Browse Source

mbEditorPro2.0 release

master
MagicBot 2 years ago
parent
commit
942b33a252
  1. 69
      README.md
  2. 7
      mbEditorPro/arcane/__init__.py
  3. 7
      mbEditorPro/arcane/enums/__init__.py
  4. 7
      mbEditorPro/arcane/enums/common/__init__.py
  5. 23
      mbEditorPro/arcane/enums/common/arc_inventory.py
  6. 41
      mbEditorPro/arcane/enums/hashes/__init__.py
  7. 38
      mbEditorPro/arcane/enums/zone/arc_mobile.py
  8. 23
      mbEditorPro/arcane/enums/zone/arc_prop.py
  9. 35
      mbEditorPro/arcane/enums/zone/arc_terraingen.py
  10. 62
      mbEditorPro/arcane/enums/zone/arc_zone.py
  11. 29
      mbEditorPro/arcane/objects/ArcAssetStructureObject.py
  12. 21
      mbEditorPro/arcane/objects/__init__.py
  13. 40
      mbEditorPro/arcane/objects/common/Discipline.py
  14. 40
      mbEditorPro/arcane/objects/common/Race.py
  15. 7
      mbEditorPro/arcane/objects/common/__init__.py
  16. 10
      mbEditorPro/arcane/util/__init__.py
  17. 39
      mbEditorPro/arcane/zones/ArcDungeonInfo.py
  18. 9
      mbEditorPro/arcane/zones/__init__.py
  19. 20
      mbEditorPro/arcane/zones/mobile/MinionInfo.py
  20. 7
      mbEditorPro/arcane/zones/mobile/__init__.py
  21. 223
      mbEditorPro/mbEditorPro.py
  22. 0
      mbEditorPro2.0/LICENSE
  23. 19
      mbEditorPro2.0/README.md
  24. 70
      mbEditorPro2.0/arcane/ArcImage.py
  25. 113
      mbEditorPro2.0/arcane/ArcMesh.py
  26. 89
      mbEditorPro2.0/arcane/ArcMotion.py
  27. 644
      mbEditorPro2.0/arcane/ArcRender.py
  28. 125
      mbEditorPro2.0/arcane/ArcSkeleton.py
  29. 40
      mbEditorPro2.0/arcane/ArcSound.py
  30. 242
      mbEditorPro2.0/arcane/ArcTile.py
  31. 396
      mbEditorPro2.0/arcane/ArcVisual.py
  32. 7
      mbEditorPro2.0/arcane/__init__.py
  33. 7
      mbEditorPro2.0/arcane/enums/__init__.py
  34. 6
      mbEditorPro2.0/arcane/enums/arc_combat.py
  35. 0
      mbEditorPro2.0/arcane/enums/arc_door.py
  36. 12
      mbEditorPro2.0/arcane/enums/arc_item.py
  37. 0
      mbEditorPro2.0/arcane/enums/arc_object.py
  38. 0
      mbEditorPro2.0/arcane/enums/arc_rune.py
  39. 0
      mbEditorPro2.0/arcane/enums/arc_sparse.py
  40. 0
      mbEditorPro2.0/arcane/enums/arc_structure.py
  41. 7
      mbEditorPro2.0/arcane/enums/common/__init__.py
  42. 23
      mbEditorPro2.0/arcane/enums/common/arc_inventory.py
  43. 41
      mbEditorPro2.0/arcane/enums/hashes/__init__.py
  44. 0
      mbEditorPro2.0/arcane/enums/hashes/attrs.txt
  45. 0
      mbEditorPro2.0/arcane/enums/hashes/classes.txt
  46. 0
      mbEditorPro2.0/arcane/enums/hashes/discipline.txt
  47. 0
      mbEditorPro2.0/arcane/enums/hashes/effects.txt
  48. 0
      mbEditorPro2.0/arcane/enums/hashes/environment.txt
  49. 0
      mbEditorPro2.0/arcane/enums/hashes/poweractions.txt
  50. 0
      mbEditorPro2.0/arcane/enums/hashes/powers.txt
  51. 0
      mbEditorPro2.0/arcane/enums/hashes/races.txt
  52. 0
      mbEditorPro2.0/arcane/enums/hashes/resources.txt
  53. 0
      mbEditorPro2.0/arcane/enums/hashes/skills.txt
  54. 0
      mbEditorPro2.0/arcane/enums/hashes/soundtables.txt
  55. 0
      mbEditorPro2.0/arcane/enums/hashes/talents.txt
  56. 0
      mbEditorPro2.0/arcane/enums/hashes/weather.txt
  57. 38
      mbEditorPro2.0/arcane/enums/zone/arc_mobile.py
  58. 23
      mbEditorPro2.0/arcane/enums/zone/arc_prop.py
  59. 35
      mbEditorPro2.0/arcane/enums/zone/arc_terraingen.py
  60. 62
      mbEditorPro2.0/arcane/enums/zone/arc_zone.py
  61. 0
      mbEditorPro2.0/arcane/enums/zone/arc_zone_goal.py
  62. 29
      mbEditorPro2.0/arcane/objects/ArcAssetStructureObject.py
  63. 28
      mbEditorPro2.0/arcane/objects/ArcCityAssetTemplate.py
  64. 0
      mbEditorPro2.0/arcane/objects/ArcCombatObj.py
  65. 1
      mbEditorPro2.0/arcane/objects/ArcContainerObject.py
  66. 0
      mbEditorPro2.0/arcane/objects/ArcDeed.py
  67. 0
      mbEditorPro2.0/arcane/objects/ArcDoorObject.py
  68. 0
      mbEditorPro2.0/arcane/objects/ArcDungeonUnitObject.py
  69. 0
      mbEditorPro2.0/arcane/objects/ArcItem.py
  70. 0
      mbEditorPro2.0/arcane/objects/ArcKey.py
  71. 0
      mbEditorPro2.0/arcane/objects/ArcObj.py
  72. 0
      mbEditorPro2.0/arcane/objects/ArcRune.py
  73. 0
      mbEditorPro2.0/arcane/objects/ArcStaticObject.py
  74. 24
      mbEditorPro2.0/arcane/objects/ArcStructureObject.py
  75. 21
      mbEditorPro2.0/arcane/objects/__init__.py
  76. 1
      mbEditorPro2.0/arcane/objects/common/Arcane.py
  77. 1
      mbEditorPro2.0/arcane/objects/common/Class.py
  78. 41
      mbEditorPro2.0/arcane/objects/common/Discipline.py
  79. 1
      mbEditorPro2.0/arcane/objects/common/Inventory.py
  80. 41
      mbEditorPro2.0/arcane/objects/common/Race.py
  81. 1
      mbEditorPro2.0/arcane/objects/common/SparseData.py
  82. 7
      mbEditorPro2.0/arcane/objects/common/__init__.py
  83. 0
      mbEditorPro2.0/arcane/util/ArcFileCache.py
  84. 16
      mbEditorPro2.0/arcane/util/ResStream.py
  85. 10
      mbEditorPro2.0/arcane/util/__init__.py
  86. 0
      mbEditorPro2.0/arcane/util/hasher.py
  87. 19
      mbEditorPro2.0/arcane/util/int32utils.py
  88. 39
      mbEditorPro2.0/arcane/zones/ArcDungeonInfo.py
  89. 0
      mbEditorPro2.0/arcane/zones/ArcMobile.py
  90. 0
      mbEditorPro2.0/arcane/zones/ArcProp.py
  91. 0
      mbEditorPro2.0/arcane/zones/ArcSoundInfo.py
  92. 0
      mbEditorPro2.0/arcane/zones/ArcTerrainGen.py
  93. 8
      mbEditorPro2.0/arcane/zones/ArcZone.py
  94. 0
      mbEditorPro2.0/arcane/zones/ArcZoneBiomState.py
  95. 8
      mbEditorPro2.0/arcane/zones/ArcZoneEvent.py
  96. 0
      mbEditorPro2.0/arcane/zones/ArcZoneGoal.py
  97. 8
      mbEditorPro2.0/arcane/zones/TerrainObjectInfo.py
  98. 0
      mbEditorPro2.0/arcane/zones/WaterInfo.py
  99. 0
      mbEditorPro2.0/arcane/zones/WeatherEventInfo.py
  100. 9
      mbEditorPro2.0/arcane/zones/__init__.py
  101. Some files were not shown because too many files have changed in this diff Show More

69
README.md

@ -1,12 +1,65 @@
``` ```
• ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
Magicbane Emulator Project © 2013 - 2022 Magicbane Emulator Project © 2013 - 2022
www.magicbane.com www.magicbane.com
``` ```
This repository holds the source code for mbEditorPro along with other tooling and data required to give every MagicBox administrator the ability to fully modify the game as they see fit. # mbEditorPro v 2.0
![Example Output](https://cdn.discordapp.com/attachments/399623779531096074/1029063849640468550/unknown.png)
Team Magicbane presents to the community technology allowing MagicBox administrators<br>
to fully modify their game using nothing more than notepad.exe. <br>
- Tool directly converts Shadowbane .cache files to and from a high fidelity pure JSON representation.
- Enumerations are used throughout hiding from the user ugly signed ulong values.
- Written in Python and open-source allowing modification and extension with ease.
- Want to raise all weapon damage by x%; Just modify item values as they are being parsed!
The tool built with Edltirch Technologies parses all Shadowbane .cache files giving the user complete control over the game<br>
Team Magicbane aims to deliver you the best crackhead free MMO technology around; all for free!
### Usage:
```
mbEditorPro.py unpack cobjects
mbEditorPro.py unpack all
```
JSON output will be in a folder **ARCANE DUMP** <br>
```
mbEditorPro.py pack textures
mbEditorPro.py pack all
```
New binary cache file will be built from the JSON and output in the current directory. <br>>
> note: Unpacked data from a 2008 cache file is available in the Data repo. Build a new cache file right out of the box.
### Limitations
Hirelings, ZoneEvents and Mobile Inventory are not parsed or written as there were no <br>
examples in the .cache files to begin with. The game does seem to support them, however.
### JSON
The tool generating pure JSON has the following benefits:
- It's ubiquitous and the tooling is mature. The standard interop exchange format.
- Human and machine-readable.
- Ease of importing into MySQL or other databases.
- Use as an intermediate representation to build a GUI World Editor or FBX importer.
### Future
mbEditorPro will be the cornerstone of Magicbane's data project. The Team's goal is threefold:
- Ship MagicBox 1.5 with both Aerynth and Vorringia mapsets available.
- Integrate Magicbane's wpak extractor technology into the tool<br>

7
mbEditorPro/arcane/__init__.py

@ -1,7 +0,0 @@
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
# Magicbane Emulator Project © 2013 - 2022
# www.magicbane.com

7
mbEditorPro/arcane/enums/__init__.py

@ -1,7 +0,0 @@
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
# Magicbane Emulator Project © 2013 - 2022
# www.magicbane.com

7
mbEditorPro/arcane/enums/common/__init__.py

@ -1,7 +0,0 @@
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
# Magicbane Emulator Project © 2013 - 2022
# www.magicbane.com

23
mbEditorPro/arcane/enums/common/arc_inventory.py

@ -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,
}

41
mbEditorPro/arcane/enums/hashes/__init__.py

@ -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()

38
mbEditorPro/arcane/enums/zone/arc_mobile.py

@ -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,
}

23
mbEditorPro/arcane/enums/zone/arc_prop.py

@ -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,
}

35
mbEditorPro/arcane/enums/zone/arc_terraingen.py

@ -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,
}

62
mbEditorPro/arcane/enums/zone/arc_zone.py

@ -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,
}

29
mbEditorPro/arcane/objects/ArcAssetStructureObject.py

@ -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

21
mbEditorPro/arcane/objects/__init__.py

@ -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

40
mbEditorPro/arcane/objects/common/Discipline.py

@ -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

40
mbEditorPro/arcane/objects/common/Race.py

@ -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

7
mbEditorPro/arcane/objects/common/__init__.py

@ -1,7 +0,0 @@
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
# Magicbane Emulator Project © 2013 - 2022
# www.magicbane.com

10
mbEditorPro/arcane/util/__init__.py

@ -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

39
mbEditorPro/arcane/zones/ArcDungeonInfo.py

@ -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']

9
mbEditorPro/arcane/zones/__init__.py

@ -1,9 +0,0 @@
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
# Magicbane Emulator Project © 2013 - 2022
# www.magicbane.com
from .ArcZone import ArcZone

20
mbEditorPro/arcane/zones/mobile/MinionInfo.py

@ -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()

7
mbEditorPro/arcane/zones/mobile/__init__.py

@ -1,7 +0,0 @@
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
# Magicbane Emulator Project © 2013 - 2022
# www.magicbane.com

223
mbEditorPro/mbEditorPro.py

