Ninex-HappyPeak icon

HappyPeak

Tired of a plain old climb? Spice up every PEAK run with a bunch of toggleable chaos events — random tornadoes, banana rain, lit dynamite, chests that hatch zombies or summon the Scoutmaster, and more.

By Ninex

CHANGELOG

Changelog

[Unreleased]

  • Default tuning pass for the public release. Events fire much less often than the previous test-mode defaults, loot is tripled instead of doubled, and small counts trimmed for balance.
    • LootMultiplier: 2 → 3 (triple loot)
    • Tornado interval: 10–30s → 90–120s; lifetime 60s → 30s
    • BananaPeel interval: 10–30s → 60–90s; min per player 2 → 1
    • Tumbleweed interval: 10–30s → 60–90s; per-player range 2–5 → 1–3
    • Dynamite interval: 15–30s → 60–90s
    • Eruption interval: 15–30s → 60–90s
    • Scoutmaster chase time: 60s → 30s
  • Fixed EnableRandomDynamite description that still said "lit on spawn by default" — it's actually false (unlit) since 0.12.0.
  • README config tables + tuning recipes updated to reflect the new defaults.

[0.12.0]

Big quality-of-life release. Major redesigns to MarkerSpawn, Dynamite, BananaPeel; new Tumbleweed, ChestTraps, and SafeZones sections; lots of bug fixes.

