Talk:Basement Diving Guide

From A KoL Wiki
Revision as of 21:13, 12 November 2007 by imported>Bagatelle (New page: ==Code== For reasons of generality, the buff rate on the article is entirely arbitrary, and excludes equipment. That's unreasonable in practice, so here's some [http://python.org/ Python] ...)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Code

For reasons of generality, the buff rate on the article is entirely arbitrary, and excludes equipment. That's unreasonable in practice, so here's some Python code that can calculate base stat/damage at given basement levels, as well as required main stat given a buff level that a player can maintain. It'll spit out two tables of tab-separated data, which should be able to be copy-pasted into any decent spreadsheet program. --Bagatelle 15:13, 12 November 2007 (CST)

################################################################################
# control outputs

# interval between basement levels to output...
# so 25 would output every 25th level
BLStep = 25

# minimum level to output
BLStart = 24

# maximum level to output, subject to BLStep and BLStart parameters
# i.e., it is possible to output zero levels if these parameters
# have strange values
BLEnd = 500

# percentage to pad tests when calculating challenge numbers
# 0 to suppress padding rows
PadPct = 5

# for those who wish to display ONLY padded output for the damage/required
# main stat tables, set this to "False"
# so setting PadPct = 0 and PrintUnpadded = False will guarantee empty output
PrintUnpadded = False

# whether to print basement levels that are multiples of 5
# usually set to "False" because levels mod 5 are always rewards, so
# no point in printing them
# however, if BLStep, BLStart, BLEnd are set to output only multiples of 5,
# the program will output an empty table
Print5 = False

################################################################################
# character/buff configuration: used to calculate main stat required to
# complete a dive

# the script has no error-checking, so don't be a nut a say "True" to both
# Seal Clubber/Turtle Tamer?
MusChar = True
# Pastamancer/Sauceror?
MysChar = False

# HP/MP percentage boosts: do you have these skills available?
GnomishHardigness = False
CosmicUgnderstanding = True
WisdomOfTheElderTortoises = True
SpiritOfRavioli = True

# Outfit data: all outfits assume you are not suffering a
# NET negative effect on stats

# input total percentages for equipment/effects using "Pct" parameters
# input total absolute modifiers for equipment/effects using "Abs" parameters
# input the equipment/buffs you are willing to sustain for the entire dive

# Muscle outfit
MusPct = 900
MusAbs = 50
# Mysticality outfit
MysPct = 900
MysAbs = 50
# Moxie outfit
MoxPct = 900
MoxAbs = 50

# HP outfit: ignores DR, which is negligible at high BL
HPMusPct = 800
HPMusAbs = 50
HPAbs = 0
HPDA = 1000

# MP outfit
MPMysPct = 900
MPMysAbs = 50
MPAbs = 0

# Elemental resistance outfit: assumes outfit is the same for all elements
EltMusPct = 900
EltMusAbs = 50
EltHPAbs = 0
EltPct = 60

# end configuration
# do not edit anything below this line
################################################################################
from math import *

# standardise percents into multiplier fractions
MusFrac = 1 + MusPct / 100.0
MysFrac = 1 + MysPct / 100.0
MoxFrac = 1 + MoxPct / 100.0
DAFrac = 1 - (sqrt(HPDA / 10) - 1) / 10
EltFrac = 1 - EltPct / 100.0
EltMusFrac = 1 + EltMusPct / 100.0
HPMusFrac = 1 + HPMusPct / 100.0
MPMysFrac = 1 + MPMysPct / 100.0
PadFrac = 1 + PadPct / 100.0

# change passive "skills" into multipliers
if MusChar:
  ClassHP = 1.5
else:
  ClassHP = 1.0
if MysChar:
  ClassMP = 1.5
else:
  ClassMP = 1.0
if WisdomOfTheElderTortoises:
  MPWisdom = 1.5
else:
  MPWisdom = 1.0
if CosmicUgnderstanding:
  MPCosmic = 1.05
else:
  MPCosmic = 1.0
if SpiritOfRavioli:
  HPSpirit = 1.25
else:
  HPSpirit = 1.0
if GnomishHardigness:
  HPHardiness = 1.05
else:
  HPHardiness = 1.0

# generate headers for list of basement data
BL = dict(
  BL = "BL", Stat = "Stat", Elt = "Elt (2x)", Phys = "Phys", Drain = "Drain"
)
Basement = [BL]
# calculate challenge data for desired basement levels
for Level in range(BLStart, BLEnd, BLStep):
  if Print5 or Level % 5 != 0:
    # format harddrive
    Basement.append(dict(
      BL = Level, Stat = Level**1.4 + 2, Elt = 4.48 * Level**1.4 + 8,
      Phys = 10 * Level**1.4, Drain = 1.67 * Level**1.4
    ))

# calculate chart of stat/damage done for common stat levels
for Rec in range(0, len(Basement)):
  Level = Basement[Rec]
  if Rec == 0:
    # header row
    TestStrengths = [[
      ["BL"], ["Stat"],
      ["Phys (0% DA)", "Phys (60% DA)", "Phys (90% DA)"],
      ["Drain"],
      ["Elt (0% Res)", "Elt (60% Res)", "Elt (80% Res)"]
    ]]
  else:
    # calculate unrounded numbers for common stat levels
    TempArray = [
      [Level["BL"]], [Level["Stat"]],
      [Level["Phys"], 0.4 * Level["Phys"], 0.1 * Level["Phys"]],
      [Level["Drain"]],
      [Level["Elt"], 0.4 * Level["Elt"], 0.2 * Level["Elt"]]
    ]
    # unpadded data: round up
    if PrintUnpadded:
      TestStrengths.append(
        [[repr(TempArray[0])]] + \
          [map(lambda x: int(ceil(x)), Arr) for Arr in TempArray[1:]]
      )
    # padded numbers: pad, then round up
    if PadPct != 0:
      TestStrengths.append(
        [[repr(TempArray[0][0]) + " (" + repr(PadPct) + "% padding)"]] + \
          [map(lambda x: int(ceil(PadFrac * x)), Arr) for Arr in TempArray[1:]]
      )

# calculate required main stat given sustained buffed main stat and
# character configurations as defined by parameters
for Rec in range(0, len(TestStrengths)):
  Level = TestStrengths[Rec]
  if Rec == 0:
    ReqStat = [["BL", "Mus", "Mys", "Mox", "Phys", "Drain", "Elt"]]
  else:
    # the HP/MP backsolve formulae are not exact, because ceiling() and floor()
    # do not have inverse functions
    # however, the large numbers involved and the understanding that there
    # is basement variation anyway makes this largely irrelevant

    # for each basement level with calculated data (including padded data,
    # if calculated), backsolve main stat for three stat tests,
    # HP/MP tests, and elemental test
    ReqStat.append(
      [Level[0][0]] + map(lambda x: int(ceil(x)), [
        # Muscle
        (Level[1][0] - MusAbs) / MusFrac,
        # Mysticality
        (Level[1][0] - MysAbs) / MysFrac,
        # Moxie
        (Level[1][0] - MoxAbs) / MoxFrac,
        # HP
        (
          (DAFrac * Level[2][0] / (HPHardiness * HPSpirit) - HPAbs) / ClassHP \
            - 3 - HPMusAbs
        ) / HPMusFrac,
        # MP
        (Level[3][0] / (MPCosmic * MPWisdom) - MPMysAbs - MPAbs) / MPMysFrac,
        # Elemental
        (
          (EltFrac * Level[4][0] / (HPHardiness * HPSpirit) - EltHPAbs) / \
            ClassHP - 3 - EltMusAbs
        ) / EltMusFrac
      ])
    )

# flatten list of lists into a single list
def Flatten(Arg):
  Val = []
  for Arr in Arg:
    if isinstance(Arr, str) or isinstance(Arr, int):
      Val.append(Arr)
    else:
      # kmail all your rares to a random account
      Val += Arr
  return Val

# tab-separated output
def TabPrint(InList):
  Table = ""
  for Rec in InList:
    Line = "\n"
    Rec = Flatten(Rec)
    for Item in Rec:
      Line += str(Item) + "\t"
    Table += Line
  print Table

print "Test Strengths"
TabPrint(TestStrengths)
print "\nRequired Main Stat (w/ equalising potions and calculated buffs)"
TabPrint(ReqStat)