mirror of
https://github.com/Dingo-Shenanigans/ReSkate.git
synced 2026-10-24 05:26:13 +02:00
Board Break: the trucks' baseplates stay on a broken board
The game's truck model has its hangers on the trucks' bones and its baseplates on the deck's bone. A broken board hides the real deck by moving that bone away, so its trucks lost their baseplates. The decks inside a deck pack bring a truck model with the baseplates on the trucks' effectors, bones under the trucks' own that no model uses. The render pose hook writes each effector from its truck's bone, so that the baseplate sits on the deck of a whole board however the truck steers, and goes with the truck when a piece carries it off. With the game's own truck model nothing is on those bones and nothing changes.
This commit is contained in:
1 parent
0c8add27a4
commit
3d8a5fc8c7
4 files changed
+93
-7
No files matched your search
@@ -133,6 +133,21 @@ void a_truck_goes_with_its_piece() {
|
||||
const auto up = truck_bone(lifted, mount, mount_at, level, front_truck_place);
|
||||
check(near(up.at + away, front_truck_place + Vec{0, 0.25f, 0}), "A piece that is lifted takes its truck up with it");
|
||||
}
|
||||
void a_baseplate_stays_on_the_deck_while_its_truck_steers() {
|
||||
// A baseplate sits on the truck's effector, a child of the truck's bone. Whatever the truck's
|
||||
// bone does, the truck's bone followed by the effector's is what it is at rest.
|
||||
for (const auto& rest : {back_truck_rest, front_truck_rest}) {
|
||||
const auto still = baseplate_bone({rest.facing, rest.at}, rest);
|
||||
check(near(still.at, rest.effector) && near(std::abs(still.facing.w), 1.0f), "At rest the effector is where the rig has it");
|
||||
const Vec bolt{0.03f, 0.08f, rest.at.z + 0.02f};
|
||||
const auto on_deck = moved({rest.facing, rest.at}, moved({{}, rest.effector}, bolt));
|
||||
for (const float lean : {-0.4f, 0.15f, 0.6f}) {
|
||||
const Rigid steered{unit(rest.facing * about({0, 0, 1}, lean)), rest.at};
|
||||
const auto effector = baseplate_bone(steered, rest);
|
||||
check(near(moved(steered, moved(effector, bolt)), on_deck, 1e-4f), "Steered, the baseplate has not moved on the deck");
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int main() {
|
||||
@@ -146,6 +161,7 @@ int main() {
|
||||
a_folded_board_meets_at_the_break();
|
||||
a_hanging_end_turns_about_the_break();
|
||||
a_truck_goes_with_its_piece();
|
||||
a_baseplate_stays_on_the_deck_while_its_truck_steers();
|
||||
std::cout << "board break tests passed\n";
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
|
||||
@@ -45,6 +45,9 @@ constexpr float hand_reach = 1.3f, hand_upright = 0.8f;
|
||||
// deck's mount, 3 the deck, 4 and 8 the trucks, and the spare bones that carry the four stretches
|
||||
// (nose, front, back, tail; the tail's hangs on the front's).
|
||||
constexpr int root_bone = 1, mount_bone = 2, deck_bone = 3, back_truck_bone = 4, front_truck_bone = 8;
|
||||
// The trucks' effectors, each right after its truck's bone: a deck pack's truck model has the
|
||||
// baseplates on them (board_break_model.h, baseplate_bone).
|
||||
constexpr int back_plate_bone = 5, front_plate_bone = 9;
|
||||
constexpr std::array<int, 4> carrier{12, 13, 15, 14};
|
||||
constexpr std::uint32_t rig_bones = 16;
|
||||
|
||||
@@ -152,6 +155,21 @@ void carry_truck(std::uintptr_t buffer, const Rigid& motion, int index, Vec plac
|
||||
(void)store_bone(bone_at(buffer, index), bone.facing, bone.at);
|
||||
}
|
||||
|
||||
// Keeps the baseplates on the deck (baseplate_bone), from each truck's bone as the animation left
|
||||
// it: a truck that a piece has carried off already, in a pose nobody has written since, is left.
|
||||
void hold_baseplates(std::uintptr_t buffer) noexcept {
|
||||
const auto hold = [&](int truck_index, int plate_index, const TruckRest& rest) {
|
||||
PoseBone truck{};
|
||||
if (!load_bone(bone_at(buffer, truck_index), truck)) return;
|
||||
const Rigid now{facing_of(truck), place_of(truck)};
|
||||
if (!(length(now.at - rest.at) < 0.05f)) return;
|
||||
const auto bone = baseplate_bone(now, rest);
|
||||
(void)store_bone(bone_at(buffer, plate_index), bone.facing, bone.at);
|
||||
};
|
||||
hold(back_truck_bone, back_plate_bone, back_truck_rest);
|
||||
hold(front_truck_bone, front_plate_bone, front_truck_rest);
|
||||
}
|
||||
|
||||
// ---- the piece that comes off --------------------------------------------------------------------
|
||||
// The client tick starts a flight (a new id) when the board breaks; the render pose hook moves the
|
||||
// piece through the world from there (a kick, gravity, the ground) and writes it relative to
|
||||
@@ -276,14 +294,15 @@ std::uint32_t fly_piece(std::uintptr_t buffer, Rigid& piece) {
|
||||
}
|
||||
|
||||
// ---- what the hook writes ------------------------------------------------------------------------
|
||||
// The local board, broken: the real deck goes away, the trucks come back, each stretch goes to
|
||||
// where its piece lies and one that belongs to no piece goes away too.
|
||||
// The local board, broken: the real deck goes away, the trucks come back (their baseplates with
|
||||
// them), each stretch goes to where its piece lies and one that belongs to no piece goes away too.
|
||||
void draw_broken(std::uintptr_t base, std::uintptr_t holder, std::uint32_t kept, Hinge hinge, float angle) {
|
||||
const auto buffer = board_pose(base, holder);
|
||||
PoseBone root{}, mount{}, deck{};
|
||||
if (!buffer || !load_bone(bone_at(buffer, root_bone), root) || !load_bone(bone_at(buffer, mount_bone), mount) ||
|
||||
!load_bone(bone_at(buffer, deck_bone), deck))
|
||||
return;
|
||||
hold_baseplates(buffer);
|
||||
// From where its animation put it this frame; a pose nobody has written since the last move stays as it is.
|
||||
if (const Vec at = place_of(deck); length(at) < 100.0f) (void)store_bone(bone_at(buffer, deck_bone), facing_of(deck), at + away);
|
||||
auto layout = lay_out(kept, hinge, angle, turn(facing_of(root), {0, 1, 0}).y, facing_of(mount));
|
||||
@@ -298,10 +317,12 @@ void draw_broken(std::uintptr_t base, std::uintptr_t holder, std::uint32_t kept,
|
||||
const auto bones = bones_of(layout.stretch);
|
||||
for (std::size_t i = 0; i < bones.size(); ++i) (void)store_bone(bone_at(buffer, carrier[i]), bones[i].facing, bones[i].at);
|
||||
}
|
||||
// A whole board, any player's: its four stretches go far away from it.
|
||||
// A whole board, any player's: its four stretches go far away from it, and its baseplates sit on
|
||||
// the deck.
|
||||
void park_pieces(std::uintptr_t base, std::uintptr_t holder) {
|
||||
const auto buffer = board_pose(base, holder);
|
||||
if (!buffer) return;
|
||||
hold_baseplates(buffer);
|
||||
const auto bones = bones_of({});
|
||||
for (std::size_t i = 0; i < bones.size(); ++i) (void)store_bone(bone_at(buffer, carrier[i]), bones[i].facing, bones[i].at);
|
||||
}
|
||||
|
||||
@@ -203,4 +203,21 @@ inline Rigid truck_bone(const Rigid& motion, Quat mount, Vec mount_at, Quat stee
|
||||
const auto at = turn(conj(mount), turn(motion.facing, mount_at) + motion.at - mount_at);
|
||||
return {unit(facing * steer), turn(facing, place) + at - away};
|
||||
}
|
||||
// The trucks' baseplates. The game's own truck model has them on the deck's bone, which goes away
|
||||
// with the real deck when the board breaks, and they went with it. A deck pack's truck model has
|
||||
// each baseplate on its truck's effector instead, a bone under the truck's that no model uses:
|
||||
// wherever a piece carries the truck, its baseplate goes along. This is where that effector goes
|
||||
// so that the baseplate sits on the deck however the truck steers: the truck's own turn and place
|
||||
// taken back, its rest put in. `truck` is the truck's bone as the animation left it this frame.
|
||||
struct TruckRest {
|
||||
Quat facing; // the truck's bone on the deck's, at rest
|
||||
Vec at;
|
||||
Vec effector; // its effector on the truck's bone, at rest (not turned)
|
||||
};
|
||||
constexpr TruckRest back_truck_rest{{-0.3641458f, -0.3641458f, -0.6061335f, 0.6061335f}, {0.0005361f, -0.0183003f, -0.2344986f}, {0.0395021f, 0.0f, 0.0f}};
|
||||
constexpr TruckRest front_truck_rest{{-0.6061674f, 0.6061674f, 0.3640894f, 0.3640894f}, {0.0005361f, -0.0182917f, 0.2346680f}, {0.0395677f, 0.0f, 0.0f}};
|
||||
inline Rigid baseplate_bone(const Rigid& truck, const TruckRest& rest) noexcept {
|
||||
const auto back = conj(truck.facing);
|
||||
return {unit(back * rest.facing), turn(back, rest.at + turn(rest.facing, rest.effector) - truck.at)};
|
||||
}
|
||||
} // namespace dingosdk::board_break
|
||||
+36
-4
@@ -19,7 +19,9 @@ deck's place in the mod list in [mod_catalog.cpp](../Engine/Vfs/mod_catalog.cpp)
|
||||
while it is ridden: the nose goes.
|
||||
- `boardbreak 0|1`, `boardbreak deck [name|number|next]`, `boardbreak snap [nose|mid|tail]` to look
|
||||
at a break (that one stays until `boardbreak mend` or a respawn). The switch and the deck are in
|
||||
the menus beside Road Rash (Mod Options > Player, and the overlay's Skater page). The switch is
|
||||
the menus beside Road Rash (Mod Options > Player, and the overlay's Skater page). The overlay has
|
||||
a card BOARD BREAK DECK with a button for each deck, on the Mods page and under the switch: a
|
||||
press asks for that deck, the mods are applied and the level loads again with it. The switch is
|
||||
saved with the profile.
|
||||
- A break plays back in the replay editor as it happened.
|
||||
- Without a deck pack installed nothing breaks and nothing is changed.
|
||||
@@ -66,6 +68,18 @@ deck's place in the mod list in [mod_catalog.cpp](../Engine/Vfs/mod_catalog.cpp)
|
||||
`light`, `medium`, `heavy`, by the size of the break), played straight to the speakers.
|
||||
- **The slam's force** comes through No Bail's existing hooks: the cause it records for the watched
|
||||
skater, and the cause collector at the moment the selector chooses Wipeout. Nothing new is hooked.
|
||||
- **The trucks' baseplates.** The game's truck model (one for every truck item,
|
||||
`characters/skateboard/unlicensed/truck/generic/default/2022/truck_gen_default_mesh`) has its
|
||||
hangers on the trucks' bones and everything bolted to the deck, the baseplates and their bolts,
|
||||
on the deck's bone. With the deck's bone moved away to hide the real deck, a broken board had
|
||||
hangers and wheels and no baseplates. The decks inside a deck pack bring a copy of the truck
|
||||
model with those vertices on the trucks' effectors instead (`eff_truckBack`, `eff_truckFront`:
|
||||
a bone under each truck's that no model uses), and the hook writes each effector from its
|
||||
truck's bone as the animation left it, so that the truck's bone followed by the effector's is
|
||||
what the two are at rest: on a whole board the baseplate sits on the deck however the truck
|
||||
steers, and a truck that a piece carries off takes its baseplate along
|
||||
(`baseplate_bone`, with a test). That is done on every board that passes the hook. With the
|
||||
game's own truck model nothing is on the effectors and writing them shows nothing.
|
||||
- **On foot the grip tape always holds.** A loose piece takes the ground from where the board
|
||||
rolled or lies; a board in the skater's hand does not tell where the ground is, and a piece that
|
||||
came off there hung in the air at hand height.
|
||||
@@ -87,7 +101,10 @@ A deck is a content mod's copy of the deck model (no code), and comes in one of
|
||||
what an older ReSkate loads from the pack. ReSkate 2.0.6 knows a deck by its folder's name only,
|
||||
so a pack in a folder named `Board_Break_<Name>` (the package `Board_Break_Pack`, installed as
|
||||
`Team-Board_Break_Pack`) with a breakable deck as its own layout breaks boards there with that
|
||||
one deck, and brings all its decks from this version on.
|
||||
one deck, and brings all its decks from this version on. The truck model with the baseplates on
|
||||
the effectors belongs in the decks inside the pack only: a ReSkate that does not place those
|
||||
bones would draw the baseplates turning with the hangers, and such a version reads the pack's
|
||||
own layout, never `decks/`.
|
||||
|
||||
The name is what the deck goes by. The eight the feature was made with are standard, wide,
|
||||
concave, powell, slim, egg, square and shaped, and the console also knows those by number. Any
|
||||
@@ -104,6 +121,9 @@ other deck that follows the recipe works, with no change to ReSkate:
|
||||
deck's own edge faces standing in the gap as the broken end. Push the row itself along the board
|
||||
by a jagged line, the same line for both sides of a break, so the pieces fit together.
|
||||
- Build the stretches at their own size, in the place they have in the whole deck.
|
||||
- The truck model for a deck inside a pack: the game's own, with every vertex that is on the bone
|
||||
Deck moved to `eff_truckBack` (behind the middle of the board) or `eff_truckFront` (ahead of
|
||||
it). Nothing else changes; Studio takes it back as it is.
|
||||
- The sounds are `sounds/light|medium|heavy/*.wav` in the folder of any mod that brings a deck.
|
||||
|
||||
## Seen working in game
|
||||
@@ -126,6 +146,15 @@ with the game's own deck there, and with a breakable deck there in a folder name
|
||||
overlay's Skater page turns it off and on. On the
|
||||
older build the feature was developed on, a middle break played back in the replay editor.
|
||||
|
||||
On main at 8351654, with the pack as the only source of decks (its decks with the truck model
|
||||
that has the baseplates on the effectors): a dozen breaks from real slams at the nose, in the
|
||||
middle and at the tail, clean and held by the grip, with the baseplates on the pieces, and on the
|
||||
whole board in hand and on the ground. The effectors are bones 5 and 9 of the pose, each at
|
||||
0.0395 m along its truck's bone and not turned, as the rig has them. A press on Shaped in the
|
||||
overlay's deck card: the mods applied in 3.8 s, the level loaded again in 15 s with that deck,
|
||||
which then broke. In the game's Mod Options > Player page, on 2.0.6: one press on Board Break
|
||||
deck is one deck further and one reload.
|
||||
|
||||
## Not tried yet
|
||||
|
||||
- Multiplayer: other players' boards are only handled by the code path (their stretches are moved
|
||||
@@ -133,6 +162,9 @@ older build the feature was developed on, a middle break played back in the repl
|
||||
- The online route: all of the above ran on the offline profile.
|
||||
- The replay editor on this branch (the replay was checked on the older build the feature was
|
||||
developed on).
|
||||
- The rows in Mod Options > Player in the game itself (their view has a test; the overlay's switch
|
||||
was used).
|
||||
- The deck card with a deck that is not one of the eight, and with none installed (it draws
|
||||
nothing then).
|
||||
- A board that does not pass the render pose hook, with the truck model from a pack: its
|
||||
baseplates would follow the hangers.
|
||||
- A mod that brings a truck model of its own beside a deck pack: the pack's is the one that loads.
|
||||
- A level change in the middle of a break.
|
||||
Reference in new issue
Block a user