Skip to content

Add the Evil Tree Distraction & Diversion - #1256

Open
HarleyGilpin wants to merge 11 commits into
GregHib:mainfrom
HarleyGilpin:evil-tree
Open

Add the Evil Tree Distraction & Diversion#1256
HarleyGilpin wants to merge 11 commits into
GregHib:mainfrom
HarleyGilpin:evil-tree

Conversation

@HarleyGilpin

@HarleyGilpin HarleyGilpin commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Builds on the existing evil-tree work in progress and finishes it so the event can be played end to end: a seedling sprouts somewhere in the world, grows into a tree, gets chopped and burned down, and pays out rewards.

Reference: 2011 wiki for the numbers and the flow.

Event lifecycle

Two world timers drive the event — evil_tree_spawn schedules the next tree, evil_tree ticks the live one. Timers rather than World.queue because clearing a queue invokes its pending block, which would respawn a tree during teardown.

A tree sprouts two minutes after startup and two hours after the last one died, both configurable, and its location is announced when world.messages is on.

Growth

Saplings advance a stage every seed_health growth points, gained either from the growth timer or from nurturing, which pays the tier's farming experience spread across the stage. Roots briefly shoot out of the ground near a sprouting sapling, once per player per tree. The final stage displaces anyone standing where the 3x3 tree appears, sets the tree's health and bursts four roots out of the ground.

Chopping and burning

  • Chopping the trunk uses the woodcutting success rates of the matching log and takes a point of health per successful chop; the tree swaps to its damaged and dying models at two thirds and one third health.
  • Chopping a root yields evil tree kindling and dies after three to seven successful chops. A replacement root bursts out every minute, shoving and stunning anyone stood on top of it.
  • Lighting kindling against the trunk places a fire in one of the twelve spots around the tree; every lit fire burns a point of health per tick cycle.
  • Lightning strikes at ten, twenty and thirty minutes, capping the tree at half then a quarter of its health before felling it outright.

Rewards

Kindling is the currency. It's handed in to the leprechaun or taken from the reward stump (varbit 1542 picks the reward or blank stump per player), capped at two hundred a day, paying coins, noted logs and "evil tree magic" scaled by the amount handed in. Evil tree magic halves the chance of felling a tree, escorts logs to the bank once the inventory is full and doubles the bird's nest rate.

Players can help with two trees a day; inspecting a tree doesn't count towards that.

Fixes to the work in progress

  • The growth timer registered player handlers (timerStart/timerTick) against an npc timer, so the body never ran and a zero interval task span every tick.
  • A string concatenation in the stage when ("evil_tree_young" + "evil_tree_young_large") meant neither young stage matched.
  • The burning code checked and removed kindling, the Lunar Diplomacy item, rather than evil_tree_kindling.
  • chop and light were never wired to an option, so a single click advanced a whole stage with no level check, animation or experience.
  • wander_radius isn't a valid npc parameter and threw on startup; wander ranges live in the npc_ranges table.
  • tree_xp held the wiki's root experience values; corrected both columns against the wiki, along with elder's burn experience and woodcutting level.
  • The spirit tree referenced an object id (strange_sapling) that doesn't exist, so its sapling branch was unreachable, and its countdown was a placeholder. Both now work off the live event state.

Testing

EvilTreeTest covers growth by nurture and by timer, the growth spurt, chopping the trunk and the roots, root death, burning kindling, fire damage, the lightning strikes, death and respawn scheduling, the reward stump, the tool loan, and both daily limits. Full suite passes.

GregHib and others added 11 commits September 1, 2026 17:17
Completes the work-in-progress evil tree event so it can be played end to
end: a seedling sprouts, grows into a tree, gets chopped and burned down,
and pays out rewards.

Event lifecycle
- Two world timers drive the event: `evil_tree_spawn` schedules the next
  tree, `evil_tree` ticks the live one. Timers are used over `World.queue`
  because clearing a queue invokes its pending block, which would respawn
  a tree during teardown.
- A tree sprouts two minutes after startup and two hours after the last one
  died, both configurable, and its location is announced when world
  messages are enabled.

Growth
- Saplings advance a stage every `seed_health` growth points, gained either
  from the growth timer or from nurturing, which pays the tier's farming
  experience spread across the stage.
- Roots briefly shoot out of the ground near a sprouting sapling, once per
  player per tree.
- The final stage displaces anyone standing where the three by three tree
  appears, sets the tree's health and bursts four roots out of the ground.

Chopping and burning
- Chopping the trunk uses the woodcutting success rates of the matching log
  and takes a point of health per successful chop; the tree swaps to its
  damaged and dying models at two thirds and one third health.
- Chopping a root yields evil tree kindling and dies after three to seven
  successful chops. A replacement root bursts out every minute, shoving and
  stunning anyone stood on top of it.
- Lighting kindling against the trunk places a fire in one of the twelve
  spots around the tree; every lit fire burns a point of health per tick
  cycle.
- Lightning strikes at ten, twenty and thirty minutes, capping the tree at
  half then a quarter of its health before felling it outright.

Rewards
- Kindling is handed in to the leprechaun, or taken from the reward stump,
  capped at two hundred a day and paying coins, noted logs and evil tree
  magic scaled by the amount handed in.
- Evil tree magic halves the chance of felling a tree, escorts logs to the
  bank once the inventory is full and doubles the bird's nest rate.
- Players can help with two trees a day; inspecting a tree doesn't count.

Also fixes several defects in the existing work in progress: the growth
timer registered player handlers against an npc timer so it never ran, a
string concatenation in the stage `when` meant neither young stage matched,
the burning code used the Lunar Diplomacy kindling item, the chop and light
loops were never wired up to an option, and `wander_radius` isn't a valid
npc parameter. The spirit tree now gives a real countdown to the next tree
and its sapling branch is reachable.
`GameObjects.remove` emitted its despawn event midway through its own
bookkeeping, before clearing the object's map flag. An object added by a
handler claimed that flag, and the clear which followed wiped it again.

The client had already been sent the ObjectAddition, so the new object was
drawn, but `map` held zero for that tile and layer, which `getLayer` treats
as empty. Every server side lookup - `getLayer`, `findOrNull`, `contains`
and so the object interaction dispatch - found nothing there. The object
was visible and completely inert.

Evil tree roots hit this: they burst out as a temporary `_spawn` model and
the settled root is added in its place from an `objectDespawn` handler, so
the roots could be seen but never chopped.

Emit the despawn once the map flag is cleared and any original object
underneath has been restored, so handlers only ever observe a settled tile.
Two existing tests pinned the old ordering of the event against the
original's re-add and have been updated to the new one.

Drives the evil tree root tests through the real burst and settle path
rather than placing roots into the event state by hand, which is why the
suite stayed green while the feature was broken in game.
The woodcutting loop breaks out on a full inventory before it ever reaches
`addLog`, so the banking branch added for evil tree magic was unreachable
and logs simply stopped being cut.

Let the loop continue while the buff is going to escort the log to the
bank, keeping the "inventory is too full" exit for everyone else and for
the log types the buff doesn't carry.

Also stores the buff's remaining duration in ticks rather than seconds. It
was counted down by a timer whose one second interval rounds to a single
tick, so the buff ran out in about six tenths of the time it was granted
for.
Testing the reward buff's woodcutting effects meant growing a tree, felling
it and handing in kindling first. `::evil_tree_magic [minutes]` grants it
directly, defaulting to the thirty minutes an elder tree pays out, and
takes it away again with 0.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants