1998-12-20 00:00:00 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// $Logfile:: /Quake 2 Engine/Sin/code/game/player.cpp $
|
1999-11-02 00:00:00 +00:00
|
|
|
// $Revision:: 450 $
|
|
|
|
// $Author:: Markd $
|
|
|
|
// $Date:: 11/02/99 12:09p $
|
1998-12-20 00:00:00 +00:00
|
|
|
//
|
|
|
|
// Copyright (C) 1997 by Ritual Entertainment, Inc.
|
|
|
|
// All rights reserved.
|
|
|
|
//
|
|
|
|
// This source is may not be distributed and/or modified without
|
|
|
|
// expressly written permission by Ritual Entertainment, Inc.
|
|
|
|
//
|
|
|
|
// $Log:: /Quake 2 Engine/Sin/code/game/player.cpp $
|
|
|
|
//
|
1999-11-02 00:00:00 +00:00
|
|
|
// 450 11/02/99 12:09p Markd
|
|
|
|
// Fixed CTF cheat bug
|
1999-03-20 00:00:00 +00:00
|
|
|
//
|
1999-11-02 00:00:00 +00:00
|
|
|
// 449 10/28/99 10:43a Markd
|
|
|
|
// made a bunch of console commands cheat protected
|
1999-03-20 00:00:00 +00:00
|
|
|
//
|
1999-11-02 00:00:00 +00:00
|
|
|
// 448 7/25/99 7:06p Markd
|
|
|
|
// Fixed major deathmatch cheat
|
1999-03-20 00:00:00 +00:00
|
|
|
//
|
1999-11-02 00:00:00 +00:00
|
|
|
// 447 6/14/99 2:11p Markd
|
|
|
|
// initialize grapple_pull to false in the constructor
|
1998-12-20 00:00:00 +00:00
|
|
|
//
|
1999-11-02 00:00:00 +00:00
|
|
|
// 446 5/19/99 11:30a Markd
|
|
|
|
// Added new camera support
|
1998-12-20 00:00:00 +00:00
|
|
|
//
|
1999-11-02 00:00:00 +00:00
|
|
|
// 445 5/18/99 7:07p Aldie
|
|
|
|
// Fix for ctf_forcejoin
|
1998-12-20 00:00:00 +00:00
|
|
|
//
|
1999-11-02 00:00:00 +00:00
|
|
|
// 444 4/16/99 5:02p Aldie
|
|
|
|
// Added takeallammo to dropweapon
|
1998-12-20 00:00:00 +00:00
|
|
|
//
|
1999-11-02 00:00:00 +00:00
|
|
|
// 443 4/02/99 5:14p Markd
|
|
|
|
// Added MOD for dedicated server support
|
1998-12-20 00:00:00 +00:00
|
|
|
//
|
1999-11-02 00:00:00 +00:00
|
|
|
// 442 3/25/99 6:29p Aldie
|
|
|
|
// Fixed grappling hook crash bug
|
1998-12-20 00:00:00 +00:00
|
|
|
//
|
1999-11-02 00:00:00 +00:00
|
|
|
// 441 3/24/99 4:39p Aldie
|
|
|
|
// Changed death messages to reliable
|
1998-12-20 00:00:00 +00:00
|
|
|
//
|
1999-11-02 00:00:00 +00:00
|
|
|
// 440 3/24/99 10:35a Markd
|
|
|
|
// Hopefully fixed a crash bug with spectator and events
|
1998-12-20 00:00:00 +00:00
|
|
|
//
|
1999-11-02 00:00:00 +00:00
|
|
|
// 439 3/22/99 2:08p Aldie
|
|
|
|
// Bulletproofed flag dropping from players
|
1998-12-20 00:00:00 +00:00
|
|
|
//
|
1999-11-02 00:00:00 +00:00
|
|
|
// 438 3/19/99 9:00p Aldie
|
|
|
|
// Added spectator_distance for spectator camera
|
1998-12-20 00:00:00 +00:00
|
|
|
//
|
1999-11-02 00:00:00 +00:00
|
|
|
// 437 3/19/99 7:36p Aldie
|
|
|
|
// Added bulletproofing for being in a vehicle and choosing spectator
|
1998-12-20 00:00:00 +00:00
|
|
|
//
|
1999-11-02 00:00:00 +00:00
|
|
|
// 436 3/19/99 5:59p Aldie
|
|
|
|
// Added dropweapon and dropflag
|
1998-12-20 00:00:00 +00:00
|
|
|
//
|
1999-11-02 00:00:00 +00:00
|
|
|
// 435 3/19/99 5:04p Aldie
|
|
|
|
// Fixed spectator mode (major overhaul) temporarily disabled MOD on client
|
|
|
|
// messages
|
1998-12-20 00:00:00 +00:00
|
|
|
//
|
1999-11-02 00:00:00 +00:00
|
|
|
// 434 3/19/99 2:12p Aldie
|
|
|
|
// Changed deathmessages
|
1998-12-20 00:00:00 +00:00
|
|
|
//
|
1999-11-02 00:00:00 +00:00
|
|
|
// 433 3/17/99 4:00p Aldie
|
|
|
|
// CTF Update
|
1998-12-20 00:00:00 +00:00
|
|
|
//
|
1999-11-02 00:00:00 +00:00
|
|
|
// 432 3/16/99 12:41p Aldie
|
|
|
|
// Fixed spectator bug
|
1998-12-20 00:00:00 +00:00
|
|
|
//
|
1999-11-02 00:00:00 +00:00
|
|
|
// 431 3/16/99 11:50a Aldie
|
|
|
|
// Fix for dropped flag stuff
|
1998-12-20 00:00:00 +00:00
|
|
|
//
|
1999-11-02 00:00:00 +00:00
|
|
|
// 430 3/12/99 10:27p Aldie
|
|
|
|
// Added obit for deathquad
|
1998-12-20 00:00:00 +00:00
|
|
|
//
|
1999-11-02 00:00:00 +00:00
|
|
|
// 429 3/12/99 10:18p Aldie
|
|
|
|
// Changed the sounds
|
1998-12-20 00:00:00 +00:00
|
|
|
//
|
1999-11-02 00:00:00 +00:00
|
|
|
// 428 3/12/99 7:40p Jimdose
|
|
|
|
// fixed possible cheats in spectator mode:
|
|
|
|
// spectators no longer touch things (so items can't be picked up)
|
|
|
|
// spectators no longer can grapple
|
|
|
|
// spectators can no longer be hurt by explosions
|
1998-12-20 00:00:00 +00:00
|
|
|
//
|
1999-11-02 00:00:00 +00:00
|
|
|
// 427 3/11/99 3:46p Aldie
|
|
|
|
// Added some meansofdeath messages
|
1998-12-20 00:00:00 +00:00
|
|
|
//
|
1999-11-02 00:00:00 +00:00
|
|
|
// 426 3/05/99 5:58p Markd
|
|
|
|
// Added vehicle use support
|
1998-12-20 00:00:00 +00:00
|
|
|
//
|
1999-11-02 00:00:00 +00:00
|
|
|
// 425 3/05/99 5:47p Aldie
|
|
|
|
// Added thrallball mod
|
1998-12-20 00:00:00 +00:00
|
|
|
//
|
1999-11-02 00:00:00 +00:00
|
|
|
// 424 3/03/99 12:38p Aldie
|
|
|
|
// Fix some stuff for CTF gravaxis and hook
|
1998-12-20 00:00:00 +00:00
|
|
|
//
|
1999-11-02 00:00:00 +00:00
|
|
|
// 423 3/02/99 9:14p Aldie
|
|
|
|
// Added CTF game code
|
1998-12-20 00:00:00 +00:00
|
|
|
//
|
1999-11-02 00:00:00 +00:00
|
|
|
// 2 2/16/99 4:09p Aldie
|
1998-12-20 00:00:00 +00:00
|
|
|
//
|
|
|
|
//
|
|
|
|
// DESCRIPTION:
|
|
|
|
// Class definition of the player.
|
|
|
|
//
|
|
|
|
#include "g_local.h"
|
|
|
|
#include "entity.h"
|
|
|
|
#include "player.h"
|
|
|
|
#include "worldspawn.h"
|
|
|
|
#include "weapon.h"
|
|
|
|
#include "trigger.h"
|
|
|
|
#include "scriptmaster.h"
|
|
|
|
#include "vehicle.h"
|
|
|
|
#include "path.h"
|
|
|
|
#include "navigate.h"
|
|
|
|
#include "misc.h"
|
|
|
|
#include "q_shared.h"
|
|
|
|
#include "console.h"
|
|
|
|
#include "earthquake.h"
|
|
|
|
#include "gravpath.h"
|
|
|
|
#include "armor.h"
|
|
|
|
#include "inventoryitem.h"
|
|
|
|
#include "gibs.h"
|
|
|
|
#include "spidermine.h"
|
|
|
|
#include "deadbody.h"
|
|
|
|
#include "actor.h"
|
1999-11-02 00:00:00 +00:00
|
|
|
#include "ctf.h"
|
|
|
|
|
1998-12-20 00:00:00 +00:00
|
|
|
#include <windows.h>
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
//temporarily put this in.
|
|
|
|
//#define OLD_DEATH_MESSAGES 1
|
|
|
|
|
1998-12-20 00:00:00 +00:00
|
|
|
const Vector power_color( 0.0, 1.0, 0.0 );
|
|
|
|
const Vector acolor( 1.0, 1.0, 1.0 );
|
|
|
|
const Vector bcolor( 1.0, 0.0, 0.0 );
|
|
|
|
|
|
|
|
static const char *ammo_types[ NUM_AMMO_TYPES ] =
|
|
|
|
{
|
|
|
|
"Bullet357", "ShotgunClip", "Bullet10mm", "Bullet50mm", "BulletPulse", "BulletSniper", "Rockets", "SpiderMines"
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char *armor_types[ NUM_ARMOR_TYPES ] =
|
|
|
|
{
|
|
|
|
"RiotHelmet", "FlakJacket", "FlakPants"
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
Event EV_Player_GodCheat( "superfuzz", EV_CHEAT );
|
|
|
|
Event EV_Player_NoTargetCheat( "wallflower", EV_CHEAT );
|
|
|
|
Event EV_Player_NoClipCheat( "nocollision", EV_CHEAT );
|
|
|
|
Event EV_Player_GiveAllCheat( "wuss", EV_CHEAT );
|
|
|
|
Event EV_Player_EndLevel( "endlevel" );
|
|
|
|
|
|
|
|
Event EV_Player_DevGodCheat( "god", EV_CHEAT );
|
|
|
|
Event EV_Player_DevNoTargetCheat( "notarget", EV_CHEAT );
|
|
|
|
Event EV_Player_DevNoClipCheat( "noclip", EV_CHEAT );
|
|
|
|
|
|
|
|
Event EV_Player_PrevWeapon( "weapprev", EV_CONSOLE );
|
|
|
|
Event EV_Player_NextWeapon( "weapnext", EV_CONSOLE );
|
|
|
|
Event EV_Player_PrevItem( "invprev", EV_CONSOLE );
|
|
|
|
Event EV_Player_NextItem( "invnext", EV_CONSOLE );
|
|
|
|
Event EV_Player_UseInventoryItem( "invuse", EV_CONSOLE );
|
|
|
|
Event EV_Player_GiveCheat( "give", EV_CHEAT );
|
|
|
|
Event EV_Player_Take( "take" );
|
|
|
|
Event EV_Player_UseItem( "use", EV_CONSOLE );
|
|
|
|
Event EV_Player_Spectator( "spectator", EV_CONSOLE );
|
|
|
|
Event EV_Player_GameVersion( "gameversion", EV_CONSOLE );
|
|
|
|
Event EV_Player_Fov( "fov" );
|
|
|
|
Event EV_Player_SaveFov( "savefov", EV_CONSOLE );
|
|
|
|
Event EV_Player_RestoreFov( "restorefov", EV_CONSOLE );
|
|
|
|
Event EV_Player_ToggleViewMode( "toggleviewmode", EV_CONSOLE );
|
|
|
|
Event EV_Player_ToggleZoomMode( "togglezoommode", EV_CHEAT );
|
|
|
|
Event EV_Player_ZoomOut( "zoomout" );
|
|
|
|
Event EV_Player_Kill( "playerkill", EV_CONSOLE );
|
|
|
|
Event EV_Player_Dead( "dead" );
|
|
|
|
Event EV_Player_SpawnEntity( "spawn", EV_CHEAT );
|
|
|
|
Event EV_Player_SpawnActor( "actor", EV_CHEAT );
|
|
|
|
Event EV_Player_ShowInfo( "showinfo", EV_CONSOLE );
|
|
|
|
Event EV_Player_ReadyToFire( "readytofire" );
|
|
|
|
Event EV_Player_WaitingToFire( "waitingtofire" );
|
|
|
|
Event EV_Player_AttackDone( "attackdone" );
|
|
|
|
Event EV_Player_AddPathNode( "addnode", EV_CHEAT );
|
|
|
|
Event EV_Player_Respawn( "respawn" );
|
|
|
|
Event EV_Player_ClearFloatingInventory( "clear_flinv" );
|
|
|
|
Event EV_Player_TestThread( "testthread", EV_CHEAT );
|
|
|
|
Event EV_Player_PowerupTimer( "poweruptimer" );
|
|
|
|
Event EV_Player_UpdatePowerupTimer( "updatepoweruptime" );
|
|
|
|
Event EV_Player_DrawOverlay( "drawoverlay" );
|
|
|
|
Event EV_Player_HideOverlay( "hideoverlay" );
|
|
|
|
Event EV_Player_DrawStats( "drawstats" );
|
|
|
|
Event EV_Player_HideStats( "hidestats" );
|
|
|
|
Event EV_Player_SetFlashColor( "setflashcolor" );
|
|
|
|
Event EV_Player_ClearFlashColor( "clearflashcolor" );
|
|
|
|
Event EV_Player_Mutate( "mutate", EV_CHEAT );
|
|
|
|
Event EV_Player_Human( "human", EV_CHEAT );
|
|
|
|
Event EV_Player_Skin( "skin" );
|
|
|
|
|
|
|
|
Event EV_Player_WhatIs( "whatis", EV_CHEAT );
|
|
|
|
Event EV_Player_ActorInfo( "actorinfo", EV_CHEAT );
|
|
|
|
Event EV_Player_Taunt( "taunt", EV_CONSOLE );
|
1999-11-02 00:00:00 +00:00
|
|
|
Event EV_Player_KillEnt( "killent", EV_CONSOLE | EV_CHEAT );
|
|
|
|
Event EV_Player_KillClass( "killclass", EV_CONSOLE | EV_CHEAT );
|
|
|
|
Event EV_Player_RemoveEnt( "removeent", EV_CONSOLE | EV_CHEAT );
|
|
|
|
Event EV_Player_RemoveClass( "removeclass", EV_CONSOLE | EV_CHEAT );
|
|
|
|
|
|
|
|
// CTF
|
|
|
|
Event EV_Player_CTF_JoinTeamHardcorps( "jointeamhardcorps", EV_CONSOLE );
|
|
|
|
Event EV_Player_CTF_JoinTeamSintek( "jointeamsintek", EV_CONSOLE );
|
|
|
|
Event EV_Player_CTF_Team( "team", EV_CONSOLE );
|
|
|
|
Event EV_Player_CTF_UpdateHookBeam( "updatebeam" );
|
|
|
|
Event EV_Player_CTF_DropTech( "droptech", EV_CONSOLE );
|
|
|
|
Event EV_Player_CTF_SoundEvent( "ctfsoundevent" );
|
|
|
|
Event EV_Player_DropWeaponEvent( "dropweap", EV_CONSOLE );
|
|
|
|
Event EV_Player_DropFlag( "dropflag", EV_CONSOLE );
|
1998-12-20 00:00:00 +00:00
|
|
|
|
|
|
|
#define UPRIGHT_SPEED 320.0f
|
|
|
|
#define CROUCH_SPEED 110.0f
|
|
|
|
#define ACCELERATION 10.0f
|
|
|
|
#define TAUNT_TIME 1.0f
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============================================================================
|
|
|
|
|
|
|
|
PLAYER
|
|
|
|
|
|
|
|
==============================================================================
|
|
|
|
*/
|
|
|
|
// deadflag values
|
|
|
|
|
|
|
|
cvar_t * s_debugmusic;
|
|
|
|
cvar_t * whereami;
|
|
|
|
|
|
|
|
CLASS_DECLARATION( Sentient, Player, "player" );
|
|
|
|
|
|
|
|
ResponseDef Player::Responses[] =
|
|
|
|
{
|
|
|
|
{ &EV_ClientMove, ( Response )Player::ClientThink },
|
|
|
|
{ &EV_ClientEndFrame, ( Response )Player::EndFrame },
|
|
|
|
{ &EV_Player_ShowInfo, ( Response )Player::ShowInfo },
|
|
|
|
{ &EV_Vehicle_Enter, ( Response )Player::EnterVehicle },
|
|
|
|
{ &EV_Vehicle_Exit, ( Response )Player::ExitVehicle },
|
|
|
|
|
|
|
|
{ &EV_Player_EndLevel, ( Response )Player::EndLevel },
|
|
|
|
|
|
|
|
{ &EV_Player_AddPathNode, ( Response )Player::AddPathNode },
|
|
|
|
{ &EV_Player_PrevWeapon, ( Response )Player::EventPreviousWeapon },
|
|
|
|
{ &EV_Player_NextWeapon, ( Response )Player::EventNextWeapon },
|
|
|
|
{ &EV_Player_PrevItem, ( Response )Player::EventPreviousItem },
|
|
|
|
{ &EV_Player_NextItem, ( Response )Player::EventNextItem },
|
|
|
|
{ &EV_Player_UseItem, ( Response )Player::EventUseItem },
|
|
|
|
{ &EV_Player_UseInventoryItem,( Response )Player::EventUseInventoryItem },
|
|
|
|
{ &EV_Player_GiveCheat, ( Response )Player::GiveCheat },
|
|
|
|
{ &EV_Player_GiveAllCheat, ( Response )Player::GiveAllCheat },
|
|
|
|
{ &EV_Player_Take, ( Response )Player::Take },
|
|
|
|
{ &EV_Player_GodCheat, ( Response )Player::GodCheat },
|
|
|
|
{ &EV_Player_DevGodCheat, ( Response )Player::GodCheat },
|
|
|
|
{ &EV_Player_Spectator, ( Response )Player::Spectator },
|
|
|
|
{ &EV_Player_NoTargetCheat, ( Response )Player::NoTargetCheat },
|
|
|
|
{ &EV_Player_DevNoTargetCheat,( Response )Player::NoTargetCheat },
|
|
|
|
{ &EV_Player_NoClipCheat, ( Response )Player::NoclipCheat },
|
|
|
|
{ &EV_Player_DevNoClipCheat, ( Response )Player::NoclipCheat },
|
|
|
|
{ &EV_Player_GameVersion, ( Response )Player::GameVersion },
|
|
|
|
{ &EV_Player_Fov, ( Response )Player::Fov },
|
|
|
|
{ &EV_Player_SaveFov, ( Response )Player::SaveFov },
|
|
|
|
{ &EV_Player_RestoreFov, ( Response )Player::RestoreFov },
|
|
|
|
{ &EV_Player_ToggleViewMode, ( Response )Player::ToggleViewMode },
|
|
|
|
{ &EV_Player_ToggleZoomMode, ( Response )Player::ToggleZoomMode },
|
|
|
|
{ &EV_Player_ZoomOut, ( Response )Player::ZoomOut },
|
|
|
|
{ &EV_EnterConsole, ( Response )Player::EnterConsole },
|
|
|
|
{ &EV_ExitConsole, ( Response )Player::ExitConsole },
|
|
|
|
{ &EV_KickFromConsole, ( Response )Player::KickConsole },
|
|
|
|
{ &EV_Player_Kill, ( Response )Player::Kill },
|
|
|
|
{ &EV_Player_Dead, ( Response )Player::Dead },
|
|
|
|
{ &EV_Player_SpawnEntity, ( Response )Player::SpawnEntity },
|
|
|
|
{ &EV_Player_SpawnActor, ( Response )Player::SpawnActor },
|
|
|
|
{ &EV_Player_Respawn, ( Response )Player::Respawn },
|
|
|
|
|
|
|
|
{ &EV_Pain, ( Response )Player::Pain },
|
|
|
|
{ &EV_Killed, ( Response )Player::Killed },
|
|
|
|
{ &EV_Gib, ( Response )Player::GibEvent },
|
|
|
|
{ &EV_GotKill, ( Response )Player::GotKill },
|
|
|
|
|
|
|
|
{ &EV_Player_ReadyToFire, ( Response )Player::ReadyToFire },
|
|
|
|
{ &EV_Player_WaitingToFire, ( Response )Player::WaitingToFire },
|
|
|
|
{ &EV_Player_AttackDone, ( Response )Player::DoneFiring },
|
|
|
|
{ &EV_Player_TestThread, ( Response )Player::TestThread },
|
|
|
|
|
|
|
|
{ &EV_Player_ClearFloatingInventory, (Response)Player::ClearFloatingInventory },
|
|
|
|
{ &EV_Player_PowerupTimer, ( Response )Player::SetPowerupTimer },
|
|
|
|
{ &EV_Player_UpdatePowerupTimer, ( Response )Player::UpdatePowerupTimer },
|
|
|
|
|
|
|
|
{ &EV_Player_WhatIs, ( Response )Player::WhatIs },
|
|
|
|
{ &EV_Player_ActorInfo, ( Response )Player::ActorInfo },
|
|
|
|
{ &EV_Player_Taunt, ( Response )Player::Taunt },
|
|
|
|
{ &EV_Player_KillEnt, ( Response )Player::KillEnt },
|
|
|
|
{ &EV_Player_RemoveEnt, ( Response )Player::RemoveEnt },
|
|
|
|
{ &EV_Player_KillClass, ( Response )Player::KillClass },
|
|
|
|
{ &EV_Player_RemoveClass, ( Response )Player::RemoveClass },
|
|
|
|
|
|
|
|
{ &EV_Player_DrawOverlay, ( Response )Player::DrawOverlay },
|
|
|
|
{ &EV_Player_HideOverlay, ( Response )Player::HideOverlay },
|
|
|
|
{ &EV_Player_DrawStats, ( Response )Player::DrawStats },
|
|
|
|
{ &EV_Player_HideStats, ( Response )Player::HideStats },
|
|
|
|
|
|
|
|
{ &EV_Player_SetFlashColor, ( Response )Player::SetFlashColor },
|
|
|
|
{ &EV_Player_ClearFlashColor, ( Response )Player::ClearFlashColor },
|
|
|
|
{ &EV_Player_Mutate, ( Response )Player::Mutate },
|
|
|
|
{ &EV_Player_Human, ( Response )Player::Human },
|
|
|
|
{ &EV_Player_Skin, ( Response )Player::SetSkin },
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
{ &EV_Player_CTF_JoinTeamHardcorps, ( Response )Player::CTF_JoinTeamHardcorps },
|
|
|
|
{ &EV_Player_CTF_JoinTeamSintek, ( Response )Player::CTF_JoinTeamSintek },
|
|
|
|
{ &EV_Player_CTF_Team, ( Response )Player::CTF_Team },
|
|
|
|
{ &EV_Player_CTF_UpdateHookBeam, ( Response )Player::CTF_UpdateHookBeam },
|
|
|
|
{ &EV_Player_CTF_DropTech, ( Response )Player::CTF_DropTech },
|
|
|
|
{ &EV_Player_CTF_SoundEvent, ( Response )Player::CTF_SoundEvent },
|
|
|
|
{ &EV_Player_DropWeaponEvent, ( Response )Player::DropWeaponEvent },
|
|
|
|
{ &EV_Player_DropFlag, ( Response )Player::CTF_DropFlag },
|
1998-12-20 00:00:00 +00:00
|
|
|
{ NULL, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
Player::Player()
|
|
|
|
{
|
|
|
|
path = NULL;
|
|
|
|
|
|
|
|
respawn_time = -1;
|
|
|
|
|
|
|
|
watchCamera = NULL;
|
|
|
|
thirdpersonCamera = NULL;
|
|
|
|
movieCamera = NULL;
|
|
|
|
spectatorCamera = NULL;
|
|
|
|
|
|
|
|
damage_blood = 0;
|
|
|
|
damage_alpha = 0;
|
|
|
|
|
|
|
|
action_level = 0;
|
|
|
|
drawoverlay = false;
|
|
|
|
|
|
|
|
defaultViewMode = FIRST_PERSON;
|
|
|
|
|
|
|
|
fov = atof( Info_ValueForKey( client->pers.userinfo, "fov" ) );
|
|
|
|
if ( fov < 1 )
|
|
|
|
{
|
|
|
|
fov = 90;
|
|
|
|
}
|
|
|
|
else if ( fov > 160 )
|
|
|
|
{
|
|
|
|
fov = 160;
|
|
|
|
}
|
|
|
|
|
|
|
|
savedfov = 0;
|
|
|
|
has_thought = false;
|
1999-11-02 00:00:00 +00:00
|
|
|
spectator_distance = 128;
|
|
|
|
|
|
|
|
grapple_pull = false;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
|
|
|
s_debugmusic = gi.cvar ("s_debugmusic", "0", 0);
|
|
|
|
whereami = gi.cvar ("whereami", "0", 0);
|
|
|
|
|
|
|
|
// Remove him from the world until we spawn him
|
|
|
|
unlink();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::InitSkin
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// If this is a new level, there will be no custom skin, so go back to the original blade skin.
|
|
|
|
if ( !LoadingSavegame && !deathmatch->value )
|
|
|
|
{
|
|
|
|
int playernum = edict-g_edicts-1;
|
|
|
|
|
|
|
|
strcpy( client->pers.skin, "blade_base" );
|
1999-11-02 00:00:00 +00:00
|
|
|
|
1998-12-20 00:00:00 +00:00
|
|
|
// combine name, skin and model into a configstring
|
|
|
|
gi.configstring( CS_PLAYERSKINS+playernum, va( "%s\\%s\\%s",
|
|
|
|
client->pers.netname,
|
|
|
|
client->pers.model,
|
|
|
|
client->pers.skin ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Player::Init
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
InitClient();
|
|
|
|
InitPhysics();
|
|
|
|
InitPowerups();
|
|
|
|
InitWorldEffects();
|
|
|
|
InitMusic();
|
|
|
|
InitPath();
|
|
|
|
InitView();
|
|
|
|
InitState();
|
|
|
|
InitEdict();
|
|
|
|
InitModel();
|
|
|
|
InitWeapons();
|
|
|
|
InitSkin();
|
|
|
|
|
1999-03-20 00:00:00 +00:00
|
|
|
// don't call RestoreEnt when respawning on a training level
|
1998-12-20 00:00:00 +00:00
|
|
|
if ( !LoadingServer && ( deathmatch->value || ( level.training && ( respawn_time != -1 ) ) ||
|
|
|
|
!PersistantData.RestoreEnt( this ) ) )
|
|
|
|
{
|
|
|
|
InitInventory();
|
|
|
|
InitHealth();
|
|
|
|
}
|
|
|
|
|
|
|
|
ChooseSpawnPoint();
|
|
|
|
|
|
|
|
if ( !LoadingSavegame && ( viewmode == THIRD_PERSON ) && !crosshair )
|
|
|
|
{
|
|
|
|
cvar_t * chair;
|
|
|
|
|
|
|
|
chair = gi.cvar("crosshair", "0", 0);
|
|
|
|
crosshair = new Entity;
|
|
|
|
crosshair->setModel( va( "sprites/crosshair%d.spr", (int)chair->value ) );
|
|
|
|
crosshair->edict->svflags |= SVF_ONLYPARENT;
|
|
|
|
crosshair->edict->owner = this->edict;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !deathmatch->value )
|
|
|
|
{
|
|
|
|
gi.AddCommandString( "con_clearfade\n" );
|
|
|
|
}
|
|
|
|
|
|
|
|
// make sure we put the player back into the world
|
1999-11-02 00:00:00 +00:00
|
|
|
link();
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Player::WritePersistantData
|
|
|
|
(
|
|
|
|
SpawnArgGroup &group
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
str text;
|
|
|
|
char t[ 3 ];
|
|
|
|
int hi;
|
|
|
|
int lo;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
// encode the damage states into a text string
|
|
|
|
t[ 2 ] = 0;
|
|
|
|
for( i = 0; i < MAX_MODEL_GROUPS; i++ )
|
|
|
|
{
|
|
|
|
hi = ( edict->s.groups[ i ] >> 4 ) & 0xf;
|
|
|
|
lo = edict->s.groups[ i ] & 0xf;
|
|
|
|
t[ 0 ] = ( char )( 'A' + hi );
|
|
|
|
t[ 1 ] = ( char )( 'A' + lo );
|
|
|
|
text += t;
|
|
|
|
}
|
|
|
|
|
|
|
|
G_SetSpawnArg( "savemodel", savemodel.c_str() );
|
|
|
|
G_SetSpawnArg( "saveskin", saveskin.c_str() );
|
|
|
|
G_SetSpawnArg( "damage_groups", text.c_str() );
|
|
|
|
G_SetFloatArg( "fov", fov );
|
|
|
|
G_SetIntArg( "defaultViewMode", defaultViewMode );
|
|
|
|
G_SetIntArg( "flags", flags & ( FL_GODMODE | FL_NOTARGET | FL_SP_MUTANT ) );
|
|
|
|
|
|
|
|
Sentient::WritePersistantData( group );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::RestorePersistantData
|
|
|
|
(
|
|
|
|
SpawnArgGroup &group
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
#ifndef SIN_DEMO
|
|
|
|
SpiderMine *spidermine;
|
|
|
|
Detonator *detonator;
|
|
|
|
#endif
|
|
|
|
int i;
|
|
|
|
int len;
|
|
|
|
str text;
|
|
|
|
const char *ptr;
|
|
|
|
int hi;
|
|
|
|
int lo;
|
|
|
|
|
|
|
|
Sentient::RestorePersistantData( group );
|
|
|
|
|
|
|
|
group.RestoreArgs( 1 );
|
|
|
|
|
|
|
|
// clear the damage states
|
|
|
|
memset( edict->s.groups, 0, sizeof( edict->s.groups ) );
|
|
|
|
|
|
|
|
savemodel = G_GetStringArg( "savemodel" );
|
|
|
|
saveskin = G_GetStringArg( "saveskin" );
|
|
|
|
|
|
|
|
text = G_GetStringArg( "damage_groups" );
|
|
|
|
len = text.length() >> 1;
|
|
|
|
if ( len > MAX_MODEL_GROUPS )
|
|
|
|
{
|
|
|
|
len = MAX_MODEL_GROUPS;
|
|
|
|
}
|
|
|
|
|
|
|
|
// decode the damage states from text string
|
|
|
|
ptr = text.c_str();
|
|
|
|
for( i = 0; i < len; i++ )
|
|
|
|
{
|
|
|
|
hi = ( *ptr++ - 'A' ) & 0xf;
|
|
|
|
lo = ( *ptr++ - 'A' ) & 0xf;
|
|
|
|
edict->s.groups[ i ] = ( hi << 4 ) + lo;
|
|
|
|
}
|
|
|
|
|
|
|
|
flags |= G_GetIntArg( "flags" );
|
|
|
|
fov = G_GetFloatArg( "fov", 90 );
|
|
|
|
defaultViewMode = ( viewmode_t )G_GetIntArg( "defaultViewMode", FIRST_PERSON );
|
|
|
|
|
|
|
|
#ifndef SIN_DEMO
|
|
|
|
spidermine = ( SpiderMine * )FindItem( "SpiderMine" );
|
|
|
|
detonator = ( Detonator * )FindItem( "Detonator" );
|
|
|
|
|
|
|
|
if ( spidermine )
|
|
|
|
{
|
|
|
|
spidermine->SetDetonator( detonator );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( FindItem( "Silencer" ) )
|
|
|
|
{
|
|
|
|
flags |= FL_SILENCER;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( FindItem( "ScubaGear" ) )
|
|
|
|
{
|
|
|
|
flags |= FL_OXYGEN;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( flags & FL_SP_MUTANT )
|
|
|
|
{
|
|
|
|
setModel( "manumit_pl.def" );
|
|
|
|
SetAnim( "idle" );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if ( defaultViewMode == CAMERA_VIEW )
|
|
|
|
{
|
|
|
|
defaultViewMode = FIRST_PERSON;
|
|
|
|
}
|
|
|
|
|
|
|
|
SetViewMode( defaultViewMode );
|
|
|
|
|
|
|
|
// prevent the player from starting dead
|
|
|
|
if ( health < 1 )
|
|
|
|
{
|
|
|
|
health = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::InitEdict
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
// entity state stuff
|
|
|
|
setSolidType( SOLID_BBOX );
|
|
|
|
setMoveType( MOVETYPE_WALK );
|
|
|
|
setSize( Vector( -16, -16, 0 ), Vector( 16, 16, STAND_HEIGHT ) );
|
|
|
|
edict->clipmask = MASK_PLAYERSOLID;
|
|
|
|
edict->svflags &= ~SVF_DEADMONSTER;
|
|
|
|
edict->svflags &= ~SVF_HIDEOWNER;
|
|
|
|
edict->owner = NULL;
|
|
|
|
|
|
|
|
// clear entity state values
|
|
|
|
edict->s.effects = 0;
|
|
|
|
edict->s.frame = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::InitMusic
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// reset the music
|
|
|
|
//
|
|
|
|
client->ps.current_music_mood = mood_normal;
|
|
|
|
client->ps.fallback_music_mood = mood_normal;
|
|
|
|
ChangeMusic( "normal", "normal", false );
|
|
|
|
music_forced = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::InitClient
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
client_persistant_t saved;
|
|
|
|
client_respawn_t resp;
|
1999-11-02 00:00:00 +00:00
|
|
|
float save_fov;
|
|
|
|
|
|
|
|
save_fov = client->ps.fov;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
|
|
|
// deathmatch wipes most client data every spawn
|
|
|
|
if ( deathmatch->value || level.training )
|
|
|
|
{
|
|
|
|
char userinfo[ MAX_INFO_STRING ];
|
|
|
|
|
|
|
|
resp = client->resp;
|
|
|
|
memcpy( userinfo, client->pers.userinfo, sizeof( userinfo ) );
|
|
|
|
G_InitClientPersistant( client );
|
|
|
|
G_ClientUserinfoChanged( edict, userinfo );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
memset( &resp, 0, sizeof( resp ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
// clear everything but the persistant data and fov
|
|
|
|
saved = client->pers;
|
|
|
|
memset( client, 0, sizeof( *client ) );
|
|
|
|
client->pers = saved;
|
|
|
|
client->resp = resp;
|
1999-11-02 00:00:00 +00:00
|
|
|
client->ps.fov = save_fov;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Player::InitState
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
in_console = false;
|
|
|
|
trappedInQuantum = false;
|
|
|
|
floating_owner = NULL;
|
|
|
|
gibbed = false;
|
|
|
|
enemy = NULL;
|
|
|
|
lastEnemyTime = 0;
|
|
|
|
lastTauntTime = 0;
|
1999-11-02 00:00:00 +00:00
|
|
|
grapple_pull = false;
|
|
|
|
grapple_speed = 0;
|
|
|
|
grapple_org = vec_zero;
|
|
|
|
grapple_time = 0;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
|
|
|
takedamage = DAMAGE_AIM;
|
|
|
|
deadflag = DEAD_NO;
|
|
|
|
flags &= ~FL_NO_KNOCKBACK;
|
|
|
|
flags |= ( FL_BLOOD | FL_DIE_GIBS );
|
|
|
|
|
|
|
|
if ( parentmode->value )
|
|
|
|
{
|
|
|
|
flags &= ~FL_BLOOD;
|
|
|
|
flags &= ~FL_DIE_GIBS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::InitHealth
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
// Don't do anything if we're loading a server game.
|
|
|
|
// This is either a loadgame or a restart
|
|
|
|
if ( LoadingServer )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// reset the health values
|
|
|
|
health = 100;
|
|
|
|
max_health = 100;
|
|
|
|
last_damage_time = 0;
|
|
|
|
|
|
|
|
// clear the damage states
|
|
|
|
memset( edict->s.groups, 0, sizeof( edict->s.groups ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::InitModel
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
str model;
|
|
|
|
|
|
|
|
// Model stuff
|
|
|
|
edict->s.renderfx |= RF_CUSTOMSKIN;
|
|
|
|
edict->s.skinnum = edict->s.number - 1;
|
|
|
|
|
|
|
|
// Make sure that the model is allowed
|
|
|
|
model = client->pers.model;
|
|
|
|
if ( !game.ValidPlayerModels.ObjectInList( model ) )
|
|
|
|
{
|
|
|
|
model = "pl_blade.def";
|
|
|
|
}
|
|
|
|
|
|
|
|
setModel( model.c_str() );
|
|
|
|
TempAnim( "idle", NULL );
|
|
|
|
showModel();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::InitPhysics
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
// Physics stuff
|
|
|
|
onladder = false;
|
|
|
|
sentientFrozen = false;
|
|
|
|
oldvelocity = vec_zero;
|
|
|
|
velocity = vec_zero;
|
|
|
|
gravity = 1.0;
|
|
|
|
falling = false;
|
|
|
|
fall_time = 0;
|
|
|
|
fall_value = 0;
|
|
|
|
fallsurface = NULL;
|
|
|
|
mass = 200;
|
|
|
|
xyspeed = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::InitPowerups
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
// powerups
|
|
|
|
poweruptimer = 0;
|
|
|
|
poweruptype = 0;
|
|
|
|
flags &= ~( FL_SHIELDS | FL_ADRENALINE | FL_CLOAK | FL_MUTANT | FL_SILENCER | FL_OXYGEN );
|
|
|
|
edict->s.renderfx &= ~( RF_DLIGHT | RF_ENVMAPPED );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::InitWorldEffects
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
// world effects
|
|
|
|
next_drown_time = 0;
|
|
|
|
air_finished = level.time + 20;
|
|
|
|
old_waterlevel = 0;
|
|
|
|
drown_damage = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::InitWeapons
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
// weapon stuff
|
|
|
|
firing = false;
|
|
|
|
firedown = false;
|
|
|
|
firedowntime = 0;
|
1999-11-02 00:00:00 +00:00
|
|
|
usedown = false;
|
1998-12-20 00:00:00 +00:00
|
|
|
gunoffset = Vector( 0, 0, STAND_HEIGHT );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::InitInventory
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
// Don't do anything if we're loading a server game.
|
|
|
|
// This is either a loadgame or a restart
|
|
|
|
if ( LoadingServer )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Give player the default weapon
|
|
|
|
if ( !FindItem( "Magnum" ) )
|
|
|
|
{
|
|
|
|
giveWeapon( "Magnum" );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !FindItem( "Fists" ) )
|
|
|
|
{
|
|
|
|
giveWeapon( "Fists" );
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef SIN_DEMO
|
|
|
|
if ( !FindItem( "SpiderMine" ) )
|
|
|
|
{
|
|
|
|
giveWeapon( "SpiderMine" );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::InitView
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
// Camera stuff
|
|
|
|
zoom_mode = ZOOMED_OUT;
|
|
|
|
spectator = false;
|
|
|
|
currentCameraTarget = 0;
|
|
|
|
checked_dead_camera = false;
|
|
|
|
SetViewMode( defaultViewMode );
|
|
|
|
|
|
|
|
// view stuff
|
|
|
|
kick_angles = vec_zero;
|
|
|
|
kick_origin = vec_zero;
|
|
|
|
v_angle = vec_zero;
|
|
|
|
oldviewangles = vec_zero;
|
|
|
|
v_gunoffset = vec_zero;
|
|
|
|
v_gunangles = vec_zero;
|
|
|
|
viewheight = STAND_EYE_HEIGHT;
|
|
|
|
|
|
|
|
// blend stuff
|
|
|
|
v_dmg_time = 0;
|
|
|
|
damage_blend = vec_zero;
|
|
|
|
flash_color[0] = flash_color[1] = flash_color[2] = flash_color[3] = 0;
|
|
|
|
|
|
|
|
// hud
|
|
|
|
hidestats = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::ChooseSpawnPoint
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
// set up the player's spawn location
|
1999-11-02 00:00:00 +00:00
|
|
|
SelectSpawnPoint( origin, angles, edict, &gravaxis );
|
1998-12-20 00:00:00 +00:00
|
|
|
setOrigin( origin + "0 0 17" );
|
|
|
|
worldorigin.copyTo( edict->s.old_origin );
|
|
|
|
edict->s.renderfx |= RF_FRAMELERP;
|
|
|
|
|
|
|
|
KillBox( this );
|
|
|
|
|
|
|
|
// set gravity axis
|
|
|
|
SetGravityAxis( gravaxis );
|
|
|
|
client->ps.pmove.gravity_axis = gravaxis;
|
|
|
|
|
|
|
|
// setup the orientation
|
|
|
|
setAngles( angles );
|
|
|
|
v_angle = worldangles;
|
|
|
|
|
|
|
|
// set the delta angle
|
|
|
|
client->ps.pmove.delta_angles[0] = ANGLE2SHORT( angles.x - client->resp.cmd_angles[0] );
|
|
|
|
client->ps.pmove.delta_angles[1] = ANGLE2SHORT( angles.y - client->resp.cmd_angles[1] );
|
|
|
|
client->ps.pmove.delta_angles[2] = ANGLE2SHORT( angles.z - client->resp.cmd_angles[2] );
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( ctf->value && client->resp.ctf_team > 0 )
|
|
|
|
SpawnTeleportEffect( worldorigin, 124 );
|
|
|
|
else if ( deathmatch->value || coop->value )
|
1998-12-20 00:00:00 +00:00
|
|
|
SpawnTeleportEffect( worldorigin, 124 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::InitPath
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
// pathnode placement stuff
|
|
|
|
nearestNode = NULL;
|
|
|
|
|
|
|
|
if ( ai_createnodes->value )
|
|
|
|
{
|
|
|
|
nearestNode = new PathNode;
|
|
|
|
nearestNode->Setup( worldorigin );
|
|
|
|
}
|
|
|
|
|
|
|
|
goalNode = nearestNode;
|
|
|
|
lastNode = nearestNode;
|
|
|
|
lastVisible = worldorigin;
|
|
|
|
searchTime = level.time + 0.1;
|
|
|
|
}
|
|
|
|
|
|
|
|
Player::~Player()
|
|
|
|
{
|
|
|
|
if ( client )
|
|
|
|
{
|
|
|
|
gi.bprintf( PRINT_HIGH, "%s disconnected\n", client->pers.netname );
|
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
//
|
|
|
|
// if he is in a vehicle
|
|
|
|
// get him out
|
|
|
|
//
|
|
|
|
if ( vehicle )
|
|
|
|
{
|
|
|
|
Event * event;
|
|
|
|
|
|
|
|
event = new Event( EV_Use );
|
|
|
|
event->AddEntity( this );
|
|
|
|
vehicle->ProcessEvent( event );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ctf->value )
|
|
|
|
{
|
|
|
|
CTF_DeadDropFlag();
|
|
|
|
CTF_DeadDropTech();
|
|
|
|
DropInventoryItems();
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
|
|
|
if ( watchCamera && ( ( watchCamera == thirdpersonCamera ) || ( watchCamera == spectatorCamera ) ) )
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
watchCamera->CancelPendingEvents();
|
1998-12-20 00:00:00 +00:00
|
|
|
delete watchCamera;
|
|
|
|
watchCamera = NULL;
|
|
|
|
thirdpersonCamera = NULL;
|
|
|
|
spectatorCamera = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( crosshair )
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
crosshair->CancelPendingEvents();
|
1998-12-20 00:00:00 +00:00
|
|
|
delete crosshair;
|
|
|
|
crosshair = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( path )
|
|
|
|
{
|
|
|
|
delete path;
|
|
|
|
path = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
edict->s.modelindex = 0;
|
|
|
|
|
|
|
|
gi.configstring( CS_PLAYERSKINS + entnum - 1, "" );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::EndLevel
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
if ( flags & FL_MUTANT )
|
|
|
|
{
|
|
|
|
Human( NULL );
|
|
|
|
}
|
|
|
|
|
|
|
|
InitPowerups();
|
|
|
|
if ( health > max_health )
|
|
|
|
{
|
|
|
|
health = max_health;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( health < 1 )
|
|
|
|
{
|
|
|
|
health = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::Respawn
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
if ( deathmatch->value || coop->value || level.training )
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
//assert ( deadflag == DEAD_DEAD );
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-03-20 00:00:00 +00:00
|
|
|
#ifdef SIN_ARCADE
|
|
|
|
if ( deathmatch->value )
|
|
|
|
{
|
|
|
|
FreeInventory();
|
|
|
|
}
|
|
|
|
#else
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( ctf->value )
|
|
|
|
{
|
|
|
|
CTF_DeadDropFlag();
|
|
|
|
CTF_DeadDropTech();
|
|
|
|
DropInventoryItems();
|
|
|
|
}
|
|
|
|
|
1998-12-20 00:00:00 +00:00
|
|
|
FreeInventory();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if ( !gibbed && !level.training )
|
|
|
|
{
|
|
|
|
CopyToBodyQueue( edict );
|
|
|
|
}
|
|
|
|
|
|
|
|
respawn_time = level.time;
|
|
|
|
|
|
|
|
Init();
|
|
|
|
|
|
|
|
// hold in place briefly
|
|
|
|
client->ps.pmove.pm_time = 50;
|
|
|
|
client->ps.pmove.pm_flags = PMF_TIME_TELEPORT;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// force the load game menu to come up
|
|
|
|
level.missionfailed = true;
|
|
|
|
level.missionfailedtime = level.time - FRAMETIME;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::SetDeltaAngles
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
// Use v_angle since we may be in a camera
|
|
|
|
for( i = 0; i < 3; i++ )
|
|
|
|
{
|
|
|
|
client->ps.pmove.delta_angles[ i ] = ANGLE2SHORT( v_angle[ i ] );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::Spectator
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( deadflag )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( spectator )
|
|
|
|
{
|
|
|
|
client->ps.stats[ STAT_LAYOUTS ] &= ~DRAW_SPECTATOR;
|
|
|
|
spectator = false;
|
|
|
|
if ( ctf->value )
|
|
|
|
{
|
|
|
|
InitCTF();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Respawn( NULL );
|
|
|
|
}
|
|
|
|
defaultViewMode = FIRST_PERSON;
|
|
|
|
SetViewMode( FIRST_PERSON );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// if he is in a vehicle
|
|
|
|
// get him out
|
|
|
|
//
|
|
|
|
if ( vehicle )
|
|
|
|
{
|
|
|
|
Event * event;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
event = new Event( EV_Use );
|
|
|
|
event->AddEntity( this );
|
|
|
|
vehicle->ProcessEvent( event );
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( ctf->value )
|
|
|
|
{
|
|
|
|
CTF_DeadDropFlag();
|
|
|
|
CTF_DeadDropTech();
|
|
|
|
CTF_ReleaseGrapple();
|
|
|
|
client->resp.ctf_team = CTF_NOTEAM;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( coop->value || ctf->value )
|
|
|
|
{
|
|
|
|
DropInventoryItems();
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
hideModel();
|
|
|
|
setSolidType( SOLID_NOT );
|
|
|
|
spectator = true;
|
|
|
|
takedamage = DAMAGE_NO;
|
|
|
|
FreeInventory();
|
|
|
|
defaultViewMode = FIRST_PERSON;
|
|
|
|
SetViewMode( FIRST_PERSON );
|
|
|
|
|
|
|
|
client->ps.stats[ STAT_LAYOUTS ] |= DRAW_SPECTATOR;
|
|
|
|
CTF_UpdateNumberOfPlayers();
|
|
|
|
spectator_distance = 128;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Player::Obituary
|
|
|
|
(
|
|
|
|
Entity *attacker,
|
|
|
|
Entity *inflictor,
|
|
|
|
str location,
|
|
|
|
int meansofdeath
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
char msg[ 1024 ];
|
1998-12-20 00:00:00 +00:00
|
|
|
const char *message1 = NULL;
|
|
|
|
const char *message2 = "";
|
|
|
|
int num;
|
|
|
|
if ( !deathmatch->value )
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Client killed themself
|
|
|
|
if ( attacker == this )
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( dedicated->value )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
switch ( meansofdeath )
|
|
|
|
{
|
|
|
|
case MOD_FALLING:
|
|
|
|
message1 = "fell down";
|
|
|
|
break;
|
|
|
|
case MOD_ADRENALINE:
|
|
|
|
message1 = "overdosed on adrenaline";
|
|
|
|
break;
|
|
|
|
case MOD_ION_DESTRUCT:
|
|
|
|
message1 = "overloaded his gun";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
message1 = "cracked under the pressure";
|
|
|
|
}
|
|
|
|
if ( message1 )
|
|
|
|
{
|
|
|
|
gi.printf( "%s %s.\n", client->pers.netname, message1 );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gi.printf( "%s died.\n", client->pers.netname );
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
#if OLD_DEATH_MESSAGES
|
1998-12-20 00:00:00 +00:00
|
|
|
if ( message1 )
|
|
|
|
{
|
|
|
|
gi.bprintf( PRINT_MEDIUM, "%s %s.\n", client->pers.netname, message1 );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gi.bprintf( PRINT_MEDIUM, "%s died.\n", client->pers.netname );
|
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
#else
|
|
|
|
// Send byte to the client to print deathmessage, 2nd parm is -1 beacause player
|
|
|
|
// killed themself.
|
|
|
|
Com_sprintf( msg, sizeof( msg ), "dm %i -1 %i", edict-g_edicts-1, meansofdeath );
|
|
|
|
gi.WriteByte( svc_console_command );
|
|
|
|
gi.WriteString( msg );
|
|
|
|
gi.multicast( NULL, MULTICAST_ALL_R );
|
|
|
|
#endif
|
1998-12-20 00:00:00 +00:00
|
|
|
client->resp.score--;
|
|
|
|
return;
|
1999-11-02 00:00:00 +00:00
|
|
|
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Killed by another client
|
|
|
|
if ( attacker && attacker->isClient() )
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( dedicated->value )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
switch (meansofdeath)
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
case MOD_FISTS: // FISTS
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
num = G_Random(6);
|
|
|
|
switch (num)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
message1 = "was knocked out by";
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
message1 = "was pummelled by";
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
message1 = "was over come by";
|
|
|
|
message2 = "'s ninja technique";
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
message1 = "ate a knuckle sandwich courtesy of";
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
message1 = "takes";
|
|
|
|
message2 = "'s beating";
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
message1 = "liked";
|
|
|
|
message2 = "'s death touch";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
message1 = "was killed by";
|
|
|
|
message2 = "'s fists";
|
|
|
|
break;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
break;
|
|
|
|
case MOD_MUTANTHANDS:
|
|
|
|
message1 = "was shredded by";
|
|
|
|
break;
|
|
|
|
case MOD_MAGNUM: // Magnum
|
|
|
|
{
|
|
|
|
num = G_Random(5);
|
|
|
|
switch (num)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
message1 = "was capped in the ass by";
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
message1 = "was gunned down in broad daylight by";
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
message1 = "eats";
|
|
|
|
message2 = "'s magnum";
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
message1 = "was punked by";
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
message1 = "was jacked by";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
message1 = "was killed by";
|
|
|
|
message2 = "'s magnum";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
case MOD_SHOTGUN: // Shotgun
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
num = G_Random(5);
|
|
|
|
switch (num)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
message1 = "is a victim of";
|
|
|
|
message2 = "'s shotgun";
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
message1 = "was slaughtered by";
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
message1 = "drowns in a rain of";
|
|
|
|
message2 = "'s hot lead";
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
message1 = "finds out why";
|
|
|
|
message2 = " got an F in gun safety";
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
message1 = "was shotgunned by";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
message1 = "was killed by";
|
|
|
|
message2 = "'s shotgun";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
case MOD_ASSRIFLE:
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
num = G_Random(4);
|
|
|
|
switch (num)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
message1 = "was assaulted by";
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
message1 = "was cut in half by";
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
message1 = "forgot that";
|
|
|
|
message2 = " had a bigger gun";
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
message1 = "was machinegunned down by";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
message1 = "was killed by";
|
|
|
|
message2 = "'s assault rifle";
|
|
|
|
break;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
break;
|
|
|
|
case MOD_CHAINGUN:
|
|
|
|
message1 = "was mowed down by";
|
|
|
|
message2 = "'s chaingun";
|
|
|
|
break;
|
|
|
|
case MOD_GRENADE:
|
|
|
|
message1 = "was fragged by";
|
|
|
|
message2 = "'s grenade";
|
|
|
|
break;
|
|
|
|
case MOD_THRALLBALL:
|
|
|
|
message1 = "ate";
|
|
|
|
message2 = "'s ThrallBall";
|
|
|
|
break;
|
|
|
|
case MOD_THRALLSPLASH:
|
|
|
|
message1 = "was bathed in";
|
|
|
|
message2 = "'s ThrallBall";
|
|
|
|
break;
|
|
|
|
case MOD_ROCKET:
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
num = G_Random(5);
|
|
|
|
switch (num)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
message1 = "was blown up by";
|
|
|
|
message2 = "'s direct rocket hit";
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
message1 = "bows down to";
|
|
|
|
message2 = "'s almighty rocket launcher";
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
message1 = "was incinerated by";
|
|
|
|
message2 = "'s rocket";
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
message1 = "was obliterated by";
|
|
|
|
message2 = "'s rocket";
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
message1 = "likes walking into";
|
|
|
|
message2 = "'s projectiles";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
message1 = "was killed by";
|
|
|
|
message2 = "'s rocket launcher";
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
break;
|
|
|
|
case MOD_ROCKETSPLASH:
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
num = G_Random(5);
|
|
|
|
switch (num)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
message1 = "was caught in";
|
|
|
|
message2 = "'s explosion";
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
message1 = "was burned to a crisp in";
|
|
|
|
message2 = "'s blast";
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
message1 = "is pulling shrapnel out of his ass thanks to";
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
message1 = "couldn't dodge";
|
|
|
|
message2 = "'s blast damage";
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
message1 = "was drenched by";
|
|
|
|
message2 = "'s splash damage";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
message1 = "was killed by";
|
|
|
|
message2 = "'s explosion";
|
|
|
|
}
|
|
|
|
break;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
case MOD_SPIDERSPLASH:
|
|
|
|
message1 = "was bitten by";
|
|
|
|
message2 = "'s spidermine";
|
|
|
|
break;
|
|
|
|
case MOD_SPEARGUN:
|
|
|
|
message1 = "was stuck by";
|
|
|
|
message2 = "'s spear";
|
|
|
|
break;
|
|
|
|
case MOD_PULSE:
|
|
|
|
message1 = "was pulsed by";
|
|
|
|
break;
|
|
|
|
case MOD_PULSELASER:
|
|
|
|
message1 = "was burned to a crisp by";
|
|
|
|
message2 = "'s laser";
|
|
|
|
break;
|
|
|
|
case MOD_ION:
|
|
|
|
case MOD_ION_DESTRUCT:
|
|
|
|
message1 = "Was ionized by";
|
|
|
|
break;
|
|
|
|
case MOD_QUANTUM:
|
|
|
|
message1 = "Was particlized by";
|
|
|
|
break;
|
|
|
|
case MOD_SNIPER:
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
num = G_Random(5);
|
|
|
|
switch (num)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
message1 = "was hollowpointed by";
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
message1 = "was put to sleep by";
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
message1 = "was sniped by";
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
message1 = "never saw it coming from";
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
message1 = "was killed by a precision shot from";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
message1 = "was killed by";
|
|
|
|
message2 = "'s sniper rifle";
|
|
|
|
}
|
|
|
|
break;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
case MOD_EMPATHY:
|
|
|
|
message1 = "felt";
|
|
|
|
message2 = "'s pain";
|
|
|
|
break;
|
|
|
|
case MOD_GRAPPLE:
|
|
|
|
message1 = "got stuck on";
|
|
|
|
message2 = "'s grapple";
|
|
|
|
break;
|
|
|
|
case MOD_FRIENDLY_FIRE:
|
|
|
|
message1 = "was killed by teammate";
|
|
|
|
break;
|
|
|
|
case MOD_CTFTURRET:
|
|
|
|
message1 = "was caught in the sights of";
|
|
|
|
message2 = "'s turret";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
message1 = "was killed by";
|
|
|
|
}
|
|
|
|
gi.printf( "%s %s %s%s\n", client->pers.netname,
|
|
|
|
message1,
|
|
|
|
attacker->client->pers.netname,
|
|
|
|
message2 );
|
|
|
|
}
|
|
|
|
#if OLD_DEATH_MESSAGES
|
1998-12-20 00:00:00 +00:00
|
|
|
gi.bprintf( PRINT_MEDIUM, "%s %s %s%s\n", client->pers.netname,
|
|
|
|
message1,
|
|
|
|
attacker->client->pers.netname,
|
|
|
|
message2 );
|
1999-11-02 00:00:00 +00:00
|
|
|
|
|
|
|
#else
|
|
|
|
Com_sprintf( msg, sizeof( msg ), "dm %i %i %i", edict-g_edicts-1, attacker->edict-g_edicts-1, meansofdeath );
|
|
|
|
gi.WriteByte( svc_console_command );
|
|
|
|
gi.WriteString( msg );
|
|
|
|
gi.multicast( NULL, MULTICAST_ALL_R );
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if ( meansofdeath != MOD_FRIENDLY_FIRE )
|
|
|
|
{
|
|
|
|
// Increment attacker's score if it wasn't a friendly kill
|
|
|
|
attacker->client->resp.score++;
|
|
|
|
}
|
|
|
|
|
1998-12-20 00:00:00 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Killed by a non-client
|
|
|
|
switch (meansofdeath)
|
|
|
|
{
|
|
|
|
case MOD_FALLING:
|
|
|
|
{
|
|
|
|
// Credit the last person who damaged me with the kill
|
|
|
|
if ( enemy && enemy->isClient() && ( enemy != this ) && level.time < lastEnemyTime )
|
|
|
|
{
|
|
|
|
attacker = enemy;
|
|
|
|
message1 = "was pushed over the edge by";
|
|
|
|
message2 = "";
|
|
|
|
|
|
|
|
// Give the last enemy a frag
|
|
|
|
enemy->client->resp.score++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
message1 = "fell down";
|
|
|
|
message2 = "";
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
case MOD_DEATHQUAD:
|
|
|
|
{
|
|
|
|
message1 = "held on to the DeathQuad for too long";
|
|
|
|
message2 = "";
|
|
|
|
break;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Killed indirectly by enemy
|
|
|
|
if (message1 && attacker->isClient() )
|
|
|
|
{
|
|
|
|
gi.bprintf( PRINT_MEDIUM, "%s %s %s%s\n", client->pers.netname,
|
|
|
|
message1,
|
|
|
|
attacker->client->pers.netname,
|
|
|
|
message2 );
|
|
|
|
}
|
|
|
|
// Killed by world somehow
|
|
|
|
else if (message1)
|
|
|
|
{
|
|
|
|
gi.bprintf( PRINT_MEDIUM, "%s %s\n", client->pers.netname,
|
|
|
|
message1);
|
|
|
|
client->resp.score--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gi.bprintf( PRINT_MEDIUM, "%s died.\n", client->pers.netname );
|
|
|
|
client->resp.score--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
|
1998-12-20 00:00:00 +00:00
|
|
|
void Player::Dead
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
deadflag = DEAD_DEAD;
|
|
|
|
StopAnimating();
|
|
|
|
|
|
|
|
//
|
|
|
|
// drop anything that might be attached to us
|
|
|
|
//
|
|
|
|
if (numchildren && ( level.training != 2 ) )
|
|
|
|
{
|
|
|
|
Entity * child;
|
|
|
|
int i;
|
|
|
|
//
|
|
|
|
// detach all our children
|
|
|
|
//
|
|
|
|
for ( i=0; i < MAX_MODEL_CHILDREN; i++ )
|
|
|
|
{
|
|
|
|
if (children[i])
|
|
|
|
{
|
|
|
|
child = ( Entity * )G_GetEntity( children[ i ] );
|
|
|
|
child->ProcessEvent( EV_Detach );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !deathmatch->value && !coop->value && !level.training )
|
|
|
|
{
|
|
|
|
// Fade to white
|
|
|
|
gi.WriteByte( svc_console_command );
|
|
|
|
gi.WriteString( "fo 0.8 1 1 1" );
|
|
|
|
gi.unicast( edict, false );
|
|
|
|
PostEvent( EV_Player_Respawn, 3.0f );
|
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
|
1998-12-20 00:00:00 +00:00
|
|
|
#ifdef SIN_ARCADE
|
1999-03-20 00:00:00 +00:00
|
|
|
gi.WriteByte( svc_stufftext );
|
|
|
|
gi.WriteString( "playerdead" );
|
|
|
|
gi.unicast( edict, true );
|
1998-12-20 00:00:00 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::Killed
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
Entity *attacker;
|
|
|
|
Entity *inflictor;
|
|
|
|
str location;
|
|
|
|
str prefix;
|
|
|
|
str aname;
|
|
|
|
int meansofdeath;
|
|
|
|
int i;
|
|
|
|
qboolean deathgib=false;
|
|
|
|
str dname;
|
|
|
|
Event *ev1;
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
attacker = ev->GetEntity( 1 );
|
|
|
|
inflictor = ev->GetEntity( 3 );
|
|
|
|
location = ev->GetString( 4 );
|
|
|
|
meansofdeath = ev->GetInteger( 5 );
|
|
|
|
|
|
|
|
//
|
|
|
|
// if he is in a vehicle
|
|
|
|
// get him out
|
|
|
|
//
|
|
|
|
if ( vehicle )
|
|
|
|
{
|
|
|
|
Event * event;
|
|
|
|
|
|
|
|
event = new Event( EV_Use );
|
|
|
|
event->AddEntity( this );
|
|
|
|
vehicle->ProcessEvent( event );
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
|
|
|
// Set the enemy to attacker if it is a client, otherwise
|
|
|
|
// some world object killed the player. We don't overwrite
|
|
|
|
// enemy with non-clients, so clients can get credit for
|
|
|
|
// kills they caused (i.e. shooting someone caused them to fall )
|
|
|
|
if ( attacker->isClient() )
|
|
|
|
{
|
|
|
|
enemy = attacker;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get rid of the third person crosshair if we have one
|
|
|
|
if ( crosshair )
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
crosshair->CancelPendingEvents();
|
1998-12-20 00:00:00 +00:00
|
|
|
delete crosshair;
|
|
|
|
crosshair = NULL;
|
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( ctf->value && ( meansofdeath != MOD_FRIENDLY_FIRE ) )
|
|
|
|
if ( attacker->isClient() )
|
|
|
|
CTF_FragBonuses( this, (Sentient *)attacker );
|
|
|
|
|
1998-12-20 00:00:00 +00:00
|
|
|
Obituary( attacker, inflictor, location, meansofdeath );
|
|
|
|
|
|
|
|
StopAnimating();
|
|
|
|
CancelPendingEvents();
|
|
|
|
|
|
|
|
//
|
|
|
|
// determine death animation
|
|
|
|
//
|
|
|
|
if ( DoGib( meansofdeath, inflictor ) )
|
|
|
|
{
|
|
|
|
deathgib = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
prefix = AnimPrefixForPlayer();
|
|
|
|
|
|
|
|
if ( deathgib )
|
|
|
|
{
|
|
|
|
str location;
|
|
|
|
|
|
|
|
location = ev->GetString( 4 );
|
|
|
|
|
|
|
|
// Check for location first otherwise randomize
|
|
|
|
if ( location == "torso_upper" )
|
|
|
|
dname += str( "gibdeath_upper" );
|
|
|
|
else if ( location == "torso_lower" )
|
|
|
|
dname += str( "gibdeath_lower" );
|
|
|
|
else if ( strstr( location.c_str(), "leg" ) )
|
|
|
|
dname += str( "gibdeath_lower" );
|
|
|
|
else if ( strstr( location.c_str(), "arm" ) )
|
|
|
|
dname += str( "gibdeath_upper" );
|
|
|
|
else if ( strstr( location.c_str(), "head" ) )
|
|
|
|
dname += str( "gibdeath_upper" );
|
|
|
|
else if ( G_Random() > 0.5 )
|
|
|
|
dname += str( "gibdeath_upper" );
|
|
|
|
else
|
|
|
|
dname += str( "gibdeath_lower" );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( deathgib )
|
|
|
|
aname = prefix + dname;
|
|
|
|
else
|
|
|
|
aname = prefix + str("death_") + location;
|
|
|
|
|
|
|
|
i = gi.Anim_Random( edict->s.modelindex, aname.c_str() );
|
|
|
|
|
|
|
|
if ( i == -1 )
|
|
|
|
{
|
|
|
|
aname = prefix + str("death");
|
|
|
|
}
|
|
|
|
|
1999-03-20 00:00:00 +00:00
|
|
|
// moved to before the deadflag being set to prevent a definate game crash
|
|
|
|
if ( flags & ( FL_MUTANT|FL_SP_MUTANT ) )
|
|
|
|
{
|
|
|
|
Human( NULL );
|
|
|
|
}
|
|
|
|
|
1998-12-20 00:00:00 +00:00
|
|
|
deadflag = DEAD_DYING;
|
|
|
|
|
|
|
|
respawn_time = level.time + 1.0;
|
|
|
|
|
|
|
|
if ( currentWeapon )
|
|
|
|
{
|
|
|
|
if ( !level.training )
|
|
|
|
{
|
|
|
|
DropWeapon( currentWeapon );
|
|
|
|
}
|
|
|
|
else if ( level.training != 2 )
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
currentWeapon->CancelPendingEvents();
|
1998-12-20 00:00:00 +00:00
|
|
|
delete currentWeapon;
|
1999-11-02 00:00:00 +00:00
|
|
|
currentWeapon = NULL;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( ctf->value )
|
|
|
|
{
|
|
|
|
CTF_DeadDropFlag();
|
|
|
|
CTF_DeadDropTech();
|
|
|
|
CTF_ReleaseGrapple();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( coop->value || ctf->value )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
|
|
|
DropInventoryItems();
|
|
|
|
}
|
|
|
|
|
|
|
|
edict->clipmask = MASK_DEADSOLID;
|
|
|
|
edict->svflags |= SVF_DEADMONSTER;
|
|
|
|
|
|
|
|
ProcessEvent( EV_Player_ZoomOut );
|
|
|
|
SetViewMode( THIRD_PERSON );
|
|
|
|
setMoveType( MOVETYPE_NONE );
|
|
|
|
|
|
|
|
edict->s.renderfx &= ~RF_DLIGHT;
|
|
|
|
edict->s.renderfx &= ~RF_ENVMAPPED;
|
|
|
|
|
|
|
|
angles.x = 0;
|
|
|
|
angles.z = 0;
|
|
|
|
setAngles( angles );
|
|
|
|
|
|
|
|
if ( deathmatch->value )
|
|
|
|
{
|
|
|
|
client->showinfo = true;
|
|
|
|
G_DeathmatchScoreboard( this );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( flags & ( FL_MUTANT|FL_SP_MUTANT ) )
|
|
|
|
{
|
|
|
|
ev1 = new Event( EV_Gib );
|
|
|
|
ev1->AddInteger( 0 );
|
|
|
|
ProcessEvent( ev1 );
|
|
|
|
ProcessEvent( EV_Player_Dead );
|
|
|
|
}
|
|
|
|
else if ( strstr( aname.c_str(), "gibdeath" ) )
|
|
|
|
{
|
|
|
|
ev1 = new Event( EV_Gib );
|
|
|
|
ev1->AddInteger( 1 );
|
|
|
|
ProcessEvent( ev1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
RandomAnimate( aname.c_str(), EV_Player_Dead );
|
|
|
|
animOverride = true;
|
|
|
|
|
|
|
|
//
|
|
|
|
// change music
|
|
|
|
//
|
|
|
|
ChangeMusic( "failure", "normal", true );
|
|
|
|
|
|
|
|
if ( !deathmatch->value && !level.training && !level.no_jc )
|
|
|
|
{
|
|
|
|
char name[ 128 ];
|
|
|
|
int num;
|
|
|
|
|
|
|
|
num = (int)G_Random( 4 ) + 1;
|
|
|
|
sprintf( name, "global/universal_script.scr::jc_talks_blade_dies%d", num );
|
|
|
|
ExecuteThread( name, true );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::Pain
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
float damage,delta;
|
|
|
|
Entity *attacker;
|
|
|
|
int meansofdeath;
|
|
|
|
|
|
|
|
damage = ev->GetFloat( 1 );
|
|
|
|
attacker = ev->GetEntity( 2 );
|
|
|
|
meansofdeath = ev->GetInteger( 4 );
|
|
|
|
|
|
|
|
if ( viewmode == CAMERA_VIEW )
|
|
|
|
{
|
|
|
|
if ( level.cinematic )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ExitConsole( NULL );
|
|
|
|
SetCamera( NULL );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// add to our damage time
|
|
|
|
v_dmg_time = level.time + DAMAGE_TIME;
|
|
|
|
|
|
|
|
if ( attacker->isClient() )
|
|
|
|
{
|
|
|
|
if ( !deadflag )
|
|
|
|
{
|
|
|
|
enemy = attacker;
|
|
|
|
lastEnemyTime = level.time + ENEMY_TIME;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// increase action level of game
|
|
|
|
action_level += damage;
|
|
|
|
|
|
|
|
// add to the damage inflicted on a player this frame
|
|
|
|
// the total will be turned into screen blends and view angle kicks
|
|
|
|
// at the end of the frame
|
|
|
|
damage_blood += damage;
|
|
|
|
|
|
|
|
// white flash signifying no damage was taken.
|
|
|
|
if ( ( damage <= 0 ) && ( meansofdeath != MOD_FISTS ) )
|
|
|
|
{
|
|
|
|
Event *ev1;
|
|
|
|
|
|
|
|
ProcessEvent( EV_Player_ClearFlashColor );
|
|
|
|
ev1 = new Event( EV_Player_SetFlashColor );
|
|
|
|
|
|
|
|
// Flash the player white
|
|
|
|
ev1->AddFloat( 1 );
|
|
|
|
ev1->AddFloat( 1 );
|
|
|
|
ev1->AddFloat( 1 );
|
|
|
|
ev1->AddFloat( 0.3 );
|
|
|
|
ProcessEvent( ev1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
delta = level.time - last_damage_time;
|
|
|
|
|
|
|
|
// Don' play more than one pain sound or animation a second
|
|
|
|
if ( delta < 1.0 )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
last_damage_time = level.time;
|
|
|
|
|
|
|
|
// If damage > 5 then play a pain animation, otherwise play a pain sound
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( !firing && !deadflag && !vehicle && damage > 5)
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
|
|
|
str prefix;
|
|
|
|
str aname;
|
|
|
|
int index;
|
|
|
|
|
|
|
|
//
|
|
|
|
// determine pain animation
|
|
|
|
//
|
|
|
|
prefix = AnimPrefixForPlayer();
|
|
|
|
aname = prefix + str("pain_") + str( ev->GetString( 3 ) );
|
|
|
|
index = gi.Anim_Random( edict->s.modelindex, aname.c_str() );
|
|
|
|
if ( index == -1 )
|
|
|
|
{
|
|
|
|
aname = prefix + str("pain");
|
|
|
|
}
|
|
|
|
|
|
|
|
TempAnim( aname.c_str(), NULL );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RandomSound( "snd_pain", 1 );
|
|
|
|
ProcessEvent( EV_PainSound );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::DoUse
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int num;
|
|
|
|
edict_t *touch[ MAX_EDICTS ];
|
|
|
|
edict_t *hit;
|
|
|
|
Event *ev;
|
|
|
|
Vector min;
|
|
|
|
Vector max;
|
|
|
|
Vector offset;
|
|
|
|
trace_t trace;
|
|
|
|
Vector start;
|
|
|
|
Vector end;
|
|
|
|
float t;
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( spectator )
|
|
|
|
{
|
|
|
|
ChangeSpectator();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ctf->value && vehicle )
|
|
|
|
{
|
|
|
|
ev = new Event( EV_Use );
|
|
|
|
ev->AddEntity( this );
|
|
|
|
vehicle->ProcessEvent( ev );
|
|
|
|
return;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
|
|
|
// Pickup inventory if one exists
|
|
|
|
PickupFloatingInventory();
|
|
|
|
|
|
|
|
start = worldorigin + Vector( 0, 0, viewheight );
|
|
|
|
end = start + Vector( orientation[ 0 ] ) * 64.0f;
|
|
|
|
|
|
|
|
trace = G_Trace( start, vec_zero, vec_zero, end, this, MASK_SOLID, "Player::DoUse" );
|
|
|
|
|
|
|
|
t = 64 * trace.fraction - maxs[ 0 ];
|
|
|
|
if ( t < 0 )
|
|
|
|
{
|
|
|
|
t = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
offset = Vector( orientation[ 0 ] ) * t;
|
|
|
|
|
|
|
|
min = start + offset + "-16 -16 -16";
|
|
|
|
max = start + offset + "16 16 16";
|
|
|
|
|
|
|
|
num = gi.BoxEdicts( min.vec3(), max.vec3(), touch, MAX_EDICTS, AREA_TRIGGERS );
|
|
|
|
|
|
|
|
// be careful, it is possible to have an entity in this
|
|
|
|
// list removed before we get to it (killtriggered)
|
|
|
|
for( i = 0; i < num; i++ )
|
|
|
|
{
|
|
|
|
hit = touch[ i ];
|
|
|
|
if ( !hit->inuse )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert( hit->entity );
|
|
|
|
|
|
|
|
ev = new Event( EV_Use );
|
|
|
|
ev->AddEntity( this );
|
|
|
|
hit->entity->ProcessEvent( ev );
|
|
|
|
}
|
|
|
|
|
|
|
|
num = gi.BoxEdicts( min.vec3(), max.vec3(), touch, MAX_EDICTS, AREA_SOLID );
|
|
|
|
|
|
|
|
// be careful, it is possible to have an entity in this
|
|
|
|
// list removed before we get to it (killtriggered)
|
|
|
|
for( i = 0; i < num; i++ )
|
|
|
|
{
|
|
|
|
hit = touch[ i ];
|
|
|
|
if ( !hit->inuse )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert( hit->entity );
|
|
|
|
|
|
|
|
ev = new Event( EV_Use );
|
|
|
|
ev->AddEntity( this );
|
|
|
|
hit->entity->ProcessEvent( ev );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Force a reload on a weapon
|
|
|
|
if ( currentWeapon )
|
|
|
|
{
|
|
|
|
currentWeapon->ForceReload();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static Entity *pm_passent;
|
|
|
|
|
|
|
|
// pmove doesn't need to know about passent and contentmask
|
|
|
|
extern "C" trace_t PM_trace
|
|
|
|
(
|
|
|
|
vec3_t start,
|
|
|
|
vec3_t mins,
|
|
|
|
vec3_t maxs,
|
|
|
|
vec3_t end
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
if ( ( pm_passent->flags & FL_GODMODE ) || ( pm_passent->health > 0 ) )
|
|
|
|
{
|
|
|
|
return G_Trace( start, mins, maxs, end, pm_passent->edict, MASK_PLAYERSOLID, "PM_trace 1" );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return G_Trace( start, mins, maxs, end, pm_passent->edict, MASK_DEADSOLID, "PM_trace 1" );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_FROM_DLL void Player::SetViewMode
|
|
|
|
(
|
|
|
|
viewmode_t mode,
|
|
|
|
Entity * newCamera
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
Camera *c;
|
|
|
|
|
|
|
|
viewmode = mode;
|
|
|
|
|
|
|
|
if ( watchCamera && ( ( watchCamera == thirdpersonCamera ) || ( watchCamera == spectatorCamera ) ) )
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
watchCamera->CancelPendingEvents();
|
1998-12-20 00:00:00 +00:00
|
|
|
delete watchCamera;
|
|
|
|
watchCamera = NULL;
|
|
|
|
thirdpersonCamera = NULL;
|
|
|
|
spectatorCamera = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( crosshair )
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
crosshair->CancelPendingEvents();
|
1998-12-20 00:00:00 +00:00
|
|
|
delete crosshair;
|
|
|
|
crosshair = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch( viewmode )
|
|
|
|
{
|
|
|
|
default :
|
|
|
|
case THIRD_PERSON :
|
|
|
|
{
|
|
|
|
Event * ev;
|
|
|
|
Vector pos;
|
|
|
|
|
|
|
|
c = new Camera;
|
|
|
|
|
|
|
|
ev = new Event( EV_Camera_MoveToPos );
|
|
|
|
pos = worldorigin;
|
|
|
|
pos.z = absmax.z;
|
|
|
|
ev->AddVector( pos );
|
|
|
|
c->ProcessEvent( ev );
|
|
|
|
|
|
|
|
ev = new Event( EV_Camera_TurnTo );
|
|
|
|
ev->AddVector( v_angle );
|
|
|
|
c->ProcessEvent( ev );
|
|
|
|
|
|
|
|
if ( vehicle )
|
|
|
|
c->FollowEntity( this, 256, MASK_OPAQUE );
|
|
|
|
else
|
|
|
|
c->FollowEntity( this, 128, MASK_PLAYERSOLID );
|
|
|
|
watchCamera = c;
|
|
|
|
thirdpersonCamera = c;
|
|
|
|
|
|
|
|
if ( !deadflag )
|
|
|
|
{
|
|
|
|
cvar_t * chair;
|
|
|
|
|
|
|
|
chair = gi.cvar("crosshair", "0", 0);
|
|
|
|
crosshair = new Entity;
|
|
|
|
crosshair->setModel( va( "sprites/crosshair%d.spr", (int)chair->value ) );
|
|
|
|
crosshair->edict->svflags |= SVF_ONLYPARENT;
|
|
|
|
crosshair->edict->owner = this->edict;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SPECTATOR :
|
|
|
|
{
|
|
|
|
Event * ev;
|
|
|
|
Vector pos;
|
|
|
|
edict_t *cl_ent;
|
|
|
|
|
|
|
|
cl_ent = g_edicts + 1 + currentCameraTarget;
|
1999-11-02 00:00:00 +00:00
|
|
|
if
|
|
|
|
(
|
|
|
|
!cl_ent->inuse ||
|
|
|
|
!cl_ent->entity ||
|
|
|
|
( !cl_ent->entity->client ) ||
|
|
|
|
( ( ( Player * )cl_ent->entity )->spectator )
|
|
|
|
)
|
|
|
|
{
|
|
|
|
ChangeSpectator();
|
|
|
|
if
|
|
|
|
(
|
|
|
|
!cl_ent->inuse ||
|
|
|
|
!cl_ent->entity ||
|
|
|
|
( !cl_ent->entity->client ) ||
|
|
|
|
( ( ( Player * )cl_ent->entity )->spectator )
|
|
|
|
)
|
|
|
|
{
|
|
|
|
SetViewMode( FIRST_PERSON );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
c = new Camera;
|
|
|
|
|
|
|
|
ev = new Event( EV_Camera_MoveToPos );
|
|
|
|
pos = cl_ent->entity->worldorigin;
|
|
|
|
pos.z = cl_ent->entity->absmax.z;
|
|
|
|
ev->AddVector( pos );
|
|
|
|
c->ProcessEvent( ev );
|
|
|
|
|
|
|
|
ev = new Event( EV_Camera_TurnTo );
|
|
|
|
ev->AddVector( cl_ent->entity->worldangles );
|
|
|
|
c->ProcessEvent( ev );
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
c->FollowEntity( cl_ent->entity, spectator_distance, MASK_PLAYERSOLID );
|
1998-12-20 00:00:00 +00:00
|
|
|
watchCamera = c;
|
|
|
|
spectatorCamera = c;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FIRST_PERSON :
|
|
|
|
watchCamera = this;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CAMERA_VIEW :
|
|
|
|
watchCamera = newCamera;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_FROM_DLL void Player::CheckButtons
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
// Only process buttons if you're not dying
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( ( deadflag != DEAD_NO ) || spectator )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
|
|
|
|
if ( spectator && ( ( new_buttons & BUTTON_ATTACK ) && ( !firedown ) ) )
|
|
|
|
{
|
|
|
|
// we set defaultViewMode as if we toggled the camera
|
|
|
|
if ( defaultViewMode == FIRST_PERSON )
|
|
|
|
{
|
|
|
|
defaultViewMode = SPECTATOR;
|
|
|
|
}
|
|
|
|
ChangeSpectator();
|
|
|
|
}
|
|
|
|
else if
|
|
|
|
(
|
|
|
|
spectator && ( buttons & BUTTON_USE ) && ( viewmode == SPECTATOR )
|
|
|
|
)
|
|
|
|
{
|
|
|
|
spectator_distance += 2;
|
|
|
|
if ( spectator_distance > 384 )
|
|
|
|
spectator_distance = 0;
|
|
|
|
if ( spectatorCamera )
|
|
|
|
{
|
|
|
|
Camera * cam;
|
|
|
|
|
|
|
|
cam = ( Camera * )( ( Entity * )spectatorCamera );
|
|
|
|
cam->SetCurrentDistance( spectator_distance );
|
|
|
|
}
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// Check for the use key getting pressed
|
|
|
|
if ( new_buttons & BUTTON_USE )
|
|
|
|
{
|
|
|
|
if ( ctf->value )
|
|
|
|
{
|
|
|
|
usedown = true;
|
|
|
|
CTF_ExtendGrapple();
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
DoUse();
|
1999-11-02 00:00:00 +00:00
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( ctf->value )
|
|
|
|
{
|
|
|
|
// Check for use key being released
|
|
|
|
if ( !( buttons & BUTTON_USE ) )
|
|
|
|
{
|
|
|
|
if ( usedown )
|
|
|
|
{
|
|
|
|
CTF_ReleaseGrapple();
|
|
|
|
usedown = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
|
|
|
// Check for button release
|
|
|
|
if ( !( buttons & BUTTON_ATTACK ) )
|
|
|
|
{
|
|
|
|
if ( firedown )
|
|
|
|
{
|
|
|
|
Event *event;
|
|
|
|
event = new Event( EV_Sentient_ReleaseAttack );
|
|
|
|
event->AddFloat( level.time - firedowntime );
|
|
|
|
ProcessEvent( event );
|
|
|
|
firedown = false;
|
1999-11-02 00:00:00 +00:00
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// fire weapon from final position if needed
|
|
|
|
if ( ( buttons & BUTTON_ATTACK ) && WeaponReady() )
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// raise the action level
|
|
|
|
//
|
|
|
|
if ( currentWeapon )
|
|
|
|
action_level += currentWeapon->ActionLevelIncrement();
|
|
|
|
|
|
|
|
firedown = true;
|
|
|
|
firedowntime = level.time;
|
|
|
|
|
|
|
|
if ( !vehicle )
|
|
|
|
{
|
|
|
|
str name;
|
|
|
|
str prefix;
|
|
|
|
|
|
|
|
prefix = AnimPrefixForPlayer();
|
|
|
|
//
|
|
|
|
// append the prefix based on which weapon we are holding
|
|
|
|
//
|
|
|
|
prefix += str( AnimPrefixForWeapon() );
|
|
|
|
|
|
|
|
if ( ( xyspeed > 20 ) )
|
|
|
|
{
|
|
|
|
int num;
|
|
|
|
int numframes;
|
|
|
|
|
|
|
|
if ( ( waterlevel > 2 ) || ( xyspeed > 250 ) )
|
|
|
|
name = prefix + str("run_fire");
|
|
|
|
else
|
|
|
|
name = prefix + str("walk_fire");
|
|
|
|
num = gi.Anim_Random( edict->s.modelindex, name.c_str() );
|
|
|
|
if ( num != -1 )
|
|
|
|
{
|
|
|
|
numframes = gi.Anim_NumFrames( edict->s.modelindex, num );
|
|
|
|
if ( ( last_frame_in_anim + 1 ) == numframes )
|
|
|
|
edict->s.anim = num;
|
|
|
|
else
|
|
|
|
TempAnim( name.c_str(), NULL );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
name = prefix + str("fire");
|
|
|
|
TempAnim( name.c_str(), NULL );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
name = prefix + str("fire");
|
|
|
|
TempAnim( name.c_str(), NULL );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ProcessEvent( EV_Sentient_Attack );
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( ctf->value )
|
|
|
|
{
|
|
|
|
Event *ctfev;
|
|
|
|
|
|
|
|
ctfev = new Event( EV_Player_CTF_SoundEvent );
|
|
|
|
ctfev->AddInteger( FIRE );
|
|
|
|
ProcessEvent( ctfev );
|
|
|
|
}
|
|
|
|
|
1998-12-20 00:00:00 +00:00
|
|
|
if ( ai_createnodes->value )
|
|
|
|
{
|
|
|
|
goalNode = nearestNode;
|
|
|
|
if ( !goalNode )
|
|
|
|
{
|
|
|
|
if ( ai_debugpath->value )
|
|
|
|
{
|
|
|
|
gi.dprintf( "New path node\n" );
|
|
|
|
}
|
|
|
|
nearestNode = new PathNode;
|
|
|
|
nearestNode->Setup( worldorigin );
|
|
|
|
goalNode = nearestNode;
|
|
|
|
lastNode = nearestNode;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_FROM_DLL void Player::TouchStuff
|
|
|
|
(
|
|
|
|
pmove_t *pm
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
edict_t *other;
|
|
|
|
Event *event;
|
|
|
|
int i;
|
|
|
|
int j;
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( spectator )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( getMoveType() != MOVETYPE_NOCLIP )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
|
|
|
G_TouchTriggers( this );
|
|
|
|
}
|
|
|
|
|
|
|
|
// touch other objects
|
|
|
|
for( i = 0; i < pm->numtouch; i++ )
|
|
|
|
{
|
|
|
|
other = pm->touchents[ i ];
|
|
|
|
for( j = 0; j < i ; j++ )
|
|
|
|
{
|
|
|
|
if ( pm->touchents[ j ] == other )
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( j != i )
|
|
|
|
{
|
|
|
|
// duplicated
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Don't bother touching the world
|
|
|
|
if ( ( !other->entity ) || ( other->entity == world ) )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
event = new Event( EV_Touch );
|
|
|
|
event->AddEntity( this );
|
|
|
|
other->entity->ProcessEvent( event );
|
|
|
|
|
|
|
|
event = new Event( EV_Touch );
|
|
|
|
event->AddEntity( other->entity );
|
|
|
|
ProcessEvent( event );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_FROM_DLL void Player::EnterVehicle
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
Entity *ent;
|
|
|
|
|
|
|
|
ent = ev->GetEntity( 1 );
|
|
|
|
if ( ent && ent->isSubclassOf( Vehicle ) )
|
|
|
|
{
|
|
|
|
viewheight = STAND_EYE_HEIGHT;
|
|
|
|
levelVars.SetVariable( "player_in_vehicle", 1 );
|
|
|
|
velocity = vec_zero;
|
|
|
|
vehicle = ( Vehicle * )ent;
|
|
|
|
if ( vehicle->IsDrivable() )
|
|
|
|
setMoveType( MOVETYPE_VEHICLE );
|
|
|
|
else
|
|
|
|
setMoveType( MOVETYPE_NOCLIP );
|
|
|
|
if ( ev->NumArgs() > 1 )
|
|
|
|
vehicleanim = ev->GetString( 2 );
|
|
|
|
else
|
|
|
|
vehicleanim = "drive";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_FROM_DLL void Player::ExitVehicle
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
levelVars.SetVariable( "player_in_vehicle", 0 );
|
|
|
|
setMoveType( MOVETYPE_WALK );
|
|
|
|
vehicle = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_FROM_DLL void Player::GetMoveInfo
|
|
|
|
(
|
|
|
|
pmove_t *pm
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
if ( !deadflag )
|
|
|
|
{
|
|
|
|
v_angle[ 0 ] = pm->viewangles[ 0 ];
|
|
|
|
v_angle[ 1 ] = pm->viewangles[ 1 ];
|
|
|
|
v_angle[ 2 ] = pm->viewangles[ 2 ];
|
|
|
|
AnglesToMat( v_angle.vec3(), orientation );
|
|
|
|
}
|
|
|
|
|
|
|
|
client->ps.pmove = pm->s;
|
|
|
|
old_pmove = pm->s;
|
|
|
|
|
|
|
|
setOrigin( Vector( pm->s.origin[ 0 ], pm->s.origin[ 1 ], pm->s.origin[ 2 ] ) * 0.125 );
|
|
|
|
velocity = Vector( pm->s.velocity[ 0 ], pm->s.velocity[ 1 ], pm->s.velocity[ 2 ] ) * 0.125;
|
|
|
|
|
|
|
|
if (
|
|
|
|
( client->ps.pmove.pm_type == PM_FREEZE ) ||
|
|
|
|
( client->ps.pmove.pm_type == PM_INVEHICLE_ZOOM ) ||
|
|
|
|
( client->ps.pmove.pm_type == PM_INVEHICLE )
|
|
|
|
)
|
|
|
|
velocity = vec_zero;
|
|
|
|
|
|
|
|
setSize( pm->mins, pm->maxs );
|
|
|
|
|
|
|
|
gunoffset = Vector( 0, 0, pm->viewheight );
|
|
|
|
viewheight = pm->viewheight;
|
|
|
|
waterlevel = pm->waterlevel;
|
|
|
|
watertype = pm->watertype;
|
|
|
|
onladder = pm->onladder;
|
|
|
|
if ( pm->groundentity )
|
|
|
|
{
|
|
|
|
groundentity = pm->groundentity;
|
|
|
|
groundsurface = pm->groundsurface;
|
|
|
|
groundplane = pm->groundplane;
|
|
|
|
groundcontents = pm->groundcontents;
|
|
|
|
groundentity_linkcount = pm->groundentity->linkcount;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
groundentity = NULL;
|
|
|
|
groundsurface = NULL;
|
|
|
|
groundcontents = 0;
|
|
|
|
}
|
|
|
|
if ( pm->groundsurface )
|
|
|
|
fallsurface = pm->groundsurface;
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_FROM_DLL void Player::SetMoveInfo
|
|
|
|
(
|
|
|
|
pmove_t *pm,
|
|
|
|
usercmd_t *ucmd
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
pm_passent = this;
|
|
|
|
|
|
|
|
// set up for pmove
|
|
|
|
memset( pm, 0, sizeof( pmove_t ) );
|
|
|
|
|
|
|
|
pm->s = client->ps.pmove;
|
|
|
|
|
|
|
|
pm->s.origin[ 0 ] = worldorigin.x * 8;
|
|
|
|
pm->s.origin[ 1 ] = worldorigin.y * 8;
|
|
|
|
pm->s.origin[ 2 ] = worldorigin.z * 8;
|
|
|
|
|
|
|
|
pm->s.velocity[ 0 ] = velocity.x * 8;
|
|
|
|
pm->s.velocity[ 1 ] = velocity.y * 8;
|
|
|
|
pm->s.velocity[ 2 ] = velocity.z * 8;
|
|
|
|
|
|
|
|
if ( !vehicle && memcmp( &old_pmove, &pm->s, sizeof( pm->s ) ) )
|
|
|
|
{
|
|
|
|
pm->snapinitial = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
pm->cmd = *ucmd;
|
|
|
|
|
|
|
|
pm->trace = PM_trace; // adds default parms
|
|
|
|
pm->pointcontents = gi.pointcontents;
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_FROM_DLL pmtype_t Player::GetMovePlayerMoveType
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
if ( level.playerfrozen || sentientFrozen )
|
|
|
|
{
|
|
|
|
return PM_FREEZE;
|
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
else if ( ( viewmode == CAMERA_VIEW ) || ( viewmode == SPECTATOR ) )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
|
|
|
return PM_LOCKVIEW;
|
|
|
|
}
|
|
|
|
else if ( vehicle )
|
|
|
|
{
|
|
|
|
if ( zoom_mode == ZOOMED_IN )
|
|
|
|
{
|
|
|
|
return PM_INVEHICLE_ZOOM;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return PM_INVEHICLE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( ( getMoveType() == MOVETYPE_NOCLIP ) || ( spectator ) )
|
|
|
|
{
|
|
|
|
return PM_SPECTATOR;
|
|
|
|
}
|
|
|
|
else if ( deadflag )
|
|
|
|
{
|
|
|
|
return PM_DEAD;
|
|
|
|
}
|
|
|
|
else if ( zoom_mode == ZOOMED_IN )
|
|
|
|
{
|
|
|
|
return PM_ZOOM;
|
|
|
|
}
|
|
|
|
else if ( ( viewmode == THIRD_PERSON ) && ( !gravaxis ) )
|
|
|
|
{
|
|
|
|
return PM_LOCKVIEW;
|
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
else if ( grapple_pull )
|
|
|
|
{
|
|
|
|
return PM_GRAPPLE_PULL;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
return PM_NORMAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_FROM_DLL void Player::ClientMove
|
|
|
|
(
|
|
|
|
usercmd_t *ucmd
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
pmove_t pm;
|
|
|
|
|
|
|
|
client->ps.pmove.pm_type = GetMovePlayerMoveType();
|
|
|
|
if (
|
|
|
|
( client->ps.pmove.pm_type == PM_LOCKVIEW ) ||
|
|
|
|
( client->ps.pmove.pm_type == PM_INVEHICLE ) ||
|
|
|
|
( client->ps.pmove.pm_type == PM_INVEHICLE_ZOOM ) ||
|
|
|
|
( client->ps.pmove.pm_type == PM_FREEZE ) ||
|
1999-11-02 00:00:00 +00:00
|
|
|
( client->ps.pmove.pm_type == PM_DEAD ) ||
|
|
|
|
( client->ps.pmove.pm_type == PM_GRAPPLE_PULL )
|
1998-12-20 00:00:00 +00:00
|
|
|
)
|
|
|
|
client->ps.pmove.pm_flags |= PMF_NO_PREDICTION;
|
|
|
|
else
|
|
|
|
client->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION;
|
|
|
|
|
|
|
|
if ( flags & FL_MUTANT )
|
|
|
|
client->ps.pmove.pm_flags |= PMF_MUTANT;
|
|
|
|
else
|
|
|
|
client->ps.pmove.pm_flags &= ~PMF_MUTANT;
|
|
|
|
|
|
|
|
if ( flags & FL_ADRENALINE )
|
|
|
|
client->ps.pmove.pm_flags |= PMF_ADRENALINE;
|
|
|
|
else
|
|
|
|
client->ps.pmove.pm_flags &= ~PMF_ADRENALINE;
|
|
|
|
|
|
|
|
if ( level.airclamp )
|
|
|
|
client->ps.pmove.pm_flags &= ~PMF_NOAIRCLAMP;
|
|
|
|
else
|
|
|
|
client->ps.pmove.pm_flags |= PMF_NOAIRCLAMP;
|
|
|
|
|
|
|
|
edict->s.effects &= ~EF_NOFOOTSTEPS;
|
|
|
|
if ( !sv_footsteps->value )
|
|
|
|
{
|
|
|
|
edict->s.effects |= EF_NOFOOTSTEPS;
|
|
|
|
}
|
|
|
|
|
|
|
|
client->ps.pmove.gravity = sv_gravity->value * gravity;
|
|
|
|
SetMoveInfo( &pm, ucmd );
|
|
|
|
|
|
|
|
// perform a pmove
|
|
|
|
gi.Pmove( &pm );
|
|
|
|
|
|
|
|
if ( !deadflag && !level.playerfrozen )
|
|
|
|
{
|
|
|
|
if ( waterlevel == 3 && falling)
|
|
|
|
{
|
|
|
|
Event * ev;
|
|
|
|
|
|
|
|
ev = new Event( EV_Sentient_AnimLoop );
|
|
|
|
ProcessEvent( ev );
|
|
|
|
falling = false;
|
|
|
|
}
|
|
|
|
if ( groundentity && !pm.groundentity && ( pm.cmd.upmove >= 10 ) && ( waterlevel <= 1 ) )
|
|
|
|
{
|
|
|
|
TempAnim( "jump", NULL );
|
|
|
|
falling = true;
|
|
|
|
}
|
|
|
|
if ( !groundentity && pm.groundentity && ( ( pm.s.velocity[ 2 ] < -1600 ) || falling ) )
|
|
|
|
{
|
|
|
|
falling = false;
|
|
|
|
if ( waterlevel <= 2 )
|
|
|
|
{
|
|
|
|
TempAnim( "land", NULL );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( ( !onladder ) && !pm.groundentity && ( velocity[ 2 ] < -200 ) && ( pm.s.velocity[ 2 ] > -2000 ) )
|
|
|
|
{
|
|
|
|
if ( !waterlevel )
|
|
|
|
{
|
|
|
|
TempAnim( "fall", NULL );
|
|
|
|
falling = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// save results of pmove
|
|
|
|
GetMoveInfo( &pm );
|
|
|
|
|
|
|
|
TouchStuff( &pm );
|
|
|
|
if ( !level.playerfrozen )
|
|
|
|
CheckButtons();
|
|
|
|
if ( whereami->value )
|
|
|
|
{
|
|
|
|
static Vector last;
|
|
|
|
if ( worldorigin != last )
|
|
|
|
{
|
|
|
|
last = worldorigin;
|
|
|
|
gi.dprintf("x %8.2f y%8.2f z %8.2f area %2d\n", worldorigin[0], worldorigin[1], worldorigin[2], edict->areanum );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
ClientThink
|
|
|
|
|
|
|
|
This will be called once for each client frame, which will
|
|
|
|
usually be a couple times for each server frame.
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
EXPORT_FROM_DLL void Player::ClientThink
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
if ( !has_thought )
|
|
|
|
{
|
|
|
|
// let any threads waiting on us know they can go ahead
|
|
|
|
Director.PlayerSpawned();
|
|
|
|
has_thought = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
new_buttons = current_ucmd->buttons & ~buttons;
|
|
|
|
buttons = current_ucmd->buttons;
|
|
|
|
|
|
|
|
// set the current gravity axis
|
|
|
|
client->ps.pmove.gravity_axis = gravaxis;
|
|
|
|
|
|
|
|
// save light level the player is standing on for
|
|
|
|
// monster sighting AI
|
|
|
|
light_level = current_ucmd->lightlevel;
|
|
|
|
|
|
|
|
if ( level.intermissiontime )
|
|
|
|
{
|
|
|
|
client->ps.pmove.pm_type = PM_FREEZE;
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// can exit intermission after 12 seconds
|
|
|
|
if ( level.time > level.intermissiontime + 12.0 && ( new_buttons & BUTTON_ANY ) )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
|
|
|
level.exitintermission = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save cmd angles so that we can get delta angle movements next frame
|
|
|
|
client->resp.cmd_angles[ 0 ] = SHORT2ANGLE( current_ucmd->angles[ 0 ] );
|
|
|
|
client->resp.cmd_angles[ 1 ] = SHORT2ANGLE( current_ucmd->angles[ 1 ] );
|
|
|
|
client->resp.cmd_angles[ 2 ] = SHORT2ANGLE( current_ucmd->angles[ 2 ] );
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ( current_ucmd->debris )
|
|
|
|
{
|
|
|
|
float mult;
|
|
|
|
mult = SURFACE_DamageMultiplier( current_ucmd->debris << SURF_START_BIT );
|
|
|
|
mult *= 2;
|
|
|
|
if ( mult > 0 )
|
|
|
|
{
|
|
|
|
Damage( world, world, ( int )mult, worldorigin, vec_zero, vec_zero, 0, 0, MOD_DEBRIS, -1, -1, 1.0f );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (
|
|
|
|
( client->ps.pmove.pm_flags & PMF_TIME_TELEPORT ) &&
|
|
|
|
( savedfov ) &&
|
|
|
|
( client->ps.pmove.pm_time < 95 )
|
|
|
|
)
|
|
|
|
{
|
|
|
|
Event * ev;
|
|
|
|
|
|
|
|
ev = new Event( EV_Player_RestoreFov );
|
|
|
|
ProcessEvent( ev );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !vehicle || !vehicle->Drive( current_ucmd ) )
|
|
|
|
{
|
|
|
|
short temporigin[ 3 ];
|
|
|
|
|
|
|
|
if ( watchCamera != this )
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// we save off the origin so that camera's origins are not messed up
|
|
|
|
//
|
|
|
|
temporigin[ 0 ] = client->ps.pmove.origin[ 0 ];
|
|
|
|
temporigin[ 1 ] = client->ps.pmove.origin[ 1 ];
|
|
|
|
temporigin[ 2 ] = client->ps.pmove.origin[ 2 ];
|
|
|
|
|
|
|
|
ClientMove( current_ucmd );
|
|
|
|
|
|
|
|
client->ps.pmove.origin[ 0 ] = temporigin[ 0 ];
|
|
|
|
client->ps.pmove.origin[ 1 ] = temporigin[ 1 ];
|
|
|
|
client->ps.pmove.origin[ 2 ] = temporigin[ 2 ];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ClientMove( current_ucmd );
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CheckWater();
|
|
|
|
if ( !level.playerfrozen )
|
|
|
|
CheckButtons();
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we're dying, check for respawn
|
|
|
|
|
|
|
|
assert( !( deadflag && deadflag != DEAD_DEAD && !animating ) );
|
|
|
|
|
|
|
|
if ( ( deadflag == DEAD_DEAD && ( level.time > respawn_time ) ) ||
|
|
|
|
( deadflag && !animating ) )
|
|
|
|
{
|
|
|
|
if ( ( deathmatch->value ) && ( !checked_dead_camera ) && ( level.time > ( respawn_time + 10 ) ) )
|
|
|
|
{
|
|
|
|
int num;
|
|
|
|
|
|
|
|
checked_dead_camera = true;
|
|
|
|
// Find the end node
|
|
|
|
num = G_FindTarget( 0, "endnode1" );
|
|
|
|
|
|
|
|
if ( num && thirdpersonCamera )
|
|
|
|
{
|
|
|
|
Entity * path;
|
|
|
|
Event * event;
|
|
|
|
|
|
|
|
event = new Event( EV_Camera_NormalAngles );
|
|
|
|
thirdpersonCamera->ProcessEvent( event );
|
|
|
|
event = new Event( EV_Camera_Orbit);
|
|
|
|
path = G_GetEntity( num );
|
|
|
|
event->AddEntity( path );
|
|
|
|
thirdpersonCamera->ProcessEvent( event );
|
|
|
|
event = new Event( EV_Camera_JumpCut );
|
|
|
|
thirdpersonCamera->ProcessEvent( event );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// wait for any button just going down
|
|
|
|
if ( new_buttons || ( DM_FLAG( DF_FORCE_RESPAWN ) ) )
|
|
|
|
{
|
|
|
|
ProcessEvent( EV_Player_Respawn );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// check to see if we want to get out of a cinematic or camera
|
|
|
|
//
|
|
|
|
if (
|
|
|
|
( viewmode == CAMERA_VIEW ) &&
|
|
|
|
(
|
|
|
|
( buttons & BUTTON_ATTACK ) ||
|
|
|
|
( buttons & BUTTON_USE ) ||
|
|
|
|
( abs( current_ucmd->forwardmove ) >= 200 ) ||
|
|
|
|
( abs( current_ucmd->sidemove ) >= 200 ) ||
|
|
|
|
( current_ucmd->upmove > 0 )
|
|
|
|
)
|
|
|
|
)
|
|
|
|
{
|
|
|
|
if ( level.cinematic )
|
|
|
|
{
|
|
|
|
if (
|
|
|
|
( buttons & BUTTON_ATTACK ) ||
|
|
|
|
( buttons & BUTTON_USE ) ||
|
|
|
|
( current_ucmd->upmove > 0 )
|
|
|
|
)
|
|
|
|
{
|
|
|
|
if ( world->skipthread.length() > 1 )
|
|
|
|
{
|
|
|
|
ExecuteThread( world->skipthread );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( !( buttons & BUTTON_USE ) &&
|
|
|
|
!( buttons & BUTTON_ATTACK ) &&
|
|
|
|
!( trappedInQuantum ) &&
|
|
|
|
!( in_console )
|
|
|
|
)
|
|
|
|
{
|
|
|
|
SetCamera( NULL );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save cmd angles so that we can get delta angle movements next frame
|
|
|
|
client->resp.cmd_angles[ 0 ] = SHORT2ANGLE( current_ucmd->angles[ 0 ] );
|
|
|
|
client->resp.cmd_angles[ 1 ] = SHORT2ANGLE( current_ucmd->angles[ 1 ] );
|
|
|
|
client->resp.cmd_angles[ 2 ] = SHORT2ANGLE( current_ucmd->angles[ 2 ] );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::EventUseItem
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
const char *name;
|
|
|
|
|
|
|
|
name = ev->GetString( 1 );
|
|
|
|
assert( name );
|
|
|
|
|
|
|
|
if ( deadflag )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( flags & ( FL_MUTANT|FL_SP_MUTANT ) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( currentWeapon && !currentWeapon->ChangingWeapons() )
|
|
|
|
{
|
|
|
|
if ( !Q_stricmp( name, currentWeapon->getClassname() ) )
|
|
|
|
{
|
|
|
|
Event *event;
|
|
|
|
event = new Event(EV_Weapon_SecondaryUse);
|
|
|
|
event->AddEntity(this);
|
|
|
|
currentWeapon->ProcessEvent(event);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ProcessEvent( EV_Player_ZoomOut );
|
|
|
|
|
|
|
|
if ( checkInheritance( &Weapon::ClassInfo, name ) )
|
|
|
|
useWeapon( name );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::EventUseInventoryItem
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
if ( deadflag )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( !currentItem )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( flags & ( FL_MUTANT|FL_SP_MUTANT ) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
currentItem->ProcessEvent(EV_InventoryItem_Use);
|
|
|
|
}
|
|
|
|
|
|
|
|
Weapon *Player::useWeapon
|
|
|
|
(
|
|
|
|
const char *weaponname
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
if ( vehicle && vehicle->HasWeapon() )
|
|
|
|
return NULL;
|
|
|
|
else
|
|
|
|
return Sentient::useWeapon( weaponname );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::Take
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
const char *name;
|
|
|
|
|
|
|
|
name = ev->GetString( 1 );
|
|
|
|
|
|
|
|
assert( name );
|
|
|
|
|
|
|
|
if ( deadflag )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !stricmp( name, "all" ) )
|
|
|
|
{
|
|
|
|
if ( currentWeapon )
|
|
|
|
currentWeapon->DetachFromOwner();
|
|
|
|
|
|
|
|
SetCurrentWeapon( NULL );
|
|
|
|
FreeInventoryOfType("Weapon");
|
|
|
|
giveWeapon( "Fists" );
|
|
|
|
giveWeapon( "SpiderMine" );
|
|
|
|
}
|
|
|
|
else if ( checkInheritance( &Weapon::ClassInfo, name ) )
|
|
|
|
{
|
|
|
|
takeWeapon( name );
|
|
|
|
}
|
|
|
|
else if ( checkInheritance( &Ammo::ClassInfo, name ) )
|
|
|
|
{
|
|
|
|
EventTakeAmmo( ev );
|
|
|
|
}
|
|
|
|
else if ( checkInheritance( &Item::ClassInfo, name ) )
|
|
|
|
{
|
|
|
|
EventTakeItem( ev );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gi.cprintf( edict, PRINT_HIGH, "Unknown take object : %s\n", name );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::GiveCheat
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
const char *name;
|
|
|
|
|
|
|
|
name = ev->GetString( 1 );
|
|
|
|
|
|
|
|
assert( name );
|
|
|
|
|
|
|
|
if ( deadflag )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( checkInheritance( &Weapon::ClassInfo, name ) )
|
|
|
|
{
|
|
|
|
giveWeapon( name );
|
|
|
|
}
|
|
|
|
else if ( checkInheritance( &Ammo::ClassInfo, name ) )
|
|
|
|
{
|
|
|
|
EventGiveAmmo( ev );
|
|
|
|
}
|
|
|
|
else if ( checkInheritance( &InventoryItem::ClassInfo, name ) )
|
|
|
|
{
|
|
|
|
if (ev->NumArgs() != 2)
|
|
|
|
{
|
|
|
|
gi.cprintf( edict, PRINT_HIGH, "Usage: give <inventory item name> <amount>\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
EventGiveInventoryItem( ev );
|
|
|
|
}
|
|
|
|
else if ( checkInheritance( &Item::ClassInfo, name ) )
|
|
|
|
{
|
|
|
|
EventGiveItem( ev );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::GiveAllCheat
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
if ( deadflag )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef SIN_DEMO
|
|
|
|
giveWeapon( "Fists" );
|
|
|
|
giveWeapon( "RocketLauncher" );
|
|
|
|
giveWeapon( "Magnum" );
|
|
|
|
giveWeapon( "SniperRifle" );
|
|
|
|
giveWeapon( "AssaultRifle" );
|
|
|
|
giveWeapon( "Shotgun" );
|
|
|
|
#else
|
|
|
|
giveWeapon( "Fists" );
|
|
|
|
giveWeapon( "RocketLauncher" );
|
|
|
|
giveWeapon( "Magnum" );
|
|
|
|
giveWeapon( "SniperRifle" );
|
|
|
|
giveWeapon( "AssaultRifle" );
|
|
|
|
giveWeapon( "ChainGun" );
|
|
|
|
giveWeapon( "PulseRifle" );
|
|
|
|
giveWeapon( "Shotgun" );
|
|
|
|
giveWeapon( "SpearGun" );
|
|
|
|
giveWeapon( "SpiderMine" );
|
|
|
|
giveWeapon( "MutantHands" );
|
|
|
|
giveWeapon( "QuantumDestabilizer" );
|
|
|
|
#endif
|
|
|
|
giveItem( "RiotHelmet", 100);
|
|
|
|
giveItem( "FlakJacket", 100);
|
|
|
|
giveItem( "FlakPants", 100);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::GodCheat
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
const char *msg;
|
|
|
|
|
|
|
|
if ( ev->NumArgs() > 0 )
|
|
|
|
{
|
|
|
|
if ( ev->GetInteger( 1 ) )
|
|
|
|
{
|
|
|
|
flags |= FL_GODMODE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
flags &= ~FL_GODMODE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
flags ^= FL_GODMODE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ev->GetSource() == EV_FROM_CONSOLE )
|
|
|
|
{
|
|
|
|
if ( !( flags & FL_GODMODE ) )
|
|
|
|
{
|
|
|
|
msg = "godmode OFF\n";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
msg = "godmode ON\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
gi.cprintf( edict, PRINT_HIGH, msg );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::Kill
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
if ( ( level.time - respawn_time ) < 5 )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
flags &= ~FL_GODMODE;
|
|
|
|
health = 0;
|
|
|
|
Damage( this, this, 10, worldorigin, vec_zero, vec_zero, 0, DAMAGE_NO_PROTECTION, MOD_SUICIDE, -1, -1, 1.0f );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::NoTargetCheat
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
const char *msg;
|
|
|
|
|
|
|
|
flags ^= FL_NOTARGET;
|
|
|
|
if ( !( flags & FL_NOTARGET ) )
|
|
|
|
{
|
|
|
|
msg = "notarget OFF\n";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
msg = "notarget ON\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
gi.cprintf( edict, PRINT_HIGH, msg );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::NoclipCheat
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
const char *msg;
|
|
|
|
|
|
|
|
if ( vehicle )
|
|
|
|
{
|
|
|
|
msg = "Must exit vehicle first\n";
|
|
|
|
}
|
|
|
|
else if ( getMoveType() == MOVETYPE_NOCLIP )
|
|
|
|
{
|
|
|
|
setMoveType( MOVETYPE_WALK );
|
|
|
|
msg = "noclip OFF\n";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
setMoveType( MOVETYPE_NOCLIP );
|
|
|
|
msg = "noclip ON\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
gi.cprintf( edict, PRINT_HIGH, msg );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::SpawnEntity
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
Entity *ent;
|
|
|
|
const char *name;
|
|
|
|
ClassDef *cls;
|
|
|
|
str text;
|
|
|
|
Vector forward;
|
|
|
|
Vector right;
|
|
|
|
Vector up;
|
|
|
|
Vector delta;
|
|
|
|
Vector v;
|
|
|
|
int n;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if ( ev->NumArgs() < 1 )
|
|
|
|
{
|
|
|
|
ev->Error( "Usage: spawn entityname [keyname] [value]..." );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
name = ev->GetString( 1 );
|
|
|
|
if ( !name || !name[ 0 ] )
|
|
|
|
{
|
|
|
|
ev->Error( "Must specify an entity name" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// create a new entity
|
|
|
|
G_InitSpawnArguments();
|
|
|
|
|
|
|
|
if ( name )
|
|
|
|
{
|
|
|
|
cls = getClassForID( name );
|
|
|
|
if ( !cls )
|
|
|
|
{
|
|
|
|
cls = getClass( name );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !cls )
|
|
|
|
{
|
|
|
|
str n;
|
|
|
|
|
|
|
|
n = name;
|
|
|
|
if ( !strstr( n.c_str(), ".def" ) )
|
|
|
|
{
|
|
|
|
n += ".def";
|
|
|
|
}
|
|
|
|
G_SetSpawnArg( "model", n.c_str() );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
G_SetSpawnArg( "classname", name );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
angles.AngleVectors( &forward, &right, &up );
|
|
|
|
v = worldorigin + ( forward + up ) * 80;
|
|
|
|
text = va( "%f %f %f", v[ 0 ], v[ 1 ], v[ 2 ] );
|
|
|
|
G_SetSpawnArg( "origin", text.c_str() );
|
|
|
|
|
|
|
|
delta = worldorigin - v;
|
|
|
|
v = delta.toAngles();
|
|
|
|
text = va( "%f", v[ 1 ] );
|
|
|
|
G_SetSpawnArg( "angle", text.c_str() );
|
|
|
|
|
|
|
|
if ( ev->NumArgs() > 2 )
|
|
|
|
{
|
|
|
|
n = ev->NumArgs();
|
|
|
|
for( i = 2; i <= n; i += 2 )
|
|
|
|
{
|
|
|
|
G_SetSpawnArg( ev->GetString( i ), ev->GetString( i + 1 ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cls = G_GetClassFromArgs();
|
|
|
|
if ( !cls )
|
|
|
|
{
|
|
|
|
ev->Error( "'%s' is not a valid entity name", name );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ent = ( Entity * )cls->newInstance();
|
|
|
|
|
|
|
|
G_InitSpawnArguments();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::SpawnActor
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
Entity *ent;
|
|
|
|
str name;
|
|
|
|
str text;
|
|
|
|
Vector forward;
|
|
|
|
Vector right;
|
|
|
|
Vector up;
|
|
|
|
Vector delta;
|
|
|
|
Vector v;
|
|
|
|
int n;
|
|
|
|
int i;
|
|
|
|
ClassDef *cls;
|
|
|
|
|
|
|
|
if ( ev->NumArgs() < 1 )
|
|
|
|
{
|
|
|
|
ev->Error( "Usage: actor [modelname] [keyname] [value]..." );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
name = ev->GetString( 1 );
|
|
|
|
if ( !name[ 0 ] )
|
|
|
|
{
|
|
|
|
ev->Error( "Must specify a model name" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !strstr( name.c_str(), ".def" ) )
|
|
|
|
{
|
|
|
|
name += ".def";
|
|
|
|
}
|
|
|
|
|
|
|
|
// create a new entity
|
|
|
|
G_InitSpawnArguments();
|
|
|
|
|
|
|
|
G_SetSpawnArg( "model", name.c_str() );
|
|
|
|
|
|
|
|
angles.AngleVectors( &forward, &right, &up );
|
|
|
|
v = worldorigin + ( forward + up ) * 80;
|
|
|
|
text = va( "%f %f %f", v[ 0 ], v[ 1 ], v[ 2 ] );
|
|
|
|
G_SetSpawnArg( "origin", text.c_str() );
|
|
|
|
|
|
|
|
delta = worldorigin - v;
|
|
|
|
v = delta.toAngles();
|
|
|
|
text = va( "%f", v[ 1 ] );
|
|
|
|
G_SetSpawnArg( "angle", text.c_str() );
|
|
|
|
|
|
|
|
if ( ev->NumArgs() > 2 )
|
|
|
|
{
|
|
|
|
n = ev->NumArgs();
|
|
|
|
for( i = 2; i <= n; i += 2 )
|
|
|
|
{
|
|
|
|
G_SetSpawnArg( ev->GetString( i ), ev->GetString( i + 1 ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cls = G_GetClassFromArgs();
|
|
|
|
if ( !cls )
|
|
|
|
{
|
|
|
|
G_SetSpawnArg( "model", name.c_str() );
|
|
|
|
ent = new Actor;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ent = ( Entity * )cls->newInstance();
|
|
|
|
}
|
|
|
|
|
|
|
|
G_InitSpawnArguments();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::EventPreviousWeapon
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
if ( deadflag )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( vehicle && vehicle->HasWeapon() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( flags & (FL_MUTANT|FL_SP_MUTANT) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Cycle backwards through weapons
|
|
|
|
if ( currentWeapon && currentWeapon->AttackDone() && !currentWeapon->ChangingWeapons() )
|
|
|
|
{
|
|
|
|
ProcessEvent( EV_Player_ZoomOut );
|
|
|
|
ChangeWeapon( PreviousWeapon( currentWeapon ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::EventNextWeapon
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
if ( deadflag )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( vehicle && vehicle->HasWeapon() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( flags & (FL_MUTANT|FL_SP_MUTANT) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Cycle forwards through weapons
|
|
|
|
if ( currentWeapon && currentWeapon->AttackDone() && !currentWeapon->ChangingWeapons() )
|
|
|
|
{
|
|
|
|
ProcessEvent( EV_Player_ZoomOut );
|
|
|
|
ChangeWeapon( NextWeapon( currentWeapon ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::EventNextItem
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
Item *nextItem;
|
|
|
|
|
|
|
|
if ( deadflag )
|
|
|
|
return;
|
|
|
|
|
|
|
|
nextItem = NextItem( currentItem );
|
|
|
|
|
|
|
|
if (nextItem)
|
|
|
|
currentItem = (InventoryItem *)nextItem;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::EventPreviousItem
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
Item *prevItem;
|
|
|
|
|
|
|
|
if ( deadflag )
|
|
|
|
return;
|
|
|
|
|
|
|
|
prevItem = PrevItem( currentItem );
|
|
|
|
|
|
|
|
if (prevItem)
|
|
|
|
currentItem = (InventoryItem *)prevItem;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::GameVersion
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
gi.cprintf( edict, PRINT_HIGH, "%s : %s\n", GAMEVERSION, __DATE__ );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::Fov
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
if ( ev->NumArgs() < 1 )
|
|
|
|
{
|
|
|
|
gi.cprintf( edict, PRINT_HIGH, "Fov = %d\n", fov );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
fov = ev->GetFloat( 1 );
|
|
|
|
|
|
|
|
if ( ( fov < 90 ) && DM_FLAG( DF_FIXED_FOV ) )
|
|
|
|
{
|
|
|
|
fov = 90;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( fov < 1 )
|
|
|
|
fov = 90;
|
|
|
|
else if ( fov > 160 )
|
|
|
|
fov = 160;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Player::SaveFov
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
savedfov = fov;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::RestoreFov
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
if ( savedfov )
|
|
|
|
fov = savedfov;
|
|
|
|
savedfov = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::ToggleViewMode
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
if ( viewmode == CAMERA_VIEW || ( vehicle && !vehicle->IsDrivable() ) )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// Spectators switch between a camera view and noclip
|
1998-12-20 00:00:00 +00:00
|
|
|
if ( spectator )
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
spectator_distance = 128;
|
|
|
|
if ( defaultViewMode == FIRST_PERSON )
|
|
|
|
{
|
|
|
|
defaultViewMode = SPECTATOR;
|
|
|
|
SetViewMode( SPECTATOR );
|
|
|
|
CTF_UpdateNumberOfPlayers();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
defaultViewMode = FIRST_PERSON;
|
|
|
|
SetViewMode( FIRST_PERSON );
|
|
|
|
CTF_UpdateNumberOfPlayers();
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( defaultViewMode == FIRST_PERSON )
|
|
|
|
{
|
|
|
|
defaultViewMode = THIRD_PERSON;
|
|
|
|
SetViewMode( THIRD_PERSON );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
defaultViewMode = FIRST_PERSON;
|
|
|
|
SetViewMode( FIRST_PERSON );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
=========================================================================
|
|
|
|
Player::ToggleZoomMode - Plays a zoom sound, sets the layout to display a
|
|
|
|
crosshair and calls the FOV event for the player.
|
|
|
|
=========================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
void Player::ToggleZoomMode
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
if ( zoom_mode == ZOOMED_IN )
|
|
|
|
{
|
|
|
|
zoom_mode = ZOOMED_OUT;
|
|
|
|
|
|
|
|
fov = atof( Info_ValueForKey( client->pers.userinfo, "fov" ) );
|
|
|
|
if ( fov < 1 )
|
|
|
|
{
|
|
|
|
fov = 90;
|
|
|
|
}
|
|
|
|
else if ( fov > 160 )
|
|
|
|
{
|
|
|
|
fov = 160;
|
|
|
|
}
|
|
|
|
|
|
|
|
RandomGlobalSound( "scope_zoomout", 1, CHAN_VOICE, ATTN_NORM );
|
|
|
|
ProcessEvent( EV_MovementSound );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RandomGlobalSound( "scope_zoomin", 1, CHAN_VOICE, ATTN_NORM );
|
|
|
|
ProcessEvent( EV_MovementSound );
|
|
|
|
zoom_mode = ZOOMED_IN;
|
|
|
|
fov = 20;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::ZoomOut
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
if ( zoom_mode == ZOOMED_IN )
|
|
|
|
{
|
|
|
|
zoom_mode = ZOOMED_OUT;
|
|
|
|
fov = atof( Info_ValueForKey( client->pers.userinfo, "fov" ) );
|
|
|
|
if ( fov < 1 )
|
|
|
|
{
|
|
|
|
fov = 90;
|
|
|
|
}
|
|
|
|
else if ( fov > 160 )
|
|
|
|
{
|
|
|
|
fov = 160;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::EnterConsole
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
{
|
|
|
|
velocity = vec_zero;
|
|
|
|
|
|
|
|
in_console = true;
|
|
|
|
con_name = ev->GetString(1);
|
|
|
|
|
|
|
|
// Create a console variable with the entnum of this player
|
|
|
|
// who used it.
|
|
|
|
|
|
|
|
Director.CreateConsoleUser(con_name.c_str(), entnum);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::ExitConsole
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
{
|
|
|
|
ProcessEvent(EV_KickFromConsole);
|
|
|
|
in_console = false;
|
|
|
|
con_name = "";
|
|
|
|
SetCamera( NULL );
|
|
|
|
|
|
|
|
showModel();
|
|
|
|
hidestats = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::KickConsole
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
{
|
|
|
|
char msg[ MAX_MSGLEN ];
|
|
|
|
|
|
|
|
in_console = false;
|
|
|
|
|
|
|
|
// Send a message to the client to kick us out of this console.
|
|
|
|
if ( !consoleManager.ConsoleExists( con_name.c_str() ) )
|
|
|
|
{
|
|
|
|
Event event = new Event( ev );
|
|
|
|
PostEvent(event,1.0f);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf( msg, "pku %s", con_name.c_str() );
|
|
|
|
gi.WriteByte (svc_console_command);
|
|
|
|
gi.WriteString (msg);
|
|
|
|
gi.unicast (edict, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
===============
|
|
|
|
CalcRoll
|
|
|
|
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
float Player::CalcRoll
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
float sign;
|
|
|
|
float side;
|
|
|
|
float value;
|
|
|
|
Vector r;
|
|
|
|
|
|
|
|
angles.AngleVectors( NULL, &r, NULL );
|
|
|
|
side = velocity * r;
|
|
|
|
sign = side < 0 ? -4 : 4;
|
|
|
|
side = fabs( side );
|
|
|
|
|
|
|
|
value = sv_rollangle->value;
|
|
|
|
|
|
|
|
if ( side < sv_rollspeed->value )
|
|
|
|
{
|
|
|
|
side = side * value / sv_rollspeed->value;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
side = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
return side * sign;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
===============
|
|
|
|
CalcViewOffset
|
|
|
|
|
|
|
|
Auto pitching on slopes?
|
|
|
|
|
|
|
|
fall from 128: 400 = 160000
|
|
|
|
fall from 256: 580 = 336400
|
|
|
|
fall from 384: 720 = 518400
|
|
|
|
fall from 512: 800 = 640000
|
|
|
|
fall from 640: 960 =
|
|
|
|
|
|
|
|
damage = deltavelocity*deltavelocity * 0.0001
|
|
|
|
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
|
|
|
|
void Player::CalcViewOffset
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
float bob;
|
|
|
|
float ratio;
|
|
|
|
float pitch;
|
|
|
|
float roll;
|
|
|
|
float delta;
|
|
|
|
Vector forward;
|
|
|
|
Vector right;
|
|
|
|
Vector ang;
|
|
|
|
|
|
|
|
// Initialize kick for this frame
|
|
|
|
v_kick = vec_zero;
|
|
|
|
|
|
|
|
// don't add any kick when dead
|
|
|
|
if ( !deadflag )
|
|
|
|
{
|
|
|
|
// add angles based on weapon kick
|
|
|
|
v_kick = kick_angles;
|
|
|
|
|
|
|
|
// add angles based on damage kick
|
|
|
|
ratio = ( v_dmg_time - level.time ) / DAMAGE_TIME;
|
|
|
|
if ( ratio < 0 )
|
|
|
|
{
|
|
|
|
ratio = 0;
|
|
|
|
v_dmg_pitch = 0;
|
|
|
|
v_dmg_roll = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
pitch = v_kick.pitch() + ratio * v_dmg_pitch;
|
|
|
|
roll = v_kick.roll() + ratio * v_dmg_roll;
|
|
|
|
|
|
|
|
// add pitch based on fall kick
|
|
|
|
|
|
|
|
ratio = ( fall_time - level.time ) / FALL_TIME;
|
|
|
|
if ( ratio < 0 )
|
|
|
|
{
|
|
|
|
ratio = 0;
|
|
|
|
}
|
|
|
|
pitch += ratio * fall_value;
|
|
|
|
|
|
|
|
// calculate forward and right based upon yaw
|
|
|
|
ang[ 1 ] = v_angle[ 1 ];
|
|
|
|
ang.AngleVectors( &forward, &right, NULL );
|
|
|
|
|
|
|
|
//FIXME: need to handle alternate gravity axis
|
|
|
|
// add pitch based on forward velocity
|
|
|
|
delta = velocity * forward;
|
|
|
|
pitch += delta * run_pitch->value;
|
|
|
|
|
|
|
|
// add roll based on side velocity
|
|
|
|
delta = -( velocity * right );
|
|
|
|
roll += delta * run_pitch->value;
|
|
|
|
|
|
|
|
// add angles based on bob
|
|
|
|
delta = bobfracsin * bob_pitch->value * xyspeed;
|
|
|
|
if ( ( waterlevel <= 1 ) && ( client->ps.pmove.pm_flags & PMF_DUCKED ) )
|
|
|
|
{
|
|
|
|
delta *= 6; // crouching
|
|
|
|
}
|
|
|
|
pitch += delta;
|
|
|
|
delta = bobfracsin * bob_roll->value * xyspeed;
|
|
|
|
if ( ( waterlevel <= 1 ) && ( client->ps.pmove.pm_flags & PMF_DUCKED ) )
|
|
|
|
{
|
|
|
|
delta *= 6; // crouching
|
|
|
|
}
|
|
|
|
if ( bobcycle & 1 )
|
|
|
|
{
|
|
|
|
delta = -delta;
|
|
|
|
}
|
|
|
|
roll += delta;
|
|
|
|
|
|
|
|
v_kick.setPitch( pitch );
|
|
|
|
v_kick.setRoll( roll );
|
|
|
|
}
|
|
|
|
|
|
|
|
// add fall height
|
|
|
|
ratio = ( fall_time - level.time ) / FALL_TIME;
|
|
|
|
if ( ratio < 0 )
|
|
|
|
{
|
|
|
|
ratio = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
v_offset = Vector( 0, 0, viewheight - ratio * fall_value * 0.4 );
|
|
|
|
|
|
|
|
// add bob height
|
|
|
|
bob = bobfracsin * xyspeed * bob_up->value;
|
|
|
|
if ( bob > 6 )
|
|
|
|
{
|
|
|
|
bob = 6;
|
|
|
|
}
|
|
|
|
|
|
|
|
//gi.DebugGraph (bob *2, 255);
|
|
|
|
v_offset.z += bob;
|
|
|
|
|
|
|
|
// add kick offset
|
|
|
|
v_offset += kick_origin;
|
|
|
|
|
|
|
|
// absolutely bound offsets
|
|
|
|
// so the view can never be outside the player box
|
|
|
|
if ( v_offset[ 0 ] < -14 )
|
|
|
|
{
|
|
|
|
v_offset[ 0 ] = -14;
|
|
|
|
}
|
|
|
|
else if ( v_offset[ 0 ] > 14 )
|
|
|
|
{
|
|
|
|
v_offset[ 0 ] = 14;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( v_offset[ 1 ] < -14 )
|
|
|
|
{
|
|
|
|
v_offset[ 1 ] = -14;
|
|
|
|
}
|
|
|
|
else if ( v_offset[ 1 ] > 14 )
|
|
|
|
{
|
|
|
|
v_offset[ 1 ] = 14;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( v_offset[ 2 ] < 0 )
|
|
|
|
{
|
|
|
|
v_offset[ 2 ] = 0;
|
|
|
|
}
|
|
|
|
else if ( v_offset[ 2 ] > STAND_HEIGHT - 2 )
|
|
|
|
{
|
|
|
|
v_offset[ 2 ] = STAND_HEIGHT - 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
// clear weapon kicks
|
|
|
|
kick_origin = vec_zero;
|
|
|
|
kick_angles = vec_zero;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
CalcGunOffset
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void Player::CalcGunOffset
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
float delta;
|
|
|
|
|
|
|
|
// gun angles from bobbing
|
|
|
|
v_gunangles[ ROLL ] = xyspeed * bobfracsin * 0.005;
|
|
|
|
v_gunangles[ YAW ] = xyspeed * bobfracsin * 0.01;
|
|
|
|
if ( bobcycle & 1 )
|
|
|
|
{
|
|
|
|
v_gunangles[ ROLL ] = -v_gunangles[ ROLL ];
|
|
|
|
v_gunangles[ YAW ] = -v_gunangles[ YAW ];
|
|
|
|
}
|
|
|
|
|
|
|
|
v_gunangles[ PITCH ] = xyspeed * bobfracsin * 0.005;
|
|
|
|
|
|
|
|
// gun angles from delta movement
|
|
|
|
for( i = 0; i < 3; i++ )
|
|
|
|
{
|
|
|
|
delta = oldviewangles[ i ] - v_angle[ i ];
|
|
|
|
if ( delta > 180 )
|
|
|
|
{
|
|
|
|
delta -= 360;
|
|
|
|
}
|
|
|
|
if ( delta < -180 )
|
|
|
|
{
|
|
|
|
delta += 360;
|
|
|
|
}
|
|
|
|
if ( delta > 45 )
|
|
|
|
{
|
|
|
|
delta = 45;
|
|
|
|
}
|
|
|
|
if ( delta < -45 )
|
|
|
|
{
|
|
|
|
delta = -45;
|
|
|
|
}
|
|
|
|
if ( i == YAW )
|
|
|
|
{
|
|
|
|
v_gunangles[ ROLL ] += 0.1 * delta;
|
|
|
|
}
|
|
|
|
v_gunangles[ i ] += 0.2 * delta;
|
|
|
|
}
|
|
|
|
|
|
|
|
oldviewangles = v_angle;
|
|
|
|
|
|
|
|
// gun height
|
|
|
|
VectorClear( v_gunoffset );
|
|
|
|
|
|
|
|
// gun_x / gun_y / gun_z are development tools
|
|
|
|
for( i = 0; i < 3; i++ )
|
|
|
|
{
|
|
|
|
v_gunoffset[ i ] += orientation[ 0 ][ i ] * gun_y->value;
|
|
|
|
v_gunoffset[ i ] += orientation[ 1 ][ i ] * gun_x->value;
|
|
|
|
v_gunoffset[ i ] += orientation[ 2 ][ i ] * -gun_z->value;
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// put gun offset and angles into client playerstate
|
|
|
|
//
|
|
|
|
client->ps.gunoffset[ 0 ] = v_gunoffset[0];
|
|
|
|
client->ps.gunoffset[ 1 ] = v_gunoffset[1];
|
|
|
|
client->ps.gunoffset[ 2 ] = v_gunoffset[2];
|
|
|
|
|
|
|
|
client->ps.gunangles[ 0 ] = v_gunangles[0];
|
|
|
|
client->ps.gunangles[ 1 ] = v_gunangles[1];
|
|
|
|
client->ps.gunangles[ 2 ] = v_gunangles[2];
|
|
|
|
|
|
|
|
if ( currentWeapon )
|
|
|
|
{
|
|
|
|
currentWeapon->SetGravityAxis( gravaxis );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::GravityNodes
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
Vector grav,gravnorm,velnorm;
|
|
|
|
float dot;
|
|
|
|
qboolean force;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Check for gravity pulling points
|
|
|
|
//
|
|
|
|
|
|
|
|
// no pull on ladders or during waterjumps
|
|
|
|
if ( onladder || ( client->ps.pmove.pm_flags & PMF_TIME_WATERJUMP ) )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
grav = gravPathManager.CalculateGravityPull( *this, worldorigin, &force );
|
|
|
|
|
|
|
|
// Check for unfightable gravity.
|
|
|
|
if ( force && grav != vec_zero )
|
|
|
|
{
|
|
|
|
velnorm = velocity;
|
|
|
|
velnorm.normalize();
|
|
|
|
|
|
|
|
gravnorm = grav;
|
|
|
|
gravnorm.normalize();
|
|
|
|
|
|
|
|
dot = gravnorm.x * velnorm.x + gravnorm.y * velnorm.y + gravnorm.z * velnorm.z;
|
|
|
|
|
|
|
|
// This prevents the player from trying to swim upstream
|
|
|
|
if ( dot < 0 )
|
|
|
|
{
|
|
|
|
float tempdot;
|
|
|
|
Vector tempvec;
|
|
|
|
|
|
|
|
tempdot = 0.2f - dot;
|
|
|
|
tempvec = velocity * tempdot;
|
|
|
|
velocity = velocity - tempvec;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
OutputDebugString(va("DOT : %f\n", dot));
|
|
|
|
OutputDebugString(va("GRAV: %f %f %f\n", grav.x, grav.y, grav.z));
|
|
|
|
OutputDebugString(va("VELN: %f %f %f\n", velnorm.x,velnorm.y,velnorm.z));
|
|
|
|
OutputDebugString(va("GRVN: %f %f %f\n", gravnorm.x,gravnorm.y,gravnorm.z));
|
|
|
|
#endif
|
|
|
|
velocity = velocity + grav;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=============
|
|
|
|
CheckWater
|
|
|
|
=============
|
|
|
|
*/
|
|
|
|
void Player::CheckWater
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
Vector point;
|
|
|
|
int cont;
|
|
|
|
int sample1;
|
|
|
|
int sample2;
|
|
|
|
const gravityaxis_t &grav = gravity_axis[ gravaxis ];
|
|
|
|
|
|
|
|
unlink();
|
|
|
|
if ( vehicle )
|
|
|
|
{
|
|
|
|
vehicle->unlink();
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// get waterlevel, accounting for ducking
|
|
|
|
//
|
|
|
|
waterlevel = 0;
|
|
|
|
watertype = 0;
|
|
|
|
|
|
|
|
sample2 = viewheight - mins[ grav.z ];
|
|
|
|
sample1 = sample2 / 2;
|
|
|
|
|
|
|
|
point[ grav.x ] = worldorigin[ grav.x ];
|
|
|
|
point[ grav.y ] = worldorigin[ grav.y ];
|
|
|
|
point[ grav.z ] = worldorigin[ grav.z ] + mins[ grav.z ] + grav.sign;
|
|
|
|
cont = gi.pointcontents( point.vec3() );
|
|
|
|
|
|
|
|
if ( cont & MASK_WATER )
|
|
|
|
{
|
|
|
|
watertype = cont;
|
|
|
|
waterlevel = 1;
|
|
|
|
point[ grav.z ] = worldorigin[ grav.z ] + mins[ grav.z ] + sample1;
|
|
|
|
cont = gi.pointcontents( point.vec3() );
|
|
|
|
if ( cont & MASK_WATER )
|
|
|
|
{
|
|
|
|
waterlevel = 2;
|
|
|
|
point[ grav.z ] = worldorigin[ grav.z ] + mins[ grav.z ] + sample2;
|
|
|
|
cont = gi.pointcontents( point.vec3() );
|
|
|
|
if ( cont & MASK_WATER )
|
|
|
|
{
|
|
|
|
waterlevel = 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
link();
|
|
|
|
if ( vehicle )
|
|
|
|
{
|
|
|
|
vehicle->link();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=============
|
|
|
|
WorldEffects
|
|
|
|
=============
|
|
|
|
*/
|
|
|
|
void Player::WorldEffects
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
if ( movetype == MOVETYPE_NOCLIP )
|
|
|
|
{
|
|
|
|
// don't need air
|
|
|
|
air_finished = level.time + 20;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Check for earthquakes
|
|
|
|
//
|
|
|
|
if ( groundentity && ( level.earthquake > level.time ) )
|
|
|
|
{
|
|
|
|
velocity += Vector(EARTHQUAKE_STRENGTH*G_CRandom(),EARTHQUAKE_STRENGTH*G_CRandom(),fabs(150*G_CRandom()));
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// if just entered a water volume, play a sound
|
|
|
|
//
|
|
|
|
if ( !old_waterlevel && waterlevel )
|
|
|
|
{
|
|
|
|
if ( watertype & CONTENTS_LAVA )
|
|
|
|
{
|
|
|
|
RandomSound( "snd_burn", 1, CHAN_BODY, ATTN_NORM );
|
|
|
|
ProcessEvent( EV_MovementSound );
|
|
|
|
}
|
|
|
|
else if ( ( watertype & CONTENTS_WATER ) && waterlevel < 3)
|
|
|
|
{
|
|
|
|
RandomGlobalSound( "impact_playersplash", 1, CHAN_BODY, ATTN_NORM );
|
|
|
|
ProcessEvent( EV_MovementSound );
|
|
|
|
}
|
|
|
|
|
|
|
|
flags |= FL_INWATER;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// if just completely exited a water volume, play a sound
|
|
|
|
//
|
|
|
|
if ( old_waterlevel && !waterlevel )
|
|
|
|
{
|
|
|
|
RandomGlobalSound( "impact_playerleavewater", 1, CHAN_BODY, ATTN_NORM );
|
|
|
|
ProcessEvent( EV_MovementSound );
|
|
|
|
flags &= ~FL_INWATER;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// check for head just going under water
|
|
|
|
//
|
|
|
|
if ( old_waterlevel && old_waterlevel != 3 && waterlevel == 3 )
|
|
|
|
{
|
|
|
|
RandomGlobalSound( "impact_playersubmerge", 1, CHAN_BODY, ATTN_NORM );
|
|
|
|
ProcessEvent( EV_MovementSound );
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// check for head just coming out of water
|
|
|
|
//
|
|
|
|
if ( old_waterlevel == 3 && waterlevel != 3 )
|
|
|
|
{
|
|
|
|
if ( air_finished < level.time )
|
|
|
|
{
|
|
|
|
// gasp for air
|
|
|
|
RandomSound( "snd_gasp", 1, CHAN_VOICE, ATTN_NORM );
|
|
|
|
ProcessEvent( EV_VoiceSound );
|
|
|
|
}
|
|
|
|
else if ( air_finished < level.time + 11 )
|
|
|
|
{
|
|
|
|
// just break surface
|
|
|
|
RandomSound( "snd_gasp", 1, CHAN_VOICE, ATTN_NORM );
|
|
|
|
ProcessEvent( EV_VoiceSound );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// check for lava
|
|
|
|
//
|
|
|
|
if ( watertype & CONTENTS_LAVA )
|
|
|
|
{
|
|
|
|
if ( next_drown_time < level.time )
|
|
|
|
{
|
|
|
|
next_drown_time = level.time + 0.2f;
|
|
|
|
Damage( world, world, 10 * waterlevel, worldorigin, vec_zero, vec_zero, 0, DAMAGE_NO_ARMOR, MOD_LAVA, -1, -1, 1.0f );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// check for drowning
|
|
|
|
//
|
|
|
|
if (waterlevel == 3)
|
|
|
|
{
|
|
|
|
// if out of air, start drowning
|
|
|
|
if ( ( air_finished < level.time ) && !( flags & FL_OXYGEN ) && !( flags & FL_GODMODE ) )
|
|
|
|
{
|
|
|
|
// drown!
|
|
|
|
if ( next_drown_time < level.time && health > 0 )
|
|
|
|
{
|
|
|
|
next_drown_time = level.time + 1;
|
|
|
|
|
|
|
|
// take more damage the longer underwater
|
|
|
|
drown_damage += 2;
|
|
|
|
if ( drown_damage > 15 )
|
|
|
|
{
|
|
|
|
drown_damage = 15;
|
|
|
|
}
|
|
|
|
|
|
|
|
// play a gurp sound instead of a normal pain sound
|
|
|
|
if ( health <= drown_damage )
|
|
|
|
{
|
|
|
|
RandomSound( "snd_drown", 1, CHAN_VOICE, ATTN_NORM );
|
|
|
|
ProcessEvent( EV_PainSound );
|
|
|
|
}
|
|
|
|
else if ( rand() & 1 )
|
|
|
|
{
|
|
|
|
RandomSound( "snd_choke", 1, CHAN_VOICE, ATTN_NORM );
|
|
|
|
ProcessEvent( EV_PainSound );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RandomSound( "snd_choke", 1, CHAN_VOICE, ATTN_NORM );
|
|
|
|
ProcessEvent( EV_PainSound );
|
|
|
|
}
|
|
|
|
|
|
|
|
Damage( world, world, drown_damage, worldorigin, vec_zero, vec_zero, 0, DAMAGE_NO_ARMOR, MOD_DROWN, -1, -1, 1.0f );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
air_finished = level.time + 20;
|
|
|
|
drown_damage = 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
GravityNodes();
|
1999-11-02 00:00:00 +00:00
|
|
|
|
|
|
|
// Apply grappling hook
|
|
|
|
if ( grapple_pull )
|
|
|
|
{
|
|
|
|
Vector v, dir;
|
|
|
|
int length;
|
|
|
|
|
|
|
|
v = worldorigin;
|
|
|
|
v[2] += viewheight;
|
|
|
|
|
|
|
|
v = centroid;
|
|
|
|
|
|
|
|
dir = grapple_org - v;
|
|
|
|
|
|
|
|
length = dir.length();
|
|
|
|
|
|
|
|
if ( length > 48 )
|
|
|
|
{
|
|
|
|
dir.normalize();
|
|
|
|
velocity = dir * grapple_speed;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
velocity = vec_zero;
|
|
|
|
gravity = 0;
|
|
|
|
hook->StopEntitySound( NULL );
|
|
|
|
}
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
|
|
|
old_waterlevel = waterlevel;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=============
|
|
|
|
AddBlend
|
|
|
|
=============
|
|
|
|
*/
|
|
|
|
void Player::AddBlend
|
|
|
|
(
|
|
|
|
float r,
|
|
|
|
float g,
|
|
|
|
float b,
|
|
|
|
float a
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
float a2;
|
|
|
|
float a3;
|
|
|
|
|
|
|
|
if ( a <= 0 )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// new total alpha
|
|
|
|
a2 = blend[ 3 ] + ( 1 - blend[ 3 ] ) * a;
|
|
|
|
|
|
|
|
// fraction of color from old
|
|
|
|
a3 = blend[ 3 ] / a2;
|
|
|
|
|
|
|
|
blend[ 0 ] = blend[ 0 ] * a3 + r * ( 1 - a3 );
|
|
|
|
blend[ 1 ] = blend[ 1 ] * a3 + g * ( 1 - a3 );
|
|
|
|
blend[ 2 ] = blend[ 2 ] * a3 + b * ( 1 - a3 );
|
|
|
|
blend[ 3 ] = a2;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=============
|
|
|
|
CalcBlend
|
|
|
|
=============
|
|
|
|
*/
|
|
|
|
void Player::CalcBlend
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
int contents;
|
|
|
|
Vector vieworg;
|
|
|
|
const gravityaxis_t &grav = gravity_axis[ gravaxis ];
|
|
|
|
|
|
|
|
blend[ 0 ] = blend[ 1 ] = blend[ 2 ] = blend[ 3 ] = 0;
|
|
|
|
|
|
|
|
// add for contents
|
|
|
|
vieworg[ grav.x ] = worldorigin[ grav.x ] + v_offset[ 0 ];
|
|
|
|
vieworg[ grav.y ] = worldorigin[ grav.y ] + v_offset[ 1 ] * grav.sign;
|
|
|
|
vieworg[ grav.z ] = worldorigin[ grav.z ] + v_offset[ 2 ] * grav.sign;
|
|
|
|
|
|
|
|
contents = gi.pointcontents( vieworg.vec3() );
|
|
|
|
|
|
|
|
if ( contents & CONTENTS_SOLID )
|
|
|
|
{
|
|
|
|
// Outside of world
|
|
|
|
AddBlend( 0.8, 0.5, 0.0, 0.2 );
|
|
|
|
}
|
|
|
|
else if ( contents & CONTENTS_LAVA )
|
|
|
|
{
|
|
|
|
AddBlend( level.lava_color[0], level.lava_color[1], level.lava_color[2], level.lava_alpha );
|
|
|
|
}
|
|
|
|
else if ( contents & CONTENTS_WATER )
|
|
|
|
{
|
|
|
|
AddBlend( level.water_color[0], level.water_color[1], level.water_color[2], level.water_alpha );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( contents & CONTENTS_LIGHTVOLUME )
|
|
|
|
{
|
|
|
|
AddBlend( level.lightvolume_color[0], level.lightvolume_color[1], level.lightvolume_color[2], level.lightvolume_alpha );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Flashes
|
|
|
|
AddBlend( flash_color[0], flash_color[1], flash_color[2], flash_color[3] );
|
|
|
|
|
|
|
|
// add for zoom
|
|
|
|
if ( zoom_mode == ZOOMED_IN )
|
|
|
|
{
|
|
|
|
AddBlend( 0.4, 1, 0.1, 0.1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
// add for damage
|
|
|
|
if ( damage_alpha > 0 )
|
|
|
|
{
|
|
|
|
AddBlend( damage_blend[ 0 ], damage_blend[ 1 ], damage_blend[ 2 ], damage_alpha );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( flags & FL_ADRENALINE )
|
|
|
|
{
|
|
|
|
AddBlend( 1.0f, 1.0f, 0.0f, 0.2f );
|
|
|
|
}
|
|
|
|
|
|
|
|
// drop the damage value
|
|
|
|
damage_alpha -= 0.06;
|
|
|
|
if ( damage_alpha < 0 )
|
|
|
|
{
|
|
|
|
damage_alpha = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Drop the flash
|
|
|
|
flash_color[3] -= 0.06;
|
|
|
|
if ( flash_color[3] < 0 )
|
|
|
|
{
|
|
|
|
flash_color[3] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
===============
|
|
|
|
P_DamageFeedback
|
|
|
|
|
|
|
|
Handles color blends and view kicks
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
|
|
|
|
void Player::DamageFeedback
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
float realcount;
|
|
|
|
float count;
|
|
|
|
|
|
|
|
// flash the backgrounds behind the status numbers
|
|
|
|
client->ps.stats[ STAT_FLASHES ] = 0;
|
|
|
|
|
|
|
|
if ( damage_blood )
|
|
|
|
{
|
|
|
|
client->ps.stats[ STAT_FLASHES ] |= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// total points of damage shot at the player this frame
|
|
|
|
if ( !damage_blood )
|
|
|
|
{
|
|
|
|
// didn't take any damage
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
count = damage_blood;
|
|
|
|
realcount = count;
|
|
|
|
if ( count < 10 )
|
|
|
|
{
|
|
|
|
// always make a visible effect
|
|
|
|
count = 10;
|
|
|
|
}
|
|
|
|
|
|
|
|
// the total alpha of the blend is always proportional to count
|
|
|
|
if ( damage_alpha < 0 )
|
|
|
|
{
|
|
|
|
damage_alpha = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
damage_alpha += count * 0.01;
|
|
|
|
if ( damage_alpha < 0.2 )
|
|
|
|
{
|
|
|
|
damage_alpha = 0.2;
|
|
|
|
}
|
|
|
|
if ( damage_alpha > 0.6 )
|
|
|
|
{
|
|
|
|
// don't go too saturated
|
|
|
|
damage_alpha = 0.6;
|
|
|
|
}
|
|
|
|
|
|
|
|
// the color of the blend will vary based on how much was absorbed
|
|
|
|
// by different armors
|
|
|
|
damage_blend = vec_zero;
|
|
|
|
if ( damage_blood )
|
|
|
|
{
|
|
|
|
damage_blend += ( damage_blood / realcount ) * bcolor;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// clear totals
|
|
|
|
//
|
|
|
|
damage_blood = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_FROM_DLL const char * Player::AnimPrefixForWeapon
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
if ( currentWeapon )
|
|
|
|
{
|
|
|
|
switch ( currentWeapon->GetType() )
|
|
|
|
{
|
|
|
|
case WEAPON_MELEE:
|
|
|
|
return "";
|
|
|
|
break;
|
|
|
|
case WEAPON_1HANDED:
|
|
|
|
return "1hand_";
|
|
|
|
break;
|
|
|
|
case WEAPON_2HANDED_HI:
|
|
|
|
return "hi2hand_";
|
|
|
|
break;
|
|
|
|
case WEAPON_2HANDED_LO:
|
|
|
|
return "lo2hand_";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return "";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
EXPORT_FROM_DLL void Player::ChooseAnim
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
str prefix;
|
|
|
|
str aname;
|
|
|
|
|
|
|
|
if ( deadflag )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( vehicle )
|
|
|
|
{
|
|
|
|
falling = false;
|
|
|
|
animOverride = false;
|
|
|
|
SetAnim( vehicleanim.c_str() );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( onladder )
|
|
|
|
{
|
|
|
|
if ( falling )
|
|
|
|
{
|
|
|
|
Event * ev;
|
|
|
|
|
|
|
|
ev = new Event( EV_Sentient_AnimLoop );
|
|
|
|
ProcessEvent( ev );
|
|
|
|
falling = false;
|
|
|
|
}
|
|
|
|
if ( fabs( velocity[ 2 ] ) > 0 )
|
|
|
|
{
|
|
|
|
SetAnim( "climb" );
|
|
|
|
}
|
|
|
|
else if (!animOverride)
|
|
|
|
{
|
|
|
|
StopAnimating();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( client->ps.pmove.pm_flags & PMF_DUCKED )
|
|
|
|
{
|
|
|
|
if ( !( old_pmove.pm_flags & PMF_DUCKED ) )
|
|
|
|
{
|
|
|
|
SetAnim( "crouch" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( old_pmove.pm_flags & PMF_DUCKED )
|
|
|
|
{
|
|
|
|
SetAnim( "uncrouch" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// put the appropriate prefix on the animation
|
|
|
|
prefix = AnimPrefixForPlayer();
|
|
|
|
|
|
|
|
if ( currentWeapon )
|
|
|
|
{
|
|
|
|
if ( currentWeapon->WeaponRaising() )
|
|
|
|
{
|
|
|
|
aname = prefix + str( "readyweapon" );
|
|
|
|
SetAnim( aname.c_str() );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if ( currentWeapon->WeaponPuttingAway() )
|
|
|
|
{
|
|
|
|
aname = prefix + str( "putaway" );
|
|
|
|
SetAnim( aname.c_str() );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if ( currentWeapon->Reloading() )
|
|
|
|
{
|
|
|
|
aname = prefix + str( "reload" );
|
|
|
|
SetAnim( aname.c_str() );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// append the prefix based on which weapon we are holding
|
|
|
|
//
|
|
|
|
prefix += str( AnimPrefixForWeapon() );
|
|
|
|
|
|
|
|
if ( waterlevel > 2 || (!groundentity && waterlevel ) )
|
|
|
|
{
|
|
|
|
if ( xyspeed > 20 )
|
|
|
|
{
|
|
|
|
aname = prefix + str( "run" );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
aname = prefix + str( "idle" );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( xyspeed > 250 )
|
|
|
|
{
|
|
|
|
aname = prefix + str( "run" );
|
|
|
|
}
|
|
|
|
else if ( xyspeed > 20 )
|
|
|
|
{
|
|
|
|
if ( client->ps.pmove.pm_flags & PMF_DUCKED )
|
|
|
|
{
|
|
|
|
aname = prefix + str( "run" );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
aname = prefix + str( "walk" );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
aname = prefix + str( "idle" );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( grapple_pull )
|
|
|
|
{
|
|
|
|
aname = "fall";
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the anim for the flag
|
|
|
|
if ( ctf->value )
|
|
|
|
{
|
|
|
|
CTF_Flag *flag;
|
|
|
|
|
|
|
|
if ( flag = ( CTF_Flag * )HasItemOfSuperclass( "CTF_Flag" ) )
|
|
|
|
{
|
|
|
|
if ( xyspeed > 250 )
|
|
|
|
{
|
|
|
|
if ( flag->limp )
|
|
|
|
{
|
|
|
|
flag->RandomAnimate( "idle", NULL );
|
|
|
|
flag->limp = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( !flag->limp )
|
|
|
|
{
|
|
|
|
flag->RandomAnimate( "limp", NULL );
|
|
|
|
flag->limp = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SetAnim( aname.c_str() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::SetCameraValues
|
|
|
|
(
|
|
|
|
Vector position,
|
|
|
|
Vector cameraoffset,
|
|
|
|
Vector ang,
|
|
|
|
Vector camerakick,
|
|
|
|
Vector vel,
|
|
|
|
float camerablend[ 4 ],
|
|
|
|
float camerafov
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
client->ps.viewangles[ 0 ] = ang[ 0 ];
|
|
|
|
client->ps.viewangles[ 1 ] = ang[ 1 ];
|
|
|
|
client->ps.viewangles[ 2 ] = ang[ 2 ];
|
|
|
|
|
|
|
|
client->ps.viewoffset[ 0 ] = cameraoffset[ 0 ];
|
|
|
|
client->ps.viewoffset[ 1 ] = cameraoffset[ 1 ];
|
|
|
|
client->ps.viewoffset[ 2 ] = cameraoffset[ 2 ];
|
|
|
|
|
|
|
|
client->ps.pmove.origin[ 0 ] = position[ 0 ] * 8;
|
|
|
|
client->ps.pmove.origin[ 1 ] = position[ 1 ] * 8;
|
|
|
|
client->ps.pmove.origin[ 2 ] = position[ 2 ] * 8;
|
|
|
|
|
|
|
|
client->ps.pmove.velocity[ 0 ] = vel[ 0 ] * 8.0;
|
|
|
|
client->ps.pmove.velocity[ 1 ] = vel[ 1 ] * 8.0;
|
|
|
|
client->ps.pmove.velocity[ 2 ] = vel[ 2 ] * 8.0;
|
|
|
|
|
|
|
|
client->ps.blend[ 0 ] = camerablend[ 0 ];
|
|
|
|
client->ps.blend[ 1 ] = camerablend[ 1 ];
|
|
|
|
client->ps.blend[ 2 ] = camerablend[ 2 ];
|
|
|
|
client->ps.blend[ 3 ] = camerablend[ 3 ];
|
|
|
|
|
|
|
|
client->ps.fov = camerafov;
|
|
|
|
|
|
|
|
client->ps.kick_angles[ 0 ] = camerakick[ 0 ];
|
|
|
|
client->ps.kick_angles[ 1 ] = camerakick[ 1 ];
|
|
|
|
client->ps.kick_angles[ 2 ] = camerakick[ 2 ];
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::SetCameraEntity
|
1998-12-20 00:00:00 +00:00
|
|
|
(
|
1999-11-02 00:00:00 +00:00
|
|
|
Entity *cameraEnt
|
1998-12-20 00:00:00 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
assert( cameraEnt );
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// In release, we should never be without a camera
|
|
|
|
if ( !cameraEnt )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
cameraEnt = this;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// should we see the player's body?
|
|
|
|
if ( cameraEnt == this )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
edict->s.renderfx |= RF_VIEWERMODEL;
|
|
|
|
if ( currentWeapon )
|
|
|
|
{
|
|
|
|
if ( !vehicle || vehicle->ShowWeapon() )
|
|
|
|
{
|
|
|
|
currentWeapon->edict->s.renderfx &= ~RF_DONTDRAW;
|
|
|
|
currentWeapon->edict->s.renderfx |= RF_VIEWERMODEL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
currentWeapon->edict->s.renderfx |= RF_DONTDRAW;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( !ctf->value && vehicle && vehicle->IsDrivable() )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
SetCameraValues( worldorigin, v_offset, v_angle, v_kick, velocity, blend, fov*1.25 );
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
else
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
SetCameraValues( worldorigin, v_offset, v_angle, v_kick, velocity, blend, fov );
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
float noblend[ 4 ];
|
|
|
|
float camerafov;
|
|
|
|
Vector pos;
|
|
|
|
|
|
|
|
/*
|
|
|
|
if ( vehicle && cameraEnt == thirdpersonCamera )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
Event * event;
|
|
|
|
|
|
|
|
event = new Event( EV_Camera_SetDistance );
|
|
|
|
event->AddFloat( 256 );
|
|
|
|
cameraEnt->ProcessEvent( event );
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
*/
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
edict->s.renderfx &= ~RF_VIEWERMODEL;
|
|
|
|
|
|
|
|
if ( currentWeapon )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
// Take the weapon out of the view
|
|
|
|
currentWeapon->edict->s.renderfx &= ~RF_VIEWERMODEL;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( in_console )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
// Make the client act like a viewmodel so it doesn't block
|
|
|
|
// the camera to the console.
|
|
|
|
edict->s.renderfx |= RF_VIEWERMODEL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME
|
|
|
|
// should add all these fields to entity or camera or whatever.
|
|
|
|
noblend[ 0 ] = 0;
|
|
|
|
noblend[ 1 ] = 0;
|
|
|
|
noblend[ 2 ] = 0;
|
|
|
|
noblend[ 3 ] = 0;
|
|
|
|
pos = vec_zero;
|
|
|
|
|
|
|
|
camerafov = 90;
|
|
|
|
if ( cameraEnt->isSubclassOf( Mine ) )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
Vector dir;
|
|
|
|
vec3_t mat[3];
|
|
|
|
|
|
|
|
camerafov = ( ( Projectile * )cameraEnt )->fov;
|
|
|
|
|
|
|
|
AnglesToMat( cameraEnt->worldangles.vec3(), mat );
|
|
|
|
dir = mat[0];
|
|
|
|
if ( cameraEnt->velocity == vec_zero )
|
|
|
|
{
|
|
|
|
pos = dir * 30;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pos = pos + Vector(0,0,1) * 30;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
else if ( cameraEnt->isSubclassOf( Camera ) )
|
|
|
|
{
|
|
|
|
camerafov = ( ( Camera * )cameraEnt )->fov;
|
|
|
|
if ( cameraEnt->isSubclassOf( SecurityCamera ) )
|
|
|
|
cameraEnt->edict->s.renderfx |= RF_DONTDRAW;
|
|
|
|
}
|
|
|
|
else if ( trappedInQuantum )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
Sentient *sent;
|
|
|
|
|
|
|
|
if ( cameraEnt->isSubclassOf( Sentient ) )
|
|
|
|
{
|
|
|
|
Vector dir;
|
|
|
|
|
|
|
|
sent = ( Sentient * )cameraEnt;
|
|
|
|
sent->GetMuzzlePositionAndDirection( &pos, &dir );
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
else if ( cameraEnt->isSubclassOf( Sentient ) )
|
|
|
|
{
|
|
|
|
pos = ( ( Sentient * )cameraEnt )->EyePosition() - cameraEnt->worldorigin;
|
|
|
|
}
|
|
|
|
|
|
|
|
SetCameraValues( cameraEnt->worldorigin, pos, cameraEnt->worldangles, vec_zero,
|
|
|
|
cameraEnt->velocity, noblend, camerafov );
|
|
|
|
//SetCameraValues( "0 0 64", pos, "0 270 0", vec_zero,
|
|
|
|
// cameraEnt->velocity, noblend, camerafov );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( flags & FL_SHIELDS )
|
|
|
|
{
|
|
|
|
edict->s.renderfx |= RF_ENVMAPPED;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
else
|
|
|
|
edict->s.renderfx &= ~RF_ENVMAPPED;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( flags & FL_CLOAK )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
setAlpha( 0 );
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
else
|
1999-11-02 00:00:00 +00:00
|
|
|
setAlpha( 1.0f );
|
|
|
|
|
|
|
|
if ( currentWeapon )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( flags & FL_SHIELDS )
|
|
|
|
currentWeapon->edict->s.renderfx |= RF_ENVMAPPED;
|
|
|
|
else
|
|
|
|
currentWeapon->edict->s.renderfx &= ~RF_ENVMAPPED;
|
|
|
|
|
|
|
|
if ( flags & FL_CLOAK )
|
|
|
|
{
|
|
|
|
currentWeapon->edict->s.alpha = 0.1f;
|
|
|
|
currentWeapon->edict->s.renderfx |= RF_TRANSLUCENT;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
currentWeapon->edict->s.alpha = 1.0f;
|
|
|
|
currentWeapon->edict->s.renderfx &= ~RF_TRANSLUCENT;
|
|
|
|
}
|
|
|
|
if ( cameraEnt != this )
|
|
|
|
{
|
|
|
|
if ( edict->s.renderfx & RF_DONTDRAW )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
currentWeapon->edict->s.renderfx |= RF_DONTDRAW;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
currentWeapon->edict->s.renderfx &= ~RF_DONTDRAW;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( ( viewmode == THIRD_PERSON ) && crosshair && currentWeapon )
|
|
|
|
{
|
|
|
|
Vector dir, src, end;
|
|
|
|
trace_t trace;
|
|
|
|
|
|
|
|
currentWeapon->GetMuzzlePosition( &src, &dir );
|
|
|
|
|
|
|
|
end = src + dir * 8192;
|
|
|
|
trace = G_FullTrace( src, vec_zero, vec_zero, end, 5, this, MASK_SHOT, "Player::SetCameraEntity" );
|
|
|
|
if ( trace.intersect.valid )
|
|
|
|
{
|
|
|
|
crosshair->edict->s.frame = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
crosshair->edict->s.frame = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
crosshair->setOrigin( trace.endpos - dir * 16 );
|
|
|
|
crosshair->edict->s.scale = ( crosshair->worldorigin - worldorigin ).length() / 256;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_FROM_DLL void Player::CalcBob
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
float time;
|
|
|
|
Vector hvel;
|
|
|
|
const gravityaxis_t &grav = gravity_axis[ gravaxis ];
|
|
|
|
//
|
|
|
|
// calculate speed and cycle to be used for
|
|
|
|
// all cyclic walking effects
|
|
|
|
//
|
|
|
|
hvel[ grav.x ] = velocity[ grav.x ];
|
|
|
|
hvel[ grav.y ] = velocity[ grav.y ];
|
|
|
|
hvel[ grav.z ] = 0;
|
|
|
|
xyspeed = hvel.length();
|
|
|
|
|
|
|
|
if ( xyspeed < 5 )
|
|
|
|
{
|
|
|
|
// start at beginning of cycle again
|
|
|
|
bobmove = 0;
|
|
|
|
bobtime = 0;
|
|
|
|
}
|
|
|
|
else if ( groundentity )
|
|
|
|
{
|
|
|
|
// so bobbing only cycles when on ground
|
|
|
|
if ( xyspeed > 210 )
|
|
|
|
{
|
|
|
|
bobmove = 0.25;
|
|
|
|
}
|
|
|
|
else if ( xyspeed > 100 )
|
|
|
|
{
|
|
|
|
bobmove = 0.125;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
bobmove = 0.0625;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bobtime += bobmove;
|
|
|
|
time = bobtime;
|
|
|
|
if ( client->ps.pmove.pm_flags & PMF_DUCKED )
|
|
|
|
{
|
|
|
|
time *= 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
bobcycle = ( int )time;
|
|
|
|
bobfracsin = fabs( sin( time * M_PI ) );
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
/*
|
|
|
|
=================
|
|
|
|
P_FallingDamage
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void Player::FallingDamage
|
1998-12-20 00:00:00 +00:00
|
|
|
(
|
1999-11-02 00:00:00 +00:00
|
|
|
void
|
1998-12-20 00:00:00 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
float delta;
|
|
|
|
float damage;
|
|
|
|
csurface_t *surf;
|
|
|
|
int z;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
z = gravity_axis[ gravaxis ].z;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( deadflag )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( flags & (FL_MUTANT|FL_SP_MUTANT|FL_ADRENALINE) || grapple_pull || ( grapple_time > level.time ) )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( getMoveType() == MOVETYPE_NOCLIP )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ( !fallsurface )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
surf = fallsurface;
|
|
|
|
fallsurface = NULL;
|
|
|
|
delta = velocity[ z ] - oldvelocity[ z ];
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
delta = delta * delta * 0.0001;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// never take falling damage if completely underwater
|
|
|
|
switch( waterlevel )
|
|
|
|
{
|
|
|
|
case 1 :
|
|
|
|
delta *= 0.5;
|
|
|
|
break;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
case 2 :
|
|
|
|
delta *= 0.25;
|
|
|
|
break;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
case 3 :
|
|
|
|
return;
|
|
|
|
break;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( delta < 3 )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
return;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
fall_value = delta * 0.5;
|
|
|
|
if ( fall_value > 40 )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
fall_value = 40;
|
|
|
|
}
|
|
|
|
|
|
|
|
fall_time = level.time + FALL_TIME;
|
|
|
|
|
|
|
|
if ( delta > 30 )
|
|
|
|
{
|
|
|
|
damage = ( delta - 30 ) / 2;
|
|
|
|
|
|
|
|
if ( surf )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
// modify damage based on surface
|
|
|
|
switch ( surf->flags & MASK_SURF_TYPE )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
// Can this happen?
|
|
|
|
case SURF_TYPE_WATER:
|
|
|
|
break;
|
|
|
|
|
|
|
|
// no damage
|
|
|
|
case SURF_TYPE_FABRIC:
|
|
|
|
damage *= 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
// low damage
|
|
|
|
case SURF_TYPE_FLESH:
|
|
|
|
case SURF_TYPE_VEGETATION:
|
|
|
|
damage *= 0.5;
|
|
|
|
break;
|
|
|
|
|
|
|
|
// medium damage
|
|
|
|
case SURF_TYPE_DIRT:
|
|
|
|
damage *= 0.6;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SURF_TYPE_WOOD:
|
|
|
|
damage *= 0.8;
|
|
|
|
break;
|
|
|
|
|
|
|
|
// full damage
|
|
|
|
case SURF_TYPE_GRAVEL:
|
|
|
|
case SURF_TYPE_GRILL:
|
|
|
|
case SURF_TYPE_METAL:
|
|
|
|
case SURF_TYPE_STONE:
|
|
|
|
case SURF_TYPE_CONCRETE:
|
|
|
|
case SURF_TYPE_DUCT:
|
|
|
|
default:
|
|
|
|
break;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
|
|
|
|
if ( surf && surf->frequency != 0 )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
damage = 0;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
|
|
|
|
if ( ( damage >= 1 ) && ( !DM_FLAG( DF_NO_FALLING ) ) )
|
|
|
|
{
|
|
|
|
Damage( world, world, ( int )damage, worldorigin, vec_zero, vec_zero, 0, DAMAGE_NO_ARMOR, MOD_FALLING, -1, -1, 1.0f );
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( surf && surf->frequency != 0 )
|
|
|
|
{
|
|
|
|
fall_time = 0;
|
|
|
|
fall_value = 0;
|
|
|
|
}
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
EXPORT_FROM_DLL void Player::FinishMove
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
{
|
|
|
|
Vector t[ 3 ];
|
|
|
|
Vector forward;
|
|
|
|
Vector right;
|
|
|
|
Vector up;
|
|
|
|
Vector temp;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( ai_createnodes->value )
|
|
|
|
{
|
|
|
|
AddPathNodes();
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
//
|
|
|
|
// If the origin or velocity have changed since ClientThink(),
|
|
|
|
// update the pmove values. This will happen when the client
|
|
|
|
// is pushed by a bmodel or kicked by an explosion.
|
|
|
|
//
|
|
|
|
// If it wasn't updated here, the view position would lag a frame
|
|
|
|
// behind the body position when pushed -- "sinking into plats"
|
|
|
|
//
|
|
|
|
if (
|
|
|
|
( GetMovePlayerMoveType() != PM_LOCKVIEW ) &&
|
|
|
|
( GetMovePlayerMoveType() != PM_FREEZE )
|
|
|
|
)
|
|
|
|
{
|
|
|
|
client->ps.pmove.origin[ 0 ] = worldorigin.x * 8.0;
|
|
|
|
client->ps.pmove.origin[ 1 ] = worldorigin.y * 8.0;
|
|
|
|
client->ps.pmove.origin[ 2 ] = worldorigin.z * 8.0;
|
|
|
|
client->ps.pmove.velocity[ 0 ] = velocity.x * 8.0;
|
|
|
|
client->ps.pmove.velocity[ 1 ] = velocity.y * 8.0;
|
|
|
|
client->ps.pmove.velocity[ 2 ] = velocity.z * 8.0;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
//
|
|
|
|
// set model angles from view angles so other things in
|
|
|
|
// the world can tell which direction you are looking
|
|
|
|
//
|
|
|
|
if ( vehicle )
|
|
|
|
{
|
|
|
|
angles[ PITCH ] = vehicle->SetDriverPitch( v_angle[ PITCH ] );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( waterlevel >= 3 )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
angles[ PITCH ] = v_angle[ PITCH ];
|
|
|
|
}
|
|
|
|
else if ( v_angle[ PITCH ] > 180 )
|
|
|
|
{
|
|
|
|
angles[ PITCH ] = ( -360 + v_angle[ PITCH ] ) / 12;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
angles[ PITCH ] = v_angle[ PITCH ] / 12;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
angles[ YAW ] = v_angle[ YAW ];
|
|
|
|
angles[ ROLL ] = CalcRoll();
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// Orient the angles to coincide with our special gravity vector
|
|
|
|
const gravityaxis_t &grav = gravity_axis[ gravaxis ];
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
angles.AngleVectors( &t[0], &t[1], &t[2] );
|
|
|
|
forward[ grav.x ] = t[ 0 ][ 0 ];
|
|
|
|
forward[ grav.y ] = t[ 0 ][ 1 ] * grav.sign;
|
|
|
|
forward[ grav.z ] = t[ 0 ][ 2 ] * grav.sign;
|
|
|
|
right[ grav.x ] = t[ 1 ][ 0 ];
|
|
|
|
right[ grav.y ] = t[ 1 ][ 1 ] * grav.sign;
|
|
|
|
right[ grav.z ] = t[ 1 ][ 2 ] * grav.sign;
|
|
|
|
up[ grav.x ] = t[ 2 ][ 0 ];
|
|
|
|
up[ grav.y ] = t[ 2 ][ 1 ] * grav.sign;
|
|
|
|
up[ grav.z ] = t[ 2 ][ 2 ] * grav.sign;
|
|
|
|
VectorsToEulerAngles( forward.vec3(), right.vec3(), up.vec3(), angles.vec3() );
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( !level.playerfrozen )
|
|
|
|
{
|
|
|
|
setAngles( angles );
|
|
|
|
AnglesToMat( v_angle.vec3(), orientation );
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
CalcBob();
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// check if we're over the limit health-wise
|
|
|
|
if ( ( (int)health > (int)max_health ) && ( ( float )( ( int )level.time ) == level.time ) )
|
|
|
|
{
|
|
|
|
// CTF: Regeneration Tech doesn't drain health over 100
|
|
|
|
if ( !FindItem( "CTF_Tech_Regeneration" ) )
|
|
|
|
{
|
|
|
|
health -= 1;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// mutant mode
|
|
|
|
if ( ( flags & FL_SP_MUTANT ) && !( flags & FL_GODMODE ) && ( ( float )( ( int )level.time ) == level.time ) )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
Damage( world, world, 1, worldorigin, vec_zero, vec_zero, 0, DAMAGE_NO_ARMOR, MOD_MUTANT_DRAIN, -1, -1, 1.0f );
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
|
|
|
|
// Check for silencer
|
|
|
|
if ( !(flags & FL_SILENCER) && FindItem( "Silencer" ) )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
flags |= FL_SILENCER;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
|
|
|
|
// Check for O2
|
|
|
|
if ( !(flags & FL_OXYGEN) && FindItem( "ScubaGear" ) )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
flags |= FL_OXYGEN;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// burn from lava, etc
|
|
|
|
WorldEffects();
|
|
|
|
FallingDamage();
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
ChooseAnim();
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// determine the view offsets
|
|
|
|
CalcViewOffset();
|
|
|
|
CalcGunOffset();
|
|
|
|
DamageFeedback();
|
|
|
|
CalcBlend();
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
oldvelocity = velocity;
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_FROM_DLL qboolean Player::CanMoveTo
|
|
|
|
(
|
|
|
|
Vector pos
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
Vector min;
|
|
|
|
trace_t trace;
|
|
|
|
Vector start;
|
|
|
|
Vector end;
|
|
|
|
Vector s;
|
|
|
|
|
|
|
|
s = Vector( 0, 0, 20 );
|
|
|
|
start = worldorigin + s;
|
|
|
|
end = pos + s;
|
|
|
|
trace = G_Trace( start, mins, maxs, end, this, MASK_SOLID, "Player::CanMoveTo" );
|
|
|
|
if ( trace.fraction == 1 )
|
|
|
|
{
|
|
|
|
return true;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
return false;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
EXPORT_FROM_DLL qboolean Player::ClearPathTo
|
1998-12-20 00:00:00 +00:00
|
|
|
(
|
1999-11-02 00:00:00 +00:00
|
|
|
Vector pos
|
1998-12-20 00:00:00 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
Vector dir;
|
|
|
|
Vector midpos;
|
|
|
|
Vector end_trace;
|
|
|
|
Vector delta;
|
|
|
|
Vector start;
|
|
|
|
Vector min;
|
|
|
|
Vector max;
|
|
|
|
trace_t trace;
|
|
|
|
float dist;
|
|
|
|
float t;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
min = Vector( -16, -16, 12 );
|
|
|
|
max = Vector( 16, 16, 40 );
|
|
|
|
start = worldorigin;
|
|
|
|
dir = pos - worldorigin;
|
|
|
|
|
|
|
|
delta = dir;
|
|
|
|
delta[ 2 ] = 0;
|
|
|
|
if ( delta.length() >= PATHMAP_CELLSIZE )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
return false;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
|
|
|
|
if ( !CanMoveTo( pos ) )
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// only do a full test when we train a level
|
|
|
|
if ( !ai_createnodes->value )
|
|
|
|
{
|
|
|
|
midpos = start + dir * 0.5;
|
|
|
|
end_trace = midpos - Vector( 0, 0, 40 );
|
|
|
|
|
|
|
|
// check that the midpos is onground (down 28 units)
|
|
|
|
trace = G_Trace( midpos, min, max, end_trace, this, MASK_SOLID, "Player::ClearPathTo 1" );
|
|
|
|
if ( trace.fraction == 1 )
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
dist = dir.length();
|
|
|
|
if ( dist < 32 )
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
dir[ 2 ] = 0;
|
|
|
|
dist = dir.length();
|
|
|
|
dir.normalize();
|
|
|
|
|
|
|
|
min = Vector( -16, -16, 0 );
|
|
|
|
// check the entire move
|
|
|
|
midpos = start;
|
|
|
|
for( t = 0; t < dist; t += 8 )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
midpos[ 0 ] = start[ 0 ] + t * dir[ 0 ];
|
|
|
|
midpos[ 1 ] = start[ 1 ] + t * dir[ 1 ];
|
|
|
|
midpos[ 2 ] += 18;
|
|
|
|
end_trace = midpos - Vector( 0, 0, 2048 );//140 );//128 );
|
|
|
|
|
|
|
|
trace = G_Trace( midpos, min, max, end_trace, this, MASK_SOLID, "Player::ClearPathTo 2" );
|
|
|
|
if ( ( trace.fraction == 1 ) || ( trace.startsolid ) )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
return false;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
|
|
|
|
midpos = trace.endpos;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// Check if we're close enough
|
|
|
|
delta = midpos - pos;
|
|
|
|
return ( delta.length() < 32 );
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
EXPORT_FROM_DLL void Player::AddPathNode
|
1998-12-20 00:00:00 +00:00
|
|
|
(
|
1999-11-02 00:00:00 +00:00
|
|
|
Event *ev
|
1998-12-20 00:00:00 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( ai_createnodes->value )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
lastNode = new PathNode;
|
|
|
|
lastNode->Setup( worldorigin );
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
EXPORT_FROM_DLL void Player::AddPathNodes
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
{
|
|
|
|
StandardMovePath find;
|
|
|
|
|
|
|
|
if ( ai_createnodes->value && groundentity )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( !lastNode || !lastNode->CheckMove( worldorigin, mins, maxs ) ||
|
|
|
|
!ClearPathTo( lastNode->worldorigin ) )
|
|
|
|
{
|
|
|
|
gi.dprintf( "Can't see lastNode\n" );
|
|
|
|
lastNode = new PathNode;
|
|
|
|
lastNode->Setup( lastVisible );
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// so that we don't just keep putting nodes in the same place
|
|
|
|
lastVisible = worldorigin;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
nearestNode = PathManager.NearestNode( worldorigin );
|
|
|
|
if ( !nearestNode )
|
|
|
|
{
|
|
|
|
gi.dprintf( "Can't see NearestNode\n" );
|
|
|
|
lastNode = new PathNode;
|
|
|
|
lastNode->Setup( worldorigin );
|
|
|
|
lastVisible = worldorigin;
|
|
|
|
}
|
|
|
|
else if ( lastNode && ( !lastNode->CheckPath( nearestNode, mins, maxs )
|
|
|
|
|| !nearestNode->CheckPath( lastNode, mins, maxs ) ) )
|
|
|
|
{
|
|
|
|
gi.dprintf( "Nearest can't see last\n" );
|
|
|
|
lastNode = new PathNode;
|
|
|
|
lastNode->Setup( worldorigin );
|
|
|
|
lastVisible = worldorigin;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( !lastNode || ( lastNode->CheckMove( worldorigin, mins, maxs ) && ClearPathTo( lastNode->worldorigin ) ) )
|
|
|
|
{
|
|
|
|
lastVisible = worldorigin;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( nearestNode )
|
|
|
|
{
|
|
|
|
lastNode = nearestNode;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
//gi.dprintf( "Num Nodes %d\n", PathManager.NumNodes() );
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( searchTime <= level.time )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
nearestNode = PathManager.NearestNode( worldorigin );
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( path )
|
|
|
|
{
|
|
|
|
delete path;
|
|
|
|
path = NULL;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( ai_showpath->value )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( nearestNode )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( !goalNode )
|
|
|
|
{
|
|
|
|
goalNode = nearestNode;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
find.heuristic.setSize( size );
|
|
|
|
path = find.FindPath( nearestNode, goalNode );
|
|
|
|
}
|
|
|
|
else if ( ai_debugpath->value )
|
|
|
|
{
|
|
|
|
gi.dprintf( "%d : No nearest node\n", level.framenum );
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
searchTime = level.time + 0.1;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( ai_showpath->value )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( path )
|
|
|
|
{
|
|
|
|
path->DrawPath( 0, 0.7, 0, 0.1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( nearestNode )
|
|
|
|
{
|
|
|
|
G_DebugLine( nearestNode->worldorigin + "0 0 16", worldorigin + "0 0 16", 0, 0, 0.7, 1 );
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
EXPORT_FROM_DLL void Player::UpdateStats
|
1998-12-20 00:00:00 +00:00
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
Armor *armor;
|
|
|
|
int i;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// Current Ammo
|
|
|
|
if ( currentWeapon )
|
|
|
|
{
|
|
|
|
client->ps.stats[ STAT_AMMO ] = currentWeapon->AmmoAvailable();
|
|
|
|
client->ps.stats[ STAT_CLIPAMMO ] = currentWeapon->ClipAmmo();
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
else
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
client->ps.stats[ STAT_AMMO ] = 0;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// not used, so don't set to save net bandwidth
|
|
|
|
#if 0
|
|
|
|
// All ammo types
|
|
|
|
for( i = 0; i < NUM_AMMO_TYPES; i++ )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
Ammo *ammo;
|
|
|
|
|
|
|
|
assert( ammo_types[ i ] );
|
|
|
|
ammo = ( Ammo * )FindItem( ammo_types[ i ] );
|
|
|
|
if ( ammo )
|
|
|
|
{
|
|
|
|
client->ps.stats[ STAT_AMMO_BASE + i ] = ammo->Amount();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
client->ps.stats[ STAT_AMMO_BASE + i ] = 0;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
#endif
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
//
|
|
|
|
// Armor
|
|
|
|
//
|
|
|
|
client->ps.stats[ STAT_ARMOR ] = 0;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
for( i = 0; i < NUM_ARMOR_TYPES; i++ )
|
|
|
|
{
|
|
|
|
assert( armor_types[ i ] );
|
|
|
|
armor = ( Armor * )FindItem( armor_types[ i ] );
|
|
|
|
if ( armor )
|
|
|
|
{
|
|
|
|
client->ps.stats[ STAT_ARMOR_BASE + i ] = armor->Amount();
|
|
|
|
client->ps.stats[ STAT_ARMOR ] += armor->Amount();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
client->ps.stats[ STAT_ARMOR_BASE + i ] = 0;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// Average the armor into a single value
|
|
|
|
client->ps.stats[ STAT_ARMOR ] /= 3;
|
|
|
|
|
|
|
|
if ( currentWeapon )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
client->ps.stats[ STAT_CURRENT_WEAPON ] = currentWeapon->GetIconIndex();
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
else
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
client->ps.stats[ STAT_CURRENT_WEAPON ] = 0;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
//
|
|
|
|
// Weapon list
|
|
|
|
//
|
|
|
|
client->ps.stats[ STAT_WEAPONLIST ] = 0;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Inventory
|
|
|
|
//
|
|
|
|
if ( currentItem && ( !( flags & ( FL_SP_MUTANT | FL_MUTANT ) ) ) )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
InventoryItem *nextItem;
|
|
|
|
InventoryItem *prevItem;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
nextItem = ( InventoryItem * )NextItem( currentItem );
|
|
|
|
prevItem = ( InventoryItem * )PrevItem( currentItem );
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
client->ps.stats[ STAT_SELECTED_ICON ] = currentItem->GetIconIndex();
|
|
|
|
client->ps.stats[ STAT_SELECTED_NAME ] = currentItem->GetItemIndex();
|
|
|
|
client->ps.stats[ STAT_SELECTED_AMOUNT ] = currentItem->Amount();
|
|
|
|
client->ps.stats[ STAT_SELECTED_MODELINDEX ] = currentItem->edict->s.modelindex;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( prevItem )
|
|
|
|
client->ps.stats[ STAT_PREVIOUS_ICON ] = prevItem->GetIconIndex();
|
|
|
|
else
|
|
|
|
client->ps.stats[ STAT_PREVIOUS_ICON ] = 0;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( nextItem )
|
|
|
|
client->ps.stats[ STAT_NEXT_ICON ] = nextItem->GetIconIndex();
|
|
|
|
else
|
|
|
|
client->ps.stats[ STAT_NEXT_ICON ] = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
client->ps.stats[ STAT_SELECTED_ICON ] = 0;
|
|
|
|
client->ps.stats[ STAT_PREVIOUS_ICON ] = 0;
|
|
|
|
client->ps.stats[ STAT_NEXT_ICON ] = 0;
|
|
|
|
client->ps.stats[ STAT_SELECTED_AMOUNT ] = 0;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
//
|
|
|
|
// Health
|
|
|
|
//
|
|
|
|
if ( ( health < 1 ) && ( health > 0 ) )
|
|
|
|
client->ps.stats[ STAT_HEALTH ] = 1;
|
|
|
|
else
|
|
|
|
client->ps.stats[ STAT_HEALTH ] = health;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
//
|
|
|
|
// Frags
|
|
|
|
//
|
|
|
|
client->ps.stats[ STAT_FRAGS ] = client->resp.score;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( spectator )
|
|
|
|
{
|
|
|
|
client->ps.stats[ STAT_LAYOUTS ] = DRAW_SPECTATOR;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( !hidestats )
|
|
|
|
client->ps.stats[ STAT_LAYOUTS ] = DRAW_STATS;
|
|
|
|
else
|
|
|
|
client->ps.stats[ STAT_LAYOUTS ] = 0;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
//
|
|
|
|
// Overlays
|
|
|
|
//
|
|
|
|
if ( drawoverlay )
|
|
|
|
{
|
|
|
|
client->ps.stats[ STAT_LAYOUTS ] |= DRAW_OVERLAY;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
//
|
|
|
|
// Show scores in dealthmatch during intermission or if the client wants to see them
|
|
|
|
//
|
|
|
|
if ( deathmatch->value && ( level.intermissiontime || client->showinfo ) )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
client->ps.stats[ STAT_LAYOUTS ] |= DRAW_SCORES;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
//
|
|
|
|
// Powerups timer
|
|
|
|
//
|
|
|
|
if ( poweruptimer > 0 )
|
|
|
|
{
|
|
|
|
client->ps.stats[ STAT_POWERUPTIMER ] = poweruptimer;
|
|
|
|
client->ps.stats[ STAT_POWERUPTYPE ] = poweruptype;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
client->ps.stats[ STAT_POWERUPTIMER ] = 0;
|
|
|
|
client->ps.stats[ STAT_POWERUPTYPE ] = 0;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
//
|
|
|
|
// Mission Computer
|
|
|
|
//
|
|
|
|
if ( client->showinfo && !deathmatch->value )
|
|
|
|
{
|
|
|
|
client->ps.stats[ STAT_LAYOUTS ] |= DRAW_MISSIONCPU;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
//
|
|
|
|
// Clear out the exit sign
|
|
|
|
// if we are in the trigger_exit field, than this will constantly be set
|
|
|
|
// so this will clear it out on subsequent calls to UpdateStats
|
|
|
|
//
|
|
|
|
if ( client->ps.stats[ STAT_EXITSIGN ] > 0 )
|
|
|
|
{
|
|
|
|
client->ps.stats[ STAT_EXITSIGN ]--;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( ctf->value )
|
|
|
|
CTF_UpdateStats( this );
|
|
|
|
//
|
|
|
|
// if the player has not joined a team, then update the number of players
|
|
|
|
// or if the scoreboard is up, update it
|
|
|
|
//
|
|
|
|
if ( !( level.framenum & 31 ) )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( ctf->value && client->resp.ctf_team == CTF_NOTEAM )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
CTF_UpdateNumberOfPlayers();
|
|
|
|
}
|
|
|
|
else if ( client->showinfo && deathmatch->value && !( level.framenum & 31 ) )
|
|
|
|
{
|
|
|
|
G_DeathmatchScoreboardMessage( this, enemy );
|
|
|
|
gi.unicast( edict, false );
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
|
|
|
|
EXPORT_FROM_DLL void Player::UpdateMusic
|
1998-12-20 00:00:00 +00:00
|
|
|
(
|
1999-11-02 00:00:00 +00:00
|
|
|
void
|
1998-12-20 00:00:00 +00:00
|
|
|
)
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( music_forced )
|
|
|
|
{
|
|
|
|
client->ps.current_music_mood = music_current_mood;
|
|
|
|
client->ps.fallback_music_mood = music_fallback_mood;
|
|
|
|
}
|
|
|
|
else if ( action_level > 30 )
|
|
|
|
{
|
|
|
|
music_current_mood = mood_normal;
|
|
|
|
music_fallback_mood = mood_normal;
|
|
|
|
client->ps.current_music_mood = mood_action;
|
|
|
|
client->ps.fallback_music_mood = mood_normal;
|
|
|
|
}
|
|
|
|
else if ( ( action_level < 15 ) && ( client->ps.current_music_mood == mood_action ) )
|
|
|
|
{
|
|
|
|
music_current_mood = mood_normal;
|
|
|
|
music_fallback_mood = mood_normal;
|
|
|
|
client->ps.current_music_mood = music_current_mood;
|
|
|
|
client->ps.fallback_music_mood = music_fallback_mood;
|
|
|
|
}
|
|
|
|
else if ( client->ps.current_music_mood != mood_action )
|
|
|
|
{
|
|
|
|
client->ps.current_music_mood = music_current_mood;
|
|
|
|
client->ps.fallback_music_mood = music_fallback_mood;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if (action_level > 0)
|
|
|
|
{
|
|
|
|
action_level -= 0.2f;
|
|
|
|
if (action_level > 80)
|
|
|
|
action_level = 80;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
action_level = 0;
|
|
|
|
|
|
|
|
//
|
|
|
|
// set the music
|
|
|
|
// naturally decay the action level
|
|
|
|
//
|
|
|
|
if (s_debugmusic->value)
|
|
|
|
{
|
|
|
|
warning("DebugMusic","%s's action_level = %4.2f\n", client->pers.netname, action_level);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
EndFrame
|
|
|
|
|
|
|
|
Called for each player at the end of the server frame
|
|
|
|
and right after spawning
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
EXPORT_FROM_DLL void Player::EndFrame
|
1998-12-20 00:00:00 +00:00
|
|
|
(
|
1999-11-02 00:00:00 +00:00
|
|
|
Event *ev
|
1998-12-20 00:00:00 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
FinishMove();
|
|
|
|
UpdateStats();
|
|
|
|
UpdateMusic();
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// set the crouch flag
|
|
|
|
if ( client->ps.pmove.pm_flags & PMF_DUCKED )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
edict->s.effects |= EF_CROUCH;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
edict->s.effects &= ~EF_CROUCH;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( movieCamera != CinematicCamera )
|
|
|
|
{
|
|
|
|
if ( movieCamera && movieCamera->isSubclassOf( SecurityCamera ) )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
movieCamera->edict->s.renderfx &= ~RF_DONTDRAW;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
movieCamera = CinematicCamera;
|
|
|
|
if ( movieCamera )
|
|
|
|
{
|
|
|
|
Entity * ent;
|
|
|
|
Camera * cam;
|
|
|
|
SetViewMode( CAMERA_VIEW, movieCamera );
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( movieCamera->isSubclassOf( Camera ) )
|
|
|
|
{
|
|
|
|
ent = movieCamera;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
cam = ( Camera * )ent;
|
|
|
|
if ( cam->Overlay().length() )
|
|
|
|
{
|
|
|
|
SendOverlay( this, cam->Overlay() );
|
|
|
|
drawoverlay = true;
|
|
|
|
hidestats = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
drawoverlay = false;
|
|
|
|
hidestats = false;
|
|
|
|
SetViewMode( defaultViewMode );
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( ( viewmode == THIRD_PERSON ) && ( zoom_mode == ZOOMED_IN ) )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
SetCameraEntity( this );
|
|
|
|
if ( crosshair )
|
|
|
|
{
|
|
|
|
crosshair->hideModel();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( ( viewmode == THIRD_PERSON ) && ( gravaxis ) )
|
|
|
|
{
|
|
|
|
SetCameraEntity( this );
|
|
|
|
if ( crosshair )
|
|
|
|
{
|
|
|
|
crosshair->hideModel();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( crosshair )
|
|
|
|
{
|
|
|
|
crosshair->showModel();
|
|
|
|
}
|
|
|
|
assert( watchCamera );
|
|
|
|
if ( !watchCamera )
|
|
|
|
{
|
|
|
|
// fix it in release
|
|
|
|
watchCamera = this;
|
|
|
|
}
|
|
|
|
SetCameraEntity( watchCamera );
|
|
|
|
}
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
EXPORT_FROM_DLL void Player::ShowInfo
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
{
|
|
|
|
client->showinfo = !client->showinfo;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// CTF - If ctf and client hasn't joined a team yet, make them open the join menu
|
|
|
|
if (ctf->value && client->resp.ctf_team == CTF_NOTEAM)
|
|
|
|
{
|
|
|
|
CTF_OpenJoinMenu();
|
|
|
|
return;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( deathmatch->value && client->showinfo )
|
|
|
|
{
|
|
|
|
G_DeathmatchScoreboard( this );
|
|
|
|
return;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::ReadyToFire
|
1998-12-20 00:00:00 +00:00
|
|
|
(
|
1999-11-02 00:00:00 +00:00
|
|
|
Event *ev
|
1998-12-20 00:00:00 +00:00
|
|
|
)
|
1999-11-02 00:00:00 +00:00
|
|
|
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
int frame;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
frame = ev->GetInteger( 1 );
|
|
|
|
if ( ( buttons & BUTTON_ATTACK ) && WeaponReady() )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
NextFrame( frame );
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Player::WaitingToFire
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
int frame;
|
|
|
|
|
|
|
|
frame = ev->GetInteger( 1 );
|
|
|
|
if ( ( buttons & BUTTON_ATTACK ) && !WeaponReady() )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
NextFrame( frame );
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::DoneFiring
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
firing = false;
|
|
|
|
}
|
1999-03-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::AddItemToFloatingInventory
|
|
|
|
(
|
|
|
|
Item *item
|
|
|
|
)
|
1999-03-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
{
|
|
|
|
floating_inventory.AddObject( item->entnum );
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::SendFloatingInventory
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
{
|
|
|
|
int i,n;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// Send over the floating inventory icons
|
|
|
|
n = floating_inventory.NumObjects();
|
|
|
|
assert( n < MAX_ITEMS );
|
|
|
|
gi.WriteByte( svc_inventory );
|
|
|
|
gi.WriteShort( n );
|
|
|
|
for( i=1; i<=n; i++)
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
Item *item;
|
|
|
|
item = ( Item * )G_GetEntity( floating_inventory.ObjectAt( i ) );
|
|
|
|
assert( item );
|
|
|
|
if ( item )
|
|
|
|
{
|
|
|
|
gi.WriteShort( item->GetIconIndex() );
|
|
|
|
gi.WriteShort( item->Amount() );
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
gi.unicast( this->edict, false );
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::ClearFloatingInventory
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
{
|
|
|
|
// Clear the items
|
|
|
|
floating_inventory.ClearObjectList();
|
|
|
|
// Clear the owner;
|
|
|
|
floating_owner = NULL;
|
|
|
|
// Clear the client's list
|
|
|
|
SendFloatingInventory();
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::SetFloatingOwner
|
|
|
|
(
|
|
|
|
Sentient *deceased_owner
|
|
|
|
)
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
{
|
|
|
|
floating_owner = deceased_owner;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
Sentient *Player::GetFloatingOwner
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
{
|
|
|
|
return floating_owner;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::PickupFloatingInventory
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
{
|
|
|
|
int i,n;
|
|
|
|
Event *event;
|
|
|
|
qboolean inventory_changed = false;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// Make sure there is an inventory to pickup
|
|
|
|
if (!floating_owner)
|
|
|
|
return;
|
|
|
|
|
|
|
|
n = floating_inventory.NumObjects();
|
|
|
|
|
|
|
|
if (!n)
|
|
|
|
return;
|
|
|
|
|
|
|
|
assert( n < MAX_ITEMS );
|
|
|
|
|
|
|
|
for( i=n; i>0; i--)
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
Item *item;
|
|
|
|
item = ( Item * )G_GetEntity( floating_inventory.ObjectAt( i ) );
|
|
|
|
assert( item );
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// Check to see if we want to pick this up
|
|
|
|
if ( !item->Pickupable( this ) )
|
|
|
|
continue;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// Remove it from the dead body
|
|
|
|
item->Drop();
|
|
|
|
|
|
|
|
// Add item to player's inventory
|
|
|
|
event = new Event( EV_Item_Pickup );
|
|
|
|
event->AddEntity( this );
|
|
|
|
item->ProcessEvent( event );
|
|
|
|
item->ProcessEvent( EV_Trigger_StartThread );
|
|
|
|
|
|
|
|
// Remove it from the floating inventory
|
|
|
|
floating_inventory.RemoveObjectAt( i );
|
|
|
|
|
|
|
|
inventory_changed = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( inventory_changed )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
// Update the client if the inventory changed
|
|
|
|
SendFloatingInventory();
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
// Make this guy useless in 60 seconds
|
|
|
|
Event *re;
|
|
|
|
re = new Event( "remove_useless" );
|
|
|
|
floating_owner->PostEvent( re, 60 );
|
|
|
|
|
|
|
|
RandomSound("snd_refusepickup");
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( !floating_inventory.NumObjects() )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
Event *re;
|
|
|
|
re = new Event( "remove_useless" );
|
|
|
|
floating_owner->ProcessEvent( re );
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::ChangeSpectator
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
{
|
|
|
|
int num;
|
|
|
|
edict_t *cl_ent;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
currentCameraTarget = ( currentCameraTarget + 1 ) % game.maxclients;
|
|
|
|
cl_ent = g_edicts + 1 + currentCameraTarget;
|
|
|
|
|
|
|
|
num = 0;
|
|
|
|
while
|
|
|
|
(
|
|
|
|
!cl_ent->inuse ||
|
|
|
|
!cl_ent->entity ||
|
|
|
|
( !cl_ent->entity->client ) ||
|
|
|
|
( ( ( Player * )cl_ent->entity )->spectator )
|
|
|
|
)
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( num == game.maxclients )
|
|
|
|
break;
|
|
|
|
currentCameraTarget = ( currentCameraTarget + 1 ) % game.maxclients;
|
|
|
|
cl_ent = g_edicts + 1 + currentCameraTarget;
|
|
|
|
num++;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( !cl_ent->inuse )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
SetViewMode( FIRST_PERSON );
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
SetViewMode( SPECTATOR );
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
CTF_UpdateNumberOfPlayers();
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::TestThread
|
|
|
|
(
|
1998-12-20 00:00:00 +00:00
|
|
|
Event *ev
|
|
|
|
)
|
1999-11-02 00:00:00 +00:00
|
|
|
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
const char *scriptfile;
|
|
|
|
const char *label = NULL;
|
|
|
|
ScriptThread * thread;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( ev->NumArgs() < 1 )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
gi.cprintf( edict, PRINT_HIGH, "Syntax: testthread scriptfile <label>.\n" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
scriptfile = ev->GetString( 1 );
|
|
|
|
if ( ev->NumArgs() > 1 )
|
|
|
|
label = ev->GetString( 2 );
|
|
|
|
thread = Director.CreateThread( scriptfile, LEVEL_SCRIPT, label );
|
|
|
|
if ( thread )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
// start right away
|
|
|
|
thread->Start( -1 );
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::GibEvent
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
{
|
|
|
|
qboolean hidemodel;
|
|
|
|
|
|
|
|
hidemodel = !ev->GetInteger( 1 );
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( sv_gibs->value && !parentmode->value )
|
|
|
|
{
|
|
|
|
if ( hidemodel )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
gibbed = true;
|
|
|
|
takedamage = DAMAGE_NO;
|
|
|
|
setSolidType( SOLID_NOT );
|
|
|
|
hideModel();
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
CreateGibs( this, health, 0.75f, 3 );
|
|
|
|
}
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::GotKill
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
Entity *victim;
|
|
|
|
Entity *inflictor;
|
|
|
|
str location;
|
|
|
|
float damage;
|
|
|
|
int meansofdeath;
|
|
|
|
qboolean gibbed;
|
|
|
|
|
|
|
|
if ( deathmatch->value )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
return;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
|
|
|
|
victim = ev->GetEntity( 1 );
|
|
|
|
damage = ev->GetInteger( 2 );
|
|
|
|
inflictor = ev->GetEntity( 3 );
|
|
|
|
location = ev->GetString( 4 );
|
|
|
|
meansofdeath = ev->GetInteger( 5 );
|
|
|
|
gibbed = ev->GetInteger( 6 );
|
|
|
|
|
|
|
|
if ( victim->isSubclassOf( Actor ) )
|
|
|
|
{
|
|
|
|
Actor * act;
|
|
|
|
act = ( Actor * )victim;
|
|
|
|
switch ( act->actortype )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
case IS_ENEMY:
|
|
|
|
case IS_MONSTER:
|
|
|
|
if ( gibbed )
|
|
|
|
{
|
|
|
|
if ( G_Random( 100 ) < 15 )
|
|
|
|
{
|
|
|
|
RandomSound( "snd_gibfest", 1, CHAN_VOICE );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( G_Random( 100 ) < 15 )
|
|
|
|
{
|
|
|
|
RandomSound( "snd_taunt", 1, CHAN_VOICE );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IS_FRIEND:
|
|
|
|
case IS_CIVILIAN:
|
|
|
|
if (
|
|
|
|
( !( flags & FL_MUTANT ) ) &&
|
|
|
|
( !deathmatch->value ) &&
|
|
|
|
( !level.no_jc )
|
|
|
|
)
|
|
|
|
{
|
|
|
|
char name[ 128 ];
|
|
|
|
int num;
|
|
|
|
|
|
|
|
num = (int)G_Random( 4 ) + 1;
|
|
|
|
sprintf( name, "global/universal_script.scr::blade_kills_innocent%d", num );
|
|
|
|
ExecuteThread( name, true );
|
|
|
|
}
|
|
|
|
break;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
}
|
|
|
|
if ( victim->isClient() )
|
|
|
|
{
|
|
|
|
if ( gibbed )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( G_Random( 100 ) < 15 )
|
|
|
|
{
|
|
|
|
RandomSound( "snd_gibfest", 1, CHAN_VOICE );
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
else if (
|
|
|
|
( G_Random( 100 ) < 15 )
|
|
|
|
)
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
RandomSound( "snd_taunt", 1, CHAN_VOICE );
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::SetPowerupTimer
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
Event *event;
|
|
|
|
|
|
|
|
poweruptimer = ev->GetInteger( 1 );
|
|
|
|
poweruptype = ev->GetInteger( 2 );
|
|
|
|
event = new Event( EV_Player_UpdatePowerupTimer );
|
|
|
|
PostEvent ( event, 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::UpdatePowerupTimer
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
poweruptimer -= 1;
|
|
|
|
|
|
|
|
if (poweruptimer > 0)
|
|
|
|
PostEvent( ev, 1 );
|
|
|
|
else
|
|
|
|
poweruptype = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
viewmode_t Player::ViewMode
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
return viewmode;
|
|
|
|
}
|
|
|
|
|
|
|
|
Camera * Player::CurrentCamera
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
Entity * ent;
|
|
|
|
ent = CinematicCamera;
|
|
|
|
return ( Camera * )ent;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::SetCamera
|
1998-12-20 00:00:00 +00:00
|
|
|
(
|
1999-11-02 00:00:00 +00:00
|
|
|
Entity *ent
|
1998-12-20 00:00:00 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
CinematicCamera = ent;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::WhatIs
|
1998-12-20 00:00:00 +00:00
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
1999-11-02 00:00:00 +00:00
|
|
|
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
int num;
|
|
|
|
Entity *ent;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( ev->NumArgs() != 1 )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
gi.cprintf( edict, PRINT_HIGH, "Usage: whatis <entity number>\n");
|
|
|
|
return;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
num = ev->GetInteger( 1 );
|
|
|
|
if ( ( num < 0 ) || ( num >= globals.max_edicts ) )
|
|
|
|
{
|
|
|
|
gi.cprintf( edict, PRINT_HIGH, "Value out of range. Possible values range from 0 to %d.\n", globals.max_edicts );
|
|
|
|
return;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
ent = G_GetEntity( num );
|
|
|
|
if ( !ent )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
gi.cprintf( edict, PRINT_HIGH, "Entity not in use.\n" );
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
const char * animname;
|
|
|
|
int master, own;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
animname = NULL;
|
|
|
|
if ( gi.IsModel( ent->edict->s.modelindex ) )
|
|
|
|
animname = gi.Anim_NameForNum( ent->edict->s.modelindex, ent->edict->s.anim );
|
|
|
|
if ( !animname )
|
|
|
|
animname = "( N/A )";
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( ent->bindmaster )
|
|
|
|
master = ent->bindmaster->entnum;
|
|
|
|
else
|
|
|
|
master = 0;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( ent->edict->owner )
|
|
|
|
own = ent->edict->owner - g_edicts;
|
|
|
|
else
|
|
|
|
own = 0;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
gi.cprintf( edict, PRINT_HIGH,
|
|
|
|
"Entity # : %d\n"
|
|
|
|
"Class ID : %s\n"
|
|
|
|
"Classname : %s\n"
|
|
|
|
"Targetname : %s\n"
|
|
|
|
"Modelname : %s\n"
|
|
|
|
"Animname : %s\n"
|
|
|
|
"Origin : ( %f, %f, %f )\n"
|
|
|
|
"Bounds : Mins( %.2f, %.2f, %.2f ) Maxs( %.2f, %.2f, %.2f )\n"
|
|
|
|
"Velocity : ( %f, %f, %f )\n"
|
|
|
|
"SVFLAGS : %x\n"
|
|
|
|
"Movetype : %i\n"
|
|
|
|
"Solidtype : %i\n"
|
|
|
|
"Parent : %i\n"
|
|
|
|
"Health : %.1f\n"
|
|
|
|
"Max Health : %.1f\n"
|
|
|
|
"BindMaster : %i\n"
|
|
|
|
"Edict Owner: %i\n",
|
|
|
|
num,
|
|
|
|
ent->getClassID(),
|
|
|
|
ent->getClassname(),
|
|
|
|
ent->TargetName(),
|
|
|
|
ent->model.c_str(),
|
|
|
|
animname,
|
|
|
|
ent->worldorigin.x, ent->worldorigin.y, ent->worldorigin.z,
|
|
|
|
ent->mins.x, ent->mins.y, ent->mins.z, ent->maxs.x, ent->maxs.y, ent->maxs.z,
|
|
|
|
ent->velocity.x, ent->velocity.y, ent->velocity.z,
|
|
|
|
ent->edict->svflags,
|
|
|
|
ent->movetype,
|
|
|
|
ent->edict->solid,
|
|
|
|
ent->edict->s.parent,
|
|
|
|
ent->health,
|
|
|
|
ent->max_health,
|
|
|
|
master,
|
|
|
|
own
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::KillEnt
|
|
|
|
(
|
|
|
|
Event * ev
|
|
|
|
)
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
int num;
|
|
|
|
Entity *ent;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( ev->NumArgs() != 1 )
|
|
|
|
{
|
|
|
|
gi.cprintf( edict, PRINT_HIGH, "Usage: killent <entity number>\n");
|
|
|
|
return;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
num = ev->GetInteger( 1 );
|
|
|
|
if ( ( num < 0 ) || ( num >= globals.max_edicts ) )
|
|
|
|
{
|
|
|
|
gi.cprintf( edict, PRINT_HIGH, "Value out of range. Possible values range from 0 to %d.\n", globals.max_edicts );
|
|
|
|
return;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
ent = G_GetEntity( num );
|
|
|
|
ent->Damage( world, world, ent->max_health + 25, worldorigin, vec_zero, vec_zero, 0, 0, 0, -1, -1, 1 );
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::RemoveEnt
|
|
|
|
(
|
|
|
|
Event * ev
|
1998-12-20 00:00:00 +00:00
|
|
|
)
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
int num;
|
|
|
|
Entity *ent;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( ev->NumArgs() != 1 )
|
|
|
|
{
|
|
|
|
gi.cprintf( edict, PRINT_HIGH, "Usage: removeent <entity number>\n");
|
|
|
|
return;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
num = ev->GetInteger( 1 );
|
|
|
|
if ( ( num < 0 ) || ( num >= globals.max_edicts ) )
|
|
|
|
{
|
|
|
|
gi.cprintf( edict, PRINT_HIGH, "Value out of range. Possible values range from 0 to %d.\n", globals.max_edicts );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ent = G_GetEntity( num );
|
|
|
|
ent->PostEvent( Event( EV_Remove ), 0 );
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::KillClass
|
|
|
|
(
|
|
|
|
Event * ev
|
1998-12-20 00:00:00 +00:00
|
|
|
)
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
int except;
|
|
|
|
str classname;
|
|
|
|
edict_t * from;
|
|
|
|
Entity *ent;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( ev->NumArgs() < 1 )
|
|
|
|
{
|
|
|
|
gi.cprintf( edict, PRINT_HIGH, "Usage: killclass <classname> [except entity number]\n");
|
|
|
|
return;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
classname = ev->GetString( 1 );
|
|
|
|
|
|
|
|
except = 0;
|
|
|
|
if ( ev->NumArgs() == 2 )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
except = ev->GetInteger( 1 );
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
for ( from = this->edict + 1; from < &g_edicts[ globals.num_edicts ]; from++ )
|
|
|
|
{
|
|
|
|
if ( !from->inuse )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
assert( from->entity );
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
ent = from->entity;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( ent->entnum == except )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( ent->inheritsFrom( classname.c_str() ) )
|
|
|
|
{
|
|
|
|
ent->Damage( world, world, ent->max_health + 25, worldorigin, vec_zero, vec_zero, 0, 0, 0, -1, -1, 1 );
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::RemoveClass
|
|
|
|
(
|
|
|
|
Event * ev
|
|
|
|
)
|
|
|
|
{
|
|
|
|
int except;
|
|
|
|
str classname;
|
|
|
|
edict_t * from;
|
|
|
|
Entity *ent;
|
|
|
|
|
|
|
|
if ( ev->NumArgs() < 1 )
|
|
|
|
{
|
|
|
|
gi.cprintf( edict, PRINT_HIGH, "Usage: removeclass <classname> [except entity number]\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
classname = ev->GetString( 1 );
|
|
|
|
|
|
|
|
except = 0;
|
|
|
|
if ( ev->NumArgs() == 2 )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
except = ev->GetInteger( 1 );
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
for ( from = this->edict + 1; from < &g_edicts[ globals.num_edicts ]; from++ )
|
|
|
|
{
|
|
|
|
if ( !from->inuse )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
assert( from->entity );
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
ent = from->entity;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( ent->entnum == except )
|
|
|
|
continue;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( ent->inheritsFrom( classname.c_str() ) )
|
|
|
|
{
|
|
|
|
ent->PostEvent( Event( EV_Remove ), 0 );
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::ActorInfo
|
|
|
|
(
|
1998-12-20 00:00:00 +00:00
|
|
|
Event *ev
|
|
|
|
)
|
1999-11-02 00:00:00 +00:00
|
|
|
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
int num;
|
|
|
|
Entity *ent;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( ev->NumArgs() != 1 )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
gi.cprintf( edict, PRINT_HIGH, "Usage: actorinfo <entity number>\n");
|
1998-12-20 00:00:00 +00:00
|
|
|
return;
|
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
|
|
|
|
num = ev->GetInteger( 1 );
|
|
|
|
if ( ( num < 0 ) || ( num >= globals.max_edicts ) )
|
|
|
|
{
|
|
|
|
gi.cprintf( edict, PRINT_HIGH, "Value out of range. Possible values range from 0 to %d.\n", globals.max_edicts );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ent = G_GetEntity( num );
|
|
|
|
if ( !ent || !ent->isSubclassOf( Actor ) )
|
|
|
|
{
|
|
|
|
gi.cprintf( edict, PRINT_HIGH, "Entity not an Actor.\n" );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
( ( Actor * )ent )->ShowInfo();
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::Taunt
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
Event * event;
|
|
|
|
str taunt;
|
|
|
|
|
|
|
|
if ( level.time < lastTauntTime )
|
|
|
|
return;
|
|
|
|
|
|
|
|
taunt = str("snd_taunt") + str( ev->GetString( 1 ) );
|
|
|
|
event = new Event( EV_VoiceSound );
|
|
|
|
event->AddString( taunt );
|
|
|
|
event->AddFloat( 1 );
|
|
|
|
ProcessEvent( event );
|
|
|
|
lastTauntTime = level.time + TAUNT_TIME;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::DrawOverlay
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
drawoverlay = true;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::HideOverlay
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
{
|
|
|
|
drawoverlay = false;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::DrawStats
|
1998-12-20 00:00:00 +00:00
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
1999-11-02 00:00:00 +00:00
|
|
|
{
|
|
|
|
hidestats = false;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::HideStats
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
{
|
|
|
|
hidestats = true;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::ChangeMusic
|
|
|
|
(
|
|
|
|
const char * current,
|
|
|
|
const char * fallback,
|
|
|
|
qboolean force
|
|
|
|
)
|
|
|
|
{
|
|
|
|
int current_mood_num;
|
|
|
|
int fallback_mood_num;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
music_forced = force;
|
|
|
|
if ( str( current ) == str( "normal" ) )
|
|
|
|
{
|
|
|
|
music_forced = false;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( current )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
current_mood_num = MusicMood_NameToNum( current );
|
|
|
|
if ( current_mood_num < 0 )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
gi.dprintf( "current music mood %s not found", current );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
music_current_mood = current_mood_num;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( fallback )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
fallback_mood_num = MusicMood_NameToNum( fallback );
|
|
|
|
if ( fallback_mood_num < 0 )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
gi.dprintf( "fallback music mood %s not found", fallback );
|
|
|
|
fallback = NULL;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
else
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
music_fallback_mood = fallback_mood_num;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::SetFlashColor
|
1998-12-20 00:00:00 +00:00
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( flash_color[3] == 0 )
|
|
|
|
{
|
|
|
|
flash_color[0] = flash_color[1] = flash_color[2] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
flash_color[0] += ev->GetFloat( 1 );
|
|
|
|
flash_color[1] += ev->GetFloat( 2 );
|
|
|
|
flash_color[2] += ev->GetFloat( 3 );
|
|
|
|
flash_color[3] += ev->GetFloat( 4 );
|
|
|
|
|
|
|
|
if ( flash_color[0] > 1 )
|
|
|
|
flash_color[0] = 1;
|
|
|
|
if ( flash_color[1] > 1 )
|
|
|
|
flash_color[1] = 1;
|
|
|
|
if ( flash_color[2] > 1 )
|
|
|
|
flash_color[2] = 1;
|
|
|
|
if ( flash_color[3] > 1 )
|
|
|
|
flash_color[3] = 1;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::ClearFlashColor
|
1998-12-20 00:00:00 +00:00
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
flash_color[0] = 0;
|
|
|
|
flash_color[1] = 0;
|
|
|
|
flash_color[2] = 0;
|
|
|
|
flash_color[3] = 0;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::GiveOxygen
|
1998-12-20 00:00:00 +00:00
|
|
|
(
|
1999-11-02 00:00:00 +00:00
|
|
|
float time
|
1998-12-20 00:00:00 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
air_finished = level.time + time;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::WeaponUse
|
1998-12-20 00:00:00 +00:00
|
|
|
(
|
1999-11-02 00:00:00 +00:00
|
|
|
Event *ev
|
1998-12-20 00:00:00 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
Event *event;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// CTF: If the current weapon has alternate fire, change the mode to
|
|
|
|
// secondary, and fire it.
|
|
|
|
if ( currentWeapon && currentWeapon->AlternateFire() )
|
|
|
|
{
|
|
|
|
currentWeapon->SetSecondaryMode();
|
|
|
|
if ( currentWeapon->ReadyToFire() && currentWeapon->HasAmmo() )
|
|
|
|
{
|
|
|
|
currentWeapon->Fire();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
currentWeapon->SetPrimaryMode();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( currentWeapon && !currentWeapon->ChangingWeapons() )
|
|
|
|
{
|
|
|
|
event = new Event( EV_Weapon_SecondaryUse );
|
|
|
|
event->AddEntity( this );
|
|
|
|
currentWeapon->ProcessEvent( event );
|
1998-12-20 00:00:00 +00:00
|
|
|
return;
|
1999-11-02 00:00:00 +00:00
|
|
|
}
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::Human
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
{
|
|
|
|
int playernum;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
flags &= ~FL_SP_MUTANT;
|
|
|
|
flags &= ~FL_MUTANT;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
setModel( savemodel.c_str() );
|
|
|
|
SetAnim( "idle" );
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
strcpy( client->pers.model, savemodel.c_str() );
|
|
|
|
strcpy( client->pers.skin, saveskin.c_str() );
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
playernum = edict-g_edicts-1;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// combine name, skin and model into a configstring
|
|
|
|
gi.configstring (CS_PLAYERSKINS+playernum, va("%s\\%s\\%s",
|
|
|
|
client->pers.netname,
|
|
|
|
client->pers.model,
|
|
|
|
client->pers.skin));
|
|
|
|
|
|
|
|
takeWeapon( "MutantHands" );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::Mutate
|
|
|
|
(
|
|
|
|
Event *ev
|
1998-12-20 00:00:00 +00:00
|
|
|
)
|
1999-11-02 00:00:00 +00:00
|
|
|
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
int playernum;
|
|
|
|
Weapon *mutanthands;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
flags |= FL_SP_MUTANT;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
setModel( "manumit_pl.def" );
|
|
|
|
SetAnim( "idle" );
|
|
|
|
|
|
|
|
savemodel = client->pers.model;
|
|
|
|
saveskin = client->pers.skin;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
strcpy( client->pers.model, "manumit_pl.def" );
|
|
|
|
|
|
|
|
playernum = edict-g_edicts-1;
|
|
|
|
|
|
|
|
|
|
|
|
// combine name, skin and model into a configstring
|
|
|
|
gi.configstring (CS_PLAYERSKINS+playernum,
|
|
|
|
va("%s\\%s\\%s",
|
|
|
|
client->pers.netname,
|
|
|
|
client->pers.model,
|
|
|
|
client->pers.skin)
|
|
|
|
);
|
|
|
|
|
|
|
|
// Give the mutanthands weapon. - Force it.
|
|
|
|
mutanthands = giveWeapon( "MutantHands" );
|
|
|
|
ForceChangeWeapon( mutanthands );
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::SetSkin
|
|
|
|
(
|
|
|
|
Event *ev
|
1998-12-20 00:00:00 +00:00
|
|
|
)
|
1999-11-02 00:00:00 +00:00
|
|
|
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
int playernum;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
playernum = edict-g_edicts-1;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
strcpy( client->pers.skin, ev->GetString( 1 ) );
|
|
|
|
|
|
|
|
// combine name, skin and model into a configstring
|
|
|
|
gi.configstring( CS_PLAYERSKINS+playernum, va( "%s\\%s\\%s",
|
|
|
|
client->pers.netname,
|
|
|
|
client->pers.model,
|
|
|
|
client->pers.skin ) );
|
1998-12-20 00:00:00 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
|
|
|
|
void Player::CTF_JoinTeam
|
1998-12-20 00:00:00 +00:00
|
|
|
(
|
1999-11-02 00:00:00 +00:00
|
|
|
int desired_team
|
|
|
|
)
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
{
|
|
|
|
int playernum;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
//
|
|
|
|
// if he is in a vehicle
|
|
|
|
// get him out
|
|
|
|
//
|
|
|
|
if ( vehicle )
|
|
|
|
{
|
|
|
|
Event * event;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
event = new Event( EV_Use );
|
|
|
|
event->AddEntity( this );
|
|
|
|
vehicle->ProcessEvent( event );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( spectator )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
client->ps.stats[ STAT_LAYOUTS ] &= ~DRAW_SPECTATOR;
|
|
|
|
spectator = false;
|
|
|
|
takedamage = DAMAGE_YES;
|
|
|
|
setSolidType( SOLID_BBOX );
|
|
|
|
setMoveType( MOVETYPE_WALK );
|
|
|
|
defaultViewMode = FIRST_PERSON;
|
|
|
|
SetViewMode( FIRST_PERSON );
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// Drop flag, release grapple, drop inventory, and free weapons
|
|
|
|
CTF_DeadDropFlag();
|
|
|
|
CTF_DeadDropTech();
|
|
|
|
CTF_ReleaseGrapple();
|
|
|
|
DropInventoryItems();
|
|
|
|
FreeInventory();
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// reset score
|
|
|
|
client->resp.score = 0;
|
|
|
|
client->resp.ctf_team = desired_team;
|
|
|
|
client->resp.ctf_state = CTF_STATE_START;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// set the respawn time of the player
|
|
|
|
respawn_time = level.time;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
Init();
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// Update team, and put state to the starting state so player will respawn near his base
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// hold in place briefly
|
|
|
|
client->ps.pmove.pm_time = 50;
|
|
|
|
client->ps.pmove.pm_flags = PMF_TIME_TELEPORT;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
switch ( client->resp.ctf_team )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
case CTF_TEAM_HARDCORPS:
|
|
|
|
strcpy( client->pers.skin, ctf_hardcorps_skin->string );
|
|
|
|
break;
|
|
|
|
case CTF_TEAM_SINTEK:
|
|
|
|
strcpy( client->pers.skin, ctf_sintek_skin->string );
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// Player number
|
|
|
|
playernum = edict-g_edicts - 1;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// combine name, skin and model into a configstring
|
|
|
|
gi.configstring (CS_PLAYERSKINS+playernum, va("%s\\%s\\%s",
|
|
|
|
client->pers.netname,
|
|
|
|
client->pers.model,
|
|
|
|
client->pers.skin));
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::CTF_JoinTeamHardcorps
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
{
|
|
|
|
CTF_JoinTeam( CTF_TEAM_HARDCORPS );
|
|
|
|
gi.bprintf( PRINT_HIGH, "%s joined the %s team.\n",client->pers.netname, CTF_TeamName( client->resp.ctf_team ) );
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::CTF_JoinTeamSintek
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
{
|
|
|
|
CTF_JoinTeam( CTF_TEAM_SINTEK );
|
|
|
|
gi.bprintf( PRINT_HIGH, "%s joined the %s team.\n",client->pers.netname, CTF_TeamName( client->resp.ctf_team ) );
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::CTF_Team
|
1998-12-20 00:00:00 +00:00
|
|
|
(
|
1999-11-02 00:00:00 +00:00
|
|
|
Event *ev
|
1998-12-20 00:00:00 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
str team;
|
|
|
|
int desired_team;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( ev->NumArgs() == 0 )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
gi.cprintf( edict, PRINT_HIGH, "You are on the %s team.\n",
|
|
|
|
CTF_TeamName( client->resp.ctf_team ) );
|
1998-12-20 00:00:00 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
team = ev->GetString( 1 );
|
|
|
|
|
|
|
|
if ( ( !stricmp( team.c_str(), "hardcorps" ) ) || ( !stricmp( team.c_str(), "blue" ) ) )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
desired_team = CTF_TEAM_HARDCORPS;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
else if ( ( !stricmp( team.c_str(), "sintek" ) ) || ( !stricmp( team.c_str(), "red" ) ) )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
desired_team = CTF_TEAM_SINTEK;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
gi.cprintf(edict, PRINT_HIGH, "Unknown team %s.\n", team.c_str() );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( client->resp.ctf_team == desired_team )
|
|
|
|
{
|
|
|
|
gi.cprintf(edict, PRINT_HIGH, "You are already on the %s team.\n",
|
|
|
|
CTF_TeamName( client->resp.ctf_team ) );
|
|
|
|
return;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
|
|
|
|
CTF_JoinTeam( desired_team );
|
|
|
|
|
|
|
|
gi.bprintf( PRINT_HIGH, "%s changed to the %s team.\n",
|
|
|
|
client->pers.netname, CTF_TeamName( desired_team ) );
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::CTF_AssignTeam
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
{
|
|
|
|
edict_t *player;
|
|
|
|
int i;
|
|
|
|
int hardcorps_count = 0, sintek_count = 0;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
client->resp.ctf_state = CTF_STATE_START;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
for (i = 1; i <= maxclients->value; i++)
|
|
|
|
{
|
|
|
|
player = &g_edicts[i];
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( !player->inuse || player->client == this->client )
|
|
|
|
continue;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
switch ( player->client->resp.ctf_team )
|
|
|
|
{
|
|
|
|
case CTF_TEAM_HARDCORPS:
|
|
|
|
hardcorps_count++;
|
|
|
|
break;
|
|
|
|
case CTF_TEAM_SINTEK:
|
|
|
|
sintek_count++;
|
|
|
|
}
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( hardcorps_count < sintek_count )
|
|
|
|
CTF_JoinTeam( CTF_TEAM_HARDCORPS );
|
|
|
|
else if ( sintek_count < hardcorps_count )
|
|
|
|
CTF_JoinTeam( CTF_TEAM_SINTEK );
|
|
|
|
else if (rand() & 1)
|
|
|
|
CTF_JoinTeam( CTF_TEAM_HARDCORPS );
|
|
|
|
else
|
|
|
|
CTF_JoinTeam( CTF_TEAM_SINTEK );
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::InitCTF
|
1998-12-20 00:00:00 +00:00
|
|
|
(
|
1999-11-02 00:00:00 +00:00
|
|
|
void
|
1998-12-20 00:00:00 +00:00
|
|
|
)
|
1999-11-02 00:00:00 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
// This player has already joined a team
|
|
|
|
if ( client->resp.ctf_team != CTF_NOTEAM )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( ctf_forcejoin->value )
|
|
|
|
{
|
|
|
|
CTF_AssignTeam();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// start as 'spectator'
|
|
|
|
hideModel();
|
|
|
|
setSolidType( SOLID_NOT );
|
|
|
|
spectator = true;
|
|
|
|
takedamage = DAMAGE_NO;
|
|
|
|
CTF_DeadDropFlag();
|
|
|
|
CTF_DeadDropTech();
|
|
|
|
DropInventoryItems();
|
|
|
|
FreeInventory();
|
|
|
|
CTF_OpenJoinMenu();
|
|
|
|
}
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::CTF_UpdateNumberOfPlayers
|
1998-12-20 00:00:00 +00:00
|
|
|
(
|
1999-11-02 00:00:00 +00:00
|
|
|
void
|
1998-12-20 00:00:00 +00:00
|
|
|
)
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
{
|
|
|
|
char string[ 1400 ];
|
|
|
|
int num_hardcorps = 0, num_sintek = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if ( !ctf->value || client->resp.ctf_team != CTF_NOTEAM )
|
|
|
|
return;
|
|
|
|
|
|
|
|
for ( i = 0; i < maxclients->value; i++ )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( !g_edicts[i+1].inuse )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if ( game.clients[i].resp.ctf_team == CTF_TEAM_HARDCORPS )
|
|
|
|
num_hardcorps++;
|
|
|
|
else if ( game.clients[i].resp.ctf_team == CTF_TEAM_SINTEK )
|
|
|
|
num_sintek++;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
|
|
|
|
// Add in an overlay that shows the number of players on each team so far.
|
|
|
|
sprintf( string,
|
|
|
|
"jcx yb 24 string \"Team Hardcorps: %d players Score: %d\""
|
|
|
|
"jcx yb 16 string \"Team Sintek: %d players Score: %d\"",
|
|
|
|
num_hardcorps, ctfgame.team_hardcorps, num_sintek, ctfgame.team_sintek );
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( spectator )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
char entry[ 1024 ];
|
|
|
|
|
|
|
|
if ( viewmode == FIRST_PERSON )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
gi.WriteByte (svc_layout);
|
|
|
|
gi.WriteString ( va( "jcx jb hstring 0 0 1 \"SPECTATOR MODE\" %s ", string ) );
|
|
|
|
gi.unicast (edict, true);
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
else if ( viewmode == SPECTATOR )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
edict_t * cl_ent;
|
|
|
|
|
|
|
|
cl_ent = g_edicts + 1 + currentCameraTarget;
|
|
|
|
if ( cl_ent && cl_ent->entity && cl_ent->entity->client )
|
|
|
|
{
|
|
|
|
Com_sprintf( entry, sizeof( entry ),
|
|
|
|
"client %i %i %i %i %i %i ",
|
|
|
|
100, 176, currentCameraTarget, cl_ent->entity->client->resp.score, cl_ent->entity->client->ping, ( level.framenum - cl_ent->entity->client->resp.enterframe ) / 600 );
|
|
|
|
gi.WriteByte (svc_layout);
|
|
|
|
gi.WriteString ( va( "jcx jb hstring 0 0 1 \"SPECTATOR MODE\" %s %s ", entry, string ) );
|
|
|
|
gi.unicast (edict, true);
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
return;
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
else
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
gi.WriteByte( svc_layout );
|
|
|
|
gi.WriteString( string );
|
|
|
|
gi.unicast( edict, true );
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
1999-11-02 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Player::CTF_OpenJoinMenu
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
// update the number of players
|
|
|
|
CTF_UpdateNumberOfPlayers();
|
|
|
|
|
|
|
|
// Load up the CTF menu so the player can choose which team.
|
|
|
|
gi.WriteByte( svc_stufftext );
|
|
|
|
gi.WriteString( "menu_load ctf.mnu; menu_generic\n" );
|
|
|
|
gi.unicast( edict, true );
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::CTF_DropTech
|
1998-12-20 00:00:00 +00:00
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
CTF_Tech *tech;
|
|
|
|
|
|
|
|
if ( tech = ( CTF_Tech * )HasItemOfSuperclass( "CTF_Tech" ) )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
Vector forward, right;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
tech->setOrigin( worldorigin + "0 0 80" );
|
|
|
|
tech->worldorigin.copyTo( tech->edict->s.old_origin );
|
|
|
|
// drop the item
|
|
|
|
tech->PlaceItem();
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
v_angle.AngleVectors( &forward, &right, NULL );
|
|
|
|
tech->velocity = velocity * 0.5 + forward * 200;
|
|
|
|
tech->setAngles( angles );
|
|
|
|
tech->avelocity = Vector( 0, G_CRandom( 360 ), 0 );
|
|
|
|
|
|
|
|
tech->SetTriggerTime( level.time + 2 );
|
|
|
|
|
|
|
|
tech->spawnflags |= DROPPED_PLAYER_ITEM;
|
|
|
|
|
|
|
|
// Remove this from the owner's item list
|
|
|
|
RemoveItem( tech );
|
|
|
|
tech->ClearOwner( );
|
|
|
|
|
|
|
|
tech->PostEvent( EV_Tech_Timeout, CTF_TECH_TIMEOUT );
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::CTF_DropFlag
|
1998-12-20 00:00:00 +00:00
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
Item *dropped_flag;
|
|
|
|
str enemy_flag;
|
|
|
|
Vector forward, right;
|
|
|
|
|
|
|
|
// Figure out the enemy flag
|
|
|
|
if ( client->resp.ctf_team == CTF_TEAM_HARDCORPS )
|
|
|
|
{
|
|
|
|
enemy_flag = "CTF_Flag_Sintek";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
enemy_flag = "CTF_Flag_Hardcorps";
|
|
|
|
}
|
|
|
|
|
|
|
|
edict->s.color_r = 0;
|
|
|
|
edict->s.color_g = 0;
|
|
|
|
edict->s.color_b = 0;
|
|
|
|
edict->s.radius = 0;
|
|
|
|
edict->s.renderfx &= ~RF_DLIGHT;
|
|
|
|
|
|
|
|
if ( dropped_flag = FindItem( enemy_flag.c_str() ) )
|
|
|
|
{
|
|
|
|
dropped_flag->detach();
|
|
|
|
|
|
|
|
if ( enemy_flag == "CTF_Flag_Hardcorps" )
|
|
|
|
{
|
|
|
|
dropped_flag->edict->s.color_r = 0;
|
|
|
|
dropped_flag->edict->s.color_g = 0;
|
|
|
|
dropped_flag->edict->s.color_b = 1.0;
|
|
|
|
dropped_flag->edict->s.radius = 150;
|
|
|
|
dropped_flag->edict->s.renderfx |= RF_DLIGHT;
|
|
|
|
}
|
|
|
|
else if ( enemy_flag == "CTF_Flag_Sintek" )
|
|
|
|
{
|
|
|
|
dropped_flag->edict->s.color_r = 1.0;
|
|
|
|
dropped_flag->edict->s.color_g = 0;
|
|
|
|
dropped_flag->edict->s.color_b = 0;
|
|
|
|
dropped_flag->edict->s.radius = 150;
|
|
|
|
dropped_flag->edict->s.renderfx |= RF_DLIGHT;
|
|
|
|
}
|
|
|
|
|
|
|
|
dropped_flag->RandomAnimate( "idle", NULL );
|
|
|
|
dropped_flag->PostEvent( EV_Flag_Reset, CTF_DROPPED_FLAG_RETURN_TIMEOUT );
|
|
|
|
dropped_flag->setOrigin( worldorigin + "0 0 80" );
|
|
|
|
dropped_flag->worldorigin.copyTo( dropped_flag->edict->s.old_origin );
|
|
|
|
// drop the item
|
|
|
|
dropped_flag->PlaceItem();
|
|
|
|
v_angle.AngleVectors( &forward, &right, NULL );
|
|
|
|
dropped_flag->velocity = velocity * 0.5 + forward * 200;
|
|
|
|
dropped_flag->setAngles( angles );
|
|
|
|
dropped_flag->avelocity = Vector( 0, G_CRandom( 360 ), 0 );
|
|
|
|
dropped_flag->SetTriggerTime( level.time + 2 );
|
|
|
|
dropped_flag->spawnflags |= DROPPED_PLAYER_ITEM;
|
|
|
|
// Remove this from the owner's item list
|
|
|
|
RemoveItem( dropped_flag );
|
|
|
|
dropped_flag->ClearOwner( );
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::CTF_DeadDropTech
|
1998-12-20 00:00:00 +00:00
|
|
|
(
|
1999-11-02 00:00:00 +00:00
|
|
|
void
|
1998-12-20 00:00:00 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
CTF_Tech *tech;
|
|
|
|
|
|
|
|
if ( tech = ( CTF_Tech * )HasItemOfSuperclass( "CTF_Tech" ) )
|
|
|
|
{
|
|
|
|
tech->detach();
|
|
|
|
tech->PostEvent( EV_Tech_Timeout, CTF_TECH_TIMEOUT );
|
|
|
|
// The tech will be dropped by the Player::Killed() function
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::CTF_DeadDropFlag
|
1998-12-20 00:00:00 +00:00
|
|
|
(
|
1999-11-02 00:00:00 +00:00
|
|
|
void
|
1998-12-20 00:00:00 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
Item *dropped_flag;
|
|
|
|
str enemy_flag;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
// When a player dies, check to see if he's carrying an enemy flag and print a message
|
|
|
|
// Also set up a timer to respawn the flag back at it's home base if it's not
|
|
|
|
// recovered
|
|
|
|
|
|
|
|
// Figure out the enemy flag
|
|
|
|
if ( client->resp.ctf_team == CTF_TEAM_HARDCORPS )
|
1998-12-20 00:00:00 +00:00
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
enemy_flag = "CTF_Flag_Sintek";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
enemy_flag = "CTF_Flag_Hardcorps";
|
|
|
|
}
|
|
|
|
|
|
|
|
edict->s.color_r = 0;
|
|
|
|
edict->s.color_g = 0;
|
|
|
|
edict->s.color_b = 0;
|
|
|
|
edict->s.radius = 0;
|
|
|
|
edict->s.renderfx &= ~RF_DLIGHT;
|
|
|
|
|
|
|
|
if ( dropped_flag = FindItem( enemy_flag.c_str() ) )
|
|
|
|
{
|
|
|
|
gi.bprintf( PRINT_HIGH, "%s lost the %s flag!\n", client->pers.netname, CTF_OtherTeamName( client->resp.ctf_team ) );
|
|
|
|
dropped_flag->detach();
|
|
|
|
|
|
|
|
if ( enemy_flag == "CTF_Flag_Hardcorps" )
|
|
|
|
{
|
|
|
|
dropped_flag->edict->s.color_r = 0;
|
|
|
|
dropped_flag->edict->s.color_g = 0;
|
|
|
|
dropped_flag->edict->s.color_b = 1.0;
|
|
|
|
dropped_flag->edict->s.radius = 150;
|
|
|
|
dropped_flag->edict->s.renderfx |= RF_DLIGHT;
|
|
|
|
}
|
|
|
|
else if ( enemy_flag == "CTF_Flag_Sintek" )
|
|
|
|
{
|
|
|
|
dropped_flag->edict->s.color_r = 1.0;
|
|
|
|
dropped_flag->edict->s.color_g = 0;
|
|
|
|
dropped_flag->edict->s.color_b = 0;
|
|
|
|
dropped_flag->edict->s.radius = 150;
|
|
|
|
dropped_flag->edict->s.renderfx |= RF_DLIGHT;
|
|
|
|
}
|
|
|
|
|
|
|
|
dropped_flag->RandomAnimate( "idle", NULL );
|
|
|
|
dropped_flag->PostEvent( EV_Flag_Reset, CTF_AUTO_FLAG_RETURN_TIMEOUT );
|
|
|
|
// The flag will be physically dropped by the Player::Killed() function
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
Vector Player::CTF_GetGrapplePosition
|
1998-12-20 00:00:00 +00:00
|
|
|
(
|
1999-11-02 00:00:00 +00:00
|
|
|
void
|
1998-12-20 00:00:00 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
const gravityaxis_t &grav = gravity_axis[ gravaxis ];
|
|
|
|
Vector right, pos;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
right[ grav.x ] = - orientation[ 1 ][ 0 ];
|
|
|
|
right[ grav.y ] = - orientation[ 1 ][ 1 ] * grav.sign;
|
|
|
|
right[ grav.z ] = - orientation[ 1 ][ 2 ] * grav.sign;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
pos = GunPosition() + ( right * 8 );
|
|
|
|
|
|
|
|
return pos;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::CTF_UpdateHookBeam
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
{
|
|
|
|
if ( beam && hook )
|
|
|
|
{
|
|
|
|
beam->setBeam( CTF_GetGrapplePosition(), hook->worldorigin, 1, 0, 0, 0, 1, 0 );
|
|
|
|
PostEvent( EV_Player_CTF_UpdateHookBeam, FRAMETIME );
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( !hook && beam )
|
|
|
|
{
|
|
|
|
beam->ProcessEvent( EV_Remove );
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::CTF_ExtendGrapple
|
1998-12-20 00:00:00 +00:00
|
|
|
(
|
1999-11-02 00:00:00 +00:00
|
|
|
void
|
1998-12-20 00:00:00 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
const gravityaxis_t &grav = gravity_axis[ gravaxis ];
|
|
|
|
Vector pos, forward, right;
|
|
|
|
|
|
|
|
forward[ grav.x ] = orientation[ 0 ][ 0 ];
|
|
|
|
forward[ grav.y ] = orientation[ 0 ][ 1 ] * grav.sign;
|
|
|
|
forward[ grav.z ] = orientation[ 0 ][ 2 ] * grav.sign;
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
pos = CTF_GetGrapplePosition();
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
RandomGlobalSound( "snd_grapfire" );
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
hook = new Hook;
|
|
|
|
hook->Setup( this, pos, forward );
|
|
|
|
hook->RandomGlobalEntitySound( "snd_grapextend" );
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
beam = new Beam;
|
|
|
|
beam->setBeam( pos, hook->worldorigin, 1, 0, 0, 0, 1, 0 );
|
|
|
|
PostEvent( EV_Player_CTF_UpdateHookBeam, FRAMETIME );
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::CTF_ReleaseGrapple
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
{
|
|
|
|
//Client released the fire button, kill the hook
|
|
|
|
if ( hook )
|
|
|
|
{
|
|
|
|
hook->setSolidType( SOLID_NOT );
|
|
|
|
hook->setMoveType( MOVETYPE_NONE );
|
|
|
|
hook->PostEvent( EV_Remove, 0 );
|
|
|
|
hook = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( beam )
|
|
|
|
{
|
|
|
|
beam->PostEvent( EV_Remove, 0 );
|
|
|
|
beam = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( grapple_pull )
|
|
|
|
RandomGlobalSound( "snd_graprels" );
|
|
|
|
|
|
|
|
ClearGrapplePull();
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::SetGrapplePull
|
|
|
|
(
|
|
|
|
Vector org,
|
|
|
|
float speed
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
grapple_pull = true;
|
|
|
|
grapple_org = org;
|
|
|
|
grapple_speed = speed;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::ClearGrapplePull
|
|
|
|
(
|
|
|
|
void
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
grapple_pull = false;
|
|
|
|
grapple_org = vec_zero;
|
|
|
|
grapple_speed = 0;
|
|
|
|
gravity = 1.0f;
|
|
|
|
grapple_time = level.time + 1.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::CTF_SoundEvent
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
Item *item;
|
|
|
|
ctfsoundevent_t type;
|
|
|
|
|
|
|
|
type = ( ctfsoundevent_t )ev->GetInteger( 1 );
|
|
|
|
|
|
|
|
if ( type == FIRE )
|
|
|
|
{
|
|
|
|
if ( item = FindItem( "CTF_Tech_Double" ) )
|
|
|
|
{
|
|
|
|
RandomGlobalSound( "snd_double" );
|
|
|
|
}
|
|
|
|
if ( item = FindItem( "CTF_Tech_DeathQuad" ) )
|
|
|
|
{
|
|
|
|
RandomGlobalSound( "snd_deathquad" );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( type == DAMAGE )
|
|
|
|
{
|
|
|
|
if ( item = FindItem( "CTF_Tech_Empathy" ) )
|
|
|
|
{
|
|
|
|
RandomGlobalSound( "snd_empathy" );
|
|
|
|
}
|
|
|
|
else if ( item = FindItem( "CTF_Tech_Half" ) )
|
|
|
|
{
|
|
|
|
RandomGlobalSound( "snd_shield" );
|
|
|
|
}
|
|
|
|
else if ( item = FindItem( "CTF_Tech_Regeneration" ) )
|
|
|
|
{
|
|
|
|
RandomGlobalSound( "snd_regen" );
|
|
|
|
}
|
|
|
|
else if ( item = FindItem( "CTF_Tech_DeathQuad" ) )
|
|
|
|
{
|
|
|
|
RandomGlobalSound( "snd_dquadpain" );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::DropWeaponEvent
|
1998-12-20 00:00:00 +00:00
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
1999-11-02 00:00:00 +00:00
|
|
|
if (
|
|
|
|
currentWeapon &&
|
|
|
|
currentWeapon->IsDroppable() &&
|
|
|
|
( !deathmatch->value || !DM_FLAG( DF_NO_DROP_WEAPONS ) )
|
|
|
|
)
|
|
|
|
{
|
|
|
|
currentWeapon->TakeAllAmmo();
|
|
|
|
DropCurrentWeapon();
|
|
|
|
}
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::SetViewAngles
|
|
|
|
(
|
|
|
|
Vector ang
|
|
|
|
)
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
{
|
|
|
|
v_angle = ang;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
void Player::GetPlayerView
|
|
|
|
(
|
|
|
|
Vector *pos,
|
|
|
|
Vector *angle
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
if ( pos )
|
|
|
|
{
|
|
|
|
*pos = origin;
|
|
|
|
pos->z += viewheight;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
|
1999-11-02 00:00:00 +00:00
|
|
|
if ( angle )
|
|
|
|
{
|
|
|
|
*angle = v_angle;
|
|
|
|
}
|
1998-12-20 00:00:00 +00:00
|
|
|
}
|