diff options
| author | historia <[not public]> | 2026-06-19 02:51:05 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-06-19 02:51:05 -0400 |
| commit | dea4a06764c507699cf9adcd1fd0a572d227aff0 (patch) | |
| tree | 25769809d34db70cf0bec7d8c6d3422c23780a55 | |
| parent | 2ae4a052fd1c15c3c6ba0f1dd324d896371aaffc (diff) | |
| download | thehouseoficarus-dea4a06764c507699cf9adcd1fd0a572d227aff0.tar.gz | |
feat: scavenge/scrap system started
49 files changed, 538 insertions, 48 deletions
@@ -15,49 +15,7 @@ Detailed implementation plans for each skill/system are in `skill_plans/`. - [x] Step 2: Combat Overhaul — OSRS per-type attack/defense bonuses (stab/slash/crush/science/ranged), OSRS accuracy formula, AttackType on weapons, per-type mob defenses, 8 new mobs, ranged combat with ammo, stats command, showItemStats on look - [x] Step 3: Combat Feel — Aggressive mobs (auto-attack on room enter, OSRS combat level rule), equipment skill requirements on all tiered gear - [x] Step 4: Technology — 25 techs (attack/str/def/ranged/science boosts, 3 protection techs, utility techs), Battery drain, 1-tick flicking, tech command, TechTick, charging station, score/prompt integration -- [x] Step 10: Pharmacy — clean (background action), mix (production), 14 herbs, 16 potions, 14 unfinished potions, 11 reagents, 30 recipes, herb drop tables - ---- - -## Step 1: Pharmacy Rename - -- [x] Rename Alchemy → Pharmacy across the entire codebase. `Alchemy SkillName = "alchemy"` → `Pharmacy SkillName = "pharmacy"` in `player.go`. Update `AllSkills`, `SkillAbbr` (`"alc"` → `"pha"`). Search all Go files and YAML files (help, rooms, etc.) for any reference to "alchemy" and replace with "pharmacy". This is a mechanical find-and-replace — do it now before any new code references the old name. See `skill_plans/pharmacy.md` section 2. - ---- - -## Step 2: Combat Overhaul - -The combat system needs to be upgraded from single AttackBonus/DefenseBonus to OSRS-style per-type bonuses (stab/slash/crush/science/ranged) before building Technology, Science, or Assassin on top of it. See `skill_plans/combat.md` for full details. - -- [x] **2a: ItemStats + Formulas** — Replace the `ItemStats` struct with per-type attack bonuses (stab/slash/crush/science/ranged), per-type defense bonuses, strength bonus, ranged strength, science damage, and technology bonus. Add `AttackType string` field to `ItemDef`. Update `formulas.go` with OSRS accuracy formula (hit chance based on attack/defense roll comparison). Update `MobDef` and `MobInstance` with Science/Ranged levels, per-type defense bonuses, attack bonus, strength bonus, and elemental weakness field. Propagate new mob fields through `SeedMobs`. - -- [x] **2b: Update All Item YAMLs** — Convert every weapon and armor YAML from the old `attack_bonus`/`defense_bonus` format to the new per-type format. Set `attack_type` on every weapon (swords=slash, daggers=stab, maces=crush, axes=slash, bows=ranged). Fix the shortbow/longbow bug where `attack:` should be `ranged_attack:`. See `combat.md` stat tables for exact numbers per tier. - -- [x] **2c: Update Mob YAMLs + New Mobs** — Update the 5 existing mobs (cow, man, guard, newbie_trainer, tanner) with new defense bonus fields. Add 8+ new mobs at various combat levels to give players something to fight: rat, goblin, skeleton, zombie, moss giant, lesser drone, greater drone, iron sentinel. Place them in appropriate rooms. See `combat.md` section 13. - -- [x] **2d: Wire Up Combat** — Update `playerAttack()` to determine attack type from weapon, sum all equipment's matching attack bonus, use mob's matching defense bonus. Update `mobAttack()` to use mob's attack bonus and strength bonus, sum player's matching defense bonus per the mob's attack type. Add a `playerEquipBonuses()` helper that sums all equipped items into a single stats struct. Remove the old single-bonus code paths. - -- [x] **2e: Equipment Stats Display** — When examining an equippable item via `look`, display its attack and defense bonuses in a formatted two-column layout. Add a new `stats` command (Instant) that shows total equipment bonuses summed from all worn items, current attack type, and weapon speed. Update `cmd_score.go` to show combat level calculation breakdown. - -- [x] **2f: Ranged Combat** — Make ranged weapons functional: when `weapon_type` is "ranged", use Ranged level for attack rolls and ranged_attack bonus for accuracy. Consume 1 ammo per attack from the ammo equipment slot. Use `ranged_strength` from ammo for max hit calculation. Award XP to Ranged (75%) + Hitpoints (25%). If ammo runs out mid-combat, switch to unarmed with a message. Require ammo to be equipped to attack with a bow. - ---- - -## Step 3: Combat Feel - -Small additions that make combat feel complete before building bigger systems on top. - -- [x] **Aggressive Mobs** — Mobs with `aggressive: true` initiate combat when a player enters their room. Add an `AggroTick()` or check in room-enter logic. Respect combat level difference (only aggro if mob's combat level is close to or above player's, or always aggro for certain mobs). Configurable via mob YAML. Some of the new mobs from step 2c should be aggressive. - -- [x] **Equipment Skill Requirements** — Add optional `requirements` map to `ItemDef` (e.g., `requirements: { attack: 20, defense: 10 }`). Check in `cmd_wear.go` before equipping. Display requirements when examining items. This prevents low-level players from wearing rune gear immediately. - ---- - -## Step 4: Technology (Prayer System) - -See `skill_plans/technology.md`. Battery = prayer points. Techs = prayers. Players toggle techs for combat bonuses and damage reduction. Battery drains per tick while techs are active. 1-tick flicking works like OSRS — enable and disable within the same tick for no drain. - -- [x] **Technology System** — Add `Battery float64` and `ActiveTechs map[string]bool` to Player. Define ~25 techs in Go (attack/strength/defense/ranged/science boosts at 3 tiers, 3 protection techs, utility techs). Add `tech` command (Instant): `tech <name>` toggles, `tech` toggles quick tech, `tech list` shows all. Add `TechTick()` to drain battery based on active techs, reduced by equipment TechnologyBonus. Implement 1-tick flicking (drain based on tick-start snapshot). Integrate protection techs into `mobAttack()` (40% damage reduction). Integrate stat boost techs into `playerAttack()`. Add "Charging Station" object to recharge battery. Show battery and active techs on score page. +- [x] Step 5: Scavenging — mine_scrap behavior verified. Created 10 junk items (solar, hydro, cosmic, eco, chaos, bio, nature, law, death, blood — all stackable) with matching identifier tools and altar objects. `id`/`identify` command (Active): scans room for altar, checks for matching identifier in inventory, converts all scrap to junk on next tick with level-based multipliers, awards Scavenging XP. 10 altar rooms (150-159) branching from Scavenging Post (room 9). Help files created. --- @@ -65,7 +23,7 @@ See `skill_plans/technology.md`. Battery = prayer points. Techs = prayers. Playe See `skill_plans/scavenging.md`. The simplest new skill — mine scrap (already exists), identify it at altars to produce junk. Must be implemented before Science since Science consumes junk. -- [ ] **Scavenging** — Verify existing mine_scrap behavior and scrap_pile object work. Create 4 base junk items (solarjunk, hydrojunk, ecojunk, biojunk — all stackable). Create 4 identifier tool items and 4 altar objects. Add `id`/`identify` command (Active): checks for correct identifier in inventory, converts all scrap to corresponding junk on next tick, awards Scavenging XP. Higher levels produce more junk per scrap (multiplier tiers). Create rooms for altars (off the existing Scavenging room 9). Add 6 higher-tier junk types (chaosjunk, deathjunk, bloodjunk, lawjunk, cosmicjunk, naturejunk) with corresponding altars and identifiers for Science to use later. +- [x] Step 5: Scavenging — mine_scrap behavior verified. Created 10 junk items (solar, hydro, cosmic, eco, chaos, bio, nature, law, death, blood — all stackable) with matching identifier tools and altar objects. `id`/`identify` command (Active): scans room for altar, checks for matching identifier in inventory, converts all scrap to junk on next tick with level-based multipliers, awards Scavenging XP. 10 altar rooms (150-159) branching from Scavenging Post (room 9). Help files created. --- diff --git a/data/help/id.yaml b/data/help/id.yaml new file mode 100644 index 0000000..6605711 --- /dev/null +++ b/data/help/id.yaml @@ -0,0 +1,26 @@ +name: "id" +category: "Commands" +description: | + Identify scrap metal at an altar to produce junk. + + Usage: id + identify + + Stand at an altar with the matching identifier tool in + your inventory and scrap metal. Type 'id' to convert all + your scrap metal into junk on the next game tick. + + Each altar type requires a specific identifier: + Solar Altar → solar identifier → solarjunk (level 1) + Hydro Altar → hydro identifier → hydrojunk (level 14) + Cosmic Altar → cosmic identifier → cosmicjunk (level 27) + Eco Altar → eco identifier → ecojunk (level 28) + Chaos Altar → chaos identifier → chaosjunk (level 35) + Bio Altar → bio identifier → biojunk (level 44) + Nature Altar → nature identifier → naturejunk (level 44) + Law Altar → law identifier → lawjunk (level 54) + Death Altar → death identifier → deathjunk (level 65) + Blood Altar → blood identifier → bloodjunk (level 77) + + At higher scavenging levels, each scrap produces multiple junk. + See 'help scavenging' for the full multiplier table. diff --git a/data/help/scavenging.yaml b/data/help/scavenging.yaml new file mode 100644 index 0000000..d91c6ed --- /dev/null +++ b/data/help/scavenging.yaml @@ -0,0 +1,39 @@ +name: "scavenging" +category: "Skills" +description: | + Scavenging is the art of reclaiming useful circuitry from + salvaged scrap metal. + + Step 1: Mine scrap metal from scrap piles (requires a pickaxe, + uses the Mining skill). + Step 2: Take scrap metal to an altar with the matching + identifier tool. + Step 3: Type 'id' to convert all scrap metal into junk. + + Junk types and requirements: + Solarjunk — level 1, solar identifier (5 XP/scrap) + Hydrojunk — level 14, hydro identifier (8 XP/scrap) + Cosmicjunk — level 27, cosmic identifier (10 XP/scrap) + Ecojunk — level 28, eco identifier (12 XP/scrap) + Chaosjunk — level 35, chaos identifier (11 XP/scrap) + Biojunk — level 44, bio identifier (16 XP/scrap) + Naturejunk — level 44, nature identifier (16 XP/scrap) + Lawjunk — level 54, law identifier (18 XP/scrap) + Deathjunk — level 65, death identifier (22 XP/scrap) + Bloodjunk — level 77, blood identifier (28 XP/scrap) + + Higher scavenging levels produce more junk per scrap: + Solarjunk: 2x at 22, 3x at 44, 4x at 66, 5x at 88, 6x at 99 + Hydrojunk: 2x at 36, 3x at 66, 4x at 88 + Cosmicjunk: 2x at 56, 3x at 78 + Ecojunk: 2x at 56, 3x at 78 + Chaosjunk: 2x at 66, 3x at 88 + Biojunk: 2x at 78, 3x at 99 + Naturejunk: 2x at 78, 3x at 99 + Lawjunk: 2x at 88 + Deathjunk: 2x at 99 + Bloodjunk: 2x at 99 + + Scrap metal is not stackable — you can carry 28 per trip + (one per inventory slot). Each trip converts all scrap in + one tick. diff --git a/data/items/bio_identifier.yaml b/data/items/bio_identifier.yaml new file mode 100644 index 0000000..1b5a941 --- /dev/null +++ b/data/items/bio_identifier.yaml @@ -0,0 +1,5 @@ +id: bio_identifier +name: bio identifier +color: "196" +description: "A handheld scanner calibrated to isolate bio-frequency signatures in scrap metal. Required to produce biojunk at a bio altar." +value: 5000 diff --git a/data/items/biojunk.yaml b/data/items/biojunk.yaml new file mode 100644 index 0000000..8832a20 --- /dev/null +++ b/data/items/biojunk.yaml @@ -0,0 +1,6 @@ +id: biojunk +name: biojunk +color: "196" +description: "A fragment of reclaimed bio circuitry. Used as a universal energy medium." +value: 50 +stackable: true diff --git a/data/items/blood_identifier.yaml b/data/items/blood_identifier.yaml new file mode 100644 index 0000000..3540179 --- /dev/null +++ b/data/items/blood_identifier.yaml @@ -0,0 +1,5 @@ +id: blood_identifier +name: blood identifier +color: "124" +description: "A handheld scanner calibrated to isolate blood-frequency signatures in scrap metal. Required to produce bloodjunk at a blood altar." +value: 15000 diff --git a/data/items/bloodjunk.yaml b/data/items/bloodjunk.yaml new file mode 100644 index 0000000..b837137 --- /dev/null +++ b/data/items/bloodjunk.yaml @@ -0,0 +1,6 @@ +id: bloodjunk +name: bloodjunk +color: "124" +description: "A fragment of reclaimed blood circuitry. Used as a universal energy medium." +value: 90 +stackable: true diff --git a/data/items/chaos_identifier.yaml b/data/items/chaos_identifier.yaml new file mode 100644 index 0000000..82a7ccf --- /dev/null +++ b/data/items/chaos_identifier.yaml @@ -0,0 +1,5 @@ +id: chaos_identifier +name: chaos identifier +color: "226" +description: "A handheld scanner calibrated to isolate chaos-frequency signatures in scrap metal. Required to produce chaosjunk at a chaos altar." +value: 7500 diff --git a/data/items/chaosjunk.yaml b/data/items/chaosjunk.yaml new file mode 100644 index 0000000..99515df --- /dev/null +++ b/data/items/chaosjunk.yaml @@ -0,0 +1,6 @@ +id: chaosjunk +name: chaosjunk +color: "226" +description: "A fragment of reclaimed chaos circuitry. Used as a universal energy medium." +value: 40 +stackable: true diff --git a/data/items/cosmic_identifier.yaml b/data/items/cosmic_identifier.yaml new file mode 100644 index 0000000..97cb89a --- /dev/null +++ b/data/items/cosmic_identifier.yaml @@ -0,0 +1,5 @@ +id: cosmic_identifier +name: cosmic identifier +color: "201" +description: "A handheld scanner calibrated to isolate cosmic-frequency signatures in scrap metal. Required to produce cosmicjunk at a cosmic altar." +value: 5000 diff --git a/data/items/cosmicjunk.yaml b/data/items/cosmicjunk.yaml new file mode 100644 index 0000000..d9acc21 --- /dev/null +++ b/data/items/cosmicjunk.yaml @@ -0,0 +1,6 @@ +id: cosmicjunk +name: cosmicjunk +color: "201" +description: "A fragment of reclaimed cosmic circuitry. Used as a universal energy medium." +value: 30 +stackable: true diff --git a/data/items/death_identifier.yaml b/data/items/death_identifier.yaml new file mode 100644 index 0000000..778bca5 --- /dev/null +++ b/data/items/death_identifier.yaml @@ -0,0 +1,5 @@ +id: death_identifier +name: death identifier +color: "52" +description: "A handheld scanner calibrated to isolate death-frequency signatures in scrap metal. Required to produce deathjunk at a death altar." +value: 10000 diff --git a/data/items/deathjunk.yaml b/data/items/deathjunk.yaml new file mode 100644 index 0000000..7dcaba8 --- /dev/null +++ b/data/items/deathjunk.yaml @@ -0,0 +1,6 @@ +id: deathjunk +name: deathjunk +color: "52" +description: "A fragment of reclaimed death circuitry. Used as a universal energy medium." +value: 70 +stackable: true diff --git a/data/items/eco_identifier.yaml b/data/items/eco_identifier.yaml new file mode 100644 index 0000000..d0af516 --- /dev/null +++ b/data/items/eco_identifier.yaml @@ -0,0 +1,5 @@ +id: eco_identifier +name: eco identifier +color: "34" +description: "A handheld scanner calibrated to isolate eco-frequency signatures in scrap metal. Required to produce ecojunk at an eco altar." +value: 2500 diff --git a/data/items/ecojunk.yaml b/data/items/ecojunk.yaml new file mode 100644 index 0000000..c050049 --- /dev/null +++ b/data/items/ecojunk.yaml @@ -0,0 +1,6 @@ +id: ecojunk +name: ecojunk +color: "34" +description: "A fragment of reclaimed eco circuitry. Used as a universal energy medium." +value: 30 +stackable: true diff --git a/data/items/hydro_identifier.yaml b/data/items/hydro_identifier.yaml new file mode 100644 index 0000000..3eb7d98 --- /dev/null +++ b/data/items/hydro_identifier.yaml @@ -0,0 +1,5 @@ +id: hydro_identifier +name: hydro identifier +color: "39" +description: "A handheld scanner calibrated to isolate hydro-frequency signatures in scrap metal. Required to produce hydrojunk at a hydro altar." +value: 1000 diff --git a/data/items/hydrojunk.yaml b/data/items/hydrojunk.yaml new file mode 100644 index 0000000..bfcd64a --- /dev/null +++ b/data/items/hydrojunk.yaml @@ -0,0 +1,6 @@ +id: hydrojunk +name: hydrojunk +color: "39" +description: "A fragment of reclaimed hydro circuitry. Used as a universal energy medium." +value: 18 +stackable: true diff --git a/data/items/law_identifier.yaml b/data/items/law_identifier.yaml new file mode 100644 index 0000000..25700e1 --- /dev/null +++ b/data/items/law_identifier.yaml @@ -0,0 +1,5 @@ +id: law_identifier +name: law identifier +color: "27" +description: "A handheld scanner calibrated to isolate law-frequency signatures in scrap metal. Required to produce lawjunk at a law altar." +value: 10000 diff --git a/data/items/lawjunk.yaml b/data/items/lawjunk.yaml new file mode 100644 index 0000000..b46bf9e --- /dev/null +++ b/data/items/lawjunk.yaml @@ -0,0 +1,6 @@ +id: lawjunk +name: lawjunk +color: "27" +description: "A fragment of reclaimed law circuitry. Used as a universal energy medium." +value: 60 +stackable: true diff --git a/data/items/nature_identifier.yaml b/data/items/nature_identifier.yaml new file mode 100644 index 0000000..dc441cf --- /dev/null +++ b/data/items/nature_identifier.yaml @@ -0,0 +1,5 @@ +id: nature_identifier +name: nature identifier +color: "46" +description: "A handheld scanner calibrated to isolate nature-frequency signatures in scrap metal. Required to produce naturejunk at a nature altar." +value: 10000 diff --git a/data/items/naturejunk.yaml b/data/items/naturejunk.yaml new file mode 100644 index 0000000..49ed1ff --- /dev/null +++ b/data/items/naturejunk.yaml @@ -0,0 +1,6 @@ +id: naturejunk +name: naturejunk +color: "46" +description: "A fragment of reclaimed nature circuitry. Used as a universal energy medium." +value: 50 +stackable: true diff --git a/data/items/solar_identifier.yaml b/data/items/solar_identifier.yaml new file mode 100644 index 0000000..663bd9f --- /dev/null +++ b/data/items/solar_identifier.yaml @@ -0,0 +1,5 @@ +id: solar_identifier +name: solar identifier +color: "220" +description: "A handheld scanner calibrated to isolate solar-frequency signatures in scrap metal. Required to produce solarjunk at a solar altar." +value: 500 diff --git a/data/items/solarjunk.yaml b/data/items/solarjunk.yaml new file mode 100644 index 0000000..ab4d5d5 --- /dev/null +++ b/data/items/solarjunk.yaml @@ -0,0 +1,6 @@ +id: solarjunk +name: solarjunk +color: "220" +description: "A fragment of reclaimed solar circuitry. Used as a universal energy medium." +value: 10 +stackable: true diff --git a/data/objects/bio_altar.yaml b/data/objects/bio_altar.yaml new file mode 100644 index 0000000..d60d71f --- /dev/null +++ b/data/objects/bio_altar.yaml @@ -0,0 +1,4 @@ +id: bio_altar +name: bio altar +color: "196" +description: "A sinister altar of red biological interfaces. Place scrap metal here with a bio identifier to produce biojunk. Type 'id' to begin." diff --git a/data/objects/blood_altar.yaml b/data/objects/blood_altar.yaml new file mode 100644 index 0000000..1e562fb --- /dev/null +++ b/data/objects/blood_altar.yaml @@ -0,0 +1,4 @@ +id: blood_altar +name: blood altar +color: "124" +description: "A pulsing altar of {124 bold}crimson crystal{/}, warm to the touch. Place scrap metal here with a blood identifier to produce bloodjunk. Type 'id' to begin." diff --git a/data/objects/chaos_altar.yaml b/data/objects/chaos_altar.yaml new file mode 100644 index 0000000..afe7d6e --- /dev/null +++ b/data/objects/chaos_altar.yaml @@ -0,0 +1,4 @@ +id: chaos_altar +name: chaos altar +color: "226" +description: "A crackling altar of {226 bold}chaotic energy{/}. Place scrap metal here with a chaos identifier to produce chaosjunk. Type 'id' to begin." diff --git a/data/objects/cosmic_altar.yaml b/data/objects/cosmic_altar.yaml new file mode 100644 index 0000000..9ada401 --- /dev/null +++ b/data/objects/cosmic_altar.yaml @@ -0,0 +1,4 @@ +id: cosmic_altar +name: cosmic altar +color: "201" +description: "A floating altar of {201 bold}shimmering pink crystal{/}, surrounded by pinpricks of light like distant stars. Place scrap metal here with a cosmic identifier to produce cosmicjunk. Type 'id' to begin." diff --git a/data/objects/death_altar.yaml b/data/objects/death_altar.yaml new file mode 100644 index 0000000..4323246 --- /dev/null +++ b/data/objects/death_altar.yaml @@ -0,0 +1,4 @@ +id: death_altar +name: death altar +color: "52" +description: "A silent altar of {52 bold}dark obsidian{/}, cold to the touch. Place scrap metal here with a death identifier to produce deathjunk. Type 'id' to begin." diff --git a/data/objects/eco_altar.yaml b/data/objects/eco_altar.yaml new file mode 100644 index 0000000..d955df0 --- /dev/null +++ b/data/objects/eco_altar.yaml @@ -0,0 +1,4 @@ +id: eco_altar +name: eco altar +color: "34" +description: "A thrumming altar of green organic circuits. Place scrap metal here with an eco identifier to produce ecojunk. Type 'id' to begin." diff --git a/data/objects/hydro_altar.yaml b/data/objects/hydro_altar.yaml new file mode 100644 index 0000000..c56a903 --- /dev/null +++ b/data/objects/hydro_altar.yaml @@ -0,0 +1,4 @@ +id: hydro_altar +name: hydro altar +color: "39" +description: "A pulsing altar of blue crystalline conduits. Place scrap metal here with a hydro identifier to produce hydrojunk. Type 'id' to begin." diff --git a/data/objects/law_altar.yaml b/data/objects/law_altar.yaml new file mode 100644 index 0000000..62407c8 --- /dev/null +++ b/data/objects/law_altar.yaml @@ -0,0 +1,4 @@ +id: law_altar +name: law altar +color: "27" +description: "An imposing altar of {27 bold}pristine blue stone{/}, inscribed with orderly geometric patterns. Place scrap metal here with a law identifier to produce lawjunk. Type 'id' to begin." diff --git a/data/objects/nature_altar.yaml b/data/objects/nature_altar.yaml new file mode 100644 index 0000000..3104c62 --- /dev/null +++ b/data/objects/nature_altar.yaml @@ -0,0 +1,4 @@ +id: nature_altar +name: nature altar +color: "46" +description: "A verdant altar of {46 bold}living green stone{/}, covered in moss and tiny flowers. Place scrap metal here with a nature identifier to produce naturejunk. Type 'id' to begin." diff --git a/data/objects/solar_altar.yaml b/data/objects/solar_altar.yaml new file mode 100644 index 0000000..e37b749 --- /dev/null +++ b/data/objects/solar_altar.yaml @@ -0,0 +1,4 @@ +id: solar_altar +name: solar altar +color: "220" +description: "A humming altar of golden circuitry. Place scrap metal here with a solar identifier to produce solarjunk. Type 'id' to begin." diff --git a/data/rooms/150.yaml b/data/rooms/150.yaml new file mode 100644 index 0000000..ba13c81 --- /dev/null +++ b/data/rooms/150.yaml @@ -0,0 +1,8 @@ +id: 150 +name: "Solar Altar Chamber" +description: "A circular chamber bathed in warm {220}golden light{/}. At its center stands a humming {220 bold}solar altar{/}, its surface etched with fractal circuit patterns that glow softly." +exits: + south: 9 + east: 156 +objects: + - id: solar_altar diff --git a/data/rooms/151.yaml b/data/rooms/151.yaml new file mode 100644 index 0000000..8d79273 --- /dev/null +++ b/data/rooms/151.yaml @@ -0,0 +1,8 @@ +id: 151 +name: "Hydro Altar Chamber" +description: "Condensation drips from the ceiling of this cool, blue-lit chamber. A {39 bold}hydro altar{/} dominates the room, its crystalline surface rippling with patterns like flowing water." +exits: + north: 9 + east: 157 +objects: + - id: hydro_altar diff --git a/data/rooms/152.yaml b/data/rooms/152.yaml new file mode 100644 index 0000000..26523a4 --- /dev/null +++ b/data/rooms/152.yaml @@ -0,0 +1,8 @@ +id: 152 +name: "Eco Altar Chamber" +description: "Bioluminescent moss covers the walls of this overgrown chamber. An {34 bold}eco altar{/} rises from the floor, entwined with living circuitry that pulses with green light." +exits: + southwest: 9 + north: 158 +objects: + - id: eco_altar diff --git a/data/rooms/153.yaml b/data/rooms/153.yaml new file mode 100644 index 0000000..36ef05c --- /dev/null +++ b/data/rooms/153.yaml @@ -0,0 +1,8 @@ +id: 153 +name: "Bio Altar Chamber" +description: "The air here is thick and warm. A {196 bold}bio altar{/} throbs at the center of the room, its surface covered in red organic membranes threaded with copper wire." +exits: + northwest: 9 + north: 159 +objects: + - id: bio_altar diff --git a/data/rooms/154.yaml b/data/rooms/154.yaml new file mode 100644 index 0000000..b86be53 --- /dev/null +++ b/data/rooms/154.yaml @@ -0,0 +1,7 @@ +id: 154 +name: "Chaos Altar Chamber" +description: "The air crackles with {226 bold}unstable energy{/} in this chamber. A {226 bold}chaos altar{/} of twisting metal and sparking wires stands at the center, humming with discordant frequencies." +exits: + southeast: 9 +objects: + - id: chaos_altar diff --git a/data/rooms/155.yaml b/data/rooms/155.yaml new file mode 100644 index 0000000..c333836 --- /dev/null +++ b/data/rooms/155.yaml @@ -0,0 +1,7 @@ +id: 155 +name: "Death Altar Chamber" +description: "Shadows pool in the corners of this cold, silent chamber. A {52 bold}death altar{/} of polished obsidian dominates the room, absorbing all light that touches it." +exits: + northeast: 9 +objects: + - id: death_altar diff --git a/data/rooms/156.yaml b/data/rooms/156.yaml new file mode 100644 index 0000000..d77f1e5 --- /dev/null +++ b/data/rooms/156.yaml @@ -0,0 +1,7 @@ +id: 156 +name: "Blood Altar Chamber" +description: "The walls of this chamber are veined with dark crimson lines that pulse rhythmically. A {124 bold}blood altar{/} of deep red crystal stands at the center, radiating gentle warmth." +exits: + west: 150 +objects: + - id: blood_altar diff --git a/data/rooms/157.yaml b/data/rooms/157.yaml new file mode 100644 index 0000000..40f6b5b --- /dev/null +++ b/data/rooms/157.yaml @@ -0,0 +1,7 @@ +id: 157 +name: "Law Altar Chamber" +description: "Orderly lines of blue light trace geometric patterns across every surface of this pristine chamber. A {27 bold}law altar{/} of perfect blue stone rises from the floor, its surface engraved with precise mathematical formulas." +exits: + west: 151 +objects: + - id: law_altar diff --git a/data/rooms/158.yaml b/data/rooms/158.yaml new file mode 100644 index 0000000..ec0f760 --- /dev/null +++ b/data/rooms/158.yaml @@ -0,0 +1,7 @@ +id: 158 +name: "Cosmic Altar Chamber" +description: "Darkness envelops this chamber save for thousands of {201}twinkling lights{/} that float like stars. A {201 bold}cosmic altar{/} of translucent pink crystal hovers above the floor, surrounded by orbiting motes of light." +exits: + south: 152 +objects: + - id: cosmic_altar diff --git a/data/rooms/159.yaml b/data/rooms/159.yaml new file mode 100644 index 0000000..ac65867 --- /dev/null +++ b/data/rooms/159.yaml @@ -0,0 +1,7 @@ +id: 159 +name: "Nature Altar Chamber" +description: "Vines and flowering moss carpet every surface of this verdant chamber. A {46 bold}nature altar{/} of living green stone rises from the floor, entwined with blooming plants that turn toward you as you enter." +exits: + south: 153 +objects: + - id: nature_altar diff --git a/data/rooms/9.yaml b/data/rooms/9.yaml index aca7ec2..da72432 100644 --- a/data/rooms/9.yaml +++ b/data/rooms/9.yaml @@ -1,6 +1,16 @@ id: 9 name: "Scavenging Post" -description: "A cluttered yard full of scrap metal and discarded technology. This area is not yet accessible." +description: "A cluttered yard full of {243}scrap metal{/} and discarded technology. Piles of salvageable debris are scattered across the ground. The air smells of ozone and rust." exits: east: 10 west: 8 + north: 150 + south: 151 + northeast: 152 + southeast: 153 + northwest: 154 + southwest: 155 +objects: + - id: scrap_pile + - id: scrap_pile + - id: scrap_pile diff --git a/internal/game/action.go b/internal/game/action.go index 641f4dd..2d30010 100644 --- a/internal/game/action.go +++ b/internal/game/action.go @@ -233,6 +233,8 @@ func (g *Game) AdvanceActions() { g.advanceStoke(sess, p) case "search": g.advanceSearch(sess, p) + case "identify": + g.advanceIdentify(sess, p) default: if productionActionTypes[p.Action.Type] { g.advanceProduction(sess, p) diff --git a/internal/game/action_identify.go b/internal/game/action_identify.go new file mode 100644 index 0000000..3f63e62 --- /dev/null +++ b/internal/game/action_identify.go @@ -0,0 +1,80 @@ +package game + +import ( + "fmt" + + "thehouseoficarus/internal/net" + "thehouseoficarus/internal/player" +) + +func (g *Game) advanceIdentify(sess *net.Session, p *player.Player) { + junkID := p.Action.Data["junk_id"].(string) + xpPer := p.Action.Data["xp_per"].(int) + + scrapCount := p.CountItem("scrap_metal") + if scrapCount == 0 { + sess.WriteLine("You don't have any scrap metal.") + g.CancelAction(p) + return + } + + scavLevel := p.Level(player.Scavenging) + multiplier := junkMultiplier(junkID, scavLevel) + totalJunk := scrapCount * multiplier + + hasExistingStack := false + for i := 0; i < 28; i++ { + slot := p.InvSlot(i) + if slot != nil && slot.ItemID == junkID { + hasExistingStack = true + break + } + } + if !hasExistingStack && p.FirstFreeSlot() == -1 { + sess.WriteLine("Your inventory is too full!") + g.CancelAction(p) + return + } + + for i := 0; i < 28; i++ { + slot := p.InvSlot(i) + if slot != nil && slot.ItemID == "scrap_metal" { + p.SetInvSlot(i, nil) + } + } + + placed := false + for i := 0; i < 28; i++ { + slot := p.InvSlot(i) + if slot != nil && slot.ItemID == junkID { + slot.Quantity += totalJunk + placed = true + break + } + } + if !placed { + freeSlot := p.FirstFreeSlot() + p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: junkID, Quantity: totalJunk}) + } + + totalXP := scrapCount * xpPer + junkName := junkID + if def, err := g.ItemStore.Load(junkID); err == nil { + junkName = def.Name + } + + msg := fmt.Sprintf("The altar hums. You identify %d scrap metal into %d %s.", scrapCount, totalJunk, junkName) + + if newLevel := p.AddSkillXP(player.Scavenging, totalXP); newLevel > 0 { + sess.WriteLine(g.colorize(sess, "level_up", + fmt.Sprintf("*** You are now level %d scavenging! ***", newLevel))) + } + + if p.OptionBool("xp_drops") && totalXP > 0 { + msg += g.colorize(sess, "xp", fmt.Sprintf(" (+%dxp scv)", totalXP)) + } + sess.WriteLine(msg) + + g.AccountStore.SaveCharacter(p) + g.CancelAction(p) +} diff --git a/internal/game/action_state.go b/internal/game/action_state.go index 1935703..0dc3d32 100644 --- a/internal/game/action_state.go +++ b/internal/game/action_state.go @@ -22,8 +22,9 @@ const ( ActionProducing ActionType = "producing" ActionFletching ActionType = "fletching" ActionEating ActionType = "eating" - ActionCleaning ActionType = "cleaning" - ActionMixing ActionType = "mixing" + ActionCleaning ActionType = "cleaning" + ActionMixing ActionType = "mixing" + ActionIdentifying ActionType = "identifying" ) type ActionState struct { @@ -79,6 +80,8 @@ func (a *ActionState) Description() string { return "cleaning herbs" case ActionMixing: return "mixing " + a.TargetName + case ActionIdentifying: + return "identifying scrap at " + a.TargetName } return "" } diff --git a/internal/game/cmd_id.go b/internal/game/cmd_id.go new file mode 100644 index 0000000..5ea146d --- /dev/null +++ b/internal/game/cmd_id.go @@ -0,0 +1,144 @@ +package game + +import ( + "fmt" + + "thehouseoficarus/internal/action" + "thehouseoficarus/internal/net" + "thehouseoficarus/internal/player" +) + +type altarConfig struct { + AltarID string + IdentifierID string + JunkID string + LevelReq int + XPPer int +} + +var altarConfigs = []altarConfig{ + {"solar_altar", "solar_identifier", "solarjunk", 1, 5}, + {"hydro_altar", "hydro_identifier", "hydrojunk", 14, 8}, + {"cosmic_altar", "cosmic_identifier", "cosmicjunk", 27, 10}, + {"eco_altar", "eco_identifier", "ecojunk", 28, 12}, + {"chaos_altar", "chaos_identifier", "chaosjunk", 35, 11}, + {"bio_altar", "bio_identifier", "biojunk", 44, 16}, + {"nature_altar", "nature_identifier", "naturejunk", 44, 16}, + {"law_altar", "law_identifier", "lawjunk", 54, 18}, + {"death_altar", "death_identifier", "deathjunk", 65, 22}, + {"blood_altar", "blood_identifier", "bloodjunk", 77, 28}, +} + +type junkMultiplierEntry struct { + Level int + Multiplier int +} + +var junkMultipliers = map[string][]junkMultiplierEntry{ + "solarjunk": { + {1, 1}, {22, 2}, {44, 3}, {66, 4}, {88, 5}, {99, 6}, + }, + "hydrojunk": { + {14, 1}, {36, 2}, {66, 3}, {88, 4}, + }, + "cosmicjunk": { + {27, 1}, {56, 2}, {78, 3}, + }, + "ecojunk": { + {28, 1}, {56, 2}, {78, 3}, + }, + "chaosjunk": { + {35, 1}, {66, 2}, {88, 3}, + }, + "biojunk": { + {44, 1}, {78, 2}, {99, 3}, + }, + "naturejunk": { + {44, 1}, {78, 2}, {99, 3}, + }, + "lawjunk": { + {54, 1}, {88, 2}, + }, + "deathjunk": { + {65, 1}, {99, 2}, + }, + "bloodjunk": { + {77, 1}, {99, 2}, + }, +} + +func junkMultiplier(junkID string, level int) int { + entries, ok := junkMultipliers[junkID] + if !ok { + return 1 + } + mult := 1 + for _, e := range entries { + if level >= e.Level { + mult = e.Multiplier + } + } + return mult +} + +func (g *Game) doIdentify(sess *net.Session, input string) { + p := sess.Player.(*player.Player) + g.CancelAction(p) + + var found altarConfig + foundAny := false + for _, ac := range altarConfigs { + if defID, _ := g.findStation(p.RoomID, []string{ac.AltarID}); defID != "" { + found = ac + foundAny = true + break + } + } + if !foundAny { + sess.WriteLine("There is no altar here.") + return + } + + identifierName := found.IdentifierID + if def, err := g.ItemStore.Load(found.IdentifierID); err == nil { + identifierName = def.Name + } + if !p.HasItem(found.IdentifierID) { + sess.WriteLine(fmt.Sprintf("You need a %s to use this altar.", identifierName)) + return + } + + scrapCount := p.CountItem("scrap_metal") + if scrapCount == 0 { + sess.WriteLine("You don't have any scrap metal.") + return + } + + scavLevel := p.Level(player.Scavenging) + if scavLevel < found.LevelReq { + junkName := found.JunkID + if def, err := g.ItemStore.Load(found.JunkID); err == nil { + junkName = def.Name + } + sess.WriteLine(fmt.Sprintf("You need level %d scavenging to identify %s.", found.LevelReq, junkName)) + return + } + + altarName := found.AltarID + if def, err := g.ObjectStore.Load(found.AltarID); err == nil { + altarName = def.Name + } + + p.Action = &action.Action{ + Type: "identify", + TargetID: found.AltarID, + TargetName: altarName, + WaitLeft: 1, + Data: map[string]any{ + "junk_id": found.JunkID, + "xp_per": found.XPPer, + "level_req": found.LevelReq, + }, + } + p.ActionState = &ActionState{Type: ActionIdentifying, TargetName: altarName} +} diff --git a/internal/game/game.go b/internal/game/game.go index 15236f4..dff78d5 100644 --- a/internal/game/game.go +++ b/internal/game/game.go @@ -149,7 +149,8 @@ func classifyCommand(cmd string) CommandClass { "attack", "kill", "north", "n", "south", "s", "east", "e", "west", "w", "up", "u", "down", "d", - "quit", "use", "burn", "stoke", "search", "walk", "cook", "smelt", "smith", "craft", "mix": + "quit", "use", "burn", "stoke", "search", "walk", "cook", "smelt", "smith", "craft", "mix", + "id", "identify": return ClassActive case "eat", "fletch", "clean": return ClassFree @@ -397,6 +398,9 @@ func (g *Game) executeCommand(sess *net.Session, cmd string, args []string, rawI case "mix": g.doMix(sess, strings.Join(args, " ")) return + case "id", "identify": + g.doIdentify(sess, strings.Join(args, " ")) + return case "talk", "speak", "ask": g.CancelAction(p) if len(args) == 0 { |
