Skip to content

Instantly share code, notes, and snippets.

@eddie-knight
Last active July 20, 2021 20:11
Show Gist options
  • Save eddie-knight/357077b8a786851cb8b8bafb37e992d2 to your computer and use it in GitHub Desktop.
Save eddie-knight/357077b8a786851cb8b8bafb37e992d2 to your computer and use it in GitHub Desktop.
import csv
## Player Weapons
#################
# 2h Weapons Note!
# two-handed weapons disable usage of the multi-tool (grapple, interact, repair, etc)
# Melee weapons are special two-handed weapons that specialize in ship DEFENSE
MELEE = "2h_melee"
# The pistol is the weapon type that can be equipped by players at all times
# low dps, small
PISTOL = "pistol"
# rifles are somewhat stronger than the pistol
# mid to high dps, mid to high range, small
RIFLE = "2h_rifle"
## Fixed Weapons
################
# a REPEATER is a fixed weapon with a small calibre and high rate of fire
# mid to low damage, high rate, mid range
REPEATER = "repeater"
# single-fire rocket launchers sacrifice damage in favor of distance and precision
# mid-to-low dps, high range
#
LAUNCHER = "rocket_launcher"
# Cannons balance range and rate of fire while achieving a high damage output
# high dps, mid range
CANNON = "cannon"
# HEAVY CANNONs have a high range and accuracy while sacrificing rate of fire
# high damage, high range, low rate
HEAVY = "heavy_cannon"
# Barrage rocket launchers sacrifice distance and precision in favor of high damage and/or rate of fire
# high dps, mid-to-low range, medium or large
BARRAGE = "barrage_rockets"
# point defense cannons will automatically fire at incoming rockets, disabling them if a successful hit is landed
# point DEFENSE weapons may look small, but the clear area on all sides requires them to be medium or large weapons
# low dps, mid-to-low range
DEFENSE = "point_defense"
# pulse weapons are weapons with a wider than normal area of attack, but short range
# any dps, low range, medium or large
PULSE = "pulse_weapon"
## Sizes
sm = "small"
md = "medium"
lg = "large"
co = "colossal"
# some value combinations may not be useful for our purposes
skipped = "skipped"
unhandled = "unhandled"
class StatBlock:
def __init__(self, dmg, rate, accuracy, eff):
self.damage = dmg
self.rate = rate
self.accuracy = accuracy
self.efficiency = eff
self.size = None
self.items = [self.damage,
self.rate,
self.accuracy,
self.efficiency]
self.value = sum(self.items)
self.prepare()
def small(self):
return self.value == 10
def medium(self):
return self.value == 15
def large(self):
return self.value == 20
def colossal(self):
return self.value == 25
def prepare(self):
if not self.small() and self.efficiency > self.damage + self.rate + self.accuracy:
return
if self.small():
self.size = sm
elif self.medium():
self.size = md
elif self.large():
self.size = lg
elif self.colossal():
self.size = co
else:
return
self.weapon_class = self.get_weapon_class()
self.items.append(self.size)
def high(self, value):
if self.small() and value >= 5:
return True
if self.medium() and value >= 6:
return True
if (self.large() or self.colossal()) and value >= 8:
return True
return False
def mid(self, value):
if self.small() and (value == 3 or value == 4):
return True
if self.medium() and (value == 4 or value == 5):
return True
if (self.large() or self.colossal()) and (value >= 5 and value <= 8):
return True
return False
def low(self, value):
if self.small() and value < 3:
return True
if self.medium() and value < 4:
return True
if (self.large() or self.colossal()) and value < 5:
return True
return False
def get_values(self):
return (self.damage, self.rate, self.accuracy, self.efficiency)
def get_weapon_class(self):
damage, rate, accuracy, efficiency = self.get_values()
if accuracy == 1:
if self.small() and not self.mid(damage+rate):
return MELEE
return skipped
if self.small(): # small may be range=2: lowest accuracy
if self.low(damage+rate) \
or (self.low(accuracy) and (self.low(damage) or self.low(rate))):
return PISTOL # low DPS -OR- low damage/rate and low range
if not self.low(damage+rate) and not self.low(accuracy):
return RIFLE
return CANNON
if accuracy == 2: # med or large range=2 are point DEFENSE: low distance
if not self.colossal():
return DEFENSE
return skipped # no colossal point DEFENSE weapons
if self.low(damage) and self.low(accuracy) and self.low(rate):
return skipped # anything weak left by this point should be dropped
if self.low(accuracy):
if self.high(rate):
return BARRAGE
if self.high(damage):
return PULSE
return skipped
if self.mid(accuracy) and not self.low(damage):
if self.high(rate):
return REPEATER
if self.high(damage) and self.low(rate):
return CANNON
if self.high(accuracy):
if self.low(rate) and self.low(damage):
return LAUNCHER
if self.high(damage) and self.low(rate):
return HEAVY
return skipped
return unhandled
def entries():
# tite_row = ["damage", "rate", "range", "cost efficiency", "type", "size"]
data = {
MELEE: [],
PISTOL: [],
RIFLE: [],
REPEATER: [],
CANNON: [],
HEAVY: [],
LAUNCHER: [],
BARRAGE: [],
DEFENSE: [],
PULSE: [],
skipped: [],
unhandled: [],
}
i = 0
for dmg in list(range(1, 11)):
for rate in list(range(1, 11)):
for rng in list(range(1, 11)):
for eff in list(range(1, 11)):
entry = StatBlock(dmg, rate, rng, eff)
if entry.size:
data[entry.weapon_class].append(entry.items)
if entry.weapon_class is not skipped \
and entry.weapon_class is not unhandled:
i += 1
del data[skipped]
del data[unhandled]
return data, i
def sort_data(data):
tree = []
for value in list(range(1,11)):
for entry in data:
if entry[3] == value:
tree.append(entry)
return tree
def write_data(data, size):
with open(f'{size}.csv', 'w', newline='') as f:
writer = csv.writer(f)
writer.writerows(data)
def main():
data, count = entries()
for category in data:
sorted_data = sort_data(data[category])
print(f"Entries for {category}: {len(sorted_data)}")
write_data(sorted_data, category)
print(f"Entries in Knowledge Tree: {count}")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment