openmohaa/code/fgame/player.cpp
2023-07-05 20:52:55 +02:00

14509 lines
274 KiB
C++

/*
===========================================================================
Copyright (C) 2015 the OpenMoHAA team
This file is part of OpenMoHAA source code.
OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// player.h: Class definition of the player.
#include "g_local.h"
#include "bg_local.h"
#include "g_spawn.h"
#include "g_phys.h"
#include "entity.h"
#include "player.h"
#include "world.h"
#include "weapon.h"
#include "trigger.h"
#include "scriptmaster.h"
#include "scriptexception.h"
#include "navigate.h"
#include "misc.h"
#include "earthquake.h"
#include "gravpath.h"
#include "armor.h"
#include "inventoryitem.h"
#include "gibs.h"
#include "actor.h"
#include "object.h"
#include "characterstate.h"
#include "weaputils.h"
#include "dm_manager.h"
#include "parm.h"
#include "body.h"
#include "playerstart.h"
#include "weapturret.h"
#include "vehicleturret.h"
//Forward
//Back
//TurnRight
//TurnLeft
//Moveleft (strafe)
//Moveright (strafe)
//Moveup (Jump)
//Movedown (Duck)
//Action (Use)
//Sneak (Toggle or Momentary)
//Speed/Walk (Toggle or Momentary)
//Fire Left hand
//Fire Right hand
#define SLOPE_45_MIN 0.7071f
#define SLOPE_45_MAX 0.831f
#define SLOPE_22_MIN SLOPE_45_MAX
#define SLOPE_22_MAX 0.95f
#define MIN_Z -999999
#define PUSH_OBJECT_DISTANCE 16.0f
#define ARMS_NAME "Bip01 Spine2"
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 Vector min_box_8x8( -4, -4, -4 );
static Vector max_box_8x8( 4, 4, 4 );
static Vector min4x4( -4, -4, 0 );
static Vector max4x4x0( 4, 4, 0 );
static Vector max4x4x8( 4, 4, 8 );
qboolean TryPush( int entnum, vec3_t move_origin, vec3_t move_end );
Event EV_Player_DumpState
(
"state",
EV_CHEAT,
NULL,
NULL,
"Dumps the player's state to the console.",
EV_NORMAL
);
Event EV_Player_ForceLegsState
(
"forcelegsstate",
EV_DEFAULT,
"s",
"legsstate",
"Force the player's legs to a certain state",
EV_NORMAL
);
Event EV_Player_ForceTorsoState
(
"forcetorsostate",
EV_DEFAULT,
"s",
"torsostate",
"Force the player's torso to a certain state",
EV_NORMAL
);
Event EV_Player_GiveAllCheat
(
"wuss",
EV_CONSOLE | EV_CHEAT,
NULL,
NULL,
"Gives player all weapons.",
EV_NORMAL
);
Event EV_Player_EndLevel
(
"endlevel",
EV_DEFAULT,
NULL,
NULL,
"Called when the player gets to the end of the level.",
EV_NORMAL
);
Event EV_Player_DevGodCheat
(
"dog",
EV_CHEAT | EV_CONSOLE,
"I",
"god_mode",
"Sets the god mode cheat or toggles it.",
EV_NORMAL
);
Event EV_Player_FullHeal
(
"fullheal",
EV_CHEAT | EV_CONSOLE,
NULL,
NULL,
"Heals player.",
EV_NORMAL
);
Event EV_Player_Face
(
"face",
EV_CHEAT | EV_CONSOLE,
"v",
"angles",
"Force angles to specified vector",
EV_NORMAL
);
Event EV_Player_DevNoTargetCheat
(
"notarget",
EV_CHEAT,
NULL,
NULL,
"Toggles the notarget cheat.",
EV_NORMAL
);
Event EV_Player_DevNoClipCheat
(
"noclip",
EV_CHEAT | EV_CONSOLE,
NULL,
NULL,
"Toggles the noclip cheat.",
EV_NORMAL
);
Event EV_Player_Teleport
(
"tele",
EV_CHEAT | EV_CONSOLE,
"v",
"location",
"Teleport to location",
EV_NORMAL
);
Event EV_Player_PrevItem
(
"invprev",
EV_CONSOLE,
NULL,
NULL,
"Cycle to player's previous item.",
EV_NORMAL
);
Event EV_Player_NextItem
(
"invnext",
EV_CONSOLE,
NULL,
NULL,
"Cycle to player's next item.",
EV_NORMAL
);
Event EV_Player_PrevWeapon
(
"weapprev",
EV_CONSOLE,
NULL,
NULL,
"Cycle to player's previous weapon.",
EV_NORMAL
);
Event EV_Player_NextWeapon
(
"weapnext",
EV_CONSOLE,
NULL,
NULL,
"Cycle to player's next weapon.",
EV_NORMAL
);
Event EV_Player_DropWeapon
(
"weapdrop",
EV_CONSOLE,
NULL,
NULL,
"Drops the player's current weapon.",
EV_NORMAL
);
Event EV_Player_GiveCheat
(
"give",
EV_CONSOLE | EV_CHEAT,
"sI",
"name amount",
"Gives the player the specified thing (weapon, ammo, item, etc.) and optionally the amount.",
EV_NORMAL
);
Event EV_Player_GiveWeaponCheat
(
"giveweapon",
EV_CONSOLE | EV_CHEAT,
"s",
"weapon_name",
"Gives the player the specified weapon.",
EV_NORMAL
);
Event EV_Player_GameVersion
(
"gameversion",
EV_CONSOLE,
NULL,
NULL,
"Prints the game version.",
EV_NORMAL
);
Event EV_Player_Fov
(
"fov",
EV_CONSOLE,
"F",
"fov",
"Sets the fov.",
EV_NORMAL
);
Event EV_Player_Dead
(
"dead",
EV_DEFAULT,
NULL,
NULL,
"Called when the player is dead.",
EV_NORMAL
);
Event EV_Player_SpawnEntity
(
"spawn",
EV_CHEAT,
"sSSSSSSSS",
"entityname keyname1 value1 keyname2 value2 keyname3 value3 keyname4 value4",
"Spawns an entity.",
EV_NORMAL
);
Event EV_Player_SpawnActor
(
"actor",
EV_CHEAT,
"sSSSSSSSS",
"modelname keyname1 value1 keyname2 value2 keyname3 value3 keyname4 value4",
"Spawns an actor.",
EV_NORMAL
);
Event EV_Player_Respawn
(
"respawn",
EV_DEFAULT,
NULL,
NULL,
"Respawns the player.",
EV_NORMAL
);
Event EV_Player_TestThread
(
"testthread",
EV_CHEAT,
"sS",
"scriptfile label",
"Starts the named thread at label if provided.",
EV_NORMAL
);
Event EV_Player_PowerupTimer
(
"poweruptimer",
EV_DEFAULT,
"ii",
"poweruptimer poweruptype",
"Sets the powerup timer and powerup type.",
EV_NORMAL
);
Event EV_Player_UpdatePowerupTimer
(
"updatepoweruptime",
EV_DEFAULT,
NULL,
NULL,
"Called once a second to decrement powerup time.",
EV_NORMAL
);
Event EV_Player_ResetState
(
"resetstate",
EV_CHEAT,
NULL,
NULL,
"Reset the player's state table.",
EV_NORMAL
);
Event EV_Player_WhatIs
(
"whatis",
EV_CHEAT,
"i",
"entity_number",
"Prints info on the specified entity.",
EV_NORMAL
);
Event EV_Player_ActorInfo
(
"actorinfo",
EV_CHEAT,
"i",
"actor_number",
"Prints info on the specified actor.",
EV_NORMAL
);
Event EV_Player_KillEnt
(
"killent",
EV_CHEAT,
"i",
"entity_number",
"Kills the specified entity.",
EV_NORMAL
);
Event EV_Player_KillClass
(
"killclass",
EV_CHEAT,
"sI",
"classname except_entity_number",
"Kills all of the entities in the specified class.",
EV_NORMAL
);
Event EV_Player_RemoveEnt
(
"removeent",
EV_CHEAT,
"i",
"entity_number",
"Removes the specified entity.",
EV_NORMAL
);
Event EV_Player_RemoveClass
(
"removeclass",
EV_CHEAT,
"sI",
"classname except_entity_number",
"Removes all of the entities in the specified class.",
EV_NORMAL
);
Event EV_Player_Jump
(
"jump",
EV_DEFAULT,
"f",
"height",
"Makes the player jump.",
EV_NORMAL
);
Event EV_Player_SwordAttack
(
"swordattack",
EV_DEFAULT,
"s",
"hand",
"Makes the player attack with the sword in the specified sword.",
EV_NORMAL
);
Event EV_Player_AnimLoop_Torso
(
"animloop_torso",
EV_DEFAULT,
NULL,
NULL,
"Called when the torso animation has finished.",
EV_NORMAL
);
Event EV_Player_ActionAnimEnd
(
"actionanimend",
EV_DEFAULT,
NULL,
NULL,
"Called when the action animation has finished."
);
Event EV_Player_AnimLoop_Legs
(
"animloop_legs",
EV_DEFAULT,
NULL,
NULL,
"Called when the legs animation has finished.",
EV_NORMAL
);
Event EV_Player_DoUse
(
"usestuff",
EV_DEFAULT,
NULL,
NULL,
"Makes the player try to use whatever is in front of her.",
EV_NORMAL
);
Event EV_Player_ListInventory
(
"listinventory",
EV_CONSOLE,
NULL,
NULL,
"List of the player's inventory.",
EV_NORMAL
);
Event EV_Player_Turn
(
"turn",
EV_DEFAULT,
"f",
"yawangle",
"Causes player to turn the specified amount.",
EV_NORMAL
);
Event EV_Player_TurnUpdate
(
"turnupdate",
EV_DEFAULT,
"ff",
"yaw timeleft",
"Causes player to turn the specified amount.",
EV_NORMAL
);
Event EV_Player_TurnLegs
(
"turnlegs",
EV_DEFAULT,
"f",
"yawangle",
"Turns the players legs instantly by the specified amount.",
EV_NORMAL
);
Event EV_Player_NextPainTime
(
"nextpaintime",
EV_DEFAULT,
"f",
"seconds",
"Set the next time the player experiences pain (Current time + seconds specified).",
EV_NORMAL
);
Event EV_Player_FinishUseAnim
(
"finishuseanim",
EV_DEFAULT,
NULL,
NULL,
"Fires off all targets associated with a particular useanim.",
EV_NORMAL
);
Event EV_Player_Holster
(
"holster",
EV_CONSOLE,
NULL,
NULL,
"Holsters all wielded weapons, or unholsters previously put away weapons",
EV_NORMAL
);
Event EV_Player_SafeHolster
(
"safeholster",
EV_CONSOLE,
"b",
"putaway",
"Holsters all wielded weapons, or unholsters previously put away weapons\n"
"preserves state, so it will not holster or unholster unless necessary",
EV_NORMAL
);
Event EV_Player_StartUseObject
(
"startuseobject",
EV_DEFAULT,
NULL,
NULL,
"starts up the useobject's animations.",
EV_NORMAL
);
Event EV_Player_FinishUseObject
(
"finishuseobject",
EV_DEFAULT,
NULL,
NULL,
"Fires off all targets associated with a particular useobject.",
EV_NORMAL
);
Event EV_Player_WatchActor
(
"watchactor",
EV_DEFAULT,
"e",
"actor_to_watch",
"Makes the player's camera watch the specified actor.",
EV_NORMAL
);
Event EV_Player_StopWatchingActor
(
"stopwatchingactor",
EV_DEFAULT,
"e",
"actor_to_stop_watching",
"Makes the player's camera stop watching the specified actor.",
EV_NORMAL
);
Event EV_Player_SetDamageMultiplier
(
"damage_multiplier",
EV_DEFAULT,
"f",
"damage_multiplier",
"Sets the current damage multiplier",
EV_NORMAL
);
Event EV_Player_WaitForState
(
"waitForState",
EV_DEFAULT,
"s",
"stateToWaitFor",
"When set, the player will clear waitforplayer when this state is hit\n"
"in the legs or torso.",
EV_NORMAL
);
Event EV_Player_LogStats
(
"logstats",
EV_CHEAT,
"b",
"state",
"Turn on/off the debugging playlog",
EV_NORMAL
);
Event EV_Player_TakePain
(
"takepain",
EV_DEFAULT,
"b",
"bool",
"Set whether or not to take pain",
EV_NORMAL
);
Event EV_Player_SkipCinematic
(
"skipcinematic",
EV_CONSOLE,
NULL,
NULL,
"Skip the current cinematic",
EV_NORMAL
);
Event EV_Player_ResetHaveItem
(
"resethaveitem",
EV_CONSOLE,
"s",
"weapon_name",
"Resets the game var that keeps track that we have gotten this weapon",
EV_NORMAL
);
Event EV_Player_ModifyHeight
(
"modheight",
EV_DEFAULT,
"s",
"height",
"change the maximum height of the player\ncan specify 'stand', 'duck' or 'prone'.",
0
);
Event EV_Player_PrimaryDMWeapon
(
"primarydmweapon",
EV_CONSOLE,
"s",
"weaptype",
"Sets the player's primary DM weapon",
EV_NORMAL
);
Event EV_Player_DeadBody
(
"deadbody",
EV_DEFAULT,
NULL,
NULL,
"Spawn a dead body"
);
Event EV_Player_Physics_On
(
"physics_on",
EV_DEFAULT,
NULL,
NULL,
"turn player physics on."
);
Event EV_Player_Physics_Off
(
"physics_off",
EV_DEFAULT,
NULL,
NULL,
"turn player physics off."
);
Event EV_Player_AttachToLadder
(
"attachtoladder",
EV_DEFAULT,
NULL,
NULL,
"Attaches the sentient to a ladder"
);
Event EV_Player_UnattachFromLadder
(
"unattachfromladder",
EV_DEFAULT,
NULL,
NULL,
"Unattaches the sentient from a ladder"
);
Event EV_Player_TweakLadderPos
(
"tweakladderpos",
EV_DEFAULT,
NULL,
NULL,
"Tweaks the player's position on a ladder to be proper"
);
Event EV_Player_EnsureOverLadder
(
"ensureoverladder",
EV_DEFAULT,
NULL,
NULL,
"Ensures that the player is at the proper height when getting off the top of a ladder"
);
Event EV_Player_EnsureForwardOffLadder
(
"ensureforwardoffladder",
EV_DEFAULT,
NULL,
NULL,
"Ensures that the player went forward off the ladder."
);
Event EV_Player_GetIsDisguised
(
"is_disguised",
EV_DEFAULT,
NULL,
NULL,
"zero = not disguised, non-zero = disguised",
EV_GETTER
);
Event EV_Player_GetHasDisguise
(
"has_disguise",
EV_DEFAULT,
NULL,
NULL,
"zero = does not have a disguise, non-zero = has a disguise",
EV_GETTER
);
Event EV_Player_SetHasDisguise
(
"has_disguise",
-1,
"i",
"is_disguised",
"zero = does not have a disguise, non-zero = has a disguise",
EV_SETTER
);
Event EV_Player_ObjectiveCount
(
"objective",
EV_DEFAULT,
"ii",
"num_completed out_of",
"Sets the number of objectives completed and the total number of objectives"
);
Event EV_Player_Stats
(
"stats",
EV_CONSOLE,
NULL,
NULL,
"Display the MissionLog."
);
Event EV_Player_Reload
(
"reload",
EV_CONSOLE,
NULL,
NULL,
"Reloads the player's weapon",
EV_NORMAL
);
Event EV_Player_CorrectWeaponAttachments
(
"correctweaponattachments",
EV_CONSOLE,
NULL,
NULL,
"makes sure the weapons is properly attached when interupting a reload",
EV_NORMAL
);
Event EV_Player_Score
(
"score",
EV_CONSOLE,
NULL,
NULL,
"Show the score for the current deathmatch game",
EV_NORMAL
);
Event EV_Player_SetMovePosFlags
(
"moveposflags",
EV_DEFAULT,
"sS",
"position movement",
"used by the state files to tell the game dll what the player is doing",
EV_NORMAL
);
Event EV_Player_GetPosition
(
"getposition",
EV_DEFAULT,
NULL,
NULL,
"returns the player current position",
EV_RETURN
);
Event EV_Player_GetMovement
(
"getmovement",
EV_DEFAULT,
NULL,
NULL,
"returns the player current movement",
EV_RETURN
);
Event EV_Player_Spectator
(
"spectator",
EV_CONSOLE,
NULL,
NULL,
"Become a spectator",
EV_NORMAL
);
Event EV_Player_SetViewModelAnim
(
"viewmodelanim",
EV_DEFAULT,
"sI",
"name force_restart",
"Sets the player's view model animation.",
EV_NORMAL
);
Event EV_Player_DMMessage
(
"dmmessage",
EV_CONSOLE,
"is",
"mode stuffstrings",
"sends a DM message to the appropriate players",
EV_NORMAL
);
Event EV_Player_IPrint
(
"iprint",
EV_CONSOLE,
"sI",
"string bold",
"prints a string to the player, optionally in bold",
EV_NORMAL
);
Event EV_Player_DMDeathDrop
(
"dmdeathdrop",
EV_DEFAULT,
NULL,
NULL,
"Drops the player inventory in DM after's he's been killed"
);
Event EV_Player_Stopwatch
(
"stopwatch",
EV_DEFAULT,
"i",
"duration",
"Starts a stopwatch for a given duration... use 0 to clear the stopwatch"
);
Event EV_Player_EnterIntermission
(
"_enterintermission",
EV_CODEONLY,
NULL,
NULL,
"CODE USE ONLY"
);
Event EV_Player_SetPerferredWeapon
(
"perferredweapon",
EV_DEFAULT,
"s",
"weapon_name",
"Overrides your perferred weapon that is displayed in the stats screen."
);
Event EV_Player_SetVoiceType
(
"voicetype",
EV_DEFAULT,
"s",
"voice_name",
"Sets the voice type to use the player."
);
Event EV_Player_Coord
(
"coord",
EV_CONSOLE,
NULL,
NULL,
"Prints out current location and angles"
);
Event EV_GetViewangles
(
"viewangles",
EV_DEFAULT,
NULL,
NULL,
"get the angles of the entity.",
EV_GETTER
);
Event EV_SetViewangles
(
"viewangles",
EV_DEFAULT,
"v",
"newAngles",
"set the view angles of the entity to newAngles.",
EV_SETTER
);
Event EV_GetUseHeld
(
"useheld",
EV_DEFAULT,
NULL,
NULL,
"returns 1 if this player is holding use, or 0 if he is not",
EV_GETTER
);
Event EV_GetFireHeld
(
"fireheld",
EV_DEFAULT,
NULL,
NULL,
"returns 1 if this player is holding fire, or 0 if he is not",
EV_GETTER
);
Event EV_Player_GetReady
(
"ready",
EV_DEFAULT,
NULL,
NULL,
"returns 1 if this player is ready, 0 otherwise",
EV_GETTER
);
Event EV_Player_SetReady
(
"ready",
EV_CONSOLE,
NULL,
NULL,
"makes this player ready for the round to start"
);
Event EV_Player_SetNotReady
(
"notready",
EV_CONSOLE,
NULL,
NULL,
"makes this player not ready for the round to start"
);
Event EV_Player_GetDMTeam
(
"dmteam",
EV_DEFAULT,
NULL,
NULL,
"returns 'allies', 'axis', 'spectator', or 'freeforall'",
EV_GETTER
);
Event EV_Player_StuffText
(
"stufftext",
EV_DEFAULT,
"s",
"stuffstrings",
"Stuffs text to the player's console"
);
Event EV_Player_TurretEnter
(
"turretenter",
EV_DEFAULT,
"es",
"turret driver_anim",
"Called when someone gets into a turret."
);
Event EV_Player_TurretExit
(
"turretexit",
EV_DEFAULT,
"e",
"turret",
"Called when driver gets out of the turret."
);
Event EV_Player_SafeZoom
(
"safezoom",
EV_DEFAULT,
"b",
"zoomin",
"0 turns off zoom, and 1 returns zoom to previous setting"
);
Event EV_Player_ZoomOff
(
"zoomoff",
EV_DEFAULT,
NULL,
NULL,
"makes sure that zoom is off"
);
// reborn stuff
Event EV_Player_AddKills
(
"addkills",
EV_DEFAULT,
"i",
"kills",
"adds kills number to player",
EV_NORMAL
);
Event EV_Player_AddDeaths
(
"adddeaths",
EV_DEFAULT,
"i",
"deaths",
"adds deaths number to player",
EV_NORMAL
);
Event EV_Player_AdminRights
(
"adminrights",
EV_DEFAULT,
NULL,
NULL,
"returns client admin rights",
EV_GETTER
);
Event EV_Player_BindWeap
(
"bindweap",
EV_DEFAULT,
"ei",
"weapon handnum",
"binds weapon to player and sets him as weapon owner",
EV_NORMAL
);
Event EV_Player_CanSwitchTeams
(
"canswitchteams",
EV_DEFAULT,
"bB",
"allow_team_change allow_spectate",
"Specify if this player is allowed to switch teams and spectate. Doesn't override global canswitchteams.",
EV_NORMAL
);
Event EV_Player_ClearCommand
(
"clearcommand",
EV_DEFAULT,
"S",
"command",
"Clears any or a specific client command",
EV_NORMAL
);
Event EV_Player_Dive
(
"dive",
EV_DEFAULT,
"fF",
"height airborne_duration",
"Makes the player dive into prone position.",
EV_NORMAL
);
Event EV_Player_Earthquake
(
"earthquake2",
EV_DEFAULT,
"ffbbVF",
"duration magnitude no_rampup no_rampdown location radius",
"Create a smooth realistic earthquake for a player. Requires sv_reborn to be set.",
EV_NORMAL
);
Event EV_Player_FreezeControls
(
"freezecontrols",
EV_DEFAULT,
"b",
"freeze_state",
"Blocks or unblocks control input from this player.",
EV_NORMAL
);
Event EV_Player_GetConnState
(
"getconnstate",
EV_DEFAULT,
NULL,
NULL,
"gets connection state. [DEPRECATED]",
EV_RETURN
);
Event EV_Player_GetDamageMultiplier
(
"damage_multiplier",
EV_DEFAULT,
"Gets the current damage multiplier",
NULL,
NULL,
EV_GETTER
);
Event EV_Player_GetKillHandler
(
"killhandler",
EV_DEFAULT,
"s",
"label",
"Gets the player's current killed event handler. Returns NIL if no custom killhandler was set.",
EV_GETTER
);
Event EV_Player_GetKills
(
"getkills",
EV_DEFAULT,
NULL,
NULL,
"gets kills number of player",
EV_RETURN
);
Event EV_Player_GetDeaths
(
"getdeaths",
EV_DEFAULT,
NULL,
NULL,
"gets deaths number of player",
EV_RETURN
);
Event EV_Player_GetLegsState
(
"getlegsstate",
EV_DEFAULT,
NULL,
NULL,
"Gets the player's current legs state name",
EV_RETURN
);
Event EV_Player_GetStateFile
(
"statefile",
EV_DEFAULT,
NULL,
NULL,
"Gets the player's current state file.",
EV_GETTER
);
Event EV_Player_GetTorsoState
(
"gettorsostate",
EV_DEFAULT,
NULL,
NULL,
"Gets the player's current torso state name",
EV_RETURN
);
Event EV_Player_HideEnt
(
"hideent",
EV_DEFAULT,
"e",
"entity",
"Hides the specified entity to the player.",
EV_NORMAL
);
Event EV_Player_Inventory
(
"inventory",
EV_DEFAULT,
NULL,
NULL,
"returns player's inventory",
EV_GETTER
);
Event EV_Player_InventorySet
(
"inventory",
EV_DEFAULT,
"e",
"array",
"Set up the player's inventory",
EV_SETTER
);
Event EV_Player_IsAdmin
(
"isadmin",
EV_DEFAULT,
NULL,
NULL,
"checks if player is logged as admin",
EV_RETURN
);
Event EV_Player_IsSpectator
(
"isspectator",
EV_DEFAULT,
NULL,
NULL,
"checks if player is in spectator",
EV_RETURN
);
Event EV_Player_JoinDMTeam
(
"join_team",
EV_CONSOLE,
"s",
"team",
"Join the specified team (allies or axis)",
EV_NORMAL
);
Event EV_Player_AutoJoinDMTeam
(
"auto_join_team",
EV_CONSOLE,
NULL,
NULL,
"Join the team with fewer players"
);
Event EV_Player_JoinArena
(
"join_arena",
EV_CONSOLE,
"i",
"arena_id_num",
"Join the specified arena"
);
Event EV_Player_LeaveArena
(
"leave_arena",
EV_CONSOLE,
NULL,
NULL,
"Leave the current arena"
);
Event EV_Player_CreateTeam
(
"create_team",
EV_CONSOLE,
NULL,
NULL,
"Create a team in the current arena"
);
Event EV_Player_LeaveTeam
(
"leave_team",
EV_CONSOLE,
NULL,
NULL,
"Leave the current team"
);
Event EV_Player_RefreshArenaUI
(
"arena_ui",
EV_CONSOLE,
NULL,
NULL,
"Refresh the arena UI"
);
Event EV_Player_CallVote
(
"callvote",
EV_CONSOLE,
"ss",
"arg1 arg2",
"Player calls a vote"
);
Event EV_Player_Vote
(
"vote",
EV_CONSOLE,
"s",
"arg1",
"Player votes either yes or no"
);
Event EV_Player_LeanLeftHeld
(
"leanleftheld",
EV_DEFAULT,
NULL,
NULL,
"Returns 1 if this player is holding lean left key, or 0 if he is not",
EV_GETTER
);
Event EV_Player_LeanRightHeld
(
"leanrightheld",
EV_DEFAULT,
NULL,
NULL,
"returns EV_RETURN if this player is holding lean right key, or 0 if he is not",
EV_GETTER
);
Event EV_Player_ModifyHeightFloat
(
"modheightfloat",
EV_DEFAULT,
"ff",
"height max_z",
"Specify the view height of the player and the height of his bounding box.",
EV_NORMAL
);
Event EV_Player_MoveSpeedScale
(
"moveSpeedScale",
EV_DEFAULT,
"f",
"speed",
"Sets the player's speed multiplier (default 1.0).",
EV_SETTER
);
Event EV_Player_MoveSpeedScaleGet
(
"moveSpeedScale",
EV_DEFAULT,
NULL,
NULL,
"Gets the player's speed multiplier.",
EV_GETTER
);
Event EV_Player_PlayLocalSound
(
"playlocalsound",
EV_DEFAULT,
"sBF",
"soundName loop time",
"Plays a local sound to the player. The sound must be aliased globally. Requires sv_reborn to be set for stereo sounds.",
EV_NORMAL
);
Event EV_Player_Replicate
(
"replicate",
EV_DEFAULT,
"s",
"variable",
"Replicate a variable to the client (needs patch 1.12).",
EV_NORMAL
);
Event EV_Player_RunHeld
(
"runheld",
EV_DEFAULT,
NULL,
NULL,
"returns 1 if this player is holding run key, or 0 if he is not",
EV_GETTER
);
Event EV_Player_SecFireHeld
(
"secfireheld",
EV_DEFAULT,
NULL,
NULL,
"returns EV_RETURN if this player is holding secondary fire, or 0 if he is not",
EV_GETTER
);
Event EV_Player_SetAnimSpeed
(
"setanimspeed",
EV_DEFAULT,
"f",
"speed",
"set the player's animation speed multiplier (default 1.0).",
EV_NORMAL
);
Event EV_Player_SetFov
(
"setfov",
EV_DEFAULT,
"f",
"fov",
"set the player's fov (default 80).",
EV_NORMAL
);
Event EV_Player_SetKillHandler
(
"killhandler",
EV_DEFAULT,
"s",
"label",
"Replace the player's killed event by a new scripted handler. None or an empty string will revert to the default killed event handler.",
EV_SETTER
);
Event EV_Player_SetClientFlag
(
"setclientflag",
EV_DEFAULT,
"s",
"name",
"Calls a flag to the script client.",
EV_NORMAL
);
Event EV_Player_SetEntityShader
(
"setentshader",
EV_DEFAULT,
"es",
"entity shadername",
"Sets an entity shader for this player. An empty string will revert to the normal entity shader.",
EV_NORMAL
);
Event EV_Player_SetLocalSoundRate
(
"setlocalsoundrate",
EV_DEFAULT,
"sfF",
"name rate time",
"Sets the local sound rate.",
EV_NORMAL
);
Event EV_Player_SetSpeed
(
"setspeed",
EV_DEFAULT,
"fI",
"speed index",
"Sets the player's speed multiplier (default 1.0). Index specify which array value will be used (maximum 4).",
EV_NORMAL
);
Event EV_Player_SetStateFile
(
"statefile",
EV_DEFAULT,
"S",
"statefile",
"Sets the player's current state file (setting NIL, NULL or an empty string will revert to the global statefile).",
EV_SETTER
);
Event EV_Player_SetTeam
(
"setteam",
EV_DEFAULT,
"s",
"team_name",
"sets the player's team without respawning.\n"
"Available team names are 'none', 'spectator', 'freeforall', 'axis' and 'allies'.",
EV_NORMAL
);
Event EV_Player_SetViewModelAnimSpeed
(
"setvmaspeed",
EV_DEFAULT,
"sf",
"name speed",
"Sets the player's animation speed when playing it.",
EV_NORMAL
);
Event EV_Player_ShowEnt
(
"showent",
EV_DEFAULT,
"e",
"entity",
"Shows the specified entity to the player.",
EV_NORMAL
);
Event EV_Player_StopLocalSound
(
"stoplocalsound",
EV_DEFAULT,
"sF",
"soundName time",
"Stops the specified sound.",
EV_NORMAL
);
Event EV_Player_UseHeld
(
"useheld",
EV_DEFAULT,
NULL,
NULL,
"returns 1 if this player is holding use key, or 0 if he is not",
EV_GETTER
);
Event EV_Player_Userinfo
(
"userinfo",
EV_DEFAULT,
NULL,
NULL,
"returns userinfo string",
EV_GETTER
);
Event EV_Player_ViewModelGetAnim
(
"viewmodelgetanim",
EV_DEFAULT,
"B",
"fullanim",
"Gets the player's current view model animation.",
EV_RETURN
);
Event EV_Player_ViewModelAnimFinished
(
"viewmodelanimfinished",
EV_DEFAULT,
NULL,
NULL,
"True if the player's current view model finished its animation.",
EV_RETURN
);
Event EV_Player_ViewModelAnimValid
(
"viewmodelanimvalid",
EV_DEFAULT,
"sB",
"anim fullanim",
"True if the view model animation is valid.",
EV_RETURN
);
Event EV_Player_VisionSetBlur
(
"visionsetblur",
EV_DEFAULT,
"fF",
"level transition_time",
"Sets the player's blur level. Level is a fraction from 0-1",
EV_NORMAL
);
Event EV_Player_VisionGetNaked
(
"visiongetnaked",
EV_DEFAULT,
NULL,
NULL,
"Gets the player's current naked-eye vision.",
EV_RETURN
);
Event EV_Player_VisionSetNaked
(
"visionsetnaked",
EV_DEFAULT,
"sFF",
"vision_name transition_time phase",
"Sets the player's naked-eye vision. Optionally give a transition time from the current vision. If vision_name is an empty string, it will revert to the current global vision.",
EV_NORMAL
);
/*
==============================================================================
PLAYER
==============================================================================
*/
CLASS_DECLARATION( Sentient, Player, "player" )
{
{ &EV_Vehicle_Enter, &Player::EnterVehicle },
{ &EV_Vehicle_Exit, &Player::ExitVehicle },
{ &EV_Turret_Enter, &Player::EnterTurret },
{ &EV_Turret_Exit, &Player::ExitTurret },
{ &EV_Player_EndLevel, &Player::EndLevel },
{ &EV_Player_PrevItem, &Player::SelectPreviousItem },
{ &EV_Player_NextItem, &Player::SelectNextItem },
{ &EV_Player_PrevWeapon, &Player::SelectPreviousWeapon },
{ &EV_Player_NextWeapon, &Player::SelectNextWeapon },
{ &EV_Player_DropWeapon, &Player::DropCurrentWeapon },
{ &EV_Player_Reload, &Player::PlayerReload },
{ &EV_Player_CorrectWeaponAttachments, &Player::EventCorrectWeaponAttachments },
{ &EV_Player_GiveCheat, &Player::GiveCheat },
{ &EV_Player_GiveWeaponCheat, &Player::GiveWeaponCheat },
{ &EV_Player_GiveAllCheat, &Player::GiveAllCheat },
{ &EV_Player_DevGodCheat, &Player::GodCheat },
{ &EV_Player_FullHeal, &Player::FullHeal },
{ &EV_Player_DevNoTargetCheat, &Player::NoTargetCheat },
{ &EV_Player_DevNoClipCheat, &Player::NoclipCheat },
{ &EV_Player_GameVersion, &Player::GameVersion },
{ &EV_Player_DumpState, &Player::DumpState },
{ &EV_Player_ForceTorsoState, &Player::ForceTorsoState },
{ &EV_Player_ForceLegsState, &Player::ForceLegsState },
{ &EV_Player_Fov, &Player::EventSetSelectedFov },
{ &EV_Kill, &Player::Kill },
{ &EV_Player_Dead, &Player::Dead },
{ &EV_Player_SpawnEntity, &Player::SpawnEntity },
{ &EV_Player_SpawnActor, &Player::SpawnActor },
{ &EV_Player_Respawn, &Player::Respawn },
{ &EV_Player_DoUse, &Player::DoUse },
{ &EV_Pain, &Player::Pain },
{ &EV_Killed, &Player::Killed },
{ &EV_GotKill, &Player::GotKill },
{ &EV_Player_TestThread, &Player::TestThread },
{ &EV_Player_PowerupTimer, &Player::SetPowerupTimer },
{ &EV_Player_UpdatePowerupTimer, &Player::UpdatePowerupTimer },
{ &EV_Player_ResetState, &Player::ResetState },
{ &EV_Player_WhatIs, &Player::WhatIs },
{ &EV_Player_ActorInfo, &Player::ActorInfo },
{ &EV_Player_KillEnt, &Player::KillEnt },
{ &EV_Player_RemoveEnt, &Player::RemoveEnt },
{ &EV_Player_KillClass, &Player::KillClass },
{ &EV_Player_RemoveClass, &Player::RemoveClass },
{ &EV_Player_AnimLoop_Legs, &Player::EndAnim_Legs },
{ &EV_Player_AnimLoop_Torso, &Player::EndAnim_Torso },
{ &EV_Player_ActionAnimEnd, &Player::EndActionAnim },
{ &EV_Player_Jump, &Player::Jump },
{ &EV_Sentient_JumpXY, &Player::JumpXY },
{ &EV_Player_ListInventory, &Player::ListInventoryEvent },
{ &EV_Player_NextPainTime, &Player::NextPainTime },
{ &EV_Player_Turn, &Player::Turn },
{ &EV_Player_TurnUpdate, &Player::TurnUpdate },
{ &EV_Player_TurnLegs, &Player::TurnLegs },
{ &EV_Player_FinishUseAnim, &Player::FinishUseAnim },
{ &EV_Player_Holster, &Player::HolsterToggle },
{ &EV_Player_SafeHolster, &Player::Holster },
{ &EV_Player_SafeZoom, &Player::SafeZoomed },
{ &EV_Player_ZoomOff, &Player::ZoomOffEvent },
{ &EV_Player_StartUseObject, &Player::StartUseObject },
{ &EV_Player_FinishUseObject, &Player::FinishUseObject },
{ &EV_Player_WatchActor, &Player::WatchActor },
{ &EV_Player_StopWatchingActor, &Player::StopWatchingActor },
{ &EV_Player_SetDamageMultiplier, &Player::SetDamageMultiplier },
{ &EV_Player_WaitForState, &Player::WaitForState },
{ &EV_Player_LogStats, &Player::LogStats },
{ &EV_Player_TakePain, &Player::SetTakePain },
{ &EV_Player_SkipCinematic, &Player::SkipCinematic },
{ &EV_Player_ResetHaveItem, &Player::ResetHaveItem },
{ &EV_Show, &Player::PlayerShowModel },
{ &EV_Player_ModifyHeight, &Player::ModifyHeight },
{ &EV_Player_SetMovePosFlags, &Player::SetMovePosFlags },
{ &EV_Player_GetPosition, &Player::GetPositionForScript },
{ &EV_Player_GetMovement, &Player::GetMovementForScript },
{ &EV_Player_Teleport, &Player::EventTeleport },
{ &EV_Player_Face, &Player::EventFace },
{ &EV_Player_Coord, &Player::EventCoord },
{ &EV_Player_Score, &Player::Score },
{ &EV_Player_JoinDMTeam, &Player::Join_DM_Team },
{ &EV_Player_AutoJoinDMTeam, &Player::Auto_Join_DM_Team },
{ &EV_Player_LeaveTeam, &Player::Leave_DM_Team },
{ &EV_Player_Spectator, &Player::Spectator },
{ &EV_Player_CallVote, &Player::CallVote },
{ &EV_Player_Vote, &Player::Vote },
{ &EV_Player_PrimaryDMWeapon, &Player::EventPrimaryDMWeapon },
{ &EV_Player_DeadBody, &Player::DeadBody },
{ &EV_Player_Physics_On, &Player::PhysicsOn },
{ &EV_Player_Physics_Off, &Player::PhysicsOff },
{ &EV_Player_AttachToLadder, &Player::AttachToLadder },
{ &EV_Player_UnattachFromLadder, &Player::UnattachFromLadder },
{ &EV_Player_TweakLadderPos, &Player::TweakLadderPos },
{ &EV_Player_EnsureOverLadder, &Player::EnsureOverLadder },
{ &EV_Player_EnsureForwardOffLadder, &Player::EnsureForwardOffLadder },
{ &EV_Damage, &Player::ArmorDamage },
{ &EV_Player_GetIsDisguised, &Player::GetIsDisguised },
{ &EV_Player_GetHasDisguise, &Player::GetHasDisguise },
{ &EV_Player_SetHasDisguise, &Player::SetHasDisguise },
{ &EV_Player_ObjectiveCount, &Player::SetObjectiveCount },
{ &EV_Player_Stats, &Player::Stats },
{ &EV_Player_StuffText, &Player::EventStuffText },
{ &EV_Player_DMMessage, &Player::EventDMMessage },
{ &EV_Player_IPrint, &Player::EventIPrint },
{ &EV_SetViewangles, &Player::SetViewangles },
{ &EV_GetViewangles, &Player::GetViewangles },
{ &EV_GetUseHeld, &Player::EventGetUseHeld },
{ &EV_GetFireHeld, &Player::EventGetFireHeld },
{ &EV_Player_GetReady, &Player::EventGetReady },
{ &EV_Player_SetReady, &Player::EventSetReady },
{ &EV_Player_SetNotReady, &Player::EventSetNotReady },
{ &EV_Player_GetDMTeam, &Player::EventGetDMTeam },
{ &EV_Player_SetViewModelAnim, &Player::EventSetViewModelAnim },
{ &EV_Player_DMDeathDrop, &Player::EventDMDeathDrop },
{ &EV_Player_Stopwatch, &Player::EventStopwatch },
{ &EV_Player_EnterIntermission, &Player::EventEnterIntermission },
{ &EV_Player_SetPerferredWeapon, &Player::EventSetPerferredWeapon },
{ &EV_Player_SetVoiceType, &Player::EventSetVoiceType },
{ &EV_Player_AddDeaths, &Player::AddDeaths },
{ &EV_Player_AddKills, &Player::AddKills },
{ &EV_Player_AdminRights, &Player::AdminRights },
{ &EV_Player_BindWeap, &Player::BindWeap },
{ &EV_Player_CanSwitchTeams, &Player::CanSwitchTeams },
{ &EV_Player_ClearCommand, &Player::ClearCommand },
{ &EV_Player_Dive, &Player::Dive },
{ &EV_Player_DMMessage, &Player::EventDMMessage },
{ &EV_Player_Earthquake, &Player::EventEarthquake },
{ &EV_Player_FreezeControls, &Player::FreezeControls },
{ &EV_Player_SetTeam, &Player::EventSetTeam },
{ &EV_Player_GetConnState, &Player::GetConnState },
{ &EV_Player_GetDamageMultiplier, &Player::GetDamageMultiplier },
{ &EV_Player_GetDeaths, &Player::GetDeaths },
{ &EV_Player_GetKillHandler, &Player::GetKillHandler },
{ &EV_Player_GetKills, &Player::GetKills },
{ &EV_Player_GetLegsState, &Player::GetLegsState },
{ &EV_Player_GetStateFile, &Player::GetStateFile },
{ &EV_Player_GetTorsoState, &Player::GetTorsoState },
{ &EV_Player_HideEnt, &Player::HideEntity },
{ &EV_Player_Inventory, &Player::Inventory },
{ &EV_Player_InventorySet, &Player::InventorySet },
{ &EV_Player_IsSpectator, &Player::EventIsSpectator },
{ &EV_Player_IsAdmin, &Player::IsAdmin },
{ &EV_Player_LeanLeftHeld, &Player::LeanLeftHeld },
{ &EV_Player_LeanRightHeld, &Player::LeanRightHeld },
{ &EV_Player_ModifyHeight, &Player::ModifyHeight },
{ &EV_Player_ModifyHeightFloat, &Player::ModifyHeightFloat },
{ &EV_Player_MoveSpeedScale, &Player::SetSpeed },
{ &EV_Player_MoveSpeedScaleGet, &Player::GetMoveSpeedScale },
{ &EV_Player_PlayLocalSound, &Player::PlayLocalSound },
{ &EV_Player_RunHeld, &Player::RunHeld },
{ &EV_Player_SecFireHeld, &Player::SecFireHeld },
{ &EV_Player_SetAnimSpeed, &Player::SetAnimSpeed },
{ &EV_Player_SetClientFlag, &Player::SetClientFlag },
{ &EV_Player_SetEntityShader, &Player::SetEntityShader },
{ &EV_Player_SetKillHandler, &Player::SetKillHandler },
{ &EV_Player_SetLocalSoundRate, &Player::SetLocalSoundRate },
{ &EV_Player_SetSpeed, &Player::SetSpeed },
{ &EV_Player_SetStateFile, &Player::SetStateFile },
{ &EV_Player_SetViewModelAnimSpeed, &Player::SetVMASpeed },
{ &EV_Player_ShowEnt, &Player::ShowEntity },
{ &EV_Player_Spectator, &Player::Spectator },
{ &EV_Player_StopLocalSound, &Player::StopLocalSound },
{ &EV_Player_UseHeld, &Player::UseHeld },
{ &EV_Player_Userinfo, &Player::Userinfo },
{ &EV_Player_ViewModelAnimFinished, &Player::EventGetViewModelAnimFinished },
{ &EV_Player_ViewModelGetAnim, &Player::EventGetViewModelAnim },
{ &EV_Player_ViewModelAnimValid, &Player::EventGetViewModelAnimValid },
{ &EV_Player_VisionGetNaked, &Player::VisionGetNaked },
{ &EV_Player_VisionSetBlur, &Player::VisionSetBlur },
{ &EV_Player_VisionSetNaked, &Player::VisionSetNaked },
{ NULL, NULL }
};
qboolean Player::checkturnleft
(
Conditional &condition
)
{
float yaw;
yaw = SHORT2ANGLE( last_ucmd.angles[ YAW ] + client->ps.delta_angles[ YAW ] );
return ( angledist( old_v_angle[ YAW ] - yaw ) < -8.0f );
}
qboolean Player::checkturnright
(
Conditional &condition
)
{
float yaw;
yaw = SHORT2ANGLE( last_ucmd.angles[ YAW ] + client->ps.delta_angles[ YAW ] );
return ( angledist( old_v_angle[ YAW ] - yaw ) > 8.0f );
}
qboolean Player::checkforward
(
Conditional &condition
)
{
return last_ucmd.forwardmove > 0;
}
qboolean Player::checkbackward
(
Conditional &condition
)
{
return last_ucmd.forwardmove < 0;
}
qboolean Player::checkstrafeleft
(
Conditional &condition
)
{
return last_ucmd.rightmove < 0;
}
qboolean Player::checkstraferight
(
Conditional &condition
)
{
return last_ucmd.rightmove > 0;
}
qboolean Player::checkrise
(
Conditional &condition
)
{
return false;
}
qboolean Player::checkjump
(
Conditional &condition
)
{
return last_ucmd.upmove > 0;
}
qboolean Player::checkcrouch( Conditional &condition )
{
if ( last_ucmd.upmove < 0 ) // check for downward movement
{
return true;
}
return false;
}
qboolean Player::checkjumpflip
(
Conditional &condition
)
{
return velocity.z < ( sv_gravity->value * 0.5f );
}
qboolean Player::checkanimdone_legs
(
Conditional &condition
)
{
return animdone_Legs;
}
qboolean Player::checkanimdone_torso
(
Conditional &condition
)
{
return animdone_Torso;
}
qboolean Player::checkattackleft
(
Conditional &condition
)
{
if( level.playerfrozen || m_bFrozen || ( flags & FL_IMMOBILE ) || (g_gametype->integer && !m_bAllowFighting) )
{
return false;
}
if( last_ucmd.buttons & BUTTON_ATTACKLEFT )
{
Weapon *weapon;
last_attack_button = BUTTON_ATTACKLEFT;
weapon = GetActiveWeapon( WEAPON_MAIN );
if( weapon )
{
return true;
}
// No ammo
return false;
}
else
{
return false;
}
}
qboolean Player::checkattackbuttonleft
(
Conditional &condition
)
{
if( level.playerfrozen || m_bFrozen || ( flags & FL_IMMOBILE ) || !m_bAllowFighting )
{
return false;
}
return ( last_ucmd.buttons & BUTTON_ATTACKLEFT );
}
qboolean Player::checkattackright
(
Conditional &condition
)
{
if( level.playerfrozen || m_bFrozen || ( flags & FL_IMMOBILE ) || !m_bAllowFighting )
{
return false;
}
if( last_ucmd.buttons & BUTTON_ATTACKRIGHT )
{
Weapon *weapon;
last_attack_button = BUTTON_ATTACKRIGHT;
weapon = GetActiveWeapon( WEAPON_MAIN );
if( weapon )
{
return true;
}
// No ammo
return false;
}
else
{
return false;
}
}
qboolean Player::checkattackbuttonright
(
Conditional &condition
)
{
if( level.playerfrozen || m_bFrozen || ( flags & FL_IMMOBILE ) || !m_bAllowFighting )
{
return false;
}
return ( last_ucmd.buttons & BUTTON_ATTACKRIGHT );
}
qboolean Player::checksneak
(
Conditional &condition
)
{
return ( last_ucmd.upmove ) < 0;
}
qboolean Player::checkrun
(
Conditional &condition
)
{
return ( last_ucmd.buttons & BUTTON_RUN ) != 0;
}
qboolean Player::checkuse
(
Conditional &condition
)
{
return ( last_ucmd.buttons & BUTTON_USE ) != 0;
}
qboolean Player::checkcanmoveleft
(
Conditional &condition
)
{
if ( condition.numParms() )
{
return move_left_vel >= atof( condition.getParm( 1 ) );
}
return move_left_vel > 1.0f;
}
qboolean Player::checkcanturn
(
Conditional &condition
)
{
float yaw;
Vector oldang( v_angle );
qboolean result;
yaw = atof( condition.getParm( 1 ) );
v_angle[ YAW ] = ( int )( anglemod( v_angle[ YAW ] + yaw ) / 22.5f ) * 22.5f;
SetViewAngles( v_angle );
result = CheckMove( vec_zero );
SetViewAngles( oldang );
return result;
}
qboolean Player::checkcanmoveright
(
Conditional &condition
)
{
if ( condition.numParms() )
{
return move_right_vel >= atof( condition.getParm( 1 ) );
}
return move_right_vel > 1.0f;
}
qboolean Player::checkcanmovebackward
(
Conditional &condition
)
{
if ( condition.numParms() )
{
return move_backward_vel >= atof( condition.getParm( 1 ) );
}
return move_backward_vel > 1.0f;
}
qboolean Player::checkcanmoveforward
(
Conditional &condition
)
{
if ( condition.numParms() )
{
return move_forward_vel >= atof( condition.getParm( 1 ) );
}
return move_forward_vel > 1.0f;
}
qboolean Player::checkcanwallhug
(
Conditional &condition
)
{
trace_t trace;
Vector start( origin.x, origin.y, origin.z + 4 );
Vector end( start - yaw_forward * 15.0f );
while( end.z < absmax.z - 4.0f )
{
trace = G_Trace( start, min_box_8x8, max_box_8x8, end, this, MASK_DEADSOLID, true, "checkcanwallhug" );
if ( ( trace.fraction == 1.0f ) || ( trace.ent->entity->getSolidType() != SOLID_BSP ) )
{
return false;
}
start.z += 16.0f;
end.z += 16.0f;
}
return true;
}
qboolean Player::checkblocked( Conditional &condition )
{
int test_moveresult;
test_moveresult = moveresult;
if( flags & FL_IMMOBILE )
test_moveresult = MOVERESULT_BLOCKED;
if ( condition.numParms() )
{
return test_moveresult >= atoi( condition.getParm( 1 ) );
}
return test_moveresult >= MOVERESULT_BLOCKED;
}
qboolean Player::checkhasvelocity( Conditional &condition )
{
float fSpeed;
if( condition.numParms() )
{
fSpeed = atof( condition.getParm( 1 ) );
}
else
{
fSpeed = 4.0f;
}
return ( ( move_forward_vel > fSpeed ) || ( move_backward_vel > fSpeed ) ||
( move_right_vel > fSpeed ) || ( move_left_vel > fSpeed ) );
}
qboolean Player::checkheight( Conditional &condition )
{
str sHeight = condition.getParm( 1 );
float fHeight;
Vector newmaxs;
trace_t trace;
if( !sHeight.icmp( "stand" ) )
{
fHeight = 94.0f;
}
else if( !sHeight.icmp( "duckrun" ) )
{
fHeight = 60.0f;
}
else if( !sHeight.icmp( "duck" ) )
{
fHeight = 54.0f;
}
else if( !sHeight.icmp( "prone" ) )
{
fHeight = 20.0f;
}
else
{
fHeight = atoi( sHeight.c_str() );
}
if( fHeight < 16.0f ) {
fHeight = 16.0f;
}
if( maxs[ 2 ] >= fHeight )
{
return true;
}
else
{
newmaxs = maxs;
newmaxs[ 2 ] = fHeight;
trace = G_Trace( origin,
mins,
newmaxs,
origin,
edict,
MASK_PLAYERSOLID,
true,
"Player::checkheight" );
if( trace.startsolid )
{
return false;
}
else
{
return true;
}
}
}
qboolean Player::checkonground
(
Conditional &condition
)
{
if( groundentity || client->ps.walking )
{
falling = 0;
return qtrue;
}
else
{
return qfalse;
}
}
qboolean Player::check22degreeslope
(
Conditional &condition
)
{
if ( client->ps.walking && client->ps.groundPlane && ( client->ps.groundTrace.plane.normal[ 2 ] < SLOPE_22_MAX ) &&
( client->ps.groundTrace.plane.normal[ 2 ] >= SLOPE_22_MIN ) )
{
return qtrue;
}
return qfalse;
}
qboolean Player::check45degreeslope
(
Conditional &condition
)
{
if ( client->ps.walking && client->ps.groundPlane && ( client->ps.groundTrace.plane.normal[ 2 ] < SLOPE_45_MAX ) &&
( client->ps.groundTrace.plane.normal[ 2 ] >= SLOPE_45_MIN ) )
{
return qtrue;
}
return qfalse;
}
qboolean Player::checklookingup( Conditional &condition )
{
float angle = 0 - atof( condition.getParm( 1 ) );
return angle > m_vViewAng[ 0 ];
}
qboolean Player::checkrightleghigh
(
Conditional &condition
)
{
float groundyaw;
float yawdelta;
int which;
groundyaw = ( int )vectoyaw( client->ps.groundTrace.plane.normal );
yawdelta = anglemod( v_angle.y - groundyaw );
which = ( ( int )yawdelta + 45 ) / 90;
return ( which == 3 );
}
qboolean Player::checkleftleghigh
(
Conditional &condition
)
{
float groundyaw;
float yawdelta;
int which;
groundyaw = ( int )vectoyaw( client->ps.groundTrace.plane.normal );
yawdelta = anglemod( v_angle.y - groundyaw );
which = ( ( int )yawdelta + 45 ) / 90;
return ( which == 1 );
}
qboolean Player::checkfacingupslope
(
Conditional &condition
)
{
float groundyaw;
float yawdelta;
int which;
groundyaw = ( int )vectoyaw( client->ps.groundTrace.plane.normal );
yawdelta = anglemod( v_angle.y - groundyaw );
which = ( ( int )yawdelta + 45 ) / 90;
return ( which == 2 );
}
qboolean Player::checkfacingdownslope
(
Conditional &condition
)
{
float groundyaw;
float yawdelta;
int which;
groundyaw = ( int )vectoyaw( client->ps.groundTrace.plane.normal );
yawdelta = anglemod( v_angle.y - groundyaw );
which = ( ( int )yawdelta + 45 ) / 90;
return ( ( which == 0 ) || ( which == 4 ) );
}
qboolean Player::checkfalling
(
Conditional &condition
)
{
return falling;
}
qboolean Player::checkgroundentity
(
Conditional &condition
)
{
return ( groundentity != NULL );
}
qboolean Player::checkhardimpact( Conditional &condition )
{
return hardimpact;
}
qboolean Player::checkmediumimpact( Conditional &condition )
{
return mediumimpact;
}
qboolean Player::checkcanfall
(
Conditional &condition
)
{
return canfall;
}
qboolean Player::checkatdoor
(
Conditional &condition
)
{
// Check if the player is at a door
return ( atobject && atobject->isSubclassOf( Door ) );
}
qboolean Player::checkatuseanim
(
Conditional &condition
)
{
// Check if the player is at a useanim
if ( atobject && atobject->isSubclassOf( UseAnim ) )
{
return ( ( UseAnim * )( Entity * )atobject )->canBeUsed( this );
}
return false;
}
qboolean Player::checktouchuseanim
(
Conditional &condition
)
{
if ( toucheduseanim )
{
return ( ( UseAnim * )( Entity * )toucheduseanim )->canBeUsed( this );
}
return qfalse;
}
qboolean Player::checkuseanimfinished
(
Conditional &condition
)
{
return ( useanim_numloops <= 0 );
}
qboolean Player::checkatuseobject
(
Conditional &condition
)
{
// Check if the player is at a useanim
if ( atobject && atobject->isSubclassOf( UseObject ) )
{
return ( ( UseObject * )( Entity * )atobject )->canBeUsed( origin, yaw_forward );
}
return false;
}
qboolean Player::checkloopuseobject
(
Conditional &condition
)
{
// Check if the player is at a useanim
if ( useitem_in_use && useitem_in_use->isSubclassOf( UseObject ) )
{
return ( ( UseObject * )( Entity * )useitem_in_use )->Loop();
}
return false;
}
qboolean Player::checkdead
(
Conditional &condition
)
{
return ( deadflag );
}
qboolean Player::checkhealth
(
Conditional &condition
)
{
return health < atoi( condition.getParm( 1 ) );
}
qboolean Player::checkpain
(
Conditional &condition
)
{
return ( pain != 0 || knockdown != 0 );
}
qboolean Player::checkknockdown
(
Conditional &condition
)
{
if ( knockdown )
{
knockdown = false;
return true;
}
else
{
return false;
}
}
qboolean Player::checkpaintype
(
Conditional &condition
)
{
if( pain_type == MOD_NameToNum( condition.getParm( 1 ) ) )
{
return qtrue;
}
else
{
return qfalse;
}
}
qboolean Player::checkpaindirection
(
Conditional &condition
)
{
if( pain_dir == Pain_string_to_int( condition.getParm( 1 ) ) )
{
return qtrue;
}
else
{
return qfalse;
}
}
qboolean Player::checkpainlocation
(
Conditional &condition
)
{
str sLocationName;
int iLocationNum;
sLocationName = condition.getParm( 1 );
if( !sLocationName.icmp( "miss" ) )
iLocationNum = LOCATION_MISS;
else if( !sLocationName.icmp( "general" ) )
iLocationNum = LOCATION_GENERAL;
else if( !sLocationName.icmp( "head" ) )
iLocationNum = LOCATION_HEAD;
else if( !sLocationName.icmp( "helmet" ) )
iLocationNum = LOCATION_HELMET;
else if( !sLocationName.icmp( "neck" ) )
iLocationNum = LOCATION_NECK;
else if( !sLocationName.icmp( "torso_upper" ) )
iLocationNum = LOCATION_TORSO_UPPER;
else if( !sLocationName.icmp( "torso_mid" ) )
iLocationNum = LOCATION_TORSO_MID;
else if( !sLocationName.icmp( "torso_lower" ) )
iLocationNum = LOCATION_TORSO_LOWER;
else if( !sLocationName.icmp( "pelvis" ) )
iLocationNum = LOCATION_PELVIS;
else if( !sLocationName.icmp( "r_arm_upper" ) )
iLocationNum = LOCATION_R_ARM_UPPER;
else if( !sLocationName.icmp( "l_arm_upper" ) )
iLocationNum = LOCATION_L_ARM_UPPER;
else if( !sLocationName.icmp( "r_leg_upper" ) )
iLocationNum = LOCATION_R_LEG_UPPER;
else if( !sLocationName.icmp( "l_leg_upper" ) )
iLocationNum = LOCATION_L_LEG_UPPER;
else if( !sLocationName.icmp( "r_arm_lower" ) )
iLocationNum = LOCATION_R_ARM_LOWER;
else if( !sLocationName.icmp( "l_arm_lower" ) )
iLocationNum = LOCATION_L_ARM_LOWER;
else if( !sLocationName.icmp( "r_leg_lower" ) )
iLocationNum = LOCATION_R_LEG_LOWER;
else if( !sLocationName.icmp( "l_leg_lower" ) )
iLocationNum = LOCATION_L_LEG_LOWER;
else if( !sLocationName.icmp( "r_hand" ) )
iLocationNum = LOCATION_R_HAND;
else if( !sLocationName.icmp( "l_hand" ) )
iLocationNum = LOCATION_L_HAND;
else if( !sLocationName.icmp( "r_foot" ) )
iLocationNum = LOCATION_R_FOOT;
else if( !sLocationName.icmp( "l_foot" ) )
iLocationNum = LOCATION_L_FOOT;
else
{
Com_Printf( "CondPainLocation: Unknown player hit location %s\n", sLocationName.c_str() );
}
return ( pain_location == iLocationNum );
}
qboolean Player::checkpainthreshold
(
Conditional &condition
)
{
float threshold = atof( condition.getParm( 1 ) );
if ( ( pain >= threshold ) && ( level.time > nextpaintime ) )
{
pain = 0; // zero out accumulation since we are going into a pain anim right now
return true;
}
else
{
return false;
}
}
qboolean Player::checklegsstate
(
Conditional &condition
)
{
if ( currentState_Legs )
{
str current = currentState_Legs->getName();
str compare = condition.getParm( 1 );
if ( current == compare )
{
return true;
}
}
return false;
}
qboolean Player::checktorsostate
(
Conditional &condition
)
{
if ( currentState_Torso )
{
str current = currentState_Torso->getName();
str compare = condition.getParm( 1 );
if ( current == compare )
{
return true;
}
}
return false;
}
qboolean Player::checkhasweapon
(
Conditional &condition
)
{
return WeaponsOut();
}
qboolean Player::checknewweapon
(
Conditional &condition
)
{
Weapon * weapon;
weapon = GetNewActiveWeapon();
if ( weapon )
return true;
else
return false;
}
qboolean Player::checkreload( Conditional &condition )
{
Weapon *weapon;
weaponhand_t hand = WEAPON_MAIN;
if( condition.numParms() > 0 )
{
hand = WeaponHandNameToNum( condition.getParm( 1 ) );
if( hand == WEAPON_ERROR )
return qfalse;
}
weapon = GetActiveWeapon( WEAPON_MAIN );
if( !weapon )
return qfalse;
if( weapon->ShouldReload() && weapon->HasAmmo( FIRE_PRIMARY ) )
return qtrue;
return qfalse;
}
// Check to see if a weapon has been raised
qboolean Player::checkuseweapon
(
Conditional &condition
)
{
const char *weaponName;
const char *parm;
weaponhand_t hand;
Weapon *weap;
weap = GetNewActiveWeapon();
parm = condition.getParm( 1 );
if ( !str::icmp( parm, "ERROR" ) )
{
if ( weap )
warning( "Player::checkuseweapon", "%s does not have a valid RAISE_WEAPON state\n", weap->item_name.c_str() );
else
warning( "Player::checkuseweapon", "New Active weapon does not exist\n" );
ClearNewActiveWeapon();
return qtrue;
}
hand = WeaponHandNameToNum( parm );
if ( hand == WEAPON_ERROR )
return false;
weaponName = condition.getParm( 2 );
if (
( weap != NULL ) &&
( GetNewActiveWeaponHand() == hand ) &&
( !Q_stricmp( weap->item_name, weaponName ) )
)
{
return true;
}
else
{
return false;
}
}
qboolean Player::checkuseweaponclass( Conditional &condition )
{
const char *weaponClass;
const char *parm;
weaponhand_t hand;
Weapon *weap;
weap = GetNewActiveWeapon();
parm = condition.getParm( 1 );
if( !str::icmp( parm, "ERROR" ) )
{
if( weap )
warning( "Player::checkuseweaponclass", "%s does not have a valid RAISE_WEAPON state\n", weap->getName().c_str() );
else
warning( "Player::checkuseweaponclass", "New Active weapon does not exist\n" );
ClearNewActiveWeapon();
return qtrue;
}
hand = WeaponHandNameToNum( parm );
if( hand == WEAPON_ERROR )
return false;
weaponClass = condition.getParm( 2 );
if(
( weap != NULL ) &&
( weap->isSubclassOf( Weapon ) ) &&
( GetNewActiveWeaponHand() == hand ) &&
( weap->GetWeaponClass() & G_WeaponClassNameToNum( weaponClass ) )
)
{
return true;
}
else
{
return false;
}
}
// Checks to see if any weapon is active in the specified hand
qboolean Player::checkanyweaponactive
(
Conditional &condition
)
{
weaponhand_t hand;
Weapon *weap;
hand = WeaponHandNameToNum( condition.getParm( 1 ) );
if ( hand == WEAPON_ERROR )
return false;
weap = GetActiveWeapon( hand );
return ( weap != NULL );
}
// Checks to see if any weapon is active in the specified hand
qboolean Player::checkweaponhasammo
(
Conditional &condition
)
{
weaponhand_t hand;
Weapon *weap;
firemode_t mode = FIRE_PRIMARY;
hand = WeaponHandNameToNum( condition.getParm( 1 ) );
if ( condition.numParms() > 1 )
mode = WeaponModeNameToNum( condition.getParm( 2 ) );
if ( hand == WEAPON_ERROR )
return false;
weap = GetActiveWeapon( hand );
if ( !weap )
return false;
else
return ( weap->HasAmmo( mode ) );
}
qboolean Player::checkweaponhasammoinclip( Conditional &condition )
{
weaponhand_t hand;
Weapon *weap;
firemode_t mode = FIRE_PRIMARY;
hand = WeaponHandNameToNum( condition.getParm( 1 ) );
if( condition.numParms() > 1 )
mode = WeaponModeNameToNum( condition.getParm( 2 ) );
if( hand == WEAPON_ERROR )
return false;
weap = GetActiveWeapon( hand );
if( !weap )
return false;
else
return ( weap->HasAmmoInClip( mode ) );
}
qboolean Player::checkmuzzleclear
(
Conditional &condition
)
{
weaponhand_t hand;
hand = WeaponHandNameToNum( condition.getParm( 1 ) );
if ( hand == WEAPON_ERROR )
return false;
Weapon *weapon = GetActiveWeapon( hand );
return ( weapon && weapon->MuzzleClear() );
}
// Checks to see if weapon is active
qboolean Player::checkweaponactive( Conditional &condition )
{
const char *weaponName;
weaponhand_t hand;
weaponName = condition.getParm( 2 );
hand = WeaponHandNameToNum( condition.getParm( 1 ) );
if ( hand == WEAPON_ERROR )
return false;
Weapon *weapon = GetActiveWeapon( hand );
return ( weapon && !Q_stricmp( weaponName, weapon->item_name ) );
}
qboolean Player::checkweaponclassactive( Conditional &condition )
{
const char *weaponClass;
weaponhand_t hand;
weaponClass = condition.getParm( 2 );
hand = WeaponHandNameToNum( condition.getParm( 1 ) );
if( hand == WEAPON_ERROR )
return false;
Weapon *weapon = GetActiveWeapon( hand );
return ( weapon && G_WeaponClassNameToNum( weaponClass ) & weapon->GetWeaponClass() );
}
// Checks to see if weapon is active and ready to fire
qboolean Player::checkweaponreadytofire
(
Conditional &condition
)
{
firemode_t mode = FIRE_PRIMARY;
str weaponName = "None";
weaponhand_t hand;
qboolean ready;
if( level.playerfrozen || m_bFrozen || ( flags & FL_IMMOBILE ) )
{
return false;
}
hand = WeaponHandNameToNum( condition.getParm( 1 ) );
if( condition.numParms() > 1 )
weaponName = condition.getParm( 2 );
if( hand == WEAPON_ERROR )
return false;
Weapon *weapon = GetActiveWeapon( hand );
// Weapon there check
if( !weapon )
return false;
// Name check
if( condition.numParms() > 1 )
{
if( strcmp( weaponName, weapon->item_name ) )
{
return false;
}
}
// Ammo check
ready = weapon->ReadyToFire( mode );
return( ready );
}
// Checks to see if weapon is active and ready to fire
qboolean Player::checkweaponclassreadytofire( Conditional &condition )
{
firemode_t mode = FIRE_PRIMARY;
str weaponClass = "None";
weaponhand_t hand;
qboolean ready;
if( level.playerfrozen || m_bFrozen || ( flags & FL_IMMOBILE ) )
{
return false;
}
hand = WeaponHandNameToNum( condition.getParm( 1 ) );
if( condition.numParms() > 1 )
weaponClass = condition.getParm( 2 );
if( hand == WEAPON_ERROR )
return false;
Weapon *weapon = GetActiveWeapon( hand );
// Weapon there check
if( !weapon )
return qfalse;
// Name check
if( condition.numParms() > 1 )
{
if( !( G_WeaponClassNameToNum( weaponClass ) & weapon->GetWeaponClass() ) )
{
return qfalse;
}
}
// Ammo check
ready = weapon->ReadyToFire( mode );
return( ready );
}
qboolean Player::checkweaponreadytofire_nosound
(
Conditional &condition
)
{
firemode_t mode = FIRE_PRIMARY;
str weaponName = "None";
weaponhand_t hand;
qboolean ready;
if( level.playerfrozen || m_bFrozen || ( flags & FL_IMMOBILE ) )
{
return false;
}
hand = WeaponHandNameToNum( condition.getParm( 1 ) );
if( condition.numParms() > 1 )
weaponName = condition.getParm( 2 );
if( hand == WEAPON_ERROR )
return false;
Weapon *weapon = GetActiveWeapon( hand );
// Weapon there check
if( !weapon )
return qfalse;
// Name check
if( condition.numParms() > 1 )
{
if( strcmp( weaponName, weapon->item_name ) )
{
return qfalse;
}
}
// Ammo check
ready = weapon->ReadyToFire( mode, qfalse );
return( ready );
}
qboolean Player::checkweaponsemiauto
(
Conditional &condition
)
{
firemode_t mode = FIRE_PRIMARY;
str handname;
weaponhand_t hand;
handname = condition.getParm( 1 );
hand = WeaponHandNameToNum( handname );
if( hand != WEAPON_ERROR )
{
return GetActiveWeapon( hand )->m_bSemiAuto;
}
else
{
return qfalse;
}
}
// Check to see if any of the active weapons need to be put away
qboolean Player::checkputawayleft
(
Conditional &condition
)
{
Weapon *weapon = GetActiveWeapon( WEAPON_OFFHAND );
return weapon && weapon->GetPutaway();
}
qboolean Player::checkputawayright
(
Conditional &condition
)
{
Weapon *weapon = GetActiveWeapon( WEAPON_MAIN );
return weapon && weapon->GetPutaway();
}
qboolean Player::returnfalse( Conditional &condition )
{
return false;
}
qboolean Player::returntrue( Conditional &condition )
{
return true;
}
qboolean Player::checkstatename
(
Conditional &condition
)
{
str part = condition.getParm( 1 );
str statename = condition.getParm( 2 );
if ( currentState_Legs && !part.icmp( "legs" ) )
{
return ( !statename.icmpn( currentState_Legs->getName(), statename.length() ) );
}
else if ( !part.icmp( "torso" ) )
{
return ( !statename.icmpn( currentState_Torso->getName(), statename.length() ) );
}
return false;
}
qboolean Player::checkattackblocked
(
Conditional &condition
)
{
if ( attack_blocked )
{
attack_blocked = qfalse;
return true;
}
else
{
return false;
}
}
qboolean Player::checkblockdelay
(
Conditional &condition
)
{
float t = atof ( condition.getParm( 1 ) );
return ( level.time > ( attack_blocked_time + t ) );
}
qboolean Player::checkpush
(
Conditional &condition
)
{
// Check if the player is at a pushobject
if ( atobject && atobject->isSubclassOf( PushObject ) && ( atobject_dist < ( PUSH_OBJECT_DISTANCE + 15.0f ) ) )
{
Vector dir;
dir = atobject_dir * 8.0f;
return ( ( PushObject * )( Entity * )atobject )->canPush( dir );
}
return qfalse;
}
qboolean Player::checkpull
(
Conditional &condition
)
{
// Check if the player is at a pushobject
if ( atobject && atobject->isSubclassOf( PushObject ) && ( atobject_dist < ( PUSH_OBJECT_DISTANCE + 15.0f ) ) )
{
Vector dir;
dir = atobject_dir * -64.0f;
return ( ( PushObject * )( Entity * )atobject )->canPush( dir );
}
return qfalse;
}
#define LADDER_HAND_HEIGHT ( MAXS_X - MINS_X )
qboolean Player::checkladder
(
Conditional &condition
)
{
trace_t trace;
Vector forward;
Vector start, end;
AngleVectors( m_vViewAng, forward, NULL, NULL );
start = ( m_vViewPos - forward * 12.0f );
end = ( m_vViewPos + forward * 128.0f );
trace = G_Trace( start, vec_zero, vec_zero, end, this, MASK_LADDER, qfalse, "checkladder" );
if( trace.fraction == 1.0f || !trace.ent ||
!trace.ent->entity || !trace.ent->entity->isSubclassOf( FuncLadder ) )
{
return qfalse;
}
return ( ( FuncLadder * )trace.ent->entity )->CanUseLadder( this );
}
qboolean Player::checktopladder
(
Conditional &condition
)
{
if( !m_pLadder ) {
return false;
}
if( maxs[ 2 ] + origin[ 2 ] > m_pLadder->absmax[ 2 ] ) {
return true;
}
return false;
}
qboolean Player::checkcangetoffladdertop
(
Conditional &condition
)
{
Vector vForward, vStart, vEnd;
trace_t trace;
angles.AngleVectorsLeft( &vForward );
vStart = origin - vForward * 12.0f;
vStart[ 2 ] += maxs[ 2 ] - 8.0f;
vEnd = vStart + vForward * 40.0f;
trace = G_Trace( vStart,
vec_zero,
vec_zero,
vEnd,
this,
MASK_LADDER,
qtrue,
"Player::CondCanGetOffLadderTop 1" );
if( trace.fraction >= 1.0f )
{
vStart = origin;
vEnd = origin;
vEnd[ 2 ] += 98.0f;
if( G_SightTrace( vStart,
mins,
maxs,
vEnd,
this,
NULL,
MASK_BEAM,
true,
"Player::CondCanGetOffLadderTop 2" ) )
{
vStart = vEnd;
vEnd = vStart + yaw_forward * 16.0f;
return G_SightTrace( vStart,
mins,
maxs,
vEnd,
this,
NULL,
MASK_BEAM,
true,
"Player::CondCanGetOffLadderTop 3" );
}
}
return false;
}
qboolean Player::checkcangetoffladderbottom
(
Conditional &condition
)
{
Vector vStart, vEnd;
trace_t trace;
vStart = origin;
vEnd = origin;
vEnd[ 2 ] -= 40.0f;
trace = G_Trace(
vStart,
mins,
maxs,
vEnd,
edict,
MASK_BEAM,
true,
"Player::checkcangetoffladerbottom" );
if( trace.fraction != 1.0f )
{
return ( trace.entityNum == ENTITYNUM_WORLD );
}
return false;
}
qboolean Player::checkcanclimbupladder
(
Conditional &condition
)
{
trace_t trace;
Vector fwd;
Vector vec;
Vector start, end;
AngleVectorsLeft( angles, fwd, NULL, NULL );
start = origin - fwd * 12.0f;
start[ 2 ] += maxs[ 2 ] - 8.0f;
end = start + fwd * 40.0f;
// check the normal bounding box first and trace to that position
trace = G_Trace( start, vec_zero, vec_zero, end, this, MASK_LADDER, qtrue, "Player::CondCanClimbUpLadder" );
if( ( trace.fraction == 1.0f ) || ( !trace.ent ) || ( !trace.ent->entity ) ||
( !trace.ent->entity->isSubclassOf( FuncLadder ) ) )
{
return qfalse;
}
Vector vEnd = ( origin + Vector( 0, 0, 16 ) );
return G_SightTrace( origin,
mins,
maxs,
vEnd,
this,
NULL,
MASK_BEAM,
qtrue,
"Player::CondCanClimbUpLadder" );
}
qboolean Player::checkcanclimbdownladder
(
Conditional &condition
)
{
Vector vEnd = origin - Vector( 0, 0, 16 );
return G_SightTrace( origin,
mins,
maxs,
vEnd,
this,
NULL,
MASK_BEAM,
qtrue,
"Player::CondCanClimbDownLadder" );
}
qboolean Player::checkfeetatladder
(
Conditional &condition
)
{
trace_t trace;
Vector newmins, newmaxs;
Vector end( origin + yaw_forward * 20.0f );
// the bounding box is made skinnier to account for the feet
newmaxs.x = MAXS_X / 2;
newmaxs.y = MAXS_Y / 2;
// just underneath the feet
newmaxs.z = 28;
newmins.x = MINS_X / 2;
newmins.y = MINS_Y / 2;
newmins.z = 0;
trace = G_Trace( origin, newmins, newmaxs, end, this, MASK_SOLID, true, "checkfeetatladder" );
if ( ( trace.fraction == 1.0f ) || !( trace.surfaceFlags & SURF_LADDER ) )
{
return qfalse;
}
return qtrue;
}
qboolean Player::checkonladder
(
Conditional &condition
)
{
return m_pLadder != NULL;
}
qboolean Player::checkcanstand
(
Conditional &condition
)
{
Vector newmins( mins );
Vector newmaxs( maxs );
trace_t trace;
newmins[ 2 ] = MINS_Z;
newmaxs[ 2 ] = MAXS_Z;
trace = G_Trace( origin, newmins, newmaxs, origin, this, MASK_PLAYERSOLID, true, "checkcanstand" );
if ( trace.startsolid )
{
return qfalse;
}
return qtrue;
}
qboolean Player::checkchance
(
Conditional &condition
)
{
float percent_chance;
percent_chance = atof( condition.getParm( 1 ) );
return ( G_Random() < percent_chance );
}
qboolean Player::checkinturret( Conditional &condition )
{
return ( m_pTurret != NULL );
}
qboolean Player::checkinvehicle( Conditional &condition )
{
return ( m_pVehicle != NULL );
}
qboolean Player::checkturrettype( Conditional &condition )
{
str name = condition.getParm( 1 );
if( m_pTurret )
{
return m_pTurret->getName() == name;
}
else
{
return name == "none";
}
}
qboolean Player::checkduckedviewinwater( Conditional &condition )
{
Vector vPos = origin;
vPos[ 2 ] += 48.0f;
return ( gi.PointContents( vPos, 0 ) & MASK_WATER ) != 0;
}
qboolean Player::checkviewinwater( Conditional &condition )
{
return ( gi.PointContents( m_vViewPos, 0 ) & MASK_WATER ) != 0;
}
qboolean Player::checksolidforward
(
Conditional &condition
)
{
// Trace out forward to see if there is a solid ahead
float dist = atof( condition.getParm( 1 ) );
Vector end( centroid + yaw_forward * dist );
Vector vMins( mins.x, mins.y, -8 );
Vector vMaxs( maxs.x, maxs.y, 8 );
trace_t trace = G_Trace( centroid, vMins, vMaxs,
end, this, MASK_SOLID, true, "Player::checksolidforward" );
return ( trace.fraction < 0.7f );
}
qboolean Player::checkweaponsholstered
(
Conditional &condition
)
{
if( holsteredWeapon )
{
return qtrue;
}
else
{
return qfalse;
}
}
qboolean Player::checkmovementtype( Conditional &condition )
{
int flags = 0;
str s;
s = condition.getParm( 1 );
if( !s.icmp( "walking" ) )
{
flags = MPF_MOVEMENT_WALKING;
}
else if( !s.icmp( "running" ) )
{
flags = MPF_MOVEMENT_RUNNING;
}
else if( !s.icmp( "falling" ) )
{
flags = MPF_MOVEMENT_FALLING;
}
return ( m_iMovePosFlags & flags );
}
qboolean Player::checkpositiontype( Conditional &condition )
{
int flags = 0;
str s;
s = condition.getParm( 1 );
if( !s.icmp( "crouching" ) )
{
flags = MPF_POSITION_CROUCHING;
}
else if( !s.icmp( "prone" ) )
{
flags = MPF_POSITION_PRONE;
}
else if( !s.icmp( "offground" ) )
{
flags = MPF_POSITION_OFFGROUND;
}
else
{
flags = MPF_POSITION_STANDING;
}
return ( m_iMovePosFlags & flags );
}
qboolean Player::checkforwardvelocity( Conditional &condition )
{
if( condition.numParms() )
{
return move_forward_vel >= atof( condition.getParm( 1 ) );
}
else
{
return move_forward_vel > 4.0f;
}
return qfalse;
}
qboolean Player::checkminchargetimemet( Conditional &condition )
{
const char *handname;
weaponhand_t hand;
Weapon *weap;
handname = condition.getParm( 1 );
hand = WeaponHandNameToNum( handname );
if( hand != WEAPON_ERROR )
{
weap = GetActiveWeapon( hand );
if( weap )
{
float charge_time = weap->GetMinChargeTime( FIRE_PRIMARY );
if( charge_time )
{
if( charge_start_time )
{
return level.time - charge_start_time >= charge_time;
}
else
{
return qfalse;
}
}
else
{
return qtrue;
}
}
}
return qfalse;
}
qboolean Player::checkmaxchargetimemet( Conditional &condition )
{
const char *handname;
weaponhand_t hand;
Weapon *weap;
handname = condition.getParm( 1 );
hand = WeaponHandNameToNum( handname );
if( hand != WEAPON_ERROR )
{
weap = GetActiveWeapon( hand );
if( weap )
{
float charge_time = weap->GetMaxChargeTime( FIRE_PRIMARY );
if( charge_time )
{
if( charge_start_time )
{
return level.time - charge_start_time >= charge_time;
}
else
{
return qfalse;
}
}
else
{
return qtrue;
}
}
}
return qfalse;
}
qboolean Player::checkimmediateswitch( Conditional &condition )
{
static cvar_t *g_immediateswitch = NULL;
if( !g_immediateswitch )
g_immediateswitch = gi.Cvar_Get( "g_immediateswitch", "0", 0 );
return ( g_gametype->integer && g_immediateswitch->integer );
}
qboolean Player::checkmovementspeed(Conditional& condition)
{
int speed = atoi(condition.getParm(1));
return client->ps.speed >= speed;
}
qboolean Player::checkabletodefuse(Conditional& condition)
{
// FIXME: unimplemented
return true;
}
qboolean Player::checkonlandmine(Conditional& condition)
{
// FIXME: unimplemented
return false;
}
qboolean Player::checknearlandmine(Conditional& condition)
{
// FIXME: unimplemented
return false;
}
qboolean Player::CondCanPlaceLandmine(Conditional& condition)
{
// FIXME: unimplemented
return false;
}
qboolean Player::CondWeaponCurrentFireAnim(Conditional& condition)
{
// FIXME: unimplemented
return false;
}
qboolean Player::CondVehicleType(Conditional& condition)
{
// FIXME: unimplemented
return false;
}
qboolean Player::CondAnimDoneVM( Conditional &condition )
{
return animDoneVM;
}
qboolean Player::CondClientCommand( Conditional &condition )
{
str command = condition.getParm( 1 );
if( !command.icmp( m_lastcommand ) )
{
return qtrue;
}
else
{
return qfalse;
}
}
qboolean Player::CondVMAnim( Conditional &condition )
{
return condition.getParm( 1 ) == m_sVMcurrent;
}
qboolean Player::CondVariable( Conditional &condition )
{
// parameters
str var_name;
str value_operator;
Player * player = ( Player* )this;
// variables
int cmp_int = 0, var_int = 0;
float cmp_float = 0.0f, var_float = 0.0f;
char *cmp_str = NULL;
char *var_str = NULL;
ScriptVariableList * variableList = NULL;
ScriptVariable * variable = NULL;
char _operator[ 2 ];
size_t i, nLength;
size_t indexval = -1;
int founds = 0;
qboolean isString = qfalse, isFloat = qfalse, isInteger = qfalse;
var_name = condition.getParm( 1 );
value_operator = condition.getParm( 2 );
if( !var_name )
{
gi.Printf( "Var_CompareValue : the variable was not specified !\n", condition.getName() );
return qfalse;
}
else if( !value_operator )
{
gi.Printf( "Var_CompareValue : the value was not specified !\n", condition.getName() );
return qfalse;
}
nLength = value_operator.length();
// Lookup for the operator, until we found one
for( i = 0; i < nLength; i++ )
{
if( ( value_operator[ i ] == '<' && value_operator[ i + 1 ] == '=' ) || ( value_operator[ i ] == '>' && value_operator[ i + 1 ] == '=' )
|| ( value_operator[ i ] == '=' && value_operator[ i + 1 ] == '=' ) || ( value_operator[ i ] == '!' && value_operator[ i + 1 ] == '=' )
|| value_operator[ i ] == '<' || value_operator[ i ] == '>'
|| value_operator[ i ] == '&' )
{
if( indexval == -1 ) {
indexval = i;
}
founds++;
}
}
// Fail if we didn't found/found multiples operators
if( !founds )
{
gi.Printf( "Var_CompareValue : unknown/no comparison/relational operator was specified (var_name=\"%s\"|value=\"%s\") !\n", var_name.c_str(), value_operator.c_str() );
return qfalse;
}
else if( founds > 1 )
{
gi.Printf( "Var_CompareValue : more than one operator was specified (var_name='%s'|value='%s') !\n", var_name.c_str(), value_operator.c_str() );
return qfalse;
}
_operator[ 0 ] = value_operator[ indexval ];
_operator[ 1 ] = value_operator[ indexval + 1 ];
// If this is not a greater/less than operator, then the loop
// shouldn't encounter a part of the operator
if( ( _operator[ 0 ] == '<' && _operator[ 1 ] != '=' ) || ( _operator[ 0 ] == '>' && _operator[ 1 ] != '=' ) )
i = indexval;
else
i = indexval + 2;
while( ( value_operator[ i ] == ' ' || value_operator[ i ] == '\0' ) && i < nLength )
i++;
indexval = -1;
founds = 0;
// Loop until we find a character after the operator
for( ; i < nLength; i++ )
{
if( value_operator[ i ] != '\0' && value_operator[ i ] != ' ' && value_operator[ i ] != _operator[ 0 ] && value_operator[ i ] != _operator[ 1 ] )
{
if( indexval == -1 )
indexval = i;
founds++;
}
}
if( !founds )
{
gi.Printf( "Var_CompareValue : no value was specified after the operator ! (var_name=\"%s\") !\n", var_name.c_str() );
return qfalse;
}
// Get the variable list from the player
variableList = this->Vars();
// Get the variable from the variable list
variable = variableList->GetVariable( var_name );
if( variable != NULL )
{
isFloat = variable->GetType() == VARIABLE_FLOAT;
isInteger = variable->GetType() == VARIABLE_INTEGER;
isString = variable->GetType() == VARIABLE_STRING || variable->GetType() == VARIABLE_CONSTSTRING;
if( !isFloat && !isString && !isInteger ) {
gi.Printf( "Var_CompareValue : invalid type \"%s\" (%d) for variable \"%s\"\n", typenames[ variable->GetType() ], variable->GetType(), var_name.c_str() );
return qfalse;
}
// Retrieve the values from the variable
if( isFloat ) {
var_float = variable->floatValue();
}
else {
var_int = variable->intValue();
}
}
cmp_str = ( char * )value_operator.c_str() + indexval;
if( !isString )
{
cmp_int = atoi( cmp_str );
cmp_float = ( float )atof( cmp_str );
}
// If this is a string, compare between the two strings
if( isString )
{
if( _operator[ 0 ] == '=' && _operator[ 1 ] == '=' )
{
// == (EQUAL TO) operator
return strcmp( cmp_str, var_str ) == 0;
}
else if( _operator[ 0 ] == '!' && _operator[ 1 ] == '=' )
{
// != (NOT EQUAL TO) operator
return strcmp( cmp_str, var_str ) != 0;
}
}
// Now compare between the two values with the right operator and return
if( _operator[ 0 ] == '<' )
{
// < (LESS THAN) operator
if( isFloat ) {
return var_float < cmp_float;
}
return var_int < cmp_int;
}
else if( _operator[ 0 ] == '>' )
{
// > (GREATER THAN) operator
if( isFloat ) {
return var_float > cmp_float;
}
return var_int > cmp_int;
}
else if( _operator[ 0 ] == '<' && _operator[ 1 ] == '=' )
{
// <= (LESS THAN OR EQUAL TO) operator
if( isFloat ) {
return var_float <= cmp_float;
}
return var_int <= cmp_int;
}
else if( _operator[ 0 ] == '>' && _operator[ 1 ] == '=' )
{
// >= (GREATER THAN OR EQUAL TO) operator
if( isFloat ) {
return var_float >= cmp_float;
}
return var_int >= cmp_int;
}
else if( _operator[ 0 ] == '!' && _operator[ 1 ] == '=' )
{
// != (NOT EQUAL TO) operator
if( isFloat ) {
return var_float != cmp_float;
}
return var_int != cmp_int;
}
else if( _operator[ 0 ] == '=' && _operator[ 1 ] == '=' )
{
// == (EQUAL TO) operator
if( isFloat ) {
return var_float == cmp_float;
}
return var_int == cmp_int;
}
else if( _operator[ 0 ] == '&' )
{
// & (BITWISE AND) operator
return var_int & cmp_int;
}
return qtrue;
}
CLASS_DECLARATION( Class, Conditional, NULL )
{
{ NULL, NULL }
};
Condition<Player> Player::Conditions[] =
{
{ "default", &Player::returntrue },
{ "SNEAK", &Player::checksneak },
{ "RUN", &Player::checkrun },
{ "USE", &Player::checkuse },
{ "LEFT", &Player::checkturnleft },
{ "RIGHT", &Player::checkturnright },
{ "FORWARD", &Player::checkforward },
{ "BACKWARD", &Player::checkbackward },
{ "STRAFE_LEFT", &Player::checkstrafeleft },
{ "STRAFE_RIGHT", &Player::checkstraferight },
{ "JUMP", &Player::checkjump },
{ "RISE", &Player::checkrise },
{ "CROUCH", &Player::checkcrouch },
{ "DO_JUMP_FLIP", &Player::checkjumpflip },
{ "ANIMDONE_LEGS", &Player::checkanimdone_legs },
{ "ANIMDONE_TORSO", &Player::checkanimdone_torso },
{ "CAN_TURN", &Player::checkcanturn },
{ "CAN_MOVE_LEFT", &Player::checkcanmoveleft },
{ "CAN_MOVE_RIGHT", &Player::checkcanmoveright },
{ "CAN_MOVE_BACKWARD", &Player::checkcanmovebackward },
{ "CAN_MOVE_FORWARD", &Player::checkcanmoveforward },
{ "CAN_WALL_HUG", &Player::checkcanwallhug },
{ "BLOCKED", &Player::checkblocked },
{ "HAS_VELOCITY", &Player::checkhasvelocity },
{ "CHECK_HEIGHT", &Player::checkheight },
{ "ONGROUND", &Player::checkonground },
{ "SLOPE_22", &Player::check22degreeslope },
{ "SLOPE_45", &Player::check45degreeslope },
{ "LOOKING_UP", &Player::checklookingup },
{ "RIGHT_LEG_HIGH", &Player::checkrightleghigh },
{ "LEFT_LEG_HIGH", &Player::checkleftleghigh },
{ "CAN_FALL", &Player::checkcanfall },
{ "AT_DOOR", &Player::checkatdoor },
{ "FALLING", &Player::checkfalling },
{ "HARD_IMPACT", &Player::checkhardimpact },
{ "MEDIUM_IMPACT", &Player::checkmediumimpact },
{ "KILLED", &Player::checkdead },
{ "HEALTH", &Player::checkhealth },
{ "PAIN", &Player::checkpain },
{ "PAIN_TYPE", &Player::checkpaintype },
{ "PAIN_DIRECTION", &Player::checkpaindirection },
{ "PAIN_LOCATION", &Player::checkpainlocation },
{ "PAIN_THRESHOLD", &Player::checkpainthreshold },
{ "KNOCKDOWN", &Player::checkknockdown },
{ "LEGS", &Player::checklegsstate },
{ "TORSO", &Player::checktorsostate },
{ "AT_USEANIM", &Player::checkatuseanim },
{ "TOUCHEDUSEANIM", &Player::checktouchuseanim },
{ "FINISHEDUSEANIM", &Player::checkuseanimfinished },
{ "AT_USEOBJECT", &Player::checkatuseobject },
{ "LOOP_USEOBJECT", &Player::checkloopuseobject },
{ "CAN_PUSH", &Player::checkpush },
{ "CAN_PULL", &Player::checkpull },
{ "AT_LADDER", &Player::checkladder },
{ "AT_TOP_OF_LADDER", &Player::checktopladder },
{ "CAN_GET_OFF_LADDER_TOP", &Player::checkcangetoffladdertop },
{ "CAN_GET_OFF_LADDER_BOTTOM", &Player::checkcangetoffladderbottom },
{ "FEET_AT_LADDER", &Player::checkfeetatladder },
{ "CAN_CLIMB_UP_LADDER", &Player::checkcanclimbupladder },
{ "CAN_CLIMB_DOWN_LADDER", &Player::checkcanclimbdownladder },
{ "ON_LADDER", &Player::checkonladder },
{ "CAN_STAND", &Player::checkcanstand },
{ "CHANCE", &Player::checkchance },
{ "FACING_UP_SLOPE", &Player::checkfacingupslope },
{ "FACING_DOWN_SLOPE", &Player::checkfacingdownslope },
{ "IS_USING_TURRET", &Player::checkinturret },
{ "IS_USING_VEHICLE", &Player::checkinvehicle },
{ "TURRET_TYPE", &Player::checkturrettype },
{ "DUCKED_VIEW_IN_WATER", &Player::checkduckedviewinwater },
{ "VIEW_IN_WATER", &Player::checkviewinwater },
{ "SOLID_FORWARD", &Player::checksolidforward },
{ "GROUNDENTITY", &Player::checkgroundentity },
{ "MOVEMENT_TYPE", &Player::checkmovementtype },
{ "POSITION_TYPE", &Player::checkpositiontype },
{ "FORWARD_VELOCITY", &Player::checkforwardvelocity },
// Weapon conditions
{ "ATTACK_PRIMARY", &Player::checkattackleft }, // Checks to see if there is an active weapon as well as the button being pressed
{ "ATTACK_SECONDARY", &Player::checkattackright }, // Checks to see if there is an active weapon as well as the button being pressed
{ "ATTACK_PRIMARY_BUTTON", &Player::checkattackbuttonleft }, // Checks to see if the left attack button is pressed
{ "ATTACK_SECONDARY_BUTTON", &Player::checkattackbuttonright },// Checks to see if the right attack button is pressed
{ "HAS_WEAPON", &Player::checkhasweapon },
{ "NEW_WEAPON", &Player::checknewweapon },
{ "RELOAD", &Player::checkreload },
{ "IS_NEW_WEAPON", &Player::checkuseweapon },
{ "IS_NEW_WEAPONCLASS", &Player::checkuseweaponclass },
{ "IS_WEAPON_ACTIVE", &Player::checkweaponactive },
{ "IS_WEAPONCLASS_ACTIVE", &Player::checkweaponclassactive },
{ "IS_WEAPON_READY_TO_FIRE", &Player::checkweaponreadytofire },
{ "IS_WEAPONCLASS_READY_TO_FIRE", &Player::checkweaponclassreadytofire },
{ "IS_WEAPON_READY_TO_FIRE_NOSOUND", &Player::checkweaponreadytofire_nosound },
{ "IS_WEAPON_SEMIAUTO", &Player::checkweaponsemiauto },
{ "PUTAWAYLEFT", &Player::checkputawayleft },
{ "PUTAWAYMAIN", &Player::checkputawayright },
{ "ANY_WEAPON_ACTIVE", &Player::checkanyweaponactive },
{ "ATTACK_BLOCKED", &Player::checkattackblocked },
{ "STATE_ACTIVE", &Player::checkstatename },
{ "BLOCK_DELAY", &Player::checkblockdelay },
{ "MUZZLE_CLEAR", &Player::checkmuzzleclear },
{ "HAS_AMMO", &Player::checkweaponhasammo },
{ "HAS_AMMO_IN_CLIP", &Player::checkweaponhasammoinclip },
{ "WEAPONS_HOLSTERED", &Player::checkweaponsholstered },
{ "MIN_CHARGE_TIME_MET", &Player::checkminchargetimemet },
{ "MAX_CHARGE_TIME_MET", &Player::checkmaxchargetimemet },
{ "IMMEDIATE_SWITCH", &Player::checkimmediateswitch },
{ "CHECK_MOVEMENT_SPEED", &Player::checkmovementspeed },
{ "ABLE_TO_DEFUSE", &Player::checkabletodefuse },
{ "ON_LANDMINE", &Player::checkonlandmine },
{ "NEAR_LANDMINE", &Player::checknearlandmine },
{ "CAN_PLACE_LANDMINE", &Player::CondCanPlaceLandmine },
{ "WEAPON_CURRENT_FIRE_ANIM", &Player::CondWeaponCurrentFireAnim },
{ "VEHICLE_TYPE", &Player::CondVehicleType },
{ "ANIMDONE_VM", &Player::CondAnimDoneVM },
{ "CLIENT_COMMAND", &Player::CondClientCommand },
{ "IS_VM_ANIM", &Player::CondVMAnim },
{ "VAR_OPERATOR", &Player::CondVariable },
{ NULL, NULL },
};
movecontrolfunc_t Player::MoveStartFuncs[] =
{
NULL, // MOVECONTROL_USER, // Quake style
NULL, // MOVECONTROL_LEGS, // Quake style, legs state system active
NULL, // MOVECONTROL_USER_MOVEANIM, // Quake style, legs state system active
NULL, // MOVECONTROL_ANIM, // move based on animation, with full collision testing
NULL, // MOVECONTROL_ABSOLUTE, // move based on animation, with full collision testing but no turning
NULL, // MOVECONTROL_HANGING, // move based on animation, with full collision testing, hanging
NULL, // MOVECONTROL_ROPE_GRAB
NULL, // MOVECONTROL_ROPE_RELEASE
NULL, // MOVECONTROL_ROPE_MOVE
NULL, // MOVECONTROL_PICKUPENEMY
&Player::StartPush, // MOVECONTROL_PUSH
NULL, // MOVECONTROL_CLIMBWALL
&Player::StartUseAnim, // MOVECONTROL_USEANIM
NULL, // MOVECONTROL_CROUCH
&Player::StartLoopUseAnim, // MOVECONTROL_LOOPUSEANIM
&Player::SetupUseObject, // MOVECONTROL_USEOBJECT
NULL, // MOVECONTROL_COOLOBJECT
};
Player::Player()
{
//
// set the entity type
//
entflags |= EF_PLAYER;
mCurTrailOrigin = 0;
m_pLastSpawnpoint = NULL;
if( LoadingSavegame ) {
return;
}
edict->s.eType = ET_PLAYER;
buttons = 0;
server_new_buttons = 0;
statemap_Legs = NULL;
statemap_Torso = NULL;
new_buttons = 0;
m_iPartSlot[ 1 ] = 2;
respawn_time = -1.0f;
m_fPartBlends[ 0 ] = 0;
m_fPartBlends[ 1 ] = 0;
m_iPartSlot[ 0 ] = 0;
partBlendMult[ 0 ] = 0;
partBlendMult[ 1 ] = 0;
m_fOldActionAnimFadeTime = 0;
m_bActionAnimPlaying = false;
m_fLastDeltaTime = level.time;
m_iBaseActionAnimSlot = 0;
m_iActionAnimType = 0;
m_fOldActionAnimWeight = 0;
m_fOldActionAnimFadeTime = 0;
m_bMovementAnimPlaying = false;
m_fOldMovementWeight = 0;
camera = NULL;
atobject = NULL;
atobject_dist = 0;
toucheduseanim = NULL;
useitem_in_use = NULL;
damage_blood = 0;
damage_count = 0;
damage_from = vec_zero;
damage_alpha = 0;
damage_yaw = 0;
fAttackerDispTime = 0;
pAttackerDistPointer = NULL;
moveresult = 0;
last_attack_button = 0;
attack_blocked = false;
canfall = false;
move_left_vel = 0;
move_right_vel = 0;
move_backward_vel = 0;
move_forward_vel = 0;
move_up_vel = 0;
move_down_vel = 0;
animspeed = 0;
airspeed = 200.0f;
weapons_holstered_by_code = false;
actor_camera = NULL;
dm_team = TEAM_NONE;
damage_multiplier = 1.0f;
take_pain = true;
current_team = NULL;
num_deaths = 0;
num_kills = 0;
num_won_matches = 0;
m_bTempSpectator = false;
m_bSpectator = false;
m_iPlayerSpectating = 0;
m_bAllowFighting = false;
m_bReady = true;
m_fTeamSelectTime = -30.0f;
voted = false;
votecount = 0;
m_fWeapSelectTime = 0;
SetSelectedFov( atof( Info_ValueForKey( client->pers.userinfo, "fov" ) ) );
SetFov( selectedfov );
m_iInZoomMode = 0;
m_iNumShotsFired = 0;
m_iNumGroinShots = 0;
m_iNumHeadShots = 0;
m_iNumHits = 0;
m_iNumLeftArmShots = 0;
m_iNumLeftLegShots = 0;
m_iNumRightArmShots = 0;
m_iNumRightLegShots = 0;
m_iNumTorsoShots = 0;
m_bShowingHint = false;
m_sPerferredWeaponOverride = "";
SetTargetName( "player" );
disable_spectate = false;
disable_team_change = false;
m_bFrozen = false;
animDoneVM = true;
m_fVMAtime = 0;
m_fpsTiki = NULL;
for( int i = 0; i < MAX_SPEED_MULTIPLIERS; i++ )
{
speed_multiplier[ i ] = 1.0f;
}
m_pKilledEvent = NULL;
m_bConnected = false;
Init();
for( int i = 0; i < MAX_TRAILS; i++ )
{
mvTrail[ i ] = vec_zero;
}
for( int i = 0; i < MAX_TRAILS; i++ )
{
mvTrailEyes[ i ] = vec_zero;
}
client->ps.pm_flags &= ~PMF_NO_HUD;
}
Player::~Player()
{
int i, num;
Conditional *cond;
gi.DPrintf("Player::~Player()\n");
//assert(0);
num = legs_conditionals.NumObjects();
for( i = num; i>0; i-- )
{
cond = legs_conditionals.ObjectAt( i );
delete cond;
}
num = torso_conditionals.NumObjects();
for( i = num; i>0; i-- )
{
cond = torso_conditionals.ObjectAt( i );
delete cond;
}
legs_conditionals.FreeObjectList();
torso_conditionals.FreeObjectList();
}
static qboolean logfile_started = qfalse;
void Player::Init( void )
{
InitClient();
InitPhysics();
InitPowerups();
InitWorldEffects();
InitSound();
InitView();
InitState();
InitEdict();
InitWeapons();
InitInventory();
InitHealth();
InitStats();
InitModel();
LoadStateTable();
if( g_gametype->integer )
{
InitDeathmatch();
}
else if( !LoadingSavegame )
{
ChooseSpawnPoint();
JoinNearbySquads();
}
InitMaxAmmo();
// notify scripts for the spawning player
parm.other = this;
parm.owner = this;
level.Unregister( STRING_PLAYERSPAWN );
// make sure we put the player back into the world
link();
logfile_started = qfalse;
if( !m_bConnected )
{
m_bConnected = true;
Event *ev = new Event;
ev->AddEntity( this );
scriptedEvents[ SE_CONNECTED ].Trigger( ev );
}
Spawned();
}
void Player::InitEdict( void )
{
// entity state stuff
setSolidType( SOLID_BBOX );
setMoveType( MOVETYPE_WALK );
edict->clipmask = MASK_PLAYERSOLID;
setSize( Vector( -16, -16, 0 ), Vector( 16, 16, 72 ) );
edict->r.contents = CONTENTS_BODY;
edict->r.ownerNum = ENTITYNUM_NONE;
// clear entity state values
edict->s.eFlags = 0;
edict->s.wasframe = 0;
// players have precise shadows
edict->s.renderfx |= RF_SHADOW_PRECISE | RF_SHADOW;
}
void Player::InitSound
(
void
)
{
//
// reset the music
//
client->ps.current_music_mood = mood_normal;
client->ps.fallback_music_mood = mood_normal;
ChangeMusic( "normal", "normal", false );
client->ps.music_volume = 1.0;
client->ps.music_volume_fade_time = 0.0;
ChangeMusicVolume( 1.0, 0.0 );
music_forced = false;
// Reset the reverb stuff
client->ps.reverb_type = eax_generic;
client->ps.reverb_level = 0;
SetReverb( client->ps.reverb_type, client->ps.reverb_level );
}
void Player::InitClient( void )
{
clientPersistant_t saved;
// deathmatch wipes most client data every spawn
if ( g_gametype->integer )
{
char userinfo[ MAX_INFO_STRING ];
char dm_primary[ MAX_QPATH ];
float enterTime = client->pers.enterTime;
teamtype_t team = client->pers.team;
int round_kills = client->pers.kills;
memcpy( userinfo, client->pers.userinfo, sizeof( userinfo ) );
memcpy( dm_primary, client->pers.weapon, sizeof( dm_primary ) );
G_InitClientPersistant( client );
G_ClientUserinfoChanged( edict, userinfo );
memcpy( client->pers.weapon, dm_primary, sizeof( client->pers.weapon ) );
client->pers.enterTime = enterTime;
client->pers.team = team;
client->pers.kills = round_kills;
}
// clear everything but the persistant data and fov
saved = client->pers;
memset( client, 0, sizeof( *client ) );
client->pers = saved;
client->ps.clientNum = client - game.clients;
client->lastActiveTime = level.inttime;
client->ps.commandTime = level.svsTime;
gi.SendServerCommand( client - game.clients, "stopwatch 0 0" );
m_bShowingHint = false;
}
void Player::InitState
(
void
)
{
gibbed = false;
pain = 0;
nextpaintime = 0;
knockdown = false;
pain_dir = PAIN_NONE;
pain_type = MOD_NONE;
pain_location = -2;
m_iMovePosFlags = MPF_POSITION_STANDING;
takedamage = DAMAGE_AIM;
deadflag = DEAD_NO;
flags &= ~FL_TEAMSLAVE;
flags |= ( FL_POSTTHINK | FL_THINK | FL_DIE_EXPLODE | FL_BLOOD );
if( !com_blood->integer )
{
flags &= ~( FL_DIE_EXPLODE | FL_BLOOD );
}
}
void Player::InitHealth
(
void
)
{
// Don't do anything if we're loading a server game.
// This is either a loadgame or a restart
if ( LoadingSavegame )
{
return;
}
// reset the health values
health = 100;
max_health = 100;
}
void Player::InitModel
(
void
)
{
gi.clearmodel( edict );
if( !g_gametype->integer )
{
setModel( "models/player/" + str( g_playermodel->string ) + ".tik" );
}
else if( dm_team != TEAM_AXIS )
{
if( Q_stricmpn( client->pers.playermodel, "american", 8 ) &&
Q_stricmpn( client->pers.playermodel, "allied", 6 ) )
{
setModel( "models/player/american_army.tik" );
}
else
{
setModel( "models/player/" + str( client->pers.playermodel ) + ".tik" );
}
}
else
{
if( Q_stricmpn( client->pers.playermodel, "german", 6 ) &&
Q_stricmpn( client->pers.playermodel, "axis", 4 ) )
{
setModel( "models/player/german_wehrmacht_soldier.tik" );
}
else
{
setModel( "models/player/" + str( client->pers.playergermanmodel ) + ".tik" );
}
}
if( !edict->tiki )
{
if( dm_team == TEAM_AXIS )
{
setModel( "models/player/german_wehrmacht_soldier.tik" );
}
else
{
setModel( "models/player/american_army.tik" );
}
}
SetControllerTag( HEAD_TAG, gi.Tag_NumForName( edict->tiki, "Bip01 Head" ) );
SetControllerTag( TORSO_TAG, gi.Tag_NumForName( edict->tiki, "Bip01 Spine2" ) );
SetControllerTag( ARMS_TAG, gi.Tag_NumForName( edict->tiki, "Bip01 Spine1" ) );
SetControllerTag( PELVIS_TAG, gi.Tag_NumForName( edict->tiki, "Bip01 Pelvis" ) );
if( g_gametype->integer )
{
if( IsSpectator() )
{
hideModel();
}
else
{
showModel();
}
}
else
{
showModel();
}
if( GetActiveWeapon( WEAPON_MAIN ) )
{
edict->s.eFlags &= ~EF_UNARMED;
}
else
{
edict->s.eFlags |= EF_UNARMED;
}
edict->s.eFlags &= ~EF_ANY_TEAM;
if( dm_team == TEAM_ALLIES )
{
edict->s.eFlags |= EF_ALLIES;
}
else if( dm_team == TEAM_AXIS )
{
edict->s.eFlags |= EF_AXIS;
}
client->ps.iViewModelAnim = 0;
client->ps.iViewModelAnimChanged = 0;
if( dm_team == TEAM_AXIS )
{
if( m_voiceType >= PVT_AXIS_END )
{
m_voiceType = PVT_AXIS_AXIS4;
}
}
else
{
if( m_voiceType >= PVT_ALLIED_END )
{
m_voiceType = PVT_ALLIED_PILOT;
}
}
char model_name[ MAX_STRING_TOKENS ];
char *model_replace;
strcpy( model_name, model.c_str() );
size_t len = strlen( model_name );
model_replace = model_name + len - 4;
strcpy( model_replace, "_fps.tik" );
m_fpsTiki = gi.modeltiki( model_name );
}
void Player::InitPhysics
(
void
)
{
// Physics stuff
oldvelocity = vec_zero;
velocity = vec_zero;
old_v_angle = v_angle;
gravity = 1.0;
falling = false;
mediumimpact = false;
hardimpact = false;
setContents( CONTENTS_BODY );
mass = 500;
memset( &last_ucmd, 0, sizeof( last_ucmd ) );
client->ps.groundTrace.fraction = 1.0f;
}
void Player::InitPowerups
(
void
)
{
// powerups
poweruptimer = 0;
poweruptype = 0;
}
void Player::InitWorldEffects
(
void
)
{
// world effects
next_painsound_time = 0;
}
void Player::InitWeapons
(
void
)
{
// Don't do anything if we're loading a server game.
// This is either a loadgame or a restart
if ( LoadingSavegame )
{
return;
}
}
void Player::InitInventory
(
void
)
{
}
void Player::InitView
(
void
)
{
// view stuff
camera = NULL;
v_angle = vec_zero;
SetViewAngles( v_angle );
viewheight = DEFAULT_VIEWHEIGHT;
// blend stuff
damage_blend = vec_zero;
damage_count = 0;
damage_blood = 0;
damage_alpha = 0;
damage_angles = vec_zero;
}
void Player::InitDeathmatch( void )
{
fAttackerDispTime = 0.0f;
pAttackerDistPointer = nullptr;
m_iInfoClient = -1;
m_fWeapSelectTime = level.time - 9.0f;
m_fDamageMultipliers[ 0 ] = 2.0f;
m_fDamageMultipliers[ 1 ] = 2.0f;
m_fDamageMultipliers[ 2 ] = 2.0f;
m_fDamageMultipliers[ 3 ] = 1.0f;
m_fDamageMultipliers[ 4 ] = 0.95f;
m_fDamageMultipliers[ 5 ] = 0.90f;
m_fDamageMultipliers[ 6 ] = 0.85f;
m_fDamageMultipliers[ 7 ] = 0.80f;
m_fDamageMultipliers[ 8 ] = 0.80f;
m_fDamageMultipliers[ 9 ] = 0.80f;
m_fDamageMultipliers[ 10 ] = 0.80f;
m_fDamageMultipliers[ 11 ] = 0.60f;
m_fDamageMultipliers[ 12 ] = 0.60f;
m_fDamageMultipliers[ 13 ] = 0.60f;
m_fDamageMultipliers[ 14 ] = 0.60f;
m_fDamageMultipliers[ 15 ] = 0.50f;
m_fDamageMultipliers[ 16 ] = 0.50f;
m_fDamageMultipliers[ 17 ] = 0.50f;
m_fDamageMultipliers[ 18 ] = 0.50f;
if( current_team )
{
EndSpectator();
if( dmManager.GetMatchStartTime() > 0.0f && !dmManager.AllowRespawn() &&
g_allowjointime->value > 0.0f && level.time - dmManager.GetMatchStartTime() > g_allowjointime->value )
{
m_bTempSpectator = true;
}
if( g_gametype->integer >= GT_TEAM_ROUNDS && g_gametype->integer <= GT_OBJECTIVE && m_bTempSpectator )
{
if( !IsSpectator() ) {
respawn_time = level.time + 1.0f;
}
Spectator();
}
else
{
BeginFight();
}
}
else
{
if( client->pers.team )
{
SetTeam( client->pers.team );
}
else
{
SetTeam( TEAM_SPECTATOR );
}
}
edict->s.eFlags &= ~( TEAM_ALLIES | TEAM_AXIS );
if( GetTeam() == TEAM_ALLIES )
{
edict->s.eFlags |= TEAM_ALLIES;
}
else if( GetTeam() == TEAM_AXIS )
{
edict->s.eFlags |= TEAM_AXIS;
}
if( g_gametype->integer >= GT_TEAM_ROUNDS )
{
if( client->pers.kills )
{
num_deaths = client->pers.kills;
client->pers.kills = 0;
}
}
ChooseSpawnPoint();
// spectators should not have weapons
if( IsSpectator() )
{
FreeInventory();
}
else
{
Event *ev = new Event( "use" );
if( !Q_stricmp( client->pers.weapon, "rifle" ) )
{
if( dm_team == TEAM_ALLIES )
{
giveItem( "models/weapons/m1_garand.tik" );
ev->AddString( "models/weapons/m1_garand.tik" );
}
else
{
giveItem( "models/weapons/kar98.tik" );
ev->AddString( "models/weapons/kar98.tik" );
}
GiveAmmo( "rifle", 100 );
}
else if( !Q_stricmp( client->pers.weapon, "sniper" ) )
{
if( dm_team == TEAM_ALLIES )
{
giveItem( "models/weapons/springfield.tik" );
ev->AddString( "models/weapons/springfield.tik" );
}
else
{
giveItem( "models/weapons/kar98sniper.tik" );
ev->AddString( "models/weapons/kar98sniper.tik" );
}
}
else if( !Q_stricmp( client->pers.weapon, "smg" ) )
{
if( dm_team == TEAM_ALLIES )
{
giveItem( "models/weapons/thompsonsmg.tik" );
ev->AddString( "models/weapons/thompsonsmg.tik" );
}
else
{
giveItem( "models/weapons/mp40.tik" );
ev->AddString( "models/weapons/mp40.tik" );
}
}
else if( !Q_stricmp( client->pers.weapon, "mg" ) )
{
if( dm_team == TEAM_ALLIES )
{
giveItem( "models/weapons/bar.tik" );
ev->AddString( "models/weapons/bar.tik" );
}
else
{
giveItem( "models/weapons/mp44.tik" );
ev->AddString( "models/weapons/mp44.tik" );
}
}
else if( !Q_stricmp( client->pers.weapon, "heavy" ) )
{
if( dm_team == TEAM_ALLIES )
{
giveItem( "models/weapons/bazooka.tik" );
ev->AddString( "models/weapons/bazooka.tik" );
}
else
{
giveItem( "models/weapons/panzerschreck.tik" );
ev->AddString( "models/weapons/panzerschreck.tik" );
}
}
else if( !Q_stricmp( client->pers.weapon, "shotgun" ) )
{
giveItem( "models/weapons/shotgun.tik" );
ev->AddString( "models/weapons/shotgun.tik" );
}
PostEvent( ev, 0.3f );
if( dm_team == TEAM_ALLIES )
{
giveItem( "models/weapons/colt45.tik" );
giveItem( "models/weapons/m2frag_grenade.tik" );
}
else
{
giveItem( "models/weapons/p38.tik" );
giveItem( "models/weapons/steilhandgranate.tik" );
}
giveItem( "models/items/binoculars.tik" );
}
if( current_team ) {
current_team->m_bHasSpawnedPlayers = qtrue;
}
}
void Player::InitMaxAmmo
(
void
)
{
GiveAmmo( "pistol", 0, 200 );
GiveAmmo( "rifle", 0, 200 );
GiveAmmo( "smg", 0, 300 );
GiveAmmo( "mg", 0, 500 );
GiveAmmo( "grenade", 0, 5 );
GiveAmmo( "agrenade", 0, 5 );
GiveAmmo( "heavy", 0, 5 );
GiveAmmo( "shotgun", 0, 50 );
}
void Player::InitStats
(
void
)
{
m_iNumObjectives = 0;
m_iObjectivesCompleted = 0;
m_iNumHitsTaken = 0;
m_iNumEnemiesKilled = 0;
m_iNumObjectsDestroyed = 0;
}
void Player::ChooseSpawnPoint( void )
{
// set up the player's spawn location
PlayerStart *p = SelectSpawnPoint( this );
setOrigin( p->origin + Vector( "0 0 1" ) );
origin.copyTo( edict->s.origin2 );
edict->s.renderfx |= RF_FRAMELERP;
if( g_gametype->integer && !IsSpectator() )
{
KillBox( this );
}
setAngles( p->angles );
SetViewAngles( p->angles );
if( g_gametype->integer )
{
for( int i = 1; i <= 4; i++ )
{
Event *ev = new Event( EV_SetViewangles );
ev->AddVector( p->angles );
PostEvent( ev, level.frametime * i );
}
}
if( p->m_bDeleteOnSpawn )
{
delete p;
}
else
{
p->Unregister( STRING_SPAWN );
m_pLastSpawnpoint = p;
}
}
void Player::Disconnect( void )
{
Event *ev = new Event;
ev->AddListener( this );
scriptedEvents[ SE_DISCONNECTED ].Trigger( ev );
if( g_gametype->integer ) {
dmManager.RemovePlayer( this );
}
}
void Player::EndLevel
(
Event *ev
)
{
InitPowerups();
if ( health > max_health )
{
health = max_health;
}
if ( health < 1 )
{
health = 1;
}
}
void Player::Respawn
(
Event *ev
)
{
if( g_gametype->integer )
{
if( health <= 0.0f )
{
DeadBody();
hideModel();
}
respawn_time = level.time;
// This is not present in MOHAA
ProcessEvent( EV_Player_UnattachFromLadder );
RemoveFromVehiclesAndTurrets();
FreeInventory();
Init();
client->ps.pm_flags |= PMF_RESPAWNED;
}
else
{
if( g_lastsave->string && *g_lastsave->string )
{
gi.SendConsoleCommand( "loadlastgame\n" );
}
else
{
gi.SendConsoleCommand( "restart\n" );
}
logfile_started = qfalse;
}
Unregister( STRING_RESPAWN );
}
Vector Player::GunTarget
(
bool bNoCollision
)
{
Vector vForward;
Vector vOut;
Vector vDest;
trace_t trace;
solid_t prev_solid = SOLID_BBOX;
if( bNoCollision )
{
AngleVectors( m_vViewAng, vForward, NULL, NULL );
vOut = m_vViewPos + vForward * 1024.0f;
return vOut;
}
else if( m_pVehicle )
{
AngleVectors( m_vViewAng, vForward, NULL, NULL );
vDest = m_vViewPos + vForward * 4096.0f;
prev_solid = m_pVehicle->edict->solid;
m_pVehicle->setSolidType( SOLID_NOT );
if( m_pVehicle->IsSubclassOfVehicle() )
{
m_pVehicle->SetSlotsNonSolid();
}
trace = G_Trace(
m_vViewPos,
vec_zero,
vec_zero,
vDest,
this,
MASK_OPAQUE,
qfalse,
"Player::GunTarget" );
vOut = trace.endpos;
}
else
{
AngleVectors( m_vViewAng, vForward, NULL, NULL );
vDest = m_vViewPos + vForward * 1024.0f;
trace = G_Trace( m_vViewPos,
vec_zero,
vec_zero,
vDest,
this,
MASK_PLAYERSOLID,
qfalse,
"Player::GunTarget" );
if( !m_pTurret || ( Vector( trace.endpos ) - m_vViewPos ).lengthSquared() >= 16384.0f )
{
vOut = trace.endpos;
}
else
{
vOut = vDest;
}
}
if( m_pVehicle )
{
m_pVehicle->setSolidType( prev_solid );
if( m_pVehicle->IsSubclassOfVehicle() )
{
m_pVehicle->SetSlotsSolid();
}
}
return vOut;
}
void Player::SetDeltaAngles
(
void
)
{
int i;
// Use v_angle since we may be in a camera
for( i = 0; i < 3; i++ )
{
client->ps.delta_angles[ i ] = ANGLE2SHORT( v_angle[ i ] );
}
}
void Player::Obituary( Entity *attacker, Entity *inflictor, int meansofdeath, int iLocation )
{
const char *s1;
const char *s2;
qboolean bDispLocation;
if( g_gametype->integer == GT_SINGLE_PLAYER ) {
return;
}
s1 = NULL;
s2 = NULL;
bDispLocation = qfalse;
if( attacker != this )
{
if( attacker && attacker->client )
{
Weapon *pAttackerWeap = NULL;
if( attacker->IsSubclassOfPlayer() )
{
pAttackerWeap = ( ( Player * )attacker )->GetActiveWeapon( WEAPON_MAIN );
}
switch( meansofdeath )
{
case MOD_CRUSH:
case MOD_CRUSH_EVERY_FRAME:
s1 = "was crushes by";
break;
case MOD_TELEFRAG:
s1 = "was telefragged by";
break;
case MOD_FALLING:
s1 = "was pushed over the edge by";
break;
case MOD_EXPLOSION:
s1 = "was blown away by";
break;
case MOD_GRENADE:
if( G_Random() >= 0.5f )
{
s1 = "tripped on";
s2 = "'s' grenade";
}
else
{
s1 = "is picking";
s2 = "'s' shrapnel out of his teeth";
}
break;
case MOD_ROCKET:
s1 = "took";
if( G_Random() >= 0.5f )
{
s2 = "'s rocket right in the kisser";
}
else
{
s2 = "'s rocket in the face";
}
break;
case MOD_IMPACT:
s1 = "was knocked out by";
break;
case MOD_BULLET:
case MOD_FAST_BULLET:
s1 = "was shot by";
if( pAttackerWeap )
{
if( pAttackerWeap->GetWeaponClass() & WEAPON_CLASS_PISTOL )
{
s1 = "was gunned down by";
}
else if( pAttackerWeap->GetWeaponClass() & WEAPON_CLASS_RIFLE )
{
if( pAttackerWeap->m_iZoom )
{
s1 = "was sniped by";
}
else
{
s1 = "was rifled by";
}
}
else if( pAttackerWeap->GetWeaponClass() & WEAPON_CLASS_SMG )
{
s1 = "was perforated by";
s2 = "'s' SMG";
}
else if( pAttackerWeap->GetWeaponClass() & WEAPON_CLASS_MG )
{
s1 = "was machine-gunned by";
}
}
if( iLocation > -1 )
{
bDispLocation = qtrue;
}
break;
case MOD_VEHICLE:
s1 = "was run over by";
break;
case MOD_LAVA:
case MOD_SLIME:
case MOD_FIRE:
case MOD_ON_FIRE:
s1 = "was burned up by";
break;
case MOD_IMPALE:
s1 = "was impaled by";
break;
case MOD_BASH:
if( G_Random() >= 0.5f )
{
s1 = "was bashed by";
}
else
{
s1 = "was clubbed by";
}
break;
case MOD_SHOTGUN:
if( G_Random() >= 0.5f )
{
s1 = "was hunted down by";
}
else
{
s1 = "was pumped full of buckshot by";
}
break;
default:
s1 = "was killed by";
break;
}
if( bDispLocation )
{
str szConv1 = gi.LV_ConvertString( s1 );
str szConv2;
str szConv3;
str szArg1 = "in the " + str( G_LocationNumToDispString( iLocation ) );
szConv3 = gi.LV_ConvertString( szArg1 );
if( s2 )
{
szConv2 = gi.LV_ConvertString( s2 );
if( dedicated->integer )
{
gi.DPrintf( "%s %s %s%s %s\n",
client->pers.netname,
szConv1.c_str(),
attacker->client->pers.netname,
szConv2.c_str(),
szConv3.c_str() );
}
G_PrintDeathMessage( va( "%s %s %s%s %s\n",
client->pers.netname,
szConv1.c_str(),
attacker->client->pers.netname,
szConv2.c_str(),
szConv3.c_str() ) );
}
else
{
if( dedicated->integer )
{
gi.DPrintf( "%s %s %s %s\n",
client->pers.netname,
szConv1.c_str(),
attacker->client->pers.netname,
szConv3.c_str() );
}
G_PrintDeathMessage( va( "%s %s %s %s\n",
client->pers.netname,
szConv1.c_str(),
attacker->client->pers.netname,
szConv3.c_str() ) );
}
}
else
{
str szConv1 = gi.LV_ConvertString( s1 );
str szConv2;
if( s2 )
{
szConv2 = gi.LV_ConvertString( s2 );
if( dedicated->integer )
{
gi.DPrintf( "%s %s %s %s\n",
client->pers.netname,
szConv1.c_str(),
attacker->client->pers.netname,
szConv2.c_str() );
}
G_PrintDeathMessage( va( "%s %s %s %s\n",
client->pers.netname,
szConv1.c_str(),
attacker->client->pers.netname,
szConv2.c_str() ) );
}
else
{
if( dedicated->integer )
{
gi.DPrintf( "%s %s %s\n",
client->pers.netname,
szConv1.c_str(),
attacker->client->pers.netname );
}
G_PrintDeathMessage( va( "%s %s %s\n",
client->pers.netname,
szConv1.c_str(),
attacker->client->pers.netname ) );
}
}
}
else
{
switch( meansofdeath )
{
case MOD_LAVA:
case MOD_SLIME:
s1 = "was burned to a crisp";
break;
case MOD_FALLING:
s1 = "cratered";
break;
case MOD_EXPLOSION:
case MOD_GRENADE:
s1 = "blew up";
break;
case MOD_ROCKET:
s1 = "caught a rocket";
break;
case MOD_BULLET:
case MOD_FAST_BULLET:
if( iLocation > -1 )
{
s1 = "was shot in the";
}
else
{
s1 = "was shot";
bDispLocation = qtrue;
}
break;
default:
s1 = "died";
break;
}
if( bDispLocation )
{
str szConv1 = gi.LV_ConvertString( s1 + str( "in the " ) + G_LocationNumToDispString( iLocation ) );
if( dedicated->integer )
{
gi.Printf( "%s %s\n", client->pers.netname, szConv1.c_str() );
}
G_PrintDeathMessage( va( "%s %s",
client->pers.netname,
szConv1.c_str() ) );
}
else
{
str szConv1 = gi.LV_ConvertString( s1 );
if( dedicated->integer )
{
gi.Printf( "%s %s\n", client->pers.netname, szConv1.c_str() );
}
G_PrintDeathMessage( va( "%s %s",
client->pers.netname,
szConv1.c_str() ) );
}
}
}
else
{
switch( meansofdeath )
{
case MOD_SUICIDE:
s1 = "took himself out of commision";
break;
case MOD_LAVA:
case MOD_SLIME:
s1 = "was burned to a crisp";
break;
case MOD_FALLING:
s1 = "cratered";
break;
case MOD_EXPLOSION:
s1 = "blew himself up";
break;
case MOD_GRENADE:
if( G_Random() >= 0.5f )
{
s1 = "played catch with himself";
}
else
{
s1 = "tripped on his own grenade";
}
break;
case MOD_ROCKET:
s1 = "rocketed himself";
break;
case MOD_BULLET:
case MOD_FAST_BULLET:
if( iLocation > -1 )
{
s1 = "shot himself";
}
else
{
s1 = "shot himself in the";
bDispLocation = qtrue;
}
default:
s1 = "died";
break;
}
if( bDispLocation )
{
str szConv1 = gi.LV_ConvertString( s1 + str( " " ) + G_LocationNumToDispString( meansofdeath ) );
if( dedicated->integer )
{
gi.Printf( "%s %s\n", client->pers.netname, szConv1.c_str() );
}
G_PrintDeathMessage( va( "%s %s\n", client->pers.netname, szConv1.c_str() ) );
}
else
{
str szConv1 = gi.LV_ConvertString( s1 );
if( dedicated->integer )
{
gi.Printf( "%s %s\n", client->pers.netname, szConv1.c_str() );
}
G_PrintDeathMessage( va( "%s %s\n", client->pers.netname, szConv1.c_str() ) );
}
}
}
void Player::Dead
(
Event *ev
)
{
if( deadflag == DEAD_DEAD ) {
return;
}
health = 0;
deadflag = DEAD_DEAD;
edict->s.renderfx &= ~RF_SHADOW;
server_new_buttons = 0;
CancelEventsOfType( EV_Player_Dead );
// stop animating
StopPartAnimating( legs );
// pause the torso anim
PausePartAnim( torso );
partAnim[ torso ] = "";
respawn_time = level.time + 1.0f;
if( g_gametype->integer )
{
if( !dmManager.AllowRespawn() )
{
respawn_time = level.time + 2.0f;
}
}
else
{
if( level.current_map && *level.current_map )
{
G_BeginIntermission( level.current_map, TRANS_LEVEL );
}
}
ZoomOff();
}
void Player::Killed
(
Event *ev
)
{
Entity *attacker;
Entity *inflictor;
int meansofdeath;
int location;
Event *event;
// Custom killed event will do the job
if( m_pKilledEvent )
{
event = new Event( m_pKilledEvent );
for( int i = 1; i <= ev->NumArgs(); i++ )
event->AddValue( ev->GetValue( i ) );
ProcessEvent( event );
Unregister( STRING_DEATH );
return;
}
if( g_gametype->integer )
{
current_team->AddDeaths( this, 1 );
}
else
{
AddDeaths( 1 );
}
attacker = ev->GetEntity( 1 );
inflictor = ev->GetEntity( 3 );
meansofdeath = ev->GetInteger( 9 );
location = ev->GetInteger( 10 );
pain_type = ( meansOfDeath_t )meansofdeath;
if( attacker ) {
Obituary( attacker, inflictor, meansofdeath, location );
}
RemoveFromVehiclesAndTurrets();
if( g_gametype->integer && attacker && attacker->IsSubclassOfPlayer() )
{
( ( Player * )attacker )->KilledPlayerInDeathmatch( this );
}
deadflag = DEAD_DYING;
health = 0;
event = new Event( EV_Pain );
event->AddEntity( attacker );
event->AddFloat( ev->GetFloat( 2 ) );
event->AddEntity( inflictor );
event->AddVector( ev->GetVector( 4 ) );
event->AddVector( ev->GetVector( 5 ) );
event->AddVector( ev->GetVector( 6 ) );
event->AddInteger( ev->GetInteger( 7 ) );
event->AddInteger( ev->GetInteger( 8 ) );
event->AddInteger( ev->GetInteger( 9 ) );
event->AddInteger( ev->GetInteger( 10 ) );
ProcessEvent( event );
if( g_gametype->integer )
{
if( HasItem( "Binoculars" ) ) {
takeItem( "Binoculars" );
}
PostEvent( EV_Player_DMDeathDrop, 0.1f );
edict->s.eFlags |= EF_DEAD;
}
edict->clipmask = MASK_DEADSOLID;
setContents( CONTENTS_CORPSE );
setSolidType( SOLID_NOT );
setMoveType( MOVETYPE_FLY );
angles.x = 0;
angles.z = 0;
setAngles( angles );
//
// change music
//
ChangeMusic( "failure", "normal", true );
takedamage = DAMAGE_NO;
// Post a dead event just in case
PostEvent( EV_Player_Dead, 5.0f );
ZoomOff();
if( g_voiceChat->integer )
{
if( m_voiceType == PVT_ALLIED_MANON )
{
Sound( "manon_death", CHAN_VOICE, -1.0f, 160, NULL, -1.0f, 1, 0, 1, 1200 );
}
else
{
Sound( "player_death" );
}
}
else
{
Sound( "player_death" );
}
event = new Event;
event->AddEntity( ev->GetEntity( 1 ) );
event->AddFloat( ev->GetFloat( 2 ) );
event->AddEntity( ev->GetEntity( 3 ) );
event->AddVector( ev->GetVector( 4 ) );
event->AddVector( ev->GetVector( 5 ) );
event->AddVector( ev->GetVector( 6 ) );
event->AddInteger( ev->GetInteger( 7 ) );
event->AddInteger( ev->GetInteger( 8 ) );
event->AddInteger( ev->GetInteger( 9 ) );
event->AddInteger( ev->GetInteger( 10 ) );
event->AddEntity( this );
scriptedEvents[ SE_KILL ].Trigger( event );
Unregister( STRING_DEATH );
}
void Player::KilledPlayerInDeathmatch
(
Player *killed
)
{
DM_Team *pDMTeam;
if( killed == this )
{
AddKills( -1 );
gi.SendServerCommand( edict - g_entities, "print \"" HUD_MESSAGE_WHITE "%s\n\"", gi.LV_ConvertString( "You killed yourself" ) );
}
else
{
pDMTeam = killed->GetDM_Team();
if( pDMTeam != GetDM_Team() || g_gametype->integer <= GT_FFA || g_gametype->integer > GT_OBJECTIVE )
{
current_team->AddKills( this, 1 );
}
else
{
current_team->AddKills( this, -1 );
}
gi.SendServerCommand( edict - g_entities, "print \"" HUD_MESSAGE_WHITE "%s %s\n\"", gi.LV_ConvertString( "You killed" ), killed->client->pers.netname );
}
}
void Player::ArmorDamage
(
Event *ev
)
{
int mod = ev->GetInteger( 9 );
if( g_gametype->integer )
{
// players that are not allowed fighting mustn't take damage
if( !m_bAllowFighting && mod != MOD_TELEFRAG )
{
return;
}
Player *attacker = ( Player * )ev->GetEntity( 1 );
if( attacker && attacker->IsSubclassOfPlayer() )
{
if( attacker != this )
{
if( g_gametype->integer > 1 && !g_teamdamage->integer )
{
// check for team damage
if( attacker->GetDM_Team() == GetDM_Team() && mod != MOD_TELEFRAG )
{
return;
}
}
pAttackerDistPointer = attacker;
fAttackerDispTime = g_drawattackertime->value + level.time;
}
}
}
m_iNumHitsTaken++;
Sentient::ArmorDamage( ev );
Event *event = new Event;
event->AddEntity( ev->GetEntity( 1 ) );
event->AddFloat( ev->GetFloat( 2 ) );
event->AddEntity( ev->GetEntity( 3 ) );
event->AddVector( ev->GetVector( 4 ) );
event->AddVector( ev->GetVector( 5 ) );
event->AddVector( ev->GetVector( 6 ) );
event->AddInteger( ev->GetInteger( 7 ) );
event->AddInteger( ev->GetInteger( 8 ) );
event->AddInteger( ev->GetInteger( 9 ) );
event->AddInteger( ev->GetInteger( 10 ) );
event->AddEntity( this );
scriptedEvents[ SE_DAMAGE ].Trigger( event );
}
void Player::Pain
(
Event *ev
)
{
float damage, yawdiff;
Entity *attacker;
int meansofdeath;
Vector dir, pos, attack_angle;
int iLocation;
attacker = ev->GetEntity( 1 );
damage = ev->GetFloat( 2 );
pos = ev->GetVector( 4 );
dir = ev->GetVector( 5 );
meansofdeath = ev->GetInteger( 9 );
iLocation = ev->GetInteger( 10 );
if( !damage && !knockdown )
return;
client->ps.stats[ STAT_LAST_PAIN ] = damage;
// Determine direction
attack_angle = dir.toAngles();
yawdiff = angles[ YAW ] - attack_angle[ YAW ] + 180;
yawdiff = AngleNormalize180( yawdiff );
if( yawdiff > -45 && yawdiff < 45 )
pain_dir = PAIN_FRONT;
else if( yawdiff < -45 && yawdiff > -135 )
pain_dir = PAIN_LEFT;
else if( yawdiff > 45 && yawdiff < 135 )
pain_dir = PAIN_RIGHT;
else
pain_dir = PAIN_REAR;
// accumulate pain for animation purposes
if( take_pain )
{
pain += damage;
}
// Spawn off any damage effect if we get hit with a certain type of damage
SpawnDamageEffect( ( meansOfDeath_t )meansofdeath );
pain_type = ( meansOfDeath_t )meansofdeath;
pain_location = iLocation;
// Only set the regular pain level if enough time since last pain has passed
if( ( level.time > nextpaintime ) && take_pain )
{
pain = 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;
damage_from += dir * damage;
damage_yaw = dir.toYaw() * 10.0f;
if( damage_yaw == client->ps.stats[ STAT_DAMAGEDIR ] )
{
if( damage_yaw < 1800.0f )
damage_yaw += 1.0f;
else
damage_yaw -= 1.0f;
}
if( g_gametype->integer &&
attacker &&
attacker->client &&
attacker != this )
{
gi.MSG_SetClient( attacker->edict - g_entities );
if( IsDead() )
gi.MSG_StartCGM(BG_MapCGMToProtocol(g_protocol, CGM_NOTIFY_KILL));
else
gi.MSG_StartCGM(BG_MapCGMToProtocol(g_protocol, CGM_NOTIFY_HIT));
gi.MSG_EndCGM();
}
if( IsDead() ) {
return;
}
if( g_voiceChat->integer )
{
if( m_voiceType == PVT_ALLIED_MANON )
{
Sound( "manon_pain", CHAN_DIALOG, -1, 160, NULL, -1, 1, 0, 1, 1200 );
}
else
{
Sound( "player_pain" );
}
}
else
{
Sound( "player_pain" );
}
}
void Player::DeadBody
(
void
)
{
Body *body;
if( knockdown ) {
return;
}
knockdown = true;
body = new Body;
body->setModel( model );
for( int i = 0; i < MAX_FRAMEINFOS; i++ )
{
body->edict->s.frameInfo[ i ] = edict->s.frameInfo[ i ];
}
body->edict->s.actionWeight = edict->s.actionWeight;
body->edict->s.scale = edict->s.scale;
body->setOrigin( origin );
body->setAngles( angles );
body->edict->s.eFlags &= ~( EF_AXIS | EF_ALLIES );
if( GetTeam() == TEAM_ALLIES )
{
edict->s.eFlags |= EF_ALLIES;
}
else if( GetTeam() == TEAM_AXIS )
{
edict->s.eFlags |= EF_AXIS;
}
}
void Player::DeadBody
(
Event *ev
)
{
DeadBody();
}
qboolean Player::canUse()
{
int touch[ MAX_GENTITIES ];
int num = getUseableEntities( touch, MAX_GENTITIES );
return num ? true : false;
}
qboolean Player::canUse( Entity *entity, bool requiresLookAt )
{
gentity_t *hit;
int touch[ MAX_GENTITIES ];
int num;
int i;
num = getUseableEntities( touch, MAX_GENTITIES, requiresLookAt );
for( i = 0; i < num; i++ )
{
hit = &g_entities[ touch[ i ] ];
if( !hit->inuse || hit->entity == NULL ) {
continue;
}
if( hit->entity == entity ) {
return true;
}
}
return false;
}
int Player::getUseableEntities( int *touch, int maxcount, bool requiresLookAt )
{
Vector end;
Vector start;
trace_t trace;
Vector offset;
Vector max;
Vector min;
if( ( g_gametype->integer && IsSpectator() ) || IsDead() ) {
return 0;
}
if( m_pTurret )
{
*touch = m_pTurret->entnum;
return 1;
}
if( m_pTurret ) {
return 0;
}
AngleVectors( client->ps.viewangles, offset, NULL, NULL );
start = origin;
start.z += client->ps.viewheight;
if( requiresLookAt )
{
min = Vector( -4.f, -4.f, -4.f );
max = Vector( 4.f, 4.f, 4.f );
end[ 0 ] = start[ 0 ] + ( offset[ 0 ] * 64.f );
end[ 1 ] = start[ 1 ] + ( offset[ 1 ] * 64.f );
if( v_angle[ 0 ] <= 0.0f ) {
end[ 2 ] = start[ 2 ] + ( offset[ 2 ] * 40.f );
} else {
end[ 2 ] = start[ 2 ] + ( offset[ 2 ] * 88.f );
}
trace = G_Trace( start,
min,
max,
end,
this,
MASK_SOLID,
false,
"Player::getUseableEntity" );
offset = trace.endpos;
min = offset - Vector( 16.f, 16.f, 16.f );
max = offset + Vector( 16.f, 16.f, 16.f );
}
else
{
min = start - Vector( 31.f, 31.f, 31.f );
max = start + Vector( 31.f, 31.f, 31.f );
}
return gi.AreaEntities( min, max, touch, maxcount );
}
void Player::DoUse
(
Event *ev
)
{
gentity_t *hit;
int touch[ MAX_GENTITIES ];
int num;
int i;
if( g_gametype->integer && IsSpectator() )
{
return;
}
if( IsDead() )
{
return;
}
if( m_pVehicle )
{
Event *event = new Event( EV_Use );
event->AddEntity( this );
m_pVehicle->ProcessEvent( event );
}
else if( m_pTurret )
{
m_pTurret->TurretEndUsed();
}
else
{
num = getUseableEntities( touch, MAX_GENTITIES, true );
for( i = 0; i < num; i++ )
{
hit = &g_entities[ touch[ i ] ];
if( !hit->inuse || hit->entity == NULL || hit->entity == this ) {
continue;
}
Event *event = new Event( EV_Use );
event->AddListener( this );
hit->entity->ProcessEvent( event );
}
}
// FIXME: reborn feature
#if 0
// Now retrieve entities that doesn't require to look at
num = getUseableEntities( touch, MAX_GENTITIES, false );
for( i = 0; i < num; i++ )
{
hit = &g_entities[ touch[ i ] ];
if( !hit->inuse || hit->entity == NULL || hit->entity == this ) {
continue;
}
Event *event = new Event( EV_Use );
event->AddListener( this );
hit->entity->ProcessEvent( event );
}
#endif
}
void Player::TouchStuff
(
pmove_t *pm
)
{
gentity_t *other;
Event *event;
int i;
int j;
//
// clear out any conditionals that are controlled by touching
//
toucheduseanim = NULL;
if( getMoveType() != MOVETYPE_NOCLIP )
{
G_TouchTriggers( this );
}
// touch other objects
for( i = 0; i < pm->numtouch; i++ )
{
other = &g_entities[ pm->touchents[ i ] ];
for( j = 0; j < i; j++ )
{
gentity_t *ge = &g_entities[ j ];
if( ge == 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 );
}
}
void Player::GetMoveInfo
(
pmove_t *pm
)
{
moveresult = pm->moveresult;
if( !deadflag || ( g_gametype->integer && IsSpectator() ) )
{
v_angle[ 0 ] = pm->ps->viewangles[ 0 ];
v_angle[ 1 ] = pm->ps->viewangles[ 1 ];
v_angle[ 2 ] = pm->ps->viewangles[ 2 ];
if( moveresult == MOVERESULT_TURNED )
{
angles.y = v_angle[ 1 ];
setAngles( angles );
SetViewAngles( angles );
}
}
setOrigin( Vector( pm->ps->origin[ 0 ], pm->ps->origin[ 1 ], pm->ps->origin[ 2 ] ) );
if( pm->ps->groundEntityNum != ENTITYNUM_NONE )
{
float backoff;
float change;
int i;
backoff = DotProduct( pm->ps->groundTrace.plane.normal, pm->ps->velocity );
for( i = 0; i < 3; i++ )
{
change = pm->ps->groundTrace.plane.normal[ i ] * backoff;
pm->ps->velocity[ i ] -= change;
}
}
// Set the ground entity
groundentity = NULL;
if( pm->ps->groundEntityNum != ENTITYNUM_NONE )
{
groundentity = &g_entities[ pm->ps->groundEntityNum ];
airspeed = 200;
if( !groundentity->entity || groundentity->entity->getMoveType() == MOVETYPE_NONE )
{
m_vPushVelocity = vec_zero;
}
// Disable predictions when the groundentity is moving up/down, looks like shaky otherwise
if( groundentity->entity && groundentity->entity != this && groundentity->entity->velocity[ 2 ] != 0 )
{
pm->ps->pm_flags |= PMF_NO_PREDICTION;
}
}
velocity = Vector( pm->ps->velocity[ 0 ], pm->ps->velocity[ 1 ], pm->ps->velocity[ 2 ] );
if( ( client->ps.pm_flags & PMF_FROZEN ) || ( client->ps.pm_flags & PMF_NO_MOVE ) )
{
velocity = vec_zero;
}
else
{
setSize( pm->mins, pm->maxs );
viewheight = pm->ps->viewheight;
}
// water type and level is set in the predicted code
waterlevel = pm->waterlevel;
watertype = pm->watertype;
}
void Player::SetMoveInfo
(
pmove_t *pm,
usercmd_t *ucmd
)
{
Vector move;
// set up for pmove
memset( pm, 0, sizeof( pmove_t ) );
velocity.copyTo( client->ps.velocity );
pm->ps = &client->ps;
if( ucmd )
{
pm->cmd = *ucmd;
}
pm->tracemask = MASK_PLAYERSOLID;
pm->trace = gi.Trace;
pm->pointcontents = gi.PointContents;
pm->ps->origin[ 0 ] = origin.x;
pm->ps->origin[ 1 ] = origin.y;
pm->ps->origin[ 2 ] = origin.z;
pm->mins[ 0 ] = mins.x;
pm->mins[ 1 ] = mins.y;
pm->mins[ 2 ] = mins.z;
pm->maxs[ 0 ] = maxs.x;
pm->maxs[ 1 ] = maxs.y;
pm->maxs[ 2 ] = maxs.z;
pm->ps->velocity[ 0 ] = velocity.x;
pm->ps->velocity[ 1 ] = velocity.y;
pm->ps->velocity[ 2 ] = velocity.z;
pm->pmove_fixed = pmove_fixed->integer;
pm->pmove_msec = pmove_msec->integer;
if( pmove_msec->integer < 8 )
{
pm->pmove_msec = 8;
}
else if( pmove_msec->integer > 33 )
{
pm->pmove_msec = 33;
}
}
pmtype_t Player::GetMovePlayerMoveType
(
void
)
{
if( getMoveType() == MOVETYPE_NOCLIP || IsSpectator() )
{
return PM_NOCLIP;
}
else if( deadflag )
{
return PM_DEAD;
}
else if( movecontrol == MOVECONTROL_CLIMBWALL )
{
return PM_CLIMBWALL;
}
else
{
return PM_NORMAL;
}
}
void Player::CheckGround
(
void
)
{
pmove_t pm;
SetMoveInfo( &pm, current_ucmd );
Pmove_GroundTrace( &pm );
GetMoveInfo( &pm );
}
qboolean Player::AnimMove
(
Vector &move,
Vector *endpos
)
{
Vector up;
Vector down;
trace_t trace;
int mask;
Vector start( origin );
Vector end( origin + move );
mask = MASK_PLAYERSOLID;
// test the player position if they were a stepheight higher
trace = G_Trace( start, mins, maxs, end, this, mask, true, "AnimMove" );
if( trace.fraction < 1 )
{
if( ( movecontrol == MOVECONTROL_HANGING ) || ( movecontrol == MOVECONTROL_CLIMBWALL ) )
{
up = origin;
up.z += move.z;
trace = G_Trace( origin, mins, maxs, up, this, mask, true, "AnimMove" );
if( trace.fraction < 1 )
{
if( endpos )
{
*endpos = origin;
}
return qfalse;
}
origin = trace.endpos;
end = origin;
end.x += move.x;
end.y += move.y;
trace = G_Trace( origin, mins, maxs, end, this, mask, true, "AnimMove" );
if( endpos )
{
*endpos = trace.endpos;
}
return ( trace.fraction > 0 );
}
else
{
return TestMove( move, endpos );
}
}
else
{
if( endpos )
{
*endpos = trace.endpos;
}
return qtrue;
}
}
qboolean Player::TestMove
(
Vector &move,
Vector *endpos
)
{
trace_t trace;
Vector pos( origin + move );
trace = G_Trace( origin, mins, maxs, pos, this, MASK_PLAYERSOLID, true, "TestMove" );
if ( trace.allsolid )
{
// player is completely trapped in another solid
if ( endpos )
{
*endpos = origin;
}
return qfalse;
}
if ( trace.fraction < 1.0f )
{
Vector up( origin );
up.z += STEPSIZE;
trace = G_Trace( origin, mins, maxs, up, this, MASK_PLAYERSOLID, true, "TestMove" );
if ( trace.fraction == 0.0f )
{
if ( endpos )
{
*endpos = origin;
}
return qfalse;
}
Vector temp( trace.endpos );
Vector end( temp + move );
trace = G_Trace( temp, mins, maxs, end, this, MASK_PLAYERSOLID, true, "TestMove" );
if ( trace.fraction == 0.0f )
{
if ( endpos )
{
*endpos = origin;
}
return qfalse;
}
temp = trace.endpos;
Vector down( trace.endpos );
down.z = origin.z;
trace = G_Trace( temp, mins, maxs, down, this, MASK_PLAYERSOLID, true, "TestMove" );
}
if ( endpos )
{
*endpos = trace.endpos;
}
return qtrue;
}
float Player::TestMoveDist
(
Vector &move
)
{
Vector endpos;
TestMove( move, &endpos );
endpos -= origin;
return endpos.length();
}
static Vector vec_up = Vector( 0, 0, 1 );
void Player::CheckMoveFlags
(
void
)
{
trace_t trace;
Vector start;
Vector end;
float oldsp;
Vector olddir( oldvelocity.x, oldvelocity.y, 0 );
//
// Check if moving forward will cause the player to fall
//
start = origin + yaw_forward * 52.0f;
end = start;
end.z -= STEPSIZE * 2;
trace = G_Trace( start, mins, maxs, end, this, MASK_PLAYERSOLID, true, "CheckMoveFlags" );
canfall = ( trace.fraction >= 1.0f );
if( !groundentity && !( client->ps.walking ) )
{
falling = true;
hardimpact = false;
mediumimpact = false;
}
else
{
falling = false;
mediumimpact = oldvelocity.z <= -180.0f;
hardimpact = oldvelocity.z < -400.0f;
}
// check for running into walls
oldsp = VectorNormalize( olddir );
if( ( oldsp > 220.0f ) && ( velocity * olddir < 2.0f ) )
{
moveresult = MOVERESULT_HITWALL;
}
move_forward_vel = DotProduct( yaw_forward, velocity );
move_backward_vel = -move_forward_vel;
if( move_forward_vel < 0.0f ) {
move_forward_vel = 0.0f;
}
if( move_backward_vel < 0.0f ) {
move_backward_vel = 0.0f;
}
move_left_vel = DotProduct( yaw_left, velocity );
move_right_vel = -move_left_vel;
if( move_left_vel < 0.0f ) {
move_left_vel = 0.0f;
}
if( move_right_vel < 0.0f ) {
move_right_vel = 0.0f;
}
move_up_vel = DotProduct( vec_up, velocity );
move_down_vel = -move_up_vel;
if( move_up_vel < 0.0f ) {
move_up_vel = 0.0f;
}
if( move_down_vel < 0.0f ) {
move_down_vel = 0.0f;
}
}
qboolean Player::CheckMove
(
Vector &move,
Vector *endpos
)
{
return AnimMove( move, endpos );
}
float Player::CheckMoveDist
(
Vector &move
)
{
Vector endpos;
CheckMove( move, &endpos );
endpos -= origin;
return endpos.length();
}
void Player::ClientMove
(
usercmd_t *ucmd
)
{
pmove_t pm;
Vector move;
int touch[MAX_GENTITIES];
int num = getUseableEntities(touch, MAX_GENTITIES, true);
bool bHintShown = false;
for (int i = 0; i < num; i++)
{
Entity* entity = g_entities[touch[i]].entity;
if (entity && entity->m_HintString.length())
{
entity->ProcessHint(edict, true);
bHintShown = true;
m_bShowingHint = true;
break;
}
}
if (!bHintShown && m_bShowingHint)
{
m_bShowingHint = false;
// FIXME: delete
/*
if (sv_reborn->integer)
{
gi.MSG_SetClient(edict - g_entities);
// Send the hint string once
gi.MSG_StartCGM(CGM_HINTSTRING);
gi.MSG_WriteString("");
gi.MSG_EndCGM();
}
*/
}
oldorigin = origin;
client->ps.pm_type = GetMovePlayerMoveType();
// set move flags
client->ps.pm_flags &= ~( PMF_FROZEN | PMF_NO_PREDICTION | PMF_NO_MOVE | PMF_DUCKED | PMF_NO_GRAVITY | PMF_VIEW_PRONE | PMF_VIEW_DUCK_RUN | PMF_VIEW_JUMP_START );
if( level.playerfrozen || m_bFrozen )
{
client->ps.pm_flags |= PMF_FROZEN;
}
if( ( flags & FL_IMMOBILE ) || ( flags & FL_PARTIAL_IMMOBILE ) )
{
client->ps.pm_flags |= PMF_NO_MOVE;
client->ps.pm_flags |= PMF_NO_PREDICTION;
}
if( maxs.z == 60.0f )
{
client->ps.pm_flags |= PMF_DUCKED;
}
else if( maxs.z == 54.0f )
{
client->ps.pm_flags |= PMF_DUCKED | PMF_VIEW_PRONE;
}
else if( maxs.z == 20.0f )
{
client->ps.pm_flags |= PMF_VIEW_PRONE;
}
else if( maxs.z == 53.0f )
{
client->ps.pm_flags |= PMF_VIEW_DUCK_RUN;
}
else if( viewheight == 52 )
{
client->ps.pm_flags |= PMF_VIEW_JUMP_START;
}
switch( movecontrol )
{
case MOVECONTROL_USER:
case MOVECONTROL_LEGS:
case MOVECONTROL_USER_MOVEANIM:
break;
case MOVECONTROL_CROUCH:
client->ps.pm_flags |= PMF_NO_PREDICTION | PMF_DUCKED | PMF_VIEW_PRONE;
break;
default:
client->ps.pm_flags |= PMF_NO_PREDICTION;
}
if( movetype == MOVETYPE_NOCLIP )
{
if( !( last_ucmd.buttons & BUTTON_RUN ) )
{
client->ps.speed = sv_walkspeed->integer;
}
else
{
client->ps.speed = sv_runspeed->integer;
}
}
else if( !groundentity )
{
client->ps.speed = airspeed;
}
else
{
int runspeed;
if( m_iMovePosFlags & MPF_MOVEMENT_WALKING )
{
runspeed = sv_walkspeed->integer;
}
else
{
runspeed = sv_runspeed->integer;
}
if( m_iMovePosFlags & MPF_POSITION_CROUCHING )
{
client->ps.speed = ( int )( ( float )runspeed * sv_crouchspeedmult->value );
}
else
{
client->ps.speed = runspeed;
}
}
if( g_gametype->integer )
{
client->ps.speed = ( int )( ( float )client->ps.speed * sv_dmspeedmult->value );
}
for( int i = 0; i < MAX_SPEED_MULTIPLIERS; i++ )
{
client->ps.speed = ( int )( ( float )client->ps.speed * speed_multiplier[ i ] );
}
for( int i = 0; i < MAX_ACTIVE_WEAPONS; i++ )
{
if( activeWeaponList[ i ] != NULL )
{
client->ps.speed *= activeWeaponList[ i ]->m_fMovementSpeed;
}
}
client->ps.gravity = sv_gravity->value * gravity;
if( ( movecontrol != MOVECONTROL_ABSOLUTE ) && ( movecontrol != MOVECONTROL_PUSH ) &&
( movecontrol != MOVECONTROL_CLIMBWALL ) )
{
Vector oldpos( origin );
SetMoveInfo( &pm, ucmd );
Pmove( &pm );
GetMoveInfo( &pm );
ProcessPmoveEvents( pm.pmoveEvent );
// if we're not moving, set the blocked flag in case the user is trying to move
if( ucmd->forwardmove && ( ( oldpos - origin ).length() < 0.005f ) )
{
moveresult = MOVERESULT_BLOCKED;
}
if( client->ps.walking && moveresult >= MOVERESULT_BLOCKED )
{
setOrigin( oldpos );
VectorCopy( origin, client->ps.origin );
}
}
else
{
if( movecontrol == MOVECONTROL_CLIMBWALL )
{
PM_UpdateViewAngles( &client->ps, ucmd );
v_angle = client->ps.viewangles;
}
else if( !deadflag )
{
v_angle = client->ps.viewangles;
}
// should collect objects to touch against
memset( &pm, 0, sizeof( pmove_t ) );
// keep the command time up to date or else the next PMove we run will try to catch up
client->ps.commandTime = ucmd->serverTime;
velocity = vec_zero;
}
if( ( getMoveType() != MOVETYPE_NOCLIP ) && ( client->ps.pm_flags & PMF_NO_PREDICTION ) )
{
if( ( movecontrol == MOVECONTROL_ABSOLUTE ) || ( movecontrol == MOVECONTROL_CLIMBWALL ) )
{
velocity = vec_zero;
}
if( ( movecontrol == MOVECONTROL_ANIM ) || ( movecontrol == MOVECONTROL_CLIMBWALL ) ||
( movecontrol == MOVECONTROL_USEANIM ) || ( movecontrol == MOVECONTROL_LOOPUSEANIM ) ||
( movecontrol == MOVECONTROL_USER_MOVEANIM ) )
{
Vector delta = vec_zero;
PlayerAnimDelta( delta );
// using PM_NOCLIP for a smooth move
//client->ps.pm_type = PM_NOCLIP;
if( delta != vec_zero )
{
float mat[ 3 ][ 3 ];
AngleVectors( angles, mat[ 0 ], mat[ 1 ], mat[ 2 ] );
MatrixTransformVector( delta, mat, move );
AnimMove( move, &origin );
setOrigin( origin );
CheckGround();
}
}
}
m_fLastDeltaTime = level.time;
TouchStuff( &pm );
if( ( whereami->integer ) && ( origin != oldorigin ) )
{
gi.DPrintf( "x %8.2f y%8.2f z %8.2f area %2d\n", origin[ 0 ], origin[ 1 ], origin[ 2 ], edict->r.areanum );
}
}
void Player::VehicleMove
(
usercmd_t *ucmd
)
{
if( !m_pVehicle ) {
return;
}
oldorigin = origin;
client->ps.pm_type = GetMovePlayerMoveType();
// set move flags
client->ps.pm_flags &= ~( PMF_FROZEN | PMF_NO_PREDICTION | PMF_NO_MOVE | PMF_DUCKED | PMF_NO_GRAVITY | PMF_VIEW_PRONE | PMF_VIEW_DUCK_RUN | PMF_VIEW_JUMP_START );
// disable HUD and prediction
client->ps.pm_flags |= PMF_NO_HUD | PMF_NO_PREDICTION;
if( level.playerfrozen || m_bFrozen )
{
client->ps.pm_flags |= PMF_FROZEN;
}
if( m_pVehicle->Drive( ucmd ) )
{
client->ps.commandTime = ucmd->serverTime;
}
else
{
ClientMove( ucmd );
}
}
void Player::TurretMove
(
usercmd_t *ucmd
)
{
if( !m_pTurret ) {
return;
}
oldorigin = origin;
client->ps.pm_type = GetMovePlayerMoveType();
// set move flags
client->ps.pm_flags &= ~( PMF_FROZEN | PMF_NO_PREDICTION | PMF_NO_MOVE | PMF_DUCKED | PMF_NO_GRAVITY | PMF_VIEW_PRONE | PMF_VIEW_DUCK_RUN | PMF_VIEW_JUMP_START );
// disable HUD and prediction
client->ps.pm_flags |= PMF_NO_HUD | PMF_NO_PREDICTION;
if( level.playerfrozen || m_bFrozen )
{
client->ps.pm_flags |= PMF_FROZEN;
}
if( !m_pTurret->IsSubclassOfTurretGun() || ( m_pTurret->IsSubclassOfTurretGun() && m_pTurret->UserAim( ucmd ) ) )
{
ClientMove( ucmd );
}
else
{
client->ps.commandTime = ucmd->serverTime;
}
}
void Player::ClientInactivityTimer
(
void
)
{
if( !g_gametype->integer )
return;
if( g_inactivekick->integer && g_inactivekick->integer < 60 )
gi.Cvar_Set( "g_inactiveKick", "60" );
if( g_inactivespectate->integer && g_inactivespectate->integer < 20 )
gi.Cvar_Set( "g_inactiveSpectate", "20" );
if( current_ucmd->buttons & BUTTON_MOUSE ||
( !g_inactivespectate->integer && !g_inactivekick->integer ) ||
current_ucmd->upmove )
{
client->lastActiveTime = level.inttime;
client->activeWarning = 0;
return;
}
if( m_bTempSpectator )
{
if( client->lastActiveTime >= level.inttime - 5000 )
{
client->lastActiveTime = level.inttime;
client->activeWarning = 0;
}
}
if( g_inactivekick->integer && client->lastActiveTime < level.inttime - 1000 * g_inactivekick->integer )
{
const char *s = Info_ValueForKey( client->pers.userinfo, "ip" );
if( strcmp( s, "localhost" ) )
{
gi.DropClient( client->ps.clientNum, "was dropped for inactivity" );
return;
}
if( m_bSpectator )
return;
SetTeam( TEAM_SPECTATOR );
if( deadflag )
deadflag = DEAD_DEAD;
PostEvent( EV_Player_Respawn, 0 );
return;
}
if( g_inactivespectate->integer &&
client->lastActiveTime < level.inttime - g_inactivespectate->integer * 1000 &&
!m_bSpectator )
{
SetTeam( TEAM_SPECTATOR );
if( deadflag )
deadflag = 2;
PostEvent( EV_Player_Respawn, 0 );
return;
}
if( g_inactivekick->integer )
{
static struct {
int iLevel;
int iTime;
} warnkick[ 7 ] =
{
1, 30,
8, 15,
9, 5,
10, 4,
11, 3,
12, 2,
13, 1
};
int iKickWait = g_inactivekick->integer - ( level.inttime - client->lastActiveTime ) / 1000 - 1;
for( int i = 0; i < 7; i++ )
{
if( client->activeWarning < warnkick[ i ].iLevel &&
iKickWait < warnkick[ i ].iTime )
{
client->activeWarning = warnkick[ i ].iLevel;
gi.centerprintf( edict, "%s %i %s",
gi.LV_ConvertString( "You will be kicked for inactivity in" ),
warnkick[ i ].iTime,
gi.LV_ConvertString( "seconds" ) );
return;
}
}
}
if( g_inactivespectate->integer && dm_team != TEAM_SPECTATOR )
{
static struct {
int iLevel;
int iTime;
} warnspectate[ 6 ] =
{
2, 15,
3, 5,
4, 4,
5, 3,
6, 2,
7, 1
};
int iSpectateWait = g_inactivespectate->integer - ( level.inttime - client->lastActiveTime ) / 1000 - 1;
for( int i = 0; i < 6; i++ )
{
if( client->activeWarning < warnspectate[ i ].iLevel &&
iSpectateWait < warnspectate[ i ].iTime )
{
client->activeWarning = warnspectate[ i ].iLevel;
gi.centerprintf( edict, "%s %i %s",
gi.LV_ConvertString( "You will be moved to spectator for inactivity in" ),
warnspectate[ i ].iTime,
gi.LV_ConvertString( "seconds" ) );
return;
}
}
}
}
/*
==============
ClientThink
This will be called once for each client frame, which will
usually be a couple times for each server frame.
==============
*/
void Player::ClientThink
(
void
)
{
// sanity check the command time to prevent speedup cheating
if( current_ucmd->serverTime > level.svsTime )
{
//
// we don't want any future commands, these could be from the previous game
//
return;
}
if( current_ucmd->serverTime < level.svsTime - 1000 )
{
current_ucmd->serverTime = level.svsTime - 1000;
}
if( ( current_ucmd->serverTime - client->ps.commandTime ) < 1 )
{
return;
}
if (g_gametype->integer && dm_team == TEAM_SPECTATOR && !IsSpectator()) {
Spectator();
}
last_ucmd = *current_ucmd;
server_new_buttons |= current_ucmd->buttons & ~buttons;
new_buttons = current_ucmd->buttons & ~buttons;
buttons = current_ucmd->buttons;
if( camera )
{
m_vViewPos = camera->origin;
m_vViewAng = camera->angles;
}
else
{
m_vViewPos[ 0 ] = ( float )current_eyeinfo->ofs[ 0 ] + origin[ 0 ];
m_vViewPos[ 1 ] = ( float )current_eyeinfo->ofs[ 1 ] + origin[ 1 ];
m_vViewPos[ 2 ] = ( float )current_eyeinfo->ofs[ 2 ] + origin[ 2 ];
m_vViewAng[ 0 ] = current_eyeinfo->angles[ 0 ];
m_vViewAng[ 1 ] = current_eyeinfo->angles[ 1 ];
m_vViewAng[ 2 ] = 0.0f;
}
VectorCopy( m_vViewPos, client->ps.vEyePos );
if( level.intermissiontime )
{
if( g_gametype->integer )
{
client->ps.pm_flags |= PMF_FROZEN;
client->ps.pm_flags |= PMF_INTERMISSION;
if( level.time - level.intermissiontime > 5.0f && ( new_buttons & ( BUTTON_ATTACKLEFT | BUTTON_ATTACKRIGHT ) ) )
{
level.exitintermission = true;
}
}
else
{
if( level.intermissiontype == TRANS_MISSION_FAILED )
{
gi.Cvar_Set( "g_success", "0" );
}
else
{
gi.Cvar_Set( "g_success", "1" );
}
gi.Cvar_Set( "g_failed", "0" );
// prevent getting medals from cheats
if( g_medal0->modificationCount > 1 ||
g_medal1->modificationCount > 1 ||
g_medal2->modificationCount > 1 ||
g_medal3->modificationCount > 1 ||
g_medal4->modificationCount > 1 ||
g_medal5->modificationCount > 1 ||
g_eogmedal0->modificationCount > 1 ||
g_eogmedal1->modificationCount > 1 ||
g_eogmedal2->modificationCount > 1
)
{
gi.Cvar_Set( "g_gotmedal", "0" );
}
else
{
gi.Cvar_Set( "g_gotmedal", "1" );
}
if( level.time - level.intermissiontime > 4.0f )
{
if( level.intermissiontype )
{
if( ( new_buttons & BUTTON_ATTACKLEFT ) || ( new_buttons & BUTTON_ATTACKRIGHT ) )
{
if( level.intermissiontype == TRANS_MISSION_FAILED )
{
G_MissionFailed();
}
else
{
g_medal0->modificationCount = 1;
g_medal1->modificationCount = 1;
g_medal2->modificationCount = 1;
g_medal3->modificationCount = 1;
g_medal4->modificationCount = 1;
g_medal5->modificationCount = 1;
g_eogmedal0->modificationCount = 1;
g_eogmedal1->modificationCount = 1;
g_eogmedal2->modificationCount = 1;
g_medal0->modified = false;
g_medal1->modified = false;
g_medal2->modified = false;
g_medal3->modified = false;
g_medal4->modified = false;
g_medal5->modified = false;
g_eogmedal0->modified = false;
g_eogmedal1->modified = false;
g_eogmedal2->modified = false;
level.exitintermission = true;
}
}
}
else
{
level.exitintermission = true;
}
}
}
// Save cmd angles so that we can get delta angle movements next frame
client->cmd_angles[ 0 ] = SHORT2ANGLE( current_ucmd->angles[ 0 ] );
client->cmd_angles[ 1 ] = SHORT2ANGLE( current_ucmd->angles[ 1 ] );
client->cmd_angles[ 2 ] = SHORT2ANGLE( current_ucmd->angles[ 2 ] );
return;
}
if( new_buttons & BUTTON_ATTACKRIGHT )
{
Weapon *weapon = GetActiveWeapon( WEAPON_MAIN );
if( ( weapon ) && ( weapon->GetZoom() ) )
{
if( ( weapon->GetZoom() == fov ) && m_iInZoomMode == -1 )
{
SetFov( selectedfov );
m_iInZoomMode = 0;
}
else
{
SetFov( weapon->GetZoom() );
m_iInZoomMode = -1;
}
}
}
if( new_buttons & BUTTON_USE )
{
DoUse( NULL );
}
moveresult = MOVERESULT_NONE;
if( m_pTurret )
{
TurretMove( current_ucmd );
}
else if( m_pVehicle )
{
VehicleMove( current_ucmd );
}
else
{
ClientMove( current_ucmd );
}
// Save cmd angles so that we can get delta angle movements next frame
client->cmd_angles[ 0 ] = SHORT2ANGLE( current_ucmd->angles[ 0 ] );
client->cmd_angles[ 1 ] = SHORT2ANGLE( current_ucmd->angles[ 1 ] );
client->cmd_angles[ 2 ] = SHORT2ANGLE( current_ucmd->angles[ 2 ] );
if( g_gametype->integer && g_smoothClients->integer && !IsSubclassOfBot() )
{
VectorCopy( client->ps.velocity, edict->s.pos.trDelta );
edict->s.pos.trTime = client->ps.commandTime;
}
else
{
VectorClear( edict->s.pos.trDelta );
edict->s.pos.trTime = 0;
}
ClientInactivityTimer();
}
void Player::UpdateEnemies
(
void
)
{
float fFov;
float fMaxDist;
float fMaxCosSquared;
Vector vLookDir;
if( g_gametype->integer )
{
return;
}
if( m_pNextSquadMate == this )
{
return;
}
fFov = fov * 0.9f;
fMaxDist = world->farplane_distance * 0.7867f;
fMaxCosSquared = 0.0f;
AngleVectors( m_vViewAng, vLookDir, NULL, NULL );
if( m_Enemy )
{
m_Enemy->m_iAttackerCount -= 3;
m_Enemy = NULL;
}
for( Sentient *obj = level.m_HeadSentient[ 0 ]; obj != NULL; obj = obj->m_NextSentient )
{
Vector vDelta;
float fDot;
float fDotSquared;
if( CanSee( obj, fFov, fMaxDist ) )
{
obj->m_fPlayerSightLevel += level.frametime;
vDelta = obj->origin - origin;
fDot = DotProduct( vDelta, vLookDir );
fDotSquared = fDot * fDot;
if( fDotSquared > fMaxCosSquared * vDelta.lengthSquared() )
{
fMaxCosSquared = fDotSquared / vDelta.lengthSquared();
m_Enemy = obj;
}
}
else
{
obj->m_fPlayerSightLevel = 0.0f;
}
}
if( m_Enemy )
{
m_Enemy->m_iAttackerCount += 3;
}
}
void Player::Think
(
void
)
{
static cvar_t *g_aimLagTime = NULL;
int m_iClientWeaponCommand;
Event *m_pWeaponCommand = NULL;
Weapon *pWeap;
/*if (!this)
{
gi.DPrintf("Player::Think() : this is null\n");
}*/
//edict->s.eFlags &= ~EF_UNARMED; where did you get this @ley0k :3
if( whereami->integer &&
origin != oldorigin )
{
gi.DPrintf( "x %8.2f y %8.2f z %8.2f area %2d\n", origin[ 0 ], origin[ 1 ], origin[ 2 ], edict->r.areanum );
}
if( g_gametype->integer == GT_SINGLE_PLAYER && g_playermodel->modified )
{
setModel( "models/player/" + str( g_playermodel->string ) + ".tik" );
if( !edict->tiki )
{
setModel( "models/player/american_army.tik" );
}
g_playermodel->modified = qfalse;
}
if( g_gametype->integer == GT_SINGLE_PLAYER)
{
m_bIsDisguised = false;
if( m_bHasDisguise && !level.m_bAlarm )
{
pWeap = GetActiveWeapon( WEAPON_MAIN );
if( !pWeap || pWeap->IsSubclassOfInventoryItem() )
{
m_bIsDisguised = true;
for( Sentient *pSent = level.m_HeadSentient[ 0 ]; pSent != NULL; pSent = pSent->m_NextSentient )
{
Actor *act = ( Actor * )pSent;
if( pSent->m_Enemy == this && act->IsAttacking())
{
m_bIsDisguised = false;
break;
}
}
}
}
PathSearch::PlayerCover( this );
UpdateEnemies();
}
if( movetype == MOVETYPE_NOCLIP )
{
StopPartAnimating( torso );
SetPartAnim( "idle" );
client->ps.walking = qfalse;
groundentity = 0;
}
else
{
CheckMoveFlags();
EvaluateState();
}
oldvelocity = velocity;
old_v_angle = v_angle;
if (g_gametype->integer == GT_SINGLE_PLAYER)
{
if (((server_new_buttons & BUTTON_ATTACKLEFT) || (server_new_buttons & BUTTON_ATTACKRIGHT)) &&
(!GetActiveWeapon(WEAPON_MAIN)) &&
(!IsDead()) &&
(!IsNewActiveWeapon()) &&
(!LoadingSavegame) )
{
Event *ev = new Event("useweaponclass");
ev->AddString("item1");
ProcessEvent(ev);
}
}
else
{
if (deadflag == DEAD_DEAD && level.time > respawn_time)
{
if (dmManager.AllowRespawn())
{
if (((server_new_buttons & BUTTON_ATTACKLEFT) || (server_new_buttons & BUTTON_ATTACKRIGHT)) ||
(g_forcerespawn->integer > 0 && level.time > g_forcerespawn->integer + respawn_time))
{
m_bSpectator = false;
m_bTempSpectator = false;
client->ps.pm_flags &= ~PMF_SPECTATING;
PostEvent(EV_Player_Respawn, 0);
}
}
else if(!IsSpectator())
{
BeginTempSpectator();
}
}
if (IsSpectator() && !m_bTempSpectator)
{
if (level.time <= respawn_time || !((server_new_buttons & BUTTON_ATTACKLEFT) || (server_new_buttons & BUTTON_ATTACKRIGHT)))
{
if (level.time - 10.0f > m_fWeapSelectTime)
{
m_fWeapSelectTime = level.time;
gi.centerprintf(edict, gi.LV_ConvertString("Press fire to join the battle!"));
}
}
else if (!current_team || dm_team == TEAM_SPECTATOR)
{
gi.SendServerCommand(edict - g_entities, "stufftext \"pushmenu_teamselect\"");
}
else if (!client->pers.weapon[0])
{
if (level.time > m_fWeapSelectTime)
{
m_fWeapSelectTime = level.time + 1.0f;
gi.SendServerCommand(edict - g_entities, "stufftext \"pushmenu_weaponselect\"");
}
}
else if ((g_gametype->integer == GT_FFA ||
(g_gametype->integer && dm_team > TEAM_FREEFORALL)) &&
(deadflag != DEAD_DEAD))
{
m_bSpectator = false;
m_bTempSpectator = false;
client->ps.pm_flags &= ~PMF_SPECTATING;
if (deadflag) {
deadflag = DEAD_DEAD;
}
PostEvent(EV_Player_Respawn, 0);
}
}
else if (!client->pers.weapon[0])
{
Spectator();
gi.SendServerCommand(edict - g_entities, "stufftext \"pushmenu_weaponselect\"");
}
if (IsSpectator())
{
if ((server_new_buttons & BUTTON_USE))
{
SetPlayerSpectate();
}
if ((g_gametype->integer <= GT_FFA) ||
(!g_forceteamspectate->integer) ||
(dm_team <= TEAM_FREEFORALL))
{
if (last_ucmd.upmove)
{
m_iPlayerSpectating = 0;
}
if (m_iPlayerSpectating)
{
gentity_t *ent = g_entities + m_iPlayerSpectating - 1;
Player *player = (Player *)ent->entity;
if ((!ent->inuse) ||
(!player) ||
(player->deadflag >= DEAD_DEAD) ||
(
(player->IsSpectator()) ||
(
g_gametype->integer > GT_FFA &&
g_forceteamspectate->integer &&
dm_team > TEAM_FREEFORALL &&
player->GetTeam() != GetTeam()
)
))
{
SetPlayerSpectate();
}
}
}
else
{
if (!m_iPlayerSpectating)
{
SetPlayerSpectate();
}
else
{
gentity_t *ent = g_entities + m_iPlayerSpectating - 1;
Player *player = (Player *)ent->entity;
if (!ent->inuse)
{
SetPlayerSpectate();
}
else if (!player)
{
SetPlayerSpectate();
}
else if (player->deadflag >= DEAD_DEAD)
{
SetPlayerSpectate();
}
else if (player->IsSpectator())
{
SetPlayerSpectate();
}
else if (g_gametype->integer > GT_FFA)
{
if ((dm_team > TEAM_FREEFORALL) &&
(g_forceteamspectate->integer) &&
(GetDM_Team()->NumLivePlayers()) &&
(player->GetTeam() != GetTeam()))
{
SetPlayerSpectate();
}
}
}
}
}
else
{
m_iPlayerSpectating = 0;
}
}
if( g_logstats->integer )
{
if( !logfile_started )
{
ProcessEvent( EV_Player_LogStats );
logfile_started = qtrue;
}
}
if( !IsDead() )
{
m_iClientWeaponCommand = ( server_new_buttons & 0x780 ) >> 7;
switch( m_iClientWeaponCommand )
{
case 0:
break;
case 1:
m_pWeaponCommand = new Event( EV_Sentient_UseWeaponClass );
m_pWeaponCommand->AddString( "pistol" );
break;
case 2:
m_pWeaponCommand = new Event( EV_Sentient_UseWeaponClass );
m_pWeaponCommand->AddString( "rifle" );
break;
case 3:
m_pWeaponCommand = new Event( EV_Sentient_UseWeaponClass );
m_pWeaponCommand->AddString( "smg" );
break;
case 4:
m_pWeaponCommand = new Event( EV_Sentient_UseWeaponClass );
m_pWeaponCommand->AddString( "mg" );
break;
case 5:
m_pWeaponCommand = new Event( EV_Sentient_UseWeaponClass );
m_pWeaponCommand->AddString( "grenade" );
break;
case 6:
m_pWeaponCommand = new Event( EV_Sentient_UseWeaponClass );
m_pWeaponCommand->AddString( "heavy" );
break;
case 7:
m_pWeaponCommand = new Event( EV_Sentient_ToggleItemUse );
break;
case 8:
m_pWeaponCommand = new Event( EV_Sentient_UseWeaponClass );
m_pWeaponCommand->AddString( "item2" );
break;
case 9:
m_pWeaponCommand = new Event( EV_Sentient_UseWeaponClass );
m_pWeaponCommand->AddString( "item3" );
break;
case 10:
m_pWeaponCommand = new Event( EV_Sentient_UseWeaponClass );
m_pWeaponCommand->AddString( "item4" );
break;
case 11:
m_pWeaponCommand = new Event( EV_Player_PrevWeapon );
break;
case 12:
m_pWeaponCommand = new Event( EV_Player_NextWeapon );
break;
case 13:
m_pWeaponCommand = new Event( EV_Sentient_UseLastWeapon );
break;
case 14:
m_pWeaponCommand = new Event( EV_Player_Holster );
break;
case 15:
m_pWeaponCommand = new Event( EV_Player_DropWeapon );
break;
default:
gi.DPrintf( "Unrecognized weapon command %d\n", m_iClientWeaponCommand );
}
if( m_pWeaponCommand )
{
ProcessEvent( m_pWeaponCommand );
}
}
if( !g_aimLagTime )
{
g_aimLagTime = gi.Cvar_Get( "g_aimLagTime", "250", 0 );
}
if( mLastTrailTime + g_aimLagTime->integer < level.inttime )
{
mLastTrailTime = level.inttime;
mvTrail[ 0 ] = centroid;
mvTrailEyes[ 0 ] = centroid;
mvTrailEyes[ 0 ][ 0 ] = EyePosition()[ 0 ];
}
UpdateFootsteps();
// where did you get this @ley0k :3
if( !animDoneVM )
{
int index;
float anim_time;
vma_t *vma = vmalist.find( m_sVMcurrent );
index = m_fpsTiki == NULL ? -1 : gi.Anim_NumForName( m_fpsTiki, m_sVMAcurrent );
if( index >= 0 )
{
anim_time = gi.Anim_Time( m_fpsTiki, index );
if( m_fVMAtime < anim_time )
{
if( vma )
{
m_fVMAtime += level.frametime * vma->speed;
}
else
{
m_fVMAtime += level.frametime;
}
}
else
{
animDoneVM = true;
m_fVMAtime = 0;
Notify( "viewmodelanim_done" );
}
}
else
{
animDoneVM = true;
m_fVMAtime = 0;
Notify( "viewmodelanim_done" );
}
}
server_new_buttons = 0;
}
void Player::Postthink
(
void
)
{
if( bindmaster )
{
SetViewAngles( GetViewAngles() + Vector( 0, bindmaster->avelocity[ YAW ] * level.frametime, 0 ) );
}
}
void Player::InitLegsStateTable( void )
{
animdone_Legs = false;
currentState_Legs = statemap_Legs->FindState( "STAND" );
str legsAnim( currentState_Legs->getLegAnim( *this, &legs_conditionals ) );
if( legsAnim == "" )
{
StopPartAnimating( legs );
}
else if( legsAnim != "none" )
{
SetPartAnim( legsAnim.c_str(), legs );
}
}
void Player::InitTorsoStateTable( void )
{
animdone_Torso = false;
currentState_Torso = statemap_Torso->FindState( "STAND" );
str torsoAnim( currentState_Torso->getActionAnim( *this, &torso_conditionals ) );
if( torsoAnim == "" )
{
StopPartAnimating( torso );
}
else if( torsoAnim != "none" )
{
SetPartAnim( torsoAnim.c_str(), torso );
}
}
void Player::LoadStateTable( void )
{
statemap_Legs = NULL;
statemap_Torso = NULL;
legs_conditionals.FreeObjectList();
torso_conditionals.FreeObjectList();
statemap_Legs = GetStatemap( str( g_statefile->string ) + "_Legs.st", ( Condition<Class> * )Conditions, &legs_conditionals, false );
statemap_Torso = GetStatemap( str( g_statefile->string ) + "_Torso.st", ( Condition<Class> * )Conditions, &torso_conditionals, false );
movecontrol = MOVECONTROL_LEGS;
InitLegsStateTable();
InitTorsoStateTable();
movecontrol = currentState_Legs->getMoveType();
if( !movecontrol ) {
movecontrol = MOVECONTROL_LEGS;
}
for( int i = 1; i <= legs_conditionals.NumObjects(); i++ )
{
Conditional *c = legs_conditionals.ObjectAt( i );
if( Q_stricmp( c->getName(), "PAIN" ) && !c->parmList.NumObjects() )
{
m_pLegsPainCond = c;
break;
}
}
for( int i = 1; i <= torso_conditionals.NumObjects(); i++ )
{
Conditional *c = torso_conditionals.ObjectAt( i );
if( Q_stricmp( c->getName(), "PAIN" ) && !c->parmList.NumObjects() )
{
m_pTorsoPainCond = c;
break;
}
}
if( ( movecontrol < ( sizeof( MoveStartFuncs ) / sizeof( MoveStartFuncs[ 0 ] ) ) ) && ( MoveStartFuncs[ movecontrol ] ) )
{
( this->*MoveStartFuncs[ movecontrol ] )( );
}
SetViewAngles( v_angle );
}
void Player::ResetState
(
Event *ev
)
{
movecontrol = MOVECONTROL_LEGS;
LoadStateTable();
}
void Player::StartPush
(
void
)
{
trace_t trace;
Vector end( origin + yaw_forward * 64.0f );
trace = G_Trace( origin, mins, maxs, end, this, MASK_SOLID, true, "StartPush" );
if ( trace.fraction == 1.0f )
{
return;
}
v_angle.y = vectoyaw( trace.plane.normal ) - 180;
SetViewAngles( v_angle );
setOrigin( trace.endpos - yaw_forward * 0.4f );
}
void Player::StartClimbWall
(
void
)
{
trace_t trace;
Vector end( origin + yaw_forward * 20.0f );
trace = G_Trace( origin, mins, maxs, end, this, MASK_SOLID, true, "StartClimbWall" );
if ( ( trace.fraction == 1.0f ) || !( trace.surfaceFlags & SURF_LADDER ) )
{
return;
}
v_angle.y = vectoyaw( trace.plane.normal ) - 180;
SetViewAngles( v_angle );
setOrigin( trace.endpos - yaw_forward * 0.4f );
}
void Player::StartUseAnim
(
void
)
{
UseAnim *ua;
Vector neworg;
Vector newangles;
str newanim;
str state;
str camera;
trace_t trace;
if( toucheduseanim )
{
ua = ( UseAnim * )( Entity * )toucheduseanim;
}
else if( atobject )
{
ua = ( UseAnim * )( Entity * )atobject;
}
else
{
return;
}
useitem_in_use = ua;
toucheduseanim = NULL;
atobject = NULL;
if( ua->GetInformation( this, &neworg, &newangles, &newanim, &useanim_numloops, &state, &camera ) )
{
trace = G_Trace( origin, mins, maxs, neworg, this, MASK_PLAYERSOLID, true, "StartUseAnim" );
if( trace.startsolid || ( trace.fraction < 1.0f ) )
{
gi.DPrintf( "Move to UseAnim was blocked.\n" );
}
if( !trace.startsolid )
{
setOrigin( trace.endpos );
}
setAngles( newangles );
v_angle.y = newangles.y;
SetViewAngles( v_angle );
movecontrol = MOVECONTROL_ABSOLUTE;
if( state.length() )
{
State * newState;
newState = statemap_Torso->FindState( state );
if( newState )
{
EvaluateState( newState );
}
else
{
gi.DPrintf( "Could not find state %s on UseAnim\n", state.c_str() );
}
}
else
{
if( currentState_Torso )
{
if( camera.length() )
{
currentState_Torso->setCameraType( camera );
}
else
{
currentState_Torso->setCameraType( "behind" );
}
}
SetPartAnim( newanim, legs );
}
}
}
void Player::StartLoopUseAnim
(
void
)
{
useanim_numloops--;
}
void Player::FinishUseAnim
(
Event *ev
)
{
UseAnim *ua;
if ( !useitem_in_use )
return;
ua = ( UseAnim * )( Entity * )useitem_in_use;
ua->TriggerTargets( this );
useitem_in_use = NULL;
}
void Player::SetupUseObject
(
void
)
{
UseObject *uo;
Vector neworg;
Vector newangles;
str state;
trace_t trace;
if ( atobject )
{
uo = ( UseObject * )( Entity * )atobject;
}
else
{
return;
}
useitem_in_use = uo;
uo->Setup( this, &neworg, &newangles, &state );
{
trace = G_Trace( neworg, mins, maxs, neworg, this, MASK_PLAYERSOLID, true, "SetupUseObject - 1" );
if ( trace.startsolid || trace.allsolid )
{
trace = G_Trace( origin, mins, maxs, neworg, this, MASK_PLAYERSOLID, true, "SetupUseObject - 2" );
if ( trace.startsolid || ( trace.fraction < 1.0f ) )
{
gi.DPrintf( "Move to UseObject was blocked.\n" );
}
}
if ( !trace.startsolid )
{
setOrigin( trace.endpos );
}
setAngles( newangles );
v_angle.y = newangles.y;
SetViewAngles( v_angle );
movecontrol = MOVECONTROL_ABSOLUTE;
if ( state.length() )
{
State * newState;
newState = statemap_Torso->FindState( state );
if ( newState )
{
EvaluateState( newState );
}
else
{
gi.DPrintf( "Could not find state %s on UseObject\n", state.c_str() );
}
}
}
}
void Player::StartUseObject
(
Event *ev
)
{
UseObject *uo;
if ( !useitem_in_use )
return;
uo = ( UseObject * )( Entity * )useitem_in_use;
uo->Start();
}
void Player::FinishUseObject
(
Event *ev
)
{
UseObject *uo;
if ( !useitem_in_use )
return;
uo = ( UseObject * )( Entity * )useitem_in_use;
uo->Stop( this );
useitem_in_use = NULL;
}
void Player::Turn
(
Event *ev
)
{
float yaw;
Vector oldang( v_angle );
yaw = ev->GetFloat( 1 );
v_angle[ YAW ] = ( int )( anglemod( v_angle[ YAW ] ) / 22.5f ) * 22.5f;
SetViewAngles( v_angle );
if ( !CheckMove( vec_zero ) )
{
SetViewAngles( oldang );
return;
}
CancelEventsOfType( EV_Player_TurnUpdate );
ev = new Event( EV_Player_TurnUpdate );
ev->AddFloat( yaw / 5.0f );
ev->AddFloat( 0.5f );
ProcessEvent( ev );
}
void Player::TurnUpdate
(
Event *ev
)
{
float yaw;
float timeleft;
Vector oldang( v_angle );
yaw = ev->GetFloat( 1 );
timeleft = ev->GetFloat( 2 );
timeleft -= 0.1f;
if ( timeleft > 0 )
{
ev = new Event( EV_Player_TurnUpdate );
ev->AddFloat( yaw );
ev->AddFloat( timeleft );
PostEvent( ev, 0.1f );
v_angle[ YAW ] += yaw;
SetViewAngles( v_angle );
}
else
{
v_angle[ YAW ] = ( int )( anglemod( v_angle[ YAW ] ) / 22.5f ) * 22.5f;
SetViewAngles( v_angle );
}
if ( !CheckMove( vec_zero ) )
{
SetViewAngles( oldang );
}
}
void Player::TurnLegs
(
Event *ev
)
{
float yaw;
yaw = ev->GetFloat( 1 );
angles[ YAW ] += yaw;
setAngles( angles );
}
void Player::EvaluateState
(
State *forceTorso,
State *forceLegs
)
{
int count;
State *laststate_Legs;
State *laststate_Torso;
State *startstate_Legs;
State *startstate_Torso;
movecontrol_t move;
if( getMoveType() == MOVETYPE_NOCLIP )
{
return;
}
// Evaluate the current state.
// When the state changes, we reevaluate the state so that if the
// conditions aren't met in the new state, we don't play one frame of
// the animation for that state before going to the next state.
startstate_Torso = laststate_Torso = currentState_Torso;
count = 0;
do
{
// since we could get into an infinite loop here, do a check
// to make sure we don't.
count++;
if( count > 10 )
{
gi.DPrintf( "Possible infinite loop in state '%s'\n", currentState_Torso->getName() );
if( count > 20 )
{
assert( 0 );
gi.Error( ERR_DROP, "Stopping due to possible infinite state loop\n" );
break;
}
}
laststate_Torso = currentState_Torso;
if( forceTorso )
currentState_Torso = forceTorso;
else
currentState_Torso = currentState_Torso->Evaluate( *this, &torso_conditionals );
if( currentState_Torso )
{
// Process exit commands of the last state
laststate_Torso->ProcessExitCommands( this );
// Process entry commands of the new state
currentState_Torso->ProcessEntryCommands( this );
if( waitForState.length() && ( !waitForState.icmpn( currentState_Torso->getName(), waitForState.length() ) ) )
{
waitForState = "";
PlayerDone( NULL );
}
move = currentState_Torso->getMoveType();
// use the current movecontrol
if( move == MOVECONTROL_NONE ) {
move = movecontrol;
}
str legsAnim;
str torsoAnim( currentState_Torso->getActionAnim( *this, &torso_conditionals ) );
if( move == MOVECONTROL_LEGS )
{
if( !currentState_Legs )
{
animdone_Legs = false;
currentState_Legs = statemap_Legs->FindState( "STAND" );
legsAnim = currentState_Legs->getLegAnim( *this, &legs_conditionals );
if( legsAnim == "" )
{
StopPartAnimating( legs );
}
else if( legsAnim != "none" )
{
SetPartAnim( legsAnim.c_str(), legs );
}
}
if( torsoAnim == "none" )
{
StopPartAnimating( torso );
animdone_Torso = true;
}
else if( torsoAnim != "" )
{
SetPartAnim( torsoAnim.c_str(), torso );
}
}
else
{
if( torsoAnim == "none" )
{
StopPartAnimating( torso );
animdone_Torso = true;
}
else if( torsoAnim != "" )
{
SetPartAnim( torsoAnim.c_str(), torso );
}
legsAnim = currentState_Torso->getLegAnim( *this, &torso_conditionals );
if( legsAnim == "none" || legsAnim == "" )
{
StopPartAnimating( legs );
}
else
{
SetPartAnim( legsAnim.c_str(), legs );
}
}
if( movecontrol != move )
{
movecontrol = move;
if( ( move < ( sizeof( MoveStartFuncs ) / sizeof( MoveStartFuncs[ 0 ] ) ) ) && ( MoveStartFuncs[ move ] ) )
{
( this->*MoveStartFuncs[ move ] )( );
}
if( movecontrol == MOVECONTROL_CLIMBWALL )
{
edict->s.eFlags |= EF_CLIMBWALL;
}
else
{
edict->s.eFlags &= ~EF_CLIMBWALL;
}
}
SetViewAngles( v_angle );
}
else
{
currentState_Torso = laststate_Torso;
}
} while( laststate_Torso != currentState_Torso );
// Evaluate the current state.
// When the state changes, we reevaluate the state so that if the
// conditions aren't met in the new state, we don't play one frame of
// the animation for that state before going to the next state.
startstate_Legs = laststate_Legs = currentState_Legs;
if( movecontrol == MOVECONTROL_LEGS )
{
count = 0;
do
{
// since we could get into an infinite loop here, do a check
// to make sure we don't.
count++;
if( count > 10 )
{
gi.DPrintf( "Possible infinite loop in state '%s'\n", currentState_Legs->getName() );
if( count > 20 )
{
assert( 0 );
gi.Error( ERR_DROP, "Stopping due to possible infinite state loop\n" );
break;
}
}
if( !laststate_Legs )
{
if( ( m_iMovePosFlags & MPF_POSITION_CROUCHING ) )
currentState_Legs = statemap_Legs->FindState( "CROUCH_IDLE" );
else
currentState_Legs = statemap_Legs->FindState( "STAND" );
}
laststate_Legs = currentState_Legs;
if( forceLegs )
currentState_Legs = forceLegs;
else
currentState_Legs = currentState_Legs->Evaluate( *this, &legs_conditionals );
animdone_Legs = false;
if( currentState_Legs )
{
// Process exit commands of the last state
laststate_Legs->ProcessExitCommands( this );
// Process entry commands of the new state
currentState_Legs->ProcessEntryCommands( this );
if( waitForState.length() && ( !waitForState.icmpn( currentState_Legs->getName(), waitForState.length() ) ) )
{
waitForState = "";
PlayerDone( NULL );
}
str legsAnim( currentState_Legs->getLegAnim( *this, &legs_conditionals ) );
if( legsAnim == "none" )
{
StopPartAnimating( legs );
animdone_Legs = true;
}
else if( legsAnim != "" )
{
SetPartAnim( legsAnim, legs );
}
}
else
{
currentState_Legs = laststate_Legs;
}
} while( laststate_Legs != currentState_Legs );
}
else
{
currentState_Legs = NULL;
}
if( g_showplayeranim->integer )
{
if( last_leg_anim_name != AnimName( legs ) )
{
gi.DPrintf( "Legs change from %s to %s\n", last_leg_anim_name.c_str(), AnimName( legs ) );
last_leg_anim_name = AnimName( legs );
}
if( last_torso_anim_name != AnimName( torso ) )
{
gi.DPrintf( "Torso change from %s to %s\n", last_torso_anim_name.c_str(), AnimName( torso ) );
last_torso_anim_name = AnimName( torso );
}
}
if( g_showplayerstate->integer )
{
if( startstate_Legs != currentState_Legs )
{
gi.DPrintf( "Legs change from %s to %s\n",
startstate_Legs ? startstate_Legs->getName() : "NULL",
currentState_Legs ? currentState_Legs->getName() : "NULL" );
}
if( startstate_Torso != currentState_Torso )
{
gi.DPrintf( "Torso change from %s to %s\n",
startstate_Torso ? startstate_Torso->getName() : "NULL",
currentState_Torso ? currentState_Torso->getName() : "NULL" );
}
}
// This is so we don't remember pain when we change to a state that has a PAIN condition
pain = 0;
}
void Player::GiveWeaponCheat
(
Event *ev
)
{
giveItem( ev->GetString( 1 ) );
}
void Player::GiveCheat
(
Event *ev
)
{
str name;
if ( deadflag )
{
return;
}
name = ev->GetString( 1 );
if ( !name.icmp( "all" ) )
{
GiveAllCheat( ev );
return;
}
EventGiveItem( ev );
}
void Player::GiveAllCheat
(
Event *ev
)
{
char *buffer;
char *buf;
char com_token[MAX_STRING_CHARS];
if ( deadflag )
{
return;
}
if ( gi.FS_ReadFile( "global/giveall.scr", ( void ** )&buf, true ) != -1 )
{
buffer = buf;
while ( 1 )
{
strcpy( com_token, COM_ParseExt( &buffer, qtrue ) );
if (!com_token[0])
break;
// Create the event
ev = new Event( com_token );
// get the rest of the line
while( 1 )
{
strcpy( com_token, COM_ParseExt( &buffer, qfalse ) );
if (!com_token[0])
break;
ev->AddToken( com_token );
}
this->ProcessEvent( ev );
}
gi.FS_FreeFile( buf );
}
}
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->IsFromScript() )
{
if( !( flags & FL_GODMODE ) )
{
msg = "godmode OFF\n";
}
else
{
msg = "godmode ON\n";
}
gi.SendServerCommand( edict-g_entities, "print \"%s\"", msg );
}
}
void Player::FullHeal
(
Event *ev
)
{
if( IsDead() )
{
if( !ev->IsFromScript() )
{
HUDPrint( "TESTING: Cannot resurrect yourself with the fullheal.\n" );
}
}
else
{
if( !ev->IsFromScript() )
{
HUDPrint( "TESTING: You used the fullheal.\n" );
}
health = max_health;
}
}
void Player::EventFace
(
Event *ev
)
{
SetViewAngles( Vector( ev->GetFloat( 1 ), ev->GetFloat( 2 ), ev->GetFloat( 3 ) ) );
}
void Player::Kill
(
Event *ev
)
{
if ( ( level.time - respawn_time ) < 5 )
{
return;
}
flags &= ~FL_GODMODE;
health = 1;
Damage( this, this, 10, origin, vec_zero, vec_zero, 0, DAMAGE_NO_PROTECTION, MOD_SUICIDE );
}
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.SendServerCommand( edict-g_entities, "print \"%s\"", msg );
}
void Player::NoclipCheat
(
Event *ev
)
{
const char *msg;
if( m_pVehicle )
{
msg = "Must exit vehicle first\n";
}
else if( m_pTurret )
{
msg = "Must exit turret first\n";
}
else if( getMoveType() == MOVETYPE_NOCLIP )
{
setMoveType( MOVETYPE_WALK );
msg = "noclip OFF\n";
// reset the state machine so that his animations are correct
ResetState( NULL );
}
else
{
client->ps.feetfalling = false;
movecontrol = MOVECONTROL_LEGS;
setMoveType( MOVETYPE_NOCLIP );
msg = "noclip ON\n";
}
gi.SendServerCommand( edict - g_entities, "print \"%s\"", msg );
}
void Player::EventTeleport
(
Event *ev
)
{
if( ev->NumArgs() == 1 )
{
setOrigin( ev->GetVector( 1 ) );
}
else
{
setOrigin( Vector( ev->GetFloat( 1 ), ev->GetFloat( 2 ), ev->GetFloat( 3 ) ) );
}
}
void Player::GameVersion
(
Event *ev
)
{
gi.SendServerCommand( edict-g_entities, "print \"%s : %s\n\"", GAMEVERSION, __DATE__ );
}
void Player::SetFov
(
float newFov
)
{
fov = newFov;
if( fov < 1 )
{
fov = 80;
}
else if( fov > 160 )
{
fov = 160;
}
}
void Player::EventSetSelectedFov
(
Event *ev
)
{
if( ev->NumArgs() < 1 )
{
gi.SendServerCommand( edict - g_entities, "print \"Fov = %d\n\"", ( unsigned int )fov );
return;
}
SetSelectedFov( ev->GetFloat( 1 ) );
SetFov( selectedfov );
}
void Player::SetSelectedFov
(
float newFov
)
{
selectedfov = newFov;
if( selectedfov < 1 )
{
selectedfov = 80;
}
else if( selectedfov > 160 )
{
selectedfov = 160;
}
/*
if( g_gametype->integer && !developer->integer )
{
if( selectedfov < 80 )
{
selectedfov = 80;
}
else if( selectedfov > 80 )
{
selectedfov = 80;
}
}
*/
}
void Player::SafeZoomed
(
Event *ev
)
{
if( ev->GetInteger( 1 ) )
{
if( m_iInZoomMode > 0 )
{
SetFov( m_iInZoomMode );
m_iInZoomMode = -1;
}
}
else
{
if( m_iInZoomMode == -1 )
{
m_iInZoomMode = fov;
SetFov( selectedfov );
}
}
}
void Player::ToggleZoom
(
int iZoom
)
{
if( iZoom && m_iInZoomMode == -1 )
{
SetFov( selectedfov );
m_iInZoomMode = 0;
}
else
{
SetFov( iZoom );
m_iInZoomMode = -1;
}
}
void Player::ZoomOff
(
void
)
{
SetFov( selectedfov );
m_iInZoomMode = 0;
}
void Player::ZoomOffEvent
(
Event *ev
)
{
ZoomOff();
}
qboolean Player::IsZoomed
(
void
)
{
return m_iInZoomMode == -1;
}
/*
===============
CalcRoll
===============
*/
float Player::CalcRoll
(
void
)
{
float sign;
float side;
float value;
Vector l;
angles.AngleVectors( NULL, &l, NULL );
side = velocity * l;
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;
}
//
// PMove Events
//
void Player::ProcessPmoveEvents
(
int event
)
{
float damage;
switch( event )
{
case EV_NONE:
break;
case EV_FALL_SHORT:
case EV_FALL_MEDIUM:
case EV_FALL_FAR:
case EV_FALL_FATAL:
if( event == EV_FALL_FATAL )
{
damage = max_health + 1.0f;
}
else if( event == EV_FALL_FAR )
{
damage = 20;
}
else if( event == EV_FALL_MEDIUM )
{
damage = 10;
}
else
{
damage = 5;
}
if( !DM_FLAG( DF_NO_FALLING ) )
{
Damage( world, world, ( int )damage, origin, vec_zero, vec_zero, 0, DAMAGE_NO_ARMOR, MOD_FALLING );
}
break;
case EV_TERMINAL_VELOCITY:
Sound( "snd_fall", CHAN_VOICE );
break;
// fakk2 remnants
/*
case EV_WATER_TOUCH: // foot touches
if( watertype & CONTENTS_LAVA )
{
Sound( "snd_burn", CHAN_LOCAL );
}
else
{
Animate *water;
trace_t trace;
Vector start;
float scale;
Sound( "impact_playersplash", CHAN_AUTO );
// Find the correct place to put the splash
start = origin + Vector( 0, 0, 90 );
trace = G_Trace( start, vec_zero, vec_zero, origin, NULL, MASK_WATER, false, "ProcessPmoveEvents" );
// Figure out a good scale for the splash
scale = 1 + ( velocity[ 2 ] + 400 ) / -1500;
if( scale < 1 )
scale = 1;
else if( scale > 1.5 )
scale = 1.5;
// Spawn in a water splash
water = new Animate;
water->setOrigin( trace.endpos );
water->setModel( "fx_splashsmall.tik" );
water->setScale( scale );
water->NewAnim( "idle" );
water->PostEvent( EV_Remove, 5 );
}
break;
*/
case EV_WATER_LEAVE: // foot leaves
Sound( "impact_playerleavewater", CHAN_AUTO );
break;
case EV_WATER_UNDER: // head touches
Sound( "impact_playersubmerge", CHAN_AUTO );
break;
case EV_WATER_CLEAR: // head leaves
Sound( "snd_gasp", CHAN_LOCAL );
break;
}
}
/*
=============
WorldEffects
=============
*/
void Player::WorldEffects
(
void
)
{
if( deadflag == DEAD_DEAD )
{
// if we are dead, no world effects
return;
}
//
// check for on fire
//
if( on_fire )
{
if( next_painsound_time < level.time )
{
next_painsound_time = level.time + 4;
Sound( "snd_onfire", CHAN_LOCAL );
}
}
}
/*
=============
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;
client->ps.stats[STAT_ADDFADE] =0;
blend[ 0 ] = blend[ 1 ] = blend[ 2 ] = blend[ 3 ] = 0;
// add for contents
vieworg = m_vViewPos;
contents = gi.PointContents( vieworg, 0 );
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 );
}
// add for damage
if ( damage_alpha > 0 )
{
AddBlend( damage_blend[ 0 ], damage_blend[ 1 ], damage_blend[ 2 ], damage_alpha );
// drop the damage value
damage_alpha -= 0.06f;
if ( damage_alpha < 0 )
{
damage_alpha = 0;
}
client->ps.blend[0] = blend[0];
client->ps.blend[1] = blend[1];
client->ps.blend[2] = blend[2];
client->ps.blend[3] = blend[3];
}
// Do the cinematic fading
float alpha=1;
level.m_fade_time -= level.frametime;
// Return if we are completely faded in
if ( ( level.m_fade_time <= 0 ) && ( level.m_fade_type == fadein ) )
{
client->ps.blend[3] = 0 + damage_alpha;
return;
}
// If we are faded out, and another fade out is coming in, then don't bother
if ( ( level.m_fade_time_start > 0 ) && ( level.m_fade_type == fadeout ) )
{
if ( client->ps.blend[3] >= 1 )
return;
}
if ( level.m_fade_time_start > 0 )
alpha = level.m_fade_time / level.m_fade_time_start;
if ( level.m_fade_type == fadeout )
alpha = 1.0f - alpha;
if ( alpha < 0 )
alpha = 0;
if ( alpha > 1 )
alpha = 1;
if ( level.m_fade_style == additive )
{
client->ps.blend[0] = level.m_fade_color[0] * level.m_fade_alpha * alpha;
client->ps.blend[1] = level.m_fade_color[1] * level.m_fade_alpha * alpha;
client->ps.blend[2] = level.m_fade_color[2] * level.m_fade_alpha * alpha;
client->ps.blend[3] = level.m_fade_alpha * alpha;
client->ps.stats[STAT_ADDFADE] = 1;
}
else
{
client->ps.blend[0] = level.m_fade_color[0];
client->ps.blend[1] = level.m_fade_color[1];
client->ps.blend[2] = level.m_fade_color[2];
client->ps.blend[3] = level.m_fade_alpha * alpha;
client->ps.stats[STAT_ADDFADE] = 0;
}
}
/*
===============
P_DamageFeedback
Handles color blends and view kicks
===============
*/
void Player::DamageFeedback
(
void
)
{
float realcount;
float count;
// if we are dead, don't setup any feedback
if( health <= 0 )
{
damage_count = 0;
damage_blood = 0;
damage_alpha = 0;
VectorClear( damage_angles );
return;
}
#define DAMAGE_MAX_PITCH_SCALE 0.3f
#define DAMAGE_MAX_YAW_SCALE 0.3f
if( damage_blood > damage_count )
{
float pitch_delta;
float yaw_delta;
damage_angles = damage_from.toAngles();
pitch_delta = AngleDelta( angles.x, damage_angles.x ) / 90.0f;
yaw_delta = AngleDelta( angles.y, damage_angles.y ) / 90.0f;
if( pitch_delta > DAMAGE_MAX_PITCH_SCALE )
pitch_delta = DAMAGE_MAX_PITCH_SCALE;
else if( pitch_delta < -DAMAGE_MAX_PITCH_SCALE )
pitch_delta = -DAMAGE_MAX_PITCH_SCALE;
if( yaw_delta > DAMAGE_MAX_YAW_SCALE )
yaw_delta = DAMAGE_MAX_YAW_SCALE;
else if( yaw_delta < -DAMAGE_MAX_YAW_SCALE )
yaw_delta = -DAMAGE_MAX_YAW_SCALE;
damage_angles[ PITCH ] = pitch_delta;
damage_angles[ ROLL ] = yaw_delta;
damage_count = damage_blood * 2.0f;
}
if( damage_count )
{
// decay damage_count over time
damage_count *= 0.90f;
if( damage_count < 0.1f )
damage_count = 0;
}
// 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.001;
if( damage_alpha < 0.2f )
{
damage_alpha = 0.2f;
}
if( damage_alpha > 0.6f )
{
// don't go too saturated
damage_alpha = 0.6f;
}
// 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;
}
void Player::GetPlayerView
(
Vector *pos,
Vector *angle
)
{
if( pos )
{
*pos = origin;
pos->z += viewheight;
}
if( angle )
{
*angle = Vector( client->ps.viewangles );
}
}
void Player::SetPlayerView
(
Camera *camera,
Vector position,
float cameraoffset,
Vector ang,
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.viewheight = cameraoffset;
client->ps.origin[ 0 ] = position[ 0 ];
client->ps.origin[ 1 ] = position[ 1 ];
client->ps.origin[ 2 ] = position[ 2 ];
client->ps.velocity[ 0 ] = vel[ 0 ];
client->ps.velocity[ 1 ] = vel[ 1 ];
client->ps.velocity[ 2 ] = vel[ 2 ];
/*
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;
if( camera )
{
if( camera->IsSubclassOfCamera() )
{
client->ps.camera_angles[ 0 ] = camera->angles[ 0 ];
client->ps.camera_angles[ 1 ] = camera->angles[ 1 ];
client->ps.camera_angles[ 2 ] = camera->angles[ 2 ];
client->ps.camera_origin[ 0 ] = camera->origin[ 0 ];
client->ps.camera_origin[ 1 ] = camera->origin[ 1 ];
client->ps.camera_origin[ 2 ] = camera->origin[ 2 ];
Vector vOfs = camera->GetPositionOffset();
VectorCopy( vOfs, client->ps.camera_posofs );
client->ps.pm_flags |= PMF_CAMERA_VIEW;
//
// clear out the flags, but preserve the CF_CAMERA_CUT_BIT
//
client->ps.camera_flags = client->ps.camera_flags & CF_CAMERA_CUT_BIT;
}
else if( camera->IsSubclassOfPlayer() )
{
//FIXME: inline func Player::GetSpectateFollowOrientation
if( !g_spectatefollow_firstperson->integer )
{
Vector forward, right, up;
Vector vAngles, vCamOfs;
Vector start;
trace_t trace;
// spectating a player
Player *m_player = ( Player * )camera;
vAngles = m_player->GetVAngles();
AngleVectors( vAngles, forward, right, up );
vCamOfs = m_player->origin;
vCamOfs[ 2 ] += m_player->viewheight;
vCamOfs += forward * g_spectatefollow_forward->value;
vCamOfs += right * g_spectatefollow_right->value;
vCamOfs += up * g_spectatefollow_up->value;
if( m_player->client->ps.fLeanAngle != 0.0f )
{
vCamOfs += client->ps.fLeanAngle * 0.65f * forward;
}
start = m_player->origin;
start[ 2 ] += m_player->maxs[ 2 ] - 2.0;
Vector vMins = Vector( -2, -2, 2 );
Vector vMaxs = Vector( 2, 2, 2 );
trace = G_Trace(
start,
vMins,
vMaxs,
vCamOfs,
m_player,
MASK_SHOT,
false,
"Player::GetSpectateFollowOrientation" );
vAngles[ 0 ] += g_spectatefollow_pitch->value * trace.fraction;
VectorCopy( vAngles, client->ps.camera_angles );
VectorCopy( trace.endpos, client->ps.camera_origin );
SetViewAngles( vAngles );
setOrigin( trace.endpos );
VectorClear( client->ps.camera_posofs );
client->ps.camera_flags = client->ps.camera_flags & CF_CAMERA_CUT_BIT;
client->ps.pm_flags |= PMF_CAMERA_VIEW;
}
else
{
Player *m_player = ( Player * )camera;
client->ps.camera_angles[ 0 ] = m_player->angles[ 0 ];
client->ps.camera_angles[ 1 ] = m_player->angles[ 1 ];
client->ps.camera_angles[ 2 ] = m_player->angles[ 2 ];
client->ps.camera_origin[ 0 ] = m_player->origin[ 0 ];
client->ps.camera_origin[ 1 ] = m_player->origin[ 1 ];
client->ps.camera_origin[ 2 ] = m_player->origin[ 2 ];
SetViewAngles( m_player->GetViewAngles() );
setOrigin( m_player->origin );
VectorClear( client->ps.camera_posofs );
client->ps.camera_flags = client->ps.camera_flags & CF_CAMERA_CUT_BIT;
client->ps.pm_flags |= PMF_CAMERA_VIEW;
}
}
else
{
client->ps.camera_angles[ 0 ] = ang[ 0 ];
client->ps.camera_angles[ 1 ] = ang[ 1 ];
client->ps.camera_angles[ 2 ] = ang[ 2 ];
client->ps.camera_origin[ 0 ] = position[ 0 ];
client->ps.camera_origin[ 1 ] = position[ 1 ];
client->ps.camera_origin[ 2 ] = position[ 2 ];
VectorClear( client->ps.camera_posofs );
client->ps.camera_flags = client->ps.camera_flags & CF_CAMERA_CUT_BIT;
client->ps.pm_flags |= PMF_CAMERA_VIEW;
}
}
else
{
client->ps.pm_flags &= ~PMF_CAMERA_VIEW;
//
// make sure the third person camera is setup correctly.
//
if( getMoveType() != MOVETYPE_NOCLIP )
{
qboolean do_cut;
int camera_type;
camera_type = currentState_Torso->getCameraType();
if( last_camera_type != camera_type )
{
//
// clear out the flags, but preserve the CF_CAMERA_CUT_BIT
//
client->ps.camera_flags = client->ps.camera_flags & CF_CAMERA_CUT_BIT;
do_cut = qtrue;
switch( camera_type )
{
case CAMERA_TOPDOWN:
client->ps.camera_flags |= CF_CAMERA_ANGLES_IGNORE_PITCH;
client->ps.camera_offset[ PITCH ] = -75;
client->ps.camera_flags |= CF_CAMERA_ANGLES_ALLOWOFFSET;
do_cut = qfalse;
break;
case CAMERA_FRONT:
client->ps.camera_flags |= CF_CAMERA_ANGLES_IGNORE_PITCH;
client->ps.camera_flags |= CF_CAMERA_ANGLES_ALLOWOFFSET;
client->ps.camera_offset[ YAW ] = 180;
client->ps.camera_offset[ PITCH ] = 0;
break;
case CAMERA_SIDE:
client->ps.camera_flags |= CF_CAMERA_ANGLES_IGNORE_PITCH;
client->ps.camera_flags |= CF_CAMERA_ANGLES_ALLOWOFFSET;
// randomly invert the YAW
if( G_Random( 1 ) > 0.5f )
{
client->ps.camera_offset[ YAW ] = -90;
}
else
{
client->ps.camera_offset[ YAW ] = 90;
}
client->ps.camera_offset[ PITCH ] = 0;
break;
case CAMERA_SIDE_LEFT:
client->ps.camera_flags |= CF_CAMERA_ANGLES_IGNORE_PITCH;
client->ps.camera_flags |= CF_CAMERA_ANGLES_ALLOWOFFSET;
client->ps.camera_offset[ YAW ] = 90;
client->ps.camera_offset[ PITCH ] = 0;
break;
case CAMERA_SIDE_RIGHT:
client->ps.camera_flags |= CF_CAMERA_ANGLES_IGNORE_PITCH;
client->ps.camera_flags |= CF_CAMERA_ANGLES_ALLOWOFFSET;
client->ps.camera_offset[ YAW ] = -90;
client->ps.camera_offset[ PITCH ] = 0;
break;
case CAMERA_BEHIND_FIXED:
do_cut = qfalse;
client->ps.camera_offset[ YAW ] = 0;
client->ps.camera_offset[ PITCH ] = 0;
client->ps.camera_flags |= CF_CAMERA_ANGLES_ALLOWOFFSET;
break;
case CAMERA_BEHIND_NOPITCH:
do_cut = qfalse;
client->ps.camera_flags |= CF_CAMERA_ANGLES_IGNORE_PITCH;
client->ps.camera_offset[ YAW ] = 0;
client->ps.camera_offset[ PITCH ] = 0;
break;
case CAMERA_BEHIND:
do_cut = qfalse;
client->ps.camera_offset[ YAW ] = 0;
client->ps.camera_offset[ PITCH ] = 0;
break;
default:
do_cut = qfalse;
client->ps.camera_offset[ YAW ] = 0;
client->ps.camera_offset[ PITCH ] = 0;
break;
}
last_camera_type = camera_type;
if( do_cut )
CameraCut();
}
}
//
// these are explicitly not cleared so that when the client lerps it still has the last
// camera position for reference. Additionally this causes no extra hits to the network
// traffic.
//
//VectorClear( client->ps.camera_angles );
//VectorClear( client->ps.camera_origin );
}
#define EARTHQUAKE_SCREENSHAKE_PITCH 2
#define EARTHQUAKE_SCREENSHAKE_YAW 2
#define EARTHQUAKE_SCREENSHAKE_ROLL 3
if( level.earthquake_magnitude > 0.0f )
{
client->ps.damage_angles[ PITCH ] = G_CRandom() * level.earthquake_magnitude * EARTHQUAKE_SCREENSHAKE_PITCH;
client->ps.damage_angles[ YAW ] = G_CRandom() * level.earthquake_magnitude * EARTHQUAKE_SCREENSHAKE_YAW;
client->ps.damage_angles[ ROLL ] = G_CRandom() * level.earthquake_magnitude * EARTHQUAKE_SCREENSHAKE_ROLL;
}
else if( damage_count )
{
client->ps.damage_angles[ PITCH ] = damage_angles[ PITCH ] * damage_count;
client->ps.damage_angles[ ROLL ] = damage_angles[ ROLL ] * damage_count;
}
else
{
VectorClear( client->ps.damage_angles );
}
if( m_vViewVariation != vec_zero )
{
for( int i = 0; i < 3; i++ )
{
if( m_vViewVariation[ i ] == 0.0f )
{
continue;
}
client->ps.damage_angles[ i ] += ( ( rand() & 0x7FFF ) * 0.00003f
+ ( rand() & 0x7FFF ) * 0.00003f
- 1.0f )
* m_vViewVariation[ i ];
m_vViewVariation[ i ] = m_vViewVariation[ i ] - m_vViewVariation[ i ] * level.frametime * 8.0f;
if( m_vViewVariation[ i ] < 0.01f )
{
m_vViewVariation[ i ] = 0.0f;
}
}
}
}
void Player::SetupView
(
void
)
{
// if we currently are not in a camera or the camera we are looking through is automatic, evaluate our camera choices
if( actor_to_watch || actor_camera )
{
Vector dir;
Vector watch_angles;
float dist = 0;
Vector focal_point;
Vector left;
trace_t trace;
qboolean delete_actor_camera = false;
Vector camera_mins;
Vector camera_maxs;
if( actor_to_watch )
{
dir = actor_to_watch->origin - origin;
dist = dir.length();
}
// See if we still want to watch this actor
if( !actor_to_watch || dist > 150 || actor_to_watch->deadflag )
{
delete_actor_camera = true;
}
else
{
// Create the camera if we don't have one yet
if( !actor_camera )
{
actor_camera = new Camera();
if( G_Random() < .5 )
{
actor_camera_right = true;
starting_actor_camera_right = true;
}
else
{
actor_camera_right = false;
starting_actor_camera_right = false;
}
}
// Setup the new position of the actor camera
// Go a little above the view height
actor_camera->origin = origin;
actor_camera->origin[ 2 ] += DEFAULT_VIEWHEIGHT + 10;
// Find the focal point ( either the actor's watch offset or top of the bounding box)
if( actor_to_watch->watch_offset != vec_zero )
{
MatrixTransformVector( actor_to_watch->watch_offset, actor_to_watch->orientation, focal_point );
focal_point += actor_to_watch->origin;
}
else
{
focal_point = actor_to_watch->origin;
focal_point[ 2 ] = actor_to_watch->maxs[ 2 ];
}
// Shift the camera back just a little
dir = focal_point - actor_camera->origin;
dir.normalize();
actor_camera->origin -= dir * 15;
// Shift the camera a little to the left or right
watch_angles = dir.toAngles();
watch_angles.AngleVectors( NULL, &left );
if( actor_camera_right )
actor_camera->origin -= left * 15;
else
actor_camera->origin += left * 15;
// Make sure this camera position is ok
camera_mins = "-5 -5 -5";
camera_maxs = "5 5 5";
trace = G_Trace( actor_camera->origin, camera_mins, camera_maxs, actor_camera->origin, actor_camera, MASK_DEADSOLID, false, "SetupView" );
if( trace.startsolid )
{
// Try other side
if( actor_camera_right == starting_actor_camera_right )
{
if( actor_camera_right )
actor_camera->origin += left * 30;
else
actor_camera->origin -= left * 30;
actor_camera_right = !actor_camera_right;
trace = G_Trace( actor_camera->origin, camera_mins, camera_maxs, actor_camera->origin, actor_camera, MASK_DEADSOLID, false, "SetupView2" );
if( trace.startsolid )
{
// Both spots have failed stop doing actor camera
delete_actor_camera = true;
}
}
else
{
// Both spots have failed stop doing actor camera
delete_actor_camera = true;
}
}
if( !delete_actor_camera )
{
// Set the camera's position
actor_camera->setOrigin( actor_camera->origin );
// Set the camera's angles
dir = focal_point - actor_camera->origin;
watch_angles = dir.toAngles();
actor_camera->setAngles( watch_angles );
// Set this as our camera
SetCamera( actor_camera, .5 );
}
}
if( delete_actor_camera )
{
// Get rid of this camera
actor_to_watch = NULL;
if( actor_camera )
{
delete actor_camera;
actor_camera = NULL;
SetCamera( NULL, .5 );
}
}
}
else if( ( level.automatic_cameras.NumObjects() > 0 ) && ( !camera || camera->IsAutomatic() ) )
{
int i;
float score, bestScore;
Camera *cam, *bestCamera;
bestScore = 999;
bestCamera = NULL;
for( i = 1; i <= level.automatic_cameras.NumObjects(); i++ )
{
cam = level.automatic_cameras.ObjectAt( i );
score = cam->CalculateScore( this, currentState_Torso->getName() );
// if this is our current camera, scale down the score a bit to favor it.
if( cam == camera )
{
score *= 0.9f;
}
if( score < bestScore )
{
bestScore = score;
bestCamera = cam;
}
}
if( bestScore <= 1.0f )
{
// we have a camera to switch to
if( bestCamera != camera )
{
float time;
if( camera )
{
camera->AutomaticStop( this );
}
time = bestCamera->AutomaticStart( this );
SetCamera( bestCamera, time );
}
}
else
{
// we don't have a camera to switch to
if( camera )
{
float time;
time = camera->AutomaticStop( this );
SetCamera( NULL, time );
}
}
}
if( IsSpectator() &&
m_iPlayerSpectating != 0 )
{
gentity_t *ent = g_entities + m_iPlayerSpectating - 1;
if( ent->inuse &&
ent->entity &&
ent->entity->deadflag <= DEAD_DYING )
{
Player *m_player = ( Player * )ent->entity;
Vector vAngles;
m_player->GetPlayerView( NULL, &vAngles );
SetPlayerView( ( Camera * )m_player, m_player->origin, m_player->viewheight, vAngles, m_player->velocity, blend, m_player->fov );
return;
}
}
// If there is no camera, use the player's view
if( !camera )
{
SetPlayerView( NULL, origin, viewheight, v_angle, velocity, blend, fov );
}
else
{
SetPlayerView( camera, origin, viewheight, v_angle, velocity, blend, camera->Fov() );
}
}
/*
==================
SwingAngles
==================
*/
void Player::SwingAngles
(
float destination,
float swingTolerance,
float clampTolerance,
float speed,
float *angle,
qboolean *swinging
)
{
float swing;
float move;
float scale;
if ( !*swinging )
{
// see if a swing should be started
swing = AngleSubtract( *angle, destination );
if ( swing > swingTolerance || swing < -swingTolerance )
{
*swinging = qtrue;
// we intentionally return so that we can start the animation before turning
return;
}
}
if ( !*swinging )
{
return;
}
// modify the speed depending on the delta
// so it doesn't seem so linear
swing = AngleSubtract( destination, *angle );
scale = fabs( swing );
#if 0
if ( scale < swingTolerance * 0.5 )
{
scale = 0.5;
}
else if ( scale < swingTolerance )
{
scale = 1.0;
}
else
{
scale = 2.0;
}
#else
scale = 1.0f;
#endif
// swing towards the destination angle
if ( swing >= 0 )
{
move = level.intframetime * scale * speed;
if ( move >= swing )
{
move = swing;
*swinging = qfalse;
}
*angle = AngleMod( *angle + move );
}
else if ( swing < 0 )
{
move = level.intframetime * scale * -speed;
if ( move <= swing )
{
move = swing;
*swinging = qfalse;
}
*angle = AngleMod( *angle + move );
}
// clamp to no more than tolerance
swing = AngleSubtract( destination, *angle );
if ( swing > clampTolerance )
{
*angle = AngleMod( destination - ( clampTolerance - 1 ) );
}
else if ( swing < -clampTolerance )
{
*angle = AngleMod( destination + ( clampTolerance - 1 ) );
}
}
qboolean Player::GetTagPositionAndOrientation
(
int tagnum,
orientation_t *new_or
)
{
int i;
orientation_t tag_or;
vec3_t axis[3];
tag_or = G_TIKI_Orientation( edict, tagnum );
/*tag_or = gi.Tag_OrientationEx( edict->tiki,
CurrentAnim( 1 ),
CurrentTime( 1 ),
tagnum & TAG_MASK,
edict->s.scale,
edict->s.bone_tag,
edict->s.bone_quat,
0,
0,
1.0f,
( edict->s.anim & ANIM_BLEND ) != 0,
( edict->s.torso_anim & ANIM_BLEND ) != 0,
CurrentAnim( 2 ),
CurrentTime( 2 ),
0,
0,
1.0f
);*/
AnglesToAxis( angles, axis );
VectorCopy( origin, new_or->origin );
for ( i=0; i<3; i++ )
VectorMA( new_or->origin, tag_or.origin[i], axis[i], new_or->origin );
MatrixMultiply( tag_or.axis, axis, new_or->axis );
return true;
}
qboolean Player::GetTagPositionAndOrientation
(
str tagname,
orientation_t *new_or
)
{
int tagnum;
tagnum = gi.Tag_NumForName( edict->tiki, tagname );
if ( tagnum < 0 )
{
warning( "Player::GetTagPositionAndOrientation", "Could not find tag \"%s\"", tagname.c_str() );
return false;
}
return GetTagPositionAndOrientation( tagnum, new_or );
}
Vector Player::GetAngleToTarget
(
Entity *ent,
str tag,
float yawclamp,
float pitchclamp,
Vector baseangles
)
{
assert( ent );
if ( ent )
{
Vector delta,angs;
orientation_t tag_or;
int tagnum = gi.Tag_NumForName( edict->tiki, tag.c_str() );
if ( tagnum < 0 )
return Vector( 0,0,0 );
GetTagPositionAndOrientation( tagnum, &tag_or );
delta = ent->centroid - tag_or.origin;
delta.normalize();
angs = delta.toAngles();
AnglesSubtract( angs, baseangles, angs );
angs[PITCH] = AngleNormalize180( angs[PITCH] );
angs[YAW] = AngleNormalize180( angs[YAW] );
if ( angs[PITCH] > pitchclamp )
angs[PITCH] = pitchclamp;
else if ( angs[PITCH] < -pitchclamp )
angs[PITCH] = -pitchclamp;
if ( angs[YAW] > yawclamp )
angs[YAW] = yawclamp;
else if ( angs[YAW] < -yawclamp )
angs[YAW] = -yawclamp;
return angs;
}
else
{
return Vector( 0,0,0 );
}
}
void Player::DebugWeaponTags
(
int controller_tag,
Weapon *weapon,
str weapon_tagname
)
{
int i;
orientation_t bone_or, tag_weapon_or, barrel_or, final_barrel_or;
GetTagPositionAndOrientation( edict->s.bone_tag[controller_tag], &bone_or );
//G_DrawCoordSystem( Vector( bone_or.origin ), Vector( bone_or.axis[0] ), Vector( bone_or.axis[1] ), Vector( bone_or.axis[2] ), 20 );
GetTagPositionAndOrientation( gi.Tag_NumForName( edict->tiki, weapon_tagname ), &tag_weapon_or );
//G_DrawCoordSystem( Vector( tag_weapon_or.origin ), Vector( tag_weapon_or.axis[0] ), Vector( tag_weapon_or.axis[1] ), Vector( tag_weapon_or.axis[2] ), 40 );
weapon->GetRawTag( "tag_barrel", &barrel_or );
VectorCopy( tag_weapon_or.origin, final_barrel_or.origin );
for ( i = 0 ; i < 3 ; i++ )
VectorMA( final_barrel_or.origin, barrel_or.origin[i], tag_weapon_or.axis[i], final_barrel_or.origin );
MatrixMultiply( barrel_or.axis, tag_weapon_or.axis, final_barrel_or.axis );
//G_DrawCoordSystem( Vector( final_barrel_or.origin ), Vector( final_barrel_or.axis[0] ), Vector( final_barrel_or.axis[1] ), Vector( final_barrel_or.axis[2] ), 80 );
#if 0
if ( g_crosshair->integer )
{
trace_t trace;
Vector start,end,ang,dir,delta;
vec3_t mat[3];
AnglesToAxis( v_angle, mat );
dir = mat[0];
start = final_barrel_or.origin;
end = start + ( dir * MAX_MAP_BOUNDS );
G_DrawCoordSystem( start, Vector( mat[0] ), Vector( mat[1] ), Vector( mat[2] ), 80 );
trace = G_Trace( start, vec_zero, vec_zero, end, this, MASK_PROJECTILE|MASK_WATER, qfalse, "Crosshair" );
crosshair->setOrigin( trace.endpos );
delta = trace.endpos - start;
float length = delta.length();
float scale = g_crosshair_maxscale->value * length / MAX_MAP_BOUNDS;
if ( scale < 1 )
scale = 1;
crosshair->setScale( scale );
if ( trace.ent )
{
vectoangles( trace.plane.normal, ang );
}
else
{
vectoangles( dir, ang );
}
crosshair->setAngles( ang );
}
#endif
}
void Player::AcquireTarget
(
void
)
{
}
void Player::RemoveTarget
(
Entity *ent_to_remove
)
{
}
void Player::AutoAim
(
void
)
{
}
/*
===============
PlayerAngles
===============
*/
void Player::PlayerAngles
(
void
)
{
PmoveAdjustAngleSettings( v_angle, angles, &client->ps, &edict->s );
SetViewAngles( v_angle );
setAngles( angles );
}
void Player::FinishMove
(
void
)
{
//
// 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( !( client->ps.pm_flags & PMF_FROZEN ) && !( client->ps.pm_flags & PMF_NO_MOVE ) )
{
origin.copyTo( client->ps.origin );
velocity.copyTo( client->ps.velocity );
}
// This check is in mohaa but the animation will look bad
if( !( client->ps.pm_flags & PMF_FROZEN ) )
{
PlayerAngles();
AdjustAnimBlends();
}
// burn from lava, etc
WorldEffects();
// determine the view offsets
DamageFeedback();
CalcBlend();
if( g_gametype->integer && g_smoothClients->integer && !IsSubclassOfBot() )
{
VectorCopy( client->ps.velocity, edict->s.pos.trDelta );
edict->s.pos.trTime = client->ps.commandTime;
}
else
{
VectorClear( edict->s.pos.trDelta );
edict->s.pos.trTime = 0;
}
}
void Player::CopyStats
(
Player *player
)
{
gentity_t *ent;
int i;
origin = player->origin;
SetViewAngles( player->GetViewAngles() );
client->ps.bobCycle = player->client->ps.bobCycle;
client->ps.pm_flags |= player->client->ps.pm_flags & ( PMF_DUCKED | PMF_VIEW_DUCK_RUN | PMF_VIEW_JUMP_START | PMF_VIEW_PRONE );
memcpy( &client->ps.stats, &player->client->ps.stats, sizeof( client->ps.stats ) );
memcpy( &client->ps.activeItems, &player->client->ps.activeItems, sizeof( client->ps.activeItems ) );
memcpy( &client->ps.ammo_name_index, &player->client->ps.ammo_name_index, sizeof( client->ps.ammo_name_index ) );
memcpy( &client->ps.ammo_amount, &player->client->ps.ammo_amount, sizeof( client->ps.ammo_amount ) );
memcpy( &client->ps.max_ammo_amount, &player->client->ps.max_ammo_amount, sizeof( client->ps.max_ammo_amount ) );
VectorCopy( player->client->ps.origin, client->ps.origin );
VectorCopy( player->client->ps.velocity, client->ps.velocity );
if( client->ps.iViewModelAnim != player->client->ps.iViewModelAnim )
{
ViewModelAnim( player->m_sVMcurrent, qfalse, 0 );
}
else if( client->ps.iViewModelAnimChanged != player->client->ps.iViewModelAnimChanged )
{
ViewModelAnim( player->m_sVMcurrent, qtrue, 0 );
}
client->ps.gravity = player->client->ps.gravity;
client->ps.speed = player->client->ps.speed;
// copy angles
memcpy( &client->ps.delta_angles, &player->client->ps.delta_angles, sizeof( client->ps.delta_angles ) );
memcpy( &client->ps.blend, &player->client->ps.blend, sizeof( client->ps.blend ) );
memcpy( &client->ps.damage_angles, &player->client->ps.damage_angles, sizeof( client->ps.damage_angles ) );
memcpy( &client->ps.viewangles, &player->client->ps.viewangles, sizeof( client->ps.delta_angles ) );
// copy camera stuff
//memcpy( &client->ps.camera_origin, &player->client->ps.camera_origin, sizeof( client->ps.camera_origin ) );
//memcpy( &client->ps.camera_angles, &player->client->ps.camera_angles, sizeof( client->ps.camera_angles ) );
//memcpy( &client->ps.camera_offset, &player->client->ps.camera_offset, sizeof( client->ps.camera_offset ) );
//memcpy( &client->ps.camera_posofs, &player->client->ps.camera_posofs, sizeof( client->ps.camera_posofs ) );
//client->ps.camera_time = player->client->ps.camera_time;
//client->ps.camera_flags = player->client->ps.camera_flags;
client->ps.fLeanAngle = player->client->ps.fLeanAngle;
client->ps.fov = player->client->ps.fov;
client->ps.viewheight = player->client->ps.viewheight;
client->ps.walking = player->client->ps.walking;
client->ps.groundPlane = player->client->ps.groundPlane;
client->ps.groundEntityNum = player->client->ps.groundEntityNum;
memcpy( &client->ps.groundTrace, &player->client->ps.groundTrace, sizeof( trace_t ) );
edict->s.eFlags &= ~EF_UNARMED;
edict->r.svFlags &= ~SVF_NOCLIENT;
edict->s.renderfx &= ~RF_DONTDRAW;
player->edict->r.svFlags |= SVF_PORTAL;
player->edict->r.singleClient = client->ps.clientNum;
edict->r.svFlags |= SVF_SINGLECLIENT;
edict->r.singleClient = client->ps.clientNum;
client->ps.pm_flags |= PMF_FROZEN | PMF_NO_MOVE | PMF_NO_PREDICTION;
memcpy( &edict->s.frameInfo, &player->edict->s.frameInfo, sizeof( edict->s.frameInfo ) );
DetachAllChildren();
for( i = 0; i < MAX_MODEL_CHILDREN; i++ )
{
Entity *dest;
if( player->children[ i ] == ENTITYNUM_NONE ) {
continue;
}
ent = g_entities + player->children[ i ];
if( !ent->inuse || !ent->entity ) {
continue;
}
dest = new Entity;
CloneEntity( dest, ent->entity );
dest->edict->r.svFlags |= SVF_SINGLECLIENT;
dest->edict->r.singleClient = client->ps.clientNum;
dest->edict->s.modelindex = ent->entity->edict->s.modelindex;
dest->edict->tiki = ent->entity->edict->tiki;
dest->edict->s.actionWeight = ent->entity->edict->s.actionWeight;
memcpy( &dest->edict->s.frameInfo, &ent->entity->edict->s.frameInfo, sizeof( dest->edict->s.frameInfo ) );
dest->CancelPendingEvents();
dest->attach( entnum, ent->entity->edict->s.tag_num );
dest->PostEvent( EV_DetachAllChildren, level.frametime );
}
}
void Player::UpdateStats
(
void
)
{
int i, count;
Vector vObjectiveLocation;
//
// Health
//
if( g_spectatefollow_firstperson->integer &&
IsSpectator() &&
m_iPlayerSpectating != 0 )
{
gentity_t *ent = g_entities + ( m_iPlayerSpectating - 1 );
if( ent->inuse &&
ent->entity &&
ent->entity->deadflag <= DEAD_DYING )
{
CopyStats( ( Player * )ent->entity );
return;
}
}
if( !g_gametype->integer )
{
client->ps.stats[ STAT_TEAM ] = TEAM_ALLIES;
client->ps.stats[ STAT_KILLS ] = 0;
client->ps.stats[ STAT_DEATHS ] = 0;
client->ps.stats[ STAT_HIGHEST_SCORE ] = 0;
client->ps.stats[ STAT_ATTACKERCLIENT ] = -1;
client->ps.stats[ STAT_INFOCLIENT ] = -1;
client->ps.stats[ STAT_INFOCLIENT_HEALTH ] = 0;
vObjectiveLocation = level.m_vObjectiveLocation;
}
else
{
client->ps.stats[ STAT_TEAM ] = dm_team;
if( g_gametype->integer >= GT_TEAM && current_team != NULL )
{
client->ps.stats[ STAT_KILLS ] = current_team->m_teamwins;
client->ps.stats[ STAT_DEATHS ] = current_team->m_iDeaths;
}
else
{
client->ps.stats[ STAT_KILLS ] = num_kills;
client->ps.stats[ STAT_DEATHS ] = num_deaths;
}
if( g_gametype->integer <= GT_FFA )
{
gentity_t *ent;
int i;
int bestKills = -9999;
// Get the best player
for( i = 0, ent = g_entities; i < game.maxclients; i++, ent++ )
{
if( !ent->inuse || !ent->client || !ent->entity )
continue;
Player *p = ( Player * )ent->entity;
if( p->GetNumKills() > bestKills )
bestKills = p->GetNumKills();
}
client->ps.stats[ STAT_HIGHEST_SCORE ] = bestKills;
}
else
{
if( dmManager.GetTeamAxis()->m_teamwins > dmManager.GetTeamAllies()->m_teamwins )
{
client->ps.stats[ STAT_HIGHEST_SCORE ] = dmManager.GetTeamAxis()->m_teamwins;
}
else
{
client->ps.stats[ STAT_HIGHEST_SCORE ] = dmManager.GetTeamAllies()->m_teamwins;
}
}
if( !pAttackerDistPointer )
{
client->ps.stats[ STAT_ATTACKERCLIENT ] = -1;
}
else if( fAttackerDispTime <= level.time && !deadflag )
{
pAttackerDistPointer = NULL;
client->ps.stats[ STAT_ATTACKERCLIENT ] = -1;
}
else
{
client->ps.stats[ STAT_ATTACKERCLIENT ] = pAttackerDistPointer->edict - g_entities;
}
client->ps.stats[ STAT_INFOCLIENT ] = -1;
client->ps.stats[ STAT_INFOCLIENT_HEALTH ] = 0;
if( IsSpectator() || g_gametype->integer > GT_FFA )
{
if( IsSpectator() && m_iPlayerSpectating )
{
gentity_t *ent = g_entities + ( m_iPlayerSpectating - 1 );
if( ent->inuse && ent->entity && !deadflag )
{
m_iInfoClient = ent - g_entities;
m_iInfoClientHealth = ent->entity->health;
m_fInfoClientTime = level.time;
float percent = ent->entity->health / ent->entity->max_health * 100.0f;
if( percent > 0.0f && percent < 1.0f )
percent = 1.0f;
client->ps.stats[ STAT_INFOCLIENT_HEALTH ] = percent;
}
}
else
{
Vector vForward;
trace_t trace;
AngleVectors( m_vViewAng, vForward, NULL, NULL );
Vector vEnd = m_vViewPos + vForward * 2048.0f;
trace = G_Trace( m_vViewPos,
vec_zero,
vec_zero,
vEnd,
this,
MASK_BEAM,
qfalse,
"infoclientcheck" );
if( trace.ent && trace.ent->entity->IsSubclassOfPlayer() )
{
Player *p = ( Player * )trace.ent->entity;
if( IsSpectator() || p->dm_team == dm_team )
{
m_iInfoClient = trace.ent - g_entities;
m_iInfoClientHealth = p->health;
m_fInfoClientTime = level.time;
float percent = trace.ent->entity->health / trace.ent->entity->max_health * 100.0f;
if( percent > 0.0f && percent < 1.0f )
percent = 1.0f;
client->ps.stats[ STAT_INFOCLIENT_HEALTH ] = percent;
}
}
}
if( m_iInfoClient != -1 )
{
if( level.time <= m_fInfoClientTime + 1.5f )
{
client->ps.stats[ STAT_INFOCLIENT ] = m_iInfoClient;
client->ps.stats[ STAT_INFOCLIENT_HEALTH ] = m_iInfoClientHealth;
}
else
{
m_iInfoClient = -1;
}
}
}
if( g_gametype->integer > GT_FFA && !IsDead() && !IsSpectator() )
{
gentity_t *ent;
int i;
Player *p;
float fNearest = 9999.0f;
float fLength;
vObjectiveLocation = vec_zero;
// match the compass direction to the nearest player
for( i = 0, ent = g_entities; i < game.maxclients; i++, ent++ )
{
if( !ent->inuse || !ent->client || !ent->entity || ent->entity == this )
continue;
p = ( Player * )ent->entity;
if( p->IsDead() || p->IsSpectator() || p->dm_team != dm_team )
continue;
fLength = ( p->centroid - centroid ).length();
if( fLength < fNearest )
{
fNearest = fLength;
vObjectiveLocation = p->centroid;
}
}
}
}
TurretGun *pTurret = NULL;
if( !m_pVehicle )
{
pTurret = m_pTurret;
}
if( ( health < 1 ) && ( health > 0 ) )
{
client->ps.stats[ STAT_HEALTH ] = 1;
}
else
{
client->ps.stats[ STAT_HEALTH ] = ( int )( health / max_health * 100.0f );
}
client->ps.stats[ STAT_MAX_HEALTH ] = 100;
Weapon *activeweap = GetActiveWeapon( WEAPON_MAIN );
client->ps.stats[ STAT_WEAPONS ] = 0;
client->ps.stats[ STAT_EQUIPPED_WEAPON ] = 0;
client->ps.stats[ STAT_AMMO ] = 0;
client->ps.stats[ STAT_MAXAMMO ] = 0;
client->ps.stats[ STAT_CLIPAMMO ] = 0;
client->ps.stats[ STAT_MAXCLIPAMMO ] = 0;
client->ps.activeItems[ ITEM_AMMO ] = -1;
client->ps.activeItems[ ITEM_WEAPON ] = -1;
client->ps.activeItems[ 2 ] = -1;
client->ps.activeItems[ 3 ] = -1;
client->ps.activeItems[ 4 ] = -1;
client->ps.activeItems[ 5 ] = -1;
if( pTurret )
{
client->ps.activeItems[ ITEM_WEAPON ] = pTurret->getIndex();
}
else if( activeweap )
{
client->ps.stats[ STAT_AMMO ] = AmmoCount( activeweap->GetAmmoType( FIRE_PRIMARY ) );
client->ps.stats[ STAT_MAXAMMO ] = MaxAmmoCount( activeweap->GetAmmoType( FIRE_PRIMARY ) );
client->ps.stats[ STAT_CLIPAMMO ] = activeweap->ClipAmmo( FIRE_PRIMARY );
client->ps.stats[ STAT_MAXCLIPAMMO ] = activeweap->GetClipSize( FIRE_PRIMARY );
client->ps.activeItems[ ITEM_AMMO ] = AmmoIndex( activeweap->GetAmmoType( FIRE_PRIMARY ) );
// grenade and rockets must match the number of ammo
if( client->ps.stats[ STAT_MAXCLIPAMMO ] == 1 )
{
client->ps.stats[ STAT_MAXAMMO ]++;
client->ps.stats[ STAT_AMMO ] += client->ps.stats[ STAT_CLIPAMMO ];
}
if( !activeweap->IsSubclassOfInventoryItem() )
{
client->ps.stats[ STAT_EQUIPPED_WEAPON ] = activeweap->GetWeaponClass();
}
client->ps.activeItems[ ITEM_WEAPON ] = activeweap->getIndex();
}
//
// set boss health
//
client->ps.stats[ STAT_BOSSHEALTH ] = bosshealth->value * 100.0f;
if( bosshealth->value * 100.0f > 0 && client->ps.stats[ STAT_BOSSHEALTH ] == 0 )
client->ps.stats[ STAT_BOSSHEALTH ] = 1;
// Set cinematic stuff
client->ps.stats[ STAT_CINEMATIC ] = 0;
if( level.cinematic )
client->ps.stats[ STAT_CINEMATIC ] = ( 1 << 0 );
if( actor_camera )
client->ps.stats[ STAT_CINEMATIC ] += ( 1 << 1 );
count = inventory.NumObjects();
if( count > MAX_WEAPONS )
{
count = MAX_WEAPONS;
warning( "Player::UpdateStats", "Max inventory exceeded\n" );
}
count = inventory.NumObjects();
int iItem = 0;
for( i = 1; i <= count; i++ )
{
int entnum = inventory.ObjectAt( i );
Weapon *weapon = ( Weapon * )G_GetEntity( entnum );
int weapon_class;
if( weapon->IsSubclassOfWeapon() )
{
if( weapon->IsSubclassOfInventoryItem() )
{
if( iItem <= 3 )
{
client->ps.activeItems[iItem + 2] = weapon->getIndex();
weapon->weapon_class = (256 << iItem) & WEAPON_CLASS_ITEMINDEX;
weapon->weapon_class |= weapon->weapon_class & ~WEAPON_CLASS_ITEMINDEX;
if( activeweap && weapon == activeweap )
{
client->ps.stats[ STAT_EQUIPPED_WEAPON ] = 256 << iItem;
}
iItem++;
}
else
{
weapon->weapon_class &= ~WEAPON_CLASS_ITEMINDEX;
}
}
else
{
weapon_class = weapon->GetWeaponClass();
if( weapon_class & WEAPON_CLASS_GRENADE )
{
if( weapon->HasAmmo( FIRE_PRIMARY ) )
client->ps.stats[ STAT_WEAPONS ] |= weapon_class;
}
else
{
client->ps.stats[ STAT_WEAPONS ] |= weapon_class;
}
}
}
}
// Go through all the player's ammo and send over the names/amounts
memset( client->ps.ammo_amount, 0, sizeof( client->ps.ammo_amount ) );
memset( client->ps.ammo_name_index, 0, sizeof( client->ps.ammo_name_index ) );
memset( client->ps.max_ammo_amount, 0, sizeof( client->ps.max_ammo_amount ) );
count = ammo_inventory.NumObjects();
for( i = 1; i <= count; i++ )
{
Ammo *ammo = ammo_inventory.ObjectAt( i );
if( ammo )
{
client->ps.ammo_amount[ i - 1 ] = ammo->getAmount();
client->ps.max_ammo_amount[ i - 1 ] = ammo->getMaxAmount();
client->ps.ammo_name_index[ i - 1 ] = ammo->getIndex();
}
}
if( m_iInZoomMode == -1 )
{
client->ps.stats[ STAT_INZOOM ] = fov;
}
else
{
client->ps.stats[ STAT_INZOOM ] = 0;
}
client->ps.stats[STAT_CROSSHAIR] = ((!client->ps.stats[STAT_INZOOM] || client->ps.stats[STAT_INZOOM] > 30) &&
(activeweap && !activeweap->IsSubclassOfInventoryItem() && activeweap->HasCrosshair())) ||
pTurret || (m_pVehicle && m_pVehicle->IsSubclassOfVehicleTank());
client->ps.stats[ STAT_COMPASSNORTH ] = ANGLE2SHORT( world->m_fNorth );
if( VectorCompare( vObjectiveLocation, vec_zero ) )
{
client->ps.stats[ STAT_OBJECTIVELEFT ] = 1730;
client->ps.stats[ STAT_OBJECTIVERIGHT ] = 1870;
client->ps.stats[ STAT_OBJECTIVECENTER ] = 1800;
}
else
{
Vector vDelta;
float yaw;
float fOffset;
vDelta = vObjectiveLocation - centroid;
yaw = AngleSubtract( v_angle[ 1 ], vDelta.toYaw() ) + 180.0f;
vDelta = yaw_left * 300.0f + yaw_forward * vDelta.length() + centroid - centroid;
fOffset = AngleSubtract( vDelta.toYaw(), v_angle[ 1 ] );
if( fOffset < 0.0f )
fOffset = -fOffset;
fOffset = 53.0f - fOffset + 7.0f;
if( fOffset < 7.0f )
fOffset = 7.0f;
client->ps.stats[ STAT_OBJECTIVELEFT ] = anglemod( yaw - fOffset ) * 10.0f;
if( client->ps.stats[ STAT_OBJECTIVELEFT ] <= 0 )
{
client->ps.stats[ STAT_OBJECTIVELEFT ] = 1;
}
else if( client->ps.stats[ STAT_OBJECTIVELEFT ] > 3599 )
{
client->ps.stats[ STAT_OBJECTIVELEFT ] = 3599;
}
client->ps.stats[ STAT_OBJECTIVERIGHT ] = anglemod( yaw + fOffset ) * 10.0f;
if( client->ps.stats[ STAT_OBJECTIVERIGHT ] <= 0 )
{
client->ps.stats[ STAT_OBJECTIVERIGHT ] = 1;
}
else if( client->ps.stats[ STAT_OBJECTIVERIGHT ] > 3599 )
{
client->ps.stats[ STAT_OBJECTIVERIGHT ] = 3599;
}
client->ps.stats[ STAT_OBJECTIVECENTER ] = anglemod( yaw ) * 10.0f;
if( client->ps.stats[ STAT_OBJECTIVECENTER ] <= 0 )
{
client->ps.stats[ STAT_OBJECTIVECENTER ] = 1;
}
else if( client->ps.stats[ STAT_OBJECTIVECENTER ] > 3599 )
{
client->ps.stats[ STAT_OBJECTIVECENTER ] = 3599;
}
}
client->ps.stats[ STAT_DAMAGEDIR ] = damage_yaw;
if( client->ps.stats[ STAT_DAMAGEDIR ] < 0 )
{
client->ps.stats[ STAT_DAMAGEDIR ] = 0;
}
else if( client->ps.stats[ STAT_DAMAGEDIR ] > 3600 )
{
client->ps.stats[ STAT_DAMAGEDIR ] = 3600;
}
// Do letterbox
// Check for letterbox fully out
if( ( level.m_letterbox_time <= 0 ) && ( level.m_letterbox_dir == letterbox_in ) )
{
client->ps.stats[ STAT_LETTERBOX ] = level.m_letterbox_fraction * MAX_LETTERBOX_SIZE;
return;
}
else if( ( level.m_letterbox_time <= 0 ) && ( level.m_letterbox_dir == letterbox_out ) )
{
client->ps.stats[ STAT_LETTERBOX ] = 0;
return;
}
float frac;
level.m_letterbox_time -= level.intframetime;
frac = level.m_letterbox_time / level.m_letterbox_time_start;
if( frac > 1 )
frac = 1;
if( frac < 0 )
frac = 0;
if( level.m_letterbox_dir == letterbox_in )
frac = 1.0f - frac;
client->ps.stats[ STAT_LETTERBOX ] = ( frac * level.m_letterbox_fraction ) * MAX_LETTERBOX_SIZE;
}
void Player::UpdateStatus
(
const char *s
)
{
gi.SendServerCommand( edict - g_entities, "status \"%s\"", s );
}
void Player::UpdateMusic
(
void
)
{
if( music_forced )
{
client->ps.current_music_mood = music_current_mood;
client->ps.fallback_music_mood = music_fallback_mood;
}
// Copy music volume and fade time to player state
client->ps.music_volume = music_current_volume;
client->ps.music_volume_fade_time = music_volume_fade_time;
}
void Player::SetReverb
(
int type,
float level
)
{
reverb_type = type;
reverb_level = level;
}
void Player::SetReverb
(
str type,
float level
)
{
reverb_type = EAXMode_NameToNum( type );
reverb_level = level;
}
void Player::SetReverb
(
Event *ev
)
{
if ( ev->NumArgs() < 2 )
return;
SetReverb( ev->GetInteger( 1 ), ev->GetFloat( 2 ) );
}
void Player::UpdateReverb
(
void
)
{
client->ps.reverb_type = reverb_type;
client->ps.reverb_level = reverb_level;
}
void Player::EndAnim_Legs
(
Event *ev
)
{
animdone_Legs = true;
if( ( animFlags[ m_iPartSlot[ legs ] ] & ANIM_LOOP ) ) {
SetAnimDoneEvent( EV_Player_AnimLoop_Legs, m_iPartSlot[ legs ] );
}
EvaluateState();
}
void Player::EndAnim_Torso
(
Event *ev
)
{
animdone_Torso = true;
if( ( animFlags[ m_iPartSlot[ torso ] ] & ANIM_LOOP ) ) {
SetAnimDoneEvent( EV_Player_AnimLoop_Torso, m_iPartSlot[ torso ] );
}
EvaluateState();
}
void Player::EndActionAnim
(
Event *ev
)
{
m_bActionAnimDone = qtrue;
EvaluateState();
}
void Player::SetPartAnim
(
const char *anim,
bodypart_t slot
)
{
int animnum;
if( getMoveType() == MOVETYPE_NOCLIP && slot )
{
StopPartAnimating( torso );
return;
}
animnum = gi.Anim_NumForName( edict->tiki, anim );
if( animnum == CurrentAnim() && partAnim[ slot ] == anim )
{
return;
}
if( animnum == -1 )
{
Event *ev;
if( slot )
{
ev = new Event( EV_Player_AnimLoop_Torso );
}
else
{
ev = new Event( EV_Player_AnimLoop_Legs );
}
PostEvent( ev, level.frametime );
gi.DPrintf( "^~^~^ Warning: Can't find player animation '%s'.\n", anim );
return;
}
if( m_fPartBlends[ slot ] < 0.5f )
{
SetAnimDoneEvent( NULL, m_iPartSlot[ slot ] );
float m_fCrossTime = gi.Anim_CrossTime( edict->tiki, animnum );
partBlendMult[ slot ] = m_fCrossTime;
if( m_fCrossTime <= 0.0f )
{
partOldAnim[ slot ] = "";
m_fPartBlends[ slot ] = 0.0f;
}
else
{
m_iPartSlot[ slot ] ^= 1;
partBlendMult[ slot ] = 1.0f / m_fCrossTime;
partOldAnim[ slot ] = partAnim[ slot ];
m_fPartBlends[ slot ] = 1.0f;
}
}
if( slot )
{
animdone_Torso = false;
}
else
{
animdone_Legs = false;
}
edict->s.frameInfo[ m_iPartSlot[ slot ] ].index = gi.Anim_NumForName( edict->tiki, "idle" );
partAnim[ slot ] = anim;
if( slot )
{
NewAnim( animnum, EV_Player_AnimLoop_Torso, m_iPartSlot[ slot ] );
}
else
{
NewAnim( animnum, EV_Player_AnimLoop_Legs, m_iPartSlot[ legs ] );
}
SetTime( m_iPartSlot[ slot ] );
}
static float m_fPartMult[ 2 ] =
{
0.2f,
0.2f
};
void Player::StopPartAnimating
(
bodypart_t part
)
{
if( partAnim[ part ] == "" ) {
return;
}
if( m_fPartBlends[ part ] < 0.5f )
{
SetAnimDoneEvent( NULL, m_iPartSlot[ part ] );
m_iPartSlot[ part ] ^= 1;
partOldAnim[ part ] = partAnim[ part ];
m_fPartBlends[ part ] = 1.0f;
}
partAnim[ part ] = "";
partBlendMult[ part ] = 1.0f / m_fPartMult[ part ];
StopAnimating( m_iPartSlot[ part ] );
if( part )
{
animdone_Torso = false;
}
else
{
animdone_Legs = false;
}
}
void Player::PausePartAnim
(
bodypart_t part
)
{
Pause( m_iPartSlot[ part ], 1 );
Pause( m_iPartSlot[ part ] ^ 1, 1 );
}
void Player::AdjustAnimBlends
(
void
)
{
int iPartSlot;
int iOldPartSlot;
float fWeightTotal;
iPartSlot = m_iPartSlot[ legs ];
iOldPartSlot = m_iPartSlot[ legs ] ^ 1;
if( m_fPartBlends[ legs ] <= 0.0f )
{
if( partOldAnim[ legs ] == "" )
{
goto __blend_torso;
}
StopAnimating( iOldPartSlot );
}
else
{
m_fPartBlends[ legs ] = m_fPartBlends[ legs ] - level.frametime * partBlendMult[ legs ];
if( m_fPartBlends[ legs ] >= 0.01f )
{
if( partOldAnim[ legs ] != "" )
{
edict->s.frameInfo[ iOldPartSlot ].weight = m_fPartBlends[ legs ];
}
if( partAnim[ legs ] != "" )
{
edict->s.frameInfo[ iPartSlot ].weight = 1.0f - m_fPartBlends[ legs ];
}
goto __blend_torso;
}
m_fPartBlends[ legs ] = 0.0f;
StopAnimating( iOldPartSlot );
partOldAnim[ legs ] = "";
}
if( partAnim[ legs ] != "" )
{
edict->s.frameInfo[ iPartSlot ].weight = 1.0f;
}
else
{
edict->s.frameInfo[ iPartSlot ].weight = 0.0f;
}
__blend_torso:
iPartSlot = m_iPartSlot[ torso ];
iOldPartSlot = m_iPartSlot[ torso ] ^ 1;
if( m_fPartBlends[ torso ] <= 0.0f )
{
if( partOldAnim[ torso ] != "" )
{
StopAnimating( iOldPartSlot );
partOldAnim[ torso ] = "";
}
}
else
{
m_fPartBlends[ torso ] = m_fPartBlends[ torso ] - level.frametime * partBlendMult[ torso ];
if( m_fPartBlends[ torso ] >= 0.01f )
{
fWeightTotal = 0.0f;
if( partOldAnim[ torso ] != "" )
{
edict->s.frameInfo[ iOldPartSlot ].weight = m_fPartBlends[ torso ];
fWeightTotal += m_fPartBlends[ torso ];
}
if( partAnim[ torso ] != "" )
{
edict->s.frameInfo[ iPartSlot ].weight = 1.0f - m_fPartBlends[ torso ];
fWeightTotal += 1.0f - m_fPartBlends[ torso ];
}
edict->s.actionWeight = fWeightTotal;
}
else
{
m_fPartBlends[ torso ] = 0.0f;
StopAnimating( iOldPartSlot );
partOldAnim[ torso ] = "";
edict->s.frameInfo[ iPartSlot ].weight = partAnim[ torso ] != "" ? 1.0f : 0.0f;
edict->s.actionWeight = partAnim[ torso ] != "" ? 1.0f : 0.0f;
}
}
}
void Player::PlayerAnimDelta
(
float *vDelta
)
{
float fTimeDelta;
float fBackTime;
float vNewDelta[ 3 ];
int animnum;
VectorClear( vDelta );
if( m_fLastDeltaTime >= level.time ) {
return;
}
fTimeDelta = level.time - m_fLastDeltaTime;
animnum = -1;
if( partAnim[ legs ] != "" )
{
animnum = CurrentAnim( m_iPartSlot[ legs ] );
}
if( animnum != -1 )
{
fBackTime = GetTime( m_iPartSlot[ legs ] ) - fTimeDelta;
if( fBackTime < 0.0f ) {
fBackTime = 0.0f;
}
float fTime = GetTime( m_iPartSlot[ legs ] );
// get the anim delta
gi.Anim_DeltaOverTime( edict->tiki, animnum, fBackTime, fTime, vNewDelta );
VectorMA( vDelta, edict->s.frameInfo[ m_iPartSlot[ legs ] ].weight, vNewDelta, vDelta );
}
animnum = -1;
if( partAnim[ torso ] != "" )
{
animnum = CurrentAnim( m_iPartSlot[ torso ] );
}
if( animnum != -1 )
{
fBackTime = GetTime( m_iPartSlot[ torso ] ) - fTimeDelta;
if( fBackTime < 0.0f ) {
fBackTime = 0.0f;
}
float fTime = GetTime( m_iPartSlot[ torso ] );
gi.Anim_DeltaOverTime( edict->tiki, animnum, fBackTime, fTime, vNewDelta );
VectorMA( vDelta, edict->s.frameInfo[ m_iPartSlot[ torso ] ].weight, vNewDelta, vDelta );
}
}
void Player::CheckReloadWeapons
(
void
)
{
Weapon *weap;
weap = GetActiveWeapon( WEAPON_OFFHAND );
if( weap )
{
weap->CheckReload( FIRE_PRIMARY );
}
weap = GetActiveWeapon( WEAPON_MAIN );
if( weap )
{
weap->CheckReload( FIRE_PRIMARY );
}
}
void Player::UpdateMisc
(
void
)
{
//
// clear out the level exit flag
//
client->ps.pm_flags &= ~PMF_LEVELEXIT;
//
// see if our camera is the level exit camera
//
if( camera && camera->IsLevelExit() )
{
client->ps.pm_flags |= PMF_LEVELEXIT;
}
else if( level.near_exit )
{
client->ps.pm_flags |= PMF_LEVELEXIT;
}
//
// do anything special for respawns
//
if( client->ps.pm_flags & PMF_RESPAWNED )
{
//
// change music
//
if( music_current_mood != mood_success )
{
ChangeMusic( "success", "normal", false );
}
}
}
/*
=================
EndFrame
Called for each player at the end of the server frame
and right after spawning
=================
*/
void Player::EndFrame
(
void
)
{
FinishMove();
UpdateStats();
UpdateMusic();
UpdateReverb();
UpdateMisc();
if( !g_spectatefollow_firstperson->integer ||
!IsSpectator() ||
!m_iPlayerSpectating )
{
SetupView();
}
else
{
gentity_t *ent = g_entities + m_iPlayerSpectating - 1;
if( !ent->inuse ||
!ent->entity ||
ent->entity->deadflag >= DEAD_DEAD )
{
SetupView();
}
}
}
void Player::GibEvent
(
Event *ev
)
{
qboolean hidemodel;
hidemodel = !ev->GetInteger( 1 );
if ( com_blood->integer )
{
if ( hidemodel )
{
gibbed = true;
takedamage = DAMAGE_NO;
setSolidType( SOLID_NOT );
hideModel();
}
CreateGibs( this, health, 0.75f, 3 );
}
}
void Player::GotKill
(
Event *ev
)
{
/*
Entity *victim;
Entity *inflictor;
float damage;
int meansofdeath;
qboolean gibbed;
if ( deathmatch->integer )
{
return;
}
victim = ev->GetEntity( 1 );
damage = ev->GetInteger( 2 );
inflictor = ev->GetEntity( 3 );
meansofdeath = ev->GetInteger( 4 );
gibbed = ev->GetInteger( 5 );
*/
}
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;
}
}
void Player::ChangeMusic
(
const char * current,
const char * fallback,
qboolean force
)
{
int current_mood_num;
int fallback_mood_num;
music_forced = force;
if( current )
{
current_mood_num = MusicMood_NameToNum( current );
if( current_mood_num < 0 )
{
gi.DPrintf( "current music mood %s not found", current );
}
else
{
music_current_mood = current_mood_num;
}
}
if( fallback )
{
fallback_mood_num = MusicMood_NameToNum( fallback );
if( fallback_mood_num < 0 )
{
gi.DPrintf( "fallback music mood %s not found", fallback );
fallback = NULL;
}
else
{
music_fallback_mood = fallback_mood_num;
}
}
}
void Player::ChangeMusicVolume
(
float volume,
float fade_time
)
{
music_volume_fade_time = fade_time;
music_saved_volume = music_current_volume;
music_current_volume = volume;
}
void Player::RestoreMusicVolume
(
float fade_time
)
{
music_volume_fade_time = fade_time;
music_current_volume = music_saved_volume;
music_saved_volume = -1.0;
}
void Player::Jump
(
Event *ev
)
{
float maxheight;
maxheight = ev->GetFloat( 1 );
if ( maxheight > 16 )
{
// v^2 = 2ad
velocity[ 2 ] += sqrt( 2 * sv_gravity->integer * maxheight );
// make sure the player leaves the ground
client->ps.walking = qfalse;
}
}
void Player::JumpXY
(
Event *ev
)
{
float forwardmove;
float sidemove;
float distance;
float time;
float speed;
forwardmove = ev->GetFloat( 1 );
sidemove = ev->GetFloat( 2 );
speed = ev->GetFloat( 3 );
velocity = yaw_forward * forwardmove - yaw_left * sidemove;
distance = velocity.length();
velocity *= speed / distance;
time = distance / speed;
velocity[ 2 ] = sv_gravity->integer * time * 0.5f;
airspeed = distance;
// make sure the player leaves the ground
client->ps.walking = qfalse;
}
Vector Player::EyePosition
(
void
)
{
return m_vViewPos;
}
void Player::GetViewangles
(
Event *ev
)
{
ev->AddVector( v_angle );
}
void Player::SetViewangles
(
Event *ev
)
{
SetViewAngles( ev->GetVector( 1 ) );
}
void Player::SetViewAngles
(
Vector newViewangles
)
{
// set the delta angle
client->ps.delta_angles[ 0 ] = ANGLE2SHORT( newViewangles.x - client->cmd_angles[ 0 ] );
client->ps.delta_angles[ 1 ] = ANGLE2SHORT( newViewangles.y - client->cmd_angles[ 1 ] );
client->ps.delta_angles[ 2 ] = ANGLE2SHORT( newViewangles.z - client->cmd_angles[ 2 ] );
v_angle = newViewangles;
// get the pitch and roll from our leg angles
newViewangles.x = angles.x;
newViewangles.z = angles.z;
AnglesToMat( newViewangles, orientation );
yaw_forward = orientation[ 0 ];
yaw_left = orientation[ 1 ];
}
Vector Player::GetViewAngles
(
void
)
{
return v_angle;
}
void Player::DumpState
(
Event *ev
)
{
gi.DPrintf( "Legs: %s Torso: %s\n", currentState_Legs ? currentState_Legs->getName() : "NULL", currentState_Torso->getName() );
}
void Player::ForceLegsState
(
Event *ev
)
{
State *ls = statemap_Legs->FindState( ev->GetString( 1 ) );
EvaluateState( NULL, ls );
}
void Player::ForceTorsoState
(
Event *ev
)
{
State *ts = statemap_Torso->FindState( ev->GetString( 1 ) );
EvaluateState( ts );
}
int Player::GetNumKills( void ) const
{
return num_kills;
}
int Player::GetNumDeaths( void ) const
{
return num_deaths;
}
void Player::AddKills( int num )
{
num_kills += num;
if( g_gametype->integer >= GT_TEAM_ROUNDS )
{
num_deaths += num;
}
}
void Player::AddDeaths( int num )
{
num_deaths += num;
}
DM_Team *Player::GetDM_Team()
{
return current_team;
}
void Player::SetDM_Team( DM_Team *team )
{
current_team = team;
// clear the player's team
edict->s.eFlags &= ~EF_ANY_TEAM;
if( team )
{
dm_team = team->teamType;
if( dm_team == TEAM_ALLIES )
{
edict->s.eFlags |= EF_ALLIES;
}
else if( dm_team == TEAM_AXIS )
{
edict->s.eFlags |= EF_AXIS;
}
}
else
{
dm_team = TEAM_NONE;
}
client->pers.team = dm_team;
if( m_fTeamSelectTime != level.time && ( edict->s.eFlags & ( EF_ANY_TEAM ) ) )
{
InitModel();
}
}
teamtype_t Player::GetTeam()
{
return dm_team;
}
void Player::SetTeam( teamtype_t team )
{
dmManager.JoinTeam( this, team );
if( dm_team == TEAM_SPECTATOR )
{
Spectator();
}
}
void Player::BeginTempSpectator( void )
{
m_bTempSpectator = true;
RemoveFromVehiclesAndTurrets();
m_iPlayerSpectating = 0;
takedamage = DAMAGE_NO;
health = max_health;
deadflag = 0;
client->ps.feetfalling = 0;
client->ps.pm_flags |= PMF_SPECTATING;
EvaluateState( statemap_Torso->FindState( "STAND" ), statemap_Legs->FindState( "STAND" ) );
setSolidType( SOLID_NOT );
setMoveType( MOVETYPE_NOCLIP );
FreeInventory();
hideModel();
SetPlayerSpectate();
}
void Player::EndSpectator( void )
{
m_bSpectator = false;
m_bTempSpectator = false;
client->ps.pm_flags &= ~( PMF_SPECTATING | PMF_SPECTATE_FOLLOW );
}
void Player::Spectator( void )
{
if( !IsSpectator() ) {
respawn_time = level.time + 1.0f;
}
RemoveFromVehiclesAndTurrets();
takedamage = DAMAGE_NO;
m_iPlayerSpectating = 0;
health = max_health;
deadflag = 0;
m_bSpectator = m_bTempSpectator ^ 1;
m_iPlayerSpectating = 0;
client->ps.feetfalling = 0;
client->ps.pm_flags |= PMF_SPECTATING;
movecontrol = MOVECONTROL_USER;
EvaluateState( statemap_Torso->FindState( "STAND" ), statemap_Legs->FindState( "STAND" ) );
setSolidType( SOLID_NOT );
setMoveType( MOVETYPE_NOCLIP );
FreeInventory();
hideModel();
SetPlayerSpectate();
}
bool Player::IsValidSpectatePlayer( Player *pPlayer )
{
if( g_gametype->integer <= GT_FFA ) {
return true;
}
if( GetTeam() <= TEAM_FREEFORALL
|| !g_forceteamspectate->integer
|| !GetDM_Team()->NumLivePlayers()
|| pPlayer->GetTeam() == GetTeam() )
{
return true;
}
else
{
return false;
}
}
void Player::SetPlayerSpectate( void )
{
int i;
gentity_t *ent;
Player *pPlayer;
if( m_iPlayerSpectating >= game.maxclients )
m_iPlayerSpectating = 0;
while( 1 )
{
for( i = m_iPlayerSpectating, ent = g_entities + i; i < game.maxclients; i++, ent++ )
{
if( !ent->inuse || !ent->entity ) {
continue;
}
pPlayer = ( Player * )ent->entity;
if( !pPlayer->IsDead() && !pPlayer->IsSpectator() && IsValidSpectatePlayer( pPlayer ) )
{
m_iPlayerSpectating = i + 1;
client->ps.camera_flags &= ~CF_CAMERA_CUT_BIT;
client->ps.camera_flags |= (client->ps.camera_flags & CF_CAMERA_CUT_BIT) ^ CF_CAMERA_CUT_BIT;
return;
}
}
if( !m_iPlayerSpectating )
return;
m_iPlayerSpectating = 0;
}
}
void Player::Spectator
(
Event *ev
)
{
client->pers.weapon[ 0 ] = 0;
SetTeam( TEAM_SPECTATOR );
}
bool Player::IsSpectator( void )
{
return ( m_bSpectator || m_bTempSpectator );
}
void Player::BeginFight( void )
{
m_bAllowFighting = true;
}
void Player::EndFight( void )
{
m_bAllowFighting = false;
}
void Player::EventGetUseHeld
(
Event *ev
)
{
ev->AddInteger( buttons & BUTTON_USE ? qtrue : qfalse );
}
void Player::EventGetFireHeld
(
Event *ev
)
{
ev->AddInteger( buttons & ( BUTTON_ATTACKLEFT | BUTTON_ATTACKRIGHT ) ? qtrue : qfalse );
}
void Player::Score
(
Event *ev
)
{
dmManager.Score( this );
}
void Player::WonMatch( void )
{
num_won_matches++;
}
void Player::LostMatch( void )
{
num_lost_matches++;
}
void Player::HUDPrint( const char *s )
{
gi.SendServerCommand( edict - g_entities, "hudprint \"%s\"\n", s );
}
void Player::GetIsDisguised
(
Event *ev
)
{
ev->AddInteger( m_bIsDisguised );
}
void Player::GetHasDisguise
(
Event *ev
)
{
ev->AddInteger( m_bHasDisguise );
}
void Player::SetHasDisguise
(
Event *ev
)
{
m_bHasDisguise = ev->GetBoolean( 1 );
}
void Player::SetObjectiveCount
(
Event *ev
)
{
m_iObjectivesCompleted = ev->GetInteger( 1 );
m_iNumObjectives = ev->GetInteger( 2 );
}
void Player::EventDMDeathDrop
(
Event *ev
)
{
Weapon *weapon = GetActiveWeapon( WEAPON_MAIN );
SpawnArgs args;
ClassDef *cls;
if( !m_bDontDropWeapons && weapon && weapon->IsSubclassOfWeapon() )
{
weapon->Drop();
}
args.setArg( "model", "models/items/dm_50_healthbox.tik" );
cls = args.getClassDef();
if( cls )
{
Item *item = ( Item * )cls->newInstance();
if( item )
{
if( item->IsSubclassOfItem() )
{
item->setModel( "models/items/dm_50_healthbox.tik" );
item->SetOwner( this );
item->ProcessPendingEvents();
item->Drop();
}
else
{
// useless and not pickupable, delete it
delete item;
}
}
}
FreeInventory();
}
void Player::EventStopwatch
(
Event *ev
)
{
int iDuration = ev->GetInteger( 1 );
if( iDuration < 0 )
{
ScriptError( "duration < 0" );
}
SetStopwatch( iDuration );
}
void Player::SetStopwatch
(
int iDuration
)
{
int iStartTime = 0;
char szCmd[ 256 ];
if( iDuration )
{
iStartTime = ( int )level.svsFloatTime;
}
sprintf( szCmd, "stopwatch %i %i", iStartTime, iDuration );
gi.SendServerCommand( edict - g_entities, szCmd );
}
void Player::CallVote
(
Event *ev
)
{
str arg1;
str arg2;
if( !g_gametype->integer )
return;
if( !g_allowvote->integer )
{
HUDPrint( gi.LV_ConvertString( "Voting not allowed here." ) );
return;
}
if( level.m_voteTime != 0.0f )
{
HUDPrint( gi.LV_ConvertString( "A vote is already in progress." ) );
return;
}
if( votecount >= MAX_VOTE_COUNT )
{
HUDPrint( va( "%s (%d).\n", gi.LV_ConvertString( "You have called the maximum number of votes" ), MAX_VOTE_COUNT ) );
return;
}
arg1 = ev->GetString( 1 );
arg2 = ev->GetString( 2 );
if( strchr( arg1.c_str(), ';' ) || strchr( arg2.c_str(), ';' ) )
{
HUDPrint( gi.LV_ConvertString( "Invalid vote string." ) );
return;
}
if( Q_stricmp( arg1.c_str(), "restart" ) &&
Q_stricmp( arg1.c_str(), "nextmap" ) &&
Q_stricmp( arg1.c_str(), "map" ) &&
Q_stricmp( arg1.c_str(), "g_gametype" ) &&
Q_stricmp( arg1.c_str(), "kick" ) &&
Q_stricmp( arg1.c_str(), "clientkick" ) &&
Q_stricmp( arg1.c_str(), "fraglimit" ) )
{
HUDPrint( gi.LV_ConvertString( "Invalid vote string." ) );
HUDPrint( va( "%s restart, nextmap, map <mapname>, g_gametype <n>, fraglimit <n>, timelimit <n>, kick <player>, and clientkick <player #>.",
gi.LV_ConvertString( "Vote commands are:" ) ) );
return;
}
if( !Q_stricmp( arg1.c_str(), "kick" ) )
{
gentity_t *ent;
int i;
for( i = 0; i < game.maxclients; i++ )
{
ent = &g_entities[ i ];
if( !ent->inuse || !ent->client || !ent->entity )
continue;
if( !Q_stricmp( ent->client->pers.netname, arg2.c_str() ) )
{
// Prevent the player from kicking himself out
if( ent->entity == this )
{
HUDPrint( gi.LV_ConvertString( "You are not allowed to kick yourself." ) );
return;
}
break;
}
}
if (i == game.maxclients)
{
HUDPrint(va("%s %s", ent->client->pers.netname, gi.LV_ConvertString("is not a valid player name to kick.")));
}
}
else if( !Q_stricmp( arg1.c_str(), "map" ) && *sv_nextmap->string )
{
level.m_voteString = va( "%s %s; set next map \"%s\"", arg1.c_str(), arg2.c_str(), arg2.c_str() );
}
else
{
level.m_voteString = va( "%s %s", arg1.c_str(), arg2.c_str() );
}
dmManager.PrintAllClients( va( "%s %s: %s\n", client->pers.netname, gi.LV_ConvertString( "called a vote" ), level.m_voteString.c_str() ) );
level.m_voteYes = 1;
level.m_voteNo = 0;
level.m_voteTime = level.time;
// Reset all player's vote
for( int i = 0; i < game.maxclients; i++ )
{
gentity_t *ent = &g_entities[ i ];
if( !ent->client || !ent->inuse )
continue;
Player *p = ( Player * )ent->entity;
p->voted = false;
}
voted = true;
votecount++;
level.m_numVoters = 0;
}
void Player::Vote
(
Event *ev
)
{
if( level.m_voteTime == 0.0f )
{
HUDPrint( gi.LV_ConvertString( "No vote in progress." ) );
return;
}
if( voted )
{
HUDPrint( gi.LV_ConvertString( "Vote already cast." ) );
return;
}
if( ev->NumArgs() != 1 )
{
HUDPrint( va( "%s: vote <1|0|y|n>", gi.LV_ConvertString( "Usage" ) ) );
return;
}
HUDPrint( gi.LV_ConvertString( "Vote cast." ) );
voted = true;
str arg1 = ev->GetString( 1 );
if( *arg1 == 'y' || *arg1 == 'Y' || *arg1 == '1' )
level.m_voteYes++;
else
level.m_voteNo++;
}
void Player::EventCoord
(
Event *ev
)
{
const char *s = va( "location: %.2f %.2f %.2f\nangles: %.2f %.2f %.2f\n(use 'tele' or 'face' to set)\n",
origin[ 0 ], origin[ 1 ], origin[ 2 ], v_angle[ 0 ], v_angle[ 1 ], v_angle[ 2 ] );
HUDPrint( s );
gi.Printf( s );
}
void Player::EventStuffText
(
Event *ev
)
{
if( level.spawning )
{
Event *event = new Event( EV_Player_StuffText );
event->AddValue( ev->GetValue( 1 ) );
PostEvent( event, level.frametime, 0 );
}
else
{
gi.SendServerCommand( edict - g_entities, "stufftext \"%s\"", ev->GetString( 1 ).c_str() );
}
}
void Player::EventSetVoiceType
(
Event *ev
)
{
str sVoiceName = ev->GetString( 1 );
if( !sVoiceName.icmp( "airborne" ) )
{
m_voiceType = PVT_ALLIED_AIRBORNE;
}
else if( !sVoiceName.icmp( "manon" ) )
{
m_voiceType = PVT_ALLIED_MANON;
}
else if( !sVoiceName.icmp( "SAS" ) )
{
m_voiceType = PVT_ALLIED_SAS;
}
else if( !sVoiceName.icmp( "pilot" ) )
{
m_voiceType = PVT_ALLIED_PILOT;
}
else if( !sVoiceName.icmp( "army" ) )
{
m_voiceType = PVT_ALLIED_ARMY;
}
else if( !sVoiceName.icmp( "ranger" ) )
{
m_voiceType = PVT_ALLIED_RANGER;
}
else if( !sVoiceName.icmp( "axis1" ) )
{
m_voiceType = PVT_AXIS_AXIS1;
}
else if( !sVoiceName.icmp( "axis2" ) )
{
m_voiceType = PVT_AXIS_AXIS2;
}
else if( !sVoiceName.icmp( "axis3" ) )
{
m_voiceType = PVT_AXIS_AXIS3;
}
else if( !sVoiceName.icmp( "axis4" ) )
{
m_voiceType = PVT_AXIS_AXIS4;
}
else if( !sVoiceName.icmp( "axis5" ) )
{
m_voiceType = PVT_AXIS_AXIS5;
}
else
{
m_voiceType = PVT_NONE_SET;
}
}
void Player::EventEnterIntermission
(
Event *ev
)
{
if( !level.intermissiontime ) {
return;
}
if( level.intermissiontype )
{
G_DisplayScores( this );
if( level.intermissiontype == TRANS_MISSION_FAILED || IsDead() )
{
gi.Cvar_Set( "g_success", "0" );
gi.Cvar_Set( "g_failed", "1" );
}
else
{
gi.Cvar_Set( "g_success", "1" );
gi.Cvar_Set( "g_failed", "0" );
}
}
else
{
G_HideScores( this );
}
}
void Player::EnterTurret
(
Event *ev
)
{
TurretGun *ent = ( TurretGun * )ev->GetEntity( 1 );
if( !ent ) {
return;
}
if( ent->IsSubclassOfTurretGun() ) {
return;
}
EnterTurret( ent );
}
void Player::EnterTurret
(
TurretGun *ent
)
{
flags |= FL_PARTIAL_IMMOBILE;
viewheight = DEFAULT_VIEWHEIGHT;
velocity = vec_zero;
m_pTurret = ent;
setMoveType( MOVETYPE_TURRET );
SafeHolster( true );
}
void Player::ExitTurret
(
Event *ev
)
{
ExitTurret();
}
void Player::ExitTurret
(
void
)
{
flags &= ~FL_PARTIAL_IMMOBILE;
setMoveType( MOVETYPE_WALK );
m_pTurret = NULL;
SafeHolster( qfalse );
}
void Player::TouchedUseAnim
(
Entity * ent
)
{
toucheduseanim = ent;
}
void Player::NextPainTime
(
Event *ev
)
{
float time = ev->GetFloat( 1 );
nextpaintime = level.time + time;
if( time >= 0.0f )
{
pain = 0.0f;
pain_type = MOD_NONE;
pain_location = LOCATION_MISS;
m_pLegsPainCond->clearCheck();
m_pTorsoPainCond->clearCheck();
}
}
void Player::SetMouthAngle
(
Event *ev
)
{
int tag_num;
float angle_percent;
Vector mouth_angles;
angle_percent = ev->GetFloat( 1 );
if ( angle_percent < 0 )
angle_percent = 0;
if ( angle_percent > 1 )
angle_percent = 1;
tag_num = gi.Tag_NumForName( edict->tiki, "tag_mouth" );
if ( tag_num != -1 )
{
SetControllerTag( MOUTH_TAG, tag_num );
mouth_angles = vec_zero;
mouth_angles[PITCH] = max_mouth_angle * angle_percent;
SetControllerAngles( MOUTH_TAG, mouth_angles );
}
}
void Player::EnterVehicle
(
Event *ev
)
{
Entity *ent;
ent = ev->GetEntity( 1 );
if( ent && ent->IsSubclassOfVehicle() )
{
flags |= FL_PARTIAL_IMMOBILE;
viewheight = STAND_EYE_HEIGHT;
velocity = vec_zero;
m_pVehicle = ( Vehicle * )ent;
if( m_pVehicle->IsDrivable() )
setMoveType( MOVETYPE_VEHICLE );
else
setMoveType( MOVETYPE_NOCLIP );
SafeHolster( true );
}
}
void Player::ExitVehicle
(
Event *ev
)
{
flags &= ~FL_PARTIAL_IMMOBILE;
setMoveType( MOVETYPE_WALK );
m_pVehicle = NULL;
}
void Player::WeaponsNotHolstered
(
void
)
{
}
void Player::WeaponsHolstered
(
void
)
{
}
void Player::HolsterToggle
(
Event *ev
)
{
if( deadflag )
{
return;
}
if( WeaponsOut() )
{
// fucking compiler bug
// it won't call the parent's override function
( ( Sentient * )this )->Holster( qtrue );
}
else
{
( ( Sentient * )this )->Holster( qfalse );
}
}
void Player::Holster
(
Event *ev
)
{
SafeHolster( ev->GetBoolean( 1 ) );
}
void Player::WatchActor
(
Event *ev
)
{
if ( camera || currentState_Torso->getCameraType() != CAMERA_BEHIND )
return;
actor_to_watch = (Actor *)ev->GetEntity( 1 );
}
void Player::StopWatchingActor
(
Event *ev
)
{
Actor *old_actor;
old_actor = (Actor *)ev->GetEntity( 1 );
if ( old_actor == actor_to_watch )
actor_to_watch = NULL;
}
void Player::setAngles
(
Vector ang
)
{
// set the angles normally
if( bindmaster )
{
ang -= bindmaster->angles;
}
Entity::setAngles( ang );
}
void Player::PlayerDone
(
Event *ev
)
{
// This is used to let scripts know that the player is done doing something
}
painDirection_t Player::Pain_string_to_int
(
str pain
)
{
if ( !pain.icmp( pain, "Front" ) )
return PAIN_FRONT;
else if ( !pain.icmp( pain, "Left" ) )
return PAIN_LEFT;
else if ( !pain.icmp( pain, "Right" ) )
return PAIN_RIGHT;
else if ( !pain.icmp( pain, "Rear" ) )
return PAIN_REAR;
else
return PAIN_NONE;
}
void Player::ArchivePersistantData
(
Archiver &arc
)
{
str model_name;
Sentient::ArchivePersistantData( arc );
model_name = g_playermodel->string;
arc.ArchiveString( &model_name );
if( arc.Loading() )
{
// set the cvar
gi.Cvar_Set( "g_playermodel", model_name.c_str() );
model_name += ".tik";
setModel( model_name.c_str() );
}
str name;
if( arc.Saving() )
{
if( holsteredWeapon )
{
name = holsteredWeapon->getName();
}
else
{
name = "none";
}
}
arc.ArchiveString( &name );
if( arc.Loading() )
{
if( name != "none" )
{
holsteredWeapon = ( Weapon * )FindItem( name );
}
}
UpdateWeapons();
// Force a re-evaluation of the player's state
LoadStateTable();
}
void Player::SpawnDamageEffect
(
meansOfDeath_t mod
)
{
switch( mod )
{
case MOD_ELECTRIC:
case MOD_ELECTRICWATER:
{
SpawnEffect( "fx_elecstrike.tik", origin );
Sound( "sound/weapons/sword/electric/hitmix2.wav", 0 );
}
default:
{
}
}
}
void Player::VelocityModified
(
void
)
{
}
int Player::GetKnockback
(
int original_knockback,
qboolean blocked
)
{
int new_knockback;
new_knockback = original_knockback - 50;
// See if we still have enough knockback to knock the player down
if( new_knockback >= 200 && take_pain )
{
knockdown = true;
if( blocked )
{
float damage;
damage = new_knockback / 50;
if( damage > 10 )
damage = 10;
Damage( world, world, damage, origin, vec_zero, vec_zero, 0, DAMAGE_NO_ARMOR, MOD_CRUSH );
}
}
// Make sure knockback is still at least 0
if( new_knockback < 0 )
new_knockback = 0;
return new_knockback;
}
int Player::GetMoveResult
(
void
)
{
return moveresult;
}
void Player::ResetHaveItem
(
Event *ev
)
{
str fullname;
ScriptVariable * var;
fullname = str( "playeritem_" ) + ev->GetString( 1 );
var = game.vars->GetVariable( fullname.c_str() );
if ( var )
var->setIntValue( 0 );
}
void Player::Join_DM_Team
(
Event *ev
)
{
teamtype_t team;
str teamname;
const char *join_message;
teamname = ev->GetString( 1 );
if( !teamname.icmp( "allies" ) )
{
team = TEAM_ALLIES;
}
else if( !teamname.icmp( "axis" ) ||
!teamname.icmp( "german" ) ||
!teamname.icmp( "nazi" ) )
{
team = TEAM_AXIS;
}
else
{
team = TEAM_AXIS;
}
if( current_team && current_team->m_teamnumber == team )
{
return;
}
float startTime = dmManager.GetMatchStartTime();
if( startTime >= 0.0f && ( level.time - startTime ) > 20.0f &&
( level.time - m_fTeamSelectTime ) < g_teamswitchdelay->integer && team != TEAM_SPECTATOR )
{
gi.SendServerCommand( edict - g_entities, "print \"" HUD_MESSAGE_WHITE "%s %i %s\n\"", gi.LV_ConvertString( "Can not change teams again for another" ), ( int )( g_teamswitchdelay->integer - ( level.time - m_fTeamSelectTime ) + 1.0f ), gi.LV_ConvertString( "seconds" ) );
return;
}
m_fTeamSelectTime = level.time;
SetTeam( team );
if( client->pers.weapon[ 0 ] )
{
if( IsSpectator() )
{
EndSpectator();
PostEvent( EV_Player_Respawn, 0 );
}
else if( g_gametype->integer <= 1 )
{
PostEvent( EV_Kill, 0 );
}
else
{
PostEvent( EV_Player_Respawn, 0 );
}
}
else
{
gi.SendServerCommand( edict - g_entities, "stufftext \"wait 250;pushmenu_weaponselect\"" );
}
if( g_gametype->integer > 1 )
{
if( GetTeam() == TEAM_ALLIES )
{
join_message = "has joined the Allies";
}
else if( GetTeam() == TEAM_AXIS )
{
join_message = "has joined the Axis";
}
else
{
return;
}
G_PrintToAllClients( va( "%s %s\n", client->pers.netname, gi.LV_ConvertString( join_message ) ) );
}
}
void Player::Auto_Join_DM_Team
(
Event *ev
)
{
Event *event = new Event( EV_Player_JoinDMTeam );
if( dmManager.GetAutoJoinTeam() == TEAM_AXIS )
{
event->AddString( "axis" );
}
else
{
event->AddString( "allies" );
}
ProcessEvent( event );
}
void Player::Leave_DM_Team
(
Event *ev
)
{
// FIXME: should it stays disabled ?
#if 0
if( current_team )
{
dmManager.LeaveTeam( this );
}
else
{
gi.centerprintf( edict, gi.LV_ConvertString( "You are not on a team" ) );
}
#endif
}
void Player::EventPrimaryDMWeapon
(
Event *ev
)
{
str dm_weapon = ev->GetString( 1 );
Q_strncpyz( client->pers.weapon, dm_weapon.c_str(), sizeof( client->pers.weapon ) );
if( m_bSpectator )
{
if( current_team && ( current_team->teamType == TEAM_AXIS || current_team->teamType == TEAM_ALLIES ) )
{
EndSpectator();
if( deadflag ) {
deadflag = DEAD_DEAD;
}
PostEvent( EV_Player_Respawn, 0 );
gi.centerprintf( edict, "" );
}
else
{
gi.SendServerCommand( edict - g_entities, "stufftext \"wait 250;pushmenu_teamselect\"" );
}
}
else
{
gi.SendServerCommand( edict - g_entities, "print \"" HUD_MESSAGE_WHITE "%s\n\"", "Will switch to new weapon next time you respawn" );
}
}
void Player::PlayerReload
(
Event *ev
)
{
Weapon *weapon;
if( deadflag )
return;
weapon = GetActiveWeapon( WEAPON_MAIN );
if( !weapon )
return;
if( weapon->CheckReload( FIRE_PRIMARY ) )
weapon->SetShouldReload( true );
}
void Player::EventCorrectWeaponAttachments
(
Event *ev
)
{
int iChild;
int iNumChildren;
int iTagRight;
int iTagLeft;
qboolean iUseAngles;
Vector vOffset;
Entity *pChild;
iTagRight = gi.Tag_NumForName( edict->tiki, "tag_weapon_right" );
iTagLeft = gi.Tag_NumForName( edict->tiki, "tag_weapon_left" );
iNumChildren = numchildren;
for( int i = 0; i < iNumChildren; i++ )
{
iChild = children[ i ];
if( iChild == ENTITYNUM_NONE ) {
continue;
}
pChild = G_GetEntity( iChild );
if( !pChild ) {
continue;
}
if( pChild->edict->s.tag_num == iTagLeft || pChild->edict->s.tag_num == iTagRight )
{
if( pChild->IsSubclassOfWeapon() )
{
if( pChild->edict->s.tag_num == iTagLeft )
{
iUseAngles = edict->s.attach_use_angles;
vOffset = edict->s.attach_offset;
// reattach to the right tag
detach();
attach( entnum, iTagRight, iUseAngles, vOffset );
}
}
else
{
// Remove entities like ammoclip
pChild->PostEvent( EV_Remove, 0 );
}
}
}
}
void Player::SelectNextItem
(
Event *ev
)
{
if( deadflag )
{
return;
}
Item *item = GetActiveWeapon( WEAPON_MAIN );
item = NextItem( item );
if( item )
{
useWeapon( ( Weapon * )item, WEAPON_MAIN );
}
}
void Player::SelectPreviousItem
(
Event *ev
)
{
if( deadflag )
{
return;
}
Item *item = GetActiveWeapon( WEAPON_MAIN );
item = PrevItem( item );
if( item )
{
useWeapon( ( Weapon * )item, WEAPON_MAIN );
}
}
void Player::SelectNextWeapon
(
Event *ev
)
{
if( deadflag )
{
return;
}
Weapon *weapon = GetActiveWeapon( WEAPON_MAIN );
Weapon *activeWeapon = weapon;
if( weapon )
{
weapon = NextWeapon( weapon );
if( g_gametype->integer )
{
while( weapon && weapon != activeWeapon && weapon->IsSubclassOfInventoryItem() )
{
weapon = NextWeapon( weapon );
}
}
}
else
{
weapon = WorstWeapon();
}
if( weapon && weapon != activeWeapon )
{
useWeapon( weapon );
}
}
void Player::SelectPreviousWeapon
(
Event *ev
)
{
if( deadflag )
{
return;
}
Weapon *weapon = GetActiveWeapon( WEAPON_MAIN );
Weapon *activeWeapon = weapon;
if( weapon )
{
weapon = PreviousWeapon( weapon );
if( g_gametype->integer )
{
while( weapon && weapon != activeWeapon && weapon->IsSubclassOfInventoryItem() )
{
weapon = PreviousWeapon( weapon );
}
}
}
else
{
weapon = BestWeapon();
}
if( weapon && weapon != activeWeapon )
{
useWeapon( weapon );
}
}
void Player::DropCurrentWeapon
(
Event *ev
)
{
Weapon *weapon;
Vector forward;
if( !g_gametype->integer )
{
return;
}
weapon = GetActiveWeapon( WEAPON_MAIN );
if( !weapon )
{
return;
}
// Don't drop the weapon if we're charging
if( charge_start_time )
{
return;
}
if( ( weapon->GetWeaponClass() & WEAPON_CLASS_ITEM ) )
{
SelectNextWeapon( NULL );
takeItem( weapon->model );
}
else
{
if( weapon->GetCurrentAttachToTag() != "tag_weapon_right" )
{
EventCorrectWeaponAttachments( NULL );
}
// This check isn't in MOHAA
if( !weapon->IsDroppable() )
{
return;
}
weapon->Drop();
AngleVectors( m_vViewAng, forward, NULL, NULL );
// make the weapon looks like it's thrown
weapon->velocity = forward * 200.0f;
edict->s.eFlags |= EF_UNARMED;
SelectNextWeapon( NULL );
if( holsteredWeapon == weapon )
{
holsteredWeapon = NULL;
}
if( lastActiveWeapon.weapon == weapon )
{
lastActiveWeapon.weapon = NULL;
}
}
}
void Player::ModifyHeight
(
Event *ev
)
{
str height = ev->GetString( 1 );
if ( !height.icmp( "stand" ) )
{
viewheight = DEFAULT_VIEWHEIGHT;
maxs.z = 94.0f;
}
else if( !height.icmp( "jumpstart" ) )
{
viewheight = JUMP_START_VIEWHEIGHT;
maxs.z = 94.0f;
}
else if( !height.icmp( "duck" ) )
{
viewheight = CROUCH_VIEWHEIGHT;
maxs.z = 54.0f;
}
else if( !height.icmp( "duckrun" ) )
{
viewheight = CROUCH_RUN_VIEWHEIGHT;
maxs.z = 60.0f;
}
else if( !height.icmp( "prone" ) )
{
viewheight = PRONE_VIEWHEIGHT;
maxs.z = 20.0f;
}
else
{
gi.Printf( "Unknown modheight '%s' defaulting to stand\n", height.c_str() );
viewheight = DEFAULT_VIEWHEIGHT;
maxs.z = 94.0f;
}
}
void Player::SetMovePosFlags
(
Event *ev
)
{
str sParm;
if( ev->NumArgs() <= 0 )
{
Com_Printf( "moveposflags command without any parameters\n" );
return;
}
sParm = ev->GetString( 1 );
if( !sParm.icmp( "crouching" ) )
{
m_iMovePosFlags = MPF_POSITION_CROUCHING;
}
else if( !sParm.icmp( "prone" ) )
{
m_iMovePosFlags = MPF_POSITION_PRONE;
}
else if( !sParm.icmp( "offground" ) )
{
m_iMovePosFlags = MPF_POSITION_OFFGROUND;
}
else
{
m_iMovePosFlags = MPF_POSITION_STANDING;
}
if( ev->NumArgs() > 1 )
{
sParm = ev->GetString( 2 );
if( !sParm.icmp( "walking" ) ||
!sParm.icmp( "walking\"" ) // there is a mistake in WALK_FORWARD
)
{
m_iMovePosFlags |= MPF_MOVEMENT_WALKING;
}
else if( !sParm.icmp( "running" ) )
{
m_iMovePosFlags |= MPF_MOVEMENT_RUNNING;
}
else if( !sParm.icmp( "falling" ) )
{
m_iMovePosFlags |= MPF_MOVEMENT_FALLING;
}
}
}
void Player::GetPositionForScript
(
Event *ev
)
{
if( m_iMovePosFlags & MPF_POSITION_CROUCHING )
{
ev->AddConstString( STRING_CROUCHING );
}
else if( m_iMovePosFlags & MPF_POSITION_PRONE )
{
ev->AddConstString( STRING_PRONE );
}
else if( m_iMovePosFlags & MPF_POSITION_OFFGROUND )
{
ev->AddConstString( STRING_OFFGROUND );
}
else
{
ev->AddConstString( STRING_STANDING );
}
}
void Player::GetMovementForScript
(
Event *ev
)
{
if( m_iMovePosFlags & MPF_MOVEMENT_WALKING )
{
ev->AddConstString( STRING_WALKING );
}
else if( m_iMovePosFlags & MPF_MOVEMENT_RUNNING )
{
ev->AddConstString( STRING_RUNNING );
}
else if( m_iMovePosFlags & MPF_MOVEMENT_FALLING )
{
ev->AddConstString( STRING_FALLING );
}
else
{
ev->AddConstString( STRING_STANDING );
}
}
void Player::EventSetViewModelAnim
(
Event *ev
)
{
str anim;
int force_restart = 0;
qboolean bfullanim = 0;
anim = ev->GetString( 1 );
if ( ev->NumArgs() > 1 ) {
force_restart = ev->GetInteger( 2 );
}
if ( ev->NumArgs() > 2 ) {
bfullanim = ev->GetInteger( 3 );
}
ViewModelAnim( anim, force_restart, bfullanim );
}
void Player::EventDMMessage
(
Event *ev
)
{
int mode;
str stuffstrings;
str convertedstuff;
str string;
str voiceName;
str soundName;
AliasListNode_t *list = NULL;
const char *prefix = NULL;
qboolean bInstaMessage = qfalse;
qboolean met_comment = false;
if( !g_gametype->integer ) {
return;
}
mode = ev->GetInteger( 1 );
if( ev->NumArgs() <= 1 ) {
return;
}
string = ev->GetString( 2 );
// Check for taunts
if( string.length() == 3 && *string == '*' )
{
char num1 = string[ 1 ];
char num2 = string[ 2 ];
if( num1 > '0' && num1 <= '9'
&& num2 > '0' && num2 <= '9' )
{
if( IsSpectator() || IsDead() ) {
return;
}
if( dm_team == TEAM_AXIS ) {
voiceName = "axis_";
} else {
voiceName = "allied_";
}
}
switch( m_voiceType )
{
case PVT_ALLIED_AIRBORNE:
voiceName += "airborne_";
break;
case PVT_ALLIED_MANON:
voiceName += "manon_";
break;
case PVT_ALLIED_SAS:
voiceName += "sas_";
break;
case PVT_ALLIED_PILOT:
voiceName += "pilot_";
break;
case PVT_ALLIED_ARMY:
voiceName += "army_";
break;
case PVT_ALLIED_RANGER:
voiceName += "ranger_";
break;
case PVT_AXIS_AXIS1:
voiceName += "axis1_";
break;
case PVT_AXIS_AXIS2:
voiceName += "axis2_";
break;
case PVT_AXIS_AXIS3:
voiceName += "axis3_";
break;
case PVT_AXIS_AXIS4:
voiceName += "axis4_";
break;
case PVT_AXIS_AXIS5:
voiceName += "axis5_";
break;
default:
if( dm_team != TEAM_AXIS ) {
voiceName += "army_";
} else {
voiceName += "axis4_";
}
}
voiceName += va( "%c%c", num1 + '0', num2 + '0' );
FindAlias( soundName, voiceName, &list );
if( list )
{
bInstaMessage = qtrue;
}
}
if( !bInstaMessage )
{
for( int i = 2; i <= ev->NumArgs(); i++ )
{
string = ev->GetString( i );
if( strstr( string, "/*" ) ) {
met_comment = true;
}
if( strstr( string, "*/" ) && met_comment )
{
G_WarnPlayer( this, "Line comments ('/*' and '*/') are not allowed in messages.\n" );
return;
}
stuffstrings += " " + string;
convertedstuff += gi.LV_ConvertString( string );
}
}
else
{
stuffstrings = " " + str( list->subtitle );
}
stuffstrings += "\n";
// Protect again buffer overflow exploit
if( stuffstrings.length() >= MAX_STRING_CHARS )
{
HUDPrint( "The message you entered is too long.\n" );
return;
}
if( convertedstuff.length() >= MAX_STRING_CHARS )
{
HUDPrint( "The message you entered is too long.\n" );
return;
}
// Prevent the comment glitch
// ley: The problem seems to be an issue with COM_Parse, which skips all C comments
if( strstr( client->pers.netname, "/*" ) ) {
met_comment = true;
}
if( strstr( client->pers.netname, "//" ) || strstr( client->pers.netname, "*/" ) )
{
HUDPrint( "C comments ('//', '/*' and '*/') are not allowed in names.\n" );
return;
}
if( IsSpectator() )
{
if( mode > 0 && mode <= game.maxclients )
{
const char *error = "Message Error: Spectators are not allowed to send private messages to non-spectators.\n";
gi.SendServerCommand( client->ps.clientNum, "print \"" HUD_MESSAGE_CHAT_WHITE "%s\"", error );
return;
}
prefix = gi.LV_ConvertString( "(spectator) " );
string = prefix + str( client->pers.netname ) + ":" + str( stuffstrings );
}
else if( IsDead() )
{
if( mode > 0 && mode <= game.maxclients )
{
const char *error = "Message Error: Dead players are not allowed to send private messages to active players.\n";
gi.SendServerCommand( client->ps.clientNum, "print \"" HUD_MESSAGE_CHAT_WHITE "%s\"", error );
return;
}
prefix = gi.LV_ConvertString( "(dead) " );
string = prefix + str( client->pers.netname ) + ":" + str( stuffstrings );
}
else
{
if( mode == -1 )
{
string = "(team) " + str( client->pers.netname ) + ":" + str( stuffstrings );
}
else
{
string = str( client->pers.netname ) + ":" + str( stuffstrings );
}
}
cvar_t *sv_chatter = gi.Cvar_Get( "sv_chatter", "0", 0 );
if( sv_chatter && sv_chatter->integer )
{
gi.Printf( "CHAT: %s", string.c_str() );
}
if( voiceName.length() )
{
if( !IsDead() && ( !IsSpectator() || g_spectate_allow_full_chat->integer ) )
{
gentity_t *ent;
int i;
for( i = 0, ent = g_entities; i < game.maxclients; i++, ent++ )
{
if( !ent->inuse || !ent->entity ) {
continue;
}
gi.SendServerCommand( i, "print \"" HUD_MESSAGE_CHAT_WHITE "%s\"", string.c_str() );
if( bInstaMessage )
{
gi.MSG_SetClient( i );
gi.MSG_StartCGM(BG_MapCGMToProtocol(g_protocol, CGM_VOICE_CHAT));
gi.MSG_WriteCoord( m_vViewPos[ 0 ] );
gi.MSG_WriteCoord( m_vViewPos[ 1 ] );
gi.MSG_WriteCoord( m_vViewPos[ 2 ] );
gi.MSG_WriteBits( 1, 1 );
gi.MSG_WriteBits( edict - g_entities, 6 );
gi.MSG_WriteString( voiceName.c_str() );
gi.MSG_EndCGM();
}
}
return;
}
}
if( mode == -1 )
{
int i;
gentity_t *ent;
Player *p;
// team message
for( i = 0, ent = g_entities; i < game.maxclients; i++, ent++ )
{
if( !ent->inuse || !ent->entity ) {
continue;
}
p = ( Player * ) ent->entity;
if( p->GetTeam() == GetTeam() )
{
gi.SendServerCommand( i, "print \"" HUD_MESSAGE_CHAT_WHITE "%s\"", string.c_str() );
}
}
}
else if( mode > 0 )
{
gentity_t *ent = g_entities + mode;
if( mode > game.maxclients || !ent->inuse || !ent->entity )
{
gi.SendServerCommand( client->ps.clientNum, "print \"" HUD_MESSAGE_CHAT_WHITE "Message Error: %d is a bad client number\n\"", mode );
return;
}
gi.SendServerCommand( client->ps.clientNum, "print \"" HUD_MESSAGE_CHAT_WHITE "%s\"", string.c_str() );
}
gi.SendServerCommand( mode - 1, "print \"" HUD_MESSAGE_CHAT_WHITE "%s\"", string.c_str() );
}
void Player::EventIPrint
(
Event *ev
)
{
str sString = ev->GetString( 1 );
qboolean iBold = qfalse;
if( ev->NumArgs() > 1 )
{
iBold = ev->GetInteger( 2 );
}
if( iBold )
{
gi.SendServerCommand( edict - g_entities, "print \"" HUD_MESSAGE_WHITE "%s\n\"", sString.c_str() );
}
else
{
gi.SendServerCommand( edict - g_entities, "print \"" HUD_MESSAGE_YELLOW "%s\n\"", sString.c_str() );
}
}
qboolean Player::ViewModelAnim( str anim, qboolean force_restart, qboolean bFullAnim )
{
Unregister( "viewmodelanim_done" );
if ( client == NULL ) {
return true;
}
int viewModelAnim;
playerState_t * playerState = &client->ps;
if ( !anim.length() ) {
anim = "";
}
if ( Q_stricmp( anim, "charge" ) == 0 ) {
viewModelAnim = VM_ANIM_CHARGE;
} else if ( Q_stricmp( anim, "fire" ) == 0 ) {
viewModelAnim = VM_ANIM_FIRE;
} else if ( Q_stricmp( anim, "fire_secondary" ) == 0 ) {
viewModelAnim = VM_ANIM_FIRE_SECONDARY;
} else if ( Q_stricmp( anim, "rechamber" ) == 0 ) {
viewModelAnim = VM_ANIM_RECHAMBER;
} else if ( Q_stricmp( anim, "reload" ) == 0 ) {
viewModelAnim = VM_ANIM_RELOAD;
} else if ( Q_stricmp( anim, "reload_single" ) == 0 ) {
viewModelAnim = VM_ANIM_RELOAD_SINGLE;
} else if ( Q_stricmp( anim, "reload_end" ) == 0 ) {
viewModelAnim = VM_ANIM_RELOAD_END;
} else if ( Q_stricmp( anim, "pullout" ) == 0 ) {
viewModelAnim = VM_ANIM_PULLOUT;
} else if ( Q_stricmp( anim, "putaway" ) == 0 ) {
viewModelAnim = VM_ANIM_PUTAWAY;
} else if ( Q_stricmp( anim, "ladderstep" ) == 0 ) {
viewModelAnim = VM_ANIM_LADDERSTEP;
} else if ( Q_stricmp( anim, "idle" ) == 0 ) {
viewModelAnim = VM_ANIM_IDLE;
}
else
{
ScriptError( "Invalid view model animation %s !\n", anim.c_str() );
return false;
}
// Copy the item prefix and the anim name
Item *item = GetActiveWeapon( WEAPON_MAIN );
if( !item )
{
item = ( Item * )newActiveWeapon.weapon.Pointer();
}
if( item )
{
m_sVMAcurrent = GetItemPrefix( item->getName() ) + str( "_" ) + anim;
}
else
{
m_sVMAcurrent = "unarmed_" + anim;
}
m_sVMcurrent = anim;
if ( viewModelAnim != playerState->iViewModelAnim || force_restart ) {
playerState->iViewModelAnimChanged = ( playerState->iViewModelAnimChanged + 1 ) & 3;
}
playerState->iViewModelAnim = viewModelAnim;
if( m_fpsTiki && gi.Anim_NumForName( m_fpsTiki, m_sVMAcurrent ) < 0 )
{
gi.DPrintf( "WARNING: Invalid view model anim \"%s\"\n", m_sVMAcurrent.c_str() );
}
animDoneVM = false;
m_fVMAtime = 0;
return true;
}
void Player::FindAlias( str &output, str name, AliasListNode_t **node )
{
const char *alias = gi.Alias_FindRandom( edict->tiki, name, node );
if( alias == NULL ) {
alias = gi.GlobalAlias_FindRandom( name, node );
}
if( alias != NULL ) {
output = alias;
}
}
bool Player::IsReady
(
void
) const
{
return m_bReady;
}
void Player::EventGetReady
(
Event *ev
)
{
ev->AddInteger( m_bReady );
}
void Player::EventSetReady
(
Event *ev
)
{
if( m_bReady )
return;
m_bReady = true;
gi.Printf( "%s is ready\n", client->pers.netname );
}
void Player::EventSetNotReady
(
Event *ev
)
{
if( !m_bReady )
return;
m_bReady = false;
gi.Printf( "%s is not ready\n", client->pers.netname );
}
void Player::EventGetDMTeam
(
Event *ev
)
{
if( dm_team == TEAM_FREEFORALL )
{
ev->AddConstString( STRING_FREEFORALL );
}
else if( dm_team == TEAM_AXIS )
{
ev->AddConstString( STRING_AXIS );
}
else if( dm_team == TEAM_ALLIES )
{
ev->AddConstString( STRING_ALLIES );
}
else if( dm_team == TEAM_SPECTATOR )
{
ev->AddConstString( STRING_SPECTATOR );
}
else
{
ScriptError( "dmteam is invalid in single player" );
}
}
void Player::EventSetPerferredWeapon
(
Event *ev
)
{
m_sPerferredWeaponOverride = ev->GetString( 1 );
}
void Player::ReceivedItem
(
Item * item
)
{
}
void Player::RemovedItem
(
Item * item
)
{
}
void Player::AmmoAmountChanged
(
Ammo * ammo,
int ammo_in_clip
)
{
str fullname;
ScriptVariable * var;
//
// set our level variables
//
fullname = str( "playerammo_" ) + ammo->getName();
var = level.vars->GetVariable( fullname.c_str() );
if( !var )
{
level.vars->SetVariable( fullname.c_str(), ammo->getAmount() + ammo_in_clip );
}
else
{
var->setIntValue( ammo->getAmount() + ammo_in_clip );
}
}
void Player::PhysicsOff
(
Event *ev
)
{
flags |= FL_IMMOBILE;
}
void Player::PhysicsOn
(
Event *ev
)
{
flags &= ~FL_IMMOBILE;
}
void Player::AttachToLadder
(
Event *ev
)
{
Vector vStart, vEnd, vOffset;
trace_t trace;
FuncLadder *pLadder;
if( deadflag ) {
return;
}
AngleVectors( m_vViewAng, vOffset, NULL, NULL );
vStart = m_vViewPos - vOffset * 12.0f;
vEnd = m_vViewPos + vOffset * 128.0f;
trace = G_Trace(
vStart,
vec_zero,
vec_zero,
vEnd,
this,
MASK_LADDER,
qfalse,
"Player::AttachToLadder" );
if( trace.fraction == 1.0f || !trace.ent || !trace.ent->entity ||
!trace.ent->entity->isSubclassOf( FuncLadder ) ) {
return;
}
pLadder = ( FuncLadder * )trace.ent->entity;
m_pLadder = pLadder;
pLadder->PositionOnLadder( this );
SetViewAngles( Vector( v_angle[ 0 ], angles[ 1 ], v_angle[ 2 ] ) );
}
void Player::UnattachFromLadder
(
Event *ev
)
{
m_pLadder = NULL;
}
void Player::TweakLadderPos
(
Event *ev
)
{
FuncLadder *pLadder = ( FuncLadder * )m_pLadder.Pointer();
if( pLadder ) {
pLadder->AdjustPositionOnLadder( this );
}
}
void Player::EnsureOverLadder
(
Event *ev
)
{
FuncLadder *pLadder = ( FuncLadder * )m_pLadder.Pointer();
if( pLadder ) {
pLadder->EnsureOverLadder( this );
}
}
void Player::EnsureForwardOffLadder
(
Event *ev
)
{
FuncLadder *pLadder = ( FuncLadder * )m_pLadder.Pointer();
if( pLadder ) {
pLadder->EnsureForwardOffLadder( this );
}
}
void Player::RemoveFromVehiclesAndTurrets
(
void
)
{
if( m_pVehicle && m_pVehicle->isLocked() )
{
m_pVehicle->UnLock();
if( m_pTurret )
{
VehicleTurretGun *turret = ( VehicleTurretGun * )m_pTurret.Pointer();
if( turret->isLocked() )
{
turret->UnLock();
DoUse( NULL );
turret->Lock();
}
else
{
DoUse( NULL );
}
}
else
{
DoUse( NULL );
}
m_pVehicle->Lock();
}
if( m_pTurret )
{
VehicleTurretGun *turret = ( VehicleTurretGun * )m_pTurret.Pointer();
if( turret->isLocked() )
{
turret->UnLock();
DoUse( NULL );
turret->Lock();
}
else
{
DoUse( NULL );
}
}
else
{
DoUse( NULL );
}
}
void Player::WaitForState
(
Event *ev
)
{
waitForState = ev->GetString( 1 );
}
void Player::SetDamageMultiplier
(
Event *ev
)
{
damage_multiplier = ev->GetFloat( 1 );
}
void Player::SetTakePain
(
Event *ev
)
{
take_pain = ev->GetBoolean( 1 );
}
void Player::Loaded
(
void
)
{
UpdateWeapons();
}
void Player::PlayerShowModel
(
Event *ev
)
{
Entity::showModel();
UpdateWeapons();
}
void Player::showModel
(
void
)
{
Entity::showModel();
UpdateWeapons();
}
void Player::Spawned
(
void
)
{
Event *ev = new Event;
ev->AddEntity( this );
scriptedEvents[ SE_SPAWN ].Trigger( ev );
}
// reborn stuff
void Player::AddKills
(
Event *ev
)
{
AddKills( ev->GetInteger( 1 ) );
}
void Player::AddDeaths
(
Event *ev
)
{
AddDeaths( ev->GetInteger( 1 ) );
}
void Player::AdminRights
(
Event *ev
)
{
// FIXME: Admin manager ?
ev->AddInteger( 0 );
}
void Player::BindWeap
(
Event *ev
)
{
// FIXME: TODO
}
void Player::CanSwitchTeams
(
Event *ev
)
{
qboolean bAllow = ev->GetBoolean( 1 );
disable_team_change = !bAllow;
if( ev->NumArgs() > 1 )
{
qboolean bAllow2 = ev->GetBoolean( 2 );
disable_spectate = !bAllow2;
}
}
void Player::ClearCommand
(
Event *ev
)
{
str command;
int clientNum = G_GetClientNumber( this );
if( ev->NumArgs() > 0 ) {
command = ev->GetString( 1 );
}
m_lastcommand = "";
}
void Player::Dive
(
Event *ev
)
{
float height, airborne_duration, speed;
Vector forwardvector = orientation[ 0 ];
height = ev->GetFloat( 1 );
if( ev->NumArgs() < 2 || ev->IsNilAt( 2 ) ) {
airborne_duration = 1;
} else {
airborne_duration = ev->GetFloat( 2 );
}
speed = height * airborne_duration;
velocity[ 0 ] += height * forwardvector[ 0 ] * ( speed / 16 );
velocity[ 1 ] += height * forwardvector[ 1 ] * ( speed / 16 );
velocity[ 2 ] += height * speed / 6.80f;
}
void Player::EventEarthquake
(
Event *ev
)
{
float duration = ev->GetFloat( 1 );
float magnitude = ev->GetFloat( 2 );
qboolean no_rampup = ev->GetBoolean( 3 );
qboolean no_rampdown = ev->GetBoolean( 4 );
// full realistic, smooth earthquake
if( ev->NumArgs() > 4 )
{
Vector location = ev->GetVector( 5 );
float radius = 1.0f;
if( ev->NumArgs() > 5 ) {
radius = ev->GetFloat( 6 );
}
gi.SendServerCommand( edict - g_entities, "eq %f %f %d %d %f %f %f %f", duration, magnitude, no_rampup, no_rampdown, location[ 0 ], location[ 1 ], location[ 2 ], radius );
}
else
{
gi.SendServerCommand( edict - g_entities, "eq %f %f %d %d", duration, magnitude, no_rampup, no_rampdown );
}
}
void Player::EventIsSpectator
(
Event *ev
)
{
ev->AddInteger( IsSpectator() );
}
void Player::EventSetTeam
(
Event *ev
)
{
str team_name;
teamtype_t teamType;
team_name = ev->GetString( 1 );
if( !team_name.length() )
{
ScriptError( "Invalid team name !" );
return;
}
if( Q_stricmp( team_name, "none" ) == 0 )
teamType = TEAM_NONE;
else if( Q_stricmp( team_name, "spectator" ) == 0 )
teamType = TEAM_SPECTATOR;
else if( Q_stricmp( team_name, "freeforall" ) == 0 )
teamType = TEAM_FREEFORALL;
else if( Q_stricmp( team_name, "allies" ) == 0 )
teamType = TEAM_ALLIES;
else if( Q_stricmp( team_name, "axis" ) == 0 )
teamType = TEAM_AXIS;
else
{
ScriptError( "Unknown team name \"%s\"\n", team_name.c_str() );
return;
}
SetTeam( teamType );
gi.Printf( "Player::SetTeam : Player is now on team \"%s\"\n", team_name.c_str() );
}
void Player::EventGetViewModelAnim
(
Event *ev
)
{
ev->AddString( m_sVMcurrent );
}
void Player::EventGetViewModelAnimFinished
(
Event *ev
)
{
ev->AddInteger( animDoneVM );
}
void Player::EventGetViewModelAnimValid
(
Event *ev
)
{
str anim_name = ev->GetString( 1 );
str fullanim;
bool bFullAnim = false;
if( ev->NumArgs() > 1 )
{
bFullAnim = ev->GetBoolean( 2 );
}
if( !bFullAnim )
{
// Copy the item prefix and the anim name
Item *item = GetActiveWeapon( WEAPON_MAIN );
if( !item )
{
item = ( Item * )newActiveWeapon.weapon.Pointer();
}
if( item )
{
fullanim = GetItemPrefix( item->getName() ) + str( "_" ) + anim_name;
}
else
{
fullanim = "unarmed_" + anim_name;
}
}
else
{
fullanim = anim_name;
}
if( !m_fpsTiki || gi.Anim_NumForName( m_fpsTiki, fullanim.c_str() ) < 0 )
{
ev->AddInteger( 0 );
}
else
{
ev->AddInteger( 1 );
}
}
void Player::FreezeControls
(
Event *ev
)
{
m_bFrozen = ev->GetBoolean( 1 );
}
void Player::GetConnState
(
Event *ev
)
{
ScriptDeprecated( "Player::GetConnState" );
}
void Player::GetDamageMultiplier
(
Event *ev
)
{
ev->AddFloat( damage_multiplier );
}
void Player::GetDeaths
(
Event *ev
)
{
ev->AddInteger( num_deaths );
}
void Player::GetKillHandler
(
Event *ev
)
{
if( m_pKilledEvent ) {
ev->AddValue( m_pKilledEvent->GetValue( 1 ) );
}
else {
ev->AddNil();
}
}
void Player::GetKills
(
Event *ev
)
{
ev->AddInteger( num_kills );
}
void Player::GetMoveSpeedScale
(
Event *ev
)
{
ev->AddFloat( speed_multiplier[ 0 ] );
}
void Player::GetLegsState
(
Event *ev
)
{
const char *name;
if( currentState_Legs != NULL ) {
name = currentState_Legs->getName();
}
else {
name = "none";
}
ev->AddString( name );
}
void Player::GetStateFile
(
Event *ev
)
{
int clientNum = G_GetClientNumber( this );
if( m_sStateFile.length() )
{
ev->AddString( m_sStateFile );
}
else
{
ev->AddString( g_statefile->string );
}
}
void Player::GetTorsoState
(
Event *ev
)
{
const char *name;
if( currentState_Torso != NULL ) {
name = currentState_Torso->getName();
}
else {
name = "none";
}
ev->AddString( name );
}
void Player::HideEntity
(
Event *ev
)
{
// FIXME: todo
}
void Player::ShowEntity
(
Event *ev
)
{
// FIXME: REDO
}
void Player::Inventory
(
Event *ev
)
{
Entity *ent = NULL;
ScriptVariable *ref = new ScriptVariable, *array = new ScriptVariable;
int i = 0;
ref->setRefValue( array );
for( i = 0; i < inventory.NumObjects(); i++ )
{
ent = G_GetEntity( inventory[ i ] );
if( ent == NULL ) {
continue;
}
ScriptVariable *index = new ScriptVariable, *value = new ScriptVariable;
index->setIntValue( i + 1 );
value->setListenerValue( ( Listener * )ent );
ref->setArrayAt( *index, *value );
}
ev->AddValue( *array );
}
void Player::InventorySet
(
Event *ev
)
{
ScriptVariable array;
ScriptVariable * value;
Entity * ent;
int arraysize;
if( ev->IsNilAt( 1 ) )
{
// Just clear the inventory
inventory.ClearObjectList();
return;
}
// Retrieve the array
array = ev->GetValue( 1 );
// Cast the array
array.CastConstArrayValue();
arraysize = array.arraysize();
// Detach all active weapons and free the inventory
if( inventory.NumObjects() > 0 ) {
inventory.FreeObjectList();
}
if( arraysize < 1 ) {
return;
}
// Allocate an inventory
for( int i = 1; i <= arraysize; i++ )
{
// Retrieve the value from the array
value = array[ i ];
// Get the entity from the value
ent = ( Entity * )value->entityValue();
if( ent == NULL || !ent->edict->inuse ) {
continue;
}
// Add the entity to the inventory
inventory.AddObject( ent->entnum );
}
// Clear the variable
array.Clear();
}
void Player::IsAdmin
(
Event *ev
)
{
// FIXME: Admin manager ?
ev->AddInteger( 0 );
}
void Player::LeanLeftHeld
(
Event *ev
)
{
Player *player = NULL;
int buttonheld = 0;
player = ( Player * )this;
buttonheld = !!( player->buttons & BUTTON_LEAN_LEFT );
ev->AddInteger( buttonheld );
}
void Player::LeanRightHeld
(
Event *ev
)
{
Player *player = NULL;
int buttonheld = 0;
player = ( Player * )this;
buttonheld = !!( player->buttons & BUTTON_LEAN_RIGHT );
ev->AddInteger( buttonheld );
}
// Specify the view height of the player and the height of his bounding box
void Player::ModifyHeightFloat
(
Event *ev
)
{
// params
int height;
float max_z;
height = ev->GetInteger( 1 );
max_z = ev->GetFloat( 2 );
viewheight = height;
if( max_z >= 94.0 ) {
max_z = 94.0;
}
else if( max_z >= 74.0 && max_z < 94.0 ) {
max_z = 54.0;
}
else if( max_z >= 30.0 && max_z < 54.0 ) {
max_z = 20.0;
}
else if( max_z <= 20.0 ) {
max_z = 20.0;
}
maxs.z = max_z;
client->ps.pm_flags &= ~( PMF_DUCKED | PMF_VIEW_PRONE | PMF_VIEW_DUCK_RUN | PMF_VIEW_JUMP_START );
// FIXME...
/*
gi.MSG_SetClient(edict - g_entities);
gi.MSG_StartCGM(CGM_MODHEIGHTFLOAT);
gi.MSG_WriteLong(height);
gi.MSG_WriteFloat(max_z);
gi.MSG_EndCGM();
*/
}
void Player::PlayLocalSound
(
Event *ev
)
{
str soundName = ev->GetString( 1 );
qboolean loop = false;
float time;
if( ev->NumArgs() > 1 ) {
loop = ev->GetBoolean( 2 );
}
if( ev->NumArgs() > 2 ) {
time = ev->GetFloat( 3 );
}
else {
time = 0.0f;
}
AliasListNode_t *alias = NULL;
const char *found = gi.GlobalAlias_FindRandom( soundName, &alias );
if( found == NULL )
{
gi.DPrintf( "ERROR: Player::PlayLocalSound: %s needs to be aliased - Please fix.\n", soundName.c_str() );
return;
}
// FIXME...
/*
gi.MSG_SetClient( client->ps.clientNum );
gi.MSG_StartCGM( CGM_PLAYLOCALSOUND );
gi.MSG_WriteString( found );
gi.MSG_WriteBits( !!loop, 1 );
gi.MSG_WriteFloat( time );
gi.MSG_WriteFloat( alias->volume );
gi.MSG_EndCGM();
return;
*/
if( loop )
{
edict->s.loopSound = gi.soundindex( found, alias->streamed );
edict->s.loopSoundVolume = 1.0f;
edict->s.loopSoundMinDist = 0;
edict->s.loopSoundMaxDist = 96;
edict->s.loopSoundPitch = 1.0f;
edict->s.loopSoundFlags = 1; // local sound
}
else
{
gi.Sound( &edict->s.origin,
entnum,
CHAN_LOCAL,
found,
1.0f,
0,
1.0f,
96,
alias->streamed );
}
}
void Player::RunHeld
(
Event *ev
)
{
Player *player = NULL;
int buttonheld = 0;
player = ( Player * )this;
buttonheld = !!( player->buttons & BUTTON_RUN );
ev->AddInteger( buttonheld );
}
void Player::SecFireHeld
(
Event *ev
)
{
Player *player = NULL;
int buttonheld = 0;
player = ( Player * )this;
buttonheld = !!( player->buttons & BUTTON_ATTACKRIGHT );
ev->AddInteger( buttonheld );
}
void Player::SetAnimSpeed
(
Event *ev
)
{
float speed;
Player * player = ( Player * )this;
speed = ev->GetFloat( 1 );
if( speed < 0.0f )
speed = 0.0f;
//player->baseSentient.baseAnimate.baseEntity.client->customanimspeed = speed;
}
void Player::SetClientFlag
(
Event *ev
)
{
str name = ev->GetString( 1 );
gi.SendServerCommand( client->ps.clientNum, "cf %s", name.c_str() );
}
void Player::SetEntityShader
(
Event *ev
)
{
Entity *entity = ev->GetEntity( 1 );
str shadername = ev->GetString( 2 );
qboolean fReset = false;
if( entity == NULL ) {
ScriptError( "Invalid entity !" );
}
if( !shadername.length() )
{
shadername = "default";
fReset = true;
}
gi.SendServerCommand( edict - g_entities, "setshader %d %s %d", entity->entnum, shadername.c_str(), fReset );
}
void Player::SetKillHandler
(
Event *ev
)
{
if( ev->IsNilAt( 1 ) || ( ev->IsStringAt( 1 ) && !ev->GetString( 1 ).icmp( "none" ) ) )
{
if( m_pKilledEvent != NULL )
{
delete m_pKilledEvent;
m_pKilledEvent = NULL;
}
}
else
{
m_pKilledEvent = new Event( EV_Listener_ExecuteScript );
m_pKilledEvent->AddValue( ev->GetValue( 1 ) );
}
}
void Player::SetLocalSoundRate
(
Event *ev
)
{
str name = ev->GetString( 1 );
float rate = ev->GetFloat( 2 );
float time;
if( ev->NumArgs() > 2 ) {
time = ev->GetFloat( 3 );
}
else {
time = 0.0f;
}
AliasListNode_t *alias = NULL;
const char *found = gi.GlobalAlias_FindRandom( name, &alias );
if( found == NULL )
{
gi.DPrintf( "ERROR: Player::SetLocalSoundRate: %s needs to be aliased - Please fix.\n", name.c_str() );
return;
}
gi.MSG_SetClient( client->ps.clientNum );
// FIXME...
/*
gi.MSG_StartCGM( CGM_SETLOCALSOUNDRATE );
gi.MSG_WriteString( found );
gi.MSG_WriteFloat( rate );
gi.MSG_WriteFloat( time );
gi.MSG_EndCGM();
*/
}
void Player::SetSpeed
(
Event *ev
)
{
float speed;
Player * player = ( Player * )this;
int clientNum = G_GetClientNumber( this );
int index = 0;
speed = ev->GetFloat( 1 );
if( speed < 0.0f )
speed = 0.0f;
if( ev->NumArgs() > 1 )
{
index = ev->GetInteger( 2 );
/* Reserve a space for moveSpeedScale */
if( index < 1 || index > MAX_SPEED_MULTIPLIERS ) {
gi.Printf( "Player::SetSpeed : invalid index %d. Index must be between 1-%d\n", index, speed_multiplier );
return;
}
}
speed_multiplier[ index ] = speed;
}
void Player::SetStateFile
(
Event *ev
)
{
int clientNum = G_GetClientNumber( this );
qboolean bRemove = false;
str string;
if( ev->NumArgs() <= 0 ) {
bRemove = true;
}
else
{
string = ev->GetString( 1 );
if( !string ) {
bRemove = true;
}
}
if( bRemove ) {
m_sStateFile = "";
} else {
m_sStateFile = string;
}
}
void Player::SetVMASpeed
(
Event *ev
)
{
str name = ev->GetString( 1 );
float speed = ev->GetFloat( 2 );
if( !client || !level.reborn ) {
return;
}
vma_t *vma = &vmalist[ name ];
if( speed < 0.0f ) {
speed = 0.0f;
}
vma->name = name;
vma->speed = speed;
// FIXME...
/*
gi.MSG_SetClient( edict - g_entities );
gi.MSG_StartCGM( CGM_SETVMASPEED );
gi.MSG_WriteString( name );
gi.MSG_WriteFloat( speed );
gi.MSG_EndCGM();
*/
}
void Player::StopLocalSound
(
Event *ev
)
{
str soundName = ev->GetString( 1 );
float time;
if( ev->NumArgs() > 1 ) {
time = ev->GetFloat( 2 );
}
else {
time = 0.0f;
}
AliasListNode_t *alias = NULL;
const char *found = gi.GlobalAlias_FindRandom( soundName, &alias );
if( found == NULL )
{
gi.DPrintf( "ERROR: Player::StopLocalSound: %s needs to be aliased - Please fix.\n", soundName.c_str() );
return;
}
edict->s.loopSound = 0;
gi.StopSound(entnum, CHAN_LOCAL);
}
void Player::UseHeld
(
Event *ev
)
{
int buttonheld = 0;
buttonheld = !!( buttons & BUTTON_USE );
ev->AddInteger( buttonheld );
}
void Player::Userinfo
(
Event *ev
)
{
if( !client )
{
ScriptError( "Entity is probably not of player type - userinfo\n" );
return;
}
ev->AddString( client->pers.userinfo );
}
void Player::VisionGetNaked
(
Event *ev
)
{
// return the global vision
if( !m_sVision.length() ) {
ev->AddString( vision_current );
}
else {
ev->AddString( m_sVision );
}
}
void Player::VisionSetBlur
(
Event *ev
)
{
float blur_level = ev->GetFloat( 1 );
float fade_time;
if( ev->NumArgs() > 1 ) {
fade_time = ev->GetFloat( 2 );
}
else {
fade_time = 0.0f;
}
gi.SendServerCommand( edict - g_entities, "vsb %f %f", blur_level, fade_time );
}
void Player::VisionSetNaked
(
Event *ev
)
{
str vision = ev->GetString( 1 );
float fade_time;
float phase;
if( ev->NumArgs() > 1 ) {
fade_time = ev->GetFloat( 2 );
}
else {
fade_time = 0.0f;
}
if( ev->NumArgs() > 2 ) {
phase = ev->GetFloat( 3 );
}
else {
phase = 0.0f;
}
if( !vision.length() ) {
vision = vision_current;
}
if( vision.length() >= MAX_STRING_TOKENS ) {
ScriptError( "vision_name exceeds the maximum vision name limit (256) !\n" );
}
m_sVision = vision;
gi.SendServerCommand( edict - g_entities, "vsn %s %f %f", vision.c_str(), fade_time, phase );
}