func_tracktrain: unbreak.

more cleanups.
This commit is contained in:
Marco Cawthorne 2025-01-14 03:00:12 -08:00
parent 6867396b09
commit 19b47e393c
81 changed files with 1419 additions and 822 deletions

View file

@ -283,18 +283,6 @@ Event_Parse(float type)
case EV_ENTITYEVENT:
EV_EntityEvent();
break;
case EV_BLOOD:
vector vBloodPos = g_vec_null;
vector vBloodColor = g_vec_null;
vBloodPos[0] = readcoord();
vBloodPos[1] = readcoord();
vBloodPos[2] = readcoord();
vBloodColor[0] = readbyte() / 255;
vBloodColor[1] = readbyte() / 255;
vBloodColor[2] = readbyte() / 255;
break;
case EV_CHAT:
float fSender = readbyte();
float fTeam = readbyte();

View file

@ -27,7 +27,6 @@ enum
EV_ANGLE,
EV_IMPACT,
EV_GIBHUMAN,
EV_BLOOD,
EV_EXPLOSION,
EV_SPARK,
EV_SHAKE,

View file

@ -35,6 +35,7 @@ class func_dustcloud:ncEntity
{
public:
void func_dustcloud(void);
virtual void Precache(void);
virtual void Spawned(void);
virtual float predraw(void);
virtual void SpawnKey(string,string);
@ -156,12 +157,17 @@ func_dustcloud::predraw(void)
return (PREDRAW_NEXT);
}
void
func_dustcloud::Precache(void)
{
precache.Model(model);
}
void
func_dustcloud::Spawned(void)
{
super::Spawned();
precache_model(model);
setmodel(this, model);
setorigin(this, origin);
movetype = MOVETYPE_NONE;

View file

@ -33,6 +33,7 @@ class func_dustmotes:ncEntity
public:
void func_dustmotes(void);
virtual void Precache(void);
virtual void Spawned(void);
virtual float predraw(void);
virtual void SpawnKey(string,string);
@ -44,6 +45,13 @@ private:
float m_flNexTime;
};
void
func_dustmotes::func_dustmotes(void)
{
solid = SOLID_NOT;
isCSQC = true;
}
bool
func_dustmotes::CanSpawn(bool clientSide)
{
@ -55,11 +63,13 @@ func_dustmotes::predraw(void)
{
vector vecPlayer = g_view.GetCameraOrigin();
if (checkpvs(vecPlayer, this) == FALSE)
if (checkpvs(vecPlayer, this) == FALSE) {
return (PREDRAW_NEXT);
}
if (m_flNexTime > cltime)
if (m_flNexTime > cltime) {
return (PREDRAW_NEXT);
}
for (int i = 0; i < m_iCount; i++) {
vector vecPos;
@ -75,12 +85,17 @@ func_dustmotes::predraw(void)
return (PREDRAW_NEXT);
}
void
func_dustmotes::Precache(void)
{
precache.Model(model);
}
void
func_dustmotes::Spawned(void)
{
super::Spawned();
precache_model(model);
setmodel(this, model);
setorigin(this, origin);
movetype = MOVETYPE_NONE;
@ -100,10 +115,3 @@ func_dustmotes::SpawnKey(string strField, string strKey)
super::SpawnKey(strField, strKey);
}
}
void
func_dustmotes::func_dustmotes(void)
{
solid = SOLID_NOT;
isCSQC = true;
}

View file

@ -37,6 +37,7 @@ class func_smokevolume:ncEntity
public:
void func_smokevolume(void);
virtual void Precache(void);
virtual void Spawned(void);
virtual float predraw(void);
virtual void SpawnKey(string, string);
@ -180,12 +181,17 @@ func_smokevolume::predraw(void)
return (PREDRAW_NEXT);
}
void
func_smokevolume::Precache(void)
{
precache.Model(model);
}
void
func_smokevolume::Spawned(void)
{
super::Spawned();
precache_model(model);
setmodel(this, model);
setorigin(this, origin);
movetype = MOVETYPE_NONE;

View file

@ -69,7 +69,8 @@ public:
virtual void Save(float);
virtual void Restore(string,string);
virtual void SpawnKey(string,string);
virtual void Spawned(void);
virtual void Precache(void);
virtual void Respawn(void);
virtual void Trigger(entity, triggermode_t);
private:
@ -129,13 +130,15 @@ env_beverage::SpawnKey(string strKey, string strValue)
}
void
env_beverage::Spawned(void)
env_beverage::Precache(void)
{
super::Spawned();
precache_model("models/can.mdl");
precache_sound("weapons/g_bounce3.wav");
precache.Model("models/can.mdl");
precache.Sound("weapons/g_bounce3.wav");
}
void
env_beverage::Respawn(void)
{
m_bReady = true;
if (m_sodaSkin == SKIN_RANDOM) {

View file

@ -51,7 +51,7 @@ env_shooter:ncRenderableEntity
public:
void env_shooter(void);
virtual void Spawned(void);
virtual void Precache(void);
virtual void Save(float);
virtual void Restore(string,string);
virtual void SpawnKey(string,string);
@ -93,41 +93,39 @@ env_shooter::env_shooter(void)
}
void
env_shooter::Spawned(void)
env_shooter::Precache(void)
{
super::Spawned();
if (STRING_SET(m_strShootModel)) {
precache.Model(m_strShootModel);
if (m_strShootModel) {
precache_model(m_strShootModel);
/* figure out if we're a sprite... */
if (Util_ExtensionFromString(m_strShootModel) == "spr") {
m_bCanScale = true;
}
}
/* There isn't a much more portable to do this, maybe this can be abstracted
through separate soundDef entries but I don't know if that'll be less annoying. */
switch (m_flShootSounds) {
case 0: /* glass */
Sound_Precache("func_breakable.impact_glass");
Sound_Precache("sfx_impact.glass");
break;
case 1: /* wood */
Sound_Precache("func_breakable.impact_wood");
Sound_Precache("sfx_impact.wood");
break;
case 2: /* metal */
Sound_Precache("func_breakable.impact_metal");
Sound_Precache("sfx_impact.metal");
break;
case 3: /* flesh */
Sound_Precache("func_breakable.impact_flesh");
Sound_Precache("sfx_impact.flesh");
break;
case 4: /* concrete */
Sound_Precache("func_breakable.impact_concrete");
Sound_Precache("sfx_impact.concrete");
break;
case -1: /* none */
default:
break;
}
/* figure out if we're a sprite... */
if (Util_ExtensionFromString(m_strShootModel) == "spr") {
m_bCanScale = true;
}
}
void
@ -212,7 +210,7 @@ env_shooter::SpawnKey(string strKey, string strValue)
m_flGibLife = ReadFloat(strValue);
break;
case "shootmodel":
m_strShootModel = strValue;
m_strShootModel = ReadString(strValue);
break;
case "shootsounds":
m_flShootSounds = ReadFloat(strValue);

View file

@ -44,7 +44,7 @@ public:
/* overrides */
virtual void Save(float);
virtual void Restore(string,string);
virtual void Spawned(void);
virtual void Precache(void);
virtual void SpawnKey(string,string);
virtual void customphysics(void);
virtual void Respawn(void);
@ -130,13 +130,11 @@ func_healthcharger::SpawnKey(string strKey, string strValue)
}
void
func_healthcharger::Spawned(void)
func_healthcharger::Precache(void)
{
super::Spawned();
precache_sound(m_strSndFirst);
precache_sound(m_strSndCharging);
precache_sound(m_strSndDone);
precache.Sound(m_strSndFirst);
precache.Sound(m_strSndCharging);
precache.Sound(m_strSndDone);
}
void

View file

@ -46,7 +46,7 @@ public:
virtual void Save(float);
virtual void Restore(string,string);
virtual void SpawnKey(string,string);
virtual void Spawned(void);
virtual void Precache(void);
virtual void Respawn(void);
virtual void customphysics(void);
@ -132,13 +132,11 @@ func_recharge::SpawnKey(string strKey, string strValue)
}
void
func_recharge::Spawned(void)
func_recharge::Precache(void)
{
super::Spawned();
precache_sound(m_strSndFirst);
precache_sound(m_strSndCharging);
precache_sound(m_strSndDone);
precache.Sound(m_strSndFirst);
precache.Sound(m_strSndCharging);
precache.Sound(m_strSndDone);
}
void

View file

@ -76,7 +76,7 @@ func_tank:ncVehicle
public:
void func_tank(void);
virtual void Spawned(void);
virtual void Precache(void);
virtual void Save(float);
virtual void Restore(string,string);
virtual void customphysics(void);
@ -209,55 +209,55 @@ func_tank::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
case "yawrate":
m_flYawRate = stof(strValue);
m_flYawRate = ReadFloat(strValue);
break;
case "yawrange":
m_flYawRange = stof(strValue);
m_flYawRange = ReadFloat(strValue);
break;
case "pitchrate":
m_flPitchRate = stof(strValue);
m_flPitchRate = ReadFloat(strValue);
break;
case "pitchrange":
m_flPitchRange = stof(strValue);
m_flPitchRange = ReadFloat(strValue);
break;
case "barrel":
m_vecTipPos[0] = stof(strValue);
m_vecTipPos[0] = ReadFloat(strValue);
break;
case "barrely":
m_vecTipPos[1] = stof(strValue);
m_vecTipPos[1] = ReadFloat(strValue);
break;
case "barrelz":
m_vecTipPos[2] = stof(strValue);
m_vecTipPos[2] = ReadFloat(strValue);
break;
case "firerate":
m_flFireRate = 1.0f / stof(strValue);
m_flFireRate = 1.0f / ReadFloat(strValue);
break;
case "bullet_damage":
m_iDamage = stoi(strValue);
m_iDamage = ReadInt(strValue);
break;
case "firespread":
m_vecSpread = [0.25, 0.25, 0] * stof(strValue);
m_vecSpread = [0.1, 0.1, 0] * ReadFloat(strValue);
break;
case "persistance":
m_flPersistance = stof(strValue);
m_flPersistance = ReadFloat(strValue);
break;
case "minRange":
m_flMinRange = stof(strValue);
m_flMinRange = ReadFloat(strValue);
break;
case "maxRange":
m_flMaxRange = stof(strValue);
m_flMaxRange = ReadFloat(strValue);
break;
case "spritesmoke":
m_strSpriteSmoke = strValue;
m_strSpriteSmoke = ReadString(strValue);
break;
case "spriteflash":
m_strSpriteFlash = strValue;
m_strSpriteFlash = ReadString(strValue);
break;
case "spritescale":
m_flSpriteScale = stof(strValue);
m_flSpriteScale = ReadFloat(strValue);
break;
case "rotatesound":
m_strSndRotate = strValue;
m_strSndRotate = ReadString(strValue);
break;
default:
super::SpawnKey(strKey, strValue);
@ -265,14 +265,10 @@ func_tank::SpawnKey(string strKey, string strValue)
}
void
func_tank::Spawned(void)
func_tank::Precache(void)
{
super::Spawned();
if (m_strSpriteFlash)
precache_model(m_strSpriteFlash);
if (m_strSpriteSmoke)
precache_model(m_strSpriteSmoke);
precache.Model(m_strSpriteFlash);
precache.Model(m_strSpriteSmoke);
}
void
@ -283,8 +279,9 @@ func_tank::Respawn(void)
SetMovetype(MOVETYPE_PUSH);
SetSolid(SOLID_BSP);
if (m_eDriver)
if (m_eDriver) {
PlayerLeave((ncPlayer)m_eDriver);
}
}
void
@ -294,8 +291,9 @@ func_tank::SpriteSmoke(vector org)
remove(self);
}
if (!m_strSpriteSmoke)
if (!STRING_SET(m_strSpriteSmoke)) {
return;
}
ncRenderableEntity smoke = spawn(ncRenderableEntity);
smoke.SetModel(m_strSpriteSmoke);
@ -315,8 +313,9 @@ func_tank::SpriteFlash(vector org)
remove(self);
}
if (!m_strSpriteFlash)
if (!STRING_SET(m_strSpriteFlash)) {
return;
}
ncRenderableEntity flash = spawn(ncRenderableEntity);
flash.SetModel(m_strSpriteFlash);
@ -332,18 +331,19 @@ func_tank::SpriteFlash(vector org)
void
func_tank::customphysics(void)
{
if (m_eDriver && m_eDriver.health <= 0)
if (m_eDriver && m_eDriver.health <= 0) {
PlayerLeave((ncPlayer)m_eDriver);
}
if (m_eDriver) {
vector endorg;
makevectors(m_eDriver.v_angle);
endorg = v_forward * 4086;
angles = vectoangles(endorg - origin);
endorg = anglesToForward(m_eDriver.v_angle) * 4096.0f;
angles = vectorToAngles(endorg - origin);
PlayerUpdateFlags();
if (vlen(m_eDriver.origin - origin) > 128)
if (distance(m_eDriver.origin, origin) > 128) {
PlayerLeave((ncPlayer)m_eDriver);
}
}
}

View file

@ -550,19 +550,14 @@ func_tracktrain::Respawn(void)
{
super::Respawn();
if (modelindex == 0) {
Destroy();
return;
}
/* legacy compat */
SetSolid(HasSpawnFlags(TRAIN_NONSOLID) ? SOLID_NOT : SOLID_BSP);
SetMovetype(MOVETYPE_PUSH);
m_flCurrentSpeed = m_flStartSpeed;
ScheduleThink(_AfterSpawn, 0.0f);
SetTriggerTarget(GetSpawnString("target"));
/* this needs to be a bit later than anything else. */
ScheduleThink(_AfterSpawn, 0.1f);
PlayerUse = OnPlayerUse;
if (m_flTrainLength == 0.0f)
@ -970,6 +965,8 @@ func_tracktrain::_AfterSpawn(void)
path_track targetNode;
path_track nodeAhead;
SetTriggerTarget(GetSpawnString("target"));
/* get the first target */
targetNode = (path_track)GetTrackNodeForward();

View file

@ -47,12 +47,27 @@ gibshooter:env_shooter
{
public:
void gibshooter(void);
virtual void Spawned(void);
virtual void Precache(void);
};
void
gibshooter::gibshooter(void)
{
}
void
gibshooter::Spawned(void)
{
m_strShootModel = "models/hgibs.mdl";
m_flShootSounds = 3;
precache_model(m_strShootModel);
super::Spawned();
}
void
gibshooter::Precache(void)
{
precache.Model(m_strShootModel);
}

View file

@ -49,13 +49,6 @@ typedef enum
HINT_WORLD_ALIEN_BLOOD = 1003,
} hinttype_t;
typedef enum
{
IGNORE_NO,
IGNORE_YES,
IGNORE_DEFAULT
} ignorefacing_t;
/* TODO: Make this match ncMonster more */
typedef enum
{
@ -142,7 +135,7 @@ However, that was never completed.
@ingroup pointentity
*/
class
info_hint:ncPointTrigger
info_hint:ncHint
{
public:
void info_hint(void);

View file

@ -55,7 +55,7 @@ public:
/* overrides */
virtual void Save(float);
virtual void Restore(string,string);
virtual void Spawned(void);
virtual void Precache(void);
virtual void SpawnKey(string,string);
virtual void customphysics(void);
virtual void Respawn(void);
@ -155,13 +155,11 @@ item_healthcharger::SpawnKey(string strKey, string strValue)
}
void
item_healthcharger::Spawned(void)
item_healthcharger::Precache(void)
{
super::Spawned();
precache_sound(m_strSndFirst);
precache_sound(m_strSndCharging);
precache_sound(m_strSndDone);
precache.Sound(m_strSndFirst);
precache.Sound(m_strSndCharging);
precache.Sound(m_strSndDone);
}

View file

@ -55,7 +55,7 @@ public:
/* overrides */
virtual void Save(float);
virtual void Restore(string,string);
virtual void Spawned(void);
virtual void Precache(void);
virtual void SpawnKey(string,string);
virtual void customphysics(void);
virtual void Respawn(void);
@ -155,13 +155,11 @@ item_recharge::SpawnKey(string strKey, string strValue)
}
void
item_recharge::Spawned(void)
item_recharge::Precache(void)
{
super::Spawned();
precache_sound(m_strSndFirst);
precache_sound(m_strSndCharging);
precache_sound(m_strSndDone);
precache.Sound(m_strSndFirst);
precache.Sound(m_strSndCharging);
precache.Sound(m_strSndDone);
}

View file

@ -95,7 +95,7 @@ path_corner::Spawned(void)
{
super::Spawned();
if (m_strOnPass)
if (STRING_SET(m_strOnPass))
m_strOnPass = CreateOutput(m_strOnPass);
}

View file

@ -131,6 +131,7 @@ path_track::SpawnKey(string keyName, string setValue)
void
path_track::Respawn(void)
{
super::Respawn();
m_bTrackEnabled = HasSpawnFlags(PATHTRACK_DISABLED) ? false : true;
}

View file

@ -126,9 +126,10 @@ trigger_auto::Respawn(void)
void
trigger_auto::Processing(void)
{
if (m_strGlobalState) {
if (GetGlobalValue(m_strGlobalState) == 0)
if (STRING_SET(m_strGlobalState)) {
if (GetGlobalValue(m_strGlobalState) == 0) {
return;
}
}
UseTargets(this, m_iTriggerState, m_flDelay);

View file

@ -76,6 +76,7 @@ public:
virtual void Restore(string,string);
virtual void SpawnKey(string,string);
virtual void Spawned(void);
virtual void Precache(void);
virtual void Respawn(void);
virtual void EvaluateEntity(void);
virtual float SendEntity(entity,float);
@ -225,7 +226,12 @@ ambient_generic::Spawned(void)
spawnflags |= MSF_MULTIPLAYER;
super::Spawned();
precache_sound(m_strSpawnPath);
}
void
ambient_generic::Precache(void)
{
precache.Sound(m_strSpawnPath);
}
void

View file

@ -68,7 +68,7 @@ public:
/* overrides */
virtual void SpawnKey(string,string);
virtual void Respawn(void);
virtual void Spawned(void);
virtual void Precache(void);
#ifdef SERVER
virtual void Save(float);
@ -298,14 +298,18 @@ env_bubbles::ReceiveEntity(float is_new, float flChanged)
angles[2] = readcoord();
}
if (flChanged & BUBBLES_DENSITY)
if (flChanged & BUBBLES_DENSITY) {
m_iDensity = readbyte();
if (flChanged & BUBBLES_FREQUENCY)
}
if (flChanged & BUBBLES_FREQUENCY) {
m_flFrequency = readfloat();
if (flChanged & BUBBLES_CURRENT)
}
if (flChanged & BUBBLES_CURRENT) {
m_flCurrent = readfloat();
if (flChanged & BUBBLES_ENABLED)
}
if (flChanged & BUBBLES_ENABLED) {
m_bEnabled = readbyte();
}
think = EmitBubbles;
nextthink = time + m_flFrequency;
@ -340,16 +344,15 @@ env_bubbles::Respawn(void)
m_flFrequency = m_flSpawnFrequency;
m_flCurrent = m_flSpawnCurrent;
if (spawnflags & BUBFL_STARTOFF)
if (spawnflags & BUBFL_STARTOFF) {
m_bEnabled = false;
else
} else {
m_bEnabled = true;
}
}
void
env_bubbles::Spawned(void)
env_bubbles::Precache(void)
{
super::Spawned();
precache_model("sprites/bubble.spr");
precache.Model("sprites/bubble.spr");
}

View file

@ -83,7 +83,6 @@ func_lod::Spawned(void)
{
super::Spawned();
precache_model(model);
setmodel(this, model);
setorigin(this, origin);
movetype = MOVETYPE_NONE;
@ -155,4 +154,4 @@ func_lod::SendEntity(entity a, float b)
{
return (0);
}
#endif
#endif

View file

@ -109,6 +109,11 @@ private:
float m_flFireTime;
};
void
func_tankmortar::func_tankmortar(void)
{
m_iVehicleFlags |= VHF_FROZEN | VHF_NOATTACK;
}
#ifdef CLIENT
void
@ -450,16 +455,7 @@ func_tankmortar::Spawned(void)
super::Spawned();
#ifdef SERVER
if (m_strSpriteFlash)
precache_model(m_strSpriteFlash);
if (m_strSpriteSmoke)
precache_model(m_strSpriteSmoke);
precache.Model(m_strSpriteFlash);
precache.Model(m_strSpriteSmoke);
#endif
}
void
func_tankmortar::func_tankmortar(void)
{
m_iVehicleFlags |= VHF_FROZEN | VHF_NOATTACK;
}

View file

@ -55,10 +55,10 @@ This entity was introduced in Quake (1996).
*/
#ifdef SERVER
class NSWorldspawn:ncEntity
class ncWorldSpawn:ncEntity
{
public:
void NSWorldspawn(void);
void ncWorldSpawn(void);
virtual void Spawned(void);
virtual void Save(float);
@ -83,7 +83,7 @@ private:
};
void
NSWorldspawn::NSWorldspawn(void)
ncWorldSpawn::ncWorldSpawn(void)
{
/* defaults */
m_flHDRIrisMinValue = 0.0;
@ -128,14 +128,14 @@ NSWorldspawn::NSWorldspawn(void)
lightstyle(64, "m");
lightstyle(65, "z");
precache_model("models/error.vvm");
precache.Model("models/error.vvm");
//if (autocvar_sv_levelexec)
// readcmd(sprintf("exec maps/%s.cfg\n", mapname));
}
void
NSWorldspawn::Spawned(void)
ncWorldSpawn::Spawned(void)
{
super::Spawned();
@ -171,7 +171,7 @@ NSWorldspawn::Spawned(void)
}
void
NSWorldspawn::SpawnKey(string strKey, string strValue)
ncWorldSpawn::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
case "skyname":
@ -228,7 +228,7 @@ NSWorldspawn::SpawnKey(string strKey, string strValue)
}
void
NSWorldspawn::Save(float handle)
ncWorldSpawn::Save(float handle)
{
super::Save(handle);
@ -248,7 +248,7 @@ NSWorldspawn::Save(float handle)
}
void
NSWorldspawn::Restore(string strKey, string strValue)
ncWorldSpawn::Restore(string strKey, string strValue)
{
switch (strKey) {
case "m_strSkyName":
@ -299,7 +299,7 @@ NSWorldspawn::Restore(string strKey, string strValue)
void
worldspawn(void)
{
NSWorldspawn ourWorld = spawn(NSWorldspawn);
ncWorldSpawn ourWorld = spawn(ncWorldSpawn);
ourWorld.pvsflags = PVSF_IGNOREPVS;
/* fill the delegate with spawndata */

65
src/nav/Hint.h Normal file
View file

@ -0,0 +1,65 @@
/*
* Copyright (c) 2016-2025 Vera Visions LLC.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
typedef enum
{
IGNORE_NO,
IGNORE_YES,
IGNORE_DEFAULT
} ignorefacing_t;
/*! \brief Nav Hint */
/*!QUAKED ncNavHint (0 0 0) (-8 -8 -8) (8 8 8)
# OVERVIEW
Helper entity for the Nav routines. Defines where to go for
sensible defense/offensive or other hints.
# KEYS
- "targetname" : Name
- "hintType" : Hint type, this controls this hints' purpose. Be short and descriptive.
- "hintActivity" : Associated animation activity. Once an NPC goes to this node they'll play it
- "nodeFOV" : Field of view of the node. You'll probably want to set a sensible angle too.
- "StartHintDisabled" : Whether or not to 'hide' the hint on start, requiring activation to work.
- "Group" : Hint group definition. Some NPCs are set up to only look for their specific group.
- "IgnoreFacing" : Whether or not we need to ignore the angle and field of view setting, see notes.
- "mindsetFilter" : Comma-separated list of mindsets required to use this hint, see notes.
The 'IgnoreFacing' field can be one of 3 values:
- NO = 0
- YES = 1
- AUTO = 2
*/
class
ncHint:ncPointTrigger
{
public:
void ncHint(void);
/* overrides */
virtual void Save(float);
virtual void Restore(string,string);
virtual void SpawnKey(string,string);
virtual void Spawned(void);
private:
string m_hintType;
string m_strHintActivity;
float m_flNodeFOV;
string m_strHintGroup;
ignorefacing_t m_ignoreFacing;
string m_mindsetFilter;
};

102
src/nav/Hint.qc Normal file
View file

@ -0,0 +1,102 @@
/*
* Copyright (c) 2016-2025 Vera Visions LLC.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
void
ncHint::ncHint(void)
{
m_hintType = __NULL__;
m_strHintActivity = __NULL__;
m_flNodeFOV = 360;
m_strHintGroup = __NULL__;
m_ignoreFacing = IGNORE_DEFAULT;
m_mindsetFilter = __NULL__;
};
void
ncHint::Save(float handle)
{
super::Save(handle);
SaveString(handle, "m_hintType", m_hintType);
SaveString(handle, "m_strHintActivity", m_strHintActivity);
SaveFloat(handle, "m_flNodeFOV", m_flNodeFOV);
SaveString(handle, "m_strHintGroup", m_strHintGroup);
SaveFloat(handle, "m_ignoreFacing", m_ignoreFacing);
SaveString(handle, "m_mindsetFilter", m_mindsetFilter);
}
void
ncHint::Restore(string strKey, string strValue)
{
switch (strKey) {
case "m_hintType":
m_hintType = ReadString(strValue);
break;
case "m_strHintActivity":
m_strHintActivity = ReadString(strValue);
break;
case "m_flNodeFOV":
m_flNodeFOV = ReadFloat(strValue);
break;
case "m_strHintGroup":
m_strHintGroup = ReadString(strValue);
break;
case "m_ignoreFacing":
m_ignoreFacing = ReadFloat(strValue);
break;
case "m_mindsetFilter":
m_mindsetFilter = ReadString(strValue);
break;
default:
super::Restore(strKey, strValue);
}
}
void
ncHint::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
case "hinttype":
m_hintType = ReadString(strValue);
break;
case "hintactivity":
m_strHintActivity = ReadString(strValue);
break;
case "nodeFOV":
m_flNodeFOV = ReadFloat(strValue);
break;
case "StartDisabled":
m_bStartDisabled = ReadFloat(strValue) == 1 ? true : false;
break;
case "Group":
m_strHintGroup = ReadString(strValue);
break;
case "IgnoreFacing":
m_ignoreFacing = ReadFloat(strValue);
break;
case "MinimumState":
m_mindsetFilter = ReadString(strValue);
break;
default:
super::SpawnKey(strKey, strValue);
}
}
void
ncHint::Spawned(void)
{
super::Spawned();
SetEditorIcon("help");
}

79
src/nav/NavInfo.h Normal file
View file

@ -0,0 +1,79 @@
/*
* Copyright (c) 2025 Vera Visions LLC.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
class
ncNavInfo
{
public:
nonvirtual vector PositionOfClosestNode(vector);
/** Returns the position of a spot that'll provide cover from the specified enemy.
@param targetEnemy The enemy to hide from.
@return Absolute position of a valid cover spot. */
nonvirtual vector FindCoverFromEnemy(ncActor targetEnemy);
/** Returns the position of a spot that'll be behind where you're currently standing
@param targetPosition The position to back away from.
@param eulerDirection The direction we're looking in, in euler-angles.
@return Absolute position of a valid cover spot. */
nonvirtual vector FindBackFromPosition(vector targetPosition, vector eulerDirection);
/** Returns the position of a spot that'll provide cover from the specified enemy, closest to a specified node.
@param targetEnemy The enemy to hide from.
@param nodePosition The position we should get closest to.
@return Absolute position of a valid cover spot. */
nonvirtual vector FindCoverFromEnemyNearNode(ncActor targetEnemy, vector nodePosition);
/** Returns the position of a spot that'll provide cover from the specified enemy, furthest from a specified node.
@param targetEnemy The enemy to hide from.
@param nodePosition The position we should get as far away from as possible from.
@return Absolute position of a valid cover spot. */
nonvirtual vector FindCoverFromEnemyFarNode(ncActor targetEnemy, vector nodePosition);
/** Returns the position of a spot that'll provide cover from the specified enemy.
@param traceEntity The entity which will be testing for collisions.
@param targetOrigin The spot to hide from.
@return Absolute position of a valid cover spot. */
nonvirtual vector FindCoverFromPosition(entity traceEntity, vector targetOrigin);
/** Returns the position of a spot that is accessible within a specified position.
@param traceEntity The entity which will be testing for collisions.
@param targetOrigin The spot to be near.
@param minRadius The mininum distance / search radius from the targetOrigin.
@param maxRadius The maximum Radius in which we'll look for a free spot.
@return Absolute position of a valid cover spot. */
nonvirtual vector FindEmptySpotNearPosition(entity traceEntity, vector position, float minRadius, float maxRadius);
/** Returns the position of a spot that is far away within a specified position.
@param traceEntity The entity which will be testing for collisions.
@param targetOrigin The spot to be near.
@param minRadius The mininum distance / search radius from the targetOrigin.
@param maxRadius The maximum Radius in which we'll look for a free spot.
@return Absolute position of a valid cover spot. */
nonvirtual vector FindEmptySpotAwayFromPosition(entity traceEntity, vector position, float minRadius, float maxRadius);
};

246
src/nav/NavInfo.qc Normal file
View file

@ -0,0 +1,246 @@
/*
* Copyright (c) 2025 Vera Visions LLC.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* Helper functions for tasks/nav */
vector
ncNavInfo::PositionOfClosestNode(vector pointOrigin)
{
float bestDistance = COST_INFINITE;
int bestNodeID = -1;
for (int i = 0; i < g_iNodes; i++) {
vector nodePosition = g_pNodes[i].m_vecOrigin;
float nodeDistance = distanceSquared(nodePosition, pointOrigin);
if (nodeDistance < bestDistance) {
bestDistance = nodeDistance;
bestNodeID = i;
}
}
return (g_pNodes[bestNodeID].m_vecOrigin);
}
vector
ncNavInfo::FindCoverFromEnemy(ncActor targetEnemy)
{
float bestDistance = COST_INFINITE;
int bestNodeID = -1i;
for (int i = 0; i < g_iNodes; i++) {
vector nodePosition = g_pNodes[i].m_vecOrigin;
float nodeRadius = g_pNodes[i].m_flRadius;
float nodeDistance = distanceSquared(nodePosition, targetEnemy.origin);
traceline(targetEnemy.origin, nodePosition, MOVE_NORMAL, targetEnemy);
if (trace_fraction < 1.0 && nodeDistance < bestDistance) {
bestDistance = nodeDistance;
bestNodeID = i;
}
}
if (bestNodeID != -1i) {
return g_vec_null;
}
return (g_pNodes[bestNodeID].m_vecOrigin);
}
vector
ncNavInfo::FindBackFromPosition(vector targetPosition, vector eulerDirection)
{
float bestDistance = COST_INFINITE;
int bestNodeID = -1;
vector forwardDir = anglesToForward(eulerDirection);
for (int i = 0; i < g_iNodes; i++) {
vector nodePosition = g_pNodes[i].m_vecOrigin;
float nodeRadius = g_pNodes[i].m_flRadius;
float nodeDistance = distanceSquared(nodePosition, targetPosition);
traceline(targetPosition, nodePosition, MOVE_NORMAL, world);
if (trace_fraction < 1.0 && nodeDistance < bestDistance) {
bestDistance = nodeDistance;
bestNodeID = i;
}
}
return (g_pNodes[bestNodeID].m_vecOrigin);
}
vector
ncNavInfo::FindCoverFromEnemyNearNode(ncActor targetEnemy, vector targetNode)
{
float bestDistance = COST_INFINITE;
int bestNodeID = -1;
for (int i = 0; i < g_iNodes; i++) {
vector nodePosition = g_pNodes[i].m_vecOrigin;
float nodeDistance = distanceSquared(nodePosition, targetNode);
traceline(targetEnemy.origin, nodePosition, MOVE_NORMAL, targetEnemy);
if (trace_fraction < 1.0 && nodeDistance < bestDistance) {
bestDistance = nodeDistance;
bestNodeID = i;
}
}
return (g_pNodes[bestNodeID].m_vecOrigin);
}
vector
ncNavInfo::FindCoverFromEnemyFarNode(ncActor targetEnemy, vector targetNode)
{
float bestDistance = 0;
int bestNodeID = -1;
for (int i = 0; i < g_iNodes; i++) {
vector nodePosition = g_pNodes[i].m_vecOrigin;
float nodeDistance = distanceSquared(nodePosition, targetNode);
traceline(targetEnemy.origin, nodePosition, MOVE_NORMAL, targetEnemy);
if (trace_fraction < 1.0 && nodeDistance > bestDistance) {
bestDistance = nodeDistance;
bestNodeID = i;
}
}
return (g_pNodes[bestNodeID].m_vecOrigin);
}
vector
ncNavInfo::FindCoverFromPosition(entity traceEntity, vector targetOrigin)
{
float bestDistance = COST_INFINITE;
int bestNodeID = -1i;
#if 0
if (g_iNodes <= 0i) {
return ncNavInfo::FindEmptySpotNearPosition(world, targetOrigin, 512.0, 4096.0f);
}
#endif
for (int i = 0; i < g_iNodes; i++) {
vector nodePosition = g_pNodes[i].m_vecOrigin;
float nodeDistance = distanceSquared(nodePosition, traceEntity.origin);
traceline(nodePosition, targetOrigin, MOVE_NORMAL, traceEntity);
if ((trace_ent == world || trace_fraction < 1.0) && nodeDistance < bestDistance) {
bestDistance = nodeDistance;
bestNodeID = i;
}
}
if (bestNodeID) {
return (g_vec_null);
}
NSError("%v", (g_pNodes[bestNodeID].m_vecOrigin));
return (g_pNodes[bestNodeID].m_vecOrigin);
}
vector
ncNavInfo::FindEmptySpotNearPosition(entity traceEntity, vector position, float minRadius, float maxRadius)
{
float bestYaw = 0.0f;
float bestDist = 0.0f;
vector testAngle = g_vec_null;
vector testPos = g_vec_null;
for (float yawTest = 0.0f; yawTest < 360.0f; yawTest += 10.0f) {
vector testPos;
float distSquared;
vector testAngle = traceEntity.angles = [0, yawTest, 0];
testAngle[0] = testAngle[2] = 0.0f;
makevectors(testAngle);
testPos = position + (v_forward * 2048.0f);
tracebox(position, traceEntity.mins, traceEntity.maxs, testPos, MOVE_NORMAL, traceEntity);
distSquared = distance(position, trace_endpos);
if (distSquared > bestDist) {
bestYaw = yawTest;
bestDist = distSquared;
}
}
/* cancel early */
if (bestDist <= minRadius) {
return (g_vec_null);
}
for (float dist = minRadius; dist < maxRadius; dist += ((maxRadius - minRadius) / 16.0f)) {
vector testAngle = [0, bestYaw, 0];
testAngle[0] = testAngle[2] = 0.0f;
makevectors(testAngle);
vector testPos = position + (v_forward * dist);
tracebox(testPos, traceEntity.mins, traceEntity.maxs, testPos, MOVE_NORMAL, traceEntity);
if (!trace_startsolid) {
return (testPos);
}
}
return (g_vec_null);
}
vector
ncNavInfo::FindEmptySpotAwayFromPosition(entity traceEntity, vector position, float minRadius, float maxRadius)
{
float bestYaw = 0.0f;
float bestDist = 0.0f;
vector testAngle = g_vec_null;
vector testPos = g_vec_null;
for (float yawTest = 0.0f; yawTest < 360.0f; yawTest += 10.0f) {
vector testPos;
float distSquared;
vector testAngle = traceEntity.angles = [0, yawTest, 0];
testAngle[0] = testAngle[2] = 0.0f;
makevectors(testAngle);
testPos = position + (v_forward * 2048.0f);
tracebox(position, traceEntity.mins, traceEntity.maxs, testPos, MOVE_NORMAL, traceEntity);
distSquared = distance(position, trace_endpos);
if (distSquared > bestDist) {
bestYaw = yawTest;
bestDist = distSquared;
}
}
/* cancel early */
if (bestDist <= minRadius) {
return (g_vec_null);
}
for (float dist = maxRadius; dist > minRadius; dist -= ((maxRadius - minRadius) / 16.0f)) {
vector testAngle = [0, bestYaw, 0];
testAngle[0] = testAngle[2] = 0.0f;
makevectors(testAngle);
vector testPos = position + (v_forward * dist);
tracebox(testPos, traceEntity.mins, traceEntity.maxs, testPos, MOVE_NORMAL, traceEntity);
if (!trace_startsolid) {
return (testPos);
}
}
return (g_vec_null);
}

56
src/nav/NodeEditor.h Normal file
View file

@ -0,0 +1,56 @@
/*
* Copyright (c) 2024 Vera Visions LLC.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/** @ingroup nav
*
* @{
*/
class
ncNodeEditor
{
/** Links node wp towards w2. */
nonvirtual void LinkNodes(node_t *, node_t *);
/** Unlinks node wp from going towards w2. */
nonvirtual void UnlinkNodes(node_t *, node_t *);
/** Returns the id of the closest node in a node graph. */
nonvirtual int FindClosestNode(vector);
/** Saves the specified nodegraph to disk with the specified filename. */
nonvirtual bool SaveFile(string);
/** Loads the nodegraph from the specified filename off disk. */
nonvirtual bool ReadFile(string, bool);
/** Flushes the nodegraph being passed. */
nonvirtual void Flush(void);
nonvirtual void Cmd(void);
nonvirtual void DrawDebugInfo(void);
private:
nonvirtual void AutoLink(int wpidx);
nonvirtual void CreateNode(entity ePlayer, int iAutoLink);
nonvirtual void DeleteNode(int iID);
nonvirtual void SetRadius(int iID, float flRadValue);
nonvirtual void LinkFlag(int linkFlag);
nonvirtual void Unlink(void);
nonvirtual void UnlinkTwo(void);
nonvirtual void HelperSpawns(void);
nonvirtual void GoToPoint(entity pl);
nonvirtual void ConnectOne(void);
nonvirtual void ConnectTwo(void);
nonvirtual void LoadCurrentMapNavMesh(void);
};
/** @} */ // end of nav

View file

@ -19,7 +19,7 @@ var int g_way1 = -1;
var int g_way2 = -1;
void
NodeEdit_LinkNodes(node_t *wp, node_t *w2)
ncNodeEditor::LinkNodes(node_t *wp, node_t *w2)
{
int w2n = w2 - g_pNodes;
@ -39,7 +39,7 @@ NodeEdit_LinkNodes(node_t *wp, node_t *w2)
}
void
NodeEdit_UnlinkNodes(node_t *wp, node_t *w2)
ncNodeEditor::UnlinkNodes(node_t *wp, node_t *w2)
{
int w2n = w2 - g_pNodes;
int nilled = 0;
@ -76,8 +76,8 @@ NodeEdit_UnlinkNodes(node_t *wp, node_t *w2)
}
}
static void
NodeEdit_AutoLink(int wpidx)
void
ncNodeEditor::AutoLink(int wpidx)
{
for (int i = 0i; i < g_iNodes; i++) {
//don't link to ourself...
@ -99,13 +99,13 @@ NodeEdit_AutoLink(int wpidx)
continue;
}
NodeEdit_LinkNodes(&g_pNodes[wpidx], &g_pNodes[i]);
NodeEdit_LinkNodes(&g_pNodes[i], &g_pNodes[wpidx]);
ncNodeEditor::LinkNodes(&g_pNodes[wpidx], &g_pNodes[i]);
ncNodeEditor::LinkNodes(&g_pNodes[i], &g_pNodes[wpidx]);
}
}
int
NodeEdit_FindClosestNode(vector vecOrigin)
ncNodeEditor::FindClosestNode(vector vecOrigin)
{
/* -1 for no nodes anywhere... */
@ -133,10 +133,10 @@ NodeEdit_FindClosestNode(vector vecOrigin)
return r;
}
static void
NodeEdit_CreateNode(entity ePlayer, int iAutoLink)
void
ncNodeEditor::CreateNode(entity ePlayer, int iAutoLink)
{
int iNearest = NodeEdit_FindClosestNode(self.origin);
int iNearest = ncNodeEditor::FindClosestNode(self.origin);
int iID = g_iNodes++;
g_pNodes = (node_t *)memreallocOld(g_pNodes, sizeof(node_t), iID, g_iNodes);
node_t *n = g_pNodes + iID;
@ -146,32 +146,32 @@ NodeEdit_CreateNode(entity ePlayer, int iAutoLink)
n->m_flRadius = autocvar_nav_radius;
if (iAutoLink == 1) {
NodeEdit_AutoLink(iID);
ncNodeEditor::AutoLink(iID);
} else {
if (iID != 0) {
if (iAutoLink == 0) {
NodeEdit_LinkNodes(n, &g_pNodes[iID-1]);
NodeEdit_LinkNodes(&g_pNodes[iID-1], n);
ncNodeEditor::LinkNodes(n, &g_pNodes[iID-1]);
ncNodeEditor::LinkNodes(&g_pNodes[iID-1], n);
} else if (iAutoLink == -1) {
NodeEdit_LinkNodes(&g_pNodes[iID-1], n);
ncNodeEditor::LinkNodes(&g_pNodes[iID-1], n);
} else if (iAutoLink == -2) {
NodeEdit_LinkNodes(n, &g_pNodes[iID-1]);
ncNodeEditor::LinkNodes(n, &g_pNodes[iID-1]);
} else if (iAutoLink == -4) {
if (iNearest == -1i)
return;
NodeEdit_LinkNodes(n, &g_pNodes[iNearest]);
NodeEdit_LinkNodes(&g_pNodes[iNearest], n);
ncNodeEditor::LinkNodes(n, &g_pNodes[iNearest]);
ncNodeEditor::LinkNodes(&g_pNodes[iNearest], n);
}
}
}
}
static void
NodeEdit_DeleteNode(int iID)
void
ncNodeEditor::DeleteNode(int iID)
{
if (iID < 0i || iID >= g_iNodes) {
print("NodeEdit_DeleteNode: invalid waypoint\n");
print("ncNodeEditor::DeleteNode: invalid waypoint\n");
return;
}
@ -196,21 +196,21 @@ NodeEdit_DeleteNode(int iID)
}
}
static void
NodeEdit_SetRadius(int iID, float flRadValue)
void
ncNodeEditor::SetRadius(int iID, float flRadValue)
{
if (iID < 0i || iID >= g_iNodes) {
print("NodeEdit_SetRadius: invalid waypoint\n");
print("ncNodeEditor::SetRadius: invalid waypoint\n");
return;
}
g_pNodes[iID].m_flRadius = flRadValue;
}
static void
NodeEdit_LinkFlag(int linkFlag)
void
ncNodeEditor::LinkFlag(int linkFlag)
{
if (g_waylink_status == 0) {
g_way1 = NodeEdit_FindClosestNode(self.origin);
g_way1 = ncNodeEditor::FindClosestNode(self.origin);
if (g_way1 == -1i)
return;
@ -218,7 +218,7 @@ NodeEdit_LinkFlag(int linkFlag)
g_waylink_status = 1;
env_message_single(self, "^2Selected first waypoint!\n");
} else if (g_waylink_status == 1) {
g_way2 = NodeEdit_FindClosestNode(self.origin);
g_way2 = ncNodeEditor::FindClosestNode(self.origin);
if (g_way2 == -1i)
return;
@ -226,7 +226,7 @@ NodeEdit_LinkFlag(int linkFlag)
g_waylink_status = 0;
if (g_way1 != g_way2) {
NodeEdit_LinkNodes(&g_pNodes[g_way1], &g_pNodes[g_way2]);
ncNodeEditor::LinkNodes(&g_pNodes[g_way1], &g_pNodes[g_way2]);
for (int b = 0i; b < g_pNodes[g_way1].m_numNeighbours; b++) {
if (g_pNodes[g_way1].m_pNeighbour[b].m_iNode == g_way2) {
g_pNodes[g_way1].m_pNeighbour[b].m_iFlags |= linkFlag;
@ -240,11 +240,11 @@ NodeEdit_LinkFlag(int linkFlag)
}
}
static void
NodeEdit_Unlink(void)
void
ncNodeEditor::Unlink(void)
{
if (g_waylink_status == 0) {
g_way1 = NodeEdit_FindClosestNode(self.origin);
g_way1 = ncNodeEditor::FindClosestNode(self.origin);
if (g_way1 == -1i)
return;
@ -252,7 +252,7 @@ NodeEdit_Unlink(void)
g_waylink_status = 1;
env_message_single(self, "^2Selected first waypoint!\n");
} else if (g_waylink_status == 1) {
g_way2 = NodeEdit_FindClosestNode(self.origin);
g_way2 = ncNodeEditor::FindClosestNode(self.origin);
if (g_way2 == -1i)
return;
@ -260,7 +260,7 @@ NodeEdit_Unlink(void)
g_waylink_status = 0;
if (g_way1 != g_way2) {
NodeEdit_UnlinkNodes(&g_pNodes[g_way1], &g_pNodes[g_way2]);
ncNodeEditor::UnlinkNodes(&g_pNodes[g_way1], &g_pNodes[g_way2]);
} else {
env_message_single(self, "^1Failed to link, the two points are the same!\n");
}
@ -268,11 +268,11 @@ NodeEdit_Unlink(void)
}
}
static void
NodeEdit_UnlinkTwo(void)
void
ncNodeEditor::UnlinkTwo(void)
{
if (g_waylink_status == 0) {
g_way1 = NodeEdit_FindClosestNode(self.origin);
g_way1 = ncNodeEditor::FindClosestNode(self.origin);
if (g_way1 == -1i)
return;
@ -280,7 +280,7 @@ NodeEdit_UnlinkTwo(void)
g_waylink_status = 1;
env_message_single(self, "^2Selected first waypoint!\n");
} else if (g_waylink_status == 1) {
g_way2 = NodeEdit_FindClosestNode(self.origin);
g_way2 = ncNodeEditor::FindClosestNode(self.origin);
if (g_way2 == -1i)
return;
@ -288,8 +288,8 @@ NodeEdit_UnlinkTwo(void)
g_waylink_status = 0;
if (g_way1 != g_way2) {
NodeEdit_UnlinkNodes(&g_pNodes[g_way1], &g_pNodes[g_way2]);
NodeEdit_UnlinkNodes(&g_pNodes[g_way2], &g_pNodes[g_way1]);
ncNodeEditor::UnlinkNodes(&g_pNodes[g_way1], &g_pNodes[g_way2]);
ncNodeEditor::UnlinkNodes(&g_pNodes[g_way2], &g_pNodes[g_way1]);
} else {
env_message_single(self, "^1Failed to link, the two points are the same!\n");
}
@ -297,16 +297,16 @@ NodeEdit_UnlinkTwo(void)
}
}
static void
NodeEdit_HelperSpawns()
void
ncNodeEditor::HelperSpawns()
{
for (entity a = world; (a = find(a, ::classname, "info_player_deathmatch"));) {
NodeEdit_CreateNode(a, TRUE);
ncNodeEditor::CreateNode(a, TRUE);
}
}
static void
NodeEdit_GoToPoint(entity pl)
void
ncNodeEditor::GoToPoint(entity pl)
{
vector vecSrc;
makevectors(pl.v_angle);
@ -314,7 +314,7 @@ NodeEdit_GoToPoint(entity pl)
traceline(vecSrc, vecSrc + (v_forward * 4096), FALSE, pl);
print(sprintf("Telling all bots to go to %v\n", trace_endpos));
for (entity a = world; (a = find(a, classname, "player"));) {
for (entity a = world; (a = find(a, ::classname, "player"));) {
if (clienttype(a) != CLIENTTYPE_REAL) {
ncBot targ;
targ = (ncBot)a;
@ -326,7 +326,7 @@ NodeEdit_GoToPoint(entity pl)
}
bool
NodeEdit_SaveFile(string filename)
ncNodeEditor::SaveFile(string filename)
{
filestream file;
@ -357,7 +357,7 @@ NodeEdit_SaveFile(string filename)
}
void
NodeEdit_Flush(void)
ncNodeEditor::Flush(void)
{
for (int i = 0i; i < g_iNodes; i++) {
memfree(g_pNodes[i].m_pNeighbour);
@ -368,14 +368,14 @@ NodeEdit_Flush(void)
}
bool
NodeEdit_ReadFile(string strFile, bool flush)
ncNodeEditor::ReadFile(string strFile, bool flush)
{
int startId = 0i;
int offSet = 0i;
filestream file = fopen(strFile, FILE_READ);
if (file < 0) {
print("NodeEdit_ReadFile: unable to open ", strFile, "\n");
print("ncNodeEditor::ReadFile: unable to open ", strFile, "\n");
return (false);
}
@ -383,7 +383,7 @@ NodeEdit_ReadFile(string strFile, bool flush)
tokenize(fgets(file));
if (flush) {
NodeEdit_Flush();
ncNodeEditor::Flush();
g_iNodes = (int)stoi(argv(0));
g_pNodes = memalloc(sizeof(*g_pNodes) * g_iNodes);
} else {
@ -415,11 +415,11 @@ NodeEdit_ReadFile(string strFile, bool flush)
return (true);
}
static void
NodeEdit_ConnectOne(void)
void
ncNodeEditor::ConnectOne(void)
{
if (g_waylink_status == 0) {
g_way1 = NodeEdit_FindClosestNode(self.origin);
g_way1 = ncNodeEditor::FindClosestNode(self.origin);
if (g_way1 == -1i)
return;
@ -427,7 +427,7 @@ NodeEdit_ConnectOne(void)
g_waylink_status = 1;
env_message_single(self, "^21/2 nodes selected... \n");
} else if (g_waylink_status == 1) {
g_way2 = NodeEdit_FindClosestNode(self.origin);
g_way2 = ncNodeEditor::FindClosestNode(self.origin);
if (g_way2 == -1i)
return;
@ -435,37 +435,7 @@ NodeEdit_ConnectOne(void)
g_waylink_status = 0;
if (g_way1 != g_way2) {
NodeEdit_LinkNodes(&g_pNodes[g_way1], &g_pNodes[g_way2]);
env_message_single(self, "^22/2 nodes selected, done!\n");
} else {
env_message_single(self, "^1Failed to link, the two points are the same!\n");
}
g_way1 = g_way2 = -1;
}
}
static void
NodeEdit_ConnectTwo(void)
{
if (g_waylink_status == 0) {
g_way1 = NodeEdit_FindClosestNode(self.origin);
if (g_way1 == -1i)
return;
g_waylink_status = 1;
env_message_single(self, "^21/2 nodes selected... \n");
} else if (g_waylink_status == 1) {
g_way2 = NodeEdit_FindClosestNode(self.origin);
if (g_way2 == -1i)
return;
g_waylink_status = 0;
if (g_way1 != g_way2) {
NodeEdit_LinkNodes(&g_pNodes[g_way1], &g_pNodes[g_way2]);
NodeEdit_LinkNodes(&g_pNodes[g_way2], &g_pNodes[g_way1]);
ncNodeEditor::LinkNodes(&g_pNodes[g_way1], &g_pNodes[g_way2]);
env_message_single(self, "^22/2 nodes selected, done!\n");
} else {
env_message_single(self, "^1Failed to link, the two points are the same!\n");
@ -475,13 +445,43 @@ NodeEdit_ConnectTwo(void)
}
void
NodeEdit_DrawDebugInfo(void)
ncNodeEditor::ConnectTwo(void)
{
if (g_waylink_status == 0) {
g_way1 = ncNodeEditor::FindClosestNode(self.origin);
if (g_way1 == -1i)
return;
g_waylink_status = 1;
env_message_single(self, "^21/2 nodes selected... \n");
} else if (g_waylink_status == 1) {
g_way2 = ncNodeEditor::FindClosestNode(self.origin);
if (g_way2 == -1i)
return;
g_waylink_status = 0;
if (g_way1 != g_way2) {
ncNodeEditor::LinkNodes(&g_pNodes[g_way1], &g_pNodes[g_way2]);
ncNodeEditor::LinkNodes(&g_pNodes[g_way2], &g_pNodes[g_way1]);
env_message_single(self, "^22/2 nodes selected, done!\n");
} else {
env_message_single(self, "^1Failed to link, the two points are the same!\n");
}
g_way1 = g_way2 = -1;
}
}
void
ncNodeEditor::DrawDebugInfo(void)
{
if (!g_iNodes) {
return;
}
int iNearest = NodeEdit_FindClosestNode(self.origin);
int iNearest = ncNodeEditor::FindClosestNode(self.origin);
makevectors([-90, 0, 0]);
for (int i = 0i; i < g_iNodes; i++) {
@ -604,14 +604,14 @@ NodeEdit_DrawDebugInfo(void)
}
}
static void
NodeEdit_LoadCurrentMapNavMesh(void)
void
ncNodeEditor::LoadCurrentMapNavMesh(void)
{
NodeEdit_ReadFile(sprintf("%s.way", mapname), true);
ncNodeEditor::ReadFile(sprintf("%s.way", mapname), true);
}
void
NodeEdit_Cmd(void)
ncNodeEditor::Cmd(void)
{
if (!self) {
return;
@ -619,46 +619,46 @@ NodeEdit_Cmd(void)
switch (argv(1)) {
case "goto":
NodeEdit_GoToPoint(self);
ncNodeEditor::GoToPoint(self);
break;
case "autolink":
NodeEdit_AutoLink(NodeEdit_FindClosestNode(self.origin));
ncNodeEditor::AutoLink(ncNodeEditor::FindClosestNode(self.origin));
break;
case "connect1":
NodeEdit_ConnectOne();
ncNodeEditor::ConnectOne();
break;
case "connect2":
NodeEdit_ConnectTwo();
ncNodeEditor::ConnectTwo();
break;
case "add":
NodeEdit_CreateNode(self, 1);
ncNodeEditor::CreateNode(self, 1);
break;
case "addchain":
NodeEdit_CreateNode(self, 0);
ncNodeEditor::CreateNode(self, 0);
break;
case "addsingle":
NodeEdit_CreateNode(self, -3);
ncNodeEditor::CreateNode(self, -3);
break;
case "addltn":
NodeEdit_CreateNode(self, -1);
ncNodeEditor::CreateNode(self, -1);
break;
case "addntl":
NodeEdit_CreateNode(self, -2);
ncNodeEditor::CreateNode(self, -2);
break;
case "addnear":
NodeEdit_CreateNode(self, -4);
ncNodeEditor::CreateNode(self, -4);
break;
case "addspawns":
NodeEdit_HelperSpawns();
ncNodeEditor::HelperSpawns();
break;
case "delete":
NodeEdit_DeleteNode(NodeEdit_FindClosestNode(self.origin));
ncNodeEditor::DeleteNode(ncNodeEditor::FindClosestNode(self.origin));
break;
case "purge":
Nodes_Flush();
break;
case "radius":
NodeEdit_SetRadius(NodeEdit_FindClosestNode(self.origin), stof(argv(2)));
ncNodeEditor::SetRadius(ncNodeEditor::FindClosestNode(self.origin), stof(argv(2)));
break;
case "radiushack":
for (int i = 0i; i < g_iNodes; i++) {
@ -685,17 +685,17 @@ NodeEdit_Cmd(void)
}
break;
case "flag":
NodeEdit_LinkFlag(stoi(argv(2)));
ncNodeEditor::LinkFlag(stoi(argv(2)));
break;
case "unlink1":
NodeEdit_Unlink();
ncNodeEditor::Unlink();
break;
case "unlink2":
NodeEdit_UnlinkTwo();
ncNodeEditor::UnlinkTwo();
break;
case "move":
vector p;
int n = NodeEdit_FindClosestNode(self.origin);
int n = ncNodeEditor::FindClosestNode(self.origin);
if (n >= 0) {
p[0] = stof(argv(2));
p[1] = stof(argv(3));
@ -704,19 +704,19 @@ NodeEdit_Cmd(void)
}
break;
case "movetopos":
int nearest = NodeEdit_FindClosestNode(self.origin);
int nearest = ncNodeEditor::FindClosestNode(self.origin);
if (nearest >= 0) {
g_pNodes[nearest].m_vecOrigin = self.origin;
}
break;
case "save":
NodeEdit_SaveFile(argv(2));
ncNodeEditor::SaveFile(argv(2));
break;
case "load":
NodeEdit_ReadFile(argv(2), true);
ncNodeEditor::ReadFile(argv(2), true);
break;
case "merge":
NodeEdit_ReadFile(argv(2), false);
ncNodeEditor::ReadFile(argv(2), false);
break;
case "loadpb":
Way_ReadPBFile(argv(2), true);
@ -743,7 +743,7 @@ void
SV_AddDebugPolygons(void)
{
if (autocvar_nav_visualize) {
NodeEdit_DrawDebugInfo();
ncNodeEditor::DrawDebugInfo();
}
if (autocvar_r_renderEntityInfo) {
@ -759,7 +759,7 @@ SV_AddDebugPolygons(void)
return;
if (!g_iNodes) {
NodeEdit_LoadCurrentMapNavMesh();
ncNodeEditor::LoadCurrentMapNavMesh();
}
#if 1

View file

@ -17,6 +17,7 @@
#include "linkflags.h"
#include "nodes.h"
#include "route.h"
#include "node_edit.h"
#include "NodeEditor.h"
#include "way_convert.h"
#include "NavInfo.h"
#include "Hint.h"

View file

@ -1,7 +1,8 @@
#includelist
Hint.qc
nodes.qc
route.qc
node_edit.qc
NodeEditor.qc
way_convert.qc
NavInfo.qc
#endlist

View file

@ -1,38 +0,0 @@
/*
* Copyright (c) 2024 Vera Visions LLC.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/** @ingroup nav
*
* @{
*/
/** Links node wp towards w2. */
void NodeEdit_LinkNodes(node_t *, node_t *);
/** Unlinks node wp from going towards w2. */
void NodeEdit_UnlinkNodes(node_t *, node_t *);
/** Returns the id of the closest node in a node graph. */
int NodeEdit_FindClosestNode(vector);
/** Saves the specified nodegraph to disk with the specified filename. */
bool NodeEdit_SaveFile(string);
/** Loads the nodegraph from the specified filename off disk. */
bool NodeEdit_ReadFile(string, bool);
/** Flushes the nodegraph being passed. */
void NodeEdit_Flush(void);
void NodeEdit_Cmd(void);
void NodeEdit_DrawDebugInfo(void);
/** @} */ // end of nav

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016-2020 Vera Visions LLC.
* Copyright (c) 2016-2025 Vera Visions LLC.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above

View file

@ -137,7 +137,7 @@ Nodes_BuildFromEnts(void)
if (g_iNodes) {
NSLog("saving nodes nodes for %s", mapname);
NodeEdit_SaveFile(sprintf("%s.way", mapname));
ncNodeEditor::SaveFile(sprintf("%s.way", mapname));
} else {
NSLog("no node data found for %s", mapname);
}
@ -172,7 +172,7 @@ Nodes_Init(void)
/* skip if present. TODO: check if they're out of date? */
if (fileExists(sprintf("data/%s.way", mapname))) {
NodeEdit_ReadFile(sprintf("data/%s.way", mapname), true);
ncNodeEditor::ReadFile(sprintf("data/%s.way", mapname), true);
} else {
Nodes_BuildFromEnts();
}
@ -185,5 +185,5 @@ Nodes_Init(void)
void
Nodes_Flush(void)
{
NodeEdit_Flush();
ncNodeEditor::Flush();
}

View file

@ -497,8 +497,8 @@ Way_ReadJumbotFile(string strFile, bool flush)
g_pNodes[i].m_flRadius = 32.0f;
if (i > startId) {
NodeEdit_LinkNodes(&g_pNodes[i], &g_pNodes[i-1]);
NodeEdit_LinkNodes(&g_pNodes[i-1], &g_pNodes[i]);
ncNodeEditor::LinkNodes(&g_pNodes[i], &g_pNodes[i-1]);
ncNodeEditor::LinkNodes(&g_pNodes[i-1], &g_pNodes[i]);
}
}

View file

@ -52,13 +52,6 @@ typedef struct
@param spawnPos the position at which it should spawn.
@return The created entity. */
entity Create(string className, vector spawnPos);
/** Precaches a given entity class.
Ensuring models, sounds and other assets referenced
within are loaded ahead of time.
@param className to precache
@return Success. */
bool Precache(string className);
/** Transitions an entity from one class to another.
@param targetEntity is the target entity.
@ -214,7 +207,6 @@ _server_main(void)
ents.Create = linkToServerProgs("spawnClass");
ents.ChangeToClass = linkToServerProgs("changeClass");
ents.Precache = linkToServerProgs("EntityDef_Precache");
ents.Input = linkToServerProgs("sendInput");
ents.isAI = linkToServerProgs("isAI");
ents.isAlive = linkToServerProgs("isAlive");

View file

@ -274,7 +274,7 @@ Cmd_ParseServerCommand(void)
break;
#ifdef BOT_INCLUDED
case "way":
NodeEdit_Cmd();
ncNodeEditor::Cmd();
break;
#endif
case "listEntityDef":

View file

@ -26,7 +26,7 @@ MapC_Init(void)
/* No mapname.dat, exit out */
if (fileExists(mapProgs) == false) {
NSWarning("No MapC for level %s loaded. (%s)", cvar_string("mapname"), mapProgs);
NSLog("No MapC for level %s loaded. (%s)", cvar_string("mapname"), mapProgs);
return;
}

View file

@ -281,8 +281,10 @@ ncActor::Spawned(void)
if (defKey != "") {
int defValue = GetDefInt(defKey);
EntLog("Giving %S some %i units of %S", classname, defValue, defKey);
GiveAmmo(i, defValue);
if (defValue > 0i) {
EntLog("Giving %S some %i units of %S", classname, defValue, defKey);
GiveAmmo(i, defValue);
}
}
}

View file

@ -55,7 +55,7 @@ void
ncEntity::Precache(void)
{
if (STRING_SET(model)) {
precache_model(model);
precache.Model(model);
}
#ifdef SERVER
@ -1213,6 +1213,7 @@ ncEntity::SpawnKey(string strKey, string strValue)
bool tempCheck = false;
/* we do re-read a lot of the builtin fields in case we want to set
defaults. just in case anybody is wondering. */
switch (strKey) {
case "spawnflags":
spawnflags = ReadFloat(strValue);

View file

@ -882,6 +882,9 @@ ncIO::SpawnKey(string strKey, string strValue)
case "maxs":
maxs = ReadVector(strValue);
break;
case "target":
target = strValue;
break;
case "targetname":
targetname = strValue;
break;
@ -1005,8 +1008,8 @@ ncIO::SetNextThink(float fl)
float flTime = GetTime() + fl;
/* HACK: to make sure things happen post-spawn */
if (flTime == 0.0f) {
flTime = 0.001f;
if (flTime < 0.1f) {
flTime = 0.1f;
}
if (flTime >= 0) {

View file

@ -33,10 +33,4 @@ public:
/** Sets up a point entity trigger with no size. */
nonvirtual void InitPointTrigger(void);
#ifdef SERVER
virtual void SpawnKey(string, string);
virtual void Save(float);
virtual void Restore(string, string);
#endif
};

View file

@ -63,32 +63,3 @@ ncPointTrigger::DebugDraw(void)
R_EndPolygon();
#endif
}
#ifdef SERVER
void
ncPointTrigger::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
default:
super::SpawnKey(strKey, strValue);
break;
}
}
void
ncPointTrigger::Save(float handle)
{
super::Save(handle);
}
void
ncPointTrigger::Restore(string strKey, string strValue)
{
switch (strKey) {
default:
super::Restore(strKey, strValue);
break;
}
}
#endif

View file

@ -49,7 +49,7 @@ ncPortal::ncPortal(void)
}
/* default fallback */
precache_model("models/b_portal.bsp");
precache.Model("models/b_portal.bsp");
SetPortalModel("models/b_portal.bsp");
#endif
}

View file

@ -476,6 +476,7 @@ ncSurfacePropEntity::SpawnKey(string keyName, string setValue)
else
DisableBleeding();
break;
case "health":
max_health = health = ReadFloat(setValue);
m_oldHealth = health;
@ -501,7 +502,6 @@ ncSurfacePropEntity::SpawnKey(string keyName, string setValue)
}
}
void
ncSurfacePropEntity::Pain(entity inflictor, entity attacker, int damage, vector dir, vector absImpactPos, int hitBody)
{

View file

@ -251,8 +251,8 @@ ncWeapon::Spawned(void)
}
m_bInvCarry = true;
precache_model(m_strWeaponViewModel);
precache_model(m_strWeaponPlayerModel);
precache.Model(m_strWeaponViewModel);
precache.Model(m_strWeaponPlayerModel);
SetViewModel(m_strWeaponViewModel);
SetWorldModel(model);

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016-2024 Vera Visions LLC.
* Copyright (c) 2016-2025 Vera Visions LLC.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -367,8 +367,40 @@ entityDefAPI_t entityDef;
typedef struct
{
float Model(string);
float Sound(string);
/** Precaches a given model file and additional helper files.
`precache.Model("models/weapons/v_pistol.vvm");`
@param pathToModel to precache
@return modelindex value. */
float Model(string pathToModel);
/** Precaches a given sound def or sample.
`precache.Sound("Foo.Bar");`
`precache.Sound("foo/bar.wav");`
@param soundDef to precache
@return sound def id. */
float Sound(string soundDef);
/** Precaches a given particle effect.
The following loads `r_part impactSpark` from `particles/weapon_laser.cfg`.
`precache.Particle("weapon_laser.impactSpark");
@param particleEffect to precache
@return particle effect num. */
float Particle(string particleEffect);
/** Precaches a given entity class.
Ensuring models, sounds and other assets referenced
within are loaded ahead of time.
@param className to precache
@return Success. */
bool Entity(string className);
} precacheAPI_t;
precacheAPI_t precache;
@ -553,6 +585,8 @@ _shared_main(void)
precache.Model = linkToSharedProgs("SHPF_precache_Model");
precache.Sound = linkToSharedProgs("SHPF_precache_Sound");
precache.Particle = linkToSharedProgs("SHPF_precache_Particle");
precache.Entity = linkToSharedProgs("EntityDef_Precache");
soundKit.Play = linkToSharedProgs("SHPF_sounds_Play");

View file

@ -892,6 +892,17 @@ void
sendInput(entity target, string inputName, string dataString, entity activator)
{
ncEntity targetEntity = (ncEntity)target;
if (!target) {
NSError("target entity is nil");
return;
}
if (!STRING_SET(inputName)) {
NSError("No input specified.");
return;
}
#ifdef SERVER
targetEntity.Input(activator, inputName, dataString);
#endif
@ -901,6 +912,10 @@ sendInput(entity target, string inputName, string dataString, entity activator)
bool
isAI(entity entityToCheck)
{
if (!entityToCheck) {
return (false);
}
if (entityToCheck.flags & FL_MONSTER) {
return (true);
}
@ -911,6 +926,10 @@ isAI(entity entityToCheck)
bool
isAlive(entity entityToCheck)
{
if (!entityToCheck) {
return (false);
}
#ifdef SERVER
if (entityToCheck.takedamage != DAMAGE_NO) {
ncSurfacePropEntity livingEnt = (ncSurfacePropEntity)entityToCheck;
@ -924,6 +943,10 @@ isAlive(entity entityToCheck)
bool
isGodMode(entity entityToCheck)
{
if (!entityToCheck) {
return (false);
}
if (entityToCheck.flags & FL_GODMODE) {
return (true);
}
@ -934,6 +957,10 @@ isGodMode(entity entityToCheck)
bool
isClient(entity entityToCheck)
{
if (!entityToCheck) {
return (false);
}
return (entityToCheck.flags & FL_CLIENT) ? (true) : (false);
}
@ -961,18 +988,30 @@ isSentient(entity entityToCheck)
bool
isBot(entity entityToCheck)
{
return userinfo.GetBool(self, "*bot");
if (!entityToCheck) {
return (false);
}
return userinfo.GetBool(entityToCheck, "*bot");
}
bool
isWeapon(entity entityToCheck)
{
if (!entityToCheck) {
return (false);
}
return (entityToCheck._isWeapon) ? (true) : (false);
}
bool
isItem(entity entityToCheck)
{
if (!entityToCheck) {
return (false);
}
return (entityToCheck._isItem) ? (true) : (false);
}
@ -1011,15 +1050,33 @@ SHPF_entityDef_GetVector(string declName, string keyName)
int
SHPF_precache_Model(string modelPath)
{
if (!STRING_SET(modelPath)) {
return (0i);
}
precache_model(modelPath);
PropData_ForModel(modelPath);
return (int)getmodelindex(modelPath, false);
}
int
SHPF_precache_Sound(string modelPath)
SHPF_precache_Sound(string soundDecl)
{
return (int)Sound_Precache(modelPath);
if (!STRING_SET(soundDecl)) {
return (-1i);
}
return (int)Sound_Precache(soundDecl);
}
int
SHPF_precache_Particle(string particleName)
{
if (!STRING_SET(particleName)) {
return (0i);
}
return (int)particleeffectnum(particleName);
}
void

View file

@ -439,23 +439,41 @@ EntityDef_PrepareEntity(entity target, int id)
static void
EntityDef_Precaches(int index)
{
if (time > 2.0f) {
return;
}
for (int i = 0; i < tokenize_console(g_entDefTable[index].spawnData); i+= 2) {
string strKey = argv(i);
string strValue = argv(i+1);
if (substring(strKey, 0, 4) == "snd_") {
Sound_Precache(strValue);
precache.Sound(strValue);
} else if (substring(strKey, 0, 6) == "smoke_") {
particleeffectnum(strValue);
} else if (strKey == "model_detonate") {
particleeffectnum(strValue);
} else if (substring(strKey, 0, 4) == "def_") {
} else if (strKey == "model") {
precache.Model(strValue);
} else if (substring(strKey, 0, 6) == "model_") {
precache.Model(strValue);
} else if (substring(strKey, 0, 4) == "def_" || (strKey == "item")) {
int defID = EntityDef_IDFromName(strValue);
/* only precache valid def, and avoid recursion */
if (defID != -1 && defID != index) {
EntityDef_Precaches(defID);
}
} else if (strKey == "weapon") {
for (int w = 0; w < tokenizebyseparator(strValue, ","); w++) {
string weaponName = argv(w);
int defID = EntityDef_IDFromName(weaponName);
/* only precache valid def, and avoid recursion */
if (defID != -1 && defID != index) {
EntityDef_Precaches(defID);
}
}
}
}
@ -506,11 +524,7 @@ EntityDef_NewClassname(string className)
for (int i = 0i; i < g_entDefCount; i++) {
if (className == g_entDefTable[i].entClass) {
if (time < 5.0) {
EntityDef_Precaches(i);
}
NSLog("Spawning eDef %S", className);
EntityDef_Precache(className);
return EntityDef_PrepareEntity(self, i);
}
}
@ -529,11 +543,7 @@ EntityDef_SpawnClassname(string className)
for (int i = 0i; i < g_entDefCount; i++) {
if (className == g_entDefTable[i].entClass) {
if (time < 5.0) {
EntityDef_Precaches(i);
}
NSLog("Spawning eDef %S", className);
EntityDef_Precache(className);
return EntityDef_PrepareEntity(self, i);
}
}
@ -549,11 +559,7 @@ EntityDef_SwitchClass(ncEntity target, string className)
for (int i = 0i; i < g_entDefCount; i++) {
if (className == g_entDefTable[i].entClass) {
if (time < 5.0) {
EntityDef_Precaches(i);
}
NSLog("Spawning eDef %S", className);
EntityDef_Precache(className);
returnEntity = EntityDef_PrepareEntity(target, i);
return (returnEntity);
}

View file

@ -77,7 +77,7 @@ PropData_PrecacheGib(string modelPath)
}
tokenizebyseparator(modelPath, "#");
precache_model(argv(0));
precache.Model(argv(0));
}
void
@ -401,14 +401,17 @@ PropData_ForModel(string modelname)
string line;
int index;
if (!g_propdata_count)
if (!g_propdata_count) {
return -1;
}
if (!modelname)
if (!modelname) {
return -1;
}
if (substring(modelname, 0, 1) == "*")
if (substring(modelname, 0, 1) == "*") {
return -1;
}
index = g_propdata_count;
modelname = strtolower(modelname);
@ -460,12 +463,13 @@ PropData_ForModel(string modelname)
/* not found. try again? */
if (fh < 0) {
/* try the Source Engine version */
fh = fopen(Util_ChangeExtension(modelname, "phy"), FILE_READ);
string binaryFile = Util_ChangeExtension(modelname, "phy");
fh = fopen(binaryFile, FILE_READ);
if (fh < 0) {
g_propdata_count--;
NSLog("No PropData for model %S", modelname);
return -1;
return -1i;
}
int fileSize;
@ -478,7 +482,7 @@ PropData_ForModel(string modelname)
filePos = fread(fh, (void*)&fileSize, 4i); /* header size, sanity check */
if (fileSize != 16i) {
NSError("Only .phy files from Source are supported.");
NSError("%s: not in Source Engine format", binaryFile);
fclose(fh);
return -1;
}
@ -494,7 +498,7 @@ PropData_ForModel(string modelname)
/* HACK: We won't support ragdolls, for now. */
if (numSolids > 1) {
NSError("Only non-ragdoll models are currently supported.");
NSError("%s: ragdoll models not supported", binaryFile);
fclose(fh);
return -1;
}
@ -608,19 +612,23 @@ PropData_Load(string type)
{
int index;
if (!type)
return -1;
if (g_propdata_count <= 0i) {
return -1i;
}
if (substring(type, 0, 1) == "*")
return -1;
if (!type) {
return -1i;
}
if (substring(type, 0, 1) == "*") {
return -1i;
}
type = strtolower(type);
index = (int)hash_get(g_hashpropdata, type, -1);
if (index < 0) {
NSLog("PropData type %S is not defined.", type);
return -1;
if (index < 0i) {
return -1i;
} else {
return index;
}
@ -883,7 +891,7 @@ PropData_Init(void)
mname = argv(0);
}
precache_model(mname);
precache.Model(mname);
/* gotta tokenize our inputs again */
x = tokenize(g_breakmodel[i].data);
@ -1025,8 +1033,7 @@ BreakModel_SpawnID(vector smins, vector smaxs, vector dir, float speed, int coun
if (usePhysics == false) {
gib.SetSize([-8,-8,-8],[8,8,8]);
makevectors(dir);
gib.velocity = (v_forward * speed) * 0.75;
gib.velocity = (dir * speed) * 0.75;
gib.velocity[0] += (random() - 0.5) * (speed * 0.25);
gib.velocity[1] += (random() - 0.5) * (speed * 0.25);
gib.velocity[2] += (random() - 0.5) * (speed * 0.25);
@ -1083,9 +1090,9 @@ BreakModel_Receive(void)
smaxs[1] = readcoord();
smaxs[2] = readcoord();
dir[0] = readcoord();
dir[1] = readcoord();
dir[2] = readcoord();
dir[0] = readfloat();
dir[1] = readfloat();
dir[2] = readfloat();
speed = readfloat();
count = readbyte();
@ -1158,9 +1165,9 @@ BreakModel_Spawn(vector smins, vector smaxs, vector dir, float speed, int count,
WriteCoord(MSG_MULTICAST, smaxs[0]);
WriteCoord(MSG_MULTICAST, smaxs[1]);
WriteCoord(MSG_MULTICAST, smaxs[2]);
WriteCoord(MSG_MULTICAST, dir[0]);
WriteCoord(MSG_MULTICAST, dir[1]);
WriteCoord(MSG_MULTICAST, dir[2]);
WriteFloat(MSG_MULTICAST, dir[0]);
WriteFloat(MSG_MULTICAST, dir[1]);
WriteFloat(MSG_MULTICAST, dir[2]);
WriteFloat(MSG_MULTICAST, speed);
WriteByte(MSG_MULTICAST, count);
multicast(pvsPosition, MULTICAST_PVS);

View file

@ -238,10 +238,10 @@ Sound_ParseField(int i, int a, string keyName, string valueCS)
g_sounds[i].flags |= SNDFL_STEP;
break;
case "distshader":
g_sounds[i].distshader = setValue;
g_sounds[i].distshader = valueCS;
break;
case "pointparticle":
g_sounds[i].pointparticle = particleeffectnum(setValue);
g_sounds[i].pointparticle = particleeffectnum(valueCS);
break;
case "alerts":
dprint("\tSound set to alert enemy AI\n");
@ -422,8 +422,14 @@ Sound_Precache(string shader)
string line;
int index;
if (!shader)
return -1;
if (!STRING_SET(shader)) {
return -1i;
}
if (fileExists(strcat("sound/", shader)) == true) {
precache_sound(shader);
return -1i;
}
index = g_sounds_count;

91
src/vgui/Widget.h Normal file
View file

@ -0,0 +1,91 @@
/** @brief The base VGUI widget class.
Every VGUI widget is based off of this. */
class vguiWidget
{
public:
void vguiWidget(void);
/** Adds a widget into this one. */
virtual void Add(vguiWidget);
/** Add a flag to the widget. */
nonvirtual void FlagAdd(int);
/** Remove a flag from the widget. */
nonvirtual void FlagRemove(int);
/** Check if the vguiWidget has a flag attached. */
nonvirtual bool HasFlag(int);
/** Set the position within its context. */
nonvirtual void SetPos(vector);
/** Return the position of the widget within its context. */
nonvirtual vector GetPos(void);
/** Returns the X coordinate of the widget position within its context. */
nonvirtual int GetPosWidth(void);
/** Returns the Y coordinate of the widget position within its context. */
nonvirtual int GetPosHeight(void);
/** Set the size of the widget to a new one. */
nonvirtual void SetSize(vector);
/** Returns the size of the widget, in pixels. */
nonvirtual vector GetSize(void);
/** Returns the width of the widget, in pixels. */
nonvirtual int GetWidth(void);
/** Returns the height of the widget, in pixels. */
nonvirtual int GetHeight(void);
/** Sets the minimum size of the widget. */
nonvirtual void SetMinSize(vector);
/** Returns the minimum size of the widget. */
nonvirtual vector GetMinSize(void);
/** Sets the maximum size of the widget. */
nonvirtual void SetMaxSize(vector);
/** Returns the maximum size of the widget. */
nonvirtual vector GetMaxSize(void);
/** Returns true/false depending on if the widget is visible. */
nonvirtual bool Visible(void);
/** Show the widget. */
nonvirtual void Show(void);
/** Hide the widget. */
nonvirtual void Hide(void);
/** Sets the vguiTheme to use on this widget (and any children it may have) */
nonvirtual void SetTheme(vguiTheme);
/** Returns the VGUI that will be used on this widget. */
nonvirtual vguiTheme GetTheme(void);
/** Called when the position of the widget was changed in any capacity. */
virtual void PositionChanged(vector, vector);
/** Called when the size of the widget has changed in any capacity. */
virtual void SizeChanged(vector, vector);
virtual void NowVisible(void);
virtual void NowHidden(void);
/** Called in order to draw the widget. */
virtual void Draw(void);
/** Called whenever the physical properties of the display change. */
virtual void Reposition(void);
/** Called whenever an input event gets directed to the widget. */
virtual bool Input(float, float, float, float);
/** Called when the widget has fully initialized.
When you override this, you may call `super::Spawned();` to ensure
the parent classes get to finish initializing also. */
virtual void Spawned(void);
private:
/* why are these 3D vectors? because drawpic() etc. take it. ..you never know what that may be used for some day! */
vector m_vecOrigin;
vector m_vecSize;
vector m_vecMinSize;
vector m_vecMaxSize;
vguiWidget m_next;
vguiWidget m_parent;
vguiWidget m_children;
int m_iFlags;
bool m_bVisible;
vguiTheme m_theme;
};

277
src/vgui/Widget.qc Normal file
View file

@ -0,0 +1,277 @@
void
vguiWidget::vguiWidget(void)
{
m_vecOrigin = [0.0f, 0.0f];
m_vecSize = [0.0f, 0.0f];
m_vecMinSize = [0.0f, 0.0f];
m_vecMaxSize = [9999.0f, 9999.0f];
m_next = __NULL__;
m_parent = __NULL__;
m_iFlags = 0i;
m_bVisible = true;
isVGUI = true;
Spawned();
}
void
vguiWidget::SetTheme(vguiTheme theme)
{
m_theme = theme;
}
vguiTheme
vguiWidget::GetTheme(void)
{
/* if no theme set, but we have a parent... inherit the parents' theme recursively */
if (!m_theme && m_parent) {
return m_parent.GetTheme();
}
/* we have nothing, use the default one. */
if (!m_theme) {
m_theme = spawn(vguiTheme);
}
return (m_theme);
}
bool
vguiWidget::Visible(void)
{
return (m_bVisible);
}
void
vguiWidget::Hide(void)
{
m_bVisible = false;
NowHidden();
}
void
vguiWidget::NowHidden(void)
{
}
void
vguiWidget::NowVisible(void)
{
}
void
vguiWidget::Show(void)
{
m_bVisible = true;
NowVisible();
}
void
vguiWidget::PositionChanged(vector vecOld, vector vecNew)
{
}
void
vguiWidget::SizeChanged(vector vecOld, vector vecNew)
{
}
void
vguiWidget::SetPos(vector vecNewPos)
{
vector vecOld = m_vecOrigin;
m_vecOrigin[0] = bound(0, vecNewPos[0], 9999.0);
m_vecOrigin[1] = bound(0, vecNewPos[1], 9999.0);
PositionChanged(vecOld, m_vecOrigin);
}
vector
vguiWidget::GetPos(void)
{
return (m_vecOrigin);
}
int
vguiWidget::GetPosWidth(void)
{
return (m_vecOrigin[0]);
}
int
vguiWidget::GetPosHeight(void)
{
return (m_vecOrigin[1]);
}
void
vguiWidget::SetSize(vector vecNewSize)
{
vector vecOld = m_vecSize;
m_vecSize[0] = bound(m_vecMinSize[0], vecNewSize[0], m_vecMaxSize[0]);
m_vecSize[1] = bound(m_vecMinSize[1], vecNewSize[1], m_vecMaxSize[1]);
SizeChanged(vecOld, m_vecSize);
}
vector
vguiWidget::GetSize(void)
{
return (m_vecSize);
}
int
vguiWidget::GetWidth(void)
{
return (m_vecSize[0]);
}
int
vguiWidget::GetHeight(void)
{
return (m_vecSize[1]);
}
void
vguiWidget::SetMinSize (vector vecNewSize)
{
m_vecMinSize = vecNewSize;
}
vector
vguiWidget::GetMinSize(void)
{
return (m_vecMinSize);
}
void
vguiWidget::SetMaxSize (vector vecNewSize)
{
m_vecMaxSize = vecNewSize;
}
vector
vguiWidget::GetMaxSize(void)
{
return (m_vecMaxSize);
}
void
vguiWidget::FlagAdd(int iFlag)
{
m_iFlags |= iFlag;
}
void
vguiWidget::FlagRemove(int iFlag)
{
m_iFlags -= (m_iFlags & iFlag);
}
bool
vguiWidget::HasFlag(int flag)
{
return (m_iFlags & flag) ? (true) : (false);
}
void
vguiWidget::Reposition(void)
{
vguiWidget wNext = this;
do {
wNext = wNext.m_next;
if (wNext) {
wNext.Reposition();
}
} while (wNext);
}
void
vguiWidget::Add(vguiWidget wNew)
{
vguiWidget wNext = this;
vguiWidget wParent;
do {
wParent = wNext;
wNext = wNext.m_next;
} while (wNext);
wParent.m_next = wNew;
wNew.m_parent = this;
}
void
vguiWidget::Draw(void)
{
vguiWidget wNext = this;
g_vguiWidgetCount = 0;
do {
wNext = wNext.m_next;
if (wNext && wNext.Visible() && wNext.m_parent.Visible()) {
g_vguiWidgetCount++;
wNext.Draw();
}
} while (wNext);
}
bool
vguiWidget::Input(float flEVType, float flKey, float flChar, float flDevID)
{
vguiWidget wNext = this;
vguiWidget wLast = __NULL__;
vguiWidget wLastBefore = __NULL__;
/* figure out the last window in the chain... */
do {
wLastBefore = wNext;
wNext = wNext.m_next;
if (wNext) {
wLast = wNext;
}
} while (wNext);
//print(sprintf("Last widget: %S\n", wLast.classname));
/* we've found a window, let's test inputs backwards. */
while (wLast.classname) {
bool test = false;
if (wLast.Visible())
test = wLast.Input(flEVType, flKey, flChar, flDevID);
//print(sprintf("Testing input for... widget: %S %d\n", wLast.classname, test));
/* input successful */
if (test == true) {
return (true);
}
/* select the former input */
for (vguiWidget a = this; a != __NULL__; a = a.m_next) {
/* we've reached the end, take one from before */
if (a == wLast) {
wLast = wLastBefore;
break;
}
wLastBefore = a;
}
/* the end of the world. */
if (wLast == this)
return (false);
}
return (false);
}
void
vguiWidget::Spawned(void)
{
}

View file

@ -1,28 +1,29 @@
#includelist
../vgui/ui_color.qc
../vgui/ui_theme.qc
../vgui/Color.qc
../vgui/Theme.qc
../vgui/ui.qc
../vgui/ui_control.qc
../vgui/ui_button.qc
../vgui/ui_commandbutton.qc
../vgui/ui_menubutton.qc
../vgui/ui_radio.qc
../vgui/ui_checkbox.qc
../vgui/ui_view.qc
../vgui/ui_window.qc
../vgui/ui_frame.qc
../vgui/ui_label.qc
../vgui/ui_menutitle.qc
../vgui/ui_pic.qc
../vgui/ui_rect.qc
../vgui/ui_3dview.qc
../vgui/ui_scrollbar.qc
../vgui/ui_list.qc
../vgui/ui_listbox.qc
../vgui/ui_textbox.qc
../vgui/ui_tabviewitem.qc
../vgui/ui_tabview.qc
../vgui/ui_progressbar.qc
../vgui/ui_loadingpanel.qc
../vgui/ui_textview.qc
../vgui/Widget.qc
../vgui/Control.qc
../vgui/Button.qc
../vgui/CommandButton.qc
../vgui/MenuButton.qc
../vgui/Radio.qc
../vgui/CheckBox.qc
../vgui/View.qc
../vgui/Window.qc
../vgui/Frame.qc
../vgui/Label.qc
../vgui/MenuTitle.qc
../vgui/Pic.qc
../vgui/Rect.qc
../vgui/3DView.qc
../vgui/ScrollBar.qc
../vgui/List.qc
../vgui/ListBox.qc
../vgui/TextBox.qc
../vgui/TabViewItem.qc
../vgui/TabView.qc
../vgui/ProgressBar.qc
../vgui/LoadingPanel.qc
../vgui/TextView.qc
#endlist

View file

@ -16,6 +16,8 @@
#warning vguiWidget needs methods to deal with .res/.gui type files.
#include "Widget.h"
.string classname;
.bool isVGUI;
@ -119,376 +121,6 @@ Util_MouseAbove(vector vecMousePos, vector vecPos, vector vecSize)
return (false);
}
/** @brief The base VGUI widget class.
Every VGUI widget is based off of this. */
class vguiWidget
{
public:
void vguiWidget(void);
/** Adds a widget into this one. */
virtual void Add(vguiWidget);
/** Add a flag to the widget. */
nonvirtual void FlagAdd(int);
/** Remove a flag from the widget. */
nonvirtual void FlagRemove(int);
/** Check if the vguiWidget has a flag attached. */
nonvirtual bool HasFlag(int);
/** Set the position within its context. */
nonvirtual void SetPos(vector);
/** Return the position of the widget within its context. */
nonvirtual vector GetPos(void);
/** Returns the X coordinate of the widget position within its context. */
nonvirtual int GetPosWidth(void);
/** Returns the Y coordinate of the widget position within its context. */
nonvirtual int GetPosHeight(void);
/** Set the size of the widget to a new one. */
nonvirtual void SetSize(vector);
/** Returns the size of the widget, in pixels. */
nonvirtual vector GetSize(void);
/** Returns the width of the widget, in pixels. */
nonvirtual int GetWidth(void);
/** Returns the height of the widget, in pixels. */
nonvirtual int GetHeight(void);
/** Sets the minimum size of the widget. */
nonvirtual void SetMinSize(vector);
/** Returns the minimum size of the widget. */
nonvirtual vector GetMinSize(void);
/** Sets the maximum size of the widget. */
nonvirtual void SetMaxSize(vector);
/** Returns the maximum size of the widget. */
nonvirtual vector GetMaxSize(void);
/** Returns true/false depending on if the widget is visible. */
nonvirtual bool Visible(void);
/** Show the widget. */
nonvirtual void Show(void);
/** Hide the widget. */
nonvirtual void Hide(void);
/** Sets the vguiTheme to use on this widget (and any children it may have) */
nonvirtual void SetTheme(vguiTheme);
/** Returns the VGUI that will be used on this widget. */
nonvirtual vguiTheme GetTheme(void);
/** Called when the position of the widget was changed in any capacity. */
virtual void PositionChanged(vector, vector);
/** Called when the size of the widget has changed in any capacity. */
virtual void SizeChanged(vector, vector);
virtual void NowVisible(void);
virtual void NowHidden(void);
/** Called in order to draw the widget. */
virtual void Draw(void);
/** Called whenever the physical properties of the display change. */
virtual void Reposition(void);
/** Called whenever an input event gets directed to the widget. */
virtual bool Input(float, float, float, float);
/** Called when the widget has fully initialized.
When you override this, you may call `super::Spawned();` to ensure
the parent classes get to finish initializing also. */
virtual void Spawned(void);
private:
/* why are these 3D vectors? because drawpic() etc. take it. ..you never know what that may be used for some day! */
vector m_vecOrigin;
vector m_vecSize;
vector m_vecMinSize;
vector m_vecMaxSize;
vguiWidget m_next;
vguiWidget m_parent;
vguiWidget m_children;
int m_iFlags;
bool m_bVisible;
vguiTheme m_theme;
};
void
vguiWidget::vguiWidget(void)
{
m_vecOrigin = [0.0f, 0.0f];
m_vecSize = [0.0f, 0.0f];
m_vecMinSize = [0.0f, 0.0f];
m_vecMaxSize = [9999.0f, 9999.0f];
m_next = __NULL__;
m_parent = __NULL__;
m_iFlags = 0i;
m_bVisible = true;
isVGUI = true;
Spawned();
}
void
vguiWidget::SetTheme(vguiTheme theme)
{
m_theme = theme;
}
vguiTheme
vguiWidget::GetTheme(void)
{
/* if no theme set, but we have a parent... inherit the parents' theme recursively */
if (!m_theme && m_parent) {
return m_parent.GetTheme();
}
/* we have nothing, use the default one. */
if (!m_theme) {
m_theme = spawn(vguiTheme);
}
return (m_theme);
}
bool
vguiWidget::Visible(void)
{
return (m_bVisible);
}
void
vguiWidget::Hide(void)
{
m_bVisible = false;
NowHidden();
}
void
vguiWidget::NowHidden(void)
{
}
void
vguiWidget::NowVisible(void)
{
}
void
vguiWidget::Show(void)
{
m_bVisible = true;
NowVisible();
}
void
vguiWidget::PositionChanged(vector vecOld, vector vecNew)
{
}
void
vguiWidget::SizeChanged(vector vecOld, vector vecNew)
{
}
void
vguiWidget::SetPos(vector vecNewPos)
{
vector vecOld = m_vecOrigin;
m_vecOrigin[0] = bound(0, vecNewPos[0], 9999.0);
m_vecOrigin[1] = bound(0, vecNewPos[1], 9999.0);
PositionChanged(vecOld, m_vecOrigin);
}
vector
vguiWidget::GetPos(void)
{
return (m_vecOrigin);
}
int
vguiWidget::GetPosWidth(void)
{
return (m_vecOrigin[0]);
}
int
vguiWidget::GetPosHeight(void)
{
return (m_vecOrigin[1]);
}
void
vguiWidget::SetSize(vector vecNewSize)
{
vector vecOld = m_vecSize;
m_vecSize[0] = bound(m_vecMinSize[0], vecNewSize[0], m_vecMaxSize[0]);
m_vecSize[1] = bound(m_vecMinSize[1], vecNewSize[1], m_vecMaxSize[1]);
SizeChanged(vecOld, m_vecSize);
}
vector
vguiWidget::GetSize(void)
{
return (m_vecSize);
}
int
vguiWidget::GetWidth(void)
{
return (m_vecSize[0]);
}
int
vguiWidget::GetHeight(void)
{
return (m_vecSize[1]);
}
void
vguiWidget::SetMinSize (vector vecNewSize)
{
m_vecMinSize = vecNewSize;
}
vector
vguiWidget::GetMinSize(void)
{
return (m_vecMinSize);
}
void
vguiWidget::SetMaxSize (vector vecNewSize)
{
m_vecMaxSize = vecNewSize;
}
vector
vguiWidget::GetMaxSize(void)
{
return (m_vecMaxSize);
}
void
vguiWidget::FlagAdd(int iFlag)
{
m_iFlags |= iFlag;
}
void
vguiWidget::FlagRemove(int iFlag)
{
m_iFlags -= (m_iFlags & iFlag);
}
bool
vguiWidget::HasFlag(int flag)
{
return (m_iFlags & flag) ? (true) : (false);
}
void
vguiWidget::Reposition(void)
{
vguiWidget wNext = this;
do {
wNext = wNext.m_next;
if (wNext) {
wNext.Reposition();
}
} while (wNext);
}
void
vguiWidget::Add(vguiWidget wNew)
{
vguiWidget wNext = this;
vguiWidget wParent;
do {
wParent = wNext;
wNext = wNext.m_next;
} while (wNext);
wParent.m_next = wNew;
wNew.m_parent = this;
}
void
vguiWidget::Draw(void)
{
vguiWidget wNext = this;
g_vguiWidgetCount = 0;
do {
wNext = wNext.m_next;
if (wNext && wNext.Visible() && wNext.m_parent.Visible()) {
g_vguiWidgetCount++;
wNext.Draw();
}
} while (wNext);
}
bool
vguiWidget::Input(float flEVType, float flKey, float flChar, float flDevID)
{
vguiWidget wNext = this;
vguiWidget wLast = __NULL__;
vguiWidget wLastBefore = __NULL__;
/* figure out the last window in the chain... */
do {
wLastBefore = wNext;
wNext = wNext.m_next;
if (wNext) {
wLast = wNext;
}
} while (wNext);
//print(sprintf("Last widget: %S\n", wLast.classname));
/* we've found a window, let's test inputs backwards. */
while (wLast.classname) {
bool test = false;
if (wLast.Visible())
test = wLast.Input(flEVType, flKey, flChar, flDevID);
//print(sprintf("Testing input for... widget: %S %d\n", wLast.classname, test));
/* input successful */
if (test == true) {
return (true);
}
/* select the former input */
for (vguiWidget a = this; a != __NULL__; a = a.m_next) {
/* we've reached the end, take one from before */
if (a == wLast) {
wLast = wLastBefore;
break;
}
wLastBefore = a;
}
/* the end of the world. */
if (wLast == this)
return (false);
}
return (false);
}
void
vguiWidget::Spawned(void)
{
}
void
UISystem_Init(void)
{