cloud
[sso] / shaken_and_spit_out / SSO.py
1 from os import listdir
2 from glob import glob
3 from random import choice
4 from collections import deque
5
6 from pygame import cursors, PixelArray, Surface, Color
7 from pygame.mouse import set_cursor
8 from pygame.font import Font
9 from pygame.image import load
10 from pygame.locals import *
11
12 from shaken_and_spit_out.pgfw.Game import Game
13 from shaken_and_spit_out.pgfw.GameChild import GameChild
14 from shaken_and_spit_out.pgfw.Sprite import Sprite
15
16 class SSO(Game):
17
18 def __init__(self):
19 Game.__init__(self)
20 set_cursor(*cursors.tri_left)
21 # string = u"\u2250\u2254\u2258"
22 # font = Font(self.get_resource("display", "font"), 24)
23 # self.message = font.render(string, True, (0, 255, 0))
24 self.backgrounds = [load(path).convert() for path in \
25 glob(self.get_resource("image", "background") + \
26 "*.png")]
27 self.used_backgrounds = []
28 self.set_random_background()
29 self.subscribe(self.respond)
30 self.title.activate()
31
32 def set_children(self):
33 Game.set_children(self)
34 self.title = Title(self)
35 self.floor = Floor(self)
36 self.cloud = Cloud(self)
37
38 def set_random_background(self):
39 index = choice(list(set(range(len(self.backgrounds))).\
40 difference(self.used_backgrounds)))
41 self.used_backgrounds.append(index)
42 if len(self.used_backgrounds) > 3:
43 self.used_backgrounds.pop(0)
44 self.background = self.backgrounds[index]
45
46 def respond(self, event):
47 if self.delegate.compare(event, "reset-game"):
48 self.set_random_background()
49
50 def update(self):
51 self.get_screen().blit(self.background, (0, 0))
52 self.title.update()
53 self.cloud.update()
54 self.floor.update()
55 # self.get_screen().fill((0, 0, 0))
56 # self.get_screen().blit(self.message, (100, 100))
57
58
59 class Title(GameChild):
60
61 def __init__(self, parent):
62 GameChild.__init__(self, parent)
63 self.delegate = self.get_delegate()
64 self.preface = Preface(self)
65 self.subscribe(self.respond)
66 self.subscribe(self.respond, MOUSEBUTTONDOWN)
67 self.deactivate()
68
69 def respond(self, event):
70 if self.delegate.is_command(event) and \
71 self.delegate.compare(event, "reset-game"):
72 self.activate()
73 elif self.active:
74 if event.type == MOUSEBUTTONDOWN and event.button == 1:
75 print "left-click"
76
77 def deactivate(self):
78 self.active = True
79
80 def activate(self):
81 self.active = True
82 self.preface.reset()
83
84 def update(self):
85 if self.active:
86 self.preface.update()
87
88
89 class Preface(GameChild, Surface):
90
91 def __init__(self, parent):
92 GameChild.__init__(self, parent)
93 ds = self.ds = self.get_display_surface()
94 w, h = ds.get_width(), int(round(ds.get_width() / 3))
95 Surface.__init__(self, (w, h), SRCALPHA)
96 self.background = Surface((w, h))
97 self.background.fill((0, 0, 0))
98 mask = self.mask = Surface((w, h), SRCALPHA)
99 pixels = PixelArray(mask)
100 for y in xrange(h):
101 alpha = int(round(255 - (float(y) / h) * 255))
102 for x in xrange(w):
103 pixels[x][y] = Color(255, 255, 255, alpha)
104 del pixels
105 self.set_text()
106 self.reset()
107
108 def set_text(self):
109 lines = self.get_configuration("text", "preface").upper()
110 lines = str.replace(lines, "\n", " ")
111 lines = lines.upper().split("/")
112 cc = 0
113 for line in lines:
114 if len(line) > cc:
115 cc = len(line)
116 cw = int(round((self.get_width() - 80) / float(cc)))
117 font = Font(self.get_resource("display", "font"), 12)
118 font.set_bold(True)
119 ch = font.metrics(lines[0][0])[0][3]
120 margin = 24
121 surface = Surface((cw * cc,
122 ch * len(lines) + margin * (len(lines) - 1)),
123 SRCALPHA)
124 text = self.text = Sprite(self, 200)
125 text.display_surface = self
126 magic_word = "PSPPIT"
127 magic_colors = deque(((255, 128, 128), (255, 255, 128), (128, 255, 128),
128 (128, 255, 255), (128, 128, 255),
129 (255, 128, 255)))
130 box_rect = Rect(0, 0, cw, ch)
131 for _ in xrange(len(magic_word)):
132 frame = surface.copy()
133 box_rect.top = 0
134 for line in lines:
135 box_rect.left = 0
136 extra = cc - len(line)
137 space_count = 0
138 for char in line:
139 if char == " ":
140 space_count += 1
141 space_widths = [1 + extra / space_count] * space_count
142 for ii in xrange(len(space_widths)):
143 if ii >= (extra % space_count):
144 break
145 space_widths[ii] += 1
146 magic_word_ii = 0
147 for ii in xrange(len(line)):
148 if line != lines[-1] and line[ii] == " ":
149 box_rect.left += cw * space_widths.pop(-1)
150 else:
151 if (magic_word_ii and \
152 magic_word_ii < len(magic_word)) \
153 or line[ii:ii + len(magic_word)] == magic_word:
154 color = magic_colors[magic_word_ii]
155 magic_word_ii += 1
156 else:
157 color = (255, 255, 255)
158 left = font.render(line[ii], True, (255, 0, 0))
159 frame.blit(left, self.get_glyph_rect(left, box_rect, 0))
160 right = font.render(line[ii], True, (0, 0, 255))
161 frame.blit(right, self.get_glyph_rect(right, box_rect,
162 4))
163 glyph = font.render(line[ii], True, color)
164 frame.blit(glyph, self.get_glyph_rect(glyph, box_rect,
165 2))
166 box_rect.left += cw
167 box_rect.top += ch + margin
168 text.add_frame(frame)
169 magic_colors.rotate(-1)
170 text.location.centerx = self.get_width() / 2
171
172 def get_glyph_rect(self, glyph, box_rect, offset):
173 gr = glyph.get_rect()
174 gr.center = box_rect.center
175 gr.left += offset
176 return gr
177
178 def reset(self):
179 self.text.location.top = self.get_height()
180
181 def update(self):
182 self.text.move(dy=-.5)
183 if self.text.location.bottom < 0:
184 self.reset()
185 self.blit(self.background, (0, 0))
186 self.text.update()
187 self.blit(self.mask, (0, 0), None, BLEND_RGBA_MIN)
188 self.ds.blit(self, (0, 0))
189
190
191 class Floor(Sprite):
192
193 def __init__(self, parent):
194 Sprite.__init__(self, parent, 340)
195 base = load(self.get_resource("image", "brick")).convert()
196 ds = self.ds = self.get_display_surface()
197 surface = Surface((ds.get_width(), 17))
198 for swap in False, True:
199 frame = surface.copy()
200 tile = base.copy()
201 if swap:
202 pixels = PixelArray(tile)
203 foreground, background = pixels[1][1], pixels[0][0]
204 for x in xrange(len(pixels)):
205 for y in xrange(len(pixels[0])):
206 if pixels[x][y] == foreground:
207 pixels[x][y] = background
208 else:
209 pixels[x][y] = foreground
210 del pixels
211 for x in xrange(0, frame.get_width(), tile.get_width()):
212 for y in xrange(0, frame.get_height(), tile.get_height()):
213 frame.blit(tile, (x, y))
214 self.add_frame(frame)
215 self.location.bottom = self.ds.get_height() - 34
216
217
218 class Cloud(GameChild):
219
220 def __init__(self, parent):
221 GameChild.__init__(self, parent)
222 self.ds = self.get_display_surface()
223 layers = self.layers = []
224 base = load(self.get_resource("image", "cloud")).convert_alpha()
225 for ii in xrange(3):
226 layer = Sprite(self)
227 frame = base.copy()
228 pixels = PixelArray(frame)
229 for x in xrange(len(pixels)):
230 for y in xrange(len(pixels[0])):
231 color = Color(*base.unmap_rgb(pixels[x][y]))
232 h, s, l, a = color.hsla
233 color.hsla = int(h), int(s), int(l), \
234 int(a * (.95 * (1 - ii * .15)))
235 pixels[x][y] = color
236 del pixels
237 layer.add_frame(frame)
238 layer.move(ii * 3)
239 layer.location.bottom = self.ds.get_height()
240 layers.append(layer)
241
242 def update(self):
243 fr = self.get_game().floor.location
244 ds = self.ds
245 ds.set_clip(fr.topleft, (ds.get_width(), ds.get_height() - fr.top))
246 for ii, layer in enumerate(self.layers):
247 layer.move(dy=1 + (ii * .5))
248 if layer.location.top > fr.top:
249 layer.location.bottom = ds.get_height() + layer.location.top - \
250 fr.top
251 layer.update()
252 ds.set_clip(None)