Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .out-of-scope/tool-and-armour-families.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Tool and armour Families

Voidworks does not upgrade tools or armour up a Family (wooden → stone → copper → iron → golden →
diamond, or the armour ladders).

## Why this is out of scope

Equipment meets the void a different way: the Void Siphon serves as an FE provider that charges
powered equipment. Void energy reaches a player's gear as power, not by mutating the gear itself.

Upgrading equipment would also have meant an upgrade carrying item data across (enchantments,
damage, custom names, armour trims), which no other Family needs. A Family stays a ladder of plain
items, so `Upgrade` hands back a fresh result and never copies item data.

## Prior requests

- #36: "Tool and armour Families"
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Written for Consumers: what a mod building against Voidworks can use, or will se

## Unreleased

- **Breaking:** a grown Void Dragon ages through four life stages, young, adult, senior and old, by the motes it unloads over its life, each stage `lifeStageMotes` (524,288) long, changing only at a stop (ADR 0010). Each stage multiplies its load and speed (`lifeStageLoads` 1/2/3.5/6, `lifeStageSpeeds` 1/0.6/0.35/0.2 in `voidworks-server.toml`), its speed stacking on its health's share, floored at a quarter; a new load applies from its next load and a new speed from its next dive. Only an adult lays Drained Dragon Eggs: eggs it still owes on turning senior are laid at its next loaded stop, then no more. An old dragon whose stage runs out dies at the end of a stop at a loaded Well, carrying nothing, living on past an unloaded one: it sets any rider down on the Well's rim, lays the eggs it owes, and its presence rises over the Well in a short Ender Dragon death, beams and sound, leaving nothing; nothing else tells its owner. An egg's price now counts its owner's living dragons and eggs soaking, not every dragon they ever hatched, so a death, or `/voidworks dragon remove`, lowers it (`Hatchery.lose`). `/voidworks dragon age <stage>` sets the grown dragon an operator looks at to the start of that stage, owing no egg. Jade shows a dragon's stage, and its presence is sized ×0.8, ×1, ×1.1 or ×1.2 by it. Dragons saved before this start young, their count toward an egg dropped. `Routing` takes a `LifeStages` and `step` returns the dragons that died; `VoidDragonRecord` gains `cargo` and loses `speed()`, now `LifeStages.speed(dragon)`; `DragonReport` gains `stage`. (#54)
- **Breaking:** a dragon egg's price is datapack data, no longer server config (ADR 0009). The `voidworks:egg_price` block data map, on `voidworks:soaking_dragon_egg`, names an owner's `first_price` (25600 void energy) and its `growth` (2), the multiple each dragon they have hatched or are soaking puts on their next egg; a growth of 1 keeps every egg at the first price, and an egg with no entry is free. `firstEggPrice` is gone from `voidworks-server.toml` and `VoidworksConfig`. `EggPrice.of(dragons)` gives a price, `EggPrice.of(state)` an egg block's entry, and `Hatchery.startSoaking` takes the `EggPrice`; `Hatchery.price` and `Hatchery.codec` give way to `EggPrice.of` and `Hatchery.CODEC`. (#25)
- A Void Dragon resting at a Well lands and sits astride its rim, over the shaft, lengthwise along the wall its core is set in so neither head nor tail covers the core, in the Ender Dragon's sitting pose, its wings held still and down, turning its head toward a nearby player. Where blocks fill the room its body takes there, it flies about over the shaft instead and lands once there is room. As it sets off it takes off, then dives into the shaft; mounted by its owner, it takes off to hover, and lands again once they get off. One at work at a Well, loading, unloading, waiting for its owner or setting a rider down, stays in the air, and one back after its chunk unloaded is sitting already. `VoidDragon.perch()` says whether a presence flies, lands, sits or takes off (`VoidDragon.Perch`), `perchYaw()` the heading it keeps meanwhile and `seatPos()` where it sits. A ridden dragon now hovers in place: before, its wandering pulled it slowly about under its rider. (#81)
- A Void Dragon resting at a Well whose chunk is not loaded no longer loads that chunk each second to see whether to show it (ADR 0005).
Expand Down
12 changes: 9 additions & 3 deletions GLOSSARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ _Avoid_: tamer, master
**Void Dragon**:
A dragon raised on void that carries motes or matter, as its Line says, between Void Wells, diving
through the void between them, across dimensions. It grows from a Dragonling. Nothing hurts it: it only weakens on dives
outside the End, heals at its Wells, and never dies.
outside the End and heals at its Wells. It ages through its life stages and dies of old age.
_Avoid_: Ender Dragon (the boss), tamed dragon

