mirror of
https://github.com/nzp-team/quakec.git
synced 2024-11-22 03:41:15 +00:00
Merge pull request #81 from nzp-team/cypress_laststand
SERVER: Last Stand and Revive Overhaul
This commit is contained in:
commit
9fc6f93e77
11 changed files with 620 additions and 413 deletions
|
@ -30,12 +30,13 @@ main.qc
|
||||||
utilities/weapon_utilities.qc
|
utilities/weapon_utilities.qc
|
||||||
utilities/game_restart.qc
|
utilities/game_restart.qc
|
||||||
utilities/command_parser.qc
|
utilities/command_parser.qc
|
||||||
player.qc
|
player/player_core.qc
|
||||||
damage.qc
|
damage.qc
|
||||||
|
player/spawn_points.qc
|
||||||
|
player/last_stand.qc
|
||||||
entities/sub_functions.qc
|
entities/sub_functions.qc
|
||||||
entities/sounds.qc
|
entities/sounds.qc
|
||||||
entities/triggers.qc
|
entities/triggers.qc
|
||||||
entities/spawn_points.qc
|
|
||||||
entities/explosive_barrel.qc
|
entities/explosive_barrel.qc
|
||||||
entities/teleporter.qc
|
entities/teleporter.qc
|
||||||
entities/map_entities.qc
|
entities/map_entities.qc
|
||||||
|
|
|
@ -101,10 +101,7 @@ var struct revive_s {
|
||||||
float draw;
|
float draw;
|
||||||
float timer;
|
float timer;
|
||||||
float state;
|
float state;
|
||||||
float org[3];
|
} revive_icons[4]; // MAX_CLIENTS
|
||||||
} revive_icons[4];
|
|
||||||
|
|
||||||
float active_revive_icons;
|
|
||||||
|
|
||||||
float weaponframetime;
|
float weaponframetime;
|
||||||
float weapon2frametime;
|
float weapon2frametime;
|
||||||
|
|
|
@ -1724,27 +1724,51 @@ void(float width, float height) HUD_PlayerNames =
|
||||||
|
|
||||||
void(float width, float height) HUD_ReviveIcons =
|
void(float width, float height) HUD_ReviveIcons =
|
||||||
{
|
{
|
||||||
for (float i = 0; i < active_revive_icons; i++) {
|
for (float i = 3; i >= 0; i = i - 1) {
|
||||||
if (revive_icons[i].draw == true) {
|
float player_index = i;
|
||||||
revive_icons[i].timer += frametime;
|
|
||||||
vector revive_origin;
|
// Don't render our own Icon.
|
||||||
revive_origin_x = revive_icons[i].org[0];
|
if (player_index + 1 == getstatf(STAT_PLAYERNUM))
|
||||||
revive_origin_y = revive_icons[i].org[1];
|
continue;
|
||||||
revive_origin_z = revive_icons[i].org[2];
|
|
||||||
vector screen_position = project(revive_origin);
|
// Player is not in Last Stand.
|
||||||
|
if (revive_icons[player_index].state <= 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Player is not being actively revived, so the
|
||||||
|
// Revive Icon should grow more and more red over time.
|
||||||
|
if (revive_icons[player_index].state == 1)
|
||||||
|
revive_icons[player_index].timer += frametime;
|
||||||
|
|
||||||
|
float player_number = getplayerkeyfloat(i, "viewentity");
|
||||||
|
|
||||||
|
//string text = getplayerkeyvalue(i, "name");
|
||||||
|
entity client = findfloat(world, playernum, player_number);
|
||||||
|
|
||||||
|
// Client does not exist/is spectating.
|
||||||
|
if (client == world || client.movetype == MOVETYPE_BOUNCE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
entity plr = findfloat(world, playernum, player_number);
|
||||||
|
vector player_origin = plr.origin + '0 0 32';
|
||||||
|
vector screen_position = project(player_origin);
|
||||||
screen_position_x -= (32)/2;
|
screen_position_x -= (32)/2;
|
||||||
|
|
||||||
|
if (player_origin == '0 0 32')
|
||||||
|
continue;
|
||||||
|
|
||||||
if (screen_position_z > 0) {
|
if (screen_position_z > 0) {
|
||||||
// being revived
|
// Client is actively being revived, render white.
|
||||||
if (revive_icons[i].state == 2)
|
if (revive_icons[i].state == 2) {
|
||||||
drawpic(screen_position, "gfx/hud/revive_icon.tga", [32, 32, 1], [1,1,1], 1);
|
drawpic(screen_position, "gfx/hud/revive_icon.tga", [32, 32, 1], [1,1,1], 1);
|
||||||
|
}
|
||||||
|
// Draw with a yellow->red hue.
|
||||||
else {
|
else {
|
||||||
drawpic(screen_position, "gfx/hud/revive_icon.tga", [32, 32, 1], [1,1 - (revive_icons[i].timer/30),0], 1);
|
drawpic(screen_position, "gfx/hud/revive_icon.tga", [32, 32, 1], [1,1 - (revive_icons[i].timer/30),0], 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void(float width, float height) HUD_StopWatch =
|
void(float width, float height) HUD_StopWatch =
|
||||||
{
|
{
|
||||||
|
|
|
@ -1076,28 +1076,20 @@ noref void() CSQC_Parse_Event =
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EVENT_REVIVECHANGE:
|
case EVENT_REVIVECHANGE:
|
||||||
float revivechange_id = readbyte();
|
float revivechange_player_index = readbyte() - 1; // playernum starts at one.
|
||||||
float state = readbyte();
|
float state = readbyte();
|
||||||
revive_icons[revivechange_id].state = state;
|
revive_icons[revivechange_player_index].state = state;
|
||||||
break;
|
break;
|
||||||
case EVENT_REVIVEON:
|
case EVENT_REVIVEON:
|
||||||
float reviveon_id = readbyte();
|
float reviveon_player_index = readbyte() - 1; // playernum starts at one.
|
||||||
revive_icons[reviveon_id].org[0] = readcoord();
|
revive_icons[reviveon_player_index].state = 1;
|
||||||
revive_icons[reviveon_id].org[1] = readcoord();
|
revive_icons[reviveon_player_index].draw = true;
|
||||||
revive_icons[reviveon_id].org[2] = readcoord();
|
|
||||||
revive_icons[reviveon_id].state = 1;
|
|
||||||
revive_icons[reviveon_id].draw = true;
|
|
||||||
active_revive_icons++;
|
|
||||||
break;
|
break;
|
||||||
case EVENT_REVIVEOFF:
|
case EVENT_REVIVEOFF:
|
||||||
float reviveoff_id = readbyte();
|
float reviveoff_player_index = readbyte() - 1; // playernum starts at one.
|
||||||
revive_icons[reviveoff_id].org[0] = 0;
|
revive_icons[reviveoff_player_index].state = 0;
|
||||||
revive_icons[reviveoff_id].org[1] = 0;
|
revive_icons[reviveoff_player_index].timer = 0;
|
||||||
revive_icons[reviveoff_id].org[2] = 0;
|
revive_icons[reviveoff_player_index].draw = false;
|
||||||
revive_icons[reviveoff_id].state = 0;
|
|
||||||
revive_icons[reviveoff_id].timer = 0;
|
|
||||||
revive_icons[reviveoff_id].draw = false;
|
|
||||||
active_revive_icons--;
|
|
||||||
break;
|
break;
|
||||||
case EVENT_MAPTYPE:
|
case EVENT_MAPTYPE:
|
||||||
map_compatibility_mode = readbyte();
|
map_compatibility_mode = readbyte();
|
||||||
|
|
|
@ -155,29 +155,26 @@ void(float round) FTE_IncrementRound =
|
||||||
|
|
||||||
#endif // FTE
|
#endif // FTE
|
||||||
|
|
||||||
void(float index, float state) ChangeReviveIconState =
|
void(float player_index, float state) ChangeReviveIconState =
|
||||||
{
|
{
|
||||||
#ifdef FTE
|
#ifdef FTE
|
||||||
|
|
||||||
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
|
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
|
||||||
WriteByte(MSG_MULTICAST, EVENT_REVIVECHANGE);
|
WriteByte(MSG_MULTICAST, EVENT_REVIVECHANGE);
|
||||||
WriteByte(MSG_MULTICAST, index);
|
WriteByte(MSG_MULTICAST, player_index);
|
||||||
WriteByte(MSG_MULTICAST, state);
|
WriteByte(MSG_MULTICAST, state);
|
||||||
multicast('0 0 0', MULTICAST_ALL);
|
multicast('0 0 0', MULTICAST_ALL);
|
||||||
|
|
||||||
#endif // FTE
|
#endif // FTE
|
||||||
}
|
}
|
||||||
|
|
||||||
void(float index, vector org) EnableReviveIcon =
|
void(float player_index) EnableReviveIcon =
|
||||||
{
|
{
|
||||||
#ifdef FTE
|
#ifdef FTE
|
||||||
|
|
||||||
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
|
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
|
||||||
WriteByte(MSG_MULTICAST, EVENT_REVIVEON);
|
WriteByte(MSG_MULTICAST, EVENT_REVIVEON);
|
||||||
WriteByte(MSG_MULTICAST, index);
|
WriteByte(MSG_MULTICAST, player_index);
|
||||||
WriteCoord(MSG_MULTICAST, org_x);
|
|
||||||
WriteCoord(MSG_MULTICAST, org_y);
|
|
||||||
WriteCoord(MSG_MULTICAST, org_z);
|
|
||||||
multicast('0 0 0', MULTICAST_ALL);
|
multicast('0 0 0', MULTICAST_ALL);
|
||||||
|
|
||||||
#endif // FTE
|
#endif // FTE
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
*/
|
*/
|
||||||
void (float achievement_id, optional entity who) GiveAchievement;
|
void (float achievement_id, optional entity who) GiveAchievement;
|
||||||
|
void(entity client) LastStand_Begin;
|
||||||
|
|
||||||
#define DMG_SCORE_HEADSHOT 100 // Death by Headshot
|
#define DMG_SCORE_HEADSHOT 100 // Death by Headshot
|
||||||
#define DMG_SCORE_MELEE 130 // Death by Melee
|
#define DMG_SCORE_MELEE 130 // Death by Melee
|
||||||
|
@ -158,213 +159,7 @@ void() EndGameSetup =
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// rec_downed is used as a recursive loop where we consistently check to see if ALL players are downed
|
|
||||||
// if they aren't dead, we keep looping until our OWN death (45 seconds, so 300 loops)
|
|
||||||
void() rec_downed =
|
|
||||||
{
|
|
||||||
if (!self.beingrevived)
|
|
||||||
self.downedloop += 1;
|
|
||||||
|
|
||||||
if (self.downedloop >= 30) {
|
|
||||||
DisableReviveIcon(self.electro_targeted);
|
|
||||||
revive_index--;
|
|
||||||
startspectate();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
float gotalive = PollPlayersAlive();
|
|
||||||
|
|
||||||
if (!gotalive && !self.progress_bar) {
|
|
||||||
EndGameSetup();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.think = rec_downed;
|
|
||||||
self.nextthink = time + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
float() push_away_zombies;
|
float() push_away_zombies;
|
||||||
void() GetDown =
|
|
||||||
{
|
|
||||||
// 'Pro Gamer Move' achievement.
|
|
||||||
if (rounds <= 1 && self.weapons[0].weapon_magazine == 0 &&
|
|
||||||
self.weapons[0].weapon_magazine_left == 0 && self.weapons[0].weapon_reserve == 0 &&
|
|
||||||
self.weapons[1].weapon_magazine == 0 && self.weapons[1].weapon_magazine_left == 0 &&
|
|
||||||
self.weapons[1].weapon_reserve == 0) {
|
|
||||||
GiveAchievement(9, self);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Aim out to reset zoom values
|
|
||||||
W_AimOut();
|
|
||||||
|
|
||||||
#ifdef FTE
|
|
||||||
|
|
||||||
self.viewzoom = 1;
|
|
||||||
|
|
||||||
#endif // FTE
|
|
||||||
|
|
||||||
// Make any zombies inside of the player's bounding box leave
|
|
||||||
push_away_zombies();
|
|
||||||
|
|
||||||
// Force the player to prone.
|
|
||||||
Player_SetStance(self, PLAYER_STANCE_PRONE, false);
|
|
||||||
|
|
||||||
// Get rid of Mule Kick Weapon
|
|
||||||
for(float i = 0; i < MAX_PLAYER_WEAPONS; i++) {
|
|
||||||
if (self.weapons[i].is_mulekick_weapon == true) {
|
|
||||||
Weapon_RemoveWeapon(i);
|
|
||||||
Weapon_SetActiveInSlot(0, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate the loss in points, take away points from downed Player.
|
|
||||||
float point_difference;
|
|
||||||
point_difference = self.points;
|
|
||||||
point_difference -= 10*rint((self.points*0.95)/10);
|
|
||||||
Player_RemoveScore(self, point_difference);
|
|
||||||
|
|
||||||
self.requirespower = point_difference;
|
|
||||||
|
|
||||||
#ifdef FTE
|
|
||||||
|
|
||||||
// FTE-Specific: Broadcast that the player has downed to everyone.
|
|
||||||
FTE_BroadcastMessage(world, CSQC_BROADCAST_PLAYERDOWNED, 3, self.playernum);
|
|
||||||
|
|
||||||
#endif // FTE
|
|
||||||
|
|
||||||
// Reset state
|
|
||||||
self.velocity = self.zoom = 0;
|
|
||||||
self.downed = true;
|
|
||||||
self.dive_delay = 0;
|
|
||||||
|
|
||||||
float players_still_alive = PollPlayersAlive();
|
|
||||||
|
|
||||||
if ((player_count && !players_still_alive) || (!player_count && !(self.perks & P_REVIVE))) {
|
|
||||||
EndGameSetup();
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
self.health = 19;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initiate Self-Revive on Solo
|
|
||||||
if ((self.perks & P_REVIVE) && !player_count) {
|
|
||||||
self.progress_bar = 10 + time;
|
|
||||||
self.progress_bar_time = 10;
|
|
||||||
self.progress_bar_percent = 1;
|
|
||||||
|
|
||||||
#ifdef FTE
|
|
||||||
|
|
||||||
// FTE-Specific: Broadcast to the player they're reviving themselves.
|
|
||||||
FTE_BroadcastMessage(self, CSQC_BROADCAST_REVIVINGPLAYER, 3, self.playernum);
|
|
||||||
|
|
||||||
#endif // FTE
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Take away weapons and Perks
|
|
||||||
self.perks = 0;
|
|
||||||
|
|
||||||
self.weaponbk = self.weapon;
|
|
||||||
self.currentammobk = self.weapons[0].weapon_reserve;
|
|
||||||
self.currentmagbk = self.weapons[0].weapon_magazine;
|
|
||||||
self.currentmagbk2 = self.weapons[0].weapon_magazine_left;
|
|
||||||
|
|
||||||
//Reset the tracker for the achievement "No Perks? No Problem"
|
|
||||||
self.ach_tracker_npnp = 0;
|
|
||||||
|
|
||||||
// Reset Juggernog health
|
|
||||||
self.max_health = self.health = PLAYER_START_HEALTH;
|
|
||||||
|
|
||||||
if(Weapon_PlayerHasWeapon(self, W_BIATCH, false) ||
|
|
||||||
Weapon_PlayerHasWeapon(self, W_RAY, true) ||
|
|
||||||
Weapon_PlayerHasWeapon(self, W_357, true)) {
|
|
||||||
float weapon_slot;
|
|
||||||
float total_ammo;
|
|
||||||
total_ammo = 0;
|
|
||||||
|
|
||||||
weapon_slot = Weapon_PlayerHasWeapon(self, W_RAY, true);
|
|
||||||
if (weapon_slot == 0) weapon_slot = Weapon_PlayerHasWeapon(self, W_BIATCH, false);
|
|
||||||
if (weapon_slot == 0) weapon_slot = Weapon_PlayerHasWeapon(self, W_357, true);
|
|
||||||
|
|
||||||
switch(weapon_slot) {
|
|
||||||
case 1:
|
|
||||||
total_ammo = self.weapons[0].weapon_magazine + self.weapons[0].weapon_magazine_left + self.weapons[0].weapon_reserve;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
total_ammo = self.weapons[1].weapon_magazine + self.weapons[1].weapon_magazine_left + self.weapons[1].weapon_reserve;
|
|
||||||
Weapon_SwapWeapons(true);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.weaponbk = self.weapon;
|
|
||||||
self.currentammobk = self.weapons[0].weapon_reserve;
|
|
||||||
self.currentmagbk = self.weapons[0].weapon_magazine;
|
|
||||||
self.currentmagbk2 = self.weapons[0].weapon_magazine_left;
|
|
||||||
|
|
||||||
// If it's greater than the mag size, we can fill the magazine.
|
|
||||||
if (total_ammo > getWeaponMag(self.weapon) || total_ammo == 0) {
|
|
||||||
self.weapons[0].weapon_magazine = getWeaponMag(self.weapon);
|
|
||||||
|
|
||||||
// subtract it from the total ammo
|
|
||||||
if (total_ammo != 0)
|
|
||||||
total_ammo -= self.weapons[0].weapon_magazine;
|
|
||||||
} else {
|
|
||||||
self.weapons[0].weapon_magazine = total_ammo;
|
|
||||||
total_ammo = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for dual wield mag too
|
|
||||||
if (IsDualWeapon(self.weapon)) {
|
|
||||||
if (total_ammo > getWeaponMag(self.weapon) || total_ammo == 0) {
|
|
||||||
self.weapons[0].weapon_magazine_left = getWeaponMag(self.weapon);
|
|
||||||
|
|
||||||
// subtract it from the total ammo
|
|
||||||
if (total_ammo != 0)
|
|
||||||
total_ammo -= self.weapons[0].weapon_magazine_left;
|
|
||||||
} else {
|
|
||||||
self.weapons[0].weapon_magazine_left = total_ammo;
|
|
||||||
total_ammo = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ray Gun has a special case where we DON'T fill its reserve
|
|
||||||
if (self.weapon != W_RAY && self.weapon != W_PORTER) {
|
|
||||||
// Now see if the reserve ammo is more than max downed capacity
|
|
||||||
if (total_ammo > getWeaponMag(self.weapon)*2) {
|
|
||||||
self.weapons[0].weapon_reserve = getWeaponMag(self.weapon)*2;
|
|
||||||
} else {
|
|
||||||
// It's not so just fill it
|
|
||||||
self.weapons[0].weapon_reserve = total_ammo;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.weapons[0].weapon_reserve = 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!player_count) {
|
|
||||||
Weapon_AssignWeapon(0, W_BIATCH, 6, 12);
|
|
||||||
} else {
|
|
||||||
Weapon_AssignWeapon(0, W_COLT, 8, 16);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Play Switch Animation
|
|
||||||
self.weaponmodel = GetWeaponModel(self.weapon, 0);
|
|
||||||
|
|
||||||
float startframe = GetFrame(self.weapon,TAKE_OUT_START);
|
|
||||||
float endframe = GetFrame(self.weapon,TAKE_OUT_END);
|
|
||||||
Set_W_Frame (startframe, endframe, 0, 0, 0, SUB_Null, self.weaponmodel, false, S_BOTH);
|
|
||||||
|
|
||||||
// Spawn Revive Sprite in Co-Op
|
|
||||||
if (player_count) {
|
|
||||||
EnableReviveIcon(revive_index, self.origin + VIEW_OFS_HL);
|
|
||||||
self.electro_targeted = revive_index;
|
|
||||||
revive_index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Play Last Stand Animation
|
|
||||||
PAnim_GetDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
void () GetUp =
|
void () GetUp =
|
||||||
{
|
{
|
||||||
|
@ -405,10 +200,6 @@ void () GetUp =
|
||||||
|
|
||||||
self.teslacount = 0;
|
self.teslacount = 0;
|
||||||
|
|
||||||
if (!player_count) {
|
|
||||||
Player_AddScore(self, self.requirespower, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
Weapon_AssignWeapon(0, self.weaponbk, self.currentmagbk, self.currentammobk);
|
Weapon_AssignWeapon(0, self.weaponbk, self.currentmagbk, self.currentammobk);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -417,8 +208,7 @@ void(entity ent) CheckRevive =
|
||||||
{
|
{
|
||||||
if (self.invoke_revive) {
|
if (self.invoke_revive) {
|
||||||
GetUp();
|
GetUp();
|
||||||
DisableReviveIcon(self.electro_targeted);
|
DisableReviveIcon(self.playernum);
|
||||||
revive_index--;
|
|
||||||
self.invoke_revive = 0;
|
self.invoke_revive = 0;
|
||||||
self.firer = world;
|
self.firer = world;
|
||||||
}
|
}
|
||||||
|
@ -561,10 +351,7 @@ void(entity victim, entity attacker, float damage, float d_style) DamageHandler
|
||||||
// Was 20 for.. some reason.
|
// Was 20 for.. some reason.
|
||||||
if (victim.health <= 1)
|
if (victim.health <= 1)
|
||||||
{
|
{
|
||||||
old_self = self;
|
LastStand_Begin(victim);
|
||||||
self = victim;
|
|
||||||
GetDown();
|
|
||||||
self = old_self;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -627,8 +627,6 @@ float G_PERKPOWER;
|
||||||
.float renderamt;
|
.float renderamt;
|
||||||
.vector rendercolor;
|
.vector rendercolor;
|
||||||
|
|
||||||
float revive_index;
|
|
||||||
|
|
||||||
#ifdef FTE
|
#ifdef FTE
|
||||||
.float last_solid;
|
.float last_solid;
|
||||||
.float had_solid_modified;
|
.float had_solid_modified;
|
||||||
|
|
505
source/server/player/last_stand.qc
Normal file
505
source/server/player/last_stand.qc
Normal file
|
@ -0,0 +1,505 @@
|
||||||
|
/*
|
||||||
|
server/player/last_stand.qc
|
||||||
|
|
||||||
|
Logic for Last Stand and Player Reviving.
|
||||||
|
|
||||||
|
Copyright (C) 2021-2024 NZ:P Team
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to:
|
||||||
|
|
||||||
|
Free Software Foundation, Inc.
|
||||||
|
59 Temple Place - Suite 330
|
||||||
|
Boston, MA 02111-1307, USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define LASTSTAND_DEATH_TIMER 30
|
||||||
|
|
||||||
|
void() W_TakeOut;
|
||||||
|
|
||||||
|
//
|
||||||
|
// LastStand_SoloRevive()
|
||||||
|
// Gets the client out of last stand after solo revive
|
||||||
|
// timer has completed.
|
||||||
|
//
|
||||||
|
void() LastStand_SoloRevive =
|
||||||
|
{
|
||||||
|
entity old_self = self;
|
||||||
|
self = self.owner;
|
||||||
|
GetUp();
|
||||||
|
self = old_self;
|
||||||
|
|
||||||
|
// Give the player their score back.
|
||||||
|
Player_AddScore(self.owner, self.owner.requirespower, false);
|
||||||
|
|
||||||
|
// No need for us to exist anymore, goodbye!
|
||||||
|
remove(self);
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// LastStand_InitiateSoloRevive(client)
|
||||||
|
// Kicks off the timer set when a player enters Last
|
||||||
|
// Stand with Quick Revive in solo.
|
||||||
|
//
|
||||||
|
void(entity client) LastStand_InitiateSoloRevive =
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifdef FTE
|
||||||
|
|
||||||
|
// FTE-Specific: Broadcast to the player they're reviving themselves.
|
||||||
|
FTE_BroadcastMessage(client, CSQC_BROADCAST_REVIVINGPLAYER, 3, client.playernum);
|
||||||
|
|
||||||
|
#endif // FTE
|
||||||
|
|
||||||
|
// Create a new entity to "watch" and be the revivee.
|
||||||
|
entity watcher = spawn();
|
||||||
|
watcher.owner = client;
|
||||||
|
watcher.think = LastStand_SoloRevive;
|
||||||
|
watcher.nextthink = time + 10;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// LastStand_Penalize(client)
|
||||||
|
// Client entered Last Stand, remove their perks and
|
||||||
|
// other minor things.
|
||||||
|
//
|
||||||
|
void(entity client) LastStand_Penalize =
|
||||||
|
{
|
||||||
|
// Reset bought Perk-A-Colas.
|
||||||
|
client.perks = 0;
|
||||||
|
|
||||||
|
// Set Max Health to that of without Jugger-Nog.
|
||||||
|
client.max_health = client.health = PLAYER_START_HEALTH;
|
||||||
|
|
||||||
|
// Get rid of Mule Kick Weapon
|
||||||
|
for(float i = 0; i < MAX_PLAYER_WEAPONS; i++) {
|
||||||
|
if (client.weapons[i].is_mulekick_weapon == true) {
|
||||||
|
entity old_self = self;
|
||||||
|
self = client;
|
||||||
|
Weapon_RemoveWeapon(i);
|
||||||
|
Weapon_SetActiveInSlot(0, false);
|
||||||
|
self = old_self;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// LastStand_AssignWeapon(client)
|
||||||
|
// Chooses what weapon to hand off to the player
|
||||||
|
// based on their loadout upon entering Last
|
||||||
|
// Stand.
|
||||||
|
//
|
||||||
|
void(entity client) LastStand_AssignWeapon =
|
||||||
|
{
|
||||||
|
entity old_self = self;
|
||||||
|
self = client;
|
||||||
|
|
||||||
|
client.weaponbk = self.weapon;
|
||||||
|
client.currentammobk = self.weapons[0].weapon_reserve;
|
||||||
|
client.currentmagbk = self.weapons[0].weapon_magazine;
|
||||||
|
client.currentmagbk2 = self.weapons[0].weapon_magazine_left;
|
||||||
|
|
||||||
|
if(Weapon_PlayerHasWeapon(self, W_BIATCH, false) ||
|
||||||
|
Weapon_PlayerHasWeapon(self, W_RAY, true) ||
|
||||||
|
Weapon_PlayerHasWeapon(self, W_357, true)) {
|
||||||
|
float weapon_slot;
|
||||||
|
float total_ammo;
|
||||||
|
total_ammo = 0;
|
||||||
|
|
||||||
|
weapon_slot = Weapon_PlayerHasWeapon(self, W_RAY, true);
|
||||||
|
if (weapon_slot == 0) weapon_slot = Weapon_PlayerHasWeapon(self, W_BIATCH, false);
|
||||||
|
if (weapon_slot == 0) weapon_slot = Weapon_PlayerHasWeapon(self, W_357, true);
|
||||||
|
|
||||||
|
switch(weapon_slot) {
|
||||||
|
case 1:
|
||||||
|
total_ammo = self.weapons[0].weapon_magazine + self.weapons[0].weapon_magazine_left + self.weapons[0].weapon_reserve;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
total_ammo = self.weapons[1].weapon_magazine + self.weapons[1].weapon_magazine_left + self.weapons[1].weapon_reserve;
|
||||||
|
Weapon_SwapWeapons(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.weaponbk = self.weapon;
|
||||||
|
self.currentammobk = self.weapons[0].weapon_reserve;
|
||||||
|
self.currentmagbk = self.weapons[0].weapon_magazine;
|
||||||
|
self.currentmagbk2 = self.weapons[0].weapon_magazine_left;
|
||||||
|
|
||||||
|
// If it's greater than the mag size, we can fill the magazine.
|
||||||
|
if (total_ammo > getWeaponMag(self.weapon) || total_ammo == 0) {
|
||||||
|
self.weapons[0].weapon_magazine = getWeaponMag(self.weapon);
|
||||||
|
|
||||||
|
// subtract it from the total ammo
|
||||||
|
if (total_ammo != 0)
|
||||||
|
total_ammo -= self.weapons[0].weapon_magazine;
|
||||||
|
} else {
|
||||||
|
self.weapons[0].weapon_magazine = total_ammo;
|
||||||
|
total_ammo = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for dual wield mag too
|
||||||
|
if (IsDualWeapon(self.weapon)) {
|
||||||
|
if (total_ammo > getWeaponMag(self.weapon) || total_ammo == 0) {
|
||||||
|
self.weapons[0].weapon_magazine_left = getWeaponMag(self.weapon);
|
||||||
|
|
||||||
|
// subtract it from the total ammo
|
||||||
|
if (total_ammo != 0)
|
||||||
|
total_ammo -= self.weapons[0].weapon_magazine_left;
|
||||||
|
} else {
|
||||||
|
self.weapons[0].weapon_magazine_left = total_ammo;
|
||||||
|
total_ammo = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ray Gun has a special case where we DON'T fill its reserve
|
||||||
|
if (self.weapon != W_RAY && self.weapon != W_PORTER) {
|
||||||
|
// Now see if the reserve ammo is more than max downed capacity
|
||||||
|
if (total_ammo > getWeaponMag(self.weapon)*2) {
|
||||||
|
self.weapons[0].weapon_reserve = getWeaponMag(self.weapon)*2;
|
||||||
|
} else {
|
||||||
|
// It's not so just fill it
|
||||||
|
self.weapons[0].weapon_reserve = total_ammo;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.weapons[0].weapon_reserve = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!player_count) {
|
||||||
|
Weapon_AssignWeapon(0, W_BIATCH, 6, 12);
|
||||||
|
} else {
|
||||||
|
Weapon_AssignWeapon(0, W_COLT, 8, 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Play Switch Animation
|
||||||
|
self.weaponmodel = GetWeaponModel(self.weapon, 0);
|
||||||
|
|
||||||
|
float startframe = GetFrame(self.weapon,TAKE_OUT_START);
|
||||||
|
float endframe = GetFrame(self.weapon,TAKE_OUT_END);
|
||||||
|
Set_W_Frame (startframe, endframe, 0, 0, 0, SUB_Null, self.weaponmodel, false, S_BOTH);
|
||||||
|
|
||||||
|
self = old_self;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// LastStand_KillPlayer(client)
|
||||||
|
// Player has bled out, force them into
|
||||||
|
// a spectator position.
|
||||||
|
//
|
||||||
|
void(entity client) LastStand_KillPlayer =
|
||||||
|
{
|
||||||
|
entity old_self = self;
|
||||||
|
self = client;
|
||||||
|
|
||||||
|
DisableReviveIcon(self.playernum);
|
||||||
|
startspectate();
|
||||||
|
|
||||||
|
self = old_self;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// LastStand_ReviveTriggerFollow()
|
||||||
|
// Updates the position of the revive trigger
|
||||||
|
// to always track it's owner (downed client),
|
||||||
|
// also handles bleed-out checks.
|
||||||
|
//
|
||||||
|
void() LastStand_ReviveTriggerFollow =
|
||||||
|
{
|
||||||
|
setorigin(self, self.owner.origin);
|
||||||
|
self.nextthink = time + 1;
|
||||||
|
|
||||||
|
// Iterate our death timer if we're not being revived.
|
||||||
|
if (self.owner.beingrevived == false)
|
||||||
|
self.downed++;
|
||||||
|
|
||||||
|
if (self.downed >= LASTSTAND_DEATH_TIMER) {
|
||||||
|
// Kill our owner.
|
||||||
|
LastStand_KillPlayer(self.owner);
|
||||||
|
|
||||||
|
// Kill ourselves.
|
||||||
|
remove(self);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// LastStand_UnlinkRevivee(client)
|
||||||
|
// Reviving has stopped, revert the state of
|
||||||
|
// both clients where necessary.
|
||||||
|
//
|
||||||
|
void(entity client) LastStand_UnlinkRevivee =
|
||||||
|
{
|
||||||
|
// We can move again.
|
||||||
|
client.speed_penalty = client.speed_penalty_time = 0;
|
||||||
|
|
||||||
|
// We're no longer being revived.
|
||||||
|
client.beingrevived = false;
|
||||||
|
|
||||||
|
// Remove our broadcast messages for visual feedback.
|
||||||
|
#ifdef FTE
|
||||||
|
|
||||||
|
FTE_BroadcastMessage(client, CSQC_BROADCAST_NONE, 0, client.playernum);
|
||||||
|
|
||||||
|
if (client.firer != world)
|
||||||
|
FTE_BroadcastMessage(client.firer, CSQC_BROADCAST_NONE, 0, client.playernum);
|
||||||
|
|
||||||
|
#endif // FTE
|
||||||
|
|
||||||
|
if (client.firer != world) {
|
||||||
|
entity old_self = self;
|
||||||
|
self = client.firer;
|
||||||
|
|
||||||
|
// The previous revivee should deploy their active weapon.
|
||||||
|
W_TakeOut();
|
||||||
|
|
||||||
|
// We should also reset their progress bar state.
|
||||||
|
Player_RemoveProgressBar(self);
|
||||||
|
|
||||||
|
self = old_self;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We no longer have an active revivee.
|
||||||
|
client.firer.firer = world;
|
||||||
|
client.firer = world;
|
||||||
|
|
||||||
|
// Revert our revive indicator.
|
||||||
|
ChangeReviveIconState(client.playernum, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// LastStand_LinkRevivee(downed_client, revivee)
|
||||||
|
// Reviving has been initiated, link the two clients to
|
||||||
|
// one another for state tracking.
|
||||||
|
//
|
||||||
|
void(entity downed_client, entity revivee) LastStand_LinkRevivee =
|
||||||
|
{
|
||||||
|
// We are, in fact, being revived.
|
||||||
|
downed_client.beingrevived = true;
|
||||||
|
|
||||||
|
// Link the downed team mate to the client who
|
||||||
|
// initiated the revive.
|
||||||
|
downed_client.firer = revivee;
|
||||||
|
revivee.firer = downed_client;
|
||||||
|
|
||||||
|
// Downed player should no longer be able to crawl
|
||||||
|
downed_client.speed_penalty = 0.01;
|
||||||
|
downed_client.speed_penalty_time = time + 100;
|
||||||
|
|
||||||
|
// Set our revive indicator to white.
|
||||||
|
ChangeReviveIconState(downed_client.playernum, 2);
|
||||||
|
|
||||||
|
#ifdef FTE
|
||||||
|
|
||||||
|
// FTE-Specific: Broadcast to the downed player they're being revived.
|
||||||
|
FTE_BroadcastMessage(downed_client, CSQC_BROADCAST_BEINGREVIVED, 2, revivee.playernum);
|
||||||
|
|
||||||
|
// FTE-Specific: Broadcast to revivee that they are reviving the downed player.
|
||||||
|
FTE_BroadcastMessage(revivee, CSQC_BROADCAST_REVIVINGPLAYER, 2, downed_client.playernum);
|
||||||
|
|
||||||
|
#endif // FTE
|
||||||
|
|
||||||
|
// Initiate an animation for morphine.
|
||||||
|
entity old_self = self;
|
||||||
|
self = revivee;
|
||||||
|
Set_W_Frame (0, 21, 0, 0, SPRINT, SUB_Null, "models/weapons/morphine/v_morphine.mdl", false, S_RIGHT);
|
||||||
|
self = old_self;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// LastStand_TouchReviveTrigger()
|
||||||
|
// Contact made with a downed player's revive trigger,
|
||||||
|
// handles reviving logic.
|
||||||
|
//
|
||||||
|
void() LastStand_TouchReviveTrigger =
|
||||||
|
{
|
||||||
|
// Only trigger for free players, and not ourself.
|
||||||
|
if (other.classname != "player" || other == self.owner)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If the team mate is actively being revived, and we are not the one
|
||||||
|
// reviving them, break out.
|
||||||
|
if (self.owner.beingrevived == true && self.owner.firer != other)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Is the client touching us down, or are they not facing us, or buying something?
|
||||||
|
if (other.downed || !PlayerIsLooking(other, self.owner) || other.isBuying) {
|
||||||
|
// Were they in the process of reviving us previously?
|
||||||
|
if (self.owner.firer == other) {
|
||||||
|
// Unlink us.
|
||||||
|
LastStand_UnlinkRevivee(self.owner);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No one is actively reviving the downed team mate.
|
||||||
|
if (self.owner.beingrevived == false) {
|
||||||
|
// Hold F to revive...
|
||||||
|
useprint(other, 13, 0, 0);
|
||||||
|
|
||||||
|
// Kick-off the revive sequence.
|
||||||
|
if (other.button7) {
|
||||||
|
// Revive time should be significantly shorter with
|
||||||
|
// Quick Revive.
|
||||||
|
float revive_time = 4;
|
||||||
|
if (other.perks & P_REVIVE)
|
||||||
|
revive_time = 2;
|
||||||
|
|
||||||
|
// Link us together!
|
||||||
|
LastStand_LinkRevivee(self.owner, other);
|
||||||
|
other.fire_delay = other.fire_delay2 = other.reload_delay = other.reload_delay2 = other.knife_delay = time + revive_time; // FIXME
|
||||||
|
|
||||||
|
// Use ltime on the revive trigger to know when the revive is finished
|
||||||
|
self.ltime = time + revive_time;
|
||||||
|
|
||||||
|
// Display progress bar for the revivee.
|
||||||
|
Player_InitiateProgressBar(other, revive_time);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Revivee has released the revive button.
|
||||||
|
if (!self.owner.firer.button7) {
|
||||||
|
LastStand_UnlinkRevivee(self.owner);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reviving has been executed for the full duration..
|
||||||
|
if (self.ltime < time) {
|
||||||
|
// Reward the revivee with the points the downed client lost
|
||||||
|
Player_AddScore(other, self.owner.requirespower, false);
|
||||||
|
|
||||||
|
entity old_self = self;
|
||||||
|
self = self.owner;
|
||||||
|
GetUp();
|
||||||
|
self = old_self;
|
||||||
|
|
||||||
|
// Unlink the revivee, no need to stay connected.
|
||||||
|
LastStand_UnlinkRevivee(self.owner);
|
||||||
|
|
||||||
|
// Remove the revive icon from above the previously downed client
|
||||||
|
DisableReviveIcon(self.owner.playernum);
|
||||||
|
|
||||||
|
// No reason for the trigger to exist anymore, goodbye!
|
||||||
|
remove(self);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// LastStand_SpawnReviveTrigger(client)
|
||||||
|
// Spawns a trigger to follow a client for reviving.
|
||||||
|
//
|
||||||
|
void(entity client) LastStand_SpawnReviveTrigger =
|
||||||
|
{
|
||||||
|
entity revive_trigger = spawn();
|
||||||
|
revive_trigger.owner = client;
|
||||||
|
revive_trigger.classname = "revive_trigger";
|
||||||
|
revive_trigger.think = LastStand_ReviveTriggerFollow;
|
||||||
|
revive_trigger.nextthink = time + 1;
|
||||||
|
revive_trigger.touch = LastStand_TouchReviveTrigger;
|
||||||
|
revive_trigger.solid = SOLID_TRIGGER;
|
||||||
|
|
||||||
|
setorigin(revive_trigger, client.origin);
|
||||||
|
setsize(revive_trigger, '-52 -52 -16', '52 52 -4');
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// LastStand_Begin(client)
|
||||||
|
// Player has gone down, oh noes! Kicks off their
|
||||||
|
// state changes and decides what the game should
|
||||||
|
// do next.
|
||||||
|
//
|
||||||
|
void(entity client) LastStand_Begin =
|
||||||
|
{
|
||||||
|
entity old_self = self;
|
||||||
|
self = client;
|
||||||
|
|
||||||
|
// 'Pro Gamer Move' achievement.
|
||||||
|
if (rounds <= 1 && self.weapons[0].weapon_magazine == 0 &&
|
||||||
|
self.weapons[0].weapon_magazine_left == 0 && self.weapons[0].weapon_reserve == 0 &&
|
||||||
|
self.weapons[1].weapon_magazine == 0 && self.weapons[1].weapon_magazine_left == 0 &&
|
||||||
|
self.weapons[1].weapon_reserve == 0) {
|
||||||
|
GiveAchievement(9, self);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aim out to reset zoom values
|
||||||
|
W_AimOut();
|
||||||
|
|
||||||
|
#ifdef FTE
|
||||||
|
|
||||||
|
self.viewzoom = 1;
|
||||||
|
|
||||||
|
#endif // FTE
|
||||||
|
|
||||||
|
// Make any zombies inside of the player's bounding box leave
|
||||||
|
push_away_zombies();
|
||||||
|
|
||||||
|
// Force the player to prone.
|
||||||
|
Player_SetStance(self, PLAYER_STANCE_PRONE, false);
|
||||||
|
|
||||||
|
// Calculate the loss in points, take away points from downed Player.
|
||||||
|
float point_difference;
|
||||||
|
point_difference = self.points;
|
||||||
|
point_difference -= 10*rint((self.points*0.95)/10);
|
||||||
|
Player_RemoveScore(self, point_difference);
|
||||||
|
self.requirespower = point_difference;
|
||||||
|
|
||||||
|
// Reset state
|
||||||
|
self.velocity = self.zoom = 0;
|
||||||
|
self.downed = true;
|
||||||
|
self.dive_delay = 0;
|
||||||
|
|
||||||
|
// End the game if no one else is alive.
|
||||||
|
float players_still_alive = PollPlayersAlive();
|
||||||
|
if ((player_count && !players_still_alive) || (!player_count && !(self.perks & P_REVIVE))) {
|
||||||
|
EndGameSetup();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef FTE
|
||||||
|
|
||||||
|
// FTE-Specific: Broadcast that the player has downed to everyone.
|
||||||
|
FTE_BroadcastMessage(world, CSQC_BROADCAST_PLAYERDOWNED, 3, self.playernum);
|
||||||
|
|
||||||
|
#endif // FTE
|
||||||
|
|
||||||
|
self.health = 19;
|
||||||
|
|
||||||
|
// Initiate Self-Revive on Solo
|
||||||
|
if ((self.perks & P_REVIVE) && !player_count) {
|
||||||
|
LastStand_InitiateSoloRevive(self);
|
||||||
|
}
|
||||||
|
// Spawn the Revive Trigger
|
||||||
|
else {
|
||||||
|
LastStand_SpawnReviveTrigger(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the tracker for the achievement "No Perks? No Problem"
|
||||||
|
self.ach_tracker_npnp = 0;
|
||||||
|
|
||||||
|
// Take away Perks, Mule Kick weapon, etc.
|
||||||
|
LastStand_Penalize(self);
|
||||||
|
|
||||||
|
// Assign the Player a temporary weapon to use while in Last Stand.
|
||||||
|
LastStand_AssignWeapon(self);
|
||||||
|
|
||||||
|
// Spawn Revive Sprite in Co-Op
|
||||||
|
if (player_count) {
|
||||||
|
EnableReviveIcon(self.playernum);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Play Last Stand Animation
|
||||||
|
PAnim_GetDown();
|
||||||
|
|
||||||
|
self = old_self;
|
||||||
|
};
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
server/player.qc
|
server/player/player_core.qc
|
||||||
|
|
||||||
Various stuff done for the player, including per-frame functions
|
Various stuff done for the player, including per-frame functions
|
||||||
like PlayerPreThink and PlayerPostThink, also client specific
|
like PlayerPreThink and PlayerPostThink, also client specific
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
void(entity e) Light_None;
|
void(entity e) Light_None;
|
||||||
void() Spawns_Init;
|
void() Spawns_Init;
|
||||||
void() SUB_UseTargets;
|
void() SUB_UseTargets;
|
||||||
void() rec_downed;
|
void(entity client) LastStand_UnlinkRevivee;
|
||||||
|
|
||||||
#define PLAYER_START_HEALTH 100
|
#define PLAYER_START_HEALTH 100
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ void() PAnim_GetDown1 =[ 2, PAnim_GetDown2 ] {self.frame = 33;};
|
||||||
void() PAnim_GetDown2 =[ 3, PAnim_GetDown3 ] {self.frame = 34;};
|
void() PAnim_GetDown2 =[ 3, PAnim_GetDown3 ] {self.frame = 34;};
|
||||||
void() PAnim_GetDown3 =[ 4, PAnim_GetDown4 ] {self.frame = 35;};
|
void() PAnim_GetDown3 =[ 4, PAnim_GetDown4 ] {self.frame = 35;};
|
||||||
void() PAnim_GetDown4 =[ 5, PAnim_GetDown5 ] {self.frame = 36;};
|
void() PAnim_GetDown4 =[ 5, PAnim_GetDown5 ] {self.frame = 36;};
|
||||||
void() PAnim_GetDown5 =[ 6, SUB_Null ] {self.frame = 37; rec_downed();};
|
void() PAnim_GetDown5 =[ 6, SUB_Null ] {self.frame = 37;};
|
||||||
|
|
||||||
// Firing, while in Last Stand
|
// Firing, while in Last Stand
|
||||||
void() PAnim_LastFire =[ 1, PAnim_LastFire1 ] {self.frame = 36; self.tp_anim_time = time + 0.25;}
|
void() PAnim_LastFire =[ 1, PAnim_LastFire1 ] {self.frame = 36; self.tp_anim_time = time + 0.25;}
|
||||||
|
@ -393,6 +393,41 @@ void(entity who, float preferred_stance, float play_animation) Player_SetStance
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Player_InitiateProgressBar(who, duration)
|
||||||
|
// Kicks-off progress bar for the server to interpret
|
||||||
|
// and render on the client side.
|
||||||
|
//
|
||||||
|
void(entity who, float duration) Player_InitiateProgressBar =
|
||||||
|
{
|
||||||
|
who.progress_bar_time = duration;
|
||||||
|
who.progress_bar = who.progress_bar_time + time;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Player_RemoveProgressBar(who)
|
||||||
|
// Resets progress bar status for client.
|
||||||
|
//
|
||||||
|
void(entity who) Player_RemoveProgressBar =
|
||||||
|
{
|
||||||
|
who.progress_bar = who.progress_bar_time = who.progress_bar_percent = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Player_UpdateProgressBar()
|
||||||
|
// Increments progress bar percentage for client rendering updates.
|
||||||
|
//
|
||||||
|
void() Player_UpdateProgressBar =
|
||||||
|
{
|
||||||
|
if (self.progress_bar_time) {
|
||||||
|
float progress_bar_remaining = self.progress_bar - time;
|
||||||
|
self.progress_bar_percent = invertfloat(progress_bar_remaining / self.progress_bar_time);
|
||||||
|
|
||||||
|
if (self.progress_bar_percent >= 0.95)
|
||||||
|
Player_RemoveProgressBar(self);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void() PlayerJump =
|
void() PlayerJump =
|
||||||
{
|
{
|
||||||
if (!(self.flags & FL_ONGROUND)
|
if (!(self.flags & FL_ONGROUND)
|
||||||
|
@ -673,25 +708,16 @@ void() PlayerPostThink =
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.progress_bar) {
|
if (self.downed && self.firer != world) {
|
||||||
if (self.progress_bar < time) {
|
// Has our revivee left the vicinity of our revive trigger?
|
||||||
if (self.downed)
|
if (fabs(vlen(self.origin - self.firer.origin)) >= 72) {
|
||||||
GetUp();
|
LastStand_UnlinkRevivee(self);
|
||||||
|
|
||||||
if (self.reviving)
|
|
||||||
self.revived = 1;
|
|
||||||
|
|
||||||
self.progress_bar = 0;
|
|
||||||
self.progress_bar_time = 0;
|
|
||||||
self.progress_bar_percent = 0;
|
|
||||||
|
|
||||||
|
|
||||||
} else {
|
|
||||||
float remaining = self.progress_bar - time;
|
|
||||||
self.progress_bar_percent = invertfloat((remaining / self.progress_bar_time));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep track of any active progress bars.
|
||||||
|
Player_UpdateProgressBar();
|
||||||
|
|
||||||
if (self.sprinting) {
|
if (self.sprinting) {
|
||||||
self.sprint_timer = self.sprint_duration + (time - self.sprint_start_time);
|
self.sprint_timer = self.sprint_duration + (time - self.sprint_start_time);
|
||||||
|
|
||||||
|
@ -1012,9 +1038,11 @@ void() ClientDisconnect =
|
||||||
|
|
||||||
GameRestart_ResetPerkaColas();
|
GameRestart_ResetPerkaColas();
|
||||||
|
|
||||||
if (self.downed) {
|
if (self.downed && self.firer != world) {
|
||||||
DisableReviveIcon(self.electro_targeted);
|
LastStand_UnlinkRevivee(self);
|
||||||
revive_index--;
|
DisableReviveIcon(self.playernum);
|
||||||
|
} else if (self.firer != world) {
|
||||||
|
self.firer.beingrevived = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FTE
|
#ifdef FTE
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
server/entities/spawn_points.qc
|
server/player/spawn_points.qc
|
||||||
|
|
||||||
Code for Player Spawn points.
|
Code for Player Spawn points.
|
||||||
|
|
|
@ -1341,6 +1341,7 @@ void() GrenadeExplode =
|
||||||
CallExplosion(self.origin);
|
CallExplosion(self.origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (self.classname != "player")
|
||||||
SUB_Remove();
|
SUB_Remove();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1768,129 +1769,6 @@ void() CheckPlayer =
|
||||||
|
|
||||||
self.oldz = self.origin_z;
|
self.oldz = self.origin_z;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Revive Sequence
|
|
||||||
//
|
|
||||||
#ifdef FTE
|
|
||||||
|
|
||||||
entity ent;
|
|
||||||
ent = findradius(self.origin, 70);
|
|
||||||
|
|
||||||
while(ent)
|
|
||||||
{
|
|
||||||
if(ent.classname == "player" && ent != self && ent.downed)
|
|
||||||
{
|
|
||||||
|
|
||||||
// perform a trace to make sure they're always facing the revivee
|
|
||||||
vector source;
|
|
||||||
makevectors(self.angles);
|
|
||||||
source = self.origin - '0 0 12';
|
|
||||||
traceline(source, source + v_forward*50, 0, self);
|
|
||||||
self.active_door = trace_ent;
|
|
||||||
|
|
||||||
if (ent.beingrevived == false && self.active_door == ent && !self.downed)
|
|
||||||
useprint (self, 13, 0, 0);
|
|
||||||
|
|
||||||
if (self.button7 && !ent.invoke_revive && self.active_door == ent && !self.downed) {
|
|
||||||
if (ent.beingrevived == true && ent.firer != self)
|
|
||||||
return;
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef FTE
|
|
||||||
|
|
||||||
// FTE-Specific: Broadcast to the player they're being revived.
|
|
||||||
FTE_BroadcastMessage(ent, CSQC_BROADCAST_BEINGREVIVED, 2, self.playernum);
|
|
||||||
|
|
||||||
// FTE-Specific: Broadcast to client that they are reviving the downed player.
|
|
||||||
FTE_BroadcastMessage(self, CSQC_BROADCAST_REVIVINGPLAYER, 2, ent.playernum);
|
|
||||||
|
|
||||||
#endif // FTE
|
|
||||||
|
|
||||||
ent.speed_penalty = 0.01;
|
|
||||||
ent.speed_penalty_time = time + 100;
|
|
||||||
ent.beingrevived = true;
|
|
||||||
ent.firer = self;
|
|
||||||
|
|
||||||
if (!self.reviving) {
|
|
||||||
ChangeReviveIconState(ent.electro_targeted, 2);
|
|
||||||
self.movetype = MOVETYPE_TOSS;
|
|
||||||
Set_W_Frame (0, 21, 0, 0, SPRINT, SUB_Null, "models/weapons/morphine/v_morphine.mdl", false, S_RIGHT);
|
|
||||||
|
|
||||||
if !(self.perks & P_REVIVE)
|
|
||||||
self.progress_bar_time = 4;
|
|
||||||
else
|
|
||||||
self.progress_bar_time = 2;
|
|
||||||
|
|
||||||
self.progress_bar = self.progress_bar_time + time;
|
|
||||||
self.progress_bar_percent = 1;
|
|
||||||
self.reviving = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.revived) {
|
|
||||||
self.movetype = MOVETYPE_WALK;
|
|
||||||
W_TakeOut();
|
|
||||||
ent.invoke_revive = 1;
|
|
||||||
ent.beingrevived = false;
|
|
||||||
ent.speed_penalty_time = 0;
|
|
||||||
self.reviving = 0;
|
|
||||||
self.progress_bar = 0;
|
|
||||||
self.progress_bar_time = 0;
|
|
||||||
self.progress_bar_percent = 0;
|
|
||||||
self.revived = 0;
|
|
||||||
Player_AddScore(self, ent.requirespower, false);
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef FTE
|
|
||||||
|
|
||||||
// FTE-Specific: End Broadcast Messages on both ends
|
|
||||||
FTE_BroadcastMessage(ent, CSQC_BROADCAST_NONE, 0, self.playernum);
|
|
||||||
FTE_BroadcastMessage(self, CSQC_BROADCAST_NONE, 0, ent.playernum);
|
|
||||||
|
|
||||||
#endif // FTE
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (self.downed || (!self.button7 && self.reviving) || (self.reviving && self.active_door != ent) || ent.classname == "disconnected") {
|
|
||||||
if (ent.classname != "disconnected")
|
|
||||||
ChangeReviveIconState(ent.electro_targeted, 1);
|
|
||||||
else
|
|
||||||
DisableReviveIcon(ent.electro_targeted);
|
|
||||||
self.movetype = MOVETYPE_WALK;
|
|
||||||
ent.beingrevived = false;
|
|
||||||
ent.speed_penalty_time = 0;
|
|
||||||
ent.firer = world;
|
|
||||||
W_TakeOut();
|
|
||||||
self.progress_bar = 0;
|
|
||||||
self.progress_bar_time = 0;
|
|
||||||
self.progress_bar_percent = 0;
|
|
||||||
self.revived = 0;
|
|
||||||
self.reviving = 0;
|
|
||||||
|
|
||||||
#ifdef FTE
|
|
||||||
|
|
||||||
// FTE-Specific: End Broadcast Messages on both ends
|
|
||||||
FTE_BroadcastMessage(ent, CSQC_BROADCAST_NONE, 0, self.playernum);
|
|
||||||
FTE_BroadcastMessage(self, CSQC_BROADCAST_NONE, 0, ent.playernum);
|
|
||||||
|
|
||||||
#endif // FTE
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(ent.classname == "player" && ent != self && !ent.downed) // small player push
|
|
||||||
{
|
|
||||||
vector push;
|
|
||||||
push = ent.origin - self.origin;
|
|
||||||
push_z = 0;
|
|
||||||
push = normalize(push) * 0.5;
|
|
||||||
|
|
||||||
ent.velocity += push;
|
|
||||||
}
|
|
||||||
ent = ent.chain;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // FTE
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
Loading…
Reference in a new issue