예제 #1
0
def unit_movement(battle: Battle):
    # first pass: desire positions / optimistic move
    for battle_unit_in_turn in BattleUnitInTurn.objects.filter(
            battle_turn=battle.get_latest_turn()):
        for battle_contubernium_in_turn in battle_unit_in_turn.battlecontuberniuminturn_set.all(
        ):
            target_distance_function = get_target_distance_function(
                battle_contubernium_in_turn)
            if target_distance_function:
                optimistic_move_desire_formulation(battle_contubernium_in_turn,
                                                   target_distance_function)
    optimistic_move_desire_resolving(battle)

    # second pass: if could not move, do "safe" move
    for battle_unit_in_turn in BattleUnitInTurn.objects.filter(
            battle_turn=battle.get_latest_turn()):
        for battle_contubernium_in_turn in battle_unit_in_turn.battlecontuberniuminturn_set.filter(
                moved_this_turn=False):
            target_distance_function = get_target_distance_function(
                battle_contubernium_in_turn)
            if target_distance_function:
                safe_move(battle_contubernium_in_turn,
                          target_distance_function)

    # finalize
    for battle_unit_in_turn in BattleUnitInTurn.objects.filter(
            battle_turn=battle.get_latest_turn()):
        battle_unit_in_turn.update_pos()
        check_if_order_done(battle_unit_in_turn)
예제 #2
0
def optimistic_move_desire_resolving(battle: Battle):
    while BattleContuberniumInTurn.objects.filter(
            desires_pos=True, battle_turn=battle.get_latest_turn()).exists():
        bcuit = BattleContuberniumInTurn.objects.filter(
            desires_pos=True, battle_turn=battle.get_latest_turn())[0]
        contubernia_desiring_position = battle.get_latest_turn(
        ).get_contubernia_desiring_position(bcuit.desired_coordinates())
        desired_position_occupier = battle.get_latest_turn(
        ).get_contubernium_in_position(bcuit.desired_coordinates())

        if desired_position_occupier:
            # test if mutually desiring positions
            if desired_position_occupier.desires_pos:
                for desirer in contubernia_desiring_position:
                    if desirer.coordinates(
                    ) == desired_position_occupier.desired_coordinates():
                        grant_position_swap(desirer, desired_position_occupier)
                        continue
                # TODO: try to move blocking contubernium before giving up
                contubernia_desiring_position.update(desires_pos=False)
            else:
                contubernia_desiring_position.update(desires_pos=False)

        else:
            desire_getter = get_highest_priority_desire(
                contubernia_desiring_position)
            grant_position_desire(desire_getter)
            contubernia_desiring_position.update(desires_pos=False)
def unit_attack(battle: Battle):
    contubernia = list(
        BattleContuberniumInTurn.objects.filter(
            battle_turn=battle.get_latest_turn()))
    random.shuffle(contubernia)
    for contubernium in contubernia:
        world_unit = contubernium.battle_unit_in_turn.battle_unit.world_unit
        enemy_contubernia = BattleContuberniumInTurn.objects.filter(
            battle_turn=contubernium.battle_turn).exclude(
                battle_contubernium__battle_unit__battle_side=contubernium.
                battle_contubernium.battle_unit.battle_side)
        target_contubernium, distance = \
            closest_in_set(contubernium.coordinates(), enemy_contubernia)

        if target_contubernium is None:
            continue

        if distance < 2:
            unit_attack_melee(contubernium, target_contubernium)
            contubernium.attack_type_this_turn = \
                BattleContuberniumInTurn.MELEE_ATTACK
            contubernium.contubernium_attacked_this_turn = \
                target_contubernium
            contubernium.save()
        elif (world_unit.is_ranged() and distance <= world_unit.shot_range()
              and contubernium.ammo_remaining > 0
              and not contubernium.moved_this_turn):
            unit_attack_ranged(contubernium, target_contubernium)
            contubernium.attack_type_this_turn = \
                BattleContuberniumInTurn.RANGED_ATTACK
            contubernium.contubernium_attacked_this_turn = \
                target_contubernium
            contubernium.save()
def battle_tick(battle: Battle):
    with perf_timer("Tick {} for {}".format(battle.get_latest_turn().num,
                                            battle)):
        create_next_turn(battle)
        unit_movement(battle)
        unit_attack(battle)
        if check_end(battle):
            battle.current = False
            battle.save()
예제 #5
0
def check_end(battle: Battle):
    for side in battle.battleside_set.all():
        if not BattleSoldierInTurn.objects.filter(
                battle_turn=battle.get_latest_turn(),
                battle_contubernium_in_turn__battle_contubernium__battle_unit__battle_side
                =side,
                wound_status__lt=BattleSoldierInTurn.DEAD).exists():
            return True
    side_0_contubs = BattleContuberniumInTurn.objects.filter(
        battle_turn=battle.get_latest_turn(),
        battle_contubernium__battle_unit__battle_side__z=False)
    side_1_contubs = BattleContuberniumInTurn.objects.filter(
        battle_turn=battle.get_latest_turn(),
        battle_contubernium__battle_unit__battle_side__z=False)
    for contub in side_0_contubs:
        closest, distance = closest_in_set(contub.coordinates(),
                                           side_1_contubs)
        if distance is not None and distance < 40:
            return False
    return True
예제 #6
0
def unit_attack(battle: Battle):
    contubernia = list(
        BattleContuberniumInTurn.objects.filter(
            battle_turn=battle.get_latest_turn()))
    random.shuffle(contubernia)
    for contubernium in contubernia:
        enemy_contubernia = BattleContuberniumInTurn.objects.filter(
            battle_turn=contubernium.battle_turn).exclude(
                battle_contubernium__battle_unit__battle_side=contubernium.
                battle_contubernium.battle_unit.battle_side)
        target_contubernium, distance = \
            closest_in_set(contubernium.coordinates(), enemy_contubernia)
        if target_contubernium is not None and distance < 2:
            for soldier in contubernium.battlesoldierinturn_set.all():
                target_soldier = random.choice(
                    target_contubernium.battlesoldierinturn_set.all()[:])
                while (random.random() <
                       0.5 * soldier.attack_chance_multiplier()):
                    if target_soldier.wound_status < BattleSoldierInTurn.DEAD:
                        target_soldier.take_hit()
                target_soldier.save()
예제 #7
0
def create_next_turn(battle: Battle):
    new_turn = battle.get_latest_turn()
    new_turn.id = None
    new_turn.num += 1
    new_turn.save()
    prev_turn = battle.battleturn_set.get(num=new_turn.num - 1)

    for side in battle.battleside_set.all():
        for organization in side.battleorganization_set.all():
            for character in organization.battlecharacter_set.all():
                bcit = BattleCharacterInTurn.objects.get(
                    battle_character=character, battle_turn=prev_turn)
                bcit.id = None
                bcit.battle_turn = new_turn
                bcit.save()

            for unit in organization.battleunit_set.all():
                try:
                    buit = BattleUnitInTurn.objects.get(battle_unit=unit,
                                                        battle_turn=prev_turn)
                    if not buit.battlecontuberniuminturn_set.filter(
                            x_pos__gte=-50,
                            x_pos__lte=50,
                            z_pos__gte=-50,
                            z_pos__lte=50,
                    ).exists():
                        buit.battle_unit.in_battle = False
                        buit.battle_unit.save()
                        buit.battle_unit.world_unit.status = \
                            WorldUnit.REGROUPING
                        buit.battle_unit.world_unit.save()
                        continue
                    if not BattleSoldierInTurn.objects.filter(
                            battle_contubernium_in_turn__battle_unit_in_turn=
                            buit,
                            wound_status__lt=BattleSoldierInTurn.DEAD).exists(
                            ):
                        buit.battle_unit.in_battle = False
                        buit.battle_unit.save()
                        buit.battle_unit.world_unit.status = \
                            WorldUnit.REGROUPING
                        buit.battle_unit.world_unit.save()
                        continue
                    buit.id = None
                    buit.battle_turn = new_turn
                    buit.battle_character_in_turn = BattleCharacterInTurn.objects.get(
                        battle_turn=new_turn,
                        battle_character=buit.battle_character_in_turn.
                        battle_character
                    ) if buit.battle_character_in_turn is not None else None
                    buit.order = buit.battle_unit.get_order()
                    buit.save()
                except BattleUnitInTurn.DoesNotExist:
                    continue

                for contubernium in unit.battlecontubernium_set.all():

                    try:
                        bcontubit = BattleContuberniumInTurn.objects.get(
                            battle_contubernium=contubernium,
                            battle_turn=prev_turn)
                        if not bcontubit.battlesoldierinturn_set.filter(
                                wound_status__lt=BattleSoldierInTurn.DEAD
                        ).exists():
                            continue
                        if (not -50 <= bcontubit.x_pos <= 50
                                or not -50 <= bcontubit.z_pos <= 50):
                            continue
                        bcontubit.id = None
                        bcontubit.moved_this_turn = False
                        bcontubit.desires_pos = False
                        bcontubit.battle_turn = new_turn
                        bcontubit.battle_unit_in_turn = buit
                        bcontubit.save()
                    except BattleContuberniumInTurn.DoesNotExist:
                        pass

                    for soldier in contubernium.battlesoldier_set.all():
                        try:
                            bsit = BattleSoldierInTurn.objects.get(
                                battle_turn=prev_turn, battle_soldier=soldier)
                            if bsit.wound_status == BattleSoldierInTurn.DEAD:
                                continue
                            bsit.id = None
                            bsit.battle_turn = new_turn
                            bsit.battle_contubernium_in_turn = bcontubit
                            bsit.save()
                        except BattleSoldierInTurn.DoesNotExist:
                            pass