share/hedgewars/Data/Scripts/Multiplayer/Balanced_Random_Weapon.lua
changeset 13718 6d57f5f61c09
parent 13173 4d1cf0d76eb7
child 13719 ed22eb551a75
--- a/share/hedgewars/Data/Scripts/Multiplayer/Balanced_Random_Weapon.lua	Wed Aug 29 03:50:53 2018 +0200
+++ b/share/hedgewars/Data/Scripts/Multiplayer/Balanced_Random_Weapon.lua	Thu Aug 30 22:07:01 2018 +0200
@@ -1,22 +1,59 @@
+--[[
+Balanced Random Weapon
+
+Every turn, each hog gets 1-3 random weapons. Weapons are reset every turn.
+
+= CUSTOMIZATION =
+The weapon chances are chosen with the weapons scheme.
+
+The "ammo count" tab is used to set the probability level that you get
+equipped with the ammo at the start of a turn:
+
+* infinity = always get this weapon
+* 3-8 bullets = high probability (more bullets don't make it more likely)
+* 2 bullets = medium probability
+* 1 bullet = low probability
+* 0 bullets = never
+
+For utilities, the low and medium probabilities are the same.
+
+The "probabilities" tab is, as usual, for crate probabilities.
+The "ammo in crate" and "delay" tabs also work as expected.
+]]
+
 HedgewarsScriptLoad("/Scripts/Locale.lua")
 HedgewarsScriptLoad("/Scripts/Tracker.lua")
 
-local weapons = { amGrenade, amClusterBomb, amBazooka, amBee, amShotgun, amMine, amDEagle, amDynamite, amFirePunch, amWhip, amPickHammer, amBaseballBat, amMortar, amCake, amSeduction, amWatermelon, amHellishBomb, amDrill, amBallgun, amRCPlane, amSniperRifle, amMolotov, amBirdy, amBlowTorch, amGasBomb, amFlamethrower, amSMine, amKamikaze, amMinigun, amAirMine, amKnife }
-
---                      G,C,B,B,S,M,D,D,F,W,P,B,M,C,S,W,H,D,B,R,S,M,B,B,G,F,S,K,M,A,K
-local weapons_values = {1,1,1,2,1,1,1,2,1,1,1,2,1,3,1,3,3,2,3,3,1,1,2,1,1,2,2,1,3,1,2}
-
-local airweapons = { amAirAttack, amMineStrike, amNapalm, amDrillStrike }
+local weapons = {}
+local weapons_values = {}
+local airweapons = {}
+local airweapons_values = {}
+local utilities = {}
+local utilities_values = {}
 
---                         A,M,N,D
-local airweapons_values = {2,2,2,2}
-
-local utilities = { amTeleport, amGirder, amSwitch, amLowGravity, amResurrector, amRope, amParachute, amJetpack, amPortalGun, amSnowball }
-
---                        T,G,S,L,R,R,P,J,P,S
-local utilities_values = {1,2,2,1,2,2,1,2,2,2}
+local isUtility, isAirWeapon
 
 function randomAmmo()
+--[[
+= WEAPON SELECTION ALGORITHM =
+Each turn, a team gets 3 "points". Each ammo that has been activated
+has a "cost" of 1-3 which is derived from the ammo probability specified
+from the ammo menu (see getCost).
+Utilities are forced to have a cost of 1-2.
+
+Steps:
+1. Add a random weapon to ammo and subtract cost
+2. If there's still points left:
+    a. Forget any item in mind
+    b. Choose a random weapon and keep it in mind (but don't add it to the ammo yet)
+    c. Choose a random utility and keep it in mind (but don't add it to the ammo yet)
+    d. Forget any items which are either too expensive or have already been taken by this hedgehog
+    e. Randomly add one of the items which are still in mind to the hedgehog's ammo and substract cost
+    f. Return to step 2
+
+If 0 points are left, the algorithm terminates.
+]]
+
     local n = 3   --"points" to be allocated on weapons
 
     --pick random weapon and subtract cost
@@ -96,16 +133,68 @@
     DisableGameFlags(gfPerHogAmmo)
     EnableGameFlags(gfResetWeps)
     Goals = loc("Each turn you get 1-3 random weapons")
+
+    isUtility = {
+        [amTeleport] = true,
+        [amGirder] = true,
+        [amSwitch] = true,
+        [amLowGravity] = true,
+        [amResurrector] = true,
+        [amRope] = true,
+        [amParachute] = true,
+        [amJetpack] = true,
+        [amPortalGun] = true,
+        [amRubber] = true,
+        [amTardis] = true,
+        [amLandGun] = true,
+        [amExtraTime] = true,
+        [amVampiric] = true,
+        [amLaserSight] = true,
+        [amExtraDamage] = true,
+        [amInvulnerable] = true,
+
+        -- unusual classification
+        [amSnowball] = true,
+    }
+
+    isAirWeapon = {
+        [amAirAttack] = true,
+        [amMineStrike] = true,
+        [amNapalm] = true,
+        [amDrillStrike] = true,
+        [amPiano] = true,
+    }
+
+end
+
+local function getCost(ammoType, ammoCount)
+    if ammoCount == 0 or ammoCount == 9 then
+        return 0
+    else
+        local max
+        if isUtility[ammoType] then
+            -- Force-limit cost of utilities to 2 because utilities with
+            -- a cost of 3 could never be "paid"
+            max = 2
+        else
+            max = 3
+        end
+        return math.max(1, math.min(max, 4 - ammoCount))
+    end
 end
 
 function onGameStart()
     trackTeams()
     if MapHasBorder() == false then
-        for i, w in pairs(airweapons) do
-            table.insert(weapons, w)
-        end
-        for i, w in pairs(airweapons_values) do
-            table.insert(weapons_values, w)
+        for a = 0, AmmoTypeMax do
+            if a ~= amNothing and a ~= amSkip then
+                local ammoCount = GetAmmo(a)
+                local cost = getCost(a, ammoCount)
+                if cost > 0 and isAirWeapon[a] then
+                    table.insert(airweapons, a)
+                    table.insert(airweapons_values, cost)
+                end
+            end
         end
     end
 end
@@ -113,22 +202,31 @@
 function onAmmoStoreInit()
     SetAmmo(amSkip, 9, 0, 0, 0)
 
-    SetAmmo(amExtraDamage, 0, 1, 0, 1)
-    SetAmmo(amInvulnerable, 0, 1, 0, 1)
-    SetAmmo(amExtraTime, 0, 1, 0, 1)
-    SetAmmo(amLaserSight, 0, 1, 0, 1)
-    SetAmmo(amVampiric, 0, 1, 0, 1)
-
-    for i, w in pairs(utilities) do
-        SetAmmo(w, 0, 0, 0, 1)
-    end
-
-    for i, w in pairs(weapons) do
-        SetAmmo(w, 0, 0, 0, 1)
-    end
-
-    for i, w in pairs(airweapons) do
-        SetAmmo(w, 0, 0, 0, 1)
+    for a=0, AmmoTypeMax do
+        if a ~= amNothing and a ~= amSkip then
+            local ammoCount, prob, delay, ammoInCrate = GetAmmo(a)
+            local cost = getCost(a, ammoCount)
+            if (not isAirWeapon[a]) then
+                if cost > 0 then
+                    if isUtility[a] then
+                        table.insert(utilities, a)
+                        table.insert(utilities, cost)
+                    else
+                        table.insert(weapons, a)
+                        table.insert(weapons_values, cost)
+                    end
+                end
+            else
+                prob = 0
+            end
+            local realAmmoCount
+            if ammoCount ~= 9 then
+                realAmmoCount = 0
+            else
+                realAmmoCount = 1
+            end
+            SetAmmo(a, realAmmoCount, prob, delay, ammoInCrate)
+        end
     end
 end