]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/turrets/util.qc
Merge branch 'terencehill/menu_languages' into 'master'
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / turrets / util.qc
1 /*
2 * Return a angle within +/- 360.
3 */
4 float anglemods(float v)
5 {
6         v = v - 360 * floor(v / 360);
7
8         if(v >= 180)
9                 return v - 360;
10         else if(v <= -180)
11                 return v + 360;
12         else
13                 return v;
14 }
15
16 /*
17 * Return the short angle
18 */
19 float shortangle_f(float ang1, float ang2)
20 {
21         if(ang1 > ang2)
22         {
23                 if(ang1 > 180)
24                         return ang1 - 360;
25         }
26         else
27         {
28                 if(ang1 < -180)
29                         return ang1 + 360;
30         }
31
32         return ang1;
33 }
34
35 vector shortangle_v(vector ang1, vector ang2)
36 {
37         vector vtmp;
38
39         vtmp_x = shortangle_f(ang1_x,ang2_x);
40         vtmp_y = shortangle_f(ang1_y,ang2_y);
41         vtmp_z = shortangle_f(ang1_z,ang2_z);
42
43         return vtmp;
44 }
45
46 vector shortangle_vxy(vector ang1, vector ang2)
47 {
48         vector vtmp = '0 0 0';
49
50         vtmp_x = shortangle_f(ang1_x,ang2_x);
51         vtmp_y = shortangle_f(ang1_y,ang2_y);
52
53         return vtmp;
54 }
55
56
57 /*
58 * Get "real" origin, in worldspace, even if ent is attached to something else.
59 */
60 vector real_origin(entity ent)
61 {
62         entity e;
63         vector v = ((ent.absmin + ent.absmax) * 0.5);
64
65         e = ent.tag_entity;
66         while(e)
67         {
68                 v = v + ((e.absmin + e.absmax) * 0.5);
69                 e = e.tag_entity;
70         }
71
72         return v;
73 }
74
75 /*
76 * Return the angle between two enteties
77 */
78 vector angleofs(entity from, entity to)
79 {
80         vector v_res;
81
82         v_res = normalize(to.origin - from.origin);
83         v_res = vectoangles(v_res);
84         v_res = v_res - from.angles;
85
86         if (v_res_x < 0)        v_res_x += 360;
87         if (v_res_x > 180)      v_res_x -= 360;
88
89         if (v_res_y < 0)        v_res_y += 360;
90         if (v_res_y > 180)      v_res_y -= 360;
91
92         return v_res;
93 }
94
95 vector angleofs3(vector from, vector from_a, entity to)
96 {
97         vector v_res;
98
99         v_res = normalize(to.origin - from);
100         v_res = vectoangles(v_res);
101         v_res = v_res - from_a;
102
103         if (v_res_x < 0)        v_res_x += 360;
104         if (v_res_x > 180)      v_res_x -= 360;
105
106         if (v_res_y < 0)        v_res_y += 360;
107         if (v_res_y > 180)      v_res_y -= 360;
108
109         return v_res;
110 }
111
112 /*
113 * Update self.tur_shotorg by getting up2date bone info
114 * NOTICE this func overwrites the global v_forward, v_right and v_up vectors.
115 */
116 float turret_tag_fire_update()
117 {SELFPARAM();
118         if(!self.tur_head)
119         {
120                 error("Call to turret_tag_fire_update with self.tur_head missing!\n");
121                 self.tur_shotorg = '0 0 0';
122                 return false;
123         }
124
125         self.tur_shotorg = gettaginfo(self.tur_head, gettagindex(self.tur_head, "tag_fire"));
126         v_forward = normalize(v_forward);
127
128         return true;
129 }
130
131 /*
132 * Railgun-like beam, but has thickness and suppots slowing of target
133 */
134 void FireImoBeam (vector start, vector end, vector smin, vector smax,
135                                   float bforce, float f_dmg, float f_velfactor, int deathtype)
136
137 {SELFPARAM();
138         vector hitloc, force, endpoint, dir;
139         entity ent;
140
141         dir = normalize(end - start);
142         force = dir * bforce;
143
144         // go a little bit into the wall because we need to hit this wall later
145         end = end + dir;
146
147         // trace multiple times until we hit a wall, each obstacle will be made unsolid.
148         // note down which entities were hit so we can damage them later
149         while (1)
150         {
151                 tracebox(start, smin, smax, end, false, self);
152
153                 // if it is world we can't hurt it so stop now
154                 if (trace_ent == world || trace_fraction == 1)
155                         break;
156
157                 if (trace_ent.solid == SOLID_BSP)
158                         break;
159
160                 // make the entity non-solid so we can hit the next one
161                 trace_ent.railgunhit = true;
162                 trace_ent.railgunhitloc = end;
163                 trace_ent.railgunhitsolidbackup = trace_ent.solid;
164
165                 // stop if this is a wall
166
167                 // make the entity non-solid
168                 trace_ent.solid = SOLID_NOT;
169         }
170
171         endpoint = trace_endpos;
172
173         // find all the entities the railgun hit and restore their solid state
174         ent = findfloat(world, railgunhit, true);
175         while (ent)
176         {
177                 // restore their solid type
178                 ent.solid = ent.railgunhitsolidbackup;
179                 ent = findfloat(ent, railgunhit, true);
180         }
181
182         // find all the entities the railgun hit and hurt them
183         ent = findfloat(world, railgunhit, true);
184         while (ent)
185         {
186                 // get the details we need to call the damage function
187                 hitloc = ent.railgunhitloc;
188                 ent.railgunhitloc = '0 0 0';
189                 ent.railgunhitsolidbackup = SOLID_NOT;
190                 ent.railgunhit = false;
191
192                 // apply the damage
193                 if (ent.takedamage)
194                 {
195                         Damage (ent, self, self, f_dmg, deathtype, hitloc, force);
196                         ent.velocity = ent.velocity * f_velfactor;
197                         //ent.alpha = 0.25 + random() * 0.75;
198                 }
199
200                 // advance to the next entity
201                 ent = findfloat(ent, railgunhit, true);
202         }
203         trace_endpos = endpoint;
204 }
205
206 #ifdef TURRET_DEBUG
207 void SUB_Remove();
208 void marker_think()
209 {SELFPARAM();
210         if(self.cnt)
211         if(self.cnt < time)
212         {
213                 self.think = SUB_Remove;
214                 self.nextthink = time;
215                 return;
216         }
217
218         self.frame += 1;
219         if(self.frame > 29)
220                 self.frame = 0;
221
222         self.nextthink = time;
223 }
224
225 void mark_error(vector where,float lifetime)
226 {
227         entity err = new(error_marker);
228         setmodel(err, MDL_MARKER);
229         setorigin(err,where);
230         err.movetype = MOVETYPE_NONE;
231         err.think = marker_think;
232         err.nextthink = time;
233         err.skin = 0;
234         if(lifetime)
235                 err.cnt = lifetime + time;
236 }
237
238 void mark_info(vector where,float lifetime)
239 {
240         entity err = spawn(info_marker);
241         setmodel(err, MDL_MARKER);
242         setorigin(err,where);
243         err.movetype = MOVETYPE_NONE;
244         err.think = marker_think;
245         err.nextthink = time;
246         err.skin = 1;
247         if(lifetime)
248                 err.cnt = lifetime + time;
249 }
250
251 entity mark_misc(vector where,float lifetime)
252 {
253         entity err = spawn(mark_misc);
254         setmodel(err, MDL_MARKER);
255         setorigin(err,where);
256         err.movetype = MOVETYPE_NONE;
257         err.think = marker_think;
258         err.nextthink = time;
259         err.skin = 3;
260         if(lifetime)
261                 err.cnt = lifetime + time;
262         return err;
263 }
264
265 MODEL(TUR_C512, "models/turrets/c512.md3");
266
267 /*
268 * Paint a v_color colord circle on target onwho
269 * that fades away over f_time
270 */
271 void paint_target(entity onwho, float f_size, vector v_color, float f_time)
272 {
273         entity e;
274
275         e = spawn();
276         setmodel(e, MDL_TUR_C512); // precision set above
277         e.scale = (f_size/512);
278         //setsize(e, '0 0 0', '0 0 0');
279         //setattachment(e,onwho,"");
280         setorigin(e,onwho.origin + '0 0 1');
281         e.alpha = 0.15;
282         e.movetype = MOVETYPE_FLY;
283
284         e.velocity = (v_color * 32); // + '0 0 1' * 64;
285
286         e.colormod = v_color;
287         SUB_SetFade(e,time,f_time);
288 }
289
290 void paint_target2(entity onwho, float f_size, vector v_color, float f_time)
291 {
292         entity e;
293
294         e = spawn();
295         setmodel(e, MDL_TUR_C512); // precision set above
296         e.scale = (f_size/512);
297         setsize(e, '0 0 0', '0 0 0');
298
299         setorigin(e,onwho.origin + '0 0 1');
300         e.alpha = 0.15;
301         e.movetype = MOVETYPE_FLY;
302
303         e.velocity = (v_color * 32); // + '0 0 1' * 64;
304         e.avelocity_x = -128;
305
306         e.colormod = v_color;
307         SUB_SetFade(e,time,f_time);
308 }
309
310 void paint_target3(vector where, float f_size, vector v_color, float f_time)
311 {
312         entity e;
313         e = spawn();
314         setmodel(e, MDL_TUR_C512); // precision set above
315         e.scale = (f_size/512);
316         setsize(e, '0 0 0', '0 0 0');
317         setorigin(e,where+ '0 0 1');
318         e.movetype = MOVETYPE_NONE;
319         e.velocity = '0 0 0';
320         e.colormod = v_color;
321         SUB_SetFade(e,time,f_time);
322 }
323 #endif