Compare commits
18 Commits
9b87f2aa30
...
907581eb29
Author | SHA1 | Date | |
---|---|---|---|
|
907581eb29 | ||
|
782d4f93b1 | ||
5735ab4cde | |||
e76d315832 | |||
|
d19c467a7c | ||
cb491f62a6 | |||
f80da65977 | |||
|
be70fa4bf4 | ||
1dff4f524b | |||
fc8bee2f73 | |||
7cb65f5895 | |||
1485f171be | |||
aea461499c | |||
7d28ac961c | |||
c4bb8f7d80 | |||
355eab297c | |||
c138250c1c | |||
89318e7321 |
@ -3,4 +3,4 @@ Based the on Harry Potter franchise.
|
||||
|
||||
|
||||
You can run the game via pipenv. If you don't, make sure package levenshtein is installed.<br>
|
||||
Run `game.py` to run the game
|
||||
Run `entry.py` to run the game
|
53
entry.py
Normal file
53
entry.py
Normal file
@ -0,0 +1,53 @@
|
||||
from game import intro_message_welcome, intro_get_username, intro_print_wands, intro_get_wand, intro_message_duel_start
|
||||
from game import round_get_player_spells, round_set_player_spells_succes, round_get_player_spells_speed, round_cast_spells, start_round
|
||||
from player import Player
|
||||
|
||||
current_round: int = 0
|
||||
|
||||
intro_message_welcome()
|
||||
|
||||
player1 = Player(None, None)
|
||||
player2 = Player(None, None)
|
||||
player1.name = intro_get_username(1)
|
||||
player2.name = intro_get_username(2)
|
||||
|
||||
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))
|
||||
intro_print_wands()
|
||||
player1.wand = intro_get_wand(player1)
|
||||
player2.wand = intro_get_wand(player2)
|
||||
print()
|
||||
print("{name} will be fighting with an {wood} wand with a {core} core".format(name=player1.name, wood=player1.wand.get_wand_wood().lower(), core=player1.wand.get_wand_core().lower()))
|
||||
print("{name} will be fighting with an {wood} wand with a {core} core".format(name=player2.name, wood=player2.wand.get_wand_wood().lower(), core=player2.wand.get_wand_core().lower()))
|
||||
|
||||
intro_message_duel_start()
|
||||
|
||||
try:
|
||||
while True:
|
||||
if player1.health == 0:
|
||||
print("END! {name} has been defeated. Congratulations {name2}!".format(name=player1.name, name2=player2.name))
|
||||
break
|
||||
elif player2.health == 0:
|
||||
print("END! {name} has been defeated. Congratulations {name2}!".format(name=player2.name, name2=player1.name))
|
||||
break
|
||||
|
||||
current_round += 1
|
||||
start_round(current_round, player1, player2)
|
||||
|
||||
round_get_player_spells(player1, player2)
|
||||
round_set_player_spells_succes(player1, player2)
|
||||
if not player1.active_spell_succes and not player2.active_spell_succes:
|
||||
continue
|
||||
if not player1.active_spell_succes and player2.active_spell_succes:
|
||||
player2.cast_spell(player1)
|
||||
continue
|
||||
elif player1.active_spell_succes and not player2.active_spell_succes:
|
||||
player1.cast_spell(player2)
|
||||
continue
|
||||
|
||||
print()
|
||||
fastest_caster, slowest_caster = round_get_player_spells_speed(player1, player2)
|
||||
round_cast_spells(fastest_caster, slowest_caster)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print()
|
||||
print("<!> Duel ended because both {} and {} suddenly decided to test out their apparition skill!".format(player1.name, player2.name))
|
319
game.py
319
game.py
@ -1,10 +1,11 @@
|
||||
from player import *
|
||||
from wands import *
|
||||
import random
|
||||
from player import Player
|
||||
from wands import wands
|
||||
from spells import Spell, spells, random_combat_spell, print_spells, find_spell_by_name
|
||||
from spells import _INVALID_SPELL, SPELL_TYPE_COMMON, SPELL_TYPE_POWERFUL
|
||||
from game_config import MIN_USERNAME_LEN, MAX_PLAYER_HEALTH
|
||||
|
||||
##
|
||||
## Definitions
|
||||
##
|
||||
input_messages = (
|
||||
INPUT_MESSAGES = (
|
||||
"{name}, what's your spell? ",
|
||||
"{name}, how will you obliviate your opponent? ",
|
||||
"{name}, go for it! Enter a spell! ",
|
||||
@ -12,206 +13,160 @@ input_messages = (
|
||||
"{name}, go time! ",
|
||||
"{name}, it's your turn to enter a spell: "
|
||||
)
|
||||
def print_turn_message(player: Player):
|
||||
return random.choice(input_messages).format(name=player.name)
|
||||
|
||||
current_round = 0
|
||||
def round_end():
|
||||
##
|
||||
## Intro functions
|
||||
##
|
||||
def intro_message_welcome() -> None:
|
||||
print()
|
||||
print("Welcome! You're about to perform a wizard duel!")
|
||||
print("After joining in, you have to select a wand. Your wand will affect the power of your spells. Spells have three atrributes that modify the power of spells:")
|
||||
print("1- DAMAGE: Damage can either deal damage to health points, or it can stun your a player for X amount of moves (DAMAGE below zero = amount of moves a player is stunned)")
|
||||
print("2- SUCCES CHANCE: How much succes chance of performing a spell. Some spells are difficult to pronounce and thus could fail..")
|
||||
print("3- SPEED: If both players succesfully cast a spell, the spell with the greatest speed will succeed and the other one will not")
|
||||
print()
|
||||
|
||||
def intro_message_duel_start() -> None:
|
||||
print("<!> If you need a list of available spells, enter: help (this will not take away a move)")
|
||||
print("<!> If you need information of a specific spell, enter: help SPELL_NAME")
|
||||
print("<!> You can press enter (without typing a spell) to cast a random basic combat spell")
|
||||
print()
|
||||
print("Alright! Time to duel!")
|
||||
|
||||
def intro_get_username(playerid: int) -> str:
|
||||
while True:
|
||||
user_input = input("Player {id} - What's your name? ".format(id=playerid))
|
||||
|
||||
if len(user_input) < MIN_USERNAME_LEN:
|
||||
print("<!> Oops! Names must be at least {len} characters long!".format(len=MIN_USERNAME_LEN))
|
||||
else: break
|
||||
|
||||
return user_input
|
||||
|
||||
def intro_print_wands() -> None:
|
||||
for i in wands.items():
|
||||
print("{wand_id}:{wand_desc}".format(wand_id=i[0], wand_desc=i[1]))
|
||||
|
||||
def intro_get_wand(player: Player) -> Spell:
|
||||
while (True):
|
||||
try:
|
||||
user_input = int(input("What wand do you want {name}? (Enter one of the numbers): ".format(name=player.name)))
|
||||
except ValueError:
|
||||
continue
|
||||
if user_input < 1 or user_input > len(wands):
|
||||
continue
|
||||
break
|
||||
|
||||
return wands[user_input]
|
||||
|
||||
##
|
||||
## Game round functions
|
||||
##
|
||||
def start_round(round: int, player1: Player, player2: Player) -> None:
|
||||
if (player1.stunned_rounds > 0): player1.stunned_rounds -= 1
|
||||
if (player2.stunned_rounds > 0): player2.stunned_rounds -= 1
|
||||
if (player2.stunned_rounds > 0): player2.stunned_rounds -= 1
|
||||
|
||||
print("<!> Round {round} ended! Current stats:\n\
|
||||
print()
|
||||
print("== Round {round} ==".format(round=round))
|
||||
print("-- Current stats:\n\
|
||||
- {p1_name}: Health: {p1_hp} | Queued effects: {p1_effects} | Round being stunned: {p1_stunned}\n\
|
||||
- {p2_name}: Health: {p2_hp} | Queued effects: {p2_effects} | Rounds being stunned: {p2_stunned}".format(
|
||||
round=current_round,
|
||||
round=round,
|
||||
p1_name=player1.name, p1_hp=player1.health, p1_effects=player1.get_queued_effects(), p1_stunned=player1.stunned_rounds,
|
||||
p2_name=player2.name, p2_hp=player2.health, p2_effects=player2.get_queued_effects(), p2_stunned=player2.stunned_rounds
|
||||
)
|
||||
)
|
||||
|
||||
def get_player_spell_from_input(player: Player):
|
||||
def print_turn_message(player: Player) -> None:
|
||||
return random.choice(INPUT_MESSAGES).format(name=player.name)
|
||||
|
||||
def get_player_spell_from_input(player: Player) -> tuple:
|
||||
while True:
|
||||
player_input = input(print_turn_message(player))
|
||||
|
||||
if not player_input:
|
||||
return [random_combat_spell(), 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]
|
||||
|
||||
if spell is spell_object_none:
|
||||
print("<!> Spell '{what}' does not exist!".format(what=find_what))
|
||||
else:
|
||||
print(spell)
|
||||
continue
|
||||
spell_name, spell_obj = random_combat_spell()
|
||||
return ((spell_name, spell_obj), 0)
|
||||
|
||||
if player_input == "help":
|
||||
print_spells()
|
||||
continue
|
||||
elif player_input.find("help", 0) != -1:
|
||||
spell_name, spell_obj = find_spell_by_name(player_input[5:])[0]
|
||||
if spell_obj is spells[_INVALID_SPELL]:
|
||||
print("<!> Spell '{what}' does not exist!".format(what=player_input))
|
||||
else:
|
||||
return find_spell_by_name(player_input)
|
||||
|
||||
##
|
||||
## ENTRY
|
||||
##
|
||||
print()
|
||||
print("Welcome! You're about to perform a wizard duel!")
|
||||
print("After joining in, you have to select a wand. Your wand will affect the power of your spells. Spells have three atrributes that modify the power of spells:")
|
||||
print("1- DAMAGE: Damage can either deal damage to health points, or it can stun your a player for X amount of moves (DAMAGE below zero = amount of moves a player is stunned)")
|
||||
print("2- SUCCES CHANCE: How much succes chance of performing a spell. Some spells are difficult to pronounce and thus could fail..")
|
||||
print("3- SPEED: If both players succesfully cast a spell, the spell with the greatest speed will succeed and the other one will not")
|
||||
print()
|
||||
#GET: USERNAMES
|
||||
while True:
|
||||
player1_name = input("Player 1 - What's your name? ")
|
||||
player2_name = input("And now player 2 - What's your name? ")
|
||||
|
||||
if len(player1_name) < 2 or len(player2_name) < 2:
|
||||
print("<!> Oops! Names must be at least 2 characters long! Please try again")
|
||||
else: break
|
||||
|
||||
#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)
|
||||
|
||||
#Player 1
|
||||
while (True):
|
||||
try:
|
||||
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):
|
||||
continue
|
||||
|
||||
player1_wand = Wand.wandList[wand_input-1]
|
||||
break
|
||||
#Player 2
|
||||
while (True):
|
||||
try:
|
||||
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):
|
||||
continue
|
||||
|
||||
player2_wand = Wand.wandList[wand_input-1]
|
||||
break
|
||||
|
||||
player1 = Player(player1_name, player1_wand)
|
||||
player2 = Player(player2_name, player2_wand)
|
||||
|
||||
print()
|
||||
print("{name} will be fighting with an {wood} wand with a {core} core".format(name=player1.name, wood=player1.wand.get_wand_wood().lower(), core=player1.wand.get_wand_core().lower()))
|
||||
print("{name} will be fighting with an {wood} wand with a {core} core".format(name=player2.name, wood=player2.wand.get_wand_wood().lower(), core=player2.wand.get_wand_core().lower()))
|
||||
print("<!> If you need a list of available spells, enter: help (this will not take away a move)")
|
||||
print("<!> If you need information of a specific spell, enter: help SPELL_NAME")
|
||||
print("<!> You can press enter (without typing a spell) to cast a random basic combat spell")
|
||||
print()
|
||||
print("Alright! Time to duel!")
|
||||
|
||||
game_running = True
|
||||
try:
|
||||
while (game_running):
|
||||
current_round += 1
|
||||
if (current_round != 1):
|
||||
# Weird, right? To have round_end() at the start of a round.
|
||||
# There will be multiple conditions where the current iteration will end.
|
||||
# I'm lazy, hence why it's here :-)
|
||||
|
||||
if player1.health == 0:
|
||||
print("END! {name} has been defeated. Congratulations {name2}!".format(name=player1.name, name2=player2.name))
|
||||
game_running = False
|
||||
break
|
||||
elif player2.health == 0:
|
||||
print("END! {name} has been defeated. Congratulations {name2}!".format(name=player2.name, name2=player1.name))
|
||||
game_running = False
|
||||
break
|
||||
|
||||
round_end()
|
||||
print("'{spell_name}':{spell_desc}".format(spell_name=spell_name, spell_desc=spell_obj))
|
||||
else:
|
||||
return find_spell_by_name(player_input)
|
||||
|
||||
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)
|
||||
def round_get_player_spells(player1: Player, player2: Player) -> None:
|
||||
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
|
||||
|
||||
# OUTCOME: SPELLS
|
||||
# > Get spell succes
|
||||
player1.active_spell_succes = player1.get_spell_succes_rate(player1.active_spell) > random.random() * 100
|
||||
player2.active_spell_succes = player2.get_spell_succes_rate(player2.active_spell) > random.random() * 100
|
||||
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
|
||||
|
||||
print(player1.cast_spell_result(player1.active_spell, player1.active_spell_succes))
|
||||
print(player2.cast_spell_result(player2.active_spell, player2.active_spell_succes))
|
||||
def round_set_player_spells_succes(player1: Player, player2: Player) -> None:
|
||||
player1.active_spell_succes = player1.get_spell_succes_rate(player1.active_spell) > random.random() * 100
|
||||
player2.active_spell_succes = player2.get_spell_succes_rate(player2.active_spell) > random.random() * 100
|
||||
print(player1.cast_spell_result(player1.active_spell, player1.active_spell_succes))
|
||||
print(player2.cast_spell_result(player2.active_spell, player2.active_spell_succes))
|
||||
|
||||
# > 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))
|
||||
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))
|
||||
#
|
||||
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))
|
||||
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))
|
||||
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.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.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.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.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:
|
||||
continue
|
||||
if not player1.active_spell_succes and player2.active_spell_succes:
|
||||
player2.cast_spell(player1)
|
||||
continue
|
||||
elif player1.active_spell_succes and not player2.active_spell_succes:
|
||||
player1.cast_spell(player2)
|
||||
continue
|
||||
def round_get_player_spells_speed(player1: Player, player2: Player) -> tuple:
|
||||
player1.active_spell_speed = player1.active_spell.speed * player1.wand.speed
|
||||
player2.active_spell_speed = player2.active_spell.speed * player2.wand.speed
|
||||
|
||||
# > Determine fastest spell
|
||||
player1.active_spell_speed = player1.active_spell.speed * player1.wand.speed
|
||||
player2.active_spell_speed = player2.active_spell.speed * player2.wand.speed
|
||||
|
||||
if player1.decreased_spell_speed and (player1.active_spell.type == SPELL_TYPE_COMMON or player1.active_spell.type == SPELL_TYPE_POWERFUL):
|
||||
print("<!> {name} is slowed, spell speed decreased by 33%!".format(name=player1.name))
|
||||
player1.active_spell_speed *= 0.67
|
||||
player1.decreased_spell_speed = False
|
||||
if player2.decreased_spell_speed and (player2.active_spell.type == SPELL_TYPE_COMMON or player2.active_spell.type == SPELL_TYPE_POWERFUL):
|
||||
print("<!> {name} is slowed, spell speed decreased by 33%!".format(name=player2.name))
|
||||
player2.active_spell_speed *= 0.67
|
||||
player2.decreased_spell_speed = False
|
||||
if player1.decreased_spell_speed and (player1.active_spell.type == SPELL_TYPE_COMMON or player1.active_spell.type == SPELL_TYPE_POWERFUL):
|
||||
print("<!> {name} is slowed, spell speed decreased by 33%!".format(name=player1.name))
|
||||
player1.active_spell_speed *= 0.67
|
||||
player1.decreased_spell_speed = False
|
||||
if player2.decreased_spell_speed and (player2.active_spell.type == SPELL_TYPE_COMMON or player2.active_spell.type == SPELL_TYPE_POWERFUL):
|
||||
print("<!> {name} is slowed, spell speed decreased by 33%!".format(name=player2.name))
|
||||
player2.active_spell_speed *= 0.67
|
||||
player2.decreased_spell_speed = False
|
||||
|
||||
if player1.decreased_spell_damage and (player1.active_spell.type == SPELL_TYPE_COMMON or player1.active_spell.type == SPELL_TYPE_POWERFUL):
|
||||
print("<!> {name} is blinded, spell damage decreased by 33%!".format(name=player1.name))
|
||||
if player2.decreased_spell_damage and (player2.active_spell.type == SPELL_TYPE_COMMON or player2.active_spell.type == SPELL_TYPE_POWERFUL):
|
||||
print("<!> {name} is blinded, spell damage decreased by 33%!".format(name=player2.name))
|
||||
if player1.decreased_spell_damage and (player1.active_spell.type == SPELL_TYPE_COMMON or player1.active_spell.type == SPELL_TYPE_POWERFUL):
|
||||
print("<!> {name} is blinded, spell damage decreased by 33%!".format(name=player1.name))
|
||||
if player2.decreased_spell_damage and (player2.active_spell.type == SPELL_TYPE_COMMON or player2.active_spell.type == SPELL_TYPE_POWERFUL):
|
||||
print("<!> {name} is blinded, spell damage decreased by 33%!".format(name=player2.name))
|
||||
|
||||
fastest_caster = player1
|
||||
slowest_caster = player2
|
||||
if player2.active_spell_speed > player1.active_spell_speed:
|
||||
fastest_caster = player2
|
||||
slowest_caster = player1
|
||||
fastest_caster = player1
|
||||
slowest_caster = player2
|
||||
if player2.active_spell_speed > player1.active_spell_speed:
|
||||
fastest_caster = player2
|
||||
slowest_caster = player1
|
||||
|
||||
print("- {p1_name}'s spell speed is {p1_spd}. {p2_name}'s spell speed is {p2_spd}. {fastest} is the fastest caster this round!".format(
|
||||
p1_name=player1.name, p1_spd=player1.active_spell_speed,
|
||||
p2_name=player2.name, p2_spd=player2.active_spell_speed,
|
||||
fastest=fastest_caster.name
|
||||
))
|
||||
|
||||
# CAST SPELLS
|
||||
fastest_caster.cast_spell(slowest_caster)
|
||||
if slowest_caster.health > 0:
|
||||
slowest_caster.cast_spell(fastest_caster)
|
||||
print("- {p1_name}'s spell speed is {p1_spd}. {p2_name}'s spell speed is {p2_spd}. {fastest} is the fastest caster this round!".format(
|
||||
p1_name=player1.name, p1_spd=player1.active_spell_speed,
|
||||
p2_name=player2.name, p2_spd=player2.active_spell_speed,
|
||||
fastest=fastest_caster.name
|
||||
))
|
||||
|
||||
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
|
||||
return (fastest_caster, slowest_caster)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print()
|
||||
print("<!> Duel ended because both {} and {} suddenly decided to test out their apparition skill!".format(player1.name, player2.name))
|
||||
def round_cast_spells(player1: Player, player2: Player) -> None:
|
||||
player1.cast_spell(player2)
|
||||
if player2.health > 0:
|
||||
player2.cast_spell(player1)
|
18
game_config.py
Normal file
18
game_config.py
Normal file
@ -0,0 +1,18 @@
|
||||
##
|
||||
## Player config
|
||||
##
|
||||
MIN_USERNAME_LEN = 2 # Minimum length of usernames
|
||||
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
|
97
player.py
97
player.py
@ -1,46 +1,48 @@
|
||||
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):
|
||||
self.name = name
|
||||
self.health = MAX_PLAYER_HEALTH
|
||||
self.wand = wand
|
||||
def __init__(self, name: str, wand: Wand) -> None:
|
||||
self.name: str = name
|
||||
self.health: float = MAX_PLAYER_HEALTH
|
||||
self.wand: Wand = wand
|
||||
|
||||
self.active_spell = spell_object_none
|
||||
self.active_spell_succes = False
|
||||
self.active_spell_levenshtein_distance = 0 # Penalty => If >0 then damage reduction, 15 per distance
|
||||
self.active_spell: Spell = spells[_INVALID_SPELL]
|
||||
self.active_spell_succes: bool = False
|
||||
self.active_spell_levenshtein_distance: int = 0 # Penalty => If >0 then damage reduction, 15 per distance
|
||||
|
||||
self.stunned_rounds = 0
|
||||
self.decreased_spell_speed = False
|
||||
self.decreased_spell_damage = False
|
||||
self.stunned_rounds: int = 0
|
||||
self.decreased_spell_speed: bool = False
|
||||
self.decreased_spell_damage: bool = False
|
||||
|
||||
self.lumos = False
|
||||
self.lumos: bool = False
|
||||
|
||||
def give_health(self, health: int):
|
||||
def give_health(self, health: int) -> float:
|
||||
self.health += health
|
||||
if self.health > MAX_PLAYER_HEALTH:
|
||||
self.health = MAX_PLAYER_HEALTH
|
||||
return self.health
|
||||
|
||||
def take_health(self, health: int):
|
||||
def take_health(self, health: int) -> float:
|
||||
self.health -= health
|
||||
if self.health < 0:
|
||||
self.health = 0
|
||||
return self.health
|
||||
|
||||
def add_stunned_rounds(self, rounds: int):
|
||||
def add_stunned_rounds(self, rounds: int) -> None:
|
||||
self.stunned_rounds += rounds + 1
|
||||
if (self.stunned_rounds > MAX_STUNNED_ROUNDS + 1):
|
||||
self.stunned_rounds = MAX_STUNNED_ROUNDS
|
||||
|
||||
def get_spell_succes_rate(self, spell: Spell):
|
||||
def get_spell_succes_rate(self, spell: Spell) -> float:
|
||||
if spell == None:
|
||||
return 0
|
||||
return 1 * self.wand.succes_rate * spell.succes_rate
|
||||
|
||||
def get_queued_effects(self):
|
||||
def get_queued_effects(self) -> str:
|
||||
output = ""
|
||||
effect_slowed = "Slowed"
|
||||
effect_blinded = "Blinded"
|
||||
@ -55,58 +57,59 @@ class Player:
|
||||
if not output: output = "None"
|
||||
return output
|
||||
|
||||
def cast_spell_result(self, spell: Spell, succes: bool):
|
||||
def cast_spell_result(self, spell: Spell, succes: bool) -> str:
|
||||
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()
|
||||
def cast_spell(self, opponent) -> None:
|
||||
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,8 +184,8 @@ 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))
|
||||
opponent.take_health(total_damage)
|
||||
opponent.take_health(total_damage)
|
143
spells.py
143
spells.py
@ -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,103 +31,116 @@ 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
|
||||
self.speed = speed
|
||||
self.damage = damage
|
||||
self.succes_rate = succes_rate
|
||||
self.description = description
|
||||
self.type = type
|
||||
def __init__(self, speed: int, damage: int, succes_rate: int, description: str, type: int = SPELL_TYPE_COMMON) -> None:
|
||||
self.speed: int = speed
|
||||
self.damage: int = damage
|
||||
self.succes_rate: int = succes_rate
|
||||
self.description: str = description
|
||||
self.type: int = 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)
|
||||
def __repr__(self) -> str:
|
||||
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):
|
||||
def chance_heal_partly_succes(self) -> bool:
|
||||
return self.type == SPELL_TYPE_DEFENSE and CHANCE_HEAL_PARTLY > random.random() * 100
|
||||
|
||||
def chance_heal_fully_succes(self):
|
||||
def chance_heal_fully_succes(self) -> bool:
|
||||
return self.type == SPELL_TYPE_DEFENSE and CHANCE_HEAL_FULLY > random.random() * 100
|
||||
|
||||
def get_spell_name(self) -> str:
|
||||
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])
|
||||
def random_combat_spell() -> tuple:
|
||||
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) -> tuple: # 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():
|
||||
def print_spells() -> None:
|
||||
header_spells_useless = "== USELESS SPELLS =="
|
||||
header_spells_defensive = "== DEFENSIVE SPELLS =="
|
||||
header_spells_common = "== COMMON COMBAT 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)
|
||||
)
|
50
wands.py
50
wands.py
@ -7,18 +7,13 @@ 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) -> None:
|
||||
self.core: int = wand_core
|
||||
self.wood: int = wand_wood
|
||||
|
||||
def __init__(self, wand_core: int, wand_wood: int):
|
||||
self.id = Wand._next_wand_id
|
||||
|
||||
self.core = wand_core
|
||||
self.wood = wand_wood
|
||||
|
||||
self.succes_rate = 1
|
||||
self.speed = 1
|
||||
self.damage = 1
|
||||
self.succes_rate: float = 1
|
||||
self.speed: float = 1
|
||||
self.damage: float = 1
|
||||
|
||||
if self.core == WAND_CORE_UNICORN:
|
||||
self.succes_rate *= 1.03
|
||||
@ -34,21 +29,18 @@ 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)
|
||||
def __repr__(self) -> str:
|
||||
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):
|
||||
def get_wand_core(self) -> str:
|
||||
if self.core == WAND_CORE_UNICORN: return "Unicorn hair"
|
||||
elif self.core == WAND_CORE_PHOENIX: return "Phoenix feather"
|
||||
elif self.core == WAND_CORE_DRAGON: return "Dragon heartstring"
|
||||
else: return "Muggle's electric wire"
|
||||
|
||||
def get_wand_wood(self):
|
||||
def get_wand_wood(self) -> str:
|
||||
if self.wood == WAND_WOOD_ASH: return "Ash"
|
||||
elif self.wood == WAND_WOOD_ELDER: return "Elder"
|
||||
elif self.wood == WAND_WOOD_APPLE: return "Apple"
|
||||
@ -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)
|
||||
}
|
Loading…
Reference in New Issue
Block a user