Scope cut: drive-only MVP (remove racing + economy)
CI / quality (push) Successful in 1m1s

Per user direction, the MVP is now simply driving cars on the expressway.
- Removed RaceManager and Economy modules entirely
- Slimmed Remotes to DataUpdated / SpawnCar / EquipCar
- ProfileTemplate now just remembers the last driven car (v2)
- Cars: dropped price/rep/upgrade fields; kept identity + driving stats
- CarManager: stat-based tuning only; RX-7 allowlist via GameConfig.canDrive
- DataManager: assign default car on join; downgrade RX-7 if de-allowlisted
- Client: replaced garage/economy UI with a simple car picker + respawn
- Docs: GDD/ROADMAP/README rewritten for drive-only; added docs/MESH_SWAP.md
- Gates: stylua clean, selene 0/0, rojo builds
This commit is contained in:
2026-07-22 00:11:11 -04:00
parent 5fc03d611d
commit 07a67204ca
14 changed files with 347 additions and 781 deletions
+5 -27
View File
@@ -9,8 +9,6 @@
the most reliable, least-buggy way to get a car moving on day one. When you
later import the real RX-7 mesh + a constraint chassis (A-Chassis style),
you swap out `buildCarModel` and keep everything else.
Upgrades scale MaxSpeed / Torque / TurnSpeed so the upgrade economy is real.
]]
local Players = game:GetService("Players")
@@ -20,10 +18,8 @@ local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Shared = ReplicatedStorage.Shared
local Cars = require(Shared.Cars)
local GameConfig = require(Shared.GameConfig)
local ProfileTemplate = require(Shared.ProfileTemplate)
local DataManager = require(script.Parent.DataManager)
type ProfileData = ProfileTemplate.ProfileData
type Car = Cars.Car
local CarManager = {}
@@ -31,17 +27,11 @@ local CarManager = {}
local activeCars: { [Player]: Model } = {}
local carsFolder: Folder
-- Convert a car's 0-100 stats + upgrade levels into VehicleSeat tuning --------
local function computeTuning(car: Car, upgrades: { Engine: number, Tires: number, Nitro: number })
local engineLvl = upgrades.Engine or 0
local tiresLvl = upgrades.Tires or 0
-- Base values derived from stats; upgrades add a percentage on top.
-- Convert a car's 0-100 stats into VehicleSeat tuning ------------------------
local function computeTuning(car: Car)
local maxSpeed = 60 + car.Stats.Speed * 1.6 -- studs/sec-ish target
maxSpeed *= (1 + engineLvl * 0.08) -- +8% top speed per engine level
local torque = 8000 + car.Stats.Acceleration * 220
torque *= (1 + engineLvl * 0.10)
local turnSpeed = 20 + car.Stats.Handling * 0.35
turnSpeed *= (1 + tiresLvl * 0.06) -- tires help turn-in
return maxSpeed, torque, turnSpeed
end
@@ -126,26 +116,14 @@ function CarManager.spawn(player: Player, carId: string?)
if not car then
return
end
-- Defense in depth: never spawn the restricted RX-7 for a non-allowlisted user,
-- even if their save somehow contained it.
if car.Id == GameConfig.RestrictedStarterCarId and not GameConfig.isRX7Allowed(player.UserId) then
return
end
-- Only spawn cars the player owns (anti-cheat: no spawning unowned exotics).
local owned
for _, o in ipairs(data.OwnedCars) do
if o.Id == id then
owned = o
break
end
end
if not owned then
-- Restricted car (RX-7) can only be driven by allowlisted UserIds.
if not GameConfig.canDrive(player.UserId, car.Id, car.Restricted) then
return
end
CarManager.despawn(player)
local maxSpeed, torque, turnSpeed = computeTuning(car, owned.Upgrades)
local maxSpeed, torque, turnSpeed = computeTuning(car)
local model = buildCarModel(car, maxSpeed, torque, turnSpeed)
model:PivotTo(spawnCFrame())
model.Parent = carsFolder