feat(fishing): eleven methods over 66 spots, on the shared skilling clock #120

Merged
sickday merged 2 commits from feat/fishing into main 2026-08-05 20:08:01 +00:00
Owner

Phase 2's fourth gathering skill. Eleven methods over 66 spots, nine tools, six
baits, the Angler's outfit, the Fishing Guild and barbarian fishing.

Full suite 4507 passed, zero failures (seed 1, fresh test database). Format,
compile --warnings-as-errors, Credo and Dialyzer all clean. The world boots.

The three findings that outlive the branch

The roll period belongs to the METHOD. Third arrangement of one field and
the one that settles it. A small fishing net rolls every 6 ticks for shrimp and
every 2 for minnow — same item id, same tool row — which kills "the tool
owns it"; a harpoon rolls every 6 bronze or dragon, which kills "the skill owns
it". So ticks lives on the method and World.Fishing.tools_among/2 stamps it
onto the tool at lookup. Contract.Skilling.best/2 needed no change: tools
sharing a method share a period, so {factor, -period} falls through to factor.

Cascade is a real mechanic and the wiki's own chart proves it. Raw shrimps
carry high: 256 — a certainty at 99 — and the published figure is 49.61%.
The missing half is anchovies, rolled first at (1 + 128) / 256 = 50.39%, and
1 - 0.5039 = 0.4961 exactly. Rolling independently would be wrong by a factor
of two at the top of the curve and look perfectly right at the bottom, since
anchovies are not eligible until 15. Pinned by walking all 256 dice faces:
129 anchovies, 127 shrimp, none empty.

Contract.Skilling.interpolate/3 truncates where the published formula
rounds
— 902 of 2,178 mining combinations. Contract.Fishing carries its own
rounded interpolation over raw wiki parameters and reproduces every published
fishing figure checked against it. Woodcutting and mining are deliberately not
moved; that is #117, and the question to answer first is which rounding
mining's own charts were generated with.

Two corrections to what was written down

622 and 623 are the two halves of one animation, not two candidates for it.
623 is the pole held in the water (2 frames / 32 cycles), 622 the initial swing
(19 / 238). Three independently maintained symbol tables agree on 623 and the
cache's own frame shapes confirm it. The barbarian rod was on 622 with no
source and is now on 623 with three.

A fishing spot stands ON the water and is worked from the bank. Measured:
194 of the dump's own 197 are blocked, and the derivation's own validator — the
barbarian-rod tiles at 2500, 3504..3513 — is blocked too. The prose said the
opposite in three places; the derivation was right and only the sentence was
wrong, so "fixing" it would have moved 28 correct rows onto the shore. The test
now asserts reachability, not walkability — 30 of 30 against the dump's
196 of 197.

Tick manipulation

Fishing is the first of the three skills the skilling clock was waiting for
(Herblore, Cooking, Fishing), and it inherited the mechanic with no engine
change
by being ordinary. Measured by driving the real loop a tick at a time:

unmanipulated (a five-tick lure)     rolls on 4, 9, 14, 19       cycle 5
delay item claimed at clock -1       rolls on 4, 7, 10, 13, 16   cycle 3
delay item claimed at clock  0       rolls on 4, 6, 8, 10, 12    cycle 2

All three are tests. What it exposed is that the delay items are thinner than
the real game's
: Production.start/4 is the only :inventory arm and is
reached only when a recipe exists, so knife-and-teak — canonical precisely
because it makes nothing and never fills the pack — does nothing here at all.
Behavioural rather than structural, and it belongs to Production rather than
to fishing.

Fly fishing

Every one of this cache's 17 Lure/Bait definitions had zero spawns, so
trout, salmon, pike and rainbow fish were absent from the world entirely and the
skill had a hole from 20 to 58. Thirty rows across five areas fill it, derived
from the collision map rather than typed. The ids are ours and the assignment is
arbitrary because all 17 definitions are identical — which a test now asserts,
so it stays arbitrary. The durable fix for the whole class is #118:
Cache.MapSquare throws the overlay id away and water is an overlay.

Also in this branch

  • A bait? gate in Contract.Skilling's chain beside tool, because a rod
    with no bait and no rod at all are the same class of problem — in the
    contract so fishing cannot grow a second, differently ordered copy of the
    gate order.
  • The branch would not boot: a stray comma in the appended spawn rows made
    npc_spawns.exs a syntax error. A green suite missed it because mix test
    was reading a stale _build/test copy of the priv file.
  • yield/3 claimed to stop at the first fish that will not fit and did not, so
    a big net into a nearly-full pack said "You can't carry any more fish."
    three times. Now a reduce_while, with a test on the message count.

Filed rather than folded in

  • #117 — the interpolation rounding, above.
  • #118Cache.MapSquare discards the overlay id, so nothing can ask
    whether a tile is water.
  • #119World.Content.LightTest is seed-flaky, and it is not this
    branch's. mix test --seed 12 on that file alone fails, as do 15 and 20.
    Light.run/2 rolls its own dice, ExUnit seeds :rand from the run seed, and
    the test needs a roll that fails only 191 times in 256. Adding any file
    reshuffles the order and re-rolls the lottery, which is why it looked like
    this branch's.

