1
0
mirror of https://gitlab.com/the-no-frauds-club/cosmonarchy-bw-prerelease.git synced 2026-10-10 05:57:51 +00:00

Fix nuke crash; Add Hecaton Cyprian; Update lua aiscripts

This commit is contained in:
Pr0nogo 2026-09-12 14:20:53 -04:00
parent a9b8c5f8e9
commit f3415c1faa
147 changed files with 6242 additions and 5593 deletions

Binary file not shown.

View File

@ -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

Binary file not shown.

Binary file not shown.

View File

@ -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

Binary file not shown.

Binary file not shown.

View File

@ -310,7 +310,7 @@ Prophet 2
Bloodsummon Advisor
Vestige
Rozirokor
Extended Portrait #203
Vespene Node
Extended Portrait #204
Extended Portrait #205
Extended Portrait #206

Binary file not shown.

View File

@ -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

Binary file not shown.

View File

@ -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

Binary file not shown.

View File

@ -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

Binary file not shown.

Binary file not shown.

Binary file not shown.

3
mpq/lua/AGENTS.md Normal file
View File

@ -0,0 +1,3 @@
# Resources
- Load local Lua API reference from `.luarc.json`
- Fetch Cosmonarchy tech tree from `https://cosmonarchy.com/export/all.json`

1
mpq/lua/CLAUDE.md Normal file
View File

@ -0,0 +1 @@
@AGENTS.md

View File

@ -0,0 +1,3 @@
require "melee.melee_ai"
MeleeAI(Personalities.Terran.Raider.EightRax):run()

View File

@ -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()

View File

@ -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

View File

@ -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,
}

View File

@ -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

View File

@ -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<UnitId, number>
---@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<UnitId, number>
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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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,
},
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
},
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
},
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
},
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
},
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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,
},
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
},
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
},
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
},
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

Some files were not shown because too many files have changed in this diff Show More