From ce6522ef54fe271ab42a286c7396e11b0a014055 Mon Sep 17 00:00:00 2001 From: Anthony Vizza Date: Fri, 5 Apr 2019 01:29:14 -0500 Subject: [PATCH] Read location values as 12 bit integers Based on research from issue #2, the game appears to only use 12 bits of the 16 from offsets 726-727. The data in the leading four bits of the most significant byte does not appear to affect loading location at all. The following two values loaded in the same location in game: dd 42 = 1101 1101 >0100< 0010 dd 02 = 1101 1101 >0000< 0010 On load, the app now ignores those four bits as the game apparently does, and on write they are zeroed out. --- sd3save_editor/save.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/sd3save_editor/save.py b/sd3save_editor/save.py index ae3db4d..5908d1c 100644 --- a/sd3save_editor/save.py +++ b/sd3save_editor/save.py @@ -97,6 +97,22 @@ def _encode(self, obj, context): return zeroes +class LocationAdapter(Adapter): + """Location data appears to be loaded as a 12bit integer by the game + This works around the absence of such a type in python core, it functions + by truncating 4 bits from the provided 16, and zeroes out the leading 4 + bits on writing + """ + def _decode(self, obj, context): + int16 = int.from_bytes(obj, byteorder='little') + bit_str12 = bin(int16)[2:].zfill(16)[4:] + return int(bit_str12, 2) + + def _encode(self, obj, context): + bit_str = '0000%s' % bin(obj)[2:].zfill(16)[4:] + return int(bit_str, 2).to_bytes(2, byteorder='little') + + char_header = Struct( "name"/CharacterNameAdapter(Bytes(12)), "lvl"/Int8sl, @@ -179,7 +195,7 @@ def _encode(self, obj, context): "unclear4"/Bytes(530), "item_storage"/Int8sl[102], "unclear5"/Bytes(26), - "location"/Int16sl, + "location"/LocationAdapter(Bytes(2)), "unclear6"/Bytes(46), "item_ring"/Int8sl[10], "unclear7"/Bytes(158)