def check_players_defeat(self, player: Player): has_no_commander = player.commander.unit is None has_no_castle = len( player.buildings.filter_by(type='castle').all()) == 0 if has_no_commander and has_no_castle: player.defeated = True db_session.commit() team_players = self.battle.players.filter_by(team=player.team, defeated=False).all() if team_players: for team_player in team_players: team_player.money += player.money // len(team_players) else: alive_players = self.battle.players.filter_by( defeated=False).all() teams_left = len({p.team for p in alive_players}) if teams_left == 1: self.battle.winner_team = alive_players[0].team self.shared_commands.append( Command('update-status', { 'winnerTeam': self.battle.winner_team, })) db_session.commit()
def increase_unit_xp(self, unit: Unit, delta_xp: int): xp = unit.xp + delta_xp level = bisect.bisect_left(levelList, xp) - 1 unit.xp = xp unit.level = level if level > unit.level: self.shared_commands.append( Command.update_unit(unit, { 'state': 'gaining-level', 'stateParams': { 'level': level }, })) self.shared_commands.append( Command.update_unit(unit, { 'state': 'waiting', 'stateParams': {}, 'level': 'level' })) commander = unit.owner.commander if commander.unit_id == unit.id: commander.xp = xp commander.level = level db_session.commit()
def activate_next_player(self): players = Player.query.filter_by(battle=self.battle, defeated=False).all() prev_player = next(p for p in players if p.id == self.battle.active_player.id) prev_player_index = players.index(prev_player) next_player = players[(prev_player_index + 1) % len(players)] self.battle.active_player = next_player db_session.commit()
def fix_building(self, unit): building = Building.query.filter_by(battle=unit.battle, x=unit.x, y=unit.y).one() building.owner = unit.owner unit.did_fix = True db_session.commit() self.shared_commands.append( Command.update_building(building, { 'state': 'normal', })) self.sync_selected_unit()
def heal_units(self): neutral_buildings_q = self.battle.buildings.filter( Building.type.in_(('well', 'temple'))) buildings = self.battle.active_player.buildings.union_all( neutral_buildings_q).all() injured_units = self.battle.active_player.units.filter( Unit.health < 100).all() deltas = {} for unit in injured_units: b = [b for b in buildings if b.x == unit.x and b.y == unit.y] building = b[0] if b else None if building: up = building_prototypes[building.type]['healthUp'] delta_hp = min(100 - unit.health, up) deltas[unit.id] = delta_hp unit.health += delta_hp db_session.commit() if [u for u in injured_units if u.id in deltas]: self.shared_commands.append( Command( 'update-units', { 'units': [{ 'id': unit.id, 'changes': { 'state': 'healing', 'stateParams': { 'deltaHp': deltas[unit.id], } } } for unit in injured_units] })) self.shared_commands.append( Command( 'update-units', { 'units': [{ 'id': unit.id, 'changes': { 'health': unit.health, 'state': 'waiting', 'stateParams': {}, } } for unit in injured_units] }))
def occupy_building(self, unit): building = Building.query.filter_by(battle=unit.battle, x=unit.x, y=unit.y).one() prev_owner = building.owner building.owner = unit.owner unit.did_occupy = True db_session.commit() self.shared_commands.append( Command.update_building(building, { 'color': building.owner.color, })) self.sync_selected_unit() if prev_owner: self.check_players_defeat(prev_owner)
def reset_units(self): units = Unit.query.filter_by(battle_id=self.battle.id, owner=self.battle.active_player).all() for unit in units: unit.did_move = False unit.did_fix = False unit.did_occupy = False unit.did_attack = False db_session.commit() self.shared_commands.append( Command( 'update-units', { 'units': [{ 'id': unit.id, 'changes': { 'active': True } } for unit in units] }))
def end_turn(self): self.clear_selected_unit() self.reset_units() self.activate_next_player() income = self.collect_gold() self.battle.active_player.money += income db_session.commit() self.shared_commands.append( Command( 'update-status', { 'color': self.battle.active_player.color, 'unitCount': self.battle.active_player.unit_count, 'unitLimit': self.battle.active_player.unit_limit, 'money': self.battle.active_player.money, 'income': income, })) self.heal_units() return self
def decrease_unit_hp(self, unit, delta_hp): health = max(unit.health - delta_hp, 0) self.shared_commands.append( Command.update_unit(unit, { 'state': 'bleeding', 'stateParams': { 'deltaHp': delta_hp, } })) if health == 0: self.kill_unit(unit) else: unit.health = health self.shared_commands.append( Command.update_unit(unit, { 'state': 'waiting', 'stateParams': {}, 'health': unit.health, })) db_session.commit()
def attack_unit(self, attacker: Unit, defender: Unit): defending_player = defender.owner self.shared_commands.append( Command.update_unit( attacker, { 'state': 'attacking', 'stateParams': { 'x': defender.x, 'y': defender.y, 'targetType': 'unit', } })) dmg = calculate_damage(attacker, defender) health = max(defender.health - dmg, 0) self.decrease_unit_hp(defender, dmg) self.increase_unit_xp(attacker, dmg) if health > 0 and can_strike_back(defender, attacker.cell): self.strike_back(defender, attacker) self.shared_commands.append( Command.update_unit(attacker, { 'state': 'waiting', 'stateParams': {}, })) attacker.did_attack = True db_session.commit() if not inspect(attacker).detached: self.sync_selected_unit() else: self.clear_selected_unit() if health == 0: self.check_players_defeat(defending_player)
def buy_unit(self, unit_type: str, store_cell: Cell): store = Building.query.filter_by(battle_id=self.battle.id, x=store_cell.x, y=store_cell.y).one_or_none() if store is None: raise Exception('No player\'s store in that cell') player = self.battle.active_player unit = Unit(type=unit_type, x=store_cell.x, y=store_cell.y, xp=0, level=0, health=100, owner=player, battle=self.battle) db_session.add(unit) if unit_type in commanderList: player.commander.unit = unit player.money -= get_unit_cost(unit.type, player) db_session.commit() self.shared_commands.append(Command.add_unit(unit)) self.shared_commands.append( Command( 'update-status', { 'unitCount': self.battle.active_player.unit_count, 'money': self.battle.active_player.money, })) self.select_unit(unit) return self
def move_unit(self, unit, cell): self.shared_commands.append( Command.update_unit(unit, { 'state': 'moving', 'stateParams': { 'x': cell.x, 'y': cell.y, } })) unit.x = cell.x unit.y = cell.y unit.did_move = True db_session.commit() self.shared_commands.append( Command.update_unit(unit, { 'state': 'waiting', 'stateParams': {}, 'x': cell.x, 'y': cell.y, })) self.sync_selected_unit()
def kill_unit(self, unit: Unit): commander = unit.owner.commander if commander.unit == unit: commander.unit = None commander.death_count += 1 db_session.commit() Unit.query.filter_by(id=unit.id).delete() self.shared_commands.append(Command.delete_unit(unit)) db_session.commit() else: if unit.battle.selected_unit == unit: unit.battle.selected_unit = None db_session.commit() Unit.query.filter_by(id=unit.id).delete() self.shared_commands.append(Command.delete_unit(unit)) grave = Grave(x=unit.x, y=unit.y, ttl=2, battle=unit.battle) db_session.add(grave) db_session.commit() self.shared_commands.append(Command.add_grave(grave))
def start_battle(self, battle_map, preferences): terrain = [] for cell, terrain_type in battle_map['terrain'].items(): [x, y] = cell.split(',') terrain.append(Terrain(x=x, y=y, type=terrain_type)) db_session.add_all(terrain) buildings = {} for b in battle_map['buildings']: building = Building(type=b['type'], x=b['x'], y=b['y'], state=b['state']) if 'ownerId' in b: building.owner_id = b['ownerId'] buildings[b['id']] = building db_session.add_all(buildings.values()) units = {} for u in battle_map['units']: unit = Unit(type=u['type'], x=u['x'], y=u['y'], xp=0, level=0, health=100, did_move=False, did_attack=False, did_fix=False, did_occupy=False) if 'ownerId' in u: unit.owner_id = u['ownerId'] units[u['id']] = unit players = {} for p in battle_map['players']: pref = next(pref for pref in preferences['players'] if pref['id'] == p['id']) commander_unit_id = p['commander']['unitId'] if commander_unit_id: commander_unit = units[commander_unit_id] commander_unit.type = pref['commander'] else: commander_unit = None commander = Commander(character=pref['commander'], death_count=0, xp=0, level=0, unit=commander_unit) player = Player(color=pref['color'], team=pref['team'], money=pref['money'], unit_limit=pref['unitLimit'], type=pref['type'], commander=commander, defeated=False) players[p['id']] = player for b in battle_map['buildings']: if 'ownerId' in b: buildings[b['id']].owner = players[b['ownerId']] for u in battle_map['units']: if 'ownerId' in u: units[u['id']].owner = players[u['ownerId']] db_session.add_all(players.values()) db_session.add_all(units.values()) first_player = next(iter(dict.values(players))) battle = Battle(map_width=battle_map['width'], map_height=battle_map['height'], turn_count=0, circle_count=0, active_player=first_player, terrain=terrain, buildings=buildings.values(), players=players.values(), units=units.values()) db_session.add(battle) db_session.commit() self.shared_commands.append(Command('start-battle', {'id': battle.id})) return self
def clear_selected_unit(self): self.battle.selected_unit = None db_session.commit() self.shared_commands.append(Command('clear-selected-unit', {}))
def select_unit(self, unit): self.battle.selected_unit = unit db_session.commit() self.sync_selected_unit()