def __init__(self, instances, show_number=True):
		self.log = logging.getLogger("gui.tabs")
		self.instances = instances
		self.widget = load_uh_widget("unit_entry_widget.xml")
		# get the icon of the first instance
		i = instances[0]
		if i.id < UNITS.DIFFERENCE_BUILDING_UNIT_ID:
			# A building. Generate dynamic thumbnail from its action set.
			imgs = list(ActionSetLoader.get_set(i._action_set_id).items())[0][1]
			thumbnail = list(imgs[45].keys())[0]
		else:
			# Units use manually created thumbnails because those need to be
			# precise and recognizable in combat situations.
			thumbnail = self.get_unit_thumbnail(i.id)
		self.widget.findChild(name="unit_button").up_image = thumbnail
		if show_number:
			self.widget.findChild(name="instance_number").text = str(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()
Exemple #2
0
	def add_overlay(self, overlay_name, z_order):
		"""Creates color overlay recoloring the area defined in *overlay_set*

		and adds it to fife instance. Note that a color overlay on *z_order*
		can only be visible if an animation overlay with that specific order
		exists as well. For order 0, `convertToOverlays()` makes sure they do.
		"""
		if not self.fife_instance.isAnimationOverlay(self.identifier):
			# parameter False: do not convert color overlays attached to base
			self.fife_instance.convertToOverlays(self.identifier, False)

		try:
			overlay_set = ActionSetLoader.get_set(self.action_set)[overlay_name]
		except KeyError:
			self.log.warning(
				'Could not find overlay action set `%s` defined for object '
				'`%s` with id `%s`. Not adding overlay for this action.',
				overlay_name, self.instance, self.identifier)
			return

		self.current_overlays[z_order] = overlay_set
		for rotation, frames in overlay_set.iteritems():
			ov_anim = fife.Animation.createAnimation()
			for frame_img, frame_data in frames.iteritems():
				try:
					frame_length = frame_data[0]
				except TypeError:
					# not using atlases
					frame_length = frame_data
				pic = horizons.globals.fife.animationloader.load_image(frame_img, self.action_set, overlay_name, rotation)
				frame_milliseconds = int(frame_length * 1000)
				ov_anim.addFrame(pic, frame_milliseconds)
			overlay = fife.OverlayColors(ov_anim)
			self.fife_instance.addColorOverlay(self.identifier, rotation, z_order, overlay)
	def __init__(self, instances, show_number=True):
		self.log = logging.getLogger("gui.tabs")
		self.instances = instances
		self.widget = load_uh_widget("unit_entry_widget.xml")
		# get the icon of the first instance
		i = instances[0]
		if i.id < UNITS.DIFFERENCE_BUILDING_UNIT_ID:
			# A building. Generate dynamic thumbnail from its action set.
			imgs = ActionSetLoader.get_set(i._action_set_id).items()[0][1]
			thumbnail = imgs[45].keys()[0]
		else:
			# Units use manually created thumbnails because those need to be
			# precise and recognizable in combat situations.
			thumbnail = self.get_unit_thumbnail(i.id)
		self.widget.findChild(name="unit_button").up_image = thumbnail
		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_settler_level_change(self, message):
		assert isinstance(message, SettlerUpdate)
		setup_tax_slider(self.widget.child_finder('tax_slider'),
		                 self.widget.child_finder('tax_val_label'),
		                 self.instance.settlement,
		                 message.level)
		taxes = self.instance.settlement.tax_settings[self.instance.level]
		self.widget.child_finder('tax_val_label').text = str(taxes)
		imgs = list(ActionSetLoader.get_set(self.instance._action_set_id).items())[0][1]
		self.widget.findChild(name="building_image").image = list(imgs[45].keys())[0]
Exemple #5
0
 def on_settler_level_change(self, message):
     assert isinstance(message, SettlerUpdate)
     setup_tax_slider(self.widget.child_finder('tax_slider'),
                      self.widget.child_finder('tax_val_label'),
                      self.instance.settlement, message.level)
     taxes = self.instance.settlement.tax_settings[self.instance.level]
     self.widget.child_finder('tax_val_label').text = unicode(taxes)
     imgs = ActionSetLoader.get_set(
         self.instance._action_set_id).items()[0][1]
     self.widget.findChild(name="building_image").image = imgs[45].keys()[0]
    def update_overlay(self, res_id, new_amount):
        """Called when inventory amount of one resource changes.

		Looks for a fitting animation overlay based on the new inventory amount for that resource.
		If that overlay is different from the currently displayed one, removes the old overlay for
		that resource and adds a new one based on what fits *new_amount* best.
		"""
        try:
            overlay_order = self.overlays[self.action_set][
                self.instance._action][res_id]
        except KeyError:
            self.log.warning(
                'No overlays defined for resource `%s`, action `%s` and action set `%s`. '
                'Consider using `null` overlays for amount 0 in this action set.',
                res_id, self.instance._action, self.action_set)
            self.current_overlays[res_id] = None
            return

        # We use max(0, new_amount) restricted to what exists in overlay_order.
        # E.g. for
        #   new_amount = 3
        #   overlay_order = [[0, None],  [2, 'as_2'],  [5, 'as_full']]
        # we drop 5 (because it is defined but too large),
        # ignore 4 and 3 (because they are not defined in overlay_order),
        # and find 'as_2' as our new overlay for the amount 2.

        for (amount, overlay_name) in sorted(overlay_order, reverse=True):

            if amount > new_amount:
                # This `if` drops defined-but-too-large candidates (i.e. case `5` in above example).
                continue

            if amount == self.current_overlays[res_id]:
                # Nothing to do, continue using the same overlay
                return

            if overlay_name is None:
                # Empty overlay, only display base action set (i.e. case `0` in above example)
                self.remove_overlay(res_id)
                return

            try:
                overlay_set = ActionSetLoader.get_set(
                    self.action_set)[overlay_name]
            except KeyError:
                self.log.warning(
                    'Could not find overlay action set defined for object '
                    '`%s` with id `%s` for resource `%s` and amount `%s`. '
                    'Falling back to next lower overlay.', self.instance,
                    self.identifier, res_id, amount)
                continue
            self.remove_overlay(res_id)
            self.add_overlay(overlay_set, z_order=res_id)
            self.current_overlays[res_id] = amount
            return
    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

        width, length = cls.size
        if rotation == 135 or rotation == 315:
            # if you look at a non-square builing from a 45 degree angle it looks
            # different than from a 135 degree angle
            # when you rotate it the width becomes the length and the length becomes the width
            width, length = length, width

        # the drawing origin is the center of it's area, minus 0.5
        # the 0.5 isn't really necessary, but other code is aligned with the 0.5 shift
        # this is at least for the gridoverlay, and the location of a build preview relative to the mouse
        # it this is changed, it should also be changed for ground tiles (world/ground.py) and units
        instance_coords = [x + width / 2 - 0.5, y + length / 2 - 0.5, 0]

        instance = session.view.layers[cls.layer].createInstance(
            cls._fife_object, fife.ExactModelCoordinate(*instance_coords),
            world_id)

        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]
        instance.actRepeat("{}_{}".format(action, action_set_id), rotation)
        return (instance, action_set_id)
	def update_overlay(self, res_id, new_amount):
		"""Called when inventory amount of one resource changes.

		Looks for a fitting animation overlay based on the new inventory amount for that resource.
		If that overlay is different from the currently displayed one, removes the old overlay for
		that resource and adds a new one based on what fits *new_amount* best.
		"""
		try:
			overlay_order = self.overlays[self.action_set][self.instance._action][res_id]
		except KeyError:
			self.log.warning(
				'No overlays defined for resource `%s`, action `%s` and action set `%s`. '
				'Consider using `null` overlays for amount 0 in this action set.',
				res_id, self.instance._action, self.action_set)
			self.current_overlays[res_id] = None
			return

		# We use max(0, new_amount) restricted to what exists in overlay_order.
		# E.g. for
		#   new_amount = 3
		#   overlay_order = [[0, None],  [2, 'as_2'],  [5, 'as_full']]
		# we drop 5 (because it is defined but too large),
		# ignore 4 and 3 (because they are not defined in overlay_order),
		# and find 'as_2' as our new overlay for the amount 2.

		for (amount, overlay_name) in sorted(overlay_order, reverse=True):

			if amount > new_amount:
				# This `if` drops defined-but-too-large candidates (i.e. case `5` in above example).
				continue

			if amount == self.current_overlays[res_id]:
				# Nothing to do, continue using the same overlay
				return

			if overlay_name is None:
				# Empty overlay, only display base action set (i.e. case `0` in above example)
				self.remove_overlay(res_id)
				return

			try:
				overlay_set = ActionSetLoader.get_set(self.action_set)[overlay_name]
			except KeyError:
				self.log.warning(
					'Could not find overlay action set defined for object '
					'`%s` with id `%s` for resource `%s` and amount `%s`. '
					'Falling back to next lower overlay.',
					self.instance, self.identifier, res_id, amount)
				continue
			self.remove_overlay(res_id)
			self.add_overlay(overlay_set, z_order=res_id)
			self.current_overlays[res_id] = amount
			return
