import json import math def floor(x,d=0): pot = 10**d return math.floor(x*pot)/pot def ceil(x,d=0): pot = 10**d return math.ceil(x*pot)/pot R=0 SR=1 UR=2 necklace_rarities = [(1, 0.5, 10, 1), (1, 0.75, 15, 1.5), (1, 1, 20, 2)] dataset = [ { # NemuMori Beginner "json": "mapdb/12007101.json", "max_stamina": 5116, "subunit_gd_bonus": -5, "necklaces": [(R,1)], "ac_clears": [9], "heals": [], "dr_permanent": [], "dr_notes": [], "known_damages": [413,413,415,416] }, { # NemuMori Intermediate "json": "mapdb/12007201.json", "max_stamina": 6369, "subunit_gd_bonus": -15, "necklaces": [(R,1)], "ac_clears": [11], "heals": [], "dr_permanent": [], "dr_notes": [], "known_damages": [453,454,454,455,457] }, { # DIVE! Beginner "json": "mapdb/12048101.json", "max_stamina": 5418, "subunit_gd_bonus": -15, "necklaces": [(R,1)], "ac_clears": [], "heals": [], "dr_permanent": [], "dr_notes": [], "known_damages": [2265,2280] }, { # KoiAqua Advanced "json": "mapdb/11009301.json", "max_stamina": 64879 + floor(10897*0.225) + floor(5999*0.225) + floor(4845*0.225) + floor(5634*0.225) + floor(8835*0.225), "subunit_gd_bonus": -10, "necklaces": [(UR,16), (UR,12), (UR,12), (SR,2), (SR,1), (SR,1)], "ac_clears": [22,56,90,132], "heals": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,4206,0,0,0,0,0,0,0,0,4626,0,0,0,0,0,4206,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4626,0,0,0,0,0,0,0,0,0,0,0,4206,0,0,4206,0,0,0,0,0,4206,0,0,4206,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4206,0,0,0,0,0,4206,0,0,4206,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4206,0,0,4206,0,0,4206,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], "dr_permanent": [], "dr_notes": [], "known_damages": [8685,8974,9135,9439,9077] }, { # NemuMori Advanced "json": "mapdb/12007301.json", "max_stamina": 64884, "subunit_gd_bonus": -10, "necklaces": [(UR,16), (UR,12), (UR,12), (SR,2), (SR,1), (SR,1)], "ac_clears": [18,37,68,87,122], "heals": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3434,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3434,0,0,0,0,0,0,0,0,3434], "dr_permanent": [], "dr_notes": [], "known_damages": [364,365,366,361,363,364,365,376,377,378,380,381,381] }, { # NemuMori Advanced "json": "mapdb/12007301.json", "max_stamina": 67072, "subunit_gd_bonus": -5, "necklaces": [], "ac_clears": [18,37,68,87,122], "heals": [], "dr_permanent": [1.2, 3.2], "dr_notes": [], "known_damages": [402,402,402,402,402,402,402,402,402,402,402,402,402] } ] def calc_single_damage_multiply_ac(damage, is_ac, acc_factor, dr_factor, type_factor): return floor( floor( floor( floor( damage * (1.1 if is_ac else 1) ) * acc_factor ) * dr_factor ) * type_factor ) def calc_single_damage_add_ac(damage, is_ac, acc_factor, dr_factor, type_factor): return floor( floor( floor( damage * (acc_factor + (0.1 if is_ac else 0)) ) * dr_factor ) * type_factor ) def calc_damage(current_stamina, note_damage, gimmick_damage, max_stamina, subunit_gd_bonus, necklaces, active_drs, is_ac, is_star, combine_ac_acc, combine_dr_type): acc_multiplier = current_stamina / max_stamina #acc_factor = 1 - sum([floor(n*100)/100 for n in necklaces]) * 3 * acc_multiplier) * 0.01 acc_factor = 1 for n in necklaces: rarity = necklace_rarities[n[0]] #print("Necklace",n,rarity) a = rarity[1] b = rarity[3] lvl_diff = (b - a) / (rarity[2] - rarity[0]) necklace_effect = a + lvl_diff * (n[1] - rarity[0]) #print(" ",lvl_diff,necklace_effect) acc_factor -= floor(necklace_effect * acc_multiplier, 2) * 3 / 100 #print(" ",acc_factor) if combine_dr_type: dr_factor = 1 - (sum(active_drs) + subunit_gd_bonus) * 0.01 type_factor = 1 else: dr_factor = 1 - (sum(active_drs)) * 0.01 type_factor = 1 - subunit_gd_bonus * 0.01 if combine_ac_acc: nd = calc_single_damage_add_ac(note_damage, is_ac, acc_factor, dr_factor, type_factor) gd = calc_single_damage_add_ac(gimmick_damage, is_ac, acc_factor, dr_factor, type_factor) else: nd = calc_single_damage_multiply_ac(note_damage, is_ac, acc_factor, dr_factor, type_factor) gd = calc_single_damage_multiply_ac(gimmick_damage, is_ac, acc_factor, dr_factor, type_factor) return (0 if is_star else nd, gd) def verify_dataset(ds, opt, stop_on_fail, output): ac_start_note_does_bonus_damage = opt[0] calc_gimmick_damage_after = opt[1] apply_regular_note_damage_on_gimmicks = True combine_dr_and_type_factors = opt[2] calc_gimmick_damage_together_with_base = opt[3] combine_ac_and_acc_factors = opt[4] notemap = json.loads(open(ds["json"]).read()) result = True current_stamina = ds["max_stamina"] active_drs = [(d, 9999) for d in ds["dr_permanent"]] in_ac = False in_cleared_ac = False current_note_index = 0 current_ac_index = 0 current_known_index = 0 if output: print(notemap["song_name"], notemap["song_difficulty"]) print("Note", ",", "Base Note Dmg", ",", "Gimmick Dmg", ",", "AC", ",", "Star Note", ",", "Stamina", ",", "Stamina Pct", ",", "Active DR", ",", "Note Dmg", ",", "Gimmick Dmg", ",", "Known Gimmick Dmg", ",", "Failed") for n in notemap["notes"]: ed = 0 if current_ac_index < len(notemap["appeal_chances"]): if not in_ac: if current_note_index == notemap["appeal_chances"][current_ac_index]["range_note_ids"][0] + (0 if ac_start_note_does_bonus_damage else 1): in_ac = True else: if current_ac_index < len(ds["ac_clears"]) and current_note_index == ds["ac_clears"][current_ac_index]: in_cleared_ac = True if current_note_index == notemap["appeal_chances"][current_ac_index]["range_note_ids"][1]+1: in_ac = False in_cleared_ac = False current_ac_index += 1 gimmick_base_damage = 0 if n["gimmick"] is not None: gimmick = notemap["note_gimmicks"][n["gimmick"]] if gimmick["effect_type"] == 68: gimmick_base_damage = gimmick["effect_amount"] this_note_base = notemap["note_damage"] if apply_regular_note_damage_on_gimmicks or gimmick_base_damage == 0 else 0 this_note_gimm = gimmick_base_damage + (this_note_base if calc_gimmick_damage_together_with_base and gimmick_base_damage > 0 else 0) if calc_gimmick_damage_after: nd,_ = calc_damage(current_stamina, this_note_base, 0, ds["max_stamina"], ds["subunit_gd_bonus"], ds["necklaces"], [d[0] for d in active_drs], in_ac, in_cleared_ac, combine_ac_and_acc_factors, combine_dr_and_type_factors) _,gd = calc_damage(current_stamina - nd, 0, this_note_gimm, ds["max_stamina"], ds["subunit_gd_bonus"], ds["necklaces"], [d[0] for d in active_drs], in_ac, in_cleared_ac, combine_ac_and_acc_factors, combine_dr_and_type_factors) else: nd, gd = calc_damage(current_stamina, this_note_base, this_note_gimm, ds["max_stamina"], ds["subunit_gd_bonus"], ds["necklaces"], [d[0] for d in active_drs], in_ac, in_cleared_ac, combine_ac_and_acc_factors, combine_dr_and_type_factors) if calc_gimmick_damage_together_with_base and gimmick_base_damage > 0: gd -= nd if output and gimmick_base_damage > 0: print(current_note_index+1, ",", notemap["note_damage"] if apply_regular_note_damage_on_gimmicks else 0, ",", gimmick_base_damage if gimmick_base_damage > 0 else "", ",", in_ac, ",", in_cleared_ac, ",", current_stamina, ",", current_stamina/ds["max_stamina"], ",", sum([d[0] for d in active_drs]), ",", nd, ",", gd if gimmick_base_damage > 0 else "", ",", ds["known_damages"][current_known_index] if gimmick_base_damage > 0 and current_known_index < len(ds["known_damages"]) else "", ",", "XXX" if gimmick_base_damage > 0 and current_known_index < len(ds["known_damages"]) and gd != ds["known_damages"][current_known_index] else "") if gimmick_base_damage != 0 and current_known_index < len(ds["known_damages"]): if gd != ds["known_damages"][current_known_index]: if stop_on_fail: return False else: result = False current_known_index += 1 if current_ac_index < len(notemap["appeal_chances"]): if current_ac_index < len(ds["ac_clears"]) and current_note_index == ds["ac_clears"][current_ac_index] - 1: in_cleared_ac = True if current_note_index == notemap["appeal_chances"][current_ac_index]["range_note_ids"][1] and not in_cleared_ac: ed += notemap["appeal_chances"][current_ac_index]["penalty_damage"] current_stamina = max(0, current_stamina - nd - gd - ed) if current_note_index < len(ds["heals"]): current_stamina = min(ds["max_stamina"], current_stamina + ds["heals"][current_note_index]) if current_stamina == 0: return True active_drs = [(d[0], d[1] - 1) for d in active_drs if d[1] > 1] if current_note_index < len(ds["dr_notes"]): if ds["dr_notes"][current_note_index] != None: active_drs.append(ds["dr_notes"][current_note_index]) current_note_index += 1 return result def option_constraints_satisfied(op): return True def generate_all_options_possibilities(n): if n<=1: return [(True,), (False,)] res = [] for t in generate_all_options_possibilities(n-1): res.append(t + (True,)) res.append(t + (False,)) return res def check_option(opt): for ds in dataset: if not verify_dataset(ds, opt, True, False): return False return True def attempt_verification(): for opt in generate_all_options_possibilities(5): print(opt, "SUCCESS!!!!!!!!!!!!!!!!!!" if check_option(opt) else "fail") attempt_verification() def print_as_csv(ds, opt): verify_dataset(ds, opt, False, True) option = (True, False, True, False, False) #print() #print_as_csv(dataset[0], option) #print() #print_as_csv(dataset[1], option) #print() #print_as_csv(dataset[2], option) print() print_as_csv(dataset[3], option) #print() #print_as_csv(dataset[4], option) #print() #print_as_csv(dataset[5], option)