What Changed, What's New, What's Gone
Overview
This update is the biggest overhaul the game has ever had. The old version was a single 17,763-line index.html with every system — game engine, UI, audio, multiplayer, progression — all crammed into one file. The new version is a fully split codebase across 12 separate .js files totalling ~22,400 lines, with entirely new systems that simply didn't exist before. This isn't a patch. Almost everything was rethought from scratch.
Architecture — Complete Rewrite
Old: One monolithic index.html. Everything in one place. Every bug touched every other system.
New:Â Split into dedicated modules.
Constants, tower/enemy/upgrade data tables
All 12 map path definitions
Core game loop, wave logic, multiplayer socket
Enemy behavior, wave data, map decorations, biome borders
All tower models, skin system, upgrade logic
All menus, HUD, event listeners
Audio engine, save/load, settings
VFX — explosions, particles, floating text
Scrap economy, skin catalog, shop, locker
Post-processing, loading screen, performance monitor
XP, levels, skill tree, achievements, daily challenges
RoleConfig.jsMaps.jsGame.jsEnemies.jsTowers.jsUI.jsUtils.jsProjectiles.jsLockerSystem.jsEnhancements.jsprogression-FINAL-v5.js
The two external scripts map-creator-system.js and map-editor-integration.js that were referenced in the old game are no longer included.
Scrap Economy & Skin System — Brand New
The old game had zero cosmetic system. No skins, no currency, no shop. The defeat screen was just "DEFEAT — You reached Wave X" with a Try Again button and an itch.io download link.
The new version has a complete cosmetic economy built from the ground up.
Scraps are the currency. You earn them every run based on waves completed and difficulty. The formula is waves × difficulty multiplier + 20 win bonus, where Easy gives ×1, Medium ×2, Hard ×3. Scraps are deferred — they're calculated at run-end but only committed to your account when you actually leave (Try Again / Menu / Continue). This prevents revive-and-die loops from multiplying your payout.
Skin Catalog has 67 skins across 4 rarity tiers spread across all 11 tower types:
Common (34) — flat recolors, no material tricks, cheap
Rare (10) — material and finish transformations, subtle emissive, camo patterns
Epic (12) — multi-tone full-body camo, heavy dual-material combos
Legendary (11) — full geometry remodels with entirely new meshes and extreme emissive glow
Shop rotates 8 skins every day at 12:00 PM CET (DST-aware). The rotation is globally seeded — everyone sees the same 8 skins. The first slot is the Featured skin, the second is the Deal of the Day at 30% off. A wishlist system lets you bookmark skins so you know when they appear in the rotation. Skins you've never seen before show a NEW badge.
Locker shows everything you own organized by tower type. You can equip one skin per tower at a time. Both the Shop and Locker have a dedicated 3D preview renderer — a mini Three.js instance with three-point lighting where you can drag to rotate the model and use the level/branch toggles to preview how a skin looks at every upgrade tier.
Defeat and Victory screens were completely rebuilt. Both now show a Scrap Breakdown panel — waves, difficulty multiplier, base total, win bonus. Two ad buttons appear: one to Revive (on defeat only) and one to double your scraps for that run. Both are disabled if ads aren't available.
Rewarded Ads — Actually Work Now
Old:Â showRewardAd()Â was a stub function that logged "reward granted instantly (ad disabled)" and immediately called the success callback. No ad ever played. The CrazyGames SDK integration file existed as a standalone helper document but wasn't wired into the game's reward flow in any meaningful way. Midgame ads were explicitly disabled with a comment saying so.
New: Uses Google IMA SDK. checkAdAvailable() is called asynchronously when the defeat/victory screen opens. Ad buttons only become clickable if IMA confirms a real ad is loaded and ready. If there's no fill, the buttons stay greyed out. The revive button replays the wave you died on, clears all leaked enemies and projectiles, and restores 1 life. The 2× scraps button doubles the pending total before it gets committed to your account. Both buttons disable themselves after use — one claim per run.
Daily Challenges — Complete Rework
Old: A flat pool of 23 static challenge objects with reward as a plain string like '300 XP + 1 SP'. The daily seed used a simple fixed CET+1 offset with no DST awareness, meaning the reset time drifted by an hour in summer. Every player got the same 3 challenges, seeded only by date. There was no Gold Earned challenge category. Challenges never reset within a session — a "kill 100 enemies in one run" challenge would keep accumulating across multiple runs.
New: A tiered template system. Each of the 9 challenge types has 3 difficulty tiers (easy/medium/hard). The daily seed picks which tier of each template shows up today, so both the challenge type and its difficulty rotate. Rewards are structured objects with separate xp, sp, and scraps fields — scraps now go directly into your LockerSystem balance when a challenge completes.
Challenge seed now includes a user token (logged-in user ID or a persistent guest token), so different players can get different challenges on the same day. The date reset is DST-aware using the same _cetResetUTCSecs helper that the shop uses.
A new perRun flag marks challenges like "kill X enemies in one run." These reset their progress back to zero at the start of every new game via resetRunChallenges(). This was missing entirely before.
Gold Earned is a new challenge track that didn't exist in the old pool.
XP Formula — Conflict Resolved
Old: There were two conflicting XP formulas in the codebase at the same time. index.html defined xpForLevel as an exponential curve: Math.floor(100 * Math.pow(1.15, level - 1)). The progression-FINAL-v5.js file simultaneously defined it as a linear formula: 100 + (level * 50). Whichever script loaded last won, creating inconsistent behavior depending on load order.
New: One canonical definition lives in progression-FINAL-v5.js: 100 + (level * 50). This gives Level 1→2 at 150 XP, Level 9→10 at 600 XP, Level 19→20 at 1,100 XP. The conflicting exponential definition in index.html is gone.
Biome World System — Brand New
The old maps were a flat 240×180 ground plane floating in fog. No edges, no context, no borders. Decorations existed but they were scattered randomly at ground level.
The new version runs buildMapBiome() on every map load. Each of the 12 maps gets a full set of world-boundary geometry:
Extended Ground Skirt — An 800×600 plane at y=-0.5 extends beyond the playable area in the map's biome color, plus four transition slope panels at the borders. No more hard cliff edges.
Road Kerbs — Thin colored strips run flush along both sides of every path segment, calculated from road width offset and aligned with each segment's direction vector.
Perimeter Backdrops — Each map has unique geometry around its outer boundary. Canyon gets layered 45-unit sandstone cliffs with sediment bands and crack lines. Frozen gets 14 jagged ice mountain peaks with snow caps. Volcano gets basalt walls with emissive lava crack strips. Kitty Kingdom gets candy castle towers with cone roofs at corners and floating cloud platforms. The Void gets 60-unit obelisks with glowing octahedron tips and a ring of floating debris. Crystal Caves gets a cave ceiling, hanging stalactites, and giant emissive crystal clusters. Neon City gets a full skyscraper backdrop up to 70 units tall with glowing window grids and neon edge strips. Toxic Swamp gets a murky water plane, shimmer patches, and gnarled dead trees with twisted branches. Space Station gets riveted hull panels, solar arrays, and a distant planet with a ring system. Harvest Valley gets rolling hill silhouettes, a barn, wheat field strips, and wooden fence posts. Jungle Temple gets a dense canopy, broken stone columns, a waterfall, and foliage backdrop walls. Mushroom Forest gets 16 bioluminescent ground patches and 14 giant mushrooms up to 31 units tall with glowing spots.
Border Landmark Pass in Enemies.js scatters 30 additional tall props exclusively in the outer band (beyond 95 units on X or 70 units on Z) per map, so the perimeter feels populated without placing anything inside the play area.
Towers — Procedural Rust Texture & Skin Engine
Old:Â Tower models existed but had no skin system whatsoever. No way to change how any tower looked. No procedural materials.
New: A full skin system runs inside createTowerModel(). When a skin is equipped, the function reads the skin's rarity and type before building materials. Common skins apply a flat recolor. Rare skins adjust metalness, roughness, and a subtle emissive. Epic camo skins use a multi-patch canvas texture applied across base and head meshes. Legendary remodel skins get their own geometry and material blocks, bypassing the default model construction entirely.
A procedural rust texture engine was added. It generates a 256×256 canvas texture at runtime with dark iron base, radial rust bloom patches at seven positions with custom gradients, vertical gravity-fed corrosion drip streaks, and randomly placed flaking pits and bright orange highlight flecks. The resulting texture is used as both the color map and roughness map so rust patches are visually rougher than clean metal.
Multiplayer skin sync now works via _applyRemoteSkin(). When you receive another player's tower build over the network, their equipped skin is applied to the freshly-created mesh on your client.
Security Fix — GameJolt Private Key
Old: GAMEJOLT_PRIVATE_KEY = 'e3a9ac5cee4e774548bbc80f2b184cd6' was sitting in plain text in index.html, visible to anyone who opened devtools or viewed source.
New:Â The private key is removed entirely. A security warning comment explains that private keys must never be in client-side code and should be handled through a backend API endpoint. The public game ID remains.
Native Alerts Replaced with Custom Modals
Old: Native browser alert() and confirm() calls were used throughout the codebase — for skill tree errors ("Max level!", "Not enough skill points!"), multiplayer errors ("Connection lost!", "Host disconnected!"), map editor confirmations, and offline warnings.
New: A custom kAlert() / kConfirm() modal system built into index.html. Styled to match the game's Orbitron glass-morphism aesthetic with icons, danger variants for error states, and keyboard Escape support. All the native alert calls are replaced with these.
Performance — Shared Geometry & Material Pools
Old: Every projectile fired created new THREE.SphereGeometry and THREE.MeshBasicMaterial objects. With high fire rates (Gatling, Laser) this generated significant garbage collection pressure.
New:Â Shared geometry and material pools defined once at startup:
_GEO.bullet_sm, _GEO.bullet_lg, _GEO.fire, _GEO.cannonball, _GEO.plasma_ball, _GEO.particle _MAT.fire, _MAT.laser, _MAT.tesla, _MAT.beam
Per-tower-color bullet materials are cached in _bulletMat{} keyed by hex color — getBulletMat(color) returns the cached instance or creates and caches a new one. Two reusable Vector3 instances (_tmpV3a, _tmpV3b) handle hot-path calculations without allocation. This eliminates per-shot GC pressure across the entire projectile system.
Multiplayer — Socket Error Resilience
Old:Â Socket event handlers were bare callbacks. Any exception thrown inside a handler would propagate uncaught and could break the socket connection.
New:Â AÂ safeSocketHandler(eventName, handler)Â wrapper catches all exceptions inside socket callbacks, logs them with the event name, and prevents connection disruption. All socket event registrations now go through this wrapper.
Cloud Save — KarloAuth Integration
Old: Progress saved to localStorage only. No account system, no cross-device sync.
New: KarloAuth is referenced throughout the codebase. saveProgress() calls window.KarloAuth.saveProgress() after every local save with a 5-second debounce — so rapid successive saves (every XP tick, every wave) batch into a single cloud call. If the cloud save fails, the error is caught and shown as an on-screen warning without losing the local save. Player names in multiplayer lobbies auto-populate from KarloAuth.getUsername() if logged in.
What Was Removed
Map Creator / Custom Maps — map-creator-system.js and map-editor-integration.js are no longer loaded. The map editor UI still exists in the HTML but the external creator system scripts are gone.
CrazyGames SDK Integration File — crazygames-sdk-integration.js was a standalone helper that laid out the integration pattern but wasn't fully wired into the reward flow. The new version handles rewarded ads directly through the IMA SDK without this file.
Hardcoded GameJolt Private Key — Removed for security (see above).
Monolithic index.html — The 17,763-line single-file structure is gone. The game no longer lives in one file.
Exponential XP Formula — The Math.pow(1.15, level - 1) curve from index.html is gone. One formula now, everywhere.
Itch.io Download Link on Defeat Screen — The "Lagging? Download Desktop Client" link that appeared on the old defeat screen has been removed.
Summary by Category
CategoryOldNewCodebase structure1 file, 17,763 lines12 files, ~22,400 linesCosmetic systemNone67 skins, 4 rarity tiersScrap economyNoneFull earn/spend/track systemDaily shopNone8-skin global rotation, Deal of the Day, wishlist3D skin previewNoneDraggable mini-renderer in Shop & LockerRewarded adsInstant stub (no real ad)Google IMA SDK, availability-checkedChallenge pool23 flat challenges, string rewards9 templates × 3 tiers, structured rewardsGold challengesMissingAddedPer-run challenge resetMissingresetRunChallenges() on game startChallenge seedDate onlyDate + user tokenDST-aware resetNoYesXP formula conflictTwo competing definitionsOne canonical linear formulaMap world boundariesFlat plane floating in fogFull biome system, 12 unique perimetersProcedural materialsNoneRust texture engine, multi-layer canvasTower skin supportNoneFull common/rare/epic/legendary pipelineMultiplayer skin syncNone_applyRemoteSkin() on remote buildsGeometry poolsPer-shot allocationShared pools, cached bullet materialsSocket error handlingNonesafeSocketHandler wrapperAlert modalsNative browser alert()Custom kAlert() / kConfirm()Cloud savelocalStorage onlyKarloAuth with 5s-debounced syncSecurityPrivate key in HTMLKey removed, backend note addedDefeat / Victory screensBasic text + buttonsScrap breakdown, ad buttons, revive











0 comments