feat(totalannihilation): add Megatank unit with multi-barrel weapons and rebalance combat
- Introduce Megatank: medium commander with Twin 150mm Cannon and Side Rocket Pods - Implement multi-barrel weapon system (barrels + barrelSpacing) in TALogic and TARules - Lower DEFENCE_MIN_SKILL from 4 to 3; make first Laser Tower proactive, not reactive - Rebalance unit triangle: Tank now counters Rocket Tank; rockets weak vs vehicle armour - Re-seed campaign missions m05 (67890) and m06 (80808) with updated maps and briefings - Skirmish default theme uses rules default (tropics) instead of hardcoded grasslands - Add intro video before main menu - Update sprite docs and verification tests for new balance
This commit is contained in:
parent
09a62f12cc
commit
045327d38a
Binary file not shown.
|
Before Width: | Height: | Size: 264 KiB After Width: | Height: | Size: 287 KiB |
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 233 KiB After Width: | Height: | Size: 258 KiB |
Binary file not shown.
Binary file not shown.
|
|
@ -598,7 +598,7 @@
|
|||
"id": "m05",
|
||||
"name": "Tropic Vice",
|
||||
"theme": "tropics",
|
||||
"seed": 71644,
|
||||
"seed": 67890,
|
||||
"playerArmy": "arm",
|
||||
"playerCommander": "vance",
|
||||
"enemies": [
|
||||
|
|
@ -628,7 +628,7 @@
|
|||
{
|
||||
"speaker": "ethel",
|
||||
"mood": "idle",
|
||||
"text": "Cy-Bro starts ahead and pushes early. Rocket tanks out-range everything CORE fields."
|
||||
"text": "Cy-Bro starts ahead and pushes early. Rockets crack their base open — armour holds the line getting there."
|
||||
}
|
||||
],
|
||||
"victoryLine": {
|
||||
|
|
@ -646,102 +646,102 @@
|
|||
"h": 96,
|
||||
"theme": "tropics",
|
||||
"rows": [
|
||||
"~~r....^^^^^^^^^^^^...........rr~~~...r...^^^^^^^^^^^^...r...~~~rr...........^^^^^^^^^^^^....r~~",
|
||||
"~~.....^^^^^^^^^^^^...........r.~~~........^^^....^^^........~~~.r...........^^^^^^^^^^^^.....~~",
|
||||
"~~....rr^^^^^^^^^^^............r~~~~.r....................r.~~~~r............^^^^^^^^^^^rr....~~",
|
||||
"~~~......^^^...................~~~~~~~rr................rr~~~~~~~...................^^^......~~~",
|
||||
"~~~~.....rr....................~~~~~~~~~................~~~~~~~~~....................rr.....~~~~",
|
||||
"~~~~......rr.....................~~~~~~rr..............rr~~~~~~.....................rr......~~~~",
|
||||
"~~~~......rr..............rr.....~~.....rr............rr.....~~.....rr..............rr......~~~~",
|
||||
"~~~..................rrrrrrr.....~......rr............rr......~.....rrrrrrr..................~~~",
|
||||
"~~~.................rrrrrrrr.....~r..........................r~.....rrrrrrrr.................~~~",
|
||||
"~~~~................rrrr.............rr..................rr.............rrrr................~~~~",
|
||||
"~~~~~...............rrrr.............rr..................rr.............rrrr...............~~~~~",
|
||||
"~~~~~~................rrr...........rr....................rr...........rrr................~~~~~~",
|
||||
"~~~~~~r...............rr................................................rr...............r~~~~~~",
|
||||
"~~~~~.rr................................................................................rr.~~~~~",
|
||||
"~~~...rr................................................................................rr...~~~",
|
||||
"~~rr........................................................................................rr~~",
|
||||
"~~rr....................rr..............rr............rr..............rr....................rr~~",
|
||||
".................rr....rrr..............rr............rr..............rrr....rr.................",
|
||||
".................rr..~~.....r....r...........rrrrrr...........r....r.....~~..rr.................",
|
||||
".................r..~~~~...~~~~~~~~~.......^^^^..^^^^.......~~~~~~~~~...~~~~..r.................",
|
||||
"..................r.~~~~..~~~~~~~~~~~......^^^^..^^^^......~~~~~~~~~~~..~~~~.r..................",
|
||||
"..................r~~~~~~~~~~~~~~~~~~.....^^^^^^^^^^^^.....~~~~~~~~~~~~~~~~~~r..................",
|
||||
".................r.~~~~~~~~~~~~~~~~~~.....^^^^^^^^^^^^.....~~~~~~~~~~~~~~~~~~.r.................",
|
||||
"................rrr~~~~~~~~~~~~~~~~~~......^^^^..^^^^......~~~~~~~~~~~~~~~~~~rrr................",
|
||||
"..............rrrr~~~~~~~.~~~~~~~~~~~...rr.^^^^..^^^^.rr...~~~~~~~~~~~.~~~~~~~rrrr..............",
|
||||
"..............rrr.~~~~~~...~~~~~~~~~~...rrr^^^^..^^^^rrr...~~~~~~~~~~...~~~~~~.rrr..............",
|
||||
"..............r............................^^^^..^^^^............................r..............",
|
||||
"..............r...........................^^^^^^^^^^^^...........................r..............",
|
||||
"............rrrrrr.......................^^^^^^^^^^^^^^.......................rrrrrr............",
|
||||
"........rr.rrrrrrr......................^^^^^^^^^^^^^^^^......................rrrrrrr.rr........",
|
||||
"........rrrrr..rrr....................^^^^^^^^^^^^^^^^^^^^....................rrr..rrrrr........",
|
||||
"...........rr...rr...................^^^^^^^^^^^^^^^^^^^^^^...................rr...rr...........",
|
||||
"...........rr....r...........^......^^^^^^^^^^^^^^^^^^^^^^^^......^...........r....rr...........",
|
||||
"...........................r^^^...r^^^^^^^^^^^^^^^^^^^^^^^^^^r...^^^r...........................",
|
||||
"r...........................^^^....^^^^^^^^^^^^^^^^^^^^^^^^^^....^^^...........................r",
|
||||
"...................................r^^^^^^^^^^^^^^^^^^^^^^^^r...................................",
|
||||
"......................................^^^^^^^^^^^^^^^^^^^^......................................",
|
||||
".................................rrr.....^^^^^^..^^^^^^.....rrr.................................",
|
||||
".........MM.....................rrrrr.....^^^^....^^^^.....rrrrr.....................MM.........",
|
||||
".........MM.....^^...............rrrrr....................rrrrr...............^^.....MM.........",
|
||||
"................^^...............rrrrr....................rrrrr...............^^................",
|
||||
"...............^^^...............rrrrr....................rrrrr...............^^^...............",
|
||||
"................^^^...............r..........................r...............^^^................",
|
||||
"~~...............^^..........................................................^^...............~~",
|
||||
"~~~.MM...........^^..........................................................^^...........MM.~~~",
|
||||
"~~~.MM.......MM...^...rr................................................rr...^...MM.......MM.~~~",
|
||||
"~~...........MM.......rr................................................rr.......MM...........~~",
|
||||
"~.....................rr................................................rr.....................~",
|
||||
"r..............................................................................................r",
|
||||
"....MM............rr........................................................rr............MM....",
|
||||
"....MM............rr........................................................rr............MM....",
|
||||
"..................rr~~~~................................................~~~~rr..................",
|
||||
"..................r.~~~~~~~..r..............^^....^^..............r..~~~~~~~.r..................",
|
||||
"...................~~~~~~~~rr..............^^^....^^^..............rr~~~~~~~~...................",
|
||||
"...................~~~~~~~~~...............^^^^..^^^^...............~~~~~~~~~...................",
|
||||
"rr.................~~~~~~~~~..............^^^^^..^^^^^..............~~~~~~~~~.................rr",
|
||||
"rrr................~~~~~~~~~..............^^^^^..^^^^^..............~~~~~~~~~................rrr",
|
||||
"..r................~~~~~~~~~................^^....^^................~~~~~~~~~................r..",
|
||||
"...................~~~~~~~~..........................................~~~~~~~~...................",
|
||||
"..................r~~~~~~~~.r......................................r.~~~~~~~~r..................",
|
||||
"...................r~~~~~~.rrr.rr......rrrr..........rrrr......rr.rrr.~~~~~~r...................",
|
||||
"...................r~~~~rrrrrrrrr.....rrrr............rrrr.....rrrrrrrrr~~~~r...................",
|
||||
"....................rr..rrrrrr.rrr....rrrr............rrrr....rrr.rrrrrr..rr....................",
|
||||
".............r..........rrrrr....r....rr................rr....r....rrrrr..........r.............",
|
||||
"...........rrrrr.........rr..........rr..................rr..........rr.........rrrrr...........",
|
||||
"..........~~~.rr.........r...........rr.....~~....~~.....rr...........r.........rr.~~~..........",
|
||||
"........r~~~~~rr.........rr..........rr....~~~~~~~~~~....rr..........rr.........rr~~~~~r........",
|
||||
"........r~~~~~rrr.......rrr..........rrr...~~~~~~~~~~...rrr..........rrr.......rrr~~~~~r........",
|
||||
".........~~~~~..rr......rrr...........rr...r~~~rr~~~r...rr...........rrr......rr..~~~~~.........",
|
||||
".........~~~~~..rr......rrr..........................................rrr......rr..~~~~~.........",
|
||||
"........~~~~~~..rr............................................................rr..~~~~~~........",
|
||||
"........~~~~~~..rr............................................................rr..~~~~~~........",
|
||||
"........~~~~~~..rr............................................................rr..~~~~~~........",
|
||||
"........~~~~~~~.......................rrrr............rrrr.......................~~~~~~~........",
|
||||
".......~~~~~~~~......r..........r^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^r..........r......~~~~~~~~.......",
|
||||
".......~~~~~~~~.....rrrr........^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^........rrrr.....~~~~~~~~.......",
|
||||
".......~~~~~~~~....rr.rr.......^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^.......rr.rr....~~~~~~~~.......",
|
||||
".......~~~~~~~~.....~~.r.......^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^.......r.~~.....~~~~~~~~.......",
|
||||
".......~~~~~~~~.....~~..r......^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^......r..~~.....~~~~~~~~.......",
|
||||
".......~~~~~~~~.....~~..rrr....^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^....rrr..~~.....~~~~~~~~.......",
|
||||
"......r~~~~~~~~.....~~~..rrr....^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^....rrr..~~~.....~~~~~~~~r......",
|
||||
"......rr~~~~~~~.....~~~..rrr.....^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^.....rrr..~~~.....~~~~~~~rr......",
|
||||
"......rr~~~~~~~.....~~~~............^^^^^^^^^^^^^^^^^^^^^^^^............~~~~.....~~~~~~~rr......",
|
||||
"......rr.~~~~~r.....~~~~...............rrrr..........rrrr...............~~~~.....r~~~~~.rr......",
|
||||
"^.........~~~~r...r~~~~~~..............rrrrrrrr..rrrrrrrr..............~~~~~~r...r~~~~.........^",
|
||||
"^^............rr..r~~~~~~~................rrrrrrrrrrrr................~~~~~~~r..rr............^^",
|
||||
"^^^...........rr..r~~~~~~~................rrr..rr..rrr................~~~~~~~r..rr...........^^^",
|
||||
"^^^.....rr........r~~~~~~~...............rrrr......rrrr...............~~~~~~~r........rr.....^^^",
|
||||
"^^^^....rr.........~~~~~~~~...............rr........rr...............~~~~~~~~.........rr....^^^^",
|
||||
"^^^^...............~~~~~~~~..........................................~~~~~~~~...............^^^^",
|
||||
"^^^^...............~~~~~~~~..........................................~~~~~~~~...............^^^^",
|
||||
"^^^^...............~~~~~~~~..........................................~~~~~~~~...............^^^^",
|
||||
"^^^................~~~~~~~~..........................................~~~~~~~~................^^^",
|
||||
"^^^................~~~~~~~~...........r....r........r....r...........~~~~~~~~................^^^",
|
||||
"^^^.................~~~~~~...........rrr..rrr......rrr..rrr...........~~~~~~.................^^^",
|
||||
"^^.....r......rr.r..~~~~~~............r....r........r....r............~~~~~~..r.rr......r.....^^"
|
||||
"...............rr.rr.............rr....rrrr~~~....~~~rrrr....rr.............rr.rr...............",
|
||||
"r.............rr..rr...................rrr~~~~~..~~~~~rrr...................rr..rr.............r",
|
||||
"..........rrrrrr...rrr...................r~~~~~..~~~~~r...................rrr...rrrrrr..........",
|
||||
".........rrrrr.......rr..................~~~~~~~~~~~~~~..................rr.......rrrrr.........",
|
||||
".......rr^^^^^............................~~~~~~~~~~~~............................^^^^^rr.......",
|
||||
"...r.^^^^^^^^^^..................................................................^^^^^^^^^^.r...",
|
||||
"...r^^^^^^^^^^^^................................................................^^^^^^^^^^^^r...",
|
||||
"..r^^^^^^^^^^^^^^^^...rr.........^r..........................r^.........rr...^^^^^^^^^^^^^^^^r..",
|
||||
"..^^^^^^^^^^^^^^^^^^^^^rrrr...r^^^^..........................^^^^r...rrrr^^^^^^^^^^^^^^^^^^^^^..",
|
||||
".^^^^^^^^^^^^^^^^^^^^^^r.rr...^^^^^..........................^^^^^...rr.r^^^^^^^^^^^^^^^^^^^^^^.",
|
||||
"^^^^^^^^^^^^^^^^^^^^^^^^..r...^^^^^^^.r..................r.^^^^^^^...r..^^^^^^^^^^^^^^^^^^^^^^^^",
|
||||
"^^^^^^^^^^^^^^^^^^^^^^^^^^^....^^^^^^^^^................^^^^^^^^^....^^^^^^^^^^^^^^^^^^^^^^^^^^^",
|
||||
"...^^^^..^.........^^^^^^^^.....^^^^^^^^^..............^^^^^^^^^.....^^^^^^^^.........^..^^^^...",
|
||||
"...rrr.............^^^^^^^^.....^^^^^^^^^..............^^^^^^^^^.....^^^^^^^^.............rrr...",
|
||||
"...........^^^.....^^^^^^^^....^^^^^^^^^................^^^^^^^^^....^^^^^^^^.....^^^...........",
|
||||
"..........^^^^^....^^^^^^^.....^^^^^^^....................^^^^^^^.....^^^^^^^....^^^^^..........",
|
||||
"..........^^^^^.....^^^^rr.....^^^^^^...rr............rr...^^^^^^.....rr^^^^.....^^^^^..........",
|
||||
"...........^^^^....r^^^rrr.....^^^^^^..rrrr..........rrrr..^^^^^^.....rrr^^^r....^^^^...........",
|
||||
"...........^^^^r...rr........r^^^^^^^^^rrrrr........rrrrr^^^^^^^^^r........rr...r^^^^...........",
|
||||
"...........^^^^.r............^^^^^^^^^^^^^r..........r^^^^^^^^^^^^^............r.^^^^...........",
|
||||
"...........^^^^^rr..........^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^..........rr^^^^^...........",
|
||||
"............^^..rr..........^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^..........rr..^^............",
|
||||
"....rrr.....................^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^.....................rrr....",
|
||||
"....rrrr......................^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^......................rrrr....",
|
||||
"......r...........................^^^^^^^^^^^^^^^^^^^^^^^^^^^^...........................r......",
|
||||
"...................................^^^^^^^^^^^^^^^^^^^^^^^^^^...................................",
|
||||
"rrr.................................^^^^^^^^^^^^^^^^^^^^^^^^.................................rrr",
|
||||
"..r..................................^......rrr..rrr......^..................................r..",
|
||||
"........rrr..........................................................................rrr........",
|
||||
"........rrr..........................................................................rrr........",
|
||||
"........rrr......rr...........rr................................rr...........rr......rrr........",
|
||||
"r.........r.....rr............rr...rr......................rr...rr............rr.....r.........r",
|
||||
"................rr...........~..rrrrr......................rrrrr..~...........rr................",
|
||||
"..................rrrr.......~~~.r.~~~~~~~............~~~~~~~.r.~~~.......rrrr..................",
|
||||
"..................rrrr.......~~~...~~~~~~~~r........r~~~~~~~~...~~~.......rrrr..................",
|
||||
"................rrrrrr.......~~......~~~~~~~~......~~~~~~~~......~~.......rrrrrr................",
|
||||
"................rrrrr.................r..~~~~~....~~~~~..r.................rrrrr................",
|
||||
".................rrr......................~~~~....~~~~......................rrr.................",
|
||||
"..................rr....~.................~~~~~rr~~~~~.................~....rr..................",
|
||||
"............rr....rr...r~.................~~~~~..~~~~~.................~r...rr....rr............",
|
||||
"~r..........~~....rr...r~.................~~~~~..~~~~~.................~r...rr....~~..........r~",
|
||||
"~~............~~~~rr...~~........^r.......~~~~~~~~~~~~.......r^........~~...rr~~~~............~~",
|
||||
"~~..............~~rr..r~~.......^^^.......~~~~~~~~~~~~.......^^^.......~~r..rr~~..............~~",
|
||||
"~~~..............~~.MMr~~.......^^^^......~~~~~~~~~~~~......^^^^.......~~rMM.~~..............~~~",
|
||||
"~~~r.............~~.MM.~~......^^^^^....rr~~~~~~~~~~~~rr....^^^^^......~~.MM.~~.............r~~~",
|
||||
"~~~...............~....~~......^^^^^....rr~~~~~~~~~~~~rr....^^^^^......~~....~...............~~~",
|
||||
"~~~..MM...........~....~~......^^^^^....rr.~~~~..~~~~.rr....^^^^^......~~....~...........MM..~~~",
|
||||
"~~r..MM...........r............^^^^^.......~~~....~~~.......^^^^^............r...........MM..r~~",
|
||||
"~~..............................^^^^........rr....rr........^^^^..............................~~",
|
||||
"~~...................rr.........^^^^........................^^^^.........rr...................~~",
|
||||
"~.............MM....rrr.........^^^^........................^^^^.........rrr....MM.............~",
|
||||
"..............MM....rrr.........^^^..........................^^^.........rrr....MM..............",
|
||||
"................................^^^..........................^^^................................",
|
||||
"................................^^^..........................^^^................................",
|
||||
".................................^^r........................r^^.................................",
|
||||
"...................................rr......................rr...................................",
|
||||
"..........MM.......................rr......................rr.......................MM..........",
|
||||
"..........MM........................................................................MM..........",
|
||||
".....rr..................................................................................rr.....",
|
||||
".....rr..................................................................................rr.....",
|
||||
".....rr..................................................................................rr.....",
|
||||
".....rr..................................................................................rr.....",
|
||||
"....^rr.................~~~..........................................~~~.................rr^....",
|
||||
"..^^^^^................~~~~~~~~....rr......................rr....~~~~~~~~................^^^^^..",
|
||||
".^^^^^^^r.............~~~~~~~~~~...~~~~~~r.....rr.....r~~~~~~...~~~~~~~~~~.............r^^^^^^^.",
|
||||
"^^^^^^^^^.............~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~.............^^^^^^^^^",
|
||||
"^^^^^^^^^.............~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~.............^^^^^^^^^",
|
||||
"^^^^^^^^^............~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~............^^^^^^^^^",
|
||||
"^^^^^^^^^.............~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~.............^^^^^^^^^",
|
||||
"^^^^^^^^^....rr........~~~~~~~~~...~~~~~~~~~~~~~~~~~~~~~~~~~~...~~~~~~~~~........rr....^^^^^^^^^",
|
||||
"..^^^^^^r....r.........r~~~~~~r....rr~~~~~~~~~~~~~~~~~~~~~~rr....r~~~~~~r.........r....r^^^^^^..",
|
||||
"...^^^^......r...............rr....r....~~~~~~~~~~~~~~~~....r....rr...............r......^^^^...",
|
||||
"....^^r......rr..............rr....rr.....~~~~~~~~~~~~.....rr....rr..............rr......r^^....",
|
||||
".....rr.......rr.............rr.....rr....~~~~~~~~~~~~....rr.....rr.............rr.......rr.....",
|
||||
".....rr......................rr......r.....~~~~..~~~~.....r......rr......................rr.....",
|
||||
".....rr......................rr.^^^........~~~~rr~~~~........^^^.rr......................rr.....",
|
||||
".....rr......................rr^^^^^.......~~~~rr~~~~.......^^^^^rr......................rr.....",
|
||||
".....rr......................r^^^^^^.......~~~~..~~~~.......^^^^^^r......................rr.....",
|
||||
"..............................^^^^^^.......~~~~..~~~~.......^^^^^^..............................",
|
||||
"..............................^^^^^^.......~~~....~~~.......^^^^^^..............................",
|
||||
".....................^r.......^^^^^^r.......~~....~~.......r^^^^^^.......r^.....................",
|
||||
".....................^r........^^^^^r.......~~....~~.......r^^^^^........r^.....................",
|
||||
"...............................^^^^rr......................rr^^^^...............................",
|
||||
"................................^^^..........................^^^................................",
|
||||
"................................^^^..........................^^^................................",
|
||||
"...............................rr.......rrr..........rrr.......rr...............................",
|
||||
"r..............................rr.......rrr..........rrr.......rr..............................r",
|
||||
"r..............................rr.........r..........r.........rr..............................r",
|
||||
".....rr........................r..........rr........rr..........r........................rr.....",
|
||||
".....rr......................rr...........rrr......rrr...........rr......................rr.....",
|
||||
"...........rr................rr............rrrr..rrrr............rr................rr...........",
|
||||
"...........rr................rr............rrrr..rrrr............rr................rr...........",
|
||||
"...........rr.....rr.........rr...........rrrr....rrrr...........rr.........rr.....rr...........",
|
||||
"..................rr........................................................rr..................",
|
||||
"..................rrr......................................................rrr..................",
|
||||
"..................r.rr..........r..............................r..........rr.r.................."
|
||||
],
|
||||
"starts": [
|
||||
{
|
||||
|
|
@ -787,7 +787,7 @@
|
|||
"id": "m06",
|
||||
"name": "Annihilation",
|
||||
"theme": "snowfields",
|
||||
"seed": 63541,
|
||||
"seed": 80808,
|
||||
"playerArmy": "arm",
|
||||
"playerCommander": "vance",
|
||||
"enemies": [
|
||||
|
|
@ -817,7 +817,7 @@
|
|||
{
|
||||
"speaker": "ethel",
|
||||
"mood": "idle",
|
||||
"text": "KLAXON at full strength with a base already standing. Nothing clever left — out-build it and end it."
|
||||
"text": "KLAXON at full strength with a base already standing, dug in behind its own defences. Nothing clever left — out-build it and end it."
|
||||
}
|
||||
],
|
||||
"victoryLine": {
|
||||
|
|
@ -835,102 +835,102 @@
|
|||
"h": 96,
|
||||
"theme": "snowfields",
|
||||
"rows": [
|
||||
"................^^^...^^^^^.............^^^^^^.......r...rr....r.........r....r...........rrr...",
|
||||
"..............MM.^^..r^^^^^..............^^^^^............................................rrr...",
|
||||
"..............MM......^^^^^^...............rr..............................................rr...",
|
||||
"......................^^^^^^..............r...............................................rrr...",
|
||||
"....................................................................rrr...................rrr...",
|
||||
"........................rr..........................................rrrr.....................r..",
|
||||
"........................rr.........................................^..rr.......rr............rr.",
|
||||
"................................................................r^^^^^..........rr...........rr.",
|
||||
".......................~~~.......................................^^^^^^.......................rr",
|
||||
"......................~~~~~.....................................^^^^^^^^........................",
|
||||
"......................~~~~~......................................^^^^^^^........................",
|
||||
"......................~~~~.....rr..............................rrrr...........................rr",
|
||||
".......................~~......rr...........................rrrrr.......................rr....rr",
|
||||
"...............................r...rr.................rr....rrrr.........................r....rr",
|
||||
"................................rrrrr................rrr.....rrr................................",
|
||||
"...............MM................rrrr..............rrrr.......rrr...............................",
|
||||
"...............MM...............rrr...............rrrrr...rr..rr................................",
|
||||
"......r..........................rr..r............rrrr....rrrrrr................rrr............r",
|
||||
"r....MM.............................rrr.........................................rrr.............",
|
||||
".....MM..............................rr...........................~~~~~~~~~~~~~~~~~.............",
|
||||
".......................^^^^..rr......rr...r~~~..................~~~~~~~~~~~~~~~~~~~~............",
|
||||
".........MM...........^^^^^.rrr......rr...~~~~~................~~~~~~~~~~~~~~~~~~~~~~~..........",
|
||||
".........MM.........^^^^^^^rrrr..........~~~~~~~...............~~~~~~~~~~~~~~~~~~~~~~~~..rr....r",
|
||||
"^^................r^^^^^rr...rr..........~~~~~~~...............~~~~~~~~~~~~~~~~~~~~~~~~.rrrrrrrr",
|
||||
"^^^...............^^^^^..................~~~~~~~.......rr......~~~~~~~~~~~~~~~~~~~~~~~~~.rrrr...",
|
||||
"^^^................^^^^...................~~~~~........rr.......~~~~~~~~~~~~~~~~~~~~~~~~~~......",
|
||||
"r..................^^^^.........................................~~~~~~~~~~~~~~~~~~~~~~~~~~~~....",
|
||||
"r..................rr^............................................~~~~~~~~~~~~~~~~~~~~~~~~~~~~..",
|
||||
".......................................................................~~~~~~~~~~~~~~~~~~~~~~~~.",
|
||||
"...rr..................rr.................................................~~~~~~~~~~~~~~~~~~~~~~",
|
||||
"r..rr..................rrr.......................................................~~~~~~~~~~~~~~~",
|
||||
"r..rr..................rrrr........................................................~~~~~~~~~~~~~",
|
||||
"...rr....................rr..........rr....................r........................~~~~~~~~~~~~",
|
||||
"..........................rr.........rr...................rrr.......................~~~~~~~~~~~~",
|
||||
"..........................rr......................rr.......r........................r~~~~~~~~~~~",
|
||||
".........................rrrr...rr................rr.................................r~~~~~~~~~~",
|
||||
".........................rrrr...rr..r.............rr.................................rrr~~~~~~..",
|
||||
".........................r.r.....rrrrrr.............................................rrrrrrrrr...",
|
||||
".................................rr..rr................^^...........................rr.rr.......",
|
||||
"................................rr...................^^^^^..rr..................................",
|
||||
".....rrr............~~..........rr..............^^^^^^^^^^..rr..................................",
|
||||
".....rrr.......rr...~~..........rr........^^^^^^^^^^^^^^^^..rr..................................",
|
||||
".......rr......rr..~~~..........rr.......^^^^^^^^^^^^^^^^^..rr..................................",
|
||||
"........rr.........~~~..................^^^^^^^^^^^^^^^^^^..rrrr..............^.................",
|
||||
"........rr.........~~~~.................^^^^^^^^^^^^^^^^^^^.rrrr.............^^^................",
|
||||
"...................~~~~................^^^^^^^^^^^^^^^^^^^..rrr..............^^^rrr......rrrrrrr",
|
||||
"...................~~~..................^^^^^^^^^^^^^^^^^^..rr...............^^^rrr......rrrrrrr",
|
||||
"....................~~..................^^^^^^^^^^^^^^^^......................^................r",
|
||||
"r................^......................^^^^^^^^^^^^^^^^..................~~....................",
|
||||
"rrrrrrr......rrr^^^...............rr..^^^^^^^^^^^^^^^^^^..................~~~...................",
|
||||
"rrrrrrr......rrr^^^..............rrr..^^^^^^^^^^^^^^^^^^^................~~~~...................",
|
||||
"................^^^.............rrrr.^^^^^^^^^^^^^^^^^^^.................~~~~.........rr........",
|
||||
".................^..............rrrr..^^^^^^^^^^^^^^^^^^..................~~~.........rr........",
|
||||
"..................................rr..^^^^^^^^^^^^^^^^^.......rr..........~~~..rr......rr.......",
|
||||
"..................................rr..^^^^^^^^^^^^^^^^........rr..........~~...rr.......rrr.....",
|
||||
"..................................rr..^^^^^^^^^^..............rr..........~~............rrr.....",
|
||||
"..................................rr..^^^^^...................rr................................",
|
||||
".......rr.rr...........................^^................rr..rr.................................",
|
||||
"...rrrrrrrrr.............................................rrrrrr.....r.r.........................",
|
||||
"..~~~~~~rrr.................................rr.............r..rr...rrrr.........................",
|
||||
"~~~~~~~~~~r.................................rr................rr...rrrr.........................",
|
||||
"~~~~~~~~~~~r........................r.......rr......................rr..........................",
|
||||
"~~~~~~~~~~~~.......................rrr...................rr.........rr..........................",
|
||||
"~~~~~~~~~~~~........................r....................rr..........rr....................rr...",
|
||||
"~~~~~~~~~~~~~........................................................rrrr..................rr..r",
|
||||
"~~~~~~~~~~~~~~~.......................................................rrr..................rr..r",
|
||||
"~~~~~~~~~~~~~~~~~~~~~~.................................................rr..................rr...",
|
||||
".~~~~~~~~~~~~~~~~~~~~~~~~.......................................................................",
|
||||
"..~~~~~~~~~~~~~~~~~~~~~~~~~~~~............................................^rr..................r",
|
||||
"....~~~~~~~~~~~~~~~~~~~~~~~~~~~~.........................................^^^^..................r",
|
||||
"......~~~~~~~~~~~~~~~~~~~~~~~~~~.......rr........~~~~~...................^^^^................^^^",
|
||||
"...rrrr.~~~~~~~~~~~~~~~~~~~~~~~~~......rr.......~~~~~~~..................^^^^^...............^^^",
|
||||
"rrrrrrrr.~~~~~~~~~~~~~~~~~~~~~~~~...............~~~~~~~..........rr...rr^^^^^r................^^",
|
||||
"r....rr..~~~~~~~~~~~~~~~~~~~~~~~~...............~~~~~~~..........rrrr^^^^^^^.........MM.........",
|
||||
"..........~~~~~~~~~~~~~~~~~~~~~~~................~~~~~...rr......rrr.^^^^^...........MM.........",
|
||||
"............~~~~~~~~~~~~~~~~~~~~..................~~~r...rr......rr..^^^^.......................",
|
||||
".............~~~~~~~~~~~~~~~~~...........................rr..............................MM.....",
|
||||
".............rrr.........................................rrr.............................MM....r",
|
||||
"r............rrr................rrrrrr....rrrr............r..rr..........................r......",
|
||||
"................................rr..rr...rrrrr...............rrr...............MM...............",
|
||||
"...............................rrr.......rrrr..............rrrr................MM...............",
|
||||
"................................rrr.....rrr................rrrrr................................",
|
||||
"rr....r.........................rrrr....rr.................rr...r...............................",
|
||||
"rr....rr.......................rrrrr...........................rr......~~.......................",
|
||||
"rr...........................rrrr..............................rr.....~~~~......................",
|
||||
"........................^^^^^^^......................................~~~~~......................",
|
||||
"........................^^^^^^^^.....................................~~~~~......................",
|
||||
"rr.......................^^^^^^.......................................~~~.......................",
|
||||
".rr...........rr..........^^^^^r................................................................",
|
||||
".rr............rr.......rr..^.........................................rr........................",
|
||||
"..r.....................rrrr..........................................rr........................",
|
||||
"...rrr...................rrr....................................................................",
|
||||
"...rrr...............................................r..............^^^^^^......................",
|
||||
"...rr..............................................rr...............^^^^^^......MM..............",
|
||||
"...rrr............................................^^^^^..............^^^^^r..^^.MM..............",
|
||||
"...rrr...........r....r.........r....rr...r.......^^^^^^.............^^^^^...^^^................"
|
||||
"~~~r....r...rrrrrr..........r.~~~~~~...............^^^^^^^^^^^^^^..................r....r..^^^^^",
|
||||
"~~~r..........r....MM.........~~~~~~...............^^^^^^^^^^^^^...........................^^^^^",
|
||||
"~~~...............rMM.........~~~~~r................^^^^^^^^^^^............................^^^^^",
|
||||
"~~~...............rr..............r...................^^^^^^............................rr.^^^^^",
|
||||
"rr................rrrr....................................r..........rr.................^^^^^^^^",
|
||||
"...................rrrr.r............................................rr................^^^^^^^^^",
|
||||
"...................rrrrrrrr............................................................^^^^^^^^^",
|
||||
"....................r...rr..................r...........................................^^^^^^rr",
|
||||
"r.....MM...................................r^^................rr........................^^^^^^..",
|
||||
"......MM.............^^^..................^^^^^............rrrrrrrrr...................^^^^^^^^.",
|
||||
"..MM................^^^^^^.............rr^^^^^^^...........rrrrrrrrr.................r^^^^^^^^^^",
|
||||
"..MM...............^^^^^^^...rr........r^^^^^^^^^............r....^^r................^^^^^^^^^^^",
|
||||
"...................^^^^^^^..rrr..rr....r^^^^^^^^^.................^^^................^^^^^^^^^^^",
|
||||
"..................r^^^^^^^rrrrrr.rr....r^^^^^^^^^..................^........rr.......^^^^^^^^^^^",
|
||||
"..................r^^^^^^...rrrr..........^^^^^^rr.....rrrrrrr..............rrrrr.....^^^^^^^^^.",
|
||||
"..................^^^^^^....rrrrr................rrrrr~~~~~rrr..............rrrrr........r...r..",
|
||||
".................^^^^^^r...rrr.rr..~.............rrr~~~~~~~~~.............................rrr...",
|
||||
"~..............^^^^^.^.....rr....~~~~.rrr........rrr~~~~~~~~~..............................r....",
|
||||
"~~.........r^^^^^^..............~~~~..rrr.............~~~~~~....................................",
|
||||
"~~MM.......^^^^^...............~~~~........................rrrrrr...............................",
|
||||
"~~MM.......^^^^^..............~~~~~........................rrrrrr...............................",
|
||||
"~~~.......r^^^^^.............~~~~~~.........................rrrr................................",
|
||||
"~~........^^^^^^^.............~~~~~.............................................................",
|
||||
"..........^^^^^^^^..............~~~.............................................rrr.....r^......",
|
||||
".........r^^^^^^^^................r.............................................rrr....^^^^.....",
|
||||
".........r^^^^^^^^rrrr.....r....................................................rrrr...^^^^^....",
|
||||
"r..........^^^^^^^rrrr....rrr......................................................rr..^^^^^....",
|
||||
"r.............rrr....rrrrr.rr......................................................rrrrr^^^.....",
|
||||
".rrrr........rrrr.......^^..r.......................................................rr..........",
|
||||
"..rrrr.......rr........^^^^^^.........................r...r...............................rrr...",
|
||||
"^^.rrr............rr..r^^^^^^r.......................^^^^^^^............................^^^^^^^^",
|
||||
"^^.rrrr...........rrrr.^^^^^.......................^^^^^^^^^^^^.r.......................^^^^^^^^",
|
||||
"^^rrrrr........rrrr...^^^^^.....^^^^^.............^^^^^^^^^^^^^^^rr....................^^^^^^^^^",
|
||||
"^^rrr..........rrr^...^^^^.....r^^^^^.............^^^^^^^^^^^^^^^^^....................^^^^^^^^^",
|
||||
"^^.rr..........rrr....^^^r.....r^^^^...............^^^^^^^^^^^^^........................^^^^^^^^",
|
||||
"^..rr..rr...............r.......^^..................^^^^^^^^^..............rrr..................",
|
||||
"....r.rrr...............r...^^^^.....................r^^^^................rrrr~.................",
|
||||
".....rrrr..............rrr..^^^^.....................rr...................rrrr~.................",
|
||||
"r......rr...............r...^^^^.....................rr.........................................",
|
||||
".r...........................^^^^^^...r...........rrr........................................rr.",
|
||||
".rr..........................^^^^^^^rrrr..........rrr.......................................rrr.",
|
||||
"..r...................~~~....^^^^^^^^^^r.r..........r.......................................rrr.",
|
||||
"~~~....rrr..........~~~~~~...^^^^^^^^^^^^^^^^^^.............................................rrrr",
|
||||
"~~~~...rrrr........~~~~~~~....^^^^^^^^^^^^^^^^^^..........rr..................................~~",
|
||||
"~~~~...rrrr........~~~~~~~....^^^^^^^^^^^^^^^^^^^.........rr......~~~........................~~~",
|
||||
"~~~~...rr..........~~~~~~~....^^^^^^^^^^^^^^^^^^^..........r......~~~........................~~~",
|
||||
"~~~~...rr..........~~~~~~~....^^^^^^^^^^^^^^^^^^.r........rr......~~..........................~~",
|
||||
"~~~~...rr..........~~~~~~~....^^^^^^^^^^^^^^^^^..rrrrr....rr..r...~~.....r....................~~",
|
||||
"~~....................r.....~~...r..rr....rrrrr..^^^^^^^^^^^^^^^^^....~~~~~~~..........rr...~~~~",
|
||||
"~~..........................~~......rr........r.^^^^^^^^^^^^^^^^^^....~~~~~~~..........rr...~~~~",
|
||||
"~~~........................~~~......r..........^^^^^^^^^^^^^^^^^^^....~~~~~~~..........rr...~~~~",
|
||||
"~~~........................~~~......rr.........^^^^^^^^^^^^^^^^^^^....~~~~~~~........rrrr...~~~~",
|
||||
"~~..................................rr..........^^^^^^^^^^^^^^^^^^....~~~~~~~........rrrr...~~~~",
|
||||
"rrrr.............................................^^^^^^^^^^^^^^^^^^...~~~~~~..........rrr....~~~",
|
||||
".rrr.......................................r..........r.r^^^^^^^^^^....~~~...................r..",
|
||||
".rrr.......................................rrr..........rrrr^^^^^^^..........................rr.",
|
||||
".rr........................................rrr...........r...^^^^^^...........................r.",
|
||||
".........................................rr.....................^^^^...r...............rr......r",
|
||||
".................~rrrr...................rr.....................^^^^..rrr..............rrrr.....",
|
||||
".................~rrrr................^^^^r.....................^^^^...r...............rrr.r....",
|
||||
"..................rrr..............^^^^^^^^^..................^^.......r...............rr..rr..^",
|
||||
"^^^^^^^^........................^^^^^^^^^^^^^...............^^^^r.....r^^^....rrr..........rr.^^",
|
||||
"^^^^^^^^^....................^^^^^^^^^^^^^^^^^.............^^^^^r.....^^^^...^rrr..........rrr^^",
|
||||
"^^^^^^^^^....................rr^^^^^^^^^^^^^^^.............^^^^^.....^^^^^...rrrr........rrrrr^^",
|
||||
"^^^^^^^^.......................r.^^^^^^^^^^^^.......................^^^^^.rrrr...........rrrr.^^",
|
||||
"^^^^^^^^............................^^^^^^^.......................r^^^^^^r..rr............rrr.^^",
|
||||
"...rrr...............................r...r.........................^^^^^^........rr.......rrrr..",
|
||||
"..........rr.......................................................r..^^.......rrrr........rrrr.",
|
||||
".....^^^rrrrr......................................................rr.rrrrr....rrr.............r",
|
||||
"....^^^^^..rr......................................................rrr....rrrr^^^^^^^..........r",
|
||||
"....^^^^^...rrrr....................................................r.....rrrr^^^^^^^^r.........",
|
||||
".....^^^^....rrr.............................................r................^^^^^^^^r.........",
|
||||
"......^r.....rrr.............................................~~~..............^^^^^^^^..........",
|
||||
".............................................................~~~~~.............^^^^^^^........~~",
|
||||
"................................rrrr.........................~~~~~~.............^^^^^r.......~~~",
|
||||
"...............................rrrrrr........................~~~~~..............^^^^^.......MM~~",
|
||||
"...............................rrrrrr........................~~~~...............^^^^^.......MM~~",
|
||||
"....................................~~~~~~.............rrr..~~~~..............^^^^^^r.........~~",
|
||||
"....r..............................~~~~~~~~~rrr........rrr.~~~~....rr.....^.^^^^^..............~",
|
||||
"...rrr.............................~~~~~~~~~rrr.............~..rr.rrr...r^^^^^^.................",
|
||||
"..r...r........rrrrr..............rrr~~~~~rrrrr................rrrrr....^^^^^^..................",
|
||||
".^^^^^^^^^.....rrrrr..............rrrrrrr.....rr^^^^^^..........rrrr...^^^^^^r..................",
|
||||
"^^^^^^^^^^^.......rr........^..................^^^^^^^^^r....rr.rrrrrr^^^^^^^r..................",
|
||||
"^^^^^^^^^^^................^^^.................^^^^^^^^^r....rr..rrr..^^^^^^^...................",
|
||||
"^^^^^^^^^^^................r^^....r............^^^^^^^^^r........rr...^^^^^^^...............MM..",
|
||||
"^^^^^^^^^^r.................rrrrrrrrr...........^^^^^^^rr.............^^^^^^................MM..",
|
||||
".^^^^^^^^...................rrrrrrrrr............^^^^^..................^^^.............MM......",
|
||||
"..^^^^^^........................rr................^^r...................................MM.....r",
|
||||
"rr^^^^^^...........................................r..................rr...r....................",
|
||||
"^^^^^^^^^............................................................rrrrrrrr...................",
|
||||
"^^^^^^^^^................rr............................................r.rrrr...................",
|
||||
"^^^^^^^^.................rr..........r....................................rrrr................rr",
|
||||
"^^^^^.rr............................^^^^^^...................r..............rr...............~~~",
|
||||
"^^^^^............................^^^^^^^^^^^................r~~~~~.........MMr...............~~~",
|
||||
"^^^^^...........................^^^^^^^^^^^^^...............~~~~~~.........MM....r..........r~~~",
|
||||
"^^^^^..r....r..................^^^^^^^^^^^^^^...............~~~~~~.r..........rrrrrr...r....r~~~"
|
||||
],
|
||||
"starts": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -402,9 +402,9 @@
|
|||
],
|
||||
"armorMul": {
|
||||
"infantry": 0.3,
|
||||
"light": 0.6,
|
||||
"medium": 1.0,
|
||||
"heavy": 1.4,
|
||||
"light": 0.35,
|
||||
"medium": 0.3,
|
||||
"heavy": 0.3,
|
||||
"structure": 1.5,
|
||||
"fortification": 1.6,
|
||||
"air": 2.6
|
||||
|
|
@ -418,6 +418,78 @@
|
|||
"sound": "sfx-ta-rocket-1",
|
||||
"impactSound": "sfx-ta-rocket-2"
|
||||
},
|
||||
{
|
||||
"id": "megatankgun",
|
||||
"name": "Twin 150mm Cannon",
|
||||
"kind": "ballistic",
|
||||
"damage": 145,
|
||||
"reload": 2.0,
|
||||
"burst": 1,
|
||||
"range": 380,
|
||||
"speed": 700,
|
||||
"spread": 0.015,
|
||||
"leadTarget": true,
|
||||
"aoe": 44,
|
||||
"aoeFalloff": 0.15,
|
||||
"targets": [
|
||||
"ground"
|
||||
],
|
||||
"barrels": 2,
|
||||
"barrelSpacing": 9,
|
||||
"armorMul": {
|
||||
"infantry": 1.3,
|
||||
"light": 1.15,
|
||||
"medium": 1.0,
|
||||
"heavy": 0.8,
|
||||
"structure": 1.2,
|
||||
"fortification": 1.1,
|
||||
"air": 1.0
|
||||
},
|
||||
"fx": {
|
||||
"style": "shell",
|
||||
"color": "#ffcf6a",
|
||||
"width": 4,
|
||||
"muzzle": 22
|
||||
},
|
||||
"sound": "sfx-battle-tank"
|
||||
},
|
||||
{
|
||||
"id": "megatankrockets",
|
||||
"name": "Side Rocket Pods",
|
||||
"kind": "guided",
|
||||
"damage": 55,
|
||||
"reload": 1.32,
|
||||
"burst": 1,
|
||||
"range": 400,
|
||||
"minRange": 90,
|
||||
"speed": 330,
|
||||
"turnRate": 2.1,
|
||||
"aoe": 42,
|
||||
"aoeFalloff": 0.15,
|
||||
"targets": [
|
||||
"ground",
|
||||
"air"
|
||||
],
|
||||
"barrels": 2,
|
||||
"barrelSpacing": 20,
|
||||
"armorMul": {
|
||||
"infantry": 0.3,
|
||||
"light": 0.6,
|
||||
"medium": 1.0,
|
||||
"heavy": 1.3,
|
||||
"structure": 1.4,
|
||||
"fortification": 1.5,
|
||||
"air": 2.4
|
||||
},
|
||||
"fx": {
|
||||
"style": "rocket",
|
||||
"color": "#ff5c3c",
|
||||
"width": 2,
|
||||
"trail": true
|
||||
},
|
||||
"sound": "sfx-ta-rocket-1",
|
||||
"impactSound": "sfx-ta-rocket-2"
|
||||
},
|
||||
{
|
||||
"id": "shoulderrocket",
|
||||
"name": "Shoulder Rocket",
|
||||
|
|
@ -878,6 +950,38 @@
|
|||
"spritePx": 56,
|
||||
"moveSound": "sfx-engine-heavy"
|
||||
},
|
||||
{
|
||||
"id": "megatank",
|
||||
"name": "Megatank",
|
||||
"role": "combat",
|
||||
"size": "medium",
|
||||
"radius": 33,
|
||||
"hp": 3200,
|
||||
"speed": 65,
|
||||
"turnRate": 1.6,
|
||||
"moveClass": "tread",
|
||||
"armorClass": "heavy",
|
||||
"sight": 320,
|
||||
"cost": {
|
||||
"energy": 3200,
|
||||
"mass": 1000
|
||||
},
|
||||
"buildTime": 80,
|
||||
"builtBy": [
|
||||
"advancedvehicleplant"
|
||||
],
|
||||
"weapons": [
|
||||
"megatankgun",
|
||||
"megatankrockets"
|
||||
],
|
||||
"sheetSlot": "unitSheet",
|
||||
"frame": 15,
|
||||
"turretFrame": 16,
|
||||
"procShape": "tank",
|
||||
"icon": 32,
|
||||
"spritePx": 66,
|
||||
"moveSound": "sfx-engine-heavy"
|
||||
},
|
||||
{
|
||||
"id": "constructor",
|
||||
"name": "Construction Vehicle",
|
||||
|
|
@ -1254,7 +1358,8 @@
|
|||
"builds": [
|
||||
"jeep",
|
||||
"tank",
|
||||
"rockettank"
|
||||
"rockettank",
|
||||
"megatank"
|
||||
],
|
||||
"spawnOffset": {
|
||||
"x": 0,
|
||||
|
|
@ -1451,7 +1556,7 @@
|
|||
"defaults": {
|
||||
"size": "medium",
|
||||
"symmetry": "mirror-x",
|
||||
"theme": "grasslands",
|
||||
"theme": "tropics",
|
||||
"aiSkill": 3,
|
||||
"playerArmy": "arm"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -302,16 +302,19 @@ function chooseBuilding(ctx, mine) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Static defence is a skill-4-and-up behaviour, like the Airfield is skill 3 and up.
|
||||
* Static defence is a skill-3-and-up behaviour, like the Airfield.
|
||||
*
|
||||
* These structures hit hard for their cost — a Laser Tower puts out 130 dps behind 1700 hp for
|
||||
* 60% of a Tank's price — and the ground roster has no dedicated siege answer to them yet, so
|
||||
* two equally-matched AIs both digging in grind rather than resolve. Reserving them for the
|
||||
* stronger opponents puts that pressure where a player goes looking for it and leaves the low
|
||||
* end of the ladder playing the open game it was tuned for. Drop this to 3 (or 1) once there is
|
||||
* a unit whose job is cracking fortifications.
|
||||
* two equally-matched AIs both digging in grind rather than resolve. Reserving them for skill 3
|
||||
* and up puts that pressure where a player goes looking for it once they're past the beginner
|
||||
* tier, and leaves skill 1-2 playing the open game they were tuned for: `urgentDefence` and
|
||||
* `steadyDefence` are still called for every skill, but their own `ctx.skill < DEFENCE_MIN_SKILL`
|
||||
* guard keeps returning null for skill 1-2 exactly as before, so lowering this constant alone
|
||||
* touches only skill 3 and up. Drop it further (to 1) once there is a unit whose job is cracking
|
||||
* fortifications.
|
||||
*/
|
||||
const DEFENCE_MIN_SKILL = 4;
|
||||
const DEFENCE_MIN_SKILL = 3;
|
||||
|
||||
/** Has anything hostile been inside the base perimeter recently? */
|
||||
function underThreat(ctx) {
|
||||
|
|
@ -325,9 +328,18 @@ function enemyAirSeen(ctx) {
|
|||
|
||||
/**
|
||||
* The one structure the base needs RIGHT NOW, ahead of any economic consideration. Kept
|
||||
* deliberately tiny — one tower against a raid, one launcher against aircraft. Everything
|
||||
* beyond the first of each is a steady-state decision (see steadyDefence), because an AI that
|
||||
* answers pressure by building walls stops building an army and loses slowly instead of fast.
|
||||
* deliberately tiny — one tower, one launcher against aircraft. Everything beyond the first of
|
||||
* each is a steady-state decision (see steadyDefence), because an AI that answers pressure by
|
||||
* building walls stops building an army and loses slowly instead of fast.
|
||||
*
|
||||
* The first Laser Tower is PROACTIVE, not a raid reaction: it goes up right after the opening
|
||||
* economy (2 energygen/1 massgen/1 barracks/3 energygen/2 massgen/1 vehicleplant), the moment
|
||||
* this function is first reachable, regardless of `underThreat`. A purely reactive first tower
|
||||
* — the previous behaviour — never exists until the base has already been hit once, which is no
|
||||
* help at all against a single decisive rush that goes straight for the Commander: the raid
|
||||
* that would have triggered it IS the loss. Everything past this first one stays reactive
|
||||
* (steadyDefence), which is what keeps two skill-3+ AIs from both digging in and turning a
|
||||
* mirror match into a stalemate — see the soak notes on that.
|
||||
*/
|
||||
function urgentDefence(ctx, mine) {
|
||||
const { rules } = ctx;
|
||||
|
|
@ -338,7 +350,7 @@ function urgentDefence(ctx, mine) {
|
|||
// Anti-air first: a Laser Tower cannot shoot at aircraft at all, so a base being bombed gets
|
||||
// nothing whatsoever from one.
|
||||
if (aa && enemyAirSeen(ctx) && n('missilelauncher') < 1) return aa;
|
||||
if (tower && underThreat(ctx) && n('lasertower') + n('missilelauncher') < 1) return tower;
|
||||
if (tower && n('lasertower') + n('missilelauncher') < 1) return tower;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -532,9 +544,11 @@ function applyCounters(ctx, weights) {
|
|||
const seen = infantryish + armour;
|
||||
if (seen) {
|
||||
const armourShare = armour / seen;
|
||||
// Tanks shred infantry; rockets and snipers answer armour and buildings.
|
||||
weights.tank *= 1 + (1 - armourShare) * 0.8;
|
||||
weights.rockettank *= 1 + armourShare * 1.0 + (structures > 2 ? 0.3 : 0);
|
||||
// The Rocket Tank's rocketpod is weak against vehicle armour (weak vs light/medium/heavy,
|
||||
// strong vs structure/fortification/air) — Tanks are now the answer to an armour-heavy
|
||||
// enemy, not Rocket Tanks. Rocket Tanks still lean into a base full of structures.
|
||||
weights.tank *= 1 + (1 - armourShare) * 0.8 + armourShare * 0.4;
|
||||
weights.rockettank *= 1 + (structures > 2 ? 0.5 : 0);
|
||||
weights.sniper *= 1 + (1 - armourShare) * 0.5;
|
||||
weights.rockettrooper *= 1 + armourShare * 0.6;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,140 @@
|
|||
// Total Annihilation — the full-screen studio intro that plays once, ahead of the main menu,
|
||||
// every time the scene starts fresh (see TotalAnnihilationGame.create — this scene is never
|
||||
// resumed in place, only entered, so "fresh" is every time).
|
||||
//
|
||||
// The clip carries its own audio track, so it plays unmuted — autoplay-with-sound is safe here
|
||||
// specifically because reaching this scene already required a user gesture (clicking the
|
||||
// game's icon in the arcade), which is what the browser's autoplay gate actually checks for.
|
||||
// The game's own soundtrack is paused for the duration so the two don't fight over the same
|
||||
// speakers, then resumed once the clip ends or is skipped.
|
||||
|
||||
import * as Phaser from 'phaser';
|
||||
import { GAME_HEIGHT, GAME_WIDTH } from '../../config.js';
|
||||
import { FONT } from './TAHud.js';
|
||||
|
||||
const INTRO_KEY = 'ta-mov-intro';
|
||||
const INTRO_PATH = 'assets/videos/ta/ta_intro.mp4';
|
||||
// Source resolution, used until the real texture decodes (a Video's own width/height report a
|
||||
// square placeholder before its first frame).
|
||||
const INTRO_SRC_W = 864;
|
||||
const INTRO_SRC_H = 480;
|
||||
|
||||
// How long "Press any key to skip" stays up after the first press before it quietly stands
|
||||
// down (rather than skipping on its own) and waits for the next one.
|
||||
const SKIP_HOLD_MS = 5000;
|
||||
|
||||
/**
|
||||
* Play the intro clip full-screen, then call `onDone`. The first key press or click surfaces a
|
||||
* skip prompt; a second one inside SKIP_HOLD_MS jumps straight to `onDone`. A load failure or
|
||||
* playback error also falls straight through to `onDone` — a missing intro is never allowed to
|
||||
* strand the player in front of a black screen.
|
||||
*/
|
||||
export function playIntroVideo(scene, onDone) {
|
||||
let done = false;
|
||||
let video = null;
|
||||
let skipArmed = false;
|
||||
let skipTimer = null;
|
||||
let skipText = null;
|
||||
|
||||
scene.music?.pause();
|
||||
let musicResumed = false;
|
||||
const resumeMusic = () => {
|
||||
if (musicResumed) return;
|
||||
musicResumed = true;
|
||||
scene.music?.resume();
|
||||
};
|
||||
|
||||
const root = scene.add.container(0, 0).setDepth(1000);
|
||||
root.add(scene.add.rectangle(0, 0, GAME_WIDTH, GAME_HEIGHT, 0x000000, 1).setOrigin(0, 0));
|
||||
|
||||
const clearPrompt = () => {
|
||||
skipTimer?.remove(false);
|
||||
skipTimer = null;
|
||||
skipText?.destroy();
|
||||
skipText = null;
|
||||
skipArmed = false;
|
||||
};
|
||||
|
||||
const cleanup = () => {
|
||||
scene.input.keyboard?.off('keydown', onInput);
|
||||
scene.input.off('pointerdown', onInput);
|
||||
clearPrompt();
|
||||
video?.destroy();
|
||||
root.destroy();
|
||||
};
|
||||
|
||||
const finish = () => {
|
||||
if (done) return;
|
||||
done = true;
|
||||
cleanup();
|
||||
resumeMusic();
|
||||
onDone();
|
||||
};
|
||||
|
||||
// Belt-and-braces: if the scene tears down mid-clip (e.g. a hot reload), drop our own
|
||||
// listeners and the video element without firing onDone a second time behind whatever else
|
||||
// shutdown is already doing.
|
||||
scene.events.once('shutdown', () => { if (!done) { done = true; cleanup(); } });
|
||||
|
||||
const armSkipPrompt = () => {
|
||||
skipArmed = true;
|
||||
skipText = scene.add.text(GAME_WIDTH / 2, GAME_HEIGHT - 96, 'Press any key to skip', {
|
||||
fontFamily: FONT, fontSize: '28px', color: '#e8f4ff',
|
||||
}).setOrigin(0.5).setAlpha(0);
|
||||
root.add(skipText);
|
||||
scene.tweens.add({ targets: skipText, alpha: 1, duration: 200 });
|
||||
skipTimer = scene.time.delayedCall(SKIP_HOLD_MS, clearPrompt);
|
||||
};
|
||||
|
||||
function onInput() {
|
||||
if (done) return;
|
||||
if (skipArmed) { finish(); return; }
|
||||
armSkipPrompt();
|
||||
}
|
||||
|
||||
scene.input.keyboard?.on('keydown', onInput);
|
||||
scene.input.on('pointerdown', onInput);
|
||||
|
||||
const startVideo = () => {
|
||||
video = scene.add.video(GAME_WIDTH / 2, GAME_HEIGHT / 2, INTRO_KEY);
|
||||
video.setLoop(false);
|
||||
video.setMute(false);
|
||||
video.setVolume(1);
|
||||
|
||||
// Cover, not contain: this is meant to fill the screen edge-to-edge, and the clip's own
|
||||
// aspect (864x480) is within a hair of the game's (1920x1080) anyway, so the crop is
|
||||
// imperceptible.
|
||||
const fit = () => {
|
||||
const real = !!video.videoTexture;
|
||||
const w = real ? video.width : INTRO_SRC_W;
|
||||
const h = real ? video.height : INTRO_SRC_H;
|
||||
video.setScale(Math.max(GAME_WIDTH / w, GAME_HEIGHT / h));
|
||||
};
|
||||
fit();
|
||||
video.on('created', fit);
|
||||
video.on('playing', fit);
|
||||
|
||||
video.once('complete', finish);
|
||||
video.once('error', finish);
|
||||
// A browser that refuses to autoplay sound fires 'locked' and keeps retrying muted from
|
||||
// preUpdate.
|
||||
video.once('locked', () => { if (video?.scene) video.setMute(true); });
|
||||
|
||||
video.play(false);
|
||||
root.add(video);
|
||||
};
|
||||
|
||||
// Deliberately NOT in the asset manifest / preloaded ahead of time — this clip is loaded
|
||||
// on demand, right here, the moment the game itself starts.
|
||||
if (scene.cache.video?.exists(INTRO_KEY)) {
|
||||
startVideo();
|
||||
return;
|
||||
}
|
||||
|
||||
scene.load.video(INTRO_KEY, INTRO_PATH, false);
|
||||
scene.load.once(`filecomplete-video-${INTRO_KEY}`, () => { if (!done) startVideo(); });
|
||||
scene.load.once(Phaser.Loader.Events.FILE_LOAD_ERROR, (file) => {
|
||||
if (file?.key === INTRO_KEY) finish();
|
||||
});
|
||||
if (!scene.load.isLoading()) scene.load.start();
|
||||
}
|
||||
|
|
@ -1644,8 +1644,15 @@ function acquireTarget(state, rules, e, def, hash, near) {
|
|||
function fireWeapon(state, rules, e, w, target, facing, aimPt) {
|
||||
const aim = aimPt ?? aimPointOn(rules, e, target);
|
||||
const muzzle = (w.fx?.muzzle ?? e.radius);
|
||||
const ox = e.x + Math.cos(facing) * muzzle;
|
||||
const oy = e.y + Math.sin(facing) * muzzle;
|
||||
const barrels = w.barrels ?? 1;
|
||||
// Perpendicular to the firing line, so twin-barrel weapons (the Megatank's cannon and its
|
||||
// side-mounted rockets) spawn each shot from its own barrel tip instead of the hull centre.
|
||||
const perpX = -Math.sin(facing), perpY = Math.cos(facing);
|
||||
|
||||
for (let bi = 0; bi < barrels; bi++) {
|
||||
const lateral = barrels > 1 ? (bi - (barrels - 1) / 2) * (w.barrelSpacing / (barrels - 1)) : 0;
|
||||
const ox = e.x + Math.cos(facing) * muzzle + perpX * lateral;
|
||||
const oy = e.y + Math.sin(facing) * muzzle + perpY * lateral;
|
||||
|
||||
state.events.push({
|
||||
t: 'weaponFired', id: e.id, army: e.army, weapon: w.id,
|
||||
|
|
@ -1672,7 +1679,7 @@ function fireWeapon(state, rules, e, w, target, facing, aimPt) {
|
|||
if (w.aoe) applyAoe(state, rules, aim.x, aim.y, w, e);
|
||||
state.events.push({ t: 'impact', x: ex, y: ey, radius: w.aoe ?? 8, style: w.fx.style, sound: w.impactSound });
|
||||
}
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Travelling ordnance: leading matters, and a strafing target can genuinely be missed.
|
||||
|
|
@ -1686,7 +1693,7 @@ function fireWeapon(state, rules, e, w, target, facing, aimPt) {
|
|||
let ang = Math.atan2(aimY - oy, aimX - ox);
|
||||
if (w.spread > 0) ang += rngRange(state, -w.spread, w.spread);
|
||||
|
||||
if (state.projectiles.length >= rules.constants.projectileCap) return;
|
||||
if (state.projectiles.length >= rules.constants.projectileCap) break;
|
||||
state.projectiles.push({
|
||||
id: state.nextProjectileId++,
|
||||
weapon: w.id, army: e.army, ownerId: e.id,
|
||||
|
|
@ -1697,6 +1704,7 @@ function fireWeapon(state, rules, e, w, target, facing, aimPt) {
|
|||
ttl: Math.ceil(((w.range * 1.4) / w.speed) * rules.constants.tickHz),
|
||||
trail: [],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function stepProjectiles(state, rules) {
|
||||
|
|
|
|||
|
|
@ -195,6 +195,12 @@ export function compileRules(json) {
|
|||
// The D-Gun is the reason this flag exists — left on auto-fire, a defending Commander
|
||||
// deletes one attacker every reload for free, which makes assaulting any base suicide.
|
||||
w.manual = w.manual === true;
|
||||
// Multi-barrel weapons (the Megatank's twin cannon and side rockets) fire every barrel
|
||||
// simultaneously on one reload, each barrel's shot spawned `barrelSpacing` px apart,
|
||||
// perpendicular to the firing line, split evenly either side of the hull centreline.
|
||||
w.barrels = w.barrels ?? 1;
|
||||
if (!(Number.isInteger(w.barrels) && w.barrels >= 1)) fail(`weapon "${w.id}" barrels must be a positive integer`);
|
||||
if (w.barrels > 1 && !(w.barrelSpacing > 0)) fail(`weapon "${w.id}" has barrels > 1 but no positive barrelSpacing`);
|
||||
}
|
||||
const weaponById = indexById(weapons);
|
||||
|
||||
|
|
|
|||
|
|
@ -140,11 +140,12 @@ export function skirmishSetup(scene, { onBack, onStart }) {
|
|||
const skills = [1, 2, 3, 4, 5].map((n) => ({ label: `SKILL ${n}`, value: n }));
|
||||
const victories = (rules.victoryModes ?? []).map((v) => ({ label: v.label, value: v.id, desc: v.desc }));
|
||||
const victoryStart = Math.max(0, victories.findIndex((v) => v.value === rules.constants.victoryDefault));
|
||||
const themeStart = Math.max(0, themes.findIndex((t) => t.value === sk.defaults?.theme));
|
||||
|
||||
const cfg = {
|
||||
seed: (Math.random() * 0xffffffff) >>> 0,
|
||||
size: sizes[0].value,
|
||||
theme: themes[0]?.value ?? 'grasslands',
|
||||
theme: themes[themeStart]?.value ?? 'grasslands',
|
||||
symmetry: syms[0].value,
|
||||
victory: victories[victoryStart]?.value ?? rules.constants.victoryDefault,
|
||||
armies: [
|
||||
|
|
@ -155,7 +156,7 @@ export function skirmishSetup(scene, { onBack, onStart }) {
|
|||
|
||||
const left = 300, right = GAME_WIDTH - 700;
|
||||
cycler(scene, objs, left, 300, 'MAP SIZE', sizes, 0, (v) => { cfg.size = v; });
|
||||
cycler(scene, objs, left, 400, 'THEME', themes, 0, (v) => { cfg.theme = v; });
|
||||
cycler(scene, objs, left, 400, 'THEME', themes, themeStart, (v) => { cfg.theme = v; });
|
||||
cycler(scene, objs, left, 500, 'SYMMETRY', syms, 0, (v) => { cfg.symmetry = v; });
|
||||
cycler(scene, objs, left, 600, 'OPPONENT SKILL', skills, 2, (v) => { cfg.armies[1].skill = v; });
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import TAWorldView, { DEPTHS } from './TAWorldView.js';
|
|||
import TAFx from './TAFx.js';
|
||||
import TAHud from './TAHud.js';
|
||||
import * as Screens from './TAScreens.js';
|
||||
import { playIntroVideo } from './TAIntroVideo.js';
|
||||
|
||||
const SAVE_KEY = 'totalannihilation-save';
|
||||
const SETTINGS_KEY = 'totalannihilation-settings';
|
||||
|
|
@ -93,7 +94,7 @@ export default class TotalAnnihilationGame extends Phaser.Scene {
|
|||
.catch(() => { /* portraits are optional */ });
|
||||
|
||||
this.events.once('shutdown', () => this._teardown());
|
||||
this.showMenu();
|
||||
playIntroVideo(this, () => this.showMenu());
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -66,6 +66,8 @@ let the scale do the work.
|
|||
| 12 | Fighter | plan-view airframe, swept wings, no tracks or wheels | 46 |
|
||||
| 13 | Bomber | plan-view airframe, long straight wing, wing-mounted engines | 60 |
|
||||
| 14 | Hover Constructor | skirted hull over a plenum, nanolathe crane, no tracks | 52 |
|
||||
| 15 | Megatank | hull + tracks, wider than the Tank | 66 |
|
||||
| 16 | Megatank turret | twin cannon barrels + side rocket pods | 66 |
|
||||
|
||||
### Units that leave the ground
|
||||
|
||||
|
|
@ -115,7 +117,8 @@ The Hover Constructor uses the same machinery at a much lower height — it shou
|
|||
independently, so the unit aims while it drives. Rules:
|
||||
|
||||
- The turret's **pivot is the centre of the cell** — draw the turret so its rotation point
|
||||
sits at (32, 32), with the barrel extending to the **right**.
|
||||
sits at the cell centre (64, 64 for the current 128×128 unit cells), with the barrel
|
||||
extending to the **right**.
|
||||
- Leave the rest of the turret cell transparent. The hull shows through it.
|
||||
- A unit with no turret (infantry, sniper, rocket trooper, construction vehicle, and all three
|
||||
Airfield units) simply has no turret frame; its whole sprite rotates to face its target. The
|
||||
|
|
@ -123,9 +126,15 @@ independently, so the unit aims while it drives. Rules:
|
|||
they just rotate to face wherever they're moving. Aircraft have fixed forward guns, so they
|
||||
aim by pointing the whole airframe, which is why they have no turret either.
|
||||
|
||||
Frames 15–63 are free. Add a unit by appending a definition to `units[]` in
|
||||
Frames 17–63 are free. Add a unit by appending a definition to `units[]` in
|
||||
`data/totalannihilation-rules.json` with its `frame` (and optional `turretFrame`) — no code.
|
||||
|
||||
A weapon may declare `barrels` (default 1) and, when `barrels > 1`, a `barrelSpacing` in world
|
||||
px: every barrel fires at once on the same reload, each shot spawned that many px apart,
|
||||
perpendicular to the firing line and centred on the hull. This is how the Megatank's twin
|
||||
cannon and side rocket pods line up with the two barrels/pods painted into its turret frame —
|
||||
measure the offset between them in the source PNG and scale by `spritePx / frameWidth`.
|
||||
|
||||
---
|
||||
|
||||
## Structure sheets (128×128 cells, 6 per row)
|
||||
|
|
|
|||
|
|
@ -72,11 +72,14 @@ const MISSIONS = [
|
|||
defeat: 'KLAXON out-produced us and it showed.',
|
||||
},
|
||||
{
|
||||
// Re-seeded twice as combat balance moved under it, both times measured over an 8-run
|
||||
// sweep: 55930 -> 40411 when armed aircraft stopped being able to hover, then 40411 (which
|
||||
// fell to 4/8) -> 71644 when the AI learned to build static defences. Cy-Bro is skill 4
|
||||
// here, which is exactly the level at which defences switch on.
|
||||
id: 'm05', name: 'Tropic Vice', seed: 71644, size: 'medium', theme: 'tropics', symmetry: 'mirror-x',
|
||||
// Re-seeded three times as combat balance moved under it, each time measured over an
|
||||
// 8-run sweep: 55930 -> 40411 when armed aircraft stopped being able to hover, then 40411
|
||||
// (which fell to 4/8) -> 71644 when the AI learned to build static defences, then 71644
|
||||
// (which fell to 6/8, and lost both of verify §13's own fixed sample runs — seed and
|
||||
// seed+101 — even though the full 8-run rate was technically still at the bar) -> 67890
|
||||
// (8/8) when rocketpod's armorMul was rebalanced weak-vs-vehicle/unchanged-vs-structure.
|
||||
// Cy-Bro is skill 4 here, which is exactly the level at which defences switch on.
|
||||
id: 'm05', name: 'Tropic Vice', seed: 67890, size: 'medium', theme: 'tropics', symmetry: 'mirror-x',
|
||||
enemy: { commander: 'cybro', skill: 4, aggression: 0.7 },
|
||||
startResources: [{ mass: 2600, energy: 4200 }, { mass: 1500, energy: 2600 }],
|
||||
prebuilt: [
|
||||
|
|
@ -84,12 +87,17 @@ const MISSIONS = [
|
|||
{ id: 'barracks', dx: 4, dy: 3 },
|
||||
{ enemy: true, id: 'energygen', dx: 3, dy: 2 },
|
||||
],
|
||||
briefing: 'Cy-Bro starts ahead and pushes early. Rocket tanks out-range everything CORE fields.',
|
||||
briefing: 'Cy-Bro starts ahead and pushes early. Rockets crack their base open — armour holds the line getting there.',
|
||||
victory: 'Cy-Bro is scrap on the sand.',
|
||||
defeat: 'The push came faster than the plant did.',
|
||||
},
|
||||
{
|
||||
id: 'm06', name: 'Annihilation', seed: 63541, size: 'medium', theme: 'snowfields', symmetry: 'rotational',
|
||||
// Re-seeded once, 8-run sweep: 63541 (fell to 0/8) -> 80808 (8/8) when static defence
|
||||
// became a skill-3+ behaviour with a PROACTIVE first tower (TAAI.urgentDefence no longer
|
||||
// waits for a raid to build the first one). KLAXON here is skill 5, well past that gate,
|
||||
// so it now stands up a tower before the player-bot's rush can land — 90123 and 56789 also
|
||||
// scored 8/8 in the same sweep if this needs revisiting again.
|
||||
id: 'm06', name: 'Annihilation', seed: 80808, size: 'medium', theme: 'snowfields', symmetry: 'rotational',
|
||||
enemy: { commander: 'klaxon', skill: 5, aggression: 0.85 },
|
||||
startResources: [{ mass: 3200, energy: 5200 }, { mass: 1800, energy: 3000 }],
|
||||
prebuilt: [
|
||||
|
|
@ -97,7 +105,7 @@ const MISSIONS = [
|
|||
{ id: 'barracks', dx: 4, dy: 3 }, { id: 'vehicleplant', dx: -4, dy: 3 },
|
||||
{ enemy: true, id: 'energygen', dx: 3, dy: -3 }, { enemy: true, id: 'barracks', dx: 4, dy: 3 },
|
||||
],
|
||||
briefing: 'KLAXON at full strength with a base already standing. Nothing clever left — out-build it and end it.',
|
||||
briefing: 'KLAXON at full strength with a base already standing, dug in behind its own defences. Nothing clever left — out-build it and end it.',
|
||||
victory: 'Total annihilation. There is nothing left to fight.',
|
||||
defeat: 'KLAXON was simply better prepared.',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1078,11 +1078,13 @@ section('6. Combat');
|
|||
const rvs = equal('rockettank', 'sniper');
|
||||
check('rocket tanks beat equal-cost snipers', rvs.fracA > rvs.fracB,
|
||||
`${rvs.a} (${(rvs.fracA * 100) | 0}%) v ${rvs.b} (${(rvs.fracB * 100) | 0}%)`);
|
||||
// Rockets out-range and out-damage armour; that is what makes the roster a triangle
|
||||
// rather than a ladder where one unit is simply the answer.
|
||||
// Rockets are the answer to buildings and air, not to armour — a straight fight against a
|
||||
// Tank is one the Rocket Tank should lose, which is what makes the roster a triangle
|
||||
// (Tank counters Rocket Tank, Rocket Tank counters Sniper/structures) rather than a ladder
|
||||
// where one unit is simply the answer.
|
||||
const rvt = equal('rockettank', 'tank');
|
||||
check('rocket tanks beat equal-cost tanks', rvt.fracA > rvt.fracB,
|
||||
`${rvt.a} (${(rvt.fracA * 100) | 0}%) v ${rvt.b} (${(rvt.fracB * 100) | 0}%)`);
|
||||
check('tanks beat equal-cost rocket tanks', rvt.fracB > rvt.fracA,
|
||||
`${rvt.b} tanks (${(rvt.fracB * 100) | 0}%) v ${rvt.a} rocket tanks (${(rvt.fracA * 100) | 0}%)`);
|
||||
|
||||
// Engagements must take long enough for reinforcement and composition to matter. When
|
||||
// fights resolved in 2-4 seconds the whole AI skill ladder collapsed to a coin flip.
|
||||
|
|
@ -1098,7 +1100,11 @@ section('6. Combat');
|
|||
check('rifle is strong vs infantry, weak vs medium',
|
||||
armorMul(rifle, 'infantry') > armorMul(rifle, 'medium') * 3);
|
||||
const rocket = combatRules.weaponById.rocketpod;
|
||||
check('rockets favour armour over infantry', armorMul(rocket, 'heavy') > armorMul(rocket, 'infantry') * 3);
|
||||
check('rockets favour fortifications over vehicle armour',
|
||||
armorMul(rocket, 'fortification') > armorMul(rocket, 'heavy') * 3);
|
||||
check('rockets are weak against vehicle armour',
|
||||
armorMul(rocket, 'light') < 1 && armorMul(rocket, 'medium') < 1 && armorMul(rocket, 'heavy') < 1,
|
||||
`light ${armorMul(rocket, 'light')}, medium ${armorMul(rocket, 'medium')}, heavy ${armorMul(rocket, 'heavy')}`);
|
||||
|
||||
// Commander death explosion.
|
||||
const dth = combatRules.unitById.commander.deathExplosion;
|
||||
|
|
|
|||
Loading…
Reference in New Issue