Skip to content

Commit a127fda

Browse files
committed
Make it possible to place regular overlays in a line by holding Shift
1 parent 35cf3f5 commit a127fda

File tree

3 files changed

+267
-2
lines changed

3 files changed

+267
-2
lines changed

src/TSMapEditor/Config/Translations/en/Translation_en.ini

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1465,9 +1465,11 @@ PlaceAircraftMutation.DisplayString=Place '{0}' at {1}
14651465
PlaceBridgeMutation.DisplayString=Place bridge '{0}' of direction {1} from {2} to {3}
14661466
PlaceBuildingMutation.DisplayString=Place '{0}' at {1}
14671467
PlaceCellTagMutation.DisplayString=Place CellTag for '{0}' at {1}
1468+
PlaceConnectedOverlayLineMutation.DisplayString=Place connected overlay '{0}' in a line from {1} towards {2} with length {3}
14681469
PlaceConnectedOverlayMutation.DisplayString=Place connected overlay '{0}' at {1} with a brush size of {2}
14691470
PlaceInfantryMutation.DisplayString=Place '{0}' at {1}
14701471
PlaceOverlayCollectionMutation.DisplayString=Place overlay collection {0} at {1} with a brush size of {2}
1472+
PlaceOverlayLineMutation.DisplayString=Place overlay '{0}' in a line from {1} towards {2} with length {3}
14711473
PlaceOverlayMutation.DisplayStringPlace=Place overlay '{0}' at {1} with a brush size of {2}
14721474
PlaceOverlayMutation.DisplayStringErase=Erase overlay at {0} with a brush size of {1}
14731475
PlaceSmudgeCollectionMutation.DisplayString=Place smudge collection {0} at {1} with brush size of {2}
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using TSMapEditor.GameMath;
4+
using TSMapEditor.Models;
5+
using TSMapEditor.UI;
6+
7+
namespace TSMapEditor.Mutations.Classes
8+
{
9+
/// <summary>
10+
/// A mutation that allows placing regular overlay in a line.
11+
/// </summary>
12+
class PlaceOverlayLineMutation : Mutation
13+
{
14+
public PlaceOverlayLineMutation(IMutationTarget mutationTarget, OverlayType overlayType, int? forcedFrameIndex, Point2D sourceCoords, Direction direction, int length) : base(mutationTarget)
15+
{
16+
this.overlayType = overlayType ?? throw new ArgumentNullException(nameof(overlayType));
17+
this.forcedFrameIndex = forcedFrameIndex;
18+
this.sourceCoords = sourceCoords;
19+
this.direction = direction;
20+
this.length = length;
21+
}
22+
23+
private readonly OverlayType overlayType;
24+
private readonly int? forcedFrameIndex;
25+
private readonly Point2D sourceCoords;
26+
private readonly Direction direction;
27+
private readonly int length;
28+
29+
private OriginalOverlayInfo[] undoData;
30+
31+
public override string GetDisplayString()
32+
{
33+
string directionString = Translate("Direction." + direction, Helpers.DirectionToName(direction));
34+
35+
return string.Format(Translate(this, "DisplayString",
36+
"Place overlay '{0}' in a line from {1} towards {2} with length {3}"),
37+
overlayType.GetEditorDisplayName(), sourceCoords, directionString, length);
38+
}
39+
40+
public override void Perform()
41+
{
42+
var originalOverlayInfos = new List<OriginalOverlayInfo>();
43+
Point2D step = Helpers.VisualDirectionToPoint(direction);
44+
45+
for (int i = 0; i <= length; i++)
46+
{
47+
Point2D coords = sourceCoords + step.ScaleBy(i);
48+
var tile = MutationTarget.Map.GetTile(coords);
49+
if (tile == null)
50+
continue;
51+
52+
originalOverlayInfos.Add(new OriginalOverlayInfo()
53+
{
54+
CellCoords = tile.CoordsToPoint(),
55+
OverlayTypeIndex = tile.Overlay == null ? -1 : tile.Overlay.OverlayType.Index,
56+
FrameIndex = tile.Overlay == null ? -1 : tile.Overlay.FrameIndex,
57+
});
58+
59+
tile.Overlay = new Overlay()
60+
{
61+
Position = tile.CoordsToPoint(),
62+
OverlayType = overlayType,
63+
FrameIndex = forcedFrameIndex ?? 0
64+
};
65+
}
66+
67+
if (!forcedFrameIndex.HasValue)
68+
{
69+
UpdateFrameIndexesAroundLine(step);
70+
}
71+
72+
undoData = originalOverlayInfos.ToArray();
73+
MutationTarget.AddRefreshPoint(sourceCoords, length + 2);
74+
}
75+
76+
private void UpdateFrameIndexesAroundLine(Point2D step)
77+
{
78+
var updatedCells = new HashSet<Point2D>();
79+
80+
for (int i = 0; i <= length; i++)
81+
{
82+
Point2D coords = sourceCoords + step.ScaleBy(i);
83+
84+
for (int y = -1; y <= 1; y++)
85+
{
86+
for (int x = -1; x <= 1; x++)
87+
{
88+
Point2D neighbor = coords + new Point2D(x, y);
89+
if (updatedCells.Add(neighbor))
90+
SetOverlayFrameIndexForTile(neighbor);
91+
}
92+
}
93+
}
94+
}
95+
96+
private void SetOverlayFrameIndexForTile(Point2D cellCoords)
97+
{
98+
var tile = MutationTarget.Map.GetTile(cellCoords);
99+
if (tile == null)
100+
return;
101+
102+
if (tile.Overlay == null)
103+
return;
104+
105+
tile.Overlay.FrameIndex = MutationTarget.Map.GetOverlayFrameIndex(cellCoords);
106+
}
107+
108+
public override void Undo()
109+
{
110+
foreach (OriginalOverlayInfo info in undoData)
111+
{
112+
var tile = MutationTarget.Map.GetTile(info.CellCoords);
113+
if (info.OverlayTypeIndex == -1)
114+
{
115+
tile.Overlay = null;
116+
continue;
117+
}
118+
119+
tile.Overlay = new Overlay()
120+
{
121+
OverlayType = MutationTarget.Map.Rules.OverlayTypes[info.OverlayTypeIndex],
122+
Position = info.CellCoords,
123+
FrameIndex = info.FrameIndex
124+
};
125+
}
126+
127+
if (!forcedFrameIndex.HasValue)
128+
{
129+
UpdateFrameIndexesAroundLine(Helpers.VisualDirectionToPoint(direction));
130+
}
131+
132+
MutationTarget.AddRefreshPoint(sourceCoords, length + 2);
133+
}
134+
}
135+
}

