cosmonarchy-bw-prerelease/mpq/lua/examples/basic_ai.lua

152 lines
4.7 KiB
Lua
Raw Permalink Normal View History

2026-09-09 14:52:21 +00:00
-- Setup main variables
local player = Player()
if player.type ~= PlayerType.Computer then
return
end
local ai = AI()
local config = PlayerVars().ai_config or {}
local main_town = ai:start_town()
-- Neat way to organize stuff is to use a table
local brain = {
saw_air_units = false,
}
---@param town Town
local function flyer_watch(town)
wait_until(function() return brain.saw_air_units end)
for i = 1, 5 do
town:build(i, UnitId.TerranWatchdog, 70-i)
wait(secs(30 + 5 * i))
end
end
---@param town Town
local function build_main_town(town)
town:build(20, UnitId.TerranMason, 90)
wait(secs(30))
town:build(1, UnitId.TerranStockade, 100)
wait(secs(90))
town:build(2, UnitId.TerranStockade, 90)
wait(secs(5))
town:build(3, UnitId.TerranStockade, 70)
wait(mins(1))
town:multirun(flyer_watch)
town:build(4, UnitId.TerranStockade, 70)
end
---@param town Town
local function build_expo(town)
cprint(TextColor.Orange, "Expanding:")
print(town)
town:build(1, UnitId.TerranMinistry, 90)
town:wait_build(1, UnitId.TerranMinistry)
town:transfer_workers(4)
town:build(20, UnitId.TerranMason, 85)
town:wait_build(10, UnitId.TerranMason)
town:multirun(flyer_watch)
town:build(1, UnitId.TerranStockade, 80)
wait(secs(30))
town:build(2, UnitId.TerranStockade, 70)
-- TODO: town:build_at(UnitId.TerranStockage, Point(69, 69), 90)
-- TODO: town:new_guard(...)
end
local function expand_loop()
wait(secs(90))
while true do
local town = ai:expand()
town:multirun(build_expo) -- town:multirun manages script lifetime based on town alive state
if town.is_alive then
wait(math.random(mins(3), mins(4)))
else
wait(math.random(secs(30), mins(1))) -- if town didn't create we wait for shorter
end
-- NOTE: if we didn't need the town.is_alive check we can use nice shorthand:
-- ai:expand:multirun(build_expo)
end
end
local function attack_waves()
main_town:wait_build(1, UnitId.TerranStockade)
while true do
-- Classic attack wave with counts
--[[
local attack = ai:new_attack()
attack.from = Point(3800, 500)
if Time.elapsed <= mins(5) then
attack:add(5 + (Time.elapsed // mins(2)), UnitId.TerranMaverick)
else
attack:add(4 + (Time.elapsed // mins(4)), UnitId.TerranMaverick)
attack:add(2 + (Time.elapsed // mins(4)), UnitId.TerranHarakan)
end
]]
-- Composing attack wave from power value
local attack_budget = player:unit_count(UnitId.TerranMason) * 50
+ (player.minerals + player.gas) // 2
local attack = ai:new_attack(attack_budget)
attack.budget = attack_budget
attack.timeout = 120
-- attack.from = Point(3800, 500)
if player:unit_count(UnitId.TerranStockade) > 0 then
attack:compose(config.pref_maverick or 1, UnitId.TerranMaverick)
attack:compose(config.pref_harakan or 1, UnitId.TerranHarakan)
attack:compose(config.pref_cyprian or 1, UnitId.TerranCyprian)
end
cprint(TextColor.Red, "Sending attack:")
print(attack)
attack:send()
wait(math.random(secs(5), secs(15)))
end
end
local function dump_defenses()
cprint(TextColor.Yellow3, "Defenses:")
print("build.gg:", ai.defense.build.gg)
print("use.gg:", ai.defense.use.gg)
print("build.ag:", ai.defense.build.ag)
print("use.ag:", ai.defense.use.ag)
print("build.ga:", ai.defense.build.ga)
print("use.ga:", ai.defense.use.ga)
print("build.aa:", ai.defense.build.aa)
print("use.aa:", ai.defense.use.aa)
end
---@param unit_id UnitId
---@param cond fun(): boolean
local function defense_watch_impl(unit_id, cond)
while true do
wait_until(cond, secs(1))
ai.defense:auto_set(unit_id)
-- dump_defenses()
wait_while(cond, secs(1))
ai.defense:auto_remove(unit_id)
-- dump_defenses()
end
end
---@param factory_id UnitId
---@param unit_id UnitId
local function defense_watch(factory_id, unit_id)
defense_watch_impl(unit_id, function()
return player:unit_count(factory_id) > 0
end)
end
-- Run all the functions
-- Special kind of multirun, this script will die when town dies
-- Equivalent to `multirun(function(town) town:auto_kill() ... end, town)`
main_town:multirun(build_main_town)
multirun(expand_loop)
multirun(attack_waves)
multirun(defense_watch, UnitId.TerranStockade, UnitId.TerranMaverick)
multirun(defense_watch, UnitId.TerranStockade, UnitId.TerranHarakan)
wait(mins(8))
brain.saw_air_units = true -- let's pretend, since we don't have api for detecting units yet