e4cc73384b9c433f61755cfd16fe73a35226770f
[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_LENGTH_HOURS, DEBUG, FONTS, SCREEN_SIZE, FPS)
22
23
24 class NightScene(BaseScene):
25
26     DARKNESS = Overlay(colour=(0, 0, 0, 150))
27     HOURS_PER_TICK = float(NIGHT_LENGTH_HOURS) / NIGHT_LENGTH
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         return int(self._lights.total_power_usage())
73
74     def remaining_hours(self):
75         return int(round(
76             (NIGHT_LENGTH - self._total_ticks) * self.HOURS_PER_TICK))
77
78     @debug_timer("night.render")
79     def render(self, surface, gamestate):
80         surface.blit(self._soil, (0, 0))
81
82         self._mould.render(surface)
83
84         for turnip in self._turnips[:]:
85             if turnip.eaten:
86                 self._turnips.remove(turnip)
87                 turnip.remove()
88                 gamestate.eaten += 1
89                 self._eaten_tonight += 1
90             else:
91                 turnip.render(surface)
92
93         self._lights.render_light(surface)
94         self._obstacles.render(surface)
95         self._lights.render_fittings(surface)
96         self._infobar.render(surface, gamestate)
97         self._countdownbar.render(surface, self.remaining_hours())
98
99         for tool in self._tools:
100             tool.render(surface)
101
102         for text, text_pos in self._night_over_text:
103             surface.blit(text, text_pos, None)
104
105     def event(self, ev, gamestate):
106         if ev.type == pgl.KEYDOWN:
107             if not self._do_ticks:
108                 # Any keypress exits
109                 self._to_day()
110             if ev.key in (pgl.K_q, pgl.K_ESCAPE):
111                 from .menu import MenuScene
112                 SceneChangeEvent.post(scene=MenuScene())
113             elif ev.key == pgl.K_e and DEBUG:
114                 self._end_night()
115             elif ev.key == pgl.K_SPACE:
116                 self.toggle_pause()
117         elif ev.type == pgl.MOUSEBUTTONDOWN:
118             if not self._do_ticks:
119                 # Any mouse press exits
120                 self._to_day()
121             if ev.button == 1:
122                 self._lights.toggle_nearest(ev.pos, surfpos=True)
123
124                 # Check tools
125                 for tool in self._tools:
126                     if tool.pressed(ev):
127                         if tool.name == 'pause play':
128                             self.toggle_pause()
129                         elif tool.name == 'exit':
130                             from .menu import MenuScene
131                             SceneChangeEvent.post(scene=MenuScene())
132                         elif tool.name == 'day':
133                             self._to_day()
134
135     def toggle_pause(self):
136         self._paused = not self._paused
137         pause_img = "play.png" if self._paused else "pause.png"
138         for tool in self._tools:
139             if tool.name == 'pause play':
140                 tool.update_image("32", pause_img)
141
142     def _to_day(self):
143         # End the night
144         from .day import DayScene
145         SceneChangeEvent.post(scene=DayScene())
146
147     def _end_night(self):
148         self._do_ticks = False
149         self._night_over_text = []
150         overlay = pygame.surface.Surface(
151             (SCREEN_SIZE[0], 240), pgl.SWSURFACE).convert_alpha()
152         overlay.fill((0, 0, 0, 172))
153         self._night_over_text.append((overlay, (0, 40)))
154         self._night_over_text.append(
155             (shadowed_text("The Night is Over", FONTS["bold"], 48), (300, 50)))
156         self._night_over_text.append(
157             (shadowed_text("Turnips eaten tonight: %d" % self._eaten_tonight,
158                            FONTS["sans"], 32), (300, 130)))
159         self._night_over_text.append(
160             (shadowed_text("Surviving turnips: %d" % len(self._turnips),
161                            FONTS["sans"], 32), (300, 170)))
162         self._night_over_text.append(
163             (shadowed_text("Press any key to continue", FONTS["sans"], 24),
164              (350, 240)))
165
166     def check_battery(self):
167         if self._battery.current == 0:
168             self._lights.battery_dead()
169
170     @debug_timer("night.tick")
171     def tick(self, gamestate):
172         if self._do_ticks and not self._paused:
173             if self._total_ticks < NIGHT_LENGTH:
174                 self._mould.tick(gamestate, self._space, self._lights)
175                 self._lights.tick()
176                 if self._total_ticks % FPS == 0:
177                     self._battery.current -= int(
178                         self._lights.total_power_usage())
179                     self.check_battery()
180                 self._total_ticks += 1
181             else:
182                 self._end_night()
183             if not self._mould.alive():
184                 self._end_night()
185             if not self.turnip_count:
186                 self.add_day_button()
187             if not self.turnip_count and not self._battery.current:
188                 self._end_night()
189
190     def exit(self, gamestate):
191         turnip_data = [turnip.serialize() for turnip in self._turnips]
192         gamestate.turnips = turnip_data
193         # TODO: Move this into the end_night function
194         gamestate.days += 1
195         self._mould.update_resistances(gamestate)