1
0
mirror of https://gitlab.com/the-no-frauds-club/cosmonarchy-bw-release.git synced 2026-09-21 22:31:45 +00:00

19 September 2026 -- Gauntelet Stage A update

This commit is contained in:
Pr0nogo 2026-09-19 11:10:21 -04:00
parent 67421c1874
commit 3d8d94764a
348 changed files with 9802 additions and 639 deletions

1
.gitignore vendored
View File

@ -5,7 +5,6 @@ logs/
**.tmp
/*.pcx
**.png
**.yml
ddraw.ini
BnetLog.txt

View File

@ -5,6 +5,7 @@ Since December 2022, this changelog shows only past changes.
See patchnotes.md for info on the most recent patch!
# Table of Contents
- [4 September 2026](#4-september-2026)
- [23 August 2026](#23-august-2026)
- [25 July 2026](#25-july-2026)
- [18 July 2026](#18-july-2026)
@ -120,6 +121,271 @@ See patchnotes.md for info on the most recent patch!
- [13 August 2020](#13-august-2020)
- [12 August 2020](#12-august-2020)
# 4 September 2026
## Year 4, month 9, patch 1
## Patch goals
- Balance tweaks ahead of Acropolis #5!
- Deploy more factional variants for Augustcrap, a Mapcrap event!
- Continue technical improvements and bugfixes
- Further improve audiovisuals
- [Subscribe on ko-fi](https://ko-fi.com/pr0nogoandveeq7) to get a sneak peek of the incoming changes!
- Join our communities ([Discord](https://discord.com/invite/s5SKBmY) | [Fluxer](https://fluxer.gg/1rebBmBw)), or get in touch with Pr0nogo via email! pr0nogo@fraudsclub.com
## Core
- **Weapon entries have been extended!**
- With much help from DarkenedFantasies (DF) and Jesse, weapon entries are (finally) virtually-unlimited! Say goodbye to broken tooltips and edge case bugs for several Askosi and factional weapons!
- *Please report any weapon-based oddities you encounter to us via discord/fluxer or email!*
- **Immense improvements have been made to helper and hook wrappers!**
- For the less technically-inclined, this means... more stability! Less desyncs! Easier debugging!
- *Please report any newfound issues you encounter to us via discord/fluxer or email!*
- **The custom trigger system has been deep-cleaned!** (c. Veeq7)
- This refactor makes the system easier to use, maintain, and improve upon in the future! But a huge refactor like this might have introduced new issues...
- *Please report any newfound issues in campaign and UMS maps to us via discord/fluxer or email!*
- **Known issues:** the `wait` crig action does not currently operate
- **A new campaign menu has been achieved!** (c. Jesse)
- It's so epic... please enjoy!
- **Options menu now allows for:** (c. Jesse)
- Advisor selection
- Player color selection
- Validation on save to prevent errors
## Game Modes
- **NEW: Mindshare** (b. BtyB)
- Resource pool is shared among allies!
- *Caveat: Starting resources are not yet doubled in all cases*
- *Caveat: Cancelling units may result in oddities until fixed*
## Bugfixes
- **Stability:**
- Arcing projectiles (Phalanx, Aphorist) no longer crash with division by zero when targeting an allied Mimic (r. TheBeaver99)
- **Gameplay:**
- **Atreus** Binding Plasma can no longer bounce to air units (r. Krankendau)
- Mimicry no longer fails to account for weapon factor in many cases (r. shopkeeper dog)
- **Egocent**s no longer fail to mimic barrage attacks properly (r. Londier)
- Mimicry no longer procs on ability weapons (r. Londier)
- **Audiovisual:**
- Corrected strings for **Izirokor** tech-enable on **Skibact Scab** and **Tethvith Swamp** (r. Mimika)
- Fixed weapon display for **Lobotomy Mine** (r. TheBeaver99)
- Corrected armors for **Akreno** and **Abutment** (latter r. TheBeaver99)
- Fixed bad shield overlay for **Vulture (Hecaton)** (r. Londier)
- Buttons for **Tiangou** and **Cutlass** now show as disabled when no **Scrapyard** is built (r. Pisens)
- **Cyclops (Futurist)** now uses its unique shadow and attack sequence instead of the standard variant's (r. lolrsk8s)
- Corrected tooltip for **Kagralisk** weapon string (r. Krankendau)
## Audiovisuals
- New models for:
- Watchdog (c. Solstice)
- Magnetar, Ardent Authority, Argosy (c. DeltaCadimus)
- Vorvrokor (c. Baelethal)
- Landlock, Radix, Cipher, Function, Proscenium (c. fasswawds)
- All new wireframes c. jun3hong!
- Resized model for:
- Talos, Cyprian
- Modified model (mostly shaders) for:
- Maverick, Maverick (Futurist), Shaman, Blackguard, Artisan, Pilgrim, Proselyte, Missionary, Vicar, Intendent, Phontis
- Zethrokor, Quazilisk, Liiralisk, Hydralisk, Izirokor, Zoryusthaleth (c. Solstice)
- Modified weaponfire VFX for Harakan (Golden) (s. Londier)
- Added weapon launch offsets for:
- Aphorist, Silversoul, Ghostwrit, Phontis, Iconoclast, Crematorium
- Modified unit responses for Vorvrokor
- New unit responses for Cardinal, Intendent
- New error and structure placement SFX for Askosi (c. lolrsk8s)
- New weapon SFX for:
- Alzurokor (c. lolrsk8s)
- Iconoclast, Paraclete
- New cast SFX for Paraclete
- New training SFX for:
- Function, Cosmoscope
- New cloaking SFX for damage cloak (e.g. Vestige; c. lolrsk8s)
## Terran
- [Maverick](https://cosmonarchy.com/terran/maverick):
- Build time 11 » 12
- HP 60 » 75
- **Stim Pack:**
- HP cost 5 » 10
- [Harakan](https://cosmonarchy.com/terran/harakan):
- Build time 16 » 14
- HP 100 » 120
- [Cyprian](https://cosmonarchy.com/terran/cyprian):
- Resource costs 75/50 » 100/50
- HP 80 » 90
- Collision size increased by ~16%
- [Heracles](https://cosmonarchy.com/terran/heracles):
- HP 200 » 240
- [Vulture](https://cosmonarchy.com/terran/vulture):
- Resource costs 100/0 » 75/0
- HP 120 » 80
- [Goliath](https://cosmonarchy.com/terran/goliath):
- Mineral cost 175/50 » 150/50
- HP 240 » 220
- Movement speed 5 » 4.5
- [Phalanx](https://cosmonarchy.com/terran/phalanx):
- Mineral cost 200/50 » 150/75
- [Cataphract](https://cosmonarchy.com/terran/cataphract):
- **Longinius Cannons:**
- No longer target air units
- [Quarry](https://cosmonarchy.com/terran/quarry):
- Build time 35 » 45
- [Anvil](https://cosmonarchy.com/terran/anvil):
- Resource costs 150/150 » 100/150
- [Morningstar](https://cosmonarchy.com/terran/morningstar):
- Resource costs 100/100 » 50/100
- Build time 30 » 25
- [Treasury](https://cosmonarchy.com/terran/treasury):
- Build time 35 » 45
- Can now train **Mason**s while a **Quarry** is constructed.
- [Stockade](https://cosmonarchy.com/terran/stockade):
- Build time 50 » 45
- [Fulcrum](https://cosmonarchy.com/terran/fulcrum):
- Resource costs 200/50 » 200/75
- Build time 50 » 45
## Terran factions
- [Hotshot](https://cosmonarchy.com/terran/hotshot):
- HP 65 » 70
- Armor 0 » 1
- [Maverick (Futurist)](https://cosmonarchy.com/terran/maverick-futurist):
- HP 70 » 75
- [Maverick (Upstart](https://cosmonarchy.com/terran/maverick-upstart):
- HP 50 » 60
- [Harakan (Golden)](https://cosmonarchy.com/terran/harakan-golden):
- Build time 16 » 15
- [Vulture (Upstart](https://cosmonarchy.com/terran/vulture-upstart):
- Resource costs 100/0 » 75/0
- HP 120 » 80
- **NEW:** [Maverick (Golden)](https://cosmonarchy.com/terran/maverick-golden):
- Maverick variant for Golden Republic. Has shields and a fast-firing phase rifle; no Stim Pack.
- **NEW:** [Shaman (Upstart](https://cosmonarchy.com/terran/shaman-upstart):
- Shaman variant for Upstart Terrans. Stims allies when deployed.
- **NEW:** [Morrigan](https://cosmonarchy.com/terran/morrigan):
- Eidolon replacement for Upstart Terrans. Has attack cloaking and an area-damage ground-only grenade launcher.
## Protoss
- [Zealot](https://cosmonarchy.com/protoss/zealot):
- HP 150 » 160
- **Phase Blades:**
- Armor penetration 1 » 3
- [Atreus](https://cosmonarchy.com/protoss/atreus):
- Sight range 9 » 8
- Transport weight 4 » 5
- **Dauntless Disruption Cannon:**
- Weapon damage 12 » 10
- Weapon range 5 » 4
- [Optecton](https://cosmonarchy.com/protoss/optecton):
- Resource costs 500/200 » 500/300
- HP 400 » 500
- [Unar](https://cosmonarchy.com/protoss/unar):
- Resource costs 300/125 » 200/200
- Build time 50 » 45
- [Architect](https://cosmonarchy.com/protoss/architect):
- Resource costs 250/200 » 300/250
- Build time 45 » 50
- HP 200 » 240
- Shields 50 » 40
- **Reactive Payload:**
- Weapon cooldown 1.33 » 1.25
- [Analogue](https://cosmonarchy.com/protoss/analogue):
- **Cylindrical Blaster:**
- Weapon range 6 » 4
- [Gateway](https://cosmonarchy.com/protoss/gateway):
- Resource costs 175/0 » 150/0
- Build time 50 » 55
- [Grand Library](https://cosmonarchy.com/protoss/grand-library):
- Resource costs 225/50 » 300/50
- [Unitary Union](https://cosmonarchy.com/protoss/unitary-union):
- Resource costs 500/250 » 500/300
## Protoss factions
- **NEW:** [Gladius (Order)](https://cosmonarchy.com/protoss/gladius-order):
- Order of the Sacred Saber Gladius variant. Has Triumphant Rise (a la Herald / Archon).
## Zerg
- **Reconstitution:**
- *Used by Agrileth (new), Vilgorokor*
- Carapace Swarm HP 200 » 300
- **Miasma:**
- No longer spreads on death; **Plague** remains unchanged
- *This will be revisited later.*
- [Agrileth](https://cosmonarchy.com/zerg/agrileth):
- Resource costs 150/50 » 150/75
- HP 200 » 140
- Armor 2 » 1
- **NEW: Reconstitution**
- Releases a Carapace Swarm upon taking damage.
- [Zethrokor](https://cosmonarchy.com/zerg/zethrokor):
- Resource cost 25/0 » 50/0
- HP 50 » 60
- Movement speed 7.5 » 8.4
- **Zethrok Claws:**
- Weapon damage 4 » 5
- [Vorvrokor](https://cosmonarchy.com/zerg/vorvrokor):
- Resource cost 50/0 » 75/0
- HP 80 » 90
- Armor 1 » 2
- Movement speed 9.1 » 9.8
- Collision size increased by ~23%
- [Liiralisk](https://cosmonarchy.com/zerg/liiralisk):
- **Homing Spore:**
- Weapon range 7 » 8
- [Protathalor](https://cosmonarchy.com/zerg/protathalor):
- Resource costs 125/75 » 100/100
- Armor 2 » 1
- [Izirokor](https://cosmonarchy.com/zerg/izirokor):
- Build time 26 » 22
- [Bactalisk](https://cosmonarchy.com/zerg/bactalisk):
- **Corrosive Acid:**
- No longer targets air units
- [Zoryusthaleth](https://cosmonarchy.com/zerg/zoryusthaleth):
- Resource costs 175/0 » 200/0
- Build time 28 » 25
- HP 200 » 220
- [Lakizilisk](https://cosmonarchy.com/zerg/lakizilisk):
- Resource costs 75/75 » 100/75
- Build time 30 » 28
- HP 140 » 150
- **Subterranean Spines:**
- Weapon damage 12 » 15
- Weapon cooldown 1.63 » 1.75
- [Vilgorokor](https://cosmonarchy.com/zerg/vilgorokor):
- Resource costs 220/75 » 200/50
- HP 280 » 200
## Askosi
- **Shared Designs:**
- Team building from **Pilgrim**s and **Constituent**s now increases build rate by 25% per worker, from 20%
- **Ash Heap:**
- Now consumes corpses
- **Power Overload:**
- *Used by Grandstand, Rove (new), Intendent*
- No longer deals damage over time to armored targets
- Now steals armor, to a cap of 4
- [Cardinal](https://cosmonarchy.com/askosi/cardinal):
- Resource costs 75/25 » 100/25
- [Rove](https://cosmonarchy.com/askosi/rove):
- **Elre Scaleshot:**
- Weapon damage 8 » 4
- Armor penetration 2 » 0
- Weapon range 5 » 3
- Weapon factor 1 » 3
- Now fires in a shotgun pattern (e.g. **Hotshot**, **Siren**)
- **Impact Dissipation** removed
- **NEW: Power Overload**
- [Tortare](https://cosmonarchy.com/askosi/tortare):
- **Deathrattle Assembly:**
- Now grants 2 armor when deployed
- [Radix](https://cosmonarchy.com/askosi/radix):
- Resource costs 100/0 » 125/0
- [Function](https://cosmonarchy.com/askosi/function):
- Resource costs 125/25 » 150/25
## Askosi factions
- **NEW: Sons of Ash**
- Conqueror clergy, set to burn the dead wood.
- **NEW:** [Scralia](https://cosmonarchy.com/askosi/scralia)
- Intendent replacement for Sons of Ash. Short-range assault craft with Booming Blast and Ash Heap.
# 23 August 2026
## Year 4, month 8, patch 1

Binary file not shown.

View File

@ -720,15 +720,15 @@ Shaman (Upstart, Adrenaline)
Ammo Crate
Medkit
Battery Cell
Extended Flingy #514
Extended Flingy #515
Extended Flingy #516
Extended Flingy #517
Extended Flingy #518
Extended Flingy #519
Extended Flingy #520
Extended Flingy #521
Extended Flingy #522
Okrimnilisk Spore
Raynor (Maverick)
Cyprian (Hecaton)
Memphis (Tank Mode)
Memphis (Flak Mode)
Memphis Turret (Tank Mode)
Memphis Turret (Flak Mode)
Fragmentary Shells (with damage)
Floor Flame Trap
Extended Flingy #523
Extended Flingy #524
Extended Flingy #525

Binary file not shown.

Binary file not shown.

View File

@ -2488,22 +2488,22 @@ Battery Cell Shadow (Carried)
Flamethrower (Blue)
Watchdog Engine
Watchdog Engine Idle
Extended Image #1488
Extended Image #1489
Extended Image #1490
Extended Image #1491
Extended Image #1492
Extended Image #1493
Extended Image #1494
Extended Image #1495
Extended Image #1496
Extended Image #1497
Extended Image #1498
Extended Image #1499
Extended Image #1500
Extended Image #1501
Extended Image #1502
Extended Image #1503
Okrimnilisk Spore
Spore Hit (White)
Spore Trail (White)
Raynor (Maverick)
Raynor (Maverick) Shadow
Raynor (Maverick) Remains
Cyprian (Hecaton)
Cyprian (Hecaton) Shadow
Memphis (Tank Mode)
Memphis Turret (Tank Mode)
Memphis (Tank Mode) Shadow
Memphis (Flak Mode)
Memphis Turret (Flak Mode)
Fragmentary Shells (with damage)
Floor Flame Trap
Floor Flame Trap Turret
Extended Image #1504
Extended Image #1505
Extended Image #1506

Binary file not shown.

Binary file not shown.

View File

@ -310,30 +310,30 @@ Prophet 2
Bloodsummon Advisor
Vestige
Rozirokor
Extended Portrait #203
Extended Portrait #204
Extended Portrait #205
Extended Portrait #206
Extended Portrait #207
Extended Portrait #208
Extended Portrait #209
Extended Portrait #210
Extended Portrait #211
Extended Portrait #212
Extended Portrait #213
Extended Portrait #214
Extended Portrait #215
Extended Portrait #216
Extended Portrait #217
Extended Portrait #218
Extended Portrait #219
Extended Portrait #220
Extended Portrait #221
Extended Portrait #222
Extended Portrait #223
Extended Portrait #224
Extended Portrait #225
Extended Portrait #226
Vespene Node
Ajax
Alzurokor
Arquebus
Azanthrokor
Broadside
Cutlass
Cyprian (Hecaton)
Garvrokor
Goremast
Morrigan
Quadriga
Serathiel
Shaman (Upstart)
Sovrokor
Tartarus Mine
Valkyrie (Hecaton)
Vulture (Hecaton)
Vulture (Upstart)
Eidolon (Golden)
Dredge
Ixodid
Camazotz
Cannibal
Extended Portrait #227
Extended Portrait #228
Extended Portrait #229

View File

@ -4391,21 +4391,21 @@ Intendent Under Attack 01
Intendent Under Attack 02
Intendent Under Attack 03
Intendent Under Attack 04
Extended Sound #1
Extended Sound #1
Extended Sound #1
Extended Sound #1
Extended Sound #1
Extended Sound #1
Extended Sound #1
Extended Sound #1
Extended Sound #1
Extended Sound #1
Extended Sound #1
Extended Sound #1
Extended Sound #1
Extended Sound #1
Extended Sound #1
Pit Door Open 01
Pit Door Open 02
Pit Door Close 01
Pit Door Close 02
Upper Door Open 01
Upper Door Open 02
Upper Door Close 01
Upper Door Close 02
Memphis Weaponfire 01
Memphis Weaponfire 02
Memphis Weaponfire 03
Memphis Weaponhit 2 01
Memphis Weaponhit 2 02
Memphis Weaponhit 2 03
Memphis Weaponhit 2 04
Extended Sound #1
Extended Sound #1
Extended Sound #1

View File

@ -4390,4 +4390,19 @@ cm\a\intendent\agg-04.wav
cm\a\intendent\hlp-01.wav
cm\a\intendent\hlp-02.wav
cm\a\intendent\hlp-03.wav
cm\a\intendent\hlp-04.wav
cm\a\intendent\hlp-04.wav
cm\n\doors\pit-open-01.wav
cm\n\doors\pit-open-02.wav
cm\n\doors\pit-close-01.wav
cm\n\doors\pit-close-02.wav
cm\n\doors\upper-open-01.wav
cm\n\doors\upper-open-02.wav
cm\n\doors\upper-close-01.wav
cm\n\doors\upper-close-02.wav
cm\f-t\memphis\wf-01.wav
cm\f-t\memphis\wf-02.wav
cm\f-t\memphis\wf-03.wav
cm\f-t\memphis\wh-2-01.wav
cm\f-t\memphis\wh-2-02.wav
cm\f-t\memphis\wh-2-03.wav
cm\f-t\memphis\wh-2-04.wav

Binary file not shown.

View File

@ -1193,18 +1193,18 @@ Ammo Crate
Medkit
Battery Cell
Flamethrower (Blue)
Extended Sprite #679
Extended Sprite #680
Extended Sprite #681
Extended Sprite #682
Extended Sprite #683
Extended Sprite #684
Extended Sprite #685
Extended Sprite #686
Extended Sprite #687
Extended Sprite #688
Extended Sprite #689
Extended Sprite #690
Okrimnilisk Spore
Spore Hit (White)
Spore Trail (White)
Raynor (Maverick)
Raynor (Maverick) Remains
Cyprian (Hecaton)
Memphis (Tank Mode)
Memphis (Flak Mode)
Memphis Turret (Tank Mode)
Memphis Turret (Flak Mode)
Fragmentary Shells (with damage)
Floor Flame Trap
Extended Sprite #691
Extended Sprite #692
Extended Sprite #693

Binary file not shown.

View File

@ -201,17 +201,17 @@ Terran Captaincy
Terran Scrapyard
Protoss Crucible
Carapace Swarm
Terran Nanite Assembly
Floor Missile Trap
Zerg Kalkiir Lake
Left Upper Level Door
Right Upper Level Door
Left Pit Door
Right Pit Door
Terran Sentinel
Terran Tarasque (Nydus)
Terran Anticthon
Zerg Kethraj Keep
Terran Atelier
Floor Gun Trap
Wall Missile Trap (Left)
Wall Flame Trap (Left)
Wall Missile Trap (Right)
Wall Flame Trap (Right)
Start Location
Terran Treasury
Zerg Larvosk Cesiant
@ -258,10 +258,10 @@ Terran Matador (Tank Mode)
Terran Future Station
Zerg Zarcavrokor
Terran Cestus
Terran Aerie (unused)
Terran Pegasus (unused)
Terran Sentinel
Terran Nanite Assembly
Terran Hippogriff
Terran Oberon (unused)
Terran Tarasque (Nydus)
Terran Aion
Protoss Herald
Protoss Epigraph
@ -287,7 +287,7 @@ Terran Dilettante
Terran Sevenstep
Terran Hypnagogue
Terran Parthenon
Terran Armistice
Terran Anticthon
Terran Pythean
Zerg Ogroszaleth
Zerg Spirtith Cesiant
@ -301,7 +301,7 @@ Terran Throneroom
Terran Emperor
Terran Jester
Zerg Agrileth
unused
Zerg Kethraj Keep
Protoss Sequestered Icon
Protoss Unitary Union
Protoss Servitor
@ -547,7 +547,7 @@ Askosi Zylode
Askosi Astrolabe
Terran Serathiel (Hecaton)
Zerg Malkothrokor
unused
Zerg Kalkiir Lake
Askosi Panoply
Askosi Aphorist
Askosi Doronin
@ -611,8 +611,8 @@ Forerunner Athla
Forerunner Vicere
Forerunner Machinamentum
Big Infested Kerrigan
Raynor Vulture
Duke Minotaur
Raynor (Vulture)
Duke (Minotaur)
Askosi Scralia
Zerg Rozirokor (Imicren)
Bloodsummon Thrombocyte
@ -637,23 +637,23 @@ Ammo Crate
Medkit
Battery Cell
Forerunner Buildings
Extended Unit #412
Extended Unit #413
Extended Unit #414
Extended Unit #415
Extended Unit #416
Extended Unit #417
Extended Unit #418
Extended Unit #419
Extended Unit #420
Extended Unit #421
Extended Unit #422
Extended Unit #423
Extended Unit #424
Extended Unit #425
Extended Unit #426
Extended Unit #427
Extended Unit #428
Terran Eveningstar
Raynor (Maverick)
Terran Cyprian (Hecaton)
Terran Memphis (Tank)
Terran Memphis (Tank, Turret)
Terran Memphis (Flak)
Terran Memphis (Flak, Turret)
Forerunner Processus
Forerunner Aestuarius
Forerunner Corcillum
Floor Flame Trap
Forerunner Bastilius
Forerunner Molaris
Forerunner Insignis
Forerunner Incaendium
Forerunner Ossum
Forerunner Voluntatis
Extended Unit #429
Extended Unit #430
Extended Unit #431

Binary file not shown.

View File

@ -29,7 +29,7 @@ Arclite Shock Cannon (Phalanx, Siege)
Monstrous Maw (Zoryusthaleth)
Longbolt Missiles (Watchdog)
Yamato Cannon (Magnetar ability)
Nuclear Missile
Nuclear Payload (Morningstar)
Lobotomy Grenade (Goska)
Psi Assault (Tassadar)
Irradiate (Seraph ability)
@ -307,14 +307,14 @@ Epitaph Grenade Launcher (Morrigan)
Scalpel Cannon (Shaman Upstart)
Reactive Blaster (Manifold Starbound)
Plasmathrower (Harakan Golden)
Extended Weapon #180
Extended Weapon #181
Extended Weapon #182
Extended Weapon #183
Extended Weapon #184
Extended Weapon #185
Extended Weapon #186
Extended Weapon #187
High-Tonnage Payload (Eveningstar)
Gauss Launcher (Raynor Maverick)
Boreal Railguns (Cyprian Hecaton)
Twinstrike Cannons (Memphis)
Twinflak Cannons (Memphis)
Hellfire Missile Pack (Missile Trap)
Vigil Autocannon (Gun Trap)
Flamethrower (Flame Trap)
Extended Weapon #188
Extended Weapon #189
Extended Weapon #190

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

56
mpq/game/huds.yml Normal file
View File

@ -0,0 +1,56 @@
huds:
Neutral: # for replays
image: game\nconsole.pcx
hud_overlay: game\nconover.pcx
progressbar_empty: game\tpbrempt.pcx
progressbar_full: game\tpbrfull.pcx
mineral_icon: 1
gas_icon: 1
supply_icon: 1
command_buttons: unit\cmdbtns\tcmdbtns.grp
command_buttons_bin: rez\statbtnn.bin
chat_textbox_bounds: [] # currently defined by a bin file
Terran:
image: game\tconsole.pcx
hud_overlay: game\tconover.pcx
progressbar_empty: game\tpbrempt.pcx
progressbar_full: game\tpbrfull.pcx
mineral_icon: 1
gas_icon: 1
supply_icon: 1
command_buttons: unit\cmdbtns\tcmdbtns.grp
command_buttons_bin: rez\statbtnt.bin
chat_textbox_bounds: [] # currently defined by a bin file
Protoss:
image: game\pconsole.pcx
hud_overlay: game\pconover.pcx
progressbar_empty: game\ppbrempt.pcx
progressbar_full: game\ppbrfull.pcx
mineral_icon: 2
gas_icon: 2
supply_icon: 2
command_buttons: unit\cmdbtns\pcmdbtns.grp
command_buttons_bin: rez\statbtnp.bin
chat_textbox_bounds: [] # currently defined by a bin file
Zerg:
image: game\zconsole.pcx
hud_overlay: game\zconover.pcx
progressbar_empty: game\zpbrempt.pcx
progressbar_full: game\zpbrfull.pcx
mineral_icon: 0
gas_icon: 0
supply_icon: 0
command_buttons: unit\cmdbtns\zcmdbtns.grp
command_buttons_bin: rez\statbtnz.bin
chat_textbox_bounds: [] # currently defined by a bin file
Askosi:
image: game\aconsole.pcx
hud_overlay: game\aconover.pcx
progressbar_empty: game\apbrempt.pcx
progressbar_full: game\apbrfull.pcx
mineral_icon: 3
gas_icon: 3
supply_icon: 3
command_buttons: unit\cmdbtns\acmdbtns.grp
command_buttons_bin: rez\statbtna.bin
chat_textbox_bounds: [] # currently defined by a bin file

Binary file not shown.

BIN
mpq/game/logo_80.pcx Normal file

Binary file not shown.

BIN
mpq/game/logo_banner.pcx Normal file

Binary file not shown.

1
mpq/lua/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.luarc.json

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

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

366
mpq/lua/melee/melee_ai.lua Normal file
View File

@ -0,0 +1,366 @@
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 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
---@field attack_wave_cost_bias? number Default derived from AI:new_attack()
---@class TownState
---@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
---@field personality AIPersonality
---@field ai AI
---@field main_town Town
---@field towns table<Town, TownState>
---@field started_expanding boolean
---@field started_attacking boolean
---@field seen_air_threats boolean
MeleeAI = {}
MeleeAI.__index = MeleeAI
setmetatable(MeleeAI, {
__call = function(cls, ...)
return cls.new(...)
end,
})
---@param personality? AIPersonality
---@param player? 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(self.player).ai_debug or false,
last_tick = -1,
last_script_id = -1,
}
self.personality = personality or Personalities.pick_random(player)
self.ai = AI(self.player.id)
self.main_town = self.ai:start_town()
self.towns = {
[self.main_town] = {
started_anti_ground_defenses = false,
started_anti_air_defenses = false,
},
}
self.started_expanding = false
self.started_attacking = false
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.White, "Starting AI with personality: " .. self.personality.name)
return self
end
function MeleeAI:debug_header()
if self.debugging.last_tick ~= Time.elapsed or self.debugging.last_script_id ~= Script.id then
self.debugging.last_tick = Time.elapsed
self.debugging.last_script_id = Script.id
print()
cprint(TextColor.Yellow3, "-- " .. tostring(self.player.name) .. " (P" .. tostring(self.player.id) .. "):\n")
end
end
function MeleeAI:debug(...)
if self.debugging.enabled then
self:debug_header()
print(...)
end
end
function MeleeAI:cdebug(color, ...)
if self.debugging.enabled then
self:debug_header()
cprint(color, ...)
end
end
---@protected
---@return table<UnitId, number>
function MeleeAI:get_final_unit_composition()
local unit_composition = {}
for unit_id, preference in pairs(self.personality.unit_composition) do
unit_composition[unit_id] = preference
end
return 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()
wait_until(function() return self.player:can_make(unit_id) end, secs(1))
self:cdebug(TextColor.Teal, "Added " .. UnitId.name(unit_id) .. " to defense")
self.ai.defense:auto_set(unit_id)
wait_while(function() return self.player:can_make(unit_id) end, secs(1))
self:cdebug(TextColor.Teal, "Added " .. UnitId.name(unit_id) .. " to defense")
self.ai.defense:auto_remove(unit_id)
end)
end
end
self.main_town:multirun(function(main_town)
self.personality.main_build_order(self, main_town)
end)
end
function MeleeAI:start_expanding()
if self.started_expanding then
return
end
self.started_expanding = true
multirun(function()
while true do
local town = self.ai:expand()
self:cdebug(TextColor.Green, "Expanding:")
self:debug(town)
if town.is_alive then
self.towns[town] = {
started_anti_ground_defenses = false,
started_anti_air_defenses = false,
}
town:multirun(function()
self.personality.expansion_build_order(self, town)
end)
wait(self.personality.expand_rate or (mins(3) + secs(30)))
else
wait(self.personality.expand_wait_after_fail or secs(30))
end
end
end)
end
function MeleeAI:start_attacking()
if self.started_attacking then
return
end
self.started_attacking = true
multirun(function()
while true do
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)
for unit_id, preference in pairs(self:get_final_unit_composition()) do
if preference > 0 and self.player:can_make(unit_id) then
attack:compose(preference, unit_id)
end
end
self:cdebug(TextColor.Orange, "Sending attack:")
self:debug(attack)
attack:send()
wait(secs(5))
end
end)
end
function MeleeAI:start_anti_ground_defenses(town)
if self.personality.build_anti_ground_defenses == nil then
return
end
if self.towns[town].started_anti_ground_defenses then
return
end
self.towns[town].started_anti_ground_defenses = true
multirun(function()
self.personality.build_anti_ground_defenses(self, town)
end)
end
function MeleeAI:start_anti_air_defenses(town)
if self.personality.build_anti_air_defenses == nil then
return
end
if self.towns[town].started_anti_air_defenses then
return
end
self.towns[town].started_anti_air_defenses = true
multirun(function()
wait_until(function() return self.seen_air_threats end, secs(1))
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

@ -0,0 +1,150 @@
---@class Personalities
Personalities = {
Terran = {
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 = {
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",
},
},
}
---@class RacePersonalities
---@param race RaceId
---@return RacePersonalities
local function by_race(race)
if race == RaceId.Terran then
return Personalities.Terran
elseif race == RaceId.Zerg then
return Personalities.Zerg
elseif race == RaceId.Protoss then
return Personalities.Protoss
elseif race == RaceId.Askosi then
return Personalities.Askosi
end
error("Race " .. tostring(race) .. " is not a valid AI race")
end
---@param dict table
---@return AIPersonality
local function pick_random(dict)
local keys = {}
for key, _ in pairs(dict) do
table.insert(keys, key)
end
local random_key = keys[math.random(#keys)]
return dict[random_key]
end
---@param player? Player
---@return AIPersonality
function Personalities.pick_random(player)
player = player or Player()
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

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

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

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

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

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

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

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

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

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

View File

@ -0,0 +1,81 @@
local Basic = require "melee.zerg.basic"
---@type AIPersonality
return {
name = "Assault: 2 Base Alkag",
unit_composition = {
-- signature units (Alkag Iteth)
[UnitId.ZergKagralisk] = 2,
[UnitId.ZergEvigrilisk] = 2,
[UnitId.ZergAlmaksalisk] = 2,
-- filler units
[UnitId.ZergSkithrokor] = 1,
[UnitId.ZergBactalisk] = 1,
},
main_build_order = function(melee_ai, town)
melee_ai:build_main(town)
-- opener
melee_ai:dynamic_wait(secs(25))
town:multirun(function(town)
town:wait_build(1, UnitId.ZergHydrithDen)
melee_ai:dynamic_wait(secs(40))
town:build(1, UnitId.ZergSkibactScab, 90, true)
melee_ai:dynamic_wait(mins(1) + secs(40))
town:build(1, UnitId.ZergTethvithSwamp, 90, true)
town:wait_build(1, UnitId.ZergIrolIris)
melee_ai:dynamic_wait(secs(15))
town:build(1, UnitId.ZergAlkagIteth, 90, true)
town:build(1, UnitId.ZergOthstolOviform, 90, true)
end)
town:build(1, UnitId.ZergHydrithDen, 90, true)
melee_ai:dynamic_wait(secs(30))
melee_ai:start_expanding()
-- tier2
melee_ai:dynamic_wait(secs(55))
town:build(1, UnitId.ZergIrolIris, 70, true)
melee_ai:dynamic_wait(mins(1) + secs(15))
town:build(2, UnitId.ZergHachirosk, 115)
melee_ai:dynamic_wait(mins(1) + secs(5))
-- tier3
town:build(1, UnitId.ZergOthstolOviform, 65, true)
melee_ai:dynamic_wait(secs(25))
-- saturated production
town:multirun(function(town)
town:wait_build(1, UnitId.ZergIrolIris)
town:build(5, UnitId.ZergLarvoskCesiant, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergHachirosk, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergCaphrolosk, 90)
town:wait_build(1, UnitId.ZergOthstolOviform)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergGathtelosk, 50)
end)
end,
expansion_build_order = function(melee_ai, town)
melee_ai:build_expansion(town, true)
town:multirun(function(town)
town:wait_build(1, UnitId.ZergIrolIris)
town:build(5, UnitId.ZergLarvoskCesiant, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergHachirosk, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergCaphrolosk, 90)
town:wait_build(1, UnitId.ZergOthstolOviform)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergGathtelosk, 50)
end)
-- production for the Alkag Iteth army (Kagralisk / Evigrilisk / Almaksalisk)
town:build(1, UnitId.ZergHydrithDen, 70, true)
melee_ai:dynamic_wait(secs(20))
town:build(1, UnitId.ZergSkibactScab, 70, true)
town:build(1, UnitId.ZergTethvithSwamp, 70, true)
melee_ai:dynamic_wait(secs(25))
town:build(1, UnitId.ZergIrolIris, 70, true)
melee_ai:dynamic_wait(secs(30))
town:build(1, UnitId.ZergAlkagIteth, 70, true)
end,
build_anti_ground_defenses = Basic.build_anti_ground,
build_anti_air_defenses = Basic.build_anti_air,
attack_wave_cost_bias = 0.6,
}

View File

@ -0,0 +1,81 @@
local Basic = require "melee.zerg.basic"
---@type AIPersonality
return {
name = "Assault: 2 Base Hydrith-Quazeth",
unit_composition = {
-- signature units
[UnitId.ZergHydralisk] = 3,
[UnitId.ZergZethrokor] = 2,
[UnitId.ZergUltrokor] = 2,
-- filler units
[UnitId.ZergQuazilisk] = 1,
[UnitId.ZergZoryusthaleth] = 1,
[UnitId.ZergNathrokor] = 1,
[UnitId.ZergVorvrokor] = 1,
},
main_build_order = function(melee_ai, town)
melee_ai:build_main(town)
-- opener
melee_ai:dynamic_wait(secs(25))
melee_ai:start_expanding()
melee_ai:dynamic_wait(secs(5))
town:build(1, UnitId.ZergHydrithDen, 90, true)
melee_ai:dynamic_wait(secs(30))
melee_ai:start_attacking()
-- tier1
melee_ai:dynamic_wait(secs(40))
town:build(1, UnitId.ZergQuazethPool, 90, true)
melee_ai:dynamic_wait(secs(50))
-- tier2
town:build(1, UnitId.ZergIrolIris, 70, true)
melee_ai:dynamic_wait(secs(15))
town:multirun(function(town)
town:wait_build(1, UnitId.ZergQuazethPool)
melee_ai:dynamic_wait(secs(50))
town:build(1, UnitId.ZergVornathPond, 70, true)
melee_ai:dynamic_wait(mins(1))
town:build(1, UnitId.ZergKalkiirLake, 70, true)
end)
melee_ai:dynamic_wait(secs(15))
-- tier3
town:build(1, UnitId.ZergOthstolOviform, 65, true)
melee_ai:dynamic_wait(secs(25))
-- saturated production
town:multirun(function(town)
town:wait_build(1, UnitId.ZergIrolIris)
town:build(5, UnitId.ZergLarvoskCesiant, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergHachirosk, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergCaphrolosk, 90)
town:wait_build(1, UnitId.ZergOthstolOviform)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergGathtelosk, 50)
end)
end,
expansion_build_order = function(melee_ai, town)
melee_ai:build_expansion(town, true)
town:multirun(function(town)
town:wait_build(1, UnitId.ZergIrolIris)
town:build(5, UnitId.ZergLarvoskCesiant, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergHachirosk, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergCaphrolosk, 90)
town:wait_build(1, UnitId.ZergOthstolOviform)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergGathtelosk, 50)
end)
-- production for the Hydralisk / Zethrokor / Ultrokor / Vornath army
town:build(1, UnitId.ZergHydrithDen, 70, true)
town:build(1, UnitId.ZergQuazethPool, 70, true)
town:build(1, UnitId.ZergZorkizShroud, 70, true)
melee_ai:dynamic_wait(secs(25))
town:build(1, UnitId.ZergVornathPond, 70, true)
town:build(1, UnitId.ZergUlgorgCavern, 70, true)
end,
build_anti_ground_defenses = Basic.build_anti_ground,
build_anti_air_defenses = Basic.build_anti_air,
attack_wave_cost_bias = 0.6,
}

View File

@ -0,0 +1,80 @@
local Basic = require "melee.zerg.basic"
---@type AIPersonality
return {
name = "Assault: 2 Base Hydrith-Zorkiz",
unit_composition = {
-- signature units
[UnitId.ZergHydralisk] = 3,
[UnitId.ZergUltrokor] = 2,
[UnitId.ZergZoryusthaleth] = 2,
-- filler units
[UnitId.ZergIzirokor] = 1,
[UnitId.ZergKalkalisk] = 1,
[UnitId.ZergSovroleth] = 1,
},
main_build_order = function(melee_ai, town)
melee_ai:build_main(town)
-- opener
melee_ai:dynamic_wait(secs(25))
melee_ai:start_expanding()
melee_ai:dynamic_wait(secs(5))
town:build(1, UnitId.ZergHydrithDen, 90, true)
-- tier1
melee_ai:dynamic_wait(secs(55))
town:build(2, UnitId.ZergHachirosk, 115)
melee_ai:dynamic_wait(secs(15))
-- tier2
town:build(1, UnitId.ZergIrolIris, 70, true)
melee_ai:dynamic_wait(secs(35))
town:build(1, UnitId.ZergZorkizShroud, 70, true)
melee_ai:dynamic_wait(secs(15))
town:build(1, UnitId.ZergTethvithSwamp, 70, true)
town:build(1, UnitId.ZergCaphrolosk, 70)
melee_ai:dynamic_wait(secs(45))
-- tier3
town:build(1, UnitId.ZergOthstolOviform, 65, true)
melee_ai:dynamic_wait(secs(25))
-- saturated production
town:multirun(function(town)
town:wait_build(1, UnitId.ZergIrolIris)
town:build(5, UnitId.ZergLarvoskCesiant, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergHachirosk, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergCaphrolosk, 90)
town:wait_build(1, UnitId.ZergOthstolOviform)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergGathtelosk, 50)
end)
end,
expansion_build_order = function(melee_ai, town)
melee_ai:build_expansion(town, true)
town:multirun(function(town)
town:wait_build(1, UnitId.ZergIrolIris)
town:build(5, UnitId.ZergLarvoskCesiant, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergHachirosk, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergCaphrolosk, 90)
town:wait_build(1, UnitId.ZergOthstolOviform)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergGathtelosk, 50)
end)
-- production for the Hydralisk / Ultrokor / Zoryusthaleth assault army
town:build(1, UnitId.ZergHydrithDen, 70, true)
town:build(1, UnitId.ZergZorkizShroud, 70, true)
town:build(1, UnitId.ZergKalkiirLake, 70, true)
melee_ai:dynamic_wait(secs(25))
town:build(1, UnitId.ZergUlgorgCavern, 70, true)
melee_ai:dynamic_wait(secs(25))
town:build(1, UnitId.ZergIrolIris, 70, true)
melee_ai:dynamic_wait(secs(30))
town:build(1, UnitId.ZergMutathSpire, 70, true)
melee_ai:dynamic_wait(secs(25))
town:build(1, UnitId.ZergTosvrolHaunt, 70, true)
end,
build_anti_ground_defenses = Basic.build_anti_ground,
build_anti_air_defenses = Basic.build_anti_air,
attack_wave_cost_bias = 0.6,
}

View File

@ -0,0 +1,17 @@
local Basic = {}
---@type BuildOrder
function Basic.build_anti_ground(melee_ai, town)
melee_ai:build_sequence(town, 1, 3, UnitId.ZergSurkithCesiant, 80, 5, secs(25), secs(5))
melee_ai:wait_can_make(UnitId.ZergSkortrithCesiant)
melee_ai:build_sequence(town, 1, 3, UnitId.ZergSkortrithCesiant, 80, 5, secs(25), secs(5))
end
---@type BuildOrder
function Basic.build_anti_air(melee_ai, town)
melee_ai:build_sequence(town, 1, 3, UnitId.ZergSpraithCesiant, 80, 5, secs(25), secs(5))
melee_ai:wait_can_make(UnitId.ZergSpirtithCesiant)
melee_ai:build_sequence(town, 1, 3, UnitId.ZergSpirtithCesiant, 80, 5, secs(25), secs(5))
end
return Basic

View File

@ -0,0 +1,96 @@
local Basic = require "melee.zerg.basic"
---@type AIPersonality
return {
name = "General: Before the Storm",
unit_composition = {
-- signature units
[UnitId.ZergZethrokor] = 2,
[UnitId.ZergKalkalisk] = 2,
-- filler units
[UnitId.ZergZoryusthaleth] = 1,
[UnitId.ZergMutalisk] = 1,
[UnitId.ZergGeszithalor] = 1,
[UnitId.ZergNathrokor] = 1,
[UnitId.ZergVorvrokor] = 1,
},
main_build_order = function(melee_ai, town)
melee_ai:build_main(town)
-- opener
melee_ai:dynamic_wait(secs(40))
town:build(1, UnitId.ZergQuazethPool, 110, true)
town:wait_build(1, UnitId.ZergQuazethPool, false)
melee_ai:start_expanding()
melee_ai:dynamic_wait(secs(25))
town:build(1, UnitId.ZergDroleth, 100)
melee_ai:dynamic_wait(secs(50))
town:build(2, UnitId.ZergHachirosk, 115)
melee_ai:dynamic_wait(secs(40))
town:build(1, UnitId.ZergZorkizShroud, 90, true)
melee_ai:dynamic_wait(secs(15))
melee_ai:start_attacking()
melee_ai:dynamic_wait(mins(2) + secs(30))
-- tier2
town:multirun(function(town)
town:build(1, UnitId.ZergIrolIris, 70, true)
end)
melee_ai:dynamic_wait(secs(15))
town:build(3, UnitId.ZergHachirosk, 115)
melee_ai:dynamic_wait(secs(15))
town:build(4, UnitId.ZergHachirosk, 115)
melee_ai:dynamic_wait(secs(15))
town:multirun(function(town)
town:wait_build(1, UnitId.ZergQuazethPool)
melee_ai:dynamic_wait(secs(30))
town:build(1, UnitId.ZergVornathPond, 70, true)
melee_ai:dynamic_wait(mins(1) + secs(40))
town:build(1, UnitId.ZergKalkiirLake, 70, true)
end)
melee_ai:dynamic_wait(secs(30))
-- tier3
town:build(1, UnitId.ZergOthstolOviform, 65, true)
melee_ai:dynamic_wait(secs(25))
-- saturated production
town:multirun(function(town)
town:wait_build(1, UnitId.ZergIrolIris)
town:build(5, UnitId.ZergLarvoskCesiant, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergHachirosk, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergCaphrolosk, 90)
town:wait_build(1, UnitId.ZergOthstolOviform)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergGathtelosk, 50)
end)
end,
expansion_build_order = function(melee_ai, town)
melee_ai:build_expansion(town, true)
town:multirun(function(town)
town:wait_build(1, UnitId.ZergIrolIris)
town:build(5, UnitId.ZergLarvoskCesiant, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergHachirosk, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergCaphrolosk, 90)
town:wait_build(1, UnitId.ZergOthstolOviform)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergGathtelosk, 50)
end)
-- production for the Zethrokor / Kalkalisk army + Mutalisk / Geszithalor
town:build(1, UnitId.ZergQuazethPool, 70, true)
town:build(1, UnitId.ZergZorkizShroud, 70, true)
town:build(1, UnitId.ZergKalkiirLake, 70, true)
melee_ai:dynamic_wait(secs(20))
town:build(1, UnitId.ZergVornathPond, 70, true)
melee_ai:dynamic_wait(secs(25))
town:build(1, UnitId.ZergIrolIris, 70, true)
melee_ai:dynamic_wait(secs(30))
town:build(1, UnitId.ZergMutathSpire, 70, true)
town:build(1, UnitId.ZergOthstolOviform, 65, true)
melee_ai:dynamic_wait(secs(30))
town:build(1, UnitId.ZergGeszkathGrotto, 50, true)
end,
build_anti_ground_defenses = Basic.build_anti_ground,
build_anti_air_defenses = Basic.build_anti_air,
attack_wave_cost_bias = 0.5,
}

View File

@ -0,0 +1,86 @@
local Basic = require "melee.zerg.basic"
---@type AIPersonality
return {
name = "General: Constrained Coil",
unit_composition = {
-- signature units
[UnitId.ZergZethrokor] = 2,
[UnitId.ZergKalkalisk] = 2,
-- filler units
[UnitId.ZergZoryusthaleth] = 1,
[UnitId.ZergMutalisk] = 1,
[UnitId.ZergGeszithalor] = 1,
[UnitId.ZergNathrokor] = 1,
[UnitId.ZergVorvrokor] = 1,
},
main_build_order = function(melee_ai, town)
melee_ai:build_main(town)
-- opener
melee_ai:dynamic_wait(secs(40))
town:build(1, UnitId.ZergQuazethPool, 110, true)
town:wait_build(1, UnitId.ZergQuazethPool, false)
melee_ai:start_expanding()
-- tier1
melee_ai:dynamic_wait(secs(25))
town:build(1, UnitId.ZergDroleth, 100)
melee_ai:dynamic_wait(secs(1))
town:build(1, UnitId.ZergQuazethPool, 90, true)
melee_ai:dynamic_wait(mins(1) + secs(40))
town:build(1, UnitId.ZergHydrithDen, 90, true)
melee_ai:dynamic_wait(secs(20))
town:build(1, UnitId.ZergVornathPond, 90, true)
melee_ai:dynamic_wait(mins(1))
-- tier2
town:multirun(function(town)
town:build(1, UnitId.ZergIrolIris, 70, true)
end)
melee_ai:dynamic_wait(mins(1) + secs(35))
town:build(2, UnitId.ZergHachirosk, 115)
-- tier3
town:build(1, UnitId.ZergOthstolOviform, 65, true)
melee_ai:dynamic_wait(secs(25))
-- saturated production
town:multirun(function(town)
town:wait_build(1, UnitId.ZergIrolIris)
town:build(5, UnitId.ZergLarvoskCesiant, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergHachirosk, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergCaphrolosk, 90)
town:wait_build(1, UnitId.ZergOthstolOviform)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergGathtelosk, 50)
end)
end,
expansion_build_order = function(melee_ai, town)
melee_ai:build_expansion(town, true)
town:multirun(function(town)
town:wait_build(1, UnitId.ZergIrolIris)
town:build(5, UnitId.ZergLarvoskCesiant, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergHachirosk, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergCaphrolosk, 90)
town:wait_build(1, UnitId.ZergOthstolOviform)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergGathtelosk, 50)
end)
-- production for the constrained Zethrokor / Kalkalisk army
town:build(1, UnitId.ZergQuazethPool, 70, true)
town:build(1, UnitId.ZergZorkizShroud, 70, true)
town:build(1, UnitId.ZergKalkiirLake, 70, true)
melee_ai:dynamic_wait(secs(20))
town:build(1, UnitId.ZergVornathPond, 70, true)
melee_ai:dynamic_wait(secs(25))
town:build(1, UnitId.ZergIrolIris, 70, true)
melee_ai:dynamic_wait(secs(30))
town:build(1, UnitId.ZergMutathSpire, 70, true)
town:build(1, UnitId.ZergOthstolOviform, 65, true)
melee_ai:dynamic_wait(secs(30))
town:build(1, UnitId.ZergGeszkathGrotto, 50, true)
end,
build_anti_ground_defenses = Basic.build_anti_ground,
build_anti_air_defenses = Basic.build_anti_air,
attack_wave_cost_bias = 0.5,
}

View File

@ -0,0 +1,95 @@
local Basic = require "melee.zerg.basic"
---@type AIPersonality
return {
name = "General: Shrieking Swarm",
unit_composition = {
-- signature units (Vornath Pond)
[UnitId.ZergVorvrokor] = 2,
[UnitId.ZergNathrokor] = 2,
-- filler units
[UnitId.ZergUltrokor] = 1,
[UnitId.ZergHydralisk] = 1,
[UnitId.ZergLakizilisk] = 1,
[UnitId.ZergSovroleth] = 1,
},
main_build_order = function(melee_ai, town)
melee_ai:build_main(town)
-- opener
melee_ai:dynamic_wait(secs(45))
melee_ai:start_expanding()
melee_ai:dynamic_wait(secs(25))
town:build(1, UnitId.ZergQuazethPool, 90, true)
melee_ai:dynamic_wait(secs(40))
melee_ai:start_attacking()
-- tier1
melee_ai:dynamic_wait(secs(15))
town:build(2, UnitId.ZergHachirosk, 115)
melee_ai:dynamic_wait(secs(25))
town:build(1, UnitId.ZergVornathPond, 90, true)
melee_ai:dynamic_wait(secs(40))
-- tier2
town:multirun(function(town)
town:build(1, UnitId.ZergIrolIris, 70, true)
end)
town:multirun(function(town)
town:wait_build(1, UnitId.ZergQuazethPool)
melee_ai:dynamic_wait(secs(40))
town:build(1, UnitId.ZergVornathPond, 70, true)
melee_ai:dynamic_wait(mins(1) + secs(40))
town:build(1, UnitId.ZergKalkiirLake, 70, true)
end)
melee_ai:dynamic_wait(mins(1))
town:build(1, UnitId.ZergZorkizShroud, 70, true)
melee_ai:dynamic_wait(secs(20))
town:build(1, UnitId.ZergCaphrolosk, 70)
melee_ai:dynamic_wait(secs(30))
town:build(3, UnitId.ZergHachirosk, 115)
melee_ai:dynamic_wait(secs(15))
-- tier3
town:build(1, UnitId.ZergOthstolOviform, 65, true)
melee_ai:dynamic_wait(secs(25))
-- saturated production
town:multirun(function(town)
town:wait_build(1, UnitId.ZergIrolIris)
town:build(5, UnitId.ZergLarvoskCesiant, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergHachirosk, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergCaphrolosk, 90)
town:wait_build(1, UnitId.ZergOthstolOviform)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergGathtelosk, 50)
end)
end,
expansion_build_order = function(melee_ai, town)
melee_ai:build_expansion(town, true)
town:multirun(function(town)
town:wait_build(1, UnitId.ZergIrolIris)
town:build(5, UnitId.ZergLarvoskCesiant, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergHachirosk, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergCaphrolosk, 90)
town:wait_build(1, UnitId.ZergOthstolOviform)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergGathtelosk, 50)
end)
-- production for the Vornath-centric army (+ Ultrokor / Hydralisk / Zorkiz)
town:build(1, UnitId.ZergQuazethPool, 70, true)
town:build(1, UnitId.ZergZorkizShroud, 70, true)
town:build(1, UnitId.ZergHydrithDen, 70, true)
melee_ai:dynamic_wait(secs(20))
town:build(1, UnitId.ZergVornathPond, 70, true)
town:build(1, UnitId.ZergUlgorgCavern, 70, true)
melee_ai:dynamic_wait(secs(25))
town:build(1, UnitId.ZergIrolIris, 70, true)
melee_ai:dynamic_wait(secs(30))
town:build(1, UnitId.ZergMutathSpire, 70, true)
melee_ai:dynamic_wait(secs(25))
town:build(1, UnitId.ZergTosvrolHaunt, 70, true)
end,
build_anti_ground_defenses = Basic.build_anti_ground,
build_anti_air_defenses = Basic.build_anti_air,
attack_wave_cost_bias = 0.5,
}

View File

@ -0,0 +1,107 @@
local Basic = require "melee.zerg.basic"
---@type AIPersonality
return {
name = "General: Sleeping Giant",
unit_composition = {
-- signature units
[UnitId.ZergZethrokor] = 2,
[UnitId.ZergUltrokor] = 2,
[UnitId.ZergHydralisk] = 2,
-- filler units
[UnitId.ZergKalkalisk] = 1,
[UnitId.ZergZoryusthaleth] = 1,
[UnitId.ZergMutalisk] = 1,
[UnitId.ZergNathrokor] = 1,
[UnitId.ZergVorvrokor] = 1,
},
main_build_order = function(melee_ai, town)
melee_ai:build_main(town)
-- opener
melee_ai:dynamic_wait(secs(45))
melee_ai:start_expanding()
melee_ai:dynamic_wait(secs(30))
town:build(1, UnitId.ZergQuazethPool, 90, true)
-- tier1
melee_ai:dynamic_wait(mins(1))
town:wait_build(15, UnitId.ZergDroleth)
melee_ai:dynamic_wait(secs(15))
town:build(1, UnitId.ZergVornathPond, 90, true)
town:build(2, UnitId.ZergHachirosk, 115)
melee_ai:dynamic_wait(secs(25))
-- tier2
town:multirun(function(town)
town:build(1, UnitId.ZergIrolIris, 70, true)
end)
melee_ai:dynamic_wait(secs(20))
town:wait_build(1, UnitId.ZergIrolIris)
town:build(1, UnitId.ZergCaphrolosk, 70)
melee_ai:dynamic_wait(secs(30))
town:build(3, UnitId.ZergHachirosk, 115)
melee_ai:dynamic_wait(secs(30))
town:build(1, UnitId.ZergZorkizShroud, 70, true)
melee_ai:dynamic_wait(secs(25))
town:multirun(function(town)
town:wait_build(1, UnitId.ZergQuazethPool)
melee_ai:dynamic_wait(mins(1))
town:build(1, UnitId.ZergVornathPond, 70, true)
melee_ai:dynamic_wait(mins(1) + secs(40))
town:build(1, UnitId.ZergKalkiirLake, 70, true)
town:wait_build(1, UnitId.ZergIrolIris)
town:build(1, UnitId.ZergMatravilNest, 70, true)
melee_ai:dynamic_wait(mins(1))
town:build(1, UnitId.ZergMutathSpire, 70, true)
melee_ai:dynamic_wait(mins(2) + secs(45))
town:build(1, UnitId.ZergTosvrolHaunt, 70, true)
end)
melee_ai:dynamic_wait(secs(25))
-- tier3
town:multirun(function(town)
town:build(1, UnitId.ZergOthstolOviform, 65, true)
end)
melee_ai:dynamic_wait(secs(50))
town:build(1, UnitId.ZergGathtelosk, 50)
melee_ai:dynamic_wait(secs(15))
-- saturated production
town:multirun(function(town)
town:wait_build(1, UnitId.ZergIrolIris)
town:build(5, UnitId.ZergLarvoskCesiant, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergHachirosk, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergCaphrolosk, 90)
town:wait_build(1, UnitId.ZergOthstolOviform)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergGathtelosk, 50)
end)
end,
expansion_build_order = function(melee_ai, town)
melee_ai:build_expansion(town, true)
town:multirun(function(town)
town:wait_build(1, UnitId.ZergIrolIris)
town:build(5, UnitId.ZergLarvoskCesiant, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergHachirosk, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergCaphrolosk, 90)
town:wait_build(1, UnitId.ZergOthstolOviform)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergGathtelosk, 50)
end)
-- production for the Zethrokor / Ultrokor / Hydralisk army
town:build(1, UnitId.ZergQuazethPool, 70, true)
town:build(1, UnitId.ZergZorkizShroud, 70, true)
town:build(1, UnitId.ZergHydrithDen, 70, true)
melee_ai:dynamic_wait(secs(20))
town:build(1, UnitId.ZergVornathPond, 70, true)
town:build(1, UnitId.ZergUlgorgCavern, 70, true)
town:build(1, UnitId.ZergKalkiirLake, 70, true)
melee_ai:dynamic_wait(secs(25))
town:build(1, UnitId.ZergIrolIris, 70, true)
melee_ai:dynamic_wait(secs(30))
town:build(1, UnitId.ZergMutathSpire, 70, true)
end,
build_anti_ground_defenses = Basic.build_anti_ground,
build_anti_air_defenses = Basic.build_anti_air,
attack_wave_cost_bias = 0.5,
}

View File

@ -0,0 +1,100 @@
local Basic = require "melee.zerg.basic"
---@type AIPersonality
return {
name = "General: Subjugation",
unit_composition = {
-- signature units (Skibact Scab)
[UnitId.ZergSkithrokor] = 2,
[UnitId.ZergBactalisk] = 2,
[UnitId.ZergZethrokor] = 2,
-- filler units
[UnitId.ZergKeskathalor] = 1,
[UnitId.ZergHydralisk] = 1,
[UnitId.ZergZoryusthaleth] = 1,
[UnitId.ZergVithrilisk] = 1,
},
main_build_order = function(melee_ai, town)
melee_ai:build_main(town)
-- opener
melee_ai:dynamic_wait(secs(45))
melee_ai:start_expanding()
melee_ai:dynamic_wait(secs(30))
town:build(1, UnitId.ZergDroleth, 100)
melee_ai:dynamic_wait(secs(5))
town:build(1, UnitId.ZergHydrithDen, 90, true)
-- tier1
melee_ai:dynamic_wait(secs(15))
town:build(2, UnitId.ZergHachirosk, 115)
melee_ai:dynamic_wait(secs(20))
town:build(1, UnitId.ZergSkibactScab, 90, true)
melee_ai:dynamic_wait(secs(45))
-- tier2
melee_ai:dynamic_wait(secs(30))
town:build(1, UnitId.ZergQuazethPool, 70, true)
melee_ai:dynamic_wait(secs(25))
town:multirun(function(town)
town:build(1, UnitId.ZergIrolIris, 70, true)
end)
melee_ai:dynamic_wait(secs(50))
town:multirun(function(town)
town:wait_build(1, UnitId.ZergHydrithDen)
melee_ai:dynamic_wait(secs(50))
town:build(1, UnitId.ZergSkibactScab, 70, true)
melee_ai:dynamic_wait(mins(1) + secs(40))
town:build(1, UnitId.ZergTethvithSwamp, 70, true)
town:wait_build(1, UnitId.ZergIrolIris)
town:build(1, UnitId.ZergMatravilNest, 70, true)
end)
melee_ai:dynamic_wait(secs(15))
town:build(1, UnitId.ZergCaphrolosk, 70)
town:build(3, UnitId.ZergHachirosk, 115)
melee_ai:dynamic_wait(secs(45))
town:build(1, UnitId.ZergZorkizShroud, 70, true)
-- tier3
town:build(1, UnitId.ZergOthstolOviform, 65, true)
melee_ai:dynamic_wait(secs(25))
-- saturated production
town:multirun(function(town)
town:wait_build(1, UnitId.ZergIrolIris)
town:build(5, UnitId.ZergLarvoskCesiant, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergHachirosk, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergCaphrolosk, 90)
town:wait_build(1, UnitId.ZergOthstolOviform)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergGathtelosk, 50)
end)
end,
expansion_build_order = function(melee_ai, town)
melee_ai:build_expansion(town, true)
town:multirun(function(town)
town:wait_build(1, UnitId.ZergIrolIris)
town:build(5, UnitId.ZergLarvoskCesiant, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergHachirosk, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergCaphrolosk, 90)
town:wait_build(1, UnitId.ZergOthstolOviform)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergGathtelosk, 50)
end)
-- production for the Skibact / Zethrokor army + Keskathalor tech
town:build(1, UnitId.ZergHydrithDen, 70, true)
town:build(1, UnitId.ZergQuazethPool, 70, true)
town:build(1, UnitId.ZergZorkizShroud, 70, true)
melee_ai:dynamic_wait(secs(20))
town:build(1, UnitId.ZergSkibactScab, 70, true)
town:build(1, UnitId.ZergTethvithSwamp, 70, true)
melee_ai:dynamic_wait(secs(25))
town:build(1, UnitId.ZergIrolIris, 70, true)
melee_ai:dynamic_wait(secs(30))
town:build(1, UnitId.ZergOthstolOviform, 65, true)
melee_ai:dynamic_wait(secs(30))
town:build(1, UnitId.ZergGeszkathGrotto, 50, true)
end,
build_anti_ground_defenses = Basic.build_anti_ground,
build_anti_air_defenses = Basic.build_anti_air,
attack_wave_cost_bias = 0.5,
}

View File

@ -0,0 +1,94 @@
local Basic = require "melee.zerg.basic"
---@type AIPersonality
return {
name = "General: Time After Time",
unit_composition = {
-- signature units
[UnitId.ZergZethrokor] = 2,
[UnitId.ZergSkithrokor] = 2,
[UnitId.ZergLakizilisk] = 2,
-- filler units
[UnitId.ZergLiiralisk] = 1,
[UnitId.ZergCikralisk] = 1,
[UnitId.ZergBactalisk] = 1,
[UnitId.ZergNathrokor] = 1,
[UnitId.ZergVorvrokor] = 1,
},
main_build_order = function(melee_ai, town)
melee_ai:build_main(town)
-- opener
melee_ai:dynamic_wait(secs(45))
melee_ai:start_expanding()
melee_ai:dynamic_wait(secs(40))
town:build(1, UnitId.ZergHydrithDen, 90, true)
melee_ai:dynamic_wait(secs(40))
melee_ai:start_attacking()
-- tier1
melee_ai:dynamic_wait(mins(1) + secs(15))
town:build(1, UnitId.ZergQuazethPool, 90, true)
melee_ai:dynamic_wait(mins(1) + secs(15))
town:build(1, UnitId.ZergSkibactScab, 90, true)
melee_ai:dynamic_wait(secs(25))
town:build(1, UnitId.ZergZorkizShroud, 90, true)
town:build(2, UnitId.ZergHachirosk, 115)
melee_ai:dynamic_wait(secs(50))
-- tier2
town:multirun(function(town)
town:build(1, UnitId.ZergIrolIris, 70, true)
end)
melee_ai:dynamic_wait(secs(15))
town:multirun(function(town)
town:wait_build(1, UnitId.ZergQuazethPool)
melee_ai:dynamic_wait(secs(50))
town:build(1, UnitId.ZergVornathPond, 70, true)
melee_ai:dynamic_wait(mins(1) + secs(40))
town:build(1, UnitId.ZergKalkiirLake, 70, true)
end)
melee_ai:dynamic_wait(secs(30))
-- tier3
town:build(1, UnitId.ZergOthstolOviform, 65, true)
melee_ai:dynamic_wait(secs(25))
-- saturated production
town:multirun(function(town)
town:wait_build(1, UnitId.ZergIrolIris)
town:build(5, UnitId.ZergLarvoskCesiant, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergHachirosk, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergCaphrolosk, 90)
town:wait_build(1, UnitId.ZergOthstolOviform)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergGathtelosk, 50)
end)
end,
expansion_build_order = function(melee_ai, town)
melee_ai:build_expansion(town, true)
town:multirun(function(town)
town:wait_build(1, UnitId.ZergIrolIris)
town:build(5, UnitId.ZergLarvoskCesiant, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergHachirosk, 90)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergCaphrolosk, 90)
town:wait_build(1, UnitId.ZergOthstolOviform)
melee_ai:dynamic_wait(secs(45))
town:build(6, UnitId.ZergGathtelosk, 50)
end)
-- production for the Zethrokor / Skithrokor / Lakizilisk army
town:build(1, UnitId.ZergHydrithDen, 70, true)
town:build(1, UnitId.ZergQuazethPool, 70, true)
town:build(1, UnitId.ZergZorkizShroud, 70, true)
town:build(1, UnitId.ZergKalkiirLake, 70, true)
melee_ai:dynamic_wait(secs(20))
town:build(1, UnitId.ZergSkibactScab, 70, true)
town:build(1, UnitId.ZergVornathPond, 70, true)
melee_ai:dynamic_wait(secs(25))
town:build(1, UnitId.ZergIrolIris, 70, true)
melee_ai:dynamic_wait(secs(30))
town:build(1, UnitId.ZergMutathSpire, 70, true)
end,
build_anti_ground_defenses = Basic.build_anti_ground,
build_anti_air_defenses = Basic.build_anti_air,
attack_wave_cost_bias = 0.5,
}

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