@ -1,223 +0,0 @@
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
# Magicbane Emulator Project © 2013 - 2022
# www.magicbane.com
import glob
import json
import os
import sys
from arcane.enums.arc_object import *
from arcane.objects import *
from arcane.util import *
from arcane.zones import *
DUMP_DIRECTORY = 'ARCANE_DUMP'
WORKING_DIRECTORY = os.path.dirname(__file__)
TARGET_DIRECTORY = os.path.join(WORKING_DIRECTORY, DUMP_DIRECTORY)
COBJECTS_DIRECTORY = os.path.join(TARGET_DIRECTORY, 'COBJECTS')
CZONE_DIRECTORY = os.path.join(TARGET_DIRECTORY, 'CZONE')
COBJECTS_MAGIC = 0x434c4e54
COBJECTS_MAP = {
OBJECT_TYPE_LIGHT: ArcObj,
OBJECT_TYPE_DOOR: ArcDoorObject,
OBJECT_TYPE_STATIC: ArcStaticObject,
OBJECT_TYPE_STRUCTURE: ArcStructureObject,
OBJECT_TYPE_ASSETSTRUCTURE: ArcAssetStructureObject,
OBJECT_TYPE_DUNGEONUNIT: ArcDungeonUnitObject,
OBJECT_TYPE_DUNGEONEXIT: ArcDungeonExitObject,
OBJECT_TYPE_DUNGEONSTAIR: ArcDungeonStairObject,
OBJECT_TYPE_ITEM: ArcItem,
OBJECT_TYPE_PLAYER: ArcCharacter,
OBJECT_TYPE_MOBILE: ArcCharacter,
OBJECT_TYPE_RUNE: ArcRune,
OBJECT_TYPE_CONTAINER: ArcContainerObject,
OBJECT_TYPE_DEED: ArcDeed,
OBJECT_TYPE_KEY: ArcKey,
OBJECT_TYPE_ASSET: ArcCityAssetTemplate,
OBJECT_TYPE_OBJECT: ArcObj,
}
def init_cobjects():
for type in COBJECTS_MAP:
directory_path = os.path.join(COBJECTS_DIRECTORY, OBJECT_TYPE_TO_STRING[type])
os.makedirs(directory_path, exist_ok=True)
def init_czones():
directory_path = CZONE_DIRECTORY
os.makedirs(directory_path, exist_ok=True)
def unpack_cobjects():
init_cobjects()
resources = load_cache_file('CObjects.cache')
for res_id, data in resources:
in_stream = ResStream(data)
magic = in_stream.read_dword()
obj_type = in_stream.read_dword()
arc_object = COBJECTS_MAP[obj_type]()
filepath = os.path.join(
COBJECTS_DIRECTORY,
OBJECT_TYPE_TO_STRING[obj_type],
f'{res_id:020d}.json'
)
arc_object.load_binary(in_stream)
parsed = arc_object.save_json()
with open(filepath, 'w') as fp:
json.dump(parsed, fp, indent=2)
def pack_cobjects():
init_cobjects()
resources = []
for obj_type in COBJECTS_MAP:
directory = os.path.join(
COBJECTS_DIRECTORY,
OBJECT_TYPE_TO_STRING[obj_type]
)
for filepath in glob.glob(os.path.join(directory, '*.json')):
filename = os.path.basename(filepath)
res_id = int(filename.split('.json')[0])
json_data = json.load(open(filepath))
out_stream = ResStream()
out_stream.write_dword(COBJECTS_MAGIC)
out_stream.write_dword(obj_type)
arc_object = COBJECTS_MAP[obj_type]()
try:
arc_object.load_json(json_data)
arc_object.save_binary(out_stream)
except:
print(res_id)
raise
resources.append([res_id, out_stream.get_bytes()])
save_cache_file('CObjects.cache.new', resources)
def test_cobjects():
resources = load_cache_file('CObjects.cache')
for res_id, data in resources:
in_stream = ResStream(data)
out_stream = ResStream()
magic = in_stream.read_dword()
o_type = in_stream.read_dword()
out_stream.write_dword(magic)
out_stream.write_dword(o_type)
arc_in = COBJECTS_MAP[o_type]()
arc_out = COBJECTS_MAP[o_type]()
arc_in.load_binary(in_stream)
parsed = arc_in.save_json()
arc_out.load_json(parsed)
arc_out.save_binary(out_stream)
try:
assert in_stream.get_bytes() == out_stream.get_bytes()
except:
print(res_id, in_stream.buffer.tell(), out_stream.buffer.tell())
print()
def unpack_czones():
init_czones()
resources = load_cache_file('CZone.cache')
for res_id, data in resources:
arc_zone = ArcZone()
in_stream = ResStream(data)
filepath = os.path.join(
CZONE_DIRECTORY,
f'{res_id:020d}.json'
)
arc_zone.load_binary(in_stream)
parsed = arc_zone.save_json()
with open(filepath, 'w') as fp:
json.dump(parsed, fp, indent=2)
def pack_czones():
init_czones()
resources = []
directory = CZONE_DIRECTORY
for filepath in glob.glob(os.path.join(directory, '*.json')):
filename = os.path.basename(filepath)
res_id = int(filename.split('.json')[0])
json_data = json.load(open(filepath))
out_stream = ResStream()
arc_object = ArcZone()
try:
arc_object.load_json(json_data)
arc_object.save_binary(out_stream)
except:
print(res_id)
raise
resources.append([res_id, out_stream.get_bytes()])
save_cache_file('CZone.cache.new', resources)
def test_czones():
resources = load_cache_file('CZone.cache')
for res_id, data in resources:
in_stream = ResStream(data)
out_stream = ResStream()
arc_in = ArcZone()
arc_out = ArcZone()
arc_in.load_binary(in_stream)
parsed = arc_in.save_json()
arc_out.load_json(parsed)
arc_out.save_binary(out_stream)
try:
assert in_stream.get_bytes() == out_stream.get_bytes()
except:
print(res_id, in_stream.buffer.tell(), out_stream.buffer.tell())
print()
def usage():
print('mbEditorPro commands:')
print('usage: {} unpack cobjects'.format(sys.argv[0]))
print('usage: {} pack cobjects'.format(sys.argv[0]))
print('usage: {} unpack czones'.format(sys.argv[0]))
print('usage: {} pack czones'.format(sys.argv[0]))
exit(1)
def main():
if not sys.argv[2:]:
usage()
if sys.argv[1] not in ['pack', 'unpack']:
usage()
if sys.argv[2] not in ['cobjects', 'czones']:
usage()
method = '_'.join(sys.argv[1:3]) + '()'
print(method)
exec(method)
main()

0
mbEditorPro/LICENSE → mbEditorPro2.0/LICENSE

