]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'z411/powerups_dropondeath' into 'master'
authorterencehill <piuntn@gmail.com>
Sat, 4 Dec 2021 22:45:51 +0000 (22:45 +0000)
committerterencehill <piuntn@gmail.com>
Sat, 4 Dec 2021 22:45:51 +0000 (22:45 +0000)
Merge branch z411/powerups_dropondeath (improves on Mario's implementation)

See merge request xonotic/xonotic-data.pk3dir!943

qcsrc/common/mutators/mutator/powerups/powerup/shield.qh
qcsrc/common/mutators/mutator/powerups/sv_powerups.qc
qcsrc/common/mutators/mutator/powerups/sv_powerups.qh
qcsrc/server/items/items.qc
qcsrc/server/items/items.qh
qcsrc/server/items/spawning.qc
qcsrc/server/items/spawning.qh
qcsrc/server/world.qc
xonotic-server.cfg

index 10900e86a89c7ec5f95dfb55693c24543b5cf6a6..508a39487ae84309a8bf106f052a586a03f1967a 100644 (file)
@@ -53,7 +53,7 @@ SPAWNFUNC_ITEM(item_shield, ITEM_Shield)
 SPAWNFUNC_ITEM(item_invincible, ITEM_Shield)
 
 CLASS(Shield, Powerups)
-    ATTRIB(Shield, netname, string, "shield");
+    ATTRIB(Shield, netname, string, "invincible"); // NOTE: referring to as invincible so that it matches the powerup item
     ATTRIB(Shield, m_name, string, _("Shield"));
     ATTRIB(Shield, m_icon, string, "shield");
 ENDCLASS(Shield)
index 2ac0bbccc930f46bf52fe3ff9cc472879cb92dd5..e7bbeeb69c2176048a2820e2349ca6b157a1c7d6 100644 (file)
@@ -77,6 +77,91 @@ MUTATOR_HOOKFUNCTION(powerups, MonsterValidTarget)
        return StatusEffects_active(STATUSEFFECT_Invisibility, targ);
 }
 
