diff --git a/YAMS-LIB/Program.cs b/YAMS-LIB/Program.cs index 35a63d6..6f9a83c 100644 --- a/YAMS-LIB/Program.cs +++ b/YAMS-LIB/Program.cs @@ -10,6 +10,8 @@ using static YAMS_LIB.ExtensionMethods; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; +using YAMS_LIB.patches; +using YAMS_LIB.patches.qol; namespace YAMS_LIB; @@ -2341,136 +2343,7 @@ void RotateTextureAndSaveToTexturePage(int rotation, UndertaleTexturePageItem te "if ((distance_to_object(oItem) > 180) && changeOnMap)"); // Door locks - // Adjust global event array to be 700 - characterVarsCode.ReplaceGMLInCode( """ - i = 350 - repeat (350) - { - i -= 1 - global.event[i] = 0 - } - """, """ - i = 700 - repeat (700) - { - i -= 1 - global.event[i] = 0 - } - """); - gmData.Code.ByName("gml_Script_sv6_add_events").ReplaceGMLInCode( "350", "700"); - gmData.Code.ByName("gml_Script_sv6_get_events").ReplaceGMLInCode( "350", "700"); - - // Replace every normal, a4 and a8 door with an a5 door for consistency - var a5Door = gmData.GameObjects.ByName("oDoorA5"); - foreach (var room in gmData.Rooms) - { - foreach (var door in room.GameObjects.Where(go => go.ObjectDefinition.Name.Content.StartsWith("oDoor"))) - { - door.ObjectDefinition = a5Door; - } - } - // Also fix depth value for them - a5Door.Depth = -99; - - - var doorEventIndex = 350; - foreach ((var id, var doorLock) in seedObject.DoorLocks) - { - bool found = false; - foreach (var room in gmData.Rooms) - { - foreach (var gameObject in room.GameObjects) - { - if (gameObject.InstanceID != id) continue; - - if (!gameObject.ObjectDefinition.Name.Content.StartsWith("oDoor") && gameObject.ObjectDefinition.Name.Content != "oA2BigTurbine") - throw new NotSupportedException($"The 'door' instance {id} is not actually a door!"); - - found = true; - if (gameObject.CreationCode is null) - { - var code = new UndertaleCode() { Name = gmData.Strings.MakeString($"gml_RoomCC_{room.Name.Content}_{id}_Create") }; - gmData.Code.Add(code); - gameObject.CreationCode = code; - } - - string codeText = doorLock.Lock switch - { - DoorLockType.Normal => "lock = 0; event = -1;", - DoorLockType.Missile => $"lock = 1; originalLock = lock; event = {doorEventIndex};", - DoorLockType.SuperMissile => $"lock = 2; originalLock = lock; event = {doorEventIndex};", - DoorLockType.PBomb => $"lock = 3; originalLock = lock; event = {doorEventIndex};", - DoorLockType.TempLocked => $"lock = 4; originalLock = lock; event = -1;", - DoorLockType.Charge => $"lock = 5; originalLock = lock; event = -1;", - DoorLockType.Wave => $"lock = 6; originalLock = lock; event = -1;", - DoorLockType.Spazer => $"lock = 7; originalLock = lock; event = -1;", - DoorLockType.Plasma => $"lock = 8; originalLock = lock; event = -1;", - DoorLockType.Ice => $"lock = 9; originalLock = lock; event = -1;", - DoorLockType.Bomb => "lock = 10; originalLock = lock; event = -1;", - DoorLockType.Spider => "lock = 11; originalLock = lock; event = -1;", - DoorLockType.Screw => "lock = 12; originalLock = lock; event = -1;", - DoorLockType.TowerEnabled => "lock = 13; originalLock = lock; event = -1;", - DoorLockType.TesterDead => "lock = 14; originalLock = lock; event = -1;", - DoorLockType.GuardianDead => "lock = 15; originalLock = lock; event = -1;", - DoorLockType.ArachnusDead => "lock = 16; originalLock = lock; event = -1;", - DoorLockType.TorizoDead => "lock = 17; originalLock = lock; event = -1;", - DoorLockType.SerrisDead => "lock = 18; originalLock = lock; event = -1;", - DoorLockType.GenesisDead => "lock = 19; originalLock = lock; event = -1;", - DoorLockType.QueenDead => "lock = 20; originalLock = lock; event = -1;", - DoorLockType.EMPActivated => "lock = 21; originalLock = lock; event = -1;", - DoorLockType.EMPA1 => "lock = 22; originalLock = lock; event = -1;", - DoorLockType.EMPA2 => "lock = 23; originalLock = lock; event = -1;", - DoorLockType.EMPA3 => "lock = 24; originalLock = lock; event = -1;", - DoorLockType.EMPA5Tutorial => "lock = 25; originalLock = lock; event = -1;", - DoorLockType.EMPA5RobotHome => "lock = 26; originalLock = lock; event = -1;", - DoorLockType.EMPA5NearZeta => "lock = 27; originalLock = lock; event = -1;", - DoorLockType.EMPA5BulletHell => "lock = 28; originalLock = lock; event = -1;", - DoorLockType.EMPA5PipeHub => "lock = 29; originalLock = lock; event = -1;", - DoorLockType.EMPA5RightExterior => "lock = 30; originalLock = lock; event = -1;", - DoorLockType.Locked => "lock = 31; originalLock = lock; event = -1;", - DoorLockType.A2WaterTurbine => $"eventToSet = {doorEventIndex};" + - $"if (global.event[eventToSet] > 0)" + - $"{{ if (!wasAlreadyDestroyed) {{ with (wall) instance_destroy(); }} instance_destroy();}} " + - $"if (wasAlreadyDestroyed && global.event[eventToSet] < 1) global.event[eventToSet] = 1;", - _ => throw new NotSupportedException($"Door {id} has an unsupported door lock ({doorLock.Lock})!") - }; - - var waterTurbineObject = gmData.GameObjects.ByName("oA2BigTurbine"); - if (gameObject.ObjectDefinition == waterTurbineObject && doorLock.Lock != DoorLockType.A2WaterTurbine) - { - gameObject.ObjectDefinition = gmData.GameObjects.ByName("oDoorA5"); - gameObject.X += (24 * (int)gameObject.ScaleX); - gameObject.ScaleX *= -1; - bool leftFacing = gameObject.ScaleX < 0; - room.Tiles.Add(CreateRoomTile(gameObject.X - (leftFacing ? 8 : 24), gameObject.Y, -110, gmData.Backgrounds.ByName("tlDoor"), (leftFacing ? 0u : 32u), 0, 32, 64)); - var tilesToDelete = room.Tiles.Where((t => (t is { X: 912, Y: 1584, SourceX: 48, SourceY: 304 } or { X: 928, Y: 1536, SourceX: 96, SourceY: 304 }))).ToList(); - foreach (var tile in tilesToDelete) - room.Tiles.Remove(tile); - } - - if (gameObject.ObjectDefinition != waterTurbineObject && doorLock.Lock == DoorLockType.A2WaterTurbine) - { - gameObject.ObjectDefinition = waterTurbineObject; - gameObject.X += (24 * (int)gameObject.ScaleX); - gameObject.ScaleX *= -1; - if ((gameObject.X - 48) == 0) - room.GameObjects.Add(CreateRoomObject(gameObject.X-72, gameObject.Y, gmData.GameObjects.ByName("oSolid1x4"))); - else if ((gameObject.X + 48) == room.Width) - room.GameObjects.Add(CreateRoomObject(gameObject.X+72, gameObject.Y, gmData.GameObjects.ByName("oSolid1x4"))); - - } - - gameObject.CreationCode.AppendGMLInCode( codeText); - doorEventIndex++; - break; - } - - if (found) break; - } - - if (!found) - throw new NotSupportedException($"There is no door with ID {id}!"); - } + DoorLockRando.Apply(gmData, decompileContext, seedObject); // Modify every location item, to give the wished item, spawn the wished text and the wished sprite foreach ((var pickupName, PickupObject pickup) in seedObject.PickupObjects) @@ -2859,111 +2732,8 @@ void RotateTextureAndSaveToTexturePage(int rotation, UndertaleTexturePageItem te // The position here is for a puzzle in a2, that when not respawned makes it a tad hard. gmData.Code.ByName("gml_Object_oBlockBomb_Other_10").PrependGMLInCode( "if (!global.respawnBombBlocks && !(room == rm_a2a06 && x == 624 && y == 128)) regentime = -1"); - // On start, make all rooms show being "unexplored" similar to primes/super - // Replaces all mentions of sMapBlock and sMapCorner with local variables. - gmData.Code.ByName("gml_Script_draw_mapblock").ReplaceGMLInCode( "sMapBlock", "blockSprite"); - gmData.Code.ByName("gml_Script_draw_mapblock").ReplaceGMLInCode( "sMapCorner", "cornerSprite"); - - // Redefine the sprite variables to the Unexplored sprites, if map tile hasn't been revealed to player. - if (seedObject.Cosmetics.ShowUnexploredMap) - characterVarsCode.ReplaceGMLInCode( "global.unexploredMap = 0", "global.unexploredMap = 1;"); - gmData.Code.ByName("gml_Script_draw_mapblock").ReplaceGMLInCode( "if (argument8 > 0)", """ - //variables for swapping map color and corner sprites - var blockSprite, cornerSprite; - - //default sprites - blockSprite = sMapBlock; - cornerSprite = sMapCorner; - - //Don't draw if map tile is a fast travel pipe - if (argument7 != "H" && argument7 != "V" && argument7 != "C") - { - //Sprite variables changed to unexplored variants if map not revealed - if (argument8 == 0 && global.unexploredMap) - { - blockSprite = sMapBlockUnexplored; - cornerSprite = sMapCornerUnexplored; - } - else if (argument8 == 0 && !global.unexploredMap) - exit; - } - """); - // Don't ever draw the debug pipe tiles - gmData.Code.ByName("gml_Script_draw_mapblock").ReplaceGMLInCode( """ - if (argument7 == "H") - draw_sprite(sMapSP, 12, argument0, argument1) - if (argument7 == "V") - draw_sprite(sMapSP, 13, argument0, argument1) - if (argument7 == "C") - draw_sprite(sMapSP, 14, argument0, argument1) - """, ""); - // Also show item pickups and metroids - gmData.Code.ByName("gml_Script_draw_mapblock").ReplaceGMLInCode( "if (argument7 == \"3\" && argument8 == 1)", "if (argument7 == \"3\" && (argument8 == 1 || argument8 == 0))"); - gmData.Code.ByName("gml_Script_draw_mapblock").ReplaceGMLInCode( "if (argument7 == \"4\" && argument8 == 1)", "if (argument7 == \"4\" && (argument8 == 1 || argument8 == 0))"); - // Add hint icons to minimap - gmData.Code.ByName("gml_Script_draw_mapblock").AppendGMLInCode( "if (argument7 == \"W\") draw_sprite(sMapSP, 15, argument0, argument1)"); - //Add "M" condition to Metroid alive icon check - gmData.Code.ByName("gml_Script_draw_mapblock").ReplaceGMLInCode( "if (argument8 == 10)", """if (argument8 == 10 || (argument7 == "M" && global.unexploredMap))"""); - //Draw metroid alive icon on undiscovered map - gmData.Code.ByName("gml_Script_init_map").AppendGMLInCode( """ - global.map[14, 34] = "10111M0" - global.map[15, 29] = "10111M0" - global.map[18, 50] = "10101M0" - global.map[19, 24] = "00112M0" - global.map[21, 15] = "10111M0" - global.map[25, 27] = "10122M0" - global.map[25, 36] = "10112M0" - global.map[25, 42] = "10112M0" - global.map[25, 47] = "10101M0" - global.map[27, 31] = "11101M0" - global.map[30, 17] = "10112M0" - global.map[30, 24] = "11002M0" - global.map[30, 26] = "11002M0" - global.map[35, 19] = "11103M0" - global.map[35, 23] = "21103M0" - global.map[35, 31] = "11103M0" - global.map[37, 33] = "11012M0" - global.map[41, 28] = "11102M0" - global.map[42, 21] = "10102M0" - global.map[42, 37] = "11102M0" - global.map[43, 24] = "10103M0" - global.map[49, 38] = "01101M0" - global.map[54, 16] = "10112M0" - global.map[54, 27] = "10102M0" - global.map[58, 25] = "10112M0" - global.map[58, 28] = "12102M0" - global.map[58, 31] = "00102M0" - global.map[59, 38] = "11001M0" - global.map[60, 16] = "11102M0" - global.map[60, 25] = "11122M0" - global.map[63, 15] = "11102M0" - global.map[64, 33] = "01112M0" - global.map[64, 47] = "10103M0" - global.map[65, 24] = "01013M0" - global.map[67, 25] = "10103M0" - global.map[67, 45] = "10013M0" - global.map[68, 46] = "01103M0" - global.map[69, 9] = "11102M0" - global.map[71, 48] = "11003M0" - global.map[73, 24] = "11102M0" - global.map[73, 31] = "11102M0" - """); - - // Fix BG3 surprise gamma map tile - gmData.Code.ByName("gml_Object_oMGamma_Alarm_9").SubstituteGMLCode( """ - myposx = floor((x / 320)) - myposy = floor(((y - 8) / 240)) - mapposx = (myposx + global.mapoffsetx) - mapposy = (myposy + global.mapoffsety) - if (myid == 20) - { - mapposx = 58 - mapposy = 31 - } - global.dmap[mapposx, mapposy] = 10 - with (oControl) - event_user(2) - """); + // On start, make all rooms show being "unexplored" similar to prime/super rando + ShowFullyUnexploredMap.Apply(gmData, decompileContext, seedObject); // Force all breakables (except the hidden super blocks) to be visible if (seedObject.Cosmetics.UnveilBlocks) @@ -3104,132 +2874,7 @@ void RotateTextureAndSaveToTexturePage(int rotation, UndertaleTexturePageItem te // Patch to add room name display near health - StringBuilder roomNameDSMapBuilder = new StringBuilder(); - foreach ((var roomName, var roomData) in seedObject.RoomObjects) - roomNameDSMapBuilder.Append($"ds_map_add(roomNames, \"{roomName}\", \"{roomData.DisplayName}\");\n"); - string roomNameDSMapString = roomNameDSMapBuilder.ToString(); - - var roomNameHudCC = new UndertaleCode() { Name = gmData.Strings.MakeString("gml_Object_oRoomNameHUD_Create_0") }; - roomNameHudCC.SubstituteGMLCode( $""" - rnh_surface = surface_create((320 + oControl.widescreen_space), 240) - fadeout = 0 - roomtime = 0 - textToDisplay = "" - image_alpha = 0 - offsetY = 0 - displayMode = {(int)seedObject.Cosmetics.RoomNameHud} - textBGColor = 0 - textColor0 = c_white - textColor1 = c_silver - roomNames = ds_map_create() - {roomNameDSMapString} - """); - var roomNameHudDestroy = new UndertaleCode() { Name = gmData.Strings.MakeString("gml_Object_oRoomNameHUD_Destroy_0") }; - roomNameHudDestroy.SubstituteGMLCode( "surface_free(rnh_surface); ds_map_destroy(roomNames)"); - var roomNameHudDrawGui = new UndertaleCode() { Name = gmData.Strings.MakeString("gml_Object_oRoomNameHUD_Draw_64") }; - roomNameHudDrawGui.SubstituteGMLCode( """ - var d; - d = application_get_position() - if (room != rm_transition && instance_exists(oCharacter) && global.ingame && displayMode != 0 && global.opshowhud) - draw_surface_ext(rnh_surface, (oControl.displayx - d[0]), (oControl.displayy - d[1]), oControl.display_scale, oControl.display_scale, 0, -1, 1) - """); - var roomNameHudRoomStart = new UndertaleCode() {Name = gmData.Strings.MakeString("gml_Object_oRoomNameHUD_Other_4")}; - roomNameHudRoomStart.SubstituteGMLCode( """ - var newRoomName = ds_map_find_value(roomNames, room_get_name(room)) - if (global.ingame && textToDisplay != newRoomName) - { - fadeout = 0 - roomtime = 0 - image_alpha = 0 - textToDisplay = newRoomName - } - """); - var roomNameHudStep = new UndertaleCode() { Name = gmData.Strings.MakeString("gml_Object_oRoomNameHUD_Step_0") }; - roomNameHudStep.SubstituteGMLCode( """ - if (displayMode == 0) - exit; - offsetY = 0 - if instance_exists(oIGT) - offsetY = 11 - if global.ingame - { - if (!fadeout) - { - if (image_alpha < 1) - image_alpha += 0.2 - else - fadeout = 1 - } - else if (displayMode == 1 && roomtime > 200 && image_alpha > 0) - image_alpha -= 0.02 - roomtime++ - } - if (surface_exists(rnh_surface) && surface_get_width(rnh_surface) < (320 + oControl.widescreen_space)) - surface_free(rnh_surface) - if (!surface_exists(rnh_surface)) - rnh_surface = surface_create((320 + oControl.widescreen_space), 240) - if surface_exists(rnh_surface) - { - surface_set_target(rnh_surface) - draw_clear_alpha(c_black, 0) - draw_set_font(global.fontGUI2) - draw_set_halign(fa_left) - draw_set_alpha(1) - draw_set_color(c_white) - draw_cool_text(4, (16 + offsetY), textToDisplay, textBGColor, textColor0, textColor1, image_alpha) - surface_reset_target() - } - """); - gmData.Code.Add(roomNameHudCC); - gmData.Code.Add(roomNameHudDestroy); - gmData.Code.Add(roomNameHudDrawGui); - gmData.Code.Add(roomNameHudRoomStart); - gmData.Code.Add(roomNameHudStep); - // Create Object and add events - - var roomHudObject = new UndertaleGameObject() { Name = gmData.Strings.MakeString("oRoomNameHUD"), Depth = -9999999, Persistent = true}; - gmData.GameObjects.Add(roomHudObject); - gmData.Code.ByName("gml_Script_load_character_vars").AppendGMLInCode( "if (!instance_exists(oRoomNameHUD))\ninstance_create(0, 0, oRoomNameHUD)"); - // Create - var roomHudCollisionList = roomHudObject.Events[0]; - var roomHudAction = new UndertaleGameObject.EventAction(); - roomHudAction.CodeId = roomNameHudCC; - var roomHudEvent = new UndertaleGameObject.Event(); - roomHudEvent.EventSubtype = 0; - roomHudEvent.Actions.Add(roomHudAction); - roomHudCollisionList.Add(roomHudEvent); - // Destroy - roomHudCollisionList = roomHudObject.Events[1]; - roomHudAction = new UndertaleGameObject.EventAction(); - roomHudAction.CodeId = roomNameHudDestroy; - roomHudEvent = new UndertaleGameObject.Event(); - roomHudEvent.EventSubtype = 0; - roomHudEvent.Actions.Add(roomHudAction); - roomHudCollisionList.Add(roomHudEvent); - // Step - roomHudCollisionList = roomHudObject.Events[3]; - roomHudAction = new UndertaleGameObject.EventAction(); - roomHudAction.CodeId = roomNameHudStep; - roomHudEvent = new UndertaleGameObject.Event(); - roomHudEvent.EventSubtype = 0; - roomHudEvent.Actions.Add(roomHudAction); - roomHudCollisionList.Add(roomHudEvent); - // Room start - roomHudCollisionList = roomHudObject.Events[7]; - roomHudAction = new UndertaleGameObject.EventAction(); - roomHudAction.CodeId = roomNameHudRoomStart; - roomHudEvent = new UndertaleGameObject.Event(); - roomHudEvent.EventSubtype = 4; - roomHudEvent.Actions.Add(roomHudAction); - roomHudCollisionList.Add(roomHudEvent); - // Draw GUI - roomHudCollisionList = roomHudObject.Events[8]; - roomHudAction = new UndertaleGameObject.EventAction(); - roomHudAction.CodeId = roomNameHudDrawGui; - roomHudEvent = new UndertaleGameObject.Event(); - roomHudEvent.EventSubtype = 64; - roomHudEvent.Actions.Add(roomHudAction); - roomHudCollisionList.Add(roomHudEvent); + DisplayRoomNameOnHUD.Apply(gmData, decompileContext, seedObject); // Set fusion mode value gmData.Code.ByName("gml_Object_oControl_Step_0").ReplaceGMLInCode( "mod_fusion = 0", $"mod_fusion = {(seedObject.Patches.FusionMode ? 1 : 0)}"); @@ -3249,177 +2894,8 @@ void RotateTextureAndSaveToTexturePage(int rotation, UndertaleTexturePageItem te // TODO: For the future, with room rando, go through each door and modify where it leads to - // Hints - // Ice Beam Hints - // Make log in lab always appear - gmData.Code.ByName("gml_Room_rm_a7b04A_Create").ReplaceGMLInCode( "oControl.chozomessage >= 10", "true"); - // Fix hint dissappearing when visiting room right after baby scan - gmData.Code.ByName("gml_Object_oChozoLogMarker_Step_0").ReplaceGMLInCode( "instance_exists(oNotification)", "instance_exists(oNotification) && oNotification.log == 1"); - // Change text to be hint - gmData.Code.ByName("gml_Script_load_logs_list").AppendGMLInCode( $"lbl[44] = \"Ice Beam Hint\"; txt[44, 0] = \"{seedObject.Hints[HintLocationEnum.ChozoLabs]}\"; pic[44, 0] = bgLogImg44B"); - // Remove second scanning - gmData.Code.ByName("gml_Room_rm_a0h01_Create").ReplaceGMLInCode( "scan_log(44, get_text(\"Misc\", \"Translation\"), 180, 1)", "if (false) {}"); - - // Septogg hints - // Prep work: - // Increase log array size to 100 - gmData.Code.ByName("gml_Script_sv6_add_logs").ReplaceGMLInCode( "repeat (50)", "repeat (100)"); - gmData.Code.ByName("gml_Script_sv6_get_logs").ReplaceGMLInCode( "repeat (50)", "repeat (100)"); - // Replace reset lists with simplified new array range - gmData.Code.ByName("gml_Script_reset_logs").SubstituteGMLCode( """ - var i = 99 - repeat (100) - { - global.log[i] = 0 - i -= 1 - } - i = 7 - repeat (8) - { - global.trooperlog[i] = 0 - i -= 1 - } - global.log[0] = 1 - global.log[1] = 1 - global.log[4] = 1 - global.log[5] = 1 - global.log[10] = 1 - global.log[20] = 1 - global.log[30] = 1 - """); - //Another array extension - gmData.Code.ByName("gml_Script_reset_logs_list").ReplaceGMLInCode( """ - i = 49 - repeat (50) - """, """ - i = 99 - repeat (100) - """); - //Add 7 new Hint logs to the new category 5 - gmData.Code.ByName("gml_Script_create_log_category").ReplaceGMLInCode( "dlognum = 0", """ - if (argument0 == 5) - { - clognum = 7 - min_log = 50 - } - dlognum = 0 - """); - //add categories - gmData.Code.ByName("gml_Object_oLogScreen_Create_0").ReplaceGMLInCode( "create_log_category(category)", """ - if (global.gotolog >= 50 && global.gotolog < 60) - category = 5 - create_log_category(category) - """); - //This stuff is for the menu. The array thing might not be needed, but did it anyway, increasing by the same amount as the global.log arrays. - gmData.Code.ByName("gml_Object_oLogScreenControl_Create_0").ReplaceGMLInCode( """ - i = 59 - repeat (60) - """, """ - i = 109 - repeat (110) - """); - gmData.Code.ByName("gml_Object_oLogScreenControl_Create_0").ReplaceGMLInCode( """ - j += 1 - create_log_label(cat[4]) - create_log_entry(41) - create_log_entry(42) - create_log_entry(43) - create_log_entry(45) - """, """ - if (global.log[41] > 0 || global.log[42] > 0 || global.log[43] > 0 || global.log[45] > 0) - { - j += 1 - create_log_label(cat[4]) - create_log_entry(41) - create_log_entry(42) - create_log_entry(43) - create_log_entry(45) - } - if (global.log[50] > 0 || global.log[51] > 0 || global.log[52] > 0 || global.log[53] > 0 || global.log[54] > 0 || global.log[55] > 0 || global.log[56] > 0) - { - j += 1 - create_log_label(cat[5]) - create_log_entry(50) - create_log_entry(51) - create_log_entry(52) - create_log_entry(53) - create_log_entry(54) - create_log_entry(55) - create_log_entry(56) - } - """); - //Defines the new septogg hint entries - gmData.Code.ByName("gml_Script_load_logs_list").AppendGMLInCode( $""" - cat[5] = "DNA Hints" - lbl[50] = "{seedObject.RoomObjects["rm_a0h13"].RegionName}" - txt[50, 0] = "{seedObject.Hints[HintLocationEnum.SeptoggA0]}" - pic[50, 0] = bgLogDNA0 - lbl[51] = "{seedObject.RoomObjects["rm_a1b02"].RegionName}" - txt[51, 0] = "{seedObject.Hints[HintLocationEnum.SeptoggA1]}" - pic[51, 0] = bgLogDNA1 - lbl[52] = "{seedObject.RoomObjects["rm_a2c05"].RegionName}" - txt[52, 0] = "{seedObject.Hints[HintLocationEnum.SeptoggA2]}" - pic[52, 0] = bgLogDNA2 - lbl[53] = "{seedObject.RoomObjects["rm_a3b10"].RegionName}" - txt[53, 0] = "{seedObject.Hints[HintLocationEnum.SeptoggA3]}" - pic[53, 0] = bgLogDNA3 - lbl[54] = "{seedObject.RoomObjects["rm_a4h03"].RegionName}" - txt[54, 0] = "{seedObject.Hints[HintLocationEnum.SeptoggA4]}" - pic[54, 0] = bgLogDNA4 - lbl[55] = "{seedObject.RoomObjects["rm_a5c17"].RegionName}" - txt[55, 0] = "{seedObject.Hints[HintLocationEnum.SeptoggA5]}" - pic[55, 0] = bgLogDNA5 - lbl[56] = "{seedObject.RoomObjects["rm_a6b02"].RegionName}" - txt[56, 0] = "{seedObject.Hints[HintLocationEnum.SeptoggA6]}" - pic[56, 0] = bgLogDNA6 - """); - - // Add wisdom septoggs into rooms - // A0 - gmData.Rooms.ByName("rm_a0h13").GameObjects.Add(CreateRoomObject(55, 194, oWisdomSeptogg)); - gmData.Code.ByName("gml_Room_rm_a0h13_Create").AppendGMLInCode( "create_log_trigger(0, 50, 55, 194, -35, 1)"); - // A1 - gmData.Rooms.ByName("rm_a1b02").GameObjects.Add(CreateRoomObject(144, 670, oWisdomSeptogg)); - gmData.Code.ByName("gml_Room_rm_a1b02_Create").AppendGMLInCode( "create_log_trigger(0, 51, 144, 670, -35, 1)"); - // A2 - gmData.Rooms.ByName("rm_a2c05").GameObjects.Add(CreateRoomObject(115, 310, oWisdomSeptogg)); - gmData.Code.ByName("gml_Room_rm_a2c05_Create").AppendGMLInCode( "create_log_trigger(0, 52, 115, 310, -35, 1)"); - // A3 - gmData.Rooms.ByName("rm_a3b10").GameObjects.Add(CreateRoomObject(768, 396, oWisdomSeptogg)); - gmData.Code.ByName("gml_Room_rm_a3b10_Create").AppendGMLInCode( "create_log_trigger(0, 53, 768, 396, -35, 1)"); - // A4 - gmData.Rooms.ByName("rm_a4h03").GameObjects.Add(CreateRoomObject(88, 523, oWisdomSeptogg)); - gmData.Code.ByName("gml_Room_rm_a4h03_Create").AppendGMLInCode( "create_log_trigger(0, 54, 88, 523, -35, 1)"); - // A5 - gmData.Rooms.ByName("rm_a5c17").GameObjects.Add(CreateRoomObject(246, 670, oWisdomSeptogg)); - gmData.Code.ByName("gml_Room_rm_a5c17_Create").AppendGMLInCode( "create_log_trigger(0, 55, 246, 670, -35, 1)"); - // A6 - gmData.Rooms.ByName("rm_a6b02").GameObjects.Add(CreateRoomObject(240, 400, oWisdomSeptogg)); - gmData.Code.ByName("gml_Room_rm_a6b02_Create").AppendGMLInCode( "create_log_trigger(0, 56, 240, 400, -35, 1)"); - - // A0 - gmData.Code.ByName("gml_Script_map_init_09").ReplaceGMLInCode( "global.map[41, 24] = \"2201100\"", "global.map[41, 24] = \"22011W0\""); - - // A1 - gmData.Code.ByName("gml_Script_map_init_12").ReplaceGMLInCode( "global.map[58, 16] = \"0212200\"", "global.map[58, 16] = \"02122W0\""); - - // A2 - gmData.Code.ByName("gml_Script_map_init_04").ReplaceGMLInCode( "global.map[24, 26] = \"0101200\"", "global.map[24, 26] = \"01012W0\""); - - // A3 - gmData.Code.ByName("gml_Script_map_init_14").ReplaceGMLInCode( "global.map[63, 28] = \"0011200\"", "global.map[63, 28] = \"00112W0\""); - - // A4 - gmData.Code.ByName("gml_Script_map_init_05").ReplaceGMLInCode( "global.map[32, 29] = \"0021200\"", "global.map[32, 29] = \"00212W0\""); - - // A5 - gmData.Code.ByName("gml_Script_map_init_16").ReplaceGMLInCode( "global.map[69, 45] = \"0112300\"", "global.map[69, 45] = \"01123W0\""); - - // A6 - gmData.Code.ByName("gml_Script_map_init_03").ReplaceGMLInCode( "global.map[20, 40] = \"0112100\"", "global.map[20, 40] = \"01121W0\""); - - // Ice - gmData.Code.ByName("gml_Script_map_init_01").ReplaceGMLInCode( "global.map[8, 22] = \"1210300\"", "global.map[8, 22] = \"12103W0\""); + // Ad in-game Hints + AddInGameHints.Apply(gmData, decompileContext, seedObject); // Pipe rando // TODO: optimization could be made here, by letting rdv provide the room where the instance id is, thus not neeeding to crawl over every room. @@ -3438,47 +2914,10 @@ void RotateTextureAndSaveToTexturePage(int rotation, UndertaleTexturePageItem te } // Add patch to see room names on minimap - StringBuilder dsMapCordBuilder = new StringBuilder("room_names_coords = ds_map_create()"); - foreach ((string key, RoomObject value) in seedObject.RoomObjects) - { - foreach (Coordinate coord in value.MinimapData) - { - dsMapCordBuilder.Append($"ds_map_add(room_names_coords, \"{coord.X}|{coord.Y}\", \"{value.RegionName} - {value.DisplayName}\");\n"); - } - } - string DSMapCoordRoomname = dsMapCordBuilder.ToString(); - gmData.Code.ByName("gml_Object_oSS_Fg_Create_0").AppendGMLInCode( DSMapCoordRoomname); - gmData.Code.ByName("gml_Object_oSS_Fg_Draw_0").ReplaceGMLInCode( """ - draw_text((view_xview[0] + 161), ((view_yview[0] + 30) - rectoffset), maptext) - draw_set_color(c_white) - draw_text((view_xview[0] + 160), ((view_yview[0] + 29) - rectoffset), maptext) - """,""" - draw_set_font(global.fontMenuSmall2) - var titleText = maptext; - if (instance_exists(oMapCursor) && oMapCursor.active && oMapCursor.state == 1) - { - titleText = ds_map_find_value(room_names_coords, string(global.mapmarkerx) + "|" + string(global.mapmarkery)); - if (titleText == undefined) - titleText = maptext; - } - draw_text((view_xview[0] + 161), ((view_yview[0] + 29) - rectoffset), titleText); - draw_set_color(c_white); - draw_text((view_xview[0] + 160), ((view_yview[0] + 28) - rectoffset), titleText); - draw_set_font(global.fontGUI2) - """); - var ssFGDestroyCode = new UndertaleCode() { Name = gmData.Strings.MakeString("gml_Object_oSS_Fg_Destroy_0") }; - ssFGDestroyCode.SubstituteGMLCode( "ds_map_destroy(room_names_coords)"); - gmData.Code.Add(ssFGDestroyCode); - var ssFGCollisionList = gmData.GameObjects.ByName("oSS_Fg").Events[1]; - var ssFGAction = new UndertaleGameObject.EventAction(); - ssFGAction.CodeId = ssFGDestroyCode; - var ssFGEvent = new UndertaleGameObject.Event(); - ssFGEvent.EventSubtype = 0; - ssFGEvent.Actions.Add(ssFGAction); - ssFGCollisionList.Add(ssFGEvent); + DisplayRoomNamesOnMap.Apply(gmData, decompileContext, seedObject); // Adjust pause screen text to mention room names - gmData.Code.ByName("gml_Object_oSS_Fg_Create_0").ReplaceGMLInCode( "tip2text = get_text(\"Subscreen\", \"Marker_Tip\")", "tip2text = \"| - Marker & Room Names\""); + RoomFeatureMapText.Apply(gmData, decompileContext); // TODO: rewrite log rendering to have color diff --git a/YAMS-LIB/patches/AddInGameHints.cs b/YAMS-LIB/patches/AddInGameHints.cs new file mode 100644 index 0000000..c9e9e19 --- /dev/null +++ b/YAMS-LIB/patches/AddInGameHints.cs @@ -0,0 +1,193 @@ +using UndertaleModLib; +using UndertaleModLib.Decompiler; +using static YAMS_LIB.ExtensionMethods; + +namespace YAMS_LIB.patches; + +public class AddInGameHints +{ + private static void PatchIceBeamHint(UndertaleData gmData, GlobalDecompileContext decompileContext, SeedObject seedObject) + { + // Make log in lab always appear + gmData.Code.ByName("gml_Room_rm_a7b04A_Create").ReplaceGMLInCode( "oControl.chozomessage >= 10", "true"); + // Fix hint dissappearing when visiting room right after baby scan + gmData.Code.ByName("gml_Object_oChozoLogMarker_Step_0").ReplaceGMLInCode( "instance_exists(oNotification)", "instance_exists(oNotification) && oNotification.log == 1"); + // Change text to be hint + gmData.Code.ByName("gml_Script_load_logs_list").AppendGMLInCode( $"lbl[44] = \"Ice Beam Hint\"; txt[44, 0] = \"{seedObject.Hints[HintLocationEnum.ChozoLabs]}\"; pic[44, 0] = bgLogImg44B"); + // Remove second scanning + gmData.Code.ByName("gml_Room_rm_a0h01_Create").ReplaceGMLInCode( "scan_log(44, get_text(\"Misc\", \"Translation\"), 180, 1)", "if (false) {}"); + + // Change minimap to include hint + gmData.Code.ByName("gml_Script_map_init_01").ReplaceGMLInCode( "global.map[8, 22] = \"1210300\"", "global.map[8, 22] = \"12103W0\""); + } + + private static void PatchWisdomSeptoggHints(UndertaleData gmData, GlobalDecompileContext decompileContext, SeedObject seedObject) + { + // Prep work: + // Increase log array size to 100 + gmData.Code.ByName("gml_Script_sv6_add_logs").ReplaceGMLInCode( "repeat (50)", "repeat (100)"); + gmData.Code.ByName("gml_Script_sv6_get_logs").ReplaceGMLInCode( "repeat (50)", "repeat (100)"); + // Replace reset lists with simplified new array range + gmData.Code.ByName("gml_Script_reset_logs").SubstituteGMLCode( """ + var i = 99 + repeat (100) + { + global.log[i] = 0 + i -= 1 + } + i = 7 + repeat (8) + { + global.trooperlog[i] = 0 + i -= 1 + } + global.log[0] = 1 + global.log[1] = 1 + global.log[4] = 1 + global.log[5] = 1 + global.log[10] = 1 + global.log[20] = 1 + global.log[30] = 1 + """); + // Another array extension + gmData.Code.ByName("gml_Script_reset_logs_list").ReplaceGMLInCode( """ + i = 49 + repeat (50) + """, """ + i = 99 + repeat (100) + """); + // Add 7 new Hint logs to the new category 5 + gmData.Code.ByName("gml_Script_create_log_category").ReplaceGMLInCode( "dlognum = 0", """ + if (argument0 == 5) + { + clognum = 7 + min_log = 50 + } + dlognum = 0 + """); + // Add categories + gmData.Code.ByName("gml_Object_oLogScreen_Create_0").ReplaceGMLInCode( "create_log_category(category)", """ + if (global.gotolog >= 50 && global.gotolog < 60) + category = 5 + create_log_category(category) + """); + // This stuff is for the menu. The array thing might not be needed, but did it anyway, increasing by the same amount as the global.log arrays. + gmData.Code.ByName("gml_Object_oLogScreenControl_Create_0").ReplaceGMLInCode( """ + i = 59 + repeat (60) + """, """ + i = 109 + repeat (110) + """); + gmData.Code.ByName("gml_Object_oLogScreenControl_Create_0").ReplaceGMLInCode( """ + j += 1 + create_log_label(cat[4]) + create_log_entry(41) + create_log_entry(42) + create_log_entry(43) + create_log_entry(45) + """, """ + if (global.log[41] > 0 || global.log[42] > 0 || global.log[43] > 0 || global.log[45] > 0) + { + j += 1 + create_log_label(cat[4]) + create_log_entry(41) + create_log_entry(42) + create_log_entry(43) + create_log_entry(45) + } + if (global.log[50] > 0 || global.log[51] > 0 || global.log[52] > 0 || global.log[53] > 0 || global.log[54] > 0 || global.log[55] > 0 || global.log[56] > 0) + { + j += 1 + create_log_label(cat[5]) + create_log_entry(50) + create_log_entry(51) + create_log_entry(52) + create_log_entry(53) + create_log_entry(54) + create_log_entry(55) + create_log_entry(56) + } + """); + // Defines the new septogg hint entries + gmData.Code.ByName("gml_Script_load_logs_list").AppendGMLInCode( $""" + cat[5] = "DNA Hints" + lbl[50] = "{seedObject.RoomObjects["rm_a0h13"].RegionName}" + txt[50, 0] = "{seedObject.Hints[HintLocationEnum.SeptoggA0]}" + pic[50, 0] = bgLogDNA0 + lbl[51] = "{seedObject.RoomObjects["rm_a1b02"].RegionName}" + txt[51, 0] = "{seedObject.Hints[HintLocationEnum.SeptoggA1]}" + pic[51, 0] = bgLogDNA1 + lbl[52] = "{seedObject.RoomObjects["rm_a2c05"].RegionName}" + txt[52, 0] = "{seedObject.Hints[HintLocationEnum.SeptoggA2]}" + pic[52, 0] = bgLogDNA2 + lbl[53] = "{seedObject.RoomObjects["rm_a3b10"].RegionName}" + txt[53, 0] = "{seedObject.Hints[HintLocationEnum.SeptoggA3]}" + pic[53, 0] = bgLogDNA3 + lbl[54] = "{seedObject.RoomObjects["rm_a4h03"].RegionName}" + txt[54, 0] = "{seedObject.Hints[HintLocationEnum.SeptoggA4]}" + pic[54, 0] = bgLogDNA4 + lbl[55] = "{seedObject.RoomObjects["rm_a5c17"].RegionName}" + txt[55, 0] = "{seedObject.Hints[HintLocationEnum.SeptoggA5]}" + pic[55, 0] = bgLogDNA5 + lbl[56] = "{seedObject.RoomObjects["rm_a6b02"].RegionName}" + txt[56, 0] = "{seedObject.Hints[HintLocationEnum.SeptoggA6]}" + pic[56, 0] = bgLogDNA6 + """); + + // Add wisdom septoggs into rooms + var oWisdomSeptogg = gmData.GameObjects.ByName("oWisdomSeptogg"); + + // A0 + gmData.Rooms.ByName("rm_a0h13").GameObjects.Add(CreateRoomObject(55, 194, oWisdomSeptogg)); + gmData.Code.ByName("gml_Room_rm_a0h13_Create").AppendGMLInCode( "create_log_trigger(0, 50, 55, 194, -35, 1)"); + // A1 + gmData.Rooms.ByName("rm_a1b02").GameObjects.Add(CreateRoomObject(144, 670, oWisdomSeptogg)); + gmData.Code.ByName("gml_Room_rm_a1b02_Create").AppendGMLInCode( "create_log_trigger(0, 51, 144, 670, -35, 1)"); + // A2 + gmData.Rooms.ByName("rm_a2c05").GameObjects.Add(CreateRoomObject(115, 310, oWisdomSeptogg)); + gmData.Code.ByName("gml_Room_rm_a2c05_Create").AppendGMLInCode( "create_log_trigger(0, 52, 115, 310, -35, 1)"); + // A3 + gmData.Rooms.ByName("rm_a3b10").GameObjects.Add(CreateRoomObject(768, 396, oWisdomSeptogg)); + gmData.Code.ByName("gml_Room_rm_a3b10_Create").AppendGMLInCode( "create_log_trigger(0, 53, 768, 396, -35, 1)"); + // A4 + gmData.Rooms.ByName("rm_a4h03").GameObjects.Add(CreateRoomObject(88, 523, oWisdomSeptogg)); + gmData.Code.ByName("gml_Room_rm_a4h03_Create").AppendGMLInCode( "create_log_trigger(0, 54, 88, 523, -35, 1)"); + // A5 + gmData.Rooms.ByName("rm_a5c17").GameObjects.Add(CreateRoomObject(246, 670, oWisdomSeptogg)); + gmData.Code.ByName("gml_Room_rm_a5c17_Create").AppendGMLInCode( "create_log_trigger(0, 55, 246, 670, -35, 1)"); + // A6 + gmData.Rooms.ByName("rm_a6b02").GameObjects.Add(CreateRoomObject(240, 400, oWisdomSeptogg)); + gmData.Code.ByName("gml_Room_rm_a6b02_Create").AppendGMLInCode( "create_log_trigger(0, 56, 240, 400, -35, 1)"); + + + // Change minimap to include hint + // A0 + gmData.Code.ByName("gml_Script_map_init_09").ReplaceGMLInCode( "global.map[41, 24] = \"2201100\"", "global.map[41, 24] = \"22011W0\""); + + // A1 + gmData.Code.ByName("gml_Script_map_init_12").ReplaceGMLInCode( "global.map[58, 16] = \"0212200\"", "global.map[58, 16] = \"02122W0\""); + + // A2 + gmData.Code.ByName("gml_Script_map_init_04").ReplaceGMLInCode( "global.map[24, 26] = \"0101200\"", "global.map[24, 26] = \"01012W0\""); + + // A3 + gmData.Code.ByName("gml_Script_map_init_14").ReplaceGMLInCode( "global.map[63, 28] = \"0011200\"", "global.map[63, 28] = \"00112W0\""); + + // A4 + gmData.Code.ByName("gml_Script_map_init_05").ReplaceGMLInCode( "global.map[32, 29] = \"0021200\"", "global.map[32, 29] = \"00212W0\""); + + // A5 + gmData.Code.ByName("gml_Script_map_init_16").ReplaceGMLInCode( "global.map[69, 45] = \"0112300\"", "global.map[69, 45] = \"01123W0\""); + + // A6 + gmData.Code.ByName("gml_Script_map_init_03").ReplaceGMLInCode( "global.map[20, 40] = \"0112100\"", "global.map[20, 40] = \"01121W0\""); + } + + public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileContext, SeedObject seedObject) + { + PatchIceBeamHint(gmData, decompileContext, seedObject); + PatchWisdomSeptoggHints(gmData, decompileContext, seedObject); + } +} diff --git a/YAMS-LIB/patches/DoorLockRando.cs b/YAMS-LIB/patches/DoorLockRando.cs new file mode 100644 index 0000000..02670f8 --- /dev/null +++ b/YAMS-LIB/patches/DoorLockRando.cs @@ -0,0 +1,145 @@ +using UndertaleModLib; +using UndertaleModLib.Decompiler; +using UndertaleModLib.Models; +using static YAMS_LIB.ExtensionMethods; + +namespace YAMS_LIB.patches; + +public class DoorLockRando +{ + public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileContext, SeedObject seedObject) + { + var characterVarsCode = gmData.Code.ByName("gml_Script_load_character_vars"); + + // Adjust global event array to be 700 + characterVarsCode.ReplaceGMLInCode( """ + i = 350 + repeat (350) + { + i -= 1 + global.event[i] = 0 + } + """, """ + i = 700 + repeat (700) + { + i -= 1 + global.event[i] = 0 + } + """); + gmData.Code.ByName("gml_Script_sv6_add_events").ReplaceGMLInCode( "350", "700"); + gmData.Code.ByName("gml_Script_sv6_get_events").ReplaceGMLInCode( "350", "700"); + + // Replace every normal, a4 and a8 door with an a5 door for consistency + var a5Door = gmData.GameObjects.ByName("oDoorA5"); + foreach (var room in gmData.Rooms) + { + foreach (var door in room.GameObjects.Where(go => go.ObjectDefinition.Name.Content.StartsWith("oDoor"))) + { + door.ObjectDefinition = a5Door; + } + } + // Also fix depth value for them + a5Door.Depth = -99; + + + var doorEventIndex = 350; + foreach ((var id, var doorLock) in seedObject.DoorLocks) + { + bool found = false; + foreach (var room in gmData.Rooms) + { + foreach (var gameObject in room.GameObjects) + { + if (gameObject.InstanceID != id) continue; + + if (!gameObject.ObjectDefinition.Name.Content.StartsWith("oDoor") && gameObject.ObjectDefinition.Name.Content != "oA2BigTurbine") + throw new NotSupportedException($"The 'door' instance {id} is not actually a door!"); + + found = true; + if (gameObject.CreationCode is null) + { + var code = new UndertaleCode() { Name = gmData.Strings.MakeString($"gml_RoomCC_{room.Name.Content}_{id}_Create") }; + gmData.Code.Add(code); + gameObject.CreationCode = code; + } + + string codeText = doorLock.Lock switch + { + DoorLockType.Normal => "lock = 0; event = -1;", + DoorLockType.Missile => $"lock = 1; originalLock = lock; event = {doorEventIndex};", + DoorLockType.SuperMissile => $"lock = 2; originalLock = lock; event = {doorEventIndex};", + DoorLockType.PBomb => $"lock = 3; originalLock = lock; event = {doorEventIndex};", + DoorLockType.TempLocked => $"lock = 4; originalLock = lock; event = -1;", + DoorLockType.Charge => $"lock = 5; originalLock = lock; event = -1;", + DoorLockType.Wave => $"lock = 6; originalLock = lock; event = -1;", + DoorLockType.Spazer => $"lock = 7; originalLock = lock; event = -1;", + DoorLockType.Plasma => $"lock = 8; originalLock = lock; event = -1;", + DoorLockType.Ice => $"lock = 9; originalLock = lock; event = -1;", + DoorLockType.Bomb => "lock = 10; originalLock = lock; event = -1;", + DoorLockType.Spider => "lock = 11; originalLock = lock; event = -1;", + DoorLockType.Screw => "lock = 12; originalLock = lock; event = -1;", + DoorLockType.TowerEnabled => "lock = 13; originalLock = lock; event = -1;", + DoorLockType.TesterDead => "lock = 14; originalLock = lock; event = -1;", + DoorLockType.GuardianDead => "lock = 15; originalLock = lock; event = -1;", + DoorLockType.ArachnusDead => "lock = 16; originalLock = lock; event = -1;", + DoorLockType.TorizoDead => "lock = 17; originalLock = lock; event = -1;", + DoorLockType.SerrisDead => "lock = 18; originalLock = lock; event = -1;", + DoorLockType.GenesisDead => "lock = 19; originalLock = lock; event = -1;", + DoorLockType.QueenDead => "lock = 20; originalLock = lock; event = -1;", + DoorLockType.EMPActivated => "lock = 21; originalLock = lock; event = -1;", + DoorLockType.EMPA1 => "lock = 22; originalLock = lock; event = -1;", + DoorLockType.EMPA2 => "lock = 23; originalLock = lock; event = -1;", + DoorLockType.EMPA3 => "lock = 24; originalLock = lock; event = -1;", + DoorLockType.EMPA5Tutorial => "lock = 25; originalLock = lock; event = -1;", + DoorLockType.EMPA5RobotHome => "lock = 26; originalLock = lock; event = -1;", + DoorLockType.EMPA5NearZeta => "lock = 27; originalLock = lock; event = -1;", + DoorLockType.EMPA5BulletHell => "lock = 28; originalLock = lock; event = -1;", + DoorLockType.EMPA5PipeHub => "lock = 29; originalLock = lock; event = -1;", + DoorLockType.EMPA5RightExterior => "lock = 30; originalLock = lock; event = -1;", + DoorLockType.Locked => "lock = 31; originalLock = lock; event = -1;", + DoorLockType.A2WaterTurbine => $"eventToSet = {doorEventIndex};" + + $"if (global.event[eventToSet] > 0)" + + $"{{ if (!wasAlreadyDestroyed) {{ with (wall) instance_destroy(); }} instance_destroy();}} " + + $"if (wasAlreadyDestroyed && global.event[eventToSet] < 1) global.event[eventToSet] = 1;", + _ => throw new NotSupportedException($"Door {id} has an unsupported door lock ({doorLock.Lock})!") + }; + + var waterTurbineObject = gmData.GameObjects.ByName("oA2BigTurbine"); + if (gameObject.ObjectDefinition == waterTurbineObject && doorLock.Lock != DoorLockType.A2WaterTurbine) + { + gameObject.ObjectDefinition = gmData.GameObjects.ByName("oDoorA5"); + gameObject.X += (24 * (int)gameObject.ScaleX); + gameObject.ScaleX *= -1; + bool leftFacing = gameObject.ScaleX < 0; + room.Tiles.Add(CreateRoomTile(gameObject.X - (leftFacing ? 8 : 24), gameObject.Y, -110, gmData.Backgrounds.ByName("tlDoor"), (leftFacing ? 0u : 32u), 0, 32, 64)); + var tilesToDelete = room.Tiles.Where((t => (t is { X: 912, Y: 1584, SourceX: 48, SourceY: 304 } or { X: 928, Y: 1536, SourceX: 96, SourceY: 304 }))).ToList(); + foreach (var tile in tilesToDelete) + room.Tiles.Remove(tile); + } + + if (gameObject.ObjectDefinition != waterTurbineObject && doorLock.Lock == DoorLockType.A2WaterTurbine) + { + gameObject.ObjectDefinition = waterTurbineObject; + gameObject.X += (24 * (int)gameObject.ScaleX); + gameObject.ScaleX *= -1; + if ((gameObject.X - 48) == 0) + room.GameObjects.Add(CreateRoomObject(gameObject.X-72, gameObject.Y, gmData.GameObjects.ByName("oSolid1x4"))); + else if ((gameObject.X + 48) == room.Width) + room.GameObjects.Add(CreateRoomObject(gameObject.X+72, gameObject.Y, gmData.GameObjects.ByName("oSolid1x4"))); + + } + + gameObject.CreationCode.AppendGMLInCode( codeText); + doorEventIndex++; + break; + } + + if (found) break; + } + + if (!found) + throw new NotSupportedException($"There is no door with ID {id}!"); + } + } +} diff --git a/YAMS-LIB/patches/qol/DisplayRoomNameOnHUD.cs b/YAMS-LIB/patches/qol/DisplayRoomNameOnHUD.cs new file mode 100644 index 0000000..49b1e85 --- /dev/null +++ b/YAMS-LIB/patches/qol/DisplayRoomNameOnHUD.cs @@ -0,0 +1,139 @@ +using System.Text; +using UndertaleModLib; +using UndertaleModLib.Decompiler; +using UndertaleModLib.Models; + +namespace YAMS_LIB.patches.qol; + +public class DisplayRoomNameOnHUD +{ + public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileContext, SeedObject seedObject) + { + StringBuilder roomNameDSMapBuilder = new StringBuilder(); + foreach ((var roomName, var roomData) in seedObject.RoomObjects) + roomNameDSMapBuilder.Append($"ds_map_add(roomNames, \"{roomName}\", \"{roomData.DisplayName}\");\n"); + string roomNameDSMapString = roomNameDSMapBuilder.ToString(); + + var roomNameHudCC = new UndertaleCode() { Name = gmData.Strings.MakeString("gml_Object_oRoomNameHUD_Create_0") }; + roomNameHudCC.SubstituteGMLCode( $""" + rnh_surface = surface_create((320 + oControl.widescreen_space), 240) + fadeout = 0 + roomtime = 0 + textToDisplay = "" + image_alpha = 0 + offsetY = 0 + displayMode = {(int)seedObject.Cosmetics.RoomNameHud} + textBGColor = 0 + textColor0 = c_white + textColor1 = c_silver + roomNames = ds_map_create() + {roomNameDSMapString} + """); + var roomNameHudDestroy = new UndertaleCode() { Name = gmData.Strings.MakeString("gml_Object_oRoomNameHUD_Destroy_0") }; + roomNameHudDestroy.SubstituteGMLCode( "surface_free(rnh_surface); ds_map_destroy(roomNames)"); + var roomNameHudDrawGui = new UndertaleCode() { Name = gmData.Strings.MakeString("gml_Object_oRoomNameHUD_Draw_64") }; + roomNameHudDrawGui.SubstituteGMLCode( """ + var d; + d = application_get_position() + if (room != rm_transition && instance_exists(oCharacter) && global.ingame && displayMode != 0 && global.opshowhud) + draw_surface_ext(rnh_surface, (oControl.displayx - d[0]), (oControl.displayy - d[1]), oControl.display_scale, oControl.display_scale, 0, -1, 1) + """); + var roomNameHudRoomStart = new UndertaleCode() {Name = gmData.Strings.MakeString("gml_Object_oRoomNameHUD_Other_4")}; + roomNameHudRoomStart.SubstituteGMLCode( """ + var newRoomName = ds_map_find_value(roomNames, room_get_name(room)) + if (global.ingame && textToDisplay != newRoomName) + { + fadeout = 0 + roomtime = 0 + image_alpha = 0 + textToDisplay = newRoomName + } + """); + var roomNameHudStep = new UndertaleCode() { Name = gmData.Strings.MakeString("gml_Object_oRoomNameHUD_Step_0") }; + roomNameHudStep.SubstituteGMLCode( """ + if (displayMode == 0) + exit; + offsetY = 0 + if instance_exists(oIGT) + offsetY = 11 + if global.ingame + { + if (!fadeout) + { + if (image_alpha < 1) + image_alpha += 0.2 + else + fadeout = 1 + } + else if (displayMode == 1 && roomtime > 200 && image_alpha > 0) + image_alpha -= 0.02 + roomtime++ + } + if (surface_exists(rnh_surface) && surface_get_width(rnh_surface) < (320 + oControl.widescreen_space)) + surface_free(rnh_surface) + if (!surface_exists(rnh_surface)) + rnh_surface = surface_create((320 + oControl.widescreen_space), 240) + if surface_exists(rnh_surface) + { + surface_set_target(rnh_surface) + draw_clear_alpha(c_black, 0) + draw_set_font(global.fontGUI2) + draw_set_halign(fa_left) + draw_set_alpha(1) + draw_set_color(c_white) + draw_cool_text(4, (16 + offsetY), textToDisplay, textBGColor, textColor0, textColor1, image_alpha) + surface_reset_target() + } + """); + gmData.Code.Add(roomNameHudCC); + gmData.Code.Add(roomNameHudDestroy); + gmData.Code.Add(roomNameHudDrawGui); + gmData.Code.Add(roomNameHudRoomStart); + gmData.Code.Add(roomNameHudStep); + // Create Object and add events + + var roomHudObject = new UndertaleGameObject() { Name = gmData.Strings.MakeString("oRoomNameHUD"), Depth = -9999999, Persistent = true}; + gmData.GameObjects.Add(roomHudObject); + gmData.Code.ByName("gml_Script_load_character_vars").AppendGMLInCode( "if (!instance_exists(oRoomNameHUD))\ninstance_create(0, 0, oRoomNameHUD)"); + // Create + var roomHudCollisionList = roomHudObject.Events[0]; + var roomHudAction = new UndertaleGameObject.EventAction(); + roomHudAction.CodeId = roomNameHudCC; + var roomHudEvent = new UndertaleGameObject.Event(); + roomHudEvent.EventSubtype = 0; + roomHudEvent.Actions.Add(roomHudAction); + roomHudCollisionList.Add(roomHudEvent); + // Destroy + roomHudCollisionList = roomHudObject.Events[1]; + roomHudAction = new UndertaleGameObject.EventAction(); + roomHudAction.CodeId = roomNameHudDestroy; + roomHudEvent = new UndertaleGameObject.Event(); + roomHudEvent.EventSubtype = 0; + roomHudEvent.Actions.Add(roomHudAction); + roomHudCollisionList.Add(roomHudEvent); + // Step + roomHudCollisionList = roomHudObject.Events[3]; + roomHudAction = new UndertaleGameObject.EventAction(); + roomHudAction.CodeId = roomNameHudStep; + roomHudEvent = new UndertaleGameObject.Event(); + roomHudEvent.EventSubtype = 0; + roomHudEvent.Actions.Add(roomHudAction); + roomHudCollisionList.Add(roomHudEvent); + // Room start + roomHudCollisionList = roomHudObject.Events[7]; + roomHudAction = new UndertaleGameObject.EventAction(); + roomHudAction.CodeId = roomNameHudRoomStart; + roomHudEvent = new UndertaleGameObject.Event(); + roomHudEvent.EventSubtype = 4; + roomHudEvent.Actions.Add(roomHudAction); + roomHudCollisionList.Add(roomHudEvent); + // Draw GUI + roomHudCollisionList = roomHudObject.Events[8]; + roomHudAction = new UndertaleGameObject.EventAction(); + roomHudAction.CodeId = roomNameHudDrawGui; + roomHudEvent = new UndertaleGameObject.Event(); + roomHudEvent.EventSubtype = 64; + roomHudEvent.Actions.Add(roomHudAction); + roomHudCollisionList.Add(roomHudEvent); + } +} diff --git a/YAMS-LIB/patches/qol/DisplayRoomNamesOnMap.cs b/YAMS-LIB/patches/qol/DisplayRoomNamesOnMap.cs new file mode 100644 index 0000000..953d267 --- /dev/null +++ b/YAMS-LIB/patches/qol/DisplayRoomNamesOnMap.cs @@ -0,0 +1,51 @@ +using System.Text; +using UndertaleModLib; +using UndertaleModLib.Decompiler; +using UndertaleModLib.Models; + +namespace YAMS_LIB.patches.qol; + +public class DisplayRoomNamesOnMap +{ + public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileContext, SeedObject seedObject) + { + StringBuilder dsMapCordBuilder = new StringBuilder("room_names_coords = ds_map_create()"); + foreach ((string key, RoomObject value) in seedObject.RoomObjects) + { + foreach (Coordinate coord in value.MinimapData) + { + dsMapCordBuilder.Append($"ds_map_add(room_names_coords, \"{coord.X}|{coord.Y}\", \"{value.RegionName} - {value.DisplayName}\");\n"); + } + } + string DSMapCoordRoomname = dsMapCordBuilder.ToString(); + gmData.Code.ByName("gml_Object_oSS_Fg_Create_0").AppendGMLInCode( DSMapCoordRoomname); + gmData.Code.ByName("gml_Object_oSS_Fg_Draw_0").ReplaceGMLInCode( """ + draw_text((view_xview[0] + 161), ((view_yview[0] + 30) - rectoffset), maptext) + draw_set_color(c_white) + draw_text((view_xview[0] + 160), ((view_yview[0] + 29) - rectoffset), maptext) + """,""" + draw_set_font(global.fontMenuSmall2) + var titleText = maptext; + if (instance_exists(oMapCursor) && oMapCursor.active && oMapCursor.state == 1) + { + titleText = ds_map_find_value(room_names_coords, string(global.mapmarkerx) + "|" + string(global.mapmarkery)); + if (titleText == undefined) + titleText = maptext; + } + draw_text((view_xview[0] + 161), ((view_yview[0] + 29) - rectoffset), titleText); + draw_set_color(c_white); + draw_text((view_xview[0] + 160), ((view_yview[0] + 28) - rectoffset), titleText); + draw_set_font(global.fontGUI2) + """); + var ssFGDestroyCode = new UndertaleCode() { Name = gmData.Strings.MakeString("gml_Object_oSS_Fg_Destroy_0") }; + ssFGDestroyCode.SubstituteGMLCode( "ds_map_destroy(room_names_coords)"); + gmData.Code.Add(ssFGDestroyCode); + var ssFGCollisionList = gmData.GameObjects.ByName("oSS_Fg").Events[1]; + var ssFGAction = new UndertaleGameObject.EventAction(); + ssFGAction.CodeId = ssFGDestroyCode; + var ssFGEvent = new UndertaleGameObject.Event(); + ssFGEvent.EventSubtype = 0; + ssFGEvent.Actions.Add(ssFGAction); + ssFGCollisionList.Add(ssFGEvent); + } +} diff --git a/YAMS-LIB/patches/qol/RoomFeatureMapText.cs b/YAMS-LIB/patches/qol/RoomFeatureMapText.cs new file mode 100644 index 0000000..45a8011 --- /dev/null +++ b/YAMS-LIB/patches/qol/RoomFeatureMapText.cs @@ -0,0 +1,12 @@ +using UndertaleModLib; +using UndertaleModLib.Decompiler; + +namespace YAMS_LIB.patches.qol; + +public class RoomFeatureMapText +{ + public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileContext) + { + gmData.Code.ByName("gml_Object_oSS_Fg_Create_0").ReplaceGMLInCode( "tip2text = get_text(\"Subscreen\", \"Marker_Tip\")", "tip2text = \"| - Marker & Room Names\""); + } +} diff --git a/YAMS-LIB/patches/qol/ShowFullyUnexploredMap.cs b/YAMS-LIB/patches/qol/ShowFullyUnexploredMap.cs new file mode 100644 index 0000000..b7167b8 --- /dev/null +++ b/YAMS-LIB/patches/qol/ShowFullyUnexploredMap.cs @@ -0,0 +1,118 @@ +using UndertaleModLib; +using UndertaleModLib.Decompiler; + +namespace YAMS_LIB.patches.qol; + +public class ShowFullyUnexploredMap +{ + public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileContext, SeedObject seedObject) + { + var characterVarsCode = gmData.Code.ByName("gml_Script_load_character_vars"); + + // Replaces all mentions of sMapBlock and sMapCorner with local variables. + gmData.Code.ByName("gml_Script_draw_mapblock").ReplaceGMLInCode( "sMapBlock", "blockSprite"); + gmData.Code.ByName("gml_Script_draw_mapblock").ReplaceGMLInCode( "sMapCorner", "cornerSprite"); + + // Redefine the sprite variables to the Unexplored sprites, if map tile hasn't been revealed to player. + if (seedObject.Cosmetics.ShowUnexploredMap) + // TODO: don't redefine, but set instead! + characterVarsCode.ReplaceGMLInCode( "global.unexploredMap = 0", "global.unexploredMap = 1;"); + gmData.Code.ByName("gml_Script_draw_mapblock").ReplaceGMLInCode( "if (argument8 > 0)", """ + // variables for swapping map color and corner sprites + var blockSprite, cornerSprite; + + // default sprites + blockSprite = sMapBlock; + cornerSprite = sMapCorner; + + // Don't draw if map tile is a fast travel pipe + if (argument7 != "H" && argument7 != "V" && argument7 != "C") + { + // Sprite variables changed to unexplored variants if map not revealed + if (argument8 == 0 && global.unexploredMap) + { + blockSprite = sMapBlockUnexplored; + cornerSprite = sMapCornerUnexplored; + } + else if (argument8 == 0 && !global.unexploredMap) + exit; + } + """); + // Don't ever draw the debug pipe tiles + gmData.Code.ByName("gml_Script_draw_mapblock").ReplaceGMLInCode( """ + if (argument7 == "H") + draw_sprite(sMapSP, 12, argument0, argument1) + if (argument7 == "V") + draw_sprite(sMapSP, 13, argument0, argument1) + if (argument7 == "C") + draw_sprite(sMapSP, 14, argument0, argument1) + """, ""); + // Also show item pickups and metroids + gmData.Code.ByName("gml_Script_draw_mapblock").ReplaceGMLInCode( "if (argument7 == \"3\" && argument8 == 1)", "if (argument7 == \"3\" && (argument8 == 1 || argument8 == 0))"); + gmData.Code.ByName("gml_Script_draw_mapblock").ReplaceGMLInCode( "if (argument7 == \"4\" && argument8 == 1)", "if (argument7 == \"4\" && (argument8 == 1 || argument8 == 0))"); + // Add hint icons to minimap + gmData.Code.ByName("gml_Script_draw_mapblock").AppendGMLInCode( "if (argument7 == \"W\") draw_sprite(sMapSP, 15, argument0, argument1)"); + // Add "M" condition to Metroid alive icon check + gmData.Code.ByName("gml_Script_draw_mapblock").ReplaceGMLInCode( "if (argument8 == 10)", """if (argument8 == 10 || (argument7 == "M" && global.unexploredMap))"""); + // Draw metroid alive icon on undiscovered map + gmData.Code.ByName("gml_Script_init_map").AppendGMLInCode( """ + global.map[14, 34] = "10111M0" + global.map[15, 29] = "10111M0" + global.map[18, 50] = "10101M0" + global.map[19, 24] = "00112M0" + global.map[21, 15] = "10111M0" + global.map[25, 27] = "10122M0" + global.map[25, 36] = "10112M0" + global.map[25, 42] = "10112M0" + global.map[25, 47] = "10101M0" + global.map[27, 31] = "11101M0" + global.map[30, 17] = "10112M0" + global.map[30, 24] = "11002M0" + global.map[30, 26] = "11002M0" + global.map[35, 19] = "11103M0" + global.map[35, 23] = "21103M0" + global.map[35, 31] = "11103M0" + global.map[37, 33] = "11012M0" + global.map[41, 28] = "11102M0" + global.map[42, 21] = "10102M0" + global.map[42, 37] = "11102M0" + global.map[43, 24] = "10103M0" + global.map[49, 38] = "01101M0" + global.map[54, 16] = "10112M0" + global.map[54, 27] = "10102M0" + global.map[58, 25] = "10112M0" + global.map[58, 28] = "12102M0" + global.map[58, 31] = "00102M0" + global.map[59, 38] = "11001M0" + global.map[60, 16] = "11102M0" + global.map[60, 25] = "11122M0" + global.map[63, 15] = "11102M0" + global.map[64, 33] = "01112M0" + global.map[64, 47] = "10103M0" + global.map[65, 24] = "01013M0" + global.map[67, 25] = "10103M0" + global.map[67, 45] = "10013M0" + global.map[68, 46] = "01103M0" + global.map[69, 9] = "11102M0" + global.map[71, 48] = "11003M0" + global.map[73, 24] = "11102M0" + global.map[73, 31] = "11102M0" + """); + + // Fix BG3 surprise gamma map tile + gmData.Code.ByName("gml_Object_oMGamma_Alarm_9").SubstituteGMLCode( """ + myposx = floor((x / 320)) + myposy = floor(((y - 8) / 240)) + mapposx = (myposx + global.mapoffsetx) + mapposy = (myposy + global.mapoffsety) + if (myid == 20) + { + mapposx = 58 + mapposy = 31 + } + global.dmap[mapposx, mapposy] = 10 + with (oControl) + event_user(2) + """); + } +}