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
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
20 void CopyBody(float keepvelocity)
23 if (self.effects & EF_NODRAW)
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 self.gibrandom = oldself.gibrandom;
48 self.customizeentityforclient = oldself.customizeentityforclient;
49 if (keepvelocity == 1)
50 self.velocity = oldself.velocity;
51 self.oldvelocity = self.velocity;
52 self.fade_time = oldself.fade_time;
53 self.fade_rate = oldself.fade_rate;
54 //self.weapon = oldself.weapon;
55 setorigin(self, oldself.origin);
56 setsize(self, oldself.mins, oldself.maxs);
57 self.oldorigin = oldself.origin;
61 void player_anim (void)
63 if (self.deadflag != DEAD_NO)
65 if (time > self.dead_time)
70 setsize(self, self.mins, self.maxs);
72 self.frame = self.dead_frame;
75 self.frame = self.die_frame;
82 if (self.movement_x * self.movement_x + self.movement_y * self.movement_y > 20)
83 self.frame = $duckwalk;
85 self.frame = $duckidle;
87 else if ((self.movement_x * self.movement_x + self.movement_y * self.movement_y) > 20)
89 if (self.movement_x > 0 && self.movement_y == 0)
91 else if (self.movement_x < 0 && self.movement_y == 0)
92 self.frame = $runbackwards;
93 else if (self.movement_x == 0 && self.movement_y > 0)
94 self.frame = $straferight;
95 else if (self.movement_x == 0 && self.movement_y < 0)
96 self.frame = $strafeleft;
97 else if (self.movement_x > 0 && self.movement_y > 0)
98 self.frame = $forwardright;
99 else if (self.movement_x > 0 && self.movement_y < 0)
100 self.frame = $forwardleft;
101 else if (self.movement_x < 0 && self.movement_y > 0)
102 self.frame = $backright;
103 else if (self.movement_x < 0 && self.movement_y < 0)
104 self.frame = $backleft;
108 else if (self.pain_finished > time)
109 self.frame = self.pain_frame;
110 else if (ATTACK_FINISHED(self) > time)
115 if (!(self.flags & FL_ONGROUND))
118 self.frame = $duckidle; // if player is crouching while in air, show crouch frame
123 //End change by Supajoe on 11:44 PM EST 11/16/03 (Subject: Player animations)
125 void SpawnThrownWeapon (vector org, float w)
127 if (!cvar("g_pickup_items"))
128 if (!cvar("g_minstagib"))
135 W_ThrowWeapon(randomvec() * 100 + '0 0 200', org - self.origin, FALSE);
138 void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
140 local float take, save;
141 te_blood (hitloc, force, damage);
142 // damage resistance (ignore most of the damage from a bullet or similar)
143 damage = max(damage - 5, 1);
145 save = bound(0, damage * cvar("g_balance_armor_blockpercent"), self.armorvalue);
146 take = bound(0, damage - save, damage);
149 sound (self, CHAN_IMPACT, "misc/armorimpact.wav", 1, ATTN_NORM);
151 sound (self, CHAN_IMPACT, "misc/bodyimpact2.wav", 1, ATTN_NORM);
153 sound (self, CHAN_IMPACT, "misc/bodyimpact1.wav", 1, ATTN_NORM);
156 TossGib (world, "models/gibs/chunk.mdl", hitloc, force * -0.1,1);
158 TossGib (world, "models/gibs/chunk.mdl", hitloc, force * -0.2,1);
160 if (!(self.flags & FL_GODMODE))
162 self.armorvalue = self.armorvalue - save;
163 self.health = self.health - take;
164 // pause regeneration for 5 seconds
165 self.pauseregen_finished = max(self.pauseregen_finished, time + cvar("g_balance_pause_health_regen"));
167 self.dmg_save = self.dmg_save + save;//max(save - 10, 0);
168 self.dmg_take = self.dmg_take + take;//max(take - 10, 0);
169 self.dmg_inflictor = inflictor;
171 if (self.health <= -50)
173 // don't use any animations as a gib
177 // view just above the floor
178 self.view_ofs = '0 0 4';
181 local float multiplier;
185 te_bloodshower (self.origin + self.mins, self.origin + self.maxs, 1200 * multiplier, 1000);
188 TossGib (self, "models/gibs/eye.md3", self.origin, self.velocity,0);
189 TossGib (world, "models/gibs/bloodyskull.md3", self.origin, '0 0 600',0);
193 while (c < multiplier)
196 TossGib (world, "models/gibs/gib1.md3", self.origin, self.velocity,0);
197 //TossGib (world, "models/gibs/gib2.md3", self.origin, self.velocity,0);
198 TossGib (world, "models/gibs/gib1.mdl", self.origin, self.velocity,0);
199 //TossGib (world, "models/gibs/gib3.md3", self.origin, self.velocity,0);
200 TossGib (world, "models/gibs/gib2.mdl", self.origin, self.velocity,0);
201 //TossGib (world, "models/gibs/gib4.md3", self.origin, self.velocity,0);
202 TossGib (world, "models/gibs/gib3.mdl", self.origin, self.velocity,0);
204 // these destory on impact
205 TossGib (world, "models/gibs/gib5.md3", self.origin, '-500 0 450',1);
206 //TossGib (world, "models/gibs/gib6.md3", self.origin, '0 500 450',1);
207 TossGib (world, "models/gibs/chunk.mdl", self.origin, '0 -500 450',1);
208 TossGib (world, "models/gibs/chunk.mdl", self.origin, '500 0 450',1);
209 TossGib (world, "models/gibs/chunk.mdl", self.origin, self.velocity,1);
210 TossGib (world, "models/gibs/chunk.mdl", self.origin, '0 0 450',1);
213 sound (self, CHAN_VOICE, "misc/gib.wav", 1, ATTN_NORM);
217 void PlayerDamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
219 local float take, save, waves, sdelay;
221 damage = damage * bound(1.0, self.cvar_cl_handicap, 100.0);
223 te_blood (hitloc, force, damage);
224 if (self.pain_finished < time) //Don't switch pain sequences like crazy
227 self.pain_frame = $pain1;
229 self.pain_frame = $pain2;
230 self.pain_finished = time + 0.5; //Supajoe
232 // throw off bot aim temporarily
234 shake = damage * 5 / (bound(0,skill,100) + 1);
235 self.v_angle_x = self.v_angle_x + (random() * 2 - 1) * shake;
236 self.v_angle_y = self.v_angle_y + (random() * 2 - 1) * shake;
243 if (!cvar("g_minstagib"))
245 save = bound(0, damage * cvar("g_balance_armor_blockpercent"), self.armorvalue);
246 take = bound(0, damage - save, damage);
255 sound (self, CHAN_IMPACT, "misc/armorimpact.wav", 1, ATTN_NORM);
257 sound (self, CHAN_IMPACT, "misc/bodyimpact2.wav", 1, ATTN_NORM);
259 sound (self, CHAN_IMPACT, "misc/bodyimpact1.wav", 1, ATTN_NORM);
262 TossGib (world, "models/gibs/chunk.mdl", hitloc, force * -0.1,1);
264 TossGib (world, "models/gibs/chunk.mdl", hitloc, force * -0.2,1);
266 if (time > self.spawnshieldtime)
268 if (!(self.flags & FL_GODMODE))
270 self.armorvalue = self.armorvalue - save;
271 self.health = self.health - take;
272 // pause regeneration for 5 seconds
273 self.pauseregen_finished = max(self.pauseregen_finished, time + cvar("g_balance_pause_health_regen"));
276 self.max_armorvalue += (save + take);
278 self.dmg_save = self.dmg_save + save;//max(save - 10, 0);
279 self.dmg_take = self.dmg_take + take;//max(take - 10, 0);
280 self.dmg_inflictor = inflictor;
284 // don't reset pushltime for self damage as it may be an attempt to
285 // escape a lava pit or similar
286 //self.pushltime = 0;
288 else if(attacker.classname == "player" || attacker.classname == "gib")
290 self.pusher = attacker;
291 self.pushltime = time + cvar("g_maxpushtime");
293 else if(time < self.pushltime)
295 attacker = self.pusher;
296 self.pushltime = max(self.pushltime, time + 0.6);
305 // become fully visible
307 // clear selected player display
308 ClearSelectedPlayer();
310 SpawnThrownWeapon (self.origin + (self.mins + self.maxs) * 0.5, self.switchweapon);
311 // print an obituary message
312 Obituary (attacker, self, deathtype);
315 kh_Key_DropAll(self, TRUE);
316 else if(attacker.classname == "player" || attacker.classname == "gib")
317 kh_Key_DropAll(self, FALSE);
319 kh_Key_DropAll(self, TRUE);
321 DropFlag(self.flagcarried);
323 WaypointSprite_PlayerDead();
324 // make the corpse upright (not tilted)
328 self.avelocity = '0 0 0';
329 // view from the floor
330 self.view_ofs = '0 0 -8';
332 self.movetype = MOVETYPE_TOSS;
334 self.solid = SOLID_CORPSE;
335 // don't stick to the floor
336 self.flags = self.flags - (self.flags & FL_ONGROUND);
338 self.deadflag = DEAD_DYING;
339 // when to allow respawn
342 if(cvar("g_respawn_mapsettings"))
344 sdelay = cvar("g_respawn_mapsettings_delay");
345 waves = cvar("g_respawn_mapsettings_waves");
348 sdelay = cvar(strcat("g_", GetGametype(), "_respawn_delay"));
350 sdelay = cvar("g_respawn_delay");
352 waves = cvar(strcat("g_", GetGametype(), "_respawn_waves"));
354 waves = cvar("g_respawn_waves");
356 self.death_time = ceil((time + sdelay) / waves) * waves;
358 self.death_time = time + sdelay;
359 if((sdelay + waves >= 5.0) && (self.death_time - time > 1.75))
360 self.respawn_countdown = 10; // first number to count down from is 10
362 self.respawn_countdown = -1; // do not count down
363 // when to switch to the dead_frame
364 self.dead_time = time + 2;
367 self.die_frame = $die1;
368 self.dead_frame = $dead1;
372 self.die_frame = $die2;
373 self.dead_frame = $dead2;
375 // start the animation
377 // set damage function to corpse damage
378 self.event_damage = PlayerCorpseDamage;
379 // call the corpse damage function just in case it wants to gib
380 self.event_damage(inflictor, attacker, 0, deathtype, hitloc, force);
381 // set up to fade out later
382 SUB_SetFade (self, time + 12 + random () * 4, 1);
385 if(self.weaponentity)
386 if(self.weaponentity.lasertarget)
387 remove(self.weaponentity.lasertarget);
389 if(clienttype(self) == CLIENTTYPE_REAL)
391 self.fixangle = TRUE;
393 //WriteByte (MSG_ONE, SVC_SETANGLE);
394 //WriteAngle (MSG_ONE, self.v_angle_x);
395 //WriteAngle (MSG_ONE, self.v_angle_y);
396 //WriteAngle (MSG_ONE, 80);
400 Spawnqueue_Unmark(self);
404 float UpdateSelectedPlayer_countvalue(float v)
406 return max(0, (v - 1.0) / 0.5);
409 // returns: -2 if no hit, otherwise cos of the angle
410 // uses the global v_angle
411 float UpdateSelectedPlayer_canSee(entity p, float mincosangle, float maxdist)
422 so = self.origin + self.view_ofs;
426 if(dist_point_line(d, '0 0 0', v_forward) > maxdist)
429 // now find the cos of the angle...
430 c = normalize(d) * v_forward;
435 traceline(so, p.origin, MOVE_NOMONSTERS, self);
436 if(trace_fraction < 1)
442 void ClearSelectedPlayer()
444 if(self.selected_player)
446 centerprint_expire(self, CENTERPRIO_POINT);
447 self.selected_player = world;
448 self.selected_player_display_needs_update = FALSE;
452 void UpdateSelectedPlayer()
455 float selected_score;
457 selected_score = 0.95; // 18 degrees
459 if(!cvar("sv_allow_shownames"))
462 if(clienttype(self) != CLIENTTYPE_REAL)
465 if(self.cvar_cl_shownames == 0)
468 if(self.cvar_cl_shownames == 1 && !teams_matter)
471 makevectors(self.v_angle); // sets v_forward
473 // 1. cursor trace is always right
474 if(self.cursor_trace_ent && self.cursor_trace_ent.classname == "player" && !self.cursor_trace_ent.deadflag)
476 selected = self.cursor_trace_ent;
480 // 2. if we don't have a cursor trace, find the player which is least
486 c = UpdateSelectedPlayer_canSee(p, selected_score, 100); // 100 = 2.5 meters
497 self.selected_player_display_timeout = time + self.cvar_scr_centertime;
501 if(time < self.selected_player_display_timeout)
502 if(UpdateSelectedPlayer_canSee(self.selected_player, 0.7, 200) >= -1) // 5 meters, 45 degrees
503 selected = self.selected_player;
508 if(selected == self.selected_player)
511 save = UpdateSelectedPlayer_countvalue(self.selected_player_count);
512 self.selected_player_count = self.selected_player_count + frametime;
513 if(save != UpdateSelectedPlayer_countvalue(self.selected_player_count))
515 string namestr, healthstr;
516 namestr = playername(selected);
519 healthstr = ftos(floor(selected.health));
520 if(self.team == selected.team)
522 namestr = strcat(namestr, " (", healthstr, "%)");
523 self.selected_player_display_needs_update = TRUE;
526 centerprint_atprio(self, CENTERPRIO_POINT, namestr);
531 ClearSelectedPlayer();
532 self.selected_player = selected;
533 self.selected_player_time = time;
534 self.selected_player_count = 0;
535 self.selected_player_display_needs_update = FALSE;
540 ClearSelectedPlayer();
543 if(self.selected_player)
544 self.last_selected_player = self.selected_player;