Skip to content

cosmicrafts/Adventures-Bevy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

210 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Cosmicrafts-Bevy

Bevy-based game project.

Progression pipeline

Player combat stats (max HP/shield, primary weapon damage, pickup power/speed tiers, AbilityModifiers, energy, crit, pickup radii) are written from a single derive pass: cosmicrafts_progression::progression_derive_player_stats, scheduled after pickup collection and before update_shooters (see src/lib.rs).

  • Grant XP or AETH from gameplay with cosmicrafts_core::events::GrantPlayerExperience and GrantPlayerAethereum (Bevy messages). Avoid mutating PlayerExperience or PlayerCurrency directly for rewards.
  • Equipment, skill nodes, wave shop push to cosmicrafts_progression::PlayerModifierStack (push / remove_by_source); dirty triggers the next derive.
  • Mode-specific rules use cosmicrafts_progression::ProgressionProfile (xp_enabled, level_stat_growth). Replace or insert this resource when starting a mode.
  • Crate: crates/cosmicrafts_progression — add ProgressionPipelinePlugin before PickupsPlugin (see root Cargo.toml / src/lib.rs).

Mobile export (iOS TestFlight & Android)

iOS → TestFlight (Xcode)

You need Xcode and a Mac for iOS.

The ios/ folder is set up: it builds cosmicrafts-bevy from this repo and bundles assets from ../assets. You already ran rustup target add aarch64-apple-ios. Do the rest in Xcode:

1. Open the project
Open ios/bevy_mobile_example.xcodeproj in Xcode (double‑click or File → Open). Keep the target name as-is so the build script keeps working.

2. Signing
Select the bevy_mobile_example target → Signing & Capabilities → check Automatically manage signing → choose your Team. Set Bundle Identifier (e.g. com.yourname.cosmicrafts) and remember it for App Store Connect.

3. Device (not simulator)
Plug in your iPhone. In the scheme bar, pick your iPhone as the run destination. iOS simulator is broken for Bevy 0.16+; use a real device only.

4. Build and run
Press ⌘R. First time on device: on the iPhone go to Settings → General → VPN & Device Management and trust your developer certificate.

5. TestFlight

  • In App Store Connect: My Apps+New App (iOS). Use the same Bundle ID as in Xcode.
  • In Xcode: Product → Archive. When it finishes, Distribute AppApp Store ConnectUpload.
  • In App Store Connect → TestFlight tab → add Internal (or External) testers and assign the new build.

Android (e.g. Galaxy S9)

One-time setup: Install Android Studio. In it: File → Settings → Android SDK → SDK Tools → tick NDK (Side by side) → Apply. Then in a terminal run cargo install cargo-ndk (that’s the cargo-ndk tool, not the ndk crate). If the build says "Could not find any NDK", set ANDROID_NDK_HOME to your NDK folder (e.g. C:\Users\You\AppData\Local\Android\Sdk\ndk\27.1.12297018); the batch script will try to find it under the default SDK path if you don’t.

Every time you want to run on the phone:

  1. Run .\build_android.ps1 (PowerShell) or build_android.bat from repo root (or run the cargo ndk ... command yourself).
  2. Open the android folder in Android Studio. Plug in your phone (USB debugging on). Click the green Run button.

That's it. For a release APK: Android Studio → Build → Generate Signed Bundle / APK.


WebGL (WASM) build — serve assets so shield impact works

