Skip to content

Instantly share code, notes, and snippets.

@Tokariew
Last active February 19, 2020 18:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Tokariew/be29edca21b3f8e995577c0f884c2baf to your computer and use it in GitHub Desktop.
Save Tokariew/be29edca21b3f8e995577c0f884c2baf to your computer and use it in GitHub Desktop.
Simple script to make plots with damage of bolt spells
import matplotlib.pyplot as plt
import numpy as np
class Spell:
"""Let's make some class to organize spells, so maybe in future i will define all bolt spell here"""
def __init__(self,
name,
mana_cost,
beg_lvl,
lvl_limit,
dmg_modif,
switch=0):
self.name = name
self.max_level = floor(
(50 - beg_lvl[0] + 1) * 1.4
) # calculate max lvl of spell with maxed school and spell-power
self.mana_cost = mana_cost
self.beg_lvl = beg_lvl
self.lvl_limit = lvl_limit
self.x = np.arange(
self.max_level) + 1 # we always start at zero, but we want at one.
self.lvls, y = np.meshgrid(
self.x, np.arange(3)
) # need array/matrix with identical vectors in each row, y is leftover
x = np.copy(self.lvls) # we will need this x for manathrust
self.dmg_modif = dmg_modif
y = np.zeros_like(
self.lvls) # make y the same shape like lvls matrix, but with 0
self.switch = switch # we will check if manathrust is in play
self.limit = [
beg_lvl[i] - beg_lvl[0] + 1 for i in range(len(beg_lvl))
] # one liner list with for
for i in range(len(self.lvl_limit)):
y[i, :] = self.lvl_limit[
i] # change y so each row have different values.
self.lvls[self.lvl_limit != 0] = y[self.lvl_limit != 0] + (
self.lvls[self.lvl_limit != 0] - y[self.lvl_limit != 0]
) / 3 # not very nice solution with boolean indexing
if self.switch == 0:
self.dice = [
self.dmg_modif[0] * self.lvls + self.dmg_modif[1],
self.dmg_modif[2] * self.lvls + self.dmg_modif[3]
]
if self.switch == 1:
self.dice = [
self.dmg_modif[0] * self.lvls + self.dmg_modif[1],
self.dmg_modif[2] * x + self.dmg_modif[3]
]
# up was calculated lvl the dice number and type, dice matrix is 3D
self.dice = np.floor(self.dice) # we don't like float, we want ints
self.dmg = self.dice[0] * (self.dice[1] +
1) / 2 # calculate actual damage
for i in range(len(self.limit)):
self.dmg[i, self.x < self.limit[
i]] = 0 # set dmg array to zero when we have to low skill
def plot(self):
plt.close('all') # make sure all other plots are close
f, (ax1, ax2) = plt.subplots(2, sharex=True, figsize=(16, 10))
# f is figure, ax1 and ax2 are subplots, with share x axis, and i like 16:10 ratio, size in inches
for i in range(len(self.lvl_limit)): # draw plots for every tier
ax1.plot(self.x,
self.dmg[i],
label='{} {}'.format(self.name, i + 1))
# use format for string if text have variables in it. don't use old % formatting
ax1.set_xlim(
1
) # we want to start with x axis at 1, not zero, at zero we cannot cast a spell
ax1.set_ylim(0) # don't show me dmg below zero
ax1.grid() # show grid
ax1.legend() # show labels, must have some label with data
ax1.set_ylabel('Avg damage')
ax1.axvline(
50 - self.beg_lvl[0] + 1, color='r'
) # vertical line when we have maxed school, and 0 in spell-power
ax1.set_title('Avg damage of {}'.format(self.name))
# below is second subplot
for i in range(len(self.lvl_limit)):
ax2.plot(self.x,
self.dmg[i] / self.mana_cost[i],
label='{} {}'.format(self.name, i + 1))
ax2.set_ylim(0)
ax2.grid()
ax2.legend()
ax2.set_ylabel('Avg damage / mana cost')
ax2.set_xlabel('Spell lvl')
ax2.axvline(50 - self.beg_lvl[0] + 1, color='r')
ax2.set_title('Mana efficiency of {}'.format(self.name))
f.tight_layout() # less spaced wasted on margins
f.set_dpi(300) # dpi of plot
f.savefig(
'{}.png'.format(self.name)
) # save plot in current catalog, with user provided name earlier
# uncomment below to save data for fire
'''
fn='Fire Bolt'
fm=np.array((3,6,12))
fb=np.array((10,25,40))
fll=np.array((1,15,0))
fd=(.6,5,.5,8)
fire=Spell(fn,fm,fb, fll, fd) # we don't need to provide switch, have def value
fire.plot()
'''
# user interactive part
name = input('Spell name: ')
mana_cost = input('Mana cost for each tier, separated by comma: ')
beg_lvl = input('First lvl for each tier: ')
lvl_limit = input('Limits lvl by tier: ')
print('Input damage modifiers (a * lvl + b )dices(c * lvl + e),')
dmg_modif = input(
'Input in form of "a,b,c,e" for acidbolt like this "0.6,6,0.5,9" : ')
dmg_modif = eval('(' + dmg_modif + ')')
mana_cost = np.array(eval('(' + mana_cost + ')'))
beg_lvl = np.array(eval('(' + beg_lvl + ')'))
lvl_limit = np.array(eval('(' + lvl_limit + ')'))
sw = input(
'Did spell use actuall lvl for type of dice, i.e. Manathrust [Y/N]:')
# i will not care if user don't provide correct output, at worse it will close at plot method with some error
if sw.upper() == 'Y':
switch = 1
elif sw.upper() == 'N':
switch = 0
first_spell = Spell(name, mana_cost, beg_lvl, lvl_limit, dmg_modif,
switch) # make instance with user defined values
first_spell.plot() # make and save plot
input(
'waiting…'
) # don't close window when we stop, wait for close or other enter/return
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment