Completed
Push — master ( 1fda9f...641cff )
by Kyle
52s
created

MouseSample   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 52
Duplicated Lines 5.77 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 3
loc 52
rs 10
wmc 11

4 Methods

Rating   Name   Duplication   Size   Complexity  
A on_enter() 0 7 1
A __init__() 2 4 1
A on_key() 0 5 3
B on_mouse() 0 32 6

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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