bookquoy/js/tricks.js
jing 53ad2030af BOOKQUOY v0.1 — Paddo, three disciplines, letters, gaps, 2:00 sesh
Level 01: Paddington Skatepark from the council plan + park guides —
heightAt(x,z) single-source terrain, grindable rails/ledges, named gaps,
B-O-O-K-Q-U-O-Y letters with the BOOKQUOYORK callback.

SKATE / BMX / BLADES (blades cop thrown rubbish, as is tradition).
character_kit two-rig banks: physics owns the root, clips are cosmetic.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 19:13:13 +10:00

81 lines
3.8 KiB
JavaScript

// BOOKQUOY trick tables — tricks are DATA, not code.
// (The core lesson from the THUG QB decompile: Neversoft shipped yearly because designers
// edited tables.) Clip names bind to the character_kit banks.
//
// Each discipline is a KIT: which bank the trick clips live in, what plays while rolling,
// and its own trick table. `mate` overrides the paired secondary clip when it differs
// from the pairs.json default (e.g. double barspin = same rider clip, faster bike clip).
export const KITS = {
skate: {
label: 'SKATE', anchor: 'Board', primary: 'prop', grinds: true,
idle: 'Board_Idle', roll: 'Board_Roll', push: 'Board_Push',
bail: 'Board_Bail', airFall: 'Ollie',
ollie: { clip: 'Ollie', name: 'Ollie', score: 10 },
grindKinds: {
rail: { clip: 'Grind_5050', name: '50-50', base: 100, perSec: 60 },
ledge: { clip: 'Grind_5050', name: 'Ledge Grind', base: 100, perSec: 60 },
},
tricks: {
KeyJ: { base: { clip: 'Kickflip', name: 'Kickflip', score: 100 },
up: { clip: 'VarialKickflip', name: 'Varial Kickflip', score: 200 },
down: { clip: 'DoubleKickflip', name: 'Double Kickflip', score: 250 } },
KeyK: { base: { clip: 'Heelflip', name: 'Heelflip', score: 100 },
up: { clip: 'VarialHeelflip', name: 'Varial Heelflip', score: 200 },
down: { clip: 'InwardHeelflip', name: 'Inward Heelflip', score: 275 } },
KeyL: { base: { clip: 'PopShoveIt', name: 'Pop Shove-It', score: 75 },
up: { clip: 'BigSpin', name: 'BigSpin', score: 150 },
down: { clip: 'Shove360', name: '360 Shove-It', score: 200 } },
KeyT: { base: { clip: 'TreFlip', name: 'Tre Flip', score: 300 } },
KeyY: { base: { clip: 'LaserFlip', name: 'Laser Flip', score: 350 } },
KeyH: { base: { clip: 'Hardflip', name: 'Hardflip', score: 300 } },
KeyN: { base: { clip: 'Impossible', name: 'Impossible', score: 250 } },
KeyF: { base: { clip: 'FSShoveIt', name: 'FS Shove-It', score: 100 } },
},
},
bmx: {
label: 'BMX', anchor: 'Bike', primary: 'rider', grinds: false,
idle: 'BikeRide_Idle', roll: 'BikeRide_Idle', push: 'BikePedal',
bail: 'BikeBail_Rider', airFall: 'BikeAir_Idle',
ollie: { clip: 'Bunnyhop_Rider', name: 'Bunnyhop', score: 50 },
tricks: {
KeyJ: { base: { clip: 'Barspin_Rider', name: 'Barspin', score: 150 },
down: { clip: 'Barspin_Rider', mate: 'Barspin_Double',
name: 'Double Barspin', score: 300 } },
KeyK: { base: { clip: 'Tailwhip_Rider', name: 'Tailwhip', score: 250 } },
KeyL: { base: { clip: 'XUp_Rider', name: 'X-Up', score: 150 } },
},
},
blades: {
label: 'BLADES', anchor: null, primary: 'rider', grinds: true, rubbish: true,
idle: 'Skate_Idle', roll: 'Skate_Roll', push: 'Skate_Push',
bail: 'Bail_Rider', airFall: 'Pop_Ollie',
ollie: { clip: 'Pop_Ollie', name: 'Air', score: 10 },
grindKinds: {
rail: { clip: 'Grind_Idle', name: 'Soul Grind', base: 100, perSec: 60 },
ledge: { clip: 'Grind_Idle', name: 'Royale', base: 100, perSec: 60 },
},
tricks: {
KeyJ: { base: { clip: 'Pop_Kick', name: '360 Spin', score: 100 } },
KeyK: { base: { clip: 'Pop_Heel', name: 'Zero Spin', score: 100 } },
KeyL: { base: { clip: 'Pop_Shove', name: 'Truespin', score: 120 } },
KeyT: { base: { clip: 'Pop_Long', name: 'Misty Flip', score: 300 } },
},
},
};
export const RUBBISH_INSULTS = [
'OI!', 'GET A BOARD!', 'FRUIT BOOTS!!', 'NICE ROLLERBLADES MATE',
'WRONG PARK, BLADER', 'COP THAT', '*thrown VB can*',
];
export const GAP_SCORE = 300;
export const LETTER_SCORE = 500;
export const ALL_LETTERS_SCORE = 5000;
export function comboLabel(items) {
return items.map(i => i.name).join(' + ') + (items.length > 1 ? ` x${items.length}` : '');
}