+void powerups_DropItem_Think(entity this)
+{
+       TakeResource(this, RES_HEALTH, 1);
+       
+       if(GetResource(this, RES_HEALTH) < 1) {
+               WaypointSprite_Kill(this.waypointsprite_attached);
+               delete(this);
+               return;
+       }
+       
+       // Only needed to update if the timer of the powerup is running
+       if(autocvar_g_powerups_drop_ondeath == 1)
+               WaypointSprite_UpdateHealth(this.waypointsprite_attached, GetResource(this, RES_HEALTH));
+       
+       this.nextthink = time + 1;
+}
+
+void powerups_DropItem(entity this, StatusEffects effect)
+{
+       entity item = Item_DefinitionFromInternalName(effect.netname);
+       float t = StatusEffects_gettime(effect, this);
+       float timeleft = t - time;
+       float maxtime = 0;
+
+       if(timeleft <= 1 || !item)
+               return;
+       entity e = spawn();
+
+       // If we want the timer to keep running, we enable expiring then use the exact time the powerup will finish at.
+       // If we want the timer to freeze, we disable expiring and we just use the time left of the powerup.
+       // See Item_SetExpiring() below.
+       float finished = (autocvar_g_powerups_drop_ondeath == 2 ? timeleft : t);
+
+       // If the timer is frozen, the item will stay on the floor for 20 secs (same as weapons),
+       // otherwise it'll disappear after the timer runs out.
+       float time_to_live = (autocvar_g_powerups_drop_ondeath == 2 ? autocvar_g_items_dropped_lifetime : timeleft);
+
+       // TODO: items cannot hold their "item field" yet, so we need to list all the powerups here!
+       switch(item)
+       {
+               case ITEM_Strength: e.strength_finished = finished; maxtime = autocvar_g_balance_powerup_strength_time; break;
+               case ITEM_Shield: e.invincible_finished = finished; maxtime = autocvar_g_balance_powerup_invincible_time; break;
+               case ITEM_Invisibility: e.invisibility_finished = finished; maxtime = autocvar_g_balance_powerup_invincible_time; break;
+               case ITEM_Speed: e.speed_finished = finished; maxtime = autocvar_g_balance_powerup_speed_time; break;
+       }
+       Item_InitializeLoot(e, item.m_canonical_spawnfunc, this.origin + '0 0 32', randomvec() * 175 + '0 0 175', time_to_live);
+
+       if(autocvar_g_powerups_drop_ondeath != 2)
+               Item_SetExpiring(e, true);
+       
+       // Use health as time left to live
+       SetResourceExplicit(e, RES_HEALTH, time_to_live);
+       
+       // Create waypoint displaying time left of the powerup
+       entity wp = WaypointSprite_Spawn(WP_Item, 0, 0, e, '0 0 1' * e.maxs.z, NULL, 0, e, waypointsprite_attached, true, RADARICON_Item);
+       wp.wp_extra = item.m_id;
+       WaypointSprite_UpdateMaxHealth(e.waypointsprite_attached, maxtime);
+       WaypointSprite_UpdateHealth(e.waypointsprite_attached, timeleft);
+       
+       // Start dropping its time to live
+       setthink(e, powerups_DropItem_Think);
+       e.nextthink = time + 1;
+}
+
+MUTATOR_HOOKFUNCTION(powerups, ItemTouched)
+{
+       entity e = M_ARGV(0, entity);
+       if(e.waypointsprite_attached)
+               WaypointSprite_Kill(e.waypointsprite_attached);
+}
+
+MUTATOR_HOOKFUNCTION(powerups, PlayerDies)
+{
+       if(!autocvar_g_powerups_drop_ondeath)
+               return;
+
+       entity frag_target = M_ARGV(2, entity);
+
+       FOREACH(StatusEffect, it.instanceOfPowerups,
+       {
+               if(StatusEffects_active(it, frag_target))
+                       powerups_DropItem(frag_target, it);
+       });
+}
+
 MUTATOR_HOOKFUNCTION(powerups, PlayerPhysics_UpdateStats)
 {
        entity player = M_ARGV(0, entity);
index b514385381c8a8bfb38d274dcf1c6f9dc36596be..b7f3b8e40d65d9218f6f4483f2505309eef471de 100644 (file)
@@ -5,6 +5,7 @@
 #include "powerups.qh"
 
 int autocvar_g_powerups;
+int autocvar_g_powerups_drop_ondeath;
 bool autocvar_g_powerups_stack;
 
 REGISTER_MUTATOR(powerups, true);
index 932db7a553dd2f663c7a1549d15cfa52f54d160c..ade4795c523e420e56c77f4f5b5164cbc8250179 100644 (file)
@@ -981,7 +981,7 @@ void _StartItem(entity this, entity def, float defaultrespawntime, float default
 
                // Savage: remove thrown items after a certain period of time ("garbage collection")
                setthink(this, RemoveItem);
-               this.nextthink = time + 20;
+               this.nextthink = time + autocvar_g_items_dropped_lifetime;
 
                this.takedamage = DAMAGE_YES;
                this.event_damage = Item_Damage;
index 7a472aa94cd7f9ccbec9ab96548ca71f508a1227..dc3898323aea38a43daddcf99624c3b9b02e7e7a 100644 (file)
@@ -6,6 +6,7 @@ float autocvar_g_balance_superweapons_time;
 bool autocvar_g_fullbrightitems;
 float autocvar_g_items_mindist;
 float autocvar_g_items_maxdist;
+float autocvar_g_items_dropped_lifetime;
 int autocvar_g_pickup_items;
 bool autocvar_g_nodepthtestitems;
 #define autocvar_g_weapon_stay cvar("g_weapon_stay")
index 11bf67f5e8650a16133728aa35aa99ba15580b85..bc780da552677418eb14e3e5943d3e678085626d 100644 (file)
@@ -29,6 +29,19 @@ entity Item_FindDefinition(string class_name)
        return NULL;
 }
 
+entity Item_DefinitionFromInternalName(string item_name)
+{
+       FOREACH(Items, it.netname == item_name,
+       {
+               return it;
+       });
+       FOREACH(Weapons, it.netname == item_name,
+       {
+               return it.m_pickup;
+       });
+       return NULL;
+}
+
 bool Item_IsAllowed(string class_name)
 {
        entity definition = Item_FindDefinition(class_name);
index b52449e7158dffab62269d6b17d32a6a7cdcc439..f4bd32e7b87adda20e0c679c29430b719c87fa20 100644 (file)
@@ -12,6 +12,12 @@ bool startitem_failed;
 /// found.
 entity Item_FindDefinition(string class_name);
 
+/// \brief Returns the item definition corresponding to the given internal name.
+/// \param[in] item_name Internal netname to search for.
+/// \return Item definition corresponding to the given internal name or NULL is not
+/// found.
+entity Item_DefinitionFromInternalName(string item_name);
+
 /// \brief Checks whether the items with the specified class name are allowed to
 /// spawn.
 /// \param[in] class_name Item class name to check.
index 02c059ea808c0d00ab4c3113c5fccb9e1249990a..728c9d757e6ffa77ad2f1edfc0637492dc2c8c0f 100644 (file)
@@ -461,6 +461,7 @@ void cvar_changes_init()
                BADCVAR("g_physics_clientselect");
                BADCVAR("g_pinata");
                BADCVAR("g_powerups");
+               BADCVAR("g_powerups_drop_ondeath");
                BADCVAR("g_player_brightness");
                BADCVAR("g_rocket_flying");
                BADCVAR("g_rocket_flying_disabledelays");
index 1634c256cca1102ea23f05da17e097a0b37bc016..1f7a0c088e22c01b973d94758a54bdbeb1c3829e 100644 (file)
@@ -198,6 +198,7 @@ set g_shootfromfixedorigin "" "if set to a string like 0 y z, the gun is moved t
 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 no powerups will spawn, if 1 they will spawn in all game modes, -1 is game mode default"
+set g_powerups_drop_ondeath 0 "players will drop their powerups on death (1 = timer continues, 2 = timer freezes until picked up)"
 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"
@@ -231,6 +232,7 @@ set g_maplist_sizes_count_bots 1 "include the number of bots currently in the se
 
 set g_items_mindist 4000 "starting distance for the fading of items"
 set g_items_maxdist 4500 "maximum distance at which an item can be viewed, after which it will be invisible"
+set g_items_dropped_lifetime 20 "default lifetime for dropped items unless explicitly overriden (ie. flags)"
 
 set g_grab_range 200 "distance at which dragable objects can be grabbed"