openmohaa/code/fgame/player_conditionals.cpp

2041 lines
55 KiB
C++
Raw Normal View History

/*
===========================================================================
Copyright (C) 2024 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_combat.cpp: Player combat system and combat utility functions
2023-08-04 00:21:19 +02:00
//
#include "player.h"
#include "weapturret.h"
#include "weaputils.h"
//Forward
//Back
//TurnRight
//TurnLeft
//Moveleft (strafe)
//Moveright (strafe)
//Moveup (Jump)
//Movedown (Duck)
//Action (Use)
//Sneak (Toggle or Momentary)
//Speed/Walk (Toggle or Momentary)
//Fire Left hand
//Fire Right hand
#define SLOPE_45_MIN 0.7071f
#define SLOPE_45_MAX 0.831f
#define SLOPE_22_MIN SLOPE_45_MAX
#define SLOPE_22_MAX 0.95f
#define MIN_Z -999999
#define PUSH_OBJECT_DISTANCE 16.0f
#define ARMS_NAME "Bip01 Spine2"
static Vector min_box_8x8(-4, -4, -4);
static Vector max_box_8x8(4, 4, 4);
static Vector min4x4(-4, -4, 0);
static Vector max4x4x0(4, 4, 0);
static Vector max4x4x8(4, 4, 8);
2023-08-08 22:39:25 +02:00
qboolean Player::CondTrue(Conditional& condition)
{
return true;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondChance(Conditional& condition)
{
float percent_chance;
percent_chance = atof(condition.getParm(1));
return (G_Random() < percent_chance);
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondHealth(Conditional& condition)
{
return health < atoi(condition.getParm(1));
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondBlocked(Conditional& condition)
{
int test_moveresult;
2023-08-08 22:39:25 +02:00
test_moveresult = moveresult;
2023-08-08 22:39:25 +02:00
if (flags & FL_IMMOBILE) {
test_moveresult = MOVERESULT_BLOCKED;
}
2023-08-08 22:39:25 +02:00
if (condition.numParms()) {
return test_moveresult >= atoi(condition.getParm(1));
}
2023-08-08 22:39:25 +02:00
return test_moveresult >= MOVERESULT_BLOCKED;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondPain(Conditional& condition)
{
return pain != 0 && level.time > nextpaintime;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondOnGround(Conditional& condition)
{
if (groundentity || client->ps.walking) {
falling = 0;
return qtrue;
} else {
return qfalse;
}
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondHasWeapon(Conditional& condition)
{
return WeaponsOut();
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondNewWeapon(Conditional& condition)
{
Weapon *weapon;
2023-08-08 22:39:25 +02:00
weapon = GetNewActiveWeapon();
2023-08-08 22:39:25 +02:00
if (weapon) {
return true;
} else {
return false;
}
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondImmediateSwitch(Conditional& condition)
{
static cvar_t *g_immediateswitch = NULL;
2023-08-08 22:39:25 +02:00
if (!g_immediateswitch) {
g_immediateswitch = gi.Cvar_Get("g_immediateswitch", "0", 0);
}
2023-08-08 22:39:25 +02:00
return (g_gametype->integer && g_immediateswitch->integer);
}
2023-08-08 22:39:25 +02:00
// Check to see if a weapon has been raised
qboolean Player::CondUseWeapon(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
const char *weaponName;
const char *parm;
2023-08-08 22:39:25 +02:00
weaponhand_t hand;
Weapon *weap;
2023-08-08 22:39:25 +02:00
weap = GetNewActiveWeapon();
parm = condition.getParm(1);
2023-08-08 22:39:25 +02:00
if (!str::icmp(parm, "ERROR")) {
if (weap) {
warning("Player::CondUseweapon", "%s does not have a valid RAISE_WEAPON state\n", weap->item_name.c_str());
} else {
warning("Player::CondUseweapon", "New Active weapon does not exist\n");
}
2023-08-08 22:39:25 +02:00
ClearNewActiveWeapon();
return qtrue;
}
2023-08-08 22:39:25 +02:00
hand = WeaponHandNameToNum(parm);
if (hand == WEAPON_ERROR) {
return false;
}
2023-08-08 22:39:25 +02:00
weaponName = condition.getParm(2);
2023-08-08 22:39:25 +02:00
if ((weap != NULL) && (GetNewActiveWeaponHand() == hand) && (!Q_stricmp(weap->item_name, weaponName))) {
return true;
} else {
return false;
}
2023-08-08 22:39:25 +02:00
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondUseWeaponClass(Conditional& condition)
{
const char *weaponClass;
const char *parm;
2023-08-08 22:39:25 +02:00
weaponhand_t hand;
Weapon *weap;
2023-08-08 22:39:25 +02:00
weap = GetNewActiveWeapon();
parm = condition.getParm(1);
if (!str::icmp(parm, "ERROR")) {
if (weap) {
warning(
"Player::CondUseweaponclass", "%s does not have a valid RAISE_WEAPON state\n", weap->getName().c_str()
);
} else {
warning("Player::CondUseweaponclass", "New Active weapon does not exist\n");
}
2023-08-08 22:39:25 +02:00
ClearNewActiveWeapon();
return qtrue;
}
2023-08-08 22:39:25 +02:00
hand = WeaponHandNameToNum(parm);
if (hand == WEAPON_ERROR) {
return false;
}
2023-08-08 22:39:25 +02:00
weaponClass = condition.getParm(2);
2023-08-08 22:39:25 +02:00
if ((weap != NULL) && (weap->isSubclassOf(Weapon)) && (GetNewActiveWeaponHand() == hand)
&& (weap->GetWeaponClass() & G_WeaponClassNameToNum(weaponClass))) {
return true;
} else {
return false;
}
}
2023-08-08 22:39:25 +02:00
// Checks to see if weapon is active
qboolean Player::CondWeaponActive(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
const char *weaponName;
weaponhand_t hand;
2023-08-08 22:39:25 +02:00
weaponName = condition.getParm(2);
hand = WeaponHandNameToNum(condition.getParm(1));
2023-08-08 22:39:25 +02:00
if (hand == WEAPON_ERROR) {
return false;
}
2023-08-08 22:39:25 +02:00
Weapon *weapon = GetActiveWeapon(hand);
2023-08-08 22:39:25 +02:00
return (weapon && !Q_stricmp(weaponName, weapon->item_name));
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondWeaponClassActive(Conditional& condition)
{
const char *weaponClass;
weaponhand_t hand;
2023-08-08 22:39:25 +02:00
weaponClass = condition.getParm(2);
hand = WeaponHandNameToNum(condition.getParm(1));
2023-08-08 22:39:25 +02:00
if (hand == WEAPON_ERROR) {
return false;
}
2023-08-08 22:39:25 +02:00
Weapon *weapon = GetActiveWeapon(hand);
2023-08-08 22:39:25 +02:00
return (weapon && G_WeaponClassNameToNum(weaponClass) & weapon->GetWeaponClass());
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondWeaponCurrentFireAnim(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
weaponhand_t hand = WeaponHandNameToNum(condition.getParm(1));
int iFireAnim = atoi(condition.getParm(2));
Weapon *weapon;
2023-08-08 22:39:25 +02:00
if (hand == WEAPON_ERROR) {
return false;
}
2023-08-08 22:39:25 +02:00
weapon = GetActiveWeapon(hand);
2023-08-08 22:39:25 +02:00
return weapon && weapon->m_iCurrentFireAnim == iFireAnim;
}
2023-08-08 22:39:25 +02:00
// Checks to see if weapon is active and ready to fire
qboolean Player::CondWeaponReadyToFire(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
firemode_t mode = FIRE_PRIMARY;
str weaponName = "None";
weaponhand_t hand;
qboolean ready;
2023-08-08 22:39:25 +02:00
if (level.playerfrozen || m_bFrozen || (flags & FL_IMMOBILE)) {
return false;
}
2023-08-08 22:39:25 +02:00
hand = WeaponHandNameToNum(condition.getParm(1));
2023-08-08 22:39:25 +02:00
if (condition.numParms() > 1) {
weaponName = condition.getParm(2);
}
2023-08-08 22:39:25 +02:00
if (hand == WEAPON_ERROR) {
return false;
}
2023-08-08 22:39:25 +02:00
Weapon *weapon = GetActiveWeapon(hand);
2023-08-08 22:39:25 +02:00
// Weapon there check
if (!weapon) {
return false;
}
2023-08-08 22:39:25 +02:00
// Name check
if (condition.numParms() > 1) {
if (strcmp(weaponName, weapon->item_name)) {
return false;
}
}
2023-08-08 22:39:25 +02:00
// Ammo check
ready = weapon->ReadyToFire(mode);
return (ready);
}
// Checks to see if weapon is active and ready to fire
qboolean Player::CondWeaponClassReadyToFire(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
firemode_t mode = FIRE_PRIMARY;
str weaponClass = "None";
weaponhand_t hand;
qboolean ready;
Weapon *weapon;
2023-08-08 22:39:25 +02:00
if (level.playerfrozen || m_bFrozen || (flags & FL_IMMOBILE)) {
return false;
}
2023-08-08 22:39:25 +02:00
hand = WeaponHandNameToNum(condition.getParm(1));
2023-08-08 22:39:25 +02:00
if (condition.numParms() > 1) {
weaponClass = condition.getParm(2);
}
2023-08-08 22:39:25 +02:00
if (hand == WEAPON_ERROR) {
return false;
}
weapon = GetActiveWeapon(hand);
2023-08-08 22:39:25 +02:00
// Weapon there check
if (!weapon) {
return qfalse;
}
2023-08-08 22:39:25 +02:00
// Name check
if (condition.numParms() > 1) {
if (!(G_WeaponClassNameToNum(weaponClass) & weapon->GetWeaponClass())) {
return qfalse;
}
if (condition.numParms() > 2) {
mode = WeaponModeNameToNum(condition.getParm(3));
}
2023-08-08 22:39:25 +02:00
}
// Ammo check
ready = weapon->ReadyToFire(mode);
return (ready);
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondUsingVehicle(Conditional& condition)
{
return (m_pVehicle != NULL);
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondVehicleType(Conditional& condition)
{
str sType = condition.getParm(1);
if (m_pVehicle && m_pVehicle->IsSubclassOfVehicle()) {
return !str::cmp(sType, m_pVehicle->getName());
} else {
return !str::cmp(sType, "none");
}
2023-08-08 22:39:25 +02:00
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondIsPassenger(Conditional& condition)
{
return m_pVehicle && m_pVehicle->IsSubclassOfVehicle() && m_pVehicle->FindPassengerSlotByEntity(this);
2023-08-08 22:39:25 +02:00
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondIsDriver(Conditional& condition)
{
return m_pVehicle && m_pVehicle->IsSubclassOfVehicle() && m_pVehicle->FindDriverSlotByEntity(this);
2023-08-08 22:39:25 +02:00
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondUsingTurret(Conditional& condition)
{
return (m_pTurret != NULL);
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondIsEscaping(Conditional& condition)
{
return m_jailstate == JAILSTATE_ESCAPE;
2023-08-08 22:39:25 +02:00
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondAbleToDefuse(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
Weapon *weapon = GetActiveWeapon(WEAPON_MAIN);
float maxrange;
2023-08-08 22:39:25 +02:00
if (!weapon) {
weapon = GetActiveWeapon(WEAPON_OFFHAND);
}
2023-08-08 22:39:25 +02:00
Vector vForward, vRight, vUp;
2023-12-28 18:55:43 +01:00
AngleVectors(m_vViewAng, vForward, vRight, vUp);
2023-08-08 22:39:25 +02:00
maxrange = weapon->GetMaxRange();
return FindDefusableObject(vForward, this, maxrange) ? true : false;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondCanPlaceLandmine(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
Weapon *weapon = GetActiveWeapon(WEAPON_MAIN);
if (!weapon) {
weapon = GetActiveWeapon(WEAPON_OFFHAND);
}
2023-08-08 22:39:25 +02:00
Vector vPos, vForward, vRight, vUp, vBarrel;
weapon->GetMuzzlePosition(vPos, vBarrel, vForward, vRight, vUp);
2023-08-08 22:39:25 +02:00
return CanPlaceLandmine(vPos, this);
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondOnLandmine(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
MeasureLandmineDistances();
2023-08-08 22:39:25 +02:00
return m_fMineDist <= 1.f;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondNearLandmine(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
MeasureLandmineDistances();
2023-08-08 22:39:25 +02:00
return m_fMineDist < 3.f && m_fMineDist > 1.f;
}
2023-08-08 22:39:25 +02:00
void Player::MeasureLandmineDistances()
{
Weapon* weapon;
float previousMineDist;
float maxrange;
int i;
if (m_fMineCheckTime == level.time) {
return;
}
m_fMineCheckTime = level.time;
previousMineDist = m_fMineDist;
m_fMineDist = 1000;
weapon = GetActiveWeapon(WEAPON_MAIN);
if (!weapon) {
weapon = GetActiveWeapon(WEAPON_OFFHAND);
}
maxrange = 40;
if (weapon) {
maxrange = weapon->GetMaxRange();
}
for (i = 0; i < globals.max_entities; i++) {
TriggerLandmine* landmine;
Entity* ent;
vec3_t forward;
Vector delta;
float radius;
ent = G_GetEntity(i);
if (!ent) {
continue;
}
if (!ent->isSubclassOf(TriggerLandmine)) {
continue;
}
landmine = static_cast<TriggerLandmine*>(ent);
// This could be from an allied player
if (landmine->IsImmune(this)) {
continue;
}
AngleVectorsLeft(angles, forward, NULL, NULL);
delta = landmine->origin - origin;
radius = delta.length();
if (radius < maxrange) {
ent->PostEvent(EV_Show, level.frametime);
}
if (radius > m_fMineDist) {
continue;
}
if (radius >= 40) {
float dot;
delta.normalize();
dot = DotProduct(delta, forward);
if (dot > 0 && radius / Square(dot) < m_fMineDist) {
m_fMineDist = radius / Square(dot);
}
} else if (radius < m_fMineDist) {
m_fMineDist = radius;
}
}
m_fMineDist /= maxrange;
if (m_fMineDist > 3) {
StopLoopSound();
return;
}
if (floorf(previousMineDist * 20) != floorf(m_fMineDist * 20)) {
float pitch;
pitch = 2.f - log(m_fMineDist + 1.0);
LoopSound("minedetector_on", -1, -1, -1, pitch);
}
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondIsAssistingEscape(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
return m_jailstate == JAILSTATE_ASSIST_ESCAPE;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondTurretType(Conditional& condition)
{
str name = condition.getParm(1);
if (m_pTurret) {
return m_pTurret->getName() == name;
} else {
return name == "none";
}
2023-08-08 22:39:25 +02:00
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondWeaponReadyToFireNoSound(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
firemode_t mode = FIRE_PRIMARY;
str weaponName = "None";
weaponhand_t hand;
qboolean ready;
2023-08-08 22:39:25 +02:00
if (level.playerfrozen || m_bFrozen || (flags & FL_IMMOBILE)) {
return false;
}
2023-08-08 22:39:25 +02:00
hand = WeaponHandNameToNum(condition.getParm(1));
if (condition.numParms() > 1) {
weaponName = condition.getParm(2);
}
2023-08-08 22:39:25 +02:00
if (hand == WEAPON_ERROR) {
return false;
}
2023-08-08 22:39:25 +02:00
Weapon *weapon = GetActiveWeapon(hand);
2023-08-08 22:39:25 +02:00
// Weapon there check
if (!weapon) {
return qfalse;
}
2023-08-08 22:39:25 +02:00
// Name check
if (condition.numParms() > 1) {
if (strcmp(weaponName, weapon->item_name)) {
return qfalse;
}
}
2023-08-08 22:39:25 +02:00
// Ammo check
ready = weapon->ReadyToFire(mode, qfalse);
return (ready);
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondPutAwayMain(Conditional& condition)
{
Weapon *weapon = GetActiveWeapon(WEAPON_MAIN);
2023-08-08 22:39:25 +02:00
return weapon && weapon->GetPutaway();
}
2023-08-08 22:39:25 +02:00
// Check to see if any of the active weapons need to be put away
qboolean Player::CondPutAwayOffHand(Conditional& condition)
{
Weapon *weapon = GetActiveWeapon(WEAPON_OFFHAND);
return weapon && weapon->GetPutaway();
}
2023-08-08 22:39:25 +02:00
// Checks to see if any weapon is active in the specified hand
qboolean Player::CondAnyWeaponActive(Conditional& condition)
{
weaponhand_t hand;
Weapon *weap;
hand = WeaponHandNameToNum(condition.getParm(1));
if (hand == WEAPON_ERROR) {
return false;
}
weap = GetActiveWeapon(hand);
return (weap != NULL);
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondAttackBlocked(Conditional& condition)
{
if (attack_blocked) {
attack_blocked = qfalse;
return true;
} else {
return false;
}
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondSemiAuto(Conditional& condition)
{
firemode_t mode = FIRE_PRIMARY;
str handname;
weaponhand_t hand;
handname = condition.getParm(1);
hand = WeaponHandNameToNum(handname);
2023-08-08 22:39:25 +02:00
if (hand != WEAPON_ERROR) {
return GetActiveWeapon(hand)->m_bSemiAuto;
} else {
return qfalse;
}
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondMinChargeTime(Conditional& condition)
{
const char *handname;
weaponhand_t hand;
Weapon *weap;
handname = condition.getParm(1);
hand = WeaponHandNameToNum(handname);
if (hand != WEAPON_ERROR) {
weap = GetActiveWeapon(hand);
// Fixed in 2.0.
// Make sure the active weapon is valid
if (weap) {
float charge_time = weap->GetMinChargeTime(FIRE_PRIMARY);
if (charge_time) {
if (charge_start_time) {
return level.time - charge_start_time >= charge_time;
} else {
return qfalse;
}
} else {
return qtrue;
}
}
}
return qfalse;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondMaxChargeTime(Conditional& condition)
{
const char *handname;
weaponhand_t hand;
Weapon *weap;
handname = condition.getParm(1);
hand = WeaponHandNameToNum(handname);
if (hand != WEAPON_ERROR) {
weap = GetActiveWeapon(hand);
if (weap) {
float charge_time = weap->GetMaxChargeTime(FIRE_PRIMARY);
if (charge_time) {
if (charge_start_time) {
return level.time - charge_start_time >= charge_time;
} else {
return qfalse;
}
} else {
return qtrue;
}
}
}
return qfalse;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondBlockDelay(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
float t = atof(condition.getParm(1));
return (level.time > (attack_blocked_time + t));
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondMuzzleClear(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
weaponhand_t hand;
2023-08-08 22:39:25 +02:00
hand = WeaponHandNameToNum(condition.getParm(1));
if (hand == WEAPON_ERROR) {
return false;
}
2023-08-08 22:39:25 +02:00
Weapon *weapon = GetActiveWeapon(hand);
return (weapon && weapon->MuzzleClear());
}
2023-08-08 22:39:25 +02:00
// Checks to see if any weapon is active in the specified hand
qboolean Player::CondWeaponHasAmmo(Conditional& condition)
{
weaponhand_t hand;
Weapon *weap;
firemode_t mode = FIRE_PRIMARY;
hand = WeaponHandNameToNum(condition.getParm(1));
if (condition.numParms() > 1) {
mode = WeaponModeNameToNum(condition.getParm(2));
}
if (hand == WEAPON_ERROR) {
return false;
}
weap = GetActiveWeapon(hand);
if (!weap) {
return false;
} else {
return (weap->HasAmmo(mode));
}
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondWeaponHasAmmoInClip(Conditional& condition)
{
weaponhand_t hand;
Weapon *weap;
firemode_t mode = FIRE_PRIMARY;
hand = WeaponHandNameToNum(condition.getParm(1));
if (condition.numParms() > 1) {
mode = WeaponModeNameToNum(condition.getParm(2));
}
if (hand == WEAPON_ERROR) {
return false;
}
weap = GetActiveWeapon(hand);
2023-08-08 22:39:25 +02:00
if (!weap) {
return false;
} else {
return (weap->HasAmmoInClip(mode));
}
}
qboolean Player::CondReload(Conditional& condition)
{
Weapon *weapon;
weaponhand_t hand = WEAPON_MAIN;
if (condition.numParms() > 0) {
hand = WeaponHandNameToNum(condition.getParm(1));
if (hand == WEAPON_ERROR) {
return qfalse;
}
}
weapon = GetActiveWeapon(WEAPON_MAIN);
if (!weapon) {
return qfalse;
}
if (weapon->ShouldReload() && weapon->HasAmmo(FIRE_PRIMARY)) {
return qtrue;
}
return qfalse;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondWeaponsHolstered(Conditional& condition)
{
if (holsteredWeapon) {
return qtrue;
} else {
return qfalse;
}
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondWeaponIsItem(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
weaponhand_t hand = WeaponHandNameToNum(condition.getParm(1));
Weapon *weapon;
if (hand == WEAPON_ERROR) {
return false;
}
2023-08-08 22:39:25 +02:00
weapon = GetActiveWeapon(hand);
2023-08-08 22:39:25 +02:00
return weapon && weapon->IsSubclassOfInventoryItem();
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondNewWeaponIsItem(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
Weapon *weapon = GetNewActiveWeapon();
return weapon && weapon->IsSubclassOfInventoryItem();
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondTurnLeft(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
float yaw;
2023-08-08 22:39:25 +02:00
yaw = SHORT2ANGLE(last_ucmd.angles[YAW] + client->ps.delta_angles[YAW]);
2023-08-08 22:39:25 +02:00
return (angledist(old_v_angle[YAW] - yaw) < -8.0f);
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondTurnRight(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
float yaw;
2023-08-08 22:39:25 +02:00
yaw = SHORT2ANGLE(last_ucmd.angles[YAW] + client->ps.delta_angles[YAW]);
2023-08-08 22:39:25 +02:00
return (angledist(old_v_angle[YAW] - yaw) > 8.0f);
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondForward(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
return last_ucmd.forwardmove > 0;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondBackward(Conditional& condition)
{
return last_ucmd.forwardmove < 0;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondStrafeLeft(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
return last_ucmd.rightmove < 0;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondStrafeRight(Conditional& condition)
{
return last_ucmd.rightmove > 0;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondJump(Conditional& condition)
{
if (client->ps.pm_flags & PMF_NO_MOVE) {
return false;
}
2023-08-08 22:39:25 +02:00
return last_ucmd.upmove > 0;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondCrouch(Conditional& condition)
{
// Added in 2.0
// Don't crouch if the player is not moving
if (client->ps.pm_flags & PMF_NO_MOVE
&& (g_target_game > target_game_e::TG_MOH || g_gametype->integer != GT_SINGLE_PLAYER)) {
// Added in 2.30
// Allow ducking if specified
if (!m_pGlueMaster || !m_bGlueDuckable) {
return viewheight != DEFAULT_VIEWHEIGHT;
}
}
return (last_ucmd.upmove) < 0;
2023-08-08 22:39:25 +02:00
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondJumpFlip(Conditional& condition)
{
return velocity.z < (sv_gravity->value * 0.5f);
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondAnimDoneLegs(Conditional& condition)
{
return animdone_Legs;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondAnimDoneTorso(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
return animdone_Torso;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondAttackPrimary(Conditional& condition)
{
Weapon *weapon;
if (level.playerfrozen || m_bFrozen || (flags & FL_IMMOBILE)) {
return false;
}
if (g_gametype->integer != GT_SINGLE_PLAYER && !m_bAllowFighting) {
return false;
}
if (!(last_ucmd.buttons & BUTTON_ATTACKLEFT)) {
return false;
}
last_attack_button = BUTTON_ATTACKLEFT;
weapon = GetActiveWeapon(WEAPON_MAIN);
if (weapon) {
return true;
}
// No ammo
return false;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondAttackButtonPrimary(Conditional& condition)
{
if (level.playerfrozen || m_bFrozen || (flags & FL_IMMOBILE)) {
return false;
}
if (g_gametype->integer != GT_SINGLE_PLAYER && !m_bAllowFighting) {
return false;
}
2023-08-08 22:39:25 +02:00
return (last_ucmd.buttons & BUTTON_ATTACKLEFT);
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondAttackSecondary(Conditional& condition)
{
Weapon *weapon;
if (level.playerfrozen || m_bFrozen || (flags & FL_IMMOBILE)) {
return false;
}
if (g_gametype->integer != GT_SINGLE_PLAYER && !m_bAllowFighting) {
return false;
}
if (!(last_ucmd.buttons & BUTTON_ATTACKRIGHT)) {
return false;
}
last_attack_button = BUTTON_ATTACKRIGHT;
weapon = GetActiveWeapon(WEAPON_MAIN);
if (weapon) {
return true;
2023-08-08 22:39:25 +02:00
}
// No ammo
return false;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondAttackButtonSecondary(Conditional& condition)
{
if (level.playerfrozen || m_bFrozen || (flags & FL_IMMOBILE)) {
return false;
}
if (g_gametype->integer != GT_SINGLE_PLAYER && !m_bAllowFighting) {
return false;
}
2023-08-08 22:39:25 +02:00
return (last_ucmd.buttons & BUTTON_ATTACKRIGHT);
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondPositionType(Conditional& condition)
{
int flags = 0;
str s;
2023-08-08 22:39:25 +02:00
s = condition.getParm(1);
2023-08-08 22:39:25 +02:00
if (!s.icmp("crouching")) {
flags = MPF_POSITION_CROUCHING;
} else if (!s.icmp("prone")) {
flags = MPF_POSITION_PRONE;
} else if (!s.icmp("offground")) {
flags = MPF_POSITION_OFFGROUND;
} else {
flags = MPF_POSITION_STANDING;
}
2023-08-08 22:39:25 +02:00
return (m_iMovePosFlags & flags);
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondMovementType(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
int flags = 0;
str s;
2023-08-08 22:39:25 +02:00
s = condition.getParm(1);
2023-08-08 22:39:25 +02:00
if (!s.icmp("walking")) {
flags = MPF_MOVEMENT_WALKING;
} else if (!s.icmp("running")) {
flags = MPF_MOVEMENT_RUNNING;
} else if (!s.icmp("falling")) {
flags = MPF_MOVEMENT_FALLING;
}
2023-08-08 22:39:25 +02:00
return (m_iMovePosFlags & flags);
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondRun(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
return (last_ucmd.buttons & BUTTON_RUN) != 0;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondUse(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
return (last_ucmd.buttons & BUTTON_USE) != 0;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondCanTurn(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
float yaw;
Vector oldang(v_angle);
qboolean result;
2023-08-08 22:39:25 +02:00
yaw = atof(condition.getParm(1));
2023-08-08 22:39:25 +02:00
v_angle[YAW] = (int)(anglemod(v_angle[YAW] + yaw) / 22.5f) * 22.5f;
SetViewAngles(v_angle);
2023-08-08 22:39:25 +02:00
result = CheckMove(vec_zero);
SetViewAngles(oldang);
return result;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondLeftVelocity(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
if (condition.numParms()) {
return move_left_vel >= atof(condition.getParm(1));
} else {
2023-08-08 22:39:25 +02:00
return move_left_vel > 4.0f;
}
2023-08-08 22:39:25 +02:00
return qfalse;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondRightVelocity(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
if (condition.numParms()) {
return move_right_vel >= atof(condition.getParm(1));
} else {
return move_right_vel > 4.0f;
}
return qfalse;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondBackwardVelocity(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
if (condition.numParms()) {
return move_backward_vel >= atof(condition.getParm(1));
} else {
return move_backward_vel > 4.0f;
}
return qfalse;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondForwardVelocity(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
if (condition.numParms()) {
return move_forward_vel >= atof(condition.getParm(1));
} else {
return move_forward_vel > 4.0f;
}
2023-08-08 22:39:25 +02:00
return qfalse;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondUpVelocity(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
if (condition.numParms()) {
return move_up_vel >= atof(condition.getParm(1));
} else {
return move_up_vel > 4.0f;
}
2023-08-08 22:39:25 +02:00
return qfalse;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondDownVelocity(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
if (condition.numParms()) {
return move_down_vel >= atof(condition.getParm(1));
} else {
return move_down_vel > 4.0f;
}
2023-08-08 22:39:25 +02:00
return qfalse;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondHasVelocity(Conditional& condition)
{
float fSpeed;
2023-08-08 22:39:25 +02:00
if (condition.numParms()) {
fSpeed = atof(condition.getParm(1));
} else {
fSpeed = 4.0f;
}
2023-08-08 22:39:25 +02:00
return (
(move_forward_vel > fSpeed) || (move_backward_vel > fSpeed) || (move_right_vel > fSpeed)
|| (move_left_vel > fSpeed)
);
}
2023-08-08 22:39:25 +02:00
qboolean Player::Cond22DegreeSlope(Conditional& condition)
{
if (client->ps.walking && client->ps.groundPlane && (client->ps.groundTrace.plane.normal[2] < SLOPE_22_MAX)
&& (client->ps.groundTrace.plane.normal[2] >= SLOPE_22_MIN)) {
return qtrue;
}
2023-08-08 22:39:25 +02:00
return qfalse;
}
2023-08-08 22:39:25 +02:00
qboolean Player::Cond45DegreeSlope(Conditional& condition)
{
if (client->ps.walking && client->ps.groundPlane && (client->ps.groundTrace.plane.normal[2] < SLOPE_45_MAX)
&& (client->ps.groundTrace.plane.normal[2] >= SLOPE_45_MIN)) {
return qtrue;
}
2023-08-08 22:39:25 +02:00
return qfalse;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondRightLegHigh(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
float groundyaw;
float yawdelta;
int which;
2023-08-08 22:39:25 +02:00
groundyaw = (int)vectoyaw(client->ps.groundTrace.plane.normal);
yawdelta = anglemod(v_angle.y - groundyaw);
which = ((int)yawdelta + 45) / 90;
2023-08-08 22:39:25 +02:00
return (which == 3);
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondLeftLegHigh(Conditional& condition)
{
float groundyaw;
float yawdelta;
int which;
2023-08-08 22:39:25 +02:00
groundyaw = (int)vectoyaw(client->ps.groundTrace.plane.normal);
yawdelta = anglemod(v_angle.y - groundyaw);
which = ((int)yawdelta + 45) / 90;
2023-08-08 22:39:25 +02:00
return (which == 1);
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondFacingUpSlope(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
float groundyaw;
float yawdelta;
int which;
2023-08-08 22:39:25 +02:00
groundyaw = (int)vectoyaw(client->ps.groundTrace.plane.normal);
yawdelta = anglemod(v_angle.y - groundyaw);
which = ((int)yawdelta + 45) / 90;
2023-08-08 22:39:25 +02:00
return (which == 2);
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondFacingDownSlope(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
float groundyaw;
float yawdelta;
int which;
2023-08-08 22:39:25 +02:00
groundyaw = (int)vectoyaw(client->ps.groundTrace.plane.normal);
yawdelta = anglemod(v_angle.y - groundyaw);
which = ((int)yawdelta + 45) / 90;
2023-08-08 22:39:25 +02:00
return ((which == 0) || (which == 4));
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondFalling(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
return falling;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondGroundEntity(Conditional& condition)
{
return (groundentity != NULL);
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondMediumImpact(Conditional& condition)
{
return mediumimpact;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondHardImpact(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
return hardimpact;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondCanFall(Conditional& condition)
{
return canfall;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondAtDoor(Conditional& condition)
{
// Check if the player is at a door
return (atobject && atobject->isSubclassOf(Door));
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondAtUseAnim(Conditional& condition)
{
// Check if the player is at a useanim
if (atobject && atobject->isSubclassOf(UseAnim)) {
return ((UseAnim *)(Entity *)atobject)->canBeUsed(this);
}
2023-08-08 22:39:25 +02:00
return false;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondTouchUseAnim(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
if (toucheduseanim) {
return ((UseAnim *)(Entity *)toucheduseanim)->canBeUsed(this);
2023-08-04 00:21:19 +02:00
}
2023-08-08 22:39:25 +02:00
return qfalse;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondUseAnimFinished(Conditional& condition)
{
return (useanim_numloops <= 0);
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondAtUseObject(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
// Check if the player is at a useanim
if (atobject && atobject->isSubclassOf(UseObject)) {
return ((UseObject *)(Entity *)atobject)->canBeUsed(origin, yaw_forward);
}
2023-08-08 22:39:25 +02:00
return false;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondLoopUseObject(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
// Check if the player is at a useanim
if (useitem_in_use && useitem_in_use->isSubclassOf(UseObject)) {
return ((UseObject *)(Entity *)useitem_in_use)->Loop();
}
return false;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondDead(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
return (deadflag);
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondKnockDown(Conditional& condition)
{
if (knockdown) {
knockdown = false;
return true;
} else {
2023-08-08 22:39:25 +02:00
return false;
}
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondPainType(Conditional& condition)
{
2023-08-15 01:27:35 +02:00
if (pain_type == MOD_string_to_int(condition.getParm(1))) {
2023-08-08 22:39:25 +02:00
return qtrue;
} else {
return qfalse;
}
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondPainDirection(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
if (pain_dir == Pain_string_to_int(condition.getParm(1))) {
return qtrue;
} else {
return qfalse;
}
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondPainLocation(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
str sLocationName;
int iLocationNum;
sLocationName = condition.getParm(1);
2023-08-08 22:39:25 +02:00
if (!sLocationName.icmp("miss")) {
2023-08-11 01:33:49 +02:00
iLocationNum = HITLOC_MISS;
2023-08-08 22:39:25 +02:00
} else if (!sLocationName.icmp("general")) {
2023-08-11 01:33:49 +02:00
iLocationNum = HITLOC_GENERAL;
2023-08-08 22:39:25 +02:00
} else if (!sLocationName.icmp("head")) {
2023-08-11 01:33:49 +02:00
iLocationNum = HITLOC_HEAD;
2023-08-08 22:39:25 +02:00
} else if (!sLocationName.icmp("helmet")) {
2023-08-11 01:33:49 +02:00
iLocationNum = HITLOC_HELMET;
2023-08-08 22:39:25 +02:00
} else if (!sLocationName.icmp("neck")) {
2023-08-11 01:33:49 +02:00
iLocationNum = HITLOC_NECK;
2023-08-08 22:39:25 +02:00
} else if (!sLocationName.icmp("torso_upper")) {
2023-08-11 01:33:49 +02:00
iLocationNum = HITLOC_TORSO_UPPER;
2023-08-08 22:39:25 +02:00
} else if (!sLocationName.icmp("torso_mid")) {
2023-08-11 01:33:49 +02:00
iLocationNum = HITLOC_TORSO_MID;
2023-08-08 22:39:25 +02:00
} else if (!sLocationName.icmp("torso_lower")) {
2023-08-11 01:33:49 +02:00
iLocationNum = HITLOC_TORSO_LOWER;
2023-08-08 22:39:25 +02:00
} else if (!sLocationName.icmp("pelvis")) {
2023-08-11 01:33:49 +02:00
iLocationNum = HITLOC_PELVIS;
2023-08-08 22:39:25 +02:00
} else if (!sLocationName.icmp("r_arm_upper")) {
2023-08-11 01:33:49 +02:00
iLocationNum = HITLOC_R_ARM_UPPER;
2023-08-08 22:39:25 +02:00
} else if (!sLocationName.icmp("l_arm_upper")) {
2023-08-11 01:33:49 +02:00
iLocationNum = HITLOC_L_ARM_UPPER;
2023-08-08 22:39:25 +02:00
} else if (!sLocationName.icmp("r_leg_upper")) {
2023-08-11 01:33:49 +02:00
iLocationNum = HITLOC_R_LEG_UPPER;
2023-08-08 22:39:25 +02:00
} else if (!sLocationName.icmp("l_leg_upper")) {
2023-08-11 01:33:49 +02:00
iLocationNum = HITLOC_L_LEG_UPPER;
2023-08-08 22:39:25 +02:00
} else if (!sLocationName.icmp("r_arm_lower")) {
2023-08-11 01:33:49 +02:00
iLocationNum = HITLOC_R_ARM_LOWER;
2023-08-08 22:39:25 +02:00
} else if (!sLocationName.icmp("l_arm_lower")) {
2023-08-11 01:33:49 +02:00
iLocationNum = HITLOC_L_ARM_LOWER;
2023-08-08 22:39:25 +02:00
} else if (!sLocationName.icmp("r_leg_lower")) {
2023-08-11 01:33:49 +02:00
iLocationNum = HITLOC_R_LEG_LOWER;
2023-08-08 22:39:25 +02:00
} else if (!sLocationName.icmp("l_leg_lower")) {
2023-08-11 01:33:49 +02:00
iLocationNum = HITLOC_L_LEG_LOWER;
2023-08-08 22:39:25 +02:00
} else if (!sLocationName.icmp("r_hand")) {
2023-08-11 01:33:49 +02:00
iLocationNum = HITLOC_R_HAND;
2023-08-08 22:39:25 +02:00
} else if (!sLocationName.icmp("l_hand")) {
2023-08-11 01:33:49 +02:00
iLocationNum = HITLOC_L_HAND;
2023-08-08 22:39:25 +02:00
} else if (!sLocationName.icmp("r_foot")) {
2023-08-11 01:33:49 +02:00
iLocationNum = HITLOC_R_FOOT;
2023-08-08 22:39:25 +02:00
} else if (!sLocationName.icmp("l_foot")) {
2023-08-11 01:33:49 +02:00
iLocationNum = HITLOC_L_FOOT;
2023-08-08 22:39:25 +02:00
} else {
Com_Printf("CondPainLocation: Unknown player hit location %s\n", sLocationName.c_str());
}
2023-08-08 22:39:25 +02:00
return (pain_location == iLocationNum);
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondPainThreshold(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
float threshold = atof(condition.getParm(1));
if ((pain >= threshold) && (level.time > nextpaintime)) {
pain = 0; // zero out accumulation since we are going into a pain anim right now
return true;
} else {
2023-08-08 22:39:25 +02:00
return false;
}
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondLegsState(Conditional& condition)
{
if (currentState_Legs) {
str current = currentState_Legs->getName();
str compare = condition.getParm(1);
2023-08-08 22:39:25 +02:00
if (current == compare) {
return true;
}
}
2023-08-08 22:39:25 +02:00
return false;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondTorsoState(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
if (currentState_Torso) {
str current = currentState_Torso->getName();
str compare = condition.getParm(1);
2023-08-08 22:39:25 +02:00
if (current == compare) {
return true;
}
}
2023-08-08 22:39:25 +02:00
return false;
}
qboolean Player::CondStateName(Conditional& condition)
{
str part = condition.getParm(1);
str statename = condition.getParm(2);
if (currentState_Legs && !part.icmp("legs")) {
return (!statename.icmpn(currentState_Legs->getName(), statename.length()));
} else if (!part.icmp("torso")) {
return (!statename.icmpn(currentState_Torso->getName(), statename.length()));
}
2023-08-08 22:39:25 +02:00
return false;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondPush(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
// Check if the player is at a pushobject
if (atobject && atobject->isSubclassOf(PushObject) && (atobject_dist < (PUSH_OBJECT_DISTANCE + 15.0f))) {
Vector dir;
dir = atobject_dir * 8.0f;
return ((PushObject *)(Entity *)atobject)->canPush(dir);
}
return qfalse;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondPull(Conditional& condition)
{
// Check if the player is at a pushobject
if (atobject && atobject->isSubclassOf(PushObject) && (atobject_dist < (PUSH_OBJECT_DISTANCE + 15.0f))) {
Vector dir;
2023-08-08 22:39:25 +02:00
dir = atobject_dir * -64.0f;
return ((PushObject *)(Entity *)atobject)->canPush(dir);
}
return qfalse;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondLadder(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
trace_t trace;
Vector forward;
Vector start, end;
2023-08-08 22:39:25 +02:00
AngleVectors(m_vViewAng, forward, NULL, NULL);
2023-08-08 22:39:25 +02:00
start = (m_vViewPos - forward * 12.0f);
end = (m_vViewPos + forward * 128.0f);
trace = G_Trace(start, vec_zero, vec_zero, end, this, MASK_LADDER, qfalse, "checkladder");
if (trace.fraction == 1.0f || !trace.ent || !trace.ent->entity || !trace.ent->entity->isSubclassOf(FuncLadder)) {
return qfalse;
}
2023-08-08 22:39:25 +02:00
return ((FuncLadder *)trace.ent->entity)->CanUseLadder(this);
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondTopOfLadder(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
if (!m_pLadder) {
return false;
}
2023-08-08 22:39:25 +02:00
if (maxs[2] + origin[2] > m_pLadder->absmax[2]) {
return true;
}
2023-08-08 22:39:25 +02:00
return false;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondOnLadder(Conditional& condition)
{
return m_pLadder != NULL;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondCanClimbUpLadder(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
trace_t trace;
Vector fwd;
Vector vec;
Vector start, end;
2023-08-08 22:39:25 +02:00
AngleVectorsLeft(angles, fwd, NULL, NULL);
2023-08-08 22:39:25 +02:00
start = origin - fwd * 12.0f;
start[2] += maxs[2] - 8.0f;
2023-08-08 22:39:25 +02:00
end = start + fwd * 40.0f;
2023-08-08 22:39:25 +02:00
// check the normal bounding box first and trace to that position
trace = G_Trace(start, vec_zero, vec_zero, end, this, MASK_LADDER, qtrue, "Player::CondCanClimbUpLadder");
if ((trace.fraction == 1.0f) || (!trace.ent) || (!trace.ent->entity)
|| (!trace.ent->entity->isSubclassOf(FuncLadder))) {
return qfalse;
}
2023-08-08 22:39:25 +02:00
Vector vEnd = (origin + Vector(0, 0, 16));
return G_SightTrace(origin, mins, maxs, vEnd, this, NULL, MASK_BEAM, qtrue, "Player::CondCanClimbUpLadder");
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondCanClimbDownLadder(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
Vector vEnd = origin - Vector(0, 0, 16);
return G_SightTrace(origin, mins, maxs, vEnd, this, NULL, MASK_BEAM, qtrue, "Player::CondCanClimbDownLadder");
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondCanGetOffLadderTop(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
Vector vForward, vStart, vEnd;
trace_t trace;
2023-08-04 00:21:19 +02:00
2023-08-08 22:39:25 +02:00
angles.AngleVectorsLeft(&vForward);
2023-08-08 22:39:25 +02:00
vStart = origin - vForward * 12.0f;
vStart[2] += maxs[2] - 8.0f;
2023-08-08 22:39:25 +02:00
vEnd = vStart + vForward * 40.0f;
trace = G_Trace(vStart, vec_zero, vec_zero, vEnd, this, MASK_LADDER, qtrue, "Player::CondCanGetOffLadderTop 1");
if (trace.fraction >= 1.0f) {
vStart = origin;
vEnd = origin;
vEnd[2] += 98.0f;
if (G_SightTrace(vStart, mins, maxs, vEnd, this, NULL, MASK_BEAM, true, "Player::CondCanGetOffLadderTop 2")) {
vStart = vEnd;
vEnd = vStart + yaw_forward * 16.0f;
return G_SightTrace(
vStart, mins, maxs, vEnd, this, NULL, MASK_BEAM, true, "Player::CondCanGetOffLadderTop 3"
);
}
}
return false;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondCanGetOffLadderBottom(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
Vector vStart, vEnd;
trace_t trace;
vStart = origin;
vEnd = origin;
vEnd[2] -= 40.0f;
trace = G_Trace(vStart, mins, maxs, vEnd, edict, MASK_BEAM, true, "Player::CondCangetoffladerbottom");
if (trace.fraction != 1.0f) {
return (trace.entityNum == ENTITYNUM_WORLD);
}
return false;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondLookingUp(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
float angle = 0 - atof(condition.getParm(1));
return angle > m_vViewAng[0];
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondCanStand(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
Vector newmins(mins);
Vector newmaxs(maxs);
trace_t trace;
newmins[2] = MINS_Z;
newmaxs[2] = MAXS_Z;
trace = G_Trace(origin, newmins, newmaxs, origin, this, MASK_PLAYERSOLID, true, "checkcanstand");
if (trace.startsolid) {
return qfalse;
}
2023-08-08 22:39:25 +02:00
return qtrue;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondSolidForward(Conditional& condition)
{
// Trace out forward to see if there is a solid ahead
float dist = atof(condition.getParm(1));
Vector end(centroid + yaw_forward * dist);
Vector vMins(mins.x, mins.y, -8);
Vector vMaxs(maxs.x, maxs.y, 8);
trace_t trace = G_Trace(centroid, vMins, vMaxs, end, this, MASK_SOLID, true, "Player::CondSolidforward");
2023-08-08 22:39:25 +02:00
return (trace.fraction < 0.7f);
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondCheckHeight(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
str sHeight = condition.getParm(1);
float fHeight;
Vector newmaxs;
trace_t trace;
if (!sHeight.icmp("stand")) {
fHeight = 94.0f;
} else if (!sHeight.icmp("duckrun")) {
fHeight = 60.0f;
} else if (!sHeight.icmp("duck")) {
fHeight = 54.0f;
} else if (!sHeight.icmp("prone")) {
fHeight = 20.0f;
} else {
2023-08-08 22:39:25 +02:00
fHeight = atoi(sHeight.c_str());
}
2023-08-08 22:39:25 +02:00
if (fHeight < 16.0f) {
fHeight = 16.0f;
}
2023-08-08 22:39:25 +02:00
if (maxs[2] >= fHeight) {
return true;
} else {
2023-08-08 22:39:25 +02:00
newmaxs = maxs;
newmaxs[2] = fHeight;
trace = G_Trace(origin, mins, newmaxs, origin, edict, MASK_PLAYERSOLID, true, "Player::CondCheckHeight");
if (trace.startsolid) {
return false;
} else {
return true;
}
}
2023-08-08 22:39:25 +02:00
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondViewInWater(Conditional& condition)
{
2023-08-15 01:27:35 +02:00
return (gi.pointcontents(m_vViewPos, 0) & MASK_WATER) != 0;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondDuckedViewInWater(Conditional& condition)
{
Vector vPos = origin;
vPos[2] += 48.0f;
return (gi.pointcontents(vPos, 0) & MASK_WATER) != 0;
}
2023-08-08 22:39:25 +02:00
qboolean Player::CondCheckMovementSpeed(Conditional& condition)
{
weaponhand_t hand;
Weapon *weapon;
hand = WeaponHandNameToNum(condition.getParm(1));
if (hand == WEAPON_ERROR) {
return false;
}
weapon = GetActiveWeapon(hand);
if (!weapon) {
return false;
}
if (weapon->m_fMaxFireMovement == 1.f) {
return true;
}
return (velocity.length() / sv_runspeed->value) <= (weapon->m_fMaxFireMovement * weapon->m_fMovementSpeed + 0.1f);
2023-08-08 22:39:25 +02:00
}
qboolean Player::CondActionAnimDone(Conditional& condition)
{
2023-08-08 22:39:25 +02:00
// was removed in mohaas 2.0
return false;
}
qboolean Player::CondAnimDoneVM(Conditional& condition)
{
return animDoneVM;
}
qboolean Player::CondClientCommand(Conditional& condition)
{
str command = condition.getParm(1);
if (!command.icmp(m_lastcommand)) {
return qtrue;
} else {
return qfalse;
}
}
qboolean Player::CondVMAnim(Conditional& condition)
{
return condition.getParm(1) == m_sVMcurrent;
}
qboolean Player::CondVariable(Conditional& condition)
{
// parameters
str var_name;
str value_operator;
Player *player = (Player *)this;
// variables
int cmp_int = 0, var_int = 0;
float cmp_float = 0.0f, var_float = 0.0f;
char *cmp_str = NULL;
char *var_str = NULL;
ScriptVariableList *variableList = NULL;
ScriptVariable *variable = NULL;
char _operator[2];
size_t i, nLength;
size_t indexval = -1;
int founds = 0;
qboolean isString = qfalse, isFloat = qfalse, isInteger = qfalse;
var_name = condition.getParm(1);
value_operator = condition.getParm(2);
if (!var_name) {
gi.Printf("Var_CompareValue : the variable was not specified !\n", condition.getName());
return qfalse;
} else if (!value_operator) {
gi.Printf("Var_CompareValue : the value was not specified !\n", condition.getName());
return qfalse;
}
nLength = value_operator.length();
// Lookup for the operator, until we found one
for (i = 0; i < nLength; i++) {
if ((value_operator[i] == '<' && value_operator[i + 1] == '=')
|| (value_operator[i] == '>' && value_operator[i + 1] == '=')
|| (value_operator[i] == '=' && value_operator[i + 1] == '=')
|| (value_operator[i] == '!' && value_operator[i + 1] == '=') || value_operator[i] == '<'
|| value_operator[i] == '>' || value_operator[i] == '&') {
if (indexval == -1) {
indexval = i;
}
founds++;
}
}
// Fail if we didn't found/found multiples operators
if (!founds) {
gi.Printf(
"Var_CompareValue : unknown/no comparison/relational operator was specified (var_name=\"%s\"|value=\"%s\") "
"!\n",
var_name.c_str(),
value_operator.c_str()
);
return qfalse;
} else if (founds > 1) {
gi.Printf(
"Var_CompareValue : more than one operator was specified (var_name='%s'|value='%s') !\n",
var_name.c_str(),
value_operator.c_str()
);
return qfalse;
}
_operator[0] = value_operator[indexval];
_operator[1] = value_operator[indexval + 1];
// If this is not a greater/less than operator, then the loop
// shouldn't encounter a part of the operator
if ((_operator[0] == '<' && _operator[1] != '=') || (_operator[0] == '>' && _operator[1] != '=')) {
i = indexval;
} else {
i = indexval + 2;
}
while ((value_operator[i] == ' ' || value_operator[i] == '\0') && i < nLength) {
i++;
}
indexval = -1;
founds = 0;
// Loop until we find a character after the operator
for (; i < nLength; i++) {
if (value_operator[i] != '\0' && value_operator[i] != ' ' && value_operator[i] != _operator[0]
&& value_operator[i] != _operator[1]) {
if (indexval == -1) {
indexval = i;
}
founds++;
}
}
if (!founds) {
gi.Printf(
"Var_CompareValue : no value was specified after the operator ! (var_name=\"%s\") !\n", var_name.c_str()
);
return qfalse;
}
// Get the variable list from the player
variableList = this->Vars();
// Get the variable from the variable list
variable = variableList->GetVariable(var_name);
if (variable != NULL) {
isFloat = variable->GetType() == VARIABLE_FLOAT;
isInteger = variable->GetType() == VARIABLE_INTEGER;
isString = variable->GetType() == VARIABLE_STRING || variable->GetType() == VARIABLE_CONSTSTRING;
if (!isFloat && !isString && !isInteger) {
gi.Printf(
"Var_CompareValue : invalid type \"%s\" (%d) for variable \"%s\"\n",
typenames[variable->GetType()],
variable->GetType(),
var_name.c_str()
);
return qfalse;
}
// Retrieve the values from the variable
if (isFloat) {
var_float = variable->floatValue();
} else {
var_int = variable->intValue();
}
}
cmp_str = (char *)value_operator.c_str() + indexval;
if (!isString) {
cmp_int = atoi(cmp_str);
cmp_float = (float)atof(cmp_str);
}
// If this is a string, compare between the two strings
if (isString) {
if (_operator[0] == '=' && _operator[1] == '=') {
// == (EQUAL TO) operator
return strcmp(cmp_str, var_str) == 0;
} else if (_operator[0] == '!' && _operator[1] == '=') {
// != (NOT EQUAL TO) operator
return strcmp(cmp_str, var_str) != 0;
}
}
// Now compare between the two values with the right operator and return
if (_operator[0] == '<') {
// < (LESS THAN) operator
if (isFloat) {
return var_float < cmp_float;
}
return var_int < cmp_int;
} else if (_operator[0] == '>') {
// > (GREATER THAN) operator
if (isFloat) {
return var_float > cmp_float;
}
return var_int > cmp_int;
} else if (_operator[0] == '<' && _operator[1] == '=') {
// <= (LESS THAN OR EQUAL TO) operator
if (isFloat) {
return var_float <= cmp_float;
}
return var_int <= cmp_int;
} else if (_operator[0] == '>' && _operator[1] == '=') {
// >= (GREATER THAN OR EQUAL TO) operator
if (isFloat) {
return var_float >= cmp_float;
}
return var_int >= cmp_int;
} else if (_operator[0] == '!' && _operator[1] == '=') {
// != (NOT EQUAL TO) operator
if (isFloat) {
return var_float != cmp_float;
}
return var_int != cmp_int;
} else if (_operator[0] == '=' && _operator[1] == '=') {
// == (EQUAL TO) operator
if (isFloat) {
return var_float == cmp_float;
}
return var_int == cmp_int;
} else if (_operator[0] == '&') {
// & (BITWISE AND) operator
return var_int & cmp_int;
}
return qtrue;
}
CLASS_DECLARATION(Class, Conditional, NULL) {
{NULL, NULL}
};
2024-11-03 20:05:44 +01:00
Condition<Player> Player::m_conditions[] = {
2023-08-04 00:21:19 +02:00
{"default", &Player::CondTrue },
{"CHANCE", &Player::CondChance },
{"HEALTH", &Player::CondHealth },
{"BLOCKED", &Player::CondBlocked },
{"PAIN", &Player::CondPain },
{"ONGROUND", &Player::CondOnGround }, // Checks to see if the right attack button is pressed
{"HAS_WEAPON", &Player::CondHasWeapon },
{"NEW_WEAPON", &Player::CondNewWeapon },
{"IMMEDIATE_SWITCH", &Player::CondImmediateSwitch },
{"IS_NEW_WEAPON", &Player::CondUseWeapon },
{"IS_WEAPON_ACTIVE", &Player::CondWeaponActive },
2023-08-08 22:39:25 +02:00
{"WEAPON_CURRENT_FIRE_ANIM", &Player::CondWeaponCurrentFireAnim },
2023-08-04 00:21:19 +02:00
{"IS_WEAPON_READY_TO_FIRE", &Player::CondWeaponReadyToFire },
{"IS_WEAPON_READY_TO_FIRE_NOSOUND", &Player::CondWeaponReadyToFireNoSound},
{"PUTAWAYMAIN", &Player::CondPutAwayMain },
{"PUTAWAYLEFT", &Player::CondPutAwayOffHand },
{"ANY_WEAPON_ACTIVE", &Player::CondAnyWeaponActive },
{"ATTACK_BLOCKED", &Player::CondAttackBlocked },
{"IS_WEAPON_SEMIAUTO", &Player::CondSemiAuto },
{"MIN_CHARGE_TIME_MET", &Player::CondMinChargeTime },
{"MAX_CHARGE_TIME_MET", &Player::CondMaxChargeTime },
{"IS_NEW_WEAPONCLASS", &Player::CondUseWeaponClass },
{"IS_WEAPONCLASS_ACTIVE", &Player::CondWeaponClassActive },
{"IS_WEAPONCLASS_READY_TO_FIRE", &Player::CondWeaponClassReadyToFire },
{"IS_USING_VEHICLE", &Player::CondUsingVehicle },
{"VEHICLE_TYPE", &Player::CondVehicleType },
{"IS_PASSENGER", &Player::CondIsPassenger },
{"IS_DRIVER", &Player::CondIsDriver },
{"IS_USING_TURRET", &Player::CondUsingTurret },
{"TURRET_TYPE", &Player::CondTurretType },
{"BLOCK_DELAY", &Player::CondBlockDelay },
{"MUZZLE_CLEAR", &Player::CondMuzzleClear },
{"HAS_AMMO", &Player::CondWeaponHasAmmo },
{"HAS_AMMO_IN_CLIP", &Player::CondWeaponHasAmmoInClip },
{"RELOAD", &Player::CondReload },
{"WEAPONS_HOLSTERED", &Player::CondWeaponsHolstered },
{"IS_WEAPON_AN_ITEM", &Player::CondWeaponIsItem },
{"NEW_WEAPON_AN_ITEM", &Player::CondNewWeaponIsItem },
{"POSITION_TYPE", &Player::CondPositionType },
{"MOVEMENT_TYPE", &Player::CondMovementType },
{"RUN", &Player::CondRun },
{"USE", &Player::CondUse },
{"LEFT", &Player::CondTurnLeft },
{"RIGHT", &Player::CondTurnRight },
{"FORWARD", &Player::CondForward },
{"BACKWARD", &Player::CondBackward },
{"STRAFE_LEFT", &Player::CondStrafeLeft },
{"STRAFE_RIGHT", &Player::CondStrafeRight },
{"JUMP", &Player::CondJump },
{"CROUCH", &Player::CondCrouch },
{"DO_JUMP_FLIP", &Player::CondJumpFlip },
{"ANIMDONE_LEGS", &Player::CondAnimDoneLegs },
{"ANIMDONE_TORSO", &Player::CondAnimDoneTorso },
{"CAN_TURN", &Player::CondCanTurn },
{"LEFT_VELOCITY", &Player::CondLeftVelocity },
{"RIGHT_VELOCITY", &Player::CondRightVelocity },
{"BACKWARD_VELOCITY", &Player::CondBackwardVelocity },
{"FORWARD_VELOCITY", &Player::CondForwardVelocity },
{"UP_VELOCITY", &Player::CondUpVelocity },
{"DOWN_VELOCITY", &Player::CondDownVelocity },
{"HAS_VELOCITY", &Player::CondHasVelocity },
{"SLOPE_22", &Player::Cond22DegreeSlope },
{"SLOPE_45", &Player::Cond45DegreeSlope },
{"LOOKING_UP", &Player::CondLookingUp },
{"RIGHT_LEG_HIGH", &Player::CondRightLegHigh },
{"LEFT_LEG_HIGH", &Player::CondLeftLegHigh },
{"CAN_FALL", &Player::CondCanFall },
{"AT_DOOR", &Player::CondAtDoor },
{"FALLING", &Player::CondFalling },
{"MEDIUM_IMPACT", &Player::CondMediumImpact },
{"HARD_IMPACT", &Player::CondHardImpact },
{"KILLED", &Player::CondDead },
{"PAIN_TYPE", &Player::CondPainType },
{"PAIN_DIRECTION", &Player::CondPainDirection },
{"PAIN_LOCATION", &Player::CondPainLocation },
{"PAIN_THRESHOLD", &Player::CondPainThreshold },
{"KNOCKDOWN", &Player::CondKnockDown },
{"LEGS", &Player::CondLegsState },
{"TORSO", &Player::CondTorsoState },
{"AT_USEANIM", &Player::CondAtUseAnim },
{"TOUCHEDUSEANIM", &Player::CondTouchUseAnim },
{"FINISHEDUSEANIM", &Player::CondUseAnimFinished },
{"AT_USEOBJECT", &Player::CondAtUseObject },
{"LOOP_USEOBJECT", &Player::CondLoopUseObject },
{"CAN_PUSH", &Player::CondPush },
{"CAN_PULL", &Player::CondPull },
{"AT_LADDER", &Player::CondLadder },
{"AT_TOP_OF_LADDER", &Player::CondTopOfLadder },
{"ON_LADDER", &Player::CondOnLadder },
{"CAN_CLIMB_UP_LADDER", &Player::CondCanClimbUpLadder },
{"CAN_CLIMB_DOWN_LADDER", &Player::CondCanClimbDownLadder },
{"CAN_GET_OFF_LADDER_TOP", &Player::CondCanGetOffLadderTop },
{"CAN_GET_OFF_LADDER_BOTTOM", &Player::CondCanGetOffLadderBottom },
{"CAN_STAND", &Player::CondCanStand },
{"FACING_UP_SLOPE", &Player::CondFacingUpSlope },
{"FACING_DOWN_SLOPE", &Player::CondFacingDownSlope },
{"SOLID_FORWARD", &Player::CondSolidForward },
{"STATE_ACTIVE", &Player::CondStateName },
{"GROUNDENTITY", &Player::CondGroundEntity },
{"CHECK_HEIGHT", &Player::CondCheckHeight },
{"VIEW_IN_WATER", &Player::CondViewInWater },
{"DUCKED_VIEW_IN_WATER", &Player::CondDuckedViewInWater },
2023-08-08 22:39:25 +02:00
{"IS_ESCAPING", &Player::CondIsEscaping },
{"IS_ASSISTING_ESCAPE", &Player::CondIsAssistingEscape },
{"NEAR_LANDMINE", &Player::CondNearLandmine },
{"ON_LANDMINE", &Player::CondOnLandmine },
{"ABLE_TO_DEFUSE", &Player::CondAbleToDefuse },
{"CAN_PLACE_LANDMINE", &Player::CondCanPlaceLandmine },
2023-08-04 00:21:19 +02:00
{"IS_USING_TURRET", &Player::CondUsingTurret },
{"ATTACK_PRIMARY", &Player::CondAttackPrimary
}, // Checks to see if there is an active weapon as well as the button being pressed
{"ATTACK_SECONDARY", &Player::CondAttackSecondary
}, // Checks to see if there is an active weapon as well as the button being pressed
2023-08-04 00:21:19 +02:00
{"ATTACK_PRIMARY_BUTTON", &Player::CondAttackButtonPrimary }, // Checks to see if the left attack button is pressed
{"ATTACK_SECONDARY_BUTTON", &Player::CondAttackButtonSecondary },
2023-08-08 22:39:25 +02:00
{"CHECK_MOVEMENT_SPEED", &Player::CondCheckMovementSpeed },
// Weapon conditions
2023-08-04 00:21:19 +02:00
{"ANIMDONE_VM", &Player::CondAnimDoneVM },
{"CLIENT_COMMAND", &Player::CondClientCommand },
{"IS_VM_ANIM", &Player::CondVMAnim },
{"VAR_OPERATOR", &Player::CondVariable },
{NULL, NULL },
};