19
mbEditorPro/README.md → mbEditorPro2.0/README.md

@ -8,34 +8,32 @@
www.magicbane.com www.magicbane.com
``` ```
# mbEditorPro v 1.0 # mbEditorPro v 2.0
![Example Output](https://cdn.discordapp.com/attachments/399623779531096074/1029063849640468550/unknown.png) ![Example Output](https://cdn.discordapp.com/attachments/399623779531096074/1029063849640468550/unknown.png)
Team Magicbane presents to the community technology allowing MagicBox administrators<br> Team Magicbane presents to the community technology allowing MagicBox administrators<br>
to fully modify their game using nothing more than notepad.exe. <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. - Enumerations are used throughout hiding from the user ugly signed ulong values.
- Written in Python and open-source allowing modification and extension with ease. - 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! - 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> The tool built with Edltirch Technologies parses all Shadowbane .cache files giving the user complete control over the game<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>
Team Magicbane aims to deliver you the best crackhead free MMO technology around; all for free! Team Magicbane aims to deliver you the best crackhead free MMO technology around; all for free!
### Usage: ### Usage:
``` ```
mbEditorPro.py unpack cobjects mbEditorPro.py unpack cobjects
mbEditorPro.py unpack czones mbEditorPro.py unpack all
``` ```
JSON output will be in a folder **ARCANE DUMP** <br> JSON output will be in a folder **ARCANE DUMP** <br>
``` ```
mbEditorPro.py pack cobjects mbEditorPro.py pack textures
mbEditorPro.py pack czones mbEditorPro.py pack all
``` ```
New binary cache file will be built from the JSON and output in the current directory. <br>> 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: 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. - Ship MagicBox 1.5 with both Aerynth and Vorringia mapsets available.
- Build up the tool and technology to parse the remaining .cache file. - Integrate Magicbane's wpak extractor technology into the tool<br>
- Ship MagicBox 1.5 with both Aerynth and Vorringia mapsets available.<br>

70
mbEditorPro2.0/arcane/ArcImage.py

@ -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()}

113
mbEditorPro2.0/arcane/ArcMesh.py

@ -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

89
mbEditorPro2.0/arcane/ArcMotion.py

@ -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

644
mbEditorPro2.0/arcane/ArcRender.py

@ -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

125
mbEditorPro2.0/arcane/ArcSkeleton.py

@ -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

40
mbEditorPro2.0/arcane/ArcSound.py

@ -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)

242
mbEditorPro2.0/arcane/ArcTile.py

@ -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

396
mbEditorPro2.0/arcane/ArcVisual.py

@ -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

7
mbEditorPro2.0/arcane/__init__.py

@ -0,0 +1,7 @@
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
# Magicbane Emulator Project © 2013 - 2022
# www.magicbane.com

7
mbEditorPro2.0/arcane/enums/__init__.py

@ -0,0 +1,7 @@
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
# Magicbane Emulator Project © 2013 - 2022
# www.magicbane.com

6
mbEditorPro/arcane/enums/arc_combat.py → mbEditorPro2.0/arcane/enums/arc_combat.py

