Skip to content

Instantly share code, notes, and snippets.

@robfrawley
Last active October 15, 2025 11:16
Show Gist options
  • Select an option

  • Save robfrawley/fcc90744e5ea8b76b4904bcc809d40fc to your computer and use it in GitHub Desktop.

Select an option

Save robfrawley/fcc90744e5ea8b76b4904bcc809d40fc to your computer and use it in GitHub Desktop.
Crit Simulator
import sys
import random
# configure simulation parameters
crit_multiplier = float(sys.argv[1]) if len(sys.argv) > 1 else 2.0 # the crit damage multiplier, read from cli args or default to 2.0 (fixed value)
base_damage = 100 # base damage per shot (fixed value)
base_crit_chance = 0.05 # 5% base crit chance (fixed value)
crit_chance = base_crit_chance # current crit chance, starts at base crit chance
shots_per_second = 2 # total shots every second (fixed value)
total_shots = 1000000 # total number of shots to simulate (fixed value)
total_crits = 0 # total number of crits during the simulation
total_damage = 0.0 # total damage dealt during the simulation
total_crit_chance_when_critting = 0.0 # total crit chance value when a crit occurs
crit_cooldown = 0 # number of shots until next crit is allowed, starts at 0
# simulate the shots
for _ in range(total_shots - 1):
# determine if the shot is a crit, random returns a float between 0.0 and 1.0
is_crit = random.random() < crit_chance and crit_cooldown == 0
# calculate damage for the shot, base_damage or base_damage*crit_multiplier for crits
damage = base_damage * crit_multiplier if is_crit else base_damage
# add damage to total damage
total_damage += damage
# adjust crit chance for next shot, if crit:
if is_crit:
crit_cooldown = (shots_per_second * 5) + 1; # set crit cooldown to (shots_per_second (2 shots) * 5 seconds) + 1 = 11 shots, one extra to account for the current shot
total_crits += 1 # track total number of crit shots
total_crit_chance_when_critting += crit_chance # add the crit chance to the total crit chance
crit_chance = base_crit_chance # reset crit chance back to base chance (5%) after a crit
# if not a crit and not on cooldown:
elif not is_crit and crit_cooldown == 0:
crit_chance += base_crit_chance # increase crit chance by base crit chance (5%) when not a crit
crit_cooldown = max(0, crit_cooldown - 1) # decrease crit cooldown by 1, min of 0
# output simulation results
average_damage_dealt = total_damage / total_shots
print(f"Base Damage: {base_damage}")
print(f"Base Crit Chance: {base_crit_chance * 100}%")
print(f"Total Shots: {total_shots:,}")
print(f"Total Crits: {total_crits:,}")
print(f"Percent of Shots that Critted: {(total_crits / total_shots) * 100:.2f}%")
print(f"Crit Multiplier: {crit_multiplier}x")
print(f"Average Damage Dealt: {average_damage_dealt:.2f}")
print(f"Average Damage Dealt Over Base Damage: {((average_damage_dealt - base_damage) / base_damage) * 100:.2f}%")
print(f"Average Crit Chance Value For Crit Hits: {total_crit_chance_when_critting / total_crits * 100:.2f}%")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment