#include <client/mapvoting.qc>
#include <client/miscfunctions.qc>
#include <client/player_skeleton.qc>
+#include <client/resources.qc>
#include <client/shownames.qc>
#include <client/teamradar.qc>
#include <client/view.qc>
#include <client/mapvoting.qh>
#include <client/miscfunctions.qh>
#include <client/player_skeleton.qh>
+#include <client/resources.qh>
#include <client/shownames.qh>
#include <client/teamradar.qh>
#include <client/view.qh>
IL_EACH(g_radaricons, it.teamradar_icon, {
if ( hud_panel_radar_mouse )
- if ( it.health >= 0 )
+ if ( GetResourceAmount(it, RESOURCE_HEALTH) >= 0 )
if ( it.team == myteam + 1 || gametype == MAPINFO_TYPE_RACE || !teamplay )
{
vector coord = teamradar_texcoord_to_2dcoord(teamradar_3dcoord_to_texcoord(it.origin));
vector Rotate(vector v, float a);
-#define IS_DEAD(s) (((s).classname == "csqcmodel") ? (s).csqcmodel_isdead : ((s).health <= 0))
+#define IS_DEAD(s) (((s).classname == "csqcmodel") ? (s).csqcmodel_isdead : (GetResourceAmount((s), RESOURCE_HEALTH) <= 0))
// decolorizes and team colors the player name when needed
--- /dev/null
+#include "resources.qh"
+
+/// \file
+/// \brief Source file that contains implementation of the resource system.
+/// \copyright GNU GPLv2 or any later version.
+
+float GetResourceAmount(entity e, int resource_type)
+{
+ .float resource_field = GetResourceField(resource_type);
+ return e.(resource_field);
+}
+
+bool SetResourceAmountExplicit(entity e, int resource_type, float amount)
+{
+ .float resource_field = GetResourceField(resource_type);
+ if (e.(resource_field) != amount)
+ {
+ e.(resource_field) = amount;
+ return true;
+ }
+ return false;
+}
+
+void SetResourceAmount(entity e, int resource_type, float amount)
+{
+ SetResourceAmountExplicit(e, resource_type, amount);
+}
+
+int GetResourceType(.float resource_field)
+{
+ switch (resource_field)
+ {
+ case health: { return RESOURCE_HEALTH; }
+ case armorvalue: { return RESOURCE_ARMOR; }
+ case ammo_shells: { return RESOURCE_SHELLS; }
+ case ammo_nails: { return RESOURCE_BULLETS; }
+ case ammo_rockets: { return RESOURCE_ROCKETS; }
+ case ammo_cells: { return RESOURCE_CELLS; }
+ case ammo_plasma: { return RESOURCE_PLASMA; }
+ case ammo_fuel: { return RESOURCE_FUEL; }
+ }
+ error("GetResourceType: Invalid field.");
+ return 0;
+}
+
+.float GetResourceField(int resource_type)
+{
+ switch (resource_type)
+ {
+ case RESOURCE_HEALTH: { return health; }
+ case RESOURCE_ARMOR: { return armorvalue; }
+ case RESOURCE_SHELLS: { return ammo_shells; }
+ case RESOURCE_BULLETS: { return ammo_nails; }
+ case RESOURCE_ROCKETS: { return ammo_rockets; }
+ case RESOURCE_CELLS: { return ammo_cells; }
+ case RESOURCE_PLASMA: { return ammo_plasma; }
+ case RESOURCE_FUEL: { return ammo_fuel; }
+ }
+ error("GetResourceField: Invalid resource type.");
+ return health;
+}
--- /dev/null
+#pragma once
+
+/// \file
+/// \brief Header file that describes the resource system.
+/// \copyright GNU GPLv2 or any later version.
+
+#include <common/resources.qh>
+
+/// \brief Unconditional maximum amount of resources the entity can have.
+const int RESOURCE_AMOUNT_HARD_LIMIT = 999;
+
+// ============================ Public API ====================================
+
+/// \brief Returns the current amount of resource the given entity has.
+/// \param[in] e Entity to check.
+/// \param[in] resource_type Type of the resource (a RESOURCE_* constant).
+/// \return Current amount of resource the given entity has.
+float GetResourceAmount(entity e, int resource_type);
+
+/// \brief Sets the resource amount of an entity without calling any hooks.
+/// \param[in,out] e Entity to adjust.
+/// \param[in] resource_type Type of the resource (a RESOURCE_* constant).
+/// \param[in] amount Amount of resource to set.
+/// \return Boolean for whether the ammo amount was changed
+bool SetResourceAmountExplicit(entity e, int resource_type, float amount);
+
+/// \brief Sets the current amount of resource the given entity will have.
+/// \param[in,out] e Entity to adjust.
+/// \param[in] resource_type Type of the resource (a RESOURCE_* constant).
+/// \param[in] amount Amount of resource to set.
+/// \return No return.
+void SetResourceAmount(entity e, int resource_type, float amount);
+
+// ===================== Legacy and/or internal API ===========================
+
+/// \brief Converts an entity field to resource type.
+/// \param[in] resource_field Entity field to convert.
+/// \return Resource type (a RESOURCE_* constant).
+int GetResourceType(.float resource_field);
+
+/// \brief Converts resource type (a RESOURCE_* constant) to entity field.
+/// \param[in] resource_type Type of the resource.
+/// \return Entity field for that resource.
+.float GetResourceField(int resource_type);
this.healthvalue / autocvar_hud_panel_healtharmor_maxhealth, false, 1, '1 0 0', a,
DRAWFLAG_NORMAL);
}
- if (this.armorvalue > 0)
+ if (GetResourceAmount(this, RESOURCE_ARMOR) > 0)
{
HUD_Panel_DrawProgressBar(pos + eX * 0.5 * mySize.x, sz, "nametag_statusbar",
- this.armorvalue / autocvar_hud_panel_healtharmor_maxarmor, false, 0, '0 1 0', a,
+ GetResourceAmount(this, RESOURCE_ARMOR) / autocvar_hud_panel_healtharmor_maxarmor, false, 0, '0 1 0', a,
DRAWFLAG_NORMAL);
}
}
if (entcs.m_entcs_private)
{
it.healthvalue = entcs.healthvalue;
- it.armorvalue = entcs.armorvalue;
+ SetResourceAmountExplicit(it, RESOURCE_ARMOR, GetResourceAmount(entcs, RESOURCE_ARMOR));
it.sameteam = true;
}
else
{
it.healthvalue = 0;
- it.armorvalue = 0;
+ SetResourceAmountExplicit(it, RESOURCE_ARMOR, 0);
it.sameteam = false;
}
bool dead = entcs_IsDead(i) || entcs_IsSpectating(i);
CONSTRUCT(DebugText3d);
this.origin = pos;
this.message = strzone(msg);
- this.health = align;
+ SetResourceAmount(this, RESOURCE_HEALTH, align);
this.hit_time = time;
this.fade_rate = fade_rate_;
this.velocity = vel;
int size = 8;
vector screen_pos = project_3d_to_2d(this.origin) + since_created * this.velocity;
- float align = this.health;
+ float align = GetResourceAmount(this, RESOURCE_HEALTH);
if (align > 0)
screen_pos.x -= stringwidth(this.message, true, size * '1 1 0') * min(1, align);
if (screen_pos.z < 0) return; // behind camera
ENTCS_PROP_RESOURCE(ARMOR, false, RESOURCE_ARMOR, ENTCS_SET_NORMAL,
{ WriteByte(chan, bound(0, GetResourceAmount(ent, RESOURCE_ARMOR) / 10, 255)); /* FIXME: use a better scale? */ },
- { ent.armorvalue = ReadByte() * 10; })
+ { SetResourceAmountExplicit(ent, RESOURCE_ARMOR, ReadByte() * 10); })
ENTCS_PROP(NAME, true, netname, ENTCS_SET_MUTABLE_STRING,
{ WriteString(chan, ent.netname); },
this.cp_bob_spd = this.cp_bob_spd + 1.875 * frametime;
this.colormod = '1 1 1' * (2 - bound(0, (this.pain_finished - time) / 10, 1));
- if(!this.iscaptured) this.alpha = this.health / this.max_health;
+ if(!this.iscaptured) this.alpha = GetResourceAmount(this, RESOURCE_HEALTH) / this.max_health;
if(this.iscaptured)
{
this.origin = ReadVector();
setorigin(this, this.origin);
- this.health = ReadByte();
+ SetResourceAmountExplicit(this, RESOURCE_HEALTH, ReadByte());
this.max_health = ReadByte();
this.count = ReadByte();
this.team = ReadByte();
this.iscaptured = ReadByte();
if(!this.count)
- this.count = (this.health - this.max_health) * frametime;
+ this.count = (GetResourceAmount(this, RESOURCE_HEALTH) - this.max_health) * frametime;
cpicon_changeteam(this);
cpicon_construct(this, isnew);
_tmp = ReadByte();
- if(_tmp != this.health)
+ if(_tmp != GetResourceAmount(this, RESOURCE_HEALTH))
cpicon_damage(this, _tmp);
- this.health = _tmp;
+ SetResourceAmountExplicit(this, RESOURCE_HEALTH, _tmp);
}
}
if(time < this.move_time)
return;
- if(this.health > 0)
+ if(GetResourceAmount(this, RESOURCE_HEALTH) > 0)
{
// damaged fx (less probable the more damaged is the generator)
- if(random() < 0.9 - this.health / this.max_health)
+ if(random() < 0.9 - GetResourceAmount(this, RESOURCE_HEALTH) / this.max_health)
if(random() < 0.01)
{
pointparticles(EFFECT_ELECTRO_BALLEXPLODE, this.origin + randompos('-50 -50 -20', '50 50 50'), '0 0 0', 1);
this.origin = ReadVector();
setorigin(this, this.origin);
- this.health = ReadByte();
+ SetResourceAmountExplicit(this, RESOURCE_HEALTH, ReadByte());
this.max_health = ReadByte();
this.count = ReadByte();
this.team = ReadByte();
_tmp = ReadByte();
- if(_tmp != this.health)
+ if(_tmp != GetResourceAmount(this, RESOURCE_HEALTH))
generator_damage(this, _tmp);
- this.health = _tmp;
+ SetResourceAmountExplicit(this, RESOURCE_HEALTH, _tmp);
}
}
entity gen = NULL;
if(ons_roundlost)
{
- IL_EACH(g_onsgenerators, it.health <= 0,
+ IL_EACH(g_onsgenerators, GetResourceAmount(it, RESOURCE_HEALTH) <= 0,
{
gen = it;
break;
if (this.max_health)
{
this.takedamage = DAMAGE_YES;
- #ifdef SVQC
SetResourceAmountExplicit(this, RESOURCE_HEALTH, this.max_health);
- #elif defined(CSQC)
- this.health = this.max_health;
- #endif
}
this.state = STATE_DOWN;
if(this.spawnflags & NOSPLASH)
if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
return;
-#ifdef SVQC
SetResourceAmountExplicit(this, RESOURCE_HEALTH, GetResourceAmount(this, RESOURCE_HEALTH) - damage);
-#elif defined(CSQC)
- this.health -= damage;
-#endif
if (this.itemkeys)
{
return;
}
-#ifdef SVQC
if (GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
{
SetResourceAmountExplicit(this.owner, RESOURCE_HEALTH, this.owner.max_health);
this.owner.takedamage = DAMAGE_NO; // will be reset upon return
door_use(this.owner, NULL, NULL);
}
-#elif defined(CSQC)
- if(this.health <= 0)
- {
- this.owner.health = this.owner.max_health;
- this.owner.takedamage = DAMAGE_NO;
- door_use(this.owner, NULL, NULL);
- }
-#endif
}
.float door_finished;
void door_trigger_touch(entity this, entity toucher)
{
-#ifdef SVQC
if (GetResourceAmount(toucher, RESOURCE_HEALTH) < 1)
+#ifdef SVQC
if (!((toucher.iscreature || (toucher.flags & FL_PROJECTILE)) && !IS_DEAD(toucher)))
#elif defined(CSQC)
- if (toucher.health < 1)
if(!((IS_CLIENT(toucher) || toucher.classname == "csqcprojectile") && !IS_DEAD(toucher)))
#endif
return;
{
this.owner = this.enemy = this;
-#ifdef SVQC
if (GetResourceAmount(this, RESOURCE_HEALTH))
-#elif defined(CSQC)
- if(this.health)
-#endif
return;
IFTARGETED
return;
cmaxs = this.absmax;
for(t = this; ; t = t.enemy)
{
- #ifdef SVQC
if(GetResourceAmount(t, RESOURCE_HEALTH) && !GetResourceAmount(this, RESOURCE_HEALTH))
SetResourceAmountExplicit(this, RESOURCE_HEALTH, GetResourceAmount(t, RESOURCE_HEALTH));
- #elif defined(CSQC)
- if(t.health && !this.health)
- this.health = t.health;
- #endif
if((t.targetname != "") && (this.targetname == ""))
this.targetname = t.targetname;
if((t.message != "") && (this.message == ""))
// distribute health, targetname, message
for(t = this; t; t = t.enemy)
{
- #ifdef SVQC
SetResourceAmountExplicit(t, RESOURCE_HEALTH, GetResourceAmount(this, RESOURCE_HEALTH));
- #elif defined(CSQC)
- t.health = this.health;
- #endif
t.targetname = this.targetname;
t.message = this.message;
if(t.enemy == this)
// shootable, or triggered doors just needed the owner/enemy links,
// they don't spawn a field
-#ifdef SVQC
if (GetResourceAmount(this, RESOURCE_HEALTH))
-#elif defined(CSQC)
- if(this.health)
-#endif
return;
IFTARGETED
return;
if (this.max_health)
{
this.takedamage = DAMAGE_YES;
- #ifdef SVQC
SetResourceAmountExplicit(this, RESOURCE_HEALTH, this.max_health);
- #elif defined(CSQC)
- this.health = this.max_health;
- #endif
}
this.state = STATE_DOWN;
void swampslug_think(entity this)
{
//Slowly kill the slug
-#ifdef SVQC
SetResourceAmountExplicit(this, RESOURCE_HEALTH, GetResourceAmount(this, RESOURCE_HEALTH) - 1);
-#elif defined(CSQC)
- this.health -= 1;
-#endif
//Slug dead? then remove curses.
-#ifdef SVQC
if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
-#elif defined(CSQC)
- if(this.health <= 0)
-#endif
{
this.owner.in_swamp = 0;
delete(this);
// If not attach one.
//centerprint(toucher,"Entering swamp!\n");
toucher.swampslug = spawn();
- #ifdef SVQC
SetResourceAmountExplicit(toucher.swampslug, RESOURCE_HEALTH, 2);
- #elif defined(CSQC)
- toucher.swampslug.health = 2;
- #endif
setthink(toucher.swampslug, swampslug_think);
toucher.swampslug.nextthink = time;
toucher.swampslug.owner = toucher;
//toucher.in_swamp = 1;
//Revitalize players swampslug
-#ifdef SVQC
SetResourceAmountExplicit(toucher.swampslug, RESOURCE_HEALTH, 2);
-#elif defined(CSQC)
- toucher.swampslug.health = 2;
-#endif
}
REGISTER_NET_LINKED(ENT_CLIENT_SWAMP)
e.draw = orb_draw;
IL_PUSH(g_drawables, e);
- e.health = 255;
+ SetResourceAmountExplicit(e, RESOURCE_HEALTH, 255);
set_movetype(e, MOVETYPE_NONE);
e.solid = SOLID_NOT;
e.drawmask = MASK_NORMAL;
int t = ReadByte();
if (t < 192)
{
- this.health = t / 191.0;
+ SetResourceAmountExplicit(this, RESOURCE_HEALTH, t / 191.0);
this.build_finished = 0;
}
else
t = (t - 192) * 256 + ReadByte();
this.build_started = servertime;
if (this.build_finished)
- this.build_starthealth = bound(0, this.health, 1);
+ this.build_starthealth = bound(0, GetResourceAmount(this, RESOURCE_HEALTH), 1);
else
this.build_starthealth = 0;
this.build_finished = servertime + t / 32;
}
else
{
- this.health = -1;
+ SetResourceAmountExplicit(this, RESOURCE_HEALTH, -1);
this.build_finished = 0;
}
if (time < this.build_finished + 0.25)
{
if (time < this.build_started)
- this.health = this.build_starthealth;
+ SetResourceAmountExplicit(this, RESOURCE_HEALTH, this.build_starthealth);
else if (time < this.build_finished)
- this.health = (time - this.build_started) / (this.build_finished - this.build_started) * (1 - this.build_starthealth) + this.build_starthealth;
+ SetResourceAmountExplicit(this, RESOURCE_HEALTH, (time - this.build_started) / (this.build_finished - this.build_started) * (1 - this.build_starthealth) + this.build_starthealth);
else
- this.health = 1;
+ SetResourceAmountExplicit(this, RESOURCE_HEALTH, 1);
}
else
- this.health = -1;
+ SetResourceAmountExplicit(this, RESOURCE_HEALTH, -1);
}
o = drawspritearrow(o, ang, rgb, a, SPRITE_ARROW_SCALE * t);
}
draw_beginBoldFont();
- if (this.health >= 0)
+ if (GetResourceAmount(this, RESOURCE_HEALTH) >= 0)
{
float align = 0, marg;
if (this.build_finished)
drawhealthbar(
o,
0,
- this.health,
+ GetResourceAmount(this, RESOURCE_HEALTH),
'0 0 0',
'0 0 0',
SPRITE_HEALTHBAR_WIDTH * t,
this.tur_head.angles += dt * this.tur_head.avelocity;
- if (this.health < 127)
+ if (GetResourceAmount(this, RESOURCE_HEALTH) < 127)
{
dt = random();
te_spark(this.origin + '0 0 40', randomvec() * 256 + '0 0 256', 16);
}
- if(this.health < 85)
+ if(GetResourceAmount(this, RESOURCE_HEALTH) < 85)
if(dt < 0.01)
pointparticles(EFFECT_SMOKE_LARGE, (this.origin + (randomvec() * 80)), '0 0 0', 1);
- if(this.health < 32)
+ if(GetResourceAmount(this, RESOURCE_HEALTH) < 32)
if(dt < 0.015)
pointparticles(EFFECT_SMOKE_SMALL, (this.origin + (randomvec() * 80)), '0 0 0', 1);
drawhealthbar(
o,
0,
- this.health / 255,
+ GetResourceAmount(this, RESOURCE_HEALTH) / 255,
'0 0 0',
'0 0 0',
0.5 * SPRITE_HEALTHBAR_WIDTH * t,
set_movetype(this.tur_head, MOVETYPE_NOCLIP);
set_movetype(this, MOVETYPE_NOCLIP);
this.tur_head.angles = this.angles;
- this.health = 255;
+ SetResourceAmountExplicit(this, RESOURCE_HEALTH, 255);
this.solid = SOLID_BBOX;
this.tur_head.solid = SOLID_NOT;
set_movetype(this, MOVETYPE_NOCLIP);
}
_tmp = ReadByte();
- if(_tmp == 0 && this.health != 0)
+ float myhp = GetResourceAmount(this, RESOURCE_HEALTH);
+ if(_tmp == 0 && myhp != 0)
turret_die(this);
- else if(this.health && this.health != _tmp)
+ else if(myhp && myhp != _tmp)
this.helpme = servertime + 10;
- this.health = _tmp;
+ SetResourceAmountExplicit(this, RESOURCE_HEALTH, _tmp);
}
- //this.enemy.health = this.health / 255;
return true;
}
setorigin(this, this.origin + this.velocity * dt);
this.tur_head.angles += dt * this.tur_head.avelocity;
- if(this.health < 127)
+ if(GetResourceAmount(this, RESOURCE_HEALTH) < 127)
if(random() < 0.05)
te_spark(this.origin + '0 0 40', randomvec() * 256 + '0 0 256', 16);
}
setorigin(this, this.origin + this.velocity * dt);
this.tur_head.angles += dt * this.tur_head.avelocity;
- if (this.health < 127)
+ if(GetResourceAmount(this, RESOURCE_HEALTH) < 127)
if(random() < 0.15)
te_spark(this.origin + '0 0 40', randomvec() * 256 + '0 0 256', 16);
}
- METHOD(WalkerTurret, tr_setup, void(WalkerTurret this, entity it))
- {
- it.gravity = 1;
- set_movetype(it, MOVETYPE_BOUNCE);
- it.move_time = time;
- it.draw = walker_draw;
- }
+METHOD(WalkerTurret, tr_setup, void(WalkerTurret this, entity it))
+{
+ it.gravity = 1;
+ set_movetype(it, MOVETYPE_BOUNCE);
+ it.move_time = time;
+ it.draw = walker_draw;
+}
#endif // CSQC
// Ugly hack to make sure the health and armor don't go beyond hard limit.
// TODO: Remove this hack when all code uses GivePlayerHealth and
// GivePlayerArmor.
- if (this.health > RESOURCE_AMOUNT_HARD_LIMIT)
+ if (GetResourceAmount(this, RESOURCE_HEALTH) > RESOURCE_AMOUNT_HARD_LIMIT)
{
- this.health = RESOURCE_AMOUNT_HARD_LIMIT;
+ SetResourceAmountExplicit(this, RESOURCE_HEALTH, RESOURCE_AMOUNT_HARD_LIMIT);
}
- if (this.armorvalue > RESOURCE_AMOUNT_HARD_LIMIT)
+ if (GetResourceAmount(this, RESOURCE_ARMOR) > RESOURCE_AMOUNT_HARD_LIMIT)
{
- this.armorvalue = RESOURCE_AMOUNT_HARD_LIMIT;
+ SetResourceAmountExplicit(this, RESOURCE_ARMOR, RESOURCE_AMOUNT_HARD_LIMIT);
}
// End hack.
}