@ -6,7 +6,7 @@
# Magicbane Emulator Project © 2013 - 2022 # Magicbane Emulator Project © 2013 - 2022
# www.magicbane.com # www.magicbane.com
ATTACK_RESIST_UNKOWN = 0 ATTACK_RESIST_UNKNOWN = 0
ATTACK_RESIST_SLASHING = 1 ATTACK_RESIST_SLASHING = 1
ATTACK_RESIST_CRUSHING = 2 ATTACK_RESIST_CRUSHING = 2
ATTACK_RESIST_PIERCING = 3 ATTACK_RESIST_PIERCING = 3
@ -24,7 +24,7 @@ ATTACK_RESIST_UNHOLY = 14
ATTACK_RESIST_ANTISIEGE = 15 ATTACK_RESIST_ANTISIEGE = 15
ATTACK_RESIST_TO_STRING = { ATTACK_RESIST_TO_STRING = {
ATTACK_RESIST_UNKOWN: 'UNKOWN', ATTACK_RESIST_UNKNOWN: 'UNKNOWN',
ATTACK_RESIST_SLASHING: 'SLASHING', ATTACK_RESIST_SLASHING: 'SLASHING',
ATTACK_RESIST_CRUSHING: 'CRUSHING', ATTACK_RESIST_CRUSHING: 'CRUSHING',
ATTACK_RESIST_PIERCING: 'PIERCING', ATTACK_RESIST_PIERCING: 'PIERCING',
@ -43,7 +43,7 @@ ATTACK_RESIST_TO_STRING = {
} }
STRING_TO_ATTACK_RESIST = { STRING_TO_ATTACK_RESIST = {
'UNKOWN': ATTACK_RESIST_UNKOWN, 'UNKNOWN': ATTACK_RESIST_UNKNOWN,
'SLASHING': ATTACK_RESIST_SLASHING, 'SLASHING': ATTACK_RESIST_SLASHING,
'CRUSHING': ATTACK_RESIST_CRUSHING, 'CRUSHING': ATTACK_RESIST_CRUSHING,
'PIERCING': ATTACK_RESIST_PIERCING, 'PIERCING': ATTACK_RESIST_PIERCING,

0
mbEditorPro/arcane/enums/arc_door.py → mbEditorPro2.0/arcane/enums/arc_door.py

12
mbEditorPro/arcane/enums/arc_item.py → mbEditorPro2.0/arcane/enums/arc_item.py

@ -241,26 +241,26 @@ STRING_TO_ITEM_USE_FLAGS = {
'EMPTY_NEWITEM': ITEM_USE_FLAGS_EMPTY_NEWITEM, 'EMPTY_NEWITEM': ITEM_USE_FLAGS_EMPTY_NEWITEM,
} }
ITEM_SHEATHSLOT_UNKOWN = 0 ITEM_SHEATHSLOT_UNKNOWN = 0
ITEM_SHEATHSLOT_BACK = 1 ITEM_SHEATHSLOT_BACK = 1
ITEM_SHEATHSLOT_WAIST = 2 ITEM_SHEATHSLOT_WAIST = 2
ITEM_SHEATHSLOT_NONE = 4 ITEM_SHEATHSLOT_NONE = 4
ITEM_SHEATHSLOT_TO_STRING = { ITEM_SHEATHSLOT_TO_STRING = {
ITEM_SHEATHSLOT_NONE: 'NONE', ITEM_SHEATHSLOT_NONE: 'NONE',
ITEM_SHEATHSLOT_UNKOWN: 'UNKOWN', ITEM_SHEATHSLOT_UNKNOWN: 'UNKNOWN',
ITEM_SHEATHSLOT_BACK: 'BACK', ITEM_SHEATHSLOT_BACK: 'BACK',
ITEM_SHEATHSLOT_WAIST: 'WAIST', ITEM_SHEATHSLOT_WAIST: 'WAIST',
} }
STRING_TO_ITEM_SHEATHSLOT = { STRING_TO_ITEM_SHEATHSLOT = {
'NONE': ITEM_SHEATHSLOT_NONE, 'NONE': ITEM_SHEATHSLOT_NONE,
'UNKOWN': ITEM_SHEATHSLOT_UNKOWN, 'UNKNOWN': ITEM_SHEATHSLOT_UNKNOWN,
'BACK': ITEM_SHEATHSLOT_BACK, 'BACK': ITEM_SHEATHSLOT_BACK,
'WAIST': ITEM_SHEATHSLOT_WAIST, 'WAIST': ITEM_SHEATHSLOT_WAIST,
} }
DAMAGE_UNKOWN = 0 DAMAGE_UNKNOWN = 0
DAMAGE_SLASHING = 1 DAMAGE_SLASHING = 1
DAMAGE_CRUSHING = 2 DAMAGE_CRUSHING = 2
DAMAGE_PIERCING = 3 DAMAGE_PIERCING = 3
@ -278,7 +278,7 @@ DAMAGE_UNHOLY = 14
DAMAGE_ANTISIEGE = 15 DAMAGE_ANTISIEGE = 15
DAMAGE_TO_STRING = { DAMAGE_TO_STRING = {
DAMAGE_UNKOWN: 'UNKOWN', DAMAGE_UNKNOWN: 'UNKNOWN',
DAMAGE_SLASHING: 'SLASHING', DAMAGE_SLASHING: 'SLASHING',
DAMAGE_CRUSHING: 'CRUSHING', DAMAGE_CRUSHING: 'CRUSHING',
DAMAGE_PIERCING: 'PIERCING', DAMAGE_PIERCING: 'PIERCING',
@ -297,7 +297,7 @@ DAMAGE_TO_STRING = {
} }
STRING_TO_DAMAGE = { STRING_TO_DAMAGE = {
'UNKOWN': DAMAGE_UNKOWN, 'UNKNOWN': DAMAGE_UNKNOWN,
'SLASHING': DAMAGE_SLASHING, 'SLASHING': DAMAGE_SLASHING,
'CRUSHING': DAMAGE_CRUSHING, 'CRUSHING': DAMAGE_CRUSHING,
'PIERCING': DAMAGE_PIERCING, 'PIERCING': DAMAGE_PIERCING,

0
mbEditorPro/arcane/enums/arc_object.py → mbEditorPro2.0/arcane/enums/arc_object.py

0
mbEditorPro/arcane/enums/arc_rune.py → mbEditorPro2.0/arcane/enums/arc_rune.py

0
mbEditorPro/arcane/enums/arc_sparse.py → mbEditorPro2.0/arcane/enums/arc_sparse.py

0
mbEditorPro/arcane/enums/arc_structure.py → mbEditorPro2.0/arcane/enums/arc_structure.py

7
mbEditorPro2.0/arcane/enums/common/__init__.py

@ -0,0 +1,7 @@
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
# Magicbane Emulator Project © 2013 - 2022
# www.magicbane.com

23
mbEditorPro2.0/arcane/enums/common/arc_inventory.py

@ -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,
}

41
mbEditorPro2.0/arcane/enums/hashes/__init__.py

@ -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
mbEditorPro/arcane/enums/hashes/attrs.txt → mbEditorPro2.0/arcane/enums/hashes/attrs.txt

0
mbEditorPro/arcane/enums/hashes/classes.txt → mbEditorPro2.0/arcane/enums/hashes/classes.txt

0
mbEditorPro/arcane/enums/hashes/discipline.txt → mbEditorPro2.0/arcane/enums/hashes/discipline.txt

0
mbEditorPro/arcane/enums/hashes/effects.txt → mbEditorPro2.0/arcane/enums/hashes/effects.txt

0
mbEditorPro/arcane/enums/hashes/environment.txt → mbEditorPro2.0/arcane/enums/hashes/environment.txt

0
mbEditorPro/arcane/enums/hashes/poweractions.txt → mbEditorPro2.0/arcane/enums/hashes/poweractions.txt

0
mbEditorPro/arcane/enums/hashes/powers.txt → mbEditorPro2.0/arcane/enums/hashes/powers.txt

0
mbEditorPro/arcane/enums/hashes/races.txt → mbEditorPro2.0/arcane/enums/hashes/races.txt

0
mbEditorPro/arcane/enums/hashes/resources.txt → mbEditorPro2.0/arcane/enums/hashes/resources.txt

0
mbEditorPro/arcane/enums/hashes/skills.txt → mbEditorPro2.0/arcane/enums/hashes/skills.txt

0
mbEditorPro/arcane/enums/hashes/soundtables.txt → mbEditorPro2.0/arcane/enums/hashes/soundtables.txt

0
mbEditorPro/arcane/enums/hashes/talents.txt → mbEditorPro2.0/arcane/enums/hashes/talents.txt

0
mbEditorPro/arcane/enums/hashes/weather.txt → mbEditorPro2.0/arcane/enums/hashes/weather.txt

38
mbEditorPro2.0/arcane/enums/zone/arc_mobile.py

@ -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,
}

23
mbEditorPro2.0/arcane/enums/zone/arc_prop.py

@ -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,
}

35
mbEditorPro2.0/arcane/enums/zone/arc_terraingen.py

@ -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,
}

62
mbEditorPro2.0/arcane/enums/zone/arc_zone.py

@ -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
mbEditorPro/arcane/enums/zone/arc_zone_goal.py → mbEditorPro2.0/arcane/enums/zone/arc_zone_goal.py

29
mbEditorPro2.0/arcane/objects/ArcAssetStructureObject.py

@ -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

28
mbEditorPro/arcane/objects/ArcCityAssetTemplate.py → mbEditorPro2.0/arcane/objects/ArcCityAssetTemplate.py

@ -130,13 +130,13 @@ class ArcCityAssetTemplate():
self.template_energy_set = stream.read_dword() self.template_energy_set = stream.read_dword()
self.template_use_trigger = stream.read_string() self.template_use_trigger = stream.read_string()
self.template_unkown_check1 = stream.read_bool() self.template_unknown_check1 = stream.read_bool()
if self.template_unkown_check1: if self.template_unknown_check1:
pass pass
self.template_loot_trigger = stream.read_string() self.template_loot_trigger = stream.read_string()
self.template_unkown_check2 = stream.read_bool() self.template_unknown_check2 = stream.read_bool()
if self.template_unkown_check2: if self.template_unknown_check2:
pass pass
self.has_embedded_template = stream.read_bool() self.has_embedded_template = stream.read_bool()
@ -199,7 +199,7 @@ class ArcCityAssetTemplate():
stream.read_dword(), stream.read_dword(),
] for _ in range(num_resource_limit) ] for _ in range(num_resource_limit)
] ]
self.template_unkown = stream.read_dword() self.template_unknown = stream.read_dword()
def save_binary(self, stream: ResStream): def save_binary(self, stream: ResStream):
stream.write_dword(self.template_max_ranks) 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_damage_set)
stream.write_dword(self.template_energy_set) stream.write_dword(self.template_energy_set)
stream.write_string(self.template_use_trigger) 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_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) stream.write_bool(self.has_embedded_template)
if self.has_embedded_template: if self.has_embedded_template:
self.template_embed_template.save_binary(stream) self.template_embed_template.save_binary(stream)
@ -276,7 +276,7 @@ class ArcCityAssetTemplate():
stream.write_dword(resource[0]) stream.write_dword(resource[0])
stream.write_dword(resource[1]) stream.write_dword(resource[1])
stream.write_dword(resource[2]) stream.write_dword(resource[2])
stream.write_dword(self.template_unkown) stream.write_dword(self.template_unknown)
def load_json(self, data): def load_json(self, data):
self.template_max_ranks = data['template_max_ranks'] self.template_max_ranks = data['template_max_ranks']
@ -307,9 +307,9 @@ class ArcCityAssetTemplate():
self.template_damage_set = data['template_damage_set'] self.template_damage_set = data['template_damage_set']
self.template_energy_set = data['template_energy_set'] self.template_energy_set = data['template_energy_set']
self.template_use_trigger = data['template_use_trigger'] 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_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'] self.has_embedded_template = data['has_embedded_template']
if self.has_embedded_template: if self.has_embedded_template:
self.template_embed_template = ArcCityAssetTemplate() self.template_embed_template = ArcCityAssetTemplate()
@ -330,7 +330,7 @@ class ArcCityAssetTemplate():
self.template_placement_type = data['template_placement_type'] self.template_placement_type = data['template_placement_type']
self.template_offering_adjustment = data['template_offering_adjustment'] self.template_offering_adjustment = data['template_offering_adjustment']
self.template_resource_limit = data['template_resource_limit'] self.template_resource_limit = data['template_resource_limit']
self.template_unkown = data['template_unkown'] self.template_unknown = data['template_unknown']
def save_json(self): def save_json(self):
data = OrderedDict() data = OrderedDict()
@ -362,9 +362,9 @@ class ArcCityAssetTemplate():
data['template_damage_set'] = self.template_damage_set data['template_damage_set'] = self.template_damage_set
data['template_energy_set'] = self.template_energy_set data['template_energy_set'] = self.template_energy_set
data['template_use_trigger'] = self.template_use_trigger 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_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 data['has_embedded_template'] = self.has_embedded_template
if self.has_embedded_template: if self.has_embedded_template:
data['template_embed_template'] = self.template_embed_template.save_json() 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_placement_type'] = self.template_placement_type
data['template_offering_adjustment'] = self.template_offering_adjustment data['template_offering_adjustment'] = self.template_offering_adjustment
data['template_resource_limit'] = self.template_resource_limit data['template_resource_limit'] = self.template_resource_limit
data['template_unkown'] = self.template_unkown data['template_unknown'] = self.template_unknown
return data return data

