1
0

Merge pull request #16 from KW46/improvement-use-dicts

Switch to dictionaries, better imports, adds game_config.py and DEBUG_MODE
This commit is contained in:
Kwarde 2024-01-18 17:05:09 +01:00 committed by GitHub
commit be70fa4bf4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 161 additions and 136 deletions

62
game.py
View File

@ -1,5 +1,10 @@
from player import *
from wands import *
import random
from player import Player
from wands import wands
from spells import SPELL_TYPE_COMMON, SPELL_TYPE_POWERFUL, _INVALID_SPELL
from spells import random_combat_spell, print_spells, find_spell_by_name
from spells import spells
from game_config import MAX_PLAYER_HEALTH
##
## Definitions
@ -34,19 +39,20 @@ def get_player_spell_from_input(player: Player):
player_input = input(print_turn_message(player))
if not player_input:
return [random_combat_spell(), 0]
spell_name, spell_obj = random_combat_spell()
return ((spell_name, spell_obj), 0)
else:
if player_input == "help":
print_spells()
continue
elif player_input.find("help", 0) != -1:
find_what = player_input[5:]
spell = find_spell_by_name(find_what)[0]
spell_name, spell_obj = find_spell_by_name(find_what)[0]
if spell is spell_object_none:
print("<!> Spell '{what}' does not exist!".format(what=find_what))
if spell_obj is spells[_INVALID_SPELL]:
print("<!> Spell '{what}' does not exist!".format(what=spell_name))
else:
print(spell)
print("'{spell_name}':{spell_desc}".format(spell_name=spell_name, spell_desc=spell_obj))
continue
else:
return find_spell_by_name(player_input)
@ -72,8 +78,8 @@ while True:
#GET: WANDS
print("Welcome {p1_name} and {p2_name}! You're about to choose a wand to use in this duel! Available wands are:".format(p1_name=player1_name, p2_name=player2_name))
for i in Wand.wandList:
print(i)
for i in wands.items():
print("{wand_id}:{wand_desc}".format(wand_id=i[0], wand_desc=i[1]))
#Player 1
while (True):
@ -81,10 +87,10 @@ while (True):
wand_input = int(input("What wand do you want {name}? (Enter one of the numbers): ".format(name=player1_name)))
except ValueError:
continue
if wand_input < 1 or wand_input > len(Wand.wandList):
if wand_input < 1 or wand_input > len(wands):
continue
player1_wand = Wand.wandList[wand_input-1]
player1_wand = wands[wand_input]
break
#Player 2
while (True):
@ -92,10 +98,10 @@ while (True):
wand_input = int(input("What wand do you want {name}? (Enter one of the numbers): ".format(name=player2_name)))
except ValueError:
continue
if wand_input < 1 or wand_input > len(Wand.wandList):
if wand_input < 1 or wand_input > len(wands):
continue
player2_wand = Wand.wandList[wand_input-1]
player2_wand = wands[wand_input]
break
player1 = Player(player1_name, player1_wand)
@ -131,13 +137,18 @@ try:
round_end()
print("== Round {round} ==".format(round=current_round))
player1.active_spell, player1.active_spell_levenshtein_distance = get_player_spell_from_input(player1)
player2.active_spell, player2.active_spell_levenshtein_distance = get_player_spell_from_input(player2)
spell, dist = get_player_spell_from_input(player1)
player1.active_spell = spells.get(spell[0])
player1.active_spell_levenshtein_distance = dist
if (player1.stunned_rounds > 0 and player1.active_spell is not spell_finite_incantatem):
player1.active_spell = spell_object_stunned
if (player2.stunned_rounds > 0 and player2.active_spell is not spell_finite_incantatem):
player2.active_spell = spell_object_stunned
spell, dist = get_player_spell_from_input(player2)
player2.active_spell = spells.get(spell[0])
player2.active_spell_levenshtein_distance = dist
if (player1.stunned_rounds > 0 and player1.active_spell is not spells["Finite Incantatem"]):
player1.active_spell = None
if (player2.stunned_rounds > 0 and player2.active_spell is not spells["Finite Incantatem"]):
player2.active_spell = None
# OUTCOME: SPELLS
# > Get spell succes
@ -150,17 +161,17 @@ try:
# > Add health if defensive spell was lucky (partial heal, fully heal)
if player1.active_spell_succes and player1.active_spell.chance_heal_partly_succes():
player1.give_health(MAX_PLAYER_HEALTH * 0.05)
print("<!> {name} casted {spell} above expectations, and receives {hp} health!".format(name=player1.name, spell=player1.active_spell.name, hp=MAX_PLAYER_HEALTH*0.05))
print("<!> {name} casted {spell} above expectations, and receives {hp} health!".format(name=player1.name, spell=player1.active_spell.get_spell_name(), hp=MAX_PLAYER_HEALTH*0.05))
elif player1.active_spell_succes and player1.active_spell.chance_heal_fully_succes() and player1.health < MAX_PLAYER_HEALTH:
player1.give_health(MAX_PLAYER_HEALTH)
print("<!> {name} casted {spell} outstanding! {name} now has full health!".format(name=player1.name, spell=player1.active_spell.name, hp=MAX_PLAYER_HEALTH*0.05))
print("<!> {name} casted {spell} outstanding! {name} now has full health!".format(name=player1.name, spell=player1.active_spell.get_spell_name(), hp=MAX_PLAYER_HEALTH*0.05))
#
if player2.active_spell_succes and player2.active_spell.chance_heal_partly_succes():
player2.give_health(MAX_PLAYER_HEALTH * 0.05)
print("<!> {name} casted {spell} above expectations, and receives {hp} health!".format(name=player2.name, spell=player2.active_spell.name, hp=MAX_PLAYER_HEALTH*0.05))
print("<!> {name} casted {spell} above expectations, and receives {hp} health!".format(name=player2.name, spell=player2.active_spell.get_spell_name(), hp=MAX_PLAYER_HEALTH*0.05))
elif player2.active_spell_succes and player2.active_spell.chance_heal_fully_succes() and player2.health < MAX_PLAYER_HEALTH:
player2.give_health(MAX_PLAYER_HEALTH)
print("<!> {name} casted {spell} outstanding! {name} now has full health!".format(name=player2.name, spell=player2.active_spell.name, hp=MAX_PLAYER_HEALTH*0.05))
print("<!> {name} casted {spell} outstanding! {name} now has full health!".format(name=player2.name, spell=player2.active_spell.get_spell_name(), hp=MAX_PLAYER_HEALTH*0.05))
# > Determine instant winner or skip to next round
if not player1.active_spell_succes and not player2.active_spell_succes:
@ -207,11 +218,6 @@ try:
if slowest_caster.health > 0:
slowest_caster.cast_spell(fastest_caster)
fastest_caster.active_spell = spell_object_none
fastest_caster.active_spell_levenshtein_distance = 0
slowest_caster.active_spell = spell_object_none
slowest_caster.active_spell_levenshtein_distance = 0
except KeyboardInterrupt:
print()
print("<!> Duel ended because both {} and {} suddenly decided to test out their apparition skill!".format(player1.name, player2.name))

