centerprints now are managed independently per line
[divverent/nexuiz.git] / data / qcsrc / server / cl_player.qc
1 $frame die1 die2 draw duck duckwalk duckjump duckidle idle
2 $frame jump pain1 pain2 shoot taunt run runbackwards
3 $frame strafeleft straferight dead1 dead2 forwardright
4 $frame forwardleft backright backleft
5
6 // changes by LordHavoc on 03/29/04 and 03/30/04 at Vermeulen's request
7 // merged player_run and player_stand to player_anim
8 // added death animations to player_anim
9 // can now spawn thrown weapons from anywhere, not just from players
10 // thrown weapons now fade out after 20 seconds
11 // created PlayerGib function
12 // PlayerDie no longer uses hitloc or damage
13 // PlayerDie now supports dying animations as well as gibbing
14 // cleaned up PlayerDie a lot
15 // added CopyBody
16
17 .entity pusher;
18 .float pushltime;
19
20 void CopyBody(float keepvelocity)
21 {
22         local entity oldself;
23         if (self.effects & EF_NODRAW)
24                 return;
25         oldself = self;
26         self = spawn();
27         self.colormap = oldself.colormap;
28         self.iscreature = oldself.iscreature;
29         self.angles = oldself.angles;
30         self.avelocity = oldself.avelocity;
31         self.classname = "body";
32         self.damageforcescale = oldself.damageforcescale;
33         self.effects = oldself.effects;
34         self.event_damage = oldself.event_damage;
35         self.frame = oldself.frame;
36         self.health = oldself.health;
37         self.armorvalue = oldself.armorvalue;
38         self.armortype = oldself.armortype;
39         self.model = oldself.model;
40         self.modelindex = oldself.modelindex;
41         self.movetype = oldself.movetype;
42         self.nextthink = oldself.nextthink;
43         self.skin = oldself.skin;
44         self.solid = oldself.solid;
45         self.takedamage = oldself.takedamage;
46         self.think = oldself.think;
47         if (keepvelocity == 1)
48                 self.velocity = oldself.velocity;
49         self.oldvelocity = self.velocity;
50         self.fade_time = oldself.fade_time;
51         self.fade_rate = oldself.fade_rate;
52         //self.weapon = oldself.weapon;
53         setorigin(self, oldself.origin);
54         setsize(self, oldself.mins, oldself.maxs);
55         self.oldorigin = oldself.origin;
56         self = oldself;
57 }
58
59 void player_anim (void)
60 {
61         if (self.deadflag != DEAD_NO)
62         {
63                 if (time > self.dead_time)
64                 {
65                         if (self.maxs_z > 5)
66                         {
67                                 self.maxs_z = 5;
68                                 setsize(self, self.mins, self.maxs);
69                         }
70                         self.frame = self.dead_frame;
71                 }
72                 else
73                         self.frame = self.die_frame;
74                 return;
75         }
76
77
78         if (self.crouch)
79         {
80                 if (self.movement_x * self.movement_x + self.movement_y * self.movement_y > 20)
81                         self.frame = $duckwalk;
82                 else
83                         self.frame = $duckidle;
84         }
85         else if ((self.movement_x * self.movement_x + self.movement_y * self.movement_y) > 20)
86         {
87                 if (self.movement_x > 0 && self.movement_y == 0)
88                         self.frame = $run;
89                 else if (self.movement_x < 0 && self.movement_y == 0)
90                         self.frame = $runbackwards;
91                 else if (self.movement_x == 0 && self.movement_y > 0)
92                         self.frame = $straferight;
93                 else if (self.movement_x == 0 && self.movement_y < 0)
94                         self.frame = $strafeleft;
95                 else if (self.movement_x > 0 && self.movement_y > 0)
96                         self.frame = $forwardright;
97                 else if (self.movement_x > 0 && self.movement_y < 0)
98                         self.frame = $forwardleft;
99                 else if (self.movement_x < 0 && self.movement_y > 0)
100                         self.frame = $backright;
101                 else if (self.movement_x < 0 && self.movement_y < 0)
102                         self.frame = $backleft;
103                 else
104                         self.frame = $run;
105         }
106         else if (self.pain_finished > time)
107                 self.frame = self.pain_frame;
108         else if (self.attack_finished > time)
109                 self.frame = $shoot;
110         else
111                 self.frame = $idle;
112
113         if (!(self.flags & FL_ONGROUND))
114         {
115                 if (self.crouch)
116                         self.frame = $duckidle;         // if player is crouching while in air, show crouch frame
117                 else
118                         self.frame = $jump;
119         }
120 }
121 //End change by Supajoe on 11:44 PM EST 11/16/03 (Subject: Player animations)
122
123 void SpawnThrownWeapon (vector org, float w)
124 {
125         local entity oldself;
126
127         if (!cvar("g_pickup_items"))
128         if (!cvar("g_minstagib"))
129                 return;
130         if (w == IT_LASER)
131                 return;
132
133         oldself = self;
134         self = spawn();
135         // this will cause it to be removed later
136         self.classname = "droppedweapon";
137
138         setorigin(self, org);
139         self.velocity = randomvec() * 100 + '0 0 200';
140         SUB_SetFade(self, time + 20, 1);
141
142         if (w == WEP_UZI)
143                 weapon_uzi ();
144         else if (w == WEP_SHOTGUN)
145                 weapon_shotgun ();
146         else if (w == WEP_GRENADE_LAUNCHER)
147                 weapon_grenadelauncher ();
148         else if (w == WEP_ELECTRO)
149                 weapon_electro ();
150         else if (w == WEP_CRYLINK)
151                 weapon_crylink ();
152         else if (w == WEP_NEX)
153                 weapon_nex ();
154         else if (w == WEP_HAGAR)
155                 weapon_hagar ();
156         else if (w == WEP_ROCKET_LAUNCHER)
157                 weapon_rocketlauncher ();
158
159         // making absolutely sure...
160         self.classname = "droppedweapon";
161         self.colormap = oldself.colormap;
162
163         self = oldself;
164 }
165
166 void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
167 {
168         local float take, save;
169         te_blood (hitloc, force, damage);
170         // damage resistance (ignore most of the damage from a bullet or similar)
171         damage = max(damage - 5, 1);
172
173         save = bound(0, damage * cvar("g_balance_armor_blockpercent"), self.armorvalue);
174         take = bound(0, damage - save, damage);
175
176         if (save > 10)
177                 sound (self, CHAN_IMPACT, "misc/armorimpact.wav", 1, ATTN_NORM);
178         else if (take > 30)
179                 sound (self, CHAN_IMPACT, "misc/bodyimpact2.wav", 1, ATTN_NORM);
180         else if (take > 10)
181                 sound (self, CHAN_IMPACT, "misc/bodyimpact1.wav", 1, ATTN_NORM);
182
183         if (take > 50)
184                 TossGib (world, "models/gibs/chunk.mdl", hitloc, force * -0.1,1);
185         if (take > 100)
186                 TossGib (world, "models/gibs/chunk.mdl", hitloc, force * -0.2,1);
187
188         if (!(self.flags & FL_GODMODE))
189         {
190                 self.armorvalue = self.armorvalue - save;
191                 self.health = self.health - take;
192                 // pause regeneration for 5 seconds
193                 self.pauseregen_finished = max(self.pauseregen_finished, time + cvar("g_balance_pause_health_regen"));
194         }
195         self.dmg_save = self.dmg_save + save;//max(save - 10, 0);
196         self.dmg_take = self.dmg_take + take;//max(take - 10, 0);
197         self.dmg_inflictor = inflictor;
198
199         if (self.health <= -50)
200         {
201                 // don't use any animations as a gib
202                 self.frame = 0;
203                 self.dead_frame = 0;
204                 self.die_frame = 0;
205                 // view just above the floor
206                 self.view_ofs = '0 0 4';
207
208                 // make a juicy mess
209                 te_bloodshower (self.origin + self.mins, self.origin + self.maxs, 800, 1000);
210                 te_bloodshower (self.origin + self.mins, self.origin + self.maxs, 400, 1000);
211
212                 // make a meaty mess
213                 TossGib (self, "models/gibs/eye.md3", self.origin, self.velocity,0);
214                 TossGib (world, "models/gibs/bloodyskull.md3", self.origin, '0 0 600',0);
215
216                 TossGib (world, "models/gibs/gib1.md3", self.origin, self.velocity,0);
217                 //TossGib (world, "models/gibs/gib2.md3", self.origin, self.velocity,0);
218                 TossGib (world, "models/gibs/gib1.mdl", self.origin, self.velocity,0);
219                 //TossGib (world, "models/gibs/gib3.md3", self.origin, self.velocity,0);
220                 TossGib (world, "models/gibs/gib2.mdl", self.origin, self.velocity,0);
221                 //TossGib (world, "models/gibs/gib4.md3", self.origin, self.velocity,0);
222                 TossGib (world, "models/gibs/gib3.mdl", self.origin, self.velocity,0);
223
224                 // these destory on impact
225                 TossGib (world, "models/gibs/gib5.md3", self.origin, '-500 0 450',1);
226                 //TossGib (world, "models/gibs/gib6.md3", self.origin, '0 500 450',1);
227                 TossGib (world, "models/gibs/chunk.mdl", self.origin, '0 -500 450',1);
228                 TossGib (world, "models/gibs/chunk.mdl", self.origin, '500 0 450',1);
229                 TossGib (world, "models/gibs/chunk.mdl", self.origin, self.velocity,1);
230                 TossGib (world, "models/gibs/chunk.mdl", self.origin, '0 0 450',1);
231
232                 sound (self, CHAN_VOICE, "misc/gib.wav", 1, ATTN_NORM);
233         }
234 }
235
236 void DropAllRunes(entity pl);
237
238
239 void PlayerDamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
240 {
241         local float take, save;
242
243         te_blood (hitloc, force, damage);
244         if (self.pain_finished < time)          //Don't switch pain sequences like crazy
245         {
246                 if (random() > 0.5)
247                         self.pain_frame = $pain1;
248                 else
249                         self.pain_frame = $pain2;
250                 self.pain_finished = time + 0.5;        //Supajoe
251
252                 // throw off bot aim temporarily
253                 local float shake;
254                 shake = damage * 5 / (skill + 1);
255                 self.v_angle_x = self.v_angle_x + (random() * 2 - 1) * shake;
256                 self.v_angle_y = self.v_angle_y + (random() * 2 - 1) * shake;
257         }
258
259         if(cvar("g_arena"))
260         if(numspawned < 2)
261                 return;
262
263         if (!cvar("g_minstagib"))
264         {
265                 save = bound(0, damage * cvar("g_balance_armor_blockpercent"), self.armorvalue);
266                 take = bound(0, damage - save, damage);
267         }
268         else
269         {
270                 save = 0;
271                 take = damage;
272         }
273
274         if (save > 10)
275                 sound (self, CHAN_IMPACT, "misc/armorimpact.wav", 1, ATTN_NORM);
276         else if (take > 30)
277                 sound (self, CHAN_IMPACT, "misc/bodyimpact2.wav", 1, ATTN_NORM);
278         else if (take > 10)
279                 sound (self, CHAN_IMPACT, "misc/bodyimpact1.wav", 1, ATTN_NORM);
280
281         if (take > 50)
282                 TossGib (world, "models/gibs/chunk.mdl", hitloc, force * -0.1,1);
283         if (take > 100)
284                 TossGib (world, "models/gibs/chunk.mdl", hitloc, force * -0.2,1);
285
286         if (!(self.flags & FL_GODMODE))
287         if (time > self.spawnshieldtime)
288         {
289                 self.armorvalue = self.armorvalue - save;
290                 self.health = self.health - take;
291                 // pause regeneration for 5 seconds
292                 self.pauseregen_finished = max(self.pauseregen_finished, time + cvar("g_balance_pause_health_regen"));
293         }
294         self.dmg_save = self.dmg_save + save;//max(save - 10, 0);
295         self.dmg_take = self.dmg_take + take;//max(take - 10, 0);
296         self.dmg_inflictor = inflictor;
297
298         if(attacker == self)
299         {
300                 // don't reset pushltime for self damage as it may be an attempt to
301                 // escape a lava pit or similar
302                 //self.pushltime = 0;
303         }
304         else if(attacker.classname == "player" || attacker.classname == "gib")
305         {
306                 self.pusher = attacker;
307                 self.pushltime = time + cvar("g_maxpushtime");
308         }
309         else if(time < self.pushltime)
310         {
311                 attacker = self.pusher;
312                 self.pushltime = max(self.pushltime, time + 0.6);
313         }
314         else
315                 self.pushltime = 0;
316
317         if (self.health < 1)
318         {
319                 self.deaths += 1;
320
321                 // become fully visible
322                 self.alpha = 1;
323                 // throw a weapon
324                 SpawnThrownWeapon (self.origin + (self.mins + self.maxs) * 0.5, self.weapon);
325                 // print an obituary message
326                 Obituary (attacker, self, deathtype);
327                 DropAllRunes(self);
328                 // make the corpse upright (not tilted)
329                 self.angles_x = 0;
330                 self.angles_z = 0;
331                 // don't spin
332                 self.avelocity = '0 0 0';
333                 // view from the floor
334                 self.view_ofs = '0 0 -8';
335                 // toss the corpse
336                 self.movetype = MOVETYPE_TOSS;
337                 // shootable corpse
338                 self.solid = SOLID_CORPSE;
339                 // don't stick to the floor
340                 self.flags = self.flags - (self.flags & FL_ONGROUND);
341                 // dying animation
342                 self.deadflag = DEAD_DYING;
343                 // when to allow respawn
344                 self.death_time = time + 0.5;
345                 // when to switch to the dead_frame
346                 self.dead_time = time + 2;
347                 if (random() < 0.5)
348                 {
349                         self.die_frame = $die1;
350                         self.dead_frame = $dead1;
351                 }
352                 else
353                 {
354                         self.die_frame = $die2;
355                         self.dead_frame = $dead2;
356                 }
357                 // start the animation
358                 player_anim();
359                 // set damage function to corpse damage
360                 self.event_damage = PlayerCorpseDamage;
361                 // call the corpse damage function just in case it wants to gib
362                 self.event_damage(inflictor, attacker, 0, deathtype, hitloc, force);
363                 // set up to fade out later
364                 SUB_SetFade (self, time + 12 + random () * 4, 1);
365
366                 // remove laserdot
367                 remove(self.weaponentity.lasertarget);
368
369                 if(clienttype(self) == CLIENTTYPE_REAL)
370                 {
371                         self.fixangle = TRUE;
372                         //msg_entity = self;
373                         //WriteByte (MSG_ONE, SVC_SETANGLE);
374                         //WriteAngle (MSG_ONE, self.v_angle_x);
375                         //WriteAngle (MSG_ONE, self.v_angle_y);
376                         //WriteAngle (MSG_ONE, 80);
377                 }
378
379                 if(cvar("g_arena"))
380                         Spawnqueue_Unmark(self);
381         }
382 }
383