Major: turret.ticrate was NOT beeing correctly set, resulting in thinks EVERY FRAME...
[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;
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;
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     v = v + ((ent.absmin + ent.absmax) * 0.5);
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 {
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, float deathtype)
136
137 {
138     local vector hitloc, force, endpoint, dir;
139     local 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 // Plug this into wherever precache is done.
207 void g_turrets_common_precash()
208 {
209     precache_model ("models/turrets/c512.md3");
210     precache_model ("models/marker.md3");
211 }
212
213 void turrets_precache_debug_models()
214 {
215     precache_model ("models/turrets/c512.md3");
216     precache_model ("models/pathlib/goodsquare.md3");
217     precache_model ("models/pathlib/badsquare.md3");
218     precache_model ("models/pathlib/square.md3");
219     precache_model ("models/pathlib/edge.md3");
220 }
221
222 void turrets_precash()
223 {
224     precache_model ("models/turrets/base-gib1.md3");
225     precache_model ("models/turrets/base-gib2.md3");
226     precache_model ("models/turrets/base-gib3.md3");
227     precache_model ("models/turrets/base-gib4.md3");
228
229     precache_model ("models/turrets/head-gib1.md3");
230     precache_model ("models/turrets/head-gib2.md3");
231     precache_model ("models/turrets/head-gib3.md3");
232     precache_model ("models/turrets/head-gib4.md3");
233     precache_model ("models/turrets/terrainbase.md3");
234
235     //precache_model ("models/turrets/base.md3");
236     //precache_model ("models/turrets/flac.md3");
237     //precache_model ("models/turrets/pd_proj.md3");
238     //precache_model ("models/turrets/reactor.md3");
239     //precache_model ("models/turrets/mlrs_rocket.md3");
240     //precache_model ("models/turrets/hellion.md3");
241     //precache_model ("models/turrets/hunter2.md3");
242     //precache_model ("models/turrets/hk.md3");
243     //precache_model ("models/turrets/machinegun.md3");
244     //precache_model ("models/turrets/rocket.md3");
245     //precache_model ("models/turrets/mlrs.md3");
246     //precache_model ("models/turrets/phaser.md3");
247     //precache_model ("models/turrets/phaser_beam.md3");
248     //precache_model ("models/turrets/plasmad.md3");
249     //precache_model ("models/turrets/plasma.md3");
250     //precache_model ("models/turrets/tesla_head.md3");
251     //precache_model ("models/turrets/tesla_base.md3");
252     #ifdef TURRET_DEBUG
253         turrets_precache_debug_models();
254         #endif
255 }
256
257
258 #ifdef TURRET_DEBUG
259 void SUB_Remove();
260 void marker_think()
261 {
262     if(self.cnt)
263     if(self.cnt < time)
264     {
265         self.think = SUB_Remove;
266         self.nextthink = time;
267         return;
268     }
269
270     self.frame += 1;
271     if(self.frame > 29)
272         self.frame = 0;
273
274     self.nextthink = time;
275 }
276
277 void mark_error(vector where,float lifetime)
278 {
279     entity err;
280
281     err = spawn();
282     err.classname = "error_marker";
283     setmodel(err,"models/marker.md3");
284     setorigin(err,where);
285     err.movetype = MOVETYPE_NONE;
286     err.think = marker_think;
287     err.nextthink = time;
288     err.skin = 0;
289     if(lifetime)
290         err.cnt = lifetime + time;
291 }
292
293 void mark_info(vector where,float lifetime)
294 {
295     entity err;
296
297     err = spawn();
298     err.classname = "info_marker";
299     setmodel(err,"models/marker.md3");
300     setorigin(err,where);
301     err.movetype = MOVETYPE_NONE;
302     err.think = marker_think;
303     err.nextthink = time;
304     err.skin = 1;
305     if(lifetime)
306         err.cnt = lifetime + time;
307 }
308
309 entity mark_misc(vector where,float lifetime)
310 {
311     entity err;
312
313     err = spawn();
314     err.classname = "mark_misc";
315     setmodel(err,"models/marker.md3");
316     setorigin(err,where);
317     err.movetype = MOVETYPE_NONE;
318     err.think = marker_think;
319     err.nextthink = time;
320     err.skin = 3;
321     if(lifetime)
322         err.cnt = lifetime + time;
323     return err;
324 }
325
326 /*
327 * Paint a v_color colord circle on target onwho
328 * that fades away over f_time
329 */
330 void paint_target(entity onwho, float f_size, vector v_color, float f_time)
331 {
332     entity e;
333
334     e = spawn();
335     setmodel(e, "models/turrets/c512.md3"); // precision set above
336     e.scale = (f_size/512);
337     //setsize(e, '0 0 0', '0 0 0');
338     //setattachment(e,onwho,"");
339     setorigin(e,onwho.origin + '0 0 1');
340     e.alpha = 0.15;
341     e.movetype = MOVETYPE_FLY;
342
343     e.velocity = (v_color * 32); // + '0 0 1' * 64;
344
345     e.colormod = v_color;
346     SUB_SetFade(e,time,f_time);
347 }
348
349 void paint_target2(entity onwho, float f_size, vector v_color, float f_time)
350 {
351     entity e;
352
353     e = spawn();
354     setmodel(e, "models/turrets/c512.md3"); // precision set above
355     e.scale = (f_size/512);
356     setsize(e, '0 0 0', '0 0 0');
357
358     setorigin(e,onwho.origin + '0 0 1');
359     e.alpha = 0.15;
360     e.movetype = MOVETYPE_FLY;
361
362     e.velocity = (v_color * 32); // + '0 0 1' * 64;
363     e.avelocity_x = -128;
364
365     e.colormod = v_color;
366     SUB_SetFade(e,time,f_time);
367 }
368
369 void paint_target3(vector where, float f_size, vector v_color, float f_time)
370 {
371     entity e;
372     e = spawn();
373     setmodel(e, "models/turrets/c512.md3"); // precision set above
374     e.scale = (f_size/512);
375     setsize(e, '0 0 0', '0 0 0');
376     setorigin(e,where+ '0 0 1');
377     e.movetype = MOVETYPE_NONE;
378     e.velocity = '0 0 0';
379     e.colormod = v_color;
380     SUB_SetFade(e,time,f_time);
381 }
382 #endif