@rpgm-tools/neo-angband-core 0.24.0 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/agent/entity-views.d.ts +62 -0
- package/dist/agent/entity-views.d.ts.map +1 -0
- package/dist/agent/entity-views.js +195 -0
- package/dist/agent/entity-views.js.map +1 -0
- package/dist/agent/index.d.ts +5 -1
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +2 -0
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/loadout.d.ts +97 -0
- package/dist/agent/loadout.d.ts.map +1 -0
- package/dist/agent/loadout.js +312 -0
- package/dist/agent/loadout.js.map +1 -0
- package/dist/agent/perceive.d.ts.map +1 -1
- package/dist/agent/perceive.js +16 -162
- package/dist/agent/perceive.js.map +1 -1
- package/dist/agent/types.d.ts +167 -2
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js +10 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/game/context.d.ts +15 -0
- package/dist/game/context.d.ts.map +1 -1
- package/dist/game/context.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/mod/registry-host.d.ts +97 -0
- package/dist/mod/registry-host.d.ts.map +1 -1
- package/dist/mod/registry-host.js +7 -0
- package/dist/mod/registry-host.js.map +1 -1
- package/dist/mod/save-blocks.d.ts +1 -1
- package/dist/player/calcs.d.ts +9 -0
- package/dist/player/calcs.d.ts.map +1 -1
- package/dist/player/calcs.js +13 -1
- package/dist/player/calcs.js.map +1 -1
- package/dist/player/loadout.d.ts +178 -0
- package/dist/player/loadout.d.ts.map +1 -0
- package/dist/player/loadout.js +172 -0
- package/dist/player/loadout.js.map +1 -0
- package/dist/player/spell.d.ts +21 -1
- package/dist/player/spell.d.ts.map +1 -1
- package/dist/player/spell.js +53 -14
- package/dist/player/spell.js.map +1 -1
- package/dist/session/game.d.ts +39 -0
- package/dist/session/game.d.ts.map +1 -1
- package/dist/session/game.js +201 -31
- package/dist/session/game.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/src/agent/entity-views.ts +227 -0
- package/src/agent/index.ts +9 -0
- package/src/agent/loadout.ts +400 -0
- package/src/agent/perceive.ts +22 -168
- package/src/agent/types.ts +166 -2
- package/src/game/context.ts +18 -0
- package/src/index.ts +1 -0
- package/src/mod/registry-host.ts +108 -0
- package/src/player/calcs.ts +22 -1
- package/src/player/loadout.ts +331 -0
- package/src/player/spell.ts +67 -16
- package/src/session/game.ts +287 -35
- package/src/version.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"game.d.ts","sourceRoot":"","sources":["../../src/session/game.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAMrC,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AA0D3E,OAAO,KAAK,EACV,SAAS,EAGV,MAAM,oBAAoB,CAAC;AAM5B,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAS3D,OAAO,KAAK,EAAiB,WAAW,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"game.d.ts","sourceRoot":"","sources":["../../src/session/game.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAMrC,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AA0D3E,OAAO,KAAK,EACV,SAAS,EAGV,MAAM,oBAAoB,CAAC;AAM5B,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAS3D,OAAO,KAAK,EAAiB,WAAW,EAAE,MAAM,wBAAwB,CAAC;AA8FzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAQpD,OAAO,KAAK,EAAE,KAAK,EAAqB,MAAM,mBAAmB,CAAC;AASlE,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAgB,MAAM,sBAAsB,CAAC;AAUhF,OAAO,EAKL,eAAe,EACf,iBAAiB,EASlB,MAAM,qBAAqB,CAAC;AAsB7B,OAAO,KAAK,EAAE,UAAU,EAAkB,MAAM,kBAAkB,CAAC;AAKnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAsB7D,OAAO,KAAK,EACV,WAAW,EACX,gBAAgB,EAChB,QAAQ,EAET,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAmCvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAQ3C,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE/E;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,SAAS,EAChB,GAAG,EAAE,WAAW,GACf,UAAU,GAAG,IAAI,CAiBnB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,GAAG,GAAG,GAAG,IAAI,CAM7D;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,SAAS,EAChB,SAAS,EAAE,SAAS,MAAM,EAAE,GAC3B,MAAM,GAAG,IAAI,CAMf;AAED,gFAAgF;AAChF,MAAM,WAAW,QAAS,SAAQ,QAAQ;IACxC,MAAM,EAAE,iBAAiB,CAAC;CAC3B;AAED,uCAAuC;AACvC,MAAM,WAAW,gBAAiB,SAAQ,gBAAgB;IACxD,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC5B;;;;OAIG;IACH,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B;;;;;OAKG;IACH,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;IACvD,uEAAuE;IACvE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC7C;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,iBAAiB,EAAE,QAAQ,CAAC;IAC9C;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;CACxC;AAED,iFAAiF;AACjF,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,EAAE,cAAc,CAAC;IACzB;;;;;OAKG;IACH,OAAO,EAAE,cAAc,GAAG,IAAI,CAAC;IAC/B,gFAAgF;IAChF,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,cAAc,CAAC;IACxB,oEAAoE;IACpE,MAAM,EAAE,eAAe,CAAC;IACxB;;;OAGG;IACH,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,6EAA6E;IAC7E,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,QAAQ,EAAE,YAAY,CAAC;IACvB,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B;;;OAGG;IACH,OAAO,EAAE,WAAW,CAAC;IACrB,gFAAgF;IAChF,mBAAmB,EAAE,OAAO,CAAC;IAC7B;;;;;;OAMG;IACH,aAAa,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACvD,iEAAiE;IACjE,OAAO,EAAE,WAAW,CAAC;IACrB;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC;;;;;;;;;;OAUG;IACH,WAAW,EAAE,CAAC,IAAI,CAAC,EAAE,kBAAkB,KAAK,iBAAiB,CAAC;IAC9D;;;;OAIG;IACH,aAAa,EAAE,YAAY,CAAC;IAC5B;;;OAGG;IACH,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,KAAK,SAAS,CAAC;IAC/D;;;;OAIG;IACH,IAAI,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,UAAU,CAAC;IAChE;;;;OAIG;IACH,SAAS,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,KAAK,UAAU,CAAC;IACtE;;;OAGG;IACH,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;IACpF;;;;OAIG;IACH,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,UAAU,KAAK,OAAO,CAAC;CACrD;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,YAAY,GAAG,IAAI,CAC7B,UAAU,EACV,UAAU,GAAG,SAAS,GAAG,QAAQ,GAAG,UAAU,GAAG,UAAU,CAC5D,CAAC;AAy1EF;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,oEAAoE;IACpE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,8CAA8C;AAC9C,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AA4UD;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,GAAE,gBAAqB,GAAG,WAAW,CA8blF;AA6VD,uEAAuE;AACvE,wBAAgB,QAAQ,CAAC,IAAI,EAAE,WAAW,GAAG,SAAS,CAkBrD;AAED;;;;;GAKG;AACH,yEAAyE;AACzE,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC7C;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,iBAAiB,EAAE,QAAQ,CAAC;IAC9C;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,QAAQ,CACtB,IAAI,EAAE,QAAQ,EACd,YAAY,EAAE,SAAS,EACvB,OAAO,GAAE,WAAW,CAAC,MAAM,CAAqB,EAChD,IAAI,GAAE,eAAoB,GACzB,WAAW,CAmeb"}
|
package/dist/session/game.js
CHANGED
|
@@ -85,7 +85,7 @@ import { displayFeeling, installCaveCommands, movementAutoDig } from "../game/ca
|
|
|
85
85
|
import { installSteal } from "../game/steal.js";
|
|
86
86
|
import { calcUnlockingChance, installChunkFeatHook, installTrap, installTraps, playerIsTrapsafe, squareDoorPower, squareIsPlayerTrap, squareIsWarded, squareIsWebbed, squareRemoveAllTraps, squareSetDoorLock, trapPredicates, } from "../game/trap.js";
|
|
87
87
|
import { lookupTrap } from "../world/trap.js";
|
|
88
|
-
import { calcMana, calcSpells, cumberArmorFrom, playerSpellsInit, registerBookKinds, } from "../player/spell.js";
|
|
88
|
+
import { calcMana, calcSpells, cumberArmorFrom, playerSpellsInit, registerBookKinds, wornArmorWeight, } from "../player/spell.js";
|
|
89
89
|
import { installSpellCommands, makeSpellChanceEnv } from "../game/spell-cmd.js";
|
|
90
90
|
import { installRangedCommands } from "../game/ranged-cmd.js";
|
|
91
91
|
import { markNoscore, NOSCORE } from "../game/wizard.js";
|
|
@@ -351,6 +351,20 @@ function wireGame(state, reg, players, pstate, seedFlavor) {
|
|
|
351
351
|
state.knownPlayerState = known;
|
|
352
352
|
state.actor.knownCombat = toCombatState(known);
|
|
353
353
|
};
|
|
354
|
+
/**
|
|
355
|
+
* The calc_bonuses options bag for the world as it stands, minus the loadout.
|
|
356
|
+
* ONE definition, because a hypothetical derive that reads a different bag
|
|
357
|
+
* from the live one is a derive that quietly answers a different question -
|
|
358
|
+
* the curse traversal in particular is easy to leave out and impossible to
|
|
359
|
+
* notice from the number that comes back.
|
|
360
|
+
*/
|
|
361
|
+
const liveBonusOptions = (update) => ({
|
|
362
|
+
timedEffects: players.timed,
|
|
363
|
+
curses: reg.objects.curses,
|
|
364
|
+
update,
|
|
365
|
+
depth: state.chunk.depth,
|
|
366
|
+
isDaytime: isDaytime(state.turn, state.z.dayLength),
|
|
367
|
+
});
|
|
354
368
|
const refreshDerived = () => {
|
|
355
369
|
const p = state.actor.player;
|
|
356
370
|
const equipment = p.equipment.map((h) => h ? gearGet(state.gear, h) : null);
|
|
@@ -358,14 +372,7 @@ function wireGame(state, reg, players, pstate, seedFlavor) {
|
|
|
358
372
|
/* p->state before the memcpy at the end of calc_bonuses: the encumbrance
|
|
359
373
|
* notices below diff against it (player-calcs.c:2412-2453). */
|
|
360
374
|
const before = derived;
|
|
361
|
-
const bonusOptions = {
|
|
362
|
-
equipment,
|
|
363
|
-
timedEffects: players.timed,
|
|
364
|
-
curses: reg.objects.curses,
|
|
365
|
-
update: true,
|
|
366
|
-
depth: state.chunk.depth,
|
|
367
|
-
isDaytime: daytime,
|
|
368
|
-
};
|
|
375
|
+
const bonusOptions = { ...liveBonusOptions(true), equipment };
|
|
369
376
|
derived = calcBonuses(p, bonusOptions);
|
|
370
377
|
state.playerState = derived;
|
|
371
378
|
refreshKnownCombat(p, bonusOptions);
|
|
@@ -410,6 +417,22 @@ function wireGame(state, reg, players, pstate, seedFlavor) {
|
|
|
410
417
|
}
|
|
411
418
|
};
|
|
412
419
|
state.updateBonuses = refreshDerived;
|
|
420
|
+
/**
|
|
421
|
+
* calc_bonuses for a loadout the player is NOT wearing (update=false, so the
|
|
422
|
+
* derive keeps its hands off p->timed[TMD_FASTCAST] and the town-light redraw),
|
|
423
|
+
* over the same options bag the live refresh uses.
|
|
424
|
+
*
|
|
425
|
+
* This is the one thing a hypothetical derive could not do from outside: the
|
|
426
|
+
* bag carries the bound timed table and the curse registry, and a caller
|
|
427
|
+
* assembling its own would silently drop whichever it did not know about. It is
|
|
428
|
+
* installed here for the same reason updateBonuses is - the session is the only
|
|
429
|
+
* place that has all of it.
|
|
430
|
+
*/
|
|
431
|
+
state.derivedFor = (equipment, totalWeight) => calcBonuses(state.actor.player, {
|
|
432
|
+
...liveBonusOptions(false),
|
|
433
|
+
equipment: equipment.slice(),
|
|
434
|
+
...(totalWeight === undefined ? {} : { totalWeight }),
|
|
435
|
+
});
|
|
413
436
|
/**
|
|
414
437
|
* update_stuff's PU_UPDATE_VIEW arm (player-calcs.c:2608), as the DEFAULT.
|
|
415
438
|
*
|
|
@@ -2309,6 +2332,163 @@ function makeChangeLevel(state, reg, trapDeps, opts = {}) {
|
|
|
2309
2332
|
state.chunk.onlyPartial = false;
|
|
2310
2333
|
};
|
|
2311
2334
|
}
|
|
2335
|
+
/**
|
|
2336
|
+
* reincarnate_borg (borg/borg-reincarnate.c:408): wipe the live player in place,
|
|
2337
|
+
* roll a new one, and carry on in the SAME session.
|
|
2338
|
+
*
|
|
2339
|
+
* WHAT MAKES THIS DIFFERENT FROM A NEW GAME. Upstream never exits to a menu and
|
|
2340
|
+
* never opens a second savefile. It saves the level off, calls `player_init` and
|
|
2341
|
+
* `player_generate` on the same `struct player *`, restores the level, and returns
|
|
2342
|
+
* to the game loop. Everything a session owns - the turn counter, the RNG stream,
|
|
2343
|
+
* the message log, the option store, the mod manifest, the save slot - is still
|
|
2344
|
+
* the same object afterwards. This does the same thing for the same reason: a host
|
|
2345
|
+
* that reloaded the page or claimed a new slot would be a different program that
|
|
2346
|
+
* happens to end up somewhere similar.
|
|
2347
|
+
*
|
|
2348
|
+
* THE PLAYER OBJECT IS MUTATED, NOT REPLACED, and that is load-bearing rather than
|
|
2349
|
+
* incidental. wireGame's closures captured `state`, and a good number of them
|
|
2350
|
+
* captured `state.actor.player` - the same reason a level change swaps the chunk in
|
|
2351
|
+
* place. Upstream reuses the pointer for the identical reason.
|
|
2352
|
+
*
|
|
2353
|
+
* WHERE THE NEW CHARACTER COMES FROM. `generatePlayer` and `outfitPlayer`, the
|
|
2354
|
+
* same two functions `startGame` births from. Upstream's `borg_roll_hp` and
|
|
2355
|
+
* `borg_outfit_player` are near-copies of `roll_hp` and `player_outfit` that exist
|
|
2356
|
+
* because the borg cannot run the interactive birth UI; this port's birth pipeline
|
|
2357
|
+
* is not interactive, so the real one is reachable and the copies are not needed.
|
|
2358
|
+
* The one upstream detail with no equivalent here is `create_random_name`'s
|
|
2359
|
+
* per-race syllable tables - this port has `playerRandomName`, so a caller passes
|
|
2360
|
+
* `fullName` from that rather than a second name generator landing in core.
|
|
2361
|
+
*
|
|
2362
|
+
* WHAT IT DELIBERATELY DOES NOT DO. Upstream re-seeds `seed_flavor` and, under
|
|
2363
|
+
* `birth_randarts`, `seed_randart`. Both are seeds this port's savefile stores and
|
|
2364
|
+
* re-derives the world from (docs/PARITY.md names them as the two places a stream
|
|
2365
|
+
* change IS a defect), so moving either mid-session would make the save describe a
|
|
2366
|
+
* world the game is not in. The flavour KNOWLEDGE is reset instead, which is the
|
|
2367
|
+
* half a player can observe: the new character does not inherit what the dead one
|
|
2368
|
+
* identified.
|
|
2369
|
+
*/
|
|
2370
|
+
function makeReincarnate(state, reg, players, flavor, everseen, changeLevel) {
|
|
2371
|
+
return (opts = {}) => {
|
|
2372
|
+
const rng = state.rng;
|
|
2373
|
+
/* "save the existing dungeon. It is cleared later but needs to be blank when
|
|
2374
|
+
* creating the new player" (borg-reincarnate.c:414-418). Nothing below clears
|
|
2375
|
+
* it here - the wipe is confined to the player and their gear - so the restore
|
|
2376
|
+
* at the end is a no-op in the ordinary case. It is still written both ways,
|
|
2377
|
+
* because the pair is what says the level is not this function's to touch. */
|
|
2378
|
+
const savedChunk = state.chunk;
|
|
2379
|
+
const savedMonsters = state.monsters;
|
|
2380
|
+
const savedGroups = state.groups;
|
|
2381
|
+
const savedFloor = state.floor;
|
|
2382
|
+
const savedTraps = state.traps;
|
|
2383
|
+
const savedKnown = state.known;
|
|
2384
|
+
const savedGrid = state.actor.grid;
|
|
2385
|
+
/* Roll up a new character (borg-reincarnate.c:465-476). A named race or class
|
|
2386
|
+
* that no pack defines falls through to the roll rather than throwing: the
|
|
2387
|
+
* caller is a mod's configuration, and a typo there should cost a reroll. */
|
|
2388
|
+
const race = (opts.raceName ? players.raceByName(opts.raceName) : null) ??
|
|
2389
|
+
players.races[rng.randint0(players.races.length)];
|
|
2390
|
+
const cls = (opts.className ? players.classByName(opts.className) : null) ??
|
|
2391
|
+
players.classes[rng.randint0(players.classes.length)];
|
|
2392
|
+
const body = players.bodies[race.body] ?? players.bodies[0];
|
|
2393
|
+
const birth = generatePlayer(race, cls, { body, historyChart: players.historyChart(race) }, rng);
|
|
2394
|
+
/* player_init(player) then player_generate(player, race, class, false)
|
|
2395
|
+
* (borg-reincarnate.c:435, :476), on the same object. Every own key goes and
|
|
2396
|
+
* the fresh character's keys land, so a field added to Player later is carried
|
|
2397
|
+
* across without this function being edited - the alternative, a field-by-field
|
|
2398
|
+
* copy, is a list that silently stops being complete. */
|
|
2399
|
+
const live = state.actor.player;
|
|
2400
|
+
for (const key of Object.keys(live))
|
|
2401
|
+
delete live[key];
|
|
2402
|
+
Object.assign(live, birth.player);
|
|
2403
|
+
const p = state.actor.player;
|
|
2404
|
+
/* player_quests_reset (player-quest.c:157), as at birth. */
|
|
2405
|
+
playerQuestsReset(p, reg.quests);
|
|
2406
|
+
/* The dead character's belongings do not come forward. Emptied IN PLACE for
|
|
2407
|
+
* the same reason the player object is: `state.gear` is captured. */
|
|
2408
|
+
state.gear.store.clear();
|
|
2409
|
+
state.gear.next = 1;
|
|
2410
|
+
state.gear.pack.length = 0;
|
|
2411
|
+
state.gear.inven = [];
|
|
2412
|
+
state.gear.quiver = [];
|
|
2413
|
+
/* Nor does what they identified. Upstream reaches this through flavor_init's
|
|
2414
|
+
* reshuffle; see the header for why the seed itself is left alone. */
|
|
2415
|
+
flavor.restore({ aware: [], tried: [] });
|
|
2416
|
+
/* borg_outfit_player (borg-reincarnate.c:521) is player_outfit. */
|
|
2417
|
+
const startKinds = [];
|
|
2418
|
+
outfitPlayer(state.gear, p, reg.objects, rng, reg.constants, {
|
|
2419
|
+
opt: (name) => state.options?.get(name) ?? false,
|
|
2420
|
+
onStartKind: (kind) => void startKinds.push(kind),
|
|
2421
|
+
});
|
|
2422
|
+
/* The same three passes over the new kit startGame runs after birth:
|
|
2423
|
+
* kind->everseen (player-birth.c:658), object_flavor_aware (:650) and
|
|
2424
|
+
* obj->known->effect (:650). */
|
|
2425
|
+
for (const obj of state.gear.store.values())
|
|
2426
|
+
everseen.markKind(obj.kind);
|
|
2427
|
+
for (const kind of startKinds) {
|
|
2428
|
+
flavor.objectFlavorAware(kind, NOOP_FLAVOR_AWARE_DEPS);
|
|
2429
|
+
}
|
|
2430
|
+
for (const obj of state.gear.store.values())
|
|
2431
|
+
obj.knownEffect = obj.effect;
|
|
2432
|
+
/* player_spells_init (borg-reincarnate.c:518), then the derived recompute -
|
|
2433
|
+
* PU_BONUS | PU_HP | PU_MANA - which is what turns the rolled hitdice into
|
|
2434
|
+
* mhp and the worn armour into the mana penalty. calcSpells wants the stat
|
|
2435
|
+
* indices that recompute produces, so it follows rather than leads. */
|
|
2436
|
+
playerSpellsInit(p);
|
|
2437
|
+
state.updateBonuses?.();
|
|
2438
|
+
calcSpells(p, state.statInd ?? [], (text) => state.msg?.(text));
|
|
2439
|
+
/* rd_gear's tail / the first update_stuff after player_outfit. The ammo tval
|
|
2440
|
+
* is the NEW class's, so it is read back off the recompute above. */
|
|
2441
|
+
buildGearViews(state, reg, state.playerState?.ammoTval ?? 0);
|
|
2442
|
+
/* player_learn_innate (borg-reincarnate.c:515) and the worn kit's obvious
|
|
2443
|
+
* runes, exactly as startGame does them after the rune env exists. */
|
|
2444
|
+
playerLearnInnate(p, state.runeEnv);
|
|
2445
|
+
for (let i = 0; i < p.body.count; i++) {
|
|
2446
|
+
const worn = state.runeEnv.slotObject(i);
|
|
2447
|
+
if (worn)
|
|
2448
|
+
objectLearnOnWield(p, worn, state.runeEnv);
|
|
2449
|
+
}
|
|
2450
|
+
/* "fully healed and rested" (borg-reincarnate.c:569-571). */
|
|
2451
|
+
p.chp = p.mhp;
|
|
2452
|
+
p.csp = p.msp;
|
|
2453
|
+
/* Mark the savefile (borg-reincarnate.c:587-589). One-way. */
|
|
2454
|
+
if (opts.noscore)
|
|
2455
|
+
p.noscore = markNoscore(p.noscore, opts.noscore);
|
|
2456
|
+
if (opts.fullName !== undefined)
|
|
2457
|
+
p.fullName = opts.fullName;
|
|
2458
|
+
/* The new player is now ready (borg-reincarnate.c:585). Cheating death is
|
|
2459
|
+
* upstream's other branch and not this one, so any suspended fatal blow is
|
|
2460
|
+
* dropped with the character that took it. */
|
|
2461
|
+
state.isDead = false;
|
|
2462
|
+
state.playing = true;
|
|
2463
|
+
state.pendingDeath = undefined;
|
|
2464
|
+
/* Restore the level (borg-reincarnate.c:579-582). */
|
|
2465
|
+
state.chunk = savedChunk;
|
|
2466
|
+
state.monsters = savedMonsters;
|
|
2467
|
+
state.groups = savedGroups;
|
|
2468
|
+
state.floor = savedFloor;
|
|
2469
|
+
state.traps = savedTraps;
|
|
2470
|
+
state.known = savedKnown;
|
|
2471
|
+
state.actor.grid = savedGrid;
|
|
2472
|
+
installChunkFeatHook(state);
|
|
2473
|
+
/* store_reset() and chunk_list_max = 0 (borg-reincarnate.c:534-535): the new
|
|
2474
|
+
* character does not inherit the dead one's shopping, its home stash, or any
|
|
2475
|
+
* frozen level. Dropping `stores` is what makes refreshTownStores rebuild them
|
|
2476
|
+
* from scratch on arrival rather than age the old ones forward. */
|
|
2477
|
+
delete state.stores;
|
|
2478
|
+
state.daycount = 0;
|
|
2479
|
+
state.levelCache?.clear();
|
|
2480
|
+
state.townChunk = null;
|
|
2481
|
+
/* "Start in town" plus generate_level = true (borg-reincarnate.c:483, :524).
|
|
2482
|
+
* Upstream's restored cave survives only until run_game_loop's next pass calls
|
|
2483
|
+
* prepare_next_level at the new depth of 0; changeLevel IS that call, so it is
|
|
2484
|
+
* made here and the flag is left down rather than handed to the host as a
|
|
2485
|
+
* second thing to remember. */
|
|
2486
|
+
changeLevel(0);
|
|
2487
|
+
state.generateLevel = false;
|
|
2488
|
+
delete state.targetDepth;
|
|
2489
|
+
return { raceName: race.name, className: cls.name };
|
|
2490
|
+
};
|
|
2491
|
+
}
|
|
2312
2492
|
/**
|
|
2313
2493
|
* Resolve the quest guardians to place on a freshly generated level
|
|
2314
2494
|
* (generate.c L1170-1191). Returns one QuestSpawn per active quest whose
|
|
@@ -2798,6 +2978,10 @@ export function startGame(pack, opts = {}) {
|
|
|
2798
2978
|
search(state); /* on_new_level (game-world.c:1052). */
|
|
2799
2979
|
state.chunk.onlyPartial = false;
|
|
2800
2980
|
}
|
|
2981
|
+
/* One instance, shared: reincarnate ends by asking for the town, and it must be
|
|
2982
|
+
* the same level changer the host drives so the arena bookkeeping inside it is
|
|
2983
|
+
* not split across two closures with separate `inArena` flags. */
|
|
2984
|
+
const changeLevel = makeChangeLevel(state, reg, wired.trapDeps);
|
|
2801
2985
|
return {
|
|
2802
2986
|
state,
|
|
2803
2987
|
registry: wired.registry,
|
|
@@ -2815,7 +2999,8 @@ export function startGame(pack, opts = {}) {
|
|
|
2815
2999
|
orphansAcknowledged: false,
|
|
2816
3000
|
options,
|
|
2817
3001
|
randartSeed,
|
|
2818
|
-
changeLevel
|
|
3002
|
+
changeLevel,
|
|
3003
|
+
reincarnate: makeReincarnate(state, reg, players, wired.flavor, wired.everseen, changeLevel),
|
|
2819
3004
|
wizardBundles: wired.wizardBundles,
|
|
2820
3005
|
...makeStoreApi(state, reg, wired.flavor, options),
|
|
2821
3006
|
};
|
|
@@ -3102,24 +3287,6 @@ function swapRandartSet(reg, seed, timedFoil, activationSummarize) {
|
|
|
3102
3287
|
reg.objects.artifacts.length = 0;
|
|
3103
3288
|
reg.objects.artifacts.push(...randarts);
|
|
3104
3289
|
}
|
|
3105
|
-
/** The worn-armor weight calc_mana penalizes (non-weapon/bow/jewelry slots). */
|
|
3106
|
-
function wornArmorWeight(player, equipment) {
|
|
3107
|
-
let weight = 0;
|
|
3108
|
-
for (let i = 0; i < player.body.count; i++) {
|
|
3109
|
-
const slotType = player.body.slots[i]?.type ?? "";
|
|
3110
|
-
if (slotType === "WEAPON" ||
|
|
3111
|
-
slotType === "BOW" ||
|
|
3112
|
-
slotType === "RING" ||
|
|
3113
|
-
slotType === "AMULET" ||
|
|
3114
|
-
slotType === "LIGHT") {
|
|
3115
|
-
continue;
|
|
3116
|
-
}
|
|
3117
|
-
const worn = equipment[i];
|
|
3118
|
-
if (worn)
|
|
3119
|
-
weight += worn.weight;
|
|
3120
|
-
}
|
|
3121
|
-
return weight;
|
|
3122
|
-
}
|
|
3123
3290
|
/** Serialize a started game into the JSON save format (decision 9). */
|
|
3124
3291
|
export function saveGame(game) {
|
|
3125
3292
|
const ids = new ContentIdResolver(game.booted.registries);
|
|
@@ -3487,6 +3654,10 @@ export function loadGame(pack, saveDocument, present = new Set(["core"]), opts =
|
|
|
3487
3654
|
};
|
|
3488
3655
|
/* Resuming in town: re-stock the shops (store stock is not persisted). */
|
|
3489
3656
|
refreshTownStores(state, reg);
|
|
3657
|
+
/* One level changer, shared with reincarnate - see the note at startGame's. */
|
|
3658
|
+
const changeLevel = makeChangeLevel(state, reg, wired.trapDeps, {
|
|
3659
|
+
inArena: !!save.arena,
|
|
3660
|
+
});
|
|
3490
3661
|
return {
|
|
3491
3662
|
state,
|
|
3492
3663
|
registry: wired.registry,
|
|
@@ -3505,9 +3676,8 @@ export function loadGame(pack, saveDocument, present = new Set(["core"]), opts =
|
|
|
3505
3676
|
: {}),
|
|
3506
3677
|
options,
|
|
3507
3678
|
randartSeed,
|
|
3508
|
-
changeLevel
|
|
3509
|
-
|
|
3510
|
-
}),
|
|
3679
|
+
changeLevel,
|
|
3680
|
+
reincarnate: makeReincarnate(state, reg, players, wired.flavor, wired.everseen, changeLevel),
|
|
3511
3681
|
wizardBundles: wired.wizardBundles,
|
|
3512
3682
|
...makeStoreApi(state, reg, wired.flavor, options),
|
|
3513
3683
|
};
|