Not done

The live sitting, narrowed to five things: whether the rod's initial swing
is worth playing before the held pose; that the five fly-spot clusters render on
water rather than in a wall; that the catch lines read correctly; that the guild
door toggles the boost; and that a big net attempt visibly lands several fish at
once.

Declined with a reason each, in the table's own header: spot relocation (wants a
tile set nothing states), the single-fish bait spots, karambwan and karambwanji,
dark crab, minnow, and big net junk (rates published nowhere).

Phase 2's fourth gathering skill. Eleven methods over 66 spots, nine tools, six baits, the Angler's outfit, the Fishing Guild and barbarian fishing. Full suite **4507 passed, zero failures** (seed 1, fresh test database). Format, `compile --warnings-as-errors`, Credo and Dialyzer all clean. The world boots. ## The three findings that outlive the branch **The roll period belongs to the METHOD.** Third arrangement of one field and the one that settles it. A small fishing net rolls every 6 ticks for shrimp and every **2** for minnow — same item id, same tool row — which kills "the tool owns it"; a harpoon rolls every 6 bronze or dragon, which kills "the skill owns it". So `ticks` lives on the method and `World.Fishing.tools_among/2` stamps it onto the tool at lookup. `Contract.Skilling.best/2` needed no change: tools sharing a method share a period, so `{factor, -period}` falls through to factor. **Cascade is a real mechanic and the wiki's own chart proves it.** Raw shrimps carry `high: 256` — a certainty at 99 — and the published figure is **49.61%**. The missing half is anchovies, rolled first at `(1 + 128) / 256 = 50.39%`, and `1 - 0.5039 = 0.4961` exactly. Rolling independently would be wrong by a factor of two at the top of the curve and *look perfectly right at the bottom*, since anchovies are not eligible until 15. Pinned by walking all 256 dice faces: 129 anchovies, 127 shrimp, none empty. **`Contract.Skilling.interpolate/3` truncates where the published formula rounds** — 902 of 2,178 mining combinations. `Contract.Fishing` carries its own rounded interpolation over raw wiki parameters and reproduces every published fishing figure checked against it. Woodcutting and mining are deliberately not moved; that is #117, and the question to answer first is which rounding mining's own charts were generated with. ## Two corrections to what was written down **622 and 623 are the two halves of one animation, not two candidates for it.** 623 is the pole held in the water (2 frames / 32 cycles), 622 the initial swing (19 / 238). Three independently maintained symbol tables agree on 623 and the cache's own frame shapes confirm it. The barbarian rod was on 622 with no source and is now on 623 with three. **A fishing spot stands ON the water** and is worked from the bank. Measured: 194 of the dump's own 197 are blocked, and the derivation's own validator — the barbarian-rod tiles at `2500, 3504..3513` — is blocked too. The prose said the opposite in three places; the derivation was right and only the sentence was wrong, so "fixing" it would have moved 28 correct rows onto the shore. The test now asserts **reachability, not walkability** — 30 of 30 against the dump's 196 of 197. ## Tick manipulation Fishing is the first of the three skills the skilling clock was waiting for (Herblore, Cooking, Fishing), and it inherited the mechanic with **no engine change** by being ordinary. Measured by driving the real loop a tick at a time: unmanipulated (a five-tick lure) rolls on 4, 9, 14, 19 cycle 5 delay item claimed at clock -1 rolls on 4, 7, 10, 13, 16 cycle 3 delay item claimed at clock 0 rolls on 4, 6, 8, 10, 12 cycle 2 All three are tests. What it exposed is that the **delay items are thinner than the real game's**: `Production.start/4` is the only `:inventory` arm and is reached only when a recipe exists, so knife-and-teak — canonical precisely because it makes nothing and never fills the pack — does nothing here at all. Behavioural rather than structural, and it belongs to `Production` rather than to fishing. ## Fly fishing Every one of this cache's 17 `Lure`/`Bait` definitions had **zero spawns**, so trout, salmon, pike and rainbow fish were absent from the world entirely and the skill had a hole from 20 to 58. Thirty rows across five areas fill it, derived from the collision map rather than typed. The ids are ours and the assignment is arbitrary *because* all 17 definitions are identical — which a test now asserts, so it stays arbitrary. The durable fix for the whole class is #118: `Cache.MapSquare` throws the overlay id away and water is an overlay. ## Also in this branch * A `bait?` gate in `Contract.Skilling`'s chain beside `tool`, because a rod with no bait and no rod at all are the same class of problem — in the contract so fishing cannot grow a second, differently ordered copy of the gate order. * **The branch would not boot**: a stray comma in the appended spawn rows made `npc_spawns.exs` a syntax error. A green suite missed it because `mix test` was reading a stale `_build/test` copy of the priv file. * `yield/3` claimed to stop at the first fish that will not fit and did not, so a big net into a nearly-full pack said *"You can't carry any more fish."* three times. Now a `reduce_while`, with a test on the message count. ## Filed rather than folded in * **#117** — the interpolation rounding, above. * **#118** — `Cache.MapSquare` discards the overlay id, so nothing can ask whether a tile is water. * **#119** — `World.Content.LightTest` is **seed-flaky**, and it is not this branch's. `mix test --seed 12` on that file *alone* fails, as do 15 and 20. `Light.run/2` rolls its own dice, ExUnit seeds `:rand` from the run seed, and the test needs a roll that fails only 191 times in 256. Adding any file reshuffles the order and re-rolls the lottery, which is why it looked like this branch's. ## Not done **The live sitting**, narrowed to five things: whether the rod's initial swing is worth playing before the held pose; that the five fly-spot clusters render on water rather than in a wall; that the catch lines read correctly; that the guild door toggles the boost; and that a big net attempt visibly lands several fish at once. Declined with a reason each, in the table's own header: spot relocation (wants a tile set nothing states), the single-fish bait spots, karambwan and karambwanji, dark crab, minnow, and big net junk (rates published nowhere).
feat(fishing): eleven methods over 66 spots, on the shared skilling clock
All checks were successful
ci / gates (pull_request) Successful in 55s
012dd1ae6c
Core spots plus barbarian fishing. The spots are scanned from the cache the
way trees are -- every one is named `Fishing spot` and carries its methods as
menu actions -- so no prior revision's NPC ids are in the path. Two traps that
must not be re-derived: the options sit at menu slots 1 and 3 and the op
indexes the action array directly, and the verb does not name the tool (`Net`
is a small net at one spot and a big net at another; only Piscatoris'
coordinates say which is monkfish).

