예제 #1
0
	def load(self, db, worldid):
		super(Ship, self).load(db, worldid)
		self.__init()

		# if ship did not have route configured, do not add attribute
		if TradeRoute.has_route(db, worldid):
			self.create_route()
			self.route.load(db)
예제 #2
0
	def load(self, db, worldid):
		super(Ship, self).load(db, worldid)
		self.__init()

		# if ship did not have route configured, do not add attribute
		if TradeRoute.has_route(db, worldid):
			self.create_route()
			self.route.load(db)
예제 #3
0
	def create_route(self):
		self.route = TradeRoute(self)
예제 #4
0
class Ship(Unit):
	"""Class representing a ship
	@param x: int x position
	@param y: int y position
	"""
	pather_class = ShipPather
	health_bar_y = -150
	is_ship = True

	in_ship_map = True # (#1023)

	def __init__(self, x, y, **kwargs):
		super(Ship, self).__init__(x=x, y=y, **kwargs)
		self.__init()

	def save(self, db):
		super(Ship, self).save(db)
		if hasattr(self, 'route'):
			self.route.save(db)

	def load(self, db, worldid):
		super(Ship, self).load(db, worldid)
		self.__init()

		# if ship did not have route configured, do not add attribute
		if TradeRoute.has_route(db, worldid):
			self.create_route()
			self.route.load(db)

	def __init(self):
		# register ship in world
		self.session.world.ships.append(self)
		if self.in_ship_map:
			self.session.world.ship_map[self.position.to_tuple()] = weakref.ref(self)

	def set_name(self, name):
		self.get_component(ShipNameComponent).set_name(name)

	def remove(self):
		self.session.world.ships.remove(self)
		self.session.view.discard_change_listener(self.draw_health)
		if self.in_ship_map:
			if self.position.to_tuple() in self.session.world.ship_map:
				del self.session.world.ship_map[self.position.to_tuple()]
			else:
				self.log.error("Ship %s had in_ship_map flag set as True "
				               "but tuple %s was not found in world.ship_map",
				               self, self.position.to_tuple())
			if self._next_target.to_tuple() in self.session.world.ship_map:
				del self.session.world.ship_map[self._next_target.to_tuple()]
			self.in_ship_map = False
		ShipDestroyed.broadcast(self)
		super(Ship, self).remove()

	def create_route(self):
		self.route = TradeRoute(self)

	def _move_tick(self, resume=False):
		"""Keeps track of the ship's position in the global ship_map"""

		# TODO: Originally, only self.in_ship_map should suffice here,
		# but KeyError is raised during combat.
		if self.in_ship_map and self.position.to_tuple() in self.session.world.ship_map:
			del self.session.world.ship_map[self.position.to_tuple()]
		elif self.in_ship_map:  # logging purposes only
			self.log.error("Ship %s had in_ship_map flag set as True but tuple %s was "
			               "not found in world.ship_map", self, self.position.to_tuple())

		try:
			super(Ship, self)._move_tick(resume)
		except PathBlockedError:
			# if we fail to resume movement then the ship should still be on the map
			# but the exception has to be raised again.
			if resume:
				if self.in_ship_map:
					self.session.world.ship_map[self.position.to_tuple()] = weakref.ref(self)
				raise

		if self.in_ship_map:
			# save current and next position for ship, since it will be between them
			self.session.world.ship_map[self.position.to_tuple()] = weakref.ref(self)
			self.session.world.ship_map[self._next_target.to_tuple()] = weakref.ref(self)

	def _movement_finished(self):
		if self.in_ship_map:
			# if the movement somehow stops, the position sticks, and the unit isn't at next_target any more
			if self._next_target is not None:
				ship = self.session.world.ship_map.get(self._next_target.to_tuple())
				if ship is not None and ship() is self:
					del self.session.world.ship_map[self._next_target.to_tuple()]
		super(Ship, self)._movement_finished()

	def go(self, x, y):
		# Disable trade route, direct commands overwrite automated ones.
		if hasattr(self, 'route'):
			self.route.disable()
		if self.get_component(CommandableComponent).go(x, y) is None:
			self._update_buoy()

	def move(self, *args, **kwargs):
		super(Ship, self).move(*args, **kwargs)
		if self.has_component(SelectableComponent) and \
		   self.get_component(SelectableComponent).selected and \
		   self.owner.is_local_player: # handle buoy
			# if move() is called as move_callback, tmp() from above might
			# be executed after this, so draw the new buoy after move_callbacks have finished.
			Scheduler().add_new_object(self._update_buoy, self, run_in=0)

	def _update_buoy(self, remove_only=False):
		"""Draw a buoy at the move target if the ship is moving."""
		if self.owner is None or not self.owner.is_local_player:
			return
		move_target = self.get_move_target()

		ship_id = self.worldid
		session = self.session # this has to happen here,
		# cause a reference to self in a temporary function is implemented
		# as a hard reference, which causes a memory leak
		def tmp():
			session.view.renderer['GenericRenderer'].removeAll("buoy_" + str(ship_id))
		tmp() # also remove now

		if remove_only:
			return

		if move_target is not None:
			# set remove buoy callback
			self.add_move_callback(tmp)

			loc = fife.Location(self.session.view.layers[LAYERS.OBJECTS])
			loc.thisown = 0  # thisown = 0 because the genericrenderernode might delete it
			coords = fife.ModelCoordinate(move_target.x, move_target.y)
			coords.thisown = 1 # thisown = 1 because setLayerCoordinates will create a copy
			loc.setLayerCoordinates(coords)
			self.session.view.renderer['GenericRenderer'].addAnimation(
				"buoy_" + str(self.worldid), fife.RendererNode(loc),
				horizons.globals.fife.animationloader.loadResource("as_buoy0+idle+45")
			)

	def find_nearby_ships(self, radius=15):
		# TODO: Replace 15 with a distance dependent on the ship type and any
		# other conditions.
		ships = self.session.world.get_ships(self.position, radius)
		if self in ships:
			ships.remove(self)
		return ships

	def get_tradeable_warehouses(self, position=None):
		"""Returns warehouses this ship can trade with w.r.t. position, which defaults to the ships ones."""
		if position is None:
			position = self.position
		return self.session.world.get_warehouses(position, self.radius, self.owner,
		                                         include_tradeable=True)

	def get_location_based_status(self, position):
		warehouses = self.get_tradeable_warehouses(position)
		if warehouses:
			warehouse = warehouses[0] # TODO: don't ignore the other possibilities
			player_suffix = ''
			if warehouse.owner is not self.owner:
				player_suffix = ' ({name})'.format(name=warehouse.owner.name)
			return '{name}{suffix}'.format(name=warehouse.settlement.get_component(NamedComponent).name,
			                                suffix=player_suffix)
		return None

	def get_status(self):
		"""Return the current status of the ship."""
		if hasattr(self, 'route') and self.route.enabled:
			return self.route.get_ship_status()
		elif self.is_moving():
			target = self.get_move_target()
			location_based_status = self.get_location_based_status(target)
			if location_based_status is not None:
				return (T('Going to {location}').format(location=location_based_status), target)
			return (T('Going to {x}, {y}').format(x=target.x, y=target.y), target)
		else:
			location_based_status = self.get_location_based_status(self.position)
			if location_based_status is not None:
				return (T('Idle at {location}').format(location=location_based_status), self.position)
			return (T('Idle at {x}, {y}').format(x=self.position.x, y=self.position.y), self.position)
