diff --git a/src/endWeek/economics/arcmgmt.js b/src/endWeek/economics/arcmgmt.js
index 02910c5dc4665d3b7ce0a17088d058990da2859e..b90325bf7d02e81d38cf7547baba9056a611c8e5 100644
--- a/src/endWeek/economics/arcmgmt.js
+++ b/src/endWeek/economics/arcmgmt.js
@@ -560,12 +560,12 @@ App.EndWeek.arcManagement = function() {
 
 		let _desc = [];
 		let _descNeg = [];
-		for (let i = 1; i < V.arcologies.length; i++) {
-			const _opinion = App.Neighbor.opinion(0, i);
+		for (const arcology of V.arcologies) {
+			const _opinion = App.Neighbor.opinion(V.arcologies[0], arcology);
 			if (_opinion >= 100) {
-				_desc.push(V.arcologies[i].name);
+				_desc.push(arcology.name);
 			} else if (_opinion <= -100) {
-				_descNeg.push(V.arcologies[i].name);
+				_descNeg.push(arcology.name);
 			}
 		}
 		if (_desc.length > 0) {
diff --git a/src/endWeek/economics/fsDevelopments.js b/src/endWeek/economics/fsDevelopments.js
index e00f7de439de984c37076c5dbb05ae5c4b7b6524..a2eb6a00cc79edb6cd656193f3c0a121e2f0558b 100644
--- a/src/endWeek/economics/fsDevelopments.js
+++ b/src/endWeek/economics/fsDevelopments.js
@@ -28,7 +28,7 @@ App.EndWeek.FSDevelopments = function() {
 	}
 
 	/* Count adopted FS */
-	let societies = FutureSocieties.activeCount(0);
+	const societies = FutureSocieties.activeCount(V.arcologies[0]);
 
 	/* Spending, terrain, rep effects */
 	let broadProgress = 0;
diff --git a/src/endWeek/economics/neighborsDevelopment.js b/src/endWeek/economics/neighborsDevelopment.js
index bbd42ad2bee50eddb55ec4802bd64c13fb2bcfad..b34c0024e207edb7cdaf7128ea3c3da83630eedb 100644
--- a/src/endWeek/economics/neighborsDevelopment.js
+++ b/src/endWeek/economics/neighborsDevelopment.js
@@ -7,7 +7,6 @@ App.EndWeek.neighborsDevelopment = function() {
 	const averageProsperity = _.mean(V.arcologies.map(a => a.prosperity));
 	const corpBonus = V.corp.Incorporated ? Math.trunc(1000 * Math.pow(App.Corporate.value, 0.1)) : 0;
 	let agentBonusValue = 0;
-	let desc;
 
 	if (V.useTabs === 0) {
 		App.UI.DOM.appendNewElement("h2", el, `Arcologies in the Free City`);
@@ -200,13 +199,13 @@ App.EndWeek.neighborsDevelopment = function() {
 						r.push(`Its direct democracy votes to empower some elected officials in the hope they can lead the arcology out of its problems.`);
 						arc.government = "elected officials";
 				}
-				desc = FutureSocieties.decay(i).map((fs) => FutureSocieties.displayName(fs));
-				if (desc.length > 2) {
-					r.push(`Its citizens take the opportunity to make radical social changes, <span class="cyan">purging the ${arrayToSentence(desc)}</span> favored by the old government.`);
-				} else if (desc.length === 2) {
-					r.push(`Its citizens take the opportunity to make social changes, <span class="cyan">discarding the ${desc[0]} and ${desc[1]}</span> favored by the old government.`);
-				} else if (desc.length === 1) {
-					r.push(`Its citizens take the opportunity to make social change and <span class="cyan">abandon the ${desc[0]}</span> favored by the old government.`);
+				const decayedFSes = FutureSocieties.decay(i).map((fs) => FutureSocieties.displayName(fs));
+				if (decayedFSes.length > 2) {
+					r.push(`Its citizens take the opportunity to make radical social changes, <span class="cyan">purging the ${arrayToSentence(decayedFSes)}</span> favored by the old government.`);
+				} else if (decayedFSes.length === 2) {
+					r.push(`Its citizens take the opportunity to make social changes, <span class="cyan">discarding the ${decayedFSes[0]} and ${decayedFSes[1]}</span> favored by the old government.`);
+				} else if (decayedFSes.length === 1) {
+					r.push(`Its citizens take the opportunity to make social change and <span class="cyan">abandon the ${decayedFSes[0]}</span> favored by the old government.`);
 				}
 			} else {
 				r.push(`The arcology is paralyzed by internal dissension over how to respond.`);
@@ -417,7 +416,7 @@ App.EndWeek.neighborsDevelopment = function() {
 
 		/* FUTURE SOCIETY PROGRESS */
 
-		const societiesAdopted = FutureSocieties.activeCount(i);
+		const societiesAdopted = FutureSocieties.activeCount(arc);
 		let efficiency;
 		switch (arc.government) {
 			case "elected officials":
@@ -1434,483 +1433,54 @@ App.EndWeek.neighborsDevelopment = function() {
 					if (arc.ownership >= 100) {
 						appliedInfluenceBonus /= 2;
 					}
-					desc = [];
-					let alignment = 0;
 
-					if (arc2.FSSubjugationist !== "unset" && arc2.FSSubjugationist > 60) {
-						if (arc.FSSubjugationist !== "unset") {
-							if (arc2.FSSubjugationistRace === arc.FSSubjugationistRace) {
-								arc.FSSubjugationist += Math.trunc((arc2.FSSubjugationist - 60) / 4) + appliedInfluenceBonus;
-								if (arc.FSSubjugationist > V.FSLockinLevel) {
-									alignment += 1;
-								}
-								desc.push("helping to advance its racially aligned Subjugationism");
-							} else {
-								arc.FSSubjugationist -= Math.trunc((arc2.FSSubjugationist - 60) / 4) + appliedInfluenceBonus;
-								desc.push("attacking its incompatible Subjugationism");
-							}
-						} else if ((arc.FSSupremacist !== "unset") && (arc2.FSSubjugationistRace === arc.FSSupremacistRace)) {
-							arc.FSSupremacist -= Math.trunc((arc2.FSSubjugationist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its opposing Supremacism");
-						}
-					}
-					if (arc2.FSSupremacist !== "unset" && arc2.FSSupremacist > 60) {
-						if (arc.FSSupremacist !== "unset") {
-							if (arc2.FSSupremacistRace === arc.FSSupremacistRace) {
-								arc.FSSupremacist += Math.trunc((arc2.FSSupremacist - 60) / 4) + appliedInfluenceBonus;
-								if (arc.FSSupremacist > V.FSLockinLevel) {
-									alignment += 1;
-								}
-								desc.push("helping to advance its racially aligned Supremacism");
-							} else {
-								arc.FSSupremacist -= Math.trunc((arc2.FSSupremacist - 60) / 4) + appliedInfluenceBonus;
-								desc.push("attacking its incompatible Supremacism");
-							}
-						} else if ((arc.FSSubjugationist !== "unset") && (arc2.FSSupremacistRace === arc.FSSubjugationistRace)) {
-							arc.FSSubjugationist -= Math.trunc((arc2.FSSupremacist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its opposing Subjugationism");
-						}
-					}
-					if (arc2.FSRepopulationFocus !== "unset" && arc2.FSRepopulationFocus > 60) {
-						if (arc.FSRepopulationFocus !== "unset") {
-							arc.FSRepopulationFocus += Math.trunc((arc2.FSRepopulationFocus - 60) / 4) + appliedInfluenceBonus;
-							if (arc.FSRepopulationFocus > V.FSLockinLevel) {
-								alignment += 1;
-							}
-							desc.push("helping to advance its Repopulationism");
-						} else if (arc.FSRestart !== "unset") {
-							arc.FSRestart -= Math.trunc((arc2.FSRepopulationFocus - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its Eugenics");
-						}
-					} else if (arc2.FSRestart !== "unset" && arc2.FSRestart > 60) {
-						if (arc.FSRestart !== "unset") {
-							arc.FSRestart += Math.trunc((arc2.FSRestart - 60) / 4) + appliedInfluenceBonus;
-							if (arc.FSRestart > V.FSLockinLevel) {
-								alignment += 1;
-							}
-							desc.push("helping to advance its Eugenics");
-						} else if (arc.FSRepopulationFocus !== "unset") {
-							arc.FSRepopulationFocus -= Math.trunc((arc2.FSRestart - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its Repopulation Efforts");
-						}
-					}
-					if (arc2.FSGenderRadicalist !== "unset" && arc2.FSGenderRadicalist > 60) {
-						if (arc.FSGenderRadicalist !== "unset") {
-							arc.FSGenderRadicalist += Math.trunc((arc2.FSGenderRadicalist - 60) / 4) + appliedInfluenceBonus;
-							if (arc.FSGenderRadicalist > V.FSLockinLevel) {
-								alignment += 1;
-							}
-							desc.push("helping to advance its Gender Radicalism");
-						} else if (arc.FSGenderFundamentalist !== "unset") {
-							arc.FSGenderFundamentalist -= Math.trunc((arc2.FSGenderRadicalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its Gender Fundamentalism");
-						}
-					} else if (arc2.FSGenderFundamentalist !== "unset" && arc2.FSGenderFundamentalist > 60) {
-						if (arc.FSGenderFundamentalist !== "unset") {
-							arc.FSGenderFundamentalist += Math.trunc((arc2.FSGenderFundamentalist - 60) / 4) + appliedInfluenceBonus;
-							if (arc.FSGenderFundamentalist > V.FSLockinLevel) {
-								alignment += 1;
-							}
-							desc.push("helping to advance its Gender Fundamentalism");
-						} else if (arc.FSGenderRadicalist !== "unset") {
-							arc.FSGenderRadicalist -= Math.trunc((arc2.FSGenderFundamentalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its Gender Radicalism");
-						}
-					}
-					if (arc2.FSPaternalist !== "unset" && arc2.FSPaternalist > 60) {
-						if (arc.FSPaternalist !== "unset") {
-							arc.FSPaternalist += Math.trunc((arc2.FSPaternalist - 60) / 4) + appliedInfluenceBonus;
-							if (arc.FSPaternalist > V.FSLockinLevel) {
-								alignment += 1;
-							}
-							desc.push("helping to advance its Paternalism");
-						} else if (arc.FSDegradationist !== "unset") {
-							arc.FSDegradationist -= Math.trunc((arc2.FSPaternalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its Degradationism");
-						}
-					} else if (arc2.FSDegradationist !== "unset" && arc2.FSDegradationist > 60) {
-						if (arc.FSDegradationist !== "unset") {
-							arc.FSDegradationist += Math.trunc((arc2.FSDegradationist - 60) / 4) + appliedInfluenceBonus;
-							if (arc.FSDegradationist > V.FSLockinLevel) {
-								alignment += 1;
-							}
-							desc.push("helping to advance its Degradationism");
-						} else if (arc.FSPaternalist !== "unset") {
-							arc.FSPaternalist -= Math.trunc((arc2.FSDegradationist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its Paternalism");
-						}
-					}
-					if (arc2.FSIntellectualDependency !== "unset" && arc2.FSIntellectualDependency > 60) {
-						if (arc.FSIntellectualDependency !== "unset") {
-							arc.FSIntellectualDependency += Math.trunc((arc2.FSIntellectualDependency - 60) / 4) + appliedInfluenceBonus;
-							if (arc.FSIntellectualDependency > V.FSLockinLevel) {
-								alignment += 1;
-							}
-							desc.push("helping to advance its Intellectual Dependency");
-						} else if (arc.FSSlaveProfessionalism !== "unset") {
-							arc.FSSlaveProfessionalism -= Math.trunc((arc2.FSIntellectualDependency - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its Slave Professionalism");
-						}
-					} else if (arc2.FSSlaveProfessionalism !== "unset" && arc2.FSSlaveProfessionalism > 60) {
-						if (arc.FSSlaveProfessionalism !== "unset") {
-							arc.FSSlaveProfessionalism += Math.trunc((arc2.FSSlaveProfessionalism - 60) / 4) + appliedInfluenceBonus;
-							if (arc.FSSlaveProfessionalism > V.FSLockinLevel) {
-								alignment += 1;
-							}
-							desc.push("helping to advance its Slave Professionalism");
-						} else if (arc.FSIntellectualDependency !== "unset") {
-							arc.FSIntellectualDependency -= Math.trunc((arc2.FSSlaveProfessionalism - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its Intellectual Dependency");
-						}
-					}
-					if (arc2.FSBodyPurist !== "unset" && arc2.FSBodyPurist > 60) {
-						if (arc.FSBodyPurist !== "unset") {
-							arc.FSBodyPurist += Math.trunc((arc2.FSBodyPurist - 60) / 4) + appliedInfluenceBonus;
-							if (arc.FSBodyPurist > V.FSLockinLevel) {
-								alignment += 1;
-							}
-							desc.push("helping to advance its Body Purism");
-						} else if (arc.FSTransformationFetishist !== "unset") {
-							arc.FSTransformationFetishist -= Math.trunc((arc2.FSBodyPurist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its Transformation Fetishism");
-						}
-					} else if (arc2.FSTransformationFetishist !== "unset" && arc2.FSTransformationFetishist > 60) {
-						if (arc.FSTransformationFetishist !== "unset") {
-							arc.FSTransformationFetishist += Math.trunc((arc2.FSTransformationFetishist - 60) / 4) + appliedInfluenceBonus;
-							if (arc.FSTransformationFetishist > V.FSLockinLevel) {
-								alignment += 1;
-							}
-							desc.push("helping to advance its Transformation Fetishism");
-						} else if (arc.FSBodyPurist !== "unset") {
-							arc.FSBodyPurist -= Math.trunc((arc2.FSTransformationFetishist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its Body Purism");
-						}
-					}
-					if (arc2.FSYouthPreferentialist !== "unset" && arc2.FSYouthPreferentialist > 60) {
-						if (arc.FSYouthPreferentialist !== "unset") {
-							arc.FSYouthPreferentialist += Math.trunc((arc2.FSYouthPreferentialist - 60) / 4) + appliedInfluenceBonus;
-							if (arc.FSYouthPreferentialist > V.FSLockinLevel) {
-								alignment += 1;
-							}
-							desc.push("helping to advance its Youth Preferentialism");
-						} else if (arc.FSMaturityPreferentialist !== "unset") {
-							arc.FSMaturityPreferentialist -= Math.trunc((arc2.FSYouthPreferentialist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its Maturity Preferentialism");
-						}
-					} else if (arc2.FSMaturityPreferentialist !== "unset" && arc2.FSMaturityPreferentialist > 60) {
-						if (arc.FSMaturityPreferentialist !== "unset") {
-							arc.FSMaturityPreferentialist += Math.trunc((arc2.FSMaturityPreferentialist - 60) / 4) + appliedInfluenceBonus;
-							if (arc.FSMaturityPreferentialist > V.FSLockinLevel) {
-								alignment += 1;
-							}
-							desc.push("helping to advance its Maturity Preferentialism");
-						} else if (arc.FSYouthPreferentialist !== "unset") {
-							arc.FSYouthPreferentialist -= Math.trunc((arc2.FSMaturityPreferentialist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its Youth Preferentialism");
-						}
-					}
-					if (arc2.FSPetiteAdmiration !== "unset" && arc2.FSPetiteAdmiration > 60) {
-						if (arc.FSPetiteAdmiration !== "unset") {
-							arc.FSPetiteAdmiration += Math.trunc((arc2.FSPetiteAdmiration - 60) / 4) + appliedInfluenceBonus;
-							if (arc.FSPetiteAdmiration > V.FSLockinLevel) {
-								alignment += 1;
-							}
-							desc.push("helping to advance its Petite Admiration");
-						} else if (arc.FSStatuesqueGlorification !== "unset") {
-							arc.FSStatuesqueGlorification -= Math.trunc((arc2.FSPetiteAdmiration - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its Statuesque Glorification");
-						}
-					} else if (arc2.FSStatuesqueGlorification !== "unset" && arc2.FSStatuesqueGlorification > 60) {
-						if (arc.FSStatuesqueGlorification !== "unset") {
-							arc.FSStatuesqueGlorification += Math.trunc((arc2.FSStatuesqueGlorification - 60) / 4) + appliedInfluenceBonus;
-							if (arc.FSStatuesqueGlorification > V.FSLockinLevel) {
-								alignment += 1;
-							}
-							desc.push("helping to advance its Statuesque Glorification");
-						} else if (arc.FSPetiteAdmiration !== "unset") {
-							arc.FSPetiteAdmiration -= Math.trunc((arc2.FSStatuesqueGlorification - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its Petite Admiration");
-						}
-					}
-					if (arc2.FSSlimnessEnthusiast !== "unset" && arc2.FSSlimnessEnthusiast > 60) {
-						if (arc.FSSlimnessEnthusiast !== "unset") {
-							arc.FSSlimnessEnthusiast += Math.trunc((arc2.FSSlimnessEnthusiast - 60) / 4) + appliedInfluenceBonus;
-							if (arc.FSSlimnessEnthusiast > V.FSLockinLevel) {
-								alignment += 1;
-							}
-							desc.push("helping to advance its Slimness Enthusiasm");
-						} else if (arc.FSAssetExpansionist !== "unset") {
-							arc.FSAssetExpansionist -= Math.trunc((arc2.FSSlimnessEnthusiast - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its Asset Expansionism");
-						}
-					} else if (arc2.FSAssetExpansionist !== "unset" && arc2.FSAssetExpansionist > 60) {
-						if (arc.FSAssetExpansionist !== "unset") {
-							arc.FSAssetExpansionist += Math.trunc((arc2.FSAssetExpansionist - 60) / 4) + appliedInfluenceBonus;
-							if (arc.FSAssetExpansionist > V.FSLockinLevel) {
-								alignment += 1;
-							}
-							desc.push("helping to advance its Asset Expansionism");
-						} else if (arc.FSSlimnessEnthusiast !== "unset") {
-							arc.FSSlimnessEnthusiast -= Math.trunc((arc2.FSAssetExpansionist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its Slimness Enthusiasm");
-						}
-					}
-					if (arc2.FSPastoralist !== "unset" && arc2.FSPastoralist > 60) {
-						if (arc.FSPastoralist !== "unset") {
-							arc.FSPastoralist += Math.trunc((arc2.FSPastoralist - 60) / 4) + appliedInfluenceBonus;
-							if (arc.FSPastoralist > V.FSLockinLevel) {
-								alignment += 1;
-							}
-							desc.push("helping to advance its Pastoralism");
-						} else if (arc.FSCummunism !== "unset") {
-							arc.FSCummunism -= Math.trunc((arc2.FSPastoralist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its Cummunism");
-						}
-					} else if (arc2.FSCummunism !== "unset" && arc2.FSCummunism > 60) {
-						if (arc.FSCummunism !== "unset") {
-							arc.FSCummunism += Math.trunc((arc2.FSCummunism - 60) / 4) + appliedInfluenceBonus;
-							if (arc.FSCummunism > V.FSLockinLevel) {
-								alignment += 1;
-							}
-							desc.push("helping to advance its Cummunism");
-						} else if (arc.FSPastoralist !== "unset") {
-							arc.FSPastoralist -= Math.trunc((arc2.FSCummunism - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its Pastoralism");
-						}
-					}
-					if (arc2.FSPhysicalIdealist !== "unset" && arc2.FSPhysicalIdealist > 60) {
-						if (arc.FSPhysicalIdealist !== "unset") {
-							arc.FSPhysicalIdealist += Math.trunc((arc2.FSPhysicalIdealist - 60) / 4) + appliedInfluenceBonus;
-							if (arc.FSPhysicalIdealist > V.FSLockinLevel) {
-								alignment += 1;
-							}
-							desc.push("helping to advance its Physical Idealism");
-						} else if (arc.FSHedonisticDecadence !== "unset") {
-							arc.FSHedonisticDecadence -= Math.trunc((arc2.FSPhysicalIdealist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its Hedonism");
-						}
-					} else if (arc2.FSHedonisticDecadence !== "unset" && arc2.FSHedonisticDecadence > 60) {
-						if (arc.FSHedonisticDecadence !== "unset") {
-							arc.FSHedonisticDecadence += Math.trunc((arc2.FSHedonisticDecadence - 60) / 4) + appliedInfluenceBonus;
-							if (arc.FSHedonisticDecadence > V.FSLockinLevel) {
-								alignment += 1;
-							}
-							desc.push("helping to advance its Hedonism");
-						} else if (arc.FSPhysicalIdealist !== "unset") {
-							arc.FSPhysicalIdealist -= Math.trunc((arc2.FSHedonisticDecadence - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its Physical Idealism");
-						}
-					}
-					if (arc2.FSIncestFetishist !== "unset" && arc2.FSIncestFetishist > 60) {
-						if (arc.FSIncestFetishist !== "unset") {
-							arc.FSIncestFetishist += Math.trunc((arc2.FSIncestFetishist - 60) / 4) + appliedInfluenceBonus;
-							if (arc.FSIncestFetishist > V.FSLockinLevel) {
+					let alignment = 0;
+					let helping = [], attacking = [];
+					const dipFSes = FutureSocieties.diplomaticFSes(arc, arc2);
+					for (const sharedFS of dipFSes.shared) {
+						if (arc2[sharedFS] > 60) {
+							arc[sharedFS] += Math.trunc((arc2[sharedFS] - 60) / 4) + appliedInfluenceBonus;
+							if (arc[sharedFS] > V.FSLockinLevel) {
 								alignment += 1;
 							}
-							desc.push("helping to advance its Incest Fetishism");
-						}
-					}
-					if (arc2.FSChattelReligionist !== "unset" && arc2.FSChattelReligionist > 60) {
-						if (arc.FSChattelReligionist !== "unset") {
-							arc.FSChattelReligionist += Math.trunc((arc2.FSChattelReligionist - 60) / 4) + appliedInfluenceBonus;
-							if (arc.FSChattelReligionist > V.FSLockinLevel) {
-								alignment += 1;
+							if (sharedFS === "FSSubjugationist") {
+								helping.push("racially aligned Subjugationism");
+							} else if (sharedFS === "FSSupremacist") {
+								helping.push("racially aligned Supremacism");
+							} else {
+								helping.push(FutureSocieties.displayName(sharedFS));
 							}
-							desc.push("helping to advance its Chattel Religionism");
 						}
 					}
-					if (arc2.FSRomanRevivalist !== "unset" && arc2.FSRomanRevivalist > 60) {
-						if (arc.FSRomanRevivalist !== "unset") {
-							arc.FSRomanRevivalist += Math.trunc((arc2.FSRomanRevivalist - 60) / 4) + appliedInfluenceBonus;
-							if (arc.FSRomanRevivalist > V.FSLockinLevel) {
-								alignment += 1;
-							}
-							desc.push("helping to advance its Roman Revivalism");
-						} else if (arc.FSNeoImperialist !== "unset") {
-							arc.FSNeoImperialist -= Math.trunc((arc2.FSRomanRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Imperialism");
-						} else if (arc.FSAztecRevivalist !== "unset") {
-							arc.FSAztecRevivalist -= Math.trunc((arc2.FSRomanRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						} else if (arc.FSEgyptianRevivalist !== "unset") {
-							arc.FSEgyptianRevivalist -= Math.trunc((arc2.FSRomanRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						} else if (arc.FSEdoRevivalist !== "unset") {
-							arc.FSEdoRevivalist -= Math.trunc((arc2.FSRomanRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						} else if (arc.FSArabianRevivalist !== "unset") {
-							arc.FSArabianRevivalist -= Math.trunc((arc2.FSRomanRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						} else if (arc.FSChineseRevivalist !== "unset") {
-							arc.FSChineseRevivalist -= Math.trunc((arc2.FSRomanRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						}
-					} else if (arc2.FSAztecRevivalist !== "unset" && arc2.FSAztecRevivalist > 60) {
-						if (arc.FSAztecRevivalist !== "unset") {
-							arc.FSAztecRevivalist += Math.trunc((arc2.FSAztecRevivalist - 60) / 4) + appliedInfluenceBonus;
-							if (arc.FSAztecRevivalist > V.FSLockinLevel) {
-								alignment += 1;
-							}
-							desc.push("helping to advance its Aztec Revivalism");
-						} else if (arc.FSNeoImperialist !== "unset") {
-							arc.FSNeoImperialist -= Math.trunc((arc2.FSAztecRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Imperialism");
-						} else if (arc.FSRomanRevivalist !== "unset") {
-							arc.FSRomanRevivalist -= Math.trunc((arc2.FSAztecRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						} else if (arc.FSEgyptianRevivalist !== "unset") {
-							arc.FSEgyptianRevivalist -= Math.trunc((arc2.FSAztecRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						} else if (arc.FSEdoRevivalist !== "unset") {
-							arc.FSEdoRevivalist -= Math.trunc((arc2.FSAztecRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						} else if (arc.FSArabianRevivalist !== "unset") {
-							arc.FSArabianRevivalist -= Math.trunc((arc2.FSAztecRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						} else if (arc.FSChineseRevivalist !== "unset") {
-							arc.FSChineseRevivalist -= Math.trunc((arc2.FSAztecRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						}
-					} else if (arc2.FSEgyptianRevivalist !== "unset" && arc2.FSEgyptianRevivalist > 60) {
-						if (arc.FSEgyptianRevivalist !== "unset") {
-							arc.FSEgyptianRevivalist += Math.trunc((arc2.FSEgyptianRevivalist - 60) / 4) + appliedInfluenceBonus;
-							if (arc.FSEgyptianRevivalist > V.FSLockinLevel) {
-								alignment += 1;
-							}
-							desc.push("helping to advance its Egyptian Revivalism");
-						} else if (arc.FSRomanRevivalist !== "unset") {
-							arc.FSRomanRevivalist -= Math.trunc((arc2.FSEgyptianRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						} else if (arc.FSNeoImperialist !== "unset") {
-							arc.FSNeoImperialist -= Math.trunc((arc2.FSEgyptianRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Imperialism");
-						} else if (arc.FSAztecRevivalist !== "unset") {
-							arc.FSAztecRevivalist -= Math.trunc((arc2.FSEgyptianRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						} else if (arc.FSEdoRevivalist !== "unset") {
-							arc.FSEdoRevivalist -= Math.trunc((arc2.FSEgyptianRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						} else if (arc.FSArabianRevivalist !== "unset") {
-							arc.FSArabianRevivalist -= Math.trunc((arc2.FSEgyptianRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						} else if (arc.FSChineseRevivalist !== "unset") {
-							arc.FSChineseRevivalist -= Math.trunc((arc2.FSEgyptianRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						}
-					} else if (arc2.FSEdoRevivalist !== "unset" && arc2.FSEdoRevivalist > 60) {
-						if (arc.FSEdoRevivalist !== "unset") {
-							arc.FSEdoRevivalist += Math.trunc((arc2.FSEdoRevivalist - 60) / 4) + appliedInfluenceBonus;
-							if (arc.FSEdoRevivalist > V.FSLockinLevel) {
-								alignment += 1;
-							}
-							desc.push("helping to advance its Edo Revivalism");
-						} else if (arc.FSEgyptianRevivalist !== "unset") {
-							arc.FSEgyptianRevivalist -= Math.trunc((arc2.FSEdoRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						} else if (arc.FSNeoImperialist !== "unset") {
-							arc.FSNeoImperialist -= Math.trunc((arc2.FSEdoRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Imperialism");
-						} else if (arc.FSRomanRevivalist !== "unset") {
-							arc.FSRomanRevivalist -= Math.trunc((arc2.FSEdoRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						} else if (arc.FSAztecRevivalist !== "unset") {
-							arc.FSAztecRevivalist -= Math.trunc((arc2.FSEdoRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						} else if (arc.FSArabianRevivalist !== "unset") {
-							arc.FSArabianRevivalist -= Math.trunc((arc2.FSEdoRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						} else if (arc.FSChineseRevivalist !== "unset") {
-							arc.FSChineseRevivalist -= Math.trunc((arc2.FSEdoRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						}
-					} else if (arc2.FSArabianRevivalist !== "unset" && arc2.FSArabianRevivalist > 60) {
-						if (arc.FSArabianRevivalist !== "unset") {
-							arc.FSArabianRevivalist += Math.trunc((arc2.FSArabianRevivalist - 60) / 4) + appliedInfluenceBonus;
-							if (arc.FSArabianRevivalist > V.FSLockinLevel) {
-								alignment += 1;
-							}
-							desc.push("helping to advance its Arabian Revivalism");
-						} else if (arc.FSEgyptianRevivalist !== "unset") {
-							arc.FSEgyptianRevivalist -= Math.trunc((arc2.FSArabianRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						} else if (arc.FSNeoImperialist !== "unset") {
-							arc.FSNeoImperialist -= Math.trunc((arc2.FSArabianRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Imperialism");
-						} else if (arc.FSEdoRevivalist !== "unset") {
-							arc.FSEdoRevivalist -= Math.trunc((arc2.FSArabianRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						} else if (arc.FSRomanRevivalist !== "unset") {
-							arc.FSRomanRevivalist -= Math.trunc((arc2.FSArabianRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						} else if (arc.FSAztecRevivalist !== "unset") {
-							arc.FSAztecRevivalist -= Math.trunc((arc2.FSArabianRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						} else if (arc.FSChineseRevivalist !== "unset") {
-							arc.FSChineseRevivalist -= Math.trunc((arc2.FSArabianRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						}
-					} else if (arc2.FSChineseRevivalist !== "unset" && arc2.FSChineseRevivalist > 60) {
-						if (arc.FSChineseRevivalist !== "unset") {
-							arc.FSChineseRevivalist += Math.trunc((arc2.FSChineseRevivalist - 60) / 4) + appliedInfluenceBonus;
-							if (arc.FSChineseRevivalist > V.FSLockinLevel) {
-								alignment += 1;
-							}
-							desc.push("helping to advance its Chinese Revivalism");
-						} else if (arc.FSEgyptianRevivalist !== "unset") {
-							arc.FSEgyptianRevivalist -= Math.trunc((arc2.FSChineseRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						} else if (arc.FSNeoImperialist !== "unset") {
-							arc.FSNeoImperialist -= Math.trunc((arc2.FSChineseRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Imperialism");
-						} else if (arc.FSEdoRevivalist !== "unset") {
-							arc.FSEdoRevivalist -= Math.trunc((arc2.FSChineseRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						} else if (arc.FSArabianRevivalist !== "unset") {
-							arc.FSArabianRevivalist -= Math.trunc((arc2.FSChineseRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						} else if (arc.FSRomanRevivalist !== "unset") {
-							arc.FSRomanRevivalist -= Math.trunc((arc2.FSChineseRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						} else if (arc.FSAztecRevivalist !== "unset") {
-							arc.FSAztecRevivalist -= Math.trunc((arc2.FSChineseRevivalist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						}
-					} else if (arc2.FSNeoImperialist !== "unset" && arc2.FSNeoImperialist > 60) {
-						if (arc.FSNeoImperialist !== "unset") {
-							arc.FSNeoImperialist += Math.trunc((arc2.FSNeoImperialist - 60) / 4) + appliedInfluenceBonus;
-							if (arc.FSNeoImperialist > V.FSLockinLevel) {
-								alignment += 1;
+					for (const [arcFS, arc2FS] of dipFSes.conflicting) {
+						if (arc2[arc2FS] > 60) {
+							arc[arcFS] -= Math.trunc((arc2[arc2FS] - 60) / 4) + appliedInfluenceBonus;
+							if (arcFS === "FSSubjugationist" && arc2FS === "FSSupremacist") {
+								attacking.push("opposing Subjugationism");
+							} else if (arcFS === "FSSupremacist" && arc2FS === "FSSubjugationist") {
+								attacking.push("opposing Supremacism");
+							} else if (arcFS === "FSSubjugationist" && arc2FS === "FSSubjugationist") {
+								attacking.push("incompatible Subjugationism");
+							} else if (arcFS === "FSSupremacist" && arc2FS === "FSSupremacist") {
+								attacking.push("incompatible Supremacism");
+							} else if (arcFS.includes("Revivalism")) {
+								attacking.push("incompatible Revivalism");
+							} else if (arcFS.includes("Imperialism")) {
+								attacking.push("incompatible Imperialism");
+							} else {
+								attacking.push(FutureSocieties.displayName(arcFS));
 							}
-							desc.push("helping to advance its Neo-Imperialism");
-						} else if (arc.FSEgyptianRevivalist !== "unset") {
-							arc.FSEgyptianRevivalist -= Math.trunc((arc2.FSNeoImperialist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						} else if (arc.FSChineseRevivalist !== "unset") {
-							arc.FSChineseRevivalist -= Math.trunc((arc2.FSNeoImperialist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						} else if (arc.FSEdoRevivalist !== "unset") {
-							arc.FSEdoRevivalist -= Math.trunc((arc2.FSNeoImperialist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						} else if (arc.FSArabianRevivalist !== "unset") {
-							arc.FSArabianRevivalist -= Math.trunc((arc2.FSNeoImperialist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						} else if (arc.FSRomanRevivalist !== "unset") {
-							arc.FSRomanRevivalist -= Math.trunc((arc2.FSNeoImperialist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
-						} else if (arc.FSAztecRevivalist !== "unset") {
-							arc.FSAztecRevivalist -= Math.trunc((arc2.FSNeoImperialist - 60) / 4) + appliedInfluenceBonus;
-							desc.push("attacking its incompatible Revivalism");
 						}
 					}
 
-					if (desc.length === 0) {
+					if (helping.length === 0 && attacking.length === 0) {
 						r.push(`<span class="bold">${arc2.name}</span> attempts to influence it, but has no significant impacts.`);
-					} else if (desc.length > 2) {
-						r.push(`<span class="bold">${arc2.name}</span>'s mature culture influences ${arc.name}, ${desc.slice(0, desc.length - 1).join(', ') + ", and " + desc.slice(-1)}.`);
-					} else if (desc.length === 2) {
-						r.push(`<span class="bold">${arc2.name}</span>'s culture influences ${arc.name}'s ${desc[0]} and ${desc[1]}.`);
+					} else if (helping.length === 0) {
+						r.push(`<span class="bold">${arc2.name}</span>'s mature culture influences ${arc.name}, attacking its ${arrayToSentence(attacking)}.`);
+					} else if (attacking.length === 0) {
+						r.push(`<span class="bold">${arc2.name}</span>'s mature culture influences ${arc.name}, helping to advance its ${arrayToSentence(helping)}.`);
 					} else {
-						r.push(`<span class="bold">${arc2.name}</span>'s culture is beginning to influence ${arc.name}'s ${desc[0]}.`);
+						r.push(`<span class="bold">${arc2.name}</span>'s mature culture influences ${arc.name}, helping to advance its ${arrayToSentence(helping)}, while attacking its ${arrayToSentence(attacking)}.`);
 					}
 
 					if (appliedInfluenceBonus > 0) {
@@ -1928,7 +1498,7 @@ App.EndWeek.neighborsDevelopment = function() {
 					}
 
 					if (arc2.direction !== 0) {
-						if (desc.length === 0) {
+						if (helping.length === 0 && attacking.length === 0) {
 							r.push(`<span class="bold">${arc2.name}</span> is not satisfied with the impact its directed influence is having, and withdraws it with the intention of targeting it elsewhere.`);
 							arc2.influenceTarget = -1;
 						} else if (alignment >= 4) {
@@ -2066,7 +1636,7 @@ App.EndWeek.neighborsDevelopment = function() {
 				if (arc.government === "an individual") {
 					if (V.rivalryFSAdopted === 0) {
 						V.rivalryFSAdopted = 1;
-						desc = "Its owner is";
+						let desc = "Its owner is";
 						switch (V.rivalryFS) {
 							case "Racial Subjugationism":
 								if (arc.FSSubjugationist !== "unset") {
@@ -2375,7 +1945,7 @@ App.EndWeek.neighborsDevelopment = function() {
 								V.rivalryFSAdopted = 0;
 						}
 					} else { // RIVAL ADOPTION
-						desc = "Its owner is";
+						let desc = "Its owner is";
 						if (V.arcologies[0].FSSubjugationist > random(5, 60)) {
 							if (validFSes.includes("FSSupremacist") && (arc.FSSubjugationist === "unset") || (arc.FSSubjugationistRace !== V.arcologies[0].FSSubjugationistRace)) {
 								r.push(`${desc} preoccupied by belief in the superiority of the ${V.arcologies[0].FSSubjugationistRace} race, leading the arcology to <span class="yellow">adopt ${V.arcologies[0].FSSubjugationistRace} Supremacy.</span>`);
@@ -3140,10 +2710,8 @@ App.EndWeek.neighborsDevelopment = function() {
 				}
 			}
 
-
 			/* NEIGHBOR ADOPTION*/
-			for (let j = 0; j < V.arcologies.length; j++) {
-				const arc2 = V.arcologies[j];
+			for (const arc2 of V.arcologies) {
 				if (arc.direction !== arc2.direction) {
 					let influenceBonus = 0;
 					if (arc.direction === arc2.influenceTarget) {
@@ -3151,7 +2719,7 @@ App.EndWeek.neighborsDevelopment = function() {
 						influenceBonus = 20;
 					}
 
-					const opinion = App.Neighbor.opinion(i, j);
+					const opinion = App.Neighbor.opinion(arc, arc2);
 					if (opinion >= 50) {
 						r.push(`${arc.name} is aligned with ${arc2.name} socially, encouraging it to consider adopting all its cultural values.`);
 						influenceBonus += opinion - 50;
@@ -3192,6 +2760,7 @@ App.EndWeek.neighborsDevelopment = function() {
 
 			/* RANDOM ADOPTION*/
 			if (random(0, 4) === 1) {
+				let desc;
 				switch (arc.government) {
 					case "elected officials":
 						desc = "Its elected leaders are";
@@ -3215,11 +2784,9 @@ App.EndWeek.neighborsDevelopment = function() {
 					default:
 						desc = "Its citizens are";
 				}
-				let subjugationRace;
-				let supremacistRace;
 				switch (validFSes.random()) {
-					case "FSSubjugationist":
-						subjugationRace = setup.filterRacesLowercase.random();
+					case "FSSubjugationist": {
+						const subjugationRace = setup.filterRacesLowercase.random();
 						if ((arc.FSSupremacist === "unset") || (subjugationRace !== arc.FSSupremacistRace)) {
 							r.push(`${desc} preoccupied by a racial animus towards ${subjugationRace} people, leading the arcology to <span class="yellow">adopt ${subjugationRace} Subjugation.</span>`);
 							arc.FSSubjugationist = 5;
@@ -3227,8 +2794,9 @@ App.EndWeek.neighborsDevelopment = function() {
 							return;
 						}
 						break;
-					case "FSSupremacist":
-						supremacistRace = setup.filterRacesLowercase.random();
+					}
+					case "FSSupremacist": {
+						const supremacistRace = setup.filterRacesLowercase.random();
 						if ((arc.FSSubjugationist === "unset") || (supremacistRace !== arc.FSSubjugationistRace)) {
 							r.push(`${desc} preoccupied by belief in the superiority of the ${supremacistRace} race, leading the arcology to <span class="yellow">adopt ${supremacistRace} Supremacy.</span>`);
 							arc.FSSupremacist = 5;
@@ -3236,6 +2804,7 @@ App.EndWeek.neighborsDevelopment = function() {
 							return;
 						}
 						break;
+					}
 					case "FSGenderRadicalist":
 						r.push(`${desc} enthusiastic about fucking slaves in the butt, leading the arcology to <span class="yellow">adopt Gender Radicalism.</span>`);
 						arc.FSGenderRadicalist = 5;
diff --git a/src/js/futureSocietyJS.js b/src/js/futureSocietyJS.js
index e96505c2a2fcc7e35d2a594dbb24b6f2ade510fa..f22af60d1318367f568f36636062f27c97d223a8 100644
--- a/src/js/futureSocietyJS.js
+++ b/src/js/futureSocietyJS.js
@@ -115,21 +115,21 @@ globalThis.FutureSocieties = (function() {
 
 	/** get the list of FSes active for a particular arcology
 	 * helper function, not callable externally
-	 * @param {number} arcologyID
+	 * @param {FC.ArcologyState} arcology
 	 * @returns {FC.FutureSociety[]}
 	 */
-	function activeFSes(arcologyID) {
-		let isSet = (fs) => V.arcologies[arcologyID][fs] !== "unset";
-		const npcFSes = arcologyID !== 0 ? NPCSocietyList.filter(isSet) : [];
+	function activeFSes(arcology) {
+		let isSet = (fs) => arcology[fs] !== "unset";
+		const npcFSes = arcology.direction !== 0 ? NPCSocietyList.filter(isSet) : [];
 		return SocietyList.filter(isSet).concat(npcFSes);
 	}
 
-	/** call as FutureSocieties.activeCount(arcologyID)
-	 * @param {number} arcologyID
+	/** call as FutureSocieties.activeCount(arcology)
+	 * @param {FC.ArcologyState} arcology
 	 * @returns {number}
 	 */
-	function activeCount(arcologyID) {
-		return activeFSes(arcologyID).length;
+	function activeCount(arcology) {
+		return activeFSes(arcology).length;
 	}
 
 	/** call as FutureSocieties.applyBroadProgress(arcologyID, progress)
@@ -137,9 +137,10 @@ globalThis.FutureSocieties = (function() {
 	 * @param {number} progress
 	 */
 	function applyBroadProgress(arcologyID, progress) {
-		for (const fs of activeFSes(arcologyID)) {
+		const arcology = V.arcologies[arcologyID];
+		for (const fs of activeFSes(arcology)) {
 			if (fs !== "FSNull") { // does not progress this way
-				V.arcologies[arcologyID][fs] += progress;
+				arcology[fs] += progress;
 			}
 		}
 	}
@@ -150,7 +151,7 @@ globalThis.FutureSocieties = (function() {
 	 */
 	function overflowToInfluence(arcologyID) {
 		const arcology = V.arcologies[arcologyID];
-		for (const fs of activeFSes(arcologyID)) {
+		for (const fs of activeFSes(arcology)) {
 			if (fs !== "FSNull") { // no conventional progress
 				if (arcology[fs] > V.FSLockinLevel) {
 					arcology.influenceBonus += arcology[fs] - V.FSLockinLevel;
@@ -167,7 +168,7 @@ globalThis.FutureSocieties = (function() {
 	function influenceSources(arcologyID) {
 		let fses = [];
 		const arcology = V.arcologies[arcologyID];
-		for (const fs of activeFSes(arcologyID)) {
+		for (const fs of activeFSes(arcology)) {
 			if (fs !== "FSNull") { // no influence from Multiculturalism?
 				if (arcology[fs] > 60) {
 					fses.push(fs);
@@ -200,7 +201,7 @@ globalThis.FutureSocieties = (function() {
 	function validAdoptions(arcID) {
 		const arcology = V.arcologies[arcID];
 		const societies = Array.from(arcID === 0 ? SocietyList : SocietyList.concat(NPCSocietyList));
-		const arcFSes = activeFSes(arcID);
+		const arcFSes = activeFSes(arcology);
 
 		// apply game rules
 		if (!V.seeIncest) {
@@ -218,7 +219,7 @@ globalThis.FutureSocieties = (function() {
 
 		// if the government is loyal to you, FSes that conflict with FSes adopted by the player are invalid
 		if (arcology.government === "your agent" || arcology.government === "your trustees") {
-			const playerFSes = activeFSes(0);
+			const playerFSes = activeFSes(V.arcologies[0]);
 			societies.deleteWith(fs1 => playerFSes.some(fs2 => conflictingFSes(fs1, fs2)));
 		}
 
@@ -227,18 +228,18 @@ globalThis.FutureSocieties = (function() {
 
 	/** returns the set of shared FSes between two arcologies, and the set of conflicts between pairs of FSes between the arcologies
 	 * relatively expensive, try not to call frequently
-	 * call as FutureSocieties.diplomaticFSes(arc1ID, arc2ID)
-	 * @param {number} arc1ID
-	 * @param {number} arc2ID
+	 * call as FutureSocieties.diplomaticFSes(arc1, arc2)
+	 * @param {FC.ArcologyState} arc1
+	 * @param {FC.ArcologyState} arc2
 	 * @returns {{shared: FC.FutureSociety[], conflicting: FC.FutureSociety[][]}}
 	 */
-	function diplomaticFSes(arc1ID, arc2ID) {
+	function diplomaticFSes(arc1, arc2) {
 		/** @type {FC.FutureSociety[]} */
 		let shared = [];
 		/** @type {FC.FutureSociety[][]} */
 		let conflicting = [];
-		const arc1FSes = activeFSes(arc1ID);
-		const arc2FSes = activeFSes(arc2ID);
+		const arc1FSes = activeFSes(arc1);
+		const arc2FSes = activeFSes(arc2);
 		// find ordinary shared and conflicting FSes
 		for (const fs1 of arc1FSes) {
 			for (const fs2 of arc2FSes) {
@@ -250,8 +251,6 @@ globalThis.FutureSocieties = (function() {
 			}
 		}
 		// special cases: racial FSes might be conflicting even when shared
-		const arc1 = V.arcologies[arc1ID];
-		const arc2 = V.arcologies[arc2ID];
 		if (shared.contains("FSSupremacist")) {
 			// a different race is supreme
 			if (arc1.FSSupremacistRace !== arc2.FSSupremacistRace) {
@@ -301,8 +300,8 @@ globalThis.FutureSocieties = (function() {
 	 * @returns {FC.FutureSociety[]} FSes which purged completely
 	 */
 	function decayFSes(arcologyID) {
-		const fses = activeFSes(arcologyID);
 		const arc = V.arcologies[arcologyID];
+		const fses = activeFSes(arc);
 		/** @type {FC.FutureSociety[]} */
 		let purged = [];
 		for (const fs of fses) {
@@ -442,7 +441,7 @@ globalThis.FutureSocieties = (function() {
 	 */
 	function calcFSCredits() {
 		const arcology = V.arcologies[0];
-		let activeFS = activeCount(0);
+		let activeFS = activeCount(arcology);
 		if (typeof arcology.FSNull === 'number' && arcology.FSNull > 0) { // multiculturalism is accounted for separately
 			activeFS -= 1; // already counted once, remove that one and count investments instead
 			if (V.FSCreditCount === 4) {
diff --git a/src/markets/bulkSlave/bulkSlaveIntro.js b/src/markets/bulkSlave/bulkSlaveIntro.js
index a1184fd8a8e0f8e53fcb44d9c5b3de06c7317df8..faf979a0d19879a2003d951196124b2bebd45f7b 100644
--- a/src/markets/bulkSlave/bulkSlaveIntro.js
+++ b/src/markets/bulkSlave/bulkSlaveIntro.js
@@ -201,7 +201,7 @@ App.Markets.bulkSlaveIntro = function() {
 			if (V.market.numArcology >= V.arcologies.length) {
 				V.market.numArcology = 1;
 			}
-			opinion = App.Neighbor.opinion(0, V.market.numArcology);
+			opinion = App.Neighbor.opinion(V.arcologies[0], V.arcologies[V.market.numArcology]);
 			opinion = Math.clamp(Math.trunc(opinion/20), -10, 10);
 			discount -= (opinion * 25);
 		} else if (App.Data.misc.schools.has(V.market.slaveMarket)) {
diff --git a/src/markets/specificMarkets/slaveMarkets.js b/src/markets/specificMarkets/slaveMarkets.js
index 43ac7235a419d0952288f13a4f9c623b62b13a0d..7052572814da2ce4f30b9b6a94357493466f2360 100644
--- a/src/markets/specificMarkets/slaveMarkets.js
+++ b/src/markets/specificMarkets/slaveMarkets.js
@@ -193,19 +193,20 @@ App.Markets.raiders = function() {
 };
 
 App.Markets.neighbor = function() {
+	const arcology = V.arcologies[V.market.numArcology];
 	const el = new DocumentFragment();
 	el.append(`You're in the area of the slave market that specializes in slaves from within the Free City, viewing slaves from `);
-	App.UI.DOM.appendNewElement("span", el, `${V.arcologies[V.market.numArcology].name}.`, "bold");
+	App.UI.DOM.appendNewElement("span", el, `${arcology.name}.`, "bold");
 	el.append(` Some were trained there, specifically for sale, while others are simply being sold.`);
-	let _opinion = App.Neighbor.opinion(0, V.market.numArcology);
+	const opinion = App.Neighbor.opinion(V.arcologies[0], arcology);
 	let costMod = 1;
-	if (_opinion !== 0) {
-		if (_opinion > 2) {
-			el.append(` Your cultural ties with ${V.arcologies[V.market.numArcology].name} helps keep the price reasonable.`);
-		} else if (_opinion < -2) {
-			el.append(` Your social misalignment with ${V.arcologies[V.market.numArcology].name} drives up the price.`);
+	if (opinion !== 0) {
+		if (opinion > 2) {
+			el.append(` Your cultural ties with ${arcology.name} helps keep the price reasonable.`);
+		} else if (opinion < -2) {
+			el.append(` Your social misalignment with ${arcology.name} drives up the price.`);
 		}
-		costMod = (1 - (_opinion * 0.05));
+		costMod = (1 - (opinion * 0.05));
 	}
 
 	el.append(App.Markets.purchaseFramework("neighbor", {costMod: costMod}));
diff --git a/src/neighbor/arcologyDiplomacy.js b/src/neighbor/arcologyDiplomacy.js
index 26343a9e6c546724fa8de6e81bbb11126c24e7e7..e9931855a1497187063b9edad42c1275808a17e1 100644
--- a/src/neighbor/arcologyDiplomacy.js
+++ b/src/neighbor/arcologyDiplomacy.js
@@ -1,12 +1,10 @@
 /** get one arcology's opinion of another
- * @param {number} activeID index
- * @param {number} targetID index
+ * @param {FC.ArcologyState} activeArcology index
+ * @param {FC.ArcologyState} targetArcology index
  * @returns {number} opinion
  */
-App.Neighbor.opinion = function(activeID, targetID) {
-	const activeArcology = V.arcologies[activeID];
-	const targetArcology = V.arcologies[targetID];
-	const {shared, conflicting} = FutureSocieties.diplomaticFSes(activeID, targetID);
+App.Neighbor.opinion = function(activeArcology, targetArcology) {
+	const {shared, conflicting} = FutureSocieties.diplomaticFSes(activeArcology, targetArcology);
 
 	let opinion = 0;
 
@@ -43,11 +41,10 @@ App.Neighbor.selectInfluenceTarget = function(arcID) {
 		let eligibleTargets = [];
 		const obedient = (arcology.government === "your trustees" || arcology.government === "your agent");
 
-		for (let targetID = 0; targetID < V.arcologies.length; ++targetID) {
-			const target = V.arcologies[targetID];
+		for (const target of V.arcologies) {
 			if (arcology.direction !== target.direction) {
 				if (!obedient || target.direction !== 0) {
-					const {shared, conflicting} = FutureSocieties.diplomaticFSes(arcID, targetID);
+					const {shared, conflicting} = FutureSocieties.diplomaticFSes(arcology, target);
 					let count = 0;
 					count += shared.filter(notMulticulturalism).length;
 					count += conflicting.filter((pair) => pair.every(notMulticulturalism)).length;
@@ -68,15 +65,16 @@ App.Neighbor.PassiveFSInfluence = class {
 	 */
 	constructor(arcID) {
 		this._arcID = arcID;
-		/** @type {Map<number, {shared: string[], conflicting: string[][]}>} */
+		/** @type {Map<number, {shared: FC.FutureSociety[], conflicting: FC.FutureSociety[][]}>} */
 		this._relationships = new Map();
+
+		const arcology = V.arcologies[this._arcID];
 		for (let i = 0; i < V.arcologies.length; ++i) {
 			if (i !== arcID) {
-				this._relationships.set(i, FutureSocieties.diplomaticFSes(arcID, i));
+				this._relationships.set(i, FutureSocieties.diplomaticFSes(arcology, V.arcologies[i]));
 			}
 		}
 
-		const arcology = V.arcologies[this._arcID];
 		this._thresh = 5;
 		if (arcology.direction === 0) {
 			this._thresh -= V.policies.culturalOpenness * 5;
@@ -87,12 +85,12 @@ App.Neighbor.PassiveFSInfluence = class {
 	}
 
 	/** output the neighbors that have passively influenced a particular FS in this arcology
-	 * @param {string} fs
+	 * @param {FC.FutureSociety} fs
 	 */
 	output(fs) {
 		/** @type {number[]} */
 		let shared = [];
-		/** @type {Map<string, number[]>} */
+		/** @type {Map<FC.FutureSociety, number[]>} */
 		let conflicting = new Map();
 		const arcology = V.arcologies[this._arcID];
 
@@ -125,9 +123,9 @@ App.Neighbor.PassiveFSInfluence = class {
 		arcology[fs] += shared.length;
 		if (V.showNeighborDetails && shared.length > 0) {
 			t.push(FutureSocieties.displayName(fs));
-			if (fs === "FSSubjugationism") {
+			if (fs === "FSSubjugationist") {
 				t.push(`of ${arcology.FSSubjugationistRace} people`);
-			} else if (fs === "FSSupremacy") {
+			} else if (fs === "FSSupremacist") {
 				t.push(`for ${arcology.FSSupremacistRace} people`);
 			}
 			t.push(`in ${arcology.name} is influenced by`);
@@ -139,10 +137,11 @@ App.Neighbor.PassiveFSInfluence = class {
 		// passive slowing influence
 		arcology[fs] -= conflicting.size;
 		if (V.showNeighborDetails && conflicting.size > 0) {
+			/** @type {string} */
 			let actualDisplayName = FutureSocieties.displayName(fs);
-			if (fs === "FSSubjugationism") {
+			if (fs === "FSSubjugationist") {
 				actualDisplayName = `${arcology.FSSubjugationistRace} Subjugationism`;
-			} else if (fs === "FSSupremacy") {
+			} else if (fs === "FSSupremacist") {
 				actualDisplayName = `${arcology.FSSupremacistRace} Supremacy`;
 			}
 			t.push(`Development of ${actualDisplayName} in ${arcology.name} is slowed by contact with`);
diff --git a/src/neighbor/neighborDisplay.js b/src/neighbor/neighborDisplay.js
index 7f035f2e115259b5160c28b1555675ac7fe98c5b..8e5d962fd1b7d81fe2e2fee7580d6cebfb709a04 100644
--- a/src/neighbor/neighborDisplay.js
+++ b/src/neighbor/neighborDisplay.js
@@ -127,14 +127,13 @@ App.Neighbor.Display = class {
 		function fsFrag() {
 			let frag = document.createDocumentFragment();
 			frag.appendChild(document.createTextNode("FS: "));
+			const fses = FutureSocieties.activeFSes(arcology);
 			if (arcID === 0) {
-				const fses = FutureSocieties.activeFSes(0);
 				for (const fs of fses) {
 					frag.appendChild(withTooltip("⯁", FutureSocieties.displayName(fs), "steelblue"));
 				}
 			} else {
-				const fses = FutureSocieties.activeFSes(arcID);
-				const diplo = FutureSocieties.diplomaticFSes(arcID, 0);
+				const diplo = FutureSocieties.diplomaticFSes(arcology, V.arcologies[0]);
 				for (const fs of fses) {
 					let style = "white";
 					if (diplo.shared.includes(fs)) {
diff --git a/src/neighbor/neighborInteract.js b/src/neighbor/neighborInteract.js
index 85b8f77f57046793841670212a2c1d185f0d4033..61fb2d420e3e57f88d220b17fa268e1e20da8407 100644
--- a/src/neighbor/neighborInteract.js
+++ b/src/neighbor/neighborInteract.js
@@ -63,11 +63,11 @@ App.Neighbor.Interact = (function() {
 	function details(arcID) {
 		let frag = document.createDocumentFragment();
 		if (arcID === 0) {
-			const desc = FutureSocieties.activeFSes(0).map((f) => FutureSocieties.displayName(f));
+			const desc = FutureSocieties.activeFSes(V.arcologies[0]).map((f) => FutureSocieties.displayName(f));
 			if (desc.length === 0) {
 				App.UI.DOM.appendNewElement("p", frag, `Your arcology's culture has not developed to the point where it can meaningfully influence other arcologies.`);
 			} else if (desc.length > 2) {
-				App.UI.DOM.appendNewElement("p", frag, `Your arcology's mature culture is capable of exerting great cultural sway over other arcologies. It can readily project ${desc.reduce((res, ch, i, arr) => res + (i === arr.length - 1 ? ' and ' : ', ') + ch)}.`);
+				App.UI.DOM.appendNewElement("p", frag, `Your arcology's mature culture is capable of exerting great cultural sway over other arcologies. It can readily project ${arrayToSentence(desc)}.`);
 			} else if (desc.length === 2) {
 				App.UI.DOM.appendNewElement("p", frag, `Your arcology's culture is capable of exerting some cultural sway over other arcologies. It can effectively project ${desc[0]} and ${desc[1]}.`);
 			} else {
@@ -223,7 +223,7 @@ App.Neighbor.Interact = (function() {
 
 		container.append(document.createElement("br"));
 		const forceAbandonment = (fs) => { V.arcologies[arcID][fs] = "unset"; arcChanged(arcID); };
-		for (const fs of FutureSocieties.activeFSes(arcID)) {
+		for (const fs of FutureSocieties.activeFSes(V.arcologies[arcID])) {
 			App.UI.DOM.appendNewElement("div", container, App.UI.DOM.link(`Force abandonment of ${FutureSocieties.displayName(fs)}`, forceAbandonment, [fs]));
 		}
 
@@ -236,17 +236,18 @@ App.Neighbor.Interact = (function() {
 	 */
 	function fsGoods(arcID) {
 		const container = document.createElement("div");
+		const arcology = V.arcologies[arcID];
 		let r = [];
-		r.push(`If ${V.arcologies[arcID].name} has developed enough to begin exporting worthwhile goods, it may be of interest to acquire some.`);
-		const opinionDiscount = App.Neighbor.opinion(arcID, 0)*10;
+		r.push(`If ${arcology.name} has developed enough to begin exporting worthwhile goods, it may be of interest to acquire some.`);
+		const opinionDiscount = App.Neighbor.opinion(arcology, V.arcologies[0])*10;
 		const basePrice = Math.trunc((7500-opinionDiscount)*V.upgradeMultiplierTrade);
-		const controlled = (V.arcologies[arcID].government === "your trustees") || (V.arcologies[arcID].government === "your agent");
+		const controlled = (arcology.government === "your trustees") || (arcology.government === "your agent");
 		if (controlled) {
 			r.push(`Since it is under your control, it is no problem at all to request the transfer of goods to ${V.arcologies[0].name}.`);
 		} else if (V.PC.skill.hacking >= 50) {
 			r.push(`It is within your skills to redirect an outgoing shipment to ${V.arcologies[0].name} for your retrieval.`);
-		} else if (V.arcologies[arcID].direction === V.arcologies[0].embargoTarget) {
-			r.push(`However, due to your active embargo, trade with ${V.arcologies[arcID].name} is not possible.`);
+		} else if (arcology.direction === V.arcologies[0].embargoTarget) {
+			r.push(`However, due to your active embargo, trade with ${arcology.name} is not possible.`);
 		}
 		App.UI.DOM.appendNewElement("p", container, r.join(' '));
 
@@ -261,7 +262,7 @@ App.Neighbor.Interact = (function() {
 		 * @param {number} [itemPrice] - the price the player should pay for the item; by default, basePrice (computed above)
 		 */
 		function addAcquisitionBlock(fsRequired, itemName, category, itemDisplay, property, itemPrice = basePrice) {
-			if (V.arcologies[arcID][fsRequired] > 95) {
+			if (arcology[fsRequired] > 95) {
 				if (!isItemAccessible.entry(itemName, category)) {
 					if (controlled) {
 						const link = App.UI.DOM.link(`Request a shipment of ${itemDisplay}`, (f) => {
@@ -275,7 +276,7 @@ App.Neighbor.Interact = (function() {
 							replaceDetails(arcID);
 						});
 						App.UI.DOM.appendNewElement("div", container, link);
-					} else if (V.arcologies[arcID].direction !== V.arcologies[0].embargoTarget) {
+					} else if (arcology.direction !== V.arcologies[0].embargoTarget) {
 						const link = App.UI.DOM.link(`Divert an outgoing shipment of ${itemDisplay}`, (f) => {
 							property();
 							cashX(forceNeg(itemPrice), "capEx");
@@ -313,7 +314,7 @@ App.Neighbor.Interact = (function() {
 		addAcquisitionBlock("FSStatuesqueGlorification", "platform heels", "shoes", "platform shoes", () => { V.boughtItem.shoes.heels = 1; });
 
 		if (exports !== 1) {
-			const luck = (V.arcologies[arcID].direction === V.arcologies[0].embargoTarget) ? `Fortunately` : `Unfortunately`;
+			const luck = (arcology.direction === V.arcologies[0].embargoTarget) ? `Fortunately` : `Unfortunately`;
 			App.UI.DOM.appendNewElement("p", container, `${luck}, they have nothing of value.`);
 		}
 
diff --git a/src/npc/descriptions/sceneIntro.js b/src/npc/descriptions/sceneIntro.js
index 015ee8697e6d849e8584d2ec65230f5aaf4f5604..37535faaa78693829e212550fba9c3a3ac7fefea 100644
--- a/src/npc/descriptions/sceneIntro.js
+++ b/src/npc/descriptions/sceneIntro.js
@@ -43,15 +43,8 @@ App.Desc.sceneIntro = function(slave, {market, eventDescription} = {}) {
 		} else if ((slave.assignment === "work in the dairy") && (V.dairyRestraintsSetting > 1)) {
 			r.push(`You go down to ${V.dairyName} to inspect ${his} heaving body.`);
 		} else if (slave.assignment === "be your agent") {
-			r.push(`You place a call to`);
-			let agentLocation = `${his} current location`;
-			for (let _i = 0; _i < V.arcologies.length; _i++) {
-				if (V.arcologies[_i].leaderID === slave.ID) {
-					agentLocation = V.arcologies[_i].name;
-					break;
-				}
-			}
-			r.push(`${agentLocation}, and ${he} instantly appears on camera.`);
+			const arc = V.arcologies.find(a => a.leaderID === slave.ID);
+			r.push(`You place a call to ${arc ? arc.name : `${his} current location`}, and ${he} instantly appears on camera.`);
 		} else {
 			r.push(`${He} comes to you for an inspection`);
 			switch (slave.assignment) {
@@ -112,13 +105,8 @@ App.Desc.sceneIntro = function(slave, {market, eventDescription} = {}) {
 						if (V.arcologies[0].influenceTarget === -1) {
 							r.push(`right away, since you haven't decided on an arcology to target for cultural influence, leaving ${him} with nothing to do.`);
 						} else {
-							r.push(`from where ${he} was resting after ${his} latest sexually exhausting visit to`);
-							for (let i = 0; i < V.arcologies.length; i++) {
-								if (V.arcologies[i].direction === V.arcologies[0].influenceTarget) {
-									r.push(`${V.arcologies[i].name}.`);
-									break;
-								}
-							}
+							const arc = V.arcologies.find(a => a.direction === V.arcologies[0].influenceTarget);
+							r.push(`from where ${he} was resting after ${his} latest sexually exhausting visit to ${arc ? arc.name : "a nearby arcology"}.`);
 						}
 					}
 					break;
diff --git a/src/npc/generate/generateMarketSlave.js b/src/npc/generate/generateMarketSlave.js
index 785166e73b90f8c03901454c8117e336209d13a0..a93bbbcf1c26ce5ad7011ac9bbb9cc802f4be75a 100644
--- a/src/npc/generate/generateMarketSlave.js
+++ b/src/npc/generate/generateMarketSlave.js
@@ -462,7 +462,7 @@ globalThis.generateMarketSlave = function(market = "kidnappers", numArcology = 1
 		case "neighbor": {
 			const neighborID = (typeof V.arcologies[numArcology] === 'object') ? numArcology : 1;
 			const neighbor = V.arcologies[neighborID];
-			const opinion = Math.clamp(Math.trunc(App.Neighbor.opinion(0, neighborID)/20), -10, 10);
+			const opinion = Math.clamp(Math.trunc(App.Neighbor.opinion(V.arcologies[0], neighbor)/20), -10, 10);
 
 			let genes = "";
 			if (neighbor.FSSubjugationist > 20) {