// Scenarios that photograph the Kazah Tender. The map holds only a PlayerStart, so each scenario spawns its own // rig (Tender, fill lights, seabed: ADescentShowcaseRig); the water, fog and exposure are ADescentEnvironment's, as everywhere, and the pictures do not depend on // anything but this file and the imported meshes. Run with Tools/run_scenario.ps1 -Name kazah_showcase. #include "Debug/DescentScenario.h" #include "Debug/DescentDebugSubsystem.h" #include "Debug/DescentShowcaseRig.h" #include "Vehicles/KazahTender.h" #include "TheDescent.h" #include "Components/StaticMeshComponent.h" #include "Engine/StaticMesh.h" #include "Engine/World.h" DESCENT_SCENARIO(kazah_showcase, "Spawns the Kazah Tender with headlight, fill lights and the game's own water, rotors spinning, and photographs it from the front, side and rear.") { S.TimeLimit(240.f); S.Do(TEXT("spawn rig"), [](FDescentScenarioContext& C) { ADescentShowcaseRig* Rig = ADescentShowcaseRig::FindOrSpawn(C.World); if (!Rig || !Rig->GetTender()) { C.Fail(TEXT("could not spawn the showcase rig / Tender")); return; } C.SetNamed(TEXT("Rig"), Rig); AKazahTender* T = Rig->GetTender(); T->RotorRPM = 420.f; T->SetHeadlight(true); // Every part must have its mesh, otherwise the pictures would show a partial vehicle and still "pass". for (const FKazahPartDef& Def : AKazahTender::GetPartDefs()) { const UStaticMeshComponent* Part = T->GetPart(Def.Name); if (!Part || !Part->GetStaticMesh()) { C.Fail(FString::Printf(TEXT("part %s has no mesh: run Tools/import_assets.ps1"), Def.Name)); return; } } }); // Let the rotors turn through a few distinct angles before the first picture. S.WaitFrames(5); // Camera spots are in metres around the Tender's origin (nose at +X, starboard +Y, up +Z). The vehicle's // centre is about (0.2, 0, 0.3) m. The camera sits ~11 m away: the 7 m hull fills about two thirds of the frame. const FVector Centre(0.2, 0.0, 0.3); S.LookAt(FVector(8.0, 7.5, 3.2), Centre, 50.f); // front, starboard side, from above S.Shot(TEXT("front34")); // A lit Tender in a dark sea: not black, not blown out. (The numbers are the shot sidecar's.) S.Expect(TEXT("front34 is lit but dark"), [](FDescentScenarioContext& C) { return C.LastShotStats.MeanLuma > 0.02 && C.LastShotStats.MeanLuma < 0.45 && C.LastShotStats.NonBlack > 0.15; }); S.LookAt(FVector(0.2, 12.5, 0.6), Centre, 45.f); // pure side view from starboard S.Shot(TEXT("side")); S.LookAt(FVector(-9.0, -7.0, 2.8), Centre, 50.f); // rear, port side, from above S.Shot(TEXT("rear34")); S.Do(TEXT("assert rotors turned"), [](FDescentScenarioContext& C) { const ADescentShowcaseRig* Rig = Cast(C.GetNamed(TEXT("Rig"))); const AKazahTender* T = Rig ? Rig->GetTender() : nullptr; if (!T || T->GetRotorTotalDeg() < 90.0) { C.Fail(TEXT("the rotors did not turn during the showcase")); } }); S.DumpState(TEXT("end")); S.Quit(); } DESCENT_SCENARIO(kazah_closeups, "Detail shots of the Kazah Tender (stern and rotors, canopy glass, nose lens, port side) under brighter fill light, for inspecting the model.") { S.TimeLimit(240.f); S.Do(TEXT("spawn rig, brighter fill"), [](FDescentScenarioContext& C) { ADescentShowcaseRig* Rig = ADescentShowcaseRig::FindOrSpawn(C.World); if (!Rig || !Rig->GetTender()) { C.Fail(TEXT("could not spawn the showcase rig / Tender")); return; } Rig->SetFillScale(3.0f); Rig->GetTender()->RotorRPM = 90.f; // slow, so the blades are not at the same angle in every shot C.SetNamed(TEXT("Rig"), Rig); }); S.WaitFrames(5); S.LookAt(FVector(-7.0, -1.2, 1.4), FVector(-2.8, 0.0, 0.2), 45.f); // stern, looking at both rotors S.Shot(TEXT("stern")); S.LookAt(FVector(5.8, -3.2, 2.4), FVector(1.7, 0.0, 0.6), 42.f); // canopy glass from the front-port S.Shot(TEXT("canopy")); S.LookAt(FVector(6.2, 1.8, 0.6), FVector(3.7, 0.0, 0.0), 38.f); // nose lens and chin sensor S.Shot(TEXT("nose")); S.LookAt(FVector(2.0, -8.0, -0.2), FVector(1.5, 0.0, -0.3), 45.f); // port side: tool housing, lower tank S.Shot(TEXT("port")); S.DumpState(TEXT("end")); S.Quit(); }