def new_session(mapgen=create_map, rng_seed=RANDOM_SEED, human_player=True, ai_players=0): """ Create a new session with a map, add one human player and a trader (it will crash otherwise). It returns both session and player to avoid making the function-based tests too verbose. """ session = SPTestSession(rng_seed=rng_seed) human_difficulty = DifficultySettings.DEFAULT_LEVEL ai_difficulty = DifficultySettings.EASY_LEVEL players = [] if human_player: players.append({ 'id': 1, 'name': 'foobar', 'color': Color.get(1), 'local': True, 'ai': False, 'difficulty': human_difficulty, }) for i in range(ai_players): id = i + human_player + 1 players.append({ 'id': id, 'name': ('AI' + str(i)), 'color': Color.get(id), 'local': (id == 1), 'ai': True, 'difficulty': ai_difficulty, }) session.load(mapgen(), players, ai_players > 0, True) return session, session.world.player
def _get_player_list(self): if self._player_list is not None: return self._player_list # for now just make it a bit easier for the AI difficulty_level = { False: DifficultySettings.DEFAULT_LEVEL, True: DifficultySettings.EASY_LEVEL } players = [] players.append({ 'id': 1, 'name': self.player_name, 'color': Color.get(1) if self.player_color is None else self.player_color, 'local': True, 'ai': self.human_ai, 'difficulty': difficulty_level[bool(self.human_ai)], }) cur_locale = horizons.globals.fife.get_locale() # add AI players with a distinct color; if none can be found then use black for num in range(self.ai_players): color = Color.get( COLORS.BLACK) # if none can be found then be black for possible_color in Color.get_defaults(): if possible_color == Color.get(COLORS.BLACK): continue # black is used by the trader and the pirate used = any(possible_color == player['color'] for player in players) if not used: color = possible_color break name = horizons.globals.db.get_random_ai_name( cur_locale, [p['name'] for p in players]) # out of pre-defined names? if name is None: name = 'AI' + str(num + 1) players.append({ 'id': num + 2, 'name': name, 'color': color, 'local': False, 'ai': True, 'difficulty': difficulty_level[True], }) return players
def set_color(self, color_id): """Updates the background color of large label where players see their currently chosen color. @param color_id: int. Gets converted to util.Color object. """ try: self.selected_color = Color.get(color_id) except KeyError: # For some reason, color_id can be 0 apparently: # http://forum.unknown-horizons.org/viewtopic.php?t=6927 # Reset that setting to 1 if the problem occurs. self.selected_color = Color.get(1) self.gui.findChild(name='selectedcolor').background_color = self.selected_color
def setup_combat(s, ship): worldid = 10000000 p0 = Player(s, worldid, "p1", Color.get(1)) p1 = Player(s, worldid+1, "p2", Color.get(2)) for p in (p0, p1): p.initialize(None) s.world.players.append(p) s0 = CreateUnit(p0.worldid, ship, 0, 0)(issuer=p0) s1 = CreateUnit(p1.worldid, ship, 3, 3)(issuer=p1) return ((p0, s0), (p1, s1))
def setup_combat(s, ship): worldid = 10000000 p0 = Player(s, worldid, "p1", Color.get(1)) p1 = Player(s, worldid + 1, "p2", Color.get(2)) for p in (p0, p1): p.initialize(None) s.world.players.append(p) s0 = CreateUnit(p0.worldid, ship, 0, 0)(issuer=p0) s1 = CreateUnit(p1.worldid, ship, 3, 3)(issuer=p1) return ((p0, s0), (p1, s1))
def set_color(self, color_id): """Updates the background color of large label where players see their currently chosen color. @param color_id: int. Gets converted to util.Color object. """ try: self.selected_color = Color.get(color_id) except KeyError: # For some reason, color_id can be 0 apparently: # http://forum.unknown-horizons.org/viewtopic.php?t=6927 # Reset that setting to 1 if the problem occurs. self.selected_color = Color.get(1) self.gui.findChild( name='selectedcolor').background_color = self.selected_color
def _get_player_list(self): if self._player_list is not None: return self._player_list # for now just make it a bit easier for the AI difficulty_level = {False: DifficultySettings.DEFAULT_LEVEL, True: DifficultySettings.EASY_LEVEL} players = [] players.append( { "id": 1, "name": self.player_name, "color": Color.get(1) if self.player_color is None else self.player_color, "local": True, "ai": self.human_ai, "difficulty": difficulty_level[bool(self.human_ai)], } ) cur_locale = horizons.globals.fife.get_locale() # add AI players with a distinct color; if none can be found then use black for num in xrange(self.ai_players): color = Color.get(COLORS.BLACK) # if none can be found then be black for possible_color in Color.get_defaults(): if possible_color == Color.get(COLORS.BLACK): continue # black is used by the trader and the pirate used = any(possible_color == player["color"] for player in players) if not used: color = possible_color break name = horizons.globals.db.get_random_ai_name(cur_locale, [p["name"] for p in players]) # out of pre-defined names? if name is None: name = "AI" + str(num + 1) players.append( { "id": num + 2, "name": name, "color": color, "local": False, "ai": True, "difficulty": difficulty_level[True], } ) return players
def get_player_list(self): ret_players = [] for index, player in enumerate(self.players, start=1): # TODO: add support for selecting difficulty levels to the GUI status = T('Ready') if player.ready else T('Not Ready') ret_players.append({ 'id': index, 'sid': player.sid, 'name': player.name, 'color': Color.get(player.color), 'clientid': player.clientid, 'local': self.netif.get_client_name() == player.name, 'ai': False, 'difficulty': DifficultySettings.DEFAULT_LEVEL, 'status': status }) return ret_players
def _show_change_player_details_popup(self, game): """Shows a dialog where the player can change its name and/or color""" assigned = [p["color"] for p in NetworkInterface().get_game().get_player_list() if p["name"] != NetworkInterface().get_client_name()] unused_colors = set(Color.get_defaults()) - set(assigned) playerdata = PlayerDataSelection(color_palette=unused_colors) playerdata.set_player_name(NetworkInterface().get_client_name()) playerdata.set_color(NetworkInterface().get_client_color()) dialog = load_uh_widget('set_player_details.xml') dialog.findChild(name="playerdataselectioncontainer").addChild(playerdata.get_widget()) def _change_playerdata(): NetworkInterface().change_name(playerdata.get_player_name()) NetworkInterface().change_color(playerdata.get_player_color().id) dialog.hide() self._update_game_details() def _cancel(): dialog.hide() dialog.mapEvents({ OkButton.DEFAULT_NAME: _change_playerdata, CancelButton.DEFAULT_NAME: _cancel }) dialog.show()
def _show_change_player_details_popup(self, game): """Shows a dialog where the player can change its name and/or color""" assigned = [ p["color"] for p in NetworkInterface().get_game().get_player_list() if p["name"] != NetworkInterface().get_client_name() ] unused_colors = set(Color.get_defaults()) - set(assigned) playerdata = PlayerDataSelection(color_palette=unused_colors) playerdata.set_player_name(NetworkInterface().get_client_name()) playerdata.set_color(NetworkInterface().get_client_color()) dialog = load_uh_widget('set_player_details.xml') dialog.findChild(name="playerdataselectioncontainer").addChild( playerdata.get_widget()) def _change_playerdata(): NetworkInterface().change_name(playerdata.get_player_name()) NetworkInterface().change_color(playerdata.get_player_color().id) dialog.hide() self._update_game_details() def _cancel(): dialog.hide() dialog.mapEvents({ OkButton.DEFAULT_NAME: _change_playerdata, CancelButton.DEFAULT_NAME: _cancel }) dialog.show()
def _load(self, db, worldid): """This function makes it possible to load playerdata into an already allocated Player instance, which is used e.g. in Trader.load""" super(Player, self).load(db, worldid) color, name, client_id, settlerlevel, difficulty_level, max_tier_notification = db( "SELECT color, name, client_id, settler_level, difficulty_level, max_tier_notification" " FROM player WHERE rowid = ?", worldid)[0] self.__init(name, Color.get(color), client_id, difficulty_level, max_tier_notification, settlerlevel = settlerlevel)
def new_session(mapgen=create_map, rng_seed=RANDOM_SEED, human_player=True, ai_players=0): """ Create a new session with a map, add one human player and a trader (it will crash otherwise). It returns both session and player to avoid making the function-based tests too verbose. """ session = SPTestSession(rng_seed=rng_seed) human_difficulty = DifficultySettings.DEFAULT_LEVEL ai_difficulty = DifficultySettings.EASY_LEVEL players = [] if human_player: players.append({ 'id': 1, 'name': 'foobar', 'color': Color.get(1), 'local': True, 'ai': False, 'difficulty': human_difficulty, }) for i in xrange(ai_players): id = i + human_player + 1 players.append({ 'id': id, 'name': ('AI' + str(i)), 'color': Color.get(id), 'local': (id == 1), 'ai': True, 'difficulty': ai_difficulty, }) session.load(mapgen(), players, ai_players > 0, True) return session, session.world.player
def change_color(self, new_color, save=True): new_color %= len(set(Color.get_defaults())) if save: horizons.globals.fife.set_uh_setting("ColorID", new_color) horizons.globals.fife.save_settings() try: if self._client_data.color == new_color: return self.log.debug("[CHANGECOLOR] %s", new_color) if self._mode is None or self._game is None: self._client_data.color = new_color return self.send_packet(packets.client.cmd_changecolor(new_color)) except NetworkException as e: self._handle_exception(e)
def change_color(self, new_color, save=True): new_color %= len(set(Color.get_defaults())) if save: horizons.globals.fife.set_uh_setting("ColorID", new_color) horizons.globals.fife.save_settings() try: if self._client_data.color == new_color: return self.log.debug("[CHANGECOLOR] %s" % (new_color)) if self._mode is None or self._game is None: self._client_data.color = new_color return self.send_packet(packets.client.cmd_changecolor(new_color)) except NetworkException as e: self._handle_exception(e)
def __init__(self, color_palette=None): """ @param widgets: WidgetsDict """ self.gui = load_uh_widget('playerdataselection.xml') self.colors = self.gui.findChild(name='playercolor') colorlabels = [] events = {} # need the id to save it as int in settings file. for color in (Color.get_defaults() if color_palette is None else color_palette): label = Label(name='{color}'.format(color=color.name), text=" ", max_size=(20, 20), min_size=(20, 20), background_color=color) events['{label}/mouseClicked'.format(label=color.name)] = \ Callback(self.set_color, color.id) colorlabels.append(label) # split into three rows with at max 5 entries in each row # right now there are 14 different colors to choose from. for i in range(0, len(colorlabels), 5): hbox = HBox(name='line_{index}'.format(index=i)) hbox.addChildren(colorlabels[i:i + 5]) self.colors.addChild(hbox) playertextfield = self.gui.findChild(name='playername') def playertextfield_clicked(): if playertextfield.text == 'Unnamed Traveler': playertextfield.text = "" playertextfield.capture(playertextfield_clicked, event_name='mouseClicked') self.gui.mapEvents(events) self.update_data()
def __init__(self, color_palette=None): """ @param widgets: WidgetsDict """ self.gui = load_uh_widget('playerdataselection.xml') self.colors = self.gui.findChild(name='playercolor') colorlabels = [] events = {} # need the id to save it as int in settings file. for color in (Color.get_defaults() if color_palette is None else color_palette): label = Label(name = u'{color}'.format(color=color.name), text = u" ", max_size = (20, 20), min_size = (20, 20), background_color = color) events['{label}/mouseClicked'.format(label=color.name)] = \ Callback(self.set_color, color.id) colorlabels.append(label) # split into three rows with at max 5 entries in each row # right now there are 14 different colors to choose from. for i in xrange(0, len(colorlabels), 5): hbox = HBox(name='line_{index}'.format(index=i)) hbox.addChildren(colorlabels[i:i+5]) self.colors.addChild(hbox) playertextfield = self.gui.findChild(name='playername') def playertextfield_clicked(): if playertextfield.text == 'Unnamed Traveler': playertextfield.text = "" playertextfield.capture(playertextfield_clicked, event_name='mouseClicked') self.gui.mapEvents(events) self.update_data()
def test_default_color(self): self.assertTrue(Color(0, 0, 0, 255).is_default_color) self.assertFalse(Color(1, 2, 3, 255).is_default_color)
def test_indexing(): assert Color.get(1) == Color(0, 0, 0, 255) assert Color.get('black') == Color(0, 0, 0, 255)
def init_new_world(self): """This should be called if a new map is loaded (not a savegame, a fresh map). In other words when it is loaded for the first time. NOTE: commands for creating the world objects are executed directly, bypassing the manager this is necessary, because else the commands would be transmitted over the wire in network games. @return: Returs the coordinates of the players first ship """ # workaround: the creation of all the objects causes a lot of logging output, we don't need # therefore, reset the levels for now loggers_to_silence = {'world.production': None} for logger_name in loggers_to_silence: logger = logging.getLogger(logger_name) loggers_to_silence[logger_name] = logger.getEffectiveLevel() logger.setLevel(logging.WARN) from horizons.command.building import Build from horizons.command.unit import CreateUnit # add a random number of environmental objects to the gameworld if int(self.properties.get('RandomTrees', 1)) == 1: Tree = Entities.buildings[BUILDINGS.TREE_CLASS] Clay = Entities.buildings[BUILDINGS.CLAY_DEPOSIT_CLASS] Fish = Entities.buildings[BUILDINGS.FISH_DEPOSIT_CLASS] Mountain = Entities.buildings[BUILDINGS.MOUNTAIN_CLASS] for island in self.islands: max_clay_deposits = self.session.random.randint(2, 3) max_mountains = self.session.random.randint(1, 3) num_clay_deposits = 0 num_mountains = 0 # TODO: fix this sorted()-call. its slow but orderness of dict-loop isn't guaranteed for coords, tile in sorted(island.ground_map.iteritems()): # add tree to every nth tile if self.session.random.randint(0, 2) == 0 and Tree.check_build(self.session, tile, \ check_settlement=False): building = Build(Tree, coords[0], coords[1], ownerless=True, island=island)(issuer=None) building.finish_production_now( ) # make trees big and fill their inventory if self.session.random.randint( 0, 40) == 0: # add animal to every nth tree CreateUnit(island.worldid, UNITS.WILD_ANIMAL_CLASS, *coords)(issuer=None) elif num_clay_deposits < max_clay_deposits and \ self.session.random.randint(0, 40) == 0 and \ Clay.check_build(self.session, tile, check_settlement=False): num_clay_deposits += 1 Build(Clay, coords[0], coords[1], ownerless=True, island=island)(issuer=None) elif num_mountains < max_mountains and \ self.session.random.randint(0, 40) == 0 and \ Mountain.check_build(self.session, tile, check_settlement=False): num_mountains += 1 Build(Mountain, coords[0], coords[1], ownerless=True, island=island)(issuer=None) if 'coastline' in tile.classes and self.session.random.randint( 0, 4) == 0: # try to place fish # from the current position, go to random directions 2 times directions = [(i, j) for i in xrange(-1, 2) for j in xrange(-1, 2)] for (x_dir, y_dir) in self.session.random.sample( directions, 2): # move a random amount in both directions coord_to_check = ( coords[0] + x_dir * self.session.random.randint(3, 9), coords[1] + y_dir * self.session.random.randint(3, 9), ) # now we have the location, check if we can build here if coord_to_check in self.ground_map: Build(Fish, coord_to_check[0], coord_to_check[1], ownerless=True, \ island=self)(issuer=None) # reset loggers, see above for logger_name, level in loggers_to_silence.iteritems(): logging.getLogger(logger_name).setLevel(level) # add free trader self.trader = Trader(self.session, 99999, u"Free Trader", Color()) ret_coords = None for player in self.players: # Adding ships for the players point = self.get_random_possible_ship_position() # Execute command directly, not via manager, because else it would be transmitted over the # network to other players. Those however will do the same thing anyways. ship = CreateUnit(player.worldid, UNITS.PLAYER_SHIP_CLASS, point.x, point.y)(issuer=self.session.world.player) # give ship basic resources for res, amount in self.session.db( "SELECT resource, amount FROM start_resources"): ship.inventory.alter(res, amount) if player is self.player: ret_coords = (point.x, point.y) # add a pirate ship # TODO: enable pirate as soon as save/load for it is fixed # currently, it breaks human player selection on load #self.pirate = Pirate(self.session, 99998, "Captain Blackbeard", Color()) # Fire a message for new world creation self.session.ingame_gui.message_widget.add(self.max_x / 2, self.max_y / 2, 'NEW_WORLD') assert ret_coords is not None, "Return coords are none. No players loaded?" return ret_coords
def test_iter(): colors = list(Color.get_defaults()) assert len(colors) == 2 assert all(c.is_default_color for c in colors) assert colors[0] == Color(0, 0, 0, 255) assert colors[1] == Color(255, 0, 0, 255)
def test_default_color(): assert Color(0, 0, 0, 255).is_default_color assert not Color(1, 2, 3, 255).is_default_color
def test_comparison(): assert Color(0, 0, 0, 255) == Color(0, 0, 0, 255) assert Color(0, 0, 0, 255) != Color(1, 2, 3, 255)
def test_indexing(self): self.assertEqual(Color.get(1), Color(0, 0, 0, 255)) self.assertEqual(Color.get('black'), Color(0, 0, 0, 255))
def test_iter(self): colors = list(Color) self.assertEqual(len(colors), 2) self.assertTrue(all(c.is_default_color for c in colors)) self.assertEqual(colors[0], Color(0, 0, 0, 255)) self.assertEqual(colors[1], Color(255, 0, 0, 255))
def test_comparison(self): self.assertEqual(Color(0, 0, 0, 255), Color(0, 0, 0, 255)) self.assertNotEqual(Color(0, 0, 0, 255), Color(1, 2, 3, 255))
def init_new_world(self, trader_enabled, pirate_enabled, natural_resource_multiplier): """ This should be called if a new map is loaded (not a savegame, a fresh map). In other words, when it is loaded for the first time. NOTE: commands for creating the world objects are executed directly, bypassing the manager. This is necessary because else the commands would be transmitted over the wire in network games. @return: the coordinates of the players first ship """ # workaround: the creation of all the objects causes a lot of logging output we don't need. # therefore, reset the levels for now loggers_to_silence = {'world.production': None} for logger_name in loggers_to_silence: logger = logging.getLogger(logger_name) loggers_to_silence[logger_name] = logger.getEffectiveLevel() logger.setLevel(logging.WARN) # add a random number of environmental objects if natural_resource_multiplier != 0: self._add_nature_objects(natural_resource_multiplier) # reset loggers, see above for logger_name, level in loggers_to_silence.items(): logging.getLogger(logger_name).setLevel(level) # add free trader if trader_enabled: self.trader = Trader(self.session, 99999, "Free Trader", Color()) ret_coords = None for player in self.players: # Adding ships for the players # hack to place the ship on the development map point = self.get_random_possible_ship_position() # Execute command directly, not via manager, because else it would be transmitted over the # network to other players. Those however will do the same thing anyways. ship = CreateUnit(player.worldid, UNITS.PLAYER_SHIP, point.x, point.y)(issuer=self.session.world.player) # give ship basic resources for res, amount in self.session.db( "SELECT resource, amount FROM start_resources"): ship.get_component(StorageComponent).inventory.alter( res, amount) if player is self.player: ret_coords = point.to_tuple() # HACK: Store starting ship as first unit group, and select it def _preselect_player_ship(player_ship): sel_comp = player_ship.get_component(SelectableComponent) sel_comp.select(reset_cam=True) self.session.selected_instances = {player_ship} self.session.ingame_gui.handle_selection_group(1, True) sel_comp.show_menu() select_ship = partial(_preselect_player_ship, ship) Scheduler().add_new_object(select_ship, ship, run_in=0) # load the AI stuff only when we have AI players if any(isinstance(player, AIPlayer) for player in self.players): AIPlayer.load_abstract_buildings( self.session.db) # TODO: find a better place for this # add a pirate ship if pirate_enabled: self.pirate = Pirate(self.session, 99998, "Captain Blackbeard", Color()) assert ret_coords is not None, "Return coords are None. No players loaded?" return ret_coords
def test_indexing(self): self.assertEqual(Color[1], Color(0, 0, 0, 255)) self.assertEqual(Color['black'], Color(0, 0, 0, 255))