diff options
Diffstat (limited to 'srb_lib.py')
-rw-r--r-- | srb_lib.py | 55 |
1 files changed, 28 insertions, 27 deletions
@@ -28,7 +28,7 @@ # Dependencies: import sys, struct -srb_lib_version = "20240404a" +srb_lib_version = "20240405a" # 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. @@ -104,17 +104,18 @@ PLANES = [ {"p":0x3B20,"name":"all"}, ] -# c = balloon color # l = level count -# le = letters, calculated +# a = level 0 is Available if previous levelset has this number of completed missions +# c = balloon color # b = balloon count, calculated +# le = letters, calculated LEVELSETS = [ - {"id":0,"l":6,"c":"red" ,"b":0,"le":"","name":"Aerodrome Island"}, - {"id":1,"l":3,"c":"yellow","b":0,"le":"","name":"Woods of Montsec"}, - {"id":2,"l":3,"c":"green" ,"b":0,"le":"","name":"Front Lines of Verdun"}, - {"id":3,"l":5,"c":"blue" ,"b":0,"le":"","name":"Mines of the Matterhorn"}, - {"id":4,"l":3,"c":"orange","b":0,"le":"","name":"Verdon Gorge"}, - {"id":5,"l":2,"c":"none" ,"b":0,"le":"","name":"Flying Fortress"}, + {"id":0,"l":6,"a":0,"c":"red" ,"b":0,"le":"","name":"Aerodrome Island"}, + {"id":1,"l":3,"a":3,"c":"yellow","b":0,"le":"","name":"Woods of Montsec"}, + {"id":2,"l":3,"a":2,"c":"green" ,"b":0,"le":"","name":"Front Lines of Verdun"}, + {"id":3,"l":5,"a":2,"c":"blue" ,"b":0,"le":"","name":"Mines of the Matterhorn"}, + {"id":4,"l":3,"a":5,"c":"orange","b":0,"le":"","name":"Verdon Gorge"}, + {"id":5,"l":2,"a":3,"c":"none" ,"b":0,"le":"","name":"Flying Fortress"} ] # pos_r = relative position for level status @@ -411,7 +412,7 @@ def get_collected_breakables(data_object,profile_id, level, silent=False): print(f"Debug: abs 0x{CHECKSUM_LENGTH+pos_level_which_breakables:04x} which breakables: b{profile_level_which_breakables:05b}") return ','.join(breakables_list), breakables_mask -def set_level_status(data_object,profile_id,level,status,fix_levelset_available_levels=True): +def set_level_status(data_object,profile_id,level,status,fix_levelset_completed_levels=True): """ Set completion rank for a level, e.g., general """ data = _get_data_from_data_object(data_object) level_obj, message = get_level_info(level) @@ -427,19 +428,19 @@ def set_level_status(data_object,profile_id,level,status,fix_levelset_available_ #print(f"debug: will try to set bits {bits:02x}") data = srb_pack('<1I',data,PROFILE_START_POSITION[profile_id]+POS_LEVEL_START+(INT_SIZE*level_obj["pos_r"]),bits) current_status, _, _ = get_level_status(data, profile_id, level, silent=True) - levelset_available_levels = get_levelset_available_levels(data,profile_id,level_obj["setid"]) - #print(f"debug: levelset {level_obj['setid']} currently has {levelset_available_levels} available levels.") - # if setting to any completed status, if the levelset available levels is less than this level, then make it this. - if fix_levelset_available_levels: - if levelset_available_levels < (level_obj["set_pos"] + 1) and status not in ["none"]: - data, message = set_levelset_available_levels(data,profile_id,level_obj["setid"],level_obj["set_pos"] + 1) + levelset_completed_levels = get_levelset_completed_levels(data,profile_id,level_obj["setid"]) + #print(f"debug: levelset {level_obj['setid']} currently has {levelset_completed_levels} completed levels.") + # if setting to any completed status, if the levelset completed levels is less than this level, then make it this. + if fix_levelset_completed_levels: + if levelset_completed_levels < (level_obj["set_pos"] + 1) and status not in ["none"]: + data, message = set_levelset_completed_levels(data,profile_id,level_obj["setid"],level_obj["set_pos"] + 1) if message != "": - return -1, -1, f"Unable to set levelset available levels to minimum of this level set_pos {level_obj['set_pos']}" - # decrement the available levels in the levelset if clearing out this level and the available levels is exactly this one. - if levelset_available_levels == (level_obj["set_pos"] + 1) and status in ["none"]: - data, message = set_levelset_available_levels(data,profile_id,level_obj["setid"],level_obj["set_pos"]) + return -1, -1, f"Unable to set levelset completed levels to minimum of this level set_pos {level_obj['set_pos']}" + # decrement the completed levels in the levelset if clearing out this level and the completed levels is exactly this one. + if levelset_completed_levels == (level_obj["set_pos"] + 1) and status in ["none"]: + data, message = set_levelset_completed_levels(data,profile_id,level_obj["setid"],level_obj["set_pos"]) if message != "": - return -1, -1, f"Unable to decrement levelset available levels." + return -1, -1, f"Unable to decrement levelset completed levels." return data, current_status, "" def set_level_balloons(data_object,profile_id,level,count, silent = False): @@ -575,19 +576,19 @@ def set_level_letters(data_object,profile_id,level,letters, silent = False): data = srb_pack('<1I',data,pos_levelset_completed_letters_mask,new_letter_mask_final) return data, "" -def get_levelset_available_levels(data_object,profile_id,levelset): +def get_levelset_completed_levels(data_object,profile_id,levelset): data = _get_data_from_data_object(data_object) levelset_obj, message = get_levelset_info(levelset) if message != "": - return -1, f"For set_levelset_available_levels unable to get levelset for {levelset}." + return -1, f"For set_levelset_completed_levels unable to get levelset for {levelset}." pos_levelset_completed_mission_mask = PROFILE_START_POSITION[profile_id]+POS_LEVELSET_COMPLETED_MISSIONS_MASK+(INT_SIZE*levelset_obj["id"]) return data[pos_levelset_completed_mission_mask] -def set_levelset_available_levels(data_object,profile_id,levelset,completed_count): +def set_levelset_completed_levels(data_object,profile_id,levelset,completed_count): data = _get_data_from_data_object(data_object) levelset_obj, message = get_levelset_info(levelset) if message != "": - return -1, f"For set_levelset_available_levels unable to get levelset for {levelset}." + return -1, f"For set_levelset_completed_levels unable to get levelset for {levelset}." if completed_count == "all": completed_count = 8 # no levelset has more than 6 levels so this is a safe maximum, and it will get checked farther below. if completed_count == "none": @@ -596,13 +597,13 @@ def set_levelset_available_levels(data_object,profile_id,levelset,completed_coun try: completed_count = int(completed_count) except: - return -1, f"cannot set levelset available levels to {completed_count}" + return -1, f"cannot set levelset completed levels to {completed_count}" if completed_count < 0: completed_count = 0 completed_count = min(levelset_obj["l"], completed_count) pos_levelset_completed_mission_mask = PROFILE_START_POSITION[profile_id]+POS_LEVELSET_COMPLETED_MISSIONS_MASK+(INT_SIZE*levelset_obj["id"]) completed_bitmask = pow(2,completed_count)-1 - #print(f"debug: need to set levelset {levelset} available count to {completed_count}, which stored as a bitmask should be {completed_bitmask:07b}") + #print(f"debug: need to set levelset {levelset} completed count to {completed_count}, which stored as a bitmask should be {completed_bitmask:07b}") data = srb_pack('<1I',data,pos_levelset_completed_mission_mask,completed_bitmask) return data, "" |