static void AddScriptFromFile(string path) { string scriptSource = File.ReadAllText(path); string gmlWeirdName = "gml_Script_" + Path.GetFileNameWithoutExtension(path); // Make a code entry. UndertaleCode codeEntry = new UndertaleCode { Name = Data.Strings.MakeString(gmlWeirdName) }; Data.Code.Add(codeEntry); // Make a code locals entry. UndertaleCodeLocals locals = new UndertaleCodeLocals { Name = codeEntry.Name }; // Make a `var arguments;` entry. UndertaleCodeLocals.LocalVar argsLocal = new UndertaleCodeLocals.LocalVar { Name = Data.Strings.MakeString("arguments"), Index = 0 }; // Glue everything together. locals.Locals.Add(argsLocal); Data.CodeLocals.Add(locals); // Set code locals entry for the code entry. codeEntry.LocalsCount = 1; //codeEntry.GenerateLocalVarDefinitions(codeEntry.FindReferencedLocalVars(), locals); // fails here. // FINALLY compile our script. Data.Code.ByName(gmlWeirdName).ReplaceGML(scriptSource, Data); // ... and actually add it like a script... var scr = new UndertaleScript { Code = Data.Code.ByName(gmlWeirdName), Name = Data.Strings.MakeString(Path.GetFileNameWithoutExtension(path)) }; Data.Scripts.Add(scr); // ... oh, and don't forget to add a *function* reference. var funcentry = new UndertaleFunction { Name = Data.Strings.MakeString(Path.GetFileNameWithoutExtension(path)) }; Data.Functions.Add(funcentry); }
void ImportCode(string codeName, string gmlCode, bool IsGML = true, bool doParse = true, bool destroyASM = true, bool CheckDecompiler = false) { bool SkipPortions = false; UndertaleCode code = Data.Code.ByName(codeName); if (Data.Code.ByName(codeName) == null) { code = new UndertaleCode(); code.Name = Data.Strings.MakeString(codeName); Data.Code.Add(code); } if (Data?.GeneralInfo.BytecodeVersion > 14 && Data.CodeLocals.ByName(codeName) == null) { UndertaleCodeLocals locals = new UndertaleCodeLocals(); locals.Name = code.Name; UndertaleCodeLocals.LocalVar argsLocal = new UndertaleCodeLocals.LocalVar(); argsLocal.Name = Data.Strings.MakeString("arguments"); argsLocal.Index = 0; locals.Locals.Add(argsLocal); code.LocalsCount = 1; code.GenerateLocalVarDefinitions(code.FindReferencedLocalVars(), locals); // Dunno if we actually need this line, but it seems to work? Data.CodeLocals.Add(locals); } if (doParse) { // This portion links code. if (codeName.Substring(0, 10).Equals("gml_Script")) { // Add code to scripts section. if (Data.Scripts.ByName(codeName.Substring(11)) == null) { UndertaleScript scr = new UndertaleScript(); scr.Name = Data.Strings.MakeString(codeName.Substring(11)); scr.Code = code; Data.Scripts.Add(scr); } else { UndertaleScript scr = Data.Scripts.ByName(codeName.Substring(11)); scr.Code = code; } } else if (codeName.Substring(0, 16).Equals("gml_GlobalScript")) { // Add code to global init section. UndertaleGlobalInit init_entry = null; // This doesn't work, have to do it the hard way: UndertaleGlobalInit init_entry = Data.GlobalInitScripts.ByName(scr_dup_code_name_con); foreach (UndertaleGlobalInit globalInit in Data.GlobalInitScripts) { if (globalInit.Code.Name.Content == codeName) { init_entry = globalInit; break; } } if (init_entry == null) { UndertaleGlobalInit NewInit = new UndertaleGlobalInit(); NewInit.Code = code; Data.GlobalInitScripts.Add(NewInit); } else { UndertaleGlobalInit NewInit = init_entry; NewInit.Code = code; } } else if (codeName.Substring(0, 10).Equals("gml_Object")) { string afterPrefix = codeName.Substring(11); int underCount = 0; string methodNumberStr = "", methodName = "", objName = ""; for (int i = afterPrefix.Length - 1; i >= 0; i--) { if (afterPrefix[i] == '_') { underCount++; if (underCount == 1) { methodNumberStr = afterPrefix.Substring(i + 1); } else if (underCount == 2) { objName = afterPrefix.Substring(0, i); methodName = afterPrefix.Substring(i + 1, afterPrefix.Length - objName.Length - methodNumberStr.Length - 2); break; } } } int methodNumber = 0; try { methodNumber = int.Parse(methodNumberStr); if (methodName == "Collision" && (methodNumber >= Data.GameObjects.Count || methodNumber < 0)) { bool doNewObj = ScriptQuestion("Object of ID " + methodNumber.ToString() + " was not found.\nAdd new object?"); if (doNewObj) { UndertaleGameObject gameObj = new UndertaleGameObject(); gameObj.Name = Data.Strings.MakeString(SimpleTextInput("Enter object name", "Enter object name", "This is a single text line input box test.", false)); Data.GameObjects.Add(gameObj); } else { // It *needs* to have a valid value, make the user specify one. List <uint> possible_values = new List <uint>(); possible_values.Add(uint.MaxValue); methodNumber = (int)ReduceCollisionValue(possible_values); } } } catch { if (afterPrefix.LastIndexOf("_Collision_") != -1) { string s2 = "_Collision_"; objName = afterPrefix.Substring(0, (afterPrefix.LastIndexOf("_Collision_"))); methodNumberStr = afterPrefix.Substring(afterPrefix.LastIndexOf("_Collision_") + s2.Length, afterPrefix.Length - (afterPrefix.LastIndexOf("_Collision_") + s2.Length)); methodName = "Collision"; // GMS 2.3+ use the object name for the one colliding, which is rather useful. if (Data.GMS2_3) { if (Data.GameObjects.ByName(methodNumberStr) != null) { for (var i = 0; i < Data.GameObjects.Count; i++) { if (Data.GameObjects[i].Name.Content == methodNumberStr) { methodNumber = i; break; } } } else { bool doNewObj = ScriptQuestion("Object " + objName + " was not found.\nAdd new object called " + objName + "?"); if (doNewObj) { UndertaleGameObject gameObj = new UndertaleGameObject(); gameObj.Name = Data.Strings.MakeString(objName); Data.GameObjects.Add(gameObj); } } if (Data.GameObjects.ByName(methodNumberStr) != null) { // It *needs* to have a valid value, make the user specify one, silly. List <uint> possible_values = new List <uint>(); possible_values.Add(uint.MaxValue); ReassignGUIDs(methodNumberStr, ReduceCollisionValue(possible_values)); } } else { // Let's try to get this going methodNumber = (int)ReduceCollisionValue(GetCollisionValueFromCodeNameGUID(codeName)); ReassignGUIDs(methodNumberStr, ReduceCollisionValue(GetCollisionValueFromCodeNameGUID(codeName))); } } } UndertaleGameObject obj = Data.GameObjects.ByName(objName); if (obj == null) { bool doNewObj = ScriptQuestion("Object " + objName + " was not found.\nAdd new object called " + objName + "?"); if (doNewObj) { UndertaleGameObject gameObj = new UndertaleGameObject(); gameObj.Name = Data.Strings.MakeString(objName); Data.GameObjects.Add(gameObj); } else { SkipPortions = true; } } if (!(SkipPortions)) { obj = Data.GameObjects.ByName(objName); int eventIdx = (int)Enum.Parse(typeof(EventTypes), methodName); bool duplicate = false; try { foreach (UndertaleGameObject.Event evnt in obj.Events[eventIdx]) { foreach (UndertaleGameObject.EventAction action in evnt.Actions) { if (action.CodeId?.Name?.Content == codeName) { duplicate = true; } } } } catch { // Something went wrong, but probably because it's trying to check something non-existent // Just keep going } if (duplicate == false) { UndertalePointerList <UndertaleGameObject.Event> eventList = obj.Events[eventIdx]; UndertaleGameObject.EventAction action = new UndertaleGameObject.EventAction(); UndertaleGameObject.Event evnt = new UndertaleGameObject.Event(); action.ActionName = code.Name; action.CodeId = code; evnt.EventSubtype = (uint)methodNumber; evnt.Actions.Add(action); eventList.Add(evnt); } } } } SafeImport(codeName, gmlCode, IsGML, destroyASM, CheckDecompiler); }
public static void SpeedrunPatches(UndertaleData data) { UndertaleScript setboi = new UndertaleScript(); setboi.Name = data.Strings.MakeString("set_speedrun_category"); setboi.Code = new UndertaleCode(); setboi.Code.Name = data.Strings.MakeString("gml_Script_set_speedrun_category"); setboi.Code.ReplaceGML(RabbitRunCode.set_speedrun_category, data); data.Code.Add(setboi.Code); data.Scripts.Add(setboi); UndertaleScript sprun = new UndertaleScript(); sprun.Name = new UndertaleString("menu_speedrun_script"); data.Strings.Add(sprun.Name); sprun.Code = new UndertaleCode(); data.Code.Add(sprun.Code); sprun.Code.Name = new UndertaleString("gml_Script_menu_speedrun_script"); data.Strings.Add(sprun.Code.Name); sprun.Code.ReplaceGML(RabbitRunCode.menu_speedrun_script, data); sprun.Code.UpdateAddresses(); data.Scripts.Add(sprun); UndertaleCode ae = data.Code.ByName("gml_Script_setfile"); ae.AppendGML(RabbitRunCode.gml_Script_setfile, data); ae.UpdateAddresses(); UndertaleCode ee = data.Code.ByName("gml_Object_obj_mainmenus_Create_0"); ReplaceInGML("GAME\", 1, 8],", "GAME\", 1, 8], [\"SPEEDBUN\", 1, 19], ", ee, data); ee.UpdateAddresses(); ReplaceInGML("i = 0", RabbitRunCode.speedrunMenuInit, ee, data); UndertaleCode ie = data.Code.ByName("gml_Script_cKeys_beginstep"); ie.AppendGML(RabbitRunCode.tasBeginStepInput, data); UndertaleCode oe = data.Code.ByName("gml_Object_obj_init_Create_0"); oe.AppendGML(@"global.playRun = false; global.watchRun = false; global.speedrunning = true; global.inrun = false; global.onehun = false;//one hundred percent global.allbun = false;//all cuties global.anyper = false;//any percent", data); UndertaleCode ue = data.Code.ByName("gml_Script_SaveStringToFile"); ue.ReplaceGML(RabbitRunCode.saveStringFile, data); UndertaleSprite mico = data.Sprites.ByName("spr_menuicons"); UndertaleSprite.TextureEntry te = new UndertaleSprite.TextureEntry(); UndertaleTexturePageItem ti = mico.Textures[1].Texture; UndertaleTexturePageItem to = data.Sprites.ByName("spr_antibunidle").Textures[0].Texture; te.Texture = new UndertaleTexturePageItem(); te.Texture.TargetX = ti.TargetX; te.Texture.TargetY = ti.TargetY; te.Texture.SourceX = to.SourceX; te.Texture.SourceY = to.SourceY; te.Texture.BoundingHeight = ti.BoundingHeight; te.Texture.BoundingWidth = ti.BoundingWidth; te.Texture.SourceWidth = 16; te.Texture.TargetWidth = 16; te.Texture.SourceHeight = 15; te.Texture.TargetHeight = 15; te.Texture.TexturePage = to.TexturePage; data.TexturePageItems.Add(te.Texture); mico.Textures.Insert(2, te); }