MarkerSpawn (middle-click pickaxe drop)

  • Now drops a real Mesa pickaxe (鹤嘴锄) instead of a piton. Photon prefab name (0_Items/PickAxeHammered_Shitty) verified against Wesmania/RandomEvents PingGrabber.
  • Reads PointPing.hitNormal directly for accurate surface attachment on walls / overhangs / slopes. Old approach raycast in 5 world directions and often picked up the floor beneath a wall.
  • Caught instantly via a Harmony Postfix on PointPing.Start (no more 200 ms polling that missed rapid pings).
  • Spawned pickaxes don't crack/break. Mesa's preplaced pickaxes still behave normally — we tag our spawns via InstantiationData so PickaxePermanencePatch only affects ours.
  • Up to 2 unclaimed pickaxes per player (hardcoded). New ping past the cap removes the one farthest from the player so the freshly-spawned and held ones are always preserved.
  • Auto-cleanup at 60s hardcoded — no more MarkerSpawnLifetime config.
  • Spawn position offset 0.3 m out from the surface along the normal so the model doesn't z-fight inside the wall.
  • Used Quaternion.LookRotation(-normal, Vector3.up) (matching the game's own HammerClimbingSpike) so the spike pokes properly into the wall.

Dynamite (face-drop)

  • Redesigned from "drop near random player on the ground" → "drop right in front of the player's face from head height."
  • Default LightDynamiteOnSpawn = false — drops an unlit stick the player can pick up and use, instead of bombing them.
  • New configs: DynamiteForwardDistance (default 1 m in front of head), DynamiteDropHeight (default 0 m above head), DynamiteSidewaysJitter (default ±0.5 m).
  • Old DynamiteOffsetMin/Max repurposed as horizontal scatter — defaults changed from 20/100 → 0/5.
  • Item.SetState(ItemState.Ground) called on spawn so the rigidbody actually falls under gravity (PEAK items default to kinematic until the game's own drop logic activates them).
  • Respects campfire safe zone.

Tumbleweed (new section)

  • Tumbleweeds rain from above each player (same pattern as banana rain) using PEAK's native TumbleWeed prefab.
  • Default 15 s lifetime per tumbleweed.
  • Respects campfire safe zone.

BananaPeel (rain)

  • Peels spawn high above each player and fall via gravity instead of materializing at foot level.
  • Each peel is independent (random rotation, no more cumulative trail offset).
  • Respects campfire safe zone.

SafeZones (new section)

  • CampfireSafeRadius (default 30 m) — bubble around every campfire (biome rest + player-lit) where Tornado / Eruption / BananaPeel / Tumbleweed / Dynamite events skip the player.
  • EnableCampfireInvincibility (default on) — patches CharacterAfflictions.AddStatus so any positive status (injury, cold, hot, hunger, poison, …) is blocked while a player stands inside the safe radius. Healing still works.

ChestTraps (new section)

  • Each chest opening rolls per-trap chances:
    • Scoutmaster trap (default 5% chance) — teleports the existing Scoutmaster to the chest and forces him to hunt the opener for ScoutmasterChaseTime seconds. Uses the networked RPCA_SetCurrentTarget RPC so the AI on every client receives the assignment.
    • Mushroom Zombie trap (default 10%) — spawns 1–2 zombies at the chest, sets their wake-up time to 0, locks them onto the opener.

Other events

  • Tornado: Kiln detection now compares against the Segment.TheKiln enum (was a magic int >= 4 that sometimes leaked tornadoes to the summit).
  • Eruption: respects campfire safe zone.
  • All events gated on Plugin.IsInGameRun() — nothing fires in the airport / lobby.

Bug fixes

  • Bushes no longer get randomized items. Removed LootTablePatch (which patched LootData.GetRandomItem(s), hit by every spawner not just chests). Randomization is now handled in SpawnerPatch along with the multiplier; that patch filters by ChestSpawnerTypeNames (Luggage, RespawnChest) so non-chest spawners pass through to vanilla logic.
  • Marker pickaxe no longer destroys items the player is holding. Eviction checks Item.holderCharacter AND walks the GameObject's parent chain to detect "in a Character's hand/inventory" — both signals are checked; either one passing skips destroy. As of 0.12.0 the dominant safeguard is the "evict farthest from pinger" rule (anything held is 0–1 m away vs walls being further).
  • Bombs no longer hover in mid-air. Items spawned via PhotonNetwork.InstantiateItemRoom default to kinematic; we now call Item.SetState(ItemState.Ground) to enable gravity.
  • All networked spawns now use PhotonNetwork.Destroy via the shared Plugin.DelayedNetworkDestroy helper instead of Object.Destroy, so despawns replicate to every client (no more ghost objects on clients).
  • Marker pitons no longer bury themselves inside walls. Switched the rotation calc from Quaternion.FromToRotation(Vector3.up, normal) to Quaternion.LookRotation(-normal, Vector3.up) to match the game's own placement.

Configuration

  • New configs across sections (see README's full reference): DynamiteForwardDistance, DynamiteDropHeight, DynamiteSidewaysJitter, TumbleweedIntervalMin/Max/sPerPlayerMin/Max/Lifetime/DropHeight, BananaPeelDropHeight, CampfireSafeRadius, EnableCampfireInvincibility, EnableScoutmasterTrap, ScoutmasterTrapChance, ScoutmasterChaseTime, EnableZombieTrap, ZombieTrapChance, ZombieCountMin/Max, ZombieLifetime.
  • Removed configs: MarkerSpawnItemName, MarkerSpawnLifetime, MarkerSpawnMaxActive, DynamiteOffsetMin/Max (the old "distance from player" pair).
  • All descriptions are bilingual (English line + Chinese line) so the cfg file is readable in either language.
  • LootMultiplier now rounded to nearest integer at read time (no fractional item counts).

Docs

  • README rewritten for the public Thunderstore page.
  • Recommends installing PEAKModding/ModConfig for in-game live config editing.
  • Adds "Upgrading from an older version" notice — delete HappyPeak.cfg when updating, since BepInEx doesn't backfill new entries into an existing cfg.
  • "Recent changes" section.
  • Renamed mod's tagline + general polish.

[0.11.5]

  • Initial public Thunderstore release.
  • Chest randomization with custom blacklist + loot multiplier.
  • Tornado, BananaPeel (trail), Dynamite (lit), MarkerSpawn (piton), Eruption events.
  • Bilingual config descriptions.