Restore functionality to the phaser turret
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / turrets / util.qc
1 #include "util.qh"
2
3 #ifdef SVQC
4
5 /*
6 * Update this.tur_shotorg by getting up2date bone info
7 * NOTICE this func overwrites the global v_forward, v_right and v_up vectors.
8 */
9 float turret_tag_fire_update(entity this)
10 {
11         if(!this.tur_head)
12         {
13                 LOG_DEBUG("Call to turret_tag_fire_update with this.tur_head missing!");
14                 this.tur_shotorg = '0 0 0';
15                 return false;
16         }
17
18         this.tur_shotorg = gettaginfo(this.tur_head, gettagindex(this.tur_head, "tag_fire"));
19         v_forward = normalize(v_forward);
20
21         return true;
22 }
23
24 /*
25 * Railgun-like beam, but has thickness and suppots slowing of target
26 */
27 void FireImoBeam(entity this, vector start, vector end, vector smin, vector smax,
28                                   float bforce, float f_dmg, float f_velfactor, int deathtype)
29
30 {
31         vector dir = normalize(end - start);
32         vector force = dir * bforce;
33
34         // go a little bit into the wall because we need to hit this wall later
35         end = end + dir;
36
37         // trace multiple times until we hit a wall, each obstacle will be made unsolid.
38         // note down which entities were hit so we can damage them later
39         entity o = this;
40         while (1)
41         {
42                 if(CS(this).antilag_debug)
43                         WarpZone_tracebox_antilag (this, start, smin, smax, end, false, o, CS(this).antilag_debug);
44                 else
45                         WarpZone_tracebox_antilag (this, start, smin, smax, end, false, o, ANTILAG_LATENCY(this));
46                 if(o && WarpZone_trace_firstzone)
47                 {
48                         o = NULL;
49                         continue;
50                 }
51
52                 // if it is NULL we can't hurt it so stop now
53                 if (trace_ent == NULL || trace_fraction == 1)
54                         break;
55
56                 // make the entity non-solid so we can hit the next one
57                 IL_PUSH(g_railgunhit, trace_ent);
58                 trace_ent.railgunhit = true;
59                 trace_ent.railgunhitloc = end;
60                 trace_ent.railgunhitsolidbackup = trace_ent.solid;
61                 trace_ent.railgundistance = vlen(WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos) - start);
62                 trace_ent.railgunforce = WarpZone_TransformVelocity(WarpZone_trace_transform, force);
63
64                 // stop if this is a wall
65                 if (trace_ent.solid == SOLID_BSP)
66                         break;
67
68                 // make the entity non-solid
69                 trace_ent.solid = SOLID_NOT;
70         }
71
72         vector endpoint = trace_endpos;
73         entity endent = trace_ent;
74         float endq3surfaceflags = trace_dphitq3surfaceflags;
75
76         // find all the entities the railgun hit and restore their solid state
77         IL_EACH(g_railgunhit, it.railgunhit,
78         {
79                 it.solid = it.railgunhitsolidbackup;
80         });
81
82         /*
83                 Unlike the railgun, this does NOT check for targets close by
84         */
85
86         // find all the entities the railgun hit and hurt them
87         IL_EACH(g_railgunhit, it.railgunhit,
88         {
89                 // removal from the list is handled below
90                 /* no falloff applied */
91
92                 // apply the damage
93                 if (it.takedamage)
94                 {
95                         Damage(it, this, this, f_dmg, deathtype, DMG_NOWEP, it.railgunhitloc, it.railgunforce);
96                         // slow down the target
97                         it.velocity = it.velocity * f_velfactor;
98                 }
99
100                 it.railgunhitloc = '0 0 0';
101                 it.railgunhitsolidbackup = SOLID_NOT;
102                 it.railgunhit = false;
103                 it.railgundistance = 0;
104         });
105
106         IL_CLEAR(g_railgunhit);
107
108         /* no accuracy, as a weapon entity is not attached */
109
110         trace_endpos = endpoint;
111         trace_ent = endent;
112         trace_dphitq3surfaceflags = endq3surfaceflags;
113 }
114
115 #ifdef TURRET_DEBUG
116 void marker_think(entity this)
117 {
118         if(this.cnt)
119         if(this.cnt < time)
120         {
121                 setthink(this, SUB_Remove);
122                 this.nextthink = time;
123                 return;
124         }
125
126         this.frame += 1;
127         if(this.frame > 29)
128                 this.frame = 0;
129
130         this.nextthink = time;
131 }
132
133 void mark_error(vector where,float lifetime)
134 {
135         entity err = new(error_marker);
136         setmodel(err, MDL_MARKER);
137         setorigin(err, where);
138         set_movetype(err, MOVETYPE_NONE);
139         setthink(err, marker_think);
140         err.nextthink = time;
141         err.skin = 0;
142         if(lifetime)
143                 err.cnt = lifetime + time;
144 }
145
146 void mark_info(vector where,float lifetime)
147 {
148         entity err = new(info_marker);
149         setmodel(err, MDL_MARKER);
150         setorigin(err, where);
151         set_movetype(err, MOVETYPE_NONE);
152         setthink(err, marker_think);
153         err.nextthink = time;
154         err.skin = 1;
155         if(lifetime)
156                 err.cnt = lifetime + time;
157 }
158
159 entity mark_misc(vector where,float lifetime)
160 {
161         entity err = new(mark_misc);
162         setmodel(err, MDL_MARKER);
163         setorigin(err, where);
164         set_movetype(err, MOVETYPE_NONE);
165         setthink(err, marker_think);
166         err.nextthink = time;
167         err.skin = 3;
168         if(lifetime)
169                 err.cnt = lifetime + time;
170         return err;
171 }
172
173 MODEL(TUR_C512, "models/turrets/c512.md3");
174
175 /*
176 * Paint a v_color colord circle on target onwho
177 * that fades away over f_time
178 */
179 void paint_target(entity onwho, float f_size, vector v_color, float f_time)
180 {
181         entity e;
182
183         e = spawn();
184         setmodel(e, MDL_TUR_C512); // precision set above
185         e.scale = (f_size/512);
186         //setsize(e, '0 0 0', '0 0 0');
187         //setattachment(e,onwho,"");
188         setorigin(e, onwho.origin + '0 0 1');
189         e.alpha = 0.15;
190         set_movetype(e, MOVETYPE_FLY);
191
192         e.velocity = (v_color * 32); // + '0 0 1' * 64;
193
194         e.colormod = v_color;
195         SUB_SetFade(e,time,f_time);
196 }
197
198 void paint_target2(entity onwho, float f_size, vector v_color, float f_time)
199 {
200         entity e;
201
202         e = spawn();
203         setmodel(e, MDL_TUR_C512); // precision set above
204         e.scale = (f_size/512);
205         setsize(e, '0 0 0', '0 0 0');
206
207         setorigin(e, onwho.origin + '0 0 1');
208         e.alpha = 0.15;
209         set_movetype(e, MOVETYPE_FLY);
210
211         e.velocity = (v_color * 32); // + '0 0 1' * 64;
212         e.avelocity_x = -128;
213
214         e.colormod = v_color;
215         SUB_SetFade(e,time,f_time);
216 }
217
218 void paint_target3(vector where, float f_size, vector v_color, float f_time)
219 {
220         entity e;
221         e = spawn();
222         setmodel(e, MDL_TUR_C512); // precision set above
223         e.scale = (f_size/512);
224         setsize(e, '0 0 0', '0 0 0');
225         setorigin(e, where + '0 0 1');
226         set_movetype(e, MOVETYPE_NONE);
227         e.velocity = '0 0 0';
228         e.colormod = v_color;
229         SUB_SetFade(e,time,f_time);
230 }
231 #endif
232
233 #endif