**Dive**:
Expand All @@ -162,12 +162,18 @@ trip: the Well its owner calls the dragon to, or the Well its rider picks, which
them down before it goes on.
_Avoid_: route, job

**Life stage**:
How old a grown Void Dragon is: **young**, **adult**, **senior** or **old**, reached by the cargo it
has carried. Each later stage is slower and carries more; only an adult lays eggs, and an old dragon
dies when its stage runs out.
_Avoid_: age class, tier

**Dragonling**:
A young Void Dragon, hatched from an egg soaked in motes. It cannot carry yet; it stays near where
A Void Dragon before it grows, not yet in any life stage, hatched from an egg soaked in motes. It cannot carry yet; it stays near where
it hatched, follows a player holding a Void Siphon, and grows faster for the motes a Siphon feeds it.

**Drained Dragon Egg**:
The egg a grown Void Dragon lays as it works: a dragon egg drained of void. It and the vanilla egg,
The egg an adult Void Dragon lays as it works: a dragon egg drained of void. It and the vanilla egg,
the founder of the Mote line, both soak motes once a player places them touching Voidstone, as a
Dormant machine soaks its cost, and hatch once they have soaked enough; broken first, an egg loses
what it soaked.
Expand Down
13 changes: 13 additions & 0 deletions docs/adr/0010-a-void-dragon-dies-of-old-age.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
status: accepted
---

# A Void Dragon dies of old age

#5 promised that nothing hurts a Void Dragon and that it never dies. #54 takes that back for old age alone: a grown dragon ages through four life stages by the cargo it unloads, and dies when its old stage runs out, so a player keeps hatching dragons and the egg economy stays alive. Weakening still never kills, nothing else does, and a dragon dies only at a stop after unloading, so no load or rider is lost to it.

## Consequences

- A dragon is spent by work, not by time: one left resting never ages.
- The egg price counts living dragons only, so a dead dragon's replacement costs what it did.
- Once players have lost dragons to old age, making dragons immortal again would strand that history; reverse it only with a reason as strong as this one.
49 changes: 33 additions & 16 deletions docs/spec/void-energy.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,28 +274,45 @@ player who placed its egg, and it serves only its owner's Wells
is server state, not an entity: it routes, dives, weakens and heals with no chunk loaded, and the
dragon a player sees near a Well is only its presence
([ADR 0005](../adr/0005-a-void-dragon-is-server-state-not-an-entity.md)). Nothing hurts a
Dragonling or a Void Dragon.
Dragonling or a Void Dragon, and only old age kills a Void Dragon
([ADR 0010](../adr/0010-a-void-dragon-dies-of-old-age.md)).

