@adatechnology/game-vehicles 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/MIGRATION.md +397 -0
- package/README.md +267 -2
- package/dist/index.d.ts +824 -0
- package/dist/index.global.js +12015 -0
- package/dist/index.global.js.map +1 -0
- package/dist/index.js +11992 -0
- package/dist/index.js.map +1 -0
- package/package.json +59 -3
package/README.md
CHANGED
|
@@ -1,3 +1,268 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @adatechnology/game-vehicles
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A generic procedural vehicle engine for three.js. It builds cars, trucks, buses, bikes, quads, tractors, tanks, boats, planes and helicopters from
|
|
4
|
+
primitives (body shells, glass, lights, wheels, interiors, hood and engine bay) and gives each vehicle **damage zones with health from 0 to 100** in
|
|
5
|
+
five visual bands, cracking glass, dents, flying parts, fluids, particles, rollover, fire and explosions. A small widget set draws a damage map.
|
|
6
|
+
|
|
7
|
+
The engine has **no content**: no fleet, fuels, scenarios or game texts. A *content pack* (a plugin) registers its vehicles and its own data.
|
|
8
|
+
Everything is deterministic: the same vehicle in the same state with the same zone health always produces the same vertices.
|
|
9
|
+
|
|
10
|
+
`three` is a **type-only peer dependency**: the host passes its own `THREE` namespace to `createVehicleKit`, so the package never bundles three.js.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
pnpm add @adatechnology/game-vehicles three
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Browser without a bundler (the global is `GameVehicles`):
|
|
19
|
+
|
|
20
|
+
```html
|
|
21
|
+
<script src="https://unpkg.com/three@0.128.0/build/three.min.js"></script>
|
|
22
|
+
<script src="https://unpkg.com/@adatechnology/game-vehicles/dist/index.global.js"></script>
|
|
23
|
+
<script>
|
|
24
|
+
const kit = GameVehicles.createVehicleKit({ THREE })
|
|
25
|
+
</script>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
An offline, single-file example (three.js and the IIFE inlined) is built by `pnpm build && pnpm --filter @adatechnology/game-vehicles example:build`
|
|
29
|
+
into `example/dist/vehicles-example.html`. Add `?lang=pt-BR` to switch the language.
|
|
30
|
+
|
|
31
|
+
## Quick start
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import * as THREE from 'three'
|
|
35
|
+
import { createVehicleKit } from '@adatechnology/game-vehicles'
|
|
36
|
+
|
|
37
|
+
const kit = createVehicleKit({
|
|
38
|
+
THREE,
|
|
39
|
+
locale: 'en', // 'en' (default), 'pt-BR', your own registered code, or a partial string table
|
|
40
|
+
document, // optional; defaults to the global document (used for canvas textures)
|
|
41
|
+
plugins: [myContentPack], // optional; same as kit.plugin(myContentPack)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
// 1. register a vehicle: a spec and a build function that draws into the build context `c`
|
|
45
|
+
kit.register({ key: 'meteor', name: 'Meteor 1', group: 'Prototypes', fuel: 'flex', hood: true }, (c) => {
|
|
46
|
+
kit.car(c, {
|
|
47
|
+
W: 1.74, col: '#c23b22', bottomY: 0.3, noseY: 0.62, tailY: 0.8,
|
|
48
|
+
lower: [[-2.0, 0.32, 0.05], [-2.05, 0.95, 0.12], [1.3, 0.98, 0.2], [2.05, 0.75, 0.2], [2.08, 0.35, 0.08]],
|
|
49
|
+
arches: [[1.3, 0.31, 0.37], [-1.25, 0.31, 0.37]],
|
|
50
|
+
gh: { rb: -1.75, rt: -1.2, ft: 0.35, fb: 1.2, belt: 0.98, roof: 1.48, Wg: 1.62, k: 0.18, pillars: [-0.45, -1.2] },
|
|
51
|
+
hl: { style: 'wedge', w: 0.36, h: 0.1 }, tl: { style: 'bar' }, grille: { style: 'seven' },
|
|
52
|
+
interior: { rows: 2, col: '#2c2d30' }, hood: { motor: 'v8' },
|
|
53
|
+
wheels: [[1.3, 0.31, 0.2], [-1.25, 0.31, 0.2, { spokes: 6 }]],
|
|
54
|
+
})
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
// 2. build it and add it to the scene
|
|
58
|
+
const c = kit.build('meteor', 'intact')
|
|
59
|
+
scene.add(c.root)
|
|
60
|
+
|
|
61
|
+
// 3. damage: a health per zone id, or a scenario, or a point impact
|
|
62
|
+
const state = { health: { hood: 38, windshield: 0 }, flags: { burnt: true } }
|
|
63
|
+
scene.remove(c.root); kit.dispose(c)
|
|
64
|
+
const hurt = kit.build('meteor', 'intact', state)
|
|
65
|
+
scene.add(hurt.root)
|
|
66
|
+
|
|
67
|
+
// 4. animate (particles, fluids, hood, rollover, explosions)
|
|
68
|
+
kit.tick(hurt, dt)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Axes: **+x is the front**, +y is up, +z is the right side (the driver sits at negative z), the ground is y = 0, units are metres.
|
|
72
|
+
|
|
73
|
+
## Concepts
|
|
74
|
+
|
|
75
|
+
**Kit.** `createVehicleKit` returns an independent object: its own registry, caches and configuration. Make one per game (or per test).
|
|
76
|
+
|
|
77
|
+
**Build states.** `'intact'`, `'damaged'` and `'modified'` (armour and fittings). The state is part of the random seed, so the three differ in small
|
|
78
|
+
details. `'damaged'` also applies the scenario named by `config.damagedScenario` (a pack sets it) when no zone state is given.
|
|
79
|
+
|
|
80
|
+
**Zones and bands.** Every vehicle gets named zones (`hood`, `door_front_left`, `windshield`, `wheel_front_right`, `engine`, ...) derived from its
|
|
81
|
+
`c.meta` (front, rear, width, belt, top, clearance, glasshouse, wheels, glass, lights, parts) and refined by the builder. A zone has health 0..100
|
|
82
|
+
and a band decided by the health:
|
|
83
|
+
|
|
84
|
+
| Band | Id | Health | Look |
|
|
85
|
+
|---|---|---|---|
|
|
86
|
+
| 0 | `intact` | 76 to 100 | Fine scratches at most |
|
|
87
|
+
| 1 | `scratched` | 51 to 75 | Scratches and chips |
|
|
88
|
+
| 2 | `dented` | 26 to 50 | Dents, hanging parts |
|
|
89
|
+
| 3 | `destroyed` | 1 to 25 | Heavy deformation, parts fall off |
|
|
90
|
+
| 4 | `torn_off` | 0 | The part is gone |
|
|
91
|
+
|
|
92
|
+
Bands only change the look when the band changes; `kit.build(key, state, zoneState)` rebuilds the vehicle and reapplies every zone.
|
|
93
|
+
|
|
94
|
+
**Content packs.** A pack is a plugin: `{ name, configure, install(kit) }`. `configure` accepts everything in the configuration table below and
|
|
95
|
+
`install` can call `kit.register(...)`, `kit.scenario(...)`, `kit.defineFluid(...)`, `kit.on(...)` and so on. The engine never imports a pack.
|
|
96
|
+
|
|
97
|
+
**Locale.** Every user-visible string (zone and part names, band names, effect texts, UI text) comes from a string table. English is built in
|
|
98
|
+
(`locales/en.json`) and Brazilian Portuguese is included (`locales/pt-BR.json`). A partial table falls back to English key by key.
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
import { registerLocale } from '@adatechnology/game-vehicles'
|
|
102
|
+
registerLocale('es', { bands: { intact: 'Intacto', torn_off: 'Arrancado' } })
|
|
103
|
+
const kit = createVehicleKit({ THREE, locale: 'es' }) // everything else stays English
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
A content pack adds its own strings under its own top-level key with `kit.registerLocale(code, table)`. The kit keeps the locale it was
|
|
107
|
+
created with, so `kit.t('mypack.some.key')` reads from it, with English as the fallback.
|
|
108
|
+
|
|
109
|
+
## API
|
|
110
|
+
|
|
111
|
+
### Kit options (`createVehicleKit(options)`)
|
|
112
|
+
|
|
113
|
+
| Option | Meaning |
|
|
114
|
+
|---|---|
|
|
115
|
+
| `THREE` | The three.js namespace (required) |
|
|
116
|
+
| `locale` | A registered code (`'en'`, `'pt-BR'`, `'pt'`), or a partial string table. Default `'en'` |
|
|
117
|
+
| `document` | Document for canvas textures and the UI; default the global one |
|
|
118
|
+
| `plugins` | Plugins installed in order |
|
|
119
|
+
| anything else | A configuration (below), as if passed to `kit.configure` |
|
|
120
|
+
|
|
121
|
+
### Configuration (`kit.configure(options)` and `plugin.configure`)
|
|
122
|
+
|
|
123
|
+
| Key | Meaning |
|
|
124
|
+
|---|---|
|
|
125
|
+
| `bands` | Five `{ name, color, min, health }` overrides |
|
|
126
|
+
| `zoneEffects` | Effect text of a zone by `fxKey` or zone type, five texts (one per band); `{who}` is the occupant |
|
|
127
|
+
| `partEffects` | Effect text by part kind (crash report) |
|
|
128
|
+
| `scenarios` | Scenario definitions (see below) |
|
|
129
|
+
| `flagEffects` | Visual effect of a scenario flag: `{ order, settle, apply(c, flags, kit) }` |
|
|
130
|
+
| `fluids` | Fluid types for splats: `{ fresh, dry, dryTime, roughFresh, roughDry, metalFresh, metalDry, wipeable }` |
|
|
131
|
+
| `fuels`, `groups`, `waterGroups` | Registries for the pack's own use |
|
|
132
|
+
| `palette.rust` | Rust colour |
|
|
133
|
+
| `plate`, `texts` | Default plate text; `texts` has `who`, `noEffect`, `plate`, `ui` |
|
|
134
|
+
| `impactStain`, `defaultSplat` | Fluid key of the stain an impact leaves; default fluid of `splat` |
|
|
135
|
+
| `defaultGroup`, `damagedScenario` | Group of vehicles without one; scenario of the `'damaged'` state |
|
|
136
|
+
|
|
137
|
+
### Kit methods
|
|
138
|
+
|
|
139
|
+
| Area | Methods |
|
|
140
|
+
|---|---|
|
|
141
|
+
| Registry | `register(spec, build)`, `find(key)`, `fleet`, `configure`, `plugin`, `on`/`hook`, `scenario`, `defineFluid` |
|
|
142
|
+
| Lifecycle | `build(key, state?, zoneState?)`, `dispose(c)`, `tick(c, dt)`, `settle(c, seconds)`, `defaultDamage(c)` |
|
|
143
|
+
| Zones | `bandOf(health)`, `zonesOf(c)`, `applyZones(c, state)`, `zoneScenario(c, id)`, `zoneOverall(c)`, `zoneAt(c, point)`, `zoneDamageAt(c, point, dir, force)`, `zonePoint(c, zone)`, `zoneEffect(zone, health?)`, `zoneOwner` |
|
|
144
|
+
| Events | `impact(c, point, dir, force, options?)`, `zoneImpact(c, side, force)` (side: `front`, `rear`, `left`, `right` or `rolled`), `explode(c, options?)`, `blastDamage(c, amount)`, `roll(c, side?)`, `setHood(c, open)` |
|
|
145
|
+
| Fluids and particles | `splat`, `puddle`, `wipe(c, mode)` (`wiper` or `rain`), `spawn`, `burst`, `addEmitter` |
|
|
146
|
+
| Builders | `car`, `shell`, `addGlass`, `headlight`, `taillight`, `lightBar`, `grille`, `emblem`, `seat`, `interior`, `dashboard`, `steeringWheel`, `busRows`, `makeHood`, `engineBay`, `truckCab`, `truckChassis`, `spokedWheel`, `tracks`, `underbody`, `archFlare`, `jerryCan`, `geo.*` |
|
|
147
|
+
| Data | `bands`, `scenarios`, `fleet`, `fluidTypes`, `flagEffects`, `zoneEffects`, `partEffects`, `materials`, `config`, `strings`, `t(key, vars?)` |
|
|
148
|
+
| UI | `ui.damageMap`, `ui.bandButtons`, `ui.legend`, `ui.healthBar`, `ui.scenarioButtons`, `ui.zoneLabel`, `ui.bandRange`, `ui.css`, `ui.injectStyles` |
|
|
149
|
+
| Plugin helpers | `internals` (`rng`, `strHash`, `zonesOf`, `worldInverseOf`, `hideObj`, `markDecal`, `rayCaster`, `boxCenter`, `wheelInfo`) |
|
|
150
|
+
|
|
151
|
+
The typed surface (`VehicleKit`, `VehicleContext`, `DamageZone`, `ScenarioDefinition`, `Plugin`, ...) is exported from the package. The low-level
|
|
152
|
+
builders take and return three.js objects, so their parameters are loosely typed.
|
|
153
|
+
|
|
154
|
+
### The build context `c`
|
|
155
|
+
|
|
156
|
+
`kit.build` returns the context: `c.root` (add it to the scene), `c.vehicle` (the vehicle group, a child of `root`), `c.meta`, `c.zones`,
|
|
157
|
+
`c.zoneState` (`{ health, flags }`), `c.parts`, `c.glass`, `c.lights`, `c.wheels`, `c.log` (impact log), `c.rand` (deterministic random) and the
|
|
158
|
+
drawing primitives used by builders: `roundBox`, `cylinder`, `sphere`, `rod`, `add`, `part`, `wheel`, `paint`, `zone`, ...
|
|
159
|
+
|
|
160
|
+
`c.meta` fields: `kind` (`car`, `bike`, `quad`, `tractor`, `truck`, `bus`, `tank`, `boat`, `plane`, `heli`), `length`, `width`, `front`, `rear`,
|
|
161
|
+
`clearance`, `belt`, `top`, `bodyHeight`, `roof`, `bed`, `fuselageWidth`, `glasshouse`, `armor`, `damage`, `exhaust`. Missing fields are measured from the
|
|
162
|
+
bounding box.
|
|
163
|
+
|
|
164
|
+
### Scenarios
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
kit.scenario({
|
|
168
|
+
id: 'front',
|
|
169
|
+
name: 'Crushed nose',
|
|
170
|
+
init: (x) => { x.limit = x.front - 0.4 * x.length },
|
|
171
|
+
zone: (zone, x) => {
|
|
172
|
+
if (x.center.x > x.limit) x.set(zone, 15 + x.rand() * 20) // health 15..35
|
|
173
|
+
if (zone.type === 'roof') x.flags.flipped = true
|
|
174
|
+
},
|
|
175
|
+
})
|
|
176
|
+
const result = kit.zoneScenario(c, 'front') // { health, flags, scenario }
|
|
177
|
+
const hurt = kit.build('meteor', 'intact', result)
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
`x` has `c`, `meta`, `front`, `rear`, `length`, `width`, `clearance`, `top`, `rand()`, `set(zone, health)`, `flags`, `health`, `center` (of the zone
|
|
181
|
+
being visited), `isWindshield`, `bodyTypes`, `clamp`. Built-in flags are `flipped`, `burnt` and `abandoned`; a pack adds more with `flagEffects`.
|
|
182
|
+
|
|
183
|
+
### The car spec (`kit.car(c, spec)`)
|
|
184
|
+
|
|
185
|
+
Lengths in metres. The short field names are kept from the original engine and are listed here once.
|
|
186
|
+
|
|
187
|
+
| Field | Meaning |
|
|
188
|
+
|---|---|
|
|
189
|
+
| `W`, `col`, `roofCol` | Body width, paint colour, optional roof colour |
|
|
190
|
+
| `bottomY`, `noseY`, `tailY` | Lower edge of the body; heights where the front and rear ends are measured |
|
|
191
|
+
| `lower` | Side profile `[[x, y, cornerRadius], ...]` from rear to front |
|
|
192
|
+
| `arches` | Wheel arches `[[x, wheelCentreY, radius], ...]` |
|
|
193
|
+
| `gh` | Glasshouse: `rb`/`rt` rear base/top x, `ft`/`fb` front top/base x, `belt`, `roof`, `Wg` width, `k` softness, `pillars` |
|
|
194
|
+
| `hl`, `tl`, `grille` | Headlights and taillights `{ style, w, h, y, in, yaw }`; grille `{ style, w, h, y }` or `false` |
|
|
195
|
+
| `interior`, `hood` | Interior `{ rows, col, trim }` or `false`; engine bay `{ motor, front }`, `true` or `false` |
|
|
196
|
+
| `wheels` | `[[x, radius, width, options], ...]` |
|
|
197
|
+
|
|
198
|
+
### UI widgets
|
|
199
|
+
|
|
200
|
+
Plain DOM and SVG, no framework: `ui.damageMap(host, c, { selected, onSelect })` draws the top-down map (external zones on the outline, internal
|
|
201
|
+
ones in a strip below); `ui.bandButtons`, `ui.legend`, `ui.healthBar({ text, bar }, c)`, `ui.scenarioButtons`. `ui.injectStyles()` adds minimal CSS
|
|
202
|
+
(`--panel-2`, `--line` and `--muted` customise it).
|
|
203
|
+
|
|
204
|
+
## Determinism and old seeds
|
|
205
|
+
|
|
206
|
+
The random stream of a zone is seeded from the vehicle key, the zone id and the band. The first version of this engine used Portuguese ids, so ids
|
|
207
|
+
and salts that were renamed keep their original text for seeding (`LEGACY_ZONE_IDS`, `LEGACY_STATES`, `SEED_SALTS`, `legacyZoneId`, and a
|
|
208
|
+
`seedId` option on zones). A vehicle looks exactly as it did before the rename. A content pack can set `seedId` on its own zones to keep an older look,
|
|
209
|
+
`seedKey` on a vehicle spec (used instead of `key` for every random stream) and `seedId` on a scenario (used instead of `id`), so ids can be renamed without changing a result. `kit.registerLegacySeeds({ zones, glassLabels })` registers the original text of
|
|
210
|
+
zone ids and glass keys (shared by every kit); a glass key that contains `windshield` or `rear` counts as the windshield or the rear glass.
|
|
211
|
+
|
|
212
|
+
Coming from the Portuguese `VehicleSDK`? The complete old-to-new table is in [MIGRATION.md](./MIGRATION.md).
|
|
213
|
+
|
|
214
|
+
## Destruction contract
|
|
215
|
+
|
|
216
|
+
`createVehicleDestructible(kit, c, options)` makes a built vehicle follow the `DestructibleImpl` of [`@adatechnology/game-contracts`](../game-contracts), so a test room (or any host) can shoot, burn, blast and unbolt it. It depends on the contracts only (types), not on the default destruction world.
|
|
217
|
+
|
|
218
|
+
```ts
|
|
219
|
+
import { buildVehicleItem, createVehicleDestructible } from '@adatechnology/game-vehicles'
|
|
220
|
+
|
|
221
|
+
const item = buildVehicleItem(kit, 'meteor') // origin at the footprint centre, front facing +z
|
|
222
|
+
const car = createVehicleDestructible(kit, item.vehicle, { id: 'meteor_1', frame: item.root })
|
|
223
|
+
const events = car.hit({ type: 'ballistic', point, direction, energy: 500, caliber: 9 })
|
|
224
|
+
car.status() // { canStart, lightsOn, canDrive, brakeFactor, steerPull, flatTyres, ... }
|
|
225
|
+
car.animations() // open/close clips for the doors, hood and trunk
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**Parts.** Every damage zone is a part (steel body panels, doors, hood and fenders; aluminium for aircraft and boats; glass for windows and lights; plastic for bumpers and mirrors; rubber for tyres). The engine adds the mechanical parts the zones do not cover, by vehicle kind and from the meta: `battery`, `alternator`, `gearbox`, `brakes`, `steering`, `shock_absorbers`, `oil_pan`, a separate `tyre_*` for every wheel, `mirror_left/right`, `pillar_a/c_*` on cars and an optional `tow_hitch` (option `hitch`, then the spec flag `hitch`, then a seeded choice). Names are in `locales` (`mechanics.*`).
|
|
229
|
+
|
|
230
|
+
**Joints.** `hinge` for doors, hood and trunk lid; `bolt` for wheels, fenders, bumpers, mirrors, battery, lights and the mechanics; `weld` for the roof, the pillars and side panels; `glue` for glass; `clip` for the tyre on its rim. Each joint wears when the part it holds is hit, and a wrench, screwdriver or cutting torch undoes it (`disassemble`).
|
|
231
|
+
|
|
232
|
+
**Detaching.** Bumpers, fenders, mirrors, lights, wheels (and tyres), doors, hood, trunk lid, battery and hitch come off as separate objects and fall (the kit's ballistic animation). Hidden mechanics are logical: `status()` says what they do (brakes: longer stop; steering: pulls to one side; battery or alternator: no start and no lights; gearbox: no drive).
|
|
233
|
+
|
|
234
|
+
| Hit | Mapped to |
|
|
235
|
+
|---|---|
|
|
236
|
+
| `ballistic` | hole (through when the energy beats the material), dent when it holds, ricochet at a shallow angle, crack or shatter on glass, leak on a tank, flat tyre |
|
|
237
|
+
| `blunt`, `slash` | `kit.impact` for hard blows, dents with depth, damage by distance, joint wear (bumpers and mirrors tear off) |
|
|
238
|
+
| `explosive` | `kit.impact`, `kit.blastDamage`, damage by distance; a tank blast gives `explode` |
|
|
239
|
+
| `fire`, `heat` | temperature by part, `ignite`, `melt` (tyres, plastic), `burnout`, `explode` when the tank passes its temperature |
|
|
240
|
+
| wrench and others | `disassemble` with `disassemble_progress` and `detach` |
|
|
241
|
+
|
|
242
|
+
Fluids: the tank, the oil pan and the radiator hold fuel, oil and coolant; a hole below the level makes a `leak` event, a puddle and a falling level.
|
|
243
|
+
|
|
244
|
+
## Português
|
|
245
|
+
|
|
246
|
+
Motor genérico de veículos procedurais para three.js: carrocerias, vidros, faróis, rodas, interiores, capô e compartimento do motor, **zonas de dano
|
|
247
|
+
com saúde de 0 a 100** em cinco faixas visuais, vidros que trincam, peças que soltam, fluidos, partículas, capotagem, fogo e explosões, mais widgets
|
|
248
|
+
de mapa de danos. O motor **não tem conteúdo**: frota, combustíveis, cenários e textos do jogo vêm de *content packs* (plugins). Tudo é determinístico.
|
|
249
|
+
|
|
250
|
+
```ts
|
|
251
|
+
import * as THREE from 'three'
|
|
252
|
+
import { createVehicleKit } from '@adatechnology/game-vehicles'
|
|
253
|
+
|
|
254
|
+
const kit = createVehicleKit({ THREE, locale: 'pt-BR' }) // 'en' é o padrão; faltou uma chave, cai no inglês
|
|
255
|
+
kit.register({ key: 'meteoro', name: 'Meteoro 1', fuel: 'flex' }, (c) => kit.car(c, spec))
|
|
256
|
+
const c = kit.build('meteoro', 'intact', { health: { hood: 38 }, flags: {} }) // estados: 'intact' | 'damaged' | 'modified'
|
|
257
|
+
scene.add(c.root)
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
- Eixos: **+x é a frente**, +y é para cima, +z é a direita (o motorista fica em z negativo); unidades em metros.
|
|
261
|
+
- Faixas: `intact` 76 a 100, `scratched` 51 a 75, `dented` 26 a 50, `destroyed` 1 a 25, `torn_off` 0.
|
|
262
|
+
- Os textos em português estão em `locales/pt-BR.json` e saem exatamente como no SDK original (`Para-choque dianteiro`, `Capô`, `Arrancado`...).
|
|
263
|
+
- A API e os nomes agora são todos em inglês; a tabela completa de nomes antigos para novos está em [MIGRATION.md](./MIGRATION.md).
|
|
264
|
+
- O exemplo offline (`example:build`) aceita `?lang=pt-BR`.
|
|
265
|
+
|
|
266
|
+
### Contrato de destruição
|
|
267
|
+
|
|
268
|
+
`createVehicleDestructible(kit, c, opções)` faz um veículo construído seguir o `DestructibleImpl` de `@adatechnology/game-contracts`: cada zona de dano vira uma peça com material, as peças mecânicas (bateria, alternador, câmbio, freios, direção, amortecedores, pneus, retrovisores, engate) são acrescentadas, as juntas (dobradiça, parafuso, solda) se desfazem por desgaste ou com a chave inglesa, e as peças saem do veículo e caem. `status()` diz o que a mecânica faz (freios, direção, bateria, câmbio). Os nomes em português estão em `locales/pt-BR.json` (`mechanics.*`).
|