Polishes
This commit is contained in:
@@ -76,21 +76,24 @@ namespace ProjectM.Client
|
||||
Body(c, "Build menu — Tab / Y");
|
||||
Body(c, "Place / Cancel (in build) — LMB / RMB (A / B on gamepad)");
|
||||
Body(c, "Deposit at base — G");
|
||||
Body(c, "Ready up (launch a run) — T");
|
||||
Body(c, "Boons / route map / shop — mouse click");
|
||||
|
||||
Body(c, "Inventory — I");
|
||||
Body(c, "Pause — Esc");
|
||||
break;
|
||||
case 1: // The Loop
|
||||
Head(c, "THE LOOP — expeditions are how you win");
|
||||
Body(c, "1. BASE (Calm) — mine Ore, build Turrets + a Fabricator to defend your Engine Core.");
|
||||
Body(c, "2. EXPEDITION — walk to the Gate and fight the wave. CLEARING it is the progress beat.");
|
||||
Body(c, "3. RETURN — come home to bank the clear: +1 on the Engine meter.");
|
||||
Body(c, "4. SIEGE — returning provokes a retaliation attack. Defend the Core!");
|
||||
Body(c, "5. WIN — fill the Engine meter, then hold the final siege.");
|
||||
Body(c, "The Engine meter (top of screen) is the goal — base sieges are a consequence, not the win.");
|
||||
Head(c, "THE LOOP — expedition RUNS are how you win");
|
||||
Body(c, "1. BASE — build Turrets + a Fabricator around your Engine Core; spend Aether on PERMANENT class upgrades.");
|
||||
Body(c, "2. READY UP [T] — when everyone is ready, the party launches into a multi-room run together.");
|
||||
Body(c, "3. RUN — clear each room, pick 1 of 3 BOONS (this run only), choose your path on the map, mine the crystals.");
|
||||
Body(c, "4. BOSS — fell it and the party returns with the haul: +1 on the Engine meter. A wipe banks nothing.");
|
||||
Body(c, "5. SIEGE — a completed run provokes retaliation at base. Defend the Core!");
|
||||
Body(c, "6. WIN — fill the Engine meter, then hold the final siege.");
|
||||
break;
|
||||
case 2: // Build & Economy
|
||||
Head(c, "RESOURCES & BUILDING");
|
||||
Body(c, "Ore — main currency. Mine it by attacking the glowing nodes at base.");
|
||||
Body(c, "Ore — main currency. Attack the glowing crystals INSIDE runs and haul them home (they're scarce — spend well).");
|
||||
Body(c, "Turret (40 Ore) — auto-fires at enemies. Needs Charge as ammo.");
|
||||
Body(c, "Fabricator (30 Ore) — converts Ore → Charge so turrets keep firing.");
|
||||
Body(c, "Wall (Biomass) — a cheap barrier that blocks enemies.");
|
||||
@@ -101,7 +104,7 @@ namespace ProjectM.Client
|
||||
Head(c, "THREATS");
|
||||
Body(c, "Husks assault the base during a Siege — keep them off the Engine Core.");
|
||||
Body(c, "A Husk that reaches the Core drains it. Lose the Core in the final siege and the run ends.");
|
||||
Body(c, "Expeditions throw waves at you — clear them all to bank the win.");
|
||||
Body(c, "Runs escalate room by room — elites guard the deep paths, a boss guards the end.");
|
||||
Body(c, "Enemy variety scales the deeper you push.");
|
||||
break;
|
||||
default: // Win / Lose
|
||||
|
||||
@@ -80,6 +80,17 @@ namespace ProjectM.Client
|
||||
_mainPanel = MenuUi.FullScreenRoot(true);
|
||||
var card = MenuUi.Card("PROJECT M");
|
||||
card.Add(MenuUi.Caption("Frontier colony — co-op"));
|
||||
// Why the last session ended (connection watchdog / bad join address) — shown once, then cleared.
|
||||
if (!string.IsNullOrEmpty(SessionEnd.Reason))
|
||||
{
|
||||
var reason = MenuUi.Caption(SessionEnd.Reason);
|
||||
reason.style.color = new Color(1f, 0.55f, 0.35f);
|
||||
reason.style.whiteSpace = WhiteSpace.Normal;
|
||||
reason.style.maxWidth = 340;
|
||||
SessionEnd.Reason = null;
|
||||
card.Add(reason);
|
||||
}
|
||||
|
||||
// Slice 2: class picker -> sets WorldLauncher.SelectedClass for the next session (Warrior melee / Ranger ranged).
|
||||
_classLabel = new Label(ClassName(WorldLauncher.SelectedClass));
|
||||
_classLabel.style.unityTextAlign = TextAnchor.MiddleCenter;
|
||||
|
||||
@@ -31,10 +31,16 @@ namespace ProjectM.Client
|
||||
/// <summary>Slice 2: the class chosen in the menu (a CharacterId byte), seeded into the client world at session start.</summary>
|
||||
public static byte SelectedClass = (byte)CharacterId.Warrior;
|
||||
|
||||
/// <summary>The mode of the most recently started session — the HUD's outcome banner branches on it
|
||||
/// (single: PLAY AGAIN restarts; co-op: the honest exit is a clean teardown for everyone).</summary>
|
||||
public static SessionMode LastMode { get; private set; } = SessionMode.Single;
|
||||
|
||||
|
||||
public static void StartSession(SessionMode mode, string joinIp, bool loadSave)
|
||||
{
|
||||
if (Busy) return;
|
||||
Busy = true;
|
||||
LastMode = mode;
|
||||
SessionRunner.Run(StartRoutine(mode, joinIp, loadSave));
|
||||
}
|
||||
|
||||
@@ -47,6 +53,12 @@ namespace ProjectM.Client
|
||||
|
||||
static IEnumerator StartRoutine(SessionMode mode, string joinIp, bool loadSave)
|
||||
{
|
||||
// A LIVE session restarting in place (the banner's PLAY AGAIN) checkpoints first — the teardown
|
||||
// path saves, so this path must too or the terminal state (outcome, last meta buys) is dropped.
|
||||
var liveServer = ClientServerBootstrap.ServerWorld;
|
||||
if (liveServer is { IsCreated: true })
|
||||
TrySaveFromServer(liveServer);
|
||||
|
||||
// Dispose the idle menu world so a netcode world can own DefaultGameObjectInjectionWorld (the
|
||||
// subscene then streams into the netcode worlds, exactly as in the always-on bootstrap flow).
|
||||
World.DisposeAllWorlds();
|
||||
@@ -117,6 +129,10 @@ namespace ProjectM.Client
|
||||
static void StagePendingSave(World server)
|
||||
{
|
||||
var data = SaveService.Load();
|
||||
// A terminal (won/lost) save Continues as a FRESH campaign — base+meta kept, outcome/meter/core reset
|
||||
// (else the dead outcome banner re-latches from the first snapshot).
|
||||
SaveService.RollTerminalCampaignForward(data);
|
||||
|
||||
if (data == null) return;
|
||||
var em = server.EntityManager;
|
||||
var e = em.CreateEntity();
|
||||
|
||||
Reference in New Issue
Block a user