]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/turrets/util.qc
Merge branch 'master' into Mario/turrets
[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 #define turret_tag_fire_update() self.tur_shotorg = gettaginfo(self.tur_head, gettagindex(self.tur_head, "tag_fire"));v_forward = normalize(v_forward)
117 float turret_tag_fire_update_s()
118 {
119         if(!self.tur_head)
120         {
121                 error("Call to turret_tag_fire_update with self.tur_head missing!\n");
122                 self.tur_shotorg = '0 0 0';
123                 return FALSE;
124         }
125
126         self.tur_shotorg = gettaginfo(self.tur_head, gettagindex(self.tur_head, "tag_fire"));
127         v_forward = normalize(v_forward);
128
129         return TRUE;
130 }
131
132 /*
133 * Railgun-like beam, but has thickness and suppots slowing of target
134 */
135 void FireImoBeam (vector start, vector end, vector smin, vector smax,
136                                   float bforce, float f_dmg, float f_velfactor, float deathtype)
137
138 {
139         vector hitloc, force, endpoint, dir;
140         entity ent;
141
142         dir = normalize(end - start);
143         force = dir * bforce;
144
145         // go a little bit into the wall because we need to hit this wall later
146         end = end + dir;
147
148         // trace multiple times until we hit a wall, each obstacle will be made unsolid.
149         // note down which entities were hit so we can damage them later
150         while (1)
151         {
152                 tracebox(start, smin, smax, end, FALSE, self);
153
154                 // if it is world we can't hurt it so stop now
155                 if (trace_ent == world || trace_fraction == 1)
156                         break;
157
158                 if (trace_ent.solid == SOLID_BSP)
159                         break;
160
161                 // make the entity non-solid so we can hit the next one
162                 trace_ent.railgunhit = TRUE;
163                 trace_ent.railgunhitloc = end;
164                 trace_ent.railgunhitsolidbackup = trace_ent.solid;
165
166                 // stop if this is a wall
167
168                 // make the entity non-solid
169                 trace_ent.solid = SOLID_NOT;
170         }
171
172         endpoint = trace_endpos;
173
174         // find all the entities the railgun hit and restore their solid state
175         ent = findfloat(world, railgunhit, TRUE);
176         while (ent)
177         {
178                 // restore their solid type
179                 ent.solid = ent.railgunhitsolidbackup;
180                 ent = findfloat(ent, railgunhit, TRUE);
181         }
182
183         // find all the entities the railgun hit and hurt them
184         ent = findfloat(world, railgunhit, TRUE);
185         while (ent)
186         {
187                 // get the details we need to call the damage function
188                 hitloc = ent.railgunhitloc;
189                 ent.railgunhitloc = '0 0 0';
190                 ent.railgunhitsolidbackup = SOLID_NOT;
191                 ent.railgunhit = FALSE;
192
193                 // apply the damage
194                 if (ent.takedamage)
195                 {
196                         Damage (ent, self, self, f_dmg, deathtype, hitloc, force);
197                         ent.velocity = ent.velocity * f_velfactor;
198                         //ent.alpha = 0.25 + random() * 0.75;
199                 }
200
201                 // advance to the next entity
202                 ent = findfloat(ent, railgunhit, TRUE);
203         }
204         trace_endpos = endpoint;
205 }
206
207 #ifdef TURRET_DEBUG
208 void SUB_Remove();
209 void marker_think()
210 {
211         if(self.cnt)
212         if(self.cnt < time)
213         {
214                 self.think = SUB_Remove;
215                 self.nextthink = time;
216                 return;
217         }
218
219         self.frame += 1;
220         if(self.frame > 29)
221                 self.frame = 0;
222
223         self.nextthink = time;
224 }
225
226 void mark_error(vector where,float lifetime)
227 {
228         entity err;
229
230         err = spawn();
231         err.classname = "error_marker";
232         setmodel(err,"models/marker.md3");
233         setorigin(err,where);
234         err.movetype = MOVETYPE_NONE;
235         err.think = marker_think;
236         err.nextthink = time;
237         err.skin = 0;
238         if(lifetime)
239                 err.cnt = lifetime + time;
240 }
241
242 void mark_info(vector where,float lifetime)
243 {
244         entity err;
245
246         err = spawn();
247         err.classname = "info_marker";
248         setmodel(err,"models/marker.md3");
249         setorigin(err,where);
250         err.movetype = MOVETYPE_NONE;
251         err.think = marker_think;
252         err.nextthink = time;
253         err.skin = 1;
254         if(lifetime)
255                 err.cnt = lifetime + time;
256 }
257
258 entity mark_misc(vector where,float lifetime)
259 {
260         entity err;
261
262         err = spawn();
263         err.classname = "mark_misc";
264         setmodel(err,"models/marker.md3");
265         setorigin(err,where);
266         err.movetype = MOVETYPE_NONE;
267         err.think = marker_think;
268         err.nextthink = time;
269         err.skin = 3;
270         if(lifetime)
271                 err.cnt = lifetime + time;
272         return err;
273 }
274
275 /*
276 * Paint a v_color colord circle on target onwho
277 * that fades away over f_time
278 */
279 void paint_target(entity onwho, float f_size, vector v_color, float f_time)
280 {
281         entity e;
282
283         e = spawn();
284         setmodel(e, "models/turrets/c512.md3"); // precision set above
285         e.scale = (f_size/512);
286         //setsize(e, '0 0 0', '0 0 0');
287         //setattachment(e,onwho,"");
288         setorigin(e,onwho.origin + '0 0 1');
289         e.alpha = 0.15;
290         e.movetype = MOVETYPE_FLY;
291
292         e.velocity = (v_color * 32); // + '0 0 1' * 64;
293
294         e.colormod = v_color;
295         SUB_SetFade(e,time,f_time);
296 }
297
298 void paint_target2(entity onwho, float f_size, vector v_color, float f_time)
299 {
300         entity e;
301
302         e = spawn();
303         setmodel(e, "models/turrets/c512.md3"); // precision set above
304         e.scale = (f_size/512);
305         setsize(e, '0 0 0', '0 0 0');
306
307         setorigin(e,onwho.origin + '0 0 1');
308         e.alpha = 0.15;
309         e.movetype = MOVETYPE_FLY;
310
311         e.velocity = (v_color * 32); // + '0 0 1' * 64;
312         e.avelocity_x = -128;
313
314         e.colormod = v_color;
315         SUB_SetFade(e,time,f_time);
316 }
317
318 void paint_target3(vector where, float f_size, vector v_color, float f_time)
319 {
320         entity e;
321         e = spawn();
322         setmodel(e, "models/turrets/c512.md3"); // precision set above
323         e.scale = (f_size/512);
324         setsize(e, '0 0 0', '0 0 0');
325         setorigin(e,where+ '0 0 1');
326         e.movetype = MOVETYPE_NONE;
327         e.velocity = '0 0 0';
328         e.colormod = v_color;
329         SUB_SetFade(e,time,f_time);
330 }
331 #endif