|
| 1 | +-- Written by Frost |
| 2 | + |
| 3 | + |
| 4 | +console.clear() |
| 5 | + |
| 6 | +package.loaded["./resources/libs/sotn"] = nil |
| 7 | +SOTN = require("./resources/libs/sotn") |
| 8 | + |
| 9 | + |
| 10 | +local TITLE = "SotN-RandomStartRoom - v1.0.0" |
| 11 | +UTILS.TITLE = TITLE |
| 12 | + |
| 13 | +HAS_ROM_HASH = gameinfo.getromhash() ~= "" |
| 14 | +if not HAS_ROM_HASH then |
| 15 | + UTILS.message(TITLE, 'Start Castlevania - SotN first!', 'ok', 'warning') |
| 16 | +elseif mainmemory.readbyte(0x03C734) == 2 then |
| 17 | + UTILS.message(TITLE, 'Stop your game first!', 'ok', 'warning') |
| 18 | + HAS_ROM_HASH = false |
| 19 | +end |
| 20 | + |
| 21 | + |
| 22 | +UTILS.pause() |
| 23 | + |
| 24 | +local room = ROOMS.getRoom() |
| 25 | +local iColor = tonumber |
| 26 | +local dialog = {} |
| 27 | +-- print(JSON:encode_pretty(room)) |
| 28 | +-- print(JSON:encode_pretty(UTILS.settings)) |
| 29 | + |
| 30 | + |
| 31 | +local function setMap(reset) |
| 32 | + local w = room.map.w or 15 |
| 33 | + local h = room.map.h or 15 |
| 34 | + local x = w * (room.map.x+2) |
| 35 | + local y = h * room.map.y |
| 36 | + local scale = 1.25 |
| 37 | + local size = 11/scale |
| 38 | + x = (x - scale)/scale |
| 39 | + y = (y - scale)/scale |
| 40 | + |
| 41 | + if reset and dialog.group then |
| 42 | + forms.clear(dialog.group, iColor(UTILS.settings.color.Clear)) |
| 43 | + end |
| 44 | + dialog.group = forms.pictureBox(dialog.bg, 0, 20, 986/scale, 731/scale) |
| 45 | + forms.drawRectangle(dialog.group, 0, 0, 986/scale, 731/scale, iColor(UTILS.settings.color.Black), iColor(UTILS.settings.color.Black)) |
| 46 | + local image |
| 47 | + if room.vs == 0x38 then |
| 48 | + image = UTILS.settings.images.rvsd |
| 49 | + elseif room.vs == 0x18 then |
| 50 | + image = UTILS.settings.images.rvsr |
| 51 | + elseif not room.map.inv then |
| 52 | + image = UTILS.settings.images.map1 |
| 53 | + elseif room.map.inv == 2 then |
| 54 | + image = UTILS.settings.images.map2 |
| 55 | + elseif room.map.inv == 3 then |
| 56 | + image = UTILS.settings.images.map3 |
| 57 | + end |
| 58 | + if image then |
| 59 | + forms.drawImage(dialog.group, image, size, size, 964/scale, 709/scale, true) |
| 60 | + end |
| 61 | + |
| 62 | + if not room.vs then |
| 63 | + forms.drawEllipse(forms.pictureBox(dialog.group, x, y, size, size), |
| 64 | + x, y, size, size, iColor(UTILS.settings.color.Black), iColor(UTILS.settings.pointer.color)) |
| 65 | + end |
| 66 | + |
| 67 | + forms.settext(dialog.descList, string.format("%d. %s", room.pos+1, room.desc)) |
| 68 | + forms.refresh(dialog.group) |
| 69 | +end |
| 70 | + |
| 71 | +local eventtime = os.clock() |
| 72 | +local function eventLists() |
| 73 | + local selected = forms.gettext(dialog.colorList) |
| 74 | + if UTILS.settings.color[selected] ~= UTILS.settings.pointer.color then |
| 75 | + UTILS.settings.pointer.color = UTILS.settings.color[selected] |
| 76 | + setMap() |
| 77 | + end |
| 78 | + |
| 79 | + if os.clock() - eventtime > 0.5 then |
| 80 | + selected = forms.gettext(dialog.descList) |
| 81 | + if ROOMS.rooms[ROOMS.descToIndex[selected]] ~= room then |
| 82 | + room = ROOMS.rooms[ROOMS.descToIndex[selected]] |
| 83 | + setMap() |
| 84 | + end |
| 85 | + eventtime = os.clock() |
| 86 | + end |
| 87 | +end |
| 88 | + |
| 89 | +local function showDialog() |
| 90 | + forms.destroyall() |
| 91 | + dialog.bg = forms.newform(UTILS.settings.coords.w, UTILS.settings.coords.h, |
| 92 | + TITLE, function(x) dialog.cancel=true end) |
| 93 | + UTILS.centerWindow(dialog.bg) |
| 94 | + |
| 95 | + dialog.descList = forms.dropdown(dialog.bg, {room.desc}, 0, 0, 590, 794) |
| 96 | + forms.setdropdownitems(dialog.descList, ROOMS.droplist, false) |
| 97 | + -- forms.addclick(dialog.descList, function(x) eventLists() end) |
| 98 | + |
| 99 | + local space = 30 |
| 100 | + local posx, posy = 626, 20 |
| 101 | + forms.button(dialog.bg, "RANDOM ROOM", function(x) |
| 102 | + room = ROOMS.getRoom() |
| 103 | + setMap(true) |
| 104 | + end, posx, posy, 145, 25) |
| 105 | + forms.button(dialog.bg, "RICHTER VS. DRACULA", function(x) |
| 106 | + room = ROOMS.getRoom(0x38) |
| 107 | + room.vs = 0x38 |
| 108 | + setMap(true) |
| 109 | + end, posx, posy+space, 145, 25) |
| 110 | + forms.button(dialog.bg, "RICHTER VS. RICHTER", function(x) |
| 111 | + room = ROOMS.getRoom(0x18) |
| 112 | + room.vs = 0x18 |
| 113 | + setMap(true) |
| 114 | + end, posx, posy+(space*2), 145, 25) |
| 115 | + forms.button(dialog.bg, "OK", function(x) |
| 116 | + if mainmemory.readbyte(0x03C734) == 8 then |
| 117 | + dialog.okClicked = true |
| 118 | + forms.destroy(dialog.bg) |
| 119 | + else |
| 120 | + UTILS.message(TITLE, forms.gettext(dialog.statusLBL)) |
| 121 | + end |
| 122 | + end, posx, posy+(space*3), 145, 25) |
| 123 | + |
| 124 | + -- Info game |
| 125 | + posx, posy = 596, 145 |
| 126 | + forms.label(dialog.bg, "GAME", posx+87, posy, 64, 15) |
| 127 | + forms.pictureBox(dialog.bg, posx, posy+15, 270, 1) -- used as seperator |
| 128 | + forms.label(dialog.bg, gameinfo.getromname(), posx, posy+20, 200, 15) |
| 129 | + forms.label(dialog.bg, "Hash: "..gameinfo.getromhash(), posx, posy+35, 200, 15) |
| 130 | + forms.label(dialog.bg, "Seed :\nPreset :\nVersion :", posx, posy+48, 45, 45) |
| 131 | + dialog.gInfo = forms.label(dialog.bg, SOTN.getSeed(), posx+42, posy+48, 155, 45) |
| 132 | + |
| 133 | + -- Info status |
| 134 | + posy = 240 |
| 135 | + forms.label(dialog.bg, "STATUS", posx+80.5, posy, 64, 15) |
| 136 | + forms.pictureBox(dialog.bg, posx, posy+15, 270, 1) -- used as seperator |
| 137 | + dialog.statusLBL = forms.label(dialog.bg, "Busy", posx, posy+20, 200, 155) |
| 138 | + |
| 139 | + -- Options |
| 140 | + posy = 415 |
| 141 | + forms.label(dialog.bg, "OPTIONS", posx+79, posy, 64, 15) |
| 142 | + forms.pictureBox(dialog.bg, posx, posy+15, 270, 1) -- used as seperator |
| 143 | + |
| 144 | + forms.label(dialog.bg, "Room color:", posx, posy+29, 64, 15) |
| 145 | + local list = {} |
| 146 | + for name, i in pairs(UTILS.settings.color) do table.insert(list, name) end |
| 147 | + dialog.colorList = forms.dropdown(dialog.bg, list, posx+65, posy+25, 135, 100) |
| 148 | + forms.settext(dialog.colorList , "Green") |
| 149 | + |
| 150 | + forms.pictureBox(dialog.bg, posx, 470, 270, 1) -- used as seperator |
| 151 | + forms.label(dialog.bg, "Powered by Frost", 716, 475, 100, 15) |
| 152 | + |
| 153 | + setMap() |
| 154 | +end |
| 155 | + |
| 156 | +local oldstatus |
| 157 | +local function setStatusLabel() |
| 158 | + if dialog.statusLBL then |
| 159 | + local st = mainmemory.readbyte(0x03C734) |
| 160 | + if st ~= oldstatus then |
| 161 | + -- print("new status: "..st) |
| 162 | + oldstatus = st |
| 163 | + local text = "Busy" |
| 164 | + if st == 1 then |
| 165 | + text = 'On game "Press Start Button",\nGo to in "File Select".\nAnd on this window press "OK" button.' |
| 166 | + elseif st == 8 then |
| 167 | + text = 'Press "OK" button, wait 3 secondes and Start New Game.' |
| 168 | + end |
| 169 | + |
| 170 | + if st == 1 or st == 8 then |
| 171 | + cut1, cut2 = SOTN.getCutScene() |
| 172 | + if cut1 and cut1 ~= 26 then |
| 173 | + text = text .. '\n\nRemenber,\nYour game version is not fully compatible with this tool. Use original game or use this code "800A2988 001A" by default this tool enable this code, but make sure this code enabled all times with this tool.' |
| 174 | + end |
| 175 | + end |
| 176 | + forms.settext(dialog.statusLBL, text) |
| 177 | + forms.refresh(dialog.statusLBL) |
| 178 | + end |
| 179 | + end |
| 180 | +end |
| 181 | + |
| 182 | + |
| 183 | +local addEquip = true |
| 184 | +local cheatAdded = 0 |
| 185 | +local stime = 0 -- time start entering In Select your Destiny or In File Select |
| 186 | +local sleep = 3 -- time to sleep in secs before activate cheat |
| 187 | +function checkStartGame() |
| 188 | + local status = mainmemory.readbyte(0x03C734) |
| 189 | + if addEquip and status == 4 then |
| 190 | + SOTN.setEquip(room) |
| 191 | + elseif status == 2 then |
| 192 | + -- In Game |
| 193 | + if cheatAdded == 1 then |
| 194 | + client.removecheat('D00974A0 00' .. bizstring.hex(room.pos)) |
| 195 | + client.removecheat('8003C9A0 0001') -- desable richter |
| 196 | + cheatAdded = 2 |
| 197 | + end |
| 198 | + elseif status == 8 then |
| 199 | + -- In Select your Destiny or In File Select |
| 200 | + if stime == 0 then |
| 201 | + stime = os.time() + sleep |
| 202 | + end |
| 203 | + if cheatAdded == 0 and os.time() > stime then |
| 204 | + client.removecheat('8003C9A0 0001') -- desable richter |
| 205 | + if room.vs == 0x18 or room.vs == 0x38 then |
| 206 | + client.addcheat('8003C9A0 0001') -- enable richter |
| 207 | + print("Cheat: Force play as Richter") |
| 208 | + end |
| 209 | + client.addcheat('8003CAFC 0000') -- Stereo On |
| 210 | + print("Cheat: Stereo On") |
| 211 | + client.addcheat('D00974A0 00' .. bizstring.hex(room.pos)) -- set start room |
| 212 | + cut1, cut2 = SOTN.getCutScene() |
| 213 | + if cut1 and cut1 ~= 26 then |
| 214 | + client.addcheat('800A2988 001A') -- Remove Maria cut scene patched by SotN-Randomizer |
| 215 | + print("Cheat: Maria uncut scene") |
| 216 | + end |
| 217 | + cheatAdded = 1 |
| 218 | + end |
| 219 | + end |
| 220 | +end |
| 221 | + |
| 222 | +event.onexit(function(x) |
| 223 | + UTILS.saveSettings(UTILS.settings) |
| 224 | + forms.destroyall() |
| 225 | + UTILS.destroymsgid() |
| 226 | + UTILS.unpause() |
| 227 | + client.removecheat('D00974A0 0000') |
| 228 | + client.removecheat('8003C9A0 0001') -- desable richter |
| 229 | +end) |
| 230 | + |
| 231 | +if not HAS_ROM_HASH or mainmemory.readbyte(0x03C734) ~= 2 then |
| 232 | + client.removecheat('800A2988 001A') |
| 233 | + client.removecheat('D00974A0 0000') |
| 234 | + client.removecheat('8003C9A0 0001') -- desable richter |
| 235 | + client.removecheat('8003CAFC 0000') -- Stereo On |
| 236 | + client.removecheat('8003C4E6 BCAA') -- Save Palette |
| 237 | +end |
| 238 | + |
| 239 | +if HAS_ROM_HASH then |
| 240 | + UTILS.showHawk() |
| 241 | + showDialog() |
| 242 | +end |
| 243 | + |
| 244 | +UTILS.unpause() |
| 245 | + |
| 246 | +local hasinfo |
| 247 | +while HAS_ROM_HASH do |
| 248 | + if dialog.okClicked or dialog.cancel then |
| 249 | + break -- End of script |
| 250 | + else |
| 251 | + if not hasinfo then |
| 252 | + local gi = forms.gettext(dialog.gInfo) |
| 253 | + if not gi or gi == "" then |
| 254 | + forms.settext(dialog.gInfo, SOTN.getSeed()) |
| 255 | + else |
| 256 | + hasinfo = true |
| 257 | + end |
| 258 | + end |
| 259 | + setStatusLabel() |
| 260 | + eventLists() |
| 261 | + end |
| 262 | + emu.yield() |
| 263 | +end |
| 264 | + |
| 265 | +if dialog.okClicked then |
| 266 | + addEquip = room.pos ~= 0x1F and room.pos ~= 0X3F and room.pos ~= 0x41 |
| 267 | + while true do |
| 268 | + if cheatAdded == 2 then |
| 269 | + if addEquip then |
| 270 | + SOTN.setupGame(room) |
| 271 | + end |
| 272 | + print(JSON:encode_pretty(room)) |
| 273 | + break -- End of script |
| 274 | + end |
| 275 | + checkStartGame() |
| 276 | + emu.frameadvance() |
| 277 | + end |
| 278 | +end |
0 commit comments