|  | @@ -1,19 +1,26 @@
 | 
	
		
			
			| 1 | 1 |  # coding: utf-8
 | 
	
		
			
			| 2 | 2 |  import typing
 | 
	
		
			
			| 3 | 3 |  
 | 
	
		
			
			|  | 4 | +import time
 | 
	
		
			
			|  | 5 | +
 | 
	
		
			
			|  | 6 | +import pyglet
 | 
	
		
			
			| 4 | 7 |  from PIL import Image
 | 
	
		
			
			| 5 | 8 |  from synergine2.config import Config
 | 
	
		
			
			| 6 | 9 |  from synergine2.simulation import Subject
 | 
	
		
			
			| 7 | 10 |  from synergine2_cocos2d.actor import Actor
 | 
	
		
			
			| 8 | 11 |  
 | 
	
		
			
			| 9 |  | -from opencombat.exception import UnknownWeapon
 | 
	
		
			
			|  | 12 | +from opencombat.exception import UnknownWeapon, UnknownAnimationIndex
 | 
	
		
			
			| 10 | 13 |  from opencombat.gui.animation import ANIMATION_CRAWL
 | 
	
		
			
			| 11 | 14 |  from opencombat.gui.animation import ANIMATION_WALK
 | 
	
		
			
			| 12 | 15 |  from opencombat.gui.const import POSITION_MAN_STAND_UP
 | 
	
		
			
			| 13 | 16 |  from opencombat.gui.const import POSITION_MAN_CRAWLING
 | 
	
		
			
			|  | 17 | +from opencombat.gui.image import TileImageCache
 | 
	
		
			
			| 14 | 18 |  from opencombat.gui.weapon import RIFFLE
 | 
	
		
			
			| 15 | 19 |  from opencombat.gui.weapon import WeaponImageApplier
 | 
	
		
			
			| 16 | 20 |  
 | 
	
		
			
			|  | 21 | +if typing.TYPE_CHECKING:
 | 
	
		
			
			|  | 22 | +    from opencombat.gui.fire import GuiFiringEvent
 | 
	
		
			
			|  | 23 | +
 | 
	
		
			
			| 17 | 24 |  
 | 
	
		
			
			| 18 | 25 |  class BaseActor(Actor):
 | 
	
		
			
			| 19 | 26 |      position_matching = {
 | 
	
	
		
			
			|  | @@ -31,6 +38,17 @@ class BaseActor(Actor):
 | 
	
		
			
			| 31 | 38 |          self.weapon_image_applier = WeaponImageApplier(config, self)
 | 
	
		
			
			| 32 | 39 |          super().__init__(image_path, subject=subject, config=config)
 | 
	
		
			
			| 33 | 40 |  
 | 
	
		
			
			|  | 41 | +        # Firing
 | 
	
		
			
			|  | 42 | +        self.last_firing_time = 0
 | 
	
		
			
			|  | 43 | +        self.firing_change_image_gap = 0.05  # seconds
 | 
	
		
			
			|  | 44 | +        self.firing_images_cache = {}  # type: TODO
 | 
	
		
			
			|  | 45 | +
 | 
	
		
			
			|  | 46 | +        self.default_image_path = image_path
 | 
	
		
			
			|  | 47 | +
 | 
	
		
			
			|  | 48 | +        self.image_cache = TileImageCache(self, self.config)
 | 
	
		
			
			|  | 49 | +        self.image_cache.build()
 | 
	
		
			
			|  | 50 | +        pass
 | 
	
		
			
			|  | 51 | +
 | 
	
		
			
			| 34 | 52 |      @property
 | 
	
		
			
			| 35 | 53 |      def mode(self) -> str:
 | 
	
		
			
			| 36 | 54 |          return self._mode
 | 
	
	
		
			
			|  | @@ -44,9 +62,9 @@ class BaseActor(Actor):
 | 
	
		
			
			| 44 | 62 |              return []
 | 
	
		
			
			| 45 | 63 |  
 | 
	
		
			
			| 46 | 64 |          return [
 | 
	
		
			
			| 47 |  | -            self.weapon_image_applier.get_default_image_for_weapon(
 | 
	
		
			
			|  | 65 | +            self.weapon_image_applier.get_image_for_weapon(
 | 
	
		
			
			| 48 | 66 |                  self.mode,
 | 
	
		
			
			| 49 |  | -                self.weapons[0],
 | 
	
		
			
			|  | 67 | +                self.weapons[0],  # FIXME
 | 
	
		
			
			| 50 | 68 |              )
 | 
	
		
			
			| 51 | 69 |          ]
 | 
	
		
			
			| 52 | 70 |  
 | 
	
	
		
			
			|  | @@ -71,8 +89,81 @@ class BaseActor(Actor):
 | 
	
		
			
			| 71 | 89 |          except UnknownWeapon:
 | 
	
		
			
			| 72 | 90 |              return []
 | 
	
		
			
			| 73 | 91 |  
 | 
	
		
			
			| 74 |  | -    def firing(self) -> None:
 | 
	
		
			
			| 75 |  | -        pass
 | 
	
		
			
			|  | 92 | +    def get_modes(self) -> typing.List[str]:
 | 
	
		
			
			|  | 93 | +        return [POSITION_MAN_STAND_UP]
 | 
	
		
			
			|  | 94 | +
 | 
	
		
			
			|  | 95 | +    # def build_firing_images(self) -> None:
 | 
	
		
			
			|  | 96 | +    #     cache_dir = self.config.resolve('global.cache_dir_path')
 | 
	
		
			
			|  | 97 | +    #     for mode in self.get_modes():
 | 
	
		
			
			|  | 98 | +    #         for weapon in self.weapons:
 | 
	
		
			
			|  | 99 | +    #             images = self.weapon_image_applier.get_firing_image(
 | 
	
		
			
			|  | 100 | +    #                 mode=mode,
 | 
	
		
			
			|  | 101 | +    #                 weapon_type=weapon,
 | 
	
		
			
			|  | 102 | +    #             )
 | 
	
		
			
			|  | 103 | +    #
 | 
	
		
			
			|  | 104 | +    #             for position in range(len(images)):
 | 
	
		
			
			|  | 105 | +    #                 pass
 | 
	
		
			
			|  | 106 | +    #
 | 
	
		
			
			|  | 107 | +    #
 | 
	
		
			
			|  | 108 | +    #     for animation_name, animation_image_paths in self.animation_image_paths.items():
 | 
	
		
			
			|  | 109 | +    #         self.animation_images[animation_name] = []
 | 
	
		
			
			|  | 110 | +    #         for i, animation_image_path in enumerate(animation_image_paths):
 | 
	
		
			
			|  | 111 | +    #             final_image_path = self.path_manager.path(animation_image_path)
 | 
	
		
			
			|  | 112 | +    #             final_image = Image.open(final_image_path)
 | 
	
		
			
			|  | 113 | +    #
 | 
	
		
			
			|  | 114 | +    #             for appliable_image in self.get_animation_appliable_images(
 | 
	
		
			
			|  | 115 | +    #                 animation_name,
 | 
	
		
			
			|  | 116 | +    #                 i,
 | 
	
		
			
			|  | 117 | +    #             ):
 | 
	
		
			
			|  | 118 | +    #                 final_image.paste(
 | 
	
		
			
			|  | 119 | +    #                     appliable_image,
 | 
	
		
			
			|  | 120 | +    #                     (0, 0),
 | 
	
		
			
			|  | 121 | +    #                     appliable_image,
 | 
	
		
			
			|  | 122 | +    #                 )
 | 
	
		
			
			|  | 123 | +    #
 | 
	
		
			
			|  | 124 | +    #             # FIXME NOW: nom des image utilise au dessus
 | 
	
		
			
			|  | 125 | +    #             final_name = '_'.join([
 | 
	
		
			
			|  | 126 | +    #                 str(subject_id),
 | 
	
		
			
			|  | 127 | +    #                 ntpath.basename(final_image_path),
 | 
	
		
			
			|  | 128 | +    #             ])
 | 
	
		
			
			|  | 129 | +    #             final_path = os.path.join(cache_dir, final_name)
 | 
	
		
			
			|  | 130 | +    #
 | 
	
		
			
			|  | 131 | +    #             final_image.save(final_path)
 | 
	
		
			
			|  | 132 | +    #
 | 
	
		
			
			|  | 133 | +    #             self.animation_images[animation_name].append(
 | 
	
		
			
			|  | 134 | +    #                 pyglet.image.load(
 | 
	
		
			
			|  | 135 | +    #                     final_path,
 | 
	
		
			
			|  | 136 | +    #                 )
 | 
	
		
			
			|  | 137 | +    #             )
 | 
	
		
			
			|  | 138 | +
 | 
	
		
			
			|  | 139 | +    def firing(self, firing: 'GuiFiringEvent') -> None:
 | 
	
		
			
			|  | 140 | +        # FIXME: move some code ?
 | 
	
		
			
			|  | 141 | +        now = time.time()
 | 
	
		
			
			|  | 142 | +        if now - self.last_firing_time >= self.firing_change_image_gap:
 | 
	
		
			
			|  | 143 | +            self.last_firing_time = now
 | 
	
		
			
			|  | 144 | +            firing.increment_animation_index()
 | 
	
		
			
			|  | 145 | +
 | 
	
		
			
			|  | 146 | +            try:
 | 
	
		
			
			|  | 147 | +                image = self.image_cache.firing_cache.get(
 | 
	
		
			
			|  | 148 | +                    mode=self.mode,
 | 
	
		
			
			|  | 149 | +                    weapon=firing.weapon,
 | 
	
		
			
			|  | 150 | +                    position=firing.animation_index,
 | 
	
		
			
			|  | 151 | +                )
 | 
	
		
			
			|  | 152 | +            except UnknownAnimationIndex:
 | 
	
		
			
			|  | 153 | +                image = self.image_cache.firing_cache.get(
 | 
	
		
			
			|  | 154 | +                    mode=self.mode,
 | 
	
		
			
			|  | 155 | +                    weapon=firing.weapon,
 | 
	
		
			
			|  | 156 | +                    position=0,
 | 
	
		
			
			|  | 157 | +                )
 | 
	
		
			
			|  | 158 | +                firing.reset_animation_index()
 | 
	
		
			
			|  | 159 | +
 | 
	
		
			
			|  | 160 | +            # FIXME cache: prepare before firing
 | 
	
		
			
			|  | 161 | +            import uuid
 | 
	
		
			
			|  | 162 | +            tmp_path = '/tmp/{}.png'.format(str(uuid.uuid4()))
 | 
	
		
			
			|  | 163 | +            image.save(tmp_path)
 | 
	
		
			
			|  | 164 | +            pyglet_image = pyglet.image.load(tmp_path)
 | 
	
		
			
			|  | 165 | +
 | 
	
		
			
			|  | 166 | +            self.update_image(pyglet_image.get_texture())
 | 
	
		
			
			| 76 | 167 |  
 | 
	
		
			
			| 77 | 168 |  
 | 
	
		
			
			| 78 | 169 |  class Man(BaseActor):
 | 
	
	
		
			
			|  | @@ -108,7 +199,7 @@ class Man(BaseActor):
 | 
	
		
			
			| 108 | 199 |          return [RIFFLE]
 | 
	
		
			
			| 109 | 200 |  
 | 
	
		
			
			| 110 | 201 |  
 | 
	
		
			
			| 111 |  | -class HeavyVehicle(Actor):
 | 
	
		
			
			|  | 202 | +class HeavyVehicle(BaseActor):
 | 
	
		
			
			| 112 | 203 |      animation_image_paths = {
 | 
	
		
			
			| 113 | 204 |          ANIMATION_WALK: [
 | 
	
		
			
			| 114 | 205 |              'actors/tank1.png',
 | 
	
	
		
			
			|  | @@ -124,3 +215,8 @@ class HeavyVehicle(Actor):
 | 
	
		
			
			| 124 | 215 |          subject: Subject,
 | 
	
		
			
			| 125 | 216 |      ) -> None:
 | 
	
		
			
			| 126 | 217 |          super().__init__('actors/tank1.png', subject=subject, config=config)
 | 
	
		
			
			|  | 218 | +
 | 
	
		
			
			|  | 219 | +    @property
 | 
	
		
			
			|  | 220 | +    def weapons(self) -> typing.List[str]:
 | 
	
		
			
			|  | 221 | +        # TODO BS 2018-01-26: Will be managed by complex part of code
 | 
	
		
			
			|  | 222 | +        return [RIFFLE]
 |