aboutsummaryrefslogtreecommitdiff
path: root/srb_lib.py
diff options
context:
space:
mode:
Diffstat (limited to 'srb_lib.py')
-rw-r--r--srb_lib.py55
1 files changed, 28 insertions, 27 deletions
diff --git a/srb_lib.py b/srb_lib.py
index f7f79a5..be3683a 100644
--- a/srb_lib.py
+++ b/srb_lib.py
@@ -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, ""
bgstack15