17
game_config.py Normal file
View File

@ -0,0 +1,17 @@
##
## Player config
##
MAX_PLAYER_HEALTH = 1000 # Maximum health
MAX_STUNNED_ROUNDS = 10 # Max amount of rounds a player can be stunned
##
## Spells config
##
CHANCE_HEAL_PARTLY = 25 # Percentage chance a player is healed with 5% of max health when using a defensive spell
CHANCE_HEAL_FULLY = 5 # Percentage chance a player is fully healed when using a defensive spell
MAX_LEVENSHTEIN_DISTANCE = 3 # Max Levenshtein distance (max amount of typos a user can make) before considering a spell fails. Setting this to 0 disables it (and in that case also doesn't require the levenshtein package)
##
## Misc
##
DEBUG_MODE = False # Enable or disable debug mode. Sets all spell chances to 100% when enabled

View File

@ -1,8 +1,8 @@
import random
from wands import Wand
from spells import *
MAX_PLAYER_HEALTH = 1000
MAX_STUNNED_ROUNDS = 10
from spells import SPELL_TYPE_NONE, SPELL_TYPE_USELESS, SPELL_TYPE_DEFENSE, SPELL_TYPE_UNFORGIVABLE#, SPELL_TYPE_COMMON, SPELL_TYPE_POWERFUL
from spells import Spell, spells, _INVALID_SPELL
from game_config import MAX_PLAYER_HEALTH, MAX_STUNNED_ROUNDS
class Player:
def __init__(self, name: str, wand: Wand):
@ -10,7 +10,7 @@ class Player:
self.health = MAX_PLAYER_HEALTH
self.wand = wand
self.active_spell = spell_object_none
self.active_spell = spells[_INVALID_SPELL]
self.active_spell_succes = False
self.active_spell_levenshtein_distance = 0 # Penalty => If >0 then damage reduction, 15 per distance
@ -38,6 +38,8 @@ class Player:
self.stunned_rounds = MAX_STUNNED_ROUNDS
def get_spell_succes_rate(self, spell: Spell):
if spell == None:
return 0
return 1 * self.wand.succes_rate * spell.succes_rate
def get_queued_effects(self):
@ -56,57 +58,58 @@ class Player:
return output
def cast_spell_result(self, spell: Spell, succes: bool):
if spell == None:
return "<!> {name} can't cast anything but Finite Incantatem since they are stunned".format(name=self.name)
if succes:
message = "{name} casted '{spell}' with succes"
else:
if spell.type == SPELL_TYPE_UNFORGIVABLE:
message = "{name} tried to cast '{spell}' but didn't truly mean it. Cast FAILED!"
elif spell.type == SPELL_TYPE_NONE:
if spell == spell_object_none:
if spell == spells[_INVALID_SPELL]:
return "{name} must not be feeling well, since they casted a non existing spell. Cast FAILED!".format(name=self.name)
elif spell == spell_object_stunned:
return "<!> {name} can't cast anything but {spell} since they are stunned".format(name=self.name, spell=spell_finite_incantatem.name)
else: message = "{name} tried to cast '{spell}' but mispronounced it. Cast FAILED!"
return message.format(name=self.name, spell=spell.name)
return message.format(name=self.name, spell=spell.get_spell_name())
def cast_spell(self, opponent): #: Player ?
spell_name = self.active_spell.name.lower()
spell_name = self.active_spell.get_spell_name()
if self.active_spell is spell_object_none:
if self.active_spell is None:
print("- {name} does nothing".format(name=self.name))
return
if self.stunned_rounds > 0 and self.active_spell is not spell_finite_incantatem:
if self.stunned_rounds > 0 and self.active_spell is not spells["Finite Incantatem"]:
print("<!> {name} tries to cast a spell but fails because they are stunned!".format(name=self.name))
return
if self.active_spell.type == SPELL_TYPE_USELESS:
if self.active_spell is spell_lumos:
if self.active_spell is spells["Lumos"]:
if self.lumos:
print("- {name} casts {spell} with no effect: {name} already has a brutal shining light at the tip of their wand!".format(name=self.name, spell=spell_name))
else:
print("- {name} casts {spell}! Look at that brutal shining light at the tip of their wand. Absolutely gorgeous!".format(name=self.name, spell=spell_name))
self.lumos = True
elif self.active_spell is spell_nox:
elif self.active_spell is spells["Nox"]:
if not self.lumos:
print("- {name} shouts: {spell}! Nothing happened".format(name=self.name, spell=spell_name.upper()))
else:
print("- {name} shouts {spell}! Their brutal shining light dissapears".format(name=self.name, spell=spell_name.upper()))
self.lumos = False
elif self.active_spell is spell_rennervate:
elif self.active_spell is spells["Rennervate"]:
if opponent.stunned_rounds == 0:
print("- {name} casts {spell} with no effect, because {name_o} is not currently stunned!".format(name=self.name, spell=spell_name, name_o=opponent.name))
else:
print("- {name} casts {spell}! {name_o} is no longer stunned!".format(name=self.name, spell=spell_name, name_o=opponent.name))
opponent.stunned_rounds = 0
elif self.active_spell is spell_igni:
elif self.active_spell is spells["Igni"]:
print("- Geralt casts Igni. Wait. Geralt? White Wolf? The butcher of Blaviken? What is he doing here? Is he even here? What is going on?")
else:
print("<!> [debug]{name} casted SPELL_TYPE_USELESS {spell}. Behaviour unscripted!".format(name=self.name, spell=spell_name))
elif self.active_spell.type == SPELL_TYPE_DEFENSE:
spell_succes = True
if self.active_spell is spell_finite_incantatem:
if self.active_spell is spells["Finite Incantatem"]:
if self.stunned_rounds > 0:
if not 10 > random.random() * 100:
spell_succes = False
@ -125,42 +128,42 @@ class Player:
print("- {name} casts {spell}. {name_o} is looking confused. What spell did {name} try to cancel?".format(name=self.name, spell=spell_name, name_o=opponent.name))
elif not spell_succes:
print("- {name}: (nothing, still stunned)".format(name=self.name))
elif self.active_spell is spell_impendimenta:
if opponent.active_spell is spell_protego and opponent.active_spell_succes:
elif self.active_spell is spells["Impendimenta"]:
if opponent.active_spell is spells["Protego"] and opponent.active_spell_succes:
print("- {name} casts {spell} on {name_o}. FAILURE! {name_o} blocks the attack!".format(name=self.name, name_o=opponent.name, spell=spell_name))
else:
print("- {name} casts {spell} on {name_o}. {name_o} is slowed and their next offensive move will have a 33% slower spell speed!".format(name=self.name, name_o=opponent.name, spell=spell_name))
opponent.decreased_spell_speed = True
elif self.active_spell is spell_lumos_solem:
elif self.active_spell is spells["Lumos Solem"]:
# Light still goes through the shield, therefor always succeed blinding attempts
print("- {name} casts {spell} on {name_o}. {name_o} is blinded and their next offensive move will have 33% less damage!".format(name=self.name, name_o=opponent.name, spell=spell_name))
opponent.decreased_spell_damage = True
elif self.active_spell is spell_protego and self.active_spell_succes:
elif self.active_spell is spells["Protego"] and self.active_spell_succes:
print("- {name} casts {spell}".format(name=self.name, spell=spell_name))
else:
print("<!> [debug]{name} casted SPELL_TYPE_DEFENSE {spell}. Behaviour unscripted!".format(name=self.name, spell=spell_name))
elif self.active_spell.type == SPELL_TYPE_UNFORGIVABLE:
if self.active_spell is spell_avada_kedavra:
if self.active_spell is spells["Avada Kedavra"]:
print("- THE NERVE! {name} casts the killing curse! See you in the after life {name_o}!".format(name=self.name, name_o=opponent.name))
opponent.health = 0
elif self.active_spell is spell_crucio:
elif self.active_spell is spells["Crucio"]:
print("- THE NERVE! {name} casts the torture curse. {name_o} is greatly hurt and falls to the ground. They are stunned for 5 (more) moves".format(name=self.name, name_o=opponent.name))
opponent.add_stunned_rounds(5)
opponent.take_health(self.active_spell.damage)
elif self.active_spell is spell_imperio:
elif self.active_spell is spells["Imperio"]:
print("- THE NERVE! {name} casts the Imperius curse. \"Why don't you take a nice nap for {max_stunned_rounds} moves, {name_o}?\". {name_o} submits with pleasure".format(name=self.name, name_o=opponent.name, max_stunned_rounds=MAX_STUNNED_ROUNDS))
opponent.add_stunned_rounds(MAX_STUNNED_ROUNDS)
else:
if self.active_spell is spell_mimblewimble:
if opponent.active_spell is spell_protego and opponent.active_spell_succes:
if self.active_spell is spells["Mimblewimble"]:
if opponent.active_spell is spells["Protego"] and opponent.active_spell_succes:
print("- {name} casts {spell} on {name_o}. FAILURE! {name_o} blocks the attack!".format(name=self.name, spell=spell_name, name_o=opponent.name))
else:
print("- {name} casts {spell} on {name_o}. {name_o}'s tongue is tied in a knot. That's annoying! {name_o} is silenced for 1 (more) move".format(name=self.name, spell=spell_name, name_o=opponent.name))
opponent.add_stunned_rounds(-self.active_spell.damage)
elif self.active_spell is spell_silencio:
if opponent.active_spell is spell_protego and opponent.active_spell_succes:
elif self.active_spell is spells["Silencio"]:
if opponent.active_spell is spells["Protego"] and opponent.active_spell_succes:
print("- {name} casts {spell} on {name_o}. FAILURE! {name_o} blocks the attack!".format(name=self.name, spell=spell_name, name_o=opponent.name))
else:
if opponent.stunned_rounds == 0:
@ -181,7 +184,7 @@ class Player:
total_damage = self.active_spell.damage * self.wand.damage * damage_modifier - damage_penalty
if total_damage < 0: total_damage = 0
if opponent.active_spell is spell_protego and opponent.active_spell_succes:
if opponent.active_spell is spells["Protego"] and opponent.active_spell_succes:
print("- {name} casts {spell} on {name_o}. FAILURE! {name_o} blocks the attack!".format(name=self.name, spell=spell_name, name_o=opponent.name))
else:
print("- {name} casts {spell} on {name_o} causing {dmg} damage!".format(name=self.name, spell=spell_name, name_o=opponent.name, dmg=total_damage))

