============================================================
 RadioLib - Documentation
 Forge 1.20.1   modid: radiolib   package: net.astraloreo.radiolib
============================================================

A STALKER/Stalcraft-style radiation library: three radiation types with zones and
debuffs, configurable item attributes, anti-rad food, a Curios geiger counter, an
in-game zone editor with overlay, and blowout "emissions" with a custom sky.
It is an engine you drive with commands and KubeJS scripts.

This file is regenerated by the mod on every startup - edits will be overwritten.


1. RADIATION TYPES
------------------------------------------------------------
Three independent types. All three bypass armor: only the resistance attribute
mitigates them.

  rad  - ionizing radiation. Highest peak, medium decay.
  bio  - biological contamination. Low decay (sticky).
  psy  - psychic radiation. Fast decay, mental effects.

Each type has 6 tiers (0-5) of intake per second (RadType.java):
  tier 0 = background: barely above decay, ~4h to a lethal dose unprotected.
           Any small resistance neutralizes it.
  tier 1-4 = normal danger scaling.
  tier 5 = elephant's foot: near-instant death, effectively unsurvivable.

Every second, per player, per type:
  ambient = MAX of the active zones at the player position (0 in a bunker)
  intake  = ambient / (1 + resistance) * intake_mult + emission
  decay   = base_decay(type) * decay_mult
  dose   += intake - decay        (dose is unbounded, resets on death)
  stage   = highest debuff stage whose threshold < (dose - cap)

Dose is stored in the player persistent data and cleared on death.


2. ATTRIBUTES
------------------------------------------------------------
15 attributes (5 per type), assignable to any equipment via the item config.
They are normal Minecraft attributes, so any gear/Curios can carry them.
X is rad / bio / psy.

  X_resistance   (default 0)    divides zone intake. Higher = safer.
  X_cap          (default 0)    added to debuff thresholds. Tolerate more dose.
  X_decay_mult   (default 1.0)  multiplies decay. Higher = recover faster.
  X_intake_mult  (default 1.0)  multiplies radiation TAKEN from zones. >1 = worse.
  X_emission     (default 0)    flat dose PER SECOND regardless of zones.

intake_mult and emission are for negative/contaminated gear that harms the wearer.
emission is NOT mitigated by resistance (a source you carry on your body).

To survive a zone you need resistance about (intake/decay - 1). Example:
rad tier 4 = 70/s intake, decay 2/s -> about 34 total rad_resistance on the suit.


3. ZONES
------------------------------------------------------------
Two files under ./config/radlib/ :
  zones.json            HUMAN file: hand-edited, supports // and /* */ comments,
                        never touched by commands.
  zones_generated.json  MACHINE file: written by the zone commands. Do not hand-edit.

Both are merged on load. Each zone has:
  type       rad / bio / psy, or bunker (safe zone, no tier)
  tier       0-5 (ignored for bunkers)
  mode       area   (box from->to, cheapest)
             radius (sphere around center, capped at 12)
             contact(active only while touching/passing a given block)
  intensity  (optional) raw intake, overrides the tier
  water_only (optional, default false) only applies while the player is in water
  dimension  (optional) restrict to one dimension
  name       required if you want to react to the zone from commands/scripts/events

Ambient per type = MAX across all matching zones. Bunkers never emit; being inside
a bunker blocks ALL zone intake AND all emission damage (full shelter).
Contact detection uses the player hitbox plus the block underfoot, so both plants
(seagrass, grass) and floor blocks (magma) work.


4. DEBUFFS
------------------------------------------------------------
./config/radlib/debuffs.json - per type, ordered stages (low / medium / high / acute),
each with threshold, damage (per second), chance (probability applied each second),
and effects (potion effects). The active stage is the highest whose (threshold + cap)
is exceeded by the dose. Radiation damage bypasses armor.
Default thresholds are Chernobyl-scaled (e.g. rad 150 / 400 / 900 / 1800).


5. ANTI-RAD FOOD
------------------------------------------------------------
./config/radlib/foods.json - generated from consumable items by command.
Per food, per type:
  flush                             dose removed instantly on consume
  decay_boost + decay_boost_seconds temporary bonus to decay
  resistance_grant + resistance_seconds temporary resistance
Everything defaults to 0 (no effect until you edit it).


