code:
App.Events.conflictHandler = function() {
	V.nextButton = " ";
	V.encyclopedia = "Battles";

	const node = new DocumentFragment();
	const showStats = V.SecExp.settings.showStats === 1;
	const inBattle = V.SecExp.war.type.includes("Attack");
	const isMajorBattle = inBattle && V.SecExp.war.type.includes("Major");
	const inRebellion = V.SecExp.war.type.includes("Rebellion");
	const turns = (isMajorBattle || inRebellion) ? 20 : 10;
	const showProgress = function(message, tag = "div") {
		if (showStats) {
			App.UI.DOM.appendNewElement(tag, node, message);
		}
	};
	const setResult = function(varA, varB, text, value, count) {
		if (varA <= 0 || varB <= 0) {
			showProgress(`${text}!`);
			V.SecExp.war.result = value;
			V.SecExp.war.turns = count;
		}
	};
	const atEnd = function(passage) {
		if (showStats) {
			App.UI.DOM.appendNewElement("div", node, App.UI.DOM.passageLink("Proceed", passage));
		} else {
			setTimeout(() => Engine.play(passage), Engine.minDomActionDelay);
		}
	};
	const turnReport = function() {
		showProgress(`Turn: ${i + 1}`);
		// player army attacks
		damage = Math.round(Math.clamp(attack.total - enemyDefense, attack.total * 0.1, attack.total));
		showProgress(`Player damage: ${num(Math.round(damage))}`);
		enemyHp -= damage;
		showProgress(`Remaining enemy Hp: ${num(Math.round(enemyHp))}`);
		V.SecExp.war.attacker.losses += damage / enemyBaseHp;
		enemyMorale -= Math.clamp(damage / 2 + damage / enemyBaseHp, 0, damage * 1.5);
		showProgress(`Remaining enemy morale: ${num(Math.round(enemyMorale))}`);
		setResult(enemyHp, enemyMorale, 'Victory', 3, i);

		// OpFor army attacks
		damage = enemyAttack - defense.total;
		if (damage < enemyAttack * 0.1) {
			damage = enemyAttack * 0.1;
		}
		damage = Math.round(damage);
		showProgress(`Enemy damage: ${num(Math.round(damage))}`);
		hp.total -= damage * (inRebellion && V.SecExp.rebellions.sfArmor ? 0.85 : 1);
		showProgress(`Remaining hp: ${num(Math.round(hp.total))}`);
		V.SecExp.war.losses += damage / baseHp;
		morale.total -= Math.clamp(damage / 2 + damage / baseHp, 0, damage * 1.5);
		showProgress(`Remaining morale: ${num(Math.round(morale.total))}`);
		setResult(hp.total, morale.total, 'Defeat', -3, i);
	};

	let unitData;
	let damage;
	let baseHp;
	let enemyBaseHp;
	let enemyMorale;
	let attack = {base: 0, modifier: 1};
	let defense = {base: 0, modifier: 1};
	let morale = {base: 0};
	let hp = {base: 0};
	let enemyAttack = 0;
	let enemyDefense = 0;
	let enemyHp = 0;
	let armyMod = V.SecExp.war.attacker.troops / (inBattle ? 80 : 100);
	const activeSF = V.SF.Toggle && V.SF.Active >= 1;
	// Battles
	morale.militia = (isMajorBattle) ? 1.5 : 1;
	morale.slaves = (isMajorBattle) ? 1.5 : 1;
	morale.mercs = (isMajorBattle) ? 1.5 : 1;
	morale.enemy = (isMajorBattle) ? 1.5 : 1;
	morale.SF = (isMajorBattle) ? 1.5 : 1;
	let tacChance = 0.5; // by default tactics have a 50% chance of succeeding
	// Rebellions
	let irregularMod = V.SecExp.war.irregulars / 60;
	let engageMod = 0.5; // V.SecExp.war.engageRule === 0
	let rebellingSlaves = 0;
	let rebellingMilitia = 0;

	if (inBattle && V.SecExp.war.result === 1 || V.SecExp.war.result === -1) { // bribery/surrender check
		showProgress(`${V.SecExp.war.result === 1 ? 'Bribery' : 'Surrender'} chosen`);
		if (inBattle && V.SecExp.war.result === 1) {
			if (V.cash >= App.Mods.SecExp.battle.bribeCost()) { // if there's enough cash there's a 10% chance bribery fails. If there isn't there's instead a 50% chance it fails
				if (V.SecExp.war.attacker.type === "freedom fighters" && random(1, 100) <= 50 || random(1, 100) <= 10) {
					V.SecExp.war.result = 0;
				}
			} else {
				if (random(1, 100) <= 50) {
					V.SecExp.war.result = 0;
				}
			}
			showProgress(`${V.SecExp.war.result === 0 ? 'Failed' : 'Successful'}!`, "span");
			atEnd("conflictReport");
			return node;
		}
	}

	if (inBattle) {
		if (isMajorBattle) {
			if (activeSF) {
				if (V.SF.Squad.Firebase >= 7) {
					attack.modifier += (V.SF.Squad.Firebase - 6) * 0.05;
				}
				if (V.SF.Squad.GunS >= 1) {
					defense.modifier += V.SF.Squad.GunS * 0.05;
				}
				if (V.SF.Squad.Satellite >= 5 && V.SF.SatLaunched > 0) {
					attack.modifier += (V.SF.Squad.Satellite - 5) * 0.05;
				}
				if (V.SF.Squad.GiantRobot >= 6) {
					defense.modifier += (V.SF.Squad.GiantRobot - 5) * 0.05;
				}
				if (V.SF.Squad.MissileSilo >= 1) {
					attack.modifier += V.SF.Squad.MissileSilo * 0.05;
				}
			}
		}

		const commanderEffectiveness = App.Mods.SecExp.commanderEffectiveness("handler");
		morale.slaves += commanderEffectiveness.slaveMod;
		morale.militia += commanderEffectiveness.militiaMod;
		morale.mercs += commanderEffectiveness.militiaMod;
		morale.SF += commanderEffectiveness.SFMod;
		morale.enemy += commanderEffectiveness.enemyMod;
		attack.modifier += commanderEffectiveness.atkMod;
		defense.modifier += commanderEffectiveness.defMod;
		tacChance += commanderEffectiveness.tacChance;

		// Terrain and Tactics
		const tacticsObj = App.Data.SecExp.TerrainAndTactics.get(V.SecExp.war.terrain)[V.SecExp.war.chosenTactic];
		attack.modifier += tacticsObj.atkMod;
		defense.modifier += tacticsObj.defMod;
		tacChance += tacticsObj.tacChance;

		if (V.SecExp.war.chosenTactic === "Bait and Bleed") {
			if (V.SecExp.war.attacker.type === "raiders") {
				tacChance -= 0.10;
			} else if (V.SecExp.war.attacker.type === "free city") {
				tacChance += 0.10;
			} else if (V.SecExp.war.attacker.type === "old world") {
				tacChance += 0.25;
			} else if (V.SecExp.war.attacker.type === "freedom fighters") {
				tacChance -= 0.15;
			}
		} else if (V.SecExp.war.chosenTactic === "Guerrilla") {
			if (V.SecExp.war.attacker.type === "raiders") {
				tacChance -= 0.20;
			} else if (V.SecExp.war.attacker.type === "free city") {
				tacChance += 0.15;
			} else if (V.SecExp.war.attacker.type === "old world") {
				tacChance += 0.25;
			} else if (V.SecExp.war.attacker.type === "freedom fighters") {
				tacChance -= 0.25;
			}
		} else if (V.SecExp.war.chosenTactic === "Choke Points") {
			if (V.SecExp.war.attacker.type === "raiders") {
				tacChance += 0.25;
			} else if (V.SecExp.war.attacker.type === "free city") {
				tacChance -= 0.05;
			} else if (V.SecExp.war.attacker.type === "old world") {
				tacChance -= 0.10;
			} else if (V.SecExp.war.attacker.type === "freedom fighters") {
				tacChance += 0.05;
			}
		} else if (V.SecExp.war.chosenTactic === "Interior Lines") {
			if (V.SecExp.war.attacker.type === "raiders") {
				tacChance -= 0.15;
			} else if (V.SecExp.war.attacker.type === "free city") {
				tacChance += 0.15;
			} else if (V.SecExp.war.attacker.type === "old world") {
				tacChance += 0.20;
			} else if (V.SecExp.war.attacker.type === "freedom fighters") {
				tacChance -= 0.10;
			}
		} else if (V.SecExp.war.chosenTactic === "Pincer Maneuver") {
			if (V.SecExp.war.attacker.type === "raiders") {
				tacChance += 0.15;
			} else if (V.SecExp.war.attacker.type === "free city") {
				tacChance += 0.10;
			} else if (V.SecExp.war.attacker.type === "old world") {
				tacChance -= 0.10;
			} else if (V.SecExp.war.attacker.type === "freedom fighters") {
				tacChance += 0.15;
			}
		} else if (V.SecExp.war.chosenTactic === "Defense In Depth") {
			if (V.SecExp.war.attacker.type === "raiders") {
				tacChance -= 0.20;
			} else if (V.SecExp.war.attacker.type === "free city") {
				tacChance += 0.10;
			} else if (V.SecExp.war.attacker.type === "old world") {
				tacChance += 0.20;
			} else if (V.SecExp.war.attacker.type === "freedom fighters") {
				tacChance -= 0.05;
			}
		} else if (V.SecExp.war.chosenTactic === "Blitzkrieg") {
			if (V.SecExp.war.attacker.type === "raiders") {
				tacChance += 0.10;
			} else if (V.SecExp.war.attacker.type === "free city") {
				tacChance -= 0.20;
			} else if (V.SecExp.war.attacker.type === "old world") {
				tacChance += 0.25;
			} else if (V.SecExp.war.attacker.type === "freedom fighters") {
				tacChance -= 0.10;
			}
		} else if (V.SecExp.war.chosenTactic === "Human Wave") {
			if (V.SecExp.war.attacker.type === "raiders") {
				tacChance -= 0.10;
			} else if (V.SecExp.war.attacker.type === "free city") {
				tacChance += 0.10;
			} else if (V.SecExp.war.attacker.type === "old world") {
				tacChance -= 0.15;
			} else if (V.SecExp.war.attacker.type === "freedom fighters") {
				tacChance += 0.10;
			}
		}
		tacChance = Math.clamp(tacChance, 0.1, tacChance); // Calculates if tactics are successful - minimum chance is 10%

		if (random(1, 100) <= tacChance * 100) {
			morale.enemy -= 0.30;
			morale.militia += 0.20;
			morale.slaves += 0.20;
			morale.mercs += 0.20;
			attack.modifier += 0.10;
			defense.modifier += 0.10;
			V.SecExp.war.tacticsSuccessful = 1;
		} else {
			morale.enemy += 0.20;
			morale.militia -= 0.20;
			morale.slaves -= 0.20;
			morale.mercs -= 0.20;
			attack.modifier -= 0.10;
			defense.modifier -= 0.10;
		}

		// enemy morale mods
		if (V.week < 30) {
			morale.enemy += 0.15;
		} else if (V.week < 60) {
			morale.enemy += 0.30;
		} else if (V.week < 90) {
			morale.enemy += 0.45;
		} else if (V.week < 120) {
			morale.enemy += 0.60;
		} else {
			morale.enemy += 0.75;
		}
	}

	// calculates PC army stats
	if (inRebellion) {
		if (V.SecExp.war.engageRule === 1) {
			engageMod = 0.75;
		} else if (V.SecExp.war.engageRule === 2) {
			engageMod = 1;
		} else if (V.SecExp.war.engageRule > 2) {
			engageMod = 1.4;
		}

		if (V.week > 30 && V.week <= 60) {
			irregularMod = V.SecExp.war.irregulars / 50;
		} else if (V.week <= 90) {
			irregularMod = V.SecExp.war.irregulars / 40;
		} else if (V.week <= 120) {
			irregularMod = V.SecExp.war.irregulars / 30;
		} else {
			irregularMod = V.SecExp.war.irregulars / 20;
		}
		if (V.SecExp.war.irregulars > 0) {
			irregularMod = Math.trunc(irregularMod);
			unitData = App.Mods.SecExp.getIrregularUnit("militia", V.SecExp.war.irregulars, V.SecExp.war.attacker.equip);
			attack.irregulars = unitData.attack * irregularMod * 0.80;
			defense.irregulars = unitData.defense * irregularMod * 0.80;
			hp.irregulars = unitData.hp;
		}
	}

	for (const type of Array.from(App.Mods.SecExp.unit.list().keys())) {
		for (const unit of V.SecExp.units[type].squads) {
			if (App.Mods.SecExp.unit.isDeployed(unit)) {
				unitData = App.Mods.SecExp.getUnit(type, unit);
				attack.base += unitData.attack * unitData.attack;
				defense.base += unitData.defense * unitData.defense;
				hp.base += unitData.hp;
			}
		}
	}

	if (activeSF && (inBattle && V.SecExp.war.deploySF || inRebellion)) {
		unitData = App.Mods.SecExp.getUnit("SF");
		attack.SF = unitData.attack;
		defense.SF = unitData.defense;
		hp.SF = unitData.hp;
	}

	if (inRebellion) {
		for (const zone of ["assistant", "reactor", "penthouse", "waterway"]) {
			if (V.SecExp.war[zone + "Defense"]) {
				attack.base *= 0.95;
				defense.base *= 0.95;
				hp.base *= 0.95;
			}
		}
	}

	// morale and baseHp calculation
	if (inBattle) { // minimum modifier is -50%, maximum is +50%
		morale.slaves = Math.clamp(morale.slaves, 0.5, 1.5);
		morale.militia = Math.clamp(morale.militia, 0.5, 1.5);
		morale.mercs = Math.clamp(morale.mercs, 0.5, 1.5);
		morale.SF = Math.clamp(morale.SF, 0.5, 1.5);
	}
	const moraleTroopMod = Math.clamp(App.Mods.SecExp.battle.troopCount() / 100, 1, (inBattle ? 5 : 10));
	const modifierSF = activeSF ? 1 : 0;

	if (inBattle) {
		morale.total = (App.Mods.SecExp.BaseDroneUnit.morale * App.Mods.SecExp.battle.deployedUnits('bots') + App.Mods.SecExp.BaseMilitiaUnit.morale * morale.militia * App.Mods.SecExp.battle.deployedUnits('militia') + App.Mods.SecExp.BaseSlaveUnit.morale * morale.slaves * App.Mods.SecExp.battle.deployedUnits('slaves') + App.Mods.SecExp.BaseMercUnit.morale * morale.mercs * App.Mods.SecExp.battle.deployedUnits('mercs') + App.Mods.SecExp.BaseSpecialForcesUnit.morale * V.SecExp.war.deploySF * morale.SF) / (App.Mods.SecExp.battle.deployedUnits('bots') + App.Mods.SecExp.battle.deployedUnits('militia') + App.Mods.SecExp.battle.deployedUnits('slaves') + App.Mods.SecExp.battle.deployedUnits('mercs') + V.SecExp.war.deploySF);
		if (V.SecExp.buildings.barracks) {
			morale.total += morale.total * V.SecExp.buildings.barracks.luxury * 0.05;	// barracks bonus
		}
	} else {
		morale.total = (App.Mods.SecExp.BaseDroneUnit.morale * App.Mods.SecExp.battle.deployedUnits('bots') + App.Mods.SecExp.BaseMilitiaUnit.morale * App.Mods.SecExp.battle.deployedUnits('militia') + App.Mods.SecExp.BaseSlaveUnit.morale * App.Mods.SecExp.battle.deployedUnits('slaves') + App.Mods.SecExp.BaseMercUnit.morale * App.Mods.SecExp.battle.deployedUnits('mercs') + App.Mods.SecExp.BaseSpecialForcesUnit.morale * modifierSF) / (App.Mods.SecExp.battle.deployedUnits('bots') + App.Mods.SecExp.battle.deployedUnits('militia') + App.Mods.SecExp.battle.deployedUnits('slaves') + App.Mods.SecExp.battle.deployedUnits('mercs') + modifierSF);
		morale.total += morale.total * (V.SecExp.buildings.barracks ? V.SecExp.buildings.barracks.luxury * 0.05 : 1);	// barracks bonus
	}
	morale.total *= moraleTroopMod;
	if (inBattle) {
		baseHp = (App.Mods.SecExp.BaseDroneUnit.hp * App.Mods.SecExp.battle.deployedUnits('bots') + App.Mods.SecExp.BaseMilitiaUnit.hp * App.Mods.SecExp.battle.deployedUnits('militia') + App.Mods.SecExp.BaseSlaveUnit.hp * App.Mods.SecExp.battle.deployedUnits('slaves') + App.Mods.SecExp.BaseMercUnit.hp * App.Mods.SecExp.battle.deployedUnits('mercs') + App.Mods.SecExp.BaseSpecialForcesUnit.hp * V.SecExp.war.deploySF) / (App.Mods.SecExp.battle.deployedUnits('bots') + App.Mods.SecExp.battle.deployedUnits('militia') + App.Mods.SecExp.battle.deployedUnits('slaves') + App.Mods.SecExp.battle.deployedUnits('mercs') + V.SecExp.war.deploySF);
	} else {
		baseHp = (App.Mods.SecExp.BaseDroneUnit.hp * App.Mods.SecExp.battle.deployedUnits('bots') + App.Mods.SecExp.BaseMilitiaUnit.hp * App.Mods.SecExp.battle.deployedUnits('militia') + App.Mods.SecExp.BaseSlaveUnit.hp * App.Mods.SecExp.battle.deployedUnits('slaves') + App.Mods.SecExp.BaseMercUnit.hp * App.Mods.SecExp.battle.deployedUnits('mercs') + App.Mods.SecExp.BaseSpecialForcesUnit.hp * modifierSF) / (App.Mods.SecExp.battle.deployedUnits('bots') + App.Mods.SecExp.battle.deployedUnits('militia') + App.Mods.SecExp.battle.deployedUnits('slaves') + App.Mods.SecExp.battle.deployedUnits('mercs') + modifierSF);
	}

	// calculates opposing army stats
	if (V.week > 30 && V.week <= 60) {
		armyMod = V.SecExp.war.attacker.troops / (inBattle ? 75 : 90);
	} else if (V.week <= 90) {
		armyMod = V.SecExp.war.attacker.troops / (inBattle ? 70 : 80);
	} else if (V.week <= 120) {
		armyMod = V.SecExp.war.attacker.troops / (inBattle ? 65 : 70);
	} else if (V.week > 120) {
		armyMod = V.SecExp.war.attacker.troops / 60;
	}
	armyMod = Math.trunc(armyMod);
	if (isMajorBattle) {
		armyMod *= 2;
	}
	if (inBattle && armyMod <= 0) {
		armyMod = 1;
	}

	if (inRebellion) {
		if (V.SecExp.war.type.includes("Slave")) {
			rebellingSlaves = 1;
			unitData = App.Mods.SecExp.getIrregularUnit("slaves", V.SecExp.war.attacker.troops, V.SecExp.war.attacker.equip);
		} else {
			rebellingMilitia = 1;
			unitData = App.Mods.SecExp.getIrregularUnit("militia", V.SecExp.war.attacker.troops, V.SecExp.war.attacker.equip);
		}
		enemyAttack += unitData.attack * armyMod;
		enemyDefense += unitData.defense * armyMod;
		enemyHp += unitData.hp;

		for (const [type] of Array.from(App.Mods.SecExp.unit.list()).slice(1)) {
			if (rebellingSlaves === 1 && type === "slaves" || rebellingMilitia === 1 && type === "militia") {
				for (const unit of V.SecExp.units[type].squads) {
					if (V.SecExp.war.rebellingID.includes(unit.ID)) {
						V.SecExp.war.attacker.troops += unit.troops;
						unit.loyalty = 0;
						unitData = App.Mods.SecExp.getUnit(type, unit);
						enemyAttack += unitData.attack;
						enemyDefense += unitData.defense;
						enemyHp += unitData.hp;
					}
				}
			}
		}
	}

	// calculates opposing army stats
	const enemyMoraleTroopMod = Math.clamp(V.SecExp.war.attacker.troops / 100, 1, (inBattle ? 5 : 10));
	if (inBattle) {
		unitData = App.Mods.SecExp.getEnemyUnit(V.SecExp.war.attacker.type, V.SecExp.war.attacker.troops, V.SecExp.war.attacker.equip);
		enemyAttack = unitData.attack * armyMod;
		enemyDefense = unitData.defense * armyMod;
		enemyMorale = unitData.morale * morale.enemy * enemyMoraleTroopMod;
		enemyHp = unitData.hp;
		enemyBaseHp = unitData.hp / V.SecExp.war.attacker.troops;
	} else {
		enemyMorale = 1.5 * (App.Mods.SecExp.BaseMilitiaUnit.morale * rebellingMilitia + App.Mods.SecExp.BaseSlaveUnit.morale * rebellingSlaves) / (rebellingMilitia + rebellingSlaves);
		enemyMorale *= enemyMoraleTroopMod;
		enemyBaseHp = (App.Mods.SecExp.BaseMilitiaUnit.hp * rebellingMilitia + App.Mods.SecExp.BaseSlaveUnit.hp * rebellingSlaves) / (rebellingMilitia + rebellingSlaves);
	}
	enemyMorale = Math.round(enemyMorale);

	attack.total = Math.round(Object.values(attack).reduce((a, b) => a + b));
	defense.total = Math.round(Object.values(defense).reduce((a, b) => a + b));
	hp.total = Math.round(Object.values(hp).reduce((a, b) => a + b));
	morale.total = Math.round(Object.values(hp).reduce((a, b) => a + b));

	for (const variable of [attack.total, defense.total, hp.total, morale.total, enemyAttack, enemyDefense, enemyHp, enemyMorale, enemyBaseHp]) {
		if (isNaN(variable)) {
			throw Error(`Value: A key variable is NaN, please report this along with an affected save.`);
		}
	}

	enemyAttack *= V.SecExp.settings.difficulty;
	enemyDefense *= V.SecExp.settings.difficulty;
	enemyMorale *= V.SecExp.settings.difficulty;
	enemyHp *= V.SecExp.settings.difficulty;
	enemyBaseHp *= V.SecExp.settings.difficulty;

	if (showStats) {
		if (inBattle) {
			attack.modifier = Math.round((attack.modifier-1) * 100);
			defense.modifier = Math.round((defense.modifier-1) * 100);
			morale.militia = Math.round((morale.militia-1) * 100);
			morale.mercs = Math.round((morale.mercs-1) * 100);
			morale.slaves = Math.round((morale.slaves-1) * 100);
			morale.SF = Math.round((morale.SF-1) * 100);
			morale.enemy = Math.round((morale.enemy-1) * 100);
		} else {
			engageMod = Math.round((engageMod-1) * 100);
		}

		let difficultyText;
		if (V.SecExp.settings.difficulty === 0.5) {
			difficultyText = "Very easy";
		} else if (V.SecExp.settings.difficulty === 0.75) {
			difficultyText = "Easy";
		} else if (V.SecExp.settings.difficulty === 1) {
			difficultyText = "Normal";
		} else if (V.SecExp.settings.difficulty === 1.25) {
			difficultyText = "Hard";
		} else if (V.SecExp.settings.difficulty === 1.5) {
			difficultyText = "Very hard";
		} else {
			difficultyText = "Extremely hard";
		}
		App.UI.DOM.appendNewElement("div", node, `Difficulty: ${difficultyText}. Modifier: x${V.SecExp.settings.difficulty}`);

		App.UI.DOM.appendNewElement("div", node, `Army`, ["underline"]);
		App.UI.DOM.appendNewElement("div", node, `Deployed troops: ${num(App.Mods.SecExp.battle.troopCount())}`);
		App.UI.DOM.appendNewElement("div", node, `Attack: ${num(attack.total)}.`);
		if (attack.SF) {
			App.UI.DOM.appendNewElement("div", node, `Base: ${attack.base}`, ["indent"]);
			App.UI.DOM.appendNewElement("div", node, `SF Bonus: ${attack.SF}`, ["indent"]);
		}
		App.UI.DOM.appendNewElement("div", node, `Defense: ${num(Math.round(defense.total))}.`);
		if (defense.SF) {
			App.UI.DOM.appendNewElement("div", node, `Base: ${defense.base}`, ["indent"]);
			App.UI.DOM.appendNewElement("div", node, `SF Bonus: ${defense.SF}`, ["indent"]);
		}
		if (inRebellion) {
			App.UI.DOM.appendNewElement("div", node, `Engagement rule modifier: +${engageMod}%`);
		}
		App.UI.DOM.appendNewElement("div", node, `HP: ${num(Math.round(hp.total))}.`);
		if (hp.SF) {
			App.UI.DOM.appendNewElement("div", node, `Base: ${hp.base}`, ["indent"]);
			App.UI.DOM.appendNewElement("div", node, `SF Bonus: ${hp.SF}`, ["indent"]);
		}
		App.UI.DOM.appendNewElement("div", node, `Morale: ${num(Math.round(morale.total))}.`);
		if (inBattle) {
			App.UI.DOM.appendNewElement("div", node, `Slaves morale modifier: +${morale.slaves}%`, ["indent"]);
			App.UI.DOM.appendNewElement("div", node, `Militia morale modifier: +${morale.militia}%`, ["indent"]);
			App.UI.DOM.appendNewElement("div", node, `Mercenaries morale modifier: +${morale.mercs}%`, ["indent"]);
			if (activeSF && V.SecExp.war.deploySF) {
				App.UI.DOM.appendNewElement("div", node, `Special Force morale modifier: +${morale.SF}%`, ["indent"]);
			}
			if (V.SecExp.buildings.barracks && V.SecExp.buildings.barracks.luxury >= 1) {
				App.UI.DOM.appendNewElement("div", node, `Barracks bonus morale modifier: +${V.SecExp.buildings.barracks.luxury * 5}%`, ["indent"]);
			}
		}
		if (inBattle) {
			App.UI.DOM.appendNewElement("div", node, `Tactics`, ["underline"]);
			App.UI.DOM.appendNewElement("div", node, `Chance of success: ${num(Math.round(tacChance * 100))}%. Was successful?: ${V.SecExp.war.tacticsSuccessful ? 'Yes' : 'No'}`);
		}

		App.UI.DOM.appendNewElement("p", node);
		App.UI.DOM.appendNewElement("div", node, `${inBattle ? 'Enemy' : 'Rebels'}`, ["underline"]);
		App.UI.DOM.appendNewElement("div", node, `Troops: ${num(Math.round(V.SecExp.war.attacker.troops))}`);
		App.UI.DOM.appendNewElement("div", node, `Attack: ${num(Math.round(enemyAttack))}`);
		App.UI.DOM.appendNewElement("div", node, `Defense: ${num(Math.round(enemyDefense))}`);
		App.UI.DOM.appendNewElement("div", node, `HP: ${num(Math.round(enemyHp))}. Base: ${num(Math.round(enemyBaseHp))}`);
		App.UI.DOM.appendNewElement("div", node, `Morale: ${num(Math.round(enemyMorale))}.`);
	}

	let i = 0; // simulates the combat by pitting attk against def
	while (i < turns && ![3, -3].includes(V.SecExp.war.result)) {
		App.UI.DOM.appendNewElement("p", node, turnReport());
		i++;
	}

	if (![3, -3].includes(V.SecExp.war.result)) {
		showProgress(`Partial ${morale.total > enemyMorale ? 'victory' : 'defeat'}!`);
		V.SecExp.war.result = morale.total > enemyMorale ? 2 : -2;
	}

	if (V.SecExp.war.result > 3 || V.SecExp.war.result < -3) {
		throw Error(`Failed to determine battle result`);
	}

	if (inBattle && showStats) {
		App.UI.DOM.appendNewElement("div", node, `Losses: ${num(Math.trunc(V.SecExp.war.losses))}`);
		App.UI.DOM.appendNewElement("div", node, `Enemy losses: ${num(Math.trunc(V.SecExp.war.attacker.losses))}`);
	}

	if (V.SecExp.war.result === -3 && (isMajorBattle && V.SecExp.settings.battle.major.gameOver === 1 || inRebellion && V.SecExp.settings.rebellion.gameOver === 1)) {
		V.gameover = `${isMajorBattle ? "major battle" : "Rebellion"} defeat`;
		atEnd("Gameover");
	} else {
		atEnd("conflictReport");
	}
	return node;
};


