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)
示例#3
0
    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")
示例#4
0
	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)
示例#6
0
	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()
示例#11
0
	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]
示例#14
0
        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()
示例#16
0
	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)
示例#17
0
	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()