예제 #5
0
	def create_route(self):
		self.route = TradeRoute(self)
예제 #6
0
class Ship(Unit):
	"""Class representing a ship
	@param x: int x position
	@param y: int y position
	"""
	pather_class = ShipPather
	health_bar_y = -150
	is_ship = True

	in_ship_map = True # (#1023)

	def __init__(self, x, y, **kwargs):
		super(Ship, self).__init__(x=x, y=y, **kwargs)
		self.__init()

	def save(self, db):
		super(Ship, self).save(db)
		if hasattr(self, 'route'):
			self.route.save(db)

	def load(self, db, worldid):
		super(Ship, self).load(db, worldid)
		self.__init()

		# if ship did not have route configured, do not add attribute
		if TradeRoute.has_route(db, worldid):
			self.create_route()
			self.route.load(db)

	def __init(self):
		# register ship in world
		self.session.world.ships.append(self)
		if self.in_ship_map:
			self.session.world.ship_map[self.position.to_tuple()] = weakref.ref(self)

	def set_name(self, name):
		self.get_component(ShipNameComponent).set_name(name)

	def remove(self):
		self.session.world.ships.remove(self)
		if self.session.view.has_change_listener(self.draw_health):
			self.session.view.remove_change_listener(self.draw_health)
		if self.in_ship_map:
			del self.session.world.ship_map[self.position.to_tuple()]
			if self._next_target.to_tuple() in self.session.world.ship_map:
				del self.session.world.ship_map[self._next_target.to_tuple()]
			self.in_ship_map = False
		super(Ship, self).remove()

	def create_route(self):
		self.route = TradeRoute(self)

	def _move_tick(self, resume = False):
		"""Keeps track of the ship's position in the global ship_map"""
		if self.in_ship_map:
			del self.session.world.ship_map[self.position.to_tuple()]

		try:
			super(Ship, self)._move_tick(resume)
		except PathBlockedError:
			# if we fail to resume movement then the ship should still be on the map but the exception has to be raised again.
			if resume:
				if self.in_ship_map:
					self.session.world.ship_map[self.position.to_tuple()] = weakref.ref(self)
				raise

		if self.in_ship_map:
			# save current and next position for ship, since it will be between them
			self.session.world.ship_map[self.position.to_tuple()] = weakref.ref(self)
			self.session.world.ship_map[self._next_target.to_tuple()] = weakref.ref(self)

	def _movement_finished(self):
		if self.in_ship_map:
			# if the movement somehow stops, the position sticks, and the unit isn't at next_target any more
			if self._next_target is not None:
				ship = self.session.world.ship_map.get(self._next_target.to_tuple())
				if ship is not None and ship() is self:
					del self.session.world.ship_map[self._next_target.to_tuple()]
		super(Ship, self)._movement_finished()

	def go(self, x, y):
		#disable the trading route
		if hasattr(self, 'route'):
			self.route.disable()
		if self.get_component(CommandableComponent).go(x, y) is None:
			self._update_buoy()

	def move(self, *args, **kwargs):
		super(Ship, self).move(*args, **kwargs)
		if self.has_component(SelectableComponent) and \
		   self.get_component(SelectableComponent).selected and \
		   self.owner.is_local_player: # handle buoy
			# if move() is called as move_callback, tmp() from above might
			# be executed after this, so draw the new buoy after move_callbacks have finished.
			Scheduler().add_new_object(self._update_buoy, self, run_in=0)

	def _update_buoy(self, remove_only=False):
		"""Draw a buoy at the move target if the ship is moving."""
		if self.owner is None or not self.owner.is_local_player:
			return
		move_target = self.get_move_target()

		ship_id = self.worldid
		session = self.session # this has to happen here,
		# cause a reference to self in a temporary function is implemented
		# as a hard reference, which causes a memory leak
		def tmp():
			session.view.renderer['GenericRenderer'].removeAll("buoy_" + str(ship_id))
		tmp() # also remove now

		if remove_only:
			return

		if move_target != None:
			# set remove buoy callback
			self.add_move_callback(tmp)

			loc = fife.Location(self.session.view.layers[LAYERS.OBJECTS])
			loc.thisown = 0  # thisown = 0 because the genericrenderernode might delete it
			coords = fife.ModelCoordinate(move_target.x, move_target.y)
			coords.thisown = 1 # thisown = 1 because setLayerCoordinates will create a copy
			loc.setLayerCoordinates(coords)
			self.session.view.renderer['GenericRenderer'].addAnimation(
				"buoy_" + str(self.worldid), fife.RendererNode(loc),
				horizons.main.fife.animationloader.loadResource("as_buoy0+idle+45")
			)

	def find_nearby_ships(self, radius=15):
		# TODO: Replace 15 with a distance dependant on the ship type and any
		# other conditions.
		ships = self.session.world.get_ships(self.position, radius)
		if self in ships:
			ships.remove(self)
		return ships

	def get_tradeable_warehouses(self, position=None):
		"""Returns warehouses this ship can trade with w.r.t. position, which defaults to the ships ones."""
		if position is None:
			position = self.position
		return self.session.world.get_warehouses(position, self.radius, self.owner, include_tradeable=True)

	def get_location_based_status(self, position):
		warehouses = self.get_tradeable_warehouses(position)
		if warehouses:
			warehouse = warehouses[0] # TODO: don't ignore the other possibilities
			player_suffix = u''
			if warehouse.owner is not self.owner:
				player_suffix = u' ({name})'.format(name=warehouse.owner.name)
			return u'{name}{suffix}'.format(name=warehouse.settlement.get_component(NamedComponent).name,
			                                suffix=player_suffix)
		return None

	def get_status(self):
		"""Return the current status of the ship."""
		if hasattr(self, 'route') and self.route.enabled:
			return self.route.get_ship_status()
		elif self.is_moving():
			target = self.get_move_target()
			location_based_status = self.get_location_based_status(target)
			if location_based_status is not None:
				#xgettext:python-format
				return (_('Going to {location}').format(location=location_based_status), target)
			#xgettext:python-format
			return (_('Going to {x}, {y}').format(x=target.x, y=target.y), target)
		else:
			location_based_status = self.get_location_based_status(self.position)
			if location_based_status is not None:
				#xgettext:python-format
				return (_('Idle at {location}').format(location=location_based_status), self.position)
			#xgettext:python-format
			return (_('Idle at {x}, {y}').format(x=self.position.x, y=self.position.y), self.position)