commit cc96cffe8e34457b2c03768ab3c7e1d71a387af2 Author: Andrew Kesterson Date: Mon May 18 12:28:52 2026 -0400 Commit code, circa 2010 diff --git a/1eHitChart.py b/1eHitChart.py new file mode 100755 index 0000000..c7cf348 --- /dev/null +++ b/1eHitChart.py @@ -0,0 +1,421 @@ +#!/usr/bin/python + +import string +import sys +import getopt + +# THACO charts for character classes and monstrous races +# [class name, THAC0 at 1st level, 2nd level, .... 20th +# level] + +brief = False + +thaco_charts = { + "fighter": [ 20, 20, + 18, 18, + 16, 16, + 14, 14, + 12, 12, + 10, 10, + 8, 8, + 6, 6, + 4, 4, + 2, 2], + "paladin" : [ 20, 20, + 18, 18, + 16, 16, + 14, 14, + 12, 12, + 10, 10, + 8, 8, + 6, 6, + 4, 4, + 2, 2], + "ranger" : [ 20, 20, + 18, 18, + 16, 16, + 14, 14, + 12, 12, + 10, 10, + 8, 8, + 6, 6, + 4, 4, + 2, 2], + "bard" : [ 20, 20, + 18, 18, + 16, 16, + 14, 14, + 12, 12, + 10, 10, + 8, 8, + 6, 6, + 4, 4, + 2, 2], + "cleric" : [ 20, 20, 20, + 18, 18, 18, + 16, 16, 16, + 14, 14, 14, + 12, 12, 12, + 10, 10, 10, + 9, 9], + "druid" : [ 20, 20, 20, + 18, 18, 18, + 16, 16, 16, + 14, 14, 14, + 12, 12, 12, + 10, 10, 10, + 9, 9], + "monk" : [ 20, 20, 20, + 18, 18, 18, + 16, 16, 16, + 14, 14, 14, + 12, 12, 12, + 10, 10, 10, + 9, 9], + "magic user" : [20, 20, 20, 20, 20, + 19, 19, 19, 19, 19, + 16, 16, 16, 16, 16, + 13, 13, 13, 13, 13], + "illusionist" :[20, 20, 20, 20, 20, + 19, 19, 19, 19, 19, + 16, 16, 16, 16, 16, + 13, 13, 13, 13, 13], + "thief" : [ 20, 20, 20, 20, + 19, 19, 19, 19, + 16, 16, 16, 16, + 14, 14, 14, 14, + 12, 12, 12, 12], + "assassin" : [ 20, 20, 20, 20, + 19, 19, 19, 19, + 16, 16, 16, 16, + 14, 14, 14, 14, + 12, 12, 12, 12], + "monster" : [ 19, + 16, 16, 16, + 15, 15, + 13, 13, + 12, 12, + 10, 10, + 9, 9, + 8, 8, + 7, 7, 7, 7]} + +melee_weapon_charts = [ + # name AC 10 to 2 (from 10 to 2) + ["unarmed", 4, 0, 2, 0, 0, -1, -3, -5, -7], + ["battle axe", 2, 1, 1, 0, 0, -1, -2, -2, -2], + ["hand axe", 1, 1, 1, 0, 0, -1, -2, -2, -2], + ["bardiche", 3, 2, 2, 1, 1, 0, 0, -1, -2], + ["bec de corbin", + -1, 0, 0, 0, 0, 0, 2, 2, 2], + ["bill-guisarme", + 0, 0, 1, 0, 0, 0, 0, 0, 0], + ["bo stick", 3, 0, 1, 0, -1, -3, -5, -7, -9], + ["club", 1, 0, 0, -1, -1, -2, -3, -4, -5], + ["dagger", 3, 1, 1, 0, 0, -2, -2, -3, -3], + ["fauchard", -1, 1, 0, 0, 0, -1, -1, -2, -2], + ["fauchard-fork", + 1, 0, 1, 0, 0, 0, -1, -1, -1], + ["footman's flail", + -1, 1, 1, 1, 1, 2, 1, 2, 2], + ["horseman's flail", + 0, 1, 1, 1, 0, 0, 0, 0, 0], + ["military fork", + 1, 0, 1, 1, 0, 0, -1, -2, -2], + ["glaive", 0, 0, 0, 0, 0, 0, 0, -1, -1], + ["glaive-guisarme", + 0, 0, 0, 0, 0, 0, 0, -1, -1], + ["guisarme", -1, -1, 0, 0, 0, -1, -1, -2, -2], + ["guisarme-voulge", + 0, 0, 0, 1, 1, 1, 0, -1, -1], + ["halberd", 0, 1, 1, 2, 2, 2, 1, 1, 1], + ["lucern hammer", + 0, 0, 1, 1, 2, 2, 2, 1, 1], + ["hammer", 0, 0, 0, 0, 0, 1, 0, 1, 0], + ["jo stick", 2, 0, 1, 0, -1, -2, -4, -6, -8], + ["heavy lance", 0, 0, 1, 1, 2, 2, 2, 3, 3], + ["light lance", 0, 0, 0, 0, 0, 0, -1, -2, -2], + ["medium lance",0, 0, 0, 0, 1, 1, 1, 1, 0], + ["footman's mace", + -1, 1, 0, 0, 0, 0, 0, 1, 1], + ["horseman's mace", + 0, 0, 0, 0, 0, 0, 0, 1, 1], + ["morning star",2, 2, 1, 1, 1, 1, 1, 1, 0], + ["partisan", 0, 0, 0, 0, 0, 0, 0, 0, 0], + ["military footman's pick", + -2, -1, -1, -1, 0, 1, 1, 2, 2], + ["military horseman's pick", + -1, -1, -1, 0, 0, 1, 1, 1, 1], + ["awl pike", -2, -1, 0, 0, 0, 0, 0, 0, -1], + ["ranseur", 1, 0, 0, 0, 0, 0, -1, -1, -2], + ["scimitar", 3, 1, 1, 0, 0, -1, -2, -2, -3], + ["spear", 0, 0, 0, 0, 0, -1, -1, -1, -2], + ["spetum", 2, 1, 0, 0, 0, 0, 0, -1, -2], + ["quarter staff", + 1, 1, 1, 0, 0, -1, -3, -5, -7], + ["bastard sword", + 0, 1, 1, 1, 1, 1, 1, 0, 0], + ["broad sword", 2, 1, 1, 1, 0, 0, -1, -2, -3], + ["long sword", 2, 1, 0, 0, 0, 0, 0, -1, -2], + ["short sword", 2, 0, 1, 0, 0, 0, -1, -2, -3], + ["two handed sword", + 0, 1, 3, 3, 3, 2, 2, 2, 2], + ["trident", 1, 0, 1, 0, 0, -1, -1, -2, -3], + ["voulge", 0, 0, 0, 1, 1, 1, 0, -1, -1], + # placeholder... + ["", 0, 0, 0, 0, 0, 0, 0, 0, 0]] + +ranged_weapon_charts = [ + ["hand axe", 1, 0, 0, 0, -1, -1, -2, -3, -4], + ["composite long bow", + 3, 3, 2, 2, 1, 0, 0, -1, -2], + ["composite short bow", + 3, 2, 2, 2, 1, 0, -1, -3, -3], + ["long bow", 3, 3, 3, 3, 2, 1, 0, 0, -1], + ["short bow", 2, 2, 2, 1, 0, 0, -1, -4, -5], + ["club", 0, 0, -1, -1, -1, -2, -3, -5, -7], + ["heavy crossbow", + 4, 4, 4, 3, 3, 2, 1, 0, -1], + ["light crossbow", + 3, 3, 3, 2, 1, 0, 0, -1, -2], + ["dagger", 1, 0, 0, -1, -1, -2, -3, -4, -5], + ["dart", 1, 0, 1, 0, -1, -2, -3, -4, -5], + ["hammer", 1, 0, 0, 0, 0, 0, 0, -2, -2], + ["javelin", 1, 0, 1, 0, -1, -2, -3, -4, -5], + ["sling w/bullet", + 3, 1, 2, 0, 0, 0, -1, -2, -2], + ["sling w/stone", + 3, 1, 2, 0, 0, -1, -2, -4, -5], + ["spear", 0, 0, 0, 0, -1, -2, -2, -3, -3]] + +strength_bonuses = [ 0, 0, 0, -3, -2, -2, + -1, -1, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1] +strength_bonuses_18 = { 50 : 1, 75: 2, 90 : 2, 99 : 2, 100: 3} + +dexterity_bonuses = [ 0, 0, 0, -3, -2, -1, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 2, 3] + +def findWeapon(type, name): + wlist = [] + if ( type == "ranged" ): + wlist = ranged_weapon_charts + elif ( type == "melee" ): + wlist = melee_weapon_charts + else : + return [] + for weapon in wlist: + #print "trying weapon %s (%s) against name %s" % (weapon, weapon[0], name) + if ( weapon[0].lower() == name.lower() ): + return weapon + return [] + +def strBonus(strength): + percent = 0 + if ( string.find(str(type(strength)), "str") != -1) : + if ( strength.find("/") != -1): + tlist = strength.split("/") + percent = int(tlist[1]) + if ( percent == 0 ) : + percent = 100 + for perc in strength_bonuses_18.keys(): + if ( perc >= percent ): + return strength_bonuses_18[perc] + else: +# print "recursing with strength %d..." % int(strength) + return strBonus(int(strength.strip())) + else: + if ( strength <= 17): +# print "trying to return from strength_bonuses (len %d ) %d" % (len(strength_bonuses), strength) + return strength_bonuses[strength-1] + if ( strength >= 19): + return strength_bonuses_18[100] + ((strength-19)/2) + return 0 + +def dexBonus(score): +# print "trying to return from dexterity_bonuses ( len %d ) %d" % (len(dexterity_bonuses), score) + if ( score <= 18): + return dexterity_bonuses[score] + else : + return dexterity_bonuses[18] + (score-18) + +class character : + weapons = [] + strength = 0 + dexterity = 0 + charts = {} + chartSteps = {} + pclass = "" + level = 0 + + def __init__ (self, className, str, dex, level): + self.pclass = className + self.level = level + self.weapons = [] + self.strength = str + self.dexterity = dex + self.charts = {} + self.chartSteps = {} + + # work out the THAC0 chart + THAC0chart = [] + baseTHAC0 = thaco_charts[self.pclass][self.level] + for i in range(2, 11): + THAC0chart.append(baseTHAC0 - i) + #print "wrote thac0 chart %s" % THAC0chart + self.charts["Base To Hit"] = THAC0chart + + + def chartWeapon(self, weaponInfo): + """chart a weapon for THACO given its type + and name""" + self.chartSteps[weaponInfo[1]] = {} + weaponModifiers = findWeapon(weaponInfo[0], weaponInfo[1]) + weaponModifiers.reverse() + + if ( len(weaponModifiers) == 0): + self.chartSteps[weaponInfo[1]]["base weapon modifiers"] = "Unable to chart %s" % weaponInfo[1] + return + else: + self.chartSteps[weaponInfo[1]]["base weapon modifiers"] = weaponModifiers[:9] + + newChart = [] + thacoChart = self.charts["Base To Hit"] + #print "weaponModifiers is : %s", str(weaponModifiers) + for ac in range(0, 9): + #print "trying ac of %d and modifier of %d : length of weaponModifiers is %d, THAC0 is %d" % (ac, ac, len(weaponModifiers), len(thacoChart)) + newChart.append( thacoChart[ac] + -weaponModifiers[ac]) + + self.chartSteps[weaponInfo[1]]["applied to base THAC0"] = newChart + newestChart = [] + for ac in newChart: + if ( weaponInfo[0] == "ranged"): + newestChart.append(ac + -dexBonus(self.dexterity)) + else: + newestChart.append(ac + -strBonus(self.strength)) + self.chartSteps[weaponInfo[1]]["after ability bonuses"] = newestChart + self.charts[weaponInfo[1]] = newestChart + weaponModifiers.reverse() + return 0 + + def printChart(self, weapName, chart, fileHandle, makeDashes = False): + printedChart = string.center(weapName, 30) +# print "chart is %d elements long : %s" % (len(chart), str(chart)) + for ac in range(0, 9): + if ( chart[ac] <= 0 and makeDashes): + chart[ac] = "-" + printedChart += string.center(str(chart[ac]), 4) + printedChart += "\n" + fileHandle.write(printedChart) + + def writeCharts(self, fileHandle): + global brief + for weapon in self.weapons: + self.chartWeapon(weapon) + ACChart = string.center("1st Edition AD&D To Hit Charts", 70) + "\n" + ACChart += string.center("%d level %s : strength %s (to hit +%d) dexterity %d ( RAA +%d)" % (self.level, self.pclass, +self.strength, strBonus(self.strength), self.dexterity, dexBonus(self.dexterity)), 70) + "\n\n" + ACChart += " "*30 + string.center("OPPONENT ARMOR CLASS", 40) + "\n" + ACChart += string.center("WEAPON", 30) + for ac in range(2, 11): + ACChart += string.center(str(ac), 4) + ACChart += "\n" + fileHandle.write(ACChart) + fileHandle.write("="*70 + "\n") + thecharts = self.charts.keys() + thecharts.sort() + for chart in thecharts: + self.printChart(chart.upper(), self.charts[chart], fileHandle, True) + #print "brief was %s" % str(brief) + if ( (chart != "Base To Hit") and (not brief)): + self.printChart("(Base To Hit)", self.charts["Base To Hit"], fileHandle) + self.printChart("(base modifiers)", self.chartSteps[chart]["base weapon modifiers"], fileHandle) + self.printChart("(applied to Base To Hit)", self.chartSteps[chart]["applied to base THAC0"], fileHandle) + self.printChart("(after ability bonuses)", self.chartSteps[chart]["after ability bonuses"], fileHandle) + if ( not brief) : + fileHandle.write("\n") + if ( not brief): + fileHandle.write("\n" + string.center("For ACs below 2, add that much to the indicated difficulty.", 70) + "\n") + fileHandle.write("\n" + string.center("A difficulty of \"-\" indicates that you can only miss", 70) + "\n" + string.center("this armor class with the given weapon on a botch.", 70) + "\n") +def main(argc, argv): + global brief + longopts = ["class=", "level=", "strength=", + "dexterity=", "ranged=", "melee=", "help", + "brief", "weaponlist"] + shortopts = "c:l:s:d:r:m:hbw" + usage = """ +1eHitChart.py (2006 Gamecube) +usage: 1eHitChart.py +options: + --class | -c : class name + --level | -l : level number + --strength | -s : strength score + --dexterity | -d : dexterity score + --ranged | -r : ranged weapons; use a comma + separated list + --melee | -m : melee weapons; use a comma + separated list + --brief | -b : do not print an explanatory + verbose summary; just print + the charts. + --weaponlist | -w : print out a list of all + weapons this program recognises + --help | -h : this help +""" + + pclass = "" + level = 0 + strength = "" + dexterity = 0 + weapons = [] + + #print "got sys.argv %s" % str(sys.argv) + opts, args = getopt.getopt(argv[1:], shortopts, longopts) + #print "got opts %s args %s" % ( str(opts), str(args)) + for pair in opts: + #print "checking pair %s" % str(pair) + if (pair[0] == "--class" or pair[0] == "-c"): + pclass = pair[1] + elif ( pair[0] == "--level" or pair[0] == "-l"): + level = int(pair[1]) + elif ( pair[0] == "--strength" or pair[0] == "-s"): + strength = pair[1] + elif ( pair[0] == "--dexterity" or pair[0] == "-d"): + dexterity = int(pair[1]) + elif ( pair[0] == "--ranged" or pair[0] == "-r"): + for item in pair[1].split(","): + weapons.append(["ranged", item.strip()]) + elif ( pair[0] == "--melee" or pair[0] == "-m"): + for item in pair[1].split(","): + weapons.append(["melee", item.strip()]) + elif ( pair[0] == "--help" or pair[0] == "-h"): + print usage + sys.exit(1) + elif ( pair[0] == "--brief" or pair[0] == "-b"): + brief = True + elif ( pair[0] == "--weaponlist" or pair[0] == "-w"): + print "Valid melee weapons:" + for i in range(0, len(melee_weapon_charts), 3): + print "%s%s%s" % ( string.center(melee_weapon_charts[i][0], 70/3), string.center(melee_weapon_charts[i+1][0], 70/3), string.center(melee_weapon_charts[i+2][0], 70/3)) + print "\nValid ranged weapons:" + for i in range(0, len(ranged_weapon_charts), 3): + print "%s%s%s" % ( string.center(ranged_weapon_charts[i][0], 70/3), string.center(ranged_weapon_charts[i+1][0], 70/3), string.center(ranged_weapon_charts[i+2][0], 70/3)) + sys.exit(0) + + if ( not strength or not dexterity or not pclass or not level): + print usage + sys.exit(1) + + #print "Trying with pclass %s level %d strength %s dex %d weapons %s" % (pclass, level, strength, dexterity, weapons) + + pc = character(pclass, strength, dexterity, level) + pc.weapons = weapons + pc.writeCharts(sys.stdout) + #pc.weapons = [["ranged", "long bow"], ["melee", "long sword"]] + #pc.writeCharts(sys.stdout) + +if ( __name__ == "__main__" ): + main(len(sys.argv), sys.argv) diff --git a/addcurrconv b/addcurrconv new file mode 100755 index 0000000..7e440a5 --- /dev/null +++ b/addcurrconv @@ -0,0 +1,69 @@ +#!/usr/bin/python +silverval = 0.0 +fpp = 0.0 +fgp = 0.0 +fsp = 0.0 +fcp = 0.0 +fdol = 0.0 + +def getInput(): + return raw_input(">> ") + +print "AD&D Currency Converter - Converts between real and AD&D currency" +print "Enter a monetary value followed by the currency (dollars, gp, sp, cp, pp)" +print "Enter \"q\" by itself to quit." +print "Enter \"s \"" +print " to set the value of silver." + +while 1 : + value = getInput() + vlist = value.split(" ") + if vlist[0].isdigit() : + oldval = int(vlist[0]) + if vlist[1].lower() == "gp": + fgp = oldval + fsp = fgp * 10 + fcp = fsp * 10 + fpp = fgp / 10 + fdol = fsp * silverval + elif vlist[1].lower() == "sp": + fsp = oldval + fgp = fsp / 10 + fcp = fsp * 10 + fpp = fgp / 10 + fdol = fsp * silverval + elif vlist[1].lower() == "cp": + fcp = oldval + fsp = fcp / 10 + fgp = fsp / 10 + fpp = fgp / 10 + fdol = fsp * silverval + elif vlist[1].lower() == "dollars": + fsp = oldval / silverval + fcp = fsp * 10 + fgp = fsp / 10 + fpp = fgp / 10 + else: + print "I didn't understand." + continue + + print vlist[0], vlist[1], " converts to:" + print "\t", fpp, " platinum (or)" + print "\t", fgp, " gold pieces (or)" + print "\t", fsp, " silver pieces (or)" + print "\t", fcp, " copper pieces (or)" + print "\t", fdol, " dollars" + elif vlist[0].lower() == "q": + break + + elif vlist[0].lower() == "s": + if vlist[1].isdigit(): + silverval = int(vlist[1]) + print "silver value set to : ", silverval + else : + print "Please provide a numeric value as the second argument to the" + print " \"s\" command." + + else: + print "I didn't understand." + continue diff --git a/giveStats b/giveStats new file mode 100755 index 0000000..47f50f6 --- /dev/null +++ b/giveStats @@ -0,0 +1,102 @@ +#!/usr/bin/python +import random +import string +import getopt +import sys + +def total(s): + toReturn =0 + for i in s: + toReturn += int(string.strip(string.split(i)[0])) + return toReturn + +def cloneArray(a): + b = [] + for x in a: + b.append(x) + return b + +def average(s): + toReturn =0 + for i in s: + toReturn += i + return toReturn/len(s) + +def allAboveTen(s): + #print "allAboveTen got ", str(s) + for i in s: + score = i + if ( score < 10): + #print "score was below ten : ", score + return False + return True + +def suggest(l): + x = cloneArray(l) + s = [] + for i in x: + s.append(int(string.strip(string.split(i)[0]))) + + if ( average(s[0:3]) > average(s[3:6]) and + average(s[0:3]) > average([s[1], s[3], s[4]]) ): + + if ( s[5] > 15 and (average([s[2], s[1], s[3]]) < 13)): + return "Paladin" + elif ( average([s[2], s[1], s[3]]) > 13 and + s[4] > 12 ): + return "Ranger" + return "Fighter" + + elif ( average(s[0:3]) > average(s[3:6]) and + average(s[0:3]) < average([s[1], s[3], s[4]]) ): + return "Rogue" + + elif ( average(s[0:3]) < average(s[3:6]) ): + + if ( s[3] > s[5] and s[3] > s[4] ): + return "Wizard" + elif ( s[3] > s[5] and s[3] < s[4] + and average([s[4], s[5], s[0]]) > 12): + return "Cleric" + elif ( s[3] < s[5]): + return "Sorceror" + return "Spellcaster" + + elif ( average(s) < 11): + return "Slaad bait" + else: + return "No suggestion" + +def signIntStr(i): + if ( i <= 9 ) : + return " " + str((i-10)/2) + else: + return " +" + str((i-10)/2) + +if ( __name__ == "__main__" ): + sets = [] + abilities = ["strength", "dexterity", "constitution", "intelligence", "wisdom", "charisma"] + currTotal = 0 + currNum = 0 + + for setnum in range(0,3): + sets.append([]) + currTotal = 0 + for i in range(0,6): + if ( sys.argv.count("-a") > 0 or sys.argv.count("--aboveAverage") > 0): + while ( currNum < 9 ): + currNum = random.choice(range(3,18)) + else: + currNum = random.choice(range(3,18)) + sets[setnum].append(string.center(str(currNum) + signIntStr(currNum), 15)) + currTotal += currNum + currNum = 0 + sets[setnum].append(string.center(str(currTotal), 15)) + + print " "*20 + string.center(suggest(sets[0]), 15) + string.center(suggest(sets[1]), 15) + string.center(suggest(sets[2]), 15) + + for i in range(0,6): + print string.center(abilities[i], 20) + sets[0][i] + sets[1][i] + sets[2][i] + + print "-"*65 + print string.center("totals", 20) + sets[0][6] + sets[1][6] + sets[2][6] diff --git a/spellbook.py b/spellbook.py new file mode 100755 index 0000000..b9add44 --- /dev/null +++ b/spellbook.py @@ -0,0 +1,59 @@ +#!/usr/bin/python + +import sys +import random + +def main(argc, argv): + if ( argc < 2 ): + print "usage: spellbook " + print " pass =max_spell_level to generate total_spells all of" + print " level (max_spell_level). You can also pass =[x,x] to" + print " pass a list of spell levels." + return 1 + minlevel = 1 + tlist = None + if ( "=" in argv[1]): + if ( "," in argv[1]): + tlist = argv[1].strip("=").strip("[").strip("]").split(",") + for i in range(0, len(tlist)): + tlist[i] = int(tlist[i]) + else: + tmp = argv[1].strip("=").strip() + minlevel = int(tmp) + maxlevel = int(tmp) + #print "Min level : %d Max level : %d" % (minlevel, maxlevel) + else: + maxlevel = int(argv[1]) + total = int(argv[2]) + PHBSpells = { 1: 30, 2: 24, 3: 34, 4: 24, 5: 24, 6: 24, 7: 16, 8: 16, 9: 12} + choices = [True, False] + spellLevels = {} + if ( tlist ) : + for i in range(0, total): + level = random.choice(tlist) + snum = random.choice(range(1, PHBSpells[level]+1)) + if ( spellLevels.has_key(level)): + spellLevels[level].append(snum) + else: + spellLevels[level] = [] + spellLevels[level].append(snum) + else: + for i in range(0, total): + #if ( random.choice(choices) ): + level = random.choice(range(minlevel, maxlevel+1)) + snum = random.choice(range(1, PHBSpells[level]+1)) + if ( spellLevels.has_key(level) ): + spellLevels[level].append(snum) + else: + spellLevels[level] = [] + spellLevels[level].append(snum) + for i in range(1, 10): + if ( spellLevels.has_key(i) ): + spells = spellLevels[i] + spells.sort() + print "LEVEL %d : %s" % (i, str(spells)) + + + +if ( __name__ == "__main__" ): + main(len(sys.argv), sys.argv)