mirror of
https://github.com/nzp-team/quakec.git
synced 2024-11-24 12:51:39 +00:00
SERVER: Last Stand and Revive Overhaul
This commit is contained in:
parent
98dfb45702
commit
ccb892909a
11 changed files with 620 additions and 413 deletions
|
@ -30,12 +30,13 @@ main.qc
|
|||
utilities/weapon_utilities.qc
|
||||
utilities/game_restart.qc
|
||||
utilities/command_parser.qc
|
||||
player.qc
|
||||
player/player_core.qc
|
||||
damage.qc
|
||||
player/spawn_points.qc
|
||||
player/last_stand.qc
|
||||
entities/sub_functions.qc
|
||||
entities/sounds.qc
|
||||
entities/triggers.qc
|
||||
entities/spawn_points.qc
|
||||
entities/explosive_barrel.qc
|
||||
entities/teleporter.qc
|
||||
entities/map_entities.qc
|
||||
|
|
|
@ -101,10 +101,7 @@ var struct revive_s {
|
|||
float draw;
|
||||
float timer;
|
||||
float state;
|
||||
float org[3];
|
||||
} revive_icons[4];
|
||||
|
||||
float active_revive_icons;
|
||||
} revive_icons[4]; // MAX_CLIENTS
|
||||
|
||||
float weaponframetime;
|
||||
float weapon2frametime;
|
||||
|
|
|
@ -1724,27 +1724,51 @@ void(float width, float height) HUD_PlayerNames =
|
|||
|
||||
void(float width, float height) HUD_ReviveIcons =
|
||||
{
|
||||
for (float i = 0; i < active_revive_icons; i++) {
|
||||
if (revive_icons[i].draw == true) {
|
||||
revive_icons[i].timer += frametime;
|
||||
vector revive_origin;
|
||||
revive_origin_x = revive_icons[i].org[0];
|
||||
revive_origin_y = revive_icons[i].org[1];
|
||||
revive_origin_z = revive_icons[i].org[2];
|
||||
vector screen_position = project(revive_origin);
|
||||
for (float i = 3; i >= 0; i = i - 1) {
|
||||
float player_index = i;
|
||||
|
||||
// Don't render our own Icon.
|
||||
if (player_index + 1 == getstatf(STAT_PLAYERNUM))
|
||||
continue;
|
||||
|
||||
// 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;
|
||||
|
||||
if (player_origin == '0 0 32')
|
||||
continue;
|
||||
|
||||
if (screen_position_z > 0) {
|
||||
// being revived
|
||||
if (revive_icons[i].state == 2)
|
||||
// Client is actively being revived, render white.
|
||||
if (revive_icons[i].state == 2) {
|
||||
drawpic(screen_position, "gfx/hud/revive_icon.tga", [32, 32, 1], [1,1,1], 1);
|
||||
}
|
||||
// Draw with a yellow->red hue.
|
||||
else {
|
||||
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 =
|
||||
{
|
||||
|
|
|
@ -1072,28 +1072,20 @@ noref void() CSQC_Parse_Event =
|
|||
}
|
||||
break;
|
||||
case EVENT_REVIVECHANGE:
|
||||
float revivechange_id = readbyte();
|
||||
float revivechange_player_index = readbyte() - 1; // playernum starts at one.
|
||||
float state = readbyte();
|
||||
revive_icons[revivechange_id].state = state;
|
||||
revive_icons[revivechange_player_index].state = state;
|
||||
break;
|
||||
case EVENT_REVIVEON:
|
||||
float reviveon_id = readbyte();
|
||||
revive_icons[reviveon_id].org[0] = readcoord();
|
||||
revive_icons[reviveon_id].org[1] = readcoord();
|
||||
revive_icons[reviveon_id].org[2] = readcoord();
|
||||
revive_icons[reviveon_id].state = 1;
|
||||
revive_icons[reviveon_id].draw = true;
|
||||
active_revive_icons++;
|
||||
float reviveon_player_index = readbyte() - 1; // playernum starts at one.
|
||||
revive_icons[reviveon_player_index].state = 1;
|
||||
revive_icons[reviveon_player_index].draw = true;
|
||||
break;
|
||||
case EVENT_REVIVEOFF:
|
||||
float reviveoff_id = readbyte();
|
||||
revive_icons[reviveoff_id].org[0] = 0;
|
||||
revive_icons[reviveoff_id].org[1] = 0;
|
||||
revive_icons[reviveoff_id].org[2] = 0;
|
||||
revive_icons[reviveoff_id].state = 0;
|
||||
revive_icons[reviveoff_id].timer = 0;
|
||||
revive_icons[reviveoff_id].draw = false;
|
||||
active_revive_icons--;
|
||||
float reviveoff_player_index = readbyte() - 1; // playernum starts at one.
|
||||
revive_icons[reviveoff_player_index].state = 0;
|
||||
revive_icons[reviveoff_player_index].timer = 0;
|
||||
revive_icons[reviveoff_player_index].draw = false;
|
||||
break;
|
||||
case EVENT_MAPTYPE:
|
||||
map_compatibility_mode = readbyte();
|
||||
|
|
|
@ -155,29 +155,26 @@ void(float round) FTE_IncrementRound =
|
|||
|
||||
#endif // FTE
|
||||
|
||||
void(float index, float state) ChangeReviveIconState =
|
||||
void(float player_index, float state) ChangeReviveIconState =
|
||||
{
|
||||
#ifdef FTE
|
||||
|
||||
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
|
||||
WriteByte(MSG_MULTICAST, EVENT_REVIVECHANGE);
|
||||
WriteByte(MSG_MULTICAST, index);
|
||||
WriteByte(MSG_MULTICAST, player_index);
|
||||
WriteByte(MSG_MULTICAST, state);
|
||||
multicast('0 0 0', MULTICAST_ALL);
|
||||
|
||||
#endif // FTE
|
||||
}
|
||||
|
||||
void(float index, vector org) EnableReviveIcon =
|
||||
void(float player_index) EnableReviveIcon =
|
||||
{
|
||||
#ifdef FTE
|
||||
|
||||
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
|
||||
WriteByte(MSG_MULTICAST, EVENT_REVIVEON);
|
||||
WriteByte(MSG_MULTICAST, index);
|
||||
WriteCoord(MSG_MULTICAST, org_x);
|
||||
WriteCoord(MSG_MULTICAST, org_y);
|
||||
WriteCoord(MSG_MULTICAST, org_z);
|
||||
WriteByte(MSG_MULTICAST, player_index);
|
||||
multicast('0 0 0', MULTICAST_ALL);
|
||||
|
||||
#endif // FTE
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
*/
|
||||
void (float achievement_id, optional entity who) GiveAchievement;
|
||||
void(entity client) LastStand_Begin;
|
||||
|
||||
#define DMG_SCORE_HEADSHOT 100 // Death by Headshot
|
||||
#define DMG_SCORE_MELEE 130 // Death by Melee
|
||||
|
@ -158,213 +159,7 @@ void() EndGameSetup =
|
|||
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;
|
||||
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 =
|
||||
{
|
||||
|
@ -405,10 +200,6 @@ void () GetUp =
|
|||
|
||||
self.teslacount = 0;
|
||||
|
||||
if (!player_count) {
|
||||
Player_AddScore(self, self.requirespower, false);
|
||||
}
|
||||
|
||||
Weapon_AssignWeapon(0, self.weaponbk, self.currentmagbk, self.currentammobk);
|
||||
};
|
||||
|
||||
|
@ -417,8 +208,7 @@ void(entity ent) CheckRevive =
|
|||
{
|
||||
if (self.invoke_revive) {
|
||||
GetUp();
|
||||
DisableReviveIcon(self.electro_targeted);
|
||||
revive_index--;
|
||||
DisableReviveIcon(self.playernum);
|
||||
self.invoke_revive = 0;
|
||||
self.firer = world;
|
||||
}
|
||||
|
@ -561,10 +351,7 @@ void(entity victim, entity attacker, float damage, float d_style) DamageHandler
|
|||
// Was 20 for.. some reason.
|
||||
if (victim.health <= 1)
|
||||
{
|
||||
old_self = self;
|
||||
self = victim;
|
||||
GetDown();
|
||||
self = old_self;
|
||||
LastStand_Begin(victim);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -627,8 +627,6 @@ float G_PERKPOWER;
|
|||
.float renderamt;
|
||||
.vector rendercolor;
|
||||
|
||||
float revive_index;
|
||||
|
||||
#ifdef FTE
|
||||
.float last_solid;
|
||||
.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
|
||||
like PlayerPreThink and PlayerPostThink, also client specific
|
||||
|
@ -30,7 +30,7 @@
|
|||
void(entity e) Light_None;
|
||||
void() Spawns_Init;
|
||||
void() SUB_UseTargets;
|
||||
void() rec_downed;
|
||||
void(entity client) LastStand_UnlinkRevivee;
|
||||
|
||||
#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_GetDown3 =[ 4, PAnim_GetDown4 ] {self.frame = 35;};
|
||||
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
|
||||
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 =
|
||||
{
|
||||
if (!(self.flags & FL_ONGROUND)
|
||||
|
@ -673,25 +708,16 @@ void() PlayerPostThink =
|
|||
}
|
||||
}
|
||||
|
||||
if (self.progress_bar) {
|
||||
if (self.progress_bar < time) {
|
||||
if (self.downed)
|
||||
GetUp();
|
||||
|
||||
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));
|
||||
if (self.downed && self.firer != world) {
|
||||
// Has our revivee left the vicinity of our revive trigger?
|
||||
if (fabs(vlen(self.origin - self.firer.origin)) >= 72) {
|
||||
LastStand_UnlinkRevivee(self);
|
||||
}
|
||||
}
|
||||
|
||||
// Keep track of any active progress bars.
|
||||
Player_UpdateProgressBar();
|
||||
|
||||
if (self.sprinting) {
|
||||
self.sprint_timer = self.sprint_duration + (time - self.sprint_start_time);
|
||||
|
||||
|
@ -1012,9 +1038,11 @@ void() ClientDisconnect =
|
|||
|
||||
GameRestart_ResetPerkaColas();
|
||||
|
||||
if (self.downed) {
|
||||
DisableReviveIcon(self.electro_targeted);
|
||||
revive_index--;
|
||||
if (self.downed && self.firer != world) {
|
||||
LastStand_UnlinkRevivee(self);
|
||||
DisableReviveIcon(self.playernum);
|
||||
} else if (self.firer != world) {
|
||||
self.firer.beingrevived = false;
|
||||
}
|
||||
|
||||
#ifdef FTE
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
server/entities/spawn_points.qc
|
||||
server/player/spawn_points.qc
|
||||
|
||||
Code for Player Spawn points.
|
||||
|
|
@ -1341,6 +1341,7 @@ void() GrenadeExplode =
|
|||
CallExplosion(self.origin);
|
||||
}
|
||||
|
||||
if (self.classname != "player")
|
||||
SUB_Remove();
|
||||
};
|
||||
|
||||
|
@ -1768,129 +1769,6 @@ void() CheckPlayer =
|
|||
|
||||
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