123
spells.py
View File

@ -1,5 +1,8 @@
import random
from Levenshtein import distance
from game_config import CHANCE_HEAL_PARTLY, CHANCE_HEAL_FULLY, DEBUG_MODE, MAX_LEVENSHTEIN_DISTANCE
if MAX_LEVENSHTEIN_DISTANCE > 0:
from Levenshtein import distance
SPELL_TYPE_NONE = -1
SPELL_TYPE_USELESS = 0
@ -8,25 +11,14 @@ SPELL_TYPE_COMMON = 2
SPELL_TYPE_POWERFUL = 3
SPELL_TYPE_UNFORGIVABLE = 4
# If SPELL_TYPE_DEFENSE is casted, always these chances to heal partly (restore 5% of max hp) or completely
CHANCE_HEAL_PARTLY = 25
CHANCE_HEAL_FULLY = 5
#Maximum Levenshtein distance. Eg if a user casts 'Pritrgo' instead of 'Protego', distance would be 2 and Protego would still be cast if MAX_LEVENSHTEIN_DISTANCE is at least 2
#Set to 0 to disable
MAX_LEVENSHTEIN_DISTANCE = 3
__INVALID_SPELL = ".@wizardduel@__spell_invalid__" #Internal usage only
_INVALID_SPELL = ".@wizardduel@__spell_invalid__" #Internal usage only
##
## Spell class
##
class Spell:
spellList = []
#Class special methods
"""
name (str) Name of the spell as used in combat
speed (int) Speed of the spell. This will determine what spell is casted first.
damage (int) Damage that the spell does.
<!> Negative damage takes away moves from opponent (eg -2 = cancel 2 moves of opponent)
@ -39,18 +31,15 @@ class Spell:
- SPELL_TYPE_POWER: Powerful combat spell - deals alot of damage or takes away a few moves from opponent
- SPELL_TYPE_UNFORGIVABLE: deals alot of damage or takes away alot of moves from opponent
"""
def __init__(self, name: str, speed: int, damage: int, succes_rate: int, description: str, type: int = SPELL_TYPE_COMMON):
self.name = name
def __init__(self, speed: int, damage: int, succes_rate: int, description: str, type: int = SPELL_TYPE_COMMON):
self.speed = speed
self.damage = damage
self.succes_rate = succes_rate
self.description = description
self.type = type
Spell.spellList.append(self)
def __repr__(self):
return " ['{spell}']\n\t{desc}\n\tSUCCES RATE: {srate}%\tSPEED: {speed}\tDAMAGE: {dmg}".format(spell=self.name, type=type, desc=self.description, srate=self.succes_rate, speed=self.speed, dmg=self.damage)
return "\n\t{desc}\n\tSUCCES RATE: {srate}%\tSPEED: {speed}\tDAMAGE: {dmg}".format(type=type, desc=self.description, srate=self.succes_rate, speed=self.speed, dmg=self.damage)
def chance_heal_partly_succes(self):
return self.type == SPELL_TYPE_DEFENSE and CHANCE_HEAL_PARTLY > random.random() * 100
@ -58,58 +47,69 @@ class Spell:
def chance_heal_fully_succes(self):
return self.type == SPELL_TYPE_DEFENSE and CHANCE_HEAL_FULLY > random.random() * 100
def get_spell_name(self):
return str(list(i for i in spells if spells[i] == self)).strip("[]'")
##
## Spells
##
# Useless spells - These don't do anything useful in combat
spell_lumos = Spell("Lumos", 100, 000, 100, "Creates a small light at the tip of your wand", SPELL_TYPE_USELESS)
spell_nox = Spell("Nox", 100, 000, 100, "Counter spell of Lumos", SPELL_TYPE_USELESS)
spell_rennervate = Spell("Rennervate", 100, 000, 100, "Revives your opponent if they are stunned", SPELL_TYPE_USELESS)
spell_igni = Spell("Igno", 100, 000, 100, "Damages an enemy using fire. Except, this is a Witcher sign. It thus has no effect at all", SPELL_TYPE_USELESS)
spells = {
# Useless spells - These don't do anything useful in combat
"Lumos": Spell(100, 000, 100, "Creates a small light at the tip of your wand", SPELL_TYPE_USELESS),
"Nox": Spell(100, 000, 100, "Counter spell of Lumos", SPELL_TYPE_USELESS),
"Rennervate": Spell(100, 000, 100, "Revives your opponent if they are stunned", SPELL_TYPE_USELESS),
"Igni": Spell(100, 000, 100, "Damages an enemy using fire. Except, this is a Witcher sign. It thus has no effect at all", SPELL_TYPE_USELESS),
# Defensive spell. Each cast from this category has a 5% chance of completely restoring health or 25% chance to heal 5% of maximum health
spell_finite_incantatem = Spell("Finite Incantatem", 100, 000, 45, "Cancel all effects casted upon you. If you are stunned/silenced, there's a 10% chance this spell might work", SPELL_TYPE_DEFENSE)
spell_impendimenta = Spell("Impendimenta", 94, 000, 60, "Slows your opponent. EFFECT: Decrease opponent's spell speed by 33% in their next offensive move", SPELL_TYPE_DEFENSE)
spell_lumos_solem = Spell("Lumos Solem", 94, 000, 60, "Blinds your opponent. EFFECT: Decrease opponent's spell damage by 33% in their next offensive move", SPELL_TYPE_DEFENSE)
spell_protego = Spell("Protego", 100, 000, 80, "Create a shield that blocks most attacks", SPELL_TYPE_DEFENSE)
"Finite Incantatem": Spell(100, 000, 45, "Cancel all effects casted upon you. If you are stunned/silenced, there's a 10% chance this spell might work", SPELL_TYPE_DEFENSE),
"Impendimenta": Spell(94, 000, 60, "Slows your opponent. EFFECT: Decrease opponent's spell speed by 33% in their next offensive move", SPELL_TYPE_DEFENSE),
"Lumos Solem": Spell(94, 000, 60, "Blinds your opponent. EFFECT: Decrease opponent's spell damage by 33% in their next offensive move", SPELL_TYPE_DEFENSE),
"Protego": Spell(100, 000, 80, "Create a shield that blocks most attacks", SPELL_TYPE_DEFENSE),
# Common combat spells. High chance of succes, deals some damage
spell_reducto = Spell("Reducto", 75, 150, 85, "Blast an object near your opponent")
spell_rictusempra = Spell("Rictusempra", 85, 90, 90, "Causes your opponent to curl up in laughter, tiring them out")
spell_stupefy = Spell("Stupefy", 95, 75, 95, "Knock over your opponent")
"Reducto": Spell(75, 150, 85, "Blast an object near your opponent"),
"Rictusempra": Spell(85, 90, 90, "Causes your opponent to curl up in laughter, tiring them out"),
"Stupefy": Spell(95, 75, 95, "Knock over your opponent"),
# Powerful combat spells. Medium chance of succes, deals more damage or stuns opponents
spell_bombarda = Spell("Bombarda", 50, 180, 75, "Creates an explosion near your opponent", SPELL_TYPE_POWERFUL)
spell_confringo = Spell("Confringo", 50, 200, 70, "Creates an explosion directly at your opponent", SPELL_TYPE_POWERFUL)
spell_mimblewimble = Spell("Mimblewimble", 50, -1, 70, "Ties a knot in your opponents tongue, causing them to be unable to cast a spell for 1 (more) move", SPELL_TYPE_POWERFUL)
spell_sectumsempra = Spell("Sectumsempra", 90, 400, 35, "Slices your opponent", SPELL_TYPE_POWERFUL)
spell_silencio = Spell("Silencio", 35, -3, 55, "Silences your opponent, causing them unable to cast spells for 3 moves. <!>Only works if opponent is not stunned yet", SPELL_TYPE_POWERFUL)
"Bombarda": Spell(50, 180, 75, "Creates an explosion near your opponent", SPELL_TYPE_POWERFUL),
"Confringo": Spell(50, 200, 70, "Creates an explosion directly at your opponent", SPELL_TYPE_POWERFUL),
"Mimblewimble": Spell(50, -1, 70, "Ties a knot in your opponents tongue, causing them to be unable to cast a spell for 1 (more) move", SPELL_TYPE_POWERFUL),
"Sectumsempra": Spell(90, 400, 35, "Slices your opponent", SPELL_TYPE_POWERFUL),
"Silencio": Spell(35, -3, 55, "Silences your opponent, causing them unable to cast spells for 3 moves. <!>Only works if opponent is not stunned yet", SPELL_TYPE_POWERFUL),
# Unforgivable spells. Very low chance of success, instantly kills or deals alot of damage/stun amount
spell_avada_kedavra = Spell("Avada Kedavra", 999, 999, 2, "Instantly end your opponent", SPELL_TYPE_UNFORGIVABLE)
spell_crucio = Spell("Crucio", 999, 500, 5, "Cause excruciating pain to your opponent, causing alot of damage and making them unable to cast spells for 5 moves", SPELL_TYPE_UNFORGIVABLE)
spell_imperio = Spell("Imperio", 999, -1, 3, "Muddle with your opponent's mind, convincing them to stop casting spells for 10 moves", SPELL_TYPE_UNFORGIVABLE)
"Avada Kedavra": Spell(999, 999, 2, "Instantly end your opponent", SPELL_TYPE_UNFORGIVABLE),
"Crucio": Spell(999, 500, 5, "Cause excruciating pain to your opponent, causing alot of damage and making them unable to cast spells for 5 moves", SPELL_TYPE_UNFORGIVABLE),
"Imperio": Spell(999, -1, 3, "Muddle with your opponent's mind, convincing them to stop casting spells for 10 moves", SPELL_TYPE_UNFORGIVABLE),
# Internal usage
spell_object_none = Spell(__INVALID_SPELL, 0, 0, 0, "(internal) invalid spell", SPELL_TYPE_NONE)
spell_object_stunned = Spell(__INVALID_SPELL, 0, 0, 0, "(internal) object when stunned", SPELL_TYPE_NONE)
_INVALID_SPELL: Spell(0, 0, 0, "(internal) invalid spell", SPELL_TYPE_NONE)
}
# Set succes rates to 100% if debug mode is enabled
if DEBUG_MODE:
for i in spells.items():
i[1].succes_rate = 100
##
## Standalone spell functions
##
def random_combat_spell():
return random.choice([i for i in Spell.spellList if i.type == SPELL_TYPE_COMMON])
return random.choice([i for i in spells.items() if i[1].type == SPELL_TYPE_COMMON]) # note: returns tuple ('spell_name', spell_obj)
def find_spell_by_name(input: str): # Returns a list with: [spell_object, levenshtein_distance]. If distance is greater than 0 (typos were made), damage goes down
for i in Spell.spellList:
if input.title() == i.name.title():
return [i, 0]
else:
if MAX_LEVENSHTEIN_DISTANCE > 0:
dist = distance(i.name.title(), input.title())
if dist < MAX_LEVENSHTEIN_DISTANCE:
return [i, dist]
return [spell_object_none, 0]
def find_spell_by_name(input: str): # Returns a multidimensional tuple: ( ('spell_name', spell_object), levenshtein_distance )
ret = (input, spells.get(input.title(), spells[_INVALID_SPELL]))
dist = 0
if ret[1] == spells[_INVALID_SPELL]:
ret = (_INVALID_SPELL, ret[1])
if MAX_LEVENSHTEIN_DISTANCE > 0:
for i in spells.items():
dist = distance(i[0].title(), input.title())
if dist <= MAX_LEVENSHTEIN_DISTANCE:
ret = (i[0], i[1])
break
return (ret, dist)
def print_spells():
header_spells_useless = "== USELESS SPELLS =="
@ -118,24 +118,29 @@ def print_spells():
header_spells_powerful = "== POWERFUL COMBAT SPELLS =="
header_spells_unforgivable = "== UNFORGIVABLE CURSES =="
for i in Spell.spellList:
if i.type == SPELL_TYPE_UNFORGIVABLE or i.type == SPELL_TYPE_USELESS or i.type == SPELL_TYPE_NONE:
for i in spells.items():
if i[1].type == SPELL_TYPE_UNFORGIVABLE or i[1].type == SPELL_TYPE_USELESS or i[1].type == SPELL_TYPE_NONE:
continue
if i.type == SPELL_TYPE_USELESS and header_spells_useless:
if i[1].type == SPELL_TYPE_USELESS and header_spells_useless:
print("\n"+header_spells_useless)
header_spells_useless = ""
elif i.type == SPELL_TYPE_DEFENSE and header_spells_defensive:
elif i[1].type == SPELL_TYPE_DEFENSE and header_spells_defensive:
print("\n"+header_spells_defensive)
header_spells_defensive = ""
elif i.type == SPELL_TYPE_COMMON and header_spells_common:
elif i[1].type == SPELL_TYPE_COMMON and header_spells_common:
print("\n"+header_spells_common)
header_spells_common = ""
elif i.type == SPELL_TYPE_POWERFUL and header_spells_powerful:
elif i[1].type == SPELL_TYPE_POWERFUL and header_spells_powerful:
print("\n"+header_spells_powerful)
header_spells_powerful = ""
elif i.type == SPELL_TYPE_UNFORGIVABLE and header_spells_unforgivable:
elif i[1].type == SPELL_TYPE_UNFORGIVABLE and header_spells_unforgivable:
print("\n"+header_spells_unforgivable)
header_spells_unforgivable = ""
print(i)
print(
str(i)
.strip('(')
.strip(')')
.replace(',', ':', 1)
)

View File

@ -7,12 +7,7 @@ WAND_WOOD_ELDER = 1 #Speed -4%
WAND_WOOD_APPLE = 2 #Damage -5%
class Wand:
_next_wand_id = 1
wandList = []
def __init__(self, wand_core: int, wand_wood: int):
self.id = Wand._next_wand_id
self.core = wand_core
self.wood = wand_wood
@ -34,12 +29,9 @@ class Wand:
elif self.wood == WAND_WOOD_APPLE:
self.damage *= 0.95
Wand.wandList.append(self)
Wand._next_wand_id += 1
def __repr__(self):
return"\t{id}: {wood} wand with core: {core}\n\t\t-- SPEED: {info_speed}\tDAMAGE: {info_dmg}\tSUCCES RATE: {info_srate}".format(
id=self.id, wood=self.get_wand_wood(), core=self.get_wand_core(), info_srate=round(self.succes_rate, 2), info_speed=self.speed, info_dmg=round(self.damage, 2)
return"\t{wood} wand with core: {core}\n\t\t-- SPEED: {info_speed}\tDAMAGE: {info_dmg}\tSUCCES RATE: {info_srate}".format(
wood=self.get_wand_wood(), core=self.get_wand_core(), info_srate=round(self.succes_rate, 2), info_speed=self.speed, info_dmg=round(self.damage, 2)
)
def get_wand_core(self):
@ -57,14 +49,16 @@ class Wand:
##
## Wands
##
wand_1 = Wand(WAND_CORE_UNICORN, WAND_WOOD_ASH)
wand_2 = Wand(WAND_CORE_UNICORN, WAND_WOOD_ELDER)
wand_3 = Wand(WAND_CORE_UNICORN, WAND_WOOD_APPLE)
wands = {
1: Wand(WAND_CORE_UNICORN, WAND_WOOD_ASH),
2: Wand(WAND_CORE_UNICORN, WAND_WOOD_ELDER),
3: Wand(WAND_CORE_UNICORN, WAND_WOOD_APPLE),
wand_4 = Wand(WAND_CORE_PHOENIX, WAND_WOOD_ASH)
wand_5 = Wand(WAND_CORE_PHOENIX, WAND_WOOD_ELDER)
wand_6 = Wand(WAND_CORE_PHOENIX, WAND_WOOD_APPLE)
4: Wand(WAND_CORE_PHOENIX, WAND_WOOD_ASH),
5: Wand(WAND_CORE_PHOENIX, WAND_WOOD_ELDER),
6: Wand(WAND_CORE_PHOENIX, WAND_WOOD_APPLE),
wand_7 = Wand(WAND_CORE_DRAGON, WAND_WOOD_ASH)
wand_8 = Wand(WAND_CORE_DRAGON, WAND_WOOD_ELDER)
wand_9 = Wand(WAND_CORE_DRAGON, WAND_WOOD_APPLE)
7: Wand(WAND_CORE_DRAGON, WAND_WOOD_ASH),
8: Wand(WAND_CORE_DRAGON, WAND_WOOD_ELDER),
9: Wand(WAND_CORE_DRAGON, WAND_WOOD_APPLE)
}