jardiacaj/finem_imperii

View on GitHub
turn/battle.py

Summary

Maintainability
C
1 day
Test Coverage
import organization.models
import unit.models
from battle.battle_init import start_battle, initialize_from_conflict, \
    add_unit_to_battle_in_progress
from battle.battle_tick import battle_turn
from battle.models import Battle, BattleOrganization
from world.models.geography import World


def worldwide_trigger_battles(world: World):
    for tile in world.tile_set.all():
        if not Battle.objects.filter(
                tile=tile,
                end_turn=world.current_turn).exists():
            trigger_battles_in_tile(tile)


def trigger_battles_in_tile(tile):
    conflicts = opponents_in_organization_list(
        organizations_with_battle_ready_units(tile),
        tile
    )
    for conflict in conflicts:
        add_allies(conflict, tile)
    conflict = get_largest_conflict_in_list(conflicts, tile)
    if conflict:
        return create_battle_from_conflict(conflict, tile)


def worldwide_battle_joins(world: World):
    for battle in Battle.objects.filter(
            tile__world=world, current=True
    ):
        battle_joins(battle)


def worldwide_battle_starts(world: World):
    for battle in Battle.objects.filter(
            tile__world=world, current=True, started=False
    ):
        start_battle(battle)


def worldwide_battle_turns(world: World):
    for battle in Battle.objects.filter(
            tile__world=world, current=True
    ):
        battle_turn(battle)


def organizations_with_battle_ready_units(tile):
    result = []
    for unit in battle_ready_units_in_tile(tile):
        violence_monopoly = unit.get_violence_monopoly()
        if violence_monopoly and violence_monopoly not in result:
            result.append(violence_monopoly)
    return result


def battle_ready_units_in_tile(tile):
    return tile.get_units().\
        exclude(status=unit.models.WorldUnit.NOT_MOBILIZED).\
        exclude(status=unit.models.WorldUnit.REGROUPING).\
        exclude(battleunit__battle_side__battle__current=True)


def opponents_in_organization_list(organizations, tile):
    potential_conflicts = []

    input_list = list(organizations)
    while len(input_list):
        i = input_list.pop()
        for j in input_list:
            if i.get_region_stance_to(j, tile).get_stance() == organization.models.relationship.MilitaryStance.AGGRESSIVE:
                potential_conflicts.append([[i, ], [j, ]])
    return potential_conflicts


def add_allies(conflict, tile):
    for i, conflict_side in enumerate(conflict):
        other_conflict_side = conflict[0 if i == 1 else 1]
        for candidate in organizations_with_battle_ready_units(tile):
            if candidate in conflict_side or candidate in other_conflict_side:
                continue
            aggressive_to_all_in_other_side = True
            for state in other_conflict_side:
                stance = candidate.get_region_stance_to(state, tile).get_stance()
                if stance != organization.models.relationship.MilitaryStance.AGGRESSIVE:
                    aggressive_to_all_in_other_side = False
                    break
            aggressive_to_own_side = False
            for state in conflict_side:
                stance = candidate.get_region_stance_to(state, tile).get_stance()
                if stance == organization.models.relationship.MilitaryStance.AGGRESSIVE:
                    aggressive_to_own_side = True
                    break
            if aggressive_to_all_in_other_side and not aggressive_to_own_side:
                conflict[i].append(candidate)


def get_largest_conflict_in_list(conflicts, tile):
    result = None
    max_soldiers = 0
    for conflict in conflicts:
        soldiers = 0
        conflicting_states = conflict[0] + conflict[1]
        for unit in battle_ready_units_in_tile(tile):
            if unit.get_violence_monopoly() in conflicting_states:
                soldiers += unit.get_fighting_soldiers().count()
        if soldiers > max_soldiers:
            result = conflict
    return result


def create_battle_from_conflict(conflict, tile):
    battle = Battle.objects.create(
        tile=tile,
        current=True,
        start_turn=tile.world.current_turn
    )
    initialize_from_conflict(battle, conflict, tile)

    battle.tile.world.broadcast(
        'messaging/messages/battle_start.html',
        'Battle starts!',
        {'battle': battle},
        battle.get_absolute_url()
    )

    return battle


def battle_joins(battle: Battle):
    for candidate_unit in battle_ready_units_in_tile(battle.tile):
        candidate_vm = candidate_unit.get_violence_monopoly()
        try:
            battle_org = BattleOrganization.objects.get(
                side__battle=battle,
                organization=candidate_vm
            )
            add_unit_to_battle_in_progress(battle_org, candidate_unit)
        except BattleOrganization.DoesNotExist:
            sides = list(battle.battleside_set.all())
            for i, side in enumerate(sides):
                other_side = sides[0 if i == 1 else 1]
                aggressive_to_all_in_other_side = True
                for battle_state in other_side.battleorganization_set.all():
                    state = battle_state.organization
                    if candidate_vm.get_region_stance_to(state, battle.tile).get_stance() != organization.models.relationship.MilitaryStance.AGGRESSIVE:
                        aggressive_to_all_in_other_side = False
                        break
                aggressive_to_own_side = False
                for battle_state in side.battleorganization_set.all():
                    state = battle_state.organization
                    if candidate_vm.get_region_stance_to(state, battle.tile).get_stance() == organization.models.relationship.MilitaryStance.AGGRESSIVE:
                        aggressive_to_own_side = True
                        break
                if aggressive_to_all_in_other_side and not aggressive_to_own_side:
                    battle_org = BattleOrganization.objects.create(
                        side=side,
                        organization=candidate_vm
                    )
                    add_unit_to_battle_in_progress(battle_org, candidate_unit)