Started work on container objects like Chests etc.
[butaba-adventures.git] / leveleditor.py
1 #!/usr/bin/env python
2
3 # level designer gui - this is used to design level graphics
4 # very rough and ready - main purpose is to allow quick game
5 # design. inputting levels by hand array is very tedious
6
7 import pygame
8 import os.path
9 import sys
10 import cPickle
11 import math
12
13 import utility
14
15 # draw the level actually
16 def draw_level (screen, leveldata, tileset):
17 i = 0
18 for row in leveldata:
19 j = 0
20 for tilerow, tilecol, is_solid in row:
21 tilex = tilecol * 48
22 tiley = tilerow * 48
23 screen.blit (tileset, (j*48, i*48), pygame.Rect (tilex, tiley, 48, 48))
24 if is_solid == 1:
25 utility.put_text (screen, j*48+2, i*48+2, 10, (255,255,0), "w")
26 j += 1
27 i += 1
28
29 def display_menu (screen, tileset, tilerow, tilecol):
30 utility.put_text (screen, 490, 10, 10, (255,255,0), "p to pick tile")
31 utility.put_text (screen, 490, 50, 10, (255,255,0), "w to wall (solid)")
32 utility.put_text (screen, 490, 90, 10, (255,255,0), "<Space> or <Enter>")
33 utility.put_text (screen, 490, 110, 10, (255,255,0), "to place")
34 utility.put_text (screen, 490, 150, 10,(255,255,0), "Arrows to move around")
35 utility.put_text (screen, 490, 190, 10, (255,255,0), "s to Save level")
36 utility.put_text (screen, 490, 230, 10, (255,255,0), "q to Quit editor")
37
38 # currently selected tile
39 utility.put_text (screen, 490, 270, 10, (255,255,255), "Tile selected")
40 screen.blit (tileset, (490, 290), (tilecol*48, tilerow*48, 48, 48))
41
42 # draw the tile cursor
43 def draw_cursor (screen, currow, curcol):
44 pygame.draw.rect (screen, (255,255,255), (curcol*48, currow*48, 48, 48), 1)
45
46 # make wall
47 def make_wall (leveldata, row, col):
48 # get the actual data in that place
49 leveldata[row][col][2] = not leveldata[row][col][2]
50
51 # place a tile at current spot
52 def put_tile (leveldata, row, col, tilerow, tilecol):
53 leveldata[row][col][0] = tilerow
54 leveldata[row][col][1] = tilecol
55
56 # picking a tile from the tileset
57 def pick_tile (screen, tileset, selrow, selcol):
58
59 # total number of rows and columns
60 totalrows = tileset.get_height () / 48
61 totalcols = tileset.get_width () / 48
62
63 # implement scrolling within the tileset image in a 480x480 viewport
64
65 # set the current page
66 curpage_cols = selrow / 10
67 curpage_rows = selcol / 10
68
69 # cursor row and column
70 cursor_row = selrow % 10
71 cursor_col = selcol % 10
72
73 # the code for scrolling through the tileset is slightly complicated here are the steps
74 # logic goes like this
75 # e.g. horizontal movement
76 # left arrow key movement:
77 # 1. reduce the absolute column by 1
78 # 2. if absolute column < 0 then set absolute column to last column as total columns - 1
79 # 3. calculate the current page based on absolute column as absolute column / 10
80 # 10 being the number of tile columns per page
81 # 4. calculate the relative column on screen as (abolute column modulo 10) giving a
82 # division remainder between 0 and 9.
83
84 # same logic is used for all other movements
85
86 while 1:
87 screen.fill (pygame.Color (0, 0, 0))
88 screen.blit (tileset, (0, 0), (curpage_cols * 480, curpage_rows * 480, 480, 480))
89 draw_cursor (screen, cursor_row, cursor_col)
90 utility.put_text (screen, 490, 10,10, (255, 255, 0), "<Space> or <Enter>")
91 utility.put_text (screen, 490, 30,10, (255, 255, 0), "to select tile")
92 utility.put_text (screen, 490, 70,10, (255, 255, 0), "<Escape> to return")
93 utility.put_text (screen, 10, 490,10, (255, 255, 0), "Selected: %d row, %d col" % (selrow, selcol))
94 pygame.display.update ()
95 for event in pygame.event.get ():
96 if event.type == pygame.KEYDOWN:
97 if event.key == pygame.K_ESCAPE:
98 return None
99 elif event.key == pygame.K_SPACE or event.key == pygame.K_RETURN:
100 return selrow, selcol
101 elif event.key == pygame.K_UP:
102 # reduce the selected row by 1
103 selrow -= 1
104 if selrow < 0:
105 selrow = totalrows - 1
106
107 # calculate the current page
108 curpage_rows = selrow / 10
109
110 # calculate the current cursor row
111 cursor_row = selrow % 10
112
113 elif event.key == pygame.K_DOWN:
114 # increase the selected row by 1
115 selrow += 1
116 if selrow >= totalrows:
117 selrow = 0
118
119 # calculate the current row page
120 curpage_rows = selrow / 10
121
122 # calculate the cursor row
123 cursor_row = selrow % 10
124 elif event.key == pygame.K_LEFT:
125 # decrease the selected col by 1
126 selcol -= 1
127 if selcol < 0:
128 selcol = totalcols - 1
129
130 # calculate the current column page
131 curpage_cols = selcol / 10
132
133 # calculate the cursor column
134 cursor_col = selcol % 10
135 elif event.key == pygame.K_RIGHT:
136 # increase the selected column by 1
137 selcol += 1
138 if selcol >= totalcols:
139 selcol = 0
140
141 # calculate the current column page
142 curpage_cols = selcol / 10
143
144 # calculate the cursor column
145 cursor_col = selcol % 10
146
147 # the actual level editor
148 def level_editor (fname):
149 # load level data
150 leveldata = cPickle.load (file (fname))
151
152 pygame.init ()
153 # load the tileset
154 tileset = pygame.image.load (os.path.join ("background", "tileset.png"))
155 screen = pygame.display.set_mode ((720, 512))
156 pygame.display.set_caption ("Level editor: %s" % fname)
157 currow, curcol = 0, 0
158 tilerow, tilecol = 0, 0
159
160 while 1:
161 screen.fill (pygame.Color (0, 0, 0))
162 display_menu (screen, tileset, tilerow, tilecol)
163 draw_level (screen, leveldata, tileset)
164 draw_cursor (screen, currow, curcol)
165 pygame.display.update ()
166 for event in pygame.event.get ():
167 if event.type == pygame.KEYDOWN:
168 if event.key == ord ("q"):
169 pygame.quit ()
170 return
171 elif event.key == ord ("s"):
172 cPickle.dump (leveldata, file (fname, "w"))
173 print ("Level saved")
174 elif event.key == pygame.K_DOWN:
175 currow += 1
176 if currow > 9:
177 currow = 0
178 elif event.key == pygame.K_UP:
179 currow -= 1
180 if currow < 0:
181 currow = 9
182 elif event.key == pygame.K_LEFT:
183 curcol -= 1
184 if curcol < 0:
185 curcol = 9
186 elif event.key == pygame.K_RIGHT:
187 curcol += 1
188 if curcol > 9:
189 curcol = 0
190 elif event.key == pygame.K_SPACE or event.key == pygame.K_RETURN:
191 put_tile (leveldata, currow, curcol, tilerow, tilecol)
192 elif event.key == ord ("p"):
193 tile = pick_tile (screen, tileset, tilerow, tilecol)
194 if tile is not None:
195 tilerow = tile[0]
196 tilecol = tile[1]
197 elif event.key == ord ("w"):
198 make_wall (leveldata, currow, curcol)
199
200 def new_level ():
201 print
202 fname = raw_input ("New level file path: ")
203 # prepare level with blank tiles
204 leveldata = [
205 [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]],
206 [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]],
207 [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]],
208 [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]],
209 [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]],
210 [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]],
211 [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]],
212 [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]],
213 [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]],
214 [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
215 ]
216 # save the level first
217 cPickle.dump (leveldata, file (fname, "w"))
218
219 # now edit it
220 level_editor (fname)
221
222 def load_level ():
223 fname = raw_input ("Level file to load: ")
224 level_editor (fname)
225
226 def main ():
227 while 1:
228 print
229 print ("Level Editor for the Adventures of Butaba")
230 print
231 print ("1. Start a new level")
232 print ("2. Load existing level")
233 print ("3. Quit")
234
235 ch = raw_input ("Your choice: ")
236 if ch == "1":
237 new_level ()
238 elif ch == "2":
239 load_level ()
240 elif ch == "3":
241 sys.exit (0)
242 else:
243 print ("Wrong choice. Must be 1, 2, or 3")
244
245
246 if __name__=="__main__":
247 main ()