Подземелье: типы персонажей, имена, окна-заголовки, инвентарь, типизированные слоты
- Типы: Игрок/Раб/Монстр/Ребёнок (по персонажу), генерация имён - Заголовки-окна над комнатами со списком занявших (имя · тип) - ПКМ по персонажу -> в инвентарь (панель справа, клик -> вернуть на карту) - Типизированные слоты: Дойка = 2 раба + 4 ребёнка, Логово = 1 раб + 1 монстр (персонаж занимает только слот своего типа; иначе не назначается) - Персонажи в комнатах опущены ниже (не висят), дети мельче и ниже - DEBUG: координаты/клетка при перетаскивании в панели Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
4df5a73ec0
commit
0882ecdf87
+220
-61
@@ -37,26 +37,54 @@ public partial class RoomMap : Node2D
|
|||||||
{
|
{
|
||||||
public Node2D Node;
|
public Node2D Node;
|
||||||
public AnimationPlayer Ap;
|
public AnimationPlayer Ap;
|
||||||
public string Name, BaseScene;
|
public string Name, BaseScene, DisplayName;
|
||||||
public int Row, TargetRow;
|
public int Row, TargetRow;
|
||||||
public float X, TargetX, Speed, MinX, MaxX, IdleTimer, FadeT;
|
public float X, TargetX, Speed, MinX, MaxX, IdleTimer, FadeT;
|
||||||
public bool Swapped;
|
public bool Swapped;
|
||||||
public PState State;
|
public PState State;
|
||||||
public string WalkAnim, IdleAnim;
|
public string WalkAnim, IdleAnim;
|
||||||
public Room AssignedRoom;
|
public Room AssignedRoom;
|
||||||
|
public CType Type;
|
||||||
}
|
}
|
||||||
|
|
||||||
// тематическая комната со слотами
|
// тематическая комната с типизированными слотами
|
||||||
private class Room
|
private class Room
|
||||||
{
|
{
|
||||||
public string Type;
|
public string Type;
|
||||||
public int Col, Row, Span, Cap;
|
public int Col, Row, Span;
|
||||||
public string[] States; // приоритет состояний-скелетов
|
public string[] States; // приоритет состояний-скелетов
|
||||||
public readonly List<Pawn> Occ = new();
|
public CType[] SlotTypes; // тип, разрешённый в каждом слоте
|
||||||
|
public Pawn[] SlotOcc; // кто в слоте (null = свободно)
|
||||||
|
public Label Header;
|
||||||
|
public int Cap => SlotTypes.Length;
|
||||||
|
public void Init() => SlotOcc = new Pawn[SlotTypes.Length];
|
||||||
|
public int Count() { int n = 0; foreach (var s in SlotOcc) if (s != null) n++; return n; }
|
||||||
|
public int SlotOf(Pawn p) => System.Array.IndexOf(SlotOcc, p);
|
||||||
|
public int FreeSlotFor(CType t)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < SlotTypes.Length; i++) if (SlotOcc[i] == null && SlotTypes[i] == t) return i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Room> _rooms;
|
private List<Room> _rooms;
|
||||||
|
|
||||||
|
// типы персонажей
|
||||||
|
private enum CType { Player, Slave, Monster, Child }
|
||||||
|
private static string TypeName(CType t) => t switch
|
||||||
|
{
|
||||||
|
CType.Player => "Игрок", CType.Slave => "Раб", CType.Monster => "Монстр", CType.Child => "Ребёнок", _ => "?"
|
||||||
|
};
|
||||||
|
private static readonly string[] Monsters = { "orc", "goblin", "horse", "oni", "man" };
|
||||||
|
private static readonly string[] SlaveNames = { "Ариа", "Луна", "Мира", "Элара", "Ника", "Рина", "Кая", "Тэя", "Лира", "Мэй", "Иврис", "Сая" };
|
||||||
|
private static readonly string[] MonsterNames = { "Грок", "Зуг", "Морг", "Рарг", "Тхок", "Гнар", "Урук", "Драк" };
|
||||||
|
private static readonly string[] ChildNames = { "Пип", "Тимо", "Лулу", "Бэн", "Ния" };
|
||||||
|
|
||||||
|
// инвентарь снятых персонажей
|
||||||
|
private class InvItem { public string Name, Scene; public CType Type; }
|
||||||
|
private readonly List<InvItem> _inventory = new();
|
||||||
|
private VBoxContainer _invBox;
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
var bg = new ColorRect
|
var bg = new ColorRect
|
||||||
@@ -79,9 +107,86 @@ public partial class RoomMap : Node2D
|
|||||||
AddChild(_label);
|
AddChild(_label);
|
||||||
|
|
||||||
BuildInfoPanel();
|
BuildInfoPanel();
|
||||||
|
BuildInventoryPanel();
|
||||||
ResetView();
|
ResetView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void BuildRoomHeaders()
|
||||||
|
{
|
||||||
|
foreach (var r in _rooms)
|
||||||
|
{
|
||||||
|
var lbl = new Label { Position = new Vector2(r.Col * Cell + 6, r.Row * Cell - 34) };
|
||||||
|
lbl.AddThemeFontSizeOverride("font_size", 26);
|
||||||
|
lbl.AddThemeConstantOverride("outline_size", 5);
|
||||||
|
lbl.AddThemeColorOverride("font_outline_color", Colors.Black);
|
||||||
|
_world.AddChild(lbl);
|
||||||
|
r.Header = lbl;
|
||||||
|
UpdateRoomHeader(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateRoomHeader(Room r)
|
||||||
|
{
|
||||||
|
if (r.Header == null) return;
|
||||||
|
var names = new List<string>();
|
||||||
|
foreach (var s in r.SlotOcc) if (s != null) names.Add($"{s.DisplayName} ({TypeName(s.Type)})");
|
||||||
|
r.Header.Text = names.Count == 0 ? $"{r.Type}: пусто" : $"{r.Type}: " + string.Join(", ", names);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- инвентарь ----------
|
||||||
|
private void BuildInventoryPanel()
|
||||||
|
{
|
||||||
|
var panel = new PanelContainer();
|
||||||
|
panel.SetAnchorsPreset(Control.LayoutPreset.TopRight);
|
||||||
|
panel.Position = new Vector2(-262, 12);
|
||||||
|
panel.CustomMinimumSize = new Vector2(250, 0);
|
||||||
|
var margin = new MarginContainer();
|
||||||
|
foreach (var s in new[] { "margin_left", "margin_right", "margin_top", "margin_bottom" })
|
||||||
|
margin.AddThemeConstantOverride(s, 8);
|
||||||
|
panel.AddChild(margin);
|
||||||
|
_invBox = new VBoxContainer();
|
||||||
|
margin.AddChild(_invBox);
|
||||||
|
AddChild(panel);
|
||||||
|
RefreshInventory();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshInventory()
|
||||||
|
{
|
||||||
|
foreach (var c in _invBox.GetChildren()) c.QueueFree();
|
||||||
|
var title = new Label { Text = $"Инвентарь ({_inventory.Count})" };
|
||||||
|
title.AddThemeColorOverride("font_color", new Color(0.95f, 0.9f, 0.7f));
|
||||||
|
_invBox.AddChild(title);
|
||||||
|
if (_inventory.Count == 0)
|
||||||
|
{
|
||||||
|
var e = new Label { Text = "пусто · ПКМ по персонажу" };
|
||||||
|
e.AddThemeColorOverride("font_color", new Color(0.7f, 0.72f, 0.78f));
|
||||||
|
_invBox.AddChild(e);
|
||||||
|
}
|
||||||
|
foreach (var it in _inventory.ToList())
|
||||||
|
{
|
||||||
|
var item = it;
|
||||||
|
var b = new Button { Text = $"{it.Name} · {TypeName(it.Type)}" };
|
||||||
|
b.Pressed += () => RespawnFromInventory(item);
|
||||||
|
_invBox.AddChild(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RespawnFromInventory(InvItem it)
|
||||||
|
{
|
||||||
|
var p = SpawnPawn(it.Scene, _rng.Next(Rows), it.Name, it.Type);
|
||||||
|
if (p != null) { _inventory.Remove(it); RefreshInventory(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SendToInventory(Pawn p)
|
||||||
|
{
|
||||||
|
RemoveFromRoom(p);
|
||||||
|
_pawns.Remove(p);
|
||||||
|
if (_selected == p) { _selected = null; _infoPanel.Visible = false; }
|
||||||
|
p.Node.QueueFree();
|
||||||
|
_inventory.Add(new InvItem { Name = p.DisplayName, Type = p.Type, Scene = p.BaseScene });
|
||||||
|
RefreshInventory();
|
||||||
|
}
|
||||||
|
|
||||||
private void BuildInfoPanel()
|
private void BuildInfoPanel()
|
||||||
{
|
{
|
||||||
_infoPanel = new PanelContainer { Position = new Vector2(16, 64), Visible = false };
|
_infoPanel = new PanelContainer { Position = new Vector2(16, 64), Visible = false };
|
||||||
@@ -97,14 +202,15 @@ public partial class RoomMap : Node2D
|
|||||||
private void ShowInfo(Pawn p)
|
private void ShowInfo(Pawn p)
|
||||||
{
|
{
|
||||||
_selected = p;
|
_selected = p;
|
||||||
|
string head = $"{p.DisplayName} · {TypeName(p.Type)}";
|
||||||
if (p.AssignedRoom != null)
|
if (p.AssignedRoom != null)
|
||||||
{
|
{
|
||||||
var r = p.AssignedRoom;
|
var r = p.AssignedRoom;
|
||||||
string mode = r.Occ.Count >= 2 ? "групповая" : "одиночная";
|
string mode = r.Count() >= 2 ? "групповая" : "одиночная";
|
||||||
_infoLabel.Text = $"Персонаж: {p.Name}\nНазначен: {r.Type} (слот {r.Occ.IndexOf(p) + 1}/{r.Cap})\nанимация: {mode}\nтащи мышью → убрать";
|
_infoLabel.Text = $"{head}\nНазначен: {r.Type} (слот {r.SlotOf(p) + 1}/{r.Cap})\nанимация: {mode}\nЛКМ тащить · ПКМ → инвентарь";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
_infoLabel.Text = $"Персонаж: {p.Name}\nЭтаж: {p.Row + 1}/{Rows}\nтащи мышью → назначить в комнату";
|
_infoLabel.Text = $"{head}\nЭтаж: {p.Row + 1}/{Rows}\nЛКМ тащить/назначить · ПКМ → инвентарь";
|
||||||
_infoPanel.Visible = true;
|
_infoPanel.Visible = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,10 +237,15 @@ public partial class RoomMap : Node2D
|
|||||||
|
|
||||||
_rooms = new List<Room>
|
_rooms = new List<Room>
|
||||||
{
|
{
|
||||||
new Room { Type = "Спальня", Col = 1, Row = 0, Span = 3, Cap = 2, States = new[] { "stand", "combat" } },
|
new Room { Type = "Спальня", Col = 1, Row = 0, Span = 3, States = new[] { "stand", "combat" },
|
||||||
new Room { Type = "Логово", Col = 0, Row = 2, Span = 1, Cap = 2, States = new[] { "milk", "birth", "down" } },
|
SlotTypes = new[] { CType.Player, CType.Slave } },
|
||||||
new Room { Type = "Дойка", Col = 4, Row = 3, Span = 1, Cap = 2, States = new[] { "milk", "milk2" } },
|
new Room { Type = "Логово", Col = 0, Row = 2, Span = 1, States = new[] { "suckle_left", "milk", "birth", "combat", "stand" },
|
||||||
|
SlotTypes = new[] { CType.Slave, CType.Monster } },
|
||||||
|
new Room { Type = "Дойка", Col = 4, Row = 3, Span = 1, States = new[] { "milk", "milk2" },
|
||||||
|
SlotTypes = new[] { CType.Slave, CType.Slave, CType.Child, CType.Child, CType.Child, CType.Child } },
|
||||||
};
|
};
|
||||||
|
foreach (var r in _rooms) r.Init();
|
||||||
|
BuildRoomHeaders();
|
||||||
|
|
||||||
// рамки поверх всех ячеек — читаемость сетки
|
// рамки поверх всех ячеек — читаемость сетки
|
||||||
for (int r = 0; r < Rows; r++)
|
for (int r = 0; r < Rows; r++)
|
||||||
@@ -195,40 +306,57 @@ public partial class RoomMap : Node2D
|
|||||||
_rng = new System.Random(20260803);
|
_rng = new System.Random(20260803);
|
||||||
(string path, int row)[] picks =
|
(string path, int row)[] picks =
|
||||||
{
|
{
|
||||||
("res://characters/elf1/elf1_combat_native.tscn", 0),
|
("res://characters/elf1/elf1_combat_native.tscn", 0), // раб
|
||||||
("res://characters/knight/knight_combat_native.tscn", 1),
|
("res://characters/sister/sister_combat_native.tscn", 1), // раб
|
||||||
("res://characters/shortstack/shortstack_combat_native.tscn", 2),
|
("res://characters/satyress/satyress_combat_native.tscn", 2), // раб
|
||||||
("res://characters/sister/sister_combat_native.tscn", 3),
|
("res://characters/knight/knight_combat_native.tscn", 3), // раб
|
||||||
("res://characters/satyress/satyress_combat_native.tscn", 4),
|
("res://characters/orc/orc_combat_native.tscn", 2), // монстр
|
||||||
|
("res://characters/baby/human_baby_native.tscn", 1), // ребёнок
|
||||||
|
("res://characters/baby/human_baby_native.tscn", 3), // ребёнок
|
||||||
};
|
};
|
||||||
|
foreach (var (path, row) in picks) SpawnPawn(path, row);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CType TypeOf(string name) =>
|
||||||
|
name == "player" ? CType.Player : name == "baby" ? CType.Child :
|
||||||
|
Monsters.Contains(name) ? CType.Monster : CType.Slave;
|
||||||
|
|
||||||
|
private string GenName(CType t)
|
||||||
|
{
|
||||||
|
var pool = t == CType.Monster ? MonsterNames : t == CType.Child ? ChildNames
|
||||||
|
: t == CType.Player ? new[] { "Игрок" } : SlaveNames;
|
||||||
|
return pool[_rng.Next(pool.Length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
private Pawn SpawnPawn(string path, int row, string name = null, CType? type = null)
|
||||||
|
{
|
||||||
|
if (!ResourceLoader.Exists(path)) return null;
|
||||||
|
var scene = ResourceLoader.Load<PackedScene>(path).Instantiate<Node2D>();
|
||||||
|
scene.Position = -FootAnchor * CharScale;
|
||||||
|
scene.Scale = new Vector2(CharScale, CharScale);
|
||||||
|
var node = new Node2D();
|
||||||
|
node.AddChild(scene);
|
||||||
|
_world.AddChild(node);
|
||||||
|
|
||||||
float minX = Cell * 0.4f, maxX = Cols * Cell - Cell * 0.4f;
|
float minX = Cell * 0.4f, maxX = Cols * Cell - Cell * 0.4f;
|
||||||
|
float x = (float)(_rng.NextDouble() * (maxX - minX) + minX);
|
||||||
|
node.Position = new Vector2(x, FloorY(row));
|
||||||
|
|
||||||
foreach (var (path, row) in picks)
|
var ap = scene.GetNodeOrNull<AnimationPlayer>("AnimationPlayer");
|
||||||
|
string[] anims = ap != null ? ap.GetAnimationList() : System.Array.Empty<string>();
|
||||||
|
string cname = path.Split('/')[3];
|
||||||
|
CType t = type ?? TypeOf(cname);
|
||||||
|
var p = new Pawn
|
||||||
{
|
{
|
||||||
if (!ResourceLoader.Exists(path)) continue;
|
Node = node, Ap = ap, Name = cname, BaseScene = path, Row = row,
|
||||||
var scene = ResourceLoader.Load<PackedScene>(path).Instantiate<Node2D>();
|
X = x, MinX = minX, MaxX = maxX,
|
||||||
scene.Position = -FootAnchor * CharScale;
|
Speed = 70f + (float)_rng.NextDouble() * 55f,
|
||||||
scene.Scale = new Vector2(CharScale, CharScale);
|
WalkAnim = Pick(anims, "walk_0"), IdleAnim = Pick(anims, "idle_0"),
|
||||||
|
Type = t, DisplayName = name ?? GenName(t)
|
||||||
var node = new Node2D();
|
};
|
||||||
node.AddChild(scene);
|
Decide(p);
|
||||||
_world.AddChild(node);
|
_pawns.Add(p);
|
||||||
|
return p;
|
||||||
float x = (float)(_rng.NextDouble() * (maxX - minX) + minX);
|
|
||||||
node.Position = new Vector2(x, FloorY(row));
|
|
||||||
|
|
||||||
var ap = scene.GetNodeOrNull<AnimationPlayer>("AnimationPlayer");
|
|
||||||
string[] anims = ap != null ? ap.GetAnimationList() : System.Array.Empty<string>();
|
|
||||||
var p = new Pawn
|
|
||||||
{
|
|
||||||
Node = node, Ap = ap, Name = path.Split('/')[3], BaseScene = path, Row = row,
|
|
||||||
X = x, MinX = minX, MaxX = maxX,
|
|
||||||
Speed = 70f + (float)_rng.NextDouble() * 55f,
|
|
||||||
WalkAnim = Pick(anims, "walk_0"), IdleAnim = Pick(anims, "idle_0")
|
|
||||||
};
|
|
||||||
Decide(p);
|
|
||||||
_pawns.Add(p);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string Pick(string[] anims, string want)
|
private static string Pick(string[] anims, string want)
|
||||||
@@ -341,11 +469,17 @@ public partial class RoomMap : Node2D
|
|||||||
int row = Mathf.Clamp((int)((p.Node.Position.Y - Cell * 0.45f) / Cell), 0, Rows - 1);
|
int row = Mathf.Clamp((int)((p.Node.Position.Y - Cell * 0.45f) / Cell), 0, Rows - 1);
|
||||||
|
|
||||||
var room = RoomAt(col, row);
|
var room = RoomAt(col, row);
|
||||||
if (room != null && (room.Occ.Contains(p) || room.Occ.Count < room.Cap))
|
if (room != null)
|
||||||
{
|
{
|
||||||
AssignToRoom(p, room);
|
int slot = room.SlotOf(p);
|
||||||
if (_selected == p) ShowInfo(p);
|
if (slot < 0) slot = room.FreeSlotFor(p.Type);
|
||||||
return;
|
if (slot >= 0)
|
||||||
|
{
|
||||||
|
AssignToRoom(p, room, slot);
|
||||||
|
if (_selected == p) ShowInfo(p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// нет свободного слота нужного типа — роняем на пол
|
||||||
}
|
}
|
||||||
|
|
||||||
// обычный сброс: снять назначение и вернуть боевую сцену
|
// обычный сброс: снять назначение и вернуть боевую сцену
|
||||||
@@ -365,10 +499,10 @@ public partial class RoomMap : Node2D
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AssignToRoom(Pawn p, Room room)
|
private void AssignToRoom(Pawn p, Room room, int slot)
|
||||||
{
|
{
|
||||||
if (p.AssignedRoom != null && p.AssignedRoom != room) RemoveFromRoom(p);
|
if (p.AssignedRoom != null && p.AssignedRoom != room) RemoveFromRoom(p);
|
||||||
if (!room.Occ.Contains(p)) room.Occ.Add(p);
|
room.SlotOcc[slot] = p;
|
||||||
p.AssignedRoom = room;
|
p.AssignedRoom = room;
|
||||||
p.State = PState.Assigned;
|
p.State = PState.Assigned;
|
||||||
|
|
||||||
@@ -381,31 +515,41 @@ public partial class RoomMap : Node2D
|
|||||||
{
|
{
|
||||||
var room = p.AssignedRoom;
|
var room = p.AssignedRoom;
|
||||||
if (room == null) return;
|
if (room == null) return;
|
||||||
room.Occ.Remove(p);
|
int slot = room.SlotOf(p);
|
||||||
|
if (slot >= 0) room.SlotOcc[slot] = null;
|
||||||
p.AssignedRoom = null;
|
p.AssignedRoom = null;
|
||||||
if (room.Occ.Count > 0) LayoutRoom(room);
|
LayoutRoom(room);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly Vector2 CenterAnchor = new Vector2(640f, 360f); // центр кадра 1280x720
|
private static readonly Vector2 CenterAnchor = new Vector2(640f, 360f); // центр кадра 1280x720
|
||||||
|
|
||||||
// расставить по слотам (центрируя в комнате) и включить анимацию: 1 — одиночную, 2+ — групповую
|
// расставить по слотам: основные (Игрок/Раб/Монстр) в ряд, дети — ниже и мельче
|
||||||
private void LayoutRoom(Room room)
|
private void LayoutRoom(Room room)
|
||||||
{
|
{
|
||||||
int n = room.Occ.Count;
|
bool group = room.Count() >= 2;
|
||||||
bool group = n >= 2;
|
var main = new List<int>();
|
||||||
float center = room.Col * Cell + room.Span * Cell * 0.5f;
|
var kids = new List<int>();
|
||||||
float band = room.Span * Cell * 0.5f;
|
for (int i = 0; i < room.Cap; i++)
|
||||||
float cellY = room.Row * Cell + Cell * 0.5f;
|
(room.SlotTypes[i] == CType.Child ? kids : main).Add(i);
|
||||||
for (int i = 0; i < n; i++)
|
PlaceGroup(room, main, group, Cell * 0.74f, 1f);
|
||||||
|
PlaceGroup(room, kids, group, Cell * 0.9f, 0.55f);
|
||||||
|
UpdateRoomHeader(room);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PlaceGroup(Room room, List<int> slots, bool group, float yOff, float scale)
|
||||||
|
{
|
||||||
|
int n = slots.Count;
|
||||||
|
for (int k = 0; k < n; k++)
|
||||||
{
|
{
|
||||||
var q = room.Occ[i];
|
var q = room.SlotOcc[slots[k]];
|
||||||
float sx = n == 1 ? center : center - band / 2f + band * (i / (float)(n - 1));
|
if (q == null) continue;
|
||||||
q.X = sx;
|
float t = n == 1 ? 0.5f : (k + 0.5f) / n;
|
||||||
// центр-анкор: центр персонажа (любого состояния) — в центр ячейки
|
float sx = room.Col * Cell + t * (room.Span * Cell);
|
||||||
if (q.Node.GetChildCount() > 0 && q.Node.GetChild(0) is Node2D sc)
|
if (q.Node.GetChildCount() > 0 && q.Node.GetChild(0) is Node2D sc)
|
||||||
sc.Position = -CenterAnchor * CharScale;
|
sc.Position = -CenterAnchor * CharScale;
|
||||||
q.Node.Position = new Vector2(sx, cellY);
|
q.X = sx;
|
||||||
q.Node.Scale = new Vector2(1f, 1f);
|
q.Node.Position = new Vector2(sx, room.Row * Cell + yOff);
|
||||||
|
q.Node.Scale = new Vector2(scale, scale);
|
||||||
var anims = q.Ap != null ? q.Ap.GetAnimationList() : System.Array.Empty<string>();
|
var anims = q.Ap != null ? q.Ap.GetAnimationList() : System.Array.Empty<string>();
|
||||||
string a = PickAction(anims, group);
|
string a = PickAction(anims, group);
|
||||||
if (q.Ap != null && a != null) q.Ap.Play(a);
|
if (q.Ap != null && a != null) q.Ap.Play(a);
|
||||||
@@ -548,6 +692,11 @@ public partial class RoomMap : Node2D
|
|||||||
_dragging = false;
|
_dragging = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (mb.ButtonIndex == MouseButton.Right && mb.Pressed)
|
||||||
|
{
|
||||||
|
var hit = PawnAt(ScreenToWorld(mb.Position));
|
||||||
|
if (hit != null) SendToInventory(hit);
|
||||||
|
}
|
||||||
else if (mb.Pressed && mb.ButtonIndex == MouseButton.WheelUp)
|
else if (mb.Pressed && mb.ButtonIndex == MouseButton.WheelUp)
|
||||||
ZoomAt(mb.Position, 1.1f);
|
ZoomAt(mb.Position, 1.1f);
|
||||||
else if (mb.Pressed && mb.ButtonIndex == MouseButton.WheelDown)
|
else if (mb.Pressed && mb.ButtonIndex == MouseButton.WheelDown)
|
||||||
@@ -556,7 +705,17 @@ public partial class RoomMap : Node2D
|
|||||||
else if (@event is InputEventMouseMotion mm)
|
else if (@event is InputEventMouseMotion mm)
|
||||||
{
|
{
|
||||||
if (_dragPawn != null)
|
if (_dragPawn != null)
|
||||||
|
{
|
||||||
_dragPawn.Node.Position = ScreenToWorld(mm.Position) + _dragOffset;
|
_dragPawn.Node.Position = ScreenToWorld(mm.Position) + _dragOffset;
|
||||||
|
var pos = _dragPawn.Node.Position;
|
||||||
|
int dcol = (int)(pos.X / Cell), drow = (int)((pos.Y - Cell * 0.45f) / Cell);
|
||||||
|
var room = RoomAt(Mathf.Clamp(dcol, 0, Cols - 1), Mathf.Clamp(drow, 0, Rows - 1));
|
||||||
|
_infoLabel.Text =
|
||||||
|
$"{_dragPawn.DisplayName} · {TypeName(_dragPawn.Type)}\n" +
|
||||||
|
$"DEBUG коорд: x={pos.X:0} y={pos.Y:0}\n" +
|
||||||
|
$"клетка: col={dcol} row={drow}" + (room != null ? $" → {room.Type}" : "");
|
||||||
|
_infoPanel.Visible = true;
|
||||||
|
}
|
||||||
else if (_dragging)
|
else if (_dragging)
|
||||||
_world.Position += mm.Relative;
|
_world.Position += mm.Relative;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user