diff --git a/.gitignore b/.gitignore index 56c4912..5622e53 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,6 @@ logs/ **.tmp /*.pcx **.png -**.yml ddraw.ini BnetLog.txt diff --git a/master changelog.md b/master changelog.md index 8231d7e..bbfc08b 100644 --- a/master changelog.md +++ b/master changelog.md @@ -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 diff --git a/mpq/arr/flingy.datex b/mpq/arr/flingy.datex index ef1d0e9..ac604eb 100644 Binary files a/mpq/arr/flingy.datex and b/mpq/arr/flingy.datex differ diff --git a/mpq/arr/flingy.txt b/mpq/arr/flingy.txt index 866ad82..23d16b3 100644 --- a/mpq/arr/flingy.txt +++ b/mpq/arr/flingy.txt @@ -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 diff --git a/mpq/arr/images.datex b/mpq/arr/images.datex index 0b71882..874237a 100644 Binary files a/mpq/arr/images.datex and b/mpq/arr/images.datex differ diff --git a/mpq/arr/images.tbl b/mpq/arr/images.tbl index 52a7990..1685338 100644 Binary files a/mpq/arr/images.tbl and b/mpq/arr/images.tbl differ diff --git a/mpq/arr/images.txt b/mpq/arr/images.txt index 3510f45..a7a7222 100644 --- a/mpq/arr/images.txt +++ b/mpq/arr/images.txt @@ -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 diff --git a/mpq/arr/portdata.datex b/mpq/arr/portdata.datex index 8413689..be79ab2 100644 Binary files a/mpq/arr/portdata.datex and b/mpq/arr/portdata.datex differ diff --git a/mpq/arr/portdata.tbl b/mpq/arr/portdata.tbl index 1ca1970..07d2793 100644 Binary files a/mpq/arr/portdata.tbl and b/mpq/arr/portdata.tbl differ diff --git a/mpq/arr/portdata.txt b/mpq/arr/portdata.txt index 6587089..6053717 100644 --- a/mpq/arr/portdata.txt +++ b/mpq/arr/portdata.txt @@ -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 diff --git a/mpq/arr/sfxdata.txt b/mpq/arr/sfxdata.txt index 3ba1a63..631f5fd 100644 --- a/mpq/arr/sfxdata.txt +++ b/mpq/arr/sfxdata.txt @@ -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 diff --git a/mpq/arr/sounds.txt b/mpq/arr/sounds.txt index 7e6179a..918611d 100644 --- a/mpq/arr/sounds.txt +++ b/mpq/arr/sounds.txt @@ -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 \ No newline at end of file +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 \ No newline at end of file diff --git a/mpq/arr/sprites.datex b/mpq/arr/sprites.datex index 33ad0f4..33b6126 100644 Binary files a/mpq/arr/sprites.datex and b/mpq/arr/sprites.datex differ diff --git a/mpq/arr/sprites.txt b/mpq/arr/sprites.txt index 96cf325..16c0a55 100644 --- a/mpq/arr/sprites.txt +++ b/mpq/arr/sprites.txt @@ -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 diff --git a/mpq/arr/units.datex b/mpq/arr/units.datex index 33808f8..2eb1176 100644 Binary files a/mpq/arr/units.datex and b/mpq/arr/units.datex differ diff --git a/mpq/arr/units.txt b/mpq/arr/units.txt index ab0e636..f637443 100644 --- a/mpq/arr/units.txt +++ b/mpq/arr/units.txt @@ -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 diff --git a/mpq/arr/weapons.datex b/mpq/arr/weapons.datex index 044d963..fe19d3c 100644 Binary files a/mpq/arr/weapons.datex and b/mpq/arr/weapons.datex differ diff --git a/mpq/arr/weapons.txt b/mpq/arr/weapons.txt index e5407b1..858b75b 100644 --- a/mpq/arr/weapons.txt +++ b/mpq/arr/weapons.txt @@ -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 diff --git a/mpq/datreq/Buttons.graft b/mpq/datreq/Buttons.graft index 54d18a1..3cbb361 100644 Binary files a/mpq/datreq/Buttons.graft and b/mpq/datreq/Buttons.graft differ diff --git a/mpq/datreq/Orders.graft b/mpq/datreq/Orders.graft index 3dc6bc3..fcaeb5c 100644 Binary files a/mpq/datreq/Orders.graft and b/mpq/datreq/Orders.graft differ diff --git a/mpq/datreq/Tech.graft b/mpq/datreq/Tech.graft index 18f5837..23cc30d 100644 Binary files a/mpq/datreq/Tech.graft and b/mpq/datreq/Tech.graft differ diff --git a/mpq/datreq/Units.graft b/mpq/datreq/Units.graft index 43c0969..be143b1 100644 Binary files a/mpq/datreq/Units.graft and b/mpq/datreq/Units.graft differ diff --git a/mpq/game/huds.yml b/mpq/game/huds.yml new file mode 100644 index 0000000..5766015 --- /dev/null +++ b/mpq/game/huds.yml @@ -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 diff --git a/mpq/game/icons.grp b/mpq/game/icons.grp index 4f210f4..c940c44 100644 Binary files a/mpq/game/icons.grp and b/mpq/game/icons.grp differ diff --git a/mpq/game/logo_80.pcx b/mpq/game/logo_80.pcx new file mode 100644 index 0000000..e9936fa Binary files /dev/null and b/mpq/game/logo_80.pcx differ diff --git a/mpq/game/logo_banner.pcx b/mpq/game/logo_banner.pcx new file mode 100644 index 0000000..3a32ae3 Binary files /dev/null and b/mpq/game/logo_banner.pcx differ diff --git a/mpq/lua/.gitignore b/mpq/lua/.gitignore new file mode 100644 index 0000000..9bbbeea --- /dev/null +++ b/mpq/lua/.gitignore @@ -0,0 +1 @@ +.luarc.json diff --git a/mpq/lua/AGENTS.md b/mpq/lua/AGENTS.md new file mode 100644 index 0000000..0d1080f --- /dev/null +++ b/mpq/lua/AGENTS.md @@ -0,0 +1,3 @@ +# Resources +- Load local Lua API reference from `.luarc.json` +- Fetch Cosmonarchy tech tree from `https://cosmonarchy.com/export/all.json` diff --git a/mpq/lua/CLAUDE.md b/mpq/lua/CLAUDE.md new file mode 100644 index 0000000..43c994c --- /dev/null +++ b/mpq/lua/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/mpq/lua/examples/basic_ai.lua b/mpq/lua/examples/basic_ai.lua new file mode 100644 index 0000000..0033ce3 --- /dev/null +++ b/mpq/lua/examples/basic_ai.lua @@ -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 diff --git a/mpq/lua/examples/start_melee_ai.lua b/mpq/lua/examples/start_melee_ai.lua new file mode 100644 index 0000000..f5dff07 --- /dev/null +++ b/mpq/lua/examples/start_melee_ai.lua @@ -0,0 +1,3 @@ +require "melee.melee_ai" + +MeleeAI(Personalities.Terran.Raider.EightRax):run() diff --git a/mpq/lua/examples/start_melee_ai_customized.lua b/mpq/lua/examples/start_melee_ai_customized.lua new file mode 100644 index 0000000..97a3112 --- /dev/null +++ b/mpq/lua/examples/start_melee_ai_customized.lua @@ -0,0 +1,6 @@ +require "melee.melee_ai" + +local eight_rax_harakan = deepcopy(Personalities.Terran.Raider.EightRax) +eight_rax_harakan.unit_composition[UnitId.TerranHarakan] = 3 + +MeleeAI(eight_rax_harakan):run() diff --git a/mpq/lua/melee/askosi/basic.lua b/mpq/lua/melee/askosi/basic.lua new file mode 100644 index 0000000..fd440d2 --- /dev/null +++ b/mpq/lua/melee/askosi/basic.lua @@ -0,0 +1,13 @@ +local Basic = {} + +---@type BuildOrder +function Basic.build_anti_ground(melee_ai, town) + melee_ai:build_sequence(town, 1, 4, UnitId.AskosiGrandstand, 70, 5, secs(25), secs(5)) +end + +---@type BuildOrder +function Basic.build_anti_air(melee_ai, town) + melee_ai:build_sequence(town, 1, 4, UnitId.AskosiGrandstand, 80, 5, secs(25), secs(5)) +end + +return Basic diff --git a/mpq/lua/melee/askosi/temp/temp_default.lua b/mpq/lua/melee/askosi/temp/temp_default.lua new file mode 100644 index 0000000..d1de789 --- /dev/null +++ b/mpq/lua/melee/askosi/temp/temp_default.lua @@ -0,0 +1,40 @@ +local Basic = require "melee.askosi.basic" + +---@type AIPersonality +return { + name = "Temp Default", + unit_composition = { + -- ground + [UnitId.AskosiMissionary] = 1, + [UnitId.AskosiCardinal] = 1, + [UnitId.AskosiRove] = 1, + [UnitId.AskosiObject] = 1, + [UnitId.AskosiScepter] = 1, + [UnitId.AskosiIntendent] = 1, + -- air + [UnitId.AskosiHelion] = 1, + [UnitId.AskosiEmissary] = 1, + [UnitId.AskosiInkblot] = 1, + [UnitId.AskosiTirade] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.AskosiRadix, 100, true) + town:build(1, UnitId.AskosiFunction, 100, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.AskosiCosmoscope, 90, true) + melee_ai:dynamic_wait(secs(20)) + melee_ai:start_attacking() + melee_ai:start_expanding() + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:build(1, UnitId.AskosiRadix, 70, true) + town:build(1, UnitId.AskosiFunction, 70, true) + town:build(1, UnitId.AskosiCosmoscope, 70, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/deepcopy.lua b/mpq/lua/melee/deepcopy.lua new file mode 100644 index 0000000..7926efe --- /dev/null +++ b/mpq/lua/melee/deepcopy.lua @@ -0,0 +1,20 @@ +---@param original any +---@param seen? table +---@return any +function deepcopy(original, seen) + if type(original) ~= "table" then + return original + end + + seen = seen or {} + if seen[original] then + return seen[original] + end + + local copy = {} + seen[original] = copy + for key, value in pairs(original) do + copy[deepcopy(key, seen)] = deepcopy(value, seen) + end + return setmetatable(copy, deepcopy(getmetatable(original), seen)) +end diff --git a/mpq/lua/melee/melee_ai.lua b/mpq/lua/melee/melee_ai.lua new file mode 100644 index 0000000..45a0bfd --- /dev/null +++ b/mpq/lua/melee/melee_ai.lua @@ -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 +---@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 +---@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 +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 diff --git a/mpq/lua/melee/personalities.lua b/mpq/lua/melee/personalities.lua new file mode 100644 index 0000000..d995e6c --- /dev/null +++ b/mpq/lua/melee/personalities.lua @@ -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 diff --git a/mpq/lua/melee/protoss/basic.lua b/mpq/lua/melee/protoss/basic.lua new file mode 100644 index 0000000..af2e61e --- /dev/null +++ b/mpq/lua/melee/protoss/basic.lua @@ -0,0 +1,13 @@ +local Basic = {} + +---@type BuildOrder +function Basic.build_anti_ground(melee_ai, town) + melee_ai:build_sequence(town, 1, 4, UnitId.ProtossWarden, 70, 5, secs(25), secs(5)) +end + +---@type BuildOrder +function Basic.build_anti_air(melee_ai, town) + melee_ai:build_sequence(town, 1, 3, UnitId.ProtossMatrix, 80, 5, secs(25), secs(5)) +end + +return Basic diff --git a/mpq/lua/melee/protoss/general/lunatic_legion.lua b/mpq/lua/melee/protoss/general/lunatic_legion.lua new file mode 100644 index 0000000..37f8d0a --- /dev/null +++ b/mpq/lua/melee/protoss/general/lunatic_legion.lua @@ -0,0 +1,72 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "General: Lunatic Legion", + unit_composition = { + -- signature units + [UnitId.ProtossLegionnaire] = 2, + [UnitId.ProtossSimulacrum] = 2, + -- filler units + [UnitId.ProtossEcclesiast] = 1, + [UnitId.ProtossAurora] = 1, + [UnitId.ProtossMagister] = 1, + [UnitId.ProtossDidact] = 1, + [UnitId.ProtossAnalogue] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(20)) + town:build(2, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossPylon, 40) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(40)) + -- tier2 + town:build(1, UnitId.ProtossStargate, 70) + melee_ai:dynamic_wait(secs(20)) + town:build(2, UnitId.ProtossStargate, 70) + melee_ai:dynamic_wait(secs(45)) + town:build(3, UnitId.ProtossGateway, 70) + melee_ai:dynamic_wait(secs(15)) + town:build(3, UnitId.ProtossStargate, 70) + melee_ai:dynamic_wait(secs(20)) + town:build(4, UnitId.ProtossGateway, 70) + melee_ai:dynamic_wait(secs(15)) + town:build(4, UnitId.ProtossStargate, 70) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossGrandLibrary, 70) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossGrandLibrary, 70) + melee_ai:dynamic_wait(secs(15)) + -- tier3 + town:build(1, UnitId.ProtossArgosy, 50) + -- tier4 + town:build(1, UnitId.ProtossSyntheticSynod, 45) + melee_ai:dynamic_wait(secs(15)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + melee_ai:dynamic_wait(secs(25)) + -- production for the Legionnaire + Simulacrum army + Stargate / Argosy fleet & Synthetic Synod + town:build(1, UnitId.ProtossGateway, 85, true) + town:build(1, UnitId.ProtossLattice, 82, true) + town:build(1, UnitId.ProtossEmbassy, 80, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ProtossStargate, 70, true) + town:build(1, UnitId.ProtossArdentAuthority, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossArgosy, 55, true) + town:build(1, UnitId.ProtossUnitaryUnion, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossSyntheticSynod, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/protoss/general/matriarchy.lua b/mpq/lua/melee/protoss/general/matriarchy.lua new file mode 100644 index 0000000..a9f56f8 --- /dev/null +++ b/mpq/lua/melee/protoss/general/matriarchy.lua @@ -0,0 +1,67 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "General: Matriarchy", + unit_composition = { + -- signature units (Prostration Stage / Synthetic Synod) + [UnitId.ProtossZealot] = 2, + [UnitId.ProtossAmaranth] = 2, + [UnitId.ProtossVassal] = 2, + -- filler units + [UnitId.ProtossEmpress] = 1, + [UnitId.ProtossAnalogue] = 1, + [UnitId.ProtossPariah] = 1, + [UnitId.ProtossMindTyrant] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(40)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(5)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(40)) + town:build(3, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(25)) + -- tier2 + town:build(1, UnitId.ProtossGrandLibrary, 70) + melee_ai:dynamic_wait(secs(15)) + town:build(3, UnitId.ProtossLattice, 70) + melee_ai:dynamic_wait(secs(25)) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(mins(1) + secs(40)) + -- tier4 + town:build(2, UnitId.ProtossSyntheticSynod, 45) + melee_ai:dynamic_wait(mins(1)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + melee_ai:dynamic_wait(secs(25)) + -- production for the Zealot / Amaranth / Vassal army + Synthetic Synod & Prostration Stage tech + town:build(1, UnitId.ProtossGateway, 85, true) + town:build(1, UnitId.ProtossLattice, 82, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + town:build(1, UnitId.ProtossArdentAuthority, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + town:build(1, UnitId.ProtossUnitaryUnion, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossSyntheticSynod, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/protoss/general/robotics_fe.lua b/mpq/lua/melee/protoss/general/robotics_fe.lua new file mode 100644 index 0000000..dcd9495 --- /dev/null +++ b/mpq/lua/melee/protoss/general/robotics_fe.lua @@ -0,0 +1,63 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "General: Robotics FE", + unit_composition = { + -- signature units (Ardent Authority x2) + [UnitId.ProtossZealot] = 2, + [UnitId.ProtossVassal] = 2, + -- filler units + [UnitId.ProtossServitor] = 1, + [UnitId.ProtossPositron] = 1, + [UnitId.ProtossAccantor] = 1, + [UnitId.ProtossClarion] = 1, + [UnitId.ProtossPariah] = 1, + [UnitId.ProtossAnalogue] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ProtossPylon, 40) + -- tier1 + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(40)) + -- tier2 + town:build(1, UnitId.ProtossArdentAuthority, 70) + melee_ai:dynamic_wait(secs(40)) + town:build(2, UnitId.ProtossArdentAuthority, 70) + melee_ai:dynamic_wait(secs(40)) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(mins(2) + secs(20)) + -- tier4 + town:build(1, UnitId.ProtossSyntheticSynod, 45) + melee_ai:dynamic_wait(secs(15)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + melee_ai:dynamic_wait(secs(25)) + -- production for the Ardent Authority core (Servitor / Positron / Accantor / Clarion) + Zealot / Vassal + town:build(1, UnitId.ProtossGateway, 85, true) + town:build(1, UnitId.ProtossLattice, 82, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ProtossArdentAuthority, 72, true) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + town:build(1, UnitId.ProtossUnitaryUnion, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossSyntheticSynod, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/protoss/general/strident_striders.lua b/mpq/lua/melee/protoss/general/strident_striders.lua new file mode 100644 index 0000000..c7ecb02 --- /dev/null +++ b/mpq/lua/melee/protoss/general/strident_striders.lua @@ -0,0 +1,58 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "General: Strident Striders", + unit_composition = { + -- signature unit + [UnitId.ProtossDracadin] = 2, + -- filler units + [UnitId.ProtossAtreus] = 1, + [UnitId.ProtossPariah] = 1, + [UnitId.ProtossAnalogue] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + town:build(1, UnitId.ProtossGateway, 90) + -- tier1 + melee_ai:dynamic_wait(secs(20)) + town:build(2, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(50)) + town:build(3, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(mins(1) + secs(45)) + -- tier2 + town:build(1, UnitId.ProtossLattice, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossGateway, 70) + town:build(1, UnitId.ProtossGrandLibrary, 70) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossSyntheticSynod, 45) + melee_ai:dynamic_wait(secs(15)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + melee_ai:dynamic_wait(secs(25)) + -- production for the Dracadin striders (+ Atreus / Pariah / Analogue) + Synthetic Synod tech + town:build(1, UnitId.ProtossGateway, 85, true) + town:build(1, UnitId.ProtossLattice, 82, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + town:build(1, UnitId.ProtossArdentAuthority, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + town:build(1, UnitId.ProtossUnitaryUnion, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossSyntheticSynod, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/protoss/general/the_swordsmiths.lua b/mpq/lua/melee/protoss/general/the_swordsmiths.lua new file mode 100644 index 0000000..5501b2e --- /dev/null +++ b/mpq/lua/melee/protoss/general/the_swordsmiths.lua @@ -0,0 +1,70 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "General: The Swordsmiths", + unit_composition = { + -- signature units (Ardent Authority x2) + [UnitId.ProtossZealot] = 2, + [UnitId.ProtossManifold] = 2, + -- filler units + [UnitId.ProtossServitor] = 1, + [UnitId.ProtossPositron] = 1, + [UnitId.ProtossAccantor] = 1, + [UnitId.ProtossClarion] = 1, + [UnitId.ProtossPariah] = 1, + [UnitId.ProtossAnalogue] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossLattice, 90) + town:wait_build(1, UnitId.ProtossGateway) + town:wait_build(1, UnitId.ProtossLattice) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(mins(1)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(40)) + -- tier2 + town:build(1, UnitId.ProtossArdentAuthority, 70) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossStargate, 70) + melee_ai:dynamic_wait(secs(40)) + town:build(2, UnitId.ProtossStargate, 70) + melee_ai:dynamic_wait(secs(40)) + town:build(2, UnitId.ProtossArdentAuthority, 70) + melee_ai:dynamic_wait(secs(25)) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossSyntheticSynod, 45) + melee_ai:dynamic_wait(secs(15)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + melee_ai:dynamic_wait(secs(25)) + -- production for the Zealot + Manifold + Ardent Authority core + Synthetic Synod tech + town:build(1, UnitId.ProtossGateway, 85, true) + town:build(1, UnitId.ProtossLattice, 82, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ProtossArdentAuthority, 72, true) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + town:build(1, UnitId.ProtossUnitaryUnion, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossSyntheticSynod, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/protoss/general/worship.lua b/mpq/lua/melee/protoss/general/worship.lua new file mode 100644 index 0000000..6db6e44 --- /dev/null +++ b/mpq/lua/melee/protoss/general/worship.lua @@ -0,0 +1,68 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "General: Worship", + unit_composition = { + -- signature units + [UnitId.ProtossAmaranth] = 2, + [UnitId.ProtossSimulacrum] = 2, + -- filler units + [UnitId.ProtossGolem] = 1, + [UnitId.ProtossDracadin] = 1, + [UnitId.ProtossPariah] = 1, + [UnitId.ProtossAnalogue] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(40)) + town:build(2, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(40)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(25)) + town:build(3, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(15)) + -- tier2 + town:build(1, UnitId.ProtossLattice, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossGateway, 70) + town:build(1, UnitId.ProtossGrandLibrary, 70) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossSyntheticSynod, 45) + melee_ai:dynamic_wait(secs(15)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + melee_ai:dynamic_wait(secs(25)) + -- production for the Amaranth + Simulacrum army + Synthetic Synod & Prostration Stage tech + town:build(1, UnitId.ProtossGateway, 85, true) + town:build(1, UnitId.ProtossLattice, 82, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + town:build(1, UnitId.ProtossArdentAuthority, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + town:build(1, UnitId.ProtossUnitaryUnion, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossSyntheticSynod, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/protoss/ranger/emissary_squared.lua b/mpq/lua/melee/protoss/ranger/emissary_squared.lua new file mode 100644 index 0000000..97f413a --- /dev/null +++ b/mpq/lua/melee/protoss/ranger/emissary_squared.lua @@ -0,0 +1,68 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Ranger: Emissary Squared", + unit_composition = { + -- signature units (Synthetic Synod) + [UnitId.ProtossAnalogue] = 2, + [UnitId.ProtossDemiurge] = 2, + [UnitId.ProtossEmpress] = 2, + -- filler units + [UnitId.ProtossVassal] = 1, + [UnitId.ProtossGolem] = 1, + [UnitId.ProtossAccantor] = 1, + [UnitId.ProtossDracadin] = 1, + [UnitId.ProtossPariah] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ProtossPylon, 40) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(55)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(mins(1)) + -- tier2 + town:build(1, UnitId.ProtossArdentAuthority, 70) + melee_ai:dynamic_wait(secs(40)) + town:build(2, UnitId.ProtossLattice, 70) + town:build(2, UnitId.ProtossGateway, 70) + melee_ai:dynamic_wait(secs(15)) + town:build(3, UnitId.ProtossGateway, 70) + melee_ai:dynamic_wait(secs(15)) + town:build(4, UnitId.ProtossGateway, 70) + melee_ai:dynamic_wait(secs(15)) + town:build(3, UnitId.ProtossLattice, 70) + melee_ai:dynamic_wait(secs(25)) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossSyntheticSynod, 45) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Lattice / Gateway army + Synthetic Synod & Prostration Stage tech + town:build(1, UnitId.ProtossLattice, 85, true) + town:build(1, UnitId.ProtossGateway, 82, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ProtossArdentAuthority, 70, true) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + town:build(1, UnitId.ProtossUnitaryUnion, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossSyntheticSynod, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/protoss/ranger/lattice_expo.lua b/mpq/lua/melee/protoss/ranger/lattice_expo.lua new file mode 100644 index 0000000..87e45d7 --- /dev/null +++ b/mpq/lua/melee/protoss/ranger/lattice_expo.lua @@ -0,0 +1,60 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Ranger: Lattice Expo", + unit_composition = { + -- signature unit + [UnitId.ProtossSimulacrum] = 2, + -- filler units + [UnitId.ProtossIdol] = 1, + [UnitId.ProtossDracadin] = 1, + [UnitId.ProtossAccantor] = 1, + [UnitId.ProtossPariah] = 1, + [UnitId.ProtossAnalogue] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(50)) + town:build(2, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(3, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(4, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(45)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(15)) + -- tier2 + town:build(1, UnitId.ProtossArdentAuthority, 70) + melee_ai:dynamic_wait(secs(50)) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossSyntheticSynod, 45) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Lattice / Gateway army + Synthetic Synod & Prostration Stage tech + town:build(1, UnitId.ProtossLattice, 85, true) + town:build(1, UnitId.ProtossGateway, 82, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ProtossArdentAuthority, 70, true) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + town:build(1, UnitId.ProtossUnitaryUnion, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossSyntheticSynod, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/protoss/ranger/one_gate_authority.lua b/mpq/lua/melee/protoss/ranger/one_gate_authority.lua new file mode 100644 index 0000000..0995608 --- /dev/null +++ b/mpq/lua/melee/protoss/ranger/one_gate_authority.lua @@ -0,0 +1,73 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Ranger: 1 Gate Authority", + unit_composition = { + -- signature unit + [UnitId.ProtossManifold] = 2, + -- filler units (Prostration Stage) + [UnitId.ProtossPariah] = 1, + [UnitId.ProtossPotentate] = 1, + [UnitId.ProtossSycophant] = 1, + [UnitId.ProtossMindTyrant] = 1, + [UnitId.ProtossIdol] = 1, + [UnitId.ProtossAccantor] = 1, + [UnitId.ProtossAnalogue] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(20)) + town:build(2, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_attacking() + -- tier1 + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(3, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(25)) + -- tier2 + town:build(1, UnitId.ProtossArdentAuthority, 70) + melee_ai:dynamic_wait(secs(15)) + town:build(4, UnitId.ProtossGateway, 70) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossLattice, 70) + melee_ai:dynamic_wait(secs(15)) + town:build(3, UnitId.ProtossLattice, 70) + melee_ai:dynamic_wait(secs(5)) + town:build(4, UnitId.ProtossLattice, 70) + melee_ai:dynamic_wait(secs(15)) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + town:build(2, UnitId.ProtossArdentAuthority, 50) + melee_ai:dynamic_wait(mins(1) + secs(15)) + -- tier4 + town:build(1, UnitId.ProtossSyntheticSynod, 45) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Manifold + Prostration Stage army (+ Accantor / Analogue) + town:build(1, UnitId.ProtossLattice, 85, true) + town:build(1, UnitId.ProtossGateway, 82, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ProtossArdentAuthority, 70, true) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + town:build(1, UnitId.ProtossUnitaryUnion, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossSyntheticSynod, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/protoss/ranger/simulant_swarm.lua b/mpq/lua/melee/protoss/ranger/simulant_swarm.lua new file mode 100644 index 0000000..2b8adb2 --- /dev/null +++ b/mpq/lua/melee/protoss/ranger/simulant_swarm.lua @@ -0,0 +1,67 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Ranger: Simulant Swarm", + unit_composition = { + -- signature unit + [UnitId.ProtossSimulacrum] = 2, + -- filler units + [UnitId.ProtossIdol] = 1, + [UnitId.ProtossEcclesiast] = 1, + [UnitId.ProtossAccantor] = 1, + [UnitId.ProtossPariah] = 1, + [UnitId.ProtossAnalogue] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(25)) + town:build(3, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(4, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(20)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(mins(1)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(20)) + town:build(5, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(20)) + -- tier2 + town:build(1, UnitId.ProtossLattice, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossGateway, 70) + town:build(1, UnitId.ProtossArdentAuthority, 70) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossSyntheticSynod, 45) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Simulacrum swarm + Synthetic Synod & Prostration Stage tech + town:build(1, UnitId.ProtossLattice, 85, true) + town:build(1, UnitId.ProtossGateway, 82, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ProtossArdentAuthority, 70, true) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + town:build(1, UnitId.ProtossUnitaryUnion, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossSyntheticSynod, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/protoss/ranger/the_registry.lua b/mpq/lua/melee/protoss/ranger/the_registry.lua new file mode 100644 index 0000000..bf8ab98 --- /dev/null +++ b/mpq/lua/melee/protoss/ranger/the_registry.lua @@ -0,0 +1,60 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Ranger: The Registry", + unit_composition = { + -- signature unit + [UnitId.ProtossManifold] = 2, + -- filler units + [UnitId.ProtossIdol] = 1, + [UnitId.ProtossAccantor] = 1, + [UnitId.ProtossPariah] = 1, + [UnitId.ProtossAnalogue] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(30)) + town:build(2, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(40)) + melee_ai:start_attacking() + -- tier1 + melee_ai:dynamic_wait(secs(40)) + town:build(2, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(40)) + town:build(4, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(secs(30)) + -- tier2 + town:build(1, UnitId.ProtossLattice, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossGateway, 70) + town:build(1, UnitId.ProtossArdentAuthority, 70) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossSyntheticSynod, 45) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Manifold registry army + Synthetic Synod & Prostration Stage tech + town:build(1, UnitId.ProtossLattice, 85, true) + town:build(1, UnitId.ProtossGateway, 82, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ProtossArdentAuthority, 70, true) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + town:build(1, UnitId.ProtossUnitaryUnion, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossSyntheticSynod, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/protoss/ranger/two_gate_strider.lua b/mpq/lua/melee/protoss/ranger/two_gate_strider.lua new file mode 100644 index 0000000..9ab1b19 --- /dev/null +++ b/mpq/lua/melee/protoss/ranger/two_gate_strider.lua @@ -0,0 +1,65 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Ranger: 2 Gate Strider", + unit_composition = { + -- signature units + [UnitId.ProtossVassal] = 2, + [UnitId.ProtossDracadin] = 2, + -- filler units + [UnitId.ProtossIdol] = 1, + [UnitId.ProtossAccantor] = 1, + [UnitId.ProtossPariah] = 1, + [UnitId.ProtossAnalogue] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(20)) + town:build(2, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(30)) + town:build(3, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(mins(1)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(45)) + town:build(4, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(5)) + -- tier2 + town:build(1, UnitId.ProtossLattice, 70) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ProtossGrandLibrary, 70) + melee_ai:dynamic_wait(secs(15)) + town:build(5, UnitId.ProtossGateway, 70) + town:build(1, UnitId.ProtossArdentAuthority, 70) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossSyntheticSynod, 45) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Vassal + Dracadin striders + Synthetic Synod & Prostration Stage tech + town:build(1, UnitId.ProtossGateway, 85, true) + town:build(1, UnitId.ProtossLattice, 82, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ProtossArdentAuthority, 70, true) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + town:build(1, UnitId.ProtossUnitaryUnion, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossSyntheticSynod, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/protoss/skylord/deadly_omen.lua b/mpq/lua/melee/protoss/skylord/deadly_omen.lua new file mode 100644 index 0000000..31538a5 --- /dev/null +++ b/mpq/lua/melee/protoss/skylord/deadly_omen.lua @@ -0,0 +1,71 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Skylord: Deadly Omen", + unit_composition = { + -- signature units + [UnitId.ProtossZealot] = 2, + [UnitId.ProtossVassal] = 2, + -- filler units + [UnitId.ProtossPanoptus] = 1, + [UnitId.ProtossExemplar] = 1, + [UnitId.ProtossPariah] = 1, + [UnitId.ProtossStarSovereign] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossStargate, 90) + melee_ai:dynamic_wait(secs(40)) + town:build(2, UnitId.ProtossStargate, 90) + town:wait_build(1, UnitId.ProtossStargate) + melee_ai:start_attacking() + melee_ai:dynamic_wait(mins(1)) + town:build(2, UnitId.ProtossPylon, 40) + town:build(2, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(40)) + town:build(3, UnitId.ProtossStargate, 90) + melee_ai:dynamic_wait(mins(1)) + town:build(4, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(50)) + town:build(5, UnitId.ProtossStargate, 90) + melee_ai:dynamic_wait(mins(1) + secs(40)) + -- tier2 + town:build(1, UnitId.ProtossLattice, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossGateway, 70) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossMonumentOfSin, 45) + melee_ai:dynamic_wait(secs(15)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Zealot + Vassal + Panoptus army (-> Argosy -> Monument of Sin) + Pariah tech + town:build(1, UnitId.ProtossGateway, 85, true) + town:build(1, UnitId.ProtossLattice, 80, true) + town:build(1, UnitId.ProtossEmbassy, 78, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ProtossStargate, 70, true) + town:build(1, UnitId.ProtossGrandLibrary, 68, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossArgosy, 55, true) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossMonumentOfSin, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/protoss/skylord/exalted.lua b/mpq/lua/melee/protoss/skylord/exalted.lua new file mode 100644 index 0000000..c91cf19 --- /dev/null +++ b/mpq/lua/melee/protoss/skylord/exalted.lua @@ -0,0 +1,73 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Skylord: Exalted", + unit_composition = { + -- signature units (Monument of Sin) + [UnitId.ProtossVassal] = 2, + [UnitId.ProtossStarSovereign] = 2, + [UnitId.ProtossAnthelion] = 2, + -- filler units + [UnitId.ProtossPanoptus] = 1, + [UnitId.ProtossExemplar] = 1, + [UnitId.ProtossDidact] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ProtossStargate, 90) + town:build(1, UnitId.ProtossWarden, 79) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossWarden, 79) + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(mins(1)) + town:build(3, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(mins(1)) + town:build(3, UnitId.ProtossStargate, 90) + melee_ai:dynamic_wait(secs(40)) + -- tier2 + town:build(1, UnitId.ProtossLattice, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossGateway, 70) + -- tier3 + town:build(1, UnitId.ProtossArgosy, 50) + town:wait_build(1, UnitId.ProtossArgosy, false) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossCrucible, 50) + melee_ai:dynamic_wait(secs(40)) + town:build(2, UnitId.ProtossArgosy, 50) + melee_ai:dynamic_wait(mins(1) + secs(15)) + -- tier4 + town:build(1, UnitId.ProtossMonumentOfSin, 45) + melee_ai:dynamic_wait(mins(1) + secs(40)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the exalted capital fleet (Star Sovereign / Anthelion / Didact) + Crucible + town:build(1, UnitId.ProtossGateway, 85, true) + town:build(1, UnitId.ProtossLattice, 80, true) + town:build(1, UnitId.ProtossEmbassy, 78, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ProtossStargate, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossArgosy, 55, true) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ProtossCrucible, 50, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ProtossMonumentOfSin, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/protoss/skylord/ships_and_swords.lua b/mpq/lua/melee/protoss/skylord/ships_and_swords.lua new file mode 100644 index 0000000..7dd67ae --- /dev/null +++ b/mpq/lua/melee/protoss/skylord/ships_and_swords.lua @@ -0,0 +1,67 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Skylord: Ships and Swords", + unit_composition = { + -- signature units + [UnitId.ProtossVassal] = 2, + [UnitId.ProtossAurora] = 1.5, + [UnitId.ProtossMagister] = 1.5, + -- filler units + [UnitId.ProtossGladius] = 1, + [UnitId.ProtossStarSovereign] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(20)) + town:build(2, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(5)) + town:build(1, UnitId.ProtossStargate, 90) + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_attacking() + -- tier1 + melee_ai:dynamic_wait(mins(1)) + town:build(3, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossStargate, 90) + melee_ai:dynamic_wait(secs(55)) + town:build(3, UnitId.ProtossStargate, 90) + melee_ai:dynamic_wait(secs(50)) + -- tier2 + town:build(1, UnitId.ProtossLattice, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossGateway, 70) + -- tier3 + town:build(1, UnitId.ProtossArgosy, 50) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossMonumentOfSin, 45) + melee_ai:dynamic_wait(secs(15)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Stargate + Argosy fleet (Aurora / Magister / Gladius) -> Monument of Sin + town:build(1, UnitId.ProtossGateway, 85, true) + town:build(1, UnitId.ProtossLattice, 80, true) + town:build(1, UnitId.ProtossEmbassy, 78, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ProtossStargate, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossArgosy, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossMonumentOfSin, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/protoss/skylord/solar_escort.lua b/mpq/lua/melee/protoss/skylord/solar_escort.lua new file mode 100644 index 0000000..7b7519a --- /dev/null +++ b/mpq/lua/melee/protoss/skylord/solar_escort.lua @@ -0,0 +1,63 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Skylord: Solar Escort", + unit_composition = { + -- signature units + [UnitId.ProtossSolarion] = 2, + [UnitId.ProtossLegionnaire] = 2, + [UnitId.ProtossVassal] = 2, + -- filler units + [UnitId.ProtossEcclesiast] = 1, + [UnitId.ProtossPanoptus] = 1, + [UnitId.ProtossGladius] = 1, + [UnitId.ProtossEmpyrean] = 1, + [UnitId.ProtossStarSovereign] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(40)) + -- tier2 + town:build(1, UnitId.ProtossStargate, 70) + melee_ai:dynamic_wait(secs(5)) + town:build(2, UnitId.ProtossStargate, 70) + melee_ai:dynamic_wait(secs(45)) + town:build(3, UnitId.ProtossStargate, 70) + melee_ai:dynamic_wait(mins(1)) + -- tier3 + town:build(1, UnitId.ProtossArgosy, 50) + melee_ai:dynamic_wait(secs(40)) + town:build(2, UnitId.ProtossArgosy, 50) + melee_ai:dynamic_wait(secs(40)) + town:build(3, UnitId.ProtossArgosy, 50) + melee_ai:dynamic_wait(secs(25)) + -- tier4 + town:build(1, UnitId.ProtossMonumentOfSin, 45) + melee_ai:dynamic_wait(secs(15)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Solarion + Vassal escort (Stargate -> Argosy -> Monument of Sin) + Gateway + town:build(1, UnitId.ProtossGateway, 85, true) + town:build(1, UnitId.ProtossLattice, 80, true) + town:build(1, UnitId.ProtossEmbassy, 78, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ProtossStargate, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossArgosy, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossMonumentOfSin, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/protoss/skylord/sorrow_fleet.lua b/mpq/lua/melee/protoss/skylord/sorrow_fleet.lua new file mode 100644 index 0000000..f5f1957 --- /dev/null +++ b/mpq/lua/melee/protoss/skylord/sorrow_fleet.lua @@ -0,0 +1,63 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Skylord: Sorrow Fleet", + unit_composition = { + -- signature units (Monument of Sin) + [UnitId.ProtossVassal] = 2, + [UnitId.ProtossStarSovereign] = 2, + [UnitId.ProtossAnthelion] = 1.5, + -- filler units + [UnitId.ProtossPanoptus] = 1, + [UnitId.ProtossGladius] = 1, + [UnitId.ProtossEmpyrean] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ProtossLattice, 90) + melee_ai:dynamic_wait(mins(1)) + town:build(1, UnitId.ProtossStargate, 90) + melee_ai:dynamic_wait(secs(40)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(40)) + -- tier2 + town:build(1, UnitId.ProtossLattice, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossGateway, 70) + -- tier3 + town:build(1, UnitId.ProtossArgosy, 50) + melee_ai:dynamic_wait(mins(1)) + town:build(2, UnitId.ProtossArgosy, 50) + melee_ai:dynamic_wait(secs(40)) + town:build(3, UnitId.ProtossArgosy, 50) + melee_ai:dynamic_wait(mins(1) + secs(15)) + -- tier4 + town:build(1, UnitId.ProtossMonumentOfSin, 45) + melee_ai:dynamic_wait(mins(2) + secs(45)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Monument of Sin fleet (Star Sovereign / Anthelion) + Stargate / Argosy + town:build(1, UnitId.ProtossGateway, 85, true) + town:build(1, UnitId.ProtossLattice, 80, true) + town:build(1, UnitId.ProtossEmbassy, 78, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ProtossStargate, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossArgosy, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossMonumentOfSin, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/protoss/skylord/two_gate_panoptus.lua b/mpq/lua/melee/protoss/skylord/two_gate_panoptus.lua new file mode 100644 index 0000000..cbc4249 --- /dev/null +++ b/mpq/lua/melee/protoss/skylord/two_gate_panoptus.lua @@ -0,0 +1,62 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Skylord: 2 Gate Panoptus", + unit_composition = { + -- signature units + [UnitId.ProtossPanoptus] = 3, + [UnitId.ProtossVassal] = 2, + -- filler units + [UnitId.ProtossHierophant] = 1, + [UnitId.ProtossPariah] = 1, + [UnitId.ProtossStarSovereign] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossStargate, 90) + melee_ai:dynamic_wait(secs(50)) + town:build(2, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(5)) + melee_ai:start_attacking() + -- tier1 + melee_ai:dynamic_wait(mins(1) + secs(35)) + town:build(3, UnitId.ProtossGateway, 90) + -- tier2 + town:build(1, UnitId.ProtossLattice, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossGateway, 70) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossMonumentOfSin, 45) + melee_ai:dynamic_wait(secs(15)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Panoptus + Vassal army (-> Argosy -> Monument of Sin) + Hierophant / Pariah tech + town:build(1, UnitId.ProtossGateway, 85, true) + town:build(1, UnitId.ProtossLattice, 80, true) + town:build(1, UnitId.ProtossEmbassy, 78, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ProtossStargate, 70, true) + town:build(1, UnitId.ProtossGrandLibrary, 68, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossArgosy, 55, true) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossMonumentOfSin, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/protoss/templar/initiates.lua b/mpq/lua/melee/protoss/templar/initiates.lua new file mode 100644 index 0000000..461c64d --- /dev/null +++ b/mpq/lua/melee/protoss/templar/initiates.lua @@ -0,0 +1,66 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Templar: Initiates", + unit_composition = { + -- signature unit + [UnitId.ProtossZealot] = 2, + -- filler units + [UnitId.ProtossEcclesiast] = 1, + [UnitId.ProtossCantavis] = 1, + [UnitId.ProtossAccantor] = 1, + [UnitId.ProtossArchon] = 1, + [UnitId.ProtossPariah] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossPylon, 40) + town:wait_build(2, UnitId.ProtossGateway) + melee_ai:dynamic_wait(secs(10)) + town:build(3, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(40)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(20)) + town:build(4, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(25)) + -- tier2 + town:build(1, UnitId.ProtossLattice, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ProtossGateway, 70) + town:build(1, UnitId.ProtossGrandLibrary, 70) + town:build(1, UnitId.ProtossArdentAuthority, 70) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossAncestralArchives, 45) + melee_ai:dynamic_wait(secs(15)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Zealot core (+ Cantavis / Accantor / Archon / Pariah) + town:build(1, UnitId.ProtossGateway, 85, true) + town:build(1, UnitId.ProtossLattice, 80, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + town:build(1, UnitId.ProtossArdentAuthority, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossAncestralArchives, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/protoss/templar/legion.lua b/mpq/lua/melee/protoss/templar/legion.lua new file mode 100644 index 0000000..547a4ce --- /dev/null +++ b/mpq/lua/melee/protoss/templar/legion.lua @@ -0,0 +1,68 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Templar: Legion", + unit_composition = { + -- signature unit + [UnitId.ProtossLegionnaire] = 2, + -- filler units + [UnitId.ProtossEcclesiast] = 1, + [UnitId.ProtossArchon] = 1, + [UnitId.ProtossAtreus] = 1, + [UnitId.ProtossPariah] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(35)) + town:build(3, UnitId.ProtossGateway, 90) + town:build(3, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(30)) + town:build(4, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(5, UnitId.ProtossGateway, 90) + town:build(4, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(20)) + town:build(6, UnitId.ProtossGateway, 90) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(40)) + town:build(9, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(40)) + -- tier2 + town:build(1, UnitId.ProtossGrandLibrary, 70) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossGrandLibrary, 70) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossAncestralArchives, 45) + melee_ai:dynamic_wait(secs(15)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Legionnaire core (Gateway -> Grand Library -> Ancestral Archives) + town:build(1, UnitId.ProtossGateway, 85, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossAncestralArchives, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/protoss/templar/legions_heralds.lua b/mpq/lua/melee/protoss/templar/legions_heralds.lua new file mode 100644 index 0000000..e4c85b9 --- /dev/null +++ b/mpq/lua/melee/protoss/templar/legions_heralds.lua @@ -0,0 +1,64 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Templar: Legion's Heralds", + unit_composition = { + -- signature unit + [UnitId.ProtossLegionnaire] = 2, + -- filler units + [UnitId.ProtossEcclesiast] = 1, + [UnitId.ProtossAtreus] = 1, + [UnitId.ProtossHerald] = 1, + [UnitId.ProtossPatriarch] = 1, + [UnitId.ProtossPariah] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(20)) + town:build(2, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(20)) + -- tier2 + town:build(1, UnitId.ProtossGrandLibrary, 70) + melee_ai:dynamic_wait(secs(20)) + town:build(3, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(3, UnitId.ProtossGateway, 70) + melee_ai:dynamic_wait(secs(40) + mins(1)) + town:build(5, UnitId.ProtossGateway, 70) + melee_ai:dynamic_wait(secs(40)) + town:build(2, UnitId.ProtossGrandLibrary, 70) + melee_ai:dynamic_wait(mins(1)) + town:build(9, UnitId.ProtossGateway, 70) + melee_ai:dynamic_wait(mins(1) + secs(55)) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossAncestralArchives, 45) + melee_ai:dynamic_wait(secs(15)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Legionnaire + Herald / Patriarch core (Gateway -> Grand Library -> Ancestral Archives) + town:build(1, UnitId.ProtossGateway, 85, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossAncestralArchives, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/protoss/templar/martyrdom.lua b/mpq/lua/melee/protoss/templar/martyrdom.lua new file mode 100644 index 0000000..b603672 --- /dev/null +++ b/mpq/lua/melee/protoss/templar/martyrdom.lua @@ -0,0 +1,67 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Templar: Martyrdom", + unit_composition = { + -- signature units (Ancestral Archives x4) + [UnitId.ProtossArchon] = 2, + [UnitId.ProtossLegionnaire] = 2, + -- filler units + [UnitId.ProtossAtreus] = 1, + [UnitId.ProtossMindTyrant] = 1, + [UnitId.ProtossOptecton] = 1, + [UnitId.ProtossPatriarch] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(3, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(3, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(40)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(mins(2) + secs(30)) + -- tier2 + town:build(4, UnitId.ProtossPylon, 40) + town:build(2, UnitId.ProtossRogueGallery, 70) + town:build(1, UnitId.ProtossGrandLibrary, 70) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ProtossCrucible, 50) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(2, UnitId.ProtossAncestralArchives, 45) + melee_ai:dynamic_wait(mins(1)) + town:wait_build(2, UnitId.ProtossAncestralArchives, false) + melee_ai:dynamic_wait(secs(25)) + town:build(4, UnitId.ProtossAncestralArchives, 45) + melee_ai:dynamic_wait(secs(45)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Ancestral Archives martyrs (Archon / Optecton / Patriarch + Legionnaire) + town:build(1, UnitId.ProtossGateway, 85, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ProtossCrucible, 50, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ProtossAncestralArchives, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/protoss/templar/suffocating_shadow.lua b/mpq/lua/melee/protoss/templar/suffocating_shadow.lua new file mode 100644 index 0000000..5bb0131 --- /dev/null +++ b/mpq/lua/melee/protoss/templar/suffocating_shadow.lua @@ -0,0 +1,59 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Templar: Suffocating Shadow", + unit_composition = { + -- signature units (Rogue Gallery) + [UnitId.ProtossVagrant] = 2, + [UnitId.ProtossCabalist] = 2, + [UnitId.ProtossCharlatan] = 2, + [UnitId.ProtossBarghest] = 2, + [UnitId.ProtossZealot] = 2, + -- filler units + [UnitId.ProtossAtreus] = 1, + [UnitId.ProtossEcclesiast] = 1, + [UnitId.ProtossPariah] = 1, + [UnitId.ProtossArchon] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossGateway, 90) + -- tier1 + melee_ai:dynamic_wait(secs(20)) + town:build(2, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(45)) + -- tier2 + town:build(1, UnitId.ProtossRogueGallery, 70) + town:build(2, UnitId.ProtossRogueGallery, 70) + melee_ai:dynamic_wait(secs(30) + secs(40)) + town:build(1, UnitId.ProtossGrandLibrary, 70) + melee_ai:dynamic_wait(mins(1) + secs(5)) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossAncestralArchives, 45) + melee_ai:dynamic_wait(secs(15)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Rogue Gallery shadow army (Vagrant / Cabalist / Charlatan / Barghest + Zealot) + town:build(1, UnitId.ProtossGateway, 85, true) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossRogueGallery, 75, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossAncestralArchives, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/protoss/templar/three_gate_strider.lua b/mpq/lua/melee/protoss/templar/three_gate_strider.lua new file mode 100644 index 0000000..447699e --- /dev/null +++ b/mpq/lua/melee/protoss/templar/three_gate_strider.lua @@ -0,0 +1,60 @@ +local Basic = require "melee.protoss.basic" + +---@type AIPersonality +return { + name = "Templar: 3 Gate Strider", + unit_composition = { + -- signature unit + [UnitId.ProtossLegionnaire] = 2, + -- filler units + [UnitId.ProtossAccantor] = 1, + [UnitId.ProtossDracadin] = 1, + [UnitId.ProtossArchon] = 1, + [UnitId.ProtossPariah] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossPylon, 40) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ProtossGateway, 90) + -- tier1 + melee_ai:dynamic_wait(secs(30)) + town:build(2, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(mins(1)) + town:build(3, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(4, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(5, UnitId.ProtossGateway, 90) + melee_ai:dynamic_wait(secs(15)) + -- tier2 + town:build(1, UnitId.ProtossGrandLibrary, 70) + melee_ai:dynamic_wait(mins(1)) + town:build(2, UnitId.ProtossGrandLibrary, 70) + town:build(1, UnitId.ProtossArdentAuthority, 70) + -- tier3 + town:build(1, UnitId.ProtossProstrationStage, 65) + melee_ai:dynamic_wait(secs(50)) + -- tier4 + town:build(1, UnitId.ProtossAncestralArchives, 45) + melee_ai:dynamic_wait(secs(15)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Legionnaire striders (+ Accantor / Dracadin / Archon / Pariah) + town:build(1, UnitId.ProtossGateway, 85, true) + town:build(1, UnitId.ProtossLattice, 80, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ProtossGrandLibrary, 70, true) + town:build(1, UnitId.ProtossArdentAuthority, 70, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossProstrationStage, 55, true) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ProtossAncestralArchives, 45, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/terran/armor/david_and_goliath.lua b/mpq/lua/melee/terran/armor/david_and_goliath.lua new file mode 100644 index 0000000..dfc5ed9 --- /dev/null +++ b/mpq/lua/melee/terran/armor/david_and_goliath.lua @@ -0,0 +1,97 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Armor: David and Goliath", + unit_composition = { + -- signature units + [UnitId.TerranGoliath] = 3, + [UnitId.TerranMaverick] = 2, + -- filler units + [UnitId.TerranMatadorTankMode] = 1, + [UnitId.TerranPhalanxTankMode] = 1, + [UnitId.TerranWraith] = 1, + [UnitId.TerranBlackjack] = 1, + [UnitId.TerranRamesses] = 1, + [UnitId.TerranCuirassTankMode] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranFulcrum, 110) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(40)) + town:build(2, UnitId.TerranStockade, 90) + town:wait_build(2, UnitId.TerranStockade, false) + melee_ai:dynamic_wait(secs(15)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(30)) + town:build(2, UnitId.TerranFulcrum, 90) + town:wait_build(2, UnitId.TerranFulcrum, false) + town:multirun(function(town) + town:wait_build(2, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranScrapyard, 89) + town:wait_build(2, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranPalladium, 89) + melee_ai:dynamic_wait(secs(5)) + town:wait_build(3, UnitId.TerranFulcrum) + town:build(2, UnitId.TerranPalladium, 89) + melee_ai:dynamic_wait(secs(15)) + town:wait_build(5, UnitId.TerranFulcrum) + town:build(3, UnitId.TerranPalladium, 89) + melee_ai:dynamic_wait(secs(15)) + end) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(50)) + town:build(3, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(4, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(3, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(mins(1) + secs(20)) + town:wait_build(1, UnitId.TerranFulcrum) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.TerranStarpad, 90) + melee_ai:dynamic_wait(secs(40)) + -- tier2 + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(4, UnitId.TerranFulcrum, 70) + melee_ai:dynamic_wait(secs(25)) + town:build(5, UnitId.TerranFulcrum, 70) + melee_ai:dynamic_wait(secs(5)) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Goliath / Maverick army (+ Matador / Phalanx / Wraith / Cuirass) + town:build(1, UnitId.TerranFulcrum, 70, true) + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranScrapyard, 68, true) + town:build(1, UnitId.TerranPalladium, 68, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranStarpad, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranMantle, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranIronFoundry, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/terran/armor/fe_five_fulc.lua b/mpq/lua/melee/terran/armor/fe_five_fulc.lua new file mode 100644 index 0000000..a01081e --- /dev/null +++ b/mpq/lua/melee/terran/armor/fe_five_fulc.lua @@ -0,0 +1,80 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Armor: FE 5Fulc", + unit_composition = { + -- signature units + [UnitId.TerranVulture] = 2, + [UnitId.TerranBlackjack] = 2, + [UnitId.TerranPhalanxTankMode] = 2, + -- filler units + [UnitId.TerranMaverick] = 1, + [UnitId.TerranAzazel] = 1, + [UnitId.TerranSeraph] = 1, + [UnitId.TerranRamesses] = 1, + [UnitId.TerranCuirassTankMode] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranStockade, 110) + melee_ai:dynamic_wait(secs(35)) + town:build(1, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(secs(45)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(50)) + town:build(3, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(secs(5)) + -- tier2 (starport/commandment) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranScrapyard, 69) + town:wait_build(2, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranPalladium, 69) + town:wait_build(3, UnitId.TerranFulcrum) + town:build(2, UnitId.TerranPalladium, 69) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranStarport, 70) + town:wait_build(1, UnitId.TerranStarport) + town:build(1, UnitId.TerranCommandment, 69) + end) + melee_ai:dynamic_wait(secs(25)) + town:wait_build(2, UnitId.TerranFulcrum, false) + melee_ai:dynamic_wait(secs(70) + secs(25)) + town:build(5, UnitId.TerranFulcrum, 70) + melee_ai:dynamic_wait(mins(2) + secs(15)) + town:build(1, UnitId.TerranAtlas, 70, true) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Vulture / Blackjack / Phalanx army (+ Azazel / Seraph / Cuirass) + town:build(1, UnitId.TerranFulcrum, 70, true) + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranScrapyard, 68, true) + town:build(1, UnitId.TerranPalladium, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranStarport, 65, true) + town:build(1, UnitId.TerranCommandment, 65, true) + town:build(1, UnitId.TerranMantle, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranIronFoundry, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/terran/armor/iron_crusade.lua b/mpq/lua/melee/terran/armor/iron_crusade.lua new file mode 100644 index 0000000..2ce4087 --- /dev/null +++ b/mpq/lua/melee/terran/armor/iron_crusade.lua @@ -0,0 +1,78 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Armor: Iron Crusade", + unit_composition = { + -- signature units (Iron Foundry x4 is the real investment of this build) + [UnitId.TerranPaladin] = 3, + [UnitId.TerranCuirassTankMode] = 2, + [UnitId.TerranPazuzu] = 2, + -- filler units + [UnitId.TerranVulture] = 1, + [UnitId.TerranWraith] = 1, + [UnitId.TerranRamesses] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(mins(1)) + town:wait_build(1, UnitId.TerranFulcrum) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.TerranStarpad, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(mins(1) + secs(20)) + -- tier2 + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(3, UnitId.TerranFulcrum, 70) + melee_ai:dynamic_wait(secs(5)) + town:wait_build(2, UnitId.TerranFulcrum) + town:wait_build(3, UnitId.TerranFulcrum, false) + town:wait_build(1, UnitId.TerranAtlas) + melee_ai:dynamic_wait(secs(20)) + town:build(4, UnitId.TerranFulcrum, 70) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranMantle, 69, true) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + melee_ai:dynamic_wait(secs(5)) + town:build(1, UnitId.TerranIronFoundry, 50) + melee_ai:dynamic_wait(secs(5)) + town:build(2, UnitId.TerranIronFoundry, 50) + melee_ai:dynamic_wait(secs(5)) + town:build(3, UnitId.TerranIronFoundry, 50) + melee_ai:dynamic_wait(secs(5)) + town:build(4, UnitId.TerranIronFoundry, 50) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Iron Foundry crusade (Paladin / Cuirass / Pazuzu + Vulture / Wraith / Ramesses) + town:build(1, UnitId.TerranFulcrum, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranStarpad, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranMantle, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranIronFoundry, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/terran/armor/tank_push.lua b/mpq/lua/melee/terran/armor/tank_push.lua new file mode 100644 index 0000000..e2784aa --- /dev/null +++ b/mpq/lua/melee/terran/armor/tank_push.lua @@ -0,0 +1,84 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Armor: Tank Push", + unit_composition = { + -- signature units + [UnitId.TerranMatadorTankMode] = 2, + [UnitId.TerranPhalanxTankMode] = 2, + -- healers + [UnitId.TerranCleric] = 1, + -- filler units + [UnitId.TerranCyprian] = 1, + [UnitId.TerranBlackjack] = 1, + [UnitId.TerranMadrigalImperiosoMode] = 1, + [UnitId.TerranRamesses] = 1, + [UnitId.TerranCuirassTankMode] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranFulcrum, 110) + melee_ai:dynamic_wait(secs(5)) + town:wait_build(1, UnitId.TerranFulcrum) + melee_ai:dynamic_wait(secs(5)) + town:build(1, UnitId.TerranScrapyard, 90) + town:multirun(function(town) + melee_ai:dynamic_wait(secs(18)) + town:wait_build(2, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranPalladium, 89) + town:wait_build(3, UnitId.TerranFulcrum) + town:build(2, UnitId.TerranPalladium, 89) + town:wait_build(4, UnitId.TerranFulcrum) + town:build(3, UnitId.TerranPalladium, 89) + town:wait_build(1, UnitId.TerranStockade) + town:build(1, UnitId.TerranVestry, 89) + end) + town:wait_build(1, UnitId.TerranScrapyard, false) + town:build(2, UnitId.TerranFulcrum, 90) + town:wait_build(2, UnitId.TerranFulcrum, false) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(40)) + town:build(3, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(4, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(25)) + -- tier2 + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(mins(1)) + town:build(1, UnitId.TerranStockade, 70) + melee_ai:dynamic_wait(secs(25)) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Matador / Phalanx tank push (+ Cleric / Ramesses / Cuirass) + town:build(1, UnitId.TerranFulcrum, 70, true) + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranScrapyard, 68, true) + town:build(1, UnitId.TerranPalladium, 68, true) + town:build(1, UnitId.TerranVestry, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranMantle, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranIronFoundry, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/terran/armor/two_fulc_vulture.lua b/mpq/lua/melee/terran/armor/two_fulc_vulture.lua new file mode 100644 index 0000000..de82e37 --- /dev/null +++ b/mpq/lua/melee/terran/armor/two_fulc_vulture.lua @@ -0,0 +1,57 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Armor: 2Fulc Vulture", + unit_composition = { + -- signature unit + [UnitId.TerranVulture] = 3, + -- filler units + [UnitId.TerranMaverick] = 1, + [UnitId.TerranCyclops] = 1, + [UnitId.TerranRamesses] = 1, + [UnitId.TerranCuirassTankMode] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranFulcrum, 110) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(mins(1) + secs(15)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(50)) + melee_ai:start_expanding() + -- tier1 + town:build(3, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(secs(5)) + town:build(1, UnitId.TerranStockade, 90) + -- tier2/tier3 + town:build(1, UnitId.TerranAtlas, 70, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Vulture-heavy mech (+ Maverick / Cyclops / Ramesses / Cuirass) + town:build(1, UnitId.TerranFulcrum, 70, true) + town:build(1, UnitId.TerranStockade, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranMantle, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranIronFoundry, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/terran/armor/walker_power.lua b/mpq/lua/melee/terran/armor/walker_power.lua new file mode 100644 index 0000000..794b9f0 --- /dev/null +++ b/mpq/lua/melee/terran/armor/walker_power.lua @@ -0,0 +1,70 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Armor: Walker Power", + unit_composition = { + -- signature units (walkers) + [UnitId.TerranGoliath] = 3, + [UnitId.TerranCyclops] = 2, + [UnitId.TerranBlackjack] = 2, + -- filler units + [UnitId.TerranPhalanxTankMode] = 1, + [UnitId.TerranMaverick] = 1, + [UnitId.TerranRamesses] = 1, + [UnitId.TerranCuirassTankMode] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.TerranFulcrum, 110) + melee_ai:dynamic_wait(secs(20)) + town:build(2, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(secs(35)) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranScrapyard, 89) + melee_ai:dynamic_wait(secs(15)) + town:wait_build(2, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranPalladium, 89) + end) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(5)) + town:wait_build(1, UnitId.TerranFulcrum) + town:wait_build(2, UnitId.TerranFulcrum, false) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(mins(1) + secs(10)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(mins(1)) + -- tier2/tier3 + town:build(1, UnitId.TerranAtlas, 70, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Goliath / Cyclops / Blackjack walkers (+ Phalanx / Ramesses / Cuirass) + town:build(1, UnitId.TerranFulcrum, 70, true) + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranScrapyard, 68, true) + town:build(1, UnitId.TerranPalladium, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranMantle, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranIronFoundry, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/terran/basic.lua b/mpq/lua/melee/terran/basic.lua new file mode 100644 index 0000000..fb8cf0b --- /dev/null +++ b/mpq/lua/melee/terran/basic.lua @@ -0,0 +1,13 @@ +local Basic = {} + +---@type BuildOrder +function Basic.build_anti_ground(melee_ai, town) + melee_ai:build_sequence(town, 1, 2, UnitId.TerranAnchor, 70, 5, secs(25), secs(5)) +end + +---@type BuildOrder +function Basic.build_anti_air(melee_ai, town) + melee_ai:build_sequence(town, 1, 4, UnitId.TerranWatchdog, 80, 5, secs(25), secs(5)) +end + +return Basic diff --git a/mpq/lua/melee/terran/general/doubling_up.lua b/mpq/lua/melee/terran/general/doubling_up.lua new file mode 100644 index 0000000..2f1eb7c --- /dev/null +++ b/mpq/lua/melee/terran/general/doubling_up.lua @@ -0,0 +1,84 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "General: Doubling Up", + unit_composition = { + -- signature units + [UnitId.TerranMaverick] = 2, + [UnitId.TerranGoliath] = 2, + -- healers + [UnitId.TerranShamanSupportMode] = 1, + -- filler units + [UnitId.TerranCyclops] = 1, + [UnitId.TerranBlackjack] = 1, + [UnitId.TerranRamesses] = 1, + [UnitId.TerranCuirassTankMode] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranStockade, 110) + melee_ai:dynamic_wait(secs(5)) + town:build(2, UnitId.TerranStockade, 90) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(25)) + town:build(3, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(mins(1) + secs(30)) + town:build(1, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(secs(15)) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranStockade) + town:build(1, UnitId.TerranVestry, 89) + town:wait_build(1, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranScrapyard, 89) + town:wait_build(2, UnitId.TerranFulcrum) + town:build(2, UnitId.TerranScrapyard, 89) + town:wait_build(2, UnitId.TerranStockade) + town:build(1, UnitId.TerranCovenant, 89) + melee_ai:dynamic_wait(secs(5)) + town:wait_build(3, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranPalladium, 89) + end) + melee_ai:dynamic_wait(secs(15)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.TerranStarpad, 90) + melee_ai:dynamic_wait(secs(25)) + -- tier2 + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(3, UnitId.TerranFulcrum, 70) + melee_ai:dynamic_wait(secs(45)) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Maverick + Goliath doubles (+ Shaman / Cyclops / Blackjack / Cuirass) + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranVestry, 68, true) + town:build(1, UnitId.TerranFulcrum, 70, true) + town:build(1, UnitId.TerranScrapyard, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranMantle, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranIronFoundry, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/terran/general/early_riser.lua b/mpq/lua/melee/terran/general/early_riser.lua new file mode 100644 index 0000000..6074c06 --- /dev/null +++ b/mpq/lua/melee/terran/general/early_riser.lua @@ -0,0 +1,65 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "General: Early Riser", + unit_composition = { + -- signature unit + [UnitId.TerranMaverick] = 2, + -- healers + [UnitId.TerranCleric] = 1, + -- filler units + [UnitId.TerranCyclops] = 1, + [UnitId.TerranRamesses] = 1, + [UnitId.TerranCuirassTankMode] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + melee_ai:dynamic_wait(secs(40)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(secs(25)) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranStockade) + town:build(1, UnitId.TerranVestry, 89) + town:wait_build(1, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranPalladium, 89) + end) + melee_ai:dynamic_wait(secs(5)) + town:build(1, UnitId.TerranStarpad, 90) + melee_ai:dynamic_wait(secs(5)) + town:build(2, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(mins(1)) + -- tier2/tier3 + town:build(1, UnitId.TerranAtlas, 70, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Maverick + Cleric core (+ Cyclops / Ramesses / Cuirass) + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranVestry, 68, true) + town:build(1, UnitId.TerranFulcrum, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranMantle, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranIronFoundry, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/terran/general/mech_into_air.lua b/mpq/lua/melee/terran/general/mech_into_air.lua new file mode 100644 index 0000000..f9582b9 --- /dev/null +++ b/mpq/lua/melee/terran/general/mech_into_air.lua @@ -0,0 +1,107 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "General: Mech into Air", + unit_composition = { + -- signature units (the mech-into-air transition) + [UnitId.TerranPhalanxTankMode] = 2, + [UnitId.TerranMinotaur] = 2, + -- filler units + [UnitId.TerranMatadorTankMode] = 1, + [UnitId.TerranSalamander] = 1, + [UnitId.TerranSeraph] = 1, + [UnitId.TerranHippogriff] = 1, + [UnitId.TerranPhobos] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranFulcrum, 110) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(mins(1)) + -- tier2 + town:build(1, UnitId.TerranAtlas, 70, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranScrapyard, 69) + town:wait_build(2, UnitId.TerranFulcrum) + town:build(2, UnitId.TerranScrapyard, 69) + town:build(1, UnitId.TerranQuarry, 69) + town:wait_build(3, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranPalladium, 69) + town:wait_build(4, UnitId.TerranFulcrum) + town:build(2, UnitId.TerranPalladium, 69) + town:wait_build(1, UnitId.TerranAtlas) + town:build(2, UnitId.TerranStarport, 70) + town:wait_build(1, UnitId.TerranStarport) + town:build(1, UnitId.TerranRotary, 69) + town:wait_build(2, UnitId.TerranStarport) + town:build(2, UnitId.TerranRotary, 69) + town:wait_build(5, UnitId.TerranFulcrum) + town:build(3, UnitId.TerranPalladium, 69) + town:wait_build(6, UnitId.TerranFulcrum) + town:build(4, UnitId.TerranPalladium, 69) + town:wait_build(3, UnitId.TerranStarport) + town:build(3, UnitId.TerranRotary, 69) + town:wait_build(4, UnitId.TerranStarport) + town:build(4, UnitId.TerranRotary, 69) + town:wait_build(5, UnitId.TerranStarport) + town:build(5, UnitId.TerranRotary, 69) + town:wait_build(1, UnitId.TerranDaedala) + town:wait_build(6, UnitId.TerranStarport) + town:build(1, UnitId.TerranCommandment, 69) + town:wait_build(7, UnitId.TerranStarport) + town:build(2, UnitId.TerranCommandment, 69) + town:wait_build(8, UnitId.TerranStarport) + town:build(3, UnitId.TerranCommandment, 69) + town:build(2, UnitId.TerranNaniteAssembly, 69) + town:wait_build(1, UnitId.TerranNaniteAssembly) + town:build(1, UnitId.TerranHadron, 69) + end) + melee_ai:dynamic_wait(mins(1) + secs(15)) + town:build(1, UnitId.TerranStarpad, 70) + melee_ai:dynamic_wait(secs(15) + mins(1) + secs(15)) + town:build(6, UnitId.TerranFulcrum, 70) + melee_ai:dynamic_wait(mins(1) + secs(40)) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + melee_ai:dynamic_wait(mins(1) + secs(15)) + town:build(4, UnitId.TerranStarport, 50) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(8, UnitId.TerranStarport, 50) + melee_ai:dynamic_wait(mins(1) + secs(15)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the mech-to-air transition (Phalanx / Matador -> Minotaur / Seraph / Hippogriff) + town:build(1, UnitId.TerranFulcrum, 70, true) + town:build(1, UnitId.TerranScrapyard, 68, true) + town:build(1, UnitId.TerranPalladium, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranStarport, 65, true) + town:build(1, UnitId.TerranRotary, 65, true) + town:build(1, UnitId.TerranCommandment, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranNaniteAssembly, 65, true) + town:build(1, UnitId.TerranHadron, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/terran/general/observant.lua b/mpq/lua/melee/terran/general/observant.lua new file mode 100644 index 0000000..2a34bbd --- /dev/null +++ b/mpq/lua/melee/terran/general/observant.lua @@ -0,0 +1,73 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "General: Observant", + unit_composition = { + -- signature unit + [UnitId.TerranCyprian] = 2, + -- filler units + [UnitId.TerranSeraph] = 1, + [UnitId.TerranBlackjack] = 1, + [UnitId.TerranCentaur] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranStockade, 110) + melee_ai:dynamic_wait(secs(5)) + -- tier2 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranStockade) + town:build(1, UnitId.TerranVestry, 69) + town:wait_build(1, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranScrapyard, 69) + town:wait_build(2, UnitId.TerranFulcrum) + town:build(2, UnitId.TerranPalladium, 69) + town:wait_build(3, UnitId.TerranFulcrum) + town:wait_build(1, UnitId.TerranAtlas) + town:build(2, UnitId.TerranStarport, 70) + town:wait_build(2, UnitId.TerranStarport) + town:build(2, UnitId.TerranCommandment, 69) + town:wait_build(1, UnitId.TerranCommandment) + melee_ai:dynamic_wait(secs(15)) + end) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.TerranFulcrum, 70) + melee_ai:dynamic_wait(secs(5) + secs(35)) + town:build(1, UnitId.TerranStarpad, 70) + melee_ai:dynamic_wait(secs(30)) + town:build(2, UnitId.TerranFulcrum, 70) + melee_ai:dynamic_wait(secs(25) + secs(50)) + town:build(1, UnitId.TerranAtlas, 70, true) + town:build(3, UnitId.TerranFulcrum, 70) + melee_ai:dynamic_wait(secs(50)) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Cyprian core + Blackjack / Seraph / Centaur + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranFulcrum, 70, true) + town:build(1, UnitId.TerranScrapyard, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranStarport, 65, true) + town:build(1, UnitId.TerranCommandment, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranNaniteAssembly, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/terran/general/the_cube.lua b/mpq/lua/melee/terran/general/the_cube.lua new file mode 100644 index 0000000..d9d732a --- /dev/null +++ b/mpq/lua/melee/terran/general/the_cube.lua @@ -0,0 +1,69 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "General: The Cube", + unit_composition = { + -- signature unit + [UnitId.TerranMaverick] = 2, + -- filler units + [UnitId.TerranVulture] = 1, + [UnitId.TerranPhalanxTankMode] = 1, + [UnitId.TerranSalamander] = 1, + [UnitId.TerranCentaur] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranFulcrum, 110) + -- tier1 + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.TerranStarpad, 90) + melee_ai:dynamic_wait(secs(25)) + -- tier2 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranStockade) + town:build(1, UnitId.TerranVestry, 69) + town:wait_build(1, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranPalladium, 69) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranStarport, 70) + town:wait_build(1, UnitId.TerranStarport) + town:build(1, UnitId.TerranRotary, 69) + end) + melee_ai:dynamic_wait(secs(40) + secs(25) + secs(50)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(3, UnitId.TerranFulcrum, 70) + melee_ai:dynamic_wait(secs(45)) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Maverick core + Vulture / Phalanx / Salamander / Centaur + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranFulcrum, 70, true) + town:build(1, UnitId.TerranPalladium, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranStarport, 65, true) + town:build(1, UnitId.TerranRotary, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranNaniteAssembly, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/terran/general/two_fulcrum_mech.lua b/mpq/lua/melee/terran/general/two_fulcrum_mech.lua new file mode 100644 index 0000000..fdafbf7 --- /dev/null +++ b/mpq/lua/melee/terran/general/two_fulcrum_mech.lua @@ -0,0 +1,71 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "General: 2 Fulcrum Mech", + unit_composition = { + -- signature units (Mantle x2) + [UnitId.TerranPhalanxTankMode] = 2, + [UnitId.TerranRamesses] = 2, + [UnitId.TerranDurendal] = 2, + [UnitId.TerranCataphract] = 2, + -- filler units + [UnitId.TerranBlackjack] = 1, + [UnitId.TerranMadrigalImperiosoMode] = 1, + [UnitId.TerranCuirassTankMode] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.TerranFulcrum, 110) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(mins(1)) + town:build(3, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(secs(40)) + -- tier2 + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranScrapyard, 69) + town:wait_build(2, UnitId.TerranFulcrum) + town:build(2, UnitId.TerranScrapyard, 69) + town:wait_build(3, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranPalladium, 69) + town:wait_build(4, UnitId.TerranFulcrum) + town:build(2, UnitId.TerranPalladium, 69) + end) + melee_ai:dynamic_wait(secs(40) + secs(40)) + town:build(2, UnitId.TerranMantle, 70) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Mantle walkers (Ramesses / Durendal / Cataphract) + Phalanx / Blackjack / Cuirass + town:build(1, UnitId.TerranFulcrum, 70, true) + town:build(1, UnitId.TerranScrapyard, 68, true) + town:build(1, UnitId.TerranPalladium, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranMantle, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranIronFoundry, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/terran/orbital/aces_high.lua b/mpq/lua/melee/terran/orbital/aces_high.lua new file mode 100644 index 0000000..30d4377 --- /dev/null +++ b/mpq/lua/melee/terran/orbital/aces_high.lua @@ -0,0 +1,72 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Orbital: Aces High", + unit_composition = { + -- signature units + [UnitId.TerranVulture] = 3, + [UnitId.TerranWraith] = 3, + -- filler units + [UnitId.TerranBlackjack] = 1, + [UnitId.TerranCyclops] = 1, + [UnitId.TerranSalamander] = 1, + [UnitId.TerranCentaur] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranFulcrum, 110) + melee_ai:dynamic_wait(secs(20)) + town:build(2, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(secs(25)) + town:wait_build(2, UnitId.TerranFulcrum, false) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranFulcrum) + town:build(1, UnitId.TerranScrapyard, 89) + town:wait_build(2, UnitId.TerranFulcrum) + town:build(2, UnitId.TerranScrapyard, 89) + town:wait_build(3, UnitId.TerranFulcrum) + town:build(3, UnitId.TerranScrapyard, 89) + end) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(50)) + town:build(3, UnitId.TerranFulcrum, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(3, UnitId.TerranStarpad, 90) + melee_ai:dynamic_wait(mins(1) + secs(20)) + -- tier2/tier3 + town:build(1, UnitId.TerranAtlas, 70, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Vulture + Wraith aces (+ Blackjack / Cyclops / Salamander / Centaur) + town:build(1, UnitId.TerranFulcrum, 70, true) + town:build(1, UnitId.TerranScrapyard, 68, true) + town:build(1, UnitId.TerranStarpad, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranStarport, 65, true) + town:build(1, UnitId.TerranRotary, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranNaniteAssembly, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/terran/orbital/hotdrop.lua b/mpq/lua/melee/terran/orbital/hotdrop.lua new file mode 100644 index 0000000..af7f204 --- /dev/null +++ b/mpq/lua/melee/terran/orbital/hotdrop.lua @@ -0,0 +1,78 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Orbital: Hotdrop", + unit_composition = { + -- signature unit + [UnitId.TerranHarakan] = 3, + -- filler units + [UnitId.TerranWraith] = 1, + [UnitId.TerranSalamander] = 1, + [UnitId.TerranCentaur] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranStockade, 110) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranStarpad, 90) + melee_ai:dynamic_wait(secs(35)) + town:build(2, UnitId.TerranStarpad, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(2, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(20)) + town:build(3, UnitId.TerranStarpad, 90) + melee_ai:dynamic_wait(secs(35)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(15)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(40)) + town:wait_build(3, UnitId.TerranStarpad) + town:wait_build(2, UnitId.TerranStockade, false) + -- tier2 + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:multirun(function(town) + town:build(1, UnitId.TerranCovenant, 69) + town:wait_build(1, UnitId.TerranCovenant) + town:build(1, UnitId.TerranAnvil, 69) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranStarport, 70) + town:wait_build(1, UnitId.TerranStarport) + town:build(1, UnitId.TerranRotary, 69) + town:build(2, UnitId.TerranStarport, 70) + town:wait_build(2, UnitId.TerranStarport) + town:build(2, UnitId.TerranRotary, 69) + melee_ai:dynamic_wait(secs(50)) + end) + melee_ai:dynamic_wait(secs(40)) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Harakan drop force + Wraith / Salamander / Centaur support + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranStarpad, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranStarport, 65, true) + town:build(1, UnitId.TerranRotary, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranNaniteAssembly, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/terran/orbital/rapid_starpads.lua b/mpq/lua/melee/terran/orbital/rapid_starpads.lua new file mode 100644 index 0000000..c978893 --- /dev/null +++ b/mpq/lua/melee/terran/orbital/rapid_starpads.lua @@ -0,0 +1,75 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Orbital: 2 Starpad Wraith", + unit_composition = { + -- signature unit + [UnitId.TerranWraith] = 3, + -- filler units + [UnitId.TerranSalamander] = 1, + [UnitId.TerranAzazel] = 1, + [UnitId.TerranSeraph] = 1, + [UnitId.TerranCentaur] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.TerranStarpad, 110) + melee_ai:dynamic_wait(secs(50)) + town:build(2, UnitId.TerranStarpad, 90) + melee_ai:dynamic_wait(mins(1) + secs(5)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(mins(1) + secs(15)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(25)) + town:wait_build(2, UnitId.TerranStarpad) + town:build(2, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(20)) + town:build(3, UnitId.TerranStarpad, 90) + melee_ai:dynamic_wait(mins(2) + secs(5)) + -- tier2 + town:build(1, UnitId.TerranAtlas, 70, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranStarport, 70) + town:wait_build(1, UnitId.TerranStarport) + town:build(1, UnitId.TerranRotary, 69) + town:build(2, UnitId.TerranStarport, 70) + town:wait_build(2, UnitId.TerranStarport) + town:build(2, UnitId.TerranRotary, 69) + town:build(3, UnitId.TerranStarport, 70) + town:wait_build(3, UnitId.TerranStarport) + town:build(1, UnitId.TerranCommandment, 69) + end) + melee_ai:dynamic_wait(secs(40)) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Wraith fleet + Salamander / Azazel / Seraph gunships + town:build(1, UnitId.TerranStarpad, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranStarport, 65, true) + town:build(1, UnitId.TerranRotary, 65, true) + town:build(1, UnitId.TerranCommandment, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranNaniteAssembly, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/terran/orbital/sudden_starport.lua b/mpq/lua/melee/terran/orbital/sudden_starport.lua new file mode 100644 index 0000000..e46f41a --- /dev/null +++ b/mpq/lua/melee/terran/orbital/sudden_starport.lua @@ -0,0 +1,78 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Orbital: Sudden Starport", + unit_composition = { + -- signature units + [UnitId.TerranMaverick] = 2, + [UnitId.TerranSundog] = 2, + [UnitId.TerranSalamander] = 2, + -- healers + [UnitId.TerranCleric] = 1.5, + -- filler units + [UnitId.TerranCentaur] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranStockade, 110) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(40)) + town:build(2, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(20)) + town:build(3, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(15)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(50)) + town:wait_build(3, UnitId.TerranStockade, false) + -- tier2 + town:multirun(function(town) + town:wait_build(2, UnitId.TerranStockade) + town:build(1, UnitId.TerranVestry, 69) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranStarport, 70) + town:wait_build(1, UnitId.TerranStarport, false) + town:build(4, UnitId.TerranStarport, 70) + town:wait_build(1, UnitId.TerranStarport) + town:build(1, UnitId.TerranRotary, 69) + town:wait_build(2, UnitId.TerranStarport) + town:build(2, UnitId.TerranRotary, 69) + town:wait_build(3, UnitId.TerranStarport) + town:build(3, UnitId.TerranRotary, 69) + town:wait_build(4, UnitId.TerranStarport) + town:build(4, UnitId.TerranRotary, 69) + melee_ai:dynamic_wait(secs(15)) + end) + melee_ai:dynamic_wait(mins(1) + secs(15)) + town:build(1, UnitId.TerranAtlas, 70, true) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Maverick + Sundog / Salamander army (+ Cleric / Centaur) + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranVestry, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranStarport, 65, true) + town:build(1, UnitId.TerranRotary, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranNaniteAssembly, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/terran/orbital/the_don.lua b/mpq/lua/melee/terran/orbital/the_don.lua new file mode 100644 index 0000000..9e7d24d --- /dev/null +++ b/mpq/lua/melee/terran/orbital/the_don.lua @@ -0,0 +1,56 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Orbital: The Don", + unit_composition = { + -- signature units (Nanite Assembly x3) + [UnitId.TerranMinotaur] = 2, + [UnitId.TerranCentaur] = 2, + [UnitId.TerranMagnetar] = 2, + -- filler units + [UnitId.TerranGorgon] = 1, + [UnitId.TerranWraith] = 0.5, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + melee_ai:dynamic_wait(secs(50)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(mins(1)) + town:wait_build(1, UnitId.TerranStockade) + melee_ai:dynamic_wait(secs(40)) + -- tier2 + town:build(1, UnitId.TerranAtlas, 70, true) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(2, UnitId.TerranNaniteAssembly, 50) + melee_ai:dynamic_wait(secs(20)) + town:build(3, UnitId.TerranNaniteAssembly, 50) + melee_ai:dynamic_wait(secs(20)) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Nanite Assembly capital fleet (+ Gorgon / Wraith) + town:build(1, UnitId.TerranStarpad, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranStarport, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranNaniteAssembly, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/terran/orbital/wraith_bio.lua b/mpq/lua/melee/terran/orbital/wraith_bio.lua new file mode 100644 index 0000000..b7b6cfd --- /dev/null +++ b/mpq/lua/melee/terran/orbital/wraith_bio.lua @@ -0,0 +1,65 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Orbital: Wraith Bio", + unit_composition = { + -- signature units + [UnitId.TerranMaverick] = 3, + [UnitId.TerranWraith] = 3, + -- filler units + [UnitId.TerranValkyrie] = 1, + [UnitId.TerranSalamander] = 1, + [UnitId.TerranCentaur] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranStockade, 110) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranStarpad, 90) + melee_ai:dynamic_wait(secs(15)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(40)) + town:build(2, UnitId.TerranStarpad, 90) + melee_ai:dynamic_wait(secs(5)) + town:build(2, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(3, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(5)) + melee_ai:start_attacking() + -- tier1 + melee_ai:dynamic_wait(secs(40)) + town:wait_build(3, UnitId.TerranStockade, false) + town:build(1, UnitId.TerranVestry, 89) + melee_ai:dynamic_wait(mins(1) + secs(15)) + -- tier2/tier3 + town:build(1, UnitId.TerranAtlas, 70, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Maverick + Wraith bio-air army (+ Valkyrie / Salamander / Centaur) + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranStarpad, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranStarport, 65, true) + town:build(1, UnitId.TerranRotary, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranNaniteAssembly, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/terran/raider/eight_rax.lua b/mpq/lua/melee/terran/raider/eight_rax.lua new file mode 100644 index 0000000..e53b5b6 --- /dev/null +++ b/mpq/lua/melee/terran/raider/eight_rax.lua @@ -0,0 +1,72 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Raider: 8Rax", + unit_composition = { + -- signature unit + [UnitId.TerranMaverick] = 3, + -- healers + [UnitId.TerranCleric] = 1.5, + -- filler units + [UnitId.TerranHarakan] = 1, + [UnitId.TerranCyprian] = 1, + [UnitId.TerranMadcap] = 1, + [UnitId.TerranDilettante] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + melee_ai:build_and_wait(town, 1, UnitId.TerranStockade, 110, secs(15)) + melee_ai:build_sequence(town, 2, 6, UnitId.TerranStockade, 110, 0, secs(15), 0) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(15)) + town:wait_build(6, UnitId.TerranStockade, false) + melee_ai:dynamic_wait(mins(1) + secs(15)) + melee_ai:start_expanding() + -- tier1 scale-up + melee_ai:dynamic_wait(secs(40)) + melee_ai:build_and_wait(town, 8, UnitId.TerranStockade, 90, secs(50)) + -- tier2 + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(15)) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranStockade) + town:build(1, UnitId.TerranVestry, 69) + town:wait_build(2, UnitId.TerranStockade) + town:build(2, UnitId.TerranVestry, 69) + town:wait_build(3, UnitId.TerranStockade) + town:build(1, UnitId.TerranCovenant, 69) + town:wait_build(4, UnitId.TerranStockade) + town:build(2, UnitId.TerranCovenant, 69) + end) + melee_ai:dynamic_wait(secs(25)) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + + -- production for the Maverick-heavy raid (+ Cleric / Madcap / Dilettante) + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranVestry, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranCaptaincy, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranApothecary, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/terran/raider/fast_anvil.lua b/mpq/lua/melee/terran/raider/fast_anvil.lua new file mode 100644 index 0000000..c3f5ee0 --- /dev/null +++ b/mpq/lua/melee/terran/raider/fast_anvil.lua @@ -0,0 +1,77 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Raider: Fast Anvil", + unit_composition = { + -- signature units + [UnitId.TerranCyprian] = 2, + [UnitId.TerranEidolon] = 2, + -- filler units + [UnitId.TerranMaverick] = 1, + [UnitId.TerranMadcap] = 1, + [UnitId.TerranDilettante] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranStockade, 110) + melee_ai:dynamic_wait(secs(40)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(3, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(40)) + town:wait_build(3, UnitId.TerranStockade, false) + melee_ai:dynamic_wait(secs(25)) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranStockade) + town:build(1, UnitId.TerranVestry, 89) + town:wait_build(2, UnitId.TerranStockade) + town:build(1, UnitId.TerranCovenant, 89) + town:wait_build(1, UnitId.TerranCovenant, false) + town:build(1, UnitId.TerranAnvil, 89) + town:wait_build(3, UnitId.TerranStockade) + town:wait_build(1, UnitId.TerranAnvil, false) + town:build(2, UnitId.TerranCovenant, 89) + town:wait_build(4, UnitId.TerranStockade) + town:build(3, UnitId.TerranCovenant, 89) + end) + melee_ai:dynamic_wait(secs(25)) + -- tier2 + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(15)) + town:build(4, UnitId.TerranStockade, 70) + melee_ai:dynamic_wait(secs(40)) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Cyprian + Eidolon anvil raid (+ Madcap / Dilettante) + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranCovenant, 68, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranAnvil, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranCaptaincy, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranApothecary, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/terran/raider/four_rax_pressure.lua b/mpq/lua/melee/terran/raider/four_rax_pressure.lua new file mode 100644 index 0000000..0e2ef9a --- /dev/null +++ b/mpq/lua/melee/terran/raider/four_rax_pressure.lua @@ -0,0 +1,71 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Raider: 4Rax Pressure", + unit_composition = { + -- healers + [UnitId.TerranShamanSupportMode] = 2, + -- filler units + [UnitId.TerranSavantEntropyGauntlets] = 1, + [UnitId.TerranCyprian] = 1, + [UnitId.TerranMadcap] = 1, + [UnitId.TerranDilettante] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranStockade, 110) + melee_ai:dynamic_wait(secs(20)) + town:build(2, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(20)) + town:build(3, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(20)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(mins(1)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(30)) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranStockade) + town:build(1, UnitId.TerranVestry, 89) + town:wait_build(2, UnitId.TerranStockade) + town:build(2, UnitId.TerranVestry, 89) + town:wait_build(3, UnitId.TerranStockade) + town:build(1, UnitId.TerranCovenant, 89) + town:wait_build(4, UnitId.TerranStockade) + town:build(2, UnitId.TerranCovenant, 89) + end) + melee_ai:dynamic_wait(secs(5)) + town:wait_build(4, UnitId.TerranStockade) + melee_ai:dynamic_wait(mins(1)) + -- tier2/tier3 + town:build(1, UnitId.TerranAtlas, 70, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Shaman + Savant support raid (+ Cyprian / Madcap / Dilettante) + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranVestry, 68, true) + town:build(1, UnitId.TerranCovenant, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranCaptaincy, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranApothecary, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/terran/raider/holy_ackmeds.lua b/mpq/lua/melee/terran/raider/holy_ackmeds.lua new file mode 100644 index 0000000..fbe2ec4 --- /dev/null +++ b/mpq/lua/melee/terran/raider/holy_ackmeds.lua @@ -0,0 +1,70 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Raider: Holy Ackmeds!", + unit_composition = { + -- signature unit + [UnitId.TerranHarakan] = 3, + -- filler units + [UnitId.TerranSundog] = 1, + [UnitId.TerranSalamander] = 1, + [UnitId.TerranDilettante] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranStockade, 110) + melee_ai:dynamic_wait(secs(45)) + town:build(2, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(25)) + town:build(3, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(25)) + town:build(4, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(15)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(40)) + town:wait_build(4, UnitId.TerranStockade, false) + melee_ai:dynamic_wait(mins(1) + secs(40)) + -- tier2 + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(5)) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranStockade) + town:build(1, UnitId.TerranVestry, 69) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranStarport, 70) + town:wait_build(1, UnitId.TerranStarport) + town:build(1, UnitId.TerranRotary, 69) + end) + melee_ai:dynamic_wait(secs(15)) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Harakan raid + Sundog / Salamander gunships + town:build(1, UnitId.TerranStockade, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranStarport, 65, true) + town:build(1, UnitId.TerranRotary, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranApothecary, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/terran/raider/three_rax_bio.lua b/mpq/lua/melee/terran/raider/three_rax_bio.lua new file mode 100644 index 0000000..5742b85 --- /dev/null +++ b/mpq/lua/melee/terran/raider/three_rax_bio.lua @@ -0,0 +1,65 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Raider: 3Rax Maverick & Cleric", + unit_composition = { + -- signature units + [UnitId.TerranMaverick] = 3, + -- healers + [UnitId.TerranCleric] = 2, + -- filler units + [UnitId.TerranEidolon] = 1, + [UnitId.TerranMadcap] = 1, + [UnitId.TerranDilettante] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranStockade, 110) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(mins(1) + secs(5)) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranStockade) + town:build(1, UnitId.TerranVestry, 89) + town:wait_build(2, UnitId.TerranStockade) + town:build(2, UnitId.TerranVestry, 89) + end) + melee_ai:dynamic_wait(secs(20)) + town:build(3, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(10)) + town:wait_build(3, UnitId.TerranStockade, false) + melee_ai:start_expanding() + melee_ai:dynamic_wait(mins(1) + secs(40)) + -- tier2 + town:build(1, UnitId.TerranAtlas, 70, true) + -- tier3 + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Maverick + Cleric bio raid (+ Eidolon / Madcap / Dilettante) + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranVestry, 68, true) + town:build(1, UnitId.TerranCovenant, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranCaptaincy, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranApothecary, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/terran/raider/uprising.lua b/mpq/lua/melee/terran/raider/uprising.lua new file mode 100644 index 0000000..07f1bd4 --- /dev/null +++ b/mpq/lua/melee/terran/raider/uprising.lua @@ -0,0 +1,67 @@ +local Basic = require "melee.terran.basic" + +---@type AIPersonality +return { + name = "Raider: Uprising", + unit_composition = { + -- signature units + [UnitId.TerranCyprian] = 3, + -- healers + [UnitId.TerranCleric] = 1.5, + -- filler units + [UnitId.TerranEidolon] = 1, + [UnitId.TerranMadcap] = 1, + [UnitId.TerranDilettante] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.TerranStockade, 110) + -- tier1 + melee_ai:dynamic_wait(secs(20)) + town:build(2, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(20)) + town:build(3, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(20)) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranStockade) + town:build(1, UnitId.TerranVestry, 89) + town:wait_build(4, UnitId.TerranStockade) + town:build(2, UnitId.TerranVestry, 89) + end) + melee_ai:dynamic_wait(secs(15)) + town:build(4, UnitId.TerranStockade, 90) + melee_ai:dynamic_wait(secs(20)) + town:wait_build(4, UnitId.TerranStockade) + town:wait_build(2, UnitId.TerranVestry) + melee_ai:dynamic_wait(mins(1) + secs(40)) + -- tier2/tier3 + town:build(1, UnitId.TerranAtlas, 70, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + -- production for the Cyprian-heavy raid (+ Cleric / Eidolon / Madcap / Dilettante) + town:build(1, UnitId.TerranStockade, 70, true) + town:build(1, UnitId.TerranVestry, 68, true) + town:build(1, UnitId.TerranCovenant, 68, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.TerranAtlas, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.TerranCaptaincy, 65, true) + town:multirun(function(town) + town:wait_build(1, UnitId.TerranAtlas) + town:build(1, UnitId.TerranDaedala, 65, true) + end) + town:wait_build(1, UnitId.TerranDaedala) + town:build(1, UnitId.TerranApothecary, 65, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/zerg/assault/earthen_tides.lua b/mpq/lua/melee/zerg/assault/earthen_tides.lua new file mode 100644 index 0000000..52c6601 --- /dev/null +++ b/mpq/lua/melee/zerg/assault/earthen_tides.lua @@ -0,0 +1,104 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Assault: Earthen Tides", + unit_composition = { + -- signature units + [UnitId.ZergIzirokor] = 2, + [UnitId.ZergLakizilisk] = 2, + [UnitId.ZergProtathalor] = 2, + -- filler units + [UnitId.ZergSovroleth] = 1, + [UnitId.ZergKeskathalor] = 1, + [UnitId.ZergSkithrokor] = 1, + [UnitId.ZergBactalisk] = 1, + [UnitId.ZergNathrokor] = 1, + [UnitId.ZergVorvrokor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergHydrithDen, 110, true) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(45)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(30)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergZorkizShroud, 90, true) + melee_ai:dynamic_wait(mins(1) + secs(30)) + town:build(1, UnitId.ZergSkibactScab, 90, true) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + melee_ai:dynamic_wait(secs(50)) + -- tier2 + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(40)) + town:build(3, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(25)) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(1, UnitId.ZergMutathSpire, 70, true) + melee_ai:dynamic_wait(mins(1)) + town:build(1, UnitId.ZergMatravilNest, 70, true) + end) + melee_ai:dynamic_wait(mins(2) + secs(5)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Earthen Tides army (Izirokor / Lakizilisk / Protathalor) + town:build(1, UnitId.ZergHydrithDen, 70, true) + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergVornathPond, 70, true) + town:build(1, UnitId.ZergSkibactScab, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergTosvrolHaunt, 70, true) + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergGeszkathGrotto, 50, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/zerg/assault/potency.lua b/mpq/lua/melee/zerg/assault/potency.lua new file mode 100644 index 0000000..4f70ce2 --- /dev/null +++ b/mpq/lua/melee/zerg/assault/potency.lua @@ -0,0 +1,104 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Assault: Potency", + unit_composition = { + -- signature units + [UnitId.ZergZoryusthaleth] = 2, + [UnitId.ZergHydralisk] = 2, + [UnitId.ZergKalkalisk] = 2, + -- filler units + [UnitId.ZergMutalisk] = 1, + [UnitId.ZergKagralisk] = 1, + [UnitId.ZergSovroleth] = 1, + [UnitId.ZergEvigrilisk] = 1, + [UnitId.ZergAlmaksalisk] = 1, + [UnitId.ZergSkithrokor] = 1, + [UnitId.ZergBactalisk] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergHydrithDen, 110, true) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(45)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(30)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergZorkizShroud, 90, true) + melee_ai:dynamic_wait(mins(1) + secs(30)) + town:build(1, UnitId.ZergSkibactScab, 90, true) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + melee_ai:dynamic_wait(secs(50)) + -- tier2 + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(40)) + town:build(3, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(25)) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergHydrithDen) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergTethvithSwamp, 70, true) + town:wait_build(1, UnitId.ZergIrolIris) + melee_ai:dynamic_wait(mins(1)) + town:build(1, UnitId.ZergAlkagIteth, 70, true) + end) + melee_ai:dynamic_wait(secs(25)) + town:build(4, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(mins(1) + secs(40)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the broad Potency army (Zorkiz / Hydra / Kalkiir / Alkag / Mutath) + town:build(1, UnitId.ZergHydrithDen, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + town:build(1, UnitId.ZergTethvithSwamp, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + town:build(1, UnitId.ZergAlkagIteth, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergTosvrolHaunt, 70, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/zerg/assault/three_base_hydrith.lua b/mpq/lua/melee/zerg/assault/three_base_hydrith.lua new file mode 100644 index 0000000..4352082 --- /dev/null +++ b/mpq/lua/melee/zerg/assault/three_base_hydrith.lua @@ -0,0 +1,89 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Assault: 3 Base Hydrith", + unit_composition = { + -- signature units + [UnitId.ZergHydralisk] = 3, + [UnitId.ZergZethrokor] = 2, + [UnitId.ZergUltrokor] = 2, + -- filler units + [UnitId.ZergKalkalisk] = 1, + [UnitId.ZergSovroleth] = 1, + [UnitId.ZergSkithrokor] = 1, + [UnitId.ZergBactalisk] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(5)) + town:build(1, UnitId.ZergHydrithDen, 90, true) + -- tier1 + melee_ai:dynamic_wait(mins(1) + secs(30)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergSkibactScab, 90, true) + melee_ai:dynamic_wait(secs(40)) + -- tier2 + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(15)) + town:build(3, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + melee_ai:dynamic_wait(secs(25)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + town:build(4, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Hydralisk / Zethrokor / Ultrokor assault army + town:build(1, UnitId.ZergHydrithDen, 70, true) + town:build(1, UnitId.ZergQuazethPool, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergTosvrolHaunt, 70, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/zerg/assault/two_base_alkag.lua b/mpq/lua/melee/zerg/assault/two_base_alkag.lua new file mode 100644 index 0000000..d2d0f73 --- /dev/null +++ b/mpq/lua/melee/zerg/assault/two_base_alkag.lua @@ -0,0 +1,81 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Assault: 2 Base Alkag", + unit_composition = { + -- signature units (Alkag Iteth) + [UnitId.ZergKagralisk] = 2, + [UnitId.ZergEvigrilisk] = 2, + [UnitId.ZergAlmaksalisk] = 2, + -- filler units + [UnitId.ZergSkithrokor] = 1, + [UnitId.ZergBactalisk] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(25)) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergHydrithDen) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergSkibactScab, 90, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergTethvithSwamp, 90, true) + town:wait_build(1, UnitId.ZergIrolIris) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ZergAlkagIteth, 90, true) + town:build(1, UnitId.ZergOthstolOviform, 90, true) + end) + town:build(1, UnitId.ZergHydrithDen, 90, true) + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_expanding() + -- tier2 + melee_ai:dynamic_wait(secs(55)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(15)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(mins(1) + secs(5)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Alkag Iteth army (Kagralisk / Evigrilisk / Almaksalisk) + town:build(1, UnitId.ZergHydrithDen, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + town:build(1, UnitId.ZergTethvithSwamp, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergAlkagIteth, 70, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/zerg/assault/two_base_hydrith_quazeth.lua b/mpq/lua/melee/zerg/assault/two_base_hydrith_quazeth.lua new file mode 100644 index 0000000..8b19b49 --- /dev/null +++ b/mpq/lua/melee/zerg/assault/two_base_hydrith_quazeth.lua @@ -0,0 +1,81 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Assault: 2 Base Hydrith-Quazeth", + unit_composition = { + -- signature units + [UnitId.ZergHydralisk] = 3, + [UnitId.ZergZethrokor] = 2, + [UnitId.ZergUltrokor] = 2, + -- filler units + [UnitId.ZergQuazilisk] = 1, + [UnitId.ZergZoryusthaleth] = 1, + [UnitId.ZergNathrokor] = 1, + [UnitId.ZergVorvrokor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(5)) + town:build(1, UnitId.ZergHydrithDen, 90, true) + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_attacking() + -- tier1 + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + melee_ai:dynamic_wait(secs(50)) + -- tier2 + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(15)) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(mins(1)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + end) + melee_ai:dynamic_wait(secs(15)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Hydralisk / Zethrokor / Ultrokor / Vornath army + town:build(1, UnitId.ZergHydrithDen, 70, true) + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergVornathPond, 70, true) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/zerg/assault/two_base_zorkiz.lua b/mpq/lua/melee/zerg/assault/two_base_zorkiz.lua new file mode 100644 index 0000000..927449b --- /dev/null +++ b/mpq/lua/melee/zerg/assault/two_base_zorkiz.lua @@ -0,0 +1,80 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Assault: 2 Base Hydrith-Zorkiz", + unit_composition = { + -- signature units + [UnitId.ZergHydralisk] = 3, + [UnitId.ZergUltrokor] = 2, + [UnitId.ZergZoryusthaleth] = 2, + -- filler units + [UnitId.ZergIzirokor] = 1, + [UnitId.ZergKalkalisk] = 1, + [UnitId.ZergSovroleth] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(5)) + town:build(1, UnitId.ZergHydrithDen, 90, true) + -- tier1 + melee_ai:dynamic_wait(secs(55)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(15)) + -- tier2 + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(35)) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ZergTethvithSwamp, 70, true) + town:build(1, UnitId.ZergCaphrolosk, 70) + melee_ai:dynamic_wait(secs(45)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Hydralisk / Ultrokor / Zoryusthaleth assault army + town:build(1, UnitId.ZergHydrithDen, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergTosvrolHaunt, 70, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/zerg/basic.lua b/mpq/lua/melee/zerg/basic.lua new file mode 100644 index 0000000..931880b --- /dev/null +++ b/mpq/lua/melee/zerg/basic.lua @@ -0,0 +1,17 @@ +local Basic = {} + +---@type BuildOrder +function Basic.build_anti_ground(melee_ai, town) + melee_ai:build_sequence(town, 1, 3, UnitId.ZergSurkithCesiant, 80, 5, secs(25), secs(5)) + melee_ai:wait_can_make(UnitId.ZergSkortrithCesiant) + melee_ai:build_sequence(town, 1, 3, UnitId.ZergSkortrithCesiant, 80, 5, secs(25), secs(5)) +end + +---@type BuildOrder +function Basic.build_anti_air(melee_ai, town) + melee_ai:build_sequence(town, 1, 3, UnitId.ZergSpraithCesiant, 80, 5, secs(25), secs(5)) + melee_ai:wait_can_make(UnitId.ZergSpirtithCesiant) + melee_ai:build_sequence(town, 1, 3, UnitId.ZergSpirtithCesiant, 80, 5, secs(25), secs(5)) +end + +return Basic diff --git a/mpq/lua/melee/zerg/general/before_the_storm.lua b/mpq/lua/melee/zerg/general/before_the_storm.lua new file mode 100644 index 0000000..d0f77b2 --- /dev/null +++ b/mpq/lua/melee/zerg/general/before_the_storm.lua @@ -0,0 +1,96 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "General: Before the Storm", + unit_composition = { + -- signature units + [UnitId.ZergZethrokor] = 2, + [UnitId.ZergKalkalisk] = 2, + -- filler units + [UnitId.ZergZoryusthaleth] = 1, + [UnitId.ZergMutalisk] = 1, + [UnitId.ZergGeszithalor] = 1, + [UnitId.ZergNathrokor] = 1, + [UnitId.ZergVorvrokor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergQuazethPool, 110, true) + town:wait_build(1, UnitId.ZergQuazethPool, false) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergDroleth, 100) + melee_ai:dynamic_wait(secs(50)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergZorkizShroud, 90, true) + melee_ai:dynamic_wait(secs(15)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(mins(2) + secs(30)) + -- tier2 + town:multirun(function(town) + town:build(1, UnitId.ZergIrolIris, 70, true) + end) + melee_ai:dynamic_wait(secs(15)) + town:build(3, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(15)) + town:build(4, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(15)) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + end) + melee_ai:dynamic_wait(secs(30)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Zethrokor / Kalkalisk army + Mutalisk / Geszithalor + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergGeszkathGrotto, 50, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/zerg/general/constrained_coil.lua b/mpq/lua/melee/zerg/general/constrained_coil.lua new file mode 100644 index 0000000..c5504c5 --- /dev/null +++ b/mpq/lua/melee/zerg/general/constrained_coil.lua @@ -0,0 +1,86 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "General: Constrained Coil", + unit_composition = { + -- signature units + [UnitId.ZergZethrokor] = 2, + [UnitId.ZergKalkalisk] = 2, + -- filler units + [UnitId.ZergZoryusthaleth] = 1, + [UnitId.ZergMutalisk] = 1, + [UnitId.ZergGeszithalor] = 1, + [UnitId.ZergNathrokor] = 1, + [UnitId.ZergVorvrokor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergQuazethPool, 110, true) + town:wait_build(1, UnitId.ZergQuazethPool, false) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergDroleth, 100) + melee_ai:dynamic_wait(secs(1)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergHydrithDen, 90, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergVornathPond, 90, true) + melee_ai:dynamic_wait(mins(1)) + -- tier2 + town:multirun(function(town) + town:build(1, UnitId.ZergIrolIris, 70, true) + end) + melee_ai:dynamic_wait(mins(1) + secs(35)) + town:build(2, UnitId.ZergHachirosk, 115) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the constrained Zethrokor / Kalkalisk army + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergGeszkathGrotto, 50, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/zerg/general/shrieking_swarm.lua b/mpq/lua/melee/zerg/general/shrieking_swarm.lua new file mode 100644 index 0000000..92650a6 --- /dev/null +++ b/mpq/lua/melee/zerg/general/shrieking_swarm.lua @@ -0,0 +1,95 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "General: Shrieking Swarm", + unit_composition = { + -- signature units (Vornath Pond) + [UnitId.ZergVorvrokor] = 2, + [UnitId.ZergNathrokor] = 2, + -- filler units + [UnitId.ZergUltrokor] = 1, + [UnitId.ZergHydralisk] = 1, + [UnitId.ZergLakizilisk] = 1, + [UnitId.ZergSovroleth] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(45)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + melee_ai:dynamic_wait(secs(40)) + melee_ai:start_attacking() + -- tier1 + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergVornathPond, 90, true) + melee_ai:dynamic_wait(secs(40)) + -- tier2 + town:multirun(function(town) + town:build(1, UnitId.ZergIrolIris, 70, true) + end) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + end) + melee_ai:dynamic_wait(mins(1)) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergCaphrolosk, 70) + melee_ai:dynamic_wait(secs(30)) + town:build(3, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(15)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Vornath-centric army (+ Ultrokor / Hydralisk / Zorkiz) + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + town:build(1, UnitId.ZergHydrithDen, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergVornathPond, 70, true) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergTosvrolHaunt, 70, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/zerg/general/sleeping_giant.lua b/mpq/lua/melee/zerg/general/sleeping_giant.lua new file mode 100644 index 0000000..5c8ebeb --- /dev/null +++ b/mpq/lua/melee/zerg/general/sleeping_giant.lua @@ -0,0 +1,107 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "General: Sleeping Giant", + unit_composition = { + -- signature units + [UnitId.ZergZethrokor] = 2, + [UnitId.ZergUltrokor] = 2, + [UnitId.ZergHydralisk] = 2, + -- filler units + [UnitId.ZergKalkalisk] = 1, + [UnitId.ZergZoryusthaleth] = 1, + [UnitId.ZergMutalisk] = 1, + [UnitId.ZergNathrokor] = 1, + [UnitId.ZergVorvrokor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(45)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + -- tier1 + melee_ai:dynamic_wait(mins(1)) + town:wait_build(15, UnitId.ZergDroleth) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ZergVornathPond, 90, true) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(25)) + -- tier2 + town:multirun(function(town) + town:build(1, UnitId.ZergIrolIris, 70, true) + end) + melee_ai:dynamic_wait(secs(20)) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(1, UnitId.ZergCaphrolosk, 70) + melee_ai:dynamic_wait(secs(30)) + town:build(3, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:dynamic_wait(mins(1)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(1, UnitId.ZergMatravilNest, 70, true) + melee_ai:dynamic_wait(mins(1)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + melee_ai:dynamic_wait(mins(2) + secs(45)) + town:build(1, UnitId.ZergTosvrolHaunt, 70, true) + end) + melee_ai:dynamic_wait(secs(25)) + -- tier3 + town:multirun(function(town) + town:build(1, UnitId.ZergOthstolOviform, 65, true) + end) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ZergGathtelosk, 50) + melee_ai:dynamic_wait(secs(15)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Zethrokor / Ultrokor / Hydralisk army + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + town:build(1, UnitId.ZergHydrithDen, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergVornathPond, 70, true) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/zerg/general/subjugation.lua b/mpq/lua/melee/zerg/general/subjugation.lua new file mode 100644 index 0000000..73779a6 --- /dev/null +++ b/mpq/lua/melee/zerg/general/subjugation.lua @@ -0,0 +1,100 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "General: Subjugation", + unit_composition = { + -- signature units (Skibact Scab) + [UnitId.ZergSkithrokor] = 2, + [UnitId.ZergBactalisk] = 2, + [UnitId.ZergZethrokor] = 2, + -- filler units + [UnitId.ZergKeskathalor] = 1, + [UnitId.ZergHydralisk] = 1, + [UnitId.ZergZoryusthaleth] = 1, + [UnitId.ZergVithrilisk] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(45)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergDroleth, 100) + melee_ai:dynamic_wait(secs(5)) + town:build(1, UnitId.ZergHydrithDen, 90, true) + -- tier1 + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergSkibactScab, 90, true) + melee_ai:dynamic_wait(secs(45)) + -- tier2 + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergQuazethPool, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:multirun(function(town) + town:build(1, UnitId.ZergIrolIris, 70, true) + end) + melee_ai:dynamic_wait(secs(50)) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergHydrithDen) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergTethvithSwamp, 70, true) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(1, UnitId.ZergMatravilNest, 70, true) + end) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ZergCaphrolosk, 70) + town:build(3, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Skibact / Zethrokor army + Keskathalor tech + town:build(1, UnitId.ZergHydrithDen, 70, true) + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + town:build(1, UnitId.ZergTethvithSwamp, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergGeszkathGrotto, 50, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/zerg/general/time_after_time.lua b/mpq/lua/melee/zerg/general/time_after_time.lua new file mode 100644 index 0000000..2f7a3cf --- /dev/null +++ b/mpq/lua/melee/zerg/general/time_after_time.lua @@ -0,0 +1,94 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "General: Time After Time", + unit_composition = { + -- signature units + [UnitId.ZergZethrokor] = 2, + [UnitId.ZergSkithrokor] = 2, + [UnitId.ZergLakizilisk] = 2, + -- filler units + [UnitId.ZergLiiralisk] = 1, + [UnitId.ZergCikralisk] = 1, + [UnitId.ZergBactalisk] = 1, + [UnitId.ZergNathrokor] = 1, + [UnitId.ZergVorvrokor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(45)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergHydrithDen, 90, true) + melee_ai:dynamic_wait(secs(40)) + melee_ai:start_attacking() + -- tier1 + melee_ai:dynamic_wait(mins(1) + secs(15)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + melee_ai:dynamic_wait(mins(1) + secs(15)) + town:build(1, UnitId.ZergSkibactScab, 90, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergZorkizShroud, 90, true) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(50)) + -- tier2 + town:multirun(function(town) + town:build(1, UnitId.ZergIrolIris, 70, true) + end) + melee_ai:dynamic_wait(secs(15)) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + end) + melee_ai:dynamic_wait(secs(30)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Zethrokor / Skithrokor / Lakizilisk army + town:build(1, UnitId.ZergHydrithDen, 70, true) + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.5, +} diff --git a/mpq/lua/melee/zerg/sunblot/big_and_little.lua b/mpq/lua/melee/zerg/sunblot/big_and_little.lua new file mode 100644 index 0000000..1bbc2c1 --- /dev/null +++ b/mpq/lua/melee/zerg/sunblot/big_and_little.lua @@ -0,0 +1,107 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Sunblot: Big and Little", + unit_composition = { + -- signature units + [UnitId.ZergNathrokor] = 2, + [UnitId.ZergMutalisk] = 2, + [UnitId.ZergGorgrokor] = 2, + -- filler units + [UnitId.ZergGeszithalor] = 1, + [UnitId.ZergVilgorokor] = 1, + [UnitId.ZergSovroleth] = 1, + [UnitId.ZergVorvrokor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + melee_ai:dynamic_wait(secs(15)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergVornathPond, 90, true) + melee_ai:dynamic_wait(secs(45)) + melee_ai:start_attacking() + -- tier1 + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergZorkizShroud, 90, true) + melee_ai:dynamic_wait(mins(1) + secs(55)) + -- tier2 + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(1)) + town:multirun(function(town) + melee_ai:dynamic_wait(secs(1)) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + town:wait_build(1, UnitId.ZergZorkizShroud) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(1, UnitId.ZergMutathSpire, 70, true) + town:wait_build(1, UnitId.ZergMutathSpire) + melee_ai:dynamic_wait(mins(3) + secs(20)) + town:build(1, UnitId.ZergTosvrolHaunt, 70, true) + end) + melee_ai:dynamic_wait(mins(1) + secs(15)) + town:build(1, UnitId.ZergCaphrolosk, 70) + melee_ai:dynamic_wait(mins(1) + secs(45)) + town:build(3, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(30)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Nathrokor / Mutalisk / Gorgrokor flyer army + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergVornathPond, 70, true) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + town:build(1, UnitId.ZergMatravilNest, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergTosvrolHaunt, 70, true) + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergGeszkathGrotto, 50, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/zerg/sunblot/descending_horizon.lua b/mpq/lua/melee/zerg/sunblot/descending_horizon.lua new file mode 100644 index 0000000..c5688ba --- /dev/null +++ b/mpq/lua/melee/zerg/sunblot/descending_horizon.lua @@ -0,0 +1,107 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Sunblot: Descending Horizon", + unit_composition = { + -- signature units (Skibact Scab) + [UnitId.ZergSkithrokor] = 2, + [UnitId.ZergBactalisk] = 2, + -- filler units + [UnitId.ZergGorgrokor] = 1, + [UnitId.ZergMutalisk] = 1, + [UnitId.ZergGeszithalor] = 1, + [UnitId.ZergNathrokor] = 1, + [UnitId.ZergVorvrokor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergQuazethPool, 110, true) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(mins(1) + secs(50)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergVornathPond, 90, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergHydrithDen, 90, true) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(mins(1)) + -- tier2 + town:build(1, UnitId.ZergIrolIris, 70, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergHydrithDen) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergTethvithSwamp, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:wait_build(1, UnitId.ZergQuazethPool) + town:build(1, UnitId.ZergVornathPond, 70, true) + town:wait_build(1, UnitId.ZergVornathPond) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(1, UnitId.ZergMutathSpire, 70, true) + town:wait_build(1, UnitId.ZergMutathSpire) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergTosvrolHaunt, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergMatravilNest, 70, true) + end) + melee_ai:dynamic_wait(mins(2)) + -- tier3 + town:multirun(function(town) + melee_ai:dynamic_wait(mins(1) + secs(15)) + town:build(1, UnitId.ZergOthstolOviform, 65, true) + end) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Skibact horizon army + Nathrokor flyer support + town:build(1, UnitId.ZergHydrithDen, 70, true) + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + town:build(1, UnitId.ZergVornathPond, 70, true) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergGeszkathGrotto, 50, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/zerg/sunblot/early_birds.lua b/mpq/lua/melee/zerg/sunblot/early_birds.lua new file mode 100644 index 0000000..c3b1662 --- /dev/null +++ b/mpq/lua/melee/zerg/sunblot/early_birds.lua @@ -0,0 +1,93 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Sunblot: Early Birds", + unit_composition = { + -- signature units (Alkag Iteth) + [UnitId.ZergKagralisk] = 2, + [UnitId.ZergEvigrilisk] = 2, + [UnitId.ZergAlmaksalisk] = 2, + -- filler units + [UnitId.ZergNathrokor] = 1, + [UnitId.ZergGorgrokor] = 1, + [UnitId.ZergMutalisk] = 1, + [UnitId.ZergGeszithalor] = 1, + [UnitId.ZergVorvrokor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(mins(1) + secs(25)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + -- tier1 + melee_ai:dynamic_wait(secs(55)) + town:build(1, UnitId.ZergVornathPond, 90, true) + melee_ai:dynamic_wait(secs(25)) + -- tier2 + town:build(1, UnitId.ZergIrolIris, 70, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + town:wait_build(1, UnitId.ZergIrolIris) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergAlkagIteth, 70, true) + end) + melee_ai:dynamic_wait(mins(1) + secs(30)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(mins(1) + secs(15)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Alkag Iteth army + Nathrokor / Mutalisk flyers + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergVornathPond, 70, true) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + town:build(1, UnitId.ZergAlkagIteth, 70, true) + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergGeszkathGrotto, 50, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/zerg/sunblot/flying_feint.lua b/mpq/lua/melee/zerg/sunblot/flying_feint.lua new file mode 100644 index 0000000..3dffde8 --- /dev/null +++ b/mpq/lua/melee/zerg/sunblot/flying_feint.lua @@ -0,0 +1,102 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Sunblot: Flying Feint", + unit_composition = { + -- signature units + [UnitId.ZergNathrokor] = 2, + [UnitId.ZergSkithrokor] = 2, + -- filler units + [UnitId.ZergGorgrokor] = 1, + [UnitId.ZergMutalisk] = 1, + [UnitId.ZergBactalisk] = 1, + [UnitId.ZergGeszithalor] = 1, + [UnitId.ZergVorvrokor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergQuazethPool, 110, true) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(mins(1)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(40)) + -- tier2 + town:build(1, UnitId.ZergIrolIris, 70, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(mins(3) + secs(20)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:wait_build(1, UnitId.ZergHydrithDen) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergTethvithSwamp, 70, true) + town:wait_build(1, UnitId.ZergIrolIris) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + end) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ZergHydrithDen, 70, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Nathrokor / Skithrokor feint army + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergHydrithDen, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergVornathPond, 70, true) + town:build(1, UnitId.ZergSkibactScab, 70, true) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergGeszkathGrotto, 50, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/zerg/sunblot/skittering_duo.lua b/mpq/lua/melee/zerg/sunblot/skittering_duo.lua new file mode 100644 index 0000000..7c98248 --- /dev/null +++ b/mpq/lua/melee/zerg/sunblot/skittering_duo.lua @@ -0,0 +1,84 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Sunblot: Skittering Duo", + unit_composition = { + -- signature units (Skibact Scab) + [UnitId.ZergSkithrokor] = 2, + [UnitId.ZergBactalisk] = 2, + [UnitId.ZergNathrokor] = 2, + -- filler units + [UnitId.ZergGorgrokor] = 1, + [UnitId.ZergMutalisk] = 1, + [UnitId.ZergGeszithalor] = 1, + [UnitId.ZergVorvrokor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergHydrithDen, 90, true) + melee_ai:dynamic_wait(mins(1)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + melee_ai:dynamic_wait(secs(50)) + melee_ai:start_attacking() + -- tier1 + melee_ai:dynamic_wait(mins(1) + secs(15)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergVornathPond, 90, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergSkibactScab, 90, true) + melee_ai:dynamic_wait(mins(2) + secs(20)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Skibact duo + Nathrokor flyer support + town:build(1, UnitId.ZergHydrithDen, 70, true) + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + town:build(1, UnitId.ZergVornathPond, 70, true) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergGeszkathGrotto, 50, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/zerg/sunblot/the_triad.lua b/mpq/lua/melee/zerg/sunblot/the_triad.lua new file mode 100644 index 0000000..3daa51d --- /dev/null +++ b/mpq/lua/melee/zerg/sunblot/the_triad.lua @@ -0,0 +1,84 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Sunblot: The Triad", + unit_composition = { + -- signature units + [UnitId.ZergNathrokor] = 2, + [UnitId.ZergGorgrokor] = 2, + [UnitId.ZergKalkalisk] = 2, + -- filler units + [UnitId.ZergMutalisk] = 1, + [UnitId.ZergGeszithalor] = 1, + [UnitId.ZergIsthrathaleth] = 1, + [UnitId.ZergVorvrokor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(30)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + -- tier1 + melee_ai:dynamic_wait(mins(1) + secs(10)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(45)) + town:build(1, UnitId.ZergVornathPond, 90, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergHydrithDen, 90, true) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergZorkizShroud, 90, true) + melee_ai:dynamic_wait(mins(1)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Nathrokor / Gorgrokor / Kalkalisk triad + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergVornathPond, 70, true) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + town:build(1, UnitId.ZergMatravilNest, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergAlmakisAntre, 70, true) + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergGeszkathGrotto, 50, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.6, +} diff --git a/mpq/lua/melee/zerg/swarm/gates_of_hell.lua b/mpq/lua/melee/zerg/swarm/gates_of_hell.lua new file mode 100644 index 0000000..5766a29 --- /dev/null +++ b/mpq/lua/melee/zerg/swarm/gates_of_hell.lua @@ -0,0 +1,118 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Swarm: Gates of Hell", + unit_composition = { + -- signature units + [UnitId.ZergZethrokor] = 2, + [UnitId.ZergKeskathalor] = 2, + [UnitId.ZergHydralisk] = 2, + -- filler units + [UnitId.ZergKalkalisk] = 1, + [UnitId.ZergSovroleth] = 1, + [UnitId.ZergGorgrokor] = 1, + [UnitId.ZergSkithrokor] = 1, + [UnitId.ZergBactalisk] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(45)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(mins(1) + secs(55)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergZorkizShroud, 90, true) + melee_ai:dynamic_wait(secs(25)) + melee_ai:start_attacking() + -- tier1 + melee_ai:dynamic_wait(secs(55)) + town:build(1, UnitId.ZergHydrithDen, 90, true) + melee_ai:dynamic_wait(secs(20)) + -- tier2 + town:multirun(function(town) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(mins(1)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:wait_build(1, UnitId.ZergHydrithDen) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ZergTethvithSwamp, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:wait_build(1, UnitId.ZergZorkizShroud) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergZozarcGorge, 70, true) + town:wait_build(1, UnitId.ZergIrolIris) + melee_ai:dynamic_wait(mins(8) + secs(20)) + town:multirun(function(town) + melee_ai:dynamic_wait(secs(1)) + town:build(1, UnitId.ZergOthstolOviform, 65, true) + end) + end) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(15)) + town:multirun(function(town) + melee_ai:dynamic_wait(secs(1)) + town:build(1, UnitId.ZergIrolIris, 70, true) + end) + melee_ai:dynamic_wait(secs(30)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Zethrokor / Keskathalor / Hydralisk army + town:build(1, UnitId.ZergHydrithDen, 70, true) + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergTosvrolHaunt, 70, true) + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergGeszkathGrotto, 50, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/zerg/swarm/instant_quazeth.lua b/mpq/lua/melee/zerg/swarm/instant_quazeth.lua new file mode 100644 index 0000000..9b8f75b --- /dev/null +++ b/mpq/lua/melee/zerg/swarm/instant_quazeth.lua @@ -0,0 +1,93 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Swarm: Instant Quazeth", + unit_composition = { + -- signature units + [UnitId.ZergZethrokor] = 3, + [UnitId.ZergUltrokor] = 2, + [UnitId.ZergHydralisk] = 2, + -- filler units + [UnitId.ZergQuazilisk] = 1, + [UnitId.ZergKalkalisk] = 1, + [UnitId.ZergZoryusthaleth] = 1, + [UnitId.ZergNathrokor] = 1, + [UnitId.ZergVorvrokor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ZergQuazethPool, 110, true) + melee_ai:dynamic_wait(secs(5)) + town:wait_build(1, UnitId.ZergQuazethPool, false) + melee_ai:dynamic_wait(secs(5)) + town:build(2, UnitId.ZergHachirosk, 115) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(4)) + town:build(4, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(mins(1) + secs(20)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergVornathPond, 90, true) + melee_ai:dynamic_wait(mins(1) + secs(55)) + town:build(1, UnitId.ZergHydrithDen, 90, true) + melee_ai:dynamic_wait(mins(2) + secs(45)) + -- tier2 + town:multirun(function(town) + melee_ai:dynamic_wait(secs(1)) + town:build(1, UnitId.ZergIrolIris, 70, true) + end) + melee_ai:dynamic_wait(secs(25)) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:dynamic_wait(mins(3) + secs(20)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + end) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Zethrokor-heavy Quazeth swarm (+ Ultrokor / Hydralisk / Vornath) + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + town:build(1, UnitId.ZergHydrithDen, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergVornathPond, 70, true) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/zerg/swarm/primitive_pressure.lua b/mpq/lua/melee/zerg/swarm/primitive_pressure.lua new file mode 100644 index 0000000..d14d565 --- /dev/null +++ b/mpq/lua/melee/zerg/swarm/primitive_pressure.lua @@ -0,0 +1,104 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Swarm: Primitive Pressure", + unit_composition = { + -- signature units + [UnitId.ZergZethrokor] = 2, + [UnitId.ZergHydralisk] = 2, + [UnitId.ZergZoryusthaleth] = 2, + -- filler units + [UnitId.ZergLiiralisk] = 1, + [UnitId.ZergProtathalor] = 1, + [UnitId.ZergMatraleth] = 1, + [UnitId.ZergSovroleth] = 1, + [UnitId.ZergKeskathalor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(45)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergHydrithDen, 90, true) + melee_ai:dynamic_wait(secs(40)) + melee_ai:start_attacking() + -- tier1 + melee_ai:dynamic_wait(secs(30)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergVornathPond, 90, true) + melee_ai:dynamic_wait(mins(1) + secs(30)) + town:build(1, UnitId.ZergZorkizShroud, 90, true) + melee_ai:dynamic_wait(secs(50)) + -- tier2 + town:multirun(function(town) + melee_ai:dynamic_wait(secs(1)) + town:build(1, UnitId.ZergIrolIris, 70, true) + end) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:wait_build(1, UnitId.ZergHydrithDen) + melee_ai:dynamic_wait(mins(1)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergTethvithSwamp, 70, true) + end) + melee_ai:dynamic_wait(secs(40)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Zethrokor / Hydralisk / Zoryusthaleth pressure army + town:build(1, UnitId.ZergHydrithDen, 70, true) + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + town:build(1, UnitId.ZergMatravilNest, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergTosvrolHaunt, 70, true) + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergGeszkathGrotto, 50, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/zerg/swarm/three_base_flood.lua b/mpq/lua/melee/zerg/swarm/three_base_flood.lua new file mode 100644 index 0000000..75bd1d1 --- /dev/null +++ b/mpq/lua/melee/zerg/swarm/three_base_flood.lua @@ -0,0 +1,101 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Swarm: 3 Base Flood", + unit_composition = { + -- signature units + [UnitId.ZergZethrokor] = 2, + [UnitId.ZergUltrokor] = 2, + [UnitId.ZergHydralisk] = 2, + -- filler units + [UnitId.ZergKalkalisk] = 1, + [UnitId.ZergZoryusthaleth] = 1, + [UnitId.ZergMutalisk] = 1, + [UnitId.ZergNathrokor] = 1, + [UnitId.ZergVorvrokor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergQuazethPool, 110, true) + melee_ai:dynamic_wait(secs(50)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(15)) + melee_ai:start_expanding() + -- tier1 + melee_ai:dynamic_wait(secs(40)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(15)) + -- tier2 + town:multirun(function(town) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + town:wait_build(1, UnitId.ZergIrolIris) + town:wait_build(3, UnitId.ZergHachirosk, false) + melee_ai:dynamic_wait(secs(15)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + town:wait_build(1, UnitId.ZergMutathSpire) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergTosvrolHaunt, 70, true) + end) + melee_ai:dynamic_wait(secs(25)) + town:multirun(function(town) + melee_ai:dynamic_wait(secs(1)) + town:build(1, UnitId.ZergIrolIris, 70, true) + end) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ZergCaphrolosk, 70) + melee_ai:dynamic_wait(mins(1) + secs(20)) + town:build(3, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(25)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Zethrokor / Ultrokor / Hydralisk flood + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + town:build(1, UnitId.ZergHydrithDen, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergVornathPond, 70, true) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/zerg/swarm/three_base_othstol.lua b/mpq/lua/melee/zerg/swarm/three_base_othstol.lua new file mode 100644 index 0000000..ebe3d4d --- /dev/null +++ b/mpq/lua/melee/zerg/swarm/three_base_othstol.lua @@ -0,0 +1,110 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Swarm: 3 Base Othstol", + unit_composition = { + -- signature units + [UnitId.ZergIzirokor] = 2, + [UnitId.ZergUltrokor] = 2, + [UnitId.ZergHydralisk] = 2, + -- filler units + [UnitId.ZergKalkalisk] = 1, + [UnitId.ZergZoryusthaleth] = 1, + [UnitId.ZergGorgrokor] = 1, + [UnitId.ZergSkithrokor] = 1, + [UnitId.ZergBactalisk] = 1, + [UnitId.ZergZobriolisk] = 1, + [UnitId.ZergZarcavrokor] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(45)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(mins(1) + secs(55)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + -- tier1 + melee_ai:dynamic_wait(mins(1) + secs(15)) + town:build(2, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergVornathPond, 90, true) + melee_ai:dynamic_wait(secs(15)) + -- tier2 + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(40)) + town:build(3, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(25)) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergVornathPond, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:wait_build(1, UnitId.ZergHydrithDen) + town:build(1, UnitId.ZergSkibactScab, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:wait_build(1, UnitId.ZergZorkizShroud) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergTethvithSwamp, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergZozarcGorge, 70, true) + town:wait_build(1, UnitId.ZergIrolIris) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergMatravilNest, 70, true) + town:wait_build(1, UnitId.ZergOthstolOviform) + town:build(1, UnitId.ZergGathtelosk, 50) + town:wait_build(1, UnitId.ZergGathtelosk, false) + town:wait_build(2, UnitId.ZergHachirosk, false) + end) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergHydrithDen, 70, true) + melee_ai:dynamic_wait(secs(15)) + town:build(3, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(5)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Izirokor / Ultrokor / Hydralisk + Zozarc swarm + town:build(1, UnitId.ZergHydrithDen, 70, true) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergSkibactScab, 70, true) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergZozarcGorge, 70, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/melee/zerg/swarm/three_base_ultrav.lua b/mpq/lua/melee/zerg/swarm/three_base_ultrav.lua new file mode 100644 index 0000000..33e5aac --- /dev/null +++ b/mpq/lua/melee/zerg/swarm/three_base_ultrav.lua @@ -0,0 +1,114 @@ +local Basic = require "melee.zerg.basic" + +---@type AIPersonality +return { + name = "Swarm: 3 Base Ultrav", + unit_composition = { + -- signature units + [UnitId.ZergUltrokor] = 3, + [UnitId.ZergZethrokor] = 2, + [UnitId.ZergHydralisk] = 2, + -- filler units + [UnitId.ZergKalkalisk] = 1, + [UnitId.ZergZoryusthaleth] = 1, + [UnitId.ZergMutalisk] = 1, + [UnitId.ZergNathrokor] = 1, + [UnitId.ZergVorvrokor] = 1, + [UnitId.ZergSkithrokor] = 1, + [UnitId.ZergBactalisk] = 1, + }, + main_build_order = function(melee_ai, town) + melee_ai:build_main(town) + -- opener + melee_ai:dynamic_wait(secs(45)) + melee_ai:start_expanding() + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ZergQuazethPool, 90, true) + melee_ai:dynamic_wait(mins(1) + secs(15)) + town:build(2, UnitId.ZergHachirosk, 115) + town:build(1, UnitId.ZergVornathPond, 90, true) + melee_ai:dynamic_wait(secs(50)) + melee_ai:start_attacking() + melee_ai:dynamic_wait(secs(40)) + -- tier2 + town:multirun(function(town) + melee_ai:dynamic_wait(secs(1)) + town:build(1, UnitId.ZergIrolIris, 70, true) + end) + melee_ai:dynamic_wait(secs(55)) + town:build(1, UnitId.ZergCaphrolosk, 70) + melee_ai:dynamic_wait(mins(1) + secs(15)) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergQuazethPool) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + town:wait_build(1, UnitId.ZergZorkizShroud) + town:wait_build(2, UnitId.ZergHachirosk, false) + melee_ai:dynamic_wait(mins(1) + secs(40)) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:wait_build(1, UnitId.ZergHydrithDen) + town:build(1, UnitId.ZergSkibactScab, 70, true) + melee_ai:dynamic_wait(secs(50)) + town:build(1, UnitId.ZergTethvithSwamp, 70, true) + town:wait_build(1, UnitId.ZergIrolIris) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergMatravilNest, 70, true) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergGathtelosk, 50) + end) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + melee_ai:dynamic_wait(mins(1) + secs(45)) + town:build(3, UnitId.ZergHachirosk, 115) + melee_ai:dynamic_wait(secs(40)) + town:build(1, UnitId.ZergHydrithDen, 70, true) + melee_ai:dynamic_wait(secs(50)) + -- tier3 + town:build(1, UnitId.ZergOthstolOviform, 65, true) + melee_ai:dynamic_wait(secs(25)) + -- saturated production + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + end, + expansion_build_order = function(melee_ai, town) + melee_ai:build_expansion(town, true) + town:multirun(function(town) + town:wait_build(1, UnitId.ZergIrolIris) + town:build(5, UnitId.ZergLarvoskCesiant, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergHachirosk, 90) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergCaphrolosk, 90) + town:wait_build(1, UnitId.ZergOthstolOviform) + melee_ai:dynamic_wait(secs(45)) + town:build(6, UnitId.ZergGathtelosk, 50) + end) + -- production for the Ultrokor-heavy swarm (+ Zethrokor / Hydralisk / Skibact) + town:build(1, UnitId.ZergZorkizShroud, 70, true) + town:build(1, UnitId.ZergQuazethPool, 70, true) + town:build(1, UnitId.ZergHydrithDen, 70, true) + melee_ai:dynamic_wait(secs(20)) + town:build(1, UnitId.ZergUlgorgCavern, 70, true) + town:build(1, UnitId.ZergVornathPond, 70, true) + town:build(1, UnitId.ZergSkibactScab, 70, true) + town:build(1, UnitId.ZergKalkiirLake, 70, true) + melee_ai:dynamic_wait(secs(25)) + town:build(1, UnitId.ZergIrolIris, 70, true) + melee_ai:dynamic_wait(secs(30)) + town:build(1, UnitId.ZergMutathSpire, 70, true) + end, + build_anti_ground_defenses = Basic.build_anti_ground, + build_anti_air_defenses = Basic.build_anti_air, + attack_wave_cost_bias = 0.4, +} diff --git a/mpq/lua/start_melee_ai.lua b/mpq/lua/start_melee_ai.lua new file mode 100644 index 0000000..0c17bde --- /dev/null +++ b/mpq/lua/start_melee_ai.lua @@ -0,0 +1,3 @@ +require "melee.melee_ai" + +MeleeAI():run() diff --git a/mpq/portrait/b/dredge/fid00.smk b/mpq/portrait/b/dredge/fid00.smk new file mode 100644 index 0000000..081115f Binary files /dev/null and b/mpq/portrait/b/dredge/fid00.smk differ diff --git a/mpq/portrait/b/dredge/fid01.smk b/mpq/portrait/b/dredge/fid01.smk new file mode 100644 index 0000000..a34ebb5 Binary files /dev/null and b/mpq/portrait/b/dredge/fid01.smk differ diff --git a/mpq/portrait/b/dredge/fid02.smk b/mpq/portrait/b/dredge/fid02.smk new file mode 100644 index 0000000..9ae6226 Binary files /dev/null and b/mpq/portrait/b/dredge/fid02.smk differ diff --git a/mpq/portrait/b/dredge/fid03.smk b/mpq/portrait/b/dredge/fid03.smk new file mode 100644 index 0000000..27c02b4 Binary files /dev/null and b/mpq/portrait/b/dredge/fid03.smk differ diff --git a/mpq/portrait/b/dredge/tlk00.smk b/mpq/portrait/b/dredge/tlk00.smk new file mode 100644 index 0000000..c35ce82 Binary files /dev/null and b/mpq/portrait/b/dredge/tlk00.smk differ diff --git a/mpq/portrait/b/dredge/tlk01.smk b/mpq/portrait/b/dredge/tlk01.smk new file mode 100644 index 0000000..6426d2f Binary files /dev/null and b/mpq/portrait/b/dredge/tlk01.smk differ diff --git a/mpq/portrait/b/dredge/tlk02.smk b/mpq/portrait/b/dredge/tlk02.smk new file mode 100644 index 0000000..27eff7d Binary files /dev/null and b/mpq/portrait/b/dredge/tlk02.smk differ diff --git a/mpq/portrait/b/ixodid/fid00.smk b/mpq/portrait/b/ixodid/fid00.smk new file mode 100644 index 0000000..950a2ce Binary files /dev/null and b/mpq/portrait/b/ixodid/fid00.smk differ diff --git a/mpq/portrait/b/ixodid/fid01.smk b/mpq/portrait/b/ixodid/fid01.smk new file mode 100644 index 0000000..4cd6836 Binary files /dev/null and b/mpq/portrait/b/ixodid/fid01.smk differ diff --git a/mpq/portrait/b/ixodid/fid02.smk b/mpq/portrait/b/ixodid/fid02.smk new file mode 100644 index 0000000..af2bc37 Binary files /dev/null and b/mpq/portrait/b/ixodid/fid02.smk differ diff --git a/mpq/portrait/b/ixodid/tlk00.smk b/mpq/portrait/b/ixodid/tlk00.smk new file mode 100644 index 0000000..7dd405d Binary files /dev/null and b/mpq/portrait/b/ixodid/tlk00.smk differ diff --git a/mpq/portrait/b/ixodid/tlk01.smk b/mpq/portrait/b/ixodid/tlk01.smk new file mode 100644 index 0000000..86be82f Binary files /dev/null and b/mpq/portrait/b/ixodid/tlk01.smk differ diff --git a/mpq/portrait/f/ajax/fid00.smk b/mpq/portrait/f/ajax/fid00.smk new file mode 100644 index 0000000..81bfd63 Binary files /dev/null and b/mpq/portrait/f/ajax/fid00.smk differ diff --git a/mpq/portrait/f/ajax/fid01.smk b/mpq/portrait/f/ajax/fid01.smk new file mode 100644 index 0000000..93c1a6f Binary files /dev/null and b/mpq/portrait/f/ajax/fid01.smk differ diff --git a/mpq/portrait/f/ajax/fid02.smk b/mpq/portrait/f/ajax/fid02.smk new file mode 100644 index 0000000..43af253 Binary files /dev/null and b/mpq/portrait/f/ajax/fid02.smk differ diff --git a/mpq/portrait/f/ajax/tlk00.smk b/mpq/portrait/f/ajax/tlk00.smk new file mode 100644 index 0000000..05d072e Binary files /dev/null and b/mpq/portrait/f/ajax/tlk00.smk differ diff --git a/mpq/portrait/f/alzurokor/fid00.smk b/mpq/portrait/f/alzurokor/fid00.smk new file mode 100644 index 0000000..2f2425b Binary files /dev/null and b/mpq/portrait/f/alzurokor/fid00.smk differ diff --git a/mpq/portrait/f/alzurokor/fid01.smk b/mpq/portrait/f/alzurokor/fid01.smk new file mode 100644 index 0000000..f4adcb2 Binary files /dev/null and b/mpq/portrait/f/alzurokor/fid01.smk differ diff --git a/mpq/portrait/f/alzurokor/fid02.smk b/mpq/portrait/f/alzurokor/fid02.smk new file mode 100644 index 0000000..9a28b80 Binary files /dev/null and b/mpq/portrait/f/alzurokor/fid02.smk differ diff --git a/mpq/portrait/f/alzurokor/tlk00.smk b/mpq/portrait/f/alzurokor/tlk00.smk new file mode 100644 index 0000000..f29c1b4 Binary files /dev/null and b/mpq/portrait/f/alzurokor/tlk00.smk differ diff --git a/mpq/portrait/f/alzurokor/tlk01.smk b/mpq/portrait/f/alzurokor/tlk01.smk new file mode 100644 index 0000000..259f9ea Binary files /dev/null and b/mpq/portrait/f/alzurokor/tlk01.smk differ diff --git a/mpq/portrait/f/alzurokor/tlk02.smk b/mpq/portrait/f/alzurokor/tlk02.smk new file mode 100644 index 0000000..2e9ffa5 Binary files /dev/null and b/mpq/portrait/f/alzurokor/tlk02.smk differ diff --git a/mpq/portrait/f/arquebus/fid00.smk b/mpq/portrait/f/arquebus/fid00.smk new file mode 100644 index 0000000..041d134 Binary files /dev/null and b/mpq/portrait/f/arquebus/fid00.smk differ diff --git a/mpq/portrait/f/arquebus/fid01.smk b/mpq/portrait/f/arquebus/fid01.smk new file mode 100644 index 0000000..64ea20b Binary files /dev/null and b/mpq/portrait/f/arquebus/fid01.smk differ diff --git a/mpq/portrait/f/arquebus/fid02.smk b/mpq/portrait/f/arquebus/fid02.smk new file mode 100644 index 0000000..e4008b3 Binary files /dev/null and b/mpq/portrait/f/arquebus/fid02.smk differ diff --git a/mpq/portrait/f/arquebus/tlk00.smk b/mpq/portrait/f/arquebus/tlk00.smk new file mode 100644 index 0000000..31ebc61 Binary files /dev/null and b/mpq/portrait/f/arquebus/tlk00.smk differ diff --git a/mpq/portrait/f/arquebus/tlk01.smk b/mpq/portrait/f/arquebus/tlk01.smk new file mode 100644 index 0000000..8eef3f3 Binary files /dev/null and b/mpq/portrait/f/arquebus/tlk01.smk differ diff --git a/mpq/portrait/f/azanthrokor/fid00.smk b/mpq/portrait/f/azanthrokor/fid00.smk new file mode 100644 index 0000000..18b1ec8 Binary files /dev/null and b/mpq/portrait/f/azanthrokor/fid00.smk differ diff --git a/mpq/portrait/f/azanthrokor/fid01.smk b/mpq/portrait/f/azanthrokor/fid01.smk new file mode 100644 index 0000000..4724b80 Binary files /dev/null and b/mpq/portrait/f/azanthrokor/fid01.smk differ diff --git a/mpq/portrait/f/azanthrokor/tlk00.smk b/mpq/portrait/f/azanthrokor/tlk00.smk new file mode 100644 index 0000000..e1370d9 Binary files /dev/null and b/mpq/portrait/f/azanthrokor/tlk00.smk differ diff --git a/mpq/portrait/f/broadside/fid00.smk b/mpq/portrait/f/broadside/fid00.smk new file mode 100644 index 0000000..d4f4798 Binary files /dev/null and b/mpq/portrait/f/broadside/fid00.smk differ diff --git a/mpq/portrait/f/broadside/fid01.smk b/mpq/portrait/f/broadside/fid01.smk new file mode 100644 index 0000000..5e10cd4 Binary files /dev/null and b/mpq/portrait/f/broadside/fid01.smk differ diff --git a/mpq/portrait/f/broadside/tlk00.smk b/mpq/portrait/f/broadside/tlk00.smk new file mode 100644 index 0000000..99b2524 Binary files /dev/null and b/mpq/portrait/f/broadside/tlk00.smk differ diff --git a/mpq/portrait/f/broadside/tlk01.smk b/mpq/portrait/f/broadside/tlk01.smk new file mode 100644 index 0000000..3bca5a5 Binary files /dev/null and b/mpq/portrait/f/broadside/tlk01.smk differ diff --git a/mpq/portrait/f/camazotz/fid00.smk b/mpq/portrait/f/camazotz/fid00.smk new file mode 100644 index 0000000..e079177 Binary files /dev/null and b/mpq/portrait/f/camazotz/fid00.smk differ diff --git a/mpq/portrait/f/camazotz/fid01.smk b/mpq/portrait/f/camazotz/fid01.smk new file mode 100644 index 0000000..47b480f Binary files /dev/null and b/mpq/portrait/f/camazotz/fid01.smk differ diff --git a/mpq/portrait/f/camazotz/fid02.smk b/mpq/portrait/f/camazotz/fid02.smk new file mode 100644 index 0000000..4f1b9ce Binary files /dev/null and b/mpq/portrait/f/camazotz/fid02.smk differ diff --git a/mpq/portrait/f/camazotz/fid03.smk b/mpq/portrait/f/camazotz/fid03.smk new file mode 100644 index 0000000..461583e Binary files /dev/null and b/mpq/portrait/f/camazotz/fid03.smk differ diff --git a/mpq/portrait/f/camazotz/tlk00.smk b/mpq/portrait/f/camazotz/tlk00.smk new file mode 100644 index 0000000..9cda2c1 Binary files /dev/null and b/mpq/portrait/f/camazotz/tlk00.smk differ diff --git a/mpq/portrait/f/camazotz/tlk01.smk b/mpq/portrait/f/camazotz/tlk01.smk new file mode 100644 index 0000000..fd16e54 Binary files /dev/null and b/mpq/portrait/f/camazotz/tlk01.smk differ diff --git a/mpq/portrait/f/cannibal/fid00.smk b/mpq/portrait/f/cannibal/fid00.smk new file mode 100644 index 0000000..bd0f18a Binary files /dev/null and b/mpq/portrait/f/cannibal/fid00.smk differ diff --git a/mpq/portrait/f/cannibal/fid01.smk b/mpq/portrait/f/cannibal/fid01.smk new file mode 100644 index 0000000..a4f76b2 Binary files /dev/null and b/mpq/portrait/f/cannibal/fid01.smk differ diff --git a/mpq/portrait/f/cannibal/fid02.smk b/mpq/portrait/f/cannibal/fid02.smk new file mode 100644 index 0000000..824e2ac Binary files /dev/null and b/mpq/portrait/f/cannibal/fid02.smk differ diff --git a/mpq/portrait/f/cannibal/tlk00.smk b/mpq/portrait/f/cannibal/tlk00.smk new file mode 100644 index 0000000..c2d2d4c Binary files /dev/null and b/mpq/portrait/f/cannibal/tlk00.smk differ diff --git a/mpq/portrait/f/cannibal/tlk01.smk b/mpq/portrait/f/cannibal/tlk01.smk new file mode 100644 index 0000000..0aa785d Binary files /dev/null and b/mpq/portrait/f/cannibal/tlk01.smk differ diff --git a/mpq/portrait/f/cannibal/tlk02.smk b/mpq/portrait/f/cannibal/tlk02.smk new file mode 100644 index 0000000..5035211 Binary files /dev/null and b/mpq/portrait/f/cannibal/tlk02.smk differ diff --git a/mpq/portrait/f/cutlass/fid00.smk b/mpq/portrait/f/cutlass/fid00.smk new file mode 100644 index 0000000..4108bbf Binary files /dev/null and b/mpq/portrait/f/cutlass/fid00.smk differ diff --git a/mpq/portrait/f/cutlass/fid01.smk b/mpq/portrait/f/cutlass/fid01.smk new file mode 100644 index 0000000..f0e4358 Binary files /dev/null and b/mpq/portrait/f/cutlass/fid01.smk differ diff --git a/mpq/portrait/f/cutlass/fid02.smk b/mpq/portrait/f/cutlass/fid02.smk new file mode 100644 index 0000000..c731924 Binary files /dev/null and b/mpq/portrait/f/cutlass/fid02.smk differ diff --git a/mpq/portrait/f/cutlass/fid03.smk b/mpq/portrait/f/cutlass/fid03.smk new file mode 100644 index 0000000..f7d30a5 Binary files /dev/null and b/mpq/portrait/f/cutlass/fid03.smk differ diff --git a/mpq/portrait/f/cutlass/tlk00.smk b/mpq/portrait/f/cutlass/tlk00.smk new file mode 100644 index 0000000..2303c7d Binary files /dev/null and b/mpq/portrait/f/cutlass/tlk00.smk differ diff --git a/mpq/portrait/f/cutlass/tlk01.smk b/mpq/portrait/f/cutlass/tlk01.smk new file mode 100644 index 0000000..89aaa84 Binary files /dev/null and b/mpq/portrait/f/cutlass/tlk01.smk differ diff --git a/mpq/portrait/f/cutlass/tlk02.smk b/mpq/portrait/f/cutlass/tlk02.smk new file mode 100644 index 0000000..14371ef Binary files /dev/null and b/mpq/portrait/f/cutlass/tlk02.smk differ diff --git a/mpq/portrait/f/cyprian_hecaton/fid00.smk b/mpq/portrait/f/cyprian_hecaton/fid00.smk new file mode 100644 index 0000000..77ca7fc Binary files /dev/null and b/mpq/portrait/f/cyprian_hecaton/fid00.smk differ diff --git a/mpq/portrait/f/cyprian_hecaton/tlk00.smk b/mpq/portrait/f/cyprian_hecaton/tlk00.smk new file mode 100644 index 0000000..b33bd4c Binary files /dev/null and b/mpq/portrait/f/cyprian_hecaton/tlk00.smk differ diff --git a/mpq/portrait/f/eidolon_golden/fid00.smk b/mpq/portrait/f/eidolon_golden/fid00.smk new file mode 100644 index 0000000..280304f Binary files /dev/null and b/mpq/portrait/f/eidolon_golden/fid00.smk differ diff --git a/mpq/portrait/f/eidolon_golden/fid01.smk b/mpq/portrait/f/eidolon_golden/fid01.smk new file mode 100644 index 0000000..ec69762 Binary files /dev/null and b/mpq/portrait/f/eidolon_golden/fid01.smk differ diff --git a/mpq/portrait/f/eidolon_golden/fid02.smk b/mpq/portrait/f/eidolon_golden/fid02.smk new file mode 100644 index 0000000..8460b80 Binary files /dev/null and b/mpq/portrait/f/eidolon_golden/fid02.smk differ diff --git a/mpq/portrait/f/eidolon_golden/fid03.smk b/mpq/portrait/f/eidolon_golden/fid03.smk new file mode 100644 index 0000000..f0de2a8 Binary files /dev/null and b/mpq/portrait/f/eidolon_golden/fid03.smk differ diff --git a/mpq/portrait/f/eidolon_golden/tlk00.smk b/mpq/portrait/f/eidolon_golden/tlk00.smk new file mode 100644 index 0000000..3361536 Binary files /dev/null and b/mpq/portrait/f/eidolon_golden/tlk00.smk differ diff --git a/mpq/portrait/f/eidolon_nydus/fid01.smk b/mpq/portrait/f/eidolon_nydus/fid01.smk index 0433336..616e6f6 100644 Binary files a/mpq/portrait/f/eidolon_nydus/fid01.smk and b/mpq/portrait/f/eidolon_nydus/fid01.smk differ diff --git a/mpq/portrait/f/eidolon_nydus/fid02.smk b/mpq/portrait/f/eidolon_nydus/fid02.smk new file mode 100644 index 0000000..0433336 Binary files /dev/null and b/mpq/portrait/f/eidolon_nydus/fid02.smk differ diff --git a/mpq/portrait/f/garvrokor/fid00.smk b/mpq/portrait/f/garvrokor/fid00.smk new file mode 100644 index 0000000..ef5013e Binary files /dev/null and b/mpq/portrait/f/garvrokor/fid00.smk differ diff --git a/mpq/portrait/f/garvrokor/fid01.smk b/mpq/portrait/f/garvrokor/fid01.smk new file mode 100644 index 0000000..fb19ba5 Binary files /dev/null and b/mpq/portrait/f/garvrokor/fid01.smk differ diff --git a/mpq/portrait/f/garvrokor/fid02.smk b/mpq/portrait/f/garvrokor/fid02.smk new file mode 100644 index 0000000..5762aa4 Binary files /dev/null and b/mpq/portrait/f/garvrokor/fid02.smk differ diff --git a/mpq/portrait/f/garvrokor/fid03.smk b/mpq/portrait/f/garvrokor/fid03.smk new file mode 100644 index 0000000..70c8317 Binary files /dev/null and b/mpq/portrait/f/garvrokor/fid03.smk differ diff --git a/mpq/portrait/f/garvrokor/tlk00.smk b/mpq/portrait/f/garvrokor/tlk00.smk new file mode 100644 index 0000000..0c00266 Binary files /dev/null and b/mpq/portrait/f/garvrokor/tlk00.smk differ diff --git a/mpq/portrait/f/garvrokor/tlk01.smk b/mpq/portrait/f/garvrokor/tlk01.smk new file mode 100644 index 0000000..a243b7a Binary files /dev/null and b/mpq/portrait/f/garvrokor/tlk01.smk differ diff --git a/mpq/portrait/f/goremast/fid00.smk b/mpq/portrait/f/goremast/fid00.smk new file mode 100644 index 0000000..69e610f Binary files /dev/null and b/mpq/portrait/f/goremast/fid00.smk differ diff --git a/mpq/portrait/f/goremast/fid01.smk b/mpq/portrait/f/goremast/fid01.smk new file mode 100644 index 0000000..08e2b07 Binary files /dev/null and b/mpq/portrait/f/goremast/fid01.smk differ diff --git a/mpq/portrait/f/goremast/tlk00.smk b/mpq/portrait/f/goremast/tlk00.smk new file mode 100644 index 0000000..68c7ef0 Binary files /dev/null and b/mpq/portrait/f/goremast/tlk00.smk differ diff --git a/mpq/portrait/f/memphis/fid00.smk b/mpq/portrait/f/memphis/fid00.smk new file mode 100644 index 0000000..30c4784 Binary files /dev/null and b/mpq/portrait/f/memphis/fid00.smk differ diff --git a/mpq/portrait/f/memphis/fid01.smk b/mpq/portrait/f/memphis/fid01.smk new file mode 100644 index 0000000..0bc5586 Binary files /dev/null and b/mpq/portrait/f/memphis/fid01.smk differ diff --git a/mpq/portrait/f/memphis/fid02.smk b/mpq/portrait/f/memphis/fid02.smk new file mode 100644 index 0000000..f0c5476 Binary files /dev/null and b/mpq/portrait/f/memphis/fid02.smk differ diff --git a/mpq/portrait/f/memphis/fid03.smk b/mpq/portrait/f/memphis/fid03.smk new file mode 100644 index 0000000..88ecd6e Binary files /dev/null and b/mpq/portrait/f/memphis/fid03.smk differ diff --git a/mpq/portrait/f/memphis/tlk00.smk b/mpq/portrait/f/memphis/tlk00.smk new file mode 100644 index 0000000..b4cb1be Binary files /dev/null and b/mpq/portrait/f/memphis/tlk00.smk differ diff --git a/mpq/portrait/f/memphis/tlk01.smk b/mpq/portrait/f/memphis/tlk01.smk new file mode 100644 index 0000000..f5b828a Binary files /dev/null and b/mpq/portrait/f/memphis/tlk01.smk differ diff --git a/mpq/portrait/f/memphis/tlk02.smk b/mpq/portrait/f/memphis/tlk02.smk new file mode 100644 index 0000000..40c9c03 Binary files /dev/null and b/mpq/portrait/f/memphis/tlk02.smk differ diff --git a/mpq/portrait/f/morrigan/fid00.smk b/mpq/portrait/f/morrigan/fid00.smk new file mode 100644 index 0000000..7cce649 Binary files /dev/null and b/mpq/portrait/f/morrigan/fid00.smk differ diff --git a/mpq/portrait/f/morrigan/fid01.smk b/mpq/portrait/f/morrigan/fid01.smk new file mode 100644 index 0000000..861fc4d Binary files /dev/null and b/mpq/portrait/f/morrigan/fid01.smk differ diff --git a/mpq/portrait/f/morrigan/fid02.smk b/mpq/portrait/f/morrigan/fid02.smk new file mode 100644 index 0000000..7a0354e Binary files /dev/null and b/mpq/portrait/f/morrigan/fid02.smk differ diff --git a/mpq/portrait/f/morrigan/fid03.smk b/mpq/portrait/f/morrigan/fid03.smk new file mode 100644 index 0000000..9331f8c Binary files /dev/null and b/mpq/portrait/f/morrigan/fid03.smk differ diff --git a/mpq/portrait/f/morrigan/tlk00.smk b/mpq/portrait/f/morrigan/tlk00.smk new file mode 100644 index 0000000..774ce56 Binary files /dev/null and b/mpq/portrait/f/morrigan/tlk00.smk differ diff --git a/mpq/portrait/f/quadriga/fid00.smk b/mpq/portrait/f/quadriga/fid00.smk new file mode 100644 index 0000000..8606f7a Binary files /dev/null and b/mpq/portrait/f/quadriga/fid00.smk differ diff --git a/mpq/portrait/f/quadriga/fid01.smk b/mpq/portrait/f/quadriga/fid01.smk new file mode 100644 index 0000000..7b41621 Binary files /dev/null and b/mpq/portrait/f/quadriga/fid01.smk differ diff --git a/mpq/portrait/f/quadriga/fid02.smk b/mpq/portrait/f/quadriga/fid02.smk new file mode 100644 index 0000000..e22970f Binary files /dev/null and b/mpq/portrait/f/quadriga/fid02.smk differ diff --git a/mpq/portrait/f/quadriga/fid03.smk b/mpq/portrait/f/quadriga/fid03.smk new file mode 100644 index 0000000..ffb5d93 Binary files /dev/null and b/mpq/portrait/f/quadriga/fid03.smk differ diff --git a/mpq/portrait/f/quadriga/tlk00.smk b/mpq/portrait/f/quadriga/tlk00.smk new file mode 100644 index 0000000..79795f6 Binary files /dev/null and b/mpq/portrait/f/quadriga/tlk00.smk differ diff --git a/mpq/portrait/f/quadriga/tlk01.smk b/mpq/portrait/f/quadriga/tlk01.smk new file mode 100644 index 0000000..bbe2299 Binary files /dev/null and b/mpq/portrait/f/quadriga/tlk01.smk differ diff --git a/mpq/portrait/f/quadriga/tlk02.smk b/mpq/portrait/f/quadriga/tlk02.smk new file mode 100644 index 0000000..57e468b Binary files /dev/null and b/mpq/portrait/f/quadriga/tlk02.smk differ diff --git a/mpq/portrait/f/serathiel/fid00.smk b/mpq/portrait/f/serathiel/fid00.smk new file mode 100644 index 0000000..519f0c5 Binary files /dev/null and b/mpq/portrait/f/serathiel/fid00.smk differ diff --git a/mpq/portrait/f/serathiel/fid01.smk b/mpq/portrait/f/serathiel/fid01.smk new file mode 100644 index 0000000..f4ba3de Binary files /dev/null and b/mpq/portrait/f/serathiel/fid01.smk differ diff --git a/mpq/portrait/f/serathiel/fid02.smk b/mpq/portrait/f/serathiel/fid02.smk new file mode 100644 index 0000000..ef92591 Binary files /dev/null and b/mpq/portrait/f/serathiel/fid02.smk differ diff --git a/mpq/portrait/f/serathiel/fid03.smk b/mpq/portrait/f/serathiel/fid03.smk new file mode 100644 index 0000000..436ac63 Binary files /dev/null and b/mpq/portrait/f/serathiel/fid03.smk differ diff --git a/mpq/portrait/f/serathiel/tlk00.smk b/mpq/portrait/f/serathiel/tlk00.smk new file mode 100644 index 0000000..3eee65b Binary files /dev/null and b/mpq/portrait/f/serathiel/tlk00.smk differ diff --git a/mpq/portrait/f/serathiel/tlk01.smk b/mpq/portrait/f/serathiel/tlk01.smk new file mode 100644 index 0000000..b555238 Binary files /dev/null and b/mpq/portrait/f/serathiel/tlk01.smk differ diff --git a/mpq/portrait/f/serathiel/tlk02.smk b/mpq/portrait/f/serathiel/tlk02.smk new file mode 100644 index 0000000..1948f9c Binary files /dev/null and b/mpq/portrait/f/serathiel/tlk02.smk differ diff --git a/mpq/portrait/f/shaman_upstart/fid00.smk b/mpq/portrait/f/shaman_upstart/fid00.smk new file mode 100644 index 0000000..e00a555 Binary files /dev/null and b/mpq/portrait/f/shaman_upstart/fid00.smk differ diff --git a/mpq/portrait/f/shaman_upstart/tlk00.smk b/mpq/portrait/f/shaman_upstart/tlk00.smk new file mode 100644 index 0000000..e00a555 Binary files /dev/null and b/mpq/portrait/f/shaman_upstart/tlk00.smk differ diff --git a/mpq/portrait/f/sovrokor/fid00.smk b/mpq/portrait/f/sovrokor/fid00.smk new file mode 100644 index 0000000..f88fd4a Binary files /dev/null and b/mpq/portrait/f/sovrokor/fid00.smk differ diff --git a/mpq/portrait/f/sovrokor/fid01.smk b/mpq/portrait/f/sovrokor/fid01.smk new file mode 100644 index 0000000..d429448 Binary files /dev/null and b/mpq/portrait/f/sovrokor/fid01.smk differ diff --git a/mpq/portrait/f/sovrokor/fid02.smk b/mpq/portrait/f/sovrokor/fid02.smk new file mode 100644 index 0000000..7725c55 Binary files /dev/null and b/mpq/portrait/f/sovrokor/fid02.smk differ diff --git a/mpq/portrait/f/sovrokor/fid03.smk b/mpq/portrait/f/sovrokor/fid03.smk new file mode 100644 index 0000000..288b019 Binary files /dev/null and b/mpq/portrait/f/sovrokor/fid03.smk differ diff --git a/mpq/portrait/f/sovrokor/tlk00.smk b/mpq/portrait/f/sovrokor/tlk00.smk new file mode 100644 index 0000000..7566342 Binary files /dev/null and b/mpq/portrait/f/sovrokor/tlk00.smk differ diff --git a/mpq/portrait/f/sovrokor/tlk01.smk b/mpq/portrait/f/sovrokor/tlk01.smk new file mode 100644 index 0000000..cfa781e Binary files /dev/null and b/mpq/portrait/f/sovrokor/tlk01.smk differ diff --git a/mpq/portrait/f/sovrokor/tlk02.smk b/mpq/portrait/f/sovrokor/tlk02.smk new file mode 100644 index 0000000..ec98c19 Binary files /dev/null and b/mpq/portrait/f/sovrokor/tlk02.smk differ diff --git a/mpq/portrait/f/tartarusmine/fid00.smk b/mpq/portrait/f/tartarusmine/fid00.smk new file mode 100644 index 0000000..0ec7965 Binary files /dev/null and b/mpq/portrait/f/tartarusmine/fid00.smk differ diff --git a/mpq/portrait/f/tartarusmine/fid01.smk b/mpq/portrait/f/tartarusmine/fid01.smk new file mode 100644 index 0000000..ae49704 Binary files /dev/null and b/mpq/portrait/f/tartarusmine/fid01.smk differ diff --git a/mpq/portrait/f/tartarusmine/tlk00.smk b/mpq/portrait/f/tartarusmine/tlk00.smk new file mode 100644 index 0000000..1348699 Binary files /dev/null and b/mpq/portrait/f/tartarusmine/tlk00.smk differ diff --git a/mpq/portrait/f/valkyrie_hecaton/fid00.smk b/mpq/portrait/f/valkyrie_hecaton/fid00.smk new file mode 100644 index 0000000..47179a1 Binary files /dev/null and b/mpq/portrait/f/valkyrie_hecaton/fid00.smk differ diff --git a/mpq/portrait/f/valkyrie_hecaton/fid01.smk b/mpq/portrait/f/valkyrie_hecaton/fid01.smk new file mode 100644 index 0000000..afa55be Binary files /dev/null and b/mpq/portrait/f/valkyrie_hecaton/fid01.smk differ diff --git a/mpq/portrait/f/valkyrie_hecaton/fid02.smk b/mpq/portrait/f/valkyrie_hecaton/fid02.smk new file mode 100644 index 0000000..7363def Binary files /dev/null and b/mpq/portrait/f/valkyrie_hecaton/fid02.smk differ diff --git a/mpq/portrait/f/valkyrie_hecaton/fid03.smk b/mpq/portrait/f/valkyrie_hecaton/fid03.smk new file mode 100644 index 0000000..62f5a02 Binary files /dev/null and b/mpq/portrait/f/valkyrie_hecaton/fid03.smk differ diff --git a/mpq/portrait/f/valkyrie_hecaton/tlk00.smk b/mpq/portrait/f/valkyrie_hecaton/tlk00.smk new file mode 100644 index 0000000..a3bd652 Binary files /dev/null and b/mpq/portrait/f/valkyrie_hecaton/tlk00.smk differ diff --git a/mpq/portrait/f/valkyrie_hecaton/tlk01.smk b/mpq/portrait/f/valkyrie_hecaton/tlk01.smk new file mode 100644 index 0000000..2b27294 Binary files /dev/null and b/mpq/portrait/f/valkyrie_hecaton/tlk01.smk differ diff --git a/mpq/portrait/f/valkyrie_hecaton/tlk02.smk b/mpq/portrait/f/valkyrie_hecaton/tlk02.smk new file mode 100644 index 0000000..e6ab0a1 Binary files /dev/null and b/mpq/portrait/f/valkyrie_hecaton/tlk02.smk differ diff --git a/mpq/portrait/f/vulture_hecaton/fid00.smk b/mpq/portrait/f/vulture_hecaton/fid00.smk new file mode 100644 index 0000000..3f7a4b8 Binary files /dev/null and b/mpq/portrait/f/vulture_hecaton/fid00.smk differ diff --git a/mpq/portrait/f/vulture_hecaton/fid01.smk b/mpq/portrait/f/vulture_hecaton/fid01.smk new file mode 100644 index 0000000..88060ae Binary files /dev/null and b/mpq/portrait/f/vulture_hecaton/fid01.smk differ diff --git a/mpq/portrait/f/vulture_hecaton/fid02.smk b/mpq/portrait/f/vulture_hecaton/fid02.smk new file mode 100644 index 0000000..fc62eed Binary files /dev/null and b/mpq/portrait/f/vulture_hecaton/fid02.smk differ diff --git a/mpq/portrait/f/vulture_hecaton/fid03.smk b/mpq/portrait/f/vulture_hecaton/fid03.smk new file mode 100644 index 0000000..1dab047 Binary files /dev/null and b/mpq/portrait/f/vulture_hecaton/fid03.smk differ diff --git a/mpq/portrait/f/vulture_hecaton/tlk00.smk b/mpq/portrait/f/vulture_hecaton/tlk00.smk new file mode 100644 index 0000000..9c64192 Binary files /dev/null and b/mpq/portrait/f/vulture_hecaton/tlk00.smk differ diff --git a/mpq/portrait/f/vulture_hecaton/tlk01.smk b/mpq/portrait/f/vulture_hecaton/tlk01.smk new file mode 100644 index 0000000..9b89b2f Binary files /dev/null and b/mpq/portrait/f/vulture_hecaton/tlk01.smk differ diff --git a/mpq/portrait/f/vulture_upstart/fid00.smk b/mpq/portrait/f/vulture_upstart/fid00.smk new file mode 100644 index 0000000..3555f44 Binary files /dev/null and b/mpq/portrait/f/vulture_upstart/fid00.smk differ diff --git a/mpq/portrait/f/vulture_upstart/fid01.smk b/mpq/portrait/f/vulture_upstart/fid01.smk new file mode 100644 index 0000000..4d3492d Binary files /dev/null and b/mpq/portrait/f/vulture_upstart/fid01.smk differ diff --git a/mpq/portrait/f/vulture_upstart/fid02.smk b/mpq/portrait/f/vulture_upstart/fid02.smk new file mode 100644 index 0000000..fe49765 Binary files /dev/null and b/mpq/portrait/f/vulture_upstart/fid02.smk differ diff --git a/mpq/portrait/f/vulture_upstart/fid03.smk b/mpq/portrait/f/vulture_upstart/fid03.smk new file mode 100644 index 0000000..4882b1e Binary files /dev/null and b/mpq/portrait/f/vulture_upstart/fid03.smk differ diff --git a/mpq/portrait/f/vulture_upstart/tlk00.smk b/mpq/portrait/f/vulture_upstart/tlk00.smk new file mode 100644 index 0000000..ca11fbd Binary files /dev/null and b/mpq/portrait/f/vulture_upstart/tlk00.smk differ diff --git a/mpq/portrait/f/vulture_upstart/tlk01.smk b/mpq/portrait/f/vulture_upstart/tlk01.smk new file mode 100644 index 0000000..e4f4316 Binary files /dev/null and b/mpq/portrait/f/vulture_upstart/tlk01.smk differ diff --git a/mpq/portrait/n/vespene/fid00.smk b/mpq/portrait/n/vespene/fid00.smk new file mode 100644 index 0000000..60c7056 Binary files /dev/null and b/mpq/portrait/n/vespene/fid00.smk differ diff --git a/mpq/rez/stat.txt b/mpq/rez/stat.txt index ab5bbd2..d7f1a69 100644 --- a/mpq/rez/stat.txt +++ b/mpq/rez/stat.txt @@ -309,17 +309,17 @@ <0> <0> <0> -<0> -<0> -<0> -<0> +a<1><4>Build Memphis <1>(<3>A<1>)<10>Flak microtank.<0> +Memphis Requires:<10> Scrapyard<0> +e<3><4>Flak Mode <1>(<3>E<1>)<10>Switches forms, gaining splash radius and targeting only airborne hostiles, while disabling movement.<0> +e<0><4>Tank Mode <1>(<3>E<1>)<10>Returns the Memphis's weapon and mobility to normal.<0> Spider Mines<0> Goremasts<0> Piety Wards<0> Morrigan Requires:<10> Covenant<0> -f<1><4>Train Morrigan <1>(<3>G<1>)<10>Crowd-control infantry.<0> +g<1><4>Train Morrigan <1>(<3>G<1>)<10>Crowd-control infantry.<0> ¤<3><4>Dampening Field <2>(passive)<10>This combatant becomes cloaked for 2 seconds after attacking.<0> -a<1><4>Bestow Maverick <1>(<3>F<1>)<10>Disciplined infantry.<0> +a<1><4>Bestow Maverick <1>(<3>A<1>)<10>Disciplined infantry.<0> ¤<3><4>Accelerated Speech <2>(passive)<10>While the Missionary is within 2 range of its target, it gains +2 armor penetration.<0> ¤<3><4>Flanking Spines <2>(passive)<10>When targeting debuffed enemies, Almaksalisk attacks ignore armor.<0> Anchor Attack requires:<10> Loaded ranged combatant<0> @@ -496,7 +496,7 @@ r<3><4>Aural Assault <1>(<3>R<1>)<10>Fires a projectile that blinds all targets Okrimnil Aspect requires:<10> Chokral Chazsal<0> ¤<3><4>Fleeting Focus <2>(passive)<10>When struck by a mobile hostile within 2 range, Strigas repulse their attacker backwards by 1 range.<0> z<3><4>Lobotomize <1>(<3>Z<1>)<10>Detonates the Lobotomy Mine immediately, applying its slow effects to all combatants within 2 range.<0> -c<3><4>Conflagrate <1>(<3>Z<1>)<10>Detonates the Tartarus Mine immediately, applying its armor rend to all combatants within 2 range.<0> +c<3><4>Conflagrate <1>(<3>C<1>)<10>Detonates the Tartarus Mine immediately, applying its armor rend to all combatants within 2 range.<0> c<3><4>Controlled Demolition <1>(<3>C<1>)<10>After 10 seconds, the structure explodes in a controlled demolition, dealing no damage to nearby targets. This process can be cancelled.<0> e<3><4>Emergency Detonation <1>(<3>E<1>)<10>After 3 seconds, the structure self-destructs violently, dealing up to 250 damage to all targets within 3 range.<0> ¤<3><4>Scrapworld: Gold Rush <2>(passive)<10>This combatant's attacks debuff hostiles for 2 seconds. If a victim dies during this time, its corpse is salvaged, granting this combatant's owner 25% of their victim's resource cost.<0> @@ -817,7 +817,7 @@ Game Menu (<3>F10<1>)<0> ¤<3><4>Astral Splendor <2>(passive)<10>Once every 2 seconds, this core restores 10 shields to allies within 8 range. Allies can only be restored once every 2 seconds.<0> x<1><4>Build Cestus <1>(<3>X<1>)<10>Warding outpost.<0> b<1><4>Warp in Bulwark <1>(<3>B<1>)<10>Protective core.<0> -v<1><4>Morph into Yblyleth <1>(<3>V<1>)<10>Expanding strain.<0> +g<1><4>Morph into Yblyleth <1>(<3>G<1>)<10>Expanding strain.<0> ¤<3><4>Cagra Autophagy <2>(passive)<10>Every 2 seconds while burrowed, Yblyleths consume the closest corpse within 5 range, spawning 2 Rilirokors.<0> ¤<3><4>Cagragenesis <2>(passive)<10>While burrowed, this strain generates cagra in an 8-tile radius.<0> ¤<3><4>Corrosive Touch <2>(passive)<10>This strain's air attacks debuff enemies, increasing attack cooldown by 25% and reducing armor by 1 for 3 seconds.<0> @@ -954,7 +954,7 @@ Crematorium requires:<10> Conduit<0> Paraclete requires:<10> Bestiary<0> v<1><4>Morph into Zethalor <1>(<3>V<1>)<10>Swarming artillery strain.<0> Zethar Aspect requires:<10> Vornath Pond<0> -r<1><4>Morph into Scrylyleth <1>(<3>V<1>)<10>Territorial strain.<0> +g<1><4>Morph into Scrylyleth <1>(<3>G<1>)<10>Territorial strain.<0> Scrylyl Aspect requires:<10> Irol Iris<0> c<1><4>Install Conduit <1>(<3>C<1>)<10>Ashen relay.<0> Conduit Requires<10> Proscenium OR Zylode<0> @@ -1000,16 +1000,16 @@ v<1><4>Meld Tortare <1>(<3>V<1>)<10>Heavy corvette.<0> d<1><4>Meld Cybrene <1>(<3>D<1>)<10>Supreme cruiser.<0> Tortare requires:<10> Lekrot<0> Cybrene requires:<10> Hearthshard<0> -c<1><4>Install Lekrot <1>(<3>S<1>)<10>Manipulation relay.<0> +c<1><4>Install Lekrot <1>(<3>C<1>)<10>Manipulation relay.<0> Lekrot Requires<10> Panoply OR Lotiro<0> -t<1><4>Install Hearthshard <1>(<3>S<1>)<10>Immortal relay.<0> +t<1><4>Install Hearthshard <1>(<3>T<1>)<10>Immortal relay.<0> Hearthshard Requires<10> Panoply OR Lotiro<0> Zytryleth Requires:<10> Othstol Oviform<0> t<1><4>Bleed Thrombocyte <1>(<3>T<1>)<10>Regenerative biode.<0> b<3><4>Bloody Burst <1>(<3>B<1>)<10>Bursts the Thrombocyte, releasing a pulse that heals allies within 3 range for the Thrombocyte's current health.<0> ¤<3><4>Coagulation <2>(passive)<10>This combatant's attacks heal allies equal to damage dealt.<0> ¤<3><4>Portents <2>(passive)<10>When this combatant receives damage, it becomes cloaked, and decloaks after 2 seconds of not taking damage.<0> -t<1><4>Build Arquebus <1>(<3>C<1>)<10>Incendiary platform.<0> +c<1><4>Build Arquebus <1>(<3>C<1>)<10>Incendiary platform.<0> ¤<3><4>Forlorn Haste <2>(passive)<10>While isolated within 3 range, this combatant gains 200% movement speed.<0> t<1><4>Morph into Alzurokor <1>(<3>T<1>)<10>Subjugation strain.<0> Alzur Aspect requires:<10> Ulgorg Cavern<0> @@ -1025,7 +1025,7 @@ a<1><4>Construct Athla <1>(<3>A<1>)<10>Constructor model.<0> f<1><4>Construct Ferrum <1>(<3>F<1>)<10>Aggressor model.<0> c<1><4>Construct Chalyb <1>(<3>C<1>)<10>Defender model.<0> t<1><4>Construct Circitor <1>(<3>T<1>)<10>Pursuit model.<0> -x<1><4>Construct Exigo <1>(<3>X<1>)<10>Defense platform.<0> +x<1><4>Construct Exigo <1>(<3>X<1>)<10>Enforcer platform.<0> v<1><4>Construct Vicere <1>(<3>V<1>)<10>Assault platform.<0> Forerunner Alloy<0> Forerunner Lattice<0> @@ -1150,8 +1150,8 @@ Sasyrvoleth requires:<10> Axtoth Axis<0> e<1><4>Warp in Cicatus <1>(<3>E<1>)<10>Destitute skirmisher.<0> ¤<3><4>Servile Vigor <2>(passive)<10>Cohorts revive once after death, gaining a 10-second timed life. They can consume a nearby corpse to become permanent again.<0> a<1><4>Warp in Extatus <1>(<3>A<1>)<10>Stolid fighter.<0> -c<1><4>Erect Machinamentum <1>(<3>C<1>)<10>Assembly site.<0> -<0> +c<1><4>Erect Machinamentum <1>(<3>C<1>)<10>Core installation.<0> +r<1><4>Train Cyprian <1>(<3>R<1>)<10>Suppressing infantry.<0> s<1><4>Assemble Oscilliant <1>(<3>S<1>)<10>Assault drone.<0> a<1><4>Assemble Unar <1>(<3>A<1>)<10>Sniper drone.<0> r<1><4>Warp in Ashguard <1>(<3>R<1>)<10>Conquering strider.<0> @@ -1380,7 +1380,7 @@ s<1><4>Build Treasury <1>(<3>S<1>)<10>Frontier town center.<0> ¤<3><4>Tranquility Array <2>(passive)<10>Upon taking shield damage, the Golem radiates energy, restoring 2 shields for allies within 3 range.<0> <0> ¤<3><4>Interception <2>(passive)<10>This combatant's projectiles can be intercepted by hostiles.<0> -t<3><4>Nanite Field <2>(passive)<10>Every second, Shamans release a pulse that heals allies within 3 range for 8 HP.<10>An ally cannot be healed by a Shaman more than once per second.<0> +¤<3><4>Nanite Field <2>(passive)<10>Every second, Shamans release a pulse that heals allies within 3 range for 8 HP.<10>An ally cannot be healed by a Shaman more than once per second.<0> ¤<3><4>Virile Coating <2>(passive)<10>Victims of the Tetcaerokor's attacks begin incubating, birthing 1 Rililisk if they survive for 2 seconds.<10><10>This status cannot be applied if the target is already incubating.<0> r<1><4>Warp in Automaton Register <1>(<3>R<1>)<10>Heavy robotic production.<0> z<1><4>Mutate into Alkag Iteth <1>(<3>Z<1>)<10>Assault node. Enables Kagralisks, Evigrilisks, and Almaksalisks.<0> @@ -1804,156 +1804,156 @@ Algoz Aspect requires:<10> Chokral Chazsal<0> ¤<3><4>Fan of Teeth <2>(passive)<10>Upon taking damage, this strain launches a retaliatory bone in the direction of their attacker that travels up to 3 range, piercing any hostiles in its path.<0> Cherbrath Aspect requires:<10> Chokral Chazsal<0> c<1><4>Morph into Cherbrathalor <1>(<3>C<1>)<10>Crowd-controlling artillery strain.<0> -e<3><4>Sublime Shepherd <2>(passive)<10>All allies within 6 range of the source gain +2 armor when facing incoming attacks.<0> +¤<3><4>Sublime Shepherd <2>(passive)<10>All allies within 6 range of the source gain +2 armor when facing incoming attacks.<0> ¤<3><4>Ocsal Gestation <2>(passive)<10>This cell generates one Ocsal Larva every 14 seconds. Ocsal Larvae morph directly into mutated strains.<0> ¤<3><4>Swarmhold <2>(passive)<10>This cell generates one Larva every 14 seconds. Larvae generated by this cell create twice as many Zerg.<0> ¤<3><4>Recursion Rounds <2>(passive)<10>Each Cyclops attack leaves behind a dangerous shell that detonates after 2 seconds, damaging all combatants within 2 range.<0> <0> e<3><4>Cinder Mode <1>(<3>E<1>)<10>Switches forms, gaining 25% bonus attack speed and 2 armor, while disabling movement.<0> e<0><4>Tank Mode <1>(<3>E<1>)<10>Returns the Matador's weapon, armor, and mobility to normal.<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> +Ground<0> +Air<0> +Burrowed<0> +Cloaked<0> +Lifted Off<0> +Deployed<0> +Detector<0> +Detector (disabled)<0> +Structure<0> +Factory<0> +Addon<0> +Worker<0> +Hero<0> +Invincible<0> +Requires Cagra<0> +<10>Movespeed: <0> +<10>Sight Range: <0> +<10>Status: <0> +<10>Color: <0> +<10>Plane: <0> +<10>Flags: <0> +<10>Acceleration: <0> +<10>Turn Rate: <0> +<10>Transport Space: <0> +<10>Transport Capacity: <0> +<10>-- Hold <03>Shift<02> for more details --<0> +Size:<0> +<06>Unsafe<02><0> +<07>Safe<02><0> +<07>Ally Safe<02><0> +<03>Air Only<02><0> +<04>Normal Hit<02><0> +Non-Building<0> +Terrain<0> +<10>Armor Pen: <0> +<10>Attack Speed: <0> +<10>Cooldown: <0> +<10>DPS: <0> +<10>Range: <0> +Melee<0> +<10>Targets: <0> +<10>Splash Radius: <0> +<10>Splash Type: <0> +Apollyoid Adhesive<0> +Empowered<0> +Siphoned<0> +Deconstructed<0> +Petrified<0> +Observed<0> +Ensnared<0> +Whetted Appetite<0> +Anodyne Annex<0> +Shattered<0> +Ash Heap<0> +Cowardice<0> +Malice<0> +Controlled Demolition<0> +Emergency Detonation<0> +Ion Field<0> +Incineration<0> +Lobotomized<0> +Kelvin Munitions<0> +Hallucination<0> +Triumphant Rise<0> +Maelstrom<0> +Autovitality<0> +Terminal Surge<0> +Crisis of Faith<0> +Stellar Enforcement<0> +Adrenal Frenzy<0> +Caustic Discharge<0> +Incubating<0> +Kaiser Rampage<0> +Blinded<0> +Swarming Omen<0> +Mitosal Fog<0> +Pending Injection<0> +Vengeance<0> +Ascension<0> +Nanoshielded<0> +Activating Prying Eyes<0> +Corrosive Touch<0> +Hidebreaker<0> +Booming Blast<0> +Segmented Expansion<0> +Impact Dissipation<0> +Impact Prevarication<0> +Retaliation Protocol<0> +New Dominion<0> +Imploded<0> +Crippled<0> +Mechanical Rage<0> +Stunned<0> +Ensnaring Brood<0> +Cabeirus Feeders<0> +Sublime Shepherd<0> +Stonewall Protocol<0> +Reconstitution<0> +Controlled Opposition<0> +Energy Decay<0> +Khaydarin Charge<0> +Reclaimed<0> +Repentant Chorus<0> +Concurring Chorus<0> +Adaptive Amitosis<0> +Lucilleri Pheremones<0> +Solitary Focus<0> +Malefactor<0> +Prying Eyes<0> +Embedded<0> +Segmented Expansion<0> +Vital Remians<0> +Principal Augment<0> +Crushed<0> +Decided Armor<0> +Decided Reach<0> +Decided Piercing<0> +Decided Damage<0> +Decided Collateral (Inner)<0> +Decided Collateral (Medium)<0> +Decided Collateral (Outer)<0> +Power Siphon<0> +Entropy Gauntlets<0> +Tempo Up<0> +Tempo Down<0> +Phase Link<0> +Astral Rule<0> +Blissfully Embraced<0> +Tyrannized<0> +Worshiping<0> +Zombified<0> +Observing<0> +Dermal Accelerant<0> +Blissful Embrace<0> +Defensive Matrix<0> +Stimpack Injected<0> +Irradiated<0> +Maelstromed<0> +Plagued<0> +In Stasis<0> +Timed Life<0> +Cannot Attack<0> +Under Carapace Swarm<0> <0> <0> <0> @@ -2306,14 +2306,14 @@ Epitaph Grenade Launcher<0> Scalpel Cannon<0> Reactive Blaster<0> Plasmathrower<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> -<0> +High-Tonnage Payload<0> +Gauss Launcher<0> +Boreal Railguns<0> +Twinstrike Cannons<0> +Twinflak Cannons<0> +Hellfire Missile Pack<0> +Vigil Autocannon<0> +Flamethrower<0> <0> <0> <0> diff --git a/mpq/rez/unitnames.tbl b/mpq/rez/unitnames.tbl index 7c2c17f..483b4f5 100644 Binary files a/mpq/rez/unitnames.tbl and b/mpq/rez/unitnames.tbl differ diff --git a/mpq/rez/unitnames.txt b/mpq/rez/unitnames.txt new file mode 100644 index 0000000..044cd15 --- /dev/null +++ b/mpq/rez/unitnames.txt @@ -0,0 +1,1540 @@ +Terran Maverick<0>*<0>Ground Units<0> +Terran Eidolon<0>*<0>Ground Units<0> +Terran Vulture<0>*<0>Ground Units<0> +Terran Goliath<0>*<0>Ground Units<0> +Goliath Turret<0>*<0>Special<0> +Terran Phalanx<0>Tank Mode<0>Ground Units<0> +Phalanx Turret<0>*<0>Special<0> +Terran Mason<0>*<0>Ground Units<0> +Terran Wraith<0>*<0>Air Units<0> +Terran Seraph<0>*<0>Air Units<0> +Terran Apostle<0>*<0>Ground Units<0> +Terran Trojan<0>*<0>Air Units<0> +Terran Minotaur<0>*<0>Air Units<0> +Terran Spider Mine<0>*<0>Special<0> +Terran Morningstar<0>*<0>Special<0> +Terran Shaman<0>Support Mode<0>Ground Units<0> +Protoss Manifold<0>*<0>Ground Units<0> +Protoss Architect<0>*<0>Ground Units<0> +Terran Madcap<0>*<0>Ground Units<0> +Terran Cuirass<0>*<0>Ground Units<0> +Terran Talos<0>*<0>Air Units<0> +Protoss Star Sovereign<0>*<0>Air Units<0> +Terran Salamander<0>*<0>Air Units<0> +Terran Gorgon<0>*<0>Air Units<0> +Terran Phobos<0>*<0>Air Units<0> +Protoss Gladius<0>*<0>Air Units<0> +Protoss Magister<0>*<0>Air Units<0> +Terran Madrigal<0>Imperioso Mode<0>Ground Units<0> +Terran Centaur<0>*<0>Air Units<0> +Zerg Almaksalisk<0>*<0>Air Units<0> +Terran Phalanx<0>Siege Mode<0>Ground Units<0> +Phalanx Siege Turret<0>*<0>Special<0> +Terran Harakan<0>*<0>Ground Units<0> +Scanner Sweep<0>*<0>Special<0> +Terran Cleric<0>*<0>Ground Units<0> +Zerg Larva<0>*<0>Special<0> +Zerg Egg<0>*<0>Special<0> +Zerg Zethrokor<0>*<0>Ground Units<0> +Zerg Hydralisk<0>*<0>Ground Units<0> +Zerg Ultrokor<0>*<0>Ground Units<0> +Zerg Rilirokor<0>*<0>Ground Units<0> +Zerg Droleth<0>*<0>Ground Units<0> +Zerg Ovileth<0>*<0>Air Units<0> +Zerg Mutalisk<0>*<0>Air Units<0> +Zerg Geszithalor<0>*<0>Air Units<0> +Zerg Matraleth<0>*<0>Air Units<0> +Zerg Isthrathaleth<0>*<0>Ground Units<0> +Zerg Gosvileth<0>*<0>Unused<0> +Zerg Alkajelisk<0>*<0>Air Units<0> +Terran Pazuzu<0>*<0>Ground Units<0> +Terran Cohort<0>*<0>Factional Units<0> +Zerg Kalkalisk<0>*<0>Air Units<0> +Zerg Evigrilisk<0>*<0>Ground Units<0> +Terran Penumbra<0>*<0>Ground Units<0> +Zerg Nathrokor<0>*<0>Air Units<0> +Terran Cyclops<0>*<0>Ground Units<0> +Zerg Gorgrokor<0>*<0>Air Units<0> +Zerg Othstoleth<0>*<0>Air Units<0> +Terran Valkyrie<0>*<0>Air Units<0> +Zerg Cocoon<0>*<0>Special<0> +Protoss Lanifect<0>*<0>Air Units<0> +Protoss Cabalist<0>*<0>Ground Units<0> +Zerg Vithrilisk<0>*<0>Air Units<0> +Protoss Mind Tyrant<0>*<0>Ground Units<0> +Protoss Scribe<0>*<0>Ground Units<0> +Protoss Zealot<0>*<0>Ground Units<0> +Protoss Dracadin<0>*<0>Ground Units<0> +Protoss Cantavis<0>*<0>Ground Units<0> +Protoss Archon<0>*<0>Ground Units<0> +Protoss Envoy<0>*<0>Air Units<0> +Protoss Panoptus<0>*<0>Air Units<0> +Protoss Didact<0>*<0>Air Units<0> +Protoss Solarion<0>*<0>Air Units<0> +Protoss Steward<0>*<0>Air Units<0> +Protoss Legionnaire<0>*<0>Ground Units<0> +Protoss Amaranth<0>*<0>Ground Units<0> +Protoss Hierophant<0>*<0>Ground Units<0> +Terran Heracles<0>*<0>Ground Units<0> +Protoss Atreus<0>*<0>Ground Units<0> +Protoss Ecclesiast<0>*<0>Ground Units<0> +Protoss Aurora<0>*<0>Air Units<0> +Protoss Clarion<0>*<0>Air Units<0> +Protoss Empyrean<0>*<0>Air Units<0> +<0> +Protoss Witness<0>*<0>Air Units<0> +Protoss Plasma Shell<0>*<0>Ground Units<0> +Protoss Demiurge<0>*<0>Ground Units<0> +Protoss Pariah<0>*<0>Ground Units<0> +Tassadar<0>*<60><62>Heroes<0> +Protoss Simulacrum<0>*<0>Ground Units<0> +Protoss Charlatan<0>*<0>Ground Units<0> +Terran Wyvern<0>*<0>Air Units<0> +Terran Cyprian<0>*<0>Ground Units<0> +Zerg Rililisk<0>*<0>Air Units<0> +Protoss Exemplar<0>*<0>Air Units<0> +Zerg Quazilisk<0>*<0>Ground Units<0> +Zerg Keskathalor<0>*<0>Ground Units<0> +Zerg Zoryusthaleth<0>*<0>Ground Units<0> +Terran Azazel<0>*<0>Air Units<0> +Protoss Idol<0>*<0>Ground Units<0> +Protoss Golem<0>*<0>Ground Units<0> +Map Revealer<0>*<0>Special<0> +Protoss Augur<0>*<0>Ground Units<0> +Zerg Lakizilisk<0>*<0>Ground Units<0> +Protoss Barghest<0>*<0>Ground Units<0> +Disruption Field<0>*<0>Special<0> +Terran Ministry<0>*<0>Buildings<0> +Terran Comsat Station<0>*<0>Addons<0> +Terran Anvil<0>*<0>Addons<0> +Terran Supply Depot<0>*<0>Buildings<0> +Terran Reservoir<0>*<0>Buildings<0> +Terran Stockade<0>*<0>Buildings<0> +Zerg Liiralisk<0>*<0>Ground Units<0> +Terran Fulcrum<0>*<0>Buildings<0> +Terran Starport<0>*<0>Buildings<0> +Terran Commandment<0>*<0>Addons<0> +Terran Daedala<0>*<0>Buildings<0> +Terran Covenant<0>*<0>Addons<0> +Terran Magnetar<0>*<0>Air Units<0> +Terran Vestry<0>*<0>Addons<0> +Terran Palladium<0>*<0>Addons<0> +Terran Rotary<0>*<0>Addons<0> +Terran Atlas<0>*<0>Buildings<0> +Zerg Sovroleth<0>*<0>Air Units<0> +Terran Watchdog<0>*<0>Buildings<0> +Terran Anchor<0>*<0>Buildings<0> +Zerg Kagralisk<0>*<0>Ground Units<0> +Terran Diadem<0>*<0>Buildings<0> +Zerg Vorvrokor<0>*<0>Ground Units<0> +Zerg Bactalisk<0>*<0>Ground Units<0> +Zerg Axtoth Axis<0>*<0>Buildings<0> +Zerg Hachirosk<0>*<0>Buildings<0> +Zerg Caphrolosk<0>*<0>Buildings<0> +Zerg Gathtelosk<0>*<0>Buildings<0> +Zerg Nydus Cesiant<0>*<0>Buildings<0> +Zerg Hydrith Den<0>*<0>Buildings<0> +Zerg Rakzogth Roost<0>*<0>Buildings<0> +Terran Olympian<0>*<0>Ground Units<0> +Zerg Matravil Nest<0>*<0>Buildings<0> +Zerg Almakis Antre<0>*<0>Buildings<0> +Zerg Ulgorg Cavern<0>*<0>Buildings<0> +Zerg Mutath Spire<0>*<0>Buildings<0> +Zerg Quazeth Pool<0>*<0>Buildings<0> +Zerg Cagrant Cesiant<0>*<0>Buildings<0> +Zerg Spraith Cesiant<0>*<0>Buildings<0> +Terran Autocrat<0>*<0>Ground Units<0> +Zerg Surkith Cesiant<0>*<0>Buildings<0> +Terran Guildhall<0>*<0>Addons<0> +Terran Striga<0>*<0>Ground Units<0> +Zerg Excisant<0>*<0>Buildings<0> +Terran Luminary<0>*<0>Factional Units<0> +Terran Siren<0>*<0>Ground Units<0> +Zerg Othstol Oviform<0>*<0>Buildings<0> +Zerg Tethvith Swamp<0>*<0>Buildings<0> +Protoss Nexus<0>*<0>Buildings<0> +Protoss Lattice<0>*<0>Buildings<0> +Protoss Pylon<0>*<0>Buildings<0> +Protoss Aquifer<0>*<0>Buildings<0> +Protoss Automaton Register<0>*<0>Buildings<0> +Protoss Prostration Stage<0>*<0>Buildings<0> +Protoss Gateway<0>*<0>Buildings<0> +Protoss Rogue Gallery<0>*<0>Buildings<0> +Protoss Warden<0>*<0>Buildings<0> +Terran Fountainhead<0>*<0>Buildings<0> +Protoss Cenotaph<0>*<0>Buildings<0> +Protoss Ancestral Archives<0>*<0>Buildings<0> +Protoss Embassy<0>*<0>Buildings<0> +Protoss Stargate<0>*<0>Buildings<0> +Protoss Argosy<0>*<0>Buildings<0> +Protoss Fleet Beacon<0>*<0>Buildings<0> +Zerg Alkag Iteth<0>*<0>Buildings<0> +Protoss Synthetic Synod<0>*<0>Buildings<0> +Protoss Vagrant<0>*<0>Ground Units<0> +Zerg Alaszileth<0>*<0>Air Units<0> +Terran Quarry<0>*<0>Addons<0> +Terran Tinkerer's Tower<0>*<0>Addons<0> +Mineral Field<0>Type 1<0>Resources<0> +Mineral Field<0>Type 2<0>Resources<0> +Mineral Field<0>Type 3<0>Resources<0> +Protoss Anthelion<0>*<0>Air Units<0> +Zerg Izirokor<0>*<0>Ground Units<0> +Zerg Irulent Ivoa<0>*<0>Buildings<0> +Protoss Artisan<0>*<0>Air Units<0> +Protoss Empress<0>*<0>Air Units<0> +Protoss Prudence<0>*<0>Air Units<0> +Zerg Skithrokor<0>*<0>Air Units<0> +Terran Paladin<0>*<0>Ground Units<0> +Terran Savant<0>*<0>Ground Units<0> +Vespene Geyser<0>*<0>Resources<0> +Terran Hadron<0>*<0>Addons<0> +Terran Biotic Bastion<0>*<0>Addons<0> +Zerg Axitrilisk<0>*<0>Ground Units<0> +Town Center Marker<0>*<0>Special<0> +Zerg Zorkiz Shroud<0>*<0>Buildings<0> +Terran Aspirant<0>*<0>Factional Units<0> +Terran Blackjack<0>*<0>Ground Units<0> +Terran Claymore<0>*<0>Ground Units<0> +Zerg Tosvrol Haunt<0>*<0>Buildings<0> +Terran Iron Foundry<0>*<0>Buildings<0> +Terran Captaincy<0>*<0>Buildings<0> +Terran Scrapyard<0>*<0>Buildings<0> +Protoss Crucible<0>*<0>Buildings<0> +Dark Swarm<0>*<0>Special<0> +Floor Missile Trap<0>*<0>Special<0> +Zerg Kalkiir Lake<0>*<0>Buildings<0> +Left Upper Level Door<0>*<0>Doors<0> +Right Upper Level Door<0>*<0>Doors<0> +Left Pit Door<0>*<0>Doors<0> +Right Pit Door<0>*<0>Doors<0> +Floor Gun Trap<0>*<0>Special<0> +Left Wall Missile Trap<0>*<0>Special<0> +Left Wall Flame Trap<0>*<0>Special<0> +Right Wall Missile Trap<0>*<0>Special<0> +Right Wall Flame Trap<0>*<0>Special<0> +Start Location<0>*<0>U<0> +Terran Treasury<0>*<0>Buildings<0> +Zerg Larvosk Cesiant<0>*<0>Buildings<0> +Zerg Konvilisk<0>*<0>Ground Units<0> +Zerg Akistrokor<0>*<0>Air Units<0> +Zerg Geszkath Grotto<0>*<0>Buildings<0> +Protoss Ardent Authority<0>*<0>Buildings<0> +Vespene Ridge<0>*<0>Resources<0> +Zerg Iroleth<0>*<0>Air Units<0> +Protoss Monument of Sin<0>*<0>Buildings<0> +Zerg Irol Iris<0>*<0>Buildings<0> +Protoss Sanctum of Sorrow<0>*<0>Buildings<0> +Protoss Grand Library<0>*<0>Buildings<0> +Zerg Sibraelosk<0>*<0>Buildings<0> +Reserved<0>*<0>*<0> +Reserved<0>*<0>*<0> +Reserved<0>*<0>*<0> +Reserved<0>*<0>*<0> +Reserved<0>*<0>*<0> +Reserved<0>*<0>*<0> +Reserved<0>*<0>*<0> +Reserved<0>*<0>*<0> +Reserved<0>*<0>*<0> +Reserved<0>*<0>*<0> +Reserved<0>*<0>*<0> +Reserved<0>*<0>*<0> +Reserved<0>*<0>*<0> +Reserved<0>*<0>*<0> +Reserved<0>*<0>*<0> +Reserved<0>*<0>*<0> +Reserved<0>*<0>*<0> +Reserved<0>*<0>*<0> +Reserved<0>*<0>*<0> +Reserved<0>*<0>*<0> +Reserved<0>*<0>*<0> +Reserved<0>*<0>*<0> +Reserved<0>*<0>*<0> +Reserved<0>*<0>*<0> +Protoss Matrix<0>*<0>Buildings<0> +Terran Sundog<0>*<0>Air Units<0> +Terran Starpad<0>*<0>Buildings<0> +Terran Ancile<0>*<0>Air Units<0> +Terran Matador<0>*<0>Ground Units<0> +Terran Future Station<0>*<0>Addons<0> +Zerg Zarcavrokor<0>*<0>Air Units<0> +Terran Cestus<0>*<0>Buildings<0> +Terran Sentinel<0>*<0>Buildings<0> +Terran Nanite Assembly<0>*<0>Buildings<0> +Terran Hippogriff<0>*<0>Air Units<0> +Terran Tarasque<0>*<0>Factional Units<0> +Terran Aion<0>*<0>Ground Units<0> +Protoss Herald<0>*<0>Ground Units<0> +Protoss Epigraph<0>*<0>Air Units<0> +Zerg Tethzorokor<0>*<0>Ground Units<0> +Zerg Protathalor<0>*<0>Ground Units<0> +Zerg Vilgorokor<0>*<0>Ground Units<0> +Zerg Cikralisk<0>*<0>Ground Units<0> +Zerg Tosgrilisk<0>*<0>Air Units<0> +Zerg Ghitorokor<0>*<0>Air Units<0> +Zerg Zobriolisk<0>*<0>Ground Units<0> +Zerg Tetcaerokor<0>*<0>Air Units<0> +Terran Wendigo<0>*<0>Air Units<0> +Terran Southpaw<0>*<0>Ground Units<0> +Zerg Selkerilisk<0>*<0>Ground Units<0> +Protoss Strident Stratum<0>*<0>Buildings<0> +Protoss Auxiliary Oasis<0>*<0>Buildings<0> +Terran Mantle<0>*<0>Buildings<0> +Terran Ramesses<0>*<0>Ground Units<0> +Terran Durendal<0>*<0>Ground Units<0> +Terran Cataphract<0>*<0>Ground Units<0> +Terran Apothecary<0>*<0>Buildings<0> +Terran Dilettante<0>*<0>Ground Units<0> +Terran Sevenstep<0>*<0>Ground Units<0> +Terran Hypnagogue<0>*<0>Ground Units<0> +Terran Parthenon<0>*<0>Buildings<0> +Terran Anticthon<0>*<0>Ground Units<0> +Terran Pythean<0>*<0>Air Units<0> +Zerg Ogroszaleth<0>*<0>Ground Units<0> +Zerg Spirtith Cesiant<0>*<0>Buildings<0> +Zerg Skortrith Cesiant<0>*<0>Buildings<0> +Protoss Engram<0>*<0>Buildings<0> +unused<0>*<0>Buildings<0> +unused<0>*<0>Buildings<0> +Terran Thespian<0>*<0>Ground Units<0> +Terran Silvertongue<0>*<0>Ground Units<0> +Terran Throneroom<0>*<0>Addons<0> +Terran Emperor<0>*<0>Ground Units<0> +Terran Jester<0>*<0>Ground Units<0> +Zerg Agrileth<0>*<0>Ground Units<0> +Zerg Kethraj Keep<0>*<0>Buildings<0> +Protoss Sequestered Icon<0>*<0>Buildings<0> +Protoss Unitary Union<0>*<0>Buildings<0> +Protoss Servitor<0>*<0>Ground Units<0> +Protoss Positron<0>*<0>Ground Units<0> +Protoss Analogue<0>*<0>Ground Units<0> +Protoss Unar<0>*<0>Ground Units<0> +Protoss Maven<0>*<0>Ground Units<0> +Protoss Cloudform<0>*<0>Air Units<0> +Protoss Vibrance<0>*<0>Ground Units<0> +Protoss Oscilliant<0>*<0>Ground Units<0> +Protoss Potentate<0>*<0>Ground Units<0> +Protoss Sycophant<0>*<0>Ground Units<0> +Protoss Optecton<0>*<0>Ground Units<0> +Protoss Patriarch<0>*<0>Ground Units<0> +Protoss Apostate<0>*<0>Ground Units<0> +Zerg Mortothrokor<0>*<0>Ground Units<0> +Zerg Cherbrathalor<0>*<0>Ground Units<0> +Zerg Okrimnilisk<0>*<0>Ground Units<0> +Zerg Algoztalisk<0>*<0>Air Units<0> +Zerg Elthrazalisk<0>*<0>Ground Units<0> +Zerg Begrothilisk<0>*<0>Ground Units<0> +Zerg Oztukrokor<0>*<0>Ground Units<0> +Zerg Kethrostalor<0>*<0>Ground Units<0> +Zerg Rakzilisk<0>*<0>Ground Units<0> +Terran Philoc<0>*<0>Factional Units<0> +Zerg Begrozith Barrow<0>*<0>Buildings<0> +Zerg Chokral Chazsal<0>*<0>Buildings<0> +Protoss Bulwark<0>*<0>Air Units<0> +Terran Civilian<0>*<0>Special<0> +Sarah Kerrigan<0>*<0>Heroes<0> +Infested Kerrigan<0>*<0>Heroes<0> +Crashed Minotaur<0>*<0>Special Buildings<0> +Terran Psi Disruptor<0>*<0>Special Buildings<0> +Terran Power Generator<0>*<0>Special Buildings<0> +Zerg Overmind<0>*<0>Special Buildings<0> +Zerg Overmind<0>(With Shell)<0>Special Buildings<0> +Zerg Chrysalis<0>*<0>Special Buildings<0> +Zerg Cerebrate<0>*<0>Special Buildings<0> +Zerg Overmind Cocoon<0>*<0>Special Buildings<0> +Khaydarin Formation<0>*<0>Special Buildings<0> +Protoss Temple<0>*<0>Special Buildings<0> +Xel'Naga Temple<0>*<0>Special Buildings<0> +Protoss Warp Gate<0>*<0>Special Buildings<0> +Protoss Stasis Cell<0>*<0>Special Buildings<0> +Protoss Monogram<0>*<0>Ground Units<0> +Protoss Hall of Heretics<0>*<0>Buildings<0> +Zerg Nephrilosk<0>*<0>Buildings<0> +Protoss Vagrant Shade<0>*<0>Special<0> +Protoss Accantor<0>*<0>Ground Units<0> +Zerg Ocsal Larva<0>*<0>Special<0> +Zerg Ocsal Cesiant<0>*<0>Buildings<0> +Zerg Kazitrith Cesiant<0>*<0>Buildings<0> +Reserved<0>Buttonset Ocsal Larva Swarm<0>*<0> +Reserved<0>Buttonset Ocsal Larva Assault<0>*<0> +Reserved<0>Buttonset Ocsal Larva Control<0>*<0> +Terran Control Node<0>*<0>Special Buildings<0> +Protoss Vassal<0>*<0>Air Units<0> +Reserved<0>Buttonset Mixed Mason Training<0>*<0> +Daniel's Son<0>*<0>Special Units<0> +Smoochie Boy<0>*<0>Special Units<0> +Zerg Ezigrisant<0>*<0>Buildings<0> +Terran Wellbore<0>*<0>Buildings<0> +Protoss Pennant<0>*<0>Buildings<0> +<0> +Reserved<0>Buttonset Basic Police Structures<0>*<0> +Reserved<0>Buttonset Advanced Police Structures<0>*<0> +<0> +Terran Matador<0>Cinder Mode<0>Ground Units<0> +Terran Cuirass<0>Trench Mode<0>Ground Units<0> +Matador Turret<0>Tank Mode<0>*<0> +Matador Turret<0>Cinder Mode<0>*<0> +Terran Lobotomy Mine<0>*<0>*<0> +Wyvern Turret<0>*<0>*<0> +Zerg Axitrilisk<0>Weaponless<0>Ground Units<0> +Zerg Vilgoleth<0>*<0>Ground Units<0> +Terran Shaman<0>Visionary Mode<0>Ground Units<0> +Madrigal Turret<0>Imperioso<0>*<0> +Terran Madrigal<0>Furia Mode<0>Ground Units<0> +Madrigal Turret<0>Furia<0>*<0> +Omnivale<0>*<0>Special Buildings<0> +Terran Lodestone<0>*<0>Addons<0><0> +Floor Hatch<0>*<0>*<0> +<0>*<0>*<0> +Terran Lodestone<0>*<0>Addons<0><0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +Terran Hotshot<0>*<0>Factional Units<0> +Zerg Vornath Pond<0>*<0>Buildings<0> +Zerg Skibact Scab<0>*<0>Buildings<0> +Terran Qilin<0>*<0>Factional Units<0> +Terran Auriel<0>*<0>Factional Units<0> +Protoss Adherent<0>*<0>Factional Units<0> +Protoss Extatus<0>*<0>Factional Units<0> +Zerg Nathrelisk<0>*<0>Factional Units<0> +Zerg Iziralisk<0>*<0>Factional Units<0> +<0> +<0> +Terran Trenchfoot<0>*<0>Buildings<0> +Zerg Sasyrvoleth<0>*<0>Air Units<0> +Terran Tencendur<0>*<0>Buildings<0> +Ackmed<0>Harakan<0>Heroes<0> +Terran Cyclops<0>Futurist Federation<0>Factional Units<0> +Protoss Zealot<0>Starbound<0>Factional Units<0> +Protoss Ecclesiast<0>Khalendric Knights<0>Factional Units<0> +Terran Harakan<0>Golden Republic<0>Factional Units<0> +Protoss Cicatus<0>*<0>Factional Units<0> +Zerg Inzorthrokor<0>*<0>Factional Units<0> +Volatile Egg<0>*<0>Special<0> +Terran Piety Ward<0>*<0>Special<0> +Terran Cleric<0>Futurist Federation<0>Factional Units<0> +Terran Sieve<0>*<0>Buildings<0> +Protoss Cedent<0>*<0>Buildings<0> +Zerg Eskigant<0>*<0>Buildings<0> +Zerg Quazrokor<0>Zorthos Tendril<0>Factional Units<0> +Protoss Renesair<0>Order of the Sacred Saber<0>Factional Units<0> +Protoss Ashguard<0>Khalendric Knights<0>Factional Units<0> +Zerg Lakizilisk<0>Zorthos Tendril<0>Factional Units<0> +Protoss Xenolith<0>*<0>Buildings<0> +Terran Facade<0>*<0>Buildings<0> +Terran Savant<0>Power Siphon<0>Ground Units<0> +Askosi Landlock<0>*<0>Buildings<0> +Protoss Dracadin<0>Order of the Sacred Saber<0>Factional Units<0> +Terran Blackjack<0>Golden Republic<0>Factional Units<0> +Terran Eidolon<0>Nydus Trinity<0>Factional Units<0> +Terran Tiangou<0>Base<0>Factional Units<0> +Terran Tiangou<0>Turret<0>Factional Units<0> +Terran Maverick<0>Futurist Federation<0>Factional Units<0> +Zerg Hydralisk<0>Orkoti Tendril<0>Factional Units<0> +Protoss Manifold<0>Starbound<0>Factional Units<0> +Zerg Yblyleth<0>Zorthos Tendril<0>Factional Units<0> +Askosi Pilgrim<0>*<0>Ground Units<0> +Basic Askosi Facilities<0>*<0>*<0> +Advanced Askosi Facilities<0>*<0>*<0> +Supreme Askosi Facilities<0>*<0>*<0> +Askosi Proselyte<0>*<0>Ground Units<0> +Askosi Dyad<0>*<0>Ground Units<0> +Askosi Missionary<0>*<0>Ground Units<0> +Askosi Cardinal<0>*<0>Ground Units<0> +Askosi Mimic<0>*<0>Ground Units<0> +Askosi Vicar<0>*<0>Ground Units<0> +Askosi Rove<0>*<0>Ground Units<0> +Askosi Object<0>*<0>Ground Units<0> +Askosi Scepter<0>*<0>Ground Units<0> +Askosi Intendent<0>*<0>Ground Units<0> +Askosi Helion<0>*<0>Air Units<0> +Askosi Emissary<0>*<0>Air Units<0> +Askosi Inkblot<0>*<0>Air Units<0> +Askosi Tirade<0>*<0>Air Units<0> +Askosi Arch<0>*<0>Buildings<0> +Askosi Grandstand<0>Cannon Module<0>Buildings<0> +Askosi Chantry<0>*<0>Buildings<0> +Askosi Radix<0>*<0>Buildings<0> +Askosi Cipher<0>*<0>Buildings<0> +Askosi Function<0>*<0>Buildings<0> +Askosi Gauntlet<0>*<0>Buildings<0> +Askosi Cosmoscope<0>*<0>Buildings<0> +Ragnasaur<0>*<0>Critters<0> +Rhynadon<0>*<0>Critters<0> +Bengalaas<0>*<0>Critters<0> +Scantid<0>*<0>Critters<0> +Ursadon<0>*<0>Critters<0> +Kakaru<0>*<0>Critters<0> +Flag<0>*<0>Powerups<0> +Young Chrysalis<0>*<0>Powerups<0> +Psi Emitter<0>*<0>Powerups<0> +Data Disk<0>*<0>Powerups<0> +Khaydarin Crystal<0>*<0>Powerups<0> +Uraj<0>*<0>Powerups<0> +Khalis<0>*<0>Powerups<0> +Mineral Chunk<0>*<0>Powerups<0> +Mineral Chunk<0>Depleted<0>Powerups<0> +Vespene Barrel<0>*<0>Powerups<0> +Vespene Barrel<0>Depleted<0>Powerups<0> +Vespene Tank<0>*<0>Powerups<0> +Vespene Tank<0>Depleted<0>Powerups<0> +Vespene Sac<0>*<0>Powerups<0> +Vespene Sac<0>Depleted<0>Powerups<0> +Terran Beacon<0>*<0>Special<0> +Protoss Beacon<0>*<0>Special<0> +Zerg Beacon<0>*<0>Special<0> +Terran Blackguard<0>*<0>Faction Units<0> +Terran Arhaun<0>*<0>Faction Units<0> +Arhaun Turret<0>*<0>Faction Units<0> +Reserved<0>Buttonset Terran Addon Submenu<0>*<0> +Zerg Zozarc Gorge<0>*<0>Buildings<0> +Terran Ogun<0>Worker Mode<0>Ground Units<0> +Protoss Autocort<0>*<0>Ground Units<0> +Terran Cannibal<0>*<0>Factional Units<0> +Terran Ogun<0>Smithy Mode<0>Ground Units<0> +Basic Zerg Mutations<0>*<0>*<0> +Advanced Zerg Mutations<0>*<0>*<0> +Francisco Goska<0>Eidolon<0>Heroes<0> +Stroluum<0>Magnorokor<0>Heroes<0> +Cerebrate Tuzor<0>*<0>Special Buildings<0> +Zerg Skryrokor<0>*<0>Air Units<0> +Terran Madrigal<0>Hecaton Imperioso<0>Factional Units<0> +Madrigal Turret<0>Hecaton Imperioso<0>Special<0> +Terran Vulture<0>Hecaton<0>Factional Units<0> +Terran Tartarus Mine<0>Hecaton<0>Special<0> +Terran Madrigal<0>Hecaton Furia<0>Factional Units<0> +Madrigal Turret<0>Hecaton Furia<0>Special<0> +Askosi Bounty<0>*<0>Buildings<0> +Zerg Azanthrokor<0>Orkoti Tendril<0>Factional Units<0> +Terran Triton<0>*<0>Ground Units<0> +Triton Turret<0>*<0>Special<0> +Mineral Field<0>Rich 1<0>Resources<0> +Mineral Field<0>Rich 2<0>Resources<0> +Mineral Field<0>Rich 3<0>Resources<0> +Mineral Chunk<0>Rich<0>Powerups<0> +Mineral Chunk<0>Rich Depleted<0>Powerups<0> +Zerg Sovrokor<0>Goszirith Tendril<0>Factional Units<0> +Terran Valkyrie<0>Hecaton<0>Factional Units<0> +Zerg Garvrokor<0>Goszirith Tendril<0>Factional Units<0> +Protoss Simulacrum<0>Astral Omen<0>Factional Units<0> +Protoss Warlock<0>Astral Omen<0>Factional Units<0> +Scenario Unit 1<0>*<0>Special<0> +Scenario Unit 2<0>*<0>Special<0> +Scenario Unit 3<0>*<0>Special<0> +Scenario Unit 4<0>*<0>Special<0> +Scenario Unit 5<0>*<0>Special<0> +Scenario Unit 6<0>*<0>Special<0> +Scenario Unit 7<0>*<0>Special<0> +Scenario Unit 8<0>*<0>Special<0> +Askosi Grandstand<0>Holdout Module<0>Buildings<0> +Askosi Grandstand<0>Vision Module<0>Buildings<0> +Protoss Warp Gate<0>The Fall<0>Special Buildings<0> +Zerg Cerebrate<0>The Fall<0>Special Buildings<0> +Zerg Overmind<0>The Fall (With Shell)<0>Special Buildings<0> +Zerg Overmind<0>The Fall<0>Special Buildings<0> +Askosi Avatar<0>*<0>Ground Units<0> +Askosi Abutment<0>*<0>Buildings<0> +Askosi Proscenium<0>*<0>Buildings<0> +Terran Quadriga<0>Golden Republic<0>Factional Units<0> +Askosi Thaumalogue<0>*<0>Ground Units<0> +Askosi Petract<0>*<0>Ground Units<0> +Askosi Crematorium<0>*<0>Air Units<0> +Askosi Zylode<0>*<0>Buildings<0> +Askosi Astrolabe<0>*<0>Buildings<0> +Terran Serathiel<0>Hecaton Coalition<0>Factional Units<0> +Zerg Malkothrokor<0>*<0>Ground Units<0> +<0> +Askosi Panoply<0>*<0>Structures<0> +Askosi Aphorist<0>*<0>Ground Units<0> +Askosi Doronin<0>*<0>Ground Units<0> +Askosi Agonist<0>*<0>Ground Units<0> +Askosi Phontis<0>*<0>Ground Units<0> +Askosi Zonguard<0>*<0>Ground Units<0> +Askosi Akreno<0>*<0>Air Units<0> +Askosi Iconoclast<0>*<0>Air Units<0> +Askosi Paraclete<0>*<0>Air Units<0> +Zerg Zethalor<0>Zorthos Tendril<0>Factional Units<0> +Zerg Scrylyleth<0>Zorthos Tendril<0>Factional Units<0> +Askosi Bestiary<0>*<0>Structures<0> +Askosi Conduit<0>*<0>Structures<0> +Askosi Obelisk<0>*<0>Structures<0> +Askosi Eyelet<0>*<0>Special Units<0> +Askosi Auxine<0>*<0>Special Units<0> +Askosi Constituent<0>*<0>Air Units<0> +Terran Goremast<0>Upstart<0>Factional Units<0> +Terran Broadside<0>Upstart<0>Factional Units<0> +Broadside Turret<0>Upstart<0>Factional Units<0> +Terran Vulture<0>Upstart<0>Factional Units<0> +Terran Cutlass<0>Futurist Federation<0>Factional Units<0> +Cutlass Turret<0>Futurist Federation<0>Factional Units<0> +Terran Maverick<0>Upstart<0>Factional Units<0> +Protoss Tritius<0>Astral Omen<0>Factional Units<0> +Terran Morrigan<0>Upstart<0>Factional Units<0> +Terran Ajax<0>Futurist Federation<0>Factional Units<0> +Askosi Dorminge<0>*<0>Structures<0> +Askosi Lotiro<0>*<0>Structures<0> +Askosi Domain<0>*<0>Structures<0> +Terran Maverick<0>Golden Republic<0>Factional Units<0> +Terran Shaman<0>Support, Upstart<0>Factional Units<0> +Terran Shaman<0>Adrenaline, Upstart<0>Factional Units<0> +Askosi Insurant<0>*<0>Ground Units<0> +Askosi Silversoul<0>*<0>Ground Units<0> +Askosi Ghostwrit<0>*<0>Ground Units<0> +Askosi Azjoran<0>*<0>Ground Units<0> +Askosi Elgird<0>*<0>Ground Units<0> +Askosi Histrion<0>*<0>Ground Units<0> +Askosi Egocent<0>*<0>Special Units<0> +Askosi Alacyne<0>*<0>Ground Units<0> +Askosi Begolor<0>*<0>Ground Units<0> +Askosi Limire<0>*<0>Air Units<0> +Askosi Endbore<0>*<0>Air Units<0> +Askosi Tortare<0>*<0>Air Units<0> +Askosi Cybrene<0>*<0>Air Units<0> +Askosi Lekrot<0>*<0>Structures<0> +Askosi Hearthshard<0>*<0>Structures<0> +Terran Nuriel<0>*<0>Factional Units<0> +Terran Phoenix<0>*<0>Factional Units<0> +Terran Archbishop<0>*<0>Factional Units<0> +Protoss Pathlight<0>*<0>Factional Units<0> +Protoss Saladius<0>*<0>Factional Units<0> +Protoss Garantis<0>*<0>Factional Units<0> +Zerg Zoltorokor<0>*<0>Factional Units<0> +Forerunner Ferrum<0>*<0>Air Units<0> +Forerunner Chalyb<0>*<0>Air Units<0> +Forerunner Circitor<0>*<0>Air Units<0> +Forerunner Exigo<0>*<0>Air Units<0> +Forerunner Athla<0>*<0>Air Units<0> +Forerunner Vicere<0>*<0>Air Units<0> +Forerunner Machinamentum<0>*<0>Structures<0> +Infested Kerrigan<0>Big<0>Heroes<0> +Jim Raynor<0>Vulture<0>Heroes<0> +Norad II<0>Minotaur<0>Heroes<0> +Askosi Scralia<0>Sons of Ash<0>Factional Units<0> +Zerg Rozirokor<0>Imicren Tendril<0>Factional Units<0> +Bloodsummon Thrombocyte<0>*<0>Ground Units<0> +Bloodsummon Grimoire<0>*<0>Structures<0> +Zerg Zytryleth<0>Zorthos Tendril<0>Factional Units<0> +Terran Camazotz<0>Nydus Trinity<0>Factional Units<0> +Protoss Simulacrum<0>Khalendric Knights<0>Factional Units<0> +Protoss Idol<0>Khalendric Knights<0>Factional Units<0> +Protoss Vestige<0>Starbound<0>Factional Units<0> +Terran Arquebus<0>Hecaton Coalition<0>Factional Units<0> +Bloodsummon Acqui<0>*<0>Ground Units<0> +Zerg Alzurokor<0>Imicren Tendril<0>Factional Units<0> +Zerg Hydrokor<0>Goszirith Tendril<0>Factional Units<0> +Protoss Gladius<0>Order of the Sacred Saber<0>Factional Units<0> +Terran Eidolon<0>Golden Republic<0>Factional Units<0> +Zerg Zethalisk<0>Orkoti Tendril<0>Factional Units<0> +Bloodsummon Nihilist<0>*<0>Ground Units<0> +Faction Selection Askosi<0>*<0>*<0> +Terran Fleshthief<0>Nydus Trinity<0>Factional Units<0> +Forerunner Lumen<0>*<0>Air Units<0> +Ammo Crate<0>*<0>Powerups<0> +Medkit<0>*<0>Powerups<0> +Battery Cell<0>*<0>Powerups<0> +Forerunner Buildings<0>Buttonset<0>Unused<0> +Terran Eveningstar<0>*<0>*<0> +Jim Raynor<0>Maverick<0>Heroes<0> +Terran Cyprian<0>Hecaton Coalition<0>Factional Units<0> +Terran Memphis<0>Tank<0>Factional Units<0> +Memphis Turret<0>Tank<0>Factional Units<0> +Terran Memphis<0>Flak<0>Factional Units<0> +Memphis Turret<0>Flak<0>Factional Units<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> diff --git a/mpq/samase/unitdef.txt b/mpq/samase/unitdef.txt index 538a638..ef658bb 100644 --- a/mpq/samase/unitdef.txt +++ b/mpq/samase/unitdef.txt @@ -36,6 +36,10 @@ military ackmed = 408 military goska = 500 military stroluum = 501 building tuzor = 502 +military infested_kerrigan_big = 612 +military raynor_vulture = 613 +military duke_minotaur = 614 +military raynor_maverick = 640 # Terran military units military maverick = 0 @@ -85,13 +89,10 @@ military paladin = 186 military savant = 187 military blackjack = 195 military claymore = 196 -military anticthon = 211 military sundog = 253 military ancile = 255 military matador = 256 -military pegasus = 261 military hippogriff = 262 -military oberon = 263 military aion = 264 military wendigo = 275 military southpaw = 276 @@ -101,7 +102,7 @@ military cataphract = 283 military dilettante = 285 military sevenstep = 286 military hypnagogue = 287 -military armistice = 289 +military anticthon = 289 military pythean = 290 military heir = 293 military horseman = 294 @@ -116,7 +117,7 @@ military triton = 512 military cohort = 50 military luminary = 150 military aspirant = 194 -military tarasque = 210 +military tarasque = 263 military philoc = 328 military hotshot = 395 military qilin = 398 @@ -149,6 +150,9 @@ military nuriel = 598 military phoenix = 599 military archbishop = 600 military camazotz = 620 +military arquebus = 624 +military cyprian_hecaton = 641 +military memphis = 642 @spellcaster(serathiel) # Terran buildings @@ -183,14 +187,12 @@ building biotic_bastion = 190 building iron_foundry = 198 building captaincy = 199 building scrapyard = 200 -building nanite_assembly = 203 -building sentinel = 209 -building atelier = 213 building treasury = 215 building starpad = 254 building future_station = 257 building quantum_institute = 259 -building aerie = 260 +building sentinel = 260 +building nanite_assembly = 261 building mantle = 280 building apothecary = 284 building parthenon = 288 @@ -438,7 +440,6 @@ building alkag_iteth = 170 building irulent_ivoa = 181 building zorkiz_shroud = 193 building tosvrol_haunt = 197 -building kalkiir_lake = 204 building alkaj_chasm = 212 building larvosk_cesiant = 216 building geszkath_grotto = 219 @@ -446,7 +447,7 @@ building irol_iris = 224 building sibraelosk = 227 building spirtith_cesiant = 292 building skortrith_cesiant = 293 -building rakzogth_roost = 303 +building kethraj_keep = 303 building begrozith_barrow = 329 building chokral_chazsal = 330 building nephrilosk = 350 @@ -457,6 +458,7 @@ building vornath_pond = 396 building skibact_scab = 397 building eskigant = 421 building zozarc_gorge = 493 +building kalkiir_lake = 549 # Askosi units military proselyte = 443 diff --git a/mpq/scripts/aiscript.bin b/mpq/scripts/aiscript.bin index c98730f..dffc57c 100644 Binary files a/mpq/scripts/aiscript.bin and b/mpq/scripts/aiscript.bin differ diff --git a/mpq/scripts/iscript_general.bin b/mpq/scripts/iscript_general.bin index 8fd4413..c6cd410 100644 Binary files a/mpq/scripts/iscript_general.bin and b/mpq/scripts/iscript_general.bin differ diff --git a/mpq/scripts/iscript_general.txt b/mpq/scripts/iscript_general.txt index b20df87..bd66708 100644 --- a/mpq/scripts/iscript_general.txt +++ b/mpq/scripts/iscript_general.txt @@ -1924,6 +1924,7 @@ InstallationDoodadAlmostBuilt: goto SkryrokorLocal00 InstallationDoodadStarEditInit: + playsndbtwn 4395 4396 # Pit Door close 01, 02 playfram 9 wait 2 playfram 8 @@ -1943,10 +1944,11 @@ InstallationDoodadStarEditInit: playfram 1 wait 2 playfram 0x00 - sigorder 1 + sigorder 64 goto SkryrokorLocal00 InstallationDoodadDisable: + playsndbtwn 4393 4394 # Pit Door open 01, 02 playfram 0x00 wait 2 playfram 1 @@ -1966,7 +1968,7 @@ InstallationDoodadDisable: playfram 8 wait 2 playfram 9 - sigorder 1 + sigorder 32 goto SkryrokorLocal00 # ----------------------------------------------------------------------------- # @@ -2018,6 +2020,7 @@ InstallationDoodad2AlmostBuilt: goto SkryrokorLocal00 InstallationDoodad2Enable: + playsndbtwn 4395 4396 # Pit Door close 01, 02 playfram 9 setflipstate 1 wait 2 @@ -2038,10 +2041,11 @@ InstallationDoodad2Enable: playfram 1 wait 2 playfram 0x00 - sigorder 1 + sigorder 64 goto SkryrokorLocal00 InstallationDoodad2Disable: + playsndbtwn 4393 4394 # Pit Door open 01, 02 playfram 1 wait 2 playfram 2 @@ -2059,7 +2063,7 @@ InstallationDoodad2Disable: playfram 8 wait 2 playfram 9 - sigorder 1 + sigorder 32 goto SkryrokorLocal00 # ----------------------------------------------------------------------------- # @@ -2162,13 +2166,13 @@ Type 27 Init FloorMissileTrapInit Death FloorMissileTrapDeath GndAttkInit FloorMissileTrapGndAttkInit -AirAttkInit [NONE] +AirAttkInit FloorMissileTrapGndAttkInit Unused1 [NONE] GndAttkRpt FloorMissileTrapGndAttkInit -AirAttkRpt [NONE] +AirAttkRpt FloorMissileTrapGndAttkInit CastSpell [NONE] GndAttkToIdle SkryrokorLocal00 -AirAttkToIdle [NONE] +AirAttkToIdle SkryrokorLocal00 Unused2 [NONE] Walking [NONE] WalkingToIdle [NONE] @@ -2201,7 +2205,7 @@ FloorMissileTrapDeath: FloorMissileTrapGndAttkInit: wait 1 - attackwith 1 + attack gotorepeatattk ignorerest goto SkryrokorLocal00 @@ -2273,13 +2277,13 @@ Type 24 Init FloorMissileTrapTurretInit Death Generic_Wait1End GndAttkInit SkryrokorLocal00 -AirAttkInit [NONE] +AirAttkInit SkryrokorLocal00 Unused1 [NONE] GndAttkRpt SkryrokorLocal00 -AirAttkRpt [NONE] +AirAttkRpt SkryrokorLocal00 CastSpell [NONE] GndAttkToIdle SkryrokorLocal00 -AirAttkToIdle [NONE] +AirAttkToIdle SkryrokorLocal00 Unused2 [NONE] Walking [NONE] WalkingToIdle [NONE] @@ -2321,13 +2325,13 @@ Type 27 Init FloorGunTrapInit Death FloorGunTrapDeath GndAttkInit FloorGunTrapGndAttkInit -AirAttkInit [NONE] +AirAttkInit FloorGunTrapGndAttkInit Unused1 [NONE] -GndAttkRpt FloorGunTrapGndAttkInit -AirAttkRpt [NONE] +GndAttkRpt FloorGunTrapGndAttkRpt +AirAttkRpt FloorGunTrapGndAttkRpt CastSpell [NONE] GndAttkToIdle FloorGunTrapGndAttkToIdle -AirAttkToIdle [NONE] +AirAttkToIdle FloorGunTrapGndAttkToIdle Unused2 [NONE] Walking [NONE] WalkingToIdle [NONE] @@ -2359,6 +2363,10 @@ FloorGunTrapDeath: end FloorGunTrapGndAttkInit: + wait 1 + sigorder 32 + wait 4 +FloorGunTrapGndAttkRpt: wait 1 nobrkcodestart playsnd 70 # Bullet\TGoFir00.wav @@ -2367,14 +2375,6 @@ FloorGunTrapGndAttkInit: wait 1 playfram 10 wait 1 - playfram 11 - wait 1 - playfram 10 - wait 1 - playfram 11 - wait 1 - playfram 10 - wait 1 nobrkcodeend gotorepeatattk ignorerest @@ -2650,10 +2650,13 @@ WallFlameTrapType1GndAttkInit: imgoluselo 421 0 0 # FlameThrower (thingy\flamer.grp) setfldirect 12 attkshiftproj 24 + sigorder 32 wait 2 attkshiftproj 52 + sigorder 32 wait 1 attkshiftproj 80 + sigorder 32 wait 10 ignorerest goto SkryrokorLocal00 @@ -2758,10 +2761,13 @@ WallFlameTrapType2GndAttkInit: imgoluselo 421 0 0 # FlameThrower (thingy\flamer.grp) setfldirect 20 attkshiftproj 24 + sigorder 32 wait 2 attkshiftproj 52 + sigorder 32 wait 1 attkshiftproj 80 + sigorder 32 wait 10 ignorerest goto SkryrokorLocal00 @@ -4984,7 +4990,6 @@ VicereDeath: VicereGndAttkInit: wait 1 attack - attack wait 2 gotorepeatattk ignorerest @@ -5225,4 +5230,312 @@ AmmoCrateLocal00: AmmoCrateDeath: imgol 332 0 0 # Explosion2 (Small) (thingy\tBangS.grp) wait 3 - end \ No newline at end of file + end + +# ----------------------------------------------------------------------------- # +# This header is used by images.dat entries: +# 742 Left Upper Level Door (thingy\tileset\install\CRDoor1.grp) +.headerstart +IsId 386 +Type 27 +Init UpperDoorInit +Death Generic_Wait1End +GndAttkInit [NONE] +AirAttkInit [NONE] +Unused1 [NONE] +GndAttkRpt [NONE] +AirAttkRpt [NONE] +CastSpell [NONE] +GndAttkToIdle [NONE] +AirAttkToIdle [NONE] +Unused2 [NONE] +Walking [NONE] +WalkingToIdle [NONE] +SpecialState1 [NONE] +SpecialState2 [NONE] +AlmostBuilt UpperDoorAlmostBuilt +Built [NONE] +Landing [NONE] +LiftOff [NONE] +IsWorking [NONE] +WorkingToIdle [NONE] +WarpIn [NONE] +Unused3 [NONE] +StarEditInit UpperDoorStarEditInit +Disable UpperDoorDisable +Burrow [NONE] +UnBurrow [NONE] +Enable UpperDoorStarEditInit +.headerend +# ----------------------------------------------------------------------------- # + +UpperDoorInit: + playfram 0x00 + goto SkryrokorLocal00 + +UpperDoorAlmostBuilt: + playfram 9 + goto SkryrokorLocal00 + +UpperDoorStarEditInit: + playsndbtwn 4399 4400 # Upper Door close 01, 02 + playfram 9 + wait 2 + playfram 8 + wait 2 + playfram 7 + wait 2 + playfram 6 + wait 2 + playfram 5 + wait 2 + playfram 4 + wait 2 + playfram 3 + wait 2 + playfram 2 + wait 2 + playfram 1 + wait 2 + playfram 0x00 + sigorder 64 + goto SkryrokorLocal00 + +UpperDoorDisable: + playsndbtwn 4397 4398 # Upper Door open 01, 02 + playfram 0x00 + wait 2 + playfram 1 + wait 2 + playfram 2 + wait 2 + playfram 3 + wait 2 + playfram 4 + wait 2 + playfram 4 + wait 2 + playfram 6 + wait 2 + playfram 7 + wait 2 + playfram 8 + wait 2 + playfram 9 + sigorder 32 + goto SkryrokorLocal00 + +# ----------------------------------------------------------------------------- # +# This header is used by images.dat entries: +# 743 Right Upper Level Door (thingy\tileset\install\CRDoor1.grp) +.headerstart +IsId 389 +Type 27 +Init UpperDoor2Init +Death Generic_Wait1End +GndAttkInit [NONE] +AirAttkInit [NONE] +Unused1 [NONE] +GndAttkRpt [NONE] +AirAttkRpt [NONE] +CastSpell [NONE] +GndAttkToIdle [NONE] +AirAttkToIdle [NONE] +Unused2 [NONE] +Walking [NONE] +WalkingToIdle [NONE] +SpecialState1 [NONE] +SpecialState2 [NONE] +AlmostBuilt UpperDoor2AlmostBuilt +Built [NONE] +Landing [NONE] +LiftOff [NONE] +IsWorking [NONE] +WorkingToIdle [NONE] +WarpIn [NONE] +Unused3 [NONE] +StarEditInit [NONE] +Disable UpperDoor2Disable +Burrow [NONE] +UnBurrow [NONE] +Enable UpperDoor2Enable +.headerend +# ----------------------------------------------------------------------------- # + +UpperDoor2Init: + playfram 0x00 + setflipstate 1 + goto SkryrokorLocal00 + +UpperDoor2AlmostBuilt: + playfram 9 + setflipstate 1 + goto SkryrokorLocal00 + +UpperDoor2Enable: + playsndbtwn 4399 4400 # Upper Door close 01, 02 + playfram 9 + setflipstate 1 + wait 2 + playfram 8 + wait 2 + playfram 7 + wait 2 + playfram 6 + wait 2 + playfram 5 + wait 2 + playfram 4 + wait 2 + playfram 3 + wait 2 + playfram 2 + wait 2 + playfram 1 + wait 2 + playfram 0x00 + sigorder 64 + goto SkryrokorLocal00 + +UpperDoor2Disable: + playsndbtwn 4397 4398 # Upper Door open 01, 02 + playfram 1 + wait 2 + playfram 2 + wait 2 + playfram 3 + wait 2 + playfram 4 + wait 2 + playfram 5 + wait 2 + playfram 6 + wait 2 + playfram 7 + wait 2 + playfram 8 + wait 2 + playfram 9 + sigorder 32 + goto SkryrokorLocal00 + +# ----------------------------------------------------------------------------- # +# This header is used by images.dat entries: +# 2504 Floor Flame Trap (cm\n\floor-flame-trap.grp) +.headerstart +IsId 390 +Type 27 +Init FloorFlameTrapInit +Death FloorFlameTrapDeath +GndAttkInit FloorFlameTrapGndAttkInit +AirAttkInit FloorFlameTrapGndAttkInit +Unused1 [NONE] +GndAttkRpt FloorFlameTrapGndAttkInit +AirAttkRpt FloorFlameTrapGndAttkInit +CastSpell [NONE] +GndAttkToIdle SkryrokorLocal00 +AirAttkToIdle SkryrokorLocal00 +Unused2 [NONE] +Walking [NONE] +WalkingToIdle [NONE] +SpecialState1 FloorFlameTrapSpecialState1 +SpecialState2 FloorFlameTrapSpecialState2 +AlmostBuilt SkryrokorLocal00 +Built [NONE] +Landing [NONE] +LiftOff [NONE] +IsWorking [NONE] +WorkingToIdle [NONE] +WarpIn [NONE] +Unused3 [NONE] +StarEditInit [NONE] +Disable FloorFlameTrapSpecialState2 +Burrow [NONE] +UnBurrow [NONE] +Enable SkryrokorLocal00 +.headerend +# ----------------------------------------------------------------------------- # + +FloorFlameTrapInit: + playfram 1 + goto SkryrokorLocal00 + +FloorFlameTrapDeath: + imgol 332 0 0 # Explosion2 (Small) (thingy\tBangS.grp) + wait 1 + end + +FloorFlameTrapGndAttkInit: + wait 1 + nobrkcodestart + imgol 421 0 0 # FlameThrower (thingy\flamer.grp) + attkshiftproj 24 + sigorder 32 + wait 2 + attkshiftproj 52 + sigorder 32 + wait 1 + attkshiftproj 80 + sigorder 32 + wait 5 + nobrkcodeend + ignorerest + goto SkryrokorLocal00 + +FloorFlameTrapSpecialState1: + playfram 1 + wait 2 + playfram 2 + wait 2 + playfram 3 + wait 2 + playfram 4 + wait 2 + playfram 5 + wait 2 + playfram 6 + wait 2 + playfram 7 + wait 2 + playfram 8 + wait 2 + playfram 9 + wait 2 + playfram 10 + wait 2 + playfram 11 + imgol 2505 0 0 # Floor Flame Trap Turret (cm\n\floor-flame-trap-turret.grp) + sigorder 1 + goto SkryrokorLocal00 + +FloorFlameTrapSpecialState2: + setspawnframe 20 + wait 1 +FloorFlameTrapLocal00: + curdirectcondjmp 160 10 FloorFlameTrapLocal01 + wait 2 + goto FloorFlameTrapLocal00 + +FloorFlameTrapLocal01: + wait 1 + playfram 10 + wait 2 + playfram 9 + wait 2 + playfram 8 + wait 2 + playfram 7 + wait 2 + playfram 6 + wait 2 + playfram 5 + wait 2 + playfram 4 + wait 2 + playfram 3 + wait 2 + playfram 2 + wait 2 + playfram 1 + sigorder 1 + goto SkryrokorLocal00 \ No newline at end of file diff --git a/mpq/scripts/iscript_protoss.bin b/mpq/scripts/iscript_protoss.bin index 3cee776..3879154 100644 Binary files a/mpq/scripts/iscript_protoss.bin and b/mpq/scripts/iscript_protoss.bin differ diff --git a/mpq/scripts/iscript_protoss.txt b/mpq/scripts/iscript_protoss.txt index 69c3ba8..6f16118 100644 --- a/mpq/scripts/iscript_protoss.txt +++ b/mpq/scripts/iscript_protoss.txt @@ -13824,8 +13824,8 @@ CastSpell [NONE] GndAttkToIdle EngramGndAttkToIdle AirAttkToIdle EngramGndAttkToIdle Unused2 [NONE] -Walking [NONE] -WalkingToIdle [NONE] +Walking SkryrokorLocal00 +WalkingToIdle SkryrokorLocal00 SpecialState1 [NONE] SpecialState2 [NONE] AlmostBuilt [NONE] diff --git a/mpq/scripts/iscript_terran.bin b/mpq/scripts/iscript_terran.bin index 1968fe6..c46ec68 100644 Binary files a/mpq/scripts/iscript_terran.bin and b/mpq/scripts/iscript_terran.bin differ diff --git a/mpq/scripts/iscript_terran.txt b/mpq/scripts/iscript_terran.txt index bfb85df..2481b55 100644 --- a/mpq/scripts/iscript_terran.txt +++ b/mpq/scripts/iscript_terran.txt @@ -2662,7 +2662,7 @@ LodestoneOverlayIsWorking: # ----------------------------------------------------------------------------- # # This header is used by images.dat entries: -# 275 Ministry (terran\control.grp) +# 275 Ministry (terran\ministry.grp) .headerstart IsId 102 Type 20 @@ -2692,7 +2692,7 @@ WarpIn [NONE] # ----------------------------------------------------------------------------- # MinistryInit: - imgul 277 0 0 # Ministry Shadow (terran\tccShad.grp) + imgul 277 0 0 # Ministry Shadow (terran\ministry-shadow.grp) MinistryBuilt: playfram 0x00 goto SkryrokorLocal00 @@ -2707,7 +2707,7 @@ MinistryDeath: end MinistrySpecialState1: - playfram 4 + playfram 9 goto SkryrokorLocal00 MinistryAlmostBuilt: @@ -2718,14 +2718,16 @@ MinistryLanding: nobrkcodestart wait 18 playsnd 472 # Misc\Land.WAV - playfram 4 - wait 5 - playfram 3 - wait 5 - playfram 2 - wait 5 + playfram 8 + wait 4 + playfram 7 + wait 4 + playfram 6 + wait 4 playfram 5 - wait 5 + wait 4 + playfram 4 + wait 4 playfram 0x00 sigorder 16 nobrkcodeend @@ -2734,33 +2736,37 @@ MinistryLanding: MinistryLiftOff: nobrkcodestart playsnd 471 # Misc\LiftOff.WAV - playfram 5 - wait 5 - playfram 2 - wait 5 - playfram 3 - wait 5 playfram 4 + wait 3 + playfram 5 + wait 3 + playfram 6 + wait 3 + playfram 7 + wait 3 + playfram 8 + wait 4 + playfram 9 sigorder 16 nobrkcodeend goto SkryrokorLocal00 MinistryIsWorking: - playfram 6 + playfram 2 wait 4 - playfram 0x00 + playfram 3 wait 1 - playfram 6 + playfram 2 wait 1 - playfram 0x00 + playfram 3 wait 1 - playfram 6 + playfram 2 wait 3 - playfram 0x00 + playfram 3 wait 1 - playfram 6 + playfram 2 wait 3 - playfram 0x00 + playfram 3 wait 1 goto MinistryIsWorking @@ -4483,7 +4489,6 @@ MorningstarLocal00: goto MorningstarLocal00 MorningstarSpecialState1: - castspell sigorder 1 tmprmgraphicstart imgol 428 0 0 # Nuclear Missile Death (thingy\small.grp) @@ -11261,11 +11266,11 @@ CaptaincyInit: goto SkryrokorLocal00 CaptaincySpecialState1: - playfram 4 + playfram 10 goto SkryrokorLocal00 CaptaincyAlmostBuilt: - playfram 11 + playfram 1 goto SkryrokorLocal00 CaptaincyBuilt: @@ -11276,14 +11281,15 @@ CaptaincyLanding: nobrkcodestart wait 15 playsnd 472 # Misc\Land.WAV -# playfram 4 - wait 8 -# playfram 3 - wait 8 -# playfram 2 - wait 8 -# playfram 5 - wait 8 + wait 6 + playfram 9 + wait 3 + playfram 8 + wait 3 + playfram 7 + wait 3 + playfram 6 + wait 3 playfram 0x00 sigorder 16 nobrkcodeend @@ -11294,40 +11300,35 @@ CaptaincyLiftOff: playsnd 471 # Misc\LiftOff.WAV playfram 0x00 wait 1 -# playfram 5 - wait 8 -# playfram 2 - wait 8 -# playfram 3 - wait 8 -# playfram 4 + playfram 6 + wait 3 + playfram 7 + wait 3 + playfram 8 + wait 3 + playfram 9 + wait 3 + playfram 10 sigorder 16 nobrkcodeend goto SkryrokorLocal00 CaptaincyIsWorking: - playfram 1 - wait 2 - playfram 2 - wait 2 - playfram 3 - wait 2 - playfram 4 - wait 2 - playfram 5 - wait 2 - playfram 6 - wait 2 - playfram 7 - wait 2 - playfram 8 - wait 2 - playfram 9 - wait 2 - playfram 10 - wait 2 - playfram 0x00 + playfram 2 wait 2 + playfram 3 + wait 2 + playfram 4 + wait 2 + playfram 5 + wait 2 + playfram 4 + wait 2 + playfram 3 + wait 2 + playfram 2 + wait 2 + playfram 0 goto CaptaincyIsWorking CaptaincyDisable: @@ -21625,7 +21626,6 @@ MaverickGoldenGndAttkRpt: wait 1 nobrkcodestart attackwith 1 - playsndbtwn 1427 1434 # Simulacrum weapon fire 01, 02, 03, 04, 05, 06, 07, 08 playfram 0x60 wait 1 playfram 0x40 @@ -22298,5 +22298,649 @@ BuildingEngineLanding: playfram 0 wait 1 playfram 1 + wait 1 + end + +# ----------------------------------------------------------------------------- # +# This header is used by images.dat entries: +# 239 Raynor (Maverick) (cm\h\raynor-maverick.grp) +.headerstart +IsId 859 +Type 12 +Init RaynorMaverickInit +Death RaynorMaverickDeath +GndAttkInit RaynorMaverickGndAttkInit +AirAttkInit RaynorMaverickGndAttkInit +Unused1 RaynorMaverickUnused1 +GndAttkRpt RaynorMaverickGndAttkRpt +AirAttkRpt RaynorMaverickGndAttkRpt +CastSpell RaynorMaverickCastSpell +GndAttkToIdle RaynorMaverickGndAttkToIdle +AirAttkToIdle RaynorMaverickGndAttkToIdle +Unused2 [NONE] +Walking RaynorMaverickWalking +WalkingToIdle RaynorMaverickWalkingToIdle +SpecialState1 [NONE] +.headerend +# ----------------------------------------------------------------------------- # + +RaynorMaverickInit: + imgulnextid 0 0 # Raynor (Maverick) Shadow (cm\h\raynor-maverick-shadow.grp) +RaynorMaverickWalkingToIdle: + playfram 0x80 +RaynorMaverickLocal00: + wait 63 + randcondjmp 25 RaynorMaverickLocal01 + randcondjmp 128 RaynorMaverickLocal02 + goto RaynorMaverickLocal00 + +RaynorMaverickLocal01: + playfram 0x00 + wait 1 + playfram 0x20 + wait 1 + playfram 0x40 + randcondjmp 192 RaynorMaverickLocal03 + turnccwise 2 + wait 3 + turnccwise 2 + wait 3 + turnccwise 2 + wait 3 + turnccwise 2 + wait 3 + turnccwise 2 + wait 3 + wait 6 + turncwise 2 + wait 3 + turncwise 2 + wait 3 + turncwise 2 + wait 3 + turncwise 2 + wait 3 + turncwise 2 + wait 3 + wait 6 + turnccwise 2 + wait 3 + turnccwise 2 + wait 3 + turnccwise 2 + wait 3 + goto RaynorMaverickLocal04 + +RaynorMaverickLocal04: + playfram 0x20 + wait 1 + playfram 0x00 + wait 1 + goto RaynorMaverickWalkingToIdle + +RaynorMaverickLocal03: + wait 13 + playfram 0x20 + wait 1 + playfram 0x00 + wait 1 + goto RaynorMaverickWalkingToIdle + +RaynorMaverickLocal02: + playfram 0xA0 + wait 1 + playfram 0xC0 + wait 1 + turnrand 3 + wait 1 + playfram 0xA0 + wait 1 + goto RaynorMaverickWalkingToIdle + +RaynorMaverickDeath: + playsndbtwn 276 277 # Terran\MARINE\TMaDth00.WAV | Terran\MARINE\TMaDth01.WAV + setfldirect 0 + playfram 416 + wait 2 + playfram 417 + wait 2 + playfram 418 + wait 2 + playfram 419 + wait 2 + playfram 420 + wait 2 + playfram 421 + wait 2 + playfram 422 + wait 2 + playfram 423 + wait 2 + lowsprul 1199 0 0 # Raynor (Maverick) Remnants (cm\h\raynor-maverick-remains.grp) + wait 1 + end + +RaynorMaverickUnused1: + wait 1 + nobrkcodestart + setfldirect 0 + playsndbtwn 1161 1162 + playfram 422 + wait 2 + playfram 421 + wait 2 + playfram 420 + wait 2 + playfram 419 + wait 2 + playfram 418 + wait 2 + playfram 417 + wait 2 + playfram 416 + wait 2 + setfldirect 12 + nobrkcodeend + goto RaynorMaverickWalkingToIdle + +RaynorMaverickGndAttkInit: + playfram 0x00 + wait 1 + playfram 0x20 + wait 1 + playfram 0x40 +RaynorMaverickGndAttkRpt: + wait 1 + nobrkcodestart + attackwith 1 + playsnd 69 # Maverick weaponfire 01 + playfram 0x60 + wait 1 + playfram 0x40 + wait 1 + playfram 0x60 + wait 1 + playfram 0x40 + wait 1 + playfram 0x60 + wait 1 + playfram 0x40 + wait 1 + nobrkcodeend + gotorepeatattk + ignorerest +RaynorMaverickGndAttkToIdle: + playfram 0x20 + wait 1 + playfram 0x00 + wait 1 + goto RaynorMaverickWalkingToIdle + +RaynorMaverickCastSpell: + wait 1 + nobrkcodestart + castspell + playsnd 69 # Maverick weaponfire 01 + playfram 0x60 + wait 1 + playfram 0x40 + wait 1 + nobrkcodeend + gotorepeatattk + ignorerest + goto RaynorMaverickGndAttkToIdle + +RaynorMaverickWalking: + move 4 + wait 1 + playfram 0xA0 + move 4 + wait 1 + playfram 0xC0 + move 4 + wait 1 + playfram 0xE0 + move 4 + wait 1 + playfram 0x100 + move 4 + wait 1 + playfram 0x120 + move 4 + wait 1 + playfram 0x140 + move 4 + wait 1 + playfram 0x160 + move 4 + wait 1 + playfram 0x180 + move 4 + wait 1 + playfram 0x80 + goto RaynorMaverickWalking + +# ----------------------------------------------------------------------------- # +# This header is used by images.dat entries: +# 1586 Cyprian (Hecaton) (cm\f-t\cyprian-hecaton.grp) +.headerstart +IsId 860 +Type 12 +Init CyprianHecatonInit +Death CyprianHecatonDeath +GndAttkInit CyprianHecatonGndAttkInit +AirAttkInit CyprianHecatonGndAttkInit +Unused1 SkryrokorLocal00 +GndAttkRpt CyprianHecatonGndAttkRpt +AirAttkRpt CyprianHecatonGndAttkRpt +CastSpell CyprianHecatonCastSpell +GndAttkToIdle CyprianHecatonGndAttkToIdle +AirAttkToIdle CyprianHecatonGndAttkToIdle +Unused2 [NONE] +Walking CyprianHecatonWalking +WalkingToIdle CyprianHecatonWalkingToIdle +SpecialState1 [NONE] +.headerend +# ----------------------------------------------------------------------------- # + +CyprianHecatonInit: + imgulnextid 0 0 # Cyprian (Hecaton) Shadow (cm\f-t\cyprian-hecaton-shadow.grp) +CyprianHecatonWalkingToIdle: + playfram 0x00 + goto CyprianHecatonLocal00 + +CyprianHecatonLocal00: + wait 125 + goto CyprianHecatonLocal00 + +CyprianHecatonDeath: + playsndbtwn 276 277 # Maverick death 01, 02 + imgol 332 0 0 # Explosion2 (Small) (thingy\tBangS.grp) + wait 3 + lowsprul 820 0 0 # Cyprian (Hecaton) Remains (cm\terran\cyprian-remains.grp) + wait 1 + end + +CyprianHecatonGndAttkInit: + playfram 0x120 + wait 1 + playfram 0x140 + wait 1 + sigorder 32 + playfram 0x160 + wait 16 +CyprianHecatonGndAttkRpt: + wait 1 + nobrkcodestart + playfram 0x1E0 + playsndbtwn 1189 1193 # Cyprian (Hecaton) weaponfire 01, 02, 03, 04, 05 + attackwith 1 + wait 1 + playfram 0x1C0 + wait 1 + playfram 0x1A0 + wait 1 + playfram 0x180 + wait 1 + nobrkcodeend + gotorepeatattk + ignorerest +CyprianHecatonGndAttkToIdle: + playfram 0x160 + wait 1 + playfram 0x140 + wait 1 + goto CyprianHecatonWalkingToIdle + +CyprianHecatonCastSpell: + wait 1 + goto CyprianHecatonGndAttkToIdle + +CyprianHecatonWalking: + move 3 + wait 1 + playfram 0x80 + move 3 + wait 1 + playfram 0xA0 + move 3 + wait 1 + playfram 0xC0 + move 3 + wait 1 + playfram 0xE0 + move 3 + wait 1 + playfram 0x100 + move 3 + wait 1 + playfram 0x20 + move 3 + wait 1 + playfram 0x40 + move 3 + wait 1 + playfram 0x60 + goto CyprianHecatonWalking + +# ----------------------------------------------------------------------------- # +# This header is used by images.dat entries: +# 2498 Memphis Tank Mode (cm\f-t\memphis.grp) +.headerstart +IsId 861 +Type 23 +Init MemphisInit +Death MemphisDeath +GndAttkInit MemphisGndAttkInit +AirAttkInit MemphisGndAttkInit +Unused1 MemphisUnused1 +GndAttkRpt MemphisGndAttkInit +AirAttkRpt MemphisGndAttkInit +CastSpell [NONE] +GndAttkToIdle InfestedTerranWalkingToIdle +AirAttkToIdle InfestedTerranWalkingToIdle +Unused2 [NONE] +Walking MemphisWalking +WalkingToIdle InfestedTerranWalkingToIdle +SpecialState1 [NONE] +SpecialState2 [NONE] +AlmostBuilt [NONE] +Built [NONE] +Landing [NONE] +LiftOff [NONE] +IsWorking [NONE] +WorkingToIdle [NONE] +WarpIn [NONE] +Unused3 [NONE] +StarEditInit Memphis_Tank_BaseStarEditInit +.headerend +# ----------------------------------------------------------------------------- # + +MemphisInit: + imgul 2500 0 0 # Memphis Shadow (cm\f-t\memphis-shadow.grp) + playfram 0x00 + goto InfestedTerranWalkingToIdle + +MemphisDeath: + playsndbtwn 1385 1386 # Memphis death 01, 02 + imgol 332 0 -5 # Explosion2 (Small) (thingy\tBangS.grp) + wait 3 + lowsprul 845 0 0 # Terran Unit Rubble Small + wait 1 + end + +MemphisUnused1: + wait 1 + nobrkcodestart + playsndbtwn 1705 1706 + sprol 742 0 0 + setfldirect 12 + wait 12 + nobrkcodeend + goto InfestedTerranWalkingToIdle + +MemphisGndAttkInit: + playfram 0x00 + wait 1 + nobrkcodestart + playfram 0x100 + playsndbtwn 4401 4403 # Memphis weaponfire 01, 02, 03 + attack + wait 1 + playfram 0x00 + wait 1 + nobrkcodeend + gotorepeatattk + goto InfestedTerranWalkingToIdle + +MemphisWalking: + playfram 0x20 + move 4 + wait 1 + playfram 0x40 + move 4 + wait 1 + playfram 0x60 + move 4 + wait 1 + playfram 0x80 + move 4 + wait 1 + playfram 0xA0 + move 4 + wait 1 + playfram 0xC0 + move 4 + wait 1 + playfram 0xE0 + move 4 + wait 1 + goto MemphisWalking + +Memphis_Tank_BaseStarEditInit: + setfldirect 12 + imgoluselo 2499 2 0 # Memphis (Tank) Turret (cm\f-t\memphis-turret.grp) + wait 1 + imgul 2500 0 0 # Memphis (Tank) Base Shadow (cm\f-t\memphis-shadow.grp) + setfldirect 12 + playfram 0x00 + goto InfestedTerranWalkingToIdle + +# ----------------------------------------------------------------------------- # +# This header is used by images.dat entries: +# 2501 Memphis Flak Mode (cm\f-t\memphis.grp) +.headerstart +IsId 862 +Type 23 +Init MemphisFlakModeInit +Death MemphisFlakModeDeath +GndAttkInit MemphisFlakModeGndAttkInit +AirAttkInit MemphisFlakModeGndAttkInit +Unused1 MemphisFlakModeUnused1 +GndAttkRpt [NONE] +AirAttkRpt [NONE] +CastSpell [NONE] +GndAttkToIdle MemphisFlakModeGndAttkToIdle +AirAttkToIdle MemphisFlakModeGndAttkToIdle +Unused2 [NONE] +Walking [NONE] +WalkingToIdle SkryrokorLocal00 +SpecialState1 MemphisFlakModeSpecialState2 +SpecialState2 MemphisFlakModeSpecialState2 +AlmostBuilt [NONE] +Built [NONE] +Landing [NONE] +LiftOff [NONE] +IsWorking [NONE] +WorkingToIdle [NONE] +WarpIn [NONE] +Unused3 [NONE] +StarEditInit MemphisFlakModeStarEditInit +.headerend +# ----------------------------------------------------------------------------- # + +MemphisFlakModeInit: + imgul 2500 0 0 # Memphis Shadow (cm\f-t\memphis-shadow.grp) + wait 1 + playsnd 2429 # Memphis Flak Transform + setflspeed 0 + playfram 0x120 + wait 1 + playfram 0x140 + wait 1 + playfram 0x160 + wait 1 + playfram 0x180 + wait 6 + sigorder 1 + goto MemphisFlakModeGndAttkToIdle + +MemphisFlakModeGndAttkToIdle: + playfram 0x180 + goto SkryrokorLocal00 + +MemphisFlakModeDeath: + playsndbtwn 1385 1386 # Memphis death 01, 02 + imgol 332 0 -5 # Explosion2 (Small) (thingy\tBangS.grp) + wait 3 + lowsprul 845 0 0 # Terran Unit Rubble Small + wait 1 + end + +MemphisFlakModeUnused1: + wait 1 + nobrkcodestart + playsndbtwn 1705 1706 + sprol 742 0 0 + setfldirect 12 + wait 12 + nobrkcodeend + goto MemphisFlakModeGndAttkToIdle + +MemphisFlakModeGndAttkInit: + playfram 0x180 + wait 1 + nobrkcodestart + playfram 0x1A0 + playsndbtwn 4401 4403 # Memphis weaponfire 01, 02, 03 + attack + wait 1 + playfram 0x180 + wait 1 + nobrkcodeend + gotorepeatattk + goto MemphisFlakModeGndAttkToIdle + +MemphisFlakModeSpecialState2: + playsnd 2430 # Memphis Tank Transform + playfram 0x160 + wait 1 + playfram 0x140 + wait 1 + playfram 0x120 + wait 1 + playfram 0x00 + wait 6 + sigorder 1 + goto SkryrokorLocal00 + +MemphisFlakModeStarEditInit: + imgoluselo 2501 2 0 # Memphis Flak Turret (terran\memphis-turret.grp) + imgul 2500 0 0 # Memphis Flak Base Shadow (terran\memphis-shadow.grp) + wait 1 + setflspeed 0 + playsnd 2430 # Memphis Tank Transform + playfram 0x160 + wait 1 + playfram 0x140 + wait 1 + playfram 0x120 + wait 1 + playfram 0x00 + wait 6 + sigorder 1 + goto SkryrokorLocal00 + +# ----------------------------------------------------------------------------- # +# This header is used by images.dat entries: +# 2499 Memphis Tank Mode Turret (cm\f-t\memphis-turret.grp) +.headerstart +IsId 863 +Type 13 +Init InfestedTerranWalkingToIdle +Death Generic_Wait1End +GndAttkInit MemphisGndAttkInit +AirAttkInit MemphisGndAttkInit +Unused1 [NONE] +GndAttkRpt MemphisGndAttkInit +AirAttkRpt MemphisGndAttkInit +CastSpell [NONE] +GndAttkToIdle InfestedTerranWalkingToIdle +AirAttkToIdle InfestedTerranWalkingToIdle +Unused2 [NONE] +Walking MemphisWalking +WalkingToIdle InfestedTerranWalkingToIdle +SpecialState1 SkryrokorLocal00 +.headerend +# ----------------------------------------------------------------------------- # + +# ----------------------------------------------------------------------------- # +# This header is used by images.dat entries: +# 2502 Memphis Turret Flak Mode (cm\f-t\memphis-turret.grp) +.headerstart +IsId 864 +Type 14 +Init MemphisFlakModeTurretInit +Death Generic_Wait1End +GndAttkInit MemphisFlakModeGndAttkInit +AirAttkInit MemphisFlakModeGndAttkInit +Unused1 [NONE] +GndAttkRpt MemphisFlakModeGndAttkInit +AirAttkRpt MemphisFlakModeGndAttkInit +CastSpell [NONE] +GndAttkToIdle MemphisFlakModeGndAttkToIdle +AirAttkToIdle MemphisFlakModeGndAttkToIdle +Unused2 [NONE] +Walking [NONE] +WalkingToIdle [NONE] +SpecialState1 MemphisFlakModeSpecialState2 +SpecialState2 MemphisFlakModeSpecialState2 +AlmostBuilt [NONE] +.headerend +# ----------------------------------------------------------------------------- # + +MemphisFlakModeTurretInit: + wait 1 + setflspeed 0 + playfram 0x120 + wait 1 + playfram 0x140 + wait 1 + playfram 0x160 + wait 1 + playfram 0x180 + wait 6 + sigorder 1 + goto MemphisFlakModeGndAttkToIdle + +# ----------------------------------------------------------------------------- # +# This header is used by images.dat entries: +# 1477 Cyclops Fragmentary Explosion with Damage (cm\t\cyclops-fragmentary-shells.grp) +.headerstart +IsId 865 +Type 1 +Init CyclopsFragmentaryExplosionDamageInit +Death CyclopsFragmentaryExplosionDamageDeath +.headerend +# ----------------------------------------------------------------------------- # + +CyclopsFragmentaryExplosionDamageInit: + playfram 10 + wait 1 + playsndbtwn 4404 4407 # Memphis weaponhit 01, 02, 03, 04 + domissiledmg + playfram 11 + wait 1 + playfram 12 + wait 1 + playfram 13 + wait 1 + playfram 14 + wait 1 + playfram 15 + wait 1 + playfram 16 + wait 1 + playfram 17 + wait 1 + playfram 18 + wait 1 + playfram 19 + wait 1 + playfram 20 + wait 1 + end + +CyclopsFragmentaryExplosionDamageDeath: wait 1 end \ No newline at end of file diff --git a/mpq/scripts/iscript_zerg.bin b/mpq/scripts/iscript_zerg.bin index eb57ead..897703e 100644 Binary files a/mpq/scripts/iscript_zerg.bin and b/mpq/scripts/iscript_zerg.bin differ diff --git a/mpq/scripts/iscript_zerg.txt b/mpq/scripts/iscript_zerg.txt index b18c0ec..1580f71 100644 --- a/mpq/scripts/iscript_zerg.txt +++ b/mpq/scripts/iscript_zerg.txt @@ -17936,7 +17936,7 @@ ZethalorGndAttkInit: ZethalorGndAttkRpt: wait 1 nobrkcodestart - playsndbtwn 3467 3469 # Zethalor weaponfire 01, 02, 03 + playsndbtwn 4367 4369 # Zethalor weaponfire 01, 02, 03 playfram 0x1A0 wait 1 playfram 0x1E0 @@ -19919,4 +19919,44 @@ GarvrokorUnBurrow: playfram 0xcc wait 1 sigorder 4 - goto GarvrokorGndAttkToIdle \ No newline at end of file + goto GarvrokorGndAttkToIdle + +# ----------------------------------------------------------------------------- # +# This header is used by images.dat entries: +# 2490 Seeker Spores Silent (cm\z\okrimnilisk-spore.grp) +.headerstart +IsId 849 +Type 2 +Init OkrimniliskSporeInit +Death OkrimniliskSporeDeath +GndAttkInit OkrimniliskSporeGndAttkInit +AirAttkInit [NONE] +.headerend +# ----------------------------------------------------------------------------- # + +OkrimniliskSporeInit: + playfram 0x00 + wait 1 + sigorder 1 + wait 1 +OkrimniliskSporeGndAttkInit: + sprol 1197 0 0 # Spore Trail (White) (cm\z\spore-trail-white.grp) + playfram 0x00 + wait 1 + sprol 1197 0 0 # Spore Trail (White) (cm\z\spore-trail-white.grp) + playfram 1 + wait 1 + sprol 1197 0 0 # Spore Trail (White) (cm\z\spore-trail-white.grp) + playfram 2 + wait 1 + sprol 1197 0 0 # Spore Trail (White) (cm\z\spore-trail-white.grp) + playfram 3 + wait 1 + sprol 1197 0 0 # Spore Trail (White) (cm\z\spore-trail-white.grp) + goto OkrimniliskSporeGndAttkInit + +OkrimniliskSporeDeath: + sprol 1196 0 0 # Spore Hit (White) (cm\z\spore-hit-white.grp) + domissiledmg + wait 1 + end \ No newline at end of file diff --git a/mpq/sound/cm/f-t/memphis/wf-01.wav b/mpq/sound/cm/f-t/memphis/wf-01.wav new file mode 100644 index 0000000..ba9e330 Binary files /dev/null and b/mpq/sound/cm/f-t/memphis/wf-01.wav differ diff --git a/mpq/sound/cm/f-t/memphis/wf-02.wav b/mpq/sound/cm/f-t/memphis/wf-02.wav new file mode 100644 index 0000000..bfd47fd Binary files /dev/null and b/mpq/sound/cm/f-t/memphis/wf-02.wav differ diff --git a/mpq/sound/cm/f-t/memphis/wf-03.wav b/mpq/sound/cm/f-t/memphis/wf-03.wav new file mode 100644 index 0000000..7b5fc6b Binary files /dev/null and b/mpq/sound/cm/f-t/memphis/wf-03.wav differ diff --git a/mpq/sound/cm/f-t/memphis/wh-2-01.wav b/mpq/sound/cm/f-t/memphis/wh-2-01.wav new file mode 100644 index 0000000..932aeb9 Binary files /dev/null and b/mpq/sound/cm/f-t/memphis/wh-2-01.wav differ diff --git a/mpq/sound/cm/f-t/memphis/wh-2-02.wav b/mpq/sound/cm/f-t/memphis/wh-2-02.wav new file mode 100644 index 0000000..fe54174 Binary files /dev/null and b/mpq/sound/cm/f-t/memphis/wh-2-02.wav differ diff --git a/mpq/sound/cm/f-t/memphis/wh-2-03.wav b/mpq/sound/cm/f-t/memphis/wh-2-03.wav new file mode 100644 index 0000000..24ac5c7 Binary files /dev/null and b/mpq/sound/cm/f-t/memphis/wh-2-03.wav differ diff --git a/mpq/sound/cm/f-t/memphis/wh-2-04.wav b/mpq/sound/cm/f-t/memphis/wh-2-04.wav new file mode 100644 index 0000000..41f52f9 Binary files /dev/null and b/mpq/sound/cm/f-t/memphis/wh-2-04.wav differ diff --git a/mpq/sound/cm/n/doors/pit-close-01.wav b/mpq/sound/cm/n/doors/pit-close-01.wav new file mode 100644 index 0000000..2323733 Binary files /dev/null and b/mpq/sound/cm/n/doors/pit-close-01.wav differ diff --git a/mpq/sound/cm/n/doors/pit-close-02.wav b/mpq/sound/cm/n/doors/pit-close-02.wav new file mode 100644 index 0000000..0eed118 Binary files /dev/null and b/mpq/sound/cm/n/doors/pit-close-02.wav differ diff --git a/mpq/sound/cm/n/doors/pit-open-01.wav b/mpq/sound/cm/n/doors/pit-open-01.wav new file mode 100644 index 0000000..5abbd47 Binary files /dev/null and b/mpq/sound/cm/n/doors/pit-open-01.wav differ diff --git a/mpq/sound/cm/n/doors/pit-open-02.wav b/mpq/sound/cm/n/doors/pit-open-02.wav new file mode 100644 index 0000000..807a4c3 Binary files /dev/null and b/mpq/sound/cm/n/doors/pit-open-02.wav differ diff --git a/mpq/sound/cm/n/doors/upper-close-01.wav b/mpq/sound/cm/n/doors/upper-close-01.wav new file mode 100644 index 0000000..ac7fff5 Binary files /dev/null and b/mpq/sound/cm/n/doors/upper-close-01.wav differ diff --git a/mpq/sound/cm/n/doors/upper-close-02.wav b/mpq/sound/cm/n/doors/upper-close-02.wav new file mode 100644 index 0000000..38f5d17 Binary files /dev/null and b/mpq/sound/cm/n/doors/upper-close-02.wav differ diff --git a/mpq/sound/cm/n/doors/upper-open-01.wav b/mpq/sound/cm/n/doors/upper-open-01.wav new file mode 100644 index 0000000..3362822 Binary files /dev/null and b/mpq/sound/cm/n/doors/upper-open-01.wav differ diff --git a/mpq/sound/cm/n/doors/upper-open-02.wav b/mpq/sound/cm/n/doors/upper-open-02.wav new file mode 100644 index 0000000..c8e3eda Binary files /dev/null and b/mpq/sound/cm/n/doors/upper-open-02.wav differ diff --git a/mpq/tileset/badlands.cv5 b/mpq/tileset/badlands.cv5 index f36abac..6d60534 100644 Binary files a/mpq/tileset/badlands.cv5 and b/mpq/tileset/badlands.cv5 differ diff --git a/mpq/tileset/badlands.vf4 b/mpq/tileset/badlands.vf4 index 5ef5df9..0b9371a 100644 Binary files a/mpq/tileset/badlands.vf4 and b/mpq/tileset/badlands.vf4 differ diff --git a/mpq/tileset/badlands.vr4 b/mpq/tileset/badlands.vr4 index a418308..a3f1685 100644 Binary files a/mpq/tileset/badlands.vr4 and b/mpq/tileset/badlands.vr4 differ diff --git a/mpq/tileset/badlands.vx4ex b/mpq/tileset/badlands.vx4ex index a1bc079..bbf2f5f 100644 Binary files a/mpq/tileset/badlands.vx4ex and b/mpq/tileset/badlands.vx4ex differ diff --git a/mpq/tileset/install.cv5 b/mpq/tileset/install.cv5 index 62cb209..1f4de05 100644 Binary files a/mpq/tileset/install.cv5 and b/mpq/tileset/install.cv5 differ diff --git a/mpq/tileset/install.vf4 b/mpq/tileset/install.vf4 index fde9027..bd413a8 100644 Binary files a/mpq/tileset/install.vf4 and b/mpq/tileset/install.vf4 differ diff --git a/mpq/tileset/install.vr4 b/mpq/tileset/install.vr4 index 5202f41..ec6175e 100644 Binary files a/mpq/tileset/install.vr4 and b/mpq/tileset/install.vr4 differ diff --git a/mpq/tileset/install.vx4ex b/mpq/tileset/install.vx4ex index 8aac9f8..3431d63 100644 Binary files a/mpq/tileset/install.vx4ex and b/mpq/tileset/install.vx4ex differ diff --git a/mpq/tileset/platform.vf4 b/mpq/tileset/platform.vf4 index 12b0ddd..5129c06 100644 Binary files a/mpq/tileset/platform.vf4 and b/mpq/tileset/platform.vf4 differ diff --git a/mpq/unit/cm/f-t/cyprian-hecaton-shadow.grp b/mpq/unit/cm/f-t/cyprian-hecaton-shadow.grp new file mode 100644 index 0000000..01a655e Binary files /dev/null and b/mpq/unit/cm/f-t/cyprian-hecaton-shadow.grp differ diff --git a/mpq/unit/cm/f-t/cyprian-hecaton.grp b/mpq/unit/cm/f-t/cyprian-hecaton.grp new file mode 100644 index 0000000..efb5878 Binary files /dev/null and b/mpq/unit/cm/f-t/cyprian-hecaton.grp differ diff --git a/mpq/unit/cm/f-t/memphis-shadow.grp b/mpq/unit/cm/f-t/memphis-shadow.grp new file mode 100644 index 0000000..da8ffea Binary files /dev/null and b/mpq/unit/cm/f-t/memphis-shadow.grp differ diff --git a/mpq/unit/cm/f-t/memphis-turret.grp b/mpq/unit/cm/f-t/memphis-turret.grp new file mode 100644 index 0000000..86d2116 Binary files /dev/null and b/mpq/unit/cm/f-t/memphis-turret.grp differ diff --git a/mpq/unit/cm/f-t/memphis-turret.lol b/mpq/unit/cm/f-t/memphis-turret.lol new file mode 100644 index 0000000..e6892c9 Binary files /dev/null and b/mpq/unit/cm/f-t/memphis-turret.lol differ diff --git a/mpq/unit/cm/f-t/memphis.grp b/mpq/unit/cm/f-t/memphis.grp new file mode 100644 index 0000000..fc20b10 Binary files /dev/null and b/mpq/unit/cm/f-t/memphis.grp differ diff --git a/mpq/unit/cm/h/raynor-maverick-remains.grp b/mpq/unit/cm/h/raynor-maverick-remains.grp new file mode 100644 index 0000000..7487c9d Binary files /dev/null and b/mpq/unit/cm/h/raynor-maverick-remains.grp differ diff --git a/mpq/unit/cm/h/raynor-maverick-shadow.grp b/mpq/unit/cm/h/raynor-maverick-shadow.grp new file mode 100644 index 0000000..a842320 Binary files /dev/null and b/mpq/unit/cm/h/raynor-maverick-shadow.grp differ diff --git a/mpq/unit/cm/h/raynor-maverick.grp b/mpq/unit/cm/h/raynor-maverick.grp new file mode 100644 index 0000000..d1d6684 Binary files /dev/null and b/mpq/unit/cm/h/raynor-maverick.grp differ diff --git a/mpq/unit/cm/n/batterycell-shadow.grp b/mpq/unit/cm/n/batterycell-shadow.grp new file mode 100644 index 0000000..05ea92f Binary files /dev/null and b/mpq/unit/cm/n/batterycell-shadow.grp differ diff --git a/mpq/unit/cm/n/batterycell.grp b/mpq/unit/cm/n/batterycell.grp new file mode 100644 index 0000000..dd75cf3 Binary files /dev/null and b/mpq/unit/cm/n/batterycell.grp differ diff --git a/mpq/unit/cm/n/floor-flame-trap-turret.grp b/mpq/unit/cm/n/floor-flame-trap-turret.grp new file mode 100644 index 0000000..20aba29 Binary files /dev/null and b/mpq/unit/cm/n/floor-flame-trap-turret.grp differ diff --git a/mpq/unit/cm/n/floor-flame-trap.grp b/mpq/unit/cm/n/floor-flame-trap.grp new file mode 100644 index 0000000..f2083f3 Binary files /dev/null and b/mpq/unit/cm/n/floor-flame-trap.grp differ diff --git a/mpq/unit/cm/t/blackjack.grp b/mpq/unit/cm/t/blackjack.grp index 26e3618..5c79091 100644 Binary files a/mpq/unit/cm/t/blackjack.grp and b/mpq/unit/cm/t/blackjack.grp differ diff --git a/mpq/unit/cm/t/captaincy-damage.lof b/mpq/unit/cm/t/captaincy-damage.lof index 5f3131d..f607e67 100644 Binary files a/mpq/unit/cm/t/captaincy-damage.lof and b/mpq/unit/cm/t/captaincy-damage.lof differ diff --git a/mpq/unit/cm/t/captaincy-shadow.grp b/mpq/unit/cm/t/captaincy-shadow.grp index d837a79..48e202d 100644 Binary files a/mpq/unit/cm/t/captaincy-shadow.grp and b/mpq/unit/cm/t/captaincy-shadow.grp differ diff --git a/mpq/unit/cm/t/captaincy.grp b/mpq/unit/cm/t/captaincy.grp index 9836a89..f53c9fb 100644 Binary files a/mpq/unit/cm/t/captaincy.grp and b/mpq/unit/cm/t/captaincy.grp differ diff --git a/mpq/unit/cm/t/cyprian-remains.grp b/mpq/unit/cm/t/cyprian-remains.grp index 5214a54..49848db 100644 Binary files a/mpq/unit/cm/t/cyprian-remains.grp and b/mpq/unit/cm/t/cyprian-remains.grp differ diff --git a/mpq/unit/cm/t/cyprian-shadow.grp b/mpq/unit/cm/t/cyprian-shadow.grp index 28c9de6..2fdc357 100644 Binary files a/mpq/unit/cm/t/cyprian-shadow.grp and b/mpq/unit/cm/t/cyprian-shadow.grp differ diff --git a/mpq/unit/cm/t/cyprian.grp b/mpq/unit/cm/t/cyprian.grp index 0f21450..a6f103f 100644 Binary files a/mpq/unit/cm/t/cyprian.grp and b/mpq/unit/cm/t/cyprian.grp differ diff --git a/mpq/unit/cm/t/hippogriff-engine.grp b/mpq/unit/cm/t/hippogriff-engine.grp index 388fb0e..42b683d 100644 Binary files a/mpq/unit/cm/t/hippogriff-engine.grp and b/mpq/unit/cm/t/hippogriff-engine.grp differ diff --git a/mpq/unit/cm/t/hippogriff.grp b/mpq/unit/cm/t/hippogriff.grp index e487d95..c41e3e0 100644 Binary files a/mpq/unit/cm/t/hippogriff.grp and b/mpq/unit/cm/t/hippogriff.grp differ diff --git a/mpq/unit/cm/t/ministry-damage.lof b/mpq/unit/cm/t/ministry-damage.lof new file mode 100644 index 0000000..e9b0a91 Binary files /dev/null and b/mpq/unit/cm/t/ministry-damage.lof differ diff --git a/mpq/unit/cm/t/quarry-connector.grp b/mpq/unit/cm/t/quarry-connector.grp index ffb25dc..d152b36 100644 Binary files a/mpq/unit/cm/t/quarry-connector.grp and b/mpq/unit/cm/t/quarry-connector.grp differ diff --git a/mpq/unit/cm/t/quarry-damage.lof b/mpq/unit/cm/t/quarry-damage.lof index e4f618e..560f1e7 100644 Binary files a/mpq/unit/cm/t/quarry-damage.lof and b/mpq/unit/cm/t/quarry-damage.lof differ diff --git a/mpq/unit/cm/t/quarry-shadow.grp b/mpq/unit/cm/t/quarry-shadow.grp index cf5ba85..0f5e879 100644 Binary files a/mpq/unit/cm/t/quarry-shadow.grp and b/mpq/unit/cm/t/quarry-shadow.grp differ diff --git a/mpq/unit/cm/t/quarry.grp b/mpq/unit/cm/t/quarry.grp index 85e0c7f..8f97e21 100644 Binary files a/mpq/unit/cm/t/quarry.grp and b/mpq/unit/cm/t/quarry.grp differ diff --git a/mpq/unit/cm/t/rotary-connector.grp b/mpq/unit/cm/t/rotary-connector.grp index 1917926..78a0b0b 100644 Binary files a/mpq/unit/cm/t/rotary-connector.grp and b/mpq/unit/cm/t/rotary-connector.grp differ diff --git a/mpq/unit/cm/t/rotary-shadow.grp b/mpq/unit/cm/t/rotary-shadow.grp index df26cd9..f632193 100644 Binary files a/mpq/unit/cm/t/rotary-shadow.grp and b/mpq/unit/cm/t/rotary-shadow.grp differ diff --git a/mpq/unit/cm/t/rotary.grp b/mpq/unit/cm/t/rotary.grp index 43b8d64..08e737c 100644 Binary files a/mpq/unit/cm/t/rotary.grp and b/mpq/unit/cm/t/rotary.grp differ diff --git a/mpq/unit/cm/t/starpad-landing.lou b/mpq/unit/cm/t/starpad-landing.lou index 51975f4..c56cbd0 100644 Binary files a/mpq/unit/cm/t/starpad-landing.lou and b/mpq/unit/cm/t/starpad-landing.lou differ diff --git a/mpq/unit/cm/t/starpad-liftoff.lod b/mpq/unit/cm/t/starpad-liftoff.lod index 51975f4..c56cbd0 100644 Binary files a/mpq/unit/cm/t/starpad-liftoff.lod and b/mpq/unit/cm/t/starpad-liftoff.lod differ diff --git a/mpq/unit/cm/t/starpad-shadow.grp b/mpq/unit/cm/t/starpad-shadow.grp index 02d0e0e..d1a09d6 100644 Binary files a/mpq/unit/cm/t/starpad-shadow.grp and b/mpq/unit/cm/t/starpad-shadow.grp differ diff --git a/mpq/unit/cm/t/starpad.grp b/mpq/unit/cm/t/starpad.grp index 4cf7202..b8ca975 100644 Binary files a/mpq/unit/cm/t/starpad.grp and b/mpq/unit/cm/t/starpad.grp differ diff --git a/mpq/unit/cm/t/treasury-damage.lof b/mpq/unit/cm/t/treasury-damage.lof index 4474b9f..c2e55d3 100644 Binary files a/mpq/unit/cm/t/treasury-damage.lof and b/mpq/unit/cm/t/treasury-damage.lof differ diff --git a/mpq/unit/cm/t/treasury-shadow.grp b/mpq/unit/cm/t/treasury-shadow.grp index 84d8a42..07cd084 100644 Binary files a/mpq/unit/cm/t/treasury-shadow.grp and b/mpq/unit/cm/t/treasury-shadow.grp differ diff --git a/mpq/unit/cm/t/treasury.grp b/mpq/unit/cm/t/treasury.grp index bb68295..96583fa 100644 Binary files a/mpq/unit/cm/t/treasury.grp and b/mpq/unit/cm/t/treasury.grp differ diff --git a/mpq/unit/cm/z/okrimnilisk-spore.grp b/mpq/unit/cm/z/okrimnilisk-spore.grp new file mode 100644 index 0000000..dfedc80 Binary files /dev/null and b/mpq/unit/cm/z/okrimnilisk-spore.grp differ diff --git a/mpq/unit/cm/z/quazilisk-birth.grp b/mpq/unit/cm/z/quazilisk-birth.grp index 6d27c5b..2a29869 100644 Binary files a/mpq/unit/cm/z/quazilisk-birth.grp and b/mpq/unit/cm/z/quazilisk-birth.grp differ diff --git a/mpq/unit/cm/z/quazilisk-mutate.grp b/mpq/unit/cm/z/quazilisk-mutate.grp index a4b6e36..395e380 100644 Binary files a/mpq/unit/cm/z/quazilisk-mutate.grp and b/mpq/unit/cm/z/quazilisk-mutate.grp differ diff --git a/mpq/unit/cm/z/quazilisk-remains.grp b/mpq/unit/cm/z/quazilisk-remains.grp index c215a9e..6d76878 100644 Binary files a/mpq/unit/cm/z/quazilisk-remains.grp and b/mpq/unit/cm/z/quazilisk-remains.grp differ diff --git a/mpq/unit/cm/z/quazilisk.grp b/mpq/unit/cm/z/quazilisk.grp index b54034f..ab23b81 100644 Binary files a/mpq/unit/cm/z/quazilisk.grp and b/mpq/unit/cm/z/quazilisk.grp differ diff --git a/mpq/unit/cm/z/spore-hit-white.grp b/mpq/unit/cm/z/spore-hit-white.grp new file mode 100644 index 0000000..4febda1 Binary files /dev/null and b/mpq/unit/cm/z/spore-hit-white.grp differ diff --git a/mpq/unit/cm/z/spore-trail-white.grp b/mpq/unit/cm/z/spore-trail-white.grp new file mode 100644 index 0000000..3e47686 Binary files /dev/null and b/mpq/unit/cm/z/spore-trail-white.grp differ diff --git a/mpq/unit/cmdbtns/cmdicons.grp b/mpq/unit/cmdbtns/cmdicons.grp index 7e41ab0..0fe6148 100644 Binary files a/mpq/unit/cmdbtns/cmdicons.grp and b/mpq/unit/cmdbtns/cmdicons.grp differ diff --git a/mpq/unit/cmdbtns/uniticons.grp b/mpq/unit/cmdbtns/uniticons.grp index 62f68f7..709a9f5 100644 Binary files a/mpq/unit/cmdbtns/uniticons.grp and b/mpq/unit/cmdbtns/uniticons.grp differ diff --git a/mpq/unit/protoss/nexus-damage.lof b/mpq/unit/protoss/nexus-damage.lof new file mode 100644 index 0000000..59b7ddd Binary files /dev/null and b/mpq/unit/protoss/nexus-damage.lof differ diff --git a/mpq/unit/protoss/nexus-shadow.grp b/mpq/unit/protoss/nexus-shadow.grp new file mode 100644 index 0000000..0b68cca Binary files /dev/null and b/mpq/unit/protoss/nexus-shadow.grp differ diff --git a/mpq/unit/cm/p/photoncannon-attack.lol b/mpq/unit/protoss/warden-attack.lol similarity index 100% rename from mpq/unit/cm/p/photoncannon-attack.lol rename to mpq/unit/protoss/warden-attack.lol diff --git a/mpq/unit/protoss/photon.lof b/mpq/unit/protoss/warden-damage.lof similarity index 100% rename from mpq/unit/protoss/photon.lof rename to mpq/unit/protoss/warden-damage.lof diff --git a/mpq/unit/protoss/ppbshad.grp b/mpq/unit/protoss/warden-shadow.grp similarity index 100% rename from mpq/unit/protoss/ppbshad.grp rename to mpq/unit/protoss/warden-shadow.grp diff --git a/mpq/unit/protoss/photon.grp b/mpq/unit/protoss/warden.grp similarity index 100% rename from mpq/unit/protoss/photon.grp rename to mpq/unit/protoss/warden.grp diff --git a/mpq/unit/terran/eidolon-remains.grp b/mpq/unit/terran/eidolon-remains.grp index 2630de7..de67d76 100644 Binary files a/mpq/unit/terran/eidolon-remains.grp and b/mpq/unit/terran/eidolon-remains.grp differ diff --git a/mpq/unit/terran/eidolon-shadow.grp b/mpq/unit/terran/eidolon-shadow.grp index 58920c3..c5b620b 100644 Binary files a/mpq/unit/terran/eidolon-shadow.grp and b/mpq/unit/terran/eidolon-shadow.grp differ diff --git a/mpq/unit/terran/eidolon.grp b/mpq/unit/terran/eidolon.grp index 8e3784f..67f1da1 100644 Binary files a/mpq/unit/terran/eidolon.grp and b/mpq/unit/terran/eidolon.grp differ diff --git a/mpq/unit/terran/ministry-damage.lof b/mpq/unit/terran/ministry-damage.lof new file mode 100644 index 0000000..23cd0ca Binary files /dev/null and b/mpq/unit/terran/ministry-damage.lof differ diff --git a/mpq/unit/terran/ministry-shadow.grp b/mpq/unit/terran/ministry-shadow.grp new file mode 100644 index 0000000..323f1d7 Binary files /dev/null and b/mpq/unit/terran/ministry-shadow.grp differ diff --git a/mpq/unit/terran/ministry.grp b/mpq/unit/terran/ministry.grp new file mode 100644 index 0000000..4435058 Binary files /dev/null and b/mpq/unit/terran/ministry.grp differ diff --git a/mpq/unit/terran/watchdog-shadow.grp b/mpq/unit/terran/watchdog-shadow.grp index 8e7732b..294e399 100644 Binary files a/mpq/unit/terran/watchdog-shadow.grp and b/mpq/unit/terran/watchdog-shadow.grp differ diff --git a/mpq/unit/terran/watchdog-turret.grp b/mpq/unit/terran/watchdog-turret.grp index 1cd9b15..c03a283 100644 Binary files a/mpq/unit/terran/watchdog-turret.grp and b/mpq/unit/terran/watchdog-turret.grp differ diff --git a/mpq/unit/terran/watchdog.grp b/mpq/unit/terran/watchdog.grp index dea8d87..2fa6ad3 100644 Binary files a/mpq/unit/terran/watchdog.grp and b/mpq/unit/terran/watchdog.grp differ diff --git a/mpq/unit/wirefram/grpwire.grp b/mpq/unit/wirefram/grpwire.grp index 6ad03fc..771479b 100644 Binary files a/mpq/unit/wirefram/grpwire.grp and b/mpq/unit/wirefram/grpwire.grp differ diff --git a/mpq/unit/wirefram/wirefram.grp b/mpq/unit/wirefram/wirefram.grp index a876ab3..12d8c62 100644 Binary files a/mpq/unit/wirefram/wirefram.grp and b/mpq/unit/wirefram/wirefram.grp differ diff --git a/mpq/unit/zerg/zethrokor-birth.grp b/mpq/unit/zerg/zethrokor-birth.grp index 53657ef..193c700 100644 Binary files a/mpq/unit/zerg/zethrokor-birth.grp and b/mpq/unit/zerg/zethrokor-birth.grp differ diff --git a/mpq/unit/zerg/zethrokor-mutate.grp b/mpq/unit/zerg/zethrokor-mutate.grp index ae2d364..90ea921 100644 Binary files a/mpq/unit/zerg/zethrokor-mutate.grp and b/mpq/unit/zerg/zethrokor-mutate.grp differ diff --git a/mpq/unit/zerg/zethrokor-remains.grp b/mpq/unit/zerg/zethrokor-remains.grp index d0dc69d..0edef2a 100644 Binary files a/mpq/unit/zerg/zethrokor-remains.grp and b/mpq/unit/zerg/zethrokor-remains.grp differ diff --git a/mpq/unit/zerg/zethrokor.grp b/mpq/unit/zerg/zethrokor.grp index d7aa678..be842a8 100644 Binary files a/mpq/unit/zerg/zethrokor.grp and b/mpq/unit/zerg/zethrokor.grp differ diff --git a/patchnotes.md b/patchnotes.md index 6b6768d..9176625 100644 --- a/patchnotes.md +++ b/patchnotes.md @@ -1,264 +1,63 @@ -# 4 September 2026 -## Year 4, month 9, patch 1 +# 19 September 2026 +## Year 4, month 9, patch 2 ## 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 +- Continue technical improvements, bugfixes, and audiovisual additions ahead of the Gauntlet Stages! - [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* +- **User Interface:** + - The HUD can now be toggled with F11! (c. Jesse, b. Londier) + - *Send us your screenshots...* + - Shift-tab now correctly sets minimap colors to red, blue, etc for replay/witness (a. Jesse & DF) + - *Additional functionality forthcoming...* +- **Triggers:** + - New custom trigger actions: (c. Jesse) + - `set_hud` - accepts racial names for racial HUDs + - `set_hud_visibility` - accepts `Visible` (default), `Hidden` (as with F11), or `Cinematic` (must be turned off manually in triggers) + - New custom trigger subcommand for **set_unit_stat** + - **transport_capacity** (b. Lucifirius) -- enables transporting via any unit, modifies transport capacity on any transport +- **User-defined resource areas:** (c. DF) + - Our methodology for user-defined resource areas has changed from the previous system! + - **The location-based system has been removed.** + - To use the new system: + - Select the resource nodes you wish to assign to a specific resarea + - Tick **burrowed** (bottom-left-most status flag) in the unit property panel + - Set the **HP** field to the intended resarea id (a number between 1 and 255) +- **Editor / UMS:** + - Installation traps have been reimplemented! + - The following unit ids are deprecated and should be updated to the new versions in maps (unit layer and triggers): + - **Unit id: old id -> new id** + - Nanite Assembly: 203 -> 261 + - Kalkiir Lake: 204 -> 549 + - Sentinel: 209 -> 260 + - Tarasque: 210 -> 263 + - Anticthon: 211 -> 289 + - Kethraj Keep: 212 -> 303 ## 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) + - Fixed **Arquebus** attempting to attack air units (r. Londier) + - Installation doors can once again be disabled and enabled via triggers - **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) + - Resolved error printout when loading recently-repowered **Engram**s (r. Concealed Organic) + - Corrected **Maverick (Golden)** weaponfire SFX (r. lolrsk8s) +- **Triggers:** + - Allowed **set_player_color** to apply to player 12 (r. 3crow, c. Veeq7) ## 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 + - Ministry, Captaincy (c. Solstice & fasswawds) +- Tweaked models for: + - Cyprian, Eidolon, Hippogriff, Watchdog, Treasury, Quarry, Starpad, Rotary, Zethrokor, Quazilisk (c. Solstice) +- Modified weapon VFX for Okrimnilisk +- Updated wireframes for Savant, Vulture (Upstart), Tartarus Mine, Piety Ward, Tarasque, Rotary, Witness, Cicatus, Vestige, Simulacrum, Phontis (c. jun3hong) +- Added placeholder portrait for Vespene nodes (c. jun3hong) +- Added factional portraits for: Alzurokor, Arquebus, Azanthrokor, Broadside, Camazotz, Cannibal, Cutlass, Garvrokor, Goremast, Morrigan, Quadriga, Serathiel, Shaman (Upstart), Sovrokor, Tartarus Mine, Valkyrie (Hecaton), Vulture (Hecaton), Vulture (Upstart) (c. jun3hong) ## 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. \ No newline at end of file +- **NEW:** [Cyprian (Hecaton)](https://cosmonarchy.com/terran/cyprian-hecaton): + - Factional Cyprian variant for Hecaton Coalition; Has Kelvin Munitions +- **NEW:** [Memphis](https://cosmonarchy.com/terran/memphis): + - Factional Matador replacement for Upstarts; Has anti-air Flak Mode \ No newline at end of file diff --git a/plugins/gptp.qdp b/plugins/gptp.qdp index 03b0b62..35e2781 100644 Binary files a/plugins/gptp.qdp and b/plugins/gptp.qdp differ