added tooltips for all the other tools
[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 ..sound import sound
18 from ..transforms import Overlay
19 from ..turnip import Turnip
20 from ..widgets import ImageButton, Tooltip
21 from ..constants import (
22     NIGHT_LENGTH, NIGHT_HOURS_PER_TICK, DEBUG, FONTS,
23     SCREEN_SIZE, FPS)
24
25
26 class NightScene(BaseScene):
27
28     DARKNESS = Overlay(colour=(0, 0, 0, 150))
29
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
36         self.check_battery()
37         self._infobar = InfoBar("day", battery=self._battery, scene=self)
38         self._countdownbar = CountDownBar("h")
39         self._mould = Boyd(gamestate, self._space)
40         self._turnips = []
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)
47         self._total_ticks = 0
48         self._do_ticks = True
49         self._paused = False
50         self._eaten_tonight = 0
51         self._night_over_text = []
52         self._ending = False
53
54     def create_tools(self, gamestate):
55         tools = []
56         y = SCREEN_SIZE[1] - 40
57         tools.append(ImageButton(
58             '32', 'day.png', name='day', pos=(SCREEN_SIZE[0] - 200, y), tooltip=Tooltip(["Skip to day"])))
59         tools.append(ImageButton(
60             '32', 'pause.png', name='pause play',
61             pos=(SCREEN_SIZE[0] - 150, y), tooltip=Tooltip(["Pause"])))
62         tools.append(ImageButton(
63             '32', 'exit.png', name='exit', pos=(SCREEN_SIZE[0] - 50, y), tooltip=Tooltip(["Exit"])))
64         tools[0].disable()
65         return tools
66
67     @property
68     def turnip_count(self):
69         return len(self._turnips)
70
71     @property
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))
76
77     def remaining_hours(self):
78         return int(round(
79             (NIGHT_LENGTH - self._total_ticks) * NIGHT_HOURS_PER_TICK))
80
81     @debug_timer("night.render")
82     def render(self, surface, gamestate):
83         surface.blit(self._soil, (0, 0))
84
85         self._mould.render(surface)
86
87         for turnip in self._turnips[:]:
88             if turnip.eaten:
89                 self._turnips.remove(turnip)
90                 turnip.remove()
91                 gamestate.eaten += 1
92                 self._eaten_tonight += 1
93             else:
94                 turnip.render(surface)
95
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())
101
102         for tool in self._tools:
103             tool.render(surface)
104
105         for text, text_pos in self._night_over_text:
106             surface.blit(text, text_pos, None)
107
108     def event(self, ev, gamestate):
109         if self._ending:
110             return
111         if ev.type == pgl.KEYDOWN:
112             if not self._do_ticks:
113                 # Any keypress exits
114                 self._to_day(gamestate)
115             if ev.key in (pgl.K_q, pgl.K_ESCAPE):
116                 self._ending = True
117                 from .menu import MenuScene
118                 SceneChangeEvent.post(scene=MenuScene())
119             elif ev.key == pgl.K_e and DEBUG:
120                 self._end_night()
121             elif ev.key == pgl.K_SPACE:
122                 self.toggle_pause()
123         elif ev.type == pgl.MOUSEBUTTONDOWN:
124             if not self._do_ticks:
125                 # Any mouse press exits
126                 self._to_day(gamestate)
127             if ev.button == 1:
128                 self._lights.toggle_nearest(ev.pos, surfpos=True)
129
130                 # Check tools
131                 for tool in self._tools:
132                     if tool.pressed(ev):
133                         if tool.name == 'pause play':
134                             self.toggle_pause()
135                         elif tool.name == 'exit':
136                             self._ending = True
137                             from .menu import MenuScene
138                             SceneChangeEvent.post(scene=MenuScene())
139                         elif tool.name == 'day':
140                             self._to_day(gamestate)
141
142     def toggle_pause(self):
143         self._paused = not self._paused
144         pause_img = "play.png" if self._paused else "pause.png"
145         pause_text = "Play" if self._paused else "Pause"
146         for tool in self._tools:
147             if tool.name == 'pause play':
148                 tool.update_image("32", pause_img)
149                 tool.tooltip = Tooltip([pause_text])
150
151     def _to_day(self, gamestate):
152         # End the night
153         if self._ending:
154             return
155         gamestate.update_lights(self._lights)
156         # Turnip
157         self.grow_turnips(gamestate)
158         turnip_data = [turnip.serialize() for turnip in self._turnips]
159         gamestate.turnips = turnip_data
160         gamestate.days += 1
161         self._mould.update_resistances(gamestate)
162         self._ending = True
163         from .day import DayScene
164         SceneChangeEvent.post(scene=DayScene())
165
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),
183              (350, 240)))
184
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()
190
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)
196                 self._lights.tick()
197                 if self._total_ticks % FPS == 0:
198                     self._battery.current -= int(
199                         self._lights.total_power_usage())
200                     self.check_battery()
201                 self._total_ticks += 1
202             else:
203                 self._end_night()
204             if not self._mould.alive():
205                 self._end_night()
206             if not self.turnip_count:
207                 self._tools[0].enable()
208             if not self.turnip_count and not self._battery.current:
209                 self._end_night()
210
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()
216             if seeds:
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