#!/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()