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):