#! /usr/bin/env python3 # -*- coding: utf8 -*- # # Copyright (C) 2010-2011 Evol Online # Author: Andrei Karas (4144) import datetime import os import xml import sys from xml.dom import minidom wikia=open("Items.md", "w") wikib=open("Monsters.md", "w") iconsDir = "graphics/items/" spritesDir = "graphics/sprites/" particlesDir = "graphics/particles/" sfxDir = "sfx/" musicDir = "music/" mapsDir = "maps/" spriteErrorFile = "error.xml" levelUpEffectFile = "levelup.particle.xml" portalEffectFile = "warparea.particle.xml" minimapsDir = "graphics/minimaps/" wallpapersDir = "graphics/images/" wallpaperFile = "login_wallpaper.png" errors = 0 warnings = 0 errDict = set() safeDye = False borderSize = 20 colorsList = set() showAll = False silent = False herc = False testBadCollisions = False # number of tiles difference. after this amount tiles can be counted as incorrect tileNumDiff = 3 # max number of incorrect tiles. If more then tile not counted as error maxNumErrTiles = 5 class Tileset: None class Layer: None def printErr(err): errDict.add(err) #print err def showFileErrorById(id, rootDir, fileDir): rootDir = rootDir fileDir = fileDir #print "error: id=" + id + ", file not found: " + fileDir + " (" + rootDir + fileDir + ")" def showFileWarningById(id, rootDir, fileDir): rootDir = rootDir fileDir = fileDir #print "warn: id=" + id + ", file not found: " + fileDir + " (" + rootDir + fileDir + ")" def showError(id, text): text = text #print "error: id=" + id + " " + text def showWarning(id, text): text = text #print "warn: id=" + id + " " + text def showMsg(id, text, src, iserr): pass def showMsgSprite(file, text, iserr): pass def showMsgFile(file, text, iserr): pass def showFileMsgById(id, rootDir, fileDir, iserr): global errors, warnings if iserr == True: showFileErrorById(id, rootDir, fileDir) errors = errors + 1 else: showFileWarningById(id, rootDir, fileDir) warnings = warnings + 1 def printSeparator(): print("--------------------------------------------------------------------------------") def showHeader(): print("TMW2 Wiki Generator") ##print "Evol client data validator." print("Run at: " + datetime.datetime.now().isoformat()) ##print "https://gitlab.com/evol/evol-tools/blob/master/testxml/testxml.py" printSeparator() def showFooter(): #pass #printSeparator() print("Done.") def checkFilePermission(fullName): global warnings if os.access(fullName, os.X_OK): #print "warn: execute flag on file: " + fullName warnings = warnings + 1 def loadPaths(): pass def splitImage(image): try: idx = image.find("|") if idx > 0: imagecolor = image[idx + 1:] image = image[0:idx] else: imagecolor = "" except: image = "" imagecolor = "" return [image, imagecolor] def testDye(id, color, text, src, iserr): pass def testDyeInternal(id, col, text, src, iserr): return True def testDyeColors(id, color, text, src, iserr): return 4 def testDyeChannel(file, color, text, iserr): return 1 def testSprites(id, node, checkGender, isNormalDye, isMust, checkAction, iserr): pass def testSprite(id, file, variant, isNormalDye, checkAction, iserr): pass def powerOfTwo(num): val = 1 while val < num: val = val * 2 return val def testSpriteFile(id, fullPath, file, fileLoc, dnum, variant, checkAction, iserr): pass def testSpriteAction(file, name, action, numframes, iserr): pass def testImageFile(file, fullPath, sz, src, iserr): pass def testSound(file, sfxDir, msg): pass def testItems(fileName, imgDir): global warnings, errors, safeDye #print "Checking " + fileName wikia.write("# Items\n\ + [Usable Items](#usable-items)\n\ + [Generic Items](#generic-items)\n\ + [1H Weapons](#1h-weapons)\n\ + [2H Weapons and Ammo](#2h-weapons-and-ammo)\n\ + [Trinkets](#trinkets)\n\ + [Headgear](#headgear)\n\ + [Armors](#armors)\n\ + [Pants](#pants)\n\ + [Boots](#boots)\n\ \n") wk_usb=[] wk_generic=[] wk_neck=[] wk_1h=[] wk_2h=[] # Shield, gloves, wings, pets, cards and such are still not handled. #wk_shd=[] wk_arm=[] wk_pant=[] wk_shoe=[] wk_helm=[] try: dom = minidom.parse(parentDir + "/" + fileName) except Exception as err: #print "error: " + fileName + ": corrupted" #print err errors = errors + 1 return idset = set() #oldId = None for node in dom.documentElement.childNodes: if node.nodeName == "include": try: name = node.attributes["name"].value if name == "": errors = errors + 1 #print "error: " + fileName + ": Empty include name"; testItems(name, imgDir) except: errors = errors + 1 #print "error: " + fileName + ": Broken include tag"; continue if node.nodeName != "item": continue if node.parentNode != dom.documentElement: continue try: id = node.attributes["id"].value except: errors = errors + 1 continue #oldId = id if id in idset: #print "error: " + fileName + ": duplicated id=" + id errors = errors + 1 else: idset.add(id) idI = int(id) try: colors = node.attributes["colors"].value except: colors = None try: type = node.attributes["type"].value except: type = "" #print "warn: " + fileName + ": no type attribute for id=" + id warnings = warnings + 1 try: image = node.attributes["image"].value image0 = image img = splitImage(image) image = img[0] imagecolor = img[1] except: image = "" image0 = "" imagecolor = "" try: floor = node.attributes["floor"].value floor0 = floor flr = splitImage(floor) floor = flr[0] floorcolor = flr[1] except: floor = None floor0 = None floorcolor = None try: description = node.attributes["description"].value except: description = "" #try: # missile = node.attributes["missile-particle"].value #except: # missile = "" try: drawBefore = node.attributes["drawBefore"].value except: drawBefore = "" try: drawAfter = node.attributes["drawAfter"].value except: drawAfter = "" # try: # drawPriority = int(node.attributes["drawPriority"].value) # except: # drawPriority = 0 if type == "hairsprite": if idI >= 0: #print "error: " + fileName + ": hairsprite with id=" + id errors = errors + 1 elif idI < -100: #print "error: " + fileName + ": hairsprite override player sprites" errors = errors + 1 safeDye = True testSprites(id, node, True, True, True, "", True) safeDye = False elif type == "racesprite": if idI >= 0: #print "error: " + fileName + ": racesprite with id=" + id errors = errors + 1 elif idI > -100: #print "error: " + fileName + ": racesprite override player hair" errors = errors + 1 elif type == "usable" or type == "unusable" or type == "generic" \ or type == "equip-necklace" or type == "equip-torso" or type == "equip-feet" \ or type == "equip-arms" or type == "equip-legs" or type == "equip-head" \ or type == "equip-shield" or type == "equip-1hand" or type == "equip-2hand" \ or type == "equip-charm" or type == "equip-ammo" or type == "equip-neck" \ or type == "equip-ring" or type == "card": if image == "": #print "error: " + fileName + ": missing image attribute on id=" + id errors = errors + 1 continue elif len(imagecolor) > 0: if colors is None: testDye(id, imagecolor, "image=" + image0, fileName, True) else: testDyeChannel(id, imagecolor, "image=" + image0, True) if colors not in colorsList: #print "error: " + fileName + ": colors value " + colors + " not found in itemcolors.xml" errors = errors + 1 if floorcolor != None and len(floorcolor) > 0: if colors is None: testDye(id, floorcolor, "floor=" + floor0, fileName, True) else: testDyeChannel(id, imagecolor, "floor=" + floor0, True); if colors not in colorsList: #print "error: " + fileName + ": colors value " + colors + " not found in itemcolors.xml" errors = errors + 1 if description == "": #print "warn: " + fileName + ": missing description attribute on id=" + id warnings = warnings + 1 elif description == ".": #print "warn: " + fileName + ": broken description attribute on id=" + id warnings = warnings + 1 try: floorSprite = node.getElementsByTagName("floor")[0] except: floorSprite = None if floorSprite != None: if floor != None: errors = errors + 1 testSprites(id, floorSprite, False, colors is None, True, "", err) fullPath = os.path.abspath(parentDir + "/" + imgDir + image) if not os.path.isfile(fullPath) or os.path.exists(fullPath) == False: showFileErrorById (id, imgDir, image) errors = errors + 1 else: testImageFile(imgDir + image, fullPath, 32, "", True) if floor != None: fullPath = os.path.abspath(parentDir + "/" + imgDir + floor) if not os.path.isfile(fullPath) or os.path.exists(fullPath) == False: showFileErrorById (id, imgDir, floor) errors = errors + 1 else: testImageFile(imgDir + floor, fullPath, 0, "", True) testItemReplace(id, node, "replace") if drawBefore != "": checkSpriteName(id, drawBefore) if drawAfter != "": checkSpriteName(id, drawAfter) try: attackaction = node.attributes["attack-action"].value except: attackaction = "" testSprites(id, node, True, colors is None, False, attackaction, True) if type != "usable" and type != "unusable" and type != "generic" \ and type != "equip-necklace" and type != "equip-1hand" \ and type != "equip-2hand" and type != "equip-ammo" \ and type != "equip-charm" and type != "equip-neck": err = type != "equip-shield" testSprites(id, node, True, colors is None, True, "", err) if type == "usable": try: wk_usb.append([node.attributes["id"].value,node.attributes["name"].value,node.attributes["effect"].value]) except: wk_usb.append([node.attributes["id"].value,node.attributes["name"].value,"UNKNOWN"]) elif type == "unusable" or type == "generic": try: wk_generic.append([node.attributes["id"].value,node.attributes["name"].value]) except: wk_generic.append([node.attributes["id"].value,"SYSTEM ERROR"]) elif type == "equip-1hand": try: wk_1h.append([node.attributes["id"].value,node.attributes["name"].value, node.attributes["attack"].value, "Lv "+node.attributes["level"].value]) except: wk_1h.append([node.attributes["id"].value,node.attributes["name"].value, node.attributes["attack"].value,"-"]) elif type == "equip-2hand": try: wk_2h.append([node.attributes["id"].value,node.attributes["attack-range"].value,node.attributes["name"].value, node.attributes["attack"].value, "Lv "+node.attributes["level"].value]) except: wk_2h.append([node.attributes["id"].value,"?",node.attributes["name"].value, node.attributes["attack"].value,"-"]) elif type == "equip-ammo": try: wk_2h.append([node.attributes["id"].value,"-".value,node.attributes["name"].value, node.attributes["attack"].value, "Lv "+node.attributes["level"].value]) except: wk_2h.append([node.attributes["id"].value,"-",node.attributes["name"].value, node.attributes["attack"].value,"-"]) if type == "equip-necklace" or type == "equip-neck": try: wk_neck.append([node.attributes["id"].value,"NECK",node.attributes["name"].value,node.attributes["effect"].value]) except: wk_neck.append([node.attributes["id"].value,"NECK",node.attributes["name"].value,"UNKNOWN"]) if type == "equip-charm": try: wk_neck.append([node.attributes["id"].value,"RING",node.attributes["name"].value,node.attributes["effect"].value]) except: wk_neck.append([node.attributes["id"].value,"RING",node.attributes["name"].value,"UNKNOWN"]) elif type == "equip-head": try: # why not head? wk_helm.append([node.attributes["id"].value,node.attributes["name"].value, node.attributes["defense"].value, "Lv "+node.attributes["level"].value]) except: wk_helm.append([node.attributes["id"].value,node.attributes["name"].value, node.attributes["defense"].value,"-"]) elif type == "equip-torso": try: wk_arm.append([node.attributes["id"].value,node.attributes["name"].value, node.attributes["defense"].value, "Lv "+node.attributes["level"].value]) except: wk_arm.append([node.attributes["id"].value,node.attributes["name"].value, node.attributes["defense"].value,"-"]) elif type == "equip-legs": try: wk_pant.append([node.attributes["id"].value,node.attributes["name"].value, node.attributes["defense"].value, "Lv "+node.attributes["level"].value]) except: wk_pant.append([node.attributes["id"].value,node.attributes["name"].value, node.attributes["defense"].value,"-"]) elif type == "equip-feet": try: wk_shoe.append([node.attributes["id"].value,node.attributes["name"].value, node.attributes["defense"].value, "Lv "+node.attributes["level"].value]) except: wk_shoe.append([node.attributes["id"].value,node.attributes["name"].value, node.attributes["defense"].value,"-"]) elif type == "other": None elif type != "": #print "warn: " + fileName + ": unknown type '" + type + "' for id=" + id warnings = warnings + 1 print("Generating Item Wiki...") ################################################### USABLE wikia.write("## Usable Items\n") wikia.write("| ID | ITEM | EFFECT |\n\ | -- | -------------- | ------ |\n") # Show image? for i in wk_usb: wikia.write(i[0] + "|" + i[1] + "|" + i[2] +"|\n") wikia.write('[Back to Top](#items)\n') wikia.write('\n') ################################################### GENERIC wikia.write("## Generic Items\n") wikia.write("| ID | ITEM |\n\ | -- | -------------- |\n") # Show image? for i in wk_generic: wikia.write(i[0] + "|" + i[1] + "|\n") wikia.write('[Back to Top](#items)\n') wikia.write('\n') ################################################### 1 Hand Weapons wikia.write("## 1H Weapons\n") wikia.write("| ID | ITEM | ATK | LVL\n\ | -- | -------------- | --- | ---|\n") for i in sorted(wk_1h, key=lambda x: x[2], reverse=True): try: wikia.write(i[0] + "|" + i[1] + "|" + i[2] + "|" + i[3] +"|\n") except: wikia.write(i[0] + "|" + i[1] + "|" + "INVALID" + "|" + "INVALID" +"|\n") wikia.write('[Back to Top](#items)\n') wikia.write('\n') ################################################### 2 Hand Weapons and Ammo wikia.write("## 2H Weapons and Ammo\n") wikia.write("| ID | Range | ITEM | ATK | LVL\n\ | -- | -- | ---------- | --- | ---|\n") for i in sorted(wk_2h, key=lambda x: x[1], reverse=True): try: wikia.write(i[0] + "|" + i[1] + "|" + i[2] + "|" + i[3] + "|" + i[4] +"|\n") except: wikia.write(i[0] + "|" + "INVALID" + "|" + "INVALID" + "|" + "INVALID" + "|" + "INVALID" +"|\n") wikia.write('[Back to Top](#items)\n') wikia.write('\n') ################################################### 2 Hand Weapons and Ammo wikia.write("## Trinkets\n") wikia.write("| ID | Slot | ITEM | EFFECT\n\ | -- | -- | ---------- | --- |\n") for i in sorted(wk_neck, key=lambda x: x[1], reverse=True): try: wikia.write(i[0] + "|" + i[1] + "|" + i[2] +"|" + i[3] +"|\n") except: wikia.write(i[0] + "|" + i[1] + "|" + "INVALID NAME! NON ASCII CHAR FOUND." +"|" + "INVALID EFFECT! NON ASCII CHAR FOUND." +"|\n") wikia.write('[Back to Top](#items)\n') wikia.write('\n') ################################################### Helmets wikia.write("## Headgear\n") wikia.write("| ID | ITEM | DEF | LVL\n\ | -- | -------------- | --- | ---|\n") for i in sorted(wk_helm, key=lambda x: x[2], reverse=True): wikia.write(i[0] + "|" + i[1] + "|" + i[2] +"|" + i[3] +"|\n") wikia.write('[Back to Top](#items)\n') wikia.write('\n') ################################################### Armors wikia.write("## Armors\n") wikia.write("| ID | ITEM | DEF | LVL\n\ | -- | -------------- | --- | ---|\n") for i in sorted(wk_arm, key=lambda xy: xy[2], reverse=True): try: wikia.write(i[0] + "|" + i[1] + "|" + i[2] +"|" + i[3] +"|\n") except: wikia.write(i[0] + "|" + "INVALID" + "|" + "INVALID" +"|" + "INVALID" +"|\n") wikia.write('[Back to Top](#items)\n') wikia.write('\n') ################################################### Pants wikia.write("## Pants\n") wikia.write("| ID | ITEM | DEF | LVL\n\ | -- | -------------- | --- | ---|\n") for i in sorted(wk_pant, key=lambda xz: xz[2], reverse=True): wikia.write(i[0] + "|" + i[1] + "|" + i[2] +"|" + i[3] +"|\n") wikia.write('[Back to Top](#items)\n') wikia.write('\n') ################################################### Boots wikia.write("## Boots\n") wikia.write("| ID | ITEM | DEF | LVL\n\ | -- | -------------- | --- | ---|\n") for i in sorted(wk_shoe, key=lambda x: x[2], reverse=True): wikia.write(i[0] + "|" + i[1] + "|" + i[2] +"|" + i[3] +"|\n") wikia.write('[Back to Top](#items)\n') wikia.write('\n') # Shield, gloves, wings, pets, cards and such are still not handled. def writeMob(wikib, tmb): wikib.write("|"+ tmb[0]+"|"+ tmb[1]+"|"+ tmb[2]+"|"+ tmb[3]+"|"+ tmb[4]+"|"+ tmb[5]+"|"+ tmb[6]+"|"+ tmb[7]+"|\n" ) def testMobs(): print("Generating Mob Wiki...") src=open("../../server-data/db/re/mob_db.conf", "r") wikib.write("# Monster Database\n") wikib.write("|ID|Name|hp|xp|def|atk|delay|modes|\n") # 0 1 2 3 4 5 6 7 #tm_entry=False # TODO: Drop list tmb=['--','----','--','--','---','---','-----','-----'] # 0 1 2 3 4 5 6 7 for a in src: if a == "{\n": writeMob(wikib, tmb) tmb=['','','','','','', '', ''] # 0 1 2 3 4 5 6 7 if " Id:" in a: tmb[0]=stp(a) if " Name:" in a: tmb[1]=stp(a) if " Hp:" in a: tmb[2]=stp(a) if " Exp:" in a: tmb[3]=stp(a) if " Def:" in a: tmb[4]=stp(a) if " Attack:" in a: tmb[5]=stp(a) if " AttackDelay:" in a: tmb[6]=stp(a) if " Looter: true" in a: tmb[7]+="Lot," if " Assist: true" in a: tmb[7]+="Ass," if " Aggressive: true" in a: tmb[7]+="Agr," # Write last entry writeMob(wikib, tmb) wikib.write('\n\n|Mode|Desc|\n|----|----|\n') wikib.write('|Lot|Looter|\n') wikib.write('|Ass|Assist|\n') wikib.write('|Agr|Aggressive|\n') src.close() def stp(x): return x.replace('\n', '').replace('|', '').replace('(int, defaults to ', '').replace(')', '').replace('basic experience', '').replace('"','').replace(" ","").replace('(string', '').replace('Name: ','').replace('AttackDelay', 'ms') def testItemReplace(id, rootNode, name): global warnings, errors for node in rootNode.getElementsByTagName(name): if node.parentNode != rootNode: continue try: sprite = node.attributes["sprite"].value except: if len(node.attributes) != 0: #print "error: reading replace sprite name, id=" + str(id) errors = errors + 1 continue checkSpriteName(id, sprite) for itemNode in node.getElementsByTagName("item"): if itemNode.parentNode != node: continue #TODO here need check "from" and "to" for correct item id def checkSpriteName(id, name): global warnings, errors if name != "race" and name != "type" and name != "shoes" and name != "boot" and \ name != "boots" and name != "bottomclothes" \ and name != "bottom" and name != "pants" and name != "topclothes" and \ name != "top" and name != "torso" and name != "body" and name != "misc1" \ and name != "misc2" and name != "scarf" and name != "scarfs" and \ name != "hair" and name != "hat" and name != "hats" and name != "wings" \ and name != "glove" and name != "gloves" and name != "weapon" and \ name != "weapons" and name != "shield" and name != "shields" and \ name != "amulet" and name != "amulets" and name != "ring" and name != "rings": #print "error: unknown sprite name " + name + ", id=" + str(id) errors = errors + 1 def splitBytes(num): i1 = int(num % 256) i2 = int(((num % 65536) - i1) / 256) i3 = int(((num % 16777216) - i2 - i1) / 65536) i4 = int(((num % 4294967296) - i3 - i2 - i1) / 16777216) return (i1, i2, i3, i4) def testDirExists(path): global errors fullName = parentDir + "/" + path if not os.path.exists(fullName): #print "error: path '" + path + "' not exists." errors = errors + 1 elif not os.path.isdir(fullName): #print "error: path '" + path + "' is incorrect directory." errors = errors + 1 def testDefaultFiles(): pass def testMinimapsDir(): pass def testImagesDir(imagesDir, sz): pass def testSpritesDir(dir): pass def testParticlesDir(dir): pass def testSoundsDir(dir, sfxDir): return def testItemColors(fileName): global warnings, errors, safeDye, colorLists #print "Checking itemcolors.xml" try: dom = minidom.parse(parentDir + "/" + fileName) except: return for node in dom.getElementsByTagName("list"): if node.parentNode != dom.documentElement: continue try: name = node.attributes["name"].value except: #print "error: colors list dont have name" errors = errors + 1 continue if name in colorsList: #print "error: duplicate color list: " + name errors = errors + 1 continue colorsList.add(name) colors = set() names = set() for colorNode in node.getElementsByTagName("color"): if colorNode.parentNode != node: continue try: id = colorNode.attributes["id"].value except: #print "error: getting id in list: " + name errors = errors + 1 continue try: colorName = colorNode.attributes["name"].value except: #print "error: getting name in list: " + name errors = errors + 1 continue try: colorDye = colorNode.attributes["value"].value except: #print "error: getting color in list: " + name errors = errors + 1 if id in colors: #print "error: color with id " + str(id) + " already in list: " + name errors = errors + 1 else: colors.add(id) if colorName in names: #print "error: color with name \"" + colorName + "\" already in list: " + name errors = errors + 1 else: names.add(colorName) testDyeColors(id, colorDye, colorDye, name, True) def haveXml(dir): if not os.path.isdir(dir) or not os.path.exists(dir): return False for file in os.listdir(dir): #if filt.search(file): return True return False def detectClientData(dirs): global parentDir parentDir="../../client-data" return for dir in dirs: if haveXml(dir): #print "Detected client data directory in: " + dir parentDir = dir return True #print "Cant detect client data directory" exit(1) if len(sys.argv) == 2: if sys.argv[1] == "all": showAll = True elif sys.argv[1] == "silent": silent = True elif sys.argv[1] == "herc": silent = True herc = True showHeader() #print "Detecting clientdata dir" detectClientData([".", "..", "../../client-data", "../../clientdata"]) #print "Checking xml file syntax" #loadPaths() #testItemColors("/itemcolors.xml") testItems("/items.xml", iconsDir) testMobs() wikia.close() wikib.close() showFooter() exit(0)