Mercurial > nagslang
comparison tools/area_editor.py @ 355:9589e1db4433
Allow copying polygon 6 into terrain objects
author | Neil Muller <drnlmuller@gmail.com> |
---|---|
date | Fri, 06 Sep 2013 17:32:25 +0200 |
parents | 6e32494b9f9e |
children | 314ddad2d6d2 |
comparison
equal
deleted
inserted
replaced
354:55752fc7b753 | 355:9589e1db4433 |
---|---|
47 BUTTON_RECT = pygame.rect.Rect(0, 0, MENU_WIDTH, MENU_BUTTON_HEIGHT) | 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, | 48 CHECK_RECT = pygame.rect.Rect(0, 0, MENU_BUTTON_HEIGHT // 2, |
49 MENU_BUTTON_HEIGHT // 2) | 49 MENU_BUTTON_HEIGHT // 2) |
50 | 50 |
51 | 51 |
52 class TestWorld(object): | |
53 | |
54 def __init__(self): | |
55 self.level_state = {} | |
56 | |
57 | |
52 class EditorLevel(Level): | 58 class EditorLevel(Level): |
53 | 59 |
54 def __init__(self, name, x=800, y=600): | 60 def __init__(self, name, x=800, y=600): |
55 super(EditorLevel, self).__init__(name, None) | 61 world = TestWorld() |
62 super(EditorLevel, self).__init__(name, world) | |
56 self.x = x | 63 self.x = x |
57 self.y = y | 64 self.y = y |
58 # Lookup initiliasition info from the objects | 65 # Lookup initiliasition info from the objects |
59 self.lookup = {} | 66 self.lookup = {} |
60 | 67 |
260 return None | 267 return None |
261 | 268 |
262 | 269 |
263 class EditClassDialog(Dialog): | 270 class EditClassDialog(Dialog): |
264 | 271 |
265 def __init__(self, classname, cls, data, delete=False): | 272 def __init__(self, classname, cls, data, level_widget, |
273 delete=False): | |
266 super(EditClassDialog, self).__init__() | 274 super(EditClassDialog, self).__init__() |
275 self.level_widget = level_widget | |
267 self.classname = classname | 276 self.classname = classname |
268 self.rect = pygame.rect.Rect(0, 0, 800, 550) | 277 self.rect = pygame.rect.Rect(0, 0, 900, 550) |
269 title = Label("Editing %s" % classname) | 278 title = Label("Editing %s" % classname) |
270 title.rect = pygame.rect.Rect(100, 10, 600, 25) | 279 title.rect = pygame.rect.Rect(100, 10, 600, 25) |
271 self.add(title) | 280 self.add(title) |
272 self.requires = cls.requires() | 281 self.requires = cls.requires() |
273 y = 40 | 282 y = 40 |
274 self.fields = {} | 283 self.fields = {} |
275 index = 0 | 284 index = 0 |
285 self.poly_field = None | |
286 self.needs_cleanup = False | |
276 for requirement, hint in self.requires: | 287 for requirement, hint in self.requires: |
277 label = Label(requirement) | 288 label = Label(requirement) |
278 label.rect = pygame.rect.Rect(40, y, 200, 25) | 289 label.rect = pygame.rect.Rect(40, y, 200, 25) |
279 self.add(label) | 290 self.add(label) |
280 field = TextField() | 291 field = TextField() |
290 field.set_text('%s' % data['args'][index]) | 301 field.set_text('%s' % data['args'][index]) |
291 index += 1 | 302 index += 1 |
292 except IndexError: | 303 except IndexError: |
293 # Assumed to be arguments with the default value | 304 # Assumed to be arguments with the default value |
294 pass | 305 pass |
306 if hint.startswith('polygon'): | |
307 self.poly_field = field | |
295 self.fields[requirement] = field | 308 self.fields[requirement] = field |
296 hintlabel = Label(hint) | 309 hintlabel = Label(hint) |
297 hintlabel.rect = pygame.rect.Rect(640, y, 100, 25) | 310 hintlabel.rect = pygame.rect.Rect(640, y, 250, 25) |
298 self.add(hintlabel) | 311 self.add(hintlabel) |
299 y += 30 | 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) | |
300 buttons = [] | 318 buttons = [] |
301 if delete: | 319 if delete: |
302 labels = ['OK', 'Delete', 'Cancel'] | 320 labels = ['OK', 'Delete', 'Cancel'] |
303 else: | 321 else: |
304 labels = ['OK', 'Cancel'] | 322 labels = ['OK', 'Cancel'] |
306 but = Button(text, action=lambda x=text: self.dismiss(x)) | 324 but = Button(text, action=lambda x=text: self.dismiss(x)) |
307 buttons.append(but) | 325 buttons.append(but) |
308 row = Row(buttons) | 326 row = Row(buttons) |
309 row.rect = pygame.rect.Rect(250, 500, 700, 50) | 327 row.rect = pygame.rect.Rect(250, 500, 700, 50) |
310 self.add(row) | 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() | |
311 | 348 |
312 def get_data(self): | 349 def get_data(self): |
313 result = {} | 350 result = {} |
314 result['classname'] = self.classname | 351 result['classname'] = self.classname |
315 args = [] | 352 args = [] |
320 if not text: | 357 if not text: |
321 # skip empty fields | 358 # skip empty fields |
322 continue | 359 continue |
323 if val == 'name': | 360 if val == 'name': |
324 result['name'] = text | 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 | |
325 else: | 378 else: |
326 args.append(' - ' + text) | 379 args.append(' - ' + text) |
327 data = "args:\n" + '\n'.join(args) | 380 data = "args:\n" + '\n'.join(args) |
328 result['args'] = load_s(data)['args'] | 381 result['args'] = load_s(data)['args'] |
329 return result | 382 return result |
502 else: | 555 else: |
503 alert("Failed to close the polygon") | 556 alert("Failed to close the polygon") |
504 | 557 |
505 def _edit_class(self, classname, cls, data): | 558 def _edit_class(self, classname, cls, data): |
506 # Dialog for class properties | 559 # Dialog for class properties |
507 dialog = EditClassDialog(classname, cls, data) | 560 dialog = EditClassDialog(classname, cls, data, self) |
508 if dialog.present() == 'OK': | 561 if dialog.present() == 'OK': |
509 return dialog.get_data() | 562 return dialog |
510 return None | 563 return None |
511 | 564 |
512 def _edit_selected(self, obj): | 565 def _edit_selected(self, obj): |
513 data = self.level.lookup[obj] | 566 data = self.level.lookup[obj] |
514 cls = obj.__class__ | 567 cls = obj.__class__ |
515 classname = obj.__class__.__name__ | 568 classname = obj.__class__.__name__ |
516 dialog = EditClassDialog(classname, cls, data, True) | 569 dialog = EditClassDialog(classname, cls, data, self, True) |
517 res = dialog.present() | 570 res = dialog.present() |
518 if res == 'OK': | 571 if res == 'OK': |
519 edited = dialog.get_data() | 572 edited = dialog.get_data() |
520 if edited is not None: | 573 if edited is not None: |
521 for target in [self.level._game_objects, self.level._enemies]: | 574 for target in [self.level._game_objects, self.level._enemies]: |
522 if data in target: | 575 if data in target: |
523 self.level.try_new_object(classname, target, | 576 if self.level.try_new_object(classname, target, |
524 edited, data) | 577 edited, data): |
578 dialog.cleanup() | |
525 break | 579 break |
526 elif res == 'Delete': | 580 elif res == 'Delete': |
527 for target in [self.level._game_objects, self.level._enemies]: | 581 for target in [self.level._game_objects, self.level._enemies]: |
528 if data in target: | 582 if data in target: |
529 target.remove(data) | 583 target.remove(data) |
552 choice = edit_box.get_selection() | 606 choice = edit_box.get_selection() |
553 if choice is None: | 607 if choice is None: |
554 return | 608 return |
555 if res == 'OK': | 609 if res == 'OK': |
556 cls = self.level.get_class(choice['classname']) | 610 cls = self.level.get_class(choice['classname']) |
557 edited = self._edit_class(choice['classname'], cls, choice) | 611 edit_dlg = self._edit_class(choice['classname'], cls, choice) |
558 if edited is not None: | 612 if edit_dlg is not None: |
559 self.level.try_new_object(choice["classname"], | 613 edited = edit_dlg.get_data() |
560 self.level._game_objects, | 614 if self.level.try_new_object(choice["classname"], |
561 edited, choice) | 615 self.level._game_objects, |
616 edited, choice): | |
617 edit_dlg.cleanup() | |
562 elif res == 'Delete': | 618 elif res == 'Delete': |
563 self.level._game_objects.remove(choice) | 619 self.level._game_objects.remove(choice) |
564 self.level.reset_objs() | 620 self.level.reset_objs() |
565 | 621 |
566 def edit_enemies(self): | 622 def edit_enemies(self): |
569 choice = edit_box.get_selection() | 625 choice = edit_box.get_selection() |
570 if choice is None: | 626 if choice is None: |
571 return | 627 return |
572 if res == 'OK': | 628 if res == 'OK': |
573 cls = self.level.get_class(choice['classname'], ne) | 629 cls = self.level.get_class(choice['classname'], ne) |
574 edited = self._edit_class(choice['classname'], cls, choice) | 630 edit_dlg = self._edit_class(choice['classname'], cls, choice) |
575 if edited is not None: | 631 if edit_dlg is not None: |
576 self.level.try_new_object(choice["classname"], | 632 edited = edit_dlg.get_data() |
577 self.level._enemies, edited, choice) | 633 if self.level.try_new_object(choice["classname"], |
634 self.level._enemies, | |
635 edited, choice): | |
636 edit_dlg.cleanup() | |
578 elif res == 'Delete': | 637 elif res == 'Delete': |
579 self.level._enemies.remove(choice) | 638 self.level._enemies.remove(choice) |
580 self.level.reset_objs() | 639 self.level.reset_objs() |
581 | 640 |
582 def _make_choice_dialog(self, classes): | 641 def _make_choice_dialog(self, classes): |
604 res = choose.present() | 663 res = choose.present() |
605 choice = choose.get_selection() | 664 choice = choose.get_selection() |
606 if res == 'OK' and choice is not None: | 665 if res == 'OK' and choice is not None: |
607 classname = choice['classname'] | 666 classname = choice['classname'] |
608 cls = choice['class'] | 667 cls = choice['class'] |
609 new_cls = self._edit_class(classname, cls, None) | 668 edit_dlg = self._edit_class(classname, cls, None) |
610 if new_cls is not None: | 669 if edit_dlg is not None: |
611 self.level.try_new_object(classname, self.level._game_objects, | 670 new_cls = edit_dlg.get_data() |
612 new_cls, None) | 671 if self.level.try_new_object(classname, |
672 self.level._game_objects, | |
673 new_cls, None): | |
674 edit_dlg.cleanup() | |
613 | 675 |
614 def add_enemy(self): | 676 def add_enemy(self): |
615 classes = ne.get_editable_enemies() | 677 classes = ne.get_editable_enemies() |
616 choose = self._make_choice_dialog(classes) | 678 choose = self._make_choice_dialog(classes) |
617 res = choose.present() | 679 res = choose.present() |
618 choice = choose.get_selection() | 680 choice = choose.get_selection() |
619 if res == 'OK' and choice is not None: | 681 if res == 'OK' and choice is not None: |
620 classname = choice['classname'] | 682 classname = choice['classname'] |
621 cls = choice['class'] | 683 cls = choice['class'] |
622 new_cls = self._edit_class(classname, cls, None) | 684 edit_dlg = self._edit_class(classname, cls, None) |
623 if new_cls is not None: | 685 if edit_dlg is not None: |
624 self.level.try_new_object(classname, self.level._enemies, | 686 new_cls = edit_dlg.get_data() |
625 new_cls, None) | 687 if self.level.try_new_object(classname, self.level._enemies, |
688 new_cls, None): | |
689 edit_dlg.cleanup() | |
626 | 690 |
627 def add_puzzler(self): | 691 def add_puzzler(self): |
628 classes = np.get_editable_puzzlers() | 692 classes = np.get_editable_puzzlers() |
629 choose = self._make_choice_dialog(classes) | 693 choose = self._make_choice_dialog(classes) |
630 res = choose.present() | 694 res = choose.present() |
631 choice = choose.get_selection() | 695 choice = choose.get_selection() |
632 if res == 'OK' and choice is not None: | 696 if res == 'OK' and choice is not None: |
633 classname = choice['classname'] | 697 classname = choice['classname'] |
634 cls = choice['class'] | 698 cls = choice['class'] |
635 new_cls = self._edit_class(classname, cls, None) | 699 edit_dlg = self._edit_class(classname, cls, None) |
636 if new_cls is not None: | 700 if edit_dlg is not None: |
637 self.level.try_new_object(classname, self.level._game_objects, | 701 new_cls = edit_dlg.get_data() |
638 new_cls, None) | 702 if self.level.try_new_object(classname, |
703 self.level._game_objects, | |
704 new_cls, None): | |
705 edit_dlg.cleanup() | |
639 | 706 |
640 | 707 |
641 class HighLightButton(Button): | 708 class HighLightButton(Button): |
642 """Button with highlight support""" | 709 """Button with highlight support""" |
643 def __init__(self, text, parent, **kwds): | 710 def __init__(self, text, parent, **kwds): |