#!/usr/bin/env python3.4 import re from operator import itemgetter dataFile = open("DollData.dbs", "rb") nameFile = open("DollName.csv", "r") captionFile = open("DollCaption.csv", "r") skillFile = open("SkillData.csv", "r") abilityFile = open("AbilityData.csv", "r") skillDataFile = open("SkillData.sbs", "rb") itemFile = open("ItemData.csv", "r") offsetTable = [0x5d, 0xc2, 0x127] typeNames = ['None', 'Void', 'Fire', 'Water', 'Nature', 'Earth', 'Steel', 'Wind', 'Electric', 'Light', 'Dark', 'Nether', 'Poison', 'Fighting', 'Illusion', 'Sound', 'Dream'] # Each row represents the defender, and each column represents the attacker typeTable = [ [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0], [1.0, 1.0, 0.5, 2.0, 0.5, 2.0, 0.5, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [1.0, 1.0, 0.5, 0.5, 2.0, 1.0, 0.5, 1.0, 2.0, 0.5, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0], [1.0, 1.0, 2.0, 0.5, 0.5, 0.5, 2.0, 1.0, 0.5, 0.5, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0], [1.0, 1.0, 0.5, 2.0, 2.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.5, 2.0, 1.0, 1.0, 1.0], [1.0, 1.0, 2.0, 1.0, 1.0, 2.0, 0.5, 0.5, 1.0, 1.0, 1.0, 1.0, 0.0, 2.0, 0.5, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0, 0.5, 0.0, 2.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 0.5, 1.0, 0.5, 1.0], [1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 0.5, 0.5, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [1.0, 0.5, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.5, 0.5, 2.0, 0.5, 1.0, 1.0, 2.0, 0.5, 1.0], [1.0, 0.5, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 2.0, 0.5, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 0.5, 0.0, 0.5, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0, 0.5, 2.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 0.5, 0.5, 1.0, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0, 1.0, 0.5, 1.0, 2.0, 1.0, 1.0, 0.5, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0], [1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.5, 0.5, 1.0, 1.0, 0.5, 2.0, 2.0, 1.0], [1.0, 1.0, 1.0, 0.5, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.5, 1.0], [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]] styleNames = ['None', 'Normal', 'Power', 'Defense', 'Assist', 'Speed'] costTable = [80, 90, 100, 110, 120] expTable = ['700,000', '850,000', '1,000,000', '1,150,000', '1,300,000'] tmSkillIds = [ 0, 106, 155, 206, 353, 403, 454, 603, 20, 22, 24, 107, 104, 152, 204, 201, 253, 254, 257, 303, 301, 351, 354, 355, 404, 455, 452, 504, 507, 506, 605, 553, 655, 656, 664, 666, 706, 707, 753, 34, 37, 38, 116, 111, 162, 165, 212, 213, 264, 313, 363, 405, 410, 407, 460, 511, 610, 611, 555, 670, 716, 712, 756, 41, 42, 47, 54, 121, 173, 366, 461, 462, 463, 468, 513, 518, 618, 561, 718, 762, 776, 127, 179, 233, 273, 327, 375, 421, 474, 524, 623, 566, 680, 741, 782] baseSkillLevelOffset = [(0, 0x6e), (0, 0x70), (0, 0x72), (0, 0x74), (7, 0x21), (10, 0x23), (14, 0x25), (19, 0x27), (24, 0x29)] evolvedSkillLevelOffset = [(0, 0x11), (0, 0x13), (0, 0x15), (0, 0x17), (30, 0x19), (36, 0x1b), (42, 0x1d), (49, 0x1f), (56, 0x21), (63, 0x23), (70, 0x25)] puppetNames = nameFile.readlines() for i in range(len(puppetNames)): puppetNames[i] = str.strip(puppetNames[i]) puppetCaptions = captionFile.readlines() for i in range(len(puppetCaptions)): puppetCaptions[i] = re.sub(r'\s+', ' ', ','.join(puppetCaptions[i].split(',')[2:])) abilityNames = abilityFile.readlines() for i in range(len(abilityNames)): abilityNames[i] = abilityNames[i].split(',')[1] itemNames = itemFile.readlines()[1:] for i in range(len(itemNames)): itemNames[i] = itemNames[i].split(',')[1] #skillNames = skillFile.readlines() #for i in range(len(skillNames)): # skillNames[i] = skillNames[i].split(',')[0] skillSps = [] skillNames = [] while True: skillData = skillDataFile.read(0x77) if len(skillData) < 0x77: break skillNames.append(bytes(skillData[0:0x20])[0:bytes(skillData[0:0x20]).find(b"\x00")].decode('shift_jis').rstrip(' \t\r\n\0')) skillSps.append(skillData[0x23]) skillNames[680] = "12th Sign - Warrior" def getAbilityLink(ability): #return '[[Abilities#' + ability + '|' + ability + ']]' return '[[' + ability + ']]' def immunityOverride(abilityName, type, typeEffectiveness, typeFootnote, typeFootnoteText, abilityn, footnoteCount): old = typeEffectiveness[type] typeEffectiveness[type] *= 0 typeFootnote[type] = getFootnoteTag(footnoteCount) if abilityn == 1: typeFootnoteText.append(typeFootnote[type] + 'Immunity due to ' + abilityName + '.') else: typeFootnoteText.append(typeFootnote[type] + 'Immunity only when using ' + abilityName + ". Otherwise, the modifier is '''" + '{:g}x'.format(old) + ".'''") def getFootnoteTag(count): if count == 0: return '*' return '*' * (count + 1) def addDrop(drops, drop, value): if drop in drops: drops[drop] += value else: drops[drop] = value def readWord(data, offset): return (data[offset+1] << 8) + data[offset] def makeDropsString(drops): dropsList = [[drop, drops[drop]] for drop in drops] dropsList = sorted(dropsList, key=itemgetter(1), reverse=True) return ", ".join("%d%% %s" % (drop[1], drop[0]) for drop in dropsList) speciesIndex = 0 i = 0 while True: puppetData = dataFile.read(0x1F1) if len(puppetData) < 0x1F1: break jpName = bytes(puppetData[0:0x20]).decode('shift_jis').rstrip(' \t\r\n\0') cost = str(costTable[puppetData[0x20]]) if speciesIndex > 125: break for j in range(3): offset = offsetTable[j] # id = str(puppetData[0x2a] << 8 + puppetData[0x29]) id = str(i) style = styleNames[puppetData[offset]] if style == 'None': continue type1 = typeNames[puppetData[offset+1]] type2 = typeNames[puppetData[offset+2]] typen = 2 if type2 == 'None': typen = 1 hp = str(puppetData[offset+3]) foatk = str(puppetData[offset+4]) fodef = str(puppetData[offset+5]) spatk = str(puppetData[offset+6]) spdef = str(puppetData[offset+7]) spd = str(puppetData[offset+8]) bst = str(puppetData[offset+3] + puppetData[offset+4] + puppetData[offset+5] + puppetData[offset+6] + puppetData[offset+7] + puppetData[offset+8]) ability1Id = readWord(puppetData, offset+9) ability2Id = readWord(puppetData, offset+11) ability1 = abilityNames[ability1Id] ability2 = abilityNames[ability2Id] abilityn = 2 if ability2Id == 0: abilityn = 1 ability2 = 'None' # Drop Table drops = {} addDrop(drops, itemNames[readWord(puppetData, 0x2B)], 80) addDrop(drops, itemNames[readWord(puppetData, 0x2D)], 20) dropslow = makeDropsString(drops) for drop in drops: drops[drop] //= 2 addDrop(drops, itemNames[readWord(puppetData, 0x2F)], 40) addDrop(drops, itemNames[readWord(puppetData, 0x31)], 10) dropshigh = makeDropsString(drops) # Style Changes styleChanges = [] for k in range(3): if k != j: styleChanges.append('[[' + styleNames[puppetData[offsetTable[k]]] + ' ' + puppetNames[speciesIndex] + ']]') outputFile = open('dollPages\\' + style + ' ' + puppetNames[speciesIndex] + '.txt', 'w') # InfoBox outputFile.write('\n'.join([ '{{InfoBox', '|name=' + style + ' ' + puppetNames[speciesIndex], '|jname=' + jpName, '|imagename=' + puppetNames[speciesIndex], '|typen=' + str(typen), '|type1=' + type1, ''])) if typen == 2: outputFile.write('|type2=' + type2 + '\n') outputFile.write('\n'.join([ '|dexnum=' + str(i), '|cost=' + cost, '|abilityn=' + str(abilityn), '|ability1=' + getAbilityLink(ability1), ''])) if abilityn == 2: outputFile.write('|ability2=' + getAbilityLink(ability2) + '\n') outputFile.write('\n'.join([ '|lv100exp=' + expTable[puppetData[0x20]], '|style1=' + styleChanges[0], '|style2=' + styleChanges[1], '|lowdrops=' + dropslow, '|highdrops=' + dropshigh, '}}\n'])) # Dex Entry and Base Stats outputFile.write('\n'.join([ '{| border="0"', '|-', '| colspan="2" |', '{| class="wikitable" border="1" cellpadding="2" style="border-collapse: collapse; width: 556px;"', '|-', '! scope="row" style="width: 54px;" | Dex Entry', '| ' + puppetCaptions[speciesIndex], '|}', '|-', '| colspan="2" |', '{| class="wikitable" border="1" cellpadding="2" style="border-collapse: collapse; width: 556px;"', '|-', '! scope="col" style="width: 79px;" | HP', '! scope="col" style="width: 79px;" | Fo.Att.', '! scope="col" style="width: 79px;" | Fo.Def.', '! scope="col" style="width: 79px;" | Sp.Att.', '! scope="col" style="width: 79px;" | Sp.Def.', '! scope="col" style="width: 79px;" | Speed', '! scope="col" style="width: 82px;" | Total', '|-', '| style="text-align: center;" | ' + hp, '| style="text-align: center;" | ' + foatk, '| style="text-align: center;" | ' + fodef, '| style="text-align: center;" | ' + spatk, '| style="text-align: center;" | ' + spdef, '| style="text-align: center;" | ' + spd, '| style="text-align: center;" | ' + bst, '|}\n'])) # Type Effectiveness outputFile.write('{{TypeEffectiveness\n') if typen == 1: typeEffectiveness = list(typeTable[puppetData[offset+1]]) else: typeEffectiveness = [] for k in range(17): typeEffectiveness.append(typeTable[puppetData[offset+1]][k] * typeTable[puppetData[offset+2]][k]) typeFootnote = [''] * 17 typeFootnoteText = [] footnoteCount = 0 if ability1Id == 120 or ability2Id == 120: oldLight = typeEffectiveness[9] oldDark = typeEffectiveness[10] typeEffectiveness[9] *= 1.25 typeEffectiveness[10] *= 0 typeFootnote[9] = getFootnoteTag(footnoteCount) typeFootnote[10] = getFootnoteTag(footnoteCount) footnoteCount += 1 if typeEffectiveness[9] >= 2.01: word = 'Stronger weakness' elif typeEffectiveness[9] >= 1.01: word = 'Weakness' else: word = 'Reduced resistance' if abilityn == 1: typeFootnoteText.append(typeFootnote[9] + word + ' and immunity due to ' + getAbilityLink(abilityNames[120]) + '.') else: typeFootnoteText.append(typeFootnote[10] + word + ' and immunity only when using ' + getAbilityLink(abilityNames[120]) + ". Otherwise, the modifiers are '''" + '{:g}x'.format(oldLight) + "''' (Light) and '''" + '{:g}x'.format(oldDark) + "''' (Dark).") for k in range(138, 152): if ability1Id == k or ability2Id == k: immunityOverride(abilityNames[k], k - 136, typeEffectiveness, typeFootnote, typeFootnoteText, abilityn, footnoteCount) footnoteCount += 1 if ability1Id == 155 or ability2Id == 155: oldLight = typeEffectiveness[9] oldDark = typeEffectiveness[10] typeEffectiveness[9] /= 2 typeEffectiveness[10] /= 2 typeFootnote[9] = getFootnoteTag(footnoteCount) typeFootnote[10] = getFootnoteTag(footnoteCount) footnoteCount += 1 if typeEffectiveness[9] >= 0.99 and typeEffectiveness[9] <= 1.01: if typeEffectiveness[10] >= 0.99 and typeEffectiveness[10] <= 1.01: prefix = "Neutralities" else: prefix = "Neutrality and resistance" elif typeEffectiveness[10] >= 0.99 and typeEffectiveness[10] <= 1.01: prefix = "Resistance and neutrality" else: prefix = "Resistances" if abilityn == 1: typeFootnoteText.append(typeFootnote[9] + prefix + ' due to ' + getAbilityLink(abilityNames[155]) + '.') else: typeFootnoteText.append(typeFootnote[10] + prefix + ' only when using ' + getAbilityLink(abilityNames[155]) + ". Otherwise, the modifiers are '''" + '{:g}x'.format(oldLight) + "''' (Light) and '''" + '{:g}x'.format(oldDark) + "''' (Dark).") if ability1Id == 313 or ability2Id == 313: footnote = getFootnoteTag(footnoteCount) footnoteCount += 1 for k in range(1, 17): if typeEffectiveness[k] > 0.24 and typeEffectiveness[k] < 1.01: typeEffectiveness[k] = 0 typeFootnote[k] = footnote if abilityn == 1: typeFootnoteText.append(footnote + 'Immunities due to ' + getAbilityLink(abilityNames[313]) + '.') else: typeFootnoteText.append(footnote + 'Immunities only when using ' + getAbilityLink(abilityNames[313]) + '.') for k in range(1, 17): if typeEffectiveness[k] < 0.99 or typeEffectiveness[k] > 1.01 or typeFootnote[k] != '': outputFile.write('|' + typeNames[k].lower() + '=' + '{:g}x'.format(typeEffectiveness[k]) + typeFootnote[k] + '\n') outputFile.write('}}\n') for k in range(len(typeFootnoteText)): outputFile.write('' + typeFootnoteText[k] + '
\n') # Level up moves outputFile.write('\n'.join([ '|-', '| style="vertical-align: top;" |', '{| class="wikitable" border="1" cellpadding="2" style="border-collapse: collapse;"', '|+ Level Up Moves', '|-', '! scope="col" style="width: 48px;" | Lv', '! scope="col" style="width: 164px;" | Move', '! scope="col" style="width: 48px;" | PP', '|-\n'])) for k in range(4): skillId = readWord(puppetData, baseSkillLevelOffset[k][1]) pp = min(int((baseSkillLevelOffset[k][0] / 2 + 50) * 2 / skillSps[skillId]), 99) if skillId != 0: outputFile.write('\n'.join([ '| style="text-align:center" | -', '| [[' + skillNames[skillId] + ']]', '| style="text-align:center" | ' + str(pp), '|-\n'])) if style != 'Normal': for k in range(4): skillId = readWord(puppetData, evolvedSkillLevelOffset[k][1] + offset) pp = min(int((evolvedSkillLevelOffset[k][0] / 2 + 50) * 2 / skillSps[skillId]), 99) if skillId != 0: outputFile.write('\n'.join([ '| style="text-align:center" | -', '| [[' + skillNames[skillId] + ']]', '| style="text-align:center" | ' + str(pp), '|-\n'])) for k in range(4, len(baseSkillLevelOffset)): skillId = readWord(puppetData, baseSkillLevelOffset[k][1]) pp = min(int((baseSkillLevelOffset[k][0] / 2 + 50) * 2 / skillSps[skillId]), 99) if skillId != 0: outputFile.write('\n'.join([ '| style="text-align:center" | ' + str(baseSkillLevelOffset[k][0]), '| [[' + skillNames[skillId] + ']]', '| style="text-align:center" | ' + str(pp), '|-\n'])) if style != 'Normal': for k in range(4, len(evolvedSkillLevelOffset)): skillId = readWord(puppetData, evolvedSkillLevelOffset[k][1] + offset) pp = min(int((evolvedSkillLevelOffset[k][0] / 2 + 50) * 2 / skillSps[skillId]), 99) if skillId != 0: outputFile.write('\n'.join([ '| style="text-align:center" | ' + str(evolvedSkillLevelOffset[k][0]), '| [[' + skillNames[skillId] + ']]', '| style="text-align:center" | ' + str(pp), '|-\n'])) outputFile.write('|}\n') # Skillcard moves outputFile.write('\n'.join([ '| style="vertical-align: top;" |', '{| class="wikitable" border="1" cellpadding="2" style="border-collapse: collapse;"', '|+ Skill Cards', '|-', '! scope="col" style="width: 48px;" | SC', '! scope="col" style="width: 208px;" | Skill', '|-\n'])) for k in range(1, 95): byteIndex = int((k - 1) / 8) + 0x31 + offset bitIndex = (k - 1) % 8 if (puppetData[byteIndex] >> bitIndex) & 1 == 1: outputFile.write('\n'.join([ '| style="text-align:center;" | #' + str(k), '| [[' + skillNames[tmSkillIds[k]] + ']]', '|-\n'])) # Page footer outputFile.write('\n'.join([ '|}', '|-', '|}', ''])) outputFile.close() i += 1 speciesIndex += 1 dataFile.close() nameFile.close() abilityFile.close() captionFile.close() skillFile.close() skillDataFile.close() itemFile.close()