mirror of
https://github.com/UberGames/EF2GameSource.git
synced 2024-11-14 00:11:10 +00:00
14163 lines
316 KiB
C++
14163 lines
316 KiB
C++
//-----------------------------------------------------------------------------
|
|
//
|
|
// $Logfile:: /EF2/Code/DLLs/game/player.cpp $
|
|
// $Revision:: 590 $
|
|
// $Author:: Singlis $
|
|
// $Date:: 9/26/03 2:36p $
|
|
//
|
|
// Copyright (C) 1997 by Ritual Entertainment, Inc.
|
|
// All rights reserved.
|
|
//
|
|
// This source is may not be distributed and/or modified without
|
|
// expressly written permission by Ritual Entertainment, Inc.
|
|
//
|
|
//
|
|
// DESCRIPTION:
|
|
// Class definition of the player.
|
|
//
|
|
#include "_pch_cpp.h"
|
|
#include "entity.h"
|
|
#include "player.h"
|
|
#include "worldspawn.h"
|
|
#include "weapon.h"
|
|
#include "trigger.h"
|
|
#include "scriptmaster.h"
|
|
#include "path.h"
|
|
#include "navigate.h"
|
|
#include "misc.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 "mp_manager.hpp"
|
|
#include "body.h"
|
|
#include "viewthing.h"
|
|
#include "equipment.h"
|
|
#include "powerups.h"
|
|
#include "gamecmds.h"
|
|
#include "teammateroster.hpp"
|
|
#include <qcommon/gameplaymanager.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 PUSH_OBJECT_DISTANCE 16.0f
|
|
|
|
#define R_ARM_NAME "Bip01 R UpperArm"
|
|
#define L_ARM_NAME "Bip01 L UpperArm"
|
|
|
|
#define MELEE_ATTACK_LEFT (1<<0)
|
|
#define MELEE_ATTACK_RIGHT (1<<1)
|
|
|
|
const float standardTorsoMult = 0.75f;
|
|
|
|
const Vector power_color( 0.0f, 1.0f, 0.0f );
|
|
const Vector acolor( 1.0f, 1.0f, 1.0f );
|
|
const Vector bcolor( 0.5f, 0.0f, 0.0f );
|
|
|
|
const Vector damageNormalColor( 0.5f, 0.0f, 0.0f );
|
|
const Vector damageFireColor( 0.5f, 0.25f, 0.0f );
|
|
|
|
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."
|
|
);
|
|
Event EV_Player_ForceTorsoState
|
|
(
|
|
"forcetorsostate",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"torsostate",
|
|
"Force the player's torso to a certain state"
|
|
);
|
|
Event EV_Player_GiveAllCheat
|
|
(
|
|
"wuss",
|
|
EV_CHEAT,
|
|
NULL,
|
|
NULL,
|
|
"Gives player all weapons."
|
|
);
|
|
Event EV_Player_EndLevel
|
|
(
|
|
"endlevel",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Called when the player gets to the end of the level."
|
|
);
|
|
Event EV_Player_DevGodCheat
|
|
(
|
|
"god",
|
|
EV_CHEAT,
|
|
"I",
|
|
"god_mode",
|
|
"Sets the god mode cheat or toggles it."
|
|
);
|
|
Event EV_Player_DevNoTargetCheat
|
|
(
|
|
"notarget",
|
|
EV_CHEAT,
|
|
NULL,
|
|
NULL,
|
|
"Toggles the notarget cheat."
|
|
);
|
|
Event EV_Player_DevNoClipCheat
|
|
(
|
|
"noclip",
|
|
EV_CHEAT,
|
|
NULL,
|
|
NULL,
|
|
"Toggles the noclip cheat."
|
|
);
|
|
Event EV_Player_PrevItem
|
|
(
|
|
"invprev",
|
|
EV_CONSOLE,
|
|
NULL,
|
|
NULL,
|
|
"Cycle to player's previous item."
|
|
);
|
|
Event EV_Player_NextItem
|
|
(
|
|
"invnext",
|
|
EV_CONSOLE,
|
|
NULL,
|
|
NULL,
|
|
"Cycle to player's next item."
|
|
);
|
|
Event EV_Player_GiveCheat
|
|
(
|
|
"give",
|
|
EV_CHEAT | EV_TIKIONLY | EV_SCRIPTONLY,
|
|
"sI",
|
|
"name amount",
|
|
"Gives the player the specified thing (weapon, ammo, item, etc.) and optionally the amount."
|
|
);
|
|
Event EV_Player_GiveWeaponCheat
|
|
(
|
|
"giveweapon",
|
|
EV_CHEAT,
|
|
"s",
|
|
"weapon_name",
|
|
"Gives the player the specified weapon."
|
|
);
|
|
Event EV_Player_UseItem
|
|
(
|
|
"use",
|
|
EV_CONSOLE,
|
|
"sI",
|
|
"name weapon_hand",
|
|
"Use the specified weapon in the hand choosen (optional)."
|
|
);
|
|
Event EV_Player_GameVersion
|
|
(
|
|
"gameversion",
|
|
EV_CONSOLE,
|
|
NULL,
|
|
NULL,
|
|
"Prints the game version."
|
|
);
|
|
Event EV_Player_Fov
|
|
(
|
|
"fov",
|
|
EV_CONSOLE,
|
|
"F",
|
|
"fov",
|
|
"Sets the fov."
|
|
);
|
|
Event EV_Player_Dead
|
|
(
|
|
"dead",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Called when the player is dead."
|
|
);
|
|
Event EV_Player_SpawnEntity
|
|
(
|
|
"spawn",
|
|
EV_CHEAT | EV_SCRIPTONLY,
|
|
"sSSSSSSSS",
|
|
"entityname keyname1 value1 keyname2 value2 keyname3 value3 keyname4 value4",
|
|
"Spawns an entity."
|
|
);
|
|
Event EV_Player_SpawnActor
|
|
(
|
|
"actor",
|
|
EV_CHEAT,
|
|
"sSSSSSSSS",
|
|
"modelname keyname1 value1 keyname2 value2 keyname3 value3 keyname4 value4",
|
|
"Spawns an actor."
|
|
);
|
|
Event EV_Player_Respawn
|
|
(
|
|
"respawn",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Respawns the player."
|
|
);
|
|
Event EV_Player_TestThread
|
|
(
|
|
"testthread",
|
|
EV_CHEAT,
|
|
"sS",
|
|
"scriptfile label",
|
|
"Starts the named thread at label if provided."
|
|
);
|
|
Event EV_Player_ResetState
|
|
(
|
|
"resetstate",
|
|
EV_CHEAT,
|
|
NULL,
|
|
NULL,
|
|
"Reset the player's state table."
|
|
);
|
|
Event EV_Player_WhatIs
|
|
(
|
|
"whatis",
|
|
EV_CHEAT,
|
|
"i",
|
|
"entity_number",
|
|
"Prints info on the specified entity."
|
|
);
|
|
Event EV_Player_ActorInfo
|
|
(
|
|
"actorinfo",
|
|
EV_CHEAT,
|
|
"i",
|
|
"actor_number",
|
|
"Prints info on the specified actor."
|
|
);
|
|
Event EV_Player_ShowHeuristics
|
|
(
|
|
"showheuristics",
|
|
EV_CHEAT,
|
|
NULL,
|
|
NULL,
|
|
"Shows the current heuristic numbers"
|
|
);
|
|
Event EV_Player_KillEnt
|
|
(
|
|
"killent",
|
|
EV_CHEAT | EV_SCRIPTONLY,
|
|
"i",
|
|
"entity_number",
|
|
"Kills the specified entity."
|
|
);
|
|
Event EV_Player_KillClass
|
|
(
|
|
"killclass",
|
|
EV_CHEAT | EV_SCRIPTONLY,
|
|
"sI",
|
|
"classname except_entity_number",
|
|
"Kills all of the entities in the specified class."
|
|
);
|
|
Event EV_Player_RemoveEnt
|
|
(
|
|
"removeent",
|
|
EV_CHEAT | EV_SCRIPTONLY,
|
|
"i",
|
|
"entity_number",
|
|
"Removes the specified entity."
|
|
);
|
|
Event EV_Player_RemoveClass
|
|
(
|
|
"removeclass",
|
|
EV_CHEAT | EV_SCRIPTONLY,
|
|
"sI",
|
|
"classname except_entity_number",
|
|
"Removes all of the entities in the specified class."
|
|
);
|
|
Event EV_Player_ActivateNewWeapon
|
|
(
|
|
"activatenewweapon",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Active the new weapon specified by useWeapon."
|
|
);
|
|
Event EV_Player_DeactivateWeapon
|
|
(
|
|
"deactivateweapon",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"side",
|
|
"Deactivate the weapon in the specified hand."
|
|
);
|
|
Event EV_Player_Jump
|
|
(
|
|
"jump",
|
|
EV_TIKIONLY,
|
|
"f",
|
|
"height",
|
|
"Makes the player jump."
|
|
);
|
|
Event EV_Player_AnimLoop_Torso
|
|
(
|
|
"animloop_torso",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Called when the torso animation has finished."
|
|
);
|
|
Event EV_Player_AnimLoop_Legs
|
|
(
|
|
"animloop_legs",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Called when the legs animation has finished."
|
|
);
|
|
Event EV_Player_DoUse
|
|
(
|
|
"usestuff",
|
|
EV_DEFAULT,
|
|
"E",
|
|
"usingEntity",
|
|
"Makes the player try to use whatever is in front of her."
|
|
);
|
|
Event EV_Player_SetHeadTarget
|
|
(
|
|
"headtarget",
|
|
EV_CONSOLE,
|
|
NULL,
|
|
NULL,
|
|
"Sets the Makes the player try to use whatever is in front of her."
|
|
);
|
|
Event EV_Player_ListInventory
|
|
(
|
|
"listinventory",
|
|
EV_CONSOLE,
|
|
NULL,
|
|
NULL,
|
|
"List of the player's inventory."
|
|
);
|
|
Event EV_Player_ClearTarget
|
|
(
|
|
"cleartarget",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Clears the target of the player"
|
|
);
|
|
Event EV_Player_ActivateShield
|
|
(
|
|
"activateshield",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Activates the player's shield"
|
|
);
|
|
Event EV_Player_DeactivateShield
|
|
(
|
|
"deactivateshield",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Deactivates the player's shield"
|
|
);
|
|
Event EV_Player_AdjustTorso
|
|
(
|
|
"adjust_torso",
|
|
EV_DEFAULT,
|
|
"b",
|
|
"boolean",
|
|
"Turn or off the torso adjustment"
|
|
);
|
|
Event EV_Player_DualWield
|
|
(
|
|
"dualwield",
|
|
EV_CONSOLE,
|
|
"ss",
|
|
"weaponleft weaponright",
|
|
"Dual wield the specified weapons"
|
|
);
|
|
Event EV_Player_UseDualWield
|
|
(
|
|
"usedualwield",
|
|
EV_CONSOLE,
|
|
NULL,
|
|
NULL,
|
|
"Use the weapons that are on the dual wield list"
|
|
);
|
|
Event EV_Player_EvaluateTorsoAnim
|
|
(
|
|
"evaluatetorsoanim",
|
|
EV_CONSOLE,
|
|
NULL,
|
|
NULL,
|
|
"Evaluate the torso anim for possible changes"
|
|
);
|
|
Event EV_Player_Turn
|
|
(
|
|
"turn",
|
|
EV_SCRIPTONLY,
|
|
"fF",
|
|
"yawangle time",
|
|
"Causes player to turn the specified amount."
|
|
);
|
|
Event EV_Player_TurnTowardsEntity
|
|
(
|
|
"turnTowardsEntity",
|
|
EV_SCRIPTONLY,
|
|
"e",
|
|
"entity",
|
|
"Causes the player to turn towards the specified entity."
|
|
);
|
|
Event EV_Player_TurnUpdate
|
|
(
|
|
"turnupdate",
|
|
EV_SCRIPTONLY,
|
|
"ff",
|
|
"yaw timeleft",
|
|
"Causes player to turn the specified amount."
|
|
);
|
|
Event EV_Player_TurnLegs
|
|
(
|
|
"turnlegs",
|
|
EV_SCRIPTONLY,
|
|
"f",
|
|
"yawangle",
|
|
"Turns the players legs instantly by the specified amount."
|
|
);
|
|
Event EV_Player_DontTurnLegs
|
|
(
|
|
"dontturnlegs",
|
|
EV_CODEONLY,
|
|
"b",
|
|
"flag",
|
|
"Specifies whether or not to turn the legs while strafing."
|
|
);
|
|
Event EV_Player_NextPainTime
|
|
(
|
|
"nextpaintime",
|
|
EV_CODEONLY,
|
|
"f",
|
|
"seconds",
|
|
"Set the next time the player experiences pain (Current time + seconds specified)."
|
|
);
|
|
Event EV_Player_FinishUseAnim
|
|
(
|
|
"finishuseanim",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Fires off all targets associated with a particular useanim."
|
|
);
|
|
Event EV_Player_Nightvision
|
|
(
|
|
"nightvision",
|
|
EV_CODEONLY | EV_CONSOLE,
|
|
NULL,
|
|
NULL,
|
|
"Toggles player nightvision mode"
|
|
);
|
|
Event EV_Player_Holster
|
|
(
|
|
"holster",
|
|
EV_SCRIPTONLY,
|
|
NULL,
|
|
NULL,
|
|
"Holsters all wielded weapons, or unholsters previously put away weapons"
|
|
);
|
|
Event EV_Player_SafeHolster
|
|
(
|
|
"safeholster",
|
|
EV_SCRIPTONLY,
|
|
"b",
|
|
"putaway",
|
|
"Holsters all wielded weapons, or unholsters previously put away weapons\n"
|
|
"preserves state, so it will not holster or unholster unless necessary"
|
|
);
|
|
Event EV_Player_StartUseObject
|
|
(
|
|
"startuseobject",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"starts up the useobject's animations."
|
|
);
|
|
Event EV_Player_FinishUseObject
|
|
(
|
|
"finishuseobject",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Fires off all targets associated with a particular useobject."
|
|
);
|
|
Event EV_Player_WatchActor
|
|
(
|
|
"watchactor",
|
|
EV_SCRIPTONLY,
|
|
"eFFB",
|
|
"entity_to_watch time angle watchEntireDuration",
|
|
"Makes the player's camera watch the specified entity."
|
|
);
|
|
Event EV_Player_WatchEntity
|
|
(
|
|
"watchentity",
|
|
EV_SCRIPTONLY,
|
|
"eFFB",
|
|
"entityToWatch time angle watchEntireDuration",
|
|
"Makes the player's camera watch the specified entity."
|
|
);
|
|
Event EV_Player_StopWatchingEntity
|
|
(
|
|
"stopwatchingactor",
|
|
EV_SCRIPTONLY,
|
|
"e",
|
|
"entity_to_stop_watching",
|
|
"Makes the player's camera stop watching the specified entity."
|
|
);
|
|
Event EV_Player_PutawayWeapon
|
|
(
|
|
"putawayweapon",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"whichHand",
|
|
"Put away or deactivate the current weapon, whichHand can be left, right or dual."
|
|
);
|
|
Event EV_Player_Weapon
|
|
(
|
|
"weaponcommand",
|
|
EV_CODEONLY,
|
|
"sSSSSSSS",
|
|
"hand arg1 arg2 arg3 arg4 arg5 arg6 arg7",
|
|
"Pass the args to the active weapon in the specified hand"
|
|
);
|
|
Event EV_Player_Done
|
|
(
|
|
"playerdone",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Clears the waitForPlayer script command, allowing threads to run"
|
|
);
|
|
Event EV_Player_ActivateDualWeapons
|
|
(
|
|
"activatedualweapons",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Activates 2 weapons at once"
|
|
);
|
|
Event EV_Player_StartCoolItem
|
|
(
|
|
"startcoolitem",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Player is starting to show off the cool item"
|
|
);
|
|
Event EV_Player_StopCoolItem
|
|
(
|
|
"stopcoolitem",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Player is starting to show off the cool item"
|
|
);
|
|
Event EV_Player_ShowCoolItem
|
|
(
|
|
"showcoolitem",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Player is showing the cool item, actually display it"
|
|
);
|
|
Event EV_Player_HideCoolItem
|
|
(
|
|
"hidecoolitem",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Player is finished showing the cool item, now hide it"
|
|
);
|
|
Event EV_Player_SetDamageMultiplier
|
|
(
|
|
"damage_multiplier",
|
|
EV_SCRIPTONLY,
|
|
"f",
|
|
"damage_multiplier",
|
|
"Sets the current damage multiplier"
|
|
);
|
|
Event EV_Player_WaitForState
|
|
(
|
|
"waitForState",
|
|
EV_SCRIPTONLY,
|
|
"s",
|
|
"stateToWaitFor",
|
|
"When set, the player will clear waitforplayer when this state is hit\n"
|
|
"in the legs or torso."
|
|
);
|
|
Event EV_Player_LogStats
|
|
(
|
|
"logstats",
|
|
EV_CHEAT,
|
|
"b",
|
|
"state",
|
|
"Turn on/off the debugging playlog"
|
|
);
|
|
Event EV_Player_TakePain
|
|
(
|
|
"takepain",
|
|
EV_DEFAULT,
|
|
"b",
|
|
"bool",
|
|
"Set whether or not to take pain"
|
|
);
|
|
Event EV_Player_SkipCinematic
|
|
(
|
|
"skipcinematic",
|
|
EV_CONSOLE,
|
|
NULL,
|
|
NULL,
|
|
"Skip the current cinematic"
|
|
);
|
|
Event EV_Player_ResetHaveItem
|
|
(
|
|
"resethaveitem",
|
|
EV_CONSOLE,
|
|
"s",
|
|
"weapon_name",
|
|
"Resets the game var that keeps track that we have gotten this weapon"
|
|
);
|
|
Event EV_Player_Score
|
|
(
|
|
"score",
|
|
EV_CONSOLE,
|
|
NULL,
|
|
NULL,
|
|
"Show the score for the current deathmatch game"
|
|
);
|
|
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_JoinTeam
|
|
(
|
|
"joinmpteam",
|
|
EV_CONSOLE,
|
|
"s",
|
|
"teamName",
|
|
"Makes the player join the specified team."
|
|
);
|
|
Event EV_Player_MultiplayerCommand
|
|
(
|
|
"mpCmd",
|
|
EV_CONSOLE,
|
|
"ss",
|
|
"command parm",
|
|
"Sends a command from the player to the multiplayer system."
|
|
);
|
|
Event EV_Player_DeadBody
|
|
(
|
|
"deadbody",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Spawn a dead body"
|
|
);
|
|
Event EV_Player_SetAimType
|
|
(
|
|
"setaim",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"aimtype",
|
|
"Sets the accuracy modifiers for the player"
|
|
);
|
|
Event EV_Player_ReloadWeapon
|
|
(
|
|
"forcereload",
|
|
EV_TIKIONLY,
|
|
NULL,
|
|
NULL,
|
|
"Tells the weapon to reload"
|
|
);
|
|
Event EV_Player_AnimateWeapon
|
|
(
|
|
"animateweapon",
|
|
EV_DEFAULT,
|
|
"sSB",
|
|
"anim hand animatingFlag",
|
|
"Animates the weapon, optionally, in the specific hand (defaults to DUAL)"
|
|
"If the animatingFlag is set to false, it will not set the WEAPON_ANIMATING"
|
|
"as the status for this animation."
|
|
);
|
|
Event EV_Player_SwitchWeaponMode
|
|
(
|
|
"switchmode",
|
|
EV_TIKIONLY,
|
|
NULL,
|
|
NULL,
|
|
"Tells the weapon to switch modes of fire"
|
|
);
|
|
Event EV_Player_ReloadTiki
|
|
(
|
|
"reloadviewtiki",
|
|
EV_CHEAT,
|
|
"s",
|
|
"tikiname",
|
|
"Reloads the specified TIKI file from disk"
|
|
);
|
|
Event EV_Player_SetViewAngles
|
|
(
|
|
"playerviewangles",
|
|
EV_CHEAT,
|
|
"v[0,360][0,360][0,360]",
|
|
"newAngles",
|
|
"set the angles of the player to newAngles."
|
|
);
|
|
Event EV_Player_ProjDetonate
|
|
(
|
|
"projdetonate",
|
|
EV_CODEONLY,
|
|
"b",
|
|
"detonate",
|
|
"Event that sets the whether or not to detonate a trigger projectile (grenade launcher)"
|
|
);
|
|
Event EV_Player_UseEntity
|
|
(
|
|
"useentity",
|
|
EV_DEFAULT,
|
|
"e",
|
|
"entity",
|
|
"makes player use the passed in entity"
|
|
);
|
|
Event EV_Player_SetupDialog
|
|
(
|
|
"setupdialog",
|
|
EV_CODEONLY,
|
|
"is",
|
|
"entnum soundname",
|
|
"Sets up the dialog for the player"
|
|
);
|
|
Event EV_Player_ClearDialog
|
|
(
|
|
"cleardialog",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Clears the dialog for the player"
|
|
);
|
|
|
|
Event EV_Player_ClearTextDialog
|
|
(
|
|
"cleartextdialog",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Clears the text dialog of the player"
|
|
);
|
|
|
|
//
|
|
// Objective Events
|
|
//
|
|
Event EV_Player_LoadObjectives
|
|
(
|
|
"loadobjectives",
|
|
EV_SCRIPTONLY,
|
|
"s",
|
|
"name",
|
|
"Loads the a set of objectives"
|
|
);
|
|
Event EV_Player_SetObjectiveShow
|
|
(
|
|
"setobjectiveshow",
|
|
EV_SCRIPTONLY,
|
|
"sb",
|
|
"name show",
|
|
"Sets whether or not a specified objective is shown"
|
|
);
|
|
Event EV_Player_SetObjectiveComplete
|
|
(
|
|
"setobjectivecomplete",
|
|
EV_SCRIPTONLY,
|
|
"sb",
|
|
"name complete",
|
|
"Sets whether or not a specified objective is complete"
|
|
);
|
|
Event EV_Player_SetObjectiveFailed
|
|
(
|
|
"setobjectivefailed",
|
|
EV_SCRIPTONLY,
|
|
"sb",
|
|
"name failed",
|
|
"Sets whether or not a specified objective is failed"
|
|
);
|
|
|
|
//
|
|
// Information Events
|
|
//
|
|
Event EV_Player_SetInformationShow
|
|
(
|
|
"setinformationshow",
|
|
EV_SCRIPTONLY,
|
|
"sb",
|
|
"name show",
|
|
"Sets whether or not a specified information is shown"
|
|
);
|
|
Event EV_Player_MissionFailed
|
|
(
|
|
"missionfailed",
|
|
EV_SCRIPTONLY,
|
|
"S",
|
|
"reason",
|
|
"Displays the mission failed screen on the client side"
|
|
);
|
|
Event EV_Player_SetStat
|
|
(
|
|
"setstat",
|
|
EV_SCRIPTONLY,
|
|
"si",
|
|
"stat_name stat_value",
|
|
"Sets a stat value"
|
|
);
|
|
Event EV_Player_SpecialMoveChargeStart
|
|
(
|
|
"specialmovestart",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Starts charging up for a special move"
|
|
);
|
|
Event EV_Player_SpecialMoveChargeEnd
|
|
(
|
|
"specialmoveend",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Ends charging up for a special move"
|
|
);
|
|
Event EV_Player_SpecialMoveChargeTime
|
|
(
|
|
"specialmovetime",
|
|
EV_CODEONLY,
|
|
"f",
|
|
"time",
|
|
"Sets how long to wait before triggering the special move."
|
|
);
|
|
Event EV_Player_ChangeChar
|
|
(
|
|
"changechar",
|
|
EV_SCRIPTONLY,
|
|
"ssss",
|
|
"statefile model replacemodelName spawnNPC",
|
|
"Changes the character state and model."
|
|
);
|
|
Event EV_Player_SetPlayerCharacter
|
|
(
|
|
"setplayerchar",
|
|
EV_SCRIPTONLY,
|
|
"ss",
|
|
"statefile model",
|
|
"Sets the player character."
|
|
);
|
|
Event EV_Player_PlayerKnockback
|
|
(
|
|
"playerknockback",
|
|
EV_CODEONLY,
|
|
"f",
|
|
"knockback",
|
|
"Sets knockback for the player"
|
|
);
|
|
Event EV_Player_KnockbackMultiplier
|
|
(
|
|
"knockbackmultiplier",
|
|
EV_CODEONLY,
|
|
"i",
|
|
"knockbackmult",
|
|
"Sets knockback multiplierfor the player"
|
|
);
|
|
Event EV_Player_Melee
|
|
(
|
|
"melee",
|
|
EV_DEFAULT,
|
|
"FSF",
|
|
"damage means_of_death knockback",
|
|
"Makes the player do a weapon-less melee attack. "
|
|
);
|
|
Event EV_Player_ChangeStance
|
|
(
|
|
"stance",
|
|
EV_CONSOLE,
|
|
"i",
|
|
"stanceNumber",
|
|
"Makes the player change to the specified stance"
|
|
);
|
|
Event EV_Player_ClearStanceTorso
|
|
(
|
|
"clearstancetorso",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Clears internal torso stance data."
|
|
);
|
|
Event EV_Player_ClearStanceLegs
|
|
(
|
|
"clearstancelegs",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Clears internal legs stance data."
|
|
);
|
|
Event EV_Player_GivePoints
|
|
(
|
|
"givepoints",
|
|
EV_SCRIPTONLY,
|
|
"i",
|
|
"points",
|
|
"Gives the player points (added to current points)"
|
|
);
|
|
Event EV_Player_SetPoints
|
|
(
|
|
"setpoints",
|
|
EV_SCRIPTONLY,
|
|
"i",
|
|
"points",
|
|
"Sets the players number of points."
|
|
);
|
|
Event EV_Player_ChangeCharFadeIn
|
|
(
|
|
"changecharfadein",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Begins the fade in and swaps character."
|
|
);
|
|
Event EV_Player_ClearIncomingMelee
|
|
(
|
|
"clearincomingmelee",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Clears the incoming melee flag."
|
|
);
|
|
Event EV_Player_BendTorso
|
|
(
|
|
"bendtorso",
|
|
EV_DEFAULT,
|
|
"F",
|
|
"multiplier",
|
|
"Sets multiplier for the torso bend angles, defaults to 0.75"
|
|
);
|
|
Event EV_Player_RemovePowerup
|
|
(
|
|
"removepowerup",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Removes the current powerup."
|
|
);
|
|
Event EV_Player_DropRune
|
|
(
|
|
"droprune",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Drops the player's current rune."
|
|
);
|
|
Event EV_Player_SetCanTransferEnergy
|
|
(
|
|
"canTransferEnergy",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Makes the player able to transfer energy from ammo to armor."
|
|
);
|
|
Event EV_Player_SetDoDamageScreenFlash
|
|
(
|
|
"doDamageScreenFlash",
|
|
EV_DEFAULT,
|
|
"B",
|
|
"bool",
|
|
"Makes the screen flash when the player is damaged (or turns it off)."
|
|
);
|
|
Event EV_Player_MeleeDamageStart
|
|
(
|
|
"meleedamagestart",
|
|
EV_DEFAULT,
|
|
"S",
|
|
"hand",
|
|
"Start doing melee damage with the weapon in the specified hand."
|
|
);
|
|
Event EV_Player_MeleeDamageEnd
|
|
(
|
|
"meleedamageend",
|
|
EV_DEFAULT,
|
|
"S",
|
|
"hand",
|
|
"Stop doing melee damage with the weapon in the specified hand."
|
|
);
|
|
Event EV_Player_PointofView
|
|
(
|
|
"pointofview",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Changes the viewpoint of the player, alternates between 1st and 3rd person"
|
|
);
|
|
Event EV_Player_FinishingMove
|
|
(
|
|
"finishingmove",
|
|
EV_TIKIONLY,
|
|
"ssFFFF",
|
|
"state direction coneangle distance enemyyaw chance",
|
|
"Changes the viewpoint of the player, alternates between 1st and 3rd person"
|
|
);
|
|
Event EV_Player_ClearFinishingMove
|
|
(
|
|
"clearfinishingmovelist",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Clears the finishing move list."
|
|
);
|
|
Event EV_Player_DoFinishingMove
|
|
(
|
|
"dofinishingmove",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Fires off the finishing move."
|
|
);
|
|
Event EV_Player_ForceTimeScale
|
|
(
|
|
"forcetimescale",
|
|
EV_DEFAULT,
|
|
"F",
|
|
"timescale",
|
|
"Sets the timescale for the game"
|
|
);
|
|
Event EV_Player_Freeze
|
|
(
|
|
"freeze",
|
|
EV_DEFAULT,
|
|
"B",
|
|
"freeze",
|
|
"Freezes the player until the freeze 0 is called"
|
|
);
|
|
Event EV_Player_Immobilize
|
|
(
|
|
"immobilize",
|
|
EV_DEFAULT,
|
|
"B",
|
|
"immobilize",
|
|
"Immobilizes the player until the immobilize 0 is called (can only look around)"
|
|
);
|
|
Event EV_Player_DoUseEntity
|
|
(
|
|
"douseentity",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Called from the tiki on a frame to use an entity."
|
|
);
|
|
Event EV_Player_DoneUseEntity
|
|
(
|
|
"doneuseentity",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"When the useentity animation is complete"
|
|
);
|
|
Event EV_Player_SetAttackType
|
|
(
|
|
"attacktype",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"attacktype",
|
|
"Sets the attack type of the attack"
|
|
);
|
|
Event EV_Player_NextGameplayAnim
|
|
(
|
|
"nextgameplayanim",
|
|
EV_CODEONLY,
|
|
"s",
|
|
"objname",
|
|
"Increments the gameplay animation index."
|
|
);
|
|
Event EV_Player_SetGameplayAnim
|
|
(
|
|
"setgameplayanim",
|
|
EV_CODEONLY,
|
|
"I",
|
|
"index",
|
|
"Sets the gameplay animation index directly."
|
|
);
|
|
Event EV_Player_DisableUseWeapon
|
|
(
|
|
"disableuseweapon",
|
|
EV_DEFAULT,
|
|
"B",
|
|
"disable",
|
|
"Disables the weapon use"
|
|
);
|
|
Event EV_Player_DisableInventory
|
|
(
|
|
"disableinventory",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"disable",
|
|
"Disables the player's inventory"
|
|
);
|
|
|
|
Event EV_Player_EquipItems
|
|
(
|
|
"equipitems",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Equips active items from the database."
|
|
);
|
|
Event EV_Player_AddRosterTeammate1
|
|
(
|
|
"addrosterteammate1",
|
|
EV_DEFAULT,
|
|
"e",
|
|
"entity",
|
|
"Sets the teammate to roster position 1"
|
|
);
|
|
Event EV_Player_AddRosterTeammate2
|
|
(
|
|
"addrosterteammate2",
|
|
EV_DEFAULT,
|
|
"e",
|
|
"entity",
|
|
"Sets the teammate to roster position 2"
|
|
);
|
|
Event EV_Player_AddRosterTeammate3
|
|
(
|
|
"addrosterteammate3",
|
|
EV_DEFAULT,
|
|
"e",
|
|
"entity",
|
|
"Sets the teammate to roster position 3"
|
|
);
|
|
Event EV_Player_AddRosterTeammate4
|
|
(
|
|
"addrosterteammate4",
|
|
EV_DEFAULT,
|
|
"e",
|
|
"entity",
|
|
"Sets the actor to roster position 4"
|
|
);
|
|
Event EV_Player_RemoveRosterTeammate1
|
|
(
|
|
"removerosterteammate1",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Removed the teammate from roster position 1"
|
|
);
|
|
Event EV_Player_RemoveRosterTeammate2
|
|
(
|
|
"removerosterteammate2",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Removed the teammate from roster position 2"
|
|
);
|
|
Event EV_Player_RemoveRosterTeammate3
|
|
(
|
|
"removerosterteammate3",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Removed the teammate from roster position 3"
|
|
);
|
|
Event EV_Player_RemoveRosterTeammate4
|
|
(
|
|
"removerosterteammate4",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Removed the teammate from roster position 4"
|
|
);
|
|
|
|
Event EV_Player_HudPrint
|
|
(
|
|
"hudPrint",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"string",
|
|
"Prints to the hud."
|
|
);
|
|
Event EV_Player_ClearItemText
|
|
(
|
|
"clearItemText",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Clears the item text."
|
|
);
|
|
Event EV_Player_ValidPlayerModel
|
|
(
|
|
"validPlayerModel",
|
|
EV_TIKIONLY,
|
|
NULL,
|
|
NULL,
|
|
"Specifies that this model is valid for the player."
|
|
);
|
|
Event EV_Player_AddHud
|
|
(
|
|
"addHud",
|
|
EV_SCRIPTONLY,
|
|
"s",
|
|
"hudName",
|
|
"Tells the player to add a hud to his display."
|
|
);
|
|
Event EV_Player_RemoveHud
|
|
(
|
|
"removeHud",
|
|
EV_SCRIPTONLY,
|
|
"s",
|
|
"hudName",
|
|
"Tells the player to remove a hud from his display."
|
|
);
|
|
|
|
Event EV_Player_KillAllDialog
|
|
(
|
|
"killalldialog",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Calls stopdialog on all the actors in the level"
|
|
);
|
|
Event EV_Player_ForceMoveType
|
|
(
|
|
"forceMoveType",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"moveTypeName",
|
|
"Forces the player to use the named move type"
|
|
);
|
|
Event EV_Player_IsOnGround
|
|
(
|
|
"isplayeronground",
|
|
EV_DEFAULT,
|
|
"@f",
|
|
"onground",
|
|
"Checks if the player is on the ground -- returns 1 if true 0 if false"
|
|
);
|
|
Event EV_Player_BackpackAttachOffset
|
|
(
|
|
"backpackAttachOffset",
|
|
EV_DEFAULT,
|
|
"v",
|
|
"offset",
|
|
"Sets the attachment offset for backpacks"
|
|
);
|
|
Event EV_Player_BackpackAttachAngles
|
|
(
|
|
"backpackAttachAngles",
|
|
EV_DEFAULT,
|
|
"v",
|
|
"anglesOffset",
|
|
"Sets the attachment angles offset for backpacks"
|
|
);
|
|
Event EV_Player_FlagAttachOffset
|
|
(
|
|
"flagAttachOffset",
|
|
EV_DEFAULT,
|
|
"v",
|
|
"offset",
|
|
"Sets the attachment offset for flags"
|
|
);
|
|
Event EV_Player_FlagAttachAngles
|
|
(
|
|
"flagAttachAngles",
|
|
EV_DEFAULT,
|
|
"v",
|
|
"anglesOffset",
|
|
"Sets the attachment angles offset for flags"
|
|
);
|
|
Event EV_Player_BackupModel
|
|
(
|
|
"backupModel",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"backupModelName",
|
|
"Sets the name of the model to use as backup if the client doesn't have this one"
|
|
);
|
|
|
|
/*
|
|
==============================================================================
|
|
|
|
PLAYER
|
|
|
|
==============================================================================
|
|
*/
|
|
|
|
CLASS_DECLARATION( Sentient, Player, "player" )
|
|
{
|
|
{ &EV_ClientMove, &Player::ClientThink },
|
|
{ &EV_ClientEndFrame, &Player::EndFrame },
|
|
{ &EV_Vehicle_Enter, &Player::EnterVehicle },
|
|
{ &EV_Vehicle_Exit, &Player::ExitVehicle },
|
|
{ &EV_Player_EndLevel, &Player::EndLevel },
|
|
{ &EV_Player_UseItem, &Player::EventUseItem },
|
|
{ &EV_Player_GiveCheat, &Player::GiveCheat },
|
|
{ &EV_Player_GiveWeaponCheat, &Player::GiveWeaponCheat },
|
|
{ &EV_Player_GiveAllCheat, &Player::GiveAllCheat },
|
|
{ &EV_Player_DevGodCheat, &Player::GodCheat },
|
|
{ &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_Fov, &Player::Fov },
|
|
{ &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_Gib, &Player::GibEvent },
|
|
{ &EV_GotKill, &Player::GotKill },
|
|
{ &EV_Player_TestThread, &Player::TestThread },
|
|
{ &EV_Player_ResetState, &Player::ResetState },
|
|
{ &EV_Player_WhatIs, &Player::WhatIs },
|
|
{ &EV_Player_ActorInfo, &Player::ActorInfo },
|
|
{ &EV_Player_ShowHeuristics, &Player::ShowHeuristics },
|
|
{ &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_Jump, &Player::Jump },
|
|
{ &EV_Sentient_JumpXY, &Player::JumpXY },
|
|
{ &EV_Player_ActivateNewWeapon, &Player::ActivateNewWeapon },
|
|
{ &EV_Player_DeactivateWeapon, &Player::DeactivateWeapon },
|
|
{ &EV_Player_SetHeadTarget, &Player::SetHeadTarget },
|
|
{ &EV_Player_ListInventory, &Player::ListInventoryEvent },
|
|
{ &EV_Player_ClearTarget, &Player::ClearTarget },
|
|
{ &EV_Player_ActivateShield, &Player::ActivateShield },
|
|
{ &EV_Player_DeactivateShield, &Player::DeactivateShield },
|
|
{ &EV_Player_AdjustTorso, &Player::AdjustTorso },
|
|
{ &EV_Player_DualWield, &Player::DualWield },
|
|
{ &EV_Player_UseDualWield, &Player::UseDualWield },
|
|
{ &EV_Player_EvaluateTorsoAnim, &Player::EvaluateTorsoAnim },
|
|
{ &EV_Player_NextPainTime, &Player::NextPainTime },
|
|
{ &EV_Player_Turn, &Player::Turn },
|
|
{ &EV_Player_TurnTowardsEntity, &Player::turnTowardsEntity },
|
|
{ &EV_Player_TurnUpdate, &Player::TurnUpdate },
|
|
{ &EV_Player_TurnLegs, &Player::TurnLegs },
|
|
{ &EV_Player_DontTurnLegs, &Player::DontTurnLegs },
|
|
{ &EV_Player_FinishUseAnim, &Player::FinishUseAnim },
|
|
{ &EV_Sentient_SetMouthAngle, &Player::SetMouthAngle },
|
|
{ &EV_Player_Holster, &Player::HolsterToggle },
|
|
{ &EV_Player_Nightvision, &Player::NightvisionToggle },
|
|
{ &EV_Player_SafeHolster, &Player::Holster },
|
|
{ &EV_Player_StartUseObject, &Player::StartUseObject },
|
|
{ &EV_Player_FinishUseObject, &Player::FinishUseObject },
|
|
{ &EV_Player_WatchActor, &Player::WatchEntity },
|
|
{ &EV_Player_WatchEntity, &Player::WatchEntity },
|
|
{ &EV_Player_StopWatchingEntity, &Player::StopWatchingEntity },
|
|
{ &EV_Player_PutawayWeapon, &Player::PutawayWeapon },
|
|
{ &EV_Player_Weapon, &Player::WeaponCommand },
|
|
{ &EV_Player_Done, &Player::PlayerDone },
|
|
{ &EV_Player_ActivateDualWeapons, &Player::ActivateDualWeapons },
|
|
{ &EV_Player_StartCoolItem, &Player::StartCoolItem },
|
|
{ &EV_Player_StopCoolItem, &Player::StopCoolItem },
|
|
{ &EV_Player_ShowCoolItem, &Player::ShowCoolItem },
|
|
{ &EV_Player_HideCoolItem, &Player::HideCoolItem },
|
|
{ &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_Score, &Player::Score },
|
|
{ &EV_Player_CallVote, &Player::CallVote },
|
|
{ &EV_Player_Vote, &Player::Vote },
|
|
{ &EV_Player_JoinTeam, &Player::joinTeam },
|
|
{ &EV_Player_MultiplayerCommand, &Player::multiplayerCommand },
|
|
{ &EV_Player_DeadBody, &Player::DeadBody },
|
|
{ &EV_Player_SetAimType, &Player::SetAimType },
|
|
{ &EV_Player_ReloadWeapon, &Player::ReloadWeapon },
|
|
{ &EV_Player_AnimateWeapon, &Player::AnimateWeapon },
|
|
{ &EV_Player_SwitchWeaponMode, &Player::SwitchWeaponMode },
|
|
{ &EV_Player_ReloadTiki, &Player::ReloadTiki },
|
|
{ &EV_Player_SetViewAngles, &Player::SetViewAnglesEvent },
|
|
{ &EV_Player_ProjDetonate, &Player::ProjDetonate },
|
|
{ &EV_Player_UseEntity, &Player::UseSpecifiedEntity },
|
|
{ &EV_Player_SetupDialog, &Player::SetupDialog },
|
|
{ &EV_Player_ClearDialog, &Player::ClearDialog },
|
|
{ &EV_Player_ClearTextDialog, &Player::ClearTextDialog },
|
|
{ &EV_Player_LoadObjectives, &Player::LoadObjectives },
|
|
{ &EV_Player_SetObjectiveShow, &Player::SetObjectiveShow },
|
|
{ &EV_Player_SetObjectiveComplete, &Player::SetObjectiveComplete },
|
|
{ &EV_Player_SetObjectiveFailed, &Player::SetObjectiveFailed },
|
|
{ &EV_Player_SetInformationShow, &Player::SetInformationShow },
|
|
{ &EV_Player_MissionFailed, &Player::MissionFailed },
|
|
|
|
{ &EV_Player_SetStat, &Player::SetStat },
|
|
{ &EV_Player_SpecialMoveChargeStart, &Player::SpecialMoveChargeStart },
|
|
{ &EV_Player_SpecialMoveChargeEnd, &Player::SpecialMoveChargeEnd },
|
|
{ &EV_Player_SpecialMoveChargeTime, &Player::SpecialMoveChargeTime },
|
|
{ &EV_Player_ChangeChar, &Player::ChangeChar },
|
|
{ &EV_Player_SetPlayerCharacter, &Player::SetPlayerChar },
|
|
{ &EV_Player_PlayerKnockback, &Player::PlayerKnockback },
|
|
{ &EV_Player_KnockbackMultiplier, &Player::KnockbackMultiplier },
|
|
{ &EV_Player_Melee, &Player::MeleeEvent },
|
|
{ &EV_Player_ChangeStance, &Player::ChangeStance },
|
|
{ &EV_Player_ClearStanceTorso, &Player::ClearStanceTorso },
|
|
{ &EV_Player_ClearStanceLegs, &Player::ClearStanceLegs },
|
|
|
|
{ &EV_Player_MeleeDamageStart, &Player::MeleeDamageStart },
|
|
{ &EV_Player_MeleeDamageEnd, &Player::MeleeDamageEnd },
|
|
{ &EV_Player_GivePoints, &Player::GivePointsEvent },
|
|
{ &EV_Player_SetPoints, &Player::SetPointsEvent },
|
|
{ &EV_Player_ChangeCharFadeIn, &Player::ChangeCharFadeIn },
|
|
{ &EV_Player_ClearIncomingMelee, &Player::ClearIncomingMelee },
|
|
{ &EV_Player_BendTorso, &Player::SetBendTorso },
|
|
{ &EV_Sentient_HeadWatchAllowed, &Player::HeadWatchAllowed },
|
|
|
|
{ &EV_Player_RemovePowerup, &Player::removePowerupEvent },
|
|
{ &EV_Player_DropRune, &Player::dropRune },
|
|
{ &EV_Sentient_AddMeleeAttacker, &Player::AddMeleeAttacker },
|
|
|
|
{ &EV_Player_SetCanTransferEnergy, &Player::setCanTransferEnergy },
|
|
{ &EV_Player_SetDoDamageScreenFlash, &Player::setDoDamageScreenFlash },
|
|
{ &EV_Player_PointofView, &Player::pointOfView },
|
|
{ &EV_Player_FinishingMove, &Player::addFinishingMove },
|
|
{ &EV_Player_ClearFinishingMove, &Player::clearFinishingMove },
|
|
{ &EV_Player_DoFinishingMove, &Player::doFinishingMove },
|
|
{ &EV_Player_ForceTimeScale, &Player::forceTimeScale },
|
|
{ &EV_Player_Freeze, &Player::freezePlayer },
|
|
{ &EV_Player_Immobilize, &Player::immobilizePlayer },
|
|
{ &EV_Player_DoUseEntity, &Player::doUseEntity },
|
|
{ &EV_Player_DoneUseEntity, &Player::doneUseEntity },
|
|
{ &EV_Player_SetAttackType, &Player::setAttackType },
|
|
{ &EV_Player_NextGameplayAnim, &Player::nextGameplayAnim },
|
|
{ &EV_Player_SetGameplayAnim, &Player::setGameplayAnim },
|
|
{ &EV_Player_DisableUseWeapon, &Player::setDisableUseWeapon },
|
|
{ &EV_Player_DisableInventory, &Player::setDisableInventory },
|
|
{ &EV_Player_EquipItems, &Player::equipItems },
|
|
|
|
{ &EV_Use, &Player::usePlayer },
|
|
|
|
{ &EV_Player_AddRosterTeammate1, &Player::addRosterTeammate1 },
|
|
{ &EV_Player_AddRosterTeammate2, &Player::addRosterTeammate2 },
|
|
{ &EV_Player_AddRosterTeammate3, &Player::addRosterTeammate3 },
|
|
{ &EV_Player_AddRosterTeammate4, &Player::addRosterTeammate4 },
|
|
|
|
{ &EV_Player_RemoveRosterTeammate1, &Player::removeRosterTeammate1 },
|
|
{ &EV_Player_RemoveRosterTeammate2, &Player::removeRosterTeammate2 },
|
|
{ &EV_Player_RemoveRosterTeammate3, &Player::removeRosterTeammate3 },
|
|
{ &EV_Player_RemoveRosterTeammate4, &Player::removeRosterTeammate4 },
|
|
|
|
{ &EV_Player_HudPrint, &Player::hudPrint },
|
|
|
|
{ &EV_Player_ClearItemText, &Player::clearItemText },
|
|
|
|
{ &EV_Player_ValidPlayerModel, &Player::setValidPlayerModel },
|
|
|
|
{ &EV_Player_AddHud, &Player::addHud },
|
|
{ &EV_Player_RemoveHud, &Player::removeHud },
|
|
|
|
//Vehicle Event Handoff
|
|
{ &EV_Driver_AnimDone, &Player::PassEventToVehicle },
|
|
|
|
{ &EV_Warp, &Player::warp },
|
|
{ &EV_Player_KillAllDialog, &Player::killAllDialog },
|
|
|
|
{ &EV_Player_ForceMoveType, &Player::forceMoveType },
|
|
{ &EV_Player_IsOnGround, &Player::isPlayerOnGround },
|
|
|
|
{ &EV_Player_BackpackAttachOffset, &Player::setBackpackAttachOffset },
|
|
{ &EV_Player_BackpackAttachAngles, &Player::setBackpackAttachAngles },
|
|
|
|
{ &EV_Player_FlagAttachOffset, &Player::setFlagAttachOffset },
|
|
{ &EV_Player_FlagAttachAngles, &Player::setFlagAttachAngles },
|
|
|
|
{ &EV_Player_BackupModel, &Player::setBackupModel },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
qboolean Player::checkturnleft( Conditional & )
|
|
{
|
|
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 & )
|
|
{
|
|
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 & )
|
|
{
|
|
return last_ucmd.forwardmove > 0;
|
|
}
|
|
|
|
qboolean Player::checkbackward( Conditional & )
|
|
{
|
|
return last_ucmd.forwardmove < 0;
|
|
}
|
|
|
|
qboolean Player::checkstrafeleft( Conditional & )
|
|
{
|
|
return last_ucmd.rightmove < 0;
|
|
}
|
|
|
|
qboolean Player::checkstraferight( Conditional & )
|
|
{
|
|
return last_ucmd.rightmove > 0;
|
|
}
|
|
|
|
qboolean Player::checkleanleft(Conditional &)
|
|
{
|
|
if( client->ps.leanDelta > 0 )
|
|
{
|
|
return qtrue;
|
|
}
|
|
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean Player::checkleanright( Conditional & )
|
|
{
|
|
|
|
if(client->ps.leanDelta < 0)
|
|
{
|
|
return qtrue;
|
|
}
|
|
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean Player::checkduck( Conditional & )
|
|
{
|
|
if ( client->ps.pm_flags & PMF_DUCKED )
|
|
return qtrue;
|
|
else
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean Player::checkrise( Conditional & )
|
|
{
|
|
if ( ( do_rise ) && ( velocity.z > 32.0f ) )
|
|
{
|
|
return qtrue;
|
|
}
|
|
do_rise = qfalse;
|
|
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean Player::checkjump( Conditional & )
|
|
{
|
|
if ( sv_instantjump->integer )
|
|
return client->ps.jumped;
|
|
else
|
|
return last_ucmd.upmove > 0;
|
|
}
|
|
|
|
qboolean Player::checkcrouch( Conditional & )
|
|
{
|
|
if ( last_ucmd.upmove < 0 ) // check for downward movement
|
|
return qtrue;
|
|
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean Player::checkjumpflip( Conditional & )
|
|
{
|
|
return velocity.z < ( sv_currentGravity->value * 0.5f );
|
|
}
|
|
|
|
qboolean Player::checkanimdone_legs( Conditional & )
|
|
{
|
|
if ( ( edict->s.anim & ANIM_BLEND ) == 0 )
|
|
return true;
|
|
|
|
return animdone_Legs;
|
|
}
|
|
|
|
qboolean Player::checkanimdone_torso( Conditional & )
|
|
{
|
|
if ( ( edict->s.torso_anim & ANIM_BLEND ) == 0 )
|
|
return true;
|
|
|
|
return animdone_Torso;
|
|
}
|
|
|
|
qboolean Player::checkattackleft( Conditional & )
|
|
{
|
|
if ( level.playerfrozen || ( flags & FL_IMMOBILE ) )
|
|
{
|
|
return qfalse;
|
|
}
|
|
|
|
if ( multiplayerManager.inMultiplayer() && ( !multiplayerManager.isFightingAllowed() || multiplayerManager.isPlayerSpectator( this ) ) )
|
|
{
|
|
return qfalse;
|
|
}
|
|
|
|
// Make sure we aren't leaning
|
|
|
|
if ( client->ps.leanDelta != 0 )
|
|
return false;
|
|
|
|
if ( last_ucmd.buttons & BUTTON_ATTACKLEFT )
|
|
{
|
|
Weapon *weapon;
|
|
|
|
last_attack_button = BUTTON_ATTACKLEFT;
|
|
|
|
weapon = GetActiveWeapon( WEAPON_LEFT );
|
|
if ( weapon )
|
|
{
|
|
weapon->CheckReload( FIRE_MODE1 );
|
|
return qtrue;
|
|
}
|
|
|
|
weapon = GetActiveWeapon( WEAPON_RIGHT );
|
|
if ( weapon )
|
|
{
|
|
weapon->CheckReload( FIRE_MODE1 );
|
|
return qtrue;
|
|
}
|
|
|
|
weapon = GetActiveWeapon( WEAPON_DUAL );
|
|
if ( weapon )
|
|
{
|
|
weapon->CheckReload( FIRE_MODE1 );
|
|
return qtrue;
|
|
}
|
|
|
|
// No ammo
|
|
return qfalse;
|
|
}
|
|
else
|
|
{
|
|
return qfalse;
|
|
}
|
|
}
|
|
|
|
qboolean Player::checkattackbuttonleft( Conditional & )
|
|
{
|
|
if ( level.playerfrozen || ( flags & FL_IMMOBILE ) )
|
|
{
|
|
return qfalse;
|
|
}
|
|
|
|
if ( multiplayerManager.inMultiplayer() && ( !multiplayerManager.isFightingAllowed() || multiplayerManager.isPlayerSpectator( this ) ) )
|
|
{
|
|
return qfalse;
|
|
}
|
|
else
|
|
{
|
|
return ( last_ucmd.buttons & BUTTON_ATTACKLEFT );
|
|
}
|
|
}
|
|
|
|
qboolean Player::checkattackright( Conditional & )
|
|
{
|
|
Weapon *weapon;
|
|
|
|
if ( level.playerfrozen || ( flags & FL_IMMOBILE ) )
|
|
{
|
|
return qfalse;
|
|
}
|
|
|
|
if ( multiplayerManager.inMultiplayer() && ( !multiplayerManager.isFightingAllowed() || multiplayerManager.isPlayerSpectator( this ) ) )
|
|
{
|
|
return qfalse;
|
|
}
|
|
|
|
// Make sure we aren't leaning
|
|
|
|
if ( client->ps.leanDelta != 0 )
|
|
return false;
|
|
|
|
// If we're in the middle of a reload, we're not done attacking
|
|
/* weapon = GetActiveWeapon( WEAPON_RIGHT );
|
|
if (weapon )
|
|
{
|
|
if ( weapon->weaponstate == WEAPON_RELOADING )
|
|
return true;
|
|
}*/
|
|
|
|
if ( last_ucmd.buttons & BUTTON_ATTACKRIGHT )
|
|
{
|
|
last_attack_button = BUTTON_ATTACKRIGHT;
|
|
|
|
weapon = GetActiveWeapon( WEAPON_RIGHT );
|
|
if ( weapon )
|
|
{
|
|
weapon->CheckReload( FIRE_MODE2 );
|
|
return qtrue;
|
|
}
|
|
|
|
weapon = GetActiveWeapon( WEAPON_LEFT );
|
|
if ( weapon )
|
|
{
|
|
weapon->CheckReload( FIRE_MODE2 );
|
|
return qtrue;
|
|
}
|
|
|
|
weapon = GetActiveWeapon( WEAPON_DUAL );
|
|
if ( weapon )
|
|
{
|
|
weapon->CheckReload( FIRE_MODE2 );
|
|
return qtrue;
|
|
}
|
|
|
|
// No ammo
|
|
return qfalse;
|
|
}
|
|
else
|
|
{
|
|
return qfalse;
|
|
}
|
|
}
|
|
|
|
qboolean Player::checkattackbuttonright( Conditional & )
|
|
{
|
|
if ( level.playerfrozen || ( flags & FL_IMMOBILE ) )
|
|
{
|
|
return qfalse;
|
|
}
|
|
|
|
if ( multiplayerManager.inMultiplayer() && ( !multiplayerManager.isFightingAllowed() || multiplayerManager.isPlayerSpectator( this ) ) )
|
|
{
|
|
return qfalse;
|
|
}
|
|
else
|
|
{
|
|
return ( last_ucmd.buttons & BUTTON_ATTACKRIGHT );
|
|
}
|
|
}
|
|
|
|
qboolean Player::checksneak( Conditional & )
|
|
{
|
|
return qfalse; //( last_ucmd.buttons & BUTTON_SNEAK ) != 0;
|
|
}
|
|
|
|
qboolean Player::checkrun( Conditional & )
|
|
{
|
|
return ( last_ucmd.buttons & BUTTON_RUN ) != 0;
|
|
}
|
|
|
|
qboolean Player::checkwasrunning( Conditional & )
|
|
{
|
|
return ( pm_lastruntime > MINIMUM_RUNNING_TIME );
|
|
}
|
|
|
|
qboolean Player::checkholsterweapon( Conditional & )
|
|
{
|
|
if(client->ps.pm_flags & PMF_DISABLE_INVENTORY || _disableUseWeapon)
|
|
{
|
|
return qfalse;
|
|
}
|
|
|
|
return ( last_ucmd.buttons & BUTTON_HOLSTERWEAPON ) != 0;
|
|
}
|
|
|
|
qboolean Player::checkuse( Conditional & )
|
|
{
|
|
return ( last_ucmd.buttons & BUTTON_USE ) != 0;
|
|
}
|
|
|
|
qboolean Player::checkcanturn( Conditional &condition )
|
|
{
|
|
float yaw;
|
|
Vector oldang( v_angle );
|
|
qboolean result;
|
|
|
|
yaw = (float)atof( condition.getParm( 1 ) );
|
|
|
|
v_angle[ YAW ] = (float)( ( int )( anglemod( v_angle[ YAW ] + yaw ) / 22.5f ) * 22.5f );
|
|
SetViewAngles( v_angle );
|
|
|
|
result = qtrue; //CheckMove( vec_zero );
|
|
|
|
SetViewAngles( oldang );
|
|
|
|
return result;
|
|
}
|
|
|
|
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::checkonground( Conditional & )
|
|
{
|
|
return client->ps.walking;
|
|
}
|
|
|
|
qboolean Player::check22degreeslope( Conditional & )
|
|
{
|
|
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 & )
|
|
{
|
|
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::checkrightleghigh( Conditional & )
|
|
{
|
|
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 & )
|
|
{
|
|
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 & )
|
|
{
|
|
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 & )
|
|
{
|
|
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 & )
|
|
{
|
|
return falling;
|
|
}
|
|
|
|
qboolean Player::checkgroundentity( Conditional & )
|
|
{
|
|
return ( groundentity != NULL );
|
|
}
|
|
|
|
qboolean Player::checkhardimpact( Conditional & )
|
|
{
|
|
return hardimpact;
|
|
}
|
|
|
|
qboolean Player::checkcanfall( Conditional & )
|
|
{
|
|
return canfall;
|
|
}
|
|
|
|
qboolean Player::checkatdoor( Conditional & )
|
|
{
|
|
// Check if the player is at a door
|
|
return ( atobject && atobject->isSubclassOf( Door ) );
|
|
}
|
|
|
|
qboolean Player::checkatuseanim( Conditional & )
|
|
{
|
|
// Check if the player is at a useanim
|
|
if ( atobject && atobject->isSubclassOf( UseAnim ) )
|
|
{
|
|
return ( ( UseAnim * )( Entity * )atobject )->canBeUsed( this );
|
|
}
|
|
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean Player::checktouchuseanim( Conditional & )
|
|
{
|
|
if ( toucheduseanim )
|
|
{
|
|
return ( ( UseAnim * )( Entity * )toucheduseanim )->canBeUsed( this );
|
|
}
|
|
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean Player::checkuseanimfinished( Conditional & )
|
|
{
|
|
return ( useanim_numloops <= 0 );
|
|
}
|
|
|
|
qboolean Player::checkatuseobject( Conditional & )
|
|
{
|
|
// Check if the player is at a useanim
|
|
if ( atobject && atobject->isSubclassOf( UseObject ) )
|
|
{
|
|
return ( ( UseObject * )( Entity * )atobject )->canBeUsed( origin, yaw_forward );
|
|
}
|
|
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean Player::checkloopuseobject( Conditional & )
|
|
{
|
|
// 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 qfalse;
|
|
}
|
|
|
|
qboolean Player::checkdead( Conditional & )
|
|
{
|
|
return ( deadflag );
|
|
}
|
|
|
|
qboolean Player::checkhealth( Conditional &condition )
|
|
{
|
|
return health < atoi( condition.getParm( 1 ) );
|
|
}
|
|
|
|
qboolean Player::checkpain( Conditional & )
|
|
{
|
|
return ( ( pain != 0 ) || ( knockdown != 0 ) );
|
|
}
|
|
|
|
qboolean Player::checkknockdown( Conditional & )
|
|
{
|
|
if ( knockdown )
|
|
{
|
|
knockdown = false;
|
|
return qtrue;
|
|
}
|
|
else
|
|
{
|
|
return qfalse;
|
|
}
|
|
}
|
|
|
|
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::checkaccumulatedpain( Conditional &condition )
|
|
{
|
|
float threshold = (float)atof( condition.getParm( 1 ) );
|
|
|
|
if ( accumulated_pain >= threshold )
|
|
{
|
|
accumulated_pain = 0; // zero out accumulation
|
|
return qtrue;
|
|
}
|
|
else
|
|
{
|
|
return qfalse;
|
|
}
|
|
}
|
|
|
|
qboolean Player::checkpainthreshold( Conditional &condition )
|
|
{
|
|
float threshold = (float)atof( condition.getParm( 1 ) );
|
|
|
|
if ( ( pain >= threshold ) && ( level.time > nextpaintime ) )
|
|
{
|
|
accumulated_pain = 0; // zero out accumulation since we are going into a pain anim right now
|
|
return qtrue;
|
|
}
|
|
else
|
|
{
|
|
return qfalse;
|
|
}
|
|
}
|
|
|
|
qboolean Player::checklegsstate( Conditional &condition )
|
|
{
|
|
if ( currentState_Legs )
|
|
{
|
|
str current = currentState_Legs->getName();
|
|
str compare = condition.getParm( 1 );
|
|
|
|
if ( current == compare )
|
|
{
|
|
return qtrue;
|
|
}
|
|
}
|
|
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean Player::checktorsostate( Conditional &condition )
|
|
{
|
|
if ( currentState_Torso )
|
|
{
|
|
str current = currentState_Torso->getName();
|
|
str compare = condition.getParm( 1 );
|
|
|
|
if ( current == compare )
|
|
{
|
|
return qtrue;
|
|
}
|
|
}
|
|
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean Player::checkhasweapon( Conditional &condition )
|
|
{
|
|
if ( condition.numParms() > 0 )
|
|
{
|
|
weaponhand_t hand = WeaponHandNameToNum( condition.getParm( 1 ) );
|
|
if ( GetActiveWeapon( hand ) )
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
return WeaponsOut();
|
|
}
|
|
|
|
qboolean Player::checkhasdualweapon( Conditional & )
|
|
{
|
|
return IsDualWeaponActive();
|
|
}
|
|
|
|
qboolean Player::checknewweapon( Conditional & )
|
|
{
|
|
Weapon * weapon;
|
|
|
|
weapon = GetNewActiveWeapon();
|
|
|
|
if ( weapon && _disableUseWeapon == false)
|
|
return qtrue;
|
|
else
|
|
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 qfalse;
|
|
|
|
weaponName = condition.getParm( 2 );
|
|
|
|
if (
|
|
( weap != NULL ) &&
|
|
( GetNewActiveWeaponHand() == hand ) &&
|
|
( !stricmp( weap->item_name, weaponName ) )
|
|
)
|
|
{
|
|
return qtrue;
|
|
}
|
|
else
|
|
{
|
|
return qfalse;
|
|
}
|
|
}
|
|
|
|
// 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 qfalse;
|
|
|
|
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_MODE1;
|
|
int numShots = 1;
|
|
|
|
hand = WeaponHandNameToNum( condition.getParm( 1 ) );
|
|
|
|
if ( condition.numParms() > 1 )
|
|
mode = WeaponModeNameToNum( condition.getParm( 2 ) );
|
|
|
|
if ( condition.numParms() > 2 )
|
|
numShots = atoi( condition.getParm( 3 ) );
|
|
|
|
if ( hand == WEAPON_ERROR )
|
|
return qfalse;
|
|
|
|
weap = GetActiveWeapon( hand );
|
|
|
|
if ( !weap )
|
|
return qfalse;
|
|
else
|
|
return ( weap->HasAmmo( mode, numShots ) );
|
|
}
|
|
|
|
qboolean Player::checkweaponhasfullammo( Conditional &condition )
|
|
{
|
|
str ammoName;
|
|
|
|
ammoName = condition.getParm( 1 );
|
|
|
|
if ( AmmoCount( ammoName ) == MaxAmmoCount( ammoName ) )
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
// Checks to see if any weapon is active in the specified hand
|
|
qboolean Player::checkweaponhasinvammo( Conditional &condition )
|
|
{
|
|
weaponhand_t hand;
|
|
Weapon *weap;
|
|
firemode_t mode = FIRE_MODE1;
|
|
|
|
hand = WeaponHandNameToNum( condition.getParm( 1 ) );
|
|
|
|
if ( condition.numParms() > 1 )
|
|
mode = WeaponModeNameToNum( condition.getParm( 2 ) );
|
|
|
|
if ( hand == WEAPON_ERROR )
|
|
return qfalse;
|
|
|
|
weap = GetActiveWeapon( hand );
|
|
|
|
if ( !weap )
|
|
return qfalse;
|
|
else
|
|
return ( weap->HasInvAmmo( mode ) );
|
|
}
|
|
|
|
// 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 qfalse;
|
|
|
|
Weapon *weapon = GetActiveWeapon( hand );
|
|
|
|
return ( weapon && !strcmp( weaponName, weapon->item_name ) );
|
|
}
|
|
|
|
qboolean Player::checkweaponreload( Conditional & )
|
|
{
|
|
Weapon *weapon = GetActiveWeapon( WEAPON_DUAL );
|
|
|
|
if ( weapon )
|
|
if ( weapon->weaponstate == WEAPON_RELOADING )
|
|
return qtrue;
|
|
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean Player::checkweaponswitchmode( Conditional & )
|
|
{
|
|
Weapon *weapon = GetActiveWeapon( WEAPON_DUAL );
|
|
|
|
if ( weapon )
|
|
if ( weapon->weaponstate == WEAPON_SWITCHINGMODE )
|
|
return qtrue;
|
|
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean Player::checkweaponinmode( Conditional &condition )
|
|
{
|
|
Weapon *weapon = GetActiveWeapon( WEAPON_DUAL );
|
|
str mode;
|
|
|
|
if ( weapon )
|
|
{
|
|
if ( condition.numParms() > 0 )
|
|
mode = condition.getParm( 1 );
|
|
if ( weapon->GetCurMode() == WeaponModeNameToNum( mode ) )
|
|
return qtrue;
|
|
else
|
|
return qfalse;
|
|
}
|
|
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean Player::checkweapondonefiring( Conditional & )
|
|
{
|
|
Weapon *weapon = GetActiveWeapon( WEAPON_DUAL );
|
|
|
|
// Weapon there check
|
|
if ( !weapon )
|
|
return qtrue;
|
|
|
|
return weapon->IsDoneFiring();
|
|
}
|
|
|
|
// Checks to see if weapon is active and ready to fire
|
|
qboolean Player::checkweaponreadytofire( Conditional &condition )
|
|
{
|
|
firemode_t mode = FIRE_MODE1;
|
|
str weaponName="None";
|
|
weaponhand_t hand;
|
|
qboolean ready;
|
|
|
|
if ( level.playerfrozen || ( flags & FL_IMMOBILE ) )
|
|
{
|
|
return qfalse;
|
|
}
|
|
|
|
hand = WeaponHandNameToNum( condition.getParm( 1 ) );
|
|
|
|
if ( hand == WEAPON_DUAL )
|
|
{
|
|
gi.DPrintf( "This check should only be used for single handed weapons\n" );
|
|
return qfalse;
|
|
}
|
|
|
|
if ( condition.numParms() > 1 )
|
|
weaponName = condition.getParm( 2 );
|
|
|
|
if ( hand == WEAPON_ERROR )
|
|
return qfalse;
|
|
|
|
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 );
|
|
return( ready );
|
|
}
|
|
|
|
qboolean Player::checkdualweaponreadytofire( Conditional &condition )
|
|
{
|
|
firemode_t mode = FIRE_MODE1;
|
|
str weaponName="None";
|
|
Weapon *weapon = GetActiveWeapon( WEAPON_DUAL );
|
|
qboolean ready;
|
|
|
|
|
|
mode = WeaponModeNameToNum( condition.getParm( 1 ) );
|
|
|
|
if ( condition.numParms() > 1 )
|
|
weaponName = condition.getParm( 2 );
|
|
|
|
// Make sure we aren't leaning
|
|
|
|
if ( client->ps.leanDelta != 0 )
|
|
return false;
|
|
|
|
// 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 );
|
|
|
|
// Fire timer checks
|
|
|
|
if ( !weapon->isModeNoDelay( mode ) )
|
|
{
|
|
if ( weapon->next_fire_time[mode] > level.time )
|
|
return qfalse;
|
|
|
|
if ( weapon->next_fire_time[FIRE_MODE1] > level.time )
|
|
return qfalse;
|
|
|
|
if ( weapon->next_fire_time[FIRE_MODE2] > level.time )
|
|
return qfalse;
|
|
}
|
|
|
|
return( ready );
|
|
}
|
|
|
|
qboolean Player::checkweaponlowered( Conditional & )
|
|
{
|
|
Weapon *weapon = GetActiveWeapon( WEAPON_DUAL );
|
|
|
|
if ( !weapon )
|
|
return true;
|
|
else
|
|
return ( weapon->weaponstate == WEAPON_LOWERING );
|
|
}
|
|
|
|
qboolean Player::checkweaponfiretimer( Conditional &condition )
|
|
{
|
|
firemode_t mode = FIRE_MODE1;
|
|
Weapon *weapon = GetActiveWeapon( WEAPON_DUAL );
|
|
|
|
if ( weapon->GetSwitchMode() )
|
|
mode = weapon->GetCurMode();
|
|
else
|
|
mode = WeaponModeNameToNum( condition.getParm( 1 ) );
|
|
|
|
if ( weapon->GetFireTime(mode) > level.time )
|
|
return qfalse;
|
|
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean Player::checkweaponfullclip( Conditional & )
|
|
{
|
|
Weapon *weapon = GetActiveWeapon( WEAPON_DUAL );
|
|
|
|
if ( !weapon )
|
|
return qtrue;
|
|
|
|
return weapon->HasFullClip();
|
|
}
|
|
|
|
qboolean Player::checkweaponforcereload( Conditional & )
|
|
{
|
|
return ( last_ucmd.buttons & BUTTON_RELOAD ) != 0;
|
|
}
|
|
|
|
qboolean Player::checkweaponcanreload( Conditional & )
|
|
{
|
|
Weapon *weapon = GetActiveWeapon( WEAPON_DUAL );
|
|
|
|
if ( !weapon )
|
|
return qfalse;
|
|
|
|
return weapon->canReload();
|
|
}
|
|
|
|
// Check to see if any of the active weapons need to be put away
|
|
qboolean Player::checkputawayleft( Conditional & )
|
|
{
|
|
Weapon *weapon = GetActiveWeapon( WEAPON_LEFT );
|
|
|
|
return weapon && weapon->GetPutaway();
|
|
}
|
|
|
|
qboolean Player::checkputawayright( Conditional & )
|
|
{
|
|
Weapon *weapon = GetActiveWeapon( WEAPON_RIGHT );
|
|
|
|
return weapon && weapon->GetPutaway();
|
|
}
|
|
|
|
qboolean Player::checkputawayboth( Conditional & )
|
|
{
|
|
Weapon *weapon = GetActiveWeapon( WEAPON_DUAL );
|
|
|
|
return weapon && weapon->GetPutaway();
|
|
}
|
|
|
|
qboolean Player::checktargetacquired( Conditional & )
|
|
{
|
|
return (targetEnemy != NULL);
|
|
}
|
|
|
|
qboolean Player::returntrue( Conditional & )
|
|
{
|
|
return qtrue;
|
|
}
|
|
|
|
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 qfalse;
|
|
}
|
|
|
|
qboolean Player::checkattackblocked( Conditional & )
|
|
{
|
|
if ( attack_blocked )
|
|
{
|
|
attack_blocked = false;
|
|
return qtrue;
|
|
}
|
|
else
|
|
{
|
|
return qfalse;
|
|
}
|
|
}
|
|
|
|
qboolean Player::checkblockdelay( Conditional &condition )
|
|
{
|
|
float t = (float)atof ( condition.getParm( 1 ) );
|
|
return ( level.time > ( attack_blocked_time + t ) );
|
|
}
|
|
|
|
qboolean Player::checkpush( Conditional & )
|
|
{
|
|
// 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 & )
|
|
{
|
|
// 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;
|
|
}
|
|
|
|
qboolean Player::checkcharavailable( Conditional &condition )
|
|
{
|
|
str character = condition.getParm( 1 );
|
|
Actor *act = Actor::FindActorByName(character.c_str());
|
|
if ( act )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
qboolean Player::checkOnLadder( Conditional & )
|
|
{
|
|
return _onLadder;
|
|
}
|
|
|
|
qboolean Player::checkcanstand( Conditional & )
|
|
{
|
|
Vector newmins( mins );
|
|
Vector newmaxs( maxs );
|
|
Vector tmporg( origin );
|
|
trace_t trace;
|
|
|
|
// Start the trace alittle higher than the origin, for some
|
|
// reason crouching causes the trace to start allsolid if you're
|
|
// on a slope
|
|
tmporg[ 2 ] += 2.0f;
|
|
newmins[ 2 ] = MINS_Z;
|
|
newmaxs[ 2 ] = MAXS_Z;
|
|
|
|
trace = G_Trace( tmporg, newmins, newmaxs, tmporg, this, edict->clipmask, true, "checkcanstand" );
|
|
if ( trace.startsolid )
|
|
{
|
|
return qfalse;
|
|
}
|
|
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean Player::checkdualwield( Conditional & )
|
|
{
|
|
// Only start the dual wield state if dual wield is set and the hands have no weapons
|
|
|
|
return ( dual_wield_active );
|
|
}
|
|
|
|
qboolean Player::checkdualweapons( Conditional &condition )
|
|
{
|
|
int i,j;
|
|
|
|
for ( i=1; i<=condition.numParms(); i++ )
|
|
{
|
|
str weaponName;
|
|
weaponName = condition.getParm( i );
|
|
|
|
for ( j=1; j<=dual_wield_weaponlist.NumObjects(); j++ )
|
|
{
|
|
WeaponSetItem *dw;
|
|
dw = dual_wield_weaponlist.ObjectAt( j );
|
|
|
|
if ( dw->name == weaponName )
|
|
{
|
|
goto out;
|
|
}
|
|
}
|
|
return qfalse;
|
|
out:
|
|
;
|
|
}
|
|
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean Player::checkchance( Conditional &condition )
|
|
{
|
|
float percent_chance;
|
|
|
|
percent_chance = (float)atof( condition.getParm( 1 ) );
|
|
|
|
return ( G_Random() < percent_chance );
|
|
}
|
|
|
|
qboolean Player::checkturnedleft( Conditional & )
|
|
{
|
|
return yawing_left;
|
|
}
|
|
|
|
qboolean Player::checkturnedright( Conditional & )
|
|
{
|
|
return yawing_right;
|
|
}
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name: checkinvehicle
|
|
// Class: Player
|
|
//
|
|
// Description: Checks if the vehicle is in specific type of vehicle
|
|
//
|
|
// Parameters: condition - the condition that contains the vehicle type
|
|
//
|
|
// Returns:
|
|
//-----------------------------------------------------
|
|
qboolean Player::checkinvehicle( Conditional &condition )
|
|
{
|
|
|
|
if(vehicle == NULL || vehicle->getArchetype() != condition.getParm(1))
|
|
return qfalse;
|
|
|
|
return qtrue;
|
|
|
|
}
|
|
|
|
qboolean Player::checksolidforward( Conditional &condition )
|
|
{
|
|
// Trace out forward to see if there is a solid ahead
|
|
float dist = (float)atof( condition.getParm( 1 ) );
|
|
Vector end( centroid + ( yaw_forward * dist ) );
|
|
|
|
trace_t trace = G_Trace( centroid, Vector( mins.x, mins.y, -8.0f ), Vector( maxs.x, maxs.y, 8.0f ),
|
|
end, this, MASK_SOLID, true, "Player::checksolidforward" );
|
|
|
|
return ( trace.fraction < 0.7f );
|
|
}
|
|
|
|
qboolean Player::checkweaponsholstered( Conditional & )
|
|
{
|
|
|
|
if (
|
|
( holsteredWeapons[WEAPON_DUAL] ) ||
|
|
( holsteredWeapons[WEAPON_LEFT] ) ||
|
|
( holsteredWeapons[WEAPON_RIGHT] )
|
|
)
|
|
{
|
|
return qtrue;
|
|
}
|
|
else
|
|
{
|
|
return qfalse;
|
|
}
|
|
}
|
|
|
|
qboolean Player::checkfakeplayeractive( Conditional & )
|
|
{
|
|
return fakePlayer_active;
|
|
}
|
|
|
|
qboolean Player::checkspecialmovecharge( Conditional & )
|
|
{
|
|
if ( specialMoveCharge >= specialMoveEndTime )
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
qboolean Player::checkstancechangedtorso( Conditional & )
|
|
{
|
|
return changedStanceTorso;
|
|
}
|
|
|
|
qboolean Player::checkstancechangedlegs( Conditional & )
|
|
{
|
|
return changedStanceLegs;
|
|
}
|
|
|
|
qboolean Player::checkstance( Conditional &condition )
|
|
{
|
|
int stancenum;
|
|
stancenum = (int)atoi( condition.getParm( 1 ) );
|
|
|
|
if ( stancenum == stanceNumber )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
qboolean Player::checkpoints( Conditional &condition )
|
|
{
|
|
int pointnum;
|
|
pointnum = (int)atoi( condition.getParm( 1 ) );
|
|
|
|
if ( points >= pointnum )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
qboolean Player::checkincomingmeleeattack( Conditional & )
|
|
{
|
|
return incomingMeleeAttack;
|
|
}
|
|
|
|
|
|
qboolean Player::checkfinishingmove( Conditional & )
|
|
{
|
|
if ( _finishActor )
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: checkatuseentity
|
|
// Class: Player
|
|
//
|
|
// Description: Conditional to see if the player is standing at a usable entity
|
|
//
|
|
// Parameters: Conditional &condition
|
|
//
|
|
// Returns: qboolean
|
|
//
|
|
//--------------------------------------------------------------
|
|
qboolean Player::checkatuseentity(Conditional &)
|
|
{
|
|
// Check if the player is at a useentity
|
|
if ( atobject )
|
|
{
|
|
Entity *ent = (Entity*)atobject;
|
|
if ( ent->hasUseData() )
|
|
return qtrue;
|
|
}
|
|
|
|
return qfalse;
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: checkusingentity
|
|
// Class: Player
|
|
//
|
|
// Description: Conditional to see if the player is in the middle
|
|
// of using an entity.
|
|
//
|
|
// Parameters: Conditional &condition
|
|
//
|
|
// Returns: qboolean
|
|
//
|
|
//--------------------------------------------------------------
|
|
qboolean Player::checkusingentity(Conditional &)
|
|
{
|
|
return _usingEntity;
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: checkthirdperson
|
|
// Class: Player
|
|
//
|
|
// Description: Conditional to see if the player is in third person
|
|
//
|
|
// Parameters: Conditional &condition
|
|
//
|
|
// Returns: qboolean
|
|
//
|
|
//--------------------------------------------------------------
|
|
qboolean Player::checkthirdperson(Conditional &)
|
|
{
|
|
return _isThirdPerson;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: checkPropChance
|
|
// Class: Player
|
|
//
|
|
// Description: Check the chance based on the property passed.
|
|
// This property should be located in the Actor's
|
|
// StateData object in the gameplay database.
|
|
//
|
|
// Parameters: Conditional &conditional
|
|
//
|
|
// Returns: qboolean
|
|
//
|
|
//--------------------------------------------------------------
|
|
qboolean Player::checkPropChance( Conditional &condition )
|
|
{
|
|
str propname;
|
|
str objname = condition.getParm( 1 );
|
|
if ( condition.numParms() > 1 )
|
|
propname = condition.getParm( 2 );
|
|
|
|
GameplayManager *gpm = GameplayManager::getTheGameplayManager();
|
|
str scopestr = getArchetype() + "." + objname;
|
|
if ( !gpm->hasObject(scopestr) )
|
|
return false;
|
|
|
|
float chance;
|
|
if ( propname.length() )
|
|
chance = gpm->getFloatValue(scopestr, propname);
|
|
else
|
|
chance = gpm->getFloatValue(scopestr, "value");
|
|
|
|
return ( G_Random() <= chance );
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: checkPropExists
|
|
// Class: Player
|
|
//
|
|
// Description: Check to see if the property exists
|
|
// The Actor's StateData object will be asked
|
|
// if it has the property.
|
|
//
|
|
// Parameters: Conditional &conditional
|
|
//
|
|
// Returns: qboolean
|
|
//
|
|
//--------------------------------------------------------------
|
|
qboolean Player::checkPropExists( Conditional &condition )
|
|
{
|
|
str objname = condition.getParm( 1 );
|
|
str propname = condition.getParm( 2 );
|
|
GameplayManager *gpm = GameplayManager::getTheGameplayManager();
|
|
str scopestr = getArchetype() + "." + objname;
|
|
if ( !gpm->hasProperty(scopestr, propname) )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: checkEndAnimChain
|
|
// Class: Player
|
|
//
|
|
// Description: Check to see if the current animation chain is on
|
|
// the last anim.
|
|
//
|
|
// Parameters: Conditional &conditional
|
|
//
|
|
// Returns: qboolean
|
|
//
|
|
//--------------------------------------------------------------
|
|
qboolean Player::checkEndAnimChain( Conditional &condition )
|
|
{
|
|
if ( condition.numParms() < 1 )
|
|
return false;
|
|
|
|
str objname = condition.getParm( 1 );
|
|
GameplayManager *gpm = GameplayManager::getTheGameplayManager();
|
|
str scopestr = "CurrentPlayer.ChainedMoves";
|
|
if ( !gpm->hasObject(scopestr) )
|
|
return false;
|
|
|
|
int max = (int)gpm->getFloatValue(scopestr, "value");
|
|
max++; // Increment to compensate for 0 based skill system, we always have to play the first anim
|
|
if ( _gameplayAnimIdx > max )
|
|
return false; // Loop anim
|
|
|
|
if ( _gameplayAnimIdx == max )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
qboolean Player::checkWeaponType( Conditional &condition )
|
|
{
|
|
if ( condition.numParms() < 1 )
|
|
return false;
|
|
|
|
str type = condition.getParm( 1 );
|
|
GameplayManager *gpm = GameplayManager::getTheGameplayManager();
|
|
Weapon* weap = GetActiveWeapon(WEAPON_RIGHT);
|
|
if ( !weap )
|
|
weap = GetActiveWeapon(WEAPON_LEFT);
|
|
if ( !weap )
|
|
return false;
|
|
|
|
if ( !gpm->hasObject(weap->getArchetype()) )
|
|
return false;
|
|
|
|
str weaptype = gpm->getStringValue(weap->getArchetype(), "class");
|
|
if ( weaptype == type )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
qboolean Player::checkHasAnim( Conditional &condition )
|
|
{
|
|
str animName;
|
|
|
|
if ( condition.numParms() < 1 )
|
|
return false;
|
|
|
|
animName = condition.getParm( 1 );
|
|
|
|
if ( gi.Anim_NumForName( edict->s.modelindex, animName.c_str() ) < 0 )
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
qboolean Player::checkIsWeaponControllingProjectile( Conditional & )
|
|
{
|
|
Weapon *weapon;
|
|
|
|
// Only support dual handed weapon for now
|
|
|
|
weapon = GetActiveWeapon( WEAPON_DUAL );
|
|
|
|
if ( weapon )
|
|
{
|
|
if ( weapon->getControllingProjectile() )
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
Condition<Player> Player::Conditions[] =
|
|
{
|
|
{ "default", &Player::returntrue },
|
|
{ "SNEAK", &Player::checksneak },
|
|
{ "RUN", &Player::checkrun },
|
|
{ "WAS_RUNNING", &Player::checkwasrunning },
|
|
{ "HOLSTERWEAPON", &Player::checkholsterweapon },
|
|
{ "USE", &Player::checkuse },
|
|
{ "LEFT", &Player::checkturnleft },
|
|
{ "RIGHT", &Player::checkturnright },
|
|
{ "FORWARD", &Player::checkforward },
|
|
{ "BACKWARD", &Player::checkbackward },
|
|
{ "STRAFE_LEFT", &Player::checkstrafeleft },
|
|
{ "STRAFE_RIGHT", &Player::checkstraferight },
|
|
{ "LEAN_LEFT", &Player::checkleanleft },
|
|
{ "LEAN_RIGHT", &Player::checkleanright},
|
|
{ "DUCK", &Player::checkduck },
|
|
{ "JUMP", &Player::checkjump },
|
|
{ "RISE", &Player::checkrise },
|
|
{ "CROUCH", &Player::checkcrouch },
|
|
{ "ANIMDONE_LEGS", &Player::checkanimdone_legs },
|
|
{ "ANIMDONE_TORSO", &Player::checkanimdone_torso },
|
|
{ "CAN_TURN", &Player::checkcanturn },
|
|
{ "BLOCKED", &Player::checkblocked },
|
|
{ "ONGROUND", &Player::checkonground },
|
|
{ "CAN_FALL", &Player::checkcanfall },
|
|
{ "AT_DOOR", &Player::checkatdoor },
|
|
{ "FALLING", &Player::checkfalling },
|
|
{ "HARD_IMPACT", &Player::checkhardimpact },
|
|
{ "KILLED", &Player::checkdead },
|
|
{ "HEALTH", &Player::checkhealth },
|
|
{ "PAIN", &Player::checkpain },
|
|
{ "PAIN_TYPE", &Player::checkpaintype },
|
|
{ "PAIN_DIRECTION", &Player::checkpaindirection },
|
|
{ "PAIN_THRESHOLD", &Player::checkpainthreshold },
|
|
{ "PAIN_ACCUMULATED", &Player::checkaccumulatedpain },
|
|
{ "KNOCKDOWN", &Player::checkknockdown },
|
|
{ "LEGS", &Player::checklegsstate },
|
|
{ "TORSO", &Player::checktorsostate },
|
|
{ "AT_USEANIM", &Player::checkatuseanim },
|
|
{ "TOUCHEDUSEANIM", &Player::checktouchuseanim },
|
|
{ "FINISHEDUSEANIM", &Player::checkuseanimfinished },
|
|
{ "AT_USEOBJECT", &Player::checkatuseobject },
|
|
{ "AT_USEENTITY", &Player::checkatuseentity },
|
|
{ "LOOP_USEOBJECT", &Player::checkloopuseobject },
|
|
{ "CAN_PUSH", &Player::checkpush },
|
|
{ "CAN_PULL", &Player::checkpull },
|
|
{ "ON_LADDER", &Player::checkOnLadder },
|
|
{ "CAN_STAND", &Player::checkcanstand },
|
|
{ "CHANCE", &Player::checkchance },
|
|
{ "TURNED_LEFT", &Player::checkturnedleft },
|
|
{ "TURNED_RIGHT", &Player::checkturnedright },
|
|
{ "IN_VEHICLE", &Player::checkinvehicle },
|
|
// { "WATER_LEVEL", checkwaterlevel },
|
|
{ "SOLID_FORWARD", &Player::checksolidforward },
|
|
{ "GROUNDENTITY", &Player::checkgroundentity },
|
|
{ "FAKEPLAYERACTIVE", &Player::checkfakeplayeractive },
|
|
{ "SLOPE_22", &Player::check22degreeslope },
|
|
{ "SLOPE_45", &Player::check45degreeslope },
|
|
{ "RIGHT_LEG_HIGH", &Player::checkrightleghigh },
|
|
{ "LEFT_LEG_HIGH", &Player::checkleftleghigh },
|
|
{ "FACING_UP_SLOPE", &Player::checkfacingupslope },
|
|
{ "FACING_DOWN_SLOPE", &Player::checkfacingdownslope },
|
|
|
|
// Weapon conditions
|
|
{ "ATTACKLEFT", &Player::checkattackleft }, // Checks to see if there is an active weapon as well as the button being pressed
|
|
{ "ATTACKRIGHT", &Player::checkattackright }, // Checks to see if there is an active weapon as well as the button being pressed
|
|
{ "ATTACKLEFTBUTTON", &Player::checkattackbuttonleft }, // Checks to see if the left attack button is pressed
|
|
{ "ATTACKRIGHTBUTTON", &Player::checkattackbuttonright },// Checks to see if the right attack button is pressed
|
|
{ "HAS_DUAL_WEAPON", &Player::checkhasdualweapon},
|
|
{ "HAS_WEAPON", &Player::checkhasweapon },
|
|
{ "NEW_WEAPON", &Player::checknewweapon },
|
|
{ "IS_NEW_WEAPON", &Player::checkuseweapon },
|
|
{ "IS_WEAPON_ACTIVE", &Player::checkweaponactive },
|
|
{ "IS_WEAPON_RELOADING", &Player::checkweaponreload },
|
|
{ "IS_IN_MODE", &Player::checkweaponinmode },
|
|
{ "IS_WEAPON_SWITCHINGMODE", &Player::checkweaponswitchmode },
|
|
{ "IS_WEAPON_READY_TO_FIRE", &Player::checkweaponreadytofire },
|
|
{ "IS_DUALWEAPON_READY_TO_FIRE", &Player::checkdualweaponreadytofire },
|
|
{ "IS_WEAPON_FINISHED_FIRING", &Player::checkweapondonefiring },
|
|
{ "PUTAWAYBOTH", &Player::checkputawayboth },
|
|
{ "PUTAWAYLEFT", &Player::checkputawayleft },
|
|
{ "PUTAWAYRIGHT", &Player::checkputawayright },
|
|
{ "TARGET_ACQUIRED", &Player::checktargetacquired },
|
|
{ "ANY_WEAPON_ACTIVE", &Player::checkanyweaponactive },
|
|
{ "ATTACK_BLOCKED", &Player::checkattackblocked },
|
|
{ "STATE_ACTIVE", &Player::checkstatename },
|
|
{ "BLOCK_DELAY", &Player::checkblockdelay },
|
|
{ "DUALWIELD", &Player::checkdualwield },
|
|
{ "DUALWIELDWEAPONS", &Player::checkdualweapons },
|
|
{ "HAS_AMMO", &Player::checkweaponhasammo },
|
|
{ "HAS_FULLAMMO", &Player::checkweaponhasfullammo },
|
|
{ "HAS_INVAMMO", &Player::checkweaponhasinvammo },
|
|
{ "WEAPONS_HOLSTERED", &Player::checkweaponsholstered },
|
|
{ "WEAPON_LOWERED", &Player::checkweaponlowered }, // See if we're done with our putaway anim
|
|
{ "WEAPON_FIRETIMER", &Player::checkweaponfiretimer },
|
|
{ "WEAPON_FORCERELOAD", &Player::checkweaponforcereload },
|
|
{ "WEAPON_CAN_RELOAD", &Player::checkweaponcanreload },
|
|
{ "WEAPON_FULLCLIP", &Player::checkweaponfullclip },
|
|
{ "IS_SPECIALMOVE_CHARGED", &Player::checkspecialmovecharge },
|
|
{ "IS_CHAR_AVAILABLE", &Player::checkcharavailable },
|
|
|
|
{ "STANCE_CHANGEDTORSO", &Player::checkstancechangedtorso },
|
|
{ "STANCE_CHANGEDLEGS", &Player::checkstancechangedlegs },
|
|
{ "STANCE", &Player::checkstance },
|
|
{ "POINTS", &Player::checkpoints },
|
|
{ "INCOMING_MELEE", &Player::checkincomingmeleeattack },
|
|
{ "FINISHINGMOVE", &Player::checkfinishingmove },
|
|
{ "USINGENTITY", &Player::checkusingentity },
|
|
{ "IS_THIRDPERSON", &Player::checkthirdperson },
|
|
{ "PROP_CHANCE", &Player::checkPropChance },
|
|
{ "PROP_EXISTS", &Player::checkPropExists },
|
|
{ "ANIMCHAIN_END", &Player::checkEndAnimChain },
|
|
{ "WEAPON_TYPE", &Player::checkWeaponType },
|
|
{ "HAS_ANIM", &Player::checkHasAnim },
|
|
{ "IS_WEAPON_CONTROLLING_PROJECTILE", &Player::checkIsWeaponControllingProjectile },
|
|
|
|
{ NULL, NULL },
|
|
};
|
|
|
|
movecontrolfunc_t Player::MoveStartFuncs[] =
|
|
{
|
|
NULL, // MOVECONTROL_USER, // Quake style
|
|
NULL, // MOVECONTROL_LEGS, // 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
|
|
NULL, // MOVECONTROL_WALLHUG
|
|
NULL, // MOVECONTROL_MONKEYBARS
|
|
NULL, // MOVECONTROL_PIPECRAWL
|
|
NULL, // MOVECONTROL_PIPEHANG
|
|
NULL, // MOVECONTROL_STEPUP
|
|
NULL, // MOVECONTROL_ROPE_GRAB
|
|
NULL, // MOVECONTROL_ROPE_RELEASE
|
|
NULL, // MOVECONTROL_ROPE_MOVE
|
|
NULL, // MOVECONTORL_PICKUPENEMY
|
|
&Player::StartPush, // MOVECONTROL_PUSH
|
|
NULL, // MOVECONTORL_CLIMBWALL
|
|
&Player::StartUseAnim, // MOVECONTROL_USEANIM
|
|
NULL, // MOVECONTROL_CROUCH
|
|
&Player::StartLoopUseAnim, // MOVECONTROL_LOOPUSEANIM
|
|
&Player::SetupUseObject, // MOVECONTROL_USEOBJECT
|
|
&Player::StartCoolItemAnim, // MOVECONTROL_COOLOBJECT
|
|
&Player::StartFakePlayer // MOVECONTROL_FAKEPLAYER
|
|
};
|
|
|
|
Player::Player()
|
|
{
|
|
//
|
|
// set the entity type
|
|
//
|
|
edict->s.eType = ET_PLAYER;
|
|
respawn_time = -1;
|
|
statemap_Legs = NULL;
|
|
statemap_Torso = NULL;
|
|
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;
|
|
last_attack_button = 0;
|
|
attack_blocked = false;
|
|
shield_active = false;
|
|
canfall = false;
|
|
moveresult = MOVERESULT_NONE;
|
|
animspeed = 0;
|
|
airspeed = 350;
|
|
vehicle = NULL;
|
|
action_level = 0;
|
|
adjust_torso = false;
|
|
dual_wield_active = false;
|
|
cool_item = NULL;
|
|
weapons_holstered_by_code = false;
|
|
actor_camera = NULL;
|
|
cool_camera = NULL;
|
|
|
|
_started = false;
|
|
|
|
StopWatchingEntity();
|
|
playerCameraMode = PLAYER_CAMERA_MODE_NORMAL;
|
|
|
|
damage_multiplier = 1;
|
|
take_pain = true;
|
|
look_at_time = 0;
|
|
fakePlayer_active = false;
|
|
projdetonate = false;
|
|
|
|
_flashMaxTime = 0.0f;
|
|
_flashMinTime = 0.0f;
|
|
|
|
dont_turn_legs = false;
|
|
|
|
specialMoveChargeTime = 3.0f;
|
|
specialMoveCharge = 0.0f;
|
|
specialMoveEndTime = 0.0f;
|
|
playerKnockback = 0.0f;
|
|
knockbackMultiplier = 1.0f;
|
|
changedStanceTorso = false;
|
|
changedStanceLegs = false;
|
|
incomingMeleeAttack = false;
|
|
stanceNumber = 1;
|
|
points = 0;
|
|
bendTorsoMult = standardTorsoMult;
|
|
meleeAttackFlags = 0;
|
|
changingChar = false;
|
|
_isThirdPerson = true; // This will get set later
|
|
_finishActor = 0;
|
|
_finishState = "";
|
|
_doingFinishingMove = false;
|
|
_usingEntity = false;
|
|
_attackType = "";
|
|
_gameplayAnimIdx = 1;
|
|
_disableUseWeapon = false;
|
|
_infoHudOn = false;
|
|
_nextRegenTime = 0;
|
|
_useEntityStartTimer = 0.0f;
|
|
|
|
#ifdef DEDICATED
|
|
p_heuristics = 0;
|
|
#else
|
|
p_heuristics = new PlayerHeuristics;
|
|
#endif
|
|
|
|
currentCallVolume = "";
|
|
|
|
//Add the player to the teammates list
|
|
//Probably should be a better way to do this.
|
|
TeamMateList.AddObject( this );
|
|
|
|
// make sure that we are not overflowing the stats for players
|
|
assert( STAT_LAST_STAT <= MAX_STATS );
|
|
|
|
/* fov = (float)atof( Info_ValueForKey( client->pers.userinfo, "fov" ) );
|
|
if ( fov < 1.0f )
|
|
{
|
|
fov = sv_defaultFov->value;
|
|
}
|
|
else if ( fov > 160.0f )
|
|
{
|
|
fov = 160.0f;
|
|
} */
|
|
|
|
fov = sv_defaultFov->value;
|
|
//_userFovChoice = fov;
|
|
|
|
if ( atoi( Info_ValueForKey( client->pers.userinfo, "mp_autoSwitchWeapons" ) ) )
|
|
_autoSwitchWeapons = true;
|
|
else
|
|
_autoSwitchWeapons = false;
|
|
|
|
//
|
|
// set targetnameplayer
|
|
//
|
|
if ( !LoadingSavegame )
|
|
SetTargetName( "player" );
|
|
|
|
_powerup = NULL;
|
|
_rune = NULL;
|
|
_holdableItem = NULL;
|
|
|
|
if ( !LoadingSavegame )
|
|
{
|
|
GameplayManager *gpm = GameplayManager::getTheGameplayManager();
|
|
|
|
const str selectedHighlight( "target_selected_highlight" );
|
|
if ( gpm->isDefined( selectedHighlight ) )
|
|
{
|
|
const str targetSelectedHighlightModelName( gpm->getDefine( selectedHighlight ) );
|
|
_targetSelectedHighlight = new Entity;
|
|
_targetSelectedHighlight->setModel( targetSelectedHighlightModelName );
|
|
_targetSelectedHighlight->setSolidType( SOLID_NOT );
|
|
_targetSelectedHighlight->setMoveType( MOVETYPE_NONE );
|
|
_targetSelectedHighlight->takedamage = DAMAGE_NO;
|
|
_targetSelectedHighlight->hideModel();
|
|
}
|
|
|
|
const str lockedHighlight( "target_locked_highlight" );
|
|
if ( gpm->isDefined( lockedHighlight ) )
|
|
{
|
|
const str targetLockedHighlightModelName( gpm->getDefine( lockedHighlight ) );
|
|
_targetLockedHighlight = new Entity;
|
|
_targetLockedHighlight->setModel( targetLockedHighlightModelName );
|
|
_targetLockedHighlight->setSolidType( SOLID_NOT );
|
|
_targetLockedHighlight->setMoveType( MOVETYPE_NONE );
|
|
_targetLockedHighlight->takedamage = DAMAGE_NO;
|
|
_targetLockedHighlight->hideModel();
|
|
}
|
|
}
|
|
|
|
Init();
|
|
|
|
_viewMode = 0;
|
|
|
|
addAffectingViewModes( gi.GetViewModeClassMask( "player" ) );
|
|
|
|
_canTransferEnergy = false;
|
|
|
|
_doDamageScreenFlash = false;
|
|
|
|
Vector maxs(MAXS_X,MAXS_Y,MAXS_Z),mins(MINS_X,MINS_Y,MINS_Z);
|
|
|
|
setSize( mins, maxs );
|
|
|
|
// Setup ladder stuff
|
|
|
|
_onLadder = false;
|
|
_nextLadderTime = 0.0f;
|
|
_ladderTop = 0.0f;
|
|
|
|
_objectiveStates = 0;
|
|
_informationStates = 0;
|
|
_objectiveNameIndex = 0;
|
|
|
|
_lastDamagedTimeFront = 0.0f;
|
|
_lastDamagedTimeBack = 0.0f;
|
|
_lastDamagedTimeLeft = 0.0f;
|
|
_lastDamagedTimeRight = 0.0f;
|
|
|
|
_totalGameFrames = 0;
|
|
_updateGameFrames = true;
|
|
|
|
_nextPainShaderTime = 0.0f;
|
|
_lastPainShaderMod = MOD_NONE;
|
|
|
|
_validPlayerModel = false;
|
|
|
|
_secretsFound = 0;
|
|
|
|
_allowActionMusic = true;
|
|
|
|
setSkill( skill->integer );
|
|
|
|
_needToSendBranchDialog = false;
|
|
_branchDialogActor = NULL;
|
|
}
|
|
|
|
Player::~Player()
|
|
{
|
|
if ( p_heuristics )
|
|
{
|
|
p_heuristics->SaveHeuristics( this );
|
|
delete p_heuristics;
|
|
}
|
|
|
|
Sentient *player;
|
|
player = this;
|
|
|
|
if ( TeamMateList.ObjectInList( player ) )
|
|
TeamMateList.RemoveObject( player );
|
|
|
|
if ( edict->svflags & SVF_BOT )
|
|
{
|
|
BotAIShutdownClient( entnum, qfalse );
|
|
}
|
|
|
|
edict->s.modelindex = 0;
|
|
|
|
freeConditionals( legs_conditionals );
|
|
freeConditionals( torso_conditionals );
|
|
|
|
removePowerup();
|
|
removeRune();
|
|
removeHoldableItem();
|
|
|
|
clearFinishingMove(NULL);
|
|
|
|
if ( multiplayerManager.inMultiplayer() )
|
|
{
|
|
multiplayerManager.removePlayer( this );
|
|
}
|
|
}
|
|
|
|
static qboolean logfile_started = false;
|
|
|
|
void Player::Init( void )
|
|
{
|
|
|
|
InitClient();
|
|
InitPhysics();
|
|
InitWorldEffects();
|
|
InitSound();
|
|
InitView();
|
|
InitState();
|
|
InitEdict();
|
|
InitModel();
|
|
InitWeapons();
|
|
InitInventory();
|
|
InitHealth();
|
|
//InitArmorValue();
|
|
InitStats();
|
|
|
|
_dialogEntnum = ENTITYNUM_NONE;
|
|
_dialogSoundIndex = -1;
|
|
_dialogTextSoundIndex = -1;
|
|
|
|
client->ps.objectiveNameIndex = -1;
|
|
|
|
edict->s.clientNum = client->ps.clientNum ;
|
|
|
|
LoadStateTable();
|
|
|
|
logfile_started = false;
|
|
|
|
removePowerup();
|
|
removeRune();
|
|
removeHoldableItem();
|
|
|
|
_nextEnergyTransferTime = 0.0f;
|
|
_nextPainShaderTime = 0.0f;
|
|
|
|
edict->s.renderfx &= ~RF_FORCE_ALPHA;
|
|
|
|
setAlpha( 1.0f );
|
|
|
|
if ( multiplayerManager.inMultiplayer() )
|
|
{
|
|
multiplayerManager.addPlayer( this );
|
|
}
|
|
else
|
|
{
|
|
if ( !LoadingSavegame )
|
|
{
|
|
ChooseSpawnPoint();
|
|
}
|
|
}
|
|
|
|
clearAllHuds();
|
|
|
|
|
|
_backpackAttachOffset = Vector( -12, -9, 0 );
|
|
_backpackAttachAngles = Vector( 0, 90, 90 );
|
|
|
|
_flagAttachOffset = Vector( -96, -16, 0 );
|
|
_flagAttachAngles = Vector( 0, 90, 90 );
|
|
|
|
_cameraCutThisFrame = false;
|
|
|
|
//Clear out deaththread
|
|
|
|
|
|
// Make sure we put the player back into the world
|
|
|
|
link();
|
|
}
|
|
|
|
void Player::InitEdict( void )
|
|
{
|
|
// entity state stuff
|
|
setSolidType( SOLID_BBOX );
|
|
setMoveType( MOVETYPE_WALK );
|
|
setSize( Vector( MINS_X, MINS_Y, 0.0f ), Vector( MAXS_X, MAXS_Y, MAXS_Z ) );
|
|
edict->clipmask = MASK_PLAYERSOLID;
|
|
edict->svflags &= ~SVF_DEADMONSTER;
|
|
edict->svflags &= ~SVF_HIDEOWNER;
|
|
edict->ownerNum = ENTITYNUM_NONE;
|
|
|
|
// clear entity state values
|
|
edict->s.eFlags = 0;
|
|
edict->s.frame = 0;
|
|
|
|
// players have precise shadows
|
|
edict->s.renderfx |= RF_SHADOW_PRECISE;
|
|
}
|
|
|
|
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.0f;
|
|
client->ps.music_volume_fade_time = 0.0f;
|
|
|
|
_allowMusicDucking = true;
|
|
client->ps.allowMusicDucking = true;
|
|
|
|
ChangeMusicVolume( 1.0f, 0.0f );
|
|
|
|
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 )
|
|
{
|
|
// deathmatch wipes most client data every spawn
|
|
if ( multiplayerManager.inMultiplayer() )
|
|
{
|
|
float savedTime;
|
|
char userinfo[ MAX_INFO_STRING ];
|
|
//char savedTeamName[ 16 ];
|
|
|
|
savedTime = client->pers.enterTime;
|
|
//strcpy( savedTeamName, client->pers.lastTeam );
|
|
|
|
memcpy( userinfo, client->pers.userinfo, sizeof( userinfo ) );
|
|
G_InitClientPersistant( client );
|
|
G_ClientUserinfoChanged( edict, userinfo );
|
|
|
|
//strcpy( client->pers.lastTeam, savedTeamName );
|
|
client->pers.enterTime = savedTime;
|
|
}
|
|
|
|
// save things that should be saved before memset-ing the client
|
|
// during loadgame, ps.stats is loaded before this point, so don't trample that data
|
|
int savedstats[ sizeof( client->ps.stats ) ]; // only a few hundred bytes
|
|
assert( sizeof( savedstats ) < 2048 ); // should be allocated if it gets too big
|
|
|
|
memcpy( savedstats, client->ps.stats, sizeof( client->ps.stats ) );
|
|
client_persistant_t savedpers = client->pers;
|
|
|
|
memset( client, 0, sizeof( *client ) );
|
|
|
|
client->pers = savedpers;
|
|
memcpy( client->ps.stats, savedstats, sizeof( client->ps.stats ) );
|
|
|
|
client->ps.clientNum = client - game.clients;
|
|
client->ps.vehicleoffset[0] = 0;
|
|
client->ps.vehicleoffset[1] = 0;
|
|
client->ps.vehicleoffset[2] = 0;
|
|
client->ps.in_vehicle = false;
|
|
|
|
client->ps.viewheight = (int) sv_defaultviewheight->value;
|
|
client->ps.pm_defaultviewheight = (int) sv_defaultviewheight->value;
|
|
}
|
|
|
|
void Player::InitState( void )
|
|
{
|
|
gibbed = false;
|
|
pain = 0;
|
|
accumulated_pain = 0;
|
|
nextpaintime = 0.0f;
|
|
knockdown = false;
|
|
pain_dir = PAIN_NONE;
|
|
pain_type = MOD_NONE;
|
|
takedamage = DAMAGE_AIM;
|
|
deadflag = DEAD_NO;
|
|
flags &= ~FL_NO_KNOCKBACK;
|
|
flags |= ( FL_BLOOD | FL_DIE_GIBS );
|
|
|
|
if ( !com_blood->integer )
|
|
{
|
|
flags &= ~FL_BLOOD;
|
|
flags &= ~FL_DIE_GIBS;
|
|
}
|
|
}
|
|
|
|
/*
|
|
void Player::InitArmorValue
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
//ArmorValue = 0;
|
|
}
|
|
*/
|
|
|
|
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( const char *modelName )
|
|
{
|
|
orientation_t orient;
|
|
int anim;
|
|
int tagnum;
|
|
int i;
|
|
|
|
|
|
// Reset all surface to visible
|
|
|
|
for ( i = 0 ; i < MAX_MODEL_SURFACES ; i++ )
|
|
{
|
|
edict->s.surfaces[ i ] &= ~MDL_SURFACE_NODRAW;
|
|
}
|
|
|
|
if ( modelName )
|
|
setModel( modelName );
|
|
else
|
|
setModel( str( g_playermodel->string ) + ".tik" );
|
|
|
|
SetControllerTag( HEAD_TAG, gi.Tag_NumForName( edict->s.modelindex, "Bip01 Head" ) );
|
|
SetControllerTag( TORSO_TAG, gi.Tag_NumForName( edict->s.modelindex, "Bip01 Spine1" ) );
|
|
SetControllerTag( R_ARM_TAG, gi.Tag_NumForName( edict->s.modelindex, R_ARM_NAME ) );
|
|
SetControllerTag( L_ARM_TAG, gi.Tag_NumForName( edict->s.modelindex, L_ARM_NAME ) );
|
|
SetControllerTag( MOUTH_TAG, gi.Tag_NumForName( edict->s.modelindex, "tag_mouth" ) );
|
|
|
|
anim = gi.Anim_NumForName( edict->s.modelindex, "stand_idle" );
|
|
|
|
tagnum = gi.Tag_NumForName( edict->s.modelindex, "Bip01 R Foot" ) & TAG_MASK;
|
|
orient = gi.Tag_Orientation( edict->s.modelindex, anim, 0, tagnum, 1.0f, NULL, NULL );
|
|
base_rightfoot_pos = orient.origin;
|
|
base_rightfoot_pos.z = 0;
|
|
|
|
tagnum = gi.Tag_NumForName( edict->s.modelindex, "Bip01 L Foot" ) & TAG_MASK;
|
|
orient = gi.Tag_Orientation( edict->s.modelindex, anim, 0, tagnum, 1.0f, NULL, NULL );
|
|
base_leftfoot_pos = orient.origin;
|
|
base_leftfoot_pos.z = 0;
|
|
|
|
showModel();
|
|
|
|
yawing_left = false;
|
|
yawing_right = false;
|
|
}
|
|
|
|
void Player::InitPhysics( void )
|
|
{
|
|
// Physics stuff
|
|
oldvelocity = vec_zero;
|
|
velocity = vec_zero;
|
|
old_v_angle = v_angle;
|
|
gravity = 1.0;
|
|
falling = false;
|
|
hardimpact = false;
|
|
mass = 200;
|
|
setContents( CONTENTS_BODY );
|
|
memset( &last_ucmd, 0, sizeof( last_ucmd ) );
|
|
|
|
_forcedMoveType = PM_NONE;
|
|
}
|
|
|
|
void Player::InitWorldEffects( void )
|
|
{
|
|
// world effects
|
|
next_drown_time = 0;
|
|
next_painsound_time = 0;
|
|
air_finished = level.time + 20.0f;
|
|
old_waterlevel = 0;
|
|
drown_damage = 0.0f;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
ClearNewActiveWeapon();
|
|
}
|
|
|
|
void Player::InitInventory( void )
|
|
{
|
|
}
|
|
|
|
void Player::InitView( void )
|
|
{
|
|
// view stuff
|
|
camera = NULL;
|
|
v_angle = vec_zero;
|
|
SetViewAngles( v_angle );
|
|
viewheight = STAND_EYE_HEIGHT;
|
|
|
|
head_target = NULL;
|
|
targetEnemy = NULL;
|
|
targetEnemyLocked = false;
|
|
_targetedEntity = NULL;
|
|
|
|
// blend stuff
|
|
damage_blend = vec_zero;
|
|
}
|
|
|
|
void Player::InitStats( void )
|
|
{
|
|
if ( p_heuristics )
|
|
{
|
|
p_heuristics->LoadHeuristics();
|
|
p_heuristics->ClearLevelStatistics();
|
|
}
|
|
}
|
|
|
|
void Player::ChooseSpawnPoint( void )
|
|
{
|
|
str thread;
|
|
// set up the player's spawn location
|
|
SelectSpawnPoint( origin, angles, thread );
|
|
setOrigin( origin + Vector( "0 0 1" ) );
|
|
origin.copyTo( edict->s.origin2 );
|
|
edict->s.renderfx |= RF_FRAMELERP;
|
|
|
|
KillBox( this );
|
|
|
|
setAngles( angles );
|
|
SetViewAngles( angles );
|
|
|
|
if ( thread.length() )
|
|
{
|
|
ExecuteThread( thread );
|
|
}
|
|
}
|
|
|
|
void Player::EndLevel( Event * )
|
|
{
|
|
// this happens here to avoid the last frame (displayed while loading) from being fullbright or whatever
|
|
setViewMode( "none" );
|
|
|
|
if ( health > max_health )
|
|
{
|
|
health = max_health;
|
|
}
|
|
|
|
if ( health < 1.0f )
|
|
{
|
|
health = 1.0f;
|
|
}
|
|
|
|
_updateGameFrames = false;
|
|
}
|
|
|
|
void Player::LevelCleanup( void )
|
|
{
|
|
// Do any re-initialization things that affect visuals that aren't supposed to be visible to player
|
|
// reset stats that aren't supposed to carry across missions, i.e. only between sublevels
|
|
// should only be called in single player
|
|
|
|
if( !gi.areSublevels( level.mapname, level.nextmap ) && client )
|
|
{
|
|
client->ps.stats[ STAT_ENEMIES_KILLED ] = 0;
|
|
client->ps.stats[ STAT_TEAMMATES_KILLED ] = 0;
|
|
client->ps.stats[ STAT_SHOTS_FIRED ] = 0;
|
|
client->ps.stats[ STAT_SHOTS_HIT ] = 0;
|
|
client->ps.stats[ STAT_MISSION_DURATION ] =0;
|
|
}
|
|
|
|
client->ps.pm_flags &= ~PMF_NIGHTVISION;
|
|
}
|
|
|
|
void Player::Respawn( Event * )
|
|
{
|
|
if ( multiplayerManager.inMultiplayer() )
|
|
{
|
|
assert ( deadflag == DEAD_DEAD );
|
|
|
|
respawn_time = level.time;
|
|
|
|
Init();
|
|
|
|
// hold in place briefly
|
|
client->ps.pm_time = 50;
|
|
client->ps.pm_flags |= PMF_TIME_TELEPORT;
|
|
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
#ifdef PRE_RELEASE_DEMO
|
|
gi.SendConsoleCommand( "forcemenu demomain; forcemenu loadsave\n" );
|
|
#else
|
|
// gi.SendConsoleCommand( "forcemenu main; forcemenu loadsave\n" );
|
|
#endif
|
|
logfile_started = false;
|
|
}
|
|
}
|
|
|
|
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::Dead( Event * )
|
|
{
|
|
|
|
CancelEventsOfType( EV_Player_Dead );
|
|
|
|
animate->StopAnimatingAtEnd();
|
|
|
|
if ( edict->s.torso_anim & ANIM_BLEND )
|
|
animate->StopAnimatingAtEnd(torso);
|
|
|
|
//if ( ( pain_type == MOD_VAPORIZE || pain_type == MOD_VAPORIZE_COMP || pain_type == MOD_VAPORIZE_DISRUPTOR ) && ( edict->s.eFlags | EF_EFFECT_PHASER ) && ( edict->s.alpha > 0.0f ) )
|
|
if ( ( ( pain_type == MOD_VAPORIZE ) || ( pain_type == MOD_VAPORIZE_COMP ) ||
|
|
( pain_type == MOD_VAPORIZE_DISRUPTOR ) || ( pain_type == MOD_VAPORIZE_PHOTON ) || ( pain_type == MOD_SNIPER ) ) &&
|
|
( edict->s.alpha > 0.0f ) && ( level.time < respawn_time ) )
|
|
{
|
|
PostEvent( EV_Player_Dead, FRAMETIME );
|
|
return;
|
|
}
|
|
|
|
deadflag = DEAD_DEAD;
|
|
|
|
// stop animating
|
|
//animate->StopAnimating( legs );
|
|
|
|
// increase player's death count
|
|
if ( p_heuristics )
|
|
p_heuristics->IncrementNumberOfDeaths();
|
|
++client->ps.stats[ STAT_DEATHS ];
|
|
|
|
// Heuristics Stay Persistant Regardless of deaths.
|
|
if ( p_heuristics )
|
|
p_heuristics->SaveHeuristics( this );
|
|
|
|
if ( multiplayerManager.inMultiplayer() )
|
|
{
|
|
multiplayerManager.playerDead( this );
|
|
}
|
|
else
|
|
{
|
|
//pick random player killed string.
|
|
int i = (rand() % 10) + 1;
|
|
str playerKilled = "PlayerKilled";
|
|
playerKilled += i;
|
|
G_MissionFailed(playerKilled);
|
|
}
|
|
|
|
_updateGameFrames = false;
|
|
}
|
|
|
|
void Player::Killed( Event *ev )
|
|
{
|
|
Entity *attacker;
|
|
Entity *inflictor;
|
|
int meansofdeath;
|
|
Vector direction;
|
|
|
|
attacker = ev->GetEntity( 1 );
|
|
inflictor = ev->GetEntity( 3 );
|
|
meansofdeath = ev->GetInteger( 4 );
|
|
direction = ev->GetVector( 7 );
|
|
|
|
pain_type = (meansOfDeath_t)meansofdeath;
|
|
|
|
damage_from = direction;
|
|
|
|
if ( multiplayerManager.inMultiplayer() )
|
|
{
|
|
if ( attacker && attacker->isSubclassOf( Player ) )
|
|
multiplayerManager.playerKilled( this, (Player *)attacker, inflictor, meansofdeath );
|
|
else
|
|
multiplayerManager.playerKilled( this, NULL, inflictor, meansofdeath );
|
|
}
|
|
|
|
SpawnDamageEffect( (meansOfDeath_t)meansofdeath );
|
|
|
|
animate->ClearTorsoAnim();
|
|
animate->ClearLegsAnim();
|
|
|
|
deadflag = DEAD_DYING;
|
|
|
|
respawn_time = level.time + 1.0f;
|
|
|
|
edict->clipmask = MASK_DEADSOLID;
|
|
edict->svflags |= SVF_DEADMONSTER;
|
|
|
|
setContents( CONTENTS_CORPSE );
|
|
|
|
setMoveType( MOVETYPE_NONE );
|
|
|
|
angles.x = 0;
|
|
angles.z = 0;
|
|
setAngles( angles );
|
|
|
|
//
|
|
// change music
|
|
//
|
|
ChangeMusic( "failure", "normal", true );
|
|
|
|
health = 0;
|
|
|
|
// Stop targeting monsters
|
|
if( _targetedEntity != NULL)
|
|
{
|
|
_targetedEntity->edict->s.eFlags &= ~EF_DISPLAY_INFO;
|
|
_targetedEntity = NULL;
|
|
}
|
|
|
|
// Post a dead event just in case
|
|
PostEvent( EV_Player_Dead, 5.0f );
|
|
|
|
dropRune();
|
|
dropPowerup();
|
|
removeHoldableItem();
|
|
|
|
// In Deathmatch drop your weapon
|
|
|
|
if ( multiplayerManager.inMultiplayer() && !multiplayerManager.checkFlag( MP_FLAG_NO_DROP_WEAPONS ) &&
|
|
multiplayerManager.checkRule( "dropWeapons", true ) )
|
|
{
|
|
int i;
|
|
for ( i=0; i<MAX_ACTIVE_WEAPONS; i++ )
|
|
{
|
|
Weapon *weap = activeWeaponList[i];
|
|
|
|
if ( weap )
|
|
{
|
|
weap->Drop();
|
|
activeWeaponList[i] = NULL;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
ClearNewActiveWeapon();
|
|
|
|
// Now take away the rest of the weapons
|
|
FreeInventory();
|
|
|
|
|
|
_updateGameFrames = false;
|
|
}
|
|
|
|
void Player::Pain( Event *ev )
|
|
{
|
|
float damage,yawdiff;
|
|
Entity *attacker;
|
|
int meansofdeath;
|
|
Vector dir,pos,attack_angle;
|
|
|
|
damage = ev->GetFloat( 1 );
|
|
attacker = ev->GetEntity( 2 );
|
|
meansofdeath = ev->GetInteger( 3 );
|
|
pos = ev->GetVector( 4 );
|
|
dir = ev->GetVector( 5 );
|
|
|
|
if ( !damage && !knockdown )
|
|
return;
|
|
|
|
client->ps.stats[ STAT_LAST_PAIN ] = (int) damage;
|
|
|
|
// Determine direction
|
|
attack_angle = dir.toAngles();
|
|
yawdiff = torsoAngles[YAW] - attack_angle[YAW] + 180.0f;
|
|
yawdiff = AngleNormalize180( yawdiff );
|
|
|
|
if ( ( yawdiff > -45.0f ) && ( yawdiff < 45.0f ) )
|
|
pain_dir = PAIN_FRONT;
|
|
else if ( ( yawdiff < -45.0f ) && ( yawdiff > -135.0f ) )
|
|
pain_dir = PAIN_LEFT;
|
|
else if ( ( yawdiff > 45.0f ) && ( yawdiff < 135.0f ) )
|
|
pain_dir = PAIN_RIGHT;
|
|
else
|
|
pain_dir = PAIN_REAR;
|
|
|
|
// accumulate pain for animation purposes
|
|
if ( take_pain )
|
|
{
|
|
accumulated_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;
|
|
|
|
// Only set the regular pain level if enough time since last pain has passed
|
|
if ( ( level.time > nextpaintime ) && take_pain )
|
|
{
|
|
pain = damage;
|
|
}
|
|
|
|
if ( ( level.time > next_painsound_time ) && ( health > 0.0f ) )
|
|
{
|
|
if ( G_GetDatabaseFloat( "MOD", MOD_NumToName( meansofdeath ), "DoPainSound" ) )
|
|
{
|
|
next_painsound_time = level.time + 0.25f + G_Random( 0.25f );
|
|
Sound( "snd_pain", CHAN_VOICE, DEFAULT_VOL, 300.0f );
|
|
}
|
|
}
|
|
|
|
// 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;
|
|
|
|
if ( deadflag == DEAD_NO )
|
|
{
|
|
if ( meansofdeath == MOD_DEATH_QUAD )
|
|
damage_from = vec_zero;
|
|
else
|
|
damage_from = ev->GetVector( 5 ) * damage;
|
|
}
|
|
|
|
|
|
if ( meansofdeath == MOD_FIRE || meansofdeath == MOD_ON_FIRE )
|
|
damage_blend = damageFireColor;
|
|
else
|
|
damage_blend = damageNormalColor;
|
|
|
|
// Determine which side was hit
|
|
|
|
if ( damage_from == vec_zero )
|
|
{
|
|
_lastDamagedTimeFront = level.time;
|
|
_lastDamagedTimeLeft = level.time;
|
|
_lastDamagedTimeRight = level.time;
|
|
_lastDamagedTimeBack = level.time;
|
|
}
|
|
else
|
|
{
|
|
Vector damageAngles;
|
|
float yaw;
|
|
|
|
damageAngles = damage_from * -1.0f;
|
|
damageAngles = damageAngles.toAngles();
|
|
|
|
yaw = AngleNormalize180( AngleNormalize180( damageAngles[ YAW ] ) - AngleNormalize180( v_angle[ YAW ] ) );
|
|
|
|
if ( ( yaw >= -45.0f ) && ( yaw <= 45.0f ) )
|
|
_lastDamagedTimeFront = level.time;
|
|
else if ( ( yaw > 45.0f ) && ( yaw < 135.0f ) )
|
|
_lastDamagedTimeLeft = level.time;
|
|
else if ( ( yaw < -45.0f ) && ( yaw > -135.0f ) )
|
|
_lastDamagedTimeRight = level.time;
|
|
else
|
|
_lastDamagedTimeBack = level.time;
|
|
}
|
|
}
|
|
|
|
void Player::DoUse( Event *ev )
|
|
{
|
|
int i;
|
|
int num;
|
|
int touch[ MAX_GENTITIES ];
|
|
gentity_t *hit;
|
|
Event *event;
|
|
Vector min;
|
|
Vector max;
|
|
Vector offset;
|
|
trace_t trace;
|
|
Vector start;
|
|
Vector end;
|
|
float t;
|
|
Entity *usingEntity;
|
|
bool entityActuallyUsed;
|
|
Entity *bestActor;
|
|
|
|
|
|
if ( multiplayerManager.inMultiplayer() && multiplayerManager.isPlayerSpectator( this ) )
|
|
return;
|
|
|
|
if ( ev->NumArgs() > 0 )
|
|
usingEntity = ev->GetEntity( 1 );
|
|
else
|
|
usingEntity = this;
|
|
|
|
// if we are in a vehicle, we want to use the vehicle always
|
|
if ( vehicle )
|
|
{
|
|
event = new Event( EV_Use );
|
|
event->AddEntity( this );
|
|
vehicle->ProcessEvent( event );
|
|
return;
|
|
}
|
|
|
|
start = origin;
|
|
start.z += client->ps.viewheight;
|
|
end = start + ( yaw_forward * 64.0f );
|
|
|
|
trace = G_Trace( start, vec_zero, vec_zero, end, this, MASK_USABLE, true, "Player::DoUse" );
|
|
|
|
t = 64.0f * trace.fraction - maxs[ 0 ];
|
|
if ( t < 0.0f )
|
|
{
|
|
t = 0.0f;
|
|
}
|
|
|
|
offset = yaw_forward * t;
|
|
|
|
min = start + offset + Vector( "-31 -31 -31" );
|
|
max = start + offset + Vector( "31 31 31" );
|
|
|
|
num = gi.AreaEntities( min, max, touch, MAX_GENTITIES, qfalse );
|
|
|
|
entityActuallyUsed = false;
|
|
|
|
bestActor = getBestActorToUse( touch, num );
|
|
|
|
// be careful, it is possible to have an entity in this
|
|
// list removed before we get to it (killtriggered)
|
|
for( i = 0; i < num; i++ )
|
|
{
|
|
hit = &g_entities[ touch[ i ] ];
|
|
if ( !hit->inuse )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( usingEntity == hit->entity )
|
|
continue;
|
|
|
|
if ( hit->entity->isSubclassOf( Actor ) && ( hit->entity != bestActor ) )
|
|
continue;
|
|
|
|
assert( hit->entity );
|
|
|
|
event = new Event( EV_Use );
|
|
event->AddEntity( usingEntity );
|
|
hit->entity->ProcessEvent( event );
|
|
|
|
if ( hit->entity->isSubclassOf( Weapon ) )
|
|
continue;
|
|
|
|
if ( hit->entity->isSubclassOf( Projectile ) )
|
|
continue;
|
|
|
|
if ( hit->entity->getSolidType() == SOLID_NOT )
|
|
continue;
|
|
|
|
entityActuallyUsed = true;
|
|
}
|
|
|
|
// If we didn't use any object in the world, use our holdable item (if any)
|
|
|
|
if ( !entityActuallyUsed )
|
|
useHoldableItem();
|
|
}
|
|
|
|
Actor *Player::getBestActorToUse( int *entityList, int count )
|
|
{
|
|
int i;
|
|
float bestYawDiff = 1000.0f;
|
|
float yawDiff;
|
|
Actor *bestActor = NULL;
|
|
Actor *currentActor;
|
|
gentity_t *edict;
|
|
Vector dir;
|
|
Vector angles;
|
|
|
|
for ( i = 0 ; i < count ; i++ )
|
|
{
|
|
edict = &g_entities[ entityList[ i ] ];
|
|
|
|
if ( !edict->inuse || !edict->entity || !edict->entity->isSubclassOf( Actor ) )
|
|
continue;
|
|
|
|
currentActor = (Actor *)edict->entity;
|
|
|
|
dir = currentActor->centroid - centroid;
|
|
dir.normalize();
|
|
angles = dir.toAngles();
|
|
|
|
yawDiff = AngleNormalize180( AngleNormalize180( v_angle[ YAW ] ) - AngleNormalize180( angles[ YAW ] ) );
|
|
yawDiff = abs( (int)yawDiff );
|
|
|
|
if ( yawDiff < bestYawDiff )
|
|
{
|
|
bestYawDiff = yawDiff;
|
|
bestActor = currentActor;
|
|
}
|
|
}
|
|
|
|
return bestActor;
|
|
}
|
|
|
|
void Player::TouchStuff( const pmove_t *pm )
|
|
{
|
|
gentity_t *other;
|
|
Event *event;
|
|
int i;
|
|
int j;
|
|
|
|
//
|
|
// clear out any conditionals that are controlled by touching
|
|
//
|
|
toucheduseanim = NULL;
|
|
|
|
if ( GetMovePlayerMoveType() != PM_NOCLIP )
|
|
{
|
|
// See if we should touch all triggers or just teleporters
|
|
|
|
if ( multiplayerManager.inMultiplayer() && multiplayerManager.isPlayerSpectator( this ) )
|
|
G_TouchTeleporters( this );
|
|
else
|
|
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 );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name: disableInventory
|
|
// Class: Player
|
|
//
|
|
// Description: Disables the player's inventory
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: None
|
|
//-----------------------------------------------------
|
|
void Player::disableInventory( void )
|
|
{
|
|
client->ps.pm_flags |= PMF_DISABLE_INVENTORY;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name: enableInventory
|
|
// Class: Player
|
|
//
|
|
// Description: Enables the players inventory
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: None
|
|
//-----------------------------------------------------
|
|
void Player::enableInventory( void )
|
|
{
|
|
client->ps.pm_flags &= ~PMF_DISABLE_INVENTORY;
|
|
}
|
|
|
|
usercmd_t Player::GetLastUcmd(void)
|
|
{
|
|
return last_ucmd;
|
|
}
|
|
|
|
void Player::GetMoveInfo( pmove_t *pm )
|
|
{
|
|
moveresult = pm->moveresult;
|
|
|
|
if ( !deadflag || ( multiplayerManager.inMultiplayer() && multiplayerManager.isPlayerSpectator( this ) ) )
|
|
{
|
|
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 ] ) );
|
|
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
|
|
{
|
|
if ( !vehicle )
|
|
setSize( pm->mins, pm->maxs );
|
|
else
|
|
setSize( vehicle->_DriverBBoxMins , vehicle->_DriverBBoxMaxs );
|
|
}
|
|
|
|
// water type and level is set in the predicted code
|
|
waterlevel = pm->waterlevel;
|
|
watertype = pm->watertype;
|
|
|
|
// Set the ground entity
|
|
groundentity = NULL;
|
|
if ( pm->ps->groundEntityNum != ENTITYNUM_NONE )
|
|
{
|
|
groundentity = &g_entities[ pm->ps->groundEntityNum ];
|
|
airspeed = 350;
|
|
}
|
|
}
|
|
|
|
void Player::SetMoveInfo( pmove_t *pm, const usercmd_t *ucmd )
|
|
{
|
|
Vector move;
|
|
|
|
//float test;
|
|
//test = velocity[0];
|
|
//test = velocity[1];
|
|
//test = velocity[2];
|
|
// 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->tracemask = edict->clipmask;
|
|
pm->trace = gi.trace;
|
|
pm->pointcontents = gi.pointcontents;
|
|
pm->trypush = TryPush;
|
|
|
|
pm->ps->origin[ 0 ] = origin.x;
|
|
pm->ps->origin[ 1 ] = origin.y;
|
|
pm->ps->origin[ 2 ] = origin.z;
|
|
|
|
pm->ps->velocity[ 0 ] = velocity.x;
|
|
pm->ps->velocity[ 1 ] = velocity.y;
|
|
pm->ps->velocity[ 2 ] = velocity.z;
|
|
|
|
// save off pm_runtime
|
|
if ( pm->ps->pm_runtime )
|
|
pm_lastruntime = pm->ps->pm_runtime;
|
|
}
|
|
|
|
pmtype_t Player::GetMovePlayerMoveType( void )
|
|
{
|
|
if ( multiplayerManager.isPlayerSpectator( this, SPECTATOR_TYPE_FOLLOW ) )
|
|
{
|
|
return PM_SPECTATOR_FOLLOW;
|
|
}
|
|
else if ( multiplayerManager.isPlayerSpectator( this, SPECTATOR_TYPE_FREEFORM ) )
|
|
{
|
|
return PM_NOCLIP;
|
|
}
|
|
else if ( multiplayerManager.isPlayerSpectator( this ) )
|
|
{
|
|
return PM_SPECTATOR;
|
|
}
|
|
else if ( getMoveType() == MOVETYPE_NOCLIP )
|
|
{
|
|
return PM_NOCLIP;
|
|
}
|
|
else if ( deadflag )
|
|
{
|
|
return PM_DEAD;
|
|
}
|
|
else if ( _forcedMoveType != PM_NONE )
|
|
{
|
|
return _forcedMoveType;
|
|
}
|
|
else
|
|
{
|
|
return PM_NORMAL;
|
|
}
|
|
}
|
|
|
|
void Player::CheckGround( void )
|
|
{
|
|
pmove_t pm;
|
|
|
|
SetMoveInfo( &pm, current_ucmd );
|
|
Pmove_GroundTrace( &pm );
|
|
GetMoveInfo( &pm );
|
|
}
|
|
|
|
qboolean Player::AnimMove( const Vector &move, Vector *endpos )
|
|
{
|
|
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 )
|
|
{
|
|
return TestMove( move, endpos );
|
|
}
|
|
else
|
|
{
|
|
if ( endpos )
|
|
{
|
|
*endpos = trace.endpos;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
qboolean Player::TestMove( const Vector &move, Vector *endpos )
|
|
{
|
|
trace_t trace;
|
|
Vector pos( origin + move );
|
|
|
|
trace = G_Trace( origin, mins, maxs, pos, this, edict->clipmask, true, "TestMove" );
|
|
if ( trace.allsolid )
|
|
{
|
|
// player is completely trapped in another solid
|
|
if ( endpos )
|
|
{
|
|
*endpos = origin;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if ( trace.fraction < 1.0f )
|
|
{
|
|
Vector up( origin );
|
|
up.z += STEPSIZE;
|
|
|
|
trace = G_Trace( origin, mins, maxs, up, this, edict->clipmask, true, "TestMove" );
|
|
if ( trace.fraction == 0.0f )
|
|
{
|
|
if ( endpos )
|
|
{
|
|
*endpos = origin;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
Vector temp( trace.endpos );
|
|
Vector end( temp + move );
|
|
|
|
trace = G_Trace( temp, mins, maxs, end, this, edict->clipmask, true, "TestMove" );
|
|
if ( trace.fraction == 0.0f )
|
|
{
|
|
if ( endpos )
|
|
{
|
|
*endpos = origin;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
temp = trace.endpos;
|
|
|
|
Vector down( trace.endpos );
|
|
down.z = origin.z;
|
|
|
|
trace = G_Trace( temp, mins, maxs, down, this, edict->clipmask, true, "TestMove" );
|
|
}
|
|
|
|
if ( endpos )
|
|
{
|
|
*endpos = trace.endpos;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: showObjectInfo
|
|
// Class: Player
|
|
//
|
|
// Description: This build the string to be displayed when
|
|
// the sv_showinfo cvar is set.
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: None
|
|
//
|
|
//--------------------------------------------------------------
|
|
void Player::showObjectInfo()
|
|
{
|
|
str desc;
|
|
char addstr[512];
|
|
|
|
Entity *ent = (Entity*)atobject;
|
|
desc = "tiki : " + ent->model + "\n";
|
|
sprintf(addstr,"entnum: %d\n",ent->entnum);
|
|
desc += addstr;
|
|
sprintf(addstr,"origin: (%.2f, %.2f, %.2f)\n",ent->origin.x, ent->origin.y, ent->origin.z);
|
|
desc += addstr;
|
|
sprintf(addstr,"angles: (%.2f, %.2f, %.2f)\n",ent->angles.x, ent->angles.y, ent->angles.z);
|
|
desc += addstr;
|
|
sprintf(addstr,"bounds Mins: ( %.2f, %.2f, %.2f )\n", ent->mins.x, ent->mins.y, ent->mins.z);
|
|
desc += addstr;
|
|
sprintf(addstr,"bounds Maxs: ( %.2f, %.2f, %.2f )\n", ent->maxs.x, ent->maxs.y, ent->maxs.z );
|
|
desc += addstr;
|
|
sprintf(addstr,"size: ( %.2f, %.2f, %.2f )\n", ent->size.x, ent->size.y, ent->size.z );
|
|
desc += addstr;
|
|
sprintf(addstr,"velocity: ( %.2f, %.2f, %.2f )\n\n", ent->velocity.x, ent->velocity.y, ent->velocity.z );
|
|
desc += addstr;
|
|
|
|
if ( ent->isSubclassOf(Actor) )
|
|
{
|
|
Actor *act = (Actor *)ent;
|
|
desc += "--------- SUBCLASS OF ACTOR ------------\n";
|
|
sprintf(addstr, "Class ID: %s\n", act->getClassID() );
|
|
desc += addstr;
|
|
sprintf(addstr, "Classname: %s\n", act->getClassname() );
|
|
desc += addstr;
|
|
sprintf(addstr, "Name: %s\n", act->name.c_str() );
|
|
desc += addstr;
|
|
if ( act->part_name.length() > 0 )
|
|
{
|
|
sprintf(addstr, "Part name: %s\n", act->part_name.c_str() );
|
|
desc += addstr;
|
|
}
|
|
sprintf(addstr, "Targetname: %s\n", act->TargetName() );
|
|
desc += addstr;
|
|
|
|
if ( act->behavior )
|
|
sprintf(addstr, "Behavior: %s\n", act->behavior->getClassname() );
|
|
else
|
|
sprintf(addstr, "Behavior: NULL -- was '%s'\n", act->currentBehavior.c_str() );
|
|
desc += addstr;
|
|
|
|
if ( act->headBehavior )
|
|
sprintf(addstr, "Head Behavior: %s\n", act->headBehavior->getClassname() );
|
|
else
|
|
sprintf(addstr, "Head Behavior: NULL -- was %s\n", act->currentHeadBehavior.c_str() );
|
|
desc += addstr;
|
|
|
|
if ( act->eyeBehavior )
|
|
sprintf(addstr, "Eye Behavior: %s\n", act->eyeBehavior->getClassname() );
|
|
else
|
|
sprintf(addstr, "Eye Behavior: NULL -- was %s\n", act->currentEyeBehavior.c_str() );
|
|
desc += addstr;
|
|
|
|
if ( act->torsoBehavior )
|
|
sprintf(addstr, "Torso Behavior: %s\n", act->torsoBehavior->getClassname() );
|
|
else
|
|
sprintf(addstr, "Torso Behavior: NULL -- was %s\n", act->currentTorsoBehavior.c_str() );
|
|
desc += addstr;
|
|
|
|
if ( act->currentState )
|
|
sprintf(addstr, "State: %s\n", act->currentState->getName() );
|
|
else
|
|
sprintf(addstr, "State: NONE\n" );
|
|
desc += addstr;
|
|
|
|
if ( act->GetActorFlag( ACTOR_FLAG_AI_ON ) )
|
|
sprintf(addstr, "AI is ON\n" );
|
|
else
|
|
sprintf(addstr, "AI is OFF\n" );
|
|
desc += addstr;
|
|
|
|
if ( act->isThinkOn() )
|
|
sprintf(addstr, "Think is ON\n" );
|
|
else
|
|
sprintf(addstr, "Think is OFF\n" );
|
|
desc += addstr;
|
|
|
|
if ( act->mode == ACTOR_MODE_IDLE )
|
|
sprintf(addstr, "Mode: IDLE\n" );
|
|
else if ( act->mode == ACTOR_MODE_AI )
|
|
sprintf(addstr, "Mode: AI\n" );
|
|
else if ( act->mode == ACTOR_MODE_SCRIPT )
|
|
sprintf(addstr, "Mode: SCRIPT\n" );
|
|
else if ( act->mode == ACTOR_MODE_TALK )
|
|
sprintf(addstr, "Mode: TALK\n" );
|
|
desc += addstr;
|
|
|
|
sprintf(addstr, "Actortype: %d\n", act->actortype );
|
|
desc += addstr;
|
|
sprintf(addstr, "Anim: %s\n", act->animname.c_str() );
|
|
desc += addstr;
|
|
sprintf(addstr, "Health: %f\n", act->health );
|
|
desc += addstr;
|
|
|
|
sprintf(addstr, "CurrentEnemy: " );
|
|
desc += addstr;
|
|
|
|
// Get our current enemy
|
|
Entity *currentEnemy;
|
|
currentEnemy = act->enemyManager->GetCurrentEnemy();
|
|
if ( currentEnemy )
|
|
sprintf(addstr, "%d : '%s'\n", currentEnemy->entnum, currentEnemy->targetname.c_str() );
|
|
else
|
|
sprintf(addstr, "None\n" );
|
|
desc += addstr;
|
|
|
|
switch( act->deadflag )
|
|
{
|
|
case DEAD_NO :
|
|
sprintf(addstr, "deadflag: NO\n" );
|
|
break;
|
|
case DEAD_DYING :
|
|
sprintf(addstr, "deadflag: DYING\n" );
|
|
break;
|
|
case DEAD_DEAD :
|
|
sprintf(addstr, "deadflag: DEAD\n" );
|
|
break;
|
|
case DEAD_RESPAWNABLE :
|
|
sprintf(addstr, "deadflag: RESPAWNABLE\n" );
|
|
break;
|
|
}
|
|
desc += addstr;
|
|
|
|
}
|
|
|
|
G_SendCommandToPlayer( edict, "ui_addhud showinfo");
|
|
G_EnableWidgetOfPlayer( edict, "InfoHUD", true );
|
|
G_SetWidgetTextOfPlayer( edict, "InfoHUD", desc);
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: clearActionType
|
|
// Class: Player
|
|
//
|
|
// Description: Clears the action icon on the hud and NULL's
|
|
// out use entity.
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: None
|
|
//
|
|
//--------------------------------------------------------------
|
|
void Player::clearActionType()
|
|
{
|
|
if ( lastActionType.length() )
|
|
{
|
|
G_EnableWidgetOfPlayer( edict, lastActionType.c_str(), false );
|
|
//G_EnableWidgetOfPlayer( edict, "ActionTextArea", false );
|
|
lastActionType = "";
|
|
}
|
|
|
|
atobject = NULL;
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: handleUseEntity
|
|
// Class: Player
|
|
//
|
|
// Description: Called from CheckMoveFlags to handle the
|
|
// case that our trace hit an entity.
|
|
// We test to see if this is a usable entity
|
|
//
|
|
// Parameters: Entity *ent -- Entity to test
|
|
// float real_dist -- The real distance away from this entity,
|
|
// ignoring pitch.
|
|
//
|
|
// Returns: None
|
|
//
|
|
//--------------------------------------------------------------
|
|
void Player::handleUseEntity(Entity *ent, float real_dist)
|
|
{
|
|
if ( ent->hasUseData() )
|
|
{
|
|
// See if this entity is within distance to use.
|
|
if ( real_dist > ent->useData->getUseMaxDist() )
|
|
{
|
|
clearActionType();
|
|
return;
|
|
}
|
|
|
|
// Check to see if this entity is usable (due to count)
|
|
if ( ent->useData->getUseCount() == 0)
|
|
{
|
|
// Our count is 0, we can't use this entity anymore,
|
|
// so delete the useData for him.
|
|
delete ent->useData;
|
|
ent->useData = NULL;
|
|
clearActionType();
|
|
return;
|
|
}
|
|
|
|
// If he has a usetype show the HUD icon
|
|
if ( ent->useData->getUseType().length() > 0 && !lastActionType.length() )
|
|
{
|
|
G_EnableWidgetOfPlayer( edict, ent->useData->getUseType().c_str(), true );
|
|
//G_EnableWidgetOfPlayer( edict, "ActionTextArea", true );
|
|
//G_SetWidgetTextOfPlayer( edict, "ActionTextArea", ent->getArchetype().c_str());
|
|
lastActionType = ent->useData->getUseType();
|
|
}
|
|
}
|
|
else
|
|
clearActionType();
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: handleUseObject
|
|
// Class: Player
|
|
//
|
|
// Description: Called from CheckMoveFlags to handle the
|
|
// case that our trace hit a useobject
|
|
//
|
|
// Parameters: UseObject *uo
|
|
//
|
|
// Returns: None
|
|
//
|
|
//--------------------------------------------------------------
|
|
void Player::handleUseObject(UseObject *uo)
|
|
{
|
|
if ( uo->canBeUsed( origin, yaw_forward ) )
|
|
{
|
|
if ( uo->action_type.length() > 0 && !lastActionType.length() )
|
|
{
|
|
G_EnableWidgetOfPlayer( edict, uo->action_type.c_str(), true );
|
|
lastActionType = uo->action_type;
|
|
}
|
|
}
|
|
else // Not usable, clear HUD icon and data
|
|
clearActionType();
|
|
}
|
|
|
|
void Player::CheckMoveFlags()
|
|
{
|
|
trace_t trace;
|
|
Vector start, end, fwd, yfwd;
|
|
float oldsp, tracelen, real_dist;
|
|
int content;
|
|
Vector olddir( oldvelocity.x, oldvelocity.y, 0.0f );
|
|
|
|
//MatrixTransformVector( base_righthand_pos, orientation, righthand_pos );
|
|
//MatrixTransformVector( base_lefthand_pos, orientation, lefthand_pos );
|
|
MatrixTransformVector( base_rightfoot_pos, orientation, rightfoot_pos );
|
|
MatrixTransformVector( base_leftfoot_pos, orientation, leftfoot_pos );
|
|
//righthand_pos += origin;
|
|
//lefthand_pos += origin;
|
|
rightfoot_pos += origin;
|
|
leftfoot_pos += origin;
|
|
|
|
//
|
|
// Check if moving forward will cause the player to fall
|
|
//
|
|
start = origin + ( yaw_forward * 52.0f );
|
|
end = start;
|
|
end.z -= STEPSIZE * 2.0f;
|
|
|
|
trace = G_Trace( start, mins, maxs, end, this, edict->clipmask, true, "CheckMoveFlags" );
|
|
canfall = !( trace.fraction < 1.0f );
|
|
|
|
CheckGround();
|
|
if ( !groundentity && ( velocity.z < -250.0f ) )
|
|
{
|
|
falling = true;
|
|
hardimpact = false;
|
|
}
|
|
else
|
|
{
|
|
hardimpact = ( oldvelocity.z < -1000.0f );
|
|
falling = false;
|
|
}
|
|
|
|
// check for running into walls
|
|
oldsp = VectorNormalize( olddir );
|
|
if ( ( oldsp > 250.0f ) && ( velocity * olddir < 5.0f ) )
|
|
moveresult = MOVERESULT_HITWALL;
|
|
|
|
//
|
|
// Check if the useobject or useentity
|
|
//
|
|
start = origin;
|
|
start[ 2 ] += viewheight;
|
|
GetVAngles().AngleVectors(&fwd);
|
|
yfwd = yaw_forward;
|
|
yfwd.normalize();
|
|
|
|
// Normal test trace
|
|
tracelen = 96.0f;
|
|
content = MASK_USABLE;
|
|
|
|
// If we have sv_showinfo on, use a better, longer trace.
|
|
if ( sv_showinfo->integer )
|
|
{
|
|
_infoHudOn = true;
|
|
tracelen = sv_showinfodist->value;
|
|
|
|
if ( sv_showinfo->integer == 1 )
|
|
content = MASK_ALL;
|
|
else
|
|
content = CONTENTS_BODY | CONTENTS_CORPSE;
|
|
}
|
|
|
|
// See if the cvar has been turned off, if so, clear the hud.
|
|
if ( !sv_showinfo->integer && _infoHudOn )
|
|
{
|
|
G_EnableWidgetOfPlayer( edict, "InfoHUD", false );
|
|
_infoHudOn = false;
|
|
}
|
|
|
|
float tracedist = tracelen / (Vector::Dot(fwd, yfwd)); // lengthen the trace to compensate for pitch
|
|
end = start + ( fwd * tracedist );
|
|
trace = G_Trace( start, Vector(-5,-5,5), Vector(-5,-5,5), end, this, content, true, "CheckMoveFlags -- Checking for UseEntities" );
|
|
if ( trace.ent && trace.ent->entity && ( trace.ent->entity != world ) )
|
|
{
|
|
atobject = trace.ent->entity;
|
|
if ( trace.startsolid )
|
|
trace.fraction = 0.0;
|
|
atobject_dist = trace.fraction * tracedist;
|
|
real_dist = (atobject_dist / tracedist) * tracelen; // real distance ignoring pitch
|
|
atobject_dir.setXYZ( -trace.plane.normal[ 0 ], -trace.plane.normal[ 1 ], -trace.plane.normal[ 2 ] );
|
|
|
|
if ( sv_showinfo->integer )
|
|
showObjectInfo();
|
|
|
|
if ( atobject->isSubclassOf( UseObject ) )
|
|
{
|
|
UseObject *uo = (UseObject *)(Entity *)atobject;
|
|
handleUseObject(uo);
|
|
}
|
|
else
|
|
{
|
|
Entity *ent = (Entity *)atobject;
|
|
handleUseEntity(ent, real_dist); // see if this entity is usable
|
|
}
|
|
}
|
|
else // Didn't hit anything
|
|
{
|
|
if ( sv_showinfo->integer )
|
|
{
|
|
G_EnableWidgetOfPlayer( edict, "InfoHUD", false );
|
|
}
|
|
|
|
clearActionType();
|
|
}
|
|
|
|
/*
|
|
//
|
|
// get the distances the player can move left, right, forward, and back
|
|
//
|
|
if ( ( movecontrol == MOVECONTROL_USER ) || ( movecontrol == MOVECONTROL_LEGS ) )
|
|
{
|
|
move_left_dist = TestMoveDist( yaw_left * 128.0f );
|
|
move_right_dist = TestMoveDist( yaw_left * -128.0f );
|
|
move_backward_dist = TestMoveDist( yaw_forward * -128.0f );
|
|
move_forward_dist = TestMoveDist( yaw_forward * 128.0f );
|
|
}
|
|
else
|
|
{
|
|
move_left_dist = CheckMoveDist( yaw_left * 2.0f );
|
|
move_right_dist = CheckMoveDist( yaw_left * -2.0f );
|
|
move_backward_dist = CheckMoveDist( yaw_forward * -2.0f );
|
|
move_forward_dist = CheckMoveDist( yaw_forward * 2.0f );
|
|
}
|
|
*/
|
|
}
|
|
|
|
qboolean Player::CheckMove( const Vector &move, Vector *endpos )
|
|
{
|
|
return AnimMove( move, endpos );
|
|
}
|
|
|
|
void Player::ApplyPowerupEffects(int &moveSpeed)
|
|
{
|
|
if ( _powerup )
|
|
moveSpeed *= (int)_powerup->getMoveMultiplier();
|
|
|
|
if ( _rune )
|
|
moveSpeed *= (int)_rune->getMoveMultiplier();
|
|
|
|
/* if ( poweruptype == POWERUP_SPEED )
|
|
moveSpeed *= 2;
|
|
|
|
if ( poweruptype == POWERUP_STEALTH )
|
|
{
|
|
if ( !(flags & FL_NOTARGET) )
|
|
flags ^= FL_NOTARGET;
|
|
}
|
|
|
|
if ( poweruptype == POWERUP_PROTECTION )
|
|
{
|
|
if ( !(flags & FL_GODMODE) )
|
|
flags ^= FL_GODMODE;
|
|
}
|
|
|
|
if ( poweruptype == POWERUP_FLIGHT )
|
|
{
|
|
client->ps.pm_flags |= PMF_FLIGHT;
|
|
}
|
|
|
|
if ( poweruptype == POWERUP_ACCURACY )
|
|
{
|
|
// Tell the weapon we have the accuracy powerup
|
|
Weapon *weap;
|
|
weap = GetActiveWeapon( WEAPON_DUAL );
|
|
if ( weap )
|
|
weap->SetAccuracyPowerup( true );
|
|
} */
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: applyWeaponSpeedModifiers
|
|
// Class: Player
|
|
//
|
|
// Description: Applies any weapon speed modifiers
|
|
//
|
|
// Parameters: int *moveSpeed - the move speed to modify
|
|
//
|
|
// Returns: none
|
|
//----------------------------------------------------------------
|
|
|
|
void Player::applyWeaponSpeedModifiers( int *moveSpeed )
|
|
{
|
|
Weapon *weap;
|
|
|
|
weap = GetActiveWeapon( WEAPON_DUAL );
|
|
|
|
if ( weap )
|
|
{
|
|
*moveSpeed *= (int) weap->getMoveSpeedModifier();
|
|
}
|
|
|
|
}
|
|
|
|
void Player::ClientMoveLadder( usercmd_t *ucmd )
|
|
{
|
|
if ( _onLadder )
|
|
{
|
|
// Get off the ladder if the player jumps, the player touches the ground while moving down, or the player
|
|
// is no longer on the ladder physically
|
|
|
|
if ( ucmd->upmove > 0 )
|
|
{
|
|
velocity = _ladderNormal * sv_jumpvelocity->value;
|
|
_nextLadderTime = level.time + 0.20;
|
|
}
|
|
else
|
|
{
|
|
Vector climbDir;
|
|
Vector climbAngles;
|
|
Vector playerForward;
|
|
Vector playerLeft;
|
|
Vector forward;
|
|
Vector left;
|
|
Vector climbForward;
|
|
Vector climbLeft;
|
|
Vector climbUp;
|
|
bool goingUp;
|
|
float upAmount;
|
|
float rightAmount;
|
|
float forwardAmount;
|
|
trace_t trace;
|
|
bool pushForward;
|
|
|
|
// Change the forward velocity to directly up or down depending on how the player is facing and whether
|
|
// he is trying to go forwards or backwards
|
|
|
|
v_angle.AngleVectors( &playerForward, &playerLeft );
|
|
|
|
if ( playerForward.z > 0.0f )
|
|
goingUp = true;
|
|
else
|
|
goingUp = false;
|
|
|
|
if ( ucmd->forwardmove < 0 )
|
|
goingUp = !goingUp;
|
|
|
|
// Get the ladder climbing angles
|
|
|
|
climbDir = -_ladderNormal;
|
|
|
|
climbAngles = climbDir.toAngles();
|
|
climbAngles.AngleVectors( &climbForward, &climbLeft, &climbUp );
|
|
|
|
// Determine if we want to push against the ladder
|
|
|
|
trace = G_Trace( origin, mins, maxs, origin + climbForward * 4, this, edict->clipmask, true, "ClientMoveLadder" );
|
|
|
|
if ( trace.fraction < 1.0f )
|
|
pushForward = false;
|
|
else
|
|
pushForward = true;
|
|
|
|
// Get the forward/backwards movement of the player
|
|
|
|
if ( ucmd->forwardmove < 0 )
|
|
playerForward *= -1;
|
|
|
|
// Get the up/down amount from the forward movement
|
|
|
|
upAmount = playerForward * climbUp;
|
|
|
|
if ( ( upAmount >= -0.1f ) && ( upAmount <= 0.1f ) )
|
|
upAmount = 0.1f;
|
|
|
|
forwardAmount = abs( (int)(playerForward * climbForward) );
|
|
|
|
if ( upAmount >= 0.0f )
|
|
upAmount += forwardAmount;
|
|
else
|
|
upAmount -= forwardAmount;
|
|
|
|
// Get the left/right amount from the forward movement
|
|
|
|
rightAmount = playerForward * climbLeft;
|
|
|
|
if ( ( rightAmount >= -0.1f ) && ( rightAmount <= 0.1f ) )
|
|
rightAmount = 0.0f;
|
|
|
|
// Calculate the forward movement
|
|
|
|
forward = ( climbUp * upAmount + climbLeft * rightAmount ) * 0.5f;
|
|
forward.normalize();
|
|
|
|
if ( pushForward )
|
|
{
|
|
forward = ( climbForward + forward ) * 0.5f;
|
|
}
|
|
|
|
// Get the left/right movement of the player
|
|
|
|
if ( ucmd->rightmove > 0 )
|
|
playerLeft *= -1;
|
|
|
|
// Get the up/down amount from the strafe movement
|
|
|
|
upAmount = playerLeft * climbUp;
|
|
|
|
forwardAmount = playerLeft * climbForward;
|
|
|
|
upAmount += forwardAmount;
|
|
|
|
// Get the left/right amount from the strafe movement
|
|
|
|
rightAmount = playerLeft * climbLeft;
|
|
|
|
if ( ( rightAmount >= -0.1f ) && ( rightAmount <= 0.1f ) )
|
|
rightAmount = 0.0f;
|
|
|
|
// Calculate the strafe movement
|
|
|
|
left = ( climbUp * upAmount + climbLeft * rightAmount ) * 0.5f;
|
|
left.normalize();
|
|
|
|
if ( pushForward )
|
|
{
|
|
left = ( climbForward + left ) * 0.5f;
|
|
}
|
|
|
|
// Change our velocity based on the forward/strafe movements calculated
|
|
|
|
forward.normalize();
|
|
|
|
forward *= abs( ucmd->forwardmove ) / 127.0f * sv_maxspeed->value * 0.75f;
|
|
|
|
left *= abs( ucmd->rightmove ) / 127.0f * sv_maxspeed->value * 0.75f;
|
|
|
|
velocity = forward + left;
|
|
|
|
ucmd->forwardmove = 0;
|
|
|
|
client->ps.pm_flags |= PMF_NO_GRAVITY;
|
|
|
|
// If we have a groundentity and we are going down get off the ladder
|
|
|
|
if ( groundentity && !goingUp )
|
|
{
|
|
_nextLadderTime = level.time + 0.20;
|
|
}
|
|
}
|
|
|
|
_onLadder = false;
|
|
}
|
|
}
|
|
|
|
void Player::ClientMoveDuck( usercmd_t *ucmd )
|
|
{
|
|
if ( client->ps.pm_flags & PMF_DUCKED )
|
|
{
|
|
// See if we can stand where we are, otherwise we have to stay ducked.
|
|
Vector newmins( mins );
|
|
Vector newmaxs( maxs );
|
|
Vector tmporg( origin );
|
|
trace_t trace;
|
|
tmporg[ 2 ] += 2.0f;
|
|
newmins[ 2 ] = MINS_Z;
|
|
newmaxs[ 2 ] = MAXS_Z;
|
|
trace = G_Trace( tmporg, newmins, newmaxs, tmporg, this, edict->clipmask, true, "checkcanstand" );
|
|
if ( trace.startsolid )
|
|
{
|
|
client->ps.pm_flags |= PMF_DUCKED;
|
|
}
|
|
else
|
|
{
|
|
client->ps.pm_flags &= ~PMF_DUCKED;
|
|
}
|
|
}
|
|
|
|
if ( ucmd->upmove < 0 && sv_cancrouch->integer )
|
|
client->ps.pm_flags |= PMF_DUCKED;
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
// Name: ClientMoveLean
|
|
//
|
|
// Class: Player
|
|
//
|
|
// Description: Leans the player
|
|
//
|
|
// Parameters: ucmd - the structure of user commands from the client
|
|
//
|
|
// Returns: None
|
|
//-----------------------------------------------
|
|
void Player::ClientMoveLean( usercmd_t *ucmd )
|
|
{
|
|
Q_UNUSED(ucmd);
|
|
/*
|
|
client->ps.pm_flags &= ~(PMF_LEAN_RIGHT | PMF_LEAN_LEFT);
|
|
|
|
if(ucmd->lean > 0)
|
|
{
|
|
client->ps.pm_flags |= PMF_LEAN_RIGHT;
|
|
}
|
|
|
|
if(ucmd->lean < 0)
|
|
{
|
|
client->ps.pm_flags |= PMF_LEAN_LEFT;
|
|
}
|
|
*/
|
|
}
|
|
|
|
void Player::ClientMoveFlagsAndSpeeds( int moveSpeed, int noclipSpeed, int crouchSpeed, int airSpeed )
|
|
{
|
|
if ( level.playerfrozen || ( flags & FL_STUNNED ) )
|
|
{
|
|
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 ( movecontrol == MOVECONTROL_ANIM )
|
|
client->ps.pm_flags |= PMF_NO_PREDICTION;
|
|
|
|
if ( !groundentity )
|
|
{
|
|
client->ps.speed = airSpeed;
|
|
}
|
|
else if ( getMoveType() == MOVETYPE_NOCLIP || ( waterlevel > 1 ) )
|
|
{
|
|
// No clip underwater speeds
|
|
if ( last_ucmd.buttons & BUTTON_RUN )
|
|
client->ps.speed = noclipSpeed;
|
|
else
|
|
client->ps.speed = noclipSpeed/2;
|
|
}
|
|
else
|
|
{
|
|
// Duck speed
|
|
if ( client->ps.pm_flags & PMF_DUCKED )
|
|
{
|
|
client->ps.speed = crouchSpeed;
|
|
}
|
|
else
|
|
{
|
|
// Normal run/walk speed
|
|
if ( sv_useanimmovespeed->integer || movecontrol == MOVECONTROL_ANIM )
|
|
{
|
|
client->ps.speed = (int) animspeed;
|
|
}
|
|
else
|
|
{
|
|
if ( last_ucmd.buttons & BUTTON_RUN )
|
|
client->ps.speed = moveSpeed;
|
|
else
|
|
client->ps.speed = moveSpeed/2;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( getMoveType() == MOVETYPE_NOCLIP )
|
|
{
|
|
// Normal noclip speed (run/walk)
|
|
if ( last_ucmd.buttons & BUTTON_RUN )
|
|
client->ps.speed = noclipSpeed;
|
|
else
|
|
client->ps.speed = noclipSpeed/2;
|
|
}
|
|
|
|
if ( sv_instantjump->integer )
|
|
client->ps.instantJump = true;
|
|
else
|
|
client->ps.instantJump = false;
|
|
|
|
if ( sv_strafeJumpingAllowed->integer )
|
|
client->ps.strafeJumpingAllowed = true;
|
|
else
|
|
client->ps.strafeJumpingAllowed = false;
|
|
}
|
|
|
|
void Player::ClientMoveMisc( usercmd_t *ucmd )
|
|
{
|
|
// We're falling, can't move around in the air
|
|
if ( client->ps.feetfalling && ( waterlevel < 2 ) && !( client->ps.pm_time ) )
|
|
{
|
|
ucmd->forwardmove = 0;
|
|
ucmd->rightmove = 0;
|
|
}
|
|
|
|
// Fake player, cancel any movement input
|
|
if ( fakePlayer_active || movecontrol == MOVECONTROL_ANIM )
|
|
{
|
|
ucmd->forwardmove = 0;
|
|
ucmd->rightmove = 0;
|
|
ucmd->upmove = 0;
|
|
}
|
|
}
|
|
|
|
void Player::ClientMove( usercmd_t *ucmd )
|
|
{
|
|
pmove_t pm;
|
|
Vector move;
|
|
|
|
int moveSpeed;
|
|
int noclipSpeed = (int) sv_noclipspeed->value;
|
|
int crouchSpeed;
|
|
int airSpeed;
|
|
|
|
if ( world->getPhysicsVar( WORLD_PHYSICS_MAXSPEED ) != -1.0f )
|
|
moveSpeed = (int) world->getPhysicsVar( WORLD_PHYSICS_MAXSPEED );
|
|
else
|
|
moveSpeed = (int) sv_maxspeed->value;
|
|
|
|
if ( sv_crouchspeed->value > 0.0f )
|
|
crouchSpeed = (int) sv_crouchspeed->value;
|
|
else
|
|
crouchSpeed = (int)((float)moveSpeed * 0.5);
|
|
|
|
if ( sv_airmaxspeed->value > 0.0f )
|
|
airSpeed = (int) sv_airmaxspeed->value;
|
|
else
|
|
airSpeed = moveSpeed;
|
|
|
|
// Save off current origin
|
|
oldorigin = origin;
|
|
|
|
client->ps.pm_type = GetMovePlayerMoveType();
|
|
|
|
// Clear movement flags
|
|
client->ps.pm_flags &= ~( PMF_FLIGHT | PMF_FROZEN | PMF_NO_PREDICTION | PMF_NO_MOVE | PMF_HAVETARGET | PMF_NO_GRAVITY );
|
|
|
|
// Modify speeds
|
|
|
|
ApplyPowerupEffects( moveSpeed );
|
|
applyWeaponSpeedModifiers( &moveSpeed );
|
|
|
|
if ( multiplayerManager.inMultiplayer() )
|
|
multiplayerManager.applySpeedModifiers( this, &moveSpeed );
|
|
|
|
ApplyPowerupEffects( crouchSpeed );
|
|
applyWeaponSpeedModifiers( &crouchSpeed );
|
|
|
|
if ( multiplayerManager.inMultiplayer() )
|
|
multiplayerManager.applySpeedModifiers( this, &crouchSpeed );
|
|
|
|
ApplyPowerupEffects( airSpeed );
|
|
applyWeaponSpeedModifiers( &airSpeed );
|
|
|
|
if ( multiplayerManager.inMultiplayer() )
|
|
multiplayerManager.applySpeedModifiers( this, &airSpeed );
|
|
|
|
// Handle ducking
|
|
ClientMoveDuck(ucmd);
|
|
|
|
//Handle leaning
|
|
ClientMoveLean(ucmd);
|
|
|
|
// Movement speed and mobility flags
|
|
ClientMoveFlagsAndSpeeds(moveSpeed, noclipSpeed, crouchSpeed, airSpeed);
|
|
|
|
// Misc movement stuff, like falling, and fake player control
|
|
ClientMoveMisc(ucmd);
|
|
|
|
// Handle ladder situations
|
|
ClientMoveLadder(ucmd);
|
|
|
|
// Gravity modifier
|
|
client->ps.gravity = (int)(sv_currentGravity->value * gravity);
|
|
|
|
// Perform the move
|
|
CheckGround();
|
|
SetMoveInfo( &pm, ucmd );
|
|
Pmove( &pm );
|
|
GetMoveInfo( &pm );
|
|
ProcessPmoveEvents( pm.pmoveEvent );
|
|
|
|
// Animation driven stuff happens here
|
|
if ( ( getMoveType() == MOVETYPE_NOCLIP ) || !( client->ps.pm_flags & PMF_NO_PREDICTION ) )
|
|
{
|
|
total_delta = vec_zero;
|
|
}
|
|
else
|
|
{
|
|
if ( movecontrol == MOVECONTROL_ABSOLUTE )
|
|
{
|
|
velocity = vec_zero;
|
|
}
|
|
|
|
if ( total_delta != vec_zero )
|
|
{
|
|
// Animation driven move
|
|
MatrixTransformVector( total_delta, orientation, move );
|
|
CheckMove( move, &origin );
|
|
setOrigin( origin );
|
|
CheckGround();
|
|
}
|
|
}
|
|
|
|
total_delta = vec_zero;
|
|
|
|
TouchStuff( &pm );
|
|
|
|
// Debug output
|
|
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->areanum );
|
|
}
|
|
|
|
/*
|
|
==============
|
|
ClientThink
|
|
|
|
This will be called once for each client frame, which will
|
|
usually be a couple times for each server frame.
|
|
==============
|
|
*/
|
|
void Player::ClientThink( Event * )
|
|
{
|
|
// sanity check the command time to prevent speedup cheating
|
|
if ( current_ucmd->serverTime > level.inttime )
|
|
{
|
|
//
|
|
// we don't want any future commands, these could be from the previous game
|
|
//
|
|
return;
|
|
}
|
|
|
|
if ( current_ucmd->serverTime < ( level.inttime - 1000 ) )
|
|
{
|
|
current_ucmd->serverTime = level.inttime - 1000;
|
|
}
|
|
|
|
if ( ( current_ucmd->serverTime - client->ps.commandTime ) < 1 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
_started = true;
|
|
|
|
last_ucmd = *current_ucmd;
|
|
new_buttons = current_ucmd->buttons & ~buttons;
|
|
buttons = current_ucmd->buttons;
|
|
|
|
// Handle Heath Regen if it's in the gameplay database
|
|
GameplayManager *gpm = GameplayManager::getTheGameplayManager();
|
|
str scopestr = "CurrentPlayer.HPRegen";
|
|
if ( gpm->hasObject(scopestr) )
|
|
{
|
|
int value = (int)gpm->getFloatValue(scopestr, "value");
|
|
if ( level.inttime > _nextRegenTime && value > 0 )
|
|
{
|
|
_nextRegenTime = level.inttime + ((6-value) * 1000);
|
|
AddHealth(1.0f);
|
|
}
|
|
}
|
|
|
|
if ( _useEntityStartTimer != 0.0f )
|
|
{
|
|
if ( level.time > _useEntityStartTimer )
|
|
{
|
|
_usingEntity = false;
|
|
_useEntityStartTimer = 0.0f;
|
|
}
|
|
}
|
|
|
|
if ( current_ucmd->thirdperson )
|
|
_isThirdPerson = true;
|
|
else
|
|
_isThirdPerson = false;
|
|
|
|
// Set cvar values
|
|
if ( world->getPhysicsVar( WORLD_PHYSICS_AIRACCELERATE ) != -1.0f )
|
|
client->ps.pm_airaccelerate = (int) world->getPhysicsVar( WORLD_PHYSICS_AIRACCELERATE );
|
|
else
|
|
client->ps.pm_airaccelerate = (int) sv_airaccelerate->value;
|
|
|
|
if ( multiplayerManager.inMultiplayer() )
|
|
multiplayerManager.applyAirAccelerationModifiers( this, &client->ps.pm_airaccelerate );
|
|
|
|
client->ps.pm_wateraccelerate = (int) sv_wateraccelerate->value;
|
|
client->ps.pm_stopspeed = (int) sv_stopspeed->value;
|
|
client->ps.pm_friction = (int) sv_friction->value;
|
|
client->ps.pm_waterfriction = (int) sv_waterfriction->value;
|
|
client->ps.jumpvelocity = (int) sv_jumpvelocity->value;
|
|
|
|
if ( multiplayerManager.inMultiplayer() )
|
|
multiplayerManager.applyJumpModifiers( this, &client->ps.jumpvelocity );
|
|
|
|
client->ps.crouchjumpvelocity = (int) sv_crouchjumpvelocity->value;
|
|
|
|
client->ps.pm_accelerate = (int) sv_accelerate->value;
|
|
client->ps.pm_defaultviewheight = (int) sv_defaultviewheight->value;
|
|
|
|
viewheight = client->ps.pm_defaultviewheight;
|
|
|
|
|
|
|
|
if ( level.intermissiontime )
|
|
{
|
|
client->ps.pm_flags |= PMF_FROZEN;
|
|
|
|
if (g_endintermission->integer > 0 )
|
|
{
|
|
g_endintermission->integer = 0;
|
|
level.exitintermission = true;
|
|
}
|
|
// can exit intermission after 10 seconds (default)
|
|
if ( (( level.time - level.intermissiontime ) > level.intermission_advancetime)
|
|
&& (level.intermission_advancetime != 0))
|
|
{
|
|
if ( multiplayerManager.inMultiplayer() )
|
|
{
|
|
//if ( new_buttons & BUTTON_ANY )
|
|
if ( ( new_buttons & BUTTON_ATTACKRIGHT ) || ( new_buttons & BUTTON_ATTACKLEFT ) )
|
|
{
|
|
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;
|
|
}
|
|
|
|
moveresult = MOVERESULT_NONE;
|
|
|
|
if ( !vehicle || !vehicle->Drive( current_ucmd ) )
|
|
{
|
|
ClientMove( current_ucmd );
|
|
}
|
|
|
|
if ( vehicle )
|
|
{
|
|
pmove_t pm;
|
|
|
|
SetMoveInfo( &pm, current_ucmd );
|
|
Pmove( &pm );
|
|
}
|
|
|
|
|
|
if(current_ucmd)
|
|
{
|
|
_crossHairXOffset = current_ucmd->choffset[0];
|
|
_crossHairYOffset = current_ucmd->choffset[1];
|
|
}
|
|
|
|
|
|
client->ps.pm_flags &= ~(PMF_RADAR_MODE | PMF_SCANNER );
|
|
|
|
CheckForTargetedEntity();
|
|
ProcessTargetedEntity();
|
|
|
|
Weapon *weap;
|
|
weap = GetActiveWeapon( WEAPON_DUAL );
|
|
if ( weap )
|
|
{
|
|
if(weap->GetPutaway())
|
|
{
|
|
// weap->SetTargetedEntity(0);
|
|
}
|
|
else
|
|
{
|
|
// weap->SetRealViewOrigin();
|
|
// weap->SetThirdPerson();
|
|
// weap->SetCHOffset( current_ucmd->choffset[0], current_ucmd->choffset[1]);
|
|
|
|
weap->ProcessTargetedEntity(GetTargetedEntity());
|
|
}
|
|
|
|
if ( ( ( weap->GetFireType( FIRE_MODE1 ) == FT_CONTROL_PROJECTILE ) && ( new_buttons & BUTTON_ATTACKLEFT ) ) ||
|
|
( ( weap->GetFireType( FIRE_MODE2 ) == FT_CONTROL_PROJECTILE ) && ( new_buttons & BUTTON_ATTACKRIGHT ) ) )
|
|
{
|
|
weap->toggleProjectileControl();
|
|
}
|
|
|
|
if ( ( ( weap->GetFireType( FIRE_MODE1 ) == FT_CONTROL_ZOOM ) && ( new_buttons & BUTTON_ATTACKLEFT ) ) ||
|
|
( ( weap->GetFireType( FIRE_MODE2 ) == FT_CONTROL_ZOOM ) && ( new_buttons & BUTTON_ATTACKRIGHT ) ) )
|
|
{
|
|
weap->changeZoomStage( 40.0f, 10.0f );
|
|
}
|
|
}
|
|
|
|
// If we're charging up for a special move, set the current time
|
|
if ( specialMoveCharge > 0.0f )
|
|
{
|
|
specialMoveCharge = level.time;
|
|
//gi.Printf("Charging Up... Time: %.2f\n",specialMoveEndTime - level.time);
|
|
}
|
|
|
|
|
|
// only evaluate the state when not noclipping
|
|
if ( getMoveType() == MOVETYPE_NOCLIP )
|
|
{
|
|
// force the stand animation if were in noclip
|
|
SetAnim( "idle", all );
|
|
}
|
|
else
|
|
{
|
|
// set flags for state machine
|
|
CheckMoveFlags();
|
|
EvaluateState();
|
|
|
|
if ( groundentity && groundentity->entity && groundentity->entity->isSubclassOf( Actor ) )
|
|
{
|
|
Event *event = new Event( EV_Actor_Push );
|
|
event->AddVector( Vector( 0.0f, 0.0f, -10.0f ) );
|
|
groundentity->entity->PostEvent( event, 0.0f );
|
|
}
|
|
}
|
|
|
|
oldvelocity = velocity;
|
|
old_v_angle = v_angle;
|
|
|
|
// If we're dying, check for respawn
|
|
if ( ( deadflag == DEAD_DEAD && ( level.time > respawn_time ) ) )
|
|
{
|
|
// wait for any button just going down
|
|
//if ( new_buttons || ( multiplayerManager.inMultiplayer() && multiplayerManager.checkFlag( MP_FLAG_FORCE_RESPAWN ) ) )
|
|
if ( ( ( new_buttons & BUTTON_ATTACKRIGHT ) || ( new_buttons & BUTTON_ATTACKLEFT ) ) ||
|
|
( multiplayerManager.inMultiplayer() && multiplayerManager.checkFlag( MP_FLAG_FORCE_RESPAWN ) ) )
|
|
{
|
|
if ( multiplayerManager.inMultiplayer() )
|
|
{
|
|
//respawn_time = level.time ;
|
|
multiplayerManager.respawnPlayer( this, false );
|
|
// ProcessEvent( EV_Player_Respawn );
|
|
}
|
|
|
|
else
|
|
{
|
|
G_RestartLevelWithDelay( 1.0f );
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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 ( client->ps.pm_flags & PMF_CAMERA_VIEW )
|
|
{
|
|
VectorCopy( current_ucmd->realvieworigin, client->ps.camera_origin );
|
|
VectorCopy( current_ucmd->realviewangles, client->ps.camera_angles );
|
|
}
|
|
|
|
if ( g_logstats->integer )
|
|
{
|
|
if ( !logfile_started )
|
|
{
|
|
ProcessEvent( EV_Player_LogStats );
|
|
logfile_started = true;
|
|
}
|
|
}
|
|
|
|
if ( ( last_ucmd.buttons & BUTTON_USE ) != 0 )
|
|
ProcessEvent( EV_Player_DoUse );
|
|
|
|
if ( ( last_ucmd.buttons & BUTTON_DROP_RUNE ) != 0 )
|
|
dropRune();
|
|
|
|
if ( ( last_ucmd.buttons & BUTTON_TRANSFER_ENERGY ) != 0 )
|
|
transferEnergy();
|
|
|
|
if ( multiplayerManager.inMultiplayer() )
|
|
multiplayerManager.playerInput( this, new_buttons );
|
|
|
|
// Check for incoming melee attacks and set the incomingMeleeAttack flag
|
|
incomingMeleeAttack = false;
|
|
if ( meleeAttackerList.NumObjects() )
|
|
{
|
|
Entity *attacker;
|
|
int i;
|
|
for( i = meleeAttackerList.NumObjects() ; i >= 1 ; i-- )
|
|
{
|
|
attacker = (Entity*)meleeAttackerList.ObjectAt(i);
|
|
if ( !attacker )
|
|
continue;
|
|
|
|
if ( attacker->isSubclassOf(Actor) )
|
|
{
|
|
Actor *act = (Actor *)attacker;
|
|
if ( act->in_melee_attack )
|
|
incomingMeleeAttack = true;
|
|
else
|
|
meleeAttackerList.RemoveObjectAt( i );
|
|
}
|
|
}
|
|
|
|
// No one is attacking us, make sure the list is clear
|
|
if ( !incomingMeleeAttack )
|
|
meleeAttackerList.ClearObjectList();
|
|
}
|
|
}
|
|
|
|
// This function returns the endpoint of where the crosshair is located on the
|
|
// screen. Regardless of whether we're in camera, first or 3rd person view.
|
|
void Player::GetViewTrace( trace_t& trace, int contents, float maxDistance )
|
|
{
|
|
// trace_t trace;
|
|
Vector f,r,u,p,s;
|
|
Vector pos, forward, endpoint, vorg, dir;
|
|
vec3_t viewAngles;
|
|
|
|
|
|
if (client->ps.pm_flags & PMF_CAMERA_VIEW ) // 3rd person automatic camera
|
|
{
|
|
vorg = client->ps.camera_origin;
|
|
VectorCopy(client->ps.camera_angles, viewAngles);
|
|
}
|
|
else if ( !_isThirdPerson ) // First person
|
|
{
|
|
vorg = origin;
|
|
vorg.z += client->ps.viewheight;
|
|
VectorCopy(GetVAngles(), viewAngles);
|
|
}
|
|
else // Third person
|
|
{
|
|
//vorg = current_ucmd->realviewangles;
|
|
VectorCopy(GetVAngles(), viewAngles);
|
|
|
|
}
|
|
|
|
vec3_t left;
|
|
//Adjust the view end point if we are leaning.
|
|
if( client->ps.leanDelta != 0)
|
|
{
|
|
viewAngles[2] -= client->ps.leanDelta / 2.0f;
|
|
|
|
AngleVectors( viewAngles, NULL, left, NULL );
|
|
VectorMA( vorg, client->ps.leanDelta, left, vorg );
|
|
}
|
|
|
|
// Add the damage angles
|
|
VectorSubtract( viewAngles, client->ps.damage_angles, viewAngles );
|
|
|
|
AngleVectors(viewAngles, f,r,u);
|
|
|
|
float xmax,ymax, fov_x, fov_y, x;
|
|
|
|
fov_x = client->ps.fov;
|
|
x = 640.0f / (float)tan( fov_x / 360.0 * M_PI );
|
|
fov_y = (float)atan2( 480.0f, x );
|
|
fov_y *= 360.0f / M_PI;
|
|
|
|
ymax = 4.0f * (float)tan( fov_y * M_PI / 360.0 );
|
|
xmax = 4.0f * (float)tan( fov_x * M_PI / 360.0 );
|
|
|
|
p.x = (float) _crossHairXOffset * (-xmax / 320.0f);
|
|
p.y = (float) _crossHairYOffset * (-ymax / 240.0f);
|
|
s = ( 4.0f * f ) + ( p.x * r ) + ( p.y * u );
|
|
s.normalize();
|
|
endpoint = vorg + (s * maxDistance );
|
|
|
|
if ( !multiplayerManager.inMultiplayer() || multiplayerManager.fullCollision() )
|
|
trace = G_FullTrace( vorg, vec_zero, vec_zero, endpoint, this, contents, true, "Player::GetViewEndPoint" );
|
|
else
|
|
trace = G_Trace( vorg, vec_zero, vec_zero, endpoint, this, contents, true, "Player::GetViewEndPoint" );
|
|
|
|
//endpoint = trace.endpos;
|
|
|
|
//G_DebugLine( vorg, endpoint, 1,0,1,1 );
|
|
|
|
//return endpoint;
|
|
}
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name: CheckForTargetedEntity
|
|
// Class: Player
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Returns:
|
|
//-----------------------------------------------------
|
|
void Player::CheckForTargetedEntity( void )
|
|
{
|
|
trace_t viewTrace;
|
|
|
|
memset(&viewTrace,0,sizeof(trace_t));
|
|
GetViewTrace(viewTrace, MASK_SHOT | CONTENTS_TARGETABLE);
|
|
|
|
if ( viewTrace.ent && ( viewTrace.entityNum != ENTITYNUM_WORLD ))
|
|
{
|
|
if(viewTrace.ent->entity->isSubclassOf(Actor) && viewTrace.ent->entity->getHealth() <= 0)
|
|
{
|
|
SetTargetedEntity(0);
|
|
}
|
|
else
|
|
{
|
|
SetTargetedEntity(viewTrace.ent->entity);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
SetTargetedEntity(0);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name: SetTargetedEntity
|
|
// Class: Player
|
|
//
|
|
// Description: Sets the targeted entity.
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Returns:
|
|
//-----------------------------------------------------
|
|
void Player::SetTargetedEntity(EntityPtr entity)
|
|
{
|
|
//remove the EF_DISPLAY_INFO from the previous entity.
|
|
if(_targetedEntity != 0)
|
|
_targetedEntity ->edict->s.eFlags &= ~(EF_DISPLAY_INFO|EF_DISPLAY_DESC1 | EF_DISPLAY_DESC2 | EF_DISPLAY_DESC3);
|
|
|
|
|
|
_targetedEntity = entity;
|
|
if(_targetedEntity != 0)
|
|
_targetedEntity->edict->s.eFlags |= EF_DISPLAY_INFO;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name: ProcessTargetedEntity
|
|
// Class: Player
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Returns:
|
|
//-----------------------------------------------------
|
|
void Player::ProcessTargetedEntity( void )
|
|
{
|
|
if(_targetedEntity == 0)
|
|
return;
|
|
|
|
_targetedEntity->edict->s.eFlags |= EF_DISPLAY_DESC1;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: SetState
|
|
// Class: Player
|
|
//
|
|
// Description: Sets the state machine to the specific legs and torso state specified
|
|
//
|
|
// Parameters: const str& legsstate -- Legs state name
|
|
// const str& torsostate -- Torso state name
|
|
//
|
|
// Returns: None
|
|
//
|
|
//--------------------------------------------------------------
|
|
void Player::SetState(const str& legsstate, const str& torsostate)
|
|
{
|
|
animdone_Legs = false;
|
|
animdone_Torso = false;
|
|
|
|
movecontrol = MOVECONTROL_USER;
|
|
|
|
currentState_Legs = statemap_Legs->FindState( legsstate.c_str() );
|
|
currentState_Torso = statemap_Torso->FindState( torsostate.c_str() );
|
|
|
|
str legsAnim( currentState_Legs->getLegAnim( *this, &legs_conditionals ) );
|
|
if ( !animate->HasAnim(legsAnim) )
|
|
legsAnim = getGameplayAnim(legsAnim);
|
|
if ( legsAnim == "" )
|
|
{
|
|
partAnim[ legs ] = "";
|
|
animate->ClearLegsAnim();
|
|
}
|
|
else if ( legsAnim != "none" )
|
|
{
|
|
SetAnim( legsAnim, legs );
|
|
}
|
|
|
|
str torsoAnim( currentState_Torso->getTorsoAnim( *this, &torso_conditionals ) );
|
|
if ( !animate->HasAnim(torsoAnim) )
|
|
torsoAnim = getGameplayAnim(torsoAnim);
|
|
if ( torsoAnim == "" )
|
|
{
|
|
partAnim[ torso ] = "";
|
|
animate->ClearTorsoAnim();
|
|
}
|
|
else if ( torsoAnim != "none" )
|
|
{
|
|
SetAnim( torsoAnim.c_str(), torso );
|
|
}
|
|
|
|
movecontrol = currentState_Legs->getMoveType();
|
|
if ( ( movecontrol < ( sizeof( MoveStartFuncs ) / sizeof( MoveStartFuncs[ 0 ] ) ) ) && ( MoveStartFuncs[ movecontrol ] ) )
|
|
{
|
|
( this->*MoveStartFuncs[ movecontrol ] )();
|
|
}
|
|
|
|
// This seems breaks the secret move mode because it's called at a bad time and causes the client/server angles
|
|
// to get out of sync because delta_angles is not updated correctly.
|
|
// I don't think it's necessary to call it anyway, so I'm removing it.
|
|
//SetViewAngles( v_angle );
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: LoadStateTable
|
|
// Class: Player
|
|
//
|
|
// Description: Loads the state table for the player.
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: None
|
|
//
|
|
//--------------------------------------------------------------
|
|
void Player::LoadStateTable()
|
|
{
|
|
statemap_Legs = NULL;
|
|
statemap_Torso = NULL;
|
|
|
|
freeConditionals( legs_conditionals );
|
|
freeConditionals( torso_conditionals );
|
|
|
|
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 );
|
|
|
|
SetState("STAND", "START");
|
|
}
|
|
|
|
void Player::ResetState( Event * )
|
|
{
|
|
movecontrol = MOVECONTROL_USER;
|
|
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.0f;
|
|
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, edict->clipmask, true, "StartUseAnim" );
|
|
if ( trace.startsolid || ( trace.fraction < 1.0f ) )
|
|
{
|
|
gi.WDPrintf( "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.WDPrintf( "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" );
|
|
}
|
|
}
|
|
SetAnim( newanim, legs );
|
|
}
|
|
}
|
|
}
|
|
|
|
void Player::StartLoopUseAnim( void )
|
|
{
|
|
useanim_numloops--;
|
|
}
|
|
|
|
void Player::FinishUseAnim( Event * )
|
|
{
|
|
UseAnim *ua;
|
|
|
|
if ( !useitem_in_use )
|
|
return;
|
|
|
|
ua = ( UseAnim * )( Entity * )useitem_in_use;
|
|
ua->TriggerTargets( this );
|
|
useitem_in_use = NULL;
|
|
}
|
|
|
|
void Player::SetupUseObject()
|
|
{
|
|
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 );
|
|
if ( uo->movetheplayer )
|
|
{
|
|
trace = G_Trace( neworg, mins, maxs, neworg, this, edict->clipmask, true, "SetupUseObject - 1" );
|
|
if ( trace.startsolid || trace.allsolid )
|
|
{
|
|
trace = G_Trace( origin, mins, maxs, neworg, this, edict->clipmask, true, "SetupUseObject - 2" );
|
|
if ( trace.startsolid || ( trace.fraction < 1.0f ) )
|
|
{
|
|
gi.WDPrintf( "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.WDPrintf( "Could not find state %s on UseObject\n", state.c_str() );
|
|
}
|
|
else
|
|
{
|
|
uo->Start();
|
|
}
|
|
}
|
|
|
|
void Player::StartUseObject( Event * )
|
|
{
|
|
UseObject *uo;
|
|
|
|
if ( !useitem_in_use )
|
|
return;
|
|
|
|
uo = ( UseObject * )( Entity * )useitem_in_use;
|
|
uo->Start();
|
|
}
|
|
|
|
void Player::FinishUseObject( Event * )
|
|
{
|
|
UseObject *uo;
|
|
|
|
if ( !useitem_in_use )
|
|
return;
|
|
|
|
uo = ( UseObject * )( Entity * )useitem_in_use;
|
|
uo->Stop( this );
|
|
useitem_in_use = NULL;
|
|
}
|
|
|
|
void Player::turnTowardsEntity( Event *ev )
|
|
{
|
|
Entity *entity;
|
|
Vector dir;
|
|
Vector angles;
|
|
Event *turnEvent;
|
|
float currentYaw;
|
|
float yawDiff;
|
|
|
|
entity = ev->GetEntity( 1 );
|
|
|
|
if ( !entity )
|
|
return;
|
|
|
|
// Get the angles to the entity
|
|
|
|
dir = entity->origin - origin;
|
|
dir.normalize();
|
|
|
|
angles = dir.toAngles();
|
|
|
|
// Get the yaw difference
|
|
|
|
currentYaw = anglemod( v_angle[ YAW ] );
|
|
|
|
yawDiff = angles[ YAW ] - currentYaw;
|
|
|
|
yawDiff = AngleNormalize180( yawDiff );
|
|
|
|
// Actually turn the appropriate amount
|
|
|
|
turnEvent = new Event( EV_Player_Turn );
|
|
turnEvent->AddFloat( yawDiff );
|
|
ProcessEvent( turnEvent );
|
|
}
|
|
|
|
void Player::Turn( Event *ev )
|
|
{
|
|
float yaw;
|
|
float time;
|
|
int numFrames;
|
|
|
|
yaw = ev->GetFloat( 1 );
|
|
|
|
if ( ev->NumArgs() > 1 )
|
|
time = ev->GetFloat( 2 );
|
|
else
|
|
time = 0.5;
|
|
|
|
numFrames = (int)(time * ( 1 / level.frametime ));
|
|
time = numFrames * level.frametime;
|
|
|
|
CancelEventsOfType( EV_Player_TurnUpdate );
|
|
|
|
if ( time > 0 )
|
|
{
|
|
ev = new Event( EV_Player_TurnUpdate );
|
|
ev->AddFloat( yaw / numFrames );
|
|
ev->AddFloat( time );
|
|
ProcessEvent( ev );
|
|
}
|
|
else
|
|
{
|
|
v_angle[ YAW ] += yaw;
|
|
SetViewAngles( v_angle );
|
|
}
|
|
}
|
|
|
|
void Player::TurnUpdate( Event *ev )
|
|
{
|
|
float yaw;
|
|
float timeleft;
|
|
|
|
yaw = ev->GetFloat( 1 );
|
|
timeleft = ev->GetFloat( 2 );
|
|
|
|
// Remove some time
|
|
|
|
timeleft -= 0.05f;
|
|
|
|
// Turn the specified amount
|
|
|
|
v_angle[ YAW ] += yaw;
|
|
SetViewAngles( v_angle );
|
|
|
|
// Repost the turn event if we have time remaining
|
|
|
|
if ( timeleft > 0.0f )
|
|
{
|
|
ev = new Event( EV_Player_TurnUpdate );
|
|
ev->AddFloat( yaw );
|
|
ev->AddFloat( timeleft );
|
|
PostEvent( ev, 0.05f );
|
|
}
|
|
}
|
|
|
|
void Player::TurnLegs( Event *ev )
|
|
{
|
|
float yaw;
|
|
|
|
yaw = ev->GetFloat( 1 );
|
|
|
|
angles[ YAW ] += yaw;
|
|
setAngles( angles );
|
|
}
|
|
|
|
void Player::DontTurnLegs( Event *ev )
|
|
{
|
|
dont_turn_legs = ev->GetBoolean( 1 );
|
|
}
|
|
|
|
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.WDPrintf( "Possible infinite loop in state '%s'\n", currentState_Torso->getName() );
|
|
assert( 0 );
|
|
if ( count > 20 )
|
|
{
|
|
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 );
|
|
|
|
animdone_Torso = false;
|
|
if ( movecontrol != MOVECONTROL_LEGS )
|
|
{
|
|
animdone_Legs = false;
|
|
}
|
|
if ( laststate_Torso != 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();
|
|
|
|
str legsAnim( currentState_Torso->getLegAnim( *this, &torso_conditionals ) );
|
|
if ( !animate->HasAnim(legsAnim) )
|
|
legsAnim = getGameplayAnim(legsAnim);
|
|
str torsoAnim( currentState_Torso->getTorsoAnim( *this, &torso_conditionals ) );
|
|
if ( !animate->HasAnim(torsoAnim) )
|
|
torsoAnim = getGameplayAnim(torsoAnim);
|
|
|
|
if ( legsAnim != "" )
|
|
{
|
|
animdone_Legs = false;
|
|
if ( !vehicle )
|
|
SetAnim( legsAnim, legs );
|
|
}
|
|
else if ( move == MOVECONTROL_LEGS )
|
|
{
|
|
if ( !currentState_Legs )
|
|
{
|
|
animdone_Legs = false;
|
|
currentState_Legs = statemap_Legs->FindState( "STAND" );
|
|
legsAnim = currentState_Legs->getLegAnim( *this, &legs_conditionals );
|
|
if ( !animate->HasAnim(legsAnim) )
|
|
legsAnim = getGameplayAnim(legsAnim);
|
|
if ( legsAnim == "" )
|
|
{
|
|
partAnim[ legs ] = "";
|
|
animate->ClearLegsAnim();
|
|
}
|
|
else if ( legsAnim != "none" )
|
|
{
|
|
if ( !vehicle )
|
|
SetAnim( legsAnim, legs );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
partAnim[ legs ] = "";
|
|
animate->ClearLegsAnim();
|
|
}
|
|
|
|
if ( torsoAnim == "" )
|
|
{
|
|
partAnim[ torso ] = "";
|
|
animate->ClearTorsoAnim();
|
|
}
|
|
else if ( torsoAnim != "none" )
|
|
{
|
|
SetAnim( torsoAnim.c_str(), torso );
|
|
}
|
|
|
|
if ( movecontrol != move )
|
|
{
|
|
movecontrol = move;
|
|
if ( ( move < ( sizeof( MoveStartFuncs ) / sizeof( MoveStartFuncs[ 0 ] ) ) ) && ( MoveStartFuncs[ move ] ) )
|
|
{
|
|
( this->*MoveStartFuncs[ move ] )();
|
|
}
|
|
}
|
|
|
|
// This seems breaks the secret move mode because it's called at a bad time and causes the client/server angles
|
|
// to get out of sync because delta_angles is not updated correctly.
|
|
// I don't think it's necessary to call it anyway, so I'm removing it.
|
|
//SetViewAngles( v_angle );
|
|
}
|
|
}
|
|
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.WDPrintf( "Possible infinite loop in state '%s'\n", currentState_Legs->getName() );
|
|
assert( 0 );
|
|
if ( count > 20 )
|
|
{
|
|
gi.Error( ERR_DROP, "Stopping due to possible infinite state loop\n" );
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( !currentState_Legs )
|
|
{
|
|
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 ( laststate_Legs != 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 ( !animate->HasAnim(legsAnim) )
|
|
legsAnim = getGameplayAnim(legsAnim);
|
|
if ( legsAnim == "" )
|
|
{
|
|
partAnim[ legs ] = "";
|
|
animate->ClearLegsAnim();
|
|
}
|
|
else if ( legsAnim != "none" )
|
|
{
|
|
if ( !vehicle )
|
|
SetAnim( legsAnim, legs );
|
|
}
|
|
}
|
|
}
|
|
while( laststate_Legs != currentState_Legs );
|
|
}
|
|
else
|
|
{
|
|
currentState_Legs = NULL;
|
|
}
|
|
|
|
if ( g_showplayeranim->integer )
|
|
{
|
|
if ( last_leg_anim_name != animate->AnimName( legs ) )
|
|
{
|
|
gi.DPrintf( "Legs change from %s to %s\n", last_leg_anim_name.c_str(), animate->AnimName( legs ) );
|
|
last_leg_anim_name = animate->AnimName( legs );
|
|
}
|
|
|
|
if ( last_torso_anim_name != animate->AnimName( torso ) )
|
|
{
|
|
gi.DPrintf( "Torso change from %s to %s\n", last_torso_anim_name.c_str(), animate->AnimName( torso ) );
|
|
last_torso_anim_name = animate->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" );
|
|
}
|
|
}
|
|
|
|
if ( g_showplayerweapon->integer )
|
|
{
|
|
Weapon *weapon;
|
|
|
|
weapon = GetActiveWeapon( WEAPON_DUAL );
|
|
|
|
if ( !weapon )
|
|
weapon = GetActiveWeapon( WEAPON_RIGHT );
|
|
|
|
if ( !weapon )
|
|
weapon = GetActiveWeapon( WEAPON_LEFT );
|
|
|
|
if ( weapon )
|
|
{
|
|
gi.DPrintf( "Weapon - anim %s, frame %d\n", weapon->animate->GetName().c_str(), weapon->animate->CurrentFrame() );
|
|
}
|
|
}
|
|
|
|
// This is so we don't remember pain when we change to a state that has a PAIN condition
|
|
pain = 0;
|
|
// Every second drop accumulated pain by 1
|
|
if ( ( float )( int )( level.time ) == level.time )
|
|
{
|
|
accumulated_pain -= 1.0f;
|
|
if ( accumulated_pain < 0.0f )
|
|
accumulated_pain = 0.0f;
|
|
}
|
|
}
|
|
|
|
void Player::EventUseItem( Event *ev )
|
|
{
|
|
const char *name;
|
|
weaponhand_t hand = WEAPON_DUAL;
|
|
|
|
if ( deadflag || _disableUseWeapon )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( multiplayerManager.inMultiplayer() && ( !multiplayerManager.isFightingAllowed() || multiplayerManager.isPlayerSpectator( this ) ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
name = ev->GetString( 1 );
|
|
|
|
GameplayManager *gpm = GameplayManager::getTheGameplayManager();
|
|
|
|
str objectName("CurrentPlayer.");
|
|
objectName += name ;
|
|
if ( gpm->hasProperty( objectName, "name" ) )
|
|
name = gpm->getStringValue( objectName, "name" );
|
|
else if ( gpm->hasProperty(name, "consumable" ) )
|
|
{
|
|
str slotname = gpm->getStringValue(name, "invslot");
|
|
if ( !gpm->hasProperty(slotname, "quantity") )
|
|
return;
|
|
|
|
float quantity = gpm->getFloatValue(slotname, "quantity");
|
|
if ( quantity < 1.0f )
|
|
return;
|
|
|
|
// Give the model, decrement the quantity
|
|
str model = gpm->getStringValue(name, "model");
|
|
giveItem(model);
|
|
gpm->setFloatValue(slotname, "quantity", quantity-1.0f);
|
|
}
|
|
|
|
Item *item = ( Item * )FindItem( name );
|
|
|
|
if ( item && item->isSubclassOf( InventoryItem ) )
|
|
{
|
|
InventoryItem *ii = ( InventoryItem * )item;
|
|
Event *ev1;
|
|
|
|
ev1 = new Event( EV_InventoryItem_Use );
|
|
ev1->AddEntity( this );
|
|
ii->ProcessEvent( ev1 );
|
|
return;
|
|
}
|
|
else if ( ev->NumArgs() > 1 )
|
|
{
|
|
hand = WeaponHandNameToNum( ev->GetString( 2 ) );
|
|
}
|
|
|
|
useWeapon( name, hand );
|
|
}
|
|
|
|
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];
|
|
int numEvents;
|
|
float postTime;
|
|
|
|
|
|
if ( deadflag )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( !gi.isClientActive( this->edict ) )
|
|
{
|
|
PostEvent( *ev, FRAMETIME );
|
|
return;
|
|
}
|
|
|
|
numEvents = 0;
|
|
postTime = 0.0f;
|
|
|
|
if ( gi.FS_ReadFile( "global/giveall.scr", ( void ** )&buf, true ) != -1 )
|
|
{
|
|
buffer = buf;
|
|
|
|
while ( 1 )
|
|
{
|
|
strcpy( com_token, COM_ParseExt( &buffer, true ) );
|
|
|
|
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, false ) );
|
|
if (!com_token[0])
|
|
break;
|
|
|
|
ev->AddToken( com_token );
|
|
}
|
|
|
|
if ( numEvents >= 5 )
|
|
{
|
|
numEvents = 0;
|
|
//postTime += level.frametime * 4;
|
|
postTime += 1.0f;
|
|
}
|
|
|
|
PostEvent( ev, postTime );
|
|
|
|
numEvents++;
|
|
}
|
|
|
|
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->GetSource() == EV_FROM_CONSOLE )
|
|
{
|
|
if ( !( flags & FL_GODMODE ) )
|
|
{
|
|
msg = "godmode OFF\n";
|
|
}
|
|
else
|
|
{
|
|
msg = "godmode ON\n";
|
|
}
|
|
|
|
gi.SendServerCommand( edict-g_entities, "print \"%s\"", msg );
|
|
}
|
|
}
|
|
|
|
void Player::Kill( Event * )
|
|
{
|
|
if ( ( level.time - respawn_time ) < 5.0f )
|
|
{
|
|
return;
|
|
}
|
|
|
|
flags &= ~FL_GODMODE;
|
|
health = 1.0f;
|
|
Damage( this, this, 10.0f, origin, vec_zero, vec_zero, 0, DAMAGE_NO_PROTECTION, MOD_SUICIDE );
|
|
}
|
|
|
|
void Player::NoTargetCheat( Event * )
|
|
{
|
|
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 );
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: NoclipCheat
|
|
// Class: Player
|
|
//
|
|
// Description: This is the event that puts the player in noclip mode
|
|
//
|
|
// Parameters: Event *ev - No params
|
|
//
|
|
// Returns: None
|
|
//
|
|
//--------------------------------------------------------------
|
|
void Player::NoclipCheat( Event * )
|
|
{
|
|
const char *msg;
|
|
|
|
if ( vehicle )
|
|
msg = "Must exit vehicle first\n";
|
|
else if ( getMoveType() == MOVETYPE_NOCLIP )
|
|
{
|
|
setMoveType( MOVETYPE_WALK );
|
|
msg = "noclip OFF\n";
|
|
|
|
// reset the state machine so that her animations are correct
|
|
SetState("STAND", "STAND");
|
|
}
|
|
else
|
|
{
|
|
client->ps.feetfalling = false;
|
|
movecontrol = MOVECONTROL_USER;
|
|
|
|
setMoveType( MOVETYPE_NOCLIP );
|
|
msg = "noclip ON\n";
|
|
}
|
|
|
|
gi.SendServerCommand( edict-g_entities, "print \"%s\"", msg );
|
|
}
|
|
|
|
void Player::GameVersion( Event * )
|
|
{
|
|
gi.SendServerCommand( edict-g_entities, "print \"%s : %s\n\"", GAME_NAME, __DATE__ );
|
|
}
|
|
|
|
void Player::SetFov( float newFov, bool forced )
|
|
{
|
|
fov = newFov;
|
|
|
|
if ( !forced && ( fov != sv_defaultFov->value ) && multiplayerManager.checkFlag( MP_FLAG_FIXED_FOV ) )
|
|
{
|
|
fov = sv_defaultFov->value;
|
|
return;
|
|
}
|
|
|
|
//if ( !forced )
|
|
//{
|
|
// _userFovChoice = newFov;
|
|
//}
|
|
|
|
if ( fov < 1.0f )
|
|
{
|
|
fov = sv_defaultFov->value;
|
|
}
|
|
else if ( fov > 160.0f )
|
|
{
|
|
fov = 160.0f;
|
|
}
|
|
|
|
str tempString( fov );
|
|
gi.cvar_set( "r_fov", tempString.c_str() );
|
|
}
|
|
|
|
float Player::getDefaultFov( void )
|
|
{
|
|
if ( multiplayerManager.inMultiplayer() && multiplayerManager.checkFlag( MP_FLAG_FIXED_FOV ) )
|
|
return sv_defaultFov->value;
|
|
else
|
|
//return _userFovChoice;
|
|
return userFov;
|
|
}
|
|
|
|
void Player::Fov( Event *ev )
|
|
{
|
|
CancelEventsOfType(EV_Player_Fov);
|
|
if ( ev->NumArgs() > 1 )
|
|
{
|
|
Event *event = new Event( EV_Player_Fov );
|
|
event->AddFloat( ev->GetFloat( 1 ) );
|
|
PostEvent ( event, ev->GetFloat( 2 ) );
|
|
return;
|
|
}
|
|
|
|
if ( ev->NumArgs() < 1 )
|
|
{
|
|
gi.SendServerCommand( edict-g_entities, "print \"Fov = %d\n\"", fov );
|
|
return;
|
|
}
|
|
|
|
SetFov( ev->GetFloat( 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.0f ? 4.0f : -4.0f;
|
|
side = fabs( side );
|
|
|
|
value = sv_rollangle->value;
|
|
|
|
if ( side < sv_rollspeed->value )
|
|
{
|
|
side = side * value / sv_rollspeed->value;
|
|
}
|
|
else
|
|
{
|
|
side = value;
|
|
}
|
|
|
|
return side * sign;
|
|
}
|
|
|
|
void Player::GravityNodes( void )
|
|
{
|
|
Vector grav;
|
|
Vector gravnorm;
|
|
Vector velnorm;
|
|
float dot;
|
|
qboolean force;
|
|
float max_speed;
|
|
Vector new_velocity;
|
|
|
|
//
|
|
// Check for gravity pulling points
|
|
//
|
|
|
|
// no pull during waterjumps
|
|
if ( client->ps.pm_flags & PMF_TIME_WATERJUMP )
|
|
{
|
|
return;
|
|
}
|
|
|
|
grav = gravPathManager.CalculateGravityPull( *this, origin, &force, &max_speed );
|
|
|
|
// Check for unfightable gravity.
|
|
if ( force && ( grav != vec_zero ) )
|
|
{
|
|
velnorm = velocity;
|
|
velnorm.normalize();
|
|
|
|
gravnorm = grav;
|
|
gravnorm.normalize();
|
|
|
|
dot = ( gravnorm.x * velnorm.x ) + ( gravnorm.y * velnorm.y ) + ( gravnorm.z * velnorm.z );
|
|
|
|
// This prevents the player from trying to swim upstream
|
|
if ( dot < 0.0f )
|
|
{
|
|
float tempdot;
|
|
Vector tempvec;
|
|
|
|
tempdot = 0.2f - dot;
|
|
tempvec = velocity * tempdot;
|
|
velocity = velocity - tempvec;
|
|
}
|
|
}
|
|
|
|
if ( grav != vec_zero )
|
|
{
|
|
new_velocity = velocity + grav;
|
|
|
|
if ( new_velocity.length() < velocity.length() )
|
|
{
|
|
// Is slowing down, defintely need to apply grav
|
|
velocity = new_velocity;
|
|
}
|
|
else if ( velocity.length() < max_speed )
|
|
{
|
|
// Applay grav
|
|
|
|
velocity = new_velocity;
|
|
|
|
// Make sure we aren't making the player go too fast
|
|
|
|
if ( velocity.length() > max_speed )
|
|
{
|
|
velocity.normalize();
|
|
velocity *= max_speed;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Going too fast but still want to pull the player up if any z velocity in grav
|
|
|
|
grav.x = 0;
|
|
grav.y = 0;
|
|
|
|
velocity = velocity + grav;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// PMove Events
|
|
//
|
|
void Player::ProcessPmoveEvents( int event )
|
|
{
|
|
float damage;
|
|
|
|
switch( event )
|
|
{
|
|
case EV_NONE:
|
|
break;
|
|
case EV_FALL_VERY_SHORT:
|
|
case EV_FALL_SHORT:
|
|
case EV_FALL_MEDIUM:
|
|
case EV_FALL_FAR:
|
|
case EV_FALL_VERY_FAR:
|
|
case EV_FALL_FATAL:
|
|
damage = 0.0f;
|
|
if ( event == EV_FALL_VERY_SHORT )
|
|
damage = 5.0f;
|
|
else if ( event == EV_FALL_SHORT )
|
|
damage = 10.0f;
|
|
else if ( event == EV_FALL_MEDIUM )
|
|
damage = 25.0f;
|
|
else if ( event == EV_FALL_FAR )
|
|
damage = 50.0f;
|
|
else if ( event == EV_FALL_VERY_FAR )
|
|
damage = 100.0f;
|
|
else if ( event == EV_FALL_FATAL )
|
|
damage = 1000.0f;
|
|
|
|
if ( !multiplayerManager.checkFlag( MP_FLAG_NO_FALLING ) )
|
|
{
|
|
Damage( world, world, damage, origin, vec_zero, vec_zero, 0, DAMAGE_NO_ARMOR, MOD_FALLING );
|
|
}
|
|
break;
|
|
case EV_TERMINAL_VELOCITY:
|
|
Sound( "snd_fall", CHAN_VOICE );
|
|
break;
|
|
|
|
case EV_WATER_TOUCH: // foot touches
|
|
if ( watertype & CONTENTS_LAVA )
|
|
{
|
|
Sound( "snd_burn", CHAN_LOCAL );
|
|
}
|
|
else
|
|
{
|
|
Entity *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.0f, 0.0f, 90.0f );
|
|
trace = G_Trace( start, vec_zero, vec_zero, origin, NULL, MASK_WATER, false, "ProcessPmoveEvents" );
|
|
|
|
// Figure out a good scale for the splash
|
|
|
|
scale = 1.0f + ( velocity[2] + 400.0f ) / -1500.0f;
|
|
|
|
if ( scale < 1.0f )
|
|
scale = 1.0f;
|
|
else if ( scale > 1.5f )
|
|
scale = 1.5f;
|
|
|
|
// Spawn in a water splash
|
|
|
|
water = new Entity( ENTITY_CREATE_FLAG_ANIMATE );
|
|
|
|
water->setOrigin( trace.endpos );
|
|
water->setModel( "fx_splashsmall.tik" );
|
|
water->setScale( scale );
|
|
water->animate->RandomAnimate( "idle" );
|
|
water->PostEvent( EV_Remove, 5.0f );
|
|
|
|
}
|
|
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;
|
|
}
|
|
|
|
if ( movetype == MOVETYPE_NOCLIP )
|
|
{
|
|
// don't need air
|
|
air_finished = level.time + 20.0f;
|
|
return;
|
|
}
|
|
|
|
//
|
|
// check for on fire
|
|
//
|
|
if ( on_fire )
|
|
{
|
|
if ( next_painsound_time < level.time )
|
|
{
|
|
next_painsound_time = level.time + 4.0f;
|
|
Sound( "snd_onfire", CHAN_LOCAL );
|
|
}
|
|
}
|
|
|
|
//
|
|
// check for lava
|
|
//
|
|
if ( watertype & CONTENTS_LAVA )
|
|
{
|
|
if ( next_drown_time < level.time )
|
|
{
|
|
next_drown_time = level.time + 0.2f;
|
|
Damage( world, world, 10.0f * waterlevel, origin, vec_zero, vec_zero, 0, DAMAGE_NO_ARMOR, MOD_LAVA );
|
|
}
|
|
if ( next_painsound_time < level.time )
|
|
{
|
|
next_painsound_time = level.time + 3.0f;
|
|
Sound( "snd_burned", CHAN_LOCAL );
|
|
}
|
|
}
|
|
|
|
//
|
|
// check for slime
|
|
//
|
|
if ( watertype & CONTENTS_SLIME )
|
|
{
|
|
if ( next_drown_time < level.time )
|
|
{
|
|
next_drown_time = level.time + 0.4f;
|
|
Damage( world, world, 7.0f * waterlevel, origin, vec_zero, vec_zero, 0, DAMAGE_NO_ARMOR, MOD_SLIME );
|
|
}
|
|
if ( next_painsound_time < level.time )
|
|
{
|
|
next_painsound_time = level.time + 5.0f;
|
|
Sound( "snd_burned", CHAN_LOCAL );
|
|
}
|
|
}
|
|
|
|
//
|
|
// check for drowning
|
|
//
|
|
if ( waterlevel == 3 )
|
|
{
|
|
// if out of air, start drowning
|
|
if ( ( air_finished < level.time ) && !( flags & FL_GODMODE ) )
|
|
{
|
|
// drown!
|
|
if ( ( next_drown_time < level.time ) && ( health > 0 ) )
|
|
{
|
|
next_drown_time = level.time + 1.0f;
|
|
|
|
// take more damage the longer underwater
|
|
drown_damage += 2.0f;
|
|
if ( drown_damage > 15.0f )
|
|
{
|
|
drown_damage = 15.0f;
|
|
}
|
|
|
|
// play a gurp sound instead of a normal pain sound
|
|
if ( health <= drown_damage )
|
|
{
|
|
Sound( "snd_drown", CHAN_LOCAL );
|
|
BroadcastSound();
|
|
}
|
|
else if ( rand() & 1 )
|
|
{
|
|
Sound( "snd_choke", CHAN_LOCAL );
|
|
BroadcastSound();
|
|
}
|
|
else
|
|
{
|
|
Sound( "snd_choke", CHAN_LOCAL );
|
|
BroadcastSound();
|
|
}
|
|
|
|
Damage( world, world, drown_damage, origin, vec_zero, vec_zero, 0, DAMAGE_NO_ARMOR, MOD_DROWN );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
air_finished = level.time + 20.0f;
|
|
drown_damage = 2.0f;
|
|
}
|
|
|
|
GravityNodes();
|
|
|
|
old_waterlevel = waterlevel;
|
|
}
|
|
|
|
/*
|
|
=============
|
|
AddBlend
|
|
=============
|
|
*/
|
|
void Player::AddBlend( float r, float g, float b, float a )
|
|
{
|
|
float a2;
|
|
float a3;
|
|
|
|
if ( a <= 0.0f )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// new total alpha
|
|
a2 = blend[ 3 ] + ( 1.0f - blend[ 3 ] ) * a;
|
|
|
|
// fraction of color from old
|
|
a3 = blend[ 3 ] / a2;
|
|
|
|
blend[ 0 ] = ( blend[ 0 ] * a3 ) + ( r * ( 1.0f - a3 ) );
|
|
blend[ 1 ] = ( blend[ 1 ] * a3 ) + ( g * ( 1.0f - a3 ) );
|
|
blend[ 2 ] = ( blend[ 2 ] * a3 ) + ( b * ( 1.0f - a3 ) );
|
|
blend[ 3 ] = a2;
|
|
}
|
|
|
|
/*
|
|
=============
|
|
SetBlend
|
|
=============
|
|
*/
|
|
void Player::SetBlend( float r, float g, float b, float a, int additive )
|
|
{
|
|
client->ps.blend[ 0 ] = r;
|
|
client->ps.blend[ 1 ] = g;
|
|
client->ps.blend[ 2 ] = b;
|
|
client->ps.blend[ 3 ] = a;
|
|
|
|
client->ps.stats[ STAT_ADDFADE ] = additive;
|
|
}
|
|
|
|
void Player::SetBlend( int additive )
|
|
{
|
|
SetBlend( blend[ 0 ], blend[ 1 ], blend[ 2 ], blend[ 3], additive );
|
|
}
|
|
|
|
/*
|
|
=============
|
|
CalcBlend
|
|
=============
|
|
*/
|
|
void Player::CalcBlend( void )
|
|
{
|
|
int contents;
|
|
Vector vieworg;
|
|
Vector viewModeColor;
|
|
float viewModeAlpha;
|
|
qboolean viewModeAdditive;
|
|
|
|
client->ps.stats[STAT_ADDFADE] = 0;
|
|
blend[ 0 ] = blend[ 1 ] = blend[ 2 ] = blend[ 3 ] = 0;
|
|
SetBlend( false );
|
|
|
|
// Set to view mode blend if necessary
|
|
|
|
if ( gi.GetViewModeScreenBlend( getViewMode(), viewModeColor, &viewModeAlpha, &viewModeAdditive ) )
|
|
{
|
|
AddBlend( viewModeColor[ 0 ], viewModeColor[ 1 ], viewModeColor[ 2 ], viewModeAlpha );
|
|
SetBlend( viewModeAdditive );
|
|
|
|
return;
|
|
}
|
|
|
|
// add for contents
|
|
vieworg = origin;
|
|
vieworg[ 2 ] += viewheight;
|
|
|
|
contents = gi.pointcontents( vieworg, 0 );
|
|
|
|
if ( flags & FL_STUNNED )
|
|
{
|
|
AddBlend( 0.0f, 0.0f, 0.5f, 0.1f );
|
|
SetBlend( true );
|
|
}
|
|
else 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 );
|
|
SetBlend( true );
|
|
}
|
|
else if ( contents & CONTENTS_WATER )
|
|
{
|
|
AddBlend( level.water_color[0], level.water_color[1], level.water_color[2], level.water_alpha );
|
|
SetBlend( true );
|
|
}
|
|
else if ( contents & CONTENTS_SLIME )
|
|
{
|
|
AddBlend( level.slime_color[0], level.slime_color[1], level.slime_color[2], level.slime_alpha );
|
|
SetBlend( true );
|
|
}
|
|
|
|
// add for damage
|
|
if ( _doDamageScreenFlash && ( damage_alpha > 0 ) )
|
|
{
|
|
AddBlend( damage_blend[ 0 ], damage_blend[ 1 ], damage_blend[ 2 ], damage_alpha );
|
|
SetBlend( false );
|
|
|
|
// drop the damage value
|
|
/* damage_alpha -= 0.06;
|
|
|
|
if ( damage_alpha < 0 )
|
|
{
|
|
damage_alpha = 0;
|
|
} */
|
|
}
|
|
|
|
// Add screen flash
|
|
|
|
if ( level.time < _flashMaxTime )
|
|
{
|
|
float currentFlashAlpha;
|
|
|
|
currentFlashAlpha = _flashAlpha;
|
|
|
|
if ( level.time > _flashMinTime )
|
|
{
|
|
currentFlashAlpha = _flashAlpha * ( _flashMaxTime - level.time ) / ( _flashMaxTime - _flashMinTime );
|
|
}
|
|
|
|
AddBlend( _flashBlend[ 0 ], _flashBlend[ 1 ], _flashBlend[ 2 ], currentFlashAlpha );
|
|
SetBlend( false );
|
|
}
|
|
|
|
|
|
// 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.0f ) && ( 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.0f )
|
|
alpha = level.m_fade_time / level.m_fade_time_start;
|
|
|
|
if ( level.m_fade_type == fadeout )
|
|
alpha = 1.0f - alpha;
|
|
|
|
if ( alpha < 0.0f )
|
|
alpha = 0.0f;
|
|
|
|
if ( alpha > 1.0f )
|
|
alpha = 1.0f;
|
|
|
|
if ( level.m_fade_style == additive )
|
|
{
|
|
if ( client->ps.stats[STAT_ADDFADE] == 1 )
|
|
{
|
|
AddBlend( level.m_fade_color[0] * level.m_fade_alpha * alpha, level.m_fade_color[1] * level.m_fade_alpha * alpha,
|
|
level.m_fade_color[2] * level.m_fade_alpha * alpha, level.m_fade_alpha * alpha );
|
|
SetBlend( true );
|
|
}
|
|
else
|
|
{
|
|
SetBlend( level.m_fade_color[0] * level.m_fade_alpha * alpha, level.m_fade_color[1] * level.m_fade_alpha * alpha,
|
|
level.m_fade_color[2] * level.m_fade_alpha * alpha, level.m_fade_alpha * alpha, true );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetBlend( level.m_fade_color[0], level.m_fade_color[1], level.m_fade_color[2], level.m_fade_alpha * alpha, false );
|
|
}
|
|
}
|
|
|
|
void Player::setFlash( const Vector &color, float alpha, float minTime, float maxTime )
|
|
{
|
|
_flashBlend = color;
|
|
_flashAlpha = alpha;
|
|
_flashMinTime = level.time + minTime;
|
|
_flashMaxTime = level.time + maxTime;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
P_DamageFeedback
|
|
|
|
Handles color blends and view kicks
|
|
===============
|
|
*/
|
|
|
|
#define DAMAGE_MAX_PITCH_SCALE 0.3f
|
|
#define DAMAGE_MAX_YAW_SCALE 0.3f
|
|
|
|
void Player::DamageFeedback( void )
|
|
{
|
|
if ( _lastDamagedTimeFront + 0.25f >= level.time )
|
|
client->ps.pm_flags |= PMF_DAMAGE_FRONT;
|
|
else
|
|
client->ps.pm_flags &= ~PMF_DAMAGE_FRONT;
|
|
|
|
if ( _lastDamagedTimeBack + 0.25f >= level.time )
|
|
client->ps.pm_flags |= PMF_DAMAGE_BACK;
|
|
else
|
|
client->ps.pm_flags &= ~PMF_DAMAGE_BACK;
|
|
|
|
if ( _lastDamagedTimeLeft + 0.25f >= level.time )
|
|
client->ps.pm_flags |= PMF_DAMAGE_LEFT;
|
|
else
|
|
client->ps.pm_flags &= ~PMF_DAMAGE_LEFT;
|
|
|
|
if ( _lastDamagedTimeRight + 0.25f >= level.time )
|
|
client->ps.pm_flags |= PMF_DAMAGE_RIGHT;
|
|
else
|
|
client->ps.pm_flags &= ~PMF_DAMAGE_RIGHT;
|
|
|
|
// if we are dead, don't setup any feedback
|
|
|
|
if ( health <= 0.0f )
|
|
{
|
|
damage_count = 0;
|
|
damage_blood = 0;
|
|
damage_alpha = 0;
|
|
VectorClear( damage_angles );
|
|
return;
|
|
}
|
|
|
|
if ( damage_blood > damage_count )
|
|
{
|
|
Vector delta;
|
|
Vector damageDir;
|
|
|
|
//damageDir = damage_from * -1.0f;
|
|
damageDir = damage_from;
|
|
|
|
delta = damageDir.toAngles();
|
|
|
|
delta[ PITCH ] = AngleDelta( delta[ PITCH ], v_angle[ PITCH ] );
|
|
delta[ YAW ] = AngleDelta( delta[ YAW ], v_angle[ YAW ] );
|
|
delta[ ROLL ] = AngleDelta( delta[ ROLL ], v_angle[ ROLL ] );
|
|
|
|
// Dim it down by a factor of a hundred so we can multiple it by our built up damage later
|
|
|
|
delta *= 0.01f;
|
|
|
|
damage_angles = delta;
|
|
}
|
|
|
|
if ( damage_count > 0 )
|
|
{
|
|
// decay damage_count over time
|
|
|
|
if ( damage_count * 0.1f < 0.25f )
|
|
{
|
|
damage_count -= 0.25f;
|
|
}
|
|
else
|
|
{
|
|
damage_count *= 0.9f;
|
|
}
|
|
|
|
if ( damage_count < 0.1f )
|
|
{
|
|
damage_count = 0;
|
|
}
|
|
}
|
|
|
|
damage_count += damage_blood;
|
|
|
|
if ( damage_count <= 0.0f )
|
|
{
|
|
damage_alpha = 0.0f;
|
|
return;
|
|
}
|
|
|
|
// the total alpha of the blend is always proportional to count
|
|
|
|
damage_alpha = damage_count / 25.0f;
|
|
|
|
// Make sure the alpha is within a reasonable range
|
|
|
|
if ( damage_alpha < 0.1f )
|
|
{
|
|
damage_alpha = 0.1f;
|
|
}
|
|
else if ( damage_alpha > 0.6f )
|
|
{
|
|
damage_alpha = 0.6f;
|
|
}
|
|
|
|
//damage_blend = 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 );
|
|
}
|
|
}
|
|
|
|
#define EARTHQUAKE_SCREENSHAKE_PITCH 2
|
|
#define EARTHQUAKE_SCREENSHAKE_YAW 2
|
|
#define EARTHQUAKE_SCREENSHAKE_ROLL 3
|
|
|
|
void Player::SetClientViewAngles( const Vector &position, const float cameraoffset, const Vector &ang, const Vector &vel, const float camerafov ) const
|
|
{
|
|
if ( client->ps.useCameraFocalPoint )
|
|
{
|
|
client->ps.cameraFocalPoint[ 0 ] = position[ 0 ];
|
|
client->ps.cameraFocalPoint[ 1 ] = position[ 1 ];
|
|
client->ps.cameraFocalPoint[ 2 ] = position[ 2 ] + cameraoffset + 18.0f;
|
|
}
|
|
|
|
client->ps.origin[ 0 ] = position[ 0 ];
|
|
client->ps.origin[ 1 ] = position[ 1 ];
|
|
client->ps.origin[ 2 ] = position[ 2 ];
|
|
|
|
client->ps.viewheight = (int) cameraoffset;
|
|
|
|
client->ps.viewangles[ 0 ] = ang[ 0 ];
|
|
client->ps.viewangles[ 1 ] = ang[ 1 ];
|
|
client->ps.viewangles[ 2 ] = ang[ 2 ];
|
|
|
|
client->ps.velocity[ 0 ] = vel[ 0 ];
|
|
client->ps.velocity[ 1 ] = vel[ 1 ];
|
|
client->ps.velocity[ 2 ] = vel[ 2 ];
|
|
|
|
client->ps.fov = camerafov;
|
|
}
|
|
|
|
void Player::ShakeCamera( void )
|
|
{
|
|
// Shake the player's view
|
|
|
|
VectorClear( client->ps.damage_angles );
|
|
|
|
// Don't shake camera if in cinematic and not allowed to
|
|
|
|
if ( ( playerCameraMode == PLAYER_CAMERA_MODE_CINEMATIC ) && !world->canShakeCamera() )
|
|
return;
|
|
|
|
// Add earthquake shaking
|
|
|
|
float earthquakeMagnitude = level.getEarthquakeMagnitudeAtPosition( origin );
|
|
|
|
if ( earthquakeMagnitude > 0.0f )
|
|
{
|
|
client->ps.damage_angles[ PITCH ] += G_CRandom() * earthquakeMagnitude * EARTHQUAKE_SCREENSHAKE_PITCH;
|
|
client->ps.damage_angles[ YAW ] += G_CRandom() * earthquakeMagnitude * EARTHQUAKE_SCREENSHAKE_YAW;
|
|
client->ps.damage_angles[ ROLL ] += G_CRandom() * earthquakeMagnitude * EARTHQUAKE_SCREENSHAKE_ROLL;
|
|
}
|
|
|
|
// Don't do anything else to the camera if in a cinematic
|
|
|
|
if ( playerCameraMode == PLAYER_CAMERA_MODE_CINEMATIC )
|
|
return;
|
|
|
|
VectorAdd( client->ps.damage_angles, getWeaponViewShake(), client->ps.damage_angles );
|
|
|
|
// Add damage shaking
|
|
|
|
if ( damage_count && sv_showdamageshake->integer )
|
|
{
|
|
if ( health <= 0.0f )
|
|
{
|
|
damage_angles = vec_zero;
|
|
}
|
|
else if ( multiplayerManager.inMultiplayer() )
|
|
{
|
|
damage_angles[ YAW ] = G_CRandom( 0.05f );
|
|
damage_angles[ PITCH ] = G_CRandom( 0.05f );
|
|
damage_angles[ ROLL ] = G_CRandom( 0.05f );
|
|
}
|
|
else
|
|
{
|
|
damage_angles[ YAW ] = G_CRandom( 0.2f );
|
|
damage_angles[ PITCH ] = G_CRandom( 0.2f );
|
|
damage_angles[ ROLL ] = G_CRandom( 0.2f );
|
|
}
|
|
|
|
client->ps.damage_angles[ YAW ] += damage_angles[ YAW ] * damage_count;
|
|
client->ps.damage_angles[ PITCH ] += damage_angles[ PITCH ] * damage_count;
|
|
client->ps.damage_angles[ ROLL ] += damage_angles[ ROLL ] * damage_count;
|
|
}
|
|
|
|
if ( client->pers.mp_lowBandwidth )
|
|
{
|
|
client->ps.damage_angles[ YAW ] = 0.0f;
|
|
client->ps.damage_angles[ PITCH ] = 0.0f;
|
|
client->ps.damage_angles[ ROLL ] = 0.0f;
|
|
}
|
|
}
|
|
|
|
|
|
void Player::SetPlayerViewUsingNoClipController( void )
|
|
{
|
|
client->ps.pm_flags &= ~PMF_CAMERA_VIEW;
|
|
|
|
// Force camera to behind in NOCLIP
|
|
client->ps.camera_flags = client->ps.camera_flags & CF_CAMERA_CUT_BIT;
|
|
}
|
|
|
|
void Player::SetPlayerViewUsingCinematicController( Camera *camera )
|
|
{
|
|
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 ];
|
|
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;
|
|
|
|
ShakeCamera();
|
|
}
|
|
|
|
|
|
void Player::SetPlayerViewUsingActorController( Camera *camera )
|
|
{
|
|
if ( actor_camera )
|
|
{
|
|
// Find the focal point ( either the actor's watch offset or top of the bounding box)
|
|
|
|
// Go a little above the view height
|
|
|
|
actor_camera->origin = origin;
|
|
actor_camera->origin[2] += client->ps.pm_defaultviewheight + 10.f;
|
|
|
|
// Shift the camera back just a little
|
|
|
|
Vector forward;
|
|
Vector left;
|
|
angles.AngleVectors( &forward, &left );
|
|
actor_camera->origin -= forward * 15.0f;
|
|
|
|
// Shift the camera a little to the left or right
|
|
actor_camera->origin -= left * 15.0f;
|
|
|
|
// Set the camera's position
|
|
|
|
actor_camera->setOrigin( actor_camera->origin );
|
|
|
|
// Set the camera's angles
|
|
|
|
actor_camera->setAngles( angles );
|
|
|
|
// Set this as our camera
|
|
|
|
SetCamera( actor_camera, 0.5f );
|
|
|
|
}
|
|
else if ( ( level.automatic_cameras.NumObjects() > 0 ) && ( !camera || camera->IsAutomatic() ) )
|
|
{
|
|
// if we currently are not in a camera or the camera we are looking through is automatic, evaluate our camera choices
|
|
AutomaticallySelectedNewCamera();
|
|
}
|
|
|
|
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 ];
|
|
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;
|
|
}
|
|
|
|
void Player::SetPlayerViewUsingEntityWatchingController( void )
|
|
{
|
|
|
|
SetPlayerViewNormal();
|
|
|
|
// Find the focal point ( either the actor's watch offset or top of the bounding box)
|
|
|
|
Vector focal_point;
|
|
if ( entity_to_watch->watch_offset != vec_zero )
|
|
{
|
|
MatrixTransformVector( entity_to_watch->watch_offset, entity_to_watch->orientation, focal_point );
|
|
focal_point += entity_to_watch->origin;
|
|
focal_point[2] += client->ps.pm_defaultviewheight + 18.0f;
|
|
}
|
|
else
|
|
{
|
|
focal_point = entity_to_watch->origin;
|
|
focal_point[2] += client->ps.pm_defaultviewheight + 18.0f;
|
|
}
|
|
|
|
if ( client->ps.useCameraFocalPoint )
|
|
{
|
|
client->ps.cameraFocalPoint[ 0 ] = focal_point[ 0 ];
|
|
client->ps.cameraFocalPoint[ 1 ] = focal_point[ 1 ];
|
|
client->ps.cameraFocalPoint[ 2 ] = focal_point[ 2 ];
|
|
}
|
|
|
|
}
|
|
|
|
void Player::SetPlayerViewNormal( void )
|
|
{
|
|
client->ps.pm_flags &= ~PMF_CAMERA_VIEW;
|
|
|
|
//
|
|
// make sure the third person camera is setup correctly.
|
|
//
|
|
|
|
int 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;
|
|
bool do_cut = false;
|
|
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;
|
|
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;
|
|
do_cut = true;
|
|
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.0f ) > 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:
|
|
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:
|
|
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:
|
|
client->ps.camera_offset[ YAW ] = 0;
|
|
client->ps.camera_offset[ PITCH ] = 0;
|
|
break;
|
|
default:
|
|
client->ps.camera_offset[ YAW ] = 0;
|
|
client->ps.camera_offset[ PITCH ] = 0;
|
|
break;
|
|
}
|
|
last_camera_type = camera_type;
|
|
if ( do_cut )
|
|
CameraCut();
|
|
}
|
|
|
|
// Add weapon shaking
|
|
ShakeCamera();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::SetupView( void )
|
|
{
|
|
// Check for change of state
|
|
// These switch statements are indicative that we need a polymorphic set of classes based off a base class called PlayerCameraController
|
|
switch( playerCameraMode )
|
|
{
|
|
case PLAYER_CAMERA_MODE_NORMAL:
|
|
case PLAYER_CAMERA_MODE_CINEMATIC:
|
|
break;
|
|
|
|
case PLAYER_CAMERA_MODE_ACTOR:
|
|
{
|
|
if ( !entity_to_watch || entity_to_watch->deadflag )
|
|
{
|
|
DestroyActorCamera();
|
|
}
|
|
else
|
|
{
|
|
trace_t trace = G_Trace( actor_camera->origin, Vector(-5, -5, -5), Vector(5, 5, 5), actor_camera->origin, actor_camera, MASK_DEADSOLID, false, "SetupView" );
|
|
if ( trace.startsolid )
|
|
{
|
|
DestroyActorCamera();
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case PLAYER_CAMERA_MODE_ENTITY_WATCHING:
|
|
// See if we still want to watch this actor
|
|
{
|
|
if ( entity_to_watch )
|
|
{
|
|
Vector cameraPosition;
|
|
Vector cameraAngles;
|
|
GetPlayerView( &cameraPosition, &cameraAngles );
|
|
Vector directionToWatchedEntity( entity_to_watch->origin - cameraPosition );
|
|
Vector cameraForward;
|
|
cameraAngles.AngleVectors( &cameraForward );
|
|
const float angleToWatchedEntity = RAD2DEG( Vector::AngleBetween( directionToWatchedEntity, cameraForward ) );
|
|
if ( angleToWatchedEntity > maximumAngleToWatchedEntity )
|
|
{
|
|
if ( watchEntityForEntireDuration )
|
|
{
|
|
client->ps.useCameraFocalPoint = false;
|
|
}
|
|
else
|
|
{
|
|
StopWatchingEntity();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
client->ps.useCameraFocalPoint = true;
|
|
}
|
|
|
|
}
|
|
}
|
|
break;
|
|
|
|
case PLAYER_CAMERA_MODE_NO_CLIP:
|
|
break;
|
|
|
|
default:
|
|
assert( false ); // default case is not valid
|
|
}
|
|
|
|
|
|
|
|
// Select the camera mode for the player (btw I hate that the player knows anything about cameras) -BillS
|
|
if ( actor_camera)
|
|
{
|
|
playerCameraMode = PLAYER_CAMERA_MODE_ACTOR;
|
|
if ( !camera )
|
|
{
|
|
AutomaticallySelectedNewCamera();
|
|
}
|
|
}
|
|
else if ( entity_to_watch )
|
|
{
|
|
playerCameraMode = PLAYER_CAMERA_MODE_ENTITY_WATCHING;
|
|
}
|
|
else if ( camera )
|
|
{
|
|
playerCameraMode = PLAYER_CAMERA_MODE_CINEMATIC;
|
|
}
|
|
else if ( getMoveType() == MOVETYPE_NOCLIP )
|
|
{
|
|
playerCameraMode = PLAYER_CAMERA_MODE_NO_CLIP;
|
|
}
|
|
else
|
|
{
|
|
playerCameraMode = PLAYER_CAMERA_MODE_NORMAL;
|
|
}
|
|
|
|
|
|
// Update the camera position using the appropriate controller
|
|
switch( playerCameraMode )
|
|
{
|
|
case PLAYER_CAMERA_MODE_NORMAL:
|
|
{
|
|
SetClientViewAngles( origin, client->ps.viewheight, v_angle, velocity, fov );
|
|
SetPlayerViewNormal();
|
|
}
|
|
break;
|
|
|
|
case PLAYER_CAMERA_MODE_ACTOR:
|
|
{
|
|
// Create the camera if we don't have one yet
|
|
if ( !actor_camera )
|
|
{
|
|
actor_camera = new Camera();
|
|
}
|
|
if ( !camera )
|
|
{
|
|
SetCamera( actor_camera, 0.5f );
|
|
}
|
|
SetClientViewAngles( origin, viewheight, v_angle, velocity, camera->Fov() );
|
|
SetPlayerViewUsingActorController( camera );
|
|
}
|
|
break;
|
|
|
|
case PLAYER_CAMERA_MODE_ENTITY_WATCHING:
|
|
{
|
|
SetClientViewAngles( origin, client->ps.viewheight, v_angle, velocity, fov);
|
|
SetPlayerViewUsingEntityWatchingController();
|
|
}
|
|
break;
|
|
|
|
case PLAYER_CAMERA_MODE_NO_CLIP:
|
|
{
|
|
SetClientViewAngles( origin, client->ps.viewheight, v_angle, velocity, fov );
|
|
SetPlayerViewUsingNoClipController();
|
|
}
|
|
break;
|
|
|
|
case PLAYER_CAMERA_MODE_CINEMATIC:
|
|
{
|
|
SetClientViewAngles( origin, viewheight, v_angle, velocity, camera->Fov() );
|
|
SetPlayerViewUsingCinematicController( camera );
|
|
}
|
|
break;
|
|
|
|
default:
|
|
assert( false ); // default case is not valid
|
|
}
|
|
}
|
|
|
|
|
|
void Player::AutomaticallySelectedNewCamera( void )
|
|
{
|
|
float bestScore = 999;
|
|
Camera *bestCamera = NULL;
|
|
|
|
for( int i = 1; i <= level.automatic_cameras.NumObjects(); i++ )
|
|
{
|
|
Camera *cam = level.automatic_cameras.ObjectAt( i );
|
|
float 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 )
|
|
{
|
|
if ( camera )
|
|
{
|
|
camera->AutomaticStop( this );
|
|
}
|
|
SetCamera( bestCamera, bestCamera->AutomaticStart( this ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// we don't have a camera to switch to
|
|
if ( camera )
|
|
{
|
|
SetCamera( NULL, camera->AutomaticStop( this ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: getWeaponViewShake
|
|
// Class: Player
|
|
//
|
|
// Description: Gets the view shake from the current weapon(s)
|
|
//
|
|
// Parameters: none
|
|
//
|
|
// Returns: Vector - angles to shake the view by
|
|
//----------------------------------------------------------------
|
|
|
|
Vector Player::getWeaponViewShake( void )
|
|
{
|
|
Vector viewShake;
|
|
Weapon *weapon;
|
|
|
|
// Try dual hand
|
|
|
|
weapon = GetActiveWeapon( WEAPON_DUAL );
|
|
|
|
if ( weapon )
|
|
{
|
|
viewShake = weapon->getViewShake();
|
|
}
|
|
else
|
|
{
|
|
// Try left hand
|
|
|
|
weapon = GetActiveWeapon( WEAPON_LEFT );
|
|
|
|
if ( weapon )
|
|
{
|
|
viewShake = weapon->getViewShake();
|
|
}
|
|
|
|
// Try right hand
|
|
|
|
weapon = GetActiveWeapon( WEAPON_RIGHT );
|
|
|
|
if ( weapon )
|
|
{
|
|
viewShake += weapon->getViewShake();
|
|
}
|
|
}
|
|
|
|
return viewShake;
|
|
}
|
|
|
|
void Player::StopWatchingEntity( void )
|
|
{
|
|
entity_to_watch = NULL;
|
|
maximumAngleToWatchedEntity = 0.0f;
|
|
client->ps.useCameraFocalPoint = false;
|
|
client->ps.pm_flags &= ~PMF_CAMERA_VIEW;
|
|
}
|
|
|
|
void Player::DestroyActorCamera( void )
|
|
{
|
|
if ( actor_camera )
|
|
{
|
|
delete actor_camera;
|
|
actor_camera = NULL;
|
|
SetCamera( NULL, .5f );
|
|
}
|
|
}
|
|
/*
|
|
==================
|
|
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 = true;
|
|
// 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 );
|
|
|
|
/****************************************************************************
|
|
Squirrel : #if 0 / 1 block demoted to comment
|
|
|
|
#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;
|
|
/****************************************************************************
|
|
Squirrel : #if 0 / 1 block demoted to comment
|
|
|
|
#endif
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
// swing towards the destination angle
|
|
if ( swing >= 0.0f )
|
|
{
|
|
move = level.frametime * scale * speed;
|
|
if ( move >= swing )
|
|
{
|
|
move = swing;
|
|
*swinging = false;
|
|
}
|
|
|
|
*angle = AngleMod( *angle + move );
|
|
}
|
|
else if ( swing < 0.0f )
|
|
{
|
|
move = level.frametime * scale * -speed;
|
|
if ( move <= swing )
|
|
{
|
|
move = swing;
|
|
*swinging = false;
|
|
}
|
|
*angle = AngleMod( *angle + move );
|
|
}
|
|
|
|
// clamp to no more than tolerance
|
|
swing = AngleSubtract( destination, *angle );
|
|
if ( swing > clampTolerance )
|
|
{
|
|
*angle = AngleMod( destination - ( clampTolerance - 1.0f ) );
|
|
}
|
|
else if ( swing < -clampTolerance )
|
|
{
|
|
*angle = AngleMod( destination + ( clampTolerance - 1.0f ) );
|
|
}
|
|
}
|
|
|
|
void Player::SetHeadTarget
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
str ht = ev->GetString( 1 );
|
|
|
|
head_target = G_FindTarget( 0, ht );
|
|
}
|
|
|
|
qboolean Player::GetTagPositionAndOrientation( int tagnum, orientation_t *new_or )
|
|
{
|
|
int i;
|
|
orientation_t tag_or;
|
|
vec3_t axis[3];
|
|
|
|
tag_or = gi.Tag_OrientationEx( edict->s.modelindex,
|
|
CurrentAnim( legs ),
|
|
CurrentFrame( legs ),
|
|
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( torso ),
|
|
CurrentFrame( torso ),
|
|
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( const str &tagname, orientation_t *new_or )
|
|
{
|
|
int tagnum;
|
|
|
|
tagnum = gi.Tag_NumForName( edict->s.modelindex, 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( const Entity *ent, const str &tag, float yawclamp, float pitchclamp,
|
|
const Vector &baseangles )
|
|
{
|
|
assert( ent );
|
|
|
|
if ( ent )
|
|
{
|
|
Vector delta,angs;
|
|
orientation_t tag_or;
|
|
|
|
int tagnum = gi.Tag_NumForName( edict->s.modelindex, tag.c_str() );
|
|
|
|
if ( tagnum < 0 )
|
|
return Vector( 0.0f, 0.0f, 0.0f );
|
|
|
|
GetTagPositionAndOrientation( tagnum, &tag_or );
|
|
|
|
delta = ent->centroid - tag_or.origin;
|
|
delta.normalize();
|
|
|
|
angs = delta.toAngles();
|
|
|
|
//AnglesSubtract( angs, baseangles, angs );
|
|
angs -= baseangles;
|
|
|
|
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.0f, 0.0f, 0.0f );
|
|
}
|
|
}
|
|
|
|
void Player::DebugWeaponTags( int controller_tag, Weapon *weapon, const 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->s.modelindex, 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 );
|
|
}
|
|
|
|
Entity const * Player::GetTarget( void ) const
|
|
{
|
|
return targetEnemy;
|
|
}
|
|
|
|
bool Player::GetProjectileLaunchAngles( Vector &launchAngles, const Vector &launchPoint, const float initialSpeed, const float gravity ) const
|
|
{
|
|
Entity const *target = GetTarget();
|
|
if ( target && targetEnemyLocked)
|
|
{
|
|
const Vector targetPoint( target->centroid );
|
|
|
|
Trajectory projectileTrajectory( launchPoint, targetPoint, initialSpeed, gravity * -sv_currentGravity->value );
|
|
if ( projectileTrajectory.GetTravelTime() > 0.0f )
|
|
{
|
|
launchAngles.setPitch( projectileTrajectory.GetLaunchAngle() );
|
|
|
|
Vector direction( targetPoint - launchPoint );
|
|
direction.z = 0.0f;
|
|
direction.normalize();
|
|
|
|
launchAngles.setYaw( direction.toYaw() );
|
|
launchAngles.setRoll( 0.0f );
|
|
return true;
|
|
}
|
|
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void Player::AcquireTarget( void )
|
|
{
|
|
targetEnemyLocked = false;
|
|
|
|
if ( GetTarget() )
|
|
{
|
|
GetTarget()->edict->s.eFlags &= ~PMF_ENEMY_TARGETED;
|
|
}
|
|
|
|
// Find a right hand target ( might be the same one )
|
|
|
|
Weapon *weapon = GetActiveWeapon( WEAPON_RIGHT );
|
|
if ( ! (weapon && weapon->autoAimTargetSelectionAngle) )
|
|
{
|
|
weapon = GetActiveWeapon( WEAPON_LEFT );
|
|
}
|
|
if ( weapon && weapon->autoAimTargetSelectionAngle )
|
|
{
|
|
Entity *newTarget = FindClosestEntityInRadius( weapon->autoAimTargetSelectionAngle, 170.0f, weapon->GetMaxRange() );
|
|
targetEnemy = newTarget;
|
|
if ( newTarget )
|
|
{
|
|
|
|
if ( FindClosestEntityInRadius( weapon->autoAimLockonAngle, 170.0f, weapon->GetMaxRange() ) )
|
|
{
|
|
targetEnemyLocked = true;
|
|
targetEnemy->edict->s.eFlags |= PMF_ENEMY_TARGETED;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void Player::AutoAim( void )
|
|
{
|
|
if ( deadflag )
|
|
return;
|
|
|
|
// Check for targets in the FOV
|
|
AcquireTarget();
|
|
|
|
// Update Crosshair
|
|
if ( _targetSelectedHighlight )
|
|
{
|
|
_targetSelectedHighlight->hideModel();
|
|
}
|
|
|
|
if ( _targetLockedHighlight )
|
|
{
|
|
_targetLockedHighlight->hideModel();
|
|
}
|
|
|
|
EntityPtr currentHighlight = _targetSelectedHighlight;
|
|
if ( targetEnemyLocked )
|
|
{
|
|
currentHighlight = _targetLockedHighlight;
|
|
}
|
|
|
|
if ( currentHighlight && !level.cinematic)
|
|
{
|
|
if ( !GetTarget() )
|
|
{
|
|
return;
|
|
}
|
|
Weapon *weapon = GetActiveWeapon( WEAPON_RIGHT );
|
|
if ( !(weapon && weapon->crosshair) )
|
|
{
|
|
weapon = GetActiveWeapon( WEAPON_LEFT );
|
|
}
|
|
if ( weapon && weapon->crosshair )
|
|
{
|
|
Vector newCrosshairLocation( GetTarget()->origin );
|
|
currentHighlight->setOrigin( newCrosshairLocation );
|
|
currentHighlight->showModel();
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
PlayerAngles
|
|
===============
|
|
*/
|
|
void Player::PlayerAngles( void )
|
|
{
|
|
float deltayaw;
|
|
Vector moveangles;
|
|
float speed;
|
|
float yawAngle;
|
|
float speedscale;
|
|
vec3_t temp;
|
|
Vector dir;
|
|
Vector newAimAngles;
|
|
|
|
if ( gi.Anim_Flags( edict->s.modelindex, CurrentAnim( legs ) ) & MDL_ANIM_DEFAULT_ANGLES )
|
|
{
|
|
//SetControllerAngles( HEAD_TAG, vec_zero );
|
|
SetControllerAngles( TORSO_TAG, vec_zero );
|
|
setAngles( Vector( 0.0f, v_angle.y, 0.0f ) );
|
|
return;
|
|
}
|
|
|
|
// set the head and torso directly
|
|
headAngles.setXYZ( v_angle.x, AngleMod( v_angle.y ), v_angle.z );
|
|
torsoAngles.setXYZ( v_angle.x, AngleMod( v_angle.y ), v_angle.z );
|
|
|
|
dir = Vector( velocity.x, velocity.y, 0.0f );
|
|
speed = VectorNormalize( dir );
|
|
|
|
// If moving, angle the legs toward the direction we are moving
|
|
if ( ( speed > 32.0f ) && groundentity && ( last_ucmd.forwardmove || last_ucmd.rightmove ) )
|
|
{
|
|
speedscale = 3;
|
|
yawing = true; // always center
|
|
deltayaw = AngleSubtract( dir.toYaw(), headAngles[ YAW ] );
|
|
}
|
|
else
|
|
{
|
|
speedscale = 1;
|
|
deltayaw = 0;
|
|
}
|
|
|
|
// --------- yaw -------------
|
|
// Clamp to g_legclampangle
|
|
if ( fabs( deltayaw ) > 90.0f )
|
|
deltayaw = AngleSubtract( deltayaw, 180.0f );
|
|
|
|
if ( deltayaw > g_legclampangle->value )
|
|
deltayaw = g_legclampangle->value;
|
|
else if ( deltayaw < -g_legclampangle->value )
|
|
deltayaw = -g_legclampangle->value;
|
|
|
|
yawAngle = headAngles[ YAW ] + deltayaw;
|
|
|
|
yawing_left = false;
|
|
yawing_right = false;
|
|
|
|
if ( client->ps.walking && client->ps.groundPlane && ( movecontrol == MOVECONTROL_LEGS ) &&
|
|
!last_ucmd.forwardmove && !last_ucmd.rightmove && ( client->ps.groundTrace.plane.normal[ 2 ] < SLOPE_22_MAX ) )
|
|
{
|
|
float groundyaw;
|
|
float yawdelta;
|
|
|
|
groundyaw = ( int )vectoyaw( client->ps.groundTrace.plane.normal );
|
|
yawdelta = anglemod( v_angle.y - groundyaw );
|
|
yawdelta = (float)( ( ( ( int )yawdelta + 45 ) / 90 ) * 90.0f );
|
|
angles.y = groundyaw + yawdelta;
|
|
}
|
|
else
|
|
{
|
|
// if purely strafing, don't swing the legs
|
|
if ( dont_turn_legs )
|
|
{
|
|
setAngles( Vector( 0, v_angle.y, 0 ) );
|
|
}
|
|
else
|
|
{
|
|
SwingAngles( yawAngle, g_legtolerance->value, g_legclamptolerance->value, g_legswingspeed->value * speedscale, &angles[ YAW ], &yawing );
|
|
/*if ( yawing )
|
|
{
|
|
float swing;
|
|
swing = AngleSubtract( yawAngle, angles[ YAW ] );
|
|
if ( swing > 0.0f )
|
|
{
|
|
yawing_left = true;
|
|
}
|
|
else
|
|
{
|
|
yawing_right = true;
|
|
}
|
|
}*/
|
|
|
|
if(last_ucmd.deltaAngles[ YAW ] > 0.0f)
|
|
yawing_left = true;
|
|
if(last_ucmd.deltaAngles[ YAW] < 0.0f)
|
|
yawing_right = true;
|
|
}
|
|
}
|
|
|
|
if ( ( deadflag == DEAD_DYING ) || ( deadflag == DEAD_DEAD ) )
|
|
headAngles[PITCH] = 0.0f;
|
|
|
|
// --------- pitch -------------
|
|
headAngles[PITCH] *= 0.65f; // Nerf head angles alittle... head pitch 90 degrees is not reasonable.
|
|
|
|
// only show a fraction of the pitch angle in the torso
|
|
if ( headAngles[ PITCH ] > 180.0f )
|
|
{
|
|
torsoAngles[PITCH] = ( -360.0f + headAngles[ PITCH ] ) * bendTorsoMult;
|
|
}
|
|
else
|
|
{
|
|
torsoAngles[PITCH] = headAngles[ PITCH ] * bendTorsoMult;
|
|
}
|
|
|
|
if ( _headWatchAllowed )
|
|
AcquireHeadTarget();
|
|
else
|
|
head_target = NULL;
|
|
|
|
// Adjust head and torso angles for the target if needed
|
|
if ( head_target )
|
|
{
|
|
//newAimAngles = GetAngleToTarget( head_target, "Bip01 Head", 60, 45, torsoAngles );
|
|
newAimAngles = GetAngleToTarget( head_target, "Bip01 Head", 40.0f, 30.0f, torsoAngles );
|
|
|
|
headAimAngles[PITCH] = LerpAngle( headAimAngles[PITCH], newAimAngles[PITCH], 0.25f );
|
|
headAimAngles[YAW] = LerpAngle( headAimAngles[YAW], newAimAngles[YAW], 0.25f );
|
|
|
|
torsoAimAngles[PITCH] = LerpAngle( torsoAimAngles[PITCH], 0.0f, 0.5f );
|
|
torsoAimAngles[YAW] = LerpAngle( torsoAimAngles[YAW], 0.0f, 0.5f );
|
|
}
|
|
else // Otherwise return to them to 0
|
|
{
|
|
headAimAngles[PITCH] = LerpAngle( headAimAngles[PITCH], 0.0f, 0.5f );
|
|
headAimAngles[YAW] = LerpAngle( headAimAngles[YAW], 0.0f, 0.1f );
|
|
|
|
torsoAimAngles[PITCH] = LerpAngle( torsoAimAngles[PITCH], 0.0f, 0.5f );
|
|
torsoAimAngles[YAW] = LerpAngle( torsoAimAngles[YAW], 0.0f, 0.5f );
|
|
}
|
|
|
|
//if ( !multiplayerManager.inMultiplayer() )
|
|
{
|
|
// pull the head angles back out of the hierarchial chain
|
|
AnglesSubtract( headAngles, torsoAngles, temp );
|
|
|
|
// Add in the aim angles for the head
|
|
VectorAdd( temp, headAimAngles, temp );
|
|
|
|
// Update the head controller
|
|
SetControllerAngles( HEAD_TAG, temp );
|
|
|
|
// pull the torso angles back out of the hierarchial chain
|
|
AnglesSubtract( torsoAngles, angles, temp );
|
|
|
|
// Add in the aim angles for the torso
|
|
VectorAdd( temp, torsoAimAngles, temp );
|
|
|
|
// Update the torso controller
|
|
SetControllerAngles( TORSO_TAG, temp );
|
|
}
|
|
|
|
// Set the rest (legs)
|
|
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 );
|
|
}
|
|
|
|
if ( !( client->ps.pm_flags & PMF_FROZEN ) )
|
|
{
|
|
PlayerAngles();
|
|
}
|
|
|
|
// burn from lava, etc
|
|
WorldEffects();
|
|
|
|
// determine the view offsets
|
|
DamageFeedback();
|
|
CalcBlend();
|
|
}
|
|
|
|
void Player::UpdateStats( void )
|
|
{
|
|
int i,count;
|
|
float healthToDisplay;
|
|
float armorToDisplay;
|
|
|
|
// Deathmatch stats for arena mode
|
|
if ( multiplayerManager.inMultiplayer() )
|
|
{
|
|
/*
|
|
// Arena name configstring index
|
|
if ( current_arena )
|
|
{
|
|
client->ps.stats[STAT_ARENA] = CS_ARENA_INFO + current_arena->getID();
|
|
}
|
|
else
|
|
{
|
|
// CS_ARENA_INFO index holds the "No Arena" string
|
|
client->ps.stats[STAT_ARENA] = CS_ARENA_INFO;
|
|
}
|
|
|
|
if ( current_team )
|
|
{
|
|
client->ps.stats[STAT_TEAM] = current_team->getIndex();
|
|
}
|
|
else
|
|
{
|
|
// CS_TEAM_INFO index holds the "No Team" string
|
|
client->ps.stats[STAT_TEAM] = CS_TEAM_INFO;
|
|
}
|
|
*/
|
|
|
|
//client->ps.stats[STAT_KILLS] = multiplayerManager.getPoints( this );
|
|
//client->ps.stats[STAT_DEATHS] = multiplayerManager.getDeaths( this );
|
|
//client->ps.stats[STAT_ARENA] = multiplayerManager.getTeamPoints( this );
|
|
|
|
client->ps.stats[STAT_RED_TEAM_SCORE] = multiplayerManager.getTeamPoints( "Red" );
|
|
client->ps.stats[STAT_BLUE_TEAM_SCORE] = multiplayerManager.getTeamPoints( "Blue" );
|
|
|
|
client->ps.stats[STAT_SCORE] = multiplayerManager.getPoints( this );
|
|
client->ps.stats[STAT_KILLS] = multiplayerManager.getKills( this );
|
|
client->ps.stats[STAT_DEATHS] = multiplayerManager.getDeaths( this );
|
|
|
|
client->ps.stats[STAT_MP_GENERIC1] = multiplayerManager.getStat( this, STAT_MP_GENERIC1 );
|
|
client->ps.stats[STAT_MP_GENERIC2] = multiplayerManager.getStat( this, STAT_MP_GENERIC2 );
|
|
client->ps.stats[STAT_MP_GENERIC3] = multiplayerManager.getStat( this, STAT_MP_GENERIC3 );
|
|
client->ps.stats[STAT_MP_GENERIC4] = multiplayerManager.getStat( this, STAT_MP_GENERIC4 );
|
|
client->ps.stats[STAT_MP_GENERIC5] = multiplayerManager.getStat( this, STAT_MP_GENERIC5 );
|
|
client->ps.stats[STAT_MP_GENERIC6] = multiplayerManager.getStat( this, STAT_MP_GENERIC6 );
|
|
client->ps.stats[STAT_MP_GENERIC7] = multiplayerManager.getStat( this, STAT_MP_GENERIC7 );
|
|
client->ps.stats[STAT_MP_GENERIC8] = multiplayerManager.getStat( this, STAT_MP_GENERIC8 );
|
|
|
|
client->ps.stats[STAT_MP_SPECTATING_ENTNUM] = multiplayerManager.getStat( this, STAT_MP_SPECTATING_ENTNUM );
|
|
|
|
client->ps.stats[STAT_MP_MODE_ICON] = multiplayerManager.getIcon( this, STAT_MP_MODE_ICON );
|
|
client->ps.stats[STAT_MP_TEAM_ICON] = multiplayerManager.getIcon( this, STAT_MP_TEAM_ICON );
|
|
client->ps.stats[STAT_MP_TEAMHUD_ICON] = multiplayerManager.getIcon( this, STAT_MP_TEAMHUD_ICON );
|
|
client->ps.stats[STAT_MP_SPECIALTY_ICON] = multiplayerManager.getIcon( this, STAT_MP_SPECIALTY_ICON );
|
|
|
|
client->ps.stats[STAT_MP_OTHERTEAM_ICON] = multiplayerManager.getIcon( this, STAT_MP_OTHERTEAM_ICON );
|
|
|
|
if ( multiplayerManager.inMultiplayer() )
|
|
edict->s.infoIcon = multiplayerManager.getInfoIcon( this, last_ucmd.buttons );
|
|
else
|
|
edict->s.infoIcon = 0;
|
|
|
|
client->ps.stats[STAT_MP_AWARD_ICON] = multiplayerManager.getIcon( this, STAT_MP_AWARD_ICON );
|
|
client->ps.stats[STAT_MP_AWARD_COUNT] = multiplayerManager.getStat( this, STAT_MP_AWARD_COUNT );
|
|
|
|
client->ps.stats[STAT_MP_STATE] = multiplayerManager.getStat( this, STAT_MP_STATE );
|
|
|
|
if ( _holdableItem )
|
|
client->ps.stats[STAT_MP_HOLDABLEITEM_ICON] = _holdableItem->getIcon();
|
|
else
|
|
client->ps.stats[STAT_MP_HOLDABLEITEM_ICON] = -1;
|
|
|
|
if ( _rune )
|
|
client->ps.stats[STAT_MP_RUNE_ICON] = _rune->getIcon();
|
|
else
|
|
client->ps.stats[STAT_MP_RUNE_ICON] = -1;
|
|
|
|
if ( _powerup )
|
|
client->ps.stats[STAT_MP_POWERUP_ICON] = _powerup->getIcon();
|
|
else
|
|
client->ps.stats[STAT_MP_POWERUP_ICON] = -1;
|
|
|
|
/* client->ps.stats[STAT_WON_MATCHES] = num_won_matches;
|
|
client->ps.stats[STAT_LOST_MATCHES] = num_lost_matches; */
|
|
|
|
// Get queue position
|
|
//client->ps.stats[STAT_QUEUE_PLACE] = 0;
|
|
/*
|
|
if ( current_arena )
|
|
{
|
|
client->ps.stats[STAT_QUEUE_PLACE] = current_arena->GetLinePosition( this );
|
|
}
|
|
*/
|
|
// multiplayerManager.getStat( this, STAT_TIMELEFT_MINUTES );
|
|
client->ps.stats[STAT_TIMELEFT_SECONDS] = multiplayerManager.getStat( this, STAT_TIMELEFT_SECONDS );
|
|
}
|
|
|
|
//
|
|
// Health
|
|
//
|
|
|
|
// Use my health/armor as the default to display
|
|
|
|
healthToDisplay = health;
|
|
armorToDisplay = GetArmorValue();
|
|
|
|
if ( multiplayerManager.inMultiplayer() && multiplayerManager.isPlayerSpectator( this, SPECTATOR_TYPE_FOLLOW ) )
|
|
{
|
|
Player *playerSpectating;
|
|
|
|
playerSpectating = multiplayerManager.getPlayerSpectating( this );
|
|
|
|
if ( playerSpectating )
|
|
{
|
|
// Display the health/armor of the player we are spectating instead of ours
|
|
|
|
healthToDisplay = playerSpectating->getHealth();
|
|
armorToDisplay = playerSpectating->GetArmorValue();
|
|
}
|
|
}
|
|
|
|
// Round health a little so that it doesn't mislead the player when it gets changed to an int
|
|
|
|
if ( ( healthToDisplay < 1.0f ) && ( healthToDisplay > 0.0f ) )
|
|
{
|
|
client->ps.stats[ STAT_HEALTH ] = 1;
|
|
}
|
|
else
|
|
{
|
|
client->ps.stats[ STAT_HEALTH ] = (int)healthToDisplay;
|
|
}
|
|
|
|
|
|
if ( health <= 0.0f )
|
|
{
|
|
Vector damageAngles = damage_from * -1;
|
|
damageAngles = damageAngles.toAngles();
|
|
client->ps.stats[ STAT_DEAD_YAW ] = (int) damageAngles[ YAW ];
|
|
}
|
|
else
|
|
{
|
|
client->ps.stats[ STAT_DEAD_YAW ] = 0;
|
|
}
|
|
|
|
//ArmorValue Stat Update
|
|
client->ps.stats[ STAT_ARMOR_LEVEL ] = (int) armorToDisplay;
|
|
|
|
Weapon *leftweapon = GetActiveWeapon( WEAPON_LEFT );
|
|
Weapon *rightweapon = GetActiveWeapon( WEAPON_RIGHT );
|
|
Weapon *dualweapon = GetActiveWeapon( WEAPON_DUAL );
|
|
|
|
client->ps.stats[STAT_AMMO_LEFT] = 0;
|
|
client->ps.stats[STAT_AMMO_RIGHT] = 0;
|
|
client->ps.stats[STAT_CLIPAMMO_LEFT] = 0;
|
|
client->ps.stats[STAT_CLIPAMMO_RIGHT] = 0;
|
|
client->ps.stats[STAT_NUM_SHOTS_LEFT] = 0;
|
|
client->ps.stats[STAT_MAX_NUM_SHOTS_LEFT] = 0;
|
|
client->ps.stats[STAT_NUM_SHOTS_RIGHT] = 0;
|
|
client->ps.stats[STAT_MAXAMMO_LEFT] = 0;
|
|
client->ps.stats[STAT_MAXAMMO_RIGHT] = 0;
|
|
client->ps.stats[STAT_MAXCLIPAMMO_LEFT] = 0;
|
|
client->ps.stats[STAT_MAXCLIPAMMO_RIGHT] = 0;
|
|
|
|
client->ps.stats[STAT_AMMO_TYPE1] = 0;
|
|
client->ps.stats[STAT_AMMO_TYPE2] = 0;
|
|
client->ps.stats[STAT_AMMO_TYPE3] = 0;
|
|
client->ps.stats[STAT_AMMO_TYPE4] = 0;
|
|
|
|
if ( _powerup )
|
|
client->ps.stats[ STAT_POWERUPTIME ] = static_cast<int>( _powerup->getTimeLeft() );
|
|
else
|
|
client->ps.stats[ STAT_POWERUPTIME ] = 0;
|
|
|
|
client->ps.stats[ STAT_ACCUMULATED_PAIN] = (int) accumulated_pain;
|
|
|
|
client->ps.activeItems[ ITEM_NAME_AMMO_LEFT ] = -1;
|
|
client->ps.activeItems[ ITEM_NAME_AMMO_RIGHT ] = -1;
|
|
client->ps.activeItems[ ITEM_NAME_WEAPON_LEFT ] = -1;
|
|
client->ps.activeItems[ ITEM_NAME_WEAPON_RIGHT ] = -1;
|
|
client->ps.activeItems[ ITEM_NAME_WEAPON_DUAL ] = -1;
|
|
#ifndef DEDICATED
|
|
//
|
|
// mission objectives
|
|
//
|
|
client->ps.stats[STAT_NUM_OBJECTIVES] = gi.MObjective_GetNumActiveObjectives();
|
|
client->ps.stats[STAT_COMPLETE_OBJECTIVES] = gi.MObjective_GetNumCompleteObjectives();
|
|
client->ps.stats[STAT_FAILED_OBJECTIVES] = gi.MObjective_GetNumFailedObjectives();
|
|
client->ps.stats[STAT_INCOMPLETE_OBJECTIVES] = gi.MObjective_GetNumIncompleteObjectives();
|
|
#endif
|
|
|
|
// misc stats
|
|
if ( client->ps.stats[ STAT_SHOTS_FIRED ] > 0 )
|
|
client->ps.stats[STAT_ACCURACY] = (int)((float)( (float)client->ps.stats[ STAT_SHOTS_HIT ] / (float)client->ps.stats[ STAT_SHOTS_FIRED ] ) * 100.0f);
|
|
else
|
|
client->ps.stats[STAT_ACCURACY] = 100;
|
|
|
|
client->ps.stats[STAT_MISSION_DURATION] = (int) level.timeInLevel;
|
|
|
|
client->ps.stats[ STAT_WEAPON_GENERIC1 ] = 0;
|
|
client->ps.stats[ STAT_WEAPON_GENERIC2 ] = 0;
|
|
|
|
if ( dualweapon )
|
|
{
|
|
// Left is PRIMARY
|
|
if ( dualweapon->GetClipSize( FIRE_MODE1 ) > 0 )
|
|
{
|
|
//set the max ammo to contain the number of clips and the max number of clips.
|
|
client->ps.stats[STAT_AMMO_LEFT] = AmmoCount( dualweapon->GetAmmoType( FIRE_MODE1 ) ) / dualweapon->GetClipSize( FIRE_MODE1 );
|
|
client->ps.stats[STAT_MAXAMMO_LEFT] = MaxAmmoCount( dualweapon->GetAmmoType( FIRE_MODE1 ) ) / dualweapon->GetClipSize( FIRE_MODE1 );
|
|
|
|
client->ps.stats[STAT_CLIPAMMO_LEFT] = dualweapon->ClipAmmo( FIRE_MODE1 );
|
|
client->ps.stats[STAT_MAXCLIPAMMO_LEFT] = dualweapon->GetClipSize( FIRE_MODE1 );
|
|
|
|
if( dualweapon->ammorequired[FIRE_MODE1] != 0)
|
|
{
|
|
client->ps.stats[STAT_NUM_SHOTS_LEFT] = dualweapon->ClipAmmo( FIRE_MODE1 ) / dualweapon->ammorequired[FIRE_MODE1];
|
|
client->ps.stats[STAT_MAX_NUM_SHOTS_LEFT] = dualweapon->GetClipSize( FIRE_MODE1 ) / dualweapon->ammorequired[FIRE_MODE1];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
client->ps.stats[STAT_AMMO_LEFT] = AmmoCount( dualweapon->GetAmmoType( FIRE_MODE1 ) );
|
|
client->ps.stats[STAT_MAXAMMO_LEFT] = MaxAmmoCount( dualweapon->GetAmmoType( FIRE_MODE1 ) );
|
|
|
|
client->ps.stats[STAT_CLIPAMMO_LEFT] = AmmoCount( dualweapon->GetAmmoType( FIRE_MODE1 ) );
|
|
client->ps.stats[STAT_MAXCLIPAMMO_LEFT] = MaxAmmoCount( dualweapon->GetAmmoType( FIRE_MODE1 ) );
|
|
|
|
if( dualweapon->ammorequired[FIRE_MODE1] != 0)
|
|
{
|
|
client->ps.stats[STAT_NUM_SHOTS_LEFT] = AmmoCount( dualweapon->GetAmmoType( FIRE_MODE1 ) ) / dualweapon->ammorequired[FIRE_MODE1];
|
|
client->ps.stats[STAT_MAX_NUM_SHOTS_LEFT] = MaxAmmoCount( dualweapon->GetAmmoType( FIRE_MODE1 ) ) / dualweapon->ammorequired[FIRE_MODE1];
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
client->ps.activeItems[ITEM_NAME_AMMO_LEFT] = AmmoIndex( dualweapon->GetAmmoType( FIRE_MODE1 ) );
|
|
|
|
// Right is AlTERNATE
|
|
client->ps.stats[STAT_AMMO_RIGHT] = AmmoCount( dualweapon->GetAmmoType( FIRE_MODE2 ) );
|
|
client->ps.stats[STAT_MAXAMMO_RIGHT] = MaxAmmoCount( dualweapon->GetAmmoType( FIRE_MODE2 ) );
|
|
|
|
if ( dualweapon->GetClipSize( FIRE_MODE2 ) > 0 )
|
|
{
|
|
client->ps.stats[STAT_CLIPAMMO_RIGHT] = dualweapon->ClipAmmo( FIRE_MODE2 );
|
|
client->ps.stats[STAT_MAXCLIPAMMO_RIGHT] = dualweapon->GetClipSize( FIRE_MODE2 );
|
|
|
|
if(dualweapon->ammorequired[FIRE_MODE2] != 0)
|
|
client->ps.stats[STAT_NUM_SHOTS_RIGHT] = dualweapon->ClipAmmo( FIRE_MODE2 ) / dualweapon->ammorequired[FIRE_MODE2];
|
|
}
|
|
else
|
|
{
|
|
client->ps.stats[STAT_CLIPAMMO_RIGHT] = AmmoCount( dualweapon->GetAmmoType( FIRE_MODE2 ) );
|
|
client->ps.stats[STAT_MAXCLIPAMMO_RIGHT] = MaxAmmoCount( dualweapon->GetAmmoType( FIRE_MODE2 ) );
|
|
|
|
if(dualweapon->ammorequired[FIRE_MODE2] != 0)
|
|
client->ps.stats[STAT_NUM_SHOTS_RIGHT] = AmmoCount( dualweapon->GetAmmoType( FIRE_MODE2 ) ) / dualweapon->ammorequired[FIRE_MODE2];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
client->ps.activeItems[ITEM_NAME_AMMO_RIGHT] = AmmoIndex( dualweapon->GetAmmoType( FIRE_MODE2 ) );
|
|
|
|
client->ps.activeItems[ITEM_NAME_WEAPON_DUAL] = dualweapon->getIndex();
|
|
|
|
//Send the # for all ammo groups
|
|
//This should be fixed since its a poor implementation.
|
|
|
|
for( int i = 1; i <= ammo_inventory.NumObjects(); i++ )
|
|
{
|
|
if(ammo_inventory.ObjectAt(i)->getName() == "Plasma")
|
|
{
|
|
client->ps.stats[STAT_AMMO_TYPE1] = ammo_inventory.ObjectAt(i)->getAmount();
|
|
}
|
|
else if(ammo_inventory.ObjectAt(i)->getName() == "Fed")
|
|
{
|
|
client->ps.stats[STAT_AMMO_TYPE2] = ammo_inventory.ObjectAt(i)->getAmount();
|
|
}
|
|
else if(ammo_inventory.ObjectAt(i)->getName() == "Idryll")
|
|
{
|
|
client->ps.stats[STAT_AMMO_TYPE3] = ammo_inventory.ObjectAt(i)->getAmount();
|
|
}
|
|
else if( ammo_inventory.ObjectAt(i)->getName() == "Phaser" )
|
|
{
|
|
client->ps.stats[STAT_AMMO_TYPE4] = ammo_inventory.ObjectAt(i)->getAmount();
|
|
}
|
|
}
|
|
|
|
client->ps.stats[ STAT_WEAPON_GENERIC1 ] = dualweapon->getStat( STAT_WEAPON_GENERIC1 );
|
|
client->ps.stats[ STAT_WEAPON_GENERIC2 ] = dualweapon->getStat( STAT_WEAPON_GENERIC2 );
|
|
}
|
|
else
|
|
{
|
|
if ( leftweapon )
|
|
{
|
|
client->ps.stats[STAT_AMMO_LEFT] = AmmoCount( leftweapon->GetAmmoType( FIRE_MODE1 ) );
|
|
client->ps.stats[STAT_MAXAMMO_LEFT] = MaxAmmoCount( leftweapon->GetAmmoType( FIRE_MODE1 ) );
|
|
client->ps.stats[STAT_CLIPAMMO_LEFT] = leftweapon->ClipAmmo( FIRE_MODE1 );
|
|
client->ps.stats[STAT_MAXCLIPAMMO_LEFT] = leftweapon->GetClipSize( FIRE_MODE1 );
|
|
client->ps.activeItems[ITEM_NAME_AMMO_LEFT] = AmmoIndex( leftweapon->GetAmmoType( FIRE_MODE1 ) );
|
|
client->ps.activeItems[ITEM_NAME_WEAPON_LEFT] = leftweapon->getIndex();
|
|
|
|
}
|
|
|
|
if ( rightweapon )
|
|
{
|
|
client->ps.stats[STAT_AMMO_RIGHT] = AmmoCount( rightweapon->GetAmmoType( FIRE_MODE1 ) );
|
|
client->ps.stats[STAT_MAXAMMO_RIGHT] = MaxAmmoCount( rightweapon->GetAmmoType( FIRE_MODE1 ) );
|
|
client->ps.stats[STAT_CLIPAMMO_RIGHT] = rightweapon->ClipAmmo( FIRE_MODE1 );
|
|
client->ps.stats[STAT_MAXCLIPAMMO_RIGHT] = rightweapon->GetClipSize( FIRE_MODE1 );
|
|
client->ps.activeItems[ITEM_NAME_AMMO_RIGHT] = AmmoIndex( rightweapon->GetAmmoType( FIRE_MODE1 ) );
|
|
client->ps.activeItems[ITEM_NAME_WEAPON_RIGHT] = rightweapon->getIndex();
|
|
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// set boss health and name
|
|
//
|
|
|
|
if ( bosshealth->value > 0.0f )
|
|
{
|
|
client->ps.stats[ STAT_BOSSHEALTH ] = (int)(bosshealth->value * 100.0f);
|
|
|
|
if ( ( ( bosshealth->value * 100.0f ) > 0 ) && ( client->ps.stats[ STAT_BOSSHEALTH ] == 0 ) )
|
|
{
|
|
client->ps.stats[ STAT_BOSSHEALTH ] = 1;
|
|
}
|
|
|
|
client->ps.stats[ STAT_BOSSNAME_CONFIGINDEX ] = G_FindConfigstringIndex( bossname->string, CS_GENERAL_STRINGS, MAX_GENERAL_STRINGS, true ) + CS_GENERAL_STRINGS;
|
|
//client->ps.stats[ STAT_BOSSNAME_CONFIGINDEX ] = gi.soundindex( bossname->string ) + CS_SOUNDS;
|
|
}
|
|
else
|
|
{
|
|
client->ps.stats[ STAT_BOSSHEALTH ] = 0;
|
|
}
|
|
|
|
if ( _itemText.length() > 0 )
|
|
{
|
|
client->ps.stats[ STAT_ITEMICON ] = _itemIcon;
|
|
|
|
client->ps.stats[ STAT_ITEMTEXT ] = G_FindConfigstringIndex( _itemText.c_str(), CS_GENERAL_STRINGS, MAX_GENERAL_STRINGS, true ) + CS_GENERAL_STRINGS;
|
|
//client->ps.stats[ STAT_BOSSNAME_CONFIGINDEX ] = gi.soundindex( bossname->string ) + CS_SOUNDS;
|
|
}
|
|
else
|
|
{
|
|
client->ps.stats[ STAT_ITEMTEXT ] = -1;
|
|
}
|
|
|
|
if ( _voteText.length() > 0 )
|
|
{
|
|
client->ps.stats[ STAT_VOTETEXT ] = G_FindConfigstringIndex( _voteText.c_str(), CS_GENERAL_STRINGS, MAX_GENERAL_STRINGS, true ) + CS_GENERAL_STRINGS;
|
|
}
|
|
else
|
|
{
|
|
client->ps.stats[ STAT_VOTETEXT ] = -1;
|
|
}
|
|
|
|
if ( specialMoveEndTime > 0.0f )
|
|
{
|
|
float beginTime = specialMoveEndTime - specialMoveChargeTime;
|
|
float timeElapsed = specialMoveCharge - beginTime;
|
|
float percentElapsed = timeElapsed / specialMoveChargeTime;
|
|
float finalValue = percentElapsed * 100.0f;
|
|
if ( finalValue > 100.0f )
|
|
finalValue = 100.0f;
|
|
client->ps.stats[ STAT_SPECIALMOVETIMER ] = (int) finalValue;
|
|
}
|
|
else
|
|
client->ps.stats[ STAT_SPECIALMOVETIMER ] = 0;
|
|
|
|
client->ps.stats[ STAT_POINTS ] = points;
|
|
|
|
client->ps.stats[ STAT_SECRETS_TOTAL ] = level.total_secrets;
|
|
client->ps.stats[ STAT_SECRETS_FOUND ] = level.found_secrets;
|
|
client->ps.stats[ STAT_ITEMS_TOTAL ] = level.total_specialItems;
|
|
client->ps.stats[ STAT_ITEMS_FOUND ] = level.found_specialItems;
|
|
|
|
|
|
// 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);
|
|
|
|
// Go through all the player's weapons and send over the indexes of the names
|
|
memset( client->ps.inventory_name_index, 0, sizeof( client->ps.inventory_name_index ) );
|
|
memset( client->ps.ammo_in_clip, 0, sizeof(client->ps.ammo_in_clip));
|
|
|
|
count = inventory.NumObjects();
|
|
|
|
if ( count > MAX_INVENTORY )
|
|
{
|
|
count = MAX_INVENTORY;
|
|
warning( "Player::UpdateStats", "Max inventory exceeded\n" );
|
|
}
|
|
|
|
Weapon* weapon;
|
|
Ammo* ammo;
|
|
int ammoRequired;
|
|
for ( i=1; i<=count; i++ )
|
|
{
|
|
int entnum = inventory.ObjectAt( i );
|
|
Item *item = ( Item * )G_GetEntity( entnum );
|
|
|
|
if ( item )
|
|
{
|
|
client->ps.inventory_name_index[i-1] = item->getIndex();
|
|
if( item->isSubclassOf(Weapon) )
|
|
{
|
|
weapon = (Weapon*) item;
|
|
ammo = FindAmmoByName(weapon->GetAmmoType(FIRE_MODE1));
|
|
if( ammo == 0)
|
|
continue;
|
|
client->ps.inventory_weapon_ammo_index[ i - 1 ] = ammo->getIndex();
|
|
|
|
ammoRequired = weapon->GetRequiredAmmo(FIRE_MODE1);
|
|
client->ps.inventory_weapon_required_ammo[i - 1] = ammoRequired;
|
|
|
|
client->ps.ammo_in_clip[ i - 1 ] = weapon->getAmmoInClip(FIRE_MODE1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Go through all the player's ammo and send over the names/amounts
|
|
memset( client->ps.ammo_amount, 0, sizeof( client->ps.ammo_amount ) );
|
|
count = ammo_inventory.NumObjects();
|
|
|
|
assert( count < MAX_AMMO );
|
|
if ( count > MAX_AMMO )
|
|
{
|
|
gi.Error( ERR_DROP, "Player::UpdateStats : Exceeded MAX_AMMO\n" );
|
|
}
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
// Do letterbox
|
|
|
|
// Check for letterbox fully out
|
|
if ( ( level.m_letterbox_time <= 0.0f ) && ( level.m_letterbox_dir == letterbox_in ) )
|
|
{
|
|
client->ps.stats[STAT_LETTERBOX] = (int)(level.m_letterbox_fraction * MAX_LETTERBOX_SIZE);
|
|
return;
|
|
}
|
|
else if ( ( level.m_letterbox_time <= 0.0f ) && ( level.m_letterbox_dir == letterbox_out ) )
|
|
{
|
|
client->ps.stats[STAT_LETTERBOX] = 0;
|
|
return;
|
|
}
|
|
|
|
float frac;
|
|
|
|
level.m_letterbox_time -= level.frametime;
|
|
|
|
frac = level.m_letterbox_time / level.m_letterbox_time_start;
|
|
|
|
if ( frac > 1.0f )
|
|
frac = 1.0f;
|
|
if ( frac < 0.0f )
|
|
frac = 0.0f;
|
|
|
|
if ( level.m_letterbox_dir == letterbox_in )
|
|
frac = 1.0f - frac;
|
|
|
|
client->ps.stats[STAT_LETTERBOX] = (int)((float)( frac * level.m_letterbox_fraction ) * MAX_LETTERBOX_SIZE);
|
|
|
|
// Stats for Mission Status
|
|
}
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name: UpdateObjectiveStatus
|
|
// Class: Player
|
|
//
|
|
// Description: Updates the player state of the mission objectives.
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: None
|
|
//-----------------------------------------------------
|
|
void Player::UpdateObjectiveStatus( void )
|
|
{
|
|
client->ps.objectiveStates = _objectiveStates;
|
|
client->ps.informationStates = _informationStates;
|
|
client->ps.objectiveNameIndex = _objectiveNameIndex;
|
|
}
|
|
|
|
void Player::UpdateMusic( void )
|
|
{
|
|
|
|
if ( !g_allowActionMusic->integer || !_allowActionMusic )
|
|
{
|
|
action_level = 0.0f;
|
|
}
|
|
|
|
if ( music_forced )
|
|
{
|
|
client->ps.current_music_mood = music_current_mood;
|
|
client->ps.fallback_music_mood = music_fallback_mood;
|
|
}
|
|
else if ( action_level > 30.0f )
|
|
{
|
|
client->ps.current_music_mood = mood_action;
|
|
client->ps.fallback_music_mood = mood_normal;
|
|
}
|
|
else if ( action_level < 15.0f )
|
|
{
|
|
client->ps.current_music_mood = music_current_mood;
|
|
client->ps.fallback_music_mood = music_fallback_mood;
|
|
}
|
|
|
|
if ( action_level > 0.0f )
|
|
{
|
|
if ( multiplayerManager.inMultiplayer() )
|
|
{
|
|
action_level -= level.fixedframetime * 2.0f;
|
|
}
|
|
else
|
|
{
|
|
action_level -= level.fixedframetime * 15.0f;
|
|
}
|
|
|
|
if ( action_level > 80.0f )
|
|
{
|
|
action_level = 80.0f;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
action_level = 0.0f;
|
|
}
|
|
|
|
//
|
|
// set the music
|
|
// naturally decay the action level
|
|
//
|
|
if ( s_debugmusic->integer )
|
|
{
|
|
gi.DPrintf( "%s's action_level = %4.2f\n", client->pers.netname, action_level );
|
|
}
|
|
|
|
// 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;
|
|
client->ps.allowMusicDucking = _allowMusicDucking;
|
|
}
|
|
|
|
void Player::SetReverb( int type, float level )
|
|
{
|
|
reverb_type = type;
|
|
reverb_level = level;
|
|
}
|
|
|
|
void Player::SetReverb( const 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 * )
|
|
{
|
|
if ( vehicle )
|
|
return;
|
|
|
|
animdone_Legs = true;
|
|
animate->SetAnimDoneEvent( EV_Player_AnimLoop_Legs, legs );
|
|
EvaluateState();
|
|
}
|
|
|
|
void Player::EndAnim_Torso( Event * )
|
|
{
|
|
if ( vehicle )
|
|
return;
|
|
|
|
animdone_Torso = true;
|
|
animate->SetAnimDoneEvent( EV_Player_AnimLoop_Torso, torso );
|
|
EvaluateState();
|
|
}
|
|
|
|
void Player::SetAnim( const char *anim, bodypart_t part, bool force )
|
|
{
|
|
assert( anim );
|
|
|
|
if ( !force && ( part != all ) && ( partAnim[ part ] == anim ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( !force && ( part == all ) && ( partAnim[ legs ] == anim ) && ( partAnim[ torso ] == anim ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( getMoveType() == MOVETYPE_NOCLIP )
|
|
{
|
|
anim = "idle";
|
|
}
|
|
|
|
if ( part != all )
|
|
{
|
|
partAnim[ part ] = anim;
|
|
}
|
|
else
|
|
{
|
|
partAnim[ legs ] = anim;
|
|
partAnim[ torso ] = anim;
|
|
}
|
|
|
|
switch( part )
|
|
{
|
|
default :
|
|
case all :
|
|
animate->RandomAnimate( anim, EV_Player_AnimLoop_Legs, part );
|
|
break;
|
|
|
|
case legs :
|
|
animate->RandomAnimate( anim, EV_Player_AnimLoop_Legs, part );
|
|
break;
|
|
|
|
case torso :
|
|
animate->RandomAnimate( anim, EV_Player_AnimLoop_Torso, part );
|
|
break;
|
|
}
|
|
|
|
if ( ( part == legs ) || ( part == all ) )
|
|
{
|
|
Vector animmove;
|
|
float time;
|
|
float len;
|
|
|
|
time = gi.Anim_Time( edict->s.modelindex, CurrentAnim() );
|
|
gi.Anim_Delta( edict->s.modelindex, CurrentAnim(), animmove );
|
|
len = animmove.length();
|
|
if ( ( len == 0.0f ) || ( time == 0.0f ) )
|
|
{
|
|
animspeed = 0;
|
|
}
|
|
else
|
|
{
|
|
animspeed = len / time;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Player::CheckReloadWeapons( void )
|
|
{
|
|
Weapon *weap;
|
|
|
|
weap = GetActiveWeapon( WEAPON_DUAL );
|
|
|
|
if ( weap )
|
|
{
|
|
weap->CheckReload();
|
|
}
|
|
else
|
|
{
|
|
weap = GetActiveWeapon( WEAPON_LEFT );
|
|
if ( weap )
|
|
{
|
|
weap->CheckReload();
|
|
}
|
|
|
|
weap = GetActiveWeapon( WEAPON_RIGHT );
|
|
if ( weap )
|
|
{
|
|
weap->CheckReload();
|
|
}
|
|
}
|
|
}
|
|
|
|
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 level exits
|
|
//
|
|
if ( client->ps.pm_flags & PMF_LEVELEXIT )
|
|
{
|
|
//
|
|
// change music
|
|
//
|
|
if ( music_current_mood != mood_success )
|
|
{
|
|
ChangeMusic( "success", "normal", false );
|
|
}
|
|
}
|
|
|
|
if(_updateGameFrames == true)
|
|
_totalGameFrames++;
|
|
|
|
//Update the dialog information.
|
|
client->ps.dialogEntnum = _dialogEntnum;
|
|
client->ps.dialogSoundIndex = _dialogSoundIndex;
|
|
client->ps.dialogTextSoundIndex = _dialogTextSoundIndex;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
EndFrame
|
|
|
|
Called for each player at the end of the server frame
|
|
and right after spawning
|
|
=================
|
|
*/
|
|
void Player::EndFrame( Event * )
|
|
{
|
|
AutoAim();
|
|
|
|
if ( meleeAttackFlags & MELEE_ATTACK_LEFT )
|
|
AdvancedMeleeAttack(WEAPON_LEFT);
|
|
|
|
if ( meleeAttackFlags & MELEE_ATTACK_RIGHT )
|
|
AdvancedMeleeAttack(WEAPON_RIGHT);
|
|
|
|
if ( finishableList.NumObjects() > 0 )
|
|
HandleFinishableList();
|
|
else
|
|
{
|
|
//G_EnableWidgetOfPlayer( edict, "ActionIcon_Kick", false ); // Temporary
|
|
_doingFinishingMove = false;
|
|
_finishActor = NULL;
|
|
_finishState = "";
|
|
}
|
|
|
|
FinishMove();
|
|
CheckReloadWeapons();
|
|
UpdateStats();
|
|
UpdateMusic();
|
|
UpdateReverb();
|
|
UpdateMisc();
|
|
SetupView();
|
|
UpdateObjectiveStatus();
|
|
|
|
if ( _powerup )
|
|
_powerup->update( level.frametime );
|
|
|
|
if ( _rune )
|
|
_rune->update( level.frametime );
|
|
|
|
if ( _holdableItem )
|
|
_holdableItem->update( level.frametime );
|
|
|
|
if ( multiplayerManager.inMultiplayer() && ( _lastPainShaderMod != MOD_NONE ) && ( _nextPainShaderTime < level.time ) )
|
|
{
|
|
str painShader = getPainShader( _lastPainShaderMod, false );
|
|
|
|
clearCustomShader( "ArmorDeflection" );
|
|
|
|
if ( painShader.length() > 0 )
|
|
{
|
|
clearCustomShader( painShader );
|
|
|
|
_lastPainShaderMod = MOD_NONE;
|
|
}
|
|
}
|
|
|
|
if ( needToSendAllHudsToClient() )
|
|
{
|
|
sendAllHudsToClient();
|
|
}
|
|
|
|
if( _needToSendBranchDialog == true && _started )
|
|
{
|
|
_needToSendBranchDialog = false;
|
|
if(_branchDialogActor)
|
|
_branchDialogActor->setBranchDialog();
|
|
}
|
|
|
|
_cameraCutThisFrame = false;
|
|
}
|
|
|
|
|
|
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 * )
|
|
{
|
|
}
|
|
|
|
/* void Player::SetPowerupTimer
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
Event *event;
|
|
|
|
poweruptimer = ev->GetInteger( 1 );
|
|
poweruptype = (powerup_t)ev->GetInteger( 2 );
|
|
event = new Event( EV_Player_UpdatePowerupTimer );
|
|
PostEvent ( event, 1.0f );
|
|
|
|
if ( p_heuristics )
|
|
p_heuristics->IncrementItemsPickedUp();
|
|
} */
|
|
|
|
/* void Player::UpdatePowerupTimer
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
poweruptimer -= 1;
|
|
if ( poweruptimer > 0 )
|
|
{
|
|
Event *event = new Event( EV_Player_UpdatePowerupTimer );
|
|
PostEvent ( event, 1.0f );
|
|
}
|
|
else
|
|
{
|
|
// Reset any flags as necessary, powerup is done
|
|
if ( poweruptype == POWERUP_STEALTH && (flags & FL_NOTARGET) )
|
|
flags ^= FL_NOTARGET;
|
|
if ( poweruptype == POWERUP_PROTECTION && (flags & FL_GODMODE) )
|
|
flags ^= FL_GODMODE;
|
|
|
|
if ( poweruptype == POWERUP_ACCURACY )
|
|
{
|
|
Weapon *weap;
|
|
weap = GetActiveWeapon( WEAPON_DUAL );
|
|
// Tell the weapon we lost the accuracy powerup
|
|
if ( weap )
|
|
weap->SetAccuracyPowerup( false );
|
|
}
|
|
|
|
poweruptype = POWERUP_NONE;
|
|
}
|
|
} */
|
|
|
|
void Player::ChangeMusic( const char * current, const char * fallback, qboolean force )
|
|
{
|
|
int current_mood_num;
|
|
int fallback_mood_num;
|
|
|
|
music_forced = force;
|
|
if ( str( current ) == "normal" )
|
|
{
|
|
music_forced = false;
|
|
}
|
|
|
|
// We no longer let any music be forced
|
|
//music_forced = false;
|
|
|
|
// zero out action_level so that we do get a change
|
|
//
|
|
action_level = 0;
|
|
|
|
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.0f;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: allowMusicDucking
|
|
// Class: Player
|
|
//
|
|
// Description: Specifies whether or not music ducking is allowed
|
|
//
|
|
// Parameters: bool allowMusicDucking - whether or not music ducking is allowed
|
|
//
|
|
// Returns: none
|
|
//----------------------------------------------------------------
|
|
|
|
void Player::allowMusicDucking( bool allowMusicDucking )
|
|
{
|
|
_allowMusicDucking = allowMusicDucking;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: allowActionMusic
|
|
// Class: Player
|
|
//
|
|
// Description: Specifies whether or not action music is allowed
|
|
//
|
|
// Parameters: bool allowActionMusic - whether or not action music is allowed
|
|
//
|
|
// Returns: none
|
|
//----------------------------------------------------------------
|
|
|
|
void Player::allowActionMusic( bool allowActionMusic )
|
|
{
|
|
_allowActionMusic = allowActionMusic;
|
|
}
|
|
|
|
void Player::GiveOxygen( float time )
|
|
{
|
|
air_finished = level.time + time;
|
|
}
|
|
|
|
void Player::Jump( Event *ev )
|
|
{
|
|
float maxheight;
|
|
|
|
maxheight = ev->GetFloat( 1 );
|
|
|
|
if ( maxheight > 16.0f )
|
|
{
|
|
// v^2 = 2ad
|
|
velocity[ 2 ] += sqrt( 2.0f * sv_currentGravity->integer * maxheight );
|
|
|
|
// make sure the player leaves the ground
|
|
client->ps.walking = false;
|
|
}
|
|
}
|
|
|
|
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_currentGravity->integer * time * 0.5f;
|
|
|
|
airspeed = distance;
|
|
|
|
// make sure the player leaves the ground
|
|
client->ps.walking = false;
|
|
}
|
|
|
|
void Player::StartFakePlayer( void )
|
|
{
|
|
Actor * fake;
|
|
|
|
//
|
|
// if we don't have a fakePlayer active, no need to check
|
|
//
|
|
if ( !fakePlayer_active )
|
|
{
|
|
return;
|
|
}
|
|
|
|
fakePlayer_active = false;
|
|
|
|
fakePlayer = new Actor;
|
|
|
|
if ( !fakePlayer )
|
|
return;
|
|
|
|
fake = fakePlayer;
|
|
|
|
CloneEntity( fake, this );
|
|
|
|
fake->SetTargetName( "fakeplayer" );
|
|
fake->ProcessEvent( EV_Actor_AIOff );
|
|
|
|
// make sure it thinks so that it can fall when necessary
|
|
fake->turnThinkOn();
|
|
|
|
// Make the fake player a stepsize shorter to prevent some collision issues
|
|
|
|
fake->maxs[2] -= STEPSIZE;
|
|
fake->setSize( mins, maxs );
|
|
|
|
fake->takedamage = DAMAGE_NO;
|
|
|
|
// hide the player
|
|
this->hideModel();
|
|
this->ProcessEvent( EV_Sentient_TurnOffShadow );
|
|
//
|
|
// immobolize the player
|
|
//
|
|
this->flags |= FL_IMMOBILE;
|
|
// make the player not solid
|
|
setSolidType( SOLID_NOT );
|
|
|
|
// let the scripts now we are ready
|
|
PostEvent( EV_Player_Done, 0.0f );
|
|
}
|
|
|
|
void Player::FakePlayer( qboolean holster )
|
|
{
|
|
//
|
|
// make sure we don't have one already
|
|
//
|
|
if ( fakePlayer )
|
|
{
|
|
return;
|
|
}
|
|
|
|
fakePlayer_active = true;
|
|
|
|
// if we are in the holster state, wait until next frame
|
|
// if we aren't process immediately
|
|
if ( !holster )
|
|
{
|
|
StartFakePlayer();
|
|
}
|
|
else
|
|
{
|
|
if ( WeaponsOut() )
|
|
{
|
|
SafeHolster( true );
|
|
}
|
|
}
|
|
}
|
|
|
|
void Player::RemoveFakePlayer( void )
|
|
{
|
|
Actor * fake;
|
|
|
|
//
|
|
// make sure we have one
|
|
//
|
|
if ( !fakePlayer )
|
|
{
|
|
return;
|
|
}
|
|
fake = fakePlayer;
|
|
|
|
//
|
|
// warp the real player to the fakeplayer location
|
|
//
|
|
this->setOrigin( fake->origin );
|
|
this->setAngles( fake->angles );
|
|
this->SetViewAngles( fake->angles );
|
|
// show the player
|
|
this->showModel();
|
|
this->ProcessEvent( EV_Sentient_TurnOnShadow );
|
|
// allow the player to move
|
|
this->flags &= ~FL_IMMOBILE;
|
|
// make the player solid
|
|
setSolidType( SOLID_BBOX );
|
|
// remove the fake
|
|
fake->PostEvent ( EV_Remove, 0.f );
|
|
// null out the fake player
|
|
fakePlayer = NULL;
|
|
SafeHolster( false );
|
|
}
|
|
|
|
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 ];
|
|
|
|
//MatrixTransformVector( base_righthand_pos, orientation, righthand_pos );
|
|
//MatrixTransformVector( base_lefthand_pos, orientation, lefthand_pos );
|
|
MatrixTransformVector( base_rightfoot_pos, orientation, rightfoot_pos );
|
|
MatrixTransformVector( base_leftfoot_pos, orientation, leftfoot_pos );
|
|
//righthand_pos += origin;
|
|
//lefthand_pos += origin;
|
|
rightfoot_pos += origin;
|
|
leftfoot_pos += origin;
|
|
}
|
|
|
|
void Player::DumpState( Event * )
|
|
{
|
|
gi.DPrintf( "Legs: %s Torso: %s\n", currentState_Legs ? currentState_Legs->getName() : "NULL", currentState_Torso->getName() );
|
|
}
|
|
|
|
void Player::ForceTorsoState( Event *ev )
|
|
{
|
|
State *ts = statemap_Torso->FindState( ev->GetString( 1 ) );
|
|
EvaluateState( ts );
|
|
}
|
|
|
|
void Player::TouchedUseAnim( Entity * ent )
|
|
{
|
|
toucheduseanim = ent;
|
|
}
|
|
|
|
void Player::ClearTarget( Event * )
|
|
{
|
|
targetEnemy = NULL;
|
|
}
|
|
|
|
void Player::AdjustTorso( Event *ev )
|
|
{
|
|
adjust_torso = ev->GetBoolean( 1 );
|
|
}
|
|
|
|
void Player::UseDualWield( Event * )
|
|
{
|
|
// This is triggered by the state machine.
|
|
// If there is a weapon in the dual wield list, use it, then remove it from the list.
|
|
if ( dual_wield_weaponlist.NumObjects() )
|
|
{
|
|
WeaponSetItem *dw;
|
|
|
|
dw = dual_wield_weaponlist.ObjectAt( 1 );
|
|
|
|
useWeapon( dw->name, dw->hand );
|
|
dual_wield_weaponlist.RemoveObjectAt( 1 );
|
|
delete dw;
|
|
}
|
|
else
|
|
{
|
|
dual_wield_active = false; // We are done wielding all the weapons
|
|
}
|
|
}
|
|
|
|
void Player::DualWield( Event *ev )
|
|
{
|
|
str leftweap, rightweap;
|
|
Weapon *leftactweap, *rightactweap, *dualactweap;
|
|
|
|
leftweap = ev->GetString( 1 );
|
|
rightweap = ev->GetString( 2 );
|
|
|
|
// Set the putaway flags on any active weapons
|
|
leftactweap = GetActiveWeapon( WEAPON_LEFT );
|
|
rightactweap = GetActiveWeapon( WEAPON_RIGHT );
|
|
dualactweap = GetActiveWeapon( WEAPON_DUAL );
|
|
|
|
// Check for any dual handed weapon being out, and mark it for putaway
|
|
if ( dualactweap )
|
|
{
|
|
dualactweap->SetPutAway( true );
|
|
}
|
|
|
|
// if the left and right weapons are already out, then holster them both
|
|
if (
|
|
( leftactweap && !leftweap.icmp( leftactweap->getName() ) ) &&
|
|
( rightactweap && !rightweap.icmp( rightactweap->getName() ) )
|
|
)
|
|
{
|
|
leftactweap->SetPutAway( true );
|
|
rightactweap->SetPutAway( true );
|
|
return;
|
|
}
|
|
|
|
WeaponSetItem *dualweap;
|
|
|
|
// Putaway the old weapons, and add the new ones to the dual_wield list
|
|
if ( !leftactweap )
|
|
{
|
|
dualweap = new WeaponSetItem;
|
|
dualweap->name = leftweap;
|
|
dualweap->hand = WEAPON_LEFT;
|
|
dual_wield_weaponlist.AddObject( dualweap );
|
|
}
|
|
else if ( leftweap.icmp( leftactweap->getName() ) )
|
|
{
|
|
leftactweap->SetPutAway( true );
|
|
|
|
dualweap = new WeaponSetItem;
|
|
dualweap->name = leftweap;
|
|
dualweap->hand = WEAPON_LEFT;
|
|
dual_wield_weaponlist.AddObject( dualweap );
|
|
}
|
|
|
|
if ( !rightactweap )
|
|
{
|
|
dualweap = new WeaponSetItem;
|
|
dualweap->name = rightweap;
|
|
dualweap->hand = WEAPON_RIGHT;
|
|
dual_wield_weaponlist.AddObject( dualweap );
|
|
}
|
|
else if ( rightweap.icmp( rightactweap->getName() ) )
|
|
{
|
|
rightactweap->SetPutAway( true );
|
|
|
|
dualweap = new WeaponSetItem;
|
|
dualweap->name = rightweap;
|
|
dualweap->hand = WEAPON_RIGHT;
|
|
dual_wield_weaponlist.AddObject( dualweap );
|
|
}
|
|
|
|
dual_wield_active = true;
|
|
}
|
|
|
|
void Player::EvaluateTorsoAnim( Event * )
|
|
{
|
|
str torsoAnim( currentState_Torso->getTorsoAnim( *this, &torso_conditionals ) );
|
|
if ( !animate->HasAnim(torsoAnim) )
|
|
torsoAnim = getGameplayAnim(torsoAnim);
|
|
|
|
if ( torsoAnim == "" )
|
|
{
|
|
partAnim[ torso ] = "";
|
|
animate->ClearTorsoAnim();
|
|
}
|
|
else if ( torsoAnim != "none" )
|
|
{
|
|
SetAnim( torsoAnim.c_str(), torso );
|
|
}
|
|
}
|
|
|
|
void Player::NextPainTime( Event *ev )
|
|
{
|
|
nextpaintime = level.time + ev->GetFloat( 1 );
|
|
pain_type = MOD_NONE;
|
|
pain = 0;
|
|
}
|
|
|
|
void Player::SetMouthAngle( Event *ev )
|
|
{
|
|
int tag_num;
|
|
float angle_percent;
|
|
Vector mouth_angles;
|
|
|
|
|
|
angle_percent = ev->GetFloat( 1 );
|
|
|
|
if ( angle_percent < 0.0f )
|
|
angle_percent = 0.0f;
|
|
|
|
if ( angle_percent > 1.0f )
|
|
angle_percent = 1.0f;
|
|
|
|
tag_num = gi.Tag_NumForName( edict->s.modelindex, "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->isSubclassOf( Vehicle ) )
|
|
{
|
|
flags |= FL_PARTIAL_IMMOBILE;
|
|
viewheight = STAND_EYE_HEIGHT;
|
|
velocity = vec_zero;
|
|
vehicle = ( Vehicle * )ent;
|
|
if ( vehicle->IsDrivable() )
|
|
setMoveType( MOVETYPE_VEHICLE );
|
|
else
|
|
setMoveType( MOVETYPE_NOCLIP );
|
|
}
|
|
}
|
|
|
|
void Player::ExitVehicle( Event * )
|
|
{
|
|
flags &= ~FL_PARTIAL_IMMOBILE;
|
|
setMoveType( MOVETYPE_WALK );
|
|
vehicle = NULL;
|
|
}
|
|
|
|
qboolean Player::WeaponsOut( void )
|
|
{
|
|
return ( GetActiveWeapon( WEAPON_LEFT ) || GetActiveWeapon( WEAPON_RIGHT ) || GetActiveWeapon( WEAPON_DUAL ) );
|
|
}
|
|
|
|
qboolean Player::IsDualWeaponActive( void )
|
|
{
|
|
if(GetActiveWeapon( WEAPON_LEFT ) || GetActiveWeapon( WEAPON_RIGHT ))
|
|
{
|
|
return qfalse;
|
|
}
|
|
|
|
return qtrue;
|
|
}
|
|
|
|
|
|
void Player::Holster( qboolean putaway )
|
|
{
|
|
// if(client->ps.pm_flags & PMF_DISABLE_INVENTORY)
|
|
// return;
|
|
|
|
Weapon *leftWeap, *rightWeap, *dualWeap;
|
|
|
|
leftWeap = GetActiveWeapon( WEAPON_LEFT );
|
|
rightWeap = GetActiveWeapon( WEAPON_RIGHT );
|
|
dualWeap = GetActiveWeapon( WEAPON_DUAL );
|
|
|
|
// Holster
|
|
if ( leftWeap || rightWeap || dualWeap )
|
|
{
|
|
if ( putaway )
|
|
{
|
|
if ( leftWeap )
|
|
{
|
|
leftWeap->SetPutAway( true );
|
|
holsteredWeapons[WEAPON_LEFT] = leftWeap;
|
|
}
|
|
if ( rightWeap )
|
|
{
|
|
rightWeap->SetPutAway( true );
|
|
holsteredWeapons[WEAPON_RIGHT] = rightWeap;
|
|
}
|
|
if ( dualWeap )
|
|
{
|
|
dualWeap->SetPutAway( true );
|
|
holsteredWeapons[WEAPON_DUAL] = dualWeap;
|
|
}
|
|
|
|
// Set a level var so the script can know if the player is going to holster
|
|
levelVars.SetVariable( "holster_active", 1 );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( !putaway )
|
|
{
|
|
// Unholster
|
|
if ( holsteredWeapons[WEAPON_DUAL] )
|
|
{
|
|
useWeapon( holsteredWeapons[WEAPON_DUAL], WEAPON_DUAL );
|
|
}
|
|
else if ( holsteredWeapons[WEAPON_LEFT] && holsteredWeapons[WEAPON_RIGHT] )
|
|
{
|
|
Event *ev1;
|
|
|
|
ev1 = new Event( EV_Player_DualWield );
|
|
ev1->AddString( holsteredWeapons[WEAPON_LEFT]->getName() );
|
|
ev1->AddString( holsteredWeapons[WEAPON_RIGHT]->getName() );
|
|
ProcessEvent( ev1 );
|
|
}
|
|
else if ( holsteredWeapons[WEAPON_RIGHT] )
|
|
{
|
|
useWeapon( holsteredWeapons[WEAPON_RIGHT], WEAPON_RIGHT );
|
|
}
|
|
else if ( holsteredWeapons[WEAPON_LEFT] )
|
|
{
|
|
useWeapon( holsteredWeapons[WEAPON_LEFT], WEAPON_LEFT );
|
|
}
|
|
|
|
holsteredWeapons[WEAPON_LEFT] = NULL;
|
|
holsteredWeapons[WEAPON_RIGHT] = NULL;
|
|
holsteredWeapons[WEAPON_DUAL] = NULL;
|
|
// Set a level var to let the script know there is no holstering
|
|
levelVars.SetVariable( "holster_active", 0 );
|
|
}
|
|
}
|
|
}
|
|
|
|
void Player::SafeHolster( qboolean putaway )
|
|
{
|
|
if ( WeaponsOut() )
|
|
{
|
|
if ( putaway )
|
|
{
|
|
weapons_holstered_by_code = true;
|
|
Holster( true );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( putaway )
|
|
{
|
|
if ( !fakePlayer_active )
|
|
{
|
|
WeaponsHolstered();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( weapons_holstered_by_code )
|
|
{
|
|
weapons_holstered_by_code = false;
|
|
Holster( false );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Player::WeaponsNotHolstered( void )
|
|
{
|
|
}
|
|
|
|
void Player::WeaponsHolstered( void )
|
|
{
|
|
}
|
|
|
|
void Player::setTargeted( bool targeted )
|
|
{
|
|
if ( targeted )
|
|
{
|
|
gi.SendServerCommand( entnum, "stufftext \"ui_addhud targetedhud\"\n");
|
|
}
|
|
else
|
|
{
|
|
gi.SendServerCommand( entnum, "stufftext \"ui_removehud targetedhud\"\n");
|
|
}
|
|
}
|
|
|
|
void Player::NightvisionToggle( Event * )
|
|
{
|
|
if ( level.cinematic )
|
|
return;
|
|
|
|
if ( ( multiplayerManager.isPlayerSpectator( this ) ) && ( client->ps.pm_flags ^ PMF_NIGHTVISION ) )
|
|
return;
|
|
|
|
client->ps.pm_flags ^= PMF_NIGHTVISION;
|
|
|
|
Event *newEvent;
|
|
newEvent = new Event( EV_Sentient_SetViewMode );
|
|
if (client->ps.pm_flags & PMF_NIGHTVISION)
|
|
newEvent->AddString("nightvision");
|
|
else
|
|
newEvent->AddString("normal");
|
|
ProcessEvent( newEvent );
|
|
}
|
|
|
|
void Player::HolsterToggle( Event * )
|
|
{
|
|
if ( WeaponsOut() )
|
|
{
|
|
Holster( true );
|
|
}
|
|
else
|
|
{
|
|
Holster( false );
|
|
}
|
|
}
|
|
|
|
void Player::Holster( Event *ev )
|
|
{
|
|
|
|
SafeHolster( ev->GetBoolean( 1 ) );
|
|
}
|
|
|
|
void Player::IncreaseActionLevel( float action_level_increase )
|
|
{
|
|
action_level += action_level_increase;
|
|
}
|
|
|
|
void Player::WatchEntity( Event *ev )
|
|
{
|
|
if ( camera || ( currentState_Torso->getCameraType() != CAMERA_BEHIND ) )
|
|
return;
|
|
|
|
watchEntityForEntireDuration = false;
|
|
|
|
if ( ev->NumArgs() > 1 )
|
|
{
|
|
Event *stopWatchingEvent = new Event( EV_Player_StopWatchingEntity );
|
|
stopWatchingEvent->AddEntity( ev->GetEntity( 1 ) );
|
|
const float timeToWatch = ev->GetFloat( 2 );
|
|
PostEvent( stopWatchingEvent, timeToWatch );
|
|
|
|
maximumAngleToWatchedEntity = ev->GetFloat( 3 );
|
|
|
|
if ( ev->NumArgs() > 3 )
|
|
{
|
|
watchEntityForEntireDuration = ev->GetBoolean( 4 );
|
|
}
|
|
|
|
}
|
|
|
|
entity_to_watch = ev->GetEntity( 1 );
|
|
}
|
|
|
|
void Player::StopWatchingEntity( Event * )
|
|
{
|
|
StopWatchingEntity();
|
|
}
|
|
|
|
void Player::setAngles( const Vector &ang )
|
|
{
|
|
Vector new_ang;
|
|
|
|
new_ang = ang;
|
|
|
|
// set the angles normally
|
|
Entity::setAngles( new_ang );
|
|
|
|
// set the orientation based off of the current view, also update our yaw_forward and yaw_left
|
|
new_ang[ YAW ] = v_angle[ YAW ];
|
|
AnglesToMat( new_ang, orientation );
|
|
yaw_forward = orientation[ 0 ];
|
|
yaw_left = orientation[ 1 ];
|
|
}
|
|
|
|
void Player::WeaponCommand( Event *ev )
|
|
{
|
|
weaponhand_t hand;
|
|
Weapon *weap;
|
|
int i;
|
|
|
|
if ( ev->NumArgs() < 2 )
|
|
return;
|
|
|
|
hand = WeaponHandNameToNum( ev->GetString( 1 ) );
|
|
weap = GetActiveWeapon( hand );
|
|
|
|
if ( !weap )
|
|
return;
|
|
|
|
Event *e;
|
|
e = new Event( ev->GetToken( 2 ) );
|
|
|
|
for( i=3; i<=ev->NumArgs(); i++ )
|
|
e->AddToken( ev->GetToken( i ) );
|
|
|
|
weap->ProcessEvent( e );
|
|
}
|
|
|
|
qboolean TryPush( int entnum, vec3_t move_origin, vec3_t move_end )
|
|
{
|
|
Actor *act;
|
|
Vector dir;
|
|
Vector dir2;
|
|
Entity *ent;
|
|
|
|
if ( entnum == ENTITYNUM_NONE )
|
|
return false;
|
|
|
|
ent = G_GetEntity( entnum );
|
|
|
|
if ( ent->isSubclassOf( Actor ) )
|
|
{
|
|
act = (Actor *) ent;
|
|
|
|
dir = act->origin - move_origin;
|
|
dir.z = 0.0f;
|
|
dir.normalize();
|
|
|
|
dir2 = move_end;
|
|
dir2 -= move_origin;
|
|
|
|
if ( act->flags & FL_FLY )
|
|
{
|
|
dir *= dir2.length() / 2.0f;
|
|
|
|
if ( act->movementSubsystem->Push( dir ) )
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
dir *= dir2.length();
|
|
|
|
Event *event = new Event( EV_Actor_Push );
|
|
event->AddVector( dir );
|
|
act->PostEvent( event, 0.0f );
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void Player::PlayerDone( Event * )
|
|
{
|
|
// This is used to let scripts know that the player is done doing something
|
|
|
|
// let any threads waiting on us know they can go ahead
|
|
Director.PlayerSpawned();
|
|
}
|
|
|
|
painDirection_t Player::Pain_string_to_int( const 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, qboolean sublevelTransition )
|
|
{
|
|
int i;
|
|
str model_name;
|
|
bool anglesArchived;
|
|
|
|
Sentient::ArchivePersistantData( arc, sublevelTransition );
|
|
|
|
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() );
|
|
}
|
|
|
|
for( i = 0; i < MAX_ACTIVE_WEAPONS; i++ )
|
|
{
|
|
str name;
|
|
if ( arc.Saving() )
|
|
{
|
|
if ( holsteredWeapons[ i ] )
|
|
{
|
|
name = holsteredWeapons[ i ]->getName();
|
|
}
|
|
else
|
|
{
|
|
name = "none";
|
|
}
|
|
}
|
|
arc.ArchiveString( &name );
|
|
if ( arc.Loading() )
|
|
{
|
|
if ( name != "none" )
|
|
{
|
|
holsteredWeapons[ i ] = ( Weapon * )FindItem( name );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( arc.Saving() )
|
|
{
|
|
if ( sublevelTransition && level._saveOrientation )
|
|
{
|
|
anglesArchived = true;
|
|
arc.ArchiveBool( &anglesArchived );
|
|
arc.ArchiveVector( &angles );
|
|
arc.ArchiveVector( &v_angle );
|
|
}
|
|
else
|
|
{
|
|
anglesArchived = false;
|
|
arc.ArchiveBool( &anglesArchived );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
arc.ArchiveBool( &anglesArchived );
|
|
|
|
if ( anglesArchived )
|
|
{
|
|
arc.ArchiveVector( &angles );
|
|
arc.ArchiveVector( &v_angle );
|
|
|
|
setAngles( angles );
|
|
SetViewAngles( v_angle );
|
|
}
|
|
}
|
|
|
|
|
|
// Force a re-evaluation of the player's state
|
|
LoadStateTable();
|
|
|
|
arc.ArchiveInteger(&_totalGameFrames);
|
|
_updateGameFrames = true;
|
|
|
|
arc.ArchiveInteger( &_secretsFound );
|
|
|
|
arc.ArchiveInteger( &_skillLevel );
|
|
|
|
arc.ArchiveRaw( client->ps.stats, sizeof( client->ps.stats ) );
|
|
}
|
|
|
|
const str Player::getPainShader( meansOfDeath_t mod, bool takeArmorIntoAccount )
|
|
{
|
|
if ( ( takeArmorIntoAccount ) && ( GetArmorValue() >= 100 ) )
|
|
return "ArmorDeflection";
|
|
else
|
|
return getPainShader( MOD_NumToName( mod ) );
|
|
}
|
|
|
|
const str Player::getPainShader( const char *MODName )
|
|
{
|
|
GameplayManager *gpm;
|
|
str modName;
|
|
const char *defaultName = "default";
|
|
|
|
gpm = GameplayManager::getTheGameplayManager();
|
|
|
|
if ( !gpm )
|
|
return str("");
|
|
|
|
modName = "MOD";
|
|
modName += MODName;
|
|
|
|
if ( !gpm->hasObject( modName ) )
|
|
{
|
|
if ( stricmp( MODName, defaultName ) == 0 )
|
|
return "";
|
|
else
|
|
return getPainShader( defaultName );
|
|
}
|
|
|
|
return gpm->getStringValue( modName, "PainShaderName" );
|
|
|
|
/* switch ( mod )
|
|
{
|
|
case MOD_NONE:
|
|
return "none";
|
|
break;
|
|
default:
|
|
return "electriclines";
|
|
break;
|
|
} */
|
|
}
|
|
|
|
void Player::SpawnDamageEffect( meansOfDeath_t mod )
|
|
{
|
|
/* switch ( mod )
|
|
{
|
|
case MOD_ELECTRIC:
|
|
// lint -fallthrough
|
|
case MOD_ELECTRICWATER:
|
|
//SpawnEffect( "fx_elecstrike.tik", origin );
|
|
//Sound( "sound/weapons/sword/electric/hitmix2.wav", 0 );
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
} */
|
|
|
|
if ( multiplayerManager.inMultiplayer() )
|
|
{
|
|
if ( ( mod != MOD_NONE ) && ( mod != MOD_DEATH_QUAD ) && ( _nextPainShaderTime < level.time ) && !hasCustomShader() )
|
|
{
|
|
str painShader = getPainShader( mod, true );
|
|
|
|
if ( painShader.length() > 0 )
|
|
{
|
|
setCustomShader( painShader );
|
|
|
|
_lastPainShaderMod = mod;
|
|
_nextPainShaderTime = level.time + 0.25f;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Player::ActivateDualWeapons( Event * )
|
|
{
|
|
int i;
|
|
|
|
Weapon *weapon = 0;
|
|
for ( i=dual_wield_weaponlist.NumObjects(); i>=1; i-- )
|
|
{
|
|
WeaponSetItem *dw;
|
|
|
|
dw = dual_wield_weaponlist.ObjectAt( i );
|
|
|
|
weapon = ( Weapon * )FindItem( dw->name, weapon );
|
|
|
|
// Check to see if player has the weapon
|
|
if ( !weapon )
|
|
{
|
|
warning( "Player::ActivateDualWeapons", "Player does not have weapon %s", dw->name.c_str() );
|
|
return;
|
|
}
|
|
|
|
ChangeWeapon( weapon, dw->hand );
|
|
dual_wield_weaponlist.RemoveObjectAt( i );
|
|
delete dw;
|
|
}
|
|
|
|
// Clear out the newActiveWeapon
|
|
ClearNewActiveWeapon();
|
|
|
|
// Clear out the holstered weapons
|
|
holsteredWeapons[WEAPON_LEFT] = NULL;
|
|
holsteredWeapons[WEAPON_RIGHT] = NULL;
|
|
holsteredWeapons[WEAPON_DUAL] = NULL;
|
|
|
|
// let the player know that our weapons are not holstered
|
|
WeaponsNotHolstered();
|
|
}
|
|
|
|
void Player::VelocityModified( void )
|
|
{
|
|
if ( velocity.z > 32.0f )
|
|
{
|
|
do_rise = true;
|
|
}
|
|
}
|
|
|
|
int Player::GetKnockback( int original_knockback, qboolean blocked )
|
|
{
|
|
int new_knockback;
|
|
|
|
new_knockback = original_knockback;
|
|
|
|
// If blocked, absorb some of the knockback
|
|
|
|
if ( blocked )
|
|
{
|
|
if ( LargeShieldActive() )
|
|
new_knockback -= 150;
|
|
else
|
|
new_knockback -= 50;
|
|
}
|
|
|
|
// See if we still have enough knockback to knock the player down
|
|
|
|
if ( ( new_knockback >= 200.0f ) && take_pain )
|
|
{
|
|
knockdown = true;
|
|
|
|
if ( blocked )
|
|
{
|
|
float damage;
|
|
|
|
damage = new_knockback / 50;
|
|
|
|
if ( damage > 10.0f )
|
|
damage = 10.0f;
|
|
|
|
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;
|
|
}
|
|
|
|
void Player::ResetHaveItem( Event *ev )
|
|
{
|
|
str fullname;
|
|
ScriptVariable * var;
|
|
|
|
fullname = str( "playeritem_" ) + ev->GetString( 1 );
|
|
|
|
var = gameVars.GetVariable( fullname.c_str() );
|
|
|
|
if ( var )
|
|
var->setIntValue( 0 );
|
|
}
|
|
|
|
void Player::ReceivedItem( Item * item )
|
|
{
|
|
qboolean forced;
|
|
qboolean first;
|
|
str fullname;
|
|
str dialog;
|
|
str anim;
|
|
ScriptVariable * var;
|
|
|
|
//
|
|
// set our global game variables
|
|
//
|
|
|
|
if ( item->isSubclassOf( Weapon ) )
|
|
{
|
|
setItemText( item->getIcon(), va( "$$PickedUpThe$$ $$Weapon-%s$$\n", item->getName().c_str() ) );
|
|
//gi.centerprintf ( edict, CENTERPRINT_IMPORTANCE_NORMAL, "$$PickedUpThe$$ $$%s$$\n", item->getName() );
|
|
}
|
|
else if ( item->getAmount() > 1 )
|
|
{
|
|
if ( item->getName() == "health" ) // I know this is horrible :(
|
|
setItemText( item->getIcon(), va( "$$PickedUp$$ %d $$Item-%s$$\n", (int)item->getAmount(), item->getName().c_str() ) );
|
|
//gi.centerprintf ( edict, CENTERPRINT_IMPORTANCE_NORMAL, "$$PickedUp$$ %d %s\n", (int)item->getAmount(), item->getName() );
|
|
else
|
|
setItemText( item->getIcon(), va( "$$PickedUp$$ %d $$Item-%s$$s\n", (int)item->getAmount(), item->getName().c_str() ) );
|
|
//gi.centerprintf ( edict, CENTERPRINT_IMPORTANCE_NORMAL, "$$PickedUp$$ %d %ss\n", (int)item->getAmount(), item->getName() );
|
|
}
|
|
else
|
|
{
|
|
setItemText( item->getIcon(), va( "$$PickedUpThe$$ $$Item-%s$$\n", item->getName().c_str() ) );
|
|
//gi.centerprintf ( edict, CENTERPRINT_IMPORTANCE_NORMAL, "$$PickedUpThe$$ %s\n", item->getName() );
|
|
}
|
|
|
|
fullname = str( "playeritem_" ) + item->getName();
|
|
|
|
first = true;
|
|
|
|
var = gameVars.GetVariable( fullname.c_str() );
|
|
if ( !var )
|
|
{
|
|
gameVars.SetVariable( fullname.c_str(), 1 );
|
|
}
|
|
else
|
|
{
|
|
int amount;
|
|
|
|
amount = var->intValue() + 1;
|
|
var->setIntValue( amount );
|
|
//
|
|
// if we just received it, let the player know
|
|
//
|
|
if ( amount > 1 )
|
|
{
|
|
first = false;
|
|
}
|
|
}
|
|
|
|
var = levelVars.GetVariable( fullname.c_str() );
|
|
if ( !var )
|
|
{
|
|
levelVars.SetVariable( fullname.c_str(), 1 );
|
|
}
|
|
else
|
|
{
|
|
int amount;
|
|
|
|
amount = var->intValue() + 1;
|
|
var->setIntValue( amount );
|
|
}
|
|
|
|
if ( item->IsItemCool( &dialog, &anim, &forced ) )
|
|
{
|
|
if ( first || forced )
|
|
{
|
|
cool_item = item;
|
|
cool_dialog = dialog;
|
|
cool_anim = anim;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Player::RemovedItem( Item * item )
|
|
{
|
|
str fullname;
|
|
ScriptVariable * var;
|
|
|
|
//
|
|
// set our global game variables if client
|
|
//
|
|
|
|
fullname = str( "playeritem_" ) + item->getName();
|
|
|
|
var = levelVars.GetVariable( fullname.c_str() );
|
|
if ( var )
|
|
{
|
|
int amount;
|
|
|
|
amount = var->intValue() - 1;
|
|
if ( amount < 0 )
|
|
amount = 0;
|
|
var->setIntValue( amount );
|
|
}
|
|
|
|
var = gameVars.GetVariable( fullname.c_str() );
|
|
if ( var )
|
|
{
|
|
int amount;
|
|
|
|
amount = var->intValue() - 1;
|
|
if ( amount < 0 )
|
|
amount = 0;
|
|
var->setIntValue( amount );
|
|
}
|
|
}
|
|
|
|
void Player::AmmoAmountChanged( Ammo * ammo, int ammo_in_clip )
|
|
{
|
|
str fullname;
|
|
ScriptVariable * var;
|
|
|
|
//
|
|
// set our level variables
|
|
//
|
|
fullname = str( "playerammo_" ) + ammo->getName();
|
|
|
|
var = levelVars.GetVariable( fullname.c_str() );
|
|
if ( !var )
|
|
{
|
|
levelVars.SetVariable( fullname.c_str(), ammo->getAmount() + ammo_in_clip );
|
|
}
|
|
else
|
|
{
|
|
var->setIntValue( ammo->getAmount() + ammo_in_clip );
|
|
}
|
|
}
|
|
|
|
void Player::StartCoolItem( Event * )
|
|
{
|
|
// turn off ai off during the cinematic
|
|
level.ai_on = false;
|
|
// make sure we don't take damage during this time
|
|
takedamage = DAMAGE_NO;
|
|
// freeze the player
|
|
level.playerfrozen = true;
|
|
// turn on cinematic mode
|
|
G_StartCinematic();
|
|
|
|
assert( ( Camera * )cool_camera == NULL );
|
|
// start playing the success music
|
|
if ( music_current_mood != mood_success )
|
|
{
|
|
ChangeMusic( "success", MusicMood_NumToName( music_current_mood ), false );
|
|
}
|
|
|
|
// create an orbit cam
|
|
cool_camera = new Camera();
|
|
cool_camera->SetOrbitHeight( 150.0f );
|
|
cool_camera->Orbit( this, 200.0f, this, -90.0f );
|
|
cool_camera->Cut( NULL );
|
|
SetCamera( cool_camera, 1.0f );
|
|
}
|
|
|
|
void Player::ShowCoolItem( Event * )
|
|
{
|
|
Entity *fx;
|
|
Vector org;
|
|
|
|
org = origin;
|
|
org.z += 128.0f;
|
|
|
|
fx = new Entity( ENTITY_CREATE_FLAG_ANIMATE );
|
|
|
|
fx->setOrigin( org );
|
|
fx->setModel( "fx_coolitem.tik" );
|
|
fx->animate->RandomAnimate( "idle" );
|
|
fx->PostEvent( EV_Remove, 1.0f );
|
|
|
|
if ( cool_item )
|
|
{
|
|
cool_item->setOrigin( org );
|
|
cool_item->PostEvent( EV_Show, 0.1f );
|
|
// place a lens flare on the object
|
|
cool_item->edict->s.renderfx |= RF_VIEWLENSFLARE;
|
|
|
|
if ( cool_dialog.length() )
|
|
{
|
|
Sound( cool_dialog, CHAN_DIALOG );
|
|
}
|
|
}
|
|
}
|
|
|
|
void Player::HideCoolItem( Event * )
|
|
{
|
|
Entity *fx;
|
|
Vector org;
|
|
|
|
org = origin;
|
|
org.z += 128.0f;
|
|
|
|
fx = new Entity( ENTITY_CREATE_FLAG_ANIMATE );
|
|
|
|
fx->setOrigin( org );
|
|
fx->setModel( "fx_coolitem_reverse.tik" );
|
|
fx->animate->RandomAnimate( "idle" );
|
|
fx->PostEvent( EV_Remove, 1.0f );
|
|
|
|
if ( cool_item )
|
|
{
|
|
Event * event;
|
|
|
|
cool_item->PostEvent( EV_Hide, 1.0f );
|
|
|
|
event = new Event( EV_SetOrigin );
|
|
event->AddVector( vec_zero );
|
|
cool_item->PostEvent( event, 1.0f );
|
|
// remove the lens flare on the object
|
|
cool_item->edict->s.renderfx &= ~RF_VIEWLENSFLARE;
|
|
}
|
|
}
|
|
|
|
void Player::StartCoolItemAnim( void )
|
|
{
|
|
movecontrol = MOVECONTROL_ABSOLUTE;
|
|
|
|
if ( cool_item && cool_anim.length() )
|
|
{
|
|
SetAnim( cool_anim, legs );
|
|
// clear out anim till next time
|
|
cool_anim = "";
|
|
}
|
|
}
|
|
|
|
void Player::StopCoolItem( Event * )
|
|
{
|
|
if ( cool_item && cool_anim.length() )
|
|
{
|
|
State * newState;
|
|
|
|
newState = statemap_Torso->FindState( "DO_COOL_ITEM_ANIM" );
|
|
if ( newState )
|
|
{
|
|
currentState_Torso = newState;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// turn ai back on
|
|
level.ai_on = true;
|
|
|
|
// turn damage back on
|
|
takedamage = DAMAGE_AIM;
|
|
|
|
// unfreeze the player
|
|
level.playerfrozen = false;
|
|
|
|
// turn off cinematic mode
|
|
G_StopCinematic();
|
|
|
|
cool_item = NULL;
|
|
|
|
// delete our camera
|
|
if ( cool_camera )
|
|
{
|
|
SetCamera( NULL, 1.0f );
|
|
delete cool_camera;
|
|
cool_camera = 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 )
|
|
{
|
|
}
|
|
|
|
void Player::PlayerShowModel( Event * )
|
|
{
|
|
Entity::showModel();
|
|
}
|
|
|
|
void Player::showModel( void )
|
|
{
|
|
Entity::showModel();
|
|
}
|
|
|
|
void Player::WarpToPoint( const Entity *spawnpoint )
|
|
{
|
|
if ( !spawnpoint )
|
|
return;
|
|
|
|
NoLerpThisFrame();
|
|
setOrigin( spawnpoint->origin + Vector( "0 0 1" ) );
|
|
origin.copyTo( edict->s.origin2 );
|
|
setAngles( spawnpoint->angles );
|
|
SetViewAngles( angles );
|
|
CameraCut();
|
|
|
|
oldvelocity = vec_zero;
|
|
velocity = vec_zero;
|
|
}
|
|
|
|
void Player::Gib( void )
|
|
{
|
|
/* str gib_name;
|
|
int number_of_gibs;
|
|
float scale;
|
|
Entity *ent;
|
|
str real_gib_name;
|
|
|
|
if ( !com_blood->integer )
|
|
return;
|
|
|
|
gib_name = "fx_rgib";
|
|
number_of_gibs = 5;
|
|
scale = 1.3;
|
|
|
|
// Spawn the gibs
|
|
real_gib_name = gib_name;
|
|
real_gib_name += number_of_gibs;
|
|
real_gib_name += ".tik";
|
|
|
|
ent = new Entity( ENTITY_CREATE_FLAG_ANIMATE );
|
|
ent->setModel( real_gib_name.c_str() );
|
|
ent->setScale( scale );
|
|
ent->setOrigin( centroid );
|
|
ent->animate->RandomAnimate( "idle" );
|
|
ent->PostEvent( EV_Remove, 1.0f );
|
|
|
|
this->hideModel();
|
|
Sound( "snd_decap", CHAN_BODY, 1.0f, 300.0f );
|
|
gibbed = true; */
|
|
}
|
|
|
|
void Player::ArmorDamage( Event *ev )
|
|
{
|
|
float oldHealth;
|
|
|
|
::Damage damage(ev);
|
|
|
|
// Protect the player from errant damage before fighting
|
|
if ( multiplayerManager.inMultiplayer() && !multiplayerManager.isFightingAllowed() )
|
|
return;
|
|
|
|
if ( multiplayerManager.inMultiplayer() && multiplayerManager.isPlayerSpectator( this ) )
|
|
return;
|
|
|
|
// Quick dirty hack to do no damage when you have the shield up.
|
|
if ( shield_active )
|
|
{
|
|
// Code to be implemented soon.
|
|
Weapon *weapon = GetActiveWeapon(WEAPON_RIGHT);
|
|
if ( !weapon )
|
|
return;
|
|
|
|
Vector attack_angle;
|
|
float yaw_diff;
|
|
attack_angle = damage.attacker->angles;
|
|
yaw_diff = angles[YAW] - attack_angle[YAW] + 180.0f;
|
|
yaw_diff = AngleNormalize180( yaw_diff );
|
|
if ( ( yaw_diff > -45.0f ) && ( yaw_diff < 45.0f ) )
|
|
{
|
|
int tagnum = 0;
|
|
tagnum = gi.Tag_NumForName( weapon->edict->s.modelindex, "tag_swipe1" );
|
|
if ( tagnum >= 0)
|
|
{
|
|
Vector pos, pos2, sparkpos;
|
|
weapon->GetActorMuzzlePosition(&pos, NULL, NULL, NULL, "tag_swipe1");
|
|
weapon->GetActorMuzzlePosition(&pos2, NULL, NULL, NULL, "tag_swipe2");
|
|
sparkpos = (pos + pos2) / 2.0f; // Spark is halfway between the two points
|
|
WeaponEffectsAndSound( weapon, "Parry", sparkpos );
|
|
}
|
|
|
|
if ( damage.attacker->isSubclassOf( Sentient ) )
|
|
{
|
|
Sentient *sent = ( Sentient * )damage.attacker;
|
|
sent->SetAttackBlocked( true );
|
|
}
|
|
|
|
//attack_blocked = true;
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ( _powerup )
|
|
damage.damage = _powerup->getDamageTaken( damage.attacker, damage.damage, damage.meansofdeath );
|
|
|
|
if ( _rune )
|
|
damage.damage = _rune->getDamageTaken( damage.attacker, damage.damage, damage.meansofdeath );
|
|
|
|
if ( multiplayerManager.inMultiplayer() && damage.attacker->isSubclassOf( Player ) )
|
|
{
|
|
damage.damage = multiplayerManager.playerDamaged( this, (Player *)damage.attacker, damage.damage, damage.meansofdeath );
|
|
|
|
damage.knockback = (int)multiplayerManager.getModifiedKnockback( this, (Player *)damage.attacker, damage.knockback );
|
|
}
|
|
|
|
if ( !multiplayerManager.inMultiplayer() && ( damage.meansofdeath != MOD_FALLING ) )
|
|
{
|
|
GameplayManager *gpm;
|
|
float damageMultiplier;
|
|
int skillLevel;
|
|
|
|
skillLevel = getSkill();
|
|
|
|
gpm = GameplayManager::getTheGameplayManager();
|
|
|
|
if ( gpm->hasObject( "SkillLevel-PlayerDamage" ) )
|
|
{
|
|
if ( skillLevel == 0 )
|
|
damageMultiplier = gpm->getFloatValue( "SkillLevel-PlayerDamage", "Easy" );
|
|
else if ( skillLevel == 1 )
|
|
damageMultiplier = gpm->getFloatValue( "SkillLevel-PlayerDamage", "Normal" );
|
|
else if ( skillLevel == 2 )
|
|
damageMultiplier = gpm->getFloatValue( "SkillLevel-PlayerDamage", "Hard" );
|
|
else
|
|
damageMultiplier = gpm->getFloatValue( "SkillLevel-PlayerDamage", "VeryHard" );
|
|
|
|
|
|
damage.damage *= damageMultiplier;
|
|
}
|
|
}
|
|
|
|
oldHealth = health;
|
|
|
|
Sentient::ArmorDamage(damage);
|
|
|
|
if ( multiplayerManager.inMultiplayer() )
|
|
{
|
|
float damageTaken;
|
|
|
|
damageTaken = oldHealth - health;
|
|
|
|
if ( damageTaken > 0.0f )
|
|
{
|
|
// Increase victim's action level
|
|
|
|
if ( damage.meansofdeath > MOD_LAST_SELF_INFLICTED )
|
|
{
|
|
IncreaseActionLevel( damageTaken );
|
|
}
|
|
|
|
if ( damage.attacker->isSubclassOf( Player ) )
|
|
{
|
|
Player *attackingPlayer = (Player *)damage.attacker;
|
|
|
|
// Tell the multiplayer system that the player took damage
|
|
|
|
multiplayerManager.playerTookDamage( this, attackingPlayer, damageTaken, damage.meansofdeath );
|
|
|
|
// Increase attacker's action level
|
|
|
|
if ( attackingPlayer != this )
|
|
{
|
|
attackingPlayer->IncreaseActionLevel( damageTaken );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If we're dead, go ahead and gib completely on Projectiles
|
|
if ( ( multiplayerManager.inMultiplayer() ) && ( health <= 0.0f ) && damage.inflictor->isSubclassOf( Projectile ) )
|
|
{
|
|
Gib();
|
|
}
|
|
}
|
|
|
|
void Player::DeadBody( Event * )
|
|
{
|
|
// Spawn a dead body at the spot
|
|
Body *body;
|
|
int surfaceNum;
|
|
|
|
if ( ( pain_type == MOD_VAPORIZE ) || ( pain_type == MOD_VAPORIZE_COMP ) ||
|
|
( pain_type == MOD_VAPORIZE_DISRUPTOR ) || ( pain_type == MOD_VAPORIZE_PHOTON ) || ( pain_type == MOD_SNIPER ))
|
|
return;
|
|
|
|
body = new Body;
|
|
|
|
if ( gibbed )
|
|
return;
|
|
|
|
body->setModel( this->model );
|
|
body->ProcessInitCommands( body->edict->s.modelindex );
|
|
body->edict->s.anim = this->edict->s.anim;
|
|
body->edict->s.frame = this->edict->s.frame;
|
|
|
|
//body->edict->s.torso_anim = this->edict->s.anim;
|
|
//body->edict->s.torso_frame = this->edict->s.frame;
|
|
|
|
body->edict->s.torso_anim = this->edict->s.torso_anim;
|
|
body->edict->s.torso_frame = this->edict->s.torso_frame;
|
|
body->edict->s.scale = this->edict->s.scale;
|
|
|
|
body->setOrigin( this->origin );
|
|
body->setAngles( this->angles );
|
|
|
|
// Copy over all of the surface data from the player to the body
|
|
|
|
for( surfaceNum = 0 ; surfaceNum < numsurfaces ; surfaceNum++ )
|
|
{
|
|
body->edict->s.surfaces[ surfaceNum ] = edict->s.surfaces[ surfaceNum ];
|
|
}
|
|
}
|
|
|
|
void Player::ShowHeuristics( Event * )
|
|
{
|
|
|
|
if ( p_heuristics )
|
|
p_heuristics->ShowHeuristics( this );
|
|
}
|
|
|
|
void Player::FireWeapon( Event *ev )
|
|
{
|
|
Sentient::FireWeapon(ev);
|
|
}
|
|
|
|
void Player::ReleaseFireWeapon( Event *ev )
|
|
{
|
|
Sentient::ReleaseFireWeapon(ev);
|
|
}
|
|
|
|
void Player::SetAimType( Event *ev )
|
|
{
|
|
Weapon* weapon = 0;
|
|
weapon = GetActiveWeapon( WEAPON_DUAL );
|
|
if (!weapon )
|
|
return;
|
|
|
|
// Forward the event to the weapon itself
|
|
weapon->SetAimType( ev );
|
|
}
|
|
|
|
void Player::ReloadWeapon( Event * )
|
|
{
|
|
Weapon* weapon = 0;
|
|
weapon = GetActiveWeapon( WEAPON_DUAL );
|
|
if (!weapon )
|
|
return;
|
|
|
|
// Reload
|
|
weapon->ForceReload();
|
|
}
|
|
|
|
void Player::AnimateWeapon( Event *ev )
|
|
{
|
|
Weapon* weapon = 0;
|
|
weaponhand_t hand = WEAPON_DUAL;
|
|
bool animatingFlag = true;
|
|
|
|
if ( ev->NumArgs() > 1 )
|
|
hand = WeaponHandNameToNum(ev->GetString( 2 ));
|
|
|
|
if ( ev->NumArgs() > 2 )
|
|
animatingFlag = ev->GetBoolean( 3 );
|
|
|
|
weapon = GetActiveWeapon( hand );
|
|
if ( !weapon )
|
|
return;
|
|
|
|
weapon->playAnim( ev->GetString( 1 ), animatingFlag );
|
|
}
|
|
|
|
void Player::SwitchWeaponMode( Event * )
|
|
{
|
|
Weapon* weapon = 0;
|
|
weapon = GetActiveWeapon( WEAPON_DUAL );
|
|
if (!weapon )
|
|
return;
|
|
|
|
// Switch Modes
|
|
weapon->SwitchMode();
|
|
}
|
|
|
|
qboolean Player::GetCrouch( void )
|
|
{
|
|
if ( last_ucmd.upmove < 0 ) // check for downward movement
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
void Player::ReloadTiki( Event *ev )
|
|
{
|
|
if ( ev->NumArgs() < 1 )
|
|
return;
|
|
|
|
int frame, anim, animstate;
|
|
Viewthing *viewthing;
|
|
|
|
viewthing = ( Viewthing * )( ( Entity * )Viewmodel.current_viewthing );
|
|
if ( !viewthing )
|
|
return;
|
|
|
|
// Save off info about the current viewspawn
|
|
frame = viewthing->frame;
|
|
anim = viewthing->CurrentAnim();
|
|
Vector vieworigin(viewthing->origin.x, viewthing->origin.y, viewthing->origin.z);
|
|
Vector viewangles(viewthing->angles.x, viewthing->angles.y, viewthing->angles.z);
|
|
|
|
// We're actually going to call ToggleAnimationState, so we
|
|
// set the animstate here one less than the real state
|
|
animstate = viewthing->animstate-1;
|
|
if ( animstate < 0 )
|
|
animstate = -1;
|
|
|
|
// Process the event that deletes the old viewmodel and spawns the new one
|
|
Event *ev2 = new Event(EV_ViewThing_SpawnFromTS);
|
|
ev2->AddString(ev->GetString(1));
|
|
ev2->AddString(viewthing->model);
|
|
Viewmodel.ProcessEvent(ev2);
|
|
|
|
// Re-get the new viewthing pointer
|
|
viewthing = ( Viewthing * )( ( Entity * )Viewmodel.current_viewthing );
|
|
|
|
// Update all its info to be the same to the one we deleted
|
|
ev2 = new Event;
|
|
ev2->AddFloat(vieworigin.x);
|
|
ev2->AddFloat(vieworigin.y);
|
|
ev2->AddFloat(vieworigin.z);
|
|
viewthing->ChangeOrigin(ev2);
|
|
if ( ev2 ) delete ev2;
|
|
|
|
ev2 = new Event;
|
|
ev2->AddFloat(viewangles.x);
|
|
ev2->AddFloat(viewangles.y);
|
|
ev2->AddFloat(viewangles.z);
|
|
viewthing->SetAnglesEvent(ev2);
|
|
|
|
viewthing->frame = frame;
|
|
viewthing->SetAnim(anim);
|
|
viewthing->animstate = animstate;
|
|
if ( ev2 ) delete ev2;
|
|
ev2 = new Event;
|
|
viewthing->ToggleAnimateEvent(ev2);
|
|
}
|
|
|
|
void Player::SetViewAnglesEvent( Event *ev )
|
|
{
|
|
if ( ev->NumArgs() > 0 )
|
|
SetViewAngles(ev->GetVector(1));
|
|
}
|
|
|
|
void Player::ProjDetonate(Event *ev)
|
|
{
|
|
if ( ev->NumArgs() > 0 )
|
|
projdetonate = ev->GetBoolean(1);
|
|
}
|
|
|
|
void Player::SetProjDetonate(qboolean value)
|
|
{
|
|
projdetonate = value;
|
|
}
|
|
|
|
qboolean Player::GetProjDetonate()
|
|
{
|
|
Weapon *weapon;
|
|
|
|
if ( projdetonate )
|
|
return true;
|
|
|
|
weapon = GetActiveWeapon( WEAPON_DUAL );
|
|
|
|
if ( !weapon )
|
|
return false;
|
|
|
|
if ( ( weapon->GetFireType( FIRE_MODE1 ) == FT_TRIGGER_PROJECTILE ) && ( isButtonDown( BUTTON_ATTACKLEFT ) ) )
|
|
return true;
|
|
|
|
if ( ( weapon->GetFireType( FIRE_MODE2 ) == FT_TRIGGER_PROJECTILE ) && ( isButtonDown( BUTTON_ATTACKRIGHT ) ) )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
void Player::PassEventToVehicle( Event *ev )
|
|
{
|
|
if ( vehicle )
|
|
vehicle->HandleEvent( ev );
|
|
}
|
|
|
|
void Player::UseSpecifiedEntity( Event *ev )
|
|
{
|
|
Event *event = NULL;
|
|
Entity *ent = NULL;
|
|
|
|
// Event with a param is old functionality
|
|
if ( ev->NumArgs() > 0 )
|
|
{
|
|
ent = ev->GetEntity( 1 );
|
|
if ( ent == 0 )
|
|
{
|
|
Com_Error ( ERR_DROP , "UseSpecifiedEntity(): NULL entity referenced\n" );
|
|
return;
|
|
}
|
|
|
|
event = new Event( EV_Use );
|
|
event->AddEntity( this );
|
|
ent->ProcessEvent( event );
|
|
return;
|
|
}
|
|
else // No params, new functionality
|
|
{
|
|
if ( !atobject )
|
|
return;
|
|
ent = (Entity *)atobject;
|
|
if ( !ent->hasUseData() )
|
|
return;
|
|
|
|
ent->useData->useMe();
|
|
|
|
if ( ent->useData->getUseAnim().length() > 0 && animate->HasAnim(ent->useData->getUseAnim()) )
|
|
{
|
|
// We are assuming we have a valid anim that
|
|
// will manually trigger the use on a specific frame
|
|
// using the "douseentity" call
|
|
|
|
SetAnim( ent->useData->getUseAnim(), legs );
|
|
movecontrol = MOVECONTROL_ABSOLUTE;
|
|
_usingEntity = true;
|
|
_useEntityStartTimer = level.time + 2.5f;
|
|
}
|
|
else
|
|
{
|
|
// No animation, just call the thread and notify the entity
|
|
// he's been used.
|
|
if ( ent->useData->getUseThread().length() > 0 )
|
|
ExecuteThread(ent->useData->getUseThread().c_str(), true, ent);
|
|
|
|
_usingEntity = false; // No anim, so we can just leave the state immediately.
|
|
|
|
// If it's an item, we're going to pick it up, so no need to call
|
|
// it's use event. Check the gameplay manager to make sure this item
|
|
// cannot be auto-picked up.
|
|
GameplayManager *gpm = GameplayManager::getTheGameplayManager();
|
|
if ( ent->isSubclassOf(Item) && gpm->hasProperty(ent->getArchetype(), "noautopickup"))
|
|
{
|
|
Item *item = (Item *)ent;
|
|
handlePickupItem(item);
|
|
return;
|
|
}
|
|
|
|
event = new Event( EV_Use );
|
|
event->AddEntity( this );
|
|
ent->ProcessEvent( event );
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: handlePickupItem
|
|
// Class: Player
|
|
//
|
|
// Description: Called when the user has clicked on a useentity that
|
|
// happens to be an item. The default behavior of this
|
|
// action is to put the item in the inventory and remove
|
|
// it from the world.
|
|
//
|
|
// Parameters: Item *item -- The item to pick up
|
|
//
|
|
// Returns: None
|
|
//
|
|
//--------------------------------------------------------------
|
|
void Player::handlePickupItem( Item *item )
|
|
{
|
|
GameplayManager *gpm = GameplayManager::getTheGameplayManager();
|
|
str type = item->getArchetype();
|
|
str invslot = gpm->getStringValue(type, "invslot");
|
|
if ( invslot.length() )
|
|
{
|
|
float quantity = gpm->getFloatValue(invslot, "quantity");
|
|
quantity += 1.0f;
|
|
gpm->setFloatValue(invslot, "quantity", quantity);
|
|
gpm->setStringValue(invslot, "name", type);
|
|
}
|
|
else
|
|
{
|
|
str slotName = getFreeInventorySlot();
|
|
if ( !slotName.length() )
|
|
return;
|
|
|
|
gpm->setStringValue(slotName, "name", type);
|
|
}
|
|
|
|
str snd = gpm->getStringValue(type + ".Pickup", "wav");
|
|
if ( snd.length() )
|
|
{
|
|
int channel = CHAN_BODY;
|
|
float volume = -1.0f;
|
|
float mindist = -1.0f;
|
|
if ( gpm->hasProperty(type + ".Pickup","channel") )
|
|
channel = (int)gpm->getFloatValue(type + ".Pickup", "channel");
|
|
if ( gpm->hasProperty(getArchetype() + ".Pickup","volume") )
|
|
volume = (int)gpm->getFloatValue(getArchetype() + ".Pickup", "volume");
|
|
if ( gpm->hasProperty(getArchetype() + ".Pickup","mindist") )
|
|
mindist = (int)gpm->getFloatValue(getArchetype() + ".Pickup", "mindist");
|
|
item->Sound(snd, channel, volume, mindist);
|
|
}
|
|
|
|
// Remove the item from the world
|
|
item->ProcessEvent(EV_Remove);
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: doUseEntity
|
|
// Class: Player
|
|
//
|
|
// Description: Called from the tiki to do the actual useentity
|
|
//
|
|
// Parameters: Event *ev
|
|
//
|
|
// Returns: None
|
|
//
|
|
//--------------------------------------------------------------
|
|
void Player::doUseEntity( Event * )
|
|
{
|
|
Entity *ent = NULL;
|
|
Event *event = NULL;
|
|
|
|
if ( !atobject )
|
|
return;
|
|
|
|
ent = (Entity *)atobject;
|
|
if ( !ent->hasUseData() )
|
|
return;
|
|
|
|
if ( ent->useData->getUseThread().length() > 0 )
|
|
ExecuteThread(ent->useData->getUseThread().c_str(), true, ent);
|
|
|
|
// If it's an item, we're going to pick it up, so no need to call
|
|
// it's use event. Check the gameplay manager to make sure this item
|
|
// cannot be auto-picked up.
|
|
GameplayManager *gpm = GameplayManager::getTheGameplayManager();
|
|
if ( ent->isSubclassOf(Item) && gpm->hasProperty(ent->getArchetype(), "noautopickup"))
|
|
{
|
|
Item *item = (Item *)ent;
|
|
handlePickupItem(item);
|
|
return;
|
|
}
|
|
|
|
event = new Event( EV_Use );
|
|
event->AddEntity( this );
|
|
ent->ProcessEvent( event );
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: doneUseEntity
|
|
// Class: Player
|
|
//
|
|
// Description: Called when the useentity animation is done
|
|
//
|
|
// Parameters: Event *ev
|
|
//
|
|
// Returns: None
|
|
//
|
|
//--------------------------------------------------------------
|
|
void Player::doneUseEntity( Event * )
|
|
{
|
|
_usingEntity = false;
|
|
level.playerfrozen = false;
|
|
_useEntityStartTimer = 0.0f;
|
|
SetState("STAND", "STAND");
|
|
}
|
|
|
|
void Player::SetupDialog( Event *ev )
|
|
{
|
|
Entity *entity;
|
|
str soundName;
|
|
|
|
entity = ev->GetEntity( 1 );
|
|
soundName = ev->GetString( 2 );
|
|
|
|
SetupDialog( entity, soundName );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name:
|
|
// Class:
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Returns:
|
|
//-----------------------------------------------------
|
|
void Player::SetupDialog( Entity *entity, const str &soundName )
|
|
{
|
|
if( gi.SoundLength( soundName.c_str() ) <= 0 )
|
|
return;
|
|
|
|
//If we have an entity, then we are dealing with Dialog events.
|
|
if ( entity )
|
|
{
|
|
handleDialogSetup(entity, soundName);
|
|
}
|
|
else
|
|
{
|
|
handleTextDialogSetup( soundName );
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name:
|
|
// Class:
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Returns:
|
|
//-----------------------------------------------------
|
|
void Player::handleDialogSetup( Entity* entity, const str& soundName )
|
|
{
|
|
// Set the correct info and post the clear event when done
|
|
// Make sure all current clears are canceled
|
|
CancelEventsOfType( EV_Player_ClearDialog );
|
|
|
|
// Make sure current stuff is cleared properly
|
|
|
|
ClearDialog();
|
|
|
|
if ( gi.SoundLength( soundName.c_str() ) >= 0 )
|
|
{
|
|
_dialogEntnum = entity->entnum;
|
|
_dialogSoundIndex = gi.soundindex( soundName.c_str() );
|
|
|
|
PostEvent( EV_Player_ClearDialog, gi.SoundLength( soundName.c_str() ) );
|
|
}
|
|
else
|
|
{
|
|
ProcessEvent( EV_Player_ClearDialog );
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name:
|
|
// Class:
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Returns:
|
|
//-----------------------------------------------------
|
|
void Player::handleTextDialogSetup( const str& soundName )
|
|
{
|
|
// Set the correct info and post the clear event when done
|
|
// Make sure all current clears are canceled
|
|
CancelEventsOfType( EV_Player_ClearTextDialog );
|
|
|
|
// Make sure current stuff is cleared properly
|
|
ClearTextDialog();
|
|
|
|
if ( gi.SoundLength( soundName.c_str() ) >= 0 )
|
|
{
|
|
_dialogTextSoundIndex = gi.soundindex( soundName.c_str() );
|
|
PostEvent( EV_Player_ClearTextDialog, gi.SoundLength( soundName.c_str() ) );
|
|
}
|
|
else
|
|
{
|
|
ProcessEvent( EV_Player_ClearTextDialog );
|
|
}
|
|
}
|
|
|
|
|
|
void Player::ClearDialog( Event * )
|
|
{
|
|
ClearDialog();
|
|
}
|
|
|
|
void Player::ClearDialog( void )
|
|
{
|
|
// Clear the dialog info
|
|
_dialogEntnum = ENTITYNUM_NONE;
|
|
_dialogSoundIndex = -1;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name:
|
|
// Class:
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Returns:
|
|
//-----------------------------------------------------
|
|
void Player::ClearTextDialog( Event* )
|
|
{
|
|
ClearTextDialog();
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name:
|
|
// Class:
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Returns:
|
|
//-----------------------------------------------------
|
|
void Player::ClearTextDialog( void )
|
|
{
|
|
_dialogTextSoundIndex = -1;
|
|
}
|
|
|
|
|
|
//
|
|
// Objective Functions
|
|
//
|
|
void Player::SetObjectiveComplete( Event* ev )
|
|
{
|
|
int ObjIndex;
|
|
str ObjName;
|
|
qboolean Complete;
|
|
|
|
ObjName = ev->GetString( 1 );
|
|
Complete = ev->GetBoolean( 2 );
|
|
|
|
ObjIndex = gi.MObjective_GetIndexFromName( ObjName.c_str() );
|
|
if ( ObjIndex == 0 )
|
|
return;
|
|
|
|
switch ( ObjIndex )
|
|
{
|
|
case OBJECTIVE1:
|
|
if ( Complete )
|
|
_objectiveStates |= OBJECTIVE1_COMPLETE;
|
|
else
|
|
_objectiveStates &= ~(OBJECTIVE1_COMPLETE);
|
|
break;
|
|
|
|
case OBJECTIVE2:
|
|
if ( Complete )
|
|
_objectiveStates |= OBJECTIVE2_COMPLETE;
|
|
else
|
|
_objectiveStates &= ~(OBJECTIVE2_COMPLETE);
|
|
break;
|
|
|
|
case OBJECTIVE3:
|
|
if ( Complete )
|
|
_objectiveStates |= OBJECTIVE3_COMPLETE;
|
|
else
|
|
_objectiveStates &= ~(OBJECTIVE3_COMPLETE);
|
|
|
|
break;
|
|
|
|
case OBJECTIVE4:
|
|
if ( Complete )
|
|
_objectiveStates |= OBJECTIVE4_COMPLETE;
|
|
else
|
|
_objectiveStates &= ~(OBJECTIVE4_COMPLETE);
|
|
|
|
break;
|
|
|
|
case OBJECTIVE5:
|
|
if ( Complete )
|
|
_objectiveStates |= OBJECTIVE5_COMPLETE;
|
|
else
|
|
_objectiveStates &= ~(OBJECTIVE5_COMPLETE);
|
|
|
|
break;
|
|
|
|
case OBJECTIVE6:
|
|
if ( Complete )
|
|
_objectiveStates |= OBJECTIVE6_COMPLETE;
|
|
else
|
|
_objectiveStates &= ~(OBJECTIVE6_COMPLETE);
|
|
|
|
break;
|
|
|
|
case OBJECTIVE7:
|
|
if ( Complete )
|
|
_objectiveStates |= OBJECTIVE7_COMPLETE;
|
|
else
|
|
_objectiveStates &= ~(OBJECTIVE7_COMPLETE);
|
|
|
|
break;
|
|
|
|
case OBJECTIVE8:
|
|
if ( Complete )
|
|
_objectiveStates |= OBJECTIVE8_COMPLETE;
|
|
else
|
|
_objectiveStates &= ~(OBJECTIVE8_COMPLETE);
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
|
|
// gi.MObjective_SetObjectiveComplete( ObjName.c_str() , Complete );
|
|
}
|
|
|
|
|
|
|
|
void Player::SetObjectiveFailed( Event *ev )
|
|
{
|
|
int ObjIndex;
|
|
str ObjName;
|
|
qboolean Failed;
|
|
|
|
ObjName = ev->GetString( 1 );
|
|
Failed = ev->GetBoolean( 2 );
|
|
|
|
ObjIndex = gi.MObjective_GetIndexFromName( ObjName.c_str() );
|
|
if ( ObjIndex == 0 )
|
|
return;
|
|
|
|
switch ( ObjIndex )
|
|
{
|
|
case OBJECTIVE1:
|
|
if ( Failed )
|
|
_objectiveStates |= OBJECTIVE1_FAILED;
|
|
else
|
|
_objectiveStates &= ~(OBJECTIVE1_FAILED);
|
|
break;
|
|
|
|
case OBJECTIVE2:
|
|
if ( Failed )
|
|
_objectiveStates |= OBJECTIVE2_FAILED;
|
|
else
|
|
_objectiveStates &= ~(OBJECTIVE2_FAILED);
|
|
|
|
break;
|
|
|
|
case OBJECTIVE3:
|
|
if ( Failed )
|
|
_objectiveStates |= OBJECTIVE3_FAILED;
|
|
else
|
|
_objectiveStates &= ~(OBJECTIVE3_FAILED);
|
|
|
|
break;
|
|
|
|
case OBJECTIVE4:
|
|
if ( Failed )
|
|
_objectiveStates |= OBJECTIVE4_FAILED;
|
|
else
|
|
_objectiveStates &= ~(OBJECTIVE4_FAILED);
|
|
|
|
break;
|
|
|
|
case OBJECTIVE5:
|
|
if ( Failed )
|
|
_objectiveStates |= OBJECTIVE5_FAILED;
|
|
else
|
|
_objectiveStates &= ~(OBJECTIVE5_FAILED);
|
|
|
|
break;
|
|
|
|
case OBJECTIVE6:
|
|
if ( Failed )
|
|
_objectiveStates |= OBJECTIVE6_FAILED;
|
|
else
|
|
_objectiveStates &= ~(OBJECTIVE6_FAILED);
|
|
|
|
break;
|
|
|
|
case OBJECTIVE7:
|
|
if ( Failed )
|
|
_objectiveStates |= OBJECTIVE7_FAILED;
|
|
else
|
|
_objectiveStates &= ~(OBJECTIVE7_FAILED);
|
|
|
|
|
|
case OBJECTIVE8:
|
|
if ( Failed )
|
|
_objectiveStates |= OBJECTIVE8_FAILED;
|
|
else
|
|
_objectiveStates &= ~(OBJECTIVE8_FAILED);
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// gi.MObjective_SetObjectiveFailed( ObjName.c_str() , Failed );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name: LoadObjectives
|
|
// Class: Player
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Returns:
|
|
//-----------------------------------------------------
|
|
void Player::LoadObjectives(Event* ev)
|
|
{
|
|
loadObjectives(ev->GetString(1));
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name: loadObjectives
|
|
// Class: Player
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Returns:
|
|
//-----------------------------------------------------
|
|
void Player::loadObjectives( const str& objectiveName )
|
|
{
|
|
_objectiveStates = 0;
|
|
_informationStates = 0;
|
|
gi.MObjective_Update(objectiveName);
|
|
|
|
_objectiveNameIndex = gi.objectivenameindex(objectiveName);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name: SetObjectiveShow
|
|
// Class: Player
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Returns:
|
|
//-----------------------------------------------------
|
|
void Player::SetObjectiveShow( Event* ev )
|
|
{
|
|
int ObjIndex;
|
|
str ObjName;
|
|
qboolean Show;
|
|
bool playSound;
|
|
|
|
playSound = false;
|
|
|
|
ObjName = ev->GetString( 1 );
|
|
Show = ev->GetBoolean( 2 );
|
|
|
|
|
|
ObjIndex = gi.MObjective_GetIndexFromName( ObjName.c_str() );
|
|
if ( ObjIndex == 0 )
|
|
return;
|
|
|
|
//Update the objective show flag.
|
|
gi.MObjective_SetShowObjective(ObjName.c_str(), Show);
|
|
|
|
|
|
//Set the appropriate bit on the flag passed to the client.
|
|
unsigned int bitToChange;
|
|
|
|
switch ( ObjIndex )
|
|
{
|
|
case OBJECTIVE1:
|
|
bitToChange = OBJECTIVE1_SHOW;
|
|
break;
|
|
case OBJECTIVE2:
|
|
bitToChange = OBJECTIVE2_SHOW;
|
|
break;
|
|
case OBJECTIVE3:
|
|
bitToChange = OBJECTIVE3_SHOW;
|
|
break;
|
|
case OBJECTIVE4:
|
|
bitToChange = OBJECTIVE4_SHOW;
|
|
break;
|
|
case OBJECTIVE5:
|
|
bitToChange = OBJECTIVE5_SHOW;
|
|
break;
|
|
case OBJECTIVE6:
|
|
bitToChange = OBJECTIVE6_SHOW;
|
|
break;
|
|
case OBJECTIVE7:
|
|
bitToChange = OBJECTIVE7_SHOW;
|
|
break;
|
|
case OBJECTIVE8:
|
|
bitToChange = OBJECTIVE8_SHOW;
|
|
break;
|
|
default:
|
|
bitToChange = 0;
|
|
break;
|
|
}
|
|
|
|
if ( Show && !(_objectiveStates & bitToChange) )
|
|
{
|
|
_objectiveStates |= bitToChange;
|
|
playSound = true;
|
|
}
|
|
|
|
// Else is removed because if we call setobjectiveshow on the same objective twice, we will
|
|
// actually hide it
|
|
//else
|
|
//{
|
|
// _objectiveStates &= ~bitToChange;
|
|
//}
|
|
|
|
if ( playSound )
|
|
Sound( "snd_objectivechanged", CHAN_LOCAL );
|
|
}
|
|
|
|
void Player::SpecialMoveChargeStart( Event* )
|
|
{
|
|
specialMoveCharge = level.time;
|
|
specialMoveEndTime = level.time + specialMoveChargeTime;
|
|
}
|
|
|
|
void Player::SpecialMoveChargeEnd( Event* )
|
|
{
|
|
specialMoveCharge = 0.0f;
|
|
specialMoveChargeTime = 0.0f;
|
|
specialMoveEndTime = 0.0f;
|
|
}
|
|
|
|
void Player::SpecialMoveChargeTime( Event* ev )
|
|
{
|
|
if ( ev->NumArgs() > 0 )
|
|
specialMoveChargeTime = ev->GetFloat( 1 );
|
|
}
|
|
|
|
void Player::SetInformationShow( Event* ev )
|
|
{
|
|
int InfoIndex;
|
|
str InfoName;
|
|
qboolean Show;
|
|
|
|
InfoName = ev->GetString( 1 );
|
|
Show = ev->GetBoolean( 2 );
|
|
|
|
InfoIndex = gi.MI_GetIndexFromName( InfoName.c_str() );
|
|
if ( InfoIndex == 0 )
|
|
return;
|
|
|
|
|
|
switch ( InfoIndex )
|
|
{
|
|
case INFORMATION1:
|
|
if ( Show )
|
|
_informationStates |= INFORMATION1_SHOW;
|
|
else
|
|
_informationStates &= ~(INFORMATION1_SHOW);
|
|
break;
|
|
|
|
case INFORMATION2:
|
|
if ( Show )
|
|
_informationStates |= INFORMATION2_SHOW;
|
|
else
|
|
_informationStates &= ~(INFORMATION2_SHOW);
|
|
|
|
break;
|
|
|
|
case INFORMATION3:
|
|
if ( Show )
|
|
_informationStates |= INFORMATION3_SHOW;
|
|
else
|
|
_informationStates &= ~(INFORMATION3_SHOW);
|
|
|
|
break;
|
|
|
|
case INFORMATION4:
|
|
if ( Show )
|
|
_informationStates |= INFORMATION4_SHOW;
|
|
else
|
|
_informationStates &= ~(INFORMATION4_SHOW);
|
|
|
|
break;
|
|
|
|
case INFORMATION5:
|
|
if ( Show )
|
|
_informationStates |= INFORMATION5_SHOW;
|
|
else
|
|
_informationStates &= ~(INFORMATION5_SHOW);
|
|
|
|
break;
|
|
|
|
case INFORMATION6:
|
|
if ( Show )
|
|
_informationStates |= INFORMATION6_SHOW;
|
|
else
|
|
_informationStates &= ~(INFORMATION6_SHOW);
|
|
|
|
break;
|
|
|
|
case INFORMATION7:
|
|
if ( Show )
|
|
_informationStates |= INFORMATION7_SHOW;
|
|
else
|
|
_informationStates &= ~(INFORMATION7_SHOW);
|
|
|
|
|
|
case INFORMATION8:
|
|
if ( Show )
|
|
_informationStates |= INFORMATION8_SHOW;
|
|
else
|
|
_informationStates &= ~(INFORMATION8_SHOW);
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Player::MissionFailed( Event* ev )
|
|
{
|
|
str reason = "DefaultFailure";
|
|
if ( ev->NumArgs() > 0 )
|
|
reason = ev->GetString( 1 );
|
|
|
|
G_MissionFailed(reason);
|
|
}
|
|
|
|
void Player::setMissionFailed( void )
|
|
{
|
|
client->ps.missionStatus |= MISSION_FAILED;
|
|
}
|
|
|
|
void Player::SetStat( Event *ev )
|
|
{
|
|
int stat_index;
|
|
int stat_value;
|
|
|
|
stat_index = PlayerStat_NameToNum( ev->GetString( 1 ) );
|
|
|
|
if ( stat_index < 0 )
|
|
{
|
|
gi.Printf( "Couldn't find player stat %s\n", ev->GetString( 1 ) );
|
|
return;
|
|
}
|
|
|
|
stat_value = ev->GetInteger( 2 );
|
|
|
|
client->ps.stats[ stat_index ] = stat_value;
|
|
}
|
|
|
|
void Player::SetStateFile( Event *ev )
|
|
{
|
|
str stateFileName(ev->GetString(1));
|
|
gi.cvar_set( "g_statefile", stateFileName );
|
|
LoadStateTable();
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: ShouldSendToClient
|
|
// Class: Player
|
|
//
|
|
// Description: Decides whether or not we should send this entity to the client
|
|
//
|
|
// Parameters: Entity *entityToSend - entity that we deciding about
|
|
//
|
|
// Returns: qboolean - whether or not we should send this entity
|
|
//----------------------------------------------------------------
|
|
|
|
qboolean Player::ShouldSendToClient( Entity *entityToSend )
|
|
{
|
|
// For now, early out if we don't have care about any view modes
|
|
|
|
if ( multiplayerManager.inMultiplayer() && client->pers.mp_lowBandwidth && entityToSend->isNetworkDetail() )
|
|
return false;
|
|
|
|
if ( !entityToSend->_affectingViewModes )
|
|
return true;
|
|
|
|
|
|
// Check to see if we should send this entity based on the player's current view mode
|
|
|
|
if ( entityToSend->_affectingViewModes & _viewMode )
|
|
return gi.GetViewModeSendInMode( entityToSend->_affectingViewModes & _viewMode );
|
|
else
|
|
return gi.GetViewModeSendNotInMode( entityToSend->_affectingViewModes & (~_viewMode) );
|
|
}
|
|
|
|
void Player::UpdateEntityStateForClient( entityState_t *state )
|
|
{
|
|
int i;
|
|
|
|
if ( !state )
|
|
return;
|
|
|
|
// Only update entity in multiplayer
|
|
|
|
if ( !multiplayerManager.inMultiplayer() )
|
|
return;
|
|
|
|
// Only update entity in low bandwidth mode
|
|
|
|
if ( !client->pers.mp_lowBandwidth )
|
|
return;
|
|
|
|
// Clear net angles if a client
|
|
|
|
if ( state->clientNum != ENTITYNUM_NONE )
|
|
{
|
|
VectorClear( state->netangles );
|
|
}
|
|
|
|
// Clear bone angles
|
|
|
|
for ( i = 0 ; i < NUM_BONE_CONTROLLERS ; i++ )
|
|
{
|
|
VectorClear( state->bone_angles[ i ] );
|
|
}
|
|
}
|
|
|
|
void Player::UpdatePlayerStateForClient( playerState_t *state )
|
|
{
|
|
if ( !state )
|
|
return;
|
|
|
|
// Only update playerstate in multiplayer
|
|
|
|
if ( !multiplayerManager.inMultiplayer() )
|
|
return;
|
|
|
|
if ( !multiplayerManager.isPlayerSpectator( this, SPECTATOR_TYPE_FOLLOW ) && !mp_savingDemo )
|
|
{
|
|
VectorClear( state->viewangles );
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: ExtraEntitiesToSendToClient
|
|
// Class: Player
|
|
//
|
|
// Description: Adds extra entities to send over to the client
|
|
//
|
|
// Parameters: int *numExtraEntities - the number of extra entities we added
|
|
// int *extraEntities - the list of entity numbers that we added
|
|
//
|
|
// Returns: None
|
|
//----------------------------------------------------------------
|
|
|
|
void Player::ExtraEntitiesToSendToClient( int *numExtraEntities, int *extraEntities )
|
|
{
|
|
*numExtraEntities = 0;
|
|
|
|
// Add in our current dialog person (if any)
|
|
if ( _dialogEntnum != ENTITYNUM_NONE )
|
|
{
|
|
extraEntities[ *numExtraEntities ] = _dialogEntnum;
|
|
(*numExtraEntities)++;
|
|
|
|
// Make sure we haven't added too many entities to the list
|
|
|
|
if ( *numExtraEntities == MAX_EXTRA_ENTITIES_FROM_GAME )
|
|
return;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: setViewMode
|
|
// Class: Player
|
|
//
|
|
// Description: Sets the players current view mode
|
|
//
|
|
// Parameters: const str &viewModeName - the name of the view mode to go to
|
|
//
|
|
// Returns: None
|
|
//----------------------------------------------------------------
|
|
|
|
void Player::setViewMode( const str &viewModeName )
|
|
{
|
|
Sentient::setViewMode( viewModeName );
|
|
client->ps.viewMode = getViewMode();
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: AwardPoints
|
|
// Class: Player
|
|
//
|
|
// Description: Gives the player points
|
|
//
|
|
// Parameters: int numPoints -- the number of points to give
|
|
//
|
|
// Returns: int -- The new total number of points
|
|
//----------------------------------------------------------------
|
|
int Player::AwardPoints(int numPoints)
|
|
{
|
|
points += numPoints;
|
|
|
|
GameplayManager *gpm = GameplayManager::getTheGameplayManager();
|
|
if ( !gpm ) return points ;
|
|
|
|
float maxPoints = 0.0f ;
|
|
float experience = 0.0f ;
|
|
|
|
if ( gpm->hasProperty( "CurrentPlayer", "maxPoints" ) )
|
|
{
|
|
maxPoints = gpm->getFloatValue( "CurrentPlayer", "maxPoints" );
|
|
experience = 100.0f * (points / maxPoints) ;
|
|
gpm->setFloatValue( "CurrentPlayer", "experience", experience );
|
|
|
|
if ( experience >= 100.0f )
|
|
{
|
|
float level = gpm->getFloatValue( "CurrentPlayer", "level" );
|
|
float skillPoints = gpm->getFloatValue( "CurrentPlayer", "SkillPoints" );
|
|
|
|
level += 1.0 ;
|
|
skillPoints += level ;
|
|
maxPoints = level * level * 100.0f ;
|
|
experience = 0.0f ;
|
|
|
|
gpm->setFloatValue( "CurrentPlayer", "level", level );
|
|
gpm->setFloatValue( "CurrentPlayer", "SkillPoints", skillPoints );
|
|
gpm->setFloatValue( "CurrentPlayer", "maxPoints", maxPoints );
|
|
gpm->setFloatValue( "CurrentPlayer", "experience", experience );
|
|
points = 0 ;
|
|
|
|
G_EnableWidgetOfPlayer( edict, "level_up", true );
|
|
}
|
|
}
|
|
|
|
return points;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: TakePoints
|
|
// Class: Player
|
|
//
|
|
// Description: Takes points away (never below 0)
|
|
//
|
|
// Parameters: int numPoints -- the number of points to take
|
|
//
|
|
// Returns: int -- The new total number of points
|
|
//----------------------------------------------------------------
|
|
int Player::TakePoints(int numPoints)
|
|
{
|
|
points -= numPoints;
|
|
if ( points < 0 )
|
|
points = 0;
|
|
|
|
return points;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: GivePointsEvent
|
|
// Class: Player
|
|
//
|
|
// Description: Gives the player points (from script)
|
|
//
|
|
// Parameters: Event *ev
|
|
//
|
|
// Returns: None
|
|
//----------------------------------------------------------------
|
|
void Player::GivePointsEvent( Event *ev )
|
|
{
|
|
if ( ev->NumArgs() > 0 )
|
|
AwardPoints(ev->GetInteger( 1 ));
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: SetPointsEvent
|
|
// Class: Player
|
|
//
|
|
// Description: Sets the players total number of points
|
|
//
|
|
// Parameters: Event *ev
|
|
//
|
|
// Returns: None
|
|
//----------------------------------------------------------------
|
|
void Player::SetPointsEvent( Event *ev )
|
|
{
|
|
if ( ev->NumArgs() > 0 )
|
|
points = ev->GetInteger( 1 );
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: ChangeChar
|
|
// Class: Player
|
|
//
|
|
// Description: Starts the screen fading out. When it fades to black
|
|
// we switch characters.
|
|
//
|
|
// Parameters: Event *ev
|
|
//
|
|
// Returns: None
|
|
//----------------------------------------------------------------
|
|
void Player::ChangeChar( Event *ev )
|
|
{
|
|
if ( changingChar ) // In the process of changing don't allow this event AGAIN until we're done.
|
|
return;
|
|
|
|
// Don't switch characters if we're already that character.
|
|
str curChar = gi.cvar("g_playermodel","",0)->string;
|
|
str curStateFile = gi.cvar("g_statefile","",0)->string;
|
|
if ((ev->GetString( 1 ) == curStateFile) && (ev->GetString( 2 ) == curChar))
|
|
return;
|
|
|
|
Actor *act = Actor::FindActorByName(ev->GetString( 3 ));
|
|
if ( act )
|
|
{
|
|
changingChar = true;
|
|
G_FadeOut(1.0f);
|
|
Event *ev2 = new Event(EV_Player_ChangeCharFadeIn);
|
|
ev2->AddString(ev->GetString( 1 ));
|
|
ev2->AddString(ev->GetString( 2 ));
|
|
ev2->AddString(ev->GetString( 3 ));
|
|
ev2->AddString(ev->GetString( 4 ));
|
|
ev2->AddEntity(act);
|
|
PostEvent(ev2, 1.0f);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: ChangeCharFadeIn
|
|
// Class: Player
|
|
//
|
|
// Description: Changes to the specified state machine and model
|
|
// as the screen fades in.
|
|
//
|
|
// Parameters: Event *ev
|
|
//
|
|
// Returns: None
|
|
//----------------------------------------------------------------
|
|
void Player::ChangeCharFadeIn( Event *ev )
|
|
{
|
|
str statemachine = ev->GetString( 1 );
|
|
str newmodel = ev->GetString( 2 );
|
|
str replacemodel = ev->GetString( 3 );
|
|
str spawnNPC = ev->GetString( 4 );
|
|
Actor *act = (Actor*)ev->GetEntity( 5 );
|
|
|
|
ProcessEvent(EV_DetachAllChildren);
|
|
|
|
gi.cvar_set( "g_statefile", statemachine.c_str() );
|
|
gi.cvar_set( "g_playermodel", newmodel.c_str() );
|
|
InitModel();
|
|
LoadStateTable();
|
|
|
|
Event *e = new Event( EV_Player_SpawnActor );
|
|
e->AddString( spawnNPC.c_str() );
|
|
e->AddString( "origin" );
|
|
e->AddVector(origin);
|
|
e->AddString( "angles" );
|
|
e->AddVector(angles);
|
|
// Spawn the actor where the player is currently positioned
|
|
SpawnActor(e);
|
|
|
|
// Set the player angles and origin to the new location
|
|
origin = act->origin;
|
|
SetViewAngles(act->angles);
|
|
act->ProcessEvent( EV_Remove );
|
|
|
|
G_AutoFadeIn();
|
|
changingChar = false;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: SetPlayerChar
|
|
// Class: Player
|
|
//
|
|
// Description: Sets the player character
|
|
//
|
|
// Parameters: Event *ev
|
|
//
|
|
// Returns: None
|
|
//----------------------------------------------------------------
|
|
void Player::SetPlayerChar( Event *ev )
|
|
{
|
|
str statemachine = ev->GetString( 1 );
|
|
str newmodel = ev->GetString( 2 );
|
|
|
|
// Don't switch characters if we're already that character.
|
|
str curChar = gi.cvar("g_playermodel","",0)->string;
|
|
str curStateFile = gi.cvar("g_statefile","",0)->string;
|
|
if ((statemachine == curStateFile) && (newmodel == curChar))
|
|
return;
|
|
|
|
gi.cvar_set( "g_statefile", statemachine.c_str() );
|
|
gi.cvar_set( "g_playermodel", newmodel.c_str() );
|
|
ProcessEvent(EV_DetachAllChildren);
|
|
InitModel();
|
|
LoadStateTable();
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: PlayerKnockback
|
|
// Class: Player
|
|
//
|
|
// Description: Sets the player knockback value.
|
|
//
|
|
// Parameters: Event *ev
|
|
//
|
|
// Returns: None
|
|
//----------------------------------------------------------------
|
|
void Player::PlayerKnockback(Event *ev)
|
|
{
|
|
playerKnockback = ev->GetInteger( 1 );
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: KnockbackMultiplier
|
|
// Class: Player
|
|
//
|
|
// Description: Sets the player knockback multiplier
|
|
//
|
|
// Parameters: Event *ev
|
|
//
|
|
// Returns: None
|
|
//----------------------------------------------------------------
|
|
void Player::KnockbackMultiplier(Event *ev)
|
|
{
|
|
knockbackMultiplier = ev->GetInteger( 1 );
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: MeleeEvent
|
|
// Class: Player
|
|
//
|
|
// Description: Performs a weaponless melee attack.
|
|
//
|
|
// Parameters: Event *ev
|
|
//
|
|
// Returns: None
|
|
//----------------------------------------------------------------
|
|
void Player::MeleeEvent( Event *ev )
|
|
{
|
|
Vector melee_pos;
|
|
Vector melee_end;
|
|
float damage = 20;
|
|
str means_of_death_string;
|
|
meansOfDeath_t attack_means_of_death;
|
|
float knockback;
|
|
|
|
// Get all of the parameters
|
|
|
|
if ( ev->NumArgs() > 0 )
|
|
damage = ev->GetFloat( 1 );
|
|
|
|
if ( ev->NumArgs() > 1 )
|
|
means_of_death_string = ev->GetString( 2 );
|
|
|
|
if ( ev->NumArgs() > 2 )
|
|
knockback = ev->GetFloat( 3 );
|
|
else
|
|
knockback = damage * 8.0f;
|
|
|
|
melee_pos = centroid;
|
|
melee_end = centroid + Vector( orientation[0] ) * 96.0f;
|
|
|
|
if ( means_of_death_string.length() > 0 )
|
|
attack_means_of_death = (meansOfDeath_t)MOD_NameToNum( means_of_death_string );
|
|
else
|
|
attack_means_of_death = MOD_CRUSH;
|
|
|
|
// Do the actual attack
|
|
MeleeAttack( melee_pos, melee_end, damage, this, attack_means_of_death, 15.0f, -45.0f, 45.0f, knockback );
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: MeleeDamageStart
|
|
// Class: Player
|
|
//
|
|
// Description: Sets flags to perform melee damage with the weapon
|
|
// in the hand specified (defaults to right hand)
|
|
//
|
|
// Parameters: Event *ev
|
|
//
|
|
// Returns: None
|
|
//----------------------------------------------------------------
|
|
void Player::MeleeDamageStart( Event *ev )
|
|
{
|
|
Weapon *weapon;
|
|
weaponhand_t hand = WEAPON_RIGHT;
|
|
|
|
if ( ev->NumArgs() > 0 )
|
|
hand = WeaponHandNameToNum(ev->GetString( 1 ));
|
|
|
|
weapon = GetActiveWeapon( hand );
|
|
if ( !weapon )
|
|
return;
|
|
|
|
// Make sure the tags are there on the weapon, or it will crash.
|
|
int tag_num = 0;
|
|
tag_num += gi.Tag_NumForName( weapon->edict->s.modelindex, "tag_swipe1" );
|
|
tag_num += gi.Tag_NumForName( weapon->edict->s.modelindex, "tag_swipe2" );
|
|
if ( tag_num < 0 )
|
|
return;
|
|
|
|
weapon->ClearMeleeVictims();
|
|
if ( hand == WEAPON_RIGHT )
|
|
meleeAttackFlags |= MELEE_ATTACK_RIGHT;
|
|
if ( hand == WEAPON_LEFT )
|
|
meleeAttackFlags |= MELEE_ATTACK_LEFT;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: MeleeDamageEnd
|
|
// Class: Player
|
|
//
|
|
// Description: Stops doing damage with the melee weapon in the hand
|
|
// specified.
|
|
//
|
|
// Parameters: Event *ev
|
|
//
|
|
// Returns: None
|
|
//----------------------------------------------------------------
|
|
void Player::MeleeDamageEnd( Event *ev )
|
|
{
|
|
weaponhand_t hand = WEAPON_RIGHT;
|
|
|
|
if ( ev->NumArgs() > 0 )
|
|
hand = WeaponHandNameToNum(ev->GetString( 1 ));
|
|
|
|
if ( hand == WEAPON_RIGHT )
|
|
meleeAttackFlags &= ~MELEE_ATTACK_RIGHT;
|
|
if ( hand == WEAPON_LEFT )
|
|
meleeAttackFlags &= ~MELEE_ATTACK_LEFT;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: ChangeStance
|
|
// Class: Player
|
|
//
|
|
// Description: Changes to the stance specified
|
|
//
|
|
// Parameters: Event *ev
|
|
//
|
|
// Returns: None
|
|
//----------------------------------------------------------------
|
|
void Player::ChangeStance(Event *ev)
|
|
{
|
|
if ( ev->NumArgs() < 1 )
|
|
return;
|
|
|
|
changedStanceTorso = true;
|
|
changedStanceLegs = true;
|
|
stanceNumber = ev->GetInteger( 1 );
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: ClearStanceTorso
|
|
// Class: Player
|
|
//
|
|
// Description: Clears internal torso stance data
|
|
//
|
|
// Parameters: Event *ev
|
|
//
|
|
// Returns: None
|
|
//----------------------------------------------------------------
|
|
void Player::ClearStanceTorso(Event *)
|
|
{
|
|
changedStanceTorso = false;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: ClearStanceLegs
|
|
// Class: Player
|
|
//
|
|
// Description: Clears internal legs stance data
|
|
//
|
|
// Parameters: Event *ev
|
|
//
|
|
// Returns: None
|
|
//----------------------------------------------------------------
|
|
void Player::ClearStanceLegs(Event *)
|
|
{
|
|
changedStanceLegs = false;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: ClearIncomingMelee
|
|
// Class: Player
|
|
//
|
|
// Description: Clears the incoming melee flag
|
|
//
|
|
// Parameters: Event *ev
|
|
//
|
|
// Returns: None
|
|
//----------------------------------------------------------------
|
|
void Player::ClearIncomingMelee(Event *)
|
|
{
|
|
incomingMeleeAttack = false;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: AddMeleeAttacker
|
|
// Class: Player
|
|
//
|
|
// Description: Adds the entity to the melee attacker container
|
|
//
|
|
// Parameters: Event *ev
|
|
//
|
|
// Returns: None
|
|
//----------------------------------------------------------------
|
|
void Player::AddMeleeAttacker( Event *ev)
|
|
{
|
|
Entity *ent = ev->GetEntity( 1 );
|
|
meleeAttackerList.AddUniqueObject( ent );
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: SetBendTorso
|
|
// Class: Player
|
|
//
|
|
// Description: Sets the torso bending for the player
|
|
//
|
|
// Parameters: Event *ev
|
|
//
|
|
// Returns: None
|
|
//----------------------------------------------------------------
|
|
void Player::SetBendTorso(Event *ev)
|
|
{
|
|
if ( ev->NumArgs() > 0 )
|
|
bendTorsoMult = ev->GetFloat( 1 );
|
|
else
|
|
bendTorsoMult = standardTorsoMult;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: HeadWatchAllowed
|
|
// Class: Player
|
|
//
|
|
// Description: Sets whether to headwatch or not, defaults to true
|
|
//
|
|
// Parameters: Event *ev
|
|
//
|
|
// Returns: None
|
|
//----------------------------------------------------------------
|
|
void Player::HeadWatchAllowed(Event *ev)
|
|
{
|
|
Sentient::HeadWatchAllowed( ev );
|
|
}
|
|
|
|
void Player::SetCurrentCallVolume( const str &volumeName )
|
|
{
|
|
currentCallVolume = volumeName;
|
|
}
|
|
|
|
str Player::GetCurrentCallVolume()
|
|
{
|
|
return currentCallVolume;
|
|
}
|
|
|
|
//
|
|
// Multiplayer stuff
|
|
//
|
|
|
|
void Player::Score( Event * )
|
|
{
|
|
multiplayerManager.score( this );
|
|
}
|
|
|
|
void Player::joinTeam( Event *ev )
|
|
{
|
|
str teamName;
|
|
|
|
teamName = ev->GetString( 1 );
|
|
|
|
multiplayerManager.joinTeam( this, teamName );
|
|
}
|
|
|
|
void Player::multiplayerCommand( Event *ev )
|
|
{
|
|
str command;
|
|
str parm;
|
|
|
|
command = ev->GetString( 1 );
|
|
parm = ev->GetString( 2 );
|
|
|
|
multiplayerManager.playerCommand( this, command, parm );
|
|
}
|
|
|
|
void Player::Disconnect( void )
|
|
{
|
|
if ( multiplayerManager.inMultiplayer() )
|
|
{
|
|
multiplayerManager.removePlayer( this );
|
|
}
|
|
}
|
|
|
|
void Player::CallVote( Event *ev )
|
|
{
|
|
str command;
|
|
str arg;
|
|
|
|
if ( multiplayerManager.inMultiplayer() )
|
|
{
|
|
command = ev->GetString( 1 );
|
|
|
|
if ( ev->NumArgs() > 1 )
|
|
arg = ev->GetString( 2 );
|
|
|
|
multiplayerManager.callVote( this, command, arg );
|
|
}
|
|
}
|
|
|
|
void Player::Vote( Event *ev )
|
|
{
|
|
str vote;
|
|
|
|
if ( multiplayerManager.inMultiplayer() )
|
|
{
|
|
if ( ev->NumArgs() != 1 )
|
|
{
|
|
multiplayerManager.HUDPrint( entnum, "$$Usage$$: vote <1|0|y|n>" );
|
|
return;
|
|
}
|
|
|
|
vote = ev->GetString( 1 );
|
|
|
|
multiplayerManager.vote( this, vote );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Powerup stuff
|
|
//
|
|
|
|
void Player::addPowerupEffect( PowerupBase *powerup )
|
|
{
|
|
str modelName;
|
|
str tagName;
|
|
float modelRemoveTime;
|
|
str shaderName;
|
|
|
|
if ( !powerup )
|
|
return;
|
|
|
|
// Attach a model to the player if necessary
|
|
|
|
powerup->getModelToAttachOnUse( modelName, tagName, modelRemoveTime );
|
|
|
|
if ( modelName.length() > 0 )
|
|
{
|
|
Event *attachModel;
|
|
|
|
attachModel = new Event( EV_AttachModel );
|
|
|
|
attachModel->AddString( modelName );
|
|
attachModel->AddString( tagName );
|
|
attachModel->AddFloat( 1.0f );
|
|
attachModel->AddString( "" );
|
|
attachModel->AddInteger( 0 );
|
|
attachModel->AddFloat( modelRemoveTime );
|
|
|
|
ProcessEvent( attachModel );
|
|
}
|
|
}
|
|
|
|
void Player::removePowerupEffect( PowerupBase *powerup )
|
|
{
|
|
str modelName;
|
|
str tagName;
|
|
float modelRemoveTime;
|
|
str shaderName;
|
|
|
|
if ( !powerup )
|
|
return;
|
|
|
|
// Remove the attached model from the player if attached before
|
|
|
|
powerup->getModelToAttachOnUse( modelName, tagName, modelRemoveTime );
|
|
|
|
if ( modelName.length() > 0 )
|
|
{
|
|
Event *removeAttachedModel;
|
|
|
|
removeAttachedModel = new Event( EV_RemoveAttachedModel );
|
|
|
|
removeAttachedModel->AddString( tagName );
|
|
removeAttachedModel->AddFloat( 0.0f );
|
|
removeAttachedModel->AddString( modelName );
|
|
|
|
ProcessEvent( removeAttachedModel );
|
|
}
|
|
|
|
// Remove the custom shader from the player if set before
|
|
|
|
powerup->getShaderToDisplayOnUse( shaderName );
|
|
|
|
if ( shaderName.length() > 0 )
|
|
{
|
|
clearCustomShader( shaderName.c_str() );
|
|
}
|
|
}
|
|
|
|
void Player::setPowerup( Powerup *powerup )
|
|
{
|
|
// If this is the same powerup type, stack them
|
|
|
|
if ( _powerup && powerup && ( _powerup->getName() == powerup->getName() ) && _powerup->canStack() && powerup->canStack() )
|
|
{
|
|
float newTimeLeft;
|
|
newTimeLeft = _powerup->getTimeLeft() + powerup->getTimeLeft();
|
|
_powerup->setTimeLeft( newTimeLeft );
|
|
}
|
|
else
|
|
{
|
|
removePowerup();
|
|
|
|
CancelEventsOfType( EV_Player_RemovePowerup );
|
|
|
|
_powerup = powerup;
|
|
|
|
if ( !_powerup )
|
|
return;
|
|
|
|
addPowerupEffect( _powerup );
|
|
}
|
|
|
|
setItemText( _powerup->getIcon(), va( "$$Using$$ $$Item-%s$$", _powerup->getName().c_str() ) );
|
|
//gi.centerprintf ( edict, CENTERPRINT_IMPORTANCE_NORMAL, "$$Using$$ %s", _powerup->getRealName() );
|
|
}
|
|
|
|
void Player::removePowerup( void )
|
|
{
|
|
if ( _powerup )
|
|
{
|
|
removePowerupEffect( _powerup );
|
|
|
|
delete _powerup;
|
|
_powerup = NULL;
|
|
}
|
|
}
|
|
|
|
void Player::removePowerupEvent( Event * )
|
|
{
|
|
removePowerup();
|
|
}
|
|
|
|
void Player::dropPowerup( void )
|
|
{
|
|
if ( _powerup )
|
|
{
|
|
if ( _powerup->canDrop() )
|
|
{
|
|
_powerup->spawn( centroid );
|
|
}
|
|
|
|
removePowerup();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Rune stuff
|
|
//
|
|
|
|
bool Player::hasRune( void )
|
|
{
|
|
if ( _rune )
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
void Player::setRune( Rune *rune )
|
|
{
|
|
removeRune();
|
|
|
|
_rune = rune;
|
|
|
|
if ( !_rune )
|
|
return;
|
|
|
|
addPowerupEffect( _rune );
|
|
|
|
// Tell the player they are now using this rune
|
|
|
|
setItemText( rune->getIcon(), va( "$$Using$$ $$Item-%s$$", _rune->getName().c_str() ) );
|
|
//gi.centerprintf ( edict, CENTERPRINT_IMPORTANCE_NORMAL, "$$Using$$ %s", _rune->getRealName() );
|
|
}
|
|
|
|
void Player::removeRune( void )
|
|
{
|
|
if ( _rune )
|
|
{
|
|
removePowerupEffect( _rune );
|
|
|
|
delete _rune;
|
|
_rune = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Holdable item stuff
|
|
//
|
|
|
|
void Player::setHoldableItem( HoldableItem *holdableItem )
|
|
{
|
|
removeHoldableItem();
|
|
|
|
_holdableItem = holdableItem;
|
|
}
|
|
|
|
void Player::removeHoldableItem( void )
|
|
{
|
|
if ( _holdableItem )
|
|
{
|
|
_holdableItem->PostEvent( EV_Remove, 0.0f );
|
|
|
|
_holdableItem = NULL;
|
|
}
|
|
}
|
|
|
|
void Player::useHoldableItem( void )
|
|
{
|
|
if ( _holdableItem )
|
|
{
|
|
if ( multiplayerManager.inMultiplayer() )
|
|
{
|
|
multiplayerManager.playerEventNotification( "use-HoldableItem", _holdableItem->getName(), this );
|
|
}
|
|
|
|
if ( _holdableItem->use() )
|
|
{
|
|
// Must check again if holdable item exists, because use might have caused the holdable item to be destroyed
|
|
|
|
if ( _holdableItem )
|
|
{
|
|
addPowerupEffect( _holdableItem );
|
|
|
|
setItemText( _holdableItem->getIcon(), va( "$$Used$$ $$Item-%s$$", _holdableItem->getName().c_str() ) );
|
|
//gi.centerprintf ( edict, CENTERPRINT_IMPORTANCE_NORMAL, "$$Using$$ $$Item-%s$$", _holdableItem->getName() );
|
|
removeHoldableItem();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
HoldableItem* Player::getHoldableItem( void )
|
|
{
|
|
return _holdableItem;
|
|
}
|
|
|
|
float Player::getDamageDone( float damage, int meansOfDeath, bool inMelee )
|
|
{
|
|
float damageDone;
|
|
|
|
|
|
damageDone = damage;
|
|
|
|
if ( inMelee )
|
|
damageDone *= damage_multiplier;
|
|
|
|
if ( _powerup )
|
|
damageDone = _powerup->getDamageDone( damageDone, meansOfDeath );
|
|
|
|
if ( _rune )
|
|
damageDone = _rune->getDamageDone( damageDone, meansOfDeath );
|
|
|
|
return damageDone;
|
|
}
|
|
|
|
meansOfDeath_t Player::changetMeansOfDeath( meansOfDeath_t meansOfDeath )
|
|
{
|
|
meansOfDeath_t realMeansOfDeath;
|
|
|
|
realMeansOfDeath = meansOfDeath;
|
|
|
|
if ( _powerup )
|
|
realMeansOfDeath = _powerup->changetMeansOfDeath( realMeansOfDeath );
|
|
|
|
if ( _rune )
|
|
realMeansOfDeath = _rune->changetMeansOfDeath( realMeansOfDeath );
|
|
|
|
if ( _finishActor && _doingFinishingMove )
|
|
realMeansOfDeath = MOD_REDEMPTION; // Finishing move MOD... oh sweet irony
|
|
|
|
return realMeansOfDeath;
|
|
}
|
|
|
|
void Player::dropRune( Event * )
|
|
{
|
|
if ( _rune )
|
|
{
|
|
dropRune();
|
|
}
|
|
}
|
|
|
|
void Player::dropRune( void )
|
|
{
|
|
if ( _rune )
|
|
{
|
|
setItemText( _rune->getIcon(), va( "$$Dropping$$ $$Item-%s$$", _rune->getName().c_str() ) );
|
|
//gi.centerprintf ( edict, CENTERPRINT_IMPORTANCE_NORMAL, "$$Dropping$$ $$Item-%s$$", _rune->getName() );
|
|
|
|
_rune->spawn( centroid );
|
|
|
|
removeRune();
|
|
}
|
|
else
|
|
{
|
|
multiplayerManager.playerCommand( this, "dropItem", "" );
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: setCanTransferEnergy
|
|
// Class: Player
|
|
//
|
|
// Description: Makes the player allowed to transfer energy from ammo to armor
|
|
//
|
|
// Parameters: Event *
|
|
//
|
|
// Returns: none
|
|
//----------------------------------------------------------------
|
|
|
|
void Player::setCanTransferEnergy( Event * )
|
|
{
|
|
_canTransferEnergy = true;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: transferEnergy
|
|
// Class: Player
|
|
//
|
|
// Description: Transfers some energy from ammo to the armor
|
|
//
|
|
// Parameters: none
|
|
//
|
|
// Returns: none
|
|
//----------------------------------------------------------------
|
|
|
|
void Player::transferEnergy( void )
|
|
{
|
|
Event *armorEvent;
|
|
|
|
// Make sure we are allowed to transfer energy
|
|
|
|
if ( !_canTransferEnergy )
|
|
return;
|
|
|
|
// Make sure enough time has gone by to transfer more energy
|
|
|
|
if ( _nextEnergyTransferTime > level.time )
|
|
return;
|
|
|
|
_nextEnergyTransferTime = level.time + level.frametime;
|
|
|
|
// Make sure we have enough energy
|
|
|
|
if ( AmmoCount( "Plasma" ) < 1 )
|
|
return;
|
|
|
|
// Make sure we still need more armor
|
|
|
|
if ( GetArmorValue() >= 100 )
|
|
return;
|
|
|
|
// Give ourselves a little bit of armor
|
|
|
|
armorEvent = new Event( EV_Sentient_GiveArmor );
|
|
|
|
armorEvent->AddString( "BasicArmor" );
|
|
armorEvent->AddFloat( 1.0f );
|
|
|
|
ProcessEvent( armorEvent );
|
|
|
|
// Use up some energy
|
|
|
|
UseAmmo( "Plasma", 1 );
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: AdvancedMeleeAttack
|
|
// Class: Player
|
|
//
|
|
// Description: Gets the waepon in the hand specified and calls
|
|
// it's AdvancedMeleeAttack function.
|
|
//
|
|
// Parameters: weaponhand_t hand -- weapon hand
|
|
//
|
|
// Returns: None
|
|
//
|
|
//--------------------------------------------------------------
|
|
void Player::AdvancedMeleeAttack(weaponhand_t hand)
|
|
{
|
|
Weapon *weapon;
|
|
bool critical = false ;
|
|
|
|
if ( hand == WEAPON_ERROR )
|
|
return;
|
|
|
|
weapon = GetActiveWeapon( hand );
|
|
if ( !weapon )
|
|
return;
|
|
|
|
GameplayManager *gpm = GameplayManager::getTheGameplayManager();
|
|
if ( gpm->hasProperty( "CurrentPlayer.Criticals", "value" ) )
|
|
{
|
|
float criticalSkill = gpm->getFloatValue( "CurrentPlayer.Criticals", "value" );
|
|
float criticalBaseChance = gpm->getFloatValue( "Criticals", "baseChance" );
|
|
float criticalChance = criticalSkill * criticalBaseChance ;
|
|
if ( G_Random() < criticalChance )
|
|
{
|
|
critical = true ;
|
|
}
|
|
}
|
|
|
|
weapon->AdvancedMeleeAttack("tag_swipe1", "tag_swipe2", critical );
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
// Name: setDoDamageScreenFlash
|
|
// Class: Player
|
|
//
|
|
// Description: Sets whether or not we want to flash the player's screen when he is damaged
|
|
//
|
|
// Parameters: Event *ev - optionally contains a bool specifying on or off
|
|
//
|
|
// Returns: None
|
|
//--------------------------------------------------------------
|
|
|
|
void Player::setDoDamageScreenFlash( Event *ev )
|
|
{
|
|
if ( ev->NumArgs() > 0 )
|
|
_doDamageScreenFlash = ev->GetBoolean( 1 );
|
|
else
|
|
_doDamageScreenFlash = true;
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
// Name: pointOfView
|
|
// Class: Player
|
|
//
|
|
// Description: Forces the player into a different point of view
|
|
//
|
|
// Parameters: Event *ev - 1 = 1st person, 0 = 3rd person
|
|
//
|
|
// Returns: None
|
|
//--------------------------------------------------------------
|
|
|
|
void Player::pointOfView( Event *ev )
|
|
{
|
|
if ( ev->NumArgs() > 0 )
|
|
{
|
|
// More than one argument, we are attempting to SET
|
|
// the point of view specifically.
|
|
bool pov = ev->GetBoolean( 1 );
|
|
if ( pov == _isThirdPerson )
|
|
return;
|
|
}
|
|
|
|
// Toggle the point of view
|
|
if ( _isThirdPerson )
|
|
{
|
|
G_SendCommandToPlayer(edict, "cg_3rd_person 0");
|
|
_isThirdPerson = false;
|
|
}
|
|
else
|
|
{
|
|
G_SendCommandToPlayer(edict, "cg_3rd_person 1");
|
|
_isThirdPerson = true;
|
|
}
|
|
}
|
|
|
|
void Player::HandleFinishableList()
|
|
{
|
|
int i,j;
|
|
for ( i=1; i<=finishableList.NumObjects(); i++ )
|
|
{
|
|
Actor *act = finishableList.ObjectAt(i);
|
|
for ( j=1; j<=finishingMoveList.NumObjects(); j++ )
|
|
{
|
|
FinishingMove *fm = finishingMoveList.ObjectAt(j);
|
|
float fovdot = cos( DEG2RAD( fm->coneangle * 0.5f) );
|
|
Vector delta = ( act->origin ) - origin;
|
|
if ( delta.length() > fm->distance )
|
|
continue;
|
|
|
|
// Enemy Angles not yet used...
|
|
// Chance not yet used...
|
|
|
|
delta.z = 0.0f;
|
|
delta.normalize();
|
|
float dot = 0.0f;
|
|
switch ( fm->direction )
|
|
{
|
|
case 0 : dot = DotProduct( yaw_forward, delta ); break;
|
|
case 1 : dot = DotProduct( yaw_forward*-1.0f, delta ); break;
|
|
case 2 : dot = DotProduct( yaw_left, delta ); break;
|
|
case 3 : dot = DotProduct( yaw_left*-1.0f, delta ); break;
|
|
}
|
|
|
|
if ( dot > fovdot )
|
|
{
|
|
// G_EnableWidgetOfPlayer( edict, "ActionIcon_Kick", true );
|
|
_finishActor = act;
|
|
_finishState = fm->statename;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// G_EnableWidgetOfPlayer( edict, "ActionIcon_Kick", false );
|
|
_finishActor = NULL;
|
|
_finishState = "";
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: addFinishingMove
|
|
// Class: Player
|
|
//
|
|
// Description: Add a finishing move to the list
|
|
//
|
|
// Parameters: Event *ev
|
|
//
|
|
// Returns: None
|
|
//
|
|
//--------------------------------------------------------------
|
|
void Player::addFinishingMove( Event *ev )
|
|
{
|
|
str state, dirstr;
|
|
float coneangle = 45.0f;
|
|
float dist = 64.0f;
|
|
float eyaw = 0.0f;
|
|
float chance = 1.0f;
|
|
|
|
state = ev->GetString( 1 );
|
|
dirstr = ev->GetString( 2 );
|
|
|
|
if ( ev->NumArgs() > 2 )
|
|
coneangle = ev->GetFloat( 3 );
|
|
if ( ev->NumArgs() > 3 )
|
|
dist = ev->GetFloat( 4 );
|
|
if ( ev->NumArgs() > 4 )
|
|
eyaw = ev->GetFloat( 5 );
|
|
if ( ev->NumArgs() > 5 )
|
|
chance = ev->GetFloat( 6 );
|
|
|
|
FinishingMove *fm = new FinishingMove();
|
|
fm->statename = state;
|
|
if ( dirstr == "front" )
|
|
fm->direction = 0;
|
|
else if ( dirstr == "behind" )
|
|
fm->direction = 1;
|
|
else if ( dirstr == "left" )
|
|
fm->direction = 2;
|
|
else if ( dirstr = "right" )
|
|
fm->direction = 3;
|
|
else
|
|
fm->direction = 0; // Front default
|
|
fm->coneangle = coneangle;
|
|
fm->distance = dist;
|
|
fm->enemyyaw = eyaw;
|
|
fm->chance = chance;
|
|
|
|
finishingMoveList.AddObject(fm);
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: clearFinishingMove
|
|
// Class: Player
|
|
//
|
|
// Description: Clears the finishing move list.
|
|
//
|
|
// Parameters: Event *ev -- no params
|
|
//
|
|
// Returns: None
|
|
//
|
|
//--------------------------------------------------------------
|
|
void Player::clearFinishingMove( Event * )
|
|
{
|
|
int i;
|
|
for ( i=1; i<=finishingMoveList.NumObjects(); i++ )
|
|
{
|
|
FinishingMove *fm = finishingMoveList.ObjectAt(i);
|
|
delete fm;
|
|
}
|
|
finishingMoveList.FreeObjectList();
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: doFinishingMove
|
|
// Class: Player
|
|
//
|
|
// Description: Fires off the finishing move that's currently prepared
|
|
//
|
|
// Parameters: Event *ev -- no params
|
|
//
|
|
// Returns: None
|
|
//
|
|
//--------------------------------------------------------------
|
|
void Player::doFinishingMove( Event * )
|
|
{
|
|
movecontrol = MOVECONTROL_ABSOLUTE;
|
|
|
|
if ( _finishState.length() )
|
|
{
|
|
State* newState = statemap_Torso->FindState( _finishState );
|
|
if ( newState )
|
|
{
|
|
EvaluateState( newState );
|
|
_doingFinishingMove = true;
|
|
_finishActor->SetState("FINISH_ME");
|
|
}
|
|
else
|
|
gi.WDPrintf( "Could not find state %s on doFinishingMove\n", _finishState.c_str() );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: forceTimeScale
|
|
// Class: Player
|
|
//
|
|
// Description: Forces timescale for the game
|
|
//
|
|
// Parameters: Event *ev
|
|
//
|
|
// Returns: None
|
|
//
|
|
//--------------------------------------------------------------
|
|
void Player::forceTimeScale( Event *ev )
|
|
{
|
|
float timescale = 1.0f;
|
|
if ( ev->NumArgs() > 0 )
|
|
timescale = ev->GetFloat( 1 );
|
|
|
|
char tmp[15];
|
|
sprintf(tmp, "timescale %f", timescale);
|
|
|
|
G_SendCommandToPlayer(edict, tmp);
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: freezePlayer
|
|
// Class: Player
|
|
//
|
|
// Description: Freezes the player
|
|
//
|
|
// Parameters: Event *ev
|
|
//
|
|
// Returns: None
|
|
//
|
|
//--------------------------------------------------------------
|
|
void Player::freezePlayer( Event *ev )
|
|
{
|
|
bool freeze = true;
|
|
if ( ev->NumArgs() > 0 )
|
|
freeze = ev->GetBoolean( 1 );
|
|
|
|
level.playerfrozen = freeze;
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: immobilizePlayer
|
|
// Class: Player
|
|
//
|
|
// Description: Immobilizes the player (can only look around)
|
|
//
|
|
// Parameters: Event *ev
|
|
//
|
|
// Returns: None
|
|
//
|
|
//--------------------------------------------------------------
|
|
void Player::immobilizePlayer( Event *ev )
|
|
{
|
|
bool freeze = true;
|
|
|
|
if ( ev->NumArgs() > 0 )
|
|
freeze = ev->GetBoolean( 1 );
|
|
|
|
if ( freeze )
|
|
flags |= FL_IMMOBILE;
|
|
else
|
|
flags &= ~FL_IMMOBILE;
|
|
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: setAttackType
|
|
// Class: Player
|
|
//
|
|
// Description: Sets the attack type of the attack
|
|
//
|
|
// Parameters: Event *ev
|
|
//
|
|
// Returns: None
|
|
//
|
|
//--------------------------------------------------------------
|
|
void Player::setAttackType( Event *ev )
|
|
{
|
|
_attackType = ev->GetString( 1 );
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: getGameplayAnim
|
|
// Class: Player
|
|
//
|
|
// Description: Gets the anim name from the gameplay database
|
|
// based on the current gameplayAnimIdx
|
|
//
|
|
// Parameters: const str& objname -- The object
|
|
//
|
|
// Returns: const str
|
|
//
|
|
//--------------------------------------------------------------
|
|
const str Player::getGameplayAnim(const str& objname)
|
|
{
|
|
if ( !objname.length() || !getArchetype().length() )
|
|
return "";
|
|
|
|
GameplayManager *gpm = GameplayManager::getTheGameplayManager();
|
|
str scopestr = getArchetype() + "." + objname;
|
|
if ( !gpm->hasObject(scopestr) )
|
|
return "";
|
|
|
|
char tmpstr[6];
|
|
sprintf(tmpstr, "%d", _gameplayAnimIdx);
|
|
return gpm->getStringValue(scopestr, tmpstr);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: nextGameplayAnim
|
|
// Class: Player
|
|
//
|
|
// Description: Increment the the gameplay animation up to
|
|
// the maxchain value in the database. Wrap
|
|
// around afterwards.
|
|
//
|
|
// Parameters: Event *ev
|
|
//
|
|
// Returns: None
|
|
//
|
|
//--------------------------------------------------------------
|
|
void Player::nextGameplayAnim( Event *ev )
|
|
{
|
|
if ( ev->NumArgs() < 1 )
|
|
return;
|
|
|
|
str objname = ev->GetString( 1 );
|
|
GameplayManager *gpm = GameplayManager::getTheGameplayManager();
|
|
str scopestr = "CurrentPlayer.ChainedMoves";
|
|
if ( !gpm->hasObject(scopestr) )
|
|
return;
|
|
|
|
int max = (int)gpm->getFloatValue(scopestr, "value");
|
|
max++; // Increment to compensate for 0 based skill system, we always have to play the first anim
|
|
if ( _gameplayAnimIdx < max )
|
|
_gameplayAnimIdx++;
|
|
else
|
|
_gameplayAnimIdx = 1;
|
|
|
|
// Max of 4 chains deep.
|
|
if ( _gameplayAnimIdx > 4 )
|
|
_gameplayAnimIdx = 1;
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: setGameplayAnim
|
|
// Class: Player
|
|
//
|
|
// Description: Sets the gameplayAnimIdx to the number specified
|
|
//
|
|
// Parameters: Event *ev
|
|
//
|
|
// Returns: None
|
|
//
|
|
//--------------------------------------------------------------
|
|
void Player::setGameplayAnim( Event *ev )
|
|
{
|
|
int val = 1;
|
|
if ( ev->NumArgs() > 0)
|
|
val = ev->GetInteger( 1 );
|
|
|
|
_gameplayAnimIdx = val;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name: SetDisableUseWeapon
|
|
// Class: Player
|
|
//
|
|
// Description: Can disable the use of a new weapon
|
|
//
|
|
// Parameters: ev - the event that sets the disableUseWeapon
|
|
//
|
|
// Returns: None
|
|
//-----------------------------------------------------
|
|
void Player::setDisableUseWeapon( Event* ev)
|
|
{
|
|
if(ev->NumArgs() > 0)
|
|
{
|
|
_disableUseWeapon = ev->GetBoolean(1);
|
|
}
|
|
else
|
|
{
|
|
_disableUseWeapon = true;
|
|
}
|
|
|
|
|
|
Com_Printf("DisableUseWeapon %d", _disableUseWeapon);
|
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name:
|
|
// Class:
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Returns:
|
|
//-----------------------------------------------------
|
|
void Player::setDisableInventory( Event* ev )
|
|
{
|
|
if(ev->NumArgs() > 0)
|
|
{
|
|
disableInventory();
|
|
return;
|
|
}
|
|
else if( ev->GetFloat(1))
|
|
{
|
|
enableInventory();
|
|
return;
|
|
}
|
|
|
|
disableInventory();
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: skillChanged
|
|
// Class: Player
|
|
//
|
|
// Description: Handles skills when they change
|
|
//
|
|
// Parameters: const str& objname -- Object in the database that has changed
|
|
//
|
|
// Returns: None
|
|
//
|
|
//--------------------------------------------------------------
|
|
void Player::skillChanged(const str& objname)
|
|
{
|
|
GameplayManager *gpm = GameplayManager::getTheGameplayManager();
|
|
if ( !gpm->hasObject(objname) )
|
|
return;
|
|
|
|
float value = gpm->getFloatValue(objname, "value");
|
|
if ( objname == "CurrentPlayer.BonusHP" && value > 0.0f )
|
|
{
|
|
if ( gpm->hasFormula("BonusHP") )
|
|
{
|
|
GameplayFormulaData fd(this);
|
|
float hp = gpm->calculate("BonusHP", fd);
|
|
float maxhp = max_health + ( max_health * hp );
|
|
setMaxHealth(maxhp);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: EquipItems
|
|
// Class: Player
|
|
//
|
|
// Description: Equips items from the database
|
|
//
|
|
// Parameters: Event *ev -- not used
|
|
//
|
|
// Returns: None
|
|
//
|
|
//--------------------------------------------------------------
|
|
void Player::equipItems( Event * )
|
|
{
|
|
GameplayManager *gpm = GameplayManager::getTheGameplayManager();
|
|
|
|
str itemName, modelName;
|
|
|
|
itemName = gpm->getStringValue("CurrentPlayer.DualWield", "name");
|
|
modelName = gpm->getStringValue(itemName, "model");
|
|
if ( modelName.length() )
|
|
giveItem(modelName);
|
|
|
|
itemName = gpm->getStringValue("CurrentPlayer.TwoHanded", "name");
|
|
modelName = gpm->getStringValue(itemName, "model");
|
|
if ( modelName.length() )
|
|
giveItem(modelName);
|
|
|
|
itemName = gpm->getStringValue("CurrentPlayer.Ranged", "name");
|
|
modelName = gpm->getStringValue(itemName, "model");
|
|
if ( modelName.length() )
|
|
giveItem(modelName);
|
|
|
|
itemName = gpm->getStringValue("CurrentPlayer.Ring", "name");
|
|
modelName = gpm->getStringValue(itemName, "model");
|
|
if ( modelName.length() )
|
|
giveItem(modelName);
|
|
|
|
itemName = gpm->getStringValue("CurrentPlayer.Amulet", "name");
|
|
modelName = gpm->getStringValue(itemName, "model");
|
|
if ( modelName.length() )
|
|
giveItem(modelName);
|
|
|
|
useWeapon("DualWield", WEAPON_RIGHT);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: getFreeInventorySlot
|
|
// Class: Player
|
|
//
|
|
// Description: Finds a free inventory slot from the database
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: Object name of the free slot, or "" if the inventory
|
|
// is full.
|
|
//
|
|
//--------------------------------------------------------------
|
|
const str Player::getFreeInventorySlot()
|
|
{
|
|
GameplayManager *gpm = GameplayManager::getTheGameplayManager();
|
|
|
|
int i;
|
|
char tmpstr[128];
|
|
for ( i=1; i<15; i++ )
|
|
{
|
|
sprintf(tmpstr,"PartyInventory.Slot%d",i);
|
|
str invitem = gpm->getStringValue(tmpstr, "name");
|
|
if ( invitem == "Empty" )
|
|
return tmpstr;
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
void Player::usePlayer( Event *ev )
|
|
{
|
|
Player *usingPlayer = NULL;
|
|
Equipment *equipment = NULL;
|
|
Entity *owner;
|
|
|
|
if ( multiplayerManager.inMultiplayer() )
|
|
{
|
|
Entity *entity;
|
|
|
|
entity = ev->GetEntity( 1 );
|
|
|
|
if ( entity->isSubclassOf( Player ) )
|
|
{
|
|
usingPlayer = (Player *)entity;
|
|
}
|
|
else if ( entity->isSubclassOf( Equipment ) )
|
|
{
|
|
equipment = (Equipment *)entity;
|
|
|
|
owner = equipment->GetOwner();
|
|
|
|
if ( owner && owner->isSubclassOf( Player ) )
|
|
{
|
|
usingPlayer = (Player *)owner;
|
|
}
|
|
}
|
|
|
|
multiplayerManager.playerUsed( this, usingPlayer, equipment );
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name: addRosterTeammate1
|
|
// Class: Player
|
|
//
|
|
// Description: Sets the third teammate in the roster.
|
|
//
|
|
// Parameters: ev
|
|
//
|
|
// Returns: None
|
|
//-----------------------------------------------------
|
|
void Player::addRosterTeammate1( Event* )
|
|
{
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name: addRosterTeammate2
|
|
// Class: Player
|
|
//
|
|
// Description: Adds the second teammate from the roster.
|
|
//
|
|
// Parameters: ev
|
|
//
|
|
// Returns: None
|
|
//-----------------------------------------------------
|
|
void Player::addRosterTeammate2( Event* )
|
|
{
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name: addRosterTeammate3
|
|
// Class: Player
|
|
//
|
|
// Description: Adds the third teammate from the roster.
|
|
//
|
|
// Parameters: ev
|
|
//
|
|
// Returns: None
|
|
//-----------------------------------------------------
|
|
void Player::addRosterTeammate3( Event* )
|
|
{
|
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name: addRosterTeammate4
|
|
// Class: Player
|
|
//
|
|
// Description: Adds the fourth teammate from the roster.
|
|
//
|
|
// Parameters: ev
|
|
//
|
|
// Returns: None
|
|
//-----------------------------------------------------
|
|
void Player::addRosterTeammate4( Event* )
|
|
{
|
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name: removeRosterTeammate1
|
|
// Class: Player
|
|
//
|
|
// Description: Removes the first teammate from the roster.
|
|
//
|
|
// Parameters: ev
|
|
//
|
|
// Returns: None
|
|
//-----------------------------------------------------
|
|
void Player::removeRosterTeammate1( Event* )
|
|
{
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name: removeRosterTeammate2
|
|
// Class: Player
|
|
//
|
|
// Description: Removes the second teammate from the roster.
|
|
//
|
|
// Parameters: ev
|
|
//
|
|
// Returns: None
|
|
//-----------------------------------------------------
|
|
void Player::removeRosterTeammate2( Event* )
|
|
{
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name: removeRosterTeammate3
|
|
// Class: Player
|
|
//
|
|
// Description: Removes the third teammate from the roster.
|
|
//
|
|
// Parameters: ev
|
|
//
|
|
// Returns: None
|
|
//-----------------------------------------------------
|
|
void Player::removeRosterTeammate3( Event* )
|
|
{
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name: removeRosterTeammate4
|
|
// Class: Player
|
|
//
|
|
// Description: Removes the fourth teammate from the roster.
|
|
//
|
|
// Parameters: ev
|
|
//
|
|
// Returns: None
|
|
//-----------------------------------------------------
|
|
void Player::removeRosterTeammate4( Event* )
|
|
{
|
|
}
|
|
|
|
|
|
bool Player::isButtonDown( int button )
|
|
{
|
|
if ( last_ucmd.buttons & button )
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
void Player::notifyPlayerOfMultiplayerEvent( const char *eventName, const char *eventItemName, Player *eventPlayer )
|
|
{
|
|
Q_UNUSED(eventName);
|
|
Q_UNUSED(eventItemName);
|
|
Q_UNUSED(eventPlayer);
|
|
// Put stuff here :)
|
|
}
|
|
|
|
void Player::touchingLadder( Trigger *ladder, const Vector &normal, float top )
|
|
{
|
|
Q_UNUSED(ladder);
|
|
|
|
// Make sure we are allowed to get on the ladder time wise
|
|
|
|
if ( level.time < _nextLadderTime )
|
|
return;
|
|
|
|
// If we are near the top of the ladder and we have a groundentity don't get on the ladder
|
|
|
|
if ( groundentity && origin.z > top - 48 )
|
|
return;
|
|
|
|
// Save off all necessary info
|
|
|
|
_onLadder = true;
|
|
_ladderNormal = normal;
|
|
_ladderTop = top;
|
|
}
|
|
|
|
void Player::warp( Event *ev )
|
|
{
|
|
setOrigin( ev->GetVector( 1 ) );
|
|
NoLerpThisFrame();
|
|
client->ps.pm_flags |= PMF_TIME_TELEPORT;
|
|
CameraCut();
|
|
}
|
|
|
|
void Player::hudPrint( Event *ev )
|
|
{
|
|
hudPrint( ev->GetString( 1 ) );
|
|
}
|
|
|
|
void Player::hudPrint( const str &string )
|
|
{
|
|
str command;
|
|
|
|
// Build the hud print command to send to the client
|
|
|
|
command = "hudprint \"";
|
|
command += string;
|
|
command += "\"\n";
|
|
|
|
// Send the HUD print command
|
|
|
|
gi.SendServerCommand( edict - g_entities, command.c_str() );
|
|
}
|
|
|
|
void Player::setItemText( int itemIcon, const str &itemText )
|
|
{
|
|
CancelEventsOfType( EV_Player_ClearItemText );
|
|
|
|
_itemIcon = itemIcon;
|
|
_itemText = itemText;
|
|
|
|
PostEvent( EV_Player_ClearItemText, 2.0f );
|
|
}
|
|
|
|
void Player::clearItemText( void )
|
|
{
|
|
_itemIcon = 0;
|
|
_itemText = "";
|
|
|
|
CancelEventsOfType( EV_Player_ClearItemText );
|
|
}
|
|
|
|
void Player::clearItemText( Event * )
|
|
{
|
|
clearItemText();
|
|
}
|
|
|
|
void Player::shotFired( void )
|
|
{
|
|
if ( p_heuristics )
|
|
{
|
|
p_heuristics->IncrementShotsFired();
|
|
}
|
|
|
|
++client->ps.stats[ STAT_SHOTS_FIRED ];
|
|
|
|
}
|
|
|
|
void Player::shotHit( void )
|
|
{
|
|
if ( p_heuristics )
|
|
{
|
|
p_heuristics->IncrementShotsHit();
|
|
}
|
|
|
|
++client->ps.stats[ STAT_SHOTS_HIT ];
|
|
}
|
|
|
|
|
|
void Player::cinematicStarted( void )
|
|
{
|
|
|
|
// Turn off any viewmodes
|
|
|
|
setViewMode( "normal" );
|
|
|
|
// Kill the zoom if any
|
|
|
|
Weapon *weapon = GetActiveWeapon( WEAPON_DUAL );
|
|
|
|
if ( weapon )
|
|
{
|
|
weapon->ProcessEvent( "endZoom" );
|
|
|
|
// Force the weapon to idle
|
|
|
|
weapon->ForceIdle();
|
|
}
|
|
}
|
|
|
|
void Player::cinematicStopped( void )
|
|
{
|
|
Weapon *weapon;
|
|
Equipment *equipment;
|
|
|
|
weapon = GetActiveWeapon( WEAPON_DUAL );
|
|
|
|
if ( weapon && weapon->isSubclassOf( Equipment ) )
|
|
{
|
|
equipment = (Equipment *)weapon;
|
|
|
|
equipment->updateMode();
|
|
}
|
|
|
|
// Force the player's state back to idle
|
|
|
|
SetAnim( "stand_idle", legs, true );
|
|
SetAnim( "stand_idle", torso, true );
|
|
LoadStateTable();
|
|
}
|
|
|
|
void Player::loadUseItem( const str &item )
|
|
{
|
|
Event *event;
|
|
str itemName;
|
|
|
|
itemName = item;
|
|
|
|
if ( stricmp( item.c_str(), "tricorder" ) == 0 )
|
|
{
|
|
if ( HasItem( "Tricorder-stx" ) )
|
|
itemName = "Tricorder-stx";
|
|
else if ( HasItem( "Tricorder-rom" ) )
|
|
itemName = "Tricorder-rom";
|
|
}
|
|
|
|
if ( itemName.length() )
|
|
{
|
|
event = new Event( EV_Player_UseItem );
|
|
event->AddString( itemName );
|
|
ProcessEvent( event );
|
|
}
|
|
}
|
|
|
|
void Player::setValidPlayerModel( Event * )
|
|
{
|
|
_validPlayerModel = true;
|
|
}
|
|
|
|
void Player::setVoteText( const str &voteText )
|
|
{
|
|
_voteText = voteText;
|
|
}
|
|
|
|
void Player::clearVoteText( void )
|
|
{
|
|
_voteText = "";
|
|
}
|
|
|
|
void Player::incrementSecretsFound( void )
|
|
{
|
|
_secretsFound++;
|
|
|
|
// Update the cvar if we are greater
|
|
|
|
if ( _secretsFound > g_secretCount->integer )
|
|
{
|
|
gi.cvar_set( "g_secretCount", va( "%d", _secretsFound ) );
|
|
}
|
|
}
|
|
|
|
void Player::addHud( Event *ev )
|
|
{
|
|
addHud( ev->GetString( 1 ) );
|
|
}
|
|
|
|
void Player::addHud( const str &hudName )
|
|
{
|
|
if ( !_hudList.ObjectInList( hudName ) )
|
|
{
|
|
addHudToClient( hudName );
|
|
|
|
_hudList.AddObject( hudName );
|
|
}
|
|
}
|
|
|
|
void Player::removeHud( Event *ev )
|
|
{
|
|
removeHud( ev->GetString( 1 ) );
|
|
}
|
|
|
|
void Player::removeHud( const str &hudName )
|
|
{
|
|
if ( _hudList.ObjectInList( hudName ) )
|
|
{
|
|
removeHudFromClient( hudName );
|
|
|
|
_hudList.RemoveObject( hudName );
|
|
}
|
|
}
|
|
|
|
bool Player::needToSendAllHudsToClient( void )
|
|
{
|
|
if ( _needToSendHuds && _started )
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
void Player::sendAllHudsToClient( void )
|
|
{
|
|
int i;
|
|
str commandString;
|
|
str hudName;
|
|
|
|
if ( _needToSendHuds )
|
|
{
|
|
for( i = 1 ; i <= _hudList.NumObjects() ; i++ )
|
|
{
|
|
hudName = _hudList.ObjectAt( i );
|
|
|
|
addHudToClient( hudName );
|
|
}
|
|
}
|
|
|
|
_needToSendHuds = false;
|
|
}
|
|
|
|
void Player::clearAllHuds( void )
|
|
{
|
|
int i;
|
|
str commandString;
|
|
str hudName;
|
|
|
|
for( i = 1 ; i <= _hudList.NumObjects() ; i++ )
|
|
{
|
|
hudName = _hudList.ObjectAt( i );
|
|
|
|
removeHudFromClient( hudName );
|
|
}
|
|
|
|
_hudList.ClearObjectList();
|
|
}
|
|
|
|
void Player::addHudToClient( const str &hudName )
|
|
{
|
|
str commandString;
|
|
|
|
commandString = "stufftext \"ui_addhud ";
|
|
commandString += hudName;
|
|
commandString += "\"\n";
|
|
|
|
gi.SendServerCommand( entnum, commandString.c_str() );
|
|
}
|
|
|
|
void Player::removeHudFromClient( const str &hudName )
|
|
{
|
|
str commandString;
|
|
|
|
commandString = "stufftext \"ui_removehud ";
|
|
commandString += hudName;
|
|
commandString += "\"\n";
|
|
|
|
gi.SendServerCommand( entnum, commandString.c_str() );
|
|
}
|
|
|
|
void Player::killAllDialog( Event * )
|
|
{
|
|
killAllDialog();
|
|
}
|
|
|
|
void Player::killAllDialog()
|
|
{
|
|
Actor *theActor;
|
|
int i;
|
|
|
|
for ( i = 1; i <= SleepList.NumObjects(); i++ )
|
|
{
|
|
theActor = (Actor*)SleepList.ObjectAt( i );
|
|
theActor->StopDialog();
|
|
}
|
|
|
|
for ( i = 1; i <= ActiveList.NumObjects(); i++ )
|
|
{
|
|
theActor = (Actor*)ActiveList.ObjectAt( i );
|
|
theActor->StopDialog();
|
|
}
|
|
}
|
|
|
|
void Player::clearTempAttachments( void )
|
|
{
|
|
int i;
|
|
Entity *child;
|
|
|
|
if ( bind_info )
|
|
{
|
|
for( i = 0; i < MAX_MODEL_CHILDREN ; i++ )
|
|
{
|
|
if ( bind_info->children[ i ] == ENTITYNUM_NONE )
|
|
continue;
|
|
|
|
child = ( Entity * )G_GetEntity( bind_info->children[ i ] );
|
|
|
|
if ( child )
|
|
{
|
|
if ( child->isSubclassOf( Projectile ) || child->CancelEventsOfType( EV_Remove ) )
|
|
{
|
|
child->PostEvent( EV_Remove, 0.0f );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Player::setSkill( int skill )
|
|
{
|
|
_skillLevel = skill;
|
|
|
|
if ( _skillLevel < 0 )
|
|
_skillLevel = 0;
|
|
else if ( _skillLevel > 3 )
|
|
_skillLevel = 3;
|
|
|
|
|
|
}
|
|
|
|
int Player::getSkill( void )
|
|
{
|
|
return _skillLevel;
|
|
}
|
|
|
|
void Player::forceMoveType( Event *ev )
|
|
{
|
|
str moveTypeName;
|
|
|
|
moveTypeName = ev->GetString( 1 );
|
|
|
|
if ( stricmp( moveTypeName, "secret" ) == 0 )
|
|
_forcedMoveType = PM_SECRET_MOVE_MODE;
|
|
else if ( stricmp( moveTypeName, "3rdPerson" ) == 0 )
|
|
_forcedMoveType = PM_3RD_PERSON;
|
|
else if ( stricmp( moveTypeName, "none" ) == 0 )
|
|
_forcedMoveType = PM_NONE;
|
|
}
|
|
|
|
void Player::isPlayerOnGround( Event *ev )
|
|
{
|
|
float onGround;
|
|
|
|
if ( client->ps.walking )
|
|
{
|
|
onGround = 1.0f;
|
|
}
|
|
else
|
|
{
|
|
onGround = 0.0f;
|
|
}
|
|
|
|
|
|
ev->ReturnFloat( onGround );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name:
|
|
// Class:
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Returns:
|
|
//-----------------------------------------------------
|
|
void Player::setBranchDialogActor( const Actor* actor)
|
|
{
|
|
if( _branchDialogActor != 0)
|
|
_branchDialogActor->clearBranchDialog();
|
|
|
|
_branchDialogActor = (Actor*)actor;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name:
|
|
// Class:
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Returns:
|
|
//-----------------------------------------------------
|
|
void Player::clearBranchDialogActor( void )
|
|
{
|
|
if( _branchDialogActor != 0)
|
|
_branchDialogActor->clearBranchDialog( );
|
|
|
|
_branchDialogActor = 0;
|
|
}
|
|
|
|
void Player::setBackpackAttachOffset( Event *ev )
|
|
{
|
|
_backpackAttachOffset = ev->GetVector( 1 );
|
|
}
|
|
|
|
void Player::setBackpackAttachAngles( Event *ev )
|
|
{
|
|
_backpackAttachAngles = ev->GetVector( 1 );
|
|
}
|
|
|
|
Vector Player::getBackpackAttachOffset( void )
|
|
{
|
|
return _backpackAttachOffset;
|
|
}
|
|
|
|
Vector Player::getBackpackAttachAngles( void )
|
|
{
|
|
return _backpackAttachAngles;
|
|
}
|
|
|
|
void Player::setFlagAttachOffset( Event *ev )
|
|
{
|
|
_flagAttachOffset = ev->GetVector( 1 );
|
|
}
|
|
|
|
void Player::setFlagAttachAngles( Event *ev )
|
|
{
|
|
_flagAttachAngles = ev->GetVector( 1 );
|
|
}
|
|
|
|
Vector Player::getFlagAttachOffset( void )
|
|
{
|
|
return _flagAttachOffset;
|
|
}
|
|
|
|
Vector Player::getFlagAttachAngles( void )
|
|
{
|
|
return _flagAttachAngles;
|
|
}
|
|
|
|
bool Player::canRegenerate( void )
|
|
{
|
|
if ( _powerup && !_powerup->canOwnerRegenerate() )
|
|
return false;
|
|
|
|
if ( _rune && !_rune->canOwnerRegenerate() )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void Player::modelChanged( void )
|
|
{
|
|
if ( _powerup )
|
|
{
|
|
removePowerupEffect( _powerup );
|
|
addPowerupEffect( _powerup );
|
|
}
|
|
|
|
if ( _rune )
|
|
{
|
|
removePowerupEffect( _rune );
|
|
addPowerupEffect( _rune );
|
|
}
|
|
}
|
|
|
|
void Player::setBackupModel( Event *ev )
|
|
{
|
|
setBackupModel( ev->GetString( 1 ) );
|
|
}
|
|
|
|
void Player::setBackupModel( const str &modelName )
|
|
{
|
|
gi.setviewmodel( edict, modelName );
|
|
}
|