halflife-photomode/dlls/maprules.cpp

922 lines
20 KiB
C++
Raw Normal View History

/***
2013-08-30 13:34:05 -07:00
*
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
// -------------------------------------------
//
// maprules.cpp
//
// This module contains entities for implementing/changing game
// rules dynamically within each map (.BSP)
//
// -------------------------------------------
#include "extdll.h"
#include "eiface.h"
#include "util.h"
#include "gamerules.h"
#include "maprules.h"
#include "cbase.h"
#include "player.h"
class CRuleEntity : public CBaseEntity
{
public:
void Spawn() override;
bool KeyValue(KeyValueData* pkvd) override;
bool Save(CSave& save) override;
bool Restore(CRestore& restore) override;
static TYPEDESCRIPTION m_SaveData[];
2013-08-30 13:34:05 -07:00
void SetMaster(int iszMaster) { m_iszMaster = iszMaster; }
2013-08-30 13:34:05 -07:00
protected:
bool CanFireForActivator(CBaseEntity* pActivator);
2013-08-30 13:34:05 -07:00
private:
string_t m_iszMaster;
2013-08-30 13:34:05 -07:00
};
TYPEDESCRIPTION CRuleEntity::m_SaveData[] =
{
DEFINE_FIELD(CRuleEntity, m_iszMaster, FIELD_STRING),
2013-08-30 13:34:05 -07:00
};
IMPLEMENT_SAVERESTORE(CRuleEntity, CBaseEntity);
2013-08-30 13:34:05 -07:00
void CRuleEntity::Spawn()
2013-08-30 13:34:05 -07:00
{
pev->solid = SOLID_NOT;
pev->movetype = MOVETYPE_NONE;
pev->effects = EF_NODRAW;
2013-08-30 13:34:05 -07:00
}
bool CRuleEntity::KeyValue(KeyValueData* pkvd)
2013-08-30 13:34:05 -07:00
{
if (FStrEq(pkvd->szKeyName, "master"))
{
SetMaster(ALLOC_STRING(pkvd->szValue));
return true;
2013-08-30 13:34:05 -07:00
}
return CBaseEntity::KeyValue(pkvd);
2013-08-30 13:34:05 -07:00
}
bool CRuleEntity::CanFireForActivator(CBaseEntity* pActivator)
2013-08-30 13:34:05 -07:00
{
if (!FStringNull(m_iszMaster))
2013-08-30 13:34:05 -07:00
{
return UTIL_IsMasterTriggered(m_iszMaster, pActivator);
2013-08-30 13:34:05 -07:00
}
2021-11-19 13:45:16 +01:00
return true;
2013-08-30 13:34:05 -07:00
}
//
2013-08-30 13:34:05 -07:00
// CRulePointEntity -- base class for all rule "point" entities (not brushes)
//
class CRulePointEntity : public CRuleEntity
{
public:
void Spawn() override;
2013-08-30 13:34:05 -07:00
};
void CRulePointEntity::Spawn()
2013-08-30 13:34:05 -07:00
{
CRuleEntity::Spawn();
pev->frame = 0;
pev->model = 0;
2013-08-30 13:34:05 -07:00
}
//
2013-08-30 13:34:05 -07:00
// CRuleBrushEntity -- base class for all rule "brush" entities (not brushes)
// Default behavior is to set up like a trigger, invisible, but keep the model for volume testing
//
class CRuleBrushEntity : public CRuleEntity
{
public:
void Spawn() override;
2013-08-30 13:34:05 -07:00
private:
};
void CRuleBrushEntity::Spawn()
2013-08-30 13:34:05 -07:00
{
SET_MODEL(edict(), STRING(pev->model));
2013-08-30 13:34:05 -07:00
CRuleEntity::Spawn();
}
// CGameScore / game_score -- award points to player / team
2013-08-30 13:34:05 -07:00
// Points +/- total
// Flag: Allow negative scores SF_SCORE_NEGATIVE
// Flag: Award points to team in teamplay SF_SCORE_TEAM
#define SF_SCORE_NEGATIVE 0x0001
#define SF_SCORE_TEAM 0x0002
2013-08-30 13:34:05 -07:00
class CGameScore : public CRulePointEntity
{
public:
void Spawn() override;
void Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value) override;
bool KeyValue(KeyValueData* pkvd) override;
2013-08-30 13:34:05 -07:00
inline int Points() { return pev->frags; }
inline bool AllowNegativeScore() { return (pev->spawnflags & SF_SCORE_NEGATIVE) != 0; }
inline bool AwardToTeam() { return (pev->spawnflags & SF_SCORE_TEAM) != 0; }
2013-08-30 13:34:05 -07:00
inline void SetPoints(int points) { pev->frags = points; }
2013-08-30 13:34:05 -07:00
private:
};
LINK_ENTITY_TO_CLASS(game_score, CGameScore);
2013-08-30 13:34:05 -07:00
void CGameScore::Spawn()
2013-08-30 13:34:05 -07:00
{
CRulePointEntity::Spawn();
}
bool CGameScore::KeyValue(KeyValueData* pkvd)
2013-08-30 13:34:05 -07:00
{
if (FStrEq(pkvd->szKeyName, "points"))
{
SetPoints(atoi(pkvd->szValue));
return true;
2013-08-30 13:34:05 -07:00
}
return CRulePointEntity::KeyValue(pkvd);
2013-08-30 13:34:05 -07:00
}
void CGameScore::Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value)
2013-08-30 13:34:05 -07:00
{
if (!CanFireForActivator(pActivator))
2013-08-30 13:34:05 -07:00
return;
// Only players can use this
if (pActivator->IsPlayer())
2013-08-30 13:34:05 -07:00
{
if (AwardToTeam())
2013-08-30 13:34:05 -07:00
{
pActivator->AddPointsToTeam(Points(), AllowNegativeScore());
2013-08-30 13:34:05 -07:00
}
else
{
pActivator->AddPoints(Points(), AllowNegativeScore());
2013-08-30 13:34:05 -07:00
}
}
}
// CGameEnd / game_end -- Ends the game in MP
class CGameEnd : public CRulePointEntity
{
public:
void Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value) override;
2013-08-30 13:34:05 -07:00
private:
};
LINK_ENTITY_TO_CLASS(game_end, CGameEnd);
2013-08-30 13:34:05 -07:00
void CGameEnd::Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value)
2013-08-30 13:34:05 -07:00
{
if (!CanFireForActivator(pActivator))
2013-08-30 13:34:05 -07:00
return;
g_pGameRules->EndMultiplayerGame();
}
//
// CGameText / game_text -- NON-Localized HUD Message (use env_message to display a titles.txt message)
// Flag: All players SF_ENVTEXT_ALLPLAYERS
//
#define SF_ENVTEXT_ALLPLAYERS 0x0001
2013-08-30 13:34:05 -07:00
class CGameText : public CRulePointEntity
{
public:
void Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value) override;
bool KeyValue(KeyValueData* pkvd) override;
2013-08-30 13:34:05 -07:00
bool Save(CSave& save) override;
bool Restore(CRestore& restore) override;
static TYPEDESCRIPTION m_SaveData[];
2013-08-30 13:34:05 -07:00
inline bool MessageToAll() { return (pev->spawnflags & SF_ENVTEXT_ALLPLAYERS) != 0; }
inline void MessageSet(const char* pMessage) { pev->message = ALLOC_STRING(pMessage); }
inline const char* MessageGet() { return STRING(pev->message); }
2013-08-30 13:34:05 -07:00
private:
hudtextparms_t m_textParms;
2013-08-30 13:34:05 -07:00
};
LINK_ENTITY_TO_CLASS(game_text, CGameText);
2013-08-30 13:34:05 -07:00
// Save parms as a block. Will break save/restore if the structure changes, but this entity didn't ship with Half-Life, so
// it can't impact saved Half-Life games.
TYPEDESCRIPTION CGameText::m_SaveData[] =
{
DEFINE_ARRAY(CGameText, m_textParms, FIELD_CHARACTER, sizeof(hudtextparms_t)),
2013-08-30 13:34:05 -07:00
};
IMPLEMENT_SAVERESTORE(CGameText, CRulePointEntity);
2013-08-30 13:34:05 -07:00
bool CGameText::KeyValue(KeyValueData* pkvd)
2013-08-30 13:34:05 -07:00
{
if (FStrEq(pkvd->szKeyName, "channel"))
{
m_textParms.channel = atoi(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "x"))
{
m_textParms.x = atof(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "y"))
{
m_textParms.y = atof(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "effect"))
{
m_textParms.effect = atoi(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "color"))
{
int color[4];
UTIL_StringToIntArray(color, 4, pkvd->szValue);
2013-08-30 13:34:05 -07:00
m_textParms.r1 = color[0];
m_textParms.g1 = color[1];
m_textParms.b1 = color[2];
m_textParms.a1 = color[3];
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "color2"))
{
int color[4];
UTIL_StringToIntArray(color, 4, pkvd->szValue);
2013-08-30 13:34:05 -07:00
m_textParms.r2 = color[0];
m_textParms.g2 = color[1];
m_textParms.b2 = color[2];
m_textParms.a2 = color[3];
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "fadein"))
{
m_textParms.fadeinTime = atof(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "fadeout"))
{
m_textParms.fadeoutTime = atof(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "holdtime"))
{
m_textParms.holdTime = atof(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "fxtime"))
{
m_textParms.fxTime = atof(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
return CRulePointEntity::KeyValue(pkvd);
2013-08-30 13:34:05 -07:00
}
void CGameText::Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value)
2013-08-30 13:34:05 -07:00
{
if (!CanFireForActivator(pActivator))
2013-08-30 13:34:05 -07:00
return;
if (MessageToAll())
2013-08-30 13:34:05 -07:00
{
UTIL_HudMessageAll(m_textParms, MessageGet());
2013-08-30 13:34:05 -07:00
}
else
{
if (pActivator->IsNetClient())
2013-08-30 13:34:05 -07:00
{
UTIL_HudMessage(pActivator, m_textParms, MessageGet());
2013-08-30 13:34:05 -07:00
}
}
}
//
// CGameTeamMaster / game_team_master -- "Masters" like multisource, but based on the team of the activator
// Only allows mastered entity to fire if the team matches my team
//
// team index (pulled from server team list "mp_teamlist"
// Flag: Remove on Fire
// Flag: Any team until set? -- Any team can use this until the team is set (otherwise no teams can use it)
//
#define SF_TEAMMASTER_FIREONCE 0x0001
#define SF_TEAMMASTER_ANYTEAM 0x0002
2013-08-30 13:34:05 -07:00
class CGameTeamMaster : public CRulePointEntity
{
public:
bool KeyValue(KeyValueData* pkvd) override;
void Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value) override;
int ObjectCaps() override { return CRulePointEntity::ObjectCaps() | FCAP_MASTER; }
2013-08-30 13:34:05 -07:00
bool IsTriggered(CBaseEntity* pActivator) override;
const char* TeamID() override;
inline bool RemoveOnFire() { return (pev->spawnflags & SF_TEAMMASTER_FIREONCE) != 0; }
inline bool AnyTeam() { return (pev->spawnflags & SF_TEAMMASTER_ANYTEAM) != 0; }
2013-08-30 13:34:05 -07:00
private:
bool TeamMatch(CBaseEntity* pActivator);
2013-08-30 13:34:05 -07:00
int m_teamIndex;
USE_TYPE triggerType;
2013-08-30 13:34:05 -07:00
};
LINK_ENTITY_TO_CLASS(game_team_master, CGameTeamMaster);
2013-08-30 13:34:05 -07:00
bool CGameTeamMaster::KeyValue(KeyValueData* pkvd)
2013-08-30 13:34:05 -07:00
{
if (FStrEq(pkvd->szKeyName, "teamindex"))
{
m_teamIndex = atoi(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "triggerstate"))
{
int type = atoi(pkvd->szValue);
switch (type)
2013-08-30 13:34:05 -07:00
{
case 0:
triggerType = USE_OFF;
break;
case 2:
triggerType = USE_TOGGLE;
break;
default:
triggerType = USE_ON;
break;
}
return true;
2013-08-30 13:34:05 -07:00
}
return CRulePointEntity::KeyValue(pkvd);
2013-08-30 13:34:05 -07:00
}
void CGameTeamMaster::Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value)
2013-08-30 13:34:05 -07:00
{
if (!CanFireForActivator(pActivator))
2013-08-30 13:34:05 -07:00
return;
if (useType == USE_SET)
2013-08-30 13:34:05 -07:00
{
if (value < 0)
2013-08-30 13:34:05 -07:00
{
m_teamIndex = -1;
}
else
{
m_teamIndex = g_pGameRules->GetTeamIndex(pActivator->TeamID());
2013-08-30 13:34:05 -07:00
}
return;
}
if (TeamMatch(pActivator))
2013-08-30 13:34:05 -07:00
{
SUB_UseTargets(pActivator, triggerType, value);
if (RemoveOnFire())
UTIL_Remove(this);
2013-08-30 13:34:05 -07:00
}
}
bool CGameTeamMaster::IsTriggered(CBaseEntity* pActivator)
2013-08-30 13:34:05 -07:00
{
return TeamMatch(pActivator);
2013-08-30 13:34:05 -07:00
}
const char* CGameTeamMaster::TeamID()
2013-08-30 13:34:05 -07:00
{
if (m_teamIndex < 0) // Currently set to "no team"
2013-08-30 13:34:05 -07:00
return "";
return g_pGameRules->GetIndexedTeamName(m_teamIndex); // UNDONE: Fill this in with the team from the "teamlist"
2013-08-30 13:34:05 -07:00
}
bool CGameTeamMaster::TeamMatch(CBaseEntity* pActivator)
2013-08-30 13:34:05 -07:00
{
if (m_teamIndex < 0 && AnyTeam())
2021-11-19 13:45:16 +01:00
return true;
2013-08-30 13:34:05 -07:00
if (!pActivator)
2021-11-19 13:43:33 +01:00
return false;
2013-08-30 13:34:05 -07:00
return UTIL_TeamsMatch(pActivator->TeamID(), TeamID());
2013-08-30 13:34:05 -07:00
}
//
// CGameTeamSet / game_team_set -- Changes the team of the entity it targets to the activator's team
// Flag: Fire once
// Flag: Clear team -- Sets the team to "NONE" instead of activator
#define SF_TEAMSET_FIREONCE 0x0001
#define SF_TEAMSET_CLEARTEAM 0x0002
2013-08-30 13:34:05 -07:00
class CGameTeamSet : public CRulePointEntity
{
public:
void Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value) override;
inline bool RemoveOnFire() { return (pev->spawnflags & SF_TEAMSET_FIREONCE) != 0; }
inline bool ShouldClearTeam() { return (pev->spawnflags & SF_TEAMSET_CLEARTEAM) != 0; }
2013-08-30 13:34:05 -07:00
private:
};
LINK_ENTITY_TO_CLASS(game_team_set, CGameTeamSet);
2013-08-30 13:34:05 -07:00
void CGameTeamSet::Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value)
2013-08-30 13:34:05 -07:00
{
if (!CanFireForActivator(pActivator))
2013-08-30 13:34:05 -07:00
return;
if (ShouldClearTeam())
2013-08-30 13:34:05 -07:00
{
SUB_UseTargets(pActivator, USE_SET, -1);
2013-08-30 13:34:05 -07:00
}
else
{
SUB_UseTargets(pActivator, USE_SET, 0);
2013-08-30 13:34:05 -07:00
}
if (RemoveOnFire())
2013-08-30 13:34:05 -07:00
{
UTIL_Remove(this);
2013-08-30 13:34:05 -07:00
}
}
//
// CGamePlayerZone / game_player_zone -- players in the zone fire my target when I'm fired
//
// Needs master?
class CGamePlayerZone : public CRuleBrushEntity
{
public:
bool KeyValue(KeyValueData* pkvd) override;
void Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value) override;
2013-08-30 13:34:05 -07:00
bool Save(CSave& save) override;
bool Restore(CRestore& restore) override;
static TYPEDESCRIPTION m_SaveData[];
2013-08-30 13:34:05 -07:00
private:
string_t m_iszInTarget;
string_t m_iszOutTarget;
string_t m_iszInCount;
string_t m_iszOutCount;
2013-08-30 13:34:05 -07:00
};
LINK_ENTITY_TO_CLASS(game_zone_player, CGamePlayerZone);
TYPEDESCRIPTION CGamePlayerZone::m_SaveData[] =
{
DEFINE_FIELD(CGamePlayerZone, m_iszInTarget, FIELD_STRING),
DEFINE_FIELD(CGamePlayerZone, m_iszOutTarget, FIELD_STRING),
DEFINE_FIELD(CGamePlayerZone, m_iszInCount, FIELD_STRING),
DEFINE_FIELD(CGamePlayerZone, m_iszOutCount, FIELD_STRING),
2013-08-30 13:34:05 -07:00
};
IMPLEMENT_SAVERESTORE(CGamePlayerZone, CRuleBrushEntity);
2013-08-30 13:34:05 -07:00
bool CGamePlayerZone::KeyValue(KeyValueData* pkvd)
2013-08-30 13:34:05 -07:00
{
if (FStrEq(pkvd->szKeyName, "intarget"))
{
m_iszInTarget = ALLOC_STRING(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "outtarget"))
{
m_iszOutTarget = ALLOC_STRING(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "incount"))
{
m_iszInCount = ALLOC_STRING(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "outcount"))
{
m_iszOutCount = ALLOC_STRING(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
return CRuleBrushEntity::KeyValue(pkvd);
2013-08-30 13:34:05 -07:00
}
void CGamePlayerZone::Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value)
2013-08-30 13:34:05 -07:00
{
int playersInCount = 0;
int playersOutCount = 0;
if (!CanFireForActivator(pActivator))
2013-08-30 13:34:05 -07:00
return;
CBaseEntity* pPlayer = NULL;
2013-08-30 13:34:05 -07:00
for (int i = 1; i <= gpGlobals->maxClients; i++)
2013-08-30 13:34:05 -07:00
{
pPlayer = UTIL_PlayerByIndex(i);
if (pPlayer)
2013-08-30 13:34:05 -07:00
{
TraceResult trace;
int hullNumber;
2013-08-30 13:34:05 -07:00
hullNumber = human_hull;
if ((pPlayer->pev->flags & FL_DUCKING) != 0)
2013-08-30 13:34:05 -07:00
{
hullNumber = head_hull;
}
UTIL_TraceModel(pPlayer->pev->origin, pPlayer->pev->origin, hullNumber, edict(), &trace);
2013-08-30 13:34:05 -07:00
if (0 != trace.fStartSolid)
2013-08-30 13:34:05 -07:00
{
playersInCount++;
if (!FStringNull(m_iszInTarget))
2013-08-30 13:34:05 -07:00
{
FireTargets(STRING(m_iszInTarget), pPlayer, pActivator, useType, value);
2013-08-30 13:34:05 -07:00
}
}
else
{
playersOutCount++;
if (!FStringNull(m_iszOutTarget))
2013-08-30 13:34:05 -07:00
{
FireTargets(STRING(m_iszOutTarget), pPlayer, pActivator, useType, value);
2013-08-30 13:34:05 -07:00
}
}
}
}
if (!FStringNull(m_iszInCount))
2013-08-30 13:34:05 -07:00
{
FireTargets(STRING(m_iszInCount), pActivator, this, USE_SET, playersInCount);
2013-08-30 13:34:05 -07:00
}
if (!FStringNull(m_iszOutCount))
2013-08-30 13:34:05 -07:00
{
FireTargets(STRING(m_iszOutCount), pActivator, this, USE_SET, playersOutCount);
2013-08-30 13:34:05 -07:00
}
}
//
// CGamePlayerHurt / game_player_hurt -- Damages the player who fires it
// Flag: Fire once
#define SF_PKILL_FIREONCE 0x0001
2013-08-30 13:34:05 -07:00
class CGamePlayerHurt : public CRulePointEntity
{
public:
void Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value) override;
inline bool RemoveOnFire() { return (pev->spawnflags & SF_PKILL_FIREONCE) != 0; }
2013-08-30 13:34:05 -07:00
private:
};
LINK_ENTITY_TO_CLASS(game_player_hurt, CGamePlayerHurt);
2013-08-30 13:34:05 -07:00
void CGamePlayerHurt::Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value)
2013-08-30 13:34:05 -07:00
{
if (!CanFireForActivator(pActivator))
2013-08-30 13:34:05 -07:00
return;
if (pActivator->IsPlayer())
2013-08-30 13:34:05 -07:00
{
if (pev->dmg < 0)
pActivator->TakeHealth(-pev->dmg, DMG_GENERIC);
2013-08-30 13:34:05 -07:00
else
pActivator->TakeDamage(pev, pev, pev->dmg, DMG_GENERIC);
2013-08-30 13:34:05 -07:00
}
SUB_UseTargets(pActivator, useType, value);
if (RemoveOnFire())
2013-08-30 13:34:05 -07:00
{
UTIL_Remove(this);
2013-08-30 13:34:05 -07:00
}
}
//
// CGameCounter / game_counter -- Counts events and fires target
// Flag: Fire once
// Flag: Reset on Fire
#define SF_GAMECOUNT_FIREONCE 0x0001
#define SF_GAMECOUNT_RESET 0x0002
2013-08-30 13:34:05 -07:00
class CGameCounter : public CRulePointEntity
{
public:
void Spawn() override;
void Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value) override;
inline bool RemoveOnFire() { return (pev->spawnflags & SF_GAMECOUNT_FIREONCE) != 0; }
inline bool ResetOnFire() { return (pev->spawnflags & SF_GAMECOUNT_RESET) != 0; }
inline void CountUp() { pev->frags++; }
inline void CountDown() { pev->frags--; }
inline void ResetCount() { pev->frags = pev->dmg; }
inline int CountValue() { return pev->frags; }
inline int LimitValue() { return pev->health; }
inline bool HitLimit() { return CountValue() == LimitValue(); }
2013-08-30 13:34:05 -07:00
private:
inline void SetCountValue(int value) { pev->frags = value; }
inline void SetInitialValue(int value) { pev->dmg = value; }
2013-08-30 13:34:05 -07:00
};
LINK_ENTITY_TO_CLASS(game_counter, CGameCounter);
2013-08-30 13:34:05 -07:00
void CGameCounter::Spawn()
2013-08-30 13:34:05 -07:00
{
// Save off the initial count
SetInitialValue(CountValue());
2013-08-30 13:34:05 -07:00
CRulePointEntity::Spawn();
}
void CGameCounter::Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value)
2013-08-30 13:34:05 -07:00
{
if (!CanFireForActivator(pActivator))
2013-08-30 13:34:05 -07:00
return;
switch (useType)
2013-08-30 13:34:05 -07:00
{
case USE_ON:
case USE_TOGGLE:
CountUp();
break;
2013-08-30 13:34:05 -07:00
case USE_OFF:
CountDown();
break;
case USE_SET:
SetCountValue((int)value);
2013-08-30 13:34:05 -07:00
break;
}
if (HitLimit())
2013-08-30 13:34:05 -07:00
{
SUB_UseTargets(pActivator, USE_TOGGLE, 0);
if (RemoveOnFire())
2013-08-30 13:34:05 -07:00
{
UTIL_Remove(this);
2013-08-30 13:34:05 -07:00
}
if (ResetOnFire())
2013-08-30 13:34:05 -07:00
{
ResetCount();
}
}
}
//
// CGameCounterSet / game_counter_set -- Sets the counter's value
// Flag: Fire once
#define SF_GAMECOUNTSET_FIREONCE 0x0001
2013-08-30 13:34:05 -07:00
class CGameCounterSet : public CRulePointEntity
{
public:
void Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value) override;
inline bool RemoveOnFire() { return (pev->spawnflags & SF_GAMECOUNTSET_FIREONCE) != 0; }
2013-08-30 13:34:05 -07:00
private:
};
LINK_ENTITY_TO_CLASS(game_counter_set, CGameCounterSet);
2013-08-30 13:34:05 -07:00
void CGameCounterSet::Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value)
2013-08-30 13:34:05 -07:00
{
if (!CanFireForActivator(pActivator))
2013-08-30 13:34:05 -07:00
return;
SUB_UseTargets(pActivator, USE_SET, pev->frags);
2013-08-30 13:34:05 -07:00
if (RemoveOnFire())
2013-08-30 13:34:05 -07:00
{
UTIL_Remove(this);
2013-08-30 13:34:05 -07:00
}
}
//
// CGamePlayerEquip / game_playerequip -- Sets the default player equipment
// Flag: USE Only
#define SF_PLAYEREQUIP_USEONLY 0x0001
#define MAX_EQUIP 32
2013-08-30 13:34:05 -07:00
class CGamePlayerEquip : public CRulePointEntity
{
public:
bool KeyValue(KeyValueData* pkvd) override;
void Touch(CBaseEntity* pOther) override;
void Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value) override;
2013-08-30 13:34:05 -07:00
inline bool UseOnly() { return (pev->spawnflags & SF_PLAYEREQUIP_USEONLY) != 0; }
2013-08-30 13:34:05 -07:00
bool Save(CSave& save) override;
bool Restore(CRestore& restore) override;
static TYPEDESCRIPTION m_SaveData[];
2013-08-30 13:34:05 -07:00
private:
void EquipPlayer(CBaseEntity* pPlayer);
2013-08-30 13:34:05 -07:00
string_t m_weaponNames[MAX_EQUIP];
int m_weaponCount[MAX_EQUIP];
2013-08-30 13:34:05 -07:00
};
TYPEDESCRIPTION CGamePlayerEquip::m_SaveData[] =
{
DEFINE_ARRAY(CGamePlayerEquip, m_weaponNames, FIELD_STRING, MAX_EQUIP),
DEFINE_ARRAY(CGamePlayerEquip, m_weaponCount, FIELD_INTEGER, MAX_EQUIP),
};
IMPLEMENT_SAVERESTORE(CGamePlayerEquip, CRulePointEntity);
LINK_ENTITY_TO_CLASS(game_player_equip, CGamePlayerEquip);
2013-08-30 13:34:05 -07:00
bool CGamePlayerEquip::KeyValue(KeyValueData* pkvd)
2013-08-30 13:34:05 -07:00
{
if (CRulePointEntity::KeyValue(pkvd))
{
return true;
}
2013-08-30 13:34:05 -07:00
for (int i = 0; i < MAX_EQUIP; i++)
2013-08-30 13:34:05 -07:00
{
if (FStringNull(m_weaponNames[i]))
2013-08-30 13:34:05 -07:00
{
char tmp[128];
2013-08-30 13:34:05 -07:00
UTIL_StripToken(pkvd->szKeyName, tmp, sizeof(tmp));
2013-08-30 13:34:05 -07:00
m_weaponNames[i] = ALLOC_STRING(tmp);
m_weaponCount[i] = atoi(pkvd->szValue);
m_weaponCount[i] = V_max(1, m_weaponCount[i]);
return true;
2013-08-30 13:34:05 -07:00
}
}
return false;
2013-08-30 13:34:05 -07:00
}
void CGamePlayerEquip::Touch(CBaseEntity* pOther)
2013-08-30 13:34:05 -07:00
{
if (!CanFireForActivator(pOther))
2013-08-30 13:34:05 -07:00
return;
if (UseOnly())
2013-08-30 13:34:05 -07:00
return;
EquipPlayer(pOther);
2013-08-30 13:34:05 -07:00
}
void CGamePlayerEquip::EquipPlayer(CBaseEntity* pEntity)
2013-08-30 13:34:05 -07:00
{
if (!pEntity || !pEntity->IsPlayer())
2013-08-30 13:34:05 -07:00
{
return;
2013-08-30 13:34:05 -07:00
}
CBasePlayer* pPlayer = (CBasePlayer*)pEntity;
2013-08-30 13:34:05 -07:00
for (int i = 0; i < MAX_EQUIP; i++)
2013-08-30 13:34:05 -07:00
{
if (FStringNull(m_weaponNames[i]))
2013-08-30 13:34:05 -07:00
break;
for (int j = 0; j < m_weaponCount[i]; j++)
2013-08-30 13:34:05 -07:00
{
pPlayer->GiveNamedItem(STRING(m_weaponNames[i]));
2013-08-30 13:34:05 -07:00
}
}
}
void CGamePlayerEquip::Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value)
2013-08-30 13:34:05 -07:00
{
EquipPlayer(pActivator);
2013-08-30 13:34:05 -07:00
}
//
// CGamePlayerTeam / game_player_team -- Changes the team of the player who fired it
// Flag: Fire once
// Flag: Kill Player
// Flag: Gib Player
#define SF_PTEAM_FIREONCE 0x0001
#define SF_PTEAM_KILL 0x0002
#define SF_PTEAM_GIB 0x0004
2013-08-30 13:34:05 -07:00
class CGamePlayerTeam : public CRulePointEntity
{
public:
void Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value) override;
2013-08-30 13:34:05 -07:00
private:
inline bool RemoveOnFire() { return (pev->spawnflags & SF_PTEAM_FIREONCE) != 0; }
inline bool ShouldKillPlayer() { return (pev->spawnflags & SF_PTEAM_KILL) != 0; }
inline bool ShouldGibPlayer() { return (pev->spawnflags & SF_PTEAM_GIB) != 0; }
const char* TargetTeamName(const char* pszTargetName);
2013-08-30 13:34:05 -07:00
};
LINK_ENTITY_TO_CLASS(game_player_team, CGamePlayerTeam);
2013-08-30 13:34:05 -07:00
const char* CGamePlayerTeam::TargetTeamName(const char* pszTargetName)
2013-08-30 13:34:05 -07:00
{
CBaseEntity* pTeamEntity = NULL;
2013-08-30 13:34:05 -07:00
while ((pTeamEntity = UTIL_FindEntityByTargetname(pTeamEntity, pszTargetName)) != NULL)
2013-08-30 13:34:05 -07:00
{
if (FClassnameIs(pTeamEntity->pev, "game_team_master"))
2013-08-30 13:34:05 -07:00
return pTeamEntity->TeamID();
}
return NULL;
}
void CGamePlayerTeam::Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value)
2013-08-30 13:34:05 -07:00
{
if (!CanFireForActivator(pActivator))
2013-08-30 13:34:05 -07:00
return;
if (pActivator->IsPlayer())
2013-08-30 13:34:05 -07:00
{
const char* pszTargetTeam = TargetTeamName(STRING(pev->target));
if (pszTargetTeam)
2013-08-30 13:34:05 -07:00
{
CBasePlayer* pPlayer = (CBasePlayer*)pActivator;
g_pGameRules->ChangePlayerTeam(pPlayer, pszTargetTeam, ShouldKillPlayer(), ShouldGibPlayer());
2013-08-30 13:34:05 -07:00
}
}
if (RemoveOnFire())
2013-08-30 13:34:05 -07:00
{
UTIL_Remove(this);
2013-08-30 13:34:05 -07:00
}
}