all repos — Legends-RPG @ c34273ecf367cfde3fa95f9181f1e4ca13095502

A fantasy mini-RPG built with Python and Pygame.

Refactored level states, began making the castle level
Justin Armstrong justinmeister@gmail.com
Mon, 17 Mar 2014 17:01:01 -0700
commit

c34273ecf367cfde3fa95f9181f1e4ca13095502

parent

9c199248033bcdb14712e2705aa0b8b200e044c0

M data/components/person.pydata/components/person.py

@@ -8,12 +8,15 @@ class Person(pg.sprite.Sprite):

"""Base class for all world characters controlled by the computer""" - def __init__(self, sheet_key, x, y, direction='down'): + def __init__(self, sheet_key, x, y, direction='down', state='animated resting'): super(Person, self).__init__() self.get_image = setup.tools.get_image self.spritesheet_dict = self.create_spritesheet_dict(sheet_key) self.animation_dict = self.create_animation_dict() - self.index = 0 + if direction == 'left': + self.index = 1 + else: + self.index = 0 self.direction = direction self.image_list = self.animation_dict[self.direction] self.image = self.image_list[self.index]

@@ -26,10 +29,11 @@ self.y_vel = 0

self.timer = 0.0 self.move_timer = 0.0 self.current_time = 0.0 - self.state = 'animated resting' + self.state = state self.blockers = self.set_blockers() self.location = self.get_tile_location() self.dialogue = ['Placeholder Dialogue'] + self.name = sheet_key def create_spritesheet_dict(self, sheet_key):

@@ -93,7 +97,7 @@

return vector_dict - def update(self, current_time): + def update(self, current_time, *args): """Implemented by inheriting classes""" self.blockers = self.set_blockers() self.current_time = current_time

@@ -101,6 +105,7 @@ self.image_list = self.animation_dict[self.direction]

state_function = self.state_dict[self.state] state_function() self.location = self.get_tile_location() + def set_blockers(self):

@@ -304,9 +309,8 @@

class Soldier(Person): """Soldier for the castle""" - def __init__(self, x, y): - super(Soldier, self).__init__('soldier', x, y) - self.state = 'animated resting' + def __init__(self, x, y, direction='down', state='animated resting'): + super(Soldier, self).__init__('soldier', x, y, direction, state)
M data/constants.pydata/constants.py

@@ -8,6 +8,7 @@ ##GAME STATES"""

TOWN = 'town' MAIN_MENU = 'main menu' +CASTLE = 'castle' ##Colors
M data/main.pydata/main.py

@@ -1,14 +1,18 @@

+from data.states.main_menu import main_menu +from data.states.town import town +from data.states.castle import castle + __author__ = 'justinarmstrong' from . import setup, tools -from . states import town, main_menu from . import constants as c def main(): """Add states to control here""" run_it = tools.Control(setup.ORIGINAL_CAPTION) - state_dict = {c.TOWN: town.Town(), - c.MAIN_MENU: main_menu.Menu()} + state_dict = {c.TOWN: town.Town(c.TOWN), + c.MAIN_MENU: main_menu.Menu(c.MAIN_MENU), + c.CASTLE: castle.Castle(c.CASTLE)} run_it.setup_states(state_dict, c.MAIN_MENU) run_it.main()
A data/states/castle/__init__.py

@@ -0,0 +1,1 @@

+__author__ = 'justinarmstrong'
A data/states/castle/castle.py

@@ -0,0 +1,15 @@

+"""This is the castle state. Most of its functionality is inherited +from the level_state.py module. Most of the level data is contained +in the tilemap .txt files in this state's directory. Essentially the +only purpose of castle.py is to assign dialogue to each sprite. +""" + +from .. import level_state + +class Castle(level_state.LevelState): + def __init__(self, name): + super(Castle, self).__init__(name) + + def set_sprite_dialogue(self): + """Sets unique dialogue for each sprite""" + return None
A data/states/castle/layer1.txt

@@ -0,0 +1,51 @@