To run the game in the browser and test shield impact (and whether it affects FPS on WebGL), shaders and textures must be served with the WASM build. RON files are embedded at compile time; shaders (assets/shaders/*.wgsl) and images (e.g. assets/sprites/shield.webp) are loaded at runtime and must be available from the same origin.

Option A: Trunk (recommended)

  1. Install Trunk: cargo install trunk
  2. Add wasm target: rustup target add wasm32-unknown-unknown
  3. From the repo root run:
    • Dev: trunk serve — builds, copies assets/ to dist/, and serves. Open the URL shown (e.g. http://127.0.0.1:8080).
    • Release: trunk build — output in dist/; deploy that folder so the server serves dist/assets/ (and the rest) from the same origin.

index.html at the repo root is set up so Trunk copies the full assets/ directory (including shaders/ and sprites/) into the build output. That lets the shield impact shader and texture load on WebGL.

Option B: Manual serve

If you build WASM another way (e.g. cargo build --target wasm32-unknown-unknown and a custom HTML/JS loader), copy at least assets/shaders/ and assets/sprites/ (or the whole assets/ folder) into the directory you serve so that requests for assets/shaders/shield_impact.wgsl, assets/shaders/vfx_noise.wgsl, and assets/sprites/shield.webp return the files (same path layout as on disk). Then open the game and trigger shield hits to see if the effect runs and how it affects FPS.


Assets and enemy spawn

Single enemy spawn source: All in-world enemies come from assets/stress_test_ranges.ron only. When config.enabled is true, stress_spawn maintains target_enemies (spawns heroes from hero_pool or taxonomy classes, plus optional followers). When enabled is false, no enemies spawn. Enemies can still summon minions via abilities (e.g. spawn_drone); those are descendants of the stress-spawned pool. The old chunk/pack spawner and enemy_packs.ron have been removed.

Asset RONs in use (loaded by code):

Path Purpose
stress_test_ranges.ron Enemy spawn config (count, distance, hero_pool, stats ranges).
settings.ron Game settings, fog, keys, fonts.
unit_taxonomy.ron, unit_models.ron, ai_profiles.ron Units and AI.
companion_settings.ron Companion formation and behavior.
lighting.ron, parallax_settings.ron Lighting and sky.
physics_settings.ron, shield.ron, aura.ron Physics, shield VFX, unit aura.
adjustment_layer.ron Color grading.
world/zones.ron, world/levels.ron Zones and event levels (dialogue/levels; spawn uses only stress_test_ranges).
event_behavior_overrides.ron Loaded but not used for current stress-only spawn.
ui/*.ron Layout, theme, strings, healthbar, playerhud, pickups.
effects/death_explosion.ron Death effect.
abilities/*.ron Ability definitions.
units/**/*.ron Unit definitions (heroes, companions, elite_void, etc.).
world/npc_weights.ron Per-faction weights for sector orbiting NPCs (merchant, scammer, mystic, etc.). Role "patrol" is ignored in code (Vanguards not spawned).
tutorial/*.ron, maps/*.ron Designer map config; each can define an npcs array for mission NPCs (see below).

manifest.ron is auto-generated by build.rs and lists all .ron paths for embedding (WASM) and discovery.

What spawns when you start a game (profile reference)

Everything that is spawned from the moment you leave the menu until you are in play, in order. No logging is added; this is a static reference for profiling and debugging.

1. Startup (once per app boot)
No units or NPCs. Only resources and assets: load_stress_test_ranges, load_companion_settings, load_physics_settings, load_healthbar_config, load_playerhud_config, pickups/popups/minimap/tooltip/inventory config, load_ui_theme, load_item_registry, hero node trees, faction relations, lore registry, thruster settings, bullet/laser/missile/orb/burst assets, projectile pool, camera, load_parallax_settings, effect assets, mission templates, objective waypoint 3D (hidden), etc.

2. OnEnter(SceneLoading)

  • Save/load: teardown_in_game_state, clear_procedural_mission_state, clear_in_game_session_initialized.
  • Then (chained): mission_load_tutorial_if_new_game (sets ActiveMap from Tutorial / Adventure / SafeZone / or none for free play), apply_pending_load_world_seed, apply_intro_dialogue_from_map, spawn_mission_npcs.
  • spawn_mission_npcs (mission/triggers.rs): For each entry in ActiveMap.config.npcs with a unit_id, spawns one full unit via spawn_unit (ScriptedNpc) at npc.position, then inserts MissionNpc, Name, and unit_nameplate_from_def. So: every mission/tutorial/safe_zone NPC from the map RON (e.g. Command Center, Engineering Bay, Armory, Aldrin, etc.) is spawned here.
  • Scene loading UI: init_scene_loading, spawn_scene_loading_ui.

3. SceneLoading Update (several frames)

  • advance_scene_loading, update_scene_loading_label; after N frames, transition to InGame. No extra unit spawns in this loop.

4. OnEnter(InGame)

  • Player: player/spawning.rs spawn_player — one unit from SelectedHero (e.g. player.ron or hero unit id) at map player_start or default; manual ability bar starts empty until item resolution runs.
  • Progression: resolve_abilities::auto_equip_base_items (after spawn_player, all modes when equipment is empty) — equips default starter items, then ResolveAbilitiesRequest fills the hotbar from equipment.
  • HUD: Inventory panel, info panel, interaction prompt roots (hud/mod.rs).
  • Gameplay UI: Joystick, HP/shield/energy rows, ability buttons, FPS text, etc. (gameplay/mod.rs, fps_counter.rs).
  • Environment: environment/mod.rs spawn_background_layers (star layers, nebula tiles; no units).

5. InGame Update (first frames and ongoing)

  • Hero companion: companion/spawning.rs try_spawn_hero_companion — when no companion is alive and respawn timer is done, spawns one companion unit (e.g. Aurora Carrier, Comet) from hero_companion_unit_id(selected_hero) or map companion_override.
  • Stress-test enemies: enemy_spawner/stress.rs stress_spawn — when stress_maintainer_spawn_enabled: free play always; Tutorial/Adventure only if F2 → Stress tab Toggle maintainer in Tutorial/Adventure (DesignerStressMaintainerOverride). Maintains target_enemies from stress_test_ranges.ron: spawns units from hero_pool (e.g. aurora, tempest) or taxonomy, at min_distance..max_distance from player; spawn_per_frame caps how many per frame. Then spawn_stress_followers_system adds follower formation; apply_stress_enemy_shield adds Shield from PendingShield.
  • Ambush waves: handle_spawn_ambush_request — spawns wave units from event/mission requests.
  • Parallax sector decorations: environment/parallax/rendering.rs spawn_sector_decorations — for each new sector marker (player entered range): spawns one station unit per sector (e.g. cosmicons_station, celestials_station from units/structures) and 2–5 orbiting NPCs (from world/npc_weights.ron, e.g. merchant, mechanic, smuggler). So stations and sector NPCs appear as you move into new sectors, not all at game start.
  • Ability summons: abilities/spawn.rs spawn_unit_on_activate — when the player (or an enemy) uses a spawn ability (e.g. spawn_drone, spawn_sunfire_comet), spawns one unit via spawn_unit (Summoned role).
  • Procedural missions: mission/procedural.rs — when a procedural mission is started, a cluster of ProceduralMissionEnemy units is spawned (count from mission def) via spawn_unit (Enemy role).

Summary table

When What spawns (units / entities)
Startup No units; config and assets only.
OnEnter(SceneLoading) All mission NPCs from the active map RON (npcs array with unit_id).
OnEnter(InGame) Player (1), background layers (meshes/tiles, no units).
InGame Update Hero companion (1 when eligible), stress enemies (up to target_enemies, rate-limited by spawn_per_frame), ambush waves (on request), sector stations + orbiting NPCs (per new sector), ability summons (on cast), procedural mission enemies (when mission starts).

So at the very start of a run you get: mission NPCs (if any map is active) + player + hero companion (soon after) + stress enemies (if free play) filling up to target_enemies from stress_test_ranges.ron. Sector stations and NPCs appear only when the player enters new sectors.

Procedural NPC spawning — what exists and how to control it

All non-enemy NPCs are spawned from exactly two pipelines. There is no other procedural NPC spawn.

Source What is spawned Where it’s defined Where it’s run How to control it
1. Sector orbiting NPCs Ships orbiting the faction station in each sector (merchants, mechanics, smugglers, etc.). Get FactionNPC + optional DockingPort and dialogue. Weights: assets/world/npc_weights.ron (per-faction map: role → weight, e.g. "merchant": 25, "patrol": 20). Units: assets/units/npc/{faction}_{role}.ron (e.g. cosmicons_merchant.ron, webes_mystic.ron). crates/cosmicrafts_graphics/src/environment/parallax/rendering.rs: when a sector’s decorations are spawned, it reads LoreRegistry.npc_weights for that faction, builds a weighted role pool, picks 2–5 roles per sector, and for each spawns the unit {faction_lowercase}_{role} from UnitRegistry. Turn off a role everywhere: In npc_weights.ron set that role’s weight to 0 for every faction (or remove the key). Turn off one role in code: In rendering.rs, when building the role pool, skip that role (e.g. "patrol" is already skipped so Vanguard patrols are never spawned). Add a new role: Add weights in npc_weights.ron and add assets/units/npc/{faction}_{role}.ron for each faction that should have it.
2. Mission / designer map NPCs Scripted NPCs for tutorial or campaign: waypoints, dialogue, objective targets, optional convert-to-enemy. Get MissionNpc + full unit or minimal scene. Map RON: Each designer map file (e.g. assets/tutorial/tutorial1.ron, assets/maps/safe_zone.ron) has an npcs array. Each entry: id, display_name, position, optional model, optional unit_id (e.g. "juggernaut", "tempest"). crates/cosmicrafts_world/src/mission/triggers.rs: spawn_mission_npcs runs once when ActiveMap is present and no MissionNpc exists yet. For each npc in active.config.npcs: if unit_id is set, spawns via spawn_unit + MissionNpc; else spawns a minimal entity (Transform, SceneRoot, MissionNpc). Add/remove/list NPCs: Edit the map RON’s npcs array. Which map is active: Set by game flow (e.g. TUTORIAL → load_tutorial1()tutorial/tutorial1.ron; safe zone → load_safe_zone()maps/safe_zone.ron). See crates/cosmicrafts_world/src/mission/mod.rs (load_tutorial1, load_safe_zone) and crates/cosmicrafts_core/src/game_state/mod.rs for when ActiveMap is inserted.

Stations (docking posts) are also spawned in the same sector-decoration pass in rendering.rs: one per sector from a fixed mapping (e.g. cosmicons_station, archs_station). They are not driven by npc_weights.ron; they come from assets/units/structures/*_station.ron.

Models (GLB): Unit and ability RONs reference models/… paths under assets/models/. GLBs not referenced by any unit or ability RON live in assets/models/unused/ (same subfolder structure, e.g. unused/gundam/, unused/omen/) so they can be restored or repurposed without cluttering the active set.

Text rendering: Plain UI labels, menus, and tooltips use Bevy's built-in Text + TextColor. Stylized text (outline, gradient fill) uses crates/bevy_sdf_text: SDF/MSDF atlases (e.g. from msdf-atlas-gen), one quad per glyph, shader outline and four-corner gradient. Damage popups use SDF when an SDF font is available (fonts/Goldman-Bold.json); config in assets/ui/popups.ron can set damage_fill_crit, damage_fill_normal, etc. to solid or gradient. See crates/bevy_sdf_text/README.md for when to use which.

Abilities and pickups (synergy): Energy fuels abilities (cost per cast; regen over time). Energy pickups grant a temporary regen buff so you can sustain ability use. Power increases weapon damage (including from abilities that use the same damage source) and is capped by PowerLevel. Speed increases ship max speed. Drop chance and pickup-type weights are data-driven from ui/pickups.ron (per-tier weights and drop chance by enemy value). Abilities support hold-to-repeat: keep the key or ability button pressed to fire again at a configurable interval (see hold_repeat_interval_secs in ability RONs) until energy or cooldown blocks.

HUD interaction (action registry): In crates/cosmicrafts_ui_hud, UI clicks and touches are wired through a single pattern. For new HUD buttons: define a marker component on the entity → map in a collector system (e.g. in hud/actions.rs) from Interaction/pointer events to HudUiActionRequesthandle in dispatch_hud_actions (one handler per action variant) → style in a visual updater (hover/active/ready). Collectors run before the dispatcher; visuals run after state updates. Hover: collectors write HudHoverState; one dispatch_hover system updates tooltips and hover state (inventory, trading, minimap, standmark, equipment nameplate, skill nodes).

Sector map: manual testing by phase

Run the game, start or continue a run (so you have a world seed and sector), then use these cues to verify each phase.

Phase 1 — Full-screen map and sector borders

  • Open map: InGame → press M or click the Map button next to the minimap (top-right). Overlay should open.
  • Full-screen cue: The map grid uses most of the screen (not a small 520px panel). There is a thin header (“SECTOR MAP (M to close)”) and a Close button; the grid fills the remaining space and scales with window size.
  • Sector borders cue: Every cell has a visible edge (1px border). Current sector has a thicker or accent border. Cells look like a “country map” with clear sector boundaries.
  • Close: M or Escape or Close button hides the overlay.

Phase 2 — Map drawn from world data (biome colors)

  • Open map (M or HUD Map) while in a sector.
  • Biome colors cue: Explored cells are not all the same gray. You see different colors per sector (e.g. dark gray empty, brownish asteroid, purple nebula, reddish pirate, greenish friendly, etc.). Unexplored cells stay pitch black.
  • Current sector: One cell is highlighted (accent color/border) — “You” or current. Lead targets (if any) show a Go (Travel) button.
  • Determinism: Same seed + same sector coord always yield the same cell color; the map matches the procedural world.

Phase 3 — Subdivision (design only)

  • No in-game visuals to test. Verify in docs/RON.md: section “Sector and chunk subdivision (procedural world)” describes chunk key, chunk_seed, and data contract. assets/world/chunk_content.ron exists as a stub. Code: cosmicrafts_world::ChunkKey and chunk_seed(world_seed, key) exist for future procedural env.

Phase 4 — Icons / LOD (future)

  • Deferred. Map biome colors are from Phase 2; LOD/sprites for astronomical zoom are a later milestone.

Quick checklist

Phase Cue
1 Map is full-screen; every cell has a border; current sector stands out.
2 Explored cells show different colors by biome; unexplored = black.
3 Docs + stub RON + ChunkKey / chunk_seed in code.
4 Not implemented; skip.

Tutorial & designer map — follow-up

Designer maps (e.g. tutorial/tutorial1.ron) run a separate pipeline from free play: when ActiveMap is present, free-play enemy spawn (stress_test_ranges.ron) is gated off. Map RONs define player_hero (optional; unit id the player controls, default "aurora"), intro dialogue, player_start, companion_override, NPCs, missions, triggers (MissionComplete, Proximity, Timer, PhaseTimer, WhenChoice, WhenChoiceValue, AllEnemiesDefeated, AllEnemiesDefeatedAfterChoice), and actions (ShowDialogue, SpawnWave, ShowUnitDialogue, AddNpcWaypoints, SetEnemyTarget, ShowChoiceDialogue, ConvertNpcToEnemy). See docs/RON.md and crates/cosmicrafts_world/src/mission/ for schema and code.

Current state

  • Wired: Niri companion unit, map companion_override, blocking dialogue, popup speech bubbles with companion resolution, choice schema (ShowChoiceDialogue, WhenChoice, WhenChoiceValue, AllEnemiesDefeated, AllEnemiesDefeatedAfterChoice), trigger runner, apply_pending_convert_npc_to_enemy (NPC→enemy), apply_choice_made_to_runtime (ChoiceMade→MapRuntime), choice dialogue UI (overlay + buttons, sends ChoiceMade).
  • Content: Full tutorial in tutorial1.ron: Niri (sarcastic barks), report to Aldrin, holdout wave and waypoint follow, Spirat boss at rally with choice (join pirates / destroy pirates), branch (Aldrin converts to enemy if join), final war wave, victory only after all_enemies_defeated_after_choice("spirat_choice") then complete_mission("tutorial_win") and cleanup.

Key files: crates/cosmicrafts_world/src/mission/mod.rs, triggers.rs, cosmicrafts_core::events (CurrentChoiceDialogue, ChoiceMade), cosmicrafts_ui gameplay (choice overlay).


Core Loop Foundation Map

GDD is the canonical design source for the sector-based core loop. This README section is the implementation map: it explains which systems already support that loop, which systems are incomplete, and where future coding should anchor itself.

Documentation split

  • GDD — authoritative game-direction doc: core fantasy, sector episode loop, risk model, reward model, diplomacy role, persistence promise.
  • README.md — repo-level implementation map for current reusable systems, ownership of core loop foundations, and next milestones.
  • docs/RON.md — technical home for future data/schema authoring around sectors, tribes, shrines, clues, and mission-style contracts.

Current reusable foundations

  • Sector/world seed base: crates/cosmicrafts_world/src/generator.rs and world-zone data already support deterministic space, sector coordinates, naming, and discovered-sector tracking.
  • Adventure pacing base: crates/cosmicrafts_world/src/adventure/markov.rs already provides encounter rhythm, escalation, refill behavior, and light narrative pacing. This should remain the pacing layer inside a larger sector episode system.
  • Tribe interaction seed: crates/cosmicrafts_world/src/mission/ already supports dialogue, rewards, triggers, branching choices, NPC targeting, and consequence-style scripting. This is the seed for optional diplomacy and procedural tribe encounters.
  • Progression seed: crates/cosmicrafts_world/src/progression/ plus crates/cosmicrafts_ui_hud/src/hud/inventory_panel.rs and skill_tree_tab.rs already provide items, bag/equipment, modifier stacking, hero nodes, and UI.
  • Pickups/blessing seed: assets/ui/pickups.ron and crates/cosmicrafts_world/src/pickups/ already provide fight-scale boosts. These should eventually ladder upward into sector-scale shrines and blessings.
  • Save/load seed: src/save_load.rs and crates/cosmicrafts_core/src/save_game.rs already persist world seed, discovered zones, player stats, XP, and currency.

Save/load reference: bevy_save

The bevy_save repo (e.g. sibling bevy_save/ or github.com/hankjordan/bevy_save) is a useful reference for patterns; it targets Bevy 0.16, so we do not depend on it directly (this project uses Bevy 0.18). Concepts worth reusing in our own save system:

  • Reflection-based snapshots: Capture/apply full or partial World state (resources + entities + components) via Bevy’s Reflect; we stay with an explicit GameSave struct and manual read/write for now, but the idea of “snapshot → serialize → deserialize → apply” is the same.
  • Platform save dirs: Uses something like platform-dirs for a standard save location per OS; we use a fixed saves/ path and could later align with platform conventions.
  • Migrations: A Migrate trait and versioned snapshots for backward compatibility; we use a single SAVE_VERSION and #[serde(default)] for new fields; if we add more versions later, a small migration layer inspired by bevy_save would help.
  • Pipelines / backends: Pluggable backend (e.g. file vs in-memory) and format (JSON, RON, etc.); we currently have one path (RON to saves/); we could later abstract backend/format if needed.
  • Checkpoints / rollback: In-memory checkpoints for rollback; not required for our current loop but useful to remember for future “rewind” or debug tools.

So: use bevy_save for ideas and patterns, not as a dependency; keep our implementation on the existing GameSave + write_save / read_save contract.

Cloud save (optional): A small HTTP backend in server/ (run with cargo run -p cosmicrafts-server) exposes PUT/GET /save, POST /stats, and POST /achievements. The game can upload saves and stats and download the latest save when Continue is used. Build the game with cargo build --features cloud and set env COSMICRAFTS_CLOUD_URL=http://127.0.0.1:8080 to use the local server; otherwise the game uses a no-op backend and local files only.

Four core loop foundation layers

  1. Sector State The future source of truth for a sector episode: faction control, local tribes, power web, shrines, anomalies, clues, extraction state, and next-sector leads.
  2. Tribe Interaction Mission/dialogue systems extended into optional negotiation, tribute, alliance, betrayal, and declaration-of-hostility flows.
  3. Persistent Progression Inventory, equipment, nodes, faction standing, and extraction outcomes promoted from runtime/session helpers into long-term identity.
  4. Pickups -> Shrines -> Mutations A reward ladder where pickups stay fight-scale, shrines become sector-scale choices, and mutations add run/build-scale procedural identity.

Known blockers and stale risks

  • Adventure is currently pacing, not a full sector loop.
  • World discovery exists, but persistent sector episode state does not.
  • Save/load still does not preserve the full progression backbone needed for long-term play.
  • There is stale or half-wired behavior worth treating as foundation debt:
    • split save paths between root save/load flow and older UI save flow
    • progression teardown still clears resources that should eventually become persistent
    • player.inventory save data is still tied to ability loadout instead of real inventory/equipment persistence
    • old placeholder content and docs can misrepresent the current direction

Recommended implementation order

In place now: Phase 5 (discovered leads visible in pause menu, Travel to lead) and the sector map (M key, biome grid, Travel on leads) are implemented. Extract is an explicit pause-menu action: it runs the same save path as SAVE and shows “Sector progress saved. Travel to a lead when ready.” so the player can leave the sector with progress persisted.

  1. Define the SectorState contract and its persistence boundaries.
  2. Define the persistence contract for progression, extraction, and clues.
  3. Define the data/schema contract for procedural tribes, shrines, and sector content.
  4. Build the actual sector episode loop on top of Adventure pacing, mission interactions, and persistent progression.

Pickup regen audit (post–percent-of-max refactor)

After switching pickup HP/shield/energy regen to % of max per second with ranges and stacking, the following lingering or optional pieces are left for you to decide:

Finding Location Suggestion
Shield instant_heal_percent RegenEffectRon / effects.rs: shield branch uses e.instant_heal_percent for an instant shield heal on collect. Not used in assets/ui/pickups.ron (only health has it). Keep for future tuning or remove from RON/config and the shield branch in effects.rs if you want zero dead branches.
Energy instant_heal_percent RegenEffectConfig has the field for energy too; energy pickups never had instant heal. Purely redundant; only health (and optionally shield) use it. Safe to leave for symmetry or remove from energy in RegenEffectRon / build_effects if you prefer a minimal config.
Save/load and buff components HealthRegenBuff, ShieldRegenBuff, EnergyRegenBuff are now { stacks: Vec<(f32, f32)> }. If save/load ever persisted these (e.g. via Reflect), old saves would deserialize with the wrong shape. Current save flow does not appear to persist these short-lived buffs; if it does, treat this as a breaking save format change and document or version it.
Progression ModifierStat::HealthRegen / ShieldRegen / EnergyRegen progression/types.rs and modifier_stack.rs. These affect permanent passives (HealthRegenPassive, ShieldRegenPassive, reactor energy regen), not pickup buffs. No change needed; they are still correct.

No other dead code was found; the old absolute rate/remaining single-buff logic has been fully replaced by rate_percent and stacks.


Pickups dropped by enemies — assessment for customization

All of the following are in-world orbs spawned when an enemy dies. Config: assets/ui/pickups.ron. Equipment (thrusters, cannons, reactor, etc.) drops are separate and use the item registry + progression item-drop system.

Drop flow: On enemy death, DropPickupRequest { position, enemy_value } is sent. spawn_pickups_from_requests (cosmicrafts_world):

  1. If enemy_value > 0: spawns one Aeth orb with that value (always; no roll).
  2. Rolls one random orb with probability drop_chance(enemy_value) (from drop_chance in pickups.ron: high/mid/low by enemy_value thresholds).
  3. If the roll passes, the type is chosen by weights and player tier (Critical / Damaged / Healthy). A single random in (0,1] is compared to cumulative weights; first type whose weight ≥ roll wins.
Pickup type Dropped? What it does on collect Config (effects in pickups.ron) Customization levers
Aeth Yes (one per kill if enemy has aeth_reward > 0) Adds enemy_value to player Aethereum; no orb type roll. N/A (value from unit def aeth_reward). Unit RON aeth_reward; no pickups.ron effect block.
Health Yes (via weight roll) HoT: adds a regen stack (% of max HP/sec for random 2–5 s). Small instant heal (2–8% of max). Stacks with other Health pickups. health: rate_percent, duration_secs, tier_modifier, instant_heal_percent. Ranges for rate (8–12%), duration (2–5 s), instant (2–8%); tier modifiers; weights per player state.
Shield Yes (via weight roll) HoT: regen stack (% of max shield/sec, 2–5 s). Small instant (2–8% of max) if configured. Stacks. shield: same shape as health. Same levers as Health; weights and tier modifiers.
Energy Yes (via weight roll) HoT only: regen stack (% of max energy/sec, 2–5 s). No instant. Only applies if player has Energy component. Stacks. energy: rate_percent, duration_secs, tier_modifier. Rate (15–25%), duration (2–5 s); weights and tier modifiers.
Power Yes (via weight roll) +1 damage tier (resource PowerLevel). Each tier adds 15% damage; capped at max tier. power: max_tier, multiplier_per_tier, tier_modifier. Max tier (5), multiplier (0.15); weights.
Speed Yes (via weight roll) +1 speed tier (resource SpeedTier). Each tier adds 20% max speed; capped at max. speed: max_tier, multiplier_per_tier, tier_modifier. Max tier (3), multiplier (0.2); weights.
Xp Not dropped as orb (Orb type exists; collection branch skips.) Not in weight table. Would need to be added to weights and drop logic if desired.
Credits Not dropped as orb Same as Xp. Same.

Where to tune:

  • Drop chance: drop_chance (enemy_value_high, enemy_value_mid, chance_high, chance_mid, chance_low). Higher enemy value → higher chance of an extra orb (Aeth is always separate).
  • Which orb type: weights.critical, weights.damaged, weights.healthy. Cumulative weights 0..1; lower weight = chosen earlier (e.g. Health 0.28 → roll ≤0.28 gives Health). Duplicate "Health" at end is fallback so roll always wins.
  • Effect strength: Each effects.* block (health, shield, energy, power, speed). All use (min, max) ranges and optional tier_modifier for player state.

Ability ideas backlog (primitive VFX + current stack)

How new abilities hook in today (short):

  • Data: Add assets/abilities/<id>.ron (cooldown, costs, metadata). Effect payload must match a variant in cosmicrafts_units_data / ability definitions (see existing ChainLightning, Laser, Burst, etc.).
  • Runtime: crates/cosmicrafts_units/src/abilities/ — subscribe to AbilityActivateEvent, read AbilityRegistry, spawn VFX entities, send DamageEvent, optional Knockback, reuse missile::Explosion for flashes.
  • Meshes/materials: bevy::math::primitivesAssets<Mesh> once at Startup; EmissiveMaterialCache + Assets<StandardMaterial> for shared glowing materials (same pattern as chain_lightning.rs).
  • Targeting: GameplaySpatialGrid + Team for nearby enemies (chain lightning already shows cell-radius query).
  • Juice: assets/settings.ronshake_*, hit_stop_*, hurt_flash_*, vfx_enabled / vfx_quality.

Easiest first: #1 Rail burst — Same cylinder + jagged segments as chain lightning, but one straight path (caster → first enemy or aim direction), no bounce loop. Smallest new AbilityEffect variant and one plugin module; fastest way to validate RON → damage → VFX end-to-end.


Original seven (from chain-lightning-style discussion)

# Name Do Systems
1 Rail burst Straight beam built from N jittered cylinder segments along one ray; single target or first hit in range. Copy chain lightning segment spawn; replace grid bounce with one DamageEvent; EmissiveMaterialCache.
2 Expanding ring Flat torus or squashed cylinder at impact; scale XZ over time, despawn. New mesh in ability init_*_assets; Update system scales Transform; damage once or tick in radius.
3 Spiral drill Helix of short cylinders from caster to target. Loop: position = lerp + offset on orthogonal axes by sin/cos along t; same mesh/material as lightning.
4 Double-layer glow Two cylinders per segment (wider dim + narrow bright) or halo sphere + core. Two mat_cache.get_or_insert keys; spawn two children or two entities per segment.
5 Impact core + spikes Sphere pop + 6–12 thin cylinders radiating from hit. Reuse Explosion + radial dirs from Vec3::Y cross products; thin scale on cylinders.
6 Orbital stakes Capsules arranged in a ring, then lerp toward target over ~0.3s. Components with start/end/timer; Update moves Transform.translation; damage on arrival or overlap.
7 Pillar column Stack of vertical cylinder segments at a ground point, staggered despawn timers. Fixed XZ; vary Y; reuse LightningVfx-style shrink or alpha via scale.

Twenty-three more (same stack: primitives + emissive + events)

# Name One-line build note
8 Fan burst N cylinders in a horizontal arc from caster; cone query on grid, one damage per enemy or per ray.
9 Backstab arc Short wide cylinder arc behind target relative to caster facing (flip dir).
10 Ricochet disc Flat cylinder projectile; on hit, reflect dir, spawn second trail; reuse bullet/orb motion patterns.
11 Black hole pull Torus + inward knockback over time in radius; damage tick; optional dark emissive.
12 Nova bloom Nested spheres (3 scales) expanding at different speeds; sphere mesh only.
13 Laser rake Several parallel thin cylinders (offset orthogonally); sweep rotation over 0.2s Update.
14 Mine cluster Spawn small spheres that sit, then pulse scale + radius damage once.
15 Booster ram Capsule stretched along velocity; damage on overlap + self dash (see existing Dash plugin).
16 Orbiting shields 3 toruses orbiting player transform; block or reflect one hit (component + timer).
17 Comet tail Trail of fading cylinders along recent positions (ring buffer on caster).
18 Ground slam Cylinder from sky to ground point; shockwave ring (flat cylinder) + Knockback radial.
19 Sniper needle One long thin cylinder, minimal jitter; high single-target damage.
20 Forked rail Rail burst but 3 parallel rays with slight Y/Z offset (three damage queries).
21 Delayed mark Sphere at target; after delay, cylinder strikes from above (two-phase timer component).
22 Chain shorter Chain lightning with max_bounces: 2 but huge damage — tune RON only.
23 Heal pulse Expanding ring, green emissive, negative damage or heal event if you add a heal message.
24 EMP dome Hemisphere (half-scale trick or many small spheres); silence/debuff if status system wired.
25 Drone line Spawn summoned unit in line (reuse spawn ability) + cylinder tether VFX between caster and drone.
26 Scissor cut Two cylinders crossing at hit point; quick rotation 90° over lifetime.
27 Whirlpool Cylinders arranged in decreasing-radius rings, rotating Y each frame.
28 Meteor drop Sphere + motion from sky; Explosion on land; reuse missile gravity pattern if any.
29 Void tether Cylinder between caster and enemy; damage per second while line intact (distance check).
30 Victory beam Vertical column of stacked capsules; static art; wide radius tick damage.

  • tools/ — See tools/README.md for tool usage (e.g. glb-optimize).

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors