const int IT_KEY1 = BIT(6);
const int IT_KEY2 = BIT(7);
+ const int IT_BUFF = BIT(8); // unused bit for buff items
+
// special colorblend meaning in engine
- const int IT_INVISIBILITY = BIT(9);
- const int IT_INVINCIBLE = BIT(10);
+ // legacy bitflags for powerups
+ const int IT_INVISIBILITY = BIT(9);
+ const int IT_INVINCIBLE = BIT(10);
const int IT_SUPERWEAPON = BIT(11); // suit
- const int IT_STRENGTH = BIT(12);
+ const int IT_STRENGTH = BIT(12);
+ const int IT_SPEED = BIT(13);
// item masks
const int IT_PICKUPMASK = IT_UNLIMITED_AMMO | IT_UNLIMITED_SUPERWEAPONS | IT_JETPACK | IT_FUEL_REGEN; // strength and invincible are handled separately
.float invincible_finished; // ditto
.float buffs_finished; // ditts
-#define spawnfunc_body(item) \
- if (!Item_IsDefinitionAllowed(item)) \
+#define SPAWNFUNC_BODY(item) \
+ if (item && Item_IsDefinitionAllowed(item)) \
+ StartItem(this, item); \
+ else \
{ \
startitem_failed = true; \
delete(this); \
- return; \
- } \
- StartItem(this, item)
+ }
#define SPAWNFUNC_ITEM(name, item) \
spawnfunc(name) \
{ \
- spawnfunc_body(item); \
+ SPAWNFUNC_BODY(item) \
}
#define SPAWNFUNC_ITEM_COND(name, cond, item1, item2) \
- spawnfunc(name) \
- { \
- entity item = (cond) ? item1 : item2; \
- spawnfunc_body(item); \
- }
+ SPAWNFUNC_ITEM(name, (cond ? item1 : item2))
#else
{
switch(buffname)
{
- case "ammoregen": return "ammo";
- case "guard": return "resistance";
- case "revival": case "regen": return "medic";
- case "jumper": return "jump";
+ case "ammoregen": return "ammo"; // Q3TA ammoregen
- case "haste": return "speed"; // Q3A haste
+ case "doubler": return "inferno"; // Q3TA doubler
+ case "scout": return "bash"; // Q3TA scout
+ case "guard": return "resistance"; // Q3TA guard
+ case "revival": case "regen": return "medic"; // WOP revival, Q3A regen
- case "invis": return "invisible"; // Q3A invis
+ case "jumper": return "jump"; // WOP jumper
+ case "invulnerability": return "vampire"; // Q3TA invulnerability
+ case "kamikaze": return "vengeance"; // Q3TA kamikaze
+ case "teleporter": return "swapper"; // Q3A personal teleporter
default: return buffname;
}
}
- REGISTER_BUFF(AMMO) {
- this.m_name = _("Ammo");
- this.netname = "ammo";
- this.m_icon = "buff_ammo";
- this.m_skin = 3;
- this.m_color = '0.76 1 0.1';
- }
+ CLASS(AmmoBuff, Buff)
+ ATTRIB(AmmoBuff, m_name, string, _("Ammo"));
+ ATTRIB(AmmoBuff, netname, string, "ammo");
+ ATTRIB(AmmoBuff, m_icon, string, "buff_ammo");
+ ATTRIB(AmmoBuff, m_skin, int, 3);
+ ATTRIB(AmmoBuff, m_color, vector, '0.76 1 0.1');
+ ENDCLASS(AmmoBuff)
+ REGISTER_BUFF(AMMO, NEW(AmmoBuff));
BUFF_SPAWNFUNCS(ammo, BUFF_AMMO)
-BUFF_SPAWNFUNC_Q3TA_COMPAT(ammoregen, BUFF_AMMO)
+BUFF_SPAWNFUNC_Q3COMPAT(item_ammoregen, BUFF_AMMO)
- REGISTER_BUFF(RESISTANCE) {
- this.m_name = _("Resistance");
- this.netname = "resistance";
- this.m_icon = "buff_resistance";
- this.m_skin = 0;
- this.m_color = '0.36 1 0.07';
- }
+ CLASS(ResistanceBuff, Buff)
+ ATTRIB(ResistanceBuff, m_name, string, _("Resistance"));
+ ATTRIB(ResistanceBuff, netname, string, "resistance");
+ ATTRIB(ResistanceBuff, m_icon, string, "buff_resistance");
+ ATTRIB(ResistanceBuff, m_skin, int, 0);
+ ATTRIB(ResistanceBuff, m_color, vector, '0.36 1 0.07');
+ ENDCLASS(ResistanceBuff)
+ REGISTER_BUFF(RESISTANCE, NEW(ResistanceBuff));
BUFF_SPAWNFUNCS(resistance, BUFF_RESISTANCE)
-BUFF_SPAWNFUNC_Q3TA_COMPAT(guard, BUFF_RESISTANCE)
+BUFF_SPAWNFUNC_Q3COMPAT(item_guard, BUFF_RESISTANCE)
- REGISTER_BUFF(SPEED) {
- this.m_name = _("Speed");
- this.netname = "speed";
- this.m_icon = "buff_speed";
- this.m_skin = 9;
- this.m_color = '0.1 1 0.84';
- }
- BUFF_SPAWNFUNCS(speed, BUFF_SPEED)
- BUFF_SPAWNFUNC_Q3COMPAT(item_haste, BUFF_SPEED)
-
- REGISTER_BUFF(MEDIC) {
- this.m_name = _("Medic");
- this.netname = "medic";
- this.m_icon = "buff_medic";
- this.m_skin = 1;
- this.m_color = '1 0.12 0';
- }
+ CLASS(MedicBuff, Buff)
+ ATTRIB(MedicBuff, m_name, string, _("Medic"));
+ ATTRIB(MedicBuff, netname, string, "medic");
+ ATTRIB(MedicBuff, m_icon, string, "buff_medic");
+ ATTRIB(MedicBuff, m_skin, int, 1);
+ ATTRIB(MedicBuff, m_color, vector, '1 0.12 0');
+ ENDCLASS(MedicBuff)
+ REGISTER_BUFF(MEDIC, NEW(MedicBuff));
BUFF_SPAWNFUNCS(medic, BUFF_MEDIC)
-BUFF_SPAWNFUNC_Q3TA_COMPAT(regen, BUFF_MEDIC)
-BUFF_SPAWNFUNC_Q3TA_COMPAT(revival, BUFF_MEDIC)
+BUFF_SPAWNFUNC_Q3COMPAT(item_regen, BUFF_MEDIC)
+BUFF_SPAWNFUNC_Q3COMPAT(item_revival, BUFF_MEDIC)
- REGISTER_BUFF(BASH) {
- this.m_name = _("Bash");
- this.netname = "bash";
- this.m_icon = "buff_bash";
- this.m_skin = 5;
- this.m_color = '1 0.39 0';
- }
+ CLASS(BashBuff, Buff)
+ ATTRIB(BashBuff, m_name, string, _("Bash"));
+ ATTRIB(BashBuff, netname, string, "bash");
+ ATTRIB(BashBuff, m_icon, string, "buff_bash");
+ ATTRIB(BashBuff, m_skin, int, 5);
+ ATTRIB(BashBuff, m_color, vector, '1 0.39 0');
+ ENDCLASS(BashBuff)
+ REGISTER_BUFF(BASH, NEW(BashBuff));
BUFF_SPAWNFUNCS(bash, BUFF_BASH)
-BUFF_SPAWNFUNC_Q3TA_COMPAT(doubler, BUFF_BASH)
+BUFF_SPAWNFUNC_Q3COMPAT(item_scout, BUFF_BASH)
- REGISTER_BUFF(VAMPIRE) {
- this.m_name = _("Vampire");
- this.netname = "vampire";
- this.m_icon = "buff_vampire";
- this.m_skin = 2;
- this.m_color = '1 0 0.24';
- }
+ CLASS(VampireBuff, Buff)
+ ATTRIB(VampireBuff, m_name, string, _("Vampire"));
+ ATTRIB(VampireBuff, netname, string, "vampire");
+ ATTRIB(VampireBuff, m_icon, string, "buff_vampire");
+ ATTRIB(VampireBuff, m_skin, int, 2);
+ ATTRIB(VampireBuff, m_color, vector, '1 0 0.24');
+ ENDCLASS(VampireBuff)
+ REGISTER_BUFF(VAMPIRE, NEW(VampireBuff));
BUFF_SPAWNFUNCS(vampire, BUFF_VAMPIRE)
+BUFF_SPAWNFUNC_Q3COMPAT(holdable_invulnerability, BUFF_VAMPIRE)
- REGISTER_BUFF(DISABILITY) {
- this.m_name = _("Disability");
- this.netname = "disability";
- this.m_icon = "buff_disability";
- this.m_skin = 7;
- this.m_color = '0.94 0.3 1';
- }
+ CLASS(DisabilityBuff, Buff)
+ ATTRIB(DisabilityBuff, m_name, string, _("Disability"));
+ ATTRIB(DisabilityBuff, netname, string, "disability");
+ ATTRIB(DisabilityBuff, m_icon, string, "buff_disability");
+ ATTRIB(DisabilityBuff, m_skin, int, 7);
+ ATTRIB(DisabilityBuff, m_color, vector, '0.94 0.3 1');
+ ENDCLASS(DisabilityBuff)
+ REGISTER_BUFF(DISABILITY, NEW(DisabilityBuff));
BUFF_SPAWNFUNCS(disability, BUFF_DISABILITY)
+ // status effect applied to targets by the disability buff
+ CLASS(Disabled, StatusEffects)
+ ATTRIB(Disabled, netname, string, "disabled");
+ #if 0
+ // NOTE: status effect name and icon disabled as they are not displayed
+ // re-enable if status effects are given a visual element
+ ATTRIB(Disabled, m_name, string, _("Disabled"));
+ ATTRIB(Disabled, m_icon, string, "buff_disability");
+ #endif
+ ATTRIB(Disabled, m_color, vector, '0.94 0.3 1');
+ ATTRIB(Disabled, m_hidden, bool, true);
+ ATTRIB(Disabled, m_lifetime, float, 10);
+ ATTRIB(Disabled, disabled_effect_time, float, 0); // TODO: handle this effect client side like EF_FLAME!
+ ENDCLASS(Disabled)
+ REGISTER_STATUSEFFECT(Disabled, NEW(Disabled));
- REGISTER_BUFF(VENGEANCE) {
- this.m_name = _("Vengeance");
- this.netname = "vengeance";
- this.m_icon = "buff_vengeance";
- this.m_skin = 15;
- this.m_color = '1 0.23 0.61';
- }
+ CLASS(VengeanceBuff, Buff)
+ ATTRIB(VengeanceBuff, m_name, string, _("Vengeance"));
+ ATTRIB(VengeanceBuff, netname, string, "vengeance");
+ ATTRIB(VengeanceBuff, m_icon, string, "buff_vengeance");
+ ATTRIB(VengeanceBuff, m_skin, int, 15);
+ ATTRIB(VengeanceBuff, m_color, vector, '1 0.23 0.61');
+ ENDCLASS(VengeanceBuff)
+ REGISTER_BUFF(VENGEANCE, NEW(VengeanceBuff));
BUFF_SPAWNFUNCS(vengeance, BUFF_VENGEANCE)
+BUFF_SPAWNFUNC_Q3COMPAT(holdable_kamikaze, BUFF_VENGEANCE)
- REGISTER_BUFF(JUMP) {
- this.m_name = _("Jump");
- this.netname = "jump";
- this.m_icon = "buff_jump";
- this.m_skin = 10;
- this.m_color = '0.24 0.78 1';
- }
+ CLASS(JumpBuff, Buff)
+ ATTRIB(JumpBuff, m_name, string, _("Jump"));
+ ATTRIB(JumpBuff, netname, string, "jump");
+ ATTRIB(JumpBuff, m_icon, string, "buff_jump");
+ ATTRIB(JumpBuff, m_skin, int, 10);
+ ATTRIB(JumpBuff, m_color, vector, '0.24 0.78 1');
+ ENDCLASS(JumpBuff)
+ REGISTER_BUFF(JUMP, NEW(JumpBuff));
BUFF_SPAWNFUNCS(jump, BUFF_JUMP)
-BUFF_SPAWNFUNC_Q3TA_COMPAT(jumper, BUFF_JUMP)
+BUFF_SPAWNFUNC_Q3COMPAT(item_jumper, BUFF_JUMP)
- REGISTER_BUFF(INVISIBLE) {
- this.m_name = _("Invisible");
- this.netname = "invisible";
- this.m_icon = "buff_invisible";
- this.m_skin = 12;
- this.m_color = '0.5 0.5 1';
- }
- BUFF_SPAWNFUNCS(invisible, BUFF_INVISIBLE)
- BUFF_SPAWNFUNC_Q3COMPAT(item_invis, BUFF_INVISIBLE)
-
- REGISTER_BUFF(INFERNO) {
- this.m_name = _("Inferno");
- this.netname = "inferno";
- this.m_icon = "buff_inferno";
- this.m_skin = 16;
- this.m_color = '1 0.62 0';
- }
+ CLASS(InfernoBuff, Buff)
+ ATTRIB(InfernoBuff, m_name, string, _("Inferno"));
+ ATTRIB(InfernoBuff, netname, string, "inferno");
+ ATTRIB(InfernoBuff, m_icon, string, "buff_inferno");
+ ATTRIB(InfernoBuff, m_skin, int, 16);
+ ATTRIB(InfernoBuff, m_color, vector, '1 0.62 0');
+ ENDCLASS(InfernoBuff)
+ REGISTER_BUFF(INFERNO, NEW(InfernoBuff));
BUFF_SPAWNFUNCS(inferno, BUFF_INFERNO)
+BUFF_SPAWNFUNC_Q3COMPAT(item_doubler, BUFF_INFERNO)
- REGISTER_BUFF(SWAPPER) {
- this.m_name = _("Swapper");
- this.netname = "swapper";
- this.m_icon = "buff_swapper";
- this.m_skin = 17;
- this.m_color = '0.63 0.36 1';
- }
+ CLASS(SwapperBuff, Buff)
+ ATTRIB(SwapperBuff, m_name, string, _("Swapper"));
+ ATTRIB(SwapperBuff, netname, string, "swapper");
+ ATTRIB(SwapperBuff, m_icon, string, "buff_swapper");
+ ATTRIB(SwapperBuff, m_skin, int, 17);
+ ATTRIB(SwapperBuff, m_color, vector, '0.63 0.36 1');
+ ENDCLASS(SwapperBuff)
+ REGISTER_BUFF(SWAPPER, NEW(SwapperBuff));
BUFF_SPAWNFUNCS(swapper, BUFF_SWAPPER)
+BUFF_SPAWNFUNC_Q3COMPAT(holdable_teleporter, BUFF_SWAPPER)
- REGISTER_BUFF(MAGNET) {
- this.m_name = _("Magnet");
- this.netname = "magnet";
- this.m_icon = "buff_magnet";
- this.m_skin = 18;
- this.m_color = '1 0.95 0.18';
- }
+ CLASS(MagnetBuff, Buff)
+ ATTRIB(MagnetBuff, m_name, string, _("Magnet"));
+ ATTRIB(MagnetBuff, netname, string, "magnet");
+ ATTRIB(MagnetBuff, m_icon, string, "buff_magnet");
+ ATTRIB(MagnetBuff, m_skin, int, 18);
+ ATTRIB(MagnetBuff, m_color, vector, '1 0.95 0.18');
+ ENDCLASS(MagnetBuff)
+ REGISTER_BUFF(MAGNET, NEW(MagnetBuff));
BUFF_SPAWNFUNCS(magnet, BUFF_MAGNET)
- REGISTER_BUFF(LUCK) {
- this.m_name = _("Luck");
- this.netname = "luck";
- this.m_icon = "buff_luck";
- this.m_skin = 19;
- this.m_color = '1 0.23 0.44';
- }
+ CLASS(LuckBuff, Buff)
+ ATTRIB(LuckBuff, m_name, string, _("Luck"));
+ ATTRIB(LuckBuff, netname, string, "luck");
+ ATTRIB(LuckBuff, m_icon, string, "buff_luck");
+ ATTRIB(LuckBuff, m_skin, int, 19);
+ ATTRIB(LuckBuff, m_color, vector, '1 0.23 0.44');
+ ENDCLASS(LuckBuff)
+ REGISTER_BUFF(LUCK, NEW(LuckBuff));
BUFF_SPAWNFUNCS(luck, BUFF_LUCK)
- REGISTER_BUFF(FLIGHT) {
- this.m_name = _("Flight");
- this.netname = "flight";
- this.m_icon = "buff_flight";
- this.m_skin = 11;
- this.m_color = '0.23 0.44 1';
- }
+ CLASS(FlightBuff, Buff)
+ ATTRIB(FlightBuff, m_name, string, _("Flight"));
+ ATTRIB(FlightBuff, netname, string, "flight");
+ ATTRIB(FlightBuff, m_icon, string, "buff_flight");
+ ATTRIB(FlightBuff, m_skin, int, 11);
+ ATTRIB(FlightBuff, m_color, vector, '0.23 0.44 1');
+ ENDCLASS(FlightBuff)
+ REGISTER_BUFF(FLIGHT, NEW(FlightBuff));
BUFF_SPAWNFUNCS(flight, BUFF_FLIGHT)
-BUFF_SPAWNFUNC_Q3TA_COMPAT(flight, BUFF_FLIGHT)
+BUFF_SPAWNFUNC_Q3COMPAT(item_flight, BUFF_FLIGHT)
#include <common/util.qh>
#ifdef GAMEQC
+ #include <common/items/item.qh>
#include <common/mutators/mutator/waypoints/all.qh>
#endif
REGISTER_RADARICON(Buff, 1);
#endif
- #define REGISTER_BUFF(id) \
- REGISTER(StatusEffect, BUFF_##id, m_id, NEW(Buff))
+ #define REGISTER_BUFF(id, inst) \
+ REGISTER(StatusEffect, BUFF_##id, m_id, inst)
#include <common/mutators/mutator/status_effects/_mod.qh>
CLASS(Buff, StatusEffects)
- /** bit index */
- ATTRIB(Buff, m_itemid, int, 0);
+ #ifdef GAMEQC
+ ATTRIB(Buff, m_itemid, int, IT_BUFF);
+ #endif
ATTRIB(Buff, netname, string, "buff");
ATTRIB(Buff, m_icon, string, "buff");
ATTRIB(Buff, m_color, vector, '1 1 1');
STATIC_INIT(REGISTER_BUFFS) {
FOREACH(StatusEffect, it.instanceOfBuff, {
- it.m_itemid = BIT(it.m_id - 1);
it.m_sprite = strzone(strcat("buff-", it.netname));
});
}
void buff_Init_Compat(entity ent, entity replacement);
#define BUFF_SPAWNFUNC(e, b, t) spawnfunc(item_buff_##e) { \
this.buffdef = b; \
- this.team = t; \
+ if(teamplay) \
+ this.team_forced = t; \
buff_Init(this); \
}
#define BUFF_SPAWNFUNCS(e, b) \
BUFF_SPAWNFUNC(e##_team2, b, NUM_TEAM_2) \
BUFF_SPAWNFUNC(e##_team3, b, NUM_TEAM_3) \
BUFF_SPAWNFUNC(e##_team4, b, NUM_TEAM_4)
- #define BUFF_SPAWNFUNC_Q3TA_COMPAT(o, r) spawnfunc(item_##o) { buff_Init_Compat(this, r); }
+ #define BUFF_SPAWNFUNC_Q3COMPAT(o, r) spawnfunc(o) { buff_Init_Compat(this, r); }
#else
#define BUFF_SPAWNFUNC(e, b, t)
#define BUFF_SPAWNFUNCS(e, b)
- #define BUFF_SPAWNFUNC_Q3TA_COMPAT(o, r)
+ #define BUFF_SPAWNFUNC_Q3COMPAT(o, r)
#endif
string Buff_UndeprecateName(string buffname);
#include "sv_buffs.qh"
#include <common/mapobjects/target/music.qh>
- #include <common/mutators/mutator/instagib/_mod.qh>
+ #include <common/mutators/mutator/powerups/_mod.qh>
#include <common/gamemodes/_mod.qh>
#include <server/items/items.qh>
{
entity player = WaypointSprite_getviewentity(client);
entity myowner = this.owner;
+ entity heldbuff = buff_FirstFromFlags(myowner);
+
+ if(!heldbuff)
+ return false;
if(myowner.alpha <= 0.5 && DIFF_TEAM(player, myowner) && myowner.alpha != 0)
return false;
else
{
this.effects = EF_FULLBRIGHT | EF_LOWPRECISION;
- this.alpha = 1;
+ this.alpha = myowner.alpha;
}
return true;
}
+ void buffs_BuffModel_Think(entity this)
+ {
+ this.nextthink = time;
+ entity player = this.owner;
+ if(player.alpha < 0 || player.buff_model != this)
+ {
+ if(player) // remnant from ChatBubbleThink, same question... WHY?!
+ player.buff_model = NULL;
+ delete(this);
+ return;
+ }
+
+ entity heldbuff = buff_FirstFromFlags(player);
+
+ if(!heldbuff)
+ {
+ this.effects = EF_NODRAW;
+ return;
+ }
+
+ this.color = heldbuff.m_color;
+ this.glowmod = heldbuff.m_color;
+ this.skin = heldbuff.m_skin;
+
+ this.effects = player.effects;
+ this.effects |= EF_LOWPRECISION;
+ this.effects = this.effects & EFMASK_CHEAP; // eat performance
+
+ this.alpha = player.alpha;
+ }
+
+ void buffs_BuffModel_Remove(entity player)
+ {
+ if(player.buff_model)
+ delete(player.buff_model);
+ player.buff_model = NULL;
+ }
+
void buffs_BuffModel_Spawn(entity player)
{
player.buff_model = new(buff_model);
setattachment(player.buff_model, player, "");
setorigin(player.buff_model, '0 0 1' * (player.buff_model.maxs.z * 1));
player.buff_model.owner = player;
+ player.buff_model.exteriormodeltoclient = player;
player.buff_model.scale = 0.7;
player.buff_model.pflags = PFLAGS_FULLDYNAMIC;
player.buff_model.light_lev = 200;
+ setthink(player.buff_model, buffs_BuffModel_Think);
+ player.buff_model.nextthink = time;
setcefc(player.buff_model, buffs_BuffModel_Customize);
}
- void buffs_BuffModel_Remove(entity player)
+ void buffs_BuffModel_Update(entity this)
{
- if(player.buff_model)
- delete(player.buff_model);
- player.buff_model = NULL;
- }
-
- vector buff_GlowColor(entity buff)
- {
- //if(buff.team_forced) { return Team_ColorRGB(buff.team_forced); }
- return buff.m_color;
+ if (this.alpha < 0)
+ return;
+ // spawn a buff model entity if needed
+ if (!this.buff_model)
+ buffs_BuffModel_Spawn(this);
}
void buff_Effect(entity player, string eff)
if(autocvar_g_buffs_waypoint_distance <= 0) return;
entity buff = e.buffdef;
- entity wp = WaypointSprite_Spawn(WP_Buff, 0, autocvar_g_buffs_waypoint_distance, e, '0 0 1' * e.maxs.z, NULL, e.team, e, buff_waypoint, true, RADARICON_Buff);
+ entity wp = WaypointSprite_Spawn(WP_Buff, 0, autocvar_g_buffs_waypoint_distance, e, '0 0 1' * e.maxs.z, NULL, e.team_forced, e, buff_waypoint, true, RADARICON_Buff);
wp.wp_extra = buff.m_id;
WaypointSprite_UpdateTeamRadar(e.buff_waypoint, RADARICON_Buff, e.glowmod);
e.buff_waypoint.waypointsprite_visible_for_player = buff_Waypoint_visible_for_player;
if(!IS_PLAYER(toucher))
return; // incase mutator changed toucher
- if((this.team && DIFF_TEAM(toucher, this))
+ if((this.team_forced && toucher.team != this.team_forced)
|| (STAT(FROZEN, toucher))
|| (toucher.vehicle)
|| (!this.buffdef) // TODO: error out or maybe reset type if this occurs?
- || (time < PS(toucher).buff_shield)
+ || (time < toucher.buff_shield)
)
{
// can't touch this
{
entity buff = this.buffdef;
this.color = buff.m_color;
- this.glowmod = buff_GlowColor(buff);
+ this.glowmod = buff.m_color;
this.skin = buff.m_skin;
setmodel(this, MDL_BUFF);
if(this.buff_active)
{
- if(this.team && !this.buff_waypoint)
+ if(this.team_forced && !this.buff_waypoint)
buff_Waypoint_Spawn(this);
if(this.lifetime && time >= this.lifetime)
bool buff_Customize(entity this, entity client)
{
entity player = WaypointSprite_getviewentity(client);
- if((!this.buff_active || !this.buffdef) || (this.team && DIFF_TEAM(player, this)))
+ if((!this.buff_active || !this.buffdef) || (this.team_forced && player.team != this.team_forced))
{
this.alpha = 0.3;
if(this.effects & EF_FULLBRIGHT) { this.effects &= ~(EF_FULLBRIGHT); }
{
if(!cvar("g_buffs")) { delete(this); return; }
- if(!teamplay && this.team) { this.team = 0; }
-
entity buff = this.buffdef;
if(!buff || !buff_Available(buff))
setcefc(this, buff_Customize);
//this.gravity = 100;
this.color = buff.m_color;
- this.glowmod = buff_GlowColor(this);
+ this.glowmod = buff.m_color;
buff_SetCooldown(this, autocvar_g_buffs_cooldown_activate + max(0, game_starttime - time));
this.buff_active = !this.buff_activetime;
this.pflags = PFLAGS_FULLDYNAMIC;
void buff_Init_Compat(entity ent, entity replacement)
{
- if (ent.spawnflags & 2)
- ent.team = NUM_TEAM_1;
- else if (ent.spawnflags & 4)
- ent.team = NUM_TEAM_2;
+ if (teamplay)
+ {
+ if (ent.spawnflags & 2)
+ ent.team_forced = NUM_TEAM_1;
+ else if (ent.spawnflags & 4)
+ ent.team_forced = NUM_TEAM_2;
+ }
ent.buffdef = replacement;
return offset_y + (intersect_y - offset_y) * logn(((damg - offset_x) * ((base - 1) / intersect_x)) + 1, base);
}
+ METHOD(Buff, m_apply, void(StatusEffects this, entity actor, float eff_time, float eff_flags))
+ {
+ if(IS_PLAYER(actor))
+ actor.effects |= EF_NOSHADOW; // does not play well with buff icon
+ SUPER(Buff).m_apply(this, actor, eff_time, eff_flags);
+ }
+ METHOD(Buff, m_remove, void(StatusEffects this, entity actor, int removal_type))
+ {
+ bool wasactive = (actor.statuseffects && (actor.statuseffects.statuseffect_flags[this.m_id] & STATUSEFFECT_FLAG_ACTIVE));
+ if(wasactive)
+ {
+ int buffid = this.m_id;
+ if(removal_type == STATUSEFFECT_REMOVE_TIMEOUT)
+ {
+ Send_Notification(NOTIF_ONE, actor, MSG_MULTI, ITEM_BUFF_DROP, buffid); // TODO: special timeout message?
+ sound(actor, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
+ }
+ else if(removal_type == STATUSEFFECT_REMOVE_NORMAL && !IS_INDEPENDENT_PLAYER(actor))
+ Send_Notification(NOTIF_ALL_EXCEPT, actor, MSG_INFO, INFO_ITEM_BUFF_LOST, actor.netname, buffid);
+ actor.buff_shield = time + max(0, autocvar_g_buffs_pickup_delay); // always put in a delay, even if small
+ }
+ if(IS_PLAYER(actor))
+ actor.effects &= ~EF_NOSHADOW;
+ SUPER(Buff).m_remove(this, actor, removal_type);
+ }
+
+ METHOD(Disabled, m_tick, void(StatusEffects this, entity actor))
+ {
+ if(time >= actor.disabled_effect_time)
+ {
+ Send_Effect(EFFECT_SMOKING, actor.origin + ((actor.mins + actor.maxs) * 0.5), '0 0 0', 1);
+ actor.disabled_effect_time = time + 0.5;
+ }
+ SUPER(Disabled).m_tick(this, actor);
+ }
+ METHOD(Disabled, m_remove, void(StatusEffects this, entity actor, int removal_type))
+ {
+ actor.disabled_effect_time = 0;
+ SUPER(Disabled).m_remove(this, actor, removal_type);
+ }
+
+ METHOD(AmmoBuff, m_apply, void(StatusEffects this, entity actor, float eff_time, float eff_flags))
+ {
+ bool wasactive = (actor.statuseffects && (actor.statuseffects.statuseffect_flags[this.m_id] & STATUSEFFECT_FLAG_ACTIVE));
+ if(!wasactive)
+ {
+ actor.buff_ammo_prev_infitems = (actor.items & IT_UNLIMITED_AMMO);
+ actor.items |= IT_UNLIMITED_AMMO;
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ .entity weaponentity = weaponentities[slot];
+ if(!actor.(weaponentity))
+ continue;
+ if(actor.(weaponentity).clip_load)
+ actor.(weaponentity).buff_ammo_prev_clipload = actor.(weaponentity).clip_load;
+ if(actor.(weaponentity).clip_size)
+ actor.(weaponentity).clip_load = actor.(weaponentity).(weapon_load[actor.(weaponentity).m_switchweapon.m_id]) = actor.(weaponentity).clip_size;
+ }
+ }
+ SUPER(AmmoBuff).m_apply(this, actor, eff_time, eff_flags);
+ }
+ METHOD(AmmoBuff, m_remove, void(StatusEffects this, entity actor, int removal_type))
+ {
+ bool wasactive = (actor.statuseffects && (actor.statuseffects.statuseffect_flags[this.m_id] & STATUSEFFECT_FLAG_ACTIVE));
+ if(wasactive)
+ {
+ actor.items = BITSET(actor.items, IT_UNLIMITED_AMMO, actor.buff_ammo_prev_infitems);
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ .entity weaponentity = weaponentities[slot];
+ if(!actor.(weaponentity))
+ continue;
+ if(actor.(weaponentity).buff_ammo_prev_clipload)
+ {
+ actor.(weaponentity).clip_load = actor.(weaponentity).buff_ammo_prev_clipload;
+ actor.(weaponentity).buff_ammo_prev_clipload = 0;
+ }
+ }
+ }
+ actor.buff_ammo_prev_infitems = 0;
+ SUPER(AmmoBuff).m_remove(this, actor, removal_type);
+ }
+ METHOD(AmmoBuff, m_tick, void(StatusEffects this, entity actor))
+ {
+ if(IS_PLAYER(actor))
+ {
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ .entity weaponentity = weaponentities[slot];
+ if(actor.(weaponentity).clip_size)
+ actor.(weaponentity).clip_load = actor.(weaponentity).(weapon_load[actor.(weaponentity).m_switchweapon.m_id]) = actor.(weaponentity).clip_size;
+ }
+ }
+
+ SUPER(AmmoBuff).m_tick(this, actor);
+ }
+
+
+ METHOD(FlightBuff, m_apply, void(StatusEffects this, entity actor, float eff_time, float eff_flags))
+ {
+ bool wasactive = (actor.statuseffects && (actor.statuseffects.statuseffect_flags[this.m_id] & STATUSEFFECT_FLAG_ACTIVE));
+ if(!wasactive)
+ {
+ actor.buff_flight_oldgravity = actor.gravity;
+ if(!actor.gravity)
+ actor.gravity = 1;
+ }
+ SUPER(FlightBuff).m_apply(this, actor, eff_time, eff_flags);
+ }
+ METHOD(FlightBuff, m_remove, void(StatusEffects this, entity actor, int removal_type))
+ {
+ bool wasactive = (actor.statuseffects && (actor.statuseffects.statuseffect_flags[this.m_id] & STATUSEFFECT_FLAG_ACTIVE));
+ if(wasactive)
+ {
+ actor.gravity = ((actor.trigger_gravity_check) ? actor.trigger_gravity_check.enemy.gravity : actor.buff_flight_oldgravity);
+ }
+ actor.buff_flight_oldgravity = 0;
+ SUPER(FlightBuff).m_remove(this, actor, removal_type);
+ }
+
+ METHOD(MagnetBuff, m_tick, void(StatusEffects this, entity actor))
+ {
+ if(IS_PLAYER(actor))
+ {
+ vector pickup_size;
+ IL_EACH(g_items, it.itemdef,
+ {
+ if(it.buffdef)
+ pickup_size = '1 1 1' * autocvar_g_buffs_magnet_range_buff;
+ else
+ pickup_size = '1 1 1' * autocvar_g_buffs_magnet_range_item;
+
+ if(boxesoverlap(actor.absmin - pickup_size, actor.absmax + pickup_size, it.absmin, it.absmax))
+ {
+ if(gettouch(it))
+ gettouch(it)(it, actor);
+ }
+ });
+ }
+
+ SUPER(MagnetBuff).m_tick(this, actor);
+ }
+
// mutator hooks
MUTATOR_HOOKFUNCTION(buffs, Damage_Calculate)
{
frag_damage = bound(0, frag_damage - reduced, frag_damage);
}
- if(StatusEffects_active(BUFF_SPEED, frag_target))
- if(frag_target != frag_attacker)
- frag_damage *= autocvar_g_buffs_speed_damage_take;
-
if(StatusEffects_active(BUFF_MEDIC, frag_target))
if((GetResource(frag_target, RES_HEALTH) - frag_damage) <= 0)
if(!ITEM_DAMAGE_NEEDKILL(frag_deathtype))
if(StatusEffects_active(BUFF_DISABILITY, frag_attacker))
if(frag_target != frag_attacker)
- frag_target.buff_disability_time = time + autocvar_g_buffs_disability_slowtime;
+ StatusEffects_apply(STATUSEFFECT_Disabled, frag_target, time + autocvar_g_buffs_disability_slowtime, 0);
if(StatusEffects_active(BUFF_INFERNO, frag_target))
{
MUTATOR_HOOKFUNCTION(buffs, PlayerDamage_SplitHealthArmor)
{
+ // NOTE: vampire PlayerDamage_SplitHealthArmor code is similar
entity frag_attacker = M_ARGV(1, entity);
entity frag_target = M_ARGV(2, entity);
if(!StatusEffects_active(BUFF_VAMPIRE, frag_attacker))
return;
float health_take = bound(0, M_ARGV(4, float), GetResource(frag_target, RES_HEALTH));
- if(time >= frag_target.spawnshieldtime &&
- frag_target != frag_attacker &&
- IS_PLAYER(frag_attacker) &&
- !IS_DEAD(frag_target) && !STAT(FROZEN, frag_target))
+ if (!StatusEffects_active(STATUSEFFECT_SpawnShield, frag_target) && frag_target != frag_attacker
+ && IS_PLAYER(frag_attacker) && !IS_DEAD(frag_target) && !STAT(FROZEN, frag_target))
{
- GiveResource(frag_attacker, RES_HEALTH,
- autocvar_g_buffs_vampire_damage_steal * health_take);
+ GiveResource(frag_attacker, RES_HEALTH, autocvar_g_buffs_vampire_damage_steal * health_take);
}
}
- MUTATOR_HOOKFUNCTION(buffs, PlayerSpawn)
- {
- entity player = M_ARGV(0, entity);
-
- buffs_BuffModel_Remove(player);
- player.oldbuffs = NULL;
- // reset timers here to prevent them continuing after re-spawn
- player.buff_disability_time = 0;
- player.buff_disability_effect_time = 0;
- }
-
MUTATOR_HOOKFUNCTION(buffs, PlayerPhysics_UpdateStats)
{
entity player = M_ARGV(0, entity);
// these automatically reset, no need to worry
- if(StatusEffects_active(BUFF_SPEED, player))
- STAT(MOVEVARS_HIGHSPEED, player) *= autocvar_g_buffs_speed_speed;
-
- if(time < player.buff_disability_time)
+ if(StatusEffects_active(STATUSEFFECT_Disabled, player))
STAT(MOVEVARS_HIGHSPEED, player) *= autocvar_g_buffs_disability_speed;
}
{
entity mon = M_ARGV(0, entity);
- if(time < mon.buff_disability_time)
+ if(StatusEffects_active(STATUSEFFECT_Disabled, mon))
{
M_ARGV(1, float) *= autocvar_g_buffs_disability_speed; // run speed
M_ARGV(2, float) *= autocvar_g_buffs_disability_speed; // walk speed
}
}
- MUTATOR_HOOKFUNCTION(buffs, PlayerDies)
- {
- entity frag_target = M_ARGV(2, entity);
-
- entity heldbuff = buff_FirstFromFlags(frag_target);
- if(heldbuff)
- {
- int buffid = heldbuff.m_id;
- if(!IS_INDEPENDENT_PLAYER(frag_target))
- Send_Notification(NOTIF_ALL_EXCEPT, frag_target, MSG_INFO, INFO_ITEM_BUFF_LOST, frag_target.netname, buffid);
-
- buffs_BuffModel_Remove(frag_target);
- }
- }
-
MUTATOR_HOOKFUNCTION(buffs, PlayerUseKey, CBC_ORDER_FIRST)
{
if(MUTATOR_RETURNVALUE || game_stopped || !autocvar_g_buffs_drop) return;
Send_Notification(NOTIF_ALL_EXCEPT, player, MSG_INFO, INFO_ITEM_BUFF_LOST, player.netname, buffid);
buff_RemoveAll(player, STATUSEFFECT_REMOVE_NORMAL);
- PS(player).buff_shield = time + max(0, autocvar_g_buffs_pickup_delay);
+ player.buff_shield = time + max(0, autocvar_g_buffs_pickup_delay);
sound(player, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
return true;
}
{
buffs_BuffModel_Remove(player);
- // also reset timers here to prevent them continuing after spectating
- player.buff_disability_time = 0;
- player.buff_disability_effect_time = 0;
-
return false;
}
MUTATOR_HOOKFUNCTION(buffs, MakePlayerObserver) { entity player = M_ARGV(0, entity); return buffs_RemovePlayer(player); }
MUTATOR_HOOKFUNCTION(buffs, ClientDisconnect) { entity player = M_ARGV(0, entity); return buffs_RemovePlayer(player); }
- MUTATOR_HOOKFUNCTION(buffs, CustomizeWaypoint)
- {
- entity wp = M_ARGV(0, entity);
- entity player = M_ARGV(1, entity);
-
- entity e = WaypointSprite_getviewentity(player);
-
- // if you have the invisibility powerup, sprites ALWAYS are restricted to your team
- // but only apply this to real players, not to spectators
- if((wp.owner.flags & FL_CLIENT) && (e == player) && StatusEffects_active(BUFF_INVISIBLE, wp.owner))
- if(DIFF_TEAM(wp.owner, e))
- return true;
- }
-
MUTATOR_HOOKFUNCTION(buffs, FilterItem)
{
if(autocvar_g_buffs < 0)
entity item = M_ARGV(0, entity);
- if(autocvar_g_buffs_replace_powerups)
+ if(autocvar_g_buffs_replace_powerups && item.itemdef.instanceOfPowerup)
{
- switch(item.classname)
- {
- case "item_strength":
- case "item_shield":
- {
- entity e = spawn();
- buff_SpawnReplacement(e, item);
- return true;
- }
- }
+ entity e = spawn();
+ buff_SpawnReplacement(e, item);
+ return true;
}
return false;
{
entity player = M_ARGV(1, entity);
- if(StatusEffects_active(BUFF_SPEED, player))
- M_ARGV(0, float) *= autocvar_g_buffs_speed_rate;
-
- if(time < player.buff_disability_time)
+ if(StatusEffects_active(STATUSEFFECT_Disabled, player))
M_ARGV(0, float) *= autocvar_g_buffs_disability_rate;
}
{
entity player = M_ARGV(1, entity);
- if(StatusEffects_active(BUFF_SPEED, player))
- M_ARGV(0, float) *= autocvar_g_buffs_speed_weaponspeed;
-
- if(time < player.buff_disability_time)
+ if(StatusEffects_active(STATUSEFFECT_Disabled, player))
M_ARGV(0, float) *= autocvar_g_buffs_disability_weaponspeed;
}
- .bool buff_flight_crouchheld;
+ MUTATOR_HOOKFUNCTION(buffs, Freeze)
+ {
+ entity targ = M_ARGV(0, entity);
+ buff_RemoveAll(targ, STATUSEFFECT_REMOVE_NORMAL);
+ }
MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink)
{
if(game_stopped || IS_DEAD(player) || !IS_PLAYER(player)) return;
+ // NOTE: this is kept here to ensure crouches are picked up each player movement frame
if(StatusEffects_active(BUFF_FLIGHT, player))
{
if(!PHYS_INPUT_BUTTON_CROUCH(player))
}
}
- if(time < player.buff_disability_time)
- if(time >= player.buff_disability_effect_time)
- {
- Send_Effect(EFFECT_SMOKING, player.origin + ((player.mins + player.maxs) * 0.5), '0 0 0', 1);
- player.buff_disability_effect_time = time + 0.5;
- }
-
- // handle buff lost status
- // 1: notify everyone else
- // 2: notify carrier as well
- int buff_lost = 0;
-
- entity heldbuff = buff_FirstFromFlags(player);
- float bufftime = StatusEffects_gettime(heldbuff, player);
- if(heldbuff && bufftime && time >= bufftime)
- buff_lost = 2;
-
- if(STAT(FROZEN, player)) { buff_lost = 1; }
-
- if(buff_lost && heldbuff)
- {
- int buffid = heldbuff.m_id;
- if(buff_lost == 2)
- {
- 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 if(!IS_INDEPENDENT_PLAYER(player))
- Send_Notification(NOTIF_ALL_EXCEPT, player, MSG_INFO, INFO_ITEM_BUFF_LOST, player.netname, buffid);
- buff_RemoveAll(player, STATUSEFFECT_REMOVE_TIMEOUT); // TODO: remove only the currently active buff?
- heldbuff = NULL;
- PS(player).buff_shield = time + max(0, autocvar_g_buffs_pickup_delay); // always put in a delay, even if small
- }
-
- if(StatusEffects_active(BUFF_MAGNET, player))
- {
- vector pickup_size;
- IL_EACH(g_items, it.itemdef,
- {
- if(it.buffdef)
- pickup_size = '1 1 1' * autocvar_g_buffs_magnet_range_buff;
- else
- pickup_size = '1 1 1' * autocvar_g_buffs_magnet_range_item;
-
- if(boxesoverlap(player.absmin - pickup_size, player.absmax + pickup_size, it.absmin, it.absmax))
- {
- if(gettouch(it))
- gettouch(it)(it, player);
- }
- });
- }
-
- if(StatusEffects_active(BUFF_AMMO, player))
- {
- for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
- {
- .entity weaponentity = weaponentities[slot];
- if(player.(weaponentity).clip_size)
- player.(weaponentity).clip_load = player.(weaponentity).(weapon_load[player.(weaponentity).m_switchweapon.m_id]) = player.(weaponentity).clip_size;
- }
- }
-
- if(!player.vehicle && StatusEffects_active(BUFF_INVISIBLE, player) && player.oldbuffs == BUFF_INVISIBLE)
- player.alpha = ((autocvar_g_buffs_invisible_alpha) ? autocvar_g_buffs_invisible_alpha : -1); // powerups reset alpha, so we must enforce this (TODO)
-
- #define BUFF_ONADD(b) if ( (heldbuff == (b)) && (player.oldbuffs != (b)))
- #define BUFF_ONREM(b) if ( (heldbuff != (b)) && (player.oldbuffs == (b)))
-
- if(heldbuff != player.oldbuffs)
- {
- bufftime = heldbuff ? heldbuff.m_time(heldbuff) : 0;
- if(StatusEffects_gettime(heldbuff, player) <= time) // if the player still has a buff countdown, don't reset it!
- {
- player.statuseffects.statuseffect_time[heldbuff.m_id] = (bufftime) ? time + bufftime : 0;
- StatusEffects_update(player);
- }
-
- BUFF_ONADD(BUFF_AMMO)
- {
- player.buff_ammo_prev_infitems = (player.items & IT_UNLIMITED_AMMO);
- player.items |= IT_UNLIMITED_AMMO;
-
- if(StatusEffects_active(BUFF_AMMO, player))
- {
- for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
- {
- .entity weaponentity = weaponentities[slot];
- if(player.(weaponentity).clip_load)
- player.(weaponentity).buff_ammo_prev_clipload = player.(weaponentity).clip_load;
- if(player.(weaponentity).clip_size)
- player.(weaponentity).clip_load = player.(weaponentity).(weapon_load[player.(weaponentity).m_switchweapon.m_id]) = player.(weaponentity).clip_size;
- }
- }
- }
-
- BUFF_ONREM(BUFF_AMMO)
- {
- if(player.buff_ammo_prev_infitems)
- player.items |= IT_UNLIMITED_AMMO;
- else
- player.items &= ~IT_UNLIMITED_AMMO;
-
- if(StatusEffects_active(BUFF_AMMO, player))
- {
- for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
- {
- .entity weaponentity = weaponentities[slot];
- if(player.(weaponentity).buff_ammo_prev_clipload)
- player.(weaponentity).clip_load = player.(weaponentity).buff_ammo_prev_clipload;
- }
- }
- }
-
- BUFF_ONADD(BUFF_INVISIBLE)
- {
- if(StatusEffects_active(STATUSEFFECT_Strength, player) && MUTATOR_IS_ENABLED(mutator_instagib))
- player.buff_invisible_prev_alpha = default_player_alpha; // we don't want to save the powerup's alpha, as player may lose the powerup while holding the buff
- else
- player.buff_invisible_prev_alpha = player.alpha;
- if(!player.vehicle)
- player.alpha = autocvar_g_buffs_invisible_alpha;
- }
-
- BUFF_ONREM(BUFF_INVISIBLE)
- {
- if(!player.vehicle)
- {
- if(StatusEffects_active(STATUSEFFECT_Strength, player) && MUTATOR_IS_ENABLED(mutator_instagib))
- player.alpha = autocvar_g_instagib_invis_alpha;
- else
- player.alpha = player.buff_invisible_prev_alpha;
- }
- }
-
- BUFF_ONADD(BUFF_FLIGHT)
- {
- player.buff_flight_oldgravity = player.gravity;
- if(!player.gravity)
- player.gravity = 1;
- }
-
- BUFF_ONREM(BUFF_FLIGHT)
- player.gravity = ((player.trigger_gravity_check) ? player.trigger_gravity_check.enemy.gravity : player.buff_flight_oldgravity);
-
- player.oldbuffs = heldbuff;
- if(heldbuff)
- {
- if(!player.buff_model)
- buffs_BuffModel_Spawn(player);
-
- player.buff_model.color = heldbuff.m_color;
- player.buff_model.glowmod = buff_GlowColor(heldbuff);
- player.buff_model.skin = heldbuff.m_skin;
-
- player.effects |= EF_NOSHADOW;
- }
- else
- {
- buffs_BuffModel_Remove(player);
-
- player.effects &= ~(EF_NOSHADOW);
- }
- }
-
- if(player.buff_model)
- {
- player.buff_model.effects = player.effects;
- player.buff_model.effects |= EF_LOWPRECISION;
- player.buff_model.effects = player.buff_model.effects & EFMASK_CHEAP; // eat performance
-
- player.buff_model.alpha = player.alpha;
- }
-
- #undef BUFF_ONADD
- #undef BUFF_ONREM
+ if(IS_PLAYER(player))
+ buffs_BuffModel_Update(player);
}
MUTATOR_HOOKFUNCTION(buffs, PlayerRegen)
M_ARGV(4, float) = M_ARGV(1, float) = autocvar_g_buffs_medic_max; // limit_mod = max_mod
M_ARGV(2, float) = autocvar_g_buffs_medic_regen; // regen_mod
}
-
- if(StatusEffects_active(BUFF_SPEED, player))
- M_ARGV(2, float) = autocvar_g_buffs_speed_regen; // regen_mod
}
REPLICATE(cvar_cl_buffs_autoreplace, bool, "cl_buffs_autoreplace");
float autocvar_g_buffs_disability_speed;
float autocvar_g_buffs_disability_rate;
float autocvar_g_buffs_disability_weaponspeed;
- float autocvar_g_buffs_speed_speed;
- float autocvar_g_buffs_speed_rate;
- float autocvar_g_buffs_speed_weaponspeed;
- float autocvar_g_buffs_speed_damage_take;
- float autocvar_g_buffs_speed_regen;
float autocvar_g_buffs_vampire_damage_steal;
- float autocvar_g_buffs_invisible_alpha;
float autocvar_g_buffs_jump_height;
float autocvar_g_buffs_inferno_burntime_factor;
float autocvar_g_buffs_inferno_burntime_min_time;
// ammo
.float buff_ammo_prev_infitems;
.int buff_ammo_prev_clipload;
- // invisible
- .float buff_invisible_prev_alpha;
- // disability
- .float buff_disability_time;
- .float buff_disability_effect_time;
// flight
.float buff_flight_oldgravity;
+ .bool buff_flight_crouchheld;
// common buff variables
.float buff_effect_delay;
// buff definitions
-.float buff_active;
+.bool buff_active;
.float buff_activetime;
-.float buff_activetime_updated;
+.bool buff_activetime_updated;
.entity buff_waypoint;
.entity oldbuffs; // for updating effects
.float buff_shield; // delay for players to keep them from spamming buff pickups
: 0;
STAT(MOVEVARS_AIRSPEEDLIMIT_NONQW, this) = Physics_ClientOption(this, "airspeedlimit_nonqw", autocvar_sv_airspeedlimit_nonqw) * maxspd_mod;
}
- bool q3dfcompat = autocvar_sv_q3defragcompat && autocvar_sv_q3defragcompat_changehitbox; // NOTE: these hitboxes are off by 1 due to engine differences
- STAT(PL_MIN, this) = (q3dfcompat) ? '-15 -15 -20' : autocvar_sv_player_mins;
- STAT(PL_MAX, this) = (q3dfcompat) ? '15 15 36' : autocvar_sv_player_maxs;
- STAT(PL_VIEW_OFS, this) = (q3dfcompat) ? '0 0 30' : autocvar_sv_player_viewoffset;
- STAT(PL_CROUCH_MIN, this) = (q3dfcompat) ? '-15 -15 -20' : autocvar_sv_player_crouch_mins;
- STAT(PL_CROUCH_MAX, this) = (q3dfcompat) ? '15 15 20' : autocvar_sv_player_crouch_maxs;
- STAT(PL_CROUCH_VIEW_OFS, this) = (q3dfcompat) ? '0 0 16' : autocvar_sv_player_crouch_viewoffset;
+ bool q3hb = q3compat && autocvar_sv_q3compat_changehitbox;
+ STAT(PL_MIN, this) = (q3hb) ? '-15 -15 -20' : autocvar_sv_player_mins;
+ STAT(PL_MAX, this) = (q3hb) ? '15 15 36' : autocvar_sv_player_maxs;
+ STAT(PL_VIEW_OFS, this) = (q3hb) ? '0 0 30' : autocvar_sv_player_viewoffset;
+ STAT(PL_CROUCH_MIN, this) = (q3hb) ? '-15 -15 -20' : autocvar_sv_player_crouch_mins;
+ STAT(PL_CROUCH_MAX, this) = (q3hb) ? '15 15 20' : autocvar_sv_player_crouch_maxs;
+ STAT(PL_CROUCH_VIEW_OFS, this) = (q3hb) ? '0 0 16' : autocvar_sv_player_crouch_viewoffset;
// old stats
// fix some new settings
{ // open at eye level
this.velocity_z = 225;
this.flags |= FL_WATERJUMP;
+ this.teleport_time = time + 2; // safety net
SET_JUMP_HELD(this);
}
}
if (!CheatImpulse(this, CHIMPULSE_GIVE_ALL.impulse))
LOG_INFO("A hollow voice says \"Plugh\".");
}
- else
- STAT(MOVEVARS_SPECIALCOMMAND, this) = true;
}
#endif
{
#ifdef SVQC
string c;
- if (!buttons)
- c = "x";
- else if (buttons == 1)
- c = "1";
- else if (buttons == 2)
- c = " ";
- else if (buttons == 128)
- c = "s";
- else if (buttons == 256)
- c = "w";
- else if (buttons == 512)
- c = "a";
- else if (buttons == 1024)
- c = "d";
- else
- c = "?";
+ switch (buttons)
+ {
+ // buttons mapped in PHYS_INPUT_BUTTON_MASK
+ case 0: c = "x"; break;
+ case BIT(0): c = "1"; break;
+ case BIT(2): c = " "; break;
+ case BIT(7): c = "s"; break;
+ case BIT(8): c = "w"; break;
+ case BIT(9): c = "a"; break;
+ case BIT(10): c = "d"; break;
+ default: c = "?";
+ }
if (c == substring(specialcommand, CS(this).specialcommand_pos, 1))
{
#ifdef SVQC
#include <server/client.qh>
+#include <server/compat/quake3.qh>
#include <server/main.qh>
#include <common/gamemodes/sv_rules.qh>
#include <common/mapobjects/teleporters.qh>
REGISTER_STAT(PL_MAX, vector)
REGISTER_STAT(PL_CROUCH_MAX, vector)
- REGISTER_STAT(KH_KEYS, int)
+ // networked bitflag for game objective display (modicons)
+ REGISTER_STAT(OBJECTIVE_STATUS, int)
+ #ifdef SVQC
+ SPECTATE_COPYFIELD(_STAT(OBJECTIVE_STATUS))
+ #endif
#ifdef SVQC
float W_WeaponRateFactor(entity this);
float game_stopped;
float game_starttime; //point in time when the countdown to game start is over
float round_starttime; //point in time when the countdown to round start is over
- bool autocvar_g_allow_oldvortexbeam;
int autocvar_leadlimit;
// TODO: world.qh can't be included here due to circular includes!
#define autocvar_fraglimit cvar("fraglimit")
REGISTER_STAT(GAMESTARTTIME, float, game_starttime)
/** arc heat in [0,1] */
REGISTER_STAT(PRESSED_KEYS, int)
- /** this stat could later contain some other bits of info, like, more server-side particle config */
- REGISTER_STAT(ALLOW_OLDVORTEXBEAM, bool, autocvar_g_allow_oldvortexbeam)
REGISTER_STAT(FUEL, int)
REGISTER_STAT(NB_METERSTART, float)
/** compressShotOrigin */
REGISTER_STAT(FROZEN, int)
REGISTER_STAT(REVIVE_PROGRESS, float)
REGISTER_STAT(ROUNDLOST, int)
- REGISTER_STAT(CTF_FLAGSTATUS, int)
REGISTER_STAT(CAPTURE_PROGRESS, float)
REGISTER_STAT(ENTRAP_ORB, float)
REGISTER_STAT(ENTRAP_ORB_ALPHA, float)
float g_bugrigs_speed_pow;
float g_bugrigs_steer;
#endif
+ #if 0
REGISTER_STAT(BUGRIGS, int, g_bugrigs)
REGISTER_STAT(BUGRIGS_ACCEL, float, g_bugrigs_accel)
REGISTER_STAT(BUGRIGS_AIR_STEERING, int, g_bugrigs_air_steering)
REGISTER_STAT(BUGRIGS_SPEED_POW, float, g_bugrigs_speed_pow)
REGISTER_STAT(BUGRIGS_SPEED_REF, float, g_bugrigs_speed_ref)
REGISTER_STAT(BUGRIGS_STEER, float, g_bugrigs_steer)
+ #endif
#ifdef SVQC
int autocvar_sv_gameplayfix_downtracesupportsongroundflag = 1;
#endif
REGISTER_STAT(SLICK_APPLYGRAVITY, bool, autocvar_sv_slick_applygravity)
-#ifdef SVQC
-bool autocvar_sv_q3defragcompat;
-#endif
-REGISTER_STAT(Q3DEFRAGCOMPAT, bool, autocvar_sv_q3defragcompat)
+REGISTER_STAT(Q3COMPAT, int, q3compat)
#ifdef SVQC
#include "physics/movetypes/movetypes.qh"
REGISTER_STAT(MOVEVARS_STEPHEIGHT, float, autocvar_sv_stepheight)
REGISTER_STAT(MOVEVARS_AIRACCEL_QW, float)
REGISTER_STAT(MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION, float)
- REGISTER_STAT(MOVEVARS_SPECIALCOMMAND, bool)
#ifdef SVQC
int autocvar_sv_wallclip;
#endif
noref bool require_spawnfunc_prefix;
.bool spawnfunc_checked;
/** Not for production use, provides access to a dump of the entity's fields when it is parsed from map data */
-//noref string __fullspawndata;
+noref string __fullspawndata;
+.string fullspawndata;
// Optional type checking; increases compile time too much to be enabled by default
#if 0
FIELD_SCALAR(fld, height) \
FIELD_SCALAR(fld, impulse) \
FIELD_SCALAR(fld, invincible_finished) \
+ FIELD_SCALAR(fld, invisibility_finished) \
FIELD_SCALAR(fld, item_pickupsound) \
FIELD_SCALAR(fld, killtarget) \
FIELD_SCALAR(fld, lerpfrac) \
FIELD_SCALAR(fld, noise2) \
FIELD_SCALAR(fld, noise3) \
FIELD_SCALAR(fld, noise) \
+ FIELD_SCALAR(fld, notcpm) \
+ FIELD_SCALAR(fld, notfree) \
+ FIELD_SCALAR(fld, notta) \
+ FIELD_SCALAR(fld, notteam) \
+ FIELD_SCALAR(fld, notvq3) \
FIELD_SCALAR(fld, phase) \
FIELD_SCALAR(fld, platmovetype) \
FIELD_SCALAR(fld, race_place) \
+ FIELD_SCALAR(fld, speed_finished) \
FIELD_SCALAR(fld, strength_finished) \
FIELD_SCALAR(fld, radius) \
FIELD_SCALAR(fld, respawntimestart) \
this.classname = #id; \
if (!this.spawnfunc_checked) { \
_checkWhitelisted(this, #id); \
+ if (__fullspawndata) { \
+ /* not supported in old DP */ \
+ /* must be read inside the real spawnfunc */ \
+ this.fullspawndata = __fullspawndata; \
+ } \
this.spawnfunc_checked = true; \
if (this) { \
/* not worldspawn, delay spawn */ \
case "spawnfunc":
case "weaponchild":
case "chatbubbleentity":
+ case "buff_model":
//case "net_linked": // actually some real entities are linked without classname, fail
case "":
return true;
bool WarpZoneLib_ExactTrigger_Touch(entity this, entity toucher)
{
vector emin = toucher.absmin, emax = toucher.absmax;
- // the engine offsets absolute bounding boxes by a single quake unit
- // we must undo that here to allow accurate touching
- emin += '1 1 1';
- emax -= '1 1 1';
+ if(STAT(Q3COMPAT))
+ {
+ // DP's tracebox enlarges absolute bounding boxes by a single quake unit
+ // we must undo that here to allow accurate touching
+ emin += '1 1 1';
+ emax -= '1 1 1';
+ }
return !WarpZoneLib_BoxTouchesBrush(emin, emax, this, toucher);
}
#include <common/effects/qc/globalsound.qh>
#include <common/ent_cs.qh>
#include <common/gamemodes/_mod.qh>
+ #include <common/gamemodes/gamemode/lms/sv_lms.qh>
#include <common/gamemodes/gamemode/nexball/sv_nexball.qh>
#include <common/items/_mod.qh>
#include <common/items/inventory.qh>
PS(this).dual_weapons = '0 0 0';
+ if(STAT(WEAPONS, this) & WEPSET_SUPERWEAPONS)
+ StatusEffects_apply(STATUSEFFECT_Superweapons, this, time + autocvar_g_balance_superweapons_time, 0);
+
this.items = start_items;
- this.spawnshieldtime = time + autocvar_g_spawnshieldtime;
+ float shieldtime = time + autocvar_g_spawnshieldtime;
+
this.pauserotarmor_finished = time + autocvar_g_balance_pause_armor_rot_spawn;
this.pauserothealth_finished = time + autocvar_g_balance_pause_health_rot_spawn;
this.pauserotfuel_finished = time + autocvar_g_balance_pause_fuel_rot_spawn;
if (!sv_ready_restart_after_countdown && time < game_starttime)
{
float f = game_starttime - time;
- this.spawnshieldtime += f;
+ shieldtime += f;
this.pauserotarmor_finished += f;
this.pauserothealth_finished += f;
this.pauseregen_finished += f;
}
+ StatusEffects_apply(STATUSEFFECT_SpawnShield, this, shieldtime, 0);
+
this.damageforcescale = autocvar_g_player_damageforcescale;
this.death_time = 0;
this.respawn_flags = 0;
this.respawn_time = 0;
STAT(RESPAWN_TIME, this) = 0;
- bool q3dfcompat = autocvar_sv_q3defragcompat && autocvar_sv_q3defragcompat_changehitbox;
- this.scale = ((q3dfcompat) ? 0.9 : autocvar_sv_player_scale);
+ this.scale = ((q3compat && autocvar_sv_q3compat_changehitbox) ? 0.9 : autocvar_sv_player_scale);
this.fade_time = 0;
this.pain_finished = 0;
this.pushltime = 0;
modifications = strcat(modifications, ", Weapons stay");
if(autocvar_g_jetpack)
modifications = strcat(modifications, ", Jet pack");
- if(autocvar_g_powerups == 0)
- modifications = strcat(modifications, ", No powerups");
- if(autocvar_g_powerups > 0)
- modifications = strcat(modifications, ", Powerups");
modifications = substring(modifications, 2, strlen(modifications) - 2);
string versionmessage = GetClientVersionMessage(this);
- string s = strcat(versionmessage, "^8\n^8\nhost is ^9", autocvar_hostname, "^8\n");
+ string s = strcat(versionmessage, "^8\n^8\nserver is ^9", autocvar_hostname, "^8\n");
s = strcat(s, "^8\nmatch type is ^1", gamemode_name, "^8\n");
return s;
}
- bool autocvar_sv_qcphysics = true; // TODO this is for testing - remove when qcphysics work
-
/**
=============
ClientConnect
void player_powerups_remove_all(entity this)
{
- if (this.items & (ITEM_Strength.m_itemid | ITEM_Shield.m_itemid | IT_SUPERWEAPON))
+ if (this.items & IT_SUPERWEAPON)
{
// don't play the poweroff sound when the game restarts or the player disconnects
if (time > game_starttime + 1 && IS_CLIENT(this))
sound(this, CH_INFO, SND_POWEROFF, VOL_BASE, ATTEN_NORM);
stopsound(this, CH_TRIGGER_SINGLE); // get rid of the pickup sound
- this.items &= ~ITEM_Strength.m_itemid;
- this.items &= ~ITEM_Shield.m_itemid;
this.items -= (this.items & IT_SUPERWEAPON);
}
}
else
this.modelflags &= ~MF_ROCKET;
- this.effects &= ~(EF_RED | EF_BLUE | EF_ADDITIVE | EF_FULLBRIGHT | EF_NODEPTHTEST);
+ this.effects &= ~EF_NODEPTHTEST;
if (IS_DEAD(this))
player_powerups_remove_all(this);
if (!MUTATOR_IS_ENABLED(mutator_instagib))
{
- if (this.items & ITEM_Strength.m_itemid)
- {
- play_countdown(this, StatusEffects_gettime(STATUSEFFECT_Strength, this), SND_POWEROFF);
- this.effects = this.effects | (EF_BLUE | EF_ADDITIVE | EF_FULLBRIGHT);
- if (time > StatusEffects_gettime(STATUSEFFECT_Strength, this))
- {
- this.items = this.items - (this.items & ITEM_Strength.m_itemid);
- //Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERDOWN_STRENGTH, this.netname);
- Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_POWERDOWN_STRENGTH);
- }
- }
- else
- {
- if (time < StatusEffects_gettime(STATUSEFFECT_Strength, this))
- {
- this.items = this.items | ITEM_Strength.m_itemid;
- if(!g_cts)
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERUP_STRENGTH, this.netname);
- Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_POWERUP_STRENGTH);
- }
- }
- if (this.items & ITEM_Shield.m_itemid)
- {
- play_countdown(this, StatusEffects_gettime(STATUSEFFECT_Shield, this), SND_POWEROFF);
- this.effects = this.effects | (EF_RED | EF_ADDITIVE | EF_FULLBRIGHT);
- if (time > StatusEffects_gettime(STATUSEFFECT_Shield, this))
- {
- this.items = this.items - (this.items & ITEM_Shield.m_itemid);
- //Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERDOWN_SHIELD, this.netname);
- Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_POWERDOWN_SHIELD);
- }
- }
- else
- {
- if (time < StatusEffects_gettime(STATUSEFFECT_Shield, this))
- {
- this.items = this.items | ITEM_Shield.m_itemid;
- if(!g_cts)
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERUP_SHIELD, this.netname);
- Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_POWERUP_SHIELD);
- }
- }
+ // NOTE: superweapons are a special case and as such are handled here instead of the status effects system
if (this.items & IT_SUPERWEAPON)
{
if (!(STAT(WEAPONS, this) & WEPSET_SUPERWEAPONS))
if(autocvar_g_fullbrightplayers)
this.effects = this.effects | EF_FULLBRIGHT;
- if (time >= game_starttime)
- if (time < this.spawnshieldtime)
- this.effects = this.effects | (EF_ADDITIVE | EF_FULLBRIGHT);
-
MUTATOR_CALLHOOK(PlayerPowerups, this, items_prev);
}
Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_MOVETOSPEC_IDLING, this.netname, maxidle_time);
if (this.caplayer)
this.caplayer = 0;
+ this.lms_spectate_warning = 2; // TODO: mutator hook for players forcibly moved to spectator?
PutObserverInServer(this);
}
else
#include <common/mapobjects/triggers.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/notifications/all.qh>
#include <common/stats.qh>
#include <server/resources.qh>
#include <server/world.qh>
-//***********************
-//QUAKE 3 ENTITIES - So people can play quake3 maps with the xonotic weapons
-//***********************
+/***********************
+ * QUAKE 3 ENTITIES - So people can play quake3 maps with the xonotic weapons
+ ***********************
+
+ * Map entities NOT handled in this file:
+ holdable_invulnerability Q3TA buffs mutator
+ holdable_kamikaze Q3TA buffs mutator
+ holdable_teleporter Q3A buffs mutator
+ item_ammoregen Q3TA buffs mutator
+ item_doubler Q3TA buffs mutator
+ item_guard Q3TA buffs mutator
+ item_scout Q3TA buffs mutator
+ item_armor_jacket CPMA quake2.qc
+ item_flight Q3A buffs mutator
+ item_haste Q3A buffs mutator
+ item_health Q3A quake.qc
+ item_health_large Q3A items.qc
+ item_health_small Q3A health.qh
+ item_health_mega Q3A health.qh
+ item_invis Q3A buffs mutator
+ item_quad Q3A items.qc
+ item_regen Q3A buffs mutator
+ weapon_machinegun Q3A machinegun.qh
+ weapon_grenadelauncher Q3A mortar.qh
+ weapon_rocketlauncher Q3A devastator.qh
+ CTF spawnfuncs handled in sv_ctf.qc
+
+ NOTE: for best experience, you need to swap MGs with SGs in the map or it won't have a MG
+*/
+
+// SG -> MG || SG
+SPAWNFUNC_Q3_COND(weapon_shotgun, ammo_shells, (q3compat & Q3COMPAT_ARENA), WEP_MACHINEGUN, WEP_SHOTGUN)
+
+// MG -> SG || MG
+// Technically we should replace weapon_machinegun with WEP_SHOTGUN if Q3COMPAT_ARENA, but it almost never occurs on Q3 maps
+SPAWNFUNC_Q3AMMO_COND(ammo_bullets, (q3compat & Q3COMPAT_ARENA), WEP_SHOTGUN, WEP_MACHINEGUN)
-// NOTE: for best experience, you need to swap MGs with SGs in the map or it won't have a MG
+// GL -> Mortar
+SPAWNFUNC_Q3AMMO(ammo_grenades, WEP_MORTAR)
-// SG -> SG
-SPAWNFUNC_ITEM(ammo_shells, ITEM_Shells)
+// Team Arena Proximity Launcher -> Mortar
+// It's more accurate to spawn Mine Layer but players prefer Mortar, and weapon_grenadelauncher is usually disabled by "notta" and weapon_prox_launcher placed at the same origin
+SPAWNFUNC_Q3(weapon_prox_launcher, ammo_mines, WEP_MORTAR)
-// MG -> MG
-SPAWNFUNC_ITEM(ammo_bullets, ITEM_Bullets)
+// Team Arena Chaingun -> HLAC
+SPAWNFUNC_Q3(weapon_chaingun, ammo_belt, WEP_HLAC)
-// GL -> Mortar
-SPAWNFUNC_ITEM(ammo_grenades, ITEM_Rockets)
+// Quake Live Heavy Machine Gun -> HLAC
+SPAWNFUNC_Q3(weapon_hmg, ammo_hmg, WEP_HLAC)
-// Mines -> Rockets
-SPAWNFUNC_WEAPON(weapon_prox_launcher, WEP_MINE_LAYER)
-SPAWNFUNC_ITEM(ammo_mines, ITEM_Rockets)
+// Team Arena Nailgun -> Crylink || Quake Nailgun -> Electro
+SPAWNFUNC_Q3_COND(weapon_nailgun, ammo_nails, cvar("sv_mapformat_is_quake3"), WEP_CRYLINK, WEP_ELECTRO)
-// LG -> Lightning
-SPAWNFUNC_WEAPON(weapon_lightning, WEP_ELECTRO)
-SPAWNFUNC_ITEM(ammo_lightning, ITEM_Cells)
+// LG -> Electro
+SPAWNFUNC_Q3(weapon_lightning, ammo_lightning, WEP_ELECTRO)
// Plasma -> Hagar
-SPAWNFUNC_WEAPON(weapon_plasmagun, WEP_HAGAR)
-SPAWNFUNC_ITEM(ammo_cells, ITEM_Rockets)
+SPAWNFUNC_Q3(weapon_plasmagun, ammo_cells, WEP_HAGAR)
// Rail -> Vortex
-SPAWNFUNC_WEAPON(weapon_railgun, WEP_VORTEX)
-SPAWNFUNC_ITEM(ammo_slugs, ITEM_Cells)
+SPAWNFUNC_Q3(weapon_railgun, ammo_slugs, WEP_VORTEX)
-// BFG -> Crylink
-SPAWNFUNC_WEAPON(weapon_bfg, WEP_CRYLINK)
-SPAWNFUNC_ITEM(ammo_bfg, ITEM_Cells)
+// BFG -> Crylink || Fireball
+SPAWNFUNC_Q3_COND(weapon_bfg, ammo_bfg, cvar_string("g_mod_balance") == "XDF", WEP_CRYLINK, WEP_FIREBALL)
+ // FIXME: WEP_FIREBALL has no ammo_type field so ammo_bfg is deleted by SPAWNFUNC_BODY
// grappling hook -> hook
SPAWNFUNC_WEAPON(weapon_grapplinghook, WEP_HOOK)
// RL -> RL
-SPAWNFUNC_ITEM(ammo_rockets, ITEM_Rockets)
+SPAWNFUNC_Q3AMMO(ammo_rockets, WEP_DEVASTATOR)
+
+// Gauntlet -> Tuba
+SPAWNFUNC_ITEM(weapon_gauntlet, WEP_TUBA)
// Armor
SPAWNFUNC_ITEM(item_armor_body, ITEM_ArmorMega)
SPAWNFUNC_ITEM(item_armor_combat, ITEM_ArmorBig)
SPAWNFUNC_ITEM(item_armor_shard, ITEM_ArmorSmall)
+SPAWNFUNC_ITEM(item_armor_green, ITEM_ArmorMedium) // CCTF
+
+// Battle Suit
SPAWNFUNC_ITEM(item_enviro, ITEM_Shield)
// medkit -> armor (we have no holdables)
if (!(this.spawnflags & 8))
{
- StatusEffects_remove(STATUSEFFECT_Strength, actor, STATUSEFFECT_REMOVE_NORMAL);
- StatusEffects_remove(STATUSEFFECT_Shield, actor, STATUSEFFECT_REMOVE_NORMAL);
+ FOREACH(StatusEffect, it.instanceOfPowerups,
+ {
+ it.m_remove(it, actor, STATUSEFFECT_REMOVE_NORMAL);
+ });
entity heldbuff = buff_FirstFromFlags(actor);
if(heldbuff) // TODO: make a dropbuffs function to handle this
{
InitializeEntity(this, target_init_verify, INITPRIO_FINDTARGET);
}
-// weapon give ent from defrag
+// weapon give ent from Q3
void target_give_init(entity this)
{
IL_EACH(g_items, it.targetname == this.target,
{
- if (it.classname == "weapon_devastator") {
- SetResourceExplicit(this, RES_ROCKETS, GetResource(this, RES_ROCKETS) + it.count * WEP_CVAR_PRI(devastator, ammo)); // WEAPONTODO
- this.netname = cons(this.netname, "devastator");
- }
- else if (it.classname == "weapon_vortex") {
- SetResourceExplicit(this, RES_CELLS, GetResource(this, RES_CELLS) + it.count * WEP_CVAR_PRI(vortex, ammo)); // WEAPONTODO
- this.netname = cons(this.netname, "vortex");
- }
- else if (it.classname == "weapon_electro") {
- SetResourceExplicit(this, RES_CELLS, GetResource(this, RES_CELLS) + it.count * WEP_CVAR_PRI(electro, ammo)); // WEAPONTODO
- this.netname = cons(this.netname, "electro");
- }
- else if (it.classname == "weapon_hagar") {
- SetResourceExplicit(this, RES_ROCKETS, GetResource(this, RES_ROCKETS) + it.count * WEP_CVAR_PRI(hagar, ammo)); // WEAPONTODO
- this.netname = cons(this.netname, "hagar");
- }
- else if (it.classname == "weapon_crylink") {
- SetResourceExplicit(this, RES_CELLS, GetResource(this, RES_CELLS) + it.count * WEP_CVAR_PRI(crylink, ammo)); // WEAPONTODO
- this.netname = cons(this.netname, "crylink");
- }
- else if (it.classname == "weapon_mortar") {
- SetResourceExplicit(this, RES_ROCKETS, GetResource(this, RES_ROCKETS) + it.count * WEP_CVAR_PRI(mortar, ammo)); // WEAPONTODO
- this.netname = cons(this.netname, "mortar");
- }
- else if (it.classname == "weapon_shotgun") {
- SetResourceExplicit(this, RES_SHELLS, GetResource(this, RES_SHELLS) + it.count * WEP_CVAR_PRI(shotgun, ammo)); // WEAPONTODO
- this.netname = cons(this.netname, "shotgun");
- }
- else if (it.classname == "item_armor_mega")
- SetResourceExplicit(this, RES_ARMOR, 100);
- else if (it.classname == "item_health_mega")
- SetResourceExplicit(this, RES_HEALTH, 200);
- else if (it.classname == "item_buff") {
+ if (it.classname == "item_buff")
+ {
entity buff = it.buffdef;
this.netname = cons(this.netname, buff.netname);
- this.buffs_finished = it.count;
+ this.buffs_finished += it.count;
+ }
+ else
+ {
+ if (it.ammo_rockets)
+ this.ammo_rockets += it.ammo_rockets;
+ else if (it.ammo_cells)
+ this.ammo_cells += it.ammo_cells;
+ else if (it.ammo_shells)
+ this.ammo_shells += it.ammo_shells;
+ else if (it.ammo_nails)
+ this.ammo_nails += it.ammo_nails;
+ else if (it.invincible_finished)
+ this.invincible_finished += it.invincible_finished;
+ else if (it.strength_finished)
+ this.strength_finished += it.strength_finished;
+ else if (it.health)
+ this.health += it.health;
+ else if (it.armorvalue)
+ this.armorvalue += it.armorvalue;
+
+ this.netname = cons(this.netname, it.netname);
}
//remove(it); // removing ents in init functions causes havoc, workaround:
- setthink(it, SUB_Remove);
- it.nextthink = time;
+ setthink(it, SUB_Remove);
+ it.nextthink = time;
});
this.spawnflags = 2;
this.spawnfunc_checked = true;
this.use = fragsfilter_use;
}
-//spawnfunc(item_flight) /* handled by buffs mutator */
-//spawnfunc(item_doubler) /* handled by buffs mutator */
-//spawnfunc(item_haste) /* handled by powerups mutator */
-//spawnfunc(item_health) /* handled in t_quake.qc */
-//spawnfunc(item_health_large) /* handled in items.qc */
-//spawnfunc(item_health_small) /* handled in items.qc */
-//spawnfunc(item_health_mega) /* handled in items.qc */
-//spawnfunc(item_invis) /* handled by powerups mutator */
-//spawnfunc(item_regen) /* handled by buffs mutator */
-
-// CTF spawnfuncs handled in mutators/gamemode_ctf.qc now
-
-.float notteam;
-.float notsingle;
-.float notfree;
-.float notq3a;
-.float notta;
+.bool notteam;
+.bool notsingle;
+.bool notfree;
+.bool notta;
+.bool notvq3;
+.bool notcpm;
.string gametype;
bool DoesQ3ARemoveThisEntity(entity this)
{
// Q3 style filters (DO NOT USE, THIS IS COMPAT ONLY)
- if(this.notq3a)
- if(!teamplay || g_tdm || g_ctf)
+ // DeFRaG mappers use "notcpm" or "notvq3" to disable an entity in CPM or VQ3 physics
+ // Xonotic is usually played with a CPM-based physics so we default to CPM mode
+ if(cvar_string("g_mod_physics") == "Q3")
+ {
+ if(this.notvq3)
return true;
+ }
+ else if(this.notcpm)
+ return true;
+ // Q3 mappers use "notq3a" or "notta" to disable an entity in Q3A or Q3TA
+ // Xonotic has ~equivalent features to Team Arena
if(this.notta)
- if (!(!teamplay || g_tdm || g_ctf))
- return true;
+ return true;
if(this.notsingle)
if(maxclients == 1)
if(this.gametype)
{
string gametypename;
- // static char *gametypeNames[] = {"ffa", "tournament", "single", "team", "ctf", "oneflag", "obelisk", "harvester", "teamtournament"}
+ // From ioq3 g_spawn.c: static char *gametypeNames[] = {"ffa", "tournament", "single", "team", "ctf", "oneflag", "obelisk", "harvester"};
gametypename = "ffa";
if(teamplay)
gametypename = "team";
gametypename = "tournament";
if(maxclients == 1)
gametypename = "single";
- // we do not have the other types (obelisk, harvester, teamtournament)
+ // we do not have the other types (obelisk, harvester)
if(strstrofs(this.gametype, gametypename, 0) < 0)
return true;
}
return false;
}
+
+int GetAmmoConsumptionQ3(string netname)
+// Returns ammo consumed per shot by the primary/default fire mode
+// Returns 0 if the netname has no ammo cvar
+{
+ switch (netname)
+ {
+ case "arc": return autocvar_g_balance_arc_beam_ammo;
+ case "devastator": return autocvar_g_balance_devastator_ammo;
+ case "machinegun": return autocvar_g_balance_machinegun_sustained_ammo;
+ case "minelayer": return autocvar_g_balance_minelayer_ammo;
+ case "seeker": return autocvar_g_balance_seeker_tag_ammo;
+ default: return cvar(strcat("g_balance_", netname, "_primary_ammo"));
+ }
+}
+
#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/notifications/all.qh>
#include <common/util.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");
pickedup = true;
StatusEffects_apply(STATUSEFFECT_Shield, player, max(StatusEffects_gettime(STATUSEFFECT_Shield, player), time) + item.invincible_finished, 0);
}
+ if (item.speed_finished)
+ {
+ pickedup = true;
+ StatusEffects_apply(STATUSEFFECT_Speed, player, max(StatusEffects_gettime(STATUSEFFECT_Speed, player), time) + item.speed_finished, 0);
+ }
+ if (item.invisibility_finished)
+ {
+ pickedup = true;
+ StatusEffects_apply(STATUSEFFECT_Invisibility, player, max(StatusEffects_gettime(STATUSEFFECT_Invisibility, player), time) + item.invisibility_finished, 0);
+ }
if (item.superweapons_finished)
{
pickedup = true;
{
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;
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(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))
this.bot_pickupevalfunc = pickupevalfunc;
this.bot_pickupbasevalue = pickupbasevalue;
this.mdl = this.model ? this.model : strzone(this.item_model_ent.model_str());
- this.netname = itemname;
+ this.netname = (def.m_weapon) ? def.m_weapon.netname : def.netname;
settouch(this, Item_Touch);
setmodel(this, MDL_Null); // precision set below
//this.effects |= EF_LOWPRECISION;
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;
+ }
+
+ 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;
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");
}
if(new_buff_time <= 0)
{
- StatusEffects_remove(thebuff, e, STATUSEFFECT_REMOVE_TIMEOUT);
+ if(had_buff) // only trigger removal mechanics if there is an effect to remove!
+ StatusEffects_remove(thebuff, e, STATUSEFFECT_REMOVE_NORMAL);
}
else
{
break;
}
if(new_eff_time <= 0)
- StatusEffects_remove(this, e, STATUSEFFECT_REMOVE_TIMEOUT);
+ {
+ 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);
PREGIVE_WEAPONS(e);
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);
continue;
case "ALL":
got += GiveBit(e, items, ITEM_JetpackRegen.m_itemid, op, val);
- got += GiveStatusEffect(e, STATUSEFFECT_Strength, op, val);
- got += GiveStatusEffect(e, STATUSEFFECT_Shield, op, val);
- got += GiveStatusEffect(e, STATUSEFFECT_Superweapons, 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);
got += GiveStatusEffect(e, STATUSEFFECT_Strength, op, val);
break;
case "invincible":
+ 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 += GiveStatusEffect(e, STATUSEFFECT_Superweapons, op, val);
break;
if(STAT(WEAPONS, e) & (it.m_wepset))
it.wr_init(it);
});
- POSTGIVE_STATUSEFFECT(e, STATUSEFFECT_Strength, 1, SND_POWERUP, SND_POWEROFF);
- POSTGIVE_STATUSEFFECT(e, STATUSEFFECT_Shield, 1, SND_POWERUP, SND_POWEROFF);
+ 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);
float autocvar_g_balance_superweapons_time;
bool autocvar_g_fullbrightitems;
- int autocvar_g_powerups;
float autocvar_g_items_mindist;
float autocvar_g_items_maxdist;
int autocvar_g_pickup_items;
.float max_armorvalue;
.float pickup_anyway;
+.int count;
.float scheduledrespawntime;
.float respawntime;
#define PREGIVE_WEAPONS(e) WepSet save_weapons; save_weapons = STAT(WEAPONS, e)
#define PREGIVE(e,f) float save_##f; save_##f = (e).f
- #define PREGIVE_STATUSEFFECT(e,f) float save_##f = StatusEffects_gettime((f), (e))
+ #define PREGIVE_STATUSEFFECT(e,f) bool save_##f = StatusEffects_active(f, (e))
#define PREGIVE_RESOURCE(e,f) float save_##f = GetResource((e), (f))
#define POSTGIVE_WEAPON(e,b,snd_incr,snd_decr) GiveSound((e), !!(save_weapons & WepSet_FromWeapon(b)), !!(STAT(WEAPONS, e) & WepSet_FromWeapon(b)), 0, snd_incr, snd_decr)
#define POSTGIVE_BIT(e,f,b,snd_incr,snd_decr) GiveSound((e), save_##f & (b), (e).f & (b), 0, snd_incr, snd_decr)
- #define POSTGIVE_STATUSEFFECT(e,f,t,snd_incr,snd_decr) GiveSound((e), save_##f, StatusEffects_gettime((f), (e)), t, snd_incr, snd_decr)
+ #define POSTGIVE_STATUSEFFECT(e,f,snd_incr,snd_decr) GiveSound((e), save_##f, StatusEffects_active(f, (e)), 0, snd_incr, snd_decr)
#define POSTGIVE_RESOURCE(e,f,t,snd_incr,snd_decr) GiveSound((e), save_##f, GetResource((e), (f)), t, snd_incr, snd_decr)
#define POSTGIVE_RES_ROT(e,f,t,rotfield,rottime,regenfield,regentime,snd_incr,snd_decr) GiveRot((e),save_##f,GetResource((e),(f)),rotfield,rottime,regenfield,regentime);GiveSound((e),save_##f,GetResource((e),(f)),t,snd_incr,snd_decr)
#define POSTGIVE_VALUE(e,f,t,snd_incr,snd_decr) GiveSound((e), save_##f, (e).f, t, snd_incr, snd_decr)
{
WriteHeader(MSG_BROADCAST, TE_CSQC_PINGPLREPORT);
WriteByte(MSG_BROADCAST, this.cnt);
- WriteShort(MSG_BROADCAST, bound(1, CS(e).ping, 32767));
+ WriteShort(MSG_BROADCAST, bound(1, rint(CS(e).ping), 32767));
WriteByte(MSG_BROADCAST, min(ceil(CS(e).ping_packetloss * 255), 255));
WriteByte(MSG_BROADCAST, min(ceil(CS(e).ping_movementloss * 255), 255));
BADCVAR("g_ctf_flag_glowtrails");
BADCVAR("g_ctf_dynamiclights");
BADCVAR("g_ctf_flag_pickup_verbosename");
+ BADCVAR("g_ctf_flagcarrier_auto_helpme_damage");
BADPRESUFFIX("g_ctf_flag_", "_model");
BADPRESUFFIX("g_ctf_flag_", "_skin");
BADCVAR("g_domination_point_leadlimit");
BADCVAR("sv_minigames");
BADCVAR("sv_namechangetimer");
BADCVAR("sv_precacheplayermodels");
+ BADCVAR("sv_qcphysics");
BADCVAR("sv_radio");
BADCVAR("sv_stepheight");
BADCVAR("sv_timeout");
BADCVAR("g_ctf_leaderboard");
BADCVAR("g_domination_point_limit");
BADCVAR("g_domination_teams_override");
+ BADCVAR("g_freezetag_revive_spawnshield");
BADCVAR("g_freezetag_teams_override");
BADCVAR("g_friendlyfire");
BADCVAR("g_fullbrightitems");
BADCVAR("g_player_brightness");
BADCVAR("g_rocket_flying");
BADCVAR("g_rocket_flying_disabledelays");
- BADCVAR("g_spawnshieldtime");
+ BADPREFIX("g_spawnshield");
BADCVAR("g_start_delay");
BADCVAR("g_superspectate");
BADCVAR("g_tdm_teams_override");
// character set: ASCII 33-126 without the following characters: : ; ' " \ $
if(autocvar_sv_eventlog)
{
- string s = sprintf("%s.%s.%06d", itos(autocvar_sv_eventlog_files_counter), strftime(false, "%s"), floor(random() * 1000000));
+ string num = strftime_s(); // strftime(false, "%s") isn't reliable, see strftime_s description
+ string s = sprintf("%s.%s.%06d", itos(autocvar_sv_eventlog_files_counter), num, floor(random() * 1000000));
matchid = strzone(s);
GameLogEcho(strcat(":gamestart:", GetGametype(), "_", GetMapname(), ":", s));
if(autocvar_g_norecoil)
s = strcat(s, ":norecoil");
- // TODO to mutator system
- if(autocvar_g_powerups == 0)
- s = strcat(s, ":no_powerups");
- if(autocvar_g_powerups > 0)
- s = strcat(s, ":powerups");
-
GameLogEcho(s);
GameLogEcho(":gameinfo:end");
}
MapInfo_Enumerate();
MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 1);
- if(fexists(strcat("scripts/", mapname, ".arena")))
- cvar_settemp("sv_q3acompat_machineshotgunswap", "1");
-
- if(fexists(strcat("scripts/", mapname, ".defi")))
- cvar_settemp("sv_q3defragcompat", "1");
+ q3compat = BITSET(q3compat, Q3COMPAT_ARENA, fexists(strcat("scripts/", mapname, ".arena")));
+ q3compat = BITSET(q3compat, Q3COMPAT_DEFI, fexists(strcat("scripts/", mapname, ".defi")));
if(whichpack(strcat("maps/", mapname, ".cfg")) != "")
{
}
bool autocvar_sv_gameplayfix_multiplethinksperframe = true;
- void RunThink(entity this)
+ void RunThink(entity this, float dt)
{
// don't let things stay in the past.
// it is possible to start that way by a trigger with a local time.
- if(this.nextthink <= 0 || this.nextthink > time + frametime)
+ if(this.nextthink <= 0 || this.nextthink > time + dt)
return;
float oldtime = time; // do we need to save this?
// we don't want to loop in that case, so exit if the new nextthink is
// <= the time the qc was told, also exit if it is past the end of the
// frame
- if(this.nextthink <= time || this.nextthink > oldtime + frametime || !autocvar_sv_gameplayfix_multiplethinksperframe)
+ if(this.nextthink <= time || this.nextthink > oldtime + dt || !autocvar_sv_gameplayfix_multiplethinksperframe)
break;
}
if(it.move_movetype == MOVETYPE_PUSH || it.move_movetype == MOVETYPE_FAKEPUSH)
continue; // these movetypes have no regular think function
// handle thinking here
- if (getthink(it) && it.nextthink > 0 && it.nextthink <= time + frametime)
- RunThink(it);
+ if (getthink(it) && it.nextthink > 0 && it.nextthink <= time + PHYS_INPUT_TIMELENGTH)
+ RunThink(it, PHYS_INPUT_TIMELENGTH);
}
});
set sv_timeout_leadtime 4 "how long the players will be informed that a timeout was called before it starts, in seconds"
set sv_timeout_resumetime 3 "how long the remaining timeout-time will be after a player called the timein command"
- set g_allow_oldvortexbeam 1 "If enabled, clients are allowed to use old v2.3 Vortex beam"
-
set g_telefrags 1 "telefragging, i.e. killing someone who stands in the way of someone who is teleporting"
set g_telefrags_teamplay 1 "never telefrag team mates"
set g_telefrags_avoid 1 "when teleporters have a random destination, avoid teleporting to locations where a telefrag would happen"
sv_gameplayfix_gravityunaffectedbyticrate 1
sv_gameplayfix_nogravityonground 1
-set sv_q3acompat_machineshotgunswap 0 "shorthand for swapping machinegun and shotgun (for Q3A map compatibility in mapinfo files)"
-set sv_q3defragcompat 0 "toggle for some compatibility hacks (for Q3DF map compatibility)"
+set sv_q3compat_changehitbox 0 "use Q3 player hitbox dimensions and camera height on Q3 maps (maps with an entry in a .arena or .defi file)
set g_movement_highspeed 1 "multiplier scale for movement speed (applies to sv_maxspeed and sv_maxairspeed, also applies to air acceleration when g_movement_highspeed_q3_compat is set to 0)"
set g_movement_highspeed_q3_compat 0 "apply speed modifiers to air movement in a more Q3-compatible way (only apply speed buffs and g_movement_highspeed to max air speed, not to acceleration)"