code:
App.Events.conflictOptions = class conflictOptions extends App.Events.BaseEvent {
	eventPrerequisites() {
		return [
			() => V.secExpEnabled > 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.Mods.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.Mods.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.Mods.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.Mods.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.Mods.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.Mods.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.Mods.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.Mods.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.Mods.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.Mods.SecExp.battle.recon() === 2) {
				r.push(`Your recon capabilities are decent. The information collected will be mostly close to the truth:`);
			} else if (App.Mods.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")) {
				const capSF = capFirstChar(V.SF.Lower || "the Special Force");
				options = new App.UI.OptionsGroup();
				options.addOption(`The incoming attack's scale warrants deploying ${capSF}.`, "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 ${capSF} is not deployed.`);
				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.Mods.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.Mods.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.Mods.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`);
			r.push(`${isSlaveRebellion ? 'freeing their peers' : '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.`);
			}

			const rebelling = [];
			const defending = [];
			if (V.arcologyUpgrade.drones === 1) {
				defending.push(`Your security drones`);
			}
			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`);
			}
			for (const squad of App.Mods.SecExp.unit.squads("human").filter(u => u.active)) {
				if (V.SecExp.war.rebellingID.includes(squad.ID)) {
					rebelling.push(squad.platoonName);
				} else {
					defending.push(squad.platoonName);
				}
			}

			if (V.SecExp.war.rebellingID.length > 0) {
				App.Events.addParagraph(node, r);
				r = [];
				r.push(`${toSentence(rebelling)} betrayed you and joined the insurrection.`);
			}
			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.Mods.SecExp.unit.replenishAll());
		if (isBattle) {
			if (App.Mods.SecExp.battle.deployableUnits() === 0) {
				App.UI.DOM.appendNewElement("div", node, `Unit roster full.`, ["strong"]);
			}
			if (App.Mods.SecExp.unit.squads().length > 0) {
				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.Mods.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.Mods.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
			}, `conflictHandler`);
		} else if (isBattle && App.Mods.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.Mods.SecExp.battle.bribeCost() * (1 + either(-1, 1) * random(2) * 0.1)))})`, () => {
				V.SecExp.war.result = 1;
			}, `conflictHandler`);
		}
		option.addButton(`Surrender`, () => {
			V.SecExp.war.result = -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.Mods.SecExp.unit.describe(u, true));
			}
			return frag;
		}
	}
};

repo_name: Fekenol/fc

license: mit