123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476 |
- # coding: utf-8
- import time
- import typing
-
- from synergine2.simulation import SubjectBehaviour
- from synergine2.simulation import SubjectMechanism
- from synergine2.simulation import Event
- from synergine2_xyz.move.intention import MoveToIntention
- from synergine2_xyz.simulation import XYZSimulation
- from synergine2_xyz.utils import get_angle
- from synergine2.simulation import disable_when
- from synergine2.simulation import config_value
-
- from opencombat.const import COLLECTION_ALIVE
- from opencombat.user_action import UserAction
-
-
- class SubjectStartRotationEvent(Event):
- def __init__(
- self,
- subject_id: int,
- rotate_relative: float,
- rotate_absolute: float,
- duration: float,
- gui_action: UserAction,
- ) -> None:
- self.subject_id = subject_id
- self.rotate_relative = rotate_relative
- self.rotate_absolute = rotate_absolute
- self.duration = duration
- self.gui_action = gui_action
-
-
- class SubjectContinueRotationEvent(Event):
- def __init__(
- self,
- subject_id: int,
- rotate_relative: float,
- duration: float,
- gui_action: UserAction,
- ) -> None:
- self.subject_id = subject_id
- self.rotate_relative = rotate_relative
- self.duration = duration
- self.gui_action = gui_action
-
-
- class SubjectFinishRotationEvent(Event):
- def __init__(
- self,
- subject_id: int,
- rotation_absolute: float,
- gui_action: UserAction,
- ) -> None:
- self.subject_id = subject_id
- self.rotation_absolute = rotation_absolute
- self.gui_action = gui_action
-
-
- class SubjectStartTileMoveEvent(Event):
- def __init__(
- self,
- subject_id: int,
- move_to: typing.Tuple[int, int],
- duration: float,
- gui_action: UserAction,
- ) -> None:
- self.subject_id = subject_id
- self.move_to = move_to
- self.duration = duration
- self.gui_action = gui_action
-
-
- class SubjectContinueTileMoveEvent(Event):
- def __init__(
- self,
- subject_id: int,
- move_to: typing.Tuple[int, int],
- duration: float,
- gui_action: UserAction,
- ) -> None:
- self.subject_id = subject_id
- self.move_to = move_to
- self.duration = duration
- self.gui_action = gui_action
-
-
- class SubjectFinishTileMoveEvent(Event):
- def __init__(
- self,
- subject_id: int,
- move_to: typing.Tuple[int, int],
- gui_action: UserAction,
- ) -> None:
- self.subject_id = subject_id
- self.move_to = move_to
- self.gui_action = gui_action
-
-
- class SubjectFinishMoveEvent(Event):
- def __init__(
- self,
- subject_id: int,
- move_to: typing.Tuple[int, int],
- gui_action: UserAction,
- ) -> None:
- self.subject_id = subject_id
- self.move_to = move_to
- self.gui_action = gui_action
-
-
- class MoveToMechanism(SubjectMechanism):
- @disable_when(config_value('_runtime.placement_mode'))
- def run(self) -> dict:
- try:
- # TODO: MoveToIntention doit être configurable
- move = self.subject.intentions.get(MoveToIntention) # type: MoveToIntention
- except KeyError:
- return {}
-
- if COLLECTION_ALIVE not in self.subject.collections:
- return {}
-
- return move.get_data()
-
-
- class MoveWithRotationBehaviour(SubjectBehaviour):
- use = [MoveToMechanism]
-
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
- self.simulation = typing.cast(XYZSimulation, self.simulation)
-
- @disable_when(config_value('_runtime.placement_mode'))
- def run(self, data) -> object:
- """
- Compute data relative to move
- """
- data = data[MoveToMechanism]
- if not data:
- return False
-
- # Prepare data
- to = data['to'] # type: typing.Tuple(int, int)
- return_data = {}
- now = time.time()
-
- # Test if it's first time
- if not data.get('path'):
- return_data['path'] = self.simulation.physics.found_path(
- start=self.subject.position,
- end=to,
- subject=self.subject,
- )
- # find path algorithm can skip start position, add it if not in
- if return_data['path'][0] != self.subject.position:
- return_data['path'] = [self.subject.position] + return_data['path']
- data['path'] = return_data['path']
-
- # Prepare data
- path = data['path'] # type: typing.List[typing.Tuple(int, int)]
- path_index = path.index(self.subject.position)
- next_position = path[path_index + 1]
- next_position_direction = get_angle(self.subject.position, next_position)
- rotate_relative = next_position_direction - self.subject.direction
-
- # Test if finish move
- if path_index == len(path) - 1:
- return {
- 'move_to_finished': to,
- 'gui_action': data['gui_action'],
- }
-
- # Check if moving
- if self.subject.moving_to == next_position:
- if self.subject.start_move + self.subject.move_duration > now:
- # Let moving
- return {
- 'tile_move_to': next_position,
- 'gui_action': data['gui_action'],
- }
- return_data['tile_move_to_finished'] = self.subject.moving_to
- # Must consider new position of subject
- path_index = path.index(return_data['tile_move_to_finished'])
- if path_index == len(path) - 1:
- return {
- 'move_to_finished': to,
- 'gui_action': data['gui_action'],
- }
- next_position = path[path_index + 1]
- next_position_direction = get_angle(
- return_data['tile_move_to_finished'],
- next_position,
- )
- rotate_relative = next_position_direction - self.subject.direction
-
- # Check if rotating
- if self.subject.rotate_to != -1:
- # If it is not finished
- if self.subject.start_rotation + self.subject.rotate_duration > now:
- # Let rotation do it's job
- return {
- 'rotate_relative': rotate_relative,
- 'rotate_absolute': next_position_direction,
- 'gui_action': data['gui_action'],
- }
- # rotation finish
- return_data['rotate_to_finished'] = self.subject.rotate_to
-
- # Check if need to rotate
- if not return_data.get('rotate_to_finished') \
- and self.subject.direction != next_position_direction:
- return_data.update({
- 'rotate_relative': rotate_relative,
- 'rotate_absolute': next_position_direction,
- 'gui_action': data['gui_action'],
- })
- return return_data
-
- # Need to move to next tile
- return_data['tile_move_to'] = next_position
- return_data['gui_action'] = data['gui_action']
- return return_data
-
- def action(self, data) -> [Event]:
- events = []
- now = time.time()
-
- if data.get('path'):
- move = self.subject.intentions.get(MoveToIntention)
- move.path = data['path']
- self.subject.intentions.set(move)
-
- if data.get('tile_move_to_finished'):
- self.subject.position = data['tile_move_to_finished']
- self.subject.moving_to = (-1, -1)
- self.subject.start_move = -1
- self.subject.move_duration = -1
- events.append(SubjectFinishTileMoveEvent(
- subject_id=self.subject.id,
- move_to=data['tile_move_to_finished'],
- gui_action=data['gui_action'],
- ))
-
- if data.get('move_to_finished'):
- self.subject.position = data['move_to_finished']
- self.subject.moving_to = (-1, -1)
- self.subject.start_move = -1
- self.subject.move_duration = -1
- self.subject.intentions.remove(MoveToIntention)
- events.append(SubjectFinishMoveEvent(
- subject_id=self.subject.id,
- move_to=data['move_to_finished'],
- gui_action=data['gui_action'],
- ))
-
- if data.get('rotate_to_finished'):
- self.subject.rotate_to = -1
- self.subject.rotate_duration = -1
- self.subject.start_rotation = -1
- self.subject.direction = data['rotate_to_finished']
-
- events.append(SubjectFinishRotationEvent(
- subject_id=self.subject.id,
- rotation_absolute=data['rotate_to_finished'],
- gui_action=data['gui_action'],
- ))
-
- if data.get('rotate_relative'):
- # Test if rotation is already started
- if self.subject.rotate_to == data['rotate_absolute']:
- # look at progression
- rotate_since = now - self.subject.start_rotation
- rotate_progress = rotate_since / self.subject.rotate_duration
- rotation_to_do = self.subject.rotate_to - self.subject.direction # nopep8
- rotation_done = rotation_to_do * rotate_progress
- self.subject.direction = self.subject.direction + rotation_done
- rotation_left = self.subject.rotate_to - self.subject.direction
- duration = abs(self.subject.get_rotate_duration(
- angle=rotation_left,
- ))
- self.subject.rotate_duration = duration
- self.subject.start_rotation = now
-
- return [SubjectContinueRotationEvent(
- subject_id=self.subject.id,
- rotate_relative=rotation_left,
- duration=duration,
- gui_action=data['gui_action'],
- )]
- else:
- duration = abs(self.subject.get_rotate_duration(
- angle=data['rotate_relative'],
- ))
- self.subject.rotate_to = data['rotate_absolute']
- self.subject.rotate_duration = duration
- self.subject.start_rotation = time.time()
-
- events.append(SubjectStartRotationEvent(
- subject_id=self.subject.id,
- rotate_relative=data['rotate_relative'],
- rotate_absolute=data['rotate_absolute'],
- duration=duration,
- gui_action=data['gui_action'],
- ))
-
- if data.get('tile_move_to'):
- # It is already moving ?
- if self.subject.moving_to == data.get('tile_move_to'):
- # look at progression
- move_since = now - self.subject.start_move
- move_progress = move_since / self.subject.move_duration
- move_done = self.subject.move_duration * move_progress
- duration = self.subject.move_duration - move_done
- self.subject.move_duration = duration
-
- return [SubjectContinueTileMoveEvent(
- subject_id=self.subject.id,
- move_to=data['tile_move_to'],
- duration=duration,
- gui_action=data['gui_action'],
- )]
- else:
- move = self.subject.intentions.get(MoveToIntention)
- move_type_duration = self.subject.get_move_duration(move)
- # FIXME: duration depend next tile type, etc
- # see opencombat.gui.base.Game#start_move_subject
- duration = move_type_duration * 1
- self.subject.moving_to = data['tile_move_to']
- self.subject.move_duration = duration
- self.subject.start_move = time.time()
- events.append(SubjectStartTileMoveEvent(
- subject_id=self.subject.id,
- move_to=data['tile_move_to'],
- duration=duration,
- gui_action=data['gui_action'],
- ))
-
- return events
-
-
- class MoveBehaviour(SubjectBehaviour):
- use = [MoveToMechanism]
-
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
- self.simulation = typing.cast(XYZSimulation, self.simulation)
-
- @disable_when(config_value('_runtime.placement_mode'))
- def run(self, data) -> object:
- """
- Compute data relative to move
- """
- data = data[MoveToMechanism]
- if not data:
- return False
-
- # Prepare data
- to = data['to'] # type: typing.Tuple(int, int)
- return_data = {}
- now = time.time()
-
- # Test if it's first time
- if not data.get('path'):
- return_data['path'] = self.simulation.physics.found_path(
- start=self.subject.position,
- end=to,
- subject=self.subject,
- )
- # find path algorithm can skip start position, add it if not in
- if return_data['path'][0] != self.subject.position:
- return_data['path'] = [self.subject.position] + return_data['path']
- data['path'] = return_data['path']
-
- # Prepare data
- path = data['path'] # type: typing.List[typing.Tuple(int, int)]
- path_index = path.index(self.subject.position)
- next_position = path[path_index + 1]
-
- # Test if finish move
- if path_index == len(path) - 1:
- return {
- 'move_to_finished': to,
- 'gui_action': data['gui_action'],
- }
-
- # Check if moving
- if self.subject.moving_to == next_position:
- if self.subject.start_move + self.subject.move_duration > now:
- # Let moving
- return {
- 'tile_move_to': next_position,
- 'gui_action': data['gui_action'],
- }
- return_data['tile_move_to_finished'] = self.subject.moving_to
- # Must consider new position of subject
- path_index = path.index(return_data['tile_move_to_finished'])
- if path_index == len(path) - 1:
- return {
- 'move_to_finished': to,
- 'gui_action': data['gui_action'],
- }
- next_position = path[path_index + 1]
-
- # Need to move to next tile
- return_data['tile_move_to'] = next_position
- return_data['gui_action'] = data['gui_action']
- return return_data
-
- def action(self, data) -> [Event]:
- events = []
- now = time.time()
-
- if data.get('path'):
- move = self.subject.intentions.get(MoveToIntention)
- move.path = data['path']
- self.subject.intentions.set(move)
-
- if data.get('tile_move_to_finished'):
- self.subject.position = data['tile_move_to_finished']
- self.subject.moving_to = (-1, -1)
- self.subject.start_move = -1
- self.subject.move_duration = -1
- events.append(SubjectFinishTileMoveEvent(
- subject_id=self.subject.id,
- move_to=data['tile_move_to_finished'],
- gui_action=data['gui_action'],
- ))
-
- if data.get('move_to_finished'):
- self.subject.position = data['move_to_finished']
- self.subject.moving_to = (-1, -1)
- self.subject.start_move = -1
- self.subject.move_duration = -1
- self.subject.intentions.remove(MoveToIntention)
- events.append(SubjectFinishMoveEvent(
- subject_id=self.subject.id,
- move_to=data['move_to_finished'],
- gui_action=data['gui_action'],
- ))
-
- if data.get('tile_move_to'):
- # It is already moving ?
- if self.subject.moving_to == data.get('tile_move_to'):
- # look at progression
- move_since = now - self.subject.start_move
- move_progress = move_since / self.subject.move_duration
- move_done = self.subject.move_duration * move_progress
- duration = self.subject.move_duration - move_done
- self.subject.move_duration = duration
- self.subject.start_move = time.time()
-
- return [SubjectContinueTileMoveEvent(
- subject_id=self.subject.id,
- move_to=data['tile_move_to'],
- duration=duration,
- gui_action=data['gui_action'],
- )]
- else:
- move = self.subject.intentions.get(MoveToIntention)
- move_type_duration = self.subject.get_move_duration(move)
- # FIXME: duration depend next tile type, etc
- # see opencombat.gui.base.Game#start_move_subject
- duration = move_type_duration * 1
- self.subject.moving_to = data['tile_move_to']
- self.subject.move_duration = duration
- self.subject.start_move = time.time()
- events.append(SubjectStartTileMoveEvent(
- subject_id=self.subject.id,
- move_to=data['tile_move_to'],
- duration=duration,
- gui_action=data['gui_action'],
- ))
-
- return events
|