#include <common/monsters/_mod.qh>
#include <common/mutators/mutator/buffs/buffs.qh>
#include <common/mutators/mutator/buffs/sv_buffs.qh>
+#include <common/mutators/mutator/powerups/_mod.qh>
+#include <common/mutators/mutator/status_effects/_mod.qh>
+#include <common/net_linked.qh>
#include <common/notifications/all.qh>
+#include <common/resources/resources.qh>
#include <common/util.qh>
#include <common/weapons/_all.qh>
#include <common/wepent.qh>
if(sf & ISF_MODEL)
{
- WriteShort(MSG_ENTITY, this.fade_end);
- WriteShort(MSG_ENTITY, this.fade_start);
+ WriteShort(MSG_ENTITY, bound(0, this.fade_end, 32767));
+ WriteShort(MSG_ENTITY, bound(0, this.fade_start, 32767));
if(this.mdl == "")
LOG_TRACE("^1WARNING!^7 this.mdl is unset for item ", this.classname, "expect a crash just about now");
WriteString(MSG_ENTITY, this.mdl);
+ WriteByte(MSG_ENTITY, bound(0, this.skin, 255));
}
-
if(sf & ISF_COLORMAP)
{
WriteShort(MSG_ENTITY, this.colormap);
{
Item_Show(this, 1);
sound(this, CH_TRIGGER, this.itemdef.m_respawnsound, VOL_BASE, ATTEN_NORM); // play respawn sound
- setorigin(this, this.origin);
if (Item_ItemsTime_Allow(this.itemdef) || (STAT(WEAPONS, this) & WEPSET_SUPERWEAPONS))
{
}
} while (0);
bool mutator_returnvalue = MUTATOR_CALLHOOK(Item_RespawnCountdown, this);
- if(this.waypointsprite_attached)
- {
- GameItem def = this.itemdef;
- if (Item_ItemsTime_SpectatorOnly(def) && !mutator_returnvalue)
- WaypointSprite_UpdateRule(this.waypointsprite_attached, 0, SPRITERULE_SPECTATOR);
- WaypointSprite_UpdateBuildFinished(this.waypointsprite_attached, time + ITEM_RESPAWN_TICKS);
- }
+ if(this.waypointsprite_attached)
+ {
+ GameItem def = this.itemdef;
+ if (Item_ItemsTime_SpectatorOnly(def) && !mutator_returnvalue)
+ WaypointSprite_UpdateRule(this.waypointsprite_attached, 0, SPRITERULE_SPECTATOR);
+ WaypointSprite_UpdateBuildFinished(this.waypointsprite_attached, time + ITEM_RESPAWN_TICKS);
+ }
}
if(this.waypointsprite_attached)
}
}
-bool Item_GiveAmmoTo(entity item, entity player, int res_type, float ammomax)
+bool Item_GiveAmmoTo(entity item, entity player, Resource res_type, float ammomax)
{
float amount = GetResource(item, res_type);
if (amount == 0)
return true;
}
+void Item_NotifyWeapon(entity player, int wep)
+{
+ FOREACH_CLIENT(IS_REAL_CLIENT(it) && (it == player || (IS_SPEC(it) && it.enemy == player)), {
+ msg_entity = it;
+ WriteHeader(MSG_ONE, TE_CSQC_WEAPONPICKUP);
+ WriteByte(MSG_ONE, wep);
+ });
+}
+
bool Item_GiveTo(entity item, entity player)
{
// if nothing happens to player, just return without taking the item
// if the player is using their best weapon before items are given, they
// probably want to switch to an even better weapon after items are given
- if(CS_CVAR(player).autoswitch)
+ if(CS_CVAR(player).cvar_cl_autoswitch)
{
for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
{
pickedup |= Item_GiveAmmoTo(item, player, RES_FUEL, g_pickup_fuel_max);
if (item.itemdef.instanceOfWeaponPickup)
{
- WepSet w;
+ WepSet w, wp;
w = STAT(WEAPONS, item);
- w &= ~STAT(WEAPONS, player);
+ wp = w & ~STAT(WEAPONS, player);
- if (w || (item.spawnshieldtime && item.pickup_anyway > 0))
+ if (wp || (item.spawnshieldtime && item.pickup_anyway > 0))
{
pickedup = true;
FOREACH(Weapons, it != WEP_Null, {
if(w & (it.m_wepset))
+ Item_NotifyWeapon(player, it.m_id);
+
+ if(wp & (it.m_wepset))
{
for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
{
if (item.strength_finished)
{
pickedup = true;
- STAT(STRENGTH_FINISHED, player) = max(STAT(STRENGTH_FINISHED, player), time) + item.strength_finished;
+ float t = max(StatusEffects_gettime(STATUSEFFECT_Strength, player), time);
+ if (autocvar_g_powerups_stack)
+ t += item.strength_finished;
+ else
+ t = max(t, time + item.strength_finished);
+ StatusEffects_apply(STATUSEFFECT_Strength, player, t, 0);
}
if (item.invincible_finished)
{
pickedup = true;
- STAT(INVINCIBLE_FINISHED, player) = max(STAT(INVINCIBLE_FINISHED, player), time) + item.invincible_finished;
+ float t = max(StatusEffects_gettime(STATUSEFFECT_Shield, player), time);
+ if (autocvar_g_powerups_stack)
+ t += item.invincible_finished;
+ else
+ t = max(t, time + item.invincible_finished);
+ StatusEffects_apply(STATUSEFFECT_Shield, player, t, 0);
+ }
+ if (item.speed_finished)
+ {
+ pickedup = true;
+ float t = max(StatusEffects_gettime(STATUSEFFECT_Speed, player), time);
+ if (autocvar_g_powerups_stack)
+ t += item.speed_finished;
+ else
+ t = max(t, time + item.speed_finished);
+ StatusEffects_apply(STATUSEFFECT_Speed, player, t, 0);
+ }
+ if (item.invisibility_finished)
+ {
+ pickedup = true;
+ float t = max(StatusEffects_gettime(STATUSEFFECT_Invisibility, player), time);
+ if (autocvar_g_powerups_stack)
+ t += item.invisibility_finished;
+ else
+ t = max(t, time + item.invisibility_finished);
+ StatusEffects_apply(STATUSEFFECT_Invisibility, player, t, 0);
}
if (item.superweapons_finished)
{
pickedup = true;
- STAT(SUPERWEAPONS_FINISHED, player) = max(STAT(SUPERWEAPONS_FINISHED, player), time) + item.superweapons_finished;
+ StatusEffects_apply(STATUSEFFECT_Superweapons, player, max(StatusEffects_gettime(STATUSEFFECT_Superweapons, player), time) + item.superweapons_finished, 0);
}
// always eat teamed entities
{
if (ITEM_TOUCH_NEEDKILL())
{
- delete(this);
+ RemoveItem(this);
return;
}
}
{
this.strength_finished = max(0, this.strength_finished - time);
this.invincible_finished = max(0, this.invincible_finished - time);
+ this.speed_finished = max(0, this.speed_finished - time);
+ this.invisibility_finished = max(0, this.invisibility_finished - time);
this.superweapons_finished = max(0, this.superweapons_finished - time);
}
bool gave = ITEM_HANDLE(Pickup, this.itemdef, this, toucher);
// undo what we did above
this.strength_finished += time;
this.invincible_finished += time;
+ this.speed_finished += time;
+ this.invisibility_finished += time;
this.superweapons_finished += time;
}
return;
void Item_Reset(entity this)
{
Item_Show(this, !this.state);
- setorigin(this, this.origin);
if (Item_IsLoot(this))
{
void Item_FindTeam(entity this)
{
- entity e;
+ if(!(this.effects & EF_NOGUNBOB)) // marker for item team search
+ return;
- if(this.effects & EF_NODRAW)
+ LOG_TRACE("Initializing item team ", ftos(this.team));
+ RandomSelection_Init();
+ IL_EACH(g_items, it.team == this.team,
{
- // marker for item team search
- LOG_TRACE("Initializing item team ", ftos(this.team));
- RandomSelection_Init();
- IL_EACH(g_items, it.team == this.team,
- {
- if(it.itemdef) // is a registered item
- RandomSelection_AddEnt(it, it.cnt, 0);
- });
+ if(it.itemdef) // is a registered item
+ RandomSelection_AddEnt(it, it.cnt, 0);
+ });
- e = RandomSelection_chosen_ent;
- if (!e)
- return;
+ entity e = RandomSelection_chosen_ent;
+ if (!e)
+ return;
- IL_EACH(g_items, it.team == this.team,
+ IL_EACH(g_items, it.team == this.team,
+ {
+ if(it.itemdef) // is a registered item
{
- if(it.itemdef) // is a registered item
+ if(it != e)
{
- if(it != e)
- {
- // make it non-spawned
- Item_Show(it, -1);
- it.state = 1; // state 1 = initially hidden item, apparently
- }
- else
- Item_Reset(it);
- it.effects &= ~EF_NODRAW;
+ Item_Show(it, -1); // make it non-spawned
+ if (it.waypointsprite_attached)
+ WaypointSprite_Kill(it.waypointsprite_attached);
+ it.nextthink = 0; // disable any scheduled powerup spawn
}
- });
- }
+ else
+ Item_Reset(it);
+
+ // leave 'this' marked so Item_FindTeam() works when called again via this.reset
+ if(it != this)
+ it.effects &= ~EF_NOGUNBOB;
+ }
+ });
}
// Savage: used for item garbage-collection
void RemoveItem(entity this)
{
if(wasfreed(this) || !this) { return; }
+ if(this.waypointsprite_attached)
+ WaypointSprite_Kill(this.waypointsprite_attached);
Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(this), '0 0 0', 1);
delete(this);
}
float ammo_pickupevalfunc(entity player, entity item)
{
- bool need_shells = false, need_nails = false, need_rockets = false, need_cells = false, need_plasma = false, need_fuel = false;
+ entity item_resource = NULL; // pointer to the resource that may be associated with the given item
entity wpn = NULL;
float c = 0;
float rating = 0;
- // Detect needed ammo
+ // detect needed ammo
if(item.itemdef.instanceOfWeaponPickup)
{
- entity ammo = NULL;
- if(GetResource(item, RES_SHELLS)) { need_shells = true; ammo = ITEM_Shells; }
- else if(GetResource(item, RES_BULLETS)) { need_nails = true; ammo = ITEM_Bullets; }
- else if(GetResource(item, RES_ROCKETS)) { need_rockets = true; ammo = ITEM_Rockets; }
- else if(GetResource(item, RES_CELLS)) { need_cells = true; ammo = ITEM_Cells; }
- else if(GetResource(item, RES_PLASMA)) { need_plasma = true; ammo = ITEM_Plasma; }
- else if(GetResource(item, RES_FUEL)) { need_fuel = true; ammo = ITEM_JetpackFuel; }
-
+ entity res = item.itemdef.m_weapon.ammo_type;
+ entity ammo = (res != RES_NONE) ? GetAmmoItem(res) : NULL;
if(!ammo)
return 0;
+ if(res != RES_NONE && GetResource(item, res))
+ item_resource = res;
+
wpn = item;
rating = ammo.m_botvalue;
}
FOREACH(Weapons, it != WEP_Null, {
if(!(STAT(WEAPONS, player) & (it.m_wepset)))
continue;
+ if(it.ammo_type == RES_NONE)
+ continue;
- switch(it.ammo_type)
+ if(GetResource(item, it.ammo_type))
{
- case RES_SHELLS: need_shells = true; break;
- case RES_BULLETS: need_nails = true; break;
- case RES_ROCKETS: need_rockets = true; break;
- case RES_CELLS: need_cells = true; break;
- case RES_PLASMA: need_plasma = true; break;
- case RES_FUEL: need_fuel = true; break;
+ item_resource = it.ammo_type;
+ break;
}
});
rating = item.bot_pickupbasevalue;
float noammorating = 0.5;
- if ((need_shells) && GetResource(item, RES_SHELLS) && (GetResource(player, RES_SHELLS) < g_pickup_shells_max))
- c = GetResource(item, RES_SHELLS) / max(noammorating, GetResource(player, RES_SHELLS));
-
- if ((need_nails) && GetResource(item, RES_BULLETS) && (GetResource(player, RES_BULLETS) < g_pickup_nails_max))
- c = GetResource(item, RES_BULLETS) / max(noammorating, GetResource(player, RES_BULLETS));
-
- if ((need_rockets) && GetResource(item, RES_ROCKETS) && (GetResource(player, RES_ROCKETS) < g_pickup_rockets_max))
- c = GetResource(item, RES_ROCKETS) / max(noammorating, GetResource(player, RES_ROCKETS));
-
- if ((need_cells) && GetResource(item, RES_CELLS) && (GetResource(player, RES_CELLS) < g_pickup_cells_max))
- c = GetResource(item, RES_CELLS) / max(noammorating, GetResource(player, RES_CELLS));
-
- if ((need_plasma) && GetResource(item, RES_PLASMA) && (GetResource(player, RES_PLASMA) < g_pickup_plasma_max))
- c = GetResource(item, RES_PLASMA) / max(noammorating, GetResource(player, RES_PLASMA));
-
- if ((need_fuel) && GetResource(item, RES_FUEL) && (GetResource(player, RES_FUEL) < g_pickup_fuel_max))
- c = GetResource(item, RES_FUEL) / max(noammorating, GetResource(player, RES_FUEL));
+ if(item_resource && (GetResource(player, item_resource) < GetResourceLimit(player, item_resource)))
+ c = GetResource(item, item_resource) / max(noammorating, GetResource(player, item_resource));
rating *= min(c, 2);
if(wpn)
precache_model(this.model);
precache_sound(this.item_pickupsound);
+ if(q3compat && !this.team)
+ {
+ string t = GetField_fullspawndata(this, "team", false);
+ // bones_was_here: this hack is cheaper than changing to a .string strcmp()
+ if(t) this.team = crc16(false, t);
+ }
+
if (Item_IsLoot(this))
{
- this.reset = SUB_Remove;
+ this.reset = RemoveItem;
set_movetype(this, MOVETYPE_TOSS);
// Savage: remove thrown items after a certain period of time ("garbage collection")
setthink(this, RemoveItem);
- this.nextthink = time + 20;
+ this.nextthink = time + autocvar_g_items_dropped_lifetime;
this.takedamage = DAMAGE_YES;
this.event_damage = Item_Damage;
+ // enable this to have thrown items burn in lava
+ //this.damagedbycontents = true;
+ //IL_PUSH(g_damagedbycontents, this);
if (Item_IsExpiring(this))
{
if(this.angles != '0 0 0')
this.SendFlags |= ISF_ANGLES;
- this.reset = Item_Reset;
+ this.reset = this.team ? Item_FindTeam : Item_Reset;
// it's a level item
if(this.spawnflags & 1)
this.noalign = 1;
if(autocvar_spawn_debug >= 2)
{
- // why not flags & fl_item?
- FOREACH_ENTITY_RADIUS(this.origin, 3, it.is_item, {
- LOG_TRACE("XXX Found duplicated item: ", itemname, vtos(this.origin));
- LOG_TRACE(" vs ", it.netname, vtos(it.origin));
- error("Mapper sucks.");
- });
+ // why not flags & fl_item?
+ FOREACH_ENTITY_RADIUS(this.origin, 3, it.is_item, {
+ LOG_TRACE("XXX Found duplicated item: ", itemname, vtos(this.origin));
+ LOG_TRACE(" vs ", it.netname, vtos(it.origin));
+ error("Mapper sucks.");
+ });
this.is_item = true;
}
weaponsInMap |= WepSet_FromWeapon(REGISTRY_GET(Weapons, weaponid));
- if ( def.instanceOfPowerup
- || def.instanceOfWeaponPickup
+ if ( def.instanceOfPowerup
+ || def.instanceOfWeaponPickup
|| (def.instanceOfHealth && def != ITEM_HealthSmall)
|| (def.instanceOfArmor && def != ITEM_ArmorSmall)
|| (itemid & (IT_KEY1 | IT_KEY2))
setmodel(this, MDL_Null); // precision set below
//this.effects |= EF_LOWPRECISION;
+ // support skinned models for powerups
+ if(!this.skin)
+ this.skin = def.m_skin;
+
setsize (this, this.pos1 = def.m_mins, this.pos2 = def.m_maxs);
this.SendFlags |= ISF_SIZE;
if(Item_IsLoot(this))
this.gravity = 1;
+ else
+ this.glowmod = def.m_color;
if(def.instanceOfWeaponPickup)
{
if(!this.cnt)
this.cnt = 1; // item probability weight
- this.effects |= EF_NODRAW; // marker for item team search
+ this.effects |= EF_NOGUNBOB; // marker for item team search
InitializeEntity(this, Item_FindTeam, INITPRIO_FINDTARGET);
}
else
void StartItem(entity this, GameItem def)
{
- def = def.m_spawnfunc_hookreplace(def, this);
- if (def.spawnflags & ITEM_FLAG_MUTATORBLOCKED)
- {
- delete(this);
- return;
- }
- this.classname = def.m_canonical_spawnfunc;
- _StartItem(
- this,
- this.itemdef = def,
- def.m_respawntime(), // defaultrespawntime
- def.m_respawntimejitter() // defaultrespawntimejitter
+ def = def.m_spawnfunc_hookreplace(def, this);
+
+ if (def.spawnflags & ITEM_FLAG_MUTATORBLOCKED)
+ {
+ delete(this);
+ return; // TODO does not set startitem_failed
+ }
+
+ this.classname = def.m_canonical_spawnfunc;
+
+ _StartItem(
+ this,
+ this.itemdef = def,
+ def.m_respawntime(), // defaultrespawntime
+ def.m_respawntimejitter() // defaultrespawntimejitter
);
}
this.strength_finished = autocvar_g_balance_powerup_strength_time;
if(!this.invincible_finished)
this.invincible_finished = autocvar_g_balance_powerup_invincible_time;
+ if(!this.speed_finished)
+ this.speed_finished = autocvar_g_balance_powerup_speed_time;
+ if(!this.invisibility_finished)
+ this.invisibility_finished = autocvar_g_balance_powerup_invisibility_time;
if(!this.superweapons_finished)
this.superweapons_finished = autocvar_g_balance_superweapons_time;
else if(argv(j) == "unlimited_superweapons") this.items |= IT_UNLIMITED_SUPERWEAPONS;
else if(argv(j) == "strength") this.items |= ITEM_Strength.m_itemid;
else if(argv(j) == "invincible") this.items |= ITEM_Shield.m_itemid;
+ else if(argv(j) == "speed") this.items |= ITEM_Speed.m_itemid;
+ else if(argv(j) == "invisibility") this.items |= ITEM_Invisibility.m_itemid;
else if(argv(j) == "superweapons") this.items |= IT_SUPERWEAPON;
else if(argv(j) == "jetpack") this.items |= ITEM_Jetpack.m_itemid;
else if(argv(j) == "fuel_regen") this.items |= ITEM_JetpackRegen.m_itemid;
else
{
- FOREACH(Buffs, it != BUFF_Null,
+ FOREACH(StatusEffect, it.instanceOfBuff,
{
- string s = Buff_UndeprecateName(argv(j));
+ string s = Buff_CompatName(argv(j));
if(s == it.netname)
{
- STAT(BUFFS, this) |= (it.m_itemid);
- if(!STAT(BUFF_TIME, this))
- STAT(BUFF_TIME, this) = it.m_time(it);
+ this.buffdef = it;
+ if(!this.buffs_finished)
+ this.buffs_finished = it.m_time(it);
break;
}
});
FOREACH(Weapons, it != WEP_Null, {
- string s = W_UndeprecateName(argv(j));
- if(s == it.netname)
+ string s = argv(j);
+ if(s == it.netname || s == it.m_deprecated_netname)
{
STAT(WEAPONS, this) |= (it.m_wepset);
if(this.spawnflags == 0 || this.spawnflags == 2)
str = sprintf("%s %s%d %s", str, itemprefix, boolean(this.items & IT_UNLIMITED_SUPERWEAPONS), "unlimited_superweapons");
str = sprintf("%s %s%d %s", str, valueprefix, this.strength_finished * boolean(this.items & ITEM_Strength.m_itemid), "strength");
str = sprintf("%s %s%d %s", str, valueprefix, this.invincible_finished * boolean(this.items & ITEM_Shield.m_itemid), "invincible");
+ str = sprintf("%s %s%d %s", str, valueprefix, this.invisibility_finished * boolean(this.items & ITEM_Invisibility.m_itemid), "invisibility");
+ str = sprintf("%s %s%d %s", str, valueprefix, this.speed_finished * boolean(this.items & ITEM_Speed.m_itemid), "speed");
str = sprintf("%s %s%d %s", str, valueprefix, this.superweapons_finished * boolean(this.items & IT_SUPERWEAPON), "superweapons");
str = sprintf("%s %s%d %s", str, itemprefix, boolean(this.items & ITEM_Jetpack.m_itemid), "jetpack");
str = sprintf("%s %s%d %s", str, itemprefix, boolean(this.items & ITEM_JetpackRegen.m_itemid), "fuel_regen");
res = GetResource(this, RES_FUEL); if(res != 0) str = sprintf("%s %s%d %s", str, valueprefix, max(0, res), "fuel");
res = GetResource(this, RES_HEALTH); if(res != 0) str = sprintf("%s %s%d %s", str, valueprefix, max(0, res), "health");
res = GetResource(this, RES_ARMOR); if(res != 0) str = sprintf("%s %s%d %s", str, valueprefix, max(0, res), "armor");
- // HACK: buffs share a single timer, so we need to include enabled buffs AFTER disabled ones to avoid loss
- FOREACH(Buffs, it != BUFF_Null && !(STAT(BUFFS, this) & it.m_itemid), str = sprintf("%s %s%d %s", str, valueprefix, max(0, STAT(BUFF_TIME, this)), it.netname));
- FOREACH(Buffs, it != BUFF_Null && (STAT(BUFFS, this) & it.m_itemid), str = sprintf("%s %s%d %s", str, valueprefix, max(0, STAT(BUFF_TIME, this)), it.netname));
+ FOREACH(StatusEffect, it.instanceOfBuff, str = sprintf("%s %s%d %s", str, valueprefix, this.buffs_finished * boolean(this.buffdef == it), it.netname));
FOREACH(Weapons, it != WEP_Null, str = sprintf("%s %s%d %s", str, itemprefix, !!(STAT(WEAPONS, this) & (it.m_wepset)), it.netname));
}
this.netname = strzone(str);
n = tokenize_console(this.netname);
for(int j = 0; j < n; ++j)
{
- FOREACH(Weapons, it != WEP_Null && W_UndeprecateName(argv(j)) == it.netname, {
+ string cmd = argv(j);
+ FOREACH(Weapons, it != WEP_Null && (cmd == it.netname || cmd == it.m_deprecated_netname), {
it.wr_init(it);
break;
});
bool GiveBuff(entity e, Buff thebuff, int op, int val)
{
- bool had_buff = (STAT(BUFFS, e) & thebuff.m_itemid);
- float new_buff_time = ((had_buff) ? STAT(BUFF_TIME, e) : 0);
+ bool had_buff = StatusEffects_active(thebuff, e);
+ float new_buff_time = ((had_buff) ? StatusEffects_gettime(thebuff, e) : 0);
switch (op)
{
case OP_SET:
}
if(new_buff_time <= 0)
{
- if(had_buff)
- STAT(BUFF_TIME, e) = new_buff_time;
- STAT(BUFFS, e) &= ~thebuff.m_itemid;
+ if(had_buff) // only trigger removal mechanics if there is an effect to remove!
+ StatusEffects_remove(thebuff, e, STATUSEFFECT_REMOVE_NORMAL);
}
else
{
- STAT(BUFF_TIME, e) = new_buff_time;
- STAT(BUFFS, e) = thebuff.m_itemid; // NOTE: replaces any existing buffs on the player!
+ buff_RemoveAll(e, STATUSEFFECT_REMOVE_CLEAR); // clear old buffs on the player first!
+ StatusEffects_apply(thebuff, e, new_buff_time, 0);
}
- bool have_buff = (STAT(BUFFS, e) & thebuff.m_itemid);
+ bool have_buff = StatusEffects_active(thebuff, e);
return (had_buff != have_buff);
}
if(v1 <= v0 - t)
{
if(snd_decr != NULL)
- sound (e, CH_TRIGGER, snd_decr, VOL_BASE, ATTEN_NORM);
+ sound(e, CH_TRIGGER, snd_decr, VOL_BASE, ATTEN_NORM);
}
else if(v0 >= v0 + t)
{
if(snd_incr != NULL)
- sound (e, CH_TRIGGER, snd_incr, VOL_BASE, ATTEN_NORM);
+ sound(e, ((snd_incr == SND_POWERUP) ? CH_TRIGGER_SINGLE : CH_TRIGGER), snd_incr, VOL_BASE, ATTEN_NORM);
}
}
else if(v0 > v1)
e.(regenfield) = max(e.(regenfield), time + regentime);
}
-bool GiveResourceValue(entity e, int res_type, int op, int val)
+bool GiveResourceValue(entity e, Resource res_type, int op, int val)
{
int v0 = GetResource(e, res_type);
float new_val = 0;
return SetResourceExplicit(e, res_type, new_val);
}
+bool GiveStatusEffect(entity e, StatusEffects this, int op, float val)
+{
+ bool had_eff = StatusEffects_active(this, e);
+ float new_eff_time = ((had_eff) ? StatusEffects_gettime(this, e) : 0);
+ switch (op)
+ {
+ case OP_SET:
+ new_eff_time = val;
+ break;
+ case OP_MIN:
+ new_eff_time = max(new_eff_time, val);
+ break;
+ case OP_MAX:
+ new_eff_time = min(new_eff_time, val);
+ break;
+ case OP_PLUS:
+ new_eff_time += val;
+ break;
+ case OP_MINUS:
+ new_eff_time -= val;
+ break;
+ }
+ if(new_eff_time <= 0)
+ {
+ if(had_eff) // only trigger removal mechanics if there is an effect to remove!
+ StatusEffects_remove(this, e, STATUSEFFECT_REMOVE_NORMAL);
+ }
+ else
+ StatusEffects_apply(this, e, new_eff_time, 0);
+ bool have_eff = StatusEffects_active(this, e);
+ return (had_eff != have_eff);
+}
float GiveItems(entity e, float beginarg, float endarg)
{
int _switchweapon = 0;
- if(CS_CVAR(e).autoswitch)
+ if(CS_CVAR(e).cvar_cl_autoswitch)
{
for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
{
}
}
- STAT(STRENGTH_FINISHED, e) = max(0, STAT(STRENGTH_FINISHED, e) - time);
- STAT(INVINCIBLE_FINISHED, e) = max(0, STAT(INVINCIBLE_FINISHED, e) - time);
- STAT(SUPERWEAPONS_FINISHED, e) = max(0, STAT(SUPERWEAPONS_FINISHED, e) - time);
- STAT(BUFF_TIME, e) = max(0, STAT(BUFF_TIME, e) - time);
+ if(e.statuseffects)
+ {
+ FOREACH(StatusEffect, true,
+ {
+ e.statuseffects.statuseffect_time[it.m_id] = max(0, e.statuseffects.statuseffect_time[it.m_id] - time);
+ });
+ }
PREGIVE(e, items);
PREGIVE_WEAPONS(e);
- PREGIVE(e, stat_STRENGTH_FINISHED);
- PREGIVE(e, stat_INVINCIBLE_FINISHED);
- PREGIVE(e, stat_SUPERWEAPONS_FINISHED);
+ PREGIVE_STATUSEFFECT(e, STATUSEFFECT_Strength);
+ PREGIVE_STATUSEFFECT(e, STATUSEFFECT_Shield);
+ PREGIVE_STATUSEFFECT(e, STATUSEFFECT_Speed);
+ PREGIVE_STATUSEFFECT(e, STATUSEFFECT_Invisibility);
+ //PREGIVE_STATUSEFFECT(e, STATUSEFFECT_Superweapons);
PREGIVE_RESOURCE(e, RES_BULLETS);
PREGIVE_RESOURCE(e, RES_CELLS);
PREGIVE_RESOURCE(e, RES_PLASMA);
continue;
case "ALL":
got += GiveBit(e, items, ITEM_JetpackRegen.m_itemid, op, val);
- got += GiveValue(e, stat_STRENGTH_FINISHED, op, val);
- got += GiveValue(e, stat_INVINCIBLE_FINISHED, op, val);
- got += GiveValue(e, stat_SUPERWEAPONS_FINISHED, op, val);
+ FOREACH(StatusEffect, it.instanceOfPowerups, got += GiveStatusEffect(e, it, op, val));
got += GiveBit(e, items, IT_UNLIMITED_AMMO | IT_UNLIMITED_SUPERWEAPONS, op, val);
case "all":
got += GiveBit(e, items, ITEM_Jetpack.m_itemid, op, val);
case "allweapons":
FOREACH(Weapons, it != WEP_Null && !(it.spawnflags & (WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_SPECIALATTACK)), got += GiveWeapon(e, it.m_id, op, val));
//case "allbuffs": // all buffs makes a player god, do not want!
- //FOREACH(Buffs, it != BUFF_Null, got += GiveBuff(e, it.m_itemid, op, val));
+ //FOREACH(StatusEffect, it.instanceOfBuff, got += GiveBuff(e, it, op, val));
case "allammo":
got += GiveResourceValue(e, RES_CELLS, op, val);
got += GiveResourceValue(e, RES_PLASMA, op, val);
got += GiveBit(e, items, ITEM_JetpackRegen.m_itemid, op, val);
break;
case "strength":
- got += GiveValue(e, stat_STRENGTH_FINISHED, op, val);
+ got += GiveStatusEffect(e, STATUSEFFECT_Strength, op, val);
break;
case "invincible":
- got += GiveValue(e, stat_INVINCIBLE_FINISHED, op, val);
+ case "shield":
+ got += GiveStatusEffect(e, STATUSEFFECT_Shield, op, val);
+ break;
+ case "speed":
+ got += GiveStatusEffect(e, STATUSEFFECT_Speed, op, val);
+ break;
+ case "invisibility":
+ got += GiveStatusEffect(e, STATUSEFFECT_Invisibility, op, val);
break;
case "superweapons":
- got += GiveValue(e, stat_SUPERWEAPONS_FINISHED, op, val);
+ got += GiveStatusEffect(e, STATUSEFFECT_Superweapons, op, val);
break;
case "cells":
got += GiveResourceValue(e, RES_CELLS, op, val);
got += GiveResourceValue(e, RES_FUEL, op, val);
break;
default:
- FOREACH(Buffs, it != BUFF_Null && buff_Available(it) && Buff_UndeprecateName(cmd) == it.netname,
+ FOREACH(StatusEffect, it.instanceOfBuff && buff_Available(it) && Buff_CompatName(cmd) == it.netname,
{
got += GiveBuff(e, it, op, val);
break;
});
- FOREACH(Weapons, it != WEP_Null && W_UndeprecateName(cmd) == it.netname, {
+ FOREACH(Weapons, it != WEP_Null && (cmd == it.netname || cmd == it.m_deprecated_netname), {
got += GiveWeapon(e, it.m_id, op, val);
break;
});
if(STAT(WEAPONS, e) & (it.m_wepset))
it.wr_init(it);
});
- POSTGIVE_VALUE(e, stat_STRENGTH_FINISHED, 1, SND_POWERUP, SND_POWEROFF);
- POSTGIVE_VALUE(e, stat_INVINCIBLE_FINISHED, 1, SND_Shield, SND_POWEROFF);
- //POSTGIVE_VALUE(e, stat_SUPERWEAPONS_FINISHED, 1, SND_Null, SND_Null);
+ POSTGIVE_STATUSEFFECT(e, STATUSEFFECT_Strength, SND_POWERUP, SND_POWEROFF);
+ POSTGIVE_STATUSEFFECT(e, STATUSEFFECT_Shield, SND_POWERUP, SND_POWEROFF);
+ POSTGIVE_STATUSEFFECT(e, STATUSEFFECT_Speed, SND_POWERUP, SND_POWEROFF);
+ POSTGIVE_STATUSEFFECT(e, STATUSEFFECT_Invisibility, SND_POWERUP, SND_POWEROFF);
POSTGIVE_RESOURCE(e, RES_BULLETS, 0, SND_ITEMPICKUP, SND_Null);
POSTGIVE_RESOURCE(e, RES_CELLS, 0, SND_ITEMPICKUP, SND_Null);
POSTGIVE_RESOURCE(e, RES_PLASMA, 0, SND_ITEMPICKUP, SND_Null);
POSTGIVE_RES_ROT(e, RES_ARMOR, 1, pauserotarmor_finished, autocvar_g_balance_pause_armor_rot, pauseregen_finished, autocvar_g_balance_pause_health_regen, SND_ARMOR25, SND_Null);
POSTGIVE_RES_ROT(e, RES_HEALTH, 1, pauserothealth_finished, autocvar_g_balance_pause_health_rot, pauseregen_finished, autocvar_g_balance_pause_health_regen, SND_MEGAHEALTH, SND_Null);
- if(STAT(SUPERWEAPONS_FINISHED, e) <= 0)
+ if(!StatusEffects_active(STATUSEFFECT_Superweapons, e))
+ {
if(!g_weaponarena && (STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS))
- STAT(SUPERWEAPONS_FINISHED, e) = autocvar_g_balance_superweapons_time;
+ StatusEffects_apply(STATUSEFFECT_Superweapons, e, autocvar_g_balance_superweapons_time, 0);
+ }
- if(STAT(STRENGTH_FINISHED, e) <= 0)
- STAT(STRENGTH_FINISHED, e) = 0;
- else
- STAT(STRENGTH_FINISHED, e) += time;
- if(STAT(INVINCIBLE_FINISHED, e) <= 0)
- STAT(INVINCIBLE_FINISHED, e) = 0;
- else
- STAT(INVINCIBLE_FINISHED, e) += time;
- if(STAT(SUPERWEAPONS_FINISHED, e) <= 0)
- STAT(SUPERWEAPONS_FINISHED, e) = 0;
- else
- STAT(SUPERWEAPONS_FINISHED, e) += time;
- if(STAT(BUFF_TIME, e) <= 0)
- STAT(BUFF_TIME, e) = 0;
- else
- STAT(BUFF_TIME, e) += time;
+ if(e.statuseffects)
+ {
+ FOREACH(StatusEffect, true,
+ {
+ if(e.statuseffects.statuseffect_time[it.m_id] <= 0)
+ e.statuseffects.statuseffect_time[it.m_id] = 0;
+ else
+ e.statuseffects.statuseffect_time[it.m_id] += time;
+ });
+
+ StatusEffects_update(e);
+ }
for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
{