1 | #!/usr/bin/env python
|
---|
2 |
|
---|
3 | # The basic area editor
|
---|
4 | #
|
---|
5 | # To edit an existing level, use
|
---|
6 | # editor levelname
|
---|
7 | #
|
---|
8 | # To create a new level:
|
---|
9 | #
|
---|
10 | # editor levelname <xsize> <ysize>
|
---|
11 | # (size specified in pixels
|
---|
12 | #
|
---|
13 |
|
---|
14 | import os
|
---|
15 | import sys
|
---|
16 |
|
---|
17 | import pygame
|
---|
18 | import pygame.locals as pgl
|
---|
19 |
|
---|
20 | sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
|
---|
21 |
|
---|
22 | import pymunk
|
---|
23 |
|
---|
24 | from albow.root import RootWidget
|
---|
25 | from albow.widget import Widget
|
---|
26 | from albow.controls import Button, Label, CheckBox
|
---|
27 | from albow.dialogs import alert, Dialog
|
---|
28 | from albow.layout import Row
|
---|
29 | from albow.fields import TextField
|
---|
30 | from albow.table_view import TableView, TableColumn
|
---|
31 |
|
---|
32 | from nagslang.options import parse_args
|
---|
33 | from nagslang.constants import SCREEN
|
---|
34 | from nagslang.level import Level, POLY_COLORS, LINE_COLOR
|
---|
35 | from nagslang.yamlish import load_s
|
---|
36 | import nagslang.enemies as ne
|
---|
37 | import nagslang.game_object as ngo
|
---|
38 | import nagslang.puzzle as np
|
---|
39 |
|
---|
40 | # layout constants
|
---|
41 | MENU_BUTTON_HEIGHT = 35
|
---|
42 | MENU_PAD = 6
|
---|
43 | MENU_HALF_PAD = MENU_PAD // 2
|
---|
44 | MENU_LEFT = SCREEN[0] + MENU_HALF_PAD
|
---|
45 | MENU_WIDTH = 200 - MENU_PAD
|
---|
46 |
|
---|
47 | BUTTON_RECT = pygame.rect.Rect(0, 0, MENU_WIDTH, MENU_BUTTON_HEIGHT)
|
---|
48 | CHECK_RECT = pygame.rect.Rect(0, 0, MENU_BUTTON_HEIGHT // 2,
|
---|
49 | MENU_BUTTON_HEIGHT // 2)
|
---|
50 |
|
---|
51 |
|
---|
52 | class TestWorld(object):
|
---|
53 |
|
---|
54 | def __init__(self):
|
---|
55 | self.level_state = {}
|
---|
56 |
|
---|
57 |
|
---|
58 | class EditorLevel(Level):
|
---|
59 |
|
---|
60 | def __init__(self, name, x=800, y=600):
|
---|
61 | world = TestWorld()
|
---|
62 | super(EditorLevel, self).__init__(name, world)
|
---|
63 | self.x = x
|
---|
64 | self.y = y
|
---|
65 | # Lookup initiliasition info from the objects
|
---|
66 | self.lookup = {}
|
---|
67 |
|
---|
68 | def round_point(self, pos):
|
---|
69 | return (10 * (pos[0] // 10), 10 * (pos[1] // 10))
|
---|
70 |
|
---|
71 | def load(self, space):
|
---|
72 | super(EditorLevel, self).load(space)
|
---|
73 | # Needed to fill in the lookup dict
|
---|
74 | self.reset_objs()
|
---|
75 |
|
---|
76 | def point_to_pymunk(self, pos):
|
---|
77 | # inverse of point_to_pygame
|
---|
78 | # (this is also the same as point_to_pygame, but a additional
|
---|
79 | # function for sanity later in pyweek).
|
---|
80 | return (pos[0], self.y - pos[1])
|
---|
81 |
|
---|
82 | def add_point(self, poly_index, pos):
|
---|
83 | self.polygons.setdefault(poly_index, [])
|
---|
84 | if not self.polygons[poly_index]:
|
---|
85 | point = self.point_to_pymunk(self.round_point(pos))
|
---|
86 | self.polygons[poly_index].append(point)
|
---|
87 | else:
|
---|
88 | add_pos = self.fix_poly_angle(poly_index, pos)
|
---|
89 | self.polygons[poly_index].append(add_pos)
|
---|
90 |
|
---|
91 | def _fix_angle(self, point1, pos):
|
---|
92 | # We want the line (point1 to pos) to be an angle of
|
---|
93 | # 0, 45, 90, 135, 180, 225, 270, 305
|
---|
94 | # However, we only need to consider half the circle
|
---|
95 | # This is a hack to approximate the right thing
|
---|
96 | pos0 = (pos[0], point1[1])
|
---|
97 | pos90 = (point1[0], pos[1])
|
---|
98 | dist = max(abs(point1[0] - pos[0]), abs(point1[1] - pos[1]))
|
---|
99 | pos45 = (point1[0] + dist, point1[1] + dist)
|
---|
100 | pos135 = (point1[0] + dist, point1[1] - dist)
|
---|
101 | pos225 = (point1[0] - dist, point1[1] - dist)
|
---|
102 | pos305 = (point1[0] - dist, point1[1] + dist)
|
---|
103 | min_dist = 9999999
|
---|
104 | new_pos = point1
|
---|
105 | for cand in [pos0, pos90, pos45, pos135, pos225, pos305]:
|
---|
106 | dist = (pos[0] - cand[0]) ** 2 + (pos[1] - cand[1]) ** 2
|
---|
107 | if dist < min_dist:
|
---|
108 | new_pos = cand
|
---|
109 | min_dist = dist
|
---|
110 | return self.point_to_pymunk(new_pos)
|
---|
111 |
|
---|
112 | def fix_line_angle(self, start_pos, pos):
|
---|
113 | start_pos = self.round_point(start_pos)
|
---|
114 | pos = self.round_point(pos)
|
---|
115 | return self._fix_angle(start_pos, pos)
|
---|
116 |
|
---|
117 | def fix_poly_angle(self, index, pos):
|
---|
118 | # Last point
|
---|
119 | point1 = self.point_to_pygame(self.polygons[index][-1])
|
---|
120 | pos = self.round_point(pos)
|
---|
121 | return self._fix_angle(point1, pos)
|
---|
122 |
|
---|
123 | def delete_point(self, index):
|
---|
124 | if index in self.polygons and len(self.polygons[index]) > 0:
|
---|
125 | self.polygons[index].pop()
|
---|
126 |
|
---|
127 | def close_poly(self, index):
|
---|
128 | """Attempts to close the current polygon.
|
---|
129 |
|
---|
130 | We allow a small additional step to close the polygon, but
|
---|
131 | it's limited as it's a magic point addition"""
|
---|
132 | if len(self.polygons[index]) < 2:
|
---|
133 | # Too small
|
---|
134 | return False
|
---|
135 | first = self.polygons[index][0]
|
---|
136 | if self.fix_poly_angle(index, self.point_to_pygame(first)) == first:
|
---|
137 | self.add_point(index, self.point_to_pygame(first))
|
---|
138 | return True
|
---|
139 | candidates = [(first[0] + 10 * i, first[1]) for
|
---|
140 | i in (-3, -2, -1, 1, 2, 3)]
|
---|
141 | candidates.extend([(first[0], first[1] + 10 * i) for
|
---|
142 | i in (-3, -2, -1, 1, 2, 3)])
|
---|
143 | candidates.extend([(first[0] + 10 * i, first[1] + 10 * i) for
|
---|
144 | i in (-3, -2, -1, 1, 2, 3)])
|
---|
145 | candidates.extend([(first[0] + 10 * i, first[1] - 10 * i) for
|
---|
146 | i in (-3, -2, -1, 1, 2, 3)])
|
---|
147 | min_dist = 99999
|
---|
148 | poss = None
|
---|
149 | for cand in candidates:
|
---|
150 | if self.fix_poly_angle(index, self.point_to_pygame(cand)) == cand:
|
---|
151 | dist = (first[0] - cand[0]) ** 2 + (first[1] - cand[1]) ** 2
|
---|
152 | if dist < min_dist:
|
---|
153 | poss = cand
|
---|
154 | if poss is not None:
|
---|
155 | self.add_point(index, self.point_to_pygame(poss))
|
---|
156 | self.add_point(index, self.point_to_pygame(first))
|
---|
157 | return True
|
---|
158 | return False
|
---|
159 |
|
---|
160 | def add_line(self, start_pos, end_pos):
|
---|
161 | endpoint = self.fix_line_angle(start_pos, end_pos)
|
---|
162 | startpoint = self.point_to_pymunk(self.round_point(start_pos))
|
---|
163 | self.lines.append([startpoint, endpoint])
|
---|
164 |
|
---|
165 | def draw(self, mouse_pos, mouse_poly, filled, draw_cand_line, start_pos):
|
---|
166 | self._draw_background(True)
|
---|
167 | # Draw polygons as needed for the editor
|
---|
168 | if filled:
|
---|
169 | self._draw_exterior(True)
|
---|
170 | for index, polygon in self.polygons.items():
|
---|
171 | color = POLY_COLORS[index]
|
---|
172 | if len(polygon) > 1:
|
---|
173 | pointlist = [self.point_to_pygame(p) for p in polygon]
|
---|
174 | pygame.draw.lines(self._surface, color, False, pointlist, 2)
|
---|
175 | if index == mouse_poly and mouse_pos:
|
---|
176 | endpoint = self.fix_poly_angle(index, mouse_pos)
|
---|
177 | pygame.draw.line(self._surface, color,
|
---|
178 | self.point_to_pygame(polygon[-1]),
|
---|
179 | self.point_to_pygame(endpoint))
|
---|
180 | for line in self.lines:
|
---|
181 | pointlist = [self.point_to_pygame(p) for p in line]
|
---|
182 | pygame.draw.lines(self._surface, LINE_COLOR, False, pointlist, 2)
|
---|
183 | if draw_cand_line and start_pos and mouse_pos:
|
---|
184 | endpoint = self.fix_line_angle(start_pos, mouse_pos)
|
---|
185 | pointlist = [self.round_point(start_pos),
|
---|
186 | self.point_to_pygame(endpoint)]
|
---|
187 | pygame.draw.lines(self._surface, LINE_COLOR, False, pointlist, 1)
|
---|
188 | return self._surface.copy()
|
---|
189 |
|
---|
190 | def reset_objs(self):
|
---|
191 | # Reset the object state - needed when changing stuff
|
---|
192 | self.drawables = []
|
---|
193 | self.overlay_drawables = []
|
---|
194 | self._glue = np.PuzzleGlue()
|
---|
195 | for game_object_dict in self._game_objects:
|
---|
196 | obj = self._create_game_object(pymunk.Space(), **game_object_dict)
|
---|
197 | self.lookup[obj] = game_object_dict
|
---|
198 | for enemy_dict in self._enemies:
|
---|
199 | obj = self._create_enemy(pymunk.Space(), **enemy_dict)
|
---|
200 | self.lookup[obj] = enemy_dict
|
---|
201 |
|
---|
202 | def get_class(self, classname, mod=None):
|
---|
203 | # Get the class given the classname
|
---|
204 | modules = {
|
---|
205 | 'game_object': ngo,
|
---|
206 | 'enemies': ne,
|
---|
207 | 'puzzle': np,
|
---|
208 | }
|
---|
209 | if '.' in classname:
|
---|
210 | modname, classname = classname.split('.')
|
---|
211 | mod = modules[modname]
|
---|
212 | if mod is None:
|
---|
213 | mod = ngo
|
---|
214 | return getattr(mod, classname)
|
---|
215 |
|
---|
216 | def try_new_object(self, classname, target, new, old=None):
|
---|
217 | if old in target:
|
---|
218 | target.remove(old)
|
---|
219 | try:
|
---|
220 | target.append(new)
|
---|
221 | self.reset_objs()
|
---|
222 | return True
|
---|
223 | except Exception as e:
|
---|
224 | target.remove(new)
|
---|
225 | if old is not None:
|
---|
226 | target.append(old)
|
---|
227 | self.reset_objs()
|
---|
228 | alert("Failed to update object %s: %s" % (classname, e))
|
---|
229 | return False
|
---|
230 |
|
---|
231 | def find_obj_at_pos(self, mouse_pos):
|
---|
232 | pymunk_pos = self.point_to_pymunk(mouse_pos)
|
---|
233 | # Search visible objects
|
---|
234 | for obj in self.drawables:
|
---|
235 | if obj.get_shape().point_query(pymunk_pos):
|
---|
236 | return obj
|
---|
237 | return None
|
---|
238 |
|
---|
239 |
|
---|
240 | class ObjectTable(TableView):
|
---|
241 |
|
---|
242 | columns = [TableColumn("Object", 690, 'l', '%r')]
|
---|
243 |
|
---|
244 | def __init__(self, data):
|
---|
245 | super(ObjectTable, self).__init__(height=450)
|
---|
246 | self.data = data
|
---|
247 | self.selected_row = -1
|
---|
248 |
|
---|
249 | def num_rows(self):
|
---|
250 | return len(self.data)
|
---|
251 |
|
---|
252 | def row_data(self, i):
|
---|
253 | data = self.data[i]
|
---|
254 | if 'name' in data:
|
---|
255 | return ('%s (%s)' % (data['classname'], data['name']), )
|
---|
256 | return (data['classname'], )
|
---|
257 |
|
---|
258 | def row_is_selected(self, i):
|
---|
259 | return self.selected_row == i
|
---|
260 |
|
---|
261 | def click_row(self, i, ev):
|
---|
262 | self.selected_row = i
|
---|
263 |
|
---|
264 | def get_selection(self):
|
---|
265 | if self.selected_row >= 0:
|
---|
266 | return self.data[self.selected_row]
|
---|
267 | return None
|
---|
268 |
|
---|
269 |
|
---|
270 | class EditClassDialog(Dialog):
|
---|
271 |
|
---|
272 | def __init__(self, classname, cls, data, level_widget,
|
---|
273 | delete=False):
|
---|
274 | super(EditClassDialog, self).__init__()
|
---|
275 | self.level_widget = level_widget
|
---|
276 | self.classname = classname
|
---|
277 | self.rect = pygame.rect.Rect(0, 0, 900, 550)
|
---|
278 | title = Label("Editing %s" % classname)
|
---|
279 | title.rect = pygame.rect.Rect(100, 10, 600, 25)
|
---|
280 | self.add(title)
|
---|
281 | self.requires = cls.requires()
|
---|
282 | y = 40
|
---|
283 | self.fields = {}
|
---|
284 | index = 0
|
---|
285 | self.poly_field = None
|
---|
286 | self.needs_cleanup = False
|
---|
287 | for requirement, hint in self.requires:
|
---|
288 | label = Label(requirement)
|
---|
289 | label.rect = pygame.rect.Rect(40, y, 200, 25)
|
---|
290 | self.add(label)
|
---|
291 | field = TextField()
|
---|
292 | field.rect = pygame.rect.Rect(220, y, 400, 25)
|
---|
293 | self.add(field)
|
---|
294 | if data is not None:
|
---|
295 | if requirement in data:
|
---|
296 | field.set_text('%s' % data[requirement])
|
---|
297 | elif 'args' in data and requirement != 'name':
|
---|
298 | # NB: The ordering assumptions in requires should make
|
---|
299 | # this safe, but it's really, really, really fragile
|
---|
300 | try:
|
---|
301 | field.set_text('%s' % data['args'][index])
|
---|
302 | index += 1
|
---|
303 | except IndexError:
|
---|
304 | # Assumed to be arguments with the default value
|
---|
305 | pass
|
---|
306 | if hint.startswith('polygon'):
|
---|
307 | self.poly_field = field
|
---|
308 | self.fields[requirement] = field
|
---|
309 | hintlabel = Label(hint)
|
---|
310 | hintlabel.rect = pygame.rect.Rect(640, y, 250, 25)
|
---|
311 | self.add(hintlabel)
|
---|
312 | y += 30
|
---|
313 | if self.poly_field:
|
---|
314 | y += 20
|
---|
315 | button = Button('Use Polygon 6', action=self.get_poly)
|
---|
316 | button.rect = pygame.rect.Rect(350, y, 250, 30)
|
---|
317 | self.add(button)
|
---|
318 | buttons = []
|
---|
319 | if delete:
|
---|
320 | labels = ['OK', 'Delete', 'Cancel']
|
---|
321 | else:
|
---|
322 | labels = ['OK', 'Cancel']
|
---|
323 | for text in labels:
|
---|
324 | but = Button(text, action=lambda x=text: self.dismiss(x))
|
---|
325 | buttons.append(but)
|
---|
326 | row = Row(buttons)
|
---|
327 | row.rect = pygame.rect.Rect(250, 500, 700, 50)
|
---|
328 | self.add(row)
|
---|
329 |
|
---|
330 | def get_poly(self):
|
---|
331 | try:
|
---|
332 | data = self.level_widget.level.polygons[6][:]
|
---|
333 | except KeyError:
|
---|
334 | data = []
|
---|
335 | if data:
|
---|
336 | # We unclose the polygon, because that's what pymunk
|
---|
337 | # wants
|
---|
338 | if data[0] == data[-1] and len(data) > 1:
|
---|
339 | data.pop()
|
---|
340 | data = [list(x) for x in data]
|
---|
341 | self.needs_cleanup = True
|
---|
342 | self.poly_field.set_text('%s' % data)
|
---|
343 |
|
---|
344 | def cleanup(self):
|
---|
345 | if self.needs_cleanup:
|
---|
346 | self.level_widget.level.polygons[6] = []
|
---|
347 | self.level_widget.invalidate()
|
---|
348 |
|
---|
349 | def get_data(self):
|
---|
350 | result = {}
|
---|
351 | result['classname'] = self.classname
|
---|
352 | args = []
|
---|
353 | # We arrange to bounce this through yaml'ish to convert
|
---|
354 | # stuff to the expected type
|
---|
355 | for val, _ in self.requires:
|
---|
356 | text = self.fields[val].get_text()
|
---|
357 | if not text:
|
---|
358 | # skip empty fields
|
---|
359 | continue
|
---|
360 | if val == 'name':
|
---|
361 | result['name'] = text
|
---|
362 | elif self.fields[val] == self.poly_field and text:
|
---|
363 | # Evil, but faster than good
|
---|
364 | try:
|
---|
365 | l = eval(text)
|
---|
366 | args.append(' - - %s' % l[0])
|
---|
367 | for coord in l[1:]:
|
---|
368 | args.append(' - %s' % coord)
|
---|
369 | except Exception:
|
---|
370 | alert("Invalid polygon %s" % text)
|
---|
371 | self.needs_cleanup = False
|
---|
372 | return None
|
---|
373 | # Check for convexity
|
---|
374 | hull = pymunk.util.convex_hull(l)
|
---|
375 | if hull != l:
|
---|
376 | alert("Invalid polygon %s - not convex" % text)
|
---|
377 | return None
|
---|
378 | else:
|
---|
379 | args.append(' - ' + text)
|
---|
380 | data = "args:\n" + '\n'.join(args)
|
---|
381 | result['args'] = load_s(data)['args']
|
---|
382 | return result
|
---|
383 |
|
---|
384 |
|
---|
385 | class LevelWidget(Widget):
|
---|
386 |
|
---|
387 | def __init__(self, level, parent):
|
---|
388 | super(LevelWidget, self).__init__(pygame.rect.Rect(0, 0,
|
---|
389 | SCREEN[0], SCREEN[1]))
|
---|
390 | self.level = level
|
---|
391 | self.pos = (0, 0)
|
---|
392 | self.filled_mode = False
|
---|
393 | self.mouse_pos = None
|
---|
394 | self.cur_poly = None
|
---|
395 | self._mouse_drag = False
|
---|
396 | self._draw_objects = False
|
---|
397 | self._draw_enemies = False
|
---|
398 | self._draw_lines = False
|
---|
399 | self.sel_mode = False
|
---|
400 | self._start_pos = None
|
---|
401 | self._parent = parent
|
---|
402 |
|
---|
403 | def _level_coordinates(self, pos):
|
---|
404 | # Move positions to level values
|
---|
405 | if not pos:
|
---|
406 | return (0, 0)
|
---|
407 | return pos[0] + self.pos[0], pos[1] + self.pos[1]
|
---|
408 |
|
---|
409 | def _move_view(self, offset):
|
---|
410 | new_pos = [self.pos[0] + offset[0], self.pos[1] + offset[1]]
|
---|
411 | if new_pos[0] < 0:
|
---|
412 | new_pos[0] = self.pos[0]
|
---|
413 | elif new_pos[0] > self.level.x - SCREEN[0]:
|
---|
414 | new_pos[0] = self.pos[0]
|
---|
415 | if new_pos[1] < 0:
|
---|
416 | new_pos[1] = self.pos[1]
|
---|
417 | elif new_pos[1] > self.level.y - SCREEN[1]:
|
---|
418 | new_pos[1] = self.pos[1]
|
---|
419 | self.pos = tuple(new_pos)
|
---|
420 |
|
---|
421 | def set_objects(self, value):
|
---|
422 | if self._draw_objects != value:
|
---|
423 | self._draw_objects = value
|
---|
424 | self.invalidate()
|
---|
425 |
|
---|
426 | def set_enemies(self, value):
|
---|
427 | if self._draw_enemies != value:
|
---|
428 | self._draw_enemies = value
|
---|
429 | self.invalidate()
|
---|
430 |
|
---|
431 | def draw(self, surface):
|
---|
432 | if (self.cur_poly is not None and self.cur_poly in self.level.polygons
|
---|
433 | and len(self.level.polygons[self.cur_poly])):
|
---|
434 | # We have an active polygon
|
---|
435 | mouse_pos = self._level_coordinates(self.mouse_pos)
|
---|
436 | elif self._draw_lines:
|
---|
437 | # Interior wall mode
|
---|
438 | mouse_pos = self._level_coordinates(self.mouse_pos)
|
---|
439 | else:
|
---|
440 | mouse_pos = None
|
---|
441 | level_surface = level.draw(mouse_pos, self.cur_poly, self.filled_mode,
|
---|
442 | self._draw_lines, self._start_pos)
|
---|
443 | if self._draw_objects:
|
---|
444 | for thing in self.level.drawables:
|
---|
445 | if not isinstance(thing, ne.Enemy):
|
---|
446 | thing.render(level_surface)
|
---|
447 | if self._draw_enemies:
|
---|
448 | for thing in self.level.drawables:
|
---|
449 | if isinstance(thing, ne.Enemy):
|
---|
450 | thing.render(level_surface)
|
---|
451 | surface_area = pygame.rect.Rect(self.pos, SCREEN)
|
---|
452 | surface.blit(level_surface, (0, 0), surface_area)
|
---|
453 |
|
---|
454 | def change_poly(self, new_poly):
|
---|
455 | self.cur_poly = new_poly
|
---|
456 | self._draw_lines = False
|
---|
457 | if self.cur_poly is not None:
|
---|
458 | self._parent.reset_lit_buttons()
|
---|
459 | self.filled_mode = False
|
---|
460 |
|
---|
461 | def line_mode(self):
|
---|
462 | self.cur_poly = None
|
---|
463 | self._parent.reset_lit_buttons()
|
---|
464 | self._draw_lines = True
|
---|
465 | self.filled_mode = False
|
---|
466 | self._start_pos = None
|
---|
467 |
|
---|
468 | def key_down(self, ev):
|
---|
469 | if ev.key == pgl.K_LEFT:
|
---|
470 | self._move_view((-10, 0))
|
---|
471 | elif ev.key == pgl.K_RIGHT:
|
---|
472 | self._move_view((10, 0))
|
---|
473 | elif ev.key == pgl.K_UP:
|
---|
474 | self._move_view((0, -10))
|
---|
475 | elif ev.key == pgl.K_DOWN:
|
---|
476 | self._move_view((0, 10))
|
---|
477 | elif ev.key in (pgl.K_1, pgl.K_2, pgl.K_3, pgl.K_4, pgl.K_5, pgl.K_6):
|
---|
478 | self.change_poly(ev.key - pgl.K_0)
|
---|
479 | elif ev.key == pgl.K_0:
|
---|
480 | self.change_poly(None)
|
---|
481 | elif ev.key == pgl.K_d and self.cur_poly:
|
---|
482 | self.level.delete_point(self.cur_poly)
|
---|
483 | elif ev.key == pgl.K_f:
|
---|
484 | self.set_filled()
|
---|
485 | elif ev.key == pgl.K_c:
|
---|
486 | self.close_poly()
|
---|
487 |
|
---|
488 | def set_filled(self):
|
---|
489 | closed, _ = self.level.all_closed()
|
---|
490 | if closed:
|
---|
491 | self.cur_poly = None
|
---|
492 | self._parent.reset_lit_buttons()
|
---|
493 | self.filled_mode = True
|
---|
494 | self._draw_lines = False
|
---|
495 | else:
|
---|
496 | alert('Not all polygons closed, so not filling')
|
---|
497 |
|
---|
498 | def mouse_move(self, ev):
|
---|
499 | old_pos = self.mouse_pos
|
---|
500 | self.mouse_pos = ev.pos
|
---|
501 | if old_pos != self.mouse_pos and (self.cur_poly or self._draw_lines):
|
---|
502 | self.invalidate()
|
---|
503 |
|
---|
504 | def mouse_drag(self, ev):
|
---|
505 | if self._mouse_drag:
|
---|
506 | old_pos = self.mouse_pos
|
---|
507 | self.mouse_pos = ev.pos
|
---|
508 | diff = (-self.mouse_pos[0] + old_pos[0],
|
---|
509 | -self.mouse_pos[1] + old_pos[1])
|
---|
510 | self._move_view(diff)
|
---|
511 | self.invalidate()
|
---|
512 |
|
---|
513 | def mouse_down(self, ev):
|
---|
514 | if self.sel_mode and ev.button == 1:
|
---|
515 | corrected_pos = ev.pos[0] + self.pos[0], ev.pos[1] + self.pos[1]
|
---|
516 | obj = self.level.find_obj_at_pos(corrected_pos)
|
---|
517 | if obj is not None:
|
---|
518 | self._edit_selected(obj)
|
---|
519 | elif ev.button == 1:
|
---|
520 | if self._draw_lines:
|
---|
521 | if self._start_pos is None:
|
---|
522 | self._start_pos = ev.pos
|
---|
523 | else:
|
---|
524 | self.level.add_line(self._start_pos, ev.pos)
|
---|
525 | self._start_pos = None
|
---|
526 | else:
|
---|
527 | print "Click: %r" % (
|
---|
528 | self.level.point_to_pymunk(
|
---|
529 | self._level_coordinates(ev.pos)),)
|
---|
530 | if ev.button == 4: # Scroll up
|
---|
531 | self._move_view((0, -10))
|
---|
532 | elif ev.button == 5: # Scroll down
|
---|
533 | self._move_view((0, 10))
|
---|
534 | elif ev.button == 6: # Scroll left
|
---|
535 | self._move_view((-10, 0))
|
---|
536 | elif ev.button == 7: # Scroll right
|
---|
537 | self._move_view((10, 0))
|
---|
538 | elif self.cur_poly and ev.button == 1:
|
---|
539 | # Add a point
|
---|
540 | self.level.add_point(self.cur_poly,
|
---|
541 | self._level_coordinates(ev.pos))
|
---|
542 | elif ev.button == 3:
|
---|
543 | self._mouse_drag = True
|
---|
544 |
|
---|
545 | def mouse_up(self, ev):
|
---|
546 | if ev.button == 3:
|
---|
547 | self._mouse_drag = False
|
---|
548 |
|
---|
549 | def close_poly(self):
|
---|
550 | if self.cur_poly is None:
|
---|
551 | return
|
---|
552 | if self.level.close_poly(self.cur_poly):
|
---|
553 | alert("Successfully closed the polygon")
|
---|
554 | self.change_poly(None)
|
---|
555 | else:
|
---|
556 | alert("Failed to close the polygon")
|
---|
557 |
|
---|
558 | def _edit_class(self, classname, cls, data):
|
---|
559 | # Dialog for class properties
|
---|
560 | dialog = EditClassDialog(classname, cls, data, self)
|
---|
561 | if dialog.present() == 'OK':
|
---|
562 | return dialog
|
---|
563 | return None
|
---|
564 |
|
---|
565 | def _edit_selected(self, obj):
|
---|
566 | data = self.level.lookup[obj]
|
---|
567 | cls = obj.__class__
|
---|
568 | classname = obj.__class__.__name__
|
---|
569 | dialog = EditClassDialog(classname, cls, data, self, True)
|
---|
570 | res = dialog.present()
|
---|
571 | if res == 'OK':
|
---|
572 | edited = dialog.get_data()
|
---|
573 | if edited is not None:
|
---|
574 | for target in [self.level._game_objects, self.level._enemies]:
|
---|
575 | if data in target:
|
---|
576 | if self.level.try_new_object(classname, target,
|
---|
577 | edited, data):
|
---|
578 | dialog.cleanup()
|
---|
579 | break
|
---|
580 | elif res == 'Delete':
|
---|
581 | for target in [self.level._game_objects, self.level._enemies]:
|
---|
582 | if data in target:
|
---|
583 | target.remove(data)
|
---|
584 | self.level.reset_objs()
|
---|
585 | break
|
---|
586 |
|
---|
587 | def _make_edit_dialog(self, entries):
|
---|
588 | # Dialog to hold the editor
|
---|
589 | edit_box = Dialog()
|
---|
590 | edit_box.rect = pygame.rect.Rect(0, 0, 700, 500)
|
---|
591 | table = ObjectTable(entries)
|
---|
592 | edit_box.add(table)
|
---|
593 | buttons = []
|
---|
594 | for text in ['OK', 'Delete', 'Cancel']:
|
---|
595 | but = Button(text, action=lambda x=text: edit_box.dismiss(x))
|
---|
596 | buttons.append(but)
|
---|
597 | row = Row(buttons)
|
---|
598 | row.rect = pygame.rect.Rect(250, 450, 700, 50)
|
---|
599 | edit_box.add(row)
|
---|
600 | edit_box.get_selection = lambda: table.get_selection()
|
---|
601 | return edit_box
|
---|
602 |
|
---|
603 | def edit_objects(self):
|
---|
604 | edit_box = self._make_edit_dialog(self.level._game_objects)
|
---|
605 | res = edit_box.present()
|
---|
606 | choice = edit_box.get_selection()
|
---|
607 | if choice is None:
|
---|
608 | return
|
---|
609 | if res == 'OK':
|
---|
610 | cls = self.level.get_class(choice['classname'])
|
---|
611 | edit_dlg = self._edit_class(choice['classname'], cls, choice)
|
---|
612 | if edit_dlg is not None:
|
---|
613 | edited = edit_dlg.get_data()
|
---|
614 | if self.level.try_new_object(choice["classname"],
|
---|
615 | self.level._game_objects,
|
---|
616 | edited, choice):
|
---|
617 | edit_dlg.cleanup()
|
---|
618 | elif res == 'Delete':
|
---|
619 | self.level._game_objects.remove(choice)
|
---|
620 | self.level.reset_objs()
|
---|
621 |
|
---|
622 | def edit_enemies(self):
|
---|
623 | edit_box = self._make_edit_dialog(self.level._enemies)
|
---|
624 | res = edit_box.present()
|
---|
625 | choice = edit_box.get_selection()
|
---|
626 | if choice is None:
|
---|
627 | return
|
---|
628 | if res == 'OK':
|
---|
629 | cls = self.level.get_class(choice['classname'], ne)
|
---|
630 | edit_dlg = self._edit_class(choice['classname'], cls, choice)
|
---|
631 | if edit_dlg is not None:
|
---|
632 | edited = edit_dlg.get_data()
|
---|
633 | if self.level.try_new_object(choice["classname"],
|
---|
634 | self.level._enemies,
|
---|
635 | edited, choice):
|
---|
636 | edit_dlg.cleanup()
|
---|
637 | elif res == 'Delete':
|
---|
638 | self.level._enemies.remove(choice)
|
---|
639 | self.level.reset_objs()
|
---|
640 |
|
---|
641 | def _make_choice_dialog(self, classes):
|
---|
642 | # Dialog to hold the editor
|
---|
643 | data = []
|
---|
644 | for cls_name, cls in classes:
|
---|
645 | data.append({"classname": cls_name, "class": cls})
|
---|
646 | choice_box = Dialog()
|
---|
647 | choice_box.rect = pygame.rect.Rect(0, 0, 700, 500)
|
---|
648 | table = ObjectTable(data)
|
---|
649 | choice_box.add(table)
|
---|
650 | buttons = []
|
---|
651 | for text in ['OK', 'Cancel']:
|
---|
652 | but = Button(text, action=lambda x=text: choice_box.dismiss(x))
|
---|
653 | buttons.append(but)
|
---|
654 | row = Row(buttons)
|
---|
655 | row.rect = pygame.rect.Rect(250, 450, 700, 50)
|
---|
656 | choice_box.add(row)
|
---|
657 | choice_box.get_selection = lambda: table.get_selection()
|
---|
658 | return choice_box
|
---|
659 |
|
---|
660 | def add_game_object(self):
|
---|
661 | classes = ngo.get_editable_game_objects()
|
---|
662 | choose = self._make_choice_dialog(classes)
|
---|
663 | res = choose.present()
|
---|
664 | choice = choose.get_selection()
|
---|
665 | if res == 'OK' and choice is not None:
|
---|
666 | classname = choice['classname']
|
---|
667 | cls = choice['class']
|
---|
668 | edit_dlg = self._edit_class(classname, cls, None)
|
---|
669 | if edit_dlg is not None:
|
---|
670 | new_cls = edit_dlg.get_data()
|
---|
671 | if self.level.try_new_object(classname,
|
---|
672 | self.level._game_objects,
|
---|
673 | new_cls, None):
|
---|
674 | edit_dlg.cleanup()
|
---|
675 |
|
---|
676 | def add_enemy(self):
|
---|
677 | classes = ne.get_editable_enemies()
|
---|
678 | choose = self._make_choice_dialog(classes)
|
---|
679 | res = choose.present()
|
---|
680 | choice = choose.get_selection()
|
---|
681 | if res == 'OK' and choice is not None:
|
---|
682 | classname = choice['classname']
|
---|
683 | cls = choice['class']
|
---|
684 | edit_dlg = self._edit_class(classname, cls, None)
|
---|
685 | if edit_dlg is not None:
|
---|
686 | new_cls = edit_dlg.get_data()
|
---|
687 | if self.level.try_new_object(classname, self.level._enemies,
|
---|
688 | new_cls, None):
|
---|
689 | edit_dlg.cleanup()
|
---|
690 |
|
---|
691 | def add_puzzler(self):
|
---|
692 | classes = np.get_editable_puzzlers()
|
---|
693 | choose = self._make_choice_dialog(classes)
|
---|
694 | res = choose.present()
|
---|
695 | choice = choose.get_selection()
|
---|
696 | if res == 'OK' and choice is not None:
|
---|
697 | classname = choice['classname']
|
---|
698 | cls = choice['class']
|
---|
699 | edit_dlg = self._edit_class(classname, cls, None)
|
---|
700 | if edit_dlg is not None:
|
---|
701 | new_cls = edit_dlg.get_data()
|
---|
702 | if self.level.try_new_object(classname,
|
---|
703 | self.level._game_objects,
|
---|
704 | new_cls, None):
|
---|
705 | edit_dlg.cleanup()
|
---|
706 |
|
---|
707 |
|
---|
708 | class HighLightButton(Button):
|
---|
709 | """Button with highlight support"""
|
---|
710 | def __init__(self, text, parent, **kwds):
|
---|
711 | super(HighLightButton, self).__init__(text, **kwds)
|
---|
712 | self._parent = parent
|
---|
713 |
|
---|
714 | def highlight(self):
|
---|
715 | self.border_color = pygame.color.Color('red')
|
---|
716 |
|
---|
717 | def reset(self):
|
---|
718 | self.border_color = self.fg_color
|
---|
719 |
|
---|
720 |
|
---|
721 | class PolyButton(HighLightButton):
|
---|
722 | """Button for coosing the correct polygon"""
|
---|
723 |
|
---|
724 | def __init__(self, index, level_widget, parent):
|
---|
725 | if index is not None:
|
---|
726 | text = "Draw: %s" % index
|
---|
727 | else:
|
---|
728 | text = 'Exit Draw Mode'
|
---|
729 | super(PolyButton, self).__init__(text, parent)
|
---|
730 | self.index = index
|
---|
731 | self.level_widget = level_widget
|
---|
732 |
|
---|
733 | def action(self):
|
---|
734 | self.level_widget.change_poly(self.index)
|
---|
735 | self._parent.reset_lit_buttons()
|
---|
736 | if self.index is not None:
|
---|
737 | self.highlight()
|
---|
738 |
|
---|
739 |
|
---|
740 | class EditorApp(RootWidget):
|
---|
741 |
|
---|
742 | def __init__(self, level, surface):
|
---|
743 | super(EditorApp, self).__init__(surface)
|
---|
744 | self.level = level
|
---|
745 | self.level_widget = LevelWidget(self.level, self)
|
---|
746 | self.add(self.level_widget)
|
---|
747 |
|
---|
748 | self._dMenus = {}
|
---|
749 |
|
---|
750 | self._light_buttons = []
|
---|
751 |
|
---|
752 | self._make_draw_menu()
|
---|
753 | self._make_objects_menu()
|
---|
754 |
|
---|
755 | self._menu_mode = 'drawing'
|
---|
756 | self._populate_menu()
|
---|
757 |
|
---|
758 | def _make_draw_menu(self):
|
---|
759 | widgets = []
|
---|
760 |
|
---|
761 | # Add poly buttons
|
---|
762 | y = 15
|
---|
763 | for poly in range(1, 7):
|
---|
764 | but = PolyButton(poly, self.level_widget, self)
|
---|
765 | but.rect = pygame.rect.Rect(0, 0, MENU_WIDTH // 2 - MENU_PAD,
|
---|
766 | MENU_BUTTON_HEIGHT)
|
---|
767 | if poly % 2:
|
---|
768 | but.rect.move_ip(MENU_LEFT, y)
|
---|
769 | else:
|
---|
770 | but.rect.move_ip(MENU_LEFT + MENU_WIDTH // 2 - MENU_HALF_PAD,
|
---|
771 | y)
|
---|
772 | y += MENU_BUTTON_HEIGHT + MENU_PAD
|
---|
773 | self._light_buttons.append(but)
|
---|
774 | widgets.append(but)
|
---|
775 |
|
---|
776 | end_poly_but = PolyButton(None, self.level_widget, self)
|
---|
777 | end_poly_but.rect = BUTTON_RECT.copy()
|
---|
778 | end_poly_but.rect.move_ip(MENU_LEFT, y)
|
---|
779 | widgets.append(end_poly_but)
|
---|
780 | y += MENU_BUTTON_HEIGHT + MENU_PAD
|
---|
781 |
|
---|
782 | self.draw_line_but = HighLightButton("Draw interior wall", self,
|
---|
783 | action=self.set_line_mode)
|
---|
784 | self.draw_line_but.rect = BUTTON_RECT.copy()
|
---|
785 | self.draw_line_but.rect.move_ip(MENU_LEFT, y)
|
---|
786 | widgets.append(self.draw_line_but)
|
---|
787 | self._light_buttons.append(self.draw_line_but)
|
---|
788 | y += MENU_BUTTON_HEIGHT + MENU_PAD
|
---|
789 |
|
---|
790 | fill_but = Button('Fill exterior', action=self.level_widget.set_filled)
|
---|
791 | fill_but.rect = BUTTON_RECT.copy()
|
---|
792 | fill_but.rect.move_ip(MENU_LEFT, y)
|
---|
793 | widgets.append(fill_but)
|
---|
794 | y += MENU_BUTTON_HEIGHT + MENU_PAD
|
---|
795 |
|
---|
796 | close_poly_but = Button('Close Polygon',
|
---|
797 | action=self.level_widget.close_poly)
|
---|
798 | close_poly_but.rect = BUTTON_RECT.copy()
|
---|
799 | close_poly_but.rect.move_ip(MENU_LEFT, y)
|
---|
800 | widgets.append(close_poly_but)
|
---|
801 | y += MENU_BUTTON_HEIGHT + MENU_PAD
|
---|
802 |
|
---|
803 | white = pygame.color.Color("white")
|
---|
804 | self.show_objs = CheckBox(fg_color=white)
|
---|
805 | self.show_objs.rect = CHECK_RECT.copy()
|
---|
806 | self.show_objs.rect.move_ip(MENU_LEFT, y)
|
---|
807 | label = Label("Show Objects", fg_color=white)
|
---|
808 | label.rect.move_ip(MENU_LEFT + MENU_BUTTON_HEIGHT // 2 + MENU_PAD, y)
|
---|
809 | widgets.append(self.show_objs)
|
---|
810 | widgets.append(label)
|
---|
811 | y += label.rect.height + MENU_PAD
|
---|
812 |
|
---|
813 | self.show_enemies = CheckBox(fg_color=white)
|
---|
814 | self.show_enemies.rect = CHECK_RECT.copy()
|
---|
815 | self.show_enemies.rect.move_ip(MENU_LEFT, y)
|
---|
816 | label = Label("Show enemy start pos", fg_color=white)
|
---|
817 | label.rect.move_ip(MENU_LEFT + MENU_BUTTON_HEIGHT // 2 + MENU_PAD, y)
|
---|
818 | widgets.append(self.show_enemies)
|
---|
819 | widgets.append(label)
|
---|
820 | y += label.rect.height + MENU_PAD
|
---|
821 |
|
---|
822 | y += MENU_PAD
|
---|
823 | switch_but = Button('Switch to Objects', action=self.switch_to_objects)
|
---|
824 | switch_but.rect = BUTTON_RECT.copy()
|
---|
825 | switch_but.rect.move_ip(MENU_LEFT, y)
|
---|
826 | widgets.append(switch_but)
|
---|
827 | y += switch_but.rect.height + MENU_PAD
|
---|
828 |
|
---|
829 | save_but = Button('Save Level', action=self.save)
|
---|
830 | save_but.rect = BUTTON_RECT.copy()
|
---|
831 | save_but.rect.move_ip(MENU_LEFT, y)
|
---|
832 | widgets.append(save_but)
|
---|
833 | y += MENU_BUTTON_HEIGHT + MENU_PAD
|
---|
834 |
|
---|
835 | y = SCREEN[1] - MENU_BUTTON_HEIGHT - MENU_PAD
|
---|
836 | quit_but = Button('Quit', action=self.quit)
|
---|
837 | quit_but.rect = BUTTON_RECT.copy()
|
---|
838 | quit_but.rect.move_ip(MENU_LEFT, y)
|
---|
839 | widgets.append(quit_but)
|
---|
840 |
|
---|
841 | self._dMenus['drawing'] = widgets
|
---|
842 |
|
---|
843 | def _make_objects_menu(self):
|
---|
844 | widgets = []
|
---|
845 |
|
---|
846 | # Add poly buttons
|
---|
847 | y = 15
|
---|
848 |
|
---|
849 | edit_objs_but = Button('Edit Objects',
|
---|
850 | action=self.level_widget.edit_objects)
|
---|
851 | edit_objs_but.rect = BUTTON_RECT.copy()
|
---|
852 | edit_objs_but.rect.move_ip(MENU_LEFT, y)
|
---|
853 | widgets.append(edit_objs_but)
|
---|
854 | y += MENU_BUTTON_HEIGHT + MENU_PAD
|
---|
855 |
|
---|
856 | edir_enemies_but = Button('Edit Enemies',
|
---|
857 | action=self.level_widget.edit_enemies)
|
---|
858 | edir_enemies_but.rect = BUTTON_RECT.copy()
|
---|
859 | edir_enemies_but.rect.move_ip(MENU_LEFT, y)
|
---|
860 | widgets.append(edir_enemies_but)
|
---|
861 | y += MENU_BUTTON_HEIGHT + MENU_PAD
|
---|
862 |
|
---|
863 | add_obj_but = Button('Add Game Object',
|
---|
864 | action=self.level_widget.add_game_object)
|
---|
865 | add_obj_but.rect = BUTTON_RECT.copy()
|
---|
866 | add_obj_but.rect.move_ip(MENU_LEFT, y)
|
---|
867 | widgets.append(add_obj_but)
|
---|
868 | y += MENU_BUTTON_HEIGHT + MENU_PAD
|
---|
869 |
|
---|
870 | add_puzzle_but = Button('Add Puzzler',
|
---|
871 | action=self.level_widget.add_puzzler)
|
---|
872 | add_puzzle_but.rect = BUTTON_RECT.copy()
|
---|
873 | add_puzzle_but.rect.move_ip(MENU_LEFT, y)
|
---|
874 | widgets.append(add_puzzle_but)
|
---|
875 | y += MENU_BUTTON_HEIGHT + MENU_PAD
|
---|
876 |
|
---|
877 | add_enemy_but = Button('Add Enemy',
|
---|
878 | action=self.level_widget.add_enemy)
|
---|
879 | add_enemy_but.rect = BUTTON_RECT.copy()
|
---|
880 | add_enemy_but.rect.move_ip(MENU_LEFT, y)
|
---|
881 | widgets.append(add_enemy_but)
|
---|
882 | y += MENU_BUTTON_HEIGHT + MENU_PAD
|
---|
883 |
|
---|
884 | y += MENU_PAD
|
---|
885 | self.sel_mode_but = HighLightButton('Select Object', self,
|
---|
886 | action=self.sel_mode)
|
---|
887 | self.sel_mode_but.rect = BUTTON_RECT.copy()
|
---|
888 | self.sel_mode_but.rect.move_ip(MENU_LEFT, y)
|
---|
889 | widgets.append(self.sel_mode_but)
|
---|
890 | self._light_buttons.append(self.sel_mode_but)
|
---|
891 | y += MENU_BUTTON_HEIGHT + MENU_PAD
|
---|
892 |
|
---|
893 | y += MENU_PAD
|
---|
894 | switch_but = Button('Switch to Drawing', action=self.switch_to_draw)
|
---|
895 | switch_but.rect = BUTTON_RECT.copy()
|
---|
896 | switch_but.rect.move_ip(MENU_LEFT, y)
|
---|
897 | widgets.append(switch_but)
|
---|
898 | y += switch_but.rect.height + MENU_PAD
|
---|
899 |
|
---|
900 | save_but = Button('Save Level', action=self.save)
|
---|
901 | save_but.rect = BUTTON_RECT.copy()
|
---|
902 | save_but.rect.move_ip(MENU_LEFT, y)
|
---|
903 | widgets.append(save_but)
|
---|
904 | y += MENU_BUTTON_HEIGHT + MENU_PAD
|
---|
905 |
|
---|
906 | y = SCREEN[1] - MENU_BUTTON_HEIGHT - MENU_PAD
|
---|
907 | quit_but = Button('Quit', action=self.quit)
|
---|
908 | quit_but.rect = BUTTON_RECT.copy()
|
---|
909 | quit_but.rect.move_ip(MENU_LEFT, y)
|
---|
910 | widgets.append(quit_but)
|
---|
911 |
|
---|
912 | self._dMenus['objects'] = widgets
|
---|
913 |
|
---|
914 | def key_down(self, ev):
|
---|
915 | if ev.key == pgl.K_ESCAPE:
|
---|
916 | self.quit()
|
---|
917 | elif ev.key == pgl.K_s:
|
---|
918 | self.save()
|
---|
919 | else:
|
---|
920 | self.level_widget.key_down(ev)
|
---|
921 |
|
---|
922 | def save(self):
|
---|
923 | closed, messages = self.level.all_closed()
|
---|
924 | if closed:
|
---|
925 | self.level.save()
|
---|
926 | # display success
|
---|
927 | alert("Level %s saved successfully." % self.level.name)
|
---|
928 | else:
|
---|
929 | # display errors
|
---|
930 | alert("Failed to save level.\n\n%s" % '\n'.join(messages))
|
---|
931 |
|
---|
932 | def switch_to_draw(self):
|
---|
933 | if self._menu_mode != 'drawing':
|
---|
934 | self._clear_menu()
|
---|
935 | self._menu_mode = 'drawing'
|
---|
936 | self._populate_menu()
|
---|
937 |
|
---|
938 | def switch_to_objects(self):
|
---|
939 | if self._menu_mode != 'objects':
|
---|
940 | self._clear_menu()
|
---|
941 | self._menu_mode = 'objects'
|
---|
942 | self._populate_menu()
|
---|
943 |
|
---|
944 | def _clear_menu(self):
|
---|
945 | for widget in self._dMenus[self._menu_mode]:
|
---|
946 | self.remove(widget)
|
---|
947 |
|
---|
948 | def reset_lit_buttons(self):
|
---|
949 | for but in self._light_buttons:
|
---|
950 | but.reset()
|
---|
951 |
|
---|
952 | def _populate_menu(self):
|
---|
953 | self.level_widget.change_poly(None)
|
---|
954 | self.level_widget.sel_mode = False
|
---|
955 | for widget in self._dMenus[self._menu_mode]:
|
---|
956 | self.add(widget)
|
---|
957 | self.invalidate()
|
---|
958 |
|
---|
959 | def set_line_mode(self):
|
---|
960 | self.level_widget.line_mode()
|
---|
961 | self.draw_line_but.highlight()
|
---|
962 |
|
---|
963 | def sel_mode(self):
|
---|
964 | self.level_widget.sel_mode = not self.level_widget.sel_mode
|
---|
965 | if self.level_widget.sel_mode:
|
---|
966 | self.sel_mode_but.highlight()
|
---|
967 | else:
|
---|
968 | self.sel_mode_but.reset()
|
---|
969 |
|
---|
970 | def mouse_move(self, ev):
|
---|
971 | self.level_widget.mouse_move(ev)
|
---|
972 |
|
---|
973 | def draw(self, surface):
|
---|
974 | # Update checkbox state
|
---|
975 | if self._menu_mode == 'drawing':
|
---|
976 | self.level_widget.set_objects(self.show_objs.value)
|
---|
977 | self.level_widget.set_enemies(self.show_enemies.value)
|
---|
978 | else:
|
---|
979 | self.level_widget.set_objects(True)
|
---|
980 | self.level_widget.set_enemies(True)
|
---|
981 | super(EditorApp, self).draw(surface)
|
---|
982 |
|
---|
983 |
|
---|
984 | if __name__ == "__main__":
|
---|
985 | if len(sys.argv) not in [2, 4]:
|
---|
986 | print 'Please supply a levelname or levelname and level size'
|
---|
987 | sys.exit()
|
---|
988 | # Need to ensure we have defaults for rendering
|
---|
989 | parse_args([])
|
---|
990 | pygame.display.init()
|
---|
991 | pygame.font.init()
|
---|
992 | pygame.display.set_mode((SCREEN[0] + MENU_WIDTH, SCREEN[1]),
|
---|
993 | pgl.SWSURFACE)
|
---|
994 | if len(sys.argv) == 2:
|
---|
995 | level = EditorLevel(sys.argv[1])
|
---|
996 | level.load(pymunk.Space())
|
---|
997 | elif len(sys.argv) == 4:
|
---|
998 | level = EditorLevel(sys.argv[1], int(sys.argv[2]), int(sys.argv[3]))
|
---|
999 | pygame.display.set_caption('Nagslang Area Editor')
|
---|
1000 | pygame.key.set_repeat(200, 100)
|
---|
1001 | app = EditorApp(level, pygame.display.get_surface())
|
---|
1002 | app.run()
|
---|