Use projectile images.
[koperkapel.git] / koperkapel / weapons.py
1 """ Tools for dealing with weapons. """
2
3 from pygame.surface import Surface
4 from pygame.draw import circle
5 from pgzero.loaders import images, sounds
6 from .actors.anim import AnimatedSurfActor
7 from .util import safepath
8
9
10 class Weapon:
11     def __init__(self, name, damage, image_name=None, bullet_range=0,
12                  can_tape=True, frames=("_1",), projectile=None, sound=None):
13         self.name = name
14         self.image_name = image_name or name
15         self.frames = frames
16         self.damage = damage
17         self.bullet_range = bullet_range
18         self.can_tape = can_tape
19         self.projectile = projectile
20         self.sound = None
21         if sound:
22             self.sound = sounds.load(sound)
23
24     def play_sound(self):
25         if self.sound:
26             self.sound.play()
27
28     def assemble_bullet(self):
29         return BulletActor(self)
30
31
32 WEAPONS = [
33     Weapon("spit", damage=1, bullet_range=2, can_tape=False,
34            image_name="blank", frames=("",), sound="fire_spit",
35            projectile="spit"),
36     Weapon("butter_knife", damage=2),
37     Weapon("crowbar", damage=4),
38     Weapon("gun", damage=4, bullet_range=4, sound='gun_fire',
39            projectile="bullet"),
40 ]
41
42 WEAPON_LOOKUP = {w.name: w for w in WEAPONS}
43
44
45 def weapon_by_name(weapon_name):
46     return WEAPON_LOOKUP[weapon_name]
47
48
49 class WeaponActor(AnimatedSurfActor):
50     def __init__(self, weapon, **kw):
51         super().__init__(**kw)
52         self.weapon = weapon
53
54
55 class BulletActor(AnimatedSurfActor):
56     def __init__(self, weapon, **kw):
57         frames = self._shiny_frames(weapon)
58         if frames is None:
59             frames = self._ugly_circle_frames(weapon)
60         super().__init__(frames=frames, **kw)
61         self.weapon = weapon
62
63     def _shiny_frames(self, weapon):
64         if weapon.projectile is None:
65             return None
66         surf = images.load(safepath("projectiles/%s" % (weapon.projectile,)))
67         return [surf]
68
69     def _ugly_circle_frames(self, weapon):
70         radius = min(weapon.damage * 5, 32)
71         surf = Surface((radius * 2, radius * 2))
72         surf.convert_alpha()
73         surf.fill((255, 255, 255, 0))
74         circle(surf, (255, 0, 255, 32), (radius, radius), radius)
75         return [surf]
76
77
78 class WeaponFactory:
79
80     def assemble_frame(self, suffix, weapon, tape):
81         surf = images.load(safepath("weapons/%s%s")
82                            % (weapon.image_name, suffix))
83         frame = surf.copy()
84         if tape:
85             tape_surf = images.load(safepath("weapons/tape"))
86             frame.blit(tape_surf, (0, 0))
87         return frame
88
89     def assemble(self, weapon_name, tape=False):
90         weapon = weapon_by_name(weapon_name)
91         tape = tape and weapon.can_tape
92         frames = [
93             self.assemble_frame(suffix, weapon, tape)
94             for suffix in weapon.frames]
95         return WeaponActor(weapon, frames=frames)
96
97
98 default_weapons = WeaponFactory()