]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/common/t_items.qc
Merge branch 'master' into terencehill/bot_AI_improvements
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / t_items.qc
index a121d1568358846d2d05f88f32b176b10e991a38..f295c1da3eaa092bf1cf4dba4d756b4338369b48 100644 (file)
@@ -22,6 +22,8 @@
 
     #include <common/weapons/_all.qh>
 
+    #include <common/mutators/mutator/buffs/buffs.qh>
+
     #include "../lib/warpzone/util_server.qh"
 #elif defined(CSQC)
        #include "physics/movetypes/movetypes.qh"
@@ -957,7 +959,16 @@ float weapon_pickupevalfunc(entity player, entity item)
                        return 0;
                return ammo_pickupevalfunc(player, item);
        }
-       return item.bot_pickupbasevalue;
+
+       // reduce weapon value if bot already got a good arsenal
+       float c = 1;
+       int weapons_value = 0;
+       FOREACH(Weapons, it != WEP_Null && (player.weapons & it.m_wepset), {
+               weapons_value += it.bot_pickupbasevalue;
+       });
+       c -= bound(0, weapons_value / 20000, 1) * 0.5;
+
+       return item.bot_pickupbasevalue * c;
 }
 
 float ammo_pickupevalfunc(entity player, entity item)
@@ -1028,26 +1039,34 @@ float ammo_pickupevalfunc(entity player, entity item)
        if (player.ammo_fuel < g_pickup_fuel_max)
                c = item.ammo_fuel / player.ammo_fuel;
 
-       rating *= min(3, 1 + c);
+       rating *= min(2, c);
        if(wpn)
-               // Skilled bots will grab more
-               rating += wpn.bot_pickupbasevalue * (0.1 + 0.1 * bound(0, skill / 10, 1));
+               rating += wpn.bot_pickupbasevalue * 0.1;
        return rating;
 }
 
+.int item_group;
+.int item_group_count;
 float healtharmor_pickupevalfunc(entity player, entity item)
 {
        float c = 0;
        float rating = item.bot_pickupbasevalue;
 
-       if (item.armorvalue)
+       float itemarmor = item.armorvalue;
+       float itemhealth = item.health;
+       if(item.item_group)
+       {
+               itemarmor *= min(4, item.item_group_count);
+               itemhealth *= min(4, item.item_group_count);
+       }
+       if (itemarmor)
        if (player.armorvalue < item.max_armorvalue)
-               c = item.armorvalue / (max(1, player.armorvalue + player.health));
-       if (item.health)
+               c = itemarmor / max(1, player.armorvalue * 2/3 + player.health * 1/3);
+       if (itemhealth)
        if (player.health < item.max_health)
-               c = item.health / max(1, player.health);
+               c = itemhealth / max(1, player.health);
 
-       rating *= min(3, 1 + c);
+       rating *= min(2, c);
        return rating;
 }
 
@@ -1083,6 +1102,9 @@ void _StartItem(entity this, entity def, float defaultrespawntime, float default
                this.respawntimejitter = defaultrespawntimejitter;
        }
 
+       if(!this.pickup_anyway && def.m_pickupanyway)
+               this.pickup_anyway = def.m_pickupanyway();
+
        int itemid = def.m_itemid;
        this.items = itemid;
        int weaponid = def.instanceOfWeaponPickup ? def.m_weapon.m_id : 0;
@@ -1266,6 +1288,8 @@ void _StartItem(entity this, entity def, float defaultrespawntime, float default
                delete(this);
                return;
        }
+
+       setItemGroup(this);
 }
 
 void StartItem(entity this, GameItem def)
@@ -1278,12 +1302,58 @@ void StartItem(entity this, GameItem def)
        );
 }
 
+#define IS_SMALL(def) ((def.instanceOfHealth && def == ITEM_HealthSmall) || (def.instanceOfArmor && def == ITEM_ArmorSmall))
+int group_count = 1;
+
+void setItemGroup(entity this)
+{
+       if(!IS_SMALL(this.itemdef))
+               return;
+
+       FOREACH_ENTITY_RADIUS(this.origin, 120, (it != this) && IS_SMALL(it.itemdef),
+       {
+               if(!this.item_group)
+               {
+                       if(!it.item_group)
+                       {
+                               it.item_group = group_count;
+                               group_count++;
+                       }
+                       this.item_group = it.item_group;
+               }
+               else // spawning item is already part of a item_group X
+               {
+                       if(!it.item_group)
+                               it.item_group = this.item_group;
+                       else if(it.item_group != this.item_group) // found an item near the spawning item that is part of a different item_group Y
+                       {
+                               int grY = it.item_group;
+                               // move all items of item_group Y to item_group X
+                               FOREACH_ENTITY(IS_SMALL(it.itemdef),
+                               {
+                                       if(it.item_group == grY)
+                                               it.item_group = this.item_group;
+                               });
+                       }
+               }
+       });
+}
+
+void setItemGroupCount()
+{
+       for (int k = 1; k <= group_count; k++)
+       {
+               int count = 0;
+               FOREACH_ENTITY(IS_SMALL(it.itemdef) && it.item_group == k, { count++; });
+               if (count)
+                       FOREACH_ENTITY(IS_SMALL(it.itemdef) && it.item_group == k, { it.item_group_count = count; });
+       }
+}
+
 spawnfunc(item_rockets)
 {
        if(!this.ammo_rockets)
                this.ammo_rockets = g_pickup_rockets;
-       if(!this.pickup_anyway)
-               this.pickup_anyway = g_pickup_ammo_anyway;
     StartItem(this, ITEM_Rockets);
 }
 