The roll period belongs to the METHOD. Woodcutting says the skill owns it and
mining says the tool does; fishing kills both, since a small fishing net rolls
every 6 ticks for shrimp and every 2 for minnow while a harpoon rolls every 6
bronze or dragon. `ticks` lives on the method and is stamped onto the tool at
lookup, which left `Contract.Skilling.best/2` unchanged.

Cascade is stated per method rather than inferred. Raw shrimps carry
`high: 256` and are published at 49.61% at 99 because anchovies rolls first at
50.39%; rolling independently is wrong by a factor of two at the top of the
curve and looks right at the bottom, since anchovies are not eligible until
15. Pinned by walking all 256 dice faces.

`Contract.Fishing` carries its own interpolation because the published formula
rounds where `Contract.Skilling` truncates -- 902 of 2,178 mining combinations
-- and its scale is in tenths because the dragon harpoon's published 3/40 to
3/48 is inexpressible in eighths. The two shipped skills are deliberately not
moved.

Fishing is also the first skill that can be tick-manipulated, and it needed no
engine change: it arms the clock under `:gathering`, never clears it in
`halt/1`, and is in `World.Skilling.loops/0`. Measured through the real loop at
3 ticks with the guide's rotation and 2 on the tighter clock-zero claim,
against 5 unmanipulated. All three cycles are tests.

Fly fishing had zero spawns for all 17 `Lure` definitions, so trout, salmon,
pike and rainbow fish were absent from the world entirely and the skill had a
hole from 20 to 58. Thirty rows across five areas fill it, derived from the
collision map rather than typed: a fishing spot stands ON the water and is
worked from the bank, which is 194 of the dump's own 197, and what has to hold
is reachability rather than walkability.

Every rod takes sequence 623. 622 and 623 are the two halves of one animation
rather than two candidates for it -- 623 is the pole held in the water at 2
frames over 32 cycles, 622 the initial swing at 19 over 238 -- which three
independent symbol tables agree on and the cache's own frame shapes confirm.

Adds a `bait?` gate to `Contract.Skilling`'s chain beside `tool`, because a rod
with no bait and no rod at all are the same class of problem, and putting it in
the contract stops fishing growing a second differently ordered copy of the
gate order.
feat(fishing): relocate fly spots between their candidates instead of pinning all of them
All checks were successful
ci / gates (pull_request) Successful in 52s
build / image (push) Successful in 33s
ci / gates (push) Successful in 59s
b282629a34
Fly-fishing spots were placed one per derived candidate tile, so a stretch of
river with eight reachable tiles stood as eight permanent spots -- the
modelling error the live sitting named. Hold a few of each cluster live and
move them instead.

World.FishSpots is World.ItemSpawns' shape: a registry the ground phase
reconciles each tick, pure where the lifecycle is, effectful only where the
world is. The 30 candidate rows group into five clusters and the world holds
three of a cluster of six-plus tiles and two below it -- 13 live over 30
candidates, exactly the reduction the sitting asked for, without deleting a
row. A relocation is a despawn and a fresh spawn at another candidate, because
the NPC block has no teleport; the new index is what stops a player fishing the
spot that moved, through the loop's existing empty-slot check. Water-and-shore
is re-checked on every move, and the timer is the era's 250-530 ticks.
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Revenant/Server!120
No description provided.