Поход «Разведка» (решения 31.10, п. 2): до цели и обратно без боя, сбора и потерь, обычный слот

IWorld.TryStartScout, MarchData.scout, WorldEventType.ScoutArrived; кнопка «Разведка» в окне атаки;
разведка не разбивает лагерь и не занимает точку.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Alexander
2026-11-01 13:11:55 +01:00
co-authored by Claude Opus 5.5
parent 24268f3cfb
commit 33db41002e
14 changed files with 208 additions and 17 deletions
+6 -4
View File
@@ -113,7 +113,8 @@ public static class ArmiesWindow
switch (m.state)
{
case MarchState.Outbound:
action = m.gather ? $"идёт на сбор: <b>{target}</b>" : $"идёт в бой: <b>{target}</b>";
action = m.scout ? $"идёт в разведку: <b>{target}</b>"
: m.gather ? $"идёт на сбор: <b>{target}</b>" : $"идёт в бой: <b>{target}</b>";
timer = $"до цели {Clock(m.arriveMs - now)}, вернётся примерно через {Clock(ExpectedReturn(m) - now)}";
break;
case MarchState.Gathering:
@@ -121,7 +122,8 @@ public static class ArmiesWindow
timer = $"сбор ещё {Clock(m.gatherEndMs - now)}, вернётся через {Clock(ExpectedReturn(m) - now)}";
break;
default:
action = (m.gather ? "возвращается со сбора: " : m.victory ? "возвращается с победой: " : "возвращается: ") + $"<b>{target}</b>";
action = (m.scout ? "возвращается из разведки: " : m.gather ? "возвращается со сбора: "
: m.victory ? "возвращается с победой: " : "возвращается: ") + $"<b>{target}</b>";
timer = $"дома через {Clock(m.returnMs - now)}";
break;
}
@@ -183,7 +185,7 @@ public static class ArmiesWindow
{
switch (m.state)
{
case MarchState.Outbound: return m.gather ? new Color(0.25f, 0.55f, 0.3f) : new Color(0.7f, 0.25f, 0.2f);
case MarchState.Outbound: return m.scout ? new Color(0.45f, 0.45f, 0.55f) : m.gather ? new Color(0.25f, 0.55f, 0.3f) : new Color(0.7f, 0.25f, 0.2f);
case MarchState.Gathering: return new Color(0.75f, 0.6f, 0.15f);
default: return new Color(0.25f, 0.45f, 0.75f);
}
@@ -193,7 +195,7 @@ public static class ArmiesWindow
{
switch (m.state)
{
case MarchState.Outbound: return m.gather ? "С" : "Б"; // на сбор / в бой
case MarchState.Outbound: return m.scout ? "Р" : m.gather ? "С" : "Б"; // разведка / на сбор / в бой
case MarchState.Gathering: return "Д"; // добыча
default: return "В"; // возвращается
}
+1 -1
View File
@@ -124,7 +124,7 @@ public class MarchView : MonoBehaviour
long secondsLeft = System.Math.Max(0, (endMs - nowMs + 999) / 1000);
string direction = returning ? (march.cargo > 0 ? $"домой, груз {march.cargo}" : "домой")
: gathering ? $"сбор {march.cargo}"
: march.gather ? "на сбор" : "в бой";
: march.scout ? "разведка" : march.gather ? "на сбор" : "в бой";
// Марши идут часами (регламент 31.10) -- «1:05:30», меньше часа -- «12:30»
string time = secondsLeft >= 3600
? $"{secondsLeft / 3600}:{secondsLeft / 60 % 60:00}:{secondsLeft % 60:00}"
@@ -106,6 +106,7 @@ public class WorldMapController : MonoBehaviour
if (circleNavButton != null) circleNavButton.onClick.AddListener(CircleWindow.Open); // модуль Круга
HookUpComingSoon(settlementNavButton, "Поселение");
sendButton.onClick.AddListener(OnSendPressed);
CreateScoutButton();
cancelButton.onClick.AddListener(CloseAttackPanel);
popupOkButton.onClick.AddListener(ShowNextPopup);
soldiersSlider.onValueChanged.AddListener(_ => { UpdateSoldiersToSendText(); if (attackPanel.activeSelf) RefreshAttackConditions(); });
@@ -124,6 +125,7 @@ public class WorldMapController : MonoBehaviour
if (MarchManager.Instance == null) return;
MarchManager.Instance.OnBattleResolved += HandleBattleResolved;
MarchManager.Instance.OnGatherStarted += HandleGatherStarted;
MarchManager.Instance.OnScoutArrived += HandleScoutArrived;
MarchManager.Instance.OnMarchReturned += HandleMarchReturned;
}
@@ -132,6 +134,7 @@ public class WorldMapController : MonoBehaviour
if (MarchManager.Instance == null) return;
MarchManager.Instance.OnBattleResolved -= HandleBattleResolved;
MarchManager.Instance.OnGatherStarted -= HandleGatherStarted;
MarchManager.Instance.OnScoutArrived -= HandleScoutArrived;
MarchManager.Instance.OnMarchReturned -= HandleMarchReturned;
}
@@ -165,6 +168,41 @@ public class WorldMapController : MonoBehaviour
button.onClick.AddListener(ArmiesWindow.Open);
}
// Кнопка «Разведка» в окне атаки (решения 31.10, п. 2) -- копия «Отправить». Три кнопки в ряд: Отмена, Разведка, Отправить
private Button scoutButton;
void CreateScoutButton()
{
var copy = Instantiate(sendButton.gameObject, sendButton.transform.parent);
copy.name = "ScoutButton";
scoutButton = copy.GetComponent<Button>();
scoutButton.onClick.RemoveAllListeners();
scoutButton.onClick.AddListener(OnScoutPressed);
var label = copy.GetComponentInChildren<TMP_Text>();
if (label != null) label.text = "Разведка";
Place(cancelButton, -290f);
Place(scoutButton, 0f);
Place(sendButton, 290f);
}
static void Place(Button button, float x)
{
var rt = (RectTransform)button.transform;
rt.anchoredPosition = new Vector2(x, rt.anchoredPosition.y);
rt.sizeDelta = new Vector2(Mathf.Min(rt.sizeDelta.x, 260f), rt.sizeDelta.y);
}
void OnScoutPressed()
{
if (selectedTarget == null) return;
int soldiers = (int)soldiersSlider.value;
hintText.text = MarchManager.Instance.TryStartScout(selectedTarget.id, soldiers, out string error)
? $"Разведка выступила: {soldiers} воинов идут к цели «{selectedTarget.displayName}» и вернутся без боя"
: "Разведка не начата: " + error;
CloseAttackPanel();
}
void HookUpComingSoon(Button button, string sectionName)
{
if (button == null) return;
@@ -415,6 +453,7 @@ public class WorldMapController : MonoBehaviour
soldiersSlider.interactable = available > 0;
bool slotFree = !GameServices.TryGet(out IArmy slotsArmy) || slotsArmy.ActiveMarches < slotsArmy.MarchSlots;
sendButton.interactable = available > 0 && slotFree;
if (scoutButton != null) scoutButton.interactable = available > 0 && slotFree;
UpdateSoldiersToSendText();
RefreshAttackConditions(); // путь -- по составу при выбранном числе воинов
@@ -669,6 +708,14 @@ public class WorldMapController : MonoBehaviour
EnqueuePopup(title, body);
}
void HandleScoutArrived(MarchData march)
{
string target = World.TargetName(march);
hintText.text = march.targetEmpty
? $"Разведка: «{target}» уже нет, войско возвращается"
: $"Разведка дошла до цели «{target}» и возвращается домой";
}
void HandleGatherStarted(MarchData march)
{
string target = World.TargetName(march);