#include <common/teams.qh>
#include <common/util.qh>
+#ifdef GAMEQC
+#include <common/mutators/mutator/waypoints/all.qh>
+#endif
+
#ifdef GAMEQC
REGISTER_WAYPOINT(Buff, _("Buff"), "", '1 0.5 0', 1);
REGISTER_RADARICON(Buff, 1);
{
if (CS(toucher).cvar_cl_buffs_autoreplace && STAT(BUFFS, toucher) != STAT(BUFFS, this))
{
+ // TODO: lost-gained notification for this case
int buffid = buff_FirstFromFlags(STAT(BUFFS, toucher)).m_id;
- //Send_Notification(NOTIF_ONE, toucher, MSG_MULTI, ITEM_BUFF_DROP, STAT(BUFFS, toucher));
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ITEM_BUFF_LOST, toucher.netname, buffid);
+ Send_Notification(NOTIF_ONE, toucher, MSG_INFO, INFO_ITEM_BUFF_LOST, toucher.netname, buffid);
+ if(!IS_INDEPENDENT_PLAYER(toucher))
+ Send_Notification(NOTIF_ALL_EXCEPT, toucher, MSG_INFO, INFO_ITEM_BUFF_LOST, toucher.netname, buffid);
STAT(BUFFS, toucher) = 0;
//sound(toucher, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
this.owner = toucher;
this.buff_active = false;
this.lifetime = 0;
- int buffid = buff_FirstFromFlags(STAT(BUFFS, this)).m_id;
- Send_Notification(NOTIF_ONE, toucher, MSG_MULTI, ITEM_BUFF_GOT, buffid);
- Send_Notification(NOTIF_ALL_EXCEPT, toucher, MSG_INFO, INFO_ITEM_BUFF, toucher.netname, buffid);
+ entity thebuff = buff_FirstFromFlags(STAT(BUFFS, this));
+ Send_Notification(NOTIF_ONE, toucher, MSG_MULTI, ITEM_BUFF_GOT, thebuff.m_id);
+ if(!IS_INDEPENDENT_PLAYER(toucher))
+ Send_Notification(NOTIF_ALL_EXCEPT, toucher, MSG_INFO, INFO_ITEM_BUFF, toucher.netname, thebuff.m_id);
Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(this), '0 0 0', 1);
sound(toucher, CH_TRIGGER, SND_SHIELD_RESPAWN, VOL_BASE, ATTN_NORM);
STAT(BUFFS, toucher) |= (STAT(BUFFS, this));
+ float bufftime = ((this.count) ? this.count : thebuff.m_time(thebuff));
+ if(bufftime)
+ STAT(BUFF_TIME, toucher) = min(time + bufftime, max(STAT(BUFF_TIME, toucher), time) + bufftime);
}
float buff_Available(entity buff)
return true;
}
+void buff_Delete(entity this)
+{
+ WaypointSprite_Kill(this.buff_waypoint);
+ delete_fn(this);
+}
+
void buff_Init(entity this)
{
if(!cvar("g_buffs")) { delete(this); return; }
buff_SetCooldown(this, autocvar_g_buffs_cooldown_activate + max(0, game_starttime - time));
this.buff_active = !this.buff_activetime;
this.pflags = PFLAGS_FULLDYNAMIC;
+ this.dtor = buff_Delete;
if(this.spawnflags & 1)
this.noalign = true;
{
entity player = M_ARGV(0, entity);
- STAT(BUFFS, player) = 0;
- STAT(BUFF_TIME, player) = 0;
+ player.oldbuffs = 0;
PS(player).buff_shield = time + 0.5; // prevent picking up buffs immediately
// reset timers here to prevent them continuing after re-spawn
player.buff_disability_time = 0;
if(STAT(BUFFS, frag_target))
{
int buffid = buff_FirstFromFlags(STAT(BUFFS, frag_target)).m_id;
- Send_Notification(NOTIF_ALL_EXCEPT, frag_target, MSG_INFO, INFO_ITEM_BUFF_LOST, frag_target.netname, buffid);
+ if(!IS_INDEPENDENT_PLAYER(frag_target))
+ Send_Notification(NOTIF_ALL_EXCEPT, frag_target, MSG_INFO, INFO_ITEM_BUFF_LOST, frag_target.netname, buffid);
STAT(BUFFS, frag_target) = 0;
+ STAT(BUFF_TIME, frag_target) = 0;
if(frag_target.buff_model)
{
{
int buffid = buff_FirstFromFlags(STAT(BUFFS, player)).m_id;
Send_Notification(NOTIF_ONE, player, MSG_MULTI, ITEM_BUFF_DROP, buffid);
- Send_Notification(NOTIF_ALL_EXCEPT, player, MSG_INFO, INFO_ITEM_BUFF_LOST, player.netname, buffid);
+ if(!IS_INDEPENDENT_PLAYER(player))
+ Send_Notification(NOTIF_ALL_EXCEPT, player, MSG_INFO, INFO_ITEM_BUFF_LOST, player.netname, buffid);
STAT(BUFFS, player) = 0;
+ STAT(BUFF_TIME, player) = 0;
PS(player).buff_shield = time + max(0, autocvar_g_buffs_pickup_delay);
- //STAT(BUFF_TIME, player) = 0; // already notified
sound(player, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
return true;
}
Send_Notification(NOTIF_ONE, player, MSG_MULTI, ITEM_BUFF_DROP, buffid); // TODO: special timeout message?
sound(player, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
}
- else
+ else if(!IS_INDEPENDENT_PLAYER(player))
Send_Notification(NOTIF_ALL_EXCEPT, player, MSG_INFO, INFO_ITEM_BUFF_LOST, player.netname, buffid);
STAT(BUFFS, player) = 0;
PS(player).buff_shield = time + max(0, autocvar_g_buffs_pickup_delay); // always put in a delay, even if small
{
entity buff = buff_FirstFromFlags(STAT(BUFFS, player));
float bufftime = buff != BUFF_Null ? buff.m_time(buff) : 0;
- STAT(BUFF_TIME, player) = (bufftime) ? time + bufftime : 0;
+ if(STAT(BUFF_TIME, player) <= time) // if the player still has a buff countdown, don't reset it!
+ STAT(BUFF_TIME, player) = (bufftime) ? time + bufftime : 0;
BUFF_ONADD(BUFF_AMMO)
{
FOREACH(Buffs, it != BUFF_Null,
{
s = Buff_UndeprecateName(argv(j));
- if(s == it.m_name)
+ if(s == it.netname)
{
STAT(BUFFS, this) |= (it.m_itemid);
+ if(!STAT(BUFF_TIME, this))
+ STAT(BUFF_TIME, this) = it.m_time(it);
break;
}
});
if(GetResource(this, RES_FUEL) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResource(this, RES_FUEL)), "fuel");
if(GetResource(this, RES_HEALTH) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResource(this, RES_HEALTH)), "health");
if(GetResource(this, RES_ARMOR) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResource(this, RES_ARMOR)), "armor");
- FOREACH(Buffs, it != BUFF_Null, this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, !!(STAT(BUFFS, this) & (it.m_itemid)), it.m_name));
+ FOREACH(Buffs, it != BUFF_Null && (STAT(BUFFS, this) & it.m_itemid), this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, STAT(BUFF_TIME, this)), it.netname));
FOREACH(Weapons, it != WEP_Null, this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, !!(STAT(WEAPONS, this) & (it.m_wepset)), it.netname));
}
this.netname = strzone(this.netname);
bool GiveBuff(entity e, Buff thebuff, int op, int val)
{
bool had_buff = (STAT(BUFFS, e) & thebuff.m_itemid);
- switch(op)
+ switch (op)
{
case OP_SET:
- if(val > 0)
- STAT(BUFFS, e) |= thebuff.m_itemid;
- else
- STAT(BUFFS, e) &= ~thebuff.m_itemid;
+ STAT(BUFF_TIME, e) = val;
break;
case OP_MIN:
- case OP_PLUS:
- if(val > 0)
- STAT(BUFFS, e) |= thebuff.m_itemid;
+ STAT(BUFF_TIME, e) = max(STAT(BUFF_TIME, e), val);
break;
case OP_MAX:
- if(val <= 0)
- STAT(BUFFS, e) &= ~thebuff.m_itemid;
+ STAT(BUFF_TIME, e) = min(STAT(BUFF_TIME, e), val);
+ break;
+ case OP_PLUS:
+ STAT(BUFF_TIME, e) += val;
break;
case OP_MINUS:
- if(val > 0)
- STAT(BUFFS, e) &= ~thebuff.m_itemid;
+ STAT(BUFF_TIME, e) -= val;
break;
}
+ if(STAT(BUFF_TIME, e) <= 0)
+ STAT(BUFFS, e) &= ~thebuff.m_itemid;
+ else
+ STAT(BUFFS, e) = thebuff.m_itemid; // NOTE: replaces any existing buffs on the player!
bool have_buff = (STAT(BUFFS, e) & thebuff.m_itemid);
return (had_buff != have_buff);
}
e.strength_finished = max(0, e.strength_finished - time);
e.invincible_finished = max(0, e.invincible_finished - time);
e.superweapons_finished = max(0, e.superweapons_finished - time);
+ STAT(BUFF_TIME, e) = max(0, STAT(BUFF_TIME, e) - time);
PREGIVE(e, items);
PREGIVE_WEAPONS(e);
got += GiveResourceValue(e, RES_FUEL, op, val);
break;
default:
- FOREACH(Buffs, it != BUFF_Null && Buff_UndeprecateName(cmd) == it.m_name,
+ FOREACH(Buffs, it != BUFF_Null && Buff_UndeprecateName(cmd) == it.netname,
{
got += GiveBuff(e, it, op, val);
break;
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(e.superweapons_finished <= 0)
- if(!g_weaponarena && STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS)
+ if(!g_weaponarena && (STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS))
e.superweapons_finished = autocvar_g_balance_superweapons_time;
if(e.strength_finished <= 0)
e.superweapons_finished = 0;
else
e.superweapons_finished += time;
+ if(STAT(BUFF_TIME, e) <= 0)
+ STAT(BUFF_TIME, e) = 0;
+ else
+ STAT(BUFF_TIME, e) += time;
for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
{
SetResource(this.personal, RES_HEALTH, max(1, GetResource(this, RES_HEALTH)));
SetResource(this.personal, RES_ARMOR, GetResource(this, RES_ARMOR));
STAT(WEAPONS, this.personal) = STAT(WEAPONS, this);
+ STAT(BUFFS, this.personal) = STAT(BUFFS, this);
+ STAT(BUFF_TIME, this.personal) = STAT(BUFF_TIME, this);
this.personal.items = this.items;
this.personal.pauserotarmor_finished = this.pauserotarmor_finished;
this.personal.pauserothealth_finished = this.pauserothealth_finished;
SetResource(this, RES_HEALTH, GetResource(this.personal, RES_HEALTH));
SetResource(this, RES_ARMOR, GetResource(this.personal, RES_ARMOR));
STAT(WEAPONS, this) = STAT(WEAPONS, this.personal);
+ STAT(BUFFS, this) = STAT(BUFFS, this.personal);
+ STAT(BUFF_TIME, this) = STAT(BUFF_TIME, this.personal);
this.items = this.personal.items;
this.pauserotarmor_finished = time + this.personal.pauserotarmor_finished - this.personal.teleport_time;
this.pauserothealth_finished = time + this.personal.pauserothealth_finished - this.personal.teleport_time;
STAT(REVIVE_PROGRESS, this) = 0;
this.revival_time = 0;
+ // TODO: we can't set these in the PlayerSpawn hook since the target code is called before it!
+ STAT(BUFFS, this) = 0;
+ STAT(BUFF_TIME, this) = 0;
+
this.air_finished = time + 12;
this.waterlevel = WATERLEVEL_NONE;
this.watertype = CONTENT_EMPTY;
#include <common/t_items.qh>
#include <common/mapobjects/triggers.qh>
#include <common/mapobjects/trigger/counter.qh>
+#include <common/mutators/mutator/buffs/buffs.qh>
+#include <common/notifications/all.qh>
#include <common/weapons/_all.qh>
//***********************
{
actor.strength_finished = 0;
actor.invincible_finished = 0;
- STAT(BUFFS, actor) = 0;
+ if(STAT(BUFFS, actor)) // TODO: make a dropbuffs function to handle this
+ {
+ int buffid = buff_FirstFromFlags(STAT(BUFFS, actor)).m_id;
+ Send_Notification(NOTIF_ONE, actor, MSG_MULTI, ITEM_BUFF_DROP, buffid);
+ sound(actor, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
+ if(!IS_INDEPENDENT_PLAYER(actor))
+ Send_Notification(NOTIF_ALL_EXCEPT, actor, MSG_INFO, INFO_ITEM_BUFF_LOST, actor.netname, buffid);
+ STAT(BUFFS, actor) = 0;
+ STAT(BUFF_TIME, actor) = 0;
+ }
}
if (!(this.spawnflags & 16))
SetResourceExplicit(this, RES_ARMOR, 100);
else if (it.classname == "item_health_mega")
SetResourceExplicit(this, RES_HEALTH, 200);
+ else if (it.classname == "item_buff") {
+ entity buff = buff_FirstFromFlags(STAT(BUFFS, it));
+ this.netname = cons(this.netname, buff.netname);
+ STAT(BUFF_TIME, this) = it.count;
+ }
+
//remove(it); // removing ents in init functions causes havoc, workaround:
setthink(it, SUB_Remove);
it.nextthink = time;
set sv_vote_nospectators 1
set timelimit_override 20
set g_buffs_cooldown_respawn 0.1
+set g_buffs_randomize 0
// game mode settings
set g_cts_finish_kill_delay 2