def refresh(self): super(PlayersShips, self).refresh() player = self.session.world.player self._clear_entries() #xgettext:python-format self._gui.findChild(name='headline').text = _("Ships of {player}").format(player=self.session.world.player.name) sequence_number = 0 events = {} for ship in sorted(self.session.world.ships, key = lambda ship: (ship.get_component(NamedComponent).name, ship.worldid)): if ship.owner is player and ship.has_component(SelectableComponent): sequence_number += 1 name_label, rename_icon, status_label, status_position = \ self._add_line_to_gui(ship, sequence_number) events['%s/mouseClicked' % name_label.name] = Callback(self._go_to_ship, ship) cb = Callback(self.session.ingame_gui.show_change_name_dialog, ship) events['%s/mouseClicked' % rename_icon.name] = cb events['%s/mouseClicked' % status_label.name] = Callback(self._go_to_point, status_position) self._gui.mapEvents(events) self._content_vbox.adaptLayout()
def _setup_state_callbacks(self): self.combatIntermissions = { self.missionStates.sailing_to_target: (self.sail_to_target, self.flee_home), self.missionStates.chasing_ship: (self.chase_ship, self.flee_home), self.missionStates.going_home: (self.go_home, self.flee_home), self.missionStates.fleeing_home: (self.flee_home, self.flee_home), } self._state_fleet_callbacks = { self.missionStates.sailing_to_target: Callback(self.go_home), self.missionStates.chasing_ship: Callback(self.chase_ship), self.missionStates.going_home: Callback(self.report_success, "Pirate routine ended successfully"), self.missionStates.fleeing_home: Callback(self.report_failure, "Mission was a failure, ships fled home successfully"), }
def _build_interface(self): button_container = self.widget.findChild(name='button_container') sec_button_container = self.widget.findChild( name='sec_button_container') for i, action in enumerate(self.actions): button = self._create_button(action, i) sec_button = self._create_button(action, i) button.mapEvents({ button.name + '/mouseClicked': Callback(self._detect_click_on_button, button, 1) }) sec_button.mapEvents({ button.name + '/mouseClicked': Callback(self._detect_click_on_button, sec_button, 2) }) button_container.addChild(button) sec_button_container.addChild(sec_button) self.buttons.append(button) self.secondary_buttons.append(sec_button) self.update_buttons_text()
def __init__(self, windows, settlement): StatsWidget.__init__(self, settlement.session, center_widget=True) Window.__init__(self, windows) self.current_page = 0 self.settlement = settlement self.db = self.settlement.session.db Scheduler().add_new_object(Callback(self._refresh_tick), self, run_in=GAME_SPEED.TICKS_PER_SECOND, loops=-1)
def build_groundunit_info(self, index, groundunit, prodline): size = (260, 90) widget = Container(name='showcase_%s' % index, position=(0, 20 + index * 90), min_size=size, max_size=size, size=size) bg_icon = Icon(image='content/gui/images/background/square_80.png', name='bg_%s' % index) widget.addChild(bg_icon) image = 'content/gui/images/objects/groundunit/76/{unit_id}.png'.format( unit_id=groundunit) helptext = self.instance.session.db.get_unit_tooltip(groundunit) unit_icon = Icon(image=image, name='icon_%s' % index, position=(2, 2), helptext=helptext) widget.addChild(unit_icon) # if not buildable, this returns string with reason why to be displayed as helptext #groundunit_unbuildable = self.is_groundunit_unbuildable(groundunit) groundunit_unbuildable = False if not groundunit_unbuildable: button = OkButton(position=(60, 50), name='ok_%s' % index, helptext=T('Build this groundunit!')) button.capture(Callback(self.start_production, prodline)) else: button = CancelButton(position=(60, 50), name='ok_%s' % index, helptext=groundunit_unbuildable) widget.addChild(button) # Get production line info production = self.producer.create_production_line(prodline) # consumed == negative, reverse to sort in *ascending* order: costs = sorted(production.consumed_res.iteritems(), key=itemgetter(1)) for i, (res, amount) in enumerate(costs): xoffset = 103 + (i % 2) * 55 yoffset = 20 + (i // 2) * 20 icon = create_resource_icon(res, self.instance.session.db) icon.max_size = icon.min_size = icon.size = (16, 16) icon.position = (xoffset, yoffset) label = Label(name='cost_%s_%s' % (index, i)) if res == RES.GOLD: label.text = unicode(-amount) else: label.text = u'{amount:02}t'.format(amount=-amount) label.position = (22 + xoffset, yoffset) widget.addChild(icon) widget.addChild(label) return widget
def load_ship_states(self, db): # load ships one by one from db (ship instances themselves are loaded already, but # we have to use them here) for ship_id, state_id, remaining_ticks, targeted_warehouse in \ db("SELECT rowid, state, remaining_ticks, targeted_warehouse FROM trader_ships"): state = self.shipStates[state_id] ship = WorldObject.get_object_by_id(ship_id) self.ships[ship] = state if state == self.shipStates.moving_random: ship.add_move_callback(Callback(self.ship_idle, ship)) elif state == self.shipStates.moving_to_warehouse: ship.add_move_callback(Callback(self.reached_warehouse, ship)) assert targeted_warehouse is not None self.office[ship.worldid] = WorldObject.get_object_by_id(targeted_warehouse) elif state == self.shipStates.reached_warehouse: assert remaining_ticks is not None Scheduler().add_new_object( Callback(self.ship_idle, ship), self, remaining_ticks)
def refresh(self): events = { # show rename when you click on name 'name': Callback(self.instance.session.ingame_gui.show_change_name_dialog, self.instance), 'configure_route/mouseClicked': Callback(self._configure_route), 'discard_res/mouseClicked': Callback(self._discard_resources) } self._refresh_found_settlement_button(events) self._refresh_trade_button(events) self.widget.mapEvents(events) self.widget.child_finder('inventory').update() self._refresh_combat() self._refresh_discard_resources() super(ShipOverviewTab, self).refresh()
def __init(self, ships, destroy_callback=None): self.owner = ships[0].owner # dictionary of ship => state self._ships = WeakKeyDictionary() for ship in ships: self._ships[ship] = self.shipStates.idle #TODO: @below, this caused errors on one occasion but I was not able to reproduce it. ship.add_remove_listener(Callback(self._lost_ship, ship)) self.state = self.fleetStates.idle self.destroy_callback = destroy_callback
def ship_idle(self, ship): """Called if a ship is idle. Sends ship to either a random place or warehouse. Probability for 'random warehouse' in percent: TRADER.BUSINESS_SENSE. @param ship: ship instance""" if self.session.random.randint(0, 100) < TRADER.BUSINESS_SENSE: # delay one tick, to allow old movement calls to completely finish self.log.debug( "Trader %s ship %s: idle, moving to random warehouse", self.worldid, ship.worldid) Scheduler().add_new_object(Callback( self.send_ship_random_warehouse, ship), self, run_in=0) else: self.log.debug( "Trader %s ship %s: idle, moving to random location", self.worldid, ship.worldid) Scheduler().add_new_object(Callback(self.send_ship_random, ship), self, run_in=0)
def __init(self, target_ship): self.target_ship = target_ship self.combatIntermissions = { self.missionStates.sailing_to_target: (self.sail_to_target, self.flee_home), self.missionStates.in_combat: (self.check_ship_alive, self.flee_home), self.missionStates.fleeing_home: (self.flee_home, self.flee_home), } self._state_fleet_callbacks = { self.missionStates.sailing_to_target: Callback(self.was_reached), self.missionStates.fleeing_home: Callback(self.report_failure, "Combat was lost, ships fled home successfully"), } ShipDestroyed.subscribe(self._on_ship_destroyed)
def _schedule_refresh(self): """Schedule a refresh soon, dropping all other refresh request, that appear until then. This saves a lot of CPU time, if you have a huge island, or play on high speed.""" if not self._refresh_scheduled: self._refresh_scheduled = True def unset_flag(): # set the flag here and not in refresh() since we can't be sure whether # refresh() of this class will be reached or a subclass will not call super() self._refresh_scheduled = False ExtScheduler().add_new_object(Callback.ChainedCallbacks(unset_flag, self.refresh), self, run_in=self.__class__.scheduled_update_delay)
def __init(self, target_point, starting_point): self.target_point = target_point self.starting_point = starting_point self.combatIntermissions = { self.missionStates.sailing_to_target: (self.sail_to_target, self.flee_home), self.missionStates.going_back: (self.go_back, self.flee_home), self.missionStates.fleeing_home: (self.flee_home, self.flee_home), } self._state_fleet_callbacks = { self.missionStates.sailing_to_target: Callback(self.go_back), self.missionStates.going_back: Callback(self.report_success, "Ships arrived at the target"), self.missionStates.fleeing_home: Callback(self.report_failure, "Combat was lost, ships fled home successfully"), }
def __init__(self, world_editor, ingame_gui): super(SettingsTab, self).__init__(widget=self.widget) self._world_editor = world_editor # Brush size for i in range(1, 6): b = self.widget.findChild(name='size_%d' % i) b.capture(Callback(self._change_brush_size, i)) # Activate radio button for default brush size self._change_brush_size(self._world_editor.brush_size) # Tile selection for tile_type in ('default_land', 'sand', 'shallow_water', 'water'): image = self.widget.findChild(name=tile_type) tile = getattr(GROUND, tile_type.upper()) image.up_image = self._get_tile_image(tile) image.size = image.min_size = image.max_size = (64, 32) image.capture(Callback(ingame_gui.set_cursor, 'tile_layer', tile))
def tick(self): Scheduler().add_new_object(Callback(self.tick), self, run_in=self.tick_interval) self.settlement_founder.tick() self.handle_enemy_expansions() self.handle_settlements() self.special_domestic_trade_manager.tick() self.international_trade_manager.tick() self.unit_manager.tick() self.combat_manager.tick()
def show(self): run_in = PLAYER.STATS_UPDATE_FREQUENCY / GAME_SPEED.TICKS_PER_SECOND ExtScheduler().add_new_object(Callback(self._refresh_tick), self, run_in=run_in, loops=-1) if not self._initialised: self._initialised = True self._init_gui() self.refresh() self._gui.show()
def load_attacks(cls, session, db): """ Loads ongoing attacks from savegame database Creates scheduled calls for on_impact """ for (ticks, weapon_id, damage, dx, dy) in db( "SELECT remaining_ticks, weapon_id, damage, dest_x, dest_y FROM attacks" ): Scheduler().add_new_object( Callback(Weapon.on_impact, session, weapon_id, damage, Point(dx, dy)), Weapon, ticks)
def __init__(self, instances, show_number=True): self.instances = instances self.widget = load_uh_widget("unit_entry_widget.xml") # get the icon of the first instance self.widget.findChild( name="unit_button").up_image = self.get_thumbnail_icon( instances[0].id) if show_number: self.widget.findChild(name="instance_number").text = unicode( len(self.instances)) # only two callbacks are needed so drop unwanted changelistener inheritance for i in instances: if not i.has_remove_listener(Callback(self.on_instance_removed, i)): i.add_remove_listener(Callback(self.on_instance_removed, i)) health_component = i.get_component(HealthComponent) if not health_component.has_damage_dealt_listener( self.draw_health): health_component.add_damage_dealt_listener(self.draw_health) self.draw_health()
def on_instance_removed(self, instance): self.instances.remove(instance) instance.discard_remove_listener( Callback(self.on_instance_removed, instance)) health_component = instance.get_component(HealthComponent) if health_component.has_damage_dealt_listener(self.draw_health): health_component.remove_damage_dealt_listener(self.draw_health) if self.instances: self.widget.findChild(name="instance_number").text = unicode( len(self.instances))
def refresh(self): self.widget.child_finder( 'headline').text = self.settlement.get_component( NamedComponent).name events = { 'headline': Callback(self.instance.session.ingame_gui.show_change_name_dialog, self.settlement) } self.widget.mapEvents(events) super(MainSquareOverviewTab, self).refresh()
def fire(self, destination, position, bullet_delay=0): """ Fires the weapon at a certain destination @param destination: Point with position where weapon will be fired @param position: position where the weapon is fired from @param bullet_delay: """ self.log.debug("%s fire; ready: %s", self, self.attack_ready) if not self.attack_ready: return distance = round(position.distance(destination.center)) if not self.check_target_in_range(distance): self.log.debug("%s target not in range", self) return #calculate the ticks until impact impact_ticks = int(GAME_SPEED.TICKS_PER_SECOND * distance / self.attack_speed) #deal damage when attack reaches target Scheduler().add_new_object( Callback(Weapon.on_impact, self.session, self.weapon_id, self.get_damage_modifier(), destination), Weapon, impact_ticks) #calculate the ticks until attack is ready again ready_ticks = int(GAME_SPEED.TICKS_PER_SECOND * self.cooldown_time) Scheduler().add_new_object(self.make_attack_ready, self, ready_ticks) if self.bullet_image: Scheduler().add_new_object(Callback(Bullet, self.bullet_image, position, destination, impact_ticks - bullet_delay, self.session), self, run_in=bullet_delay) self.log.debug("fired %s at %s, impact in %s", self, destination, impact_ticks - bullet_delay) self.attack_ready = False self.on_weapon_fired()
def _on_resource_produced(self, message): """This is called by the message bus with ResourceProduced messages""" assert isinstance(message, ResourceProduced) # if we get an empty dictionary, abort if (not message.produced_resources or not message.produced_resources.keys()) or \ not message.caller.instance.owner.is_local_player: return # makes the animation independent from game speed cur_ticks_per_second = Scheduler().timer.ticks_per_second interval = None if cur_ticks_per_second > GAME_SPEED.TICKS_PER_SECOND: interval = (cur_ticks_per_second // GAME_SPEED.TICKS_PER_SECOND) - 1 display_latency = 1 for resource_item in message.produced_resources.items(): res = resource_item[0] # TODO multiple resources amount = message.sender.get_component( StorageComponent).inventory[res] # abort if amount is zero if not amount: continue group = self.get_resource_string(message.sender, res) self.run[group] = self.animation_steps tick_callback = Callback(self.__render_icon, message.sender, group, res, amount) finish_callback = Callback(self.remove_icon, group) Scheduler().add_new_object(tick_callback, self, finish_callback=finish_callback, run_in=display_latency, loops=self.animation_duration, loop_interval=interval) display_latency += (self.animation_duration * display_latency) * ( interval if interval else 1)
def add_weapon_to_storage(self, weapon_id): """ adds weapon to storage @param weapon_id : id of the weapon to be added """ self.log.debug("%s add weapon %s", self, weapon_id) #if weapon is stackable, try to stack weapon = None if self.equipped_weapon_number == self.total_number_of_weapons: self.log.debug("%s weapon storage full", self) return False if self.session.db.get_weapon_stackable(weapon_id): stackable = [ w for w in self._weapon_storage if weapon_id == w.weapon_id ] #try to increase the number of weapons for one stackable weapon increased = False for weapon in stackable: try: weapon.increase_number_of_weapons(1) increased = True break except SetStackableWeaponNumberError: continue if not increased: weapon = StackableWeapon(self.session, weapon_id) else: weapon = Weapon(self.session, weapon_id) if weapon: self._weapon_storage.append(weapon) weapon.add_weapon_fired_listener( Callback(self._remove_from_fireable, weapon)) weapon.add_attack_ready_listener( Callback(self._add_to_fireable, weapon)) weapon.add_weapon_fired_listener( self._increase_fired_weapons_number) self._fireable.append(weapon) self.equipped_weapon_number += 1 self.on_storage_modified() # will update the range return True
def infect(self, building, load=None): """@load: (db, disaster_worldid), set on restoring infected state of savegame""" super(BuildingInfluencingDisaster, self).infect(building, load=load) self._affected_buildings.append(building) havoc_time = self.TIME_BEFORE_HAVOC # keep in sync with load() if load: db, worldid = load havoc_time = db("SELECT remaining_ticks_havoc FROM building_influencing_disaster WHERE disaster = ? AND building = ?", worldid, building.worldid)[0][0] Scheduler().add_new_object(Callback(self.wreak_havoc, building), self, run_in=havoc_time) AddStatusIcon.broadcast(building, self.STATUS_ICON(building)) NewDisaster.broadcast(building.owner, building, self.__class__, self)
def prepare(self): if self._mode == 'load': self._map_files, self._map_file_display = SavegameManager.get_saves( ) if not self._map_files: self._windows.open_popup( T("No saved games"), T("There are no saved games to load.")) return False elif self._mode == 'save': self._map_files, self._map_file_display = SavegameManager.get_regular_saves( ) elif self._mode == 'editor-save': self._map_files, self._map_file_display = SavegameManager.get_maps( ) self._gui.distributeInitialData( {'savegamelist': self._map_file_display}) if self._mode == 'load': self._gui.distributeData({'savegamelist': 0}) self._cb = self._create_show_savegame_details(self._gui, self._map_files, 'savegamelist') if self._mode in ('save', 'editor-save'): def selected_changed(): """Fills in the name of the savegame in the textbox when selected in the list""" if self._gui.collectData( 'savegamelist' ) == -1: # set blank if nothing is selected self._gui.findChild(name="savegamefile").text = u"" else: savegamefile = self._map_file_display[ self._gui.collectData('savegamelist')] self._gui.distributeData({'savegamefile': savegamefile}) self._cb = Callback.ChainedCallbacks(self._cb, selected_changed) self._cb() # Refresh data on start self._gui.mapEvents({'savegamelist/action': self._cb}) self._gui.findChild(name="savegamelist").capture( self._cb, event_name="keyPressed") self._gui.findChild(name="savegamelist").capture( self.check_double_click, event_name="mousePressed") self.return_events = { OkButton.DEFAULT_NAME: True, CancelButton.DEFAULT_NAME: False, DeleteButton.DEFAULT_NAME: 'delete' } if self._mode in ('save', 'editor-save'): self.return_events['savegamefile'] = True
def apply_new_key(newkey=None): if not newkey: newkey = free_keys[listbox.selected] else: listbox.selected = listbox.items.index(newkey) self.keyconf.save_new_key(action, newkey=newkey) update_hotkey_info(action, newkey) lbl.text = self.HELPSTRING_LAYOUT.format(text=lbl.explanation, key=newkey) lbl.capture( Callback(self.show_hotkey_change_popup, action, lbl, newkey)) lbl.adaptLayout()
def __init__(self, selected_instances=None): self.selected_instances = selected_instances or [] # keep track of units that have stance self.stance_unit_number = 0 # keep local track of selected instances self.instances = [] # keep track of number of instances per type self.type_number = defaultdict(int) for i in self.selected_instances: if hasattr(i, 'stance'): self.stance_unit_number += 1 self.instances.append(i) if not i.has_remove_listener(Callback(self.on_instance_removed, i)): i.add_remove_listener(Callback(self.on_instance_removed, i)) self.type_number[i.id] += 1 self._scheduled_refresh = False super(SelectMultiTab, self).__init__()
def _initialize_mission(self): """ Initializes mission after loading is finished. """ # Add move callback for fleet, dependent on loaded fleet state if self.state in self._state_fleet_callbacks: self.fleet.callback = self._state_fleet_callbacks[self.state] # Add destroy callback, the same for every case of fleet being destroyed self.fleet.destroy_callback = Callback(self.cancel, "All ships were destroyed")
def refresh(self): self.widget.findChild( name="headline").text = self.instance.settlement.get_component( NamedComponent).name events = { 'headline': Callback(self.instance.session.ingame_gui.show_change_name_dialog, self.instance.settlement) } self.widget.mapEvents(events) self._refresh_collector_utilization() super(WarehouseOverviewTab, self).refresh()
def _create_build_buttons(self, building_id, container): # {{mode}} in double braces because it is replaced as a second step path = "content/gui/icons/buildmenu/{id:03d}{{mode}}.png".format( id=building_id) helptext = self.instance.session.db.get_building_tooltip(building_id) build_button = ImageButton(name="build{id}".format(id=building_id), helptext=helptext) build_button.up_image = path.format(mode='') build_button.down_image = build_button.hover_image = path.format( mode='_h') build_button.capture(Callback(self.build_related, building_id)) return build_button
def _load(self, db, worldid, success_callback, failure_callback): db_result = db( "SELECT settlement_manager, settlement, ship, bought_resource, sold_resource, state FROM ai_mission_international_trade WHERE rowid = ?", worldid)[0] self.settlement_manager = WorldObject.get_object_by_id(db_result[0]) self.settlement = WorldObject.get_object_by_id(db_result[1]) self.bought_resource = db_result[3] self.sold_resource = db_result[4] self.state = self.missionStates[db_result[5]] super(InternationalTrade, self).load(db, worldid, success_callback, failure_callback, WorldObject.get_object_by_id(db_result[2])) if self.state is self.missionStates.moving_to_my_settlement: self.ship.add_move_callback(Callback(self._reached_my_settlement)) self.ship.add_blocked_callback( Callback(self._move_to_my_settlement)) elif self.state is self.missionStates.moving_to_other_settlement: self.ship.add_move_callback( Callback(self._reached_other_settlement)) self.ship.add_blocked_callback( Callback(self._move_to_other_settlement)) elif self.state is self.missionStates.returning_to_my_settlement: self.ship.add_move_callback( Callback(self._returned_to_my_settlement)) self.ship.add_blocked_callback( Callback(self._return_to_my_settlement)) else: assert False, 'invalid state'