@@ -1301,8 +1371,6 @@ spawnfunc(item_bullets)
 
        if(!this.ammo_nails)
                this.ammo_nails = g_pickup_nails;
-       if(!this.pickup_anyway)
-               this.pickup_anyway = g_pickup_ammo_anyway;
     StartItem(this, ITEM_Bullets);
 }
 
@@ -1310,8 +1378,6 @@ spawnfunc(item_cells)
 {
        if(!this.ammo_cells)
                this.ammo_cells = g_pickup_cells;
-       if(!this.pickup_anyway)
-               this.pickup_anyway = g_pickup_ammo_anyway;
        StartItem(this, ITEM_Cells);
 }
 
@@ -1319,8 +1385,6 @@ spawnfunc(item_plasma)
 {
        if(!this.ammo_plasma)
                this.ammo_plasma = g_pickup_plasma;
-       if(!this.pickup_anyway)
-               this.pickup_anyway = g_pickup_ammo_anyway;
        StartItem(this, ITEM_Plasma);
 }
 
@@ -1338,8 +1402,6 @@ spawnfunc(item_shells)
 
        if(!this.ammo_shells)
                this.ammo_shells = g_pickup_shells;
-       if(!this.pickup_anyway)
-               this.pickup_anyway = g_pickup_ammo_anyway;
        StartItem(this, ITEM_Shells);
 }
 
@@ -1349,8 +1411,6 @@ spawnfunc(item_armor_small)
                this.armorvalue = g_pickup_armorsmall;
        if(!this.max_armorvalue)
                this.max_armorvalue = g_pickup_armorsmall_max;
-       if(!this.pickup_anyway)
-               this.pickup_anyway = g_pickup_armorsmall_anyway;
        StartItem(this, ITEM_ArmorSmall);
 }
 
@@ -1360,8 +1420,6 @@ spawnfunc(item_armor_medium)
                this.armorvalue = g_pickup_armormedium;
        if(!this.max_armorvalue)
                this.max_armorvalue = g_pickup_armormedium_max;
-       if(!this.pickup_anyway)
-               this.pickup_anyway = g_pickup_armormedium_anyway;
        StartItem(this, ITEM_ArmorMedium);
 }
 
@@ -1371,8 +1429,6 @@ spawnfunc(item_armor_big)
                this.armorvalue = g_pickup_armorbig;
        if(!this.max_armorvalue)
                this.max_armorvalue = g_pickup_armorbig_max;
-       if(!this.pickup_anyway)
-               this.pickup_anyway = g_pickup_armorbig_anyway;
        StartItem(this, ITEM_ArmorBig);
 }
 
@@ -1382,8 +1438,6 @@ spawnfunc(item_armor_mega)
                this.armorvalue = g_pickup_armormega;
        if(!this.max_armorvalue)
                this.max_armorvalue = g_pickup_armormega_max;
-       if(!this.pickup_anyway)
-               this.pickup_anyway = g_pickup_armormega_anyway;
        StartItem(this, ITEM_ArmorMega);
 }
 
@@ -1393,8 +1447,6 @@ spawnfunc(item_health_small)
                this.max_health = g_pickup_healthsmall_max;
        if(!this.health)
                this.health = g_pickup_healthsmall;
-       if(!this.pickup_anyway)
-               this.pickup_anyway = g_pickup_healthsmall_anyway;
        StartItem(this, ITEM_HealthSmall);
 }
 
@@ -1404,8 +1456,6 @@ spawnfunc(item_health_medium)
                this.max_health = g_pickup_healthmedium_max;
        if(!this.health)
                this.health = g_pickup_healthmedium;
-       if(!this.pickup_anyway)
-               this.pickup_anyway = g_pickup_healthmedium_anyway;
     StartItem(this, ITEM_HealthMedium);
 }
 
