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 ..sound import sound
18 from ..transforms import Overlay
19 from ..turnip import Turnip
20 from ..widgets import ImageButton
21 from ..constants import (
22 NIGHT_LENGTH, NIGHT_HOURS_PER_TICK, DEBUG, FONTS,
26 class NightScene(BaseScene):
28 DARKNESS = Overlay(colour=(0, 0, 0, 150))
30 def enter(self, gamestate):
31 self._space = pymunk.Space()
32 self._obstacles = ObstacleManager(self._space, gamestate)
33 self._lights = LightManager(self._space, gamestate)
34 self._battery = BatteryManager(gamestate)
35 self._battery_dead = False
37 self._infobar = InfoBar("day", battery=self._battery, scene=self)
38 self._countdownbar = CountDownBar("h")
39 self._mould = Boyd(gamestate, self._space)
41 for turnip_data in gamestate.turnips:
42 turnip = Turnip(space=self._space, **turnip_data)
43 self._turnips.append(turnip)
44 self._soil = loader.load_image(
45 "textures", "soil.png", transform=self.DARKNESS)
46 self._tools = self.create_tools(gamestate)
50 self._eaten_tonight = 0
51 self._night_over_text = []
54 def create_tools(self, gamestate):
56 y = SCREEN_SIZE[1] - 40
57 tools.append(ImageButton(
58 '32', 'pause.png', name='pause play',
59 pos=(SCREEN_SIZE[0] - 150, y)))
60 tools.append(ImageButton(
61 '32', 'exit.png', name='exit', pos=(SCREEN_SIZE[0] - 50, y)))
64 def add_day_button(self):
65 y = SCREEN_SIZE[1] - 40
66 self._tools.append(ImageButton(
67 '32', 'day.png', name='day', pos=(SCREEN_SIZE[0] - 200, y)))
70 def turnip_count(self):
71 return len(self._turnips)
74 def power_usage(self):
75 power = self._lights.total_power_usage()
76 power = power / (FPS * NIGHT_HOURS_PER_TICK)
77 return int(round(power))
79 def remaining_hours(self):
81 (NIGHT_LENGTH - self._total_ticks) * NIGHT_HOURS_PER_TICK))
83 @debug_timer("night.render")
84 def render(self, surface, gamestate):
85 surface.blit(self._soil, (0, 0))
87 self._mould.render(surface)
89 for turnip in self._turnips[:]:
91 self._turnips.remove(turnip)
94 self._eaten_tonight += 1
96 turnip.render(surface)
98 self._lights.render_light(surface)
99 self._obstacles.render(surface)
100 self._lights.render_fittings(surface)
101 self._infobar.render(surface, gamestate)
102 self._countdownbar.render(surface, self.remaining_hours())
104 for tool in self._tools:
107 for text, text_pos in self._night_over_text:
108 surface.blit(text, text_pos, None)
110 def event(self, ev, gamestate):
113 if ev.type == pgl.KEYDOWN:
114 if not self._do_ticks:
116 self._to_day(gamestate)
117 if ev.key in (pgl.K_q, pgl.K_ESCAPE):
119 from .menu import MenuScene
120 SceneChangeEvent.post(scene=MenuScene())
121 elif ev.key == pgl.K_e and DEBUG:
123 elif ev.key == pgl.K_SPACE:
125 elif ev.type == pgl.MOUSEBUTTONDOWN:
126 if not self._do_ticks:
127 # Any mouse press exits
128 self._to_day(gamestate)
130 self._lights.toggle_nearest(ev.pos, surfpos=True)
133 for tool in self._tools:
135 if tool.name == 'pause play':
137 elif tool.name == 'exit':
139 from .menu import MenuScene
140 SceneChangeEvent.post(scene=MenuScene())
141 elif tool.name == 'day':
142 self._to_day(gamestate)
144 def toggle_pause(self):
145 self._paused = not self._paused
146 pause_img = "play.png" if self._paused else "pause.png"
147 for tool in self._tools:
148 if tool.name == 'pause play':
149 tool.update_image("32", pause_img)
151 def _to_day(self, gamestate):
155 gamestate.update_lights(self._lights)
157 from .day import DayScene
158 SceneChangeEvent.post(scene=DayScene())
160 def _end_night(self):
161 self._do_ticks = False
162 self._night_over_text = []
163 overlay = pygame.surface.Surface(
164 (SCREEN_SIZE[0], 240), pgl.SWSURFACE).convert_alpha()
165 overlay.fill((0, 0, 0, 172))
166 self._night_over_text.append((overlay, (0, 40)))
167 self._night_over_text.append(
168 (shadowed_text("The Night is Over", FONTS["bold"], 48), (300, 50)))
169 self._night_over_text.append(
170 (shadowed_text("Turnips eaten tonight: %d" % self._eaten_tonight,
171 FONTS["sans"], 32), (300, 130)))
172 self._night_over_text.append(
173 (shadowed_text("Surviving turnips: %d" % len(self._turnips),
174 FONTS["sans"], 32), (300, 170)))
175 self._night_over_text.append(
176 (shadowed_text("Press any key to continue", FONTS["sans"], 24),
179 def check_battery(self):
180 if self._battery.current == 0 and not self._battery_dead:
181 self._battery_dead = True
182 sound.play_sound("battery_dying.ogg")
183 self._lights.battery_dead()
185 @debug_timer("night.tick")
186 def tick(self, gamestate):
187 if self._do_ticks and not self._paused:
188 if self._total_ticks < NIGHT_LENGTH:
189 self._mould.tick(gamestate, self._space, self._lights)
191 if self._total_ticks % FPS == 0:
192 self._battery.current -= int(
193 self._lights.total_power_usage())
195 self._total_ticks += 1
198 if not self._mould.alive():
200 if not self.turnip_count:
201 self.add_day_button()
202 if not self.turnip_count and not self._battery.current:
205 def exit(self, gamestate):
206 turnip_data = [turnip.serialize() for turnip in self._turnips]
207 gamestate.turnips = turnip_data
208 # TODO: Move this into the end_night function
210 self._mould.update_resistances(gamestate)