0
mbEditorPro/arcane/objects/ArcCombatObj.py → mbEditorPro2.0/arcane/objects/ArcCombatObj.py

1
mbEditorPro/arcane/objects/ArcContainerObject.py → mbEditorPro2.0/arcane/objects/ArcContainerObject.py

@ -5,6 +5,7 @@
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ # ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
# Magicbane Emulator Project © 2013 - 2022 # Magicbane Emulator Project © 2013 - 2022
# www.magicbane.com # www.magicbane.com
from arcane.util import ResStream from arcane.util import ResStream
from .ArcItem import ArcItem from .ArcItem import ArcItem
from .common.Inventory import Inventory from .common.Inventory import Inventory

0
mbEditorPro/arcane/objects/ArcDeed.py → mbEditorPro2.0/arcane/objects/ArcDeed.py

0
mbEditorPro/arcane/objects/ArcDoorObject.py → mbEditorPro2.0/arcane/objects/ArcDoorObject.py

0
mbEditorPro/arcane/objects/ArcDungeonUnitObject.py → mbEditorPro2.0/arcane/objects/ArcDungeonUnitObject.py

0
mbEditorPro/arcane/objects/ArcItem.py → mbEditorPro2.0/arcane/objects/ArcItem.py

0
mbEditorPro/arcane/objects/ArcKey.py → mbEditorPro2.0/arcane/objects/ArcKey.py

0
mbEditorPro/arcane/objects/ArcObj.py → mbEditorPro2.0/arcane/objects/ArcObj.py

0
mbEditorPro/arcane/objects/ArcRune.py → mbEditorPro2.0/arcane/objects/ArcRune.py

0
mbEditorPro/arcane/objects/ArcStaticObject.py → mbEditorPro2.0/arcane/objects/ArcStaticObject.py

24
mbEditorPro/arcane/objects/ArcStructureObject.py → mbEditorPro2.0/arcane/objects/ArcStructureObject.py

