]> icculus.org git repositories - divverent/nexuiz.git/blob - TeamNexuiz/game/gamec/cl_player.c
- Tesla no longer crashes game while attacking (changed MSG_BROADCAST to "2")
[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                 self.frame = $jump;\r
139 }\r
140 //End change by Supajoe on 11:44 PM EST 11/16/03 (Subject: Player animations)\r
141 \r
142 \r
143 void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)\r
144 {\r
145         local float take, save;\r
146         te_blood (hitloc, force, damage);\r
147         // damage resistance (ignore most of the damage from a bullet or similar)\r
148         damage = max(damage - 5, 1);\r
149         save = bound(0, damage * 0.6, self.armorvalue);\r
150         take = bound(0, damage - save, damage);\r
151         self.armorvalue = self.armorvalue - save;\r
152         self.health = self.health - take;\r
153         self.dmg_save = self.dmg_save + save;\r
154         self.dmg_take = self.dmg_take + take;\r
155         self.dmg_inflictor = inflictor;\r
156         if (self.health <= -50)\r
157         {\r
158                 // don't use any animations as a gib\r
159                 self.frame = 0;\r
160                 self.dead_frame = 0;\r
161                 self.die_frame = 0;\r
162                 // view just above the floor\r
163                 self.view_ofs = '0 0 4';\r
164 \r
165                 // make a juicy mess\r
166                 te_bloodshower (self.origin + self.mins, self.origin + self.maxs, 800, 1000);\r
167                 te_bloodshower (self.origin + self.mins, self.origin + self.maxs, 400, 1000);\r
168 \r
169                 // make a meaty mess\r
170                 TossGib (self, "models/gibs/eye.md3", self.origin, self.velocity,0);\r
171                 TossGib (world, "models/gibs/bloodyskull.md3", self.origin, '0 0 600',0);\r
172 \r
173                 TossGib (world, "models/gibs/gib1.md3", self.origin, self.velocity,0);\r
174                 TossGib (world, "models/gibs/gib2.md3", self.origin, self.velocity,0);\r
175                 TossGib (world, "models/gibs/gib3.md3", self.origin, self.velocity,0);\r
176                 TossGib (world, "models/gibs/gib4.md3", self.origin, self.velocity,0);\r
177 \r
178                 // these destory on impact\r
179                 TossGib (world, "models/gibs/gib5.md3", self.origin, '-500 0 450',1);\r
180                 TossGib (world, "models/gibs/gib6.md3", self.origin, '0 500 450',1);\r
181                 TossGib (world, "models/gibs/chunk.mdl", self.origin, '0 -500 450',1);\r
182                 TossGib (world, "models/gibs/chunk.mdl", self.origin, '500 0 450',1);\r
183                 TossGib (world, "models/gibs/chunk.mdl", self.origin, self.velocity,1);\r
184                 TossGib (world, "models/gibs/chunk.mdl", self.origin, '0 0 450',1);\r
185 \r
186                 sound (trace_ent, CHAN_VOICE, "misc/gib.wav", 1, ATTN_NORM);\r
187         }\r
188 }\r
189 \r
190 void PlayerKilled (float unnatural_death, entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)\r
191 {\r
192         if(self.class == CLASS_SPY)\r
193                 SpyDecloak();\r
194 \r
195         // fixes death while reloading glitch\r
196         inflictor.reload_time = 0;\r
197         // fixes flash effects staying after death bug\r
198         self.FlashTime = 0;\r
199         stuffcmd(inflictor, "v_cshift 0 0 0 0\n");\r
200         \r
201         // throw a weapon\r
202         SpawnThrownWeapon (self.origin + (self.mins + self.maxs) * 0.5, self.wpn5.weapon);//self.weapon);\r
203         // print an obituary message\r
204         Obituary (attacker, self, deathtype);\r
205         // Drop flag or any carried item\r
206         TeamFortress_RemoveTimers ();\r
207         // Make sure corpse cant take tfgoal items\r
208         self.is_dead = 1;\r
209         // make the corpse upright (not tilted)\r
210         self.angles_x = 0;\r
211         self.angles_z = 0;\r
212         // don't spin\r
213         self.avelocity = '0 0 0';\r
214         // no weapon when dead\r
215         self.weaponmodel = "";\r
216         w_clear();\r
217         // view from the floor\r
218         self.view_ofs = '0 0 -8';\r
219         // toss the corpse\r
220         self.movetype = MOVETYPE_TOSS;\r
221         // shootable corpse\r
222         self.solid = SOLID_CORPSE;\r
223         // don't stick to the floor\r
224         self.flags = self.flags - (self.flags & FL_ONGROUND);\r
225         // dying animation\r
226         self.deadflag = DEAD_DYING;\r
227         // when to allow respawn\r
228         self.death_time = time + 0.5;\r
229         // when to switch to the dead_frame\r
230         self.dead_time = time + 2;\r
231         if(!unnatural_death)\r
232         {\r
233                 if (random() < 0.5)\r
234                 {\r
235                         self.die_frame = $die1;\r
236                         self.dead_frame = $dead1;\r
237                 }\r
238                 else\r
239                 {\r
240                         self.die_frame = $die2;\r
241                         self.dead_frame = $dead2;\r
242                 }\r
243         }\r
244         else\r
245         {\r
246                 self.die_frame = $dead2;\r
247                 self.dead_frame = $dead2;\r
248                 if(self.health > -1)\r
249                         self.health = -1;\r
250         }\r
251         // start the animation\r
252         player_anim();\r
253         // set damage function to corpse damage\r
254         self.event_damage = PlayerCorpseDamage;\r
255         // call the corpse damage function just in case it wants to gib\r
256         self.event_damage(inflictor, attacker, 0, deathtype, hitloc, force);\r
257         // set up to fade out later\r
258         SUB_SetFade (self, time + 12 + random () * 4, 1);\r
259 }\r
260 \r
261 float PlayerShouldDie (entity inflictor, entity attacker, float damage, float deathtype)\r
262 {\r
263         // returns true if player should die from this source of damage.\r
264         // If so, don't block this damage in any way\r
265 \r
266         if(damage > 2000)\r
267                 return TRUE;\r
268 \r
269         if(    deathtype == DEATH_FALL\r
270                 || deathtype == DEATH_TELEFRAG\r
271                 || deathtype == DEATH_DROWN\r
272                 || deathtype == DEATH_HURTTRIGGER\r
273                 || deathtype == DEATH_LAVA\r
274                 || deathtype == DEATH_SLIME\r
275                 || deathtype == DEATH_KILL\r
276                 || deathtype == DEATH_CLASSCHANGE\r
277 //              || deathtype == DEATH_BURNING\r
278                 || deathtype == DEATH_LASERGATE\r
279                 )\r
280                 return TRUE;\r
281 \r
282         return FALSE;\r
283 }\r
284 \r
285 void PlayerDamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)\r
286 {\r
287         local float take, save, damagearmor;\r
288 \r
289          te_blood (hitloc, force, damage);\r
290         if (self.pain_finished < time)          //Don't switch pain sequences like crazy\r
291         {\r
292                 if (random() > 0.5)\r
293                         self.pain_frame = $pain1;\r
294                 else\r
295                         self.pain_frame = $pain2;\r
296                 self.pain_finished = time + 0.5;        //Supajoe\r
297         }\r
298 \r
299         if(self.class == CLASS_MEDIC)\r
300         {\r
301                 if(deathtype == DEATH_BURNING)\r
302                         damage = 0;     // being on fire or near burning targets does nothing to medics\r
303                 // the flame thrower, flame rockets, and hotbombs also do minimal damage\r
304                 else if(deathtype == WEP_FLAMER ||\r
305                                 deathtype == WEP_ROCKET_INCENDIARY ||\r
306                                 deathtype == WEP_HOTBOMBS)\r
307                         damage = damage * cvar("g_balance_class_medic_flame_takedamage");\r
308         }\r
309 \r
310         // how much damage to deal to armor\r
311         damagearmor = bound(0, damage * 0.2 * (self.armorvalue / 50) * cvar("g_balance_armor_takedamage"), self.armorvalue);\r
312         // how much damage armor blocks\r
313         save = bound(0, damage * (self.armorvalue / 100) * cvar("g_balance_armor_effectiveness"), damage);\r
314         // how much damage to deal to player\r
315         take = bound(0, damage - save, damage);\r
316 \r
317         // if being telefragged or killed by a death trigger etc, don't block that\r
318         if(PlayerShouldDie(inflictor, attacker, damage, deathtype))\r
319         {\r
320                 if(take < damage)\r
321                         take = damage; // deal full damage\r
322         }\r
323         else\r
324         {\r
325                 // keep the damage the armor allowed through, and further reduce it if the player is using the shield\r
326                 if(self.class == CLASS_SCOUT)\r
327                         take = SpecialShieldProtect(take);\r
328         }\r
329 \r
330         if (save > 10)\r
331                 sound (self, CHAN_IMPACT, "misc/armorimpact.wav", 1, ATTN_NORM);\r
332         if (take > 10)\r
333                 sound (self, CHAN_IMPACT, "misc/bodyimpact1.wav", 1, ATTN_NORM);\r
334         if (take > 30)\r
335                 sound (self, CHAN_IMPACT, "misc/bodyimpact2.wav", 1, ATTN_NORM);\r
336 \r
337         if (take > 50)\r
338                 TossGib (world, "models/gibs/chunk.mdl", hitloc, force * -0.1,1);\r
339         if (take > 100)\r
340                 TossGib (world, "models/gibs/chunk.mdl", hitloc, force * -0.1,1);\r
341 \r
342         if (!(self.flags & FL_GODMODE))\r
343         {\r
344                 self.armorvalue = self.armorvalue - damagearmor;\r
345                 self.health = self.health - take;\r
346         }\r
347 \r
348         DelayHealthRegen(self);\r
349         DelayArmorRegen(self);\r
350 \r
351 \r
352         self.dmg_save = self.dmg_save + max(save - 10, 0);\r
353         self.dmg_take = self.dmg_take + max(take - 10, 0);\r
354         self.dmg_inflictor = inflictor;\r
355         if (self.health <= 2)\r
356         {\r
357                 PlayerKilled(FALSE, inflictor, attacker, damage, deathtype, hitloc, force);\r
358         }\r
359 }\r
360 \r