behaviour.py 6.2KB

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