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 self.grow_turnips(gamestate)
158 turnip_data = [turnip.serialize() for turnip in self._turnips]
159 gamestate.turnips = turnip_data
161 self._mould.update_resistances(gamestate)
163 from .day import DayScene
164 SceneChangeEvent.post(scene=DayScene())
166 def _end_night(self):
167 self._do_ticks = False
168 self._night_over_text = []
169 overlay = pygame.surface.Surface(
170 (SCREEN_SIZE[0], 240), pgl.SWSURFACE).convert_alpha()
171 overlay.fill((0, 0, 0, 172))
172 self._night_over_text.append((overlay, (0, 40)))
173 self._night_over_text.append(
174 (shadowed_text("The Night is Over", FONTS["bold"], 48), (300, 50)))
175 self._night_over_text.append(
176 (shadowed_text("Turnips eaten tonight: %d" % self._eaten_tonight,
177 FONTS["sans"], 32), (300, 130)))
178 self._night_over_text.append(
179 (shadowed_text("Surviving turnips: %d" % len(self._turnips),
180 FONTS["sans"], 32), (300, 170)))
181 self._night_over_text.append(
182 (shadowed_text("Press any key to continue", FONTS["sans"], 24),
185 def check_battery(self):
186 if self._battery.current == 0 and not self._battery_dead:
187 self._battery_dead = True
188 sound.play_sound("battery_dying.ogg")
189 self._lights.battery_dead()
191 @debug_timer("night.tick")
192 def tick(self, gamestate):
193 if self._do_ticks and not self._paused:
194 if self._total_ticks < NIGHT_LENGTH:
195 self._mould.tick(gamestate, self._space, self._lights)
197 if self._total_ticks % FPS == 0:
198 self._battery.current -= int(
199 self._lights.total_power_usage())
201 self._total_ticks += 1
204 if not self._mould.alive():
206 if not self.turnip_count:
207 self.add_day_button()
208 if not self.turnip_count and not self._battery.current:
211 def grow_turnips(self, gamestate):
212 """ Turnips grow at the end of the night """
213 for turnip in self._turnips[:]:
214 # Turnips grow at dawn
215 seeds = turnip.grow()
217 gamestate.seeds += seeds
218 gamestate.harvested += 1
219 self._turnips.remove(turnip)
220 # We ignore the body cleanup, since the space is going away