code:
App.SecExp.troopDiffAdjust = function() {
	let pc = 1.0;
	let enemy = 1.0;
	if (V.SecExp && V.SecExp.war) {
		const diff = App.SecExp.battle.troopCount() / V.SecExp.war.attacker.troops;
		if (diff > 0) {
			pc += diff;
			enemy -= diff;
		} else if (diff < 0) {
			pc -= diff;
			enemy += diff;
		}
	}
	return {pc: Math.clamp(pc, 0.5, 1.5), enemy: Math.clamp(enemy, 0.5, 1.5)};
};

/** Takes the passed input and returns a clamped V.SecExp.core.authority
 * @param {number} input defaults to zero
 */
App.SecExp.authorityX = function(input = 0) {
	V.SecExp.core.authority = Math.trunc(Math.clamp(V.SecExp.core.authority + input, 0, 20000));
};

App.SecExp.generator = (function() {
	return {
		attack,
		rebellion,
	};

	function shared() {
		V.SecExp.war.commander = "assistant";
		V.SecExp.war.losses = 0;
		V.SecExp.war.attacker = {losses: 0};
	}

	function attack() {
		let attackChance = 0; // attackChance value is the chance out of 100 of an attack happening this week
		// attacks are deactivated if security drones are not around yet, there is not a rebellion this week or the last attack/rebellion happened within 3 weeks
		if (V.arcologyUpgrade.drones === 1 && V.SecExp.war.type === "" && V.SecExp.battles.lastEncounterWeeks > 3 && V.SecExp.rebellions.lastEncounterWeeks > 3) {
			if (V.week < 30) {
				attackChance = 5;
			} else if (V.week < 60) {
				attackChance = 8;
			} else if (V.week < 90) {
				attackChance = 12;
			} else if (V.week < 120) {
				attackChance = 16;
			} else {
				attackChance = 20;
			}
			if (V.SecExp.battles.victories + V.SecExp.battles.losses >= 0) {
				attackChance = 25;
			}

			if (V.SecExp.battles.lastEncounterWeeks >= 10) {
				attackChance += V.SecExp.battles.lastEncounterWeeks/2; // attackChance += 5;
			}
			if (V.terrain === "oceanic") {
				attackChance -= 10;
			}
			attackChance *= V.SecExp.settings.battle.frequency; // battle frequency
		}

		if (V.SecExp.settings.battle.force === 1 && V.SecExp.settings.rebellion.force === 0) {
			attackChance = 100;
		}

		if (random(1, 100) > attackChance) { // Rolls to see if attack happens this week
			V.SecExp.battles.lastEncounterWeeks++;
		} else {
			let type; let terrain; let troops; let equip = 0; let L = 0;
			V.SecExp.battles.lastEncounterWeeks = 0;
			let raider = 25; let oldWorld = 25; let freeCity = 25; let free = 25; // type is the chance out of 100 of an attack of that type happening
			// the old world attracted by "degenerate" future societies
			const setA = [
				'FSRomanRevivalist', 'FSEdoRevivalist', 'FSArabianRevivalist',
				'FSChineseRevivalist', 'FSEgyptianRevivalist', 'FSAztecRevivalist'];
			const setB = [
				'FSRepopulationFocus', 'FSGenderRadicalist', 'FSPastoralist',
				'FSChattelReligionist', 'FSNeoImperialist'];
			const resultA = setA.some((FS) => V.arcologies[0][FS] !== "unset");
			const resultB = setB.some((FS) => V.arcologies[0][FS] !== "unset");
			if (resultA && resultB) {
				oldWorld += 15;
				raider -= 5;
				freeCity -= 5;
				free -= 5;
			} else if (resultA || resultB) {
				oldWorld += 24;
				raider -= 8;
				freeCity -= 8;
				free -= 8;
			}
			// freedom fighters attracted by high slave/citizen ratio
			if (V.ASlaves > V.ACitizens * 2) {
				oldWorld -= 8;
				raider -= 8;
				freeCity -= 8;
				free += 24;
			} else if (V.ASlaves > V.ACitizens * 1.2 || V.arcologies[0].FSDegradationist !== "unset") {
				oldWorld -= 5;
				raider -= 5;
				freeCity -= 5;
				free += 15;
			}
			// free Cities attracted by high prosperity
			if (V.arcologies[0].prosperity >= 10 && V.arcologies[0].prosperity < 20) {
				oldWorld -= 5;
				raider -= 5;
				freeCity += 15;
				free -= 5;
			} else if (V.arcologies[0].prosperity >= 20) {
				oldWorld -= 8;
				raider -= 8;
				freeCity += 24;
				free -= 8;
			}
			// raiders are attracted by low security
			if (V.SecExp.core.security <= 50) {
				oldWorld -= 5;
				raider += 15;
				freeCity -= 5;
				free -= 5;
			} else if (V.SecExp.core.security <= 25) {
				oldWorld -= 8;
				raider += 24;
				freeCity -= 8;
				free -= 8;
			}

			const roll = random(1, 100); // makes the actual roll
			if (roll <= raider) {
				type = "raiders";
				troops = random(40, 80); L = 1;
			} else if (roll <= raider + oldWorld) {
				type = "old world";
				troops = random(25, 50);
			} else if (roll <= raider + oldWorld + freeCity) {
				type = "free city";
				troops = random(20, 40);
			} else if (roll <= raider + oldWorld + freeCity + free) {
				type = "freedom fighters";
				troops = random(30, 60);
			}

			V.SecExp.war.type = 'Attack';
			if (V.terrain === "urban") {
				terrain = either("outskirts", "urban", "wasteland");
			} else if (V.terrain === "rural") {
				terrain = either("hills", "outskirts", "rural", "wasteland");
			} else if (V.terrain === "ravine") {
				terrain = either("hills", "mountains", "outskirts", "wasteland");
			} else if (V.terrain === "marine") {
				terrain = either("coast", "hills", "outskirts", "wasteland");
			} else if (V.terrain === "oceanic") {
				terrain = either("international waters", "an underwater cave", "a sunken ship");
			} else {
				terrain = "error";
			}

			if (V.week < 30) {
				troops *= random(1, 2); // troops *= Math.trunc(random( (1*(1.01+(V.week/100))), (2*(1.01+(V.week/100))) ))) {
			} else if (V.week < 60) {
				troops *= random(1, 3); // troops *= Math.trunc(random( (1*(1.01+(V.week/200))), (3*(1.01+(V.week/200))) ))) {
				equip = random(0, 1);
			} else if (V.week < 90) {
				troops *= random(2, 3); // troops *= Math.trunc(random( (2*(1.01+(V.week/300))), (3*(1.01+(V.week/300))) ))) {
				equip = random(0, 3-L); // "raiders" equip = random(0,2)) {
			} else if (V.week < 120) {
				troops *= random(2, 4); // troops *= Math.trunc(random( (2*(1.01+(V.week/400))), (4*(1.01+(V.week/400))) ))) {
				equip = random(1-L, 3); // "raiders" equip = random(0,3)) {
			} else {
				troops *= random(3, 5);
				equip = random(2-L, 4-L); // "raiders" equip = random(1,3)) {
			}

			if (V.SecExp.settings.battle.major.enabled === 1) { // major battles have a 50% chance of firing after week 120
				if ((V.week >= 120 && random(1, 100) >= 50) || V.SecExp.settings.battle.major.force === 1) {
					V.SecExp.war.type = 'Major Attack';
					const sfActive = V.SF.Toggle && V.SF.Active >= 1;
					troops *= sfActive ? random(4, 6) : random(2, 3);
					equip = sfActive ? either(3, 4) : either(2, 3, 4);
				}
			}

			if (V.SecExp.settings.difficulty > 1) {
				troops *= V.SecExp.settings.difficulty;
			}

			shared();
			V.SecExp.war.attacker.troops = troops;
			V.SecExp.war.attacker.equip = equip;
			V.SecExp.war.attacker.type = type;
			V.SecExp.war.terrain = terrain;
			V.SecExp.war.deploySF = 0;
			V.SecExp.war.saveValid = 0;
			V.SecExp.war.tacticsSuccessful = 0;
			V.SecExp.war.chosenTactic = either("Bait and Bleed", "Blitzkrieg", "Choke Points", "Defense In Depth", "Guerrilla", "Human Wave", "Interior Lines", "Pincer Maneuver");
			V.SecExp.war.estimatedMen = normalRandInt(troops, troops * (4 - App.SecExp.battle.recon()) * 0.05);
			V.SecExp.war.expectedEquip = normalRandInt(equip, (4 - App.SecExp.battle.recon()) * 0.25);
			V.SecExp.war.deployed = [];
		}
	}

	function rebellion() {
		if (V.SecExp.rebellions.slaveProgress >= 100) {
			if (random(1, 100) <= 80) {	// 80% of firing a rebellion once progress is at 100
				V.SecExp.war.type = "Slave Rebellion";
				V.SecExp.rebellions.slaveProgress = 0;
				V.SecExp.rebellions.citizenProgress *= 0.2;
			} else {
				V.SecExp.rebellions.slaveProgress = 100;
			}
		} else if (V.SecExp.rebellions.citizenProgress >= 100) {
			if (random(1, 100) <= 80) {
				V.SecExp.war.type = "Citizen Rebellion";
				V.SecExp.rebellions.citizenProgress = 0;
				V.SecExp.rebellions.slaveProgress *= 0.2;
			} else {
				V.SecExp.rebellions.citizenProgress = 100;
			}
		}

		if (V.SecExp.settings.rebellion.force === 1 && V.SecExp.war.foughtThisWeek === 0) {
			V.SecExp.war.type = `${random(1, 100) <= 50 ? 'Slave' : 'Citizen'} Rebellion`;
		}

		if (V.SecExp.war.type === "") {
			V.SecExp.rebellions.lastEncounterWeeks++;
		} else {
			const isSlaveRebellion = V.SecExp.war.type.includes("Slave");
			let weekMod;
			if (V.week <= 30) {
				weekMod = 0.75 + (0.01+(V.week/200));
			} else if (V.week <= 60) {
				weekMod = 1 + (0.01+(V.week/300));
			} else if (V.week <= 90) {
				weekMod = 1.25 + (0.01+(V.week/400));
			} else if (V.week <= 120) {
				weekMod = 1.50 + (0.01+(V.week/500));
			} else {
				weekMod = 1.75;
			}

			shared();
			V.SecExp.rebellions.lastEncounterWeeks = 0;
			const authFactor = Math.clamp(1 - (V.SecExp.core.authority / 20000), 0.4, 0.6);
			const repFactor = Math.clamp(V.rep / 20000, 0.4, 0.6);
			const rebelPercent = 0.3 * authFactor;
			const irregularPercent = 0.2 * repFactor;

			const isDisloyal = (x) => (x < 10 && jsRandom(1, 100) <= 70) || (x < 33 && jsRandom(1, 100) <= 30) || (x < 66 && jsRandom(1, 100) <= 10);
			const baseValue = Math.trunc((isSlaveRebellion ? V.ASlaves : V.ACitizens) * rebelPercent * weekMod) + random(-100, 100);
			const highestValue = isSlaveRebellion ? V.ASlaves : V.ACitizens;
			V.SecExp.war.attacker.troops = Math.clamp(baseValue, 50, highestValue);
			V.SecExp.war.attacker.equip = Math.clamp(V.SecExp.edicts.weaponsLaw + random((isSlaveRebellion ? -2 : -1), 1), 0, 4);
			V.SecExp.war.irregulars = Math.clamp(Math.trunc(V.ACitizens * irregularPercent * weekMod) + random(-100, 100), 50, V.ACitizens);
			V.SecExp.war.engageRule = 0;
			V.SecExp.war.rebellingID = App.SecExp.unit.squads("human").map(u => u.loyalty).filter(isDisloyal);
		}
	}
})();

