def upgradeHealthContainers(rom): # Reuse 2 unused shop messages for the heart containers. rom.texts[0x2A] = formatText("You found a {HEART_CONTAINER}!") rom.texts[0x2B] = formatText("You lost a heart!") rom.patch(0x03, 0x19DC, ASM(""" ld de, $59D8 call $3BC0 """), ASM(""" ld a, $05 ; renderHeartPiece rst 8 """), fill_nop=True) rom.patch(0x03, 0x19F0, ASM(""" ld hl, $DB5B inc [hl] ld hl, $DB93 ld [hl], $FF """), ASM(""" ld a, $06 ; giveItemMultiworld rst 8 ld a, $0A ; messageForItemMultiworld rst 8 skip: """), fill_nop=True) # add heart->remove heart on heart container
def patch(self, rom, option, *, multiworld=None): assert multiworld is None if self.__index == 0: rom.patch(0x04, 0x37C5, "08", "%02X" % (CHEST_ITEMS[option])) rom.texts[0x030] = formatText("Deluxe {%s} 200 {RUPEES}!" % (option), ask="Buy No Way") elif self.__index == 1: rom.patch(0x04, 0x37C6, "02", "%02X" % (CHEST_ITEMS[option])) rom.texts[0x02C] = formatText("{%s} Only 980 {RUPEES}!" % (option), ask="Buy No Way")
def patch(self, rom, option, *, multiworld=None): assert multiworld is None if self.__index == 0: rom.patch(0x04, 0x37C5, "08", "%02X" % (CHEST_ITEMS[option])) rom.texts[0x030] = formatText(b"Deluxe %s 200 Rupees!" % (INVENTORY_NAME[option]), ask=b"Buy No Way") elif self.__index == 1: rom.patch(0x04, 0x37C6, "02", "%02X" % (CHEST_ITEMS[option])) rom.texts[0x02C] = formatText(b"%s Only 980 Rupees!" % (INVENTORY_NAME[option]), ask=b"Buy No Way")
def addHints(rom, rnd, spots): spots = list(sorted(filter(lambda spot: spot.item in hint_items, spots), key=lambda spot: spot.nameId)) text_ids = hint_text_ids.copy() rnd.shuffle(text_ids) for text_id in text_ids: if len(spots) > 0: spot_index = rnd.randint(0, len(spots) - 1) spot = spots.pop(spot_index) hint = rnd.choice(hints).format("{%s}" % (spot.item), spot.metadata.area) else: hint = rnd.choice(hints).format(*rnd.choice(useless_hint)) rom.texts[text_id] = formatText(hint) for text_id in range(0x200, 0x20C, 2): rom.texts[text_id] = formatText("Read this book?", ask="YES NO")
def addHints(rom, rnd, spots): spots = list(filter(lambda spot: spot.item in hint_items, spots)) text_ids = hint_text_ids.copy() rnd.shuffle(text_ids) for text_id in text_ids: if len(spots) > 0: spot_index = rnd.randint(0, len(spots) - 1) spot = spots.pop(spot_index) hint = rnd.choice(hints).format(INVENTORY_NAME[spot.item].decode("ascii"), spot.metadata.area) else: hint = rnd.choice(hints).format(*rnd.choice(useless_hint)) rom.texts[text_id] = formatText(hint.encode("ascii")) for text_id in range(0x200, 0x20C, 2): rom.texts[text_id] = formatText(b"Read this book?", ask=b"YES NO")
def setupUi(self, Dialog, db, course, chapter, userName): threading.stack_size(1228800) #multiple of 4kB super().setupUi(Dialog) print("\n \n CHAPTER IS", chapter) print(chapter == "1 espace") if (userName == "chloé"): self.answerInput.selectAll() self.answerInput.setFontPointSize(14) self.questionInput.selectAll() self.questionInput.setFontPointSize(14) #self.textSlLabel.setVisible(False) #self.buttonSlLabel.setVisible(False) #self.textPoliceSlider.setVisible(False) #self.buttonPoliceSlider.setVisible(False) self.dialog = Dialog self.__action = "" self.__question = "" self.__answer = "" self.__relPathToDatabase = db self.__course = course self.__chapter = chapter self.__userName = userName self.__formatQ = [] self.__formatA = [] self.confirmButton.pressed.connect( lambda: utils.buttonPressed(self.confirmButton)) self.confirmButton.released.connect( lambda: utils.buttonReleased(self.confirmButton)) self.confirmButton.clicked.connect(self.finish) self.cancelButton.pressed.connect( lambda: utils.buttonPressed(self.cancelButton)) self.cancelButton.released.connect( lambda: utils.buttonReleased(self.cancelButton)) self.cancelButton.clicked.connect(self.cancel) self.newCardButton.pressed.connect( lambda: utils.buttonPressed(self.newCardButton)) self.newCardButton.released.connect( lambda: utils.buttonReleased(self.newCardButton)) self.newCardButton.clicked.connect(self.newCard) #self.textPoliceSlider.setValue(50) #self.textPoliceSlider.valueChanged.connect(self.changeTextPolice) #self.buttonPoliceSlider.setValue(50) #self.buttonPoliceSlider.valueChanged.connect(self.changeButtonPolice) self.formatMenuQ.currentIndexChanged.connect( lambda: utils.formatText(self.formatMenuQ, self.questionInput)) self.formatMenuA.currentIndexChanged.connect( lambda: utils.formatText(self.formatMenuA, self.answerInput))
def insertString(self, string): if string.startswith('"') and string.endswith('"'): self.__result += string[1:-1].encode("ascii") elif string.startswith("m\"") and string.endswith("\""): self.__result += utils.formatText(string[2:-1].replace("|", "\n")) else: raise SyntaxError
def upgradeTunicFairy(rom): rom.texts[0x268] = formatText(b"Welcome, #####. I admire you for coming this far.") rom.texts[0x0CC] = formatText(b"Got the Red Tunic! You can change Tunics at the phone booths.") rom.texts[0x0CD] = formatText(b"Got the Blue Tunic! You can change Tunics at the phone booths.") rom.patch(0x36, 0x111C, 0x1133, ASM(""" call $3B12 ld a, [$DDE1] and $10 jr z, giveItems ld [hl], $09 ret giveItems: ld a, [$DDE1] or $10 ld [$DDE1], a """), fill_nop=True) rom.patch(0x36, 0x1139, 0x1144, ASM(""" ld a, [$51BF] ldh [$F1], a ld a, $02 rst 8 ld a, $03 rst 8 """), fill_nop=True) rom.patch(0x36, 0x1162, 0x1192, ASM(""" ld a, [$51C0] ldh [$F1], a ld a, $02 rst 8 ld a, $03 rst 8 call $3B12 ret """), fill_nop=True) rom.patch(0x36, 0x119D, 0x11A2, "", fill_nop=True) rom.patch(0x36, 0x11B5, 0x11BE, ASM(""" ; Skip to the end ignoring all the tunic giving animation. call $3B12 ld [hl], $09 """), fill_nop=True) rom.banks[0x36][0x11BF] = 0x87 rom.banks[0x36][0x11C0] = 0x88
def data_from_html_table(table): rows = table.find_all('tr') data = [] for row in rows[0:15]: cols = row.find_all('td') value = re.sub(' +', ' ', cols[1].text.strip()) data.append(formatText(value)) if (len(cols) == 4): data.append(cols[3].text.strip()) data.append(rows[15].find('select').text.strip()) return data
def sentimentAnalysisExecute(sentence): obj = {} sentence = ut.formatText(sentence) # res = analyzingSentence(sentence) [vectorSentimentValues, arrWords] = analyzingSentence(sentence) # print("*", vectorSentimentValues, arrWords) semtinentOfSentence = predictSentence(sentence, vectorSentimentValues) obj["sentence"] = sentence obj["score"] = vectorSentimentValues.values[0, :].tolist() obj["predict"] = semtinentOfSentence obj["corpus"] = arrWords return obj
def patch(self, rom, option, *, multiworld=None): assert multiworld is None if self.give_bowwow: option = BOWWOW rom.texts[0xC8] = formatText(b"Got BowWow!") if option != SHIELD: rom.patch( 5, 0x0CDA, ASM("ld a, $22"), ASM("ld a, $00") ) # do not change links sprite into the one with a shield super().patch(rom, option)
def upgradeMadBatter(rom): # Normally the madbatter won't do anything if you have full capacity. Remove that check. rom.patch(0x18, 0x0F05, 0x0F1D, "", fill_nop=True) # Remove the code that finds which upgrade to apply, rom.patch(0x18, 0x0F9E, 0x0FC4, "", fill_nop=True) rom.patch(0x18, 0x0FD2, 0x0FD8, "", fill_nop=True) # Finally, at the last step, give the item and the item message. rom.patch(0x18, 0x1016, 0x101B, "", fill_nop=True) rom.patch(0x18, 0x101E, 0x1051, ASM(""" ; Mad batter rooms are E0,E1 and E2, load the item type from a table in the rom ; which only has 3 entries, and store it where bank 3E wants it. ldh a, [$F6] ; current room and $0F ld d, $00 ld e, a ld hl, $4F90 add hl, de ld a, [hl] ldh [$F1], a ; Give item ld a, $06 ; giveItemMultiworld rst 8 ; Message ld a, $0A ; showMessageMultiworld rst 8 ; Force the dialog at the bottom ld a, [$C19F] or $80 ld [$C19F], a """), fill_nop=True) # Setup the default items rom.patch(0x18, 0x0F90, "406060", "848586") rom.texts[0xE2] = formatText("You can now carry more Magic Powder!") rom.texts[0xE3] = formatText("You can now carry more Bombs!") rom.texts[0xE4] = formatText("You can now carry more Arrows!")
def reduceMessageLengths(rom): # Into text from Marin. Got to go fast, so less text. (This intro text is very long) rom.texts[0x01] = formatText(b"Let's a go!") # Reduce length of a bunch of common texts rom.texts[0xEA] = formatText(b"You've got a Guardian Acorn!") rom.texts[0xEB] = rom.texts[0xEA] rom.texts[0xEC] = rom.texts[0xEA] rom.texts[0x08] = formatText(b"You got a Piece of Power!") rom.texts[0xEF] = formatText(b"You found a Secret Seashell!") rom.texts[0xA7] = formatText(b"You've got the Compass!") rom.texts[0x07] = formatText(b"You need the nightmare key!") rom.texts[0x8C] = formatText(b"You need a key!") # keyhole block
def updateTarin(rom): # Do not give the shield. rom.patch(0x05, 0x0CD0, ASM(""" ld d, $04 call $5321 ld a, $01 ld [$DB44], a """), "", fill_nop=True) # Instead of showing the usual "your shield back" message, give the proper message and give the item. rom.patch(0x05, 0x0CDE, ASM(""" ld a, $91 call $2385 """), ASM(""" ld a, $0B ; GiveItemAndMessageForRoom rst 8 """), fill_nop=True) rom.patch(0x05, 0x0CF0, ASM(""" xor a ldh [$F1], a ld de, $4CC6 call $3C77 """), ASM(""" ld a, $0C ; RenderItemForRoom rst 8 xor a ldh [$F1], a """), fill_nop=True) # Set the room status to finished. (replaces a GBC check) rom.patch(0x05, 0x0CAB, 0x0CB0, ASM(""" ld a, $20 call $36C4 """), fill_nop=True) # Instead of checking for the shield level to put you in the bed, check the room flag. rom.patch(0x05, 0x1202, ASM("ld a, [$DB44]\nand a"), ASM("ldh a, [$F8]\nand $20")) rom.patch(0x05, 0x0C6D, ASM("ld a, [$DB44]\nand a"), ASM("ldh a, [$F8]\nand $20")) # If the starting item is picked up, load the right palette when entering the room rom.patch(0x21, 0x0176, ASM("ld a, [$DB48]\ncp $01"), ASM("ld a, [$DAA3]\ncp $A1"), fill_nop=True) rom.patch(0x05, 0x0C94, "FF473152C5280000", "FD2ED911CE100000") rom.patch(0x05, 0x0CB0, ASM("ld hl, $DC88"), ASM("ld hl, $DC80")) # Patch the text that Tarin uses to give your shield back. rom.texts[0x54] = formatText(b"#####, it is dangerous to go alone!\nTake this!")
def patch(self, rom, option, *, multiworld=None): assert multiworld is None if self.give_bowwow: option = BOWWOW rom.texts[0xC8] = formatText("Got BowWow!") if option != SHIELD: rom.patch( 5, 0x0CDA, ASM("ld a, $22"), ASM("ld a, $00") ) # do not change links sprite into the one with a shield if option in (MAGIC_POWDER, BOMB): re = RoomEditor(rom, 0x0A2) re.entities.append((1, 3, 0x41)) re.store(rom) super().patch(rom, option)
def postTopic(title, content_json, channel, created_at, username, api_key, topic_id): #Set the API user context as the username of whoever wrote the original topic headers = {"Api-Key": api_key, "Api-Username": username} #Set the POST body body = { 'title': title, 'raw': formatText(content_json), 'category': channel, 'created_at': created_at } #Make the API call to the posts endpoint r = requests.post(url='https://community.retool.com/posts.json', data=body, headers=headers) #Declare the topic_mappings dataframe as global to we can write to it global topic_mappings #If the response object has a 'topic_id' key, it was successful; append a row to topic mappings try: discourse_topic_id = json.loads(r.text)['topic_id'] #Use for debugging # print("Topic ID: " + str(discourse_topic_id)) topic_mappings = topic_mappings.append( { 'topic_id': topic_id, 'discourse_topic_id': discourse_topic_id, 'posts_posted': False }, ignore_index=True) #If the request wasn't successful except: #If it's a rate limit error, write the new data to the topic mappings csv and get outta here try: if r['error_type'] == 'rate_limit': topic_mappings.to_csv('topic_mappings.csv') raise #If it's another kind of error, let it go and print the response text except: print(json.loads(r.text))
def postPost(api_key, username, discourse_topic_id, content_json, created_at): #Set the API user context as the username of whoever wrote the original topic headers = {"Api-Key": api_key, "Api-Username": username} #Define POST body (gee, a lot of the word "post" in here) post_body = { 'topic_id': discourse_topic_id, 'raw': formatText(content_json), 'created_at': created_at } #Use for debugging if you'd like #print("Topic ID: " + str(discourse_topic_id)) #POST message r = requests.post('https://community.retool.com/posts.json', data=post_body, headers=headers) #Declare the topic_mappings dataframe as global to we can write to it global topic_mappings #If the post was successfully created, the response will have 'id' in it if 'id' in json.loads(r.text).keys(): print("Post successfully added") #If we got rate limited, the response will have 'error_type' in it elif 'error_type' in json.loads(r.text).keys(): time.sleep(60) #If there's a different type of error, print the response else: print(r.text) #Set posts_posted in topic_mappings to True idx = topic_mappings[topic_mappings['discourse_topic_id'] == discourse_topic_id].index[0] topic_mappings.loc[idx, 'posts_posted'] = True #Write the new information to the topic mappings CSV topic_mappings.to_csv('topic_mappings.csv')
def setupUi(self, dialog, username, data, database, databaseFile, itemsToStudy, isRandom, spacingMistakes, minPointsRequired): threading.stack_size(1228800) #multiple of 4kB super().setupUi(dialog) self.__userName = username self.__isRandom = isRandom self.__dialog = dialog self.__data = data self.__database = database self.__databaseFile = databaseFile self.__itemsToStudy = [] for s in itemsToStudy : #splitting string to get parent and child in a list i = s.split("{") if len(i) > 1: self.__itemsToStudy.append(i) else: self.__itemsToStudy.append(i[0]) self.__indexChapter = 0 self.__index = -1 self.__nOfQuestions = 0 self.__course = self.__itemsToStudy[0] if type(self.__itemsToStudy[0]) is str else self.__itemsToStudy[0][0] self.__chapter = None if type(self.__itemsToStudy[0]) is str else self.__itemsToStudy[0][1] self.__nOfCoursesToStudy = len([item for item in self.__itemsToStudy if (type(item) is str)]) lCoursesToStudy = [] self.__nOfChaptersToStudy = len([item for item in self.__itemsToStudy if type(item) is not str]) for item in self.__itemsToStudy : if type(item) is not str : if item[0] not in lCoursesToStudy : lCoursesToStudy.append(item[0]) self.__nOfCoursesToStudy += 1 else : #item is a course self.__nOfChaptersToStudy += self.getNumberOfChapters(item) self.__question = "" self.__answer = "" self.__formatA = [] self.__formatQ = [] self.__coursesDone = 0 self.__chaptersDone = 0 self.__neededWork = [] self.__playbackCounter = 0 self.__spacingMistakes = spacingMistakes if spacingMistakes > 2 else 3 self.__unAnsweredQuestions = [] self.getAllQuestionsByIndex() self.__pointsRequired = 1 if minPointsRequired > 1 : self.__pointsRequired = minPointsRequired #self.__pointsRequired = 2 if isRandom else 1 self.__prevQIsWrong = False self.__qActive = True self.validateQButton.setVisible(False) self.needWorkButton.setVisible(False) self.cancelChangeButton.setVisible(False) self.validateChangeButton.setVisible(False) self.formatMenu.setVisible(False) self.nextQuestion() self.viewAnswerButton.clicked.connect(self.viewAnswer) self.stopButton.clicked.connect(self.stop) self.needWorkButton.clicked.connect(self.needsWork) self.validateQButton.clicked.connect(self.validateQuestion) self.validateChangeButton.clicked.connect(self.validateChange) self.cancelChangeButton.clicked.connect(self.cancelChange) self.editButton.clicked.connect(self.edit) self.formatMenu.currentIndexChanged.connect(lambda:utils.formatText(self.formatMenu, self.displayQA)) for button in self.__dialog.findChildren(QtWidgets.QPushButton): button.pressed.connect(lambda:utils.buttonPressed(button)) button.released.connect(lambda:utils.buttonReleased(button))
def assemble(self, line): if ";" in line: line = line[:line.find(";")] input_line = line.strip() line = line.strip().replace("\t", " ").upper() while " " in line: line = line.strip().replace(" ", " ") if line.endswith(":"): line = line[:-1] if line.startswith("."): assert self.__scope + line not in self.__label, "Duplicate label: %s" % (self.__scope + line) self.__label[self.__scope + line] = len(self.__result) else: assert "." not in line, line assert line not in self.__label, "Duplicate label: %s" % (line) self.__label[line] = len(self.__result) self.__scope = line return if len(line) < 1: return if " " in line: mnemonic, params = line.split(" ", 1) params = list(map(str.strip, params.split(","))) else: mnemonic = line params = [] if mnemonic == "NOP": assert len(params) == 0, line self.__result.append(0x00) elif mnemonic == "HALT": assert len(params) == 0, line self.__result.append(0x76) elif mnemonic == "STOP": assert len(params) == 0, line self.__result.append(0x10) elif mnemonic == "DI": assert len(params) == 0, line self.__result.append(0xF3) elif mnemonic == "EI": assert len(params) == 0, line self.__result.append(0xFB) elif mnemonic == "RLA": assert len(params) == 0, line self.__result.append(0x17) elif mnemonic == "RLCA": assert len(params) == 0, line self.__result.append(0x07) elif mnemonic == "RRA": assert len(params) == 0, line self.__result.append(0x1f) elif mnemonic == "RRCA": assert len(params) == 0, line self.__result.append(0x0f) elif mnemonic == "DAA": assert len(params) == 0, line self.__result.append(0x27) elif mnemonic == "SCF": assert len(params) == 0, line self.__result.append(0x37) elif mnemonic == "CPL": assert len(params) == 0, line self.__result.append(0x2F) elif mnemonic == "CCF": assert len(params) == 0, line self.__result.append(0x3F) elif mnemonic == "JP": if len(params) == 2: flag = FLAGS[params[0]] self.__result.append(0xC2 | flag) self.__result += self.toWord(params[1]) elif len(params) == 1: if params[0] == "HL": self.__result.append(0xE9) else: self.__result.append(0xC3) self.__result += self.toWord(params[0]) else: raise RuntimeError("Cannot ASM: %s" % (line)) elif mnemonic == "JR": if len(params) == 2: self.__result.append(0x20 | FLAGS[params[0]]) params.pop(0) else: self.__result.append(0x18) assert len(params) == 1, line if params[0].startswith("$"): self.__result.append(self.toByte(params[0])) else: if params[0].startswith("."): assert self.__scope is not None, line params[0] = self.__scope + params[0] self.__link[len(self.__result)] = (Assembler.LINK_REL8, params[0]) self.__result.append(0) elif mnemonic == "RETI": self.__result.append(0xD9) elif mnemonic == "RET": if len(params) == 0: self.__result.append(0xC9) elif len(params) == 1: self.__result.append(0xC0 | FLAGS[params[0]]) else: raise RuntimeError("Cannot ASM: %s" % (line)) elif mnemonic == "RST": assert len(params) == 1, line value = int(params[0], 16) assert (value & 0x07) == 0, line assert 0 <= value < 0x40, line self.__result.append(0xC7 + value) elif mnemonic == "PUSH": assert len(params) == 1, line if params[0] == "BC": self.__result.append(0xC5) elif params[0] == "DE": self.__result.append(0xD5) elif params[0] == "HL": self.__result.append(0xE5) elif params[0] == "AF": self.__result.append(0xF5) else: raise RuntimeError("Cannot ASM: %s" % (line)) elif mnemonic == "POP": assert len(params) == 1, line if params[0] == "BC": self.__result.append(0xC1) elif params[0] == "DE": self.__result.append(0xD1) elif params[0] == "HL": self.__result.append(0xE1) elif params[0] == "AF": self.__result.append(0xF1) else: raise RuntimeError("Cannot ASM: %s" % (line)) elif mnemonic == "LDI": assert len(params) == 2, line if params[0] == "A" and params[1] == "[HL]": self.__result.append(0x2A) elif params[0] == "[HL]" and params[1] == "A": self.__result.append(0x22) else: raise RuntimeError("Cannot ASM: %s" % (line)) elif mnemonic == "LDD": assert len(params) == 2, line if params[0] == "A" and params[1] == "[HL]": self.__result.append(0x3A) elif params[0] == "[HL]" and params[1] == "A": self.__result.append(0x32) else: raise RuntimeError("Cannot ASM: %s" % (line)) elif mnemonic == "LD": assert len(params) == 2, line dst = REGS.get(params[0]) src = REGS.get(params[1]) if params[0] == "A" and src is None and params[1].startswith("[") and params[1].endswith("]"): if params[1] == "[BC]": self.__result.append(0x0A) elif params[1] == "[DE]": self.__result.append(0x1A) elif params[1] == "[C]": self.__result.append(0xF2) else: self.__result.append(0xFA) self.__result += self.toWord(params[1][1:-1]) elif params[1] == "A" and dst is None and params[0].startswith("[") and params[0].endswith("]"): if params[0] == "[BC]": self.__result.append(0x02) elif params[0] == "[DE]": self.__result.append(0x12) elif params[0] == "[C]": self.__result.append(0xE2) else: self.__result.append(0xEA) self.__result += self.toWord(params[0][1:-1]) elif params[1] == "SP" and dst is None and params[0].startswith("[") and params[0].endswith("]"): self.__result.append(0x08) self.__result += self.toWord(params[0][1:-1]) elif params[0] == "BC": self.__result.append(0x01) self.__result += self.toWord(params[1]) elif params[0] == "DE": self.__result.append(0x11) self.__result += self.toWord(params[1]) elif params[0] == "HL": self.__result.append(0x21) self.__result += self.toWord(params[1]) elif params[0] == "SP" and params[1] == "HL": self.__result.append(0xF9) elif params[0] == "SP": self.__result.append(0x31) self.__result += self.toWord(params[1]) elif dst is not None and src is not None: assert src != 6 or dst != 6, line self.__result.append(0x40 | src | (dst << 3)) elif dst is not None: self.__result.append(0x06 | (dst << 3)) self.__result.append(self.toByte(params[1])) else: raise RuntimeError("Cannot ASM: %s" % (line)) elif mnemonic == "ADD": assert len(params) == 2, line src = REGS.get(params[1]) if params[0] == "A" and src is not None: self.__result.append(0x80 | src) elif params[0] == "A": self.__result.append(0xC6) self.__result.append(self.toByte(params[1])) elif params[0] == "HL" and params[1] == "BC": self.__result.append(0x09) elif params[0] == "HL" and params[1] == "DE": self.__result.append(0x19) elif params[0] == "HL" and params[1] == "HL": self.__result.append(0x29) elif params[0] == "HL" and params[1] == "SP": self.__result.append(0x39) elif params[0] == "SP": self.__result.append(0xE8) self.__result.append(self.toByte(params[1])) else: raise RuntimeError("Cannot ASM: %s" % (line)) elif mnemonic == "SUB": assert len(params) == 1, line reg = REGS.get(params[0]) if reg is not None: self.__result.append(0x90 | reg) else: self.__result.append(0xD6) self.__result.append(self.toByte(params[0])) elif mnemonic == "ADC": assert len(params) == 2, line assert params[0] == 'A', line reg = REGS.get(params[1]) if reg is not None: self.__result.append(0x88 | reg) else: self.__result.append(0xCE) self.__result.append(self.toByte(params[1])) elif mnemonic == "SBC": assert len(params) == 2, line assert params[0] == 'A', line reg = REGS.get(params[1]) if reg is not None: self.__result.append(0x98 | reg) else: self.__result.append(0xDE) self.__result.append(self.toByte(params[1])) elif mnemonic == "XOR": assert len(params) == 1, line reg = REGS.get(params[0]) if reg is not None: self.__result.append(0xA8 | reg) else: self.__result.append(0xEE) self.__result.append(self.toByte(params[0])) elif mnemonic == "AND": assert len(params) == 1, line reg = REGS.get(params[0]) if reg is not None: self.__result.append(0xA0 | reg) else: self.__result.append(0xE6) self.__result.append(self.toByte(params[0])) elif mnemonic == "OR": assert len(params) == 1, line reg = REGS.get(params[0]) if reg is not None: self.__result.append(0xB0 | reg) else: self.__result.append(0xF6) self.__result.append(self.toByte(params[0])) elif mnemonic == "CP": assert len(params) == 1, line reg = REGS.get(params[0]) if reg is not None: self.__result.append(0xB8 | reg) else: self.__result.append(0xFE) self.__result.append(self.toByte(params[0])) elif mnemonic == "INC": assert len(params) == 1, line reg = REGS.get(params[0]) if reg is not None: self.__result.append(0x04 | (reg << 3)) elif params[0] == "BC": self.__result.append(0x03) elif params[0] == "DE": self.__result.append(0x13) elif params[0] == "HL": self.__result.append(0x23) elif params[0] == "SP": self.__result.append(0x33) else: raise RuntimeError("Cannot ASM: %s" % (line)) elif mnemonic == "DEC": assert len(params) == 1, line reg = REGS.get(params[0]) if reg is not None: self.__result.append(0x05 | (reg << 3)) elif params[0] == "BC": self.__result.append(0x0B) elif params[0] == "DE": self.__result.append(0x1B) elif params[0] == "HL": self.__result.append(0x2B) elif params[0] == "SP": self.__result.append(0x3B) else: raise RuntimeError("Cannot ASM: %s" % (line)) elif mnemonic == "LDH": assert len(params) == 2, line if params[0] == "A" and params[1].startswith("[") and params[1].endswith("]"): self.__result.append(0xF0) self.__result.append(self.toByte(params[1][1:-1])) elif params[1] == "A" and params[0].startswith("[") and params[0].endswith("]"): self.__result.append(0xE0) self.__result.append(self.toByte(params[0][1:-1])) else: raise RuntimeError("Cannot ASM: %s" % (line)) elif mnemonic == "BIT": assert len(params) == 2, line reg = REGS[params[1]] bit = int(params[0]) assert 0 <= bit < 8, line self.__result.append(0xCB) self.__result.append(0x40 | reg | (bit << 3)) elif mnemonic == "RES": assert len(params) == 2, line reg = REGS[params[1]] bit = int(params[0]) assert 0 <= bit < 8 self.__result.append(0xCB) self.__result.append(0x80 | reg | (bit << 3)) elif mnemonic == "SET": assert len(params) == 2 reg = REGS[params[1]] bit = int(params[0]) assert 0 <= bit < 8 self.__result.append(0xCB) self.__result.append(0xC0 | reg | (bit << 3)) elif mnemonic == "RLC": assert len(params) == 1 reg = REGS[params[0]] self.__result.append(0xCB) self.__result.append(0x00 | reg) elif mnemonic == "RRC": assert len(params) == 1 reg = REGS[params[0]] self.__result.append(0xCB) self.__result.append(0x08 | reg) elif mnemonic == "RL": assert len(params) == 1 reg = REGS[params[0]] self.__result.append(0xCB) self.__result.append(0x10 | reg) elif mnemonic == "RR": assert len(params) == 1 reg = REGS[params[0]] self.__result.append(0xCB) self.__result.append(0x18 | reg) elif mnemonic == "SLA": assert len(params) == 1 reg = REGS[params[0]] self.__result.append(0xCB) self.__result.append(0x20 | reg) elif mnemonic == "SRA": assert len(params) == 1 reg = REGS[params[0]] self.__result.append(0xCB) self.__result.append(0x28 | reg) elif mnemonic == "SWAP": assert len(params) == 1 reg = REGS[params[0]] self.__result.append(0xCB) self.__result.append(0x30 | reg) elif mnemonic == "SRL": assert len(params) == 1 reg = REGS[params[0]] self.__result.append(0xCB) self.__result.append(0x38 | reg) elif mnemonic == "CALL": if len(params) == 1: self.__result.append(0xCD) self.__result += self.toWord(params[0]) elif len(params) == 2: flag = FLAGS[params[0]] self.__result.append(0xC4 | flag) self.__result += self.toWord(params[1]) else: raise RuntimeError("Cannot ASM: %s" % (line)) elif mnemonic == "DB": for param in map(str.strip, input_line[2:].strip().split(",")): if param.startswith("\"") and param.endswith("\""): self.__result += param[1:-1].encode("ascii") elif param.startswith("m\"") and param.endswith("\""): self.__result += utils.formatText(param[2:-1].encode("ascii")) else: self.__result.append(self.toByte(param.strip())) elif mnemonic == "DW": for byte in params: self.__result += self.toWord(byte) else: raise RuntimeError("Cannot ASM: %s" % (line))
def addBank3E(rom, seed): # No default text for getting the bow, so use an unused slot. rom.texts[0x89] = formatText("Found the {BOW}!") rom.texts[0xD9] = formatText( "Found the {BOOMERANG}!") # owl text slot reuse rom.texts[0xBE] = rom.texts[ 0x111] # owl text slot reuse to get the master skull message in the first dialog group rom.texts[0xC8] = formatText( "Found {BOWWOW}! Which monster put him in a chest? He is a good boi, and waits for you at the Swamp." ) rom.texts[0xC9] = 0xC0A0 # Custom message slot rom.texts[0xCA] = formatText("Found {ARROWS_10}!") rom.texts[0xCB] = formatText("Found a {SINGLE_ARROW}... joy?") # Create a trampoline to bank 0x3E in bank 0x00. # There is very little room in bank 0, so we set this up as a single trampoline for multiple possible usages. # the A register is preserved and can directly be used as a jumptable in page 3E. # Trampoline at rst 8 # the A register is preserved and can directly be used as a jumptable in page 3E. rom.patch(0, 0x0008, "0000000000000000000000000000", ASM(""" ld h, a ld a, [$DBAF] push af ld a, $3E call $080C ; switch bank ld a, h jp $4000 """), fill_nop=True) # Special trampoline to jump to the damage-entity code, we use this from bowwow to damage instead of eat. rom.patch( 0x00, 0x0018, "000000000000000000000000000000", ASM(""" ld a, $03 ld [$2100], a call $71C0 ld a, [$DBAF] ld [$2100], a ret """)) my_path = os.path.dirname(__file__) rom.patch( 0x3E, 0x0000, 0x3000, ASM( """ call MainJumpTable pop af jp $080C ; switch bank and return to normal code. MainJumpTable: rst 0 ; JUMP TABLE dw MainLoop ; 0 dw RenderChestItem ; 1 dw GiveItemFromChest ; 2 dw ItemMessage ; 3 dw RenderDroppedKey ; 4 dw RenderHeartPiece ; 5 dw GiveItemFromChestMultiworld ; 6 dw CheckIfLoadBowWow ; 7 dw BowwowEat ; 8 dw HandleOwlStatue ; 9 dw ItemMessageMultiworld ; A dw GiveItemAndMessageForRoom ; B dw RenderItemForRoom ; C dw StartGameMarinMessage ; D StartGameMarinMessage: ; Injection to reset our frame counter call $27D0 ; Enable SRAM ld hl, $B000 xor a ldi [hl], a ;subsecond counter ld a, $08 ;(We set the counter to 8 seconds, as it takes 8 seconds before link wakes up and marin talks to him) ldi [hl], a ;second counter xor a ldi [hl], a ;minute counter ldi [hl], a ;hour counter ld hl, $B010 ldi [hl], a ;check counter low ldi [hl], a ;check counter high ; Show the normal message ld a, $01 jp $2385 """ + open(os.path.join(my_path, "bank3e.asm/multiworld.asm"), "rt").read() + open(os.path.join(my_path, "bank3e.asm/link.asm"), "rt").read() + open(os.path.join(my_path, "bank3e.asm/chest.asm"), "rt").read() + open(os.path.join(my_path, "bank3e.asm/bowwow.asm"), "rt").read() + open(os.path.join(my_path, "bank3e.asm/message.asm"), "rt").read() + open(os.path.join(my_path, "bank3e.asm/owl.asm"), "rt").read(), 0x4000), fill_nop=True) # 3E:3300-3616: Multiworld flags per room (for both chests and dropped keys) # 3E:3800-3B16: DroppedKey item types # 3E:3B16-3E2C: Owl statue items # Put 20 rupees in all owls by default. rom.patch(0x3E, 0x3B16, "00" * 0x316, "1C" * 0x316) rom.patch(0x3E, 0x2F00, "00" * len(seed), binascii.hexlify(seed)) # Prevent the photo album from crashing due to serial interrupts rom.patch(0x28, 0x00D2, ASM("ld a, $09"), ASM("ld a, $01"))
def addBank3E(rom, seed): # No default text for getting the bow, so use an unused slot. rom.texts[0x89] = formatText(b"Found the bow!") rom.texts[0xD9] = formatText( b"Found the boomerang!") # owl text slot reuse rom.texts[0xBE] = rom.texts[ 0x111] # owl text slot reuse to get the master skull message in the first dialog group for idx in range(8): rom.texts[0xBF + idx] = b"" rom.texts[0xC7] = b"" rom.texts[0xC8] = formatText( b"Found BowWow! Which monster put him in a chest? He is a good boi, and waits for you at the Swamp." ) rom.texts[0xC9] = 0xC0A0 # Custom message slot rom.texts[0xCA] = formatText(b"Found 10 arrows!") rom.texts[0xCB] = formatText(b"Found a single arrow... joy?") # Create a trampoline to bank 0x3E in bank 0x00. # There is very little room in bank 0, so we set this up as a single trampoline for multiple possible usages. # the A register is preserved and can directly be used as a jumptable in page 3E. # Trampoline at rst 8 # the A register is preserved and can directly be used as a jumptable in page 3E. rom.patch(0, 0x0008, "0000000000000000000000000000", ASM(""" ld h, a ld a, [$DBAF] push af ld a, $3E call $080C ; switch bank ld a, h jp $4000 """), fill_nop=True) # Special trampoline to jump to the damage-entity code, we use this from bowwow to damage instead of eat. rom.patch( 0x00, 0x0018, "000000000000000000000000000000", ASM(""" ld a, $03 ld [$2100], a call $71C0 ld a, [$DBAF] ld [$2100], a ret """)) my_path = os.path.dirname(__file__) rom.patch( 0x3E, 0x0000, 0x3000, ASM( """ call MainJumpTable pop af jp $080C ; switch bank and return to normal code. MainJumpTable: rst 0 ; JUMP TABLE dw MainLoop ; 0 dw RenderChestItem ; 1 dw GiveItemFromChest ; 2 dw ItemMessage ; 3 dw RenderDroppedKey ; 4 dw RenderHeartPiece ; 5 dw GiveItemFromChestMultiworld ; 6 dw CheckIfLoadBowWow ; 7 dw BowwowEat ; 8 dw HandleOwlStatue ; 9 dw ItemMessageMultiworld ; A dw GiveItemAndMessageForRoom ; B dw RenderItemForRoom ; C """ + open(os.path.join(my_path, "bank3e.asm/link.asm"), "rt").read() + open(os.path.join(my_path, "bank3e.asm/chest.asm"), "rt").read() + open(os.path.join(my_path, "bank3e.asm/bowwow.asm"), "rt").read() + open(os.path.join(my_path, "bank3e.asm/message.asm"), "rt").read() + open(os.path.join(my_path, "bank3e.asm/owl.asm"), "rt").read(), 0x4000), fill_nop=True) # 3E:3300-3616: Multiworld flags per room (for both chests and dropped keys) # 3E:3800-3B16: DroppedKey item types # 3E:3B16-3E2C: Owl statue items # Put 20 rupees in all owls by default. rom.patch(0x3E, 0x3B16, "00" * 0x316, "1C" * 0x316) rom.patch(0x3E, 0x2F00, "00" * len(seed), binascii.hexlify(seed))
def setSeashellGoal(rom, count): rom.texts[0x1A3] = formatText(b"You need %d seashells" % (count)) # Remove the seashell mansion handler (as it will take your seashells) but put a heartpiece instead re = RoomEditor(rom, 0x2E9) re.entities = [(4, 4, 0x35)] re.store(rom) rom.patch(0x19, 0x0ACB, 0x0C21, ASM( """ ldh a, [$F8] ; room status and $10 ret nz ldh a, [$F0] ; active entity state rst 0 dw state0, state1, state2, state3, state4 state0: ld a, [$C124] ; room transition state and a ret nz ldh a, [$99] ; link position Y cp $70 ret nc jp $3B12 ; increase entity state state1: call $0C05 ; get entity transition countdown jr nz, renderShells ld [hl], $10 call renderShells ld hl, $C2B0 ; private state 1 table add hl, bc ld a, [wSeashellsCount] cp [hl] jp z, $3B12 ; increase entity state ld a, [hl] ; increase the amount of compared shells inc a daa ld [hl], a ld hl, $C2C0 ; private state 2 table add hl, bc inc [hl] ; increase amount of displayed shells ld a, $2B ldh [$F4], a ; SFX ret state2: ld a, [wSeashellsCount] cp $%02d jr c, renderShells ; got enough shells call $3B12 ; increase entity state call $0C05 ; get entity transition countdown ld [hl], $40 jp renderShells state3: ld a, $23 ldh [$F2], a ; SFX: Dungeon opened ld hl, $D806 ; egg room status set 4, [hl] ld a, [hl] ldh [$F8], a ; current room status call $3B12 ; increase entity state ld a, $00 jp $4C2E state4: ret renderShells: ld hl, $C2C0 ; private state 2 table add hl, bc ld a, [hl] cp $14 jr c, .noMax ld a, $14 .noMax: and a ret z ld c, a ld hl, spriteRect call $3CE6 ; RenderActiveEntitySpritesRect ret spriteRect: db $10, $1E, $1E, $0C db $10, $2A, $1E, $0C db $10, $36, $1E, $0C db $10, $42, $1E, $0C db $10, $4E, $1E, $0C db $10, $5A, $1E, $0C db $10, $66, $1E, $0C db $10, $72, $1E, $0C db $10, $7E, $1E, $0C db $10, $8A, $1E, $0C db $24, $1E, $1E, $0C db $24, $2A, $1E, $0C db $24, $36, $1E, $0C db $24, $42, $1E, $0C db $24, $4E, $1E, $0C db $24, $5A, $1E, $0C db $24, $66, $1E, $0C db $24, $72, $1E, $0C db $24, $7E, $1E, $0C db $24, $8A, $1E, $0C """ % (count), 0x4ACB), fill_nop=True)
def patch(self, rom, option, *, multiworld=None): assert multiworld is None # Always have the boomerang trade guy enabled (normally you need the magnifier) rom.patch(0x19, 0x05EC, ASM("ld a, [wTradeSequenceItem]\ncp $0E"), ASM("ld a, $0E\ncp $0E"), fill_nop=True) # show the guy rom.patch(0x00, 0x3199, ASM("ld a, [wTradeSequenceItem]\ncp $0E"), ASM("ld a, $0E\ncp $0E"), fill_nop=True) # load the proper room layout if self.setting == 'trade': inv = INVENTORY_MAP[option] # Patch the check if you traded back the boomerang (so traded twice) rom.patch(0x19, 0x063F, ASM("cp $0D"), ASM("cp $%s" % (inv))) # Item to give by "default" (aka, boomerang) rom.patch(0x19, 0x06C1, ASM("ld a, $0D"), ASM("ld a, $%s" % (inv))) # Check if inventory slot is boomerang to give back item in this slot rom.patch(0x19, 0x06FC, ASM("cp $0D"), ASM("cp $%s" % (inv))) # Put the boomerang ID in the inventory of the boomerang guy (aka, traded back) rom.patch(0x19, 0x0710, ASM("ld a, $0D"), ASM("ld a, $%s" % (inv))) rom.texts[0x222] = formatText("Okay, let's do it!") rom.texts[0x224] = formatText( "You got the {%s} in exchange for the item you had." % (option)) rom.texts[0x225] = formatText( "Give me back my {%s}, I beg you! I'll return the item you gave me" % (option), ask="Okay Not Now") rom.texts[0x226] = formatText( "The item came back to you. You returned the other item.") else: # Patch the inventory trade to give an specific item instead rom.texts[0x221] = formatText( "I found a good item washed up on the beach... Want to have it?", ask="Okay No") rom.patch(0x19, 0x069C, 0x06C6, ASM(""" ; Mark trade as done ld a, $06 ld [$DB7D], a ld a, [$472B] ldh [$F1], a ld a, $02 rst 8 ld a, $0D """), fill_nop=True) # Show the right item above link rom.patch(0x19, 0x0786, 0x0793, ASM(""" ld a, [$472B] ldh [$F1], a ld a, $01 rst 8 """), fill_nop=True) # Give the proper message for this item rom.patch(0x19, 0x075A, 0x076A, ASM(""" ld a, [$472B] ldh [$F1], a ld a, $03 rst 8 """), fill_nop=True) rom.patch(0x19, 0x072B, "00", "%02X" % (CHEST_ITEMS[option])) # Ignore the trade back. rom.texts[0x225] = formatText("It's a secret to everybody.") rom.patch(0x19, 0x0668, ASM("ld a, [$DB7D]"), ASM("ret"), fill_nop=True)
def setRaftGoal(rom): rom.texts[0x1A3] = formatText(b"Just sail away.") # Remove the egg and egg event handler. re = RoomEditor(rom, 0x006) for x in range(4, 7): for y in range(0, 4): re.removeObject(x, y) re.objects.append(ObjectHorizontal(4, 1, 0x4d, 3)) re.objects.append(ObjectHorizontal(4, 2, 0x03, 3)) re.objects.append(ObjectHorizontal(4, 3, 0x03, 3)) re.entities = [] re.updateOverlay() re.store(rom) re = RoomEditor(rom, 0x08D) re.objects[6].count = 4 re.objects[7].x += 2 re.objects[7].type_id = 0x2B re.objects[8].x += 2 re.objects[8].count = 2 re.objects[9].x += 1 re.objects[11] = ObjectVertical(7, 5, 0x37, 2) re.objects[12].x -= 1 re.objects[13].x -= 1 re.objects[14].x -= 1 re.objects[14].type_id = 0x34 re.objects[17].x += 3 re.objects[17].count -= 3 re.updateOverlay() re.overlay[7 + 60] = 0x33 re.store(rom) re = RoomEditor(rom, 0x0E9) re.objects[30].count = 1 re.objects[30].x += 2 re.overlay[7 + 70] = 0x0E re.overlay[8 + 70] = 0x0E re.store(rom) re = RoomEditor(rom, 0x0F9) re.objects = [ ObjectHorizontal(4, 0, 0x0E, 6), ObjectVertical(9, 0, 0xCA, 8), ObjectVertical(8, 0, 0x0E, 8), Object(3, 0, 0x38), Object(3, 1, 0x32), ObjectHorizontal(4, 1, 0x2C, 3), Object(7, 1, 0x2D), ObjectVertical(7, 2, 0x38, 5), Object(7, 7, 0x34), ObjectHorizontal(0, 7, 0x2F, 7), ObjectVertical(2, 3, 0xE8, 4), ObjectVertical(3, 2, 0xE8, 5), ObjectVertical(4, 2, 0xE8, 2), ObjectVertical(4, 4, 0x5C, 3), ObjectVertical(5, 2, 0x5C, 5), ObjectVertical(6, 2, 0x5C, 5), Object(6, 4, 0xC6), ObjectWarp(1, 0x1F, 0xF6, 136, 112) ] re.updateOverlay(True) re.entities.append((0, 0, 0x41)) re.store(rom) re = RoomEditor(rom, 0x1F6) re.objects[-1].target_x -= 16 re.store(rom) # Fix the raft graphics (this overrides some unused graphic tiles) rom.banks[0x31][0x21C0:0x2200] = rom.banks[0x2E][0x07C0:0x0800] # Patch the owl entity to run our custom end handling. rom.patch(0x06, 0x27F5, 0x2A77, ASM(""" ld a, [$DB95] cp $0B ret nz ; If map is not fully loaded, return ld a, [$C124] and a ret nz ; Check if we are moving off the bottom of the map ldh a, [$99] cp $7D ret c ; Move link back so it does not move off the map ld a, $7D ldh [$99], a xor a ld e, a ld d, a raftSearchLoop: ld hl, $C280 add hl, de ld a, [hl] and a jr z, .skipEntity ld hl, $C3A0 add hl, de ld a, [hl] cp $6A jr nz, .skipEntity ; Raft found, check if near the bottom of the screen. ld hl, $C210 add hl, de ld a, [hl] cp $70 jr nc, raftOffWorld .skipEntity: inc e ld a, e cp $10 jr nz, raftSearchLoop ret raftOffWorld: ; Switch to the end credits ld a, $01 ld [$DB95], a ld a, $00 ld [$DB96], a ret """), fill_nop=True) # We need to run quickly trough part of the credits, or else it bugs out # Skip the whole windfish part. rom.patch(0x17, 0x0D39, None, ASM("ld a, $18\nld [$D00E], a\nret")) # And skip the zoomed out laying on the log rom.patch(0x17, 0x20ED, None, ASM("ld a, $00")) # Finally skip some waking up on the log. rom.patch(0x17, 0x23BC, None, ASM("jp $4CD9")) rom.patch(0x17, 0x2476, None, ASM("jp $4CD9"))
def setRequiredInstrumentCount(rom, count): if count >= 8: return if count < 0: rom.patch(0x00, 0x31f5, ASM("ld a, [$D806]\nand $10\njr z, $25"), ASM(""), fill_nop=True) rom.patch(0x20, 0x2dea, ASM("ld a, [$D806]\nand $10\njr z, $29"), ASM(""), fill_nop=True) count = 0 # TODO: Music bugs out at the end, unless you have all instruments. rom.texts[0x1A3] = formatText(b"You need %d instruments" % (count)) rom.patch( 0x19, 0x0B79, None, "0000" ) # always spawn all instruments, we need the last one as that handles opening the egg. rom.patch(0x19, 0x0BF4, ASM("jp $3BC0"), ASM("jp $7FE0") ) # instead of rendering the instrument, jump to the code below. rom.patch(0x19, 0x0BFE, ASM(""" ; Normal check fo all instruments ld e, $08 ld hl, $DB65 loop: ldi a, [hl] and $02 jr z, $12 dec e jr nz, loop """), ASM(""" jp $7F2B ; jump to the end of the bank, where there is some space for code. """), fill_nop=True) # Add some code at the end of the bank, as we do not have enough space to do this "in place" rom.patch(0x19, 0x3F2B, "0000000000000000000000000000000000000000000000000000", ASM(""" ld d, $00 ld e, $08 ld hl, $DB65 ; start of has instrument memory loop: ld a, [hl] and $02 jr z, noinc inc d noinc: inc hl dec e jr nz, loop ld a, d cp $%02x ; check if we have a minimal of this amount of instruments. jp c, $4C1A ; not enough instruments jp $4C0B ; enough instruments """ % (count)), fill_nop=True) rom.patch(0x19, 0x3FE0, "0000000000000000000000000000000000000000000000000000", ASM(""" ; Entry point of render code ld hl, $DB65 ; table of having instruments push bc ldh a, [$F1] ld c, a add hl, bc pop bc ld a, [hl] and $02 ; check if we have this instrument ret z jp $3BC0 ; jump to render code """), fill_nop=True)
def fixChests(rom): # Patch the chest code, so it can give a lvl1 sword. # Normally, there is some code related to the owl event when getting the tail key, # as we patched out the owl. We use it to jump to our custom code in bank $3E to handle getting the item rom.patch(0x03, 0x109C, ASM(""" cp $11 ; if not tail key, skip jr nz, end push af ld a, [$C501] ld e, a ld hl, $C2F0 add hl, de ld [hl], $38 pop af end: ld e, a cp $21 ; if is message chest or higher number, next instruction is to skip giving things. """), ASM(""" ld a, $06 ; GiveItemMultiworld rst 8 and a ; clear the carry flag to always skip giving stuff. """), fill_nop=True) # Instead of the normal logic to on which sprite data to show, we jump to our custom code in bank 3E. rom.patch(0x07, 0x3C36, None, ASM(""" ld a, $01 rst 8 jp $7C5E """), fill_nop=True) # Instead of the normal logic of showing the proper dialog, we jump to our custom code in bank 3E. rom.patch( 0x07, 0x3C9C, None, ASM(""" ld a, $0A ; showItemMessageMultiworld rst 8 jp $7CE9 """)) # Sound to play is normally loaded from a table, which is no longer big enough. So always use the same sound. rom.patch(0x07, 0x3C81, ASM(""" add hl, de ld a, [hl] """), ASM("ld a, $01"), fill_nop=True) # Always spawn seashells even if you have the L2 sword rom.patch(0x14, 0x192F, ASM("ld a, $1C"), ASM("ld a, $20")) rom.texts[0x9A] = formatText("You found 10 {BOMB}!")
def setupUi(self, Dialog, data, databaseFile, course, userName, chapter = None): threading.stack_size(1228800) #multiple of 4kB super().setupUi(Dialog) #self.fullScreenSize = QtWidgets.QDesktopWidget().availableGeometry().size() if (userName == "chloé"): self.displayAnswer.selectAll() self.displayAnswer.setFontPointSize(14) self.displayQuestion.selectAll() self.displayQuestion.setFontPointSize(14) #self.sliderButtonLabel.setVisible(False) #self.sliderTextLabel.setVisible(False) #self.textPoliceSlider.setVisible(False) #self.buttonPoliceSlider.setVisible(False) self.dialog = Dialog self.__action = "" self.__data = data self.__databaseFile = databaseFile self.__course = course self.__chapter = chapter self.__userName = userName self.__currentChapter = "" self.__question = "" self.__answer = "" self.__index = 0 self.__indexChapter = 0 self.__formatQ = [] self.__formatA = [] if self.__chapter is not None : self.__indexChapter = self.getIndexOfChapter() self.__numberOfQInChapter = 0 self.validateChangeButton.setVisible(False) self.deleteButton.pressed.connect(lambda:utils.buttonPressed(self.deleteButton)) self.deleteButton.released.connect(lambda:utils.buttonReleased(self.deleteButton)) self.deleteButton.clicked.connect(self.delete) self.editButton.pressed.connect(lambda:utils.buttonPressed(self.editButton)) self.editButton.released.connect(lambda:utils.buttonReleased(self.editButton)) self.editButton.clicked.connect(self.edit) self.stopButton.pressed.connect(lambda:utils.buttonPressed(self.stopButton)) self.stopButton.released.connect(lambda:utils.buttonReleased(self.stopButton)) self.stopButton.clicked.connect(self.stop) self.nextButton.pressed.connect(lambda:utils.buttonPressed(self.nextButton)) self.nextButton.released.connect(lambda:utils.buttonReleased(self.nextButton)) self.nextButton.clicked.connect(self.next) self.previousButton.pressed.connect(lambda:utils.buttonPressed(self.previousButton)) self.previousButton.released.connect(lambda:utils.buttonReleased(self.previousButton)) self.previousButton.clicked.connect(self.previous) self.insertButton.pressed.connect(lambda:utils.buttonPressed(self.insertButton)) self.insertButton.released.connect(lambda:utils.buttonReleased(self.insertButton)) self.insertButton.clicked.connect(self.insert) #self.displayAnswer.setAutoFormatting(QtWidgets.QTextEdit.AutoBulletList) #self.displayQuestion.setAutoFormatting(QtWidgets.QTextEdit.AutoBulletList) self.displayChapter.setText(self.getchapterFromIndex()) #self.textPoliceSlider.setValue(50) #self.textPoliceSlider.valueChanged.connect(self.changeTextPolice) #self.buttonPoliceSlider.setValue(50) #self.buttonPoliceSlider.valueChanged.connect(self.changeButtonPolice) self.readyToValidate = False self.validateChangeButton.clicked.connect(self.validateChange) self.displayChapter.repaint() self.validateChangeButton.repaint() self.display() self.formatMenuQ.setVisible(False) self.formatMenuQ.currentIndexChanged.connect(lambda:utils.formatText(self.formatMenuQ, self.displayQuestion)) self.formatMenuA.setVisible(False) self.formatMenuA.currentIndexChanged.connect(lambda:utils.formatText(self.formatMenuA, self.displayAnswer))
def reduceMessageLengths(rom, rnd): # Into text from Marin. Got to go fast, so less text. (This intro text is very long) rom.texts[0x01] = formatText( rnd.choice([ "Let's a go!", "Remember, sword goes on A!", "Avoid the heart piece of shame!", "Marin? No, this is Zelda. Welcome to Hyrule", "Why are you in my bed?", "This is not a Mario game!", "MuffinJets was here...", "Remember, there are no bugs in LADX", "#####, #####, you got to wake up!\nDinner is ready.", "Go find the stepladder", "Pizza power!", "Eastmost penninsula is the secret", "There is no cow level", "You cannot lift rocks with your bear hands", ])) # Reduce length of a bunch of common texts rom.texts[0xEA] = formatText("You've got a Guardian Acorn!") rom.texts[0xEB] = rom.texts[0xEA] rom.texts[0xEC] = rom.texts[0xEA] rom.texts[0x08] = formatText("You got a Piece of Power!") rom.texts[0xEF] = formatText("You found a {SEASHELL}!") rom.texts[0xA7] = formatText("You've got the {COMPASS}!") rom.texts[0x07] = formatText("You need the {NIGHTMARE_KEY}!") rom.texts[0x8C] = formatText("You need a {KEY}!") # keyhole block rom.texts[0x09] = formatText( "Ahhh... It has the Sleepy {TOADSTOOL}, it does! We'll mix it up something in a jiffy, we will!" ) rom.texts[0x0A] = formatText( "The last thing I kin remember was bitin' into a big juicy {TOADSTOOL}... Then, I had the darndest dream... I was a raccoon! Yeah, sounds strange, but it sure was fun!" ) rom.texts[0x0F] = formatText( "You pick the {TOADSTOOL}... As you hold it over your head, a mellow aroma flows into your nostrils." ) rom.texts[0x13] = formatText( "You've learned the ^{SONG1}!^ This song will always remain in your heart!" ) rom.texts[0x18] = formatText("Will you give me 28 {RUPEES} for my secret?", ask="Give Don't") rom.texts[0x19] = formatText( "How about it? 42 {RUPEES} for my little secret...", ask="Give Don't") rom.texts[0x1e] = formatText( "...You're so cute! I'll give you a 7 {RUPEE} discount!") rom.texts[0x2d] = formatText("{ARROWS_10}\n10 {RUPEES}!", ask="Buy Don't") rom.texts[0x32] = formatText("{SHIELD}\n20 {RUPEES}!", ask="Buy Don't") rom.texts[0x33] = formatText("Ten {BOMB}\n10 {RUPEES}", ask="Buy Don't") rom.texts[0x3d] = formatText( "It's a {SHIELD}! There is space for your name!") rom.texts[0x42] = formatText( "It's 30 {RUPEES}! You can play the game three more times with this!") rom.texts[0x45] = formatText( "How about some fishing, little buddy? I'll only charge you 10 {RUPEES}...", ask="Fish Not Now") rom.texts[0x4b] = formatText( "Wow! Nice Fish! It's a lunker!! I'll give you a 20 {RUPEE} prize! Try again?", ask="Cast Not Now") rom.texts[0x4e] = formatText( "You're short of {RUPEES}? Don't worry about it. You just come back when you have more money, little buddy." ) rom.texts[0x4f] = formatText( "You've got a {HEART_PIECE}! Press SELECT on the Subscreen to see.") rom.texts[0x8e] = formatText( "Well, it's an {OCARINA}, but you don't know how to play it...") rom.texts[0x90] = formatText( "You found the {POWER_BRACELET}! At last, you can pick up pots and stones!" ) rom.texts[0x91] = formatText( "You got your {SHIELD} back! Press the button and repel enemies with it!" ) rom.texts[0x93] = formatText( "You've got the {HOOKSHOT}! Its chain stretches long when you use it!") rom.texts[0x94] = formatText( "You've got the {MAGIC_ROD}! Now you can burn things! Burn it! Burn, baby burn!" ) rom.texts[0x95] = formatText( "You've got the {PEGASUS_BOOTS}! If you hold down the Button, you can dash!" ) rom.texts[0x96] = formatText( "You've got the {OCARINA}! You should learn to play many songs!") rom.texts[0x97] = formatText( "You've got the {FEATHER}! It feels like your body is a lot lighter!") rom.texts[0x98] = formatText( "You've got a {SHOVEL}! Now you can feel the joy of digging!") rom.texts[0x99] = formatText( "You've got some {MAGIC_POWDER}! Try sprinkling it on a variety of things!" ) rom.texts[0x9b] = formatText( "You found your {SWORD}! It must be yours because it has your name engraved on it!" ) rom.texts[0x9c] = formatText( "You've got the {FLIPPERS}! If you press the B Button while you swim, you can dive underwater!" ) rom.texts[0x9e] = formatText( "You've got a new {SWORD}! You should put your name on it right away!") rom.texts[0x9f] = formatText( "You've got a new {SWORD}! You should put your name on it right away!") rom.texts[0xa0] = formatText( "You found the {MEDICINE}! You should apply this and see what happens!" ) rom.texts[0xa1] = formatText( "You've got the {TAIL_KEY}! Now you can open the Tail Cave gate!") rom.texts[0xa2] = formatText( "You've got the {SLIME_KEY}! Now you can open the gate in Ukuku Prairie!" ) rom.texts[0xa3] = formatText("You've got the {ANGLER_KEY}!") rom.texts[0xa4] = formatText("You've got the {FACE_KEY}!") rom.texts[0xa5] = formatText("You've got the {BIRD_KEY}!") rom.texts[0xa6] = formatText( "At last, you got a {MAP}! Press the START Button to look at it!") rom.texts[0xa8] = formatText( "You found a {STONE_BEAK}! Let's find the owl statue that belongs to it." ) rom.texts[0xa9] = formatText( "You've got the {NIGHTMARE_KEY}! Now you can open the door to the Nightmare's Lair!" ) rom.texts[0xaa] = formatText( "You got a {KEY}! You can open a locked door.") rom.texts[0xab] = formatText("You got 20 {RUPEES}! JOY!", center=True) rom.texts[0xac] = formatText("You got 50 {RUPEES}! Very Nice!", center=True) rom.texts[0xad] = formatText("You got 100 {RUPEES}! You're Happy!", center=True) rom.texts[0xae] = formatText("You got 200 {RUPEES}! You're Ecstatic!", center=True) rom.texts[0xdc] = formatText( "Ribbit! Ribbit! I'm Mamu, on vocals! But I don't need to tell you that, do I? Everybody knows me! Want to hang out and listen to us jam? For 300 Rupees, we'll let you listen to a previously unreleased cut! What do you do?", ask="Pay Leave") rom.texts[0xe8] = formatText( "You've found a {GOLD_LEAF}! Press START to see how many you've collected!" ) rom.texts[0xed] = formatText( "You've got the Mirror Shield! You can now turnback the beams you couldn't block before!" ) rom.texts[0xee] = formatText( "You've got a more Powerful {POWER_BRACELET}! Now you can almost lift a whale!" ) rom.texts[0xf0] = formatText( "Want to go on a raft ride for a hundred {RUPEES}?", ask="Yes No Way")
def patch(self, rom, option, *, multiworld=None): assert multiworld is None if self.give_bowwow: option = BOWWOW rom.texts[0xC8] = formatText(b"Got BowWow!") rom.patch(0x05, 0x0CD0, 0x0CDA, ASM(""" ld a, $01 ld [$DB56], a """), fill_nop=True) rom.patch(0x05, 0x0CF3, ASM("ld de, $4CC6\ncall $3C77"), ASM("ld de, $401C\ncall $3BC0")) rom.patch( 5, 0x0CDA, ASM("ld a, $22"), ASM("ld a, $00") ) # do not change links sprite into the one with a shield else: # Change which item you get at the start. rom.patch(5, 0x0CD1, "04", INVENTORY_MAP[option]) rom.patch(5, 0x0CC6, "8617", INVENTORY_ICON[option] ) # patch shield that icon that is shown. if option != SHIELD: rom.patch( 5, 0x0CDA, ASM("ld a, $22"), ASM("ld a, $00") ) # do not change links sprite into the one with a shield # Do not set the shield level to 1, but potentially set another item level if needed. if option == SWORD: # TOFIX: This directly hides marin and tarin rom.patch(5, 0x0CD7, ASM("ld [$DB44], a"), ASM("ld [$DB4E], a"), fill_nop=True) elif option == POWER_BRACELET: rom.patch(5, 0x0CD7, ASM("ld [$DB44], a"), ASM("ld [$DB43], a"), fill_nop=True) else: rom.patch(5, 0x0CD7, ASM("ld [$DB44], a"), "", fill_nop=True) # Patch the text that Tarin uses to give your shield back. rom.texts[0x54] = formatText( b"#####, it is dangerous to go alone!\nTake this!") rom.patch(5, 0x0CDE, ASM("ld a, $91"), ASM("ld a, $%02x" % (self.MESSAGE[option]))) rom.patch(0x05, 0x0CAB, 0x0CB0, ASM(""" ; Set the room status to finished. ld a, $20 call $36C4 """), fill_nop=True) # Instead of checking for the shield level to put you in the bed, check the room flag. rom.patch(0x05, 0x1202, ASM("ld a, [$DB44]\nand a"), ASM("ldh a, [$F8]\nand $20")) rom.patch(0x05, 0x0C6D, ASM("ld a, [$DB44]\nand a"), ASM("ldh a, [$F8]\nand $20")) # If the starting item is picked up, load the right palette when entering the room rom.patch(0x21, 0x0176, ASM("ld a, [$DB48]\ncp $01"), ASM("ld a, [$DAA3]\ncp $A1"), fill_nop=True) rom.patch(0x05, 0x0C94, "FF473152C5280000", "FD2ED911CE100000") rom.patch(0x05, 0x0CB0, ASM("ld hl, $DC88"), ASM("ld hl, $DC80"))
def removeOwlEvents(rom): # Remove all the owl events from the entity tables. for room in range(0x100): re = RoomEditor(rom, room) if re.hasEntity(0x41): re.removeEntities(0x41) re.store(rom) # Clear texts used by the owl. Potentially reused somewhere o else. rom.texts[0x0D9] = b'\xff' # used by boomerang # 1 Used by empty chest (master stalfos message) # 8 unused (0x0C0-0x0C7) # 1 used by bowwow in chest # 1 used by item for other player message # 2 used by arrow chest messages # 2 used by tunics for idx in range(0x0BE, 0x0CE): rom.texts[idx] = b'\xff' # Patch the owl entity into a ghost to allow refill of powder/bombs/arrows rom.texts[0xC0] = formatText("Everybody hates me, so I give away free things in the hope people will love me. Want something?", ask="Okay No") rom.texts[0xC1] = formatText("Good for you.") rom.patch(0x06, 0x27F5, 0x2A77, ASM(""" ; Check if we have powder or bombs. ld e, INV_SIZE ld hl, $DB00 loop: ldi a, [hl] cp $02 ; bombs jr z, hasProperItem cp $0C ; powder jr z, hasProperItem cp $05 ; bow jr z, hasProperItem dec e jr nz, loop ret hasProperItem: ; Render ghost ld de, sprite call $3BC0 call $64C6 ; check if game is busy (pops this stack frame if busy) ldh a, [$E7] ; frame counter swap a and $01 call $3B0C ; set entity sprite variant call $641A ; check collision ldh a, [$F0] ;entity state rst 0 dw waitForTalk dw talking waitForTalk: call $645D ; check if talked to ret nc ld a, $C0 call $2385 ; open dialog call $3B12 ; increase entity state ret talking: ; Check if we are still talking ld a, [$C19F] and a ret nz call $3B12 ; increase entity state ld [hl], $00 ; set to state 0 ld a, [$C177] ; get which option we selected and a ret nz ; Give powder ld a, [$DB4C] cp $10 jr nc, doNotGivePowder ld a, $10 ld [$DB4C], a doNotGivePowder: ld a, [$DB4D] cp $10 jr nc, doNotGiveBombs ld a, $10 ld [$DB4D], a doNotGiveBombs: ld a, [$DB45] cp $10 jr nc, doNotGiveArrows ld a, $10 ld [$DB45], a doNotGiveArrows: ld a, $C1 call $2385 ; open dialog ret sprite: db $76, $09, $78, $09, $7A, $09, $7C, $09 """, 0x67F5), fill_nop=True) rom.patch(0x20, 0x0322 + 0x41 * 2, "734A", "564B") # Remove the owl init handler re = RoomEditor(rom, 0x2A3) re.entities.append((7, 6, 0x41)) re.store(rom)