@ -30,9 +30,9 @@ class Region:
stream.read_byte(), stream.read_byte(),
stream.read_byte() stream.read_byte()
] ]
self.region_unkown2 = stream.read_byte() self.region_unknown2 = stream.read_byte()
self.region_unkown3 = stream.read_byte() self.region_unknown3 = stream.read_byte()
self.region_unkown4 = stream.read_tuple() self.region_unknown4 = stream.read_tuple()
def save_binary(self, stream: ResStream): def save_binary(self, stream: ResStream):
stream.write_dword(len(self.region_points)) stream.write_dword(len(self.region_points))
@ -46,9 +46,9 @@ class Region:
if self.region_has_stairs: if self.region_has_stairs:
stream.write_byte(self.region_stairs[0]) stream.write_byte(self.region_stairs[0])
stream.write_byte(self.region_stairs[1]) stream.write_byte(self.region_stairs[1])
stream.write_byte(self.region_unkown2) stream.write_byte(self.region_unknown2)
stream.write_byte(self.region_unkown3) stream.write_byte(self.region_unknown3)
stream.write_tuple(self.region_unkown4) stream.write_tuple(self.region_unknown4)
def load_json(self, data): def load_json(self, data):
self.region_points = data['region_points'] self.region_points = data['region_points']
@ -61,9 +61,9 @@ class Region:
self.region_has_stairs = data['region_has_stairs'] self.region_has_stairs = data['region_has_stairs']
if self.region_has_stairs: if self.region_has_stairs:
self.region_stairs = data['region_stairs'] self.region_stairs = data['region_stairs']
self.region_unkown2 = data['region_unkown2'] self.region_unknown2 = data['region_unknown2']
self.region_unkown3 = data['region_unkown3'] self.region_unknown3 = data['region_unknown3']
self.region_unkown4 = data['region_unkown4'] self.region_unknown4 = data['region_unknown4']
def save_json(self): def save_json(self):
data = OrderedDict() data = OrderedDict()
@ -77,9 +77,9 @@ class Region:
data['region_has_stairs'] = self.region_has_stairs data['region_has_stairs'] = self.region_has_stairs
if self.region_has_stairs: if self.region_has_stairs:
data['region_stairs'] = self.region_stairs data['region_stairs'] = self.region_stairs
data['region_unkown2'] = self.region_unkown2 data['region_unknown2'] = self.region_unknown2
data['region_unkown3'] = self.region_unkown3 data['region_unknown3'] = self.region_unknown3
data['region_unkown4'] = self.region_unkown4 data['region_unknown4'] = self.region_unknown4
return data return data

21
mbEditorPro2.0/arcane/objects/__init__.py

@ -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
mbEditorPro/arcane/objects/common/Arcane.py → mbEditorPro2.0/arcane/objects/common/Arcane.py

@ -5,6 +5,7 @@
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ # ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
# Magicbane Emulator Project © 2013 - 2022 # Magicbane Emulator Project © 2013 - 2022
# www.magicbane.com # www.magicbane.com
from collections import OrderedDict from collections import OrderedDict
from arcane.enums.hashes import hash_to_string, string_to_hash from arcane.enums.hashes import hash_to_string, string_to_hash

1
mbEditorPro/arcane/objects/common/Class.py → mbEditorPro2.0/arcane/objects/common/Class.py

@ -5,6 +5,7 @@
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ # ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
# Magicbane Emulator Project © 2013 - 2022 # Magicbane Emulator Project © 2013 - 2022
# www.magicbane.com # www.magicbane.com
from collections import OrderedDict from collections import OrderedDict
from arcane.enums.hashes import hash_to_string, string_to_hash from arcane.enums.hashes import hash_to_string, string_to_hash

41
mbEditorPro2.0/arcane/objects/common/Discipline.py

@ -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
mbEditorPro/arcane/objects/common/Inventory.py → mbEditorPro2.0/arcane/objects/common/Inventory.py

@ -5,6 +5,7 @@
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ # ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
# Magicbane Emulator Project © 2013 - 2022 # Magicbane Emulator Project © 2013 - 2022
# www.magicbane.com # www.magicbane.com
from collections import OrderedDict from collections import OrderedDict
from arcane.enums.common.arc_inventory import * from arcane.enums.common.arc_inventory import *

41
mbEditorPro2.0/arcane/objects/common/Race.py

@ -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
mbEditorPro/arcane/objects/common/SparseData.py → mbEditorPro2.0/arcane/objects/common/SparseData.py

@ -5,6 +5,7 @@
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ # ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
# Magicbane Emulator Project © 2013 - 2022 # Magicbane Emulator Project © 2013 - 2022
# www.magicbane.com # www.magicbane.com
from collections import OrderedDict from collections import OrderedDict
from arcane.enums.arc_sparse import * from arcane.enums.arc_sparse import *

7
mbEditorPro2.0/arcane/objects/common/__init__.py

@ -0,0 +1,7 @@
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
# Magicbane Emulator Project © 2013 - 2022
# www.magicbane.com

0
mbEditorPro/arcane/util/ArcFileCache.py → mbEditorPro2.0/arcane/util/ArcFileCache.py

16
mbEditorPro/arcane/util/ResStream.py → mbEditorPro2.0/arcane/util/ResStream.py

@ -18,6 +18,14 @@ class ResStream:
data = self.buffer.read(1) data = self.buffer.read(1)
return struct.unpack('<B', data)[0] 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): def read_dword(self):
data = self.buffer.read(4) data = self.buffer.read(4)
return struct.unpack('<I', data)[0] return struct.unpack('<I', data)[0]
@ -52,6 +60,14 @@ class ResStream:
data = struct.pack('<B', value) data = struct.pack('<B', value)
self.buffer.write(data) 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): def write_dword(self, value):
data = struct.pack('<I', value) data = struct.pack('<I', value)
self.buffer.write(data) self.buffer.write(data)

10
mbEditorPro2.0/arcane/util/__init__.py

@ -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
mbEditorPro/arcane/util/hasher.py → mbEditorPro2.0/arcane/util/hasher.py

19
mbEditorPro2.0/arcane/util/int32utils.py

@ -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

39
mbEditorPro2.0/arcane/zones/ArcDungeonInfo.py

@ -0,0 +1,39 @@
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
# Magicbane Emulator Project © 2013 - 2022
# www.magicbane.com
from collections import OrderedDict
from arcane.util import ResStream
class ArcDungeonInfo:
def load_binary(self, stream: ResStream):
self.dungeon_template_id = stream.read_qword()
self.dungeon_unknown = stream.read_qword()
self.dungeon_spawn_location = stream.read_tuple()
self.dungeon_y_offset = stream.read_float()
def save_binary(self, stream: ResStream):
stream.write_qword(self.dungeon_template_id)
stream.write_qword(self.dungeon_unknown)
stream.write_tuple(self.dungeon_spawn_location)
stream.write_float(self.dungeon_y_offset)
def save_json(self):
data = OrderedDict()
data['dungeon_template_id'] = self.dungeon_template_id
data['dungeon_unknown'] = self.dungeon_unknown
data['dungeon_spawn_location'] = self.dungeon_spawn_location
data['dungeon_y_offset'] = self.dungeon_y_offset
return data
def load_json(self, data):
self.dungeon_template_id = data['dungeon_template_id']
self.dungeon_unknown = data['dungeon_unknown']
self.dungeon_spawn_location = data['dungeon_spawn_location']
self.dungeon_y_offset = data['dungeon_y_offset']

0
mbEditorPro/arcane/zones/ArcMobile.py → mbEditorPro2.0/arcane/zones/ArcMobile.py

