void DungeonChanged() { Dungeon dungeon = Project.GetDungeon(dungeonSpinButton.ValueAsInt); dungeonEventWrapper.ReplaceEventSource(dungeon); floorSpinButton.Adjustment.Upper = dungeon.NumFloors - 1; if (floorSpinButton.ValueAsInt >= dungeon.NumFloors) { floorSpinButton.Value = dungeon.NumFloors - 1; } var vrg = dungeon.ValueReferenceGroup; if (dungeonVre != null) { dungeonVre.ReplaceValueReferenceGroup(vrg); } else { dungeonVre = new ValueReferenceEditor(Project, vrg, "Base Data"); dungeonVre.ShowAll(); dungeonVreContainer.Add(dungeonVre); } minimap.SetMap(dungeon); minimap.Floor = floorSpinButton.ValueAsInt; RoomChanged(); }
void RoomChanged() { Dungeon dungeon = minimap.Map as Dungeon; Room room = minimap.GetRoom(); roomSpinButton.Value = room.Index & 0xff; // This could go in the constructor I guess // TODO: Not tied to underlying event handlers, should generate this in Room.cs instead // (but doesn't currently matter since the data is not editable in multiple places at // once) var vrs = new ValueReference[] { new AbstractBoolValueReference(Project, name: "Up", getter: () => minimap.GetRoom().DungeonFlagUp, setter: (v) => minimap.GetRoom().DungeonFlagUp = v), new AbstractBoolValueReference(Project, name: "Right", getter: () => minimap.GetRoom().DungeonFlagRight, setter: (v) => minimap.GetRoom().DungeonFlagRight = v), new AbstractBoolValueReference(Project, name: "Down", getter: () => minimap.GetRoom().DungeonFlagDown, setter: (v) => minimap.GetRoom().DungeonFlagDown = v), new AbstractBoolValueReference(Project, name: "Left", getter: () => minimap.GetRoom().DungeonFlagLeft, setter: (v) => minimap.GetRoom().DungeonFlagLeft = v), new AbstractBoolValueReference(Project, name: "Key", getter: () => minimap.GetRoom().DungeonFlagKey, setter: (v) => minimap.GetRoom().DungeonFlagKey = v), new AbstractBoolValueReference(Project, name: "Chest", getter: () => minimap.GetRoom().DungeonFlagChest, setter: (v) => minimap.GetRoom().DungeonFlagChest = v), new AbstractBoolValueReference(Project, name: "Boss", getter: () => minimap.GetRoom().DungeonFlagBoss, setter: (v) => minimap.GetRoom().DungeonFlagBoss = v), new AbstractBoolValueReference(Project, name: "Dark", getter: () => minimap.GetRoom().DungeonFlagDark, setter: (v) => minimap.GetRoom().DungeonFlagDark = v), }; var vrg = new ValueReferenceGroup(vrs); if (roomVre != null) { roomVre.ReplaceValueReferenceGroup(vrg); } else { roomVre = new ValueReferenceEditor(Project, vrg, 4, "Minimap Data"); roomVreContainer.Add(roomVre); } }
// Called when room index (or season) is changed void OnRoomChanged() { if (ActiveRoom == null) { return; } eventGroup.Lock(); roomSpinButton.Value = ActiveRoom.Index; warpEditor.SetMap(ActiveRoom.Index >> 8, ActiveRoom.Index & 0xff); SetTileset(ActiveRoomLayout.Tileset); if (roomVre == null) { // This only runs once roomVre = new ValueReferenceEditor(Project, ActiveRoom.ValueReferenceGroup); roomVre.AddWidgetToRight("Tileset", editTilesetButton); roomVreHolder.Add(roomVre); roomVre.ShowAll(); roomTilesetModifiedEventWrapper.Bind <ValueModifiedEventArgs>("ModifiedEvent", (sender, args) => SetTileset((sender as ValueReference).GetIntValue(), ActiveSeason)); } else { roomVre.ReplaceValueReferenceGroup(ActiveRoom.ValueReferenceGroup); } // Watch for changes to this room's tileset roomTilesetModifiedEventWrapper.ReplaceEventSource(ActiveRoom.ValueReferenceGroup["Tileset"]); // Watch for changes to the chest UpdateChestData(); eventGroup.Unlock(); UpdateLayoutGroupWarning(); }
public override void Clicked() { Box tmpBox, tmpBox2; Alignment tmpAlign; Box vbox = new Gtk.VBox(); vbox.Spacing = 3; Box hbox = new Gtk.HBox(); hbox.Spacing = 3; Box dungeonVreContainer = new Gtk.VBox(); Box roomVreContainer = new Gtk.VBox(); ValueReferenceEditor dungeonVre = null; ValueReferenceEditor roomVre = null; Alignment frame = new Alignment(0, 0, 0, 0); var dungeonSpinButton = new SpinButton(0, 15, 1); var floorSpinButton = new SpinButton(0, 15, 1); var roomSpinButton = new SpinButtonHexadecimal(0, 255, 1); roomSpinButton.Digits = 2; Minimap minimap = null; System.Action RoomChanged = () => { Dungeon dungeon = minimap.Map as Dungeon; Room room = minimap.GetRoom(); roomSpinButton.Value = room.Index & 0xff; var vrs = new List <ValueReference>(); vrs.Add(new StreamValueReference("Up", room.Index & 0xff, 0, 0, DataValueType.ByteBit)); vrs.Add(new StreamValueReference("Right", room.Index & 0xff, 1, 1, DataValueType.ByteBit)); vrs.Add(new StreamValueReference("Down", room.Index & 0xff, 2, 2, DataValueType.ByteBit)); vrs.Add(new StreamValueReference("Left", room.Index & 0xff, 3, 3, DataValueType.ByteBit)); vrs.Add(new StreamValueReference("Key", room.Index & 0xff, 4, 4, DataValueType.ByteBit)); vrs.Add(new StreamValueReference("Chest", room.Index & 0xff, 5, 5, DataValueType.ByteBit)); vrs.Add(new StreamValueReference("Boss", room.Index & 0xff, 6, 6, DataValueType.ByteBit)); vrs.Add(new StreamValueReference("Dark", room.Index & 0xff, 7, 7, DataValueType.ByteBit)); Stream stream = Project.GetBinaryFile("rooms/" + Project.GameString + "/group" + dungeon.Group + "DungeonProperties.bin"); foreach (StreamValueReference r in vrs) { r.SetStream(stream); } if (roomVre != null) { roomVreContainer.Remove(roomVre); } var vrg = new ValueReferenceGroup(vrs); roomVre = new ValueReferenceEditor(Project, vrg, 4, "Minimap Data"); roomVreContainer.Add(roomVre); }; System.Action DungeonChanged = () => { Dungeon dungeon = Project.GetIndexedDataType <Dungeon>(dungeonSpinButton.ValueAsInt); floorSpinButton.Adjustment.Upper = dungeon.NumFloors - 1; if (floorSpinButton.ValueAsInt >= dungeon.NumFloors) { floorSpinButton.Value = dungeon.NumFloors - 1; } var vrs = new List <ValueReference>(); vrs.Add(new ValueReference("Group", 0, DataValueType.String, false)); vrs.Add(new ValueReference("Wallmaster dest room", 0, DataValueType.Byte)); vrs.Add(new ValueReference("Bottom floor layout", 0, DataValueType.Byte, false)); vrs.Add(new ValueReference("# of floors", 0, DataValueType.Byte, false)); vrs.Add(new ValueReference("Base floor name", 0, DataValueType.Byte)); vrs.Add(new ValueReference("Floors unlocked with compass", 0, DataValueType.Byte)); Data data = dungeon.DataStart; foreach (ValueReference r in vrs) { r.SetData(data); data = data.NextData; } // Remove last ValueReferenceEditor if (dungeonVre != null) { dungeonVreContainer.Remove(dungeonVre); } var vrg = new ValueReferenceGroup(vrs); dungeonVre = new ValueReferenceEditor(Project, vrg, "Base Data"); dungeonVre.AddDataModifiedHandler(() => { floorSpinButton.Adjustment.Upper = dungeon.NumFloors; minimap.GenerateImage(); RoomChanged(); }); // Replace the "group" option with a custom widget for finer // control. SpinButton groupSpinButton = new SpinButton(4, 5, 1); groupSpinButton.Value = dungeon.Group; groupSpinButton.ValueChanged += (c, d) => { vrg.SetValue("Group", ">wGroup" + groupSpinButton.ValueAsInt + "Flags"); }; dungeonVre.ReplaceWidget(0, groupSpinButton); dungeonVre.ShowAll(); // Tooltips dungeonVre.SetTooltip(0, "Also known as the high byte of the room index."); dungeonVre.SetTooltip(1, "The low byte of the room index wallmasters will send you to."); dungeonVre.SetTooltip(2, "The index of the layout for the bottom floor. Subsequent floors will use subsequent indices."); dungeonVre.SetTooltip(4, "Determines what the game will call the bottom floor. For a value of:\n$00: The bottom floor is 'B3'.\n$01: The bottom floor is 'B2'.\n$02: The bottom floor is 'B1'.\n$03: The bottom floor is 'F1'."); dungeonVre.SetTooltip(5, "A bitset of floors that will appear on the map when the compass is obtained.\n\nEg. If this is $05, then floors 0 and 2 will be unlocked (bits 0 and 2 are set)."); dungeonVreContainer.Add(dungeonVre); minimap.SetMap(dungeon); minimap.Floor = floorSpinButton.ValueAsInt; RoomChanged(); }; dungeonSpinButton.ValueChanged += (a, b) => { DungeonChanged(); }; floorSpinButton.ValueChanged += (a, b) => { DungeonChanged(); }; frame.Add(vbox); tmpBox = new Gtk.HBox(); tmpBox.Add(new Gtk.Label("Dungeon ")); tmpBox.Add(dungeonSpinButton); tmpBox.Add(new Gtk.Label("Floor ")); tmpBox.Add(floorSpinButton); tmpAlign = new Alignment(0, 0, 0, 0); tmpAlign.Add(tmpBox); vbox.Add(tmpAlign); vbox.Add(hbox); // Leftmost column tmpBox = new VBox(); tmpBox.Add(dungeonVreContainer); var addFloorButton = new Button("Add Floor"); addFloorButton.Image = new Gtk.Image(Gtk.Stock.Add, Gtk.IconSize.Button); addFloorButton.Clicked += (a, b) => { Dungeon dungeon = minimap.Map as Dungeon; int newFloorIndex = dungeon.FirstLayoutIndex + dungeon.NumFloors; // Shift all subsequent layouts 64 bytes down in the data file Stream layoutFile = Project.GetBinaryFile("rooms/" + Project.GameString + "/dungeonLayouts.bin"); layoutFile.SetLength(layoutFile.Length + 64); for (int i = (int)layoutFile.Length / 64 - 1; i > newFloorIndex; i--) { var buf = new byte[64]; layoutFile.Position = (i - 1) * 64; layoutFile.Read(buf, 0, 64); layoutFile.Write(buf, 0, 64); } // Clear the new floor layoutFile.Position = newFloorIndex * 64; for (int j = 0; j < 64; j++) { layoutFile.WriteByte(0); } // Shift each dungeon's "FirstLayoutIndex" to match the shifted layouts. for (int i = 0; i < Project.GetNumDungeons(); i++) { Dungeon d2 = Project.GetIndexedDataType <Dungeon>(i); if (d2.FirstLayoutIndex >= newFloorIndex) { d2.FirstLayoutIndex++; } } dungeon.NumFloors = dungeon.NumFloors + 1; floorSpinButton.Value = dungeon.NumFloors - 1; DungeonChanged(); }; tmpAlign = new Gtk.Alignment(0.5f, 0, 0, 0); tmpAlign.Add(addFloorButton); tmpBox.Add(tmpAlign); var removeFloorButton = new Button("Remove Top Floor"); removeFloorButton.Image = new Gtk.Image(Gtk.Stock.Remove, Gtk.IconSize.Button); removeFloorButton.Clicked += (a, b) => { Dungeon dungeon = minimap.Map as Dungeon; if (dungeon.NumFloors <= 1) { return; } Gtk.MessageDialog d = new MessageDialog(null, DialogFlags.DestroyWithParent, MessageType.Warning, ButtonsType.YesNo, "Are you quite certain that you wish to delete the top floor of this dungeon?"); var response = (ResponseType)d.Run(); d.Destroy(); if (response == Gtk.ResponseType.Yes) { int deletedFloorIndex = dungeon.FirstLayoutIndex + dungeon.NumFloors - 1; // Shift all subsequent layouts 64 bytes up in the data file Stream layoutFile = Project.GetBinaryFile("rooms/" + Project.GameString + "/dungeonLayouts.bin"); for (int i = deletedFloorIndex; i < layoutFile.Length / 64 - 1; i++) { var buf = new byte[64]; layoutFile.Position = (i + 1) * 64; layoutFile.Read(buf, 0, 64); layoutFile.Position = i * 64; layoutFile.Write(buf, 0, 64); } layoutFile.SetLength(layoutFile.Length - 64); // Shift each dungeon's "FirstLayoutIndex" to match the shifted layouts. for (int i = 0; i < Project.GetNumDungeons(); i++) { Dungeon d2 = Project.GetIndexedDataType <Dungeon>(i); if (d2.FirstLayoutIndex > deletedFloorIndex) { d2.FirstLayoutIndex--; } } dungeon.NumFloors = dungeon.NumFloors - 1; DungeonChanged(); } }; tmpAlign = new Gtk.Alignment(0.5f, 0, 0, 0); tmpAlign.Add(removeFloorButton); tmpBox.Add(tmpAlign); hbox.Add(tmpBox); // Middle column (minimap) minimap = new Minimap(); minimap.TileSelectedEvent += (sender) => { RoomChanged(); }; hbox.Add(minimap); // Rightmost column tmpAlign = new Alignment(0, 0, 0, 0); tmpAlign.Add(roomVreContainer); tmpBox2 = new HBox(); tmpBox2.Add(new Gtk.Label("Room ")); roomSpinButton.ValueChanged += (a, b) => { (minimap.Map as Dungeon).SetRoom(minimap.SelectedX, minimap.SelectedY, minimap.Floor, roomSpinButton.ValueAsInt); minimap.GenerateImage(); RoomChanged(); }; tmpBox2.Add(roomSpinButton); tmpBox = new VBox(); tmpBox.Add(tmpBox2); tmpBox.Add(tmpAlign); hbox.Add(tmpBox); Window w = new Window(null); w.Add(frame); w.ShowAll(); Map map = manager.GetActiveMap(); if (map is Dungeon) { dungeonSpinButton.Value = map.Index; } DungeonChanged(); }
public DungeonEditorImplementation(PluginManager manager) { this.manager = manager; Box tmpBox, tmpBox2; Alignment tmpAlign; Box vbox = new Gtk.VBox(); vbox.Spacing = 3; Box hbox = new Gtk.HBox(); hbox.Spacing = 3; dungeonVreContainer = new Gtk.VBox(); roomVreContainer = new Gtk.VBox(); dungeonVre = null; roomVre = null; Alignment frame = new Alignment(0, 0, 0, 0); dungeonSpinButton = new SpinButton(0, 15, 1); floorSpinButton = new SpinButton(0, 15, 1); roomSpinButton = new SpinButtonHexadecimal(0, 255, 1); roomSpinButton.Digits = 2; dungeonSpinButton.ValueChanged += (a, b) => { DungeonChanged(); }; floorSpinButton.ValueChanged += (a, b) => { DungeonChanged(); }; frame.Add(vbox); tmpBox = new Gtk.HBox(); tmpBox.Add(new Gtk.Label("Dungeon ")); tmpBox.Add(dungeonSpinButton); tmpBox.Add(new Gtk.Label("Floor ")); tmpBox.Add(floorSpinButton); tmpAlign = new Alignment(0, 0, 0, 0); tmpAlign.Add(tmpBox); vbox.Add(tmpAlign); vbox.Add(hbox); // Leftmost column tmpBox = new VBox(); tmpBox.Add(dungeonVreContainer); var addFloorAboveButton = new Button("Add Floor Above"); addFloorAboveButton.Image = new Gtk.Image(Gtk.Stock.Add, Gtk.IconSize.Button); addFloorAboveButton.Clicked += (a, b) => { int floorIndex = floorSpinButton.ValueAsInt + 1; (minimap.Map as Dungeon).InsertFloor(floorIndex); DungeonChanged(); floorSpinButton.Value = floorIndex; }; tmpAlign = new Gtk.Alignment(0.5f, 0, 0, 0); tmpAlign.Add(addFloorAboveButton); tmpBox.Add(tmpAlign); var addFloorBelowButton = new Button("Add Floor Below"); addFloorBelowButton.Image = new Gtk.Image(Gtk.Stock.Add, Gtk.IconSize.Button); addFloorBelowButton.Clicked += (a, b) => { int floorIndex = floorSpinButton.ValueAsInt; (minimap.Map as Dungeon).InsertFloor(floorIndex); DungeonChanged(); }; tmpAlign = new Gtk.Alignment(0.5f, 0, 0, 0); tmpAlign.Add(addFloorBelowButton); tmpBox.Add(tmpAlign); var removeFloorButton = new Button("Remove Floor"); removeFloorButton.Image = new Gtk.Image(Gtk.Stock.Remove, Gtk.IconSize.Button); removeFloorButton.Clicked += (a, b) => { Dungeon dungeon = minimap.Map as Dungeon; if (dungeon.NumFloors <= 1) { return; } Gtk.MessageDialog d = new MessageDialog(null, DialogFlags.DestroyWithParent, MessageType.Warning, ButtonsType.YesNo, "Really delete this floor?"); var response = (ResponseType)d.Run(); d.Dispose(); if (response == Gtk.ResponseType.Yes) { dungeon.RemoveFloor(floorSpinButton.ValueAsInt); DungeonChanged(); } }; tmpAlign = new Gtk.Alignment(0.5f, 0, 0, 0); tmpAlign.Add(removeFloorButton); tmpBox.Add(tmpAlign); hbox.Add(tmpBox); // Middle column (minimap) minimap = new Minimap(); minimap.AddTileSelectedHandler((sender, index) => { RoomChanged(); }); hbox.Add(minimap); // Rightmost column tmpAlign = new Alignment(0, 0, 0, 0); tmpAlign.Add(roomVreContainer); tmpBox2 = new HBox(); tmpBox2.Add(new Gtk.Label("Room ")); roomSpinButton.ValueChanged += (a, b) => { (minimap.Map as Dungeon).SetRoom(minimap.SelectedX, minimap.SelectedY, minimap.Floor, roomSpinButton.ValueAsInt); }; tmpBox2.Add(roomSpinButton); tmpBox = new VBox(); tmpBox.Add(tmpBox2); tmpBox.Add(tmpAlign); hbox.Add(tmpBox); Map map = manager.GetActiveMap(); if (map is Dungeon) { dungeonSpinButton.Value = (map as Dungeon).Index; } DungeonChanged(); dungeonEventWrapper.Bind <DungeonRoomChangedEventArgs>("RoomChangedEvent", (sender, args) => RoomChanged()); vbox.Destroyed += (a, b) => dungeonEventWrapper.UnbindAll(); this.Add(frame); ShowAll(); }
public void SetRoom(int room) { indexSpinButton.Value = room; vrContainer.Remove(vrEditor); vrEditor = null; v1 = null; v2 = null; v3 = null; v4 = null; Data data = Chest.GetChestData(room); if (data == null) { VBox vbox = new VBox(); Button addButton = new Button("Add"); addButton.Clicked += (a, b) => { Chest.AddChestData(RoomIndex); SetRoom(RoomIndex); }; addButton.Label = "gtk-add"; addButton.UseStock = true; var l = new Gtk.Label("No chest data\nexists for this room."); vbox.Add(l); var btnAlign = new Alignment(0.5f, 0.5f, 0.0f, 0.2f); btnAlign.TopPadding = 3; btnAlign.Add(addButton); vbox.Add(btnAlign); vrEditor = vbox; } else { v1 = new ValueReference("YX", 0, DataValueType.Byte); v1.SetData(data); data = data.NextData; v2 = new ValueReference("Room", 0, DataValueType.Byte, false); v2.SetData(data); data = data.NextData; v3 = new ValueReference("ID1", 0, DataValueType.Byte); v3.SetData(data); data = data.NextData; v4 = new ValueReference("ID2", 0, DataValueType.Byte); v4.SetData(data); data = data.NextData; ValueReferenceGroup vrGroup = new ValueReferenceGroup(new ValueReference[] { v1, v2, v3, v4 }); var vr = new ValueReferenceEditor( Project, vrGroup, "Data"); vr.SetMaxBound(0, 0xfe); // Max bound for YX vr.AddDataModifiedHandler(() => { if (ChestChangedEvent != null) { ChestChangedEvent(); } }); VBox vbox = new VBox(); vbox.Add(vr); Button delButton = new Button("Remove"); delButton.Clicked += (a, b) => { Chest.DeleteChestData(RoomIndex); SetRoom(RoomIndex); }; delButton.Label = "gtk-delete"; delButton.UseStock = true; Alignment btnAlign = new Alignment(0.5f, 0.5f, 0.0f, 0.2f); btnAlign.TopPadding = 3; btnAlign.Add(delButton); vbox.Add(btnAlign); vrEditor = vbox; } if (ChestChangedEvent != null) { ChestChangedEvent(); } vrContainer.Add(vrEditor); vrContainer.ShowAll(); }
public void SetTreasure(int index) { int hIndex = index >> 8; int lIndex = index & 0xff; int hMax = Treasure.GetNumHighIndices(); if (hIndex >= hMax) { hIndex = hMax - 1; } int lMax = Treasure.GetNumLowIndices(hIndex); if (lIndex >= lMax) { lIndex = lMax - 1; } highIndexButton.Adjustment.Upper = hMax - 1; lowIndexButton.Adjustment.Upper = lMax - 1; highIndexButton.Value = hIndex; lowIndexButton.Value = lIndex; index = hIndex << 8 | lIndex; vrContainer.Remove(vrEditor); Data data = Treasure.GetTreasureDataBase(index); ValueReference v1 = new ValueReference("Spawn Mode", 0, 4, 6, DataValueType.ByteBits); v1.SetData(data); ValueReference v5 = new ValueReference("Grab Mode", 0, 0, 2, DataValueType.ByteBits); v5.SetData(data); ValueReference v6 = new ValueReference("Unknown", 0, 3, 3, DataValueType.ByteBit); v6.SetData(data); data = data.NextData; ValueReference v2 = new ValueReference("Parameter", 0, DataValueType.Byte); v2.SetData(data); data = data.NextData; ValueReference v3 = new ValueReference("Text ID", 0, DataValueType.Byte); v3.SetData(data); data = data.NextData; ValueReference v4 = new ValueReference("Gfx", 0, DataValueType.Byte); v4.SetData(data); data = data.NextData; // Byte 1 is sometimes set to 0x80 for unused treasures? v1.SetValue(v1.GetIntValue() & 0x7f); ValueReferenceGroup vrGroup = new ValueReferenceGroup(new ValueReference[] { v1, v5, v6, v2, v3, v4 }); var vr = new ValueReferenceEditor( Project, vrGroup, "Data"); vr.SetMaxBound(0, 0x7f); // Max bound for Spawn Mode vr.AddDataModifiedHandler(() => { if (TreasureChangedEvent != null) { TreasureChangedEvent(); } }); vrEditor = vr; vrContainer.Add(vrEditor); if (TreasureChangedEvent != null) { TreasureChangedEvent(); } }
void UpdateChestData() { Chest chest = ActiveRoom.Chest; if (chest != null) { ValueReferenceGroup vrg = ActiveRoom.Chest.ValueReferenceGroup; if (chestVre == null) { chestVre = new ValueReferenceEditor(Project, vrg); chestVreHolder.Add(chestVre); } else { chestVre.ReplaceValueReferenceGroup(vrg); } TreasureObject treasure = chest.Treasure; if (treasure == null) { nonExistentTreasureHolder.ShowAll(); treasureVreHolder.Hide(); if (chest.TreasureID >= Project.NumTreasures) { treasureDataFrame.Hide(); } else { treasureDataFrame.Show(); } } else { nonExistentTreasureHolder.Hide(); treasureDataFrame.Show(); treasureVreHolder.Show(); if (treasureVre == null) { treasureVre = new ValueReferenceEditor(Project, treasure.ValueReferenceGroup); treasureVreHolder.Add(treasureVre); } else { treasureVre.ReplaceValueReferenceGroup(treasure.ValueReferenceGroup); } } treasureDataLabel.Text = string.Format("Treasure ${0:X2} Subid ${1:X2} Data", vrg.GetIntValue("ID"), vrg.GetIntValue("SubID")); } if (chest == null) { chestEditorBox.Hide(); treasureDataFrame.Hide(); chestAddHolder.ShowAll(); } else { chestEditorBox.ShowAll(); chestAddHolder.Hide(); } chestEventWrapper.ReplaceEventSource(chest); }