- **Eggs.** The first dragon kill gives the vanilla egg, the founder of every line. Later kills give
nothing, but while no player has hatched a dragon in the world, a kill places a vanilla egg on the
exit portal again, so a lost founder is replaced. Every other egg is a **Drained Dragon Egg**,
laid by a grown Void Dragon each time it has carried a set number of motes since its last, counted
as it unloads them, a stowed load too: it pops out of the shaft of the next Well it stops at, to
laid by an adult Void Dragon each time it has carried a set number of motes since its last, or
since it became adult, counted as it unloads them, a stowed load too: it pops out of the shaft of the next Well it stops at, to
load or unload, as an item, so eggs are given and traded. A Well whose chunk is not loaded lays
none: the dragon owes the egg, with any others it comes to owe, to its next stop at a loaded Well,
where it lays them all, so its eggs follow only the motes it carries. Until it
where it lays them all, so its eggs follow only the motes it carries; eggs still owed as it turns
senior are laid the same way, and none after. A dragon lays eggs of its own Line, so 8 in its life. Until it
soaks, a Drained Dragon Egg falls and teleports when hit, as the vanilla egg does.
- **Hatching.** Either egg, placed by a player touching a Voidstone network, soaks up motes from it
by the spend rule at the egg's block, in four visible stages, until it hatches a Dragonling its
placer owns. A soaking egg neither falls nor teleports. Its price is fixed when it starts soaking
and grows, doubling by default, with every dragon its owner has hatched or is soaking, so carriers grow as fast as an
owner can pay for them, and an egg given away starts its new owner cheap. An egg no player placed
and grows, doubling by default, with every living dragon its owner has, Dragonling or Void Dragon of
either Line, and every egg they are soaking, so carriers grow as fast as an owner can pay for them,
a dead dragon's replacement costs what it did, and an egg given away starts its new owner cheap. An egg no player placed
never soaks. Broken while soaking, it drops the egg it was and loses what it soaked.
- **Growing.** A **Dragonling** is a young Void Dragon, an ordinary creature until it grows. It stays
- **Growing.** A **Dragonling** is a Void Dragon before it grows, an ordinary creature until then. It stays
near where it hatched, follows a player holding a Void Siphon, and grows up over a set time while
its chunk is loaded. Its owner feeds it by using a Siphon on it, which empties into it by the spend
rule at the Dragonling, and the void energy takes time off its growing. It cannot carry, and does
not weaken.
- **Ageing.** A grown Void Dragon ages through four **life stages**, **young**, **adult**, **senior**
and **old**, by the cargo it unloads, in its Line's unit: each stage lasts the same amount, so a
stage changes only at a stop, as it unloads. Its load takes the new stage's size from its next
load, and its speed from its next dive; a load it holds is never cut. Each stage multiplies the
Line's speed and load (provisional: young 1 and 1, adult 0.6 and 2, senior 0.35 and 3.5, old 0.2
and 6), so a young dragon is a quick courier and an old one a slow freighter, carrying about as
much an hour either way. Stages are not inherited: every dragon lives all four, and bred traits,
if they come, multiply on top of them. An old dragon whose stage runs out **dies**, only at a stop
at a loaded Well, once that stop is over: carrying nothing, it lays the eggs it owes, sets any rider
down on the rim, even one still mounted, then its presence rises over the Well in a short Ender
Dragon death, beams and sound, and leaves nothing. Its stage running out at a Well that is not
loaded, it lives on and dies at its next stop at a loaded one, so no egg is lost. Nothing else
tells its owner. Dragons from before life stages start young, their count toward an egg dropped. Matching a dragon's stage to a trip, fast for far and big for large shortfalls, is left
to routing as it is, and to a later ticket if play needs it.
- **Routing.** A Void Dragon serves all its owner's Void Wells in every dimension. It flies only to a
Well below its fill target, and takes from the owner's Well of highest network pressure that holds
something worth delivering there, a reservoir or a Well above its target, which gives its excess;
Expand Down Expand Up @@ -344,15 +361,16 @@ Dragonling or a Void Dragon.
- **Harm.** It weakens as it dives, at a rate set by how far the Void Pressure at the worse of the
dive's two ends is below the End's, so a trip to or from the Nether, where motes pay most, costs it
most, and one between End Wells nothing. Stopped at a Well or resting, it does not weaken. Hurt, it
flies more slowly, down to a quarter of its speed, and a dive slows as it weakens during it, so a
long dive to or from the Nether takes longer still; it cannot die. It never dives from a Well before
flies more slowly, its health's share of its stage's speed, never below a quarter of it, and a dive slows as it weakens during it, so a
long dive to or from the Nether takes longer still; weakening never kills it. It never dives from a Well before
that Well has healed it, from its store, a fixed number of motes per point of health, lowest grade
first and not by the spend rule, as far as the motes go; an empty Well heals nothing.
- **Seen in Jade.** Anyone looking at a dragon's presence sees what its record holds: what it is
doing, the Well it is bound for by name, the motes it carries by grade and in total, its health
doing, its life stage, the Well it is bound for by name, the motes it carries by grade and in total, its health
and its owner; looking at a Dragonling, how far it has grown and its owner.
- **Look.** The vanilla Ender Dragon, its model and its texture read from the player's own game at
runtime and tinted the void's purple: the Void Dragon about half the Ender Dragon's size, the
runtime and tinted the void's purple: the Void Dragon about half the Ender Dragon's size, scaled by its stage (young 0.8, adult 1, senior
1.1, old 1.2), the
Dragonling about a fifth. Nothing of Mojang's ships in the jar, and the dragon has no texture of its
own. The Drained Dragon Egg is a pale, cracked dragon egg on the vanilla egg's shape, its cracks dark
while it is only an egg. Soaking, either egg wears that look, the vanilla egg too, though it is still
Expand Down Expand Up @@ -439,6 +457,7 @@ What Voidworks ships, ⇒ marking a steep Rung, each ladder one Family (`gems`,
shell. Boss drops (nether star, dragon egg, dragon's breath) are left out.
- **Passive drops**: feather → leather → rabbit hide → ink sac → glow ink sac → rabbit's foot →
armadillo scute → turtle scute.
- **No tools or armour.** An upgrade gives a fresh result and carries no item data, so gear has no Family; void energy reaches gear as FE through the Void Siphon instead ([ADR 0007](../adr/0007-a-void-siphon-charges-fe-items-and-voidworks-makes-no-gear.md)).

The shipped Families keep three rules, which a pack may break on purpose:

Expand Down Expand Up @@ -503,8 +522,6 @@ ends as Voidstone. The Void Siphon alone must never close a profitable loop.
## Open

- **Voidstone raising Void Pressure around it** — a later layer, compounding a site's harvests.
- **Tool and armour Families** — wooden → stone → copper → iron → golden → diamond, and what an
upgrade carries over: enchantments, damage, names, trims.
- **Numbers** — prices are datapack data and the rest server config
([ADR 0009](../adr/0009-prices-are-datapack-data-and-physics-is-server-config.md)): the pressures and grades beyond the provisional bands above, the Density curve, Zone sizes and upgrade costs,
each Dormant machine's cost, how much a Voidstone holds, each Rung's count, cost and chance (provisional: metal, gem
Expand All @@ -514,11 +531,11 @@ ends as Voidstone. The Void Siphon alone must never close a profitable loop.
the Void Siphon's capacity per tier, the FE a void energy charges (provisional: 10, tuned against
Gearworks' Gear, whose battery upgrade holds 100,000; a server config value), and the network pressure cap, and the Void Dragon's (provisional:
the first egg 25,600 void energy, doubling per dragon; Dragonling growth 40 minutes, 1 minute off
per 1,000 void energy fed; a load of 8,192 motes; about 5 seconds a stop; 1 second a dive per 64
per 1,000 void energy fed; a young dragon's load of 8,192 motes; a life stage 524,288 motes carried; about 5 seconds a stop; 1 second a dive per 64
blocks, and 10 seconds more between dimensions; 100 health, weakening by the pressure gap per 10 seconds, healing 1 per 16
motes; an egg laid each 65,536 motes carried).
- **Void Dragon life stages** — young, adult, senior and old, trading speed for load, and death in
old age ([#54](https://github.com/5thlayer/voidworks/issues/54)).
- **A Matter-line dragon's life** — its cargo unit, base load, stage length and egg cost, set with
its throughput ([#86](https://github.com/5thlayer/voidworks/issues/86)).
- **FE from a network** — a Voidstone network or a Void Well turning motes into FE for any mod's
cables: base power, which balancing void energy against FE generation makes a design of its own.
- **Teams** — after the first major version: players sharing Wells and dragons as a team, beyond
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/io/github/_5thlayer/voidworks/Voidworks.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import net.neoforged.fml.ModContainer;
import net.neoforged.fml.common.Mod;
import net.neoforged.fml.config.ModConfig;
import net.neoforged.fml.event.config.ModConfigEvent;
import net.neoforged.neoforge.common.NeoForge;

/**
Expand Down Expand Up @@ -52,6 +53,8 @@ public Voidworks(IEventBus modBus, ModContainer container) {
Families.register(modBus);
UnmakingRecipes.register(modBus);
container.registerConfig(ModConfig.Type.SERVER, VoidworksConfig.SPEC);
modBus.addListener(ModConfigEvent.Loading.class, VoidworksConfig::onLoad);
modBus.addListener(ModConfigEvent.Reloading.class, VoidworksConfig::onLoad);
NeoForge.EVENT_BUS.addListener(Conduction::onLevelTick);
Hatching.register();
DragonPresences.register();
Expand Down
Loading
Loading