NotQuiteParadise2

Source code for nqp.command.basic_entity_behaviour

from __future__ import annotations

from typing import TYPE_CHECKING

import snecs
from snecs.typedefs import EntityID

from nqp.base_classes.entity_behaviour import EntityBehaviour
from nqp.command.unit import Unit
from nqp.core.constants import HealingSource, PATH_UPDATE_FREQ
from nqp.core.utility import distance_to
from nqp.world_elements.entity_components import Allegiance, HealReceived, IsDead, IsReadyToAttack, Position, Stats

if TYPE_CHECKING:
    from nqp.core.game import Game


__all__ = ["BasicEntityBehaviour"]


[docs]class BasicEntityBehaviour(EntityBehaviour):
[docs] def __init__(self, game: Game, unit: Unit, entity: EntityID): super().__init__(game, unit, entity)
[docs] def update(self, delta_time: float): self.last_path_update += delta_time if self.state == "path_fast": self.new_move_speed = 500 else: self.reset_move_speed = True # check for new orders if self.target_unit != self._unit.behaviour.target_unit: self.target_unit = self._unit.behaviour.target_unit self.update_target_entity() if self.target_entity: is_alive = not snecs.has_component(self.target_entity, IsDead) if (self.target_entity not in self._unit.behaviour.valid_targets) or (not is_alive): self.update_target_entity() self.determine_next_action(True) # update path if self.last_path_update > PATH_UPDATE_FREQ: self.update_path() # apply and reset regen, if needed if self.regen_timer < 0: self.apply_regen() self.regen_timer = 1 # update timers self.attack_timer -= delta_time self.regen_timer -= delta_time
[docs] def determine_next_action(self, focus_entity: bool): """ Determine what to do next, i.e. what state to transition into. If focus_entity is True then should a target position exist it will be overwritten by the target entity's position. """ stats = snecs.entity_component(self._entity, Stats) pos = snecs.entity_component(self._entity, Position) target_stats = snecs.entity_component(self.target_entity, Stats) # update target pos if focus_entity or self.target_position is None: target_pos = snecs.entity_component(self.target_entity, Position).pos self.target_position = target_pos else: target_pos = self.target_position # check distance to target if (stats.range.value + stats.size.value + target_stats.size.value < distance_to(pos.pos, target_pos)) or ( self._unit.behaviour.check_visibility and not self.visibility_line ): self.state = self.movement_mode else: self.state = "idle" # attack intent if ((not self._unit.behaviour.check_visibility) or self.visibility_line) and self.attack_timer <= 0: # ensure doesnt al ready have component if not snecs.has_component(self._entity, IsReadyToAttack): snecs.add_component(self._entity, IsReadyToAttack())
[docs] def update_path(self): """ Update pathing to target. """ # decrement timer self.last_path_update -= PATH_UPDATE_FREQ # check if can see target if self.target_entity: pos = snecs.entity_component(self._entity, Position) target_pos = snecs.entity_component(self.target_entity, Position) self.visibility_line = self._game.world.model.terrain.sight_line(pos.pos, target_pos.pos) else: self.visibility_line = False # if we cant see target, move somewhere new if not self.visibility_line: if self._unit.behaviour.smart_range_retarget: team = snecs.entity_component(self._entity, Allegiance).team stats = snecs.entity_component(self._entity, Stats) pos = snecs.entity_component(self._entity, Position) for entity in self._game.world.model.get_all_entities(): target_team = snecs.entity_component(entity, Allegiance).team # find entities on different team if target_team != team: target_pos = snecs.entity_component(self.target_entity, Position) target_stats = snecs.entity_component(entity, Stats) # check if in range if stats.range.value + stats.size.value + target_stats.size.value < distance_to( pos.pos, target_pos.pos ): # check target is visible if self._game.world.model.terrain.sight_line(target_pos.pos, pos.pos): # new target found, update info and stop searching self.target_entity = entity self.target_position = target_pos.pos break if self.state == "path" or self.state == "path_fast": if self._unit.behaviour.regrouping: self.target_position = self._unit.behaviour.leader.pos if self._unit.behaviour.retreating: self.target_position = list(self._unit.behaviour.retreat_target) if self.target_position: pos = snecs.entity_component(self._entity, Position) self.current_path = self._game.world.model.terrain.pathfind_px(pos.pos, self.target_position)
[docs] def apply_regen(self): """ Create heal component on entity """ stats = snecs.entity_component(self._entity, Stats) # try to apply try: snecs.add_component(self._entity, HealReceived(stats.regen.value, HealingSource.SELF)) except ValueError: heal_received = snecs.entity_component(self._entity, HealReceived) heal_received.add_heal(stats.regen.value, HealingSource.SELF)