openmohaa/code/fgame/player.cpp

8881 lines
248 KiB
C++
Raw Normal View History

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