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()
Exemple #10
0
    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)
Exemple #11
0
    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
Exemple #12
0
    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()
Exemple #13
0
    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))
Exemple #14
0
    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
Exemple #15
0
    def clear_selected_unit(self):
        self.battle.selected_unit = None
        db_session.commit()

        self.shared_commands.append(Command('clear-selected-unit', {}))
Exemple #16
0
    def select_unit(self, unit):
        self.battle.selected_unit = unit
        db_session.commit()

        self.sync_selected_unit()