6. GEIGER COUNTER
------------------------------------------------------------
Create a Curios item in MCreator with registry name geiger_counter.
  Right-click in hand -> prints dose + resistance per type in chat (colored by stage).
  Worn in ANY Curios slot -> loops a geiger sound whose level = the zone tier at your
  position (tier 0 = silent). Level ramps one step at a time up/down; volume and pitch
  scale exponentially with the level. Sounds geiger1..geiger6 are imported in MCreator
  as six separate sound entries.


7. ZONE EDITOR (WAND + OVERLAY)
------------------------------------------------------------
  /radiation tool give - gives the Zone Wand (an NBT-tagged wooden hoe; plain hoes are
     untouched). Left-click a block = pos1, right-click = pos2, shift+right-click in air
     = clear selection.
  The zone commands turn your current selection into a zone.
  Overlay keybind (default ALT+Z, rebindable, category "Radiation Lib"): draws wireframes
     of all zones (rad = yellow-green, bio = green, psy = purple, bunker = blue),
     highlights contact blocks within ~12 blocks, and shows your wand selection in white.
Zones sync server -> client on login and after any create/delete/reload/sync.


8. EMISSIONS (BLOWOUTS)
------------------------------------------------------------
A timed server event with three phases:
  WARMUP (initial seconds) - sky reddens (custom cube skybox from emission.png), clouds
     hide, fog thickens gently, a warning shows above the hotbar; no lethal damage yet.
  PEAK (duration seconds)  - anyone NOT in a bunker takes direct armor-bypassing damage
     and accumulates cumulative outside-exposure; at 15s cumulative exposure they die.
     If duration < 15s, players who stayed out survive. Exposure freezes (not resets)
     in a bunker.
  FADE (~5s) - sky, fog and sounds ease back to normal.
State is in-memory only: a server crash ends the emission. Effects are client-side and
driven by a synced intensity value, so they stay in sync and fade smoothly.

Client visuals:
  Sky    - cube skybox from assets/radiolib/textures/environment/emission.png (a 3x2
           atlas arranged into a T-cross), drawn over the vanilla sky with alpha from
           the emission intensity so it hides the sun/moon. Face mapping/rotation is
           tunable in EmissionSkyRenderer.java.
  Fog    - turns red and thickens (to ~80 blocks).
  Clouds - turned off for the duration, restored afterward.
  Sounds - layered: loops (emission_wind / emission_whoosh / emission_music), random
           one-shots (emission_thunder / emission_rain_thunder / emission_crow /
           emission_scream), and a start/end sting (emission_psy). Imported in MCreator
           as separate entries; volume follows intensity.
  Warning- text above the hotbar: red "Search a bunker and hide" outside, green
           "You're in a Safe Zone!" inside a bunker.


9. COMMANDS
------------------------------------------------------------
All under /radiation, admin-only (permission level 2).

  getconfig items|armors|all|foods [full]  generate the attribute/food config
  getconfig inventory                       dump the stacks in hand (NBT/enchant included)
  reload                                    reload ALL configs and re-sync
  sync                                      re-read zone files from disk, push to all clients
  dose                                      show your current doses
  clear all|rad|bio|psy <targets>           zero dose(s) for players (@a/@p/@s/@e/name)
  tool give                                 give the Zone Wand
  zone create rad|bio|psy <tier> <name>     area radioactive zone from wand selection
  zone create bunker <name>                 area safe zone from wand selection
  zone delete <name>                        remove a generated zone (manual: edit zones.json)
  zone list                                 all zones with [manual]/[generated] origin
  zone info                                 zones at your current position
  emission start <initial> <duration>       start a blowout
  emission stop                             end the emission now
  emission status                           current phase and time left


10. CONFIG FILES  (./config/radlib/)
------------------------------------------------------------
  item_attributes.json    item -> slot -> attribute modifiers (grouped by modid)
  foods.json              anti-rad food effects
  zones.json              hand-edited zones (comments allowed)
  zones_generated.json    command/script-created zones (do not hand-edit)
  debuffs.json            per-type poisoning stages
  wiki.txt                this file (regenerated each startup)
zones.json and debuffs.json self-generate with examples/defaults on first run.


11. KUBEJS API
------------------------------------------------------------
Server scripts only (kubejs/server_scripts/). Reach the facade with:
  const RadLib = Java.loadClass('net.astraloreo.radiolib.api.RadLibAPI')
Type ids are 'rad' / 'bio' / 'psy' (case-insensitive). All methods are null-safe.

Dose:
  getDose(player, type) -> double
  setDose(player, type, value)          overwrite (clamped >= 0)
  addDose(player, type, amount)         add (negative subtracts)
  clearDose(player, type)               zero one type
  clearAllDoses(player)                 zero everything
  getStage(player, type) -> "safe"/"low"/"medium"/"high"/"acute"

