behaviour.py 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. # coding: utf-8
  2. import random
  3. import time
  4. import typing
  5. from opencombat.const import COLLECTION_ALIVE
  6. from opencombat.simulation.base import AliveSubjectBehaviour
  7. from opencombat.simulation.event import NoLongerVisibleOpponent
  8. from opencombat.simulation.event import FireEvent
  9. from opencombat.simulation.event import DieEvent
  10. from opencombat.simulation.event import NewVisibleOpponent
  11. from opencombat.simulation.mechanism import OpponentVisibleMechanism
  12. from opencombat.user_action import UserAction
  13. from synergine2.simulation import Event
  14. from synergine2_xyz.move.simulation import MoveToBehaviour as BaseMoveToBehaviour
  15. class MoveToBehaviour(BaseMoveToBehaviour):
  16. def is_terminated(self) -> bool:
  17. return COLLECTION_ALIVE not in self.subject.collections
  18. def _can_move_to_next_step(self, move_to_data: dict) -> bool:
  19. if move_to_data['gui_action'] == UserAction.ORDER_MOVE:
  20. return time.time() - move_to_data['last_intention_time'] >= \
  21. self.subject.walk_duration
  22. if move_to_data['gui_action'] == UserAction.ORDER_MOVE_FAST:
  23. return time.time() - move_to_data['last_intention_time'] >= \
  24. self.subject.run_duration
  25. if move_to_data['gui_action'] == UserAction.ORDER_MOVE_CRAWL:
  26. return time.time() - move_to_data['last_intention_time'] >= \
  27. self.subject.crawl_duration
  28. raise NotImplementedError(
  29. 'Gui action {} unknown'.format(move_to_data['gui_action'])
  30. )
  31. def get_move_duration(self, move_to_data: dict) -> float:
  32. if move_to_data['gui_action'] == UserAction.ORDER_MOVE:
  33. return self.subject.walk_duration
  34. if move_to_data['gui_action'] == UserAction.ORDER_MOVE_FAST:
  35. return self.subject.run_duration
  36. if move_to_data['gui_action'] == UserAction.ORDER_MOVE_CRAWL:
  37. return self.subject.crawl_duration
  38. raise NotImplementedError(
  39. 'Gui action {} unknown'.format(move_to_data['gui_action'])
  40. )
  41. def finalize_event(self, move_to_data: dict, event: Event) -> None:
  42. event.move_duration = self.get_move_duration(move_to_data)
  43. class LookAroundBehaviour(AliveSubjectBehaviour):
  44. """
  45. Behaviour who permit to reference visible things like enemies
  46. """
  47. visible_mechanism = OpponentVisibleMechanism
  48. use = [visible_mechanism]
  49. def __init__(self, *args, **kwargs) -> None:
  50. super().__init__(*args, **kwargs)
  51. self._seconds_frequency = float(self.config.resolve('game.look_around.frequency'))
  52. @property
  53. def seconds_frequency(self) -> typing.Optional[float]:
  54. return self._seconds_frequency
  55. def action(self, data) -> [Event]:
  56. new_visible_subject_events = []
  57. no_longer_visible_subject_events = []
  58. for no_longer_visible_subject_id in data['no_longer_visible_subject_ids']:
  59. no_longer_visible_subject_events.append(NoLongerVisibleOpponent(
  60. observer_subject_id=self.subject.id,
  61. observed_subject_id=no_longer_visible_subject_id,
  62. ))
  63. self.subject.visible_opponent_ids.remove(no_longer_visible_subject_id)
  64. for new_visible_subject_id in data['new_visible_subject_ids']:
  65. new_visible_subject_events.append(NewVisibleOpponent(
  66. observer_subject_id=self.subject.id,
  67. observed_subject_id=new_visible_subject_id,
  68. ))
  69. self.subject.visible_opponent_ids.append(new_visible_subject_id)
  70. return new_visible_subject_events + no_longer_visible_subject_events
  71. def run(self, data):
  72. visible_subjects = data[self.visible_mechanism]['visible_subjects']
  73. visible_subject_ids = [s.id for s in visible_subjects]
  74. new_visible_subject_ids = []
  75. no_longer_visible_subject_ids = []
  76. for subject_id in self.subject.visible_opponent_ids:
  77. if subject_id not in visible_subject_ids:
  78. no_longer_visible_subject_ids.append(subject_id)
  79. for subject in visible_subjects:
  80. if subject.id not in self.subject.visible_opponent_ids:
  81. new_visible_subject_ids.append(subject.id)
  82. return {
  83. 'new_visible_subject_ids': new_visible_subject_ids,
  84. 'no_longer_visible_subject_ids': no_longer_visible_subject_ids,
  85. }
  86. class EngageOpponent(AliveSubjectBehaviour):
  87. visible_mechanism = OpponentVisibleMechanism
  88. use = [visible_mechanism]
  89. def __init__(self, *args, **kwargs) -> None:
  90. super().__init__(*args, **kwargs)
  91. self._seconds_frequency = float(self.config.resolve('game.engage.frequency'))
  92. @property
  93. def seconds_frequency(self) -> typing.Optional[float]:
  94. return self._seconds_frequency
  95. def action(self, data) -> [Event]:
  96. kill = data['kill']
  97. target_subject_id = data['target_subject_id']
  98. target_subject = self.simulation.subjects.index[target_subject_id]
  99. target_position = data['target_position']
  100. events = list()
  101. events.append(FireEvent(shooter_subject_id=self.subject.id, target_position=target_position))
  102. # Must be check if target is not already dead (killed same cycle)
  103. if kill and COLLECTION_ALIVE in target_subject.collections:
  104. DieEvent.apply_subject_death(target_subject)
  105. events.append(DieEvent(
  106. shooter_subject_id=self.subject.id,
  107. shoot_subject_id=target_subject_id,
  108. ))
  109. return events
  110. def run(self, data):
  111. visible_subjects = data[self.visible_mechanism]['visible_subjects']
  112. if not visible_subjects:
  113. return
  114. # Manage selected target (can change, better visibility, etc ...)
  115. # Manage weapon munition to be able to fire
  116. # Manage fear/under fire ...
  117. # Manage weapon reload time
  118. # For dev fun, don't fire at random
  119. if random.randint(1, 3) == -1:
  120. # Executed but decided to fail
  121. self.last_execution_time = time.time()
  122. return False
  123. target_subject = random.choice(visible_subjects)
  124. kill = random.randint(0, 100) >= 75
  125. # Manage fire miss or touch (visibility, fear, opponent hiding, etc ...)
  126. return {
  127. 'kill': kill,
  128. 'target_subject_id': target_subject.id,
  129. 'target_position': target_subject.position,
  130. }