Exemple #9
0
    def init_widget(self):
        super(SettlerOverviewTab, self).init_widget()
        name = self.instance.settlement.get_component(NamedComponent).name
        self.widget.findChild(name="headline").text = name
        setup_tax_slider(self.widget.child_finder('tax_slider'),
                         self.widget.child_finder('tax_val_label'),
                         self.instance.settlement, self.instance.level)

        taxes = self.instance.settlement.tax_settings[self.instance.level]
        self.widget.child_finder('tax_val_label').text = unicode(taxes)
        action_set = ActionSetLoader.get_set(self.instance._action_set_id)
        action_gfx = action_set.items()[0][1]
        image = action_gfx[45].keys()[0]
        self.widget.findChild(name="building_image").image = image
	def init_widget(self):
		super().init_widget()
		name = self.instance.settlement.get_component(NamedComponent).name
		self.widget.findChild(name="headline").text = name
		setup_tax_slider(self.widget.child_finder('tax_slider'),
		                 self.widget.child_finder('tax_val_label'),
		                 self.instance.settlement,
		                 self.instance.level)

		taxes = self.instance.settlement.tax_settings[self.instance.level]
		self.widget.child_finder('tax_val_label').text = str(taxes)
		action_set = ActionSetLoader.get_set(self.instance._action_set_id)
		action_gfx = list(action_set.items())[0][1]
		image = list(action_gfx[45].keys())[0]
		self.widget.findChild(name="building_image").image = image
    def add_overlay(self, overlay_name, z_order):
        """Creates color overlay recoloring the area defined in *overlay_set*

		and adds it to fife instance. Note that a color overlay on *z_order*
		can only be visible if an animation overlay with that specific order
		exists as well. For order 0, `convertToOverlays()` makes sure they do.
		"""
        if not self.fife_instance.isAnimationOverlay(self.identifier):
            # parameter False: do not convert color overlays attached to base
            self.fife_instance.convertToOverlays(self.identifier, False)

        try:
            overlay_set = ActionSetLoader.get_set(
                self.action_set)[overlay_name]
        except KeyError:
            self.log.warning(
                'Could not find overlay action set `%s` defined for object '
                '`%s` with id `%s`. Not adding overlay for this action.',
                overlay_name, self.instance, self.identifier)
            return

        animationmanager = horizons.globals.fife.animationmanager
        self.current_overlays[z_order] = overlay_set
        for rotation, frames in overlay_set.items():
            id = '{}+{}'.format(self.identifier, rotation)
            if animationmanager.exists(id):
                ov_anim = animationmanager.getPtr(id)
            else:
                ov_anim = animationmanager.create(id)
                for frame_img, frame_data in frames.items():
                    try:
                        frame_length = frame_data[0]
                    except TypeError:
                        # not using atlases
                        frame_length = frame_data
                    pic = horizons.globals.fife.animationloader.load_image(
                        frame_img, self.action_set, overlay_name, rotation)
                    frame_milliseconds = int(frame_length * 1000)
                    ov_anim.addFrame(pic, frame_milliseconds)
            overlay = fife.OverlayColors(ov_anim)
            self.fife_instance.addColorOverlay(self.identifier, rotation,
                                               z_order, overlay)
 def init_widget(self):
     super(SignalFireOverviewTab, self).init_widget()
     action_set = ActionSetLoader.get_set(self.instance._action_set_id)
     action_gfx = action_set.items()[0][1]
     image = action_gfx[45].keys()[0]
     self.widget.findChild(name="building_image").image = image
Exemple #13
0
    def has_action(self, action):
        """Checks if this unit has a certain action.
		@param action: animation id as string"""
        return (action in ActionSetLoader.get_set(self._action_set_id))
 def init_widget(self):
     super(SignalFireOverviewTab, self).init_widget()
     action_set = ActionSetLoader.get_set(self.instance._action_set_id)
     action_gfx = list(action_set.items())[0][1]
     image = list(action_gfx[45].keys())[0]
     self.widget.findChild(name="building_image").image = image
Exemple #15
0
	def has_action(self, action):
		"""Checks if this unit has a certain action.
		@param action: animation id as string"""
		return (action in ActionSetLoader.get_set(self._action_set_id))
Exemple #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]

		instance.actRepeat(action + "_" + str(action_set_id), facing_loc)
		return (instance, action_set_id)
Exemple #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_set = ActionSetLoader.get_set(action_set_id)
		if not action in action_set:
			if 'idle' in action_set:
				action = 'idle'
			elif 'idle_full' in action_set:
				action = 'idle_full'
			else:
				# set first action
				action = 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)