Enable powerup versions of speed and invis, with temporary use of buff models, and XDF support
Closes #2612
See merge request xonotic/xonotic-data.pk3dir!918
precache_model(this.mdl);
_setmodel(this, this.mdl);
+ this.skin = ReadByte();
+
setsize(this, '-16 -16 0', '16 16 48');
}
CLASS(Pickup, GameItem)
#ifdef GAMEQC
ATTRIB(Pickup, m_model, Model);
+ ATTRIB(Pickup, m_skin, int);
+ ATTRIB(Pickup, m_color, vector);
ATTRIB(Pickup, m_sound, Sound, SND_ITEMPICKUP);
#endif
ATTRIB(Pickup, netname, string);
#endif
#ifdef GAMEQC
-MODEL(Invisibility_ITEM, Item_Model("g_strength.md3"));
+//MODEL(Invisibility_ITEM, Item_Model("g_strength.md3")); // TODO: new model required
SOUND(Invisibility, Item_Sound("powerup"));
#endif
#ifdef SVQC
.float invisibility_finished;
+bool autocvar_g_powerups_invisibility = 1;
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;
+ item.invisibility_finished = (item.count) ? item.count : autocvar_g_balance_powerup_invisibility_time;
}
#endif
REGISTER_ITEM(Invisibility, Powerup) {
this.m_canonical_spawnfunc = "item_invisibility";
+#ifdef SVQC
+ if(autocvar_g_powerups_invisibility)
+ this.spawnflags = ITEM_FLAG_NORMAL;
+ else
+ this.spawnflags = ITEM_FLAG_MUTATORBLOCKED;
+
+ this.m_iteminit = powerup_invisibility_init;
+#endif
#ifdef GAMEQC
- this.spawnflags = ITEM_FLAG_MUTATORBLOCKED; // TODO: ITEM_FLAG_NORMAL (once it has a model!)
- this.m_model = MDL_Invisibility_ITEM;
+ this.m_itemid = IT_INVISIBILITY;
+ this.m_model = MDL_BUFF; // TODO: MDL_Invisibility_ITEM when new model available
+ this.m_skin = 12;
this.m_sound = SND_Invisibility;
this.m_glow = true;
this.m_respawnsound = SND_STRENGTH_RESPAWN;
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)
#endif
#ifdef SVQC
+bool autocvar_g_powerups_shield = 1;
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;
+ item.invincible_finished = (item.count) ? item.count : autocvar_g_balance_powerup_invincible_time;
}
#endif
REGISTER_ITEM(Shield, Powerup) {
this.m_canonical_spawnfunc = "item_shield";
+#ifdef SVQC
+ if(autocvar_g_powerups_shield)
+ this.spawnflags = ITEM_FLAG_NORMAL;
+ else
+ this.spawnflags = ITEM_FLAG_MUTATORBLOCKED;
+
+ this.m_iteminit = powerup_shield_init;
+#endif
#ifdef GAMEQC
- this.spawnflags = ITEM_FLAG_NORMAL;
+ this.m_itemid = IT_INVINCIBLE;
this.m_model = MDL_Shield_ITEM;
this.m_sound = SND_Shield;
this.m_glow = true;
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)
#endif
#ifdef GAMEQC
-MODEL(Speed_ITEM, Item_Model("g_invincible.md3"));
+//MODEL(Speed_ITEM, Item_Model("g_invincible.md3")); // TODO: new model required
SOUND(Speed, Item_Sound("powerup_shield"));
#endif
#ifdef SVQC
.float speed_finished;
+bool autocvar_g_powerups_speed = 1;
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;
void powerup_speed_init(Pickup this, entity item)
{
if(!item.speed_finished)
- item.speed_finished = autocvar_g_balance_powerup_speed_time;
+ item.speed_finished = (item.count) ? item.count : autocvar_g_balance_powerup_speed_time;
}
#endif
REGISTER_ITEM(Speed, Powerup) {
this.m_canonical_spawnfunc = "item_speed";
+#ifdef SVQC
+ if(autocvar_g_powerups_speed)
+ this.spawnflags = ITEM_FLAG_NORMAL;
+ else
+ this.spawnflags = ITEM_FLAG_MUTATORBLOCKED;
+
+ this.m_iteminit = powerup_speed_init;
+#endif
#ifdef GAMEQC
- this.spawnflags = ITEM_FLAG_MUTATORBLOCKED; // TODO: ITEM_FLAG_NORMAL (once it has a model!)
- this.m_model = MDL_Speed_ITEM;
+ this.m_itemid = IT_SPEED;
+ this.m_model = MDL_BUFF; // TODO: MDL_Speed_ITEM when new model available
+ this.m_skin = 9;
this.m_sound = SND_Speed;
this.m_glow = true;
this.m_respawnsound = SND_SHIELD_RESPAWN;
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)
#endif
#ifdef SVQC
+bool autocvar_g_powerups_strength = 1;
float autocvar_g_balance_powerup_strength_damage;
float autocvar_g_balance_powerup_strength_force;
float autocvar_g_balance_powerup_strength_selfdamage;
void powerup_strength_init(Pickup this, entity item)
{
if(!item.strength_finished)
- item.strength_finished = autocvar_g_balance_powerup_strength_time;
+ item.strength_finished = (item.count) ? item.count : autocvar_g_balance_powerup_strength_time;
}
#endif
REGISTER_ITEM(Strength, Powerup) {
this.m_canonical_spawnfunc = "item_strength";
+#ifdef SVQC
+ if(autocvar_g_powerups_strength)
+ this.spawnflags = ITEM_FLAG_NORMAL;
+ else
+ this.spawnflags = ITEM_FLAG_MUTATORBLOCKED;
+
+ this.m_iteminit = powerup_strength_init;
+#endif
#ifdef GAMEQC
- this.spawnflags = ITEM_FLAG_NORMAL;
+ this.m_itemid = IT_STRENGTH;
this.m_model = MDL_Strength_ITEM;
this.m_sound = SND_Strength;
this.m_glow = true;
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)
#include "powerups.qh"
int autocvar_g_powerups;
+bool autocvar_g_powerups_stack;
REGISTER_MUTATOR(powerups, true);
.float prevstrengthsound;
.float prevstrengthsoundattempt;
+
+// q3compat
+.float count;
MULTITEAM_INFO(ONSLAUGHT_GENDESTROYED, N_CONSOLE, 0, 0, "", "", "", _("^TC^TT^BG generator has been destroyed"), "", GENERATOR)
MULTITEAM_INFO(ONSLAUGHT_GENDESTROYED_OVERTIME, N_CONSOLE, 0, 0, "", "", "", _("^TC^TT^BG generator spontaneously combusted due to overtime!"), "", GENERATOR)
- MSG_INFO_NOTIF(POWERUP_INVISIBILITY, N_CONSOLE, 1, 0, "s1", "s1", "strength", _("^BG%s^K1 picked up Invisibility"), "")
- MSG_INFO_NOTIF(POWERUP_SHIELD, N_CONSOLE, 1, 0, "s1", "s1", "shield", _("^BG%s^K1 picked up Shield"), "")
- MSG_INFO_NOTIF(POWERUP_SPEED, N_CONSOLE, 1, 0, "s1", "s1", "shield", _("^BG%s^K1 picked up Speed"), "")
- MSG_INFO_NOTIF(POWERUP_STRENGTH, N_CONSOLE, 1, 0, "s1", "s1", "strength", _("^BG%s^K1 picked up Strength"), "")
+ MSG_INFO_NOTIF(POWERUP_INVISIBILITY, N_CONSOLE, 1, 0, "s1", "s1", "buff_invisible", _("^BG%s^K1 picked up Invisibility"), "")
+ MSG_INFO_NOTIF(POWERUP_SHIELD, N_CONSOLE, 1, 0, "s1", "s1", "shield", _("^BG%s^K1 picked up Shield"), "")
+ MSG_INFO_NOTIF(POWERUP_SPEED, N_CONSOLE, 1, 0, "s1", "s1", "buff_speed", _("^BG%s^K1 picked up Speed"), "")
+ MSG_INFO_NOTIF(POWERUP_STRENGTH, N_CONSOLE, 1, 0, "s1", "s1", "strength", _("^BG%s^K1 picked up Strength"), "")
MSG_INFO_NOTIF(QUIT_DISCONNECT, N_CHATCON, 1, 0, "s1", "", "", _("^BG%s^F3 disconnected"), "")
MSG_INFO_NOTIF(QUIT_KICK_IDLING, N_CHATCON, 1, 1, "s1 f1", "", "", _("^BG%s^F3 was kicked after idling for %s seconds"), "")
LOG_TRACE("^1WARNING!^7 this.mdl is unset for item ", this.classname, "expect a crash just about now");
WriteString(MSG_ENTITY, this.mdl);
+ WriteByte(MSG_ENTITY, bound(0, this.skin, 255));
}
-
if(sf & ISF_COLORMAP)
{
WriteShort(MSG_ENTITY, this.colormap);
if (item.strength_finished)
{
pickedup = true;
- StatusEffects_apply(STATUSEFFECT_Strength, player, max(StatusEffects_gettime(STATUSEFFECT_Strength, player), time) + item.strength_finished, 0);
+ float t = max(StatusEffects_gettime(STATUSEFFECT_Strength, player), time);
+ if (autocvar_g_powerups_stack)
+ t += item.strength_finished;
+ else
+ t = max(t, time + item.strength_finished);
+ StatusEffects_apply(STATUSEFFECT_Strength, player, t, 0);
}
if (item.invincible_finished)
{
pickedup = true;
- StatusEffects_apply(STATUSEFFECT_Shield, player, max(StatusEffects_gettime(STATUSEFFECT_Shield, player), time) + item.invincible_finished, 0);
+ float t = max(StatusEffects_gettime(STATUSEFFECT_Shield, player), time);
+ if (autocvar_g_powerups_stack)
+ t += item.invincible_finished;
+ else
+ t = max(t, time + item.invincible_finished);
+ StatusEffects_apply(STATUSEFFECT_Shield, player, t, 0);
}
if (item.speed_finished)
{
pickedup = true;
- StatusEffects_apply(STATUSEFFECT_Speed, player, max(StatusEffects_gettime(STATUSEFFECT_Speed, player), time) + item.speed_finished, 0);
+ float t = max(StatusEffects_gettime(STATUSEFFECT_Speed, player), time);
+ if (autocvar_g_powerups_stack)
+ t += item.speed_finished;
+ else
+ t = max(t, time + item.speed_finished);
+ StatusEffects_apply(STATUSEFFECT_Speed, player, t, 0);
}
if (item.invisibility_finished)
{
pickedup = true;
- StatusEffects_apply(STATUSEFFECT_Invisibility, player, max(StatusEffects_gettime(STATUSEFFECT_Invisibility, player), time) + item.invisibility_finished, 0);
+ float t = max(StatusEffects_gettime(STATUSEFFECT_Invisibility, player), time);
+ if (autocvar_g_powerups_stack)
+ t += item.invisibility_finished;
+ else
+ t = max(t, time + item.invisibility_finished);
+ StatusEffects_apply(STATUSEFFECT_Invisibility, player, t, 0);
}
if (item.superweapons_finished)
{
setmodel(this, MDL_Null); // precision set below
//this.effects |= EF_LOWPRECISION;
+ // support skinned models for powerups
+ this.skin = def.m_skin;
+ this.glowmod = def.m_color;
+
setsize (this, this.pos1 = def.m_mins, this.pos2 = def.m_maxs);
this.SendFlags |= ISF_SIZE;
g_balance_kill_antispam 0
g_forced_respawn 1
// g_playerclip_collisions 0 // do not check playerclips
-g_powerups 0 // no powerups until the speed powerup has its own model
+// Powerups including speed enabled by default.
+g_powerups_strength 0
+g_powerups_shield 0
+g_powerups_invisibility 0
+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_inferno 0
-g_buffs_swapper 0
-g_buffs_magnet 0
-g_buffs_luck 0
-g_buffs_flight 0
-
// speed powerup (q3 haste replacement)
g_movement_highspeed_q3_compat 1
-g_balance_powerup_speed_time 30
-g_balance_powerup_speed_highspeed 1.3 // q3 haste lasts 30 seconds
+g_balance_powerup_speed_time 30 // q3 haste lasts 30 seconds unless count field set otherwise
+g_balance_powerup_speed_highspeed 1.3
g_balance_powerup_speed_attackrate 0.7692307692 // 1/1.3
// game mode settings
set g_shootfromfixedorigin "" "if set to a string like 0 y z, the gun is moved to the given y and z coordinates. If set to a string like x y z, the whole shot origin is used"
set g_weapon_stay 0 "1: ghost weapons can be picked up but give no ammo, thrown guns have ammo 2: ghost weapons can be picked up and refill ammo to one pickup size, thrown guns have no ammo (to prevent infinite ammo abuse)"
set g_weapon_throwable 1 "if set to 1, weapons can be dropped"
-set g_powerups -1 "if set to 0 the strength and shield (invincibility) will not spawn on the map, if 1 they will spawn in all game modes, -1 is game mode default"
+set g_powerups -1 "if set to 0 no powerups will spawn, if 1 they will spawn in all game modes, -1 is game mode default"
+set g_powerups_stack 0 "enables stacking of powerup timers when picking up a powerup you already have; otherwise timer is reset to the time granted by the item, if greater than the time you currently have"
+set g_powerups_strength 1 "allow strength powerups to spawn"
+set g_powerups_shield 1 "allow shield powerups to spawn"
+set g_powerups_speed 1 "allow speed powerups to spawn"
+set g_powerups_invisibility 1 "allow invisibility powerups to spawn"
set g_use_ammunition 1 "if set to 0 all weapons have unlimited ammo"
set g_pickup_items -1 "if set to 0 all items (health, armor, ammo, weapons...) are removed from the map, if 1 they are forced to spawn"
set g_pickup_respawntime_scaling_reciprocal 0 "Multiply respawn time by `reciprocal / (p + offset) + linear` where `p` is the current number of players, takes effect with 2 or more players present, `reciprocal` (with `offset` and `linear` set to 0) can be used to achieve a constant number of items spawned *per player*"