1 """ In the night, the mould attacks. """
4 import pygame.locals as pgl
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,
25 class NightScene(BaseScene):
27 DARKNESS = Overlay(colour=(0, 0, 0, 150))
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)
35 self._infobar = InfoBar("day", battery=self._battery, scene=self)
36 self._countdownbar = CountDownBar("h")
37 self._mould = Boyd(gamestate, self._space)
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)
48 self._eaten_tonight = 0
49 self._night_over_text = []
52 def create_tools(self, gamestate):
54 y = SCREEN_SIZE[1] - 40
55 tools.append(ImageButton(
56 '32', 'pause.png', name='pause play',
57 pos=(SCREEN_SIZE[0] - 150, y)))
58 tools.append(ImageButton(
59 '32', 'exit.png', name='exit', pos=(SCREEN_SIZE[0] - 50, y)))
62 def add_day_button(self):
63 y = SCREEN_SIZE[1] - 40
64 self._tools.append(ImageButton(
65 '32', 'day.png', name='day', pos=(SCREEN_SIZE[0] - 200, y)))
68 def turnip_count(self):
69 return len(self._turnips)
72 def power_usage(self):
73 power = self._lights.total_power_usage()
74 power = power / (FPS * NIGHT_HOURS_PER_TICK)
75 return int(round(power))
77 def remaining_hours(self):
79 (NIGHT_LENGTH - self._total_ticks) * NIGHT_HOURS_PER_TICK))
81 @debug_timer("night.render")
82 def render(self, surface, gamestate):
83 surface.blit(self._soil, (0, 0))
85 self._mould.render(surface)
87 for turnip in self._turnips[:]:
89 self._turnips.remove(turnip)
92 self._eaten_tonight += 1
94 turnip.render(surface)
96 self._lights.render_light(surface)
97 self._obstacles.render(surface)
98 self._lights.render_fittings(surface)
99 self._infobar.render(surface, gamestate)
100 self._countdownbar.render(surface, self.remaining_hours())
102 for tool in self._tools:
105 for text, text_pos in self._night_over_text:
106 surface.blit(text, text_pos, None)
108 def event(self, ev, gamestate):
111 if ev.type == pgl.KEYDOWN:
112 if not self._do_ticks:
114 self._to_day(gamestate)
115 if ev.key in (pgl.K_q, pgl.K_ESCAPE):
117 from .menu import MenuScene
118 SceneChangeEvent.post(scene=MenuScene())
119 elif ev.key == pgl.K_e and DEBUG:
121 elif ev.key == pgl.K_SPACE:
123 elif ev.type == pgl.MOUSEBUTTONDOWN:
124 if not self._do_ticks:
125 # Any mouse press exits
126 self._to_day(gamestate)
128 self._lights.toggle_nearest(ev.pos, surfpos=True)
131 for tool in self._tools:
133 if tool.name == 'pause play':
135 elif tool.name == 'exit':
137 from .menu import MenuScene
138 SceneChangeEvent.post(scene=MenuScene())
139 elif tool.name == 'day':
140 self._to_day(gamestate)
142 def toggle_pause(self):
143 self._paused = not self._paused
144 pause_img = "play.png" if self._paused else "pause.png"
145 for tool in self._tools:
146 if tool.name == 'pause play':
147 tool.update_image("32", pause_img)
149 def _to_day(self, gamestate):
153 gamestate.update_lights(self._lights)
155 from .day import DayScene
156 SceneChangeEvent.post(scene=DayScene())
158 def _end_night(self):
159 self._do_ticks = False
160 self._night_over_text = []
161 overlay = pygame.surface.Surface(
162 (SCREEN_SIZE[0], 240), pgl.SWSURFACE).convert_alpha()
163 overlay.fill((0, 0, 0, 172))
164 self._night_over_text.append((overlay, (0, 40)))
165 self._night_over_text.append(
166 (shadowed_text("The Night is Over", FONTS["bold"], 48), (300, 50)))
167 self._night_over_text.append(
168 (shadowed_text("Turnips eaten tonight: %d" % self._eaten_tonight,
169 FONTS["sans"], 32), (300, 130)))
170 self._night_over_text.append(
171 (shadowed_text("Surviving turnips: %d" % len(self._turnips),
172 FONTS["sans"], 32), (300, 170)))
173 self._night_over_text.append(
174 (shadowed_text("Press any key to continue", FONTS["sans"], 24),
177 def check_battery(self):
178 if self._battery.current == 0:
179 self._lights.battery_dead()
181 @debug_timer("night.tick")
182 def tick(self, gamestate):
183 if self._do_ticks and not self._paused:
184 if self._total_ticks < NIGHT_LENGTH:
185 self._mould.tick(gamestate, self._space, self._lights)
187 if self._total_ticks % FPS == 0:
188 self._battery.current -= int(
189 self._lights.total_power_usage())
191 self._total_ticks += 1
194 if not self._mould.alive():
196 if not self.turnip_count:
197 self.add_day_button()
198 if not self.turnip_count and not self._battery.current:
201 def exit(self, gamestate):
202 turnip_data = [turnip.serialize() for turnip in self._turnips]
203 gamestate.turnips = turnip_data
204 # TODO: Move this into the end_night function
206 self._mould.update_resistances(gamestate)