/
main.py
223 lines (208 loc) · 9.17 KB
/
main.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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
import libtcodpy as tcod
import shelve
from constants import *
from entities import *
from renderer import RenderScreen
from game_map import GameMap
from tile_loader import *
from config import USE_TILES
def get_key_event(turn_based=None):
if turn_based:
# Turn-based game play; wait for a key stroke
key = tcod.console_wait_for_keypress(True)
else:
# Real-time game play; don't wait for a player's key stroke
key = tcod.console_check_for_keypress()
return key
def get_names_under_mouse(mouse, game_map):
# return a string with the names of all objects under the mouse
(x, y) = (mouse.cx, mouse.cy)
# create a list with the names of all objects at the mouse's coordinates and in FOV
names = [
obj.name for obj in game_map.level_objects
if obj.get_x_position() == x and obj.get_y_position() == y and tcod.map_is_in_fov(
game_map.fov_map,
obj.get_x_position(),
obj.get_y_position()
)
]
names = ', '.join(names) #join the names, separated by commas
return names.capitalize()
def new_game(logger, renderer):
# clear console
renderer.clear_all()
# Game map
game_map = GameMap(MAP_WIDTH, MAP_HEIGHT, logger=logger)
# generate an populate dungeons, create fov map
game_map.generate_map()
player_pos = game_map.player_initial_pos
# instantiate player
fighter_component = Fighter(hp=30, defense=2, power=2, death_function=player_death)
player = MainPlayer(
player_pos[0],
player_pos[1],
PLAYER_TILE[USE_TILES].code,
'player',
PLAYER_TILE[USE_TILES].color,
blocks=True,
fighter=fighter_component,
logger=logger)
# initial equipment: a dagger
equipment_component = Equipment(slot=RIGHT_HAND, power_bonus=2)
obj = BaseObject(player.get_x_position(), player.get_y_position, DAGGER_TILE[USE_TILES], 'dagger', DAGGER_TILE[USE_TILES].color, logger=logger, equipment=equipment_component)
player.inventory.append(obj)
equipment_component.equip(player.inventory)
obj.always_visible = True
# Greet the player
logger.log_message(
'Welcome stranger! Prepare to perish in the Tombs of the Ancient Kings.',
tcod.red
)
return game_map, player
def main(renderer, game_map, player, logger, turn_based=True):
# Game state and player's last action
game_state = PLAYING
player_action = None
# Track mouse and keys
mouse = tcod.Mouse()
key = tcod.Key()
# Game loop
while not tcod.console_is_window_closed():
# check for events
tcod.sys_check_for_event(tcod.EVENT_KEY_PRESS | tcod.EVENT_MOUSE, key, mouse)
# sort objects in level to draw first corpses
game_map.level_objects = [
o for o in game_map.level_objects if o.fighter is None
] + [
o for o in game_map.level_objects if o.fighter is not None
]
objects = game_map.level_objects + [player]
# key = get_key_event(turn_based)
player_action = player.handle_keys(game_map, game_state, key)
if player_action == SHOW_INVENTORY:
chosen_item = renderer.render_inventory_menu(
'Press the key next to an item to use it, or any other to cancel.\n',
player.inventory
)
if chosen_item is not None:
# player = kwargs['player']
# game_map = kwargs['game_map']
# renderer = kwargs['renderer']
# names_under_mouse = kwargs['names_under_mouse']
# show_map_chars = kwargs['show_map_chars']
# mouse = kwargs['mouse']
# key = kwargs['key']
chosen_item.use(
player.inventory,
player=player,
game_map=game_map,
mouse=mouse,
renderer=renderer,
key=key,
names_under_mouse=get_names_under_mouse(mouse, game_map),
show_map_chars=False
)
elif player_action == DROP_ITEM:
# show the inventory; if an item is selected, drop it
chosen_item = renderer.render_inventory_menu(
'Press the key next to an item to drop it, or any other to cancel.\n',
player.inventory
)
if chosen_item is not None:
chosen_item.drop(player.inventory, game_map, player)
elif player_action == SHOW_STATUS:
level_up_xp = LEVEL_UP_BASE + player.level * LEVEL_UP_FACTOR
renderer.msgbox('Character Information\n\nLevel: ' + str(player.level) + '\nExperience: ' + str(player.fighter.xp) +
'\nExperience to level up: ' + str(level_up_xp) + '\n\nMaximum HP: ' + str(player.fighter.max_hp) +
'\nAttack: ' + str(player.fighter.power) + '\nDefense: ' + str(player.fighter.defense), CHARACTER_SCREEN_WIDTH)
if key.vk == tcod.KEY_ENTER and key.lalt:
#Alt+Enter: toggle fullscreen
tcod.console_set_fullscreen(not tcod.console_is_fullscreen())
elif key.vk == tcod.KEY_ESCAPE:
# go to main menu
choice = renderer.render_main_menu()
if choice == NEW_GAME:
logger.clear_messages()
game_map, player = new_game(logger, renderer)
game_state = PLAYING
player_action = None
names_under_mouse = get_names_under_mouse(mouse, game_map)
game_map.level_objects = [
o for o in game_map.level_objects if o.fighter is None
] + [
o for o in game_map.level_objects if o.fighter is not None
]
renderer.render_all(game_map.level_objects + [player], game_map, names_under_mouse, show_map_chars=False)
elif choice == LOAD_GAME:
try:
player, game_state = load_game(game_map, logger)
renderer.render_all(game_map.level_objects + [player], game_map, names_under_mouse, show_map_chars=False)
except:
renderer.msgbox('\n No saved game to load.\n', 24)
elif choice == EXIT_GAME:
break
# let monsters take their turn if the player did
if game_state == PLAYING and player_action != DIDNT_TAKE_TURN:
for o in objects:
if o != player and o.ai:
o.ai.take_turn(game_map, player)
# Update game state with player death
game_state = player.state
names_under_mouse = get_names_under_mouse(mouse, game_map)
renderer.render_all(objects, game_map, names_under_mouse, show_map_chars=False)
# check level up
if player.check_level_up():
renderer.render_level_up(player)
save_game(game_map, game_state, player, logger)
def save_game(game_map, game_state, player, logger):
with shelve.open('gamedata', 'n') as gd:
gd['maps'] = game_map.full_map
gd['active_level'] = game_map.active_level
gd['objects'] = game_map.map_objects
gd['player'] = player
gd['inventory'] = player.inventory
gd['game_msgs'] = logger.game_msgs
gd['game_state'] = game_state
def load_game(game_map, logger):
# open the previously saved shelve and load the game data
with shelve.open('gamedata', 'r') as gd:
game_map.full_map = gd['maps']
game_map.active_level = gd['active_level']
game_map.map_objects = gd['objects']
player = gd['player']
player.inventory = gd['inventory']
logger.game_msgs = gd['game_msgs']
game_state = gd['game_state']
game_map.init_fov()
game_map.change_level(game_map.active_level, only_tile_map=False) # only tile map?
player.logger = logger
for l in game_map.map_objects:
for o in l:
o.logger = logger
game_map.level_objects = [
o for o in game_map.level_objects if o.fighter is None
] + [
o for o in game_map.level_objects if o.fighter is not None
]
return player, game_state
if __name__ == "__main__":
# Game config
turn_based = True
load_font(use_tiles=USE_TILES)
tcod.console_init_root(SCREEN_WIDTH, SCREEN_HEIGHT, WINDOW_TITLE, FULLSCREEN)
tcod.sys_set_fps(LIMIT_FPS)
# system wide message logger
logger = Logger()
renderer = RenderScreen(SCREEN_WIDTH, SCREEN_HEIGHT, PANEL_HEIGHT, logger)
choice = renderer.render_main_menu()
if choice == NEW_GAME:
game_map, player = new_game(logger, renderer)
main(renderer, game_map, player, logger, turn_based)
elif choice == LOAD_GAME:
try:
game_map = GameMap(MAP_WIDTH, MAP_HEIGHT, logger=logger)
player, game_state = load_game(game_map, logger)
renderer.render_all(game_map.level_objects + [player], game_map, '', show_map_chars=False)
main(renderer, game_map, player, logger, turn_based)
except:
renderer.msgbox('\n No saved game to load.\n', 24)