XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

AshfallFrontier

【Unity】灰烬边境,一款生存策略游戏

公开
关注 0 Fork 0 Star 0
UTF-8
using System;
using System.Collections.Generic;
using System.Linq;

namespace Ashfall.Core
{
    public sealed partial class GameSimulation
    {
        public ActionResult Execute(string authenticatedPlayerId, GameCommand cmd)
        {
            var p = World.Player(authenticatedPlayerId);
            if (p == null || !p.connected) return ActionResult.Fail("玩家未连接");
            if (cmd == null || cmd.sequence <= p.lastCommand) return ActionResult.Fail("重复或过期指令");
            if (!cmd.position.Finite || !Enum.IsDefined(typeof(CommandKind), cmd.kind)
                || (cmd.targetId?.Length ?? 0) > 128 || (cmd.value?.Length ?? 0) > 128 || (cmd.slot?.Length ?? 0) > 128)
                return ActionResult.Fail("无效指令");
            p.lastCommand = cmd.sequence;
            if (p.transitionId != "") return ActionResult.Fail("正在通过连接通道");
            ActionResult result;
            switch (cmd.kind)
            {
                case CommandKind.Interact: result = Interact(p, cmd.targetId); break;
                case CommandKind.LeaveStation: ReleaseStation(p); result = ActionResult.Ok("已离开操作台"); break;
                case CommandKind.InstallModule: result = Install(p, cmd); break;
                case CommandKind.Build: result = Build(p, cmd); break;
                case CommandKind.Dismantle: result = Dismantle(p, cmd.targetId); break;
                case CommandKind.Research: result = Research(p, cmd.targetId); break;
                case CommandKind.Craft: result = Craft(p, cmd); break;
                case CommandKind.Transfer: result = Transfer(p, cmd); break;
                case CommandKind.Cruise: result = SetCruise(p); break;
                case CommandKind.ChangeAltitude: result = ChangeAltitude(p); break;
                case CommandKind.Repair: result = Repair(p, cmd.targetId); break;
                case CommandKind.SwitchSpecies: result = SwitchSpecies(p, cmd.value); break;
                case CommandKind.Ability: result = Ability(p); break;
                case CommandKind.Collect: result = Collect(p, cmd.targetId); break;
                case CommandKind.Evolve: result = Evolve(p, cmd.targetId); break;
                default: result = ActionResult.Fail("未实现的指令"); break;
            }
            if (result.success) CriticalChange?.Invoke();
            return result;
        }

        private ActionResult Interact(PlayerState p, string target)
        {
            if (p.stationId != "") { ReleaseStation(p); return ActionResult.Ok("已离开操作台"); }
            var seat = FindStation(target);
            if (seat != null)
            {
                if (!Near(p, seat.location)) return ActionResult.Fail("请走到操作台旁");
                if (seat.playerId != "") return ActionResult.Fail("岗位已被队友占用");
                if (p.burrowUntil > World.time || p.location.height > 0) return ActionResult.Fail("当前移动状态不能操作设备");
                seat.playerId = p.id; p.stationId = seat.id; p.preferredStationId = seat.id;
                p.location.position = seat.location.position; p.input = new PlayerInput { sequence = p.input.sequence };
                return ActionResult.Ok(seat.role == StationRole.Driver ? "WASD 驾驶 · 鼠标独立瞄准 · E 返回舱内" : "已接管主武器组 · E 返回舱内");
            }
            var f = World.facilities.Find(x => x.id == target);
            if (f != null)
            {
                if (!Near(p, f.location)) return ActionResult.Fail("请靠近设施");
                if (f.kind == FacilityKind.Generator)
                {
                    f.powered = !f.powered;
                    foreach (var other in World.facilities.Where(x => x.location.spaceId == f.location.spaceId)) other.powered = f.powered;
                    return ActionResult.Ok(f.powered ? "供电已恢复" : "供电已关闭");
                }
                if (f.kind == FacilityKind.Medical)
                { if (!f.powered) return ActionResult.Fail("设施缺少供能"); p.health = p.maxHealth; p.energy = 100; return ActionResult.Ok("生命与能量已恢复"); }
                return ActionResult.Ok("已连接:" + f.name);
            }
            return Collect(p, target);
        }

