// Console commands of the player (DESIGN_UE.md section 9.3): M2 Place, PlaceLocal, MoveTo, Look, Use, Mode; M3 Set, Swim, PoolDrop, Climb. // (Descent.Player.Intent lives in DescentCommands_Intent.cpp, with the sim core that owns the latch.) #include "Core/DescentSimSubsystem.h" #include "Debug/DescentCommandUtil.h" #include "Player/DescentCharacter.h" #include "Player/DescentPlayerController.h" #include "Player/DescentVitals.h" #include "DescentUnits.h" #include "Vehicles/CarrierLayout.h" #include "Vehicles/DescentCarrier.h" #include "TheDescent.h" #include "Engine/World.h" #include "HAL/IConsoleManager.h" namespace { ADescentCharacter* PlayerCmdCharacter(UWorld* World, const TCHAR* Cmd) { const ADescentPlayerController* PC = World ? Cast(World->GetFirstPlayerController()) : nullptr; ADescentCharacter* C = PC ? PC->GetDescentCharacter() : nullptr; if (!C || !UDescentCarrierSubsystem::GetCarrier(World)) { Descent::Cmd::Fail(World, Cmd, TEXT("needs a running game with a character and the carrier")); return nullptr; } return C; } void CmdPlayerPlace(const TArray& Args, UWorld* World) { ADescentCharacter* C = PlayerCmdCharacter(World, TEXT("Descent.Player.Place")); if (!C) { return; } const Descent::Carrier::FRoomDef* R = Args.Num() > 0 ? Descent::Carrier::FLayout::Get().FindRoom(FName(*Args[0])) : nullptr; if (!R) { Descent::Cmd::Fail(World, TEXT("Descent.Player.Place"), TEXT("usage: Descent.Player.Place (bridge q1 q2 q3 q4 hab fab comp corr3 stair galley cargo refinery engine corr2 bay)")); return; } C->PlaceOnCarrier(FVector(R->Stop.X, R->Stop.Y, R->FloorZ), R->StopYawDeg, 0.0); UE_LOG(LogDescent, Display, TEXT("Player.Place: %s at carrier-local (%.2f, %.2f, %.2f)"), *R->Id.ToString(), R->Stop.X, R->Stop.Y, R->FloorZ); } void CmdPlayerPlaceLocal(const TArray& Args, UWorld* World) { TArray N; if (!Descent::Cmd::ParseNumbers(Args, 0, 4, N)) { Descent::Cmd::Fail(World, TEXT("Descent.Player.PlaceLocal"), TEXT("usage: Descent.Player.PlaceLocal x y z yawDeg (carrier-local metres, z = feet)")); return; } if (ADescentCharacter* C = PlayerCmdCharacter(World, TEXT("Descent.Player.PlaceLocal"))) { C->PlaceOnCarrier(FVector(N[0], N[1], N[2]), N[3], 0.0); } } void CmdPlayerMoveTo(const TArray& Args, UWorld* World) { ADescentCharacter* C = PlayerCmdCharacter(World, TEXT("Descent.Player.MoveTo")); if (!C) { return; } const Descent::Carrier::FLayout& L = Descent::Carrier::FLayout::Get(); const FVector Feet = C->GetFeetLocalM(); TArray Way; FString Label; bool bOk = false; if (Args.Num() == 1) { Label = Args[0]; bOk = L.FindRoute(Feet, FName(*Args[0]), nullptr, Way); } else { TArray N; if (Descent::Cmd::ParseNumbers(Args, 0, 2, N)) { Label = FString::Printf(TEXT("(%.1f, %.1f)"), N[0], N[1]); const FVector2D Target(N[0], N[1]); // the room of the target on the deck we stand on const Descent::Carrier::FRoomDef* Here = L.RoomAt(Feet + FVector(0, 0, 0.3)); const Descent::Carrier::FRoomDef* There = nullptr; for (const Descent::Carrier::FRoomDef& R : L.Rooms) { if (R.ContainsXY(N[0], N[1]) && Here && R.FloorZ <= Here->FloorZ + 0.01 && R.CeilZ >= Feet.Z + 0.3) { There = &R; if (&R == Here) { break; } } } if (There && Here == There) { Way.Add(Target); bOk = true; } else if (There) { bOk = L.FindRoute(Feet, There->Id, &Target, Way); } } } if (!bOk || !C->StartAutoWalk(Way, Label)) { Descent::Cmd::Fail(World, TEXT("Descent.Player.MoveTo"), TEXT("usage: Descent.Player.MoveTo or (carrier-local); no route found")); return; } UE_LOG(LogDescent, Display, TEXT("Player.MoveTo: walking to %s through %d waypoint(s)"), *Label, Way.Num()); } void CmdPlayerLook(const TArray& Args, UWorld* World) { TArray N; if (!Descent::Cmd::ParseNumbers(Args, 0, 2, N)) { Descent::Cmd::Fail(World, TEXT("Descent.Player.Look"), TEXT("usage: Descent.Player.Look yawDeg pitchDeg (yaw relative to the carrier bow, pitch up positive)")); return; } if (ADescentCharacter* C = PlayerCmdCharacter(World, TEXT("Descent.Player.Look"))) { C->SetViewLocal(N[0], N[1]); } } void CmdPlayerUse(const TArray&, UWorld* World) { if (ADescentCharacter* C = PlayerCmdCharacter(World, TEXT("Descent.Player.Use"))) { // E, whatever the mode: on foot the focus, in a Tender dock / leave, swimming the ladder or a Tender if (ADescentPlayerController* PC = Cast(C->GetController())) { PC->PressUse(); } } } void CmdPlayerSet(const TArray& Args, UWorld* World) { ADescentCharacter* C = PlayerCmdCharacter(World, TEXT("Descent.Player.Set")); TArray N; if (!C || Args.Num() < 2 || !Descent::Cmd::ParseNumbers(Args, 1, 1, N)) { Descent::Cmd::Fail(World, TEXT("Descent.Player.Set"), TEXT("usage: Descent.Player.Set value")); return; } FDescentVitalsState& V = C->Vitals->State; if (Args[0].Equals(TEXT("o2"), ESearchCase::IgnoreCase)) { V.O2 = FMath::Clamp(N[0], 0.0, V.O2Max); } else if (Args[0].Equals(TEXT("health"), ESearchCase::IgnoreCase)) { V.Health = FMath::Clamp(N[0], 0.0, 100.0); } else if (Args[0].Equals(TEXT("nutrition"), ESearchCase::IgnoreCase)) { V.Nutrition = FMath::Clamp(N[0], 0.0, 100.0); } else { Descent::Cmd::Fail(World, TEXT("Descent.Player.Set"), TEXT("unknown vital (nutrition, o2, health)")); } } void CmdPlayerSwim(const TArray& Args, UWorld* World) { ADescentCharacter* C = PlayerCmdCharacter(World, TEXT("Descent.Player.Swim")); ADescentPlayerController* PC = C ? Cast(C->GetController()) : nullptr; TArray N; if (!PC || !Descent::Cmd::ParseNumbers(Args, 0, 3, N)) { Descent::Cmd::Fail(World, TEXT("Descent.Player.Swim"), TEXT("usage: Descent.Player.Swim x y z (world metres: the body swims there; from Foot or Swim)")); return; } const FVector Where = Descent::MetresToUU(FVector(N[0], N[1], N[2])); if (!PC->EnterSwim(&Where)) { Descent::Cmd::Fail(World, TEXT("Descent.Player.Swim"), TEXT("refused: only from Foot or Swim")); } } void CmdPlayerPoolDrop(const TArray&, UWorld* World) { ADescentCharacter* C = PlayerCmdCharacter(World, TEXT("Descent.Player.PoolDrop")); ADescentPlayerController* PC = C ? Cast(C->GetController()) : nullptr; FString Why; if (PC && !PC->PoolDrop(&Why)) { Descent::Cmd::Fail(World, TEXT("Descent.Player.PoolDrop"), FString::Printf(TEXT("refused: %s"), *Why)); } } void CmdPlayerClimb(const TArray&, UWorld* World) { ADescentCharacter* C = PlayerCmdCharacter(World, TEXT("Descent.Player.Climb")); ADescentPlayerController* PC = C ? Cast(C->GetController()) : nullptr; FString Why; if (PC && !PC->Climb(false, &Why)) { Descent::Cmd::Fail(World, TEXT("Descent.Player.Climb"), FString::Printf(TEXT("refused: %s"), *Why)); } } void CmdPlayerMode(const TArray& Args, UWorld* World) { ADescentPlayerController* PC = World ? Cast(World->GetFirstPlayerController()) : nullptr; if (!PC) { Descent::Cmd::Fail(World, TEXT("Descent.Player.Mode"), TEXT("needs a running game")); return; } if (Args.Num() > 0) { if (Args[0].Equals(TEXT("Foot"), ESearchCase::IgnoreCase)) { PC->SetMode(EDescentMode::Foot); } else if (Args[0].Equals(TEXT("Title"), ESearchCase::IgnoreCase)) { PC->SetMode(EDescentMode::Title); } else { Descent::Cmd::Fail(World, TEXT("Descent.Player.Mode"), TEXT("usage: Descent.Player.Mode [Foot|Title]")); return; } } UE_LOG(LogDescent, Display, TEXT("Player.Mode: %s"), DescentModeName(PC->GetMode())); } FAutoConsoleCommandWithWorldAndArgs GPlayerCmdPlace(TEXT("Descent.Player.Place"), TEXT("Descent.Player.Place - put the character on foot at the room stop point"), FConsoleCommandWithWorldAndArgsDelegate::CreateStatic(&CmdPlayerPlace)); FAutoConsoleCommandWithWorldAndArgs GPlayerCmdPlaceLocal(TEXT("Descent.Player.PlaceLocal"), TEXT("Descent.Player.PlaceLocal x y z yaw - carrier-local feet position"), FConsoleCommandWithWorldAndArgsDelegate::CreateStatic(&CmdPlayerPlaceLocal)); FAutoConsoleCommandWithWorldAndArgs GPlayerCmdMoveTo(TEXT("Descent.Player.MoveTo"), TEXT("Descent.Player.MoveTo | - walk there with real movement input (20 s limit)"), FConsoleCommandWithWorldAndArgsDelegate::CreateStatic(&CmdPlayerMoveTo)); FAutoConsoleCommandWithWorldAndArgs GPlayerCmdLook(TEXT("Descent.Player.Look"), TEXT("Descent.Player.Look yaw pitch - set the view (yaw relative to the carrier)"), FConsoleCommandWithWorldAndArgsDelegate::CreateStatic(&CmdPlayerLook)); FAutoConsoleCommandWithWorldAndArgs GPlayerCmdUse(TEXT("Descent.Player.Use"), TEXT("Descent.Player.Use - press E on the current focus"), FConsoleCommandWithWorldAndArgsDelegate::CreateStatic(&CmdPlayerUse)); FAutoConsoleCommandWithWorldAndArgs GPlayerCmdSet(TEXT("Descent.Player.Set"), TEXT("Descent.Player.Set v"), FConsoleCommandWithWorldAndArgsDelegate::CreateStatic(&CmdPlayerSet)); FAutoConsoleCommandWithWorldAndArgs GPlayerCmdSwim(TEXT("Descent.Player.Swim"), TEXT("Descent.Player.Swim x y z - the body swims at a world position"), FConsoleCommandWithWorldAndArgsDelegate::CreateStatic(&CmdPlayerSwim)); FAutoConsoleCommandWithWorldAndArgs GPlayerCmdPoolDrop(TEXT("Descent.Player.PoolDrop"), TEXT("Descent.Player.PoolDrop - drop into the moon pool (E at the ladder sign)"), FConsoleCommandWithWorldAndArgsDelegate::CreateStatic(&CmdPlayerPoolDrop)); FAutoConsoleCommandWithWorldAndArgs GPlayerCmdClimb(TEXT("Descent.Player.Climb"), TEXT("Descent.Player.Climb - E at the pool ladder (Swim -> Ladder -> Foot)"), FConsoleCommandWithWorldAndArgsDelegate::CreateStatic(&CmdPlayerClimb)); FAutoConsoleCommandWithWorldAndArgs GPlayerCmdMode(TEXT("Descent.Player.Mode"), TEXT("Descent.Player.Mode [Foot|Title] - print (and set) the mode"), FConsoleCommandWithWorldAndArgsDelegate::CreateStatic(&CmdPlayerMode)); }