-
-
Save cltnschlosser/e3b792cbeb10ae54107c1c72e1536be9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from itertools import product | |
from typing import Dict, Tuple | |
import sys | |
melee_as = 3.9 | |
ranged_as = 2.9 | |
ranged_haste = 1.15 * 1.2 | |
auto_damage, steady_damage, raptor_damage, attack_damage = 1463, 1457, 1432, 1207 | |
_ranged_cd = (ranged_as - .5) / ranged_haste | |
i_cast_time = 0 | |
i_cooldown = 1 | |
i_damage = 2 | |
i_shared_cd = 3 | |
i_gcd = 4 | |
# skill, cast_time, cooldown, damage, relies on CD, gcd | |
actions : Dict[str, Tuple[float, int, int, str, bool]] = { | |
"attack": (.4, melee_as, attack_damage, "", False), | |
"raptor": (.4, 6, raptor_damage, "attack", False), | |
"auto": (.5 / ranged_haste, _ranged_cd, auto_damage, "", False), | |
"steady": (1.5 / ranged_haste, 0, steady_damage, "", True), | |
"multi": (0.5 / ranged_haste, 10, steady_damage + 170,"", True), | |
"arcane": (0, 6, 900, "", True), | |
} | |
# Commenting out skills above can help runtime quite a bit | |
index_of = dict(zip(actions.keys(), range(len(actions)))) | |
GCD_SLOT = len(actions) | |
def update_cooldowns(cooldowns, time_before_action, action_name): | |
wait_time = max(cooldowns[index_of[action_name]] - time_before_action, 0) | |
if depends_on := actions[action_name][i_shared_cd]: | |
wait_time = max(wait_time, cooldowns[index_of[depends_on]] - time_before_action) | |
if uses_gcd := actions[action_name][i_gcd]: | |
wait_time = max(wait_time, cooldowns[GCD_SLOT] - time_before_action) | |
# print(f'{action_name}: {wait_time}') | |
cast_time = actions[action_name][i_cast_time] | |
time_spent = time_before_action + cast_time + wait_time | |
cooldowns = [max(cd - time_spent, 0) for cd in cooldowns] | |
cooldowns[index_of[action_name]] = actions[action_name][i_cooldown] | |
if depends_on: | |
cooldowns[index_of[depends_on]] = actions[depends_on][i_cooldown] | |
if uses_gcd: | |
cooldowns[GCD_SLOT] = max(0, 1.5 - cast_time) | |
return time_spent, cooldowns | |
input_lag = 0 # BRRTTTT | |
def solve_sequence(sequence): | |
total_damage = 0 | |
total_time = 0 | |
cooldowns_remaining = [0] * (len(actions) + 1) | |
earliest_cast = [float("inf")] * (len(actions) + 1) | |
for action_name, values in sequence: | |
cast_time, cooldown, damage, shared_cd, uses_gcd = values | |
if earliest_cast[index_of[action_name]] == float("inf"): | |
earliest_cast[index_of[action_name]] = total_time | |
if shared_cd and earliest_cast[index_of[shared_cd]] == float("inf"): | |
earliest_cast[index_of[shared_cd]] = total_time | |
if uses_gcd and earliest_cast[GCD_SLOT] == float("inf"): | |
earliest_cast[GCD_SLOT] = total_time | |
time_before_action = input_lag # for the action | |
time_spent, cooldowns_remaining = update_cooldowns(cooldowns_remaining, time_before_action, action_name) | |
total_damage += damage | |
total_time += time_spent | |
wait_before_repeating = input_lag + max(max(cdr - earliest, 0) for earliest, cdr in zip(earliest_cast, cooldowns_remaining)) | |
# print(f'repeating_wait: {wait_before_repeating}') | |
# print() | |
# for i in range(len(cooldowns_remaining) - 1): | |
# print(f'{list(actions.keys())[i]}: {cooldowns_remaining[i]}') | |
total_damage = total_damage | |
total_time = total_time + wait_before_repeating | |
return total_damage, total_time | |
# Sequence checker, run with action names as arguments. | |
# Ex: python3 dumb_sim.py auto steady attack auto steady auto steady | |
if len(sys.argv) > 1: | |
sequence = [(name, actions[name]) for name in sys.argv[1:]] | |
total_damage, total_time = solve_sequence(sequence) | |
dps = total_damage / total_time | |
print(dps) | |
print((total_damage, total_time, tuple(action for action, *_ in sequence))) | |
sys.exit(0) | |
best_dps = 0 | |
best_sequence = (0, 10, ()) | |
for sequence_length in range(5, 11): | |
print(f"Solving for length {sequence_length}...") | |
for sequence in product(actions.items(), repeat=sequence_length): | |
total_damage, total_time = solve_sequence(sequence) | |
if total_damage / total_time > best_dps: | |
best_dps = total_damage / total_time | |
best_sequence = (total_damage, total_time, tuple(action for action, *_ in sequence)) | |
print(f'New best: {best_sequence}') | |
print(best_dps) | |
print(best_sequence) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment