]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/common/t_items.qc
Merge branch 'Lyberta/URS2' into Lyberta/RandomStartWeapons
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / t_items.qc
index 674793bca16c70ef4bb53c3a21032f2623e3b640..5f545151b1eb88d201217bef61e64f237221ca5f 100644 (file)
@@ -634,29 +634,40 @@ void Item_ScheduleRespawnIn(entity e, float t)
 AUTOCVAR(g_pickup_respawntime_scaling_reciprocal, float, 0.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*");
 AUTOCVAR(g_pickup_respawntime_scaling_offset, float, 0.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, `offset` offsets the curve left or right - the results are not intuitive and I recommend plotting the respawn time and the number of items per player to see what's happening");
 AUTOCVAR(g_pickup_respawntime_scaling_linear, float, 1.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, `linear` can be used to simply scale the respawn time linearly");
+
+float adjust_respawntime(float normal_respawntime) {
+       float r = autocvar_g_pickup_respawntime_scaling_reciprocal;
+       float o = autocvar_g_pickup_respawntime_scaling_offset;
+       float l = autocvar_g_pickup_respawntime_scaling_linear;
+
+       if (r == 0 && l == 1) {
+               return normal_respawntime;
+       }
+
+       CheckAllowedTeams(NULL);
+       GetTeamCounts(NULL);
+       int players = 0;
+       if (c1 != -1) players += c1;
+       if (c2 != -1) players += c2;
+       if (c3 != -1) players += c3;
+       if (c4 != -1) players += c4;
+
+       if (players >= 2) {
+               return normal_respawntime * (r / (players + o) + l);
+       } else {
+               return normal_respawntime;
+       }
+}
+
 void Item_ScheduleRespawn(entity e)
 {
        if(e.respawntime > 0)
        {
                Item_Show(e, 0);
 
-               CheckAllowedTeams(NULL);
-               GetTeamCounts(NULL);
-               int players = 0;
-               if (c1 != -1) players += c1;
-               if (c2 != -1) players += c2;
-               if (c3 != -1) players += c3;
-               if (c4 != -1) players += c4;
-               float adjusted_respawntime;
-               if (players >= 2) {
-                       float a = autocvar_g_pickup_respawntime_scaling_reciprocal;
-                       float b = autocvar_g_pickup_respawntime_scaling_offset;
-                       float c = autocvar_g_pickup_respawntime_scaling_linear;
-                       adjusted_respawntime = e.respawntime * (a / (players + b) + c);
-               } else {
-                       adjusted_respawntime = e.respawntime;
-               }
-               //LOG_INFOF("item %s will respawn in %f\n", e.classname, adjusted_respawntime);
+               float adjusted_respawntime = adjust_respawntime(e.respawntime);
+               //LOG_INFOF("item %s will respawn in %f", e.classname, adjusted_respawntime);
+
                // range: adjusted_respawntime - respawntimejitter .. adjusted_respawntime + respawntimejitter
                float actual_time = adjusted_respawntime + crandom() * e.respawntimejitter;
                Item_ScheduleRespawnIn(e, actual_time);
@@ -671,57 +682,134 @@ void Item_ScheduleInitialRespawn(entity e)
        Item_ScheduleRespawnIn(e, max(0, game_starttime - time) + ((e.respawntimestart) ? e.respawntimestart : ITEM_RESPAWNTIME_INITIAL(e)));
 }
 
-void GivePlayerResource(entity player, .float resource_type, float amount)
+int GetResourceType(.float resource_property)
+{
+       switch (resource_property)
+       {
+               case health: { return RESOURCE_HEALTH; }
+               case armorvalue: { return RESOURCE_ARMOR; }
+               case ammo_shells: { return RESOURCE_SHELLS; }
+               case ammo_nails: { return RESOURCE_BULLETS; }
+               case ammo_rockets: { return RESOURCE_ROCKETS; }
+               case ammo_cells: { return RESOURCE_CELLS; }
+               case ammo_plasma: { return RESOURCE_PLASMA; }
+               case ammo_fuel: { return RESOURCE_FUEL; }
+       }
+       error("GetResourceType: Invalid property.");
+       return 0;
+}
+
+.float GetResourceProperty(int resource_type)
+{
+       switch (resource_type)
+       {
+               case RESOURCE_HEALTH: { return health; }
+               case RESOURCE_ARMOR: { return armorvalue; }
+               case RESOURCE_SHELLS: { return ammo_shells; }
+               case RESOURCE_BULLETS: { return ammo_nails; }
+               case RESOURCE_ROCKETS: { return ammo_rockets; }
+               case RESOURCE_CELLS: { return ammo_cells; }
+               case RESOURCE_PLASMA: { return ammo_plasma; }
+               case RESOURCE_FUEL: { return ammo_fuel; }
+       }
+       error("GetResourceProperty: Invalid resource type.");
+       return health;
+}
+
+float GetResourceLimit(int resource_type)
+{
+       float limit;
+       switch (resource_type)
+       {
+               case RESOURCE_HEALTH:
+               {
+                       limit = autocvar_g_balance_health_limit;
+                       break;
+               }
+               case RESOURCE_ARMOR:
+               {
+                       limit = autocvar_g_balance_armor_limit;
+                       break;
+               }
+               case RESOURCE_SHELLS:
+               {
+                       limit = g_pickup_shells_max;
+                       break;
+               }
+               case RESOURCE_BULLETS:
+               {
+                       limit = g_pickup_nails_max;
+                       break;
+               }
+               case RESOURCE_ROCKETS:
+               {
+                       limit = g_pickup_rockets_max;
+                       break;
+               }
+               case RESOURCE_CELLS:
+               {
+                       limit = g_pickup_cells_max;
+                       break;
+               }
+               case RESOURCE_PLASMA:
+               {
+                       limit = g_pickup_plasma_max;
+                       break;
+               }
+               case RESOURCE_FUEL:
+               {
+                       limit = autocvar_g_balance_fuel_limit;
+                       break;
+               }
+               default:
+               {
+                       error("GetResourceLimit: Invalid resource type.");
+                       return 0;
+               }
+       }
+       MUTATOR_CALLHOOK(GetResourceLimit, resource_type, limit);
+       limit = M_ARGV(1, float);
+       if (limit > RESOURCE_AMOUNT_HARD_LIMIT)
+       {
+               limit = RESOURCE_AMOUNT_HARD_LIMIT;
+       }
+       return limit;
+}
+
+void GivePlayerResource(entity player, int resource_type, float amount)
 {
        if (amount == 0)
        {
                return;
        }
+       bool forbid = MUTATOR_CALLHOOK(GivePlayerResource, player, resource_type,
+               amount);
+       if (forbid)
+       {
+               return;
+       }
+       resource_type = M_ARGV(1, int);
+       amount = M_ARGV(2, float);
+       .float resource_property = GetResourceProperty(resource_type);
+       float max_amount = GetResourceLimit(resource_type);
+       player.(resource_property) = bound(player.(resource_property),
+               player.(resource_property) + amount, max_amount);
        switch (resource_type)
        {
-               case health:
+               case RESOURCE_HEALTH:
                {
-                       // Ugly hack. We do not check if health goes beyond hard limit since
-                       // currently it is done in player_regen. We need to bring back this
-                       // check when other code is ported to this function.
-                       player.health = bound(player.health, player.health + amount,
-                               autocvar_g_balance_health_limit);
-                       // Correct code:
-                       //player.health = bound(player.health, player.health + amount,
-                       //      min(autocvar_g_balance_health_limit,
-                       //      RESOURCE_AMOUNT_HARD_LIMIT));
                        player.pauserothealth_finished = max(player.pauserothealth_finished,
                                time + autocvar_g_balance_pause_health_rot);
                        return;
                }
-               case armorvalue:
+               case RESOURCE_ARMOR:
                {
-                       // Ugly hack. We do not check if armor goes beyond hard limit since
-                       // currently it is done in player_regen. We need to bring back this
-                       // check when other code is ported to this function.
-                       player.armorvalue = bound(player.armorvalue, player.armorvalue +
-                               amount, autocvar_g_balance_armor_limit);
-                       // Correct code:
-                       //player.armorvalue = bound(player.armorvalue, player.armorvalue +
-                       //      amount, min(autocvar_g_balance_armor_limit,
-                       //      RESOURCE_AMOUNT_HARD_LIMIT));
                        player.pauserotarmor_finished = max(player.pauserotarmor_finished,
                                time + autocvar_g_balance_pause_armor_rot);
                        return;
                }
-               case ammo_shells:
-               case ammo_nails:
-               case ammo_rockets:
-               case ammo_cells:
-               case ammo_plasma:
-               {
-                       GivePlayerAmmo(player, resource_type, amount);
-                       return;
-               }
-               case ammo_fuel:
+               case RESOURCE_FUEL:
                {
-                       player.ammo_fuel = bound(player.ammo_fuel, player.ammo_fuel +
-                               amount, min(g_pickup_fuel_max, RESOURCE_AMOUNT_HARD_LIMIT));
                        player.pauserotfuel_finished = max(player.pauserotfuel_finished,
                                time + autocvar_g_balance_pause_fuel_rot);
                        return;
@@ -729,58 +817,106 @@ void GivePlayerResource(entity player, .float resource_type, float amount)
        }
 }
 
+void GivePlayerResourceViaProperty(entity player, .float resource_property,
+       float amount)
+{
+       GivePlayerResource(player, GetResourceType(resource_property), amount);
+}
+
 void GivePlayerHealth(entity player, float amount)
 {
-       GivePlayerResource(player, health, amount);
+       GivePlayerResource(player, RESOURCE_HEALTH, amount);
 }
 
 void GivePlayerArmor(entity player, float amount)
 {
-       GivePlayerResource(player, armorvalue, amount);
+       GivePlayerResource(player, RESOURCE_ARMOR, amount);
 }
 
-void GivePlayerAmmo(entity player, .float ammotype, float amount)
+void GivePlayerFuel(entity player, float amount)
 {
-       if (amount == 0)
+       GivePlayerResource(player, RESOURCE_FUEL, amount);
+}
+
+void GivePlayerRandomWeapons(entity player, int num_weapons,
+       string weapon_names, float shells, float bullets, float rockets,
+       float cells, float plasma)
+{
+       if (num_weapons == 0)
        {
                return;
        }
-       float maxvalue = RESOURCE_AMOUNT_HARD_LIMIT;
-       switch (ammotype)
+       int num_potential_weapons = tokenize_console(weapon_names);
+       for (int i = 0; i < num_weapons; ++i)
        {
-               case ammo_shells:
-               {
-                       maxvalue = g_pickup_shells_max;
-                       break;
-               }
-               case ammo_cells:
-               {
-                       maxvalue = g_pickup_cells_max;
-                       break;
-               }
-               case ammo_rockets:
+               RandomSelection_Init();
+               for (int j = 0; j < num_potential_weapons; ++j)
                {
-                       maxvalue = g_pickup_rockets_max;
-                       break;
+                       string weapon = argv(j);
+                       FOREACH(Weapons, it != WEP_Null,
+                       {
+                               // Finding a weapon which player doesn't have.
+                               if (!(player.weapons & it.m_wepset) && (it.netname == weapon))
+                               {
+                                       RandomSelection_AddEnt(it, 1, 1);
+                                       break;
+                               }
+                       });
                }
-               case ammo_plasma:
+               if (RandomSelection_chosen_ent == NULL)
                {
-                       maxvalue = g_pickup_plasma_max;
-                       break;
+                       return;
                }
-               case ammo_nails:
+               player.weapons |= RandomSelection_chosen_ent.m_wepset;
+               switch (RandomSelection_chosen_ent.ammo_field)
                {
-                       maxvalue = g_pickup_nails_max;
-                       break;
+                       case (ammo_shells):
+                       {
+                               if (player.ammo_shells != 0)
+                               {
+                                       break;
+                               }
+                               GivePlayerAmmo(player, ammo_shells, shells);
+                               break;
+                       }
+                       case (ammo_nails):
+                       {
+                               if (player.ammo_nails != 0)
+                               {
+                                       break;
+                               }
+                               GivePlayerAmmo(player, ammo_nails, bullets);
+                               break;
+                       }
+                       case (ammo_rockets):
+                       {
+                               if (player.ammo_rockets != 0)
+                               {
+                                       break;
+                               }
+                               GivePlayerAmmo(player, ammo_rockets, rockets);
+                               break;
+                       }
+                       case (ammo_cells):
+                       {
+                               if (player.ammo_cells != 0)
+                               {
+                                       break;
+                               }
+                               GivePlayerAmmo(player, ammo_cells, cells);
+                               break;
+                       }
+                       case (ammo_plasma):
+                       {
+                               if (player.ammo_plasma != 0)
+                               {
+                                       break;
+                               }
+                               GivePlayerAmmo(player, ammo_plasma, plasma);
+                               break;
+                       }
                }
        }
-       player.(ammotype) = min(player.(ammotype) + amount,
-               min(maxvalue, RESOURCE_AMOUNT_HARD_LIMIT));
-}
-
-void GivePlayerFuel(entity player, float amount)
-{
-       GivePlayerResource(player, ammo_fuel, amount);
 }
 
 float Item_GiveAmmoTo(entity item, entity player, .float ammotype, float ammomax)
@@ -797,7 +933,7 @@ float Item_GiveAmmoTo(entity item, entity player, .float ammotype, float ammomax
                        {
                                amount = ammomax - player.(ammotype);
                        }
-                       GivePlayerResource(player, ammotype, amount);
+                       GivePlayerResourceViaProperty(player, ammotype, amount);
                        return true;
                }
        }
@@ -806,7 +942,8 @@ float Item_GiveAmmoTo(entity item, entity player, .float ammotype, float ammomax
                float mi = min(item.(ammotype), ammomax);
                if (player.(ammotype) < mi)
                {
-                       GivePlayerResource(player, ammotype, mi - player.(ammotype));
+                       GivePlayerResourceViaProperty(player, ammotype, mi -
+                               player.(ammotype));
                }
                return true;
        }