Files
Not-so-Rogue-like/editor/editor.py

407 lines
13 KiB
Python
Executable File

#!/usr/bin/env python
# Copyright (c) 2014, Miguel Angel Astor Romero. All rights reserved.
# See the file LICENSE for more details.
"""
The map editor for TITLE PENDING, a game for the Cyberpunk Jam 2014.
Usage:
*) Click on a game_map cell to set it's type.
Use the keypad numbers to change the type of cell a cell will turn into
when clicked. The active cell type is displayed on the title bar.
*) Left click to place an object on the game_map.
Objects have to be edited by hand once the game_map has been saved. Use
the keys 'd', 'k', 'p', 'n' and 'e' to set the active object type. The
active object type is displayed on the title bar.
*) Press 'q' to set the player's starting position.
*) Press 's' to save the map to the text file 'map_file.map'. This will
replace any previous map with the same name!
Press escape to quit.
"""
import pygame
CELL_SIZE = 10
MAP_SIZE = (64, 64)
SCREEN_SIZE = ((MAP_SIZE[1] * CELL_SIZE) + 1, (MAP_SIZE[0] * CELL_SIZE) + 1)
SCREEN_FLAGS = pygame.HWSURFACE | pygame.DOUBLEBUF
TITLE = "Cyberpunk Jam 2014 - Level editor"
FPS = 60
# Cell types
VOID = 0
SOLID_WALL = 1
SECRET_WALL = 2
CLEAR_WALL = 3
NEON_WALL = 4
WINDOW_WALL = 5
EMPTY_FLOOR = 6
RUG = 7
WATER = 8
BAR = 9
# Object types
DOOR = 0
KEY = 1
PERSON = 2
PLAYER = 3
EXIT = 4
def get_object_type_name(game_object):
""" Return a string name for an object type. """
name = ""
if game_object == DOOR:
name = "DOOR"
elif game_object == KEY:
name = "KEY"
elif game_object == PERSON:
name = "PERSON"
elif game_object == PLAYER:
name = "PLAYER"
elif game_object == EXIT:
name = "EXIT"
elif game_object == None:
name = "NONE"
else:
raise ValueError("Invalid object type.")
return name
def get_object_type_color(game_object):
""" Return a string name for an object type. """
color = (0, 0, 0)
if game_object == DOOR:
color = (255, 0, 255)
elif game_object == KEY:
color = (255, 255, 0)
elif game_object == PERSON:
color = (0, 255, 255)
elif game_object == PLAYER:
color = (128, 255, 0)
elif game_object == EXIT:
color = (255, 0, 255)
else:
raise ValueError("Invalid object type.")
return color
def get_floor_type_name(floor_type):
""" Return a string name for a floor type. """
name = ""
if floor_type == VOID:
name = "VOID"
elif floor_type == SOLID_WALL:
name = "SOLID WALL"
elif floor_type == SECRET_WALL:
name = "SECRET WALL"
elif floor_type == CLEAR_WALL:
name = "CLEAR WALL"
elif floor_type == NEON_WALL:
name = "NEON WALL"
elif floor_type == WINDOW_WALL:
name = "WINDOW"
elif floor_type == EMPTY_FLOOR:
name = "EMPTY FLOOR"
elif floor_type == RUG:
name = "RUG"
elif floor_type == WATER:
name = "WATER"
elif floor_type == BAR:
name = "BAR"
else:
raise ValueError("Invalid floor type.")
return name
def get_floor_type_color(floor_type):
""" Return a string name for a floor type. """
color = (0, 0, 0)
if floor_type == VOID:
color = (0, 0, 0)
elif floor_type == SOLID_WALL:
color = (255, 255, 255)
elif floor_type == SECRET_WALL:
color = (128, 128, 128)
elif floor_type == CLEAR_WALL:
color = (50, 50, 50)
elif floor_type == NEON_WALL:
color = (255, 0, 0)
elif floor_type == WINDOW_WALL:
color = (128, 128, 255)
elif floor_type == EMPTY_FLOOR:
color = (128, 128, 0)
elif floor_type == RUG:
color = (128, 0, 128)
elif floor_type == WATER:
color = (64, 64, 255)
elif floor_type == BAR:
color = (255, 255, 0)
else:
raise ValueError("Invalid floor type.")
return color
def save_map(game_map):
p_id = 0
dialogs = list()
f = open("map_file.map", "w")
f.write("[MAP]\n")
f.write(str(MAP_SIZE [0]) + " " + str(MAP_SIZE[1]) + "\n")
for i in range(0, MAP_SIZE[0]):
for j in range(0, MAP_SIZE[1]):
f_t = game_map[i][j].get_type();
f.write(str(f_t))
f.write("\n")
f.write("[PLAYER]\n")
f.write("%player = X Y\n")
for i in range(0, MAP_SIZE[0]):
for j in range(0, MAP_SIZE[1]):
o_t = game_map[i][j].get_object();
if o_t is not None and o_t == PLAYER:
f.write("player = " + str(i) + " " + str(j) + "\n")
f.write("[EXITS]\n")
f.write("%exit = X Y MAP_NAME MAP_X MAP_Y\n")
for i in range(0, MAP_SIZE[0]):
for j in range(0, MAP_SIZE[1]):
o_t = game_map[i][j].get_object();
if o_t is not None and o_t == EXIT:
f.write("exit = " + str(i) + " " + str(j))
f.write(" map_file.map 0 0\n")
f.write("[DOORS]\n")
f.write("%door = X Y ID UNLOCKED\n")
for i in range(0, MAP_SIZE[0]):
for j in range(0, MAP_SIZE[1]):
o_t = game_map[i][j].get_object();
if o_t is not None and o_t == DOOR:
f.write("door = " + str(i) + " " + str(j) + " 0" + " 0\n")
f.write("[KEYS]\n")
f.write("%key = X Y ID\n")
for i in range(0, MAP_SIZE[0]):
for j in range(0, MAP_SIZE[1]):
o_t = game_map[i][j].get_object();
if o_t is not None and o_t == KEY:
f.write("key = " + str(i) + " " + str(j) + " 0\n")
f.write("[PERSONS]\n")
f.write("%person = X Y NAME DIALOG_ID\n")
for i in range(0, MAP_SIZE[0]):
for j in range(0, MAP_SIZE[1]):
o_t = game_map[i][j].get_object();
if o_t is not None and o_t == PERSON:
f.write("person = " + str(i) + " " + str(j))
f.write(" SOMEONE " + str(p_id) + "\n")
dialogs.append(p_id)
p_id += 1
f.write("[DIALOGS]\n")
f.write("%dialog = ID TEXT\n")
for id in dialogs:
text = " Heavy boxes perform quick waltzes and jigs.\n"
f.write("dialog = " + str(id) + text)
f.close()
class Cell:
""" A game_map cell. """
def __init__(self, x_size, y_size):
""" Create a new cell. """
self.x_size = x_size
self.y_size = y_size
self.floor_type = VOID
self.game_object = None
# Create the drawing rectangles.
self.border = pygame.Rect((0, 0), (CELL_SIZE, CELL_SIZE))
self.cell = pygame.Rect((0, 0), (CELL_SIZE - 2, CELL_SIZE - 2))
def set_type(self, floor_type):
""" Set this cell floor type. Raises a value error if the type is
not valid. """
if floor_type < VOID or floor_type > BAR:
raise ValueError("Floor type must be a number between 0 and 9.")
else:
self.floor_type = floor_type
def get_type(self):
""" Returns this cell's type. """
return self.floor_type
def set_object(self, game_object):
""" Set this cells object. """
if game_object is not None and game_object < DOOR or game_object > EXIT:
raise ValueError("Object type must be a number between 0 and 2.")
else:
self.game_object = game_object
def get_object(self):
""" Return this cell's object. """
return self.game_object
def draw(self, canvas, x_pos, y_pos):
""" Render this cell at the given position on the given screen. """
self.border.center = (x_pos, y_pos)
self.cell.center = (x_pos, y_pos)
pygame.draw.rect(canvas, (0, 0, 255), self.border)
color = get_floor_type_color(self.floor_type)
pygame.draw.rect(canvas, color, self.cell)
if self.game_object is not None and self.game_object < PLAYER:
r = (CELL_SIZE - 2) // 2
color = get_object_type_color(self.game_object)
pygame.draw.circle(canvas, color, (x_pos, y_pos), r, 1)
elif self.game_object is not None and self.game_object >= PLAYER:
r = (CELL_SIZE - 3) // 2
color = get_object_type_color(self.game_object)
pygame.draw.circle(canvas, color, (x_pos, y_pos), r, 0)
def main():
""" Application entry point. """
# Local variables
done = False
game_map = list()
curr_obj = None
curr_fl = VOID
obj_str = ""
fl_str = ""
mouse_pos = (0, 0)
mouse_r_click = False
mouse_l_click = False
# Initialize Pygame.
pygame.init()
clock = pygame.time.Clock()
screen = pygame.display.set_mode(SCREEN_SIZE, SCREEN_FLAGS)
pygame.mouse.set_visible(True)
for i in range(0, MAP_SIZE[0]):
game_map.append([Cell(10, 10) for j in range(0, MAP_SIZE[1])])
# Main game loop.
while(not done):
try:
fps = clock.get_fps() + 0.001
# Set title bar.
obj_str = get_object_type_name(curr_obj)
fl_str = get_floor_type_name(curr_fl)
title = TITLE + " :: FPS: " + str(int(fps))
title += " :: " + obj_str + " :: " + fl_str
pygame.display.set_caption(title)
# Input capture.
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.MOUSEBUTTONDOWN:
mouse_pos = event.pos
if event.button == 1:
mouse_r_click = True
elif event.button == 3:
mouse_l_click = True
if event.type == pygame.MOUSEMOTION:
if mouse_r_click:
mouse_pos = event.pos
if event.type == pygame.MOUSEBUTTONUP:
mouse_pos = event.pos
if event.button == 1:
mouse_r_click = False
elif event.button == 3:
mouse_l_click = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
done = True
if event.key == pygame.K_d:
curr_obj = DOOR
if event.key == pygame.K_k:
curr_obj = KEY
if event.key == pygame.K_p:
curr_obj = PERSON
if event.key == pygame.K_q:
curr_obj = PLAYER
if event.key == pygame.K_e:
curr_obj = EXIT
if event.key == pygame.K_n:
curr_obj = None
if event.key == pygame.K_0:
curr_fl = VOID
if event.key == pygame.K_1:
curr_fl = SOLID_WALL
if event.key == pygame.K_2:
curr_fl = SECRET_WALL
if event.key == pygame.K_3:
curr_fl = CLEAR_WALL
if event.key == pygame.K_4:
curr_fl = NEON_WALL
if event.key == pygame.K_5:
curr_fl = WINDOW_WALL
if event.key == pygame.K_6:
curr_fl = EMPTY_FLOOR
if event.key == pygame.K_7:
curr_fl = RUG
if event.key == pygame.K_8:
curr_fl = WATER
if event.key == pygame.K_9:
curr_fl = BAR
if event.key == pygame.K_s:
save_map(game_map)
# Update cycle.
if mouse_r_click:
i = mouse_pos[1] // CELL_SIZE
j = mouse_pos[0] // CELL_SIZE
if i >= MAP_SIZE[0]:
i = MAP_SIZE[0] - 1
if j >= MAP_SIZE[1]:
j = MAP_SIZE[1] - 1
game_map[i][j].set_type(curr_fl)
if mouse_l_click:
i = mouse_pos[1] // CELL_SIZE
j = mouse_pos[0] // CELL_SIZE
if i >= MAP_SIZE[0]:
i = MAP_SIZE[0] - 1
if j >= MAP_SIZE[1]:
j = MAP_SIZE[1] - 1
game_map[i][j].set_object(curr_obj)
# Render cycle.
screen.fill((0, 0, 0))
for i in range(0, MAP_SIZE[0]):
for j in range(0, MAP_SIZE[1]):
x = (j * CELL_SIZE) + (CELL_SIZE // 2)
y = (i * CELL_SIZE) + (CELL_SIZE // 2)
game_map[i][j].draw(screen, x, y)
pygame.display.update()
clock.tick(FPS)
except KeyboardInterrupt:
done = True
pygame.quit()
if __name__ == "__main__":
main()