Mercurial > mamba
changeset 508:6c61d5862310
Massive speical sprite editor rewrite
author | Neil Muller <drnlmuller@gmail.com> |
---|---|
date | Sun, 18 Sep 2011 00:11:30 +0200 |
parents | f4f883418ac2 |
children | a332f8b3619c |
files | mamba/habitats/editor.py mamba/level.py mamba/sprites.py mamba/widgets/editsprite.py |
diffstat | 4 files changed, 160 insertions(+), 38 deletions(-) [+] |
line wrap: on
line diff
--- a/mamba/habitats/editor.py Sun Sep 18 00:04:42 2011 +0200 +++ b/mamba/habitats/editor.py Sun Sep 18 00:11:30 2011 +0200 @@ -9,6 +9,7 @@ import urllib2 from mamba.engine import Habitat, NewHabitatEvent +from mamba.sprites import find_special_sprites from mamba.widgets.level import EditLevelWidget from mamba.widgets.text import TextWidget, TextButton from mamba.widgets.imagebutton import ImageButtonWidget @@ -20,7 +21,7 @@ from mamba.widgets.editlevel import EditLevelBox from mamba.level import Level, Tileset, TILE_MAP, THING_MAP, InvalidMapError from mamba.data import (check_level_exists, get_level_list, load_file, - load_image) + load_image, load_tile_image) from mamba.constants import (SCREEN, EDIT_SCREEN, NAME, ESCAPE_KEYS, RESERVED_NAMES, WINDOW_ICON, LEVEL_SERVER) @@ -41,6 +42,7 @@ self.container.add_callback(MOUSEBUTTONDOWN, self.mouse_event) self.mode = 'Tiles' self.sprite_mode = 'Add' + self.sprite_cls = None def on_enter(self): # We need to juggle the display to the correct size @@ -139,10 +141,19 @@ tile_char, text) tool_list.append(tile_button) if self.mode == "Sprites": - for name in ['Add', 'Edit', 'Delete']: + for cls_name, sprite_cls in find_special_sprites(): + image = load_tile_image(sprite_cls.image_name, + self.level.tileset.name) + name = sprite_cls.name + tile_button = ImageButtonWidget((0, 0), image, name, + color='white') + tile_button.add_callback('clicked', self.sprite_tool, + 'Add', cls_name, sprite_cls) + tool_list.append(tile_button) + for name in ['Edit', 'Delete']: tile_button = TextButton((0, 0), '%s Sprite' % name) tile_button.add_callback('clicked', self.sprite_tool, - name) + name, None, None) tool_list.append(tile_button) self.tool_widget = ToolListWidget((button_left, button_height), tool_list, MAX_TOOLS, start_key=K_2) @@ -362,9 +373,11 @@ self.level.level_name = new_name return None - def sprite_tool(self, ev, widget, sprite_mode): + def sprite_tool(self, ev, widget, sprite_mode, cls_name, sprite_cls): """Handle sprite stuff""" self.sprite_mode = sprite_mode + self.sprite_cls_name = cls_name + self.sprite_cls = sprite_cls self.level.update_tiles_ascii() # commit any changes self.clear_toolbar() self.setup_toolbar() @@ -377,18 +390,19 @@ if self.container.paused: return False tile_pos = self.edit_widget.convert_pos(ev.pos) - sprite = self.level.get_sprite_at(tile_pos) + sprite, sprite_ascii = self.level.get_sprite_at(tile_pos) if self.sprite_mode == 'Delete' and sprite: - self.level.remove_sprite(sprite) + self.level.remove_sprite(sprite_ascii) self.level.restart() elif self.sprite_mode == 'Edit' and sprite: self.edit_sprite(tile_pos, sprite) elif self.sprite_mode == 'Add' and sprite is None: - self.edit_sprite(tile_pos, sprite) + self.edit_sprite(tile_pos, + (self.sprite_cls_name, self.sprite_cls, None, [])) return True - def edit_sprite(self, tile_pos, sprite): - sprite_editor = EditSpriteBox((200, 100), tile_pos, sprite, + def edit_sprite(self, tile_pos, sprite_info): + sprite_editor = EditSpriteBox((200, 100), tile_pos, sprite_info, post_callback=self.commit_line) self.display_dialog(sprite_editor)
--- a/mamba/level.py Sun Sep 18 00:04:42 2011 +0200 +++ b/mamba/level.py Sun Sep 18 00:11:30 2011 +0200 @@ -336,8 +336,13 @@ except ValueError: continue if pos[0] == sprite_pos[0] and pos[1] == sprite_pos[1]: - return sprite_ascii - return None + pos, _sep, rest = sprite_ascii.partition(':') + class_name, rest = rest.split(None, 1) + args = rest.split() + sprite_cls = sprites.find_sprite(class_name) + sprite_id, args = args[0], args[1:] + return (class_name, sprite_cls, sprite_id, args), sprite_ascii + return None, None def remove_sprite(self, sprite): """Remove the given sprite line from the list of sprites""" @@ -366,10 +371,10 @@ def add_sprite(self, sprite): self.sprites_ascii.append(sprite) - def replace_sprite(self, sprite): + def replace_sprite(self, new_ascii): # Need to find the sprite at the same psoition - pos, _sep, rest = sprite.partition(':') + pos, _sep, rest = new_ascii.partition(':') pos = [int(x.strip()) for x in pos.split(',')] - old_sprite = self.get_sprite_at(pos) - self.sprites_ascii.remove(old_sprite) - self.sprites_ascii.append(sprite) + old_sprite, old_ascii = self.get_sprite_at(pos) + self.sprites_ascii.remove(old_ascii) + self.sprites_ascii.append(new_ascii)
--- a/mamba/sprites.py Sun Sep 18 00:04:42 2011 +0200 +++ b/mamba/sprites.py Sun Sep 18 00:11:30 2011 +0200 @@ -36,6 +36,15 @@ return cls +def find_special_sprites(): + results = [] + for cls_name, cls in globals().iteritems(): + if isinstance(cls, type) and issubclass(cls, Sprite): + if hasattr(cls, 'get_sprite_args'): + results.append((cls_name, cls)) + return results + + class SpriteImageVariants(object): VARIANTS = { '....': ('-0', ()), @@ -250,6 +259,12 @@ other = world.get_sprite(self.other_id) head.shift_tile_and_pixels((other.tile_pos, self.direction)) + @classmethod + def get_sprite_args(cls): + """Arguments for the tile constructor""" + return [('Other ID:', None), + ('Direction', ('north', 'east', 'south', 'west'))] + class ButtonSprite(SingleImageTileSprite): image_name = 'button' @@ -266,9 +281,15 @@ other = world.get_sprite(self.other_id) other.button_pushed() + @classmethod + def get_sprite_args(cls): + """Arguments for the tile constructor""" + return [('Other ID:', None)] + class GateSprite(SingleImageTileSprite): closed_name = 'closed_gate' + image_name = 'closed_gate' open_image = 'floor' name = 'gate' tileset = 'lab' @@ -287,6 +308,11 @@ self.image_name = self.open_image self.image = self.load_image(self.image_name, mutators=()) + @classmethod + def get_sprite_args(cls): + """Arguments for the tile constructor""" + return [] + class PuddleSprite(SingleImageTileSprite): image_name = 'puddle'
--- a/mamba/widgets/editsprite.py Sun Sep 18 00:04:42 2011 +0200 +++ b/mamba/widgets/editsprite.py Sun Sep 18 00:11:30 2011 +0200 @@ -5,20 +5,20 @@ class EditSpriteBox(Box): """Edit details for a special sprite on the level map""" - def __init__(self, rect, sprite_pos, sprite, post_callback=None): + def __init__(self, rect, sprite_pos, sprite_info, post_callback=None): super(EditSpriteBox, self).__init__(rect) self.sprite_pos = sprite_pos - if sprite: - _, _, rest = sprite.partition(':') - self.sprite_name, rest = rest.split(None, 1) - args = rest.split() - self.sprite_id = args[0] - self.sprite_parameters = " ".join(args[1:]) + sprite_cls_name, sprite_cls, sprite_id, args = sprite_info + self.sprite_cls_name = sprite_cls_name + self.sprite_cls = sprite_cls + if sprite_id: + self.sprite_id = sprite_id else: - self.sprite_name = '' self.sprite_id = '' - self.sprite_parameters = "" + self.sprite_parameters = args + self.new_sprite_parameters = [] self.post_callback = post_callback + self.parameter_widgets = [] self.prepare() self.modal = True @@ -26,19 +26,75 @@ title = TextWidget(self.rect, "Specify Sprite Details") self.add(title) height = self.rect.top + title.rect.height + 2 - self.edit_sprite_name = EntryTextWidget((self.rect.left, height), - self.sprite_name, prompt='Sprite Class:') + self.edit_sprite_name = TextWidget((self.rect.left, height), + 'Sprite Class: %s' % self.sprite_cls.name) self.add(self.edit_sprite_name) height += self.edit_sprite_name.rect.height + 2 - self.edit_sprite_id = EntryTextWidget((self.rect.left, height), - self.sprite_id, prompt='Sprite Id:') + self.edit_sprite_id = EntryTextWidget((self.rect.left + 20, height), + self.sprite_id, prompt='Sprite Id (required):') self.add(self.edit_sprite_id) height += self.edit_sprite_id.rect.height + 2 - self.edit_sprite_param = EntryTextWidget((self.rect.left, height), - self.sprite_parameters, prompt='Sprite Parameters:') - self.add(self.edit_sprite_param) - height += self.edit_sprite_param.rect.height + 2 - + poss_params = self.sprite_cls.get_sprite_args() + if not poss_params: + self.sprite_param = TextWidget((self.rect.left, height), + 'No Parameters') + self.add(self.sprite_param) + height += self.sprite_param.rect.height + 2 + else: + self.sprite_param = TextWidget((self.rect.left, height), + 'Parameters') + self.add(self.sprite_param) + height += self.sprite_param.rect.height + 2 + for i, param_tuple in enumerate(poss_params): + if len(self.sprite_parameters) > i: + value = self.sprite_parameters[i] + else: + value = None + if param_tuple[1] is None: + # Text Entry Parameter + if value is None: + value = '' + edit_widget = EntryTextWidget( + (self.rect.left + 20, height), + value, prompt=param_tuple[0]) + self.parameter_widgets.append(edit_widget) + self.add(edit_widget) + height += edit_widget.rect.height + elif isinstance(param_tuple[1], tuple): + # We have a list of possible values + if value is None: + value = param_tuple[1][0] # Take the first + mylist = [] + list_width = 0 + list_height = 0 + for choice in param_tuple[1]: + list_parameter = TextWidget( + (self.rect.left + 20, height), + '%s: %s' % (param_tuple[0], choice)) + # So we can pull it out of this later + list_parameter.choice = choice + list_width = max(list_width, list_parameter.rect.width) + change_list = TextButton( + (list_parameter.rect.right + 5, height), + 'Next Option') + change_list.add_callback('clicked', self.change_list, + choice, param_tuple[1], mylist) + mylist.append((list_parameter, change_list)) + list_height = max(list_height, change_list.rect.height, + list_parameter.rect.height) + if choice == value: + self.add(list_parameter) + self.add(change_list) + for x in mylist: + x[1].rect.left = self.rect.left + list_width + 25 + if x[0].rect.height < list_height: + x[0].rect.top += (list_height - + x[0].rect.height) / 2 + height += max(list_parameter.rect.height, + change_list.rect.height) + self.parameter_widgets.append(mylist) + # FIXME: Other cases + height += 20 self.ok_button = TextButton((self.rect.left + 10, height), 'OK') self.ok_button.add_callback('clicked', self.close, True) self.add(self.ok_button) @@ -49,10 +105,30 @@ self.rect.width = max(self.rect.width, 400) self.rect.height += 5 + def change_list(self, ev, widget, cur_choice, all_choices, widget_list): + pos = all_choices.index(cur_choice) + if pos == len(all_choices) - 1: + next_pos = 0 + else: + next_pos = pos + 1 + self.remove(widget_list[pos][0]) + self.remove(widget_list[pos][1]) + self.add(widget_list[next_pos][0]) + self.add(widget_list[next_pos][1]) + def close(self, ev, widget, do_update): if do_update: - self.sprite_parameters = self.edit_sprite_param.value - self.sprite_name = self.edit_sprite_name.value + self.new_sprite_parameters = [] + for param in self.parameter_widgets: + if hasattr(param, 'value'): + self.new_sprite_parameters.append(param.value) + elif isinstance(param, list): + # Find the selected one + for choice, _ in param: + if choice in self.children: + # Is selected, so we grab this choice + self.new_sprite_parameters.append(choice.choice) + break self.sprite_id = self.edit_sprite_id.value sprite = self.make_sprite() if not self.post_callback(sprite): @@ -64,8 +140,9 @@ def make_sprite(self): """Convert values to a sprite line""" pos = "%s, %s" % self.sprite_pos - return "%s: %s %s %s" % (pos, self.sprite_name, self.sprite_id, - self.sprite_parameters) + sprite_string = "%s: %s %s %s" % (pos, self.sprite_cls_name, + self.sprite_id, " ".join(self.new_sprite_parameters)) + return sprite_string def grab_focus(self): return self.ok_button.grab_focus()