Last active
July 14, 2023 10:43
-
-
Save horstjens/dabf7ea02e4ce695a52d8186ddba4d7d to your computer and use it in GitHub Desktop.
konstantins_magic_duel
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import PySimpleGUI as sg | |
import random | |
from PIL import Image | |
from io import BytesIO | |
import pathlib | |
class Game: | |
tile_size = 80 | |
#image_size = 72*2 # ? # replaced by .size attribute of each monster | |
window = None | |
round = 1 | |
spells = {} | |
log = [] | |
armies = {"red":[], | |
"blue":[], | |
} | |
images = {} | |
red_spell = None | |
blue_spell = None | |
class Spell: | |
def __init__(self, name, **kwargs): | |
self.image_data = None # | |
self.name = name | |
self.image_name = None | |
self.text1 = "" | |
self.text2 = "" | |
Game.spells[name] = self | |
for k,v in kwargs.items(): | |
setattr(self, k, v) | |
def get_image(self): | |
"""search for file lowercase f'{self.name}.png' | |
and load this image, (72x72 pixel), | |
double its size and stores it as data into | |
self.image_data """ | |
filename = self.name.lower()+".png" | |
img = Image.open(filename) | |
w, h = img.size | |
new_size = w*2, h*2 | |
img = img.resize(new_size) | |
# --- transform into data --- | |
with BytesIO() as output: | |
img.save(output, format="PNG") | |
data = output.getvalue() | |
self.image_data = data | |
def __repr__(self): | |
return f"{self.name} mana cost: {self.mana}" | |
def cast(self, caster, enemy_color): | |
my_color = caster.color | |
Game.log.append(f"{my_color} wizard is casting {self.name}....") | |
Game.log.append("effects:") | |
# enough mana to cast the spell? | |
if self.mana > caster.mana: | |
Game.log.append("not enough mana to cast this spell") | |
return | |
caster.mana -= self.mana | |
if self.name == "Rest": | |
caster.mana += 10 | |
Game.log.append(f"{my_color} Wizard is resting and regains 10 mana.") | |
return | |
if self.name.startswith("Summon"): | |
monster = self.name.split(" ")[1] | |
Game.log.append(f"a {monster} appears and joins the {my_color} army.") | |
#if monster == "Dog": | |
#Game.armies[my_color].append(Dog(my_color)) | |
#elif monster == "Cat": | |
#Game.armies[my_color].append(Cat(my_color)) | |
new_monster = globals()[monster](my_color) | |
# load images | |
new_monster.load_images() | |
#new_monster.create_figures() # self.figure is now a number | |
# place new monster on correct square | |
if new_monster.color == "red": | |
i = len(Game.armies["red"]) | |
i -= 1 | |
x = i // 5 | |
y = i % 5 | |
new_monster.create_figures( | |
location=(Game.tile_size * (x) + Game.tile_size/2 - new_monster.size/2, | |
Game.tile_size * (y) + Game.tile_size/2 - new_monster.size/2, | |
)) | |
elif new_monster.color == "blue": | |
i = len(Game.armies["blue"]) | |
i -= 1 | |
x = 10 - i //5 | |
y = 5 - i % 5 | |
new_monster.create_figures( | |
location=(Game.tile_size * (x-1) + Game.tile_size/2 - new_monster.size/2, | |
Game.tile_size * (y-1) + Game.tile_size/2 - new_monster.size/2, | |
)) | |
return | |
# damage spells | |
victims = [] | |
enemy_army = Game.armies[enemy_color] | |
if self.victims == -1: | |
victims = Game.armies[enemy_color] | |
elif self.victims == 1: | |
victims.append(random.choice(enemy_army)) | |
else: | |
random.shuffle(enemy_army) | |
for i in range(self.victims): | |
if len(enemy_army) > i: | |
victims.append(enemy_army[i]) | |
if random.random() > self.jump_chance: | |
break | |
# deal damage | |
for v in victims: | |
damage = random.randint(self.min_damage, self.max_damage) | |
if self.damage_type == "physical": | |
#v.hp -= damage | |
resist = 0 | |
#Game.log.append(f"{my_color} Wizard hits {enemy_color} {v.__class__.__name__} causing {damage} hp damage") | |
# resist damage by type | |
if self.damage_type == "fire": | |
resist = damage * v.resist_fire | |
damage -= resist | |
if self.damage_type == "water": | |
resist = damage * v.resist_water | |
damage -= resist | |
if self.damage_type == "electricity": | |
resist = damage * v.resist_electricity | |
damage -= resist | |
if self.damage_type == "earth": | |
resist = damage * v.resist_earth | |
damage -= resist | |
if self.damage_type == "mind": | |
resist = damage * v.resist_mind | |
damage -= resist | |
# TODO: change state | |
resist = int(resist) | |
damage = int(damage) | |
text = f"{enemy_color} {v.__class__.__name__} can resist {resist} of {damage+resist} {self.damage_type} damage and looses {damage} hp" | |
v.hp -= damage | |
if v.hp <= 0: | |
text += "...killed!" | |
text += f" ({v.hp} hp left)." | |
Game.log.append(text) | |
class Monster: | |
def __init__(self, color): | |
self.color = color | |
self.state = "normal" | |
self.cast_user_spell = False | |
self.cast_random_spell = False | |
self.images = {"normal":[], | |
"attack":[], | |
"defend":[], | |
} | |
if self.color in Game.armies: | |
Game.armies[color].append(self) | |
else: | |
Game.armies[color] = [self] | |
def create_figures(self, location): | |
self.figure = Game.window["canvas"].draw_image(data=self.images["normal"][0], | |
location=location) | |
def __repr__(self): | |
return f"{self.color} {self.__class__.__name__} hp:{self.hp} state:{self.state}" | |
def get_image(self, filename, flip=False, factor=2): | |
"""search for file lowercase f'{self.name}.png' | |
and load this image, (72x72 pixel), | |
double its size and stores it as data into | |
self.image_data """ | |
#filename = self.name.lower()+".png" | |
img = Image.open(filename) | |
w, h = img.size | |
print("factor:", factor) | |
new_size = w*factor, h*factor | |
img = img.resize(new_size) | |
self.size = img.size[0] | |
# --- flip left/right ? ---- | |
if flip: | |
img = img.transpose(Image.FLIP_LEFT_RIGHT) | |
# --- transform into data --- | |
with BytesIO() as output: | |
img.save(output, format="PNG") | |
data = output.getvalue() | |
#self.image_data = data | |
return data | |
def load_images(self): | |
flip = False if self.color == "red" else True | |
for png_file_name in pathlib.Path(".").glob("*.png"): | |
p = png_file_name.parts[-1] | |
if p.startswith(self.__class__.__name__.lower()): | |
if p[:-4] == self.__class__.__name__.lower(): | |
self.images["normal"].append(self.get_image(p, factor=1,flip=flip)) | |
continue | |
for state in self.images: # keys: normal, attack, defend | |
if state == "normal": | |
continue | |
if state in p: | |
self.images[state].append(self.get_image(p, factor=1, flip=flip)) | |
class Wizard(Monster): | |
def __init__(self, color): | |
super().__init__(color) | |
self.cast_user_spell = True | |
#self.color = color | |
self.hp = 100 | |
self.mana = 100 | |
self.resist_fire = 0.8 | |
self.resist_water = 0.5 | |
self.resist_electricity = 0.5 | |
self.resist_earth = 0.5 | |
self.resist_mind = 0.9 | |
self.state = "clear" | |
self.attack = 10 | |
self.defense = 20 | |
self.damage = 10 | |
self.load_images() | |
def load_images(self): | |
if self.color == "red": | |
self.images["normal"].append(self.get_image("red_wizard.png")) | |
self.images["attack"].append(self.get_image("red_wizard-attack1.png")) | |
self.images["attack"].append(self.get_image("red_wizard-attack2.png")) | |
self.images["attack"].append(self.get_image("red_wizard-attack3.png")) | |
self.images["attack"].append(self.get_image("red_wizard-attack4.png")) | |
self.images["attack"].append(self.get_image("red_wizard-attack5.png")) | |
self.images["attack"].append(self.get_image("red_wizard-attack6.png")) | |
self.images["attack"].append(self.get_image("red_wizard-attack7.png")) | |
self.images["attack"].append(self.get_image("red_wizard-attack8.png")) | |
self.images["defend"].append(self.get_image("red_wizard-defend1.png")) | |
self.images["defend"].append(self.get_image("red_wizard-defend2.png")) | |
elif self.color == "blue": | |
self.images["normal"].append(self.get_image("blue_wizard.png")) # flip not necessary because blue wizard images are already flipped | |
self.images["attack"].append(self.get_image("blue_wizard-attack1.png")) | |
self.images["attack"].append(self.get_image("blue_wizard-attack2.png")) | |
self.images["defend"].append(self.get_image("blue_wizard-defend.png")) | |
def __repr__(self): | |
# overwrite __repr__ of Monster class because wizard must show also mana | |
return f"{self.color} {self.__class__.__name__} hp:{self.hp} mana:{self.mana} state:{self.state}" | |
class Bear(Monster): | |
def __init__(self, color): | |
super().__init__(color) | |
#self.color = color | |
self.hp = 150 | |
self.resist_fire = 0.5 | |
self.resist_water = 0.5 | |
self.resist_electricity = 0.5 | |
self.resist_earth = 0.8 | |
self.resist_mind = 0.2 | |
self.state = "clear" | |
self.attack = 25 | |
self.defense = 10 | |
self.damage = 30 | |
class Wolf(Monster): | |
def __init__(self, color): | |
super().__init__(color) | |
#self.color = color | |
self.hp = 50 | |
self.resist_fire = 0.1 | |
self.resist_water = 0.8 | |
self.resist_electricity = 0.5 | |
self.resist_earth = 0.2 | |
self.resist_mind = 0.5 | |
self.state = "clear" | |
self.attack = 15 | |
self.defense = 10 | |
self.damage = 15 | |
def fight(attacker, defender): | |
a = random.randint(1,6) + random.randint(1,6) | |
d = random.randint(1,6) + random.randint(1,6) | |
attack_value = a + attacker.attack | |
defense_value = d + defender.defense | |
if attack_value > defense_value: | |
defender.hp -= attacker.damage | |
Game.log.append(f"{defender} looses {attacker.damage} hp") | |
if defender.hp > 0: | |
Game.log.append(f"({defender.hp} hp left)") | |
else: | |
Game.log.append(f"{defender} is killed") | |
else: | |
Game.log.append("attack fails") | |
def battle(attacker, defender): | |
Game.log.append("strike") | |
fight(attacker, defender) | |
if defender.hp > 0: | |
Game.log.append("counterstrike") | |
fight(defender, attacker) | |
#sg.PopupOK("Hallo") | |
layout = [ | |
[sg.Table([["red wizard", 100, "clear"]], | |
headings=["monster"," hp ","state"], | |
key="red_army", size=(20,25)), | |
sg.Graph((800,400), | |
graph_bottom_left=(0,400), | |
graph_top_right = (800,0), | |
key="canvas", | |
background_color="black"), | |
sg.Table([["blue wizard", 100, "clear"]], | |
headings=["monster"," hp ","state"], | |
key="blue_army", size=(20,25)), | |
], | |
[sg.Text("red Wizard (100 mana)",font="Arial 20", text_color="red", key="redmana"), | |
#sg.Text("mana:100", key="redmana"), | |
sg.Push(), | |
sg.Text("blue Wizard (100 mana)",font="Arial 20", text_color="blue", key="bluemana"), | |
#sg.Text("m, key="bluewizstat", text_color="blue") | |
], | |
[sg.Table([["Fireball", 15]], | |
headings=["Spell name", "mana cost"], | |
select_mode=sg.TABLE_SELECT_MODE_BROWSE, | |
key="spells_red", | |
size=(25,10), | |
enable_events=True, | |
), | |
sg.Push(), | |
sg.Multiline("Game log:", key="log", disabled=True, | |
autoscroll=True,size=(45,10)), | |
sg.Graph(canvas_size=(450,180), | |
graph_bottom_left=(0.0,1.0), | |
graph_top_right=(1.0,0.0), | |
background_color="black", | |
key="details"), | |
sg.Push(), | |
#sg.Listbox(["Fireball","Tsunami"], | |
# select_mode=sg.SELECT_MODE_SINGLE, | |
# key="spells_blue", | |
# size=(25,10), | |
# disabled=False), | |
sg.Table([["Fireball", 15]], | |
headings=["Spell name", "mana cost"], | |
select_mode=sg.TABLE_SELECT_MODE_BROWSE, | |
key="spells_blue", | |
size=(25,10), | |
enable_events=True, | |
), | |
], | |
[sg.Button("OK"), sg.Button("Cancel"),sg.Text("red Wizard, choose a spell and click OK", key="message", font="Arial 20", text_color="red"),], | |
] | |
def main(): | |
Spell("Fireball", | |
mana=20, | |
damage_type="fire", | |
min_damage=10, | |
max_damage=25, | |
victims = 3, | |
jump_chance=1.0, | |
text1 = "3 victims suffer 10-25 fire damage") | |
Spell("Flash", | |
mana=15, | |
damage_type="electricity", | |
victims=5, | |
min_damage=5, | |
max_damage=15, | |
jump_chance=0.6, | |
text1 = "Inflicts 5-15 electric damage ", | |
text2 = "to 1-5 victims (60% jump chance)" | |
) | |
Spell("Quake", | |
mana = 40, | |
damage_type="earth", | |
victims=-1, | |
min_damage=20, | |
max_damage=50, | |
text1= "Inflicts 20-50 earth damage", | |
text2= "to all enemies") | |
Spell("Tsunami", | |
mana=60, | |
damage_type="water", | |
victims=-1, | |
min_damage=30, | |
max_damage=60, | |
text1="Inflicts 30-60 water damage", | |
text2="to all enemies") | |
Spell("Dazzle", | |
mana = 10, | |
damage_type="mind", | |
victims=1, | |
min_damage=3, | |
max_damage=11, | |
text1="Inflicts 3-11 mind damage", | |
text2="to a single enemy",) | |
Spell("Summon Bear", mana=35, victims=0, text1="Bear has 120 hp") | |
Spell("Summon Wolf", mana=20, victims=0, text1="Wolf has 50 hp") | |
Spell("Melee attack", | |
mana=1, | |
victims=1, | |
damage_type="physical", | |
min_damage=1, | |
max_damage=5, | |
text1="Inflicts 1-5 physical damage", | |
text2="to one enemy (no counterstrike)") | |
Spell("Rest", mana=0, victims=0, text1="wizard regains 10 mana points") | |
# all spells done, load spell images | |
for s in Game.spells.values(): | |
s.get_image() # dont do this on __init__ more safe here... should be only made once | |
Game.window = sg.Window("magic duel", layout) | |
Game.window.finalize() | |
# ---- grid lines ---- | |
for y in range(0, 401, Game.tile_size): | |
Game.window["canvas"].draw_line((0,y),(800,y),"white",1) | |
for x in range(0, 801, Game.tile_size): | |
Game.window["canvas"].draw_line((x,0),(x,400),"white",1) | |
wiz_red = Wizard("red") | |
wiz_red.create_figures(location=(Game.tile_size/2 - wiz_red.size/2, | |
Game.tile_size/2 - wiz_red.size/2,)) | |
wiz_blue = Wizard("blue") | |
wiz_blue.create_figures(location=(Game.tile_size * 9 + Game.tile_size/2 - wiz_blue.size/2, | |
Game.tile_size * 4 + Game.tile_size/2 - wiz_blue.size/2,)) | |
spell_list = list(Game.spells.values()) | |
spell_list.sort(key=lambda x: x.mana) | |
show_list = [[f"{s.name}",f"{s.mana}"] for s in spell_list if s.mana <= wiz_red.mana] | |
Game.window["spells_red"].update(show_list) | |
#show_list = [f"{s.name}" for s in spell_list if s.mana <= wiz_blue.mana] | |
show_list = [[f"{s.name}",f"{s.mana}"] for s in spell_list if s.mana <= wiz_blue.mana] | |
Game.window["spells_blue"].update(show_list) | |
Game.window["spells_blue"].update(num_rows=0) | |
number_of_spells = len(Game.spells) | |
while True: | |
event, values = Game.window.read() | |
if event in (sg.WIN_CLOSED, "Cancel"): | |
break | |
if event == "OK": | |
if Game.red_spell is None and Game.blue_spell is None: | |
sg.PopupError("red Wizard must choose a spell") | |
continue | |
if Game.red_spell is not None and Game.blue_spell is None: | |
Game.log.append(f"Red wizard choose: {Game.red_spell.name}") | |
Game.window["log"].update("\n".join(Game.log)) | |
Game.window["message"].update("Blue wizard, choose a spell and click OK", text_color="blue") | |
Game.window["spells_red"].update(num_rows=0) # hide rows | |
Game.window["spells_blue"].update(num_rows=number_of_spells) # show all rows | |
continue | |
if Game.red_spell is not None and Game.blue_spell is not None: | |
Game.log.append(f"Blue wizard choose: {Game.blue_spell.name}") | |
# execute turn | |
Game.log.append(f"----- round {Game.round} ------") | |
# cast simultanious ? | |
# summoning spells | |
for i, s in enumerate([Game.red_spell, Game.blue_spell]): | |
if s.name.startswith("Summon"): | |
caster = wiz_red if i==0 else wiz_blue | |
enemy_color = "blue" if i == 0 else "red" | |
s.cast(caster, enemy_color ) | |
# ---- non-summuning spells ------ | |
for i, s in enumerate([Game.red_spell, Game.blue_spell]): | |
if not s.name.startswith("Summon"): | |
caster = wiz_red if i==0 else wiz_blue | |
enemy_color = "blue" if i == 0 else "red" | |
s.cast(caster, enemy_color ) | |
# --- update mana --- | |
Game.window["redmana"].update(f"red Wizard ({wiz_red.mana} mana)") | |
Game.window["bluemana"].update(f"blue Wizard ({wiz_blue.mana} mana)") | |
# ---- update battle map (remove dead figures) ---- | |
for color in ("red", "blue"): | |
for m in Game.armies[color]: | |
if m.hp <= 0: | |
Game.log.append(f"{m.color} {m.__class__.__name__} dies!") | |
Game.window["canvas"].delete_figure(m.figure) | |
# ---- update army list (remove dead monsters ) ---- | |
Game.armies[color] = [m for m in Game.armies[color] if m.hp >0] | |
# ---- prepare next round --- | |
Game.round += 1 | |
Game.window["log"].update("\n".join(Game.log)) | |
Game.red_spell = None | |
Game.blue_spell = None | |
Game.window["spells_red"].update(num_rows=number_of_spells, select_rows=[]) | |
Game.window["spells_blue"].update(num_rows=0) | |
# ---- update spell list --- | |
for i, wiz in enumerate((wiz_red, wiz_blue)): | |
show_list = [[f"{s.name}",f"{s.mana}"] for s in spell_list if s.mana <= wiz.mana] | |
if i == 0: | |
Game.window["spells_red"].update(show_list) | |
elif i == 1: | |
Game.window["spells_blue"].update(show_list) | |
Game.window["message"].update("Red wizard, choose a spell and click OK", text_color="red") | |
Game.window["details"].erase() | |
# ---- update army list ---- | |
red_army_list = [("red wizard", wiz_red.hp, wiz_red.state)] | |
for m in Game.armies["red"]: | |
if m.__class__.__name__ != "Wizard": | |
red_army_list.append((f"red {m.__class__.__name__}", m.hp, m.state)) | |
blue_army_list = [("blue wizard", wiz_blue.hp, wiz_blue.state)] | |
for m in Game.armies["blue"]: | |
if m.__class__.__name__ != "Wizard": | |
blue_army_list.append((f"blue {m.__class__.__name__}", m.hp, m.state)) | |
Game.window["red_army"].update(red_army_list) | |
Game.window["blue_army"].update(blue_army_list) | |
if event in ("spells_red", "spells_blue"): | |
if len(values[event]) == 0: # nothing selected | |
continue | |
line_number = values[event][0] # list with line number inside | |
#print(line_number) | |
wiz = wiz_red if event == "spells_red" else wiz_blue | |
show_list = [[f"{s.name}",f"{s.mana}"] for s in spell_list if s.mana <= wiz.mana] | |
spell_name = show_list[line_number][0] | |
text1 = Game.spells[spell_name].text1 | |
text2 = Game.spells[spell_name].text2 | |
spell = Game.spells[spell_name] | |
if event == "spells_red": | |
Game.red_spell = spell | |
elif event == "spells_blue": | |
Game.blue_spell = spell | |
#print(spell_name, text1, text2) | |
# detail feld löschen | |
d = Game.window["details"] | |
d.erase() | |
d.draw_text(spell_name, | |
location=(0.4, 0), | |
color="red", | |
font="System 20", | |
text_location=sg.TEXT_LOCATION_TOP_LEFT | |
) | |
d.draw_text(text1, | |
location=(0.4, 0.5), | |
color="white", | |
font="System 12", | |
text_location=sg.TEXT_LOCATION_TOP_LEFT | |
) | |
d.draw_text(text2, | |
location=(0.4, 0.75), | |
color="white", | |
font="System 12", | |
text_location=sg.TEXT_LOCATION_TOP_LEFT | |
) | |
d.draw_image(#filename=spell_name.lower()+".png", | |
data = spell.image_data, | |
location=(0,0)) | |
Game.window.close() | |
if __name__ == "__main__": | |
main() | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import random | |
class Game: | |
spells = {} | |
log = [] | |
armies = {"red":[], | |
"blue":[], | |
} | |
class Spell: | |
def __init__(self, name, **kwargs): | |
self.name = name | |
Game.spells[name] = self | |
for k,v in kwargs.items(): | |
setattr(self, k, v) | |
def __repr__(self): | |
return f"{self.name} mana cost: {self.mana}" | |
def cast(self, my_color, enemy_color): | |
Game.log.append(f"{my_color} wizard is casting {self.name}....") | |
Game.log.append("effects:") | |
if self.name == "Rest": | |
self.mana += 10 | |
Game.log.append(f"{my_color} Wizard is resting and regains 10 mana.") | |
return | |
if self.name.startswith("Summon"): | |
monster = self.name.split(" ")[1] | |
Game.log.append(f"a {monster} appears and joins the {my_color} army.") | |
#if monster == "Dog": | |
#Game.armies[my_color].append(Dog(my_color)) | |
#elif monster == "Cat": | |
#Game.armies[my_color].append(Cat(my_color)) | |
globals()[monster](my_color) | |
return | |
# damage spells | |
victims = [] | |
enemy_army = Game.armies[enemy_color] | |
if self.victims == -1: | |
victims = Game.armies[enemy_color] | |
elif self.victims == 1: | |
victims.append(random.choice(enemy_army)) | |
else: | |
random.shuffle(enemy_army) | |
for i in range(self.victims): | |
if len(enemy_army) > i: | |
victims.append(enemy_army[i]) | |
if random.random() > self.jump_chance: | |
break | |
# deal damage | |
for v in victims: | |
damage = random.randint(self.min_damage, self.max_damage) | |
if self.damage_type == "physical": | |
#v.hp -= damage | |
resist = 0 | |
#Game.log.append(f"{my_color} Wizard hits {enemy_color} {v.__class__.__name__} causing {damage} hp damage") | |
# resist damage by type | |
if self.damage_type == "fire": | |
resist = damage * v.resist_fire | |
damage -= resist | |
if self.damage_type == "water": | |
resist = damage * v.resist_water | |
damage -= resist | |
if self.damage_type == "electricity": | |
resist = damage * v.resist_electricity | |
damage -= resist | |
if self.damage_type == "earth": | |
resist = damage * v.resist_earth | |
damage -= resist | |
if self.damage_type == "mind": | |
resist = damage * v.resist_mind | |
damage -= resist | |
# TODO: change state | |
resist = int(resist) | |
damage = int(damage) | |
text = f"{enemy_color} {v.__class__.__name__} can resist {resist} of {damage+resist} {self.damage_type} damage and looses {damage} hp" | |
v.hp -= damage | |
if v.hp <= 0: | |
text += "...killed!" | |
text += f" ({v.hp} hp left)." | |
Game.log.append(text) | |
Spell("Fireball", | |
mana=20, | |
damage_type="fire", | |
min_damage=10, | |
max_damage=25, | |
victims = 3, | |
jump_chance=1.0) | |
Spell("Flash", | |
mana=15, | |
damage_type="electricity", | |
victims=5, | |
min_damage=5, | |
max_damage=15, | |
jump_chance=0.6) | |
Spell("Quake", | |
mana = 40, | |
damage_type="earth", | |
victims=-1, | |
min_damage=20, | |
max_damage=50) | |
Spell("Tsunami", | |
mana=60, | |
damage_type="water", | |
victims=-1, | |
min_damage=30, | |
max_damage=60) | |
Spell("Dazzle", | |
mana = 10, | |
damage_type="mind", | |
victims=1, | |
min_damage=3, | |
max_damage=11) | |
Spell("Summon Cat", mana=5, victims=0) | |
Spell("Summon Dog", mana=15, victims=0) | |
Spell("Melee attack", | |
mana=1, | |
victims=1, | |
damage_type="physical", | |
min_damage=1, | |
max_damage=5) | |
Spell("Rest", mana=0, victims=0) | |
class Monster: | |
def __init__(self, color): | |
self.color = color | |
if self.color in Game.armies: | |
Game.armies[color].append(self) | |
else: | |
Game.armies[color] = [self] | |
def __repr__(self): | |
return f"{self.color} {self.__class__.__name__} hp:{self.hp} state:{self.state}" | |
class Wizard(Monster): | |
def __init__(self, color): | |
super().__init__(color) | |
#self.color = color | |
self.hp = 100 | |
self.mana = 100 | |
self.resist_fire = 0.8 | |
self.resist_water = 0.5 | |
self.resist_electricity = 0.5 | |
self.resist_earth = 0.5 | |
self.resist_mind = 0.9 | |
self.state = "clear" | |
self.attack = 10 | |
self.defense = 20 | |
self.damage = 10 | |
def __repr__(self): | |
# overwrite __repr__ of Monster class because wizard must show also mana | |
return f"{self.color} {self.__class__.__name__} hp:{self.hp} mana:{self.mana} state:{self.state}" | |
class Cat(Monster): | |
def __init__(self, color): | |
super().__init__(color) | |
#self.color = color | |
self.hp = 20 | |
self.resist_fire = 0.2 | |
self.resist_water = 0.1 | |
self.resist_electricity = 0.5 | |
self.resist_earth = 0.8 | |
self.resist_mind = 0.1 | |
self.state = "clear" | |
self.attack = 8 | |
self.defense = 30 | |
self.damage = 4 | |
class Dog(Monster): | |
def __init__(self, color): | |
super().__init__(color) | |
#self.color = color | |
self.hp = 40 | |
self.resist_fire = 0.1 | |
self.resist_water = 0.8 | |
self.resist_electricity = 0.5 | |
self.resist_earth = 0.2 | |
self.resist_mind = 0.5 | |
self.state = "clear" | |
self.attack = 15 | |
self.defense = 10 | |
self.damage = 15 | |
wiz_red = Wizard("red") | |
wiz_blue = Wizard("blue") | |
#print(army1, army2) | |
game_round = 0 | |
while (wiz_red.hp > 0) and (wiz_blue.hp > 0): | |
game_round += 1 | |
print(f"========== Game round {game_round} =============") | |
print("++++++army overview:++++++") | |
for color in Game.armies: | |
print("=======",color, "army: =========") | |
for soldier in Game.armies[color]: | |
print(soldier) | |
print("----------------") | |
print("------ choosing actions -------") | |
actions = {} | |
spells = {} | |
for color in Game.armies: | |
print(f"{color} Wizard, please choose your action") | |
for i, spell in enumerate(Game.spells.values()): | |
print(i, spell) | |
actions[color] = input("?") | |
spells[color] = list(Game.spells.values())[int(actions[color])] | |
print("======== results =============") | |
# TODO: random colorlist (initative-wert?) | |
for color in Game.armies: | |
last_line = len(Game.log) | |
if color == "red": | |
enemy_color = "blue" | |
elif color == "blue": | |
enemy_color = "red" | |
# TODO: ask player for enemy color | |
# TODO: make sure summoning spells are executed before damage spells | |
spells[color].cast(color, enemy_color) | |
print("\n".join(Game.log[last_line:])) | |
print("----------------------------") | |
# eliminate dead monsters | |
for color in Game.armies: | |
Game.armies[color] = [m for m in Game.armies[color] if m.hp > 0] | |
# TODO: surviving monsters attack random enemy | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment