예제 #1
0
 def undo_split(self, parent_markerid, child_markerid):
     parent = self.markerid_to_legion.get(parent_markerid)
     if parent is None:
         return
     child = self.markerid_to_legion.get(child_markerid)
     if child is None:
         return
     parent_creature_names = parent.creature_names
     child_creature_names = child.creature_names
     parent.creatures += child.creatures
     child.remove_observer(self)
     del self.markerid_to_legion[child_markerid]
     self.markerids_left.add(child.markerid)
     self.selected_markerid = None
     del child
     # One action for our player with creature names, and a
     # different action for other players without.
     action = Action.UndoSplit(self.game.name, self.name, parent_markerid,
                               child_markerid, parent_creature_names,
                               child_creature_names)
     self.notify(action, names=[self.name])
     action = Action.UndoSplit(self.game.name, self.name, parent_markerid,
                               child_markerid,
                               len(parent_creature_names) * ["Unknown"],
                               len(child_creature_names) * ["Unknown"])
     other_playernames = self.game.playernames
     other_playernames.remove(self.name)
     self.notify(action, names=other_playernames)
예제 #2
0
def test_save():
    game_name = "game"
    playername = "player"
    parent_markerid = "Rd01"
    child_markerid = "Rd02"

    history = History.History()
    assert history.actions == []
    assert history.undone == []
    assert not history.can_undo(playername)
    assert not history.can_redo(playername)

    action1 = Action.MoveLegion(game_name, playername, parent_markerid,
                                1, 1, False, None, 2)
    history.update(None, action1, None)
    assert history.actions == [action1]
    assert history.undone == []
    assert history.can_undo(playername)
    assert not history.can_undo("")
    assert not history.can_redo(playername)

    action2 = Action.MoveLegion(game_name, playername, child_markerid,
                                2, 3, False, None, 3)
    history.update(None, action2, None)
    assert history.actions == [action1, action2]

    global tmp_path
    with tempfile.NamedTemporaryFile(prefix="test_history",
                                     delete=False) as fil:
        tmp_path = fil.name
        history.save(fil)

    with open(tmp_path) as fil:
        lines = fil.readlines()
    assert len(lines) == 2
예제 #3
0
def test_undo_then_do_different():
    game_name = "game"
    playername = "player"
    parent_markerid = "Rd01"
    child_markerid = "Rd02"
    other_markerid = "Rd03"
    parent_creature_names = 4 * [None]
    child_creature_names = 4 * [None]

    history = History.History()
    action = Action.SplitLegion(game_name, playername, parent_markerid,
                                child_markerid, parent_creature_names,
                                child_creature_names)
    history.update(None, action, None)

    undo_action = Action.UndoSplit(game_name, playername, parent_markerid,
                                   child_markerid, parent_creature_names,
                                   child_creature_names)
    history.update(None, undo_action, None)

    action2 = Action.SplitLegion(game_name, playername, parent_markerid,
                                 other_markerid, parent_creature_names,
                                 child_creature_names)
    history.update(None, action2, None)
    assert history.actions == [action2]
    assert history.undone == []
    assert history.can_undo(playername)
    assert not history.can_redo(playername)
