Files
ReSkate/Engine/Game/Skater/Test/first_person_cycle_tests.cpp
VebjorhkandClaude Opus 5.5 76ba5a1739 First person as a step in the R3 camera height cycle (opt-in)
With the game's Camera height control on (Gameplay > Advanced Camera),
R3 on the board switches between the high and the low camera by writing
the opposite of the UseHighCam option. A new switch in SKATER > CAMERA >
FIRST PERSON, "First person in the camera cycle" (off by default), makes
it high -> low -> first person -> high.

- The existing native option hook passes UseHighCam writes to a
  listener, so the settings code does not depend on the skater code
- Low -> first person keeps the low camera and turns first person on;
  first person -> high turns it off and keeps the high camera
- First person is switched through the menu toggle's own action on the
  next client tick, so the player's first-person settings apply as
  they are; it only starts on the board, outside Freecam, Noclip and
  the Park Editor
- Saved as FirstPerson.CameraCycle; Reset arm settings keeps it
- Add a ctest (first_person_cycle) for the cycle's steps

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 01:02:01 +02:00

74 lines
3.1 KiB
C++

#include "Engine/Game/Skater/first_person_cycle.h"
#include <cstdio>
#include <string_view>
// First person in the camera cycle (first_person::cycle_height_write): the game's camera height
// button flips UseHighCam; the option turns that into high -> low -> first person -> high.
namespace {
using namespace dingosdk::first_person;
int failures = 0;
void expect(bool condition, std::string_view what) {
if (condition) return;
++failures;
std::printf("FAIL: %.*s\n", static_cast<int>(what.size()), what.data());
}
bool same(const CycleWrite& write, bool high, CycleStep step) { return write.high == high && write.step == step; }
void off() {
for (const bool first_person : {false, true})
for (const bool high : {false, true})
expect(same(cycle_height_write({false, first_person, true}, high), high, CycleStep::none),
"with the option off the game's height passes through and first person is left alone");
}
void steps() {
expect(same(cycle_height_write({true, false, true}, false), false, CycleStep::none), "high -> low is the game's own step");
expect(same(cycle_height_write({true, false, true}, true), false, CycleStep::enter),
"low -> first person keeps the low camera behind it");
expect(same(cycle_height_write({true, true, false}, true), true, CycleStep::leave),
"first person (low behind it) -> the high camera");
expect(same(cycle_height_write({true, true, false}, false), true, CycleStep::leave),
"first person switched on in the menu over the high camera still lands on high");
expect(same(cycle_height_write({true, false, false}, true), true, CycleStep::none),
"where first person cannot start (on foot, Freecam) low -> high is the game's own step");
}
// The game reads the height it keeps and writes the opposite on every press.
void presses() {
for (const bool start_high : {true, false}) {
bool high = start_high, first_person = false;
const auto press = [&] {
const auto write = cycle_height_write({true, first_person, !first_person}, !high);
high = write.high;
if (write.step == CycleStep::enter) first_person = true;
if (write.step == CycleStep::leave) first_person = false;
};
if (!start_high) press(); // low -> first person
if (!start_high) press(); // first person -> high
for (int round = 0; round < 3; ++round) {
expect(high && !first_person, "the cycle starts each round on the high camera");
press();
expect(!high && !first_person, "first press: low camera");
press();
expect(!high && first_person, "second press: first person over the low camera");
press();
}
expect(high && !first_person, "the third press of each round returns to the high camera");
}
}
} // namespace
int main() {
off();
steps();
presses();
if (failures) {
std::printf("%d first-person cycle test(s) failed\n", failures);
return 1;
}
std::printf("first-person cycle tests passed\n");
return 0;
}