Completed scrolling in tile picker for level editor
[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
12 import utility
13
14 # draw the level actually
15 def draw_level (screen, leveldata, tileset):
16 i = 0
17 for row in leveldata:
18 j = 0
19 for tilerow, tilecol, is_solid in row:
20 tilex = tilecol * 48
21 tiley = tilerow * 48
22 screen.blit (tileset, (j*48, i*48), pygame.Rect (tilex, tiley, 48, 48))
23 if is_solid == 1:
24 utility.put_text (screen, j*48+2, i*48+2, 10, (255,255,0), "w")
25 j += 1
26 i += 1
27
28 def display_menu (screen, tileset, tilerow, tilecol):
29 utility.put_text (screen, 490, 10, 10, (255,255,0), "p to pick tile")
30 utility.put_text (screen, 490, 50, 10, (255,255,0), "w to wall (solid)")
31 utility.put_text (screen, 490, 90, 10, (255,255,0), "<space> to place")
32 utility.put_text (screen, 490, 130, 10,(255,255,0), "Arrows to move around")
33 utility.put_text (screen, 490, 170, 10, (255,255,0), "s to Save level")
34 utility.put_text (screen, 490, 210, 10, (255,255,0), "q to Quit editor")
35
36 # currently selected tile
37 utility.put_text (screen, 490, 250, 10, (255,255,255), "Tile selected")
38 screen.blit (tileset, (490, 290), (tilecol*48, tilerow*48, 48, 48))
39
40 # draw the tile cursor
41 def draw_cursor (screen, currow, curcol):
42 pygame.draw.rect (screen, (255,255,255), (curcol*48, currow*48, 48, 48), 1)
43
44 # make wall
45 def make_wall (leveldata, row, col):
46 # get the actual data in that place
47 leveldata[row][col][2] = not leveldata[row][col][2]
48
49 # place a tile at current spot
50 def put_tile (leveldata, row, col, tilerow, tilecol):
51 leveldata[row][col][0] = tilerow
52 leveldata[row][col][1] = tilecol
53
54 # picking a tile from the tileset
55 def pick_tile (screen, tileset):
56 selrow, selcol = 0, 0
57
58 # total number of rows and columns
59 totalrows = tileset.get_height () / 48
60 totalcols = tileset.get_width () / 48
61
62 # implement scrolling by 480x480
63 # first get the number of pages to span across. If the width is
64 # exactly fitting in the page use totalwidth/480 else totalwidth/480+1
65 # (integer divison)
66 if tileset.get_width () % 480 == 0:
67 totalpages_cols = tileset.get_width () / 480
68 else:
69 totalpages_cols = tileset.get_width () / 480 + 1
70
71 if tileset.get_height () % 480 == 0:
72 totalpages_rows = tileset.get_height () / 480
73 else:
74 totalpages_rows = tileset.get_height () / 480 + 1
75
76 # set the current page
77 curpage_cols = 0
78 curpage_rows = 0
79
80 # cursor row and column
81 cursor_row = 0
82 cursor_col = 0
83
84 # the code for scrolling through the tileset is quite complicated here are the steps
85 # first we determine the total number of pages (number of row pages and col pages
86 # then when scrolling we check for two things:
87 # first horizontal scrolling:
88 # logic goes like this
89 # left arrow key movement:
90 # is the cursor col < 0 ? if so, is it the first page? if so, then set the
91 # cursor col to the last col of the last page. This unfortunately is not so easy
92 # because it need not be 10. So we determine the last col as follows:
93 # total width of the tileset image modulo 480 = this gives us a multiple of 48
94 # since we are using 48x48 tiles and the tileset file size is a multiple of 48.
95 # then we divide that value by 48 which gives us a number between 0 and 9.
96 # this is the last col. If it is not the first page, we simply set the cursor
97 # column to 9 and reduce the page by 1.
98 # right arrow movement:
99 # simply if it is the last col and last page we simply reset the
100 # page to 0 and the cursor col to 0. Otherwise page is incremented by 1
101 # and col is still set to 0. simple logic
102
103 # vertical scrolling using the same logic
104
105 while 1:
106 screen.fill (pygame.Color (0, 0, 0))
107 screen.blit (tileset, (0, 0), (curpage_cols * 480, curpage_rows * 480, 480, 480))
108 draw_cursor (screen, cursor_row, cursor_col)
109 pygame.display.update ()
110 for event in pygame.event.get ():
111 if event.type == pygame.KEYDOWN:
112 if event.key == pygame.K_ESCAPE:
113 return None
114 elif event.key == pygame.K_SPACE or event.key == pygame.K_RETURN:
115 return selrow, selcol
116 elif event.key == pygame.K_UP:
117 # reduce the selected row by 1
118 selrow -= 1
119 if selrow < 0:
120 selrow = totalrows - 1
121
122 # reduce the cursor row by 1
123 cursor_row -= 1
124 # if cursor row is < 0
125 if cursor_row < 0:
126 # reduce the page by 1
127 curpage_rows -= 1
128 if curpage_rows < 0:
129 curpage_rows = totalpages_rows - 1
130 if tileset.get_height () % 480 > 0 :
131 # cursor row should be the last row - this is
132 cursor_row = (tileset.get_height () % 480) / 48 - 1
133 else:
134 cursor_row = 9
135 else:
136 cursor_row = 9
137
138 elif event.key == pygame.K_DOWN:
139 # increase the selected row by 1
140 selrow += 1
141 if selrow >= totalrows:
142 selrow = 0
143
144 # increase the cursor row by 1
145 cursor_row += 1
146 # if cursor row is > 9
147 if ((tileset.get_height () % 480 > 0 and curpage_rows >= totalpages_rows - 1 and cursor_row >= (tileset.get_height () % 480) / 48)
148 or cursor_row >= 10):
149 # increase the page by 1
150 curpage_rows += 1
151 # if the pages rows is >= totalpages_rows
152 if curpage_rows >= totalpages_rows:
153 curpage_rows = 0
154 cursor_row = 0
155 else:
156 cursor_row = 0
157
158 elif event.key == pygame.K_LEFT:
159 # decrease the selected col by 1
160 selcol -= 1
161 if selcol < 0:
162 selcol = totalcols - 1
163
164 # decrease the cursor col by 1
165 cursor_col -= 1
166 # if cursor col < 0
167 if cursor_col < 0:
168 curpage_cols -= 1
169 if curpage_cols < 0:
170 curpage_cols = totalpages_cols - 1
171 if tileset.get_width () % 480 > 0:
172 cursor_col = (tileset.get_width () % 480) / 48 - 1
173 else:
174 cursor_col = 9
175 else:
176 cursor_col = 9
177 elif event.key == pygame.K_RIGHT:
178 selcol += 1
179 if selcol >= totalcols:
180 selcol = 0
181
182 # increase the cursor col by 1
183 cursor_col += 1
184 # if cursor col > 9
185 if ((tileset.get_width () % 480 > 0 and curpage_cols >= totalpages_cols - 1 and cursor_col >= (tileset.get_width () % 480) / 48)
186 or cursor_col >= 10):
187 curpage_cols += 1
188 if curpage_cols >= totalpages_cols:
189 curpage_cols = 0
190 cursor_col = 0
191 else:
192 cursor_col = 0
193
194
195 # the actual level editor
196 def level_editor (fname):
197 # load level data
198 leveldata = cPickle.load (file (fname))
199
200 pygame.init ()
201 # load the tileset
202 tileset = pygame.image.load (os.path.join ("background", "tileset.png"))
203 screen = pygame.display.set_mode ((720, 512))
204 pygame.display.set_caption ("Level editor")
205 currow, curcol = 0, 0
206 tilerow, tilecol = 0, 0
207
208 while 1:
209 screen.fill (pygame.Color (0, 0, 0))
210 display_menu (screen, tileset, tilerow, tilecol)
211 draw_level (screen, leveldata, tileset)
212 draw_cursor (screen, currow, curcol)
213 pygame.display.update ()
214 for event in pygame.event.get ():
215 if event.type == pygame.KEYDOWN:
216 if event.key == ord ("q"):
217 pygame.quit ()
218 return
219 elif event.key == ord ("s"):
220 cPickle.dump (leveldata, file (fname, "w"))
221 print ("Level saved")
222 elif event.key == pygame.K_DOWN:
223 currow += 1
224 if currow > 9:
225 currow = 0
226 elif event.key == pygame.K_UP:
227 currow -= 1
228 if currow < 0:
229 currow = 9
230 elif event.key == pygame.K_LEFT:
231 curcol -= 1
232 if curcol < 0:
233 curcol = 9
234 elif event.key == pygame.K_RIGHT:
235 curcol += 1
236 if curcol > 9:
237 curcol = 0
238 elif event.key == pygame.K_SPACE or event.key == pygame.K_RETURN:
239 put_tile (leveldata, currow, curcol, tilerow, tilecol)
240 elif event.key == ord ("p"):
241 tile = pick_tile (screen, tileset)
242 if tile is not None:
243 tilerow = tile[0]
244 tilecol = tile[1]
245 elif event.key == ord ("w"):
246 make_wall (leveldata, currow, curcol)
247
248 def new_level ():
249 print
250 fname = raw_input ("New level file path: ")
251 # prepare level with blank tiles
252 leveldata = [
253 [[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]],
254 [[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]],
255 [[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]],
256 [[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]],
257 [[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]],
258 [[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]],
259 [[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]],
260 [[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]],
261 [[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]],
262 [[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]]
263 ]
264 # save the level first
265 cPickle.dump (leveldata, file (fname, "w"))
266
267 # now edit it
268 level_editor (fname)
269
270 def load_level ():
271 fname = raw_input ("Level file to load: ")
272 level_editor (fname)
273
274 def main ():
275 while 1:
276 print
277 print ("Level Editor for the Adventures of Butaba")
278 print
279 print ("1. Start a new level")
280 print ("2. Load existing level")
281 print ("3. Quit")
282
283 ch = raw_input ("Your choice: ")
284 if ch == "1":
285 new_level ()
286 elif ch == "2":
287 load_level ()
288 elif ch == "3":
289 sys.exit (0)
290 else:
291 print ("Wrong choice. Must be 1, 2, or 3")
292
293
294 if __name__=="__main__":
295 main ()