Consume power at FPS rate
[tabakrolletjie.git] / tabakrolletjie / scenes / night.py
1 """ In the night, the mould attacks. """
2
3 import pygame.surface
4 import pygame.locals as pgl
5
6 import pymunk
7
8 from .base import BaseScene
9 from ..battery import BatteryManager
10 from ..lights import LightManager
11 from ..infobar import InfoBar
12 from ..obstacles import ObstacleManager
13 from ..enemies import Boyd
14 from ..events import SceneChangeEvent
15 from ..utils import debug_timer, shadowed_text
16 from ..loader import loader
17 from ..transforms import Overlay
18 from ..turnip import Turnip
19 from ..widgets import ImageButton
20 from ..constants import NIGHT_LENGTH, DEBUG, FONTS, SCREEN_SIZE, FPS
21
22
23 class NightScene(BaseScene):
24
25     DARKNESS = Overlay(colour=(0, 0, 0, 150))
26
27     def enter(self, gamestate):
28         self._space = pymunk.Space()
29         self._obstacles = ObstacleManager(self._space, gamestate)
30         self._lights = LightManager(self._space, gamestate)
31         self._battery = BatteryManager(gamestate)
32         self.check_battery()
33         self._infobar = InfoBar("day", battery=self._battery, scene=self)
34         self._mould = Boyd(gamestate, self._space)
35         self._turnips = []
36         for turnip_data in gamestate.turnips:
37             turnip = Turnip(space=self._space, **turnip_data)
38             self._turnips.append(turnip)
39         self._soil = loader.load_image(
40             "textures", "soil.png", transform=self.DARKNESS)
41         self._tools = self.create_tools(gamestate)
42         self._total_ticks = 0
43         self._do_ticks = True
44         self._paused = False
45         self._eaten_tonight = 0
46         self._night_over_text = []
47
48     def create_tools(self, gamestate):
49         tools = []
50         y = SCREEN_SIZE[1] - 40
51         tools.append(ImageButton(
52             '32', 'pause.png', name='pause play',
53             pos=(SCREEN_SIZE[0] - 150, y)))
54         tools.append(ImageButton(
55             '32', 'exit.png', name='exit', pos=(SCREEN_SIZE[0] - 50, y)))
56         return tools
57
58     @property
59     def turnip_count(self):
60         return len(self._turnips)
61
62     @property
63     def power_usage(self):
64         return int(self._lights.total_power_usage())
65
66     @debug_timer("night.render")
67     def render(self, surface, gamestate):
68         surface.blit(self._soil, (0, 0))
69
70         self._mould.render(surface)
71
72         for turnip in self._turnips[:]:
73             if turnip.eaten:
74                 self._turnips.remove(turnip)
75                 turnip.remove()
76                 gamestate.eaten += 1
77                 self._eaten_tonight += 1
78             else:
79                 turnip.render(surface)
80
81         self._lights.render_light(surface)
82         self._obstacles.render(surface)
83         self._lights.render_fittings(surface)
84         self._infobar.render(surface, gamestate)
85
86         for tool in self._tools:
87             tool.render(surface)
88
89         for text, text_pos in self._night_over_text:
90             surface.blit(text, text_pos, None)
91
92     def event(self, ev, gamestate):
93         if ev.type == pgl.KEYDOWN:
94             if not self._do_ticks:
95                 # Any keypress exits
96                 self._to_day()
97             if ev.key in (pgl.K_q, pgl.K_ESCAPE):
98                 from .menu import MenuScene
99                 SceneChangeEvent.post(scene=MenuScene())
100             elif ev.key == pgl.K_e and DEBUG:
101                 self._end_night()
102             elif ev.key == pgl.K_SPACE:
103                 self.toggle_pause()
104         elif ev.type == pgl.MOUSEBUTTONDOWN:
105             if not self._do_ticks:
106                 # Any mouse press exits
107                 self._to_day()
108             if ev.button == 1:
109                 self._lights.toggle_nearest(ev.pos, surfpos=True)
110
111                 # Check tools
112                 for tool in self._tools:
113                     if tool.pressed(ev):
114                         if tool.name == 'pause play':
115                             self.toggle_pause()
116                         elif tool.name == 'exit':
117                             from .menu import MenuScene
118                             SceneChangeEvent.post(scene=MenuScene())
119
120     def toggle_pause(self):
121         self._paused = not self._paused
122         pause_img = "play.png" if self._paused else "pause.png"
123         for tool in self._tools:
124             if tool.name == 'pause play':
125                 tool.update_image("32", pause_img)
126
127     def _to_day(self):
128         # End the night
129         from .day import DayScene
130         SceneChangeEvent.post(scene=DayScene())
131
132     def _end_night(self):
133         self._do_ticks = False
134         self._night_over_text = []
135         overlay = pygame.surface.Surface(
136             (SCREEN_SIZE[0], 240), pgl.SWSURFACE).convert_alpha()
137         overlay.fill((0, 0, 0, 172))
138         self._night_over_text.append((overlay, (0, 40)))
139         self._night_over_text.append(
140             (shadowed_text("The Night is Over", FONTS["bold"], 48), (300, 50)))
141         self._night_over_text.append(
142             (shadowed_text("Turnips eaten tonight: %d" % self._eaten_tonight,
143                            FONTS["sans"], 32), (300, 130)))
144         self._night_over_text.append(
145             (shadowed_text("Surviving turnips: %d" % len(self._turnips),
146                            FONTS["sans"], 32), (300, 170)))
147         self._night_over_text.append(
148             (shadowed_text("Press any key to continue", FONTS["sans"], 24),
149              (350, 240)))
150
151     def check_battery(self):
152         if self._battery.current == 0:
153             self._lights.battery_dead()
154
155     @debug_timer("night.tick")
156     def tick(self, gamestate):
157         if self._do_ticks and not self._paused:
158             if self._total_ticks < NIGHT_LENGTH:
159                 self._mould.tick(gamestate, self._space, self._lights)
160                 self._lights.tick()
161                 if self._total_ticks % FPS == 0:
162                     self._battery.current -= int(
163                         self._lights.total_power_usage())
164                     self.check_battery()
165                 self._total_ticks += 1
166             else:
167                 self._end_night()
168             if not self._mould.alive():
169                 self._end_night()
170
171     def exit(self, gamestate):
172         turnip_data = [turnip.serialize() for turnip in self._turnips]
173         gamestate.turnips = turnip_data
174         # TODO: Move this into the end_night function
175         gamestate.days += 1
176         self._mould.update_resistances(gamestate)