Skip to content

Commit dd374b5

Browse files
committed
Implement line-based terrain painting by holding Shift when placing tiles
1 parent f88b59a commit dd374b5

File tree

10 files changed

+355
-32
lines changed

10 files changed

+355
-32
lines changed

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

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,19 @@ SubCell.Right=Right
205205
SubCell.Left=Left
206206
SubCell.Bottom=Bottom
207207
208+
; *************************************************
209+
; Visual Direction
210+
; *************************************************
211+
212+
Direction.NE=Northeast
213+
Direction.E=East
214+
Direction.SE=Southeast
215+
Direction.S=South
216+
Direction.SW=Southwest
217+
Direction.W=West
218+
Direction.NW=Northwest
219+
Direction.N=North
220+
208221
; *************************************************
209222
; Keyboard Commands
210223
; *************************************************
@@ -236,6 +249,7 @@ KeyboardCommands.RotateUnit=Rotate Unit
236249
KeyboardCommands.RotateObjectOneStep=Rotate Object One Step
237250
KeyboardCommands.PlaceTerrainBelowCursor=Place Terrain Below Cursor
238251
KeyboardCommands.FillTerrain=Fill Terrain (1x1 tiles only)
252+
KeyboardCommands.PlaceTerrainLine=Place Terrain Line
239253
KeyboardCommands.CloneObject=Clone Object (Modifier)
240254
KeyboardCommands.OverlapObjects=Overlap Objects (Modifier)
241255
KeyboardCommands.ViewMegamap=View Megamap
@@ -1429,6 +1443,52 @@ ToggleIceGrowthCursorAction.DisableName=Disable Ice Growth
14291443
14301444
UnitPlacementAction.Name=Place Vehicle
14311445
1446+
; *************************************************
1447+
; Mutations
1448+
; *************************************************
1449+
1450+
ChangeAttachedTagMutation.DisplayString=Change attached tag of '{0}' at {1} to '{2}'
1451+
ChangeTechnoOwnerMutation.DisplayString=Change owner of {0} at {1} to {2}
1452+
CloneObjectMutation.DisplayString=Clone {0} to {1}
1453+
DeleteObjectMutation.DisplayString=Delete {0} objects at {1} with a brush size of {2}
1454+
DeleteTubeMutation.DisplayString=Delete tunnel tube of length {0} at {1}
1455+
DrawCliffMutation.DisplayString=Draw Connected Tiles of type {0}
1456+
FillTerrainAreaMutation.DisplayString=Flood-fill terrain tiles at {0} with tile from set '{1}'
1457+
FlattenGroundMutation.DisplayString=Flatten ground at {0} to a level of {1} with a brush size of {2}
1458+
FSLowerGroundMutation.DisplayString=Lower ground at {0} with a brush size of {1} using non-steep ramps
1459+
FSRaiseGroundMutation.DisplayString=Raise ground at {0} with a brush size of {1} using non-steep ramps
1460+
LowerCellsMutation.DisplayString=Lower cell height at {0} with a brush size of {1}
1461+
LowerGroundMutation.DisplayString=Lower ground at {0} with a brush size of {1} using steep ramps
1462+
MoveObjectMutation.DisplayString=Move {0} from {1} to {2}
1463+
PasteTerrainMutation.DisplayString=Paste copied terrain of size {0}x{1} at {2}
1464+
PlaceAircraftMutation.DisplayString=Place '{0}' at {1}
1465+
PlaceBridgeMutation.DisplayString=Place bridge '{0}' of direction {1} from {2} to {3}
1466+
PlaceBuildingMutation.DisplayString=Place '{0}' at {1}
1467+
PlaceCellTagMutation.DisplayString=Place CellTag for '{0}' at {1}
1468+
PlaceConnectedOverlayMutation.DisplayString=Place connected overlay '{0}' at {1} with a brush size of {2}
1469+
PlaceInfantryMutation.DisplayString=Place '{0}' at {1}
1470+
PlaceOverlayCollectionMutation.DisplayString=Place overlay collection {0} at {1} with a brush size of {2}
1471+
PlaceOverlayMutation.DisplayStringPlace=Place overlay '{0}' at {1} with a brush size of {2}
1472+
PlaceOverlayMutation.DisplayStringErase=Erase overlay at {0} with a brush size of {1}
1473+
PlaceSmudgeCollectionMutation.DisplayString=Place smudge collection {0} at {1} with brush size of {2}
1474+
PlaceSmudgeMutation.DisplayString=Place smudge '{0}' at {1} with brush size of {2}
1475+
PlaceSmudgeMutation.DisplayStringErase=Erase smudges at {0} with brush size of {1}
1476+
PlaceTerrainLineMutation.DisplayString=Place Terrain Line from {0} towards {1} with distance of {2}
1477+
PlaceTerrainObjectCollectionMutation.DisplayString=Place terrain object collection '{0}' at {1}
1478+
PlaceTerrainObjectMutation.DisplayString=Place terrain object '{0}' at {1}
1479+
PlaceTerrainTileMutation.DisplayString=Place terrain tile of TileSet {0} at {1} with a brush size of {2}
1480+
PlaceTubeMutation.DisplayString=Place tunnel tube of length {0} at {1}
1481+
PlaceVehicleMutation.DisplayString=Place '{0}' at {1}
1482+
PlaceVeinholeMonsterMutation.DisplayString=Lower ground at {0} with a brush size of {1} using non-steep ramps
1483+
PlaceWaypointMutation.DisplayString=Place waypoint {0} at {1}
1484+
RaiseCellsMutation.DisplayString=Raise cell height at {0} with a brush size of {1}
1485+
RaiseGroundMutation.DisplayString=Raise ground at {0} with a brush size of {1} using steep ramps
1486+
SetFollowerMutation.DisplayString=Set follower of vehicle {0} at {1} to {2} at {3}
1487+
SetIceGrowthMutation.DisplayString={0} ice growth at {1} with a brush size of {2}
1488+
SetIceGrowthMutation.Enable=Enable
1489+
SetIceGrowthMutation.Disable=Disable
1490+
TerrainGenerationMutation.DisplayString=Generate Terrain over {0} cells
1491+
14321492
; *************************************************
14331493
; *************************************************
14341494
; WAE Configuration Elements