예제 #4
0
 def split_legion(self, parent_markerid, child_markerid,
                  parent_creature_names, child_creature_names):
     logging.info("%s %s %s %s", parent_markerid, child_markerid,
                  parent_creature_names, child_creature_names)
     parent = self.markerid_to_legion.get(parent_markerid)
     if parent is None:
         return
     if child_markerid not in self.markerids_left:
         raise AssertionError("illegal marker")
     if (bag(parent.creature_names) != bag(parent_creature_names).union(
             bag(child_creature_names))
             and bag(parent_creature_names).union(bag(child_creature_names))
             != bag({"Unknown": len(parent)})):
         raise AssertionError("wrong creatures", "parent.creature_names",
                              parent.creature_names,
                              "parent_creature_names",
                              parent_creature_names, "child_creature_names",
                              child_creature_names)
     new_legion1 = Legion.Legion(self, parent_markerid,
                                 Creature.n2c(parent_creature_names),
                                 parent.hexlabel)
     new_legion2 = Legion.Legion(self, child_markerid,
                                 Creature.n2c(child_creature_names),
                                 parent.hexlabel)
     if not parent.is_legal_split(new_legion1, new_legion2):
         raise AssertionError("illegal split")
     del new_legion1
     parent.creatures = Creature.n2c(parent_creature_names)
     for creature in parent.creatures:
         creature.legion = parent
     self.take_marker(child_markerid)
     new_legion2.add_observer(self.game)
     self.markerid_to_legion[child_markerid] = new_legion2
     del parent
     # One action for our player with creature names
     action = Action.SplitLegion(self.game.name, self.name, parent_markerid,
                                 child_markerid, parent_creature_names,
                                 child_creature_names)
     logging.info(action)
     self.notify(action, names=[self.name])
     # Another action for everyone (including our player, who will
     # ignore it as a duplicate) without creature names.
     action = Action.SplitLegion(self.game.name, self.name, parent_markerid,
                                 child_markerid,
                                 len(parent_creature_names) * ["Unknown"],
                                 len(child_creature_names) * ["Unknown"])
     logging.info(action)
     self.notify(action)
예제 #5
0
 def fight(self, playername, game_name, attacker_markerid,
           defender_markerid):
     """Fight the current current engagement."""
     logging.info("Server.fight %s %s %s %s", playername, game_name,
                  attacker_markerid, defender_markerid)
     game = self.name_to_game(game_name)
     if game:
         attacker_legion = game.find_legion(attacker_markerid)
         attacker_legion = game.find_legion(attacker_markerid)
         defender_legion = game.find_legion(defender_markerid)
         if (not attacker_legion or not defender_legion
                 or playername not in [
                     attacker_legion.player.name,
                     defender_legion.player.name
                 ]):
             logging.warning("illegal fight call from %s", playername)
             return
         if (defender_legion.can_flee
                 and not game.defender_chose_not_to_flee):
             logging.warning(
                 "Illegal fight call while defender can still flee")
             return
         action = Action.Fight(game.name, attacker_markerid,
                               defender_markerid, attacker_legion.hexlabel)
         logging.info("Server.fight calling game.update")
         game.update(self, action, None)
예제 #6
0
 def remove_observer(self, user):
     Observed.remove_observer(self, user)
     playername = user.name
     if playername in self.playernames:
         self.playernames.remove(playername)
         action = Action.DelUsername(playername)
         self.notify(action)
