source: tools/area_editor.py

Last change on this file was 691:1eecaa7ed894, checked in by Neil Muller <drnlmuller@…>, 2 years ago

fix

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