Major: turret.ticrate was NOT beeing correctly set, resulting in thinks EVERY FRAME...
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / tturrets / system / system_damage.qc
1 /*
2 * Trow a turret gib
3 */
4 void turret_gib_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector vforce)
5 {
6     self.velocity += vforce;
7 }
8
9 void turret_trowgib(
10     vector v_from, vector v_to, vector v_colormod,
11     string smodel,
12     float f_lifetime, float f_fadetime, float b_burn)
13 {
14     local entity gib;
15     local entity burn;
16
17     gib = spawn();
18
19     gib.classname = "turret_gib";
20     setmodel(gib, smodel);
21     setorigin(gib, v_from);
22     SUB_SetFade(gib,time + f_lifetime, 2);
23
24     gib.solid              = SOLID_BBOX;
25     gib.movetype           = MOVETYPE_BOUNCE;
26     gib.takedamage         = DAMAGE_YES;
27     gib.event_damage       = turret_gib_damage;
28     gib.health             = -1;
29     gib.effects            = EF_LOWPRECISION;
30     gib.flags              = FL_NOTARGET;
31     gib.colormod           = v_colormod;
32     gib.velocity           = v_to;
33
34     if (b_burn)
35     {
36         burn = spawn();
37         burn.effects        = EF_LOWPRECISION;//|EF_FLAME;
38         setattachment(burn,gib,"");
39         setorigin(burn,(gib.mins + gib.maxs) * 0.5);
40         SUB_SetFade(burn,time + (f_lifetime * 0.5), 2);
41     }
42 }
43
44 void turret_gib_boom()
45 {
46     entity gib;
47     float i;
48     string s;
49
50     for (i = 1; i < 5; i = i +1)
51     {
52         gib = spawn();
53         gib.classname = "turret_gib";
54
55         s = strcat("models/turrets/head-gib",ftos(i));
56         s = strcat(s,".md3");
57         setmodel(gib, s);
58
59         setorigin(gib,self.origin);
60
61         SUB_SetFade(gib,time + 5,2);
62
63         gib.solid              = SOLID_BBOX;
64         gib.movetype           = MOVETYPE_BOUNCE;
65         gib.gravity            = 0.5;
66         gib.damageforcescale   = 2;
67         gib.takedamage         = DAMAGE_YES;
68         gib.event_damage       = turret_gib_damage;
69         gib.health             = -1;
70         gib.effects            = EF_LOWPRECISION;
71         gib.flags              = FL_NOTARGET;
72         gib.velocity           = self.velocity + (randomvec() * 700);
73         gib.avelocity          = randomvec() * 64;
74     }
75
76     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
77     WriteByte (MSG_BROADCAST, 78);
78     WriteCoord (MSG_BROADCAST, self.origin_x);
79     WriteCoord (MSG_BROADCAST, self.origin_y);
80     WriteCoord (MSG_BROADCAST, self.origin_z);
81
82     remove(self);
83 }
84
85 void turret_trowgib2(
86     vector v_from, vector v_to, vector v_colormod,
87     entity e_mimic, float boomtime)
88 {
89     entity gib;
90
91     gib = spawn();
92
93     gib.classname = "turret_gib";
94     setmodel(gib,e_mimic.model);
95     setorigin(gib,v_from);
96
97     gib.solid              = SOLID_BBOX;
98
99     gib.movetype           = MOVETYPE_BOUNCE;
100     gib.gravity            = 0.75;
101     gib.damageforcescale   = 2;
102     gib.takedamage         = DAMAGE_YES;
103     gib.event_damage       = turret_gib_damage;
104     gib.health             = -1;
105     gib.effects            = EF_LOWPRECISION;
106     gib.flags              = FL_NOTARGET;
107     gib.colormod           = v_colormod;
108     gib.velocity           = v_to;
109     gib.avelocity          = randomvec() * 32;
110     gib.think              = turret_gib_boom;
111     gib.nextthink          = boomtime;
112     //gib.effects            = EF_FLAME;
113
114
115 }
116 /*
117 * Spawn a boom, trow fake bits arround
118 * and hide the real ones.
119 */
120 void turret_stdproc_die()
121 {
122     vector org2;
123     vector t_dir;
124
125     self.deadflag           = DEAD_DEAD;
126     self.tur_head.deadflag  = self.deadflag;
127
128     sound (self, CHAN_PLAYER, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
129     org2 = self.origin + '0 0 40';
130
131 // Explotion grafix
132     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
133     WriteByte (MSG_BROADCAST, 78);
134     WriteCoord (MSG_BROADCAST, org2_x);
135     WriteCoord (MSG_BROADCAST, org2_y);
136     WriteCoord (MSG_BROADCAST, org2_z);
137
138 // Unsolidify and hide real parts
139     self.solid              = SOLID_NOT;
140     self.tur_head.solid     = self.solid;
141
142     self.alpha             = -1;
143     self.tur_head.alpha    = self.alpha;
144     self.customizeentityforclient = SUB_False;
145     self.tur_head.customizeentityforclient = SUB_False;
146
147     self.event_damage           = SUB_Null;
148     self.takedamage             = DAMAGE_NO;
149
150     self.effects            = 0;
151     self.tur_head.effects   = self.effects;
152     self.health             = 0;
153
154 // Trow fake parts arround
155     // base
156     if not(self.damage_flags & TFL_DMG_DEATH_NOGIBS)
157     {
158         makevectors(self.angles);
159         if (random() > 0.5)
160         {
161             turret_trowgib(self.origin, '0 0 0', '1 1 1', "models/turrets/base-gib2.md3", min(self.respawntime, 20), 1, 1);
162             
163             t_dir = (v_up * 700) + (randomvec() * 300);            
164             turret_trowgib(self.origin, t_dir, '1 1 1', "models/turrets/base-gib3.md3", min(self.respawntime, 10), 1, 1);
165             
166             t_dir = (v_up * 700) + (randomvec() * 300);
167             turret_trowgib(self.origin, t_dir, '1 1 1', "models/turrets/base-gib4.md3", min(self.respawntime, 10), 1, 1);
168         }
169         else
170         {
171             turret_trowgib(self.origin, '0 0 0', '1 1 1', "models/turrets/base-gib1.md3", min(self.respawntime, 20), 1, 1);
172         }
173
174         // Blow the top part up into the air
175         turret_trowgib2( self.origin + (v_up * 50), v_up * 150 + randomvec() * 50, '0.2 0.2 0.2', self.tur_head,time + 0.5 + (random() * 0.5));
176     }
177
178 // Go boom
179     //RadiusDamage (self,self, min(self.ammo,50),min(self.ammo,50) * 0.25,250,world,min(self.ammo,50)*5,DEATH_TURRET,world);
180
181     if(self.damage_flags & TFL_DMG_DEATH_NORESPAWN)
182     {
183         if (self.turret_diehook)
184             self.turret_diehook();
185
186         remove(self.tur_head);
187         remove(self);
188     }
189     else
190     {
191                 // Setup respawn
192         self.nextthink      = time + self.respawntime;
193         self.think          = turret_stdproc_respawn;
194         
195         if (self.turret_diehook)
196             self.turret_diehook();
197     }
198 }
199
200 var const float SUB_NullFloat();
201 void turret_stdproc_respawn()
202 {
203     // Make sure all parts belong to the same team since
204     // this function doubles as "teamchange" function.
205
206     self.tur_head.team  = self.team;
207         self.colormod           = '0 0 0';
208
209         switch(self.team)
210         {
211         case COLOR_TEAM1: // Red
212             self.colormod = '1.4 0.8 0.8';
213             break;
214
215         case COLOR_TEAM2: // Blue
216             self.colormod = '0.8 0.8 1.4';
217             break;
218
219         case COLOR_TEAM3: // Yellow
220             self.colormod = '1.4 1.4 0.6';
221             break;
222
223         case COLOR_TEAM4: // Pink
224             self.colormod = '1.4 0.6 1.4';
225             break;
226         }
227
228     self.deadflag           = DEAD_NO;
229     self.effects            = EF_LOWPRECISION;
230     self.tur_head.effects   = self.effects;
231     self.solid              = SOLID_BBOX;
232     self.alpha                          = 1;
233     self.tur_head.alpha     = self.alpha;
234     
235     self.customizeentityforclient                       = SUB_NullFloat;
236     self.tur_head.customizeentityforclient      = SUB_NullFloat;
237
238     self.takedamage                     = DAMAGE_AIM;
239     self.event_damage           = turret_stdproc_damage;
240
241     self.avelocity              = '0 0 0';
242     self.tur_head.avelocity     = self.avelocity;
243     self.tur_head.angles        = self.idle_aim;
244     self.health                 = self.tur_health;
245
246     self.enemy                  = world;
247     self.volly_counter          = self.shot_volly;
248     self.ammo                   = self.ammo_max;
249
250     self.nextthink  = time + self.ticrate;
251     self.think      = turret_think;
252
253     if (self.turret_respawnhook)
254         self.turret_respawnhook();
255
256 }
257
258 /*
259 * Standard damage proc.
260 */
261 void turret_stdproc_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector vforce)
262 {
263
264     // Enougth allready!
265     if (self.health <= 0)
266         return;
267
268     // Inactive turrets take no damage. (hm..)
269     if not (self.tur_active)
270         return;
271
272     if (teamplay != 0)
273     if (self.team == attacker.team)
274     {
275         // This does not happen anymore. Re-enable if you fix that.
276         if(clienttype(attacker) == CLIENTTYPE_REAL)
277             sprint(attacker, "\{1}Turret tells you: I'm on your team!\n");
278
279         if(cvar("g_friendlyfire"))
280             damage = damage * cvar("g_friendlyfire");
281         else
282             return;
283     }
284
285     self.health = self.health - damage;
286
287     // thorw head slightly off aim when hit?
288     if (self.damage_flags & TFL_DMG_HEADSHAKE)
289     {
290         //baseent.tur_aimoff_x += (random() * damage);
291         //baseent.tur_aimoff_y += ((random()*0.75) * damage);
292         self.tur_head.angles_x = self.tur_head.angles_x + (-0.5 + random()) * damage;
293         self.tur_head.angles_y = self.tur_head.angles_y + (-0.5 + random()) * damage;
294     }
295
296     if (self.turrcaps_flags & TFL_TURRCAPS_MOVE)
297         self.velocity = self.velocity + vforce;
298
299     // FIXME: Better damage feedback
300     // Start burning when we have 10% or less health left
301     //if (self.health < (self.tur_health * 0.1))
302     //    self.effects = EF_FLAME;
303
304     if (self.health <= 0)
305     {
306         self.event_damage           = SUB_Null;
307         self.tur_head.event_damage  = SUB_Null;
308         self.takedamage             = DAMAGE_NO;
309         self.nextthink = time;
310         self.think = turret_stdproc_die;
311     }
312 }