0
mbEditorPro/arcane/zones/ArcProp.py → mbEditorPro2.0/arcane/zones/ArcProp.py

0
mbEditorPro/arcane/zones/ArcSoundInfo.py → mbEditorPro2.0/arcane/zones/ArcSoundInfo.py

0
mbEditorPro/arcane/zones/ArcTerrainGen.py → mbEditorPro2.0/arcane/zones/ArcTerrainGen.py

8
mbEditorPro/arcane/zones/ArcZone.py → mbEditorPro2.0/arcane/zones/ArcZone.py

@ -41,7 +41,7 @@ class ArcZone:
self.zone_min_blend = stream.read_float() self.zone_min_blend = stream.read_float()
self.zone_max_blend = stream.read_float() self.zone_max_blend = stream.read_float()
self.zone_influence = 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_y_offset = stream.read_float()
self.zone_global_height = stream.read_float() self.zone_global_height = stream.read_float()
self.zone_transition_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_min_blend)
stream.write_float(self.zone_max_blend) stream.write_float(self.zone_max_blend)
stream.write_float(self.zone_influence) 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_y_offset)
stream.write_float(self.zone_global_height) stream.write_float(self.zone_global_height)
stream.write_float(self.zone_transition_height) stream.write_float(self.zone_transition_height)
@ -255,7 +255,7 @@ class ArcZone:
data['zone_min_blend'] = self.zone_min_blend data['zone_min_blend'] = self.zone_min_blend
data['zone_max_blend'] = self.zone_max_blend data['zone_max_blend'] = self.zone_max_blend
data['zone_influence'] = self.zone_influence 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_y_offset'] = self.zone_y_offset
data['zone_global_height'] = self.zone_global_height data['zone_global_height'] = self.zone_global_height
data['zone_transition_height'] = self.zone_transition_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_min_blend = data['zone_min_blend']
self.zone_max_blend = data['zone_max_blend'] self.zone_max_blend = data['zone_max_blend']
self.zone_influence = data['zone_influence'] 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_y_offset = data['zone_y_offset']
self.zone_global_height = data['zone_global_height'] self.zone_global_height = data['zone_global_height']
self.zone_transition_height = data['zone_transition_height'] self.zone_transition_height = data['zone_transition_height']

0
mbEditorPro/arcane/zones/ArcZoneBiomState.py → mbEditorPro2.0/arcane/zones/ArcZoneBiomState.py

8
mbEditorPro/arcane/zones/ArcZoneEvent.py → mbEditorPro2.0/arcane/zones/ArcZoneEvent.py

@ -14,7 +14,7 @@ class ArcZTriggerAction:
self.zone_trigger_action_type = stream.read_dword() self.zone_trigger_action_type = stream.read_dword()
self.zone_trigger_action_unknown1 = stream.read_bool() self.zone_trigger_action_unknown1 = stream.read_bool()
self.zone_trigger_action_is_timed = 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: if self.zone_trigger_action_is_timed:
self.zone_trigger_action_time_begin = stream.read_float() 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_spawn_radius = stream.read_float()
self.zone_event_fc_label = stream.read_string() self.zone_event_fc_label = stream.read_string()
self.zone_event_event_name = 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_spawn_location = stream.read_tuple()
self.zone_event_parent_name = stream.read_string() self.zone_event_parent_name = stream.read_string()
self.zone_event_unkown2 = stream.read_dword() self.zone_event_unknown2 = stream.read_dword()
self.zone_event_unkown3 = stream.read_bool() self.zone_event_unknown3 = stream.read_bool()
num_triggers = stream.read_dword() num_triggers = stream.read_dword()
self.zone_event_triggers = [ArcZTriggerAction() for _ in range(num_triggers)] self.zone_event_triggers = [ArcZTriggerAction() for _ in range(num_triggers)]
for action in self.zone_event_triggers: for action in self.zone_event_triggers:

0
mbEditorPro/arcane/zones/ArcZoneGoal.py → mbEditorPro2.0/arcane/zones/ArcZoneGoal.py

8
mbEditorPro/arcane/zones/TerrainObjectInfo.py → mbEditorPro2.0/arcane/zones/TerrainObjectInfo.py

@ -26,7 +26,7 @@ class TerrainObjectInfo:
self.terrain_object_max_slope = stream.read_float() self.terrain_object_max_slope = stream.read_float()
self.terrain_object_max_pop = stream.read_dword() self.terrain_object_max_pop = stream.read_dword()
self.terrain_object_is_fractal_pop = stream.read_bool() 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_y_offset = stream.read_float()
self.terrain_object_pop_image_id = stream.read_qword() self.terrain_object_pop_image_id = stream.read_qword()
self.terrain_object_image_min_y = stream.read_float() 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_float(self.terrain_object_max_slope)
stream.write_dword(self.terrain_object_max_pop) stream.write_dword(self.terrain_object_max_pop)
stream.write_bool(self.terrain_object_is_fractal_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_float(self.terrain_object_y_offset)
stream.write_qword(self.terrain_object_pop_image_id) stream.write_qword(self.terrain_object_pop_image_id)
stream.write_float(self.terrain_object_image_min_y) 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_slope'] = self.terrain_object_max_slope
data['terrain_object_max_pop'] = self.terrain_object_max_pop 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_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_y_offset'] = self.terrain_object_y_offset
data['terrain_object_pop_image_id'] = self.terrain_object_pop_image_id data['terrain_object_pop_image_id'] = self.terrain_object_pop_image_id
data['terrain_object_image_min_y'] = self.terrain_object_image_min_y 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_slope = data['terrain_object_max_slope']
self.terrain_object_max_pop = data['terrain_object_max_pop'] 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_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_y_offset = data['terrain_object_y_offset']
self.terrain_object_pop_image_id = data['terrain_object_pop_image_id'] self.terrain_object_pop_image_id = data['terrain_object_pop_image_id']
self.terrain_object_image_min_y = data['terrain_object_image_min_y'] self.terrain_object_image_min_y = data['terrain_object_image_min_y']

0
mbEditorPro/arcane/zones/WaterInfo.py → mbEditorPro2.0/arcane/zones/WaterInfo.py

0
mbEditorPro/arcane/zones/WeatherEventInfo.py → mbEditorPro2.0/arcane/zones/WeatherEventInfo.py

9
mbEditorPro2.0/arcane/zones/__init__.py

@ -0,0 +1,9 @@
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
# Magicbane Emulator Project © 2013 - 2022
# www.magicbane.com
from .ArcZone import ArcZone

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save