from __future__ import annotations
import logging
import random
import scripts.engine.core.matter
from scripts.engine.core import hourglass, world
from scripts.engine.core.component import Knowledge, Position
from scripts.engine.internal import library
from scripts.engine.internal.action import Behaviour
from scripts.engine.internal.constant import Direction, TileTag
[docs]class SkipTurn(Behaviour):
"""
Just skips turn
"""
[docs] def act(self):
name = scripts.engine.core.matter.get_name(self.entity)
logging.debug(f"'{name}' skipped their turn.")
hourglass.end_turn(self.entity, library.GAME_CONFIG.default_values.move_cost)
[docs]class FollowPlayer(Behaviour):
"""
Basic AI to follow the player
"""
[docs] def act(self):
entity = self.entity
# get position info
pos = scripts.engine.core.matter.get_entitys_component(entity, Position)
player = scripts.engine.core.matter.get_player()
player_pos = scripts.engine.core.matter.get_entitys_component(player, Position)
# get move direction
move_dir = world.get_a_star_direction((pos.x, pos.y), (player_pos.x, player_pos.y))
# get info for skill
move = scripts.engine.core.matter.get_known_skill(entity, "Move")
target_tile = world.get_tile((pos.x, pos.y))
name = scripts.engine.core.matter.get_name(entity)
# attempt to use skill
if scripts.engine.core.matter.can_use_skill(entity, "Move"):
scripts.engine.core.matter.use_skill(entity, move, target_tile, move_dir)
logging.debug(f"'{name}' moved to ({pos.x},{pos.y}).")
else:
logging.debug(f"'{name}' tried to move to ({pos.x},{pos.y}), but couldn`t.")
hourglass.end_turn(entity, library.GAME_CONFIG.default_values.move_cost)
[docs]class SearchAndAttack(Behaviour):
"""
Search and attack the player
"""
[docs] def act(self):
entity = self.entity
pos = scripts.engine.core.matter.get_entitys_component(entity, Position)
target = scripts.engine.core.matter.choose_target(entity)
# if we have no target move in random direction
if not target:
self._move_randomly()
return # exit
target_pos = scripts.engine.core.matter.get_entitys_component(target, Position)
# what skills are ready to use?
possible_skills = []
knowledge = scripts.engine.core.matter.get_entitys_component(entity, Knowledge)
for skill in knowledge.skills.values():
if scripts.engine.core.matter.can_use_skill(entity, skill.name) and skill.name != "Move":
possible_skills.append(skill)
# where can we cast from?
skill_cast_positions = world.get_cast_positions(entity, target_pos, possible_skills)
# are we currently on a cast position?
skills_can_cast = []
for skill, cast_positions in skill_cast_positions.items():
if (pos.x, pos.y) in cast_positions:
skills_can_cast.append(skill)
# if we can cast a skill now then pick one at random and cast
if skills_can_cast:
# get target tile
skill_dir = world.get_direction((pos.x, pos.y), (target_pos.x, target_pos.y))
target_tile = world.get_tile((pos.x + skill_dir[0], pos.y + skill_dir[1]))
# set skill to cast
skill_to_cast = random.choice(skills_can_cast)
# cast whatever skill has been chosen
scripts.engine.core.matter.use_skill(entity, skill_to_cast, target_tile, skill_dir)
logging.debug(
f"'{scripts.engine.core.matter.get_name(entity)}' cast {skill_to_cast.name} from ({pos.x},"
f"{pos.y}) towards ({pos.x + skill_dir[0]},{pos.y + skill_dir[1]}), with range "
f"{skill_to_cast.range}."
)
# end turn
hourglass.end_turn(entity, skill_to_cast.time_cost)
# we cant cast, find nearest cast_position
else:
# add all possible positions to pathfinder
pathfinder = scripts.engine.core.matter.create_pathfinder()
for cast_positions in skill_cast_positions.values():
for cast_pos in cast_positions:
pathfinder.add_root(cast_pos)
# get nearest location
path = pathfinder.path_from((pos.x, pos.y))[1:].tolist() # slice out starting pos
assert isinstance(path, list)
# check is path has any value - there might not have been any valid cast positions
if path:
nearest_pos = path[0]
# get target tile
skill_dir = world.get_a_star_direction((pos.x, pos.y), (nearest_pos[0], nearest_pos[1]))
target_tile = world.get_tile((pos.x, pos.y)) # target tile for Move is current pos
# set skill to cast to move
skill_to_cast = knowledge.skills["Move"]
# cast whatever skill has been chosen
scripts.engine.core.matter.use_skill(entity, skill_to_cast, target_tile, skill_dir)
logging.debug(
f"'{scripts.engine.core.matter.get_name(entity)}' moved towards a cast position, from ({pos.x},"
f"{pos.y}) to ({pos.x + skill_dir[0]},{pos.y + skill_dir[1]})."
)
# end turn
hourglass.end_turn(entity, skill_to_cast.time_cost)
else:
# no valid cast position, just wander
self._move_randomly()
[docs] def _move_randomly(self):
"""
Move self in random direction. End turn, whether moved or not.
"""
entity = self.entity
pos = scripts.engine.core.matter.get_entitys_component(entity, Position)
knowledge = scripts.engine.core.matter.get_entitys_component(entity, Knowledge)
move = knowledge.skills["Move"]
cardinals = [Direction.UP, Direction.DOWN, Direction.LEFT, Direction.RIGHT]
# check spaces are free
poss_directions = []
for _dir in cardinals:
x = pos.x + _dir[0]
y = pos.y + _dir[1]
tile = world.get_tile((x, y))
has_tags = world.tile_has_tag(entity, tile, TileTag.OPEN_SPACE)
if has_tags:
poss_directions.append((_dir[0], _dir[1]))
# if any space we can move to, do so
if poss_directions:
move_dir = random.choice(poss_directions)
target_tile = world.get_tile((pos.x, pos.y)) # target tile for Move is current pos
scripts.engine.core.matter.use_skill(entity, move, target_tile, move_dir)
logging.debug(
f"'{scripts.engine.core.matter.get_name(entity)}' couldnt see a target so moved randomly from ({pos.x},"
f"{pos.y}) to ({pos.x + move_dir[0]},{pos.y + move_dir[1]})."
)
hourglass.end_turn(entity, move.time_cost)