From ba6138a450017ab9a2647d6e05261ae75a039dd7 Mon Sep 17 00:00:00 2001 From: Jason Lautzenheiser Date: Sun, 31 May 2015 20:10:36 -0400 Subject: [PATCH] Automapper now handles rooms with parenthesis a little better. --- Automap.cs | 24 +- Canvas.Automap.cs | 926 +++++++++++++++++++------------------ DisambiguateRoomsDialog.cs | 4 +- IAutomapCanvas.cs | 4 +- Revisions.txt | 5 +- 5 files changed, 489 insertions(+), 474 deletions(-) diff --git a/Automap.cs b/Automap.cs index 02250647..d0bf11c6 100644 --- a/Automap.cs +++ b/Automap.cs @@ -127,12 +127,12 @@ private bool ExtractRoomName(string line, string previousLine, out string name) return false; } - if (!char.IsLetterOrDigit(line[line.Length - 1])) - { - // the last character of the room name must be a number or a letter - SetFailureReason("the line didn't end with a letter or a number"); - return false; - } +// if (!char.IsLetterOrDigit(line[line.Length - 1])) +// { +// // the last character of the room name must be a number or a letter +// SetFailureReason("the line didn't end with a letter or a number"); +// return false; +// } // strip suffixes such as those in "Bedroom, on the bed" or "Bedroom (on the bed)" or "Bedroom - on the bed" bool strippedSuffix; @@ -141,7 +141,7 @@ private bool ExtractRoomName(string line, string previousLine, out string name) strippedSuffix = false; foreach (var decorativeSuffixMarker in s_roomDecorativeSuffixMarkers) { - var indexOfMarker = line.IndexOf(decorativeSuffixMarker); + var indexOfMarker = line.IndexOf(decorativeSuffixMarker, StringComparison.Ordinal); if (indexOfMarker >= 0) { var suffixLength = line.Length - indexOfMarker; @@ -248,7 +248,7 @@ private bool IsRoomDescriptionWord(string word) SetFailureReason("the word contains no text"); return false; } - if (!char.IsLetterOrDigit(word[0])) + if (!char.IsLetterOrDigit(word[0]) && word[0] != '#') { // the first character must be a letter or a digit SetFailureReason("the word must begin with a letter or a digit"); @@ -325,9 +325,9 @@ private bool ExtractParagraph(List lines, int lineIndex, out string para return paragraph != null; } - private Room FindRoom(string roomName, string roomDescription) + private Room FindRoom(string roomName, string roomDescription, string line) { - return m_canvas.FindRoom(roomName, roomDescription, delegate(string n, string d, Room r) { return Match(r, n, d); }); + return m_canvas.FindRoom(roomName, roomDescription, line, (n, d, r) => Match(r, n, d)); } private bool? Match(Room room, string name, string description) @@ -433,7 +433,7 @@ private async Task ProcessTranscriptText(List lines) ExtractParagraph(lines, index + 1, out roomDescription); // work out which room the transcript is referring to here, asking them if necessary - var room = FindRoom(roomName, roomDescription); + var room = FindRoom(roomName, roomDescription, line); if (room == null) { // new room @@ -441,7 +441,7 @@ private async Task ProcessTranscriptText(List lines) { // player moved to new room // if not added already, add room to map; and join it up to the previous one - room = m_canvas.CreateRoom(m_lastKnownRoom, m_lastMoveDirection.Value, roomName); + room = m_canvas.CreateRoom(m_lastKnownRoom, m_lastMoveDirection.Value, roomName, line); m_canvas.Connect(m_lastKnownRoom, m_lastMoveDirection.Value, room); Trace("{0}: {1} is now {2} from {3}.", FormatTranscriptLineForDisplay(line), roomName, m_lastMoveDirection.Value.ToString().ToLower(), m_lastKnownRoom.Name); } diff --git a/Canvas.Automap.cs b/Canvas.Automap.cs index 0433f117..4a50f7f1 100644 --- a/Canvas.Automap.cs +++ b/Canvas.Automap.cs @@ -23,526 +23,540 @@ THE SOFTWARE. */ using System; -using System.ComponentModel; -using System.Windows.Forms; -using System.Diagnostics; using System.Collections.Generic; +using System.Diagnostics; +using System.Windows.Forms; namespace Trizbort { - partial class Canvas + partial class Canvas + { + private readonly Automap m_automap = Automap.Instance; + private readonly MultithreadedAutomapCanvas m_threadSafeAutomapCanvas; + private bool m_dontAskAboutAmbiguities; + + public bool IsAutomapping + { + get { return m_automap.Running; } + } + + public string AutomappingStatus + { + get { return m_automap.Status; } + } + + Room IAutomapCanvas.FindRoom(string roomName, string roomDescription, string line, RoomMatcher matcher) { - public bool IsAutomapping + var list = new List(); + foreach (var element in Project.Current.Elements) + { + if (element is Room) { - get { return m_automap.Running; } + var room = (Room) element; + var matches = matcher(roomName, roomDescription, room); + if (matches.HasValue && matches.Value) + { + // it's definitely this room + return room; + } + if (!matches.HasValue) + { + // it's ambiguous + list.Add(room); + } } - - public void StartAutomapping(AutomapSettings settings) + } + + if (list.Count == 0) + { + return null; + } + if (m_dontAskAboutAmbiguities) + { + // the user has long given up on this process; + // use the first ambiguous room in the list. + return list[0]; + } + if ((string.IsNullOrEmpty(roomDescription) || !list[0].HasDescription) && list.Count == 1) + { + // technically it's ambiguous, but we don't two descriptions for the user to compare; + // there's only one option, so use it. They probably didn't have VERBOSE on for the whole transcript. + return list[0]; + } + + using (var dialog = new DisambiguateRoomsDialog()) + { + dialog.SetTranscriptContext(roomName, roomDescription, line); + dialog.AddAmbiguousRooms(list); + dialog.ShowDialog(); + if (dialog.UserDoesntCareAnyMore) { - StopAutomapping(); - - m_automap.Start(m_threadSafeAutomapCanvas, settings); - m_dontAskAboutAmbiguities = false; + // The user has given up on this process! Can't say I blame them. + // Use the first ambiguous room on the list, as above. + m_dontAskAboutAmbiguities = true; + return list[0]; } - public void StopAutomapping() + // Either the user picked a room, or they said "New Room" in which case we don't match, returning null. + return dialog.Disambiguation; + } + } + + Room IAutomapCanvas.CreateRoom(Room existing, string name) + { + // start by placing the room at the origin + var room = new Room(Project.Current); + room.Name = name; + + if (existing != null) + { + // if we know which room we were just in, start at that instead + room.Position = existing.Position; + } + room.Position = Settings.Snap(room.Position); + + // while we can't place the room, try to the left, then the right, + // expanding our distance as we go, until we find a blank space. + var tryOtherSideNext = false; + var tryLeft = true; + var distance = 0; + var initialPosition = room.Position; + while (AnyRoomsIntersect(room)) + { + if (tryOtherSideNext) { - m_automap.Stop(); + tryLeft = !tryLeft; + tryOtherSideNext = false; } - - public string AutomappingStatus + else { - get - { return m_automap.Status; } + tryOtherSideNext = true; + ++distance; } - - Room IAutomapCanvas.FindRoom(string roomName, string roomDescription, RoomMatcher matcher) + if (tryLeft) { - var list = new List(); - foreach (var element in Project.Current.Elements) - { - if (element is Room) - { - var room = (Room)element; - var matches = matcher(roomName, roomDescription, room); - if (matches.HasValue && matches.Value) - { - // it's definitely this room - return room; - } - else if (!matches.HasValue) - { - // it's ambiguous - list.Add(room); - } - } - - } - - if (list.Count == 0) - { - return null; - } - if (m_dontAskAboutAmbiguities) - { - // the user has long given up on this process; - // use the first ambiguous room in the list. - return list[0]; - } - if ((string.IsNullOrEmpty(roomDescription) || !list[0].HasDescription) && list.Count == 1) - { - // technically it's ambiguous, but we don't two descriptions for the user to compare; - // there's only one option, so use it. They probably didn't have VERBOSE on for the whole transcript. - return list[0]; - } - - using (var dialog = new DisambiguateRoomsDialog()) - { - dialog.SetTranscriptContext(roomName, roomDescription); - dialog.AddAmbiguousRooms(list); - dialog.ShowDialog(); - if (dialog.UserDoesntCareAnyMore) - { - // The user has given up on this process! Can't say I blame them. - // Use the first ambiguous room on the list, as above. - m_dontAskAboutAmbiguities = true; - return list[0]; - } - - // Either the user picked a room, or they said "New Room" in which case we don't match, returning null. - return dialog.Disambiguation; - } + room.Position = Settings.Snap(new Vector(initialPosition.X - distance*(Settings.PreferredDistanceBetweenRooms + room.Width), room.Position.Y)); } - - Room IAutomapCanvas.CreateRoom(Room existing, string name) + else { - // start by placing the room at the origin - var room = new Room(Project.Current); - room.Name = name; - - if (existing != null) - { - // if we know which room we were just in, start at that instead - room.Position = existing.Position; - } - room.Position = Settings.Snap(room.Position); - - // while we can't place the room, try to the left, then the right, - // expanding our distance as we go, until we find a blank space. - bool tryOtherSideNext = false; - bool tryLeft = true; - int distance = 0; - var initialPosition = room.Position; - while (AnyRoomsIntersect(room)) - { - if (tryOtherSideNext) - { - tryLeft = !tryLeft; - tryOtherSideNext = false; - } - else - { - tryOtherSideNext = true; - ++distance; - } - if (tryLeft) - { - room.Position = Settings.Snap(new Vector(initialPosition.X - distance * (Settings.PreferredDistanceBetweenRooms + room.Width), room.Position.Y)); - } - else - { - room.Position = Settings.Snap(new Vector(initialPosition.X + distance * (Settings.PreferredDistanceBetweenRooms + room.Width), room.Position.Y)); - } - - Debug.WriteLine(string.Format("Try again, more to the {0}.", tryLeft ? "left" : "right")); - } - - // after we set the position, set this flag, - // since setting the position clears this flag if set. - room.ArbitraryAutomappedPosition = true; - - Project.Current.Elements.Add(room); - return room; + room.Position = Settings.Snap(new Vector(initialPosition.X + distance*(Settings.PreferredDistanceBetweenRooms + room.Width), room.Position.Y)); } - Room IAutomapCanvas.CreateRoom(Room existing, AutomapDirection directionFromExisting, string name) - { - if (!Project.Current.Elements.Contains(existing)) - { - // avoid issues if the user has just deleted the existing room - return null; - } + Debug.WriteLine(string.Format("Try again, more to the {0}.", tryLeft ? "left" : "right")); + } - var room = new Room(Project.Current); - room.Name = name; + // after we set the position, set this flag, + // since setting the position clears this flag if set. + room.ArbitraryAutomappedPosition = true; - Vector delta; - PositionRelativeTo(room, existing, CompassPointHelper.GetCompassDirection(directionFromExisting), out delta); + Project.Current.Elements.Add(room); + return room; + } - if (AnyRoomsIntersect(room)) - { - ShiftMap(room.InnerBounds, delta); - Debug.WriteLine("Shift map."); - } + Room IAutomapCanvas.CreateRoom(Room existing, AutomapDirection directionFromExisting, string roomName, string line) + { + if (!Project.Current.Elements.Contains(existing)) + { + // avoid issues if the user has just deleted the existing room + return null; + } + + var room = new Room(Project.Current) {Name = roomName}; + if (line != roomName) + { + room.SubTitle = line.Replace(roomName, ""); + } + + Vector delta; + PositionRelativeTo(room, existing, CompassPointHelper.GetCompassDirection(directionFromExisting), out delta); + + if (AnyRoomsIntersect(room)) + { + ShiftMap(room.InnerBounds, delta); + Debug.WriteLine("Shift map."); + } + + Project.Current.Elements.Add(room); + + return room; + } - Project.Current.Elements.Add(room); + void IAutomapCanvas.AddExitStub(Room room, AutomapDirection direction) + { + if (!Project.Current.Elements.Contains(room)) + { + // avoid issues if the user has just deleted one of these rooms + return; + } + + var sourceCompassPoint = CompassPointHelper.GetCompassDirection(direction); + var connection = addConnection(room, sourceCompassPoint, room, sourceCompassPoint); + switch (direction) + { + case AutomapDirection.Up: + connection.StartText = Connection.Up; + break; + case AutomapDirection.Down: + connection.StartText = Connection.Down; + break; + } + } - return room; + void IAutomapCanvas.RemoveExitStub(Room room, AutomapDirection direction) + { + if (!Project.Current.Elements.Contains(room)) + { + // avoid issues if the user has just deleted one of these rooms + return; + } + + var compassPoint = CompassPointHelper.GetCompassDirection(direction); + foreach (var connection in room.GetConnections(compassPoint)) + { + CompassPoint sourceCompassPoint, targetCompassPoint; + var source = connection.GetSourceRoom(out sourceCompassPoint); + var target = connection.GetTargetRoom(out targetCompassPoint); + if (source == room && target == room && sourceCompassPoint == compassPoint && targetCompassPoint == compassPoint) + { + Project.Current.Elements.Remove(connection); } + } + } - private bool AnyRoomsIntersect(Room room) - { - var bounds = room.InnerBounds; - foreach (var element in Project.Current.Elements) + void IAutomapCanvas.Connect(Room source, AutomapDirection directionFromSource, Room target) + { + if (!Project.Current.Elements.Contains(source) || !Project.Current.Elements.Contains(target)) + { + // avoid issues if the user has just deleted one of these rooms + return; + } + + // work out the correct compass point to use for the given direction + + // look for existing connections: + // if the given direction is up/down/in/out, any existing connection will suffice; + // otherwise, only match an existing connection if it's pretty close to the one we want. + var sourceCompassPoint = CompassPointHelper.GetCompassDirection(directionFromSource); + CompassPoint? acceptableSourceCompassPoint; + switch (directionFromSource) + { + case AutomapDirection.Up: + case AutomapDirection.Down: + case AutomapDirection.In: + case AutomapDirection.Out: + acceptableSourceCompassPoint = null; // any existing connection will do + break; + default: + acceptableSourceCompassPoint = sourceCompassPoint; + break; + } + bool wrongWay; + var connection = FindConnection(source, target, acceptableSourceCompassPoint, out wrongWay); + + if (connection == null) + { + // there is no suitable connection between these rooms: + var targetCompassPoint = CompassPointHelper.GetAutomapOpposite(sourceCompassPoint); + + // check whether we can move one of the rooms to make the connection tidier; + // we won't need this very often, but it can be useful especially if the user teleports into a room + // and then steps out into an existing one (this can appear to happen if the user moves into a + // dark room, turns on the light, then leaves). + TryMoveRoomsForTidyConnection(source, sourceCompassPoint, target, targetCompassPoint); + + // add a new connection + connection = addConnection(source, sourceCompassPoint, target, targetCompassPoint); + connection.Style = ConnectionStyle.Solid; + connection.Flow = ConnectionFlow.OneWay; + } + else if (wrongWay) + { + // there is a suitable connection between these rooms, but it goes the wrong way; + // make it bidirectional since we can now go both ways. + connection.Flow = ConnectionFlow.TwoWay; + } + + // if this is an up/down/in/out connection, mark it as such; + // but don't override any existing text. + switch (directionFromSource) + { + case AutomapDirection.Up: + case AutomapDirection.Down: + case AutomapDirection.In: + case AutomapDirection.Out: + if (string.IsNullOrEmpty(connection.StartText) && string.IsNullOrEmpty(connection.EndText)) + { + switch (directionFromSource) { - if (element is Room && element != room && element.Intersects(bounds)) - { - Debug.WriteLine(string.Format("{0} is blocking {1}.", (element as Room).Name, room.Name)); - return true; - } - } - return false; - } + case AutomapDirection.Up: + connection.SetText(wrongWay ? ConnectionLabel.Down : ConnectionLabel.Up); + break; + case AutomapDirection.Down: + connection.SetText(wrongWay ? ConnectionLabel.Up : ConnectionLabel.Down); + break; + case AutomapDirection.In: + connection.SetText(wrongWay ? ConnectionLabel.Out : ConnectionLabel.In); + break; + case AutomapDirection.Out: + connection.SetText(wrongWay ? ConnectionLabel.In : ConnectionLabel.Out); + break; + } + } + break; + } + } - void PositionRelativeTo(Room room, Room existing, CompassPoint existingCompassPoint, out Vector delta) - { - delta = CompassPointHelper.GetAutomapDirectionVector(existingCompassPoint); - delta.X *= Settings.PreferredDistanceBetweenRooms + room.Width; - delta.Y *= Settings.PreferredDistanceBetweenRooms + room.Height; + void IAutomapCanvas.SelectRoom(Room room) + { + if (!Project.Current.Elements.Contains(room)) + { + // avoid issues if the user has just deleted this room + return; + } + + SelectedElement = room; + if (room != null) + { + EnsureVisible(room); + } + } - var newRoomCenter = existing.InnerBounds.Center + delta; - room.Position = Settings.Snap(new Vector(newRoomCenter.X - room.Width / 2, newRoomCenter.Y - room.Height / 2)); - } + public void StartAutomapping(AutomapSettings settings) + { + StopAutomapping(); - void ShiftMap(Rect deltaOrigin, Vector delta) - { - // move all elements to the left/right of the origin left/right by the given delta - foreach (var element in Project.Current.Elements) - { - if (element is Room) - { - var room = (Room)element; - var bounds = room.InnerBounds; - if (delta.X < 0) - { - if (bounds.Center.X < deltaOrigin.Right) - { - room.Position = new Vector(room.Position.X + delta.X, room.Position.Y); - } - } - else if (delta.X > 0) - { - if (bounds.Center.X > deltaOrigin.Left) - { - room.Position = new Vector(room.Position.X + delta.X, room.Position.Y); - } - } - } - } + m_automap.Start(m_threadSafeAutomapCanvas, settings); + m_dontAskAboutAmbiguities = false; + } - // move all elements above/below the origin up/down by the given delta - foreach (var element in Project.Current.Elements) - { - if (element is Room) - { - var room = (Room)element; - var bounds = room.InnerBounds; - if (delta.Y < 0) - { - if (bounds.Center.Y < deltaOrigin.Bottom) - { - room.Position = new Vector(room.Position.X, room.Position.Y + delta.Y); - } - } - else if (bounds.Center.Y > deltaOrigin.Top) - { - if (bounds.Bottom > deltaOrigin.Y) - { - room.Position = new Vector(room.Position.X, room.Position.Y + delta.Y); - } - } - } - } - } + public void StopAutomapping() + { + m_automap.Stop(); + } - /// - /// Approximately match two directions, allowing for aesthetic rearrangement by the user. - /// - /// - /// Two compass points match if they are on the same side of a box representing the room. - /// - bool ApproximateDirectionMatch(CompassPoint one, CompassPoint two) + private bool AnyRoomsIntersect(Room room) + { + var bounds = room.InnerBounds; + foreach (var element in Project.Current.Elements) + { + if (element is Room && element != room && element.Intersects(bounds)) { - return CompassPointHelper.GetAutomapDirectionVector(one) == CompassPointHelper.GetAutomapDirectionVector(two); - } - - Connection FindConnection(Room source, Room target, CompassPoint? directionFromSource, out bool wrongWay) - { - foreach (var element in Project.Current.Elements) - { - if (element is Connection) - { - var connection = (Connection)element; - CompassPoint fromDirection, toDirection; - var fromRoom = connection.GetSourceRoom(out fromDirection); - var toRoom = connection.GetTargetRoom(out toDirection); - if (fromRoom == source && toRoom == target && (directionFromSource == null || ApproximateDirectionMatch(directionFromSource.Value, fromDirection))) - { - // the two rooms are connected already in the given direction, A to B or both ways. - wrongWay = false; - return connection; - } - if (fromRoom == target && toRoom == source && (directionFromSource == null || ApproximateDirectionMatch(directionFromSource.Value, toDirection))) - { - // the two rooms are connected already in the given direction, B to A or both ways. - wrongWay = connection.Flow == ConnectionFlow.OneWay; - return connection; - } - } - } - wrongWay = false; - return null; + Debug.WriteLine("{0} is blocking {1}.", (element as Room).Name, room.Name); + return true; } + } + return false; + } - void IAutomapCanvas.AddExitStub(Room room, AutomapDirection direction) - { - if (!Project.Current.Elements.Contains(room)) - { - // avoid issues if the user has just deleted one of these rooms - return; - } + private void PositionRelativeTo(Room room, Room existing, CompassPoint existingCompassPoint, out Vector delta) + { + delta = CompassPointHelper.GetAutomapDirectionVector(existingCompassPoint); + delta.X *= Settings.PreferredDistanceBetweenRooms + room.Width; + delta.Y *= Settings.PreferredDistanceBetweenRooms + room.Height; - var sourceCompassPoint = CompassPointHelper.GetCompassDirection(direction); - var connection = addConnection(room, sourceCompassPoint, room, sourceCompassPoint); - switch (direction) - { - case AutomapDirection.Up: - connection.StartText = Connection.Up; - break; - case AutomapDirection.Down: - connection.StartText = Connection.Down; - break; - } - } + var newRoomCenter = existing.InnerBounds.Center + delta; + room.Position = Settings.Snap(new Vector(newRoomCenter.X - room.Width/2, newRoomCenter.Y - room.Height/2)); + } - void IAutomapCanvas.RemoveExitStub(Room room, AutomapDirection direction) + private void ShiftMap(Rect deltaOrigin, Vector delta) + { + // move all elements to the left/right of the origin left/right by the given delta + foreach (var element in Project.Current.Elements) + { + if (element is Room) { - if (!Project.Current.Elements.Contains(room)) + var room = (Room) element; + var bounds = room.InnerBounds; + if (delta.X < 0) + { + if (bounds.Center.X < deltaOrigin.Right) { - // avoid issues if the user has just deleted one of these rooms - return; + room.Position = new Vector(room.Position.X + delta.X, room.Position.Y); } - - var compassPoint = CompassPointHelper.GetCompassDirection(direction); - foreach (var connection in room.GetConnections(compassPoint)) + } + else if (delta.X > 0) + { + if (bounds.Center.X > deltaOrigin.Left) { - CompassPoint sourceCompassPoint, targetCompassPoint; - var source = connection.GetSourceRoom(out sourceCompassPoint); - var target = connection.GetTargetRoom(out targetCompassPoint); - if (source == room && target == room && sourceCompassPoint == compassPoint && targetCompassPoint == compassPoint) - { - Project.Current.Elements.Remove(connection); - } + room.Position = new Vector(room.Position.X + delta.X, room.Position.Y); } + } } + } - void IAutomapCanvas.Connect(Room source, AutomapDirection directionFromSource, Room target) + // move all elements above/below the origin up/down by the given delta + foreach (var element in Project.Current.Elements) + { + if (element is Room) { - if (!Project.Current.Elements.Contains(source) || !Project.Current.Elements.Contains(target)) - { - // avoid issues if the user has just deleted one of these rooms - return; - } - - // work out the correct compass point to use for the given direction - - // look for existing connections: - // if the given direction is up/down/in/out, any existing connection will suffice; - // otherwise, only match an existing connection if it's pretty close to the one we want. - var sourceCompassPoint = CompassPointHelper.GetCompassDirection(directionFromSource); - CompassPoint? acceptableSourceCompassPoint; - switch (directionFromSource) - { - case AutomapDirection.Up: - case AutomapDirection.Down: - case AutomapDirection.In: - case AutomapDirection.Out: - acceptableSourceCompassPoint = null; // any existing connection will do - break; - default: - acceptableSourceCompassPoint = sourceCompassPoint; - break; - } - bool wrongWay; - var connection = FindConnection(source, target, acceptableSourceCompassPoint, out wrongWay); - - if (connection == null) + var room = (Room) element; + var bounds = room.InnerBounds; + if (delta.Y < 0) + { + if (bounds.Center.Y < deltaOrigin.Bottom) { - // there is no suitable connection between these rooms: - var targetCompassPoint = CompassPointHelper.GetAutomapOpposite(sourceCompassPoint); - - // check whether we can move one of the rooms to make the connection tidier; - // we won't need this very often, but it can be useful especially if the user teleports into a room - // and then steps out into an existing one (this can appear to happen if the user moves into a - // dark room, turns on the light, then leaves). - TryMoveRoomsForTidyConnection(source, sourceCompassPoint, target, targetCompassPoint); - - // add a new connection - connection = addConnection(source, sourceCompassPoint, target, targetCompassPoint); - connection.Style = ConnectionStyle.Solid; - connection.Flow = ConnectionFlow.OneWay; + room.Position = new Vector(room.Position.X, room.Position.Y + delta.Y); } - else if (wrongWay) + } + else if (bounds.Center.Y > deltaOrigin.Top) + { + if (bounds.Bottom > deltaOrigin.Y) { - // there is a suitable connection between these rooms, but it goes the wrong way; - // make it bidirectional since we can now go both ways. - connection.Flow = ConnectionFlow.TwoWay; - } - - // if this is an up/down/in/out connection, mark it as such; - // but don't override any existing text. - switch (directionFromSource) - { - case AutomapDirection.Up: - case AutomapDirection.Down: - case AutomapDirection.In: - case AutomapDirection.Out: - if (string.IsNullOrEmpty(connection.StartText) && string.IsNullOrEmpty(connection.EndText)) - { - switch (directionFromSource) - { - case AutomapDirection.Up: - connection.SetText(wrongWay ? ConnectionLabel.Down : ConnectionLabel.Up); - break; - case AutomapDirection.Down: - connection.SetText(wrongWay ? ConnectionLabel.Up : ConnectionLabel.Down); - break; - case AutomapDirection.In: - connection.SetText(wrongWay ? ConnectionLabel.Out : ConnectionLabel.In); - break; - case AutomapDirection.Out: - connection.SetText(wrongWay ? ConnectionLabel.In : ConnectionLabel.Out); - break; - } - } - break; + room.Position = new Vector(room.Position.X, room.Position.Y + delta.Y); } + } } + } + } - void TryMoveRoomsForTidyConnection(Room source, CompassPoint sourceCompassPoint, Room target, CompassPoint targetCompassPoint) + /// + /// Approximately match two directions, allowing for aesthetic rearrangement by the user. + /// + /// + /// Two compass points match if they are on the same side of a box representing the room. + /// + private bool ApproximateDirectionMatch(CompassPoint one, CompassPoint two) + { + return CompassPointHelper.GetAutomapDirectionVector(one) == CompassPointHelper.GetAutomapDirectionVector(two); + } + + private Connection FindConnection(Room source, Room target, CompassPoint? directionFromSource, out bool wrongWay) + { + foreach (var element in Project.Current.Elements) + { + if (element is Connection) { - if (source.ArbitraryAutomappedPosition && !source.IsConnected) - { - if (TryMoveRoomForTidyConnection(source, targetCompassPoint, target)) - { - return; - } - } - if (target.ArbitraryAutomappedPosition && !target.IsConnected) - { - TryMoveRoomForTidyConnection(target, sourceCompassPoint, source); - } + var connection = (Connection) element; + CompassPoint fromDirection, toDirection; + var fromRoom = connection.GetSourceRoom(out fromDirection); + var toRoom = connection.GetTargetRoom(out toDirection); + if (fromRoom == source && toRoom == target && (directionFromSource == null || ApproximateDirectionMatch(directionFromSource.Value, fromDirection))) + { + // the two rooms are connected already in the given direction, A to B or both ways. + wrongWay = false; + return connection; + } + if (fromRoom == target && toRoom == source && (directionFromSource == null || ApproximateDirectionMatch(directionFromSource.Value, toDirection))) + { + // the two rooms are connected already in the given direction, B to A or both ways. + wrongWay = connection.Flow == ConnectionFlow.OneWay; + return connection; + } } + } + wrongWay = false; + return null; + } - bool TryMoveRoomForTidyConnection(Room source, CompassPoint targetCompassPoint, Room target) + private void TryMoveRoomsForTidyConnection(Room source, CompassPoint sourceCompassPoint, Room target, CompassPoint targetCompassPoint) + { + if (source.ArbitraryAutomappedPosition && !source.IsConnected) + { + if (TryMoveRoomForTidyConnection(source, targetCompassPoint, target)) { - var sourceArbitrary = source.ArbitraryAutomappedPosition; - var sourcePosition = source.Position; + return; + } + } + if (target.ArbitraryAutomappedPosition && !target.IsConnected) + { + TryMoveRoomForTidyConnection(target, sourceCompassPoint, source); + } + } - Vector delta; - PositionRelativeTo(source, target, targetCompassPoint, out delta); - if (AnyRoomsIntersect(source)) - { - // didn't work; restore previous position - source.Position = sourcePosition; - source.ArbitraryAutomappedPosition = sourceArbitrary; - return false; - } + private bool TryMoveRoomForTidyConnection(Room source, CompassPoint targetCompassPoint, Room target) + { + var sourceArbitrary = source.ArbitraryAutomappedPosition; + var sourcePosition = source.Position; + + Vector delta; + PositionRelativeTo(source, target, targetCompassPoint, out delta); + if (AnyRoomsIntersect(source)) + { + // didn't work; restore previous position + source.Position = sourcePosition; + source.ArbitraryAutomappedPosition = sourceArbitrary; + return false; + } + + // that's better + return true; + } - // that's better - return true; + /// + /// A proxy class which implements IAutomapCanvas, marshalling calls to the real canvas on the main thread. + /// + private class MultithreadedAutomapCanvas : IAutomapCanvas + { + private readonly IAutomapCanvas m_canvas; + private readonly Control m_control; + + public MultithreadedAutomapCanvas(Canvas canvas) + { + m_control = canvas; + m_canvas = canvas; + } + + public Room FindRoom(string roomName, string roomDescription, string line, RoomMatcher matcher) + { + Room room = null; + try { m_control.Invoke((MethodInvoker) delegate { room = m_canvas.FindRoom(roomName, roomDescription, line, matcher); }); } + catch (Exception) + { } - - void IAutomapCanvas.SelectRoom(Room room) + return room; + } + + public Room CreateRoom(Room existing, string name) + { + Room room = null; + try { m_control.Invoke((MethodInvoker) delegate { room = m_canvas.CreateRoom(existing, name); }); } + catch (Exception) { - if (!Project.Current.Elements.Contains(room)) - { - // avoid issues if the user has just deleted this room - return; - } - - SelectedElement = room; - if (room != null) - { - EnsureVisible(room); - } } - - /// - /// A proxy class which implements IAutomapCanvas, marshalling calls to the real canvas on the main thread. - /// - private class MultithreadedAutomapCanvas : IAutomapCanvas + return room; + } + + public Room CreateRoom(Room existing, AutomapDirection directionFromExisting, string roomName, string line) + { + Room room = null; + try { m_control.Invoke((MethodInvoker) delegate { room = m_canvas.CreateRoom(existing, directionFromExisting, roomName,line); }); } + catch (Exception) { - public MultithreadedAutomapCanvas(Canvas canvas) - { - m_control = canvas; - m_canvas = canvas; - } - - public Room FindRoom(string roomName, string roomDescription, RoomMatcher matcher) - { - Room room = null; - try { m_control.Invoke((MethodInvoker)delegate() { room = m_canvas.FindRoom(roomName, roomDescription, matcher); }); } - catch (Exception) { } - return room; - } - - public Room CreateRoom(Room existing, string name) - { - Room room = null; - try { m_control.Invoke((MethodInvoker)delegate() { room = m_canvas.CreateRoom(existing, name); }); } - catch (Exception) { } - return room; - } - - public Room CreateRoom(Room existing, AutomapDirection directionFromExisting, string name) - { - Room room = null; - try { m_control.Invoke((MethodInvoker)delegate() { room = m_canvas.CreateRoom(existing, directionFromExisting, name); }); } - catch (Exception) { } - return room; - } - - public void Connect(Room source, AutomapDirection directionFromSource, Room target) - { - try { m_control.Invoke((MethodInvoker)delegate() { m_canvas.Connect(source, directionFromSource, target); }); } - catch (Exception) { } - } - - public void AddExitStub(Room room, AutomapDirection direction) - { - try { m_control.Invoke((MethodInvoker)delegate() { m_canvas.AddExitStub(room, direction); }); } - catch (Exception) { } - } + } + return room; + } - public void RemoveExitStub(Room room, AutomapDirection direction) - { - try { m_control.Invoke((MethodInvoker)delegate() { m_canvas.RemoveExitStub(room, direction); }); } - catch (Exception) { } - } + public void Connect(Room source, AutomapDirection directionFromSource, Room target) + { + try { m_control.Invoke((MethodInvoker) delegate { m_canvas.Connect(source, directionFromSource, target); }); } + catch (Exception) + { + } + } - public void SelectRoom(Room room) - { - try { m_control.Invoke((MethodInvoker)delegate() { m_canvas.SelectRoom(room); }); } - catch (Exception) { } - } + public void AddExitStub(Room room, AutomapDirection direction) + { + try { m_control.Invoke((MethodInvoker) delegate { m_canvas.AddExitStub(room, direction); }); } + catch (Exception) + { + } + } - private Control m_control; - private IAutomapCanvas m_canvas; + public void RemoveExitStub(Room room, AutomapDirection direction) + { + try { m_control.Invoke((MethodInvoker) delegate { m_canvas.RemoveExitStub(room, direction); }); } + catch (Exception) + { } + } - private MultithreadedAutomapCanvas m_threadSafeAutomapCanvas; - private Automap m_automap = Automap.Instance; - private bool m_dontAskAboutAmbiguities = false; + public void SelectRoom(Room room) + { + try { m_control.Invoke((MethodInvoker) delegate { m_canvas.SelectRoom(room); }); } + catch (Exception) + { + } + } } -} + } +} \ No newline at end of file diff --git a/DisambiguateRoomsDialog.cs b/DisambiguateRoomsDialog.cs index d44c61f0..97f11c82 100644 --- a/DisambiguateRoomsDialog.cs +++ b/DisambiguateRoomsDialog.cs @@ -41,9 +41,9 @@ public DisambiguateRoomsDialog() m_thisRoomButton.Enabled = false; } - public void SetTranscriptContext(string roomName, string roomDescription) + public void SetTranscriptContext(string roomName, string roomDescription, string line) { - m_transcriptContextTextBox.Text = string.Format("{0}\n{1}", roomName, roomDescription).Replace("\r", string.Empty).Replace("\n", "\r\n"); + m_transcriptContextTextBox.Text = string.Format("{0}\n{1}", line, roomDescription).Replace("\r", string.Empty).Replace("\n", "\r\n"); } protected override void OnLoad(EventArgs e) diff --git a/IAutomapCanvas.cs b/IAutomapCanvas.cs index 9a3093f4..87ff9f57 100644 --- a/IAutomapCanvas.cs +++ b/IAutomapCanvas.cs @@ -33,11 +33,11 @@ internal interface IAutomapCanvas /// /// Find a room matching the given name and, if the given description isn't null, the given description. /// - Room FindRoom(string roomName, string roomDescription, RoomMatcher matcher); + Room FindRoom(string roomName, string roomDescription, string line, RoomMatcher matcher); Room CreateRoom(Room existing, string name); - Room CreateRoom(Room existing, AutomapDirection directionFromExisting, string name); + Room CreateRoom(Room existing, AutomapDirection directionFromExisting, string roomName, string line); void Connect(Room source, AutomapDirection directionFromSource, Room target); diff --git a/Revisions.txt b/Revisions.txt index c109f728..ecc1ecd4 100644 --- a/Revisions.txt +++ b/Revisions.txt @@ -4,10 +4,11 @@ Change Log ------------- ++ beginning of some map statistics. ++ swap room names with ctrl-W, swap formats/fills with shift-W, swap regions with alt-W #49 --- setting a connection to plain (P), now sets the color back to default and removes the middle text if any --- fixes broken copy/paste ++ automapper does a bit of a better job of ignoring the game title (still not 100%) +++ Automap now handles rooms with () a bit better. ++ added a Edit->Select Special with sub menu to allow for smart selection of different elements. +-- setting a connection to plain (P), now sets the color back to default and removes the middle text if any +-- copy/paste was broken 1.5.8.8 -------------