set g_balance_powerup_invincible_takedamage 0.33 // only 1/3rd damage is taken
set g_balance_powerup_invincible_takeforce 0.33
set g_balance_powerup_invincible_time 30
+set g_balance_powerup_invisibility_alpha 0.15
+set g_balance_powerup_invisibility_time 30
+set g_balance_powerup_speed_attackrate 0.8
+set g_balance_powerup_speed_highspeed 1.5
+set g_balance_powerup_speed_time 30
+set g_balance_powerup_speed_weaponspeed 1.5
set g_balance_powerup_strength_damage 3
set g_balance_powerup_strength_force 3
set g_balance_powerup_strength_time 30
set g_balance_powerup_invincible_takedamage 0.2
set g_balance_powerup_invincible_takeforce 1
set g_balance_powerup_invincible_time 30
+set g_balance_powerup_invisibility_alpha 0.15
+set g_balance_powerup_invisibility_time 30
+set g_balance_powerup_speed_attackrate 0.8
+set g_balance_powerup_speed_highspeed 1.5
+set g_balance_powerup_speed_time 30
+set g_balance_powerup_speed_weaponspeed 1.5
set g_balance_powerup_strength_damage 3
set g_balance_powerup_strength_force 4
set g_balance_powerup_strength_time 30
set g_balance_powerup_invincible_takedamage 0.33 // only 1/3rd damage is taken
set g_balance_powerup_invincible_takeforce 0.33
set g_balance_powerup_invincible_time 30
+set g_balance_powerup_invisibility_alpha 0.15
+set g_balance_powerup_invisibility_time 30
+set g_balance_powerup_speed_attackrate 0.8
+set g_balance_powerup_speed_highspeed 1.5
+set g_balance_powerup_speed_time 30
+set g_balance_powerup_speed_weaponspeed 1.5
set g_balance_powerup_strength_damage 3
set g_balance_powerup_strength_force 3
set g_balance_powerup_strength_time 30
set g_balance_powerup_invincible_takedamage 0.25 // only 1/4th damage is taken
set g_balance_powerup_invincible_takeforce 1
set g_balance_powerup_invincible_time 30
+set g_balance_powerup_invisibility_alpha 0.15
+set g_balance_powerup_invisibility_time 30
+set g_balance_powerup_speed_attackrate 0.8
+set g_balance_powerup_speed_highspeed 1.5
+set g_balance_powerup_speed_time 30
+set g_balance_powerup_speed_weaponspeed 1.5
set g_balance_powerup_strength_damage 3
set g_balance_powerup_strength_force 3
set g_balance_powerup_strength_time 30
set g_balance_powerup_invincible_takedamage 0.33 // only 1/3rd damage is taken
set g_balance_powerup_invincible_takeforce 0.33
set g_balance_powerup_invincible_time 30
+set g_balance_powerup_invisibility_alpha 0.15
+set g_balance_powerup_invisibility_time 30
+set g_balance_powerup_speed_attackrate 0.8
+set g_balance_powerup_speed_highspeed 1.5
+set g_balance_powerup_speed_time 30
+set g_balance_powerup_speed_weaponspeed 1.5
set g_balance_powerup_strength_damage 3
set g_balance_powerup_strength_force 3
set g_balance_powerup_strength_time 30
set g_balance_powerup_invincible_takedamage 0.33 // only 1/3rd damage is taken
set g_balance_powerup_invincible_takeforce 0.33
set g_balance_powerup_invincible_time 30
+set g_balance_powerup_invisibility_alpha 0.15
+set g_balance_powerup_invisibility_time 30
+set g_balance_powerup_speed_attackrate 0.8
+set g_balance_powerup_speed_highspeed 1.5
+set g_balance_powerup_speed_time 30
+set g_balance_powerup_speed_weaponspeed 1.5
set g_balance_powerup_strength_damage 3
set g_balance_powerup_strength_force 3
set g_balance_powerup_strength_time 30
set g_balance_powerup_invincible_takedamage 0.33 // only 1/3rd damage is taken
set g_balance_powerup_invincible_takeforce 0.33
set g_balance_powerup_invincible_time 30
+set g_balance_powerup_invisibility_alpha 0.15
+set g_balance_powerup_invisibility_time 30
+set g_balance_powerup_speed_attackrate 0.8
+set g_balance_powerup_speed_highspeed 1.5
+set g_balance_powerup_speed_time 30
+set g_balance_powerup_speed_weaponspeed 1.5
set g_balance_powerup_strength_damage 3
set g_balance_powerup_strength_force 3
set g_balance_powerup_strength_time 30
set g_instagib_ammo_convert_rockets 0 "convert rocket ammo packs to insta cell ammo packs"
set g_instagib_ammo_convert_shells 0 "convert shell ammo packs to insta cell ammo packs"
set g_instagib_invisibility_time 30 "Time of invisibility powerup in seconds."
-set g_instagib_invis_alpha 0.15
set g_instagib_speed_time 30 "Time of speed powerup in seconds."
-set g_instagib_speed_highspeed 1.5 "speed-multiplier that applies while you carry the invincibility powerup"
set g_instagib_damagedbycontents 1 "allow damage from lava pits in instagib"
set g_instagib_blaster_keepdamage 0 "allow secondary fire to hurt players"
set g_instagib_blaster_keepforce 0 "allow secondary fire to push players"
set g_buffs_disability_speed 0.7 "player speed multiplier while disabled"
set g_buffs_disability_rate 1.5 "player weapon rate multiplier while disabled"
set g_buffs_disability_weaponspeed 0.7 "weapon speed multiplier while disabled"
-set g_buffs_speed 1 "speed buff: increased movement/attack/health regeneration speed, carrier takes slightly more damage"
-set g_buffs_speed_time 60 "speed buff carry time"
-set g_buffs_speed_speed 1.7 "player speed multiplier while holding speed buff"
-set g_buffs_speed_rate 0.8 "weapon attack rate multiplier, smaller value means faster rate while holding the speed buff"
-set g_buffs_speed_weaponspeed 1.6 "projectile speed multiplier, higher value means faster projectiles while holding the speed buff"
-set g_buffs_speed_damage_take 1.2 "damage taken multiplier, higher value means more damage taken while holding speed buff"
-set g_buffs_speed_regen 1.2 "regeneration speed multiplier, higher value means faster health regeneration while holding speed buff"
set g_buffs_vampire 1 "vampire buff: attacks to players and monsters heal the carrier"
set g_buffs_vampire_time 60 "vampire buff carry time"
set g_buffs_vampire_damage_steal 0.4 "damage stolen multiplier while holding vampire buff"
set g_buffs_jump 0 "jump buff: greatly increased jump height"
set g_buffs_jump_time 60 "jump buff carry time"
set g_buffs_jump_height 600 "jump height while holding jump buff"
-set g_buffs_invisible 1 "invisible buff: carrier becomes invisible"
-set g_buffs_invisible_time 60 "invisible buff carry time"
-set g_buffs_invisible_alpha 0.15 "player invisibility multiplier while holding invisible buff"
set g_buffs_inferno 1 "inferno buff: targets damaged by player carrying inferno buff will also receive burning damage"
set g_buffs_inferno_time 60 "inferno buff carry time"
set g_buffs_inferno_damagemultiplier 0.3 "multiplier of damage dealt during burn"
#include <common/mapobjects/trigger/viewloc.qh>
#include <common/minigames/cl_minigames.qh>
#include <common/minigames/cl_minigames_hud.qh>
+#include <common/mutators/mutator/powerups/_mod.qh>
#include <common/mutators/mutator/status_effects/_mod.qh>
#include <common/mutators/mutator/waypoints/all.qh>
#include <common/net_linked.qh>
}
// edge detection postprocess handling done second (used by hud_powerup)
- float sharpen_intensity = 0, strength_finished = StatusEffects_gettime(STATUSEFFECT_Strength, g_statuseffects), invincible_finished = StatusEffects_gettime(STATUSEFFECT_Shield, g_statuseffects);
- if (strength_finished - time > 0) { sharpen_intensity += (strength_finished - time); }
- if (invincible_finished - time > 0) { sharpen_intensity += (invincible_finished - time); }
+ float sharpen_intensity = 0;
+ FOREACH(StatusEffect, it.instanceOfPowerups,
+ {
+ float powerup_finished = StatusEffects_gettime(it, g_statuseffects) - time;
+ if(powerup_finished > 0)
+ sharpen_intensity += powerup_finished;
+ });
sharpen_intensity = bound(0, ((STAT(HEALTH) > 0) ? sharpen_intensity : 0), 5); // Check to see if player is alive (if not, set 0) - also bound to fade out starting at 5 seconds.
entity item = M_ARGV(0, entity);
if (autocvar_g_powerups <= 0)
- if (item.flags & FL_POWERUP)
+ if (item.itemdef.instanceOfPowerup)
return true;
if (autocvar_g_pickup_items <= 0)
#include <common/effects/all.qh>
#include <common/mapobjects/teleporters.qh>
#include <common/mapobjects/triggers.qh>
+#include <common/mutators/mutator/powerups/_mod.qh>
#include <common/vehicles/all.qh>
#include <server/command/vote.qh>
#include <server/client.qh>
{
makevectors((player.v_angle.y * '0 1 0') + (bound(autocvar_g_ctf_throw_angle_min, player.v_angle.x, autocvar_g_ctf_throw_angle_max) * '1 0 0'));
- flag_velocity = (('0 0 1' * autocvar_g_ctf_throw_velocity_up) + ((v_forward * autocvar_g_ctf_throw_velocity_forward) * ((player.items & ITEM_Strength.m_itemid) ? autocvar_g_ctf_throw_strengthmultiplier : 1)));
+ flag_velocity = (('0 0 1' * autocvar_g_ctf_throw_velocity_up) + ((v_forward * autocvar_g_ctf_throw_velocity_forward) * ((StatusEffects_active(STATUSEFFECT_Strength, player)) ? autocvar_g_ctf_throw_strengthmultiplier : 1)));
flag.velocity = W_CalculateProjectileVelocity(player, player.velocity, flag_velocity, false);
ctf_Handle_Drop(flag, player, droptype);
navigation_dynamicgoal_set(flag, player);
#include <common/monsters/sv_spawn.qh>
#include <common/monsters/sv_spawner.qh>
#include <common/monsters/sv_monsters.qh>
+#include <common/mutators/mutator/status_effects/_mod.qh>
#include <server/bot/api.qh>
#include <server/world.qh>
if(!monster)
return;
- monster.spawnshieldtime = time;
+ StatusEffects_remove(STATUSEFFECT_SpawnShield, monster, STATUSEFFECT_REMOVE_NORMAL);
if(spawn_point)
{
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
#include <common/items/item/health.qc>
#include <common/items/item/jetpack.qc>
#include <common/items/item/pickup.qc>
-#include <common/items/item/powerup.qc>
#include <common/items/item/health.qh>
#include <common/items/item/jetpack.qh>
#include <common/items/item/pickup.qh>
-#include <common/items/item/powerup.qh>
#endif
#include "ammo.qh"
-#include "powerup.qh"
+#include <common/mutators/mutator/powerups/_mod.qh>
#ifndef SVQC
.int m_itemid;
CLASS(Jetpack, Powerup)
ENDCLASS(Jetpack)
-REGISTER_ITEM(Jetpack, Powerup) {
+REGISTER_ITEM(Jetpack, Jetpack) {
this.m_canonical_spawnfunc = "item_jetpack";
#ifdef GAMEQC
this.spawnflags = ITEM_FLAG_NORMAL;
+++ /dev/null
-#include "powerup.qh"
+++ /dev/null
-#pragma once
-
-#ifdef SVQC
- // For FL_POWERUP
- #include <common/constants.qh>
-#endif
-
-#include "pickup.qh"
-CLASS(Powerup, Pickup)
-#ifdef SVQC
- ATTRIB(Powerup, m_mins, vector, '-16 -16 0');
- ATTRIB(Powerup, m_maxs, vector, '16 16 80');
- ATTRIB(Powerup, m_botvalue, int, 11000);
- ATTRIB(Powerup, m_itemflags, int, FL_POWERUP);
- ATTRIB(Powerup, m_respawntime, float(), GET(g_pickup_respawntime_powerup));
- ATTRIB(Powerup, m_respawntimejitter, float(), GET(g_pickup_respawntimejitter_powerup));
-#endif
-ENDCLASS(Powerup)
-
-#ifdef GAMEQC
-MODEL(Strength_ITEM, Item_Model("g_strength.md3"));
-SOUND(Strength, Item_Sound("powerup"));
-#endif
-
-#ifdef SVQC
-float autocvar_g_balance_powerup_strength_damage;
-float autocvar_g_balance_powerup_strength_force;
-float autocvar_g_balance_powerup_strength_selfdamage;
-float autocvar_g_balance_powerup_strength_selfforce;
-float autocvar_g_balance_powerup_strength_time;
-void powerup_strength_init(Pickup this, entity item)
-{
- if(!item.strength_finished)
- item.strength_finished = autocvar_g_balance_powerup_strength_time;
-}
-#endif
-REGISTER_ITEM(Strength, Powerup) {
- this.m_canonical_spawnfunc = "item_strength";
-#ifdef GAMEQC
- this.spawnflags = ITEM_FLAG_NORMAL;
- this.m_model = MDL_Strength_ITEM;
- this.m_sound = SND_Strength;
- this.m_glow = true;
- this.m_respawnsound = SND_STRENGTH_RESPAWN;
-#endif
- this.netname = "strength";
- this.m_name = _("Strength");
- this.m_icon = "strength";
- this.m_color = '0 0 1';
- this.m_waypoint = _("Strength");
- this.m_waypointblink = 2;
-#ifdef GAMEQC
- this.m_itemid = IT_STRENGTH;
-#endif
-#ifdef SVQC
- this.m_iteminit = powerup_strength_init;
-#endif
-}
-
-SPAWNFUNC_ITEM(item_strength, ITEM_Strength)
-
-#ifdef GAMEQC
-MODEL(Shield_ITEM, Item_Model("g_invincible.md3"));
-SOUND(Shield, Item_Sound("powerup_shield"));
-#endif
-
-#ifdef SVQC
-float autocvar_g_balance_powerup_invincible_takedamage;
-float autocvar_g_balance_powerup_invincible_takeforce = 0.33;
-float autocvar_g_balance_powerup_invincible_time;
-void powerup_shield_init(Pickup this, entity item)
-{
- if(!item.invincible_finished)
- item.invincible_finished = autocvar_g_balance_powerup_invincible_time;
-}
-#endif
-REGISTER_ITEM(Shield, Powerup) {
- this.m_canonical_spawnfunc = "item_shield";
-#ifdef GAMEQC
- this.spawnflags = ITEM_FLAG_NORMAL;
- this.m_model = MDL_Shield_ITEM;
- this.m_sound = SND_Shield;
- this.m_glow = true;
- this.m_respawnsound = SND_SHIELD_RESPAWN;
-#endif
- this.netname = "invincible";
- this.m_name = _("Shield");
- this.m_icon = "shield";
- this.m_color = '1 0 1';
- this.m_waypoint = _("Shield");
- this.m_waypointblink = 2;
-#ifdef GAMEQC
- this.m_itemid = IT_INVINCIBLE;
-#endif
-#ifdef SVQC
- this.m_iteminit = powerup_shield_init;
-#endif
-}
-
-SPAWNFUNC_ITEM(item_shield, ITEM_Shield)
-SPAWNFUNC_ITEM(item_invincible, ITEM_Shield)
.entity mage_spike;
.float mage_shield_delay;
-.float mage_shield_time;
bool M_Mage_Defend_Heal_Check(entity this, entity targ)
{
return false;
if(!IS_PLAYER(targ))
return (IS_MONSTER(targ) && GetResource(targ, RES_HEALTH) < targ.max_health);
- if(targ.items & ITEM_Shield.m_itemid)
+ if(StatusEffects_active(STATUSEFFECT_Shield, targ))
return false;
switch(this.skin)
this.attack_finished_single[0] = time + 0.2;
}
-void M_Mage_Defend_Shield_Remove(entity this)
-{
- this.effects &= ~(EF_ADDITIVE | EF_BLUE);
- SetResourceExplicit(this, RES_ARMOR, autocvar_g_monsters_armor_blockpercent);
-}
-
void M_Mage_Defend_Shield(entity this)
{
- this.effects |= (EF_ADDITIVE | EF_BLUE);
+ StatusEffects_apply(STATUSEFFECT_Shield, this, time + autocvar_g_monster_mage_shield_time, 0);
this.mage_shield_delay = time + (autocvar_g_monster_mage_shield_delay);
SetResourceExplicit(this, RES_ARMOR, autocvar_g_monster_mage_shield_blockpercent);
- this.mage_shield_time = time + (autocvar_g_monster_mage_shield_time);
setanim(this, this.anim_shoot, true, true, true);
this.attack_finished_single[0] = time + 1;
this.anim_finished = time + 1;
if(random() < 0.5)
M_Mage_Defend_Heal(actor);
- if(time >= actor.mage_shield_time && GetResource(actor, RES_ARMOR))
- M_Mage_Defend_Shield_Remove(actor);
-
- if(actor.enemy)
- if(GetResource(actor, RES_HEALTH) < actor.max_health)
- if(time >= actor.mage_shield_delay)
- if(random() < 0.5)
+ if(actor.enemy && time >= actor.mage_shield_delay && random() < 0.5)
+ if(GetResource(actor, RES_HEALTH) < actor.max_health && !StatusEffects_active(STATUSEFFECT_Shield, actor))
M_Mage_Defend_Shield(actor);
return true;
setanim(actor, actor.anim_shoot, false, true, true);
actor.spawn_time = actor.animstate_endtime;
- actor.spawnshieldtime = actor.spawn_time;
+ StatusEffects_apply(STATUSEFFECT_SpawnShield, actor, actor.spawn_time, 0);
actor.monster_attackfunc = M_Shambler_Attack;
return true;
#ifdef SVQC
-.float spider_slowness; // effect time of slowness inflicted by spiders
-
.float spider_web_delay;
float autocvar_g_monster_spider_attack_web_damagetime;
{
entity player = M_ARGV(0, entity);
- if(time < player.spider_slowness)
+ if(StatusEffects_active(STATUSEFFECT_Webbed, player))
STAT(MOVEVARS_HIGHSPEED, player) *= 0.5;
}
{
entity mon = M_ARGV(0, entity);
- if(time < mon.spider_slowness)
+ if(StatusEffects_active(STATUSEFFECT_Webbed, mon))
{
M_ARGV(1, float) *= 0.5; // run speed
M_ARGV(2, float) *= 0.5; // walk speed
}
}
-MUTATOR_HOOKFUNCTION(spiderweb, PlayerSpawn)
-{
- entity player = M_ARGV(0, entity);
-
- player.spider_slowness = 0;
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(spiderweb, MonsterSpawn)
-{
- entity mon = M_ARGV(0, entity);
-
- mon.spider_slowness = 0;
-}
-
SOUND(SpiderAttack_FIRE, W_Sound("electro_fire"));
METHOD(SpiderAttack, wr_think, void(SpiderAttack thiswep, entity actor, .entity weaponentity, int fire))
{
FOREACH_ENTITY_RADIUS(this.origin, 25, it != this && it.takedamage && !IS_DEAD(it) && GetResource(it, RES_HEALTH) > 0 && it.monsterdef != MON_SPIDER,
{
- it.spider_slowness = time + (autocvar_g_monster_spider_attack_web_damagetime);
+ StatusEffects_apply(STATUSEFFECT_Webbed, it, time + autocvar_g_monster_spider_attack_web_damagetime, 0);
});
delete(this);
/* wepname */ ATTRIB(SpiderAttack, m_name, string, _("Spider attack"));
ENDCLASS(SpiderAttack)
REGISTER_WEAPON(SPIDER_ATTACK, NEW(SpiderAttack));
+
+#include <common/mutators/mutator/status_effects/all.qh>
+
+CLASS(Webbed, StatusEffects)
+ ATTRIB(Webbed, netname, string, "webbed");
+ ATTRIB(Webbed, m_name, string, _("Webbed"));
+ ATTRIB(Webbed, m_icon, string, "buff_disability");
+ ATTRIB(Webbed, m_color, vector, '0.94 0.3 1');
+ ATTRIB(Webbed, m_hidden, bool, true);
+ ATTRIB(Webbed, m_lifetime, float, 10);
+ENDCLASS(Webbed)
+REGISTER_STATUSEFFECT(Webbed, NEW(Webbed));
actor.monster_loot = ITEM_HealthMedium;
actor.monster_attackfunc = M_Zombie_Attack;
- actor.spawnshieldtime = actor.spawn_time;
+ StatusEffects_apply(STATUSEFFECT_SpawnShield, actor, actor.spawn_time, 0);
actor.respawntime = 0.2;
actor.damageforcescale = 0.0001; // no push while spawning
#include <common/mapobjects/triggers.qh>
#include <common/monsters/all.qh>
#include <common/mutators/mutator/nades/nades.qh>
+#include <common/mutators/mutator/status_effects/_mod.qh>
#include <common/physics/movelib.qh>
#include <common/stats.qh>
#include <common/teams.qh>
|| (time < game_starttime) // monsters do nothing before match has started
|| (targ.takedamage == DAMAGE_NO)
|| (game_stopped)
- || (targ.items & IT_INVISIBILITY)
|| (IS_SPEC(targ) || IS_OBSERVER(targ)) // don't attack spectators
|| (!IS_VEHICLE(targ) && (IS_DEAD(targ) || IS_DEAD(this) || GetResource(targ, RES_HEALTH) <= 0 || GetResource(this, RES_HEALTH) <= 0))
|| (this.monster_follow == targ || targ.monster_follow == this)
//if(time < this.pain_finished && deathtype != DEATH_KILL.m_id)
//return;
- if(time < this.spawnshieldtime && deathtype != DEATH_KILL.m_id)
+ if(StatusEffects_active(STATUSEFFECT_SpawnShield, this) && deathtype != DEATH_KILL.m_id)
return;
if(deathtype == DEATH_FALL.m_id && this.draggedby != NULL)
bool reverse = false;
if(trace_fraction != 1.0)
reverse = true;
- if(trace_ent && IS_PLAYER(trace_ent) && !(trace_ent.items & ITEM_Strength.m_itemid))
+ if(trace_ent && IS_PLAYER(trace_ent))
reverse = false;
if(trace_ent && IS_MONSTER(trace_ent))
reverse = true;
else
setmodel(this, mon.m_model);
+ if(this.statuseffects && this.statuseffects.owner == this)
+ {
+ StatusEffects_clearall(this.statuseffects);
+ StatusEffects_update(this);
+ }
+ else
+ this.statuseffects = NULL;
+
this.flags = FL_MONSTER;
this.classname = "monster";
this.takedamage = DAMAGE_AIM;
this.use = Monster_Use;
this.solid = SOLID_BBOX;
set_movetype(this, MOVETYPE_WALK);
- this.spawnshieldtime = time + autocvar_g_monsters_spawnshieldtime;
+ StatusEffects_apply(STATUSEFFECT_SpawnShield, this, time + autocvar_g_monsters_spawnshieldtime, 0);
this.enemy = NULL;
this.velocity = '0 0 0';
this.moveto = this.origin;
#include <common/mutators/mutator/overkill/_mod.inc>
#include <common/mutators/mutator/physical_items/_mod.inc>
#include <common/mutators/mutator/pinata/_mod.inc>
+#include <common/mutators/mutator/powerups/_mod.inc>
#include <common/mutators/mutator/random_gravity/_mod.inc>
#include <common/mutators/mutator/random_items/_mod.inc>
#include <common/mutators/mutator/rocketflying/_mod.inc>
#include <common/mutators/mutator/overkill/_mod.qh>
#include <common/mutators/mutator/physical_items/_mod.qh>
#include <common/mutators/mutator/pinata/_mod.qh>
+#include <common/mutators/mutator/powerups/_mod.qh>
#include <common/mutators/mutator/random_gravity/_mod.qh>
#include <common/mutators/mutator/random_items/_mod.qh>
#include <common/mutators/mutator/rocketflying/_mod.qh>
switch(buffname)
{
case "ammoregen": return "ammo";
- case "haste": case "scout": return "speed";
case "guard": return "resistance";
case "revival": case "regen": return "medic";
- case "invis": return "invisible";
case "jumper": return "jump";
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)
-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)
-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_Q3TA_COMPAT(haste, BUFF_SPEED)
-BUFF_SPAWNFUNC_Q3TA_COMPAT(scout, 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)
-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)
-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)
-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");
+ ATTRIB(Disabled, m_name, string, _("Disabled"));
+ ATTRIB(Disabled, m_icon, string, "buff_disability");
+ 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)
-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)
-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_Q3TA_COMPAT(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)
-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)
-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)
#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));
});
}
#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) { return Team_ColorRGB(buff.team); }
- 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)
{
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);
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;
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);
+ entity store = IS_PLAYER(actor) ? PS(actor) : actor;
+ store.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))
{
return;
float health_take = bound(0, M_ARGV(4, float), GetResource(frag_target, RES_HEALTH));
- if(time >= frag_target.spawnshieldtime &&
+ if(!StatusEffects_active(STATUSEFFECT_SpawnShield, frag_target) &&
frag_target != frag_attacker &&
IS_PLAYER(frag_attacker) &&
!IS_DEAD(frag_target) && !STAT(FROZEN, frag_target))
}
}
-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;
{
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;
// generated file; do not modify
#include <common/mutators/mutator/instagib/items.qc>
-#ifdef SVQC
- #include <common/mutators/mutator/instagib/sv_items.qc>
-#endif
#ifdef SVQC
#include <common/mutators/mutator/instagib/sv_instagib.qc>
#endif
// generated file; do not modify
#include <common/mutators/mutator/instagib/items.qh>
-#ifdef SVQC
- #include <common/mutators/mutator/instagib/sv_items.qh>
-#endif
#ifdef SVQC
#include <common/mutators/mutator/instagib/sv_instagib.qh>
#endif
#include <common/items/_mod.qh>
#include <common/items/item/ammo.qh>
-#include <common/items/item/powerup.qh>
+#include <common/mutators/mutator/powerups/_mod.qh>
float instagib_respawntime_ammo = 45;
float instagib_respawntimejitter_ammo = 0;
}
SPAWNFUNC_ITEM(item_extralife, ITEM_ExtraLife)
-
-#ifdef GAMEQC
-MODEL(Invisibility_ITEM, Item_Model("g_strength.md3"));
-SOUND(Invisibility, Item_Sound("powerup"));
-#endif
-
-#ifdef SVQC
-/// \brief Initializes the invisibility powerup.
-/// \param[in,out] item Item to initialize.
-/// \return No return.
-void powerup_invisibility_init(Pickup this, entity item);
-#endif
-
-REGISTER_ITEM(Invisibility, Powerup) {
- this.m_canonical_spawnfunc = "item_invisibility";
-#ifdef GAMEQC
- this.spawnflags = ITEM_FLAG_MUTATORBLOCKED;
- this.m_model = MDL_Invisibility_ITEM;
- this.m_sound = SND_Invisibility;
- this.m_glow = true;
- this.m_respawnsound = SND_STRENGTH_RESPAWN;
-#endif
- this.netname = "invisibility";
- this.m_name = _("Invisibility");
- this.m_icon = "strength";
- this.m_color = '0 0 1';
- this.m_waypoint = _("Invisibility");
- this.m_waypointblink = 2;
-#ifdef GAMEQC
- this.m_itemid = IT_STRENGTH;
-#endif
-#ifdef SVQC
- this.m_iteminit = powerup_invisibility_init;
-#endif
-}
-
-SPAWNFUNC_ITEM(item_invisibility, ITEM_Invisibility)
-
-#ifdef GAMEQC
-MODEL(Speed_ITEM, Item_Model("g_invincible.md3"));
-SOUND(Speed, Item_Sound("powerup_shield"));
-#endif
-
-#ifdef SVQC
-/// \brief Initializes the speed powerup.
-/// \param[in,out] item Item to initialize.
-/// \return No return.
-void powerup_speed_init(Pickup this, entity item);
-#endif
-
-REGISTER_ITEM(Speed, Powerup) {
- this.m_canonical_spawnfunc = "item_speed";
-#ifdef GAMEQC
- this.spawnflags = ITEM_FLAG_MUTATORBLOCKED;
- this.m_model = MDL_Speed_ITEM;
- this.m_sound = SND_Speed;
- this.m_glow = true;
- this.m_respawnsound = SND_SHIELD_RESPAWN;
-#endif
- this.netname = "speed";
- this.m_name = _("Speed");
- this.m_icon = "shield";
- this.m_color = '1 0 1';
- this.m_waypoint = _("Speed");
- this.m_waypointblink = 2;
-#ifdef GAMEQC
- this.m_itemid = IT_INVINCIBLE;
-#endif
-#ifdef SVQC
- this.m_iteminit = powerup_speed_init;
-#endif
-}
-
-SPAWNFUNC_ITEM(item_speed, ITEM_Speed)
#include <server/client.qh>
#include <common/items/_mod.qh>
+#include <common/mutators/mutator/powerups/_mod.qh>
#include <common/mutators/mutator/status_effects/_mod.qh>
#include "../random_items/sv_random_items.qh"
bool autocvar_g_instagib_ammo_convert_rockets;
bool autocvar_g_instagib_ammo_convert_shells;
bool autocvar_g_instagib_ammo_convert_bullets;
-float autocvar_g_instagib_speed_highspeed;
void instagib_invisibility(entity this)
{
- this.strength_finished = autocvar_g_instagib_invisibility_time;
+ this.invisibility_finished = autocvar_g_instagib_invisibility_time;
StartItem(this, ITEM_Invisibility);
}
void instagib_speed(entity this)
{
- this.invincible_finished = autocvar_g_instagib_speed_time;
+ this.speed_finished = autocvar_g_instagib_speed_time;
StartItem(this, ITEM_Speed);
}
mon.skin = 1;
}
-MUTATOR_HOOKFUNCTION(mutator_instagib, BotShouldAttack)
-{
- entity targ = M_ARGV(1, entity);
-
- if (targ.items & ITEM_Invisibility.m_itemid)
- return true;
-}
-
MUTATOR_HOOKFUNCTION(mutator_instagib, MakePlayerObserver)
{
entity player = M_ARGV(0, entity);
return true;
}
-MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerPowerups)
-{
- entity player = M_ARGV(0, entity);
-
- player.effects |= EF_FULLBRIGHT;
-
- if (player.items & ITEM_Invisibility.m_itemid)
- {
- play_countdown(player, StatusEffects_gettime(STATUSEFFECT_Strength, player), SND_POWEROFF);
- if (time > StatusEffects_gettime(STATUSEFFECT_Strength, player))
- {
- if(!player.vehicle) // already reset upon exit
- {
- player.alpha = default_player_alpha;
- player.exteriorweaponentity.alpha = default_weapon_alpha;
- }
- player.items &= ~ITEM_Invisibility.m_itemid;
- Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_POWERDOWN_INVISIBILITY);
- }
- }
- else
- {
- if (time < StatusEffects_gettime(STATUSEFFECT_Strength, player))
- {
- if(!player.vehicle) // incase the player is given powerups while inside a vehicle
- {
- player.alpha = autocvar_g_instagib_invis_alpha;
- player.exteriorweaponentity.alpha = autocvar_g_instagib_invis_alpha;
- }
- player.items |= ITEM_Invisibility.m_itemid;
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERUP_INVISIBILITY, player.netname);
- Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_POWERUP_INVISIBILITY);
- }
- }
-
- if (player.items & ITEM_Speed.m_itemid)
- {
- play_countdown(player, StatusEffects_gettime(STATUSEFFECT_Shield, player), SND_POWEROFF);
- if (time > StatusEffects_gettime(STATUSEFFECT_Shield, player))
- {
- player.items &= ~ITEM_Speed.m_itemid;
- Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_POWERDOWN_SPEED);
- }
- }
- else
- {
- if (time < StatusEffects_gettime(STATUSEFFECT_Shield, player))
- {
- player.items |= ITEM_Speed.m_itemid;
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERUP_SPEED, player.netname);
- Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_POWERUP_SPEED);
- }
- }
-}
-
-MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerPhysics_UpdateStats)
-{
- entity player = M_ARGV(0, entity);
- // these automatically reset, no need to worry
-
- if(player.items & ITEM_Speed.m_itemid)
- STAT(MOVEVARS_HIGHSPEED, player) *= autocvar_g_instagib_speed_highspeed;
-}
-
MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerDamage_SplitHealthArmor)
{
M_ARGV(4, float) = M_ARGV(7, float); // take = damage
return true;
}
- if(item.flags & FL_POWERUP)
+ if(item.itemdef.instanceOfPowerup)
return false;
float cells = GetResource(item, RES_CELLS);
return true;
}
-MUTATOR_HOOKFUNCTION(mutator_instagib, 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) && (wp.owner.items & ITEM_Invisibility.m_itemid) && (e == player))
- if(DIFF_TEAM(wp.owner, e))
- return true;
-}
-
MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerDies)
{
float frag_deathtype = M_ARGV(3, float);
if (!autocvar_g_powerups) { return; }
entity ent = M_ARGV(0, entity);
// Can't use .itemdef here
- if (!(ent.classname == "item_strength" || ent.classname == "item_shield" || ent.classname == "item_health_mega"))
+ if (!(ent.classname == "item_strength" || ent.classname == "item_shield" || ent.classname == "item_invincible" || ent.classname == "item_health_mega"))
return;
entity e = spawn();
#include "items.qh"
#include <common/gamemodes/_mod.qh>
+#include <common/mutators/mutator/powerups/_mod.qh>
// TODO: make this its own mutator (somehow)!
float autocvar_g_rm;
float autocvar_g_rm_laser_force;
bool autocvar_g_instagib;
-float autocvar_g_instagib_invis_alpha;
int autocvar_g_instagib_extralives;
+/// \brief Time of invisibility powerup in seconds.
+float autocvar_g_instagib_invisibility_time;
+/// \brief Time of speed powerup in seconds.
+float autocvar_g_instagib_speed_time;
+
void instagib_invisibility(entity this);
void instagib_extralife(entity this);
void instagib_speed(entity this);
+++ /dev/null
-#include "sv_items.qh"
-
-#include "items.qh"
-
-/// \brief Time of ivisibility powerup in seconds.
-float autocvar_g_instagib_invisibility_time;
-/// \brief Time of speed powerup in seconds.
-float autocvar_g_instagib_speed_time;
-
-void powerup_invisibility_init(Pickup this, entity item)
-{
- if(!item.strength_finished)
- {
- item.strength_finished = autocvar_g_instagib_invisibility_time;
- }
-}
-
-
-void powerup_speed_init(Pickup this, entity item)
-{
- if(!item.invincible_finished)
- {
- item.invincible_finished = autocvar_g_instagib_speed_time;
- }
-}
+++ /dev/null
-#pragma once
int ntype;
string pntype = this.pokenade_type;
- if((this.items & ITEM_Strength.m_itemid) && autocvar_g_nades_bonus_onstrength)
+ if(StatusEffects_active(STATUSEFFECT_Strength, this) && autocvar_g_nades_bonus_onstrength)
ntype = STAT(NADE_BONUS_TYPE, this);
else if (STAT(NADE_BONUS, this) >= 1)
{
return;
}
- if((!thiswep.wr_checkammo1(thiswep, actor, weaponentity) && !(actor.items & IT_UNLIMITED_AMMO)) || (!(actor.items & IT_SUPERWEAPON) && !(actor.items & IT_UNLIMITED_SUPERWEAPONS)))
+ if((!thiswep.wr_checkammo1(thiswep, actor, weaponentity) && !(actor.items & IT_UNLIMITED_AMMO)) || (!StatusEffects_active(STATUSEFFECT_Superweapons, actor) && !(actor.items & IT_UNLIMITED_SUPERWEAPONS)))
{
W_SwitchWeapon_Force(actor, w_getbestweapon(actor, weaponentity), weaponentity);
w_ready(thiswep, actor, weaponentity, fire);
--- /dev/null
+// generated file; do not modify
+#include <common/mutators/mutator/powerups/powerups.qc>
+#ifdef CSQC
+ #include <common/mutators/mutator/powerups/cl_powerups.qc>
+#endif
+#ifdef SVQC
+ #include <common/mutators/mutator/powerups/sv_powerups.qc>
+#endif
+
+#include <common/mutators/mutator/powerups/powerup/_mod.inc>
--- /dev/null
+// generated file; do not modify
+#include <common/mutators/mutator/powerups/powerups.qh>
+#ifdef CSQC
+ #include <common/mutators/mutator/powerups/cl_powerups.qh>
+#endif
+#ifdef SVQC
+ #include <common/mutators/mutator/powerups/sv_powerups.qh>
+#endif
+
+#include <common/mutators/mutator/powerups/powerup/_mod.qh>
--- /dev/null
+#include "cl_powerups.qh"
--- /dev/null
+#pragma once
+
+#include "powerups.qh"
+
--- /dev/null
+// generated file; do not modify
+#include <common/mutators/mutator/powerups/powerup/invisibility.qc>
+#include <common/mutators/mutator/powerups/powerup/shield.qc>
+#include <common/mutators/mutator/powerups/powerup/speed.qc>
+#include <common/mutators/mutator/powerups/powerup/strength.qc>
--- /dev/null
+// generated file; do not modify
+#include <common/mutators/mutator/powerups/powerup/invisibility.qh>
+#include <common/mutators/mutator/powerups/powerup/shield.qh>
+#include <common/mutators/mutator/powerups/powerup/speed.qh>
+#include <common/mutators/mutator/powerups/powerup/strength.qh>
--- /dev/null
+#include "invisibility.qh"
+
+#ifdef SVQC
+METHOD(Invisibility, 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(removal_type == STATUSEFFECT_REMOVE_TIMEOUT && wasactive && IS_PLAYER(actor))
+ {
+ //Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERDOWN_INVISIBILITY, actor.netname);
+ Send_Notification(NOTIF_ONE, actor, MSG_CENTER, CENTER_POWERDOWN_INVISIBILITY);
+ }
+ if(wasactive)
+ stopsound(actor, CH_TRIGGER_SINGLE); // get rid of the pickup sound
+ if(!actor.vehicle)
+ {
+ actor.alpha = default_player_alpha;
+ if(actor.exteriorweaponentity)
+ actor.exteriorweaponentity.alpha = default_weapon_alpha;
+ }
+ SUPER(Invisibility).m_remove(this, actor, removal_type);
+}
+METHOD(Invisibility, 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 && IS_PLAYER(actor))
+ {
+ if(!g_cts)
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERUP_INVISIBILITY, actor.netname);
+ Send_Notification(NOTIF_ONE, actor, MSG_CENTER, CENTER_POWERUP_INVISIBILITY);
+ }
+ SUPER(Invisibility).m_apply(this, actor, eff_time, eff_flags);
+}
+METHOD(Invisibility, m_tick, void(StatusEffects this, entity actor))
+{
+ play_countdown(actor, StatusEffects_gettime(this, actor), SND_POWEROFF);
+ if(!actor.vehicle)
+ {
+ actor.alpha = autocvar_g_balance_powerup_invisibility_alpha;
+ if(actor.exteriorweaponentity)
+ actor.exteriorweaponentity.alpha = autocvar_g_balance_powerup_invisibility_alpha;
+ }
+ SUPER(Invisibility).m_tick(this, actor);
+}
+#endif
--- /dev/null
+#pragma once
+
+#include <common/items/all.qh>
+#include <common/mutators/mutator/powerups/powerups.qh>
+#ifdef SVQC
+ // For FL_POWERUP
+ #include <common/constants.qh>
+ #include <server/items/items.qh>
+#endif
+
+#ifdef GAMEQC
+MODEL(Invisibility_ITEM, Item_Model("g_strength.md3"));
+SOUND(Invisibility, Item_Sound("powerup"));
+#endif
+
+#ifdef SVQC
+.float invisibility_finished;
+
+float autocvar_g_balance_powerup_invisibility_alpha = 0.15;
+float autocvar_g_balance_powerup_invisibility_time = 30;
+void powerup_invisibility_init(Pickup this, entity item)
+{
+ if(!item.invisibility_finished)
+ item.invisibility_finished = autocvar_g_balance_powerup_invisibility_time;
+}
+#endif
+REGISTER_ITEM(Invisibility, Powerup) {
+ this.m_canonical_spawnfunc = "item_invisibility";
+#ifdef GAMEQC
+ this.spawnflags = ITEM_FLAG_MUTATORBLOCKED; // TODO: ITEM_FLAG_NORMAL (once it has a model!)
+ this.m_model = MDL_Invisibility_ITEM;
+ this.m_sound = SND_Invisibility;
+ this.m_glow = true;
+ this.m_respawnsound = SND_STRENGTH_RESPAWN;
+#endif
+ this.netname = "invisibility";
+ this.m_name = _("Invisibility");
+ this.m_icon = "buff_invisible";
+ this.m_color = '0.5 0.5 1';
+ this.m_waypoint = _("Invisibility");
+ this.m_waypointblink = 2;
+#ifdef GAMEQC
+ this.m_itemid = IT_INVISIBILITY;
+#endif
+#ifdef SVQC
+ this.m_iteminit = powerup_invisibility_init;
+#endif
+}
+
+SPAWNFUNC_ITEM(item_invisibility, ITEM_Invisibility)
+// compat
+SPAWNFUNC_ITEM(item_invis, ITEM_Invisibility)
+
+CLASS(Invisibility, Powerups)
+ ATTRIB(Invisibility, netname, string, "invisibility");
+ ATTRIB(Invisibility, m_name, string, _("Invisibility"));
+ ATTRIB(Invisibility, m_color, vector, '0.5 0.5 1');
+ ATTRIB(Invisibility, m_icon, string, "buff_invisible");
+ENDCLASS(Invisibility)
+REGISTER_STATUSEFFECT(Invisibility, NEW(Invisibility));
--- /dev/null
+#include "shield.qh"
+
+#ifdef SVQC
+METHOD(Shield, 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(removal_type == STATUSEFFECT_REMOVE_TIMEOUT && wasactive && IS_PLAYER(actor))
+ {
+ //Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERDOWN_SHIELD, actor.netname);
+ Send_Notification(NOTIF_ONE, actor, MSG_CENTER, CENTER_POWERDOWN_SHIELD);
+ }
+ if(wasactive)
+ stopsound(actor, CH_TRIGGER_SINGLE); // get rid of the pickup sound
+ actor.effects &= ~(EF_RED | EF_ADDITIVE | EF_FULLBRIGHT);
+ SUPER(Shield).m_remove(this, actor, removal_type);
+}
+METHOD(Shield, 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 && IS_PLAYER(actor))
+ {
+ if(!g_cts)
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERUP_SHIELD, actor.netname);
+ Send_Notification(NOTIF_ONE, actor, MSG_CENTER, CENTER_POWERUP_SHIELD);
+ }
+ SUPER(Shield).m_apply(this, actor, eff_time, eff_flags);
+}
+METHOD(Shield, m_tick, void(StatusEffects this, entity actor))
+{
+ play_countdown(actor, StatusEffects_gettime(this, actor), SND_POWEROFF);
+ actor.effects |= (EF_RED | EF_ADDITIVE | EF_FULLBRIGHT);
+ SUPER(Shield).m_tick(this, actor);
+}
+#endif
+#ifdef CSQC
+METHOD(Shield, m_active, bool(StatusEffects this, entity actor))
+{
+ if(autocvar__hud_configure)
+ return true;
+ return SUPER(Shield).m_active(this, actor);
+}
+METHOD(Shield, m_tick, void(StatusEffects this, entity actor))
+{
+ if(this.m_hidden)
+ return;
+
+ float currentTime = (autocvar__hud_configure) ? 27 : bound(0, actor.statuseffect_time[this.m_id] - time, 99);
+ addPowerupItem(this.m_name, this.m_icon, autocvar_hud_progressbar_shield_color, currentTime, this.m_lifetime, (actor.statuseffect_flags[this.m_id] & STATUSEFFECT_FLAG_PERSISTENT));
+}
+#endif
--- /dev/null
+#pragma once
+
+#include <common/items/all.qh>
+#include <common/mutators/mutator/powerups/powerups.qh>
+#ifdef SVQC
+ // For FL_POWERUP
+ #include <common/constants.qh>
+ #include <server/items/items.qh>
+#endif
+
+#ifdef GAMEQC
+MODEL(Shield_ITEM, Item_Model("g_invincible.md3"));
+SOUND(Shield, Item_Sound("powerup_shield"));
+#endif
+
+#ifdef SVQC
+float autocvar_g_balance_powerup_invincible_takedamage;
+float autocvar_g_balance_powerup_invincible_takeforce = 0.33;
+float autocvar_g_balance_powerup_invincible_time;
+void powerup_shield_init(Pickup this, entity item)
+{
+ if(!item.invincible_finished)
+ item.invincible_finished = autocvar_g_balance_powerup_invincible_time;
+}
+#endif
+REGISTER_ITEM(Shield, Powerup) {
+ this.m_canonical_spawnfunc = "item_shield";
+#ifdef GAMEQC
+ this.spawnflags = ITEM_FLAG_NORMAL;
+ this.m_model = MDL_Shield_ITEM;
+ this.m_sound = SND_Shield;
+ this.m_glow = true;
+ this.m_respawnsound = SND_SHIELD_RESPAWN;
+#endif
+ this.netname = "invincible";
+ this.m_name = _("Shield");
+ this.m_icon = "shield";
+ this.m_color = '1 0 1';
+ this.m_waypoint = _("Shield");
+ this.m_waypointblink = 2;
+#ifdef GAMEQC
+ this.m_itemid = IT_INVINCIBLE;
+#endif
+#ifdef SVQC
+ this.m_iteminit = powerup_shield_init;
+#endif
+}
+
+SPAWNFUNC_ITEM(item_shield, ITEM_Shield)
+SPAWNFUNC_ITEM(item_invincible, ITEM_Shield)
+
+CLASS(Shield, Powerups)
+ ATTRIB(Shield, netname, string, "shield");
+ ATTRIB(Shield, m_name, string, _("Shield"));
+ ATTRIB(Shield, m_icon, string, "shield");
+ENDCLASS(Shield)
+REGISTER_STATUSEFFECT(Shield, NEW(Shield));
--- /dev/null
+#include "speed.qh"
+
+#ifdef SVQC
+METHOD(Speed, 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(removal_type == STATUSEFFECT_REMOVE_TIMEOUT && wasactive && IS_PLAYER(actor))
+ {
+ //Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERDOWN_SPEED, actor.netname);
+ Send_Notification(NOTIF_ONE, actor, MSG_CENTER, CENTER_POWERDOWN_SPEED);
+ }
+ if(wasactive)
+ stopsound(actor, CH_TRIGGER_SINGLE); // get rid of the pickup sound
+ actor.effects &= ~EF_STARDUST;
+ SUPER(Speed).m_remove(this, actor, removal_type);
+}
+METHOD(Speed, 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 && IS_PLAYER(actor))
+ {
+ if(!g_cts)
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERUP_SPEED, actor.netname);
+ Send_Notification(NOTIF_ONE, actor, MSG_CENTER, CENTER_POWERUP_SPEED);
+ }
+ SUPER(Speed).m_apply(this, actor, eff_time, eff_flags);
+}
+METHOD(Speed, m_tick, void(StatusEffects this, entity actor))
+{
+ play_countdown(actor, StatusEffects_gettime(this, actor), SND_POWEROFF);
+ actor.effects |= EF_STARDUST;
+ SUPER(Speed).m_tick(this, actor);
+}
+#endif
--- /dev/null
+#pragma once
+
+#include <common/items/all.qh>
+#include <common/mutators/mutator/powerups/powerups.qh>
+#ifdef SVQC
+ // For FL_POWERUP
+ #include <common/constants.qh>
+ #include <server/items/items.qh>
+#endif
+
+#ifdef GAMEQC
+MODEL(Speed_ITEM, Item_Model("g_invincible.md3"));
+SOUND(Speed, Item_Sound("powerup_shield"));
+#endif
+
+#ifdef SVQC
+.float speed_finished;
+
+float autocvar_g_balance_powerup_speed_attackrate = 0.8;
+float autocvar_g_balance_powerup_speed_highspeed = 1.5;
+float autocvar_g_balance_powerup_speed_time = 30;
+float autocvar_g_balance_powerup_speed_weaponspeed = 1.5;
+void powerup_speed_init(Pickup this, entity item)
+{
+ if(!item.speed_finished)
+ item.speed_finished = autocvar_g_balance_powerup_speed_time;
+}
+#endif
+REGISTER_ITEM(Speed, Powerup) {
+ this.m_canonical_spawnfunc = "item_speed";
+#ifdef GAMEQC
+ this.spawnflags = ITEM_FLAG_MUTATORBLOCKED; // TODO: ITEM_FLAG_NORMAL (once it has a model!)
+ this.m_model = MDL_Speed_ITEM;
+ this.m_sound = SND_Speed;
+ this.m_glow = true;
+ this.m_respawnsound = SND_SHIELD_RESPAWN;
+#endif
+ this.netname = "speed";
+ this.m_name = _("Speed");
+ this.m_icon = "buff_speed";
+ this.m_color = '0.1 1 0.84';
+ this.m_waypoint = _("Speed");
+ this.m_waypointblink = 2;
+#ifdef GAMEQC
+ this.m_itemid = IT_SPEED;
+#endif
+#ifdef SVQC
+ this.m_iteminit = powerup_speed_init;
+#endif
+}
+
+SPAWNFUNC_ITEM(item_speed, ITEM_Speed)
+// compat
+SPAWNFUNC_ITEM(item_haste, ITEM_Speed)
+SPAWNFUNC_ITEM(item_scout, ITEM_Speed)
+
+CLASS(Speed, Powerups)
+ ATTRIB(Speed, netname, string, "speed");
+ ATTRIB(Speed, m_name, string, _("Speed"));
+ ATTRIB(Speed, m_color, vector, '0.1 1 0.84');
+ ATTRIB(Speed, m_icon, string, "buff_speed");
+ENDCLASS(Speed)
+REGISTER_STATUSEFFECT(Speed, NEW(Speed));
--- /dev/null
+#include "strength.qh"
+
+#ifdef SVQC
+METHOD(Strength, 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(removal_type == STATUSEFFECT_REMOVE_TIMEOUT && wasactive && IS_PLAYER(actor))
+ {
+ //Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERDOWN_STRENGTH, actor.netname);
+ Send_Notification(NOTIF_ONE, actor, MSG_CENTER, CENTER_POWERDOWN_STRENGTH);
+ }
+ if(wasactive)
+ stopsound(actor, CH_TRIGGER_SINGLE); // get rid of the pickup sound
+ actor.effects &= ~(EF_BLUE | EF_ADDITIVE | EF_FULLBRIGHT);
+ SUPER(Strength).m_remove(this, actor, removal_type);
+}
+METHOD(Strength, 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 && IS_PLAYER(actor))
+ {
+ if(!g_cts)
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERUP_STRENGTH, actor.netname);
+ Send_Notification(NOTIF_ONE, actor, MSG_CENTER, CENTER_POWERUP_STRENGTH);
+ }
+ SUPER(Strength).m_apply(this, actor, eff_time, eff_flags);
+}
+METHOD(Strength, m_tick, void(StatusEffects this, entity actor))
+{
+ play_countdown(actor, StatusEffects_gettime(this, actor), SND_POWEROFF);
+ actor.effects |= (EF_BLUE | EF_ADDITIVE | EF_FULLBRIGHT);
+ SUPER(Strength).m_tick(this, actor);
+}
+#endif
+#ifdef CSQC
+METHOD(Strength, m_active, bool(StatusEffects this, entity actor))
+{
+ if(autocvar__hud_configure)
+ return true;
+ return SUPER(Strength).m_active(this, actor);
+}
+METHOD(Strength, m_tick, void(StatusEffects this, entity actor))
+{
+ if(this.m_hidden)
+ return;
+
+ float currentTime = (autocvar__hud_configure) ? 15 : bound(0, actor.statuseffect_time[this.m_id] - time, 99);
+ addPowerupItem(this.m_name, this.m_icon, autocvar_hud_progressbar_strength_color, currentTime, this.m_lifetime, (actor.statuseffect_flags[this.m_id] & STATUSEFFECT_FLAG_PERSISTENT));
+}
+#endif
--- /dev/null
+#pragma once
+
+#include <common/items/all.qh>
+#include <common/mutators/mutator/powerups/powerups.qh>
+#ifdef SVQC
+ // For FL_POWERUP
+ #include <common/constants.qh>
+ #include <server/items/items.qh>
+#endif
+
+#ifdef GAMEQC
+MODEL(Strength_ITEM, Item_Model("g_strength.md3"));
+SOUND(Strength, Item_Sound("powerup"));
+#endif
+
+#ifdef SVQC
+float autocvar_g_balance_powerup_strength_damage;
+float autocvar_g_balance_powerup_strength_force;
+float autocvar_g_balance_powerup_strength_selfdamage;
+float autocvar_g_balance_powerup_strength_selfforce;
+float autocvar_g_balance_powerup_strength_time;
+void powerup_strength_init(Pickup this, entity item)
+{
+ if(!item.strength_finished)
+ item.strength_finished = autocvar_g_balance_powerup_strength_time;
+}
+#endif
+REGISTER_ITEM(Strength, Powerup) {
+ this.m_canonical_spawnfunc = "item_strength";
+#ifdef GAMEQC
+ this.spawnflags = ITEM_FLAG_NORMAL;
+ this.m_model = MDL_Strength_ITEM;
+ this.m_sound = SND_Strength;
+ this.m_glow = true;
+ this.m_respawnsound = SND_STRENGTH_RESPAWN;
+#endif
+ this.netname = "strength";
+ this.m_name = _("Strength");
+ this.m_icon = "strength";
+ this.m_color = '0 0 1';
+ this.m_waypoint = _("Strength");
+ this.m_waypointblink = 2;
+#ifdef GAMEQC
+ this.m_itemid = IT_STRENGTH;
+#endif
+#ifdef SVQC
+ this.m_iteminit = powerup_strength_init;
+#endif
+}
+
+SPAWNFUNC_ITEM(item_strength, ITEM_Strength)
+
+CLASS(Strength, Powerups)
+ ATTRIB(Strength, netname, string, "strength");
+ ATTRIB(Strength, m_name, string, _("Strength"));
+ ATTRIB(Strength, m_icon, string, "strength");
+ENDCLASS(Strength)
+REGISTER_STATUSEFFECT(Strength, NEW(Strength));
--- /dev/null
+#include "powerups.qh"
+
--- /dev/null
+#pragma once
+
+#include <common/items/item/pickup.qh>
+CLASS(Powerup, Pickup)
+#ifdef SVQC
+ ATTRIB(Powerup, m_mins, vector, '-16 -16 0');
+ ATTRIB(Powerup, m_maxs, vector, '16 16 80');
+ ATTRIB(Powerup, m_botvalue, int, 11000);
+ ATTRIB(Powerup, m_itemflags, int, FL_POWERUP);
+ ATTRIB(Powerup, m_respawntime, float(), GET(g_pickup_respawntime_powerup));
+ ATTRIB(Powerup, m_respawntimejitter, float(), GET(g_pickup_respawntimejitter_powerup));
+#endif
+ENDCLASS(Powerup)
+
+#include <common/mutators/mutator/status_effects/all.qh>
+CLASS(Powerups, StatusEffects)
+#ifdef GAMEQC
+ ATTRIB(Powerups, m_sound_rm, Sound, SND_POWEROFF);
+#endif
+ENDCLASS(Powerups)
--- /dev/null
+#include "sv_powerups.qh"
+
+MUTATOR_HOOKFUNCTION(powerups, W_PlayStrengthSound)
+{
+ entity player = M_ARGV(0, entity);
+ entity store = IS_PLAYER(player) ? PS(player) : player; // because non-player entities can fire weapons
+
+ if(StatusEffects_active(STATUSEFFECT_Strength, player)
+ && ((time > store.prevstrengthsound + autocvar_sv_strengthsound_antispam_time) // prevent insane sound spam
+ || (time > store.prevstrengthsoundattempt + autocvar_sv_strengthsound_antispam_refire_threshold)))
+ {
+ sound(player, CH_TRIGGER, SND_STRENGTH_FIRE, VOL_BASE, ATTEN_NORM);
+ store.prevstrengthsound = time;
+ }
+ store.prevstrengthsoundattempt = time;
+}
+
+MUTATOR_HOOKFUNCTION(powerups, LogDeath_AppendItemCodes)
+{
+ entity player = M_ARGV(0, entity);
+
+ if(StatusEffects_active(STATUSEFFECT_Strength, player))
+ M_ARGV(1, string) = strcat(M_ARGV(1, string), "S");
+
+ if(StatusEffects_active(STATUSEFFECT_Shield, player))
+ M_ARGV(1, string) = strcat(M_ARGV(1, string), "I");
+
+ // TODO: item codes for other powerups?
+}
+
+MUTATOR_HOOKFUNCTION(powerups, Damage_Calculate)
+{
+ entity attacker = M_ARGV(1, entity);
+ entity targ = M_ARGV(2, entity);
+
+ // apply strength multiplier
+ if(StatusEffects_active(STATUSEFFECT_Strength, attacker))
+ {
+ if(targ == attacker)
+ {
+ M_ARGV(4, float) = M_ARGV(4, float) * autocvar_g_balance_powerup_strength_selfdamage;
+ M_ARGV(6, vector) = M_ARGV(6, vector) * autocvar_g_balance_powerup_strength_selfforce;
+ }
+ else
+ {
+ M_ARGV(4, float) = M_ARGV(4, float) * autocvar_g_balance_powerup_strength_damage;
+ M_ARGV(6, vector) = M_ARGV(6, vector) * autocvar_g_balance_powerup_strength_force;
+ }
+ }
+
+ // apply shield multiplier
+ if(StatusEffects_active(STATUSEFFECT_Shield, targ))
+ {
+ M_ARGV(4, float) = M_ARGV(4, float) * autocvar_g_balance_powerup_invincible_takedamage;
+ if (targ != attacker)
+ {
+ M_ARGV(6, vector) = M_ARGV(6, vector) * autocvar_g_balance_powerup_invincible_takeforce;
+ }
+ }
+}
+
+MUTATOR_HOOKFUNCTION(powerups, 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(IS_CLIENT(wp.owner) && (e == player) && DIFF_TEAM(wp.owner, e) && StatusEffects_active(STATUSEFFECT_Invisibility, wp.owner))
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(powerups, MonsterValidTarget)
+{
+ entity targ = M_ARGV(1, entity);
+ return StatusEffects_active(STATUSEFFECT_Invisibility, targ);
+}
+
+MUTATOR_HOOKFUNCTION(powerups, PlayerPhysics_UpdateStats)
+{
+ entity player = M_ARGV(0, entity);
+ // these automatically reset, no need to worry
+
+ if(StatusEffects_active(STATUSEFFECT_Speed, player))
+ STAT(MOVEVARS_HIGHSPEED, player) *= autocvar_g_balance_powerup_speed_highspeed;
+}
+
+MUTATOR_HOOKFUNCTION(powerups, WeaponSpeedFactor)
+{
+ entity player = M_ARGV(1, entity);
+
+ if(StatusEffects_active(STATUSEFFECT_Speed, player))
+ M_ARGV(0, float) *= autocvar_g_balance_powerup_speed_weaponspeed;
+}
+
+MUTATOR_HOOKFUNCTION(powerups, WeaponRateFactor)
+{
+ entity player = M_ARGV(1, entity);
+
+ if(StatusEffects_active(STATUSEFFECT_Speed, player))
+ M_ARGV(0, float) *= autocvar_g_balance_powerup_speed_attackrate;
+}
+
+MUTATOR_HOOKFUNCTION(powerups, BuildMutatorsPrettyString)
+{
+ if(autocvar_g_powerups == 0)
+ M_ARGV(0, string) = strcat(M_ARGV(0, string), ", No powerups");
+ if(autocvar_g_powerups > 0)
+ M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Powerups");
+}
+
+MUTATOR_HOOKFUNCTION(powerups, BotShouldAttack)
+{
+ entity targ = M_ARGV(1, entity);
+
+ if(StatusEffects_active(STATUSEFFECT_Invisibility, targ))
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(powerups, BuildMutatorsString)
+{
+ if(autocvar_g_powerups == 0)
+ M_ARGV(0, string) = strcat(M_ARGV(0, string), ":no_powerups");
+ if(autocvar_g_powerups > 0)
+ M_ARGV(0, string) = strcat(M_ARGV(0, string), ":powerups");
+}
--- /dev/null
+#pragma once
+
+#include <common/mutators/base.qh>
+
+#include "powerups.qh"
+
+int autocvar_g_powerups;
+
+REGISTER_MUTATOR(powerups, true);
+
+.float prevstrengthsound;
+.float prevstrengthsoundattempt;
if (autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health && GetResource(it, RES_HEALTH) < autocvar_g_balance_health_regenstable) continue;
if (IS_DEAD(it)) continue;
if (time < it.msnt_timer) continue;
- if (time < it.spawnshieldtime) continue;
+ if (StatusEffects_active(STATUSEFFECT_SpawnShield, it)) continue;
if (weaponLocked(it)) continue;
if (it == player) continue;
// generated file; do not modify
#include <common/mutators/mutator/status_effects/status_effect/burning.qc>
-#include <common/mutators/mutator/status_effects/status_effect/powerups.qc>
+#include <common/mutators/mutator/status_effects/status_effect/spawnshield.qc>
+#include <common/mutators/mutator/status_effects/status_effect/superweapons.qc>
// generated file; do not modify
#include <common/mutators/mutator/status_effects/status_effect/burning.qh>
-#include <common/mutators/mutator/status_effects/status_effect/powerups.qh>
+#include <common/mutators/mutator/status_effects/status_effect/spawnshield.qh>
+#include <common/mutators/mutator/status_effects/status_effect/superweapons.qh>
+++ /dev/null
-#include "powerups.qh"
-
-#ifdef CSQC
-METHOD(Strength, m_active, bool(StatusEffects this, entity actor))
-{
- if(autocvar__hud_configure)
- return true;
- return SUPER(Strength).m_active(this, actor);
-}
-METHOD(Strength, m_tick, void(StatusEffects this, entity actor))
-{
- if(this.m_hidden)
- return;
-
- float currentTime = (autocvar__hud_configure) ? 15 : bound(0, actor.statuseffect_time[this.m_id] - time, 99);
- addPowerupItem(this.m_name, this.m_icon, autocvar_hud_progressbar_strength_color, currentTime, this.m_lifetime, (actor.statuseffect_flags[this.m_id] & STATUSEFFECT_FLAG_PERSISTENT));
-}
-
-METHOD(Superweapons, m_active, bool(StatusEffects this, entity actor))
-{
- if(autocvar__hud_configure)
- return true;
- return SUPER(Superweapons).m_active(this, actor);
-}
-METHOD(Superweapons, m_tick, void(StatusEffects this, entity actor))
-{
- if(this.m_hidden)
- return;
-
- int allItems = STAT(ITEMS);
-
- // Prevent stuff to show up on mismatch that will be fixed next frame
- if(!(allItems & IT_SUPERWEAPON) && !autocvar__hud_configure)
- return;
-
- if(allItems & IT_UNLIMITED_SUPERWEAPONS)
- return;
-
- float currentTime = (autocvar__hud_configure) ? 13 : bound(0, actor.statuseffect_time[this.m_id] - time, 99);
- addPowerupItem(this.m_name, this.m_icon, autocvar_hud_progressbar_superweapons_color, currentTime, this.m_lifetime, (actor.statuseffect_flags[this.m_id] & STATUSEFFECT_FLAG_PERSISTENT));
-}
-
-METHOD(Shield, m_active, bool(StatusEffects this, entity actor))
-{
- if(autocvar__hud_configure)
- return true;
- return SUPER(Shield).m_active(this, actor);
-}
-METHOD(Shield, m_tick, void(StatusEffects this, entity actor))
-{
- if(this.m_hidden)
- return;
-
- float currentTime = (autocvar__hud_configure) ? 27 : bound(0, actor.statuseffect_time[this.m_id] - time, 99);
- addPowerupItem(this.m_name, this.m_icon, autocvar_hud_progressbar_shield_color, currentTime, this.m_lifetime, (actor.statuseffect_flags[this.m_id] & STATUSEFFECT_FLAG_PERSISTENT));
-}
-#endif
+++ /dev/null
-#pragma once
-
-#include <common/mutators/mutator/status_effects/all.qh>
-
-CLASS(Powerups, StatusEffects)
-#ifdef GAMEQC
- ATTRIB(Powerups, m_sound_rm, Sound, SND_POWEROFF);
-#endif
-ENDCLASS(Powerups)
-
-CLASS(Strength, Powerups)
- ATTRIB(Strength, netname, string, "strength");
- ATTRIB(Strength, m_name, string, _("Strength"));
- ATTRIB(Strength, m_icon, string, "strength");
-ENDCLASS(Strength)
-REGISTER_STATUSEFFECT(Strength, NEW(Strength));
-
-CLASS(Shield, Powerups)
- ATTRIB(Shield, netname, string, "shield");
- ATTRIB(Shield, m_name, string, _("Shield"));
- ATTRIB(Shield, m_icon, string, "shield");
-ENDCLASS(Shield)
-REGISTER_STATUSEFFECT(Shield, NEW(Shield));
-
-CLASS(Superweapons, StatusEffects)
- ATTRIB(Superweapons, netname, string, "superweapons");
- ATTRIB(Superweapons, m_name, string, _("Superweapons"));
- ATTRIB(Superweapons, m_icon, string, "superweapons");
-#ifdef GAMEQC
- ATTRIB(Superweapons, m_sound_rm, Sound, SND_POWEROFF);
-#endif
-ENDCLASS(Superweapons)
-REGISTER_STATUSEFFECT(Superweapons, NEW(Superweapons));
--- /dev/null
+#include "burning.qh"
+
+#ifdef SVQC
+METHOD(SpawnShield, m_remove, void(StatusEffects this, entity actor, int removal_type))
+{
+ actor.effects &= ~(EF_ADDITIVE | EF_FULLBRIGHT);
+ SUPER(SpawnShield).m_remove(this, actor, removal_type);
+}
+METHOD(SpawnShield, m_tick, void(StatusEffects this, entity actor))
+{
+ if(time >= game_starttime)
+ actor.effects |= (EF_ADDITIVE | EF_FULLBRIGHT);
+ SUPER(SpawnShield).m_tick(this, actor);
+}
+#endif
--- /dev/null
+#pragma once
+
+#include <common/mutators/mutator/status_effects/all.qh>
+
+CLASS(SpawnShield, StatusEffects)
+ ATTRIB(SpawnShield, netname, string, "spawnshield");
+ ATTRIB(SpawnShield, m_name, string, _("Spawn Shield"));
+ ATTRIB(SpawnShield, m_icon, string, "shield");
+ ATTRIB(SpawnShield, m_color, vector, '0.36 1 0.07');
+ ATTRIB(SpawnShield, m_hidden, bool, true);
+ ATTRIB(SpawnShield, m_lifetime, float, 10);
+ENDCLASS(SpawnShield)
+REGISTER_STATUSEFFECT(SpawnShield, NEW(SpawnShield));
--- /dev/null
+#include "superweapons.qh"
+
+#ifdef CSQC
+METHOD(Superweapons, m_active, bool(StatusEffects this, entity actor))
+{
+ if(autocvar__hud_configure)
+ return true;
+ return SUPER(Superweapons).m_active(this, actor);
+}
+METHOD(Superweapons, m_tick, void(StatusEffects this, entity actor))
+{
+ if(this.m_hidden)
+ return;
+
+ int allItems = STAT(ITEMS);
+
+ // Prevent stuff to show up on mismatch that will be fixed next frame
+ if(!(allItems & IT_SUPERWEAPON) && !autocvar__hud_configure)
+ return;
+
+ if(allItems & IT_UNLIMITED_SUPERWEAPONS)
+ return;
+
+ float currentTime = (autocvar__hud_configure) ? 13 : bound(0, actor.statuseffect_time[this.m_id] - time, 99);
+ addPowerupItem(this.m_name, this.m_icon, autocvar_hud_progressbar_superweapons_color, currentTime, this.m_lifetime, (actor.statuseffect_flags[this.m_id] & STATUSEFFECT_FLAG_PERSISTENT));
+}
+#endif
--- /dev/null
+#pragma once
+
+#include <common/mutators/mutator/status_effects/all.qh>
+
+CLASS(Superweapons, StatusEffects)
+ ATTRIB(Superweapons, netname, string, "superweapons");
+ ATTRIB(Superweapons, m_name, string, _("Superweapons"));
+ ATTRIB(Superweapons, m_icon, string, "superweapons");
+#ifdef GAMEQC
+ ATTRIB(Superweapons, m_sound_rm, Sound, SND_POWEROFF);
+#endif
+ENDCLASS(Superweapons)
+REGISTER_STATUSEFFECT(Superweapons, NEW(Superweapons));
MUTATOR_HOOKFUNCTION(status_effects, SV_StartFrame)
{
+ if(game_stopped)
+ return;
// TODO: explicitly only loop through entities with a valid statuseffects object
+ // NOTE: due to the way vehicles work currently, this does not function correctly! effect does not tick while inside a vehicle
IL_EACH(g_damagedbycontents, it.damagedbycontents,
{
if (it.move_movetype == MOVETYPE_NOCLIP || !it.statuseffects) continue;
client.statuseffects = spectatee.statuseffects;
}
-MUTATOR_HOOKFUNCTION(status_effects, PlayerSpawn)
+MUTATOR_HOOKFUNCTION(status_effects, PutClientInServer)
{
entity player = M_ARGV(0, entity);
StatusEffects_clearall(player.statuseffects_store);
player.statuseffects = NULL;
}
-
- // TODO: special hook for when effects are initialized?
- if(STAT(WEAPONS, player) & WEPSET_SUPERWEAPONS)
- StatusEffects_apply(STATUSEFFECT_Superweapons, player, time + autocvar_g_balance_superweapons_time, 0);
}
if(cmd_name == "followpowerup")
{
+ // TODO: somehow cheaply loop through all held powerups
FOREACH_CLIENT(IS_PLAYER(it) && (StatusEffects_active(STATUSEFFECT_Strength, it) || StatusEffects_active(STATUSEFFECT_Shield, it)), { return superspec_Spectate(player, it); });
superspec_msg("", "", player, "No active powerup\n", 1);
float armor_take = bound(0, M_ARGV(5, float), GetResource(frag_target, RES_ARMOR));
float damage_take = (autocvar_g_vampire_use_total_damage) ? health_take + armor_take : health_take;
- if(time >= frag_target.spawnshieldtime &&
+ if(!StatusEffects_active(STATUSEFFECT_SpawnShield, frag_target) &&
frag_target != frag_attacker &&
IS_PLAYER(frag_attacker) &&
!IS_DEAD(frag_target) && !STAT(FROZEN, frag_target))
}
#ifdef SVQC
+ // TODO: move these to the client side where they belong
// NOTE: reusing .invincible_finished here as delay counter for the smoke effect
if(vehic.invincible_finished < time)
{
});
float desirabledamage;
desirabledamage = enemydamage;
- if(StatusEffects_active(STATUSEFFECT_Shield, actor) && time > actor.spawnshieldtime)
+ if(StatusEffects_active(STATUSEFFECT_Shield, actor) && !StatusEffects_active(STATUSEFFECT_SpawnShield, actor))
desirabledamage = desirabledamage - selfdamage * autocvar_g_balance_selfdamagepercent;
if(teamplay && actor.team)
desirabledamage = desirabledamage - teamdamage;
float desirabledamage;
desirabledamage = enemydamage;
- if(StatusEffects_active(STATUSEFFECT_Shield, actor) && time > actor.spawnshieldtime)
+ if(StatusEffects_active(STATUSEFFECT_Shield, actor) && !StatusEffects_active(STATUSEFFECT_SpawnShield, actor))
desirabledamage = desirabledamage - selfdamage * autocvar_g_balance_selfdamagepercent;
if(teamplay && actor.team)
desirabledamage = desirabledamage - teamdamage;
setthink(gren, W_Porto_Think);
settouch(gren, W_Porto_Touch);
- if(actor.items & ITEM_Strength.m_itemid)
+ // TODO: handle as mutator effect
+ if(StatusEffects_active(STATUSEFFECT_Strength, actor))
W_SetupProjVelocity_Basic(gren, WEP_CVAR_BOTH(porto, (type <= 0), speed) * autocvar_g_balance_powerup_strength_force, 0);
else
W_SetupProjVelocity_Basic(gren, WEP_CVAR_BOTH(porto, (type <= 0), speed), 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, 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) \
case "spawnfunc":
case "weaponchild":
case "chatbubbleentity":
+ case "buff_model":
//case "net_linked": // actually some real entities are linked without classname, fail
case "":
return true;
#include <common/mapobjects/teleporters.qh>
#include <common/mapobjects/trigger/hurt.qh>
#include <common/mapobjects/trigger/jumppads.qh>
+#include <common/mutators/mutator/powerups/_mod.qh>
#include <common/mutators/mutator/status_effects/_mod.qh>
#include <common/net_linked.qh>
#include <common/physics/player.qh>
#include "roles.qh"
#include <common/stats.qh>
+#include <common/mutators/mutator/powerups/_mod.qh>
#include <common/mutators/mutator/status_effects/_mod.qh>
#include <common/weapons/_all.qh>
#include <server/bot/default/bot.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;
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);
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);
}
#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>
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
{
//spawnfunc(item_flight) /* handled by buffs mutator */
//spawnfunc(item_doubler) /* handled by buffs mutator */
-//spawnfunc(item_haste) /* 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 buffs mutator */
+//spawnfunc(item_invis) /* handled by powerups mutator */
//spawnfunc(item_regen) /* handled by buffs mutator */
// CTF spawnfuncs handled in mutators/gamemode_ctf.qc now
#include "wop.qh"
#include <common/stats.qh>
-#include <common/weapons/_all.qh>
+#include <common/mutators/mutator/powerups/_mod.qh>
#include <common/weapons/_all.qh>
#include <server/items/spawning.qh>
-spawnfunc(item_haste);
-spawnfunc(item_invis);
+spawnfunc(item_speed);
+spawnfunc(item_invisibility);
//***********************
//WORLD OF PADMAN ENTITIES - So people can play wop maps with the xonotic weapons
SPAWNFUNC_ITEM(item_padpower, ITEM_Strength)
SPAWNFUNC_ITEM(item_climber, ITEM_Shield)
-spawnfunc(item_speedy) { spawnfunc_item_haste(this); }
-spawnfunc(item_visionless) { spawnfunc_item_invis(this); }
+spawnfunc(item_speedy) { spawnfunc_item_speed(this); }
+spawnfunc(item_visionless) { spawnfunc_item_invisibility(this); }
SPAWNFUNC_ITEM(item_armor_padshield, ITEM_ArmorMega)
SPAWNFUNC_ITEM(holdable_floater, ITEM_Jetpack)
if(w != 0 || slot == 0)
s = strcat(s, ftos(w));
}
- if(StatusEffects_active(STATUSEFFECT_Strength, player))
- s = strcat(s, "S");
- if(StatusEffects_active(STATUSEFFECT_Shield, player))
- s = strcat(s, "I");
if(PHYS_INPUT_BUTTON_CHAT(player))
s = strcat(s, "T");
// TODO: include these codes as a flag on the item itself
// No damage modification here
// Instead, prepare the victim for his death...
SetResourceExplicit(targ, RES_ARMOR, 0);
- targ.spawnshieldtime = 0;
+ StatusEffects_remove(STATUSEFFECT_SpawnShield, targ, STATUSEFFECT_REMOVE_CLEAR);
SetResourceExplicit(targ, RES_HEALTH, 0.9); // this is < 1
targ.flags -= targ.flags & FL_GODMODE;
damage = 100000;
}
}
- if(!MUTATOR_IS_ENABLED(mutator_instagib))
- {
- // apply strength multiplier
- if (attacker.items & ITEM_Strength.m_itemid)
- {
- if(targ == attacker)
- {
- damage = damage * autocvar_g_balance_powerup_strength_selfdamage;
- force = force * autocvar_g_balance_powerup_strength_selfforce;
- }
- else
- {
- damage = damage * autocvar_g_balance_powerup_strength_damage;
- force = force * autocvar_g_balance_powerup_strength_force;
- }
- }
-
- // apply invincibility multiplier
- if (targ.items & ITEM_Shield.m_itemid)
- {
- damage = damage * autocvar_g_balance_powerup_invincible_takedamage;
- if (targ != attacker)
- {
- force = force * autocvar_g_balance_powerup_invincible_takeforce;
- }
- }
- }
-
if (targ == attacker)
damage = damage * autocvar_g_balance_selfdamagepercent; // Partial damage if the attacker hits himself
// apply push
if (targ.damageforcescale)
if (force)
- if (!IS_PLAYER(targ) || time >= targ.spawnshieldtime || targ == attacker)
+ if (!IS_PLAYER(targ) || !StatusEffects_active(STATUSEFFECT_SpawnShield, targ) || targ == attacker)
{
vector farce = damage_explosion_calcpush(targ.damageforcescale * force, targ.velocity, autocvar_g_balance_damagepush_speedfactor);
if(targ.move_movetype == MOVETYPE_PHYSICS)
#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>
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.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;
#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)
/**/ o(bool, MUTATOR_ARGV_0_bool) \
/**/
MUTATOR_HOOKABLE(AllowRocketJumping, EV_AllowRocketJumping);
+
+/** Called when weapons are performing their attack, useful for applying bonus attack sounds */
+#define EV_W_PlayStrengthSound(i, o) \
+ /** player */ i(entity, MUTATOR_ARGV_0_entity) \
+ /**/
+MUTATOR_HOOKABLE(W_PlayStrengthSound, EV_W_PlayStrengthSound);
#include <common/mapobjects/subs.qh>
#include <common/mapobjects/teleporters.qh>
#include <common/minigames/sv_minigames.qh>
+#include <common/mutators/mutator/status_effects/_mod.qh>
#include <common/mutators/mutator/waypoints/waypointsprites.qh>
#include <common/physics/player.qh>
#include <common/playerstats.qh>
if (!ITEM_DAMAGE_NEEDKILL(deathtype))
damage = 0;
}
- else if (time < this.spawnshieldtime && autocvar_g_spawnshield_blockdamage < 1)
+ else if (StatusEffects_active(STATUSEFFECT_SpawnShield, this) && autocvar_g_spawnshield_blockdamage < 1)
damage *= 1 - max(0, autocvar_g_spawnshield_blockdamage);
if(deathtype & HITTYPE_SOUND) // sound based attacks cause bleeding from the ears
if (take > 100)
Violence_GibSplash_At(hitloc, force * -0.2, 3, 1, this, attacker);
- if (time >= this.spawnshieldtime || autocvar_g_spawnshield_blockdamage < 1)
+ if (!StatusEffects_active(STATUSEFFECT_SpawnShield, this) || autocvar_g_spawnshield_blockdamage < 1)
{
if (!(this.flags & FL_GODMODE))
{
void W_PlayStrengthSound(entity player)
{
- entity store = IS_PLAYER(player) ? PS(player) : player; // because non-player entities can fire, but can they have items? TODO
-
- if((player.items & ITEM_Strength.m_itemid)
- && ((time > store.prevstrengthsound + autocvar_sv_strengthsound_antispam_time) // prevent insane sound spam
- || (time > store.prevstrengthsoundattempt + autocvar_sv_strengthsound_antispam_refire_threshold)))
- {
- sound(player, CH_TRIGGER, SND_STRENGTH_FIRE, VOL_BASE, ATTEN_NORM);
- store.prevstrengthsound = time;
- }
- store.prevstrengthsoundattempt = time;
+ MUTATOR_CALLHOOK(W_PlayStrengthSound, player);
}
float W_CheckProjectileDamage(entity inflictor, entity projowner, int deathtype, float exception)
bool W_DualWielding(entity player);
void W_GiveWeapon (entity e, float wep);
-.float prevstrengthsound;
-.float prevstrengthsoundattempt;
void W_PlayStrengthSound(entity player);
float W_CheckProjectileDamage(entity inflictor, entity projowner, int deathtype, float exception);
void W_PrepareExplosionByDamage(entity this, entity attacker, void(entity this) explode);
#include <common/items/_mod.qh>
#include <common/mapobjects/platforms.qh>
#include <common/monsters/_mod.qh>
+#include <common/mutators/mutator/status_effects/_mod.qh>
#include <common/net_linked.qh>
#include <common/notifications/all.qh>
#include <common/state.qh>
if (this == NULL) return;
this.state = WS_INUSE;
- actor.spawnshieldtime = min(actor.spawnshieldtime, time); // kill spawn shield when you fire
+ if(StatusEffects_active(STATUSEFFECT_SpawnShield, actor)) // given this is performed often, perform a lighter check first
+ StatusEffects_remove(STATUSEFFECT_SpawnShield, actor, STATUSEFFECT_REMOVE_CLEAR); // kill spawn shield when you fire
// if the weapon hasn't been firing continuously, reset the timer
if (attacktime >= 0)
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");
}
g_balance_kill_antispam 0
g_forced_respawn 1
// g_playerclip_collisions 0 // do not check playerclips
-g_powerups 0
+g_powerups -1 // needed for speed powerup
+g_buffs 0
g_start_delay 3
g_use_ammunition 0
g_weapon_stay 1
sv_vote_nospectators 1
timelimit_override 20
-// general buff settings
-g_buffs_cooldown_activate 0
-g_buffs_cooldown_respawn 0
-g_buffs_randomize 0
-
-// disabled buffs
-g_buffs_ammo 0
-g_buffs_resistance 0
-g_buffs_medic 0
-g_buffs_vengeance 0
-g_buffs_bash 0
-g_buffs_disability 0
-g_buffs_vampire 0
-g_buffs_jump 0
-g_buffs_invisible 0
-g_buffs_inferno 0
-g_buffs_swapper 0
-g_buffs_magnet 0
-g_buffs_luck 0
-g_buffs_flight 0
-
-// speed buff (q3 haste replacement)
+// speed powerup (q3 haste replacement)
g_movement_highspeed_q3_compat 1
-g_buffs_speed 1
-g_buffs_speed_time 30
-g_buffs_speed_speed 1.3 // q3 haste lasts 30 seconds
-g_buffs_speed_rate 0.7692307692 // 1/1.3
-g_buffs_speed_weaponspeed 1 // do not increase projectile speed
-g_buffs_speed_damage_take 1
-g_buffs_speed_regen 1.2
+g_balance_powerup_speed_time 30
+g_balance_powerup_speed_highspeed 1.3 // q3 haste lasts 30 seconds
+g_balance_powerup_speed_attackrate 0.7692307692 // 1/1.3
+g_balance_powerup_speed_weaponspeed 1 // do not increase projectile speed
// game mode settings
g_cts_finish_kill_delay 2