228 lines
7.6 KiB
Python
228 lines
7.6 KiB
Python
|
#! /usr/bun/python3
|
||
|
|
||
|
"""spell.py"""
|
||
|
|
||
|
import random
|
||
|
|
||
|
def random_chance(chance):
|
||
|
maximum = 1 / chance
|
||
|
draw = random.randint(1, maximum)
|
||
|
return (draw == 1)
|
||
|
|
||
|
class Spelling_Player:
|
||
|
"""A base player that can be used as an abstract class for other players."""
|
||
|
LEVEL = 16
|
||
|
|
||
|
def __init__(self):
|
||
|
self.hp = 100
|
||
|
self.status = 0
|
||
|
self.name = ""
|
||
|
self.max_letters = Spelling_Player.LEVEL
|
||
|
self.casted = {}
|
||
|
|
||
|
class Letter:
|
||
|
"""A single letter of a spell."""
|
||
|
VALUES = {"a" : 16, "e" : 8, "i" : 12, "o" : 6, "u" : 4}
|
||
|
STATUSES = {"h" : 1, "j" : 2, "l" : 4, "m" : 8, "n" : 16, "q" : 32, "r" : 64, "w" : 128}
|
||
|
|
||
|
def __init__(self, character = ""):
|
||
|
self.character = character
|
||
|
if(self.character in Letter.VALUES.keys()):
|
||
|
self.value = Letter.VALUES[self.character]
|
||
|
else:
|
||
|
self.value = 0
|
||
|
if(self.character in Letter.STATUSES.keys()):
|
||
|
self.status = Letter.STATUSES[self.character]
|
||
|
else:
|
||
|
self.status = 0
|
||
|
|
||
|
def __str__(self):
|
||
|
return str(self.character)
|
||
|
|
||
|
class Spell:
|
||
|
"""A spell."""
|
||
|
#constants:
|
||
|
VOWELS = "aeiouy"
|
||
|
UNPAIREDS = "hjlmnqrw"
|
||
|
XBUFFS = "bd"
|
||
|
IBUFFS = "gvz"
|
||
|
XNERFS = "fks"
|
||
|
INERFS = "pt"
|
||
|
SPECIALS = "cx"
|
||
|
|
||
|
def __init__(self, word = ""):
|
||
|
valid = False
|
||
|
for i in Spell.VOWELS:
|
||
|
if(i in word):
|
||
|
valid = True
|
||
|
break
|
||
|
if(not valid): raise ValueError("No vowels are present.")
|
||
|
self.word = []
|
||
|
for i in word:
|
||
|
if(i == "y"):
|
||
|
i = random.choice("aeiou") #if the next letter is "y", change it to any other vowel
|
||
|
elif(self.is_special(i)):
|
||
|
i = random.choice(Spell.UNPAIREDS + Spell.XBUFFS + Spell.IBUFFS + Spell.XNERFS + Spell.INERFS) #unpaireds, buffs, & nerfs
|
||
|
else: pass
|
||
|
self.word.append(Letter(i))
|
||
|
if(len(self.word) >= 16): break
|
||
|
self.values = {"a" : 0, "e" : 0, "i" : 0, "o" : 0, "u" : 0}
|
||
|
self.xnerfs = {"a" : 1, "e" : 1, "i" : 1, "o" : 1, "u" : 1}
|
||
|
self.inerfs = {"a" : 0, "e" : 0, "i" : 0, "o" : 0, "u" : 0}
|
||
|
self.stats = 0
|
||
|
self.last_vowel = None
|
||
|
self.vowel_coef = 1
|
||
|
self.total_damage = 0
|
||
|
self.absorb = 0
|
||
|
|
||
|
def is_vowel(self, char):
|
||
|
return (char in Spell.VOWELS)
|
||
|
|
||
|
def is_unpaired(self, char):
|
||
|
return (char in Spell.UNPAIREDS)
|
||
|
|
||
|
def is_xbuff(self, char):
|
||
|
return (char in Spell.XBUFFS)
|
||
|
|
||
|
def is_ibuff(self, char):
|
||
|
return (char in Spell.IBUFFS)
|
||
|
|
||
|
def is_xnerf(self, char):
|
||
|
return (char in Spell.XNERFS)
|
||
|
|
||
|
def is_inerf(self, char):
|
||
|
return (char in Spell.INERFS)
|
||
|
|
||
|
def is_special(self, char):
|
||
|
return (char in Spell.SPECIALS)
|
||
|
|
||
|
def parse(self):
|
||
|
"""Initial parser"""
|
||
|
next_syl = []
|
||
|
for next_letter in self.word:
|
||
|
if(self.is_vowel(next_letter.character)):
|
||
|
if(self.last_vowel):
|
||
|
self.syl(next_syl)
|
||
|
next_syl = []
|
||
|
self.last_vowel = next_letter.character
|
||
|
next_syl.append(next_letter)
|
||
|
self.syl(next_syl) #remember not to let the last syllable drop off the Earth!
|
||
|
|
||
|
def syl(self, syllable):
|
||
|
"""Process a single syllable.
|
||
|
In this game, a syllable contains exactly one vowel,
|
||
|
all consonants adjacent to && after it (until the next vowel),
|
||
|
and, if it's the first one, all consonants in front as well."""
|
||
|
vowel = None
|
||
|
xvalue = 1
|
||
|
ivalue = 0
|
||
|
xnerf = 1
|
||
|
inerf = 0
|
||
|
status = 0
|
||
|
for next_letter in syllable:
|
||
|
|
||
|
if(self.is_vowel(next_letter.character)): #vowels
|
||
|
vowel = next_letter.character
|
||
|
xvalue *= max(int((next_letter.value / self.vowel_coef) + 0.5), 1)
|
||
|
ivalue *= next_letter.value
|
||
|
inerf *= int(next_letter.value / 2)
|
||
|
self.vowel_coef *= 2
|
||
|
|
||
|
elif(self.is_unpaired(next_letter.character)): #unpairedes
|
||
|
if(random_chance(1 / 8)):
|
||
|
status = status | next_letter.status
|
||
|
|
||
|
elif(self.is_xbuff(next_letter.character)): #xbuffs
|
||
|
xvalue *= 2
|
||
|
|
||
|
elif(self.is_ibuff(next_letter.character)): #ibuffs
|
||
|
if(vowel): ivalue += Letter.VALUES[vowel]
|
||
|
else: ivalue += 1
|
||
|
|
||
|
elif(self.is_xnerf(next_letter.character)): #xnerfs
|
||
|
xnerf *= 2
|
||
|
|
||
|
elif(self.is_inerf(next_letter.character)): #inerfs
|
||
|
if(vowel): inerf += int(Letter.VALUES[vowel] / 2)
|
||
|
else: inerf += 1
|
||
|
|
||
|
else: continue
|
||
|
|
||
|
self.values[vowel] += (xvalue + ivalue)
|
||
|
self.xnerfs[vowel] *= xnerf
|
||
|
self.inerfs[vowel] += inerf
|
||
|
self.stats = self.stats | status
|
||
|
|
||
|
def parse_nerfs(self, opponent): #opponent is the other guy's spell
|
||
|
for k in opponent.xnerfs.keys():
|
||
|
if(self.values[k] > 0):
|
||
|
self.values[k] = int(max((self.values[k] - opponent.inerfs[k]), 1)) #incremental nerfs are applied
|
||
|
self.values[k] = int(max((self.values[k] / opponent.xnerfs[k]) + 0.5, 1)) #multiplicative nerfs are applied (is "multiplicative" a word?)
|
||
|
|
||
|
def parse_atk(self):
|
||
|
self.total_damage = self.values["a"]
|
||
|
|
||
|
def parse_ret_def(self, opponent):
|
||
|
opponent.absorb = min(self.total_damage, opponent.values["u"])
|
||
|
self.total_damage = max(self.total_damage - opponent.values["u"], 0)
|
||
|
|
||
|
def parse_def(self, opponent):
|
||
|
#print(self.total_damage)
|
||
|
total = min(self.total_damage, opponent.values["i"])
|
||
|
self.total_damage -= total #total damage is decremented by the opponent's defense
|
||
|
opponent.values["i"] -= total
|
||
|
#print(self.total_damage)
|
||
|
|
||
|
def parse_defatk_def(self, opponent):
|
||
|
defense = min(opponent.values["e"], self.total_damage) #do defatk defense first
|
||
|
opponent.values["e"] -= defense
|
||
|
self.total_damage -= defense
|
||
|
|
||
|
def parse_defatk_atk(self, opponent):
|
||
|
self.total_damage += self.values["e"]
|
||
|
total = min(self.total_damage, opponent.values["i"])
|
||
|
self.total_damage -= total
|
||
|
opponent.values["i"] -= total
|
||
|
|
||
|
def parse_ret_atk(self, opponent):
|
||
|
self.total_damage += self.absorb
|
||
|
self.total_damage -= opponent.values["i"]
|
||
|
if(self.total_damage < 0): self.total_damage = 0
|
||
|
|
||
|
def affect(self, opponent, caster): #opponent is the other guy's spell, caster is the player who cast the spell
|
||
|
caster.hp -= opponent.total_damage
|
||
|
if(caster.hp <= 0):
|
||
|
caster.hp = 0
|
||
|
return
|
||
|
caster.hp += self.values["o"]
|
||
|
if(caster.hp > 100): caster.hp = 100
|
||
|
caster.status = opponent.stats
|
||
|
|
||
|
def compare_spells(spell1, spell2):
|
||
|
spell1.parse()
|
||
|
spell2.parse()
|
||
|
spell1.parse_nerfs(spell2)
|
||
|
spell2.parse_nerfs(spell1)
|
||
|
spell1.parse_atk()
|
||
|
spell2.parse_atk()
|
||
|
spell1.parse_ret_def(spell2)
|
||
|
spell2.parse_ret_def(spell1)
|
||
|
spell1.parse_def(spell2)
|
||
|
spell2.parse_def(spell1)
|
||
|
spell1.parse_defatk_def(spell2)
|
||
|
spell2.parse_defatk_def(spell1)
|
||
|
spell1.parse_defatk_atk(spell2)
|
||
|
spell2.parse_defatk_atk(spell1)
|
||
|
spell1.parse_ret_atk(spell2)
|
||
|
spell2.parse_ret_atk(spell1)
|
||
|
return spell1, spell2
|
||
|
|
||
|
if(__name__ == "__main__"):
|
||
|
print("""spell.py
|
||
|
Contents:
|
||
|
random_chance(chance)
|
||
|
class Spelling_Player
|
||
|
class Letter
|
||
|
class Spell
|
||
|
compare_spells(spell1, spell2)""")
|