Created
April 29, 2021 14:19
-
-
Save verarong/9f44f13b8becd58be34a9a394a077d9e to your computer and use it in GitHub Desktop.
fight
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
try: | |
from FlaskApp.FlaskApp import app, db, tools, schema | |
except: | |
import sys | |
sys.path.append('..') | |
from FlaskApp import app, db, schema | |
from FlaskApp.Mongo_Model import configs | |
from FlaskApp.utils import _sum_dict, debug | |
from itertools import cycle | |
from transitions import Machine | |
from enum import Enum, auto | |
import random | |
from functools import reduce | |
# ============================================= RandomTree ========================================== | |
# | |
class Node: | |
def __init__(self, layer_id, node_id, w, h, min_range, max_range, node_type="monster", | |
legal_buff=(1000, 1001, 1005, 1006, 1010, 1011, 1015, 1016, 1020, 1021)): | |
self.id = str(layer_id * 10 + node_id) | |
self.node_id = node_id | |
if node_type in ["boss", "thread"]: | |
self.loc = (int(w * 0.5), int(h * (layer_id + 0.5))) | |
else: | |
self.loc = (random.randint(int(w * (node_id + min_range)), int(w * (node_id + max_range))), | |
random.randint(int(h * (layer_id + min_range)), int(h * (layer_id + max_range)))) | |
self.node_type = node_type | |
self.legal_buff = legal_buff | |
self.parents = [] | |
def _generate_detail(self, node_type, node_params): | |
if node_type == 'monster': | |
return random.sample(node_params['monster_group'], random.randint(2, 3)) | |
elif node_type == 'warden': | |
return random.sample(node_params['monster_group'], 2) + random.sample(node_params['warden_group'], 1) | |
elif node_type == 'boss': | |
return random.sample(node_params['monster_group'], 2) + random.sample(node_params['boss_group'], 1) | |
elif node_type == 'event': | |
return random.choice(node_params['event_group']) | |
elif node_type == 'box': | |
return random.choice(node_params['box_group']) | |
elif node_type == 'thread': | |
return node_params['thread'] | |
elif node_type == 'campfire': | |
return 'campfire' | |
def add_parent(self, node): | |
if node not in self.parents: | |
self.parents.append(node) | |
def generate(self, node_params): | |
drop, drop_min, drop_max = node_params["drop"] | |
detail = self._generate_detail(self.node_type, node_params) | |
return {"type": self.node_type, "detail": detail, "drop": [drop, random.randint(drop_min, drop_max)], | |
"loc": self.loc, "parents": [node.id for node in self.parents], | |
"legal_buff": random.sample(self.legal_buff, 3) if self.node_type == 'warden' else []} | |
class Layer: | |
def __init__(self, layer_id, width, x, h, min_range, max_range, types, depth, thread=None): | |
self.layer_id = layer_id | |
self.terminal = True if layer_id == depth else False | |
self.pre = True if layer_id == depth - 1 else False | |
self.node_amount = 1 if self.terminal else random.randint(2, width) | |
self.w = int(x / self.node_amount) | |
self.h = h | |
self.thread = thread | |
self.layer = self._add_node(min_range, max_range, types) | |
self.size = len(self.layer) | |
def _add_node(self, min_range, max_range, types): | |
if self.terminal: | |
return [Node(self.layer_id, 0, self.w, self.h, min_range, max_range, "boss")] | |
elif self.thread and self.pre: | |
return [Node(self.layer_id, 0, self.w, self.h, min_range, max_range, "thread")] | |
else: | |
nodes_type = ["monster"] * (self.node_amount - 1) + [random.choice(types)] | |
random.shuffle(nodes_type) | |
return [Node(self.layer_id, i, self.w, self.h, min_range, max_range, x) for i, x in enumerate(nodes_type)] | |
def get_node(self, node_id): | |
return self.layer[node_id] | |
class RandomTree: | |
def __init__(self, depth, width, node_params, x=680, height=200, y=2000, min_range=0.3, max_range=0.7, | |
types=("warden", "event", "box", "campfire")): | |
self.depth = depth | |
self.width = width | |
self.x = x | |
self.y = y | |
self.h = height | |
self.node_params = node_params | |
self.thread = node_params["thread"] if "thread" in node_params else None | |
self.tree = self._generate(min_range, max_range, types) | |
self._get_path() | |
def _generate(self, min_range, max_range, types): | |
return [Layer(i, self.width, self.x, self.h, min_range, max_range, types, self.depth, self.thread) | |
for i in range(self.depth + 1)] | |
def _get_layer(self, layer_id): | |
return self.tree[layer_id] | |
def _get_node(self, layer_id, node_id): | |
return self._get_layer(layer_id).get_node(node_id) | |
def _get_path(self): | |
for layer_id in range(self.depth): | |
current_amount = self._get_layer(layer_id).size | |
next_amount = self._get_layer(layer_id + 1).size | |
current_parent = 0 | |
for node_id in range(current_amount): | |
terminal = next_amount if node_id == current_amount - 1 else random.randint(current_parent, | |
max(1, next_amount - 2)) | |
if terminal == next_amount: | |
self._get_node(layer_id, node_id).add_parent( | |
self._get_node(layer_id + 1, next_amount - 1)) | |
for next_node_id in range(current_parent, min(terminal + 1, next_amount)): | |
self._get_node(layer_id, node_id).add_parent( | |
self._get_node(layer_id + 1, next_node_id)) | |
current_parent = terminal | |
def generate(self): | |
return {node.id: node.generate(self.node_params) for layer in self.tree for node in layer.layer} | |
# ============================================= Fighter ========================================== | |
# | |
class FightSkill(): | |
def __init__(self, skill_id, level=1): | |
self.skill_id = skill_id | |
self.level = level | |
self.cold = 0 | |
self.name, self.cold_round, self.target, self.element, self.ratio, damage_per_level, self.attack_attribute_expand, \ | |
expand_amount_per_level, buff, debuff = self._get_skill() | |
self.damage = damage_per_level * level | |
self.expand_amount = expand_amount_per_level * level | |
self.buff = buff if buff else None | |
self.debuff = debuff if debuff else None | |
def _get_skill(self): | |
return configs.get_values('talent', self.skill_id, | |
["name", "cold_round", "target", "element", "ratio", "damage_per_level", | |
"attack_attribute_expand", "expand_amount_pre_level", "buff", "debuff"]) | |
def update_cold(self, x=-1): | |
self.cold = max(0, self.cold + x) | |
def bool_cold(self): | |
return True if self.cold == 0 else False | |
def generate_attack(self, attack_params): | |
attack = attack_params.copy() | |
attack["attack"] = self.ratio * attack["attack"] + self.damage | |
for x in ["attack", "gold_attack", "wood_attack", "water_attack", "fire_attack", "soil_attack"]: | |
if self.attack_attribute_expand == x: | |
x_ = x.split("_")[0] | |
attack[x_] = attack[x_] + self.expand_amount | |
if self.element: | |
total = sum(attack.values()) | |
attack = {k: total if k == self.element else 0 for k, v in attack.items()} | |
self.update_cold(self.cold_round) | |
return attack | |
class FightBuff(object): | |
def __init__(self, buff_id): | |
self.buff_id = buff_id | |
self.round = 0 | |
self.stack = 1 | |
self.class_, self.bool_stack, self.max_stack, self.max_round, self.type, self.ratio, self.expand = self._get_buff() | |
def _get_buff(self): | |
return configs.get_values('buff', self.buff_id, | |
["class", "bool_stack", "max_stack", "round", "type", "ratio", "expand"]) | |
def update_round(self, x=1): | |
self.round += x | |
if self.type == "hot": | |
return self.expand | |
elif self.type == "drug": | |
return -self.expand | |
return None | |
def update_stack(self, x=1): | |
if self.bool_stack and self.max_stack > self.stack: | |
self.stack += x | |
class Fighter(object): | |
def __init__(self, name="", attack=0, defence=0, life=0, speed=0, hit=0, dodge=0, crit=0, gold_attack=0, | |
wood_attack=0, water_attack=0, fire_attack=0, soil_attack=0, gold_resistance=0, wood_resistance=0, | |
water_resistance=0, fire_resistance=0, soil_resistance=0, all_resistance=0, ignore_defence=0, | |
ignore_resistance=0, hit_param=8888, dodge_param=8888, crit_param=8888, ignore_defence_param=8888, | |
ignore_resistance_param=8888, defence_param=2888, crit_multiply=2, buff=None, current_life=None, | |
base_hit=0.9, *args, **kwargs): | |
self.name = str(name) | |
self.current_life = int(min(current_life, life)) if current_life else int(life) | |
self.hit_param = hit_param | |
self.dodge_param = dodge_param | |
self.crit_param = crit_param | |
self.ignore_defence_param = ignore_defence_param | |
self.ignore_resistance_param = ignore_resistance_param | |
self.defence_param = defence_param | |
self.crit_multiply = crit_multiply | |
self.base_hit = base_hit | |
self.original = {"attack": int(attack), | |
"defence": int(defence), | |
"life": int(life), | |
"current_life": self.current_life, | |
"speed": int(speed), | |
"hit": int(hit), | |
"dodge": int(dodge), | |
"crit": int(crit), | |
"gold_attack": int(gold_attack), | |
"wood_attack": int(wood_attack), | |
"water_attack": int(water_attack), | |
"fire_attack": int(fire_attack), | |
"soil_attack": int(soil_attack), | |
"gold_resistance": int(gold_resistance), | |
"wood_resistance": int(wood_resistance), | |
"water_resistance": int(water_resistance), | |
"fire_resistance": int(fire_resistance), | |
"soil_resistance": int(soil_resistance), | |
"all_resistance": int(all_resistance), | |
"ignore_defence": int(ignore_defence), | |
"ignore_resistance": int(ignore_resistance)} | |
self.buff = [] | |
if buff: | |
for x in buff: | |
self.add_buff(x) | |
self.buff_ratio = {} | |
self.buff_expand = {} | |
self._calculate_attribute() | |
def bool_alive(self): | |
return True if self.current_life > 0 else False | |
def resurrection(self): | |
self.current_life = self.original["life"] | |
def bool_dead(self): | |
return True if self.current_life <= 0 else False | |
def add_buff(self, buff_id): | |
non_exist = True | |
for x in self.buff: | |
if buff_id == x.buff_id and x.bool_stack == 1: | |
x.update_stack() | |
non_exist = False | |
elif buff_id == x.buff_id and x.max_round != 99999: | |
x.update_round(x.max_round) | |
non_exist = False | |
if non_exist: | |
self.buff.append(FightBuff(buff_id)) | |
self._calculate_buff() | |
def buff_progress(self, round=1): | |
buff = [] | |
for x in self.buff: | |
if x.round + round <= x.max_round: | |
life_change = x.update_round(round) | |
buff.append(x) | |
if life_change: | |
self.current_life = min(self.current_life + life_change, self.life) | |
self.buff = buff | |
self._calculate_buff() | |
def _calculate_buff(self): | |
buff_ratio = [] | |
buff_expand = [] | |
for x in self.buff: | |
if x.class_ == 0: | |
buff_ratio.append({x.type: x.ratio * x.stack}) | |
buff_expand.append({x.type: x.expand * x.stack}) | |
elif x.class_ == 1: | |
buff_ratio.append({x.type: -x.ratio * x.stack}) | |
buff_expand.append({x.type: -x.expand * x.stack}) | |
self.buff_ratio = reduce(_sum_dict, buff_ratio) if buff_ratio else {} | |
self.buff_expand = reduce(_sum_dict, buff_expand) if buff_expand else {} | |
self._calculate_attribute() | |
def _calculate_by_type(self, attribute_type): | |
return int(self.original.get(attribute_type, 0) * ( | |
1 + self.buff_ratio.get(attribute_type, 0))) + self.buff_expand.get(attribute_type, 0) | |
def _calculate_attribute(self): | |
self.attack = {"attack": self._calculate_by_type("attack"), | |
"gold": self._calculate_by_type("gold_attack"), | |
"wood": self._calculate_by_type("wood_attack"), | |
"water": self._calculate_by_type("water_attack"), | |
"fire": self._calculate_by_type("fire_attack"), | |
"soil": self._calculate_by_type("soil_attack")} | |
all_resistance = self._calculate_by_type("all_resistance") | |
self.defence = {"defence": self.defence_param / (self._calculate_by_type("defence") + self.defence_param), | |
"gold": self._calculate_by_type("gold_resistance") + all_resistance, | |
"wood": self._calculate_by_type("wood_resistance") + all_resistance, | |
"water": self._calculate_by_type("water_resistance") + all_resistance, | |
"fire": self._calculate_by_type("fire_resistance") + all_resistance, | |
"soil": self._calculate_by_type("soil_resistance") + all_resistance} | |
self.life = self._calculate_by_type("life") | |
self.speed = self._calculate_by_type("speed") | |
self.hit = self._calculate_by_type("hit") | |
self.dodge = self._calculate_by_type("dodge") | |
self.crit = self._calculate_by_type("crit") | |
self.ignore_defence = self._calculate_by_type("ignore_defence") | |
self.ignore_resistance = self._calculate_by_type("ignore_resistance") | |
def _bool_hit(self, skill): | |
hit = self.hit | |
if skill and skill.attack_attribute_expand == "hit": | |
hit += skill.expand_amount | |
return random.random() <= (hit + self.hit_param * self.base_hit) / (hit + self.hit_param) | |
def _bool_crit(self, skill): | |
crit = self.crit | |
if skill and skill.attack_attribute_expand == "crit": | |
crit += skill.expand_amount | |
return random.random() <= crit / (crit + self.crit_param) | |
def _bool_ignore_defence(self, skill): | |
ignore_defence = self.ignore_defence | |
if skill and skill.attack_attribute_expand == "ignore_defence": | |
ignore_defence += skill.expand_amount | |
return random.random() <= ignore_defence / (ignore_defence + self.ignore_defence_param) | |
def _bool_ignore_resistance(self, skill): | |
ignore_resistance = self.ignore_resistance | |
if skill and skill.attack_attribute_expand == "ignore_resistance": | |
ignore_resistance += skill.expand_amount | |
return random.random() <= ignore_resistance / (ignore_resistance + self.ignore_resistance_param) | |
def _get_attack_state(self, skill): | |
state = "hit" | |
bool_ignore_defence = False | |
bool_ignore_resistance = False | |
if not self._bool_hit(skill): | |
return "miss", bool_ignore_defence, bool_ignore_resistance | |
if self._bool_crit(skill): | |
state = "crit" | |
if self._bool_ignore_defence(skill): | |
bool_ignore_defence = True | |
if self._bool_ignore_resistance(skill): | |
bool_ignore_resistance = True | |
return state, bool_ignore_defence, bool_ignore_resistance | |
def generate_attack(self, skill): | |
self.buff_progress() | |
state, bool_ignore_defence, bool_ignore_resistance = self._get_attack_state(skill) | |
attack_param = skill.generate_attack(self.attack) if skill else self.attack | |
if state == "crit": | |
attack_param["attack"] *= self.crit_multiply | |
buff = None | |
if skill and skill.buff: | |
buff = skill.buff | |
self.add_buff(buff) | |
debuff = skill.debuff if skill and skill.debuff else None | |
skill_id = skill.skill_id if skill else None | |
return self.name, skill_id, state, bool_ignore_defence, bool_ignore_resistance, attack_param, buff, debuff | |
def _get_harm_state(self, state): | |
if random.random() <= self.dodge / (self.dodge + self.dodge_param): | |
state = "dodge" | |
return state | |
def generate_harm(self, attack_name, skill_id, state, bool_ignore_defence, bool_ignore_resistance, attack_param, | |
buff, debuff): | |
state = self._get_harm_state(state) | |
if bool_ignore_defence: | |
harm = {'attack': attack_param['attack']} | |
else: | |
harm = {'attack': attack_param['attack'] * self.defence["defence"]} | |
element = ['gold', 'wood', 'water', 'fire', 'soil'] | |
for i in element: | |
harm[i] = attack_param[i] if bool_ignore_resistance else max(0, attack_param[i] - self.defence[i]) | |
if debuff: | |
self.add_buff(debuff) | |
harm_total = 0 | |
if state not in ["miss", "dodge"]: | |
# harm at least 1 | |
harm_total = max(1, int(sum(harm.values()))) | |
self.current_life -= harm_total | |
return [skill_id, state, bool_ignore_defence, bool_ignore_resistance, harm_total, buff, debuff] | |
class Gamer(Fighter): | |
def __init__(self, name, mf, skill_list, animation, *args, **kwargs): | |
super().__init__(*args, **kwargs) | |
self.name = str(name) | |
self.mf = int(mf) | |
self.skill_list = skill_list | |
self.skill = self._generate_skill(**kwargs) | |
self.type_ = "gamer" | |
self.animation = animation | |
self.environment_effect() | |
def get_skills(self): | |
return [i for i, _ in self.skill_list] | |
def _generate_skill(self, **kwargs): | |
return [FightSkill(i, level + kwargs.get(f"talent_{i}", 0)) for i, level in self.skill_list] | |
def environment_effect(self): | |
self.original["attack"] = self.original["attack"] * configs.get_environment_ratio_by_type( | |
"character_attack_strengthen") | |
def get_next_skill(self): | |
for skill in self.skill: | |
skill.update_cold() | |
for skill in self.skill: | |
if skill.bool_cold(): | |
skill.update_cold(skill.cold_round) | |
return skill | |
return FightSkill(100, 1) | |
class Monster(Fighter): | |
def __init__(self, monster_id, ratio=1, *args, **kwargs): | |
super().__init__(name=self._get_name(monster_id), *args, **self._generate_attribute(monster_id, ratio), | |
**kwargs) | |
self.monster_id = monster_id | |
self.type_, self.animation = configs.get_values("monster", monster_id, ["type", "icon"]) | |
self.skill = cycle([FightSkill(i) for i in self.action_tree]) | |
self.environment_effect() | |
def get_skills(self): | |
return self.action_tree | |
def reset_skill(self): | |
self.skill = cycle([FightSkill(i) for i in self.action_tree]) | |
def rebuild(self, monster_id, ratio=1, *args, **kwargs): | |
self.__init__(monster_id, ratio, *args, **kwargs) | |
def environment_effect(self): | |
environment = configs.get_environment_ratio_by_type("monster_life_weaken") | |
self.original["life"] = int(self.original["life"] * environment) | |
self.current_life = int(self.current_life * environment) | |
self.original["attack"] = int(self.original["attack"] * configs.get_environment_ratio_by_type( | |
"monster_attack_strengthen")) | |
def _get_name(self, monster_id): | |
return configs.get_value("monster", monster_id, "name") | |
def _generate_attribute(self, monster_id, ratio): | |
monster_params = configs.get_params('monster', monster_id, configs.legal_params('attribute')) | |
if ratio != 1: | |
monster_params = {k: int(v * ratio) for k, v in monster_params.items()} | |
action_tree_id = configs.get_value('monster', monster_id, 'action_tree') | |
self.action_tree = configs.get_values('action_tree', action_tree_id, drop_na=True) | |
return monster_params | |
# ============================================= Fight ========================================== | |
# | |
class States(Enum): | |
prepare = auto() | |
init = auto() | |
progress = auto() | |
terminal = auto() | |
done = auto() | |
class Fight(object): | |
transitions = [{'trigger': 'prepare', 'source': States.prepare, 'dest': States.init, 'prepare': '_prepare'}, | |
{'trigger': 'progress', 'source': [States.init, States.progress], 'dest': States.terminal, | |
'conditions': '_check_terminal'}, | |
{'trigger': 'progress', 'source': States.progress, 'dest': States.terminal, | |
'conditions': '_check_time_out'}, | |
{'trigger': 'progress', 'source': [States.init, States.progress], 'dest': States.progress, | |
'conditions': '_reverse_check_terminal', 'after': '_progress'}, | |
{'trigger': 'statement', 'source': States.terminal, 'dest': States.done, 'prepare': '_statement'}] | |
def __init__(self, gamer_list, monster_list, gamer_fight=False, distance=1000, second_limit=3000, | |
monster_reset_skill=False): | |
self.gamer_list = gamer_list | |
self.monster_list = monster_list | |
if monster_reset_skill: | |
for monster in self.monster_list: | |
monster.reset_skill() | |
self.fighters = gamer_list + monster_list | |
self.gamer_fight = gamer_fight | |
self.distance = distance | |
self.second_limit = second_limit | |
self.current = 0 | |
self.bool_succeeded = False | |
self.summary = [] | |
self.total_damage_summary = {"gamer": 0, | |
"monster": 0} | |
self.machine = Machine(model=self, states=States, transitions=Fight.transitions, initial=States.prepare) | |
def _prepare(self): | |
self.timer = {x: 0 for x in self.fighters} | |
def _reverse_check_terminal(self): | |
return not self._check_terminal() | |
def _bool_succeeded(self): | |
for x in self.monster_list: | |
if x.bool_alive(): | |
return False | |
return True | |
def _bool_failed(self): | |
for x in self.gamer_list: | |
if x.bool_alive(): | |
return False | |
return True | |
def _check_terminal(self): | |
if self._bool_failed(): | |
return True | |
elif self._bool_succeeded(): | |
self.bool_succeeded = True | |
return True | |
return False | |
def _check_time_out(self): | |
return self.current > self.second_limit | |
def _generate_attack(self, fighter): | |
skill = self._get_skill(fighter) | |
target = self._get_target(fighter, skill) | |
return skill, target, fighter.generate_attack(skill) | |
def _generate_harm(self, fighters, attack_params): | |
summary = [] | |
for fighter in fighters: | |
summary_ = fighter.generate_harm(*attack_params) | |
summary.append(summary_) | |
if fighter in self.gamer_list: | |
self.total_damage_summary["gamer"] += summary_[4] | |
else: | |
self.total_damage_summary["monster"] += summary_[4] | |
return summary | |
def _get_skill(self, fighter): | |
if fighter in self.gamer_list or self.gamer_fight: | |
return fighter.get_next_skill() | |
elif fighter in self.monster_list: | |
return next(fighter.skill) | |
def _get_target(self, fighter, skill): | |
if fighter in self.gamer_list: | |
target_list = [x for x in self.monster_list if x.bool_alive()] | |
else: | |
target_list = [x for x in self.gamer_list if x.bool_alive()] | |
target = skill.target if skill else "start" | |
# print(target, target_list) | |
if target == "all": | |
return target_list | |
elif target == "start": | |
return target_list[:1] | |
elif target == "terminal": | |
return target_list[-1:] | |
else: | |
return target_list[:1] | |
def _get_next_action(self): | |
self.timer = {x: self.timer[x] for x in self.fighters if x.bool_alive()} | |
next_cost = {k: round((self.distance - v) / k.speed, 2) for k, v in self.timer.items()} | |
next_ = min(next_cost, key=next_cost.get) | |
cost = next_cost[next_] | |
self.timer = {k: min(self.distance, v + k.speed * cost) if k != next_ else 0 for k, v in self.timer.items()} | |
return cost, next_ | |
def _progress(self): | |
# print(self.action_index, self.action_tree) | |
cost, fighter = self._get_next_action() | |
self.current += cost | |
# print(fighter.name, fighter.speed) | |
# fighter.buff_progress() | |
skill, target, attack_params = self._generate_attack(fighter) | |
if fighter in self.gamer_list: | |
type_ = "attack" | |
gamer = self.gamer_list.index(fighter) | |
monster = [self.monster_list.index(x) for x in target] | |
else: | |
type_ = "harm" | |
gamer = [self.gamer_list.index(x) for x in target] | |
monster = self.monster_list.index(fighter) | |
self.summary.append({str(self.current): {"type": type_, | |
"fighter": gamer, | |
"monster": monster, | |
"params": self._generate_harm(target, attack_params)}}) | |
def _statement(self): | |
self.flag = "Win" if self.bool_succeeded else "Lose" | |
def get_total_damage(self): | |
return self.total_damage_summary["monster"] | |
def get_total_harm(self): | |
return self.total_damage_summary["gamer"] | |
def get_summary(self): | |
self.prepare() | |
while True: | |
self.progress() | |
if self.state == States.terminal: | |
break | |
self.statement() | |
return self.flag, {"type": "fight", | |
"state": self.bool_succeeded, | |
"battle_terminal": False, | |
"award": None, | |
"gamer_fight": self.gamer_fight, | |
"gamers_summary": [ | |
{"life": x.original["life"], "current_life": x.original["current_life"], "name": x.name, | |
"animation": x.animation, "type": x.type_, "skill": x.get_skills()} | |
for x in self.gamer_list], | |
"monsters_summary": [ | |
{"life": x.original["life"], "current_life": x.original["current_life"], "name": x.name, | |
"animation": x.animation, "type": x.type_, "skill": x.get_skills()} | |
for x in self.monster_list], | |
"summary": self.summary} | |
if __name__ == "__main__": | |
fight = Fight([Gamer("", 0, [], 0, attack=100, life=100, speed=1000, buff=[1000])], [Monster(11)]) | |
state, summary = fight.get_summary() | |
print(state) | |
print(summary) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment