-- buyrobot_adrian_test.lua -- Menu de compra e controle do Heavy "Heavy weapons money". -- Carregado pelo popfile com LuaScriptFile. local BUY_COST = 17560 local MAX_ACTIVE_HEAVIES = 1 local HEAVY_LIFETIME = 650 local WAVESPAWN_NAME = "buyrobot_wave" local HEAVY_NAME = "Heavy weapons money" local HEAVY_TAG = "buyrobot_money_heavy" local HEAVY_WEAPON_NAME = "Natascha" local TELEPORTER_NAME = "buyrobot_teleporter" local KIOSK_TRIGGER_NAME = "buyrobot_trigger" local REPROGRAMMED_CONDITION = 43 local activeHeavies = {} local zombieDamageCallbacks = {} local purchasePending = false local waveActive = false local spinAngle = 0 local trackHeavy local function countActiveHeavies() local stale = {} local alive = 0 for handle, bot in pairs(activeHeavies) do if not IsValid(bot) or not bot:IsAlive() then stale[#stale + 1] = handle else alive = alive + 1 end end for _, handle in ipairs(stale) do activeHeavies[handle] = nil end return alive end local function setKioskEnabled(enabled) local trigger = ents.FindByName(KIOSK_TRIGGER_NAME) if IsValid(trigger) then trigger:AcceptInput(enabled and "Enable" or "Disable") end end local function printHeavyLimit(player) player:Print(2, "There is already 1 living Heavy weapons money; limit reached.") end local function hasTag(tags, wanted) if type(tags) ~= "table" then return false end for _, tag in ipairs(tags) do if tag == wanted then return true end end return false end local function isHeavyName(bot) if not IsValid(bot) then return false end local netname = bot.m_szNetname if type(netname) == "string" and netname:find(HEAVY_NAME, 1, true) then return true end local playername = bot:GetPlayerName() return type(playername) == "string" and playername:find(HEAVY_NAME, 1, true) ~= nil end local function resetBuyRobotState() activeHeavies = {} purchasePending = false waveActive = false setKioskEnabled(false) end local function wavespawnInput(inputName) local populator = ents.FindByName("populator") if populator and IsValid(populator) then populator:AcceptInput(inputName, WAVESPAWN_NAME) end end function BuyRobot_PauseWavespawn() wavespawnInput("$PauseWavespawn") if not purchasePending then return end timer.Simple(0.2, function() if not purchasePending then return end for _, player in pairs(ents.GetAllPlayers()) do if player:IsBot() and isHeavyName(player) then trackHeavy(player) return end end end) end local function spinTeleporter() local teleporters = ents.FindAllByName(TELEPORTER_NAME .. "*") if #teleporters == 0 then local fallback = ents.FindByName(TELEPORTER_NAME) if IsValid(fallback) then teleporters = { fallback } end end spinAngle = (spinAngle + 3) % 360 for _, teleporter in pairs(teleporters) do if IsValid(teleporter) then teleporter:SetAbsAngles(Vector(0, spinAngle, 0)) end end end function BuyRobot_Purchase(player) if not IsValid(player) or not player:IsRealPlayer() then return end if not player:IsAlive() then player:Print(2, "You must be alive to buy a robot.") return end if not waveActive then player:Print(2, "The Buy Robot kiosk is disabled until the wave starts.") return end local alive = countActiveHeavies() if alive >= MAX_ACTIVE_HEAVIES then printHeavyLimit(player) return end if purchasePending then player:Print(2, "A Heavy weapons money purchase is already pending.") return end if player.m_nCurrency < BUY_COST then player:Print(2, "You need " .. BUY_COST .. " currency to buy Heavy weapons money.") return end player:AcceptInput("$RemoveCurrency", tostring(BUY_COST)) purchasePending = true wavespawnInput("$ResumeWavespawn") for _, other in pairs(ents.GetAllPlayers()) do if other:IsRealPlayer() then other:DisplayTextChat( "\x07FF0000" .. player:GetPlayerName() .. " \x01has purchased \x07ffdd001\x01 Heavy weapons money for \x07ffdd00" .. BUY_COST .. "\x01 currency!" ) end end end function BuyRobot_OpenMenu(param, activator) if not IsValid(activator) or not activator:IsRealPlayer() then return end if not activator:IsAlive() then activator:Print(2, "You must be alive to use the Buy Robot kiosk.") return end if not waveActive then activator:Print(2, "The Buy Robot kiosk is disabled until the wave starts.") return end local alive = countActiveHeavies() if alive >= MAX_ACTIVE_HEAVIES then printHeavyLimit(activator) return end local menu = { timeout = 0, title = "Buy Robot", itemsPerPage = 10, flags = MENUFLAG_BUTTON_EXIT, onSelect = function(player, index, value) if IsValid(player) then player:HideMenu() end if value == "buy" and IsValid(player) then BuyRobot_Purchase(player) end end, onCancel = nil, } table.insert(menu, { text = "Buy Heavy weapons money for 17560 currency?", value = "info1", disabled = true, }) table.insert(menu, { text = "Description: Normal Heavy with Natascha and Vampire rune. Zombies ignore him.", value = "info2", disabled = true, }) table.insert(menu, { text = "Lasts 650 seconds. Each Natascha hit gives every player 1-145 currency.", value = "info3", disabled = true, }) if purchasePending then table.insert(menu, { text = "Heavy purchase pending...", value = "status", disabled = true, }) elseif alive > 0 then table.insert(menu, { text = "Active Heavies: " .. alive .. "/" .. MAX_ACTIVE_HEAVIES .. ". Limit reached.", value = "status", disabled = true, }) end table.insert(menu, { text = "Buy Heavy weapons money for 17560 currency?", value = "buy", disabled = alive > 0 or purchasePending, }) activator:DisplayMenu(menu) end trackHeavy = function(bot) if not IsValid(bot) then return false end local handle = bot:GetHandleIndex() if activeHeavies[handle] then return true end activeHeavies[handle] = bot purchasePending = false bot:AddCallback(ON_DEATH, function() activeHeavies[handle] = nil end) wavespawnInput("$PauseWavespawn") timer.Simple(HEAVY_LIFETIME, function() if IsValid(bot) and bot:IsAlive() then bot:Suicide() end end) return true end local function attachZombieMoneyCallback(zombie) if not IsValid(zombie) or not zombie:IsBot() or zombie.m_iTeamNum ~= 3 then return end if isHeavyName(zombie) or zombie:InCond(REPROGRAMMED_CONDITION) then return end local handle = zombie:GetHandleIndex() if zombieDamageCallbacks[handle] then return end local damageCallback damageCallback = zombie:AddCallback(ON_DAMAGE_RECEIVED_PRE, function(_, damageInfo) if not damageInfo or not damageInfo.Damage or damageInfo.Damage <= 0 then return end local attacker = damageInfo.Attacker if not IsValid(attacker) or not attacker:IsBot() then return end if activeHeavies[attacker:GetHandleIndex()] == nil and not isHeavyName(attacker) then return end local weapon = damageInfo.Weapon if IsValid(weapon) then local weaponName = weapon:GetItemName() if type(weaponName) == "string" and weaponName:find(HEAVY_WEAPON_NAME, 1, true) == nil then return end end for _, player in pairs(ents.GetAllPlayers()) do if IsValid(player) and player:IsRealPlayer() then player:AddCurrency(math.random(1, 145)) end end end) zombieDamageCallbacks[handle] = damageCallback local function clearDamageCallback() zombieDamageCallbacks[handle] = nil if IsValid(zombie) and damageCallback then zombie:RemoveCallback(damageCallback) end end zombie:AddCallback(ON_DEATH, clearDamageCallback) zombie:AddCallback(ON_REMOVE, clearDamageCallback) end AddGlobalCallback("OnWaveInit", function() resetBuyRobotState() end) AddGlobalCallback("OnWaveSuccess", function() resetBuyRobotState() end) AddGlobalCallback("OnWaveFail", function() resetBuyRobotState() end) local previousOnWaveStart = OnWaveStart function OnWaveStart(waveNumber) waveActive = true setKioskEnabled(true) if previousOnWaveStart then previousOnWaveStart(waveNumber) end end AddGlobalCallback("OnWaveSpawnBot", function(bot, wave, tags) if not IsValid(bot) then return end attachZombieMoneyCallback(bot) if not purchasePending then return end timer.Simple(0.2, function() if not IsValid(bot) or not purchasePending then return end if not hasTag(tags, HEAVY_TAG) and not isHeavyName(bot) then return end trackHeavy(bot) end) end) AddGlobalCallback("OnWaveReset", function() resetBuyRobotState() end) timer.Create(0.1, spinTeleporter, 0)