diff --git a/src/js/foreachMacroJS.js b/src/js/foreachMacroJS.js
deleted file mode 100644
index 5aa54d90562c88b890c9458d1a7da4a2567a1c1f..0000000000000000000000000000000000000000
--- a/src/js/foreachMacroJS.js
+++ /dev/null
@@ -1,58 +0,0 @@
-/* eslint-disable no-undef */
-Macro.add('foreach', {
-	skipArgs : true,
-	tags : null,
-
-	handler() {
-		const payload = this.payload[0].contents.replace(/\n$/, '');
-		let statement = this.args.raw.trim();
-		let variable;
-		let array;
-		let result;
-
-		if (statement.length !== 0) {
-			const parts = statement.match(/^(\S+?)\s+of\s+(\S.*?)\s*$/i);
-			if(parts !== null) {
-				variable = parts[1];
-				array = parts[2];
-			}
-		}
-		if(!variable || !array) {
-			return this.error('invalid syntax, format: <<foreach variable of array-expression>>... <</foreach>>');
-		}
-
-		try {
-			result = Scripting.evalTwineScript(array);
-		} catch (ex) {
-			return this.error(`bad evaluation: ${typeof ex === 'object' ? ex.message : ex}`);
-		}
-
-		let resultLength = result['length'];
-
-		// We don't check for "instanceof Array" to also be able to pass arguments or other strange objects
-		if(typeof resultLength !== 'number' || (resultLength % 1) !== 0) {
-			return this.error(`bad evaluation: '${ result }' is not an array or array-like object`);
-		}
-
-		if(resultLength > Config.macros.maxLoopIterations) {
-			return this.error(`Array too large for maxLoopIterations (${ resultLength } > ${ Config.macros.maxLoopIterations })`);
-		}
-
-		if(!new RegExp(`^(${Patterns.variable})$`).test(variable)) {
-			return this.error(`not a variable identifier: ${ variable}`);
-		}
-
-		if(resultLength <= 0) {
-			// Don't bother with empty stuff
-			return;
-		}
-
-		Config.debug && this.debugView.modes({block: true});
-
-		payload.replace(/^\n/, '');
-		for(let i = 0; i < resultLength; ++ i) {
-			Wikifier.setValue(variable, result[i]);
-			new Wikifier(this.output, payload);
-		}
-	}
-});
diff --git a/src/pregmod/basenationalitiesControls.tw b/src/pregmod/basenationalitiesControls.tw
index 21d4a28a50535981a1a8cefec77dab7d8834ee0a..5a28b3895d209e116d64a6e3e08dee4c489842e3 100644
--- a/src/pregmod/basenationalitiesControls.tw
+++ b/src/pregmod/basenationalitiesControls.tw
@@ -107,7 +107,7 @@ Filter by Region:
 		</div>
 	<</for>>
 	<div style="clear: both;">By dominant race/ethnicity (hover over the name to see the nationalities affected):</div>
-	<<foreach _race of setup.filterRaces>>
+	<<for _race range setup.filterRaces>>
 		<<set _racialNationalities = setup.baseNationalities.filter(function(n) {
 			var races = setup.raceSelector[n] || setup.raceSelector[''];
 			return races[_race.toLowerCase()] * 3.5 > hashSum(races); })>>
@@ -126,7 +126,7 @@ Filter by Region:
 				<<replace '#PopControl'>><<include 'Basenationalities Controls'>><</replace>>
 			<</link>>@@</div>">>
 		<</if>>
-	<</foreach>>
+	<</for>>
 <<else>>
 /* Filtered pop controls */
 	<<set _controlsNationality = setup[$baseControlsFilter+'Nationalities']>>
diff --git a/src/pregmod/seDeath.tw b/src/pregmod/seDeath.tw
index 27e6a0cdc31efd6aa0a029e75c5b85a36aee4d15..51cd278c447670cf8fcd9d2f936b1f266cf768d5 100644
--- a/src/pregmod/seDeath.tw
+++ b/src/pregmod/seDeath.tw
@@ -3,7 +3,7 @@
 <<set $nextButton = "Continue", $nextLink = "Scheduled Event">>
 
 <<set _killedSlaves = []>>
-<<foreach _slave of $slaves>>
+<<for _slave range $slaves>>
 	<<switch _slave.death.toLowerCase()>>
 		<<case "old">>
 			<<DeathOldAge _slave>>
@@ -22,16 +22,16 @@
 			<br><br><hr style="margin:0"><br>
 			<<set _killedSlaves.push(_slave)>>
 	<</switch>>
-<</foreach>>
+<</for>>
 <<if _killedSlaves.length == 0>>
 	/* if something beats this to the slaves, this should kick the player along instead of leaving them at a blank screen */
 	<<set $slaveDeath = 0>>
 	<<goto "Scheduled Event">>
 <</if>>
-<<foreach _slave of _killedSlaves>>
+<<for _slave range _killedSlaves>>
 	<<set $activeSlave = _slave>>
 	<<= removeActiveSlave() >>
-<</foreach>>
+<</for>>
 <<unset _killedSlaves>>
 
-<<set $slaveDeath = 0>>
\ No newline at end of file
+<<set $slaveDeath = 0>>
diff --git a/src/pregmod/widgets/marketWidgets.tw b/src/pregmod/widgets/marketWidgets.tw
index c9d19f880eaa6f8e82568347ae9b63de191a00a8..b568f38367b81882839bfeb336e8b259d8ae36fe 100644
--- a/src/pregmod/widgets/marketWidgets.tw
+++ b/src/pregmod/widgets/marketWidgets.tw
@@ -19,9 +19,9 @@
 			while(match = re.exec(wp.text)) { result.push(match[1]); }
 			return result; })
 		.value()>>
-	<<silently>><<foreach _widget of _widgets>>
+	<<silently>><<for _widget range _widgets>>
 		<<= "<<" + _widget + " $args[1]>>">>
-	<</foreach>><</silently>>
+	<</for>><</silently>>
 <</if>>
 <</widget>>
 
@@ -35,4 +35,4 @@
 		<<include "Generate Random Slave">>
 	<</if>>
 <</silently>>
-<</widget>>
\ No newline at end of file
+<</widget>>
diff --git a/src/uncategorized/main.tw b/src/uncategorized/main.tw
index 4aec940dc9292dc84bc8039eb8a205ee3377f06e..fda0d00c63ff99db3d458208eabc122a0bb8f8b4 100644
--- a/src/uncategorized/main.tw
+++ b/src/uncategorized/main.tw
@@ -49,10 +49,10 @@
 /* end extra sanity checks and repair */
 
 <<set _duplicateSlaves = _($slaves).countBy(s => s.ID).pickBy(v => v > 1).keys().map(v => Number(v)).value()>>
-<<foreach _i of _duplicateSlaves>>
+<<for _i range _duplicateSlaves>>
 	<br><br>@@.red;Duplicate slave ID _i at indices
 	<<= _($slaves).map((s, idx) => ({ID: s.ID, idx: idx, name: s.slaveName, assignment: s.assignment})).filter(s => s.ID === _i).map(s => s.idx + ' - ' + s.name + ' (' + s.assignment + ')').join(', ')>>@@
-<</foreach>>
+<</for>>
 <<set _visibleSlaves = $slaves.filter(s => s.assignmentVisible == 1 && (s.assignment != "be your Head Girl" || $HGSuite != 1) && (s.assignment != "guard you" || $dojo <= 1)),
 	$slavesVisible = _visibleSlaves.length,
 	$dormitoryPopulation = _visibleSlaves.filter(s => s.livingRules != "luxurious").length,