mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-19 04:06:10 +02:00
big ass modding update
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
# Weather Battles Example
|
||||
|
||||
Adds rain: for the first five turns of every battle, WATER moves deal 1.5x
|
||||
damage and FIRE moves deal 0.5x. Only under the `WEATHER` ruleset — pick
|
||||
`gen1_faithful` and the mod is installed and inert.
|
||||
|
||||
**Persona: the Mechanic Designer.** A new battle mechanic, no engine fork.
|
||||
The status and ruleset registries plus one hook carry the whole thing.
|
||||
|
||||
## Try it
|
||||
|
||||
```sh
|
||||
python3 tools/modkit.py validate mods/examples/example_weather --base imported
|
||||
luajit mods/examples/example_weather/tests/example_weather_test.lua
|
||||
```
|
||||
|
||||
Enable it (`example_weather = true` under `mods` in `options.lua`, or the
|
||||
F10 manager), then **OPTIONS → RULESET → WEATHER**.
|
||||
|
||||
## What it demonstrates
|
||||
|
||||
| Seam | Where |
|
||||
|---|---|
|
||||
| `content.statuses:register` | `main.lua` — declaring a field effect |
|
||||
| `content.rulesets:register` | `main.lua` — a ruleset the OPTIONS menu lists automatically |
|
||||
| `content.rulesets:get` | `main.lua` — deriving from vanilla without requiring a private module |
|
||||
| `hooks:wrap("battle.damage")` | `main.lua` — the one behavior change |
|
||||
| `events:on("battle.started" / "battle.turn_started" / "battle.ended")` | `main.lua` — the rain counter |
|
||||
| `mod.save:get/set` | `main.lua` — per-mod state, not a global |
|
||||
|
||||
## Parity, at the mod level
|
||||
|
||||
The engine's promise is that a mod-free game is unchanged. This example
|
||||
makes the same promise one level up: a *player* who installs it but does
|
||||
not select the ruleset gets vanilla battles.
|
||||
|
||||
```lua
|
||||
if not (ctx.ruleset and ctx.ruleset.exampleWeather and raining()) then
|
||||
return next(ctx)
|
||||
end
|
||||
```
|
||||
|
||||
`next(ctx)` with the arguments it was handed *is* the vanilla call. No
|
||||
allocation, no rounding, no reordering — the same number the engine would
|
||||
have produced. Everything above that line is a gate, and every gate that
|
||||
fails defers.
|
||||
|
||||
## Preserving multiple returns
|
||||
|
||||
`Damage.compute` returns two values: the damage number and an info table
|
||||
carrying the crit flag and the type multiplier. A wrapper that returns only
|
||||
the first silently throws the second away, and the battle log stops saying
|
||||
"A critical hit!".
|
||||
|
||||
```lua
|
||||
local damage, info = next(ctx)
|
||||
if type(damage) ~= "number" then return damage, info end
|
||||
return math.max(1, math.floor(damage * scale)), info
|
||||
```
|
||||
|
||||
Hook chains preserve every return value, so passing `info` back through is
|
||||
all it takes.
|
||||
|
||||
## Deriving a ruleset from vanilla
|
||||
|
||||
A ruleset record is the *whole* rule table — `oneIn256Miss`,
|
||||
`critUsesBaseSpeed`, `randMin`, `randMax` and the rest. Registering one
|
||||
that only sets `name` would silently drop every Gen 1 quirk. So this mod
|
||||
reads the vanilla record out of the merged registry and copies it:
|
||||
|
||||
```lua
|
||||
local base = mod.content.rulesets:get("gen1_faithful")
|
||||
local weather = {}
|
||||
for key, value in pairs(base) do weather[key] = value end
|
||||
weather.name = "WEATHER"
|
||||
weather.exampleWeather = true
|
||||
```
|
||||
|
||||
`:get` on a registry is the public path to engine content. It needs no
|
||||
permission, and it composes: if another mod patched `gen1_faithful` first,
|
||||
this ruleset inherits that patch too.
|
||||
|
||||
`exampleWeather` is not in the ruleset schema. Unknown fields on a record
|
||||
registry are preserved rather than rejected — that is what makes rulesets
|
||||
extensible, and it is how the damage hook recognizes its own ruleset
|
||||
without a second lookup.
|
||||
|
||||
## Missing dependency, handled
|
||||
|
||||
If another mod removed `gen1_faithful`, `:get` returns nil. This example
|
||||
logs a remediation line and returns — the rest of the game keeps working
|
||||
and the manager shows one attributed message. No `assert`, no crash.
|
||||
|
||||
## Credits
|
||||
|
||||
- pret/pokered — the damage formula the hook scales.
|
||||
Reference in New Issue
Block a user