diff --git a/SaveManager.py b/SaveManager.py index e6a59e7..e44f384 100644 --- a/SaveManager.py +++ b/SaveManager.py @@ -206,7 +206,7 @@ def grab_metadata(file): """Used to grab metadata from archive info.txt""" with open(file.replace(" ", "__").replace(":", "."), 'r') as f: meta = f.read() - popup(meta) + popup(meta.replace(",", "\n")) def get_charnames(file): @@ -2401,17 +2401,15 @@ def run_cheat(): popupwin.geometry("+%d+%d" % (x + 200, y + 200)) main_label = Label(popupwin, text="DO NOT use this feature online! You will most certainly get banned.\n\nThis will set your HP,ST,FP to 60,000\n\n Note: Your stats will return to normal after leveling up or equipping a stat boosting item. \n\nNote: Remove any stat boosting gear from your character before doing this or it won't work.\n\n") -# main_label.grid(row=0) main_label.pack() + # MAIN SAVE FILE LISTBOX lb1 = Listbox(popupwin, borderwidth=3, width=15, height=10, exportselection=0) lb1.config(font=bolded) -# lb1.grid(row=1, column=0, padx=(155, 0), pady=(35, 15)) lb1.pack() load_listbox(lb1) but_select1 = Button( popupwin, text="Select", command=lambda: get_char_names(lb1, dropdown1, c_vars)) -# but_select1.grid(row=2, column=0, padx=(155, 0), pady=(0, 10)) but_select1.pack() # CHARACTER DROPDOWN MENU @@ -2419,18 +2417,12 @@ def run_cheat(): c_vars = StringVar(popupwin) c_vars.set("Character") dropdown1 = OptionMenu(popupwin, c_vars, *opts) -# dropdown1.grid(row=3, column=0, padx=(155, 0), pady=(0, 10)) dropdown1.pack() - - - - # SELECT LISTBOX ITEM BUTTON but_set = Button(popupwin, text="Set", command=run_cheat) but_set.config(font=bolded) -# but_set.grid(row=6, column=0, padx=(155, 0), pady=(22, 10)) but_set.pack() @@ -2554,6 +2546,140 @@ def fix(): but_set_stats.grid(row=0, column=0, padx=(25, 0), pady=(420, 0), sticky="n") +def set_runes_menu(): + def get_char_names(lstbox, drop, v): + """Populates dropdown menu containing the name of characters in a save file""" + v.set("Character") + name = fetch_listbox_entry(lstbox)[0] + if len(name) < 1: + return + file = f"{savedir}{name}/{ext()}" + names = get_charnames(file) + if names is False: + popup("FileNotFoundError: This is a known issue.\nPlease try re-importing your save file.") + drop["menu"].delete(0, "end") # remove full list + + index = 1 + for ind, opt in enumerate(names): + if not opt is None: + opt = f"{index}. {opt}" + drop["menu"].add_command(label=opt, command=TKIN._setit(v, opt)) + index += 1 + elif opt is None: + opt = f"{ind + 1}. " + drop["menu"].add_command(label=opt, command=TKIN._setit(v, opt)) + index += 1 + + def validate(P): + + if P.isdigit(): + return True + else: + return False + + + def set_runecount(): + old_quantity = old_q_ent.get() + new_quantity = new_q_ent.get() + + char = c_vars.get() # "1. charname" + if char == "Character" or char == "": + popup("Character not selected", parent_window=popupwin) + return + + if char.split(".")[1] == " ": + popup("Can't write to empty slot.\nGo in-game and create a character to overwrite.", parent_window=popupwin) + return + + + + name = fetch_listbox_entry(lb1)[0] # Save file name. EX: main + if len(name) < 1: + popup(txt="Slot not selected", parent_window=popupwin) + return + + dest_file = f"{savedir}{name}/{ext()}" + char_ind = int(char.split(".")[0]) + + if old_quantity == "" or new_quantity == "": + popup("Enter a rune quantity", parent_window = popupwin) + return + + if int(old_quantity) < 1000 or int(new_quantity) < 1000: + popup("Rune count is too low! Enter a value greater than 1000", parent_window=popupwin) + return + if int(new_quantity) > 999999999: # Max quantity in-game + new_quantity = 999999999 + + + archive_file(dest_file, fetch_listbox_entry(lb1)[0], "ACTION: Set rune count", get_charnames(dest_file)) + out = hexedit.set_runes(dest_file, char_ind, int(old_quantity), int(new_quantity)) + if out is False: + popup("Unable to find rune count!\nMake sure you have a larger value with the number being fairly random. Ex: 85732", parent_window=popupwin) + return + else: + popup(f"Successfully set rune count to {new_quantity}", parent_window=popupwin) + + popupwin = Toplevel(root) + popupwin.title("Set Rune Count") + popupwin.resizable(width=True, height=True) + popupwin.geometry("510x590") + + x = root.winfo_x() + y = root.winfo_y() + popupwin.geometry("+%d+%d" % (x + 200, y + 200)) + vcmd = (popupwin.register(validate), "%P") + + + main_label = Label(popupwin, text="Go in-game and take note of how many held runes the character has.\nBigger numbers ensure the program finds the proper location of your runes.\n") + main_label.pack() + + # MAIN SAVE FILE LISTBOX + lb1 = Listbox(popupwin, borderwidth=3, width=15, height=10, exportselection=0) + lb1.config(font=bolded) + + lb1.pack() + load_listbox(lb1) + + but_select1 = Button( popupwin, text="Select", command=lambda: get_char_names(lb1, dropdown1, c_vars)) + but_select1.pack() + + # CHARACTER DROPDOWN MENU + opts = [""] + c_vars = StringVar(popupwin) + c_vars.set("Character") + dropdown1 = OptionMenu(popupwin, c_vars, *opts) + dropdown1.pack() + + padding_lab1 = Label(popupwin, text="\n\n") + padding_lab1.pack() + + # OLD QUANTITY LABEL + old_q_label = Label(popupwin, text="Enter Current rune count:") + old_q_label.pack() + + # OLD QUANTITY ENTRY + old_q_ent = Entry(popupwin, borderwidth=5, validate="key", validatecommand=vcmd) + old_q_ent.pack() + + + # NEW QUANTITY LABEL + new_q_label = Label(popupwin, text="Enter new rune count:") + new_q_label.pack() + + # NEW QUANTITY ENTRY + new_q_ent = Entry(popupwin, borderwidth=5, validate="key", validatecommand=vcmd) + new_q_ent.pack() + + + padding_lab3 = Label(popupwin, text="\n\n") + padding_lab3.pack() + + # SET BUTTON + but_set = Button(popupwin, text="Set", command=set_runecount) + but_set.config(font=bolded) + but_set.pack() + # //// LEGACY FUNCTIONS (NO LONGER USED) //// @@ -2719,6 +2845,7 @@ def open_notes(): # CHEAT MENU cheatmenu = Menu(menubar, tearoff=0) cheatmenu.add_command(label="God Mode", command=godmode_menu) +cheatmenu.add_command(label="Set Runes", command=set_runes_menu) menubar.add_cascade(label="Cheats", menu=cheatmenu) # HELP MENU diff --git a/data/changelog.txt b/data/changelog.txt index 80a6a89..09e97fd 100644 --- a/data/changelog.txt +++ b/data/changelog.txt @@ -1,2 +1 @@ -God mode fix (read the new description in god-mode window) -Minor bug fixes and improvements \ No newline at end of file +New cheat to set amount of held runes \ No newline at end of file diff --git a/hexedit.py b/hexedit.py index a435e76..4808663 100644 --- a/hexedit.py +++ b/hexedit.py @@ -379,7 +379,7 @@ def get_stats(file, char_slot): l_endian(slot1[ind + 24 : ind + 25]), l_endian(slot1[ind + 28 : ind + 29]), ] - + if sum(stats) == lv + 79 and l_endian(slot1[ind + 44 : ind + 46]) == lv: start_ind = ind @@ -785,3 +785,33 @@ def fix_stats(file, char_slot, stat_list): fh.write(data) set_level(file, char_slot, new_lv) # Set level runs recalc_checksum return True + + +def set_runes(file, char_slot, old_quantity, new_quantity): + + + slots = get_slot_ls(file) + slot_slices = get_slot_slices(file) + slot1 = slots[char_slot -1] + index = 0 + for ind, b in enumerate(slot1): + if ind > 80000: + break + x = l_endian(slot1[ind : ind + 4]) + if x == old_quantity: + index = ind + + + if index == 0: + return False + data = ( + slot_slices[char_slot - 1][0] + + slot1[:index] + + new_quantity.to_bytes(4,"little") + + slot1[index + 4 :] + + slot_slices[char_slot - 1][1] + ) + + with open(file, "wb") as fh: + fh.write(data) + recalc_checksum(file) diff --git a/os_layer.py b/os_layer.py index 7164494..0b34512 100644 --- a/os_layer.py +++ b/os_layer.py @@ -13,8 +13,8 @@ update_dir = "./data/updates/" temp_dir = "./data/temp/" post_update_file = "./data/post.update" -version = "v1.67" -v_num = 1.67 # Used for checking version for update +version = "v1.68" +v_num = 1.68 # Used for checking version for update video_url = "https://youtu.be/LQxmFuq3dfg" custom_search_tutorial_url = "https://youtu.be/li-ZiMXBmRk" background_img = "./data/background.png"