1 | #!/usr/bin/env python |
||
2 | # |
||
3 | # libtcod python samples |
||
4 | # This code demonstrates various usages of libtcod modules |
||
5 | # It's in the public domain. |
||
6 | # |
||
7 | from __future__ import division |
||
8 | |||
9 | import os |
||
10 | |||
11 | import math |
||
12 | |||
13 | import numpy as np |
||
14 | import tcod as libtcod |
||
15 | |||
16 | SAMPLE_SCREEN_WIDTH = 46 |
||
17 | SAMPLE_SCREEN_HEIGHT = 20 |
||
18 | SAMPLE_SCREEN_X = 20 |
||
19 | SAMPLE_SCREEN_Y = 10 |
||
20 | font = os.path.join('data/fonts/consolas10x10_gs_tc.png') |
||
21 | libtcod.console_set_custom_font( |
||
22 | font, libtcod.FONT_TYPE_GREYSCALE | libtcod.FONT_LAYOUT_TCOD) |
||
23 | root_console = libtcod.console_init_root(80, 50, "tcod python sample", False) |
||
24 | sample_console = libtcod.console_new(SAMPLE_SCREEN_WIDTH, SAMPLE_SCREEN_HEIGHT) |
||
25 | |||
26 | class Sample(): |
||
27 | def __init__(self, name='', func=None): |
||
28 | self.name = name |
||
29 | self.func = func |
||
30 | |||
31 | def on_enter(self): |
||
32 | pass |
||
33 | |||
34 | def on_draw(self, delta_time): |
||
35 | pass |
||
36 | |||
37 | def on_key(self, key): |
||
38 | pass |
||
39 | |||
40 | def on_mouse(self, mouse): |
||
41 | pass |
||
42 | |||
43 | ############################################# |
||
44 | # true color sample |
||
45 | ############################################# |
||
46 | class TrueColorSample(Sample): |
||
47 | |||
48 | def __init__(self): |
||
49 | self.name = "True colors" |
||
50 | # corner colors |
||
51 | self.colors = np.array([(50, 40, 150), (240, 85, 5), |
||
52 | (50, 35, 240), (10, 200, 130)], dtype=np.int16) |
||
53 | # color shift direction |
||
54 | self.slide_dir = np.array([[1, 1, 1], [-1, -1, 1], |
||
55 | [1, -1, 1], [1, 1, -1]], dtype=np.int16) |
||
56 | # corner indexes |
||
57 | self.corners = np.array([0, 1, 2, 3]) |
||
58 | # sample screen mesh-grid |
||
59 | self.mgrid = np.mgrid[0:1:SAMPLE_SCREEN_HEIGHT * 1j, |
||
60 | 0:1:SAMPLE_SCREEN_WIDTH * 1j] |
||
61 | |||
62 | def on_enter(self): |
||
63 | libtcod.sys_set_fps(0) |
||
64 | sample_console.clear() |
||
65 | |||
66 | def on_draw(self, delta_time): |
||
67 | self.slide_corner_colors() |
||
68 | self.interpolate_corner_colors() |
||
69 | self.darken_background_characters() |
||
70 | self.randomize_sample_conole() |
||
71 | self.print_banner() |
||
72 | |||
73 | def slide_corner_colors(self): |
||
74 | # pick random RGB channels for each corner |
||
75 | rand_channels = np.random.randint(low=0, high=3, size=4) |
||
76 | |||
77 | # shift picked color channels in the direction of slide_dir |
||
78 | self.colors[self.corners, rand_channels] += \ |
||
79 | self.slide_dir[self.corners, rand_channels] * 5 |
||
80 | |||
81 | # reverse slide_dir values when limits are reached |
||
82 | self.slide_dir[self.colors[:] == 255] = -1 |
||
83 | self.slide_dir[self.colors[:] == 0] = 1 |
||
84 | |||
85 | def interpolate_corner_colors(self): |
||
86 | # interpolate corner colors across the sample console |
||
87 | for i in range(3): # for each color channel |
||
88 | left = ((self.colors[2, i] - self.colors[0, i]) * self.mgrid[0] + |
||
89 | self.colors[0, i]) |
||
90 | right = ((self.colors[3, i] - self.colors[1, i]) * self.mgrid[0] + |
||
91 | self.colors[1, i]) |
||
92 | sample_console.bg[:, :, i] = (right - left) * self.mgrid[1] + left |
||
93 | |||
94 | def darken_background_characters(self): |
||
95 | # darken background characters |
||
96 | sample_console.fg[:] = sample_console.bg[:] |
||
97 | sample_console.fg[:] //= 2 |
||
98 | |||
99 | def randomize_sample_conole(self): |
||
100 | # randomize sample console characters |
||
101 | sample_console.ch[:] = np.random.randint( |
||
102 | low=ord('a'), high=ord('z') + 1, |
||
103 | size=sample_console.ch.size, |
||
104 | dtype=np.intc, |
||
105 | ).reshape(sample_console.ch.shape) |
||
106 | |||
107 | def print_banner(self): |
||
108 | # print text on top of samples |
||
109 | sample_console.default_bg = libtcod.grey |
||
110 | sample_console.print_rect( |
||
111 | x=sample_console.width // 2, y=5, |
||
112 | width=sample_console.width - 2, height=sample_console.height - 1, |
||
113 | string="The Doryen library uses 24 bits colors, for both " |
||
114 | "background and foreground.", |
||
115 | bg_blend=libtcod.BKGND_MULTIPLY, alignment=libtcod.CENTER, |
||
116 | ) |
||
117 | |||
118 | ############################################# |
||
119 | # offscreen console sample |
||
120 | ############################################# |
||
121 | |||
122 | class OffscreenConsoleSample(Sample): |
||
123 | |||
124 | def __init__(self): |
||
125 | self.name = 'Offscreen console' |
||
126 | self.secondary = libtcod.console.Console(sample_console.width // 2, |
||
127 | sample_console.height // 2) |
||
128 | self.screenshot = libtcod.console.Console(sample_console.width, |
||
129 | sample_console.height) |
||
130 | self.counter = 0 |
||
131 | self.x = 0 |
||
132 | self.y = 0 |
||
133 | self.xdir = 1 |
||
134 | self.ydir = 1 |
||
135 | |||
136 | self.secondary.print_frame( |
||
137 | 0, 0, sample_console.width // 2, sample_console.height // 2, |
||
138 | "Offscreen console", |
||
139 | False, |
||
140 | libtcod.BKGND_NONE |
||
141 | ) |
||
142 | |||
143 | self.secondary.print_rect( |
||
144 | sample_console.width // 4, 2, |
||
145 | sample_console.width // 2 - 2, sample_console.height // 2, |
||
146 | "You can render to an offscreen console and blit in on another " |
||
147 | "one, simulating alpha transparency.", |
||
148 | libtcod.BKGND_NONE, libtcod.CENTER |
||
149 | ) |
||
150 | |||
151 | def on_enter(self): |
||
152 | libtcod.sys_set_fps(0) |
||
153 | # get a "screenshot" of the current sample screen |
||
154 | sample_console.blit(0, 0, sample_console.width, sample_console.height, |
||
155 | self.screenshot, 0, 0) |
||
156 | |||
157 | def on_draw(self, delta_time): |
||
158 | self.counter += delta_time * 1.5 |
||
159 | if self.counter >= 1: |
||
160 | self.counter -= 1 |
||
161 | self.x += self.xdir |
||
162 | self.y += self.ydir |
||
163 | if self.x == sample_console.width / 2 + 5: |
||
164 | self.xdir = -1 |
||
165 | elif self.x == -5: |
||
166 | self.xdir = 1 |
||
167 | if self.y == sample_console.height / 2 + 5: |
||
168 | self.ydir = -1 |
||
169 | elif self.y == -5: |
||
170 | self.ydir = 1 |
||
171 | self.screenshot.blit(0, 0, sample_console.width, sample_console.height, |
||
172 | sample_console, 0, 0) |
||
173 | self.secondary.blit( |
||
174 | 0, 0, sample_console.width // 2, sample_console.height // 2, |
||
175 | sample_console, self.x, self.y, 1.0, 0.75 |
||
176 | ) |
||
177 | |||
178 | ############################################# |
||
179 | # line drawing sample |
||
180 | ############################################# |
||
181 | |||
182 | class LineDrawingSample(Sample): |
||
183 | |||
184 | FLAG_NAMES = [ |
||
185 | 'BKGND_NONE', |
||
186 | 'BKGND_SET', |
||
187 | 'BKGND_MULTIPLY', |
||
188 | 'BKGND_LIGHTEN', |
||
189 | 'BKGND_DARKEN', |
||
190 | 'BKGND_SCREEN', |
||
191 | 'BKGND_COLOR_DODGE', |
||
192 | 'BKGND_COLOR_BURN', |
||
193 | 'BKGND_ADD', |
||
194 | 'BKGND_ADDALPHA', |
||
195 | 'BKGND_BURN', |
||
196 | 'BKGND_OVERLAY', |
||
197 | 'BKGND_ALPHA', |
||
198 | ] |
||
199 | |||
200 | def __init__(self): |
||
201 | self.name = 'Line drawing' |
||
202 | self.mk_flag = libtcod.BKGND_SET |
||
203 | self.bk_flag = libtcod.BKGND_SET |
||
204 | |||
205 | self.bk = libtcod.console_new(sample_console.width, |
||
206 | sample_console.height) |
||
207 | # initialize the colored background |
||
208 | for x in range(sample_console.width): |
||
209 | for y in range(sample_console.height): |
||
210 | col = libtcod.Color( |
||
211 | x * 255 // (sample_console.width - 1), |
||
212 | (x + y) * 255 // (sample_console.width - 1 + |
||
213 | sample_console.height - 1), |
||
214 | y * 255 // (sample_console.height-1), |
||
215 | ) |
||
216 | self.bk.bg[y, x] = col |
||
217 | self.bk.ch[:] = ord(' ') |
||
218 | |||
219 | |||
220 | def on_key(self, key): |
||
221 | if key.vk in (libtcod.KEY_ENTER, libtcod.KEY_KPENTER): |
||
222 | self.bk_flag += 1 |
||
223 | if (self.bk_flag & 0xff) > libtcod.BKGND_ALPH: |
||
224 | self.bk_flag = libtcod.BKGND_NONE |
||
225 | |||
226 | def on_enter(self): |
||
227 | libtcod.sys_set_fps(0) |
||
228 | libtcod.console_set_default_foreground(sample_console, libtcod.white) |
||
229 | |||
230 | def on_draw(self, delta_time): |
||
231 | alpha = 0.0 |
||
232 | if (self.bk_flag & 0xff) == libtcod.BKGND_ALPH: |
||
233 | # for the alpha mode, update alpha every frame |
||
234 | alpha = (1.0 + math.cos(libtcod.sys_elapsed_seconds() * 2)) / 2.0 |
||
235 | self.bk_flag = libtcod.BKGND_ALPHA(alpha) |
||
236 | elif (self.bk_flag & 0xff) == libtcod.BKGND_ADDA: |
||
237 | # for the add alpha mode, update alpha every frame |
||
238 | alpha = (1.0 + math.cos(libtcod.sys_elapsed_seconds() * 2)) / 2.0 |
||
239 | self.bk_flag = libtcod.BKGND_ADDALPHA(alpha) |
||
240 | |||
241 | self.bk.blit(0, 0, sample_console.width, |
||
242 | sample_console.height, sample_console, 0, 0) |
||
243 | recty = int((sample_console.height - 2) |
||
244 | * ((1.0 + math.cos(libtcod.sys_elapsed_seconds())) / 2.0)) |
||
245 | for x in range(sample_console.width): |
||
246 | col = libtcod.Color(x * 255 // sample_console.width, |
||
247 | x * 255 // sample_console.width, |
||
248 | x * 255 // sample_console.width) |
||
249 | libtcod.console_set_char_background( |
||
250 | sample_console, x, recty, col, self.bk_flag) |
||
251 | libtcod.console_set_char_background( |
||
252 | sample_console, x, recty + 1, col, self.bk_flag) |
||
253 | libtcod.console_set_char_background( |
||
254 | sample_console, x, recty + 2, col, self.bk_flag) |
||
255 | angle = libtcod.sys_elapsed_seconds() * 2.0 |
||
256 | cos_angle = math.cos(angle) |
||
257 | sin_angle = math.sin(angle) |
||
258 | xo = int(sample_console.width // 2 * (1 + cos_angle)) |
||
259 | yo = int(sample_console.height // 2 |
||
260 | + sin_angle * sample_console.width // 2) |
||
261 | xd = int(sample_console.width // 2 * (1 - cos_angle)) |
||
262 | yd = int(sample_console.height // 2 |
||
263 | - sin_angle * sample_console.width // 2) |
||
264 | # draw the line |
||
265 | # in python the easiest way is to use the line iterator |
||
266 | for x, y in libtcod.line_iter(xo, yo, xd, yd): |
||
267 | if 0 <= x < sample_console.width and \ |
||
268 | 0 <= y < sample_console.height: |
||
269 | libtcod.console_set_char_background( |
||
270 | sample_console, x, y, libtcod.light_blue, self.bk_flag) |
||
271 | sample_console.print_( |
||
272 | 2, 2, |
||
273 | '%s (ENTER to change)' % self.FLAG_NAMES[self.bk_flag & 0xff] |
||
274 | ) |
||
275 | |||
276 | ############################################# |
||
277 | # noise sample |
||
278 | ############################################# |
||
279 | |||
280 | NOISE_OPTIONS = [ # [name, algorithm, implementation], |
||
281 | ['perlin noise', libtcod.NOISE_PERLIN, libtcod.noise.SIMPLE], |
||
282 | ['simplex noise', libtcod.NOISE_SIMPLEX, libtcod.noise.SIMPLE], |
||
283 | ['wavelet noise', libtcod.NOISE_WAVELET, libtcod.noise.SIMPLE], |
||
284 | ['perlin fbm', libtcod.NOISE_PERLIN, libtcod.noise.FBM], |
||
285 | ['perlin turbulence', libtcod.NOISE_PERLIN, libtcod.noise.TURBULENCE], |
||
286 | ['simplex fbm', libtcod.NOISE_SIMPLEX, libtcod.noise.FBM], |
||
287 | ['simplex turbulence', |
||
288 | libtcod.NOISE_SIMPLEX, libtcod.noise.TURBULENCE], |
||
289 | ['wavelet fbm', libtcod.NOISE_WAVELET, libtcod.noise.FBM], |
||
290 | ['wavelet turbulence', |
||
291 | libtcod.NOISE_WAVELET, libtcod.noise.TURBULENCE], |
||
292 | ] |
||
293 | |||
294 | class NoiseSample(Sample): |
||
295 | |||
296 | def __init__(self): |
||
297 | self.name = 'Noise' |
||
298 | self.func = 0 |
||
299 | self.dx = 0.0 |
||
300 | self.dy = 0.0 |
||
301 | self.octaves = 4.0 |
||
302 | self.zoom = 3.0 |
||
303 | self.hurst = libtcod.NOISE_DEFAULT_HURST |
||
304 | self.lacunarity = libtcod.NOISE_DEFAULT_LACUNARITY |
||
305 | self.noise = self.get_noise() |
||
306 | self.img = libtcod.image_new(SAMPLE_SCREEN_WIDTH * 2, |
||
307 | SAMPLE_SCREEN_HEIGHT * 2) |
||
308 | |||
309 | @property |
||
310 | def algorithm(self): |
||
311 | return NOISE_OPTIONS[self.func][1] |
||
312 | |||
313 | @property |
||
314 | def implementation(self): |
||
315 | return NOISE_OPTIONS[self.func][2] |
||
316 | |||
317 | def get_noise(self): |
||
318 | return libtcod.noise.Noise( |
||
319 | 2, |
||
320 | self.algorithm, |
||
321 | self.implementation, |
||
322 | self.hurst, |
||
323 | self.lacunarity, |
||
324 | self.octaves, |
||
325 | seed=None, |
||
326 | ) |
||
327 | |||
328 | def on_enter(self): |
||
329 | libtcod.sys_set_fps(0) |
||
330 | |||
331 | def on_draw(self, delta_time): |
||
332 | sample_console.clear() |
||
333 | self.dx += delta_time * 0.25 |
||
334 | self.dy += delta_time * 0.25 |
||
335 | for y in range(2 * sample_console.height): |
||
336 | for x in range(2 * sample_console.width): |
||
337 | f = [self.zoom * x / (2 * sample_console.width) + self.dx, |
||
338 | self.zoom * y / (2 * sample_console.height) + self.dy] |
||
339 | value = self.noise.get_point(*f) |
||
340 | c = int((value + 1.0) / 2.0 * 255) |
||
341 | c = max(0, min(c, 255)) |
||
342 | self.img.put_pixel(x, y, (c // 2, c // 2, c)) |
||
343 | sample_console.default_bg = libtcod.grey |
||
344 | rectw = 24 |
||
345 | recth = 13 |
||
346 | if self.implementation == libtcod.noise.SIMPLE: |
||
347 | recth = 10 |
||
348 | self.img.blit_2x(sample_console, 0, 0) |
||
349 | sample_console.default_bg = libtcod.grey |
||
350 | sample_console.rect(2, 2, rectw, recth, False, libtcod.BKGND_MULTIPLY) |
||
351 | sample_console.fg[2:2+recth, 2:2+rectw] = \ |
||
352 | (sample_console.fg[2:2+recth, 2:2+rectw] * |
||
353 | sample_console.default_bg / 255) |
||
354 | |||
355 | for curfunc in range(len(NOISE_OPTIONS)): |
||
356 | text = '%i : %s' % (curfunc + 1, NOISE_OPTIONS[curfunc][0]) |
||
357 | if curfunc == self.func: |
||
358 | sample_console.default_fg = libtcod.white |
||
359 | sample_console.default_bg = libtcod.light_blue |
||
360 | sample_console.print_(2, 2 + curfunc, text, |
||
361 | libtcod.BKGND_SET, libtcod.LEFT) |
||
362 | else: |
||
363 | sample_console.default_fg = libtcod.grey |
||
364 | sample_console.print_(2, 2 + curfunc, text) |
||
365 | sample_console.default_fg = libtcod.white |
||
366 | sample_console.print_(2, 11, 'Y/H : zoom (%2.1f)' % self.zoom) |
||
367 | if self.implementation != libtcod.noise.SIMPLE: |
||
368 | sample_console.print_(2, 12, 'E/D : hurst (%2.1f)' % self.hurst) |
||
369 | sample_console.print_(2, 13, |
||
370 | 'R/F : lacunarity (%2.1f)' % |
||
371 | self.lacunarity) |
||
372 | sample_console.print_(2, 14, |
||
373 | 'T/G : octaves (%2.1f)' % self.octaves) |
||
374 | |||
375 | def on_key(self, key): |
||
376 | if key.vk == libtcod.KEY_NONE: |
||
377 | return |
||
378 | if ord('9') >= key.c >= ord('1'): |
||
379 | self.func = key.c - ord('1') |
||
380 | self.noise = self.get_noise() |
||
381 | elif key.c in (ord('E'), ord('e')): |
||
382 | self.hurst += 0.1 |
||
383 | self.noise = self.get_noise() |
||
384 | elif key.c in (ord('D'), ord('d')): |
||
385 | self.hurst -= 0.1 |
||
386 | self.noise = self.get_noise() |
||
387 | elif key.c in (ord('R'), ord('r')): |
||
388 | self.lacunarity += 0.5 |
||
389 | self.noise = self.get_noise() |
||
390 | elif key.c in (ord('F'), ord('f')): |
||
391 | self.lacunarity -= 0.5 |
||
392 | self.noise = self.get_noise() |
||
393 | elif key.c in (ord('T'), ord('t')): |
||
394 | self.octaves += 0.5 |
||
395 | self.noise.octaves = self.octaves |
||
396 | elif key.c in (ord('G'), ord('g')): |
||
397 | self.octaves -= 0.5 |
||
398 | self.noise.octaves = self.octaves |
||
399 | elif key.c in (ord('Y'), ord('y')): |
||
400 | self.zoom += 0.2 |
||
401 | elif key.c in (ord('H'), ord('h')): |
||
402 | self.zoom -= 0.2 |
||
403 | |||
404 | ############################################# |
||
405 | # field of view sample |
||
406 | ############################################# |
||
407 | DARK_WALL = libtcod.Color(0, 0, 100) |
||
408 | LIGHT_WALL = libtcod.Color(130, 110, 50) |
||
409 | DARK_GROUND = libtcod.Color(50, 50, 150) |
||
410 | LIGHT_GROUND = libtcod.Color(200, 180, 50) |
||
411 | |||
412 | SAMPLE_MAP = [ |
||
413 | '##############################################', |
||
414 | '####################### #################', |
||
415 | '##################### # ###############', |
||
416 | '###################### ### ###########', |
||
417 | '################## ##### ####', |
||
418 | '################ ######## ###### ####', |
||
419 | '############### #################### ####', |
||
420 | '################ ###### ##', |
||
421 | '######## ####### ###### # # # ##', |
||
422 | '######## ###### ### ##', |
||
423 | '######## ##', |
||
424 | '#### ###### ### # # # ##', |
||
425 | '#### ### ########## #### ##', |
||
426 | '#### ### ########## ###########=##########', |
||
427 | '#### ################## ##### #####', |
||
428 | '#### ### #### ##### #####', |
||
429 | '#### # #### #####', |
||
430 | '######## # #### ##### #####', |
||
431 | '######## ##### ####################', |
||
432 | '##############################################', |
||
433 | ] |
||
434 | |||
435 | SAMPLE_MAP = np.array([list(line) for line in SAMPLE_MAP]) |
||
436 | |||
437 | FOV_ALGO_NAMES = [ |
||
438 | 'BASIC ', |
||
439 | 'DIAMOND ', |
||
440 | 'SHADOW ', |
||
441 | 'PERMISSIVE0', |
||
442 | 'PERMISSIVE1', |
||
443 | 'PERMISSIVE2', |
||
444 | 'PERMISSIVE3', |
||
445 | 'PERMISSIVE4', |
||
446 | 'PERMISSIVE5', |
||
447 | 'PERMISSIVE6', |
||
448 | 'PERMISSIVE7', |
||
449 | 'PERMISSIVE8', |
||
450 | 'RESTRICTIVE', |
||
451 | ] |
||
452 | |||
453 | TORCH_RADIUS = 10 |
||
454 | SQUARED_TORCH_RADIUS = TORCH_RADIUS * TORCH_RADIUS |
||
455 | |||
456 | class FOVSample(Sample): |
||
457 | |||
458 | def __init__(self): |
||
459 | self.name = 'Field of view' |
||
460 | |||
461 | self.px = 20 |
||
462 | self.py = 10 |
||
463 | self.recompute = True |
||
464 | self.torch = False |
||
465 | self.map = None |
||
466 | self.noise = None |
||
467 | self.torchx = 0.0 |
||
468 | self.light_walls = True |
||
469 | self.algo_num = 0 |
||
470 | # 1d noise for the torch flickering |
||
471 | self.noise = libtcod.noise_new(1, 1.0, 1.0) |
||
472 | |||
473 | self.map = libtcod.map_new(SAMPLE_SCREEN_WIDTH, SAMPLE_SCREEN_HEIGHT) |
||
474 | self.map.walkable[:] = SAMPLE_MAP[:] == ' ' |
||
475 | self.map.transparent[:] = self.map.walkable[:] | (SAMPLE_MAP == '=') |
||
476 | |||
477 | self.light_map_bg = np.full(SAMPLE_MAP.shape + (3,), LIGHT_GROUND, |
||
478 | dtype=np.uint8) |
||
479 | self.light_map_bg[SAMPLE_MAP[:] == '#'] = LIGHT_WALL |
||
480 | self.dark_map_bg = np.full(SAMPLE_MAP.shape + (3,), DARK_GROUND, |
||
481 | dtype=np.uint8) |
||
482 | self.dark_map_bg[SAMPLE_MAP[:] == '#'] = DARK_WALL |
||
483 | |||
484 | def draw_ui(self): |
||
485 | libtcod.console_set_default_foreground(sample_console, libtcod.white) |
||
486 | libtcod.console_print( |
||
487 | sample_console, 1, 1, |
||
488 | "IJKL : move around\n" |
||
489 | "T : torch fx %s\n" |
||
490 | "W : light walls %s\n" |
||
491 | "+-: algo %s" % ('on ' if self.torch else 'off', |
||
492 | 'on ' if self.light_walls else 'off', |
||
493 | FOV_ALGO_NAMES[self.algo_num], |
||
494 | ), |
||
495 | ) |
||
496 | libtcod.console_set_default_foreground(sample_console, libtcod.black) |
||
497 | |||
498 | def on_enter(self): |
||
499 | libtcod.sys_set_fps(60) |
||
500 | # we draw the foreground only the first time. |
||
501 | # during the player movement, only the @ is redrawn. |
||
502 | # the rest impacts only the background color |
||
503 | # draw the help text & player @ |
||
504 | libtcod.console_clear(sample_console) |
||
505 | self.draw_ui() |
||
506 | libtcod.console_put_char(sample_console, self.px, self.py, '@', |
||
507 | libtcod.BKGND_NONE) |
||
508 | # draw windows |
||
509 | sample_console.ch[np.where(SAMPLE_MAP == '=')] = libtcod.CHAR_DHLINE |
||
510 | sample_console.fg[np.where(SAMPLE_MAP == '=')] = libtcod.black |
||
511 | |||
512 | def on_draw(self, delta_time): |
||
513 | dx = 0.0 |
||
514 | dy = 0.0 |
||
515 | di = 0.0 |
||
516 | if self.recompute: |
||
517 | self.recompute = False |
||
518 | self.map.compute_fov( |
||
519 | self.px, |
||
520 | self.py, |
||
521 | TORCH_RADIUS if self.torch else 0, |
||
522 | self.light_walls, |
||
523 | self.algo_num |
||
524 | ) |
||
525 | sample_console.bg[:] = self.dark_map_bg[:] |
||
526 | if self.torch: |
||
527 | # slightly change the perlin noise parameter |
||
528 | self.torchx += 0.1 |
||
529 | # randomize the light position between -1.5 and 1.5 |
||
530 | tdx = [self.torchx + 20.0] |
||
531 | dx = libtcod.noise_get(self.noise, tdx, |
||
532 | libtcod.NOISE_SIMPLEX) * 1.5 |
||
533 | tdx[0] += 30.0 |
||
534 | dy = libtcod.noise_get(self.noise, tdx, |
||
535 | libtcod.NOISE_SIMPLEX) * 1.5 |
||
536 | di = 0.2 * libtcod.noise_get(self.noise, [self.torchx], |
||
537 | libtcod.NOISE_SIMPLEX) |
||
538 | #where_fov = np.where(self.map.fov[:]) |
||
539 | mgrid = np.mgrid[:SAMPLE_SCREEN_HEIGHT, :SAMPLE_SCREEN_WIDTH] |
||
540 | # get squared distance |
||
541 | light = ((mgrid[0] - self.py + dy) ** 2 + |
||
542 | (mgrid[1] - self.px + dx) ** 2) |
||
543 | light = light.astype(np.float16) |
||
544 | where_visible = np.where((light < SQUARED_TORCH_RADIUS) & |
||
545 | self.map.fov[:]) |
||
546 | light[where_visible] = SQUARED_TORCH_RADIUS - light[where_visible] |
||
547 | light[where_visible] /= SQUARED_TORCH_RADIUS |
||
548 | light[where_visible] += di |
||
549 | light[where_visible] = light[where_visible].clip(0, 1) |
||
550 | |||
551 | for yx in zip(*where_visible): |
||
552 | sample_console.bg[yx] = libtcod.color_lerp( |
||
553 | tuple(self.dark_map_bg[yx]), |
||
554 | tuple(self.light_map_bg[yx]), |
||
555 | light[yx], |
||
556 | ) |
||
557 | else: |
||
558 | where_fov = np.where(self.map.fov[:]) |
||
559 | sample_console.bg[where_fov] = self.light_map_bg[where_fov] |
||
560 | |||
561 | |||
562 | def on_key(self, key): |
||
563 | MOVE_KEYS = { |
||
564 | ord('i'): (0, -1), |
||
565 | ord('j'): (-1, 0), |
||
566 | ord('k'): (0, 1), |
||
567 | ord('l'): (1, 0), |
||
568 | } |
||
569 | FOV_SELECT_KEYS = {ord('-'): -1, ord('='): 1} |
||
570 | if key.c in MOVE_KEYS: |
||
571 | x, y = MOVE_KEYS[key.c] |
||
572 | if SAMPLE_MAP[self.py + y][self.px + x] == ' ': |
||
573 | libtcod.console_put_char(sample_console, self.px, self.py, ' ', |
||
574 | libtcod.BKGND_NONE) |
||
575 | self.px += x |
||
576 | self.py += y |
||
577 | libtcod.console_put_char(sample_console, self.px, self.py, '@', |
||
578 | libtcod.BKGND_NONE) |
||
579 | self.recompute = True |
||
580 | elif key.c == ord('t'): |
||
581 | self.torch = not self.torch |
||
582 | self.draw_ui() |
||
583 | self.recompute = True |
||
584 | elif key.c == ord('w'): |
||
585 | self.light_walls = not self.light_walls |
||
586 | self.draw_ui() |
||
587 | self.recompute = True |
||
588 | elif key.c in FOV_SELECT_KEYS: |
||
589 | self.algo_num += FOV_SELECT_KEYS[key.c] |
||
590 | self.algo_num %= libtcod.NB_FOV_ALGORITHMS |
||
591 | self.draw_ui() |
||
592 | self.recompute = True |
||
593 | |||
594 | ############################################# |
||
595 | # pathfinding sample |
||
596 | ############################################# |
||
597 | |||
598 | class PathfindingSample(Sample): |
||
599 | def __init__(self): |
||
600 | self.name = 'Path finding' |
||
601 | |||
602 | self.px = 20 |
||
603 | self.py = 10 |
||
604 | self.dx = 24 |
||
605 | self.dy = 1 |
||
606 | self.map = None |
||
607 | self.path = None |
||
608 | self.dijk_dist = 0.0 |
||
609 | self.using_astar = True |
||
610 | self.dijk = None |
||
611 | self.recalculate = False |
||
612 | self.busy = 0.0 |
||
613 | self.oldchar = ' ' |
||
614 | |||
615 | self.map = libtcod.map_new(SAMPLE_SCREEN_WIDTH, SAMPLE_SCREEN_HEIGHT) |
||
616 | for y in range(SAMPLE_SCREEN_HEIGHT): |
||
617 | for x in range(SAMPLE_SCREEN_WIDTH): |
||
618 | if SAMPLE_MAP[y][x] == ' ': |
||
619 | # ground |
||
620 | libtcod.map_set_properties(self.map, x, y, True, True) |
||
621 | elif SAMPLE_MAP[y][x] == '=': |
||
622 | # window |
||
623 | libtcod.map_set_properties(self.map, x, y, True, False) |
||
624 | self.path = libtcod.path_new_using_map(self.map) |
||
625 | self.dijk = libtcod.dijkstra_new(self.map) |
||
626 | |||
627 | def on_enter(self): |
||
628 | libtcod.sys_set_fps(60) |
||
629 | # we draw the foreground only the first time. |
||
630 | # during the player movement, only the @ is redrawn. |
||
631 | # the rest impacts only the background color |
||
632 | # draw the help text & player @ |
||
633 | libtcod.console_clear(sample_console) |
||
634 | libtcod.console_set_default_foreground(sample_console, libtcod.white) |
||
635 | libtcod.console_put_char(sample_console, self.dx, self.dy, '+', |
||
636 | libtcod.BKGND_NONE) |
||
637 | libtcod.console_put_char(sample_console, self.px, self.py, '@', |
||
638 | libtcod.BKGND_NONE) |
||
639 | libtcod.console_print( |
||
640 | sample_console, 1, 1, |
||
641 | "IJKL / mouse :\nmove destination\nTAB : A*/dijkstra") |
||
642 | libtcod.console_print(sample_console, 1, 4, "Using : A*") |
||
643 | # draw windows |
||
644 | for y in range(SAMPLE_SCREEN_HEIGHT): |
||
645 | for x in range(SAMPLE_SCREEN_WIDTH): |
||
646 | if SAMPLE_MAP[y][x] == '=': |
||
647 | libtcod.console_put_char(sample_console, x, y, |
||
648 | libtcod.CHAR_DHLINE, |
||
649 | libtcod.BKGND_NONE) |
||
650 | self.recalculate = True |
||
651 | |||
652 | def on_draw(self, delta_time): |
||
653 | if self.recalculate: |
||
654 | if self.using_astar: |
||
655 | libtcod.path_compute(self.path, self.px, self.py, |
||
656 | self.dx, self.dy) |
||
657 | else: |
||
658 | self.dijk_dist = 0.0 |
||
659 | # compute dijkstra grid (distance from px,py) |
||
660 | libtcod.dijkstra_compute(self.dijk, self.px, self.py) |
||
661 | # get the maximum distance (needed for rendering) |
||
662 | for y in range(SAMPLE_SCREEN_HEIGHT): |
||
663 | for x in range(SAMPLE_SCREEN_WIDTH): |
||
664 | d = libtcod.dijkstra_get_distance(self.dijk, x, y) |
||
665 | if d > self.dijk_dist: |
||
666 | self.dijk_dist = d |
||
667 | # compute path from px,py to dx,dy |
||
668 | libtcod.dijkstra_path_set(self.dijk, self.dx, self.dy) |
||
669 | self.recalculate = False |
||
670 | View Code Duplication | self.busy = 0.2 |
|
0 ignored issues
–
show
Duplication
introduced
by
![]() |
|||
671 | # draw the dungeon |
||
672 | for y in range(SAMPLE_SCREEN_HEIGHT): |
||
673 | for x in range(SAMPLE_SCREEN_WIDTH): |
||
674 | if SAMPLE_MAP[y][x] == '#': |
||
675 | libtcod.console_set_char_background( |
||
676 | sample_console, x, y, DARK_WALL, libtcod.BKGND_SET) |
||
677 | else: |
||
678 | libtcod.console_set_char_background( |
||
679 | sample_console, x, y, DARK_GROUND, libtcod.BKGND_SET) |
||
680 | # draw the path |
||
681 | if self.using_astar: |
||
682 | for i in range(libtcod.path_size(self.path)): |
||
683 | x, y = libtcod.path_get(self.path, i) |
||
684 | libtcod.console_set_char_background( |
||
685 | sample_console, x, y, LIGHT_GROUND, libtcod.BKGND_SET) |
||
686 | else: |
||
687 | for y in range(SAMPLE_SCREEN_HEIGHT): |
||
688 | for x in range(SAMPLE_SCREEN_WIDTH): |
||
689 | if SAMPLE_MAP[y][x] != '#': |
||
690 | libtcod.console_set_char_background( |
||
691 | sample_console, x, y, |
||
692 | libtcod.color_lerp( |
||
693 | LIGHT_GROUND, DARK_GROUND, |
||
694 | 0.9* libtcod.dijkstra_get_distance(self.dijk, |
||
695 | x, y) |
||
696 | / self.dijk_dist), |
||
697 | libtcod.BKGND_SET, |
||
698 | ) |
||
699 | for i in range(libtcod.dijkstra_size(self.dijk)): |
||
700 | x, y = libtcod.dijkstra_get(self.dijk, i) |
||
701 | libtcod.console_set_char_background( |
||
702 | sample_console, x, y, LIGHT_GROUND, libtcod.BKGND_SET) |
||
703 | |||
704 | # move the creature |
||
705 | self.busy -= libtcod.sys_get_last_frame_length() |
||
706 | if self.busy <= 0.0: |
||
707 | self.busy = 0.2 |
||
708 | if self.using_astar: |
||
709 | if not libtcod.path_is_empty(self.path): |
||
710 | libtcod.console_put_char(sample_console, self.px, self.py, |
||
711 | ' ', libtcod.BKGND_NONE) |
||
712 | self.px, self.py = libtcod.path_walk(self.path, True) |
||
713 | libtcod.console_put_char(sample_console, self.px, self.py, |
||
714 | '@', libtcod.BKGND_NONE) |
||
715 | else: |
||
716 | if not libtcod.dijkstra_is_empty(self.dijk): |
||
717 | libtcod.console_put_char(sample_console, self.px, self.py, |
||
718 | ' ', libtcod.BKGND_NONE) |
||
719 | self.px, self.py = libtcod.dijkstra_path_walk(self.dijk) |
||
720 | libtcod.console_put_char(sample_console, self.px, self.py, |
||
721 | '@', libtcod.BKGND_NONE) |
||
722 | self.recalculate = True |
||
723 | |||
724 | def on_key(self, key): |
||
725 | if key.c in (ord('I'), ord('i')) and self.dy > 0: |
||
726 | # destination move north |
||
727 | libtcod.console_put_char(sample_console, self.dx, self.dy, |
||
728 | self.oldchar, libtcod.BKGND_NONE) |
||
729 | self.dy -= 1 |
||
730 | self.oldchar = libtcod.console_get_char(sample_console, self.dx, |
||
731 | self.dy) |
||
732 | libtcod.console_put_char(sample_console, self.dx, self.dy, '+', |
||
733 | libtcod.BKGND_NONE) |
||
734 | if SAMPLE_MAP[self.dy][self.dx] == ' ': |
||
735 | self.recalculate = True |
||
736 | elif (key.c in (ord('K'), ord('k')) |
||
737 | and self.dy < SAMPLE_SCREEN_HEIGHT - 1): |
||
738 | # destination move south |
||
739 | libtcod.console_put_char(sample_console, self.dx, self.dy, |
||
740 | self.oldchar, libtcod.BKGND_NONE) |
||
741 | self.dy += 1 |
||
742 | self.oldchar = libtcod.console_get_char(sample_console, self.dx, |
||
743 | self.dy) |
||
744 | libtcod.console_put_char(sample_console, self.dx, self.dy, '+', |
||
745 | libtcod.BKGND_NONE) |
||
746 | if SAMPLE_MAP[self.dy][self.dx] == ' ': |
||
747 | self.recalculate = True |
||
748 | elif key.c in (ord('J'), ord('j')) and self.dx > 0: |
||
749 | # destination move west |
||
750 | libtcod.console_put_char(sample_console, self.dx, self.dy, |
||
751 | self.oldchar, libtcod.BKGND_NONE) |
||
752 | self.dx -= 1 |
||
753 | self.oldchar = libtcod.console_get_char(sample_console, self.dx, |
||
754 | self.dy) |
||
755 | libtcod.console_put_char(sample_console, self.dx, self.dy, '+', |
||
756 | libtcod.BKGND_NONE) |
||
757 | if SAMPLE_MAP[self.dy][self.dx] == ' ': |
||
758 | self.recalculate = True |
||
759 | elif (key.c in (ord('L'), ord('l')) and |
||
760 | self.dx < SAMPLE_SCREEN_WIDTH - 1): |
||
761 | # destination move east |
||
762 | libtcod.console_put_char(sample_console, self.dx, self.dy, |
||
763 | self.oldchar, libtcod.BKGND_NONE) |
||
764 | self.dx += 1 |
||
765 | self.oldchar = libtcod.console_get_char(sample_console, self.dx, |
||
766 | self.dy) |
||
767 | libtcod.console_put_char(sample_console, self.dx, self.dy, '+', |
||
768 | libtcod.BKGND_NONE) |
||
769 | if SAMPLE_MAP[self.dy][self.dx] == ' ': |
||
770 | self.recalculate = True |
||
771 | elif key.vk == libtcod.KEY_TAB: |
||
772 | self.using_astar = not self.using_astar |
||
773 | if self.using_astar: |
||
774 | libtcod.console_print(sample_console, 1, 4, "Using : A* ") |
||
775 | else: |
||
776 | libtcod.console_print(sample_console, 1, 4, "Using : Dijkstra") |
||
777 | self.recalculate = True |
||
778 | |||
779 | def on_mouse(self, mouse): |
||
780 | mx = mouse.cx - SAMPLE_SCREEN_X |
||
781 | my = mouse.cy - SAMPLE_SCREEN_Y |
||
782 | if (0 <= mx < SAMPLE_SCREEN_WIDTH and 0 <= my < SAMPLE_SCREEN_HEIGHT |
||
783 | and (self.dx != mx or self.dy != my)): |
||
784 | libtcod.console_put_char(sample_console, self.dx, self.dy, |
||
785 | self.oldchar, libtcod.BKGND_NONE) |
||
786 | self.dx = mx |
||
787 | self.dy = my |
||
788 | self.oldchar = libtcod.console_get_char(sample_console, self.dx, |
||
789 | self.dy) |
||
790 | libtcod.console_put_char(sample_console, self.dx, self.dy, '+', |
||
791 | libtcod.BKGND_NONE) |
||
792 | if SAMPLE_MAP[self.dy][self.dx] == ' ': |
||
793 | self.recalculate = True |
||
794 | |||
795 | ############################################# |
||
796 | # bsp sample |
||
797 | ############################################# |
||
798 | bsp_depth = 8 |
||
799 | bsp_min_room_size = 4 |
||
800 | # a room fills a random part of the node or the maximum available space ? |
||
801 | bsp_random_room = False |
||
802 | # if true, there is always a wall on north & west side of a room |
||
803 | bsp_room_walls = True |
||
804 | bsp_map = None |
||
805 | # draw a vertical line |
||
806 | def vline(m, x, y1, y2): |
||
807 | if y1 > y2: |
||
808 | y1, y2 = y2, y1 |
||
809 | for y in range(y1, y2 + 1): |
||
810 | m[x][y] = True |
||
811 | |||
812 | # draw a vertical line up until we reach an empty space |
||
813 | def vline_up(m, x, y): |
||
814 | while y >= 0 and not m[x][y]: |
||
815 | m[x][y] = True |
||
816 | y -= 1 |
||
817 | |||
818 | # draw a vertical line down until we reach an empty space |
||
819 | def vline_down(m, x, y): |
||
820 | while y < SAMPLE_SCREEN_HEIGHT and not m[x][y]: |
||
821 | m[x][y] = True |
||
822 | y += 1 |
||
823 | |||
824 | # draw a horizontal line |
||
825 | View Code Duplication | def hline(m, x1, y, x2): |
|
0 ignored issues
–
show
|
|||
826 | if x1 > x2: |
||
827 | x1, x2 = x2, x1 |
||
828 | for x in range(x1, x2 + 1): |
||
829 | m[x][y] = True |
||
830 | |||
831 | # draw a horizontal line left until we reach an empty space |
||
832 | def hline_left(m, x, y): |
||
833 | while x >= 0 and not m[x][y]: |
||
834 | m[x][y] = True |
||
835 | x -= 1 |
||
836 | |||
837 | # draw a horizontal line right until we reach an empty space |
||
838 | def hline_right(m, x, y): |
||
839 | while x < SAMPLE_SCREEN_WIDTH and not m[x][y]: |
||
840 | m[x][y] = True |
||
841 | x += 1 |
||
842 | |||
843 | # the class building the dungeon from the bsp nodes |
||
844 | def traverse_node(node, *dat): |
||
845 | global bsp_map |
||
846 | if libtcod.bsp_is_leaf(node): |
||
847 | # calculate the room size |
||
848 | minx = node.x + 1 |
||
849 | maxx = node.x + node.w - 1 |
||
850 | miny = node.y + 1 |
||
851 | maxy = node.y + node.h - 1 |
||
852 | if not bsp_room_walls: |
||
853 | if minx > 1: |
||
854 | minx -= 1 |
||
855 | if miny > 1: |
||
856 | miny -= 1 |
||
857 | if maxx == SAMPLE_SCREEN_WIDTH - 1: |
||
858 | maxx -= 1 |
||
859 | if maxy == SAMPLE_SCREEN_HEIGHT - 1: |
||
860 | maxy -= 1 |
||
861 | if bsp_random_room: |
||
862 | minx = libtcod.random_get_int(None, |
||
863 | minx, maxx - bsp_min_room_size + 1) |
||
864 | miny = libtcod.random_get_int(None, |
||
865 | miny, maxy - bsp_min_room_size + 1) |
||
866 | maxx = libtcod.random_get_int(None, |
||
867 | minx + bsp_min_room_size - 1, maxx) |
||
868 | maxy = libtcod.random_get_int(None, |
||
869 | miny + bsp_min_room_size - 1, maxy) |
||
870 | # resize the node to fit the room |
||
871 | node.x = minx |
||
872 | node.y = miny |
||
873 | node.w = maxx - minx + 1 |
||
874 | node.h = maxy - miny + 1 |
||
875 | # dig the room |
||
876 | for x in range(minx, maxx + 1): |
||
877 | for y in range(miny, maxy + 1): |
||
878 | bsp_map[x][y] = True |
||
879 | else: |
||
880 | # resize the node to fit its sons |
||
881 | left = libtcod.bsp_left(node) |
||
882 | right = libtcod.bsp_right(node) |
||
883 | node.x = min(left.x, right.x) |
||
884 | node.y = min(left.y, right.y) |
||
885 | node.w = max(left.x + left.w, right.x + right.w) - node.x |
||
886 | node.h = max(left.y + left.h, right.y + right.h) - node.y |
||
887 | # create a corridor between the two lower nodes |
||
888 | if node.horizontal: |
||
889 | # vertical corridor |
||
890 | if left.x + left.w - 1 < right.x or right.x + right.w - 1 < left.x: |
||
891 | # no overlapping zone. we need a Z shaped corridor |
||
892 | x1 = libtcod.random_get_int(None, left.x, left.x + left.w - 1) |
||
893 | x2 = libtcod.random_get_int(None, |
||
894 | right.x, right.x + right.w - 1) |
||
895 | y = libtcod.random_get_int(None, left.y + left.h, right.y) |
||
896 | vline_up(bsp_map, x1, y - 1) |
||
897 | hline(bsp_map, x1, y, x2) |
||
898 | vline_down(bsp_map, x2, y + 1) |
||
899 | else: |
||
900 | # straight vertical corridor |
||
901 | minx = max(left.x, right.x) |
||
902 | maxx = min(left.x + left.w - 1, right.x + right.w - 1) |
||
903 | x = libtcod.random_get_int(None, minx, maxx) |
||
904 | vline_down(bsp_map, x, right.y) |
||
905 | vline_up(bsp_map, x, right.y - 1) |
||
906 | else: |
||
907 | # horizontal corridor |
||
908 | if left.y + left.h - 1 < right.y or right.y + right.h - 1 < left.y: |
||
909 | # no overlapping zone. we need a Z shaped corridor |
||
910 | y1 = libtcod.random_get_int(None, left.y, left.y + left.h - 1) |
||
911 | View Code Duplication | y2 = libtcod.random_get_int(None, |
|
0 ignored issues
–
show
|
|||
912 | right.y, right.y + right.h - 1) |
||
913 | x = libtcod.random_get_int(None, left.x + left.w, right.x) |
||
914 | hline_left(bsp_map, x - 1, y1) |
||
915 | vline(bsp_map, x, y1, y2) |
||
916 | hline_right(bsp_map, x + 1, y2) |
||
917 | else: |
||
918 | # straight horizontal corridor |
||
919 | miny = max(left.y, right.y) |
||
920 | maxy = min(left.y + left.h - 1, right.y + right.h - 1) |
||
921 | y = libtcod.random_get_int(None, miny, maxy) |
||
922 | hline_left(bsp_map, right.x - 1, y) |
||
923 | hline_right(bsp_map, right.x, y) |
||
924 | return True |
||
925 | |||
926 | bsp = None |
||
927 | bsp_generate = True |
||
928 | bsp_refresh = False |
||
929 | class BSPSample(Sample): |
||
930 | def __init__(self): |
||
931 | self.name = 'Bsp toolkit' |
||
932 | |||
933 | def on_draw(self, delta_time): |
||
934 | global bsp, bsp_generate, bsp_refresh, bsp_map |
||
935 | global bsp_random_room, bsp_room_walls, bsp_depth, bsp_min_room_size |
||
936 | if bsp_generate or bsp_refresh: |
||
937 | # dungeon generation |
||
938 | if bsp is None: |
||
939 | # create the bsp |
||
940 | bsp = libtcod.bsp_new_with_size(0, 0, SAMPLE_SCREEN_WIDTH, |
||
941 | SAMPLE_SCREEN_HEIGHT) |
||
942 | else: |
||
943 | # restore the nodes size |
||
944 | libtcod.bsp_resize(bsp, 0, 0, SAMPLE_SCREEN_WIDTH, |
||
945 | SAMPLE_SCREEN_HEIGHT) |
||
946 | bsp_map = list() |
||
947 | for x in range(SAMPLE_SCREEN_WIDTH): |
||
948 | bsp_map.append([False] * SAMPLE_SCREEN_HEIGHT) |
||
949 | if bsp_generate: |
||
950 | # build a new random bsp tree |
||
951 | libtcod.bsp_remove_sons(bsp) |
||
952 | if bsp_room_walls: |
||
953 | libtcod.bsp_split_recursive(bsp, 0, bsp_depth, |
||
954 | bsp_min_room_size + 1, |
||
955 | bsp_min_room_size + 1, 1.5, 1.5) |
||
956 | else: |
||
957 | libtcod.bsp_split_recursive(bsp, 0, bsp_depth, |
||
958 | bsp_min_room_size, |
||
959 | bsp_min_room_size, 1.5, 1.5) |
||
960 | # create the dungeon from the bsp |
||
961 | libtcod.bsp_traverse_inverted_level_order(bsp, traverse_node) |
||
962 | bsp_generate = False |
||
963 | bsp_refresh = False |
||
964 | libtcod.console_clear(sample_console) |
||
965 | libtcod.console_set_default_foreground(sample_console, libtcod.white) |
||
966 | rooms = 'OFF' |
||
967 | if bsp_random_room: |
||
968 | rooms = 'ON' |
||
969 | libtcod.console_print(sample_console, 1, 1, |
||
970 | View Code Duplication | "ENTER : rebuild bsp\n" |
|
0 ignored issues
–
show
|
|||
971 | "SPACE : rebuild dungeon\n" |
||
972 | "+-: bsp depth %d\n" |
||
973 | "*/: room size %d\n" |
||
974 | "1 : random room size %s" |
||
975 | % (bsp_depth, bsp_min_room_size, rooms)) |
||
976 | if bsp_random_room: |
||
977 | walls = 'OFF' |
||
978 | if bsp_room_walls: |
||
979 | walls = 'ON' |
||
980 | libtcod.console_print(sample_console, 1, 6, |
||
981 | '2 : room walls %s' % walls) |
||
982 | # render the level |
||
983 | for y in range(SAMPLE_SCREEN_HEIGHT): |
||
984 | for x in range(SAMPLE_SCREEN_WIDTH): |
||
985 | if not bsp_map[x][y]: |
||
986 | libtcod.console_set_char_background( |
||
987 | sample_console, x, y, DARK_WALL, libtcod.BKGND_SET) |
||
988 | else: |
||
989 | libtcod.console_set_char_background( |
||
990 | sample_console, x, y, DARK_GROUND, libtcod.BKGND_SET) |
||
991 | |||
992 | def on_key(self, key): |
||
993 | global bsp, bsp_generate, bsp_refresh, bsp_map |
||
994 | global bsp_random_room, bsp_room_walls, bsp_depth, bsp_min_room_size |
||
995 | if key.vk in (libtcod.KEY_ENTER, libtcod.KEY_KPENTER): |
||
996 | bsp_generate = True |
||
997 | elif key.c == ord(' '): |
||
998 | bsp_refresh = True |
||
999 | elif key.c == ord('='): |
||
1000 | bsp_depth += 1 |
||
1001 | bsp_generate = True |
||
1002 | elif key.c == ord('-') and bsp_depth > 1: |
||
1003 | bsp_depth -= 1 |
||
1004 | bsp_generate = True |
||
1005 | elif key.c == ord('*'): |
||
1006 | bsp_min_room_size += 1 |
||
1007 | bsp_generate = True |
||
1008 | elif key.c == ord('/') and bsp_min_room_size > 2: |
||
1009 | bsp_min_room_size -= 1 |
||
1010 | bsp_generate = True |
||
1011 | elif key.c == ord('1') or key.vk in (libtcod.KEY_1, libtcod.KEY_KP1): |
||
1012 | bsp_random_room = not bsp_random_room |
||
1013 | if not bsp_random_room: |
||
1014 | bsp_room_walls = True |
||
1015 | bsp_refresh = True |
||
1016 | elif key.c == ord('2') or key.vk in (libtcod.KEY_2, libtcod.KEY_KP2): |
||
1017 | bsp_room_walls = not bsp_room_walls |
||
1018 | bsp_refresh = True |
||
1019 | |||
1020 | ############################################# |
||
1021 | # image sample |
||
1022 | ############################################# |
||
1023 | img_blue = libtcod.Color(0, 0, 255) |
||
1024 | img_green = libtcod.Color(0, 255, 0) |
||
1025 | class ImageSample(Sample): |
||
1026 | def __init__(self): |
||
1027 | self.name = 'Image toolkit' |
||
1028 | |||
1029 | self.img = libtcod.image_load('data/img/skull.png') |
||
1030 | self.img.set_key_color(libtcod.black) |
||
1031 | self.circle = libtcod.image_load('data/img/circle.png') |
||
1032 | |||
1033 | def on_enter(self): |
||
1034 | libtcod.sys_set_fps(0) |
||
1035 | |||
1036 | def on_draw(self, delta_time): |
||
1037 | sample_console.default_bg = libtcod.black |
||
1038 | sample_console.clear() |
||
1039 | x = (sample_console.width / 2 |
||
1040 | + math.cos(libtcod.sys_elapsed_seconds()) * 10.0) |
||
1041 | y = float(sample_console.height / 2) |
||
1042 | scalex = (0.2 + 1.8 |
||
1043 | * (1.0 + math.cos(libtcod.sys_elapsed_seconds() / 2)) / 2.0) |
||
1044 | scaley = scalex |
||
1045 | angle = libtcod.sys_elapsed_seconds() |
||
1046 | elapsed = libtcod.sys_elapsed_milli() // 2000 |
||
1047 | if elapsed & 1 != 0: |
||
1048 | # split the color channels of circle.png |
||
1049 | # the red channel |
||
1050 | sample_console.default_bg = libtcod.red |
||
1051 | |||
1052 | sample_console.rect(0, 3, 15, 15, False, libtcod.BKGND_SET) |
||
1053 | self.circle.blit_rect(sample_console, 0, 3, -1, -1, |
||
1054 | libtcod.BKGND_MULTIPLY) |
||
1055 | # the green channel |
||
1056 | sample_console.default_bg = img_green |
||
1057 | sample_console.rect(15, 3, 15, 15, False, libtcod.BKGND_SET) |
||
1058 | self.circle.blit_rect(sample_console, |
||
1059 | 15, 3, -1, -1, libtcod.BKGND_MULTIPLY) |
||
1060 | # the blue channel |
||
1061 | sample_console.default_bg = img_blue |
||
1062 | sample_console.rect(30, 3, 15, 15, False, libtcod.BKGND_SET) |
||
1063 | self.circle.blit_rect(sample_console, |
||
1064 | 30, 3, -1, -1, libtcod.BKGND_MULTIPLY) |
||
1065 | else: |
||
1066 | # render circle.png with normal blitting |
||
1067 | self.circle.blit_rect(sample_console, |
||
1068 | 0, 3, -1, -1, libtcod.BKGND_SET) |
||
1069 | self.circle.blit_rect(sample_console, |
||
1070 | 15, 3, -1, -1, libtcod.BKGND_SET) |
||
1071 | self.circle.blit_rect(sample_console, |
||
1072 | 30, 3, -1, -1, libtcod.BKGND_SET) |
||
1073 | self.img.blit(sample_console, x, y, |
||
1074 | libtcod.BKGND_SET, scalex, scaley, angle) |
||
1075 | |||
1076 | ############################################# |
||
1077 | # mouse sample |
||
1078 | ############################################# |
||
1079 | butstatus = ('OFF', 'ON') |
||
1080 | |||
1081 | class MouseSample(Sample): |
||
1082 | def __init__(self): |
||
1083 | self.name = 'Mouse support' |
||
1084 | |||
1085 | self.lbut = self.mbut = self.rbut = 0 |
||
1086 | |||
1087 | def on_enter(self): |
||
1088 | libtcod.console_set_default_background(sample_console, libtcod.grey) |
||
1089 | libtcod.console_set_default_foreground(sample_console, |
||
1090 | libtcod.light_yellow) |
||
1091 | libtcod.mouse_move(320, 200) |
||
1092 | libtcod.mouse_show_cursor(True) |
||
1093 | libtcod.sys_set_fps(60) |
||
1094 | |||
1095 | def on_mouse(self, mouse): |
||
1096 | libtcod.console_clear(sample_console) |
||
1097 | if mouse.lbutton_pressed: |
||
1098 | self.lbut = not self.lbut |
||
1099 | if mouse.rbutton_pressed: |
||
1100 | self.rbut = not self.rbut |
||
1101 | if mouse.mbutton_pressed: |
||
1102 | self.mbut = not self.mbut |
||
1103 | wheel = "" |
||
1104 | if mouse.wheel_up: |
||
1105 | wheel = "UP" |
||
1106 | elif mouse.wheel_down: |
||
1107 | wheel = "DOWN" |
||
1108 | sample_console.print_( |
||
1109 | 1, 1, |
||
1110 | "Mouse position : %4dx%4d\n" |
||
1111 | "Mouse cell : %4dx%4d\n" |
||
1112 | "Mouse movement : %4dx%4d\n" |
||
1113 | "Left button : %s (toggle %s)\n" |
||
1114 | "Right button : %s (toggle %s)\n" |
||
1115 | "Middle button : %s (toggle %s)\n" |
||
1116 | "Wheel : %s" |
||
1117 | % (mouse.x, mouse.y, |
||
1118 | mouse.cx, mouse.cy, |
||
1119 | mouse.dx, mouse.dy, |
||
1120 | butstatus[mouse.lbutton], butstatus[self.lbut], |
||
1121 | butstatus[mouse.rbutton], butstatus[self.rbut], |
||
1122 | butstatus[mouse.mbutton], butstatus[self.mbut], |
||
1123 | wheel, |
||
1124 | ) |
||
1125 | ) |
||
1126 | sample_console.print_(1, 10, "1 : Hide cursor\n2 : Show cursor") |
||
1127 | |||
1128 | def on_key(self, key): |
||
1129 | if key.c == ord('1'): |
||
1130 | libtcod.mouse_show_cursor(False) |
||
1131 | elif key.c == ord('2'): |
||
1132 | libtcod.mouse_show_cursor(True) |
||
1133 | |||
1134 | ############################################# |
||
1135 | # name generator sample |
||
1136 | ############################################# |
||
1137 | |||
1138 | class NameGeneratorSample(Sample): |
||
1139 | def __init__(self): |
||
1140 | self.name = 'Name generator' |
||
1141 | |||
1142 | self.curset = 0 |
||
1143 | self.nbsets = 0 |
||
1144 | self.delay = 0.0 |
||
1145 | self.names = [] |
||
1146 | self.sets = None |
||
1147 | |||
1148 | def on_enter(self): |
||
1149 | libtcod.sys_set_fps(60) |
||
1150 | |||
1151 | def on_draw(self, delta_time): |
||
1152 | if self.nbsets == 0: |
||
1153 | # parse all *.cfg files in data/namegen |
||
1154 | for file in os.listdir(b'data/namegen'): |
||
1155 | if file.find(b'.cfg') > 0: |
||
1156 | libtcod.namegen_parse( |
||
1157 | os.path.join(b'data', b'namegen', file)) |
||
1158 | # get the sets list |
||
1159 | self.sets = libtcod.namegen_get_sets() |
||
1160 | print(self.sets) |
||
1161 | self.nbsets = len(self.sets) |
||
1162 | while len(self.names) > 15: |
||
1163 | self.names.pop(0) |
||
1164 | libtcod.console_clear(sample_console) |
||
1165 | libtcod.console_set_default_foreground(sample_console, libtcod.white) |
||
1166 | libtcod.console_print(sample_console, 1, 1, |
||
1167 | "%s\n\n+ : next generator\n- : prev generator" |
||
1168 | % self.sets[self.curset]) |
||
1169 | for i in range(len(self.names)): |
||
1170 | libtcod.console_print_ex( |
||
1171 | sample_console, SAMPLE_SCREEN_WIDTH-2, 2+i, |
||
1172 | libtcod.BKGND_NONE, libtcod.RIGHT, self.names[i]) |
||
1173 | self.delay += libtcod.sys_get_last_frame_length() |
||
1174 | if self.delay > 0.5: |
||
1175 | self.delay -= 0.5 |
||
1176 | self.names.append(libtcod.namegen_generate(self.sets[self.curset])) |
||
1177 | |||
1178 | def on_key(self, key): |
||
1179 | if key.c == ord('='): |
||
1180 | self.curset += 1 |
||
1181 | if self.curset == self.nbsets: |
||
1182 | self.curset = 0 |
||
1183 | self.names.append("======") |
||
1184 | elif key.c == ord('-'): |
||
1185 | self.curset -= 1 |
||
1186 | if self.curset < 0: |
||
1187 | self.curset = self.nbsets-1 |
||
1188 | self.names.append("======") |
||
1189 | |||
1190 | ############################################# |
||
1191 | # python fast render sample |
||
1192 | ############################################# |
||
1193 | numpy_available = True |
||
1194 | |||
1195 | use_numpy = numpy_available #default option |
||
1196 | SCREEN_W = SAMPLE_SCREEN_WIDTH |
||
1197 | SCREEN_H = SAMPLE_SCREEN_HEIGHT |
||
1198 | HALF_W = SCREEN_W // 2 |
||
1199 | HALF_H = SCREEN_H // 2 |
||
1200 | RES_U = 80 #texture resolution |
||
1201 | RES_V = 80 |
||
1202 | TEX_STRETCH = 5 #texture stretching with tunnel depth |
||
1203 | SPEED = 15 |
||
1204 | LIGHT_BRIGHTNESS = 3.5 #brightness multiplier for all lights (changes their radius) |
||
1205 | LIGHTS_CHANCE = 0.07 #chance of a light appearing |
||
1206 | MAX_LIGHTS = 6 |
||
1207 | MIN_LIGHT_STRENGTH = 0.2 |
||
1208 | LIGHT_UPDATE = 0.05 #how much the ambient light changes to reflect current light sources |
||
1209 | AMBIENT_LIGHT = 0.8 #brightness of tunnel texture |
||
1210 | |||
1211 | #the coordinates of all tiles in the screen, as numpy arrays. example: (4x3 pixels screen) |
||
1212 | #xc = [[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]] |
||
1213 | #yc = [[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3]] |
||
1214 | if numpy_available: |
||
1215 | (xc, yc) = np.meshgrid(range(SCREEN_W), range(SCREEN_H)) |
||
1216 | #translate coordinates of all pixels to center |
||
1217 | xc = xc - HALF_W |
||
1218 | yc = yc - HALF_H |
||
1219 | |||
1220 | noise2d = libtcod.noise_new(2, 0.5, 2.0) |
||
1221 | if numpy_available: #the texture starts empty |
||
1222 | texture = np.zeros((RES_U, RES_V)) |
||
1223 | |||
1224 | class Light: |
||
1225 | def __init__(self, x, y, z, r, g, b, strength): |
||
1226 | self.x, self.y, self.z = x, y, z #pos. |
||
1227 | self.r, self.g, self.b = r, g, b #color |
||
1228 | self.strength = strength #between 0 and 1, defines brightness |
||
1229 | |||
1230 | class FastRenderSample(Sample): |
||
1231 | def __init__(self): |
||
1232 | self.name = 'Python fast render' |
||
1233 | |||
1234 | def on_enter(self): |
||
1235 | global frac_t, abs_t, lights, tex_r, tex_g, tex_b |
||
1236 | libtcod.sys_set_fps(0) |
||
1237 | libtcod.console_clear(sample_console) #render status message |
||
1238 | libtcod.console_set_default_foreground(sample_console, libtcod.white) |
||
1239 | libtcod.console_print(sample_console, 1, SCREEN_H - 3, |
||
1240 | "Renderer: NumPy") |
||
1241 | |||
1242 | frac_t = RES_V - 1 #time is represented in number of pixels of the texture, start later in time to initialize texture |
||
1243 | abs_t = RES_V - 1 |
||
1244 | lights = [] #lights list, and current color of the tunnel texture |
||
1245 | tex_r, tex_g, tex_b = 0, 0, 0 |
||
1246 | |||
1247 | def on_draw(self, delta_time): |
||
1248 | global use_numpy, frac_t, abs_t, lights, tex_r, tex_g, tex_b, xc, yc, texture, texture2, brightness2, R2, G2, B2 |
||
1249 | |||
1250 | time_delta = libtcod.sys_get_last_frame_length() * SPEED #advance time |
||
1251 | frac_t += time_delta #increase fractional (always < 1.0) time |
||
1252 | abs_t += time_delta #increase absolute elapsed time |
||
1253 | int_t = int(frac_t) #integer time units that passed this frame (number of texture pixels to advance) |
||
1254 | frac_t -= int_t #keep this < 1.0 |
||
1255 | |||
1256 | #change texture color according to presence of lights (basically, sum them |
||
1257 | #to get ambient light and smoothly change the current color into that) |
||
1258 | ambient_r = (AMBIENT_LIGHT |
||
1259 | * sum(light.r * light.strength for light in lights)) |
||
1260 | ambient_g = (AMBIENT_LIGHT |
||
1261 | * sum(light.g * light.strength for light in lights)) |
||
1262 | ambient_b = (AMBIENT_LIGHT |
||
1263 | * sum(light.b * light.strength for light in lights)) |
||
1264 | alpha = LIGHT_UPDATE * time_delta |
||
1265 | tex_r = tex_r * (1 - alpha) + ambient_r * alpha |
||
1266 | tex_g = tex_g * (1 - alpha) + ambient_g * alpha |
||
1267 | tex_b = tex_b * (1 - alpha) + ambient_b * alpha |
||
1268 | |||
1269 | if int_t >= 1: #roll texture (ie, advance in tunnel) according to int_t |
||
1270 | int_t = int_t % RES_V #can't roll more than the texture's size (can happen when time_delta is large) |
||
1271 | int_abs_t = int(abs_t) #new pixels are based on absolute elapsed time |
||
1272 | |||
1273 | texture = np.roll(texture, -int_t, 1) |
||
1274 | #replace new stretch of texture with new values |
||
1275 | for v in range(RES_V - int_t, RES_V): |
||
1276 | for u in range(0, RES_U): |
||
1277 | tex_v = (v + int_abs_t) / float(RES_V) |
||
1278 | texture[u, v] = ( |
||
1279 | libtcod.noise_get_fbm( |
||
1280 | noise2d, [u/float(RES_U), tex_v], 32.0) |
||
1281 | + libtcod.noise_get_fbm( |
||
1282 | noise2d, [1 - u/float(RES_U), tex_v], 32.0) |
||
1283 | ) |
||
1284 | |||
1285 | # squared distance from center, |
||
1286 | # clipped to sensible minimum and maximum values |
||
1287 | sqr_dist = xc ** 2 + yc ** 2 |
||
1288 | sqr_dist = sqr_dist.clip(1.0 / RES_V, RES_V ** 2) |
||
1289 | |||
1290 | #one coordinate into the texture, represents depth in the tunnel |
||
1291 | v = TEX_STRETCH * float(RES_V) / sqr_dist + frac_t |
||
1292 | v = v.clip(0, RES_V - 1) |
||
1293 | |||
1294 | #another coordinate, represents rotation around the tunnel |
||
1295 | u = np.mod(RES_U * (np.arctan2(yc, xc) / (2 * np.pi) + 0.5), RES_U) |
||
1296 | |||
1297 | #retrieve corresponding pixels from texture |
||
1298 | brightness = texture[u.astype(int), v.astype(int)] / 4.0 + 0.5 |
||
1299 | |||
1300 | #use the brightness map to compose the final color of the tunnel |
||
1301 | R = brightness * tex_r |
||
1302 | G = brightness * tex_g |
||
1303 | B = brightness * tex_b |
||
1304 | |||
1305 | #create new light source |
||
1306 | if (libtcod.random_get_float(0, 0, 1) <= time_delta * LIGHTS_CHANCE and |
||
1307 | len(lights) < MAX_LIGHTS): |
||
1308 | x = libtcod.random_get_float(0, -0.5, 0.5) |
||
1309 | y = libtcod.random_get_float(0, -0.5, 0.5) |
||
1310 | strength = libtcod.random_get_float(0, MIN_LIGHT_STRENGTH, 1.0) |
||
1311 | |||
1312 | color = libtcod.Color(0, 0, 0) #create bright colors with random hue |
||
1313 | hue = libtcod.random_get_float(0, 0, 360) |
||
1314 | libtcod.color_set_hsv(color, hue, 0.5, strength) |
||
1315 | lights.append(Light(x, y, TEX_STRETCH, |
||
1316 | color.r, color.g, color.b, strength)) |
||
1317 | |||
1318 | #eliminate lights that are going to be out of view |
||
1319 | lights = [light for light in lights |
||
1320 | if light.z - time_delta > 1.0 / RES_V] |
||
1321 | |||
1322 | for light in lights: #render lights |
||
1323 | #move light's Z coordinate with time, then project its XYZ coordinates to screen-space |
||
1324 | light.z -= float(time_delta) / TEX_STRETCH |
||
1325 | xl = light.x / light.z * SCREEN_H |
||
1326 | yl = light.y / light.z * SCREEN_H |
||
1327 | |||
1328 | #calculate brightness of light according to distance from viewer and strength, |
||
1329 | #then calculate brightness of each pixel with inverse square distance law |
||
1330 | light_brightness = (LIGHT_BRIGHTNESS * light.strength |
||
1331 | * (1.0 - light.z / TEX_STRETCH)) |
||
1332 | brightness = light_brightness / ((xc - xl) ** 2 + (yc - yl) ** 2) |
||
1333 | |||
1334 | #make all pixels shine around this light |
||
1335 | R += brightness * light.r |
||
1336 | G += brightness * light.g |
||
1337 | B += brightness * light.b |
||
1338 | |||
1339 | #truncate values |
||
1340 | R = R.clip(0, 255) |
||
1341 | G = G.clip(0, 255) |
||
1342 | B = B.clip(0, 255) |
||
1343 | |||
1344 | #fill the screen with these background colors |
||
1345 | sample_console.bg.transpose()[:] = [R.T, G.T, B.T] |
||
1346 | |||
1347 | ############################################# |
||
1348 | # main loop |
||
1349 | ############################################# |
||
1350 | |||
1351 | RENDERER_KEYS = { |
||
1352 | libtcod.KEY_F1: libtcod.RENDERER_GLSL, |
||
1353 | libtcod.KEY_F2: libtcod.RENDERER_OPENGL, |
||
1354 | libtcod.KEY_F3: libtcod.RENDERER_SDL, |
||
1355 | } |
||
1356 | |||
1357 | RENDERER_NAMES = ('F1 GLSL ', 'F2 OPENGL ', 'F3 SDL ') |
||
1358 | |||
1359 | SAMPLES = ( |
||
1360 | TrueColorSample(), |
||
1361 | OffscreenConsoleSample(), |
||
1362 | LineDrawingSample(), |
||
1363 | NoiseSample(), |
||
1364 | FOVSample(), |
||
1365 | PathfindingSample(), |
||
1366 | BSPSample(), |
||
1367 | ImageSample(), |
||
1368 | MouseSample(), |
||
1369 | NameGeneratorSample(), |
||
1370 | FastRenderSample() |
||
1371 | ) |
||
1372 | |||
1373 | cur_sample = 0 |
||
1374 | View Code Duplication | ||
0 ignored issues
–
show
|
|||
1375 | def main(): |
||
1376 | global cur_sample |
||
1377 | credits_end = False |
||
1378 | SAMPLES[cur_sample].on_enter() |
||
1379 | draw_samples_menu() |
||
1380 | draw_renderer_menu() |
||
1381 | |||
1382 | while not libtcod.console_is_window_closed(): |
||
1383 | root_console.default_fg = (255, 255, 255) |
||
1384 | root_console.default_bg = (0, 0, 0) |
||
1385 | # render credits |
||
1386 | if not credits_end: |
||
1387 | root_console.clear() |
||
1388 | draw_samples_menu() |
||
1389 | draw_renderer_menu() |
||
1390 | credits_end = libtcod.console_credits_render(60, 43, 0) |
||
1391 | |||
1392 | # render the sample |
||
1393 | SAMPLES[cur_sample].on_draw(libtcod.sys_get_last_frame_length()) |
||
1394 | sample_console.blit(0, 0, sample_console.width, sample_console.height, |
||
1395 | root_console, SAMPLE_SCREEN_X, SAMPLE_SCREEN_Y) |
||
1396 | draw_stats() |
||
1397 | handle_events() |
||
1398 | libtcod.console_flush() |
||
1399 | |||
1400 | def handle_events(): |
||
1401 | global cur_sample |
||
1402 | key = libtcod.Key() |
||
1403 | mouse = libtcod.Mouse() |
||
1404 | EVENT_MASK = libtcod.EVENT_MOUSE | libtcod.EVENT_KEY_PRESS |
||
1405 | while libtcod.sys_check_for_event(EVENT_MASK, key, mouse): |
||
1406 | SAMPLES[cur_sample].on_mouse(mouse) |
||
1407 | SAMPLES[cur_sample].on_key(key) |
||
1408 | # key handler |
||
1409 | if key.vk == libtcod.KEY_DOWN: |
||
1410 | cur_sample = (cur_sample + 1) % len(SAMPLES) |
||
1411 | SAMPLES[cur_sample].on_enter() |
||
1412 | draw_samples_menu() |
||
1413 | elif key.vk == libtcod.KEY_UP: |
||
1414 | cur_sample = (cur_sample - 1) % len(SAMPLES) |
||
1415 | SAMPLES[cur_sample].on_enter() |
||
1416 | draw_samples_menu() |
||
1417 | elif key.vk == libtcod.KEY_ENTER and key.lalt: |
||
1418 | libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen()) |
||
1419 | elif key.vk == libtcod.KEY_PRINTSCREEN or key.c == 'p': |
||
1420 | print("screenshot") |
||
1421 | if key.lalt: |
||
1422 | libtcod.console_save_apf(None, "samples.apf") |
||
1423 | print("apf") |
||
1424 | else: |
||
1425 | libtcod.sys_save_screenshot() |
||
1426 | print("png") |
||
1427 | elif key.vk == libtcod.KEY_ESCAPE: |
||
1428 | raise SystemExit() |
||
1429 | elif key.vk in RENDERER_KEYS: |
||
1430 | libtcod.sys_set_renderer(RENDERER_KEYS[key.vk]) |
||
1431 | draw_renderer_menu() |
||
1432 | |||
1433 | def draw_samples_menu(): |
||
1434 | for i, sample in enumerate(SAMPLES): |
||
1435 | if i == cur_sample: |
||
1436 | root_console.default_fg = libtcod.white |
||
1437 | root_console.default_bg = libtcod.light_blue |
||
1438 | else: |
||
1439 | root_console.default_fg = libtcod.grey |
||
1440 | root_console.default_bg = libtcod.black |
||
1441 | root_console.print_(2, 46 - (len(SAMPLES) - i), |
||
1442 | ' %s' % sample.name.ljust(19), |
||
1443 | libtcod.BKGND_SET, libtcod.LEFT) |
||
1444 | |||
1445 | def draw_stats(): |
||
1446 | root_console.default_fg = libtcod.grey |
||
1447 | root_console.print_( |
||
1448 | 79, 46, |
||
1449 | ' last frame : %3d ms (%3d fps)' % ( |
||
1450 | libtcod.sys_get_last_frame_length() * 1000.0, |
||
1451 | libtcod.sys_get_fps(), |
||
1452 | ), |
||
1453 | libtcod.BKGND_NONE, libtcod.RIGHT |
||
1454 | ) |
||
1455 | root_console.print_( |
||
1456 | 79, 47, |
||
1457 | 'elapsed : %8d ms %4.2fs' % (libtcod.sys_elapsed_milli(), |
||
1458 | libtcod.sys_elapsed_seconds()), |
||
1459 | libtcod.BKGND_NONE, libtcod.RIGHT, |
||
1460 | ) |
||
1461 | |||
1462 | def draw_renderer_menu(): |
||
1463 | current_renderer = libtcod.sys_get_renderer() |
||
1464 | root_console.default_fg = libtcod.grey |
||
1465 | root_console.default_bg = libtcod.black |
||
1466 | root_console.print_(42, 46 - (libtcod.NB_RENDERERS + 1), |
||
1467 | "Renderer :", libtcod.BKGND_SET, libtcod.LEFT) |
||
1468 | for i, name in enumerate(RENDERER_NAMES): |
||
1469 | if i == current_renderer: |
||
1470 | root_console.default_fg = libtcod.white |
||
1471 | root_console.default_bg = libtcod.light_blue |
||
1472 | else: |
||
1473 | root_console.default_fg = libtcod.grey |
||
1474 | root_console.default_bg = libtcod.black |
||
1475 | root_console.print_( |
||
1476 | 42, 46 - (libtcod.NB_RENDERERS - i), |
||
1477 | name, libtcod.BKGND_SET, libtcod.LEFT |
||
1478 | ) |
||
1479 | |||
1480 | if __name__ == '__main__': |
||
1481 | main() |
||
1482 |