mbEditorPro2.0 release
This commit is contained in:
@@ -1,12 +1,65 @@
|
||||
```
|
||||
• ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
|
||||
```
|
||||
• ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
Magicbane Emulator Project © 2013 - 2022
|
||||
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
|
||||
|
||||

|
||||
|
||||
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()
|
||||
@@ -8,34 +8,32 @@
|
||||
www.magicbane.com
|
||||
```
|
||||
|
||||
# mbEditorPro v 1.0
|
||||
# mbEditorPro v 2.0
|
||||
|
||||

|
||||
|
||||
Team Magicbane presents to the community technology allowing MagicBox administrators<br>
|
||||
to fully modify their game using nothing more than notepad.exe. <br>
|
||||
|
||||
- Tool directly converts Shadowbane .cache files to and from a high fidality pure JSON representation.
|
||||
- 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 currently parses both the CObject.cache and the Czones.cache files. These were chosen<br>
|
||||
to start with as they will allow a MagicBox administrator to modify the game. The remainder of the <br>
|
||||
existing .cache files modify how the game looks and will be added soon.<br>
|
||||
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 czones
|
||||
mbEditorPro.py unpack all
|
||||
```
|
||||
JSON output will be in a folder **ARCANE DUMP** <br>
|
||||
|
||||
```
|
||||
mbEditorPro.py pack cobjects
|
||||
mbEditorPro.py pack czones
|
||||
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>>
|
||||
@@ -60,9 +58,8 @@ The tool generating pure JSON has the following benefits:
|
||||
|
||||
mbEditorPro will be the cornerstone of Magicbane's data project. The Team's goal is threefold:
|
||||
|
||||
- Build tooling to generate high fidality Magicbane databases from the JSON data.
|
||||
- Build up the tool and technology to parse the remaining .cache file.
|
||||
- Ship MagicBox 1.5 with both Aerynth and Vorringia mapsets available.<br>
|
||||
- Ship MagicBox 1.5 with both Aerynth and Vorringia mapsets available.
|
||||
- Integrate Magicbane's wpak extractor technology into the tool<br>
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -6,7 +6,7 @@
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
ATTACK_RESIST_UNKOWN = 0
|
||||
ATTACK_RESIST_UNKNOWN = 0
|
||||
ATTACK_RESIST_SLASHING = 1
|
||||
ATTACK_RESIST_CRUSHING = 2
|
||||
ATTACK_RESIST_PIERCING = 3
|
||||
@@ -24,7 +24,7 @@ ATTACK_RESIST_UNHOLY = 14
|
||||
ATTACK_RESIST_ANTISIEGE = 15
|
||||
|
||||
ATTACK_RESIST_TO_STRING = {
|
||||
ATTACK_RESIST_UNKOWN: 'UNKOWN',
|
||||
ATTACK_RESIST_UNKNOWN: 'UNKNOWN',
|
||||
ATTACK_RESIST_SLASHING: 'SLASHING',
|
||||
ATTACK_RESIST_CRUSHING: 'CRUSHING',
|
||||
ATTACK_RESIST_PIERCING: 'PIERCING',
|
||||
@@ -43,7 +43,7 @@ ATTACK_RESIST_TO_STRING = {
|
||||
}
|
||||
|
||||
STRING_TO_ATTACK_RESIST = {
|
||||
'UNKOWN': ATTACK_RESIST_UNKOWN,
|
||||
'UNKNOWN': ATTACK_RESIST_UNKNOWN,
|
||||
'SLASHING': ATTACK_RESIST_SLASHING,
|
||||
'CRUSHING': ATTACK_RESIST_CRUSHING,
|
||||
'PIERCING': ATTACK_RESIST_PIERCING,
|
||||
@@ -241,26 +241,26 @@ STRING_TO_ITEM_USE_FLAGS = {
|
||||
'EMPTY_NEWITEM': ITEM_USE_FLAGS_EMPTY_NEWITEM,
|
||||
}
|
||||
|
||||
ITEM_SHEATHSLOT_UNKOWN = 0
|
||||
ITEM_SHEATHSLOT_UNKNOWN = 0
|
||||
ITEM_SHEATHSLOT_BACK = 1
|
||||
ITEM_SHEATHSLOT_WAIST = 2
|
||||
ITEM_SHEATHSLOT_NONE = 4
|
||||
|
||||
ITEM_SHEATHSLOT_TO_STRING = {
|
||||
ITEM_SHEATHSLOT_NONE: 'NONE',
|
||||
ITEM_SHEATHSLOT_UNKOWN: 'UNKOWN',
|
||||
ITEM_SHEATHSLOT_UNKNOWN: 'UNKNOWN',
|
||||
ITEM_SHEATHSLOT_BACK: 'BACK',
|
||||
ITEM_SHEATHSLOT_WAIST: 'WAIST',
|
||||
}
|
||||
|
||||
STRING_TO_ITEM_SHEATHSLOT = {
|
||||
'NONE': ITEM_SHEATHSLOT_NONE,
|
||||
'UNKOWN': ITEM_SHEATHSLOT_UNKOWN,
|
||||
'UNKNOWN': ITEM_SHEATHSLOT_UNKNOWN,
|
||||
'BACK': ITEM_SHEATHSLOT_BACK,
|
||||
'WAIST': ITEM_SHEATHSLOT_WAIST,
|
||||
}
|
||||
|
||||
DAMAGE_UNKOWN = 0
|
||||
DAMAGE_UNKNOWN = 0
|
||||
DAMAGE_SLASHING = 1
|
||||
DAMAGE_CRUSHING = 2
|
||||
DAMAGE_PIERCING = 3
|
||||
@@ -278,7 +278,7 @@ DAMAGE_UNHOLY = 14
|
||||
DAMAGE_ANTISIEGE = 15
|
||||
|
||||
DAMAGE_TO_STRING = {
|
||||
DAMAGE_UNKOWN: 'UNKOWN',
|
||||
DAMAGE_UNKNOWN: 'UNKNOWN',
|
||||
DAMAGE_SLASHING: 'SLASHING',
|
||||
DAMAGE_CRUSHING: 'CRUSHING',
|
||||
DAMAGE_PIERCING: 'PIERCING',
|
||||
@@ -297,7 +297,7 @@ DAMAGE_TO_STRING = {
|
||||
}
|
||||
|
||||
STRING_TO_DAMAGE = {
|
||||
'UNKOWN': DAMAGE_UNKOWN,
|
||||
'UNKNOWN': DAMAGE_UNKNOWN,
|
||||
'SLASHING': DAMAGE_SLASHING,
|
||||
'CRUSHING': DAMAGE_CRUSHING,
|
||||
'PIERCING': DAMAGE_PIERCING,
|
||||
@@ -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
|
||||
+14
-14
@@ -130,13 +130,13 @@ class ArcCityAssetTemplate():
|
||||
self.template_energy_set = stream.read_dword()
|
||||
self.template_use_trigger = stream.read_string()
|
||||
|
||||
self.template_unkown_check1 = stream.read_bool()
|
||||
if self.template_unkown_check1:
|
||||
self.template_unknown_check1 = stream.read_bool()
|
||||
if self.template_unknown_check1:
|
||||
pass
|
||||
self.template_loot_trigger = stream.read_string()
|
||||
|
||||
self.template_unkown_check2 = stream.read_bool()
|
||||
if self.template_unkown_check2:
|
||||
self.template_unknown_check2 = stream.read_bool()
|
||||
if self.template_unknown_check2:
|
||||
pass
|
||||
|
||||
self.has_embedded_template = stream.read_bool()
|
||||
@@ -199,7 +199,7 @@ class ArcCityAssetTemplate():
|
||||
stream.read_dword(),
|
||||
] for _ in range(num_resource_limit)
|
||||
]
|
||||
self.template_unkown = stream.read_dword()
|
||||
self.template_unknown = stream.read_dword()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.template_max_ranks)
|
||||
@@ -232,9 +232,9 @@ class ArcCityAssetTemplate():
|
||||
stream.write_dword(self.template_damage_set)
|
||||
stream.write_dword(self.template_energy_set)
|
||||
stream.write_string(self.template_use_trigger)
|
||||
stream.write_bool(self.template_unkown_check1)
|
||||
stream.write_bool(self.template_unknown_check1)
|
||||
stream.write_string(self.template_loot_trigger)
|
||||
stream.write_bool(self.template_unkown_check2)
|
||||
stream.write_bool(self.template_unknown_check2)
|
||||
stream.write_bool(self.has_embedded_template)
|
||||
if self.has_embedded_template:
|
||||
self.template_embed_template.save_binary(stream)
|
||||
@@ -276,7 +276,7 @@ class ArcCityAssetTemplate():
|
||||
stream.write_dword(resource[0])
|
||||
stream.write_dword(resource[1])
|
||||
stream.write_dword(resource[2])
|
||||
stream.write_dword(self.template_unkown)
|
||||
stream.write_dword(self.template_unknown)
|
||||
|
||||
def load_json(self, data):
|
||||
self.template_max_ranks = data['template_max_ranks']
|
||||
@@ -307,9 +307,9 @@ class ArcCityAssetTemplate():
|
||||
self.template_damage_set = data['template_damage_set']
|
||||
self.template_energy_set = data['template_energy_set']
|
||||
self.template_use_trigger = data['template_use_trigger']
|
||||
self.template_unkown_check1 = data['template_unkown_check1']
|
||||
self.template_unknown_check1 = data['template_unknown_check1']
|
||||
self.template_loot_trigger = data['template_loot_trigger']
|
||||
self.template_unkown_check2 = data['template_unkown_check2']
|
||||
self.template_unknown_check2 = data['template_unknown_check2']
|
||||
self.has_embedded_template = data['has_embedded_template']
|
||||
if self.has_embedded_template:
|
||||
self.template_embed_template = ArcCityAssetTemplate()
|
||||
@@ -330,7 +330,7 @@ class ArcCityAssetTemplate():
|
||||
self.template_placement_type = data['template_placement_type']
|
||||
self.template_offering_adjustment = data['template_offering_adjustment']
|
||||
self.template_resource_limit = data['template_resource_limit']
|
||||
self.template_unkown = data['template_unkown']
|
||||
self.template_unknown = data['template_unknown']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
@@ -362,9 +362,9 @@ class ArcCityAssetTemplate():
|
||||
data['template_damage_set'] = self.template_damage_set
|
||||
data['template_energy_set'] = self.template_energy_set
|
||||
data['template_use_trigger'] = self.template_use_trigger
|
||||
data['template_unkown_check1'] = self.template_unkown_check1
|
||||
data['template_unknown_check1'] = self.template_unknown_check1
|
||||
data['template_loot_trigger'] = self.template_loot_trigger
|
||||
data['template_unkown_check2'] = self.template_unkown_check2
|
||||
data['template_unknown_check2'] = self.template_unknown_check2
|
||||
data['has_embedded_template'] = self.has_embedded_template
|
||||
if self.has_embedded_template:
|
||||
data['template_embed_template'] = self.template_embed_template.save_json()
|
||||
@@ -382,5 +382,5 @@ class ArcCityAssetTemplate():
|
||||
data['template_placement_type'] = self.template_placement_type
|
||||
data['template_offering_adjustment'] = self.template_offering_adjustment
|
||||
data['template_resource_limit'] = self.template_resource_limit
|
||||
data['template_unkown'] = self.template_unkown
|
||||
data['template_unknown'] = self.template_unknown
|
||||
return data
|
||||
+1
@@ -5,6 +5,7 @@
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from arcane.util import ResStream
|
||||
from .ArcItem import ArcItem
|
||||
from .common.Inventory import Inventory
|
||||
+12
-12
@@ -30,9 +30,9 @@ class Region:
|
||||
stream.read_byte(),
|
||||
stream.read_byte()
|
||||
]
|
||||
self.region_unkown2 = stream.read_byte()
|
||||
self.region_unkown3 = stream.read_byte()
|
||||
self.region_unkown4 = stream.read_tuple()
|
||||
self.region_unknown2 = stream.read_byte()
|
||||
self.region_unknown3 = stream.read_byte()
|
||||
self.region_unknown4 = stream.read_tuple()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(len(self.region_points))
|
||||
@@ -46,9 +46,9 @@ class Region:
|
||||
if self.region_has_stairs:
|
||||
stream.write_byte(self.region_stairs[0])
|
||||
stream.write_byte(self.region_stairs[1])
|
||||
stream.write_byte(self.region_unkown2)
|
||||
stream.write_byte(self.region_unkown3)
|
||||
stream.write_tuple(self.region_unkown4)
|
||||
stream.write_byte(self.region_unknown2)
|
||||
stream.write_byte(self.region_unknown3)
|
||||
stream.write_tuple(self.region_unknown4)
|
||||
|
||||
def load_json(self, data):
|
||||
self.region_points = data['region_points']
|
||||
@@ -61,9 +61,9 @@ class Region:
|
||||
self.region_has_stairs = data['region_has_stairs']
|
||||
if self.region_has_stairs:
|
||||
self.region_stairs = data['region_stairs']
|
||||
self.region_unkown2 = data['region_unkown2']
|
||||
self.region_unkown3 = data['region_unkown3']
|
||||
self.region_unkown4 = data['region_unkown4']
|
||||
self.region_unknown2 = data['region_unknown2']
|
||||
self.region_unknown3 = data['region_unknown3']
|
||||
self.region_unknown4 = data['region_unknown4']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
@@ -77,9 +77,9 @@ class Region:
|
||||
data['region_has_stairs'] = self.region_has_stairs
|
||||
if self.region_has_stairs:
|
||||
data['region_stairs'] = self.region_stairs
|
||||
data['region_unkown2'] = self.region_unkown2
|
||||
data['region_unkown3'] = self.region_unkown3
|
||||
data['region_unkown4'] = self.region_unkown4
|
||||
data['region_unknown2'] = self.region_unknown2
|
||||
data['region_unknown3'] = self.region_unknown3
|
||||
data['region_unknown4'] = self.region_unknown4
|
||||
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
|
||||
+1
@@ -5,6 +5,7 @@
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.enums.hashes import hash_to_string, string_to_hash
|
||||
+1
@@ -5,6 +5,7 @@
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.enums.hashes import hash_to_string, string_to_hash
|
||||
@@ -0,0 +1,41 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.enums.hashes import hash_to_string, string_to_hash
|
||||
from arcane.util import ResStream
|
||||
|
||||
|
||||
class DiscRequired:
|
||||
def load_binary(self, stream: ResStream):
|
||||
discs = stream.read_dword()
|
||||
self.disc_restrict = stream.read_bool()
|
||||
self.disc_values = [
|
||||
stream.read_dword() for _ in range(discs)
|
||||
]
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(len(self.disc_values))
|
||||
stream.write_bool(self.disc_restrict)
|
||||
for disc in self.disc_values:
|
||||
stream.write_dword(disc)
|
||||
|
||||
def load_json(self, data):
|
||||
self.disc_restrict = data['restrict']
|
||||
self.disc_values = []
|
||||
for disc in data['discs']:
|
||||
self.disc_values.append(string_to_hash(disc))
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['restrict'] = self.disc_restrict
|
||||
data['discs'] = []
|
||||
for disc in self.disc_values:
|
||||
data['discs'].append(hash_to_string(disc))
|
||||
return data
|
||||
+1
@@ -5,6 +5,7 @@
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.enums.common.arc_inventory import *
|
||||
@@ -0,0 +1,41 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.enums.hashes import hash_to_string, string_to_hash
|
||||
from arcane.util import ResStream
|
||||
|
||||
|
||||
class RaceRequired:
|
||||
def load_binary(self, stream: ResStream):
|
||||
races = stream.read_dword()
|
||||
self.race_restrict = stream.read_bool()
|
||||
self.race_values = [
|
||||
stream.read_dword() for _ in range(races)
|
||||
]
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(len(self.race_values))
|
||||
stream.write_bool(self.race_restrict)
|
||||
for race in self.race_values:
|
||||
stream.write_dword(race)
|
||||
|
||||
def load_json(self, data):
|
||||
self.race_restrict = data['restrict']
|
||||
self.race_values = []
|
||||
for race in data['races']:
|
||||
self.race_values.append(string_to_hash(race))
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['restrict'] = self.race_restrict
|
||||
data['races'] = []
|
||||
for race in self.race_values:
|
||||
data['races'].append(hash_to_string(race))
|
||||
return data
|
||||
+1
@@ -5,6 +5,7 @@
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.enums.arc_sparse import *
|
||||
@@ -0,0 +1,7 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
@@ -18,6 +18,14 @@ class ResStream:
|
||||
data = self.buffer.read(1)
|
||||
return struct.unpack('<B', data)[0]
|
||||
|
||||
def read_bytes(self, n):
|
||||
data = self.buffer.read(n)
|
||||
return data
|
||||
|
||||
def read_word(self):
|
||||
data = self.buffer.read(2)
|
||||
return struct.unpack('<H', data)[0]
|
||||
|
||||
def read_dword(self):
|
||||
data = self.buffer.read(4)
|
||||
return struct.unpack('<I', data)[0]
|
||||
@@ -52,6 +60,14 @@ class ResStream:
|
||||
data = struct.pack('<B', value)
|
||||
self.buffer.write(data)
|
||||
|
||||
def write_bytes(self, value):
|
||||
data = value
|
||||
self.buffer.write(data)
|
||||
|
||||
def write_word(self, value):
|
||||
data = struct.pack('<H', value)
|
||||
self.buffer.write(data)
|
||||
|
||||
def write_dword(self, value):
|
||||
data = struct.pack('<I', value)
|
||||
self.buffer.write(data)
|
||||
@@ -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']
|
||||
@@ -41,7 +41,7 @@ class ArcZone:
|
||||
self.zone_min_blend = stream.read_float()
|
||||
self.zone_max_blend = stream.read_float()
|
||||
self.zone_influence = stream.read_float()
|
||||
self.zone_unkown1 = stream.read_float()
|
||||
self.zone_unknown1 = stream.read_float()
|
||||
self.zone_y_offset = stream.read_float()
|
||||
self.zone_global_height = stream.read_float()
|
||||
self.zone_transition_height = stream.read_float()
|
||||
@@ -154,7 +154,7 @@ class ArcZone:
|
||||
stream.write_float(self.zone_min_blend)
|
||||
stream.write_float(self.zone_max_blend)
|
||||
stream.write_float(self.zone_influence)
|
||||
stream.write_float(self.zone_unkown1)
|
||||
stream.write_float(self.zone_unknown1)
|
||||
stream.write_float(self.zone_y_offset)
|
||||
stream.write_float(self.zone_global_height)
|
||||
stream.write_float(self.zone_transition_height)
|
||||
@@ -255,7 +255,7 @@ class ArcZone:
|
||||
data['zone_min_blend'] = self.zone_min_blend
|
||||
data['zone_max_blend'] = self.zone_max_blend
|
||||
data['zone_influence'] = self.zone_influence
|
||||
data['zone_unkown1'] = self.zone_unkown1
|
||||
data['zone_unknown1'] = self.zone_unknown1
|
||||
data['zone_y_offset'] = self.zone_y_offset
|
||||
data['zone_global_height'] = self.zone_global_height
|
||||
data['zone_transition_height'] = self.zone_transition_height
|
||||
@@ -330,7 +330,7 @@ class ArcZone:
|
||||
self.zone_min_blend = data['zone_min_blend']
|
||||
self.zone_max_blend = data['zone_max_blend']
|
||||
self.zone_influence = data['zone_influence']
|
||||
self.zone_unkown1 = data['zone_unkown1']
|
||||
self.zone_unknown1 = data['zone_unknown1']
|
||||
self.zone_y_offset = data['zone_y_offset']
|
||||
self.zone_global_height = data['zone_global_height']
|
||||
self.zone_transition_height = data['zone_transition_height']
|
||||
+4
-4
@@ -14,7 +14,7 @@ class ArcZTriggerAction:
|
||||
self.zone_trigger_action_type = stream.read_dword()
|
||||
self.zone_trigger_action_unknown1 = stream.read_bool()
|
||||
self.zone_trigger_action_is_timed = stream.read_bool()
|
||||
self.zone_trigger_action_unkown2 = stream.read_bool()
|
||||
self.zone_trigger_action_unknown2 = stream.read_bool()
|
||||
|
||||
if self.zone_trigger_action_is_timed:
|
||||
self.zone_trigger_action_time_begin = stream.read_float()
|
||||
@@ -36,11 +36,11 @@ class ArcZoneEventInfo:
|
||||
self.zone_event_spawn_radius = stream.read_float()
|
||||
self.zone_event_fc_label = stream.read_string()
|
||||
self.zone_event_event_name = stream.read_string()
|
||||
self.zone_event_unkown1 = stream.read_dword()
|
||||
self.zone_event_unknown1 = stream.read_dword()
|
||||
self.zone_event_spawn_location = stream.read_tuple()
|
||||
self.zone_event_parent_name = stream.read_string()
|
||||
self.zone_event_unkown2 = stream.read_dword()
|
||||
self.zone_event_unkown3 = stream.read_bool()
|
||||
self.zone_event_unknown2 = stream.read_dword()
|
||||
self.zone_event_unknown3 = stream.read_bool()
|
||||
num_triggers = stream.read_dword()
|
||||
self.zone_event_triggers = [ArcZTriggerAction() for _ in range(num_triggers)]
|
||||
for action in self.zone_event_triggers:
|
||||
+4
-4
@@ -26,7 +26,7 @@ class TerrainObjectInfo:
|
||||
self.terrain_object_max_slope = stream.read_float()
|
||||
self.terrain_object_max_pop = stream.read_dword()
|
||||
self.terrain_object_is_fractal_pop = stream.read_bool()
|
||||
self.terrain_object_unkown1 = stream.read_dword()
|
||||
self.terrain_object_unknown1 = stream.read_dword()
|
||||
self.terrain_object_y_offset = stream.read_float()
|
||||
self.terrain_object_pop_image_id = stream.read_qword()
|
||||
self.terrain_object_image_min_y = stream.read_float()
|
||||
@@ -45,7 +45,7 @@ class TerrainObjectInfo:
|
||||
stream.write_float(self.terrain_object_max_slope)
|
||||
stream.write_dword(self.terrain_object_max_pop)
|
||||
stream.write_bool(self.terrain_object_is_fractal_pop)
|
||||
stream.write_dword(self.terrain_object_unkown1)
|
||||
stream.write_dword(self.terrain_object_unknown1)
|
||||
stream.write_float(self.terrain_object_y_offset)
|
||||
stream.write_qword(self.terrain_object_pop_image_id)
|
||||
stream.write_float(self.terrain_object_image_min_y)
|
||||
@@ -65,7 +65,7 @@ class TerrainObjectInfo:
|
||||
data['terrain_object_max_slope'] = self.terrain_object_max_slope
|
||||
data['terrain_object_max_pop'] = self.terrain_object_max_pop
|
||||
data['terrain_object_is_fractal_pop'] = self.terrain_object_is_fractal_pop
|
||||
data['terrain_object_unkown1'] = self.terrain_object_unkown1
|
||||
data['terrain_object_unknown1'] = self.terrain_object_unknown1
|
||||
data['terrain_object_y_offset'] = self.terrain_object_y_offset
|
||||
data['terrain_object_pop_image_id'] = self.terrain_object_pop_image_id
|
||||
data['terrain_object_image_min_y'] = self.terrain_object_image_min_y
|
||||
@@ -85,7 +85,7 @@ class TerrainObjectInfo:
|
||||
self.terrain_object_max_slope = data['terrain_object_max_slope']
|
||||
self.terrain_object_max_pop = data['terrain_object_max_pop']
|
||||
self.terrain_object_is_fractal_pop = data['terrain_object_is_fractal_pop']
|
||||
self.terrain_object_unkown1 = data['terrain_object_unkown1']
|
||||
self.terrain_object_unknown1 = data['terrain_object_unknown1']
|
||||
self.terrain_object_y_offset = data['terrain_object_y_offset']
|
||||
self.terrain_object_pop_image_id = data['terrain_object_pop_image_id']
|
||||
self.terrain_object_image_min_y = data['terrain_object_image_min_y']
|
||||
@@ -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
Reference in New Issue
Block a user