Event light, map ambient, DSL highlighting, autotile palette, action buttons on top
This commit is contained in:
1 parent
ac5b21e4c3
commit
dbe46a05bf
12 files changed
+146
-19
No files matched your search
@@ -102,3 +102,11 @@ tools/rpg_editor/item_found_line = Found: {0} ×{1}
|
|||||||
tools/rpg_editor/placed_item = “{0}” lies on the map: event {1}
|
tools/rpg_editor/placed_item = “{0}” lies on the map: event {1}
|
||||||
tools/rpg_editor/picker_no_look = No map picture found, a marker is shown
|
tools/rpg_editor/picker_no_look = No map picture found, a marker is shown
|
||||||
tools/rpg_editor/problem_event_locked = Event id {0} is taken by an event of another file or mod — pick another one
|
tools/rpg_editor/problem_event_locked = Event id {0} is taken by an event of another file or mod — pick another one
|
||||||
|
tools/rpg_editor/section_light = Light
|
||||||
|
tools/rpg_editor/light_radius = Light radius
|
||||||
|
tools/rpg_editor/light_radius_tip = In cells; 0 means the event gives no light. Light shows at dusk and at night
|
||||||
|
tools/rpg_editor/light_color = Light colour
|
||||||
|
tools/rpg_editor/light_color_tip = #rrggbb or #rrggbbaa (alpha is the strength); empty keeps the warm default
|
||||||
|
tools/rpg_editor/ambient = Fixed ambient
|
||||||
|
tools/rpg_editor/ambient_tip = #rrggbb: the map is always lit like this (a room with a lamp); empty: by the time of day
|
||||||
|
tools/rpg_editor/autotile = autotile
|
||||||
@@ -102,3 +102,11 @@ tools/rpg_editor/item_found_line = Encontrado: {0} ×{1}
|
|||||||
tools/rpg_editor/placed_item = «{0}» está en el mapa: evento {1}
|
tools/rpg_editor/placed_item = «{0}» está en el mapa: evento {1}
|
||||||
tools/rpg_editor/picker_no_look = No se encontró imagen para el mapa, se muestra un marcador
|
tools/rpg_editor/picker_no_look = No se encontró imagen para el mapa, se muestra un marcador
|
||||||
tools/rpg_editor/problem_event_locked = El id de evento {0} ya lo usa un evento de otro archivo o mod: elige otro
|
tools/rpg_editor/problem_event_locked = El id de evento {0} ya lo usa un evento de otro archivo o mod: elige otro
|
||||||
|
tools/rpg_editor/section_light = Luz
|
||||||
|
tools/rpg_editor/light_radius = Radio de luz
|
||||||
|
tools/rpg_editor/light_radius_tip = En casillas; 0: el evento no da luz. La luz se ve al anochecer y de noche
|
||||||
|
tools/rpg_editor/light_color = Color de la luz
|
||||||
|
tools/rpg_editor/light_color_tip = #rrggbb o #rrggbbaa (alfa = intensidad); vacío: el cálido por defecto
|
||||||
|
tools/rpg_editor/ambient = Luz ambiental fija
|
||||||
|
tools/rpg_editor/ambient_tip = #rrggbb: el mapa siempre tiene esta luz (una sala con lámpara); vacío: según la hora del día
|
||||||
|
tools/rpg_editor/autotile = autotile
|
||||||
@@ -102,3 +102,11 @@ tools/rpg_editor/item_found_line = 見つけた:{0} ×{1}
|
|||||||
tools/rpg_editor/placed_item = 「{0}」をマップに置いた:イベント {1}
|
tools/rpg_editor/placed_item = 「{0}」をマップに置いた:イベント {1}
|
||||||
tools/rpg_editor/picker_no_look = マップ用の画像が見つからないため、マーカーを表示します
|
tools/rpg_editor/picker_no_look = マップ用の画像が見つからないため、マーカーを表示します
|
||||||
tools/rpg_editor/problem_event_locked = イベント id {0} は別のファイルか MOD のイベントが使っています——別の id にしてください
|
tools/rpg_editor/problem_event_locked = イベント id {0} は別のファイルか MOD のイベントが使っています——別の id にしてください
|
||||||
|
tools/rpg_editor/section_light = 光
|
||||||
|
tools/rpg_editor/light_radius = 光の半径
|
||||||
|
tools/rpg_editor/light_radius_tip = マス単位。0 ならイベントは光らない。光は夕方と夜に見える
|
||||||
|
tools/rpg_editor/light_color = 光の色
|
||||||
|
tools/rpg_editor/light_color_tip = #rrggbb か #rrggbbaa(アルファが強さ)。空なら既定の暖色
|
||||||
|
tools/rpg_editor/ambient = 固定の環境光
|
||||||
|
tools/rpg_editor/ambient_tip = #rrggbb:マップは常にこの明るさ(ランプのある部屋)。空なら時刻に従う
|
||||||
|
tools/rpg_editor/autotile = オートタイル
|
||||||
@@ -102,3 +102,11 @@ tools/rpg_editor/item_found_line = 발견: {0} ×{1}
|
|||||||
tools/rpg_editor/placed_item = "{0}"이(가) 맵에 놓였습니다: 이벤트 {1}
|
tools/rpg_editor/placed_item = "{0}"이(가) 맵에 놓였습니다: 이벤트 {1}
|
||||||
tools/rpg_editor/picker_no_look = 맵용 그림을 찾지 못해 표식을 표시합니다
|
tools/rpg_editor/picker_no_look = 맵용 그림을 찾지 못해 표식을 표시합니다
|
||||||
tools/rpg_editor/problem_event_locked = 이벤트 id {0}은(는) 다른 파일이나 모드의 이벤트가 쓰고 있습니다 — 다른 것을 고르세요
|
tools/rpg_editor/problem_event_locked = 이벤트 id {0}은(는) 다른 파일이나 모드의 이벤트가 쓰고 있습니다 — 다른 것을 고르세요
|
||||||
|
tools/rpg_editor/section_light = 빛
|
||||||
|
tools/rpg_editor/light_radius = 빛 반경
|
||||||
|
tools/rpg_editor/light_radius_tip = 칸 단위, 0이면 이벤트가 빛나지 않음. 빛은 해질녘과 밤에 보임
|
||||||
|
tools/rpg_editor/light_color = 빛 색
|
||||||
|
tools/rpg_editor/light_color_tip = #rrggbb 또는 #rrggbbaa(알파가 세기), 비우면 기본 따뜻한 색
|
||||||
|
tools/rpg_editor/ambient = 고정 환경광
|
||||||
|
tools/rpg_editor/ambient_tip = #rrggbb: 맵이 항상 이 빛으로 비침(램프가 있는 방), 비우면 시간대에 따름
|
||||||
|
tools/rpg_editor/autotile = 오토타일
|
||||||
@@ -102,3 +102,11 @@ tools/rpg_editor/item_found_line = Найдено: {0} ×{1}
|
|||||||
tools/rpg_editor/placed_item = «{0}» лежит на карте: событие {1}
|
tools/rpg_editor/placed_item = «{0}» лежит на карте: событие {1}
|
||||||
tools/rpg_editor/picker_no_look = Картинка для карты не найдена, будет маркер
|
tools/rpg_editor/picker_no_look = Картинка для карты не найдена, будет маркер
|
||||||
tools/rpg_editor/problem_event_locked = Id события {0} уже занят событием из другого файла или мода — выберите другой
|
tools/rpg_editor/problem_event_locked = Id события {0} уже занят событием из другого файла или мода — выберите другой
|
||||||
|
tools/rpg_editor/section_light = Свет
|
||||||
|
tools/rpg_editor/light_radius = Радиус света
|
||||||
|
tools/rpg_editor/light_radius_tip = В клетках; 0 — событие не светит. Свет виден в сумерках и ночью
|
||||||
|
tools/rpg_editor/light_color = Цвет света
|
||||||
|
tools/rpg_editor/light_color_tip = #rrggbb или #rrggbbaa (альфа — сила); пусто — тёплый по умолчанию
|
||||||
|
tools/rpg_editor/ambient = Своё освещение
|
||||||
|
tools/rpg_editor/ambient_tip = #rrggbb: карта всегда освещена так (комната с лампой); пусто — по времени суток
|
||||||
|
tools/rpg_editor/autotile = автотайл
|
||||||
@@ -102,3 +102,11 @@ tools/rpg_editor/item_found_line = Tìm thấy: {0} ×{1}
|
|||||||
tools/rpg_editor/placed_item = "{0}" nằm trên bản đồ: sự kiện {1}
|
tools/rpg_editor/placed_item = "{0}" nằm trên bản đồ: sự kiện {1}
|
||||||
tools/rpg_editor/picker_no_look = Không tìm thấy hình cho bản đồ, hiển thị một điểm đánh dấu
|
tools/rpg_editor/picker_no_look = Không tìm thấy hình cho bản đồ, hiển thị một điểm đánh dấu
|
||||||
tools/rpg_editor/problem_event_locked = Id sự kiện {0} đã được một sự kiện ở tệp hoặc mod khác dùng — hãy chọn id khác
|
tools/rpg_editor/problem_event_locked = Id sự kiện {0} đã được một sự kiện ở tệp hoặc mod khác dùng — hãy chọn id khác
|
||||||
|
tools/rpg_editor/section_light = Ánh sáng
|
||||||
|
tools/rpg_editor/light_radius = Bán kính sáng
|
||||||
|
tools/rpg_editor/light_radius_tip = Tính theo ô; 0 là sự kiện không phát sáng. Ánh sáng hiện lúc chạng vạng và ban đêm
|
||||||
|
tools/rpg_editor/light_color = Màu ánh sáng
|
||||||
|
tools/rpg_editor/light_color_tip = #rrggbb hoặc #rrggbbaa (alpha là cường độ); để trống dùng màu ấm mặc định
|
||||||
|
tools/rpg_editor/ambient = Ánh sáng nền cố định
|
||||||
|
tools/rpg_editor/ambient_tip = #rrggbb: bản đồ luôn sáng như vậy (phòng có đèn); để trống thì theo giờ trong ngày
|
||||||
|
tools/rpg_editor/autotile = ô tự động
|
||||||
@@ -102,3 +102,11 @@ tools/rpg_editor/item_found_line = 找到:{0} ×{1}
|
|||||||
tools/rpg_editor/placed_item = "{0}"放在地图上:事件 {1}
|
tools/rpg_editor/placed_item = "{0}"放在地图上:事件 {1}
|
||||||
tools/rpg_editor/picker_no_look = 没有找到地图用的图片,显示为标记
|
tools/rpg_editor/picker_no_look = 没有找到地图用的图片,显示为标记
|
||||||
tools/rpg_editor/problem_event_locked = 事件 id {0} 已被其他文件或模组的事件占用——请换一个
|
tools/rpg_editor/problem_event_locked = 事件 id {0} 已被其他文件或模组的事件占用——请换一个
|
||||||
|
tools/rpg_editor/section_light = 光照
|
||||||
|
tools/rpg_editor/light_radius = 光照半径
|
||||||
|
tools/rpg_editor/light_radius_tip = 以格为单位;0 表示事件不发光。光在黄昏和夜晚可见
|
||||||
|
tools/rpg_editor/light_color = 光的颜色
|
||||||
|
tools/rpg_editor/light_color_tip = #rrggbb 或 #rrggbbaa(alpha 为强度);留空为默认暖色
|
||||||
|
tools/rpg_editor/ambient = 固定环境光
|
||||||
|
tools/rpg_editor/ambient_tip = #rrggbb:地图始终以此光照(点灯的房间);留空则随时间变化
|
||||||
|
tools/rpg_editor/autotile = 自动图块
|
||||||
+11
-7
@@ -28,9 +28,19 @@ namespace Cthangover.Tools.RpgEditor
|
|||||||
private readonly HBoxContainer buttons;
|
private readonly HBoxContainer buttons;
|
||||||
private List<RpgPickerEntry> all = new();
|
private List<RpgPickerEntry> all = new();
|
||||||
|
|
||||||
/// <summary>Builds the search field, the list, the option and button rows and the hint.</summary>
|
/// <summary>
|
||||||
|
/// Builds the option and button rows with their hint on top — the list grows with the
|
||||||
|
/// entries (<c>AutoHeight</c>), so buttons below it would scroll out of sight — then the
|
||||||
|
/// search field and the list.
|
||||||
|
/// </summary>
|
||||||
public RpgEntityPicker(string searchKey, string hintKey)
|
public RpgEntityPicker(string searchKey, string hintKey)
|
||||||
{
|
{
|
||||||
|
options = new HBoxContainer();
|
||||||
|
AddChild(options);
|
||||||
|
buttons = new HBoxContainer();
|
||||||
|
AddChild(buttons);
|
||||||
|
AddChild(ToolUi.Hint(ToolUi.Tr(hintKey)));
|
||||||
|
|
||||||
search = ToolUi.Text(ToolUi.Tr(searchKey), OnSearchChanged);
|
search = ToolUi.Text(ToolUi.Tr(searchKey), OnSearchChanged);
|
||||||
AddChild(search);
|
AddChild(search);
|
||||||
|
|
||||||
@@ -43,12 +53,6 @@ namespace Cthangover.Tools.RpgEditor
|
|||||||
};
|
};
|
||||||
list.ItemSelected += OnItemSelected;
|
list.ItemSelected += OnItemSelected;
|
||||||
AddChild(list);
|
AddChild(list);
|
||||||
|
|
||||||
options = new HBoxContainer();
|
|
||||||
AddChild(options);
|
|
||||||
buttons = new HBoxContainer();
|
|
||||||
AddChild(buttons);
|
|
||||||
AddChild(ToolUi.Hint(ToolUi.Tr(hintKey)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Reads the entries; called by <see cref="Reload"/>.</summary>
|
/// <summary>Reads the entries; called by <see cref="Reload"/>.</summary>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Cthangover.Mods.Rpg;
|
using Cthangover.Mods.Rpg;
|
||||||
using Cthangover.Tools.Common;
|
using Cthangover.Tools.Common;
|
||||||
|
using Cthangover.Tools.Services;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
namespace Cthangover.Tools.RpgEditor
|
namespace Cthangover.Tools.RpgEditor
|
||||||
@@ -10,7 +11,8 @@ namespace Cthangover.Tools.RpgEditor
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Properties of the selected map event: id, cell, look (charset path, tileset index
|
/// Properties of the selected map event: id, cell, look (charset path, tileset index
|
||||||
/// or item picture), facing, trigger, solidity, what it runs (scenario path,
|
/// or item picture), facing, trigger, solidity, what it runs (scenario path,
|
||||||
/// inline DSL lines, or a teleport) and the condition that shows it.
|
/// inline DSL lines with highlighting, or a teleport), the light it gives off (radius 0 = none)
|
||||||
|
/// and the condition that shows it.
|
||||||
/// <para/>
|
/// <para/>
|
||||||
/// A teleport is on when its map or cell is filled in; clearing the teleport
|
/// A teleport is on when its map or cell is filled in; clearing the teleport
|
||||||
/// map and both coordinates turns it off again. Solidity has a third state,
|
/// map and both coordinates turns it off again. Solidity has a third state,
|
||||||
@@ -40,6 +42,8 @@ namespace Cthangover.Tools.RpgEditor
|
|||||||
private readonly SpinBox teleportX;
|
private readonly SpinBox teleportX;
|
||||||
private readonly SpinBox teleportY;
|
private readonly SpinBox teleportY;
|
||||||
private readonly OptionButton teleportDir;
|
private readonly OptionButton teleportDir;
|
||||||
|
private readonly SpinBox lightRadius;
|
||||||
|
private readonly LineEdit lightColor;
|
||||||
private RpgMapEvent mapEvent;
|
private RpgMapEvent mapEvent;
|
||||||
private bool suppress;
|
private bool suppress;
|
||||||
private bool editing;
|
private bool editing;
|
||||||
@@ -78,10 +82,15 @@ namespace Cthangover.Tools.RpgEditor
|
|||||||
body.AddChild(ToolUi.Hint(ToolUi.Tr("tools/rpg_editor/commands")));
|
body.AddChild(ToolUi.Hint(ToolUi.Tr("tools/rpg_editor/commands")));
|
||||||
commandsEdit = ToolUi.Code();
|
commandsEdit = ToolUi.Code();
|
||||||
commandsEdit.CustomMinimumSize = new Vector2(0, 90);
|
commandsEdit.CustomMinimumSize = new Vector2(0, 90);
|
||||||
|
commandsEdit.SyntaxHighlighter = ScenarioSyntaxService.CreateHighlighter();
|
||||||
commandsEdit.SizeFlagsVertical = SizeFlags.Fill;
|
commandsEdit.SizeFlagsVertical = SizeFlags.Fill;
|
||||||
commandsEdit.TextChanged += OnCommandsChanged;
|
commandsEdit.TextChanged += OnCommandsChanged;
|
||||||
body.AddChild(commandsEdit);
|
body.AddChild(commandsEdit);
|
||||||
|
|
||||||
|
body.AddChild(ToolUi.Section("tools/rpg_editor/section_light"));
|
||||||
|
lightRadius = ToolUi.Field(body, "tools/rpg_editor/light_radius", ToolUi.Number(0, 16, 0.5, OnNumberChanged), "tools/rpg_editor/light_radius_tip");
|
||||||
|
lightColor = ToolUi.Field(body, "tools/rpg_editor/light_color", ToolUi.Text("#ffd8a0", OnTextChanged), "tools/rpg_editor/light_color_tip");
|
||||||
|
|
||||||
body.AddChild(ToolUi.Section("tools/rpg_editor/section_teleport"));
|
body.AddChild(ToolUi.Section("tools/rpg_editor/section_teleport"));
|
||||||
teleportMap = ToolUi.Field(body, "tools/rpg_editor/teleport_map", ToolUi.Text("", OnTextChanged), "tools/rpg_editor/teleport_map_tip");
|
teleportMap = ToolUi.Field(body, "tools/rpg_editor/teleport_map", ToolUi.Text("", OnTextChanged), "tools/rpg_editor/teleport_map_tip");
|
||||||
teleportX = ToolUi.Field(body, "tools/rpg_editor/x", ToolUi.Number(-1, 255, 1, OnNumberChanged));
|
teleportX = ToolUi.Field(body, "tools/rpg_editor/x", ToolUi.Number(-1, 255, 1, OnNumberChanged));
|
||||||
@@ -119,6 +128,8 @@ namespace Cthangover.Tools.RpgEditor
|
|||||||
teleportX.Value = value.Teleport?.X ?? -1;
|
teleportX.Value = value.Teleport?.X ?? -1;
|
||||||
teleportY.Value = value.Teleport?.Y ?? -1;
|
teleportY.Value = value.Teleport?.Y ?? -1;
|
||||||
teleportDir.Select((int)(value.Teleport?.Dir ?? RpgDirection.Down));
|
teleportDir.Select((int)(value.Teleport?.Dir ?? RpgDirection.Down));
|
||||||
|
lightRadius.Value = value.Light?.Radius ?? 0;
|
||||||
|
lightColor.Text = value.Light?.Color ?? string.Empty;
|
||||||
suppress = false;
|
suppress = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,6 +194,11 @@ namespace Cthangover.Tools.RpgEditor
|
|||||||
Dir = (RpgDirection)teleportDir.Selected,
|
Dir = (RpgDirection)teleportDir.Selected,
|
||||||
}
|
}
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
// A radius of 0 means no light; an empty colour keeps the warm default.
|
||||||
|
mapEvent.Light = lightRadius.Value > 0
|
||||||
|
? new RpgLight { Radius = (float)lightRadius.Value, Color = NullIfEmpty(lightColor.Text) ?? new RpgLight().Color }
|
||||||
|
: null;
|
||||||
Changed?.Invoke();
|
Changed?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -157,8 +157,14 @@ namespace Cthangover.Tools.RpgEditor
|
|||||||
for (var x = 0; x < grid.Width; x++)
|
for (var x = 0; x < grid.Width; x++)
|
||||||
{
|
{
|
||||||
var index = grid.GetTile(layer, x, y);
|
var index = grid.GetTile(layer, x, y);
|
||||||
if (index >= 0)
|
if (index < 0)
|
||||||
|
continue;
|
||||||
|
// Autotiles are assembled from their neighbours exactly like in the game.
|
||||||
|
var autotile = Tileset.AutotileOf(index);
|
||||||
|
if (autotile == null)
|
||||||
DrawTextureRectRegion(Atlas, CellRect(x, y), TileRegion(index), modulate);
|
DrawTextureRectRegion(Atlas, CellRect(x, y), TileRegion(index), modulate);
|
||||||
|
else if (textures.Tileset(autotile.Autotile) is { } block)
|
||||||
|
RpgAutotiles.Draw(this, block, CellRect(x, y), RpgAutotiles.QuartersAt(grid, layer, x, y, index), Tileset.TileSize, modulate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ namespace Cthangover.Tools.RpgEditor
|
|||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The map's own properties in the right column: id (the scene name, read
|
/// The map's own properties in the right column: id (the scene name, read
|
||||||
/// only — it is the file name), display name key, tileset, size, zoom, spawn
|
/// only — it is the file name), display name key, tileset, size, zoom, fixed
|
||||||
|
/// ambient light (empty: the time of day lights the map), spawn
|
||||||
/// and random encounters. The size is applied with a button, because a
|
/// and random encounters. The size is applied with a button, because a
|
||||||
/// smaller size cuts cells off. Encounter groups are written as
|
/// smaller size cuts cells off. Encounter groups are written as
|
||||||
/// <c>slime; wolf,slime</c> — groups split by semicolons.
|
/// <c>slime; wolf,slime</c> — groups split by semicolons.
|
||||||
@@ -27,6 +28,7 @@ namespace Cthangover.Tools.RpgEditor
|
|||||||
private readonly SpinBox widthSpin;
|
private readonly SpinBox widthSpin;
|
||||||
private readonly SpinBox heightSpin;
|
private readonly SpinBox heightSpin;
|
||||||
private readonly SpinBox zoomSpin;
|
private readonly SpinBox zoomSpin;
|
||||||
|
private readonly LineEdit ambientEdit;
|
||||||
private readonly SpinBox spawnX;
|
private readonly SpinBox spawnX;
|
||||||
private readonly SpinBox spawnY;
|
private readonly SpinBox spawnY;
|
||||||
private readonly OptionButton spawnDir;
|
private readonly OptionButton spawnDir;
|
||||||
@@ -61,6 +63,7 @@ namespace Cthangover.Tools.RpgEditor
|
|||||||
heightSpin = ToolUi.Field(this, "tools/rpg_editor/height", ToolUi.Number(1, 256, 1, null));
|
heightSpin = ToolUi.Field(this, "tools/rpg_editor/height", ToolUi.Number(1, 256, 1, null));
|
||||||
AddChild(ToolUi.Button("tools/rpg_editor/resize", OnResizePressed));
|
AddChild(ToolUi.Button("tools/rpg_editor/resize", OnResizePressed));
|
||||||
zoomSpin = ToolUi.Field(this, "tools/rpg_editor/zoom", ToolUi.Number(1, 4, 1, OnZoomChanged), "tools/rpg_editor/zoom_tip");
|
zoomSpin = ToolUi.Field(this, "tools/rpg_editor/zoom", ToolUi.Number(1, 4, 1, OnZoomChanged), "tools/rpg_editor/zoom_tip");
|
||||||
|
ambientEdit = ToolUi.Field(this, "tools/rpg_editor/ambient", ToolUi.Text("#e0d2b8", OnAmbientChanged), "tools/rpg_editor/ambient_tip");
|
||||||
|
|
||||||
AddChild(ToolUi.Section("tools/rpg_editor/section_spawn"));
|
AddChild(ToolUi.Section("tools/rpg_editor/section_spawn"));
|
||||||
spawnX = ToolUi.Field(this, "tools/rpg_editor/x", ToolUi.Number(0, 255, 1, OnSpawnChanged));
|
spawnX = ToolUi.Field(this, "tools/rpg_editor/x", ToolUi.Number(0, 255, 1, OnSpawnChanged));
|
||||||
@@ -94,6 +97,7 @@ namespace Cthangover.Tools.RpgEditor
|
|||||||
widthSpin.Value = value.Grid.Width;
|
widthSpin.Value = value.Grid.Width;
|
||||||
heightSpin.Value = value.Grid.Height;
|
heightSpin.Value = value.Grid.Height;
|
||||||
zoomSpin.Value = map.Zoom;
|
zoomSpin.Value = map.Zoom;
|
||||||
|
ambientEdit.Text = map.Ambient ?? string.Empty;
|
||||||
spawnX.Value = map.Spawn.X;
|
spawnX.Value = map.Spawn.X;
|
||||||
spawnY.Value = map.Spawn.Y;
|
spawnY.Value = map.Spawn.Y;
|
||||||
spawnDir.Select((int)map.Spawn.Dir);
|
spawnDir.Select((int)map.Spawn.Dir);
|
||||||
@@ -123,6 +127,14 @@ namespace Cthangover.Tools.RpgEditor
|
|||||||
Changed?.Invoke();
|
Changed?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnAmbientChanged(string text)
|
||||||
|
{
|
||||||
|
if (!Begin())
|
||||||
|
return;
|
||||||
|
document.Map.Ambient = string.IsNullOrWhiteSpace(text) ? null : text.Trim();
|
||||||
|
Changed?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
private void OnTilesetPicked(long index)
|
private void OnTilesetPicked(long index)
|
||||||
{
|
{
|
||||||
if (!Begin() || index < 0 || index >= tilesets.Count)
|
if (!Begin() || index < 0 || index >= tilesets.Count)
|
||||||
|
|||||||
+42
-9
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Cthangover.Core.UI.Theming;
|
using Cthangover.Core.UI.Theming;
|
||||||
using Cthangover.Mods.Rpg;
|
using Cthangover.Mods.Rpg;
|
||||||
@@ -10,16 +11,20 @@ namespace Cthangover.Tools.RpgEditor
|
|||||||
/// Brush picker of the editor's left column. For a tile layer it shows the
|
/// Brush picker of the editor's left column. For a tile layer it shows the
|
||||||
/// tileset atlas at one and a half times the tile size with the selected tile framed and the
|
/// tileset atlas at one and a half times the tile size with the selected tile framed and the
|
||||||
/// solid tiles marked by a red corner; a click picks a tile, the tooltip
|
/// solid tiles marked by a red corner; a click picks a tile, the tooltip
|
||||||
/// names it (index, tag, solid). For the collision layer it shows the three
|
/// names it (index, tag, solid). The tileset's autotiles follow in a row under the
|
||||||
/// collision codes instead.
|
/// atlas, each shown by its block's preview tile (<see cref="RpgAutotiles"/>). For the
|
||||||
|
/// collision layer it shows the three collision codes instead.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class RpgTilePalette : Control
|
public partial class RpgTilePalette : Control
|
||||||
{
|
{
|
||||||
private const float Scale = 1.5f;
|
private const float Scale = 1.5f;
|
||||||
private const float CodeHeight = 44f;
|
private const float CodeHeight = 44f;
|
||||||
|
private const float AutotileGap = 8f;
|
||||||
|
|
||||||
private static readonly char[] Codes = { RpgCollision.Block, RpgCollision.Open, RpgCollision.Auto };
|
private static readonly char[] Codes = { RpgCollision.Block, RpgCollision.Open, RpgCollision.Auto };
|
||||||
|
|
||||||
|
private readonly RpgTextures textures = new();
|
||||||
|
private readonly List<RpgTileInfo> autotiles = new();
|
||||||
private RpgTileset tileset;
|
private RpgTileset tileset;
|
||||||
private Texture2D atlas;
|
private Texture2D atlas;
|
||||||
private bool collisionMode;
|
private bool collisionMode;
|
||||||
@@ -49,6 +54,9 @@ namespace Cthangover.Tools.RpgEditor
|
|||||||
{
|
{
|
||||||
tileset = value;
|
tileset = value;
|
||||||
atlas = image;
|
atlas = image;
|
||||||
|
autotiles.Clear();
|
||||||
|
if (value != null)
|
||||||
|
autotiles.AddRange(value.Tiles.Where(t => !string.IsNullOrEmpty(t.Autotile)));
|
||||||
Relayout();
|
Relayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,15 +88,23 @@ namespace Cthangover.Tools.RpgEditor
|
|||||||
|
|
||||||
var cell = tileset.TileSize * Scale;
|
var cell = tileset.TileSize * Scale;
|
||||||
DrawTextureRect(atlas, new Rect2(Vector2.Zero, atlas.GetSize() * Scale), false);
|
DrawTextureRect(atlas, new Rect2(Vector2.Zero, atlas.GetSize() * Scale), false);
|
||||||
foreach (var tile in tileset.Tiles.Where(t => t.Solid))
|
foreach (var tile in tileset.Tiles.Where(t => t.Solid && string.IsNullOrEmpty(t.Autotile)))
|
||||||
|
DrawSolidMark((Vector2)RpgTileSetBuilder.AtlasCoords(tileset, tile.Index) * cell, cell);
|
||||||
|
for (var i = 0; i < autotiles.Count; i++)
|
||||||
{
|
{
|
||||||
var position = (Vector2)RpgTileSetBuilder.AtlasCoords(tileset, tile.Index) * cell;
|
if (textures.Tileset(autotiles[i].Autotile) is { } block)
|
||||||
DrawColoredPolygon(new[] { position, position + new Vector2(cell * 0.25f, 0f), position + new Vector2(0f, cell * 0.25f) }, new Color(0.9f, 0.2f, 0.2f, 0.9f));
|
DrawTextureRectRegion(block, new Rect2(Slot(i), new Vector2(cell, cell)), RpgAutotiles.PreviewRect(tileset.TileSize));
|
||||||
|
if (autotiles[i].Solid)
|
||||||
|
DrawSolidMark(Slot(i), cell);
|
||||||
}
|
}
|
||||||
var selected = (Vector2)RpgTileSetBuilder.AtlasCoords(tileset, SelectedTile) * cell;
|
var slot = autotiles.FindIndex(t => t.Index == SelectedTile);
|
||||||
|
var selected = slot >= 0 ? Slot(slot) : (Vector2)RpgTileSetBuilder.AtlasCoords(tileset, SelectedTile) * cell;
|
||||||
DrawRect(new Rect2(selected, new Vector2(cell, cell)), UiTokens.AccentBright, false, 3f);
|
DrawRect(new Rect2(selected, new Vector2(cell, cell)), UiTokens.AccentBright, false, 3f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DrawSolidMark(Vector2 position, float cell)
|
||||||
|
=> DrawColoredPolygon(new[] { position, position + new Vector2(cell * 0.25f, 0f), position + new Vector2(0f, cell * 0.25f) }, new Color(0.9f, 0.2f, 0.2f, 0.9f));
|
||||||
|
|
||||||
private void DrawCode(int i)
|
private void DrawCode(int i)
|
||||||
{
|
{
|
||||||
var rect = new Rect2(0f, i * (CodeHeight + 6f), Size.X, CodeHeight);
|
var rect = new Rect2(0f, i * (CodeHeight + 6f), Size.X, CodeHeight);
|
||||||
@@ -110,7 +126,7 @@ namespace Cthangover.Tools.RpgEditor
|
|||||||
if (collisionMode)
|
if (collisionMode)
|
||||||
CustomMinimumSize = new Vector2(200f, Codes.Length * (CodeHeight + 6f));
|
CustomMinimumSize = new Vector2(200f, Codes.Length * (CodeHeight + 6f));
|
||||||
else
|
else
|
||||||
CustomMinimumSize = atlas != null ? atlas.GetSize() * Scale : Vector2.Zero;
|
CustomMinimumSize = atlas != null && tileset != null ? new Vector2(atlas.GetWidth() * Scale, AutotileTop + AutotileRows * tileset.TileSize * Scale) : Vector2.Zero;
|
||||||
TooltipText = string.Empty;
|
TooltipText = string.Empty;
|
||||||
QueueRedraw();
|
QueueRedraw();
|
||||||
}
|
}
|
||||||
@@ -137,7 +153,7 @@ namespace Cthangover.Tools.RpgEditor
|
|||||||
else if (tileset != null && atlas != null)
|
else if (tileset != null && atlas != null)
|
||||||
{
|
{
|
||||||
var index = IndexAt(button.Position);
|
var index = IndexAt(button.Position);
|
||||||
if (index >= 0 && index < RpgTileSetBuilder.TileCount(tileset, atlas))
|
if (index >= 0 && (index < RpgTileSetBuilder.TileCount(tileset, atlas) || tileset.AutotileOf(index) != null))
|
||||||
{
|
{
|
||||||
SelectedTile = index;
|
SelectedTile = index;
|
||||||
TileSelected?.Invoke(index);
|
TileSelected?.Invoke(index);
|
||||||
@@ -147,9 +163,25 @@ namespace Cthangover.Tools.RpgEditor
|
|||||||
AcceptEvent();
|
AcceptEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private float AutotileTop => atlas == null ? 0f : atlas.GetHeight() * Scale + (autotiles.Count > 0 ? AutotileGap : 0f);
|
||||||
|
|
||||||
|
private int AutotileRows => (autotiles.Count + Math.Max(1, tileset.Columns) - 1) / Math.Max(1, tileset.Columns);
|
||||||
|
|
||||||
|
private Vector2 Slot(int i)
|
||||||
|
{
|
||||||
|
var cell = tileset.TileSize * Scale;
|
||||||
|
var columns = Math.Max(1, tileset.Columns);
|
||||||
|
return new Vector2(i % columns * cell, AutotileTop + i / columns * cell);
|
||||||
|
}
|
||||||
|
|
||||||
private int IndexAt(Vector2 position)
|
private int IndexAt(Vector2 position)
|
||||||
{
|
{
|
||||||
var cell = tileset.TileSize * Scale;
|
var cell = tileset.TileSize * Scale;
|
||||||
|
if (autotiles.Count > 0 && position.Y >= AutotileTop)
|
||||||
|
{
|
||||||
|
var slot = (int)((position.Y - AutotileTop) / cell) * Math.Max(1, tileset.Columns) + (int)(position.X / cell);
|
||||||
|
return slot >= 0 && slot < autotiles.Count && position.X < tileset.Columns * cell ? autotiles[slot].Index : -1;
|
||||||
|
}
|
||||||
var column = (int)(position.X / cell);
|
var column = (int)(position.X / cell);
|
||||||
var row = (int)(position.Y / cell);
|
var row = (int)(position.Y / cell);
|
||||||
return column < 0 || column >= tileset.Columns || row < 0 ? -1 : row * tileset.Columns + column;
|
return column < 0 || column >= tileset.Columns || row < 0 ? -1 : row * tileset.Columns + column;
|
||||||
@@ -159,7 +191,8 @@ namespace Cthangover.Tools.RpgEditor
|
|||||||
{
|
{
|
||||||
var info = tileset.Tiles.FirstOrDefault(t => t.Index == index);
|
var info = tileset.Tiles.FirstOrDefault(t => t.Index == index);
|
||||||
var solid = info?.Solid == true ? " · " + TranslationServer.Translate("tools/rpg_editor/solid_tile") : string.Empty;
|
var solid = info?.Solid == true ? " · " + TranslationServer.Translate("tools/rpg_editor/solid_tile") : string.Empty;
|
||||||
return $"#{index} {info?.Tag}{solid}";
|
var auto = string.IsNullOrEmpty(info?.Autotile) ? string.Empty : " · " + TranslationServer.Translate("tools/rpg_editor/autotile");
|
||||||
|
return $"#{index} {info?.Tag}{solid}{auto}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user