t1k:cocos:rushtank:add-player-tank
| Field | Value |
|---|---|
| Module | rushtank |
| Version | 1.2.0 |
| Effort | medium |
| Tools | — |
Keywords: cocos, garage, player, rustank, star-trait, tank, vehicle
How to invoke
Section titled “How to invoke”/t1k:cocos:rushtank:add-player-tankcocos-rushtank-add-player-tank
Section titled “cocos-rushtank-add-player-tank”Add a brand-new drivable player vehicle (e.g. v4 SIEGE, next v5…). Player vehicles are 100% data-driven
through vehicle_list.json; the engine builds ENTITY[vid] at boot via excel.js createVehicleData() by cloning
ENTITY[VEHICLE_BASE="a"] + overlaying vehicle_list fields. ENTITY.tank/tank2/… in tank.js are ENEMY tanks —
not this. Texture re-skins of an existing entity → use cocos-rushtank-entity-variant instead.
SSOT facts live in memory: project_new_player_vehicle_hardcodes, project_excel_sheet_manifest,
project_siege_tank_worktree. Read them first. Full templates + exact snippets: references/add-player-tank-reference.md.
⚠️ The codebase hard-codes v1/v2/v3 in ~6 places. A new
vNsilently falls through each one. The worst is a lookup mapn[this.define.id]inMyVehicle.js→undefined→NaNtower position → bullets deleted → “tank doesn’t attack”.grep "\\[this.define.id\\]"and every== "v3"BEFORE declaring done. This is the #1 cost.
Decision tree
Section titled “Decision tree”- New drivable vehicle with its own art/stats? → this skill (
addflow below). - Same vehicle, just re-skin texture? →
cocos-rushtank-entity-variant. - Enemy/AI tank? → edit
entities/vehicles/tank.js(ENTITY.tankN), not here. - Only add/tune a star trait on an existing player vehicle? → jump to §4 Traits.
Pick the next free vid (v1,v3 exist → next is v4, then v5…) and a free attr letter (a/c used → d,e…).
Step 0 — Verify input data (HARD-GATE — do this FIRST, every invocation)
Section titled “Step 0 — Verify input data (HARD-GATE — do this FIRST, every invocation)”REQUIRED (❌ any → must ask; cannot be safely defaulted):
| # | Field | Feeds |
|---|---|---|
| 1 | vid (v4/v5…, next free) + display name (≥ EN, ideally VI) | §1 vehicle_list / §4 local_vehicle |
| 2 | attr letter (d/e…, free) → vehicle_<attr> + vehicle_star_<attr> | §1 data files |
| 3 | base scaling — clone which existing vehicle_<attr> (hp/atk 181-level) | §1 excel table |
| 4 | art — anime/animeName/animeName2 (reuse a skeleton e.g. v3’s, or new) + gun/wheel/radius | §1 vehicle_list |
| 5 | tower/weapon (tower: MACHINE_GUN/CANNON_GUN/FIRE_GUN) + skill (bomb/incendiary/…) | §1 |
| 6 | 9-star trait design — per star: stat id + magnitude (non-atk/hp → engine extension) | §4 vehicle_star |
| 7 | unlock/shard source — alias to an existing vid’s shard pool, OR a real faucet | §5 shard sites |
OPTIONAL / derivable (❌ → note the default, don’t block):
| Field | Default if missing |
|---|---|
| trait engine wiring (pc.js/Entity.js/MyTower) | auto for any non-atk/hp stat (§4) — flag it |
| localization (16 langs) | auto-fill EN/ZH/VI, machine-translate the other 13 → flag QA |
| art | reuse an existing skeleton (e.g. lanzhanche = v3) as placeholder until real art |
| career / leftMsg / rightMsg board text | derive/placeholder |
| DEV unlock (grant/star-up buttons) | add a DEV_MODE branch for testing |
Emit exactly this shape, then ask:
Input check — <vid>: REQUIRED ✅ vid + name : <values> ❌ 9-star traits : (missing — need stat + magnitude per star) ✅ art : reuse v3 skeleton … OPTIONAL (defaults ready) ❌ localization : auto-fill + flag QA → Ready: <R>/7 required present.Then ASK — every gap, until zero ❌:
AskUserQuestionfor each ❌ REQUIRED (batch ≤4/call; loop). Don’t proceed while any REQUIRED is unanswered.AskUserQuestionto confirm each OPTIONAL default — user OKs or overrides; never apply silently.- Re-print the checklist all-✅, then final
AskUserQuestion: Confirm & build · Change something. Only after that final confirm → run the flow below.
add — full flow (ordered; do in this order)
Section titled “add — full flow (ordered; do in this order)”1. Data files (5 + 2 meta)
Section titled “1. Data files (5 + 2 meta)”| File | Action |
|---|---|
resources/excel/vehicle_<attr>.json (+.meta) | Clone an existing table: cp vehicle_a.json vehicle_<attr>.json; write a .meta with a FRESH uuid. This is the 181-level hp/atk scaling. |
resources/excel/vehicle_star_<attr>.json (+.meta) | 9-star trait table. FRESH uuid meta. See §4 for the attr format. |
resources/excel/vehicle_list.json | Append the vN entry (see reference for full field list: id/career/tower/attr/anime/animeName(2)/gunX/gunY/wheels/radius/skill/leftMsg/rightMsg). Reuse an existing art’s anime/animeName2 (e.g. lanzhanche like v3) until real art exists. |
resources/excel/local_vehicle.json | 2D array (16 lang cols). Append rows vehicle_<vid> (name) + vehicle_<vid>_info_0..8 (per-star text). Use a node script to keep the 16-column count exact — see reference. |
2. Register the new excel sheets — REQUIRED, or it crashes
Section titled “2. Register the new excel sheets — REQUIRED, or it crashes”excel.js loads sheets from a HARD-CODED list, not by scanning. Add BOTH new sheet names to the loadMany([...])
array in excel.js:
"vehicle_star_<attr>", // next to vehicle_star_a/b/c"vehicle_<attr>", // next to vehicle_a/b/cMiss this → excel.read("vehicle_star_<attr>") returns undefined → b[0] crash in createVehicleData
(excel.js:~235). (memory project_excel_sheet_manifest)
3. Patch the hard-coded v1/v3 spots — THE bug-prevention step
Section titled “3. Patch the hard-coded v1/v3 spots — THE bug-prevention step”grep -n "\[this.define.id\]" Client/assets/script and grep -rn '== "v3"\|"v1"\|"v3"' Client/assets/script.
Add the new vid to EACH (mirror v3 since you likely reuse v3 art):
| File | What | Why it matters |
|---|---|---|
scripts/MyVehicle.js top-level var n = {v1:147, v3:167} | add vN: 167 | CRITICAL. Tower mount Y-offset map. Missing → n[vid]=undefined → tower _x/_y = NaN → bullets spawn NaN → no attack. |
components/visual/Avatar.js initDisplayTalent gate | add || id == "vN" to the early-return | Else v-N runs talent-block code meant only for other vehicles. |
entities/vehicles/VehicleAvatar.js addBlock | add vid to the "v3" (→ side2) branch | block-side art. |
scripts/VehicleModel.js addLeader | add vid to the "v3" branch | garage pilot/leader position. |
scripts/checkPointMenu.js | add vid to the "v3" fix-node branch | checkpoint avatar offset. |
ui/inventory/BackpackMenu.js updateBlockSideAvatar | add vid to "v3" (→ side2) | backpack block-side art. |
(Not strictly needed if you alias shards — but know they exist: money.js SHARD_LIST, pc.js getVehiclesAttrGlobal
hard-code v1+v3, EquipmentEncoder.js singleLetterMap, ItemMenu.js ["v1","v2","v3"].)
4. Star traits (see §“Traits” below if the design has explode-radius/crit/etc.)
Section titled “4. Star traits (see §“Traits” below if the design has explode-radius/crit/etc.)”5. Shard source + unlock (for testing & real use)
Section titled “5. Shard source + unlock (for testing & real use)”- Temporary: alias the new vid to an existing vehicle’s shard pool with
pc.getVehicleShardId(vid)(returns e.g.v1), and route EVERY shard-key site through it:GaragePage.js(×2: red-dot + display),VehicleUnlock.js(×4: display, consume, ad-grant id, ad-readback). Without aliasing,shard.<vid>has no faucet → never unlockable. - DEV testing: add a
DEV_MODEbranch on the garage unlock/upgrade buttons to grant/star-up directly (pc.addVehicle({id, star:1})/pc.setVehicle({id, star:n+1})). Or console:pc.addVehicle({id:"vN",star:9}); pc.setChooseVehicle("vN").
6. Verify in-editor (no CLI runtime exists)
Section titled “6. Verify in-editor (no CLI runtime exists)”Open Cocos on the project root (or worktree) Client/, Ctrl+P preview (forces JS recompile + imports new JSON).
- Garage: the new vid auto-appears (garage iterates ALL
vehicle_listentries). - Battle: equipment fires AND damages enemies. If bullets vanish → a NaN reached
Ground.findGround(a guard there returnsleftPartinstead of crashing). Trace with a!isFinitelog atBullet.initwalkingobj → obj.objto see whether tower_xor vehicle_xis NaN (that’s how then[vid]bug was found).
§4 Traits (the 9-star system)
Section titled “§4 Traits (the 9-star system)”vehicle_star_<attr>.json = 9 rows {star, attr, info, price, global?}. attr is a kit.parse-able string:
- single stat:
"{id:'vehicle_atk',num:0.25}" - multi-stat (1 star, many effects): ARRAY string
"[{id:'vehicle_bltExploRange',num:0.25},{id:'vehicle_critChance',num:0.10}]".kit.parse(jsParser) handles arrays; other consumers (adventure.js/train.js) read.id/.globaland skip arrays harmlessly.
Engine accumulates star attrs in pc.getVehicleAttr (self path) into config.attr of the vehicle. It only natively
understands vehicle_atk / vehicle_hp. For any OTHER stat you must extend it (already done for
vehicle_bltExploRange/critChance/critBonus):
pc.js getVehicleAttrself-loop: make it array-aware (Array.isArray(u)?u:[u]) + add anif (uu.id == "vehicle_X")branch that accumulates intor.X.Entity.js initAttributes: make the attribute READconfig.attr— e.g.r.init("critChance", o.critChance||0, …),r.init("bltExploRange", o.bltExploRange||1, …)(default-read,critBonusalready readso.critBonus||…||2).
Propagation: vehicle stat → equipped WEAPONS (critical, easy to miss)
Section titled “Propagation: vehicle stat → equipped WEAPONS (critical, easy to miss)”Star stats land on the vehicle entity, but weapons are separate tower entities. Only some auto-propagate:
- ATK / HP — already reach weapons (
MyTower.getAtkScalechains tower→vehicle; HP is chassis). No work. - Crit / explode-radius / anything else — do NOT auto-reach weapons. Wire in
MyTower.initBonus: the tower inherits the base vehicle’s bonus above the Entity default:Timing is safe: vehiclevar base = this.getBase(); // = the vehiclevar defaults = { critChance:0, critBonus:2, bltExploRange:1 };for (var sn in defaults) {var bonus = base.attribute.get(sn) - defaults[sn]; // vehicle's star bonusif (bonus > 0) this.attribute.add(sn, bonus); // additive onto the tower}initAttributesruns beforeinitSubspawns towers.bltExploRangeonly affects explode bombs (Bomb.explosionreadsobj.bltExploRange) → auto-scoped to Cannon/Mortar/Rocket. Crit reaches bullets viaProto.getPrevchain (bullet→tower). Safe for v1/v3 (bonus=0 → no-op).
Star numbers are cumulative (engine sums every star ≤ current). “+50% (Total)” at ⭐6 when ⭐1 was +25% → put
num:0.25 at ⭐6. critChance is 0–1 absolute; critBonus default 2 (= crit ×2 = +100% dmg) so “+100% crit dmg” → num:1.
Gotcha quick-list (each cost real debugging on SIEGE/v4)
Section titled “Gotcha quick-list (each cost real debugging on SIEGE/v4)”n[this.define.id]in MyVehicle.js missing vid → NaN tower → no attack. Hardest to find (a map, not anif).- excel.js loadMany missing the new sheet → boot crash.
- New JSON in
resources/needs a.metawith a UNIQUE uuid (don’t copy a source.meta→ uuid collision). vehicle_a/ctables have NOhp_vehiclecolumn →config.attr.hp = undefined(fine, falls back; don’t “fix” it).careerfield (e.g."炮") is display-only, not used in logic — any string is fine.- Opening the worktree in Cocos re-imports → thousands of touched
.meta; at commit time stage ONLY the tank files. - A
Ground.findGroundisFiniteguard exists (defensive) — it converts NaN-position crashes into vanished bullets, so “no crash but no attack” still means a NaN somewhere upstream.
Done when
Section titled “Done when”npm run-style check not available; gate on: (1) garage shows vid, (2) unlock works (real shard or DEV), (3) in
battle the tank moves, equipment fires AND damages, traits visibly apply (bigger explosions / crit numbers),
(4) no […] non-finite warnings in console, (5) only the intended tank files are staged.