diff --git a/mpq/arr/flingy.datex b/mpq/arr/flingy.datex index 3e9f2075..6edcde4c 100644 Binary files a/mpq/arr/flingy.datex and b/mpq/arr/flingy.datex differ diff --git a/mpq/arr/flingy.txt b/mpq/arr/flingy.txt index d26c5273..19531f57 100644 --- a/mpq/arr/flingy.txt +++ b/mpq/arr/flingy.txt @@ -722,7 +722,7 @@ Medkit Battery Cell Okrimnilisk Spore Raynor (Maverick) -Extended Flingy #516 +Cyprian (Hecaton) Extended Flingy #517 Extended Flingy #518 Extended Flingy #519 diff --git a/mpq/arr/images.datex b/mpq/arr/images.datex index b304bddf..92ea0bda 100644 Binary files a/mpq/arr/images.datex and b/mpq/arr/images.datex differ diff --git a/mpq/arr/images.tbl b/mpq/arr/images.tbl index c07b657f..a805de5e 100644 Binary files a/mpq/arr/images.tbl and b/mpq/arr/images.tbl differ diff --git a/mpq/arr/images.txt b/mpq/arr/images.txt index 8dced035..9203731c 100644 --- a/mpq/arr/images.txt +++ b/mpq/arr/images.txt @@ -2494,8 +2494,8 @@ Spore Trail (White) Raynor (Maverick) Raynor (Maverick) Shadow Raynor (Maverick) Remains -Extended Image #1494 -Extended Image #1495 +Cyprian (Hecaton) +Cyprian (Hecaton) Shadow Extended Image #1496 Extended Image #1497 Extended Image #1498 diff --git a/mpq/arr/portdata.datex b/mpq/arr/portdata.datex index 84136898..b837b818 100644 Binary files a/mpq/arr/portdata.datex and b/mpq/arr/portdata.datex differ diff --git a/mpq/arr/portdata.tbl b/mpq/arr/portdata.tbl index 1ca1970c..5237ca96 100644 Binary files a/mpq/arr/portdata.tbl and b/mpq/arr/portdata.tbl differ diff --git a/mpq/arr/portdata.txt b/mpq/arr/portdata.txt index 65870897..3740e7d7 100644 --- a/mpq/arr/portdata.txt +++ b/mpq/arr/portdata.txt @@ -310,7 +310,7 @@ Prophet 2 Bloodsummon Advisor Vestige Rozirokor -Extended Portrait #203 +Vespene Node Extended Portrait #204 Extended Portrait #205 Extended Portrait #206 diff --git a/mpq/arr/sprites.datex b/mpq/arr/sprites.datex index 322f7b72..7781edfe 100644 Binary files a/mpq/arr/sprites.datex and b/mpq/arr/sprites.datex differ diff --git a/mpq/arr/sprites.txt b/mpq/arr/sprites.txt index d82ac5fb..163467fa 100644 --- a/mpq/arr/sprites.txt +++ b/mpq/arr/sprites.txt @@ -1198,7 +1198,7 @@ Spore Hit (White) Spore Trail (White) Raynor (Maverick) Raynor (Maverick) Remains -Extended Sprite #684 +Cyprian (Hecaton) Extended Sprite #685 Extended Sprite #686 Extended Sprite #687 diff --git a/mpq/arr/units.datex b/mpq/arr/units.datex index f08408a2..8e5ccf4b 100644 Binary files a/mpq/arr/units.datex and b/mpq/arr/units.datex differ diff --git a/mpq/arr/units.txt b/mpq/arr/units.txt index 1e3c7f75..0001f7d7 100644 --- a/mpq/arr/units.txt +++ b/mpq/arr/units.txt @@ -639,14 +639,14 @@ Battery Cell Forerunner Buildings Terran Eveningstar Raynor (Maverick) -Extended Unit #414 -Extended Unit #415 -Extended Unit #416 -Extended Unit #417 -Extended Unit #418 -Extended Unit #419 -Extended Unit #420 -Extended Unit #421 +Terran Cyprian (Hecaton) +Terran Matador (Tank, Upstart) +Matador Turret (Tank, Upstart) +Terran Matador (Flak, Upstart) +Matador Turret (Flak, Upstart) +Forerunner Processus +Forerunner Aestuarius +Forerunner Corcillum Extended Unit #422 Extended Unit #423 Extended Unit #424 diff --git a/mpq/arr/weapons.datex b/mpq/arr/weapons.datex index 5edf0958..0c66a8ea 100644 Binary files a/mpq/arr/weapons.datex and b/mpq/arr/weapons.datex differ diff --git a/mpq/arr/weapons.txt b/mpq/arr/weapons.txt index d642a65d..a252146d 100644 --- a/mpq/arr/weapons.txt +++ b/mpq/arr/weapons.txt @@ -309,7 +309,7 @@ Reactive Blaster (Manifold Starbound) Plasmathrower (Harakan Golden) High-Tonnage Payload (Eveningstar) Gauss Launcher (Raynor Maverick) -Extended Weapon #182 +Boreal Railguns (Cyprian Hecaton) Extended Weapon #183 Extended Weapon #184 Extended Weapon #185 diff --git a/mpq/datreq/Buttons.graft b/mpq/datreq/Buttons.graft index 8d9bc03e..d682f262 100644 Binary files a/mpq/datreq/Buttons.graft and b/mpq/datreq/Buttons.graft differ diff --git a/mpq/datreq/Units.graft b/mpq/datreq/Units.graft index a700c5a6..ef523fad 100644 Binary files a/mpq/datreq/Units.graft and b/mpq/datreq/Units.graft differ diff --git a/mpq/game/icons.grp b/mpq/game/icons.grp index 4f210f4b..7ebcffc5 100644 Binary files a/mpq/game/icons.grp and b/mpq/game/icons.grp differ diff --git a/mpq/lua/AGENTS.md b/mpq/lua/AGENTS.md new file mode 100644 index 00000000..0d1080fe --- /dev/null +++ b/mpq/lua/AGENTS.md @@ -0,0 +1,3 @@ +# Resources +- Load local Lua API reference from `.luarc.json` +- Fetch Cosmonarchy tech tree from `https://cosmonarchy.com/export/all.json` diff --git a/mpq/lua/CLAUDE.md b/mpq/lua/CLAUDE.md new file mode 100644 index 00000000..43c994c2 --- /dev/null +++ b/mpq/lua/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/mpq/lua/examples/start_melee_ai.lua b/mpq/lua/examples/start_melee_ai.lua new file mode 100644 index 00000000..f5dff077 --- /dev/null +++ b/mpq/lua/examples/start_melee_ai.lua @@ -0,0 +1,3 @@ +require "melee.melee_ai" + +MeleeAI(Personalities.Terran.Raider.EightRax):run() diff --git a/mpq/lua/examples/start_melee_ai_customized.lua b/mpq/lua/examples/start_melee_ai_customized.lua new file mode 100644 index 00000000..97a3112a --- /dev/null +++ b/mpq/lua/examples/start_melee_ai_customized.lua @@ -0,0 +1,6 @@ +require "melee.melee_ai" + +local eight_rax_harakan = deepcopy(Personalities.Terran.Raider.EightRax) +eight_rax_harakan.unit_composition[UnitId.TerranHarakan] = 3 + +MeleeAI(eight_rax_harakan):run() diff --git a/mpq/lua/melee/askosi/basic.lua b/mpq/lua/melee/askosi/basic.lua new file mode 100644 index 00000000..fd440d2b --- /dev/null +++ b/mpq/lua/melee/askosi/basic.lua @@ -0,0 +1,13 @@ +local Basic = {} + +---@type BuildOrder +function Basic.build_anti_ground(melee_ai, town) + melee_ai:build_sequence(town, 1, 4, UnitId.AskosiGrandstand, 70, 5, secs(25), secs(5)) +end + +---@type BuildOrder +function Basic.build_anti_air(melee_ai, town) + melee_ai:build_sequence(town, 1, 4, UnitId.AskosiGrandstand, 80, 5, secs(25), secs(5)) +end + +return Basic diff --git a/mpq/lua/melee/askosi/temp/temp_default.lua b/mpq/lua/melee/askosi/temp/temp_default.lua new file mode 100644 index 00000000..d1de789b --- /dev/null +++ b/mpq/lua/melee/askosi/temp/temp_default.lua @@ -0,0 +1,40 @@ +local Basic = require "melee.askosi.basic" + +---@type AIPersonality +return { + name = "Temp Default", + unit_composition = { + -- ground + [UnitId.AskosiMissionary] = 1, + [UnitId.AskosiCardinal] = 1, + [UnitId.AskosiRove] = 1, + [UnitId.AskosiObject] = 1, + [UnitId.AskosiScepter] = 1, + [UnitId.AskosiIntendent] = 1, + -- air + [UnitId.AskosiHelion] = 1, + [UnitId.AskosiEmissary] = 1, + [UnitId.AskosiInkblot] = 1, + [UnitId.AskosiTirade] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.AskosiRadix, 100, true) + town:build(1, UnitId.AskosiFunction, 100, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.AskosiCosmoscope, 90, true) + melee_ai:dynamic_wait(secs(20)) + melee_ai:start_attacking() + melee_ai:start_expanding() + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:build(1, UnitId.AskosiRadix, 70, true) + town:build(1, UnitId.AskosiFunction, 70, true) + town:build(1, UnitId.AskosiCosmoscope, 70, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/deepcopy.lua b/mpq/lua/melee/deepcopy.lua new file mode 100644 index 00000000..7926efe9 --- /dev/null +++ b/mpq/lua/melee/deepcopy.lua @@ -0,0 +1,20 @@ +---@param original any +---@param seen? table +---@return any +function deepcopy(original, seen) + if type(original) ~= "table" then + return original + end + + seen = seen or {} + if seen[original] then + return seen[original] + end + + local copy = {} + seen[original] = copy + for key, value in pairs(original) do + copy[deepcopy(key, seen)] = deepcopy(value, seen) + end + return setmetatable(copy, deepcopy(getmetatable(original), seen)) +end diff --git a/mpq/lua/melee/melee_ai.lua b/mpq/lua/melee/melee_ai.lua index df10dd47..45a0bfd1 100644 --- a/mpq/lua/melee/melee_ai.lua +++ b/mpq/lua/melee/melee_ai.lua @@ -1,13 +1,15 @@ -require("melee.melee_common") -require("melee.personalities") +require "melee.deepcopy" +require "melee.personalities" + +---@alias BuildOrder fun(melee_ai: MeleeAI, town: Town) ---@class AIPersonality ---@field name string ---@field unit_composition table ----@field main_build_order fun(melee_ai: MeleeAI, town: Town)[] ----@field expansion_build_order fun(melee_ai: MeleeAI, town: Town)[] ----@field build_anti_ground_defenses fun(melee_ai: MeleeAI, town: Town) ----@field build_anti_air_defenses fun(melee_ai: MeleeAI, town: Town) +---@field main_build_order BuildOrder +---@field expansion_build_order BuildOrder +---@field build_anti_ground_defenses BuildOrder +---@field build_anti_air_defenses BuildOrder ---@field expand_rate? number Default is 3 minutes 30 seconds ---@field expand_wait_after_fail? number Default is 30 seconds ---@field attack_wave_budget_scaling? number Default is 1.0 @@ -17,6 +19,7 @@ require("melee.personalities") ---@field started_anti_ground_defenses boolean ---@field started_anti_air_defenses boolean +---@overload fun(personality?: AIPersonality, player?: Player): MeleeAI ---@class MeleeAI ---@field debugging {enabled: boolean, last_tick: number, last_script_id: number} ---@field player Player @@ -36,17 +39,21 @@ setmetatable(MeleeAI, { end, }) ----@param config? table +---@param personality? AIPersonality ---@param player? Player -function MeleeAI.new(config, player) +---@return MeleeAI melee_ai +function MeleeAI.new(personality, player) local self = setmetatable({}, MeleeAI) + self.player = player or Player() + if self.player.type ~= PlayerType.Computer then + return self + end self.debugging = { - enabled = PlayerVars(player).ai_debug or false, + enabled = PlayerVars(self.player).ai_debug or false, last_tick = -1, last_script_id = -1, } - self.player = player or Player() - self.personality = config or Personalities.pick_random(player) + self.personality = personality or Personalities.pick_random(player) self.ai = AI(self.player.id) self.main_town = self.ai:start_town() self.towns = { @@ -60,8 +67,7 @@ function MeleeAI.new(config, player) self.seen_air_threats = true -- TODO: detect dynamically or after timeout -- TODO: maybe have a dynamic unit loss threshold check that triggers a stronger defense response - self:cdebug(TextColor.Yellow3, "Starting AI with personality: " .. self.personality.name) - + self:cdebug(TextColor.White, "Starting AI with personality: " .. self.personality.name) return self end @@ -88,26 +94,6 @@ function MeleeAI:cdebug(color, ...) end end --- How often the banked-resource snapshot is refreshed while a dynamic_wait is --- in progress, so a long wait reacts to resources changing mid-wait instead --- of freezing the scale from a single sample taken at the start. -local DYNAMIC_WAIT_RESAMPLE_INTERVAL = secs(2) - ----@param duration integer -function MeleeAI:dynamic_wait(duration) - local elapsed = 0 - while elapsed < duration do - local chunk = math.min(DYNAMIC_WAIT_RESAMPLE_INTERVAL, duration - elapsed) - local resources = self.player.minerals + self.player.gas - local resource_scale = math.max(0, math.min(1, (1100 - resources) / 600)) - local scaled_chunk = math.floor(chunk * resource_scale) - if scaled_chunk > 0 then - wait(scaled_chunk) - end - elapsed = elapsed + chunk - end -end - ---@protected ---@return table function MeleeAI:get_final_unit_composition() @@ -119,6 +105,9 @@ function MeleeAI:get_final_unit_composition() end function MeleeAI:run() + if not self.ai then + return + end for unit_id, preference in pairs(self:get_final_unit_composition()) do if preference > 0 then multirun(function() @@ -132,18 +121,8 @@ function MeleeAI:run() end end - multirun(function() - self.main_town:auto_kill_script() - self.main_town:build(1, MeleeCommon.default_town_building(self.player.race), 120) - self.main_town:build(self.main_town.max_workers, MeleeCommon.default_worker(self.player.race), 100) - for i, build_order_step in ipairs(self.personality.main_build_order) do - build_order_step(self, self.main_town) - if i == 1 then - -- If opener didn't enable this, we now should - self:start_attacking() - self:start_expanding() - end - end + self.main_town:multirun(function(main_town) + self.personality.main_build_order(self, main_town) end) end @@ -163,13 +142,7 @@ function MeleeAI:start_expanding() started_anti_air_defenses = false, } town:multirun(function() - for i, build_order_step in ipairs(self.personality.expansion_build_order) do - build_order_step(self, town) - if i == 1 then - self:start_anti_ground_defenses(town) - self:start_anti_air_defenses(town) - end - end + self.personality.expansion_build_order(self, town) end) wait(self.personality.expand_rate or (mins(3) + secs(30))) else @@ -186,8 +159,9 @@ function MeleeAI:start_attacking() self.started_attacking = true multirun(function() while true do - local budget = self.player:unit_count(MeleeCommon.default_worker(self.player.race)) * 50 - + (self.player.minerals + self.player.gas) / 2 + local budget = self:town_count() * 500 + + self.player:unit_count(self:default_worker()) * 50 + + (self.ai.minerals + self.ai.gas) / 2 budget = budget * (self.personality.attack_wave_budget_scaling or 1.0) local attack = self.ai:new_attack(budget, self.personality.attack_wave_cost_bias or nil) @@ -233,3 +207,160 @@ function MeleeAI:start_anti_air_defenses(town) self.personality.build_anti_air_defenses(self, town) end) end + +---@return UnitId worker_unit_id +function MeleeAI:default_worker() + local race = self.player.race + if race == RaceId.Terran then + return UnitId.TerranMason + elseif race == RaceId.Zerg then + return UnitId.ZergDroleth + elseif race == RaceId.Protoss then + return UnitId.ProtossScribe + elseif race == RaceId.Askosi then + return UnitId.AskosiPilgrim + end + error("Race " .. tostring(race) .. " has no default worker set") +end + +---@return UnitId town_building_unit_id +function MeleeAI:default_town_building() + local race = self.player.race + if race == RaceId.Terran then + return UnitId.TerranMinistry + elseif race == RaceId.Zerg then + return UnitId.ZergHachirosk + elseif race == RaceId.Protoss then + return UnitId.ProtossNexus + elseif race == RaceId.Askosi then + return UnitId.AskosiLandlock + end + error("Race " .. tostring(race) .. " has no default town set") +end + +---@param unit_id UnitId +---@return boolean +function MeleeAI:can_make(unit_id) + return self.player:can_make(unit_id) +end + +---@return number +function MeleeAI:worker_count(town) + return town:unit_count(self:default_worker(), true) +end + +---@return number +function MeleeAI:total_worker_count() + return self.player:unit_count(self:default_worker(), true) +end + +---@return number +function MeleeAI:town_count() + local count = 0 + for town, _ in pairs(self.towns) do + if town.is_alive and town:unit_count(self:default_town_building(), true) > 0 then + count = count + 1 + end + end + return count +end + +---@param duration integer +function MeleeAI:dynamic_wait(duration) + local elapsed = 0 + while elapsed < duration do + local chunk = math.min(secs(2), duration - elapsed) + local resources = self.ai.minerals + self.ai.gas + local resource_scale = math.max(0, math.min(1, (1100 - resources) / 600)) + local scaled_chunk = math.floor(chunk * resource_scale) + if scaled_chunk > 0 then + wait(scaled_chunk) + end + elapsed = elapsed + chunk + end +end + +---@param unit_id UnitId +function MeleeAI:wait_can_make(unit_id) + wait_until(function() + return self.player:can_make(unit_id) + end, secs(1)) +end + +---@param town Town +---@param count number +function MeleeAI:wait_worker_count(town, count) + wait_until(function() + return self:worker_count(town) >= count + end, secs(1)) +end + +---@param count number +function MeleeAI:wait_total_worker_count(count) + wait_until(function() + return self:total_worker_count() >= count + end, secs(1)) +end + +---@param count number +function MeleeAI:wait_town_count(count) + wait_until(function() + return self:town_count() >= count + end, secs(1)) +end + +---@param town Town +---@param ... BuildOrder +function MeleeAI:pick_random(town, ...) + local builds = {...} + builds[math.random(#builds)](self, town) +end + +---@param town Town +function MeleeAI:build_main(town) + town:build(1, self:default_town_building(), 120) + town:build(town.max_workers, self:default_worker(), 100) +end + +---@param town Town +---@param wait_for_workers boolean +function MeleeAI:build_expansion(town, wait_for_workers) + town:build(1, self:default_town_building(), 120) + town:wait_build(1, self:default_town_building()) + town:build(town.max_workers, self:default_worker(), 100) + town:transfer_workers(8) + if wait_for_workers then + town:wait_build(10, self:default_worker()) + end +end + +---@param town Town +---@param count integer +---@param unit_id UnitId +---@param priority integer +---@param wait? integer +function MeleeAI:build_and_wait(town, count, unit_id, priority, wait) + town:build(count, unit_id, priority) + town:wait_build(count, unit_id, false) + if wait then + self:dynamic_wait(wait) + end +end + +---@param town Town +---@param start integer +---@param end_ integer +---@param unit_id UnitId +---@param priority integer +---@param priority_decrease integer +---@param wait integer +---@param wait_increase integer +function MeleeAI:build_sequence(town, start, end_, unit_id, priority, priority_decrease, wait, wait_increase) + for i = start, end_ do + town:build(i, unit_id, priority - priority_decrease * (i - 1)) + town:wait_build(i, unit_id, false) + if wait and i ~= end_ then + self:dynamic_wait(wait + wait_increase * (i - 1)) + end + end +end diff --git a/mpq/lua/melee/melee_common.lua b/mpq/lua/melee/melee_common.lua deleted file mode 100644 index 5940f72f..00000000 --- a/mpq/lua/melee/melee_common.lua +++ /dev/null @@ -1,33 +0,0 @@ -MeleeCommon = {} - ----@param race RaceId ----@return UnitId worker_unit_id -function MeleeCommon.default_worker(race) - if race == RaceId.Terran then - return UnitId.TerranMason - elseif race == RaceId.Zerg then - return UnitId.ZergDroleth - elseif race == RaceId.Protoss then - return UnitId.ProtossScribe - elseif race == RaceId.Askosi then - return UnitId.AskosiPilgrim - end - error("Race " .. tostring(race) .. " has no default worker set") -end - ----@param race RaceId ----@return UnitId town_building_unit_id -function MeleeCommon.default_town_building(race) - if race == RaceId.Terran then - return UnitId.TerranMinistry - elseif race == RaceId.Zerg then - return UnitId.ZergHachirosk - elseif race == RaceId.Protoss then - return UnitId.ProtossNexus - elseif race == RaceId.Askosi then - return UnitId.AskosiLandlock - end - error("Race " .. tostring(race) .. " has no default town set") -end - -return MeleeCommon diff --git a/mpq/lua/melee/personalities.lua b/mpq/lua/melee/personalities.lua index 96f1d12f..d995e6cd 100644 --- a/mpq/lua/melee/personalities.lua +++ b/mpq/lua/melee/personalities.lua @@ -1,99 +1,112 @@ -local TerranArmor = require("melee.terran.armor") -local TerranRaider = require("melee.terran.raider") -local TerranOrbital = require("melee.terran.orbital") -local TerranGeneral = require("melee.terran.general") - -local ZergAssault = require("melee.zerg.assault") -local ZergSwarm = require("melee.zerg.swarm") -local ZergSunblot = require("melee.zerg.sunblot") -local ZergGeneral = require("melee.zerg.general") - -local ProtossRanger = require("melee.protoss.ranger") -local ProtossTemplar = require("melee.protoss.templar") -local ProtossSkylord = require("melee.protoss.skylord") -local ProtossGeneral = require("melee.protoss.general") - ---@class Personalities Personalities = { Terran = { - ArmorTankPush = TerranArmor.tank_push, - ArmorFeFiveFulc = TerranArmor.fe_five_fulc, - ArmorTwoFulcVulture = TerranArmor.two_fulc_vulture, - ArmorWalkerPower = TerranArmor.walker_power, - ArmorIronCrusade = TerranArmor.iron_crusade, - ArmorDavidAndGoliath = TerranArmor.david_and_goliath, - RaiderEightRax = TerranRaider.eight_rax, - RaiderThreeRaxBio = TerranRaider.three_rax_bio, - RaiderFastAnvil = TerranRaider.fast_anvil, - RaiderFourRaxPressure = TerranRaider.four_rax_pressure, - RaiderUprising = TerranRaider.uprising, - RaiderHolyAckmeds = TerranRaider.holy_ackmeds, - OrbitalRapidStarpads = TerranOrbital.rapid_starpads, - OrbitalTheDon = TerranOrbital.the_don, - OrbitalWraithBio = TerranOrbital.wraith_bio, - OrbitalHotdrop = TerranOrbital.hotdrop, - OrbitalSuddenStarport = TerranOrbital.sudden_starport, - OrbitalAcesHigh = TerranOrbital.aces_high, - GeneralTwoFulcrumMech = TerranGeneral.two_fulcrum_mech, - GeneralEarlyRiser = TerranGeneral.early_riser, - GeneralTheCube = TerranGeneral.the_cube, - GeneralDoublingUp = TerranGeneral.doubling_up, - GeneralMechIntoAir = TerranGeneral.mech_into_air, - GeneralObservant = TerranGeneral.observant, - }, - Zerg = { - AssaultThreeBaseHydrith = ZergAssault.three_base_hydrith, - AssaultTwoBaseZorkiz = ZergAssault.two_base_zorkiz, - AssaultTwoBaseHydrithQuazeth = ZergAssault.two_base_hydrith_quazeth, - AssaultTwoBaseAlkag = ZergAssault.two_base_alkag, - AssaultPotency = ZergAssault.potency, - AssaultEarthenTides = ZergAssault.earthen_tides, - SwarmThreeBaseFlood = ZergSwarm.three_base_flood, - SwarmThreeBaseUltrav = ZergSwarm.three_base_ultrav, - SwarmInstantQuazeth = ZergSwarm.instant_quazeth, - SwarmThreeBaseOthstol = ZergSwarm.three_base_othstol, - SwarmGatesOfHell = ZergSwarm.gates_of_hell, - SwarmPrimitivePressure = ZergSwarm.primitive_pressure, - SunblotBigAndLittle = ZergSunblot.big_and_little, - SunblotTheTriad = ZergSunblot.the_triad, - SunblotSkitteringDuo = ZergSunblot.skittering_duo, - SunblotEarlyBirds = ZergSunblot.early_birds, - SunblotFlyingFeint = ZergSunblot.flying_feint, - SunblotDescendingHorizon = ZergSunblot.descending_horizon, - GeneralSleepingGiant = ZergGeneral.sleeping_giant, - GeneralShriekingSwarm = ZergGeneral.shrieking_swarm, - GeneralSubjugation = ZergGeneral.subjugation, - GeneralBeforeTheStorm = ZergGeneral.before_the_storm, - GeneralTimeAfterTime = ZergGeneral.time_after_time, - GeneralConstrainedCoil = ZergGeneral.constrained_coil, + General = { + TwoFulcrumMech = require "melee.terran.general.two_fulcrum_mech", + EarlyRiser = require "melee.terran.general.early_riser", + TheCube = require "melee.terran.general.the_cube", + DoublingUp = require "melee.terran.general.doubling_up", + MechIntoAir = require "melee.terran.general.mech_into_air", + Observant = require "melee.terran.general.observant", + }, + Raider = { + EightRax = require "melee.terran.raider.eight_rax", + ThreeRaxBio = require "melee.terran.raider.three_rax_bio", + FastAnvil = require "melee.terran.raider.fast_anvil", + FourRaxPressure = require "melee.terran.raider.four_rax_pressure", + Uprising = require "melee.terran.raider.uprising", + HolyAckmeds = require "melee.terran.raider.holy_ackmeds", + }, + Armor = { + TankPush = require "melee.terran.armor.tank_push", + FeFiveFulc = require "melee.terran.armor.fe_five_fulc", + TwoFulcVulture = require "melee.terran.armor.two_fulc_vulture", + WalkerPower = require "melee.terran.armor.walker_power", + IronCrusade = require "melee.terran.armor.iron_crusade", + DavidAndGoliath = require "melee.terran.armor.david_and_goliath", + }, + Orbital = { + RapidStarpads = require "melee.terran.orbital.rapid_starpads", + TheDon = require "melee.terran.orbital.the_don", + WraithBio = require "melee.terran.orbital.wraith_bio", + Hotdrop = require "melee.terran.orbital.hotdrop", + SuddenStarport = require "melee.terran.orbital.sudden_starport", + AcesHigh = require "melee.terran.orbital.aces_high", + }, }, Protoss = { - RangerTwoGateStrider = ProtossRanger.two_gate_strider, - RangerEmissarySquared = ProtossRanger.emissary_squared, - RangerOneGateAuthority = ProtossRanger.one_gate_authority, - RangerLatticeExpo = ProtossRanger.lattice_expo, - RangerSimulantSwarm = ProtossRanger.simulant_swarm, - RangerTheRegistry = ProtossRanger.the_registry, - TemplarThreeGateStrider = ProtossTemplar.three_gate_strider, - TemplarSuffocatingShadow = ProtossTemplar.suffocating_shadow, - TemplarLegion = ProtossTemplar.legion, - TemplarInitiates = ProtossTemplar.initiates, - TemplarMartyrdom = ProtossTemplar.martyrdom, - TemplarLegionsHeralds = ProtossTemplar.legions_heralds, - SkylordSolarEscort = ProtossSkylord.solar_escort, - SkylordDeadlyOmen = ProtossSkylord.deadly_omen, - SkylordTwoGatePanoptus = ProtossSkylord.two_gate_panoptus, - SkylordExalted = ProtossSkylord.exalted, - SkylordSorrowFleet = ProtossSkylord.sorrow_fleet, - SkylordShipsAndSwords = ProtossSkylord.ships_and_swords, - GeneralLunaticLegion = ProtossGeneral.lunatic_legion, - GeneralStridentStriders = ProtossGeneral.strident_striders, - GeneralWorship = ProtossGeneral.worship, - GeneralRoboticsFe = ProtossGeneral.robotics_fe, - GeneralTheSwordsmiths = ProtossGeneral.the_swordsmiths, - GeneralMatriarchy = ProtossGeneral.matriarchy, + General = { + LunaticLegion = require "melee.protoss.general.lunatic_legion", + StridentStriders = require "melee.protoss.general.strident_striders", + Worship = require "melee.protoss.general.worship", + RoboticsFe = require "melee.protoss.general.robotics_fe", + TheSwordsmiths = require "melee.protoss.general.the_swordsmiths", + Matriarchy = require "melee.protoss.general.matriarchy", + }, + Templar = { + ThreeGateStrider = require "melee.protoss.templar.three_gate_strider", + SuffocatingShadow = require "melee.protoss.templar.suffocating_shadow", + Legion = require "melee.protoss.templar.legion", + Initiates = require "melee.protoss.templar.initiates", + Martyrdom = require "melee.protoss.templar.martyrdom", + LegionsHeralds = require "melee.protoss.templar.legions_heralds", + }, + Ranger = { + TwoGateStrider = require "melee.protoss.ranger.two_gate_strider", + EmissarySquared = require "melee.protoss.ranger.emissary_squared", + OneGateAuthority = require "melee.protoss.ranger.one_gate_authority", + LatticeExpo = require "melee.protoss.ranger.lattice_expo", + SimulantSwarm = require "melee.protoss.ranger.simulant_swarm", + TheRegistry = require "melee.protoss.ranger.the_registry", + }, + Skylord = { + SolarEscort = require "melee.protoss.skylord.solar_escort", + DeadlyOmen = require "melee.protoss.skylord.deadly_omen", + TwoGatePanoptus = require "melee.protoss.skylord.two_gate_panoptus", + Exalted = require "melee.protoss.skylord.exalted", + SorrowFleet = require "melee.protoss.skylord.sorrow_fleet", + ShipsAndSwords = require "melee.protoss.skylord.ships_and_swords", + }, + }, + Zerg = { + General = { + SleepingGiant = require "melee.zerg.general.sleeping_giant", + ShriekingSwarm = require "melee.zerg.general.shrieking_swarm", + Subjugation = require "melee.zerg.general.subjugation", + BeforeTheStorm = require "melee.zerg.general.before_the_storm", + TimeAfterTime = require "melee.zerg.general.time_after_time", + ConstrainedCoil = require "melee.zerg.general.constrained_coil", + }, + Swarm = { + ThreeBaseFlood = require "melee.zerg.swarm.three_base_flood", + ThreeBaseUltrav = require "melee.zerg.swarm.three_base_ultrav", + InstantQuazeth = require "melee.zerg.swarm.instant_quazeth", + ThreeBaseOthstol = require "melee.zerg.swarm.three_base_othstol", + GatesOfHell = require "melee.zerg.swarm.gates_of_hell", + PrimitivePressure = require "melee.zerg.swarm.primitive_pressure", + }, + Assault = { + ThreeBaseHydrith = require "melee.zerg.assault.three_base_hydrith", + TwoBaseZorkiz = require "melee.zerg.assault.two_base_zorkiz", + TwoBaseHydrithQuazeth = require "melee.zerg.assault.two_base_hydrith_quazeth", + TwoBaseAlkag = require "melee.zerg.assault.two_base_alkag", + Potency = require "melee.zerg.assault.potency", + EarthenTides = require "melee.zerg.assault.earthen_tides", + }, + Sunblot = { + BigAndLittle = require "melee.zerg.sunblot.big_and_little", + TheTriad = require "melee.zerg.sunblot.the_triad", + SkitteringDuo = require "melee.zerg.sunblot.skittering_duo", + EarlyBirds = require "melee.zerg.sunblot.early_birds", + FlyingFeint = require "melee.zerg.sunblot.flying_feint", + DescendingHorizon = require "melee.zerg.sunblot.descending_horizon", + }, + }, + Askosi = { + Temp = { + Default = require "melee.askosi.temp.temp_default", + }, }, - Askosi = {}, } ---@class RacePersonalities @@ -128,14 +141,10 @@ end ---@return AIPersonality function Personalities.pick_random(player) player = player or Player() - local race_personalities = by_race(player.race) - return pick_random(race_personalities) -end - ----@param personality AIPersonality ----@return AIPersonality -function Personalities.copy(personality) - error("not implemented yet") + local race = by_race(player.race) + local category = pick_random(race) + local personality = pick_random(category) + return personality end return Personalities diff --git a/mpq/lua/melee/protoss/basic.lua b/mpq/lua/melee/protoss/basic.lua new file mode 100644 index 00000000..af2e61eb --- /dev/null +++ b/mpq/lua/melee/protoss/basic.lua @@ -0,0 +1,13 @@ +local Basic = {} + +---@type BuildOrder +function Basic.build_anti_ground(melee_ai, town) + melee_ai:build_sequence(town, 1, 4, UnitId.ProtossWarden, 70, 5, secs(25), secs(5)) +end + +---@type BuildOrder +function Basic.build_anti_air(melee_ai, town) + melee_ai:build_sequence(town, 1, 3, UnitId.ProtossMatrix, 80, 5, secs(25), secs(5)) +end + +return Basic diff --git a/mpq/lua/melee/protoss/build/basic.lua b/mpq/lua/melee/protoss/build/basic.lua deleted file mode 100644 index 7ba15d7d..00000000 --- a/mpq/lua/melee/protoss/build/basic.lua +++ /dev/null @@ -1,31 +0,0 @@ -local Basic = {} - ----@param melee_ai MeleeAI ----@param town Town -function Basic.build_expansion(melee_ai, town) - town:build(1, UnitId.ProtossNexus, 120) - town:wait_build(1, UnitId.ProtossNexus) - town:build(town.max_workers, UnitId.ProtossScribe, 100) - town:transfer_workers(8) - town:wait_build(10, UnitId.ProtossScribe) -end - ----@param melee_ai MeleeAI ----@param town Town -function Basic.build_anti_ground(melee_ai, town) - for i = 1, 4 do - town:build(i, UnitId.ProtossWarden, 70 - i * 5) - wait(secs(25 + i * 5)) - end -end - ----@param melee_ai MeleeAI ----@param town Town -function Basic.build_anti_air(melee_ai, town) - for i = 1, 3 do - town:build(i, UnitId.ProtossMatrix, 80 - i * 5) - wait(secs(25 + i * 5)) - end -end - -return Basic diff --git a/mpq/lua/melee/protoss/build/openers.lua b/mpq/lua/melee/protoss/build/openers.lua deleted file mode 100644 index b4d880ab..00000000 --- a/mpq/lua/melee/protoss/build/openers.lua +++ /dev/null @@ -1,424 +0,0 @@ ----@class ProtossOpeners -local Openers = {} - --- Ranger - ----@param melee_ai MeleeAI ----@param town Town -function Openers.two_gate_strider(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossPylon, 110) - melee_ai:dynamic_wait(secs(15)) - town:wait_build(1, UnitId.ProtossPylon) - town:build(1, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(20)) - town:build(2, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(30)) - town:build(3, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(25)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(mins(1)) - melee_ai:start_expanding() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.emissary_squared(melee_ai, town) - melee_ai:dynamic_wait(secs(30)) - melee_ai:start_expanding() - melee_ai:dynamic_wait(secs(30)) - town:build(1, UnitId.ProtossPylon, 90) - town:wait_build(1, UnitId.ProtossPylon) - town:build(1, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(30)) - town:build(1, UnitId.ProtossLattice, 90) - melee_ai:dynamic_wait(secs(15)) - town:build(2, UnitId.ProtossPylon, 90) - melee_ai:dynamic_wait(secs(55)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(mins(1)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.one_gate_authority(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossPylon, 110) - melee_ai:dynamic_wait(secs(15)) - town:wait_build(1, UnitId.ProtossPylon) - town:build(1, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(20)) - town:build(2, UnitId.ProtossPylon, 90) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossLattice, 90) - melee_ai:dynamic_wait(secs(25)) - melee_ai:start_attacking() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.lattice_expo(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossPylon, 110) - melee_ai:dynamic_wait(secs(15)) - town:wait_build(1, UnitId.ProtossPylon) - town:build(1, UnitId.ProtossLattice, 90) - melee_ai:dynamic_wait(secs(25)) - melee_ai:start_expanding() - melee_ai:dynamic_wait(secs(50)) - town:build(2, UnitId.ProtossLattice, 90) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(3, UnitId.ProtossLattice, 90) - melee_ai:dynamic_wait(secs(25)) - town:build(4, UnitId.ProtossLattice, 90) - melee_ai:dynamic_wait(secs(45)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(secs(15)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.simulant_swarm(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossPylon, 110) - melee_ai:dynamic_wait(secs(25)) - town:wait_build(1, UnitId.ProtossPylon) - town:build(1, UnitId.ProtossLattice, 90) - melee_ai:dynamic_wait(secs(25)) - town:build(2, UnitId.ProtossLattice, 90) - melee_ai:dynamic_wait(secs(15)) - town:build(2, UnitId.ProtossPylon, 90) - melee_ai:dynamic_wait(secs(25)) - town:build(3, UnitId.ProtossLattice, 90) - melee_ai:dynamic_wait(secs(25)) - town:build(4, UnitId.ProtossLattice, 90) - melee_ai:dynamic_wait(secs(20)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(mins(1)) - melee_ai:start_expanding() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.the_registry(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossPylon, 110) - melee_ai:dynamic_wait(secs(15)) - town:wait_build(1, UnitId.ProtossPylon) - town:build(1, UnitId.ProtossLattice, 90) - melee_ai:dynamic_wait(secs(30)) - town:build(2, UnitId.ProtossLattice, 90) - melee_ai:dynamic_wait(secs(40)) - melee_ai:start_attacking() -end - --- Templar - ----@param melee_ai MeleeAI ----@param town Town -function Openers.three_gate_strider(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossPylon, 110) - melee_ai:dynamic_wait(secs(15)) - town:wait_build(1, UnitId.ProtossPylon) - town:build(1, UnitId.ProtossGateway, 90) -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.suffocating_shadow(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossPylon, 110) - melee_ai:dynamic_wait(secs(15)) - town:wait_build(1, UnitId.ProtossPylon) - town:build(1, UnitId.ProtossGateway, 90) -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.legion(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossPylon, 110) - melee_ai:dynamic_wait(secs(15)) - town:wait_build(1, UnitId.ProtossPylon) - town:build(1, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(15)) - town:build(2, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(15)) - town:build(2, UnitId.ProtossPylon, 90) - melee_ai:dynamic_wait(secs(35)) - town:build(3, UnitId.ProtossGateway, 90) - wait(secs(1)) - town:build(3, UnitId.ProtossPylon, 90) - melee_ai:dynamic_wait(secs(30)) - town:build(4, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(15)) - town:build(5, UnitId.ProtossGateway, 90) - wait(secs(1)) - town:build(4, UnitId.ProtossPylon, 90) - melee_ai:dynamic_wait(secs(20)) - town:build(6, UnitId.ProtossGateway, 90) - wait(secs(1)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(secs(25)) - melee_ai:start_expanding() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.initiates(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossPylon, 110) - town:wait_build(1, UnitId.ProtossPylon) - town:build(1, UnitId.ProtossGateway, 90) - - melee_ai:dynamic_wait(secs(25)) - town:build(2, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(15)) - town:build(2, UnitId.ProtossPylon, 90) - town:wait_build(2, UnitId.ProtossGateway) - melee_ai:dynamic_wait(secs(10)) - town:build(3, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(25)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(secs(40)) - melee_ai:start_expanding() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.martyrdom(melee_ai, town) - melee_ai:dynamic_wait(secs(30)) - melee_ai:start_expanding() - melee_ai:dynamic_wait(secs(30)) - town:build(1, UnitId.ProtossPylon, 90) - melee_ai:dynamic_wait(secs(15)) - town:wait_build(1, UnitId.ProtossPylon) - town:build(1, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(15)) - town:build(3, UnitId.ProtossPylon, 90) - melee_ai:dynamic_wait(secs(15)) - town:build(2, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(15)) - town:build(3, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(40)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(mins(2) + secs(30)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.legions_heralds(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossPylon, 110) - town:wait_build(1, UnitId.ProtossPylon) - town:build(1, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(30)) - melee_ai:start_expanding() -end - --- Skylord - ----@param melee_ai MeleeAI ----@param town Town -function Openers.solar_escort(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossPylon, 110) - melee_ai:dynamic_wait(secs(15)) - melee_ai:start_expanding() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.deadly_omen(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossPylon, 110) - melee_ai:dynamic_wait(secs(15)) - town:wait_build(1, UnitId.ProtossPylon) - town:build(1, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossStargate, 90) - melee_ai:dynamic_wait(secs(40)) - town:build(2, UnitId.ProtossStargate, 90) - town:wait_build(1, UnitId.ProtossStargate) - melee_ai:start_attacking() - melee_ai:dynamic_wait(mins(1)) - town:build(2, UnitId.ProtossPylon, 90) - town:wait_build(2, UnitId.ProtossPylon) - town:build(2, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(25)) - melee_ai:start_expanding() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.two_gate_panoptus(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossPylon, 110) - melee_ai:dynamic_wait(secs(15)) - town:wait_build(1, UnitId.ProtossPylon) - town:build(1, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(25)) - town:build(2, UnitId.ProtossPylon, 90) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossStargate, 90) - melee_ai:dynamic_wait(secs(50)) - town:build(2, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(5)) - melee_ai:start_attacking() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.exalted(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossPylon, 110) - town:wait_build(1, UnitId.ProtossPylon) - town:build(1, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.ProtossStargate, 90) - - town:build(1, UnitId.ProtossWarden, 79) - melee_ai:dynamic_wait(secs(15)) - town:build(2, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(25)) - town:build(2, UnitId.ProtossWarden, 79) - melee_ai:dynamic_wait(secs(30)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(secs(25)) - melee_ai:start_expanding() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.sorrow_fleet(melee_ai, town) - melee_ai:dynamic_wait(secs(30)) - melee_ai:start_expanding() - melee_ai:dynamic_wait(secs(15)) - town:build(2, UnitId.ProtossPylon, 90) - melee_ai:dynamic_wait(secs(15)) - melee_ai:start_expanding() - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:wait_build(1, UnitId.ProtossPylon) - town:build(1, UnitId.ProtossLattice, 90) - melee_ai:dynamic_wait(mins(1)) - town:build(1, UnitId.ProtossStargate, 90) - melee_ai:dynamic_wait(secs(40)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(secs(40)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.ships_and_swords(melee_ai, town) - melee_ai:dynamic_wait(secs(30)) - melee_ai:start_expanding() - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.ProtossPylon, 90) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(20)) - town:build(2, UnitId.ProtossPylon, 90) - melee_ai:dynamic_wait(secs(25)) - town:build(2, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(5)) - town:wait_build(2, UnitId.ProtossPylon) - town:build(1, UnitId.ProtossStargate, 90) - melee_ai:dynamic_wait(secs(30)) - melee_ai:start_attacking() -end - --- General - ----@param melee_ai MeleeAI ----@param town Town -function Openers.lunatic_legion(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossPylon, 110) - melee_ai:dynamic_wait(secs(15)) - town:wait_build(1, UnitId.ProtossPylon) - town:build(1, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(20)) - town:build(2, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(25)) - town:build(2, UnitId.ProtossPylon, 90) - wait(secs(3)) - melee_ai:start_expanding() - melee_ai:dynamic_wait(secs(40)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.matriarchy(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossPylon, 110) - town:wait_build(1, UnitId.ProtossPylon) - town:build(1, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossLattice, 90) - melee_ai:dynamic_wait(secs(15)) - town:build(2, UnitId.ProtossLattice, 90) - melee_ai:dynamic_wait(secs(40)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(secs(25)) - town:build(2, UnitId.ProtossPylon, 90) - melee_ai:dynamic_wait(secs(5)) - melee_ai:start_expanding() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.robotics_fe(melee_ai, town) - melee_ai:dynamic_wait(secs(30)) - melee_ai:start_expanding() - melee_ai:dynamic_wait(secs(30)) - town:build(1, UnitId.ProtossPylon, 90) -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.strident_striders(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossPylon, 110) - town:wait_build(1, UnitId.ProtossPylon) - town:build(1, UnitId.ProtossGateway, 90) -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.the_swordsmiths(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossPylon, 110) - town:wait_build(1, UnitId.ProtossPylon) - town:build(1, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossLattice, 90) - town:wait_build(1, UnitId.ProtossGateway) - town:wait_build(1, UnitId.ProtossLattice) - - melee_ai:dynamic_wait(secs(25)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(mins(1)) - melee_ai:start_expanding() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.worship(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossPylon, 110) - town:wait_build(1, UnitId.ProtossPylon) - town:build(1, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(25)) - town:build(2, UnitId.ProtossPylon, 90) - melee_ai:dynamic_wait(secs(40)) - town:build(1, UnitId.ProtossLattice, 90) - melee_ai:dynamic_wait(secs(40)) - town:build(2, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(40)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(secs(25)) - melee_ai:start_expanding() -end - -return Openers diff --git a/mpq/lua/melee/protoss/build/tier1.lua b/mpq/lua/melee/protoss/build/tier1.lua deleted file mode 100644 index 631173dd..00000000 --- a/mpq/lua/melee/protoss/build/tier1.lua +++ /dev/null @@ -1,199 +0,0 @@ ----@class ProtossTier1 -local Tier1 = {} - --- Ranger - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.two_gate_strider(melee_ai, town) - melee_ai:dynamic_wait(secs(45)) - town:build(4, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(5)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.one_gate_authority(melee_ai, town) - melee_ai:dynamic_wait(secs(25)) - town:build(2, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(45)) - town:build(3, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(25)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.simulant_swarm(melee_ai, town) - melee_ai:dynamic_wait(secs(20)) - town:build(5, UnitId.ProtossLattice, 90) - melee_ai:dynamic_wait(secs(20)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.the_registry(melee_ai, town) - melee_ai:dynamic_wait(secs(40)) - town:build(2, UnitId.ProtossPylon, 90) - melee_ai:dynamic_wait(secs(40)) - town:wait_build(2, UnitId.ProtossPylon) - town:build(4, UnitId.ProtossLattice, 90) - melee_ai:dynamic_wait(secs(30)) -end - --- Templar - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.three_gate_strider(melee_ai, town) - melee_ai:dynamic_wait(secs(30)) - town:build(2, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(mins(1)) - town:build(3, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(15)) - town:build(4, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(45)) - town:build(5, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(15)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.suffocating_shadow(melee_ai, town) - melee_ai:dynamic_wait(secs(20)) - town:build(2, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(45)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.legion(melee_ai, town) - melee_ai:dynamic_wait(secs(40)) - town:build(9, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(40)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.initiates(melee_ai, town) - melee_ai:dynamic_wait(secs(20)) - town:build(4, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(25)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.legions_heralds(melee_ai, town) - melee_ai:dynamic_wait(secs(20)) - town:build(2, UnitId.ProtossPylon, 90) - melee_ai:dynamic_wait(secs(15)) - town:wait_build(1, UnitId.ProtossPylon) - town:build(2, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(20)) -end - --- Skylord - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.solar_escort(melee_ai, town) - melee_ai:dynamic_wait(secs(45)) - town:wait_build(1, UnitId.ProtossPylon) - town:build(1, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(40)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.deadly_omen(melee_ai, town) - melee_ai:dynamic_wait(secs(40)) - town:build(3, UnitId.ProtossStargate, 90) - melee_ai:dynamic_wait(mins(1)) - town:build(4, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(50)) - town:build(5, UnitId.ProtossStargate, 90) - melee_ai:dynamic_wait(mins(1) + secs(40)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.two_gate_panoptus(melee_ai, town) - melee_ai:dynamic_wait(mins(1) + secs(35)) - town:build(3, UnitId.ProtossGateway, 90) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.exalted(melee_ai, town) - melee_ai:dynamic_wait(mins(1)) - town:build(3, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(mins(1)) - town:build(3, UnitId.ProtossStargate, 90) - melee_ai:dynamic_wait(secs(40)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.ships_and_swords(melee_ai, town) - melee_ai:dynamic_wait(mins(1)) - town:build(3, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(25)) - town:build(2, UnitId.ProtossStargate, 90) - melee_ai:dynamic_wait(secs(55)) - town:build(3, UnitId.ProtossStargate, 90) - melee_ai:dynamic_wait(secs(50)) -end - --- General - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.matriarchy(melee_ai, town) - melee_ai:dynamic_wait(secs(40)) - town:build(3, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(25)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.robotics_fe(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:wait_build(1, UnitId.ProtossPylon) - town:build(1, UnitId.ProtossLattice, 90) - melee_ai:dynamic_wait(secs(15)) - town:build(2, UnitId.ProtossPylon, 90) - melee_ai:dynamic_wait(secs(15)) - town:build(2, UnitId.ProtossLattice, 90) - melee_ai:dynamic_wait(secs(40)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.strident_striders(melee_ai, town) - melee_ai:dynamic_wait(secs(20)) - town:build(2, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(15)) - town:build(2, UnitId.ProtossPylon, 90) - melee_ai:dynamic_wait(secs(50)) - town:build(3, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(mins(1) + secs(45)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.the_swordsmiths(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:build(2, UnitId.ProtossPylon, 90) - melee_ai:dynamic_wait(secs(40)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.worship(melee_ai, town) - melee_ai:dynamic_wait(secs(25)) - town:build(3, UnitId.ProtossGateway, 90) - melee_ai:dynamic_wait(secs(25)) - town:build(2, UnitId.ProtossLattice, 90) - melee_ai:dynamic_wait(secs(15)) -end - -return Tier1 diff --git a/mpq/lua/melee/protoss/build/tier2.lua b/mpq/lua/melee/protoss/build/tier2.lua deleted file mode 100644 index 2956a647..00000000 --- a/mpq/lua/melee/protoss/build/tier2.lua +++ /dev/null @@ -1,179 +0,0 @@ ----@class ProtossTier2 -local Tier2 = {} - ---- Requests a Lattice and an extra Gateway. The generic tier-2 scale-up, for ---- personalities without bespoke tier-2 content. ----@param melee_ai MeleeAI ----@param town Town -function Tier2.acquire(melee_ai, town) - town:build(1, UnitId.ProtossLattice, 70, true) - melee_ai:dynamic_wait(secs(25)) - town:build(2, UnitId.ProtossGateway, 70) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.strider_lattice_library_gateway(melee_ai, town) - town:build(1, UnitId.ProtossLattice, 70) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.ProtossGrandLibrary, 70) - melee_ai:dynamic_wait(secs(15)) - town:build(5, UnitId.ProtossGateway, 70) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.emissary_ardent_lattice_gateway(melee_ai, town) - town:build(1, UnitId.ProtossArdentAuthority, 70) - melee_ai:dynamic_wait(secs(40)) - town:build(2, UnitId.ProtossLattice, 70) - wait(secs(3)) - town:build(2, UnitId.ProtossGateway, 70) - melee_ai:dynamic_wait(secs(15)) - town:build(3, UnitId.ProtossGateway, 70) - melee_ai:dynamic_wait(secs(15)) - town:build(4, UnitId.ProtossGateway, 70) - melee_ai:dynamic_wait(secs(15)) - town:build(3, UnitId.ProtossLattice, 70) - melee_ai:dynamic_wait(secs(25)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.authority_ardent_gateway_expand_lattice(melee_ai, town) - town:build(1, UnitId.ProtossArdentAuthority, 70) - melee_ai:dynamic_wait(secs(15)) - town:build(4, UnitId.ProtossGateway, 70) - wait(secs(1)) - melee_ai:dynamic_wait(secs(25)) - town:build(2, UnitId.ProtossLattice, 70) - melee_ai:dynamic_wait(secs(15)) - town:build(3, UnitId.ProtossLattice, 70) - melee_ai:dynamic_wait(secs(5)) - town:build(4, UnitId.ProtossLattice, 70) - melee_ai:dynamic_wait(secs(15)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.expo_ardent_authority(melee_ai, town) - town:build(1, UnitId.ProtossArdentAuthority, 70) - melee_ai:dynamic_wait(secs(50)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.strider3_library_expand(melee_ai, town) - town:build(1, UnitId.ProtossGrandLibrary, 70) - melee_ai:dynamic_wait(secs(20) + secs(40)) - town:build(2, UnitId.ProtossGrandLibrary, 70) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.shadow_roguegallery_expand_library(melee_ai, town) - town:build(1, UnitId.ProtossRogueGallery, 70) - town:build(2, UnitId.ProtossRogueGallery, 70) - melee_ai:dynamic_wait(secs(30) + secs(40)) - town:build(1, UnitId.ProtossGrandLibrary, 70) - melee_ai:dynamic_wait(mins(1) + secs(5)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.legion_library_x2(melee_ai, town) - town:build(1, UnitId.ProtossGrandLibrary, 70) - melee_ai:dynamic_wait(secs(15)) - town:build(2, UnitId.ProtossGrandLibrary, 70) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.martyrdom_pylon_roguegallery(melee_ai, town) - town:build(4, UnitId.ProtossPylon, 70) - wait(secs(3)) - town:build(2, UnitId.ProtossRogueGallery, 70) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.heralds_library_gateway_buildup(melee_ai, town) - town:build(1, UnitId.ProtossGrandLibrary, 70) - melee_ai:dynamic_wait(secs(20)) - town:build(3, UnitId.ProtossPylon, 70) - melee_ai:dynamic_wait(secs(15)) - town:build(3, UnitId.ProtossGateway, 70) - melee_ai:dynamic_wait(secs(40) + mins(1)) - town:build(5, UnitId.ProtossGateway, 70) - melee_ai:dynamic_wait(secs(40)) - town:build(2, UnitId.ProtossGrandLibrary, 70) - melee_ai:dynamic_wait(mins(1)) - town:build(9, UnitId.ProtossGateway, 70) - melee_ai:dynamic_wait(mins(1) + secs(55)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.escort_stargate_buildup(melee_ai, town) - town:build(1, UnitId.ProtossStargate, 70) - melee_ai:dynamic_wait(secs(5)) - town:build(2, UnitId.ProtossStargate, 70) - melee_ai:dynamic_wait(secs(45)) - town:build(3, UnitId.ProtossStargate, 70) - wait(secs(1)) - melee_ai:dynamic_wait(mins(1)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.legion_stargate_gateway_library(melee_ai, town) - town:build(1, UnitId.ProtossStargate, 70) - melee_ai:dynamic_wait(secs(20)) - town:build(2, UnitId.ProtossStargate, 70) - melee_ai:dynamic_wait(secs(40) + secs(5)) - town:build(3, UnitId.ProtossGateway, 70) - melee_ai:dynamic_wait(secs(15)) - town:build(3, UnitId.ProtossStargate, 70) - melee_ai:dynamic_wait(secs(20)) - town:build(4, UnitId.ProtossGateway, 70) - melee_ai:dynamic_wait(secs(15)) - town:build(4, UnitId.ProtossStargate, 70) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossGrandLibrary, 70) - melee_ai:dynamic_wait(secs(15)) - town:build(2, UnitId.ProtossGrandLibrary, 70) - melee_ai:dynamic_wait(secs(15)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.matriarchy_library_lattice(melee_ai, town) - town:build(1, UnitId.ProtossGrandLibrary, 70) - melee_ai:dynamic_wait(secs(15)) - town:build(3, UnitId.ProtossLattice, 70) - melee_ai:dynamic_wait(secs(25)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.robotics_ardent_x2(melee_ai, town) - town:build(1, UnitId.ProtossArdentAuthority, 70) - melee_ai:dynamic_wait(secs(40)) - town:build(2, UnitId.ProtossArdentAuthority, 70) - melee_ai:dynamic_wait(secs(40)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.swordsmiths_ardent_stargate(melee_ai, town) - town:build(1, UnitId.ProtossArdentAuthority, 70) - melee_ai:dynamic_wait(secs(50)) - town:build(1, UnitId.ProtossStargate, 70) - melee_ai:dynamic_wait(secs(40)) - town:build(2, UnitId.ProtossStargate, 70) - melee_ai:dynamic_wait(secs(40)) - town:build(2, UnitId.ProtossArdentAuthority, 70) - melee_ai:dynamic_wait(secs(25)) -end - -return Tier2 diff --git a/mpq/lua/melee/protoss/build/tier3.lua b/mpq/lua/melee/protoss/build/tier3.lua deleted file mode 100644 index 33b14a84..00000000 --- a/mpq/lua/melee/protoss/build/tier3.lua +++ /dev/null @@ -1,86 +0,0 @@ ----@class ProtossTier3 -local Tier3 = {} - ---- Requests a Prostration Stage and waits for it. The generic tier-3 tech ---- transition, for personalities without bespoke tier-3 content. ----@param melee_ai MeleeAI ----@param town Town -function Tier3.acquire(melee_ai, town) - town:build(1, UnitId.ProtossProstrationStage, 65) - melee_ai:dynamic_wait(secs(50)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier3.authority_prostration_ardent2(melee_ai, town) - town:build(1, UnitId.ProtossProstrationStage, 65) - melee_ai:dynamic_wait(secs(50)) - town:build(2, UnitId.ProtossArdentAuthority, 50) - melee_ai:dynamic_wait(mins(1) + secs(15)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier3.martyrdom_prostration_crucible(melee_ai, town) - town:build(1, UnitId.ProtossProstrationStage, 65) - melee_ai:dynamic_wait(secs(50)) - town:build(1, UnitId.ProtossCrucible, 50) - melee_ai:dynamic_wait(secs(50)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier3.escort_argosy_buildup(melee_ai, town) - town:build(1, UnitId.ProtossArgosy, 50) - melee_ai:dynamic_wait(secs(40)) - town:build(2, UnitId.ProtossArgosy, 50) - melee_ai:dynamic_wait(secs(40)) - town:build(3, UnitId.ProtossArgosy, 50) - - melee_ai:dynamic_wait(secs(25)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier3.exalted_argosy_crucible(melee_ai, town) - town:build(1, UnitId.ProtossArgosy, 50) - town:wait_build(1, UnitId.ProtossArgosy, false) - melee_ai:dynamic_wait(secs(50)) - town:build(1, UnitId.ProtossCrucible, 50) - melee_ai:dynamic_wait(secs(40)) - town:build(2, UnitId.ProtossArgosy, 50) - melee_ai:dynamic_wait(mins(1) + secs(15)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier3.fleet_argosy_buildup(melee_ai, town) - town:build(1, UnitId.ProtossArgosy, 50) - melee_ai:dynamic_wait(mins(1)) - town:build(2, UnitId.ProtossArgosy, 50) - melee_ai:dynamic_wait(secs(40)) - town:build(3, UnitId.ProtossArgosy, 50) - melee_ai:dynamic_wait(mins(1) + secs(15)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier3.legion_argosy_only(melee_ai, town) - town:build(1, UnitId.ProtossArgosy, 50) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier3.matriarchy_prostration(melee_ai, town) - town:build(1, UnitId.ProtossProstrationStage, 65) - melee_ai:dynamic_wait(mins(1) + secs(40)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier3.robotics_prostration(melee_ai, town) - town:build(1, UnitId.ProtossProstrationStage, 65) - melee_ai:dynamic_wait(mins(2) + secs(20)) -end - -return Tier3 diff --git a/mpq/lua/melee/protoss/build/tier4.lua b/mpq/lua/melee/protoss/build/tier4.lua deleted file mode 100644 index 6203bc8b..00000000 --- a/mpq/lua/melee/protoss/build/tier4.lua +++ /dev/null @@ -1,174 +0,0 @@ ----@class ProtossTier4 -local Tier4 = {} - ----@param melee_ai MeleeAI ----@param town Town -function Tier4.emissary_synthetic_synod(melee_ai, town) - town:build(1, UnitId.ProtossSyntheticSynod, 45) -end - ---- Generic tier-4 capstone for the Templar category, for personalities ---- without bespoke tier-4 content. ----@param melee_ai MeleeAI ----@param town Town -function Tier4.templar_archives_acquire(melee_ai, town) - town:build(1, UnitId.ProtossAncestralArchives, 45) - melee_ai:dynamic_wait(secs(15)) -end - ---- Generic tier-4 capstone for the Skylord category, for personalities ---- without bespoke tier-4 content. ----@param melee_ai MeleeAI ----@param town Town -function Tier4.skylord_monument_acquire(melee_ai, town) - town:build(1, UnitId.ProtossMonumentOfSin, 45) - melee_ai:dynamic_wait(secs(15)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier4.authority_synthetic_synod(melee_ai, town) - town:build(1, UnitId.ProtossSyntheticSynod, 45) - wait(secs(1)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier4.ranger_expansion(melee_ai, town) - town:build(1, UnitId.ProtossLattice, 90, true) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ProtossSyntheticSynod, 45, true) - wait(secs(1)) - town:build(1, UnitId.ProtossGateway, 90, true) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ProtossArdentAuthority, 70, true) - melee_ai:dynamic_wait(secs(40)) - town:build(1, UnitId.ProtossEmbassy, 70, true) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ProtossStargate, 70, true) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.ProtossArgosy, 50, true) - melee_ai:dynamic_wait(mins(1)) - town:build(1, UnitId.ProtossGrandLibrary, 70, true) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ProtossAncestralArchives, 45, true) - melee_ai:dynamic_wait(secs(50)) - town:build(1, UnitId.ProtossMonumentOfSin, 45, true) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier4.martyrdom_ancestral_archives_scaling(melee_ai, town) - town:build(2, UnitId.ProtossAncestralArchives, 45) - melee_ai:dynamic_wait(mins(1)) - town:wait_build(2, UnitId.ProtossAncestralArchives, false) - melee_ai:dynamic_wait(secs(25)) - town:build(4, UnitId.ProtossAncestralArchives, 45) - melee_ai:dynamic_wait(secs(45)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier4.templar_expansion(melee_ai, town) - town:build(1, UnitId.ProtossGateway, 90, true) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossGrandLibrary, 70, true) - town:build(1, UnitId.ProtossAncestralArchives, 45, true) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ProtossLattice, 90, true) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossEmbassy, 70, true) - melee_ai:dynamic_wait(secs(50)) - town:build(1, UnitId.ProtossArdentAuthority, 70, true) - town:build(1, UnitId.ProtossSyntheticSynod, 45, true) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossStargate, 70, true) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ProtossArgosy, 50, true) - melee_ai:dynamic_wait(secs(50)) - town:build(1, UnitId.ProtossMonumentOfSin, 45, true) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier4.exalted_monument_of_sin(melee_ai, town) - town:build(1, UnitId.ProtossMonumentOfSin, 45) - melee_ai:dynamic_wait(mins(1) + secs(40)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier4.fleet_monument_of_sin(melee_ai, town) - town:build(1, UnitId.ProtossMonumentOfSin, 45) - melee_ai:dynamic_wait(mins(2) + secs(45)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier4.skylord_expansion(melee_ai, town) - town:build(1, UnitId.ProtossGateway, 90, true) - town:wait_build(1, UnitId.ProtossGateway) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.ProtossStargate, 70, true) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossEmbassy, 70, true) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossArgosy, 50, true) - melee_ai:dynamic_wait(secs(5)) - town:wait_build(1, UnitId.ProtossStargate) - melee_ai:dynamic_wait(secs(50)) - town:wait_build(1, UnitId.ProtossArgosy) - melee_ai:dynamic_wait(secs(40)) - town:build(1, UnitId.ProtossLattice, 90) - melee_ai:dynamic_wait(secs(40)) - town:wait_build(1, UnitId.ProtossArgosy) - town:build(1, UnitId.ProtossMonumentOfSin, 45, true) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ProtossGrandLibrary, 70) - town:wait_build(1, UnitId.ProtossGrandLibrary) - town:build(1, UnitId.ProtossAncestralArchives, 45, true) - melee_ai:dynamic_wait(secs(25)) - town:wait_build(1, UnitId.ProtossLattice) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ProtossArdentAuthority, 70) - town:wait_build(1, UnitId.ProtossArdentAuthority) - town:build(1, UnitId.ProtossGrandLibrary, 70, true) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ProtossUnitaryUnion, 50, true) - melee_ai:dynamic_wait(secs(50)) - town:build(1, UnitId.ProtossSyntheticSynod, 45, true) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ProtossProstrationStage, 65, true) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier4.matriarchy_synthetic_synod_x2(melee_ai, town) - town:build(2, UnitId.ProtossSyntheticSynod, 45) - melee_ai:dynamic_wait(mins(1)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier4.robotics_synthetic_synod(melee_ai, town) - town:build(1, UnitId.ProtossSyntheticSynod, 45) - melee_ai:dynamic_wait(secs(15)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier4.general_expansion(melee_ai, town) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ProtossGateway, 90, true) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossEmbassy, 70, true) - melee_ai:dynamic_wait(secs(30)) - town:build(1, UnitId.ProtossLattice, 90, true) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ProtossStargate, 70, true) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ProtossGrandLibrary, 70, true) - town:build(1, UnitId.ProtossAncestralArchives, 45, true) -end - -return Tier4 diff --git a/mpq/lua/melee/protoss/general.lua b/mpq/lua/melee/protoss/general.lua deleted file mode 100644 index 043cda59..00000000 --- a/mpq/lua/melee/protoss/general.lua +++ /dev/null @@ -1,164 +0,0 @@ -local Basic = require("melee.protoss.build.basic") -local Openers = require("melee.protoss.build.openers") -local Tier1 = require("melee.protoss.build.tier1") -local Tier2 = require("melee.protoss.build.tier2") -local Tier3 = require("melee.protoss.build.tier3") -local Tier4 = require("melee.protoss.build.tier4") - -local expansion_build_order = { - Basic.build_expansion, - Tier4.general_expansion, -} -local attack_wave_cost_bias = 0.5 - -return { - ---@type AIPersonality - lunatic_legion = { - name = "General: Lunatic Legion", - unit_composition = { - -- signature units - [UnitId.ProtossLegionnaire] = 2, - [UnitId.ProtossSimulacrum] = 2, - -- filler units - [UnitId.ProtossEcclesiast] = 1, - [UnitId.ProtossAurora] = 1, - [UnitId.ProtossMagister] = 1, - [UnitId.ProtossDidact] = 1, - }, - main_build_order = { - Openers.lunatic_legion, - Tier2.legion_stargate_gateway_library, - Tier3.legion_argosy_only, - Tier4.robotics_synthetic_synod, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - matriarchy = { - name = "General: Matriarchy", - unit_composition = { - -- signature units (Prostration Stage / Synthetic Synod) - [UnitId.ProtossZealot] = 2, - [UnitId.ProtossAmaranth] = 2, - [UnitId.ProtossVassal] = 2, - -- filler units - [UnitId.ProtossEmpress] = 1, - [UnitId.ProtossAnalogue] = 1, - [UnitId.ProtossPariah] = 1, - [UnitId.ProtossMindTyrant] = 1, - }, - main_build_order = { - Openers.matriarchy, - Tier1.matriarchy, - Tier2.matriarchy_library_lattice, - Tier3.matriarchy_prostration, - Tier4.matriarchy_synthetic_synod_x2, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - robotics_fe = { - name = "General: Robotics FE", - unit_composition = { - -- signature units (Ardent Authority x2) - [UnitId.ProtossZealot] = 2, - [UnitId.ProtossVassal] = 2, - -- filler units - [UnitId.ProtossServitor] = 1, - [UnitId.ProtossPositron] = 1, - [UnitId.ProtossAccantor] = 1, - [UnitId.ProtossClarion] = 1, - }, - main_build_order = { - Openers.robotics_fe, - Tier1.robotics_fe, - Tier2.robotics_ardent_x2, - Tier3.robotics_prostration, - Tier4.robotics_synthetic_synod, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - strident_striders = { - name = "General: Strident Striders", - unit_composition = { - -- signature unit - [UnitId.ProtossDracadin] = 2, - -- filler units - [UnitId.ProtossAtreus] = 1, - }, - main_build_order = { - Openers.strident_striders, - Tier1.strident_striders, - Tier2.acquire, - Tier3.acquire, - Tier4.robotics_synthetic_synod, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - the_swordsmiths = { - name = "General: The Swordsmiths", - unit_composition = { - -- signature units (Ardent Authority x2) - [UnitId.ProtossZealot] = 2, - [UnitId.ProtossManifold] = 2, - -- filler units - [UnitId.ProtossServitor] = 1, - [UnitId.ProtossPositron] = 1, - [UnitId.ProtossAccantor] = 1, - [UnitId.ProtossClarion] = 1, - }, - main_build_order = { - Openers.the_swordsmiths, - Tier1.the_swordsmiths, - Tier2.swordsmiths_ardent_stargate, - Tier3.acquire, - Tier4.robotics_synthetic_synod, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - worship = { - name = "General: Worship", - unit_composition = { - -- signature units - [UnitId.ProtossAmaranth] = 2, - [UnitId.ProtossSimulacrum] = 2, - -- filler units - [UnitId.ProtossGolem] = 1, - [UnitId.ProtossDracadin] = 1, - }, - main_build_order = { - Openers.worship, - Tier1.worship, - Tier2.acquire, - Tier3.acquire, - Tier4.robotics_synthetic_synod, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, -} diff --git a/mpq/lua/melee/protoss/general/lunatic_legion.lua b/mpq/lua/melee/protoss/general/lunatic_legion.lua new file mode 100644 index 00000000..37f8d0a4 --- /dev/null +++ b/mpq/lua/melee/protoss/general/lunatic_legion.lua @@ -0,0 +1,72 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "General: Lunatic Legion", + unit_composition = { + -- signature units + [UnitId.ProtossLegionnaire] = 2, + [UnitId.ProtossSimulacrum] = 2, + -- filler units + [UnitId.ProtossEcclesiast] = 1, + [UnitId.ProtossAurora] = 1, + [UnitId.ProtossMagister] = 1, + [UnitId.ProtossDidact] = 1, + [UnitId.ProtossAnalogue] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(20)) + town:build(2, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossPylon, 40) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(40)) + -- tier2 + town:build(1, UnitId.ProtossStargate, 70) + melee_ai:dynamic_wait(secs(20)) + town:build(2, UnitId.ProtossStargate, 70) + melee_ai:dynamic_wait(secs(45)) + town:build(3, UnitId.ProtossGateway, 70) + melee_ai:dynamic_wait(secs(15)) + town:build(3, UnitId.ProtossStargate, 70) + melee_ai:dynamic_wait(secs(20)) + town:build(4, UnitId.ProtossGateway, 70) + melee_ai:dynamic_wait(secs(15)) + town:build(4, UnitId.ProtossStargate, 70) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossGrandLibrary, 70) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossGrandLibrary, 70) + melee_ai:dynamic_wait(secs(15)) + -- tier3 + town:build(1, UnitId.ProtossArgosy, 50) + -- tier4 + town:build(1, UnitId.ProtossSyntheticSynod, 45) + melee_ai:dynamic_wait(secs(15)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + melee_ai:dynamic_wait(secs(25)) + -- production for the Legionnaire + Simulacrum army + Stargate / Argosy fleet & Synthetic Synod + town:build(1, UnitId.ProtossGateway, 85, true) + town:build(1, UnitId.ProtossLattice, 82, true) + town:build(1, UnitId.ProtossEmbassy, 80, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ProtossStargate, 70, true) + town:build(1, UnitId.ProtossArdentAuthority, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossArgosy, 55, true) + town:build(1, UnitId.ProtossUnitaryUnion, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossSyntheticSynod, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/protoss/general/matriarchy.lua b/mpq/lua/melee/protoss/general/matriarchy.lua new file mode 100644 index 00000000..a9f56f8b --- /dev/null +++ b/mpq/lua/melee/protoss/general/matriarchy.lua @@ -0,0 +1,67 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "General: Matriarchy", + unit_composition = { + -- signature units (Prostration Stage / Synthetic Synod) + [UnitId.ProtossZealot] = 2, + [UnitId.ProtossAmaranth] = 2, + [UnitId.ProtossVassal] = 2, + -- filler units + [UnitId.ProtossEmpress] = 1, + [UnitId.ProtossAnalogue] = 1, + [UnitId.ProtossPariah] = 1, + [UnitId.ProtossMindTyrant] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(40)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(5)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(40)) + town:build(3, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(25)) + -- tier2 + town:build(1, UnitId.ProtossGrandLibrary, 70) + melee_ai:dynamic_wait(secs(15)) + town:build(3, UnitId.ProtossLattice, 70) + melee_ai:dynamic_wait(secs(25)) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(mins(1) + secs(40)) + -- tier4 + town:build(2, UnitId.ProtossSyntheticSynod, 45) + melee_ai:dynamic_wait(mins(1)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + melee_ai:dynamic_wait(secs(25)) + -- production for the Zealot / Amaranth / Vassal army + Synthetic Synod & Prostration Stage tech + town:build(1, UnitId.ProtossGateway, 85, true) + town:build(1, UnitId.ProtossLattice, 82, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + town:build(1, UnitId.ProtossArdentAuthority, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + town:build(1, UnitId.ProtossUnitaryUnion, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossSyntheticSynod, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/protoss/general/robotics_fe.lua b/mpq/lua/melee/protoss/general/robotics_fe.lua new file mode 100644 index 00000000..dcd94959 --- /dev/null +++ b/mpq/lua/melee/protoss/general/robotics_fe.lua @@ -0,0 +1,63 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "General: Robotics FE", + unit_composition = { + -- signature units (Ardent Authority x2) + [UnitId.ProtossZealot] = 2, + [UnitId.ProtossVassal] = 2, + -- filler units + [UnitId.ProtossServitor] = 1, + [UnitId.ProtossPositron] = 1, + [UnitId.ProtossAccantor] = 1, + [UnitId.ProtossClarion] = 1, + [UnitId.ProtossPariah] = 1, + [UnitId.ProtossAnalogue] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ProtossPylon, 40) + -- tier1 + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(40)) + -- tier2 + town:build(1, UnitId.ProtossArdentAuthority, 70) + melee_ai:dynamic_wait(secs(40)) + town:build(2, UnitId.ProtossArdentAuthority, 70) + melee_ai:dynamic_wait(secs(40)) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(mins(2) + secs(20)) + -- tier4 + town:build(1, UnitId.ProtossSyntheticSynod, 45) + melee_ai:dynamic_wait(secs(15)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + melee_ai:dynamic_wait(secs(25)) + -- production for the Ardent Authority core (Servitor / Positron / Accantor / Clarion) + Zealot / Vassal + town:build(1, UnitId.ProtossGateway, 85, true) + town:build(1, UnitId.ProtossLattice, 82, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ProtossArdentAuthority, 72, true) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + town:build(1, UnitId.ProtossUnitaryUnion, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossSyntheticSynod, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/protoss/general/strident_striders.lua b/mpq/lua/melee/protoss/general/strident_striders.lua new file mode 100644 index 00000000..c7ecb021 --- /dev/null +++ b/mpq/lua/melee/protoss/general/strident_striders.lua @@ -0,0 +1,58 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "General: Strident Striders", + unit_composition = { + -- signature unit + [UnitId.ProtossDracadin] = 2, + -- filler units + [UnitId.ProtossAtreus] = 1, + [UnitId.ProtossPariah] = 1, + [UnitId.ProtossAnalogue] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + town:build(1, UnitId.ProtossGateway, 90) + -- tier1 + melee_ai:dynamic_wait(secs(20)) + town:build(2, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(50)) + town:build(3, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(mins(1) + secs(45)) + -- tier2 + town:build(1, UnitId.ProtossLattice, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossGateway, 70) + town:build(1, UnitId.ProtossGrandLibrary, 70) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossSyntheticSynod, 45) + melee_ai:dynamic_wait(secs(15)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + melee_ai:dynamic_wait(secs(25)) + -- production for the Dracadin striders (+ Atreus / Pariah / Analogue) + Synthetic Synod tech + town:build(1, UnitId.ProtossGateway, 85, true) + town:build(1, UnitId.ProtossLattice, 82, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + town:build(1, UnitId.ProtossArdentAuthority, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + town:build(1, UnitId.ProtossUnitaryUnion, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossSyntheticSynod, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/protoss/general/the_swordsmiths.lua b/mpq/lua/melee/protoss/general/the_swordsmiths.lua new file mode 100644 index 00000000..5501b2e2 --- /dev/null +++ b/mpq/lua/melee/protoss/general/the_swordsmiths.lua @@ -0,0 +1,70 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "General: The Swordsmiths", + unit_composition = { + -- signature units (Ardent Authority x2) + [UnitId.ProtossZealot] = 2, + [UnitId.ProtossManifold] = 2, + -- filler units + [UnitId.ProtossServitor] = 1, + [UnitId.ProtossPositron] = 1, + [UnitId.ProtossAccantor] = 1, + [UnitId.ProtossClarion] = 1, + [UnitId.ProtossPariah] = 1, + [UnitId.ProtossAnalogue] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossLattice, 90) + town:wait_build(1, UnitId.ProtossGateway) + town:wait_build(1, UnitId.ProtossLattice) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(mins(1)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(40)) + -- tier2 + town:build(1, UnitId.ProtossArdentAuthority, 70) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossStargate, 70) + melee_ai:dynamic_wait(secs(40)) + town:build(2, UnitId.ProtossStargate, 70) + melee_ai:dynamic_wait(secs(40)) + town:build(2, UnitId.ProtossArdentAuthority, 70) + melee_ai:dynamic_wait(secs(25)) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossSyntheticSynod, 45) + melee_ai:dynamic_wait(secs(15)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + melee_ai:dynamic_wait(secs(25)) + -- production for the Zealot + Manifold + Ardent Authority core + Synthetic Synod tech + town:build(1, UnitId.ProtossGateway, 85, true) + town:build(1, UnitId.ProtossLattice, 82, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ProtossArdentAuthority, 72, true) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + town:build(1, UnitId.ProtossUnitaryUnion, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossSyntheticSynod, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/protoss/general/worship.lua b/mpq/lua/melee/protoss/general/worship.lua new file mode 100644 index 00000000..6db6e44b --- /dev/null +++ b/mpq/lua/melee/protoss/general/worship.lua @@ -0,0 +1,68 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "General: Worship", + unit_composition = { + -- signature units + [UnitId.ProtossAmaranth] = 2, + [UnitId.ProtossSimulacrum] = 2, + -- filler units + [UnitId.ProtossGolem] = 1, + [UnitId.ProtossDracadin] = 1, + [UnitId.ProtossPariah] = 1, + [UnitId.ProtossAnalogue] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(40)) + town:build(2, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(40)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(25)) + town:build(3, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(15)) + -- tier2 + town:build(1, UnitId.ProtossLattice, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossGateway, 70) + town:build(1, UnitId.ProtossGrandLibrary, 70) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossSyntheticSynod, 45) + melee_ai:dynamic_wait(secs(15)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + melee_ai:dynamic_wait(secs(25)) + -- production for the Amaranth + Simulacrum army + Synthetic Synod & Prostration Stage tech + town:build(1, UnitId.ProtossGateway, 85, true) + town:build(1, UnitId.ProtossLattice, 82, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + town:build(1, UnitId.ProtossArdentAuthority, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + town:build(1, UnitId.ProtossUnitaryUnion, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossSyntheticSynod, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/protoss/ranger.lua b/mpq/lua/melee/protoss/ranger.lua deleted file mode 100644 index b1c2f00b..00000000 --- a/mpq/lua/melee/protoss/ranger.lua +++ /dev/null @@ -1,159 +0,0 @@ -local Basic = require("melee.protoss.build.basic") -local Openers = require("melee.protoss.build.openers") -local Tier1 = require("melee.protoss.build.tier1") -local Tier2 = require("melee.protoss.build.tier2") -local Tier3 = require("melee.protoss.build.tier3") -local Tier4 = require("melee.protoss.build.tier4") - -local expansion_build_order = { - Basic.build_expansion, - Tier4.ranger_expansion, -} -local attack_wave_cost_bias = 0.5 - -return { - ---@type AIPersonality - two_gate_strider = { - name = "Ranger: 2 Gate Strider", - unit_composition = { - -- signature units - [UnitId.ProtossVassal] = 2, - [UnitId.ProtossDracadin] = 2, - -- filler units - [UnitId.ProtossIdol] = 1, - [UnitId.ProtossAccantor] = 1, - }, - main_build_order = { - Openers.two_gate_strider, - Tier1.two_gate_strider, - Tier2.strider_lattice_library_gateway, - Tier3.acquire, - Tier4.emissary_synthetic_synod, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - emissary_squared = { - name = "Ranger: Emissary Squared", - unit_composition = { - -- signature units (Synthetic Synod) - [UnitId.ProtossAnalogue] = 2, - [UnitId.ProtossDemiurge] = 2, - [UnitId.ProtossEmpress] = 2, - -- filler units - [UnitId.ProtossVassal] = 1, - [UnitId.ProtossGolem] = 1, - [UnitId.ProtossAccantor] = 1, - [UnitId.ProtossDracadin] = 1, - }, - main_build_order = { - Openers.emissary_squared, - Tier2.emissary_ardent_lattice_gateway, - Tier3.acquire, - Tier4.emissary_synthetic_synod, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - one_gate_authority = { - name = "Ranger: 1 Gate Authority", - unit_composition = { - -- signature unit - [UnitId.ProtossManifold] = 2, - -- filler units (Prostration Stage) - [UnitId.ProtossPariah] = 1, - [UnitId.ProtossPotentate] = 1, - [UnitId.ProtossSycophant] = 1, - [UnitId.ProtossMindTyrant] = 1, - [UnitId.ProtossIdol] = 1, - [UnitId.ProtossAccantor] = 1, - }, - main_build_order = { - Openers.one_gate_authority, - Tier1.one_gate_authority, - Tier2.authority_ardent_gateway_expand_lattice, - Tier3.authority_prostration_ardent2, - Tier4.authority_synthetic_synod, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - lattice_expo = { - name = "Ranger: Lattice Expo", - unit_composition = { - -- signature unit - [UnitId.ProtossSimulacrum] = 2, - -- filler units - [UnitId.ProtossIdol] = 1, - [UnitId.ProtossDracadin] = 1, - }, - main_build_order = { - Openers.lattice_expo, - Tier2.expo_ardent_authority, - Tier3.acquire, - Tier4.emissary_synthetic_synod, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - simulant_swarm = { - name = "Ranger: Simulant Swarm", - unit_composition = { - -- signature unit - [UnitId.ProtossSimulacrum] = 2, - -- filler units - [UnitId.ProtossIdol] = 1, - [UnitId.ProtossEcclesiast] = 1, - }, - main_build_order = { - Openers.simulant_swarm, - Tier1.simulant_swarm, - Tier2.acquire, - Tier3.acquire, - Tier4.emissary_synthetic_synod, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - the_registry = { - name = "Ranger: The Registry", - unit_composition = { - -- signature unit - [UnitId.ProtossManifold] = 2, - -- filler units - [UnitId.ProtossIdol] = 1, - [UnitId.ProtossAccantor] = 1, - }, - main_build_order = { - Openers.the_registry, - Tier1.the_registry, - Tier2.acquire, - Tier3.acquire, - Tier4.emissary_synthetic_synod, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, -} diff --git a/mpq/lua/melee/protoss/ranger/emissary_squared.lua b/mpq/lua/melee/protoss/ranger/emissary_squared.lua new file mode 100644 index 00000000..97f413a5 --- /dev/null +++ b/mpq/lua/melee/protoss/ranger/emissary_squared.lua @@ -0,0 +1,68 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Ranger: Emissary Squared", + unit_composition = { + -- signature units (Synthetic Synod) + [UnitId.ProtossAnalogue] = 2, + [UnitId.ProtossDemiurge] = 2, + [UnitId.ProtossEmpress] = 2, + -- filler units + [UnitId.ProtossVassal] = 1, + [UnitId.ProtossGolem] = 1, + [UnitId.ProtossAccantor] = 1, + [UnitId.ProtossDracadin] = 1, + [UnitId.ProtossPariah] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ProtossPylon, 40) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(55)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(mins(1)) + -- tier2 + town:build(1, UnitId.ProtossArdentAuthority, 70) + melee_ai:dynamic_wait(secs(40)) + town:build(2, UnitId.ProtossLattice, 70) + town:build(2, UnitId.ProtossGateway, 70) + melee_ai:dynamic_wait(secs(15)) + town:build(3, UnitId.ProtossGateway, 70) + melee_ai:dynamic_wait(secs(15)) + town:build(4, UnitId.ProtossGateway, 70) + melee_ai:dynamic_wait(secs(15)) + town:build(3, UnitId.ProtossLattice, 70) + melee_ai:dynamic_wait(secs(25)) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossSyntheticSynod, 45) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Lattice / Gateway army + Synthetic Synod & Prostration Stage tech + town:build(1, UnitId.ProtossLattice, 85, true) + town:build(1, UnitId.ProtossGateway, 82, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ProtossArdentAuthority, 70, true) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + town:build(1, UnitId.ProtossUnitaryUnion, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossSyntheticSynod, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/protoss/ranger/lattice_expo.lua b/mpq/lua/melee/protoss/ranger/lattice_expo.lua new file mode 100644 index 00000000..87e45d73 --- /dev/null +++ b/mpq/lua/melee/protoss/ranger/lattice_expo.lua @@ -0,0 +1,60 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Ranger: Lattice Expo", + unit_composition = { + -- signature unit + [UnitId.ProtossSimulacrum] = 2, + -- filler units + [UnitId.ProtossIdol] = 1, + [UnitId.ProtossDracadin] = 1, + [UnitId.ProtossAccantor] = 1, + [UnitId.ProtossPariah] = 1, + [UnitId.ProtossAnalogue] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(50)) + town:build(2, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(3, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(4, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(45)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(15)) + -- tier2 + town:build(1, UnitId.ProtossArdentAuthority, 70) + melee_ai:dynamic_wait(secs(50)) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossSyntheticSynod, 45) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Lattice / Gateway army + Synthetic Synod & Prostration Stage tech + town:build(1, UnitId.ProtossLattice, 85, true) + town:build(1, UnitId.ProtossGateway, 82, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ProtossArdentAuthority, 70, true) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + town:build(1, UnitId.ProtossUnitaryUnion, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossSyntheticSynod, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/protoss/ranger/one_gate_authority.lua b/mpq/lua/melee/protoss/ranger/one_gate_authority.lua new file mode 100644 index 00000000..09956080 --- /dev/null +++ b/mpq/lua/melee/protoss/ranger/one_gate_authority.lua @@ -0,0 +1,73 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Ranger: 1 Gate Authority", + unit_composition = { + -- signature unit + [UnitId.ProtossManifold] = 2, + -- filler units (Prostration Stage) + [UnitId.ProtossPariah] = 1, + [UnitId.ProtossPotentate] = 1, + [UnitId.ProtossSycophant] = 1, + [UnitId.ProtossMindTyrant] = 1, + [UnitId.ProtossIdol] = 1, + [UnitId.ProtossAccantor] = 1, + [UnitId.ProtossAnalogue] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(20)) + town:build(2, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_attacking() + -- tier1 + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(3, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(25)) + -- tier2 + town:build(1, UnitId.ProtossArdentAuthority, 70) + melee_ai:dynamic_wait(secs(15)) + town:build(4, UnitId.ProtossGateway, 70) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossLattice, 70) + melee_ai:dynamic_wait(secs(15)) + town:build(3, UnitId.ProtossLattice, 70) + melee_ai:dynamic_wait(secs(5)) + town:build(4, UnitId.ProtossLattice, 70) + melee_ai:dynamic_wait(secs(15)) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + town:build(2, UnitId.ProtossArdentAuthority, 50) + melee_ai:dynamic_wait(mins(1) + secs(15)) + -- tier4 + town:build(1, UnitId.ProtossSyntheticSynod, 45) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Manifold + Prostration Stage army (+ Accantor / Analogue) + town:build(1, UnitId.ProtossLattice, 85, true) + town:build(1, UnitId.ProtossGateway, 82, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ProtossArdentAuthority, 70, true) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + town:build(1, UnitId.ProtossUnitaryUnion, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossSyntheticSynod, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/protoss/ranger/simulant_swarm.lua b/mpq/lua/melee/protoss/ranger/simulant_swarm.lua new file mode 100644 index 00000000..2b8adb2f --- /dev/null +++ b/mpq/lua/melee/protoss/ranger/simulant_swarm.lua @@ -0,0 +1,67 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Ranger: Simulant Swarm", + unit_composition = { + -- signature unit + [UnitId.ProtossSimulacrum] = 2, + -- filler units + [UnitId.ProtossIdol] = 1, + [UnitId.ProtossEcclesiast] = 1, + [UnitId.ProtossAccantor] = 1, + [UnitId.ProtossPariah] = 1, + [UnitId.ProtossAnalogue] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(25)) + town:build(3, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(4, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(20)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(mins(1)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(20)) + town:build(5, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(20)) + -- tier2 + town:build(1, UnitId.ProtossLattice, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossGateway, 70) + town:build(1, UnitId.ProtossArdentAuthority, 70) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossSyntheticSynod, 45) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Simulacrum swarm + Synthetic Synod & Prostration Stage tech + town:build(1, UnitId.ProtossLattice, 85, true) + town:build(1, UnitId.ProtossGateway, 82, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ProtossArdentAuthority, 70, true) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + town:build(1, UnitId.ProtossUnitaryUnion, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossSyntheticSynod, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/protoss/ranger/the_registry.lua b/mpq/lua/melee/protoss/ranger/the_registry.lua new file mode 100644 index 00000000..bf8ab985 --- /dev/null +++ b/mpq/lua/melee/protoss/ranger/the_registry.lua @@ -0,0 +1,60 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Ranger: The Registry", + unit_composition = { + -- signature unit + [UnitId.ProtossManifold] = 2, + -- filler units + [UnitId.ProtossIdol] = 1, + [UnitId.ProtossAccantor] = 1, + [UnitId.ProtossPariah] = 1, + [UnitId.ProtossAnalogue] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(30)) + town:build(2, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(40)) + melee_ai:start_attacking() + -- tier1 + melee_ai:dynamic_wait(secs(40)) + town:build(2, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(40)) + town:build(4, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(30)) + -- tier2 + town:build(1, UnitId.ProtossLattice, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossGateway, 70) + town:build(1, UnitId.ProtossArdentAuthority, 70) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossSyntheticSynod, 45) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Manifold registry army + Synthetic Synod & Prostration Stage tech + town:build(1, UnitId.ProtossLattice, 85, true) + town:build(1, UnitId.ProtossGateway, 82, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ProtossArdentAuthority, 70, true) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + town:build(1, UnitId.ProtossUnitaryUnion, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossSyntheticSynod, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/protoss/ranger/two_gate_strider.lua b/mpq/lua/melee/protoss/ranger/two_gate_strider.lua new file mode 100644 index 00000000..9ab1b19c --- /dev/null +++ b/mpq/lua/melee/protoss/ranger/two_gate_strider.lua @@ -0,0 +1,65 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Ranger: 2 Gate Strider", + unit_composition = { + -- signature units + [UnitId.ProtossVassal] = 2, + [UnitId.ProtossDracadin] = 2, + -- filler units + [UnitId.ProtossIdol] = 1, + [UnitId.ProtossAccantor] = 1, + [UnitId.ProtossPariah] = 1, + [UnitId.ProtossAnalogue] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(20)) + town:build(2, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(30)) + town:build(3, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(mins(1)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(45)) + town:build(4, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(5)) + -- tier2 + town:build(1, UnitId.ProtossLattice, 70) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ProtossGrandLibrary, 70) + melee_ai:dynamic_wait(secs(15)) + town:build(5, UnitId.ProtossGateway, 70) + town:build(1, UnitId.ProtossArdentAuthority, 70) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossSyntheticSynod, 45) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Vassal + Dracadin striders + Synthetic Synod & Prostration Stage tech + town:build(1, UnitId.ProtossGateway, 85, true) + town:build(1, UnitId.ProtossLattice, 82, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ProtossArdentAuthority, 70, true) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + town:build(1, UnitId.ProtossUnitaryUnion, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossSyntheticSynod, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/protoss/skylord.lua b/mpq/lua/melee/protoss/skylord.lua deleted file mode 100644 index 9b9d7729..00000000 --- a/mpq/lua/melee/protoss/skylord.lua +++ /dev/null @@ -1,164 +0,0 @@ -local Basic = require("melee.protoss.build.basic") -local Openers = require("melee.protoss.build.openers") -local Tier1 = require("melee.protoss.build.tier1") -local Tier2 = require("melee.protoss.build.tier2") -local Tier3 = require("melee.protoss.build.tier3") -local Tier4 = require("melee.protoss.build.tier4") - -local expansion_build_order = { - Basic.build_expansion, - Tier4.skylord_expansion, -} -local attack_wave_cost_bias = 0.6 - -return { - ---@type AIPersonality - solar_escort = { - name = "Skylord: Solar Escort", - unit_composition = { - -- signature units - [UnitId.ProtossSolarion] = 2, - [UnitId.ProtossLegionnaire] = 2, - [UnitId.ProtossVassal] = 2, - -- filler units - [UnitId.ProtossEcclesiast] = 1, - [UnitId.ProtossPanoptus] = 1, - [UnitId.ProtossGladius] = 1, - [UnitId.ProtossEmpyrean] = 1, - }, - main_build_order = { - Openers.solar_escort, - Tier1.solar_escort, - Tier2.escort_stargate_buildup, - Tier3.escort_argosy_buildup, - Tier4.skylord_monument_acquire, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - deadly_omen = { - name = "Skylord: Deadly Omen", - unit_composition = { - -- signature units - [UnitId.ProtossZealot] = 2, - [UnitId.ProtossVassal] = 2, - -- filler units - [UnitId.ProtossPanoptus] = 1, - [UnitId.ProtossExemplar] = 1, - }, - main_build_order = { - Openers.deadly_omen, - Tier1.deadly_omen, - Tier2.acquire, - Tier3.acquire, - Tier4.skylord_monument_acquire, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - two_gate_panoptus = { - name = "Skylord: 2 Gate Panoptus", - unit_composition = { - -- signature units - [UnitId.ProtossPanoptus] = 3, - [UnitId.ProtossVassal] = 2, - -- filler units - [UnitId.ProtossHierophant] = 1, - }, - main_build_order = { - Openers.two_gate_panoptus, - Tier1.two_gate_panoptus, - Tier2.acquire, - Tier3.acquire, - Tier4.skylord_monument_acquire, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - exalted = { - name = "Skylord: Exalted", - unit_composition = { - -- signature units (Monument of Sin) - [UnitId.ProtossVassal] = 2, - [UnitId.ProtossStarSovereign] = 2, - [UnitId.ProtossAnthelion] = 2, - -- filler units - [UnitId.ProtossPanoptus] = 1, - [UnitId.ProtossExemplar] = 1, - [UnitId.ProtossDidact] = 1, - }, - main_build_order = { - Openers.exalted, - Tier1.exalted, - Tier2.acquire, - Tier3.exalted_argosy_crucible, - Tier4.exalted_monument_of_sin, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - sorrow_fleet = { - name = "Skylord: Sorrow Fleet", - unit_composition = { - -- signature units (Monument of Sin) - [UnitId.ProtossVassal] = 2, - [UnitId.ProtossStarSovereign] = 2, - [UnitId.ProtossAnthelion] = 1.5, - -- filler units - [UnitId.ProtossPanoptus] = 1, - [UnitId.ProtossGladius] = 1, - [UnitId.ProtossEmpyrean] = 1, - }, - main_build_order = { - Openers.sorrow_fleet, - Tier2.acquire, - Tier3.fleet_argosy_buildup, - Tier4.fleet_monument_of_sin, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - ships_and_swords = { - name = "Skylord: Ships and Swords", - unit_composition = { - -- signature units - [UnitId.ProtossVassal] = 2, - [UnitId.ProtossAurora] = 1.5, - [UnitId.ProtossMagister] = 1.5, - -- filler units - [UnitId.ProtossGladius] = 1, - [UnitId.ProtossStarSovereign] = 1, - }, - main_build_order = { - Openers.ships_and_swords, - Tier1.ships_and_swords, - Tier2.acquire, - Tier3.acquire, - Tier4.skylord_monument_acquire, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, -} diff --git a/mpq/lua/melee/protoss/skylord/deadly_omen.lua b/mpq/lua/melee/protoss/skylord/deadly_omen.lua new file mode 100644 index 00000000..31538a5c --- /dev/null +++ b/mpq/lua/melee/protoss/skylord/deadly_omen.lua @@ -0,0 +1,71 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Skylord: Deadly Omen", + unit_composition = { + -- signature units + [UnitId.ProtossZealot] = 2, + [UnitId.ProtossVassal] = 2, + -- filler units + [UnitId.ProtossPanoptus] = 1, + [UnitId.ProtossExemplar] = 1, + [UnitId.ProtossPariah] = 1, + [UnitId.ProtossStarSovereign] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossStargate, 90) + melee_ai:dynamic_wait(secs(40)) + town:build(2, UnitId.ProtossStargate, 90) + town:wait_build(1, UnitId.ProtossStargate) + melee_ai:start_attacking() + melee_ai:dynamic_wait(mins(1)) + town:build(2, UnitId.ProtossPylon, 40) + town:build(2, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(40)) + town:build(3, UnitId.ProtossStargate, 90) + melee_ai:dynamic_wait(mins(1)) + town:build(4, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(50)) + town:build(5, UnitId.ProtossStargate, 90) + melee_ai:dynamic_wait(mins(1) + secs(40)) + -- tier2 + town:build(1, UnitId.ProtossLattice, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossGateway, 70) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossMonumentOfSin, 45) + melee_ai:dynamic_wait(secs(15)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Zealot + Vassal + Panoptus army (-> Argosy -> Monument of Sin) + Pariah tech + town:build(1, UnitId.ProtossGateway, 85, true) + town:build(1, UnitId.ProtossLattice, 80, true) + town:build(1, UnitId.ProtossEmbassy, 78, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ProtossStargate, 70, true) + town:build(1, UnitId.ProtossGrandLibrary, 68, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossArgosy, 55, true) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossMonumentOfSin, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/protoss/skylord/exalted.lua b/mpq/lua/melee/protoss/skylord/exalted.lua new file mode 100644 index 00000000..c91cf19f --- /dev/null +++ b/mpq/lua/melee/protoss/skylord/exalted.lua @@ -0,0 +1,73 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Skylord: Exalted", + unit_composition = { + -- signature units (Monument of Sin) + [UnitId.ProtossVassal] = 2, + [UnitId.ProtossStarSovereign] = 2, + [UnitId.ProtossAnthelion] = 2, + -- filler units + [UnitId.ProtossPanoptus] = 1, + [UnitId.ProtossExemplar] = 1, + [UnitId.ProtossDidact] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ProtossStargate, 90) + town:build(1, UnitId.ProtossWarden, 79) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossWarden, 79) + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(mins(1)) + town:build(3, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(mins(1)) + town:build(3, UnitId.ProtossStargate, 90) + melee_ai:dynamic_wait(secs(40)) + -- tier2 + town:build(1, UnitId.ProtossLattice, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossGateway, 70) + -- tier3 + town:build(1, UnitId.ProtossArgosy, 50) + town:wait_build(1, UnitId.ProtossArgosy, false) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossCrucible, 50) + melee_ai:dynamic_wait(secs(40)) + town:build(2, UnitId.ProtossArgosy, 50) + melee_ai:dynamic_wait(mins(1) + secs(15)) + -- tier4 + town:build(1, UnitId.ProtossMonumentOfSin, 45) + melee_ai:dynamic_wait(mins(1) + secs(40)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the exalted capital fleet (Star Sovereign / Anthelion / Didact) + Crucible + town:build(1, UnitId.ProtossGateway, 85, true) + town:build(1, UnitId.ProtossLattice, 80, true) + town:build(1, UnitId.ProtossEmbassy, 78, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ProtossStargate, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossArgosy, 55, true) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ProtossCrucible, 50, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ProtossMonumentOfSin, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/protoss/skylord/ships_and_swords.lua b/mpq/lua/melee/protoss/skylord/ships_and_swords.lua new file mode 100644 index 00000000..7dd67ae6 --- /dev/null +++ b/mpq/lua/melee/protoss/skylord/ships_and_swords.lua @@ -0,0 +1,67 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Skylord: Ships and Swords", + unit_composition = { + -- signature units + [UnitId.ProtossVassal] = 2, + [UnitId.ProtossAurora] = 1.5, + [UnitId.ProtossMagister] = 1.5, + -- filler units + [UnitId.ProtossGladius] = 1, + [UnitId.ProtossStarSovereign] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(20)) + town:build(2, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(5)) + town:build(1, UnitId.ProtossStargate, 90) + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_attacking() + -- tier1 + melee_ai:dynamic_wait(mins(1)) + town:build(3, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossStargate, 90) + melee_ai:dynamic_wait(secs(55)) + town:build(3, UnitId.ProtossStargate, 90) + melee_ai:dynamic_wait(secs(50)) + -- tier2 + town:build(1, UnitId.ProtossLattice, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossGateway, 70) + -- tier3 + town:build(1, UnitId.ProtossArgosy, 50) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossMonumentOfSin, 45) + melee_ai:dynamic_wait(secs(15)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Stargate + Argosy fleet (Aurora / Magister / Gladius) -> Monument of Sin + town:build(1, UnitId.ProtossGateway, 85, true) + town:build(1, UnitId.ProtossLattice, 80, true) + town:build(1, UnitId.ProtossEmbassy, 78, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ProtossStargate, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossArgosy, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossMonumentOfSin, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/protoss/skylord/solar_escort.lua b/mpq/lua/melee/protoss/skylord/solar_escort.lua new file mode 100644 index 00000000..7b7519a2 --- /dev/null +++ b/mpq/lua/melee/protoss/skylord/solar_escort.lua @@ -0,0 +1,63 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Skylord: Solar Escort", + unit_composition = { + -- signature units + [UnitId.ProtossSolarion] = 2, + [UnitId.ProtossLegionnaire] = 2, + [UnitId.ProtossVassal] = 2, + -- filler units + [UnitId.ProtossEcclesiast] = 1, + [UnitId.ProtossPanoptus] = 1, + [UnitId.ProtossGladius] = 1, + [UnitId.ProtossEmpyrean] = 1, + [UnitId.ProtossStarSovereign] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(40)) + -- tier2 + town:build(1, UnitId.ProtossStargate, 70) + melee_ai:dynamic_wait(secs(5)) + town:build(2, UnitId.ProtossStargate, 70) + melee_ai:dynamic_wait(secs(45)) + town:build(3, UnitId.ProtossStargate, 70) + melee_ai:dynamic_wait(mins(1)) + -- tier3 + town:build(1, UnitId.ProtossArgosy, 50) + melee_ai:dynamic_wait(secs(40)) + town:build(2, UnitId.ProtossArgosy, 50) + melee_ai:dynamic_wait(secs(40)) + town:build(3, UnitId.ProtossArgosy, 50) + melee_ai:dynamic_wait(secs(25)) + -- tier4 + town:build(1, UnitId.ProtossMonumentOfSin, 45) + melee_ai:dynamic_wait(secs(15)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Solarion + Vassal escort (Stargate -> Argosy -> Monument of Sin) + Gateway + town:build(1, UnitId.ProtossGateway, 85, true) + town:build(1, UnitId.ProtossLattice, 80, true) + town:build(1, UnitId.ProtossEmbassy, 78, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ProtossStargate, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossArgosy, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossMonumentOfSin, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/protoss/skylord/sorrow_fleet.lua b/mpq/lua/melee/protoss/skylord/sorrow_fleet.lua new file mode 100644 index 00000000..f5f1957d --- /dev/null +++ b/mpq/lua/melee/protoss/skylord/sorrow_fleet.lua @@ -0,0 +1,63 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Skylord: Sorrow Fleet", + unit_composition = { + -- signature units (Monument of Sin) + [UnitId.ProtossVassal] = 2, + [UnitId.ProtossStarSovereign] = 2, + [UnitId.ProtossAnthelion] = 1.5, + -- filler units + [UnitId.ProtossPanoptus] = 1, + [UnitId.ProtossGladius] = 1, + [UnitId.ProtossEmpyrean] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(mins(1)) + town:build(1, UnitId.ProtossStargate, 90) + melee_ai:dynamic_wait(secs(40)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(40)) + -- tier2 + town:build(1, UnitId.ProtossLattice, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossGateway, 70) + -- tier3 + town:build(1, UnitId.ProtossArgosy, 50) + melee_ai:dynamic_wait(mins(1)) + town:build(2, UnitId.ProtossArgosy, 50) + melee_ai:dynamic_wait(secs(40)) + town:build(3, UnitId.ProtossArgosy, 50) + melee_ai:dynamic_wait(mins(1) + secs(15)) + -- tier4 + town:build(1, UnitId.ProtossMonumentOfSin, 45) + melee_ai:dynamic_wait(mins(2) + secs(45)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Monument of Sin fleet (Star Sovereign / Anthelion) + Stargate / Argosy + town:build(1, UnitId.ProtossGateway, 85, true) + town:build(1, UnitId.ProtossLattice, 80, true) + town:build(1, UnitId.ProtossEmbassy, 78, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ProtossStargate, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossArgosy, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossMonumentOfSin, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/protoss/skylord/two_gate_panoptus.lua b/mpq/lua/melee/protoss/skylord/two_gate_panoptus.lua new file mode 100644 index 00000000..cbc42494 --- /dev/null +++ b/mpq/lua/melee/protoss/skylord/two_gate_panoptus.lua @@ -0,0 +1,62 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Skylord: 2 Gate Panoptus", + unit_composition = { + -- signature units + [UnitId.ProtossPanoptus] = 3, + [UnitId.ProtossVassal] = 2, + -- filler units + [UnitId.ProtossHierophant] = 1, + [UnitId.ProtossPariah] = 1, + [UnitId.ProtossStarSovereign] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossStargate, 90) + melee_ai:dynamic_wait(secs(50)) + town:build(2, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(5)) + melee_ai:start_attacking() + -- tier1 + melee_ai:dynamic_wait(mins(1) + secs(35)) + town:build(3, UnitId.ProtossGateway, 90) + -- tier2 + town:build(1, UnitId.ProtossLattice, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossGateway, 70) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossMonumentOfSin, 45) + melee_ai:dynamic_wait(secs(15)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Panoptus + Vassal army (-> Argosy -> Monument of Sin) + Hierophant / Pariah tech + town:build(1, UnitId.ProtossGateway, 85, true) + town:build(1, UnitId.ProtossLattice, 80, true) + town:build(1, UnitId.ProtossEmbassy, 78, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ProtossStargate, 70, true) + town:build(1, UnitId.ProtossGrandLibrary, 68, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossArgosy, 55, true) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossMonumentOfSin, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/protoss/templar.lua b/mpq/lua/melee/protoss/templar.lua deleted file mode 100644 index efe3e4df..00000000 --- a/mpq/lua/melee/protoss/templar.lua +++ /dev/null @@ -1,163 +0,0 @@ -local Basic = require("melee.protoss.build.basic") -local Openers = require("melee.protoss.build.openers") -local Tier1 = require("melee.protoss.build.tier1") -local Tier2 = require("melee.protoss.build.tier2") -local Tier3 = require("melee.protoss.build.tier3") -local Tier4 = require("melee.protoss.build.tier4") - -local expansion_build_order = { - Basic.build_expansion, - Tier4.templar_expansion, -} -local attack_wave_cost_bias = 0.4 - -return { - ---@type AIPersonality - three_gate_strider = { - name = "Templar: 3 Gate Strider", - unit_composition = { - -- signature unit - [UnitId.ProtossLegionnaire] = 2, - -- filler units - [UnitId.ProtossAccantor] = 1, - [UnitId.ProtossDracadin] = 1, - [UnitId.ProtossArchon] = 1, - }, - main_build_order = { - Openers.three_gate_strider, - Tier1.three_gate_strider, - Tier2.strider3_library_expand, - Tier3.acquire, - Tier4.templar_archives_acquire, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - suffocating_shadow = { - name = "Templar: Suffocating Shadow", - unit_composition = { - -- signature units (Rogue Gallery) - [UnitId.ProtossVagrant] = 2, - [UnitId.ProtossCabalist] = 2, - [UnitId.ProtossCharlatan] = 2, - [UnitId.ProtossBarghest] = 2, - [UnitId.ProtossZealot] = 2, - -- filler units - [UnitId.ProtossAtreus] = 1, - [UnitId.ProtossEcclesiast] = 1, - }, - main_build_order = { - Openers.suffocating_shadow, - Tier1.suffocating_shadow, - Tier2.shadow_roguegallery_expand_library, - Tier3.acquire, - Tier4.templar_archives_acquire, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - legion = { - name = "Templar: Legion", - unit_composition = { - -- signature unit - [UnitId.ProtossLegionnaire] = 2, - -- filler units - [UnitId.ProtossEcclesiast] = 1, - [UnitId.ProtossArchon] = 1, - }, - main_build_order = { - Openers.legion, - Tier1.legion, - Tier2.legion_library_x2, - Tier3.acquire, - Tier4.templar_archives_acquire, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - initiates = { - name = "Templar: Initiates", - unit_composition = { - -- signature unit - [UnitId.ProtossZealot] = 2, - -- filler units - [UnitId.ProtossEcclesiast] = 1, - [UnitId.ProtossCantavis] = 1, - [UnitId.ProtossAccantor] = 1, - [UnitId.ProtossArchon] = 1, - }, - main_build_order = { - Openers.initiates, - Tier1.initiates, - Tier2.acquire, - Tier3.acquire, - Tier4.templar_archives_acquire, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - martyrdom = { - name = "Templar: Martyrdom", - unit_composition = { - -- signature units (Ancestral Archives x4) - [UnitId.ProtossArchon] = 2, - [UnitId.ProtossLegionnaire] = 2, - -- filler units - [UnitId.ProtossAtreus] = 1, - [UnitId.ProtossMindTyrant] = 1, - [UnitId.ProtossOptecton] = 1, - [UnitId.ProtossPatriarch] = 1, - }, - main_build_order = { - Openers.martyrdom, - Tier2.martyrdom_pylon_roguegallery, - Tier3.martyrdom_prostration_crucible, - Tier4.martyrdom_ancestral_archives_scaling, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - legions_heralds = { - name = "Templar: Legion's Heralds", - unit_composition = { - -- signature unit - [UnitId.ProtossLegionnaire] = 2, - -- filler units - [UnitId.ProtossEcclesiast] = 1, - [UnitId.ProtossAtreus] = 1, - [UnitId.ProtossHerald] = 1, - [UnitId.ProtossPatriarch] = 1, - }, - main_build_order = { - Openers.legions_heralds, - Tier1.legions_heralds, - Tier2.heralds_library_gateway_buildup, - Tier3.acquire, - Tier4.templar_archives_acquire, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, -} diff --git a/mpq/lua/melee/protoss/templar/initiates.lua b/mpq/lua/melee/protoss/templar/initiates.lua new file mode 100644 index 00000000..461c64db --- /dev/null +++ b/mpq/lua/melee/protoss/templar/initiates.lua @@ -0,0 +1,66 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Templar: Initiates", + unit_composition = { + -- signature unit + [UnitId.ProtossZealot] = 2, + -- filler units + [UnitId.ProtossEcclesiast] = 1, + [UnitId.ProtossCantavis] = 1, + [UnitId.ProtossAccantor] = 1, + [UnitId.ProtossArchon] = 1, + [UnitId.ProtossPariah] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossPylon, 40) + town:wait_build(2, UnitId.ProtossGateway) + melee_ai:dynamic_wait(secs(10)) + town:build(3, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(40)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(20)) + town:build(4, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(25)) + -- tier2 + town:build(1, UnitId.ProtossLattice, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossGateway, 70) + town:build(1, UnitId.ProtossGrandLibrary, 70) + town:build(1, UnitId.ProtossArdentAuthority, 70) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossAncestralArchives, 45) + melee_ai:dynamic_wait(secs(15)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Zealot core (+ Cantavis / Accantor / Archon / Pariah) + town:build(1, UnitId.ProtossGateway, 85, true) + town:build(1, UnitId.ProtossLattice, 80, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + town:build(1, UnitId.ProtossArdentAuthority, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossAncestralArchives, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/protoss/templar/legion.lua b/mpq/lua/melee/protoss/templar/legion.lua new file mode 100644 index 00000000..547a4ce4 --- /dev/null +++ b/mpq/lua/melee/protoss/templar/legion.lua @@ -0,0 +1,68 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Templar: Legion", + unit_composition = { + -- signature unit + [UnitId.ProtossLegionnaire] = 2, + -- filler units + [UnitId.ProtossEcclesiast] = 1, + [UnitId.ProtossArchon] = 1, + [UnitId.ProtossAtreus] = 1, + [UnitId.ProtossPariah] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(35)) + town:build(3, UnitId.ProtossGateway, 90) + town:build(3, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(30)) + town:build(4, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(5, UnitId.ProtossGateway, 90) + town:build(4, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(20)) + town:build(6, UnitId.ProtossGateway, 90) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(40)) + town:build(9, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(40)) + -- tier2 + town:build(1, UnitId.ProtossGrandLibrary, 70) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossGrandLibrary, 70) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossAncestralArchives, 45) + melee_ai:dynamic_wait(secs(15)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Legionnaire core (Gateway -> Grand Library -> Ancestral Archives) + town:build(1, UnitId.ProtossGateway, 85, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossAncestralArchives, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/protoss/templar/legions_heralds.lua b/mpq/lua/melee/protoss/templar/legions_heralds.lua new file mode 100644 index 00000000..e4c85b99 --- /dev/null +++ b/mpq/lua/melee/protoss/templar/legions_heralds.lua @@ -0,0 +1,64 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Templar: Legion's Heralds", + unit_composition = { + -- signature unit + [UnitId.ProtossLegionnaire] = 2, + -- filler units + [UnitId.ProtossEcclesiast] = 1, + [UnitId.ProtossAtreus] = 1, + [UnitId.ProtossHerald] = 1, + [UnitId.ProtossPatriarch] = 1, + [UnitId.ProtossPariah] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(20)) + town:build(2, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(20)) + -- tier2 + town:build(1, UnitId.ProtossGrandLibrary, 70) + melee_ai:dynamic_wait(secs(20)) + town:build(3, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(3, UnitId.ProtossGateway, 70) + melee_ai:dynamic_wait(secs(40) + mins(1)) + town:build(5, UnitId.ProtossGateway, 70) + melee_ai:dynamic_wait(secs(40)) + town:build(2, UnitId.ProtossGrandLibrary, 70) + melee_ai:dynamic_wait(mins(1)) + town:build(9, UnitId.ProtossGateway, 70) + melee_ai:dynamic_wait(mins(1) + secs(55)) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossAncestralArchives, 45) + melee_ai:dynamic_wait(secs(15)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Legionnaire + Herald / Patriarch core (Gateway -> Grand Library -> Ancestral Archives) + town:build(1, UnitId.ProtossGateway, 85, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossAncestralArchives, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/protoss/templar/martyrdom.lua b/mpq/lua/melee/protoss/templar/martyrdom.lua new file mode 100644 index 00000000..b6036720 --- /dev/null +++ b/mpq/lua/melee/protoss/templar/martyrdom.lua @@ -0,0 +1,67 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Templar: Martyrdom", + unit_composition = { + -- signature units (Ancestral Archives x4) + [UnitId.ProtossArchon] = 2, + [UnitId.ProtossLegionnaire] = 2, + -- filler units + [UnitId.ProtossAtreus] = 1, + [UnitId.ProtossMindTyrant] = 1, + [UnitId.ProtossOptecton] = 1, + [UnitId.ProtossPatriarch] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(3, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(3, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(40)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(mins(2) + secs(30)) + -- tier2 + town:build(4, UnitId.ProtossPylon, 40) + town:build(2, UnitId.ProtossRogueGallery, 70) + town:build(1, UnitId.ProtossGrandLibrary, 70) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossCrucible, 50) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(2, UnitId.ProtossAncestralArchives, 45) + melee_ai:dynamic_wait(mins(1)) + town:wait_build(2, UnitId.ProtossAncestralArchives, false) + melee_ai:dynamic_wait(secs(25)) + town:build(4, UnitId.ProtossAncestralArchives, 45) + melee_ai:dynamic_wait(secs(45)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Ancestral Archives martyrs (Archon / Optecton / Patriarch + Legionnaire) + town:build(1, UnitId.ProtossGateway, 85, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ProtossCrucible, 50, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ProtossAncestralArchives, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/protoss/templar/suffocating_shadow.lua b/mpq/lua/melee/protoss/templar/suffocating_shadow.lua new file mode 100644 index 00000000..5bb0131d --- /dev/null +++ b/mpq/lua/melee/protoss/templar/suffocating_shadow.lua @@ -0,0 +1,59 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Templar: Suffocating Shadow", + unit_composition = { + -- signature units (Rogue Gallery) + [UnitId.ProtossVagrant] = 2, + [UnitId.ProtossCabalist] = 2, + [UnitId.ProtossCharlatan] = 2, + [UnitId.ProtossBarghest] = 2, + [UnitId.ProtossZealot] = 2, + -- filler units + [UnitId.ProtossAtreus] = 1, + [UnitId.ProtossEcclesiast] = 1, + [UnitId.ProtossPariah] = 1, + [UnitId.ProtossArchon] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossGateway, 90) + -- tier1 + melee_ai:dynamic_wait(secs(20)) + town:build(2, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(45)) + -- tier2 + town:build(1, UnitId.ProtossRogueGallery, 70) + town:build(2, UnitId.ProtossRogueGallery, 70) + melee_ai:dynamic_wait(secs(30) + secs(40)) + town:build(1, UnitId.ProtossGrandLibrary, 70) + melee_ai:dynamic_wait(mins(1) + secs(5)) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossAncestralArchives, 45) + melee_ai:dynamic_wait(secs(15)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Rogue Gallery shadow army (Vagrant / Cabalist / Charlatan / Barghest + Zealot) + town:build(1, UnitId.ProtossGateway, 85, true) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossRogueGallery, 75, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossAncestralArchives, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/protoss/templar/three_gate_strider.lua b/mpq/lua/melee/protoss/templar/three_gate_strider.lua new file mode 100644 index 00000000..447699e5 --- /dev/null +++ b/mpq/lua/melee/protoss/templar/three_gate_strider.lua @@ -0,0 +1,60 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Templar: 3 Gate Strider", + unit_composition = { + -- signature unit + [UnitId.ProtossLegionnaire] = 2, + -- filler units + [UnitId.ProtossAccantor] = 1, + [UnitId.ProtossDracadin] = 1, + [UnitId.ProtossArchon] = 1, + [UnitId.ProtossPariah] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossGateway, 90) + -- tier1 + melee_ai:dynamic_wait(secs(30)) + town:build(2, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(mins(1)) + town:build(3, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(4, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(5, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(15)) + -- tier2 + town:build(1, UnitId.ProtossGrandLibrary, 70) + melee_ai:dynamic_wait(mins(1)) + town:build(2, UnitId.ProtossGrandLibrary, 70) + town:build(1, UnitId.ProtossArdentAuthority, 70) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossAncestralArchives, 45) + melee_ai:dynamic_wait(secs(15)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Legionnaire striders (+ Accantor / Dracadin / Archon / Pariah) + town:build(1, UnitId.ProtossGateway, 85, true) + town:build(1, UnitId.ProtossLattice, 80, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + town:build(1, UnitId.ProtossArdentAuthority, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossAncestralArchives, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/terran/armor.lua b/mpq/lua/melee/terran/armor.lua deleted file mode 100644 index d24303f2..00000000 --- a/mpq/lua/melee/terran/armor.lua +++ /dev/null @@ -1,164 +0,0 @@ -local Basic = require("melee.terran.build.basic") -local Openers = require("melee.terran.build.openers") -local Tier1 = require("melee.terran.build.tier1") -local Tier2 = require("melee.terran.build.tier2") -local Tier3 = require("melee.terran.build.tier3") - -local expansion_build_order = { - Basic.build_expansion, - Tier2.acquire, - Tier2.fulcrum_buildup, - Tier3.acquire, -} -local attack_wave_cost_bias = 0.6 - -return { - ---@type AIPersonality - tank_push = { - name = "Armor: Tank Push", - unit_composition = { - -- signature units - [UnitId.TerranMatadorTankMode] = 2, - [UnitId.TerranPhalanxTankMode] = 2, - -- healers - [UnitId.TerranCleric] = 1, - -- filler units - [UnitId.TerranCyprian] = 1, - [UnitId.TerranBlackjack] = 1, - [UnitId.TerranMadrigalImperiosoMode] = 1, - }, - main_build_order = { - Openers.tank_push, - Tier2.acquire, - Tier2.stockade_requeue, - Tier3.acquire, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - two_fulc_vulture = { - name = "Armor: 2Fulc Vulture", - unit_composition = { - -- signature unit - [UnitId.TerranVulture] = 3, - -- filler units - [UnitId.TerranMaverick] = 1, - [UnitId.TerranCyclops] = 1, - }, - main_build_order = { - Openers.two_fulc_vulture, - Tier1.two_fulc_vulture, - Tier2.acquire, - Tier3.acquire, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - fe_five_fulc = { - name = "Armor: FE 5Fulc", - unit_composition = { - -- signature units - [UnitId.TerranVulture] = 2, - [UnitId.TerranBlackjack] = 2, - [UnitId.TerranPhalanxTankMode] = 2, - -- filler units - [UnitId.TerranMaverick] = 1, - [UnitId.TerranAzazel] = 1, - [UnitId.TerranSeraph] = 1, - }, - main_build_order = { - Openers.fe_five_fulc, - Tier1.fe_five_fulc, - Tier2.starport_commandment_buildup, - Tier2.acquire, - Tier3.acquire, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - david_and_goliath = { - name = "Armor: David and Goliath", - unit_composition = { - -- signature units - [UnitId.TerranGoliath] = 3, - [UnitId.TerranMaverick] = 2, - -- filler units - [UnitId.TerranMatadorTankMode] = 1, - [UnitId.TerranPhalanxTankMode] = 1, - [UnitId.TerranWraith] = 1, - [UnitId.TerranBlackjack] = 1, - }, - main_build_order = { - Openers.david_and_goliath, - Tier1.david_and_goliath, - Tier2.acquire, - Tier2.fulcrum_scaling, - Tier3.acquire, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - iron_crusade = { - name = "Armor: Iron Crusade", - unit_composition = { - -- signature units (Iron Foundry x4 is the real investment of this build) - [UnitId.TerranPaladin] = 3, - [UnitId.TerranCuirassTankMode] = 2, - [UnitId.TerranPazuzu] = 2, - -- filler units - [UnitId.TerranVulture] = 1, - [UnitId.TerranWraith] = 1, - }, - main_build_order = { - Openers.expand_first, - Tier1.iron_crusade, - Tier2.acquire, - Tier2.fulcrum_buildup, - Tier3.acquire, - Tier3.iron_foundries, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - walker_power = { - name = "Armor: Walker Power", - unit_composition = { - -- signature units (walkers) - [UnitId.TerranGoliath] = 3, - [UnitId.TerranCyclops] = 2, - [UnitId.TerranBlackjack] = 2, - -- filler units - [UnitId.TerranPhalanxTankMode] = 1, - [UnitId.TerranMaverick] = 1, - }, - main_build_order = { - Openers.walker_power, - Tier2.acquire, - Tier3.acquire, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, -} diff --git a/mpq/lua/melee/terran/armor/david_and_goliath.lua b/mpq/lua/melee/terran/armor/david_and_goliath.lua new file mode 100644 index 00000000..dfc5ed9f --- /dev/null +++ b/mpq/lua/melee/terran/armor/david_and_goliath.lua @@ -0,0 +1,97 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Armor: David and Goliath", + unit_composition = { + -- signature units + [UnitId.TerranGoliath] = 3, + [UnitId.TerranMaverick] = 2, + -- filler units + [UnitId.TerranMatadorTankMode] = 1, + [UnitId.TerranPhalanxTankMode] = 1, + [UnitId.TerranWraith] = 1, + [UnitId.TerranBlackjack] = 1, + [UnitId.TerranRamesses] = 1, + [UnitId.TerranCuirassTankMode] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranFulcrum, 110) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(40)) + town:build(2, UnitId.TerranStockade, 90) + town:wait_build(2, UnitId.TerranStockade, false) + melee_ai:dynamic_wait(secs(15)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(30)) + town:build(2, UnitId.TerranFulcrum, 90) + town:wait_build(2, UnitId.TerranFulcrum, false) + town:multirun(function(town) + town:wait_build(2, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranScrapyard, 89) + town:wait_build(2, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranPalladium, 89) + melee_ai:dynamic_wait(secs(5)) + town:wait_build(3, UnitId.TerranFulcrum) + town:build(2, UnitId.TerranPalladium, 89) + melee_ai:dynamic_wait(secs(15)) + town:wait_build(5, UnitId.TerranFulcrum) + town:build(3, UnitId.TerranPalladium, 89) + melee_ai:dynamic_wait(secs(15)) + end) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(50)) + town:build(3, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(4, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(3, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(mins(1) + secs(20)) + town:wait_build(1, UnitId.TerranFulcrum) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.TerranStarpad, 90) + melee_ai:dynamic_wait(secs(40)) + -- tier2 + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(4, UnitId.TerranFulcrum, 70) + melee_ai:dynamic_wait(secs(25)) + town:build(5, UnitId.TerranFulcrum, 70) + melee_ai:dynamic_wait(secs(5)) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Goliath / Maverick army (+ Matador / Phalanx / Wraith / Cuirass) + town:build(1, UnitId.TerranFulcrum, 70, true) + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranScrapyard, 68, true) + town:build(1, UnitId.TerranPalladium, 68, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranStarpad, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranMantle, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranIronFoundry, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/terran/armor/fe_five_fulc.lua b/mpq/lua/melee/terran/armor/fe_five_fulc.lua new file mode 100644 index 00000000..a01081e4 --- /dev/null +++ b/mpq/lua/melee/terran/armor/fe_five_fulc.lua @@ -0,0 +1,80 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Armor: FE 5Fulc", + unit_composition = { + -- signature units + [UnitId.TerranVulture] = 2, + [UnitId.TerranBlackjack] = 2, + [UnitId.TerranPhalanxTankMode] = 2, + -- filler units + [UnitId.TerranMaverick] = 1, + [UnitId.TerranAzazel] = 1, + [UnitId.TerranSeraph] = 1, + [UnitId.TerranRamesses] = 1, + [UnitId.TerranCuirassTankMode] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranStockade, 110) + melee_ai:dynamic_wait(secs(35)) + town:build(1, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(secs(45)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(50)) + town:build(3, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(secs(5)) + -- tier2 (starport/commandment) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranScrapyard, 69) + town:wait_build(2, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranPalladium, 69) + town:wait_build(3, UnitId.TerranFulcrum) + town:build(2, UnitId.TerranPalladium, 69) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranStarport, 70) + town:wait_build(1, UnitId.TerranStarport) + town:build(1, UnitId.TerranCommandment, 69) + end) + melee_ai:dynamic_wait(secs(25)) + town:wait_build(2, UnitId.TerranFulcrum, false) + melee_ai:dynamic_wait(secs(70) + secs(25)) + town:build(5, UnitId.TerranFulcrum, 70) + melee_ai:dynamic_wait(mins(2) + secs(15)) + town:build(1, UnitId.TerranAtlas, 70, true) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Vulture / Blackjack / Phalanx army (+ Azazel / Seraph / Cuirass) + town:build(1, UnitId.TerranFulcrum, 70, true) + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranScrapyard, 68, true) + town:build(1, UnitId.TerranPalladium, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranStarport, 65, true) + town:build(1, UnitId.TerranCommandment, 65, true) + town:build(1, UnitId.TerranMantle, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranIronFoundry, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/terran/armor/iron_crusade.lua b/mpq/lua/melee/terran/armor/iron_crusade.lua new file mode 100644 index 00000000..2ce4087e --- /dev/null +++ b/mpq/lua/melee/terran/armor/iron_crusade.lua @@ -0,0 +1,78 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Armor: Iron Crusade", + unit_composition = { + -- signature units (Iron Foundry x4 is the real investment of this build) + [UnitId.TerranPaladin] = 3, + [UnitId.TerranCuirassTankMode] = 2, + [UnitId.TerranPazuzu] = 2, + -- filler units + [UnitId.TerranVulture] = 1, + [UnitId.TerranWraith] = 1, + [UnitId.TerranRamesses] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(mins(1)) + town:wait_build(1, UnitId.TerranFulcrum) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.TerranStarpad, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(mins(1) + secs(20)) + -- tier2 + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(3, UnitId.TerranFulcrum, 70) + melee_ai:dynamic_wait(secs(5)) + town:wait_build(2, UnitId.TerranFulcrum) + town:wait_build(3, UnitId.TerranFulcrum, false) + town:wait_build(1, UnitId.TerranAtlas) + melee_ai:dynamic_wait(secs(20)) + town:build(4, UnitId.TerranFulcrum, 70) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranMantle, 69, true) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + melee_ai:dynamic_wait(secs(5)) + town:build(1, UnitId.TerranIronFoundry, 50) + melee_ai:dynamic_wait(secs(5)) + town:build(2, UnitId.TerranIronFoundry, 50) + melee_ai:dynamic_wait(secs(5)) + town:build(3, UnitId.TerranIronFoundry, 50) + melee_ai:dynamic_wait(secs(5)) + town:build(4, UnitId.TerranIronFoundry, 50) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Iron Foundry crusade (Paladin / Cuirass / Pazuzu + Vulture / Wraith / Ramesses) + town:build(1, UnitId.TerranFulcrum, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranStarpad, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranMantle, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranIronFoundry, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/terran/armor/tank_push.lua b/mpq/lua/melee/terran/armor/tank_push.lua new file mode 100644 index 00000000..e2784aa0 --- /dev/null +++ b/mpq/lua/melee/terran/armor/tank_push.lua @@ -0,0 +1,84 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Armor: Tank Push", + unit_composition = { + -- signature units + [UnitId.TerranMatadorTankMode] = 2, + [UnitId.TerranPhalanxTankMode] = 2, + -- healers + [UnitId.TerranCleric] = 1, + -- filler units + [UnitId.TerranCyprian] = 1, + [UnitId.TerranBlackjack] = 1, + [UnitId.TerranMadrigalImperiosoMode] = 1, + [UnitId.TerranRamesses] = 1, + [UnitId.TerranCuirassTankMode] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranFulcrum, 110) + melee_ai:dynamic_wait(secs(5)) + town:wait_build(1, UnitId.TerranFulcrum) + melee_ai:dynamic_wait(secs(5)) + town:build(1, UnitId.TerranScrapyard, 90) + town:multirun(function(town) + melee_ai:dynamic_wait(secs(18)) + town:wait_build(2, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranPalladium, 89) + town:wait_build(3, UnitId.TerranFulcrum) + town:build(2, UnitId.TerranPalladium, 89) + town:wait_build(4, UnitId.TerranFulcrum) + town:build(3, UnitId.TerranPalladium, 89) + town:wait_build(1, UnitId.TerranStockade) + town:build(1, UnitId.TerranVestry, 89) + end) + town:wait_build(1, UnitId.TerranScrapyard, false) + town:build(2, UnitId.TerranFulcrum, 90) + town:wait_build(2, UnitId.TerranFulcrum, false) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(40)) + town:build(3, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(4, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(25)) + -- tier2 + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(mins(1)) + town:build(1, UnitId.TerranStockade, 70) + melee_ai:dynamic_wait(secs(25)) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Matador / Phalanx tank push (+ Cleric / Ramesses / Cuirass) + town:build(1, UnitId.TerranFulcrum, 70, true) + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranScrapyard, 68, true) + town:build(1, UnitId.TerranPalladium, 68, true) + town:build(1, UnitId.TerranVestry, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranMantle, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranIronFoundry, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/terran/armor/two_fulc_vulture.lua b/mpq/lua/melee/terran/armor/two_fulc_vulture.lua new file mode 100644 index 00000000..de82e37d --- /dev/null +++ b/mpq/lua/melee/terran/armor/two_fulc_vulture.lua @@ -0,0 +1,57 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Armor: 2Fulc Vulture", + unit_composition = { + -- signature unit + [UnitId.TerranVulture] = 3, + -- filler units + [UnitId.TerranMaverick] = 1, + [UnitId.TerranCyclops] = 1, + [UnitId.TerranRamesses] = 1, + [UnitId.TerranCuirassTankMode] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranFulcrum, 110) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(mins(1) + secs(15)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(50)) + melee_ai:start_expanding() + -- tier1 + town:build(3, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(secs(5)) + town:build(1, UnitId.TerranStockade, 90) + -- tier2/tier3 + town:build(1, UnitId.TerranAtlas, 70, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Vulture-heavy mech (+ Maverick / Cyclops / Ramesses / Cuirass) + town:build(1, UnitId.TerranFulcrum, 70, true) + town:build(1, UnitId.TerranStockade, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranMantle, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranIronFoundry, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/terran/armor/walker_power.lua b/mpq/lua/melee/terran/armor/walker_power.lua new file mode 100644 index 00000000..794b9f02 --- /dev/null +++ b/mpq/lua/melee/terran/armor/walker_power.lua @@ -0,0 +1,70 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Armor: Walker Power", + unit_composition = { + -- signature units (walkers) + [UnitId.TerranGoliath] = 3, + [UnitId.TerranCyclops] = 2, + [UnitId.TerranBlackjack] = 2, + -- filler units + [UnitId.TerranPhalanxTankMode] = 1, + [UnitId.TerranMaverick] = 1, + [UnitId.TerranRamesses] = 1, + [UnitId.TerranCuirassTankMode] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.TerranFulcrum, 110) + melee_ai:dynamic_wait(secs(20)) + town:build(2, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(secs(35)) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranScrapyard, 89) + melee_ai:dynamic_wait(secs(15)) + town:wait_build(2, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranPalladium, 89) + end) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(5)) + town:wait_build(1, UnitId.TerranFulcrum) + town:wait_build(2, UnitId.TerranFulcrum, false) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(mins(1) + secs(10)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(mins(1)) + -- tier2/tier3 + town:build(1, UnitId.TerranAtlas, 70, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Goliath / Cyclops / Blackjack walkers (+ Phalanx / Ramesses / Cuirass) + town:build(1, UnitId.TerranFulcrum, 70, true) + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranScrapyard, 68, true) + town:build(1, UnitId.TerranPalladium, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranMantle, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranIronFoundry, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/terran/basic.lua b/mpq/lua/melee/terran/basic.lua new file mode 100644 index 00000000..fb8cf0b7 --- /dev/null +++ b/mpq/lua/melee/terran/basic.lua @@ -0,0 +1,13 @@ +local Basic = {} + +---@type BuildOrder +function Basic.build_anti_ground(melee_ai, town) + melee_ai:build_sequence(town, 1, 2, UnitId.TerranAnchor, 70, 5, secs(25), secs(5)) +end + +---@type BuildOrder +function Basic.build_anti_air(melee_ai, town) + melee_ai:build_sequence(town, 1, 4, UnitId.TerranWatchdog, 80, 5, secs(25), secs(5)) +end + +return Basic diff --git a/mpq/lua/melee/terran/build/basic.lua b/mpq/lua/melee/terran/build/basic.lua deleted file mode 100644 index 84f3ddd5..00000000 --- a/mpq/lua/melee/terran/build/basic.lua +++ /dev/null @@ -1,31 +0,0 @@ -local Basic = {} - ----@param melee_ai MeleeAI ----@param town Town -function Basic.build_expansion(melee_ai, town) - town:build(1, UnitId.TerranMinistry, 120) - town:wait_build(1, UnitId.TerranMinistry) - town:build(town.max_workers, UnitId.TerranMason, 100) - town:transfer_workers(8) - town:wait_build(10, UnitId.TerranMason) -end - ----@param melee_ai MeleeAI ----@param town Town -function Basic.build_anti_ground(melee_ai, town) - for i = 1, 2 do - town:build(i, UnitId.TerranAnchor, 70 - i * 5) - wait(secs(25 + i * 5)) - end -end - ----@param melee_ai MeleeAI ----@param town Town -function Basic.build_anti_air(melee_ai, town) - for i = 1, 4 do - town:build(i, UnitId.TerranWatchdog, 80 - i * 5) - wait(secs(25 + i * 5)) - end -end - -return Basic diff --git a/mpq/lua/melee/terran/build/openers.lua b/mpq/lua/melee/terran/build/openers.lua deleted file mode 100644 index d425f9ad..00000000 --- a/mpq/lua/melee/terran/build/openers.lua +++ /dev/null @@ -1,416 +0,0 @@ ----@class TerranOpeners -local Openers = {} - --- Shared short openers (still used as-is by personalities whose own build --- order never repositions an attack/expand trigger within this phase). - ----@param melee_ai MeleeAI ----@param town Town -function Openers.expand_first(melee_ai, town) - melee_ai:dynamic_wait(secs(30)) - melee_ai:start_expanding() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.expand_first_slow(melee_ai, town) - melee_ai:dynamic_wait(secs(50)) - melee_ai:start_expanding() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.expand_first_very_slow(melee_ai, town) - melee_ai:dynamic_wait(secs(40)) - melee_ai:start_expanding() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.fulcrum_start_medium(melee_ai, town) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.TerranFulcrum, 110) -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.stockade_quick_start(melee_ai, town) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.TerranStockade, 110) -end - --- Armor - ----@param melee_ai MeleeAI ----@param town Town -function Openers.tank_push(melee_ai, town) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.TerranFulcrum, 110) - melee_ai:dynamic_wait(secs(5)) - town:wait_build(1, UnitId.TerranFulcrum) - melee_ai:dynamic_wait(secs(5)) - town:build(1, UnitId.TerranScrapyard, 90) - town:multirun(function() - wait(secs(18)) - town:wait_build(2, UnitId.TerranFulcrum) - town:build(1, UnitId.TerranPalladium, 89) - town:wait_build(3, UnitId.TerranFulcrum) - town:build(2, UnitId.TerranPalladium, 89) - town:wait_build(4, UnitId.TerranFulcrum) - town:build(3, UnitId.TerranPalladium, 89) - town:wait_build(1, UnitId.TerranStockade) - town:build(1, UnitId.TerranVestry, 89) - end) - town:wait_build(1, UnitId.TerranScrapyard, false) - town:build(2, UnitId.TerranFulcrum, 90) - town:wait_build(2, UnitId.TerranFulcrum, false) - melee_ai:start_expanding() - melee_ai:dynamic_wait(secs(40)) - town:build(3, UnitId.TerranFulcrum, 90) - melee_ai:dynamic_wait(secs(25)) - town:build(4, UnitId.TerranFulcrum, 90) - melee_ai:dynamic_wait(secs(25)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(secs(25)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.two_fulc_vulture(melee_ai, town) - melee_ai:dynamic_wait(secs(30)) - town:build(1, UnitId.TerranFulcrum, 110) - melee_ai:dynamic_wait(secs(15)) - town:build(2, UnitId.TerranFulcrum, 90) - melee_ai:dynamic_wait(mins(1) + secs(15)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(secs(50)) - melee_ai:start_expanding() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.fe_five_fulc(melee_ai, town) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.TerranStockade, 110) - melee_ai:dynamic_wait(secs(35)) - town:build(1, UnitId.TerranFulcrum, 90) - melee_ai:dynamic_wait(secs(45)) - melee_ai:start_expanding() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.david_and_goliath(melee_ai, town) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.TerranFulcrum, 110) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(secs(40)) - town:build(2, UnitId.TerranStockade, 90) - town:wait_build(2, UnitId.TerranStockade, false) - melee_ai:dynamic_wait(secs(15)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(secs(30)) - town:build(2, UnitId.TerranFulcrum, 90) - town:wait_build(2, UnitId.TerranFulcrum, false) - town:multirun(function() - town:wait_build(2, UnitId.TerranFulcrum) - town:build(1, UnitId.TerranScrapyard, 89) - town:wait_build(2, UnitId.TerranFulcrum) - town:build(1, UnitId.TerranPalladium, 89) - melee_ai:dynamic_wait(secs(5)) - town:wait_build(3, UnitId.TerranFulcrum) - town:build(2, UnitId.TerranPalladium, 89) - melee_ai:dynamic_wait(secs(15)) - town:wait_build(5, UnitId.TerranFulcrum) - town:build(3, UnitId.TerranPalladium, 89) - melee_ai:dynamic_wait(secs(15)) - end) - melee_ai:dynamic_wait(secs(25)) - melee_ai:start_expanding() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.walker_power(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.TerranFulcrum, 110) - melee_ai:dynamic_wait(secs(20)) - town:build(2, UnitId.TerranFulcrum, 90) - melee_ai:dynamic_wait(secs(35)) - town:multirun(function() - town:wait_build(1, UnitId.TerranFulcrum) - town:build(1, UnitId.TerranScrapyard, 89) - melee_ai:dynamic_wait(secs(15)) - town:wait_build(2, UnitId.TerranFulcrum) - town:build(1, UnitId.TerranPalladium, 89) - end) - melee_ai:dynamic_wait(secs(25)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(secs(5)) - town:wait_build(1, UnitId.TerranFulcrum) - town:wait_build(2, UnitId.TerranFulcrum, false) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(mins(1) + secs(10)) - melee_ai:start_expanding() - melee_ai:dynamic_wait(mins(1)) -end - --- Raider - ----@param melee_ai MeleeAI ----@param town Town -function Openers.eight_rax(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.TerranStockade, 110) - melee_ai:dynamic_wait(secs(15)) - town:build(2, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(secs(15)) - town:build(3, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(secs(15)) - town:build(4, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(secs(15)) - town:build(5, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(secs(15)) - town:build(6, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(secs(15)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(secs(15)) - town:wait_build(6, UnitId.TerranStockade, false) - melee_ai:dynamic_wait(mins(1) + secs(15)) - melee_ai:start_expanding() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.three_rax_bio(melee_ai, town) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.TerranStockade, 110) - melee_ai:dynamic_wait(secs(15)) - town:build(2, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(mins(1) + secs(5)) - town:multirun(function() - town:wait_build(1, UnitId.TerranStockade) - town:build(1, UnitId.TerranVestry, 89) - town:wait_build(2, UnitId.TerranStockade) - town:build(2, UnitId.TerranVestry, 89) - end) - melee_ai:dynamic_wait(secs(20)) - town:build(3, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(secs(10)) - town:wait_build(3, UnitId.TerranStockade, false) - melee_ai:start_expanding() - melee_ai:dynamic_wait(mins(1) + secs(40)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.fast_anvil(melee_ai, town) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.TerranStockade, 110) - melee_ai:dynamic_wait(secs(40)) - melee_ai:start_expanding() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.four_rax_pressure(melee_ai, town) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.TerranStockade, 110) - melee_ai:dynamic_wait(secs(20)) - town:build(2, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(secs(20)) - town:build(3, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(secs(20)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(mins(1)) - melee_ai:start_expanding() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.holy_ackmeds(melee_ai, town) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.TerranStockade, 110) - melee_ai:dynamic_wait(secs(45)) - town:build(2, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(secs(25)) - town:build(3, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(secs(25)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(secs(25)) - town:build(4, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(secs(15)) - melee_ai:start_expanding() - melee_ai:dynamic_wait(secs(40)) - town:wait_build(4, UnitId.TerranStockade, false) - melee_ai:dynamic_wait(mins(1) + secs(40)) -end - --- Orbital - ----@param melee_ai MeleeAI ----@param town Town -function Openers.rapid_starpads(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.TerranStarpad, 110) - melee_ai:dynamic_wait(secs(50)) - town:build(2, UnitId.TerranStarpad, 90) - melee_ai:dynamic_wait(mins(1) + secs(5)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(mins(1) + secs(15)) - melee_ai:start_expanding() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.wraith_bio(melee_ai, town) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.TerranStockade, 110) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.TerranStarpad, 90) - - melee_ai:dynamic_wait(secs(15)) - melee_ai:start_expanding() - melee_ai:dynamic_wait(secs(40)) - town:build(2, UnitId.TerranStarpad, 90) - melee_ai:dynamic_wait(secs(5)) - town:build(2, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(secs(25)) - town:build(3, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(secs(5)) - melee_ai:start_attacking() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.hotdrop(melee_ai, town) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.TerranStockade, 110) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.TerranStarpad, 90) - melee_ai:dynamic_wait(secs(35)) - town:build(2, UnitId.TerranStarpad, 90) - melee_ai:dynamic_wait(secs(45)) - town:build(2, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(secs(20)) - town:build(3, UnitId.TerranStarpad, 90) - melee_ai:dynamic_wait(secs(35)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(secs(15)) - melee_ai:start_expanding() - melee_ai:dynamic_wait(secs(40)) - town:wait_build(3, UnitId.TerranStarpad) - town:wait_build(2, UnitId.TerranStockade, false) -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.sudden_starport(melee_ai, town) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.TerranStockade, 110) - melee_ai:dynamic_wait(secs(25)) - melee_ai:start_expanding() - melee_ai:dynamic_wait(secs(40)) - town:build(2, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(secs(20)) - town:build(3, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(secs(15)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(secs(50)) - town:wait_build(3, UnitId.TerranStockade, false) -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.aces_high(melee_ai, town) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.TerranFulcrum, 110) - melee_ai:dynamic_wait(secs(20)) - town:build(2, UnitId.TerranFulcrum, 90) - melee_ai:dynamic_wait(secs(25)) - town:wait_build(2, UnitId.TerranFulcrum, false) - town:multirun(function() - town:wait_build(1, UnitId.TerranFulcrum) - town:build(1, UnitId.TerranScrapyard, 89) - town:wait_build(2, UnitId.TerranFulcrum) - town:build(2, UnitId.TerranScrapyard, 89) - town:wait_build(3, UnitId.TerranFulcrum) - town:build(3, UnitId.TerranScrapyard, 89) - end) - melee_ai:dynamic_wait(secs(25)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(secs(30)) - melee_ai:start_expanding() -end - --- General - ----@param melee_ai MeleeAI ----@param town Town -function Openers.two_fulcrum_mech(melee_ai, town) - melee_ai:dynamic_wait(secs(40)) - town:build(1, UnitId.TerranFulcrum, 110) - melee_ai:dynamic_wait(secs(25)) - town:build(2, UnitId.TerranFulcrum, 90) - melee_ai:dynamic_wait(secs(25)) - melee_ai:start_expanding() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.doubling_up(melee_ai, town) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.TerranStockade, 110) - melee_ai:dynamic_wait(secs(5)) - town:build(2, UnitId.TerranStockade, 90) - wait(secs(1)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(secs(25)) - town:build(3, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(mins(1) + secs(30)) - town:build(1, UnitId.TerranFulcrum, 90) - melee_ai:dynamic_wait(secs(25)) - town:build(2, UnitId.TerranFulcrum, 90) - melee_ai:dynamic_wait(secs(15)) - town:multirun(function() - town:wait_build(1, UnitId.TerranStockade) - town:build(1, UnitId.TerranVestry, 89) - town:wait_build(1, UnitId.TerranFulcrum) - town:build(1, UnitId.TerranScrapyard, 89) - town:wait_build(2, UnitId.TerranFulcrum) - town:build(2, UnitId.TerranScrapyard, 89) - town:wait_build(2, UnitId.TerranStockade) - town:build(1, UnitId.TerranCovenant, 89) - melee_ai:dynamic_wait(secs(5)) - town:wait_build(3, UnitId.TerranFulcrum) - town:build(1, UnitId.TerranPalladium, 89) - end) - melee_ai:dynamic_wait(secs(15)) - melee_ai:start_expanding() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.mech_into_air(melee_ai, town) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.TerranFulcrum, 110) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(secs(15)) - town:build(2, UnitId.TerranFulcrum, 90) - melee_ai:dynamic_wait(secs(25)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(mins(1)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.observant(melee_ai, town) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.TerranStockade, 110) - melee_ai:dynamic_wait(secs(5)) -end - -return Openers diff --git a/mpq/lua/melee/terran/build/tier1.lua b/mpq/lua/melee/terran/build/tier1.lua deleted file mode 100644 index 1d13a59d..00000000 --- a/mpq/lua/melee/terran/build/tier1.lua +++ /dev/null @@ -1,238 +0,0 @@ ----@class TerranTier1 -local Tier1 = {} - --- Shared expansion-order helpers (unrelated to the opener/tier1 split). - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.vestry_request(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.TerranVestry, 89) - melee_ai:dynamic_wait(secs(15)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.covenant_request(melee_ai, town) - town:build(1, UnitId.TerranCovenant, 89) - melee_ai:dynamic_wait(mins(1) + secs(40)) -end - --- Armor (scale-up after the opener; unlisted personalities fold entirely --- into their opener and skip tier1) - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.two_fulc_vulture(melee_ai, town) - town:build(3, UnitId.TerranFulcrum, 90) - melee_ai:dynamic_wait(secs(5)) - town:build(1, UnitId.TerranStockade, 90) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.fe_five_fulc(melee_ai, town) - melee_ai:dynamic_wait(secs(50)) - town:build(3, UnitId.TerranFulcrum, 90) - melee_ai:dynamic_wait(secs(5)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.david_and_goliath(melee_ai, town) - melee_ai:dynamic_wait(secs(50)) - town:build(3, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(secs(25)) - town:build(4, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(secs(25)) - town:build(3, UnitId.TerranFulcrum, 90) - melee_ai:dynamic_wait(mins(1) + secs(20)) - town:wait_build(1, UnitId.TerranFulcrum) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.TerranStarpad, 90) - melee_ai:dynamic_wait(secs(40)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.iron_crusade(melee_ai, town) - melee_ai:dynamic_wait(secs(30)) - town:build(1, UnitId.TerranFulcrum, 90) - melee_ai:dynamic_wait(mins(1)) - town:wait_build(1, UnitId.TerranFulcrum) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.TerranStarpad, 90) - melee_ai:dynamic_wait(secs(15)) - town:build(2, UnitId.TerranFulcrum, 90) - melee_ai:dynamic_wait(mins(1) + secs(20)) -end - --- Raider - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.eight_rax(melee_ai, town) - melee_ai:dynamic_wait(secs(40)) - town:build(8, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(secs(50)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.fast_anvil(melee_ai, town) - melee_ai:dynamic_wait(secs(25)) - town:build(2, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(secs(25)) - town:build(3, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(secs(40)) - town:wait_build(3, UnitId.TerranStockade, false) - melee_ai:dynamic_wait(secs(25)) - town:multirun(function() - town:wait_build(1, UnitId.TerranStockade) - town:build(1, UnitId.TerranVestry, 89) - town:wait_build(2, UnitId.TerranStockade) - town:build(1, UnitId.TerranCovenant, 89) - town:wait_build(1, UnitId.TerranCovenant, false) - town:build(1, UnitId.TerranAnvil, 89) - town:wait_build(3, UnitId.TerranStockade) - town:wait_build(1, UnitId.TerranAnvil, false) - town:build(2, UnitId.TerranCovenant, 89) - town:wait_build(4, UnitId.TerranStockade) - town:build(3, UnitId.TerranCovenant, 89) - end) - melee_ai:dynamic_wait(secs(25)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.four_rax_pressure(melee_ai, town) - melee_ai:dynamic_wait(secs(30)) - town:multirun(function() - town:wait_build(1, UnitId.TerranStockade) - town:build(1, UnitId.TerranVestry, 89) - town:wait_build(2, UnitId.TerranStockade) - town:build(2, UnitId.TerranVestry, 89) - town:wait_build(3, UnitId.TerranStockade) - town:build(1, UnitId.TerranCovenant, 89) - town:wait_build(4, UnitId.TerranStockade) - town:build(2, UnitId.TerranCovenant, 89) - end) - melee_ai:dynamic_wait(secs(5)) - town:wait_build(4, UnitId.TerranStockade) - melee_ai:dynamic_wait(mins(1)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.uprising(melee_ai, town) - melee_ai:dynamic_wait(secs(20)) - town:build(2, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(secs(20)) - town:build(3, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(secs(20)) - town:multirun(function() - town:wait_build(1, UnitId.TerranStockade) - town:build(1, UnitId.TerranVestry, 89) - town:wait_build(4, UnitId.TerranStockade) - town:build(2, UnitId.TerranVestry, 89) - end) - melee_ai:dynamic_wait(secs(15)) - town:build(4, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(secs(20)) - town:wait_build(4, UnitId.TerranStockade) - town:wait_build(2, UnitId.TerranVestry) - melee_ai:dynamic_wait(mins(1) + secs(40)) -end - --- Orbital - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.rapid_starpads(melee_ai, town) - melee_ai:dynamic_wait(secs(25)) - town:wait_build(2, UnitId.TerranStarpad) - town:build(2, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(secs(20)) - town:build(3, UnitId.TerranStarpad, 90) - melee_ai:dynamic_wait(mins(2) + secs(5)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.orbital_stockade_settle(melee_ai, town) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(mins(1)) - town:wait_build(1, UnitId.TerranStockade) - melee_ai:dynamic_wait(secs(40)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.wraith_bio(melee_ai, town) - melee_ai:dynamic_wait(secs(40)) - town:wait_build(3, UnitId.TerranStockade, false) - town:build(1, UnitId.TerranVestry, 89) - melee_ai:dynamic_wait(mins(1) + secs(15)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.aces_high(melee_ai, town) - melee_ai:dynamic_wait(secs(50)) - town:build(3, UnitId.TerranFulcrum, 90) - melee_ai:dynamic_wait(secs(25)) - town:build(3, UnitId.TerranStarpad, 90) - melee_ai:dynamic_wait(mins(1) + secs(20)) -end - --- General - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.two_fulcrum_mech(melee_ai, town) - melee_ai:dynamic_wait(mins(1)) - town:build(3, UnitId.TerranFulcrum, 90) - melee_ai:dynamic_wait(secs(40)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.general_stockade_fulcrum_vestry_palladium_starpad(melee_ai, town) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.TerranFulcrum, 90) - melee_ai:dynamic_wait(secs(25)) - town:multirun(function() - town:wait_build(1, UnitId.TerranStockade) - town:build(1, UnitId.TerranVestry, 89) - town:wait_build(1, UnitId.TerranFulcrum) - town:build(1, UnitId.TerranPalladium, 89) - end) - melee_ai:dynamic_wait(secs(5)) - town:build(1, UnitId.TerranStarpad, 90) - melee_ai:dynamic_wait(secs(5)) - town:build(2, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(mins(1)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.general_stockade_starpad(melee_ai, town) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.TerranStockade, 90) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.TerranStarpad, 90) - melee_ai:dynamic_wait(secs(25)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.doubling_up(melee_ai, town) - melee_ai:dynamic_wait(secs(45)) - town:build(1, UnitId.TerranStarpad, 90) - melee_ai:dynamic_wait(secs(25)) -end - -return Tier1 diff --git a/mpq/lua/melee/terran/build/tier2.lua b/mpq/lua/melee/terran/build/tier2.lua deleted file mode 100644 index 423afa83..00000000 --- a/mpq/lua/melee/terran/build/tier2.lua +++ /dev/null @@ -1,322 +0,0 @@ ----@class TerranTier2 -local Tier2 = {} - ---- Requests Atlas and waits for it. The generic tier-2 tech transition. ----@param melee_ai MeleeAI ----@param town Town -function Tier2.acquire(melee_ai, town) - town:multirun(function() - wait(secs(1)) - town:build(1, UnitId.TerranAtlas, 70, true) - end) -end - ---- Requests a bare Starport once Atlas exists, for base air units. ----@param melee_ai MeleeAI ----@param town Town -function Tier2.starport(melee_ai, town) - melee_ai:dynamic_wait(secs(40)) - town:build(1, UnitId.TerranStarport, 69, true) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.stockade_requeue(melee_ai, town) - melee_ai:dynamic_wait(mins(1)) - town:build(1, UnitId.TerranStockade, 70) - melee_ai:dynamic_wait(secs(25)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.starport_commandment_buildup(melee_ai, town) - town:multirun(function() - town:wait_build(1, UnitId.TerranFulcrum) - town:build(1, UnitId.TerranScrapyard, 69) - town:wait_build(2, UnitId.TerranFulcrum) - town:build(1, UnitId.TerranPalladium, 69) - town:wait_build(3, UnitId.TerranFulcrum) - town:build(2, UnitId.TerranPalladium, 69) - wait(secs(2)) - town:wait_build(1, UnitId.TerranAtlas) - town:build(1, UnitId.TerranStarport, 70) - town:wait_build(1, UnitId.TerranStarport) - town:build(1, UnitId.TerranCommandment, 69) - end) - melee_ai:dynamic_wait(secs(25)) - town:wait_build(2, UnitId.TerranFulcrum, false) - melee_ai:dynamic_wait(secs(70) + secs(25)) - town:build(5, UnitId.TerranFulcrum, 70) - melee_ai:dynamic_wait(mins(2) + secs(15)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.fulcrum_scaling(melee_ai, town) - melee_ai:dynamic_wait(secs(20)) - town:build(4, UnitId.TerranFulcrum, 70) - melee_ai:dynamic_wait(secs(25)) - town:build(5, UnitId.TerranFulcrum, 70) - melee_ai:dynamic_wait(secs(5)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.fulcrum_buildup(melee_ai, town) - melee_ai:dynamic_wait(secs(25)) - town:build(3, UnitId.TerranFulcrum, 70) - melee_ai:dynamic_wait(secs(5)) - town:wait_build(2, UnitId.TerranFulcrum) - town:wait_build(3, UnitId.TerranFulcrum, false) - wait(secs(1)) - town:wait_build(1, UnitId.TerranAtlas) - melee_ai:dynamic_wait(secs(20)) - town:build(4, UnitId.TerranFulcrum, 70) - melee_ai:dynamic_wait(secs(20)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.raider_vestry_covenant_buildup(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:multirun(function() - town:wait_build(1, UnitId.TerranStockade) - town:build(1, UnitId.TerranVestry, 69) - town:wait_build(2, UnitId.TerranStockade) - town:build(2, UnitId.TerranVestry, 69) - town:wait_build(3, UnitId.TerranStockade) - town:build(1, UnitId.TerranCovenant, 69) - town:wait_build(4, UnitId.TerranStockade) - town:build(2, UnitId.TerranCovenant, 69) - end) - melee_ai:dynamic_wait(secs(25)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.raider_stockade_requeue(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:build(4, UnitId.TerranStockade, 70) - melee_ai:dynamic_wait(secs(40)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.raider_vestry_starport_rotary(melee_ai, town) - melee_ai:dynamic_wait(secs(5)) - town:multirun(function() - town:wait_build(1, UnitId.TerranStockade) - town:build(1, UnitId.TerranVestry, 69) - town:wait_build(1, UnitId.TerranAtlas) - town:build(1, UnitId.TerranStarport, 70) - town:wait_build(1, UnitId.TerranStarport) - town:build(1, UnitId.TerranRotary, 69) - end) - melee_ai:dynamic_wait(secs(15)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.orbital_starport_rotary_commandment(melee_ai, town) - town:multirun(function() - town:wait_build(1, UnitId.TerranAtlas) - town:build(1, UnitId.TerranStarport, 70) - town:wait_build(1, UnitId.TerranStarport) - town:build(1, UnitId.TerranRotary, 69) - town:build(2, UnitId.TerranStarport, 70) - town:wait_build(2, UnitId.TerranStarport) - town:build(2, UnitId.TerranRotary, 69) - town:build(3, UnitId.TerranStarport, 70) - town:wait_build(3, UnitId.TerranStarport) - town:build(1, UnitId.TerranCommandment, 69) - end) - melee_ai:dynamic_wait(secs(40)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.orbital_covenant_anvil_starport_rotary(melee_ai, town) - melee_ai:dynamic_wait(secs(20)) - town:multirun(function() - town:build(1, UnitId.TerranCovenant, 69) - town:wait_build(1, UnitId.TerranCovenant) - town:build(1, UnitId.TerranAnvil, 69) - wait(secs(1)) - town:wait_build(1, UnitId.TerranAtlas) - town:build(1, UnitId.TerranStarport, 70) - town:wait_build(1, UnitId.TerranStarport) - town:build(1, UnitId.TerranRotary, 69) - town:build(2, UnitId.TerranStarport, 70) - town:wait_build(2, UnitId.TerranStarport) - town:build(2, UnitId.TerranRotary, 69) - melee_ai:dynamic_wait(secs(50)) - end) - melee_ai:dynamic_wait(secs(40)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.orbital_vestry_starport_rotary_x4(melee_ai, town) - town:multirun(function() - town:wait_build(2, UnitId.TerranStockade) - town:build(1, UnitId.TerranVestry, 69) - town:wait_build(1, UnitId.TerranAtlas) - town:build(1, UnitId.TerranStarport, 70) - town:wait_build(1, UnitId.TerranStarport, false) - town:build(4, UnitId.TerranStarport, 70) - town:wait_build(1, UnitId.TerranStarport) - town:build(1, UnitId.TerranRotary, 69) - town:wait_build(2, UnitId.TerranStarport) - town:build(2, UnitId.TerranRotary, 69) - town:wait_build(3, UnitId.TerranStarport) - town:build(3, UnitId.TerranRotary, 69) - town:wait_build(4, UnitId.TerranStarport) - town:build(4, UnitId.TerranRotary, 69) - melee_ai:dynamic_wait(secs(15)) - end) - melee_ai:dynamic_wait(mins(1) + secs(15)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.general_expansion_tail(melee_ai, town) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.TerranStarpad, 69, true) - melee_ai:dynamic_wait(secs(15)) - Tier2.acquire(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.TerranStockade, 69, true) - melee_ai:dynamic_wait(secs(5)) - town:build(1, UnitId.TerranCovenant, 69, true) - melee_ai:dynamic_wait(mins(1)) - town:build(1, UnitId.TerranStarport, 69, true) - melee_ai:dynamic_wait(mins(1) + secs(15)) - town:multirun(function() - wait(secs(1)) - town:wait_build(1, UnitId.TerranAtlas) - town:build(1, UnitId.TerranDaedala, 65, true) - end) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.general_scrapyard_palladium_mantle(melee_ai, town) - melee_ai:dynamic_wait(secs(25)) - town:multirun(function() - town:wait_build(1, UnitId.TerranFulcrum) - town:build(1, UnitId.TerranScrapyard, 69) - town:wait_build(2, UnitId.TerranFulcrum) - town:build(2, UnitId.TerranScrapyard, 69) - town:wait_build(3, UnitId.TerranFulcrum) - town:build(1, UnitId.TerranPalladium, 69) - town:wait_build(4, UnitId.TerranFulcrum) - town:build(2, UnitId.TerranPalladium, 69) - end) - melee_ai:dynamic_wait(secs(40) + secs(40)) - town:build(2, UnitId.TerranMantle, 70) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.general_vestry_palladium_starport_rotary(melee_ai, town) - town:multirun(function() - town:wait_build(1, UnitId.TerranStockade) - town:build(1, UnitId.TerranVestry, 69) - town:wait_build(1, UnitId.TerranFulcrum) - town:build(1, UnitId.TerranPalladium, 69) - town:wait_build(1, UnitId.TerranAtlas) - wait(secs(1)) - town:build(1, UnitId.TerranStarport, 70) - town:wait_build(1, UnitId.TerranStarport) - town:build(1, UnitId.TerranRotary, 69) - end) - melee_ai:dynamic_wait(secs(40) + secs(25) + secs(50)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.general_fulcrum_follow_up(melee_ai, town) - melee_ai:dynamic_wait(secs(20)) - town:build(3, UnitId.TerranFulcrum, 70) - melee_ai:dynamic_wait(secs(45)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.general_mega_tech_buildup(melee_ai, town) - town:multirun(function() - town:wait_build(1, UnitId.TerranFulcrum) - town:build(1, UnitId.TerranScrapyard, 69) - town:wait_build(2, UnitId.TerranFulcrum) - town:build(2, UnitId.TerranScrapyard, 69) - town:build(1, UnitId.TerranQuarry, 69) - town:wait_build(3, UnitId.TerranFulcrum) - town:build(1, UnitId.TerranPalladium, 69) - town:wait_build(4, UnitId.TerranFulcrum) - town:build(2, UnitId.TerranPalladium, 69) - town:wait_build(1, UnitId.TerranAtlas) - town:build(2, UnitId.TerranStarport, 70) - town:wait_build(1, UnitId.TerranStarport) - town:build(1, UnitId.TerranRotary, 69) - town:wait_build(2, UnitId.TerranStarport) - town:build(2, UnitId.TerranRotary, 69) - town:wait_build(5, UnitId.TerranFulcrum) - town:build(3, UnitId.TerranPalladium, 69) - town:wait_build(6, UnitId.TerranFulcrum) - town:build(4, UnitId.TerranPalladium, 69) - town:wait_build(3, UnitId.TerranStarport) - town:build(3, UnitId.TerranRotary, 69) - town:wait_build(4, UnitId.TerranStarport) - town:build(4, UnitId.TerranRotary, 69) - town:wait_build(5, UnitId.TerranStarport) - town:build(5, UnitId.TerranRotary, 69) - town:wait_build(1, UnitId.TerranDaedala) - town:wait_build(6, UnitId.TerranStarport) - town:build(1, UnitId.TerranCommandment, 69) - town:wait_build(7, UnitId.TerranStarport) - town:build(2, UnitId.TerranCommandment, 69) - town:wait_build(8, UnitId.TerranStarport) - town:build(3, UnitId.TerranCommandment, 69) - town:build(2, UnitId.TerranNaniteAssembly, 69) - town:wait_build(1, UnitId.TerranNaniteAssembly) - town:build(1, UnitId.TerranHadron, 69) - end) - melee_ai:dynamic_wait(mins(1) + secs(15)) - town:build(1, UnitId.TerranStarpad, 70) - melee_ai:dynamic_wait(secs(15) + mins(1) + secs(15)) - town:build(6, UnitId.TerranFulcrum, 70) - melee_ai:dynamic_wait(mins(1) + secs(40)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.general_vestry_scrapyard_palladium_starport_commandment(melee_ai, town) - town:multirun(function() - town:wait_build(1, UnitId.TerranStockade) - town:build(1, UnitId.TerranVestry, 69) - town:wait_build(1, UnitId.TerranFulcrum) - town:build(1, UnitId.TerranScrapyard, 69) - town:wait_build(2, UnitId.TerranFulcrum) - town:build(2, UnitId.TerranPalladium, 69) - town:wait_build(3, UnitId.TerranFulcrum) - wait(secs(1)) - town:wait_build(1, UnitId.TerranAtlas) - town:build(2, UnitId.TerranStarport, 70) - town:wait_build(2, UnitId.TerranStarport) - town:build(2, UnitId.TerranCommandment, 69) - town:wait_build(1, UnitId.TerranCommandment) - melee_ai:dynamic_wait(secs(15)) - end) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.TerranFulcrum, 70) - melee_ai:dynamic_wait(secs(5) + secs(35)) - town:build(1, UnitId.TerranStarpad, 70) - melee_ai:dynamic_wait(secs(30)) - town:build(2, UnitId.TerranFulcrum, 70) - melee_ai:dynamic_wait(secs(25) + secs(50)) - Tier2.acquire(melee_ai, town) - town:build(3, UnitId.TerranFulcrum, 70) - melee_ai:dynamic_wait(secs(50)) -end - -return Tier2 diff --git a/mpq/lua/melee/terran/build/tier3.lua b/mpq/lua/melee/terran/build/tier3.lua deleted file mode 100644 index d3a4daf8..00000000 --- a/mpq/lua/melee/terran/build/tier3.lua +++ /dev/null @@ -1,49 +0,0 @@ ----@class TerranTier3 -local Tier3 = {} - ---- Requests Daedala and waits for it. The generic tier-3 tech transition. ----@param melee_ai MeleeAI ----@param town Town -function Tier3.acquire(melee_ai, town) - town:multirun(function() - wait(secs(1)) - town:wait_build(1, UnitId.TerranAtlas) - town:build(1, UnitId.TerranDaedala, 65, true) - end) - wait(secs(1)) - town:wait_build(1, UnitId.TerranDaedala) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier3.iron_foundries(melee_ai, town) - melee_ai:dynamic_wait(secs(5)) - town:build(1, UnitId.TerranIronFoundry, 50) - melee_ai:dynamic_wait(secs(5)) - town:build(2, UnitId.TerranIronFoundry, 50) - melee_ai:dynamic_wait(secs(5)) - town:build(3, UnitId.TerranIronFoundry, 50) - melee_ai:dynamic_wait(secs(5)) - town:build(4, UnitId.TerranIronFoundry, 50) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier3.nanite_assembly_buildup(melee_ai, town) - town:build(2, UnitId.TerranNaniteAssembly, 50) - melee_ai:dynamic_wait(secs(20)) - town:build(3, UnitId.TerranNaniteAssembly, 50) - melee_ai:dynamic_wait(secs(20)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier3.general_starport_scaling(melee_ai, town) - melee_ai:dynamic_wait(mins(1) + secs(15)) - town:build(4, UnitId.TerranStarport, 50) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(8, UnitId.TerranStarport, 50) - melee_ai:dynamic_wait(mins(1) + secs(15)) -end - -return Tier3 diff --git a/mpq/lua/melee/terran/general.lua b/mpq/lua/melee/terran/general.lua deleted file mode 100644 index ac7e92b2..00000000 --- a/mpq/lua/melee/terran/general.lua +++ /dev/null @@ -1,161 +0,0 @@ -local Basic = require("melee.terran.build.basic") -local Openers = require("melee.terran.build.openers") -local Tier1 = require("melee.terran.build.tier1") -local Tier2 = require("melee.terran.build.tier2") -local Tier3 = require("melee.terran.build.tier3") - -local expansion_build_order = { - Basic.build_expansion, - Tier2.general_expansion_tail, -} -local attack_wave_cost_bias = 0.5 - -return { - ---@type AIPersonality - two_fulcrum_mech = { - name = "General: 2 Fulcrum Mech", - unit_composition = { - -- signature units (Mantle x2) - [UnitId.TerranPhalanxTankMode] = 2, - [UnitId.TerranRamesses] = 2, - [UnitId.TerranDurendal] = 2, - [UnitId.TerranCataphract] = 2, - -- filler units - [UnitId.TerranBlackjack] = 1, - [UnitId.TerranMadrigalImperiosoMode] = 1, - }, - main_build_order = { - Openers.two_fulcrum_mech, - Tier1.two_fulcrum_mech, - Tier2.acquire, - Tier2.general_scrapyard_palladium_mantle, - Tier3.acquire, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - early_riser = { - name = "General: Early Riser", - unit_composition = { - -- signature unit - [UnitId.TerranMaverick] = 2, - -- healers - [UnitId.TerranCleric] = 1, - -- filler units - [UnitId.TerranCyclops] = 1, - }, - main_build_order = { - Openers.expand_first_very_slow, - Tier1.general_stockade_fulcrum_vestry_palladium_starpad, - Tier2.acquire, - Tier3.acquire, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - the_cube = { - name = "General: The Cube", - unit_composition = { - -- signature unit - [UnitId.TerranMaverick] = 2, - -- filler units - [UnitId.TerranVulture] = 1, - [UnitId.TerranPhalanxTankMode] = 1, - [UnitId.TerranSalamander] = 1, - }, - main_build_order = { - Openers.fulcrum_start_medium, - Tier1.general_stockade_starpad, - Tier2.general_vestry_palladium_starport_rotary, - Tier2.acquire, - Tier2.general_fulcrum_follow_up, - Tier3.acquire, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - doubling_up = { - name = "General: Doubling Up", - unit_composition = { - -- signature units - [UnitId.TerranMaverick] = 2, - [UnitId.TerranGoliath] = 2, - -- healers - [UnitId.TerranShamanSupportMode] = 1, - -- filler units - [UnitId.TerranCyclops] = 1, - [UnitId.TerranBlackjack] = 1, - }, - main_build_order = { - Openers.doubling_up, - Tier1.doubling_up, - Tier2.acquire, - Tier2.general_fulcrum_follow_up, - Tier3.acquire, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - mech_into_air = { - name = "General: Mech into Air", - unit_composition = { - -- signature units (the mech-into-air transition) - [UnitId.TerranPhalanxTankMode] = 2, - [UnitId.TerranMinotaur] = 2, - -- filler units - [UnitId.TerranMatadorTankMode] = 1, - [UnitId.TerranSalamander] = 1, - [UnitId.TerranSeraph] = 1, - [UnitId.TerranHippogriff] = 1, - [UnitId.TerranPhobos] = 1, - }, - main_build_order = { - Openers.mech_into_air, - Tier2.acquire, - Tier2.general_mega_tech_buildup, - Tier3.acquire, - Tier3.general_starport_scaling, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - observant = { - name = "General: Observant", - unit_composition = { - -- signature unit - [UnitId.TerranCyprian] = 2, - -- filler units - [UnitId.TerranSeraph] = 1, - [UnitId.TerranBlackjack] = 1, - }, - main_build_order = { - Openers.observant, - Tier2.general_vestry_scrapyard_palladium_starport_commandment, - Tier3.acquire, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, -} diff --git a/mpq/lua/melee/terran/general/doubling_up.lua b/mpq/lua/melee/terran/general/doubling_up.lua new file mode 100644 index 00000000..2f1eb7c3 --- /dev/null +++ b/mpq/lua/melee/terran/general/doubling_up.lua @@ -0,0 +1,84 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "General: Doubling Up", + unit_composition = { + -- signature units + [UnitId.TerranMaverick] = 2, + [UnitId.TerranGoliath] = 2, + -- healers + [UnitId.TerranShamanSupportMode] = 1, + -- filler units + [UnitId.TerranCyclops] = 1, + [UnitId.TerranBlackjack] = 1, + [UnitId.TerranRamesses] = 1, + [UnitId.TerranCuirassTankMode] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranStockade, 110) + melee_ai:dynamic_wait(secs(5)) + town:build(2, UnitId.TerranStockade, 90) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(25)) + town:build(3, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(mins(1) + secs(30)) + town:build(1, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(secs(15)) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranStockade) + town:build(1, UnitId.TerranVestry, 89) + town:wait_build(1, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranScrapyard, 89) + town:wait_build(2, UnitId.TerranFulcrum) + town:build(2, UnitId.TerranScrapyard, 89) + town:wait_build(2, UnitId.TerranStockade) + town:build(1, UnitId.TerranCovenant, 89) + melee_ai:dynamic_wait(secs(5)) + town:wait_build(3, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranPalladium, 89) + end) + melee_ai:dynamic_wait(secs(15)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.TerranStarpad, 90) + melee_ai:dynamic_wait(secs(25)) + -- tier2 + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(3, UnitId.TerranFulcrum, 70) + melee_ai:dynamic_wait(secs(45)) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Maverick + Goliath doubles (+ Shaman / Cyclops / Blackjack / Cuirass) + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranVestry, 68, true) + town:build(1, UnitId.TerranFulcrum, 70, true) + town:build(1, UnitId.TerranScrapyard, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranMantle, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranIronFoundry, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/terran/general/early_riser.lua b/mpq/lua/melee/terran/general/early_riser.lua new file mode 100644 index 00000000..6074c065 --- /dev/null +++ b/mpq/lua/melee/terran/general/early_riser.lua @@ -0,0 +1,65 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "General: Early Riser", + unit_composition = { + -- signature unit + [UnitId.TerranMaverick] = 2, + -- healers + [UnitId.TerranCleric] = 1, + -- filler units + [UnitId.TerranCyclops] = 1, + [UnitId.TerranRamesses] = 1, + [UnitId.TerranCuirassTankMode] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + melee_ai:dynamic_wait(secs(40)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(secs(25)) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranStockade) + town:build(1, UnitId.TerranVestry, 89) + town:wait_build(1, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranPalladium, 89) + end) + melee_ai:dynamic_wait(secs(5)) + town:build(1, UnitId.TerranStarpad, 90) + melee_ai:dynamic_wait(secs(5)) + town:build(2, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(mins(1)) + -- tier2/tier3 + town:build(1, UnitId.TerranAtlas, 70, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Maverick + Cleric core (+ Cyclops / Ramesses / Cuirass) + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranVestry, 68, true) + town:build(1, UnitId.TerranFulcrum, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranMantle, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranIronFoundry, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/terran/general/mech_into_air.lua b/mpq/lua/melee/terran/general/mech_into_air.lua new file mode 100644 index 00000000..f9582b92 --- /dev/null +++ b/mpq/lua/melee/terran/general/mech_into_air.lua @@ -0,0 +1,107 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "General: Mech into Air", + unit_composition = { + -- signature units (the mech-into-air transition) + [UnitId.TerranPhalanxTankMode] = 2, + [UnitId.TerranMinotaur] = 2, + -- filler units + [UnitId.TerranMatadorTankMode] = 1, + [UnitId.TerranSalamander] = 1, + [UnitId.TerranSeraph] = 1, + [UnitId.TerranHippogriff] = 1, + [UnitId.TerranPhobos] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranFulcrum, 110) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(mins(1)) + -- tier2 + town:build(1, UnitId.TerranAtlas, 70, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranScrapyard, 69) + town:wait_build(2, UnitId.TerranFulcrum) + town:build(2, UnitId.TerranScrapyard, 69) + town:build(1, UnitId.TerranQuarry, 69) + town:wait_build(3, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranPalladium, 69) + town:wait_build(4, UnitId.TerranFulcrum) + town:build(2, UnitId.TerranPalladium, 69) + town:wait_build(1, UnitId.TerranAtlas) + town:build(2, UnitId.TerranStarport, 70) + town:wait_build(1, UnitId.TerranStarport) + town:build(1, UnitId.TerranRotary, 69) + town:wait_build(2, UnitId.TerranStarport) + town:build(2, UnitId.TerranRotary, 69) + town:wait_build(5, UnitId.TerranFulcrum) + town:build(3, UnitId.TerranPalladium, 69) + town:wait_build(6, UnitId.TerranFulcrum) + town:build(4, UnitId.TerranPalladium, 69) + town:wait_build(3, UnitId.TerranStarport) + town:build(3, UnitId.TerranRotary, 69) + town:wait_build(4, UnitId.TerranStarport) + town:build(4, UnitId.TerranRotary, 69) + town:wait_build(5, UnitId.TerranStarport) + town:build(5, UnitId.TerranRotary, 69) + town:wait_build(1, UnitId.TerranDaedala) + town:wait_build(6, UnitId.TerranStarport) + town:build(1, UnitId.TerranCommandment, 69) + town:wait_build(7, UnitId.TerranStarport) + town:build(2, UnitId.TerranCommandment, 69) + town:wait_build(8, UnitId.TerranStarport) + town:build(3, UnitId.TerranCommandment, 69) + town:build(2, UnitId.TerranNaniteAssembly, 69) + town:wait_build(1, UnitId.TerranNaniteAssembly) + town:build(1, UnitId.TerranHadron, 69) + end) + melee_ai:dynamic_wait(mins(1) + secs(15)) + town:build(1, UnitId.TerranStarpad, 70) + melee_ai:dynamic_wait(secs(15) + mins(1) + secs(15)) + town:build(6, UnitId.TerranFulcrum, 70) + melee_ai:dynamic_wait(mins(1) + secs(40)) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + melee_ai:dynamic_wait(mins(1) + secs(15)) + town:build(4, UnitId.TerranStarport, 50) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(8, UnitId.TerranStarport, 50) + melee_ai:dynamic_wait(mins(1) + secs(15)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the mech-to-air transition (Phalanx / Matador -> Minotaur / Seraph / Hippogriff) + town:build(1, UnitId.TerranFulcrum, 70, true) + town:build(1, UnitId.TerranScrapyard, 68, true) + town:build(1, UnitId.TerranPalladium, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranStarport, 65, true) + town:build(1, UnitId.TerranRotary, 65, true) + town:build(1, UnitId.TerranCommandment, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranNaniteAssembly, 65, true) + town:build(1, UnitId.TerranHadron, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/terran/general/observant.lua b/mpq/lua/melee/terran/general/observant.lua new file mode 100644 index 00000000..2a34bbd2 --- /dev/null +++ b/mpq/lua/melee/terran/general/observant.lua @@ -0,0 +1,73 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "General: Observant", + unit_composition = { + -- signature unit + [UnitId.TerranCyprian] = 2, + -- filler units + [UnitId.TerranSeraph] = 1, + [UnitId.TerranBlackjack] = 1, + [UnitId.TerranCentaur] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranStockade, 110) + melee_ai:dynamic_wait(secs(5)) + -- tier2 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranStockade) + town:build(1, UnitId.TerranVestry, 69) + town:wait_build(1, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranScrapyard, 69) + town:wait_build(2, UnitId.TerranFulcrum) + town:build(2, UnitId.TerranPalladium, 69) + town:wait_build(3, UnitId.TerranFulcrum) + town:wait_build(1, UnitId.TerranAtlas) + town:build(2, UnitId.TerranStarport, 70) + town:wait_build(2, UnitId.TerranStarport) + town:build(2, UnitId.TerranCommandment, 69) + town:wait_build(1, UnitId.TerranCommandment) + melee_ai:dynamic_wait(secs(15)) + end) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.TerranFulcrum, 70) + melee_ai:dynamic_wait(secs(5) + secs(35)) + town:build(1, UnitId.TerranStarpad, 70) + melee_ai:dynamic_wait(secs(30)) + town:build(2, UnitId.TerranFulcrum, 70) + melee_ai:dynamic_wait(secs(25) + secs(50)) + town:build(1, UnitId.TerranAtlas, 70, true) + town:build(3, UnitId.TerranFulcrum, 70) + melee_ai:dynamic_wait(secs(50)) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Cyprian core + Blackjack / Seraph / Centaur + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranFulcrum, 70, true) + town:build(1, UnitId.TerranScrapyard, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranStarport, 65, true) + town:build(1, UnitId.TerranCommandment, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranNaniteAssembly, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/terran/general/the_cube.lua b/mpq/lua/melee/terran/general/the_cube.lua new file mode 100644 index 00000000..d9d732ad --- /dev/null +++ b/mpq/lua/melee/terran/general/the_cube.lua @@ -0,0 +1,69 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "General: The Cube", + unit_composition = { + -- signature unit + [UnitId.TerranMaverick] = 2, + -- filler units + [UnitId.TerranVulture] = 1, + [UnitId.TerranPhalanxTankMode] = 1, + [UnitId.TerranSalamander] = 1, + [UnitId.TerranCentaur] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranFulcrum, 110) + -- tier1 + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.TerranStarpad, 90) + melee_ai:dynamic_wait(secs(25)) + -- tier2 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranStockade) + town:build(1, UnitId.TerranVestry, 69) + town:wait_build(1, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranPalladium, 69) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranStarport, 70) + town:wait_build(1, UnitId.TerranStarport) + town:build(1, UnitId.TerranRotary, 69) + end) + melee_ai:dynamic_wait(secs(40) + secs(25) + secs(50)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(3, UnitId.TerranFulcrum, 70) + melee_ai:dynamic_wait(secs(45)) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Maverick core + Vulture / Phalanx / Salamander / Centaur + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranFulcrum, 70, true) + town:build(1, UnitId.TerranPalladium, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranStarport, 65, true) + town:build(1, UnitId.TerranRotary, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranNaniteAssembly, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/terran/general/two_fulcrum_mech.lua b/mpq/lua/melee/terran/general/two_fulcrum_mech.lua new file mode 100644 index 00000000..fdafbf7e --- /dev/null +++ b/mpq/lua/melee/terran/general/two_fulcrum_mech.lua @@ -0,0 +1,71 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "General: 2 Fulcrum Mech", + unit_composition = { + -- signature units (Mantle x2) + [UnitId.TerranPhalanxTankMode] = 2, + [UnitId.TerranRamesses] = 2, + [UnitId.TerranDurendal] = 2, + [UnitId.TerranCataphract] = 2, + -- filler units + [UnitId.TerranBlackjack] = 1, + [UnitId.TerranMadrigalImperiosoMode] = 1, + [UnitId.TerranCuirassTankMode] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.TerranFulcrum, 110) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(mins(1)) + town:build(3, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(secs(40)) + -- tier2 + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranScrapyard, 69) + town:wait_build(2, UnitId.TerranFulcrum) + town:build(2, UnitId.TerranScrapyard, 69) + town:wait_build(3, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranPalladium, 69) + town:wait_build(4, UnitId.TerranFulcrum) + town:build(2, UnitId.TerranPalladium, 69) + end) + melee_ai:dynamic_wait(secs(40) + secs(40)) + town:build(2, UnitId.TerranMantle, 70) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Mantle walkers (Ramesses / Durendal / Cataphract) + Phalanx / Blackjack / Cuirass + town:build(1, UnitId.TerranFulcrum, 70, true) + town:build(1, UnitId.TerranScrapyard, 68, true) + town:build(1, UnitId.TerranPalladium, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranMantle, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranIronFoundry, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/terran/orbital.lua b/mpq/lua/melee/terran/orbital.lua deleted file mode 100644 index 846d9ea7..00000000 --- a/mpq/lua/melee/terran/orbital.lua +++ /dev/null @@ -1,153 +0,0 @@ -local Basic = require("melee.terran.build.basic") -local Openers = require("melee.terran.build.openers") -local Tier1 = require("melee.terran.build.tier1") -local Tier2 = require("melee.terran.build.tier2") -local Tier3 = require("melee.terran.build.tier3") - -local expansion_build_order = { - Basic.build_expansion, - Tier2.acquire, - Tier3.acquire, - Tier2.starport, -} -local attack_wave_cost_bias = 0.6 - -return { - ---@type AIPersonality - rapid_starpads = { - name = "Orbital: 2 Starpad Wraith", - unit_composition = { - -- signature unit - [UnitId.TerranWraith] = 3, - -- filler units - [UnitId.TerranSalamander] = 1, - [UnitId.TerranAzazel] = 1, - [UnitId.TerranSeraph] = 1, - }, - main_build_order = { - Openers.rapid_starpads, - Tier1.rapid_starpads, - Tier2.acquire, - Tier2.orbital_starport_rotary_commandment, - Tier3.acquire, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - the_don = { - name = "Orbital: The Don", - unit_composition = { - -- signature units (Nanite Assembly x3) - [UnitId.TerranMinotaur] = 2, - [UnitId.TerranCentaur] = 2, - [UnitId.TerranMagnetar] = 2, - -- filler units - [UnitId.TerranGorgon] = 1, - }, - main_build_order = { - Openers.expand_first_slow, - Tier1.orbital_stockade_settle, - Tier2.acquire, - Tier3.acquire, - Tier3.nanite_assembly_buildup, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - wraith_bio = { - name = "Orbital: Wraith Bio", - unit_composition = { - -- signature units - [UnitId.TerranMaverick] = 3, - [UnitId.TerranWraith] = 3, - -- filler units - [UnitId.TerranValkyrie] = 1, - }, - main_build_order = { - Openers.wraith_bio, - Tier1.wraith_bio, - Tier2.acquire, - Tier3.acquire, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - hotdrop = { - name = "Orbital: Hotdrop", - unit_composition = { - -- signature unit - [UnitId.TerranHarakan] = 3, - -- filler units - [UnitId.TerranWraith] = 1, - [UnitId.TerranSalamander] = 1, - }, - main_build_order = { - Openers.hotdrop, - Tier2.acquire, - Tier2.orbital_covenant_anvil_starport_rotary, - Tier3.acquire, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - sudden_starport = { - name = "Orbital: Sudden Starport", - unit_composition = { - -- signature units - [UnitId.TerranMaverick] = 2, - [UnitId.TerranSundog] = 2, - [UnitId.TerranSalamander] = 2, - -- healers - [UnitId.TerranCleric] = 1.5, - }, - main_build_order = { - Openers.sudden_starport, - Tier2.orbital_vestry_starport_rotary_x4, - Tier2.acquire, - Tier3.acquire, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - aces_high = { - name = "Orbital: Aces High", - unit_composition = { - -- signature units - [UnitId.TerranVulture] = 3, - [UnitId.TerranWraith] = 3, - -- filler units - [UnitId.TerranBlackjack] = 1, - [UnitId.TerranCyclops] = 1, - }, - main_build_order = { - Openers.aces_high, - Tier1.aces_high, - Tier2.acquire, - Tier3.acquire, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, -} diff --git a/mpq/lua/melee/terran/orbital/aces_high.lua b/mpq/lua/melee/terran/orbital/aces_high.lua new file mode 100644 index 00000000..30d43776 --- /dev/null +++ b/mpq/lua/melee/terran/orbital/aces_high.lua @@ -0,0 +1,72 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Orbital: Aces High", + unit_composition = { + -- signature units + [UnitId.TerranVulture] = 3, + [UnitId.TerranWraith] = 3, + -- filler units + [UnitId.TerranBlackjack] = 1, + [UnitId.TerranCyclops] = 1, + [UnitId.TerranSalamander] = 1, + [UnitId.TerranCentaur] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranFulcrum, 110) + melee_ai:dynamic_wait(secs(20)) + town:build(2, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(secs(25)) + town:wait_build(2, UnitId.TerranFulcrum, false) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranScrapyard, 89) + town:wait_build(2, UnitId.TerranFulcrum) + town:build(2, UnitId.TerranScrapyard, 89) + town:wait_build(3, UnitId.TerranFulcrum) + town:build(3, UnitId.TerranScrapyard, 89) + end) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(50)) + town:build(3, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(3, UnitId.TerranStarpad, 90) + melee_ai:dynamic_wait(mins(1) + secs(20)) + -- tier2/tier3 + town:build(1, UnitId.TerranAtlas, 70, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Vulture + Wraith aces (+ Blackjack / Cyclops / Salamander / Centaur) + town:build(1, UnitId.TerranFulcrum, 70, true) + town:build(1, UnitId.TerranScrapyard, 68, true) + town:build(1, UnitId.TerranStarpad, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranStarport, 65, true) + town:build(1, UnitId.TerranRotary, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranNaniteAssembly, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/terran/orbital/hotdrop.lua b/mpq/lua/melee/terran/orbital/hotdrop.lua new file mode 100644 index 00000000..af7f2045 --- /dev/null +++ b/mpq/lua/melee/terran/orbital/hotdrop.lua @@ -0,0 +1,78 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Orbital: Hotdrop", + unit_composition = { + -- signature unit + [UnitId.TerranHarakan] = 3, + -- filler units + [UnitId.TerranWraith] = 1, + [UnitId.TerranSalamander] = 1, + [UnitId.TerranCentaur] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranStockade, 110) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranStarpad, 90) + melee_ai:dynamic_wait(secs(35)) + town:build(2, UnitId.TerranStarpad, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(2, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(20)) + town:build(3, UnitId.TerranStarpad, 90) + melee_ai:dynamic_wait(secs(35)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(15)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(40)) + town:wait_build(3, UnitId.TerranStarpad) + town:wait_build(2, UnitId.TerranStockade, false) + -- tier2 + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:multirun(function(town) + town:build(1, UnitId.TerranCovenant, 69) + town:wait_build(1, UnitId.TerranCovenant) + town:build(1, UnitId.TerranAnvil, 69) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranStarport, 70) + town:wait_build(1, UnitId.TerranStarport) + town:build(1, UnitId.TerranRotary, 69) + town:build(2, UnitId.TerranStarport, 70) + town:wait_build(2, UnitId.TerranStarport) + town:build(2, UnitId.TerranRotary, 69) + melee_ai:dynamic_wait(secs(50)) + end) + melee_ai:dynamic_wait(secs(40)) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Harakan drop force + Wraith / Salamander / Centaur support + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranStarpad, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranStarport, 65, true) + town:build(1, UnitId.TerranRotary, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranNaniteAssembly, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/terran/orbital/rapid_starpads.lua b/mpq/lua/melee/terran/orbital/rapid_starpads.lua new file mode 100644 index 00000000..c978893e --- /dev/null +++ b/mpq/lua/melee/terran/orbital/rapid_starpads.lua @@ -0,0 +1,75 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Orbital: 2 Starpad Wraith", + unit_composition = { + -- signature unit + [UnitId.TerranWraith] = 3, + -- filler units + [UnitId.TerranSalamander] = 1, + [UnitId.TerranAzazel] = 1, + [UnitId.TerranSeraph] = 1, + [UnitId.TerranCentaur] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.TerranStarpad, 110) + melee_ai:dynamic_wait(secs(50)) + town:build(2, UnitId.TerranStarpad, 90) + melee_ai:dynamic_wait(mins(1) + secs(5)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(mins(1) + secs(15)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(25)) + town:wait_build(2, UnitId.TerranStarpad) + town:build(2, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(20)) + town:build(3, UnitId.TerranStarpad, 90) + melee_ai:dynamic_wait(mins(2) + secs(5)) + -- tier2 + town:build(1, UnitId.TerranAtlas, 70, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranStarport, 70) + town:wait_build(1, UnitId.TerranStarport) + town:build(1, UnitId.TerranRotary, 69) + town:build(2, UnitId.TerranStarport, 70) + town:wait_build(2, UnitId.TerranStarport) + town:build(2, UnitId.TerranRotary, 69) + town:build(3, UnitId.TerranStarport, 70) + town:wait_build(3, UnitId.TerranStarport) + town:build(1, UnitId.TerranCommandment, 69) + end) + melee_ai:dynamic_wait(secs(40)) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Wraith fleet + Salamander / Azazel / Seraph gunships + town:build(1, UnitId.TerranStarpad, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranStarport, 65, true) + town:build(1, UnitId.TerranRotary, 65, true) + town:build(1, UnitId.TerranCommandment, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranNaniteAssembly, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/terran/orbital/sudden_starport.lua b/mpq/lua/melee/terran/orbital/sudden_starport.lua new file mode 100644 index 00000000..e46f41a8 --- /dev/null +++ b/mpq/lua/melee/terran/orbital/sudden_starport.lua @@ -0,0 +1,78 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Orbital: Sudden Starport", + unit_composition = { + -- signature units + [UnitId.TerranMaverick] = 2, + [UnitId.TerranSundog] = 2, + [UnitId.TerranSalamander] = 2, + -- healers + [UnitId.TerranCleric] = 1.5, + -- filler units + [UnitId.TerranCentaur] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranStockade, 110) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(40)) + town:build(2, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(20)) + town:build(3, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(15)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(50)) + town:wait_build(3, UnitId.TerranStockade, false) + -- tier2 + town:multirun(function(town) + town:wait_build(2, UnitId.TerranStockade) + town:build(1, UnitId.TerranVestry, 69) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranStarport, 70) + town:wait_build(1, UnitId.TerranStarport, false) + town:build(4, UnitId.TerranStarport, 70) + town:wait_build(1, UnitId.TerranStarport) + town:build(1, UnitId.TerranRotary, 69) + town:wait_build(2, UnitId.TerranStarport) + town:build(2, UnitId.TerranRotary, 69) + town:wait_build(3, UnitId.TerranStarport) + town:build(3, UnitId.TerranRotary, 69) + town:wait_build(4, UnitId.TerranStarport) + town:build(4, UnitId.TerranRotary, 69) + melee_ai:dynamic_wait(secs(15)) + end) + melee_ai:dynamic_wait(mins(1) + secs(15)) + town:build(1, UnitId.TerranAtlas, 70, true) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Maverick + Sundog / Salamander army (+ Cleric / Centaur) + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranVestry, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranStarport, 65, true) + town:build(1, UnitId.TerranRotary, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranNaniteAssembly, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/terran/orbital/the_don.lua b/mpq/lua/melee/terran/orbital/the_don.lua new file mode 100644 index 00000000..9e7d24d6 --- /dev/null +++ b/mpq/lua/melee/terran/orbital/the_don.lua @@ -0,0 +1,56 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Orbital: The Don", + unit_composition = { + -- signature units (Nanite Assembly x3) + [UnitId.TerranMinotaur] = 2, + [UnitId.TerranCentaur] = 2, + [UnitId.TerranMagnetar] = 2, + -- filler units + [UnitId.TerranGorgon] = 1, + [UnitId.TerranWraith] = 0.5, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + melee_ai:dynamic_wait(secs(50)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(mins(1)) + town:wait_build(1, UnitId.TerranStockade) + melee_ai:dynamic_wait(secs(40)) + -- tier2 + town:build(1, UnitId.TerranAtlas, 70, true) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(2, UnitId.TerranNaniteAssembly, 50) + melee_ai:dynamic_wait(secs(20)) + town:build(3, UnitId.TerranNaniteAssembly, 50) + melee_ai:dynamic_wait(secs(20)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Nanite Assembly capital fleet (+ Gorgon / Wraith) + town:build(1, UnitId.TerranStarpad, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranStarport, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranNaniteAssembly, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/terran/orbital/wraith_bio.lua b/mpq/lua/melee/terran/orbital/wraith_bio.lua new file mode 100644 index 00000000..b7b6cfdb --- /dev/null +++ b/mpq/lua/melee/terran/orbital/wraith_bio.lua @@ -0,0 +1,65 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Orbital: Wraith Bio", + unit_composition = { + -- signature units + [UnitId.TerranMaverick] = 3, + [UnitId.TerranWraith] = 3, + -- filler units + [UnitId.TerranValkyrie] = 1, + [UnitId.TerranSalamander] = 1, + [UnitId.TerranCentaur] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranStockade, 110) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranStarpad, 90) + melee_ai:dynamic_wait(secs(15)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(40)) + town:build(2, UnitId.TerranStarpad, 90) + melee_ai:dynamic_wait(secs(5)) + town:build(2, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(3, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(5)) + melee_ai:start_attacking() + -- tier1 + melee_ai:dynamic_wait(secs(40)) + town:wait_build(3, UnitId.TerranStockade, false) + town:build(1, UnitId.TerranVestry, 89) + melee_ai:dynamic_wait(mins(1) + secs(15)) + -- tier2/tier3 + town:build(1, UnitId.TerranAtlas, 70, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Maverick + Wraith bio-air army (+ Valkyrie / Salamander / Centaur) + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranStarpad, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranStarport, 65, true) + town:build(1, UnitId.TerranRotary, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranNaniteAssembly, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/terran/raider.lua b/mpq/lua/melee/terran/raider.lua deleted file mode 100644 index 4bb09fa0..00000000 --- a/mpq/lua/melee/terran/raider.lua +++ /dev/null @@ -1,153 +0,0 @@ -local Basic = require("melee.terran.build.basic") -local Openers = require("melee.terran.build.openers") -local Tier1 = require("melee.terran.build.tier1") -local Tier2 = require("melee.terran.build.tier2") -local Tier3 = require("melee.terran.build.tier3") - -local expansion_build_order = { - Basic.build_expansion, - Tier1.vestry_request, - Tier2.acquire, - Tier1.covenant_request, - Tier3.acquire, -} -local attack_wave_cost_bias = 0.4 - -return { - ---@type AIPersonality - eight_rax = { - name = "Raider: 8Rax", - unit_composition = { - -- signature unit - [UnitId.TerranMaverick] = 3, - -- healers - [UnitId.TerranCleric] = 1.5, - -- filler units - [UnitId.TerranHarakan] = 1, - [UnitId.TerranCyprian] = 1, - }, - main_build_order = { - Openers.eight_rax, - Tier1.eight_rax, - Tier2.acquire, - Tier2.raider_vestry_covenant_buildup, - Tier3.acquire, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - three_rax_bio = { - name = "Raider: 3Rax Maverick & Cleric", - unit_composition = { - -- signature units - [UnitId.TerranMaverick] = 3, - -- healers - [UnitId.TerranCleric] = 2, - -- filler units - [UnitId.TerranEidolon] = 1, - }, - main_build_order = { - Openers.three_rax_bio, - Tier2.acquire, - Tier3.acquire, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - fast_anvil = { - name = "Raider: Fast Anvil", - unit_composition = { - -- signature units - [UnitId.TerranCyprian] = 2, - [UnitId.TerranEidolon] = 2, - -- filler units - [UnitId.TerranMaverick] = 1, - }, - main_build_order = { - Openers.fast_anvil, - Tier1.fast_anvil, - Tier2.acquire, - Tier2.raider_stockade_requeue, - Tier3.acquire, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - four_rax_pressure = { - name = "Raider: 4Rax Pressure", - unit_composition = { - -- healers - [UnitId.TerranShamanSupportMode] = 2, - -- filler units - [UnitId.TerranSavantEntropyGauntlets] = 1, - [UnitId.TerranCyprian] = 1, - }, - main_build_order = { - Openers.four_rax_pressure, - Tier1.four_rax_pressure, - Tier2.acquire, - Tier3.acquire, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - uprising = { - name = "Raider: Uprising", - unit_composition = { - -- signature units - [UnitId.TerranCyprian] = 3, - -- healers - [UnitId.TerranCleric] = 1.5, - -- filler units - [UnitId.TerranEidolon] = 1, - }, - main_build_order = { - Openers.stockade_quick_start, - Tier1.uprising, - Tier2.acquire, - Tier3.acquire, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - holy_ackmeds = { - name = "Raider: Holy Ackmeds!", - unit_composition = { - -- signature unit - [UnitId.TerranHarakan] = 3, - -- filler units - [UnitId.TerranSundog] = 1, - [UnitId.TerranSalamander] = 1, - }, - main_build_order = { - Openers.holy_ackmeds, - Tier2.acquire, - Tier2.raider_vestry_starport_rotary, - Tier3.acquire, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, -} diff --git a/mpq/lua/melee/terran/raider/eight_rax.lua b/mpq/lua/melee/terran/raider/eight_rax.lua new file mode 100644 index 00000000..e53b5b65 --- /dev/null +++ b/mpq/lua/melee/terran/raider/eight_rax.lua @@ -0,0 +1,72 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Raider: 8Rax", + unit_composition = { + -- signature unit + [UnitId.TerranMaverick] = 3, + -- healers + [UnitId.TerranCleric] = 1.5, + -- filler units + [UnitId.TerranHarakan] = 1, + [UnitId.TerranCyprian] = 1, + [UnitId.TerranMadcap] = 1, + [UnitId.TerranDilettante] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + melee_ai:build_and_wait(town, 1, UnitId.TerranStockade, 110, secs(15)) + melee_ai:build_sequence(town, 2, 6, UnitId.TerranStockade, 110, 0, secs(15), 0) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(15)) + town:wait_build(6, UnitId.TerranStockade, false) + melee_ai:dynamic_wait(mins(1) + secs(15)) + melee_ai:start_expanding() + -- tier1 scale-up + melee_ai:dynamic_wait(secs(40)) + melee_ai:build_and_wait(town, 8, UnitId.TerranStockade, 90, secs(50)) + -- tier2 + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(15)) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranStockade) + town:build(1, UnitId.TerranVestry, 69) + town:wait_build(2, UnitId.TerranStockade) + town:build(2, UnitId.TerranVestry, 69) + town:wait_build(3, UnitId.TerranStockade) + town:build(1, UnitId.TerranCovenant, 69) + town:wait_build(4, UnitId.TerranStockade) + town:build(2, UnitId.TerranCovenant, 69) + end) + melee_ai:dynamic_wait(secs(25)) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + + -- production for the Maverick-heavy raid (+ Cleric / Madcap / Dilettante) + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranVestry, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranCaptaincy, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranApothecary, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/terran/raider/fast_anvil.lua b/mpq/lua/melee/terran/raider/fast_anvil.lua new file mode 100644 index 00000000..c3f5ee00 --- /dev/null +++ b/mpq/lua/melee/terran/raider/fast_anvil.lua @@ -0,0 +1,77 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Raider: Fast Anvil", + unit_composition = { + -- signature units + [UnitId.TerranCyprian] = 2, + [UnitId.TerranEidolon] = 2, + -- filler units + [UnitId.TerranMaverick] = 1, + [UnitId.TerranMadcap] = 1, + [UnitId.TerranDilettante] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranStockade, 110) + melee_ai:dynamic_wait(secs(40)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(3, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(40)) + town:wait_build(3, UnitId.TerranStockade, false) + melee_ai:dynamic_wait(secs(25)) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranStockade) + town:build(1, UnitId.TerranVestry, 89) + town:wait_build(2, UnitId.TerranStockade) + town:build(1, UnitId.TerranCovenant, 89) + town:wait_build(1, UnitId.TerranCovenant, false) + town:build(1, UnitId.TerranAnvil, 89) + town:wait_build(3, UnitId.TerranStockade) + town:wait_build(1, UnitId.TerranAnvil, false) + town:build(2, UnitId.TerranCovenant, 89) + town:wait_build(4, UnitId.TerranStockade) + town:build(3, UnitId.TerranCovenant, 89) + end) + melee_ai:dynamic_wait(secs(25)) + -- tier2 + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(15)) + town:build(4, UnitId.TerranStockade, 70) + melee_ai:dynamic_wait(secs(40)) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Cyprian + Eidolon anvil raid (+ Madcap / Dilettante) + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranCovenant, 68, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranAnvil, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranCaptaincy, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranApothecary, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/terran/raider/four_rax_pressure.lua b/mpq/lua/melee/terran/raider/four_rax_pressure.lua new file mode 100644 index 00000000..0e2ef9ac --- /dev/null +++ b/mpq/lua/melee/terran/raider/four_rax_pressure.lua @@ -0,0 +1,71 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Raider: 4Rax Pressure", + unit_composition = { + -- healers + [UnitId.TerranShamanSupportMode] = 2, + -- filler units + [UnitId.TerranSavantEntropyGauntlets] = 1, + [UnitId.TerranCyprian] = 1, + [UnitId.TerranMadcap] = 1, + [UnitId.TerranDilettante] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranStockade, 110) + melee_ai:dynamic_wait(secs(20)) + town:build(2, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(20)) + town:build(3, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(20)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(mins(1)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(30)) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranStockade) + town:build(1, UnitId.TerranVestry, 89) + town:wait_build(2, UnitId.TerranStockade) + town:build(2, UnitId.TerranVestry, 89) + town:wait_build(3, UnitId.TerranStockade) + town:build(1, UnitId.TerranCovenant, 89) + town:wait_build(4, UnitId.TerranStockade) + town:build(2, UnitId.TerranCovenant, 89) + end) + melee_ai:dynamic_wait(secs(5)) + town:wait_build(4, UnitId.TerranStockade) + melee_ai:dynamic_wait(mins(1)) + -- tier2/tier3 + town:build(1, UnitId.TerranAtlas, 70, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Shaman + Savant support raid (+ Cyprian / Madcap / Dilettante) + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranVestry, 68, true) + town:build(1, UnitId.TerranCovenant, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranCaptaincy, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranApothecary, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/terran/raider/holy_ackmeds.lua b/mpq/lua/melee/terran/raider/holy_ackmeds.lua new file mode 100644 index 00000000..fbe2ec44 --- /dev/null +++ b/mpq/lua/melee/terran/raider/holy_ackmeds.lua @@ -0,0 +1,70 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Raider: Holy Ackmeds!", + unit_composition = { + -- signature unit + [UnitId.TerranHarakan] = 3, + -- filler units + [UnitId.TerranSundog] = 1, + [UnitId.TerranSalamander] = 1, + [UnitId.TerranDilettante] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranStockade, 110) + melee_ai:dynamic_wait(secs(45)) + town:build(2, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(3, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(25)) + town:build(4, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(15)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(40)) + town:wait_build(4, UnitId.TerranStockade, false) + melee_ai:dynamic_wait(mins(1) + secs(40)) + -- tier2 + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(5)) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranStockade) + town:build(1, UnitId.TerranVestry, 69) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranStarport, 70) + town:wait_build(1, UnitId.TerranStarport) + town:build(1, UnitId.TerranRotary, 69) + end) + melee_ai:dynamic_wait(secs(15)) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Harakan raid + Sundog / Salamander gunships + town:build(1, UnitId.TerranStockade, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranStarport, 65, true) + town:build(1, UnitId.TerranRotary, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranApothecary, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/terran/raider/three_rax_bio.lua b/mpq/lua/melee/terran/raider/three_rax_bio.lua new file mode 100644 index 00000000..5742b85d --- /dev/null +++ b/mpq/lua/melee/terran/raider/three_rax_bio.lua @@ -0,0 +1,65 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Raider: 3Rax Maverick & Cleric", + unit_composition = { + -- signature units + [UnitId.TerranMaverick] = 3, + -- healers + [UnitId.TerranCleric] = 2, + -- filler units + [UnitId.TerranEidolon] = 1, + [UnitId.TerranMadcap] = 1, + [UnitId.TerranDilettante] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranStockade, 110) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(mins(1) + secs(5)) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranStockade) + town:build(1, UnitId.TerranVestry, 89) + town:wait_build(2, UnitId.TerranStockade) + town:build(2, UnitId.TerranVestry, 89) + end) + melee_ai:dynamic_wait(secs(20)) + town:build(3, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(10)) + town:wait_build(3, UnitId.TerranStockade, false) + melee_ai:start_expanding() + melee_ai:dynamic_wait(mins(1) + secs(40)) + -- tier2 + town:build(1, UnitId.TerranAtlas, 70, true) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Maverick + Cleric bio raid (+ Eidolon / Madcap / Dilettante) + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranVestry, 68, true) + town:build(1, UnitId.TerranCovenant, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranCaptaincy, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranApothecary, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/terran/raider/uprising.lua b/mpq/lua/melee/terran/raider/uprising.lua new file mode 100644 index 00000000..07f1bd4c --- /dev/null +++ b/mpq/lua/melee/terran/raider/uprising.lua @@ -0,0 +1,67 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Raider: Uprising", + unit_composition = { + -- signature units + [UnitId.TerranCyprian] = 3, + -- healers + [UnitId.TerranCleric] = 1.5, + -- filler units + [UnitId.TerranEidolon] = 1, + [UnitId.TerranMadcap] = 1, + [UnitId.TerranDilettante] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranStockade, 110) + -- tier1 + melee_ai:dynamic_wait(secs(20)) + town:build(2, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(20)) + town:build(3, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(20)) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranStockade) + town:build(1, UnitId.TerranVestry, 89) + town:wait_build(4, UnitId.TerranStockade) + town:build(2, UnitId.TerranVestry, 89) + end) + melee_ai:dynamic_wait(secs(15)) + town:build(4, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(20)) + town:wait_build(4, UnitId.TerranStockade) + town:wait_build(2, UnitId.TerranVestry) + melee_ai:dynamic_wait(mins(1) + secs(40)) + -- tier2/tier3 + town:build(1, UnitId.TerranAtlas, 70, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Cyprian-heavy raid (+ Cleric / Eidolon / Madcap / Dilettante) + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranVestry, 68, true) + town:build(1, UnitId.TerranCovenant, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranCaptaincy, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranApothecary, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/zerg/assault.lua b/mpq/lua/melee/zerg/assault.lua deleted file mode 100644 index 9a63b0e8..00000000 --- a/mpq/lua/melee/zerg/assault.lua +++ /dev/null @@ -1,177 +0,0 @@ -local Basic = require("melee.zerg.build.basic") -local Openers = require("melee.zerg.build.openers") -local Tier1 = require("melee.zerg.build.tier1") -local Tier2 = require("melee.zerg.build.tier2") -local Tier3 = require("melee.zerg.build.tier3") - -local expansion_build_order = { - Basic.build_expansion, - Tier1.saturated_production, - Tier3.assault_expansion, -} -local attack_wave_cost_bias = 0.6 - -return { - ---@type AIPersonality - three_base_hydrith = { - name = "Assault: 3 Base Hydrith", - unit_composition = { - -- signature units - [UnitId.ZergHydralisk] = 3, - [UnitId.ZergZethrokor] = 2, - [UnitId.ZergUltrokor] = 2, - -- filler units - [UnitId.ZergKalkalisk] = 1, - [UnitId.ZergSovroleth] = 1, - [UnitId.ZergSkithrokor] = 1, - [UnitId.ZergBactalisk] = 1, - }, - main_build_order = { - Openers.three_base_hydrith, - Tier1.three_base_hydrith, - Tier2.hydrith_iroliris_hachirosk_zorkiz, - Tier3.hydrith_othstol_hachirosk, - Tier1.saturated_production, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - two_base_zorkiz = { - name = "Assault: 2 Base Hydrith-Zorkiz", - unit_composition = { - -- signature units - [UnitId.ZergHydralisk] = 3, - [UnitId.ZergUltrokor] = 2, - [UnitId.ZergZoryusthaleth] = 2, - -- filler units - [UnitId.ZergIzirokor] = 1, - [UnitId.ZergKalkalisk] = 1, - [UnitId.ZergSovroleth] = 1, - }, - main_build_order = { - Openers.two_base_zorkiz, - Tier1.two_base_zorkiz, - Tier2.zorkiz_iroliris_tethvith, - Tier3.acquire, - Tier1.saturated_production, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - two_base_hydrith_quazeth = { - name = "Assault: 2 Base Hydrith-Quazeth", - unit_composition = { - -- signature units - [UnitId.ZergHydralisk] = 3, - [UnitId.ZergZethrokor] = 2, - [UnitId.ZergUltrokor] = 2, - -- filler units - [UnitId.ZergQuazilisk] = 1, - [UnitId.ZergZoryusthaleth] = 1, - [UnitId.ZergNathrokor] = 1, - [UnitId.ZergVorvrokor] = 1, - }, - main_build_order = { - Openers.two_base_hydrith_quazeth, - Tier1.two_base_hydrith_quazeth, - Tier2.hydrith_quazeth_iroliris_vornath_kalkiir, - Tier3.acquire, - Tier1.saturated_production, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - two_base_alkag = { - name = "Assault: 2 Base Alkag", - unit_composition = { - -- signature units (Alkag Iteth) - [UnitId.ZergKagralisk] = 2, - [UnitId.ZergEvigrilisk] = 2, - [UnitId.ZergAlmaksalisk] = 2, - -- filler units - [UnitId.ZergSkithrokor] = 1, - [UnitId.ZergBactalisk] = 1, - }, - main_build_order = { - Openers.two_base_alkag, - Tier2.alkag_iroliris_hachirosk, - Tier3.acquire, - Tier1.saturated_production, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - potency = { - name = "Assault: Potency", - unit_composition = { - -- signature units - [UnitId.ZergZoryusthaleth] = 2, - [UnitId.ZergHydralisk] = 2, - [UnitId.ZergKalkalisk] = 2, - -- filler units - [UnitId.ZergMutalisk] = 1, - [UnitId.ZergKagralisk] = 1, - [UnitId.ZergSovroleth] = 1, - [UnitId.ZergEvigrilisk] = 1, - [UnitId.ZergAlmaksalisk] = 1, - [UnitId.ZergSkithrokor] = 1, - [UnitId.ZergBactalisk] = 1, - }, - main_build_order = { - Openers.hydrith_den_start, - Tier1.hachirosk_zorkiz_skibact_quazeth_scaleup, - Tier2.potency_iroliris_hachirosk_alkag, - Tier3.potency_othstol_settle, - Tier1.saturated_production, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - earthen_tides = { - name = "Assault: Earthen Tides", - unit_composition = { - -- signature units - [UnitId.ZergIzirokor] = 2, - [UnitId.ZergLakizilisk] = 2, - [UnitId.ZergProtathalor] = 2, - -- filler units - [UnitId.ZergSovroleth] = 1, - [UnitId.ZergKeskathalor] = 1, - [UnitId.ZergSkithrokor] = 1, - [UnitId.ZergBactalisk] = 1, - [UnitId.ZergNathrokor] = 1, - [UnitId.ZergVorvrokor] = 1, - }, - main_build_order = { - Openers.hydrith_den_start, - Tier1.hachirosk_zorkiz_skibact_quazeth_scaleup, - Tier2.earthen_iroliris_hachirosk_vornath_mutath_matravil, - Tier3.acquire, - Tier1.saturated_production, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, -} diff --git a/mpq/lua/melee/zerg/assault/earthen_tides.lua b/mpq/lua/melee/zerg/assault/earthen_tides.lua new file mode 100644 index 00000000..52c66018 --- /dev/null +++ b/mpq/lua/melee/zerg/assault/earthen_tides.lua @@ -0,0 +1,104 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Assault: Earthen Tides", + unit_composition = { + -- signature units + [UnitId.ZergIzirokor] = 2, + [UnitId.ZergLakizilisk] = 2, + [UnitId.ZergProtathalor] = 2, + -- filler units + [UnitId.ZergSovroleth] = 1, + [UnitId.ZergKeskathalor] = 1, + [UnitId.ZergSkithrokor] = 1, + [UnitId.ZergBactalisk] = 1, + [UnitId.ZergNathrokor] = 1, + [UnitId.ZergVorvrokor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergHydrithDen, 110, true) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(45)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(30)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergZorkizShroud, 90, true) + melee_ai:dynamic_wait(mins(1) + secs(30)) + town:build(1, UnitId.ZergSkibactScab, 90, true) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + melee_ai:dynamic_wait(secs(50)) + -- tier2 + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(40)) + town:build(3, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(25)) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(1, UnitId.ZergMutathSpire, 70, true) + melee_ai:dynamic_wait(mins(1)) + town:build(1, UnitId.ZergMatravilNest, 70, true) + end) + melee_ai:dynamic_wait(mins(2) + secs(5)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Earthen Tides army (Izirokor / Lakizilisk / Protathalor) + town:build(1, UnitId.ZergHydrithDen, 70, true) + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergVornathPond, 70, true) + town:build(1, UnitId.ZergSkibactScab, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergTosvrolHaunt, 70, true) + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergGeszkathGrotto, 50, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/zerg/assault/potency.lua b/mpq/lua/melee/zerg/assault/potency.lua new file mode 100644 index 00000000..4f70ce22 --- /dev/null +++ b/mpq/lua/melee/zerg/assault/potency.lua @@ -0,0 +1,104 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Assault: Potency", + unit_composition = { + -- signature units + [UnitId.ZergZoryusthaleth] = 2, + [UnitId.ZergHydralisk] = 2, + [UnitId.ZergKalkalisk] = 2, + -- filler units + [UnitId.ZergMutalisk] = 1, + [UnitId.ZergKagralisk] = 1, + [UnitId.ZergSovroleth] = 1, + [UnitId.ZergEvigrilisk] = 1, + [UnitId.ZergAlmaksalisk] = 1, + [UnitId.ZergSkithrokor] = 1, + [UnitId.ZergBactalisk] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergHydrithDen, 110, true) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(45)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(30)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergZorkizShroud, 90, true) + melee_ai:dynamic_wait(mins(1) + secs(30)) + town:build(1, UnitId.ZergSkibactScab, 90, true) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + melee_ai:dynamic_wait(secs(50)) + -- tier2 + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(40)) + town:build(3, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(25)) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergHydrithDen) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergTethvithSwamp, 70, true) + town:wait_build(1, UnitId.ZergIrolIris) + melee_ai:dynamic_wait(mins(1)) + town:build(1, UnitId.ZergAlkagIteth, 70, true) + end) + melee_ai:dynamic_wait(secs(25)) + town:build(4, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(mins(1) + secs(40)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the broad Potency army (Zorkiz / Hydra / Kalkiir / Alkag / Mutath) + town:build(1, UnitId.ZergHydrithDen, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + town:build(1, UnitId.ZergTethvithSwamp, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + town:build(1, UnitId.ZergAlkagIteth, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergTosvrolHaunt, 70, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/zerg/assault/three_base_hydrith.lua b/mpq/lua/melee/zerg/assault/three_base_hydrith.lua new file mode 100644 index 00000000..43520824 --- /dev/null +++ b/mpq/lua/melee/zerg/assault/three_base_hydrith.lua @@ -0,0 +1,89 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Assault: 3 Base Hydrith", + unit_composition = { + -- signature units + [UnitId.ZergHydralisk] = 3, + [UnitId.ZergZethrokor] = 2, + [UnitId.ZergUltrokor] = 2, + -- filler units + [UnitId.ZergKalkalisk] = 1, + [UnitId.ZergSovroleth] = 1, + [UnitId.ZergSkithrokor] = 1, + [UnitId.ZergBactalisk] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(5)) + town:build(1, UnitId.ZergHydrithDen, 90, true) + -- tier1 + melee_ai:dynamic_wait(mins(1) + secs(30)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergSkibactScab, 90, true) + melee_ai:dynamic_wait(secs(40)) + -- tier2 + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(15)) + town:build(3, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + melee_ai:dynamic_wait(secs(25)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + town:build(4, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Hydralisk / Zethrokor / Ultrokor assault army + town:build(1, UnitId.ZergHydrithDen, 70, true) + town:build(1, UnitId.ZergQuazethPool, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergTosvrolHaunt, 70, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/zerg/assault/two_base_alkag.lua b/mpq/lua/melee/zerg/assault/two_base_alkag.lua new file mode 100644 index 00000000..d2d0f73e --- /dev/null +++ b/mpq/lua/melee/zerg/assault/two_base_alkag.lua @@ -0,0 +1,81 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Assault: 2 Base Alkag", + unit_composition = { + -- signature units (Alkag Iteth) + [UnitId.ZergKagralisk] = 2, + [UnitId.ZergEvigrilisk] = 2, + [UnitId.ZergAlmaksalisk] = 2, + -- filler units + [UnitId.ZergSkithrokor] = 1, + [UnitId.ZergBactalisk] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(25)) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergHydrithDen) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergSkibactScab, 90, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergTethvithSwamp, 90, true) + town:wait_build(1, UnitId.ZergIrolIris) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ZergAlkagIteth, 90, true) + town:build(1, UnitId.ZergOthstolOviform, 90, true) + end) + town:build(1, UnitId.ZergHydrithDen, 90, true) + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_expanding() + -- tier2 + melee_ai:dynamic_wait(secs(55)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(15)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(mins(1) + secs(5)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Alkag Iteth army (Kagralisk / Evigrilisk / Almaksalisk) + town:build(1, UnitId.ZergHydrithDen, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + town:build(1, UnitId.ZergTethvithSwamp, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergAlkagIteth, 70, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/zerg/assault/two_base_hydrith_quazeth.lua b/mpq/lua/melee/zerg/assault/two_base_hydrith_quazeth.lua new file mode 100644 index 00000000..8b19b49c --- /dev/null +++ b/mpq/lua/melee/zerg/assault/two_base_hydrith_quazeth.lua @@ -0,0 +1,81 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Assault: 2 Base Hydrith-Quazeth", + unit_composition = { + -- signature units + [UnitId.ZergHydralisk] = 3, + [UnitId.ZergZethrokor] = 2, + [UnitId.ZergUltrokor] = 2, + -- filler units + [UnitId.ZergQuazilisk] = 1, + [UnitId.ZergZoryusthaleth] = 1, + [UnitId.ZergNathrokor] = 1, + [UnitId.ZergVorvrokor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(5)) + town:build(1, UnitId.ZergHydrithDen, 90, true) + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_attacking() + -- tier1 + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + melee_ai:dynamic_wait(secs(50)) + -- tier2 + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(15)) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(mins(1)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + end) + melee_ai:dynamic_wait(secs(15)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Hydralisk / Zethrokor / Ultrokor / Vornath army + town:build(1, UnitId.ZergHydrithDen, 70, true) + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergVornathPond, 70, true) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/zerg/assault/two_base_zorkiz.lua b/mpq/lua/melee/zerg/assault/two_base_zorkiz.lua new file mode 100644 index 00000000..927449be --- /dev/null +++ b/mpq/lua/melee/zerg/assault/two_base_zorkiz.lua @@ -0,0 +1,80 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Assault: 2 Base Hydrith-Zorkiz", + unit_composition = { + -- signature units + [UnitId.ZergHydralisk] = 3, + [UnitId.ZergUltrokor] = 2, + [UnitId.ZergZoryusthaleth] = 2, + -- filler units + [UnitId.ZergIzirokor] = 1, + [UnitId.ZergKalkalisk] = 1, + [UnitId.ZergSovroleth] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(5)) + town:build(1, UnitId.ZergHydrithDen, 90, true) + -- tier1 + melee_ai:dynamic_wait(secs(55)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(15)) + -- tier2 + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(35)) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ZergTethvithSwamp, 70, true) + town:build(1, UnitId.ZergCaphrolosk, 70) + melee_ai:dynamic_wait(secs(45)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Hydralisk / Ultrokor / Zoryusthaleth assault army + town:build(1, UnitId.ZergHydrithDen, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergTosvrolHaunt, 70, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/zerg/basic.lua b/mpq/lua/melee/zerg/basic.lua new file mode 100644 index 00000000..931880ba --- /dev/null +++ b/mpq/lua/melee/zerg/basic.lua @@ -0,0 +1,17 @@ +local Basic = {} + +---@type BuildOrder +function Basic.build_anti_ground(melee_ai, town) + melee_ai:build_sequence(town, 1, 3, UnitId.ZergSurkithCesiant, 80, 5, secs(25), secs(5)) + melee_ai:wait_can_make(UnitId.ZergSkortrithCesiant) + melee_ai:build_sequence(town, 1, 3, UnitId.ZergSkortrithCesiant, 80, 5, secs(25), secs(5)) +end + +---@type BuildOrder +function Basic.build_anti_air(melee_ai, town) + melee_ai:build_sequence(town, 1, 3, UnitId.ZergSpraithCesiant, 80, 5, secs(25), secs(5)) + melee_ai:wait_can_make(UnitId.ZergSpirtithCesiant) + melee_ai:build_sequence(town, 1, 3, UnitId.ZergSpirtithCesiant, 80, 5, secs(25), secs(5)) +end + +return Basic diff --git a/mpq/lua/melee/zerg/build/basic.lua b/mpq/lua/melee/zerg/build/basic.lua deleted file mode 100644 index dd9bb8e1..00000000 --- a/mpq/lua/melee/zerg/build/basic.lua +++ /dev/null @@ -1,31 +0,0 @@ -local Basic = {} - ----@param melee_ai MeleeAI ----@param town Town -function Basic.build_expansion(melee_ai, town) - town:build(1, UnitId.ZergHachirosk, 120) - town:wait_build(1, UnitId.ZergHachirosk) - town:build(town.max_workers, UnitId.ZergDroleth, 100) - town:transfer_workers(8) - town:wait_build(10, UnitId.ZergDroleth) -end - ----@param melee_ai MeleeAI ----@param town Town -function Basic.build_anti_ground(melee_ai, town) - for i = 1, 3 do - town:build(i, UnitId.ZergSurkithCesiant, 80 - i * 5) - wait(secs(25 + i * 5)) - end -end - ----@param melee_ai MeleeAI ----@param town Town -function Basic.build_anti_air(melee_ai, town) - for i = 1, 3 do - town:build(i, UnitId.ZergSpraithCesiant, 80 - i * 5) - wait(secs(25 + i * 5)) - end -end - -return Basic diff --git a/mpq/lua/melee/zerg/build/openers.lua b/mpq/lua/melee/zerg/build/openers.lua deleted file mode 100644 index 0a246487..00000000 --- a/mpq/lua/melee/zerg/build/openers.lua +++ /dev/null @@ -1,298 +0,0 @@ ----@class ZergOpeners -local Openers = {} - --- Shared opener still used unmodified by a personality whose own build order --- never repositions an attack/expand trigger within this phase. - ----@param melee_ai MeleeAI ----@param town Town -function Openers.quazeth_pool_check_then_expand(melee_ai, town) - melee_ai:dynamic_wait(secs(40)) - town:build(1, UnitId.ZergQuazethPool, 110, true) - town:wait_build(1, UnitId.ZergQuazethPool, false) - melee_ai:start_expanding() -end - --- Assault - ----@param melee_ai MeleeAI ----@param town Town -function Openers.three_base_hydrith(melee_ai, town) - melee_ai:dynamic_wait(secs(25)) - melee_ai:start_expanding() - melee_ai:dynamic_wait(secs(5)) - town:build(1, UnitId.ZergHydrithDen, 90, true) -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.two_base_zorkiz(melee_ai, town) - melee_ai:dynamic_wait(secs(25)) - melee_ai:start_expanding() - melee_ai:dynamic_wait(secs(5)) - town:build(1, UnitId.ZergHydrithDen, 90, true) -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.two_base_hydrith_quazeth(melee_ai, town) - melee_ai:dynamic_wait(secs(25)) - melee_ai:start_expanding() - melee_ai:dynamic_wait(secs(5)) - town:build(1, UnitId.ZergHydrithDen, 90, true) - melee_ai:dynamic_wait(secs(30)) - melee_ai:start_attacking() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.two_base_alkag(melee_ai, town) - melee_ai:dynamic_wait(secs(25)) - town:multirun(function() - town:wait_build(1, UnitId.ZergHydrithDen) - melee_ai:dynamic_wait(secs(40)) - town:build(1, UnitId.ZergSkibactScab, 90, true) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergTethvithSwamp, 90, true) - town:wait_build(1, UnitId.ZergIrolIris) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ZergAlkagIteth, 90, true) - town:build(1, UnitId.ZergOthstolOviform, 90, true) - end) - town:build(1, UnitId.ZergHydrithDen, 90, true) - melee_ai:dynamic_wait(secs(30)) - melee_ai:start_expanding() -end - ---- Shared by Potency and Earthen Tides (identical build up to this point). ----@param melee_ai MeleeAI ----@param town Town -function Openers.hydrith_den_start(melee_ai, town) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.ZergHydrithDen, 110, true) - melee_ai:dynamic_wait(secs(25)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(secs(45)) - melee_ai:start_expanding() -end - --- Swarm - ----@param melee_ai MeleeAI ----@param town Town -function Openers.three_base_flood(melee_ai, town) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.ZergQuazethPool, 110, true) - melee_ai:dynamic_wait(secs(50)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(secs(15)) - melee_ai:start_expanding() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.three_base_ultrav(melee_ai, town) - melee_ai:dynamic_wait(secs(45)) - melee_ai:start_expanding() - melee_ai:dynamic_wait(secs(50)) - town:build(1, UnitId.ZergQuazethPool, 90, true) - melee_ai:dynamic_wait(mins(1) + secs(15)) - town:build(2, UnitId.ZergHachirosk, 115) - town:build(1, UnitId.ZergVornathPond, 90, true) - melee_ai:dynamic_wait(secs(50)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(secs(40)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.instant_quazeth(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ZergQuazethPool, 110, true) - melee_ai:dynamic_wait(secs(5)) - town:wait_build(1, UnitId.ZergQuazethPool, false) - melee_ai:dynamic_wait(secs(5)) - town:build(2, UnitId.ZergHachirosk, 115) - town:wait_build(1, UnitId.ZergQuazethPool) - melee_ai:start_attacking() - wait(secs(4)) - town:build(4, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(mins(1) + secs(20)) - melee_ai:start_expanding() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.three_base_othstol(melee_ai, town) - melee_ai:dynamic_wait(secs(45)) - melee_ai:start_expanding() - melee_ai:dynamic_wait(mins(1) + secs(55)) - town:build(1, UnitId.ZergQuazethPool, 90, true) -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.gates_of_hell(melee_ai, town) - melee_ai:dynamic_wait(secs(45)) - melee_ai:start_expanding() - melee_ai:dynamic_wait(mins(1) + secs(55)) - town:build(1, UnitId.ZergQuazethPool, 90, true) - melee_ai:dynamic_wait(secs(40)) - town:build(1, UnitId.ZergZorkizShroud, 90, true) - melee_ai:dynamic_wait(secs(25)) - melee_ai:start_attacking() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.primitive_pressure(melee_ai, town) - melee_ai:dynamic_wait(secs(45)) - melee_ai:start_expanding() - melee_ai:dynamic_wait(secs(50)) - town:build(1, UnitId.ZergQuazethPool, 90, true) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.ZergHydrithDen, 90, true) - melee_ai:dynamic_wait(secs(40)) - melee_ai:start_attacking() -end - --- Sunblot - ----@param melee_ai MeleeAI ----@param town Town -function Openers.big_and_little(melee_ai, town) - melee_ai:dynamic_wait(secs(30)) - melee_ai:start_expanding() - melee_ai:dynamic_wait(secs(40)) - town:build(1, UnitId.ZergQuazethPool, 90, true) - melee_ai:dynamic_wait(secs(15)) - town:build(2, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(40)) - town:build(1, UnitId.ZergVornathPond, 90, true) - melee_ai:dynamic_wait(secs(45)) - melee_ai:start_attacking() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.the_triad(melee_ai, town) - melee_ai:dynamic_wait(secs(30)) - melee_ai:start_expanding() - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ZergQuazethPool, 90, true) -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.skittering_duo(melee_ai, town) - melee_ai:dynamic_wait(secs(30)) - melee_ai:start_expanding() - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.ZergHydrithDen, 90, true) - melee_ai:dynamic_wait(mins(1)) - town:build(1, UnitId.ZergQuazethPool, 90, true) - melee_ai:dynamic_wait(secs(50)) - melee_ai:start_attacking() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.early_birds(melee_ai, town) - melee_ai:dynamic_wait(secs(30)) - melee_ai:start_expanding() - melee_ai:dynamic_wait(mins(1) + secs(25)) - town:build(1, UnitId.ZergQuazethPool, 90, true) -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.flying_feint(melee_ai, town) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.ZergQuazethPool, 110, true) - melee_ai:dynamic_wait(secs(25)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(secs(30)) - melee_ai:start_expanding() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.descending_horizon(melee_ai, town) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.ZergQuazethPool, 110, true) - melee_ai:dynamic_wait(secs(25)) - melee_ai:start_expanding() - melee_ai:dynamic_wait(mins(1) + secs(50)) - town:build(2, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.ZergVornathPond, 90, true) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ZergHydrithDen, 90, true) - melee_ai:dynamic_wait(secs(25)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(mins(1)) -end - --- General - ----@param melee_ai MeleeAI ----@param town Town -function Openers.sleeping_giant(melee_ai, town) - melee_ai:dynamic_wait(secs(45)) - melee_ai:start_expanding() - melee_ai:dynamic_wait(secs(30)) - town:build(1, UnitId.ZergQuazethPool, 90, true) -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.shrieking_swarm(melee_ai, town) - melee_ai:dynamic_wait(secs(45)) - melee_ai:start_expanding() - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ZergQuazethPool, 90, true) - melee_ai:dynamic_wait(secs(40)) - melee_ai:start_attacking() -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.subjugation(melee_ai, town) - melee_ai:dynamic_wait(secs(45)) - melee_ai:start_expanding() - melee_ai:dynamic_wait(secs(30)) - town:build(1, UnitId.ZergDroleth, 100) - melee_ai:dynamic_wait(secs(5)) - town:build(1, UnitId.ZergHydrithDen, 90, true) -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.before_the_storm(melee_ai, town) - melee_ai:dynamic_wait(secs(40)) - town:build(1, UnitId.ZergQuazethPool, 110, true) - town:wait_build(1, UnitId.ZergQuazethPool, false) - melee_ai:start_expanding() - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ZergDroleth, 100) - melee_ai:dynamic_wait(secs(50)) - town:build(2, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(40)) - town:build(1, UnitId.ZergZorkizShroud, 90, true) - melee_ai:dynamic_wait(secs(15)) - melee_ai:start_attacking() - melee_ai:dynamic_wait(mins(2) + secs(30)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Openers.time_after_time(melee_ai, town) - melee_ai:dynamic_wait(secs(45)) - melee_ai:start_expanding() - melee_ai:dynamic_wait(secs(40)) - town:build(1, UnitId.ZergHydrithDen, 90, true) - melee_ai:dynamic_wait(secs(40)) - melee_ai:start_attacking() -end - -return Openers diff --git a/mpq/lua/melee/zerg/build/tier1.lua b/mpq/lua/melee/zerg/build/tier1.lua deleted file mode 100644 index 7094d36c..00000000 --- a/mpq/lua/melee/zerg/build/tier1.lua +++ /dev/null @@ -1,229 +0,0 @@ ----@class ZergTier1 -local Tier1 = {} - ---- Saturated hatchery/larva production ramp, reused by every category's main build order. ----@param melee_ai MeleeAI ----@param town Town -function Tier1.saturated_production(melee_ai, town) - town:multirun(function() - town:wait_build(1, UnitId.ZergIrolIris) - town:build(5, UnitId.ZergLarvoskCesiant, 90) - melee_ai:dynamic_wait(secs(45)) - town:build(6, UnitId.ZergHachirosk, 90) - melee_ai:dynamic_wait(secs(45)) - town:build(6, UnitId.ZergCaphrolosk, 90) - town:wait_build(1, UnitId.ZergOthstolOviform) - melee_ai:dynamic_wait(secs(45)) - town:build(6, UnitId.ZergGathtelosk, 50) - end) -end - --- Assault (scale-up after the opener; unlisted personalities fold entirely --- into their opener and skip tier1) - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.three_base_hydrith(melee_ai, town) - melee_ai:dynamic_wait(mins(1) + secs(30)) - town:build(2, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.ZergQuazethPool, 90, true) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ZergSkibactScab, 90, true) - melee_ai:dynamic_wait(secs(40)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.two_base_zorkiz(melee_ai, town) - melee_ai:dynamic_wait(secs(55)) - town:build(2, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(15)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.two_base_hydrith_quazeth(melee_ai, town) - melee_ai:dynamic_wait(secs(40)) - town:build(1, UnitId.ZergQuazethPool, 90, true) - melee_ai:dynamic_wait(secs(50)) -end - ---- Shared by Potency and Earthen Tides (identical build up to this point). ----@param melee_ai MeleeAI ----@param town Town -function Tier1.hachirosk_zorkiz_skibact_quazeth_scaleup(melee_ai, town) - melee_ai:dynamic_wait(secs(30)) - town:build(2, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(40)) - town:build(1, UnitId.ZergZorkizShroud, 90, true) - melee_ai:dynamic_wait(mins(1) + secs(30)) - town:build(1, UnitId.ZergSkibactScab, 90, true) - melee_ai:dynamic_wait(secs(40)) - town:build(1, UnitId.ZergQuazethPool, 90, true) - melee_ai:dynamic_wait(secs(50)) -end - --- Swarm - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.three_base_flood(melee_ai, town) - melee_ai:dynamic_wait(secs(40)) - town:build(2, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(15)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.instant_quazeth(melee_ai, town) - melee_ai:dynamic_wait(secs(40)) - town:build(1, UnitId.ZergVornathPond, 90, true) - melee_ai:dynamic_wait(mins(1) + secs(55)) - town:build(1, UnitId.ZergHydrithDen, 90, true) - melee_ai:dynamic_wait(mins(2) + secs(45)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.three_base_othstol(melee_ai, town) - melee_ai:dynamic_wait(mins(1) + secs(15)) - town:build(2, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ZergVornathPond, 90, true) - melee_ai:dynamic_wait(secs(15)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.gates_of_hell(melee_ai, town) - melee_ai:dynamic_wait(secs(55)) - town:build(1, UnitId.ZergHydrithDen, 90, true) - melee_ai:dynamic_wait(secs(20)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.primitive_pressure(melee_ai, town) - melee_ai:dynamic_wait(secs(30)) - town:build(2, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ZergVornathPond, 90, true) - melee_ai:dynamic_wait(mins(1) + secs(30)) - town:build(1, UnitId.ZergZorkizShroud, 90, true) - melee_ai:dynamic_wait(secs(50)) -end - --- Sunblot - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.big_and_little(melee_ai, town) - melee_ai:dynamic_wait(secs(30)) - town:build(1, UnitId.ZergZorkizShroud, 90, true) - melee_ai:dynamic_wait(mins(1) + secs(55)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.the_triad(melee_ai, town) - melee_ai:dynamic_wait(mins(1) + secs(10)) - town:build(2, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(45)) - town:build(1, UnitId.ZergVornathPond, 90, true) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ZergHydrithDen, 90, true) - melee_ai:dynamic_wait(secs(40)) - town:build(1, UnitId.ZergZorkizShroud, 90, true) - melee_ai:dynamic_wait(mins(1)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.skittering_duo(melee_ai, town) - melee_ai:dynamic_wait(secs(75)) - town:build(2, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ZergVornathPond, 90, true) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ZergSkibactScab, 90, true) - melee_ai:dynamic_wait(mins(2) + secs(20)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.early_birds(melee_ai, town) - melee_ai:dynamic_wait(secs(55)) - town:build(1, UnitId.ZergVornathPond, 90, true) - melee_ai:dynamic_wait(secs(25)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.flying_feint(melee_ai, town) - melee_ai:dynamic_wait(mins(1)) - town:build(2, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(40)) -end - --- General - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.sleeping_giant(melee_ai, town) - melee_ai:dynamic_wait(mins(1)) - town:wait_build(15, UnitId.ZergDroleth) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ZergVornathPond, 90, true) - town:build(2, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(25)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.shrieking_swarm(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:build(2, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ZergVornathPond, 90, true) - melee_ai:dynamic_wait(secs(40)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.subjugation(melee_ai, town) - melee_ai:dynamic_wait(secs(15)) - town:build(2, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.ZergSkibactScab, 90, true) - melee_ai:dynamic_wait(secs(45)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.time_after_time(melee_ai, town) - melee_ai:dynamic_wait(secs(75)) - town:build(1, UnitId.ZergQuazethPool, 90, true) - melee_ai:dynamic_wait(secs(75)) - town:build(1, UnitId.ZergSkibactScab, 90, true) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ZergZorkizShroud, 90, true) - town:build(2, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(50)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier1.coil_buildup(melee_ai, town) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ZergDroleth, 100) - wait(secs(1)) - town:build(1, UnitId.ZergQuazethPool, 90, true) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergHydrithDen, 90, true) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.ZergVornathPond, 90, true) - melee_ai:dynamic_wait(mins(1)) -end - -return Tier1 diff --git a/mpq/lua/melee/zerg/build/tier2.lua b/mpq/lua/melee/zerg/build/tier2.lua deleted file mode 100644 index 9f8283b7..00000000 --- a/mpq/lua/melee/zerg/build/tier2.lua +++ /dev/null @@ -1,512 +0,0 @@ ----@class ZergTier2 -local Tier2 = {} - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.hydrith_iroliris_hachirosk_zorkiz(melee_ai, town) - town:build(1, UnitId.ZergIrolIris, 70, true) - melee_ai:dynamic_wait(mins(1) + secs(15)) - town:build(3, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ZergZorkizShroud, 70, true) - melee_ai:dynamic_wait(secs(25)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.zorkiz_iroliris_tethvith(melee_ai, town) - town:build(1, UnitId.ZergIrolIris, 70, true) - melee_ai:dynamic_wait(secs(20) + secs(15)) - town:build(1, UnitId.ZergZorkizShroud, 70, true) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ZergTethvithSwamp, 70, true) - town:build(1, UnitId.ZergCaphrolosk, 70) - melee_ai:dynamic_wait(secs(45)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.hydrith_quazeth_iroliris_vornath_kalkiir(melee_ai, town) - town:build(1, UnitId.ZergIrolIris, 70, true) - melee_ai:dynamic_wait(secs(15)) - town:multirun(function() - town:wait_build(1, UnitId.ZergQuazethPool) - melee_ai:dynamic_wait(secs(50)) - town:build(1, UnitId.ZergVornathPond, 70, true) - melee_ai:dynamic_wait(mins(1)) - town:build(1, UnitId.ZergKalkiirLake, 70, true) - end) - melee_ai:dynamic_wait(secs(15)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.alkag_iroliris_hachirosk(melee_ai, town) - melee_ai:dynamic_wait(secs(55)) - town:build(1, UnitId.ZergIrolIris, 70, true) - melee_ai:dynamic_wait(mins(1) + secs(15)) - town:build(2, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(mins(1) + secs(5)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.potency_iroliris_hachirosk_alkag(melee_ai, town) - town:build(1, UnitId.ZergIrolIris, 70, true) - melee_ai:dynamic_wait(secs(40)) - town:build(3, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(25)) - town:multirun(function() - town:wait_build(1, UnitId.ZergHydrithDen) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ZergSkibactScab, 70, true) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergTethvithSwamp, 70, true) - town:wait_build(1, UnitId.ZergIrolIris) - melee_ai:dynamic_wait(mins(1)) - town:build(1, UnitId.ZergAlkagIteth, 70, true) - end) - melee_ai:dynamic_wait(secs(25)) - town:build(4, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(mins(1) + secs(40)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.earthen_iroliris_hachirosk_vornath_mutath_matravil(melee_ai, town) - town:build(1, UnitId.ZergIrolIris, 70, true) - melee_ai:dynamic_wait(secs(40)) - town:build(3, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(25)) - town:multirun(function() - town:wait_build(1, UnitId.ZergQuazethPool) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergVornathPond, 70, true) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergKalkiirLake, 70, true) - town:wait_build(1, UnitId.ZergIrolIris) - town:build(1, UnitId.ZergMutathSpire, 70, true) - melee_ai:dynamic_wait(mins(1)) - town:build(1, UnitId.ZergMatravilNest, 70, true) - end) - melee_ai:dynamic_wait(mins(2) + secs(5)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.flood_vornath_kalkiir_mutath_tosvrol_then_iroliris_caphrolosk_hachirosk(melee_ai, town) - town:multirun(function() - town:wait_build(1, UnitId.ZergQuazethPool) - melee_ai:dynamic_wait(secs(50)) - town:build(1, UnitId.ZergVornathPond, 70, true) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergKalkiirLake, 70, true) - town:wait_build(1, UnitId.ZergIrolIris) - town:wait_build(3, UnitId.ZergHachirosk, false) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ZergMutathSpire, 70, true) - town:wait_build(1, UnitId.ZergMutathSpire) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergTosvrolHaunt, 70, true) - end) - melee_ai:dynamic_wait(secs(25)) - town:multirun(function() - wait(secs(1)) - town:build(1, UnitId.ZergIrolIris, 70, true) - end) - melee_ai:dynamic_wait(secs(50)) - town:build(1, UnitId.ZergCaphrolosk, 70) - melee_ai:dynamic_wait(mins(1) + secs(20)) - town:build(3, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(25)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.ultrav_iroliris_caphrolosk_buildup(melee_ai, town) - town:multirun(function() - wait(secs(1)) - town:build(1, UnitId.ZergIrolIris, 70, true) - end) - melee_ai:dynamic_wait(secs(55)) - town:build(1, UnitId.ZergCaphrolosk, 70) - melee_ai:dynamic_wait(mins(1) + secs(15)) - town:multirun(function() - town:wait_build(1, UnitId.ZergQuazethPool) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergKalkiirLake, 70, true) - town:wait_build(1, UnitId.ZergZorkizShroud) - town:wait_build(2, UnitId.ZergHachirosk, false) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergUlgorgCavern, 70, true) - melee_ai:dynamic_wait(secs(20)) - town:wait_build(1, UnitId.ZergHydrithDen) - town:build(1, UnitId.ZergSkibactScab, 70, true) - melee_ai:dynamic_wait(secs(50)) - town:build(1, UnitId.ZergTethvithSwamp, 70, true) - town:wait_build(1, UnitId.ZergIrolIris) - melee_ai:dynamic_wait(secs(40)) - town:build(1, UnitId.ZergMatravilNest, 70, true) - town:wait_build(1, UnitId.ZergOthstolOviform) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ZergGathtelosk, 50) - end) - melee_ai:dynamic_wait(secs(30)) - town:build(1, UnitId.ZergZorkizShroud, 70, true) - melee_ai:dynamic_wait(mins(1) + secs(45)) - town:build(3, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(40)) - town:build(1, UnitId.ZergHydrithDen, 70, true) - melee_ai:dynamic_wait(secs(50)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.instant_iroliris_vornath_kalkiir(melee_ai, town) - town:multirun(function() - wait(secs(1)) - town:build(1, UnitId.ZergIrolIris, 70, true) - end) - melee_ai:dynamic_wait(secs(25)) - town:multirun(function() - town:wait_build(1, UnitId.ZergQuazethPool) - melee_ai:dynamic_wait(mins(3) + secs(20)) - town:build(1, UnitId.ZergVornathPond, 70, true) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergKalkiirLake, 70, true) - end) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.othstol_iroliris_buildup(melee_ai, town) - town:build(1, UnitId.ZergIrolIris, 70, true) - melee_ai:dynamic_wait(secs(40)) - town:build(3, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(25)) - town:multirun(function() - town:wait_build(1, UnitId.ZergQuazethPool) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergVornathPond, 70, true) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergKalkiirLake, 70, true) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:wait_build(1, UnitId.ZergHydrithDen) - town:build(1, UnitId.ZergSkibactScab, 70, true) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:wait_build(1, UnitId.ZergZorkizShroud) - town:build(1, UnitId.ZergUlgorgCavern, 70, true) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergTethvithSwamp, 70, true) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergZozarcGorge, 70, true) - town:wait_build(1, UnitId.ZergIrolIris) - melee_ai:dynamic_wait(secs(40)) - town:build(1, UnitId.ZergMatravilNest, 70, true) - town:wait_build(1, UnitId.ZergOthstolOviform) - town:build(1, UnitId.ZergGathtelosk, 50) - town:wait_build(1, UnitId.ZergGathtelosk, false) - town:wait_build(2, UnitId.ZergHachirosk, false) - end) - town:build(1, UnitId.ZergZorkizShroud, 70, true) - melee_ai:dynamic_wait(secs(40)) - town:build(1, UnitId.ZergHydrithDen, 70, true) - melee_ai:dynamic_wait(secs(15)) - town:build(3, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(5)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.gates_buildup_vornath_hachirosk_iroliris(melee_ai, town) - town:multirun(function() - town:wait_build(1, UnitId.ZergQuazethPool) - melee_ai:dynamic_wait(secs(40)) - town:build(1, UnitId.ZergVornathPond, 70, true) - melee_ai:dynamic_wait(mins(1)) - town:build(1, UnitId.ZergKalkiirLake, 70, true) - melee_ai:dynamic_wait(secs(20)) - town:wait_build(1, UnitId.ZergHydrithDen) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ZergSkibactScab, 70, true) - melee_ai:dynamic_wait(secs(50)) - town:build(1, UnitId.ZergTethvithSwamp, 70, true) - melee_ai:dynamic_wait(secs(20)) - town:wait_build(1, UnitId.ZergZorkizShroud) - melee_ai:dynamic_wait(secs(50)) - town:build(1, UnitId.ZergUlgorgCavern, 70, true) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergZozarcGorge, 70, true) - town:wait_build(1, UnitId.ZergIrolIris) - melee_ai:dynamic_wait(mins(8) + secs(20)) - town:multirun(function() - wait(secs(1)) - town:build(1, UnitId.ZergOthstolOviform, 65, true) - end) - end) - town:build(1, UnitId.ZergVornathPond, 70, true) - melee_ai:dynamic_wait(secs(25)) - town:build(2, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(15)) - town:multirun(function() - wait(secs(1)) - town:build(1, UnitId.ZergIrolIris, 70, true) - end) - melee_ai:dynamic_wait(secs(30)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.pressure_iroliris_vornath_skibact_tethvith(melee_ai, town) - town:multirun(function() - wait(secs(1)) - town:build(1, UnitId.ZergIrolIris, 70, true) - end) - town:multirun(function() - town:wait_build(1, UnitId.ZergQuazethPool) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergVornathPond, 70, true) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergKalkiirLake, 70, true) - melee_ai:dynamic_wait(secs(25)) - town:wait_build(1, UnitId.ZergHydrithDen) - melee_ai:dynamic_wait(mins(1)) - town:build(1, UnitId.ZergSkibactScab, 70, true) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergTethvithSwamp, 70, true) - end) - melee_ai:dynamic_wait(secs(40)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.big_little_iroliris_buildup_caphrolosk_hachirosk(melee_ai, town) - town:build(1, UnitId.ZergIrolIris, 70, true) - wait(secs(1)) - town:multirun(function() - wait(secs(1)) - town:wait_build(1, UnitId.ZergQuazethPool) - melee_ai:dynamic_wait(secs(50)) - town:build(1, UnitId.ZergVornathPond, 70, true) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergKalkiirLake, 70, true) - town:wait_build(1, UnitId.ZergZorkizShroud) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergUlgorgCavern, 70, true) - town:wait_build(1, UnitId.ZergIrolIris) - town:build(1, UnitId.ZergMutathSpire, 70, true) - town:wait_build(1, UnitId.ZergMutathSpire) - melee_ai:dynamic_wait(mins(3) + secs(20)) - town:build(1, UnitId.ZergTosvrolHaunt, 70, true) - end) - melee_ai:dynamic_wait(mins(1) + secs(15)) - town:build(1, UnitId.ZergCaphrolosk, 70) - melee_ai:dynamic_wait(mins(1) + secs(45)) - town:build(3, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(30)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.birds_iroliris_alkag(melee_ai, town) - town:build(1, UnitId.ZergIrolIris, 70, true) - town:multirun(function() - town:wait_build(1, UnitId.ZergQuazethPool) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergVornathPond, 70, true) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergKalkiirLake, 70, true) - town:wait_build(1, UnitId.ZergIrolIris) - melee_ai:dynamic_wait(secs(40)) - town:build(1, UnitId.ZergMutathSpire, 70, true) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.ZergAlkagIteth, 70, true) - end) - melee_ai:dynamic_wait(mins(1) + secs(30)) - town:build(2, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(mins(1) + secs(15)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.feint_iroliris_buildup_vornath_hydrith_skibact(melee_ai, town) - town:build(1, UnitId.ZergIrolIris, 70, true) - town:multirun(function() - town:wait_build(1, UnitId.ZergQuazethPool) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergVornathPond, 70, true) - melee_ai:dynamic_wait(mins(3) + secs(20)) - town:build(1, UnitId.ZergKalkiirLake, 70, true) - melee_ai:dynamic_wait(secs(25)) - town:wait_build(1, UnitId.ZergHydrithDen) - melee_ai:dynamic_wait(secs(50)) - town:build(1, UnitId.ZergSkibactScab, 70, true) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergTethvithSwamp, 70, true) - town:wait_build(1, UnitId.ZergIrolIris) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.ZergMutathSpire, 70, true) - end) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ZergVornathPond, 70, true) - melee_ai:dynamic_wait(secs(50)) - town:build(1, UnitId.ZergHydrithDen, 70, true) - melee_ai:dynamic_wait(secs(50)) - town:build(1, UnitId.ZergSkibactScab, 70, true) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.horizon_iroliris_buildup(melee_ai, town) - town:build(1, UnitId.ZergIrolIris, 70, true) - town:multirun(function() - town:wait_build(1, UnitId.ZergHydrithDen) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergSkibactScab, 70, true) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergTethvithSwamp, 70, true) - melee_ai:dynamic_wait(secs(25)) - town:wait_build(1, UnitId.ZergQuazethPool) - town:build(1, UnitId.ZergVornathPond, 70, true) - town:wait_build(1, UnitId.ZergVornathPond) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergKalkiirLake, 70, true) - melee_ai:dynamic_wait(secs(25)) - town:wait_build(1, UnitId.ZergIrolIris) - town:build(1, UnitId.ZergMutathSpire, 70, true) - town:wait_build(1, UnitId.ZergMutathSpire) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergTosvrolHaunt, 70, true) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ZergMatravilNest, 70, true) - end) - melee_ai:dynamic_wait(mins(2)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.giant_iroliris_caphrolosk_hachirosk_zorkiz_buildup(melee_ai, town) - town:multirun(function() - town:build(1, UnitId.ZergIrolIris, 70, true) - end) - melee_ai:dynamic_wait(secs(15) + secs(5)) - town:wait_build(1, UnitId.ZergIrolIris) - town:build(1, UnitId.ZergCaphrolosk, 70) - melee_ai:dynamic_wait(secs(30)) - town:build(3, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(30)) - town:build(1, UnitId.ZergZorkizShroud, 70, true) - melee_ai:dynamic_wait(secs(25)) - town:multirun(function() - town:wait_build(1, UnitId.ZergQuazethPool) - melee_ai:dynamic_wait(mins(1)) - town:build(1, UnitId.ZergVornathPond, 70, true) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergKalkiirLake, 70, true) - town:wait_build(1, UnitId.ZergIrolIris) - town:build(1, UnitId.ZergMatravilNest, 70, true) - melee_ai:dynamic_wait(mins(1)) - town:build(1, UnitId.ZergMutathSpire, 70, true) - melee_ai:dynamic_wait(mins(2) + secs(45)) - town:build(1, UnitId.ZergTosvrolHaunt, 70, true) - end) - melee_ai:dynamic_wait(secs(25)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.swarm_iroliris_vornathkalkiir_zorkiz_caphrolosk_hachirosk(melee_ai, town) - town:multirun(function() - town:build(1, UnitId.ZergIrolIris, 70, true) - end) - town:multirun(function() - town:wait_build(1, UnitId.ZergQuazethPool) - melee_ai:dynamic_wait(secs(40)) - town:build(1, UnitId.ZergVornathPond, 70, true) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergKalkiirLake, 70, true) - end) - melee_ai:dynamic_wait(mins(1)) - town:build(1, UnitId.ZergZorkizShroud, 70, true) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.ZergCaphrolosk, 70) - melee_ai:dynamic_wait(secs(30)) - town:build(3, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(15)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.subjugation_quazeth_iroliris_buildup(melee_ai, town) - melee_ai:dynamic_wait(secs(30)) - town:build(1, UnitId.ZergQuazethPool, 70, true) - melee_ai:dynamic_wait(secs(25)) - town:multirun(function() - town:build(1, UnitId.ZergIrolIris, 70, true) - end) - melee_ai:dynamic_wait(secs(50)) - town:multirun(function() - town:wait_build(1, UnitId.ZergHydrithDen) - melee_ai:dynamic_wait(secs(50)) - town:build(1, UnitId.ZergSkibactScab, 70, true) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergTethvithSwamp, 70, true) - town:wait_build(1, UnitId.ZergIrolIris) - town:build(1, UnitId.ZergMatravilNest, 70, true) - end) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ZergCaphrolosk, 70) - town:build(3, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(45)) - town:build(1, UnitId.ZergZorkizShroud, 70, true) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.storm_iroliris_hachirosk_vornathkalkiir(melee_ai, town) - town:multirun(function() - town:build(1, UnitId.ZergIrolIris, 70, true) - end) - melee_ai:dynamic_wait(secs(15)) - town:build(3, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(15)) - town:build(4, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(15)) - town:multirun(function() - town:wait_build(1, UnitId.ZergQuazethPool) - melee_ai:dynamic_wait(secs(30)) - town:build(1, UnitId.ZergVornathPond, 70, true) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergKalkiirLake, 70, true) - end) - melee_ai:dynamic_wait(secs(30)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.time_iroliris_vornathkalkiir(melee_ai, town) - town:multirun(function() - town:build(1, UnitId.ZergIrolIris, 70, true) - end) - melee_ai:dynamic_wait(secs(15)) - town:multirun(function() - town:wait_build(1, UnitId.ZergQuazethPool) - melee_ai:dynamic_wait(secs(50)) - town:build(1, UnitId.ZergVornathPond, 70, true) - melee_ai:dynamic_wait(mins(1) + secs(40)) - town:build(1, UnitId.ZergKalkiirLake, 70, true) - end) - melee_ai:dynamic_wait(secs(30)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier2.coil_iroliris_hachirosk(melee_ai, town) - town:multirun(function() - town:build(1, UnitId.ZergIrolIris, 70, true) - end) - melee_ai:dynamic_wait(secs(30) + mins(1) + secs(5)) - town:build(2, UnitId.ZergHachirosk, 115) -end - -return Tier2 diff --git a/mpq/lua/melee/zerg/build/tier3.lua b/mpq/lua/melee/zerg/build/tier3.lua deleted file mode 100644 index 4282ad42..00000000 --- a/mpq/lua/melee/zerg/build/tier3.lua +++ /dev/null @@ -1,168 +0,0 @@ ----@class ZergTier3 -local Tier3 = {} - ---- Requests Othstol Oviform and waits for it. The generic tier-3 tech ---- transition, for personalities without bespoke tier-3 content. ----@param melee_ai MeleeAI ----@param town Town -function Tier3.acquire(melee_ai, town) - town:build(1, UnitId.ZergOthstolOviform, 65, true) - melee_ai:dynamic_wait(secs(25)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier3.hydrith_othstol_hachirosk(melee_ai, town) - town:build(1, UnitId.ZergOthstolOviform, 65, true) - melee_ai:dynamic_wait(secs(25)) - town:build(4, UnitId.ZergHachirosk, 115) - melee_ai:dynamic_wait(secs(25)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier3.potency_othstol_settle(melee_ai, town) - town:build(1, UnitId.ZergOthstolOviform, 65, true) - melee_ai:dynamic_wait(secs(25)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier3.horizon_othstol(melee_ai, town) - town:multirun(function() - melee_ai:dynamic_wait(mins(1) + secs(15)) - town:build(1, UnitId.ZergOthstolOviform, 65, true) - end) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier3.giant_othstol_gathtelosk(melee_ai, town) - town:multirun(function() - town:build(1, UnitId.ZergOthstolOviform, 65, true) - end) - melee_ai:dynamic_wait(secs(50)) - town:build(1, UnitId.ZergGathtelosk, 50) - melee_ai:dynamic_wait(secs(15)) -end - --- Category expansion tails: reuse the same shared node-acquisition pattern per --- category, run once a new town is expanded into. - ----@param melee_ai MeleeAI ----@param town Town -function Tier3.assault_expansion(melee_ai, town) - town:build(1, UnitId.ZergIrolIris, 70, true) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ZergCaphrolosk, 70) - town:build(1, UnitId.ZergQuazethPool, 70, true) - town:build(1, UnitId.ZergKalkiirLake, 70, true) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ZergHachirosk, 70) - melee_ai:dynamic_wait(secs(5)) - town:build(1, UnitId.ZergHydrithDen, 70, true) - town:build(1, UnitId.ZergTethvithSwamp, 70, true) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.ZergMutathSpire, 70, true) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ZergMatravilNest, 70, true) - town:build(1, UnitId.ZergOthstolOviform, 65, true) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ZergZorkizShroud, 70, true) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ZergGathtelosk, 50) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ZergAlmakisAntre, 70, true) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ZergUlgorgCavern, 70, true) - melee_ai:dynamic_wait(secs(40)) - town:build(1, UnitId.ZergTosvrolHaunt, 70, true) - melee_ai:dynamic_wait(secs(50)) - town:build(1, UnitId.ZergGeszkathGrotto, 50, true) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier3.swarm_expansion(melee_ai, town) - melee_ai:dynamic_wait(secs(5)) - town:build(1, UnitId.ZergIrolIris, 70, true) - town:build(1, UnitId.ZergMutathSpire, 70, true) - melee_ai:dynamic_wait(secs(50)) - town:build(1, UnitId.ZergMatravilNest, 70, true) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ZergHydrithDen, 70, true) - town:build(1, UnitId.ZergTethvithSwamp, 70, true) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ZergZorkizShroud, 70, true) - melee_ai:dynamic_wait(secs(5)) - town:build(1, UnitId.ZergTosvrolHaunt, 70, true) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ZergOthstolOviform, 65, true) - town:build(1, UnitId.ZergGathtelosk, 50) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ZergAlmakisAntre, 70, true) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ZergUlgorgCavern, 70, true) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ZergGeszkathGrotto, 50, true) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier3.sunblot_expansion(melee_ai, town) - town:build(1, UnitId.ZergIrolIris, 70, true) - town:build(1, UnitId.ZergQuazethPool, 70, true) - town:build(1, UnitId.ZergMutathSpire, 70, true) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ZergHydrithDen, 70, true) - town:build(1, UnitId.ZergTethvithSwamp, 70, true) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ZergTosvrolHaunt, 70, true) - town:build(1, UnitId.ZergKalkiirLake, 70, true) - melee_ai:dynamic_wait(secs(40)) - town:build(1, UnitId.ZergMatravilNest, 70, true) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ZergOthstolOviform, 65, true) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ZergAlmakisAntre, 70, true) - melee_ai:dynamic_wait(secs(5)) - town:build(1, UnitId.ZergGathtelosk, 50) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ZergGeszkathGrotto, 50, true) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.ZergZorkizShroud, 70, true) - melee_ai:dynamic_wait(secs(40)) - town:build(1, UnitId.ZergUlgorgCavern, 70, true) - melee_ai:dynamic_wait(secs(25)) -end - ----@param melee_ai MeleeAI ----@param town Town -function Tier3.general_expansion(melee_ai, town) - town:build(1, UnitId.ZergHydrithDen, 70, true) - melee_ai:dynamic_wait(secs(20)) - town:build(1, UnitId.ZergQuazethPool, 70, true) - town:build(1, UnitId.ZergKalkiirLake, 70, true) - town:build(1, UnitId.ZergIrolIris, 70, true) - melee_ai:dynamic_wait(secs(5)) - town:build(1, UnitId.ZergMutathSpire, 70, true) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ZergZorkizShroud, 70, true) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ZergTethvithSwamp, 70, true) - melee_ai:dynamic_wait(secs(40)) - town:build(1, UnitId.ZergOthstolOviform, 65, true) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ZergGathtelosk, 50) - melee_ai:dynamic_wait(secs(15)) - town:build(1, UnitId.ZergUlgorgCavern, 70, true) - melee_ai:dynamic_wait(secs(40)) - town:build(1, UnitId.ZergTosvrolHaunt, 70, true) - melee_ai:dynamic_wait(secs(25)) - town:build(1, UnitId.ZergMatravilNest, 70, true) - town:build(1, UnitId.ZergAlmakisAntre, 70, true) - melee_ai:dynamic_wait(secs(50)) - town:build(1, UnitId.ZergGeszkathGrotto, 50, true) -end - -return Tier3 diff --git a/mpq/lua/melee/zerg/general.lua b/mpq/lua/melee/zerg/general.lua deleted file mode 100644 index 24e17891..00000000 --- a/mpq/lua/melee/zerg/general.lua +++ /dev/null @@ -1,176 +0,0 @@ -local Basic = require("melee.zerg.build.basic") -local Openers = require("melee.zerg.build.openers") -local Tier1 = require("melee.zerg.build.tier1") -local Tier2 = require("melee.zerg.build.tier2") -local Tier3 = require("melee.zerg.build.tier3") - -local expansion_build_order = { - Basic.build_expansion, - Tier1.saturated_production, - Tier3.general_expansion, -} -local attack_wave_cost_bias = 0.5 - -return { - ---@type AIPersonality - sleeping_giant = { - name = "General: Sleeping Giant", - unit_composition = { - -- signature units - [UnitId.ZergZethrokor] = 2, - [UnitId.ZergUltrokor] = 2, - [UnitId.ZergHydralisk] = 2, - -- filler units - [UnitId.ZergKalkalisk] = 1, - [UnitId.ZergZoryusthaleth] = 1, - [UnitId.ZergMutalisk] = 1, - [UnitId.ZergNathrokor] = 1, - [UnitId.ZergVorvrokor] = 1, - }, - main_build_order = { - Openers.sleeping_giant, - Tier1.sleeping_giant, - Tier2.giant_iroliris_caphrolosk_hachirosk_zorkiz_buildup, - Tier3.giant_othstol_gathtelosk, - Tier1.saturated_production, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - shrieking_swarm = { - name = "General: Shrieking Swarm", - unit_composition = { - -- signature units (Vornath Pond) - [UnitId.ZergVorvrokor] = 2, - [UnitId.ZergNathrokor] = 2, - -- filler units - [UnitId.ZergUltrokor] = 1, - [UnitId.ZergHydralisk] = 1, - [UnitId.ZergLakizilisk] = 1, - [UnitId.ZergSovroleth] = 1, - }, - main_build_order = { - Openers.shrieking_swarm, - Tier1.shrieking_swarm, - Tier2.swarm_iroliris_vornathkalkiir_zorkiz_caphrolosk_hachirosk, - Tier3.acquire, - Tier1.saturated_production, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - subjugation = { - name = "General: Subjugation", - unit_composition = { - -- signature units (Skibact Scab) - [UnitId.ZergSkithrokor] = 2, - [UnitId.ZergBactalisk] = 2, - [UnitId.ZergZethrokor] = 2, - -- filler units - [UnitId.ZergKeskathalor] = 1, - [UnitId.ZergHydralisk] = 1, - [UnitId.ZergZoryusthaleth] = 1, - [UnitId.ZergVithrilisk] = 1, - }, - main_build_order = { - Openers.subjugation, - Tier1.subjugation, - Tier2.subjugation_quazeth_iroliris_buildup, - Tier3.acquire, - Tier1.saturated_production, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - before_the_storm = { - name = "General: Before the Storm", - unit_composition = { - -- signature units - [UnitId.ZergZethrokor] = 2, - [UnitId.ZergKalkalisk] = 2, - -- filler units - [UnitId.ZergZoryusthaleth] = 1, - [UnitId.ZergMutalisk] = 1, - [UnitId.ZergGeszithalor] = 1, - [UnitId.ZergNathrokor] = 1, - [UnitId.ZergVorvrokor] = 1, - }, - main_build_order = { - Openers.before_the_storm, - Tier2.storm_iroliris_hachirosk_vornathkalkiir, - Tier3.acquire, - Tier1.saturated_production, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - time_after_time = { - name = "General: Time After Time", - unit_composition = { - -- signature units - [UnitId.ZergZethrokor] = 2, - [UnitId.ZergSkithrokor] = 2, - [UnitId.ZergLakizilisk] = 2, - -- filler units - [UnitId.ZergLiiralisk] = 1, - [UnitId.ZergCikralisk] = 1, - [UnitId.ZergBactalisk] = 1, - [UnitId.ZergNathrokor] = 1, - [UnitId.ZergVorvrokor] = 1, - }, - main_build_order = { - Openers.time_after_time, - Tier1.time_after_time, - Tier2.time_iroliris_vornathkalkiir, - Tier3.acquire, - Tier1.saturated_production, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - constrained_coil = { - name = "General: Constrained Coil", - unit_composition = { - -- signature units - [UnitId.ZergZethrokor] = 2, - [UnitId.ZergKalkalisk] = 2, - -- filler units - [UnitId.ZergZoryusthaleth] = 1, - [UnitId.ZergMutalisk] = 1, - [UnitId.ZergGeszithalor] = 1, - [UnitId.ZergNathrokor] = 1, - [UnitId.ZergVorvrokor] = 1, - }, - main_build_order = { - Openers.quazeth_pool_check_then_expand, - Tier1.coil_buildup, - Tier2.coil_iroliris_hachirosk, - Tier3.acquire, - Tier1.saturated_production, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, -} diff --git a/mpq/lua/melee/zerg/general/before_the_storm.lua b/mpq/lua/melee/zerg/general/before_the_storm.lua new file mode 100644 index 00000000..d0f77b20 --- /dev/null +++ b/mpq/lua/melee/zerg/general/before_the_storm.lua @@ -0,0 +1,96 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "General: Before the Storm", + unit_composition = { + -- signature units + [UnitId.ZergZethrokor] = 2, + [UnitId.ZergKalkalisk] = 2, + -- filler units + [UnitId.ZergZoryusthaleth] = 1, + [UnitId.ZergMutalisk] = 1, + [UnitId.ZergGeszithalor] = 1, + [UnitId.ZergNathrokor] = 1, + [UnitId.ZergVorvrokor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergQuazethPool, 110, true) + town:wait_build(1, UnitId.ZergQuazethPool, false) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergDroleth, 100) + melee_ai:dynamic_wait(secs(50)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergZorkizShroud, 90, true) + melee_ai:dynamic_wait(secs(15)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(mins(2) + secs(30)) + -- tier2 + town:multirun(function(town) + town:build(1, UnitId.ZergIrolIris, 70, true) + end) + melee_ai:dynamic_wait(secs(15)) + town:build(3, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(15)) + town:build(4, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(15)) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + end) + melee_ai:dynamic_wait(secs(30)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Zethrokor / Kalkalisk army + Mutalisk / Geszithalor + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergGeszkathGrotto, 50, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/zerg/general/constrained_coil.lua b/mpq/lua/melee/zerg/general/constrained_coil.lua new file mode 100644 index 00000000..c5504c5c --- /dev/null +++ b/mpq/lua/melee/zerg/general/constrained_coil.lua @@ -0,0 +1,86 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "General: Constrained Coil", + unit_composition = { + -- signature units + [UnitId.ZergZethrokor] = 2, + [UnitId.ZergKalkalisk] = 2, + -- filler units + [UnitId.ZergZoryusthaleth] = 1, + [UnitId.ZergMutalisk] = 1, + [UnitId.ZergGeszithalor] = 1, + [UnitId.ZergNathrokor] = 1, + [UnitId.ZergVorvrokor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergQuazethPool, 110, true) + town:wait_build(1, UnitId.ZergQuazethPool, false) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergDroleth, 100) + melee_ai:dynamic_wait(secs(1)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergHydrithDen, 90, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergVornathPond, 90, true) + melee_ai:dynamic_wait(mins(1)) + -- tier2 + town:multirun(function(town) + town:build(1, UnitId.ZergIrolIris, 70, true) + end) + melee_ai:dynamic_wait(mins(1) + secs(35)) + town:build(2, UnitId.ZergHachirosk, 115) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the constrained Zethrokor / Kalkalisk army + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergGeszkathGrotto, 50, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/zerg/general/shrieking_swarm.lua b/mpq/lua/melee/zerg/general/shrieking_swarm.lua new file mode 100644 index 00000000..92650a6d --- /dev/null +++ b/mpq/lua/melee/zerg/general/shrieking_swarm.lua @@ -0,0 +1,95 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "General: Shrieking Swarm", + unit_composition = { + -- signature units (Vornath Pond) + [UnitId.ZergVorvrokor] = 2, + [UnitId.ZergNathrokor] = 2, + -- filler units + [UnitId.ZergUltrokor] = 1, + [UnitId.ZergHydralisk] = 1, + [UnitId.ZergLakizilisk] = 1, + [UnitId.ZergSovroleth] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(45)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + melee_ai:dynamic_wait(secs(40)) + melee_ai:start_attacking() + -- tier1 + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergVornathPond, 90, true) + melee_ai:dynamic_wait(secs(40)) + -- tier2 + town:multirun(function(town) + town:build(1, UnitId.ZergIrolIris, 70, true) + end) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + end) + melee_ai:dynamic_wait(mins(1)) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergCaphrolosk, 70) + melee_ai:dynamic_wait(secs(30)) + town:build(3, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(15)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Vornath-centric army (+ Ultrokor / Hydralisk / Zorkiz) + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + town:build(1, UnitId.ZergHydrithDen, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergVornathPond, 70, true) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergTosvrolHaunt, 70, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/zerg/general/sleeping_giant.lua b/mpq/lua/melee/zerg/general/sleeping_giant.lua new file mode 100644 index 00000000..5c8ebeb2 --- /dev/null +++ b/mpq/lua/melee/zerg/general/sleeping_giant.lua @@ -0,0 +1,107 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "General: Sleeping Giant", + unit_composition = { + -- signature units + [UnitId.ZergZethrokor] = 2, + [UnitId.ZergUltrokor] = 2, + [UnitId.ZergHydralisk] = 2, + -- filler units + [UnitId.ZergKalkalisk] = 1, + [UnitId.ZergZoryusthaleth] = 1, + [UnitId.ZergMutalisk] = 1, + [UnitId.ZergNathrokor] = 1, + [UnitId.ZergVorvrokor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(45)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + -- tier1 + melee_ai:dynamic_wait(mins(1)) + town:wait_build(15, UnitId.ZergDroleth) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ZergVornathPond, 90, true) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(25)) + -- tier2 + town:multirun(function(town) + town:build(1, UnitId.ZergIrolIris, 70, true) + end) + melee_ai:dynamic_wait(secs(20)) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(1, UnitId.ZergCaphrolosk, 70) + melee_ai:dynamic_wait(secs(30)) + town:build(3, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:dynamic_wait(mins(1)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(1, UnitId.ZergMatravilNest, 70, true) + melee_ai:dynamic_wait(mins(1)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + melee_ai:dynamic_wait(mins(2) + secs(45)) + town:build(1, UnitId.ZergTosvrolHaunt, 70, true) + end) + melee_ai:dynamic_wait(secs(25)) + -- tier3 + town:multirun(function(town) + town:build(1, UnitId.ZergOthstolOviform, 65, true) + end) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ZergGathtelosk, 50) + melee_ai:dynamic_wait(secs(15)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Zethrokor / Ultrokor / Hydralisk army + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + town:build(1, UnitId.ZergHydrithDen, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergVornathPond, 70, true) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/zerg/general/subjugation.lua b/mpq/lua/melee/zerg/general/subjugation.lua new file mode 100644 index 00000000..73779a6e --- /dev/null +++ b/mpq/lua/melee/zerg/general/subjugation.lua @@ -0,0 +1,100 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "General: Subjugation", + unit_composition = { + -- signature units (Skibact Scab) + [UnitId.ZergSkithrokor] = 2, + [UnitId.ZergBactalisk] = 2, + [UnitId.ZergZethrokor] = 2, + -- filler units + [UnitId.ZergKeskathalor] = 1, + [UnitId.ZergHydralisk] = 1, + [UnitId.ZergZoryusthaleth] = 1, + [UnitId.ZergVithrilisk] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(45)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergDroleth, 100) + melee_ai:dynamic_wait(secs(5)) + town:build(1, UnitId.ZergHydrithDen, 90, true) + -- tier1 + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergSkibactScab, 90, true) + melee_ai:dynamic_wait(secs(45)) + -- tier2 + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergQuazethPool, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:multirun(function(town) + town:build(1, UnitId.ZergIrolIris, 70, true) + end) + melee_ai:dynamic_wait(secs(50)) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergHydrithDen) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergTethvithSwamp, 70, true) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(1, UnitId.ZergMatravilNest, 70, true) + end) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ZergCaphrolosk, 70) + town:build(3, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Skibact / Zethrokor army + Keskathalor tech + town:build(1, UnitId.ZergHydrithDen, 70, true) + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + town:build(1, UnitId.ZergTethvithSwamp, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergGeszkathGrotto, 50, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/zerg/general/time_after_time.lua b/mpq/lua/melee/zerg/general/time_after_time.lua new file mode 100644 index 00000000..2f7a3cf5 --- /dev/null +++ b/mpq/lua/melee/zerg/general/time_after_time.lua @@ -0,0 +1,94 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "General: Time After Time", + unit_composition = { + -- signature units + [UnitId.ZergZethrokor] = 2, + [UnitId.ZergSkithrokor] = 2, + [UnitId.ZergLakizilisk] = 2, + -- filler units + [UnitId.ZergLiiralisk] = 1, + [UnitId.ZergCikralisk] = 1, + [UnitId.ZergBactalisk] = 1, + [UnitId.ZergNathrokor] = 1, + [UnitId.ZergVorvrokor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(45)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergHydrithDen, 90, true) + melee_ai:dynamic_wait(secs(40)) + melee_ai:start_attacking() + -- tier1 + melee_ai:dynamic_wait(mins(1) + secs(15)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + melee_ai:dynamic_wait(mins(1) + secs(15)) + town:build(1, UnitId.ZergSkibactScab, 90, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergZorkizShroud, 90, true) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(50)) + -- tier2 + town:multirun(function(town) + town:build(1, UnitId.ZergIrolIris, 70, true) + end) + melee_ai:dynamic_wait(secs(15)) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + end) + melee_ai:dynamic_wait(secs(30)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Zethrokor / Skithrokor / Lakizilisk army + town:build(1, UnitId.ZergHydrithDen, 70, true) + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/zerg/sunblot.lua b/mpq/lua/melee/zerg/sunblot.lua deleted file mode 100644 index 6aa99082..00000000 --- a/mpq/lua/melee/zerg/sunblot.lua +++ /dev/null @@ -1,174 +0,0 @@ -local Basic = require("melee.zerg.build.basic") -local Openers = require("melee.zerg.build.openers") -local Tier1 = require("melee.zerg.build.tier1") -local Tier2 = require("melee.zerg.build.tier2") -local Tier3 = require("melee.zerg.build.tier3") - -local expansion_build_order = { - Basic.build_expansion, - Tier1.saturated_production, - Tier3.sunblot_expansion, -} -local attack_wave_cost_bias = 0.6 - -return { - ---@type AIPersonality - big_and_little = { - name = "Sunblot: Big and Little", - unit_composition = { - -- signature units - [UnitId.ZergNathrokor] = 2, - [UnitId.ZergMutalisk] = 2, - [UnitId.ZergGorgrokor] = 2, - -- filler units - [UnitId.ZergGeszithalor] = 1, - [UnitId.ZergVilgorokor] = 1, - [UnitId.ZergSovroleth] = 1, - [UnitId.ZergVorvrokor] = 1, - }, - main_build_order = { - Openers.big_and_little, - Tier1.big_and_little, - Tier2.big_little_iroliris_buildup_caphrolosk_hachirosk, - Tier3.acquire, - Tier1.saturated_production, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - the_triad = { - name = "Sunblot: The Triad", - unit_composition = { - -- signature units - [UnitId.ZergNathrokor] = 2, - [UnitId.ZergGorgrokor] = 2, - [UnitId.ZergKalkalisk] = 2, - -- filler units - [UnitId.ZergMutalisk] = 1, - [UnitId.ZergGeszithalor] = 1, - [UnitId.ZergIsthrathaleth] = 1, - [UnitId.ZergVorvrokor] = 1, - }, - main_build_order = { - Openers.the_triad, - Tier1.the_triad, - Tier3.acquire, - Tier1.saturated_production, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - skittering_duo = { - name = "Sunblot: Skittering Duo", - unit_composition = { - -- signature units (Skibact Scab) - [UnitId.ZergSkithrokor] = 2, - [UnitId.ZergBactalisk] = 2, - [UnitId.ZergNathrokor] = 2, - -- filler units - [UnitId.ZergGorgrokor] = 1, - [UnitId.ZergMutalisk] = 1, - [UnitId.ZergGeszithalor] = 1, - [UnitId.ZergVorvrokor] = 1, - }, - main_build_order = { - Openers.skittering_duo, - Tier1.skittering_duo, - Tier3.acquire, - Tier1.saturated_production, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - early_birds = { - name = "Sunblot: Early Birds", - unit_composition = { - -- signature units (Alkag Iteth) - [UnitId.ZergKagralisk] = 2, - [UnitId.ZergEvigrilisk] = 2, - [UnitId.ZergAlmaksalisk] = 2, - -- filler units - [UnitId.ZergNathrokor] = 1, - [UnitId.ZergGorgrokor] = 1, - [UnitId.ZergMutalisk] = 1, - [UnitId.ZergGeszithalor] = 1, - [UnitId.ZergVorvrokor] = 1, - }, - main_build_order = { - Openers.early_birds, - Tier1.early_birds, - Tier2.birds_iroliris_alkag, - Tier3.acquire, - Tier1.saturated_production, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - flying_feint = { - name = "Sunblot: Flying Feint", - unit_composition = { - -- signature units - [UnitId.ZergNathrokor] = 2, - [UnitId.ZergSkithrokor] = 2, - -- filler units - [UnitId.ZergGorgrokor] = 1, - [UnitId.ZergMutalisk] = 1, - [UnitId.ZergBactalisk] = 1, - [UnitId.ZergGeszithalor] = 1, - [UnitId.ZergVorvrokor] = 1, - }, - main_build_order = { - Openers.flying_feint, - Tier1.flying_feint, - Tier2.feint_iroliris_buildup_vornath_hydrith_skibact, - Tier3.acquire, - Tier1.saturated_production, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - descending_horizon = { - name = "Sunblot: Descending Horizon", - unit_composition = { - -- signature units (Skibact Scab) - [UnitId.ZergSkithrokor] = 2, - [UnitId.ZergBactalisk] = 2, - -- filler units - [UnitId.ZergGorgrokor] = 1, - [UnitId.ZergMutalisk] = 1, - [UnitId.ZergGeszithalor] = 1, - [UnitId.ZergNathrokor] = 1, - [UnitId.ZergVorvrokor] = 1, - }, - main_build_order = { - Openers.descending_horizon, - Tier2.horizon_iroliris_buildup, - Tier3.horizon_othstol, - Tier1.saturated_production, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, -} diff --git a/mpq/lua/melee/zerg/sunblot/big_and_little.lua b/mpq/lua/melee/zerg/sunblot/big_and_little.lua new file mode 100644 index 00000000..1bbc2c19 --- /dev/null +++ b/mpq/lua/melee/zerg/sunblot/big_and_little.lua @@ -0,0 +1,107 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Sunblot: Big and Little", + unit_composition = { + -- signature units + [UnitId.ZergNathrokor] = 2, + [UnitId.ZergMutalisk] = 2, + [UnitId.ZergGorgrokor] = 2, + -- filler units + [UnitId.ZergGeszithalor] = 1, + [UnitId.ZergVilgorokor] = 1, + [UnitId.ZergSovroleth] = 1, + [UnitId.ZergVorvrokor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergVornathPond, 90, true) + melee_ai:dynamic_wait(secs(45)) + melee_ai:start_attacking() + -- tier1 + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergZorkizShroud, 90, true) + melee_ai:dynamic_wait(mins(1) + secs(55)) + -- tier2 + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(1)) + town:multirun(function(town) + melee_ai:dynamic_wait(secs(1)) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + town:wait_build(1, UnitId.ZergZorkizShroud) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(1, UnitId.ZergMutathSpire, 70, true) + town:wait_build(1, UnitId.ZergMutathSpire) + melee_ai:dynamic_wait(mins(3) + secs(20)) + town:build(1, UnitId.ZergTosvrolHaunt, 70, true) + end) + melee_ai:dynamic_wait(mins(1) + secs(15)) + town:build(1, UnitId.ZergCaphrolosk, 70) + melee_ai:dynamic_wait(mins(1) + secs(45)) + town:build(3, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(30)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Nathrokor / Mutalisk / Gorgrokor flyer army + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergVornathPond, 70, true) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + town:build(1, UnitId.ZergMatravilNest, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergTosvrolHaunt, 70, true) + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergGeszkathGrotto, 50, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/zerg/sunblot/descending_horizon.lua b/mpq/lua/melee/zerg/sunblot/descending_horizon.lua new file mode 100644 index 00000000..c5688bac --- /dev/null +++ b/mpq/lua/melee/zerg/sunblot/descending_horizon.lua @@ -0,0 +1,107 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Sunblot: Descending Horizon", + unit_composition = { + -- signature units (Skibact Scab) + [UnitId.ZergSkithrokor] = 2, + [UnitId.ZergBactalisk] = 2, + -- filler units + [UnitId.ZergGorgrokor] = 1, + [UnitId.ZergMutalisk] = 1, + [UnitId.ZergGeszithalor] = 1, + [UnitId.ZergNathrokor] = 1, + [UnitId.ZergVorvrokor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergQuazethPool, 110, true) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(mins(1) + secs(50)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergVornathPond, 90, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergHydrithDen, 90, true) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(mins(1)) + -- tier2 + town:build(1, UnitId.ZergIrolIris, 70, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergHydrithDen) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergTethvithSwamp, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:wait_build(1, UnitId.ZergQuazethPool) + town:build(1, UnitId.ZergVornathPond, 70, true) + town:wait_build(1, UnitId.ZergVornathPond) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(1, UnitId.ZergMutathSpire, 70, true) + town:wait_build(1, UnitId.ZergMutathSpire) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergTosvrolHaunt, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergMatravilNest, 70, true) + end) + melee_ai:dynamic_wait(mins(2)) + -- tier3 + town:multirun(function(town) + melee_ai:dynamic_wait(mins(1) + secs(15)) + town:build(1, UnitId.ZergOthstolOviform, 65, true) + end) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Skibact horizon army + Nathrokor flyer support + town:build(1, UnitId.ZergHydrithDen, 70, true) + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + town:build(1, UnitId.ZergVornathPond, 70, true) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergGeszkathGrotto, 50, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/zerg/sunblot/early_birds.lua b/mpq/lua/melee/zerg/sunblot/early_birds.lua new file mode 100644 index 00000000..c3b16621 --- /dev/null +++ b/mpq/lua/melee/zerg/sunblot/early_birds.lua @@ -0,0 +1,93 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Sunblot: Early Birds", + unit_composition = { + -- signature units (Alkag Iteth) + [UnitId.ZergKagralisk] = 2, + [UnitId.ZergEvigrilisk] = 2, + [UnitId.ZergAlmaksalisk] = 2, + -- filler units + [UnitId.ZergNathrokor] = 1, + [UnitId.ZergGorgrokor] = 1, + [UnitId.ZergMutalisk] = 1, + [UnitId.ZergGeszithalor] = 1, + [UnitId.ZergVorvrokor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(mins(1) + secs(25)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + -- tier1 + melee_ai:dynamic_wait(secs(55)) + town:build(1, UnitId.ZergVornathPond, 90, true) + melee_ai:dynamic_wait(secs(25)) + -- tier2 + town:build(1, UnitId.ZergIrolIris, 70, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + town:wait_build(1, UnitId.ZergIrolIris) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergAlkagIteth, 70, true) + end) + melee_ai:dynamic_wait(mins(1) + secs(30)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(mins(1) + secs(15)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Alkag Iteth army + Nathrokor / Mutalisk flyers + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergVornathPond, 70, true) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + town:build(1, UnitId.ZergAlkagIteth, 70, true) + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergGeszkathGrotto, 50, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/zerg/sunblot/flying_feint.lua b/mpq/lua/melee/zerg/sunblot/flying_feint.lua new file mode 100644 index 00000000..3dffde82 --- /dev/null +++ b/mpq/lua/melee/zerg/sunblot/flying_feint.lua @@ -0,0 +1,102 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Sunblot: Flying Feint", + unit_composition = { + -- signature units + [UnitId.ZergNathrokor] = 2, + [UnitId.ZergSkithrokor] = 2, + -- filler units + [UnitId.ZergGorgrokor] = 1, + [UnitId.ZergMutalisk] = 1, + [UnitId.ZergBactalisk] = 1, + [UnitId.ZergGeszithalor] = 1, + [UnitId.ZergVorvrokor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergQuazethPool, 110, true) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(mins(1)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(40)) + -- tier2 + town:build(1, UnitId.ZergIrolIris, 70, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(mins(3) + secs(20)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:wait_build(1, UnitId.ZergHydrithDen) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergTethvithSwamp, 70, true) + town:wait_build(1, UnitId.ZergIrolIris) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + end) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ZergHydrithDen, 70, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Nathrokor / Skithrokor feint army + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergHydrithDen, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergVornathPond, 70, true) + town:build(1, UnitId.ZergSkibactScab, 70, true) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergGeszkathGrotto, 50, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/zerg/sunblot/skittering_duo.lua b/mpq/lua/melee/zerg/sunblot/skittering_duo.lua new file mode 100644 index 00000000..7c982486 --- /dev/null +++ b/mpq/lua/melee/zerg/sunblot/skittering_duo.lua @@ -0,0 +1,84 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Sunblot: Skittering Duo", + unit_composition = { + -- signature units (Skibact Scab) + [UnitId.ZergSkithrokor] = 2, + [UnitId.ZergBactalisk] = 2, + [UnitId.ZergNathrokor] = 2, + -- filler units + [UnitId.ZergGorgrokor] = 1, + [UnitId.ZergMutalisk] = 1, + [UnitId.ZergGeszithalor] = 1, + [UnitId.ZergVorvrokor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergHydrithDen, 90, true) + melee_ai:dynamic_wait(mins(1)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + melee_ai:dynamic_wait(secs(50)) + melee_ai:start_attacking() + -- tier1 + melee_ai:dynamic_wait(mins(1) + secs(15)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergVornathPond, 90, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergSkibactScab, 90, true) + melee_ai:dynamic_wait(mins(2) + secs(20)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Skibact duo + Nathrokor flyer support + town:build(1, UnitId.ZergHydrithDen, 70, true) + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + town:build(1, UnitId.ZergVornathPond, 70, true) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergGeszkathGrotto, 50, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/zerg/sunblot/the_triad.lua b/mpq/lua/melee/zerg/sunblot/the_triad.lua new file mode 100644 index 00000000..3daa51dd --- /dev/null +++ b/mpq/lua/melee/zerg/sunblot/the_triad.lua @@ -0,0 +1,84 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Sunblot: The Triad", + unit_composition = { + -- signature units + [UnitId.ZergNathrokor] = 2, + [UnitId.ZergGorgrokor] = 2, + [UnitId.ZergKalkalisk] = 2, + -- filler units + [UnitId.ZergMutalisk] = 1, + [UnitId.ZergGeszithalor] = 1, + [UnitId.ZergIsthrathaleth] = 1, + [UnitId.ZergVorvrokor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + -- tier1 + melee_ai:dynamic_wait(mins(1) + secs(10)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ZergVornathPond, 90, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergHydrithDen, 90, true) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergZorkizShroud, 90, true) + melee_ai:dynamic_wait(mins(1)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Nathrokor / Gorgrokor / Kalkalisk triad + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergVornathPond, 70, true) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + town:build(1, UnitId.ZergMatravilNest, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergAlmakisAntre, 70, true) + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergGeszkathGrotto, 50, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/zerg/swarm.lua b/mpq/lua/melee/zerg/swarm.lua deleted file mode 100644 index dd651845..00000000 --- a/mpq/lua/melee/zerg/swarm.lua +++ /dev/null @@ -1,185 +0,0 @@ -local Basic = require("melee.zerg.build.basic") -local Openers = require("melee.zerg.build.openers") -local Tier1 = require("melee.zerg.build.tier1") -local Tier2 = require("melee.zerg.build.tier2") -local Tier3 = require("melee.zerg.build.tier3") - -local expansion_build_order = { - Basic.build_expansion, - Tier1.saturated_production, - Tier3.swarm_expansion, -} -local attack_wave_cost_bias = 0.4 - -return { - ---@type AIPersonality - three_base_flood = { - name = "Swarm: 3 Base Flood", - unit_composition = { - -- signature units - [UnitId.ZergZethrokor] = 2, - [UnitId.ZergUltrokor] = 2, - [UnitId.ZergHydralisk] = 2, - -- filler units - [UnitId.ZergKalkalisk] = 1, - [UnitId.ZergZoryusthaleth] = 1, - [UnitId.ZergMutalisk] = 1, - [UnitId.ZergNathrokor] = 1, - [UnitId.ZergVorvrokor] = 1, - }, - main_build_order = { - Openers.three_base_flood, - Tier1.three_base_flood, - Tier2.flood_vornath_kalkiir_mutath_tosvrol_then_iroliris_caphrolosk_hachirosk, - Tier3.acquire, - Tier1.saturated_production, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - three_base_ultrav = { - name = "Swarm: 3 Base Ultrav", - unit_composition = { - -- signature units - [UnitId.ZergUltrokor] = 3, - [UnitId.ZergZethrokor] = 2, - [UnitId.ZergHydralisk] = 2, - -- filler units - [UnitId.ZergKalkalisk] = 1, - [UnitId.ZergZoryusthaleth] = 1, - [UnitId.ZergMutalisk] = 1, - [UnitId.ZergNathrokor] = 1, - [UnitId.ZergVorvrokor] = 1, - [UnitId.ZergSkithrokor] = 1, - [UnitId.ZergBactalisk] = 1, - }, - main_build_order = { - Openers.three_base_ultrav, - Tier2.ultrav_iroliris_caphrolosk_buildup, - Tier3.acquire, - Tier1.saturated_production, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - instant_quazeth = { - name = "Swarm: Instant Quazeth", - unit_composition = { - -- signature units - [UnitId.ZergZethrokor] = 3, - [UnitId.ZergUltrokor] = 2, - [UnitId.ZergHydralisk] = 2, - -- filler units - [UnitId.ZergQuazilisk] = 1, - [UnitId.ZergKalkalisk] = 1, - [UnitId.ZergZoryusthaleth] = 1, - [UnitId.ZergNathrokor] = 1, - [UnitId.ZergVorvrokor] = 1, - }, - main_build_order = { - Openers.instant_quazeth, - Tier1.instant_quazeth, - Tier2.instant_iroliris_vornath_kalkiir, - Tier3.acquire, - Tier1.saturated_production, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - three_base_othstol = { - name = "Swarm: 3 Base Othstol", - unit_composition = { - -- signature units - [UnitId.ZergIzirokor] = 2, - [UnitId.ZergUltrokor] = 2, - [UnitId.ZergHydralisk] = 2, - -- filler units - [UnitId.ZergKalkalisk] = 1, - [UnitId.ZergZoryusthaleth] = 1, - [UnitId.ZergGorgrokor] = 1, - [UnitId.ZergSkithrokor] = 1, - [UnitId.ZergBactalisk] = 1, - [UnitId.ZergZobriolisk] = 1, - [UnitId.ZergZarcavrokor] = 1, - }, - main_build_order = { - Openers.three_base_othstol, - Tier1.three_base_othstol, - Tier2.othstol_iroliris_buildup, - Tier3.acquire, - Tier1.saturated_production, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - gates_of_hell = { - name = "Swarm: Gates of Hell", - unit_composition = { - -- signature units - [UnitId.ZergZethrokor] = 2, - [UnitId.ZergKeskathalor] = 2, - [UnitId.ZergHydralisk] = 2, - -- filler units - [UnitId.ZergKalkalisk] = 1, - [UnitId.ZergSovroleth] = 1, - [UnitId.ZergGorgrokor] = 1, - [UnitId.ZergSkithrokor] = 1, - [UnitId.ZergBactalisk] = 1, - }, - main_build_order = { - Openers.gates_of_hell, - Tier1.gates_of_hell, - Tier2.gates_buildup_vornath_hachirosk_iroliris, - Tier3.acquire, - Tier1.saturated_production, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, - - ---@type AIPersonality - primitive_pressure = { - name = "Swarm: Primitive Pressure", - unit_composition = { - -- signature units - [UnitId.ZergZethrokor] = 2, - [UnitId.ZergHydralisk] = 2, - [UnitId.ZergZoryusthaleth] = 2, - -- filler units - [UnitId.ZergLiiralisk] = 1, - [UnitId.ZergProtathalor] = 1, - [UnitId.ZergMatraleth] = 1, - [UnitId.ZergSovroleth] = 1, - [UnitId.ZergKeskathalor] = 1, - }, - main_build_order = { - Openers.primitive_pressure, - Tier1.primitive_pressure, - Tier2.pressure_iroliris_vornath_skibact_tethvith, - Tier3.acquire, - Tier1.saturated_production, - }, - expansion_build_order = expansion_build_order, - build_anti_ground_defenses = Basic.build_anti_ground, - build_anti_air_defenses = Basic.build_anti_air, - attack_wave_cost_bias = attack_wave_cost_bias, - }, -} diff --git a/mpq/lua/melee/zerg/swarm/gates_of_hell.lua b/mpq/lua/melee/zerg/swarm/gates_of_hell.lua new file mode 100644 index 00000000..5766a297 --- /dev/null +++ b/mpq/lua/melee/zerg/swarm/gates_of_hell.lua @@ -0,0 +1,118 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Swarm: Gates of Hell", + unit_composition = { + -- signature units + [UnitId.ZergZethrokor] = 2, + [UnitId.ZergKeskathalor] = 2, + [UnitId.ZergHydralisk] = 2, + -- filler units + [UnitId.ZergKalkalisk] = 1, + [UnitId.ZergSovroleth] = 1, + [UnitId.ZergGorgrokor] = 1, + [UnitId.ZergSkithrokor] = 1, + [UnitId.ZergBactalisk] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(45)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(mins(1) + secs(55)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergZorkizShroud, 90, true) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_attacking() + -- tier1 + melee_ai:dynamic_wait(secs(55)) + town:build(1, UnitId.ZergHydrithDen, 90, true) + melee_ai:dynamic_wait(secs(20)) + -- tier2 + town:multirun(function(town) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(mins(1)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:wait_build(1, UnitId.ZergHydrithDen) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ZergTethvithSwamp, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:wait_build(1, UnitId.ZergZorkizShroud) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergZozarcGorge, 70, true) + town:wait_build(1, UnitId.ZergIrolIris) + melee_ai:dynamic_wait(mins(8) + secs(20)) + town:multirun(function(town) + melee_ai:dynamic_wait(secs(1)) + town:build(1, UnitId.ZergOthstolOviform, 65, true) + end) + end) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(15)) + town:multirun(function(town) + melee_ai:dynamic_wait(secs(1)) + town:build(1, UnitId.ZergIrolIris, 70, true) + end) + melee_ai:dynamic_wait(secs(30)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Zethrokor / Keskathalor / Hydralisk army + town:build(1, UnitId.ZergHydrithDen, 70, true) + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergTosvrolHaunt, 70, true) + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergGeszkathGrotto, 50, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/zerg/swarm/instant_quazeth.lua b/mpq/lua/melee/zerg/swarm/instant_quazeth.lua new file mode 100644 index 00000000..9b8f75bc --- /dev/null +++ b/mpq/lua/melee/zerg/swarm/instant_quazeth.lua @@ -0,0 +1,93 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Swarm: Instant Quazeth", + unit_composition = { + -- signature units + [UnitId.ZergZethrokor] = 3, + [UnitId.ZergUltrokor] = 2, + [UnitId.ZergHydralisk] = 2, + -- filler units + [UnitId.ZergQuazilisk] = 1, + [UnitId.ZergKalkalisk] = 1, + [UnitId.ZergZoryusthaleth] = 1, + [UnitId.ZergNathrokor] = 1, + [UnitId.ZergVorvrokor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ZergQuazethPool, 110, true) + melee_ai:dynamic_wait(secs(5)) + town:wait_build(1, UnitId.ZergQuazethPool, false) + melee_ai:dynamic_wait(secs(5)) + town:build(2, UnitId.ZergHachirosk, 115) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(4)) + town:build(4, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(mins(1) + secs(20)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergVornathPond, 90, true) + melee_ai:dynamic_wait(mins(1) + secs(55)) + town:build(1, UnitId.ZergHydrithDen, 90, true) + melee_ai:dynamic_wait(mins(2) + secs(45)) + -- tier2 + town:multirun(function(town) + melee_ai:dynamic_wait(secs(1)) + town:build(1, UnitId.ZergIrolIris, 70, true) + end) + melee_ai:dynamic_wait(secs(25)) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:dynamic_wait(mins(3) + secs(20)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + end) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Zethrokor-heavy Quazeth swarm (+ Ultrokor / Hydralisk / Vornath) + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + town:build(1, UnitId.ZergHydrithDen, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergVornathPond, 70, true) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/zerg/swarm/primitive_pressure.lua b/mpq/lua/melee/zerg/swarm/primitive_pressure.lua new file mode 100644 index 00000000..d14d565d --- /dev/null +++ b/mpq/lua/melee/zerg/swarm/primitive_pressure.lua @@ -0,0 +1,104 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Swarm: Primitive Pressure", + unit_composition = { + -- signature units + [UnitId.ZergZethrokor] = 2, + [UnitId.ZergHydralisk] = 2, + [UnitId.ZergZoryusthaleth] = 2, + -- filler units + [UnitId.ZergLiiralisk] = 1, + [UnitId.ZergProtathalor] = 1, + [UnitId.ZergMatraleth] = 1, + [UnitId.ZergSovroleth] = 1, + [UnitId.ZergKeskathalor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(45)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergHydrithDen, 90, true) + melee_ai:dynamic_wait(secs(40)) + melee_ai:start_attacking() + -- tier1 + melee_ai:dynamic_wait(secs(30)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergVornathPond, 90, true) + melee_ai:dynamic_wait(mins(1) + secs(30)) + town:build(1, UnitId.ZergZorkizShroud, 90, true) + melee_ai:dynamic_wait(secs(50)) + -- tier2 + town:multirun(function(town) + melee_ai:dynamic_wait(secs(1)) + town:build(1, UnitId.ZergIrolIris, 70, true) + end) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:wait_build(1, UnitId.ZergHydrithDen) + melee_ai:dynamic_wait(mins(1)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergTethvithSwamp, 70, true) + end) + melee_ai:dynamic_wait(secs(40)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Zethrokor / Hydralisk / Zoryusthaleth pressure army + town:build(1, UnitId.ZergHydrithDen, 70, true) + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + town:build(1, UnitId.ZergMatravilNest, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergTosvrolHaunt, 70, true) + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergGeszkathGrotto, 50, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/zerg/swarm/three_base_flood.lua b/mpq/lua/melee/zerg/swarm/three_base_flood.lua new file mode 100644 index 00000000..75bd1d1e --- /dev/null +++ b/mpq/lua/melee/zerg/swarm/three_base_flood.lua @@ -0,0 +1,101 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Swarm: 3 Base Flood", + unit_composition = { + -- signature units + [UnitId.ZergZethrokor] = 2, + [UnitId.ZergUltrokor] = 2, + [UnitId.ZergHydralisk] = 2, + -- filler units + [UnitId.ZergKalkalisk] = 1, + [UnitId.ZergZoryusthaleth] = 1, + [UnitId.ZergMutalisk] = 1, + [UnitId.ZergNathrokor] = 1, + [UnitId.ZergVorvrokor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergQuazethPool, 110, true) + melee_ai:dynamic_wait(secs(50)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(15)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(40)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(15)) + -- tier2 + town:multirun(function(town) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + town:wait_build(1, UnitId.ZergIrolIris) + town:wait_build(3, UnitId.ZergHachirosk, false) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + town:wait_build(1, UnitId.ZergMutathSpire) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergTosvrolHaunt, 70, true) + end) + melee_ai:dynamic_wait(secs(25)) + town:multirun(function(town) + melee_ai:dynamic_wait(secs(1)) + town:build(1, UnitId.ZergIrolIris, 70, true) + end) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ZergCaphrolosk, 70) + melee_ai:dynamic_wait(mins(1) + secs(20)) + town:build(3, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(25)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Zethrokor / Ultrokor / Hydralisk flood + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + town:build(1, UnitId.ZergHydrithDen, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergVornathPond, 70, true) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/zerg/swarm/three_base_othstol.lua b/mpq/lua/melee/zerg/swarm/three_base_othstol.lua new file mode 100644 index 00000000..ebe3d4d2 --- /dev/null +++ b/mpq/lua/melee/zerg/swarm/three_base_othstol.lua @@ -0,0 +1,110 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Swarm: 3 Base Othstol", + unit_composition = { + -- signature units + [UnitId.ZergIzirokor] = 2, + [UnitId.ZergUltrokor] = 2, + [UnitId.ZergHydralisk] = 2, + -- filler units + [UnitId.ZergKalkalisk] = 1, + [UnitId.ZergZoryusthaleth] = 1, + [UnitId.ZergGorgrokor] = 1, + [UnitId.ZergSkithrokor] = 1, + [UnitId.ZergBactalisk] = 1, + [UnitId.ZergZobriolisk] = 1, + [UnitId.ZergZarcavrokor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(45)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(mins(1) + secs(55)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + -- tier1 + melee_ai:dynamic_wait(mins(1) + secs(15)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergVornathPond, 90, true) + melee_ai:dynamic_wait(secs(15)) + -- tier2 + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(40)) + town:build(3, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(25)) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:wait_build(1, UnitId.ZergHydrithDen) + town:build(1, UnitId.ZergSkibactScab, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:wait_build(1, UnitId.ZergZorkizShroud) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergTethvithSwamp, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergZozarcGorge, 70, true) + town:wait_build(1, UnitId.ZergIrolIris) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergMatravilNest, 70, true) + town:wait_build(1, UnitId.ZergOthstolOviform) + town:build(1, UnitId.ZergGathtelosk, 50) + town:wait_build(1, UnitId.ZergGathtelosk, false) + town:wait_build(2, UnitId.ZergHachirosk, false) + end) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergHydrithDen, 70, true) + melee_ai:dynamic_wait(secs(15)) + town:build(3, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(5)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Izirokor / Ultrokor / Hydralisk + Zozarc swarm + town:build(1, UnitId.ZergHydrithDen, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergZozarcGorge, 70, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/zerg/swarm/three_base_ultrav.lua b/mpq/lua/melee/zerg/swarm/three_base_ultrav.lua new file mode 100644 index 00000000..33e5aac5 --- /dev/null +++ b/mpq/lua/melee/zerg/swarm/three_base_ultrav.lua @@ -0,0 +1,114 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Swarm: 3 Base Ultrav", + unit_composition = { + -- signature units + [UnitId.ZergUltrokor] = 3, + [UnitId.ZergZethrokor] = 2, + [UnitId.ZergHydralisk] = 2, + -- filler units + [UnitId.ZergKalkalisk] = 1, + [UnitId.ZergZoryusthaleth] = 1, + [UnitId.ZergMutalisk] = 1, + [UnitId.ZergNathrokor] = 1, + [UnitId.ZergVorvrokor] = 1, + [UnitId.ZergSkithrokor] = 1, + [UnitId.ZergBactalisk] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(45)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + melee_ai:dynamic_wait(mins(1) + secs(15)) + town:build(2, UnitId.ZergHachirosk, 115) + town:build(1, UnitId.ZergVornathPond, 90, true) + melee_ai:dynamic_wait(secs(50)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(40)) + -- tier2 + town:multirun(function(town) + melee_ai:dynamic_wait(secs(1)) + town:build(1, UnitId.ZergIrolIris, 70, true) + end) + melee_ai:dynamic_wait(secs(55)) + town:build(1, UnitId.ZergCaphrolosk, 70) + melee_ai:dynamic_wait(mins(1) + secs(15)) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + town:wait_build(1, UnitId.ZergZorkizShroud) + town:wait_build(2, UnitId.ZergHachirosk, false) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:wait_build(1, UnitId.ZergHydrithDen) + town:build(1, UnitId.ZergSkibactScab, 70, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ZergTethvithSwamp, 70, true) + town:wait_build(1, UnitId.ZergIrolIris) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergMatravilNest, 70, true) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergGathtelosk, 50) + end) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(45)) + town:build(3, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergHydrithDen, 70, true) + melee_ai:dynamic_wait(secs(50)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Ultrokor-heavy swarm (+ Zethrokor / Hydralisk / Skibact) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergHydrithDen, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + town:build(1, UnitId.ZergVornathPond, 70, true) + town:build(1, UnitId.ZergSkibactScab, 70, true) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/start_melee_ai.lua b/mpq/lua/start_melee_ai.lua index 61858569..0c17bde9 100644 --- a/mpq/lua/start_melee_ai.lua +++ b/mpq/lua/start_melee_ai.lua @@ -1,10 +1,3 @@ require "melee.melee_ai" -local player = Player() -if player.type == PlayerType.Computer then - if player.race == RaceId.Askosi then - cprint(TextColor.Orange, "Player " .. player.name .. "(P" .. player.id .. "): Askosi AI is not supported!") - return - end - MeleeAI():run() -end +MeleeAI():run() diff --git a/mpq/portrait/n/vespene/fid00.smk b/mpq/portrait/n/vespene/fid00.smk new file mode 100644 index 00000000..60c70562 Binary files /dev/null and b/mpq/portrait/n/vespene/fid00.smk differ diff --git a/mpq/rez/stat.txt b/mpq/rez/stat.txt index ac14c202..e994d1cc 100644 --- a/mpq/rez/stat.txt +++ b/mpq/rez/stat.txt @@ -1025,7 +1025,7 @@ a<1><4>Construct Athla <1>(<3>A<1>)<10>Constructor model.<0> f<1><4>Construct Ferrum <1>(<3>F<1>)<10>Aggressor model.<0> c<1><4>Construct Chalyb <1>(<3>C<1>)<10>Defender model.<0> t<1><4>Construct Circitor <1>(<3>T<1>)<10>Pursuit model.<0> -x<1><4>Construct Exigo <1>(<3>X<1>)<10>Defense platform.<0> +x<1><4>Construct Exigo <1>(<3>X<1>)<10>Enforcer platform.<0> v<1><4>Construct Vicere <1>(<3>V<1>)<10>Assault platform.<0> Forerunner Alloy<0> Forerunner Lattice<0> @@ -1150,8 +1150,8 @@ Sasyrvoleth requires:<10> Axtoth Axis<0> e<1><4>Warp in Cicatus <1>(<3>E<1>)<10>Destitute skirmisher.<0> ยค<3><4>Servile Vigor <2>(passive)<10>Cohorts revive once after death, gaining a 10-second timed life. They can consume a nearby corpse to become permanent again.<0> a<1><4>Warp in Extatus <1>(<3>A<1>)<10>Stolid fighter.<0> -c<1><4>Erect Machinamentum <1>(<3>C<1>)<10>Assembly site.<0> -<0> +c<1><4>Erect Machinamentum <1>(<3>C<1>)<10>Core installation.<0> +r<1><4>Train Cyprian <1>(<3>R<1>)<10>Suppressing infantry.<0> s<1><4>Assemble Oscilliant <1>(<3>S<1>)<10>Assault drone.<0> a<1><4>Assemble Unar <1>(<3>A<1>)<10>Sniper drone.<0> r<1><4>Warp in Ashguard <1>(<3>R<1>)<10>Conquering strider.<0> @@ -2308,7 +2308,7 @@ Reactive Blaster<0> Plasmathrower<0> High-Tonnage Payload<0> Gauss Launcher<0> -<0> +Boreal Railguns<0> <0> <0> <0> diff --git a/mpq/rez/unitnames.tbl b/mpq/rez/unitnames.tbl index bcc1baa5..88344023 100644 Binary files a/mpq/rez/unitnames.tbl and b/mpq/rez/unitnames.tbl differ diff --git a/mpq/samase/unitdef.txt b/mpq/samase/unitdef.txt index bc81fe42..1a8ae079 100644 --- a/mpq/samase/unitdef.txt +++ b/mpq/samase/unitdef.txt @@ -153,6 +153,8 @@ military nuriel = 598 military phoenix = 599 military archbishop = 600 military camazotz = 620 +military arquebus = 624 +military cyprian_hecaton = 641 @spellcaster(serathiel) # Terran buildings diff --git a/mpq/scripts/aiscript.bin b/mpq/scripts/aiscript.bin index 8d268770..b3e086d6 100644 Binary files a/mpq/scripts/aiscript.bin and b/mpq/scripts/aiscript.bin differ diff --git a/mpq/scripts/iscript_terran.bin b/mpq/scripts/iscript_terran.bin index 37c6dbd9..b09e2d0d 100644 Binary files a/mpq/scripts/iscript_terran.bin and b/mpq/scripts/iscript_terran.bin differ diff --git a/mpq/scripts/iscript_terran.txt b/mpq/scripts/iscript_terran.txt index 460ea003..41ca8da5 100644 --- a/mpq/scripts/iscript_terran.txt +++ b/mpq/scripts/iscript_terran.txt @@ -22517,4 +22517,107 @@ RaynorMaverickWalking: move 4 wait 1 playfram 0x80 - goto RaynorMaverickWalking \ No newline at end of file + goto RaynorMaverickWalking + +# ----------------------------------------------------------------------------- # +# This header is used by images.dat entries: +# 1586 Cyprian (Hecaton) (cm\f-t\cyprian-hecaton.grp) +.headerstart +IsId 860 +Type 12 +Init CyprianHecatonInit +Death CyprianHecatonDeath +GndAttkInit CyprianHecatonGndAttkInit +AirAttkInit CyprianHecatonGndAttkInit +Unused1 SkryrokorLocal00 +GndAttkRpt CyprianHecatonGndAttkRpt +AirAttkRpt CyprianHecatonGndAttkRpt +CastSpell CyprianHecatonCastSpell +GndAttkToIdle CyprianHecatonGndAttkToIdle +AirAttkToIdle CyprianHecatonGndAttkToIdle +Unused2 [NONE] +Walking CyprianHecatonWalking +WalkingToIdle CyprianHecatonWalkingToIdle +SpecialState1 [NONE] +.headerend +# ----------------------------------------------------------------------------- # + +CyprianHecatonInit: + imgulnextid 0 0 # Cyprian (Hecaton) Shadow (cm\f-t\cyprian-hecaton-shadow.grp) +CyprianHecatonWalkingToIdle: + playfram 0x00 + goto CyprianHecatonLocal00 + +CyprianHecatonLocal00: + wait 125 + goto CyprianHecatonLocal00 + +CyprianHecatonDeath: + playsndbtwn 276 277 # Maverick death 01, 02 + imgol 332 0 0 # Explosion2 (Small) (thingy\tBangS.grp) + wait 3 + lowsprul 820 0 0 # Cyprian (Hecaton) Remains (cm\terran\cyprian-remains.grp) + wait 1 + end + +CyprianHecatonGndAttkInit: + playfram 0x120 + wait 1 + playfram 0x140 + wait 1 + sigorder 32 + playfram 0x160 + wait 16 +CyprianHecatonGndAttkRpt: + wait 1 + nobrkcodestart + playfram 0x1E0 + playsndbtwn 1189 1193 # Cyprian (Hecaton) weaponfire 01, 02, 03, 04, 05 + attackwith 1 + wait 1 + playfram 0x1C0 + wait 1 + playfram 0x1A0 + wait 1 + playfram 0x180 + wait 1 + nobrkcodeend + gotorepeatattk + ignorerest +CyprianHecatonGndAttkToIdle: + playfram 0x160 + wait 1 + playfram 0x140 + wait 1 + goto CyprianHecatonWalkingToIdle + +CyprianHecatonCastSpell: + wait 1 + goto CyprianHecatonGndAttkToIdle + +CyprianHecatonWalking: + move 3 + wait 1 + playfram 0x80 + move 3 + wait 1 + playfram 0xA0 + move 3 + wait 1 + playfram 0xC0 + move 3 + wait 1 + playfram 0xE0 + move 3 + wait 1 + playfram 0x100 + move 3 + wait 1 + playfram 0x20 + move 3 + wait 1 + playfram 0x40 + move 3 + wait 1 + playfram 0x60 + goto CyprianHecatonWalking \ No newline at end of file diff --git a/mpq/unit/cm/f-t/cyprian-hecaton-shadow.grp b/mpq/unit/cm/f-t/cyprian-hecaton-shadow.grp new file mode 100644 index 00000000..01a655ef Binary files /dev/null and b/mpq/unit/cm/f-t/cyprian-hecaton-shadow.grp differ diff --git a/mpq/unit/cm/f-t/cyprian-hecaton.grp b/mpq/unit/cm/f-t/cyprian-hecaton.grp new file mode 100644 index 00000000..efb58784 Binary files /dev/null and b/mpq/unit/cm/f-t/cyprian-hecaton.grp differ diff --git a/mpq/unit/cm/h/raynor-maverick.grp b/mpq/unit/cm/h/raynor-maverick.grp index 42b7e0e4..d1d66843 100644 Binary files a/mpq/unit/cm/h/raynor-maverick.grp and b/mpq/unit/cm/h/raynor-maverick.grp differ diff --git a/mpq/unit/cmdbtns/cmdicons.grp b/mpq/unit/cmdbtns/cmdicons.grp index 7e41ab02..1ceb72de 100644 Binary files a/mpq/unit/cmdbtns/cmdicons.grp and b/mpq/unit/cmdbtns/cmdicons.grp differ diff --git a/mpq/unit/cmdbtns/uniticons.grp b/mpq/unit/cmdbtns/uniticons.grp index 62f68f76..21adf007 100644 Binary files a/mpq/unit/cmdbtns/uniticons.grp and b/mpq/unit/cmdbtns/uniticons.grp differ diff --git a/mpq/unit/wirefram/grpwire.grp b/mpq/unit/wirefram/grpwire.grp index 6ad03fcb..c9c3b122 100644 Binary files a/mpq/unit/wirefram/grpwire.grp and b/mpq/unit/wirefram/grpwire.grp differ diff --git a/mpq/unit/wirefram/wirefram.grp b/mpq/unit/wirefram/wirefram.grp index a876ab35..88b67ca7 100644 Binary files a/mpq/unit/wirefram/wirefram.grp and b/mpq/unit/wirefram/wirefram.grp differ diff --git a/patchnotes.md b/patchnotes.md index 94f0d7b7..23b279a7 100644 --- a/patchnotes.md +++ b/patchnotes.md @@ -36,4 +36,10 @@ ## Audiovisuals - Modified shaders for the following unit sprites: - Eidolon, Hippogriff, Watchdog, Treasury, Quarry, Starpad, Rotary (c. Solstice) -- Modified weapon VFX for Okrimnilisk \ No newline at end of file +- Modified weapon VFX for Okrimnilisk +- Updated wireframes for Savant, Tarasque, Rotary, Witness, Simulacrum, Vestige (c. jun3hong) +- Added placeholder portrait for Vespene nodes (c. jun3hong) + +## Terran factions +- **NEW:** [Cyprian (Hecaton)](https://cosmonarchy.com/terran/cyprian-hecaton): + - Factional Cyprian variant for Hecaton Coalition; Has Kelvin Munitions \ No newline at end of file diff --git a/plugins/gptp.qdp b/plugins/gptp.qdp index e063cfb1..8c2aa7f3 100644 Binary files a/plugins/gptp.qdp and b/plugins/gptp.qdp differ