110 changed files with 3542 additions and 1088 deletions
			
			
		| @ -1,12 +1,65 @@@@ -1,12 +1,65 @@ | ||||
|  ``` | ||||
| • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| ``` | ||||
|  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
|  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
|  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
|  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
|  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
|                Magicbane Emulator Project © 2013 - 2022 | ||||
|                           www.magicbane.com | ||||
| ``` | ||||
| 
 | ||||
| # mbEditorPro v 2.0 | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| Team Magicbane presents to the community technology allowing MagicBox administrators<br> | ||||
| to fully modify their game using nothing more than notepad.exe. <br> | ||||
| 
 | ||||
| - Tool directly converts Shadowbane .cache files to and from a high fidelity pure JSON representation. | ||||
| - Enumerations are used throughout hiding from the user ugly signed ulong values. | ||||
| - Written in Python and open-source allowing modification and extension with ease. | ||||
| - Want to raise all weapon damage by x%; Just modify item values as they are being parsed! | ||||
| 
 | ||||
|                 Magicbane Emulator Project © 2013 - 2022 | ||||
|                            www.magicbane.com | ||||
| The tool built with Edltirch Technologies parses all Shadowbane .cache files giving the user complete control over the game<br> | ||||
| 
 | ||||
| Team Magicbane aims to deliver you the best crackhead free MMO technology around; all for free! | ||||
| 
 | ||||
| ### Usage: | ||||
| ``` | ||||
| mbEditorPro.py unpack cobjects | ||||
| mbEditorPro.py unpack all | ||||
| ``` | ||||
| JSON output will be in a folder **ARCANE DUMP** <br> | ||||
| 
 | ||||
| ``` | ||||
| mbEditorPro.py pack textures | ||||
| mbEditorPro.py pack all | ||||
| ``` | ||||
| 
 | ||||
| This repository holds the source code for mbEditorPro along with other tooling and data required to give every MagicBox administrator the ability to fully modify the game as they see fit. | ||||
| New binary cache file will be built from the JSON and output in the current directory. <br>> | ||||
| 
 | ||||
| > note: Unpacked data from a 2008 cache file is available in the Data repo.  Build a new cache file right out of the box. | ||||
| 
 | ||||
| ### Limitations | ||||
| 
 | ||||
| Hirelings, ZoneEvents and Mobile Inventory are not parsed or written as there were no <br> | ||||
| examples in the .cache files to begin with.  The game does seem to support them, however. | ||||
| 
 | ||||
| ### JSON | ||||
| 
 | ||||
| The tool generating pure JSON has the following benefits: | ||||
| 
 | ||||
| - It's ubiquitous and the tooling is mature.  The standard interop exchange format. | ||||
| - Human and machine-readable. | ||||
| - Ease of importing into MySQL or other databases. | ||||
| - Use as an intermediate representation to build a GUI World Editor or FBX importer. | ||||
| 
 | ||||
| ### Future | ||||
| 
 | ||||
| mbEditorPro will be the cornerstone of Magicbane's data project. The Team's goal is threefold: | ||||
| 
 | ||||
| - Ship MagicBox 1.5 with both Aerynth and Vorringia mapsets available. | ||||
| - Integrate Magicbane's wpak extractor technology into the tool<br> | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -1,7 +0,0 @@@@ -1,7 +0,0 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| @ -1,7 +0,0 @@@@ -1,7 +0,0 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| @ -1,7 +0,0 @@@@ -1,7 +0,0 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| @ -1,23 +0,0 @@@@ -1,23 +0,0 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| 
 | ||||
| INVENTORY_TYPE_GOLD = 1 | ||||
| INVENTORY_TYPE_ITEM = 2 | ||||
| INVENTORY_TYPE_BOOTYTABLE = 3 | ||||
| 
 | ||||
| INVENTORY_TYPE_TO_STRING = { | ||||
|     INVENTORY_TYPE_GOLD: 'GOLD', | ||||
|     INVENTORY_TYPE_ITEM: 'ITEM', | ||||
|     INVENTORY_TYPE_BOOTYTABLE: 'BOOTYTABLE', | ||||
| } | ||||
| 
 | ||||
| STRING_TO_INVENTORY_TYPE = { | ||||
|     'GOLD': INVENTORY_TYPE_GOLD, | ||||
|     'ITEM': INVENTORY_TYPE_ITEM, | ||||
|     'BOOTYTABLE': INVENTORY_TYPE_BOOTYTABLE, | ||||
| } | ||||
| @ -1,41 +0,0 @@@@ -1,41 +0,0 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| 
 | ||||
| import glob | ||||
| import os | ||||
| 
 | ||||
| from arcane.util.hasher import hash_string | ||||
| 
 | ||||
| _STRING_TO_HASH = {} | ||||
| _HASH_TO_STRING = {} | ||||
| 
 | ||||
| 
 | ||||
| def load_files(): | ||||
|     directory = os.path.dirname(__file__) | ||||
| 
 | ||||
|     for filepath in glob.glob(os.path.join(directory, '*.txt')): | ||||
|         lines = list(map(lambda s: s.strip(), open(filepath).readlines())) | ||||
| 
 | ||||
|         _STRING_TO_HASH.update({ | ||||
|             s: hash_string(s) for s in lines | ||||
|         }) | ||||
| 
 | ||||
|         _HASH_TO_STRING.update({ | ||||
|             hash_string(s): s for s in lines | ||||
|         }) | ||||
| 
 | ||||
| 
 | ||||
| def string_to_hash(s): | ||||
|     return _STRING_TO_HASH.get(s, s) | ||||
| 
 | ||||
| 
 | ||||
| def hash_to_string(h): | ||||
|     return _HASH_TO_STRING.get(h, h) | ||||
| 
 | ||||
| 
 | ||||
| load_files() | ||||
| @ -1,38 +0,0 @@@@ -1,38 +0,0 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| 
 | ||||
| MOBILE = 1 | ||||
| BANKER = 2 | ||||
| SHOPKEEPER = 3 | ||||
| TRAINER = 4 | ||||
| MERCHANT = 8 | ||||
| HIRELING = 9 | ||||
| PET = 10 | ||||
| MINION = 11 | ||||
| 
 | ||||
| MOBILE_TO_STRING = { | ||||
|     MOBILE: 'MOBILE', | ||||
|     BANKER: 'BANKER', | ||||
|     SHOPKEEPER: 'SHOPKEEPER', | ||||
|     TRAINER: 'TRAINER', | ||||
|     MERCHANT: 'MERCHANT', | ||||
|     HIRELING: 'HIRELING', | ||||
|     PET: 'PET', | ||||
|     MINION: 'MINION', | ||||
| } | ||||
| 
 | ||||
| STRING_TO_MOBILE = { | ||||
|     'MOBILE': MOBILE, | ||||
|     'BANKER': BANKER, | ||||
|     'SHOPKEEPER': SHOPKEEPER, | ||||
|     'TRAINER': TRAINER, | ||||
|     'MERCHANT': MERCHANT, | ||||
|     'HIRELING': HIRELING, | ||||
|     'PET': PET, | ||||
|     'MINION': MINION, | ||||
| } | ||||
| @ -1,23 +0,0 @@@@ -1,23 +0,0 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| 
 | ||||
| PROP = 5 | ||||
| CITY = 6 | ||||
| CONTAINER = 7 | ||||
| 
 | ||||
| PROP_TO_STRING = { | ||||
|     PROP: 'PROP', | ||||
|     CITY: 'CITY', | ||||
|     CONTAINER: 'CONTAINER', | ||||
| } | ||||
| 
 | ||||
| STRING_TO_PROP = { | ||||
|     'PROP': PROP, | ||||
|     'CITY': CITY, | ||||
|     'CONTAINER': CONTAINER, | ||||
| } | ||||
| @ -1,35 +0,0 @@@@ -1,35 +0,0 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| 
 | ||||
| PEAKED = 1 | ||||
| RIDGED = 2 | ||||
| ROLLING = 3 | ||||
| MESA = 5 | ||||
| PLANAR = 4 | ||||
| MESH = 6 | ||||
| TARGA = 7 | ||||
| 
 | ||||
| TERRAIN_TYPE_TO_STRING = { | ||||
|     PEAKED: 'PEAKED', | ||||
|     RIDGED: 'RIDGED', | ||||
|     ROLLING: 'ROLLING', | ||||
|     MESA: 'MESA', | ||||
|     PLANAR: 'PLANAR', | ||||
|     MESH: 'MESH', | ||||
|     TARGA: 'TARGA', | ||||
| } | ||||
| 
 | ||||
| STRING_TO_TERRAIN_TYPE = { | ||||
|     'PEAKED': PEAKED, | ||||
|     'RIDGED': RIDGED, | ||||
|     'ROLLING': ROLLING, | ||||
|     'MESA': MESA, | ||||
|     'PLANAR': PLANAR, | ||||
|     'MESH': MESH, | ||||
|     'TARGA': TARGA, | ||||
| } | ||||
| @ -1,62 +0,0 @@@@ -1,62 +0,0 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| 
 | ||||
| ELLIPTICAL = 0 | ||||
| RECTANGULAR = 1 | ||||
| 
 | ||||
| ZONE_TO_STRING = { | ||||
|     ELLIPTICAL: 'ELLIPTICAL', | ||||
|     RECTANGULAR: 'RECTANGULAR', | ||||
| } | ||||
| 
 | ||||
| STRING_TO_ZONE = { | ||||
|     'ELLIPTICAL': ELLIPTICAL, | ||||
|     'RECTANGULAR': RECTANGULAR, | ||||
| } | ||||
| 
 | ||||
| GLOBAL = 0 | ||||
| LOCAL = 1 | ||||
| 
 | ||||
| TILECOORD_TO_STRING = { | ||||
|     GLOBAL: 'GLOBAL', | ||||
|     LOCAL: 'LOCAL', | ||||
| } | ||||
| 
 | ||||
| STRING_TO_TILECOORD = { | ||||
|     'GLOBAL': GLOBAL, | ||||
|     'LOCAL': LOCAL, | ||||
| } | ||||
| 
 | ||||
| ADJACENT = 0 | ||||
| RANDOM = 1 | ||||
| 
 | ||||
| PATTERN_TO_STRING = { | ||||
|     ADJACENT: 'ADJACENT', | ||||
|     RANDOM: 'RANDOM', | ||||
| } | ||||
| 
 | ||||
| STRING_TO_PATTERN = { | ||||
|     'ADJACENT': ADJACENT, | ||||
|     'RANDOM': RANDOM, | ||||
| } | ||||
| 
 | ||||
| PARENT = 0 | ||||
| WORLD = 1 | ||||
| SELF = 2 | ||||
| 
 | ||||
| SEALEVEL_TO_STRING = { | ||||
|     PARENT: 'PARENT', | ||||
|     WORLD: 'WORLD', | ||||
|     SELF: 'SELF', | ||||
| } | ||||
| 
 | ||||
| STRING_TO_SEALEVEL = { | ||||
|     'PARENT': PARENT, | ||||
|     'WORLD': WORLD, | ||||
|     'SELF': SELF, | ||||
| } | ||||
| @ -1,29 +0,0 @@@@ -1,29 +0,0 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| 
 | ||||
| from arcane.util import ResStream | ||||
| from .ArcStructureObject import ArcStructureObject | ||||
| 
 | ||||
| 
 | ||||
| class ArcAssetStructureObject(ArcStructureObject): | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         super().load_binary(stream) | ||||
|         self.asset_structure_template_id = stream.read_qword() | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         super().save_binary(stream) | ||||
|         stream.write_qword(self.asset_structure_template_id) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         super().load_json(data) | ||||
|         self.asset_structure_template_id = data['asset_structure_template_id'] | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = super().save_json() | ||||
|         data['asset_structure_template_id'] = self.asset_structure_template_id | ||||
|         return data | ||||
| @ -1,21 +0,0 @@@@ -1,21 +0,0 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| 
 | ||||
| from .ArcAssetStructureObject import ArcAssetStructureObject | ||||
| from .ArcCityAssetTemplate import ArcCityAssetTemplate | ||||
| from .ArcCombatObj import ArcCombatObj, ArcCharacter | ||||
| from .ArcContainerObject import ArcContainerObject | ||||
| from .ArcDeed import ArcDeed | ||||
| from .ArcDoorObject import ArcDoorObject | ||||
| from .ArcDungeonUnitObject import ArcDungeonUnitObject, ArcDungeonExitObject, ArcDungeonStairObject | ||||
| from .ArcItem import ArcItem | ||||
| from .ArcKey import ArcKey | ||||
| from .ArcObj import ArcObj | ||||
| from .ArcRune import ArcRune | ||||
| from .ArcStaticObject import ArcStaticObject | ||||
| from .ArcStructureObject import ArcStructureObject | ||||
| @ -1,40 +0,0 @@@@ -1,40 +0,0 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| from collections import OrderedDict | ||||
| 
 | ||||
| from arcane.enums.hashes import hash_to_string, string_to_hash | ||||
| from arcane.util import ResStream | ||||
| 
 | ||||
| 
 | ||||
| class DiscRequired: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         discs = stream.read_dword() | ||||
|         self.disc_restrict = stream.read_bool() | ||||
|         self.disc_values = [ | ||||
|             stream.read_dword() for _ in range(discs) | ||||
|         ] | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         stream.write_dword(len(self.disc_values)) | ||||
|         stream.write_bool(self.disc_restrict) | ||||
|         for disc in self.disc_values: | ||||
|             stream.write_dword(disc) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.disc_restrict = data['restrict'] | ||||
|         self.disc_values = [] | ||||
|         for disc in data['disces']: | ||||
|             self.disc_values.append(string_to_hash(disc)) | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         data['restrict'] = self.disc_restrict | ||||
|         data['disces'] = [] | ||||
|         for disc in self.disc_values: | ||||
|             data['disces'].append(hash_to_string(disc)) | ||||
|         return data | ||||
| @ -1,40 +0,0 @@@@ -1,40 +0,0 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| from collections import OrderedDict | ||||
| 
 | ||||
| from arcane.enums.hashes import hash_to_string, string_to_hash | ||||
| from arcane.util import ResStream | ||||
| 
 | ||||
| 
 | ||||
| class RaceRequired: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         races = stream.read_dword() | ||||
|         self.race_restrict = stream.read_bool() | ||||
|         self.race_values = [ | ||||
|             stream.read_dword() for _ in range(races) | ||||
|         ] | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         stream.write_dword(len(self.race_values)) | ||||
|         stream.write_bool(self.race_restrict) | ||||
|         for race in self.race_values: | ||||
|             stream.write_dword(race) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.race_restrict = data['restrict'] | ||||
|         self.race_values = [] | ||||
|         for race in data['racees']: | ||||
|             self.race_values.append(string_to_hash(race)) | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         data['restrict'] = self.race_restrict | ||||
|         data['racees'] = [] | ||||
|         for race in self.race_values: | ||||
|             data['racees'].append(hash_to_string(race)) | ||||
|         return data | ||||
| @ -1,7 +0,0 @@@@ -1,7 +0,0 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| @ -1,10 +0,0 @@@@ -1,10 +0,0 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| 
 | ||||
| from .ArcFileCache import load_cache_file, save_cache_file | ||||
| from .ResStream import ResStream | ||||
| @ -1,39 +0,0 @@@@ -1,39 +0,0 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| 
 | ||||
| from collections import OrderedDict | ||||
| 
 | ||||
| from arcane.util import ResStream | ||||
| 
 | ||||
| 
 | ||||
| class ArcDungeonInfo: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         self.dungeon_template_id = stream.read_qword() | ||||
|         self.dungeon_unkown = stream.read_qword() | ||||
|         self.dungeon_spawn_location = stream.read_tuple() | ||||
|         self.dungeon_y_offset = stream.read_float() | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         stream.write_qword(self.dungeon_template_id) | ||||
|         stream.write_qword(self.dungeon_unkown) | ||||
|         stream.write_tuple(self.dungeon_spawn_location) | ||||
|         stream.write_float(self.dungeon_y_offset) | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         data['dungeon_template_id'] = self.dungeon_template_id | ||||
|         data['dungeon_unkown'] = self.dungeon_unkown | ||||
|         data['dungeon_spawn_location'] = self.dungeon_spawn_location | ||||
|         data['dungeon_y_offset'] = self.dungeon_y_offset | ||||
|         return data | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.dungeon_template_id = data['dungeon_template_id'] | ||||
|         self.dungeon_unkown = data['dungeon_unkown'] | ||||
|         self.dungeon_spawn_location = data['dungeon_spawn_location'] | ||||
|         self.dungeon_y_offset = data['dungeon_y_offset'] | ||||
| @ -1,9 +0,0 @@@@ -1,9 +0,0 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| 
 | ||||
| from .ArcZone import ArcZone | ||||
| @ -1,20 +0,0 @@@@ -1,20 +0,0 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| 
 | ||||
| from arcane.util import ResStream | ||||
| from .HirelingInfo import HirelingInfo | ||||
| 
 | ||||
| 
 | ||||
| class MinionInfo(HirelingInfo): | ||||
|     def __init__(self): | ||||
|         super().__init__() | ||||
|         self.minion_info_u = None | ||||
| 
 | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         super().load_binary(stream) | ||||
|         self.minion_info_u = stream.read_string() | ||||
| @ -1,7 +0,0 @@@@ -1,7 +0,0 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| @ -1,223 +0,0 @@@@ -1,223 +0,0 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| 
 | ||||
| import glob | ||||
| import json | ||||
| import os | ||||
| import sys | ||||
| 
 | ||||
| from arcane.enums.arc_object import * | ||||
| from arcane.objects import * | ||||
| from arcane.util import * | ||||
| from arcane.zones import * | ||||
| 
 | ||||
| DUMP_DIRECTORY = 'ARCANE_DUMP' | ||||
| WORKING_DIRECTORY = os.path.dirname(__file__) | ||||
| TARGET_DIRECTORY = os.path.join(WORKING_DIRECTORY, DUMP_DIRECTORY) | ||||
| COBJECTS_DIRECTORY = os.path.join(TARGET_DIRECTORY, 'COBJECTS') | ||||
| CZONE_DIRECTORY = os.path.join(TARGET_DIRECTORY, 'CZONE') | ||||
| COBJECTS_MAGIC = 0x434c4e54 | ||||
| 
 | ||||
| COBJECTS_MAP = { | ||||
|     OBJECT_TYPE_LIGHT: ArcObj, | ||||
|     OBJECT_TYPE_DOOR: ArcDoorObject, | ||||
|     OBJECT_TYPE_STATIC: ArcStaticObject, | ||||
|     OBJECT_TYPE_STRUCTURE: ArcStructureObject, | ||||
|     OBJECT_TYPE_ASSETSTRUCTURE: ArcAssetStructureObject, | ||||
|     OBJECT_TYPE_DUNGEONUNIT: ArcDungeonUnitObject, | ||||
|     OBJECT_TYPE_DUNGEONEXIT: ArcDungeonExitObject, | ||||
|     OBJECT_TYPE_DUNGEONSTAIR: ArcDungeonStairObject, | ||||
|     OBJECT_TYPE_ITEM: ArcItem, | ||||
|     OBJECT_TYPE_PLAYER: ArcCharacter, | ||||
|     OBJECT_TYPE_MOBILE: ArcCharacter, | ||||
|     OBJECT_TYPE_RUNE: ArcRune, | ||||
|     OBJECT_TYPE_CONTAINER: ArcContainerObject, | ||||
|     OBJECT_TYPE_DEED: ArcDeed, | ||||
|     OBJECT_TYPE_KEY: ArcKey, | ||||
|     OBJECT_TYPE_ASSET: ArcCityAssetTemplate, | ||||
|     OBJECT_TYPE_OBJECT: ArcObj, | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| def init_cobjects(): | ||||
|     for type in COBJECTS_MAP: | ||||
|         directory_path = os.path.join(COBJECTS_DIRECTORY, OBJECT_TYPE_TO_STRING[type]) | ||||
|         os.makedirs(directory_path, exist_ok=True) | ||||
| 
 | ||||
| 
 | ||||
| def init_czones(): | ||||
|     directory_path = CZONE_DIRECTORY | ||||
|     os.makedirs(directory_path, exist_ok=True) | ||||
| 
 | ||||
| 
 | ||||
| def unpack_cobjects(): | ||||
|     init_cobjects() | ||||
| 
 | ||||
|     resources = load_cache_file('CObjects.cache') | ||||
| 
 | ||||
|     for res_id, data in resources: | ||||
|         in_stream = ResStream(data) | ||||
|         magic = in_stream.read_dword() | ||||
|         obj_type = in_stream.read_dword() | ||||
| 
 | ||||
|         arc_object = COBJECTS_MAP[obj_type]() | ||||
|         filepath = os.path.join( | ||||
|             COBJECTS_DIRECTORY, | ||||
|             OBJECT_TYPE_TO_STRING[obj_type], | ||||
|             f'{res_id:020d}.json' | ||||
|         ) | ||||
|         arc_object.load_binary(in_stream) | ||||
|         parsed = arc_object.save_json() | ||||
|         with open(filepath, 'w') as fp: | ||||
|             json.dump(parsed, fp, indent=2) | ||||
| 
 | ||||
| 
 | ||||
| def pack_cobjects(): | ||||
|     init_cobjects() | ||||
| 
 | ||||
|     resources = [] | ||||
|     for obj_type in COBJECTS_MAP: | ||||
|         directory = os.path.join( | ||||
|             COBJECTS_DIRECTORY, | ||||
|             OBJECT_TYPE_TO_STRING[obj_type] | ||||
|         ) | ||||
|         for filepath in glob.glob(os.path.join(directory, '*.json')): | ||||
|             filename = os.path.basename(filepath) | ||||
|             res_id = int(filename.split('.json')[0]) | ||||
|             json_data = json.load(open(filepath)) | ||||
| 
 | ||||
|             out_stream = ResStream() | ||||
|             out_stream.write_dword(COBJECTS_MAGIC) | ||||
|             out_stream.write_dword(obj_type) | ||||
| 
 | ||||
|             arc_object = COBJECTS_MAP[obj_type]() | ||||
|             try: | ||||
|                 arc_object.load_json(json_data) | ||||
|                 arc_object.save_binary(out_stream) | ||||
|             except: | ||||
|                 print(res_id) | ||||
|                 raise | ||||
| 
 | ||||
|             resources.append([res_id, out_stream.get_bytes()]) | ||||
| 
 | ||||
|     save_cache_file('CObjects.cache.new', resources) | ||||
| 
 | ||||
| 
 | ||||
| def test_cobjects(): | ||||
|     resources = load_cache_file('CObjects.cache') | ||||
| 
 | ||||
|     for res_id, data in resources: | ||||
|         in_stream = ResStream(data) | ||||
|         out_stream = ResStream() | ||||
| 
 | ||||
|         magic = in_stream.read_dword() | ||||
|         o_type = in_stream.read_dword() | ||||
|         out_stream.write_dword(magic) | ||||
|         out_stream.write_dword(o_type) | ||||
| 
 | ||||
|         arc_in = COBJECTS_MAP[o_type]() | ||||
|         arc_out = COBJECTS_MAP[o_type]() | ||||
| 
 | ||||
|         arc_in.load_binary(in_stream) | ||||
|         parsed = arc_in.save_json() | ||||
|         arc_out.load_json(parsed) | ||||
|         arc_out.save_binary(out_stream) | ||||
|         try: | ||||
|             assert in_stream.get_bytes() == out_stream.get_bytes() | ||||
|         except: | ||||
|             print(res_id, in_stream.buffer.tell(), out_stream.buffer.tell()) | ||||
|             print() | ||||
| 
 | ||||
| 
 | ||||
| def unpack_czones(): | ||||
|     init_czones() | ||||
| 
 | ||||
|     resources = load_cache_file('CZone.cache') | ||||
| 
 | ||||
|     for res_id, data in resources: | ||||
|         arc_zone = ArcZone() | ||||
|         in_stream = ResStream(data) | ||||
|         filepath = os.path.join( | ||||
|             CZONE_DIRECTORY, | ||||
|             f'{res_id:020d}.json' | ||||
|         ) | ||||
|         arc_zone.load_binary(in_stream) | ||||
|         parsed = arc_zone.save_json() | ||||
|         with open(filepath, 'w') as fp: | ||||
|             json.dump(parsed, fp, indent=2) | ||||
| 
 | ||||
| 
 | ||||
| def pack_czones(): | ||||
|     init_czones() | ||||
| 
 | ||||
|     resources = [] | ||||
|     directory = CZONE_DIRECTORY | ||||
|     for filepath in glob.glob(os.path.join(directory, '*.json')): | ||||
|         filename = os.path.basename(filepath) | ||||
|         res_id = int(filename.split('.json')[0]) | ||||
|         json_data = json.load(open(filepath)) | ||||
| 
 | ||||
|         out_stream = ResStream() | ||||
|         arc_object = ArcZone() | ||||
|         try: | ||||
|             arc_object.load_json(json_data) | ||||
|             arc_object.save_binary(out_stream) | ||||
|         except: | ||||
|             print(res_id) | ||||
|             raise | ||||
| 
 | ||||
|         resources.append([res_id, out_stream.get_bytes()]) | ||||
| 
 | ||||
|     save_cache_file('CZone.cache.new', resources) | ||||
| 
 | ||||
| 
 | ||||
| def test_czones(): | ||||
|     resources = load_cache_file('CZone.cache') | ||||
|     for res_id, data in resources: | ||||
|         in_stream = ResStream(data) | ||||
|         out_stream = ResStream() | ||||
| 
 | ||||
|         arc_in = ArcZone() | ||||
|         arc_out = ArcZone() | ||||
| 
 | ||||
|         arc_in.load_binary(in_stream) | ||||
|         parsed = arc_in.save_json() | ||||
|         arc_out.load_json(parsed) | ||||
|         arc_out.save_binary(out_stream) | ||||
|         try: | ||||
|             assert in_stream.get_bytes() == out_stream.get_bytes() | ||||
|         except: | ||||
|             print(res_id, in_stream.buffer.tell(), out_stream.buffer.tell()) | ||||
|             print() | ||||
| 
 | ||||
| 
 | ||||
| def usage(): | ||||
|     print('mbEditorPro commands:') | ||||
|     print('usage: {} unpack cobjects'.format(sys.argv[0])) | ||||
|     print('usage: {} pack cobjects'.format(sys.argv[0])) | ||||
|     print('usage: {} unpack czones'.format(sys.argv[0])) | ||||
|     print('usage: {} pack czones'.format(sys.argv[0])) | ||||
|     exit(1) | ||||
| 
 | ||||
| 
 | ||||
| def main(): | ||||
|     if not sys.argv[2:]: | ||||
|         usage() | ||||
| 
 | ||||
|     if sys.argv[1] not in ['pack', 'unpack']: | ||||
|         usage() | ||||
| 
 | ||||
|     if sys.argv[2] not in ['cobjects', 'czones']: | ||||
|         usage() | ||||
| 
 | ||||
|     method = '_'.join(sys.argv[1:3]) + '()' | ||||
|     print(method) | ||||
|     exec(method) | ||||
| 
 | ||||
| 
 | ||||
| main() | ||||
| @ -0,0 +1,70 @@@@ -0,0 +1,70 @@ | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from PIL import Image, ImageOps | ||||
| 
 | ||||
| from arcane.util import ResStream | ||||
| 
 | ||||
| 
 | ||||
| class ArcTexture: | ||||
|     VALUE_TO_MODE = { | ||||
|         (4, 8, 2): 'RGBA', | ||||
|         (3, 0, 0): 'RGB', | ||||
|         (1, 0, 0): 'L', | ||||
|         (1, 8, 2): 'P', | ||||
|     } | ||||
| 
 | ||||
|     MODE_TO_VALUE = {value: key for key, value in VALUE_TO_MODE.items()} | ||||
| 
 | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         self.image_width = stream.read_dword() | ||||
|         self.image_height = stream.read_dword() | ||||
|         self.image_color_depth = stream.read_dword() | ||||
|         self.image_alpha = stream.read_dword() | ||||
|         self.image_type = stream.read_dword() | ||||
|         self.image_compressed = stream.read_bool() | ||||
|         self.image_linear = stream.read_bool() | ||||
|         data_size = stream.read_dword() | ||||
|         self.image_data = stream.read_bytes(data_size) | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         stream.write_dword(self.image_width) | ||||
|         stream.write_dword(self.image_height) | ||||
|         stream.write_dword(self.image_color_depth) | ||||
|         stream.write_dword(self.image_alpha) | ||||
|         stream.write_dword(self.image_type) | ||||
|         stream.write_bool(self.image_compressed) | ||||
|         stream.write_bool(self.image_linear) | ||||
|         stream.write_dword(len(self.image_data)) | ||||
|         stream.write_bytes(self.image_data) | ||||
| 
 | ||||
|     def load_img(self, filepath): | ||||
|         img = Image.open(filepath) | ||||
|         img = ImageOps.mirror(img).rotate(180) | ||||
|         self.image_width = img.width | ||||
|         self.image_height = img.height | ||||
|         self.image_color_depth, self.image_alpha, self.image_type = self.MODE_TO_VALUE[img.mode] | ||||
|         self.image_compressed = True | ||||
|         self.image_linear = True | ||||
|         self.image_data = img.tobytes() | ||||
| 
 | ||||
|     def save_img(self, filepath): | ||||
|         mode = self.VALUE_TO_MODE[ | ||||
|             (self.image_color_depth, self.image_alpha, self.image_type) | ||||
|         ] | ||||
|         img = Image.frombytes(mode, (self.image_width, self.image_height), self.image_data) | ||||
|         img = ImageOps.mirror(img.rotate(180)) | ||||
|         img.save(filepath) | ||||
| 
 | ||||
| 
 | ||||
| class ArcTerrain(ArcTexture): | ||||
|     VALUE_TO_MODE = { | ||||
|         (1, 1, 0): 'P', | ||||
|     } | ||||
| 
 | ||||
|     MODE_TO_VALUE = {value: key for key, value in VALUE_TO_MODE.items()} | ||||
| @ -0,0 +1,113 @@@@ -0,0 +1,113 @@ | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from collections import OrderedDict | ||||
| 
 | ||||
| from arcane.util import ResStream | ||||
| 
 | ||||
| 
 | ||||
| class ArcMesh: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         self.mesh_name = stream.read_string() | ||||
|         self.mesh_distance = stream.read_float() | ||||
|         self.mesh_start_point = stream.read_tuple() | ||||
|         self.mesh_end_point = stream.read_tuple() | ||||
|         self.mesh_ref_point = stream.read_tuple() | ||||
|         self.mesh_use_face_normals = stream.read_bool() | ||||
|         self.mesh_use_tangent_basis = stream.read_bool() | ||||
|         num_vertices = stream.read_dword() | ||||
|         self.mesh_vertices = [stream.read_tuple() for _ in range(num_vertices)] | ||||
|         num_other_vertices = stream.read_dword() | ||||
|         self.mesh_normals = [stream.read_tuple() for _ in range(num_other_vertices)] | ||||
|         num = stream.read_dword() | ||||
|         self.mesh_uv = [ | ||||
|             [ | ||||
|                 stream.read_float(), | ||||
|                 stream.read_float(), | ||||
|             ] for _ in range(num) | ||||
|         ] | ||||
|         if self.mesh_use_tangent_basis: | ||||
|             num_tangent_vertices = stream.read_dword() | ||||
|             self.mesh_tanget_vertices = [stream.read_tuple() for _ in range(num_tangent_vertices)] | ||||
|         num_indicies = stream.read_dword() | ||||
|         self.mesh_indices = [stream.read_word() for _ in range(num_indicies)] | ||||
|         num = stream.read_dword() | ||||
|         self.mesh_extra_indices = [ | ||||
|             [ | ||||
|                 stream.read_dword(), | ||||
|                 stream.read_dword(), | ||||
|                 [stream.read_word() for _ in range(stream.read_dword())], | ||||
|             ] for _ in range(num) | ||||
|         ] | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         stream.write_string(self.mesh_name) | ||||
|         stream.write_float(self.mesh_distance) | ||||
|         stream.write_tuple(self.mesh_start_point) | ||||
|         stream.write_tuple(self.mesh_end_point) | ||||
|         stream.write_tuple(self.mesh_ref_point) | ||||
|         stream.write_bool(self.mesh_use_face_normals) | ||||
|         stream.write_bool(self.mesh_use_tangent_basis) | ||||
|         stream.write_dword(len(self.mesh_vertices)) | ||||
|         for i in range(len(self.mesh_vertices)): | ||||
|             stream.write_tuple(self.mesh_vertices[i]) | ||||
|         stream.write_dword(len(self.mesh_normals)) | ||||
|         for i in range(len(self.mesh_normals)): | ||||
|             stream.write_tuple(self.mesh_normals[i]) | ||||
|         stream.write_dword(len(self.mesh_uv)) | ||||
|         for i in range(len(self.mesh_uv)): | ||||
|             stream.write_float(self.mesh_uv[i][0]) | ||||
|             stream.write_float(self.mesh_uv[i][1]) | ||||
|         if self.mesh_use_tangent_basis: | ||||
|             stream.write_dword(len(self.mesh_tanget_vertices)) | ||||
|             for i in range(len(self.mesh_tanget_vertices)): | ||||
|                 stream.write_tuple(self.mesh_tanget_vertices[i]) | ||||
|         stream.write_dword(len(self.mesh_indices)) | ||||
|         for i in range(len(self.mesh_indices)): | ||||
|             stream.write_word(self.mesh_indices[i]) | ||||
|         stream.write_dword(len(self.mesh_extra_indices)) | ||||
|         for i in range(len(self.mesh_extra_indices)): | ||||
|             stream.write_dword(self.mesh_extra_indices[i][0]) | ||||
|             stream.write_dword(self.mesh_extra_indices[i][1]) | ||||
|             stream.write_dword(len(self.mesh_extra_indices[i][2])) | ||||
|             for j in range(len(self.mesh_extra_indices[i][2])): | ||||
|                 stream.write_word(self.mesh_extra_indices[i][2][j]) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.mesh_name = data['mesh_name'] | ||||
|         self.mesh_distance = data['mesh_distance'] | ||||
|         self.mesh_start_point = data['mesh_start_point'] | ||||
|         self.mesh_end_point = data['mesh_end_point'] | ||||
|         self.mesh_ref_point = data['mesh_ref_point'] | ||||
|         self.mesh_use_face_normals = data['mesh_use_face_normals'] | ||||
|         self.mesh_use_tangent_basis = data['mesh_use_tangent_basis'] | ||||
|         self.mesh_vertices = data['mesh_vertices'] | ||||
|         self.mesh_normals = data['mesh_normals'] | ||||
|         self.mesh_uv = data['mesh_uv'] | ||||
|         if self.mesh_use_tangent_basis: | ||||
|             self.mesh_tanget_vertices = data['mesh_tanget_vertices'] | ||||
|         self.mesh_indices = data['mesh_indices'] | ||||
|         self.mesh_extra_indices = data['mesh_extra_indices'] | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         data['mesh_name'] = self.mesh_name | ||||
|         data['mesh_distance'] = self.mesh_distance | ||||
|         data['mesh_start_point'] = self.mesh_start_point | ||||
|         data['mesh_end_point'] = self.mesh_end_point | ||||
|         data['mesh_ref_point'] = self.mesh_ref_point | ||||
|         data['mesh_use_face_normals'] = self.mesh_use_face_normals | ||||
|         data['mesh_use_tangent_basis'] = self.mesh_use_tangent_basis | ||||
|         data['mesh_vertices'] = self.mesh_vertices | ||||
|         data['mesh_normals'] = self.mesh_normals | ||||
|         data['mesh_uv'] = self.mesh_uv | ||||
|         if self.mesh_use_tangent_basis: | ||||
|             data['mesh_tanget_vertices'] = self.mesh_tanget_vertices | ||||
|         data['mesh_indices'] = self.mesh_indices | ||||
|         data['mesh_extra_indices'] = self.mesh_extra_indices | ||||
|         return data | ||||
| @ -0,0 +1,89 @@@@ -0,0 +1,89 @@ | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from collections import OrderedDict | ||||
| 
 | ||||
| from arcane.util import ResStream | ||||
| 
 | ||||
| 
 | ||||
| class ArcMotion: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         self.motion_file = stream.read_string() | ||||
|         self.motion_smoothed_count = stream.read_dword() | ||||
|         self.motion_smoothed_value = stream.read_dword() | ||||
|         self.motion_smoothed_factor = stream.read_float() | ||||
|         self.motion_sound = stream.read_qword() | ||||
|         self.motion_sheath = stream.read_dword() | ||||
|         self.motion_reset_loc = stream.read_bool() | ||||
|         self.motion_leave_ground = stream.read_bool() | ||||
|         self.motion_force = stream.read_float() | ||||
|         self.motion_disable_blend = stream.read_bool() | ||||
|         num_parts = stream.read_dword() | ||||
|         self.motion_parts = [stream.read_string() for _ in range(num_parts)] | ||||
|         num_smoothing = stream.read_dword() | ||||
|         self.motion_smoothing = [ | ||||
|             [ | ||||
|                 stream.read_float() for _ in range(10) | ||||
|             ] for _ in range(num_smoothing) | ||||
|         ] | ||||
|         num_target_frames = stream.read_dword() | ||||
|         self.motion_target_frames = [stream.read_dword() for _ in range(num_target_frames)] | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         stream.write_string(self.motion_file) | ||||
|         stream.write_dword(self.motion_smoothed_count) | ||||
|         stream.write_dword(self.motion_smoothed_value) | ||||
|         stream.write_float(self.motion_smoothed_factor) | ||||
|         stream.write_qword(self.motion_sound) | ||||
|         stream.write_dword(self.motion_sheath) | ||||
|         stream.write_bool(self.motion_reset_loc) | ||||
|         stream.write_bool(self.motion_leave_ground) | ||||
|         stream.write_float(self.motion_force) | ||||
|         stream.write_bool(self.motion_disable_blend) | ||||
|         stream.write_dword(len(self.motion_parts)) | ||||
|         for i in range(len(self.motion_parts)): | ||||
|             stream.write_string(self.motion_parts[i]) | ||||
|         stream.write_dword(len(self.motion_smoothing)) | ||||
|         for i in range(len(self.motion_smoothing)): | ||||
|             for j in range(10): | ||||
|                 stream.write_float(self.motion_smoothing[i][j]) | ||||
|         stream.write_dword(len(self.motion_target_frames)) | ||||
|         for i in range(len(self.motion_target_frames)): | ||||
|             stream.write_dword(self.motion_target_frames[i]) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.motion_file = data['motion_file'] | ||||
|         self.motion_smoothed_count = data['motion_smoothed_count'] | ||||
|         self.motion_smoothed_value = data['motion_smoothed_value'] | ||||
|         self.motion_smoothed_factor = data['motion_smoothed_factor'] | ||||
|         self.motion_sound = data['motion_sound'] | ||||
|         self.motion_sheath = data['motion_sheath'] | ||||
|         self.motion_reset_loc = data['motion_reset_loc'] | ||||
|         self.motion_leave_ground = data['motion_leave_ground'] | ||||
|         self.motion_force = data['motion_force'] | ||||
|         self.motion_disable_blend = data['motion_disable_blend'] | ||||
|         self.motion_parts = data['motion_parts'] | ||||
|         self.motion_smoothing = data['motion_smoothing'] | ||||
|         self.motion_target_frames = data['motion_target_frames'] | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         data['motion_file'] = self.motion_file | ||||
|         data['motion_smoothed_count'] = self.motion_smoothed_count | ||||
|         data['motion_smoothed_value'] = self.motion_smoothed_value | ||||
|         data['motion_smoothed_factor'] = self.motion_smoothed_factor | ||||
|         data['motion_sound'] = self.motion_sound | ||||
|         data['motion_sheath'] = self.motion_sheath | ||||
|         data['motion_reset_loc'] = self.motion_reset_loc | ||||
|         data['motion_leave_ground'] = self.motion_leave_ground | ||||
|         data['motion_force'] = self.motion_force | ||||
|         data['motion_disable_blend'] = self.motion_disable_blend | ||||
|         data['motion_parts'] = self.motion_parts | ||||
|         data['motion_smoothing'] = self.motion_smoothing | ||||
|         data['motion_target_frames'] = self.motion_target_frames | ||||
|         return data | ||||
| @ -0,0 +1,644 @@@@ -0,0 +1,644 @@ | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from collections import OrderedDict | ||||
| 
 | ||||
| from arcane.util import ResStream | ||||
| 
 | ||||
| TRACKER_TO_STRING = { | ||||
|     0: 'NONE', | ||||
|     1: 'XY', | ||||
|     2: 'Y', | ||||
| } | ||||
| STRING_TO_TRACKER = {value: key for key, value in TRACKER_TO_STRING.items()} | ||||
| 
 | ||||
| TRANSPARENT_TO_STRING = { | ||||
|     0: 'NONE', | ||||
|     1: 'PINK', | ||||
|     2: 'BLACK', | ||||
|     3: 'WHITE', | ||||
|     4: 'SEMI', | ||||
|     6: 'ALPHA', | ||||
| } | ||||
| STRING_TO_TRANSPARENT = {value: key for key, value in TRANSPARENT_TO_STRING.items()} | ||||
| 
 | ||||
| TEXTURE_TO_STRING = { | ||||
|     0: 'SINGLE_TEXTURE', | ||||
|     1: 'COLOR_TEXTURE', | ||||
|     3: 'ANIMATED_TEXTURE', | ||||
| } | ||||
| STRING_TO_TEXTURE = {value: key for key, value in TEXTURE_TO_STRING.items()} | ||||
| 
 | ||||
| LIGHT_TYPE_TO_STRING = { | ||||
|     0xb6787258: 'ArcLightPoint', | ||||
|     0x54e8ff1d: 'ArcLightAffectorAttach', | ||||
|     0xa73bd9d4: 'ArcLightAffectorFlicker', | ||||
| } | ||||
| STRING_TO_LIGHT_TYPE = {value: key for key, value in LIGHT_TYPE_TO_STRING.items()} | ||||
| 
 | ||||
| 
 | ||||
| class ArcSinglePolyMesh: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         self.polymesh_id = stream.read_qword() | ||||
|         self.polymesh_decal = stream.read_bool() | ||||
|         self.polymesh_double_sided = stream.read_bool() | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         stream.write_qword(self.polymesh_id) | ||||
|         stream.write_bool(self.polymesh_decal) | ||||
|         stream.write_bool(self.polymesh_double_sided) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.polymesh_id = data['polymesh_id'] | ||||
|         self.polymesh_decal = data['polymesh_decal'] | ||||
|         self.polymesh_double_sided = data['polymesh_double_sided'] | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         data['polymesh_id'] = self.polymesh_id | ||||
|         data['polymesh_decal'] = self.polymesh_decal | ||||
|         data['polymesh_double_sided'] = self.polymesh_double_sided | ||||
|         return data | ||||
| 
 | ||||
| 
 | ||||
| class ArcMeshSet: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         num = stream.read_dword() | ||||
|         self.mesh_set = [ArcSinglePolyMesh() for _ in range(num)] | ||||
|         for mesh in self.mesh_set: | ||||
|             mesh.load_binary(stream) | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         stream.write_dword(len(self.mesh_set)) | ||||
|         for mesh in self.mesh_set: | ||||
|             mesh.save_binary(stream) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.mesh_set = [] | ||||
|         for mesh_data in data['mesh_set']: | ||||
|             mesh = ArcSinglePolyMesh() | ||||
|             mesh.load_json(mesh_data) | ||||
|             self.mesh_set.append(mesh) | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         data['mesh_set'] = [] | ||||
|         for mesh in self.mesh_set: | ||||
|             data['mesh_set'].append(mesh.save_json()) | ||||
|         return data | ||||
| 
 | ||||
| 
 | ||||
| class ArcRenderTemplate: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         self.template_object_can_fade = stream.read_bool() | ||||
|         self.template_tracker = stream.read_dword() | ||||
|         self.template_illuminated = stream.read_bool() | ||||
|         self.template_bone_length = stream.read_float() | ||||
|         self.template_clip_map = stream.read_dword() | ||||
|         self.template_light_two_side = stream.read_dword() | ||||
|         self.template_cull_face = stream.read_dword() | ||||
|         self.template_specular_map = stream.read_qword() | ||||
|         self.template_shininess = stream.read_float() | ||||
|         self.template_has_mesh = stream.read_bool() | ||||
|         if self.template_has_mesh: | ||||
|             self.template_mesh = ArcMeshSet() | ||||
|             self.template_mesh.load_binary(stream) | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         stream.write_bool(self.template_object_can_fade) | ||||
|         stream.write_dword(self.template_tracker) | ||||
|         stream.write_bool(self.template_illuminated) | ||||
|         stream.write_float(self.template_bone_length) | ||||
|         stream.write_dword(self.template_clip_map) | ||||
|         stream.write_dword(self.template_light_two_side) | ||||
|         stream.write_dword(self.template_cull_face) | ||||
|         stream.write_qword(self.template_specular_map) | ||||
|         stream.write_float(self.template_shininess) | ||||
|         stream.write_bool(self.template_has_mesh) | ||||
|         if self.template_has_mesh: | ||||
|             self.template_mesh.save_binary(stream) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.template_object_can_fade = data['template_object_can_fade'] | ||||
|         self.template_tracker = STRING_TO_TRACKER[data['template_tracker']] | ||||
|         self.template_illuminated = data['template_illuminated'] | ||||
|         self.template_bone_length = data['template_bone_length'] | ||||
|         self.template_clip_map = data['template_clip_map'] | ||||
|         self.template_light_two_side = data['template_light_two_side'] | ||||
|         self.template_cull_face = data['template_cull_face'] | ||||
|         self.template_specular_map = data['template_specular_map'] | ||||
|         self.template_shininess = data['template_shininess'] | ||||
|         self.template_has_mesh = data['template_has_mesh'] | ||||
|         if self.template_has_mesh: | ||||
|             self.template_mesh = ArcMeshSet() | ||||
|             self.template_mesh.load_json(data['template_mesh']) | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         data['template_object_can_fade'] = self.template_object_can_fade | ||||
|         data['template_tracker'] = TRACKER_TO_STRING[self.template_tracker] | ||||
|         data['template_illuminated'] = self.template_illuminated | ||||
|         data['template_bone_length'] = self.template_bone_length | ||||
|         data['template_clip_map'] = self.template_clip_map | ||||
|         data['template_light_two_side'] = self.template_light_two_side | ||||
|         data['template_cull_face'] = self.template_cull_face | ||||
|         data['template_specular_map'] = self.template_specular_map | ||||
|         data['template_shininess'] = self.template_shininess | ||||
|         data['template_has_mesh'] = self.template_has_mesh | ||||
|         if self.template_has_mesh: | ||||
|             data['template_mesh'] = self.template_mesh.save_json() | ||||
|         return data | ||||
| 
 | ||||
| 
 | ||||
| class ArcSingleTexture: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         self.texture_id = stream.read_qword() | ||||
|         self.texture_transparent = stream.read_dword() | ||||
|         self.texture_compress = stream.read_bool() | ||||
|         self.texture_normal_map = stream.read_bool() | ||||
|         self.texture_detail_normal_map = stream.read_bool() | ||||
|         self.texture_create_mip_maps = stream.read_bool() | ||||
|         self.texture_x0 = stream.read_string() | ||||
|         self.texture_x1 = stream.read_string() | ||||
|         self.texture_x2 = stream.read_dword() | ||||
|         self.texture_x3 = stream.read_dword() | ||||
|         self.texture_x4 = stream.read_bool() | ||||
|         self.texture_wrap = stream.read_bool() | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         stream.write_qword(self.texture_id) | ||||
|         stream.write_dword(self.texture_transparent) | ||||
|         stream.write_bool(self.texture_compress) | ||||
|         stream.write_bool(self.texture_normal_map) | ||||
|         stream.write_bool(self.texture_detail_normal_map) | ||||
|         stream.write_bool(self.texture_create_mip_maps) | ||||
|         stream.write_string(self.texture_x0) | ||||
|         stream.write_string(self.texture_x1) | ||||
|         stream.write_dword(self.texture_x2) | ||||
|         stream.write_dword(self.texture_x3) | ||||
|         stream.write_bool(self.texture_x4) | ||||
|         stream.write_bool(self.texture_wrap) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.texture_id = data['texture_id'] | ||||
|         self.texture_transparent = STRING_TO_TRANSPARENT[data['texture_transparent']] | ||||
|         self.texture_compress = data['texture_compress'] | ||||
|         self.texture_normal_map = data['texture_normal_map'] | ||||
|         self.texture_detail_normal_map = data['texture_detail_normal_map'] | ||||
|         self.texture_create_mip_maps = data['texture_create_mip_maps'] | ||||
|         self.texture_x0 = '' | ||||
|         self.texture_x1 = '' | ||||
|         self.texture_x2 = 255 | ||||
|         self.texture_x3 = 0 | ||||
|         self.texture_x4 = False | ||||
|         self.texture_wrap = data['texture_wrap'] | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         data['texture_id'] = self.texture_id | ||||
|         data['texture_transparent'] = TRANSPARENT_TO_STRING[self.texture_transparent] | ||||
|         data['texture_compress'] = self.texture_compress | ||||
|         data['texture_normal_map'] = self.texture_normal_map | ||||
|         data['texture_detail_normal_map'] = self.texture_detail_normal_map | ||||
|         data['texture_create_mip_maps'] = self.texture_create_mip_maps | ||||
|         data['texture_wrap'] = self.texture_wrap | ||||
|         return data | ||||
| 
 | ||||
| 
 | ||||
| class ArcColorTexture(ArcSingleTexture): | ||||
|     pass | ||||
| 
 | ||||
| 
 | ||||
| class ArcAnimatedTexture: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         self.animated_texture_id = stream.read_qword() | ||||
|         self.animated_texture_transparent = stream.read_dword() | ||||
|         self.animated_texture_compress = stream.read_bool() | ||||
|         self.animated_texture_normal_map = stream.read_bool() | ||||
|         self.animated_texture_detail_normal_map = stream.read_bool() | ||||
|         self.animated_texture_create_mip_maps = stream.read_bool() | ||||
|         self.animated_texture_frame_timer = stream.read_float() | ||||
|         self.animated_texture_x0 = stream.read_float() | ||||
|         self.animated_texture_frame_rand = stream.read_dword() | ||||
| 
 | ||||
|         num = stream.read_dword() | ||||
|         self.animated_texture_sets = [ArcTextureSet() for _ in range(num)] | ||||
|         for texture in self.animated_texture_sets: | ||||
|             texture.load_binary(stream) | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         stream.write_qword(self.animated_texture_id) | ||||
|         stream.write_dword(self.animated_texture_transparent) | ||||
|         stream.write_bool(self.animated_texture_compress) | ||||
|         stream.write_bool(self.animated_texture_normal_map) | ||||
|         stream.write_bool(self.animated_texture_detail_normal_map) | ||||
|         stream.write_bool(self.animated_texture_create_mip_maps) | ||||
|         stream.write_float(self.animated_texture_frame_timer) | ||||
|         stream.write_float(self.animated_texture_x0) | ||||
|         stream.write_dword(self.animated_texture_frame_rand) | ||||
| 
 | ||||
|         stream.write_dword(len(self.animated_texture_sets)) | ||||
|         for texture in self.animated_texture_sets: | ||||
|             texture.save_binary(stream) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.animated_texture_id = data['animated_texture_id'] | ||||
|         self.animated_texture_transparent = STRING_TO_TRANSPARENT[data['animated_texture_transparent']] | ||||
|         self.animated_texture_compress = data['animated_texture_compress'] | ||||
|         self.animated_texture_normal_map = data['animated_texture_normal_map'] | ||||
|         self.animated_texture_detail_normal_map = data['animated_texture_detail_normal_map'] | ||||
|         self.animated_texture_create_mip_maps = data['animated_texture_create_mip_maps'] | ||||
|         self.animated_texture_frame_timer = data['animated_texture_frame_timer'] | ||||
|         self.animated_texture_x0 = 0.0 | ||||
|         self.animated_texture_frame_rand = data['animated_texture_frame_rand'] | ||||
|         self.animated_texture_sets = [] | ||||
|         for texture_data in data['animated_texture_sets']: | ||||
|             texture = ArcTextureSet() | ||||
|             texture.load_json(texture_data) | ||||
|             self.animated_texture_sets.append(texture) | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         data['animated_texture_id'] = self.animated_texture_id | ||||
|         data['animated_texture_transparent'] = TRANSPARENT_TO_STRING[self.animated_texture_transparent] | ||||
|         data['animated_texture_compress'] = self.animated_texture_compress | ||||
|         data['animated_texture_normal_map'] = self.animated_texture_normal_map | ||||
|         data['animated_texture_detail_normal_map'] = self.animated_texture_detail_normal_map | ||||
|         data['animated_texture_create_mip_maps'] = self.animated_texture_create_mip_maps | ||||
|         data['animated_texture_frame_timer'] = self.animated_texture_frame_timer | ||||
|         data['animated_texture_frame_rand'] = self.animated_texture_frame_rand | ||||
|         data['animated_texture_sets'] = [] | ||||
|         for texture in self.animated_texture_sets: | ||||
|             data['animated_texture_sets'].append(texture.save_json()) | ||||
|         return data | ||||
| 
 | ||||
| 
 | ||||
| class ArcTextureSet: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         self.texture_type = stream.read_dword() | ||||
|         if self.texture_type == 0: | ||||
|             self.texture_data = ArcSingleTexture() | ||||
|         elif self.texture_type == 1: | ||||
|             self.texture_data = ArcColorTexture() | ||||
|         elif self.texture_type == 3: | ||||
|             self.texture_data = ArcAnimatedTexture() | ||||
|         self.texture_data.load_binary(stream) | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         stream.write_dword(self.texture_type) | ||||
|         self.texture_data.save_binary(stream) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.texture_type = STRING_TO_TEXTURE[data['texture_type']] | ||||
|         if self.texture_type == 0: | ||||
|             self.texture_data = ArcSingleTexture() | ||||
|         elif self.texture_type == 1: | ||||
|             self.texture_data = ArcColorTexture() | ||||
|         elif self.texture_type == 3: | ||||
|             self.texture_data = ArcAnimatedTexture() | ||||
|         self.texture_data.load_json(data['texture_data']) | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         data['texture_type'] = TEXTURE_TO_STRING[self.texture_type] | ||||
|         data['texture_data'] = self.texture_data.save_json() | ||||
|         return data | ||||
| 
 | ||||
| 
 | ||||
| class ArcLightPoint: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         self.lightpoint_x0 = stream.read_dword() | ||||
|         self.lightpoint_x1 = stream.read_bool() | ||||
|         self.lightpoint_shader = stream.read_bool() | ||||
|         self.lightpoint_update_offscreen = stream.read_bool() | ||||
|         self.lightpoint_radius = stream.read_float() | ||||
|         self.lightpoint_position = stream.read_tuple() | ||||
|         self.lightpoint_diffuse_color = [stream.read_float() for _ in range(4)] | ||||
|         self.lightpoint_x2 = stream.read_dword() | ||||
|         self.lightpoint_orientation = [stream.read_float() for _ in range(4)] | ||||
|         self.lightpoint_cubemap = stream.read_dword() | ||||
|         self.lightpoint_x3 = stream.read_bool() | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         stream.write_dword(self.lightpoint_x0) | ||||
|         stream.write_bool(self.lightpoint_x1) | ||||
|         stream.write_bool(self.lightpoint_shader) | ||||
|         stream.write_bool(self.lightpoint_update_offscreen) | ||||
|         stream.write_float(self.lightpoint_radius) | ||||
|         stream.write_tuple(self.lightpoint_position) | ||||
|         for i in range(4): | ||||
|             stream.write_float(self.lightpoint_diffuse_color[i]) | ||||
|         stream.write_dword(self.lightpoint_x2) | ||||
|         for i in range(4): | ||||
|             stream.write_float(self.lightpoint_orientation[i]) | ||||
|         stream.write_dword(self.lightpoint_cubemap) | ||||
|         stream.write_bool(self.lightpoint_x3) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.lightpoint_x0 = 1 | ||||
|         self.lightpoint_x1 = True | ||||
|         self.lightpoint_shader = data['lightpoint_shader'] | ||||
|         self.lightpoint_update_offscreen = data['lightpoint_update_offscreen'] | ||||
|         self.lightpoint_radius = data['lightpoint_radius'] | ||||
|         self.lightpoint_position = data['lightpoint_position'] | ||||
|         self.lightpoint_diffuse_color = data['lightpoint_diffuse_color'] | ||||
|         self.lightpoint_x2 = 1 | ||||
|         self.lightpoint_orientation = data['lightpoint_orientation'] | ||||
|         self.lightpoint_cubemap = data['lightpoint_cubemap'] | ||||
|         self.lightpoint_x3 = False | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         data['lightpoint_shader'] = self.lightpoint_shader | ||||
|         data['lightpoint_update_offscreen'] = self.lightpoint_update_offscreen | ||||
|         data['lightpoint_radius'] = self.lightpoint_radius | ||||
|         data['lightpoint_position'] = self.lightpoint_position | ||||
|         data['lightpoint_diffuse_color'] = self.lightpoint_diffuse_color | ||||
|         data['lightpoint_orientation'] = self.lightpoint_orientation | ||||
|         data['lightpoint_cubemap'] = self.lightpoint_cubemap | ||||
|         return data | ||||
| 
 | ||||
| 
 | ||||
| class ArcLightAffectorAttach: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         self.attach_x0 = stream.read_dword() | ||||
|         self.attach_offset = stream.read_tuple() | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         stream.write_dword(self.attach_x0) | ||||
|         stream.write_tuple(self.attach_offset) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.attach_x0 = 1 | ||||
|         self.attach_offset = data['attach_offset'] | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         data['attach_offset'] = self.attach_offset | ||||
|         return data | ||||
| 
 | ||||
| 
 | ||||
| class ArcLightAffectorFlicker: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         self.flicker_x0 = stream.read_dword() | ||||
|         self.flicker_avg_period = stream.read_float() | ||||
|         self.flicker_std_dev_radius = stream.read_float() | ||||
|         self.flicker_std_dev_period = stream.read_float() | ||||
|         self.flicker_falloff = stream.read_float() | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         stream.write_dword(self.flicker_x0) | ||||
|         stream.write_float(self.flicker_avg_period) | ||||
|         stream.write_float(self.flicker_std_dev_radius) | ||||
|         stream.write_float(self.flicker_std_dev_period) | ||||
|         stream.write_float(self.flicker_falloff) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.flicker_x0 = 1 | ||||
|         self.flicker_avg_period = data['flicker_avg_period'] | ||||
|         self.flicker_std_dev_radius = data['flicker_std_dev_radius'] | ||||
|         self.flicker_std_dev_period = data['flicker_std_dev_period'] | ||||
|         self.flicker_falloff = data['flicker_falloff'] | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         data['flicker_avg_period'] = self.flicker_avg_period | ||||
|         data['flicker_std_dev_radius'] = self.flicker_std_dev_radius | ||||
|         data['flicker_std_dev_period'] = self.flicker_std_dev_period | ||||
|         data['flicker_falloff'] = self.flicker_falloff | ||||
|         return data | ||||
| 
 | ||||
| 
 | ||||
| class ArcLightAffectors: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         self.light_affector_type = stream.read_dword() | ||||
| 
 | ||||
|         if self.light_affector_type == 0x54e8ff1d: | ||||
|             self.light_affector_data = ArcLightAffectorAttach() | ||||
|         elif self.light_affector_type == 0xa73bd9d4: | ||||
|             self.light_affector_data = ArcLightAffectorFlicker() | ||||
|         self.light_affector_data.load_binary(stream) | ||||
| 
 | ||||
|         self.light_affector_0xdaed = stream.read_dword() | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         stream.write_dword(self.light_affector_type) | ||||
|         self.light_affector_data.save_binary(stream) | ||||
|         stream.write_dword(self.light_affector_0xdaed) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.light_affector_type = STRING_TO_LIGHT_TYPE[data['light_affector_type']] | ||||
|         if self.light_affector_type == 0x54e8ff1d: | ||||
|             self.light_affector_data = ArcLightAffectorAttach() | ||||
|         elif self.light_affector_type == 0xa73bd9d4: | ||||
|             self.light_affector_data = ArcLightAffectorFlicker() | ||||
|         self.light_affector_data.load_json(data['light_affector_data']) | ||||
|         self.light_affector_0xdaed = 0xddaaeedd | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         data['light_affector_type'] = LIGHT_TYPE_TO_STRING[self.light_affector_type] | ||||
|         data['light_affector_data'] = self.light_affector_data.save_json() | ||||
|         return data | ||||
| 
 | ||||
| 
 | ||||
| class ArcLight: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         self.light_x0 = stream.read_dword() | ||||
|         self.light_x1 = stream.read_bool() | ||||
|         self.light_type = stream.read_dword() | ||||
| 
 | ||||
|         if self.light_type == 0xb6787258: | ||||
|             self.light_data = ArcLightPoint() | ||||
|         self.light_data.load_binary(stream) | ||||
| 
 | ||||
|         self.light_0xdaed = stream.read_dword() | ||||
| 
 | ||||
|         num = stream.read_dword() | ||||
|         self.light_affectors = [ArcLightAffectors() for _ in range(num)] | ||||
|         for extra in self.light_affectors: | ||||
|             extra.load_binary(stream) | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         stream.write_dword(self.light_x0) | ||||
|         stream.write_bool(self.light_x1) | ||||
|         stream.write_dword(self.light_type) | ||||
|         self.light_data.save_binary(stream) | ||||
|         stream.write_dword(self.light_0xdaed) | ||||
| 
 | ||||
|         stream.write_dword(len(self.light_affectors)) | ||||
|         for extra in self.light_affectors: | ||||
|             extra.save_binary(stream) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.light_x0 = 1 | ||||
|         self.light_x1 = True | ||||
|         self.light_type = STRING_TO_LIGHT_TYPE[data['light_type']] | ||||
|         if self.light_type == 0xb6787258: | ||||
|             self.light_data = ArcLightPoint() | ||||
|         self.light_data.load_json(data['light_data']) | ||||
|         self.light_0xdaed = 0xddaaeedd | ||||
| 
 | ||||
|         self.light_affectors = [] | ||||
|         for extra_data in data['light_affectors']: | ||||
|             extra = ArcLightAffectors() | ||||
|             extra.load_json(extra_data) | ||||
|             self.light_affectors.append(extra) | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         data['light_type'] = LIGHT_TYPE_TO_STRING[self.light_type] | ||||
|         data['light_data'] = self.light_data.save_json() | ||||
| 
 | ||||
|         data['light_affectors'] = [] | ||||
|         for extra in self.light_affectors: | ||||
|             data['light_affectors'].append(extra.save_json()) | ||||
|         return data | ||||
| 
 | ||||
| 
 | ||||
| class ArcRender: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         self.render_template = ArcRenderTemplate() | ||||
|         self.render_template.load_binary(stream) | ||||
|         self.render_target_bone = stream.read_string() | ||||
|         self.render_scale = stream.read_tuple() | ||||
|         self.render_has_loc = stream.read_dword() | ||||
|         if self.render_has_loc: | ||||
|             self.render_loc = stream.read_tuple() | ||||
|             num_children = stream.read_dword() | ||||
|             self.render_children = [stream.read_qword() for _ in range(num_children)] | ||||
|         self.render_has_texture_set = stream.read_bool() | ||||
|         if self.render_has_texture_set: | ||||
|             num = stream.read_dword() | ||||
|             self.render_texture_set = [ArcTextureSet() for _ in range(num)] | ||||
|             for texture in self.render_texture_set: | ||||
|                 texture.load_binary(stream) | ||||
|         self.render_collides = stream.read_bool() | ||||
|         self.render_calculate_bounding_box = stream.read_bool() | ||||
|         self.render_nation_crest = stream.read_bool() | ||||
|         self.render_guild_crest = stream.read_bool() | ||||
|         self.render_bumped = stream.read_bool() | ||||
|         self.render_vp_active = stream.read_bool() | ||||
|         if self.render_vp_active: | ||||
|             self.render_vp_name = stream.read_string() | ||||
|             num_params = stream.read_dword() | ||||
|             self.render_vp_params = [ | ||||
|                 [ | ||||
|                     stream.read_dword(), | ||||
|                     stream.read_float(), | ||||
|                     stream.read_float(), | ||||
|                     stream.read_float(), | ||||
|                     stream.read_float(), | ||||
|                 ] for _ in range(num_params) | ||||
|             ] | ||||
|         self.render_has_light_effects = stream.read_bool() | ||||
|         if self.render_has_light_effects: | ||||
|             num_effects = stream.read_dword() | ||||
|             self.render_light_effects = [ArcLight() for _ in range(num_effects)] | ||||
|             for effect in self.render_light_effects: | ||||
|                 effect.load_binary(stream) | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         self.render_template.save_binary(stream) | ||||
|         stream.write_string(self.render_target_bone) | ||||
|         stream.write_tuple(self.render_scale) | ||||
|         stream.write_dword(self.render_has_loc) | ||||
|         if self.render_has_loc: | ||||
|             stream.write_tuple(self.render_loc) | ||||
|             stream.write_dword(len(self.render_children)) | ||||
|             for child in self.render_children: | ||||
|                 stream.write_qword(child) | ||||
|         stream.write_bool(self.render_has_texture_set) | ||||
|         if self.render_has_texture_set: | ||||
|             stream.write_dword(len(self.render_texture_set)) | ||||
|             for texture in self.render_texture_set: | ||||
|                 texture.save_binary(stream) | ||||
|         stream.write_bool(self.render_collides) | ||||
|         stream.write_bool(self.render_calculate_bounding_box) | ||||
|         stream.write_bool(self.render_nation_crest) | ||||
|         stream.write_bool(self.render_guild_crest) | ||||
|         stream.write_bool(self.render_bumped) | ||||
|         stream.write_bool(self.render_vp_active) | ||||
|         if self.render_vp_active: | ||||
|             stream.write_string(self.render_vp_name) | ||||
| 
 | ||||
|             stream.write_dword(len(self.render_vp_params)) | ||||
|             for param in self.render_vp_params: | ||||
|                 stream.write_dword(param[0]) | ||||
|                 stream.write_float(param[1]) | ||||
|                 stream.write_float(param[2]) | ||||
|                 stream.write_float(param[3]) | ||||
|                 stream.write_float(param[4]) | ||||
|         stream.write_bool(self.render_has_light_effects) | ||||
|         if self.render_has_light_effects: | ||||
|             stream.write_dword(len(self.render_light_effects)) | ||||
|             for effect in self.render_light_effects: | ||||
|                 effect.save_binary(stream) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.render_template = ArcRenderTemplate() | ||||
|         self.render_template.load_json(data['render_template']) | ||||
|         self.render_target_bone = data['render_target_bone'] | ||||
|         self.render_scale = data['render_scale'] | ||||
|         self.render_has_loc = data['render_has_loc'] | ||||
|         if self.render_has_loc: | ||||
|             self.render_loc = data['render_loc'] | ||||
|             self.render_children = data['render_children'] | ||||
|         self.render_has_texture_set = data['render_has_texture_set'] | ||||
|         if self.render_has_texture_set: | ||||
|             self.render_texture_set = [] | ||||
|             for texture_data in data['render_texture_set']: | ||||
|                 texture = ArcTextureSet() | ||||
|                 texture.load_json(texture_data) | ||||
|                 self.render_texture_set.append(texture) | ||||
|         self.render_collides = data['render_collides'] | ||||
|         self.render_calculate_bounding_box = data['render_calculate_bounding_box'] | ||||
|         self.render_nation_crest = data['render_nation_crest'] | ||||
|         self.render_guild_crest = data['render_guild_crest'] | ||||
|         self.render_bumped = data['render_bumped'] | ||||
|         self.render_vp_active = data['render_vp_active'] | ||||
|         if self.render_vp_active: | ||||
|             self.render_vp_name = data['render_vp_name'] | ||||
|             self.render_vp_params = data['render_vp_params'] | ||||
|         self.render_has_light_effects = data['render_has_light_effects'] | ||||
|         if self.render_has_light_effects: | ||||
|             self.render_light_effects = [] | ||||
|             for effect_data in data['render_light_effects']: | ||||
|                 effect = ArcLight() | ||||
|                 effect.load_json(effect_data) | ||||
|                 self.render_light_effects.append(effect) | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         data['render_template'] = self.render_template.save_json() | ||||
|         data['render_target_bone'] = self.render_target_bone | ||||
|         data['render_scale'] = self.render_scale | ||||
|         data['render_has_loc'] = self.render_has_loc | ||||
|         if self.render_has_loc: | ||||
|             data['render_loc'] = self.render_loc | ||||
|             data['render_children'] = self.render_children | ||||
|         data['render_has_texture_set'] = self.render_has_texture_set | ||||
|         if self.render_has_texture_set: | ||||
|             data['render_texture_set'] = [] | ||||
|             for texture in self.render_texture_set: | ||||
|                 data['render_texture_set'].append(texture.save_json()) | ||||
|         data['render_collides'] = self.render_collides | ||||
|         data['render_calculate_bounding_box'] = self.render_calculate_bounding_box | ||||
|         data['render_nation_crest'] = self.render_nation_crest | ||||
|         data['render_guild_crest'] = self.render_guild_crest | ||||
|         data['render_bumped'] = self.render_bumped | ||||
|         data['render_vp_active'] = self.render_vp_active | ||||
|         if self.render_vp_active: | ||||
|             data['render_vp_name'] = self.render_vp_name | ||||
|             data['render_vp_params'] = self.render_vp_params | ||||
|         data['render_has_light_effects'] = self.render_has_light_effects | ||||
|         if self.render_has_light_effects: | ||||
|             data['render_light_effects'] = [] | ||||
|             for effect in self.render_light_effects: | ||||
|                 data['render_light_effects'].append(effect.save_json()) | ||||
|         return data | ||||
| @ -0,0 +1,125 @@@@ -0,0 +1,125 @@ | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from collections import OrderedDict | ||||
| 
 | ||||
| from arcane.util import ResStream | ||||
| 
 | ||||
| 
 | ||||
| class ArcBone: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         self.bone_id = stream.read_dword() | ||||
|         self.bone_name = stream.read_string() | ||||
|         self.bone_direction = stream.read_tuple() | ||||
|         self.bone_length = stream.read_float() | ||||
|         self.bone_axis = stream.read_tuple() | ||||
|         self.bone_dof = stream.read_string() | ||||
|         self.bone_order = stream.read_tuple() | ||||
|         self.bone_position = stream.read_tuple() | ||||
|         self.bone_orientation = stream.read_tuple() | ||||
|         self.bone_u0 = stream.read_bool() | ||||
|         self.bone_u1 = stream.read_bool() | ||||
| 
 | ||||
|         num = stream.read_dword() | ||||
|         self.bone_hierarchy = [ArcBone() for _ in range(num)] | ||||
|         for bone in self.bone_hierarchy: | ||||
|             bone.load_binary(stream) | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         stream.write_dword(self.bone_id) | ||||
|         stream.write_string(self.bone_name) | ||||
|         stream.write_tuple(self.bone_direction) | ||||
|         stream.write_float(self.bone_length) | ||||
|         stream.write_tuple(self.bone_axis) | ||||
|         stream.write_string(self.bone_dof) | ||||
|         stream.write_tuple(self.bone_order) | ||||
|         stream.write_tuple(self.bone_position) | ||||
|         stream.write_tuple(self.bone_orientation) | ||||
|         stream.write_bool(self.bone_u0) | ||||
|         stream.write_bool(self.bone_u1) | ||||
| 
 | ||||
|         stream.write_dword(len(self.bone_hierarchy)) | ||||
|         for bone in self.bone_hierarchy: | ||||
|             bone.save_binary(stream) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.bone_id = data['bone_id'] | ||||
|         self.bone_name = data['bone_name'] | ||||
|         self.bone_direction = data['bone_direction'] | ||||
|         self.bone_length = data['bone_length'] | ||||
|         self.bone_axis = data['bone_axis'] | ||||
|         self.bone_dof = data['bone_dof'] | ||||
|         self.bone_order = data['bone_order'] | ||||
|         self.bone_position = data['bone_position'] | ||||
|         self.bone_orientation = data['bone_orientation'] | ||||
|         self.bone_u0 = data['bone_u0'] | ||||
|         self.bone_u1 = data['bone_u1'] | ||||
| 
 | ||||
|         self.bone_hierarchy = [] | ||||
|         for bone_data in data['bone_hierarchy']: | ||||
|             bone = ArcBone() | ||||
|             bone.load_json(bone_data) | ||||
|             self.bone_hierarchy.append(bone) | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         data['bone_id'] = self.bone_id | ||||
|         data['bone_name'] = self.bone_name | ||||
|         data['bone_direction'] = self.bone_direction | ||||
|         data['bone_length'] = self.bone_length | ||||
|         data['bone_axis'] = self.bone_axis | ||||
|         data['bone_dof'] = self.bone_dof | ||||
|         data['bone_order'] = self.bone_order | ||||
|         data['bone_position'] = self.bone_position | ||||
|         data['bone_orientation'] = self.bone_orientation | ||||
|         data['bone_u0'] = self.bone_u0 | ||||
|         data['bone_u1'] = self.bone_u1 | ||||
| 
 | ||||
|         data['bone_hierarchy'] = [] | ||||
|         for bone in self.bone_hierarchy: | ||||
|             data['bone_hierarchy'].append(bone.save_json()) | ||||
|         return data | ||||
| 
 | ||||
| 
 | ||||
| class ArcSkeleton: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         self.skeleton_name = stream.read_string() | ||||
| 
 | ||||
|         num = stream.read_dword() | ||||
|         self.skeleton_motion = [ | ||||
|             [ | ||||
|                 stream.read_qword(), | ||||
|                 stream.read_qword(), | ||||
|             ] for _ in range(num) | ||||
|         ] | ||||
| 
 | ||||
|         self.skeleton_root = ArcBone() | ||||
|         self.skeleton_root.load_binary(stream) | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         stream.write_string(self.skeleton_name) | ||||
| 
 | ||||
|         stream.write_dword(len(self.skeleton_motion)) | ||||
|         for i in range(len(self.skeleton_motion)): | ||||
|             stream.write_qword(self.skeleton_motion[i][0]) | ||||
|             stream.write_qword(self.skeleton_motion[i][1]) | ||||
| 
 | ||||
|         self.skeleton_root.save_binary(stream) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.skeleton_name = data['skeleton_name'] | ||||
|         self.skeleton_motion = data['skeleton_motion'] | ||||
|         self.skeleton_root = ArcBone() | ||||
|         self.skeleton_root.load_json(data['skeleton_root']) | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         data['skeleton_name'] = self.skeleton_name | ||||
|         data['skeleton_motion'] = self.skeleton_motion | ||||
|         data['skeleton_root'] = self.skeleton_root.save_json() | ||||
|         return data | ||||
| @ -0,0 +1,40 @@@@ -0,0 +1,40 @@ | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from wave import Wave_read, Wave_write | ||||
| 
 | ||||
| from arcane.util import ResStream | ||||
| 
 | ||||
| 
 | ||||
| class ArcSound: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         data_size = stream.read_dword() | ||||
|         self.sound_frame_rate = stream.read_dword() | ||||
|         self.sound_n_channels = stream.read_dword() | ||||
|         self.sound_sample_width = stream.read_dword() | ||||
|         self.sound_data = stream.read_bytes(data_size) | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         data_size = len(self.sound_data) | ||||
|         stream.write_dword(data_size) | ||||
|         stream.write_dword(self.sound_frame_rate) | ||||
|         stream.write_dword(self.sound_n_channels) | ||||
|         stream.write_dword(self.sound_sample_width) | ||||
|         stream.write_bytes(self.sound_data) | ||||
| 
 | ||||
|     def load_wav(self, stream: Wave_read): | ||||
|         self.sound_frame_rate = stream.getframerate() | ||||
|         self.sound_n_channels = stream.getnchannels() | ||||
|         self.sound_sample_width = stream.getsampwidth() * 8 | ||||
|         self.sound_data = stream.readframes(stream.getnframes()) | ||||
| 
 | ||||
|     def save_wav(self, stream: Wave_write): | ||||
|         stream.setframerate(self.sound_frame_rate) | ||||
|         stream.setnchannels(self.sound_n_channels) | ||||
|         stream.setsampwidth(self.sound_sample_width // 8) | ||||
|         stream.writeframes(self.sound_data) | ||||
| @ -0,0 +1,242 @@@@ -0,0 +1,242 @@ | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from collections import OrderedDict | ||||
| 
 | ||||
| from arcane.util import ResStream | ||||
| 
 | ||||
| TILE_TO_STRING = { | ||||
|     0: "UNKNOWN", | ||||
|     1: "Regular", | ||||
|     2: "Slope", | ||||
|     3: "Road", | ||||
| } | ||||
| STRING_TO_TILE = {value: key for key, value in TILE_TO_STRING.items()} | ||||
| 
 | ||||
| MASK_TO_STRING = { | ||||
|     0: "UNKNOWN", | ||||
|     1: "Transition", | ||||
|     2: "Road", | ||||
| } | ||||
| STRING_TO_MASK = {value: key for key, value in MASK_TO_STRING.items()} | ||||
| 
 | ||||
| 
 | ||||
| class ArcTile: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         self.tile_row_0 = stream.read_dword() | ||||
|         self.tile_row_1 = stream.read_dword() | ||||
|         self.tile_row_2 = stream.read_dword() | ||||
|         self.tile_row_3 = stream.read_dword() | ||||
|         self.tile_prob = stream.read_float() | ||||
|         self.tile_type = stream.read_dword() | ||||
| 
 | ||||
|         num_alts = stream.read_dword() | ||||
|         self.tile_alts = [stream.read_dword() for _ in range(num_alts)] | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         stream.write_dword(self.tile_row_0) | ||||
|         stream.write_dword(self.tile_row_1) | ||||
|         stream.write_dword(self.tile_row_2) | ||||
|         stream.write_dword(self.tile_row_3) | ||||
|         stream.write_float(self.tile_prob) | ||||
|         stream.write_dword(self.tile_type) | ||||
|         stream.write_dword(len(self.tile_alts)) | ||||
|         for i in range(len(self.tile_alts)): | ||||
|             stream.write_dword(self.tile_alts[i]) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.tile_row_0 = data['tile_row_0'] | ||||
|         self.tile_row_1 = data['tile_row_1'] | ||||
|         self.tile_row_2 = data['tile_row_2'] | ||||
|         self.tile_row_3 = data['tile_row_3'] | ||||
|         self.tile_prob = data['tile_prob'] | ||||
|         self.tile_type = STRING_TO_TILE[data['tile_type']] | ||||
|         self.tile_alts = data['tile_alts'] | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         data['tile_row_0'] = self.tile_row_0 | ||||
|         data['tile_row_1'] = self.tile_row_1 | ||||
|         data['tile_row_2'] = self.tile_row_2 | ||||
|         data['tile_row_3'] = self.tile_row_3 | ||||
|         data['tile_prob'] = self.tile_prob | ||||
|         data['tile_type'] = TILE_TO_STRING[self.tile_type] | ||||
|         data['tile_alts'] = self.tile_alts | ||||
|         return data | ||||
| 
 | ||||
| 
 | ||||
| class ArcTileMask: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         self.mask_row_0 = stream.read_dword() | ||||
|         self.mask_row_1 = stream.read_dword() | ||||
|         self.mask_row_2 = stream.read_dword() | ||||
|         self.mask_row_3 = stream.read_dword() | ||||
|         self.mask_prob = stream.read_float() | ||||
|         self.mask_start = stream.read_dword() | ||||
|         self.mask_end = stream.read_dword() | ||||
|         self.mask_end1 = stream.read_dword() | ||||
|         self.mask_end2 = stream.read_dword() | ||||
|         self.mask_type = stream.read_dword() | ||||
|         self.mask_width = stream.read_dword() | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         stream.write_dword(self.mask_row_0) | ||||
|         stream.write_dword(self.mask_row_1) | ||||
|         stream.write_dword(self.mask_row_2) | ||||
|         stream.write_dword(self.mask_row_3) | ||||
|         stream.write_float(self.mask_prob) | ||||
|         stream.write_dword(self.mask_start) | ||||
|         stream.write_dword(self.mask_end) | ||||
|         stream.write_dword(self.mask_end1) | ||||
|         stream.write_dword(self.mask_end2) | ||||
|         stream.write_dword(self.mask_type) | ||||
|         stream.write_dword(self.mask_width) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.mask_row_0 = data['mask_row_0'] | ||||
|         self.mask_row_1 = data['mask_row_1'] | ||||
|         self.mask_row_2 = data['mask_row_2'] | ||||
|         self.mask_row_3 = data['mask_row_3'] | ||||
|         self.mask_prob = data['mask_prob'] | ||||
|         self.mask_start = data['mask_start'] | ||||
|         self.mask_end = data['mask_end'] | ||||
|         self.mask_end1 = data['mask_end1'] | ||||
|         self.mask_end2 = data['mask_end2'] | ||||
|         self.mask_type = STRING_TO_MASK[data['mask_type']] | ||||
|         self.mask_width = data['mask_width'] | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         data['mask_row_0'] = self.mask_row_0 | ||||
|         data['mask_row_1'] = self.mask_row_1 | ||||
|         data['mask_row_2'] = self.mask_row_2 | ||||
|         data['mask_row_3'] = self.mask_row_3 | ||||
|         data['mask_prob'] = self.mask_prob | ||||
|         data['mask_start'] = self.mask_start | ||||
|         data['mask_end'] = self.mask_end | ||||
|         data['mask_end1'] = self.mask_end1 | ||||
|         data['mask_end2'] = self.mask_end2 | ||||
|         data['mask_type'] = MASK_TO_STRING[self.mask_type] | ||||
|         data['mask_width'] = self.mask_width | ||||
|         return data | ||||
| 
 | ||||
| 
 | ||||
| class ArcTilePattern: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         self.pattern_row_0 = stream.read_dword() | ||||
|         self.pattern_row_1 = stream.read_dword() | ||||
|         self.pattern_row_2 = stream.read_dword() | ||||
|         self.pattern_row_3 = stream.read_dword() | ||||
|         self.pattern_prob = stream.read_float() | ||||
|         self.pattern_patx = stream.read_dword() | ||||
|         self.pattern_patz = stream.read_dword() | ||||
|         num_tiles = stream.read_dword() | ||||
|         self.pattern_tiles = [stream.read_dword() for _ in range(num_tiles)] | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         stream.write_dword(self.pattern_row_0) | ||||
|         stream.write_dword(self.pattern_row_1) | ||||
|         stream.write_dword(self.pattern_row_2) | ||||
|         stream.write_dword(self.pattern_row_3) | ||||
|         stream.write_float(self.pattern_prob) | ||||
|         stream.write_dword(self.pattern_patx) | ||||
|         stream.write_dword(self.pattern_patz) | ||||
|         stream.write_dword(len(self.pattern_tiles)) | ||||
|         for i in range(len(self.pattern_tiles)): | ||||
|             stream.write_dword(self.pattern_tiles[i]) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.pattern_row_0 = data['pattern_row_0'] | ||||
|         self.pattern_row_1 = data['pattern_row_1'] | ||||
|         self.pattern_row_2 = data['pattern_row_2'] | ||||
|         self.pattern_row_3 = data['pattern_row_3'] | ||||
|         self.pattern_prob = data['pattern_prob'] | ||||
|         self.pattern_patx = data['pattern_patx'] | ||||
|         self.pattern_patz = data['pattern_patz'] | ||||
|         self.pattern_tiles = data['pattern_tiles'] | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         data['pattern_row_0'] = self.pattern_row_0 | ||||
|         data['pattern_row_1'] = self.pattern_row_1 | ||||
|         data['pattern_row_2'] = self.pattern_row_2 | ||||
|         data['pattern_row_3'] = self.pattern_row_3 | ||||
|         data['pattern_prob'] = self.pattern_prob | ||||
|         data['pattern_patx'] = self.pattern_patx | ||||
|         data['pattern_patz'] = self.pattern_patz | ||||
|         data['pattern_tiles'] = self.pattern_tiles | ||||
|         return data | ||||
| 
 | ||||
| 
 | ||||
| class ArcTileManager: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         self.manager_texture_width = stream.read_dword() | ||||
|         self.manager_tile_width = stream.read_dword() | ||||
|         self.manager_tile_texture = stream.read_qword() | ||||
|         num_tiles = stream.read_dword() | ||||
|         self.manager_tiles = [ArcTile() for _ in range(num_tiles)] | ||||
|         for tile in self.manager_tiles: | ||||
|             tile.load_binary(stream) | ||||
|         num_masks = stream.read_dword() | ||||
|         self.manager_masks = [ArcTileMask() for _ in range(num_masks)] | ||||
|         for mask in self.manager_masks: | ||||
|             mask.load_binary(stream) | ||||
|         num_patterns = stream.read_dword() | ||||
|         self.manager_patterns = [ArcTilePattern() for _ in range(num_patterns)] | ||||
|         for pattern in self.manager_patterns: | ||||
|             pattern.load_binary(stream) | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         stream.write_dword(self.manager_texture_width) | ||||
|         stream.write_dword(self.manager_tile_width) | ||||
|         stream.write_qword(self.manager_tile_texture) | ||||
|         stream.write_dword(len(self.manager_tiles)) | ||||
|         for tile in self.manager_tiles: | ||||
|             tile.save_binary(stream) | ||||
|         stream.write_dword(len(self.manager_masks)) | ||||
|         for mask in self.manager_masks: | ||||
|             mask.save_binary(stream) | ||||
|         stream.write_dword(len(self.manager_patterns)) | ||||
|         for pattern in self.manager_patterns: | ||||
|             pattern.save_binary(stream) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.manager_texture_width = data['manager_texture_width'] | ||||
|         self.manager_tile_width = data['manager_tile_width'] | ||||
|         self.manager_tile_texture = data['manager_tile_texture'] | ||||
|         self.manager_tiles = [] | ||||
|         for tile_data in data['manager_tiles']: | ||||
|             tile = ArcTile() | ||||
|             tile.load_json(tile_data) | ||||
|             self.manager_tiles.append(tile) | ||||
|         self.manager_masks = [] | ||||
|         for mask_data in data['manager_masks']: | ||||
|             mask = ArcTileMask() | ||||
|             mask.load_json(mask_data) | ||||
|             self.manager_masks.append(mask) | ||||
|         self.manager_patterns = [] | ||||
|         for pattern_data in data['manager_patterns']: | ||||
|             pattern = ArcTilePattern() | ||||
|             pattern.load_json(pattern_data) | ||||
|             self.manager_patterns.append(pattern) | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         data['manager_texture_width'] = self.manager_texture_width | ||||
|         data['manager_tile_width'] = self.manager_tile_width | ||||
|         data['manager_tile_texture'] = self.manager_tile_texture | ||||
|         data['manager_tiles'] = [] | ||||
|         for tile in self.manager_tiles: | ||||
|             data['manager_tiles'].append(tile.save_json()) | ||||
|         data['manager_masks'] = [] | ||||
|         for mask in self.manager_masks: | ||||
|             data['manager_masks'].append(mask.save_json()) | ||||
|         data['manager_patterns'] = [] | ||||
|         for pattern in self.manager_patterns: | ||||
|             data['manager_patterns'].append(pattern.save_json()) | ||||
|         return data | ||||
| @ -0,0 +1,396 @@@@ -0,0 +1,396 @@ | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄ | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪ | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| # | ||||
| 
 | ||||
| 
 | ||||
| from base64 import b64decode, b64encode | ||||
| from collections import OrderedDict | ||||
| 
 | ||||
| from arcane.util import ResStream | ||||
| 
 | ||||
| EFFETCT_TO_STRING = { | ||||
|     0: 'PARTICLE', | ||||
|     1: 'LIGHTNING', | ||||
|     2: 'GEOMETRY', | ||||
| } | ||||
| 
 | ||||
| STRING_TO_EFFECT = {value: key for key, value in EFFETCT_TO_STRING.items()} | ||||
| 
 | ||||
| 
 | ||||
| class ArcParticle: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         self.particle_attached_bone = stream.read_dword() | ||||
|         self.particle_count = stream.read_dword() | ||||
|         self.particle_size = stream.read_float() | ||||
|         self.particle_life = stream.read_float() | ||||
|         self.particle_life_rand = stream.read_float() | ||||
|         self.particle_shape_and_pos = stream.read_dword() | ||||
|         self.particle_emitter_scale = stream.read_float() | ||||
|         self.particle_pos_offset = stream.read_tuple() | ||||
|         self.particle_ppos_reference = stream.read_tuple() | ||||
|         self.particle_initial_velocities = stream.read_dword() | ||||
|         self.particle_velocity_scale = stream.read_float() | ||||
|         self.particle_vel_reference = stream.read_tuple() | ||||
|         self.particle_dir_random = stream.read_float() | ||||
|         self.particle_spd_random = stream.read_float() | ||||
|         self.particle_initial_rot = stream.read_float() | ||||
|         self.particle_initial_rot_random = stream.read_float() | ||||
|         self.particle_incremental_rot = stream.read_float() | ||||
|         self.particle_incremental_rot_random = stream.read_float() | ||||
|         self.particle_color_keys = [ | ||||
|             [ | ||||
|                 stream.read_float(), | ||||
|                 stream.read_float(), | ||||
|                 stream.read_float(), | ||||
|                 stream.read_float(), | ||||
|             ] for _ in range(5) | ||||
|         ] | ||||
|         self.particle_color_keytimes = [stream.read_float() for _ in range(5)] | ||||
|         self.particle_size_keys = [stream.read_float() for _ in range(5)] | ||||
|         self.particle_targettype = stream.read_dword() | ||||
|         self.particle_lifetime = stream.read_float() | ||||
|         self.particle_texture = stream.read_dword() | ||||
|         self.particle_blend_type = stream.read_dword() | ||||
|         self.particle_attractor_bone = stream.read_dword() | ||||
|         self.particle_directional_grav = stream.read_tuple() | ||||
|         self.particle_field_function = stream.read_dword() | ||||
|         self.particle_gravity_strength = stream.read_float() | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         stream.write_dword(self.particle_attached_bone) | ||||
|         stream.write_dword(self.particle_count) | ||||
|         stream.write_float(self.particle_size) | ||||
|         stream.write_float(self.particle_life) | ||||
|         stream.write_float(self.particle_life_rand) | ||||
|         stream.write_dword(self.particle_shape_and_pos) | ||||
|         stream.write_float(self.particle_emitter_scale) | ||||
|         stream.write_tuple(self.particle_pos_offset) | ||||
|         stream.write_tuple(self.particle_ppos_reference) | ||||
|         stream.write_dword(self.particle_initial_velocities) | ||||
|         stream.write_float(self.particle_velocity_scale) | ||||
|         stream.write_tuple(self.particle_vel_reference) | ||||
|         stream.write_float(self.particle_dir_random) | ||||
|         stream.write_float(self.particle_spd_random) | ||||
|         stream.write_float(self.particle_initial_rot) | ||||
|         stream.write_float(self.particle_initial_rot_random) | ||||
|         stream.write_float(self.particle_incremental_rot) | ||||
|         stream.write_float(self.particle_incremental_rot_random) | ||||
|         for i in range(5): | ||||
|             stream.write_float(self.particle_color_keys[i][0]) | ||||
|             stream.write_float(self.particle_color_keys[i][1]) | ||||
|             stream.write_float(self.particle_color_keys[i][2]) | ||||
|             stream.write_float(self.particle_color_keys[i][3]) | ||||
|         for i in range(5): | ||||
|             stream.write_float(self.particle_color_keytimes[i]) | ||||
|         for i in range(5): | ||||
|             stream.write_float(self.particle_size_keys[i]) | ||||
|         stream.write_dword(self.particle_targettype) | ||||
|         stream.write_float(self.particle_lifetime) | ||||
|         stream.write_dword(self.particle_texture) | ||||
|         stream.write_dword(self.particle_blend_type) | ||||
|         stream.write_dword(self.particle_attractor_bone) | ||||
|         stream.write_tuple(self.particle_directional_grav) | ||||
|         stream.write_dword(self.particle_field_function) | ||||
|         stream.write_float(self.particle_gravity_strength) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.particle_attached_bone = data['particle_attached_bone'] | ||||
|         self.particle_count = data['particle_count'] | ||||
|         self.particle_size = data['particle_size'] | ||||
|         self.particle_life = data['particle_life'] | ||||
|         self.particle_life_rand = data['particle_life_rand'] | ||||
|         self.particle_shape_and_pos = data['particle_shape_and_pos'] | ||||
|         self.particle_emitter_scale = data['particle_emitter_scale'] | ||||
|         self.particle_pos_offset = data['particle_pos_offset'] | ||||
|         self.particle_ppos_reference = data['particle_ppos_reference'] | ||||
|         self.particle_initial_velocities = data['particle_initial_velocities'] | ||||
|         self.particle_velocity_scale = data['particle_velocity_scale'] | ||||
|         self.particle_vel_reference = data['particle_vel_reference'] | ||||
|         self.particle_dir_random = data['particle_dir_random'] | ||||
|         self.particle_spd_random = data['particle_spd_random'] | ||||
|         self.particle_initial_rot = data['particle_initial_rot'] | ||||
|         self.particle_initial_rot_random = data['particle_initial_rot_random'] | ||||
|         self.particle_incremental_rot = data['particle_incremental_rot'] | ||||
|         self.particle_incremental_rot_random = data['particle_incremental_rot_random'] | ||||
|         self.particle_color_keys = data['particle_color_keys'] | ||||
|         self.particle_color_keytimes = data['particle_color_keytimes'] | ||||
|         self.particle_size_keys = data['particle_size_keys'] | ||||
|         self.particle_targettype = data['particle_targettype'] | ||||
|         self.particle_lifetime = data['particle_lifetime'] | ||||
|         self.particle_texture = data['particle_texture'] | ||||
|         self.particle_blend_type = data['particle_blend_type'] | ||||
|         self.particle_attractor_bone = data['particle_attractor_bone'] | ||||
|         self.particle_directional_grav = data['particle_directional_grav'] | ||||
|         self.particle_field_function = data['particle_field_function'] | ||||
|         self.particle_gravity_strength = data['particle_gravity_strength'] | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         data['particle_attached_bone'] = self.particle_attached_bone | ||||
|         data['particle_count'] = self.particle_count | ||||
|         data['particle_size'] = self.particle_size | ||||
|         data['particle_life'] = self.particle_life | ||||
|         data['particle_life_rand'] = self.particle_life_rand | ||||
|         data['particle_shape_and_pos'] = self.particle_shape_and_pos | ||||
|         data['particle_emitter_scale'] = self.particle_emitter_scale | ||||
|         data['particle_pos_offset'] = self.particle_pos_offset | ||||
|         data['particle_ppos_reference'] = self.particle_ppos_reference | ||||
|         data['particle_initial_velocities'] = self.particle_initial_velocities | ||||
|         data['particle_velocity_scale'] = self.particle_velocity_scale | ||||
|         data['particle_vel_reference'] = self.particle_vel_reference | ||||
|         data['particle_dir_random'] = self.particle_dir_random | ||||
|         data['particle_spd_random'] = self.particle_spd_random | ||||
|         data['particle_initial_rot'] = self.particle_initial_rot | ||||
|         data['particle_initial_rot_random'] = self.particle_initial_rot_random | ||||
|         data['particle_incremental_rot'] = self.particle_incremental_rot | ||||
|         data['particle_incremental_rot_random'] = self.particle_incremental_rot_random | ||||
|         data['particle_color_keys'] = self.particle_color_keys | ||||
|         data['particle_color_keytimes'] = self.particle_color_keytimes | ||||
|         data['particle_size_keys'] = self.particle_size_keys | ||||
|         data['particle_targettype'] = self.particle_targettype | ||||
|         data['particle_lifetime'] = self.particle_lifetime | ||||
|         data['particle_texture'] = self.particle_texture | ||||
|         data['particle_blend_type'] = self.particle_blend_type | ||||
|         data['particle_attractor_bone'] = self.particle_attractor_bone | ||||
|         data['particle_directional_grav'] = self.particle_directional_grav | ||||
|         data['particle_field_function'] = self.particle_field_function | ||||
|         data['particle_gravity_strength'] = self.particle_gravity_strength | ||||
|         return data | ||||
| 
 | ||||
| 
 | ||||
| class ArcLightning: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         self.lightning_texture = stream.read_dword() | ||||
|         self.lightning_src_bone = stream.read_dword() | ||||
|         self.lightning_dst_bone = stream.read_dword() | ||||
|         self.lightning_width = stream.read_float() | ||||
|         self.lightning_random_factor = stream.read_float() | ||||
|         self.lightning_sine_factor = stream.read_float() | ||||
|         self.lightning_sine_phase = stream.read_float() | ||||
|         self.lightning_sine_phase_rep = stream.read_float() | ||||
|         self.lightning_length = stream.read_float() | ||||
|         self.lightning_random_move_speed = stream.read_float() | ||||
|         self.lightning_color = stream.read_tuple() | ||||
|         self.lightning_lifetime = stream.read_float() | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         stream.write_dword(self.lightning_texture) | ||||
|         stream.write_dword(self.lightning_src_bone) | ||||
|         stream.write_dword(self.lightning_dst_bone) | ||||
|         stream.write_float(self.lightning_width) | ||||
|         stream.write_float(self.lightning_random_factor) | ||||
|         stream.write_float(self.lightning_sine_factor) | ||||
|         stream.write_float(self.lightning_sine_phase) | ||||
|         stream.write_float(self.lightning_sine_phase_rep) | ||||
|         stream.write_float(self.lightning_length) | ||||
|         stream.write_float(self.lightning_random_move_speed) | ||||
|         stream.write_tuple(self.lightning_color) | ||||
|         stream.write_float(self.lightning_lifetime) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.lightning_texture = data['lightning_texture'] | ||||
|         self.lightning_src_bone = data['lightning_src_bone'] | ||||
|         self.lightning_dst_bone = data['lightning_dst_bone'] | ||||
|         self.lightning_width = data['lightning_width'] | ||||
|         self.lightning_random_factor = data['lightning_random_factor'] | ||||
|         self.lightning_sine_factor = data['lightning_sine_factor'] | ||||
|         self.lightning_sine_phase = data['lightning_sine_phase'] | ||||
|         self.lightning_sine_phase_rep = data['lightning_sine_phase_rep'] | ||||
|         self.lightning_length = data['lightning_length'] | ||||
|         self.lightning_random_move_speed = data['lightning_random_move_speed'] | ||||
|         self.lightning_color = data['lightning_color'] | ||||
|         self.lightning_lifetime = data['lightning_lifetime'] | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         data['lightning_texture'] = self.lightning_texture | ||||
|         data['lightning_src_bone'] = self.lightning_src_bone | ||||
|         data['lightning_dst_bone'] = self.lightning_dst_bone | ||||
|         data['lightning_width'] = self.lightning_width | ||||
|         data['lightning_random_factor'] = self.lightning_random_factor | ||||
|         data['lightning_sine_factor'] = self.lightning_sine_factor | ||||
|         data['lightning_sine_phase'] = self.lightning_sine_phase | ||||
|         data['lightning_sine_phase_rep'] = self.lightning_sine_phase_rep | ||||
|         data['lightning_length'] = self.lightning_length | ||||
|         data['lightning_random_move_speed'] = self.lightning_random_move_speed | ||||
|         data['lightning_color'] = self.lightning_color | ||||
|         data['lightning_lifetime'] = self.lightning_lifetime | ||||
|         return data | ||||
| 
 | ||||
| 
 | ||||
| class ArcGeometry: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         self.geometry_texture = stream.read_dword() | ||||
|         self.geometry_src_bone = stream.read_dword() | ||||
|         self.geometry_lifetime = stream.read_float() | ||||
|         self.geometry_tex_trans_x = stream.read_float() | ||||
|         self.geometry_tex_trans_y = stream.read_float() | ||||
|         self.geometry_tex_rot = stream.read_float() | ||||
|         self.geometry_grow = stream.read_tuple() | ||||
|         self.geometry_tesselation = stream.read_float() | ||||
|         self.geometry_size = stream.read_tuple() | ||||
|         self.geometry_geo_rot_x = stream.read_float() | ||||
|         self.geometry_fade_falloff = stream.read_float() | ||||
|         self.geometry_fadein = stream.read_float() | ||||
|         self.geometry_fadeout = stream.read_float() | ||||
|         self.geometry_color = [stream.read_float() for _ in range(4)] | ||||
|         self.geometry_type = stream.read_dword() | ||||
|         self.geometry_texture_proj = stream.read_dword() | ||||
|         self.geometry_fade_dir = stream.read_dword() | ||||
|         self.geometry_offset = stream.read_tuple() | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         stream.write_dword(self.geometry_texture) | ||||
|         stream.write_dword(self.geometry_src_bone) | ||||
|         stream.write_float(self.geometry_lifetime) | ||||
|         stream.write_float(self.geometry_tex_trans_x) | ||||
|         stream.write_float(self.geometry_tex_trans_y) | ||||
|         stream.write_float(self.geometry_tex_rot) | ||||
|         stream.write_tuple(self.geometry_grow) | ||||
|         stream.write_float(self.geometry_tesselation) | ||||
|         stream.write_tuple(self.geometry_size) | ||||
|         stream.write_float(self.geometry_geo_rot_x) | ||||
|         stream.write_float(self.geometry_fade_falloff) | ||||
|         stream.write_float(self.geometry_fadein) | ||||
|         stream.write_float(self.geometry_fadeout) | ||||
|         for i in range(4): | ||||
|             stream.write_float(self.geometry_color[i]) | ||||
|         stream.write_dword(self.geometry_type) | ||||
|         stream.write_dword(self.geometry_texture_proj) | ||||
|         stream.write_dword(self.geometry_fade_dir) | ||||
|         stream.write_tuple(self.geometry_offset) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.geometry_texture = data['geometry_texture'] | ||||
|         self.geometry_src_bone = data['geometry_src_bone'] | ||||
|         self.geometry_lifetime = data['geometry_lifetime'] | ||||
|         self.geometry_tex_trans_x = data['geometry_tex_trans_x'] | ||||
|         self.geometry_tex_trans_y = data['geometry_tex_trans_y'] | ||||
|         self.geometry_tex_rot = data['geometry_tex_rot'] | ||||
|         self.geometry_grow = data['geometry_grow'] | ||||
|         self.geometry_tesselation = data['geometry_tesselation'] | ||||
|         self.geometry_size = data['geometry_size'] | ||||
|         self.geometry_geo_rot_x = data['geometry_geo_rot_x'] | ||||
|         self.geometry_fade_falloff = data['geometry_fade_falloff'] | ||||
|         self.geometry_fadein = data['geometry_fadein'] | ||||
|         self.geometry_fadeout = data['geometry_fadeout'] | ||||
|         self.geometry_color = data['geometry_color'] | ||||
|         self.geometry_type = data['geometry_type'] | ||||
|         self.geometry_texture_proj = data['geometry_texture_proj'] | ||||
|         self.geometry_fade_dir = data['geometry_fade_dir'] | ||||
|         self.geometry_offset = data['geometry_offset'] | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         data['geometry_texture'] = self.geometry_texture | ||||
|         data['geometry_src_bone'] = self.geometry_src_bone | ||||
|         data['geometry_lifetime'] = self.geometry_lifetime | ||||
|         data['geometry_tex_trans_x'] = self.geometry_tex_trans_x | ||||
|         data['geometry_tex_trans_y'] = self.geometry_tex_trans_y | ||||
|         data['geometry_tex_rot'] = self.geometry_tex_rot | ||||
|         data['geometry_grow'] = self.geometry_grow | ||||
|         data['geometry_tesselation'] = self.geometry_tesselation | ||||
|         data['geometry_size'] = self.geometry_size | ||||
|         data['geometry_geo_rot_x'] = self.geometry_geo_rot_x | ||||
|         data['geometry_fade_falloff'] = self.geometry_fade_falloff | ||||
|         data['geometry_fadein'] = self.geometry_fadein | ||||
|         data['geometry_fadeout'] = self.geometry_fadeout | ||||
|         data['geometry_color'] = self.geometry_color | ||||
|         data['geometry_type'] = self.geometry_type | ||||
|         data['geometry_texture_proj'] = self.geometry_texture_proj | ||||
|         data['geometry_fade_dir'] = self.geometry_fade_dir | ||||
|         data['geometry_offset'] = self.geometry_offset | ||||
|         return data | ||||
| 
 | ||||
| 
 | ||||
| class ArcVisualEffect: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         self.effect_type = stream.read_dword() | ||||
|         self.effect_time = stream.read_float() | ||||
| 
 | ||||
|         if self.effect_type == 0: | ||||
|             self.effect = ArcParticle() | ||||
|         elif self.effect_type == 1: | ||||
|             self.effect = ArcLightning() | ||||
|         elif self.effect_type == 2: | ||||
|             self.effect = ArcGeometry() | ||||
|         self.effect.load_binary(stream) | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         stream.write_dword(self.effect_type) | ||||
|         stream.write_float(self.effect_time) | ||||
|         self.effect.save_binary(stream) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.effect_type = STRING_TO_EFFECT[data['effect_type']] | ||||
|         self.effect_time = data['effect_time'] | ||||
|         if self.effect_type == 0: | ||||
|             self.effect = ArcParticle() | ||||
|         elif self.effect_type == 1: | ||||
|             self.effect = ArcLightning() | ||||
|         elif self.effect_type == 2: | ||||
|             self.effect = ArcGeometry() | ||||
|         self.effect.load_json(data['effect']) | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         data['effect_type'] = EFFETCT_TO_STRING[self.effect_type] | ||||
|         data['effect_time'] = self.effect_time | ||||
|         data['effect'] = self.effect.save_json() | ||||
|         return data | ||||
| 
 | ||||
| 
 | ||||
| class ArcVisual: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         num_effects = stream.read_dword() | ||||
| 
 | ||||
|         self.vfx_fail = None | ||||
|         if num_effects == 1617156728: | ||||
|             stream.buffer.seek(0, 0) | ||||
|             self.vfx_fail = stream.buffer.read() | ||||
|             return | ||||
| 
 | ||||
|         self.vfx_duration = stream.read_float() | ||||
|         self.vfx_effects = [ArcVisualEffect() for _ in range(num_effects)] | ||||
|         for effect in self.vfx_effects: | ||||
|             effect.load_binary(stream) | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         if self.vfx_fail: | ||||
|             stream.buffer.write(self.vfx_fail) | ||||
|             return | ||||
| 
 | ||||
|         stream.write_dword(len(self.vfx_effects)) | ||||
|         stream.write_float(self.vfx_duration) | ||||
|         for effect in self.vfx_effects: | ||||
|             effect.save_binary(stream) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.vfx_fail = data.get('vfx_fail') | ||||
|         if self.vfx_fail: | ||||
|             self.vfx_fail = b64decode(self.vfx_fail) | ||||
|             return | ||||
| 
 | ||||
|         self.vfx_duration = data['vfx_duration'] | ||||
|         self.vfx_effects = [] | ||||
|         for effect_data in data['vfx_effects']: | ||||
|             effect = ArcVisualEffect() | ||||
|             effect.load_json(effect_data) | ||||
|             self.vfx_effects.append(effect) | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         if self.vfx_fail: | ||||
|             data['vfx_fail'] = b64encode(self.vfx_fail).decode() | ||||
|             return data | ||||
| 
 | ||||
|         data['vfx_duration'] = self.vfx_duration | ||||
|         data['vfx_effects'] = [] | ||||
|         for effect in self.vfx_effects: | ||||
|             data['vfx_effects'].append(effect.save_json()) | ||||
|         return data | ||||
| @ -0,0 +1,7 @@@@ -0,0 +1,7 @@ | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| @ -0,0 +1,7 @@@@ -0,0 +1,7 @@ | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| @ -1,10 +1,10 @@@@ -1,10 +1,10 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| DOOR_TYPE_ROTATE = 0 | ||||
| DOOR_TYPE_SLIDE = 1 | ||||
| @ -1,10 +1,10 @@@@ -1,10 +1,10 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| OBJECT_TYPE_LIGHT = 1 | ||||
| OBJECT_TYPE_DOOR = 2 | ||||
| @ -1,10 +1,10 @@@@ -1,10 +1,10 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| RUNE_UNKNOWN = 0 | ||||
| RUNE_RACE = 1 | ||||
| @ -1,10 +1,10 @@@@ -1,10 +1,10 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| SPARSE_VAL_LONG = 0  # dword | ||||
| SPARSE_VAL_FLOAT = 1  # float | ||||
| @ -1,10 +1,10 @@@@ -1,10 +1,10 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| REGION_CONTENTBEHAVIOR_SHOWNONE = 0 | ||||
| REGION_CONTENTBEHAVIOR_SHOWCHARACTERS = 1 | ||||
| @ -0,0 +1,7 @@@@ -0,0 +1,7 @@ | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| @ -0,0 +1,23 @@@@ -0,0 +1,23 @@ | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| INVENTORY_TYPE_GOLD = 1 | ||||
| INVENTORY_TYPE_ITEM = 2 | ||||
| INVENTORY_TYPE_BOOTYTABLE = 3 | ||||
| 
 | ||||
| INVENTORY_TYPE_TO_STRING = { | ||||
|     INVENTORY_TYPE_GOLD: 'GOLD', | ||||
|     INVENTORY_TYPE_ITEM: 'ITEM', | ||||
|     INVENTORY_TYPE_BOOTYTABLE: 'BOOTYTABLE', | ||||
| } | ||||
| 
 | ||||
| STRING_TO_INVENTORY_TYPE = { | ||||
|     'GOLD': INVENTORY_TYPE_GOLD, | ||||
|     'ITEM': INVENTORY_TYPE_ITEM, | ||||
|     'BOOTYTABLE': INVENTORY_TYPE_BOOTYTABLE, | ||||
| } | ||||
| @ -0,0 +1,41 @@@@ -0,0 +1,41 @@ | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| import glob | ||||
| import os | ||||
| 
 | ||||
| from arcane.util.hasher import hash_string | ||||
| 
 | ||||
| _STRING_TO_HASH = {} | ||||
| _HASH_TO_STRING = {} | ||||
| 
 | ||||
| 
 | ||||
| def load_files(): | ||||
|     directory = os.path.dirname(__file__) | ||||
| 
 | ||||
|     for filepath in glob.glob(os.path.join(directory, '*.txt')): | ||||
|         lines = list(map(lambda s: s.strip(), open(filepath).readlines())) | ||||
| 
 | ||||
|         _STRING_TO_HASH.update({ | ||||
|             s: hash_string(s) for s in lines | ||||
|         }) | ||||
| 
 | ||||
|         _HASH_TO_STRING.update({ | ||||
|             hash_string(s): s for s in lines | ||||
|         }) | ||||
| 
 | ||||
| 
 | ||||
| def string_to_hash(s): | ||||
|     return _STRING_TO_HASH.get(s, s) | ||||
| 
 | ||||
| 
 | ||||
| def hash_to_string(h): | ||||
|     return _HASH_TO_STRING.get(h, h) | ||||
| 
 | ||||
| 
 | ||||
| load_files() | ||||
| @ -0,0 +1,38 @@@@ -0,0 +1,38 @@ | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| MOBILE = 1 | ||||
| BANKER = 2 | ||||
| SHOPKEEPER = 3 | ||||
| TRAINER = 4 | ||||
| MERCHANT = 8 | ||||
| HIRELING = 9 | ||||
| PET = 10 | ||||
| MINION = 11 | ||||
| 
 | ||||
| MOBILE_TO_STRING = { | ||||
|     MOBILE: 'MOBILE', | ||||
|     BANKER: 'BANKER', | ||||
|     SHOPKEEPER: 'SHOPKEEPER', | ||||
|     TRAINER: 'TRAINER', | ||||
|     MERCHANT: 'MERCHANT', | ||||
|     HIRELING: 'HIRELING', | ||||
|     PET: 'PET', | ||||
|     MINION: 'MINION', | ||||
| } | ||||
| 
 | ||||
| STRING_TO_MOBILE = { | ||||
|     'MOBILE': MOBILE, | ||||
|     'BANKER': BANKER, | ||||
|     'SHOPKEEPER': SHOPKEEPER, | ||||
|     'TRAINER': TRAINER, | ||||
|     'MERCHANT': MERCHANT, | ||||
|     'HIRELING': HIRELING, | ||||
|     'PET': PET, | ||||
|     'MINION': MINION, | ||||
| } | ||||
| @ -0,0 +1,23 @@@@ -0,0 +1,23 @@ | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| PROP = 5 | ||||
| CITY = 6 | ||||
| CONTAINER = 7 | ||||
| 
 | ||||
| PROP_TO_STRING = { | ||||
|     PROP: 'PROP', | ||||
|     CITY: 'CITY', | ||||
|     CONTAINER: 'CONTAINER', | ||||
| } | ||||
| 
 | ||||
| STRING_TO_PROP = { | ||||
|     'PROP': PROP, | ||||
|     'CITY': CITY, | ||||
|     'CONTAINER': CONTAINER, | ||||
| } | ||||
| @ -0,0 +1,35 @@@@ -0,0 +1,35 @@ | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| PEAKED = 1 | ||||
| RIDGED = 2 | ||||
| ROLLING = 3 | ||||
| MESA = 5 | ||||
| PLANAR = 4 | ||||
| MESH = 6 | ||||
| TARGA = 7 | ||||
| 
 | ||||
| TERRAIN_TYPE_TO_STRING = { | ||||
|     PEAKED: 'PEAKED', | ||||
|     RIDGED: 'RIDGED', | ||||
|     ROLLING: 'ROLLING', | ||||
|     MESA: 'MESA', | ||||
|     PLANAR: 'PLANAR', | ||||
|     MESH: 'MESH', | ||||
|     TARGA: 'TARGA', | ||||
| } | ||||
| 
 | ||||
| STRING_TO_TERRAIN_TYPE = { | ||||
|     'PEAKED': PEAKED, | ||||
|     'RIDGED': RIDGED, | ||||
|     'ROLLING': ROLLING, | ||||
|     'MESA': MESA, | ||||
|     'PLANAR': PLANAR, | ||||
|     'MESH': MESH, | ||||
|     'TARGA': TARGA, | ||||
| } | ||||
| @ -0,0 +1,62 @@@@ -0,0 +1,62 @@ | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| ELLIPTICAL = 0 | ||||
| RECTANGULAR = 1 | ||||
| 
 | ||||
| ZONE_TO_STRING = { | ||||
|     ELLIPTICAL: 'ELLIPTICAL', | ||||
|     RECTANGULAR: 'RECTANGULAR', | ||||
| } | ||||
| 
 | ||||
| STRING_TO_ZONE = { | ||||
|     'ELLIPTICAL': ELLIPTICAL, | ||||
|     'RECTANGULAR': RECTANGULAR, | ||||
| } | ||||
| 
 | ||||
| GLOBAL = 0 | ||||
| LOCAL = 1 | ||||
| 
 | ||||
| TILECOORD_TO_STRING = { | ||||
|     GLOBAL: 'GLOBAL', | ||||
|     LOCAL: 'LOCAL', | ||||
| } | ||||
| 
 | ||||
| STRING_TO_TILECOORD = { | ||||
|     'GLOBAL': GLOBAL, | ||||
|     'LOCAL': LOCAL, | ||||
| } | ||||
| 
 | ||||
| ADJACENT = 0 | ||||
| RANDOM = 1 | ||||
| 
 | ||||
| PATTERN_TO_STRING = { | ||||
|     ADJACENT: 'ADJACENT', | ||||
|     RANDOM: 'RANDOM', | ||||
| } | ||||
| 
 | ||||
| STRING_TO_PATTERN = { | ||||
|     'ADJACENT': ADJACENT, | ||||
|     'RANDOM': RANDOM, | ||||
| } | ||||
| 
 | ||||
| PARENT = 0 | ||||
| WORLD = 1 | ||||
| SELF = 2 | ||||
| 
 | ||||
| SEALEVEL_TO_STRING = { | ||||
|     PARENT: 'PARENT', | ||||
|     WORLD: 'WORLD', | ||||
|     SELF: 'SELF', | ||||
| } | ||||
| 
 | ||||
| STRING_TO_SEALEVEL = { | ||||
|     'PARENT': PARENT, | ||||
|     'WORLD': WORLD, | ||||
|     'SELF': SELF, | ||||
| } | ||||
| @ -1,10 +1,10 @@@@ -1,10 +1,10 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| GOAL_TYPE_NONE = 0 | ||||
| GOAL_TYPE_POINTS_ORDERED = 1 | ||||
| @ -0,0 +1,29 @@@@ -0,0 +1,29 @@ | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from arcane.util import ResStream | ||||
| from .ArcStructureObject import ArcStructureObject | ||||
| 
 | ||||
| 
 | ||||
| class ArcAssetStructureObject(ArcStructureObject): | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         super().load_binary(stream) | ||||
|         self.asset_structure_template_id = stream.read_qword() | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         super().save_binary(stream) | ||||
|         stream.write_qword(self.asset_structure_template_id) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         super().load_json(data) | ||||
|         self.asset_structure_template_id = data['asset_structure_template_id'] | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = super().save_json() | ||||
|         data['asset_structure_template_id'] = self.asset_structure_template_id | ||||
|         return data | ||||
| @ -1,10 +1,10 @@@@ -1,10 +1,10 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from collections import OrderedDict | ||||
| 
 | ||||
| @ -1,10 +1,11 @@@@ -1,10 +1,11 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from arcane.util import ResStream | ||||
| from .ArcItem import ArcItem | ||||
| from .common.Inventory import Inventory | ||||
| @ -1,10 +1,10 @@@@ -1,10 +1,10 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from arcane.util import ResStream | ||||
| from .ArcItem import ArcItem | ||||
| @ -1,10 +1,10 @@@@ -1,10 +1,10 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from collections import OrderedDict | ||||
| 
 | ||||
| @ -1,10 +1,10 @@@@ -1,10 +1,10 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from arcane.util.ResStream import ResStream | ||||
| from .ArcStructureObject import ArcStructureObject | ||||
| @ -1,10 +1,10 @@@@ -1,10 +1,10 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from collections import OrderedDict | ||||
| 
 | ||||
| @ -1,10 +1,10 @@@@ -1,10 +1,10 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from arcane.util import ResStream | ||||
| from .ArcItem import ArcItem | ||||
| @ -1,10 +1,10 @@@@ -1,10 +1,10 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from collections import OrderedDict | ||||
| 
 | ||||
| @ -1,10 +1,10 @@@@ -1,10 +1,10 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from collections import OrderedDict | ||||
| 
 | ||||
| @ -1,10 +1,10 @@@@ -1,10 +1,10 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from collections import OrderedDict | ||||
| 
 | ||||
| @ -0,0 +1,21 @@@@ -0,0 +1,21 @@ | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from .ArcAssetStructureObject import ArcAssetStructureObject | ||||
| from .ArcCityAssetTemplate import ArcCityAssetTemplate | ||||
| from .ArcCombatObj import ArcCombatObj, ArcCharacter | ||||
| from .ArcContainerObject import ArcContainerObject | ||||
| from .ArcDeed import ArcDeed | ||||
| from .ArcDoorObject import ArcDoorObject | ||||
| from .ArcDungeonUnitObject import ArcDungeonUnitObject, ArcDungeonExitObject, ArcDungeonStairObject | ||||
| from .ArcItem import ArcItem | ||||
| from .ArcKey import ArcKey | ||||
| from .ArcObj import ArcObj | ||||
| from .ArcRune import ArcRune | ||||
| from .ArcStaticObject import ArcStaticObject | ||||
| from .ArcStructureObject import ArcStructureObject | ||||
| @ -1,10 +1,11 @@@@ -1,10 +1,11 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from collections import OrderedDict | ||||
| 
 | ||||
| from arcane.enums.hashes import hash_to_string, string_to_hash | ||||
| @ -1,10 +1,11 @@@@ -1,10 +1,11 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from collections import OrderedDict | ||||
| 
 | ||||
| from arcane.enums.hashes import hash_to_string, string_to_hash | ||||
| @ -0,0 +1,41 @@@@ -0,0 +1,41 @@ | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from collections import OrderedDict | ||||
| 
 | ||||
| from arcane.enums.hashes import hash_to_string, string_to_hash | ||||
| from arcane.util import ResStream | ||||
| 
 | ||||
| 
 | ||||
| class DiscRequired: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         discs = stream.read_dword() | ||||
|         self.disc_restrict = stream.read_bool() | ||||
|         self.disc_values = [ | ||||
|             stream.read_dword() for _ in range(discs) | ||||
|         ] | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         stream.write_dword(len(self.disc_values)) | ||||
|         stream.write_bool(self.disc_restrict) | ||||
|         for disc in self.disc_values: | ||||
|             stream.write_dword(disc) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.disc_restrict = data['restrict'] | ||||
|         self.disc_values = [] | ||||
|         for disc in data['discs']: | ||||
|             self.disc_values.append(string_to_hash(disc)) | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         data['restrict'] = self.disc_restrict | ||||
|         data['discs'] = [] | ||||
|         for disc in self.disc_values: | ||||
|             data['discs'].append(hash_to_string(disc)) | ||||
|         return data | ||||
| @ -1,10 +1,11 @@@@ -1,10 +1,11 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from collections import OrderedDict | ||||
| 
 | ||||
| from arcane.enums.common.arc_inventory import * | ||||
| @ -0,0 +1,41 @@@@ -0,0 +1,41 @@ | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from collections import OrderedDict | ||||
| 
 | ||||
| from arcane.enums.hashes import hash_to_string, string_to_hash | ||||
| from arcane.util import ResStream | ||||
| 
 | ||||
| 
 | ||||
| class RaceRequired: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         races = stream.read_dword() | ||||
|         self.race_restrict = stream.read_bool() | ||||
|         self.race_values = [ | ||||
|             stream.read_dword() for _ in range(races) | ||||
|         ] | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         stream.write_dword(len(self.race_values)) | ||||
|         stream.write_bool(self.race_restrict) | ||||
|         for race in self.race_values: | ||||
|             stream.write_dword(race) | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.race_restrict = data['restrict'] | ||||
|         self.race_values = [] | ||||
|         for race in data['races']: | ||||
|             self.race_values.append(string_to_hash(race)) | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         data['restrict'] = self.race_restrict | ||||
|         data['races'] = [] | ||||
|         for race in self.race_values: | ||||
|             data['races'].append(hash_to_string(race)) | ||||
|         return data | ||||
| @ -1,10 +1,11 @@@@ -1,10 +1,11 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from collections import OrderedDict | ||||
| 
 | ||||
| from arcane.enums.arc_sparse import * | ||||
| @ -0,0 +1,7 @@@@ -0,0 +1,7 @@ | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| @ -1,10 +1,10 @@@@ -1,10 +1,10 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| import struct | ||||
| import zlib | ||||
| @ -0,0 +1,10 @@@@ -0,0 +1,10 @@ | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from .ArcFileCache import load_cache_file, save_cache_file | ||||
| from .ResStream import ResStream | ||||
| @ -1,10 +1,10 @@@@ -1,10 +1,10 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| def _hash_string_short(array): | ||||
|     v04 = (8 * array[7]) & 0xffffffff | ||||
| @ -0,0 +1,19 @@@@ -0,0 +1,19 @@ | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄ | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪ | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| # | ||||
| 
 | ||||
| def int32(x): | ||||
|     if x > 0xFFFFFFFF: | ||||
|         raise OverflowError | ||||
|     if x > 0x7FFFFFFF: | ||||
|         x = int(0x100000000 - x) | ||||
|         if x < 2147483648: | ||||
|             return -x | ||||
|         else: | ||||
|             return -2147483648 | ||||
|     return x | ||||
| @ -0,0 +1,39 @@@@ -0,0 +1,39 @@ | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from collections import OrderedDict | ||||
| 
 | ||||
| from arcane.util import ResStream | ||||
| 
 | ||||
| 
 | ||||
| class ArcDungeonInfo: | ||||
|     def load_binary(self, stream: ResStream): | ||||
|         self.dungeon_template_id = stream.read_qword() | ||||
|         self.dungeon_unknown = stream.read_qword() | ||||
|         self.dungeon_spawn_location = stream.read_tuple() | ||||
|         self.dungeon_y_offset = stream.read_float() | ||||
| 
 | ||||
|     def save_binary(self, stream: ResStream): | ||||
|         stream.write_qword(self.dungeon_template_id) | ||||
|         stream.write_qword(self.dungeon_unknown) | ||||
|         stream.write_tuple(self.dungeon_spawn_location) | ||||
|         stream.write_float(self.dungeon_y_offset) | ||||
| 
 | ||||
|     def save_json(self): | ||||
|         data = OrderedDict() | ||||
|         data['dungeon_template_id'] = self.dungeon_template_id | ||||
|         data['dungeon_unknown'] = self.dungeon_unknown | ||||
|         data['dungeon_spawn_location'] = self.dungeon_spawn_location | ||||
|         data['dungeon_y_offset'] = self.dungeon_y_offset | ||||
|         return data | ||||
| 
 | ||||
|     def load_json(self, data): | ||||
|         self.dungeon_template_id = data['dungeon_template_id'] | ||||
|         self.dungeon_unknown = data['dungeon_unknown'] | ||||
|         self.dungeon_spawn_location = data['dungeon_spawn_location'] | ||||
|         self.dungeon_y_offset = data['dungeon_y_offset'] | ||||
| @ -1,10 +1,10 @@@@ -1,10 +1,10 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from collections import OrderedDict | ||||
| 
 | ||||
| @ -1,10 +1,10 @@@@ -1,10 +1,10 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from collections import OrderedDict | ||||
| 
 | ||||
| @ -1,10 +1,10 @@@@ -1,10 +1,10 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from collections import OrderedDict | ||||
| 
 | ||||
| @ -1,10 +1,10 @@@@ -1,10 +1,10 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from collections import OrderedDict | ||||
| 
 | ||||
| @ -1,10 +1,10 @@@@ -1,10 +1,10 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from collections import OrderedDict | ||||
| 
 | ||||
| @ -1,10 +1,10 @@@@ -1,10 +1,10 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from collections import OrderedDict | ||||
| 
 | ||||
| @ -1,10 +1,10 @@@@ -1,10 +1,10 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from collections import OrderedDict | ||||
| 
 | ||||
| @ -1,10 +1,10 @@@@ -1,10 +1,10 @@ | ||||
| # • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄         | ||||
| # ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪      | ||||
| # ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄  | ||||
| # ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| # ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #               Magicbane Emulator Project © 2013 - 2022 | ||||
| #                          www.magicbane.com | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from collections import OrderedDict | ||||
| 
 | ||||
| @ -0,0 +1,9 @@@@ -0,0 +1,9 @@ | ||||
| #  • ▌ ▄ ·. ▄▄▄▄·     ▄▄▄ .·▄▄▄▄  ▪  ▄▄▄▄▄      ▄▄▄       ▄▄▄·▄▄▄        | ||||
| #  ·██ ▐███▪▐█ ▀█▪    ▀▄.▀·██▪ ██ ██ •██  ▪     ▀▄ █·    ▐█ ▄█▀▄ █·▪     | ||||
| #  ▐█ ▌▐▌▐█·▐█▀▀█▄    ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄      ██▀·▐▀▀▄  ▄█▀▄ | ||||
| #  ██ ██▌▐█▌██▄▪▐█    ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌    ▐█▪·•▐█•█▌▐█▌.▐▌ | ||||
| #  ▀▀  █▪▀▀▀·▀▀▀▀      ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀  ▀█▄▀▪.▀  ▀    .▀   .▀  ▀ ▀█▄▀▪ | ||||
| #                Magicbane Emulator Project © 2013 - 2022 | ||||
| #                           www.magicbane.com | ||||
| 
 | ||||
| from .ArcZone import ArcZone | ||||
Some files were not shown because too many files have changed in this diff Show More
					Loading…
					
					
				
		Reference in new issue