]> icculus.org git repositories - divverent/nexuiz.git/blob - TeamNexuiz/game/gamec/cl_player.c
- Fixed most body damage death messages
[divverent/nexuiz.git] / TeamNexuiz / game / gamec / cl_player.c
1 $frame die1 die2 draw duck duckwalk duckjump duckidle idle\r
2 $frame jump pain1 pain2 shoot taunt run runbackwards\r
3 $frame strafeleft straferight dead1 dead2 forwardright\r
4 $frame forwardleft backright backleft\r
5 \r
6 // changes by LordHavoc on 03/29/04 and 03/30/04 at Vermeulen's request\r
7 // merged player_run and player_stand to player_anim\r
8 // added death animations to player_anim\r
9 // can now spawn thrown weapons from anywhere, not just from players\r
10 // thrown weapons now fade out after 20 seconds\r
11 // created PlayerGib function\r
12 // PlayerDie no longer uses hitloc or damage\r
13 // PlayerDie now supports dying animations as well as gibbing\r
14 // cleaned up PlayerDie a lot\r
15 // added CopyBody\r
16 \r
17 void player_cooloff();\r
18 void BodyFakePhysics()\r
19 {\r
20         self.think = BodyFakePhysics;\r
21         self.nextthink = time;\r
22 \r
23         SV_PlayerPhysics();\r
24 \r
25         player_cooloff();\r
26 }\r
27 \r
28 void CopyBody2(float keepvelocity, float testbody)\r
29 {\r
30         local entity oldself;\r
31         if (self.effects & EF_NODRAW)\r
32                 return;\r
33         oldself = self;\r
34         self = spawn();\r
35         self.angles = oldself.angles;\r
36         self.avelocity = oldself.avelocity;\r
37         self.classname = "body";\r
38         self.mass = oldself.mass;\r
39         self.damageforcescale = oldself.damageforcescale;\r
40         self.effects = oldself.effects;\r
41         self.event_damage = oldself.event_damage;\r
42         self.frame = oldself.frame;\r
43         self.health = oldself.health;\r
44         self.model = oldself.model;\r
45         self.modelindex = oldself.modelindex;\r
46         self.movetype = oldself.movetype;\r
47         self.nextthink = oldself.nextthink;\r
48         self.skin = oldself.skin;\r
49         self.solid = oldself.solid;\r
50         self.takedamage = oldself.takedamage;\r
51         self.think = oldself.think;\r
52         if (keepvelocity == 1)\r
53                 self.velocity = oldself.velocity;\r
54         self.fade_time = oldself.fade_time;\r
55         self.fade_rate = oldself.fade_rate;\r
56         //self.weapon = oldself.weapon;\r
57         setorigin(self, oldself.origin);\r
58         setsize(self, oldself.mins, oldself.maxs);//'-16 -16 -24',  '16 16 5');\r
59         self.oldorigin = oldself.origin;\r
60         // move any fire burning me to the corpse\r
61         if(oldself.onfire != world)\r
62         {\r
63                 self.onfire = oldself.onfire;           // corpse is now on fire\r
64                 self.onfire.enemy = self;               // burn corpse instead of me when I respawn\r
65                 oldself.onfire = world;                 // I'm not on fire anymore\r
66                 setattachment(self.onfire, self, "");\r
67         }\r
68 \r
69         if(testbody)\r
70         {\r
71                 self.armorvalue = oldself.armorvalue;\r
72                 self.think = BodyFakePhysics;\r
73                 self.nextthink = time;\r
74         }\r
75         \r
76         self = oldself;\r
77 }\r
78 \r
79 void CopyBody(float keepvelocity)\r
80 {\r
81         CopyBody2(keepvelocity, FALSE);\r
82 }\r
83 \r
84 void player_anim (void)\r
85 {\r
86         if (self.deadflag != DEAD_NO)\r
87         {\r
88                 if (time > self.dead_time)\r
89                 {\r
90                         if (self.maxs_z > 5)\r
91                                 setsize(self, '-16 -16 -24', '16 16 5');\r
92                         self.frame = self.dead_frame;\r
93                 }\r
94                 else\r
95                         self.frame = self.die_frame;\r
96                 return;\r
97         }\r
98 \r
99 \r
100         if (self.crouch)\r
101         {\r
102                 if (self.movement_x * self.movement_x + self.movement_y * self.movement_y > 20)\r
103                         self.frame = $duckwalk;\r
104                 else\r
105                         self.frame = $duckidle;\r
106         }\r
107         else if ((self.movement_x * self.movement_x + self.movement_y * self.movement_y) > 20)\r
108         {\r
109                 if (self.movement_x > 0 && self.movement_y == 0)\r
110                 {\r
111                         self.frame = $run;\r
112                 }\r
113                 else if (self.movement_x < 0 && self.movement_y == 0)\r
114                         self.frame = $runbackwards;\r
115                 else if (self.movement_x == 0 && self.movement_y > 0)\r
116                         self.frame = $straferight;\r
117                 else if (self.movement_x == 0 && self.movement_y < 0)\r
118                         self.frame = $strafeleft;\r
119                 else if (self.movement_x > 0 && self.movement_y > 0)\r
120                         self.frame = $forwardright;\r
121                 else if (self.movement_x > 0 && self.movement_y < 0)\r
122                         self.frame = $forwardleft;\r
123                 else if (self.movement_x < 0 && self.movement_y > 0)\r
124                         self.frame = $backright;\r
125                 else if (self.movement_x < 0 && self.movement_y < 0)\r
126                         self.frame = $backleft;\r
127                 else\r
128                         self.frame = $run;\r
129         }\r
130         else if (self.pain_finished > time)\r
131                 self.frame = self.pain_frame;\r
132         else if (self.attack_finished > time)\r
133                 self.frame = $shoot;\r
134         else\r
135                 self.frame = $idle;\r
136 \r
137         if (!(self.flags & FL_ONGROUND))\r
138         {\r
139                 if (self.crouch)\r
140                         self.frame = $duckwalk;\r
141                 else\r
142                         self.frame = $jump;\r
143         }\r
144 }\r
145 //End change by Supajoe on 11:44 PM EST 11/16/03 (Subject: Player animations)\r
146 \r
147 \r
148 void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)\r
149 {\r
150         local float take, save;\r
151         te_blood (hitloc, force, damage);\r
152         // damage resistance (ignore most of the damage from a bullet or similar)\r
153         damage = max(damage - 5, 1);\r
154         save = bound(0, damage * 0.6, self.armorvalue);\r
155         take = bound(0, damage - save, damage);\r
156         self.armorvalue = self.armorvalue - save;\r
157         self.health = self.health - take;\r
158         self.dmg_save = self.dmg_save + save;\r
159         self.dmg_take = self.dmg_take + take;\r
160         self.dmg_inflictor = inflictor;\r
161         if (self.health <= -50)\r
162         {\r
163                 // don't use any animations as a gib\r
164                 self.frame = 0;\r
165                 self.dead_frame = 0;\r
166                 self.die_frame = 0;\r
167                 // view just above the floor\r
168                 self.view_ofs = '0 0 4';\r
169 \r
170                 // make a juicy mess\r
171                 te_bloodshower (self.origin + self.mins, self.origin + self.maxs, 800, 1000);\r
172                 te_bloodshower (self.origin + self.mins, self.origin + self.maxs, 400, 1000);\r
173 \r
174                 // make a meaty mess\r
175                 TossGib (self, "models/gibs/eye.md3", self.origin, self.velocity,0);\r
176                 TossGib (world, "models/gibs/bloodyskull.md3", self.origin, '0 0 600',0);\r
177 \r
178                 TossGib (world, "models/gibs/gib1.md3", self.origin, self.velocity,0);\r
179                 TossGib (world, "models/gibs/gib2.md3", self.origin, self.velocity,0);\r
180                 TossGib (world, "models/gibs/gib3.md3", self.origin, self.velocity,0);\r
181                 TossGib (world, "models/gibs/gib4.md3", self.origin, self.velocity,0);\r
182 \r
183                 // these destory on impact\r
184                 TossGib (world, "models/gibs/gib5.md3", self.origin, '-500 0 450',1);\r
185                 TossGib (world, "models/gibs/gib6.md3", self.origin, '0 500 450',1);\r
186                 TossGib (world, "models/gibs/chunk.mdl", self.origin, '0 -500 450',1);\r
187                 TossGib (world, "models/gibs/chunk.mdl", self.origin, '500 0 450',1);\r
188                 TossGib (world, "models/gibs/chunk.mdl", self.origin, self.velocity,1);\r
189                 TossGib (world, "models/gibs/chunk.mdl", self.origin, '0 0 450',1);\r
190 \r
191                 sound (trace_ent, CHAN_VOICE, "misc/gib.wav", 1, ATTN_NORM);\r
192         }\r
193 }\r
194 \r
195 void PlayerKilled (float unnatural_death, entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)\r
196 {\r
197         if(self.class == CLASS_SPY)\r
198                 SpyDecloak();\r
199 \r
200         // fixes death while reloading glitch\r
201         inflictor.reload_time = 0;\r
202         // fixes flash effects staying after death bug\r
203         self.FlashTime = 0;\r
204         stuffcmd(inflictor, "v_cshift 0 0 0 0\n");\r
205         \r
206         // throw a weapon\r
207         SpawnThrownWeapon (self.origin + (self.mins + self.maxs) * 0.5, self.wpn5.weapon);//self.weapon);\r
208         // print an obituary message\r
209         Obituary (attacker, self, deathtype);\r
210         // Drop flag or any carried item\r
211         TeamFortress_RemoveTimers ();\r
212         // Make sure corpse cant take tfgoal items\r
213         self.is_dead = 1;\r
214         // make the corpse upright (not tilted)\r
215         self.angles_x = 0;\r
216         self.angles_z = 0;\r
217         // don't spin\r
218         self.avelocity = '0 0 0';\r
219         // no weapon when dead\r
220         self.weaponmodel = "";\r
221         w_clear();\r
222         // view from the floor\r
223         self.view_ofs = '0 0 -8';\r
224         // toss the corpse\r
225         self.movetype = MOVETYPE_TOSS;\r
226         // shootable corpse\r
227         self.solid = SOLID_CORPSE;\r
228         // don't stick to the floor\r
229         self.flags = self.flags - (self.flags & FL_ONGROUND);\r
230         // dying animation\r
231         self.deadflag = DEAD_DYING;\r
232         // when to allow respawn\r
233         self.death_time = time + 0.5;\r
234         // when to switch to the dead_frame\r
235         self.dead_time = time + 2;\r
236         if(!unnatural_death)\r
237         {\r
238                 if (random() < 0.5)\r
239                 {\r
240                         self.die_frame = $die1;\r
241                         self.dead_frame = $dead1;\r
242                 }\r
243                 else\r
244                 {\r
245                         self.die_frame = $die2;\r
246                         self.dead_frame = $dead2;\r
247                 }\r
248         }\r
249         else\r
250         {\r
251                 self.die_frame = $dead2;\r
252                 self.dead_frame = $dead2;\r
253                 if(self.health > -1)\r
254                         self.health = -1;\r
255         }\r
256         // start the animation\r
257         player_anim();\r
258         // set damage function to corpse damage\r
259         self.event_damage = PlayerCorpseDamage;\r
260         // call the corpse damage function just in case it wants to gib\r
261         self.event_damage(inflictor, attacker, 0, deathtype, hitloc, force);\r
262         // set up to fade out later\r
263         SUB_SetFade (self, time + 12 + random () * 4, 1);\r
264 }\r
265 \r
266 float PlayerShouldDie (entity inflictor, entity attacker, float damage, float deathtype)\r
267 {\r
268         // returns true if player should die from this source of damage.\r
269         // If so, don't block this damage in any way\r
270 \r
271         if(damage > 2000)\r
272                 return TRUE;\r
273 \r
274         if(    deathtype == DEATH_FALL\r
275                 || deathtype == DEATH_TELEFRAG\r
276                 || deathtype == DEATH_DROWN\r
277                 || deathtype == DEATH_HURTTRIGGER\r
278                 || deathtype == DEATH_LAVA\r
279                 || deathtype == DEATH_SLIME\r
280                 || deathtype == DEATH_KILL\r
281                 || deathtype == DEATH_CLASSCHANGE\r
282 //              || deathtype == DEATH_BURNING\r
283                 || deathtype == DEATH_LASERGATE\r
284                 )\r
285                 return TRUE;\r
286 \r
287         return FALSE;\r
288 }\r
289 \r
290 void PlayerDamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)\r
291 {\r
292         local float take, save, damagearmor;\r
293 \r
294          te_blood (hitloc, force, damage);\r
295         if (self.pain_finished < time)          //Don't switch pain sequences like crazy\r
296         {\r
297                 if (random() > 0.5)\r
298                         self.pain_frame = $pain1;\r
299                 else\r
300                         self.pain_frame = $pain2;\r
301                 self.pain_finished = time + 0.5;        //Supajoe\r
302         }\r
303 \r
304         if(self.class == CLASS_MEDIC)\r
305         {\r
306                 if(deathtype == DEATH_BURNING)\r
307                         damage = 0;     // being on fire or near burning targets does nothing to medics\r
308                 // the flame thrower, flame rockets, and hotbombs also do minimal damage\r
309                 else if(deathtype == WEP_FLAMER ||\r
310                                 deathtype == WEP_ROCKET_INCENDIARY ||\r
311                                 deathtype == WEP_HOTBOMBS)\r
312                         damage = damage * cvar("g_balance_class_medic_flame_takedamage");\r
313         }\r
314 \r
315         // how much damage to deal to armor\r
316         damagearmor = bound(0, damage * 0.2 * (self.armorvalue / 50) * cvar("g_balance_armor_takedamage"), self.armorvalue);\r
317         // how much damage armor blocks\r
318         save = bound(0, damage * (self.armorvalue / 100) * cvar("g_balance_armor_effectiveness"), damage);\r
319         // how much damage to deal to player\r
320         take = bound(0, damage - save, damage);\r
321 \r
322         // if being telefragged or killed by a death trigger etc, don't block that\r
323         if(PlayerShouldDie(inflictor, attacker, damage, deathtype))\r
324         {\r
325                 if(take < damage)\r
326                         take = damage; // deal full damage\r
327         }\r
328         else\r
329         {\r
330                 // keep the damage the armor allowed through, and further reduce it if the player is using the shield\r
331                 if(self.class == CLASS_SCOUT)\r
332                         take = SpecialShieldProtect(take);\r
333         }\r
334 \r
335         if (save > 10)\r
336                 sound (self, CHAN_IMPACT, "misc/armorimpact.wav", 1, ATTN_NORM);\r
337         if (take > 10)\r
338                 sound (self, CHAN_IMPACT, "misc/bodyimpact1.wav", 1, ATTN_NORM);\r
339         if (take > 30)\r
340                 sound (self, CHAN_IMPACT, "misc/bodyimpact2.wav", 1, ATTN_NORM);\r
341 \r
342         if (take > 50)\r
343                 TossGib (world, "models/gibs/chunk.mdl", hitloc, force * -0.1,1);\r
344         if (take > 100)\r
345                 TossGib (world, "models/gibs/chunk.mdl", hitloc, force * -0.1,1);\r
346 \r
347         if (!(self.flags & FL_GODMODE))\r
348         {\r
349                 self.armorvalue = self.armorvalue - damagearmor;\r
350                 self.health = self.health - take;\r
351         }\r
352 \r
353         DelayHealthRegen(self);\r
354         DelayArmorRegen(self);\r
355 \r
356 \r
357         self.dmg_save = self.dmg_save + max(save - 10, 0);\r
358         self.dmg_take = self.dmg_take + max(take - 10, 0);\r
359         self.dmg_inflictor = inflictor;\r
360         if (self.health <= 2)\r
361         {\r
362                 PlayerKilled(FALSE, inflictor, attacker, damage, deathtype, hitloc, force);\r
363         }\r
364 }\r
365 \r