diff --git a/src/Mods/SecExp/js/secExp.js b/src/Mods/SecExp/js/secExp.js
index da6cdb20ff9243f1469f0a906392b57b4ca85d91..3a1ae8920e35cb0b9163a1982b03f31c78eb4577 100644
--- a/src/Mods/SecExp/js/secExp.js
+++ b/src/Mods/SecExp/js/secExp.js
@@ -1,3 +1,40 @@
+/**
+ * Returns the effect of a campaign launched from the PR hub.
+ */
+App.SecExp.propagandaEffects = function(focus, targetVariable) {
+	if (V.SecExp.buildings.propHub && V.SecExp.buildings.propHub.upgrades.campaign >= 1 && V.SecExp.buildings.propHub.focus === focus) {
+		let campaign, modifier, adjut;
+		const forcedViewing = V.SecExp.edicts.propCampaignBoost === 1;
+		const noRecuriter = V.SecExp.buildings.propHub.recruiterOffice === 0 || V.RecruiterID === 0;
+		switch(focus) {
+			case "social engineering":
+				campaign = 'societal engineering';
+				modifier = forcedViewing ? V.SecExp.buildings.propHub.upgrades.campaign : 1;
+				adjut = 32;
+				if (noRecuriter) {
+					targetVariable += (forcedViewing ? 2 : 1) * modifier;
+				}
+				break;
+			case "recruitment":
+				campaign = 'militia recruitment';
+				modifier = forcedViewing ? 1.2 : 1.15;
+				adjut = 650;
+				if (noRecuriter) {
+					targetVariable *= (forcedViewing ? 1.1 : 1.05) * modifier;
+				}
+				break;
+		}
+
+		let t = `<span class='green'>Your propaganda campaign helps further your ${campaign} efforts.`;
+		if (V.SecExp.buildings.propHub.recruiterOffice && V.RecruiterID > 0) {
+			const {his} = getPronouns(S.Recruiter);
+			t += ` <span class='slave-name'>${SlaveFullName(S.Recruiter)}</span> is able to further boost your ${campaign} campaign from ${his} PR hub office.`;
+			targetVariable += modifier + Math.floor((S.Recruiter.intelligence+S.Recruiter.intelligenceImplant)/adjut);
+		}
+		return t + `</span>`;
+	}
+}
+
 /**
  * Returns the raw percetnage of socity that can be drafted.
  */
diff --git a/src/Mods/SecExp/securityReport.tw b/src/Mods/SecExp/securityReport.tw
index c3131f44fb802dfd3cf21908614eef81e530c585..58d2d4fdb046916ff5124bedc2010c0eb8e1e748 100644
--- a/src/Mods/SecExp/securityReport.tw
+++ b/src/Mods/SecExp/securityReport.tw
@@ -342,25 +342,7 @@ Due to the deterioration of the old world countries, organized crime focuses mor
 			Having a powerful special force attracts a lot of citizens, hopeful that they may be able to fight along side it.
 			<<set _recruitsMultiplier *= 1 + (random(1, (Math.round(_size / 10))) / 20)>> /* not sure how high _size goes, so I hope this makes sense */
 		<</if>>
-		<<if $SecExp.buildings.propHub>>
-			<<if $SecExp.buildings.propHub.campaign >= 1 && $SecExp.buildings.propHub.focus == "recruitment">>
-				<<if $SecExp.buildings.propHub.recruiterOffice === 0 || $RecruiterID == 0>>
-					<<if $SecExp.edicts.propCampaignBoost == 1>>
-						<<set _recruitsMultiplier *= 1.1>>
-					<<else>>
-						<<set _recruitsMultiplier *= 1.05>>
-					<</if>>
-				<<elseif $SecExp.buildings.propHub.recruiterOffice > 0 && $RecruiterID > 0>>
-					<<setLocalPronouns _S.Recruiter>>
-					<span class='slave-name'><<= SlaveFullName(_S.Recruiter)>></span> is able to further boost your militia recruitment campaign from $his PR hub office.
-					<<if $SecExp.edicts.propCampaignBoost == 1>>
-						<<set _recruitsMultiplier *= 1.2 + ((_S.Recruiter.intelligence+_S.Recruiter.intelligenceImplant)/650)>>
-					<<else>>
-						<<set _recruitsMultiplier *= 1.15 + ((_S.Recruiter.intelligence+_S.Recruiter.intelligenceImplant)/650)>>
-					<</if>>
-				<</if>>
-			<</if>>
-		<</if>>
+		<<= App.SecExp.propagandaEffects("recruitment", _recruitsMultiplier)>>
 		<<if $SecExp.edicts.defense.militia === 2>>
 			Your militia accepts only volunteering citizens, ready to defend their arcology.
 			<<set _recruitLimit = App.SecExp.militiaCap(), _adjst = 0.0025>>
diff --git a/src/uncategorized/fsDevelopments.tw b/src/uncategorized/fsDevelopments.tw
index 038c0abc7859b3edd3e41eaaa41414935d96a851..4fd710fec16e6948a3a2f813db8839570a5a05d9 100644
--- a/src/uncategorized/fsDevelopments.tw
+++ b/src/uncategorized/fsDevelopments.tw
@@ -74,24 +74,7 @@
 <</if>>
 
 <<if $secExpEnabled > 0>>
-	<<if $SecExp.buildings.propHub && $SecExp.buildings.propHub.campaign >= 1 && $SecExp.buildings.propHub.focus == "social engineering">>
-		Your propaganda campaign helps further your societal engineering efforts.
-		<<if $SecExp.buildings.propHub.recruiterOffice == 0 || $RecruiterID == 0>>
-			<<if $SecExp.edicts.propCampaignBoost == 1>>
-				<<set _broadProgress += 2>>
-			<<else>>
-				<<set _broadProgress += 1>>
-			<</if>>
-		<<elseif $SecExp.buildings.propHub.recruiterOffice && $RecruiterID > 0>>
-			<<setLocalPronouns _S.Recruiter>>
-			<span class='slave-name'><<= SlaveFullName(_S.Recruiter)>></span> is able to further boost your societal engineering campaign from $his PR hub office.
-			<<if $SecExp.edicts.propCampaignBoost == 1>>
-				<<set _broadProgress += $SecExp.buildings.propHub.upgrades.campaign + Math.floor((_S.Recruiter.intelligence+_S.Recruiter.intelligenceImplant)/32)>>
-			<<else>>
-				<<set _broadProgress += 1 + Math.floor((_S.Recruiter.intelligence+_S.Recruiter.intelligenceImplant)/32)>>
-			<</if>>
-		<</if>>
-	<</if>>
+	<<= App.SecExp.propagandaEffects("social engineering", _broadProgress)>>
 <</if>>
 
 <<if $terrain == "urban">>