diff --git a/devTools/types/FC/SecExp.d.ts b/devTools/types/FC/SecExp.d.ts index b9e445560220f3e15374692c89189d701f0cde72..e71d7056ebbe021db5f67fe334cc2ba6035f0346 100644 --- a/devTools/types/FC/SecExp.d.ts +++ b/devTools/types/FC/SecExp.d.ts @@ -10,7 +10,6 @@ declare namespace FC { interface PlayerUnitData extends UnitData { active: number, ID: number, - isDeployed: number } interface PlayerHumanUnitData extends PlayerUnitData { diff --git a/src/002-config/fc-version.js b/src/002-config/fc-version.js index 8e55bd9e56d091c2fbdcb481290a732eea118dd3..2d224c4f0d002ddaf93a01cb8c4577db6abf50c6 100644 --- a/src/002-config/fc-version.js +++ b/src/002-config/fc-version.js @@ -2,5 +2,5 @@ App.Version = { base: "0.10.7.1", // The vanilla version the mod is based off of, this should never be changed. pmod: "4.0.0-alpha.8", commitHash: null, - release: 1139 // When getting close to 2000, please remove the check located within the onLoad() function defined at line five of src/js/eventHandlers.js. + release: 1140 // When getting close to 2000, please remove the check located within the onLoad() function defined at line five of src/js/eventHandlers.js. }; diff --git a/src/Mods/SecExp/events/attackOptions.js b/src/Mods/SecExp/events/attackOptions.js deleted file mode 100644 index c5e37fe07a6fdb38498d7d58ca3ddb194b0dbf72..0000000000000000000000000000000000000000 --- a/src/Mods/SecExp/events/attackOptions.js +++ /dev/null @@ -1,391 +0,0 @@ -App.Events.attackOptions = class attackOptions extends App.Events.BaseEvent { - eventPrerequisites() { - return [ - () => V.secExpEnabled > 0, - () => V.SecExp.war.foughtThisWeek === 0, - () => V.SecExp.war.type.includes("Attack") - ]; - } - - execute(node) { - /** Display's the deploy menu for the unit. - * @param {FC.SecExp.PlayerHumanUnitData} [input] the unit to be checked. - * @param {FC.SecExp.PlayerHumanUnitTypeMod} [type] the class of unit to be checked. - * @returns {HTMLDivElement} - */ - const deployMenu = function(input, type) { - let el = document.createElement("div"); - if (input.active === 1 && input.troops > 0) { - App.UI.DOM.appendNewElement("div", el, App.SecExp.unit.describe(input, type, true)); - } - return el; - }; - if (typeof V.SecExp.settings.unitDescriptions === "undefined") { - V.SecExp.settings.unitDescriptions = 0; - } - V.nextButton = " "; - V.encyclopedia = "Battles"; - let r = []; - - let options; - let option; - - App.UI.DOM.appendNewElement("h1", node, `${V.SecExp.war.type} Imminent`, ["monospace", "red"]); - if (!V.SecExp.war.type.includes("Major")) { - if (V.SecExp.battles.victories + V.SecExp.battles.losses > 0) { - r.push(`The ominous message dominates the screens of your office, and ${V.assistant.name} quickly gathers all information available to prepare for battle.`); - if (V.SecExp.war.attacker.type === "raiders") { - if (App.SecExp.battle.recon() >= 1) { - r.push(`A disorganized horde of raiders is coming to your city. To such jackals your arcology surely looks like an appetizing morsel.`); - r.push(`Fortunately you knew of their coming, thanks to your recon systems.`); - } else { - r.push(`Some of your citizens saw the disorganized horde of raiders coming towards the city and quickly reported it. To such jackals your arcology surely looks like an appetizing morsel.`); - } - const div = document.createElement("div"); - App.UI.DOM.makeElement("span", `Raiders`, "strong"); - App.UI.DOM.makeElement("span", `are roaming gangs of bandits, preying on the vulnerable supply lines of Free Cities and old world nations. They are rarely equipped with decent armaments and even more rarely have any formal military training, but they make up for that with high mobility and numbers.`); - r.push(div); - } else if (V.SecExp.war.attacker.type === "free city") { - if (App.SecExp.battle.recon() >= 1) { - r.push(`A menacing column of slavers and hired mercenaries is coming to your city. Another free city is ready to use their best tools to hit a dangerous competitor where it hurts.`); - r.push(`Fortunately you knew of their coming, thanks to your recon systems.`); - } else { - r.push(`Some of your citizens saw the menacing column of slavers and hired mercenaries and rushed to your office to bring the grim news. Another free city is ready to use their best tools to bring down a dangerous competitor.`); - } - const div = document.createElement("div"); - App.UI.DOM.makeElement("span", `Free City expeditions`, "strong"); - App.UI.DOM.makeElement("span", `are usually composed of mercenaries hired to take down sensible supplies or infrastructure in order to damage the enemies of their contractor. They have on average good equipment and training, together with decent mobility, making them a formidable force. Their biggest weakness however is their relatively low numbers.`); - r.push(div); - } else if (V.SecExp.war.attacker.type === "freedom fighters") { - if (App.SecExp.battle.recon() >= 1) { - r.push(`A dangerous looking army of guerrillas is gathering just outside the arcology. Fanatics and idealists armed with dead men's words and hope, set on erasing your fledgling empire.`); - r.push(`Fortunately you knew of their coming, thanks to your recon systems.`); - } else { - r.push(`Some of your citizens saw the dangerous looking army of guerrillas is gathering just outside the arcology. Fanatics and idealists armed with dead men's words and hope, set on erasing your fledgling empire.`); - } - const div = document.createElement("div"); - App.UI.DOM.makeElement("span", `Freedom Fighters`, "strong"); - App.UI.DOM.makeElement("span", `are groups of individuals fighting to rid the planet of "evils" such as the Free Cities and their way of life. Lacking the strength to assault one directly they fight guerrilla style slowly starving to death their enemies. They are rarely well equipped, but with good training and mobility they are not a threat that can be taken lightly.`); - r.push(div); - } else if (V.SecExp.war.attacker.type === "old world") { - if (App.SecExp.battle.recon() >= 1) { - r.push(`A disciplined yet dusty, scruffy old world army is approaching the confines of your arcology. There's nothing better than a good war to unite the electorate and your arcology is just the perfect target.`); - r.push(`Fortunately you knew of their coming, thanks to your recon systems.`); - } else { - r.push(`Some of your citizens saw the disciplined yet dusty, scruffy old world army is approaching the confines of your arcology. There's nothing better than a good war to unite the electorate and your arcology is just the perfect target.`); - } - const div = document.createElement("div"); - App.UI.DOM.makeElement("span", `Old world expeditions`, "strong"); - App.UI.DOM.makeElement("span", `are usually sent to secure resources and trade routes for their nation or, more often, to provide their citizens with a bogeyman to be scared of. They are usually decently equipped and trained, which together with their generous numbers make them a tough nut to crack. However, they often lack in mobility.`); - r.push(div); - } - } else { - r.push(`Your assistant interrupted your rest to bring the grim news. You quickly rush to your console, where you can see one of the convoys supplying your arcology has been attacked and looted. It seems a group of desperate looking bandits decided it was a good idea to steal from you.`); - r.push(`Due to their great wealth, Free Cities inevitably become tasty morsels for anyone able to field armed men. Considering the particular needs of arcologies their supply lines tend to be delicate lifelines, often preyed upon by those who stand to gain from the free city downfall.`); - } - } else { - if (V.SecExp.battles.major > 0) { - r.push(`The ominous message dominates the screens of your office, and ${V.assistant.name} quickly gathers all information available to prepare for the major battle ahead.`); - } else { - r.push(`Your assistant interrupted your rest to bring the grim news. You quickly rush to your console, where you can see the satellite images coming in of the force about to crash against your arcology. It's not the first time your armies fought for the survival of your empire, but this time it seems it will be a fight for life or death.`); - } - if (V.SecExp.war.attacker.type === "raiders") { - if (App.SecExp.battle.recon() >= 1) { - r.push(`A massive, disorganized horde of raiders is coming to your city. It seems a warlord of the wastelands amassed enough men to try and obtain a slice of territory of his own; if he's not defeated there won't be a tomorrow for the arcology.`); - r.push(`Fortunately you knew of their coming, thanks to your recon systems.`); - } else { - r.push(`Some of your citizens saw the massive, disorganized horde of raiders coming towards the city and quickly reported it. It seems a warlord of the wastelands amassed enough men to try and obtain a slice of territory of his own; if he's not defeated there won't be a tomorrow for the arcology.`); - } - r.push(App.UI.DOM.makeElement("div", `Raiders are roaming gangs of bandits, preying on the vulnerable supply lines of Free Cities and old world nations. They are rarely equipped with decent armaments and even more rarely have any formal military training, but they make up for that with high mobility and numbers.`)); - } else if (V.SecExp.war.attacker.type === "free city") { - if (App.SecExp.battle.recon() >= 1) { - r.push(`A massive, menacing column of slavers and hired mercenaries is coming to your city. The quantity of money invested in this assault is staggering; it seems you made some very powerful enemies. If they're not defeated your story will end this day.`); - r.push(`Fortunately you knew of their coming, thanks to your recon systems.`); - } else { - r.push(`Some of your citizens saw the massive, menacing column of slavers and hired mercenaries and rushed to your office to bring the grim news. The quantity of money invested in this assault is staggering; it seems you made some very powerful enemies. If they're not defeated your story will end this day.`); - } - r.push(App.UI.DOM.makeElement("div", `Free City expeditions are usually composed of mercenaries hired to take down sensible supplies or infrastructure in order to damage the enemies of their contractor. They have, on average, good equipment and training, together with decent mobility, making them a formidable force. Their biggest weakness, however, is their relatively low numbers.`)); - } else if (V.SecExp.war.attacker.type === "freedom fighters") { - if (App.SecExp.battle.recon() >= 1) { - r.push(`A massive, dangerous army of guerrillas is gathering just outside the arcology. A huge ocean of fanatics and idealists armed with dead men's words and hope, set on erasing your fledgling empire once and for all. And this time they won't stop until your body is burnt to a crisp.`); - r.push(`Fortunately you knew of their coming, thanks to your recon systems.`); - } else { - r.push(`Some of your citizens saw the massive, dangerous army of guerrillas is gathering just outside the arcology. A huge ocean of fanatics and idealists armed with dead men's words and hope, set on erasing your fledgling empire once and for all. And this time they won't stop until your body is burnt to a crisp.`); - } - r.push(App.UI.DOM.makeElement("div", `Freedom Fighters are groups of individuals fighting to rid the planet of "evils" such as the Free Cities and their way of life. Lacking the strength to assault one directly, they fight guerrilla style, slowly starving to death their enemies. They are rarely well equipped, but with good training and mobility they are not a threat that can be taken lightly.`)); - } else if (V.SecExp.war.attacker.type === "old world") { - if (App.SecExp.battle.recon() >= 1) { - r.push(`A massive, disciplined old world army is approaching the confines of your arcology. It seems one of the nations of the old world is determined to put your arcology to rest once and for all or die trying.`); - r.push(`Fortunately you knew of their coming, thanks to your recon systems.`); - } else { - r.push(`Some of your citizens saw the massive, disciplined old world army is approaching the confines of your arcology. It seems one of the nations of the old world is determined to put your arcology to rest once and for all or die trying.`); - } - r.push(App.UI.DOM.makeElement("div", `Old world expeditions are usually sent to secure resources and trade routes for their nation or, more often, to provide their citizens with a bogeyman to be scared of. They are usually decently equipped and trained, which together with their generous numbers make them a tough nut to crack. However, they often lack in mobility.`)); - } - } - App.Events.addParagraph(node, r); - r = []; - App.UI.DOM.appendNewElement("h3", node, `Recon: (AO: ${V.terrain})`); - const estimatedMen = V.SecExp.war.estimatedMen; - const expectedEquip = V.SecExp.war.expectedEquip; - const isOceanic = V.terrain === "oceanic"; - r.push(`It seems your troops and your adversary will fight`); - if (V.SecExp.war.terrain === "rural") { - r.push(`in`, App.UI.DOM.makeElement("span", `the rural land`, "strong"), `surrounding the free city.`); - } else if (V.SecExp.war.terrain === "urban") { - r.push(`in the old`, App.UI.DOM.makeElement("span", `abandoned city`, "strong"), `surrounding the free city.`); - } else if (V.SecExp.war.terrain === "hills") { - r.push(`on`, App.UI.DOM.makeElement("span", `the hills`, "strong"), `around the free city.`); - } else if (V.SecExp.war.terrain === "coast") { - r.push(`along`, App.UI.DOM.makeElement("span", `the coast`, "strong"), `just outside the free city.`); - } else if (V.SecExp.war.terrain === "outskirts") { - r.push(`right against`, App.UI.DOM.makeElement("span", `the walls of the arcology.`, "strong")); - } else if (V.SecExp.war.terrain === "mountains") { - r.push(`in`, App.UI.DOM.makeElement("span", `the mountains`, "strong"), `overlooking the arcology.`); - } else if (V.SecExp.war.terrain === "wasteland") { - r.push(`in`, App.UI.DOM.makeElement("span", `the wastelands`, "strong"), `outside the free city territory.`); - } else if (V.SecExp.war.terrain === "international waters") { - r.push(`in`, App.UI.DOM.makeElement("span", `the water surrounding`, "strong"), `the free city.`); - } else if (["a sunken ship", "an underwater cave"].includes(V.SecExp.war.terrain)) { - r.push(`in`, App.UI.DOM.makeElement("span", `${V.SecExp.war.terrain}`, "strong"), `near the free city.`); - } else if (V.SecExp.war.terrain === "error") { - r.push(App.UI.DOM.makeElement("span", `Error: failed to assign terrain.`, "red"), `${V.SecExp.war.terrain} reads: ${V.SecExp.war.terrain}.`); - } else { - r.push(App.UI.DOM.makeElement("span", `Error: failed to read terrain.`, "red"), `${V.SecExp.war.terrain} reads: ${V.SecExp.war.terrain}.`); - } - if (App.SecExp.battle.recon() === 3) { - r.push(`Your recon capabilities are top notch. The information collected will be most likely correct or very close to be so:`); - } else if (App.SecExp.battle.recon() === 2) { - r.push(`Your recon capabilities are decent. The information collected will be mostly close to the truth:`); - } else if (App.SecExp.battle.recon() === 1) { - r.push(`Your recon capabilities are fairly low. The information collected will be quite inaccurate:`); - } else { - r.push(`Your recon capabilities are almost non-existent. The information collected will be wild guesses at best:`); - } - r.push(`approximately`); - r.push(App.UI.DOM.makeElement("span", `${estimatedMen} men`, "strong")); - r.push(`are coming, they seem to be`); - if (expectedEquip <= 0) { - r.push(App.UI.DOM.makeElement("span", `poorly armed.`, "strong")); - r.push(`Old rusty small arms are the norm with just a few barely working civilian ${isOceanic ? 'boats' : 'vehicles'}.`); - } else if (expectedEquip === 1) { - r.push(App.UI.DOM.makeElement("span", `lightly armed,`, "strong")); - r.push(`mostly with small arms and some repurposed civilian ${isOceanic ? 'boats' : 'vehicles'} with scattered machine gun support. There's no sign of heavy ${isOceanic ? 'boats' : 'vehicles'}, ${isOceanic ? 'submarines' : 'artillery'} or aircraft.`); - } else if (expectedEquip === 2) { - r.push(App.UI.DOM.makeElement("span", `decently armed`, "strong")); - r.push(`with good quality small arms, machine guns and a few mortars. There appear to be some heavy military ${isOceanic ? 'boats' : 'vehicles'} coming as well.`); - } else if (expectedEquip === 3) { - r.push(App.UI.DOM.makeElement("span", `well armed`, "strong")); - r.push(`with high quality small arms, ${isOceanic ? 'spear men' : 'snipers'}, demolitions teams, heavy duty machine guns and mortars. Heavy military ${isOceanic ? 'boats' : 'vehicles'} are numerous and a few ${isOceanic ? 'submarines' : 'artillery pieces'} are accompanying the detachment.`); - } else if (expectedEquip >= 4) { - r.push(App.UI.DOM.makeElement("span", `extremely well armed`, "strong")); - r.push(`with excellent small arms and specialized teams with heavy duty infantry support weapons. Heavy presence of armored military ${isOceanic ? 'boats' : 'vehicles'}, ${isOceanic ? 'submarines' : 'artillery pieces'} and even some attack helicopters.`); - } - App.Events.addParagraph(node, r); - r = []; - App.UI.DOM.appendNewElement("h2", node, `Battle plan`); - if (V.SecExp.war.commander === "bodyguard" && V.BodyguardID === 0 || V.SecExp.war.commander === "headGirl" && V.HeadGirlID === 0) { - App.UI.DOM.makeElement("span", `Chosen leader ${V.SecExp.war.commander} cannot be found, please select another.`, "warning"); - V.SecExp.war.commander = "PC"; - } - - options = new App.UI.OptionsGroup(); // leader assignment - option = options.addOption("Leader of the troops", "commander", V.SecExp.war) - .addValueList([["You", "PC"], [V.assistant.name, "assistant"]]); - - if (V.BodyguardID !== 0 && V.SecExp.edicts.defense.slavesOfficers === 1) { - option.addValue("Bodyguard", "bodyguard"); - } - if (V.HeadGirlID !== 0 && V.SecExp.edicts.defense.slavesOfficers === 1) { - option.addValue("Head Girl", "headGirl"); - } - if (V.SecExp.edicts.defense.militia >= 1) { - option.addValue("Citizens' militia officers", "citizen"); - } - if (V.mercenaries > 0) { - option.addValue("Mercenary officers", "mercenary"); - } - if (V.SF.Toggle && V.SF.Active >= 1 && V.SF.MercCon.CanAttend === -2) { - option.addValue("Colonel", "colonel"); - } - node.append(options.render()); - - options = new App.UI.OptionsGroup(); - const tacticsDesc = new Map([ - ["Bait and Bleed", `Combines bait and switch tactics with guerrilla style assaults, with the objective of slowly bleed the enemy.`], - [`Guerrilla`, `Involves using terrain knowledge and small fast attacks to hinder and weaken the enemy.`], - [`Choke Points`, `Involves using terrain knowledge and strong fortifications in order to stop the enemy on its track`], - [`Interior Lines`, `Involves exploiting a defender's shorter logistics lines and redeployment times in order to keep the enemy pressured.`], - [`Pincer Maneuver`, `Involves letting the enemy push back the center in order to envelop their formation.`], - [`Defense In Depth`, `Involves letting the enemy gain terrain to gain tactical superiority by alternating between delaying actions and small counterattacks.`], - [`Blitzkrieg`, `Involves breaking the front of the enemy with a fast armored force concentrated into a small area.`], - [`Human Wave`, `Involves assaulting the enemy with large numbers of infantry to overwhelm their lines.`], - ]); - App.UI.DOM.appendNewElement("h3", node, `Tactics`); - const tactics = App.Data.SecExp.TerrainAndTactics.get(V.SecExp.war.terrain); - for (const tactic in tactics) { - const option = options.addOption(tactic, "chosenTactic", V.SecExp.war).addValue("Select", tactic); - const comment = document.createElement("span"); - if (tactics[tactic].atkMod > 0.1) { - App.UI.DOM.appendNewElement("span", comment, "Atk+, ", "green"); - } else if (tactics[tactic].atkMod < 0.1) { - App.UI.DOM.appendNewElement("span", comment, "Atk-, ", "red"); - } - if (tactics[tactic].defMod > 0.1) { - App.UI.DOM.appendNewElement("span", comment, "Def+, ", "green"); - } else if (tactics[tactic].defMod < 0.1) { - App.UI.DOM.appendNewElement("span", comment, "Def-, ", "red"); - } - comment.append(tacticsDesc.get(tactic)); - option.addComment(comment); - } - node.append(options.render()); - - App.UI.DOM.appendNewElement("h3", node, `Troops`); - if (V.SF.Toggle && V.SF.Active >= 1 && V.SecExp.war.type.includes("Major")) { - options = new App.UI.OptionsGroup(); - options.addOption("The incoming attack's scale warrants deploying the special force.", "deploySF", V.SecExp.war) - .addValue("Green light", 1).on().addValue("Red light", 0).off() - .addComment("Some upgrades will be able to support your troops even if the special force is not deployed in the fight."); - node.append(options.render()); - } - - let linkArray = []; - if (V.SecExp.battles.lastSelection.length > 0) { - linkArray.push( - App.UI.DOM.link( - `Restore saved`, - () => { - for (let i = 0; i < V.SecExp.battles.lastSelection.length; i++) { - for (const squad of App.SecExp.unit.squads()) { - if (V.SecExp.battles.lastSelection[i] === squad.ID) { - squad.isDeployed = 1; - break; - } - } - } - V.SecExp.war.saveValid = 1; - V.SecExp.war.commander = V.SecExp.battles.saved.commander; - V.SecExp.war.deploySF = V.SecExp.battles.saved.sfSupport; - }, - [], - passage() - ) - ); - } else { - r.push(`Restore saved`); - } - if (V.SecExp.war.saveValid !== 1) { - linkArray.push( - App.UI.DOM.link( - `Save current`, - () => { - if (App.SecExp.battle.deployedUnits('bots')) { - V.SecExp.battles.lastSelection.push(-1); - } - for (const squad of App.SecExp.unit.squads("human")) { - if (squad.isDeployed === 1) { - V.SecExp.battles.lastSelection.push(squad.ID); - } - } - V.SecExp.war.saveValid = 1; - V.SecExp.battles.saved.commander = V.SecExp.war.commander; - V.SecExp.battles.saved.sfSupport = V.SecExp.war.deploySF; - }, - [], - passage() - ) - ); - } else { - r.push(`Save current`); - } - if (App.SecExp.battle.deployedUnits() > 0) { - linkArray.push( - App.UI.DOM.link( - `Clear current`, - () => { - App.SecExp.unit.squads().forEach(s => s.isDeployed = 0); - V.SecExp.war.saveValid = 0; - }, - [], - passage() - ) - ); - } else { - r.push(`Clear current`); - } - if (V.SecExp.battles.lastSelection.length > 0) { - linkArray.push( - App.UI.DOM.link( - `Clear saved`, - () => { - V.SecExp.battles.lastSelection = []; - V.SecExp.war.saveValid = 0; - }, - [], - passage() - ) - ); - } else { - r.push(`Clear saved`); - } - node.append("Roster: ", App.UI.DOM.generateLinksStrip(linkArray)); - - // troop deployment - if (App.SecExp.battle.deployableUnits() > 0) { - r.push(`With your current readiness level you can send an additional`); - r.push(App.UI.DOM.makeElement("span", String(App.SecExp.battle.deployableUnits()), "strong")); - r.push(`units.`); - } - node.append(App.SecExp.unit.replenishAll()); - if (App.SecExp.battle.deployableUnits() === 0) { - App.UI.DOM.appendNewElement("div", node, `Unit roster full.`, "strong"); - } - - const tabBar = new App.UI.Tabs.TabBar("SecExpAttackOptions"); - for (const [u] of App.SecExp.unit.list()) { - if (V.SecExp.units[u].squads.length > 0) { - tabBar.addTab(capFirstChar(u), u, unitTab(u)); - } - } - node.append(tabBar.render()); - - options = new App.UI.OptionsGroup(); - option = options.addCustomOption("Send your orders"); - if (App.SecExp.battle.deployedUnits() > 0) { - option.addButton(`Deploy troops`, () => { - V.SecExp.war.result = 4; // Sets to a value outside accepted range (-3,3) to avoid evaluation problems - V.SecExp.war.foughtThisWeek = 1; - }, `conflictHandler`); - } else { - App.UI.DOM.appendNewElement("div", node, `You need at least a unit in your roster to proceed to battle.`, "red"); - } - option.addButton(`Attempt to bribe (approximately ${cashFormat(Math.round(App.SecExp.battle.bribeCost() * (1 + either(-1, 1) * random(2) * 0.1)))})`, () => { - V.SecExp.war.result = 1; - V.SecExp.war.foughtThisWeek = 1; - }, `conflictHandler`); - option.addButton(`Surrender`, () => { - V.SecExp.war.result = -1; - V.SecExp.war.foughtThisWeek = 1; - }, "conflictReport"); - node.append(options.render()); - - return node; - - function unitTab(type) { - const frag = new DocumentFragment(); - frag.append(toggleLongDesc()); - V.SecExp.units[type].squads.forEach(s => frag.append(deployMenu(s))); - return frag; - } - - function toggleLongDesc() { - const el = new DocumentFragment(); - const options = new App.UI.OptionsGroup(); - options.addOption("Unit descriptions are", "unitDescriptions", V.SecExp.settings) - .addValueList([["Abbreviated", 1], ["Summarized", 0]]); - el.append(options.render()); - return el; - } - } -}; diff --git a/src/Mods/SecExp/events/conflictOptions.js b/src/Mods/SecExp/events/conflictOptions.js new file mode 100644 index 0000000000000000000000000000000000000000..73a32eb0287ca140ca1396252fdd14595466e7e8 --- /dev/null +++ b/src/Mods/SecExp/events/conflictOptions.js @@ -0,0 +1,488 @@ +App.Events.conflictOptions = class conflictOptions extends App.Events.BaseEvent { + eventPrerequisites() { + return [ + () => V.secExpEnabled > 0, + () => V.SecExp.war.foughtThisWeek === 0, + () => V.SecExp.war.type !== "" + ]; + } + + execute(node) { + V.nextButton = " "; + V.encyclopedia = "Battles"; + const isBattle = V.SecExp.war.type.includes("Attack"); + let r = []; + let options; + let option; + + App.UI.DOM.appendNewElement("h1", node, `${V.SecExp.war.type}${isBattle ? 'Imminent' : '!'}`, ["monospace", "red"]); + if (isBattle) { + if (typeof V.SecExp.settings.unitDescriptions === "undefined") { + V.SecExp.settings.unitDescriptions = 0; + } + if (!V.SecExp.war.type.includes("Major")) { + if (V.SecExp.battles.victories + V.SecExp.battles.losses > 0) { + r.push(`The ominous message dominates the screens of your office, and ${V.assistant.name} quickly gathers all information available to prepare for battle.`); + if (V.SecExp.war.attacker.type === "raiders") { + if (App.SecExp.battle.recon() >= 1) { + r.push(`A disorganized horde of raiders is coming to your city. To such jackals your arcology surely looks like an appetizing morsel.`); + r.push(`Fortunately you knew of their coming, thanks to your recon systems.`); + } else { + r.push(`Some of your citizens saw the disorganized horde of raiders coming towards the city and quickly reported it. To such jackals your arcology surely looks like an appetizing morsel.`); + } + const div = document.createElement("div"); + App.UI.DOM.makeElement("span", `Raiders`, "strong"); + App.UI.DOM.makeElement("span", `are roaming gangs of bandits, preying on the vulnerable supply lines of Free Cities and old world nations. They are rarely equipped with decent armaments and even more rarely have any formal military training, but they make up for that with high mobility and numbers.`); + r.push(div); + } else if (V.SecExp.war.attacker.type === "free city") { + if (App.SecExp.battle.recon() >= 1) { + r.push(`A menacing column of slavers and hired mercenaries is coming to your city. Another free city is ready to use their best tools to hit a dangerous competitor where it hurts.`); + r.push(`Fortunately you knew of their coming, thanks to your recon systems.`); + } else { + r.push(`Some of your citizens saw the menacing column of slavers and hired mercenaries and rushed to your office to bring the grim news. Another free city is ready to use their best tools to bring down a dangerous competitor.`); + } + const div = document.createElement("div"); + App.UI.DOM.makeElement("span", `Free City expeditions`, "strong"); + App.UI.DOM.makeElement("span", `are usually composed of mercenaries hired to take down sensible supplies or infrastructure in order to damage the enemies of their contractor. They have on average good equipment and training, together with decent mobility, making them a formidable force. Their biggest weakness however is their relatively low numbers.`); + r.push(div); + } else if (V.SecExp.war.attacker.type === "freedom fighters") { + if (App.SecExp.battle.recon() >= 1) { + r.push(`A dangerous looking army of guerrillas is gathering just outside the arcology. Fanatics and idealists armed with dead men's words and hope, set on erasing your fledgling empire.`); + r.push(`Fortunately you knew of their coming, thanks to your recon systems.`); + } else { + r.push(`Some of your citizens saw the dangerous looking army of guerrillas is gathering just outside the arcology. Fanatics and idealists armed with dead men's words and hope, set on erasing your fledgling empire.`); + } + const div = document.createElement("div"); + App.UI.DOM.makeElement("span", `Freedom Fighters`, "strong"); + App.UI.DOM.makeElement("span", `are groups of individuals fighting to rid the planet of "evils" such as the Free Cities and their way of life. Lacking the strength to assault one directly they fight guerrilla style slowly starving to death their enemies. They are rarely well equipped, but with good training and mobility they are not a threat that can be taken lightly.`); + r.push(div); + } else if (V.SecExp.war.attacker.type === "old world") { + if (App.SecExp.battle.recon() >= 1) { + r.push(`A disciplined yet dusty, scruffy old world army is approaching the confines of your arcology. There's nothing better than a good war to unite the electorate and your arcology is just the perfect target.`); + r.push(`Fortunately you knew of their coming, thanks to your recon systems.`); + } else { + r.push(`Some of your citizens saw the disciplined yet dusty, scruffy old world army is approaching the confines of your arcology. There's nothing better than a good war to unite the electorate and your arcology is just the perfect target.`); + } + const div = document.createElement("div"); + App.UI.DOM.makeElement("span", `Old world expeditions`, "strong"); + App.UI.DOM.makeElement("span", `are usually sent to secure resources and trade routes for their nation or, more often, to provide their citizens with a bogeyman to be scared of. They are usually decently equipped and trained, which together with their generous numbers make them a tough nut to crack. However, they often lack in mobility.`); + r.push(div); + } + } else { + r.push(`Your assistant interrupted your rest to bring the grim news. You quickly rush to your console, where you can see one of the convoys supplying your arcology has been attacked and looted. It seems a group of desperate looking bandits decided it was a good idea to steal from you.`); + r.push(`Due to their great wealth, Free Cities inevitably become tasty morsels for anyone able to field armed men. Considering the particular needs of arcologies their supply lines tend to be delicate lifelines, often preyed upon by those who stand to gain from the free city downfall.`); + } + } else { + if (V.SecExp.battles.major > 0) { + r.push(`The ominous message dominates the screens of your office, and ${V.assistant.name} quickly gathers all information available to prepare for the major battle ahead.`); + } else { + r.push(`Your assistant interrupted your rest to bring the grim news. You quickly rush to your console, where you can see the satellite images coming in of the force about to crash against your arcology. It's not the first time your armies fought for the survival of your empire, but this time it seems it will be a fight for life or death.`); + } + if (V.SecExp.war.attacker.type === "raiders") { + if (App.SecExp.battle.recon() >= 1) { + r.push(`A massive, disorganized horde of raiders is coming to your city. It seems a warlord of the wastelands amassed enough men to try and obtain a slice of territory of his own; if he's not defeated there won't be a tomorrow for the arcology.`); + r.push(`Fortunately you knew of their coming, thanks to your recon systems.`); + } else { + r.push(`Some of your citizens saw the massive, disorganized horde of raiders coming towards the city and quickly reported it. It seems a warlord of the wastelands amassed enough men to try and obtain a slice of territory of his own; if he's not defeated there won't be a tomorrow for the arcology.`); + } + r.push(App.UI.DOM.makeElement("div", `Raiders are roaming gangs of bandits, preying on the vulnerable supply lines of Free Cities and old world nations. They are rarely equipped with decent armaments and even more rarely have any formal military training, but they make up for that with high mobility and numbers.`)); + } else if (V.SecExp.war.attacker.type === "free city") { + if (App.SecExp.battle.recon() >= 1) { + r.push(`A massive, menacing column of slavers and hired mercenaries is coming to your city. The quantity of money invested in this assault is staggering; it seems you made some very powerful enemies. If they're not defeated your story will end this day.`); + r.push(`Fortunately you knew of their coming, thanks to your recon systems.`); + } else { + r.push(`Some of your citizens saw the massive, menacing column of slavers and hired mercenaries and rushed to your office to bring the grim news. The quantity of money invested in this assault is staggering; it seems you made some very powerful enemies. If they're not defeated your story will end this day.`); + } + r.push(App.UI.DOM.makeElement("div", `Free City expeditions are usually composed of mercenaries hired to take down sensible supplies or infrastructure in order to damage the enemies of their contractor. They have, on average, good equipment and training, together with decent mobility, making them a formidable force. Their biggest weakness, however, is their relatively low numbers.`)); + } else if (V.SecExp.war.attacker.type === "freedom fighters") { + if (App.SecExp.battle.recon() >= 1) { + r.push(`A massive, dangerous army of guerrillas is gathering just outside the arcology. A huge ocean of fanatics and idealists armed with dead men's words and hope, set on erasing your fledgling empire once and for all. And this time they won't stop until your body is burnt to a crisp.`); + r.push(`Fortunately you knew of their coming, thanks to your recon systems.`); + } else { + r.push(`Some of your citizens saw the massive, dangerous army of guerrillas is gathering just outside the arcology. A huge ocean of fanatics and idealists armed with dead men's words and hope, set on erasing your fledgling empire once and for all. And this time they won't stop until your body is burnt to a crisp.`); + } + r.push(App.UI.DOM.makeElement("div", `Freedom Fighters are groups of individuals fighting to rid the planet of "evils" such as the Free Cities and their way of life. Lacking the strength to assault one directly, they fight guerrilla style, slowly starving to death their enemies. They are rarely well equipped, but with good training and mobility they are not a threat that can be taken lightly.`)); + } else if (V.SecExp.war.attacker.type === "old world") { + if (App.SecExp.battle.recon() >= 1) { + r.push(`A massive, disciplined old world army is approaching the confines of your arcology. It seems one of the nations of the old world is determined to put your arcology to rest once and for all or die trying.`); + r.push(`Fortunately you knew of their coming, thanks to your recon systems.`); + } else { + r.push(`Some of your citizens saw the massive, disciplined old world army is approaching the confines of your arcology. It seems one of the nations of the old world is determined to put your arcology to rest once and for all or die trying.`); + } + r.push(App.UI.DOM.makeElement("div", `Old world expeditions are usually sent to secure resources and trade routes for their nation or, more often, to provide their citizens with a bogeyman to be scared of. They are usually decently equipped and trained, which together with their generous numbers make them a tough nut to crack. However, they often lack in mobility.`)); + } + } + App.Events.addParagraph(node, r); + r = []; + + App.UI.DOM.appendNewElement("h3", node, `Recon: (AO: ${V.terrain})`); + const estimatedMen = V.SecExp.war.estimatedMen; + const expectedEquip = V.SecExp.war.expectedEquip; + const isOceanic = V.terrain === "oceanic"; + r.push(`It seems your troops and your adversary will fight`); + if (V.SecExp.war.terrain === "rural") { + r.push(`in`, App.UI.DOM.makeElement("span", `the rural land`, "strong"), `surrounding the free city.`); + } else if (V.SecExp.war.terrain === "urban") { + r.push(`in the old`, App.UI.DOM.makeElement("span", `abandoned city`, "strong"), `surrounding the free city.`); + } else if (V.SecExp.war.terrain === "hills") { + r.push(`on`, App.UI.DOM.makeElement("span", `the hills`, "strong"), `around the free city.`); + } else if (V.SecExp.war.terrain === "coast") { + r.push(`along`, App.UI.DOM.makeElement("span", `the coast`, "strong"), `just outside the free city.`); + } else if (V.SecExp.war.terrain === "outskirts") { + r.push(`right against`, App.UI.DOM.makeElement("span", `the walls of the arcology.`, "strong")); + } else if (V.SecExp.war.terrain === "mountains") { + r.push(`in`, App.UI.DOM.makeElement("span", `the mountains`, "strong"), `overlooking the arcology.`); + } else if (V.SecExp.war.terrain === "wasteland") { + r.push(`in`, App.UI.DOM.makeElement("span", `the wastelands`, "strong"), `outside the free city territory.`); + } else if (V.SecExp.war.terrain === "international waters") { + r.push(`in`, App.UI.DOM.makeElement("span", `the water surrounding`, "strong"), `the free city.`); + } else if (["a sunken ship", "an underwater cave"].includes(V.SecExp.war.terrain)) { + r.push(`in`, App.UI.DOM.makeElement("span", `${V.SecExp.war.terrain}`, "strong"), `near the free city.`); + } else if (V.SecExp.war.terrain === "error") { + r.push(App.UI.DOM.makeElement("span", `Error: failed to assign terrain.`, "red"), `${V.SecExp.war.terrain} reads: ${V.SecExp.war.terrain}.`); + } else { + r.push(App.UI.DOM.makeElement("span", `Error: failed to read terrain.`, "red"), `${V.SecExp.war.terrain} reads: ${V.SecExp.war.terrain}.`); + } + if (App.SecExp.battle.recon() === 3) { + r.push(`Your recon capabilities are top notch. The information collected will be most likely correct or very close to be so:`); + } else if (App.SecExp.battle.recon() === 2) { + r.push(`Your recon capabilities are decent. The information collected will be mostly close to the truth:`); + } else if (App.SecExp.battle.recon() === 1) { + r.push(`Your recon capabilities are fairly low. The information collected will be quite inaccurate:`); + } else { + r.push(`Your recon capabilities are almost non-existent. The information collected will be wild guesses at best:`); + } + r.push(`approximately`); + r.push(App.UI.DOM.makeElement("span", `${estimatedMen} men`, "strong")); + r.push(`are coming, they seem to be`); + if (expectedEquip <= 0) { + r.push(App.UI.DOM.makeElement("span", `poorly armed.`, "strong")); + r.push(`Old rusty small arms are the norm with just a few barely working civilian ${isOceanic ? 'boats' : 'vehicles'}.`); + } else if (expectedEquip === 1) { + r.push(App.UI.DOM.makeElement("span", `lightly armed,`, "strong")); + r.push(`mostly with small arms and some repurposed civilian ${isOceanic ? 'boats' : 'vehicles'} with scattered machine gun support. There's no sign of heavy ${isOceanic ? 'boats' : 'vehicles'}, ${isOceanic ? 'submarines' : 'artillery'} or aircraft.`); + } else if (expectedEquip === 2) { + r.push(App.UI.DOM.makeElement("span", `decently armed`, "strong")); + r.push(`with good quality small arms, machine guns and a few mortars. There appear to be some heavy military ${isOceanic ? 'boats' : 'vehicles'} coming as well.`); + } else if (expectedEquip === 3) { + r.push(App.UI.DOM.makeElement("span", `well armed`, "strong")); + r.push(`with high quality small arms, ${isOceanic ? 'spear men' : 'snipers'}, demolitions teams, heavy duty machine guns and mortars. Heavy military ${isOceanic ? 'boats' : 'vehicles'} are numerous and a few ${isOceanic ? 'submarines' : 'artillery pieces'} are accompanying the detachment.`); + } else if (expectedEquip >= 4) { + r.push(App.UI.DOM.makeElement("span", `extremely well armed`, "strong")); + r.push(`with excellent small arms and specialized teams with heavy duty infantry support weapons. Heavy presence of armored military ${isOceanic ? 'boats' : 'vehicles'}, ${isOceanic ? 'submarines' : 'artillery pieces'} and even some attack helicopters.`); + } + App.Events.addParagraph(node, r); + r = []; + + App.UI.DOM.appendNewElement("h2", node, `Battle plan`); + if (V.SecExp.war.commander === "bodyguard" && V.BodyguardID === 0 || V.SecExp.war.commander === "headGirl" && V.HeadGirlID === 0) { + App.UI.DOM.makeElement("span", `Chosen leader ${V.SecExp.war.commander} cannot be found, please select another.`, "warning"); + V.SecExp.war.commander = "PC"; + } + options = new App.UI.OptionsGroup(); // leader assignment + option = options.addOption("Leader of the troops", "commander", V.SecExp.war) + .addValueList([["You", "PC"], [V.assistant.name, "assistant"]]); + + if (V.BodyguardID !== 0 && V.SecExp.edicts.defense.slavesOfficers === 1) { + option.addValue("Bodyguard", "bodyguard"); + } + if (V.HeadGirlID !== 0 && V.SecExp.edicts.defense.slavesOfficers === 1) { + option.addValue("Head Girl", "headGirl"); + } + if (V.SecExp.edicts.defense.militia >= 1) { + option.addValue("Citizens' militia officers", "citizen"); + } + if (V.mercenaries > 0) { + option.addValue("Mercenary officers", "mercenary"); + } + if (V.SF.Toggle && V.SF.Active >= 1 && V.SF.MercCon.CanAttend === -2) { + option.addValue("Colonel", "colonel"); + } + node.append(options.render()); + + options = new App.UI.OptionsGroup(); + const tacticsDesc = new Map([ + ["Bait and Bleed", `Combines bait and switch tactics with guerrilla style assaults, with the objective of slowly bleed the enemy.`], + [`Guerrilla`, `Involves using terrain knowledge and small fast attacks to hinder and weaken the enemy.`], + [`Choke Points`, `Involves using terrain knowledge and strong fortifications in order to stop the enemy on its track`], + [`Interior Lines`, `Involves exploiting a defender's shorter logistics lines and redeployment times in order to keep the enemy pressured.`], + [`Pincer Maneuver`, `Involves letting the enemy push back the center in order to envelop their formation.`], + [`Defense In Depth`, `Involves letting the enemy gain terrain to gain tactical superiority by alternating between delaying actions and small counterattacks.`], + [`Blitzkrieg`, `Involves breaking the front of the enemy with a fast armored force concentrated into a small area.`], + [`Human Wave`, `Involves assaulting the enemy with large numbers of infantry to overwhelm their lines.`], + ]); + + App.UI.DOM.appendNewElement("h3", node, `Tactics`); + const tactics = App.Data.SecExp.TerrainAndTactics.get(V.SecExp.war.terrain); + for (const tactic in tactics) { + option = options.addOption(tactic, "chosenTactic", V.SecExp.war).addValue("Select", tactic); + const comment = document.createElement("span"); + if (tactics[tactic].atkMod > 0.1) { + App.UI.DOM.appendNewElement("span", comment, "Atk+, ", "green"); + } else if (tactics[tactic].atkMod < 0.1) { + App.UI.DOM.appendNewElement("span", comment, "Atk-, ", "red"); + } + if (tactics[tactic].defMod > 0.1) { + App.UI.DOM.appendNewElement("span", comment, "Def+, ", "green"); + } else if (tactics[tactic].defMod < 0.1) { + App.UI.DOM.appendNewElement("span", comment, "Def-, ", "red"); + } + comment.append(tacticsDesc.get(tactic)); + option.addComment(comment); + } + node.append(options.render()); + + App.UI.DOM.appendNewElement("h3", node, `Troops`); + if (V.SF.Toggle && V.SF.Active >= 1 && V.SecExp.war.type.includes("Major")) { + options = new App.UI.OptionsGroup(); + options.addOption("The incoming attack's scale warrants deploying the special force.", "deploySF", V.SecExp.war) + .addValue("Green light", 1).on().addValue("Red light", 0).off() + .addComment("Some upgrades will be able to support your troops even if the special force is not deployed in the fight."); + node.append(options.render()); + } + + let linkArray = []; + if (V.SecExp.battles.lastSelection.length > 0) { + linkArray.push( + App.UI.DOM.link( + `Restore saved`, + () => { + V.SecExp.war.deployed = V.SecExp.battles.lastSelection; + V.SecExp.war.saveValid = 1; + V.SecExp.war.commander = V.SecExp.battles.saved.commander; + V.SecExp.war.deploySF = V.SecExp.battles.saved.sfSupport; + App.UI.reload(); + } + ) + ); + } else { + r.push(`Restore saved`); + } + if (V.SecExp.war.saveValid !== 1) { + linkArray.push( + App.UI.DOM.link( + `Save current`, + () => { + V.SecExp.battles.lastSelection = V.SecExp.war.deployed; + V.SecExp.war.saveValid = 1; + V.SecExp.battles.saved.commander = V.SecExp.war.commander; + V.SecExp.battles.saved.sfSupport = V.SecExp.war.deploySF; + App.UI.reload(); + } + ) + ); + } else { + r.push(`Save current`); + } + if (App.SecExp.battle.deployedUnits() > 0) { + linkArray.push( + App.UI.DOM.link( + `Clear current`, + () => { + V.SecExp.war.deployed = []; + V.SecExp.war.saveValid = 0; + App.UI.reload(); + } + ) + ); + } else { + r.push(`Clear current`); + } + if (V.SecExp.battles.lastSelection.length > 0) { + linkArray.push( + App.UI.DOM.link( + `Clear saved`, + () => { + V.SecExp.battles.lastSelection = []; + V.SecExp.war.saveValid = 0; + App.UI.reload(); + } + ) + ); + } else { + r.push(`Clear saved`); + } + node.append("Roster: ", App.UI.DOM.generateLinksStrip(linkArray)); + + // troop deployment + if (App.SecExp.battle.deployableUnits() > 0) { + r.push(`With your current readiness level you can send an additional`); + r.push(App.UI.DOM.makeElement("span", String(App.SecExp.battle.deployableUnits()), "strong")); + r.push(`units.`); + } + } else { + const isSlaveRebellion = V.SecExp.war.type.includes("Slave"); + r.push(`In the end it happened, the ${isSlaveRebellion ? "slaves" : "citizens"}`); + r.push(`of your arcology dared took up arms and rose up against their betters. Your penthouse is flooded with reports from all over the arcology of small skirmishes between the rioting slaves and the security forces. It appears <strong>${num(Math.trunc(V.SecExp.war.attacker.troops))}</strong> rebels are in the streets right now, building barricades and`); + if (isSlaveRebellion) { + r.push(`freeing their peers.`); + } else { + r.push(`destroying your property.`); + } + if (V.SecExp.war.attacker.equip <= 0) { + r.push(`They are <strong>poorly armed</strong>.`); + } else if (V.SecExp.war.attacker.equip === 1) { + r.push(`They are <strong>lightly armed</strong>.`); + } else if (V.SecExp.war.attacker.equip === 2) { + r.push(`They are <strong>decently armed</strong>.`); + } else if (V.SecExp.war.attacker.equip === 3) { + r.push(`They are <strong>well armed</strong>.`); + } else if (V.SecExp.war.attacker.equip >= 4) { + r.push(`They are <strong>extremely well armed</strong>.`); + } + if (V.SecExp.war.irregulars > 0) { + r.push(`${num(Math.trunc(V.SecExp.war.irregulars))} of your citizens took up arms to defend their arcology owner.`); + } + if (V.SecExp.war.rebellingID.length > 0) { + App.Events.addParagraph(node, r); + r = []; + let rebelling = []; + for (const squad of App.SecExp.unit.squads("human")) { + if (squad.active === 1 && (V.SecExp.war.rebellingID.includes(squad.ID))) { + rebelling.push(squad.platoonName); + } + } + r.push(`${toSentence(rebelling)} betrayed you and joined the insurrection.`); + } + let defending = []; + if (V.arcologyUpgrade.drones === 1) { + defending.push(`Your security drones`); + } + for (const squad of App.SecExp.unit.squads("human")) { + if (squad.active === 1 && (!V.SecExp.war.rebellingID.includes(squad.ID))) { + defending.push(squad.platoonName); + } + } + if (V.SF.Toggle && V.SF.Active >= 1) { + let SFname = defending.length > 0 ? V.SF.Lower : capFirstChar(V.SF.Lower); + defending.push(`${SFname}, ${num(V.SF.ArmySize)} strong`); + } + if (defending.length > 0) { + App.Events.addParagraph(node, r); + r = []; + r.push(`${toSentence(defending)} are called to defend the arcology from this menace.`); + } + App.Events.addParagraph(node, r); + r = []; + r.push(`The confined spaces of the arcology and the number of vital yet delicate systems within its walls do not allow a lot of tactical flexibility. This will be a long and strenuous fight, street after street, barricade after barricade. In order to preserve the structural integrity of the building and the lives of our civilians, we will have to limit our firepower.`); + App.Events.addParagraph(node, r); + + let text; + if (V.SecExp.war.engageRule === 0) { + text = `Your troops will use only nonlethal weapons or light firearms to limit to the maximum the collateral damage. This will however weaken our troops considerably.`; + } else if (V.SecExp.war.engageRule === 1) { + text = `Your troops will limit the use of explosives and heavy weapons to limit considerably the collateral damage. This will however weaken our troops.`; + } else if (V.SecExp.war.engageRule === 2) { + text = `Your troops will not limit their arsenal. This will put the structure and your citizens at risk, but our troops will be at full capacity.`; + } else if (V.SecExp.war.engageRule === 3) { + text = `Your troops will make use of the special weaponry, equipment and infrastructure developed by the riot control center to surgically eliminate rebels and dissidents with little to no collateral damage.`; + } + if (text) { + App.UI.DOM.appendNewElement("div", node, text, "note"); + } + + const engageRules = new Map([ + [0, `Only light firearms and nonlethal weapons`], + [1, `No heavy ordnance`], + [2, `Normal engagement rules`], + ]); + if (V.SecExp.buildings.riotCenter && V.SecExp.buildings.riotCenter.advancedRiotEquip === 1) { + engageRules.set(3, `Advanced riot protocol`); + } + + for (const [value, text] of engageRules) { + App.UI.DOM.appendNewElement("div", node, App.UI.DOM.link( + text, + () => { + V.SecExp.war.engageRule = value; + App.UI.reload(); + } + )); + } + + App.Events.addParagraph(node, [`We can dedicate some of our forces to the protection of the vital parts of the arcology, doing so will prevent the failure of said systems, but will also take away strength from our assault.`]); + const locations = new Map([ + ["penthouseDefense", `penthouse`], + ["reactorDefense", `reactors`], + ["assistantDefense", `assistant's central CPU`], + ["waterwayDefense", `waterways`], + ]); + const activeDefenses = Array.from(locations.keys()).filter(loc => V.SecExp.war[loc] === 1); + if (activeDefenses.length > 0) { + App.UI.DOM.appendNewElement("div", node, `Your troops will garrison the ${toSentence(activeDefenses.map(loc => locations.get(loc)))}.`, "note"); + } + for (const [loc, text] of locations) { + const choices = []; + choices.push(App.UI.DOM.link( + `Garrison the ${text}`, + () => { + V.SecExp.war[loc] = 1; + App.UI.reload(); + } + )); + choices.push(App.UI.DOM.link( + `Discard the order`, + () => { + delete V.SecExp.war[loc]; + App.UI.reload(); + } + )); + App.UI.DOM.appendNewElement("div", node, App.UI.DOM.generateLinksStrip(choices)); + } + } + + node.append(App.SecExp.unit.replenishAll()); + if (isBattle) { + if (App.SecExp.battle.deployableUnits() === 0) { + App.UI.DOM.appendNewElement("div", node, `Unit roster full.`, "strong"); + } + options = new App.UI.OptionsGroup(); + options.addOption("Unit descriptions are", "unitDescriptions", V.SecExp.settings) + .addValueList([["Abbreviated", 1], ["Summarized", 0]]); + node.append(options.render()); + + const tabBar = new App.UI.Tabs.TabBar("SecExpAttackOptions"); + for (const [u] of App.SecExp.unit.list()) { + if (V.SecExp.units[u].squads.length > 0) { + tabBar.addTab(capFirstChar(u), u, unitTab(u)); + } + } + node.append(tabBar.render()); + } + + options = new App.UI.OptionsGroup(); + option = options.addCustomOption(isBattle ? "Send your orders" : "Actions"); + if (isBattle && App.SecExp.battle.deployedUnits() > 0 || !isBattle) { + option.addButton(isBattle ? `Deploy troops` : `Proceed`, () => { + V.SecExp.war.result = 4; // Sets to a value outside accepted range (-3, 3) to avoid evaluation problems + V.SecExp.war.foughtThisWeek = 1; + }, `conflictHandler`); + } else if (isBattle && App.SecExp.battle.deployedUnits() === 0) { + App.UI.DOM.appendNewElement("div", node, `You need at least a unit in your roster to proceed to battle.`, "red"); + } + if (isBattle) { + option.addButton(`Attempt to bribe (approximately ${cashFormat(Math.round(App.SecExp.battle.bribeCost() * (1 + either(-1, 1) * random(2) * 0.1)))})`, () => { + V.SecExp.war.result = 1; + V.SecExp.war.foughtThisWeek = 1; + }, `conflictHandler`); + } + option.addButton(`Surrender`, () => { + V.SecExp.war.result = -1; + V.SecExp.war.foughtThisWeek = 1; + }, "conflictReport"); + node.append(options.render()); + return node; + + // Battles + /** Generates the deploy menu for the unit. + * @param {FC.SecExp.PlayerHumanUnitTypeMod} [type] the class of unit to be checked. + */ + function unitTab(type) { + const frag = new DocumentFragment(); + for (const u of V.SecExp.units[type].squads.filter(s => s.active === 1 && s.troops > 0)) { + App.UI.DOM.appendNewElement("div", frag, App.SecExp.unit.describe(u, true)); + } + return frag; + }; + }; +}; diff --git a/src/Mods/SecExp/events/conflictReport.js b/src/Mods/SecExp/events/conflictReport.js index 9c16504f3e362774ac9be82cecf902c4c91926f7..aee28b9b3777209d7eddd9790db15ad0fb738b86 100644 --- a/src/Mods/SecExp/events/conflictReport.js +++ b/src/Mods/SecExp/events/conflictReport.js @@ -1446,9 +1446,7 @@ App.Events.conflictReport = function() { } App.Events.addParagraph(node, r); - if (inBattle) { - App.SecExp.unit.squads().forEach(s => s.isDeployed = 0); - } else { + if (inRebellion) { V.SecExp.rebellions[V.SecExp.war.type.toLowerCase().replace(' rebellion', '') + 'Progress'] = 0; V.SecExp.rebellions.tension = Math.clamp(V.SecExp.rebellions.tension - random(50, 100), 0, 100); if (slaveRebellion) { diff --git a/src/Mods/SecExp/events/rebellionOptions.js b/src/Mods/SecExp/events/rebellionOptions.js deleted file mode 100644 index 855b373e3b8e497bcb893ff87cd0a88e85faf9e4..0000000000000000000000000000000000000000 --- a/src/Mods/SecExp/events/rebellionOptions.js +++ /dev/null @@ -1,159 +0,0 @@ -App.Events.rebellionOptions = class rebellionOptions extends App.Events.BaseEvent { - eventPrerequisites() { - return [ - () => V.secExpEnabled > 0, - () => V.SecExp.war.foughtThisWeek === 0, - () => V.SecExp.war.type.includes("Rebellion") - ]; - } - - execute(node) { - let r = []; - V.nextButton = " "; - V.encyclopedia = "Battles"; - const isSlaveRebellion = V.SecExp.war.type.includes("Slave"); - - App.UI.DOM.appendNewElement("h2", node, `${V.SecExp.war.type}!`); - r.push(`In the end it happened, the ${isSlaveRebellion ? "slaves" : "citizens"}`); - r.push(`of your arcology dared took up arms and rose up against their betters. Your penthouse is flooded with reports from all over the arcology of small skirmishes between the rioting slaves and the security forces. It appears <strong>${num(Math.trunc(V.SecExp.war.attacker.troops))}</strong> rebels are in the streets right now, building barricades and`); - if (isSlaveRebellion) { - r.push(`freeing their peers.`); - } else { - r.push(`destroying your property.`); - } - if (V.SecExp.war.attacker.equip <= 0) { - r.push(`They are <strong>poorly armed</strong>.`); - } else if (V.SecExp.war.attacker.equip === 1) { - r.push(`They are <strong>lightly armed</strong>.`); - } else if (V.SecExp.war.attacker.equip === 2) { - r.push(`They are <strong>decently armed</strong>.`); - } else if (V.SecExp.war.attacker.equip === 3) { - r.push(`They are <strong>well armed</strong>.`); - } else if (V.SecExp.war.attacker.equip >= 4) { - r.push(`They are <strong>extremely well armed</strong>.`); - } - if (V.SecExp.war.irregulars > 0) { - r.push(`${num(Math.trunc(V.SecExp.war.irregulars))} of your citizens took up arms to defend their arcology owner.`); - } - if (V.SecExp.war.rebellingID.length > 0) { - App.Events.addParagraph(node, r); - r = []; - let rebelling = []; - for (const squad of App.SecExp.unit.squads("human")) { - if (squad.active === 1 && (V.SecExp.war.rebellingID.includes(squad.ID))) { - rebelling.push(squad.platoonName); - } - } - r.push(`${toSentence(rebelling)} betrayed you and joined the insurrection.`); - } - let defending = []; - if (V.arcologyUpgrade.drones === 1) { - defending.push(`Your security drones`); - } - for (const squad of App.SecExp.unit.squads("human")) { - if (squad.active === 1 && (!V.SecExp.war.rebellingID.includes(squad.ID))) { - defending.push(squad.platoonName); - } - } - if (V.SF.Toggle && V.SF.Active >= 1) { - let SFname = defending.length > 0 ? V.SF.Lower : capFirstChar(V.SF.Lower); - defending.push(`${SFname}, ${num(V.SF.ArmySize)} strong`); - } - if (defending.length > 0) { - App.Events.addParagraph(node, r); - r = []; - r.push(`${toSentence(defending)} are called to defend the arcology from this menace.`); - } - App.Events.addParagraph(node, r); - r = []; - r.push(`The confined spaces of the arcology and the number of vital yet delicate systems within its walls do not allow a lot of tactical flexibility. This will be a long and strenuous fight, street after street, barricade after barricade. In order to preserve the structural integrity of the building and the lives of our civilians, we will have to limit our firepower.`); - App.Events.addParagraph(node, r); - - let text; - if (V.SecExp.war.engageRule === 0) { - text = `Your troops will use only nonlethal weapons or light firearms to limit to the maximum the collateral damage. This will however weaken our troops considerably.`; - } else if (V.SecExp.war.engageRule === 1) { - text = `Your troops will limit the use of explosives and heavy weapons to limit considerably the collateral damage. This will however weaken our troops.`; - } else if (V.SecExp.war.engageRule === 2) { - text = `Your troops will not limit their arsenal. This will put the structure and your citizens at risk, but our troops will be at full capacity.`; - } else if (V.SecExp.war.engageRule === 3) { - text = `Your troops will make use of the special weaponry, equipment and infrastructure developed by the riot control center to surgically eliminate rebels and dissidents with little to no collateral damage.`; - } - if (text) { - App.UI.DOM.appendNewElement("div", node, text, "note"); - } - - const engageRules = new Map([ - [0, `Only light firearms and nonlethal weapons`], - [1, `No heavy ordnance`], - [2, `Normal engagement rules`], - ]); - if (V.SecExp.buildings.riotCenter && V.SecExp.buildings.riotCenter.advancedRiotEquip === 1) { - engageRules.set(3, `Advanced riot protocol`); - } - - for (const [value, text] of engageRules) { - App.UI.DOM.appendNewElement("div", node, App.UI.DOM.link( - text, - () => { - V.SecExp.war.engageRule = value; - reload(); - } - )); - } - - App.Events.addParagraph(node, [`We can dedicate some of our forces to the protection of the vital parts of the arcology, doing so will prevent the failure of said systems, but will also take away strength from our assault.`]); - - const locations = new Map([ - ["penthouseDefense", `penthouse`], - ["reactorDefense", `reactors`], - ["assistantDefense", `assistant's central CPU`], - ["waterwayDefense", `waterways`], - ]); - const activeDefenses = Array.from(locations.keys()).filter(loc => V.SecExp.war[loc] === 1); - if (activeDefenses.length > 0) { - App.UI.DOM.appendNewElement("div", node, `Your troops will garrison the ${toSentence(activeDefenses.map(loc => locations.get(loc)))}.`, "note"); - } - for (const [loc, text] of locations) { - const choices = []; - choices.push(App.UI.DOM.link( - `Garrison the ${text}`, - () => { - V.SecExp.war[loc] = 1; - reload(); - } - )); - choices.push(App.UI.DOM.link( - `Discard the order`, - () => { - delete V.SecExp.war[loc]; - reload(); - } - )); - App.UI.DOM.appendNewElement("div", node, App.UI.DOM.generateLinksStrip(choices)); - } - - node.append(App.SecExp.unit.replenishAll()); - App.UI.DOM.appendNewElement("div", node, App.UI.DOM.passageLink( - "Proceed", - "conflictHandler", - () => { - V.SecExp.war.result = 4; // Sets to a value outside accepted range (-3,3) to avoid evaluation problems - V.SecExp.war.foughtThisWeek = 1; - } - )); - App.UI.DOM.appendNewElement("div", node, App.UI.DOM.passageLink( - "Surrender", - "conflictReport", - () => { - V.SecExp.war.result = -1; - V.SecExp.war.foughtThisWeek = 1; - } - )); - - function reload() { - $(node).empty(); - new App.Events.rebellionOptions().execute(node); - } - } -}; diff --git a/src/Mods/SecExp/js/Unit.js b/src/Mods/SecExp/js/Unit.js index f57948fd59ce17798507a9e115499bb997072547..06ed89666f93c20bc68d048ac251f0c0c7659341 100644 --- a/src/Mods/SecExp/js/Unit.js +++ b/src/Mods/SecExp/js/Unit.js @@ -80,7 +80,7 @@ App.SecExp.unit = (function() { } /** Calculate the unit type via passed unitID. - * @returns {FC.SecExp.PlayerHumanUnitType} + * @returns {FC.SecExp.PlayerHumanUnitTypeMod} */ function checkID(unitID) { for (const [u, d] of list()) { @@ -125,19 +125,18 @@ App.SecExp.unit = (function() { let newUnit = { equip: 0, active: 1, maxTroops: 30, troops: 30, - ID: -1, isDeployed: 0 + platoonName: `${ordinalSuffix(V.SecExp.units[type].created)} ${V.SecExp.units[type].defaultName}` }; if (type !== "bots") { Object.assign(newUnit, { training: 0, cyber: 0, medics: 0, SF: 0, commissars: 0, battlesFought: 0, loyalty: jsRandom(40, 60), - ID: genID(), }); newUnit.troops = Math.min(newUnit.maxTroops, unitFree(type).print()); unitFree(type).remove(newUnit.troops); } - newUnit.platoonName = `${ordinalSuffix(V.SecExp.units[type].created)} ${V.SecExp.units[type].defaultName}`; + genID(newUnit, type); V.SecExp.units[type].squads.push(newUnit); } } @@ -152,7 +151,7 @@ App.SecExp.unit = (function() { let linkArray = []; linkArray.push("Default unit name:", App.UI.DOM.makeTextBox(V.SecExp.units[type].defaultName, str => { V.SecExp.units[type].defaultName = str; App.UI.reload(); })); - if (type !== "bots" && unitFree(type).canUpgrade() && App.SecExp.battle.activeUnits() < App.SecExp.battle.maxUnits()) { + if (unitFree(type).canUpgrade() && App.SecExp.battle.activeUnits() < App.SecExp.battle.maxUnits()) { linkArray.push(App.UI.DOM.link(`Form a new unit`, () => { generate(type, true); if (type === "bots") { @@ -176,20 +175,18 @@ App.SecExp.unit = (function() { App.UI.DOM.appendNewElement("div", unitDetail, describe(unit, type)); linkArray.push(App.UI.DOM.makeTextBox(unit.platoonName, str => { unit.platoonName = str; App.UI.reload(); })); - if (type !== "bots") { - linkArray.push(App.UI.DOM.link(`Disband the unit`, () => { - unitFree(type).add(unit.troops); - V.SecExp.units[type].squads.deleteAt(i); - V.SecExp.battles.lastSelection.deleteAt(i); - App.UI.reload(); - } - )); + linkArray.push(App.UI.DOM.link(`Disband the unit`, () => { + unitFree(type).add(unit.troops); + V.SecExp.units[type].squads.deleteAt(i); + V.SecExp.battles.lastSelection.deleteAt(i); + App.UI.reload(); } + )); if (unit.active === 1) { if (unit.troops < unit.maxTroops && unitFree(unit).canUpgrade()) { linkArray.push(App.UI.DOM.link(`Replenish unit`, () => { - replenish(unit, type); + replenish(unit); App.UI.reload(); } )); @@ -379,17 +376,16 @@ App.SecExp.unit = (function() { function replenishAll() { let el = document.createElement("div"); let woundedUnit = new Map([]); - for (const unit of Array.from(list().keys())) { - for (const squad of V.SecExp.units[unit].squads) { - if (squad.troops < squad.maxTroops && unitFree(unit).canUpgrade()) { - woundedUnit.set(unit); - } + for (const squad of App.SecExp.unit.squads()) { + const unit = checkID(squad.ID); + if (squad.troops < squad.maxTroops && unitFree(unit).canUpgrade()) { + woundedUnit.set(unit); } } if (woundedUnit.size > 0) { el.append(App.UI.DOM.link("Replenish all units", () => { for (const [u] of woundedUnit) { - V.SecExp.units[u].squads.forEach(s => replenish(s, u)); + V.SecExp.units[u].squads.forEach(s => replenish(s)); } App.UI.reload(); } @@ -404,28 +400,34 @@ App.SecExp.unit = (function() { * @returns {boolean} */ function isDeployed(unit) { - return (V.SecExp.war.type.includes("Attack") && unit.isDeployed === 1) || (V.SecExp.war.type.includes("Rebellion") && unit.active === 1 && !V.SecExp.war.rebellingID.includes(unit.ID)); + return V.SecExp.war && (V.SecExp.war.type.includes("Attack") && V.SecExp.war.deployed.includes(unit.ID)) || (V.SecExp.war.type.includes("Rebellion") && unit.active === 1 && !V.SecExp.war.rebellingID.includes(unit.ID)); } /** * @param {FC.SecExp.PlayerHumanUnitData} input - * @param {FC.SecExp.PlayerHumanUnitTypeMod} unitType * @param {boolean} inBattle - if true appends a deploy/recall link to the description, allowing for [input] to be deployed/recalled. * @returns {HTMLDivElement} */ - function describe(input, unitType, inBattle = false) { + function describe(input, inBattle = false) { const brief = V.SecExp.settings.unitDescriptions; + const unitType = App.SecExp.unit.checkID(input.ID); let el = new DocumentFragment(); if (inBattle) { const canDeploy = !isDeployed(input) && App.SecExp.battle.deployableUnits() > 0; el.append(App.UI.DOM.link(`(${canDeploy ? 'Deploy' : 'Recall'}) `, () => { - input.isDeployed = canDeploy ? 1 : 0; + if (canDeploy) { + V.SecExp.war.deployed.push(input.ID); + } else { + V.SecExp.war.deployed.deleteAt(s => s === input.ID); + } V.SecExp.war.saveValid = 0; App.UI.reload(); } )); } + App.UI.DOM.appendNewElement("span", el, `${input.platoonName}`, "bold"); + App.UI.DOM.appendNewElement("span", el, `${!brief ? ``:`. `} `); App.UI.DOM.appendNewElement("span", el, `${input.platoonName}`, "bold"); App.UI.DOM.appendNewElement("span", el, `${!brief ? ``:`. `} `); @@ -593,24 +595,40 @@ App.SecExp.unit = (function() { function squads(type = '') { let array = Object.values(V.SecExp.units).map(s => s.squads).flatten(); switch(type) { - case "human": - array = []; - for (const unit of Array.from(list().keys()).slice(1)) { - for (const squad of V.SecExp.units[unit].squads) { - array.push(squad); - } - } + case "human": return array.filter(s => checkID(s.ID) !== "bots"); } return array; } /** Generate a unit ID for a new unit - * @returns {number} + * @param {FC.SecExp.PlayerHumanUnitData} squad + * @param {FC.SecExp.PlayerHumanUnitTypeMod} unit + * @returns {void} */ - function genID() { - return Math.max( - squads("human").map(u => u.ID).reduce((acc, cur) => Math.max(acc, cur), 0) - ) + 1; + function genID(squad, unit) { + if (V.SecExp.units[unit].squads.filter(s => !s.ID.isBetween(list().get(unit).baseID, list().get(unit).maxID, true)).length) { + const oldID = squad.ID; + let location; + const newID = list().get(unit).baseID + (unit === 'bots' ? 0 : oldID); + if (V.SecExp.battles.lastSelection && V.SecExp.battles.lastSelection.includes(oldID) || V.lastSelection && V.lastSelection.includes(oldID)) { + if (V.SecExp.battles.lastSelection) { + location = V.SecExp.battles.lastSelection.indexOf(oldID); + } else { + location = V.lastSelection.indexOf(oldID); + V.SecExp.battles.lastSelection = []; + } + V.SecExp.battles.lastSelection[location] = newID; + } + squad.ID = newID; + } else if (!jsDef(squad.ID)) { + if (V.SecExp.units[unit].squads.length === 0) { + squad.ID = list().get(unit).baseID; + } else { + squad.ID = Math.max( + V.SecExp.units[unit].squads.map(u => u.ID).reduce((acc, cur) => Math.max(acc, cur), 0) + ) + 1; + } + } } /** performs operations on a unit @@ -692,10 +710,10 @@ App.SecExp.unit = (function() { /** Replenishes a unit if needed * helper function, not callable externally * @param {FC.SecExp.PlayerHumanUnitData} squad - * @param {FC.SecExp.PlayerHumanUnitTypeMod} type */ - function replenish(squad, type) { + function replenish(squad) { const oldTroops = squad.troops; + const type = checkID(squad.ID); if (type !== "bots") { if (unitFree(type).print() >= squad.maxTroops - squad.troops) { @@ -718,7 +736,7 @@ App.SecExp.unit = (function() { * @param {object} [unit] the unit to be checked * @param {string} [type] the type of unit to be checked */ - function bulkUpgrade(unit, type) { + function bulkUpgrade(unit, type) { unit = Array.isArray(unit) ? unit : [unit]; let el = document.createElement("a"); @@ -800,11 +818,11 @@ App.SecExp.getUnit = function(type, index) { case "bots": return new App.SecExp.DroneUnit(V.SecExp.units.bots.squads[index], App.SecExp.BaseDroneUnit); case "militia": - return new App.SecExp.HumanUnit(V.SecExp.units.militia.squads[index], App.SecExp.BaseMilitiaUnit, type); + return new App.SecExp.HumanUnit(V.SecExp.units.militia.squads[index], App.SecExp.BaseMilitiaUnit); case "slaves": - return new App.SecExp.HumanUnit(V.SecExp.units.slaves.squads[index], App.SecExp.BaseSlaveUnit, type); + return new App.SecExp.HumanUnit(V.SecExp.units.slaves.squads[index], App.SecExp.BaseSlaveUnit); case "mercs": - return new App.SecExp.HumanUnit(V.SecExp.units.mercs.squads[index], App.SecExp.BaseMercUnit, type); + return new App.SecExp.HumanUnit(V.SecExp.units.mercs.squads[index], App.SecExp.BaseMercUnit); default: throw Error(`Unknown unit type: ${type}`); } @@ -1184,7 +1202,7 @@ App.SecExp.Unit = class SecExpUnit { } /** @abstract - * @returns {string} */ + * @returns {DocumentFragment} */ printStats() { throw Error("derive me"); } @@ -1227,12 +1245,10 @@ App.SecExp.DroneUnit = class SecExpDroneUnit extends App.SecExp.Unit { App.SecExp.HumanUnit = class SecExpHumanUnit extends App.SecExp.Unit { /** @param {FC.SecExp.PlayerHumanUnitData} data * @param {BaseUnit} baseUnit - * @param {string} descriptionType */ - constructor(data, baseUnit, descriptionType) { + constructor(data, baseUnit) { super(data, baseUnit); this._data = data; // duplicate assignment, just for TypeScript - this._descType = descriptionType; } get attack() { @@ -1259,6 +1275,7 @@ App.SecExp.HumanUnit = class SecExpHumanUnit extends App.SecExp.Unit { printStats() { let r = new DocumentFragment(); + this._descType = App.SecExp.unit.checkID(this._data.ID); App.UI.DOM.appendNewElement("div", r, `${this._descType} base attack: ${this._baseUnit.attack} (After modifiers: ${Math.trunc(this.attack)})`); App.UI.DOM.appendNewElement("div", r, `${this._descType} base defense: ${this._baseUnit.defense} (After modifiers: ${Math.trunc(this.defense)})`); if (this._data.equip > 0) { diff --git a/src/Mods/SecExp/js/secExpBC.js b/src/Mods/SecExp/js/secExpBC.js index 8a869cbb91bc64a63fe41f3f7dbd86d0cfe35dc5..4ac09e38c24dfa6842b63a18581684b184dacaa6 100644 --- a/src/Mods/SecExp/js/secExpBC.js +++ b/src/Mods/SecExp/js/secExpBC.js @@ -111,12 +111,15 @@ App.SecExp.generalBC = function() { if (V.SF.Active < 1) { u.SF = 0; } + } - if (unit !== 'bots' && u.platoonName.contains('undefined')) { - u.platoonName = u.platoonName.replace('undefined', data.defaultName); - } - u.equip = u.equip || 0; + if (unit !== 'bots' && u.platoonName.contains('undefined')) { + u.platoonName = u.platoonName.replace('undefined', data.defaultName); } + + App.SecExp.unit.genID(u, unit); + u.equip = u.equip || 0; + delete u.isDeployed; }); } diff --git a/src/Mods/SecExp/js/securityReport.js b/src/Mods/SecExp/js/securityReport.js index c683497f166d2d42bffbc6357a5242532856ad65..ca7f03a1bf6ee6470128ba22424032631f932802 100644 --- a/src/Mods/SecExp/js/securityReport.js +++ b/src/Mods/SecExp/js/securityReport.js @@ -454,10 +454,8 @@ App.SecExp.securityReport = function() { } if (activeUnits > 0) { // loyalty and training - for (const [unit] of Array.from(App.SecExp.unit.list()).slice(1)) { - for (const squad of V.SecExp.units[unit].squads) { - r.push(App.SecExp.humanLoyaltyChanges(squad, unit)); - } + for (const squad of App.SecExp.unit.squads("human")) { + r.push(App.SecExp.humanLoyaltyChanges(squad)); } } } diff --git a/src/Mods/SecExp/potentialToDo.txt b/src/Mods/SecExp/potentialToDo.txt index 115cabfcfd0894eb133db51d6e2453a60f33cd5b..869d8e71ab6d3cda28dd801c8df7bf6258b92a32 100644 --- a/src/Mods/SecExp/potentialToDo.txt +++ b/src/Mods/SecExp/potentialToDo.txt @@ -3,10 +3,6 @@ Hexall90's last merged commit: 52dde0b3 - Can other Arcologies assist with the attacks from your Arcology? Like if you're being attacked by raiders they send some rapid-deployment forces and help you but when it's the Old world they wouldn't in fear of being criticize or something - Or sending your troops to help other arcologies to earn reputation, POW as menials and captured military assets for cash, to boost cultural exchange and economic development. Or choosing not to send troops (if rival) to lower its value and to preverse your cultural independance. -- Remove unit.isDeployed as it is only used in battles and add the IDs to an array. - This would require that units have unique IDs (e.g bots: -1 -> 99, militia: 100 -> 199, slaves: 200 -> 299, mercs: 300 - 399, etc). - It would also allow for _*RebelledID to potentially be removed. - - While at it something for barracks(general? commissar?) and riot center([Insert player title there]'s Will?? Big Sister? ) too would be nice - While at it decoupling of propaganda slave and recruiter when? - Would it be possible to add option for assigning hacker to security HQ that would work similarly to giving office for recruiter in propaganda hub? Preferably with smiling man slave giving extra bonuses there @@ -34,7 +30,6 @@ Hexall90's last merged commit: 52dde0b3 - Suggestion - Arcology Conquest - https://gitgud.io/pregmodfan/fc-pregmod/issues/760 - Does forcing every citizen to be in military raise appeal of slaves that know how to fight? - And if I am a master tactician, maybe I could get an estimate how effective the various tactics could be? -- Ability to create more drone squads. - Increase base maximum units to 18, 20 with SF. - Suggestion - Gradual Battle Frequency - https://gitgud.io/pregmodfan/fc-pregmod/issues/1245#note_82504 - Option to send slaves into military unit to gain some nice scars and experience wold be nice (with retrieval). diff --git a/src/events/nonRandomEvent.js b/src/events/nonRandomEvent.js index 3b49dc3aed58b99db6eed37e7fafd359e72e7bda..1a779e55824c9ff576931f41d2b4f498677e4bd6 100644 --- a/src/events/nonRandomEvent.js +++ b/src/events/nonRandomEvent.js @@ -9,8 +9,7 @@ App.Events.getNonrandomEvents = function() { // instantiate all possible scheduled/nonrandom events here // ORDER MATTERS - if multiple events from this list trigger in a single week, they are executed in this order - new App.Events.rebellionOptions(), - new App.Events.attackOptions(), + new App.Events.conflictOptions(), new App.Events.SEPlayerBirth(), new App.Events.SEpcBirthday(), new App.Events.SEIndependenceDay(),