src/TSMapEditor/Constants.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ namespace TSMapEditor
44
{
55
public static class Constants
66
{
7-
public const string ReleaseVersion = "1.7.11";
7+
public const string ReleaseVersion = "1.7.12";
88

99
public static int CellSizeX = 48;
1010
public static int CellSizeY = 24;

src/TSMapEditor/GameMath/Point2D.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ public int DistanceTo(Point2D other)
132132

133133
public Point2D ScaleBy(float scale) => new Point2D((int)(X * scale), (int)(Y * scale));
134134

135+
public Point2D ScaleBy(int scale) => new Point2D(X * scale, Y * scale);
136+
135137
public byte[] GetData()
136138
{
137139
byte[] buffer = new byte[sizeof(int) * 2];

src/TSMapEditor/Helpers.cs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,49 @@ public static string WaypointNumberToAlphabeticalString(int waypointNumber)
229229

230230
public static Point2D VisualDirectionToPoint(Direction direction) => visualDirectionToPointTable[(int)direction];
231231

232+
private static string[] directionToNameTable = new string[]
233+
{
234+
"Northeast", "East", "Southeast", "South", "Southwest", "West", "Northwest", "North"
235+
};
236+
237+
public static string DirectionToName(Direction direction) => directionToNameTable[(int)direction];
238+
239+
public static Direction DirectionFromPoints(Point2D p1, Point2D p2)
240+
{
241+
if (p1 == p2)
242+
throw new ArgumentException("Cannot get direction from two identical points.");
243+
244+
int xDiff = p2.X - p1.X;
245+
int yDiff = p2.Y - p1.Y;
246+
247+
if (xDiff == 0 || Math.Abs(yDiff) > Math.Abs(xDiff * 2))
248+
{
249+
if (yDiff > 0)
250+
return Direction.SW;
251+
252+
return Direction.NE;
253+
}
254+
255+
if (yDiff == 0 || Math.Abs(xDiff) > Math.Abs(yDiff * 2))
256+
{
257+
if (xDiff > 0)
258+
return Direction.SE;
259+
260+
return Direction.NW;
261+
}
262+
263+
if (xDiff > 0 && yDiff > 0)
264+
return Direction.S;
265+
266+
if (xDiff > 0 && yDiff < 0)
267+
return Direction.E;
268+
269+
if (xDiff < 0 && yDiff > 0)
270+
return Direction.W;
271+
272+
return Direction.N;
273+
}
274+
232275
public static List<Direction> GetDirectionsInMask(byte mask)
233276
{
234277
List<Direction> directions = new List<Direction>();

src/TSMapEditor/Mutations/Classes/OriginalTerrainData.cs

Lines changed: 0 additions & 20 deletions
This file was deleted.
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using TSMapEditor.GameMath;
4+
using TSMapEditor.Models;
5+
using TSMapEditor.Rendering;
6+
using TSMapEditor.UI;
7+
8+
namespace TSMapEditor.Mutations.Classes
9+
{
10+
public class PlaceTerrainLineMutation : Mutation
11+
{
12+
public PlaceTerrainLineMutation(IMutationTarget mutationTarget, MapTile source, Direction direction, int length, TileImage tile) : base(mutationTarget)
13+
{
14+
sourceTile = source;
15+
this.direction = direction;
16+
this.length = length;
17+
this.tile = tile;
18+
}
19+
20+
private readonly MapTile sourceTile;
21+
private readonly Direction direction;
22+
private readonly int length;
23+
private readonly TileImage tile;
24+
private List<OriginalCellTerrainData> undoData = new List<OriginalCellTerrainData>();
25+
26+
public override string GetDisplayString()
27+
{
28+
string directionString = Translate("Direction." + direction, Helpers.DirectionToName(direction));
29+
return string.Format(Translate(this, "DisplayString", "Place Terrain Line from {0} towards {1} with distance of {2}"), sourceTile.CoordsToPoint(), direction, length);
30+
}
31+
32+
int GetSouthernmostSubTileOffset()
33+
{
34+
int maxY = 1;
35+
36+
for (int i = 0; i < tile.TMPImages.Length; i++)
37+
{
38+
var image = tile.TMPImages[i];
39+
40+
if (image == null)
41+
continue;
42+
43+
int cx = i % tile.Width;
44+
int cy = i / tile.Height;
45+
46+
int southOffset = (cx + cy) / 2;
47+
if (southOffset > maxY)
48+
maxY = southOffset;
49+
}
50+
51+
return maxY;
52+
}
53+
54+
int GetEasternmostSubTileOffset()
55+
{
56+
int maxEast = 1;
57+
58+
for (int i = 0; i < tile.TMPImages.Length; i++)
59+
{
60+
var image = tile.TMPImages[i];
61+
62+
if (image == null)
63+
continue;
64+
65+
int cx = i % tile.Width;
66+
int cy = i / tile.Height;
67+
68+
int eastOffset = cx - cy;
69+
70+
if (eastOffset > maxEast)
71+
maxEast = eastOffset;
72+
}
73+
74+
return maxEast;
75+
}
76+
77+
int GetWesternmostSubTileOffset()
78+
{
79+
int maxWest = 1;
80+
81+
for (int i = 0; i < tile.TMPImages.Length; i++)
82+
{
83+
var image = tile.TMPImages[i];
84+
85+
if (image == null)
86+
continue;
87+
88+
int cx = i % tile.Width;
89+
int cy = i / tile.Height;
90+
91+
int westOffset = cy - cx;
92+
93+
if (westOffset > maxWest)
94+
maxWest = westOffset;
95+
}
96+
97+
return maxWest;
98+
}
99+
100+
public override void Perform()
101+
{
102+
int processedLength = 0;
103+
while (processedLength <= length)
104+
{
105+
Point2D coords = sourceTile.CoordsToPoint() + Helpers.VisualDirectionToPoint(direction).ScaleBy(processedLength);
106+
107+
PlaceTile(coords);
108+
109+
switch (direction)
110+
{
111+
case Direction.NE:
112+
case Direction.SW:
113+
processedLength += tile.Height;
114+
break;
115+
case Direction.NW:
116+
case Direction.SE:
117+
processedLength += tile.Width;
118+
break;
119+
case Direction.N:
120+
case Direction.S:
121+
processedLength += GetSouthernmostSubTileOffset();
122+
break;
123+
case Direction.E:
124+
processedLength += GetEasternmostSubTileOffset();
125+
break;
126+
case Direction.W:
127+
processedLength += GetWesternmostSubTileOffset();
128+
break;
129+
}
130+
}
131+
132+
MutationTarget.InvalidateMap();
133+
}
134+
135+
private void PlaceTile(Point2D coords)
136+
{
137+
var originalData = new List<OriginalCellTerrainData>();
138+
139+
// Process cells within tile foundation
140+
for (int i = 0; i < tile.TMPImages.Length; i++)
141+
{
142+
MGTMPImage image = tile.TMPImages[i];
143+
144+
if (image == null)
145+
continue;
146+
147+
int cx = coords.X + i % tile.Width;
148+
int cy = coords.Y + i / tile.Width;
149+
150+
Point2D cellCoords = new Point2D(cx, cy);
151+
var cell = Map.GetTile(cellCoords);
152+
if (cell == null)
153+
continue;
154+
155+
undoData.Add(new OriginalCellTerrainData(cellCoords, cell.TileIndex, cell.SubTileIndex, cell.Level));
156+
cell.ChangeTileIndex(tile.TileID, (byte)i);
157+
}
158+
}
159+
160+
public override void Undo()
161+
{
162+
for (int i = 0; i < undoData.Count; i++)
163+
{
164+
OriginalCellTerrainData originalTerrainData = undoData[i];
165+
166+
var mapCell = MutationTarget.Map.GetTile(originalTerrainData.CellCoords);
167+
if (mapCell != null)
168+
{
169+
mapCell.ChangeTileIndex(originalTerrainData.TileIndex, originalTerrainData.SubTileIndex);
170+
mapCell.Level = originalTerrainData.HeightLevel;
171+
RefreshCellLighting(mapCell);
172+
}
173+
}
174+
175+
MutationTarget.InvalidateMap();
176+
}
177+
}
178+
}

src/TSMapEditor/Mutations/Classes/PlaceTerrainTileMutation.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public PlaceTerrainTileMutation(IMutationTarget mutationTarget, Point2D targetCe
2525
private readonly int heightOffset;
2626
private readonly BrushSize brushSize;
2727

28-
private List<OriginalTerrainData> undoData;
28+
private List<OriginalCellTerrainData> undoData;
2929

3030
private static readonly Point2D[] surroundingTiles = new Point2D[] { new Point2D(-1, 0), new Point2D(1, 0), new Point2D(0, -1), new Point2D(0, 1) };
3131

@@ -53,14 +53,14 @@ private void AddUndoDataForTile(Point2D brushOffset)
5353
if (mapTile != null && (!MutationTarget.OnlyPaintOnClearGround || mapTile.IsClearGround()) &&
5454
!undoData.Exists(otd => otd.CellCoords.X == cx && otd.CellCoords.Y == cy))
5555
{
56-
undoData.Add(new OriginalTerrainData(mapTile.TileIndex, mapTile.SubTileIndex, mapTile.Level, mapTile.CoordsToPoint()));
56+
undoData.Add(new OriginalCellTerrainData(mapTile.CoordsToPoint(), mapTile.TileIndex, mapTile.SubTileIndex, mapTile.Level));
5757
}
5858
}
5959
}
6060

6161
public override void Perform()
6262
{
63-
undoData = new List<OriginalTerrainData>(tile.TMPImages.Length * brushSize.Width * brushSize.Height);
63+
undoData = new List<OriginalCellTerrainData>(tile.TMPImages.Length * brushSize.Width * brushSize.Height);
6464

6565
int totalWidth = tile.Width * brushSize.Width;
6666
int totalHeight = tile.Height * brushSize.Height;
@@ -164,13 +164,13 @@ public override void Undo()
164164
{
165165
for (int i = 0; i < undoData.Count; i++)
166166
{
167-
OriginalTerrainData originalTerrainData = undoData[i];
167+
OriginalCellTerrainData originalTerrainData = undoData[i];
168168

169169
var mapCell = MutationTarget.Map.GetTile(originalTerrainData.CellCoords);
170170
if (mapCell != null)
171171
{
172172
mapCell.ChangeTileIndex(originalTerrainData.TileIndex, originalTerrainData.SubTileIndex);
173-
mapCell.Level = originalTerrainData.Level;
173+
mapCell.Level = originalTerrainData.HeightLevel;
174174
RefreshCellLighting(mapCell);
175175
}
176176
}

0 commit comments

Comments
 (0)