diff --git a/devTools/FC.ts b/devTools/FC.ts
index 36c899b9169ff5c84097c4634ea8c8fdb6b7c93c..998e9f3d590a1338df1c2aa5ede39b010d6a2a7e 100644
--- a/devTools/FC.ts
+++ b/devTools/FC.ts
@@ -570,6 +570,28 @@ declare namespace FC {
 			}
 		}
 	}
+
+	namespace SecExp {
+		interface UnitData {
+			troops: number,
+			maxTroops: number,
+			equip: number
+		}
+		interface PlayerUnitData extends UnitData {
+			active: number,
+			ID: number,
+			isDeployed: number
+		}
+		interface PlayerHumanUnitData extends PlayerUnitData {
+			platoonName: string,
+			training: number,
+			loyalty: number,
+			cyber: number,
+			medics: number,
+			SF: number,
+			commissars: number
+		}
+	}
 }
 
 declare const V: FC.GameVariables;
diff --git a/js/003-data/gameVariableData.js b/js/003-data/gameVariableData.js
index ba49c027fd77f18a7d131d2e2e281edfbe50f497..93a3cf05daf6f86dd9e30dfef72f80fe447a02cc 100644
--- a/js/003-data/gameVariableData.js
+++ b/js/003-data/gameVariableData.js
@@ -494,9 +494,6 @@ App.Data.resetOnNGPlus = {
 	mercFreeManpower: 0,
 	mercEmployedManpower: 0,
 	mercTotalCasualties: 0,
-	militiaLoyalty: 0,
-	slaveArmyLoyalty: 0,
-	mercLoyalty: 0,
 	createdSlavesUnits: 0,
 	createdMilitiaUnits: 0,
 	createdMercUnits: 0,
@@ -535,11 +532,6 @@ App.Data.resetOnNGPlus = {
 	lastSelection: [],
 
 	/* statistics */
-	equipMod: 0.15,
-	secBotsBaseAttack: 7,
-	secBotsBaseDefense: 3,
-	secBotsMorale: 200,
-	secBotsBaseHp: 3,
 	militiaBaseAttack: 0,
 	militiaBaseDefense: 0,
 	militiaBaseMorale: 0,
@@ -552,33 +544,23 @@ App.Data.resetOnNGPlus = {
 	mercBaseDefense: 0,
 	mercBaseMorale: 0,
 	mercBaseHp: 0,
-	SFBaseAttack: 0,
-	SFBaseDefense: 0,
-	SFBaseMorale: 0,
-	SFBaseHp: 0,
-
-	raBaseAttack: 7,
-	raBaseDefense: 2,
-	raBaseMorale: 100,
-	raBaseHp: 2,
-	fcBaseAttack: 6,
-	fcBaseDefense: 4,
-	fcBaseMorale: 130,
-	fcBaseHp: 3,
-	owBaseAttack: 8,
-	owBaseDefense: 4,
-	owBaseMorale: 110,
-	owBaseHp: 2,
-	ffBaseAttack: 9,
-	ffBaseDefense: 2,
-	ffBaseMorale: 160,
-	ffBaseHp: 2,
 
 	/* units */
-	secBots: {},
+	/** @type {FC.SecExp.PlayerUnitData} */
+	secBots: {
+		active: 0,
+		ID: -1,
+		isDeployed: 0,
+		troops: 0,
+		maxTroops: 0,
+		equip: 0
+	},
 
+	/** @type {FC.SecExp.PlayerHumanUnitData[]} */
 	militiaUnits: [],
+	/** @type {FC.SecExp.PlayerHumanUnitData[]} */
 	slaveUnits: [],
+	/** @type {FC.SecExp.PlayerHumanUnitData[]} */
 	mercUnits: [],
 
 	/* SFanon additions */
diff --git a/src/Mods/SecExp/SecExpBackwardCompatibility.tw b/src/Mods/SecExp/SecExpBackwardCompatibility.tw
index 92f7d31b385d4186f0fba6711a369524e3b2e945..109096932f6f2f5d5420292cbdbfe7ed2a8c4b70 100644
--- a/src/Mods/SecExp/SecExpBackwardCompatibility.tw
+++ b/src/Mods/SecExp/SecExpBackwardCompatibility.tw
@@ -522,21 +522,12 @@
 <<if ndef $mercFreeManpower>>
 	<<set $mercFreeManpower = 0>>
 <</if>>
-<<if ndef mercEmployedManpower>>
+<<if ndef $mercEmployedManpower>>
 	<<set $mercEmployedManpower = 0>>
 <</if>>
 <<if ndef $mercTotalCasualties>>
 	<<set $mercTotalCasualties = 0>>
 <</if>>
-<<if ndef $militiaLoyalty>>
-	<<set $militiaLoyalty = 0>>
-<</if>>
-<<if ndef $slaveArmyLoyalty>>
-	<<set $slaveArmyLoyalty = 0>>
-<</if>>
-<<if ndef $mercLoyalty>>
-	<<set $mercLoyalty = 0>>
-<</if>>
 <<if ndef $createdSlavesUnits>>
 	<<set $createdSlavesUnits = 0>>
 <</if>>
@@ -636,131 +627,6 @@
 	<<set $lastSelection = []>>
 <</if>>
 
-/* statistics */
-<<if ndef $equipMod>>
-	<<set $equipMod = 0.15>>
-<</if>>
-<<if ndef $secBotsBaseAttack>>
-	<<set $secBotsBaseAttack = 7 + $droneUpgrades.attack>>
-<</if>>
-<<if ndef $secBotsBaseDefense>>
-	<<set $secBotsBaseDefense = 3 + $droneUpgrades.defense>>
-<</if>>
-<<if ndef $secBotsMorale>>
-	<<set $secBotsMorale = 200>>
-<</if>>
-<<if ndef $secBotsBaseHp>>
-	<<set $secBotsBaseHp = 3 + $droneUpgrades.hp>>
-<</if>>
-<<if ndef $militiaBaseAttack>>
-	<<set $militiaBaseAttack = 7 + $humanUpgrade.attack>>
-<</if>>
-<<if ndef $militiaBaseDefense>>
-	<<set $militiaBaseDefense = 5 + $humanUpgrade.defense>>
-<</if>>
-<<if ndef $militiaBaseMorale>>
-	<<set $militiaBaseMorale = 140 + $humanUpgrade.morale>>
-<</if>>
-<<if ndef $militiaBaseHp>>
-	<<set $militiaBaseHp = 3 + $humanUpgrade.hp>>
-<</if>>
-<<if ndef $slaveBaseAttack>>
-	<<set $slaveBaseAttack = 8 + $humanUpgrade.attack>>
-<</if>>
-<<if ndef $slaveBaseDefense>>
-	<<set $slaveBaseDefense = 3 + $humanUpgrade.defense>>
-<</if>>
-<<if ndef $slaveBaseMorale>>
-	<<set $slaveBaseMorale = 110 + $humanUpgrade.morale>>
-<</if>>
-<<if ndef $slaveBaseHp>>
-	<<set $slaveBaseHp = 3 + $humanUpgrade.hp>>
-<</if>>
-<<if ndef $mercBaseAttack>>
-	<<set $mercBaseAttack = 8 + $humanUpgrade.attack>>
-<</if>>
-<<if ndef $mercBaseDefense>>
-	<<set $mercBaseDefense = 4 + $humanUpgrade.defense>>
-<</if>>
-<<if ndef $mercBaseMorale>>
-	<<set $mercBaseMorale = 125 + $humanUpgrade.morale>>
-<</if>>
-<<if ndef $mercBaseHp>>
-	<<set $mercBaseHp = 4 + $humanUpgrade.hp>>
-<</if>>
-<<if ndef $SFBaseAttack>>
-	<<set $SFBaseAttack = 8 + $humanUpgrade.attack>>
-<</if>>
-<<if ndef $SFBaseDefense>>
-	<<set $SFBaseDefense = 4 + $humanUpgrade.defense>>
-<</if>>
-<<if ndef $SFBaseMorale>>
-	<<set $SFBaseMorale = 140 + $humanUpgrade.morale>>
-<</if>>
-<<if ndef $SFBaseHp>>
-	<<set $SFBaseHp = 4 + $humanUpgrade.hp>>
-<</if>>
-
-<<if ndef $raBaseAttack>>
-	<<set $raBaseAttack = 7>>
-<</if>>
-<<if ndef $raBaseDefense>>
-	<<set $raBaseDefense = 2>>
-<</if>>
-<<if ndef $raBaseMorale>>
-	<<set $raBaseMorale = 100>>
-<</if>>
-<<if ndef $raBaseHp>>
-	<<set $raBaseHp = 2>>
-<</if>>
-<<if ndef $fcBaseAttack>>
-	<<set $fcBaseAttack = 6>>
-<</if>>
-<<if ndef $fcBaseDefense>>
-	<<set $fcBaseDefense = 4>>
-<</if>>
-<<if ndef $fcBaseMorale>>
-	<<set $fcBaseMorale = 130>>
-<</if>>
-<<if ndef $fcBaseHp>>
-	<<set $fcBaseHp = 3>>
-<</if>>
-<<if ndef $owBaseAttack>>
-	<<set $owBaseAttack = 8>>
-<</if>>
-<<if ndef $owBaseDefense>>
-	<<set $owBaseDefense = 4>>
-<</if>>
-<<if ndef $owBaseMorale>>
-	<<set $owBaseMorale = 110>>
-<</if>>
-<<if ndef $owBaseHp>>
-	<<set $owBaseHp = 2>>
-<</if>>
-<<if ndef $ffBaseAttack>>
-	<<set $ffBaseAttack = 9>>
-<</if>>
-<<if ndef $ffBaseDefense>>
-	<<set $ffBaseDefense = 2>>
-<</if>>
-<<if ndef $ffBaseMorale>>
-	<<set $ffBaseMorale = 160>>
-<</if>>
-<<if ndef $ffBaseHp>>
-	<<set $ffBaseHp = 2>>
-<</if>>
-
-/* units */
-<<if ndef $militiaUnits>>
-	<<set $militiaUnits = []>>
-<</if>>
-<<if ndef $slaveUnits>>
-	<<set $slaveUnits = []>>
-<</if>>
-<<if ndef $mercUnits>>
-	<<set $mercUnits = []>>
-<</if>>
-
 /* SFanon additions */
 <<if ndef $SFSupportLevel>>
 	<<set $SFSupportLevel = 0>>
@@ -782,7 +648,6 @@
 <<fixBrokenUnits>>
 <<fixBrokenStats>>
 <<recalcManpower>>
-<<recalcBaseStats>>
 <<set $wasToggledBefore = 1>>
 
 <br>Missing Security Expansion variables set. All done!
diff --git a/src/Mods/SecExp/attackHandler.tw b/src/Mods/SecExp/attackHandler.tw
index eb5e27eb3f826d4b4552af02d31913f562673535..10c846cb6b6d27b611d65ca7a78766ff5e444a4e 100644
--- a/src/Mods/SecExp/attackHandler.tw
+++ b/src/Mods/SecExp/attackHandler.tw
@@ -872,79 +872,33 @@
 
 	/* calculates PC army stats */
 	<<if App.SecExp.conflict.deployedUnits('bots')>>
-		<<set _attack += ($secBotsBaseAttack + $secBotsBaseAttack * $secBots.equip * $equipMod) * _atkMod>>
-		<<set _defense += ($secBotsBaseDefense + $secBotsBaseDefense * $secBots.equip * $equipMod) * _defMod>>
-		<<set _hp += $secBotsBaseHp * $secBots.troops>>
+		<<set _unit = App.SecExp.getUnit("Bots")>>
+		<<set _attack += _unit.attack * _atkMod>>
+		<<set _defense += _unit.defense * _defMod>>
+		<<set _hp += _unit.hp>>
 	<</if>>
 	<<for _i = 0; _i < $militiaUnits.length; _i++>>
 		<<if $militiaUnits[_i].isDeployed == 1>>
-			<<if $militiaUnits[_i].training <= 10>>
-				<<set _expBonus = 0>>
-			<<elseif $militiaUnits[_i].training <= 33>>
-				<<set _expBonus = 0.10>>
-			<<elseif $militiaUnits[_i].training <= 66>>
-				<<set _expBonus = 0.25>>
-			<<else>>
-				<<set _expBonus = 0.50>>
-			<</if>>
-			<<if $militiaUnits[_i].loyalty <= 10>>
-				<<set _loyaltyBonus = 0>>
-			<<elseif $militiaUnits[_i].loyalty <= 33>>
-				<<set _loyaltyBonus = 0.10>>
-			<<elseif $militiaUnits[_i].loyalty <= 66>>
-				<<set _loyaltyBonus = 0.20>>
-			<<else>>
-				<<set _loyaltyBonus = 0.30>>
-			<</if>>
-			<<set _attack += ($militiaBaseAttack + $militiaBaseAttack * $militiaUnits[_i].equip * $equipMod + $militiaBaseAttack * _expBonus + $militiaBaseAttack * _loyaltyBonus + $militiaBaseAttack * $militiaUnits[_i].SF * 0.20 + $militiaUnits[_i].cyber) * _atkMod>>
-			<<set _defense += ($militiaBaseDefense + $militiaBaseDefense * $militiaUnits[_i].equip * $equipMod + $militiaBaseDefense * _expBonus + $militiaBaseDefense * _loyaltyBonus + $militiaBaseDefense * $militiaUnits[_i].SF * 0.20 + $militiaUnits[_i].cyber) * _defMod>>
-			<<set _hp += ($militiaBaseHp + $militiaUnits[_i].cyber + $militiaBaseHp * $militiaUnits[_i].medics * 0.25) * $militiaUnits[_i].troops>>
+			<<set _unit = App.SecExp.getUnit("Militia", _i)>>
+			<<set _attack += _unit.attack * _atkMod>>
+			<<set _defense += _unit.defense * _defMod>>
+			<<set _hp += _unit.hp>>
 		<</if>>
 	<</for>>
 	<<for _i = 0; _i < $slaveUnits.length; _i++>>
 		<<if $slaveUnits[_i].isDeployed == 1>>
-			<<if $slaveUnits[_i].training <= 33>>
-				<<set _expBonus = 0>>
-			<<elseif $slaveUnits[_i].training <= 66>>
-				<<set _expBonus = 0.25>>
-			<<else>>
-				<<set _expBonus = 0.50>>
-			<</if>>
-			<<if $slaveUnits[_i].loyalty <= 10>>
-				<<set _loyaltyBonus = 0>>
-			<<elseif $slaveUnits[_i].loyalty <= 33>>
-				<<set _loyaltyBonus = 0.10>>
-			<<elseif $slaveUnits[_i].loyalty <= 66>>
-				<<set _loyaltyBonus = 0.20>>
-			<<else>>
-				<<set _loyaltyBonus = 0.30>>
-			<</if>>
-			<<set _attack += ($slaveBaseAttack + $slaveBaseAttack * $slaveUnits[_i].equip * $equipMod + $slaveBaseAttack * _expBonus + $slaveBaseAttack * _loyaltyBonus + $slaveBaseAttack * $slaveUnits[_i].SF * 0.20 + $slaveUnits[_i].cyber) * _atkMod>>
-			<<set _defense += ($slaveBaseDefense + $slaveBaseDefense * $slaveUnits[_i].equip * $equipMod + $slaveBaseDefense * _expBonus + $slaveBaseDefense * _loyaltyBonus + $slaveBaseDefense * $slaveUnits[_i].SF * 0.20 + $slaveUnits[_i].cyber) * _defMod>>
-			<<set _hp += ($slaveBaseHp + $slaveUnits[_i].cyber + $slaveBaseHp * $slaveUnits[_i].medics * 0.25) * $slaveUnits[_i].troops>>
+			<<set _unit = App.SecExp.getUnit("Slaves", _i)>>
+			<<set _attack += _unit.attack * _atkMod>>
+			<<set _defense += _unit.defense * _defMod>>
+			<<set _hp += _unit.hp>>
 		<</if>>
 	<</for>>
 	<<for _i = 0; _i < $mercUnits.length; _i++>>
 		<<if $mercUnits[_i].isDeployed == 1>>
-			<<if $mercUnits[_i].training <= 33>>
-				<<set _expBonus = 0>>
-			<<elseif $mercUnits[_i].training <= 66>>
-				<<set _expBonus = 0.25>>
-			<<else>>
-				<<set _expBonus = 0.50>>
-			<</if>>
-			<<if $mercUnits[_i].loyalty <= 10>>
-				<<set _loyaltyBonus = 0>>
-			<<elseif $mercUnits[_i].loyalty <= 33>>
-				<<set _loyaltyBonus = 0.10>>
-			<<elseif $mercUnits[_i].loyalty <= 66>>
-				<<set _loyaltyBonus = 0.20>>
-			<<else>>
-				<<set _loyaltyBonus = 0.30>>
-			<</if>>
-			<<set _attack += ($mercBaseAttack + $mercBaseAttack * $mercUnits[_i].equip * $equipMod + $mercBaseAttack * _expBonus + $mercBaseAttack * _loyaltyBonus + $mercBaseAttack * $mercUnits[_i].SF * 0.20 + $mercUnits[_i].cyber) * _atkMod>>
-			<<set _defense += ($mercBaseDefense + $mercBaseDefense * $mercUnits[_i].equip * $equipMod + $mercBaseDefense * _expBonus + $mercBaseDefense * _loyaltyBonus + $mercBaseDefense * $mercUnits[_i].SF * 0.20 + $mercUnits[_i].cyber) * _defMod>>
-			<<set _hp += ($mercBaseHp + $mercUnits[_i].cyber + $mercBaseHp * $mercUnits[_i].medics * 0.25) * $mercUnits[_i].troops>>
+			<<set _unit = App.SecExp.getUnit("Mercs", _i)>>
+			<<set _attack += _unit.attack * _atkMod>>
+			<<set _defense += _unit.defense * _defMod>>
+			<<set _hp += _unit.hp>>
 		<</if>>
 	<</for>>
 
@@ -983,10 +937,10 @@
 
 	<<set _moraleTroopMod = Math.clamp(App.SecExp.conflict.troopCount() / 100,1,5)>>
 
-	<<set _morale = ($secBotsMorale * $secBots.isDeployed + $militiaBaseMorale * _militiaMod * App.SecExp.conflict.deployedUnits('militia') + $slaveBaseMorale * _slaveMod * App.SecExp.conflict.deployedUnits('slaves') + $mercBaseMorale * _mercMod * App.SecExp.conflict.deployedUnits('mercs') + $SFBaseMorale * $SFIntervention * _SFMod) / ($secBots.isDeployed + App.SecExp.conflict.deployedUnits('militia') +App.SecExp.conflict.deployedUnits('slaves') + App.SecExp.conflict.deployedUnits('mercs') + $SFIntervention)>>
+	<<set _morale = (App.SecExp.BaseDroneUnit.morale * $secBots.isDeployed + App.SecExp.BaseMilitiaUnit.morale * _militiaMod * App.SecExp.conflict.deployedUnits('militia') + App.SecExp.BaseSlaveUnit.morale * _slaveMod * App.SecExp.conflict.deployedUnits('slaves') + App.SecExp.BaseMercUnit.morale * _mercMod * App.SecExp.conflict.deployedUnits('mercs') + App.SecExp.BaseSpecialForcesUnit.morale * $SFIntervention * _SFMod) / ($secBots.isDeployed + App.SecExp.conflict.deployedUnits('militia') + App.SecExp.conflict.deployedUnits('slaves') + App.SecExp.conflict.deployedUnits('mercs') + $SFIntervention)>>
 	<<set _morale = _morale + _morale * $SecExp.buildings.barracks.upgrades.luxury * 0.05>>	/* barracks bonus */
 	<<set _morale *= _moraleTroopMod>>
-	<<set _baseHp = ($secBotsBaseHp * $secBots.isDeployed + $militiaBaseHp * App.SecExp.conflict.deployedUnits('militia') + $slaveBaseHp * App.SecExp.conflict.deployedUnits('slaves') + $mercBaseHp * App.SecExp.conflict.deployedUnits('mercs') + $SFBaseHp * $SFIntervention) / ($secBots.isDeployed + App.SecExp.conflict.deployedUnits('militia') +App.SecExp.conflict.deployedUnits('slaves') + App.SecExp.conflict.deployedUnits('mercs') + $SFIntervention)>>
+	<<set _baseHp = (App.SecExp.BaseDroneUnit.hp * $secBots.isDeployed + App.SecExp.BaseMilitiaUnit.hp * App.SecExp.conflict.deployedUnits('militia') + App.SecExp.BaseSlaveUnit.hp * App.SecExp.conflict.deployedUnits('slaves') + App.SecExp.BaseMercUnit.hp * App.SecExp.conflict.deployedUnits('mercs') + App.SecExp.BaseSpecialForcesUnit.hp * $SFIntervention) / ($secBots.isDeployed + App.SecExp.conflict.deployedUnits('militia') + App.SecExp.conflict.deployedUnits('slaves') + App.SecExp.conflict.deployedUnits('mercs') + $SFIntervention)>>
 
 	/* calculates enemy army stats */
 	<<if $week <= 30>>
@@ -1010,31 +964,12 @@
 
 	<<set _enemyMoraleTroopMod = Math.clamp($attackTroops / 100,1,5)>>
 
-	<<if $attackType == "raiders">>
-		<<set _enemyAttack = ($raBaseAttack + $weapManu * $sellTo.raiders + $raBaseAttack * $attackEquip * $equipMod) * _armyMod>>
-		<<set _enemyDefense = ($raBaseDefense + $weapManu * $sellTo.raiders + $raBaseDefense * $attackEquip * $equipMod) * _armyMod>>
-		<<set _enemyMorale = $raBaseMorale * _enemyMod * _enemyMoraleTroopMod>>
-		<<set _enemyHp = $raBaseHp * $attackTroops>>
-		<<set _enemyBaseHp = $raBaseHp>>
-	<<elseif $attackType == "free city">>
-		<<set _enemyAttack = ($fcBaseAttack + $weapManu * $sellTo.FC + $fcBaseAttack * $attackEquip * $equipMod) * _armyMod>>
-		<<set _enemyDefense = ($fcBaseDefense + $weapManu * $sellTo.FC + $fcBaseDefense * $attackEquip * $equipMod) * _armyMod>>
-		<<set _enemyMorale = $fcBaseMorale * _enemyMod * _enemyMoraleTroopMod>>
-		<<set _enemyHp = $fcBaseHp * $attackTroops>>
-		<<set _enemyBaseHp = $fcBaseHp>>
-	<<elseif $attackType == "old world">>
-		<<set _enemyAttack = ($owBaseAttack + $weapManu * $sellTo.oldWorld + $owBaseAttack * $attackEquip * $equipMod) * _armyMod>>
-		<<set _enemyDefense = ($owBaseDefense + $weapManu * $sellTo.oldWorld + $owBaseDefense * $attackEquip * $equipMod) * _armyMod>>
-		<<set _enemyMorale = $owBaseMorale * _enemyMod * _enemyMoraleTroopMod>>
-		<<set _enemyHp = $owBaseHp * $attackTroops>>
-		<<set _enemyBaseHp = $owBaseHp>>
-	<<elseif $attackType == "freedom fighters">>
-		<<set _enemyAttack = ($ffBaseAttack + $weapManu * $sellTo.oldWorld + $ffBaseAttack * $attackEquip * $equipMod) * _armyMod>>
-		<<set _enemyDefense = ($ffBaseDefense + $weapManu * $sellTo.oldWorld + $ffBaseDefense * $attackEquip * $equipMod) * _armyMod>>
-		<<set _enemyMorale = $ffBaseMorale * _enemyMod * _enemyMoraleTroopMod>>
-		<<set _enemyHp = $ffBaseHp * $attackTroops>>
-		<<set _enemyBaseHp = $ffBaseHp>>
-	<</if>>
+	<<set _unit = App.SecExp.getEnemyUnit($attackType, $attackTroops, $attackEquip)>>
+	<<set _enemyAttack = _unit.attack * _armyMod>>
+	<<set _enemyDefense = _unit.defense * _armyMod>>
+	<<set _enemyMorale = _unit.morale * _enemyMod * _enemyMoraleTroopMod>>
+	<<set _enemyHp = _unit.hp>>
+	<<set _enemyBaseHp = _unit.hp / $attackTroops>>
 
 	/* difficulty */
 	<<set _enemyAttack *= $SecExp.settings.difficulty>>
diff --git a/src/Mods/SecExp/attackOptions.tw b/src/Mods/SecExp/attackOptions.tw
index 401a3959167904f5a4c92175a1f7357c5bfc792c..efee7d2cc43bd24fdf76f85be29c55b372aa2669 100644
--- a/src/Mods/SecExp/attackOptions.tw
+++ b/src/Mods/SecExp/attackOptions.tw
@@ -279,7 +279,7 @@ __Battle Plan__:
 
 <<if App.SecExp.battle.deployableUnits() > 0>> <br>
 	<<if $secBots.active == 1 && $secBots.isDeployed == 0 && $secBots.troops > 0>>
-		<br> <<= App.SecExp.unit.dec($secBots, "Bots")>> <br>
+		<br> <<= App.SecExp.getUnit("Bots").describe()>> <br>
 		<<link "Deploy the unit" "attackOptions">>
 			<<set $secBots.isDeployed = 1, $saveValid = 0>>
 		<</link>>
@@ -301,7 +301,7 @@ __Battle Plan__:
 			<<for _i = 0; _i < _mL; _i++>>
 				<<capture _i>>
 				<<if $militiaUnits[_i].active == 1 && $militiaUnits[_i].isDeployed == 0 && $militiaUnits[_i].troops > 0>>
-					<<= App.SecExp.unit.dec($militiaUnits[_i], "Militia")>>
+					<<= App.SecExp.getUnit("Militia", _i).describe()>>
 					<br>
 					<<link "Deploy the unit" "attackOptions">>
 						<<set $militiaUnits[_i].isDeployed = 1, $saveValid = 0>>
@@ -318,7 +318,7 @@ __Battle Plan__:
 			<<for _i = 0; _i < _sL; _i++>>
 			<<capture _i>>
 			<<if $slaveUnits[_i].active == 1 && $slaveUnits[_i].isDeployed == 0 && $slaveUnits[_i].troops > 0>>
-				<<= App.SecExp.unit.dec($slaveUnits[_i], "Slaves")>>
+				<<= App.SecExp.getUnit("Slaves", _i).describe()>>
 				<br>
 				<<link "Deploy the unit" "attackOptions">>
 					<<set $slaveUnits[_i].isDeployed = 1, $saveValid = 0>>
@@ -335,7 +335,7 @@ __Battle Plan__:
 			<<for _i = 0; _i < _meL; _i++>>
 			<<capture _i>>
 			<<if $mercUnits[_i].active == 1 && $mercUnits[_i].isDeployed == 0 && $mercUnits[_i].troops > 0>>
-				<<= App.SecExp.unit.dec($mercUnits[_i], "Mercs")>>
+				<<= App.SecExp.getUnit("Mercs", _i).describe()>>
 				<br>
 				<<link "Deploy the unit" "attackOptions">>
 					<<set $mercUnits[_i].isDeployed = 1, $saveValid = 0>>
@@ -352,7 +352,7 @@ __Battle Plan__:
 
 <<if App.SecExp.conflict.deployedUnits() > 0>> <br>
 		<<if App.SecExp.conflict.deployedUnits('bots')>>
-			<<= App.SecExp.unit.dec($secBots, "Bots")>>
+			<<= App.SecExp.getUnit("Bots").describe()>>
 			<br>
 			<<link "Remove the unit" "attackOptions">>
 				<<set $secBots.isDeployed = 0, $saveValid = 0>>
@@ -362,7 +362,7 @@ __Battle Plan__:
 	<<for _i = 0; _i < _mL; _i++>>
 		<<capture _i>>
 		<<if $militiaUnits[_i].isDeployed == 1>>
-			<<= App.SecExp.unit.dec($militiaUnits[_i], "Militia")>>
+			<<= App.SecExp.getUnit("Militia", _i).describe()>>
 			<br>
 			<<link "Remove the unit" "attackOptions">>
 				<<set $militiaUnits[_i].isDeployed = 0, $saveValid = 0>>
@@ -374,7 +374,7 @@ __Battle Plan__:
 	<<for _i = 0; _i < _sL; _i++>>
 		<<capture _i>>
 		<<if $slaveUnits[_i].isDeployed == 1>>
-			<<= App.SecExp.unit.dec($slaveUnits[_i], "Slaves")>>
+			<<= App.SecExp.getUnit("Slaves", _i).describe()>>
 			<br>
 			<<link "Remove the unit" "attackOptions">>
 				<<set $slaveUnits[_i].isDeployed = 0, $saveValid = 0>>
@@ -386,7 +386,7 @@ __Battle Plan__:
 	<<for _i = 0; _i < _meL; _i++>>
 		<<capture _i>>
 		<<if $mercUnits[_i].isDeployed == 1>>
-			<<= App.SecExp.unit.dec($mercUnits[_i], "Mercs")>>
+			<<= App.SecExp.getUnit("Mercs", _i).describe()>>
 			<br>
 			<<link "Remove the unit" "attackOptions">>
 				<<set $mercUnits[_i].isDeployed = 0, $saveValid = 0>>
diff --git a/src/Mods/SecExp/attackReport.tw b/src/Mods/SecExp/attackReport.tw
index 49c82488922e7279d9185456ee2ce6f4c1b10ae7..af5af2564a51488ed24bec6bc1949665d83eeb0d 100644
--- a/src/Mods/SecExp/attackReport.tw
+++ b/src/Mods/SecExp/attackReport.tw
@@ -794,8 +794,9 @@
 			<</if>>
 		<</if>>
 		<<if App.SecExp.conflict.deployedUnits('mercs') >= 1>>
-			<<if $mercLoyalty <= 25>>
-				<<if $mercLoyalty <= 10>>
+			<<set _mercLoyalty = App.SecExp.mercenaryAvgLoyalty()>>
+			<<if _mercLoyalty <= 25>>
+				<<if _mercLoyalty <= 10>>
 					Your mercenaries barely bother to pretend being loyal; their battle performance is obviously barely passable.
 				<<else>>
 					Your presence does little to spur your mercenaries into action; their loyalty is straining and their performance suffers.
@@ -809,8 +810,8 @@
 				<<elseif $PC.career == "BlackHat">>
 					They do little to hide their disgust at being ordered around by some unscrupulous code monkey.
 				<</if>>
-			<<elseif $mercLoyalty >= 50>>
-				<<if $mercLoyalty < 75>>
+			<<elseif _mercLoyalty >= 50>>
+				<<if _mercLoyalty < 75>>
 					Your mercenaries are ready to fight their hardest for you, their loyalty a testament to your capability as a leader.
 				<<else>>
 					Your mercenaries fight with a martial fury worthy of religious fanatics. Their loyalty to you is absolute.
diff --git a/src/Mods/SecExp/buildings/secBarracks.tw b/src/Mods/SecExp/buildings/secBarracks.tw
index 3b3826a3fb2b64dbc0a0f110e02202e7f7ac8272..0f7f271b6b3eca2137e435bba36837d353b11164 100644
--- a/src/Mods/SecExp/buildings/secBarracks.tw
+++ b/src/Mods/SecExp/buildings/secBarracks.tw
@@ -140,7 +140,7 @@ Your current maximum number of units is <<print App.SecExp.battle.maxUnits()>> (
 <br>
 
 <<if $arcologyUpgrade.drones == 1>>
-	<<= App.SecExp.unit.dec($secBots, "Bots")>>
+	<<= App.SecExp.getUnit("Bots").describe()>>
 	<br>
 	<<if $secBots.active == 1>>
 		<<link "Review Equipment and upgrades" "seeUnit">>
@@ -215,7 +215,7 @@ You are free to organize your menial slaves into fighting units. Currently you h
 <</if>>
 <<for _i = 0; _i < _sL; _i++>>
 	<<capture _i>>
-	<<= App.SecExp.unit.dec($slaveUnits[_i], "Slaves")>>
+	<<= App.SecExp.getUnit("Slaves", _i).describe()>>
 	<<if $slaveUnits[_i].active == 1>>
 		<br>
 		<<link "Disband the unit" "secBarracks">>
@@ -324,7 +324,7 @@ __Militia__
 	<</if>>
 	<<for _i = 0; _i < _mL; _i++>>
 		<<capture _i>>
-		<<= App.SecExp.unit.dec($militiaUnits[_i], "Militia")>>
+		<<= App.SecExp.getUnit("Militia", _i).describe()>>
 		<<if $militiaUnits[_i].active == 1>>
 			<br>
 			<<link "Disband the unit" "secBarracks">>
@@ -430,7 +430,7 @@ __Mercenaries__
 	<</if>>
 	<<for _i = 0; _i < _meL; _i++>>
 		<<capture _i>>
-		<<= App.SecExp.unit.dec($mercUnits[_i], "Mercs")>>
+		<<= App.SecExp.getUnit("Mercs", _i).describe()>>
 		<<if $mercUnits[_i].active == 1>>
 			<br>
 			<<link "Disband the unit" "secBarracks">>
diff --git a/src/Mods/SecExp/edicts.tw b/src/Mods/SecExp/edicts.tw
index 47b162f4983027b03ed70bd1b6e02cd1d9d36161..90b55e3985ccceb09f7bd0870ac54ae400c9088e 100644
--- a/src/Mods/SecExp/edicts.tw
+++ b/src/Mods/SecExp/edicts.tw
@@ -170,12 +170,12 @@
 
 	<<if $martialSchool == 1>>
 		<br>''@@.lime;Slave martial schools:@@'' specialized schools are training slaves in martial arts and bodyguarding.
-		[[Repeal|edicts][$martialSchool = 0, $slaveBaseMorale -= 5]]
+		[[Repeal|edicts][$martialSchool = 0]]
 	<</if>>
 
 	<<if $eliteOfficers == 1>>
 		<br>''@@.lime;Elite officers:@@'' officers are exclusively recruited from the elite of society.
-		[[Repeal|edicts][$eliteOfficers = 0, $militiaBaseMorale += 5, $slaveBaseMorale -= 5]]
+		[[Repeal|edicts][$eliteOfficers = 0]]
 	<</if>>
 
 	<<if $liveTargets == 1>>
@@ -187,32 +187,32 @@
 <<if $FSAnnounced>>
 	<<if $legionTradition == 1>>
 		<br>''@@.lime;Legionaries traditions:@@'' you are funding specialized training for your recruits following the Roman tradition of professional armies.
-		[[Repeal|edicts][$legionTradition = 0, $militiaBaseDefense -= 2, $militiaBaseMorale -= 5, $militiaBaseHp--]]
+		[[Repeal|edicts][$legionTradition = 0]]
 	<</if>>
 
 	<<if $pharaonTradition == 1>>
 		<br>''@@.lime;Pharaonic traditions:@@'' you are funding specialized training for your recruits to turn them into an army worthy of a pharaon.
-		[[Repeal|edicts][$pharaonTradition = 0, $militiaBaseAttack -= 2, $militiaBaseDefense -= 2, $militiaBaseMorale -= 10]]
+		[[Repeal|edicts][$pharaonTradition = 0]]
 	<</if>>
 
 	<<if $eagleWarriors == 1>>
 		<br>''@@.lime;Eagle warriors traditions:@@'' you are funding specialized training for your mercenaries following the Aztec tradition of elite warriors.
-		[[Repeal|edicts][$eagleWarriors = 0, $mercBaseAttack -= 4, $mercBaseDefense += 2, $mercBaseMorale -= 10]]
+		[[Repeal|edicts][$eagleWarriors = 0]]
 	<</if>>
 
 	<<if $ronin == 1>>
 		<br>''@@.lime;Ronin traditions:@@'' you are funding specialized training for your mercenaries following the Japanese tradition of elite errant samurai.
-		[[Repeal|edicts][$ronin = 0, $mercBaseAttack -= 2, $mercBaseDefense -= 2, $mercBaseMorale -= 10]]
+		[[Repeal|edicts][$ronin = 0]]
 	<</if>>
 
 	<<if $mamluks == 1>>
 		<br>''@@.lime;Mamluks traditions:@@'' you are funding specialized training for your slaves following the Arabian tradition of mamluks slave soldiers.
-		[[Repeal|edicts][$mamluks = 0, $slaveBaseAttack -= 2, $slaveBaseHp--, $slaveBaseMorale -= 10]]
+		[[Repeal|edicts][$mamluks = 0]]
 	<</if>>
 
 	<<if $sunTzu == 1>>
 		<br>''@@.lime;Sun Tzu Teachings:@@'' you are funding specialized training for your units and officers to follow the teachings of the "Art of War".
-		[[Repeal|edicts][$sunTzu = 0, $militiaBaseAttack--, $militiaBaseDefense--, $mercBaseAttack--, $mercBaseDefense--, $slaveBaseAttack--, $slaveBaseDefense--, $militiaBaseMorale -= 5, $mercBaseMorale -= 5, $slaveBaseMorale -= 5]]
+		[[Repeal|edicts][$sunTzu = 0]]
 	<</if>>
 <</if>>
 
@@ -547,7 +547,7 @@
 			<<if $lowerRquirements == 0>>
 				<br>''@@.lime;Revised minimum requirements:@@'' will allow citizens outside the normally accepted range to join the militia.
 				<<if $SecExp.core.authority >= 1000>>
-					[[Implement|edicts][$lowerRquirements = 1, cashX(-5000, "edicts"), $SecExp.core.authority -= 1000, $militiaBaseDefense--, $militiaBaseHp--]]
+					[[Implement|edicts][$lowerRquirements = 1, cashX(-5000, "edicts"), $SecExp.core.authority -= 1000]]
 				<<else>>
 					<br>//Not enough Authority.//
 				<</if>>
@@ -614,7 +614,7 @@
 		<<if $martialSchool == 0>>
 			<br>''@@.lime;Slave martial schools:@@'' specialized schools will be set up to train slaves in martial arts and bodyguarding.
 			<<if $SecExp.core.authority >= 1000>>
-				[[Implement|edicts][$martialSchool = 1, cashX(-5000, "edicts"), $SecExp.core.authority -= 1000, $slaveBaseMorale += 5]]
+				[[Implement|edicts][$martialSchool = 1, cashX(-5000, "edicts"), $SecExp.core.authority -= 1000]]
 			<<else>>
 				<br>//Not enough Authority.//
 			<</if>>
@@ -626,7 +626,7 @@
 		<<if $eliteOfficers == 0>>
 			<br>''@@.lime;Elite officers:@@'' officers will be exclusively recruited from the elite of society.
 			<<if $SecExp.core.authority >= 1000>>
-				[[Implement|edicts][$eliteOfficers = 1, cashX(-5000, "edicts"), $SecExp.core.authority -= 1000, $militiaBaseMorale += 5, $slaveBaseMorale -= 5]]
+				[[Implement|edicts][$eliteOfficers = 1, cashX(-5000, "edicts"), $SecExp.core.authority -= 1000]]
 			<<else>>
 				<br>//Not enough Authority.//
 			<</if>>
@@ -653,7 +653,7 @@
 		<<if $legionTradition == 0>>
 			<br>''@@.lime;Legionaries traditions:@@'' Fund specialized training for your recruits to turn them into the professional of Roman tradition.
 			<<if $SecExp.core.authority >= 1000>>
-				[[Implement|edicts][$legionTradition = 1, cashX(-5000, "edicts"), $SecExp.core.authority -= 1000, $militiaBaseDefense += 2, $militiaBaseMorale += 5, $militiaBaseHp++]]
+				[[Implement|edicts][$legionTradition = 1, cashX(-5000, "edicts"), $SecExp.core.authority -= 1000]]
 			<<else>>
 				<br>//Not enough Authority.//
 			<</if>>
@@ -665,7 +665,7 @@
 		<<if $pharaonTradition == 0>>
 			<br>''@@.lime;Pharaonic traditions:@@'' Fund specialized training for your recruits to turn them into an army worthy of a pharaoh.
 			<<if $SecExp.core.authority >= 1000>>
-				[[Implement|edicts][$pharaonTradition = 1, cashX(-5000, "edicts"), $SecExp.core.authority -= 1000, $militiaBaseAttack += 2, $militiaBaseDefense += 2, $militiaBaseMorale += 10]]
+				[[Implement|edicts][$pharaonTradition = 1, cashX(-5000, "edicts"), $SecExp.core.authority -= 1000]]
 			<<else>>
 				<br>//Not enough Authority.//
 			<</if>>
@@ -677,7 +677,7 @@
 		<<if $eagleWarriors == 0>>
 			<br>''@@.lime;Eagle warriors traditions:@@'' Fund specialized training for your mercenaries to turn them into the elite units of Aztec tradition.
 			<<if $SecExp.core.authority >= 1000>>
-				[[Implement|edicts][$eagleWarriors = 1, cashX(-5000, "edicts"), $SecExp.core.authority -= 1000, $mercBaseAttack += 4, $mercBaseDefense -= 2, $mercBaseMorale += 10]]
+				[[Implement|edicts][$eagleWarriors = 1, cashX(-5000, "edicts"), $SecExp.core.authority -= 1000]]
 			<<else>>
 				<br>//Not enough Authority.//
 			<</if>>
@@ -689,7 +689,7 @@
 		<<if $ronin == 0>>
 			<br>''@@.lime;Ronin traditions:@@'' Fund specialized training for your mercenaries to turn them into the errant samurai of Japanese tradition.
 			<<if $SecExp.core.authority >= 1000>>
-				[[Implement|edicts][$ronin = 1, cashX(-5000, "edicts"), $SecExp.core.authority -= 1000, $mercBaseAttack += 2, $mercBaseDefense += 2, $mercBaseMorale += 10]]
+				[[Implement|edicts][$ronin = 1, cashX(-5000, "edicts"), $SecExp.core.authority -= 1000]]
 			<<else>>
 				<br>//Not enough Authority.//
 			<</if>>
@@ -701,7 +701,7 @@
 		<<if $mamluks == 0>>
 			<br>''@@.lime;Mamluks traditions:@@'' Fund specialized training for your slaves to turn them into the mamluks slave soldiers of Arabian tradition.
 			<<if $SecExp.core.authority >= 1000>>
-				[[Implement|edicts][$mamluks = 1, cashX(-5000, "edicts"), $SecExp.core.authority -= 1000, $slaveBaseAttack += 2, $slaveBaseHp++, $slaveBaseMorale += 10]]
+				[[Implement|edicts][$mamluks = 1, cashX(-5000, "edicts"), $SecExp.core.authority -= 1000]]
 			<<else>>
 				<br>//Not enough Authority.//
 			<</if>>
@@ -713,7 +713,7 @@
 		<<if $sunTzu == 0>>
 			<br>''@@.lime;Sun Tzu Teachings:@@'' Fund specialized training for your units and officers to conform your army to the teachings of the "Art of War".
 			<<if $SecExp.core.authority >= 1000>>
-				[[Implement|edicts][$sunTzu = 1, cashX(-5000, "edicts"), $SecExp.core.authority -= 1000, $militiaBaseAttack++, $militiaBaseDefense++, $mercBaseAttack++, $mercBaseDefense++, $slaveBaseAttack++, $slaveBaseDefense++, $militiaBaseMorale += 5, $mercBaseMorale += 5, $slaveBaseMorale += 5]]
+				[[Implement|edicts][$sunTzu = 1, cashX(-5000, "edicts"), $SecExp.core.authority -= 1000]]
 			<<else>>
 				<br>//Not enough Authority.//
 			<</if>>
diff --git a/src/Mods/SecExp/js/Unit.js b/src/Mods/SecExp/js/Unit.js
new file mode 100644
index 0000000000000000000000000000000000000000..d789999c0f3a67b8d1b4a2572f0a84c728f2db30
--- /dev/null
+++ b/src/Mods/SecExp/js/Unit.js
@@ -0,0 +1,507 @@
+/** Player unit factory - get a unit based on its type and index
+ * @param {string} type - "Bots", "Militia", "Slaves", or "Mercs"
+ * @param {number} [index] - must be supplied if type is not "Bots"
+ * @returns {App.SecExp.Unit}
+ */
+App.SecExp.getUnit = function(type, index) {
+	if (type === "Bots") {
+		return new App.SecExp.DroneUnit(V.secBots, App.SecExp.BaseDroneUnit);
+	} else if (typeof index !== "number") {
+		throw `Bad index for unit type ${type}: ${index}`;
+	}
+
+	switch (type) {
+		case "Militia":
+			return new App.SecExp.HumanUnit(V.militiaUnits[index], App.SecExp.BaseMilitiaUnit, type);
+		case "Slaves":
+			return new App.SecExp.HumanUnit(V.slaveUnits[index], App.SecExp.BaseSlaveUnit, type);
+		case "Mercs":
+			return new App.SecExp.HumanUnit(V.mercUnits[index], App.SecExp.BaseMercUnit, type);
+		default:
+			throw `Unknown unit type: ${type}`;
+	}
+};
+
+/** Enemy unit factory - get a unit based on its type and basic data
+ * @param {string} type - "raiders", "free city", "old world", or "freedom fighters"
+ * @param {number} troops
+ * @param {number} equipment
+ * @returns {App.SecExp.Unit}
+ */
+App.SecExp.getEnemyUnit = function(type, troops, equipment) {
+	const baseUnitMap = new Map([
+		["raiders", App.SecExp.BaseRaiderUnit],
+		["free city", App.SecExp.BaseFreeCityUnit],
+		["old world", App.SecExp.BaseOldWorldUnit],
+		["freedom fighters", App.SecExp.BaseFreedomFighterUnit],
+	]);
+	const unitData = {
+		troops: troops,
+		maxTroops: troops,
+		equip: equipment
+	};
+	return new App.SecExp.EnemyUnit(unitData, baseUnitMap.get(type));
+};
+
+/** Irregular unit factory - get an irregular unit (without organization/upgrade bonuses) based on its type and basic data
+ * @param {string} type - "Militia", "Slaves", or "Mercs"
+ * @param {number} troops
+ * @param {number} equipment
+ * @returns {App.SecExp.Unit}
+ */
+App.SecExp.getIrregularUnit = function(type, troops, equipment) {
+	const baseUnitMap = new Map([
+		["Militia", App.SecExp.BaseMilitiaUnit],
+		["Slaves", App.SecExp.BaseSlaveUnit],
+		["Mercs", App.SecExp.BaseMercUnit],
+	]);
+	const unitData = {
+		troops: troops,
+		maxTroops: troops,
+		equip: equipment
+	};
+
+	return new App.SecExp.IrregularUnit(unitData, baseUnitMap.get(type));
+};
+
+/** Equipment multiplier (static balance variable) */
+App.SecExp.equipMod = 0.15;
+
+/** Turn a loyalty value into a corresponding bonus factor
+ * @param {number} value range: [0-100]
+ * @returns {number} bonus - range: [0.0-0.3], cap at input 67
+ */
+App.SecExp.loyaltyValueToBonusFactor = function(value) {
+	return Math.min(value * 3 / 670, 0.3);
+};
+
+/** Turn a training value into a corresponding bonus factor
+ * @param {number} value range: [0-100]
+ * @returns {number} bonus - range: [0.0-0.5], cap at input 67
+ */
+App.SecExp.trainingValueToBonusFactor = function(value) {
+	return Math.min(value * 3 / 400, 0.5);
+};
+
+App.SecExp.getEdictUpgradeVal = (function() {
+	/** @typedef {Map<string, {defense?: number, attack?: number, morale?: number, hp?: number}>} EdictMap */
+	/** @type {Map<string, EdictMap>} */
+	const data = new Map([
+		["Militia", new Map([
+			["legionTradition", {defense: 2, morale: 5, hp: 1}],
+			["pharaonTradition", {attack: 2, defense: 2, morale: 10}],
+			["sunTzu", {attack: 1, defense: 1, morale: 5}],
+			["eliteOfficers", {morale: 5}],
+			["lowerRequirements", {defense: -1, hp: -1}]
+		])],
+		["Slave", new Map([
+			["mamluks", {attack: 2, morale: 10, hp: 1}],
+			["sunTzu", {attack: 1, defense: 1, morale: 5}],
+			["eliteOfficers", {morale: -5}],
+			["martialSchool", {morale: 5}]
+		])],
+		["Merc", new Map([
+			["eagleWarriors", {attack: 4, defense: -2, morale: 10}],
+			["ronin", {attack: 2, defense: 2, morale: 10}],
+			["sunTzu", {attack: 1, defense: 1, morale: 5}],
+		])],
+		["Dummy", new Map([ ["", {} ] ])] // this bastard SOMEHOW makes Typescript happy...
+	]);
+
+	/** Get the total edict upgrade effect on a particular stat for a particular unit
+	 * @param {string} unitType
+	 * @param {string} stat
+	 * @returns {number}
+	 */
+	function getNetEffect(unitType, stat) {
+		let retval = 0;
+		const unitMap = data.get(unitType);
+		for (const [key, val] of unitMap) {
+			if (V[key] > 0 && val[stat]) {
+				retval += val[stat];
+			}
+		}
+		return retval;
+	}
+
+	return getNetEffect;
+})();
+
+/** @typedef {object} BaseUnit
+ * @property {number} attack
+ * @property {number} defense
+ * @property {number} morale
+ * @property {number} hp
+ */
+
+/** @implements {BaseUnit} */
+App.SecExp.BaseMilitiaUnit = class BaseMilitiaUnit {
+	static get attack() {
+		return 7 + V.humanUpgrade.attack + App.SecExp.getEdictUpgradeVal("Militia", "attack");
+	}
+
+	static get defense() {
+		return 5 + V.humanUpgrade.defense + App.SecExp.getEdictUpgradeVal("Militia", "defense");
+	}
+
+	static get morale() {
+		return 140 + V.humanUpgrade.morale + App.SecExp.getEdictUpgradeVal("Militia", "morale");
+	}
+
+	static get hp() {
+		return 3 + V.humanUpgrade.hp + App.SecExp.getEdictUpgradeVal("Militia", "hp");
+	}
+};
+
+
+/** @implements {BaseUnit} */
+App.SecExp.BaseSlaveUnit = class BaseSlaveUnit {
+	static get attack() {
+		return 8 + V.humanUpgrade.attack + App.SecExp.getEdictUpgradeVal("Slave", "attack");
+	}
+
+	static get defense() {
+		return 3 + V.humanUpgrade.defense + App.SecExp.getEdictUpgradeVal("Slave", "defense");
+	}
+
+	static get morale() {
+		return 110 + V.humanUpgrade.morale + App.SecExp.getEdictUpgradeVal("Slave", "morale");
+	}
+
+	static get hp() {
+		return 3 + V.humanUpgrade.hp + App.SecExp.getEdictUpgradeVal("Slave", "hp");
+	}
+};
+
+/** @implements {BaseUnit} */
+App.SecExp.BaseMercUnit = class BaseMercUnit {
+	static get attack() {
+		return 8 + V.humanUpgrade.attack + App.SecExp.getEdictUpgradeVal("Merc", "attack");
+	}
+
+	static get defense() {
+		return 4 + V.humanUpgrade.defense + App.SecExp.getEdictUpgradeVal("Merc", "defense");
+	}
+
+	static get morale() {
+		return 125 + V.humanUpgrade.morale + App.SecExp.getEdictUpgradeVal("Merc", "morale");
+	}
+
+	static get hp() {
+		return 4 + V.humanUpgrade.hp + App.SecExp.getEdictUpgradeVal("Merc", "hp");
+	}
+};
+
+/** @implements {BaseUnit} */
+App.SecExp.BaseDroneUnit = class BaseDroneUnit {
+	static get attack() {
+		return 7 + V.droneUpgrades.attack;
+	}
+
+	static get defense() {
+		return 3 + V.droneUpgrades.defense;
+	}
+
+	static get morale() {
+		return 200;
+	}
+
+	static get hp() {
+		return 3 + V.droneUpgrades.hp;
+	}
+};
+
+/** @implements {BaseUnit} */
+App.SecExp.BaseRaiderUnit = class BaseRaiderUnit {
+	static get attack() {
+		return 7;
+	}
+
+	static get defense() {
+		return 2;
+	}
+
+	static get morale() {
+		return 100;
+	}
+
+	static get hp() {
+		return 2;
+	}
+};
+
+/** @implements {BaseUnit} */
+App.SecExp.BaseFreeCityUnit = class BaseFreeCityUnit {
+	static get attack() {
+		return 6;
+	}
+
+	static get defense() {
+		return 4;
+	}
+
+	static get morale() {
+		return 130;
+	}
+
+	static get hp() {
+		return 3;
+	}
+};
+
+/** @implements {BaseUnit} */
+App.SecExp.BaseOldWorldUnit = class BaseOldWorldUnit {
+	static get attack() {
+		return 8;
+	}
+
+	static get defense() {
+		return 4;
+	}
+
+	static get morale() {
+		return 110;
+	}
+
+	static get hp() {
+		return 2;
+	}
+};
+
+/** @implements {BaseUnit} */
+App.SecExp.BaseFreedomFighterUnit = class BaseFreedomFighterUnit {
+	static get attack() {
+		return 9;
+	}
+
+	static get defense() {
+		return 2;
+	}
+
+	static get morale() {
+		return 160;
+	}
+
+	static get hp() {
+		return 2;
+	}
+};
+
+/** @implements {BaseUnit} */
+App.SecExp.BaseSpecialForcesUnit = class BaseSpecialForcesUnit {
+	static get attack() {
+		return 8 + V.humanUpgrade.attack;
+	}
+
+	static get defense() {
+		return 4 + V.humanUpgrade.defense;
+	}
+
+	static get morale() {
+		return 140 + V.humanUpgrade.morale;
+	}
+
+	static get hp() {
+		return 4 + V.humanUpgrade.hp;
+	}
+};
+
+/** Unit base class */
+App.SecExp.Unit = class SecExpUnit {
+	/** @param {FC.SecExp.UnitData} data
+	 * @param {BaseUnit} baseUnit
+	 */
+	constructor(data, baseUnit) {
+		this._data = data;
+		this._baseUnit = baseUnit;
+	}
+
+	/** @abstract
+	 * @returns {number} */
+	get attack() {
+		throw "derive me";
+	}
+
+	/** @abstract
+	 * @returns {number} */
+	get defense() {
+		throw "derive me";
+	}
+
+	/** @abstract
+	 * @returns {number} */
+	get morale() {
+		return this._baseUnit.morale; // no morale modifiers
+	}
+
+	/** @abstract
+	 * @returns {number} */
+	get hp() {
+		throw "derive me";
+	}
+
+	/** @abstract
+	 * @returns {string} */
+	describe() {
+		throw "derive me";
+	}
+
+	/** @abstract
+	 * @returns {string} */
+	printStats() {
+		throw "derive me";
+	}
+};
+
+App.SecExp.DroneUnit = class SecExpDroneUnit extends App.SecExp.Unit {
+	/** @param {FC.SecExp.PlayerUnitData} data
+	 * @param {BaseUnit} baseUnit
+	 */
+	constructor(data, baseUnit) {
+		super(data, baseUnit);
+		this._data = data; // duplicate assignment, just for TypeScript
+	}
+
+	get attack() {
+		const equipmentFactor = this._data.equip * App.SecExp.equipMod;
+		return this._baseUnit.attack * (1 + equipmentFactor);
+	}
+
+	get defense() {
+		const equipmentFactor = this._data.equip * App.SecExp.equipMod;
+		return this._baseUnit.defense * (1 + equipmentFactor);
+	}
+
+	get hp() {
+		return this._baseUnit.hp * this._data.troops;
+	}
+
+	describe() {
+		return App.SecExp.describeUnit(this._data, "Bots");
+	}
+
+	printStats() {
+		let r = [];
+		r.push(`<br>Security drones base attack: ${this._baseUnit.attack} (After modifiers: ${Math.trunc(this.attack)})`);
+		r.push(`<br>Security drones base defense: ${this._baseUnit.defense} (After modifiers: ${Math.trunc(this.defense)})`);
+		r.push(`<br>Equipment bonus: +${this._data.equip * 15}%`);
+		r.push(`<br>Security drones base hp: ${this._baseUnit.hp} (Total after modifiers for ${this._data.troops} drones: ${this.hp})`);
+		r.push(`<br>Security drones base morale: ${this._baseUnit.morale}`);
+		return r.join(` `);
+	}
+};
+
+App.SecExp.HumanUnit = class SecExpHumanUnit extends App.SecExp.Unit {
+	/** @param {FC.SecExp.PlayerHumanUnitData} data
+	 * @param {BaseUnit} baseUnit
+	 * @param {string} descriptionType
+	 */
+	constructor(data, baseUnit, descriptionType) {
+		super(data, baseUnit);
+		this._data = data; // duplicate assignment, just for TypeScript
+		this._descType = descriptionType;
+	}
+
+	get attack() {
+		const equipmentFactor = this._data.equip * App.SecExp.equipMod;
+		const experienceFactor = App.SecExp.trainingValueToBonusFactor(this._data.training);
+		const loyaltyFactor = App.SecExp.loyaltyValueToBonusFactor(this._data.loyalty);
+		const SFFactor = 0.20 * this._data.SF;
+		return this._baseUnit.attack * (1 + equipmentFactor + experienceFactor + loyaltyFactor + SFFactor) + this._data.cyber;
+	}
+
+	get defense() {
+		const equipmentFactor = this._data.equip * App.SecExp.equipMod;
+		const experienceFactor = App.SecExp.trainingValueToBonusFactor(this._data.training);
+		const loyaltyFactor = App.SecExp.loyaltyValueToBonusFactor(this._data.loyalty);
+		const SFFactor = 0.20 * this._data.SF;
+		return this._baseUnit.defense * (1 + equipmentFactor + experienceFactor + loyaltyFactor + SFFactor) + this._data.cyber;
+	}
+
+	get hp() {
+		const medicFactor = 0.25 * this._data.medics;
+		const singleTroopHp = this._baseUnit.hp * (1 + medicFactor) + this._data.cyber;
+		return singleTroopHp * this._data.troops;
+	}
+
+	describe() {
+		return App.SecExp.describeUnit(this._data, this._descType);
+	}
+
+	printStats() {
+		let r = [];
+		r.push(`<br>`);
+		r.push(`<br>${this._descType} base attack: ${this._baseUnit.attack} (After modifiers: ${Math.trunc(this.attack)})`);
+		r.push(`<br>${this._descType} base defense: ${this._baseUnit.defense} (After modifiers: ${Math.trunc(this.defense)})`);
+		if (this._data.equip > 0) {
+			r.push(`<br>Equipment bonus: +${this._data.equip * 15}%`);
+		}
+		if (this._data.cyber > 0) {
+			r.push(`<br>Cyber enhancements bonus: +1`);
+		}
+		if (this._data.training > 0) {
+			r.push(`<br>Experience bonus: +${Math.trunc(App.SecExp.trainingValueToBonusFactor(this._data.training)*100)}%`);
+		}
+		if (this._data.loyalty > 0) {
+			r.push(`<br>Loyalty bonus: +${Math.trunc(App.SecExp.loyaltyValueToBonusFactor(this._data.loyalty)*100)}%`);
+		}
+		if (this._data.SF > 0) {
+			r.push(`<br>Special Force advisors bonus: +20%`);
+		}
+		r.push(`<br>${this._descType} base morale: ${this._baseUnit.morale} (After modifiers: ${this.morale})`);
+		if (V.SecExp.buildings.barracks.upgrades.luxury > 0) {
+			r.push(`<br>Barracks bonus: +${V.SecExp.buildings.barracks.upgrades.luxury * 5}%`);
+		}
+		r.push(`<br>${this._descType} base hp: ${this._baseUnit.hp} (Total after modifiers for ${this._data.troops} troops: ${this.hp})`);
+		if (this._data.medics > 0) {
+			r.push(`<br>Medics detachment bonus: +25%`);
+		}
+		return r.join(` `);
+	}
+};
+
+App.SecExp.EnemyUnit = class SecExpEnemyUnit extends App.SecExp.Unit {
+	/** @param {FC.SecExp.UnitData} data
+	 * @param {BaseUnit} baseUnit
+	 */
+	constructor(data, baseUnit) {
+		super(data, baseUnit);
+	}
+
+	get attack() {
+		const equipmentFactor = this._data.equip * App.SecExp.equipMod;
+		return this._baseUnit.attack * (1 + equipmentFactor) + V.weapManu * V.sellTo.oldWorld;
+	}
+
+	get defense() {
+		const equipmentFactor = this._data.equip * App.SecExp.equipMod;
+		return this._baseUnit.defense * (1 + equipmentFactor) + V.weapManu * V.sellTo.oldWorld;
+	}
+
+	get hp() {
+		return this._baseUnit.hp * this._data.troops;
+	}
+};
+
+App.SecExp.IrregularUnit = class SecExpEnemyUnit extends App.SecExp.Unit {
+	/** @param {FC.SecExp.UnitData} data
+	 * @param {BaseUnit} baseUnit
+	 */
+	constructor(data, baseUnit) {
+		super(data, baseUnit);
+	}
+
+	get attack() {
+		const equipmentFactor = this._data.equip * App.SecExp.equipMod;
+		return (this._baseUnit.attack - V.humanUpgrade.attack) * (1 + equipmentFactor);
+	}
+
+	get defense() {
+		const equipmentFactor = this._data.equip * App.SecExp.equipMod;
+		return (this._baseUnit.defense - V.humanUpgrade.defense) * (1 + equipmentFactor);
+	}
+
+	get hp() {
+		return (this._baseUnit.hp - V.humanUpgrade.defense) * this._data.troops;
+	}
+};
diff --git a/src/Mods/SecExp/js/secExp.js b/src/Mods/SecExp/js/secExp.js
index f9990832ae055f19d27b654916bc40638efaddc8..ee79098ed9427377f942ed4f42d63c5641231f7b 100644
--- a/src/Mods/SecExp/js/secExp.js
+++ b/src/Mods/SecExp/js/secExp.js
@@ -137,8 +137,8 @@ App.SecExp.upkeep = (function() {
 App.SecExp.conflict = (function() {
 	"use strict";
 	return {
-		deployedUnits:deployedUnits,
-		troopCount:troopCount,
+		deployedUnits,
+		troopCount,
 	};
 
 	/** Get count of deployed/active units for a particular battle
@@ -147,82 +147,31 @@ App.SecExp.conflict = (function() {
 	 */
 	function deployedUnits(input = '') {
 		let bots = 0, militiaC = 0, slavesC = 0, mercsC = 0, init = 0;
-		if(V.slaveRebellion !== 1 && V.citizenRebellion !== 1) {
+		if (V.slaveRebellion !== 1 && V.citizenRebellion !== 1) { // attack
 			if(V.secBots.isDeployed > 0) {
 				bots++;
 			}
-			if(passage() !== "attackOptions") {
-				if (V.SF.Toggle && V.SF.Active >= 1 && V.SFIntervention) { // battle
-					init++;
-				}
-			}
-			if(V.slaveRebellion+V.citizenRebellion > 0) {
-				if (V.SF.Toggle && V.SF.Active >= 1) { // rebellion
-					init++;
-				}
-				if(V.irregulars > 0) {
-					militiaC++;
-				}
-			}
-
-			const Militia = V.militiaUnits.length;
-			for(let i = 0; i < Militia; i++) {
-				if(V.militiaUnits[i].isDeployed > 0) {
-					militiaC++;
-				}
-			}
-
-			const Slaves = V.slaveUnits.length;
-			for(let i = 0; i < Slaves; i++) {
-				if(V.slaveUnits[i].isDeployed > 0) {
-					slavesC++;
-				}
+			if (V.SF.Toggle && V.SF.Active >= 1 && V.SFIntervention) {
+				init++;
 			}
 
-			const Mercs = V.mercUnits.length;
-			for(let i = 0; i < Mercs; i++) {
-				if(V.mercUnits[i].isDeployed > 0) {
-					mercsC++;
-				}
-			}
-		} else {
+			militiaC += V.militiaUnits.filter((u) => u.isDeployed === 1).length;
+			slavesC += V.slaveUnits.filter((u) => u.isDeployed === 1).length;
+			mercsC += V.mercUnits.filter((u) => u.isDeployed === 1).length;
+		} else { // rebellion
 			if(V.secBots.active > 0) {
 				bots++;
 			}
-			if(passage() !== "attackOptions") {
-				if (V.SF.Toggle && V.SF.Active >= 1 && V.SFIntervention) { // battle
-					init++;
-				}
-			}
-			if(V.slaveRebellion+V.citizenRebellion > 0) {
-				if (V.SF.Toggle && V.SF.Active >= 1) { // rebellion
-					init++;
-				}
-				if(V.irregulars > 0) {
-					militiaC++;
-				}
-			}
-
-			const Militia = V.militiaUnits.length;
-			for(let i = 0; i < Militia; i++) {
-				if(V.militiaUnits[i].active > 0) {
-					militiaC++;
-				}
+			if (V.SF.Toggle && V.SF.Active >= 1) {
+				init++;
 			}
-
-			const Slaves = V.slaveUnits.length;
-			for(let i = 0; i < Slaves; i++) {
-				if(V.slaveUnits[i].active > 0) {
-					slavesC++;
-				}
+			if(V.irregulars > 0) {
+				militiaC++;
 			}
 
-			const Mercs = V.mercUnits.length;
-			for(let i = 0; i < Mercs; i++) {
-				if(V.mercUnits[i].active > 0) {
-					mercsC++;
-				}
-			}
+			militiaC += V.militiaUnits.filter((u) => u.active === 1 && V.loyalID.includes(u.ID)).length;
+			slavesC += V.slaveUnits.filter((u) => u.active === 1 && V.loyalID.includes(u.ID)).length;
+			mercsC += V.mercUnits.filter((u) => u.active === 1 && V.loyalID.includes(u.ID)).length;
 		}
 
 		if(input === '') {
@@ -244,50 +193,34 @@ App.SecExp.conflict = (function() {
 	function troopCount() {
 		let troops = 0;
 
-		if (V.attackThisWeek === 1) {
-			if (V.secBots.isDeployed === 1) {
-				troops += V.secBots.troops;
-			}
-			for(let i = 0; i < V.militiaUnits.length; i++) {
-				if (V.militiaUnits[i].isDeployed === 1) {
-					troops += V.militiaUnits[i].troops;
-				}
-			}
-			for(let i = 0; i < V.slaveUnits.length; i++) {
-				if (V.slaveUnits[i].isDeployed === 1) {
-					troops += V.slaveUnits[i].troops;
+		/** @param {function(FC.SecExp.PlayerHumanUnitData) : boolean} pred */
+		function countHumanTroops(pred) {
+			const arrays = [V.militiaUnits, V.slaveUnits, V.mercUnits];
+			for (const arr of arrays) {
+				for (const unit of arr) {
+					if (pred(unit)) {
+						troops += unit.troops;
+					}
 				}
 			}
-			for(let i = 0; i < V.mercUnits.length; i++) {
-				if (V.mercUnits[i].isDeployed === 1) {
-					troops += V.mercUnits[i].troops;
-				}
+		}
+
+		if (V.slaveRebellion !== 1 && V.citizenRebellion !== 1) { // attack
+			if (V.secBots.isDeployed === 1) {
+				troops += V.secBots.troops;
 			}
+			countHumanTroops((u) => u.isDeployed === 1);
 			if (V.SF.Toggle && V.SF.Active >= 1 && V.SFIntervention) {
 				troops += V.carriableSoldiers;
 			}
-		} else if (V.slaveRebellion === 1 || V.citizenRebellion === 1) {
+		} else {
 			if (V.irregulars > 0) {
 				troops += V.irregulars;
 			}
 			if (V.secBots.active === 1) {
 				troops += V.secBots.troops;
 			}
-			for(let i = 0; i < V.militiaUnits.length; i++) {
-				if (V.militiaUnits[i].active === 1 && V.loyalID.includes(V.militiaUnits[i].ID)) {
-					troops += V.militiaUnits[i].troops;
-				}
-			}
-			for(let i = 0; i < V.slaveUnits.length; i++) {
-				if (V.slaveUnits[i].active === 1 && V.loyalID.includes(V.slaveUnits[i].ID)) {
-					troops += V.slaveUnits[i].troops;
-				}
-			}
-			for(let i = 0; i < V.mercUnits.length; i++) {
-				if (V.mercUnits[i].active === 1 && V.loyalID.includes(V.mercUnits[i].ID)) {
-					troops += V.mercUnits[i].troops;
-				}
-			}
+			countHumanTroops((u) => u.active === 1 && V.loyalID.includes(u.ID));
 			if (V.SF.Toggle && V.SF.Active >= 1) {
 				troops += V.carriableSoldiers;
 			}
@@ -437,7 +370,6 @@ App.SecExp.Check = (function() {
 	};
 
 	function general() {
-		V.secBots = V.secBots || {};
 		if (jsDef(V.secExp)) {
 			if (V.secExpEnabled !== 1) {
 				V.secExpEnabled = V.secExp;
@@ -765,11 +697,13 @@ App.SecExp.Check = (function() {
 	}
 })();
 
-App.SecExp.unit = (function() {
-	return {
-		dec:description,
-	};
+App.SecExp.describeUnit = (function() {
+	return description;
 
+	/**
+	 * @param {FC.SecExp.PlayerUnitData} input
+	 * @param {string} unitType
+	 */
 	function description(input, unitType = '') {
 		let r = ``;
 		if (V.SecExp.settings.unitDescriptions === 0) {
@@ -787,9 +721,9 @@ App.SecExp.unit = (function() {
 				} else {
 					r += `is ready to face the enemy in battle. `;
 				}
-				r += `\nIt's ${input.troops} men and women are `;
+				r += `\nIts ${input.troops} men and women are `;
 
-				if(unitType === "Militia") {
+				if (unitType === "Militia") {
 					r += `all proud citizens of your arcology, willing to put their lives on the line to protect their home. `;
 				} else if (unitType === "Slaves") {
 					r += `slaves in your possession, tasked with the protection of their owner and their arcology. `;
@@ -829,7 +763,7 @@ App.SecExp.unit = (function() {
 			if(unitType !== "Bots") {
 				if(input.training <= 33) {
 					r += `They lack the experience to be considered professionals, but `;
-					if (input === "Militia") {
+					if (unitType === "Militia") {
 						r += `their eagerness to defend the arcology makes up for it. `;
 					} else if (unitType === "Slaves") {
 						r += `their eagerness to prove themselves makes up for it. `;
@@ -933,3 +867,7 @@ App.SecExp.unit = (function() {
 		return r;
 	}
 })();
+
+App.SecExp.mercenaryAvgLoyalty = function() {
+	return _.mean(V.mercUnits.filter((u) => u.active === 1).map((u) => u.loyalty));
+};
diff --git a/src/Mods/SecExp/rebellionHandler.tw b/src/Mods/SecExp/rebellionHandler.tw
index eb2533f968979c7a0b1de2d8a9f675438cb32b2e..20e41d978aa6933661fa1c69426dd96b900bbc83 100644
--- a/src/Mods/SecExp/rebellionHandler.tw
+++ b/src/Mods/SecExp/rebellionHandler.tw
@@ -45,86 +45,41 @@
 <</if>>
 <<if $irregulars > 0>>
 	<<set _irregularMod = Math.trunc(_irregularMod)>>
-	<<set _attack += (($militiaBaseAttack - $humanUpgrade.attack) + ($militiaBaseAttack - $humanUpgrade.attack) * $attackEquip * $equipMod) * _irregularMod * 0.80>>
-	<<set _defense += (($militiaBaseDefense - $humanUpgrade.defense) + ($militiaBaseDefense - $humanUpgrade.defense) * $attackEquip * $equipMod) * _irregularMod * 0.80>>
-	<<set _hp += $militiaBaseHp * $irregulars>>
+	<<set _unit = App.SecExp.getIrregularUnit("Militia", $irregulars, $attackEquip)>>
+	<<set _attack += _unit.attack * _irregularMod * 0.80>>
+	<<set _defense += _unit.defense * _irregularMod * 0.80>>
+	<<set _hp += _unit.hp>>
 <</if>>
 
 <<if $secBots.active == 1>>
-	<<set _attack += ($secBotsBaseAttack + $secBotsBaseAttack * $secBots.equip * $equipMod)>>
-	<<set _defense += ($secBotsBaseDefense + $secBotsBaseDefense * $secBots.equip * $equipMod)>>
-	<<set _hp += $secBotsBaseHp * $secBots.troops>>
+	<<set _unit = App.SecExp.getUnit("Bots")>>
+	<<set _attack += _unit.attack>>
+	<<set _defense += _unit.defense>>
+	<<set _hp += _unit.hp>>
 <</if>>
 
 <<for _i = 0; _i < $militiaUnits.length; _i++>>
 	<<if $militiaUnits[_i].active == 1 && $loyalID.includes($militiaUnits[_i].ID)>>
-		<<if $militiaUnits[_i].training <= 10>>
-			<<set _expBonus = 0>>
-		<<elseif $militiaUnits[_i].training <= 33>>
-			<<set _expBonus = 0.10>>
-		<<elseif $militiaUnits[_i].training <= 66>>
-			<<set _expBonus = 0.25>>
-		<<else>>
-			<<set _expBonus = 0.50>>
-		<</if>>
-		<<if $militiaUnits[_i].loyalty <= 10>>
-			<<set _loyaltyBonus = 0>>
-		<<elseif $militiaUnits[_i].loyalty <= 33>>
-			<<set _loyaltyBonus = 0.10>>
-		<<elseif $militiaUnits[_i].loyalty <= 66>>
-			<<set _loyaltyBonus = 0.20>>
-		<<else>>
-			<<set _loyaltyBonus = 0.30>>
-		<</if>>
-		<<set _attack += ($militiaBaseAttack + $militiaBaseAttack * $militiaUnits[_i].equip * $equipMod + $militiaBaseAttack * _expBonus + $militiaBaseAttack * _loyaltyBonus + $militiaBaseAttack * $militiaUnits[_i].SF * 0.20 + $militiaUnits[_i].cyber)>>
-		<<set _defense += ($militiaBaseDefense + $militiaBaseDefense * $militiaUnits[_i].equip * $equipMod + $militiaBaseDefense * _expBonus + $militiaBaseDefense * _loyaltyBonus + $militiaBaseDefense * $militiaUnits[_i].SF * 0.20 + $militiaUnits[_i].cyber)>>
-		<<set _hp += ($militiaBaseHp + $militiaUnits[_i].cyber + $militiaBaseHp * $militiaUnits[_i].medics * 0.25) * $militiaUnits[_i].troops>>
+		<<set _unit = App.SecExp.getUnit("Militia", _i)>>
+		<<set _attack += _unit.attack>>
+		<<set _defense += _unit.defense>>
+		<<set _hp += _unit.hp>>
 	<</if>>
 <</for>>
 <<for _i = 0; _i < $slaveUnits.length; _i++>>
 	<<if $slaveUnits[_i].active == 1 && $loyalID.includes($slaveUnits[_i].ID)>>
-		<<if $slaveUnits[_i].training <= 33>>
-			<<set _expBonus = 0>>
-		<<elseif $slaveUnits[_i].training <= 66>>
-			<<set _expBonus = 0.25>>
-		<<else>>
-			<<set _expBonus = 0.50>>
-		<</if>>
-		<<if $slaveUnits[_i].loyalty <= 10>>
-			<<set _loyaltyBonus = 0>>
-		<<elseif $slaveUnits[_i].loyalty <= 33>>
-			<<set _loyaltyBonus = 0.10>>
-		<<elseif $slaveUnits[_i].loyalty <= 66>>
-			<<set _loyaltyBonus = 0.20>>
-		<<else>>
-			<<set _loyaltyBonus = 0.30>>
-		<</if>>
-		<<set _attack += ($slaveBaseAttack + $slaveBaseAttack * $slaveUnits[_i].equip * $equipMod + $slaveBaseAttack * _expBonus + $slaveBaseAttack * _loyaltyBonus + $slaveBaseAttack * $slaveUnits[_i].SF * 0.20 + $slaveUnits[_i].cyber)>>
-		<<set _defense += ($slaveBaseDefense + $slaveBaseDefense * $slaveUnits[_i].equip * $equipMod + $slaveBaseDefense * _expBonus + $slaveBaseDefense * _loyaltyBonus + $slaveBaseDefense * $slaveUnits[_i].SF * 0.20 + $slaveUnits[_i].cyber)>>
-		<<set _hp += ($slaveBaseHp + $slaveUnits[_i].cyber + $slaveBaseHp * $slaveUnits[_i].medics * 0.25) * $slaveUnits[_i].troops>>
+		<<set _unit = App.SecExp.getUnit("Slaves", _i)>>
+		<<set _attack += _unit.attack>>
+		<<set _defense += _unit.defense>>
+		<<set _hp += _unit.hp>>
 	<</if>>
 <</for>>
 <<for _i = 0; _i < $mercUnits.length; _i++>>
 	<<if $mercUnits[_i].active == 1 && $loyalID.includes($mercUnits[_i].ID)>>
-		<<if $mercUnits[_i].training <= 33>>
-			<<set _expBonus = 0>>
-		<<elseif $mercUnits[_i].training <= 66>>
-			<<set _expBonus = 0.25>>
-		<<else>>
-			<<set _expBonus = 0.50>>
-		<</if>>
-		<<if $mercUnits[_i].loyalty <= 10>>
-			<<set _loyaltyBonus = 0>>
-		<<elseif $mercUnits[_i].loyalty <= 33>>
-			<<set _loyaltyBonus = 0.10>>
-		<<elseif $mercUnits[_i].loyalty <= 66>>
-			<<set _loyaltyBonus = 0.20>>
-		<<else>>
-			<<set _loyaltyBonus = 0.30>>
-		<</if>>
-		<<set _attack += ($mercBaseAttack + $mercBaseAttack * $mercUnits[_i].equip * $equipMod + $mercBaseAttack * _expBonus + $mercBaseAttack * _loyaltyBonus + $mercBaseAttack * $mercUnits[_i].SF * 0.20 + $mercUnits[_i].cyber)>>
-		<<set _defense += ($mercBaseDefense + $mercBaseDefense * $mercUnits[_i].equip * $equipMod + $mercBaseDefense * _expBonus + $mercBaseDefense * _loyaltyBonus + $mercBaseDefense * $mercUnits[_i].SF * 0.20 + $mercUnits[_i].cyber)>>
-		<<set _hp += ($mercBaseHp + $mercUnits[_i].cyber + $mercBaseHp * $mercUnits[_i].medics * 0.25) * $mercUnits[_i].troops>>
+		<<set _unit = App.SecExp.getUnit("Mercs", _i)>>
+		<<set _attack += _unit.attack>>
+		<<set _defense += _unit.defense>>
+		<<set _hp += _unit.hp>>
 	<</if>>
 <</for>>
 
@@ -166,10 +121,10 @@
 <<set _moraleTroopMod = Math.clamp(App.SecExp.conflict.troopCount() / 100,1,10)>>
 
 /* morale and baseHp calculation */
-<<set _morale = ($secBotsMorale * $secBots.active + $militiaBaseMorale * App.SecExp.conflict.deployedUnits('militia') + $slaveBaseMorale * App.SecExp.conflict.deployedUnits('slaves') + $mercBaseMorale * App.SecExp.conflict.deployedUnits('mercs') + $SFBaseMorale * $SF.Active) / ($secBots.active + App.SecExp.conflict.deployedUnits('militia') +App.SecExp.conflict.deployedUnits('slaves') + App.SecExp.conflict.deployedUnits('mercs') + $SF.Active)>>
+<<set _morale = (App.SecExp.BaseDroneUnit.morale * $secBots.active + App.SecExp.BaseMilitiaUnit.morale * App.SecExp.conflict.deployedUnits('militia') + App.SecExp.BaseSlaveUnit.morale * App.SecExp.conflict.deployedUnits('slaves') + App.SecExp.BaseMercUnit.morale * App.SecExp.conflict.deployedUnits('mercs') + App.SecExp.BaseSpecialForcesUnit.morale * $SF.Active) / ($secBots.active + App.SecExp.conflict.deployedUnits('militia') + App.SecExp.conflict.deployedUnits('slaves') + App.SecExp.conflict.deployedUnits('mercs') + $SF.Active)>>
 <<set _morale = _morale + _morale * $SecExp.buildings.barracks.upgrades.luxury * 0.05>>	/* barracks bonus */
 <<set _morale *= _moraleTroopMod>>
-<<set _baseHp = ($secBotsBaseHp * $secBots.active + $militiaBaseHp * App.SecExp.conflict.deployedUnits('militia') + $slaveBaseHp * App.SecExp.conflict.deployedUnits('slaves') + $mercBaseHp * App.SecExp.conflict.deployedUnits('mercs') + $SFBaseHp * $SF.Active) / ($secBots.active + App.SecExp.conflict.deployedUnits('militia') +App.SecExp.conflict.deployedUnits('slaves') + App.SecExp.conflict.deployedUnits('mercs') + $SF.Active)>>
+<<set _baseHp = (App.SecExp.BaseDroneUnit.hp * $secBots.active + App.SecExp.BaseMilitiaUnit.hp * App.SecExp.conflict.deployedUnits('militia') + App.SecExp.BaseSlaveUnit.hp * App.SecExp.conflict.deployedUnits('slaves') + App.SecExp.BaseMercUnit.hp * App.SecExp.conflict.deployedUnits('mercs') + App.SecExp.BaseSpecialForcesUnit.hp * $SF.Active) / ($secBots.active + App.SecExp.conflict.deployedUnits('militia') + App.SecExp.conflict.deployedUnits('slaves') + App.SecExp.conflict.deployedUnits('mercs') + $SF.Active)>>
 
 /* calculates rebelling army stats */
 <<if $week <= 30>>
@@ -187,72 +142,54 @@
 
 <<if $slaveRebellion == 1>>
 	<<set $rebellingSlaves = 1>>
-	<<set _enemyAttack += (($slaveBaseAttack - $humanUpgrade.attack) + ($slaveBaseAttack - $humanUpgrade.attack) * $attackEquip * $equipMod) * _armyMod>>
-	<<set _enemyDefense += (($slaveBaseDefense - $humanUpgrade.defense) + ($slaveBaseDefense - $humanUpgrade.defense) * $attackEquip * $equipMod) * _armyMod>>
-	<<set _enemyHp += $slaveBaseHp * $attackTroops>>
+	<<set _unit = App.SecExp.getIrregularUnit("Slaves", $attackTroops, $attackEquip)>>
 <<else>>
 	<<set $rebellingMilitia = 1>>
-	<<set _enemyAttack += (($militiaBaseAttack - $humanUpgrade.attack) + ($militiaBaseAttack - $humanUpgrade.attack) * $attackEquip * $equipMod) * _armyMod>>
-	<<set _enemyDefense += (($militiaBaseDefense - $humanUpgrade.defense) + ($militiaBaseDefense - $humanUpgrade.defense) * $attackEquip * $equipMod) * _armyMod>>
-	<<set _enemyHp += $militiaBaseHp * $attackTroops>>
+	<<set _unit = App.SecExp.getIrregularUnit("Militia", $attackTroops, $attackEquip)>>
 <</if>>
+<<set _enemyAttack += _unit.attack * _armyMod>>
+<<set _enemyDefense += _unit.defense * _armyMod>>
+<<set _enemyHp += _unit.hp>>
 
 <<for _i = 0; _i < $militiaUnits.length; _i++>>
 	<<if $militiaUnits[_i].active == 1 && $rebellingID.includes($militiaUnits[_i].ID)>>
 		<<set $rebellingMilitia = 1>>
 		<<set $attackTroops += $militiaUnits[_i].troops>>
-		<<if $militiaUnits[_i].training <= 10>>
-			<<set _expBonus = 0>>
-		<<elseif $militiaUnits[_i].training <= 33>>
-			<<set _expBonus = 0.10>>
-		<<elseif $militiaUnits[_i].training <= 66>>
-			<<set _expBonus = 0.25>>
-		<<else>>
-			<<set _expBonus = 0.50>>
-		<</if>>
-		<<set _enemyAttack += ($militiaBaseAttack + $militiaBaseAttack * $militiaUnits[_i].equip * $equipMod + $militiaBaseAttack * _expBonus + $militiaBaseAttack * $militiaUnits[_i].SF * 0.20 + $militiaUnits[_i].cyber)>>
-		<<set _enemyDefense += ($militiaBaseDefense + $militiaBaseDefense * $militiaUnits[_i].equip * $equipMod + $militiaBaseDefense * _expBonus + $militiaBaseDefense * $militiaUnits[_i].SF * 0.20 + $militiaUnits[_i].cyber)>>
-		<<set _enemyHp += ($militiaBaseHp + $militiaUnits[_i].cyber + $militiaBaseHp * $militiaUnits[_i].medics * $equipMod) * $militiaUnits[_i].troops>>
+		<<set $militiaUnits[_i].loyalty = 0>>
+		<<set _unit = App.SecExp.getUnit("Militia", _i)>>
+		<<set _enemyAttack += _unit.attack>>
+		<<set _enemyDefense += _unit.defense>>
+		<<set _enemyHp += _unit.hp>>
 	<</if>>
 <</for>>
 <<for _i = 0; _i < $slaveUnits.length; _i++>>
 	<<if $slaveUnits[_i].active == 1 && $rebellingID.includes($slaveUnits[_i].ID)>>
 		<<set $rebellingSlaves = 1>>
 		<<set $attackTroops += $slaveUnits[_i].troops>>
-		<<if $slaveUnits[_i].training <= 33>>
-			<<set _expBonus = 0>>
-		<<elseif $slaveUnits[_i].training <= 66>>
-			<<set _expBonus = 0.25>>
-		<<else>>
-			<<set _expBonus = 0.50>>
-		<</if>>
-		<<set _enemyAttack += ($slaveBaseAttack + $slaveBaseAttack * $slaveUnits[_i].equip * $equipMod + $slaveBaseAttack * _expBonus + $slaveBaseAttack * $slaveUnits[_i].SF * 0.20 + $slaveUnits[_i].cyber)>>
-		<<set _enemyDefense += ($slaveBaseDefense + $slaveBaseDefense * $slaveUnits[_i].equip * $equipMod + $slaveBaseDefense * _expBonus + $slaveBaseDefense * $slaveUnits[_i].SF * 0.20 + $slaveUnits[_i].cyber)>>
-		<<set _enemyHp += ($slaveBaseHp + $slaveUnits[_i].cyber + $slaveBaseHp * $slaveUnits[_i].medics * 0.25) * $slaveUnits[_i].troops>>
+		<<set $slaveUnits[_i].loyalty = 0>>
+		<<set _unit = App.SecExp.getUnit("Slaves", _i)>>
+		<<set _enemyAttack += _unit.attack>>
+		<<set _enemyDefense += _unit.defense>>
+		<<set _enemyHp += _unit.hp>>
 	<</if>>
 <</for>>
 <<for _i = 0; _i < $mercUnits.length; _i++>>
 	<<if $mercUnits[_i].active == 1 && $rebellingID.includes($mercUnits[_i].ID)>>
 		<<set $rebellingMercs = 1>>
 		<<set $attackTroops += $mercUnits[_i].troops>>
-		<<if $mercUnits[_i].training <= 33>>
-			<<set _expBonus = 0>>
-		<<elseif $mercUnits[_i].training <= 66>>
-			<<set _expBonus = 0.25>>
-		<<else>>
-			<<set _expBonus = 0.50>>
-		<</if>>
-		<<set _enemyAttack += ($mercBaseAttack + $mercBaseAttack * $mercUnits[_i].equip * $equipMod + $mercBaseAttack * _expBonus + $mercBaseAttack * $mercUnits[_i].SF * 0.20 + $mercUnits[_i].cyber)>>
-		<<set _enemyDefense += ($mercBaseDefense + $mercBaseDefense * $mercUnits[_i].equip * $equipMod + $mercBaseDefense * _expBonus + $mercBaseDefense * $mercUnits[_i].SF * 0.20 + $mercUnits[_i].cyber)>>
-		<<set _enemyHp += ($mercBaseHp + $mercUnits[_i].cyber + $mercBaseHp * $mercUnits[_i].medics * 0.25) * $mercUnits[_i].troops>>
+		<<set $mercUnits[_i].loyalty = 0>>
+		<<set _unit = App.SecExp.getUnit("Mercs", _i)>>
+		<<set _enemyAttack += _unit.attack>>
+		<<set _enemyDefense += _unit.defense>>
+		<<set _enemyHp += _unit.hp>>
 	<</if>>
 <</for>>
 
 <<set _enemyMoraleTroopMod = Math.clamp($attackTroops / 100,1,10)>>
 
-<<set _enemyMorale = 1.5 * ($militiaBaseMorale * $rebellingMilitia + $slaveBaseMorale * $rebellingSlaves + $mercBaseMorale * $rebellingMercs) / ($rebellingMilitia + $rebellingSlaves + $rebellingMercs)>>
+<<set _enemyMorale = 1.5 * (App.SecExp.BaseMilitiaUnit.morale * $rebellingMilitia + App.SecExp.BaseSlaveUnit.morale * $rebellingSlaves + App.SecExp.BaseMercUnit.morale * $rebellingMercs) / ($rebellingMilitia + $rebellingSlaves + $rebellingMercs)>>
 <<set _enemyMorale *= _enemyMoraleTroopMod>>
-<<set _enemyBaseHp = ($militiaBaseHp * $rebellingMilitia + $slaveBaseHp * $rebellingSlaves + $mercBaseHp * $rebellingMercs) / ($rebellingMilitia +$rebellingSlaves + $rebellingMercs)>>
+<<set _enemyBaseHp = (App.SecExp.BaseMilitiaUnit.hp * $rebellingMilitia + App.SecExp.BaseSlaveUnit.hp * $rebellingSlaves + App.SecExp.BaseMercUnit.hp * $rebellingMercs) / ($rebellingMilitia + $rebellingSlaves + $rebellingMercs)>>
 
 <<if isNaN(_attack)>>
 	<br>@@.red;Error: attack value reported NaN@@
@@ -365,8 +302,7 @@ __Rebels__:
 	<</if>>
 	<br>
 	<<if $SecExp.settings.showStats == 1>> enemy damage: <<print num(Math.round(_damage))>><</if>>
-	<<if $SFGear>> <<set _S = .85>> <<else>> <<set _S = 1>> <</if>>
-	<<set _hp -= _damage*_S>>
+	<<set _hp -= _damage*($SFGear ? 0.85 : 1)>>
 	<br>
 	<<if $SecExp.settings.showStats == 1>> remaining hp: <<print num(Math.round(_hp))>><</if>>
 	<<set $losses += _damage / _baseHp>>
diff --git a/src/Mods/SecExp/securityReport.tw b/src/Mods/SecExp/securityReport.tw
index eb5f88d1a94d919f7b3f72504af43b22b88d9e11..a159865fb32120445fe8b2cd6eb01b3618fee7b5 100644
--- a/src/Mods/SecExp/securityReport.tw
+++ b/src/Mods/SecExp/securityReport.tw
@@ -650,9 +650,6 @@ Due to the deterioration of the old world countries, organized crime focuses mor
 				<<set $mercUnits[_i].training += random(2,4) * 1.5 * $SecExp.buildings.barracks.upgrades.training>>
 			<</if>>
 		<</for>>
-		<<if _meL > 0>>
-			<<set $mercLoyalty = (_loyaltyTotal/_meL)>>
-		<</if>>
 	<</if>>
 <</if>>
 
@@ -745,7 +742,6 @@ Due to the deterioration of the old world countries, organized crime focuses mor
 		<<set $currentUpgrade.unit = -1>>
 		<<set $currentUpgrade.time = 0>>
 		in the following days.
-		<<recalcBaseStats>>
 		<<set $completedUpgrades.push($currentUpgrade.ID)>>
 	<<else>>
 		It will be finished in <<if $currentUpgrade.time == 1>> one week.<<else>><<print $currentUpgrade.time>> weeks.<</if>>
diff --git a/src/Mods/SecExp/seeUnit.tw b/src/Mods/SecExp/seeUnit.tw
index 57ae1e59f1e1e44161ba4b91c41f9d320c94a35c..94a3a769febd45bf0247ea49dcae1ccca5b25fdb 100644
--- a/src/Mods/SecExp/seeUnit.tw
+++ b/src/Mods/SecExp/seeUnit.tw
@@ -7,7 +7,8 @@
 <</if>>
 
 <<if $targetUnit == "secBots">>
-	<<= App.SecExp.unit.dec($secBots, "Bots")>>
+	<<set _unit = App.SecExp.getUnit("Bots")>>
+	<<= _unit.describe()>>
 	<<if $secBots.maxTroops > $secBots.troops>>
 		<br>
 		<<link "Replenish the unit" "seeUnit">>
@@ -50,16 +51,11 @@
 		Your drones are equipped with top tier weaponry and armor.
 	<</if>>
 	<<if $SecExp.settings.showStats == 1>>
-		<br>
-		<br>Security drones base attack: $secBotsBaseAttack <<if $droneUpgrades.attack > 0>> + 1 <</if>>(<<print Math.round($secBotsBaseAttack + $secBotsBaseAttack * $secBots.equip * 0.15)>>)
-		<br>Security drones base defense: $secBotsBaseDefense <<if $droneUpgrades.defense > 0>> + 1 <</if>>(<<print Math.round($secBotsBaseDefense + $secBotsBaseDefense * $secBots.equip * 0.15)>>)
-		<br>Equipment bonus: + <<print $secBots.equip * 15>>%
-		<br>Security drones base hp: $secBotsBaseHp <<if $droneUpgrades.hp > 0>> + 1 <</if>>
-		<br>Security drones base morale: $secBotsMorale
+		<br><<= _unit.printStats()>>
 	<</if>>
 <<elseif $targetUnit == "militiaUnits">>
-	<<= App.SecExp.unit.dec($militiaUnits[$targetIndex], "Militia")>>
-	<br>
+	<<set _unit = App.SecExp.getUnit("Militia", $targetIndex)>>
+	<<= _unit.describe()>>
 	Rename unit <<textbox "$militiaUnits[$targetIndex].platoonName" $militiaUnits[$targetIndex].platoonName "seeUnit">>
 	<<if $militiaUnits[$targetIndex].maxTroops > $militiaUnits[$targetIndex].troops && $militiaFreeManpower > 0>>
 		<br>
@@ -162,55 +158,12 @@
 			<br>The unit has attached advisors from $SF.Lower that will help the squad remain tactically aware and active.
 		<</if>>
 	<</if>>
-
 	<<if $SecExp.settings.showStats == 1>>
-		<<if $militiaUnits[$targetIndex].training <= 10>>
-			<<set _expBonus = 0>>
-		<<elseif $militiaUnits[$targetIndex].training <= 33>>
-			<<set _expBonus = 10>>
-		<<elseif $militiaUnits[$targetIndex].training <= 66>>
-			<<set _expBonus = 25>>
-		<<else>>
-			<<set _expBonus = 50>>
-		<</if>>
-		<<if $militiaUnits[$targetIndex].loyalty <= 10>>
-			<<set _loyaltyBonus = 0>>
-		<<elseif $militiaUnits[$targetIndex].loyalty <= 33>>
-			<<set _loyaltyBonus = 10>>
-		<<elseif $militiaUnits[$targetIndex].loyalty <= 66>>
-			<<set _loyaltyBonus = 20>>
-		<<else>>
-			<<set _loyaltyBonus = 30>>
-		<</if>>
-		<br>
-		<br>Militia base attack: $militiaBaseAttack <<if $humanUpgrade.attack > 0>> + $humanUpgrade.attack <</if>>(<<print Math.round($militiaBaseAttack + $militiaUnits[$targetIndex].cyber + $militiaBaseAttack * $militiaUnits[$targetIndex].equip * $equipMod + $militiaBaseAttack * _expBonus * 0.01 + $militiaBaseAttack * _loyaltyBonus * 0.01 + $militiaBaseAttack * $militiaUnits[$targetIndex].SF * 0.20)>>)
-		<br>Militia base defense: $militiaBaseDefense <<if $humanUpgrade.defense > 0>> + $humanUpgrade.defense <</if>>(<<print Math.round($militiaBaseDefense + $militiaUnits[$targetIndex].cyber + $militiaBaseDefense * $militiaUnits[$targetIndex].equip * $equipMod + $militiaBaseDefense * _expBonus * 0.01 + $militiaBaseDefense * _loyaltyBonus * 0.01 + $militiaBaseDefense * $militiaUnits[$targetIndex].SF * 0.20)>>)
-		<<if $militiaUnits[$targetIndex].equip > 0>>
-			<br>Equipment bonus: + <<print $militiaUnits[$targetIndex].equip * 15>>%
-		<</if>>
-		<<if $militiaUnits[$targetIndex].cyber > 0>>
-			<br>Cyber enhancements bonus: + 1
-		<</if>>
-		<<if _expBonus > 0>>
-			<br>Experience bonus: +<<print _expBonus>>%
-		<</if>>
-		<<if _loyaltyBonus > 0>>
-			<br>Loyalty bonus: +<<print _loyaltyBonus>>%
-		<</if>>
-		<<if $militiaUnits[$targetIndex].SF > 0>>
-			<br>Special Force advisors bonus: +20%
-		<</if>>
-		<br>Militia base morale: $militiaBaseMorale <<if $humanUpgrade.morale > 0>> + $humanUpgrade.morale <</if>>(<<print Math.round($militiaBaseMorale + $militiaBaseMorale * $SecExp.buildings.barracks.upgrades.luxury * 0.05)>>)
-		<<if $SecExp.buildings.barracks.upgrades.luxury > 0>>
-			<br>Barracks bonus: + <<print $SecExp.buildings.barracks.upgrades.luxury * 5>>%
-		<</if>>
-		<br>Militia base hp: $militiaBaseHp <<if $humanUpgrade.hp > 0>> + $humanUpgrade.hp <</if>>(<<print Math.round($militiaBaseHp + $militiaUnits[$targetIndex].cyber + $militiaBaseHp * $militiaUnits[$targetIndex].medics * 0.25)>>)
-		<<if $militiaUnits[$targetIndex].medics > 0>>
-			<br>Medics detachment bonus: +25%
-		<</if>>
+		<br><<= _unit.printStats()>>
 	<</if>>
 <<elseif $targetUnit == "slaveUnits">>
-	<<= App.SecExp.unit.dec($slaveUnits[$targetIndex], "Slaves")>>
+	<<set _unit = App.SecExp.getUnit("Slaves", $targetIndex)>>
+	<<= _unit.describe()>>
 	<br>
 	Rename unit <<textbox "$slaveUnits[$targetIndex].platoonName" $slaveUnits[$targetIndex].platoonName "seeUnit">>
 	<<if $slaveUnits[$targetIndex].maxTroops > $slaveUnits[$targetIndex].troops && $menials > 0>>
@@ -314,53 +267,11 @@
 		<</if>>
 	<</if>>
 	<<if $SecExp.settings.showStats == 1>>
-		<<if $slaveUnits[$targetIndex].training <= 10>>
-			<<set _expBonus = 0>>
-		<<elseif $slaveUnits[$targetIndex].training <= 33>>
-			<<set _expBonus = 10>>
-		<<elseif $slaveUnits[$targetIndex].training <= 66>>
-			<<set _expBonus = 25>>
-		<<else>>
-			<<set _expBonus = 50>>
-		<</if>>
-		<<if $slaveUnits[$targetIndex].loyalty <= 10>>
-			<<set _loyaltyBonus = 0>>
-		<<elseif $slaveUnits[$targetIndex].loyalty <= 33>>
-			<<set _loyaltyBonus = 10>>
-		<<elseif $slaveUnits[$targetIndex].loyalty <= 66>>
-			<<set _loyaltyBonus = 20>>
-		<<else>>
-			<<set _loyaltyBonus = 30>>
-		<</if>>
-		<br>
-		<br>Slaves base attack: $slaveBaseAttack <<if $humanUpgrade.attack > 0>> + $humanUpgrade.attack <</if>>(<<print Math.round($slaveBaseAttack + $slaveUnits[$targetIndex].cyber + $slaveBaseAttack * $slaveUnits[$targetIndex].equip * $equipMod + $slaveBaseAttack * _expBonus * 0.01 + $slaveBaseAttack * _loyaltyBonus * 0.01 + $slaveBaseAttack * $slaveUnits[$targetIndex].SF * 0.20)>>)
-		<br>Slaves base defense: $slaveBaseDefense <<if $humanUpgrade.defense > 0>> + $humanUpgrade.defense <</if>>(<<print Math.round($slaveBaseDefense + $slaveUnits[$targetIndex].cyber + $slaveBaseDefense * $slaveUnits[$targetIndex].equip * $equipMod + $slaveBaseDefense * _expBonus * 0.01 + $slaveBaseDefense * _loyaltyBonus * 0.01 + $slaveBaseDefense * $slaveUnits[$targetIndex].SF * 0.20)>>)
-		<<if $slaveUnits[$targetIndex].equip > 0>>
-			<br>Equipment bonus: + <<print $slaveUnits[$targetIndex].equip * 15>>%
-		<</if>>
-		<<if $slaveUnits[$targetIndex].cyber > 0>>
-			<br>Cyber enhancements bonus: + 1
-		<</if>>
-		<<if _expBonus > 0>>
-			<br>Experience bonus: +<<print _expBonus>>%
-		<</if>>
-		<<if _loyaltyBonus > 0>>
-			<br>Loyalty bonus: +<<print _loyaltyBonus>>%
-		<</if>>
-		<<if $slaveUnits[$targetIndex].SF > 0>>
-			<br>Special Force advisors bonus: +20%
-		<</if>>
-		<br>Slaves base morale: $slaveBaseMorale <<if $humanUpgrade.morale > 0>> + $humanUpgrade.morale <</if>>(<<print Math.round($slaveBaseMorale + $slaveBaseMorale * $SecExp.buildings.barracks.upgrades.luxury * 0.05)>>)
-		<<if $SecExp.buildings.barracks.upgrades.luxury > 0>>
-			<br>Barracks bonus: + <<print $SecExp.buildings.barracks.upgrades.luxury * 5>>%
-		<</if>>
-		<br>Slaves base hp: $slaveBaseHp <<if $humanUpgrade.hp > 0>> + $humanUpgrade.hp <</if>>(<<print Math.round($slaveBaseHp + $slaveUnits[$targetIndex].cyber + $slaveBaseHp * $slaveUnits[$targetIndex].medics * 0.25)>>)
-		<<if $slaveUnits[$targetIndex].medics > 0>>
-			<br>Medics detachment bonus: +25%
-		<</if>>
+		<br><<= _unit.printStats()>>
 	<</if>>
 <<elseif $targetUnit == "mercUnits">>
-	<<= App.SecExp.unit.dec($mercUnits[$targetIndex], "Mercs")>>
+	<<set _unit = App.SecExp.getUnit("Mercs", $targetIndex)>>
+	<<= _unit.describe()>>
 	<br>
 	Rename unit <<textbox "$mercUnits[$targetIndex].platoonName" $mercUnits[$targetIndex].platoonName "seeUnit">>
 	<<if $mercUnits[$targetIndex].troops < $mercUnits[$targetIndex].maxTroops && $mercFreeManpower > 0>>
@@ -462,49 +373,6 @@
 		<</if>>
 	<</if>>
 	<<if $SecExp.settings.showStats == 1>>
-		<<if $mercUnits[$targetIndex].training <= 10>>
-			<<set _expBonus = 0>>
-		<<elseif $mercUnits[$targetIndex].training <= 33>>
-			<<set _expBonus = 10>>
-		<<elseif $mercUnits[$targetIndex].training <= 66>>
-			<<set _expBonus = 25>>
-		<<else>>
-			<<set _expBonus = 50>>
-		<</if>>
-		<<if $mercUnits[$targetIndex].loyalty <= 10>>
-			<<set _loyaltyBonus = 0>>
-		<<elseif $mercUnits[$targetIndex].loyalty <= 33>>
-			<<set _loyaltyBonus = 10>>
-		<<elseif $mercUnits[$targetIndex].loyalty <= 66>>
-			<<set _loyaltyBonus = 20>>
-		<<else>>
-			<<set _loyaltyBonus = 30>>
-		<</if>>
-		<br>
-		<br>Mercenaries base attack: $mercBaseAttack <<if $humanUpgrade.attack > 0>> + $humanUpgrade.attack <</if>>(<<print Math.round($mercBaseAttack + $mercBaseAttack * $mercUnits[$targetIndex].equip * $equipMod + $mercBaseAttack * _expBonus * 0.01 + $mercBaseAttack * _loyaltyBonus * 0.01 + $mercBaseAttack * $mercUnits[$targetIndex].SF * 0.20 + $mercUnits[$targetIndex].cyber)>>)
-		<br>Mercenaries base defense: $mercBaseDefense <<if $humanUpgrade.defense > 0>> + $humanUpgrade.defense <</if>>(<<print Math.round($mercBaseDefense + $mercBaseDefense * $mercUnits[$targetIndex].equip * $equipMod + $mercBaseDefense * _expBonus * 0.01 + $mercBaseDefense * _loyaltyBonus * 0.01 + $mercBaseDefense * $mercUnits[$targetIndex].SF * 0.20 + $mercUnits[$targetIndex].cyber)>>)
-		<<if $mercUnits[$targetIndex].equip > 0>>
-			<br>Equipment bonus: + <<print $mercUnits[$targetIndex].equip * 15>>%
-		<</if>>
-		<<if $mercUnits[$targetIndex].cyber > 0>>
-			<br>Cyber enhancements bonus: + 1
-		<</if>>
-		<<if _expBonus > 0>>
-			<br>Experience bonus: +<<print _expBonus>>%
-		<</if>>
-		<<if _loyaltyBonus > 0>>
-			<br>Loyalty bonus: +<<print _loyaltyBonus>>%
-		<</if>>
-		<<if $mercUnits[$targetIndex].SF > 0>>
-			<br>Special Force advisors bonus: +20%
-		<</if>>
-		<br>Mercenaries base morale: $mercBaseMorale <<if $humanUpgrade.morale > 0>> + $humanUpgrade.morale <</if>>(<<print Math.round($mercBaseMorale + $mercBaseMorale * $SecExp.buildings.barracks.upgrades.luxury * 0.05)>>)
-		<<if $SecExp.buildings.barracks.upgrades.luxury > 0>>
-			<br>Barracks bonus: + <<print $SecExp.buildings.barracks.upgrades.luxury * 5>>%
-		<</if>>
-		<br>Mercenaries base hp: $mercBaseHp <<if $humanUpgrade.hp > 0>> + $humanUpgrade.hp <</if>>(<<print Math.round($mercBaseHp + $mercBaseHp * $mercUnits[$targetIndex].medics * 0.25 + $mercUnits[$targetIndex].cyber)>>)
-		<<if $mercUnits[$targetIndex].medics > 0>>
-			<br>Medics detachment bonus: +25%
-		<</if>>
+		<br><<= _unit.printStats()>>
 	<</if>>
 <</if>>
\ No newline at end of file
diff --git a/src/Mods/SecExp/widgets/battleWidgets.js b/src/Mods/SecExp/widgets/battleWidgets.js
index c0e7504999eba2ede8800bf271b109ed3c050624..22789549aab0d7dccf8a7f340393877d15cfb71a 100644
--- a/src/Mods/SecExp/widgets/battleWidgets.js
+++ b/src/Mods/SecExp/widgets/battleWidgets.js
@@ -14,17 +14,17 @@ globalThis.calcSFStatistics = function() {
 			V.carriableSoldiers = V.SF.ArmySize / 10;
 		}
 		if (V.SF.ArmySize > V.carriableSoldiers) {
-			V.SFhp = V.carriableSoldiers * V.SFBaseHp;
+			V.SFhp = V.carriableSoldiers * App.SecExp.BaseSpecialForcesUnit.hp;
 		} else {
 			V.carriableSoldiers = V.SF.ArmySize;
-			V.SFhp = V.carriableSoldiers * V.SFBaseHp;
+			V.SFhp = V.carriableSoldiers * App.SecExp.BaseSpecialForcesUnit.hp;
 		}
 	} else {
 		/* atk, def */
 		V.SFatk = Math.trunc(0.75 * upgradesSum);
 		V.SFdef = Math.trunc(0.50 * upgradesSum);
 		/* hp */
-		V.SFhp = V.SF.ArmySize * V.SFBaseHp;
+		V.SFhp = V.SF.ArmySize * App.SecExp.BaseSpecialForcesUnit.hp;
 	}
 };
 
diff --git a/src/Mods/SecExp/widgets/miscSecExpWidgets.tw b/src/Mods/SecExp/widgets/miscSecExpWidgets.tw
index 93b8dc714e285778cbe9edc2552460964ab7872d..9a7bec5a15f1c36abdaf2ecf252a00f8ad2af7e1 100644
--- a/src/Mods/SecExp/widgets/miscSecExpWidgets.tw
+++ b/src/Mods/SecExp/widgets/miscSecExpWidgets.tw
@@ -187,69 +187,6 @@
 	<</if>>
 <</widget>>
 
-<<widget "recalcBaseStats">>
-	<<if $secBotsBaseAttack != 7 + $droneUpgrades.attack>>
-		<<set $secBotsBaseAttack = 7 + $droneUpgrades.attack>>
-	<</if>>
-	<<if $secBotsBaseDefense != 3 + $droneUpgrades.defense>>
-		<<set $secBotsBaseDefense = 3 + $droneUpgrades.defense>>
-	<</if>>
-	<<if $secBotsMorale != 200>>
-		<<set $secBotsMorale = 200>>
-	<</if>>
-	<<if $secBotsBaseHp != 3 + $droneUpgrades.hp>>
-		<<set $secBotsBaseHp = 3 + $droneUpgrades.hp>>
-	<</if>>
-	<<if $militiaBaseAttack != 7 + $humanUpgrade.attack>>
-		<<set $militiaBaseAttack = 7 + $humanUpgrade.attack>>
-	<</if>>
-	<<if $militiaBaseDefense != 5 + $humanUpgrade.defense>>
-		<<set $militiaBaseDefense = 5 + $humanUpgrade.defense>>
-	<</if>>
-	<<if $militiaBaseMorale != 140 + $humanUpgrade.morale>>
-		<<set $militiaBaseMorale = 140 + $humanUpgrade.morale>>
-	<</if>>
-	<<if $militiaBaseHp != 3 + $humanUpgrade.hp>>
-		<<set $militiaBaseHp = 3 + $humanUpgrade.hp>>
-	<</if>>
-	<<if $slaveBaseAttack != 8 + $humanUpgrade.attack>>
-		<<set $slaveBaseAttack = 8 + $humanUpgrade.attack>>
-	<</if>>
-	<<if $slaveBaseDefense != 3 + $humanUpgrade.defense>>
-		<<set $slaveBaseDefense = 3 + $humanUpgrade.defense>>
-	<</if>>
-	<<if $slaveBaseMorale != 110 + $humanUpgrade.morale>>
-		<<set $slaveBaseMorale = 110 + $humanUpgrade.morale>>
-	<</if>>
-	<<if $slaveBaseHp != 3 + $humanUpgrade.hp>>
-		<<set $slaveBaseHp = 3 + $humanUpgrade.hp>>
-	<</if>>
-	<<if $mercBaseAttack != 8 + $humanUpgrade.attack>>
-		<<set $mercBaseAttack = 8 + $humanUpgrade.attack>>
-	<</if>>
-	<<if $mercBaseDefense != 4 + $humanUpgrade.defense>>
-		<<set $mercBaseDefense = 4 + $humanUpgrade.defense>>
-	<</if>>
-	<<if $mercBaseMorale != 125 + $humanUpgrade.morale>>
-		<<set $mercBaseMorale = 125 + $humanUpgrade.morale>>
-	<</if>>
-	<<if $mercBaseHp != 4 + $humanUpgrade.hp>>
-		<<set $mercBaseHp = 4 + $humanUpgrade.hp>>
-	<</if>>
-	<<if $SFBaseAttack != 8 + $humanUpgrade.attack>>
-		<<set $SFBaseAttack = 8 + $humanUpgrade.attack>>
-	<</if>>
-	<<if $SFBaseDefense != 4 + $humanUpgrade.defense>>
-		<<set $SFBaseDefense = 4 + $humanUpgrade.defense>>
-	<</if>>
-	<<if $SFBaseMorale != 140 + $humanUpgrade.morale>>
-		<<set $SFBaseMorale = 140 + $humanUpgrade.morale>>
-	<</if>>
-	<<if $SFBaseHp != 4 + $humanUpgrade.hp>>
-		<<set $SFBaseHp = 4 + $humanUpgrade.hp>>
-	<</if>>
-<</widget>>
-
 <<widget "replenishAllUnits">>
 	<<set _hasLossesBots = 0, _hasLossesM = 0>>
 	<<set _hasLossesS = 0, _hasLossesMe = 0>>
diff --git a/src/events/intro/initNationalities.js b/src/events/intro/initNationalities.js
index 827b8516cf931af0b6017f2f8b559169731c47d7..1d054cec805aa677298691e2d02301960d92e651 100644
--- a/src/events/intro/initNationalities.js
+++ b/src/events/intro/initNationalities.js
@@ -77,16 +77,6 @@ App.Intro.initNationalities = function() {
 				V.mercFreeManpower = jsRandom(10, 30);
 			}
 		}
-
-		/* battle relevant variables */
-		V.secBots = {
-			active: 0,
-			ID: -1,
-			isDeployed: 0,
-			troops: 0,
-			maxTroops: 0,
-			equip: 0
-		};
 	}
 
 	function applyPCQualities() {