def act(self, action, facing_loc=None, repeating=False, force_restart=True): """ @param repeating: maps to fife, currently broken: http://github.com/fifengine/fifengine/issues/708 @param force_restart: whether to always restart, even if action is already displayed """ if not self.has_action(action): action = 'idle' if not force_restart and self._action == action: return self._action = action # TODO This should not happen, this is a fix for the component introduction # Should be fixed as soon as we move concrete object to a component as well # which ensures proper initialization order for loading and initing if self._instance is None: return if facing_loc is None: facing_loc = self._instance.getFacingLocation() UnitClass.ensure_action_loaded(self._action_set_id, action) # lazy if (Fife.getVersion() >= (0, 3, 6)): if repeating: self._instance.actRepeat(action+"_"+str(self._action_set_id), facing_loc) else: self._instance.actOnce(action+"_"+str(self._action_set_id), facing_loc) else: self._instance.act(action+"_"+str(self._action_set_id), facing_loc, repeating) ActionChanged.broadcast(self, action)
def act(self, action, facing_loc=None, repeating=False, force_restart=True): """ @param repeating: maps to fife instance method actRepeat or actOnce @param force_restart: whether to always restart, even if action is already displayed """ if not self.has_action(action): action = 'idle' if not force_restart and self._action == action: return self._action = action # TODO This should not happen, this is a fix for the component introduction # Should be fixed as soon as we move concrete object to a component as well # which ensures proper initialization order for loading and initing if self._instance is None: return if facing_loc is None: facing_loc = self._instance.getFacingLocation() UnitClass.ensure_action_loaded(self._action_set_id, action) # lazy if (Fife.getVersion() >= (0, 3, 6)): if repeating: self._instance.actRepeat(action + "_" + str(self._action_set_id), facing_loc) else: self._instance.actOnce(action + "_" + str(self._action_set_id), facing_loc) else: self._instance.act(action + "_" + str(self._action_set_id), facing_loc, repeating) ActionChanged.broadcast(self, action)
def update_buttons(self, container_active, cancel_container): """Show the correct active and inactive buttons, update cancel button""" button_active = container_active.findChild(name="toggle_active_active") button_inactive = container_active.findChild( name="toggle_active_inactive") to_active = not self.producer.is_active() if not to_active: # swap what we want to show and hide button_active, button_inactive = button_inactive, button_active if (Fife.getVersion() >= (0, 4, 0)): button_active.parent.hideChild(button_active) else: if button_active not in button_active.parent.hidden_children: button_active.parent.hideChild(button_active) button_inactive.parent.showChild(button_inactive) set_active_cb = Callback(self.producer.set_active, active=to_active) button_inactive.capture(set_active_cb, event_name="mouseClicked") cancel_container.parent.showChild(cancel_container) cancel_button = self.widget.findChild(name="UB_cancel_button") cancel_cb = Callback( CancelCurrentProduction(self.producer).execute, self.instance.session) cancel_button.capture(cancel_cb, event_name="mouseClicked")
def show_production_is_inactive_container(self, container_inactive, progress_container, cancel_container, container_active): """Hides all information on progress etc, and displays something to signal that the production is inactive.""" container_inactive.parent.showChild(container_inactive) for w in (container_active, progress_container, cancel_container): if (Fife.getVersion() >= (0, 4, 0)): w.parent.hideChild(w) else: if w not in w.parent.hidden_children: w.parent.hideChild(w)
def show_production_is_inactive_container(self, container_inactive, progress_container, cancel_container, container_active): """Hides all information on progress etc, and displays something to signal that the production is inactive.""" container_inactive.parent.showChild(container_inactive) for w in (container_active, progress_container, cancel_container): if (Fife.getVersion() >= (0, 4, 0)): w.parent.hideChild(w) else: if not w in w.parent.hidden_children: w.parent.hideChild(w)
def show_production_is_active_container(self, container_active, container_inactive, progress_container, cancel_container, production_lines): """Show the container containing the active production.""" container_active.parent.showChild(container_active) if (Fife.getVersion() >= (0, 4, 0)): container_inactive.parent.hideChild(container_inactive) else: if container_inactive not in container_inactive.parent.hidden_children: container_inactive.parent.hideChild(container_inactive) self.update_production_is_active_container(progress_container, container_active, cancel_container, production_lines)
def __init__(self, mode, windows): super(SelectSavegameDialog, self).__init__(windows) assert mode in ('load', 'save', 'editor-save') self._mode = mode self._gui = load_uh_widget('select_savegame.xml') if self._mode == 'save': helptext = T('Save game') elif self._mode == 'load': helptext = T('Load game') elif self._mode == 'editor-save': helptext = T('Save map') self._gui.findChild(name='headline').text = helptext self._gui.findChild(name=OkButton.DEFAULT_NAME).helptext = helptext w = self._gui.findChild(name="gamename_box") if (Fife.getVersion() >= (0, 4, 0)): w.parent.hideChild(w) else: if w not in w.parent.hidden_children: w.parent.hideChild(w) w = self._gui.findChild(name="gamepassword_box") if (Fife.getVersion() >= (0, 4, 0)): w.parent.hideChild(w) else: if w not in w.parent.hidden_children: w.parent.hideChild(w) w = self._gui.findChild(name='enter_filename') if self._mode in ('save', 'editor-save'): # only show enter_filename on save w.parent.showChild(w) else: if (Fife.getVersion() >= (0, 4, 0)): w.parent.hideChild(w) else: if w not in w.parent.hidden_children: w.parent.hideChild(w) self.last_click_event = None
def show_production_is_active_container(self, container_active, container_inactive, progress_container, cancel_container, production_lines): """Show the container containing the active production.""" container_active.parent.showChild(container_active) if (Fife.getVersion() >= (0, 4, 0)): container_inactive.parent.hideChild(container_inactive) else: if not container_inactive in container_inactive.parent.hidden_children: container_inactive.parent.hideChild(container_inactive) self.update_production_is_active_container(progress_container, container_active, cancel_container, production_lines)
def __init__(self, mode, windows): super(SelectSavegameDialog, self).__init__(windows) assert mode in ('load', 'save', 'editor-save') self._mode = mode self._gui = load_uh_widget('select_savegame.xml') if self._mode == 'save': helptext = _('Save game') elif self._mode == 'load': helptext = _('Load game') elif self._mode == 'editor-save': helptext = _('Save map') self._gui.findChild(name='headline').text = helptext self._gui.findChild(name=OkButton.DEFAULT_NAME).helptext = helptext w = self._gui.findChild(name="gamename_box") if (Fife.getVersion() >= (0, 4, 0)): w.parent.hideChild(w) else: if w not in w.parent.hidden_children: w.parent.hideChild(w) w = self._gui.findChild(name="gamepassword_box") if (Fife.getVersion() >= (0, 4, 0)): w.parent.hideChild(w) else: if w not in w.parent.hidden_children: w.parent.hideChild(w) w = self._gui.findChild(name='enter_filename') if self._mode in ('save', 'editor-save'): # only show enter_filename on save w.parent.showChild(w) else: if (Fife.getVersion() >= (0, 4, 0)): w.parent.hideChild(w) else: if w not in w.parent.hidden_children: w.parent.hideChild(w) self.last_click_event = None
def toggle(self): if (Fife.getVersion() <= (0, 3, 5)): if self._visible: self.hide() else: self.show() else: if self.isSetVisible(): self.hide() else: self.show()
def update_buttons(self, container_active, cancel_container): """Show the correct active and inactive buttons, update cancel button""" button_active = container_active.findChild(name="toggle_active_active") button_inactive = container_active.findChild(name="toggle_active_inactive") to_active = not self.producer.is_active() if not to_active: # swap what we want to show and hide button_active, button_inactive = button_inactive, button_active if Fife.getVersion() >= (0, 4, 0): button_active.parent.hideChild(button_active) else: if not button_active in button_active.parent.hidden_children: button_active.parent.hideChild(button_active) button_inactive.parent.showChild(button_inactive) set_active_cb = Callback(self.producer.set_active, active=to_active) button_inactive.capture(set_active_cb, event_name="mouseClicked") cancel_container.parent.showChild(cancel_container) cancel_button = self.widget.findChild(name="UB_cancel_button") cancel_cb = Callback(CancelCurrentProduction(self.producer).execute, self.instance.session) cancel_button.capture(cancel_cb, event_name="mouseClicked")
def _move_tick(self, resume=False): """Called by the scheduler, moves the unit one step for this tick. """ assert self._next_target is not None if self._fife_location1 is None: # this data structure is needed multiple times, only create once self._fife_location1 = fife.Location(self._instance.getLocationRef().getLayer()) self._fife_location2 = fife.Location(self._instance.getLocationRef().getLayer()) if resume: self.__is_moving = True else: #self.log.debug("%s move tick from %s to %s", self, self.last_position, self._next_target) self.last_position = self.position self.position = self._next_target self._changed() # try to get next step, handle a blocked path while self._next_target == self.position: try: self._next_target = self.path.get_next_step() except PathBlockedError: # if we are trying to resume and it isn't possible then we need to raise it again if resume: raise self.log.debug("path is blocked") self.log.debug("owner: %s", self.owner) self.__is_moving = False self._next_target = self.position if self.blocked_callbacks: self.log.debug('PATH FOR UNIT %s is blocked. Calling blocked_callback', self) self.blocked_callbacks.execute() else: # generic solution: retry in 2 secs self.log.debug('PATH FOR UNIT %s is blocked. Retry in 2 secs', self) # technically, the ship doesn't move, but it is in the process of moving, # as it will continue soon in general. Needed in border cases for add_move_callback self.__is_moving = True Scheduler().add_new_object(self._move_tick, self, GAME_SPEED.TICKS_PER_SECOND * 2) self.log.debug("Unit %s: path is blocked, no way around", self) return if self._next_target is None: self._movement_finished() return else: self.__is_moving = True #setup movement move_time = self.get_unit_velocity() UnitClass.ensure_action_loaded(self._action_set_id, self._move_action) # lazy load move action self._exact_model_coords1.set(self.position.x, self.position.y, 0) self._fife_location1.setExactLayerCoordinates(self._exact_model_coords1) self._exact_model_coords2.set(self._next_target.x, self._next_target.y, 0) self._fife_location2.setExactLayerCoordinates(self._exact_model_coords2) self._route = fife.Route(self._fife_location1, self._fife_location2) # TODO/HACK the *5 provides slightly less flickery behavior of the moving # objects. This should be fixed properly by using the fife pathfinder for # the entire route and task location_list = fife.LocationList([self._fife_location2]*5) # It exists for FIFE 0.3.4 compat. See #1993. if Fife.getVersion() == (0,3,4): location_list.thisown = 0 self._route.thisown = 0 self._route.setPath(location_list) self.act(self._move_action) diagonal = self._next_target.x != self.position.x and self._next_target.y != self.position.y speed = float(self.session.timer.get_ticks(1)) / move_time[0] action = self._instance.getCurrentAction().getId() self._instance.follow(action, self._route, speed) #self.log.debug("%s registering move tick in %s ticks", self, move_time[int(diagonal)]) Scheduler().add_new_object(self._move_tick, self, move_time[int(diagonal)]) # check if a conditional callback becomes true for cond in self._conditional_callbacks.keys(): # iterate of copy of keys to be able to delete if cond(): # start callback when this function is done Scheduler().add_new_object(self._conditional_callbacks[cond], self) del self._conditional_callbacks[cond]
def tmp_show_details(): """Fetches details of selected savegame and displays it""" gui.findChild(name="screenshot").image = None map_file = None map_file_index = gui.collectData(savegamelist) savegame_details_box = gui.findChild(name="savegame_details") savegame_details_parent = savegame_details_box.parent if map_file_index == -1: if (Fife.getVersion() >= (0, 4, 0)): savegame_details_parent.hideChild(savegame_details_box) else: if savegame_details_box not in savegame_details_parent.hidden_children: savegame_details_parent.hideChild(savegame_details_box) return else: savegame_details_parent.showChild(savegame_details_box) try: map_file = map_files[map_file_index] except IndexError: # this was a click in the savegame list, but not on an element # it happens when the savegame list is empty return savegame_info = SavegameManager.get_metadata(map_file) if savegame_info.get('screenshot'): # try to find a writable location, that is accessible via relative paths # (required by fife) fd, filename = tempfile.mkstemp() try: path_rel = os.path.relpath(filename) except ValueError: # the relative path sometimes doesn't exist on win os.close(fd) os.unlink(filename) # try again in the current dir, it's often writable fd, filename = tempfile.mkstemp(dir=os.curdir) try: path_rel = os.path.relpath(filename) except ValueError: fd, filename = None, None if fd: with os.fdopen(fd, "w") as f: f.write(savegame_info['screenshot']) # fife only supports relative paths gui.findChild(name="screenshot").image = path_rel os.unlink(filename) # savegamedetails details_label = gui.findChild(name="savegamedetails_lbl") details_label.text = u"" if savegame_info['timestamp'] == -1: details_label.text += T("Unknown savedate") else: savetime = time.strftime( "%c", time.localtime(savegame_info['timestamp'])) details_label.text += T("Saved at {time}").format( time=savetime.decode('utf-8')) details_label.text += u'\n' counter = savegame_info['savecounter'] # NT takes care of plural forms for different languages details_label.text += NT("Saved {amount} time", "Saved {amount} times", counter).format(amount=counter) details_label.text += u'\n' from horizons.constants import VERSION try: details_label.text += T("Savegame version {version}").format( version=savegame_info['savegamerev']) if savegame_info['savegamerev'] != VERSION.SAVEGAMEREVISION: if not SavegameUpgrader.can_upgrade( savegame_info['savegamerev']): details_label.text += u" " + T( "(probably incompatible)") except KeyError: # this should only happen for very old savegames, so having this unfriendly # error is ok (savegame is quite certainly fully unusable). details_label.text += u" " + T("Incompatible version") gui.adaptLayout()
def tmp_show_details(): """Fetches details of selected savegame and displays it""" gui.findChild(name="screenshot").image = None map_file = None map_file_index = gui.collectData(savegamelist) savegame_details_box = gui.findChild(name="savegame_details") savegame_details_parent = savegame_details_box.parent if map_file_index == -1: if (Fife.getVersion() >= (0, 4, 0)): savegame_details_parent.hideChild(savegame_details_box) else: if savegame_details_box not in savegame_details_parent.hidden_children: savegame_details_parent.hideChild(savegame_details_box) return else: savegame_details_parent.showChild(savegame_details_box) try: map_file = map_files[map_file_index] except IndexError: # this was a click in the savegame list, but not on an element # it happens when the savegame list is empty return savegame_info = SavegameManager.get_metadata(map_file) if savegame_info.get('screenshot'): # try to find a writable location, that is accessible via relative paths # (required by fife) fd, filename = tempfile.mkstemp() try: path_rel = os.path.relpath(filename) except ValueError: # the relative path sometimes doesn't exist on win os.close(fd) os.unlink(filename) # try again in the current dir, it's often writable fd, filename = tempfile.mkstemp(dir=os.curdir) try: path_rel = os.path.relpath(filename) except ValueError: fd, filename = None, None if fd: with os.fdopen(fd, "w") as f: f.write(savegame_info['screenshot']) # fife only supports relative paths gui.findChild(name="screenshot").image = path_rel os.unlink(filename) # savegamedetails details_label = gui.findChild(name="savegamedetails_lbl") details_label.text = u"" if savegame_info['timestamp'] == -1: details_label.text += _("Unknown savedate") else: savetime = time.strftime("%c", time.localtime(savegame_info['timestamp'])) details_label.text += _("Saved at {time}").format(time=savetime.decode('utf-8')) details_label.text += u'\n' counter = savegame_info['savecounter'] # N_ takes care of plural forms for different languages details_label.text += N_("Saved {amount} time", "Saved {amount} times", counter).format(amount=counter) details_label.text += u'\n' from horizons.constants import VERSION try: details_label.text += _("Savegame version {version}").format( version=savegame_info['savegamerev']) if savegame_info['savegamerev'] != VERSION.SAVEGAMEREVISION: if not SavegameUpgrader.can_upgrade(savegame_info['savegamerev']): details_label.text += u" " + _("(probably incompatible)") except KeyError: # this should only happen for very old savegames, so having this unfriendly # error is ok (savegame is quite certainly fully unusable). details_label.text += u" " + _("Incompatible version") gui.adaptLayout()
def getInstance(cls, session, x, y, action='idle', level=0, rotation=45, action_set_id=None, world_id=""): """Get a Fife instance @param x, y: The coordinates @param action: The action, defaults to 'idle' @param level: object level. Relevant for choosing an action set @param rotation: rotation of the object. Any of [ 45 + 90*i for i in xrange(0, 4) ] @param action_set_id: can be set if the action set is already known. If set, level isn't considered. @return: tuple (fife_instance, action_set_id) """ assert isinstance(x, int) assert isinstance(y, int) #rotation = cls.check_build_rotation(session, rotation, x, y) # TODO: replace this with new buildable api # IDEA: save rotation in savegame facing_loc = fife.Location(session.view.layers[cls.layer]) instance_coords = list((x, y, 0)) layer_coords = list((x, y, 0)) width, length = cls.size # NOTE: # nobody actually knows how the code below works. # it's for adapting the facing location and instance coords in # different rotations, and works with all quadratic buildings (tested up to 4x4) # for the first unquadratic building (2x4), a hack fix was put into it. # the plan for fixing this code in general is to wait until there are more # unquadratic buildings, and figure out a pattern of the placement error, # then fix that generally. if rotation == 45: layer_coords[0] = x + width + 3 if width == 2 and length == 4: # HACK: fix for 4x2 buildings instance_coords[0] -= 1 instance_coords[1] += 1 elif rotation == 135: instance_coords[1] = y + length - 1 layer_coords[1] = y - length - 3 if width == 2 and length == 4: # HACK: fix for 4x2 buildings instance_coords[0] += 1 instance_coords[1] -= 1 elif rotation == 225: instance_coords = list(( x + width - 1, y + length - 1, 0)) layer_coords[0] = x - width - 3 if width == 2 and length == 4: # HACK: fix for 4x2 buildings instance_coords[0] += 1 instance_coords[1] -= 1 elif rotation == 315: instance_coords[0] = x + width - 1 layer_coords[1] = y + length + 3 if width == 2 and length == 4: # HACK: fix for 4x2 buildings instance_coords[0] += 1 instance_coords[1] -= 1 else: return None instance = session.view.layers[cls.layer].createInstance( cls._fife_object, fife.ModelCoordinate(*instance_coords), world_id) facing_loc.setLayerCoordinates(fife.ModelCoordinate(*layer_coords)) if action_set_id is None: action_set_id = cls.get_random_action_set(level=level) fife.InstanceVisual.create(instance) action_set = ActionSetLoader.get_set(action_set_id) if action not in action_set: if 'idle' in action_set: action = 'idle' elif 'idle_full' in action_set: action = 'idle_full' else: # set first action action = list(action_set.keys())[0] if (Fife.getVersion() >= (0, 3, 6)): instance.actRepeat(action+"_"+str(action_set_id), facing_loc) else: instance.act(action+"_"+str(action_set_id), facing_loc, True) return (instance, action_set_id)
def getInstance(cls, session, x, y, action='idle', level=0, rotation=45, action_set_id=None, world_id=""): """Get a Fife instance @param x, y: The coordinates @param action: The action, defaults to 'idle' @param level: object level. Relevant for choosing an action set @param rotation: rotation of the object. Any of [ 45 + 90*i for i in xrange(0, 4) ] @param action_set_id: can be set if the action set is already known. If set, level isn't considered. @return: tuple (fife_instance, action_set_id) """ assert isinstance(x, int) assert isinstance(y, int) #rotation = cls.check_build_rotation(session, rotation, x, y) # TODO: replace this with new buildable api # IDEA: save rotation in savegame facing_loc = fife.Location(session.view.layers[cls.layer]) instance_coords = list((x, y, 0)) layer_coords = list((x, y, 0)) width, length = cls.size # NOTE: # nobody actually knows how the code below works. # it's for adapting the facing location and instance coords in # different rotations, and works with all quadratic buildings (tested up to 4x4) # for the first unquadratic building (2x4), a hack fix was put into it. # the plan for fixing this code in general is to wait until there are more # unquadratic buildings, and figure out a pattern of the placement error, # then fix that generally. if rotation == 45: layer_coords[0] = x + width + 3 if width == 2 and length == 4: # HACK: fix for 4x2 buildings instance_coords[0] -= 1 instance_coords[1] += 1 elif rotation == 135: instance_coords[1] = y + length - 1 layer_coords[1] = y - length - 3 if width == 2 and length == 4: # HACK: fix for 4x2 buildings instance_coords[0] += 1 instance_coords[1] -= 1 elif rotation == 225: instance_coords = list(( x + width - 1, y + length - 1, 0)) layer_coords[0] = x - width - 3 if width == 2 and length == 4: # HACK: fix for 4x2 buildings instance_coords[0] += 1 instance_coords[1] -= 1 elif rotation == 315: instance_coords[0] = x + width - 1 layer_coords[1] = y + length + 3 if width == 2 and length == 4: # HACK: fix for 4x2 buildings instance_coords[0] += 1 instance_coords[1] -= 1 else: return None instance = session.view.layers[cls.layer].createInstance( cls._fife_object, fife.ModelCoordinate(*instance_coords), world_id) facing_loc.setLayerCoordinates(fife.ModelCoordinate(*layer_coords)) if action_set_id is None: action_set_id = cls.get_random_action_set(level=level) fife.InstanceVisual.create(instance) action_sets = ActionSetLoader.get_sets() if not action in action_sets[action_set_id]: if 'idle' in action_sets[action_set_id]: action = 'idle' elif 'idle_full' in action_sets[action_set_id]: action = 'idle_full' else: # set first action action = action_sets[action_set_id].keys()[0] if (Fife.getVersion() >= (0, 3, 6)): instance.actRepeat(action+"_"+str(action_set_id), facing_loc) else: instance.act(action+"_"+str(action_set_id), facing_loc, True) return (instance, action_set_id)
def refresh(self): """This function is called by the TabWidget to redraw the widget.""" super(BoatbuilderTab, self).refresh() main_container = self.widget.findChild(name="BB_main_tab") container_active = main_container.findChild(name="container_active") container_inactive = main_container.findChild( name="container_inactive") progress_container = main_container.findChild( name="BB_progress_container") cancel_container = main_container.findChild(name="BB_cancel_container") needed_res_container = self.widget.findChild( name="BB_needed_resources_container") # a boatbuilder is considered active here if it builds sth, no matter if it's paused production_lines = self.producer.get_production_lines() if production_lines: cancel_container.parent.showChild(cancel_container) # Set progress progress_container.parent.showChild(progress_container) progress = math.floor(self.producer.get_production_progress() * 100) self.widget.findChild(name='progress').progress = progress progress_perc = self.widget.findChild(name='BB_progress_perc') progress_perc.text = u'{progress}%'.format(progress=progress) container_active.parent.showChild(container_active) if (Fife.getVersion() >= (0, 4, 0)): container_inactive.parent.hideChild(container_inactive) else: if not container_inactive in container_inactive.parent.hidden_children: container_inactive.parent.hideChild(container_inactive) # Update boatbuilder queue queue = self.producer.get_unit_production_queue() queue_container = container_active.findChild( name="queue_container") queue_container.removeAllChildren() for place_in_queue, unit_type in enumerate(queue): image = self.__class__.SHIP_THUMBNAIL.format(type_id=unit_type) helptext = _("{ship} (place in queue: {place})").format( ship=self.instance.session.db.get_unit_type_name( unit_type), place=place_in_queue + 1) # people don't count properly, always starting at 1.. icon_name = "queue_elem_" + str(place_in_queue) icon = Icon(name=icon_name, image=image, helptext=helptext) rm_from_queue_cb = Callback( RemoveFromQueue(self.producer, place_in_queue).execute, self.instance.session) icon.capture(rm_from_queue_cb, event_name="mouseClicked") queue_container.addChild(icon) # Set built ship info production_line = self.producer._get_production( production_lines[0]) produced_unit_id = production_line.get_produced_units().keys()[0] name = self.instance.session.db.get_unit_type_name( produced_unit_id) container_active.findChild( name="headline_BB_builtship_label").text = _(name) ship_icon = container_active.findChild(name="BB_cur_ship_icon") ship_icon.helptext = self.instance.session.db.get_ship_tooltip( produced_unit_id) ship_icon.image = self.__class__.SHIP_PREVIEW_IMG.format( type_id=produced_unit_id) button_active = container_active.findChild( name="toggle_active_active") button_inactive = container_active.findChild( name="toggle_active_inactive") to_active = not self.producer.is_active() if not to_active: # swap what we want to show and hide button_active, button_inactive = button_inactive, button_active if (Fife.getVersion() >= (0, 4, 0)): button_active.parent.hideChild(button_active) else: if not button_active in button_active.parent.hidden_children: button_active.parent.hideChild(button_active) button_inactive.parent.showChild(button_inactive) set_active_cb = Callback(self.producer.set_active, active=to_active) button_inactive.capture(set_active_cb, event_name="mouseClicked") upgrades_box = container_active.findChild(name="BB_upgrades_box") upgrades_box.removeAllChildren() # Update needed resources production = self.producer.get_productions()[0] needed_res = production.get_consumed_resources() # Now sort! -amount is the positive value, drop unnecessary res (amount 0) needed_res = dict((res, -amount) for res, amount in needed_res.iteritems() if amount < 0) needed_res = sorted(needed_res.iteritems(), key=itemgetter(1), reverse=True) needed_res_container.removeAllChildren() for i, (res, amount) in enumerate(needed_res): icon = create_resource_icon(res, self.instance.session.db) icon.max_size = icon.min_size = icon.size = (16, 16) label = Label(name="needed_res_lbl_%s" % i) label.text = u'{amount}t'.format(amount=amount) new_hbox = HBox(name="needed_res_box_%s" % i) new_hbox.addChildren(icon, label) needed_res_container.addChild(new_hbox) cancel_button = self.widget.findChild(name="BB_cancel_button") cancel_cb = Callback( CancelCurrentProduction(self.producer).execute, self.instance.session) cancel_button.capture(cancel_cb, event_name="mouseClicked") else: # display sth when nothing is produced container_inactive.parent.showChild(container_inactive) for w in (container_active, progress_container, cancel_container): if (Fife.getVersion() >= (0, 4, 0)): w.parent.hideChild(w) else: if not w in w.parent.hidden_children: w.parent.hideChild(w) self.widget.adaptLayout()
def _move_tick(self, resume=False): """Called by the scheduler, moves the unit one step for this tick. """ assert self._next_target is not None if self._fife_location1 is None: # this data structure is needed multiple times, only create once self._fife_location1 = fife.Location( self._instance.getLocationRef().getLayer()) self._fife_location2 = fife.Location( self._instance.getLocationRef().getLayer()) if resume: self.__is_moving = True else: #self.log.debug("%s move tick from %s to %s", self, self.last_position, self._next_target) self.last_position = self.position self.position = self._next_target self._changed() # try to get next step, handle a blocked path while self._next_target == self.position: try: self._next_target = self.path.get_next_step() except PathBlockedError: # if we are trying to resume and it isn't possible then we need to raise it again if resume: raise self.log.debug("path is blocked") self.log.debug("owner: %s", self.owner) self.__is_moving = False self._next_target = self.position if self.blocked_callbacks: self.log.debug( 'PATH FOR UNIT %s is blocked. Calling blocked_callback', self) self.blocked_callbacks.execute() else: # generic solution: retry in 2 secs self.log.debug( 'PATH FOR UNIT %s is blocked. Retry in 2 secs', self) # technically, the ship doesn't move, but it is in the process of moving, # as it will continue soon in general. Needed in border cases for add_move_callback self.__is_moving = True Scheduler().add_new_object(self._move_tick, self, GAME_SPEED.TICKS_PER_SECOND * 2) self.log.debug("Unit %s: path is blocked, no way around", self) return if self._next_target is None: self._movement_finished() return else: self.__is_moving = True #setup movement move_time = self.get_unit_velocity() UnitClass.ensure_action_loaded( self._action_set_id, self._move_action) # lazy load move action self._exact_model_coords1.set(self.position.x, self.position.y, 0) self._fife_location1.setExactLayerCoordinates( self._exact_model_coords1) self._exact_model_coords2.set(self._next_target.x, self._next_target.y, 0) self._fife_location2.setExactLayerCoordinates( self._exact_model_coords2) self._route = fife.Route(self._fife_location1, self._fife_location2) # TODO/HACK the *5 provides slightly less flickery behavior of the moving # objects. This should be fixed properly by using the fife pathfinder for # the entire route and task location_list = fife.LocationList([self._fife_location2] * 5) # It exists for FIFE 0.3.4 compat. See #1993. if Fife.getVersion() == (0, 3, 4): location_list.thisown = 0 self._route.thisown = 0 self._route.setPath(location_list) self.act(self._move_action) diagonal = self._next_target.x != self.position.x and self._next_target.y != self.position.y speed = float(self.session.timer.get_ticks(1)) / move_time[0] action = self._instance.getCurrentAction().getId() self._instance.follow(action, self._route, speed) #self.log.debug("%s registering move tick in %s ticks", self, move_time[int(diagonal)]) Scheduler().add_new_object(self._move_tick, self, move_time[int(diagonal)]) # check if a conditional callback becomes true for cond in self._conditional_callbacks.keys( ): # iterate of copy of keys to be able to delete if cond(): # start callback when this function is done Scheduler().add_new_object(self._conditional_callbacks[cond], self) del self._conditional_callbacks[cond]
def refresh(self): """This function is called by the TabWidget to redraw the widget.""" super(BoatbuilderTab, self).refresh() main_container = self.widget.findChild(name="BB_main_tab") container_active = main_container.findChild(name="container_active") container_inactive = main_container.findChild(name="container_inactive") progress_container = main_container.findChild(name="BB_progress_container") cancel_container = main_container.findChild(name="BB_cancel_container") needed_res_container = self.widget.findChild(name="BB_needed_resources_container") # a boatbuilder is considered active here if it builds sth, no matter if it's paused production_lines = self.producer.get_production_lines() if production_lines: cancel_container.parent.showChild(cancel_container) # Set progress progress_container.parent.showChild(progress_container) progress = math.floor(self.producer.get_production_progress() * 100) self.widget.findChild(name="progress").progress = progress progress_perc = self.widget.findChild(name="BB_progress_perc") progress_perc.text = u"{progress}%".format(progress=progress) container_active.parent.showChild(container_active) if Fife.getVersion() >= (0, 4, 0): container_inactive.parent.hideChild(container_inactive) else: if not container_inactive in container_inactive.parent.hidden_children: container_inactive.parent.hideChild(container_inactive) # Update boatbuilder queue queue = self.producer.get_unit_production_queue() queue_container = container_active.findChild(name="queue_container") queue_container.removeAllChildren() for place_in_queue, unit_type in enumerate(queue): image = self.__class__.SHIP_THUMBNAIL.format(type_id=unit_type) helptext = _("{ship} (place in queue: {place})").format( ship=self.instance.session.db.get_unit_type_name(unit_type), place=place_in_queue + 1 ) # people don't count properly, always starting at 1.. icon_name = "queue_elem_" + str(place_in_queue) icon = Icon(name=icon_name, image=image, helptext=helptext) rm_from_queue_cb = Callback( RemoveFromQueue(self.producer, place_in_queue).execute, self.instance.session ) icon.capture(rm_from_queue_cb, event_name="mouseClicked") queue_container.addChild(icon) # Set built ship info production_line = self.producer._get_production(production_lines[0]) produced_unit_id = production_line.get_produced_units().keys()[0] name = self.instance.session.db.get_unit_type_name(produced_unit_id) container_active.findChild(name="headline_BB_builtship_label").text = _(name) ship_icon = container_active.findChild(name="BB_cur_ship_icon") ship_icon.helptext = self.instance.session.db.get_ship_tooltip(produced_unit_id) ship_icon.image = self.__class__.SHIP_PREVIEW_IMG.format(type_id=produced_unit_id) button_active = container_active.findChild(name="toggle_active_active") button_inactive = container_active.findChild(name="toggle_active_inactive") to_active = not self.producer.is_active() if not to_active: # swap what we want to show and hide button_active, button_inactive = button_inactive, button_active if Fife.getVersion() >= (0, 4, 0): button_active.parent.hideChild(button_active) else: if not button_active in button_active.parent.hidden_children: button_active.parent.hideChild(button_active) button_inactive.parent.showChild(button_inactive) set_active_cb = Callback(self.producer.set_active, active=to_active) button_inactive.capture(set_active_cb, event_name="mouseClicked") upgrades_box = container_active.findChild(name="BB_upgrades_box") upgrades_box.removeAllChildren() # Update needed resources production = self.producer.get_productions()[0] needed_res = production.get_consumed_resources() # Now sort! -amount is the positive value, drop unnecessary res (amount 0) needed_res = dict((res, -amount) for res, amount in needed_res.iteritems() if amount < 0) needed_res = sorted(needed_res.iteritems(), key=itemgetter(1), reverse=True) needed_res_container.removeAllChildren() for i, (res, amount) in enumerate(needed_res): icon = create_resource_icon(res, self.instance.session.db) icon.max_size = icon.min_size = icon.size = (16, 16) label = Label(name="needed_res_lbl_%s" % i) label.text = u"{amount}t".format(amount=amount) new_hbox = HBox(name="needed_res_box_%s" % i) new_hbox.addChildren(icon, label) needed_res_container.addChild(new_hbox) cancel_button = self.widget.findChild(name="BB_cancel_button") cancel_cb = Callback(CancelCurrentProduction(self.producer).execute, self.instance.session) cancel_button.capture(cancel_cb, event_name="mouseClicked") else: # display sth when nothing is produced container_inactive.parent.showChild(container_inactive) for w in (container_active, progress_container, cancel_container): if Fife.getVersion() >= (0, 4, 0): w.parent.hideChild(w) else: if not w in w.parent.hidden_children: w.parent.hideChild(w) self.widget.adaptLayout()