+0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +000VHHHHHHPFFFAHHHHHHX000 +000VHHHHHHPFFFAHHHHHHX000 +000VHHHHHHPFFFAHHHHHHX000 +000VHHHHHHPFFFAHHHHHHX000 +000VHHHHHHPFFFAHHHHHHX000 +000VHHHHHHPFFFAHHHHHHX000 +000VHHHHHHPFFFAHHHHHHX000 +000VHHHHHHPFFFAHHHHHHX000 +000VHHHHHHPFFFAHHHHHHX000 +000VHHHHHHPFFFAHHHHHHX000 +000VHHHHHHPFFFAHHHHHHX000 +000VHHHHHHPFFFAHHHHHHX000 +000VHHHHHHPFFFAHHHHHHX000 +000VHHHHHHPFFFAHHHHHHX000 +000VHHHHHHPFFFAHHHHHHX000 +000VHHHHHHPFFFAHHHHHHX000 +000VHHHHHHPFFFAHHHHHHX000 +000VHHHHHHPFFFAHHHHHHX000 +000VHHHHHHPFFFAHHHHHHX000 +000VHHHHHHPFFFAHHHHHHX000 +000VHHHHHHPFFFAHHHHHHX000 +000VHHHHHHPFFFAHHHHHHX000 +000VHHHHHHPFFFAHHHHHHX000 +000VHHHHHHPFFFAHHHHHHX000 +000VHHHHHHRDDDUHHHHHHX000 +
A data/states/castle/sprite_start_pos.txt

@@ -0,0 +1,51 @@

+0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000000000000000000000 +0000000A000000000B0000000 +0000000000000000000000000 +0000000A000000000B0000000 +0000000000000000000000000 +0000000A000000000B0000000 +0000000000000000000000000 +0000000A000000000B0000000 +0000000000000000000000000 +0000000A000000000B0000000 +0000000000000000000000000 +0000000000000000000000000 +000000000000P000000000000 +
M data/states/main_menu.pydata/states/main_menu/main_menu.py

@@ -1,13 +1,13 @@

__author__ = 'justinarmstrong' import pygame as pg -from .. import setup, tools -from .. import constants as c +from ... import setup, tools +from ... import constants as c class Menu(tools._State): - def __init__(self): - tools._State.__init__(self) + def __init__(self, name): + super(Menu, self).__init__(name) self.next = c.TOWN self.surface = setup.SCREEN self.rect = self.surface.get_rect()
A data/states/main_menu/__init__.py

@@ -0,0 +1,1 @@

+__author__ = 'justinarmstrong'
D data/states/sprite_start_pos.txt

@@ -1,50 +0,0 @@

-0000000000000000000000000 -00C00C00C00C00C00C0C00000 -00V000000000000000000V000 -00V000011111111110000V000 -00V000011111111110000V000 -00V000011111111110000V000 -00V000011111111110000V000 -0TV0000000S00S0000000V000 -00V000000000000000000V000 -00C00C00C0000C00C00C00000 -0000000000000000000000000 -00000000000BB000000000000 -MMMMMMMMMMMBBMMMMMMMMMMMM -T000000000S00S0000000000T -0000000000011000000000000 -T00000000001100000000000T -0000000000011000000000000 -T00000000001100000000000T -0000000000011000000000000 -T33303330001100003330333T -0333033300011000033303330 -T22202220001100002220222T -0222022200011000022202220 -T01000100001100000100010T -0T111111111111111111111T0 -T00000000001100000000000T -0T000000000110000000000T0 -T0T00000001GG100000000T0T -0T0T000001GGGG1000000T0T0 -T0T00T00001GG1000000T0T0T -0T000000000110000000000T0 -0000000000011000000000000 -MMMMMMMMMMM11MMMMMMMMMMMM -0T000000000110000000000T0 -T00000000001100000000000T -0T000000000110000000000T0 -T0T0T0000001100000000000T -0T0T0000000110000000000T0 -T0T0000000011000000333T0T -0T033300000110000003330T0 -T0T3330000011000000222T0T -0T0222000001100F0002220T0 -T0T2220000011000000010T0T -0T0010000001100000001T0T0 -T0T0111111111111111110T0T -0T0000000001100000000T0T0 -T0T0T00W0F0110000000T0T0T -000T00000001100000000T0T0 -0T000T0000011000000T00T00 -00000000000P1000000000000
M data/states/town.pydata/states/level_state.py

@@ -1,16 +1,20 @@

__author__ = 'justinarmstrong' +""" +This is the base class all level states (i.e. states +where the player can move around the screen) inherit +from. This class inherits from the generic state class +found in the tools.py module. +""" import pygame as pg from .. import tools, collision from .. import tilemap as tm from .. components import person, textbox -from .. import constants as c - -class Town(tools._State): - def __init__(self): - super(Town, self).__init__() +class LevelState(tools._State): + def __init__(self, name): + super(LevelState, self).__init__(name) def startup(self, current_time, persist):

@@ -18,15 +22,16 @@ """Called when the State object is created"""

