I am developing a text-based RPG with a randomly generated world space. I have built a light engine to produce a world for me and fill it with 'world objects' like trees, mountains, villages, and the like. The world can be generated either through a fully automatic method, or a "manual" method, that allows for more specific placement of world objects.
My code might be a bit sloppy, since I'm rather new to Python programming and the world of OOP. That being said, the following code provides the complete WorldSpace
class, but a rather bare-bones version on the Player
class -- a version that just specifies some basic variables to show how I will be structuring the real Player
class.
I believe all of this code to be in working condition. My apologies if any of you get errors.
from random import randint, choice, randrange
Player class:
class Player(object):
def __init__(self, x, y):
self.x = x
self.y = y
self.baseStats = {'health': 1, 'stamina': 0, 'mana': 0, 'equip load': 0,
'level': 1}
self.descStats = {'name': None, 'race': None, 'class': None,
'description': None}
self.baseSkills = {'strength': 0, 'intelligence': 0, 'defense': 0,
'speech': 0, 'endurance': 0, 'faith': 0, 'luck': 0}
self.inventory = {'weapons': [], 'armor sets': [], 'rings': [],
'miracles': [], 'spells': [], 'gold': None, 'keys': None}
self.equipment = {'weapon': None, 'armor set': None, 'rings': []}
def moveNorth(self):
self.x -= 1
def moveSouth(self):
self.x += 1
def moveEast(self):
self.y += 1
def moveWest(self):
self.y -= 1
def movement(self, world):
movement_inp = raw_input("""
W. | Move North
S. | Move South
D. | Move East
A. | Move West
> """).lower()
if movement_inp == 'w':
self.moveNorth()
elif movement_inp == 's':
self.moveSouth()
elif movement_inp == 'd':
self.moveEast()
elif movement_inp == 'a':
self.moveWest()
else:
print 'Not a valid command'
self.movement(world)
hero = Player(1, 2)
World class:
class WorldSpace(object):
world_object_list = ['forest', 'mountain', 'ocean', 'other']
def __init__(self, row, col, world_array):
self.row = row # Number of lists to be created.
self.col = col # Number of indexes inside of each row.
self.world_array = world_array
def genSingle_Char(self, char, count):
# 'genSingle_Char' - Generate single character world objects.
# Adds a number of random, specific characters to the world array.
original_count = count
while count != 0:
row = randrange(len(self.world_array))
column = randrange(len(self.world_array[0]))
if self.world_array[row][column] == ' ':
self.world_array[row][column] = char
count -= 1
print 'Generated {} {}\'s...'.format(original_count, char)
def genLine_WObj(self, a, b, row_val, char, count):
# 'genLine_WObj' - Generate Line(like) world object.
# Used to place lines of psuedo-random width and length onto the world map.
while count != 0:
row_col_dict = {row_val: (a, b)}
for row in row_col_dict.keys():
startPos, endPos = row_col_dict[row]
for i in range(startPos, endPos):
self.world_array[row][i] = char
b += choice([0, 0, 1])
a += choice([0, 0, 0, 1])
row_val -= 1
count -= 1
print 'Generated psuedo-randomized line with world object `{}`'.format(char)
def genShiftBlock(self, a, b, row_val, char, count):
while count != 0:
row_col_dict = {row_val: (a, b)}
for row in row_col_dict.keys():
startPos, endPos = row_col_dict[row]
for i in range(startPos, endPos):
self.world_array[row][i] = char
a += choice([0, 1, -1])
b += choice([0, 1, -1])
row_val -= 1
count -= 1
print 'Generated shift block(`~` | oceans).'
def printPlayerMap(self):
print('\n'.join([''.join(['{:1}'.format(item) for item in row])
for row in self.world_array]))
@classmethod
def generateWorld(cls, autogen):
print 'Starting world generation...'
print
if autogen is True:
row_amt = 35
col_amt = 75
else:
print 'Recommended row amt: 35, recommended col amt: 75.'
print
row_amt = input('Please specify row length of world array.: ')
col_amt = input('Please specify column length of world array.: ')
if (row_amt or col_amt) == 0:
print 'Invalid world values!'
self.generateWorld(False)
world_array = [[' ']*col_amt for _ in xrange(row_amt)]
print 'Created world...'
return WorldSpace(row_amt, col_amt, world_array)
def autoModifyWorld(self):
print 'Now automatically modifying the world space.'
# Forests:
count = randint(1, 4)
while count != 0:
a_val_rand = choice([randint(10, 20), randint(45, 50)])
b_val_rand = a_val_rand + randint(5, 10)
row_val_rand = randint(10, 30)
count_val_rand = randint(4, 8)
self.genLine_WObj(a_val_rand, b_val_rand, row_val_rand, 't',
count_val_rand)
count -= 1
print 'Created forests...'
# Mountains:
a_val_rand = choice([randint(22, 23), randint(45, 46)])
b_val_rand = a_val_rand + 1
row_val_rand = randint(15, 34)
count_val_rand = randint(15, 20)
self.genLine_WObj(a_val_rand, b_val_rand, row_val_rand, 'm',
count_val_rand)
print 'Created mountains...'
# Oceans:
a_val_rand = choice([randint(5, 20), randint(20, 50)])
b_val_rand = a_val_rand + 10
row_val_rand = 34
count_val_rand = randint(5, 15)
self.genShiftBlock(a_val_rand, b_val_rand, row_val_rand, '~',
count_val_rand)
print 'Created oceans...'
# Other:
randCount = randint(2, 4)
while randCount != 0:
char_val_rand = choice(['D', 'V', '$']) # 'Dungeons', 'Village', 'Loot' icons.
count_val_rand = randint(1, 4)
self.genSingle_Char(char_val_rand, count_val_rand)
randCount -= 1
print 'Created random characters...'
print 'Automatically modified world...'
def manualModifyWorld(self):
# The value 'world_object_type' is represented by
# 'forest', 'mountain', 'ocean', or 'other'.
for item in self.world_object_list:
print item
world_object_type = raw_input(
('What world object would you like to implement?: ').lower())
a_val = input('Please specify value [a] of row_col_dict.: ')
b_val = input('Please specify value [b] of row_col_dict: ')
row_val = input('Please specify first row to be modified.: ')
char_val = raw_input('Please specify char used to modify array.: ')
count_val = input('Please specify number of times to repeat action: ')
if world_object_type == 'forest':
self.genLine_WObj(a_val, b_val, row_val, char_val, count_val)
elif world_object_type == 'mountain':
self.genLine_WObj(a_val, b_val, row_val, char_val, count_val)
elif world_object_type == 'ocean':
self.generateLineBlock(a_val, b_val, row_val, char_val, count_val)
elif world_object_type == 'other':
# 'other' is used to add single characters to the map.
char_val = raw_input('Please specify char used to modify array.: ')
count_val = input('Please specify times to repeat action: ')
self.genSingle_Char(char_val, count_val)
else:
print 'Not a valid world object type!'
repeat = input("""Would you like to reuse this function or continue?
1/ Yes, 2/ No.: """)
print
if repeat == 1:
self.manualModifyWorld(False)
elif repeat == 2:
print 'Manually modified world...'
pass
while repeat not in [1, 2]:
print 'Not a valid input.'
repeat = input("""Would you like to reuse this function or continue?
1/ Yes, 2/ No.: """)
print
def main(player):
print """
|[~~Welcome to the whiteWall world creator interface~~]|
"""
auto = input('Would you like to automate this process?: 1/ Yes, 2/ No: ')
if auto == 1:
world = WorldSpace.generateWorld(True)
world.autoModifyWorld()
else:
print """If you have already started a game, enter [1]. Otherwise, it is extremely
important that you enter [2], so that a world space can be generated."""
world_gen_inp = input("""
1. | Boot game?
2. | Generate new world?
> """)
if world_gen_inp == 2:
world = WorldSpace.generateWorld(False)
print
world.manualModifyWorld()
else:
pass
print 'Now booting game...'
# This section is a temporary solution.
# In final version, this will loop to the main game loop.
while player.baseStats['health'] != 0:
print '##PLAYER MAP##'
current_tile = world.world_array[player.x][player.y]
world.world_array[player.x][player.y] = 'P'
world.printPlayerMap()
world.world_array[player.x][player.y] = current_tile
print
player.movement(world)
main(hero)
I'm looking for ways to cut down my code, or improve it in any way:
Creating a map of roughly 2000 x 2000 (or some other large amount) and only printing small sections of the maybe 30 or so tiles around the player at a time, based on their location on the map, to give the impression of a field of view and a nearly endless world.
If a player crosses a water
~
, or a mountainm
tile, have them return to their previous position, to give the impression they cannot walk on certain tiles.