        private ActionResult Collect(PlayerState p, string id)
        {
            if (p.stationId != "") return ActionResult.Fail("先离开操作台");
            var node = World.resources.Find(x => x.id == id);
            if (node == null || !Near(p, node.location, 2)) return ActionResult.Fail("附近没有可采集物");
            if (!p.inventory.Add(node.itemId, node.amount)) return ActionResult.Fail("背包空间不足");
            World.resources.Remove(node);
            return ActionResult.Ok("获得 " + node.itemId + " × " + node.amount);
        }

        private ActionResult Research(PlayerState p, string target)
        {
            var f = World.facilities.Find(x => x.id == target && x.kind == FacilityKind.Research);
            if (f == null || !Near(p, f.location)) return ActionResult.Fail("请在研究设施旁操作");
            if (!f.powered) return ActionResult.Fail("请先恢复供电");
            var family = p.species == Species.Human ? Family.Mechanical : Family.Biological;
            if (f.family != family) return ActionResult.Fail("研究由对应种族进行,研究成果全队共享");
            string research = family == Family.Mechanical ? "mechanical.weapons" : "biological.weapons";
            if (World.research.Contains(research)) return ActionResult.Fail("已完成这项研究");
            var storage = Supply(p);
            string material = family == Family.Mechanical ? "metal" : "biomass";
            if (!storage.Has("sample", 2) || !storage.Has(material, 20)) return ActionResult.Fail("设施仓储需要样本 ×2 和材料 ×20");
            storage.Take("sample", 2); storage.Take(material, 20); World.research.Add(research);
            return ActionResult.Ok("已解锁重型武器改装及制造");
        }

        private ActionResult Evolve(PlayerState p, string target)
        {
            if (!p.IsWorm) return ActionResult.Fail("只有虫族蠕虫幼体需要首次蜕变");
            var f = World.facilities.Find(x => x.id == target && x.family == Family.Biological
                && (x.kind == FacilityKind.Medical || x.kind == FacilityKind.Research));
            if (f == null || !Near(p, f.location) || !f.powered) return ActionResult.Fail("请靠近已供能的再生茧或进化设施");
            if (!p.inventory.Has("biomass", 20) || !p.inventory.Has("sample", 1)) return ActionResult.Fail("随身需要生物质 ×20、样本 ×1");
            p.inventory.Take("biomass", 20); p.inventory.Take("sample", 1);
            p.broodForm = BroodForm.Adult; p.burrowUntil = 0; p.energy = 100; RefreshHealth(p, true);
            return ActionResult.Ok("蜕变完成:掘袭猎手 · 解锁骨针与完整钻地");
        }

        private ActionResult Craft(PlayerState p, GameCommand cmd)
        {
            var f = World.facilities.Find(x => x.id == cmd.targetId && x.kind == FacilityKind.Workshop);
            var recipe = Content.Recipe(cmd.value);
            if (f == null || recipe == null || !Near(p, f.location)) return ActionResult.Fail("请靠近对应制造设施");
            if (!f.powered || f.health <= 0) return ActionResult.Fail("设施不可用");
            if (recipe.family != f.family) return ActionResult.Fail("制造体系不兼容");
            if (f.jobs.Count >= 8) return ActionResult.Fail("生产队列已满");
            var module = Content.Module(recipe.id);
            if (module != null && !string.IsNullOrEmpty(module.researchId) && !World.research.Contains(module.researchId)) return ActionResult.Fail("需要先研究重型武器");
            var storage = Supply(p);
            if (recipe.inputs.Any(i => !storage.Has(i.id, i.amount))) return ActionResult.Fail("设施仓储材料不足");
            foreach (var item in recipe.inputs) storage.Take(item.id, item.amount);
            f.jobs.Add(new ProductionJob { id = World.NewId("job"), recipeId = recipe.id, outputId = recipe.outputId,
                outputAmount = recipe.outputAmount, remaining = recipe.seconds });
            return ActionResult.Ok("已加入生产队列");
        }

        private void TickProduction(float dt)
        {
            foreach (var f in World.facilities)
            {
                var vehicle = World.VehicleForSpace(f.location.spaceId);
                if (!f.powered || f.health <= 0 || f.jobs.Count == 0 || (vehicle != null && (vehicle.power <= 0 || vehicle.energy <= 0))) continue;
                var job = f.jobs[0]; job.remaining = Math.Max(0, job.remaining - dt);
                if (job.remaining > 0) continue;
                var storage = vehicle?.cargo ?? World.warehouse;
                // Retain a completed job when storage is full. No double spend and no lost output.
                if (storage.Add(job.outputId, job.outputAmount)) f.jobs.RemoveAt(0);
            }
        }

        private ActionResult Transfer(PlayerState p, GameCommand cmd)
        {
            var f = World.facilities.Find(x => x.id == cmd.targetId && x.kind == FacilityKind.Storage);
            if (f == null || !Near(p, f.location)) return ActionResult.Fail("请靠近仓储设施");
            if (cmd.amount <= 0 || cmd.amount > 10000) return ActionResult.Fail("数量无效");
            var storage = World.VehicleForSpace(f.location.spaceId)?.cargo ?? World.warehouse;
            bool success = cmd.slot == "deposit" ? Inventory.Transfer(p.inventory, storage, cmd.value, cmd.amount)
                : cmd.slot == "withdraw" && Inventory.Transfer(storage, p.inventory, cmd.value, cmd.amount);
            return success ? ActionResult.Ok("物资转移完成") : ActionResult.Fail("数量不足或目标仓储已满");
        }

        public ActionResult ValidateModule(VehicleState v, HardpointState slot, ModuleDefinition module)
        {
            if (v == null || slot == null || module == null) return ActionResult.Fail("载具、挂点或模块不存在");
            if (module.family != v.family) return ActionResult.Fail("机械与生物模块不能混装");
            if (module.size > slot.size) return ActionResult.Fail("挂点尺寸不足");
            if (module.researchId != null && !World.research.Contains(module.researchId)) return ActionResult.Fail("尚未解锁对应研究");
            float mass = module.mass, power = module.power;
            foreach (var hp in v.hardpoints.Where(h => h.id != slot.id))
            { var m = Content.Module(hp.moduleId); if (m != null) { mass += m.mass; power += m.power; } }
            if (mass > v.massLimit) return ActionResult.Fail("超过模块承重");
            if (power > v.powerBudget) return ActionResult.Fail("超过供能预算");
            return ActionResult.Ok();
        }

        private ActionResult Install(PlayerState p, GameCommand cmd)
        {
            var v = World.Vehicle(cmd.targetId);
            if (v == null || p.location.spaceId != v.spaceId || p.stationId != "") return ActionResult.Fail("请进入载具并离开操作台");
            if (!World.facilities.Any(f => f.location.spaceId == v.spaceId && f.kind == FacilityKind.Workshop && Near(p, f.location))) return ActionResult.Fail("请前往维修制造台");
            if (Math.Abs(v.speed) > .5f || v.flightMode != FlightMode.Ground) return ActionResult.Fail("载具必须落地停驻");
            var slot = v.hardpoints.Find(h => h.id == cmd.slot); var module = Content.Module(cmd.value);
            var validation = ValidateModule(v, slot, module); if (!validation.success) return validation;
            if (slot.moduleId == module.id) return ActionResult.Fail("已安装该模块");
            if (!v.cargo.Has(module.itemId, 1)) return ActionResult.Fail("货仓缺少该模块");
            var old = Content.Module(slot.moduleId);
            v.cargo.Take(module.itemId, 1); if (old != null) v.cargo.Add(old.itemId, 1);
            slot.moduleId = module.id; slot.health = 100; slot.readyAt = World.time + .3;
            return ActionResult.Ok("模块安装完成");
        }

