forked from Naburimannu/libtcodpy-tutorial
/
interface.py
188 lines (165 loc) · 7.04 KB
/
interface.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
"""
All functions that take input (other than the game mainloop).
interface.poll() returns (libtcod.Key, libtcod.Mouse) with key *presses*
and mouse events, but not key *releases*.
interface.parse_move(key) translates a libtcod.Key into directional movement.
interface.log_display(width=60)
interface.target_tile(actor, max_range=None)
"""
import libtcodpy as libtcod
import config
import algebra
import log
import renderer
def poll():
key = libtcod.Key()
mouse = libtcod.Mouse()
libtcod.sys_check_for_event(libtcod.EVENT_KEY_PRESS |
libtcod.EVENT_MOUSE, key, mouse)
return (key, mouse)
def debounce():
key = libtcod.Key()
mouse = libtcod.Mouse()
# Can't pass None for mouse even if we are only waiting for a key release.
libtcod.sys_wait_for_event(libtcod.EVENT_KEY_RELEASE, key, mouse, True)
def parse_move(key):
"""
Returns (bool, direction, bool).
First value is True if a direction key was pressed, False otherwise.
Direction will be None if first value is False or the '.' or numpad 5 were pressed.
Last value is True if shift was held (run / page-scroll), False otherwise.
"""
key_char = chr(key.c)
if (key.vk == libtcod.KEY_UP or key.vk == libtcod.KEY_KP8 or
key_char == 'k' or key_char == 'K'):
return (True, algebra.north, key.shift)
elif (key.vk == libtcod.KEY_DOWN or key.vk == libtcod.KEY_KP2 or
key_char == 'j' or key_char == 'J'):
return (True, algebra.south, key.shift)
elif (key.vk == libtcod.KEY_LEFT or key.vk == libtcod.KEY_KP4 or
key_char == 'h' or key_char == 'H'):
return (True, algebra.west, key.shift)
elif (key.vk == libtcod.KEY_RIGHT or key.vk == libtcod.KEY_KP6 or
key_char == 'l' or key_char == 'L'):
return (True, algebra.east, key.shift)
elif (key.vk == libtcod.KEY_HOME or key.vk == libtcod.KEY_KP7 or
key_char == 'y' or key_char == 'Y'):
return (True, algebra.northwest, key.shift)
elif (key.vk == libtcod.KEY_PAGEUP or key.vk == libtcod.KEY_KP9 or
key_char == 'u' or key_char == 'U'):
return (True, algebra.northeast, key.shift)
elif (key.vk == libtcod.KEY_END or key.vk == libtcod.KEY_KP1 or
key_char == 'b' or key_char == 'B'):
return (True, algebra.southwest, key.shift)
elif (key.vk == libtcod.KEY_PAGEDOWN or key.vk == libtcod.KEY_KP3 or
key_char == 'n' or key_char == 'N'):
return (True, algebra.southeast, key.shift)
elif (key.vk == libtcod.KEY_KP5 or key_char == '.'):
# do nothing but note that a relevant key was pressed
return (True, None, False)
return (False, None, False)
def _colored_text_list(lines, width):
"""
Display *lines* of (text, color) in a window of size *width*.
Scroll through them if the mouse wheel is spun or the arrows are pressed.
"""
length = len(lines)
height = min(length, 40)
window = libtcod.console_new(width, height)
offset = -height
while True:
if offset > -height:
offset = -height
if offset < -length:
offset = -length
libtcod.console_clear(window)
renderer.write_log(lines[offset:length + offset + height],
window, 0, 0)
x = config.SCREEN_WIDTH/2 - width/2
y = config.SCREEN_HEIGHT/2 - height/2
libtcod.console_blit(window, 0, 0, width, height, 0, x, y, 1.0, 0.7)
libtcod.console_flush()
while True:
(key, mouse) = poll()
(key_pressed, direction, shift) = parse_move(key)
if key_pressed:
if direction == algebra.north and not shift:
offset -= 1
break
elif direction == algebra.south and not shift:
offset += 1
break
elif (direction == algebra.northeast or
(direction == algebra.north and shift)):
offset -= height
break
elif (direction == algebra.southeast or
(direction == algebra.south and shift)):
offset += height
break
elif (key.vk == libtcod.KEY_ALT or
key.vk == libtcod.KEY_CONTROL or
key.vk == libtcod.KEY_SHIFT or
key.vk == libtcod.KEY_NONE):
break
return
def log_display(width=60):
"""
Display the recent log history, wait for any keypress.
"""
_colored_text_list(log.game_msgs, width)
def target_tile(actor, max_range=None):
"""
Return the position of a tile left-clicked in player's FOV
(optionally in a range), or (None,None) if right-clicked.
"""
(key, mouse) = poll()
(ox, oy) = (mouse.cx, mouse.cy)
using_mouse = False
using_keyboard = False
(kx, ky) = renderer.ScreenCoords.fromWorldCoords(actor.camera_position,
actor.pos)
pos = None
while True:
# Render the screen. This erases the inventory and shows
# the names of objects under the mouse.
libtcod.console_flush()
(key, mouse) = poll()
renderer.render_all(actor, (kx, ky))
actor.current_map.fov_needs_recompute = False
if (mouse.cx != ox or mouse.cy != oy):
using_mouse = True
using_keyboard = False
(key_pressed, direction, shift) = parse_move(key)
if key_pressed:
using_keyboard = True
if using_mouse:
(ox, oy) = (mouse.cx, mouse.cy)
using_mouse = False
if direction:
kx += direction.x
ky += direction.y
if using_mouse:
(kx, ky) = (mouse.cx, mouse.cy)
pos = renderer.ScreenCoords.toWorldCoords(actor.camera_position, (kx, ky))
libtcod.console_set_default_background(renderer._overlay, libtcod.black)
libtcod.console_clear(renderer._overlay)
(ux, uy) = renderer.ScreenCoords.fromWorldCoords(actor.camera_position,
actor.pos)
libtcod.line_init(ux, uy, kx, ky)
nx, ny = libtcod.line_step()
while ((not (nx is None)) and nx >= 0 and ny >= 0 and
nx < config.MAP_PANEL_WIDTH and
ny < config.MAP_PANEL_HEIGHT):
libtcod.console_set_char_background(renderer._overlay, nx, ny, libtcod.sepia, libtcod.BKGND_SET)
nx, ny = libtcod.line_step()
if mouse.rbutton_pressed or key.vk == libtcod.KEY_ESCAPE:
libtcod.console_clear(renderer._overlay)
return None
# Accept the target if the player clicked in FOV
# and within the range specified.
if ((mouse.lbutton_pressed or key.vk == libtcod.KEY_ENTER) and
libtcod.map_is_in_fov(actor.current_map.fov_map, pos.x, pos.y) and
(max_range is None or actor.distance(pos) <= max_range)):
libtcod.console_clear(renderer._overlay)
return pos