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