        private ActionResult SetCruise(PlayerState p)
        {
            var s = FindStation(p.stationId); var v = StationVehicle(p.stationId);
            if (s == null || s.role != StationRole.Driver) return ActionResult.Fail("需在驾驶台操作");
            v.cruise = !v.cruise; return ActionResult.Ok(v.cruise ? "巡航开启,可离开驾驶台" : "巡航关闭");
        }
        private ActionResult ChangeAltitude(PlayerState p)
        {
            var s = FindStation(p.stationId); var v = StationVehicle(p.stationId);
            if (s == null || s.role != StationRole.Driver || !v.flying) return ActionResult.Fail("需在航空载具驾驶台操作");
            if (Math.Abs(v.speed) > .5f) return ActionResult.Fail("请先悬停");
            FlightMode next = (FlightMode)(((int)v.flightMode + 1) % 3), old = v.flightMode;
            v.flightMode = next;
            if (!CanVehicleOccupy(v, v.position, v.heading)) { v.flightMode = old; return ActionResult.Fail("此处不能降落"); }
            v.doorOpen = next == FlightMode.Ground;
            return ActionResult.Ok("高度状态:" + next);
        }
        private ActionResult Repair(PlayerState p, string id)
        {
            var v = World.Vehicle(id);
            if (v == null || p.location.spaceId != v.spaceId || !World.facilities.Any(f => f.kind == FacilityKind.Workshop && Near(p, f.location))) return ActionResult.Fail("请前往载具维修台");
            string material = v.family == Family.Mechanical ? "metal" : "biomass";
            if (!v.cargo.Take(material, 10)) return ActionResult.Fail("货仓维修材料不足");
            v.hull = Math.Min(v.maxHull, v.hull + 200); v.engine = Math.Min(100, v.engine + 40);
            v.power = Math.Min(100, v.power + 40); v.energy = Math.Min(v.maxEnergy, v.energy + 25);
            foreach (var hp in v.hardpoints) hp.health = Math.Min(100, hp.health + 40);
            return ActionResult.Ok("维修及补给完成");
        }
        private ActionResult SwitchSpecies(PlayerState p, string value)
        {
            if (p.stationId != "" || !World.facilities.Any(f => f.kind == FacilityKind.Medical && Near(p, f.location))) return ActionResult.Fail("只能在复苏设施旁切换种族");
            if (!Enum.TryParse(value, out Species species) || !Enum.IsDefined(typeof(Species), species)) return ActionResult.Fail("无效种族");
            p.species = species; p.burrowUntil = 0; p.location.height = 0; p.energy = 100; RefreshHealth(p, true);
            return ActionResult.Ok(p.IsWorm ? "虫族:蠕虫幼体" : "角色切换完成");
        }
        private ActionResult Ability(PlayerState p)
        {
            if (p.stationId != "" || World.time < p.abilityReadyAt || p.energy < 25) return ActionResult.Fail("技能不可用");
            if (p.species == Species.Brood)
            {
                if (p.location.spaceId != "world" || p.location.height > 0) return ActionResult.Fail("钻地只适用于室外自然地表");
                p.burrowUntil = World.time + (p.IsWorm ? 3 : 8);
                p.abilityReadyAt = p.burrowUntil + 7;
            }
            else { p.buffUntil = World.time + 6; p.abilityReadyAt = World.time + 12; }
            p.energy -= 25;
            return ActionResult.Ok(p.species == Species.Brood ? "钻入地表" : "战斗超频");
        }
    }
}