@@ -1415,8 +1465,6 @@ spawnfunc(item_health_big)
                this.max_health = g_pickup_healthbig_max;
        if(!this.health)
                this.health = g_pickup_healthbig;
-       if(!this.pickup_anyway)
-               this.pickup_anyway = g_pickup_healthbig_anyway;
        StartItem(this, ITEM_HealthBig);
 }
 
@@ -1426,8 +1474,6 @@ spawnfunc(item_health_mega)
         this.max_health = g_pickup_healthmega_max;
     if(!this.health)
         this.health = g_pickup_healthmega;
-    if(!this.pickup_anyway)
-        this.pickup_anyway = g_pickup_healthmega_anyway;
     StartItem(this, ITEM_HealthMega);
 }
 
@@ -1516,6 +1562,15 @@ spawnfunc(target_items)
                        else if(argv(j) == "fuel_regen")             this.items |= ITEM_JetpackRegen.m_itemid;
                        else
                        {
+                               FOREACH(Buffs, it != BUFF_Null,
+                               {
+                                       s = Buff_UndeprecateName(argv(j));
+                                       if(s == it.m_name)
+                                       {
+                                               this.buffs |= (it.m_itemid);
+                                               break;
+                                       }
+                               });
                                FOREACH(Weapons, it != WEP_Null, {
                                        s = W_UndeprecateName(argv(j));
                                        if(s == it.netname)
@@ -1572,6 +1627,7 @@ spawnfunc(target_items)
                if(this.ammo_fuel != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.ammo_fuel), "fuel");
                if(this.health != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.health), "health");
                if(this.armorvalue != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.armorvalue), "armor");
+               FOREACH(Buffs, it != BUFF_Null, this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, !!(this.buffs & (it.m_itemid)), it.m_name));
                FOREACH(Weapons, it != WEP_Null, this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, !!(this.weapons & (it.m_wepset)), it.netname));
        }
        this.netname = strzone(this.netname);
@@ -1591,8 +1647,6 @@ spawnfunc(item_fuel)
 {
        if(!this.ammo_fuel)
                this.ammo_fuel = g_pickup_fuel;
-       if(!this.pickup_anyway)
-               this.pickup_anyway = g_pickup_ammo_anyway;
        StartItem(this, ITEM_JetpackFuel);
 }
 
@@ -1649,6 +1703,35 @@ float GiveWeapon(entity e, float wpn, float op, float val)
        return (v0 != v1);
 }
 
+bool GiveBuff(entity e, Buff thebuff, int op, int val)
+{
+       bool had_buff = (e.buffs & thebuff.m_itemid);
+       switch(op)
+       {
+               case OP_SET:
+                       if(val > 0)
+                               e.buffs |= thebuff.m_itemid;
+                       else
+                               e.buffs &= ~thebuff.m_itemid;
+                       break;
+               case OP_MIN:
+               case OP_PLUS:
+                       if(val > 0)
+                               e.buffs |= thebuff.m_itemid;
+                       break;
+               case OP_MAX:
+                       if(val <= 0)
+                               e.buffs &= ~thebuff.m_itemid;
+                       break;
+               case OP_MINUS:
+                       if(val > 0)
+                               e.buffs &= ~thebuff.m_itemid;
+                       break;
+       }
+       bool have_buff = (e.buffs & thebuff.m_itemid);
+       return (had_buff != have_buff);
+}
+
 void GiveSound(entity e, float v0, float v1, float t, Sound snd_incr, Sound snd_decr)
 {
        if(v1 == v0)
@@ -1752,6 +1835,8 @@ float GiveItems(entity e, float beginarg, float endarg)
                                got += GiveValue(e, armorvalue, op, val);
                        case "allweapons":
                                FOREACH(Weapons, it != WEP_Null && !(it.spawnflags & WEP_FLAG_MUTATORBLOCKED), got += GiveWeapon(e, it.m_id, op, val));
+                       //case "allbuffs": // all buffs makes a player god, do not want!
+                               //FOREACH(Buffs, it != BUFF_Null, got += GiveBuff(e, it.m_itemid, op, val));
                        case "allammo":
                                got += GiveValue(e, ammo_cells, op, val);
                                got += GiveValue(e, ammo_plasma, op, val);
@@ -1810,6 +1895,11 @@ float GiveItems(entity e, float beginarg, float endarg)
                                got += GiveValue(e, ammo_fuel, op, val);
                                break;
                        default:
+                               FOREACH(Buffs, it != BUFF_Null && Buff_UndeprecateName(cmd) == it.m_name,
+                               {
+                                       got += GiveBuff(e, it, op, val);
+                                       break;
+                               });
                                FOREACH(Weapons, it != WEP_Null && W_UndeprecateName(cmd) == it.netname, {
                     got += GiveWeapon(e, it.m_id, op, val);
                     break;