From 5a263e838490eb2744245972a28e6c0d73274a62 Mon Sep 17 00:00:00 2001 From: CptMacTavish2224 <95313759+CptMacTavish2224@users.noreply.github.com> Date: Sat, 4 Jul 2026 16:50:37 +0300 Subject: [PATCH 1/6] feat: Squads, comps, LW --- ChapterMaster.yyp | 2 + datafiles/data/mobility.json | 51 +- datafiles/images/ui/formation18.png | Bin 0 -> 108634 bytes datafiles/main/chapters/template.JSON | 1782 ++++++++++++++--- datafiles/main/squads/base_squads.json | 196 +- .../main/squads/company_squad_builds.json | 199 +- datafiles/main/squads/equal_scouts.json | 204 +- datafiles/main/squads/equal_specialists.json | 226 +-- datafiles/main/squads/equal_spescout.json | 264 +-- datafiles/main/squads/lightning_warriors.json | 229 +++ objects/obj_controller/Create_0.gml | 2 + objects/obj_creation/Create_0.gml | 3 +- objects/obj_popup/Create_0.gml | 32 +- scripts/is_specialist/is_specialist.gml | 2 + scripts/macros/macros.gml | 2 + scripts/scr_UnitGroup/scr_UnitGroup.gml | 189 +- scripts/scr_chapter_new/scr_chapter_new.gml | 2 + .../scr_company_order/scr_company_order.gml | 88 +- scripts/scr_creation/scr_creation.gml | 2 +- .../scr_initialize_custom.gml | 173 +- scripts/scr_management/scr_management.gml | 44 +- .../scr_marine_struct/scr_marine_struct.gml | 41 +- .../scr_popup_functions.gml | 2 +- scripts/scr_promote/scr_promote.gml | 10 + scripts/scr_roster/scr_roster.gml | 21 + scripts/scr_squads/scr_squads.gml | 347 +++- .../scr_ui_formation_bars.gml | 4 +- scripts/scr_ui_settings/scr_ui_settings.gml | 2 + 28 files changed, 2732 insertions(+), 1387 deletions(-) create mode 100644 datafiles/images/ui/formation18.png create mode 100644 datafiles/main/squads/lightning_warriors.json diff --git a/ChapterMaster.yyp b/ChapterMaster.yyp index df4dcf6035..d94c38ee1a 100644 --- a/ChapterMaster.yyp +++ b/ChapterMaster.yyp @@ -451,6 +451,7 @@ {"$GMIncludedFile":"","%Name":"formation15.png","CopyToMask":-1,"filePath":"datafiles/images/ui","name":"formation15.png","resourceType":"GMIncludedFile","resourceVersion":"2.0",}, {"$GMIncludedFile":"","%Name":"formation16.png","CopyToMask":-1,"filePath":"datafiles/images/ui","name":"formation16.png","resourceType":"GMIncludedFile","resourceVersion":"2.0",}, {"$GMIncludedFile":"","%Name":"formation17.png","CopyToMask":-1,"filePath":"datafiles/images/ui","name":"formation17.png","resourceType":"GMIncludedFile","resourceVersion":"2.0",}, + {"$GMIncludedFile":"","%Name":"formation18.png","CopyToMask":-1,"filePath":"datafiles/images/ui","name":"formation18.png","resourceType":"GMIncludedFile","resourceVersion":"2.0",}, {"$GMIncludedFile":"","%Name":"formation2.png","CopyToMask":-1,"filePath":"datafiles/images/ui","name":"formation2.png","resourceType":"GMIncludedFile","resourceVersion":"2.0",}, {"$GMIncludedFile":"","%Name":"formation3.png","CopyToMask":-1,"filePath":"datafiles/images/ui","name":"formation3.png","resourceType":"GMIncludedFile","resourceVersion":"2.0",}, {"$GMIncludedFile":"","%Name":"formation4.png","CopyToMask":-1,"filePath":"datafiles/images/ui","name":"formation4.png","resourceType":"GMIncludedFile","resourceVersion":"2.0",}, @@ -567,6 +568,7 @@ {"$GMIncludedFile":"","%Name":"equal_scouts.json","CopyToMask":-1,"filePath":"datafiles/main/squads","name":"equal_scouts.json","resourceType":"GMIncludedFile","resourceVersion":"2.0",}, {"$GMIncludedFile":"","%Name":"equal_specialists.json","CopyToMask":-1,"filePath":"datafiles/main/squads","name":"equal_specialists.json","resourceType":"GMIncludedFile","resourceVersion":"2.0",}, {"$GMIncludedFile":"","%Name":"equal_spescout.json","CopyToMask":-1,"filePath":"datafiles/main/squads","name":"equal_spescout.json","resourceType":"GMIncludedFile","resourceVersion":"2.0",}, + {"$GMIncludedFile":"","%Name":"lightning_warriors.json","CopyToMask":-1,"filePath":"datafiles/main/squads","name":"lightning_warriors.json","resourceType":"GMIncludedFile","resourceVersion":"2.0",}, {"$GMIncludedFile":"","%Name":"version.json","CopyToMask":-1,"filePath":"datafiles/main","name":"version.json","resourceType":"GMIncludedFile","resourceVersion":"2.0",}, {"$GMIncludedFile":"","%Name":"data.json","CopyToMask":-1,"filePath":"datafiles/main/visual_sets/Company_marks_roman_right_knee","name":"data.json","resourceType":"GMIncludedFile","resourceVersion":"2.0",}, {"$GMIncludedFile":"","%Name":"12.png","CopyToMask":-1,"filePath":"datafiles/main/visual_sets/Company_marks_roman_right_knee/one","name":"12.png","resourceType":"GMIncludedFile","resourceVersion":"2.0",}, diff --git a/datafiles/data/mobility.json b/datafiles/data/mobility.json index 2bfe3862cc..4b6f2b5887 100644 --- a/datafiles/data/mobility.json +++ b/datafiles/data/mobility.json @@ -2,22 +2,65 @@ "Bike": { "abbreviation": "Bike", "damage_resistance_mod": { - "artifact": 10, - "master_crafted": 10, - "standard": 5 + "artifact": 40, + "master_crafted": 30, + "standard": 20 }, "description": "A robust bike that can propel an Astartes at very high speeds. Boasts highly responsive controls that allow for fluid movement on the battlefield and respectable Twin-Linked Bolters for offensive action.", "hp_mod": { "artifact": 35, - "master_crafted": 25, + "master_crafted": 30, "standard": 25 }, + "ranged_hands": -0.5, + "melee_mod":{ + "artifact": 30, + "master_crafted": 25, + "standard": 20 + }, + "special_properties":[ + "Speed Force" + ], + "tags":[ + "bike" + ], "second_profiles": [ "Twin Linked Bolters" ], "value": 35, "requires_to_forge": ["combi_1"] }, + "Attack Bike": { + "abbreviation": "At Bike", + "damage_resistance_mod": { + "artifact": 40, + "master_crafted": 30, + "standard": 25 + }, + "description": "A robust bike that can propel an Astartes at very high speeds. Boasts highly responsive controls that allow for fluid movement on the battlefield and respectable Twin-Linked Bolters for offensive action. Sports an additional sidecar with a heavy weapon of choice.", + "hp_mod": { + "artifact": 150, + "master_crafted": 120, + "standard": 100 + }, + "ranged_hands": 1, + "melee_mod":{ + "artifact": 20, + "master_crafted": 15, + "standard": 10 + }, + "special_properties": [ + "Speed Force (Ranged)" + ], + "second_profiles": [ + "Twin Linked Bolters" + ], + "tags":[ + "bike", "sf_ranged" + ], + "value": 95, + "requires_to_forge": ["combi_1"] + }, "Conversion Beamer Pack": { "abbreviation": "CnvBmr", "buyable": false, diff --git a/datafiles/images/ui/formation18.png b/datafiles/images/ui/formation18.png new file mode 100644 index 0000000000000000000000000000000000000000..d1a2d2d1f874087f7473bf098c7123d9dc816554 GIT binary patch literal 108634 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 u@g%5jd0pS0q4&@@bmROOIs9K;b=3nWD "Deathwing Terminator" - ** - loadout: Struct containing Required and Optional weaponry this unit can equip - a required loadout always follows this syntax :[,] - so "wep1":["Bolter",4], will mean four marines are always equipped with 4 bolters in the wep1 slot - * option loadouts follow the following syntax :[[],] - for example [["Flamer", "Meltagun"],1], means the role can have a max of one flamer or meltagun - [["Plasma Pistol","Bolt Pistol"], 4] means the role can have a mix of 4 plasma pistols and bolt pistols on top - of all required loadout options - - wep1: right hand weapon - - wep2: left hand weapon - - mobi: Mobility item, e.g. Jump Packs. - - armour: required armour - - gear: special equipment needed for certain roles, like a Roasrius or Narthecium - * - type_data: names the squad, allows certain formations - */ - "squad_name": "Squad", - "custom_squads": {} + [ + "type_data", + { + "display_data": "Deathwing Terminator Squad", + "formation_options": + [ + "terminator", + "veteran", + "assault", + "devastator", + "scout", + "tactical" + ], + "allowed_companies": [1] //this is specifically for when squads are supposed to spawn only in specific companies. Ignore for chapter-wide changes + } + ] + ]*/ } +/* * Custom squad roles, loadouts and formations + * When companies are made, squads are formed based on these rules: + * - squad name: one of captain, terminator, terminator_assault, sternguard_veteran, + vanguard_veteran, devastator, tactical, assault, scout, scout_sniper + * - squad array layout [Role, Role, ...Role, type_data] + * - each element of the array is a default Role, and their settings. + - if you changed the role using `custom_roles` you need to reference the role with this new name + - for non-leader roles it is better to change the name of the role in the squad layout instead + * - unit layout [Role Name, Settings Struct] + * - settings struct: + * - max: The most amount of this unit is allowed per squad + * - min: The squad can't be formed unless at least 1 of this unit is in it + * - role: The name of the unit when it is a member of the squad. This is where you rename roles e.g. + "Terminator" > "Deathwing Terminator" + ** - loadout: Struct containing Required and Optional weaponry this unit can equip + a required loadout always follows this syntax :[,] + so "wep1":["Bolter",4], will mean four marines are always equipped with 4 bolters in the wep1 slot + * option loadouts follow the following syntax :[[],] + for example [["Flamer", "Meltagun"],1], means the role can have a max of one flamer or meltagun + [["Plasma Pistol","Bolt Pistol"], 4] means the role can have a mix of 4 plasma pistols and bolt pistols on top + of all required loadout options + - wep1: right hand weapon + - wep2: left hand weapon + - mobi: Mobility item, e.g. Jump Packs. + - armour: required armour + - gear: special equipment needed for certain roles, like a Roasrius or Narthecium + * - type_data: names the squad, allows certain formations ? idk what that does yet*/ + } } \ No newline at end of file diff --git a/datafiles/main/squads/base_squads.json b/datafiles/main/squads/base_squads.json index 7163ec86e5..a8c6442dee 100644 --- a/datafiles/main/squads/base_squads.json +++ b/datafiles/main/squads/base_squads.json @@ -7,27 +7,32 @@ "Champion": { "max": 1, "min": 0, - "role": "Company Champion" + "role": "Company Champion", + "alternative_roles": ["Champion"] }, "Apothecary": { "max": 1, "min": 0, - "role": "Company Apothecary" + "role": "Company Apothecary", + "alternative_roles": ["Apothecary"] }, "Chaplain": { "max": 1, "min": 0, - "role": "Company Chaplain" + "role": "Company Chaplain", + "alternative_roles": ["Chaplain"] }, "Ancient": { "max": 1, "min": 1, - "role": "Company Ancient" + "role": "Company Ancient", + "alternative_roles": ["Ancient"] }, "Veteran": { "max": 5, "min": 0, "role": "Company Veteran", + "alternative_roles": ["Veteran"], "loadout": { "required": { "wep1": ["", 0], @@ -43,12 +48,14 @@ "Techmarine": { "max": 2, "min": 0, - "role": "Company Techmarine" + "role": "Company Techmarine", + "alternative_roles": ["Techmarine"] }, "Librarian": { "max": 1, "min": 0, - "role": "Company Librarian" + "role": "Company Librarian", + "alternative_roles": ["Librarian"] }, "type_data": { "display_data": "Command {squad_name}", @@ -86,7 +93,7 @@ } }, "Terminator": { - "max": 4, + "max": 9, "min": 2, "loadout": { "required": { @@ -95,13 +102,20 @@ }, "option": { "wep1": [ - [["Power Fist", "Chainfist"], 4] - ], - "wep2": [ - ["{WEAPON_LIST_RANGED_COMBI}", 3], - ["{WEAPON_LIST_RANGED_HEAVY_TERMINATOR}", 1] + [["Power Fist", "Chainfist"], 7, {"wep2": "Storm Bolter"}] //if option group 3rd element is struct random pick ignores it ] - } + }, + "random_pick": [ + { + "wep1": ["Power Fist", "Chainfist"], + "wep2": "Storm Bolter", + "mobi": "Cyclone Missile System" + }, + { + "wep1": ["Power Fist", "Chainfist"], + "wep2": ["Heavy Flamer", "Assault Cannon"] + } + ] } }, "type_data": { @@ -131,19 +145,24 @@ } }, "Terminator": { - "max": 4, + "max": 9, "min": 2, "role": "Assault Terminator", "loadout": { "required": { - "wep1": ["Thunder Hammer", 1], - "wep2": ["Storm Shield", 1] + "wep1": ["", 0], + "wep2": ["", 0] }, - "option": { - "wep1": [ - [["Lightning Claw"], 3, { "wep2": "Lightning Claw" }] - ] - } + "random_pick": [ + { + "wep1": ["Thunder Hammer"], + "wep2": ["Storm Shield"] + }, + { + "wep1": ["Lightning Claw"], + "wep2": ["Lightning Claw"] + } + ] } }, "type_data": { @@ -210,14 +229,14 @@ }, "devastator_squad": { - "Devastator": { + "Devastator Marine": { "max": 9, "min": 4, + "role": "Devastator", "loadout": { "required": { "wep1": ["Bolter", 5], - "wep2": ["Combat Knife", 9], - "mobi": ["", 5] + "wep2": ["Combat Knife", 9] }, "option": { "wep1": [ @@ -255,9 +274,10 @@ }, "tactical_squad": { - "Tactical": { + "Tactical Marine": { "max": 9, "min": 4, + "role": "Tactical", "loadout": { "required": { "wep1": ["wep1[8]", 7], @@ -304,9 +324,10 @@ }, "assault_squad": { - "Assault": { + "Assault Marine": { "max": 9, "min": 4, + "role": "Assault", "loadout": { "required": { "wep1": ["wep1[10]", 5], @@ -358,6 +379,7 @@ "Scout": { "max": 9, "min": 4, + "role": "Scout", "loadout": { "required": { "wep1": ["", 0], @@ -390,6 +412,7 @@ "type_data": { "display_data": "Scout {squad_name}", "class": ["scout"], + "base": "scout", "formation_options": [ "scout", "tactical", @@ -398,39 +421,9 @@ ] } }, - "bike_squad": { - "Assault": { - "max": 9, - "min": 4, - "role": "Biker", - "loadout": { - "required": { - "wep1": ["", "max"], - "wep2": ["Chainsword", "max"], - "mobi": ["Bike", "max"] - } - } - }, - "Sergeant": { - "max": 1, - "min": 1, - "role": "Biker Sergeant", - "loadout": { - "required": { - "wep1": ["", "max"], - "wep2": ["Chainsword", "max"], - "mobi": ["Bike", 1] - } - } - }, - "type_data": { - "display_data": "Bike {squad_name}", - "class": ["bike"], - "formation_options": ["assault", "tactical"] - } - }, + "breacher_squad": { - "Tactical": { + "Tactical Marine": { "max": 9, "min": 4, "role": "Breacher", @@ -471,5 +464,90 @@ "display_data": "Breacher {squad_name}", "formation_options": ["tactical", "assault", "devastator", "scout"] } - } + }, + + "bike_squad": { + "Tactical": { + "max": 7, + "min": 1, + "role": "Biker", + "alternative_roles": ["Assault","Devastator","Tactical"], + "loadout": { + "required": { + "armour": ["", 0], + "wep1": ["", 0], + "wep2": ["", 0], + "mobi": ["Bike", 7] + }, + "option": { + "wep1": [[["Chainsword","Chainaxe"],7,{"wep2":"Bolt Pistol"}]] + } + } + }, + "Sergeant": { + "max": 1, + "min": 1, + "role": "Biker Sergeant", + "loadout": { + "required": { + "wep1": ["", 0], + "wep2": ["", 0], + "mobi": ["Bike", 1] + }, + "option": { + "wep1": [[["Power Sword", "Power Spear", "Power Axe", "Power Fist", "Chainaxe", "Chainsword"],1]], + "wep2": [[["Volkite Serpenta", "Plasma Pistol", "Bolt Pistol", "Phobos Bolt Pistol", "Grav-Pistol", "Hand Flamer", "Infernus Pistol", "Ryza Plasma Pistol"],1]] + } + } + }, + "type_data": { + "display_data": "Bike {squad_name}", + "class": ["bike"], + "formation_options": ["biker","assault", "tactical","devastator","scout"], + "base": "biker" + } + }, + + + "attack_bike_squad": { + "Tactical": { + "max": 2, + "min": 1, + "role": "Attack Biker", + "alternative_roles": ["Devastator", "Assault", "Tactical"], + "loadout": { + "required": { + "wep1": ["", 0], + "wep2": ["", 0], + "mobi": ["Attack Bike", "max"] + }, + "option": { + "wep1": [[["Multi-Melta", "Heavy Bolter"], 2]], + "wep2": [[["Chainsword", "Chainaxe", "Combat Knife"],2]] + } + } + }, + "Sergeant": { + "max": 1, + "min": 1, + "role": "Attack Bike Sergeant", + "loadout": { + "required": { + "wep1": ["", 0], + "wep2": ["", 0], + "mobi": ["Attack Bike", 1] + }, + "option": { + "wep1": [[["Multi-Melta", "Plasma Cannon", "Lascannon"],1]], + "wep2": [[["Chainsword", "Chainaxe", "Power Sword", "Power Spear", "Power Axe"],1]] + } + } + }, + "type_data": { + "display_data": "Attack Bike {squad_name}", + "class": ["bike"], + "formation_options": ["biker","assault", "tactical", "devastator", "scout"], + "base": "biker" + } +} } \ No newline at end of file diff --git a/datafiles/main/squads/company_squad_builds.json b/datafiles/main/squads/company_squad_builds.json index 705b36f420..17504439ff 100644 --- a/datafiles/main/squads/company_squad_builds.json +++ b/datafiles/main/squads/company_squad_builds.json @@ -1,210 +1,55 @@ { + "default_squads": [ + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "tactical_squad", "proportion": 6 }, + { "squad": "breacher_squad", "proportion": 0 }, + { "squad": "devastator_squad", "proportion": 2 }, + { "squad": "assault_squad", "proportion": 2 } + ], "companies": [ { "company": 1, "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "terminator_squad", - "proportion": 2 - }, - { - "squad": "terminator_assault_squad", - "proportion": 2 - }, - { - "squad": "veteran_squad", - "proportion": 1 - } - ] - }, - { - "company": 2, - "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "tactical_squad", - "proportion": 6 - }, - { - "squad": "breacher_squad", - "proportion": 0 - }, - { - "squad": "devastator_squad", - "proportion": 2 - }, - { - "squad": "assault_squad", - "proportion": 2 - } - ] - }, - { - "company": 3, - "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "tactical_squad", - "proportion": 6 - }, - { - "squad": "breacher_squad", - "proportion": 0 - }, - { - "squad": "devastator_squad", - "proportion": 2 - }, - { - "squad": "assault_squad", - "proportion": 2 - } - ] - }, - { - "company": 4, - "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "tactical_squad", - "proportion": 6 - }, - { - "squad": "breacher_squad", - "proportion": 0 - }, - { - "squad": "devastator_squad", - "proportion": 2 - }, - { - "squad": "assault_squad", - "proportion": 2 - } - ] - }, - { - "company": 5, - "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "tactical_squad", - "proportion": 6 - }, - { - "squad": "breacher_squad", - "proportion": 0 - }, - { - "squad": "devastator_squad", - "proportion": 2 - }, - { - "squad": "assault_squad", - "proportion": 2 - } + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "terminator_squad", "proportion": 2 }, + { "squad": "terminator_assault_squad", "proportion": 2 }, + { "squad": "veteran_squad", "proportion": 1 } ] }, { "company": 6, "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "tactical_squad", - "proportion": 1 - } + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "tactical_squad", "proportion": 1 } ] }, { "company": 7, "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "tactical_squad", - "proportion": 1 - } + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "tactical_squad", "proportion": 1 } ] }, { "company": 8, "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "assault_squad", - "proportion": 1 - } + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "assault_squad", "proportion": 1 } ] }, { "company": 9, "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "devastator_squad", - "proportion": 1 - } + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "devastator_squad", "proportion": 1 } ] }, { "company": 10, "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "scout_squad", - "proportion": 1 - } + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "scout_squad", "proportion": 1 } ] } ] -} \ No newline at end of file +} diff --git a/datafiles/main/squads/equal_scouts.json b/datafiles/main/squads/equal_scouts.json index 770df43fa8..ca00b88406 100644 --- a/datafiles/main/squads/equal_scouts.json +++ b/datafiles/main/squads/equal_scouts.json @@ -1,214 +1,56 @@ { + "default_squads": [ + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "tactical_squad", "proportion": 4 }, + { "squad": "devastator_squad", "proportion": 2 }, + { "squad": "assault_squad", "proportion": 2 }, + { "squad": "scout_squad", "proportion": 2 } + ], "companies": [ { "company": 1, "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "terminator_squad", - "proportion": 2 - }, - { - "squad": "terminator_assault_squad", - "proportion": 2 - }, - { - "squad": "veteran_squad", - "proportion": 1 - } - ] - }, - { - "company": 2, - "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "tactical_squad", - "proportion": 4 - }, - { - "squad": "devastator_squad", - "proportion": 2 - }, - { - "squad": "assault_squad", - "proportion": 2 - }, - { - "squad": "scout_squad", - "proportion": 2 - } - ] - }, - { - "company": 3, - "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "tactical_squad", - "proportion": 4 - }, - { - "squad": "devastator_squad", - "proportion": 2 - }, - { - "squad": "assault_squad", - "proportion": 2 - }, - { - "squad": "scout_squad", - "proportion": 2 - } - ] - }, - { - "company": 4, - "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "tactical_squad", - "proportion": 4 - }, - { - "squad": "devastator_squad", - "proportion": 2 - }, - { - "squad": "assault_squad", - "proportion": 2 - }, - { - "squad": "scout_squad", - "proportion": 2 - } - ] - }, - { - "company": 5, - "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "tactical_squad", - "proportion": 4 - }, - { - "squad": "devastator_squad", - "proportion": 2 - }, - { - "squad": "assault_squad", - "proportion": 2 - }, - { - "squad": "scout_squad", - "proportion": 2 - } + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "terminator_squad", "proportion": 2 }, + { "squad": "terminator_assault_squad", "proportion": 2 }, + { "squad": "veteran_squad", "proportion": 1 } ] }, { "company": 6, "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "tactical_squad", - "proportion": 1 - } + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "tactical_squad", "proportion": 1 } ] }, { "company": 7, "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "tactical_squad", - "proportion": 1 - } + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "tactical_squad", "proportion": 1 } ] }, { "company": 8, "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "assault_squad", - "proportion": 1 - } + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "assault_squad", "proportion": 1 } ] }, { "company": 9, "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "devastator_squad", - "proportion": 1 - } + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "devastator_squad", "proportion": 1 } ] }, { "company": 10, "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "scout_squad", - "proportion": 5 - }, - { - "squad": "tactical_squad", - "proportion": 4 - } + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "scout_squad", "proportion": 5 }, + { "squad": "tactical_squad", "proportion": 4 } ] } ] -} \ No newline at end of file +} diff --git a/datafiles/main/squads/equal_specialists.json b/datafiles/main/squads/equal_specialists.json index fb8f1c55eb..552880f543 100644 --- a/datafiles/main/squads/equal_specialists.json +++ b/datafiles/main/squads/equal_specialists.json @@ -1,226 +1,26 @@ { + "default_squads": [ + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "tactical_squad", "proportion": 6 }, + { "squad": "devastator_squad", "proportion": 2 }, + { "squad": "assault_squad", "proportion": 2 } + ], "companies": [ { "company": 1, "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "terminator_squad", - "proportion": 2 - }, - { - "squad": "terminator_assault_squad", - "proportion": 2 - }, - { - "squad": "veteran_squad", - "proportion": 1 - } - ] - }, - { - "company": 2, - "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "tactical_squad", - "proportion": 6 - }, - { - "squad": "devastator_squad", - "proportion": 2 - }, - { - "squad": "assault_squad", - "proportion": 2 - } - ] - }, - { - "company": 3, - "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "tactical_squad", - "proportion": 6 - }, - { - "squad": "devastator_squad", - "proportion": 2 - }, - { - "squad": "assault_squad", - "proportion": 2 - } - ] - }, - { - "company": 4, - "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "tactical_squad", - "proportion": 6 - }, - { - "squad": "devastator_squad", - "proportion": 2 - }, - { - "squad": "assault_squad", - "proportion": 2 - } - ] - }, - { - "company": 5, - "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "tactical_squad", - "proportion": 6 - }, - { - "squad": "devastator_squad", - "proportion": 2 - }, - { - "squad": "assault_squad", - "proportion": 2 - } - ] - }, - { - "company": 6, - "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "tactical_squad", - "proportion": 6 - }, - { - "squad": "devastator_squad", - "proportion": 2 - }, - { - "squad": "assault_squad", - "proportion": 2 - } - ] - }, - { - "company": 7, - "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "tactical_squad", - "proportion": 6 - }, - { - "squad": "devastator_squad", - "proportion": 2 - }, - { - "squad": "assault_squad", - "proportion": 2 - } - ] - }, - { - "company": 8, - "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "tactical_squad", - "proportion": 6 - }, - { - "squad": "devastator_squad", - "proportion": 2 - }, - { - "squad": "assault_squad", - "proportion": 2 - } - ] - }, - { - "company": 9, - "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "tactical_squad", - "proportion": 6 - }, - { - "squad": "devastator_squad", - "proportion": 2 - }, - { - "squad": "assault_squad", - "proportion": 2 - } + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "terminator_squad", "proportion": 2 }, + { "squad": "terminator_assault_squad", "proportion": 2 }, + { "squad": "veteran_squad", "proportion": 1 } ] }, { "company": 10, "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "scout_squad", - "proportion": 1 - } + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "scout_squad", "proportion": 1 } ] } ] -} \ No newline at end of file +} diff --git a/datafiles/main/squads/equal_spescout.json b/datafiles/main/squads/equal_spescout.json index e95d1eb94f..5fd0acbf98 100644 --- a/datafiles/main/squads/equal_spescout.json +++ b/datafiles/main/squads/equal_spescout.json @@ -1,262 +1,28 @@ { + "default_squads": [ + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "tactical_squad", "proportion": 5 }, + { "squad": "devastator_squad", "proportion": 2 }, + { "squad": "assault_squad", "proportion": 2 }, + { "squad": "scout_squad", "proportion": 1 } + ], "companies": [ { "company": 1, "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "terminator_squad", - "proportion": 2 - }, - { - "squad": "terminator_assault_squad", - "proportion": 2 - }, - { - "squad": "veteran_squad", - "proportion": 1 - } - ] - }, - { - "company": 2, - "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "tactical_squad", - "proportion": 5 - }, - { - "squad": "devastator_squad", - "proportion": 2 - }, - { - "squad": "assault_squad", - "proportion": 2 - }, - { - "squad": "scout_squad", - "proportion": 1 - } - ] - }, - { - "company": 3, - "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "tactical_squad", - "proportion": 5 - }, - { - "squad": "devastator_squad", - "proportion": 2 - }, - { - "squad": "assault_squad", - "proportion": 2 - }, - { - "squad": "scout_squad", - "proportion": 1 - } - ] - }, - { - "company": 4, - "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "tactical_squad", - "proportion": 5 - }, - { - "squad": "devastator_squad", - "proportion": 2 - }, - { - "squad": "assault_squad", - "proportion": 2 - }, - { - "squad": "scout_squad", - "proportion": 1 - } - ] - }, - { - "company": 5, - "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "tactical_squad", - "proportion": 5 - }, - { - "squad": "devastator_squad", - "proportion": 2 - }, - { - "squad": "assault_squad", - "proportion": 2 - }, - { - "squad": "scout_squad", - "proportion": 1 - } - ] - }, - { - "company": 6, - "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "tactical_squad", - "proportion": 5 - }, - { - "squad": "devastator_squad", - "proportion": 2 - }, - { - "squad": "assault_squad", - "proportion": 2 - }, - { - "squad": "scout_squad", - "proportion": 1 - } - ] - }, - { - "company": 7, - "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "tactical_squad", - "proportion": 5 - }, - { - "squad": "devastator_squad", - "proportion": 2 - }, - { - "squad": "assault_squad", - "proportion": 2 - }, - { - "squad": "scout_squad", - "proportion": 1 - } - ] - }, - { - "company": 8, - "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "tactical_squad", - "proportion": 5 - }, - { - "squad": "devastator_squad", - "proportion": 2 - }, - { - "squad": "assault_squad", - "proportion": 2 - }, - { - "squad": "scout_squad", - "proportion": 1 - } - ] - }, - { - "company": 9, - "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "tactical_squad", - "proportion": 5 - }, - { - "squad": "devastator_squad", - "proportion": 2 - }, - { - "squad": "assault_squad", - "proportion": 2 - }, - { - "squad": "scout_squad", - "proportion": 1 - } + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "terminator_squad", "proportion": 2 }, + { "squad": "terminator_assault_squad", "proportion": 2 }, + { "squad": "veteran_squad", "proportion": 1 } ] }, { "company": 10, "squads": [ - { - "squad": "command_squad", - "max_count": 1, - "min_count": 1, - "require": true - }, - { - "squad": "scout_squad", - "proportion": 5 - }, - { - "squad": "tactical_squad", - "proportion": 4 - } + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "scout_squad", "proportion": 5 }, + { "squad": "tactical_squad", "proportion": 4 } ] } ] -} \ No newline at end of file +} diff --git a/datafiles/main/squads/lightning_warriors.json b/datafiles/main/squads/lightning_warriors.json new file mode 100644 index 0000000000..41f6993946 --- /dev/null +++ b/datafiles/main/squads/lightning_warriors.json @@ -0,0 +1,229 @@ +{ + "default_squads": [ + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "tactical_squad", "proportion": 0 }, + { "squad": "bike_squad", "proportion": 9 }, + { "squad": "attack_bike_squad", "proportion": 6 }, + { "squad": "devastator_squad", "proportion": 0 }, + { "squad": "assault_squad", "proportion": 1 } + ], + "companies": [ + { + "company": 1, + "squads": [ + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "terminator_squad", "proportion": 2 }, + { "squad": "terminator_assault_squad", "proportion": 2 }, + { "squad": "veteran_squad", "proportion": 1 } + ] + }, + { + "company": 6, + "squads": [ + { "squad": "command_squad", "max_count": 1, "min_count":1, "require": true }, + { "squad": "tactical_squad", "proportion": 1 } + ] + }, + { + "company": 7, + "squads": [ + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "tactical_squad", "proportion": 1 } + ] + }, + { + "company": 8, + "squads": [ + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "assault_squad", "proportion": 1 } + ] + }, + { + "company": 9, + "squads": [ + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "devastator_squad", "proportion": 1 } + ] + }, + { + "company": 10, + "squads": [ + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "scout_squad", "proportion": 1 } + ] + } + ], + "distribution_overrides": { + "equal_specialists": { + "default_squads": [ + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "devastator_squad", "proportion": 1 }, + { "squad": "assault_squad", "proportion": 1 }, + { "squad": "tactical_squad", "proportion": 2 }, + { "squad": "attack_bike_squad", "proportion": 4 }, + { "squad": "bike_squad", "proportion": 6 } + ], + "companies": [ + { + "company": 6, + "squads": [ + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "devastator_squad", "proportion": 1 }, + { "squad": "assault_squad", "proportion": 1 }, + { "squad": "tactical_squad", "proportion": 2 }, + { "squad": "attack_bike_squad", "proportion": 4 }, + { "squad": "bike_squad", "proportion": 6 } + ] + }, + { + "company": 7, + "squads": [ + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "devastator_squad", "proportion": 1 }, + { "squad": "assault_squad", "proportion": 1 }, + { "squad": "tactical_squad", "proportion": 2 }, + { "squad": "attack_bike_squad", "proportion": 4 }, + { "squad": "bike_squad", "proportion": 6 } + ] + }, + { + "company": 8, + "squads": [ + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "devastator_squad", "proportion": 1 }, + { "squad": "assault_squad", "proportion": 1 }, + { "squad": "tactical_squad", "proportion": 2 }, + { "squad": "attack_bike_squad", "proportion": 4 }, + { "squad": "bike_squad", "proportion": 6 } + ] + }, + { + "company": 9, + "squads": [ + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "devastator_squad", "proportion": 1 }, + { "squad": "assault_squad", "proportion": 1 }, + { "squad": "tactical_squad", "proportion": 2 }, + { "squad": "attack_bike_squad", "proportion": 4 }, + { "squad": "bike_squad", "proportion": 6 } + ] + } + ] + }, + "equal_scouts": { + "default_squads": [ + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "attack_bike_squad", "proportion": 6 }, + { "squad": "bike_squad", "proportion": 8 }, + { "squad": "scout_squad", "proportion": 2 } + ], + "companies": [ + { + "company": 6, + "squads": [ + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "tactical_squad", "proportion": 6 } + ] + }, + { + "company": 7, + "squads": [ + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "tactical_squad", "proportion": 6 } + ] + }, + { + "company": 8, + "squads": [ + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "assault_squad", "proportion": 1 } + ] + }, + { + "company": 9, + "squads": [ + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "devastator_squad", "proportion": 1 } + ] + }, + { + "company": 10, + "squads": [ + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "scout_squad", "proportion": 1 }, + { "squad": "bike_squad", "proportion": 4 } + ] + } + ] + }, + "equal_spescout": { + "default_squads": [ + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "devastator_squad", "proportion": 1 }, + { "squad": "assault_squad", "proportion": 1 }, + { "squad": "scout_squad", "proportion": 1 }, + { "squad": "tactical_squad", "proportion": 1 }, + { "squad": "attack_bike_squad", "proportion": 4 }, + { "squad": "bike_squad", "proportion": 6 } + ], + "companies": [ + { + "company": 6, + "squads": [ + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "devastator_squad", "proportion": 1 }, + { "squad": "assault_squad", "proportion": 1 }, + { "squad": "scout_squad", "proportion": 1 }, + { "squad": "tactical_squad", "proportion": 1 }, + { "squad": "attack_bike_squad", "proportion": 4 }, + { "squad": "bike_squad", "proportion": 6 } + ] + }, + { + "company": 7, + "squads": [ + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "devastator_squad", "proportion": 1 }, + { "squad": "assault_squad", "proportion": 1 }, + { "squad": "scout_squad", "proportion": 1 }, + { "squad": "tactical_squad", "proportion": 1 }, + { "squad": "attack_bike_squad", "proportion": 4 }, + { "squad": "bike_squad", "proportion": 6 } + ] + }, + { + "company": 8, + "squads": [ + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "devastator_squad", "proportion": 1 }, + { "squad": "assault_squad", "proportion": 1 }, + { "squad": "scout_squad", "proportion": 1 }, + { "squad": "tactical_squad", "proportion": 1 }, + { "squad": "attack_bike_squad", "proportion": 4 }, + { "squad": "bike_squad", "proportion": 6 } + ] + }, + { + "company": 9, + "squads": [ + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "devastator_squad", "proportion": 1 }, + { "squad": "assault_squad", "proportion": 1 }, + { "squad": "scout_squad", "proportion": 1 }, + { "squad": "tactical_squad", "proportion": 1 }, + { "squad": "attack_bike_squad", "proportion": 4 }, + { "squad": "bike_squad", "proportion": 6 } + ] + }, + { + "company": 10, + "squads": [ + { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, + { "squad": "scout_squad", "proportion": 1 }, + { "squad": "bike_squad", "proportion": 4 } + ] + } + ] + } + } +} diff --git a/objects/obj_controller/Create_0.gml b/objects/obj_controller/Create_0.gml index c50a540b35..e2bfb416e2 100644 --- a/objects/obj_controller/Create_0.gml +++ b/objects/obj_controller/Create_0.gml @@ -808,6 +808,7 @@ bat_formation = array_create(_count, ""); bat_formation_type = array_create(_count, 0); bat_deva_for = array_create(_count, 1); bat_assa_for = array_create(_count, 4); +bat_bike_for = array_create(_count, 4); bat_tact_for = array_create(_count, 2); bat_vete_for = array_create(_count, 2); bat_hire_for = array_create(_count, 3); @@ -833,6 +834,7 @@ default_bat_formation(); bat_devastator_column = 1; bat_assault_column = 4; +bat_bike_column = 4; bat_tactical_column = 2; bat_veteran_column = 2; bat_hire_column = 3; diff --git a/objects/obj_creation/Create_0.gml b/objects/obj_creation/Create_0.gml index 0ecaca9b9d..7a72eb5f49 100644 --- a/objects/obj_creation/Create_0.gml +++ b/objects/obj_creation/Create_0.gml @@ -466,13 +466,14 @@ load_default_gear(eROLE.DEVASTATOR, "Devastator", "", "Combat Knife", STR_ANY_PO load_default_gear(eROLE.ASSAULT, "Assault", "Chainsword", "Bolt Pistol", STR_ANY_POWER_ARMOUR, "Jump Pack", ""); load_default_gear(eROLE.ANCIENT, "Ancient", "Company Standard", "Bolt Pistol", STR_ANY_POWER_ARMOUR, "", ""); load_default_gear(eROLE.SCOUT, "Scout", "Bolter", "Combat Knife", "Scout Armour", "", ""); +load_default_gear(eROLE.BIKER, "Biker", "Chainsword", "Bolt Pistol", STR_ANY_POWER_ARMOUR, "Bike", ""); load_default_gear(eROLE.CHAPLAIN, "Chaplain", "Crozius Arcanum", "Bolt Pistol", STR_ANY_POWER_ARMOUR, "", "Rosarius"); load_default_gear(eROLE.APOTHECARY, "Apothecary", "Chainsword", "Bolt Pistol", STR_ANY_POWER_ARMOUR, "", "Narthecium"); load_default_gear(eROLE.TECHMARINE, "Techmarine", "Power Axe", "Bolt Pistol", "Artificer Armour", "Servo-arm", ""); load_default_gear(eROLE.LIBRARIAN, "Librarian", "Force Staff", "Bolt Pistol", STR_ANY_POWER_ARMOUR, "", "Psychic Hood"); load_default_gear(eROLE.SERGEANT, "Sergeant", "Chainsword", "Bolt Pistol", STR_ANY_POWER_ARMOUR, "", ""); load_default_gear(eROLE.VETERANSERGEANT, "Veteran Sergeant", "Chainsword", "Plasma Pistol", STR_ANY_POWER_ARMOUR, "", ""); - +load_default_gear(eROLE.ATTACK_BIKER, "Attack Biker", "Heavy Bolter", "Chainsword", STR_ANY_POWER_ARMOUR, "Attack Bike", ""); if (global.restart > 0) { fade_in = -1; slate1 = -1; diff --git a/objects/obj_popup/Create_0.gml b/objects/obj_popup/Create_0.gml index 633e6523b4..72e4b3db88 100644 --- a/objects/obj_popup/Create_0.gml +++ b/objects/obj_popup/Create_0.gml @@ -191,27 +191,30 @@ get_unit_promotion_options = function() { i += 1; role_name[i] = obj_ini.role[100][8]; //tacts role_exp[i] = company_promote_data[target_comp].exp; - if (obj_controller.command_set[2] == 0) { - role_exp[i] = 0; - } } if (array_contains([2, 3, 4, 5, 8], target_comp)) { i += 1; role_name[i] = obj_ini.role[100][10]; //assualts role_exp[i] = company_promote_data[target_comp].exp; - if (obj_controller.command_set[2] == 0) { - role_exp[i] = 0; - } } if (array_contains([2, 3, 4, 5, 9], target_comp)) { i += 1; role_name[i] = obj_ini.role[100][9]; //devs role_exp[i] = company_promote_data[target_comp].exp; - if (obj_controller.command_set[2] == 0) { - role_exp[i] = 0; - } + } + + if (array_contains([2, 3, 4, 5], target_comp)) { + i += 1; + role_name[i] = obj_ini.role[100][13]; //bikers + role_exp[i] = company_promote_data[target_comp].exp; + } + + if (array_contains([2, 3, 4, 5], target_comp)) { + i += 1; + role_name[i] = obj_ini.role[100][20]; //attack bikers + role_exp[i] = company_promote_data[target_comp].exp; } if (target_comp == 1) { @@ -224,9 +227,6 @@ get_unit_promotion_options = function() { i += 1; role_name[i] = obj_ini.role[100][12]; //scouts role_exp[i] = company_promote_data[target_comp].exp; - if (obj_controller.command_set[2] == 0) { - role_exp[i] = 0; - } } if (target_comp == 1) { @@ -255,6 +255,14 @@ get_unit_promotion_options = function() { role_name[i] = obj_ini.role[100][12]; //scouts role_exp[i] = 0; + i += 1; + role_name[i] = obj_ini.role[100][13]; //bikers + role_exp[i] = 0; + + i += 1; + role_name[i] = obj_ini.role[100][20]; //attack bikers + role_exp[i] = 0; + i += 1; role_name[i] = obj_ini.role[100][3]; //veterans role_exp[i] = 0; diff --git a/scripts/is_specialist/is_specialist.gml b/scripts/is_specialist/is_specialist.gml index 0581a0c37b..9b818a1534 100644 --- a/scripts/is_specialist/is_specialist.gml +++ b/scripts/is_specialist/is_specialist.gml @@ -172,6 +172,8 @@ function role_groups(group, include_trainee = false, include_heads = true) { _roles[eROLE.TACTICAL], _roles[eROLE.DEVASTATOR], _roles[eROLE.ASSAULT], + _roles[eROLE.BIKER], + _roles[eROLE.ATTACK_BIKER], _roles[eROLE.SCOUT] ]; break; diff --git a/scripts/macros/macros.gml b/scripts/macros/macros.gml index f293b5c665..3ac5fdaca9 100644 --- a/scripts/macros/macros.gml +++ b/scripts/macros/macros.gml @@ -73,12 +73,14 @@ enum eROLE { ASSAULT = 10, ANCIENT = 11, SCOUT = 12, + BIKER = 13, CHAPLAIN = 14, APOTHECARY = 15, TECHMARINE = 16, LIBRARIAN = 17, SERGEANT = 18, VETERANSERGEANT = 19, + ATTACK_BIKER = 20, LANDRAIDER = 50, RHINO = 51, PREDATOR = 52, diff --git a/scripts/scr_UnitGroup/scr_UnitGroup.gml b/scripts/scr_UnitGroup/scr_UnitGroup.gml index e3ccf4ef9b..ebd399c620 100644 --- a/scripts/scr_UnitGroup/scr_UnitGroup.gml +++ b/scripts/scr_UnitGroup/scr_UnitGroup.gml @@ -199,10 +199,11 @@ function UnitGroup(units) constructor { var _roles = active_roles(); - static sgt_types = role_groups(SPECIALISTS_SQUAD_LEADERS); + static sgt_types = []; static create_squad = function(squad_type, squad_loadout = true, squad_uid = "", game_start = false) { - // LOGGER.info($"sgts : ${sgt_types}"); + //LOGGER.info($"sgts : ${sgt_types}"); + sgt_types = role_groups(SPECIALISTS_SQUAD_LEADERS); var roles = active_roles(); @@ -222,20 +223,74 @@ function UnitGroup(units) constructor { var _fill_squad = obj_ini.squad_types[$ squad_type]; var _fulfilled = false; + //adding multiple role sources on gen within a single squad + var _all_roles_to_fetch = array_create(0); + for (var r = 0; r < array_length(squad_unit_types); r++) { + var _primary_role = squad_unit_types[r]; + var _primary_role_def = _fill_squad[$ _primary_role]; + var _primary_role_name = struct_exists(_primary_role_def, "role") ? _primary_role_def.role : _primary_role; + if (!array_contains(_all_roles_to_fetch, _primary_role_name)) { + array_push(_all_roles_to_fetch, _primary_role_name); + } + // Always include the JSON key itself as a source — units carry their base role + // (e.g. "Terminator") before being renamed to the squad-specific role ("Deathwing Terminator") + if (!array_contains(_all_roles_to_fetch, _primary_role)) { + array_push(_all_roles_to_fetch, _primary_role); + } - var _squadless = get_from({squadless: true, roles: squad_unit_types}); + //add alternative source roles to fetch list if this squad role defines them + if (struct_exists(_primary_role_def, "alternative_roles")) { + var _alternatives = _primary_role_def.alternative_roles; + for (var a = 0; a < array_length(_alternatives); a++) { + if (!array_contains(_all_roles_to_fetch, _alternatives[a])) { + array_push(_all_roles_to_fetch, _alternatives[a]); + } + } + } + } + //ensure generic sergeant role names are always included in the pool + //JSON overrides with specific names "Tactical Sergeant" + for (var s = 0; s < 2; s++) { + if (!array_contains(_all_roles_to_fetch, sgt_types[s])) { + array_push(_all_roles_to_fetch, sgt_types[s]); + } + } + + var _squadless = get_from({squadless: true, roles: _all_roles_to_fetch}); for (var s = 0; s < 2; s++) { var _sgt_type = sgt_types[s]; - var _available_sgt = _squadless.get_from({role: _sgt_type, max_wanted: 1}); + var _available_sgt = _squadless.get_from({role: _sgt_type, max_wanted: 1}, true, true); if (_available_sgt.number() == 0) { continue; } var _sgt = _available_sgt.units[0]; - squad.add_member(_sgt); - squad_fulfilment[$ _sgt_type]++; + // Confirm this squad actually has a slot for this sergeant role BEFORE adding the + // candidate or marking sergeant_found. Otherwise a sergeant whose role the squad has + // no slot for would be added anyway and incorrectly suppress the promotion flow. + var _sgt_group = ""; + for (var r = 0; r < array_length(squad_unit_types); r++) { + var _role_name = squad_unit_types[r]; + var _role_def = _fill_squad[$ _role_name]; + var _primary_role_name = struct_exists(_role_def, "role") ? _role_def.role : _role_name; + if (_primary_role_name == _sgt_type || (_role_name == "Sergeant" && _sgt_type == sgt_types[0]) || (_role_name == "Veteran Sergeant" && _sgt_type == sgt_types[1])) { + _sgt_group = _role_name; + break; + } + } + if (_sgt_group == "") { + continue; + } + squad.add_member(_sgt.company, _sgt.marine_number); + squad_fulfilment[$ _sgt_group]++; + // Rename pre-existing sergeant to squad-specific role if needed + var _sgt_slot_def = _fill_squad[$ _sgt_group]; + var _target_sgt_role = struct_exists(_sgt_slot_def, "role") ? _sgt_slot_def.role : _sgt_type; + if (_target_sgt_role != _sgt.role()) { + _sgt.update_role(_target_sgt_role); + } sergeant_found = true; } @@ -252,8 +307,17 @@ function UnitGroup(units) constructor { var _has_sgt_requirements = false; for (var s = 0; s < 2; s++) { var _sgt_type = sgt_types[s]; - if (array_contains(squad_unit_types, _sgt_type)) { - _has_sgt_requirements = true; + for (var r = 0; r < array_length(squad_unit_types); r++) { + var _role_name = squad_unit_types[r]; + var _role_def = _fill_squad[$ _role_name]; + var _primary_role_name = struct_exists(_role_def, "role") ? _role_def.role : _role_name; + if (_primary_role_name == _sgt_type || _role_name == "Sergeant" && _sgt_type == sgt_types[0] || _role_name == "Veteran Sergeant" && _sgt_type == sgt_types[1]) { + _has_sgt_requirements = true; + break; + } + } + if (_has_sgt_requirements) { + break; } } @@ -262,15 +326,61 @@ function UnitGroup(units) constructor { } //clone or else keeps pushing up number - var _max = variable_clone(_fill_squad[$ _unit.role()][$ "max"]); + //EXPERIMENTAL Determine which role GROUP this marine belongs to + var _target_role = _unit.role(); + var _role_group = ""; // default to the marine's own role + + // Search through defined role groups to find which one this marine belongs to + for (var r = 0; r < array_length(squad_unit_types); r++) { + var _role_name = squad_unit_types[r]; + var _role_def = _fill_squad[$ _role_name]; + var _primary_role_name = struct_exists(_role_def, "role") ? _role_def.role : _role_name; + + + // Check if marine matches this primary role (squad-specific rename target) + if (_target_role == _primary_role_name) { + _role_group = _role_name; + break; + } + // Check if marine matches the JSON key itself (base role before squad rename) + if (_target_role == _role_name) { + _role_group = _role_name; + break; + } + + // Check if marine matches any alternative roles for this group + if (struct_exists(_role_def, "alternative_roles")) { + var _alts = _role_def.alternative_roles; + if (array_contains(_alts, _target_role)) { + _role_group = _role_name; + break; + } + } + } + + if (_role_group == "") { + continue; + } + + // NEW: Check max capacity for the ROLE GROUP (not the source role) + var _max = variable_clone(_fill_squad[$ _role_group][$ "max"]); if (_has_sgt_requirements) { _max += 1; } - if (squad_fulfilment[$ _unit.role()] < _max) { + // NEW: Track fulfillment by role GROUP, allowing alternatives to fill the same slot + if (squad_fulfilment[$ _role_group] < _max) { //if sergeants not required - squad_fulfilment[$ _unit.role()]++; + squad_fulfilment[$ _role_group]++; squad.add_member(_unit.company, _unit.marine_number); + // Rename unit to the squad-specific role only for rank-and-file marines + // (Tactical/Assault/Devastator/Scout → Biker, Breacher, etc.) + // Specialists (Chaplain, Ancient, Champion, Veteran, etc.) keep their existing role + var _slot_def = _fill_squad[$ _role_group]; + if (struct_exists(_slot_def, "role") && _slot_def.role != _unit.role() + && _unit.IsSpecialist(SPECIALISTS_RANK_AND_FILE)) { + _unit.update_role(_slot_def.role); + } } } @@ -279,16 +389,51 @@ function UnitGroup(units) constructor { /*and ((squad_fulfilment[$ obj_ini.role[100][8]] > 4)or (squad_fulfilment[$ obj_ini.role[100][10]] > 4) or (squad_fulfilment[$ obj_ini.role[100][9]] > 4)or (squad_fulfilment[$ obj_ini.role[100][3]] > 4) )*/ var _members = squad.get_members(true); - var _exp_unit = 0; if (!bool(_members.number())) { return [false, squad.uid]; } + // Select would-be sergeant candidates and reserve their fulfilment slot, but defer the + // actual role mutation (update_role / add_trait) until squad viability is confirmed below. + // update_role permanently rewrites obj_ini.role and applies stat/command changes, so + // promoting here — before _fulfilled is known — would leave marines mutated even when the + // squad creation attempt ultimately fails, causing persistent state drift. + var _pending_promotions = []; + var _promoted_units = []; // marines already queued for a leader slot, so a 2nd slot picks a distinct one for (var s = 0; s < 2; s++) { var _sgt_type = sgt_types[s]; - if (struct_exists(squad_fulfilment, _sgt_type) && (!sergeant_found)) { - _exp_unit = _members.highest_exp(); - - squad_fulfilment[$ _sgt_type]++; + var _sgt_group = ""; + for (var r = 0; r < array_length(squad_unit_types); r++) { + var _role_name = squad_unit_types[r]; + var _role_def = _fill_squad[$ _role_name]; + var _primary_role_name = struct_exists(_role_def, "role") ? _role_def.role : _role_name; + if (_primary_role_name == _sgt_type || (_role_name == "Sergeant" && _sgt_type == sgt_types[0]) || (_role_name == "Veteran Sergeant" && _sgt_type == sgt_types[1])) { + _sgt_group = _role_name; + break; + } + } + if (_sgt_group != "" && struct_exists(squad_fulfilment, _sgt_group) && (!sergeant_found)) { + // Highest-experience member not already queued for another leader slot, so two + // leader slots (e.g. Sergeant + Veteran Sergeant) never promote the same marine. + var _candidate = undefined; + var _candidate_exp = -1; + for (var _mi = 0; _mi < _members.number(); _mi++) { + var _m = _members.units[_mi]; + if (array_contains(_promoted_units, _m)) { + continue; + } + if (_candidate == undefined || _m.experience > _candidate_exp) { + _candidate = _m; + _candidate_exp = _m.experience; + } + } + if (_candidate == undefined) { + continue; // no distinct member left for this leader slot + } + array_push(_promoted_units, _candidate); + var _sgt_role_def = _fill_squad[$ _sgt_group]; + var _actual_sgt_role = struct_exists(_sgt_role_def, "role") ? _sgt_role_def.role : _sgt_type; + squad_fulfilment[$ _sgt_group]++; + array_push(_pending_promotions, { unit: _candidate, role: _actual_sgt_role }); } } @@ -303,12 +448,12 @@ function UnitGroup(units) constructor { } } if (_fulfilled) { - for (var s = 0; s < 2; s++) { - if (struct_exists(squad_fulfilment, sgt_types[s]) && (sergeant_found == false)) { - _exp_unit.update_role(sgt_types[s]); //if squad is viable promote marine to sergeant - if (game_start && irandom(1) == 0) { - _exp_unit.add_trait("lead_example"); - } + // Squad is viable — now apply the deferred sergeant promotions. + for (var p = 0; p < array_length(_pending_promotions); p++) { + var _promo = _pending_promotions[p]; + _promo.unit.update_role(_promo.role); //if squad is viable promote marine to sergeant + if (game_start && irandom(1) == 0) { + _promo.unit.add_trait("lead_example"); } } //update units squad marker diff --git a/scripts/scr_chapter_new/scr_chapter_new.gml b/scripts/scr_chapter_new/scr_chapter_new.gml index 132106b837..907c57727e 100644 --- a/scripts/scr_chapter_new/scr_chapter_new.gml +++ b/scripts/scr_chapter_new/scr_chapter_new.gml @@ -231,12 +231,14 @@ function scr_chapter_new(chapter_identifier) { load_default_gear(eROLE.ASSAULT, "Assault", "Chainsword", "Bolt Pistol", STR_ANY_POWER_ARMOUR, "Jump Pack", ""); load_default_gear(eROLE.ANCIENT, "Ancient", "Company Standard", "Bolt Pistol", STR_ANY_POWER_ARMOUR, "", ""); load_default_gear(eROLE.SCOUT, "Scout", "Bolter", "Combat Knife", "Scout Armour", "", ""); + load_default_gear(eROLE.BIKER, "Biker", "Chainsword", "Bolt Pistol", STR_ANY_POWER_ARMOUR,"Bike",""); load_default_gear(eROLE.CHAPLAIN, "Chaplain", "Crozius Arcanum", "Bolt Pistol", STR_ANY_POWER_ARMOUR, "", "Rosarius"); load_default_gear(eROLE.APOTHECARY, "Apothecary", "Chainsword", "Bolt Pistol", STR_ANY_POWER_ARMOUR, "", "Narthecium"); load_default_gear(eROLE.TECHMARINE, "Techmarine", "Power Axe", "Bolt Pistol", "Artificer Armour", "Servo-arm", ""); load_default_gear(eROLE.LIBRARIAN, "Librarian", "Force Staff", "Bolt Pistol", STR_ANY_POWER_ARMOUR, "", "Psychic Hood"); load_default_gear(eROLE.SERGEANT, "Sergeant", "Chainsword", "Bolt Pistol", STR_ANY_POWER_ARMOUR, "", ""); load_default_gear(eROLE.VETERANSERGEANT, "Veteran Sergeant", "Chainsword", "Plasma Pistol", STR_ANY_POWER_ARMOUR, "", ""); + load_default_gear(eROLE.ATTACK_BIKER, "Attack Biker", "Heavy Bolter", "Chainsword", STR_ANY_POWER_ARMOUR, "Attack Bike", ""); for (var c = 0; c < array_length(obj_creation.all_chapters); c++) { if (chapter_identifier == obj_creation.all_chapters[c].name && obj_creation.all_chapters[c].json == true) { diff --git a/scripts/scr_company_order/scr_company_order.gml b/scripts/scr_company_order/scr_company_order.gml index b7996fc3cc..93b62e164a 100644 --- a/scripts/scr_company_order/scr_company_order.gml +++ b/scripts/scr_company_order/scr_company_order.gml @@ -70,18 +70,8 @@ function scr_company_order(company) { if (_squadless.number() > 3) { var _squad_index = _company_marines.index_squads(); - var _data_match = false; - var _data; - if (struct_exists(obj_ini.chapter_squad_arrangement, "companies")) { - var _comp_datas = obj_ini.chapter_squad_arrangement.companies; - for (var i = 0; i < array_length(_comp_datas); i++) { - if (_comp_datas[i].company == co) { - _data_match = true; - _data = _comp_datas[i]; - } - } - } - if (_data_match) { + var _data = resolve_company_arrangement(obj_ini.chapter_squad_arrangement, co); + if (_data != undefined) { _squadless.organise_by_template(_data, _squad_index, _empty_index, false); } @@ -194,5 +184,79 @@ function role_hierarchy() { "Ork Sniper" ]; + // Dynamically collect squad-specific sergeant role variants (e.g. "Biker Sergeant", "Tactical Sergeant") + // so they sort immediately after the generic sergeant, keeping them at the top of their squads + var _sgt_base = _roles[eROLE.SERGEANT]; + var _vsgt_base = _roles[eROLE.VETERANSERGEANT]; + var _squad_type_names = struct_get_names(obj_ini.squad_types); + for (var _si = 0; _si < array_length(_squad_type_names); _si++) { + var _sq_data = obj_ini.squad_types[$ _squad_type_names[_si]]; + var _sq_keys = struct_get_names(_sq_data); + for (var _ki = 0; _ki < array_length(_sq_keys); _ki++) { + var _k = _sq_keys[_ki]; + if (_k == "type_data") continue; + var _role_def = _sq_data[$ _k]; + if (!struct_exists(_role_def, "role")) continue; + var _specific_role = _role_def.role; + if (!array_contains(hierarchy, _specific_role)) { + // Classify by the slot's JSON key (_k), not the renamed role string. Veteran-sergeant + // variants are keyed "Veteran Sergeant" but get renamed to names like "Deathwing + // Sergeant" / "Proteus Watch Sergeant" that contain "Sergeant" but NOT the exact + // substring "Veteran Sergeant" — so a role-string match would mis-rank them as + // regular sergeants. Fall back to string matching only when the key isn't a sergeant. + var _is_vsgt = (_k == _vsgt_base) || (string_count(_vsgt_base, _specific_role) > 0); + var _is_sgt = (_k == _sgt_base) || (string_count(_sgt_base, _specific_role) > 0); + if (_is_vsgt) { + // Veteran-sergeant variant — insert just before _vsgt_base position + var _vpos = array_get_index(hierarchy, _vsgt_base); + array_insert(hierarchy, max(0, _vpos), _specific_role); + } else if (_is_sgt) { + // Regular sergeant variant — insert just after _sgt_base position + var _spos = array_get_index(hierarchy, _sgt_base); + array_insert(hierarchy, _spos + 1, _specific_role); + } + } + } + } + + // Also add non-sergeant squad-specific role variants so they appear after their base role + var _base_roles = [ + _roles[eROLE.TERMINATOR], _roles[eROLE.VETERAN], + _roles[eROLE.TACTICAL], _roles[eROLE.ASSAULT], + _roles[eROLE.DEVASTATOR], _roles[eROLE.SCOUT], + _roles[eROLE.ANCIENT], _roles[eROLE.CHAMPION], + _roles[eROLE.CHAPLAIN], _roles[eROLE.APOTHECARY], + _roles[eROLE.TECHMARINE], _roles[eROLE.LIBRARIAN] + ]; + for (var _si = 0; _si < array_length(_squad_type_names); _si++) { + var _sq_data = obj_ini.squad_types[$ _squad_type_names[_si]]; + var _sq_keys = struct_get_names(_sq_data); + for (var _ki = 0; _ki < array_length(_sq_keys); _ki++) { + var _k = _sq_keys[_ki]; + if (_k == "type_data") continue; + var _role_def = _sq_data[$ _k]; + if (!struct_exists(_role_def, "role")) continue; + var _specific_role = _role_def.role; + if (array_contains(hierarchy, _specific_role)) continue; + // Skip sergeant variants (already handled above) + if (string_count(_sgt_base, _specific_role) > 0) continue; + // Find the closest matching base role and insert after it + for (var _bi = 0; _bi < array_length(_base_roles); _bi++) { + if (struct_exists(_role_def, "alternative_roles") && + array_contains(_role_def.alternative_roles, _base_roles[_bi])) { + var _bpos = array_get_index(hierarchy, _base_roles[_bi]); + if (_bpos >= 0) { + array_insert(hierarchy, _bpos + 1, _specific_role); + break; + } + } + } + // If not inserted via alternative_roles, just append before rank-and-file + if (!array_contains(hierarchy, _specific_role)) { + array_push(hierarchy, _specific_role); + } + } + } + return hierarchy; } diff --git a/scripts/scr_creation/scr_creation.gml b/scripts/scr_creation/scr_creation.gml index 8f0add29e8..fbccefd23f 100644 --- a/scripts/scr_creation/scr_creation.gml +++ b/scripts/scr_creation/scr_creation.gml @@ -39,7 +39,7 @@ function set_complex_livery_buttons() { function update_creation_roles_radio(start_role = 1) { var _role_data = []; - for (var i = start_role; i <= 19; i++) { + for (var i = start_role; i <= 20; i++) { if (race[100][i] != 0 && role[100][i] != "") { array_push(_role_data, {str1: role[100][i], font: fnt_40k_14b, role_id: i}); } diff --git a/scripts/scr_initialize_custom/scr_initialize_custom.gml b/scripts/scr_initialize_custom/scr_initialize_custom.gml index 7bee2adb51..303784081c 100644 --- a/scripts/scr_initialize_custom/scr_initialize_custom.gml +++ b/scripts/scr_initialize_custom/scr_initialize_custom.gml @@ -1482,12 +1482,14 @@ function scr_initialize_custom() { load_default_gear(eROLE.ASSAULT, "Assault", "Chainsword", "Bolt Pistol", STR_ANY_POWER_ARMOUR, "Jump Pack", ""); load_default_gear(eROLE.ANCIENT, "Ancient", "Company Standard", "Bolt Pistol", STR_ANY_POWER_ARMOUR, "", ""); load_default_gear(eROLE.SCOUT, "Scout", "Bolter", "Combat Knife", "Scout Armour", "", ""); + load_default_gear(eROLE.BIKER, "Biker", "Chainsword", "Bolt Pistol", STR_ANY_POWER_ARMOUR, "Bike", ""); load_default_gear(eROLE.CHAPLAIN, "Chaplain", "Crozius Arcanum", "Bolt Pistol", STR_ANY_POWER_ARMOUR, "", "Rosarius"); load_default_gear(eROLE.APOTHECARY, "Apothecary", "Chainsword", "Bolt Pistol", STR_ANY_POWER_ARMOUR, "", "Narthecium"); load_default_gear(eROLE.TECHMARINE, "Techmarine", "Omnissian Axe", "Bolt Pistol", _hi_qual_armour, "Servo-arm", ""); load_default_gear(eROLE.LIBRARIAN, "Librarian", "Force Staff", "Bolt Pistol", STR_ANY_POWER_ARMOUR, "", "Psychic Hood"); load_default_gear(eROLE.SERGEANT, "Sergeant", "Chainsword", "Bolt Pistol", STR_ANY_POWER_ARMOUR, "", ""); load_default_gear(eROLE.VETERANSERGEANT, "Veteran Sergeant", "Chainsword", "Plasma Pistol", STR_ANY_POWER_ARMOUR, "", ""); + load_default_gear(eROLE.ATTACK_BIKER, "Attack Biker", "Heavy Bolter", "Chainsword", STR_ANY_POWER_ARMOUR, "Attack Bike", ""); obj_ini.role[101] = obj_ini.role[100]; if (scr_has_disadv("Psyker Intolerant")) { race[defaults_slot][eROLE.LIBRARIAN] = 0; @@ -1543,6 +1545,14 @@ function scr_initialize_custom() { "scout", eROLE.SCOUT ], + [ + "biker", + eROLE.BIKER + ], + [ + "attack_biker", + eROLE.ATTACK_BIKER + ], [ "chaplain", eROLE.CHAPLAIN @@ -1639,23 +1649,41 @@ function scr_initialize_custom() { #endregion #region Squad Loadouts - switch (obj_creation.squad_distribution) { - case 1: // equal specialists only - obj_ini.chapter_squad_arrangement = json_to_gamemaker( - working_directory + $"main/squads/equal_specialists.json", json_parse); - break; - case 2: // equal scouts only - obj_ini.chapter_squad_arrangement = json_to_gamemaker( - working_directory + $"main/squads/equal_scouts.json", json_parse); - break; - case 3: // equal specialists and equal scouts - obj_ini.chapter_squad_arrangement = json_to_gamemaker( - working_directory + $"main/squads/equal_spescout.json", json_parse); - break; - default: // 0 = standard - obj_ini.chapter_squad_arrangement = json_to_gamemaker( - working_directory + $"main/squads/company_squad_builds.json", json_parse); - break; + if (scr_has_adv("Lightning Warriors")) { + obj_ini.chapter_squad_arrangement = json_to_gamemaker( + working_directory + $"main\\squads\\lightning_warriors.json", json_parse); + var _dist_key = ""; + switch (obj_creation.squad_distribution) { + case 1: _dist_key = "equal_specialists"; break; + case 2: _dist_key = "equal_scouts"; break; + case 3: _dist_key = "equal_spescout"; break; + } + if (_dist_key != "" + && struct_exists(obj_ini.chapter_squad_arrangement, "distribution_overrides") + && struct_exists(obj_ini.chapter_squad_arrangement.distribution_overrides, _dist_key)) { + apply_squad_distribution_override( + obj_ini.chapter_squad_arrangement, + obj_ini.chapter_squad_arrangement.distribution_overrides[$ _dist_key]); + } + } else { + switch (obj_creation.squad_distribution) { + case 1: // equal specialists only + obj_ini.chapter_squad_arrangement = json_to_gamemaker( + working_directory + $"main\\squads\\equal_specialists.json", json_parse); + break; + case 2: // equal scouts only + obj_ini.chapter_squad_arrangement = json_to_gamemaker( + working_directory + $"main\\squads\\equal_scouts.json", json_parse); + break; + case 3: // equal specialists and equal scouts + obj_ini.chapter_squad_arrangement = json_to_gamemaker( + working_directory + $"main\\squads\\equal_spescout.json", json_parse); + break; + default: // 0 = standard + obj_ini.chapter_squad_arrangement = json_to_gamemaker( + working_directory + $"main\\squads\\company_squad_builds.json", json_parse); + break; + } } var _squad_name = "Squad"; @@ -1749,7 +1777,8 @@ function scr_initialize_custom() { ]; var _roles_player = obj_ini.role[100]; var _default_player = obj_ini.role[101]; - for (var i = 1; i < 20; i++) { + var i; + for (i = 1; i < 21; i++) { if (_roles_player[i] == "") { continue; } @@ -1763,7 +1792,7 @@ function scr_initialize_custom() { array_push(_swaps, _set); } - for (var i = 1; i < 20; i++) { + for (i = 1; i < 21; i++) { var _set = {}; var _key = $"wep1[{i}]"; var _val = obj_ini.wep1[100][i]; @@ -1777,15 +1806,26 @@ function scr_initialize_custom() { array_push(_swaps, _set); } + // LOGGER.debug($"squads object for chapter {chapter_name}"); + // LOGGER.debug($"{custom_squads}"); + if (variable_instance_exists(obj_creation, "squad_builder")) { + if (!struct_exists(obj_ini.chapter_squad_arrangement, "companies")) { + obj_ini.chapter_squad_arrangement.companies = []; + } for (var s = 0; s < array_length(obj_creation.squad_builder); s++) { var _custom_build = obj_creation.squad_builder[s]; + var _found = false; for (var i = 0; i < array_length(obj_ini.chapter_squad_arrangement.companies); i++) { - var _default_build = obj_ini.chapter_squad_arrangement.companies[i]; - if (_custom_build.company == _default_build.company) { + if (obj_ini.chapter_squad_arrangement.companies[i].company == _custom_build.company) { obj_ini.chapter_squad_arrangement.companies[i] = _custom_build; + _found = true; + break; } } + if (!_found) { + array_push(obj_ini.chapter_squad_arrangement.companies, _custom_build); + } } } @@ -1830,40 +1870,7 @@ function scr_initialize_custom() { }; } - /*if (scr_has_adv("Lightning Warriors")) { - variable_struct_set( - custom_squads, - "bikers", - [ - [ - roles.assault, - { - "max": 9, - "min": 4, - "loadout": { - //tactical marine - "required": {"wep1": ["", "max"], "wep2": ["Chainsword", "max"], "mobi": ["Bike", "max"]}, - }, - "role": $"Biker", - } - ], - [ - roles.sergeant, - { - "max": 1, - "min": 1, - "loadout": { - //sergeant - "required": {"wep1": ["", "max"], "wep2": ["Chainsword", "max"], "mobi": ["Bike", 1]}, - }, - "role": $"Biker {roles.sergeant}", - } - ], - ["type_data", {"display_data": $"Bike {_squad_name}", "class": ["bike"], "formation_options": ["assault", "tactical"]}] - ] - ); - } - + /* if (scr_has_adv("Boarders")) { variable_struct_set( custom_squads, @@ -2303,6 +2310,7 @@ function scr_initialize_custom() { var equal_scouts = (squad_distribution == 2 || squad_distribution == 3); obj_ini.equal_scouts = equal_scouts; // for use in squad creation later + var _lw = scr_has_adv("Lightning Warriors"); var _moved_scouts = 0; var _coys = struct_get_names(companies); @@ -2361,6 +2369,15 @@ function scr_initialize_custom() { /// comp 10: tac 40: scout 50; if (squad_distribution == 1 || squad_distribution == 3) { if (_coy.coy >= 2 && _coy.coy <= 9) { + // Scout distribution logic for equal_spescout (sd==3). + // + // 10 scouts are moved from the 10th company bank into each battle company (2-9) + // so that the JSON template's scout_squad proportion can fill at game start. + // This applies regardless of whether Lightning Warriors is active; LW+equal_spescout + // distributes 10 scouts per company just like the non-LW case. + // + // Note: for LW + equal_scouts (sd==2) this branch is not reached at all because + // sd==2 does not satisfy (sd==1 || sd==3), so it falls to the else block below. if (equal_scouts) { if (companies.tenth.scouts > 10) { //theoretically this keeps track of moving scouts from the bank of them in 10th @@ -2378,6 +2395,9 @@ function scr_initialize_custom() { _coy.assaults = assault; _coy.devastators = devastator; } + // Replace the scouts that were moved out of 10th company with an equivalent number + // of tacticals so the 10th's total marine count stays consistent. + // _moved_scouts tracks the cumulative scouts transferred to other companies above. if (equal_scouts && _coy.coy == 10) { // theoretically this swaps moved scouts with tacticals _coy.tacticals = _moved_scouts; @@ -2387,11 +2407,15 @@ function scr_initialize_custom() { /// and the assaults go into the 8th and devastators into the 9th if (_coy.coy >= 2 && _coy.coy <= 5) { if (equal_scouts) { - if (companies.tenth.scouts > 10) { - _coy.scouts = 10; + // LW needs 20 scouts per company to fill proportion:2 scout squads. + // Non-LW equal_scouts uses 10 (proportion:1). Guard against the amount + // actually subtracted so the 10th's bank never goes negative. + var _coy_scout_draw = _lw ? 20 : 10; + if (companies.tenth.scouts >= _coy_scout_draw) { + _coy.scouts = _coy_scout_draw; _moved_scouts += _coy.scouts; _coy.tacticals = max(0, (_coy.total - (assault + devastator + _coy.scouts))); - companies.tenth.scouts -= _moved_scouts; + companies.tenth.scouts -= _coy.scouts; // fix: subtract this company's amount, not the cumulative total } else { // if 10th is run out somehow, revert to normal behaviour _coy.tacticals = max(0, (_coy.total - (assault + devastator))); @@ -2403,23 +2427,27 @@ function scr_initialize_custom() { _coy.devastators = devastator; } + // Companies 6-7 are tactical-only reserves for every distribution. Both + // company_squad_builds/equal_scouts.json and lightning_warriors.json's equal_scouts + // override define companies 6 and 7 as tactical_squad-only, with no scout_squad entry + // at all - so handing them scout marines here (under any distribution) would leave + // stray squadless scouts the template can never organise into squads. Scouts stay + // confined to the battle companies 2-5 (which fall through to default_squads' + // scout_squad) and the 10th; the scouts not moved here simply remain in the 10th's bank. if (real(_coy.coy) >= 6 && real(_coy.coy) <= 7) { - if (equal_scouts) { - if (companies.tenth.scouts > 10) { - _coy.scouts = 10; - _moved_scouts += _coy.scouts; - _coy.tacticals = _coy.total - _coy.scouts; - companies.tenth.scouts -= _coy.scouts; - } else { - // if 10th is run out somehow, revert to normal behaviour - _coy.tacticals = _coy.total; - } - } else { - _coy.tacticals = _coy.total; - } + _coy.tacticals = _coy.total; _coy.assaults = 0; _coy.devastators = 0; } + // Company 8 and 9: always pure assault / devastator reserves for equal_scouts + // (sd==2), regardless of Lightning Warriors. Both company_squad_builds/ + // equal_scouts.json AND lightning_warriors.json's equal_scouts override define + // company 8 as assault_squad-only and company 9 as devastator_squad-only - neither + // lists a scout_squad. The previous `_lw && equal_scouts` branches incorrectly + // handed these companies scout marines that the LW override's templates have no + // scout_squad to absorb, producing stray squadless scouts (the "all companies get + // scouts" symptom). Scouts for equal_scouts + LW must stay confined to companies + // 2-5, matching the override's default_squads scout_squad proportion. if (real(_coy.coy) == 8) { _coy.tacticals = 0; _coy.assaults = _coy.total; @@ -2432,7 +2460,8 @@ function scr_initialize_custom() { } if (real(_coy.coy) == 10 && equal_scouts) { _coy.tacticals = _moved_scouts; - _coy.scouts = _coy.scouts - _coy.tacticals; + // _coy.scouts is already the correct bank remainder after per-company + // deductions above — do not subtract tacticals again or it double-counts. } } diff --git a/scripts/scr_management/scr_management.gml b/scripts/scr_management/scr_management.gml index 4a5befcff6..55c3a20747 100644 --- a/scripts/scr_management/scr_management.gml +++ b/scripts/scr_management/scr_management.gml @@ -6,6 +6,11 @@ function scr_management(argument0) { var chapter_name = global.chapter_name; if (argument0 == 1) { + // Ensure TTRPG display data is up to date before drawing the overview + with (obj_ini) { + sort_all_companies(); + } + with (obj_managment_panel) { instance_destroy(); } @@ -85,36 +90,29 @@ function scr_management(argument0) { pane.header = 1; pane.title = t; - var _company_group = collect_company(company).index_roles(); - - pane.line = array_join(pane.line, _company_group.create_plural_strings_array()); + // Populate company panel — same pattern as the HQ specialty panels above + var _co_units = collect_company(company).index_roles(); + pane.line = array_join(pane.line, _co_units.create_plural_strings_array()); - var num = array_create(5, 0); - var nam = [ - "Land Raider", - "Predator", - "Rhino", - "Land Speeder", - "Whirlwind" - ]; - // Vehicles + // collect_company() only indexes TTRPG marines, so vehicles must be counted + // separately from obj_ini.veh_role and appended after the role strings. + var _veh_names = ["Land Raider", "Predator", "Rhino", "Land Speeder", "Whirlwind"]; + var _veh_count = array_create(array_length(_veh_names), 0); for (var i = 0; i < array_length(obj_ini.veh_role[company]); i++) { - for (var s = 0; s < array_length(nam); s++) { - if (obj_ini.veh_role[company][i] == nam[s]) { - num[s]++; + for (var s = 0; s < array_length(_veh_names); s++) { + if (obj_ini.veh_role[company][i] == _veh_names[s]) { + _veh_count[s]++; } } } - - for (var d = 0; d < 5; d++) { - if (num[d] > 0) { - if (d == 1) { - array_push(pane.line, {str1: nam[d], bold: true, italic: false}); - } else { - array_push(pane.line, nam[d], string_plural_count(nam[d], num[d], false)); - } + for (var d = 0; d < array_length(_veh_names); d++) { + if (_veh_count[d] == 1) { + array_push(pane.line, {str1: _veh_names[d], bold: true, italic: false}); + } else if (_veh_count[d] > 1) { + array_push(pane.line, string_plural_count(_veh_names[d], _veh_count[d], false)); } } + xx += 156; } } diff --git a/scripts/scr_marine_struct/scr_marine_struct.gml b/scripts/scr_marine_struct/scr_marine_struct.gml index b09d0696a3..ae2324da63 100644 --- a/scripts/scr_marine_struct/scr_marine_struct.gml +++ b/scripts/scr_marine_struct/scr_marine_struct.gml @@ -440,16 +440,18 @@ function TTRPG_stats(faction, comp, mar, class = "marine", other_spawn_data = {} stat_boosts({strength: 4, constitution: 4, dexterity: 4}); //will decide on if these are needed } } - if (!is_specialist(role())) { - //logs changes too and from specialist status - if (is_specialist(new_role)) { - obj_controller.marines -= 1; - obj_controller.command += 1; - } - } else { - if (!is_specialist(new_role)) { - obj_controller.marines += 1; - obj_controller.command -= 1; + if (instance_exists(obj_controller)) { + if (!is_specialist(role())) { + //logs changes too and from specialist status + if (is_specialist(new_role)) { + obj_controller.marines -= 1; + obj_controller.command += 1; + } + } else { + if (!is_specialist(new_role)) { + obj_controller.marines += 1; + obj_controller.command -= 1; + } } } } @@ -1662,6 +1664,25 @@ function TTRPG_stats(faction, comp, mar, class = "marine", other_spawn_data = {} return wrath; }; + static speed_force = function(_ranged = false) { + if (_ranged) { + // Attack Bike: scales off the "sidecar's" ranged weapon - single firepower profile, no melee option. + var _attack = ranged_damage_data[0]; + var _weapon = ranged_damage_data[3]; + return new EquipmentStruct({attack: _attack * 2, name: "Speed Force (Ranged)", range: 14, ammo: 12, spli: _weapon.spli, arp: _weapon.arp}, "weapon"); + } + // Standard Bike: scales off melee, dominant melee (M) profile while engaged in front. + var _melee_attack = melee_damage_data[0]; + var _melee_weapon = melee_damage_data[3]; + + var speedf = new EquipmentStruct({attack: _melee_attack * 2, name: "Speed Force", range: 14, ammo: 12, spli: _melee_weapon.spli, arp: _melee_weapon.arp}, "weapon"); + + var speedf_melee = new EquipmentStruct({attack: _melee_attack * 4, name: "Speed Force(M)", range: 1, ammo: 16, spli: _melee_weapon.spli, arp: _melee_weapon.arp}, "weapon"); + + speedf.second_profiles = [speedf_melee]; + + return speedf; + }; static armour_calc = function() { armour_rating = 0; diff --git a/scripts/scr_popup_functions/scr_popup_functions.gml b/scripts/scr_popup_functions/scr_popup_functions.gml index 6fa2266ffc..309e5ee264 100644 --- a/scripts/scr_popup_functions/scr_popup_functions.gml +++ b/scripts/scr_popup_functions/scr_popup_functions.gml @@ -303,7 +303,7 @@ function calculate_equipment_needs() { req_wep2 = "Company Standard"; req_wep2_num = units; } else { - for (var i = 2; i < 20; i++) { + for (var i = 2; i < 21; i++) { if (obj_ini.role[100][i] == rall) { req_armour = obj_ini.armour[100][i]; req_armour_num = units; diff --git a/scripts/scr_promote/scr_promote.gml b/scripts/scr_promote/scr_promote.gml index 5c050be414..45d05372db 100644 --- a/scripts/scr_promote/scr_promote.gml +++ b/scripts/scr_promote/scr_promote.gml @@ -45,7 +45,9 @@ function setup_promotion_popup() { variable_struct_set(role_squad_equivilances, obj_ini.role[100][8], "tactical_squad"); variable_struct_set(role_squad_equivilances, obj_ini.role[100][9], "devastator_squad"); variable_struct_set(role_squad_equivilances, obj_ini.role[100][10], "assault_squad"); + variable_struct_set(role_squad_equivilances, obj_ini.role[100][13], "bike_squad"); variable_struct_set(role_squad_equivilances, obj_ini.role[100][12], "scout_squad"); + variable_struct_set(role_squad_equivilances, obj_ini.role[100][20], "attack_bike_squad"); variable_struct_set(role_squad_equivilances, obj_ini.role[100][3], "veteran_squad"); variable_struct_set(role_squad_equivilances, obj_ini.role[100][4], "terminator_squad"); @@ -120,6 +122,14 @@ function setup_promotion_popup() { } // End that [i] } // End repeat + if (struct_exists(role_squad_equivilances, role_name[target_role])) { + var _grp = collect_company(target_comp); + var _result = [true]; + while (_result[0]) { + _result = _grp.create_squad(role_squad_equivilances[$ role_name[target_role]]); + } + } + with (obj_controller) { scr_management(1); } diff --git a/scripts/scr_roster/scr_roster.gml b/scripts/scr_roster/scr_roster.gml index 881512e1fb..47623a2641 100644 --- a/scripts/scr_roster/scr_roster.gml +++ b/scripts/scr_roster/scr_roster.gml @@ -478,11 +478,15 @@ function PurgeButton(purge_image, xx, yy, purge_type) constructor { }; } +/// @desc Resolves the chosen formation (formation_set, e.g. Attack/Defend/Raid) into concrete +/// per-role battle columns on obj_controller, which add_unit_to_battle/add_vehicle_to_battle +/// then use to place individual units. function setup_battle_formations() { // Formation here var new_combat = obj_ncombat; obj_controller.bat_devastator_column = obj_controller.bat_deva_for[new_combat.formation_set]; obj_controller.bat_assault_column = obj_controller.bat_assa_for[new_combat.formation_set]; + obj_controller.bat_bike_column = obj_controller.bat_bike_for[new_combat.formation_set]; obj_controller.bat_tactical_column = obj_controller.bat_tact_for[new_combat.formation_set]; obj_controller.bat_veteran_column = obj_controller.bat_vete_for[new_combat.formation_set]; obj_controller.bat_hire_column = obj_controller.bat_hire_for[new_combat.formation_set]; @@ -500,6 +504,17 @@ function setup_battle_formations() { obj_controller.bat_scout_column = obj_controller.bat_scou_for[new_combat.formation_set]; } +/// @desc Determines which formation column (block) a single marine is placed into for the +/// current battle and adds them to the nearest obj_pnunit at that column. +/// Resolution order: 1) the unit's individual role (sergeant variants, Scout, Tactical, +/// Veteran, Devastator, Assault, Librarian/Techmarine specialists, Honour Guard, +/// Dreadnought, Terminator, Chapter Master/heads, Death Company), then 2) if the unit +/// belongs to a squad, the squad's formation_place overrides the role-based column +/// (assault/veteran/tactical/devastator/terminator/command/scout), and finally +/// 3) anything still unresolved (col == 0) defaults to the hireling column. +/// @param {Id.Instance} unit The marine instance being added to the battle. +/// @param {Bool} meeting Whether this is a meeting/temp roster (uses obj_temp_meeting lookups) rather than a normal company roster. +/// @param {Bool} is_local Whether this unit belongs to the local (player-controlled) side. function add_unit_to_battle(unit, meeting, is_local) { var new_combat = obj_ncombat; var man_size = 1; @@ -685,6 +700,12 @@ function add_unit_to_battle(unit, meeting, is_local) { case "command": col = obj_controller.bat_command_column; break; + case "scout": + col = obj_controller.bat_scout_column; + break; + case "biker": + col = obj_controller.bat_bike_column; + break; } } if (col == 0) { diff --git a/scripts/scr_squads/scr_squads.gml b/scripts/scr_squads/scr_squads.gml index 7cabad2454..75852289ac 100644 --- a/scripts/scr_squads/scr_squads.gml +++ b/scripts/scr_squads/scr_squads.gml @@ -45,15 +45,66 @@ function SquadEquipmentSorting(squad, from_armoury = true, to_armoury = true) co squad_type = target_squad.type; squad_unit_types = squad.find_squad_unit_types(); full_squad_data = obj_ini.squad_types[$ squad_type]; + role_key_to_actual = {}; + for (var _i = 0; _i < array_length(squad_unit_types); _i++) { + var _key = squad_unit_types[_i]; + var _def = full_squad_data[$ _key]; + role_key_to_actual[$ _key] = struct_exists(_def, "role") ? _def.role : _key; + } unit_role = ""; members_UnitGroup = squad.get_members(true); members_UnitGroup.shuffle(); optional_load = undefined; + optional_fill_counts = {}; // flat struct: "slot_groupIndex" -> filled count required_load = undefined; target_squad.update_fulfilment(); static sort = function() { + // For each role, clear every loadout slot that role actively manages + // (required + option + random_pick). Slots not mentioned in a role's own loadout + // are left untouched — e.g. a role that only defines armour won't have wep1/wep2 cleared. + // random_pick can manage mobi/gear/armour as well as weapons, so all managed slots are + // cleared before re-equipping to avoid stale equipment persisting after a reroll. + for (var _ri = 0; _ri < array_length(squad_unit_types); _ri++) { + var _role_key = squad_unit_types[_ri]; + var _role_data = full_squad_data[$ _role_key]; + if (!struct_exists(_role_data, "loadout")) continue; + + var _managed_slots = {}; + var _ld = _role_data.loadout; + if (struct_exists(_ld, "required")) { + var _slots = struct_get_names(_ld.required); + for (var _s = 0; _s < array_length(_slots); _s++) + _managed_slots[$ _slots[_s]] = true; + } + if (struct_exists(_ld, "option")) { + var _slots = struct_get_names(_ld.option); + for (var _s = 0; _s < array_length(_slots); _s++) + _managed_slots[$ _slots[_s]] = true; + } + if (struct_exists(_ld, "random_pick")) { + var _picks = _ld.random_pick; + for (var _p = 0; _p < array_length(_picks); _p++) { + var _slots = struct_get_names(_picks[_p]); + for (var _s = 0; _s < array_length(_slots); _s++) + _managed_slots[$ _slots[_s]] = true; + } + } + + var _managed_slot_names = struct_get_names(_managed_slots); + var _role_members = members_UnitGroup.get_from({roles: [_role_key, role_key_to_actual[$ _role_key]]}); + while (_role_members.number() > 0) { + var _u = _role_members.pop(); + for (var _s = 0; _s < array_length(_managed_slot_names); _s++) { + var _clear = {}; + _clear[$ _managed_slot_names[_s]] = ""; + // Clear via the squad's own from/to_armoury so items don't get destroyed + _u.alter_equipment(_clear, from_armoury, to_armoury); + } + } + } + for (var i = 0; i < array_length(squad_unit_types); i++) { unit_role = squad_unit_types[i]; role_squad_loadout(); @@ -69,18 +120,24 @@ function SquadEquipmentSorting(squad, from_armoury = true, to_armoury = true) co "mobi" ]; - static structure_role_optional_loadout = function(optional_data) { - optional_load = variable_clone(optional_data); //create a fulfillment object for optional loadouts + static structure_role_optional_loadout = function(optional_data){ - var _optional_loadout_slots = struct_get_names(optional_load); + // Use the original data directly — no clone needed since optional_load is now read-only + // (all mutable state lives in optional_fill_counts). variable_clone can incorrectly + // flatten doubly-nested arrays in this GML version, corrupting the group structure. + optional_load = optional_data; + // Initialise fill-count tracking in a flat struct (struct field writes are always + // in-place in GML — no copy-on-write issues unlike nested array element writes) + optional_fill_counts = {}; + var _optional_loadout_slots = struct_get_names(optional_load); for (var slot = 0; slot < array_length(_optional_loadout_slots); slot++) { var _load_out_slot = _optional_loadout_slots[slot]; for (var i = 0; i < array_length(optional_load[$ _load_out_slot]); i++) { - array_insert(optional_load[$ _load_out_slot][i], 2, 0); + optional_fill_counts[$ _load_out_slot + "_" + string(i)] = 0; } } - }; + } static structure_role_required_loadout = function(required_data) { //find out if the _unit type for the squad has required equipment thresholds @@ -117,13 +174,13 @@ function SquadEquipmentSorting(squad, from_armoury = true, to_armoury = true) co var _optional_groups = optional_load[$ current_load_slot]; for (var i = 0; i < array_length(_optional_groups); i++) { - var _optional_load_data = _optional_groups[i]; - var _optionals_filled = _optional_load_data[2]; - var _optionals_max_allowed = _optional_load_data[1]; - var _optionals_equipment = _optional_load_data[0]; + var _count_key = current_load_slot + "_" + string(i); + var _optionals_filled = optional_fill_counts[$ _count_key]; // read from flat struct + var _optionals_max_allowed = _optional_groups[i][1]; + var _optionals_equipment = _optional_groups[i][0]; var _item_to_add; if (_optionals_filled < _optionals_max_allowed) { - var _is_equipment_set = array_length(_optional_load_data) > 3; + var _is_equipment_set = array_length(_optional_groups[i]) > 2; if (is_array(_optionals_equipment)) { //if the array items are varibale e.g a struct @@ -155,9 +212,10 @@ function SquadEquipmentSorting(squad, from_armoury = true, to_armoury = true) co var _opt_load_out = {}; _opt_load_out[$ current_load_slot] = _item_to_add; _unit.alter_equipment(_opt_load_out, from_armoury, to_armoury); - _optional_load_data[1]++; + // Struct field write — guaranteed in-place, no copy-on-write in GML + optional_fill_counts[$ _count_key]++; if (_is_equipment_set) { - var _equip_set_data = _optional_load_data[3]; + var _equip_set_data = _optional_groups[i][2]; if (is_struct(_equip_set_data)) { _unit.alter_equipment(_equip_set_data, from_armoury, to_armoury); array_push(ignore_units, _unit.uid); @@ -168,8 +226,9 @@ function SquadEquipmentSorting(squad, from_armoury = true, to_armoury = true) co } }; - static equip_loudouts_specific_equip_slot = function() { - var _members_with_role = members_UnitGroup.get_from({role: unit_role}); + static equip_loudouts_specific_equip_slot = function(){ + var _actual_role = role_key_to_actual[$ unit_role]; + var _members_with_role = members_UnitGroup.get_from({roles: [unit_role, _actual_role]}); if (!struct_exists(current_unit_squad_data, "loadout")) { return; } @@ -177,13 +236,11 @@ function SquadEquipmentSorting(squad, from_armoury = true, to_armoury = true) co var _loudouts = current_unit_squad_data[$ "loadout"]; while (_members_with_role.number() > 0) { _unit = _members_with_role.pop(); - if (array_contains(ignore_units, _unit.uid)) { - continue; - } - if (_unit.role() != unit_role) { + if (_unit.role() != unit_role && _unit.role() != _actual_role) { continue; } + // Required loadout is always applied — ignore_units only gates optional extras if (required_load != undefined && struct_exists(required_load, current_load_slot)) { var _needed_required = equip_required_for_role(_unit); if (_needed_required) { @@ -191,12 +248,49 @@ function SquadEquipmentSorting(squad, from_armoury = true, to_armoury = true) co } } + // Optional loadout respects ignore_units (units that already got a full equipment set) + if (array_contains(ignore_units, _unit.uid)) { + continue; + } + if (optional_load != undefined && struct_exists(optional_load, current_load_slot)) { equip_optional_for_role(_unit); } } }; + // Picks ONE entry (loadout category) at random, then resolves each slot: + // string values are used directly; array values get one item picked at random. + // Any slot omitted from an entry is left unchanged on the unit. + // + // JSON example: + // "random_pick": [ + // { "wep1": ["Sword","Axe","Mace"], "wep2": ["Pistol","Plasma","Volkite"] }, + // { "wep1": "Lightning Claw", "wep2": "Lightning Claw" } + // ] + static equip_random_pick_for_role = function(pick_options) { + var _actual_role = role_key_to_actual[$ unit_role]; + var _members_with_role = members_UnitGroup.get_from({roles: [unit_role, _actual_role]}); + while (_members_with_role.number() > 0) { + var _unit = _members_with_role.pop(); + if (array_contains(ignore_units, _unit.uid)) continue; + if (_unit.role() != unit_role && _unit.role() != _actual_role) continue; + + // Pick a random loadout category + var _chosen = pick_options[irandom(array_length(pick_options) - 1)]; + + // Resolve slots: array values → random element; strings → used as-is + var _resolved = {}; + var _slots = struct_get_names(_chosen); + for (var _s = 0; _s < array_length(_slots); _s++) { + var _slot = _slots[_s]; + var _value = _chosen[$ _slot]; + _resolved[$ _slot] = is_array(_value) ? array_random_element(_value) : _value; + } + _unit.alter_equipment(_resolved, from_armoury, to_armoury); + } + }; + static role_squad_loadout = function() { required_load = undefined; optional_load = undefined; @@ -222,6 +316,11 @@ function SquadEquipmentSorting(squad, from_armoury = true, to_armoury = true) co current_load_slot = load_out_areas[i]; equip_loudouts_specific_equip_slot(); } + + // random_pick runs after required/option — picks one complete loadout at random + if (struct_exists(_loudout_data, "random_pick")) { + equip_random_pick_for_role(_loudout_data[$ "random_pick"]); + } }; } @@ -279,6 +378,11 @@ function UnitSquad(squad_type = undefined, company = 0) constructor { static change_type = function(new_type) { type = new_type; + if (is_array(type)) { + show_debug_message($"[PROBE] change_type got ARRAY type (len {array_length(type)}): {type}"); + } else if (!struct_exists(obj_ini.squad_types, type)) { + show_debug_message($"[PROBE] change_type unknown squad type: \"{type}\""); + } add_type_data(obj_ini.squad_types[$ type].type_data); }; @@ -302,6 +406,16 @@ function UnitSquad(squad_type = undefined, company = 0) constructor { } squad_fulfilment[$ _wanted_unit_role] = 0; //create a fulfilment structure to log members of squad } + //Mapping for role groups in alternative source; + squad_role_alternatives = {}; + for (var i =0; i < array_length(squad_unit_types); i++) { + var _role_name = squad_unit_types[i]; + var _role_def = fill_squad[$ _role_name]; + //alternative source presence check + if (struct_exists(_role_def, "alternative_roles")) { + squad_role_alternatives[$ _role_name] = _role_def.alternative_roles; + } + } return squad_unit_types; }; @@ -320,10 +434,10 @@ function UnitSquad(squad_type = undefined, company = 0) constructor { }; // for creating a new sergeant from existing squad members - static new_sergeant = function(veteran = false) { + static new_sergeant = function(veteran = false, target_role = undefined) { var exp_unit = ""; var _unit; - var highest_exp = 0; + var highest_exp = -1; var member_length = array_length(members); for (var i = 0; i < member_length; i++) { _unit = fetch_unit(members[i]); @@ -333,7 +447,7 @@ function UnitSquad(squad_type = undefined, company = 0) constructor { i--; continue; } - if (_unit.experience > highest_exp) { + if (exp_unit == "" || _unit.experience > highest_exp) { highest_exp = _unit.experience; exp_unit = _unit; } @@ -341,7 +455,9 @@ function UnitSquad(squad_type = undefined, company = 0) constructor { if ((array_length(members) > 0) && is_struct(exp_unit)) { if (exp_unit.name() != "") { var new_role; - if (veteran == true) { + if (target_role != undefined) { + new_role = target_role; + } else if (veteran == true) { new_role = obj_ini.role[100][19]; } else { new_role = obj_ini.role[100][18]; @@ -374,6 +490,8 @@ function UnitSquad(squad_type = undefined, company = 0) constructor { var squad_unit_types = struct_get_names(fill_squad); //find out what type of units squad consists of var unit_type_count = array_length(squad_unit_types); + // build actual_role → json_key map to handle slots with a "role" override + var _actual_to_key = {}; for (var i = unit_type_count - 1; i >= 0; i--) { var _wanted_unit_role = squad_unit_types[i]; if (_wanted_unit_role == "type_data") { @@ -381,6 +499,9 @@ function UnitSquad(squad_type = undefined, company = 0) constructor { continue; } squad_fulfilment[$ _wanted_unit_role] = 0; //create a fulfilment structure to log members of squad + var _role_def = fill_squad[$ _wanted_unit_role]; + var _mapped = struct_exists(_role_def, "role") ? _role_def.role : _wanted_unit_role; + _actual_to_key[$ _mapped] = _wanted_unit_role; } var member_length = array_length(members); for (var i = member_length - 1; i >= 0; i--) { @@ -390,10 +511,13 @@ function UnitSquad(squad_type = undefined, company = 0) constructor { array_delete(members, i, 1); continue; } - if (struct_exists(squad_fulfilment, _unit.role())) { - squad_fulfilment[$ _unit.role()]++; + // map actual role to json key so role-overridden slots are counted correctly + var _unit_role = _unit.role(); + var _slot_key = struct_exists(_actual_to_key, _unit_role) ? _actual_to_key[$ _unit_role] : _unit_role; + if (struct_exists(squad_fulfilment, _slot_key)) { + squad_fulfilment[$ _slot_key]++; } else { - squad_fulfilment[$ _unit.role()] = 1; + squad_fulfilment[$ _slot_key] = 1; } } fulfilled = true; @@ -408,8 +532,33 @@ function UnitSquad(squad_type = undefined, company = 0) constructor { var _min_role_allowed = fill_squad[$ _wanted_unit_role][$ "min"]; if (fill_from != undefined) { - while (fill_from.has_role(_wanted_unit_role) && _squad_role_current < _max_role_count) { - var _new_member = fill_from.pop_role_member(_wanted_unit_role); + var _role_def = fill_squad[$ _wanted_unit_role]; + var _fill_role = struct_exists(_role_def, "role") + ? _role_def.role : _wanted_unit_role; + // Also try the JSON key itself as a source role (base role before squad rename) + var _fill_role_base = _wanted_unit_role; + // Build the ordered list of acceptable source roles: the mapped role, the JSON + // key, then any alternative_roles. create_squad considers alternative_roles when + // fetching/matching marines, so refill must too — otherwise valid replacement + // marines (e.g. bikers for a bike_squad) are ignored when scr_company_order + // updates existing squads. + var _fill_roles = [_fill_role, _fill_role_base]; + if (struct_exists(_role_def, "alternative_roles")) { + var _alts = _role_def.alternative_roles; + for (var _ai = 0; _ai < array_length(_alts); _ai++) { + array_push(_fill_roles, _alts[_ai]); + } + } + while (_squad_role_current < _max_role_count) { + var _pick_role = ""; + for (var _fri = 0; _fri < array_length(_fill_roles); _fri++) { + if (fill_from.has_role(_fill_roles[_fri])) { + _pick_role = _fill_roles[_fri]; + break; + } + } + if (_pick_role == "") break; + var _new_member = fill_from.pop_role_member(_pick_role); add_member(_new_member.company, _new_member.marine_number); squad_fulfilment[$ _wanted_unit_role]++; _squad_role_current = squad_fulfilment[$ _wanted_unit_role]; @@ -427,19 +576,23 @@ function UnitSquad(squad_type = undefined, company = 0) constructor { required[$ _wanted_unit_role] = _min_role_allowed - _squad_role_current; } } - var _sarge = obj_ini.role[100][eROLE.SERGEANT]; - if (struct_exists(required, _sarge)) { - if (required[$ _sarge] > 0) { - new_sergeant(); - required[$ _sarge]--; - } - } - //find a new veteran sergeant - var _vet_sarge = obj_ini.role[100][eROLE.VETERANSERGEANT]; - if (struct_exists(required, _vet_sarge)) { - if (required[$ _vet_sarge] > 0) { - new_sergeant(true); - required[$ _vet_sarge]--; + var _default_sarge = obj_ini.role[100][eROLE.SERGEANT]; + var _default_vet_sarge = obj_ini.role[100][eROLE.VETERANSERGEANT]; + var _required_keys = struct_get_names(required); + for (var _ri = 0; _ri < array_length(_required_keys); _ri++) { + var _req_key = _required_keys[_ri]; + if (required[$ _req_key] <= 0) continue; + var _role_def = fill_squad[$ _req_key]; + if (_role_def == undefined) continue; + var _actual_role = struct_exists(_role_def, "role") ? _role_def.role : _req_key; + if (_req_key == _default_sarge || _actual_role == _default_sarge + || string_lower(_req_key) == "sergeant") { + new_sergeant(false, _actual_role); + required[$ _req_key]--; + } else if (_req_key == _default_vet_sarge || _actual_role == _default_vet_sarge + || string_lower(_req_key) == "veteran sergeant") { + new_sergeant(true, _actual_role); + required[$ _req_key]--; } } }; @@ -705,17 +858,115 @@ function UnitSquad(squad_type = undefined, company = 0) constructor { }; } -// creates the origional distribution of squads accross the chapter -// lots of room for customisation of different chapters here +/// @function resolve_company_arrangement +/// @description Resolves the squad template for a specific company number from a loaded +/// arrangement struct. Explicit per-company entries take priority; if none matches, +/// the arrangement's default_squads array is wrapped and returned. Returns undefined +/// if the arrangement contains neither a matching company entry nor a default_squads. +/// @param {Struct} arrangement A parsed squad-arrangement struct (e.g. from lightning_warriors.json). +/// Expected fields: optional {Array} companies, optional {Array} default_squads. +/// @param {Real} company_number The 1-based company index to resolve a template for. +/// @return {Struct|Undefined} A company template struct with fields {Real} company and {Array} squads, +/// or undefined if no template can be resolved. +function resolve_company_arrangement(arrangement, company_number) { + if (struct_exists(arrangement, "companies")) { + var _companies = arrangement.companies; + for (var i = 0; i < array_length(_companies); i++) { + if (_companies[i].company == company_number) { + return _companies[i]; + } + } + } + if (struct_exists(arrangement, "default_squads")) { + return { company: company_number, squads: arrangement.default_squads }; + } + return undefined; +} + +/// @function apply_squad_distribution_override +/// @description Merges a distribution_overrides entry into a loaded arrangement struct in-place. +/// Two operations are performed: +/// 1. If the override defines default_squads, a deep clone of that array replaces +/// arrangement.default_squads. Cloning keeps the two references independent so +/// any future in-place mutation of one cannot corrupt the other. +/// 2. If the override defines a companies array, each entry is upserted into +/// arrangement.companies — matching on the company number field, replacing an +/// existing entry if found or appending if not. +/// Squad order within default_squads and company squads arrays matters: squads that +/// only accept their own marine role (e.g. devastator_squad, assault_squad) must be +/// listed before squads that use alternative_roles (e.g. bike_squad, attack_bike_squad) +/// so that specific squads claim their marines before greedy squads can absorb them. +/// @param {Struct} arrangement The live chapter_squad_arrangement struct to mutate. +/// @param {Struct} override One distribution_overrides child struct from the same JSON +/// (e.g. arrangement.distribution_overrides.equal_specialists). +/// Expected optional fields: {Array} default_squads, {Array} companies. +/// @return {Undefined} +function apply_squad_distribution_override(arrangement, override) { + if (struct_exists(override, "default_squads")) { + // Deep-clone so arrangement.default_squads is independent of the override sub-struct, + // preventing any future in-place mutation of the array from corrupting both references. + var _src = override.default_squads; + var _clone = array_create(array_length(_src)); + for (var _i = 0; _i < array_length(_src); _i++) { + _clone[_i] = variable_clone(_src[_i]); + } + arrangement.default_squads = _clone; + } + if (struct_exists(override, "companies")) { + if (!struct_exists(arrangement, "companies")) { + arrangement.companies = []; + } + var _ovr_companies = override.companies; + for (var oi = 0; oi < array_length(_ovr_companies); oi++) { + var _ovr = _ovr_companies[oi]; + var _found = false; + for (var ai = 0; ai < array_length(arrangement.companies); ai++) { + if (arrangement.companies[ai].company == _ovr.company) { + arrangement.companies[ai] = _ovr; + _found = true; + break; + } + } + if (!_found) { + array_push(arrangement.companies, _ovr); + } + } + } +} +/// @function game_start_squads +/// @description Populates obj_ini.squads at game start by iterating every company and calling +/// organise_by_template with the resolved squad template for that company. +/// Templates are resolved from obj_ini.chapter_squad_arrangement via +/// resolve_company_arrangement; companies with no resolvable template are skipped. +/// Must be called after obj_ini.chapter_squad_arrangement has been fully built +/// (including any apply_squad_distribution_override calls) and after all marine +/// individuals have been created by the count-based initialisation pass. +/// @return {Undefined} function get_compay_squad_arrangement(company){ - var _comp_datas = obj_ini.chapter_squad_arrangement.companies; + var _arrangement = obj_ini.chapter_squad_arrangement; + if (!struct_exists(_arrangement, "companies")) { + _arrangement.companies = []; + } + var _comp_datas = _arrangement.companies; for (var i = 0; i < array_length(_comp_datas); i++) { if (_comp_datas[i].company == company){ return _comp_datas[i]; } } + // No explicit entry: this company currently inherits default_squads. Promote it to its own + // explicit entry, deep-cloning default_squads so the editor's in-place edits can't mutate the + // shared array every other defaulted company also points at. Registering it persists the edits + // and lets resolve_company_arrangement pick this company up by its own entry from now on. + var _src = struct_exists(_arrangement, "default_squads") ? _arrangement.default_squads : []; + var _squads = array_create(array_length(_src)); + for (var _i = 0; _i < array_length(_src); _i++) { + _squads[_i] = variable_clone(_src[_i]); + } + var _entry = { company: company, squads: _squads }; + array_push(_comp_datas, _entry); + return _entry; } function ProportionalSquadEditor(data) constructor { @@ -1124,11 +1375,11 @@ function SquadArrangementEditor(company) constructor { function game_start_squads() { obj_ini.squads = {}; - if (struct_exists(chapter_squad_arrangement, "companies")) { - var _comp_datas = obj_ini.chapter_squad_arrangement.companies; - for (var i = 0; i < array_length(_comp_datas); i++) { - var _company = collect_company(_comp_datas[i].company); - _company.organise_by_template(_comp_datas[i]); + for (var co = 1; co <= obj_ini.companies; co++) { + var _data = resolve_company_arrangement(obj_ini.chapter_squad_arrangement, co); + if (_data != undefined) { + var _company = collect_company(co); + _company.organise_by_template(_data); } } } diff --git a/scripts/scr_ui_formation_bars/scr_ui_formation_bars.gml b/scripts/scr_ui_formation_bars/scr_ui_formation_bars.gml index 36bcf1ad74..6728c8754b 100644 --- a/scripts/scr_ui_formation_bars/scr_ui_formation_bars.gml +++ b/scripts/scr_ui_formation_bars/scr_ui_formation_bars.gml @@ -31,6 +31,7 @@ function scr_ui_formation_bars() { { unit_id: 11, bat_for: bat_drea_for, size: 2, image_index: 11, unit_type: "Dread", tooltip: "Dreadnoughts", tooltip2: "Dreadnoughts are the most durable and tough marines within your chapter. They are best suited for the front lines." }, { unit_id: 12, bat_for: bat_hire_for, size: 1, image_index: 7, unit_type: "???", tooltip: "Hirelings", tooltip2: "Any and all units that you recieve from other factions are placed within this block." }, { unit_id: 16, bat_for: bat_landspee_for, size: 2, image_index: 14, unit_type: "Land Speeder", tooltip: "Land Speeders", tooltip2: "Land Speeders are incredibly agile attack vehicles that offer a light highly mobile heavy weapon platform." }, + { unit_id: 18, bat_for: bat_bike_for, size: 2, image_index: 14, unit_type: "Biker", tooltip: "Bikers", tooltip2: "Bikers are the swift deathbringers of the Astartes Chapters. Descending upon a foe with speed impossible to follow by mortal means, they decimate enemies in close range by a powerful assortment of melee weapons or heavy ranged weapons on their Attack Bikes." }, ]; var _attack_only_options = [ { unit_id: 13, bat_for: bat_rhin_for, size: 4, image_index: 12, unit_type: "Rhino", tooltip: "Rhinos", tooltip2: "Rhinos offer protection for units behind them but are not well armoured and lacking in firepower." }, @@ -48,7 +49,7 @@ function scr_ui_formation_bars() { temp[ui_formations_data.te] = 0; temp[ui_formations_data.te + 100] = 0; - for (var unit_id = 0; unit_id <= 17; unit_id++) { + for (var unit_id = 0; unit_id <= 18; unit_id++) { for (var _i = 0; _i < array_length(_bar_configs); _i++) { var _cfg = _bar_configs[_i]; @@ -74,6 +75,7 @@ function scr_ui_formation_bars() { if (temp[4800 + bar] > 10) { bat_deva_for[bar] = 1; bat_assa_for[bar] = 4; + bat_bike_for[bar] = 4; bat_tact_for[bar] = 2; bat_vete_for[bar] = 2; bat_hire_for[bar] = 3; diff --git a/scripts/scr_ui_settings/scr_ui_settings.gml b/scripts/scr_ui_settings/scr_ui_settings.gml index a4a06bb21c..988a01b4ae 100644 --- a/scripts/scr_ui_settings/scr_ui_settings.gml +++ b/scripts/scr_ui_settings/scr_ui_settings.gml @@ -66,6 +66,8 @@ function setup_ui_chapter_settings(){ eROLE.DEVASTATOR, eROLE.ASSAULT, eROLE.SCOUT, + eROLE.BIKER, + eROLE.ATTACK_BIKER, eROLE.SERGEANT, eROLE.VETERANSERGEANT, ]; From 47829d0f9c01038479172ab0e415067e51edf5f1 Mon Sep 17 00:00:00 2001 From: CptMacTavish2224 <95313759+CptMacTavish2224@users.noreply.github.com> Date: Sat, 4 Jul 2026 16:51:11 +0300 Subject: [PATCH 2/6] feat: BT loadout changes --- datafiles/main/chapters/1.JSON | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/datafiles/main/chapters/1.JSON b/datafiles/main/chapters/1.JSON index 96f484826a..5774322a66 100644 --- a/datafiles/main/chapters/1.JSON +++ b/datafiles/main/chapters/1.JSON @@ -1722,7 +1722,7 @@ }, "option": { "wep2": [ - [["Flamer", "Grav-Gun", "Meltagun", "Plasma Gun", "Plasma Pistol"], 2] + [["Hand Flamer", "Grav-Pistol", "Infernus Pistol", "Plasma Pistol"], 2] ] } } @@ -1815,13 +1815,13 @@ "role": "Black Knight", "loadout": { "required": { - "wep1": ["Chainsword", 4], + "wep1": ["Power Sword", 4], "wep2": ["Bolt Pistol", 2], "mobi": ["Bike", 4] }, "option": { "wep2": [ - [["Flamer", "Grav-Gun", "Meltagun", "Plasma Gun", "Plasma Pistol"], 2] + [["Hand Flamer", "Grav-Pistol", "Infernus Pistol", "Plasma Pistol", "Volkite Serpenta"], 2] ] } } From 59fac694c7caf2d0cc229b025aacb6d2b102a3ca Mon Sep 17 00:00:00 2001 From: CptMacTavish2224 <95313759+CptMacTavish2224@users.noreply.github.com> Date: Sat, 4 Jul 2026 16:51:34 +0300 Subject: [PATCH 3/6] chore: Move id higher --- datafiles/main/chapters/34.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datafiles/main/chapters/34.json b/datafiles/main/chapters/34.json index 2dc7a424f8..b8d075f747 100644 --- a/datafiles/main/chapters/34.json +++ b/datafiles/main/chapters/34.json @@ -1,5 +1,6 @@ { "chapter": { + "id": 34, "name": "Flesh Tearers", "mutations": { "betchers": 0.0, @@ -38,7 +39,6 @@ "", "" ], - "id": 34, "chapter_master": { "ranged": 1.0, "specialty": 2.0, From df849e2d5d6d66bf68325c727dd9ef93e3ea25fd Mon Sep 17 00:00:00 2001 From: CptMacTavish2224 <95313759+CptMacTavish2224@users.noreply.github.com> Date: Wed, 1 Jul 2026 15:37:58 +0200 Subject: [PATCH 4/6] fix: bike formations reset --- scripts/scr_civil_roster/scr_civil_roster.gml | 1 + scripts/scr_ui_settings/scr_ui_settings.gml | 1 + 2 files changed, 2 insertions(+) diff --git a/scripts/scr_civil_roster/scr_civil_roster.gml b/scripts/scr_civil_roster/scr_civil_roster.gml index 9c3e538896..967cda5a6b 100644 --- a/scripts/scr_civil_roster/scr_civil_roster.gml +++ b/scripts/scr_civil_roster/scr_civil_roster.gml @@ -27,6 +27,7 @@ function scr_civil_roster(_unit_location, _target_location, _is_planet) { obj_controller.bat_devastator_column = obj_controller.bat_deva_for[new_combat.formation_set]; obj_controller.bat_assault_column = obj_controller.bat_assa_for[new_combat.formation_set]; + obj_controller.bat_bike_column = obj_controller.bat_bike_for[new_combat.formation_set]; obj_controller.bat_tactical_column = obj_controller.bat_tact_for[new_combat.formation_set]; obj_controller.bat_veteran_column = obj_controller.bat_vete_for[new_combat.formation_set]; obj_controller.bat_hire_column = obj_controller.bat_hire_for[new_combat.formation_set]; diff --git a/scripts/scr_ui_settings/scr_ui_settings.gml b/scripts/scr_ui_settings/scr_ui_settings.gml index 988a01b4ae..462e457b85 100644 --- a/scripts/scr_ui_settings/scr_ui_settings.gml +++ b/scripts/scr_ui_settings/scr_ui_settings.gml @@ -531,6 +531,7 @@ function scr_ui_settings() { bat_formation_type[formating] = 1; bat_deva_for[formating] = 1; bat_assa_for[formating] = 4; + bat_bike_for[formating] = 4; bat_tact_for[formating] = 2; bat_vete_for[formating] = 2; bat_hire_for[formating] = 3; From cc5d455ca222dea2202183b4aff7c474ae85f7a6 Mon Sep 17 00:00:00 2001 From: CptMacTavish2224 <95313759+CptMacTavish2224@users.noreply.github.com> Date: Wed, 1 Jul 2026 21:02:44 +0200 Subject: [PATCH 5/6] fix: broken armour setup --- datafiles/main/squads/base_squads.json | 1 - 1 file changed, 1 deletion(-) diff --git a/datafiles/main/squads/base_squads.json b/datafiles/main/squads/base_squads.json index a8c6442dee..cb6be7eed9 100644 --- a/datafiles/main/squads/base_squads.json +++ b/datafiles/main/squads/base_squads.json @@ -474,7 +474,6 @@ "alternative_roles": ["Assault","Devastator","Tactical"], "loadout": { "required": { - "armour": ["", 0], "wep1": ["", 0], "wep2": ["", 0], "mobi": ["Bike", 7] From ca1ab91b4f794c5f3ad347afed4d9edd5979fd12 Mon Sep 17 00:00:00 2001 From: CptMacTavish2224 <95313759+CptMacTavish2224@users.noreply.github.com> Date: Wed, 8 Jul 2026 18:58:09 +0200 Subject: [PATCH 6/6] fix: review fixes --- datafiles/main/chapters/1.JSON | 6 +- datafiles/main/chapters/template.JSON | 2 +- datafiles/main/squads/base_squads.json | 4 +- .../main/squads/company_squad_builds.json | 115 +++- datafiles/main/squads/equal_scouts.json | 120 +++- datafiles/main/squads/equal_specialists.json | 62 +- datafiles/main/squads/equal_spescout.json | 72 ++- datafiles/main/squads/lightning_warriors.json | 591 ++++++++++++++---- scripts/scr_roster/scr_roster.gml | 7 +- scripts/scr_squads/scr_squads.gml | 91 +-- 10 files changed, 808 insertions(+), 262 deletions(-) diff --git a/datafiles/main/chapters/1.JSON b/datafiles/main/chapters/1.JSON index 5774322a66..a4aba58ac6 100644 --- a/datafiles/main/chapters/1.JSON +++ b/datafiles/main/chapters/1.JSON @@ -1705,7 +1705,7 @@ }, "option": { "wep2": [ - [["Combiplasma", "Plasma Gun", "Meltagun"], 1] + [["Hand Flamer", "Grav-Pistol", "Infernus Pistol", "Plasma Pistol", "Volkite Serpenta"], 1] ] } } @@ -1771,6 +1771,7 @@ "role": "Ravenwing Ancient", "loadout": { "required": { + "wep2": ["Power Axe",1], "mobi": ["Bike", 1] } } @@ -1781,6 +1782,7 @@ "role": "Librarian", "loadout": { "required": { + "wep2": ["", 0], "mobi": ["Bike", 1] } } @@ -1802,7 +1804,7 @@ "loadout": { "required": { "wep1": ["Relic Blade", 1], - "wep2": ["Plasma Pistol", 1], + "wep2": ["", 0], "gear": ["Iron Halo", 1], "armour": ["Artificer Armour", 1], "mobi": ["Bike", 1] diff --git a/datafiles/main/chapters/template.JSON b/datafiles/main/chapters/template.JSON index 501d2fca10..17d46d21c4 100644 --- a/datafiles/main/chapters/template.JSON +++ b/datafiles/main/chapters/template.JSON @@ -390,7 +390,7 @@ "right_thorax":20, "right_trim":20, "company_marks":20, - "company_marks_loc":20 + "company_marks_loc":0 }, {//[8] Champion "weapon_primary":11, diff --git a/datafiles/main/squads/base_squads.json b/datafiles/main/squads/base_squads.json index cb6be7eed9..076374a477 100644 --- a/datafiles/main/squads/base_squads.json +++ b/datafiles/main/squads/base_squads.json @@ -93,7 +93,7 @@ } }, "Terminator": { - "max": 9, + "max": 4, "min": 2, "loadout": { "required": { @@ -145,7 +145,7 @@ } }, "Terminator": { - "max": 9, + "max": 4, "min": 2, "role": "Assault Terminator", "loadout": { diff --git a/datafiles/main/squads/company_squad_builds.json b/datafiles/main/squads/company_squad_builds.json index 17504439ff..e0501fd9e7 100644 --- a/datafiles/main/squads/company_squad_builds.json +++ b/datafiles/main/squads/company_squad_builds.json @@ -1,55 +1,126 @@ { - "default_squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "tactical_squad", "proportion": 6 }, - { "squad": "breacher_squad", "proportion": 0 }, - { "squad": "devastator_squad", "proportion": 2 }, - { "squad": "assault_squad", "proportion": 2 } - ], "companies": [ { "company": 1, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "terminator_squad", "proportion": 2 }, - { "squad": "terminator_assault_squad", "proportion": 2 }, - { "squad": "veteran_squad", "proportion": 1 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 2, + "squad": "terminator_squad" + }, + { + "proportion": 2, + "squad": "terminator_assault_squad" + }, + { + "proportion": 1, + "squad": "veteran_squad" + } ] }, { "company": 6, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "tactical_squad", "proportion": 1 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 1, + "squad": "tactical_squad" + } ] }, { "company": 7, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "tactical_squad", "proportion": 1 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 1, + "squad": "tactical_squad" + } ] }, { "company": 8, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "assault_squad", "proportion": 1 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 1, + "squad": "assault_squad" + } ] }, { "company": 9, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "devastator_squad", "proportion": 1 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 1, + "squad": "devastator_squad" + } ] }, { "company": 10, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "scout_squad", "proportion": 1 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 1, + "squad": "scout_squad" + } ] } + ], + "default_squads": [ + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 6, + "squad": "tactical_squad" + }, + { + "proportion": 0, + "squad": "breacher_squad" + }, + { + "proportion": 2, + "squad": "devastator_squad" + }, + { + "proportion": 2, + "squad": "assault_squad" + } ] -} +} \ No newline at end of file diff --git a/datafiles/main/squads/equal_scouts.json b/datafiles/main/squads/equal_scouts.json index ca00b88406..65ebb607da 100644 --- a/datafiles/main/squads/equal_scouts.json +++ b/datafiles/main/squads/equal_scouts.json @@ -1,56 +1,130 @@ { - "default_squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "tactical_squad", "proportion": 4 }, - { "squad": "devastator_squad", "proportion": 2 }, - { "squad": "assault_squad", "proportion": 2 }, - { "squad": "scout_squad", "proportion": 2 } - ], "companies": [ { "company": 1, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "terminator_squad", "proportion": 2 }, - { "squad": "terminator_assault_squad", "proportion": 2 }, - { "squad": "veteran_squad", "proportion": 1 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 2, + "squad": "terminator_squad" + }, + { + "proportion": 2, + "squad": "terminator_assault_squad" + }, + { + "proportion": 1, + "squad": "veteran_squad" + } ] }, { "company": 6, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "tactical_squad", "proportion": 1 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 1, + "squad": "tactical_squad" + } ] }, { "company": 7, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "tactical_squad", "proportion": 1 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 1, + "squad": "tactical_squad" + } ] }, { "company": 8, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "assault_squad", "proportion": 1 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 1, + "squad": "assault_squad" + } ] }, { "company": 9, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "devastator_squad", "proportion": 1 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 1, + "squad": "devastator_squad" + } ] }, { "company": 10, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "scout_squad", "proportion": 5 }, - { "squad": "tactical_squad", "proportion": 4 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 5, + "squad": "scout_squad" + }, + { + "proportion": 4, + "squad": "tactical_squad" + } ] } + ], + "default_squads": [ + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 4, + "squad": "tactical_squad" + }, + { + "proportion": 2, + "squad": "devastator_squad" + }, + { + "proportion": 2, + "squad": "assault_squad" + }, + { + "proportion": 2, + "squad": "scout_squad" + } ] -} +} \ No newline at end of file diff --git a/datafiles/main/squads/equal_specialists.json b/datafiles/main/squads/equal_specialists.json index 552880f543..abf21e358e 100644 --- a/datafiles/main/squads/equal_specialists.json +++ b/datafiles/main/squads/equal_specialists.json @@ -1,26 +1,62 @@ { - "default_squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "tactical_squad", "proportion": 6 }, - { "squad": "devastator_squad", "proportion": 2 }, - { "squad": "assault_squad", "proportion": 2 } - ], "companies": [ { "company": 1, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "terminator_squad", "proportion": 2 }, - { "squad": "terminator_assault_squad", "proportion": 2 }, - { "squad": "veteran_squad", "proportion": 1 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 2, + "squad": "terminator_squad" + }, + { + "proportion": 2, + "squad": "terminator_assault_squad" + }, + { + "proportion": 1, + "squad": "veteran_squad" + } ] }, { "company": 10, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "scout_squad", "proportion": 1 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 1, + "squad": "scout_squad" + } ] } + ], + "default_squads": [ + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 6, + "squad": "tactical_squad" + }, + { + "proportion": 2, + "squad": "devastator_squad" + }, + { + "proportion": 2, + "squad": "assault_squad" + } ] -} +} \ No newline at end of file diff --git a/datafiles/main/squads/equal_spescout.json b/datafiles/main/squads/equal_spescout.json index 5fd0acbf98..7ec5c963e5 100644 --- a/datafiles/main/squads/equal_spescout.json +++ b/datafiles/main/squads/equal_spescout.json @@ -1,28 +1,70 @@ { - "default_squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "tactical_squad", "proportion": 5 }, - { "squad": "devastator_squad", "proportion": 2 }, - { "squad": "assault_squad", "proportion": 2 }, - { "squad": "scout_squad", "proportion": 1 } - ], "companies": [ { "company": 1, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "terminator_squad", "proportion": 2 }, - { "squad": "terminator_assault_squad", "proportion": 2 }, - { "squad": "veteran_squad", "proportion": 1 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 2, + "squad": "terminator_squad" + }, + { + "proportion": 2, + "squad": "terminator_assault_squad" + }, + { + "proportion": 1, + "squad": "veteran_squad" + } ] }, { "company": 10, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "scout_squad", "proportion": 5 }, - { "squad": "tactical_squad", "proportion": 4 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 5, + "squad": "scout_squad" + }, + { + "proportion": 4, + "squad": "tactical_squad" + } ] } + ], + "default_squads": [ + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 5, + "squad": "tactical_squad" + }, + { + "proportion": 2, + "squad": "devastator_squad" + }, + { + "proportion": 2, + "squad": "assault_squad" + }, + { + "proportion": 1, + "squad": "scout_squad" + } ] -} +} \ No newline at end of file diff --git a/datafiles/main/squads/lightning_warriors.json b/datafiles/main/squads/lightning_warriors.json index 41f6993946..f33db3ebb5 100644 --- a/datafiles/main/squads/lightning_warriors.json +++ b/datafiles/main/squads/lightning_warriors.json @@ -1,229 +1,586 @@ { - "default_squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "tactical_squad", "proportion": 0 }, - { "squad": "bike_squad", "proportion": 9 }, - { "squad": "attack_bike_squad", "proportion": 6 }, - { "squad": "devastator_squad", "proportion": 0 }, - { "squad": "assault_squad", "proportion": 1 } - ], "companies": [ { "company": 1, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "terminator_squad", "proportion": 2 }, - { "squad": "terminator_assault_squad", "proportion": 2 }, - { "squad": "veteran_squad", "proportion": 1 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 2, + "squad": "terminator_squad" + }, + { + "proportion": 2, + "squad": "terminator_assault_squad" + }, + { + "proportion": 1, + "squad": "veteran_squad" + } ] }, { "company": 6, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count":1, "require": true }, - { "squad": "tactical_squad", "proportion": 1 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 1, + "squad": "tactical_squad" + } ] }, { "company": 7, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "tactical_squad", "proportion": 1 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 1, + "squad": "tactical_squad" + } ] }, { "company": 8, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "assault_squad", "proportion": 1 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 1, + "squad": "assault_squad" + } ] }, { "company": 9, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "devastator_squad", "proportion": 1 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 1, + "squad": "devastator_squad" + } ] }, { "company": 10, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "scout_squad", "proportion": 1 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 1, + "squad": "scout_squad" + } ] } ], + "default_squads": [ + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 0, + "squad": "tactical_squad" + }, + { + "proportion": 9, + "squad": "bike_squad" + }, + { + "proportion": 6, + "squad": "attack_bike_squad" + }, + { + "proportion": 0, + "squad": "devastator_squad" + }, + { + "proportion": 1, + "squad": "assault_squad" + } + ], "distribution_overrides": { - "equal_specialists": { - "default_squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "devastator_squad", "proportion": 1 }, - { "squad": "assault_squad", "proportion": 1 }, - { "squad": "tactical_squad", "proportion": 2 }, - { "squad": "attack_bike_squad", "proportion": 4 }, - { "squad": "bike_squad", "proportion": 6 } - ], + "equal_scouts": { "companies": [ { "company": 6, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "devastator_squad", "proportion": 1 }, - { "squad": "assault_squad", "proportion": 1 }, - { "squad": "tactical_squad", "proportion": 2 }, - { "squad": "attack_bike_squad", "proportion": 4 }, - { "squad": "bike_squad", "proportion": 6 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 6, + "squad": "tactical_squad" + } ] }, { "company": 7, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "devastator_squad", "proportion": 1 }, - { "squad": "assault_squad", "proportion": 1 }, - { "squad": "tactical_squad", "proportion": 2 }, - { "squad": "attack_bike_squad", "proportion": 4 }, - { "squad": "bike_squad", "proportion": 6 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 6, + "squad": "tactical_squad" + } ] }, { "company": 8, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "devastator_squad", "proportion": 1 }, - { "squad": "assault_squad", "proportion": 1 }, - { "squad": "tactical_squad", "proportion": 2 }, - { "squad": "attack_bike_squad", "proportion": 4 }, - { "squad": "bike_squad", "proportion": 6 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 1, + "squad": "assault_squad" + } ] }, { "company": 9, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "devastator_squad", "proportion": 1 }, - { "squad": "assault_squad", "proportion": 1 }, - { "squad": "tactical_squad", "proportion": 2 }, - { "squad": "attack_bike_squad", "proportion": 4 }, - { "squad": "bike_squad", "proportion": 6 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 1, + "squad": "devastator_squad" + } + ] + }, + { + "company": 10, + "squads": [ + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 1, + "squad": "scout_squad" + }, + { + "proportion": 4, + "squad": "bike_squad" + } ] } + ], + "default_squads": [ + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 6, + "squad": "attack_bike_squad" + }, + { + "proportion": 8, + "squad": "bike_squad" + }, + { + "proportion": 2, + "squad": "scout_squad" + } ] }, - "equal_scouts": { - "default_squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "attack_bike_squad", "proportion": 6 }, - { "squad": "bike_squad", "proportion": 8 }, - { "squad": "scout_squad", "proportion": 2 } - ], + "equal_specialists": { "companies": [ { "company": 6, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "tactical_squad", "proportion": 6 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 1, + "squad": "devastator_squad" + }, + { + "proportion": 1, + "squad": "assault_squad" + }, + { + "proportion": 2, + "squad": "tactical_squad" + }, + { + "proportion": 4, + "squad": "attack_bike_squad" + }, + { + "proportion": 6, + "squad": "bike_squad" + } ] }, { "company": 7, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "tactical_squad", "proportion": 6 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 1, + "squad": "devastator_squad" + }, + { + "proportion": 1, + "squad": "assault_squad" + }, + { + "proportion": 2, + "squad": "tactical_squad" + }, + { + "proportion": 4, + "squad": "attack_bike_squad" + }, + { + "proportion": 6, + "squad": "bike_squad" + } ] }, { "company": 8, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "assault_squad", "proportion": 1 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 1, + "squad": "devastator_squad" + }, + { + "proportion": 1, + "squad": "assault_squad" + }, + { + "proportion": 2, + "squad": "tactical_squad" + }, + { + "proportion": 4, + "squad": "attack_bike_squad" + }, + { + "proportion": 6, + "squad": "bike_squad" + } ] }, { "company": 9, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "devastator_squad", "proportion": 1 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 1, + "squad": "devastator_squad" + }, + { + "proportion": 1, + "squad": "assault_squad" + }, + { + "proportion": 2, + "squad": "tactical_squad" + }, + { + "proportion": 4, + "squad": "attack_bike_squad" + }, + { + "proportion": 6, + "squad": "bike_squad" + } ] + } + ], + "default_squads": [ + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" }, { - "company": 10, - "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "scout_squad", "proportion": 1 }, - { "squad": "bike_squad", "proportion": 4 } - ] + "proportion": 1, + "squad": "devastator_squad" + }, + { + "proportion": 1, + "squad": "assault_squad" + }, + { + "proportion": 2, + "squad": "tactical_squad" + }, + { + "proportion": 4, + "squad": "attack_bike_squad" + }, + { + "proportion": 6, + "squad": "bike_squad" } ] }, "equal_spescout": { - "default_squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "devastator_squad", "proportion": 1 }, - { "squad": "assault_squad", "proportion": 1 }, - { "squad": "scout_squad", "proportion": 1 }, - { "squad": "tactical_squad", "proportion": 1 }, - { "squad": "attack_bike_squad", "proportion": 4 }, - { "squad": "bike_squad", "proportion": 6 } - ], "companies": [ { "company": 6, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "devastator_squad", "proportion": 1 }, - { "squad": "assault_squad", "proportion": 1 }, - { "squad": "scout_squad", "proportion": 1 }, - { "squad": "tactical_squad", "proportion": 1 }, - { "squad": "attack_bike_squad", "proportion": 4 }, - { "squad": "bike_squad", "proportion": 6 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 1, + "squad": "devastator_squad" + }, + { + "proportion": 1, + "squad": "assault_squad" + }, + { + "proportion": 1, + "squad": "scout_squad" + }, + { + "proportion": 1, + "squad": "tactical_squad" + }, + { + "proportion": 4, + "squad": "attack_bike_squad" + }, + { + "proportion": 6, + "squad": "bike_squad" + } ] }, { "company": 7, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "devastator_squad", "proportion": 1 }, - { "squad": "assault_squad", "proportion": 1 }, - { "squad": "scout_squad", "proportion": 1 }, - { "squad": "tactical_squad", "proportion": 1 }, - { "squad": "attack_bike_squad", "proportion": 4 }, - { "squad": "bike_squad", "proportion": 6 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 1, + "squad": "devastator_squad" + }, + { + "proportion": 1, + "squad": "assault_squad" + }, + { + "proportion": 1, + "squad": "scout_squad" + }, + { + "proportion": 1, + "squad": "tactical_squad" + }, + { + "proportion": 4, + "squad": "attack_bike_squad" + }, + { + "proportion": 6, + "squad": "bike_squad" + } ] }, { "company": 8, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "devastator_squad", "proportion": 1 }, - { "squad": "assault_squad", "proportion": 1 }, - { "squad": "scout_squad", "proportion": 1 }, - { "squad": "tactical_squad", "proportion": 1 }, - { "squad": "attack_bike_squad", "proportion": 4 }, - { "squad": "bike_squad", "proportion": 6 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 1, + "squad": "devastator_squad" + }, + { + "proportion": 1, + "squad": "assault_squad" + }, + { + "proportion": 1, + "squad": "scout_squad" + }, + { + "proportion": 1, + "squad": "tactical_squad" + }, + { + "proportion": 4, + "squad": "attack_bike_squad" + }, + { + "proportion": 6, + "squad": "bike_squad" + } ] }, { "company": 9, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "devastator_squad", "proportion": 1 }, - { "squad": "assault_squad", "proportion": 1 }, - { "squad": "scout_squad", "proportion": 1 }, - { "squad": "tactical_squad", "proportion": 1 }, - { "squad": "attack_bike_squad", "proportion": 4 }, - { "squad": "bike_squad", "proportion": 6 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 1, + "squad": "devastator_squad" + }, + { + "proportion": 1, + "squad": "assault_squad" + }, + { + "proportion": 1, + "squad": "scout_squad" + }, + { + "proportion": 1, + "squad": "tactical_squad" + }, + { + "proportion": 4, + "squad": "attack_bike_squad" + }, + { + "proportion": 6, + "squad": "bike_squad" + } ] }, { "company": 10, "squads": [ - { "squad": "command_squad", "max_count": 1, "min_count": 1, "require": true }, - { "squad": "scout_squad", "proportion": 1 }, - { "squad": "bike_squad", "proportion": 4 } + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 1, + "squad": "scout_squad" + }, + { + "proportion": 4, + "squad": "bike_squad" + } ] } + ], + "default_squads": [ + { + "max_count": 1, + "min_count": 1, + "require": true, + "squad": "command_squad" + }, + { + "proportion": 1, + "squad": "devastator_squad" + }, + { + "proportion": 1, + "squad": "assault_squad" + }, + { + "proportion": 1, + "squad": "scout_squad" + }, + { + "proportion": 1, + "squad": "tactical_squad" + }, + { + "proportion": 4, + "squad": "attack_bike_squad" + }, + { + "proportion": 6, + "squad": "bike_squad" + } ] } } -} +} \ No newline at end of file diff --git a/scripts/scr_roster/scr_roster.gml b/scripts/scr_roster/scr_roster.gml index 47623a2641..32a41e8242 100644 --- a/scripts/scr_roster/scr_roster.gml +++ b/scripts/scr_roster/scr_roster.gml @@ -570,7 +570,12 @@ function add_unit_to_battle(unit, meeting, is_local) { //assualt marines col = obj_controller.bat_assault_column; new_combat.assaults++; - + } else if (_unit_role == _role[13]) { + // bikers + col = obj_controller.bat_bike_column; + } else if (_unit_role == _role[20]) { + //assbikers + col = obj_controller.bat_bike_column; //librarium roles } else if (unit.IsSpecialist(SPECIALISTS_LIBRARIANS, true)) { col = obj_controller.bat_librarian_column; //librarium diff --git a/scripts/scr_squads/scr_squads.gml b/scripts/scr_squads/scr_squads.gml index 75852289ac..a84702be03 100644 --- a/scripts/scr_squads/scr_squads.gml +++ b/scripts/scr_squads/scr_squads.gml @@ -55,8 +55,10 @@ function SquadEquipmentSorting(squad, from_armoury = true, to_armoury = true) co members_UnitGroup = squad.get_members(true); members_UnitGroup.shuffle(); optional_load = undefined; - optional_fill_counts = {}; // flat struct: "slot_groupIndex" -> filled count + optional_fill_counts = {}; // flat struct: "slot_groupIndex" -> filled count, lazily populated required_load = undefined; + required_fill_counts = {}; + required_targets = {}; target_squad.update_fulfilment(); @@ -121,49 +123,33 @@ function SquadEquipmentSorting(squad, from_armoury = true, to_armoury = true) co ]; static structure_role_optional_loadout = function(optional_data){ - - // Use the original data directly — no clone needed since optional_load is now read-only - // (all mutable state lives in optional_fill_counts). variable_clone can incorrectly - // flatten doubly-nested arrays in this GML version, corrupting the group structure. + //read-only alias into squad_types optional_load = optional_data; - - // Initialise fill-count tracking in a flat struct (struct field writes are always - // in-place in GML — no copy-on-write issues unlike nested array element writes) + //mutable state through slot_groupIndex optional_fill_counts = {}; - var _optional_loadout_slots = struct_get_names(optional_load); - for (var slot = 0; slot < array_length(_optional_loadout_slots); slot++) { - var _load_out_slot = _optional_loadout_slots[slot]; - for (var i = 0; i < array_length(optional_load[$ _load_out_slot]); i++) { - optional_fill_counts[$ _load_out_slot + "_" + string(i)] = 0; - } - } - } + }; static structure_role_required_loadout = function(required_data) { - //find out if the _unit type for the squad has required equipment thresholds - - required_load = variable_clone(required_data); - required_loadout_slots = struct_get_names(required_load); - for (var i = 0; i < array_length(required_loadout_slots); i++) { - var _current_load_slot = required_loadout_slots[i]; - var _equip_slot = required_load[$ _current_load_slot]; - if (is_string(required_load[$ _current_load_slot][1])) { - if (required_load[$ _current_load_slot][1] == "max") { - required_load[$ _current_load_slot][1] = target_squad.squad_fulfilment[$ unit_role]; - } - } - array_insert(required_load[$ _current_load_slot], 2, 0); + required_load = required_data; + required_fill_counts = {}; + required_targets = {}; + var _slots = struct_get_names(required_data); + for (var i = 0; i < array_length(_slots); i++) { + var _slot = _slots[i]; + var _target = required_data[$ _slot][1]; + required_targets[$ _slot] = + (_target == "max") ? target_squad.squad_fulfilment[$ unit_role] : _target; + required_fill_counts[$ _slot] = 0; } }; static equip_required_for_role = function(_unit) { - if (required_load[$ current_load_slot][2] < required_load[$ current_load_slot][1]) { + if (required_fill_counts[$ current_load_slot] < required_targets[$ current_load_slot]) { //if the required amount of equipment is not in the squad already equip this marine with equipment - var _item_to_add = required_load[$ current_load_slot][0]; - var required_load_set = {}; - required_load_set[$ current_load_slot] = _item_to_add; - _unit.alter_equipment(required_load_set, from_armoury, to_armoury); - required_load[$ current_load_slot][2]++; + var _required_load_set = {}; + _required_load_set[$ current_load_slot] = required_load[$ current_load_slot][0]; + _unit.alter_equipment(_required_load_set, from_armoury, to_armoury); + required_fill_counts[$ current_load_slot]++; return true; } //if all required equipment is included in the squad start adding optional equipment return false; @@ -175,7 +161,7 @@ function SquadEquipmentSorting(squad, from_armoury = true, to_armoury = true) co var _optional_groups = optional_load[$ current_load_slot]; for (var i = 0; i < array_length(_optional_groups); i++) { var _count_key = current_load_slot + "_" + string(i); - var _optionals_filled = optional_fill_counts[$ _count_key]; // read from flat struct + var _optionals_filled = optional_fill_counts[$ _count_key] ?? 0; var _optionals_max_allowed = _optional_groups[i][1]; var _optionals_equipment = _optional_groups[i][0]; var _item_to_add; @@ -212,8 +198,7 @@ function SquadEquipmentSorting(squad, from_armoury = true, to_armoury = true) co var _opt_load_out = {}; _opt_load_out[$ current_load_slot] = _item_to_add; _unit.alter_equipment(_opt_load_out, from_armoury, to_armoury); - // Struct field write — guaranteed in-place, no copy-on-write in GML - optional_fill_counts[$ _count_key]++; + optional_fill_counts[$ _count_key] = _optionals_filled + 1; if (_is_equipment_set) { var _equip_set_data = _optional_groups[i][2]; if (is_struct(_equip_set_data)) { @@ -378,11 +363,6 @@ function UnitSquad(squad_type = undefined, company = 0) constructor { static change_type = function(new_type) { type = new_type; - if (is_array(type)) { - show_debug_message($"[PROBE] change_type got ARRAY type (len {array_length(type)}): {type}"); - } else if (!struct_exists(obj_ini.squad_types, type)) { - show_debug_message($"[PROBE] change_type unknown squad type: \"{type}\""); - } add_type_data(obj_ini.squad_types[$ type].type_data); }; @@ -406,16 +386,6 @@ function UnitSquad(squad_type = undefined, company = 0) constructor { } squad_fulfilment[$ _wanted_unit_role] = 0; //create a fulfilment structure to log members of squad } - //Mapping for role groups in alternative source; - squad_role_alternatives = {}; - for (var i =0; i < array_length(squad_unit_types); i++) { - var _role_name = squad_unit_types[i]; - var _role_def = fill_squad[$ _role_name]; - //alternative source presence check - if (struct_exists(_role_def, "alternative_roles")) { - squad_role_alternatives[$ _role_name] = _role_def.alternative_roles; - } - } return squad_unit_types; }; @@ -903,14 +873,7 @@ function resolve_company_arrangement(arrangement, company_number) { /// @return {Undefined} function apply_squad_distribution_override(arrangement, override) { if (struct_exists(override, "default_squads")) { - // Deep-clone so arrangement.default_squads is independent of the override sub-struct, - // preventing any future in-place mutation of the array from corrupting both references. - var _src = override.default_squads; - var _clone = array_create(array_length(_src)); - for (var _i = 0; _i < array_length(_src); _i++) { - _clone[_i] = variable_clone(_src[_i]); - } - arrangement.default_squads = _clone; + arrangement.default_squads = variable_clone(override.default_squads) } if (struct_exists(override, "companies")) { if (!struct_exists(arrangement, "companies")) { @@ -960,11 +923,7 @@ function get_compay_squad_arrangement(company){ // shared array every other defaulted company also points at. Registering it persists the edits // and lets resolve_company_arrangement pick this company up by its own entry from now on. var _src = struct_exists(_arrangement, "default_squads") ? _arrangement.default_squads : []; - var _squads = array_create(array_length(_src)); - for (var _i = 0; _i < array_length(_src); _i++) { - _squads[_i] = variable_clone(_src[_i]); - } - var _entry = { company: company, squads: _squads }; + var _entry = { company: company, squads: variable_clone(_src) }; array_push(_comp_datas, _entry); return _entry; }