source: tools/area_editor.py@ 549:f868a8592432

Last change on this file since 549:f868a8592432 was 549:f868a8592432, checked in by Neil Muller <drnlmuller@…>, 9 years ago

Less leaky terrain movement

  • Property exe set to *
File size: 48.5 KB
Line 
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
14import os
15import sys
16
17import pygame
18import pygame.locals as pgl
19
20sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
21
22import pymunk
23
24from albow.root import RootWidget
25from albow.widget import Widget
26from albow.controls import Button, Label, CheckBox
27from albow.dialogs import alert, Dialog, ask
28from albow.layout import Row
29from albow.fields import TextField
30from albow.table_view import TableView, TableColumn
31
32from nagslang.options import parse_args
33from nagslang.constants import SCREEN
34from nagslang.level import Level, POLY_COLORS, LINE_COLOR
35from nagslang.yamlish import load_s
36import nagslang.enemies as ne
37import nagslang.game_object as ngo
38import nagslang.collectable as collectable
39import nagslang.puzzle as np
40
41# layout constants
42MENU_BUTTON_HEIGHT = 35
43MENU_PAD = 4
44MENU_HALF_PAD = MENU_PAD // 2
45MENU_LEFT = SCREEN[0] + MENU_HALF_PAD
46MENU_WIDTH = 200 - MENU_PAD
47MENU_HALF_WIDTH = MENU_WIDTH // 2 - MENU_HALF_PAD
48
49BUTTON_RECT = pygame.rect.Rect(0, 0, MENU_WIDTH, MENU_BUTTON_HEIGHT)
50HALF_BUTTON_RECT = pygame.rect.Rect(0, 0, MENU_HALF_WIDTH, MENU_BUTTON_HEIGHT)
51CHECK_RECT = pygame.rect.Rect(0, 0, MENU_BUTTON_HEIGHT // 2,
52 MENU_BUTTON_HEIGHT // 2)
53
54
55class TestWorld(object):
56
57 def __init__(self):
58 self.level_state = {}
59 self.inventory = {}
60
61
62def distance(tup1, tup2):
63 return (tup1[0] - tup2[0]) ** 2 + (tup1[1] - tup2[1]) ** 2
64
65
66class EditorLevel(Level):
67
68 def __init__(self, name, x=800, y=600):
69 world = TestWorld()
70 super(EditorLevel, self).__init__(name, world)
71 self.x = x
72 self.y = y
73 # Lookup initiliasition info from the objects
74 self.lookup = {}
75 self._move_poly = None
76
77 def _in_bounds(self, pos):
78 if pos[0] < 0 or pos[0] >= self.x:
79 return False
80 if pos[1] < 0 or pos[1] >= self.y:
81 return False
82 return True
83
84 def load(self, space):
85 super(EditorLevel, self).load(space)
86 # Needed to fill in the lookup dict
87 self.reset_objs()
88
89 def point_to_pygame(self, pos):
90 # inverse of point_to_pymunk
91 # (this is also the same as point_to_pymunk, but an additional
92 # function for sanity later in pyweek).
93 return (pos[0], self.y - pos[1])
94
95 def point_to_pymunk(self, pos):
96 # inverse of point_to_pygame
97 # (this is also the same as point_to_pygame, but an additional
98 # function for sanity later in pyweek).
99 return (pos[0], self.y - pos[1])
100
101 def add_point(self, poly_index, pos):
102 self.polygons.setdefault(poly_index, [])
103 if not self._in_bounds(pos):
104 return False
105 if not self.polygons[poly_index]:
106 point = self.point_to_pymunk(pos)
107 self.polygons[poly_index].append(point)
108 else:
109 add_pos = self.point_to_pymunk(pos)
110 self.polygons[poly_index].append(add_pos)
111 return True
112
113 def delete_point(self, index):
114 if index in self.polygons and len(self.polygons[index]) > 0:
115 self.polygons[index].pop()
116
117 def close_poly(self, index):
118 """Attempts to close the current polygon.
119
120 We allow a small additional step to close the polygon, but
121 it's limited as it's a magic point addition"""
122 if len(self.polygons[index]) < 2:
123 # Too small
124 return False
125 first = self.polygons[index][0]
126 if self.add_point(index, self.point_to_pygame(first)):
127 return True
128 return False
129
130 def add_line(self, start_pos, end_pos):
131 startpoint = self.point_to_pymunk(start_pos)
132 endpoint = self.point_to_pymunk(end_pos)
133 self.lines.append([startpoint, endpoint])
134
135 def draw(self, mouse_pos, mouse_poly, filled, draw_cand_line, start_pos,
136 move_point_mode, move_poly_mode, move_point, zoom_factor,
137 level_widget):
138 self._draw_background(True)
139 # Draw polygons as needed for the editor
140 line_width = int(2 * zoom_factor)
141 if filled:
142 self._draw_exterior(True)
143 for index, polygon in self.polygons.items():
144 color = POLY_COLORS.get(index, pygame.color.THECOLORS['black'])
145 if move_point_mode and index == self._move_poly and move_point:
146 pointlist = [p for p in polygon]
147 pointlist = [self.point_to_pygame(p) if p != move_point else
148 mouse_pos for p in pointlist]
149 pygame.draw.lines(self._surface, color, False, pointlist,
150 line_width)
151 break
152 if move_poly_mode and index == self._move_poly and move_point:
153 new_point = self.point_to_pymunk(mouse_pos)
154 pointlist = [self.point_to_pygame(p)
155 for p in self.translate_poly(
156 polygon, move_point, new_point)]
157 pygame.draw.lines(self._surface, color, False, pointlist,
158 line_width)
159 #break
160 if len(polygon) > 1:
161 pointlist = [self.point_to_pygame(p) for p in polygon]
162 pygame.draw.lines(self._surface, color, False, pointlist,
163 line_width)
164 if index == mouse_poly and mouse_pos and len(polygon) > 0:
165 endpoint = self.point_to_pymunk(mouse_pos)
166 pygame.draw.line(self._surface, color,
167 self.point_to_pygame(polygon[-1]),
168 self.point_to_pygame(endpoint),
169 line_width // 2)
170 line_found = False # Hack for sane behaviour if lines overlap
171 for line in self.lines:
172 pointlist = [self.point_to_pygame(p) for p in line]
173 if move_point_mode and not self._move_poly and not line_found:
174 if move_point in line:
175 line_found = True
176 pointlist.remove(self.point_to_pygame(move_point))
177 pointlist.append(mouse_pos)
178 pygame.draw.lines(self._surface, LINE_COLOR, False, pointlist,
179 line_width)
180 if draw_cand_line and start_pos and mouse_pos:
181 endpoint = level_widget.snap_to_grid(mouse_pos)
182 endpoint = self.point_to_pymunk(endpoint)
183 pointlist = [start_pos,
184 self.point_to_pygame(endpoint)]
185 pygame.draw.lines(self._surface, LINE_COLOR, False, pointlist, 1)
186 return self._surface
187
188 def reset_objs(self):
189 # Reset the object state - needed when changing stuff
190 self.drawables = []
191 self.overlay_drawables = []
192 self._glue = np.PuzzleGlue()
193 for game_object_dict in self._game_objects:
194 obj = self._create_game_object(pymunk.Space(), **game_object_dict)
195 self.lookup[obj] = game_object_dict
196 for enemy_dict in self._enemies:
197 obj = self._create_enemy(pymunk.Space(), **enemy_dict)
198 self.lookup[obj] = enemy_dict
199
200 def get_class(self, classname, mod=None):
201 # Get the class given the classname
202 modules = {
203 'game_object': ngo,
204 'collectable': collectable,
205 'enemies': ne,
206 'puzzle': np,
207 }
208 if '.' in classname:
209 modname, classname = classname.split('.')
210 mod = modules[modname]
211 if mod is None:
212 mod = ngo
213 return getattr(mod, classname)
214
215 def try_new_object(self, classname, target, new, old=None):
216 if old in target:
217 target.remove(old)
218 try:
219 target.append(new)
220 self.reset_objs()
221 test_surface = pygame.surface.Surface((self.x, self.y))
222 # Check for initialisation stuff that happens in render
223 for thing in self.drawables:
224 if not isinstance(thing, ne.Enemy):
225 thing.render(test_surface)
226 return True
227 except Exception as e:
228 target.remove(new)
229 if old is not None:
230 target.append(old)
231 self.reset_objs()
232 alert("Failed to update object %s: %s" % (classname, e))
233 return False
234
235 def find_obj_at_pos(self, mouse_pos):
236 pymunk_pos = self.point_to_pymunk(mouse_pos)
237 # Search visible objects
238 for obj in self.drawables:
239 if obj.get_shape().point_query(pymunk_pos):
240 return obj
241 return None
242
243 def find_vertex(self, mouse_pos):
244 # search for vertexes closest to where we've killed
245 mindist = 1000
246 move_point = None
247 search_point = self.point_to_pymunk(mouse_pos)
248 for index, polygon in self.polygons.items():
249 for point in polygon:
250 dist = distance(point, search_point)
251 if dist < mindist:
252 mindist = dist
253 move_point = point
254 self._move_poly = index
255 # Also check lines
256 for line in self.lines:
257 for point in line:
258 dist = distance(point, search_point)
259 if dist < mindist:
260 mindist = dist
261 move_point = point
262 self._move_poly = None
263 return move_point
264
265 def translate_poly(self, poly, move_point, new_point):
266 dx = new_point[0] - move_point[0]
267 dy = new_point[1] - move_point[1]
268 new_poly = [(p[0] + dx, p[1] + dy) for p in poly]
269 return new_poly
270
271 def replace_poly(self, move_point, new_point):
272 new_point = self.point_to_pymunk(new_point)
273 if self._move_poly:
274 self.polygons[self._move_poly] = self.translate_poly(
275 self.polygons[self._move_poly], move_point, new_point)
276
277 def replace_vertex(self, old_point, new_point):
278 new_point = self.point_to_pymunk(new_point)
279 if self._move_poly:
280 new_polygon = [p if p != old_point else new_point for p in
281 self.polygons[self._move_poly]]
282 self.polygons[self._move_poly] = new_polygon
283 else:
284 for line in self.lines:
285 if old_point in line:
286 line.remove(old_point)
287 line.append(new_point)
288 break
289
290
291class ObjectTable(TableView):
292
293 columns = [TableColumn("Object", 690, 'l', '%r')]
294
295 def __init__(self, data):
296 super(ObjectTable, self).__init__(height=450)
297 self.data = sorted(data,
298 key=lambda d: (d.get('classname'), d.get('name')))
299 self.selected_row = -1
300
301 def num_rows(self):
302 return len(self.data)
303
304 def row_data(self, i):
305 data = self.data[i]
306 if 'name' in data:
307 return ('%s (%s)' % (data['classname'], data['name']), )
308 return (data['classname'], )
309
310 def row_is_selected(self, i):
311 return self.selected_row == i
312
313 def click_row(self, i, ev):
314 self.selected_row = i
315
316 def get_selection(self):
317 if self.selected_row >= 0:
318 return self.data[self.selected_row]
319 return None
320
321
322class EditClassDialog(Dialog):
323
324 def __init__(self, classname, cls, data, level_widget,
325 delete=False):
326 super(EditClassDialog, self).__init__()
327 self.level_widget = level_widget
328 self.classname = classname
329 self.rect = pygame.rect.Rect(0, 0, 900, 550)
330 title = Label("Editing %s" % classname)
331 title.rect = pygame.rect.Rect(100, 10, 600, 25)
332 self.add(title)
333 self.requires = cls.requires()
334 y = 40
335 self.fields = {}
336 index = 0
337 self.poly_field = None
338 self.needs_cleanup = False
339 for requirement, hint in self.requires:
340 label = Label(requirement)
341 label.rect = pygame.rect.Rect(40, y, 200, 25)
342 self.add(label)
343 field = TextField()
344 field.rect = pygame.rect.Rect(220, y, 400, 25)
345 self.add(field)
346 if data is not None:
347 if requirement in data:
348 field.set_text('%s' % data[requirement])
349 elif 'args' in data and requirement != 'name':
350 # NB: The ordering assumptions in requires should make
351 # this safe, but it's really, really, really fragile
352 try:
353 field.set_text('%s' % data['args'][index])
354 index += 1
355 except IndexError:
356 # Assumed to be arguments with the default value
357 pass
358 if hint.startswith('polygon'):
359 self.poly_field = field
360 self.fields[requirement] = field
361 hintlabel = Label(hint)
362 hintlabel.rect = pygame.rect.Rect(640, y, 250, 25)
363 self.add(hintlabel)
364 y += 30
365 if self.poly_field:
366 y += 40
367 label = Label("Polygon to use:")
368 label.rect = pygame.rect.Rect(40, y, 200, 25)
369 self.add(label)
370 self.poly_choice = TextField()
371 self.poly_choice.rect = pygame.Rect(280, y, 400, 25)
372 self.add(self.poly_choice)
373 y += 30
374 button = Button('Use Polygon X', action=self.get_poly)
375 button.rect = pygame.rect.Rect(350, y, 250, 30)
376 self.add(button)
377 buttons = []
378 if delete:
379 labels = ['OK', 'Delete', 'Cancel']
380 else:
381 labels = ['OK', 'Cancel']
382 for text in labels:
383 but = Button(text, action=lambda x=text: self.dismiss(x))
384 buttons.append(but)
385 row = Row(buttons)
386 row.rect = pygame.rect.Rect(250, 500, 700, 50)
387 self.add(row)
388
389 def get_poly(self):
390 try:
391 try:
392 index = int(self.poly_choice.get_text())
393 except ValueError:
394 index = 0
395 data = self.level_widget.level.polygons[index][:]
396 except KeyError:
397 data = []
398 if data:
399 # We unclose the polygon, because that's what pymunk
400 # wants
401 if data[0] == data[-1] and len(data) > 1:
402 data.pop()
403 data = [list(x) for x in data]
404 self.needs_cleanup = True
405 self.poly_field.set_text('%s' % data)
406
407 def cleanup(self):
408 if self.needs_cleanup:
409 self.level_widget.level.polygons[6] = []
410 self.level_widget.invalidate()
411
412 def get_data(self):
413 result = {}
414 result['classname'] = self.classname
415 args = []
416 # We arrange to bounce this through yaml'ish to convert
417 # stuff to the expected type
418 for val, _ in self.requires:
419 text = self.fields[val].get_text()
420 if not text:
421 # skip empty fields
422 continue
423 if val == 'name':
424 result['name'] = text
425 elif self.fields[val] == self.poly_field and text:
426 # Evil, but faster than good
427 try:
428 l = eval(text)
429 except Exception:
430 alert("Invalid polygon %s" % text)
431 self.needs_cleanup = False
432 return None
433 # Check for convexity
434 if not pymunk.util.is_convex(l):
435 alert("Invalid polygon %s - not convex" % text)
436 return None
437 if not pymunk.util.is_clockwise(l):
438 l.reverse()
439 if not pymunk.util.is_clockwise(l):
440 alert("Invalid polygon %s - unable to make clockwise"
441 % text)
442 return None
443 args.append(' - - %s' % l[0])
444 for coord in l[1:]:
445 args.append(' - %s' % coord)
446 else:
447 args.append(' - ' + text)
448 data = "args:\n" + '\n'.join(args)
449 result['args'] = load_s(data)['args']
450 return result
451
452
453class LevelWidget(Widget):
454
455 def __init__(self, level, parent):
456 super(LevelWidget, self).__init__(pygame.rect.Rect(0, 0,
457 SCREEN[0], SCREEN[1]))
458 self.level = level
459 self.pos = (0, 0)
460 self.filled_mode = False
461 self.mouse_pos = None
462 self.cur_poly = None
463 self._mouse_drag = False
464 self._draw_objects = False
465 self._draw_enemies = False
466 self._draw_lines = False
467 self.grid_size = 1
468 self.sel_mode = False
469 self.move_obj_mode = False
470 self.move_obj = None
471 self._start_pos = None
472 self._parent = parent
473 self._move_point_mode = False
474 self._move_poly_mode = False
475 self._move_point = False
476 self._zoom_factor = 1.0
477
478 def _level_coordinates(self, pos):
479 # Move positions to level values
480 if not pos:
481 return (0, 0)
482 # Apply zoom_factor
483 pos = pos[0] + self.pos[0], pos[1] + self.pos[1]
484 zoomed = (pos[0] * self._zoom_factor, pos[1] * self._zoom_factor)
485 return int(zoomed[0]), int(zoomed[1])
486
487 def _move_view(self, offset):
488 new_pos = [self.pos[0] + offset[0], self.pos[1] + offset[1]]
489 if new_pos[0] < 0:
490 new_pos[0] = self.pos[0]
491 elif new_pos[0] > self.level.x - SCREEN[0]:
492 new_pos[0] = self.pos[0]
493 if new_pos[1] < 0:
494 new_pos[1] = self.pos[1]
495 elif new_pos[1] > self.level.y - SCREEN[1]:
496 new_pos[1] = self.pos[1]
497 self.pos = tuple(new_pos)
498
499 def inc_grid_size(self, amount):
500 self.grid_size = max(1, self.grid_size + amount)
501 if self.grid_size > 1:
502 self.grid_size = self.grid_size - (self.grid_size % 5)
503
504 def snap_to_grid(self, pos):
505 x = pos[0] - (pos[0] % self.grid_size)
506 y = pos[1] - (pos[1] % self.grid_size)
507 return (x, y)
508
509 def set_objects(self, value):
510 if self._draw_objects != value:
511 self._draw_objects = value
512 self.invalidate()
513
514 def set_enemies(self, value):
515 if self._draw_enemies != value:
516 self._draw_enemies = value
517 self.invalidate()
518
519 def zoom_out(self):
520 self._zoom_factor = self._zoom_factor * 2.0
521 if self._zoom_factor > 8:
522 self._zoom_factor = 8
523
524 def zoom_in(self):
525 self._zoom_factor = self._zoom_factor // 2.0
526 if self._zoom_factor < 1:
527 self._zoom_factor = 1
528
529 def draw(self, surface):
530 if (self.cur_poly is not None and self.cur_poly in self.level.polygons
531 and len(self.level.polygons[self.cur_poly])):
532 # We have an active polygon
533 mouse_pos = self._level_coordinates(self.mouse_pos)
534 mouse_pos = self.snap_to_grid(mouse_pos)
535 elif self._draw_lines:
536 # Interior wall mode
537 mouse_pos = self._level_coordinates(self.mouse_pos)
538 mouse_pos = self.snap_to_grid(mouse_pos)
539 elif self._move_point_mode or self._move_poly_mode:
540 mouse_pos = self._level_coordinates(self.mouse_pos)
541 mouse_pos = self.snap_to_grid(mouse_pos)
542 else:
543 mouse_pos = None
544 level_surface = level.draw(mouse_pos, self.cur_poly, self.filled_mode,
545 self._draw_lines, self._start_pos,
546 self._move_point_mode, self._move_poly_mode,
547 self._move_point, self._zoom_factor, self)
548 if self._draw_objects:
549 for thing in self.level.drawables:
550 if not isinstance(thing, ne.Enemy):
551 thing.render(level_surface)
552 if self._draw_enemies:
553 for thing in self.level.drawables:
554 if isinstance(thing, ne.Enemy):
555 thing.render(level_surface)
556 surface_area = pygame.rect.Rect(self.pos, SCREEN)
557 zoomed_surface = level_surface.copy()
558 if self._zoom_factor != 1:
559 zoomed_surface = pygame.transform.scale(
560 level_surface,
561 (int(level_surface.get_width() / self._zoom_factor),
562 int(level_surface.get_height() / self._zoom_factor)))
563 surface.blit(zoomed_surface, (0, 0), surface_area)
564
565 def change_poly(self, new_poly):
566 self.cur_poly = new_poly
567 self._draw_lines = False
568 self._move_point_mode = False
569 if self.cur_poly is not None:
570 self._parent.reset_lit_buttons()
571 self.filled_mode = False
572
573 def line_mode(self):
574 self.cur_poly = None
575 self._parent.reset_lit_buttons()
576 self._draw_lines = True
577 self.filled_mode = False
578 self._start_pos = None
579 self._move_point_mode = False
580 self._move_poly_mode = False
581
582 def key_down(self, ev):
583 if ev.key == pgl.K_LEFT:
584 self._move_view((-10, 0))
585 elif ev.key == pgl.K_RIGHT:
586 self._move_view((10, 0))
587 elif ev.key == pgl.K_UP:
588 self._move_view((0, -10))
589 elif ev.key == pgl.K_DOWN:
590 self._move_view((0, 10))
591 elif ev.key in (pgl.K_1, pgl.K_2, pgl.K_3, pgl.K_4, pgl.K_5, pgl.K_6):
592 self.change_poly(ev.key - pgl.K_0)
593 elif ev.key == pgl.K_0:
594 self.change_poly(None)
595 elif ev.key == pgl.K_d and self.cur_poly:
596 self.level.delete_point(self.cur_poly)
597 elif ev.key == pgl.K_f:
598 self.set_filled()
599 elif ev.key == pgl.K_c:
600 self.close_poly()
601
602 def set_move_poly_mode(self):
603 self._draw_lines = False
604 self._move_point_mode = False
605 self._move_poly_mode = True
606 self.filled_mode = False
607 self._parent.reset_lit_buttons()
608 self._move_point = None
609
610 def set_move_mode(self):
611 self._draw_lines = False
612 self._move_point_mode = True
613 self._move_poly_mode = False
614 self.filled_mode = False
615 self._parent.reset_lit_buttons()
616 self._move_point = None
617
618 def set_filled(self):
619 closed, _ = self.level.all_closed()
620 if closed:
621 self.cur_poly = None
622 self._parent.reset_lit_buttons()
623 self.filled_mode = True
624 self._draw_lines = False
625 self._move_point_mode = False
626 self._move_poly_mode = False
627 else:
628 alert('Not all polygons closed, so not filling')
629
630 def mouse_move(self, ev):
631 old_pos = self.mouse_pos
632 self.mouse_pos = ev.pos
633 if self.move_obj:
634 corrected_pos = self._level_coordinates(ev.pos)
635 snapped_pos = self.snap_to_grid(corrected_pos)
636 self._move_obj(self.move_obj, snapped_pos)
637 if old_pos != self.mouse_pos and (self.cur_poly or self._draw_lines
638 or self._move_point_mode
639 or self._move_poly_mode):
640 self.invalidate()
641
642 def mouse_drag(self, ev):
643 if self._mouse_drag:
644 old_pos = self.mouse_pos
645 self.mouse_pos = ev.pos
646 diff = (-self.mouse_pos[0] + old_pos[0],
647 -self.mouse_pos[1] + old_pos[1])
648 self._move_view(diff)
649 self.invalidate()
650
651 def mouse_down(self, ev):
652 corrected_pos = self._level_coordinates(ev.pos)
653 snapped_pos = self.snap_to_grid(corrected_pos)
654 if self.sel_mode and ev.button == 1:
655 obj = self.level.find_obj_at_pos(corrected_pos)
656 if obj is not None:
657 self._edit_selected(obj)
658 elif self.move_obj_mode and ev.button == 1 and not self.move_obj:
659 obj = self.level.find_obj_at_pos(corrected_pos)
660 if obj is not None:
661 if obj.movable():
662 self.move_obj = obj
663 elif self.move_obj_mode and ev.button == 1 and self.move_obj:
664 self._update_pos(self.move_obj, snapped_pos)
665 self.move_obj = None
666 elif self._move_poly_mode and ev.button == 1:
667 if self._move_point:
668 # Place the current point
669 self.level.replace_poly(self._move_point, snapped_pos)
670 self._move_point = None
671 self.invalidate()
672 else:
673 # find the current point
674 self._move_point = self.level.find_vertex(corrected_pos)
675 elif self._move_point_mode and ev.button == 1:
676 if self._move_point:
677 # Place the current point
678 self.level.replace_vertex(self._move_point, snapped_pos)
679 self._move_point = None
680 self.invalidate()
681 else:
682 # find the current point
683 self._move_point = self.level.find_vertex(corrected_pos)
684 elif ev.button == 1:
685 if self._draw_lines:
686 if self._start_pos is None:
687 self._start_pos = snapped_pos
688 else:
689 self.level.add_line(self._start_pos, snapped_pos)
690 self._start_pos = None
691 else:
692 print "Click: %r" % (
693 self.level.point_to_pymunk(corrected_pos),)
694 if ev.button == 4: # Scroll up
695 self._move_view((0, -10))
696 elif ev.button == 5: # Scroll down
697 self._move_view((0, 10))
698 elif ev.button == 6: # Scroll left
699 self._move_view((-10, 0))
700 elif ev.button == 7: # Scroll right
701 self._move_view((10, 0))
702 elif self.cur_poly and ev.button == 1:
703 # Add a point
704 if not self.level.add_point(self.cur_poly, snapped_pos):
705 alert("Failed to place point")
706 elif ev.button == 3:
707 self._mouse_drag = True
708
709 def mouse_up(self, ev):
710 if ev.button == 3:
711 self._mouse_drag = False
712
713 def close_poly(self):
714 if self.cur_poly is None:
715 return
716 if self.level.close_poly(self.cur_poly):
717 alert("Successfully closed the polygon")
718 self.change_poly(None)
719 else:
720 alert("Failed to close the polygon")
721
722 def _edit_class(self, classname, cls, data):
723 # Dialog for class properties
724 dialog = EditClassDialog(classname, cls, data, self)
725 if dialog.present() == 'OK':
726 return dialog
727 return None
728
729 def _edit_selected(self, obj):
730 data = self.level.lookup[obj]
731 cls = obj.__class__
732 classname = obj.__class__.__name__
733 dialog = EditClassDialog(classname, cls, data, self, True)
734 res = dialog.present()
735 if res == 'OK':
736 edited = dialog.get_data()
737 if edited is not None:
738 for target in [self.level._game_objects, self.level._enemies]:
739 if data in target:
740 if self.level.try_new_object(classname, target,
741 edited, data):
742 dialog.cleanup()
743 break
744 elif res == 'Delete':
745 for target in [self.level._game_objects, self.level._enemies]:
746 if data in target:
747 target.remove(data)
748 self.level.reset_objs()
749 break
750
751 def _make_edit_dialog(self, entries):
752 # Dialog to hold the editor
753 edit_box = Dialog()
754 edit_box.rect = pygame.rect.Rect(0, 0, 700, 500)
755 table = ObjectTable(entries)
756 edit_box.add(table)
757 buttons = []
758 for text in ['OK', 'Delete', 'Cancel']:
759 but = Button(text, action=lambda x=text: edit_box.dismiss(x))
760 buttons.append(but)
761 row = Row(buttons)
762 row.rect = pygame.rect.Rect(250, 450, 700, 50)
763 edit_box.add(row)
764 edit_box.get_selection = lambda: table.get_selection()
765 return edit_box
766
767 def edit_objects(self):
768 edit_box = self._make_edit_dialog(self.level._game_objects)
769 res = edit_box.present()
770 choice = edit_box.get_selection()
771 if choice is None:
772 return
773 if res == 'OK':
774 cls = self.level.get_class(choice['classname'])
775 edit_dlg = self._edit_class(choice['classname'], cls, choice)
776 if edit_dlg is not None:
777 edited = edit_dlg.get_data()
778 if self.level.try_new_object(choice["classname"],
779 self.level._game_objects,
780 edited, choice):
781 edit_dlg.cleanup()
782 elif res == 'Delete':
783 self.level._game_objects.remove(choice)
784 self.level.reset_objs()
785
786 def edit_enemies(self):
787 edit_box = self._make_edit_dialog(self.level._enemies)
788 res = edit_box.present()
789 choice = edit_box.get_selection()
790 if choice is None:
791 return
792 if res == 'OK':
793 cls = self.level.get_class(choice['classname'], ne)
794 edit_dlg = self._edit_class(choice['classname'], cls, choice)
795 if edit_dlg is not None:
796 edited = edit_dlg.get_data()
797 if self.level.try_new_object(choice["classname"],
798 self.level._enemies,
799 edited, choice):
800 edit_dlg.cleanup()
801 elif res == 'Delete':
802 self.level._enemies.remove(choice)
803 self.level.reset_objs()
804
805 def _make_choice_dialog(self, classes):
806 # Dialog to hold the editor
807 data = []
808 for cls_name, cls in classes:
809 data.append({"classname": cls_name, "class": cls})
810 choice_box = Dialog()
811 choice_box.rect = pygame.rect.Rect(0, 0, 700, 500)
812 table = ObjectTable(data)
813 choice_box.add(table)
814 buttons = []
815 for text in ['OK', 'Cancel']:
816 but = Button(text, action=lambda x=text: choice_box.dismiss(x))
817 buttons.append(but)
818 row = Row(buttons)
819 row.rect = pygame.rect.Rect(250, 450, 700, 50)
820 choice_box.add(row)
821 choice_box.get_selection = lambda: table.get_selection()
822 return choice_box
823
824 def add_game_object(self):
825 classes = ngo.get_editable_game_objects()
826 classes.extend(("collectable.%s" % cls_name, cls)
827 for cls_name, cls
828 in collectable.get_editable_game_objects())
829 choose = self._make_choice_dialog(classes)
830 res = choose.present()
831 choice = choose.get_selection()
832 if res == 'OK' and choice is not None:
833 classname = choice['classname']
834 cls = choice['class']
835 edit_dlg = self._edit_class(classname, cls, None)
836 if edit_dlg is not None:
837 new_cls = edit_dlg.get_data()
838 if self.level.try_new_object(classname,
839 self.level._game_objects,
840 new_cls, None):
841 edit_dlg.cleanup()
842
843 def add_enemy(self):
844 classes = ne.get_editable_enemies()
845 choose = self._make_choice_dialog(classes)
846 res = choose.present()
847 choice = choose.get_selection()
848 if res == 'OK' and choice is not None:
849 classname = choice['classname']
850 cls = choice['class']
851 edit_dlg = self._edit_class(classname, cls, None)
852 if edit_dlg is not None:
853 new_cls = edit_dlg.get_data()
854 if self.level.try_new_object(classname, self.level._enemies,
855 new_cls, None):
856 edit_dlg.cleanup()
857
858 def add_puzzler(self):
859 classes = np.get_editable_puzzlers()
860 choose = self._make_choice_dialog(classes)
861 res = choose.present()
862 choice = choose.get_selection()
863 if res == 'OK' and choice is not None:
864 classname = choice['classname']
865 cls = choice['class']
866 edit_dlg = self._edit_class(classname, cls, None)
867 if edit_dlg is not None:
868 new_cls = edit_dlg.get_data()
869 if self.level.try_new_object(classname,
870 self.level._game_objects,
871 new_cls, None):
872 edit_dlg.cleanup()
873
874 def _move_obj(self, obj, new_pos):
875 new_coords = self.level.point_to_pymunk(new_pos)
876 shape = obj.get_shape()
877 shape.body.position = (new_coords[0], new_coords[1])
878 data = self.level.lookup[obj]
879 args = data['args']
880 old_coords = list(args[0])
881 param_defs = obj.requires()[1:] # chop off name
882 for i, (_key, key_type) in enumerate(param_defs):
883 if i > len(args):
884 break
885 if key_type == "polygon (convex)":
886 new_outline = self.level.translate_poly(
887 args[i], old_coords, new_coords)
888 obj.update_image(new_outline)
889 self.invalidate()
890
891 def _update_pos(self, obj, new_pos):
892 data = self.level.lookup[obj]
893 new_coords = self.level.point_to_pymunk(new_pos)
894 args = data['args']
895 old_coords = list(args[0])
896 args[0][0] = new_coords[0]
897 args[0][1] = new_coords[1]
898 param_defs = obj.requires()[1:] # chop off name
899 for i, (_key, key_type) in enumerate(param_defs):
900 if i > len(args):
901 break
902 if key_type == "polygon (convex)":
903 args[i] = self.level.translate_poly(
904 args[i], old_coords, new_coords)
905 self.level.reset_objs()
906 self.invalidate()
907
908
909class HighLightButton(Button):
910 """Button with highlight support"""
911 def __init__(self, text, parent, **kwds):
912 super(HighLightButton, self).__init__(text, **kwds)
913 self._parent = parent
914
915 def highlight(self):
916 self.border_color = pygame.color.Color('red')
917
918 def reset(self):
919 self.border_color = self.fg_color
920
921
922class PolyButton(HighLightButton):
923 """Button for coosing the correct polygon"""
924
925 def __init__(self, index, level_widget, parent):
926 if index is not None:
927 text = "P %s" % index
928 else:
929 text = 'Exit Draw Mode'
930 super(PolyButton, self).__init__(text, parent)
931 self.index = index
932 self.level_widget = level_widget
933
934 def action(self):
935 self.level_widget.change_poly(self.index)
936 self._parent.reset_lit_buttons()
937 if self.index is not None:
938 self.highlight()
939
940
941class GridSizeLabel(Label):
942 """Label and setter for grid size."""
943
944 def __init__(self, level_widget, **kwds):
945 self.level_widget = level_widget
946 super(GridSizeLabel, self).__init__(self.grid_text(), **kwds)
947
948 def grid_text(self):
949 return "Grid size: %d" % self.level_widget.grid_size
950
951 def inc_grid_size(self, amount):
952 self.level_widget.inc_grid_size(amount)
953 self.set_text(self.grid_text())
954
955
956class SnapButton(Button):
957 """Button for increasing or decreasing snap-to-grid size."""
958
959 def __init__(self, grid_size_label, parent, inc_amount):
960 self.grid_size_label = grid_size_label
961 self.inc_amount = inc_amount
962 text = "Grid %s%d" % (
963 '-' if inc_amount < 0 else '+',
964 abs(inc_amount))
965 self._parent = parent
966 super(SnapButton, self).__init__(text)
967
968 def action(self):
969 self.grid_size_label.inc_grid_size(self.inc_amount)
970
971
972class EditorApp(RootWidget):
973
974 def __init__(self, level, surface):
975 super(EditorApp, self).__init__(surface)
976 self.level = level
977 self.level_widget = LevelWidget(self.level, self)
978 self.add(self.level_widget)
979
980 self._dMenus = {}
981
982 self._light_buttons = []
983
984 self._make_draw_menu()
985 self._make_objects_menu()
986
987 self._menu_mode = 'drawing'
988 self._populate_menu()
989
990 self._zoom = 1
991
992 def _make_draw_menu(self):
993 widgets = []
994
995 white = pygame.color.Color("white")
996
997 # Add poly buttons
998 y = 5
999 for poly in range(1, 10):
1000 but = PolyButton(poly, self.level_widget, self)
1001 but.rect = pygame.rect.Rect(0, 0, MENU_WIDTH // 3 - MENU_PAD,
1002 MENU_BUTTON_HEIGHT)
1003 index = poly % 3
1004 if index == 1:
1005 but.rect.move_ip(MENU_LEFT, y)
1006 elif index == 2:
1007 but.rect.move_ip(MENU_LEFT + MENU_WIDTH // 3 - MENU_HALF_PAD,
1008 y)
1009 else:
1010 left = MENU_LEFT + 2 * MENU_WIDTH // 3 - MENU_HALF_PAD
1011 but.rect.move_ip(left, y)
1012 y += MENU_BUTTON_HEIGHT + MENU_PAD
1013 self._light_buttons.append(but)
1014 widgets.append(but)
1015
1016 end_poly_but = PolyButton(None, self.level_widget, self)
1017 end_poly_but.rect = BUTTON_RECT.copy()
1018 end_poly_but.rect.move_ip(MENU_LEFT, y)
1019 widgets.append(end_poly_but)
1020 y += MENU_BUTTON_HEIGHT + MENU_PAD
1021
1022 self.move_point_but = HighLightButton("Mv Point", self,
1023 action=self.move_point)
1024 self.move_point_but.rect = HALF_BUTTON_RECT.copy()
1025 self.move_point_but.rect.move_ip(MENU_LEFT, y)
1026 widgets.append(self.move_point_but)
1027 self._light_buttons.append(self.move_point_but)
1028
1029 self.move_poly_but = HighLightButton("Mv Poly", self,
1030 action=self.move_poly)
1031 self.move_poly_but.rect = HALF_BUTTON_RECT.copy()
1032 self.move_poly_but.rect.move_ip(MENU_LEFT + MENU_HALF_WIDTH, y)
1033 widgets.append(self.move_poly_but)
1034 self._light_buttons.append(self.move_poly_but)
1035
1036 y += MENU_BUTTON_HEIGHT + MENU_PAD
1037
1038 # grid size widgets
1039 grid_size_label = GridSizeLabel(
1040 self.level_widget, width=BUTTON_RECT.width,
1041 align="c", fg_color=white)
1042 grid_size_label.rect.move_ip(MENU_LEFT, y)
1043 widgets.append(grid_size_label)
1044 y += grid_size_label.rect.height + MENU_PAD
1045 inc_snap_but = SnapButton(grid_size_label, self, 5)
1046 inc_snap_but.rect = HALF_BUTTON_RECT.copy()
1047 inc_snap_but.rect.move_ip(MENU_LEFT, y)
1048 widgets.append(inc_snap_but)
1049 dec_snap_but = SnapButton(grid_size_label, self, -5)
1050 dec_snap_but.rect = HALF_BUTTON_RECT.copy()
1051 dec_snap_but.rect.move_ip(
1052 MENU_LEFT + MENU_HALF_WIDTH, y)
1053 widgets.append(dec_snap_but)
1054 y += MENU_BUTTON_HEIGHT + MENU_PAD
1055
1056 self.draw_line_but = HighLightButton("Draw interior wall", self,
1057 action=self.set_line_mode)
1058 self.draw_line_but.rect = BUTTON_RECT.copy()
1059 self.draw_line_but.rect.move_ip(MENU_LEFT, y)
1060 widgets.append(self.draw_line_but)
1061 self._light_buttons.append(self.draw_line_but)
1062 y += MENU_BUTTON_HEIGHT + MENU_PAD
1063
1064 fill_but = Button('Fill exterior', action=self.level_widget.set_filled)
1065 fill_but.rect = BUTTON_RECT.copy()
1066 fill_but.rect.move_ip(MENU_LEFT, y)
1067 widgets.append(fill_but)
1068 y += MENU_BUTTON_HEIGHT + MENU_PAD
1069
1070 close_poly_but = Button('Close Polygon',
1071 action=self.level_widget.close_poly)
1072 close_poly_but.rect = BUTTON_RECT.copy()
1073 close_poly_but.rect.move_ip(MENU_LEFT, y)
1074 widgets.append(close_poly_but)
1075 y += MENU_BUTTON_HEIGHT + MENU_PAD
1076
1077 self.show_objs = CheckBox(fg_color=white)
1078 self.show_objs.rect = CHECK_RECT.copy()
1079 self.show_objs.rect.move_ip(MENU_LEFT, y)
1080 label = Label("Show Objects", fg_color=white)
1081 label.rect.move_ip(MENU_LEFT + MENU_BUTTON_HEIGHT // 2 + MENU_PAD, y)
1082 widgets.append(self.show_objs)
1083 widgets.append(label)
1084 y += label.rect.height + MENU_PAD
1085
1086 self.show_enemies = CheckBox(fg_color=white)
1087 self.show_enemies.rect = CHECK_RECT.copy()
1088 self.show_enemies.rect.move_ip(MENU_LEFT, y)
1089 label = Label("Show enemy start pos", fg_color=white)
1090 label.rect.move_ip(MENU_LEFT + MENU_BUTTON_HEIGHT // 2 + MENU_PAD, y)
1091 widgets.append(self.show_enemies)
1092 widgets.append(label)
1093 y += label.rect.height + MENU_PAD
1094
1095 y += MENU_PAD
1096 switch_but = Button('Switch to Objects', action=self.switch_to_objects)
1097 switch_but.rect = BUTTON_RECT.copy()
1098 switch_but.rect.move_ip(MENU_LEFT, y)
1099 widgets.append(switch_but)
1100 y += switch_but.rect.height + MENU_PAD
1101
1102 save_but = Button('Save Level', action=self.save)
1103 save_but.rect = BUTTON_RECT.copy()
1104 save_but.rect.move_ip(MENU_LEFT, y)
1105 widgets.append(save_but)
1106 y += MENU_BUTTON_HEIGHT + MENU_PAD
1107
1108 zoom_out = Button('Zoom out', action=self.level_widget.zoom_out)
1109 zoom_out.rect = BUTTON_RECT.copy()
1110 zoom_out.rect.width = zoom_out.rect.width // 2
1111 zoom_out.rect.move_ip(MENU_LEFT, y)
1112 widgets.append(zoom_out)
1113
1114 zoom_in = Button('Zoom in', action=self.level_widget.zoom_in)
1115 zoom_in.rect = BUTTON_RECT.copy()
1116 zoom_in.width = zoom_in.width // 2
1117 zoom_in.rect.move_ip(MENU_LEFT + zoom_out.width, y)
1118 widgets.append(zoom_in)
1119
1120 y = SCREEN[1] - MENU_BUTTON_HEIGHT - MENU_PAD
1121 quit_but = Button('Quit', action=self.do_quit)
1122 quit_but.rect = BUTTON_RECT.copy()
1123 quit_but.rect.move_ip(MENU_LEFT, y)
1124 widgets.append(quit_but)
1125
1126 self._dMenus['drawing'] = widgets
1127
1128 def _make_objects_menu(self):
1129 widgets = []
1130
1131 # Add poly buttons
1132 y = 15
1133
1134 edit_objs_but = Button('Edit Objects',
1135 action=self.level_widget.edit_objects)
1136 edit_objs_but.rect = BUTTON_RECT.copy()
1137 edit_objs_but.rect.move_ip(MENU_LEFT, y)
1138 widgets.append(edit_objs_but)
1139 y += MENU_BUTTON_HEIGHT + MENU_PAD
1140
1141 edir_enemies_but = Button('Edit Enemies',
1142 action=self.level_widget.edit_enemies)
1143 edir_enemies_but.rect = BUTTON_RECT.copy()
1144 edir_enemies_but.rect.move_ip(MENU_LEFT, y)
1145 widgets.append(edir_enemies_but)
1146 y += MENU_BUTTON_HEIGHT + MENU_PAD
1147
1148 add_obj_but = Button('Add Game Object',
1149 action=self.level_widget.add_game_object)
1150 add_obj_but.rect = BUTTON_RECT.copy()
1151 add_obj_but.rect.move_ip(MENU_LEFT, y)
1152 widgets.append(add_obj_but)
1153 y += MENU_BUTTON_HEIGHT + MENU_PAD
1154
1155 add_puzzle_but = Button('Add Puzzler',
1156 action=self.level_widget.add_puzzler)
1157 add_puzzle_but.rect = BUTTON_RECT.copy()
1158 add_puzzle_but.rect.move_ip(MENU_LEFT, y)
1159 widgets.append(add_puzzle_but)
1160 y += MENU_BUTTON_HEIGHT + MENU_PAD
1161
1162 add_enemy_but = Button('Add Enemy',
1163 action=self.level_widget.add_enemy)
1164 add_enemy_but.rect = BUTTON_RECT.copy()
1165 add_enemy_but.rect.move_ip(MENU_LEFT, y)
1166 widgets.append(add_enemy_but)
1167 y += MENU_BUTTON_HEIGHT + MENU_PAD
1168
1169 y += MENU_PAD
1170 self.sel_mode_but = HighLightButton('Select Object', self,
1171 action=self.sel_mode)
1172 self.sel_mode_but.rect = BUTTON_RECT.copy()
1173 self.sel_mode_but.rect.move_ip(MENU_LEFT, y)
1174 widgets.append(self.sel_mode_but)
1175 self._light_buttons.append(self.sel_mode_but)
1176 y += MENU_BUTTON_HEIGHT + MENU_PAD
1177
1178 y += MENU_PAD
1179 self.move_obj_mode_but = HighLightButton('Move Object', self,
1180 action=self.move_obj_mode)
1181 self.move_obj_mode_but.rect = BUTTON_RECT.copy()
1182 self.move_obj_mode_but.rect.move_ip(MENU_LEFT, y)
1183 widgets.append(self.move_obj_mode_but)
1184 self._light_buttons.append(self.move_obj_mode_but)
1185 y += MENU_BUTTON_HEIGHT + MENU_PAD
1186
1187 y += MENU_PAD
1188 switch_but = Button('Switch to Drawing', action=self.switch_to_draw)
1189 switch_but.rect = BUTTON_RECT.copy()
1190 switch_but.rect.move_ip(MENU_LEFT, y)
1191 widgets.append(switch_but)
1192 y += switch_but.rect.height + MENU_PAD
1193
1194 save_but = Button('Save Level', action=self.save)
1195 save_but.rect = BUTTON_RECT.copy()
1196 save_but.rect.move_ip(MENU_LEFT, y)
1197 widgets.append(save_but)
1198 y += MENU_BUTTON_HEIGHT + MENU_PAD
1199
1200 zoom_out = Button('Zoom out', action=self.level_widget.zoom_out)
1201 zoom_out.rect = BUTTON_RECT.copy()
1202 zoom_out.rect.width = zoom_out.rect.width // 2
1203 zoom_out.rect.move_ip(MENU_LEFT, y)
1204 widgets.append(zoom_out)
1205
1206 zoom_in = Button('Zoom in', action=self.level_widget.zoom_in)
1207 zoom_in.rect = BUTTON_RECT.copy()
1208 zoom_in.width = zoom_in.width // 2
1209 zoom_in.rect.move_ip(MENU_LEFT + zoom_out.width, y)
1210 widgets.append(zoom_in)
1211 y += MENU_BUTTON_HEIGHT + MENU_PAD
1212
1213 y = SCREEN[1] - MENU_BUTTON_HEIGHT - MENU_PAD
1214 quit_but = Button('Quit', action=self.do_quit)
1215 quit_but.rect = BUTTON_RECT.copy()
1216 quit_but.rect.move_ip(MENU_LEFT, y)
1217 widgets.append(quit_but)
1218
1219 self._dMenus['objects'] = widgets
1220
1221 def key_down(self, ev):
1222 if ev.key == pgl.K_ESCAPE:
1223 self.do_quit()
1224 elif ev.key == pgl.K_s:
1225 self.save()
1226 else:
1227 self.level_widget.key_down(ev)
1228
1229 def do_quit(self):
1230 res = ask("Really Quit?")
1231 if res == "OK":
1232 self.quit()
1233
1234 def save(self):
1235 closed, messages = self.level.all_closed()
1236 if closed:
1237 self.level.save()
1238 # display success
1239 alert("Level %s saved successfully." % self.level.name)
1240 else:
1241 # display errors
1242 alert("Failed to save level.\n\n%s" % '\n'.join(messages))
1243
1244 def switch_to_draw(self):
1245 if self._menu_mode != 'drawing':
1246 self._clear_menu()
1247 self._menu_mode = 'drawing'
1248 self._populate_menu()
1249
1250 def switch_to_objects(self):
1251 if self._menu_mode != 'objects':
1252 self._clear_menu()
1253 self._menu_mode = 'objects'
1254 self._populate_menu()
1255
1256 def _clear_menu(self):
1257 for widget in self._dMenus[self._menu_mode]:
1258 self.remove(widget)
1259
1260 def reset_lit_buttons(self):
1261 for but in self._light_buttons:
1262 but.reset()
1263
1264 def _populate_menu(self):
1265 self.level_widget.change_poly(None)
1266 self.level_widget.sel_mode = False
1267 self.level_widget.move_obj_mode = False
1268 self.level_widget.move_obj = None
1269 for widget in self._dMenus[self._menu_mode]:
1270 self.add(widget)
1271 self.invalidate()
1272
1273 def set_line_mode(self):
1274 self.level_widget.line_mode()
1275 self.draw_line_but.highlight()
1276
1277 def sel_mode(self):
1278 self.level_widget.sel_mode = not self.level_widget.sel_mode
1279 if self.level_widget.sel_mode:
1280 self.move_obj_mode_but.reset()
1281 self.sel_mode_but.highlight()
1282 self.level_widget.move_obj_mode = False
1283 self.level_widget.move_obj = None
1284 else:
1285 self.sel_mode_but.reset()
1286
1287 def move_obj_mode(self):
1288 self.level_widget.move_obj_mode = not self.level_widget.move_obj_mode
1289 if self.level_widget.move_obj_mode:
1290 self.sel_mode_but.reset()
1291 self.move_obj_mode_but.highlight()
1292 self.level_widget.sel_mode = False
1293 else:
1294 self.move_obj_mode_but.reset()
1295
1296 def mouse_move(self, ev):
1297 self.level_widget.mouse_move(ev)
1298
1299 def move_point(self):
1300 self.level_widget.set_move_mode()
1301 self.move_point_but.highlight()
1302
1303 def move_poly(self):
1304 self.level_widget.set_move_poly_mode()
1305 self.move_poly_but.highlight()
1306
1307 def draw(self, surface):
1308 # Update checkbox state
1309 if self._menu_mode == 'drawing':
1310 self.level_widget.set_objects(self.show_objs.value)
1311 self.level_widget.set_enemies(self.show_enemies.value)
1312 else:
1313 self.level_widget.set_objects(True)
1314 self.level_widget.set_enemies(True)
1315 super(EditorApp, self).draw(surface)
1316
1317
1318if __name__ == "__main__":
1319 if len(sys.argv) not in [2, 4]:
1320 print 'Please supply a levelname or levelname and level size'
1321 sys.exit()
1322 # Need to ensure we have defaults for rendering
1323 parse_args([])
1324 pygame.display.init()
1325 pygame.font.init()
1326 pygame.display.set_mode((SCREEN[0] + MENU_WIDTH, SCREEN[1]),
1327 pgl.SWSURFACE)
1328 if len(sys.argv) == 2:
1329 level = EditorLevel(sys.argv[1])
1330 level.load(pymunk.Space())
1331 elif len(sys.argv) == 4:
1332 level = EditorLevel(sys.argv[1], int(sys.argv[2]), int(sys.argv[3]))
1333 pygame.display.set_caption('Nagslang Area Editor')
1334 pygame.key.set_repeat(200, 100)
1335 app = EditorApp(level, pygame.display.get_surface())
1336 app.run()
Note: See TracBrowser for help on using the repository browser.