diff options
-rw-r--r-- | srb_lib.py | 50 |
1 files changed, 19 insertions, 31 deletions
@@ -1,26 +1,31 @@ #!/usr/bin/env python3 -# Startdate: 2024-03-08-6 15:28 # File: srb_lib.py -# Purpose: library for srb.exe savegame hacking +# Location: https://bgstack15.ddns.net/cgit/srb_lib +# Author: bgstack15 # SPDX-License-Identifier: GPL-3.0-only +# Startdate: 2024-03-08-6 15:28 +# Title: Library for manipulating savegame file for Snoopy vs. the Red Baron +# Project: srb_lib +# Purpose: library for srb.exe savegame hacking # History: # Usage: # from srb.py # Reference: -# blog posts 2024-03 +# <https://bgstack15.ddns.net/blog/posts/2024/03/22/initial-research-for-hacking-savegame-files-for-snoopy-vs-the-red-baron/> +# <https://bgstack15.ddns.net/blog/posts/2024/03/26/the-checksum-for-the-savegame-file-for-snoopy-vs-the-red-baron> # <https://github.com/8051Enthusiast/delsum> # crc width=32 poly=0x4c11db7 init=0x0 xorout=0x235b4b9c refin=false refout=false out_endian=little -# Incorrect functions: https://gist.github.com/djsweet/3477115595efab31905be7000bb013bc FAILED -# Fuctions that worked: https://gist.github.com/Lauszus/6c787a3bc26fea6e842dfb8296ebd630 Author: Lauszus -# https://stackoverflow.com/questions/46109815/reversing-the-byte-order-of-a-string-containing-hexadecimal-characters -# https://gamefaqs.gamespot.com/pc/930591-snoopy-vs-the-red-baron/faqs/46161 +# Incorrect functions: <https://gist.github.com/djsweet/3477115595efab31905be7000bb013bc> FAILED +# Fuctions that worked: <https://gist.github.com/Lauszus/6c787a3bc26fea6e842dfb8296ebd630> Author: Lauszus +# <https://stackoverflow.com/questions/46109815/reversing-the-byte-order-of-a-string-containing-hexadecimal-characters> +# <https://gamefaqs.gamespot.com/pc/930591-snoopy-vs-the-red-baron/faqs/46161> # Documentation: # winetricks vd=1024x768 # winetricks vd=off # Dependencies: import sys, struct -srb_lib_version = "20240318a" +srb_lib_version = "20240320a" # Table of byte positions of values in the savegame file, minus the first four bytes which are the checksum. Due to zero-indexing of python lists, but for ease of usage, we will always put a zero as the value of index 0. That is, profile 1 will use index 1 of the list. # "Z<dddddddd" is the start of a profile. @@ -29,13 +34,10 @@ PROFILE_START_POSITION = [0, 0x10, 0x142C, 0x2848] POS_MONEY = 0x270 POS_HEALTH = 0x274 # 0-3 is available levels POS_STUNT = 0x280 # 0-3 is available levels -POS_GUN = 0x27C # 0-3 is available levels +POS_GUN = 0x27C # 0-3 is available levels, although 4 is octo-gun POS_EQUIPPED_WEAPON = 0x284 POS_PROFILE_IN_USE = 0x290 POS_NAME = 0x294 -# absolute 0x3fc is profile 1, so relative to start position -# relative to profile: 0x3E8 is level 0, levelset 0 -# rel 0x404 is level 0 of levelset 1 NAME_CHARS = " ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!?" @@ -193,9 +195,9 @@ def write_file(filename, checksum, data): #f.write(struct.pack('>I',int(checksum))) f.write(data) -######## start copy-paste 2 -# https://gist.github.com/Lauszus/6c787a3bc26fea6e842dfb8296ebd630 - +######## start embedded file +# Source: https://gist.github.com/Lauszus/6c787a3bc26fea6e842dfb8296ebd630 +# Author: Lauszus def reflect_data(x, width): # See: https://stackoverflow.com/a/20918545 if width == 8: @@ -216,7 +218,6 @@ def reflect_data(x, width): else: raise ValueError('Unsupported width') return x - def crc_poly(data, n, poly, crc=0, ref_in=False, ref_out=False, xor_out=0): g = 1 << n | poly # Generator polynomial # Loop over the data @@ -238,7 +239,7 @@ def crc_poly(data, n, poly, crc=0, ref_in=False, ref_out=False, xor_out=0): crc = reflect_data(crc, n) # Return the CRC value return crc ^ xor_out -##### end copy-paste 2 +######## end embedded file def _get_data_from_data_object(data_object): """ Helper function to either open file, or pass bytes through. """ @@ -249,28 +250,15 @@ def _get_data_from_data_object(data_object): data = data_object return data -def _convert_dec_to_reverse_bytes(num_dec): - """ Helper function to turn a given decimal value into the little-endian values for insertion into the data. """ - # Here is how to do this manually. - #num_str = str(hex(num_dec))[2:] - #num_str = ("0" if len(num_str) % 2 else "") + num_str - #num_bytes = bytearray.fromhex(num_str) - #num_bytes.reverse() - #return bytes(num_bytes) - # I learned how to do this the pythonic way. - return struct.pack('<i',num_dec) - def get_money(data_object,profile_id): """ Print in decimal the current money value of the profile_id. """ data = _get_data_from_data_object(data_object) - money_dec = data[PROFILE_START_POSITION[profile_id]+POS_MONEY] + (data[PROFILE_START_POSITION[profile_id]+POS_MONEY+1] * 0x100) - #money_dec = int(money_hex, base=16) + money_dec = struct.unpack_from('<1i',data,PROFILE_START_POSITION[profile_id]+POS_MONEY)[0] return money_dec def set_money(data_object,profile_id, money_dec): """ Using data, set the money given in decimal for the given profile_id. """ data = _get_data_from_data_object(data_object) - #money_bytes = _convert_dec_to_reverse_bytes(money_dec) data = srb_pack('<i',data,PROFILE_START_POSITION[profile_id]+POS_MONEY,money_dec) print(f"after setting money to {money_dec}, we checked and got {get_money(data,profile_id)}") return data |