diff --git a/Source/Core/Controls/Scripting/ScriptEditorPanel.cs b/Source/Core/Controls/Scripting/ScriptEditorPanel.cs
index 0df472755a444f33a1b1a8f326ef234b5a6da6de..12a10d77fe5831824b364f2945267cdf0614f7c4 100755
--- a/Source/Core/Controls/Scripting/ScriptEditorPanel.cs
+++ b/Source/Core/Controls/Scripting/ScriptEditorPanel.cs
@@ -404,6 +404,100 @@ namespace CodeImp.DoomBuilder.Controls
 		
 		#region ================== Methods
 
+        // [ZZ] Find and Replace
+        //      This needs to be done in the script editor class, because we don't want to loop over the same value
+        //      And for this, we need to know the context properly, not just "while FindNext && Replace".
+        //      Which means there should be a function that does both find and replace manually.
+        public int FindReplace(FindReplaceOptions options)
+        {
+            // [ZZ] why do we require current tab for "find everywhere" and "replace everywhere"?
+            //      todo: understand and refactor
+            //
+            // [ZZ] note: if we want CURRENT_*, error out if no active tab.
+            FindReplaceOptions singlesearchoptions = new FindReplaceOptions(options) { SearchMode = FindReplaceSearchMode.CURRENT_FILE };
+            List<ScriptDocumentTab> rtabs = new List<ScriptDocumentTab>();
+            switch (options.SearchMode)
+            {
+                // we really need a bitfield here. Whatever.
+                case FindReplaceSearchMode.CURRENT_FILE:
+                    if (ActiveTab == null)
+                        return 0;
+                    rtabs.Add(ActiveTab);
+                    break;
+
+                case FindReplaceSearchMode.OPENED_TABS_CURRENT_SCRIPT_TYPE:
+                    if (ActiveTab == null)
+                        return 0;
+                    // .NET is heavily retarded
+                    goto case FindReplaceSearchMode.OPENED_TABS_ALL_SCRIPT_TYPES;
+                case FindReplaceSearchMode.OPENED_TABS_ALL_SCRIPT_TYPES:
+                    foreach (ScriptDocumentTab tab in tabs.TabPages)
+                    {
+                        if (options.SearchMode == FindReplaceSearchMode.OPENED_TABS_ALL_SCRIPT_TYPES ||
+                             tab.Config.ScriptType == ActiveTab.Config.ScriptType) rtabs.Add(tab);
+                    }
+                    break;
+
+                case FindReplaceSearchMode.CURRENT_PROJECT_CURRENT_SCRIPT_TYPE:
+                    if (ActiveTab == null)
+                        return 0;
+                    // .NET is heavily retarded
+                    goto case FindReplaceSearchMode.CURRENT_PROJECT_ALL_SCRIPT_TYPES;
+                case FindReplaceSearchMode.CURRENT_PROJECT_ALL_SCRIPT_TYPES:
+                    // Just search among all resources
+                    var usedscripttypes = new List<ScriptType>(General.Map.Data.ScriptResources.Keys);
+                    for (int i = 0; i < usedscripttypes.Count; i++)
+                    {
+                        if (options.SearchMode != FindReplaceSearchMode.CURRENT_PROJECT_ALL_SCRIPT_TYPES &&
+                            usedscripttypes[i] != ActiveTab.Config.ScriptType) continue; // [ZZ] skip irrelevant script types
+                        foreach (ScriptResource sr in General.Map.Data.ScriptResources[usedscripttypes[i]])
+                        {
+                            if (!sr.IsReadOnly && sr.ContainsText(singlesearchoptions))
+                            {
+                                // open this tab
+                                var newtab = OpenResource(sr);
+                                rtabs.Add(newtab);
+                            }
+                        }
+                    }
+                    break;
+            }
+
+            int replacements = 0;
+            foreach (ScriptDocumentTab tab in rtabs)
+            {
+                // do find/replace in the current tab.
+                // make sure that we don't find the same thing twice in case replacement has part of it's value.
+                int firstPosition = -1;
+                int lengthDifference = options.ReplaceWith.Length - options.FindText.Length;
+                int lastSelectionStart = -1;
+                int lastSelectionEnd = -1;
+                while (true)
+                {
+                    if (!tab.FindNext(singlesearchoptions))
+                        break;
+                    if (firstPosition < 0)
+                        firstPosition = tab.SelectionStart;
+                    else if (tab.SelectionStart == firstPosition) // found the first
+                    {
+                        tab.SelectionStart = lastSelectionStart;
+                        tab.SelectionEnd = lastSelectionEnd;
+                        break;
+                    }
+                    if (tab.SelectionStart < firstPosition) // offset the first position with string length difference if we are replacing before it.
+                        firstPosition += lengthDifference;
+                    // do replacement
+                    tab.ReplaceSelection(options.ReplaceWith);
+                    //
+                    lastSelectionStart = tab.SelectionStart;
+                    lastSelectionEnd = tab.SelectionEnd;
+                    replacements++;
+                }
+            }
+
+            return replacements;
+        }
+
 		// Find Next
 		public bool FindNext(FindReplaceOptions options)
 		{
diff --git a/Source/Core/Windows/ScriptFindReplaceForm.cs b/Source/Core/Windows/ScriptFindReplaceForm.cs
index cb9c540c69124d894fa235f4017f8e93d254cf5b..a67a34d30c8349a81a9cd6351e453225a8100451 100755
--- a/Source/Core/Windows/ScriptFindReplaceForm.cs
+++ b/Source/Core/Windows/ScriptFindReplaceForm.cs
@@ -313,17 +313,18 @@ namespace CodeImp.DoomBuilder.Windows
 			AddComboboxText(replacebox, options.ReplaceWith);
 
 			// Find next match
+            // [ZZ] why are we doing this? we aren't limited to the current tab.....
+            /*
 			ScriptDocumentTab curtab = editor.ActiveTab;
 			if(curtab == null || !curtab.FindNext(options, true))
 			{
 				editor.DisplayStatus(ScriptStatusType.Warning, "Can't find any occurrence of \"" + options.FindText + "\".");
 				return;
-			}
+			}*/
 
-			// Replace loop
-			int replacements = 0;
-			while(editor.FindNext(options) && editor.Replace(options))
-				replacements++;
+            // Replace loop
+            // We don't really want to do this outside of the script editor.
+            int replacements = editor.FindReplace(options);
 
 			// Show result
 			if(replacements == 0)
@@ -333,9 +334,9 @@ namespace CodeImp.DoomBuilder.Windows
 			else
 			{
 				editor.DisplayStatus(ScriptStatusType.Info, "Replaced " + replacements + " occurrences of \"" + options.FindText + "\" with \"" + options.ReplaceWith + "\".");
-				
-				// Find & select the last match on the now-current tab
-				curtab = editor.ActiveTab;
+
+                // Find & select the last match on the now-current tab
+                ScriptDocumentTab curtab = editor.ActiveTab;
 				if(curtab != null)
 				{
 					options.FindText = options.ReplaceWith;