started implementing level gen and char creation

The levels off the start (mostly for testing) are hard-coded, but
I would like to eventually integrate at least some element of randomness
to them to give it a more dynamic feel from one playthrough to another.
That will also save me effort in having to design each individual level,
but it does mean that I need to make sure I don't have the randomly
generated levels somehow lock the player out of advancing the game.

For character creation eventually the warrior will be a melee based
character while the mage and rogue will be ranged characters - I'm not
sure how ranged attacks will work in the terminal, but that's the next
thing on my list to test. From there, I want to start interacting with
enemies and have both dynamic monster difficulty from level to level and
a level-up system for the player to scale with the monsters.

Probably not going to get to all 100 levels the original game has,
but I would like to get to a point where I through Sauron and Morgoth at
the player and have that feel like it matters. If I can get 5 levels
and a halfway decent combat system, I'll be floored and probably spend
my entire summer developing this project...
This commit is contained in:
Pat Wick 2024-03-03 20:11:56 -05:00
parent 2d97380a0b
commit 03c110bea2
10 changed files with 169 additions and 3 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

36
angband.py Normal file
View File

@ -0,0 +1,36 @@
from retro.game import Game
from player import Player
from dungeon import Dungeon
from random import sample
from wall import Wall
from map import (
board_edges,
inner_board,
level_one,
)
print("Welcome to AngBAD (a poor representation of Angband)!\n")
race = input("Choose your race (Human, Elf, Dwarf): ").capitalize()
while race not in ["Human", "Elf", "Dwarf"]:
print("Invalid race. Please choose Human, Elf, or Dwarf.")
race = input("Choose your race (Human, Elf, Dwarf): ").capitalize()
class_ = input("Choose your class (Warrior, Mage, Rogue): ").capitalize()
while class_ not in ["Warrior", "Mage", "Rogue"]:
print("Invalid class. Please choose Warrior, Mage, or Rogue.")
class_ = input("Choose your class (Warrior, Mage, Rogue): ").capitalize()
print(f"\nYou've chosen to play as a {race} {class_}.")
input("Press Enter to continue. Good luck!")
board_size = (25,25)
x,y = board_size
walls = [Wall(position) for position in board_edges(board_size)]
level = [Wall(position) for position in level_one(board_size)]
game = Game(walls + level, {}, board_size = board_size)
game.add_agent(Player((x//2,y//2),race,class_))
game.play()

27
dungeon.py Normal file
View File

@ -0,0 +1,27 @@
# dungeon.py
# ------------
# By Pat Wick
# This module defines a dungeon generation algorithm. I
# still need to figure out what that might actually mean
class Dungeon:
board_size = (10,10)
board_width = 10
board_height = 10
position = (0,0)
dungeon_map = [["."] * board_width] * board_height
for row in range(board_height):
for col in range(board_width):
if row == 0 or row == board_height-1:
dungeon_map[row][col] = "#"
else:
if col == 0 or col == board_width-1:
dungeon_map[row][col] = "#"
else:
dungeon_map[row][col] = "."
def __init__(self, position):
self.position = position
self.name = "dungeon"

49
map.py Normal file
View File

@ -0,0 +1,49 @@
from retro.game import Game
from random import sample
from player import Player
from wall import Wall
def board_edges(board_size):
x,y = board_size
positions = []
top = [(i,0) for i in range(x)]
bottom = [(i,y-1) for i in range(x)]
left = [(0,j) for j in range(1,y-1)]
right = [(x-1,j) for j in range(1,y-1)]
return top + bottom + left + right
def inner_board(board_size):
x,y = board_size
positions = []
for i in range(1,x-1):
for j in range(1,y-1):
positions.append((i,j))
return positions
def level_one(board_size):
x,y = board_size
positions = []
for i in range(1,x-1):
for j in range(1,y//4):
if i <= x // 4 or i >= x - (x // 4):
positions.append((i,j))
for i in range(1,x//4):
for j in range((y - (y // 4)), y-1):
positions.append((i,j))
# for i in range(1,x-1):
# for j in range(1,y-1):
# if i >=4 and i <= 7 or i >= 13 and i <= 16:
# if j >= 4 and j <= 7 or j >= 13 and j <= 16:
# positions.append((i,j))
return positions
def level_two(board_size):
x,y = board_size
positions = []
for i in range(1,x-1):
for j in range(1,y-1):
if i >=4 and i <= 7 or i >= 13 and i <= 16:
if j >= 4 and j <= 7 or j >= 13 and j <= 16:
positions.append((i,j))
return positions

48
player.py Normal file
View File

@ -0,0 +1,48 @@
# player.py
# ------------
# By Pat Wick
# This module defines a player agent class. This is intended
# to be used in an implementation of an adventure game but could
# generally be adapted for other player character uses.
from retro.agent import ArrowKeyAgent
class Player:
character = "O"
name = "player"
level = 1
def __init__(self, position, race, class_):
self.position = position
if class_.capitalize() == "Warrior":
self.color = "red"
elif class_.capitalize() == "Rogue":
self.color = "green"
else:
self.color = "blue"
def handle_keystroke(self, keystroke, game):
x, y = self.position
if keystroke.name in ("KEY_LEFT", "KEY_RIGHT"):
if keystroke.name == "KEY_LEFT":
new_position = (x - 1, y)
else:
new_position = (x + 1, y)
if game.on_board(new_position):
if game.is_empty(new_position):
self.position = new_position
if keystroke.name in ("KEY_DOWN", "KEY_UP"):
if keystroke.name == "KEY_DOWN":
new_position = (x, y + 1)
else:
new_position = (x, y - 1)
if game.on_board(new_position):
if game.is_empty(new_position):
self.position = new_position
def get_agent_in_position(self, position, game):
agents = game.get_agents_by_position()[position]
if agents:
return agents[0]

6
poetry.lock generated
View File

@ -393,13 +393,13 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
[[package]] [[package]]
name = "retro-games" name = "retro-games"
version = "0.1.2" version = "0.1.3"
description = "A simple framework for Terminal-based games" description = "A simple framework for Terminal-based games"
optional = false optional = false
python-versions = ">=3.10,<4.0" python-versions = ">=3.10,<4.0"
files = [ files = [
{file = "retro_games-0.1.2-py3-none-any.whl", hash = "sha256:5f906c2755c7ab7328120a1f38164e806c6d27e7433d47995648bda01817284b"}, {file = "retro_games-0.1.3-py3-none-any.whl", hash = "sha256:7567c3a65cf5deb855bded8db810a66902b9706349dde415b6254de087a6d8f9"},
{file = "retro_games-0.1.2.tar.gz", hash = "sha256:b6cb2212c6c8fba011b37a36e638477922d2de8cb5834412963e1cbd240d9a8f"}, {file = "retro_games-0.1.3.tar.gz", hash = "sha256:a95fbeacdf903761b4c70522dd25f858d9802dcd701e900b95b7535f0014f266"},
] ]
[package.dependencies] [package.dependencies]

6
wall.py Normal file
View File

@ -0,0 +1,6 @@
class Wall:
#name = "wall"
character = ""
def __init__(self,position):
self.position = position