#ttpatch.py #Patch a vanilla angband save file so that the character is level 20 with recall level 20. #In addition, the player is given one extra scroll of recall, well actually enough gold for another one. import sys xp_lvl_20_base = 4400.0; prace = {"Human":0, "Half-Elf":1, "Elf":2, "Hobbit":3, "Gnome":4, "Dwarf":5, "Half-Orc":6, "Half-Troll":7, "Dunadan":8, "High-Elf":9, "Kobold":10} pclass = {"Warrior":0, "Mage":1, "Priest":2, "Rogue":3, "Ranger":4, "Paladin":5} xp_race = [100, 110, 120, 110, 125, 120, 110, 120, 180, 200, 115] xp_class = [0, 30, 20, 25, 30, 35] def get_new_xp(xpmod): return int(((float(xpmod) / 100.0) * xp_lvl_20_base) + 1.0) #bytes are written small bigger bigger biggest #so 6789ABCD is written CDAB8967 def write_byte(data, index, writeme): data[index] = chr(writeme) def write_int16(data, index, writeme): b1 = (writeme >> 8) & 0xff b0 = (writeme) & 0xff data[index] = chr(b0) data[index+1] = chr(b1) def write_int32(data, index, writeme): b3 = (writeme >> 32) & 0xff b2 = (writeme >> 16) & 0xff b1 = (writeme >> 8) & 0xff b0 = (writeme) & 0xff data[index] = chr(b0) data[index+1] = chr(b1) data[index+2] = chr(b2) data[index+3] = chr(b3) chgme = open(sys.argv[1], 'rb') data = [] try: byte = chgme.read(1) while byte != "": data.append(byte) byte = chgme.read(1) finally: chgme.close() #we now have the data in the buffer index = 0 foundplayer = 0 while foundplayer == 0: if(data[index] == 'p'): if(data[index+1] == 'l'): if(data[index+2] == 'a'): if(data[index+3] == 'y'): if(data[index+4] == 'e'): if(data[index+5] == 'r'): foundplayer = 1 index = index + 6 else: index = index + 1 else: index = index + 1 else: index = index + 1 else: index = index + 1 else: index = index + 1 else: index = index + 1 foundrec = 0 while foundrec == 0: if(data[index] == '.'): if(data[index+1] == 0 or data[index+1] == '\0'): print "Found player record." foundrec = 1 index = index + 2 else: index = index + 1 else: index = index + 1 #at this point the index is where we want it. #search for 2E 00 after player, and the next two bytes are prace, pclass. #After that, we get 4400 * ((xp_race[rrace], xp_class[rclass]) / 100.0) + 1 for XP #six bytes after that, we get the expfact, so screw using those tables. #however I can't get that to work for some reason, so I used the tables anyway. Nifty huh? #6 * AMAX(6) = 36 bytes then #20 + bytes then... #4 bytes gold - add 200 to this #4 bytes - max xp #4 bytes - cur xp #2 bytes - xp frac (0) #2 bytes - level (set to 20) #ignore 12 bytes #max level (20) #max depth (20) xpmult = xp_race[ord(data[index])] xpmult = xpmult + xp_class[ord(data[index + 1])] index = index + 36 + 20 + 6 gold = 0 if(data[index] != '\0'): gold = gold + ord(data[index]) if(data[index+1] != '\0'): gold = gold + ord(data[index+1]) * 8 if(data[index+2] != '\0'): gold = gold + ord(data[index+2]) * 8 * 8 if(data[index+3] != '\0'): gold = gold + ord(data[index+3]) * 8 * 8 * 8 write_int32(data, index, gold + 200) index = index + 4 #maxxp newxp = get_new_xp(xpmult) write_int32(data, index, newxp) index = index + 4 #curxp write_int32(data, index, newxp) index = index + 4 #xpfrac write_int16(data, index, 0) index = index + 2 #level write_int16(data, index, 20) index = index + 2 + 12 #maxlevel write_int16(data, index, 20) #maxlevel depth + 1 write_int16(data, index+2, 20) writefile = open(sys.argv[1]+".2020", 'wb') try: for i in data: writefile.write(chr(ord(i))) finally: writefile.close()