Attributes (read-only), all -> double:
  getResistance(player, type)  getCap(player, type)  getDecayMult(player, type)
  getIntakeMult(player, type)  getEmission(player, type)

Zones (query):
  getAmbient(player, type) -> double     intake/s at position (0 in a bunker)
  isInBunker(player) -> boolean
  getZonesAt(player) -> list of names    named zones the player is in
  isInZone(player, name) -> boolean
  listZoneNames() -> list
  zoneExists(name) -> boolean
  getZoneTier(name) -> int               radiation tier, -1 bunker, 0 unknown
  getZoneType(name) -> "rad"/"bio"/"psy"/"bunker"/""
  isZoneBunker(name) -> boolean
  getZoneIntake(name) -> double
  isZoneGenerated(name) -> boolean       command/script vs hand-written

Zones (create/delete, writes generated file + syncs):
  createRadZone(dim, type, tier, name, x1,y1,z1, x2,y2,z2) -> boolean
  createBunker(dim, name, x1,y1,z1, x2,y2,z2) -> boolean
  deleteZone(name) -> boolean            generated zones only

Emissions:
  startEmission(initialSeconds, durationSeconds) -> boolean  (false if one is running)
  stopEmission()
  isEmissionActive() -> boolean
  isEmissionPeak() -> boolean
  getEmissionPhase() -> "IDLE"/"WARMUP"/"PEAK"/"FADE"
  getEmissionSecondsLeft() -> int        seconds left in the current phase

Sync / reload:
  syncZonesFromDisk()   same as /radiation sync
  reloadAll()           same as /radiation reload

Misc:
  getTypes() -> ["rad","bio","psy"]

Events - listen with ForgeEvents.onEvent('<class>', e => { ... }). All server-side.
  net.astraloreo.radiolib.api.EmissionPhaseEvent
     e.getPhaseName(), e.isStarting(), e.isPeak(), e.isEnding()
  net.astraloreo.radiolib.api.RadiationDeathEvent
     e.getPlayer(), e.getTypeId()
  net.astraloreo.radiolib.api.RadiationStageEvent
     e.getPlayer(), e.getTypeId(), e.getStage(), e.getPreviousStage(), e.isWorsening()
  net.astraloreo.radiolib.api.ZoneChangeEvent
     e.getPlayer(), e.getEntered(), e.getExited(), e.getCurrent()

Example - automatic emissions every ~20 minutes:
  const RadLib = Java.loadClass('net.astraloreo.radiolib.api.RadLibAPI')
  let t = 0
  ServerEvents.tick(event => {
    if (++t % (20*60*20) != 0) return
    if (RadLib.isEmissionActive()) return
    if (event.server.playerList.players.isEmpty()) return
    event.server.playerList.players.forEach(p => p.tell(Text.red('An emission is coming.')))
    RadLib.startEmission(30, 45)
  })

Example - zone gating on entry:
  ForgeEvents.onEvent('net.astraloreo.radiolib.api.ZoneChangeEvent', e => {
    const RadLib = Java.loadClass('net.astraloreo.radiolib.api.RadLibAPI')
    let p = e.getPlayer()
    e.getEntered().forEach(zone => {
      if (zone == 'deep_zone' && RadLib.getResistance(p, 'rad') < 60)
        p.tell(Text.red('You are not equipped for the Deep Zone.'))
    })
  })

Example - reward bunker survivors when the emission ends:
  ForgeEvents.onEvent('net.astraloreo.radiolib.api.EmissionPhaseEvent', e => {
    if (!e.isEnding()) return
    const RadLib = Java.loadClass('net.astraloreo.radiolib.api.RadLibAPI')
    Utils.server.playerList.players.forEach(p => {
      if (RadLib.isInBunker(p)) { p.give('minecraft:emerald 3'); p.tell(Text.green('You survived.')) }
    })
  })


12. NOTES
------------------------------------------------------------
  Radiation damage always bypasses armor; only resistance mitigates it.
  Bunkers protect from both emissions and normal zone dose while you are inside.
  Emissions are in-memory: a server crash ends them.
  Client visuals (sky, fog, geiger, overlay, warning) require the client to have the
  mod; the server is authoritative for all damage.
  Sounds are owned by MCreator: import each as a separate entry, never add a manual
  sounds.json or register sounds in code (causes a duplicate-registration crash).
