python_curses_game_2021/proj/main.py

471 lines
10 KiB
Python
Raw Normal View History

2021-04-12 21:17:06 +03:00
import curses
2021-04-12 22:11:38 +03:00
import random
2021-04-13 01:20:31 +03:00
import copy
2021-04-12 21:17:06 +03:00
2021-04-14 23:50:31 +03:00
MAP_POS_X = 16
MAP_POS_Y = 2
2021-04-13 01:20:31 +03:00
2021-04-15 14:25:58 +03:00
WEAPON_SPEED = 1
2021-04-13 01:20:31 +03:00
PLAYER = 'P'
2021-04-14 23:50:31 +03:00
MONSTER = 'M'
2021-04-13 01:20:31 +03:00
EMPTY = ' '
2021-04-14 23:50:31 +03:00
DOOR = '>'
2021-04-13 01:20:31 +03:00
MARK = '!'
WALL = '#'
2021-04-15 00:24:44 +03:00
GOLD = '$'
WEAPON = '/'
2021-04-15 14:25:58 +03:00
ACTIVE_WEAPON = '.'
2021-04-15 00:24:44 +03:00
ADD_HEALTH = '+'
2021-04-15 14:25:58 +03:00
SCORE = '@'
2021-04-12 21:17:06 +03:00
2021-04-12 22:11:38 +03:00
SIMPLE_COLOR = 1
ACTIVE_COLOR = 2
2021-04-13 01:20:31 +03:00
WALL_COLOR = 3
GOLD_COLOR = 4
WEAPON_COLOR = 5
HIGHLIGHTED_COLOR = 6
PLAYER_COLOR = 7
DOOR_COLOR = 8
2021-04-14 23:50:31 +03:00
MONSTER_COLOR = 9
ADD_HEALTH_COLOR = 10
2021-04-15 14:25:58 +03:00
SCORE_COLOR = 11
ACTIVE_WEAPON_COLOR = 12
MONSTER_DAMAGE = 1
P_POS = 0
P_HEALTH = 1
P_WEAPON = 2
P_GOLD = 3
P_ACTIVE_DOOR = 4
P_SCORE = 5
MOVE_UP_ACTION = "KEY_UP"
MOVE_DOWN_ACTION = "KEY_DOWN"
MOVE_LEFT_ACTION = "KEY_LEFT"
MOVE_RIGHT_ACTION = "KEY_RIGHT"
ATTACK_UP_ACTION = 'w'
ATTACK_DOWN_ACTION = 's'
ATTACK_LEFT_ACTION = 'a'
ATTACK_RIGHT_ACTION = 'd'
NEXT_DOOR_ACTION = 'q'
PREV_DOOR_ACTION = 'e'
2021-04-12 21:17:06 +03:00
DIRECTIONS = [
2021-04-15 14:25:58 +03:00
[0, -1],
[0, 1],
2021-04-15 14:25:58 +03:00
[-1, 0],
[1, 0]
]
EXTENDED_DIRECTIONS = DIRECTIONS + [
[1, 1],
[1, -1],
[-1, 1],
[-1, -1]
]
2021-04-12 21:17:06 +03:00
2021-04-12 22:11:38 +03:00
def begin_curses():
stdscr = curses.initscr()
curses.noecho()
curses.cbreak()
curses.curs_set(0)
stdscr.keypad(True)
2021-04-14 23:50:31 +03:00
#stdscr.nodelay(True)
2021-04-12 21:17:06 +03:00
2021-04-12 22:11:38 +03:00
curses.start_color()
2021-04-12 21:17:06 +03:00
2021-04-12 22:11:38 +03:00
curses.init_pair(SIMPLE_COLOR, curses.COLOR_WHITE, curses.COLOR_BLACK)
curses.init_pair(ACTIVE_COLOR, curses.COLOR_BLACK, curses.COLOR_WHITE)
2021-04-13 01:20:31 +03:00
curses.init_pair(WALL_COLOR, curses.COLOR_WHITE, curses.COLOR_BLACK)
curses.init_pair(GOLD_COLOR, curses.COLOR_YELLOW, curses.COLOR_BLACK)
curses.init_pair(WEAPON_COLOR, curses.COLOR_CYAN, curses.COLOR_BLACK)
curses.init_pair(HIGHLIGHTED_COLOR, curses.COLOR_CYAN, curses.COLOR_BLACK)
2021-04-14 23:50:31 +03:00
curses.init_pair(PLAYER_COLOR, curses.COLOR_BLACK, curses.COLOR_WHITE)
curses.init_pair(DOOR_COLOR, curses.COLOR_BLUE, curses.COLOR_BLACK)
curses.init_pair(MONSTER_COLOR, curses.COLOR_RED, curses.COLOR_BLACK)
curses.init_pair(ADD_HEALTH_COLOR, curses.COLOR_GREEN, curses.COLOR_BLACK)
2021-04-15 14:25:58 +03:00
curses.init_pair(SCORE_COLOR, curses.COLOR_GREEN, curses.COLOR_BLACK)
curses.init_pair(ACTIVE_WEAPON_COLOR, curses.COLOR_YELLOW, curses.COLOR_BLACK)
2021-04-12 21:17:06 +03:00
2021-04-12 22:11:38 +03:00
return stdscr
2021-04-12 21:17:06 +03:00
2021-04-12 22:11:38 +03:00
def end_curses(stdscr):
2021-04-14 23:50:31 +03:00
#stdscr.nodelay(False)
2021-04-12 22:11:38 +03:00
stdscr.keypad(False)
2021-04-13 01:20:31 +03:00
curses.curs_set(1)
curses.nocbreak()
2021-04-12 22:11:38 +03:00
curses.echo()
curses.endwin()
2021-04-14 23:50:31 +03:00
def gen_map_step(map):
tmp_map = copy.deepcopy(map)
for i in range(1, len(map) - 1):
for j in range(1, len(map[i]) - 1):
x = 0
for d in EXTENDED_DIRECTIONS:
2021-04-15 14:25:58 +03:00
if tmp_map[i + d[0]][j + d[1]][0] == WALL:
x += 1
if x < 2 or x >= 4:
2021-04-15 14:25:58 +03:00
map[i][j] = [EMPTY, SIMPLE_COLOR]
elif x >= 3 and x <= 3:
map[i][j] = [WALL, WALL_COLOR]
def generate_map(map, sz_x, sz_y, map_symbols,
automata_iterations, wall_rand_range,
wall_rand_gen):
2021-04-12 22:18:20 +03:00
rand_sum = 0
2021-04-13 01:20:31 +03:00
for symbol in map_symbols:
rand_sum += symbol[1]
2021-04-12 22:18:20 +03:00
2021-04-14 23:50:31 +03:00
for i in range(sz_x):
2021-04-13 01:20:31 +03:00
map.append([])
2021-04-14 23:50:31 +03:00
for j in range(sz_y):
if i == 0 or j == 0 or i == sz_x - 1 or j == sz_y - 1:
map[i].append([WALL, WALL_COLOR])
else:
if random.randint(1, wall_rand_range) <= wall_rand_gen:
map[i].append([WALL, WALL_COLOR])
else:
map[i].append([EMPTY, SIMPLE_COLOR])
for i in range(automata_iterations):
gen_map_step(map)
for i in range(1, len(map) - 1):
for j in range(1, len(map[i]) - 1):
if (map[i][j][0] == EMPTY):
2021-04-14 23:50:31 +03:00
x = random.randint(1, rand_sum)
for symbol in map_symbols:
x -= symbol[1]
if x <= 0:
map[i][j] = symbol[0]
2021-04-14 23:50:31 +03:00
break
2021-04-12 22:11:38 +03:00
2021-04-13 01:20:31 +03:00
def map_mark_dfs(map, i, j):
2021-04-15 00:24:44 +03:00
if map[i][j][0] == WALL or map[i][j][0] == MARK:
2021-04-14 23:50:31 +03:00
return []
2021-04-13 01:20:31 +03:00
positions = [(i, j)]
2021-04-14 23:50:31 +03:00
2021-04-13 01:20:31 +03:00
map[i][j] = (MARK, SIMPLE_COLOR)
for d in DIRECTIONS:
2021-04-14 23:50:31 +03:00
# walls on all sides, then no check needed there
new_positions = map_mark_dfs(map, i + d[0], j + d[1])
for pos in new_positions:
positions.append(pos)
2021-04-13 01:20:31 +03:00
return positions
def generate_doors(map):
doors = []
tmp_map = copy.deepcopy(map)
2021-04-14 23:50:31 +03:00
2021-04-13 01:20:31 +03:00
for i in range(len(tmp_map)):
for j in range(len(tmp_map[i])):
if tmp_map[i][j][0] == EMPTY:
map_mark_dfs(tmp_map, i, j)
2021-04-14 23:50:31 +03:00
map[i][j] = [DOOR, DOOR_COLOR]
doors.append([i, j])
return doors
2021-04-13 01:20:31 +03:00
def random_direction():
k = random.randint(0, 3)
2021-04-14 23:50:31 +03:00
return [((k % 2) * 2 - 1) * (k // 2),
((k % 2) * 2 - 1) * (1 - k // 2)]
2021-04-13 01:20:31 +03:00
def generate_monsters(map, rand_range, rand_monster):
monsters = []
for i in range(len(map)):
for j in range(len(map[i])):
if (map[i][j][0] == EMPTY):
if random.randint(1, rand_range) <= rand_monster:
2021-04-14 23:50:31 +03:00
monsters.append([[i, j], random_direction()])
2021-04-13 01:20:31 +03:00
# position, move direction
return monsters
def move_monsters(map, monsters):
for i in range(len(monsters)):
2021-04-14 23:50:31 +03:00
pos = [0, 0]
pos[0] = monsters[i][0][0] + monsters[i][1][0]
pos[1] = monsters[i][0][1] + monsters[i][1][1]
2021-04-15 14:25:58 +03:00
if map[pos[0]][pos[1]][0] != WALL:
2021-04-14 23:50:31 +03:00
monsters[i][0] = pos
pass
else:
monsters[i][1] = random_direction()
pass
def damage_player(monsters, player_state):
for m in monsters:
2021-04-15 14:25:58 +03:00
if abs(player_state[P_POS][0] - m[0][0]) + abs(player_state[P_POS][1] - m[0][1]) <= 1:
player_state[P_HEALTH] -= MONSTER_DAMAGE
2021-04-12 22:11:38 +03:00
pass
2021-04-14 23:50:31 +03:00
def game_step(map, monsters, player_state, doors):
#if player_pos == door for any door ?
2021-04-13 01:20:31 +03:00
move_monsters(map, monsters)
2021-04-14 23:50:31 +03:00
damage_player(monsters, player_state)
2021-04-13 01:20:31 +03:00
pass
2021-04-12 22:11:38 +03:00
2021-04-15 14:25:58 +03:00
def draw(stdscr, map, monsters, active_weapon, player_state):
stdscr.addstr(0, 0, str(player_state))
info_str = [
"Health: " + str(player_state[P_HEALTH]),
"Weapon: " + str(player_state[P_WEAPON]),
"Gold: " + str(player_state[P_GOLD]),
"",
"Help:",
"",
"ARROWS - move",
"",
"WASD - use",
"weapon",
"",
"QE - move",
"through doors",
"",
"You must",
"collect",
"all score",
"",
"% - weapon",
"# - wall",
"@ - score",
"M - monster",
"P - player",
"> - door",
"$ - money",
"+ - add health"
]
2021-04-15 00:24:44 +03:00
2021-04-15 14:25:58 +03:00
for i in range(len(info_str)):
stdscr.addstr(MAP_POS_Y - 1 + i, 0, info_str[i],
curses.color_pair(HIGHLIGHTED_COLOR))
2021-04-15 00:24:44 +03:00
2021-04-13 01:20:31 +03:00
for i in range(len(map)):
stdscr.addstr(MAP_POS_Y - 1, i + MAP_POS_X,
'-', curses.color_pair(SIMPLE_COLOR))
stdscr.addstr(len(map[0]) + MAP_POS_Y, i + MAP_POS_X,
'-', curses.color_pair(SIMPLE_COLOR))
for i in range(len(map[0])): # ?? better ??
stdscr.addstr(i + MAP_POS_Y, MAP_POS_X - 1,
'|', curses.color_pair(SIMPLE_COLOR))
stdscr.addstr(i + MAP_POS_Y, len(map) + MAP_POS_X,
'|', curses.color_pair(SIMPLE_COLOR))
for i in range(len(map)):
for j in range(len(map[i])):
stdscr.addstr(j + MAP_POS_Y, i + MAP_POS_X,
2021-04-15 14:25:58 +03:00
map[i][j][0], curses.color_pair(map[i][j][1]))
2021-04-13 01:20:31 +03:00
for m in monsters:
stdscr.addstr(m[0][1] + MAP_POS_Y, m[0][0] + MAP_POS_X,
2021-04-14 23:50:31 +03:00
MONSTER, curses.color_pair(MONSTER_COLOR))
2021-04-13 01:20:31 +03:00
2021-04-15 14:25:58 +03:00
for w in active_weapon:
stdscr.addstr(w[0][1] + MAP_POS_Y, w[0][0] + MAP_POS_X,
ACTIVE_WEAPON, curses.color_pair(ACTIVE_WEAPON_COLOR))
stdscr.addstr(MAP_POS_Y + player_state[P_POS][1],
MAP_POS_X + player_state[P_POS][0], PLAYER,
2021-04-13 01:20:31 +03:00
curses.color_pair(PLAYER_COLOR))
def input(stdscr): # not work
2021-04-14 23:50:31 +03:00
m = [0, 0]
2021-04-15 14:25:58 +03:00
key = ""
2021-04-14 23:50:31 +03:00
2021-04-13 01:20:31 +03:00
try:
key = stdscr.getkey()
2021-04-15 14:25:58 +03:00
if key == MOVE_UP_ACTION:
2021-04-13 01:20:31 +03:00
m[1] -= 1
2021-04-15 14:25:58 +03:00
elif key == MOVE_DOWN_ACTION:
2021-04-13 01:20:31 +03:00
m[1] += 1
2021-04-15 14:25:58 +03:00
elif key == MOVE_LEFT_ACTION:
2021-04-13 01:20:31 +03:00
m[0] -= 1
2021-04-15 14:25:58 +03:00
elif key == MOVE_RIGHT_ACTION:
2021-04-13 01:20:31 +03:00
m[0] += 1
except:
pass
# no input
2021-04-14 23:50:31 +03:00
2021-04-15 14:25:58 +03:00
return (m, key)
2021-04-13 01:20:31 +03:00
pass
2021-04-12 21:17:06 +03:00
2021-04-14 23:50:31 +03:00
def move_player(map, player_state, pos_change):
2021-04-15 00:24:44 +03:00
p = copy.deepcopy(player_state[0])
p[0] += pos_change[0]
p[1] += pos_change[1]
2021-04-14 23:50:31 +03:00
2021-04-15 00:24:44 +03:00
x = map[p[0]][p[1]][0]
2021-04-14 23:50:31 +03:00
2021-04-15 00:24:44 +03:00
if x != WALL:
player_state[0] = p
if x == ADD_HEALTH:
2021-04-15 14:25:58 +03:00
player_state[P_HEALTH] += 1
2021-04-15 00:24:44 +03:00
elif x == WEAPON:
2021-04-15 14:25:58 +03:00
player_state[P_WEAPON] += 1
2021-04-15 00:24:44 +03:00
elif x == GOLD:
2021-04-15 14:25:58 +03:00
player_state[P_GOLD] += 1
elif x == SCORE:
player_state[P_SCORE] += 1
if x != WALL and x != DOOR:
map[p[0]][p[1]] = [EMPTY, SIMPLE_COLOR]
def use_weapon(map, active_weapon, player_state, direction):
p = copy.deepcopy(player_state[P_POS])
p[0] += direction[0]
p[1] += direction[1]
if map[p[0]][p[1]][0] == WALL:
if p[0] != 0 and p[1] != 0 and p[0] != len(map) - 1 and p[1] != len(map[0]):
2021-04-15 00:24:44 +03:00
map[p[0]][p[1]] = [EMPTY, SIMPLE_COLOR]
2021-04-15 14:25:58 +03:00
else:
active_weapon.append([p, copy.deepcopy(direction)])
def player_actions(map, doors, active_weapon, player_state, player_action):
if doors[player_state[P_ACTIVE_DOOR]]:
if player_action == NEXT_DOOR_ACTION:
player_state[P_ACTIVE_DOOR] += 1
player_state[P_ACTIVE_DOOR] %= len(doors)
player_state[P_POS] = copy.deepcopy(
doors[player_state[P_ACTIVE_DOOR]])
elif player_action == PREV_DOOR_ACTION:
player_state[P_ACTIVE_DOOR] = (player_state[P_ACTIVE_DOOR]
+ len(doors) - 1) % len(doors)
player_state[P_POS] = copy.deepcopy(
doors[player_state[P_ACTIVE_DOOR]])
k = -1
if player_action == ATTACK_UP_ACTION:
k = 0
elif player_action == ATTACK_DOWN_ACTION:
k = 1
elif player_action == ATTACK_LEFT_ACTION:
k = 2
elif player_action == ATTACK_RIGHT_ACTION:
k = 3
if k >= 0:
use_weapon(map, active_weapon, player_state, DIRECTIONS[k])
def move_weapon(map, active_weapon, player_state): # needed to test
remove_list = []
for i in range(len(active_weapon)):
p = copy.deepcopy(active_weapon[i][0])
p[0] += active_weapon[i][1][0]
p[1] += active_weapon[i][1][1]
if map[p[0]][p[1]][0] == WALL or \
map[p[0]][p[1]][0] == DOOR:
p = active_weapon[i][0]
if map[p[0]][p[1]][0] == SCORE:
player_state[P_SCORE] += 1
map[p[0]][p[1]] = [WALL, WALL_COLOR]
remove_list.append(i)
else:
active_weapon[i][0] = p
for i in remove_list:
active_weapon.remove(active_weapon[i])
def calc_max_score(map):
max_score = 0
for row in map:
for cell in row:
if cell[0] == SCORE:
max_score += 1
return max_score
2021-04-14 23:50:31 +03:00
2021-04-12 22:11:38 +03:00
def main():
2021-04-13 01:20:31 +03:00
map_symbols = [
2021-04-15 14:25:58 +03:00
[[EMPTY, SIMPLE_COLOR], 90],
[[GOLD, GOLD_COLOR], 2],
[[WEAPON, WEAPON_COLOR], 4],
[[ADD_HEALTH, ADD_HEALTH_COLOR], 2],
[[SCORE, SCORE_COLOR], 2]
2021-04-13 01:20:31 +03:00
]
2021-04-12 22:11:38 +03:00
stdscr = begin_curses()
2021-04-15 14:25:58 +03:00
map_size = [40, 20]
2021-04-13 01:20:31 +03:00
2021-04-15 14:25:58 +03:00
active_weapon = [] # positions of active weapon
2021-04-13 01:20:31 +03:00
2021-04-12 22:11:38 +03:00
map = []
2021-04-15 14:25:58 +03:00
generate_map(map, map_size[0], map_size[1], map_symbols, 20, 100, 45)
2021-04-13 01:20:31 +03:00
doors = generate_doors(map)
2021-04-15 14:25:58 +03:00
monsters = generate_monsters(map, 100, 3)
2021-04-14 23:50:31 +03:00
2021-04-15 14:25:58 +03:00
max_score = calc_max_score(map)
player_state = [doors[0], 10, 2, 0, 0, 0]
# pos = [x, y], lives, weapon, money, active door, score
2021-04-13 01:20:31 +03:00
main_loop_exception = False
2021-04-12 22:11:38 +03:00
2021-04-15 14:25:58 +03:00
player_win = False
2021-04-13 01:20:31 +03:00
2021-04-15 14:25:58 +03:00
try:
while(True):
stdscr.clear()
game_step(map, monsters, player_state, doors)
draw(stdscr, map, monsters, active_weapon, player_state)
stdscr.refresh()
pos_change, player_action = input(stdscr)
move_player(map, player_state, pos_change)
player_actions(map, doors, active_weapon, player_state, player_action)
for i in range(WEAPON_SPEED):
move_weapon(map, active_weapon, player_state)
if player_state[P_HEALTH] <= 0:
break
if player_state[P_SCORE] == max_score:
player_win = True
break # win
except:
main_loop_exception = True
2021-04-12 22:11:38 +03:00
end_curses(stdscr)
2021-04-13 01:20:31 +03:00
if main_loop_exception:
2021-04-15 14:25:58 +03:00
print("Error during main loop")
elif player_win:
print("You win!")
else:
print("You lose(")
2021-04-13 01:20:31 +03:00
2021-04-14 23:50:31 +03:00
main()