/**
 * Returns the raw percentage of society that can be drafted.
 * @returns {number}
 */
App.SecExp.militiaCap = function(x = 0) {
	x = x || V.SecExp.edicts.defense.militia;
	if (x === 2) {
		return 0.02;
	} else if (x === 3) {
		return 0.05;
	} else if (x === 4) {
		return 0.1;
	} else if (x === 5) {
		return 0.2;
	}
};

App.SecExp.initTrade = function() {
	if (V.SecExp.core.trade === 0 || !jsDef(V.SecExp.core.trade)) {
		let init = jsRandom(20, 30);
		if (V.terrain === "urban") {
			init += jsRandom(10, 10);
		} else if (V.terrain === "ravine") {
			init -= jsRandom(5, 5);
		}
		if (isPCCareerInCategory("wealth") || isPCCareerInCategory("capitalist") || isPCCareerInCategory("celebrity") || isPCCareerInCategory("BlackHat")) {
			init += jsRandom(5, 5);
		} else if (isPCCareerInCategory("escort") || isPCCareerInCategory("gang") || isPCCareerInCategory("servant")) {
			init -= jsRandom(5, 5);
		}
		V.SecExp.core.trade = init;
	}
};

App.SecExp.generalInit = function() {
	if (V.secExpEnabled === 0) {
		return;
	}

	Object.assign(V.SecExp, {
		battles: {
			major: 0,
			slaveVictories: [],
			lastSelection: [],
			victories: 0,
			victoryStreak: 0,
			losses: 0,
			lossStreak: 0,
			lastEncounterWeeks: 0,
			saved: {}
		},
		rebellions: {
			tension: 0,
			slaveProgress: 0,
			citizenProgress: 0,
			victories: 0,
			losses: 0,
			lastEncounterWeeks: 0,
			repairTime: {},
		},
		core: {
			trade: 0,
			authority: 0,
			security: 100,
			crimeLow: 30,
			totalKills: 0,
		},
		settings: {
			difficulty: 1,
			unitDescriptions: 0,
			showStats: 0,
			battle: {
				enabled: 1,
				allowSlavePrestige: 1,
				force: 0,
				frequency: 1,
				major: {
					enabled: 0,
					gameOver: 1,
					mult: 1,
					force: 0
				}
			},
			rebellion: {
				enabled: 1,
				force: 0,
				gameOver: 1,
				speed: 1
			}
		},
		buildings: {},
		proclamation: {
			cooldown: 0,
			currency: "",
			type: "crime"
		},
		units: {},
		edicts: {
			alternativeRents: 0,
			enslavementRights: 0,
			sellData: 0,
			propCampaignBoost: 0,
			tradeLegalAid: 0,
			taxTrade: 0,
			slaveWatch: 0,
			subsidyChurch: 0,
			SFSupportLevel: 0,
			limitImmigration: 0,
			openBorders: 0,
			weaponsLaw: 3,
			defense: {
				soldierWages: 1,
				slavesOfficers: 0,
				discountMercenaries: 0,
				militia: 0,
				militaryExemption: 0,
				noSubhumansInArmy: 0,
				pregExemption: 0,
				liveTargets: 0,
				privilege: {
					militiaSoldier: 0,
					slaveSoldier: 0,
					mercSoldier: 0,
				},
				// Soldiers
				martialSchool: 0,
				eliteOfficers: 0,
				lowerRequirements: 0,
				// FS soldiers
				legionTradition: 0,
				eagleWarriors: 0,
				ronin: 0,
				sunTzu: 0,
				mamluks: 0,
				pharaonTradition: 0,
			}
		},
		smilingMan: {progress: 0}
	});

	for (const [unit] of App.SecExp.unit.list()) {
		App.SecExp.unit.gen(unit);
	}
	App.SecExp.initTrade();
};

App.SecExp.battle = (function() {
	"use strict";
	const unitFunctions = App.SecExp.unit;
	return {
		deployedUnits,
		troopCount,
		deploySpeed,
		deployableUnits,
		activeUnits,
		maxUnits,
		recon,
		bribeCost,
	};

	/** Get count of deployed/active units for a particular battle
	 * @param {string} input type of to measure; if omitted, count all types
	 * @returns {number} unit count
	 */
	function deployedUnits(input = '') {
		const inBattle = V.SecExp.war.type.includes("Attack");
		let count = {}; let init = 0;
		Array.from(unitFunctions.list().keys()).forEach((s) => count[s] = 0);
		if (V.SF.Toggle && V.SF.Active >= 1 && (inBattle && V.SecExp.war.deploySF || !inBattle)) {
			init++;
		}
		if (!inBattle && V.SecExp.war.irregulars > 0) { // rebellion
			count.militia++;
		}

		Array.from(unitFunctions.list().keys()).forEach((s) => count[s] += V.SecExp.units[s].squads.filter(u => App.SecExp.unit.isDeployed(u)).length);
		if (input === '') {
			return Object.values(count).reduce((a, b) => a + b) + init;
		} else {
			return count[input];
		}
	}

	/** Get total troop count of deployed/active units for a particular battle
	 * @returns {number} troop count
	 */
	function troopCount() {
		const inBattle = V.SecExp.war.type.includes("Attack");
		let troops = 0;
		if (V.SF.Toggle && V.SF.Active >= 1 && (inBattle && V.SecExp.war.deploySF || !inBattle)) {
			troops += App.SecExp.troopsFromSF();
		}
		if (!inBattle) {
			troops += V.SecExp.war.irregulars;
		}
		return Math.round(troops += unitFunctions.squads().filter(s => unitFunctions.isDeployed(s)).reduce((acc, t) => acc += t.troops, 0));
	}

	/** Get mobilization readiness (in *pairs* of units) given upgrades
	 * @returns {number} readiness
	 */
	function deploySpeed() {
		let init = 1;
		if (V.SecExp.buildings.secHub) {
			if (V.SecExp.buildings.secHub.upgrades.readiness.pathways > 0) {
				init += 1;
			}
			if (V.SecExp.buildings.secHub.upgrades.readiness.rapidVehicles > 0) {
				init += 2;
			}
			if (V.SecExp.buildings.secHub.upgrades.readiness.rapidPlatforms > 0) {
				init += 2;
			}
			if (V.SecExp.buildings.secHub.upgrades.readiness.earlyWarn > 0) {
				init += 2;
			}
		}
		if (V.SF.Toggle && V.SF.Active >= 1 && V.SecExp.sectionInFirebase >= 1) {
			init += 2;
		}
		return init;
	}

	/** Get remaining deployable units (mobilization in units minus units already deployed)
	 * @returns {number}
	 */
	function deployableUnits() {
		let init = 2 * App.SecExp.battle.deploySpeed();
		init -= unitFunctions.squads().filter(s => unitFunctions.isDeployed(s)).length;
		return Math.max(0, init);
	}

	/** Get total active units
	 * @returns {number}
	 */
	function activeUnits() {
		return V.secExpEnabled > 0 ? App.SecExp.unit.squads().filter(s => s.active).length : 0;
	}

	/** Get maximum active units
	 * @returns {number}
	 */
	function maxUnits() {
		let max = 0;
		if (V.SecExp.buildings.barracks) {
			max += 8 + (V.SecExp.buildings.barracks.size * 2);
			if (App.SecExp.battle.deploySpeed() === 10) {
				max += 2;
			}
		}
		return max;
	}

	/** Get recon score (scale 0-3)
	 * @returns {number}
	 */
	function recon() {
		return V.SecExp.buildings.secHub ? Object.values(V.SecExp.buildings.secHub.upgrades.intel).reduce((a, b) => a + b) : 0;
	}

	/** Get bribe cost for an attacker to go away
	 * @returns {number}
	 */
	function bribeCost() {
		let cost; const baseBribePerAttacker = 5;
		if (V.week <= 30) {
			cost = 5000 + baseBribePerAttacker * V.SecExp.war.attacker.troops;
		} else if (V.week <= 40) {
			cost = 10000 + baseBribePerAttacker * V.SecExp.war.attacker.troops;
		} else if (V.week <= 50) {
			cost = 15000 + baseBribePerAttacker * V.SecExp.war.attacker.troops;
		} else if (V.week <= 60) {
			cost = 20000 + baseBribePerAttacker * V.SecExp.war.attacker.troops;
		} else if (V.week <= 70) {
			cost = 25000 + baseBribePerAttacker * V.SecExp.war.attacker.troops;
		} else {
			cost = 30000 + baseBribePerAttacker * V.SecExp.war.attacker.troops;
		}
		cost *= (V.SecExp.war.type.includes("Major") ? 3 : 1);
		return Math.trunc(Math.clamp(cost, 0, 1000000));
	}
})();

App.SecExp.Check = (function() {
	"use strict";
	return {
		secRestPoint,
		crimeCap,
		reqMenials,
	};

	function secRestPoint() {
		let rest = 40;
		if (V.SecExp.buildings.secHub) {
			if (V.SecExp.buildings.secHub.upgrades.security.nanoCams === 1) {
				rest += 15;
			}
			if (V.SecExp.buildings.secHub.upgrades.security.cyberBots === 1) {
				rest += 15;
			}
			if (V.SecExp.buildings.secHub.upgrades.security.eyeScan === 1) {
				rest += 20;
			}
			if (V.SecExp.buildings.secHub.upgrades.security.cryptoAnalyzer === 1) {
				rest += 20;
			}
		}
		return rest;
	}

	function crimeCap() {
		let cap = 100;
		if (V.SecExp.buildings.secHub) {
			if (V.SecExp.buildings.secHub.upgrades.crime.autoTrial === 1) {
				cap -= 10;
			}
			if (V.SecExp.buildings.secHub.upgrades.crime.autoArchive === 1) {
				cap -= 10;
			}
			if (V.SecExp.buildings.secHub.upgrades.crime.worldProfiler === 1) {
				cap -= 15;
			}
			if (V.SecExp.buildings.secHub.upgrades.crime.advForensic === 1) {
				cap -= 15;
			}
		}
		return cap;
	}

	function reqMenials() {
		let Req = 20;
		if (V.SecExp.buildings.secHub) {
			if (V.SecExp.buildings.secHub.upgrades.security.nanoCams === 1) {
				Req += 5;
			}
			if (V.SecExp.buildings.secHub.upgrades.security.cyberBots === 1) {
				Req += 5;
			}
			if (V.SecExp.buildings.secHub.upgrades.security.eyeScan === 1) {
				Req += 10;
			}
			if (V.SecExp.buildings.secHub.upgrades.security.cryptoAnalyzer === 1) {
				Req += 10;
			}

			if (V.SecExp.buildings.secHub.upgrades.crime.advForensic === 1) {
				Req += 10;
			}
			if (V.SecExp.buildings.secHub.upgrades.crime.autoArchive === 1) {
				Req += 5;
			}
			if (V.SecExp.buildings.secHub.upgrades.crime.autoTrial === 1) {
				Req += 5;
			}
			if (V.SecExp.buildings.secHub.upgrades.crime.worldProfiler === 1) {
				Req += 10;
			}

			if (V.SecExp.buildings.secHub.upgrades.intel.sensors === 1) {
				Req += 5;
			}
			if (V.SecExp.buildings.secHub.upgrades.intel.signalIntercept === 1) {
				Req += 5;
			}
			if (V.SecExp.buildings.secHub.upgrades.intel.radar === 1) {
				Req += 10;
			}

			if (V.SecExp.buildings.secHub.upgrades.readiness.pathways === 1) {
				Req += 5;
			}
			if (V.SecExp.buildings.secHub.upgrades.readiness.rapidVehicles === 1) {
				Req += 5;
			}
			if (V.SecExp.buildings.secHub.upgrades.readiness.rapidPlatforms === 1) {
				Req += 10;
			}
			if (V.SecExp.buildings.secHub.upgrades.readiness.earlyWarn === 1) {
				Req += 10;
			}
			Req -= 5 * V.SecExp.edicts.SFSupportLevel;
			Req -= 10 * V.SecExp.buildings.secHub.coldstorage;
		}
		return Req;
	}
})();