src/TSMapEditor/UI/CursorActions/OverlayPlacementAction.cs

Lines changed: 130 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using System;
1+
using Microsoft.Xna.Framework;
2+
using Rampastring.XNAUI;
3+
using System;
24
using System.Collections.Generic;
35
using TSMapEditor.GameMath;
46
using TSMapEditor.Models;
@@ -49,8 +51,33 @@ public OriginalOverlayInfo(OverlayType overlayType, int frameIndex)
4951

5052
private List<OriginalOverlayInfo> originalOverlay = new List<OriginalOverlayInfo>();
5153

54+
private Point2D? lineSourceCell;
55+
private PlaceOverlayLineMutation linePreviewMutation;
56+
private bool blocked;
57+
58+
public override void OnActionExit()
59+
{
60+
ClearLinePreview();
61+
base.OnActionExit();
62+
}
63+
64+
private (Direction direction, int length) GetLineInformation(Point2D cellCoords)
65+
{
66+
Direction direction = Helpers.DirectionFromPoints(lineSourceCell.Value, cellCoords);
67+
Point2D vector = cellCoords - lineSourceCell.Value;
68+
int length = Math.Max(Math.Abs(vector.X), Math.Abs(vector.Y));
69+
70+
return (direction, length);
71+
}
72+
5273
public override void PreMapDraw(Point2D cellCoords)
5374
{
75+
if (lineSourceCell.HasValue)
76+
{
77+
ApplyLinePreview(cellCoords);
78+
return;
79+
}
80+
5481
originalOverlay.Clear();
5582

5683
int brushSize = CursorActionTarget.BrushSize.Width * CursorActionTarget.BrushSize.Height;
@@ -98,6 +125,12 @@ public override void PreMapDraw(Point2D cellCoords)
98125

99126
public override void PostMapDraw(Point2D cellCoords)
100127
{
128+
if (lineSourceCell.HasValue)
129+
{
130+
ClearLinePreview();
131+
return;
132+
}
133+
101134
int index = 0;
102135

103136
CursorActionTarget.BrushSize.DoForBrushSize(offset =>
@@ -126,12 +159,107 @@ public override void PostMapDraw(Point2D cellCoords)
126159
CursorActionTarget.AddRefreshPoint(cellCoords, Math.Max(CursorActionTarget.BrushSize.Height, CursorActionTarget.BrushSize.Width) + 1);
127160
}
128161

162+
private void ApplyLinePreview(Point2D cellCoords)
163+
{
164+
if (!lineSourceCell.HasValue || lineSourceCell.Value == cellCoords)
165+
return;
166+
167+
(Direction direction, int length) = GetLineInformation(cellCoords);
168+
169+
if (length < 1)
170+
return;
171+
172+
linePreviewMutation = new PlaceOverlayLineMutation(CursorActionTarget.MutationTarget, OverlayType, FrameIndex, lineSourceCell.Value, direction, length);
173+
linePreviewMutation.Perform();
174+
}
175+
176+
private void ClearLinePreview()
177+
{
178+
if (linePreviewMutation != null)
179+
{
180+
linePreviewMutation.Undo();
181+
linePreviewMutation = null;
182+
}
183+
184+
CursorActionTarget.InvalidateMap();
185+
}
186+
187+
public override void DrawPreview(Point2D cellCoords, Point2D cameraTopLeftPoint)
188+
{
189+
if (!lineSourceCell.HasValue)
190+
return;
191+
192+
if (cellCoords == lineSourceCell.Value)
193+
return;
194+
195+
(Direction direction, int length) = GetLineInformation(cellCoords);
196+
197+
Point2D cameraPoint1 = (CellMath.CellCenterPointFromCellCoords_3D(lineSourceCell.Value, Map) - cameraTopLeftPoint).ScaleBy(CursorActionTarget.Camera.ZoomLevel);
198+
Point2D cameraPoint2 = (CellMath.CellCenterPointFromCellCoords_3D(lineSourceCell.Value + Helpers.VisualDirectionToPoint(direction).ScaleBy(length), Map) - cameraTopLeftPoint).ScaleBy(CursorActionTarget.Camera.ZoomLevel);
199+
200+
Renderer.DrawLine(cameraPoint1.ToXNAVector(), cameraPoint2.ToXNAVector(), Color.Orange, 2);
201+
}
202+
129203
public override void LeftDown(Point2D cellCoords)
130204
{
205+
if (blocked)
206+
return;
207+
208+
if (KeyboardCommands.Instance.PlaceTerrainLine.AreKeysOrModifiersDown(Keyboard))
209+
{
210+
if (lineSourceCell == null && CursorActionTarget.Map.GetTile(cellCoords) != null)
211+
{
212+
lineSourceCell = cellCoords;
213+
}
214+
215+
return;
216+
}
217+
131218
var mutation = new PlaceOverlayMutation(CursorActionTarget.MutationTarget, OverlayType, FrameIndex, cellCoords);
132219
CursorActionTarget.MutationManager.PerformMutation(mutation);
133220
}
134221

135-
public override void LeftClick(Point2D cellCoords) => LeftDown(cellCoords);
222+
private void ApplyLine(Point2D cellCoords)
223+
{
224+
if (OverlayType != null)
225+
{
226+
(Direction direction, int length) = GetLineInformation(cellCoords);
227+
var mutation = new PlaceOverlayLineMutation(CursorActionTarget.MutationTarget, OverlayType, FrameIndex, lineSourceCell.Value, direction, length);
228+
PerformMutation(mutation);
229+
}
230+
231+
lineSourceCell = null;
232+
}
233+
234+
public override void LeftClick(Point2D cellCoords)
235+
{
236+
if (KeyboardCommands.Instance.PlaceTerrainLine.AreKeysOrModifiersDown(Keyboard))
237+
{
238+
if (lineSourceCell != null && cellCoords != lineSourceCell.Value)
239+
{
240+
ApplyLine(cellCoords);
241+
}
242+
243+
return;
244+
}
245+
246+
LeftDown(cellCoords);
247+
blocked = false;
248+
}
249+
250+
public override void Update(Point2D? cellCoords)
251+
{
252+
if (lineSourceCell != null && cellCoords != null && lineSourceCell != cellCoords)
253+
{
254+
if (!KeyboardCommands.Instance.PlaceTerrainLine.AreKeysOrModifiersDown(Keyboard))
255+
{
256+
ApplyLine(cellCoords.Value);
257+
blocked = true;
258+
}
259+
}
260+
261+
if (!CursorActionTarget.WindowManager.Cursor.LeftDown && !CursorActionTarget.WindowManager.Cursor.LeftClicked)
262+
blocked = false;
263+
}
136264
}
137265
}

0 commit comments

Comments
 (0)