self.persist = persist self.current_time = current_time self.state = 'normal' - self.town_map = tm.create_town_map() + self.town_map = tm.create_town_map(self.name) self.viewport = tm.create_viewport(self.town_map) - self.blockers = tm.create_blockers() + self.blockers = tm.create_blockers(self.name) self.level_surface = tm.create_level_surface(self.town_map) self.level_rect = self.level_surface.get_rect() self.player = person.Player('up') self.town_sprites = pg.sprite.Group() self.start_positions = tm.set_sprite_positions(self.player, - self.town_sprites) + self.town_sprites, + self.name) self.set_sprite_dialogue() self.collision_handler = collision.CollisionHandler(self.player, self.blockers,

@@ -35,30 +40,12 @@ self.dialogue_handler = textbox.DialogueHandler(self.player,

self.town_sprites, self) self.state_dict = self.make_state_dict() - self.portals = tm.make_level_portals() + self.portals = tm.make_level_portals(self.name) def set_sprite_dialogue(self): """Sets unique dialogue for each sprite""" - for sprite in self.town_sprites: - if sprite.location == (10, 47): - sprite.dialogue = ['Welcome to our town, Mr. Traveller!', - 'The King is loved by all!', - 'You should go visit him in his castle.'] - elif sprite.location == (16, 42): - sprite.dialogue = ['You seem tired, why not rest at our Inn?'] - sprite.begin_auto_resting() - elif sprite.location == (14, 14): - sprite.dialogue = ['Be careful. There are monsters surrounding our town.', - 'Make sure to equip sufficient armour and weapons.', - 'Spells and potions are useful too.'] - elif sprite.location == (11, 14): - sprite.dialogue = ['I have heard rumours that the King has lost something...', - 'Perhaps you should pay him a visit.'] - elif sprite.location == (11, 8): - sprite.dialogue = ['Welcome to the castle, citizen.'] - elif sprite.location == (14, 8): - sprite.dialogue = ['Move along.'] + raise NotImplementedError def make_state_dict(self):

@@ -87,8 +74,7 @@ """Check if the player walks into a door, requiring a level change"""

portal = pg.sprite.spritecollideany(self.player, self.portals) if portal and self.player.state == 'resting': - #self.next = portal.name - self.next = c.TOWN + self.next = portal.name self.done = True
A data/states/town/__init__.py

@@ -0,0 +1,1 @@

+__author__ = 'justinarmstrong'
A data/states/town/sprite_start_pos.txt

@@ -0,0 +1,50 @@

+0000000000000000000000000 +0000000000000000000000000 +00V000000000000000000V000 +00V000011111111110000V000 +00V000011111111110000V000 +00V000011111111110000V000 +00V000011111111110000V000 +00V0000000S11S0000000V000 +00V000000001100000000V000 +0000000000011000000000000 +0000000000011000000000000 +0000000000011000000000000 +0000000000011000000000000 +0000000000S11S00000000000 +0000000000011000000000000 +0000000000011000000000000 +0000000000011000000000000 +0000000000011000000000000 +0000000000011000000000000 +0333033300011000033303330 +0333033300011000033303330 +0222022200011000022202220 +0222022200011000022202220 +0010001000011000001000100 +0011111111111111111111100 +0000000000011000000000000 +0000000000011000000000000 +00000000001GG100000000000 +0000000001GGGG10000000000 +00000000001GG100000000000 +0000000000011000000000000 +0000000000011000000000000 +0000000000011000000000000 +0000000000011000000000000 +0000000000011000000000000 +0000000000011000000000000 +0000000000011000000000000 +0000000000011000000000000 +0000000000011000000333000 +0003330000011000000333000 +0003330000011000000222000 +000222000001100F000222000 +0002220000011000000010000 +0000100000011000000010000 +0000111111111111111110000 +0000000000011000000000000 +0000000W0F011000000000000 +0000000000011000000000000 +0000000000011000000000000 +000000000001P000000000000
A data/states/town/town.py

@@ -0,0 +1,34 @@

+"""This is town state. Most of its functionality is inherited from +the level_state.py module. Most of the level data is contained in +the tilemap .txt files in this state's directory. Essentially the +only purpose of town.py is to assign dialogue to each sprite +""" + +from .. import level_state + +class Town(level_state.LevelState): + def __init__(self, name): + super(Town, self).__init__(name) + + def set_sprite_dialogue(self): + """Sets unique dialogue for each sprite""" + for sprite in self.town_sprites: + if sprite.location == (10, 47): + sprite.dialogue = ['Welcome to our town, Mr. Traveller!', + 'The King is loved by all!', + 'You should go visit him in his castle.'] + elif sprite.location == (16, 42): + sprite.dialogue = ['You seem tired, why not rest at our Inn?'] + sprite.begin_auto_resting() + elif sprite.location == (14, 14): + sprite.dialogue = ['Be careful. There are monsters surrounding our town.', + 'Make sure to equip sufficient armour and weapons.', + 'Spells and potions are useful too.'] + elif sprite.location == (11, 14): + sprite.dialogue = ['I have heard rumours that the King has lost something...', + 'Perhaps you should pay him a visit.'] + elif sprite.location == (11, 8): + sprite.dialogue = ['Welcome to the castle, citizen.'] + elif sprite.location == (14, 8): + sprite.dialogue = ['Move along.'] +
M data/tilemap.pydata/tilemap.py

@@ -37,7 +37,8 @@ tile_dict['castle bridge'] = get_tile(48, 27, tileset1, 16, 32 )

tile_dict['flower1'] = get_tile(64, 64, tileset2) tile_dict['flower2'] = get_tile(80, 64, tileset2) tile_dict['horiz castle wall'] = get_tile(32, 0, tileset3, 48, 32) - tile_dict['vert castle wall'] = get_tile(0, 16, tileset3) + tile_dict['left vert castle wall'] = get_tile(0, 16, tileset3) + tile_dict['right vert castle wall'] = get_tile(162, 16, tileset3) tile_dict['castle tower'] = get_tile(116, 16, tileset1, 48, 64) tile_dict['main castle roof'] = get_tile(0, 0, tileset1, 160, 16) tile_dict['left castle roof piece'] = get_tile(0, 0, tileset1, 48, 16)

@@ -48,9 +49,13 @@ tile_dict['carpet topleft'] = get_tile(112, 112, tileset2)

tile_dict['carpet topright'] = get_tile(144, 112, tileset2) tile_dict['carpet bottomleft'] = get_tile(112, 144, tileset2) tile_dict['carpet bottomright'] = get_tile(144, 144, tileset2) + tile_dict['carpet bottom'] = get_tile(128, 144, tileset2) + tile_dict['carpet top'] = get_tile(128, 144, tileset2) tile_dict['carpet left'] = get_tile(112, 128, tileset2) tile_dict['carpet right'] = get_tile(144, 128, tileset2) + tile_dict['carpet center'] = get_tile(128, 128, tileset2) tile_dict['castle window'] = get_tile(128, 59, tileset1) + tile_dict['marble floor'] = get_tile(80, 96, tileset3) tile_dict['inn sign'] = get_tile(0, 96, medieval_signs, 32, 32) return tile_dict

@@ -68,30 +73,34 @@

return tile_dict -def create_town_map(): +def create_town_map(state): """Blits the different layers of the map onto one surface""" - map = create_background() - map = create_map_layer1(map) - map = create_map_layer2(map) + map = create_background(state) + map = create_map_layer1(map, state) + map = create_map_layer2(map, state) map = scale_map(map) - map = create_map_layer3(map) + map = create_map_layer3(map, state) return map -def create_background(): +def create_background(state_name): """Creates the background surface that the rest of the town map will be blitted on""" size = (25*16, 50*16) surface = pg.Surface(size) - grass_tile = get_image(0, 0, 16, 16, setup.GFX['tileset2']) - grass_rect = grass_tile.get_rect() + if state_name == c.CASTLE: + tile = pg.Surface((16, 16)) + tile.fill(c.NEAR_BLACK) + else: + tile = get_image(0, 0, 16, 16, setup.GFX['tileset2']) + rect = tile.get_rect() for row in range(50): for column in range(25): - grass_rect.y = row * 16 - grass_rect.x = column * 16 - surface.blit(grass_tile, grass_rect) + rect.y = row * 16 + rect.x = column * 16 + surface.blit(tile, rect) surface_rect = surface.get_rect()

@@ -101,10 +110,10 @@

return background_dict -def create_map_layer1(map): +def create_map_layer1(map, state): """Creates the town from a tile map and creates a surface on top of the background""" - tile_map = open(os.path.join('data', 'states', 'town_map.txt'), 'r') + tile_map = open(os.path.join('data', 'states', state, 'layer1.txt'), 'r') for row, line in enumerate(tile_map): for column, letter in enumerate(line):

@@ -145,7 +154,11 @@ tile = town_map_dict['horiz castle wall']

blit_tile_to_map(tile, row, column, map) elif letter == 'V': - tile = town_map_dict['vert castle wall'] + tile = town_map_dict['left vert castle wall'] + blit_tile_to_map(tile, row, column, map) + + elif letter == 'X': + tile = town_map_dict['right vert castle wall'] blit_tile_to_map(tile, row, column, map) elif letter == 'S':

@@ -168,6 +181,10 @@ elif letter == 'U':

tile = town_map_dict['carpet bottomright'] blit_tile_to_map(tile, row, column, map) + elif letter == 'D': + tile = town_map_dict['carpet bottom'] + blit_tile_to_map(tile, row, column, map) + elif letter == 'P': tile = town_map_dict['carpet left'] blit_tile_to_map(tile, row, column, map)

@@ -176,15 +193,23 @@ elif letter == 'A':

tile = town_map_dict['carpet right'] blit_tile_to_map(tile, row, column, map) + elif letter == 'F': + tile = town_map_dict['carpet center'] + blit_tile_to_map(tile, row, column, map) + + elif letter == 'H': + tile = town_map_dict['marble floor'] + blit_tile_to_map(tile, row, column, map) + tile_map.close() return map -def create_map_layer2(map): +def create_map_layer2(map, state): """Creates doors and other items on top of the rest of the map""" - tile_map = open(os.path.join('data', 'states', 'town_layer2.txt'), 'r') + tile_map = open(os.path.join('data', 'states', state, 'layer2.txt'), 'r') for row, line in enumerate(tile_map): for column, letter in enumerate(line):

@@ -204,7 +229,7 @@ elif letter == 'T':

tile = town_map_dict['castle tower'] blit_tile_to_map(tile, row, column, map) elif letter == 'W': - tile = town_map_dict['vert castle wall'] + tile = town_map_dict['left vert castle wall'] blit_tile_to_map(tile, row, column, map) elif letter == 'M': tile = town_map_dict['main castle roof']

@@ -238,9 +263,9 @@

return map -def create_map_layer3(map): +def create_map_layer3(map, state): """Layers for images that are already 32x32""" - tile_map = open(os.path.join('data', 'states', 'town_layer3.txt'), 'r') + tile_map = open(os.path.join('data', 'states', state, 'layer3.txt'), 'r') for row, line in enumerate(tile_map): for column, letter in enumerate(line):

@@ -274,10 +299,10 @@

map['surface'].blit(tile['surface'], tile['rect']) -def create_blockers(): +def create_blockers(state): """Creates invisible rect objects that will prevent the player from walking into trees, buildings and other solid objects""" - tile_map = open(os.path.join('data', 'states', 'town_blocker_layer.txt'), 'r') + tile_map = open(os.path.join('data', 'states', state, 'blockers.txt'), 'r') blockers = [] for row, line in enumerate(tile_map):

@@ -303,9 +328,9 @@ """Create the viewport to view the level through"""

return setup.SCREEN.get_rect(bottom=map['rect'].bottom) -def set_sprite_positions(player, level_sprites): +def set_sprite_positions(player, level_sprites, state): """Set the start positions for all the sprites in the level""" - tile_map = open(os.path.join('data', 'states', 'sprite_start_pos.txt'), 'r') + tile_map = open(os.path.join('data', 'states', state, 'sprite_start_pos.txt'), 'r') for row, line in enumerate(tile_map): for column, letter in enumerate(line):

@@ -317,19 +342,25 @@ level_sprites.add(fem_villager)

elif letter == 'S': soldier = person.Soldier(column*32, row*32) level_sprites.add(soldier) + elif letter == 'A': + soldier = person.Soldier(column*32, row*32, 'right', 'resting') + level_sprites.add(soldier) + elif letter == 'B': + soldier = person.Soldier(column*32, row*32, 'left', 'resting') + level_sprites.add(soldier) tile_map.close() -def make_level_portals(): +def make_level_portals(state): """Create portals to different levels on doors""" - tile_map = open(os.path.join('data', 'states', 'level_change_map.txt'), 'r') + tile_map = open(os.path.join('data', 'states', state, 'portals.txt'), 'r') portal_group = pg.sprite.Group() for row, line in enumerate(tile_map): for column, letter in enumerate(line): if letter == 'A': - portal_group.add(portal.Portal(column, row, c.MAIN_MENU)) + portal_group.add(portal.Portal(column, row, c.CASTLE)) return portal_group
M data/tools.pydata/tools.py

@@ -77,7 +77,7 @@

class _State(object): """Base class for all game states""" - def __init__(self): + def __init__(self, name): self.start_time = 0.0 self.current_time = 0.0 self.done = False

@@ -85,6 +85,7 @@ self.quit = False

self.next = None self.previous = None self.persist = {} + self.name = name def get_event(self, event): pass