Pay 'n' Spray and mod shops¶
The game's Pay 'n' Sprays and mod shops run on the server and work as they do in the game. Both are on by default. Players' games run no garage logic: in single player it was the game's own code and mission script, for one player.
Turn either off to build your own from garages and
menus, or keep them and change how they work with
configure.
server.payNSpray.configure({ price: 250 }); // dearer resprays
server.modShops.configure({ priceScale: 1.5 }); // every part 50% more
server.modShops.enabled = false; // no mod shops at all
Pay 'n' Spray¶
server.payNSpray (PayNSpray).
- A player drives in. A police car (or the like) is turned away ("Whoa! I don't touch nothing THAT hot!"), an RC toy too ("I don't do toys!"), and so is anyone without the price ("No more freebies!"). Each gets the game's sound.
- Once the car is wholly inside, the door shuts and holds them still while the spray hisses.
- The car is repaired and resprayed in another colour, and the price is
taken, and it comes out clean (
vehicle.dirt0). A car modified in a mod shop (vehicle.modded) keeps its paint: it's only repaired and cleaned. - Their wanted level is cleared on parole: the old stars flash for 20 seconds, and a crime brings them back.
- The door opens with the game's notice, and a cloud of dust in the new colour rolls out.
It fires vehicleRespray.
enabled¶
Whether they work. Default true. Turned off, their doors stay as they
are: open or shut them yourself as you need.
configure(options)¶
Changes how they work. Only the options given change.
| Option | Type | Default | Description |
|---|---|---|---|
price |
number |
100 |
What a respray costs. |
clearWanted |
boolean |
true |
Clear their wanted level, on parole. |
repair |
boolean |
true |
Repair the car. |
respray |
boolean |
true |
New colours, never the one it had. |
dust |
boolean |
true |
The cloud of dust from the door. |
blips |
boolean |
true |
The game's spray can icon on everyone's radar, near each one. |
hotModels |
number[] |
the game's police vehicles | Models turned away as too hot. |
onEnter |
(player, vehicle, garage) => boolean \| string \| number \| void |
Asked as they drive in, after the game's own checks. |
onEnter can:
- return
falseto turn them away (tell them why yourself); - return a text to turn them away with that notice;
- return a number to use it as the price this time.
server.payNSpray.configure({
onEnter: (player, vehicle) => {
if (player.data.banned) return "~r~We don't serve your kind.";
if (player.data.vip) return 0; // free for VIPs
},
});
garages¶
The Pay 'n' Spray garages.
Mod shops¶
server.modShops (ModShops).
There are five: TransFender in Temple, Doherty and Come-A-Lot, Loco Low Co in Willowfield, and Wheel Arch Angels in Ocean Flats.
Each shop works on its own cars (ModShops.shopFor(model)):
- Loco Low Co: lowriders;
- Wheel Arch Angels: street racers;
-
TransFender: other cars.
-
A player drives in through the door. A car the shop doesn't work on is turned away ("You cannot mod this vehicle here.").
- At the game's spot just inside, the door shuts behind them and the screen fades. The car is put on the shop's own floor, the game's interior for it, in a world of its own, so others can use the shop at the same time. Passengers come along.
- A menu like the game's, under the shop's sign on every level (TransFender's and Wheel Arch Angels' own, from the game; Loco Low Co has none, so its name), lists the areas the car has parts for: Colors, Spoilers, Hood, Exhausts, Wheels, Paint Jobs, and so on. The keys for it show along the bottom left. The radar and chat are hidden meanwhile, and come back as the gamemode had them.
- Each area lists its parts with prices. The car shows each part as it's
chosen, and the camera turns to that part of the car. Colours are the
game's grid of 64, 8 across, the first chosen (and shown on the car) to
begin with. New paint repairs and cleans the car, as the game's script does. With
plateson (the default), a Licence Plate area lets them type a plate of their own. Under the grid: the car's colour now, and the chosen one's price. - Enter buys, and Backspace (or F, as in the game) goes back. Something already on the car, or too dear, gets the game's notice and sound.
- Backing out of the areas puts the car back at the spot inside the door, facing in, as the game does: they reverse out.
Anything chosen but not bought is taken off again.
All of this is the game's own: part names and prices from its
shopping.dat, and from its mod shop script (carmod1.scm) the spots, the
cameras, the headings, the colour and paint job prices, the sounds and the
notices.
It fires modShop on the way in and out (with the
shop's id), vehicleLivery, and
vehicleMod,
vehiclePaintjob and
vehicleRespray for each purchase.
enabled¶
Whether they work. Default true. On, their doors are open, as the game's
script opened them. Off, they're shut, as the game starts them.
configure(options)¶
Changes how every shop works. Only the options given change. Each shop can
have its own options on top (shop(id)), and so can each
player (forPlayer).
| Option | Type | Default | Description |
|---|---|---|---|
enabled |
boolean |
true |
Open. A closed game shop's door is shut. |
shops |
{ transFender?, locoLowCo?, wheelArchAngels? } |
all true |
Which of the game's shops are open. |
title |
string |
the shop's name | The menu's title (text, or gxt()). |
logo |
string \| null |
the shop's sign | An image over the menu: a client file, or a game texture ("game:<txd>/<texture>"). null shows the title alone. |
accepts |
(model) => boolean |
the game's rule | Which cars the shop works on. The game's shops take their own (lowriders, street racers, the rest); a shop you make takes any car with parts. |
sells |
number |
its own | Whose parts it sells: ModShop values added together. A shop you make sells all three. |
areas |
{ [area]: boolean } |
all on | Each area on or off: colors, finishes, liveries, paintjobs, plate, spoilers, hood, vents, sideSkirts, exhausts, nitro, frontBumper, rearBumper, lights, roof, wheels, frontBullbars, rearBullbars, misc, stereo, hydraulics. An area also hides when there's nothing in it for the car, and paintjobs defaults to off at TransFender, as in the game. |
parts |
{ [part]: number \| false } |
Each part by id (MOD_SHOP_PARTS; each wheel is its own part): a price (used as is, without priceScale), or false to not sell it. |
|
priceScale |
number |
1 |
Every other price is multiplied by this. |
price |
(part, price, vehicle, player) => number \| null \| void |
A part's price for this car, after the rest. Return a number to change it, or null to not sell it. |
|
colors |
number[] |
the game's 64, then yours | Exactly which colour ids the colour grid offers, 8 to a row. |
gameColors |
boolean |
true |
The game's 64 colours in the grid (when colors isn't given). false leaves only your own (server.vehicleColors). |
hideColors |
number[] |
Colours left out of the grid. | |
colorPrice |
number |
150 (the game's) |
A colour's price. |
paintjobPrice |
number |
500 (the game's) |
One of the game's paint jobs. |
finishes |
ModShopFinish[] |
DEFAULT_MOD_SHOP_FINISHES |
The Paint Finish area's list (below). |
finishPrice |
number |
1000 |
A finish's price, where it has none of its own. |
liveries |
ModShopLivery[] |
none | The Liveries area's list (below). With none, the area is hidden. |
liveryPrice |
number |
2000 |
A livery's price, where it has none of its own. |
platePrice |
number |
250 |
A plate's price. |
blips |
boolean |
true |
The game's mod garage icon on everyone's radar, near each open shop. |
onEnter |
(player, vehicle, shop, garage) => boolean \| string \| void |
Asked as they drive in, after the shop's own checks. Return false to turn them away (tell them why yourself), or a text to turn them away with that notice. |
|
forPlayer |
(player, vehicle, shop) => ModShopOptions \| void |
Options for this player and car, over the rest (see Per player). |
server.modShops.configure({
gameColors: false, // only your own colours
parts: { 1010: false, 1080: 2500 }, // no 10x nitro; the Switch wheels at $2500
areas: { hydraulics: false },
onEnter: (player) => (player.data.level < 5 ? "~r~Come back at level 5." : undefined),
});
Finishes¶
interface ModShopFinish {
name: string; // as the menu shows it
finish: PaintFinish | null; // null: standard paint
price?: number;
available?: (player, vehicle) => boolean | string | void;
}
The list starts as DEFAULT_MOD_SHOP_FINISHES (Standard, Metallic, Pearl,
Satin, Matte, Colour Shift). Give your own list to reorder it, remove
finishes or add your own paint finish shaders.
available decides who may buy one:
- true (or nothing): everyone;
- false: hidden from them;
- a text: shown, locked, with the text in place of the price.
import { DEFAULT_MOD_SHOP_FINISHES } from "@sagl/server";
server.modShops.configure({
finishes: [
...DEFAULT_MOD_SHOP_FINISHES,
{ name: "Candy", finish: { shader: "shaders/candy.hlsl", params: { depth: 0.6 } }, price: 5000,
available: (player) => player.data.donor ? true : "~r~Donors only" },
],
});
Liveries¶
interface ModShopLivery {
name: string;
livery: Livery | null; // null: none (to take one off)
price?: number;
models?: number[]; // only these models (a livery drawn for one layout)
available?: (player, vehicle) => boolean | string | void;
}
Liveries (paint jobs of your own) shown on the car as they're chosen.
server.modShops.configure({
liveries: [
{ name: "None", livery: null, price: 0 },
{ name: "Sticker Bomb", livery: { texture: "liveries/stickerbomb.jpg" } },
{ name: "Flames", livery: { texture: "game:savanna1/savanna92body256a", mapping: "uv", blend: "multiply" }, models: [567] },
],
});
Per player¶
forPlayer gives options for one player and car, on top of everything
else, when they drive in.
server.modShops.configure({
forPlayer: (player) => {
if (player.data.staff) return { priceScale: 0 }; // free for staff
if (!player.data.donor) return { finishes: DEFAULT_MOD_SHOP_FINISHES.slice(0, 2) }; // Standard, Metallic
},
});
shop(id), shops¶
One shop, and every shop. The game's are "transfender-ls",
"transfender-sf", "transfender-lv", "locolow" and "waa"; yours have
the ids you gave them. A shop's own options go over everyone's.
server.modShops.shop("waa").configure({ priceScale: 1.5, areas: { plate: false } });
server.modShops.shop("transfender-lv").configure({ enabled: false });
ModShopSite |
|
|---|---|
id |
Its id. |
shop |
The game's shop it is (ModShop), or 0 for one you made. |
floor |
Whose shop floor it uses (ModShop). |
garage |
Its garage, or null. |
position |
Where a car starts it. |
configure(options) |
Its own options. |
remove() |
Takes away a shop you made. |
create(spec)¶
Makes a mod shop of your own. A car driving onto at goes to one of the
game's shop floors, with any options you give.
| Field | Type | Default | Description |
|---|---|---|---|
id |
string |
"custom-1", ... |
Its id, for shop(id). |
at |
Vector3 |
Where a car starts it: the middle of the spot it drives onto. | |
size |
Vector3 |
4 x 4 x 2 | How far from at (m, each way) counts. |
exitHeading |
number |
as it came in | Which way the car faces when it's put back at at. |
floor |
number |
ModShop.TransFender |
Whose shop floor it uses: its interior and cameras. |
garage |
Garage |
none | A garage whose door shuts behind them. |
| ...options | Any of configure's. |
server.modShops.create({
id: "docks", at: { x: 2770, y: -2400, z: 13.6 }, floor: ModShop.WheelArchAngels,
title: "Docks Tuning", logo: "ui/docks.png", priceScale: 0.8,
});
garages¶
The mod shop garages, and which shop each is (ModShop).
isShopping(player), kickOut(player)¶
Whether a player is in a shop now, and sending them out of it as if they'd left.
ModShops.shopFor(model)¶
Which shop (ModShop) works on a vehicle model, or 0 for none.
ModShop¶
| Name | Value |
|---|---|
TransFender |
1 |
LocoLowCo |
2 |
WheelArchAngels |
4 |
Data¶
MOD_SHOP_PARTS lists every part the shops sell. Each entry has:
part: the component id;gxt: its name, as a GXT key forgxt();price: the game's price;shops: theModShops that sell it, added together;cat: its area, thenof the game'sCARMntext;pair: for left and right halves sold as one, the other half.
CAR_COLORS lists the game's car colours, 0-127, as 0xRRGGBB, and
MOD_SHOP_COLORS the 64 in the shops' grid (colour ids, row by row).
MOD_SHOP_SITES holds each shop's spots, floor, cameras and exit heading,
from its mission script.
All three come from the game's own files (scripts/gen-modshop-data.py).