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