]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/tturrets/system/system_misc.qc
Merge branch 'master' into Mario/qc_physics_prehax
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / tturrets / system / system_misc.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, int 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 // Plug this into wherever precache is done.
208 void g_turrets_common_precash()
209 {
210     precache_model ("models/turrets/c512.md3");
211     precache_model ("models/marker.md3");
212 }
213
214 void turrets_precache_debug_models()
215 {
216     precache_model ("models/turrets/c512.md3");
217     precache_model ("models/pathlib/goodsquare.md3");
218     precache_model ("models/pathlib/badsquare.md3");
219     precache_model ("models/pathlib/square.md3");
220     precache_model ("models/pathlib/edge.md3");
221 }
222
223 void turrets_precash()
224 {
225     #ifdef TURRET_DEBUG
226         turrets_precache_debug_models();
227         #endif
228 }
229
230
231 #ifdef TURRET_DEBUG
232 void marker_think()
233 {
234     if(self.cnt)
235     if(self.cnt < time)
236     {
237         self.think = SUB_Remove;
238         self.nextthink = time;
239         return;
240     }
241
242     self.frame += 1;
243     if(self.frame > 29)
244         self.frame = 0;
245
246     self.nextthink = time;
247 }
248
249 void mark_error(vector where,float lifetime)
250 {
251     entity err;
252
253     err = spawn();
254     err.classname = "error_marker";
255     setmodel(err,"models/marker.md3");
256     setorigin(err,where);
257     err.movetype = MOVETYPE_NONE;
258     err.think = marker_think;
259     err.nextthink = time;
260     err.skin = 0;
261     if(lifetime)
262         err.cnt = lifetime + time;
263 }
264
265 void mark_info(vector where,float lifetime)
266 {
267     entity err;
268
269     err = spawn();
270     err.classname = "info_marker";
271     setmodel(err,"models/marker.md3");
272     setorigin(err,where);
273     err.movetype = MOVETYPE_NONE;
274     err.think = marker_think;
275     err.nextthink = time;
276     err.skin = 1;
277     if(lifetime)
278         err.cnt = lifetime + time;
279 }
280
281 entity mark_misc(vector where,float lifetime)
282 {
283     entity err;
284
285     err = spawn();
286     err.classname = "mark_misc";
287     setmodel(err,"models/marker.md3");
288     setorigin(err,where);
289     err.movetype = MOVETYPE_NONE;
290     err.think = marker_think;
291     err.nextthink = time;
292     err.skin = 3;
293     if(lifetime)
294         err.cnt = lifetime + time;
295     return err;
296 }
297
298 /*
299 * Paint a v_color colord circle on target onwho
300 * that fades away over f_time
301 */
302 void paint_target(entity onwho, float f_size, vector v_color, float f_time)
303 {
304     entity e;
305
306     e = spawn();
307     setmodel(e, "models/turrets/c512.md3"); // precision set above
308     e.scale = (f_size/512);
309     //setsize(e, '0 0 0', '0 0 0');
310     //setattachment(e,onwho,"");
311     setorigin(e,onwho.origin + '0 0 1');
312     e.alpha = 0.15;
313     e.movetype = MOVETYPE_FLY;
314
315     e.velocity = (v_color * 32); // + '0 0 1' * 64;
316
317     e.colormod = v_color;
318     SUB_SetFade(e,time,f_time);
319 }
320
321 void paint_target2(entity onwho, float f_size, vector v_color, float f_time)
322 {
323     entity e;
324
325     e = spawn();
326     setmodel(e, "models/turrets/c512.md3"); // precision set above
327     e.scale = (f_size/512);
328     setsize(e, '0 0 0', '0 0 0');
329
330     setorigin(e,onwho.origin + '0 0 1');
331     e.alpha = 0.15;
332     e.movetype = MOVETYPE_FLY;
333
334     e.velocity = (v_color * 32); // + '0 0 1' * 64;
335     e.avelocity_x = -128;
336
337     e.colormod = v_color;
338     SUB_SetFade(e,time,f_time);
339 }
340
341 void paint_target3(vector where, float f_size, vector v_color, float f_time)
342 {
343     entity e;
344     e = spawn();
345     setmodel(e, "models/turrets/c512.md3"); // precision set above
346     e.scale = (f_size/512);
347     setsize(e, '0 0 0', '0 0 0');
348     setorigin(e,where+ '0 0 1');
349     e.movetype = MOVETYPE_NONE;
350     e.velocity = '0 0 0';
351     e.colormod = v_color;
352     SUB_SetFade(e,time,f_time);
353 }
354 #endif