56593c58cf
Show touch controls only on touch platforms and keyboard hints only on desktop, via a shared Controls.use_touch_ui() gate (is_touchscreen_available is unreliable with emulate_touch_from_mouse). Bumps version to 0.2.0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
396 lines
24 KiB
GDScript
396 lines
24 KiB
GDScript
extends Node
|
|
## Central registry for all runtime-tunable parameters.
|
|
## Add a new param with one _reg_f() call in _register_all() — the menu picks it up automatically.
|
|
## Access: DP.f("key") • Persist: DP.save() / DP.load_saved() • Reset: DP.reset_all()
|
|
|
|
signal any_changed(key: String, value: Variant)
|
|
|
|
const SAVE_PATH := "user://debug_params.cfg"
|
|
|
|
# _params holds the full metadata (min/max/step/default/section/type) and is the
|
|
# authority the debug menu reads. _values is a flat key→value mirror so the hot
|
|
# f()/b() reads — called dozens of times per matador per physics frame — cost a
|
|
# single hash lookup instead of a nested dict access. Every write updates both.
|
|
var _params: Dictionary = {}
|
|
var _values: Dictionary = {}
|
|
|
|
|
|
func _ready() -> void:
|
|
_register_all()
|
|
load_saved()
|
|
|
|
|
|
func _register_all() -> void:
|
|
# ── Movement ──────────────────────────────────────────────────────────────
|
|
# WASD/arrows drive the bull: move_accel ramps flat velocity toward max_speed in
|
|
# the input direction; move_friction bleeds it off when no direction is held.
|
|
_reg_f("Movement", "max_speed", 10.0, 2.0, 1000.0)
|
|
_reg_f("Movement", "move_accel", 120.0, 5.0, 600.0)
|
|
_reg_f("Movement", "move_friction", 90.0, 5.0, 600.0)
|
|
_reg_f("Movement", "jump_velocity", 4.5, 1.0, 200.0)
|
|
_reg_f("Movement", "visual_turn_speed", 12.0, 1.0, 200.0)
|
|
_reg_f("Movement", "bounce_restitution", 0.55, 0.0, 2.0, 0.05)
|
|
_reg_f("Movement", "bounce_min_impact", 1.0, 0.0, 20.0)
|
|
_reg_f("Movement", "wall_bounce_restitution", 0.6, 0.0, 1.5, 0.05)
|
|
_reg_f("Movement", "wall_min_bounce_speed", 6.0, 0.0, 30.0)
|
|
# ── Bull health ───────────────────────────────────────────────────────────
|
|
# The bull soaks bull_max_hp clean hits before it dies; each hit grants
|
|
# bull_hit_iframes seconds of invulnerability so a single pass can't drain it.
|
|
_reg_f("Bull", "bull_max_hp", 10.0, 1.0, 100.0, 1.0)
|
|
_reg_f("Bull", "bull_hit_iframes", 0.8, 0.0, 3.0, 0.1)
|
|
# ── Dust speed thresholds ─────────────────────────────────────────────────
|
|
_reg_f("Dust", "dust_walk_spd", 1.5, 0.1, 10.0)
|
|
_reg_f("Dust", "dust_charge_spd", 7.0, 1.0, 20.0)
|
|
# ── Dust ──────────────────────────────────────────────────────────────────
|
|
_reg_f("Dust", "dust_lifetime", 0.9, 0.1, 4.0)
|
|
_reg_f("Dust", "dust_explosiveness", 0.35, 0.0, 1.0)
|
|
_reg_f("Dust", "dust_spread", 45.0, 5.0, 90.0)
|
|
_reg_f("Dust", "dust_gravity_y", -1.5,-15.0, 0.0)
|
|
_reg_f("Dust", "walk_scale_min", 0.35, 0.05, 3.0)
|
|
_reg_f("Dust", "walk_scale_max", 0.65, 0.05, 3.0)
|
|
_reg_f("Dust", "walk_vel_min", 0.8, 0.1, 12.0)
|
|
_reg_f("Dust", "walk_vel_max", 1.8, 0.1, 12.0)
|
|
_reg_f("Dust", "charge_scale_min", 1.0, 0.05, 6.0)
|
|
_reg_f("Dust", "charge_scale_max", 2.2, 0.05, 6.0)
|
|
_reg_f("Dust", "charge_vel_min", 2.8, 0.1, 20.0)
|
|
_reg_f("Dust", "charge_vel_max", 5.5, 0.1, 20.0)
|
|
# ── Tail ──────────────────────────────────────────────────────────────────
|
|
_reg_f("Tail", "tail_gravity", 9.8, 0.0, 30.0)
|
|
_reg_f("Tail", "tail_damping", 0.08, 0.0, 0.5, 0.01)
|
|
_reg_f("Tail", "tail_body_radius", 0.35, 0.05, 2.0, 0.05)
|
|
_reg_f("Tail", "tail_wag_freq", 4.0, 0.5, 15.0)
|
|
_reg_f("Tail", "tail_wag_idle", 0.3, 0.0, 2.0, 0.05)
|
|
# ── Charge pose (horns-down lean during dash / roll) ─────────────────────
|
|
_reg_f("Charge", "charge_head_pitch", 0.3, 0.0, 1.2, 0.01)
|
|
_reg_f("Charge", "charge_head_speed", 5.0, 0.5, 20.0)
|
|
# ── Body ──────────────────────────────────────────────────────────────────
|
|
_reg_f("Body", "body_tilt_fwd", 0.015, 0.0, 0.1, 0.001)
|
|
_reg_f("Body", "body_tilt_side", 0.01, 0.0, 0.1, 0.001)
|
|
_reg_f("Body", "aerial_pitch_scale", 0.6, 0.0, 2.0)
|
|
_reg_f("Body", "aerial_pitch_speed", 5.0, 0.5, 20.0)
|
|
# ── Legs ──────────────────────────────────────────────────────────────────
|
|
_reg_f("Legs", "leg_step_threshold", 0.15, 0.01, 1.0, 0.01)
|
|
_reg_f("Legs", "leg_step_duration", 0.12, 0.02, 0.5, 0.01)
|
|
_reg_f("Legs", "leg_step_height", 0.15, 0.0, 0.5)
|
|
_reg_f("Legs", "leg_step_overshoot", 0.3, 0.0, 1.0)
|
|
_reg_f("Legs", "gait_freq", 1.5, 0.1, 5.0)
|
|
_reg_f("Legs", "launch_hold_time", 0.15, 0.0, 1.0, 0.01)
|
|
_reg_f("Legs", "ragdoll_wobble_amp", 0.15, 0.0, 1.0)
|
|
_reg_f("Legs", "tuck_apex_threshold", 0.5, -5.0, 5.0)
|
|
_reg_f("Legs", "jump_tuck_speed", 8.0, 1.0, 30.0)
|
|
_reg_f("Legs", "jump_tuck_up", 0.2, 0.0, 1.0)
|
|
_reg_f("Legs", "jump_tuck_fwd", -0.1, -0.5, 0.5)
|
|
_reg_f("Legs", "jump_land_threshold", 1.5, 0.5, 5.0)
|
|
# ── Camera ────────────────────────────────────────────────────────────────
|
|
_reg_f("Camera", "charge_zoom_factor", 0.65, 0.3, 1.0, 0.05)
|
|
_reg_f("Camera", "cam_lerp_power", 6.0, 0.5, 30.0)
|
|
_reg_f("Camera", "cam_sensitivity", 0.005, 0.001, 0.05, 0.001)
|
|
_reg_f("Camera", "cam_min_zoom", 3.5, 0.5, 20.0)
|
|
_reg_f("Camera", "cam_max_zoom", 40.0, 2.0, 80.0)
|
|
_reg_f("Camera", "cam_spring_length", 7.0, 1.0, 30.0)
|
|
_reg_f("Camera", "cam_min_vert_angle", -60.0, -90.0, 0.0, 1.0)
|
|
_reg_f("Camera", "cam_max_vert_angle", 45.0, 0.0, 90.0, 1.0)
|
|
# Trailing "drag" camera: the focus point lags the bull and slides opposite to
|
|
# its velocity, so the camera visibly drags behind during a fast charge.
|
|
# cam_drag = metres of trail per m/s of bull speed (0 = rigid follow)
|
|
# cam_drag_speed = how fast the trail offset eases toward its target
|
|
# cam_follow_lerp = how tightly the focus point chases the bull (higher = snappier)
|
|
_reg_f("Camera", "cam_drag", 0.12, 0.0, 1.0, 0.01)
|
|
_reg_f("Camera", "cam_drag_speed", 3.5, 0.5, 20.0)
|
|
_reg_f("Camera", "cam_follow_lerp", 10.0, 1.0, 40.0)
|
|
# ── Matador ───────────────────────────────────────────────────────────────
|
|
_reg_f("Matador", "mat_spawn_count", 1.0, 1.0, 30.0, 1.0)
|
|
# Hydra split: a slain matador is replaced on the spot by mat_split_factor fresh
|
|
# matadors, so the horde doubles each generation (1 → 2 → 4 → 8 …) at the default
|
|
# 2. Capped at mat_split_generations deep so the arena stays winnable (factor <2 or
|
|
# generations 0 = no splitting, the classic one-and-done arena).
|
|
_reg_f("Matador", "mat_split_factor", 2.0, 1.0, 6.0, 1.0)
|
|
_reg_f("Matador", "mat_split_generations", 3.0, 0.0, 6.0, 1.0)
|
|
# The bull wins outright once it has slain this many matadors, even if the hydra
|
|
# still has bodies on the sand. 0 = disabled (win only when the horde dies out)
|
|
_reg_f("Matador", "mat_win_kills", 21.0, 0.0, 200.0, 1.0)
|
|
_reg_f("Matador", "mat_walk_speed", 5.5, 0.5, 10.0)
|
|
_reg_f("Matador", "mat_wander_radius", 22.0, 5.0, 50.0)
|
|
# Radius of the inner fighting floor: bull + matadors spawn on this ring (so
|
|
# they stay off the benches). Tune in the console to hug the bench edge.
|
|
_reg_f("Matador", "arena_spawn_radius", 10.0, 2.0, 22.0, 0.5)
|
|
_reg_f("Matador", "mat_idle_min", 1.2, 0.0, 5.0, 0.1)
|
|
_reg_f("Matador", "mat_idle_max", 4.0, 0.5, 10.0, 0.1)
|
|
_reg_f("Matador", "mat_hit_threshold", 4.0, 1.0, 30.0)
|
|
_reg_f("Matador", "mat_ragdoll_impulse", 6.0, 0.5, 20.0)
|
|
# Ragdoll joint limits — lower swing/twist = stiffer corpse that keeps its
|
|
# shape; higher angular damp settles the flail instead of flopping flat.
|
|
_reg_f("Matador", "mat_joint_swing", 35.0, 0.0, 180.0, 1.0)
|
|
_reg_f("Matador", "mat_joint_twist", 40.0, 0.0, 180.0, 1.0)
|
|
_reg_f("Matador", "mat_ragdoll_damp", 1.5, 0.0, 10.0, 0.1)
|
|
_reg_f("Matador", "mat_flee_range", 3.5, 2.0, 40.0)
|
|
_reg_f("Matador", "mat_flee_speed", 7.0, 0.5, 12.0)
|
|
_reg_f("Matador", "mat_charge_speed", 10.0, 1.0, 30.0)
|
|
_reg_f("Matador", "mat_brace_range", 5.0, 2.0, 20.0)
|
|
_reg_f("Matador", "mat_brace_duration", 0.7, 0.05, 1.5, 0.05)
|
|
_reg_f("Matador", "mat_commit_dist", 2.5, 0.5, 6.0, 0.1)
|
|
_reg_f("Matador", "mat_step_speed", 6.5, 2.0, 20.0)
|
|
_reg_f("Matador", "mat_step_duration", 0.35, 0.1, 1.0, 0.05)
|
|
# How strongly the sidestep biases toward the bull so the blade sweeps through
|
|
# its path during the pass (0 = pure lateral dodge, 1 = straight at the bull).
|
|
_reg_f("Matador", "mat_pass_lunge", 0.35, 0.0, 1.0, 0.05)
|
|
_reg_f("Matador", "mat_dodge_cooldown", 2.5, 0.5, 12.0, 0.25)
|
|
_reg_f("Matador", "mat_dodge_chance", 0.72, 0.0, 1.0, 0.05)
|
|
_reg_f("Matador", "mat_attack_range", 8.0, 2.0, 20.0)
|
|
_reg_f("Matador", "mat_attack_speed", 7.5, 1.0, 12.0)
|
|
_reg_f("Matador", "mat_attack_duration", 1.8, 0.5, 5.0, 0.1)
|
|
_reg_f("Matador", "mat_attack_min_dist", 3.2, 0.5, 6.0, 0.1)
|
|
# Forward drive during the opening of a melee swing — turns the stationary stab
|
|
# into an estocada lunge so the blade covers ground toward the bull.
|
|
_reg_f("Matador", "mat_lunge_speed", 13.0, 0.0, 20.0)
|
|
_reg_f("Matador", "mat_lunge_time", 0.22, 0.0, 0.6, 0.01)
|
|
# Reach of the reach-based stab (the reliable melee hit) and its re-strike gap.
|
|
# The bull dies if it comes inside mat_stab_reach of a matador that's attacking,
|
|
# bracing, or passing with a drawn blade — closing in is genuinely deadly.
|
|
_reg_f("Matador", "mat_stab_reach", 1.7, 0.5, 4.0, 0.1)
|
|
_reg_f("Matador", "mat_stab_cooldown", 0.6, 0.1, 3.0, 0.1)
|
|
# Half-angle (deg) the matador must be facing the bull within for a stab to land.
|
|
# Stops "sword's off to the side but I still died" — you're only gored when the
|
|
# blade is actually presented at you.
|
|
_reg_f("Matador", "mat_stab_arc", 55.0, 5.0, 180.0, 5.0)
|
|
_reg_f("Matador", "mat_roll_chance", 0.35, 0.0, 1.0, 0.05)
|
|
_reg_f("Matador", "mat_roll_duration", 0.45, 0.1, 1.5, 0.05)
|
|
# Playback rate of the Draw_weapon clip used for both drawing and sheathing —
|
|
# higher = snappier unholster/holster.
|
|
_reg_f("Matador", "mat_draw_speed", 1.9, 0.25, 3.0, 0.05)
|
|
# Cross-fade between matador animation clips — smooths Run/Attack/Taunt cuts.
|
|
_reg_f("Matador", "mat_anim_blend", 0.12, 0.0, 0.5, 0.01)
|
|
# ── Matador heuristics (utility AI) ───────────────────────────────────────
|
|
# Every mat_decide_interval seconds the matador scores its options — dodge the
|
|
# pass, close for a strike, retreat, throw the blade, or strut/taunt — and picks
|
|
# the highest. These weights bias the personality: crank aggression for a reckless
|
|
# bullfighter, caution for a slippery one. mat_w_commit is a stickiness bonus for
|
|
# the current choice so it doesn't dither between two near-tied options.
|
|
_reg_f("Matador", "mat_decide_interval", 0.2, 0.05, 1.0, 0.05)
|
|
_reg_f("Matador", "mat_w_aggression", 1.1, 0.0, 3.0, 0.05)
|
|
_reg_f("Matador", "mat_w_caution", 1.0, 0.0, 3.0, 0.05)
|
|
_reg_f("Matador", "mat_w_flee", 0.8, 0.0, 3.0, 0.05)
|
|
# Showmanship (strut, circle the bull, taunt) — the supporting matadors lean on
|
|
# this to spread out and give the lead room, so a whole crowd reads as a bullring,
|
|
# not a swarm. Crank it for more posturing, drop it for a relentless mob.
|
|
_reg_f("Matador", "mat_w_showmanship", 1.6, 0.0, 3.0, 0.05)
|
|
# Weight on hurling the blade. Kept low — a thrown sword is an occasional flourish,
|
|
# not a barrage; raising this brings back the pelting.
|
|
_reg_f("Matador", "mat_w_throw", 0.35, 0.0, 3.0, 0.05)
|
|
# How many matadors press the bull at once. The nearest this-many engage (close,
|
|
# throw); everyone else keeps their distance and taunts, taking turns as the bull
|
|
# moves. 1 = strict one-on-one, higher = a bolder pack.
|
|
_reg_f("Matador", "mat_engage_slots", 2.0, 1.0, 8.0, 1.0)
|
|
# Preferred distance (m) a taunting matador circles the bull at while waiting its
|
|
# turn — the showmanship ring the crowd spreads out onto.
|
|
_reg_f("Matador", "mat_taunt_ring", 7.0, 3.0, 15.0, 0.5)
|
|
# How long (s) a matador safely out of the action holds a taunt before drifting to
|
|
# a new spot — much longer than the between-passes idle, so bystanders mostly pose
|
|
# for the crowd instead of milling about. Actual hold is randomised ±30%.
|
|
_reg_f("Matador", "mat_taunt_hold", 8.0, 1.0, 20.0, 0.5)
|
|
# Small so it smooths dithering without locking the matador into idling.
|
|
_reg_f("Matador", "mat_w_commit", 0.15, 0.0, 2.0, 0.05)
|
|
# ── Sword ─────────────────────────────────────────────────────────────────
|
|
# Local seating of the sword in the right hand (drawn / fighting).
|
|
# Defaults are identity — the bone is oriented in Blender to seat the sword
|
|
# directly; these exist to fine-tune in-game without re-exporting.
|
|
_reg_f("Sword", "sword_pos_x", 0.0, -1.0, 1.0, 0.01)
|
|
_reg_f("Sword", "sword_pos_y", 0.0, -1.0, 1.0, 0.01)
|
|
_reg_f("Sword", "sword_pos_z", 0.0, -1.0, 1.0, 0.01)
|
|
_reg_f("Sword", "sword_rot_x", 0.0, -180.0, 180.0, 1.0)
|
|
_reg_f("Sword", "sword_rot_y", 0.0, -180.0, 180.0, 1.0)
|
|
_reg_f("Sword", "sword_rot_z", 0.0, -180.0, 180.0, 1.0)
|
|
# Local seating of the sword in the hip holster (sheathed / wandering).
|
|
# Independent of the hand grip so each pose can be tuned without affecting the
|
|
# other. Defaults angle the blade down along the matador's side.
|
|
_reg_f("Sword", "sword_rest_pos_x", 0.0, -1.0, 1.0, 0.01)
|
|
_reg_f("Sword", "sword_rest_pos_y", 0.0, -1.0, 1.0, 0.01)
|
|
_reg_f("Sword", "sword_rest_pos_z", 0.0, -1.0, 1.0, 0.01)
|
|
_reg_f("Sword", "sword_rest_rot_x", -120.0, -180.0, 180.0, 1.0)
|
|
_reg_f("Sword", "sword_rest_rot_y", 0.0, -180.0, 180.0, 1.0)
|
|
_reg_f("Sword", "sword_rest_rot_z", 0.0, -180.0, 180.0, 1.0)
|
|
# ── Spear throw (matador ranged attack) ──────────────────────────────────
|
|
# Local seating of the spear in the throwing hand during the wind-up. Tune to
|
|
# seat the shaft in the grip without re-exporting; flight orientation is derived
|
|
# from the aim direction at release, not from this pose.
|
|
_reg_f("Sword", "spear_pos_x", 0.0, -1.0, 1.0, 0.01)
|
|
_reg_f("Sword", "spear_pos_y", 0.0, -1.0, 1.0, 0.01)
|
|
_reg_f("Sword", "spear_pos_z", 0.0, -1.0, 1.0, 0.01)
|
|
_reg_f("Sword", "spear_rot_x", 0.0, -180.0, 180.0, 1.0)
|
|
_reg_f("Sword", "spear_rot_y", 0.0, -180.0, 180.0, 1.0)
|
|
_reg_f("Sword", "spear_rot_z", 0.0, -180.0, 180.0, 1.0)
|
|
# Delay before a fresh sword reappears in the holster if one is ever lost.
|
|
_reg_f("Sword", "mat_resword_delay", 2.0, 0.0, 10.0, 0.5)
|
|
_reg_f("Sword", "mat_throw_range", 18.0, 5.0, 40.0)
|
|
_reg_f("Sword", "mat_throw_min_dist", 5.0, 2.0, 15.0, 0.1)
|
|
_reg_f("Sword", "mat_throw_windup", 0.5, 0.2, 2.0, 0.05)
|
|
_reg_f("Sword", "mat_throw_release", 0.55, 0.1, 0.95, 0.01)
|
|
# Horizontal speed of the thrown spear; the vertical launch is solved from this
|
|
# and the gravity below so the arc lands on the bull. Lower = a higher, slower lob.
|
|
_reg_f("Sword", "mat_throw_speed", 11.0, 5.0, 60.0)
|
|
# Gravity scale on the spear (higher = a more pronounced arc) and the vertical aim
|
|
# offset from the bull origin down onto its low collision body.
|
|
_reg_f("Sword", "mat_throw_gravity", 1.0, 0.1, 3.0, 0.05)
|
|
_reg_f("Sword", "mat_throw_aim_y", -0.45,-1.5, 0.5, 0.05)
|
|
# Aim scatter (± degrees) so thrown blades can be read and dodged on the move.
|
|
_reg_f("Sword", "mat_throw_spread", 11.0, 0.0, 30.0, 0.5)
|
|
_reg_f("Sword", "mat_throw_arm_cock", 70.0,-180.0, 180.0, 1.0)
|
|
_reg_f("Sword", "mat_throw_arm_release", -90.0,-180.0, 180.0, 1.0)
|
|
_reg_f("Sword", "mat_throw_elbow", 80.0,-180.0, 180.0, 1.0)
|
|
# ── Abilities ─────────────────────────────────────────────────────────────
|
|
_reg_f("Abilities", "kick_cooldown", 1.5, 0.2, 10.0, 0.1)
|
|
_reg_f("Abilities", "kick_range", 6.0, 0.5, 8.0, 0.1)
|
|
_reg_f("Abilities", "kick_strength", 12.0, 1.0, 30.0)
|
|
_reg_f("Abilities", "slam_cooldown", 4.0, 0.5, 15.0, 0.1)
|
|
_reg_f("Abilities", "slam_jump_velocity", 7.0, 2.0, 20.0)
|
|
# Descent gravity multiplier — higher = faster crash, less airtime.
|
|
_reg_f("Abilities", "slam_fall_mult", 3.0, 1.0, 8.0, 0.5)
|
|
# Upward launch velocity (m/s) given to a slammed matador's ragdoll — pops them
|
|
# skyward. ~7 ≈ a 2.5 m hop; 0 disables the launch.
|
|
_reg_f("Abilities", "slam_launch_up", 7.0, 0.0, 15.0, 0.5)
|
|
_reg_f("Abilities", "slam_range", 4.0, 1.0, 10.0, 0.1)
|
|
_reg_f("Abilities", "slam_strength", 14.0, 1.0, 30.0)
|
|
_reg_f("Abilities", "dash_cooldown", 0.5, 0.1, 10.0, 0.1)
|
|
_reg_f("Abilities", "dash_speed", 66.0, 5.0, 200.0)
|
|
# Exponential rate the dash bleeds from dash_speed back to cruise (max_speed).
|
|
# Higher = a snappier bullet that dies off quicker; lower = a longer glide.
|
|
_reg_f("Abilities", "dash_decel", 7.0, 0.5, 30.0, 0.5)
|
|
# ── Roll (homing chain ball) ──────────────────────────────────────────────
|
|
# The bull curls into a ball and ACCELERATES the longer it rolls, from
|
|
# roll_base_speed up to roll_max_speed over roll_rampup_time. It HOMES on the
|
|
# closest matador; on slamming one the ball POPS it (launched skyward via
|
|
# roll_knockup) then CHAINS to the next closest, up to roll_chain_count times.
|
|
# roll_turn is the homing turn rate. When no chain targets remain, the roll ends.
|
|
_reg_f("Roll", "roll_cooldown", 3.0, 0.5, 15.0, 0.1)
|
|
_reg_f("Roll", "roll_duration", 2.5, 0.5, 6.0, 0.1) # max roll time
|
|
_reg_f("Roll", "roll_chain_count", 2.0, 0.0, 8.0, 1.0) # extra matadors chained after the first
|
|
_reg_f("Roll", "roll_base_speed", 28.0, 5.0, 120.0) # speed at the start of the roll
|
|
_reg_f("Roll", "roll_max_speed", 95.0, 10.0, 200.0) # top speed once fully ramped
|
|
_reg_f("Roll", "roll_rampup_time", 2.0, 0.2, 6.0, 0.1) # time to reach top speed
|
|
_reg_f("Roll", "roll_turn", 7.0, 0.2, 20.0) # homing turn rate (higher = tighter tracking)
|
|
_reg_f("Roll", "roll_spin_radius", 1.4, 0.3, 4.0, 0.1) # ball radius for tumble spin (smaller = faster)
|
|
_reg_f("Roll", "roll_hit_radius", 2.4, 0.5, 6.0, 0.1) # contact radius that pops the ball
|
|
_reg_f("Roll", "roll_hit_strength", 22.0, 1.0, 40.0) # horizontal launch on the pop
|
|
_reg_f("Roll", "roll_knockup", 11.0, 0.0, 25.0) # vertical knock-up on the pop
|
|
# ── Debug overlays (see debug_draw.gd) ───────────────────────────────────
|
|
_reg_b("Debug", "show_collisions", false)
|
|
# PS1 post-process filter (see ps1_filter.gd on the fullscreen ColorRect):
|
|
# screen-covering CRT/PS1 shader — pixelation, colour-banding + dither, and a
|
|
# rolling scanline. Keys map 1:1 onto the shader uniforms; show_ps1 toggles the
|
|
# whole overlay. Ranges mirror the shader's hint_range so the console can't push
|
|
# a uniform out of bounds.
|
|
_reg_b("PS1", "show_ps1", true)
|
|
_reg_f("PS1", "ps1_pixel_scale", 4.0, 1.0, 8.0, 1.0)
|
|
_reg_f("PS1", "ps1_color_depth", 5.0, 2.0, 8.0, 1.0)
|
|
_reg_f("PS1", "ps1_dither_strength", 0.8, 0.0, 2.0, 0.05)
|
|
_reg_f("PS1", "ps1_scanline_strength", 0.2, 0.0, 1.0, 0.05)
|
|
_reg_f("PS1", "ps1_roll_speed", 3.0, 0.0, 10.0, 0.1)
|
|
_reg_f("PS1", "ps1_roll_strength", 1.0, 0.0, 1.0, 0.05)
|
|
_reg_b("Debug", "show_hitboxes", false)
|
|
_reg_b("Debug", "show_bones", false)
|
|
_reg_b("Debug", "show_raycasts", false)
|
|
_reg_b("Debug", "show_tail", false)
|
|
_reg_b("Debug", "show_stats", false)
|
|
_reg_b("Debug", "show_states", false)
|
|
_reg_b("Debug", "show_animation_name", false)
|
|
_reg_b("Debug", "show_wireframe", false)
|
|
_reg_b("Debug", "show_grid", false)
|
|
_reg_b("Debug", "show_axes", false)
|
|
# Force the on-screen touch controls (joystick + ability buttons) on even on a
|
|
# desktop build — otherwise they appear only when a touchscreen is detected.
|
|
_reg_b("Touch", "force_touch_controls", false)
|
|
|
|
|
|
func _reg_f(section: String, key: String, default: float,
|
|
min_val: float, max_val: float, step: float = 0.05) -> void:
|
|
_params[key] = {
|
|
"value": default,
|
|
"default": default,
|
|
"section": section,
|
|
"type": TYPE_FLOAT,
|
|
"min": min_val,
|
|
"max": max_val,
|
|
"step": step,
|
|
}
|
|
_values[key] = default
|
|
|
|
|
|
func _reg_b(section: String, key: String, default: bool) -> void:
|
|
_params[key] = {
|
|
"value": default,
|
|
"default": default,
|
|
"section": section,
|
|
"type": TYPE_BOOL,
|
|
}
|
|
_values[key] = default
|
|
|
|
|
|
## Read a float param. Panics on unknown key — intentional: typos should be loud.
|
|
func f(key: String) -> float:
|
|
return _values[key] as float
|
|
|
|
|
|
## Read a bool param.
|
|
func b(key: String) -> bool:
|
|
return _values[key] as bool
|
|
|
|
|
|
func set_value(key: String, value: Variant) -> void:
|
|
if not _params.has(key):
|
|
return
|
|
_params[key]["value"] = value
|
|
_values[key] = value
|
|
any_changed.emit(key, value)
|
|
|
|
|
|
## Returns the full metadata dict — used by Console to build UI.
|
|
func get_all() -> Dictionary:
|
|
return _params
|
|
|
|
|
|
func save() -> void:
|
|
var cfg := ConfigFile.new()
|
|
for key: String in _params:
|
|
var p: Dictionary = _params[key]
|
|
cfg.set_value(p["section"], key, p["value"])
|
|
cfg.save(SAVE_PATH)
|
|
|
|
|
|
func load_saved() -> void:
|
|
var cfg := ConfigFile.new()
|
|
if cfg.load(SAVE_PATH) != OK:
|
|
return
|
|
for section: String in cfg.get_sections():
|
|
for key: String in cfg.get_section_keys(section):
|
|
if not _params.has(key):
|
|
continue
|
|
var p: Dictionary = _params[key]
|
|
var val: Variant = cfg.get_value(section, key)
|
|
if p["type"] == TYPE_FLOAT:
|
|
val = clampf(val as float, p["min"] as float, p["max"] as float)
|
|
_params[key]["value"] = val
|
|
_values[key] = val
|
|
|
|
|
|
func reset_all() -> void:
|
|
for key: String in _params:
|
|
var default: Variant = _params[key]["default"]
|
|
_params[key]["value"] = default
|
|
_values[key] = default
|
|
any_changed.emit("__all__", null)
|
|
|
|
|
|
## Reset a single param to its default. No-op on unknown key.
|
|
func reset(key: String) -> void:
|
|
if not _params.has(key):
|
|
return
|
|
var default: Variant = _params[key]["default"]
|
|
_params[key]["value"] = default
|
|
_values[key] = default
|
|
any_changed.emit(key, default)
|
|
|
|
|
|
## True when the param currently differs from its registered default.
|
|
func is_modified(key: String) -> bool:
|
|
return _params.has(key) and _params[key]["value"] != _params[key]["default"]
|