예제 #7
0
 def add_points(self, points, can_acquire_angels):
     logging.info("Legion.add_points %s %s %s", self, points,
                  can_acquire_angels)
     ARCHANGEL_POINTS = Creature.Creature("Archangel").acquirable_every
     ANGEL_POINTS = Creature.Creature("Angel").acquirable_every
     player = self.player
     score0 = player.score
     score1 = score0 + points
     player.score = score1
     logging.info("%s now has score %s", player, player.score)
     if can_acquire_angels:
         height = len(self)
         archangels = 0
         if (height < 7 and
                 score1 // ARCHANGEL_POINTS > score0 // ARCHANGEL_POINTS):
             archangels += 1
             score1 -= ANGEL_POINTS
         logging.info("archangels %d" % archangels)
         angels = 0
         while (height + archangels + angels < 7
                and score1 // ANGEL_POINTS > score0 // ANGEL_POINTS):
             angels += 1
             score1 -= ANGEL_POINTS
         logging.info("angels %d" % angels)
         self._angels_pending = angels
         self._archangels_pending = archangels
         if angels + archangels > 0:
             action = Action.CanAcquireAngels(self.player.game.name,
                                              self.player.name,
                                              self.markerid, angels,
                                              archangels)
             self.notify(action)
예제 #8
0
 def done_with_counterstrikes(self):
     if self.has_forced_strikes:
         logging.info("Forced strikes remain")
         return
     action = Action.StartReinforceBattlePhase(self.game.name, self.name,
                                               self.game.battle_turn)
     self.notify(action)
예제 #9
0
    def join_game(self, playername, game_name, player_class, player_info):
        """Join an existing game that hasn't started yet.

        Return True on success, False on failure.
        """
        logging.info("%s %s %s %s", playername, game_name, player_class,
                     player_info)
        game = self.name_to_game(game_name)
        if game:
            try:
                game.add_player(playername, player_class, player_info)
            except AssertionError:
                logging.exception("join_game caught an exception")
                return False
            else:
                action = Action.JoinGame(playername, game.name, player_class,
                                         player_info)
                self.notify(action)
            set1 = self.game_to_waiting_ais.get(game_name)
            if set1:
                set1.discard(playername)
                if not set1:
                    game = self.name_to_game(game_name)
                    reactor.callLater(1, game.start, game.owner.name)
            return True
        return False
예제 #10
0
 def flee(self, playername, game_name, markerid):
     """Flee from an engagement."""
     game = self.name_to_game(game_name)
     if game:
         legion = game.find_legion(markerid)
         if not legion:
             logging.warning("flee with no legion %s", markerid)
             return
         hexlabel = legion.hexlabel
         for enemy_legion in game.all_legions(hexlabel):
             if enemy_legion != legion:
                 break
         # Enemy illegally managed to concede before we could flee.
         if enemy_legion == legion:
             logging.warning("illegal concede before flee")
             return
         player = game.get_player_by_name(playername)
         if player == game.active_player:
             logging.warning("attacker tried to flee")
             return
         if legion.player != player:
             logging.warning("wrong player tried to flee")
             return
         if not legion.can_flee:
             logging.warning("illegal flee attempt")
             return
         enemy_markerid = enemy_legion.markerid
         action = Action.Flee(game.name, markerid, enemy_markerid,
                              legion.hexlabel)
         game.update(self, action, None)
예제 #11
0
 def load(self, fil):
     """Load history from a file, which should already be open for read."""
     self.actions = []
     self.undone = []
     for line in fil:
         line = line.strip()
         action = Action.fromstring(line)
         self.actions.append(action)
예제 #12
0
 def do_not_acquire_angels(self):
     """Do not acquire any angels, and notify observers."""
     logging.info("do_not_acquire_angels %s", self)
     if self.angels_pending or self.archangels_pending:
         self.reset_angels_pending()
         action = Action.DoNotAcquireAngels(self.player.game.name,
                                            self.player.name, self.markerid)
         self.notify(action)
예제 #13
0
 def done_with_recruits(self):
     if self.game.active_player != self or self.game.phase != Phase.MUSTER:
         logging.info("illegal call to done_with_recruits")
         return
     (player, turn) = self.game.next_player_and_turn
     if player is not None:
         action = Action.StartSplitPhase(self.game.name, player.name, turn)
         self.notify(action)
예제 #14
0
 def done_with_moves(self):
     logging.debug("")
     if self.can_exit_move_phase:
         self.recombine()
         action = Action.StartFightPhase(self.game.name, self.name)
         self.notify(action)
     else:
         logging.warning("%s cannot exit move phase", self)
예제 #15
0
 def load(self, fil):
     """Load history from a file, which should already be open for read."""
     self.actions = []
     self.undone = []
     for line in fil:
         line = line.strip()
         action = Action.fromstring(line)
         self.actions.append(action)
예제 #16
0
def test_history_2():
    game_name = "game"
    playername = "player"
    parent_markerid = "Rd01"
    child_markerid = "Rd02"

    history = History.History()
    assert history.actions == []
    assert history.undone == []
    assert not history.can_undo(playername)
    assert not history.can_redo(playername)

    action1 = Action.MoveLegion(game_name, playername, parent_markerid,
                                1, 1, False, None, 2)
    history.update(None, action1, None)
    assert history.actions == [action1]
    assert history.undone == []
    assert history.can_undo(playername)
    assert not history.can_undo("")
    assert not history.can_redo(playername)

    action2 = Action.MoveLegion(game_name, playername, child_markerid,
                                2, 3, False, None, 3)
    history.update(None, action2, None)
    assert history.actions == [action1, action2]
    assert history.undone == []
    assert history.can_undo(playername)
    assert not history.can_undo("")
    assert not history.can_redo(playername)

    undo_action2 = Action.UndoMoveLegion(game_name, playername,
                                         child_markerid, 2, 3, False, None, 3)
    history.update(None, undo_action2, None)
    assert history.actions == [action1]
    assert history.undone == [action2]
    assert history.can_undo(playername)
    assert history.can_redo(playername)

    undo_action1 = Action.UndoMoveLegion(game_name, playername,
                                         parent_markerid, 1, 1, False, None, 2)
    history.update(None, undo_action1, None)
    assert history.actions == []
    assert history.undone == [action2, action1]
    assert not history.can_undo(playername)
    assert history.can_redo(playername)
예제 #17
0
 def assign_color(self, color):
     """Set this player's color"""
     self.color = color
     abbrev = self.color_abbrev
     num_markers = len(markerdata.data[color])
     for ii in xrange(num_markers):
         self.markerids_left.add("%s%02d" % (abbrev, ii + 1))
     logging.info(self.markerids_left)
     action = Action.PickedColor(self.game.name, self.name, color)
     self.notify(action)
예제 #18
0
    def send_chat_message(self, source, dest, text):
        """Send a chat message from user source to users in dest.

        source is a playername.  dest is a set of playernames.
        If dest is None, send to all users
        """
        message = "%s: %s" % (source, text)
        if dest is not None:
            dest.add(source)
        action = Action.ChatMessage(source, message)
        self.notify(action, names=dest)
예제 #19
0
 def done_with_strikes(self):
     if self.has_forced_strikes:
         logging.info("Forced strikes remain")
         return
     player = None
     for legion in self.game.battle_legions:
         if legion.player != self:
             player = legion.player
     action = Action.StartCounterstrikeBattlePhase(self.game.name,
                                                   player.name)
     self.notify(action)
예제 #20
0
 def withdraw(self, playername, game_name):
     """Withdraw a player from the game."""
     game = self.name_to_game(game_name)
     if game:
         if game.started:
             game.withdraw(playername)
         else:
             try:
                 game.remove_player(playername)
             except AssertionError:
                 pass
             else:
                 if len(game.players) == 0:
                     if game in self.games:
                         self.games.remove(game)
                     action = Action.RemoveGame(game.name)
                     self.notify(action)
                 else:
                     action = Action.Withdraw(playername, game.name)
                     self.notify(action)
예제 #21
0
def test_eq():
    obj1 = Action.fromstring(
        "MoveLegion {'markerid': 'Rd01', \
'entry_side': 1, 'teleport': False, 'playername': 'player', \
'teleporting_lord': None, 'game_name': 'game', 'hexlabel': 1, \
'previous_hexlabel': 2}"
    )
    obj2 = Action.fromstring(
        "MoveLegion {'markerid': 'Rd01', \
'entry_side': 1, 'teleport': False, 'playername': 'player', \
'teleporting_lord': None, 'game_name': 'game', 'hexlabel': 1, \
'previous_hexlabel': 2}"
    )
    assert obj1 == obj2
    obj3 = Action.fromstring(
        "MoveLegion {'markerid': 'Rd01', \
'entry_side': 1, 'teleport': True, 'playername': 'player', \
'teleporting_lord': None, 'game_name': 'game', 'hexlabel': 1, \
'previous_hexlabel': 2}"
    )
    assert obj1 != obj3
예제 #22
0
 def die(self, scoring_player, check_for_victory):
     """Die and give half points to scoring_player, except for legions
     which are engaged with someone else.
     """
     logging.info("Player.die %s %s %s", self, scoring_player,
                  check_for_victory)
     # First reveal all this player's legions.
     for legion in self.legions:
         if (legion.all_known and legion not in self.game.battle_legions):
             # Only reveal the legion if we're sure about its contents,
             # to avoid spreading disinformation.
             # Do not reveal the legion that's currently in battle, because
             # its contents are in flux.
             action = Action.RevealLegion(self.game.name, legion.markerid,
                                          legion.creature_names)
             self.notify(action)
     if scoring_player is None:
         scoring_player_name = ""
     else:
         scoring_player_name = scoring_player.name
     self.has_titan = False
     action = Action.EliminatePlayer(self.game.name, scoring_player_name,
                                     self.name, check_for_victory)
     reactor.callLater(0.1, self.notify, action)
예제 #23
0
def test_fromstring():
    obj = Action.fromstring(
        "MoveLegion {'markerid': 'Rd01', \
'entry_side': 1, 'teleport': False, 'playername': 'player', \
'teleporting_lord': None, 'game_name': 'game', 'hexlabel': 1, \
'previous_hexlabel': 2}"
    )
    assert isinstance(obj, Action.MoveLegion)
    assert obj.markerid == "Rd01"
    assert obj.entry_side == 1
    assert obj.teleport is False
    assert obj.playername == "player"
    assert obj.teleporting_lord is None
    assert obj.game_name == "game"
    assert obj.hexlabel == 1
    assert obj.previous_hexlabel == 2
예제 #24
0
 def unreinforce(self):
     """Undo reinforcement, and notify observers."""
     # Avoid double undo
     if not self.recruited:
         return
     player = self.player
     creature = self.creatures.pop()
     recruiter_names = self.recruiter_names_list.pop()
     logging.info("%s clearing self.recruited", self)
     self.recruited = False
     caretaker = self.player.game.caretaker
     caretaker.put_one_back(creature.name)
     action = Action.UnReinforce(player.game.name, player.name,
                                 self.markerid, creature.name,
                                 recruiter_names)
     self.notify(action)
예제 #25
0
def test_undo_nothing():
    game_name = "game"
    playername = "player"
    parent_markerid = "Rd01"
    child_markerid = "Rd02"
    parent_creature_names = 4 * [None]
    child_creature_names = 4 * [None]

    history = History.History()
    undo_action = Action.UndoSplit(game_name, playername, parent_markerid,
                                   child_markerid, parent_creature_names,
                                   child_creature_names)
    history.update(None, undo_action, None)
    assert history.actions == []
    assert history.undone == []
    assert not history.can_undo(playername)
    assert not history.can_redo(playername)
예제 #26
0
 def unsummon_angel(self, legion, creature_name):
     donor = self.last_donor
     # Avoid doing it twice.
     if not self.summoned or donor is None or len(donor) >= 7:
         return
     # Can be done during battle, so it matters which of this creature.
     if not legion.creatures or legion.creatures[-1].name != creature_name:
         return
     legion.creatures.pop()
     donor.add_creature_by_name(creature_name)
     creature = donor.creatures[-1]
     creature.legion = donor
     self.summoned = False
     self.last_donor = None
     action = Action.UnsummonAngel(self.game.name, self.name,
                                   legion.markerid, donor.markerid,
                                   creature.name)
     self.notify(action)
예제 #27
0
def test_find_last_split():
    game_name = "game"
    playername = "player"
    parent_markerid = "Rd01"
    child_markerid = "Rd02"
    parent_creature_names = 4 * [None]
    child_creature_names = 4 * [None]

    history = History.History()
    action = Action.SplitLegion(game_name, playername, parent_markerid,
                                child_markerid, parent_creature_names,
                                child_creature_names)
    assert history.find_last_split(playername, parent_markerid,
                                   child_markerid) is None

    history.update(None, action, None)
    assert history.find_last_split(playername, parent_markerid,
                                   child_markerid) == action
    assert history.find_last_split(playername, "Rd03", "Rd04") is None
예제 #28
0
    def form_game(self, playername, game_name, min_players, max_players,
                  ai_time_limit, player_time_limit, player_class, player_info):
        """Form a new game.

        Return None normally, or an error string if there's a problem.
        """
        logging.info("%s %s %s %s %s %s %s %s", playername, game_name,
                     min_players, max_players, ai_time_limit,
                     player_time_limit, player_class, player_info)
        if not game_name:
            st = "Games must be named"
            logging.warning(st)
            return st
        game_info_tuples = self.get_game_info_tuples()
        game_names = set((tup[0] for tup in game_info_tuples))
        if game_name in game_names:
            st = 'The game name "%s" is already in use' % game_name
            logging.warning(st)
            return st
        if min_players > max_players:
            st = "min_players must be <= max_players"
            logging.warning(st)
            return st
        now = time.time()
        GAME_START_DELAY = 5 * 60
        game = Game.Game(game_name,
                         playername,
                         now,
                         now + GAME_START_DELAY,
                         min_players,
                         max_players,
                         master=True,
                         ai_time_limit=ai_time_limit,
                         player_time_limit=player_time_limit,
                         player_class=player_class,
                         player_info=player_info)
        self.games.append(game)
        game.add_observer(self)
        action = Action.FormGame(playername, game.name, game.create_time,
                                 game.start_time, game.min_players,
                                 game.max_players, ai_time_limit,
                                 player_time_limit, player_class, player_info)
        self.notify(action)
예제 #29
0
 def recruit_creature(self, playername, game_name, markerid, creature_name,
                      recruiter_names):
     """Recruit one creature."""
     game = self.name_to_game(game_name)
     if game:
         player = game.get_player_by_name(playername)
         if player:
             legion = player.markerid_to_legion.get(markerid)
             if legion and not legion.recruited:
                 caretaker = game.caretaker
                 hexlabel = legion.hexlabel
                 masterhex = game.board.hexes[hexlabel]
                 mterrain = masterhex.terrain
                 lst = list(recruiter_names[:])
                 lst.insert(0, creature_name)
                 tup = tuple(lst)
                 if tup in legion.available_recruits_and_recruiters(
                         mterrain, caretaker):
                     action = Action.RecruitCreature(
                         game.name, player.name, markerid, creature_name,
                         tuple(recruiter_names))
                     game.update(self, action, None)
예제 #30
0
 def create_starting_legion(self):
     markerid = self.selected_markerid
     if markerid is None:
         raise AssertionError("create_starting_legion without marker")
     if markerid not in self.markerids_left:
         raise AssertionError("create_starting_legion with bad marker")
     if self.markerid_to_legion:
         raise AssertionError("create_starting_legion but have a legion")
     creatures = [
         Creature.Creature(name)
         for name in creaturedata.starting_creature_names
     ]
     legion = Legion.Legion(self, self.take_marker(markerid), creatures,
                            self.starting_tower)
     self.markerid_to_legion[markerid] = legion
     legion.add_observer(self.game)
     action = Action.CreateStartingLegion(self.game.name, self.name,
                                          markerid)
     caretaker = self.game.caretaker
     for creature in creatures:
         caretaker.take_one(creature.name)
     self.created_starting_legion = True
     self.notify(action)
예제 #31
0
 def do_not_flee(self, playername, game_name, markerid):
     """Do not flee from an engagement."""
     game = self.name_to_game(game_name)
     if game:
         legion = game.find_legion(markerid)
         hexlabel = legion.hexlabel
         player = game.get_player_by_name(playername)
         if player == game.active_player:
             logging.warning("attacker tried to not flee")
             return
         legion = player.markerid_to_legion.get(markerid)
         if legion is None:
             logging.warning("no legion")
             return
         if legion.player != player:
             logging.warning("wrong player tried to not flee")
             return
         for enemy_legion in game.all_legions(hexlabel):
             if enemy_legion != legion:
                 break
         enemy_markerid = enemy_legion.markerid
         action = Action.DoNotFlee(game.name, markerid, enemy_markerid,
                                   hexlabel)
         game.update(self, action, None)
예제 #32
0
                                          Legion.find_picname(action.markerid),
                                          ", ".join(action.angel_names))
        elif isinstance(action, Action.GameOver):
            if len(action.winner_names) == 1:
                st = "%s wins!" % action.winner_names[0]
            else:
                st = "%s draw" % " and ".join(action.winner_names)
        if st and st != self.last_st:
            self.last_st = st
            label = gtk.Label(st)
            # left-align the label
            label.set_alignment(0.0, 0.5)
            self.vbox2.pack_start(label, expand=False, fill=False)
            label.show()
            upper = self.vadjustment.get_upper()
            self.vadjustment.set_value(upper)


if __name__ == "__main__":
    import time
    from slugathon.util import guiutils

    parent = gtk.Window()
    event_log = EventLog(None, None)
    event_log.connect("destroy", guiutils.exit)
    parent.add(event_log)
    parent.show_all()
    action = Action.GameOver("a", ["Bob"], time.time())
    reactor.callWhenRunning(event_log.update, None, action, None)
    reactor.run()
예제 #33
0
 def add_observer(self, user):
     playername = user.name
     Observed.add_observer(self, user, playername)
     self.playernames.add(playername)
     action = Action.AddUsername(playername)
     self.notify(action)