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 ? "钻入地表" : "战斗超频");
}
}
}
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 ? "钻入地表" : "战斗超频");
}
}
}