Package: wmwpy
wmwpyPython module for working with Where's My...? game files.This is being used inWhere's My Editor, a level editor for the Where's My...? series.Table of contentswmwpyTable of contentsInstallationUsageGet game folderLoading the gameMain classesLevelChallengesObjectBuilding packageBuilding docsCreditsInstallationTo installwmwpy, runpip install wmwpyorpython -m pip install wmwpyYou can also install it from the source, which may be needed because it is frequently being updated, although you need to make suregitis installed.pip install wmwpy@git+https://github.com/wmw-modding/wmwpyUsageGet game folderTo get started, you need to have a Where's My Water? game folder, either an extracted apk, ipa, or on a rooted / jailbroken device (for editing the game files directly). The game must be extracted like this.- root
 - assets
  - ...The assets folder can be specified inwmwpy.Loading the gameStart by loading the game insidewmwpyimportwmwpygame=wmwpy.load('game/wmw')You can specify the assets foldergame=wmwpy.load('game/wmw',assets='/assets')You can setassets = '.'if you have the gamepath (first parameter) set to the assets folder (such as on a rooted / jailbroken device).Alternately, you can specify the platform.game=wmwpy.load('game/wmw',platform='android')This automatically sets the assets folder to what it is on the platform.Platformassets folderandroid/assetsios/ContentYou can also specify the game, which sets things up for that game.game=wmwpy.load('game/wmp',game='WMP')Currently all the games areGameCodeWhere's My Water?'WMW'Where's My Water? Free'WMWF'Where's My Perry?'WMP'Where's My Perry? Free'WMPF'Where's My Mickey?'WMM'Where's My Mickey? XL'WMMXL'Where's My Mickey? Free'WMMF'Where's My XiYangYang?'WMXYY'Where's My Water? Featuring XiYangYang'WMWFXYY'Where's My Water? 2'WMW2'Where's My Holiday?'WMH'Where's My Valentine?'WMV'Where's My Summer?'WMS'You can also specify the base assets path, the folder within the assets folder that contains all the assets. For example, Where's My Perry? has all the data within/assets/Perry.game=wmwpy.load('game/wmp',baseassets='/Perry')Each game has the database in a different location, so you can specify it.game=wmwpy.load('game/wmp',db='/Perry/Data/perry.db')Since Where's My Water? 2 uses a profile instead of a database for the save data, you can also specify that.game=wmwpy.load('game/wmw2',profile='/Water/Data/factory_profile.json')You can also provide a function to be called during the loading, so you can keep track of the current progress, e.g. in a gui application with a progress bar.game=wmwpy.load('game/wmw',load_hook=lambdaprogress,text,max:print(f'({progress}/{max}){text}'))The inputs for the function are(
   progress : int,
   text : str,
   max : int,
)Once you're done editing all the files, you need to dump the all the assets.game.dump()This will save all the files in the game inside the assets folder. You can customize this if you want them saved in a different location.game.dump(folder='path/to/output')Main classesLevelTo load a level from within a game, use the.Level()method.level=game.Level('first_dig')The first input can be the name of a level inside the/Levelsfolder (first_dig), an absolute path to the level (/Levels/first_dig), or the path to an xml file (/Levels/first_dig.xml).You can also specify the xml and image separately.level=game.Level(xmlPath='/Levels/first_dig.xml',imagePath='/Levels/first_dig.png')Some levels include objects that wmwpy fails to load, so you can use theignore_errorsparameter to ignore them.level=game.Level('first_dig',ignore_errors=True)You can also use the HD or TabHD textures for the objects.level=game.Level('first_dig',HD=True,TabHD=True)If both are specified, TabHD will get priority. If it can't load TabHD textures. See hierarchy.- TabHD
 - HD
  - Low QualityYou can also provide a function to run while loading to see the current progress.level=game.Level('first_dig',load_callback=lambdaprogress,text,max:print(f'({progress}/{max}){text}'))The inputs for the function are(
   progress : int,
   text : str,
   max : int,
)The objects in the level are all accessible in a list>>level.objects[<wmwpy.classes.object.Objectobjectat0x000001C7627FE850>,...]SeeObjectThe level properties are also accessible as a dictionary>>level.properties{'HeavyIntro':'1'}WMW2 challenges are also accessible in a list>>level.challenges[<wmwpy.classes.level.Level.Challengeobjectat0x000001C72176ADD0>]Once you're finished editing the level, you can get the xml.xml=level.export(filename='/Levels/first_dig.xml',)This returns the xml file asbytes, but also saves the file to the game filesystem.ChallengesEach challenge has requirements in a dictionary>>level.challenges[0].requirements{'WinWait':{'seconds':''},'Duck':{'count':'2'}}ObjectTo load an object within a game, use the.Object()method.obj=game.Object('/Objects/broken_pipe.hs')You can also use the HD or TabHD textures for the objects.level=game.Level('first_dig',HD=True,TabHD=True)If both are specified, TabHD will get priority. If it can't load TabHD textures. See hierarchy.- TabHD
 - HD
  - Low QualityAn object has many properties>>obj.properties{'Type':'spout','SpoutType':'DrainSpout','Goal':'1','GoalPreset',:'Swampy',}An object also has manySprites>>obj.sprites[<wmwpy.classes.sprite.Spriteobject>]The object image is aPILimage.>>obj.image<PIL.Image.Imageimagemode=RGBAsize=300x300>The image scale can be setobj.scale=20You can also save a GIF of the object animationsobj.saveGIF('broken_pipe.gif')Once you're finished editing the object, you can get the xml.xml=export('/Objects/broken_pipe.hs',)This returns the xml file asbytes, but also saves the file to the game filesystem.Building packageTo build the package, installbuildpip install buildThen runpy -m buildBuilding docsTo build the docs, make sure sphinx is installedpip install -r doc-build/requirements.txtYou then need to runsphinx-build -b html doc-build docsCreditsThanks to@campbellsonicfor the script to read waltex images. I could not have done it without them.Thanks toMark Setchellfor helping to make loading waltex images faster (still need rgb565 and rgba5551).