MagicBot
2 years ago
110 changed files with 3542 additions and 1088 deletions
@ -1,12 +1,65 @@ |
|||||||
``` |
``` |
||||||
• ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
• ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
||||||
·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
||||||
▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
||||||
██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
||||||
▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
||||||
|
|
||||||
Magicbane Emulator Project © 2013 - 2022 |
Magicbane Emulator Project © 2013 - 2022 |
||||||
www.magicbane.com |
www.magicbane.com |
||||||
``` |
``` |
||||||
|
|
||||||
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. |
# mbEditorPro v 2.0 |
||||||
|
|
||||||
|
![Example Output](https://cdn.discordapp.com/attachments/399623779531096074/1029063849640468550/unknown.png) |
||||||
|
|
||||||
|
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! |
||||||
|
|
||||||
|
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 |
||||||
|
``` |
||||||
|
|
||||||
|
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 @@ |
|||||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
|
||||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
|
||||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
|
||||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
|
||||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
|
||||||
# Magicbane Emulator Project © 2013 - 2022 |
|
||||||
# www.magicbane.com |
|
@ -1,7 +0,0 @@ |
|||||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
|
||||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
|
||||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
|
||||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
|
||||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
|
||||||
# Magicbane Emulator Project © 2013 - 2022 |
|
||||||
# www.magicbane.com |
|
@ -1,7 +0,0 @@ |
|||||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
|
||||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
|
||||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
|
||||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
|
||||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
|
||||||
# Magicbane Emulator Project © 2013 - 2022 |
|
||||||
# www.magicbane.com |
|
@ -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 @@ |
|||||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
|
||||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
|
||||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
|
||||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
|
||||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
|
||||||
# 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 @@ |
|||||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
|
||||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
|
||||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
|
||||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
|
||||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
|
||||||
# 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 @@ |
|||||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
|
||||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
|
||||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
|
||||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
|
||||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
|
||||||
# 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 @@ |
|||||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
|
||||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
|
||||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
|
||||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
|
||||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
|
||||||
# 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 @@ |
|||||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
|
||||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
|
||||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
|
||||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
|
||||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
|
||||||
# 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 @@ |
|||||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
|
||||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
|
||||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
|
||||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
|
||||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
|
||||||
# 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 @@ |
|||||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
|
||||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
|
||||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
|
||||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
|
||||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
|
||||||
# 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 @@ |
|||||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
|
||||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
|
||||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
|
||||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
|
||||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
|
||||||
# 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 @@ |
|||||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
|
||||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
|
||||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
|
||||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
|
||||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
|
||||||
# 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 @@ |
|||||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
|
||||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
|
||||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
|
||||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
|
||||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
|
||||||
# Magicbane Emulator Project © 2013 - 2022 |
|
||||||
# www.magicbane.com |
|
@ -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 @@ |
|||||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
|
||||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
|
||||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
|
||||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
|
||||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
|
||||||
# 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 @@ |
|||||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
|
||||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
|
||||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
|
||||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
|
||||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
|
||||||
# Magicbane Emulator Project © 2013 - 2022 |
|
||||||
# www.magicbane.com |
|
||||||
|
|
||||||
from .ArcZone import ArcZone |
|
@ -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 @@ |
|||||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
|
||||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
|
||||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
|
||||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
|
||||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
|
||||||
# Magicbane Emulator Project © 2013 - 2022 |
|
||||||
# www.magicbane.com |
|
@ -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 @@ |
|||||||
|
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
||||||
|
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
||||||
|
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
||||||
|
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
||||||
|
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
||||||
|
# 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 @@ |
|||||||
|
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
||||||
|
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
||||||
|
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
||||||
|
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
||||||
|
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
||||||
|
# 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 @@ |
|||||||
|
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
||||||
|
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
||||||
|
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
||||||
|
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
||||||
|
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
||||||
|
# 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 @@ |
|||||||
|
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
||||||
|
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
||||||
|
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
||||||
|
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
||||||
|
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
||||||
|
# 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 @@ |
|||||||
|
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
||||||
|
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
||||||
|
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
||||||
|
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
||||||
|
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
||||||
|
# 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 @@ |
|||||||
|
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
||||||
|
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
||||||
|
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
||||||
|
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
||||||
|
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
||||||
|
# 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 @@ |
|||||||
|
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
||||||
|
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
||||||
|
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
||||||
|
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
||||||
|
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
||||||
|
# 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 @@ |
|||||||
|
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
||||||
|
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
||||||
|
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
||||||
|
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
||||||
|
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
||||||
|
# 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 @@ |
|||||||
|
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
||||||
|
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
||||||
|
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
||||||
|
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
||||||
|
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
||||||
|
# Magicbane Emulator Project © 2013 - 2022 |
||||||
|
# www.magicbane.com |
@ -0,0 +1,7 @@ |
|||||||
|
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
||||||
|
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
||||||
|
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
||||||
|
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
||||||
|
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
||||||
|
# Magicbane Emulator Project © 2013 - 2022 |
||||||
|
# www.magicbane.com |
@ -0,0 +1,7 @@ |
|||||||
|
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
||||||
|
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
||||||
|
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
||||||
|
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
||||||
|
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
||||||
|
# Magicbane Emulator Project © 2013 - 2022 |
||||||
|
# www.magicbane.com |
@ -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 @@ |
|||||||
|
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
||||||
|
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
||||||
|
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
||||||
|
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
||||||
|
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
||||||
|
# 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 @@ |
|||||||
|
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
||||||
|
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
||||||
|
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
||||||
|
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
||||||
|
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
||||||
|
# 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 @@ |
|||||||
|
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
||||||
|
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
||||||
|
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
||||||
|
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
||||||
|
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
||||||
|
# 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 @@ |
|||||||
|
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
||||||
|
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
||||||
|
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
||||||
|
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
||||||
|
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
||||||
|
# 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 @@ |
|||||||
|
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
||||||
|
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
||||||
|
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
||||||
|
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
||||||
|
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
||||||
|
# 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, |
||||||
|
} |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -0,0 +1,7 @@ |
|||||||
|
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
||||||
|
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
||||||
|
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
||||||
|
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
||||||
|
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
||||||
|
# Magicbane Emulator Project © 2013 - 2022 |
||||||
|
# www.magicbane.com |
@ -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 |
@ -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 @@ |
|||||||
|
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
||||||
|
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
||||||
|
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
||||||
|
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
||||||
|
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
||||||
|
# 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'] |
@ -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