App.SecExp.inflictBattleWound = (function() {
	/** @typedef {object} Wound
	 * @property {number} weight
	 * @property {function(App.Entity.SlaveState):boolean} allowed
	 * @property {function(App.Entity.SlaveState):void} effects
	 */
	/** @type { Object<string, Wound> } */
	const wounds = {
		eyes: {
			weight: 10,
			allowed: (s) => canSee(s),
			effects: (s) => {
				clampedDamage(s, 30);
				eyeSurgery(s, "both", "blind");
				App.Medicine.Modification.addScar(s, "damaged eyes", "While leading your army a splinter hit the eyes causing major damage.");
			}
		},
		voice: {
			weight: 10,
			allowed: (s) => canTalk(s),
			effects: (s) => {
				clampedDamage(s, 60);
				s.voice = 0;
				App.Medicine.Modification.addScar(s, "damaged throat", "While leading your army a splinter hit and destroyed vocal cords");
			}
		},
		legs: {
			weight: 5,
			allowed: (s) => hasAnyNaturalLegs(s),
			effects: (s) => {
				clampedDamage(s, 80);
				removeLimbs(s, "left leg");
				removeLimbs(s, "right leg");
				App.Medicine.Modification.addScar(s, "arm blown off", "While leading your army a nearby explosion mangled both legs to the point of amputation.");
			}
		},
		arm: {
			weight: 5,
			allowed: (s) => hasAnyNaturalArms(s),
			effects: (s) => {
				clampedDamage(s, 60);
				removeLimbs(s, jsEither(["left arm", "right arm"]));
				App.Medicine.Modification.addScar(s, "arm blown off", "While leading your army a nearby explosion mangled an arm to the point of amputation.");
			}
		},
		flesh: {
			weight: 70,
			allowed: () => true,
			effects: (s) => {
				clampedDamage(s, 30);
				App.Medicine.Modification.addScar(s, "flesh wound", "A stray shot during leading your army grazed the skin and destroyed nerve endings");
			}
		}
		// TODO: add more wound types? destroy prosthetics?
	};

	/** Inflicts a large amount of damage upon a slave without killing them (i.e. leaving their health total above -90)
	 * @param {App.Entity.SlaveState} slave
	 * @param {number} magnitude
	 */
	function clampedDamage(slave, magnitude) {
		if ((slave.health.health - magnitude) > -90) {
			healthDamage(slave, magnitude);
		} else {
			healthDamage(slave, 90 + slave.health.health);
		}
	}

	/** Inflicts a wound upon a slave during a battle. Returns the wound type from the wound table (see above) so it can be described.
	 * @param {App.Entity.SlaveState} slave
	 * @returns {string}
	 */
	function doWound(slave) {
		let woundHash = {};
		for (const w of Object.keys(wounds)) {
			if (wounds[w].allowed(slave)) {
				woundHash[w] = wounds[w].weight;
			}
		}
		/** @type {string} */
		// @ts-ignore - FIXME: hashChoice has bad JSDoc
		const wound = hashChoice(woundHash);
		wounds[wound].effects(slave);
		return wound;
	}

	return doWound;
})();


code:
// @ts-nocheck
App.SecExp.generalBC = function() {
	if (jsDef(V.secExp)) {
		if (V.secExpEnabled !== 1) {
			V.secExpEnabled = V.secExp;
		}
	}
	if (typeof V.secExpEnabled !== "number") {
		V.secExpEnabled = 0;
	}

	delete V.SecExp.army;

	if (V.secExpEnabled === 0) {
		return;
	}
	V.SecExp.settings = V.SecExp.settings || {};
	V.SecExp.edicts = V.SecExp.edicts || {};
	V.SecExp.edicts.defense = V.SecExp.edicts.defense || {};
	V.SecExp.units = V.SecExp.units || {};
	V.SecExp.units.bots = V.SecExp.units.bots || {};
	V.SecExp.smilingMan = V.SecExp.smilingMan || {};
	V.SecExp.core = V.SecExp.core || {};
	V.SecExp.battles = V.SecExp.battles || {};
	V.SecExp.rebellions = V.SecExp.rebellions || {};
	V.SecExp.settings.battle = V.SecExp.settings.battle || {};
	V.SecExp.settings.battle.major = V.SecExp.settings.battle.major || {};
	V.SecExp.settings.rebellion = V.SecExp.settings.rebellion || {};
	V.SecExp.buildings = V.SecExp.buildings || {};
	V.SecExp.proclamation = V.SecExp.proclamation || {};

	V.SecExp.edicts.alternativeRents = V.SecExp.edicts.alternativeRents || V.alternativeRents || 0;
	V.SecExp.edicts.enslavementRights = V.SecExp.edicts.enslavementRights || V.enslavementRights || 0;
	V.SecExp.edicts.sellData = V.SecExp.edicts.sellData || V.sellData || 0;
	V.SecExp.edicts.propCampaignBoost = V.SecExp.edicts.propCampaignBoost || V.propCampaignBoost || 0;
	V.SecExp.edicts.tradeLegalAid = V.SecExp.edicts.tradeLegalAid || V.tradeLegalAid || 0;
	V.SecExp.edicts.taxTrade = V.SecExp.edicts.taxTrade || V.taxTrade || 0;
	V.SecExp.edicts.slaveWatch = V.SecExp.edicts.slaveWatch || V.slaveWatch || 0;
	V.SecExp.edicts.subsidyChurch = V.SecExp.edicts.subsidyChurch || V.subsidyChurch || 0;
	V.SecExp.edicts.SFSupportLevel = V.SecExp.edicts.SFSupportLevel || V.SFSupportLevel || 0;
	V.SecExp.edicts.limitImmigration = V.SecExp.edicts.limitImmigration || V.limitImmigration || 0;
	V.SecExp.edicts.openBorders = V.SecExp.edicts.openBorders || V.openBorders || 0;
	if (typeof V.SecExp.edicts.weaponsLaw !== "number") {
		V.SecExp.edicts.weaponsLaw = V.weaponsLaw || 3;
	}

	V.SecExp.edicts.defense.soldierWages = V.SecExp.edicts.defense.soldierWages || V.soldierWages || 1;
	V.SecExp.edicts.defense.slavesOfficers = V.SecExp.edicts.defense.slavesOfficers || V.slavesOfficers || 0;
	V.SecExp.edicts.defense.discountMercenaries = V.SecExp.edicts.defense.discountMercenaries || V.discountMercenaries || 0;

	V.SecExp.edicts.defense.militia = V.SecExp.edicts.defense.militia || 0;
	if (V.militiaFounded) {
		V.SecExp.edicts.defense.militia = 1;
	}
	if (V.recruitVolunteers) {
		V.SecExp.edicts.defense.militia = 2;
	}
	if (V.conscription) {
		V.SecExp.edicts.defense.militia = 3;
	}
	if (V.militaryService) {
		V.SecExp.edicts.defense.militia = 4;
	}
	if (V.militarizedSociety) {
		V.SecExp.edicts.defense.militia = 5;
	}

	V.SecExp.edicts.defense.militaryExemption = V.SecExp.edicts.defense.militaryExemption || V.militaryExemption || 0;
	V.SecExp.edicts.defense.noSubhumansInArmy = V.SecExp.edicts.defense.noSubhumansInArmy || V.noSubhumansInArmy || 0;
	V.SecExp.edicts.defense.pregExemption = V.SecExp.edicts.defense.pregExemption || V.pregExemption || 0;
	V.SecExp.edicts.defense.liveTargets = V.SecExp.edicts.defense.liveTargets || V.liveTargets || 0;
	V.SecExp.edicts.defense.pregExemption = V.SecExp.edicts.defense.pregExemption || V.pregExemption || 0;

	// Units
	V.SecExp.edicts.defense.martialSchool = V.SecExp.edicts.defense.martialSchool || V.martialSchool || 0;
	V.SecExp.edicts.defense.eliteOfficers = V.SecExp.edicts.defense.eliteOfficers || V.eliteOfficers || 0;
	V.SecExp.edicts.defense.lowerRequirements = V.SecExp.edicts.defense.lowerRequirements || V.lowerRequirements|| V.lowerRquirements || 0;
	V.SecExp.edicts.defense.legionTradition = V.SecExp.edicts.defense.legionTradition || V.legionTradition || 0;
	V.SecExp.edicts.defense.eagleWarriors = V.SecExp.edicts.defense.eagleWarriors || V.eagleWarriors || 0;
	V.SecExp.edicts.defense.ronin = V.SecExp.edicts.defense.ronin || V.ronin || 0;
	V.SecExp.edicts.defense.sunTzu = V.SecExp.edicts.defense.sunTzu || V.sunTzu || 0;
	V.SecExp.edicts.defense.mamluks = V.SecExp.edicts.defense.mamluks || V.mamluks || 0;
	V.SecExp.edicts.defense.pharaonTradition = V.SecExp.edicts.defense.pharaonTradition || V.pharaonTradition || 0;

	// Priv
	V.SecExp.edicts.defense.privilege = V.SecExp.edicts.defense.privilege || {};
	V.SecExp.edicts.defense.privilege.militiaSoldier = V.SecExp.edicts.defense.privilege.militiaSoldier || V.militiaSoldier || 0;
	V.SecExp.edicts.defense.privilege.slaveSoldier = V.SecExp.edicts.defense.privilege.slaveSoldier || V.slaveSoldier || 0;
	V.SecExp.edicts.defense.privilege.mercSoldier = V.SecExp.edicts.defense.privilege.mercSoldier || V.mercSoldier || 0;

	for (const [unit, data] of App.SecExp.unit.list()) {
		App.SecExp.unit.gen(unit);
		V.SecExp.units[unit].squads.forEach(u => {
			if (unit === 'bots') {
				u.active = Math.max(0, u.active) || V.arcologyUpgrade.drones > 0 ? 1 : 0;
				u.troops = Math.max(u.troops || 0, V.arcologyUpgrade.drones > 0 ? 30 : 0);
				u.maxTroops = Math.max(u.maxTroops || 0, V.arcologyUpgrade.drones > 0 ? 30 : 0);
				if (V.secBots) {
					V.SecExp.units.bots.squads[0] = Object.assign(V.secBots, {platoonName: "1st " + data.defaultName});
				}
				if (V.SecExp.units[unit].squads.length === 1 && !u.platoonName) {
					u.platoonName = "1st " + data.defaultName;
				}
			} else {
				u.SF = u.SF || 0;
				if (!jsDef(u.ID)) {
					u.ID = genID();
				}
				u.cyber = u.cyber || 0;
				u.commissars = u.commissars || 0;
				u.troops = Math.clamp(u.troops, 0, u.maxTroops || 30);
				u.training = Math.clamp(u.training, 0, 100);
				if (V.SF.Active < 1) {
					u.SF = 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;
		});
	}

	if (V.SecExp.units.mercs.free === 0) {
		if (V.mercenaries === 1) {
			V.SecExp.units.mercs.free = 15;
		} else if (V.mercenaries > 1) {
			V.SecExp.units.mercs.free = 30;
		}
	}

	if (V.SecExp.defaultNames) {
		V.SecExp.units.slaves.defaultName = V.SecExp.defaultNames.slaves;
		V.SecExp.units.militia.defaultName = V.SecExp.defaultNames.milita || V.SecExp.defaultNames.militia;
		V.SecExp.units.mercs.defaultName = V.SecExp.defaultNames.mercs;
		delete V.SecExp.defaultNames;
	}

	V.SecExp.smilingMan.progress = V.SecExp.smilingMan.progress || V.smilingManProgress || 0;
	if (jsDef(V.smilingManFate)) {
		if (V.smilingManFate === 0) { // Offer $him a new life
			V.SecExp.smilingMan.progress = 10;
		} else if (V.smilingManFate === 1) { // Make $him pay
			V.SecExp.smilingMan.progress = 20;
		} else if (V.smilingManFate === 2) { // Enslave $him
			V.SecExp.smilingMan.progress = 30;
		}
	}

	if (V.SecExp.smilingMan.progress === 4) {
		V.SecExp.smilingMan.progress = 10;
	} else if (V.SecExp.smilingMan.progress < 4) {
		if (V.SecExp.smilingMan.progress === 0 && V.investedFunds) {
			V.SecExp.smilingMan.investedFunds = V.investedFunds;
		}
		if (V.relationshipLM) {
			V.SecExp.smilingMan.relationship = V.relationshipLM;
		}
		if (V.globalCrisisWeeks) {
			V.SecExp.smilingMan.globalCrisisWeeks = V.globalCrisisWeeks;
		}
	}

	delete V.SecExp.core.crimeCap;
	V.SecExp.core.trade = V.SecExp.core.trade || V.trade || 0;
	App.SecExp.initTrade();

	V.SecExp.core.authority = V.SecExp.core.authority || V.authority || 0;
	V.SecExp.core.security = V.SecExp.core.security || V.security || 100;
	if (jsDef(V.SecExp.security)) {
		V.SecExp.core.security = V.SecExp.security.cap;
		delete V.SecExp.security;
	}
	V.SecExp.core.totalKills = +V.SecExp.core.totalKills || V.totalKills || 0;

	if (V.week === 1 || !jsDef(V.SecExp.core.crimeLow)) {
		V.SecExp.core.crimeLow = 30;
	}
	V.SecExp.core.crimeLow = Math.clamp(V.SecExp.core.crimeLow, 0, 100) || V.crime || 0;

	V.SecExp.battles.slaveVictories = V.SecExp.battles.slaveVictories || V.slaveVictories || [];
	V.SecExp.battles.major = V.SecExp.battles.major || 0;
	if (jsDef(V.majorBattlesCount)) {
		if (V.majorBattlesCount === 0 && V.hasFoughtMajorBattleOnce === 1) {
			V.SecExp.battles.major = 1;
		} else {
			V.SecExp.battles.major = V.majorBattlesCount;
		}
	}
	V.SecExp.battles.victories = V.SecExp.battles.victories || V.PCvictories || 0;
	V.SecExp.battles.victoryStreak = V.SecExp.battles.victoryStreak || V.PCvictoryStreak || 0;
	V.SecExp.battles.losses = V.SecExp.battles.losses || V.PClosses || 0;
	V.SecExp.battles.lossStreak = V.SecExp.battles.lossStreak || V.PClossStreak || 0;
	V.SecExp.battles.lastEncounterWeeks = V.SecExp.battles.lastEncounterWeeks || V.lastAttackWeeks || 0;
	V.SecExp.battles.lastSelection = V.SecExp.battles.lastSelection || V.lastSelection || [];
	V.SecExp.battles.saved = V.SecExp.battles.saved || {};
	V.SecExp.battles.saved.commander = V.SecExp.battles.saved.commander || V.SavedLeader || "";
	V.SecExp.battles.saved.sfSupport = V.SecExp.battles.saved.sfSupport || V.SavedSFI || 0;

	V.SecExp.rebellions.tension = V.SecExp.rebellions.tension || V.tension || 0;
	V.SecExp.rebellions.slaveProgress = V.SecExp.rebellions.slaveProgress || V.slaveProgress || 0;
	V.SecExp.rebellions.citizenProgress = V.SecExp.rebellions.citizenProgress || V.citizenProgress || 0;
	V.SecExp.rebellions.victories = V.SecExp.rebellions.victories || V.PCrebWon || 0;
	V.SecExp.rebellions.losses = V.SecExp.rebellions.losses || V.PCrebLoss || 0;
	V.SecExp.rebellions.lastEncounterWeeks = V.SecExp.rebellions.lastEncounterWeeks || V.lastRebellionWeeks || 0;
	if (V.SFGear) {
		V.SecExp.rebellions.sfArmor = V.SFGear;
	}

	V.SecExp.settings.difficulty = V.SecExp.settings.difficulty || 1;
	if (jsDef(V.difficulty)) {
		V.SecExp.settings.difficulty = V.difficulty;
	}

	if (!jsDef(V.SecExp.settings.battle.enabled)) {
		V.SecExp.settings.battle.enabled = 1;
	}
	if (jsDef(V.battlesEnabled)) {
		V.SecExp.settings.battle.enabled = V.battlesEnabled;
	}
	delete V.SecExp.battle;

	V.SecExp.settings.battle.frequency = V.SecExp.settings.battle.frequency || 1;
	if (jsDef(V.battleFrequency)) {
		V.SecExp.settings.battle.frequency = V.battleFrequency;
	}
	V.SecExp.settings.battle.force = V.SecExp.settings.battle.force || 0;
	if (jsDef(V.forceBattle)) {
		V.SecExp.settings.battle.force = V.forceBattle;
	}

	if (V.readiness && V.readiness === 10 || V.sectionInFirebase) {
		V.SecExp.sectionInFirebase = 1;
	}

	V.SecExp.settings.unitDescriptions = V.SecExp.settings.unitDescriptions || 0;

	if (!jsDef(V.SecExp.settings.battle.allowSlavePrestige)) {
		V.SecExp.settings.battle.allowSlavePrestige = 1;
	}
	if (jsDef(V.allowPrestigeFromBattles)) {
		V.SecExp.settings.battle.allowSlavePrestige = V.allowPrestigeFromBattles;
	}

	V.SecExp.settings.battle.major.enabled = V.SecExp.settings.battle.major.enabled || 0;
	if (jsDef(V.majorBattlesEnabled)) {
		V.SecExp.settings.battle.major.enabled = V.majorBattlesEnabled;
	}

	if (!jsDef(V.SecExp.settings.battle.major.gameOver)) {
		V.SecExp.settings.battle.major.gameOver = 1;
	}
	if (jsDef(V.majorBattleGameOver)) {
		V.SecExp.settings.battle.major.gameOver = V.majorBattleGameOver;
	}
	V.SecExp.settings.battle.major.force = V.SecExp.settings.battle.major.force || 0;
	if (jsDef(V.forceMajorBattle)) {
		V.SecExp.settings.battle.major.force = V.forceMajorBattle;
	}
	V.SecExp.settings.battle.major.mult = V.SecExp.settings.battle.major.mult || 1;

	if (!jsDef(V.SecExp.settings.rebellion.enabled)) {
		V.SecExp.settings.rebellion.enabled = 1;
	}
	if (jsDef(V.rebellionsEnabled)) {
		V.SecExp.settings.rebellion.enabled = V.rebellionsEnabled;
	}

	V.SecExp.settings.rebellion.force = V.SecExp.settings.rebellion.force || 0;
	if (jsDef(V.forceRebellion)) {
		V.SecExp.settings.rebellion.force = V.forceRebellion;
	}
	if (!jsDef(V.SecExp.settings.rebellion.gameOver)) {
		V.SecExp.settings.rebellion.gameOver = 1;
	}
	if (jsDef(V.rebellionGameOver)) {
		V.SecExp.settings.rebellion.gameOver = V.rebellionGameOver;
	}

	V.SecExp.settings.rebellion.speed = V.SecExp.settings.rebellion.speed || 1;
	if (jsDef(V.rebellionSpeed)) {
		V.SecExp.settings.rebellion.speed = V.rebellionSpeed;
	}

	V.SecExp.settings.showStats = V.SecExp.settings.showStats || 0;
	if (jsDef(V.showBattleStatistics)) {
		V.SecExp.settings.showStats = V.showBattleStatistics;
	}

	App.SecExp.BC.propHub();
	App.SecExp.BC.barracks();
	App.SecExp.BC.secHub();
	App.SecExp.BC.transportHub();
	App.SecExp.BC.riotCenter();
	App.SecExp.BC.weaponsManufacturing();

	V.SecExp.proclamation.cooldown = V.SecExp.proclamation.cooldown || V.proclamationsCooldown || 0;
	V.SecExp.proclamation.currency = V.SecExp.proclamation.currency || V.proclamationCurrency || "";
	V.SecExp.proclamation.type = V.SecExp.proclamation.type || "crime";
	if (jsDef(V.proclamationType) && V.proclamationType !== "none") {
		V.SecExp.proclamation.type = V.proclamationType;
	}

	V.SecExp.rebellions.repairTime = V.SecExp.rebellions.repairTime || {};
	if (jsDef(V.garrison)) {
		if (V.garrison.waterwayTime > 0) {
			V.SecExp.rebellions.repairTime.waterway = V.garrison.waterwayTime;
		}
		if (V.garrison.assistantTime > 0) {
			V.SecExp.rebellions.repairTime.assistant = V.garrison.assistantTime;
		}
		if (V.garrison.reactorTime > 0) {
			V.SecExp.rebellions.repairTime.reactor = V.garrison.reactorTime;
		}
	}
	if (V.arcRepairTime && V.arcRepairTime > 0) {
		V.SecExp.rebellions.repairTime.arc = V.arcRepairTime;
	}

	delete V.SecExp.settings.show;
};

repo_name: Pecanus/fc

license: mit


code:
/** @returns {DocumentFragment} */
App.SecExp.securityReport = function() {
	let immigration = 0;
	let emigration = 0;
	let secGrowth = 0;
	let crimeGrowth = 0;
	if (V.ACitizens > V.oldACitizens) {
		immigration = V.ACitizens - V.oldACitizens;
	} else {
		emigration = V.oldACitizens - V.ACitizens; // takes into account citizens leaving and those getting enslaved
	}
	const activeUnits = App.SecExp.battle.activeUnits();
	/** @type {(string|HTMLElement|DocumentFragment)[]} */
	let r = V.useTabs === 0 ? ['
Security
'] : [];

	if (V.SecExp.buildings.secHub && V.SecExp.buildings.secHub.menials > 0) {
		r.push(`${num(V.SecExp.buildings.secHub.menials)} slaves work to improve the security of your arcology, while your`);
	} else {
		r.push(`Your`);
	}

	if (V.mercenaries >= 1 && V.arcologyUpgrade.drones === 1) {
		r.push(`mercenaries and security drones tirelessly patrol the streets to keep them safe.`);
	} else if (V.arcologyUpgrade.drones === 1) {
		r.push(`security drones tirelessly patrol the arcology to keep it safe.`);
	} else {
		r.push(`loyal subordinates try to keep the arcology safe to the best of their abilities.`);
	}

	// security modifiers
	if (V.PC.career === "mercenary") {
		r.push(`Your past life as a mercenary makes it easier to manage the security of the arcology.`);
		secGrowth += 1;
	}
	if (V.SecExp.smilingMan.progress === 10) {
		r.push(`The ex-criminal known to the world as The Smiling Man puts their impressive skills to work, dramatically increasing the efficiency of your security measures.`);
		secGrowth += 2;
	}
	if (V.ACitizens + V.ASlaves <= 5000) {
		r.push(`The small number of residents makes their job easier.`);
		secGrowth += 2;
	} else if (V.ACitizens + V.ASlaves <= 7500) {
		r.push(`The fairly low number of residents makes their job a little easier.`);
		secGrowth += 1;
	} else if (V.ACitizens + V.ASlaves <= 10000) {
		r.push(`The fairly high number of residents makes their job a little harder.`);
		secGrowth -= -0.5;
	} else if (V.ACitizens + V.ASlaves <= 15000) {
		r.push(`The high number of residents makes their job harder.`);
		secGrowth -= 1;
	} else {
		r.push(`The extremely high number of residents makes their job a lot harder.`);
		secGrowth -= 2;
	}
	if (immigration >= 0 && emigration === 0) {
		if (immigration < 50) {
			r.push(`The limited number of immigrants that reached the arcology this week does not have any serious impact on the efficiency of current security measures.`);
			secGrowth += 0.5;
		} else if (immigration < 150) {
			r.push(`The number of immigrants that reached the arcology this week is high enough to complicate security protocols.`);
			secGrowth -= 0.2;
		} else if (immigration < 300) {
			r.push(`The high number of immigrants that reached the arcology this week complicates security protocols.`);
			secGrowth -= 0.5;
		} else if (immigration < 500) {
			r.push(`The high number of immigrants that reached the arcology this week severely complicates security protocols.`);
			secGrowth -= 1;
		} else {
			r.push(`The extremely high number of immigrants that reached the arcology this week severely complicates security protocols.`);
			secGrowth -= 2;
		}
	}
	if (V.visitors < 300) {
		r.push(`The limited number of visitors coming and going did not have any serious impact on the efficiency of current security measures.`);
		secGrowth += 0.5;
	} else if (immigration < 750) {
		r.push(`The number of visitors coming and going somewhat complicates security protocols.`);
		secGrowth -= 0.2;
	} else if (immigration < 1500) {
		r.push(`The high number of visitors coming and going complicates security protocols.`);
		secGrowth -= 0.5;
	} else if (immigration < 2500) {
		r.push(`The high number of visitors coming and going greatly complicates security protocols.`);
		secGrowth -= 1;
	} else {
		r.push(`The extremely high number of visitors coming and going severely complicates security protocols.`);
		secGrowth -= 2;
	}
	if (emigration !== 0 && immigration === 0) {
		if (emigration < 100) {
			r.push(`The limited reduction in citizens this week does not have any serious impact on the efficiency of current security measures.`);
			secGrowth += 0.5;
		} else if (emigration < 300) {
			r.push(`The reduction in citizens this week is high enough to complicate security protocols.`);
			secGrowth -= 0.2;
		} else if (emigration < 600) {
			r.push(`The large reduction in citizens this week complicates security protocols.`);
			secGrowth -= 0.5;
		} else if (emigration < 1000) {
			r.push(`The huge reduction in citizens this week severely complicates security protocols.`);
			secGrowth -= 1;
		} else {
			r.push(`The extreme reduction in citizens this week severely complicates security protocols.`);
			secGrowth -= 2;
		}
	}
	if (V.SecExp.core.crimeLow < 20) {
		r.push(`Crime is a distant problem in the arcology, which makes improving security easier.`);
		secGrowth += 1;
	} else if (V.SecExp.core.crimeLow < 40) {
		r.push(`Crime is a minor problem in the arcology, not serious enough to disrupt security efforts.`);
	} else if (V.SecExp.core.crimeLow < 60) {
		r.push(`Crime is an issue in the arcology, which makes improving security harder.`);
		secGrowth -= 0.5;
	} else if (V.SecExp.core.crimeLow < 80) {
		r.push(`Crime is an overbearing problem in the arcology, which makes improving security a lot harder.`);
		secGrowth -= 1;
	} else {
		r.push(`Crime is sovereign in the arcology, which makes improving security extremely difficult.`);
		secGrowth -= 2;
	}
	if (V.SecExp.core.authority < 5000) {
		r.push(`The low authority you hold on the arcology hampers the efforts of your security department.`);
		secGrowth -= 1;
	} else if (V.SecExp.core.authority < 7500) {
		r.push(`The limited authority you hold on the arcology hampers the efforts of your security department.`);
		secGrowth -= 0.5;
	} else if (V.SecExp.core.authority < 10000) {
		r.push(`The authority you hold on the arcology does not significantly impact the efforts of your security department.`);
	} else if (V.SecExp.core.authority < 15000) {
		r.push(`The high authority you hold on the arcology facilitates the security department's work.`);
		secGrowth += 0.5;
	} else {
		r.push(`The absolute authority you hold on the arcology makes the security department's work a lot easier.`);
		secGrowth += 1;
	}
	if (activeUnits >= 6) {
		r.push(`Your military is the size of a small army. Security is easier to maintain with such forces at your disposal.`);
		secGrowth += 0.5;
	}
	if (V.SecExp.battles.victories + V.SecExp.battles.losses >= 1) {
		if (V.SecExp.battles.lastEncounterWeeks < 3) {
			r.push(`The recent attack has a negative effect on the security of the arcology.`);
			secGrowth -= 1;
		} else if (V.SecExp.battles.lastEncounterWeeks < 5) {
			r.push(`While some time has passed, the last attack still has a negative effect on the security of the arcology.`);
			secGrowth -= 0.5;
		} else {
			r.push(`The arcology has not been attacked in a while, which has a positive effect on security.`);
			secGrowth += 0.5;
		}
	}

	if (V.SecExp.buildings.transportHub) {
		secGrowth -= (V.SecExp.buildings.transportHub.airport + V.SecExp.buildings.transportHub.surfaceTransport - V.SecExp.buildings.transportHub.security * 3) / 2;
		r.push(`The transport hub, for all its usefulness, is a hotspot of malicious`);
		if (V.SecExp.buildings.transportHub.airport + V.SecExp.buildings.transportHub.surfaceTransport > V.SecExp.buildings.transportHub.security * 3) {
			r.push(`activity and hub security forces are not sufficient to keep up with all threats.`);
		} else {
			r.push(`activity, but the hub security forces are up to the task.`);
		}
	}

	if (V.SecExp.buildings.propHub && V.SecExp.buildings.propHub.upgrades.blackOps > 0) {
		r.push(`Your black ops team proves to be a formidable tool against anyone threatening the security of your arcology.`);
		secGrowth += 0.5 * random(1, 2);
	}

	const assistantDamaged = App.SecExp.updateFacilityDamage("assistant");
	r.push(assistantDamaged.text);
	secGrowth -= assistantDamaged.security;
	crimeGrowth += assistantDamaged.crime;

	if (V.SF.Toggle && V.SF.Active >= 1) {
		if (V.SecExp.edicts.SFSupportLevel >= 3) {
			r.push(`The two squads of ${V.SF.Lower} assigned to the Security HQ provide an essential help to the security department.`);
		}
		if (V.SecExp.edicts.SFSupportLevel >= 2) {
			r.push(`The training officers of ${V.SF.Lower} assigned to the Security HQ improve its effectiveness.`);
		}
		if (V.SecExp.edicts.SFSupportLevel >= 1) {
			r.push(`Providing your Security Department with equipment from ${V.SF.Lower} slightly boosts the security of your arcology.`);
		}
		secGrowth *= 1+(V.SecExp.edicts.SFSupportLevel/10);
	}

	let secRest = App.SecExp.Check.secRestPoint() * (Math.clamp(V.SecExp.buildings.secHub ? V.SecExp.buildings.secHub.menials : 0, 0, App.SecExp.Check.reqMenials()) / App.SecExp.Check.reqMenials());
	secRest = Math.max(20, secRest);
	if (secRest < App.SecExp.Check.reqMenials() && V.SecExp.buildings.secHub) {
		r.push(`The limited staff assigned to the HQ hampered the improvements to security achieved this week.`);
	} else if (secRest < App.SecExp.Check.reqMenials()) {
		r.push(`The limited infrastructure available slowly erodes away the security level of the arcology.`);
	}

	r.push(`The security level of the arcology is`);
	if (V.SecExp.core.security > (secRest + 5)) {
		r.push(`over its effective resting point, limiting the achievable growth this week.`);
		secGrowth *= 0.5;
	} else if (V.SecExp.core.security < (secRest - 5)) {
		r.push(`under its effective resting point, speeding up its growth.`);
		secGrowth *= 1.5;
	} else if (V.SecExp.core.security === secRest) {
		r.push(`at its effective resting point, this severely limits the influence of external factors on the change achievable this week.`);
		secGrowth *= 0.3;
	} else {
		r.push(`near its effective resting point, this severely limits the influence of external factors on the change achievable this week.`);
		if (secGrowth < 0) {
			secGrowth *= 0.3;
		}
	}

	const restGrowth = (secRest - V.SecExp.core.security) * 0.2;
	const newSec = Math.trunc(V.SecExp.core.security + secGrowth + restGrowth);
	if (newSec < V.SecExp.core.security) {
		r.push(`This week <span class="red">security decreased.</span>`);
	} else if (newSec === V.SecExp.core.security) {
		r.push(`This week <span class="yellow">security did not change.</span>`);
	} else {
		r.push(`This week <span class="green">security improved.</span>`);
	}
	V.SecExp.core.security = Math.clamp(newSec, 0, 100);

	r.push(`<br><br><strong>Crime</strong>:`);
	r.push(`Due to the deterioration of the old world countries, organized crime focuses more and more on the prosperous Free Cities, yours included. This has a`);
	if (V.week < 30) {
		r.push(`small`);
		crimeGrowth += 0.5;
	} else if (V.week < 60) {
		r.push(`noticeable`);
		crimeGrowth += 1;
	} else if (V.week < 90) {
		r.push(`moderate`);
		crimeGrowth += 1.5;
	} else if (V.week < 120) {
		r.push(`big`);
		crimeGrowth += 2;
	} else {
		r.push(`huge`);
		crimeGrowth += 2.5;
	}
	r.push(`impact on the growth of criminal activities in your arcology.`);

	if (V.arcologies[0].prosperity < 50) {
		r.push(`The low prosperity of the arcology facilitates criminal recruitment and organization.`);
		crimeGrowth += 1;
	} else if (V.arcologies[0].prosperity < 80) {
		r.push(`The fairly low prosperity of the arcology facilitates criminal recruitment and organization.`);
		crimeGrowth += 0.5;
	} else if (V.arcologies[0].prosperity < 120) {
		r.push(`The prosperity of the arcology is not high or low enough to have significant effects on criminal recruitment and organization.`);
	} else if (V.arcologies[0].prosperity < 160) {
		r.push(`The prosperity of the arcology is high enough to provide its citizens a decent life, hampering criminal recruitment and organization.`);
		crimeGrowth -= 0.5;
	} else if (V.arcologies[0].prosperity < 180) {
		r.push(`The prosperity of the arcology is high enough to provide its citizens a decent life, significantly hampering criminal recruitment and organization.`);
		crimeGrowth -= 1;
	} else {
		r.push(`The prosperity of the arcology is high enough to provide its citizens a very good life, significantly hampering criminal recruitment and organization.`);
		crimeGrowth -= 2;
	}
	if (V.ASlaves < 1000) {
		r.push(`The low number of slaves in the arcology does not hinder the activity of law enforcement, limiting crime growth.`);
		crimeGrowth -= 1;
	} else if (V.ASlaves < 2000) {
		r.push(`The fairly low number of slaves in the arcology does not hinder significantly the activity of law enforcement, limiting crime growth.`);
		crimeGrowth -= 0.5;
	} else if (V.ASlaves < 3000) {
		r.push(`The number of slaves in the arcology is becoming an impediment for law enforcement, facilitating crime growth.`);
		crimeGrowth += 1;
	} else {
		r.push(`The number of slaves in the arcology is becoming a big issue for law enforcement, facilitating crime growth.`);
		crimeGrowth += 1.5;
	}
	if (V.SecExp.core.security <= 20) {
		r.push(`The security measures in place are severely limited, allowing crime to grow uncontested.`);
	} else if (V.SecExp.core.security <= 50) {
		r.push(`The security measures in place are of limited effect and use, giving only mixed results in their fight against crime.`);
		crimeGrowth -= 1.5;
	} else if (V.SecExp.core.security <= 75) {
		r.push(`The security measures in place are well developed and effective, making a serious dent in the profitability of criminal activity in your arcology.`);
		crimeGrowth -= 3;
	} else {
		r.push(`The security measures in place are extremely well developed and very effective, posing a serious threat even to the most powerful criminal organizations in existence.`);
		crimeGrowth -= 5.5;
	}
	if (V.SecExp.core.authority < 5000) {
		r.push(`Your low authority allows crime to grow undisturbed.`);
		crimeGrowth += 1;
	} else if (V.SecExp.core.authority < 7500) {
		r.push(`Your relatively low authority facilitates criminal activities.`);
		crimeGrowth += 0.5;
	} else if (V.SecExp.core.authority < 10000) {
		r.push(`Your authority is not high enough to discourage criminal activity.`);
	} else if (V.SecExp.core.authority < 15000) {
		r.push(`Your high authority is an effective tool against crime.`);
		crimeGrowth -= 1;
	} else {
		r.push(`Your absolute authority is an extremely effective tool against crime.`);
		crimeGrowth -= 2;
	}
	if (V.cash >= 100000) {
		r.push(`Your great wealth acts as a beacon for the greediest criminals, calling them to your arcology as moths to a flame.`);
		crimeGrowth += 0.5;
	}
	if (V.SecExp.buildings.propHub && V.SecExp.buildings.propHub.upgrades.marketInfiltration > 0) {
		crimeGrowth += 0.5 * random(1, 2);
	}

	const crimeCap = Math.trunc(Math.clamp(App.SecExp.Check.crimeCap() + (App.SecExp.Check.crimeCap() - App.SecExp.Check.crimeCap() * ((V.SecExp.buildings.secHub ? V.SecExp.buildings.secHub.menials : 0) / App.SecExp.Check.reqMenials())), 0, 100));
	if (V.SecExp.buildings.secHub) {
		if (crimeCap > App.SecExp.Check.crimeCap()) {
			r.push(`The limited staff assigned to the HQ allows more space for criminals to act.`);
		}
		if (V.SecExp.buildings.secHub.coldstorage < 6) {
			if (V.SecExp.core.authority > 12000) {
				if (V.SecExp.buildings.secHub.coldstorage === 0) {
					r.push(`Adding a facility`);
				} else {
					r.push(`Improving the cold storage facility attached`);
				}
				r.push(`to the SecurityHQ should allow the staff to be more efficient in dealing with crime.`);
			}
		} else {
			r.push(`The cold storage facility attached to SecurityHQ allows the staff to be more efficient in dealing with crime.`);
		}
	}
	const newCrime = Math.trunc(Math.clamp(V.SecExp.core.crimeLow + crimeGrowth, 0, crimeCap));
	if (newCrime > V.SecExp.core.crimeLow) {
		r.push(`This week <span class="red">crime increased.</span>`);
	} else if (newCrime === V.SecExp.core.crimeLow) {
		r.push(`This week <span class="yellow">crime did not change.</span>`);
	} else {
		r.push(`This week <span class="green">crime decreased.</span>`);
	}
	V.SecExp.core.crimeLow = Math.clamp(newCrime, 0, 100);

	if (V.SecExp.edicts.defense.militia >= 1 || activeUnits >= 1) {
		r.push(`<br><br> <strong>Military</strong>:`);
		if (V.SecExp.edicts.defense.militia >= 1) {
			let recruitsMultiplier = 1;
			let recruitLimit = 0;
			let adjst;

			const SF = App.SecExp.assistanceSF('security', 'militia');
			r.push(SF.text); recruitsMultiplier += SF.bonus;

			const propagandaEffects = App.SecExp.propagandaEffects("recruitment");
			r.push(propagandaEffects.text);
			recruitsMultiplier *= (1 + propagandaEffects.effect);
			if (V.SecExp.edicts.defense.militia === 2) {
				r.push(`Your militia accepts only volunteering citizens, ready to defend their arcology.`);
				recruitLimit = App.SecExp.militiaCap(); adjst = 0.0025;
				if (V.rep >= 10000) {
					r.push(`Many citizens volunteer just to fight for someone of your renown.`);
					recruitLimit += adjst;
				}
				if (V.SecExp.core.authority >= 10000) {
					r.push(`Many citizens feel it is their duty to fight for you, boosting volunteer enrollment.`);
					recruitLimit += adjst;
				}
			} else if (V.SecExp.edicts.defense.militia === 3) {
				r.push(`Adult citizens are required to join the militia for a period of time.`);
				recruitLimit = App.SecExp.militiaCap(); adjst = 0.005;
			} else if (V.SecExp.edicts.defense.militia === 4) {
				r.push(`Adult citizens are required to register and serve in the militia whenever necessary.`);
				recruitLimit = App.SecExp.militiaCap(); adjst = 0.01;
			} else if (V.SecExp.edicts.defense.militia === 5) {
				r.push(`Every citizen is required to train and participate in the military activities of the arcology.`);
				recruitLimit = App.SecExp.militiaCap(); adjst = 0.02;
			}
			if (V.SecExp.edicts.defense.lowerRequirements === 1) {
				r.push(`Your lax physical requirements to enter the militia allows for a greater number of citizens to join.`);
				recruitLimit += adjst;
			}
			if (V.SecExp.edicts.defense.militia >= 3) {
				if (V.SecExp.edicts.defense.militaryExemption === 1) {
					r.push(`Some citizens prefer to contribute to the arcology's defense through financial support rather than military service, making you <span class="yellowgreen">a small sum.</span>`);
					recruitLimit -= adjst;
					cashX(250, "securityExpansion");
				}
				if (V.SecExp.edicts.defense.noSubhumansInArmy === 1) {
					r.push(`Guaranteeing the purity of your armed forces comes with a small loss of potential recruits.`);
					recruitLimit -= adjst;
				}
				if (V.SecExp.edicts.defense.pregExemption === 1) {
					r.push(`Many pregnant citizens prefer to avoid military service not to endanger themselves and their children.`);
					recruitLimit -= adjst;
				}
			}

			const recruits = Math.trunc((recruitLimit * V.ACitizens - App.SecExp.Manpower.totalMilitia) / 20 * recruitsMultiplier);
			if (recruits > 0) {
				V.SecExp.units.militia.free += recruits;
				r.push(`This week ${recruits} citizens joined the militia.<br>`);
			} else if (V.SecExp.edicts.defense.militia === 5) {
				r.push(`No citizens joined your militia this week because your society is as militarized as it can get.<br>`);
			} else if (V.SecExp.edicts.defense.militia === 2) {
				r.push(`There are no more citizens willing to join the arcology armed forces. You'll need to enact higher recruitment edicts if you need more manpower.<br>`);
			} else {
				r.push(`No more citizens could be drafted into your militia. You'll need to enact higher recruitment edicts if you need more manpower.<br>`);
			}
		}

		if (V.mercenaries >= 1) { // mercs
			let newMercs = random(0, 3);
			if (V.rep < 6000) {
				r.push(`Your low reputation turns some mercenaries away, hoping to find contracts that would bring them more renown.`);
				newMercs -= 1;
			} else if (V.rep < 12000) {
				r.push(`Your reputation is not high enough to attract many mercenaries to your free city.`);
			} else {
				r.push(`Your reputation attracts many guns for hire who would be proud to have such distinct character on their resume.`);
				newMercs += 1;
			}
			if (V.arcologies[0].prosperity < 50) {
				r.push(`The low prosperity of the arcology discourages new guns for hire from coming to your arcology.`);
				newMercs -= 1;
			} else if (V.arcologies[0].prosperity < 80) {
				r.push(`The fairly low prosperity of the arcology discourages new guns for hire from coming to your arcology.`);
				newMercs += 1;
			} else if (V.arcologies[0].prosperity < 120) {
				r.push(`The prosperity of the arcology attracts a few mercenaries, hopeful to find lucrative contracts within its walls.`);
				newMercs += random(1, 2);
			} else if (V.arcologies[0].prosperity < 160) {
				r.push(`The fairly high prosperity of the arcology attracts some mercenaries, hopeful to find lucrative contracts within its walls.`);
				newMercs += random(2, 3);
			} else if (V.arcologies[0].prosperity < 180) {
				r.push(`The high prosperity of the arcology is attracts some mercenaries, hopeful to find lucrative contracts within its walls.`);
				newMercs += random(2, 4);
			} else {
				r.push(`The very high prosperity of the arcology attracts a lot of mercenaries, hopeful to find lucrative contracts within its walls.`);
				newMercs += random(3, 5);
			}
			if (V.SecExp.core.crimeLow > 60) {
				r.push(`The powerful crime organizations that nested themselves in the arcology have an unending need for cheap guns for hire, many mercenaries flock to your free city in search of employment.`);
				newMercs += random(1, 2);
			}

			const SF = App.SecExp.assistanceSF('security', 'mercs');
			r.push(SF.text); newMercs += SF.bonus;

			if (V.SecExp.edicts.defense.discountMercenaries > 0) {
				r.push(`More mercenaries are attracted to your arcology as a result of the reduced rent.`);
				newMercs += random(2, 4);
			}
			newMercs = Math.trunc(newMercs / 2);
			if (newMercs > 0) {
				V.SecExp.units.mercs.free += newMercs;
				r.push(`This week ${newMercs} mercenaries reached the arcology.<br>`);
			} else {
				r.push(`This week no new mercenaries reached the arcology.<br>`);
			}
			V.SecExp.units.mercs.free = Math.clamp(V.SecExp.units.mercs.free, 0, 2000);
		}

		if (activeUnits > 0 && App.SecExp.unit.squads("human").length > 0) { // loyalty and training
			for (const squad of App.SecExp.unit.squads("human")) {
				r.push(App.SecExp.humanLoyaltyChanges(squad));
			}
		}
	}

	if (V.SecExp.buildings.riotCenter && V.SecExp.buildings.riotCenter.brainImplantProject > 0 && V.SecExp.buildings.riotCenter.brainImplant < 106) {
		r.push(`<br><br>`);
		V.SecExp.buildings.riotCenter.brainImplant += V.SecExp.buildings.riotCenter.brainImplantProject;
		if (100 - V.SecExp.buildings.riotCenter.brainImplant <= 0) {
			r.push(`The project has been completed!`);
			V.SecExp.buildings.riotCenter.brainImplant = 106;
		} else {
			r.push(`The great brain implant project is proceeding steadily. This week we made`);
			if (V.SecExp.buildings.riotCenter.brainImplantProject <= 2) {
				r.push(`some small progress.`);
			} else if (V.SecExp.buildings.riotCenter.brainImplantProject <= 4) {
				r.push(`some progress.`);
			} else {
				r.push(`good progress.`);
			}
		}
	}

	if (V.SecExp.buildings.weapManu) {
		if (App.SecExp.weapManu.completed()) {
			delete V.SecExp.buildings.weapManu.upgrades.queue;
		}
		if (V.SecExp.buildings.weapManu.upgrades.queue) {
			for (let item = 0; item < V.SecExp.buildings.weapManu.upgrades.queue.length; item++) {
				const currentItem = V.SecExp.buildings.weapManu.upgrades.queue[item];
				Object.assign(currentItem, App.SecExp.weapManu.current(currentItem.ID));
				if (item === 0) {
					currentItem.time--;
					r.push(`<br>In the research lab, ${currentItem.dec}`);
					switch (currentItem.dec) {
						case "adaptive armored frames":
						case "advanced synthetic alloys":
						case "ceramo-metallic alloys":
						case "rapid action stimulants":
						case "universal cyber enhancements":
						case "remote neural links":
						case "combined training regimens with the special force":
							r.push(`are`); break;
						default: r.push(`is`);
					}
					r.push(`being developed with the aim of enhancing ${currentItem.unit}' ${currentItem.purpose}.`);
					if (currentItem.time <= 0) {
						r.push(`Reports indicate it is ready for deployment and will be issued in the following days.`);
						V.SecExp.buildings.weapManu.upgrades.completed.push(currentItem.ID);
						V.SecExp.buildings.weapManu.upgrades.queue.splice(0, 1);
					} else {
						r.push(`It will be finished in ${numberWithPluralOne(currentItem.time, "week")}.`);
					}
				} else {
					r.push(`<br>${ordinalSuffix(item + 1)} in queue: ${currentItem.dec} for ${currentItem.unit}. It will enhance their ${currentItem.purpose}.`);
				}
			}
		}
	}

	if (V.SecExp.settings.battle.enabled > 0 && App.SecExp.unit.squads().length > 0) {
		App.SecExp.generator.attack();
	}

	const frag = new DocumentFragment();
	$(frag).append(...App.Events.spaceSentences(r));
	return frag;
};


code:
globalThis.terrainAndTactics = function() {
	const el = new DocumentFragment();
	const table = App.UI.DOM.appendNewElement("table", el);
	table.classList.add("facility-stats");
	const header = table.createTHead();
	let row = header.insertRow();
	row.insertCell(); // top left corner should be empty

	const tacticTotal = new Map();

	// Column headers
	for (const terrainType of Object.keys(App.Data.SecExp.TerrainAndTactics.get("urban"))) {
		const cell = row.insertCell();
		cell.innerHTML = terrainType;
	}

	// Column summarizing which terrains are the easiest.
	const cell = row.insertCell();
	cell.innerHTML = "Ease";

	for (const [terrainType, tactics] of App.Data.SecExp.TerrainAndTactics) {
		const row = table.insertRow();

		// First cell describes terrain
		const cell = row.insertCell();
		cell.innerHTML = capFirstChar(terrainType);

		let terrainDifficulty = 0;
		for (const tactic in tactics) {
			let mods = 0;
			for (const mod of ["atkMod", "defMod", "tacChance"]) {
				mods += tactics[tactic][mod] || 0;
			}
			terrainDifficulty += mods;
			tacticTotal.set(tactic, tacticTotal.get(tactic) + mods || mods);
			const color = (mods > 0) ? "green" : "red";
			App.UI.DOM.appendNewElement("td", row, stringy(mods), color);
		}

		// Ease column entry
		App.UI.DOM.appendNewElement("td", row, stringy(terrainDifficulty));
	}

	// Row summarizing average of each tactic.
	row = table.insertRow();
	App.UI.DOM.appendNewElement("td", row, "Strength");
	for (const value of tacticTotal.values()) {
		App.UI.DOM.appendNewElement("td", row, stringy(value));
	}
	return el;

	function stringy(num) {
		return String(Math.trunc(100*num)/10);
	}
};

App.Data.SecExp.TerrainAndTactics = new Map([
	["urban", {
		"Bait and Bleed": {
			atkMod: 0.15,
			defMod: 0.10,
			tacChance: 0.25,
		},
		"Guerrilla": {
			atkMod: 0.10,
			defMod: 0.15,
			tacChance: 0.25,
		},
		"Choke Points": {
			atkMod: 0.10,
			defMod: 0.15,
			tacChance: 0.25,
		},
		"Interior Lines": {
			atkMod: 0.05,
			defMod: 0.10,
			tacChance: 0.15,
		},
		"Pincer Maneuver": {
			atkMod: -0.05,
			defMod: -0.10,
			tacChance: -0.15,
		},
		"Defense In Depth": {
			atkMod: -0.05,
			defMod: -0.05,
			tacChance: -0.10,
		},
		"Blitzkrieg": {
			atkMod: -0.15,
			defMod: -0.10,
			tacChance: -0.25,
		},
		"Human Wave": {
			atkMod: -0.15 * App.SecExp.troopDiffAdjust().enemy,
			defMod: -0.15 * App.SecExp.troopDiffAdjust().enemy,
			tacChance: -0.30 * App.SecExp.troopDiffAdjust().enemy,
		},
	}],
	["rural", {
		"Bait and Bleed": {
			atkMod: -0.05,
			defMod: -0.10,
			tacChance: -0.15,
		},
		"Guerrilla": {
			atkMod: -0.10,
			defMod: -0.10,
			tacChance: -0.20,
		},
		"Choke Points": {
			atkMod: -0.10,
			defMod: -0.15,
			tacChance: -0.25,
		},
		"Interior Lines": {
			atkMod: 0.10,
			defMod: 0.15,
			tacChance: 0.25,
		},
		"Pincer Maneuver": {
			atkMod: 0.15,
			defMod: 0.10,
			tacChance: 0.25,
		},
		"Defense In Depth": {
			atkMod: 0.15,
			defMod: 0.15,
			tacChance: 0.30,
		},
		"Blitzkrieg": {
			atkMod: 0.15,
			defMod: 0.10,
			tacChance: 0.25,
		},
		"Human Wave": {
			atkMod: 0.20 * App.SecExp.troopDiffAdjust().enemy,
			defMod: 0.05 * App.SecExp.troopDiffAdjust().enemy,
			tacChance: 0.25 * App.SecExp.troopDiffAdjust().enemy,
		},
	}],
	["hills", {
		"Bait and Bleed": {
			atkMod: 0.05,
			defMod: 0.05,
			tacChance: 0.10,
		},
		"Guerrilla": {
			atkMod: 0.05,
			defMod: 0.10,
			tacChance: 0.15,
		},
		"Choke Points": {
			atkMod: 0.10,
			defMod: 0.10,
			tacChance: 0.20,
		},
		"Interior Lines": {
			atkMod: -0.05,
			defMod: -0.05,
			tacChance: -0.10,
		},
		"Pincer Maneuver": {
			atkMod: 0.10,
			defMod: 0.05,
			tacChance: 0.15,
		},
		"Defense In Depth": {
			atkMod: -0.10,
			defMod: -0.05,
			tacChance: -0.15,
		},
		"Blitzkrieg": {
			atkMod: -0.10,
			defMod: -0.15,
			tacChance: 0.25,
		},
		"Human Wave": {
			atkMod: -0.15 * App.SecExp.troopDiffAdjust().enemy,
			defMod: -0.15 * App.SecExp.troopDiffAdjust().enemy,
			tacChance: -0.30 * App.SecExp.troopDiffAdjust().enemy,
		},
	}],
	["coast", {
		"Bait and Bleed": {
			atkMod: -0.05,
			defMod: -0.05,
			tacChance: -0.10,
		},
		"Guerrilla": {
			atkMod: 0.05,
			defMod: 0.05,
			tacChance: 0.10,
		},
		"Choke Points": {
			atkMod: 0.05,
			defMod: 0.15,
			tacChance: 0.15,
		},
		"Interior Lines": {
			atkMod: 0.10,
			defMod: 0.10,
			tacChance: 0.20,
		},
		"Pincer Maneuver": {
			atkMod: -0.10,
			defMod: -0.10,
			tacChance: -0.20,
		},
		"Defense In Depth": {
			atkMod: 0.10,
			defMod: 0.10,
			tacChance: 0.20,
		},
		"Blitzkrieg": {
			atkMod: -0.05,
			defMod: -0.05,
			tacChance: -0.10,
		},
		"Human Wave": {
			atkMod: 0.05 * App.SecExp.troopDiffAdjust().enemy,
			defMod: -0.05 * App.SecExp.troopDiffAdjust().enemy,
		},
	}],
	["outskirts", {
		"Bait and Bleed": {
			atkMod: -0.10,
			defMod: -0.15,
			tacChance: -0.25,
		},
		"Guerrilla": {
			atkMod: -0.10,
			defMod: -0.05,
			tacChance: -0.15,
		},
		"Choke Points": {
			atkMod: 0.10,
			defMod: 0.15,
			tacChance: 0.25,
		},
		"Interior Lines": {
			atkMod: 0.15,
			defMod: 0.10,
			tacChance: 0.25,
		},
		"Pincer Maneuver": {
			atkMod: 0.05,
			defMod: 0.10,
			tacChance: 0.15,
		},
		"Defense In Depth": {
			atkMod: 0.10,
			defMod: 0.15,
			tacChance: 0.25,
		},
		"Blitzkrieg": {
			atkMod: 0.10,
			defMod: -0.05,
			tacChance: 0.05,
		},
		"Human Wave": {
			atkMod: 0.10 * App.SecExp.troopDiffAdjust().enemy,
			defMod: -0.10 * App.SecExp.troopDiffAdjust().enemy,
		},
	}],
	["mountains", {
		"Bait and Bleed": {
			atkMod: 0.10,
			defMod: 0.15,
			tacChance: 0.25,
		},
		"Guerrilla": {
			atkMod: 0.10,
			defMod: 0.15,
			tacChance: 0.25,
		},
		"Choke Points": {
			atkMod: 0.05,
			defMod: 0.20,
			tacChance: 0.25,
		},
		"Interior Lines": {
			atkMod: 0.10,
			defMod: 0.10,
			tacChance: 0.20,
		},
		"Pincer Maneuver": {
			atkMod: 0.10,
			defMod: -0.05,
			tacChance: 0.05,
		},
		"Defense In Depth": {
			atkMod: 0.10,
			defMod: 0.10,
			tacChance: 0.20,
		},
		"Blitzkrieg": {
			atkMod: -0.10,
			defMod: -0.10,
			tacChance: -0.20,
		},
		"Human Wave": {
			atkMod: -0.10 * App.SecExp.troopDiffAdjust().enemy,
			defMod: -0.10 * App.SecExp.troopDiffAdjust().enemy,
			tacChance: -0.20 * App.SecExp.troopDiffAdjust().enemy,
		},
	}],
	["wasteland", {
		"Bait and Bleed": {
			atkMod: 0.05,
			defMod: 0.05,
			tacChance: 0.10,
		},
		"Guerrilla": {
			atkMod: 0.10,
			defMod: 0.05,
			tacChance: 0.15,
		},
		"Choke Points": {
			atkMod: -0.10,
			defMod: 0.05,
			tacChance: -0.05,
		},
		"Interior Lines": {
			atkMod: 0.10,
			defMod: 0.15,
			tacChance: 0.25,
		},
		"Pincer Maneuver": {
			atkMod: 0.15,
			defMod: 0.10,
			tacChance: 0.25,
		},
		"Defense In Depth": {
			atkMod: 0.05,
			defMod: 0.10,
			tacChance: 0.15,
		},
		"Blitzkrieg": {
			atkMod: 0.15,
			defMod: 0.15,
			tacChance: 0.30,
		},
		"Human Wave": {
			atkMod: 0.20 * App.SecExp.troopDiffAdjust().enemy,
			defMod: 0.05 * App.SecExp.troopDiffAdjust().enemy,
			tacChance: 0.25 * App.SecExp.troopDiffAdjust().enemy,
		},
	}],
	["international waters", {
		"Bait and Bleed": {
			atkMod: -0.05,
			defMod: -0.10,
			tacChance: -0.15,
		},
		"Guerrilla": {
			atkMod: -0.10,
			defMod: -0.10,
			tacChance: -0.20,
		},
		"Choke Points": {
			atkMod: -0.10,
			defMod: -0.15,
			tacChance: -0.25,
		},
		"Interior Lines": {
			atkMod: 0.10,
			defMod: 0.15,
			tacChance: 0.25,
		},
		"Pincer Maneuver": {
			atkMod: 0.15,
			defMod: 0.10,
			tacChance: 0.25,
		},
		"Defense In Depth": {
			atkMod: 0.15,
			defMod: 0.15,
			tacChance: 0.30,
		},
		"Blitzkrieg": {
			atkMod: 0.15,
			defMod: 0.10,
			tacChance: 0.25,
		},
		"Human Wave": {
			atkMod: 0.20 * App.SecExp.troopDiffAdjust().enemy,
			defMod: 0.05 * App.SecExp.troopDiffAdjust().enemy,
			tacChance: 0.25 * App.SecExp.troopDiffAdjust().enemy,
		},
	}],
	["an underwater cave", {
		"Bait and Bleed": {
			atkMod: -0.05,
			defMod: -0.05,
			tacChance: -0.10,
		},
		"Guerrilla": {
			atkMod: 0.30,
			defMod: 0.30,
			tacChance: 0.5,
		},
		"Choke Points": {
			atkMod: 0.30,
			defMod: 0.30,
			tacChance: 0.5,
		},
		"Interior Lines": {
			atkMod: -0.10,
			defMod: -0.15,
			tacChance: -0.05,
		},
		"Pincer Maneuver": {
			atkMod: -0.15,
			defMod: -0.10,
			tacChance: -0.25,
		},
		"Defense In Depth": {
			atkMod: 0.15,
			defMod: 0.15,
			tacChance: 0.35,
		},
		"Blitzkrieg": {
			atkMod: -0.15,
			defMod: -0.15,
			tacChance: -0.30,
		},
		"Human Wave": {
			atkMod: -0.20 * App.SecExp.troopDiffAdjust().enemy,
			defMod: -0.05 * App.SecExp.troopDiffAdjust().enemy,
			tacChance: -0.25 * App.SecExp.troopDiffAdjust().enemy,
		},
	}],
	["a sunken ship", {
		"Bait and Bleed": {
			atkMod: 0.30,
			defMod: 0.30,
			tacChance: 0.5,
		},
		"Guerrilla": {
			atkMod: 0.30,
			defMod: 0.30,
			tacChance: 0.5,
		},
		"Choke Points": {
			atkMod: 0.30,
			defMod: 0.30,
			tacChance: 0.5,
		},
		"Interior Lines": {
			atkMod: -0.10,
			defMod: -0.15,
			tacChance: -0.05,
		},
		"Pincer Maneuver": {
			atkMod: -0.15,
			defMod: -0.10,
			tacChance: -0.05,
		},
		"Defense In Depth": {
			atkMod: -0.05,
			defMod: -0.10,
			tacChance: -0.15,
		},
		"Blitzkrieg": {
			atkMod: -0.15,
			defMod: -0.15,
			tacChance: -0.30,
		},
		"Human Wave": {
			atkMod: -0.20 * App.SecExp.troopDiffAdjust().enemy,
			defMod: -0.05 * App.SecExp.troopDiffAdjust().enemy,
			tacChance: -0.25 * App.SecExp.troopDiffAdjust().enemy,
		},
	}],
]);


code:
App.SecExp.tradeReport = function() {
	let r = [];
	let tradeChange = 0;
	let bonus = 0;
	if (V.week < 30) {
		r.push(`The world economy is in good enough shape to sustain economic growth. Trade flows liberally in all the globe.`);
		tradeChange += 1;
	} else if (V.week < 60) {
		r.push(`The world economy is deteriorating, but still in good enough shape to sustain economic growth.`);
		tradeChange += 0.5;
	} else if (V.week < 90) {
		r.push(`The world economy is deteriorating, but still in decent enough shape to sustain economic growth.`);
	} else if (V.week < 120) {
		r.push(`The world economy is deteriorating and the slowing down of global growth is starting to have some effect on trade flow.`);
		tradeChange -= 1;
	} else {
		r.push(`The world economy is heavily deteriorated. The slowing down of global growth has a great negative effect on trade flow.`);
		tradeChange -= 2;
	}

	const warEffects = function(type) {
		if (V.SecExp[type].victories + V.SecExp[type].losses >= 1) {
			if (V.SecExp[type].lastEncounterWeeks < 2) {
				r.push(`The recent ${type === 'battles' ? 'attack' : 'rebellion'} has a negative effect on the trade of the arcology.`);
				tradeChange -= 1;
			} else if (V.SecExp[type].lastEncounterWeeks < 4) {
				r.push(`While some time has passed, the last ${type === 'battles' ? 'attack' : 'rebellion'} still has a negative effect on the commercial activity of the arcology.`);
				tradeChange -= 0.5;
			}
		}
	};

	warEffects('battles');
	warEffects('rebellions');

	if (V.terrain === "urban") {
		r.push(`Since your arcology is located in the heart of an urban area, its commerce is naturally vibrant.`);
		tradeChange++;
	} else if (V.terrain === "ravine") {
		r.push(`Since your arcology is located in the heart of a ravine, its commerce is hindered by a lack of accessibility.`);
		tradeChange -= 0.5;
	}

	if (["BlackHat", "capitalist", "celebrity", "wealth"].includes(V.PC.career)) {
		tradeChange += 1;
	} else if (["escort", "gang", "servant"].includes(V.PC.career)) {
		tradeChange -= 0.5;
	}

	if (V.rep > 12000) {
		r.push(`Your ${V.rep > 18000 ? 'extremely' : ''} high reputation attracts trade from all over the world.`);
		tradeChange += (V.rep > 18000 ? 2 : 1);
	}

	if (V.assistant.power > 0) {
		const lowPower = V.assistant.power === 1;
		r.push(`Due to ${lowPower ? '' : 'incredible'} computing power, ${V.assistant.name} is able to guide the commercial development of the arcology to greater levels.`);
		tradeChange += (lowPower ? 1 : 2);
	}

	if (V.SecExp.edicts.tradeLegalAid === 1) {
		r.push(`Your support in legal matters for new businesses helps improve the economic dynamicity of your arcology, boosting commercial activities.`);
		tradeChange += 1;
	}

	if (V.SecExp.edicts.taxTrade === 1) {
		r.push(`The fees imposed on transitioning goods do little to earn you the favor of the companies making use of your arcology.`);
		tradeChange -= 1;
	}

	if (V.SecExp.buildings.weapManu) {
		r.push(`The weapons manufacturing facility of the arcology attracts a significant amount of trade.`);
		tradeChange += 0.5 * (V.SecExp.buildings.weapManu.productivity + V.SecExp.buildings.weapManu.lab);
	}
	if (V.SecExp.buildings.transportHub) {
		if (V.SecExp.buildings.transportHub.airport === 1) {
			r.push(`The airport, while small, helps facilitate the commercial development of the arcology.`);
			tradeChange += 1;
		} else if (V.SecExp.buildings.transportHub.airport === 2) {
			r.push(`The airport, while fairly small, helps facilitate the commercial development of the arcology.`);
			tradeChange += 1.5;
		} else if (V.SecExp.buildings.transportHub.airport === 3) {
			r.push(`The airport helps facilitate the commercial development of the arcology.`);
			tradeChange += 2;
		} else if (V.SecExp.buildings.transportHub.airport === 4) {
			r.push(`The airport is a great boon to the commercial development of the arcology.`);
			tradeChange += 2.5;
		} else {
			r.push(`The airport is an incredible boon to the commercial development of the arcology.`);
			tradeChange += 3;
		}

		if (V.terrain !== "oceanic" && V.terrain !== "marine") {
			if (V.SecExp.buildings.transportHub.surfaceTransport === 1) {
				r.push(`The railway network's age and limited extension limit commercial activity.`);
			} else if (V.SecExp.buildings.transportHub.surfaceTransport === 2) {
				r.push(`The railway network is a great help to the commercial development of the arcology, but its limited extension hampers its potential.`);
				tradeChange += 1;
			} else if (V.SecExp.buildings.transportHub.surfaceTransport === 3) {
				r.push(`The railway network is a great help to the commercial development of the arcology.`);
				tradeChange += 1.5;
			} else {
				r.push(`The railway network is a huge help to the commercial development of the arcology. Few in the world can boast such a modern and efficient transport system.`);
				tradeChange += 2;
			}
		} else {
			if (V.SecExp.buildings.transportHub.surfaceTransport === 1) {
				r.push(`The docks' age and limited size limit commercial activity.`);
			} else if (V.SecExp.buildings.transportHub.surfaceTransport === 2) {
				r.push(`The docks are a great help to the commercial development of the arcology, but their limited size hampers its potential.`);
				tradeChange += 1;
			} else if (V.SecExp.buildings.transportHub.surfaceTransport === 3) {
				r.push(`The docks are a great help to the commercial development of the arcology.`);
				tradeChange += 1.5;
			} else {
				r.push(`The docks are a huge help to the commercial development of the arcology. Few in the world can boast such a modern and efficient transport system.`);
				tradeChange += 2;
			}
		}
	}

	const SF = App.SecExp.assistanceSF('trade');
	r.push(SF.text); tradeChange += SF.bonus;

	if (tradeChange > 0) {
		r.push(`This week <span class="green">trade improved.</span>`);
	} else if (tradeChange === 0) {
		r.push(`This week <span class="yellow">trade did not change.</span>`);
	} else {
		r.push(`This week <span class="red">trade diminished.</span>`);
	}

	V.SecExp.core.trade = Math.clamp(V.SecExp.core.trade + tradeChange, 0, 100);
	if (V.SecExp.core.trade <= 20) {
		r.push(`The almost non-existent trade crossing the arcology <span class="yellow">does little to promote growth.</span>`);
	} else if (V.SecExp.core.trade <= 40) {
		r.push(`The low level of trade crossing the arcology promotes a <span class="green">slow yet steady growth</span> of its economy.`);
		bonus += 1.5;
	} else if (V.SecExp.core.trade <= 60) {
		r.push(`With trade at positive levels, the <span class="green">prosperity of the arcology grows more powerful.</span>`);
		bonus += 2.5;
	} else if (V.SecExp.core.trade <= 80) {
		r.push(`With trade at high levels, the <span class="green">prosperity of the arcology grows quickly and violently.</span>`);
		bonus += 3.5;
	} else {
		r.push(`With trade at extremely high levels, the <span class="green">prosperity of the arcology grows with unprecedented speed.</span>`);
		bonus += 4.5;
	}

	return {text: r.join(" "), bonus: bonus};
};


code:
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.
- 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
- Does having a large standing army give any bonus to authority/reputation growth?

	Fine, I'll Do It Myself
	Pirates? Enemy navies? - 328279
	Pirates could raid trade routs and such ,even could capture a high class cruise liner and you have to move retake it with an army similar to the ground battles. you could have an event where you gain a old world port to ship your goods to, and you have to defend it .		-328413
- How to make threads - 355478
- One thing I find to be weird/stupid is that facilities must be manned with menial slaves. I think that it instead should be an option, like with armies, to man them with free citizens instead who then do a better job but instead require a monthly wage.
- Oni-girl soldiers.
- Update encyclopedia entry to reflect above.
- Add suicide units.
- Add WarAnimal's units - Optimally Functioning Code, 254511 - 3rd Military Animal Platoon.
- Loli unit - Unlocked from Black market, origin Wedding edition - 310602.
- Feature Request: Potential for damage to Security Expansion Upgrades - https://gitgud.io/pregmodfan/fc-pregmod/issues/1146
- Suggestion - Specialized Schools, Fortifications and Militia Edicts -https://gitgud.io/pregmodfan/fc-pregmod/issues/763
- Suggestion - Arcology Conquest - https://gitgud.io/pregmodfan/fc-pregmod/issues/760
- And if I am a master tactician, maybe I could get an estimate how effective the various tactics could be?
- 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).
- So would be taking slaves from slave units as personal ones. The slave units would pretty much be menial slaves I'd imagine, not sex slaves.
- If I think about it having a squad of personal slaves that you equip in whatever gear you want and send out to capture new slaves, raid caravans and cities and shit would be pretty sweet, I would even call it special forces but that's taken, also the combat skill is still a binary thing which makes the whole thing pointless.
	How about to start off with option to send one or two of your combat trained slaves to assist the merc's when they are on a raid with the possibility of receiving battle wounds.
- How about to start off with option to send one or two of your combat trained slaves to assist the merc's when they are on a raid with the possibility of receiving battle wounds.
- If there are choices, they should be along the lines of "higher risk, higher reward" (defeating the enemy with fewer casualties and damage if it goes right, but suffering higher casualties and damage if it goes wrong), or things like accepting more/less military casualties for better/worse protection of economic assets (costing money/damaging economy) and civilians (costing reputation/damaging population).
- The ability to send units to the general to increase relationship as an alternative to sending slaves.