Tutorial: spellcasting

Add some basic spellcasting stuff to the tutorial: read a spellbook,
cast a spell.  If the hero doesn't have enough energy, just adds
a note saying so.

Remove/restore the known spells when entering/leaving the tutorial.
This commit is contained in:
Pasi Kallinen
2025-07-09 18:30:54 +03:00
parent b4f2ef853a
commit 3440193a5a
4 changed files with 23 additions and 3 deletions

View File

@@ -32,10 +32,10 @@ des.level_flags("mazelevel", "noflip",
des.map([[
---------------------------------------------------------------------------
|-.--|.......|......|..S....|.F.......|.............|.....................|
|-.--|.......|......|..S....|.F.......|.............|.......|.............|
|.-..........|......|--|....|.F.....|.|S-------.....|.....................|
||.--|.......|..T......|....|.F.....|.|.......|.....|.....................|
||.|.|.......|......|-.|....|.F.....|.|.......|.....|.....................|
||.--|.......|..T......|....|.F.....|.|.......|.....|.......|.............|
||.|.|.......|......|-.|....|.F.....|.|.......|.....|--------.............|
||.|.|.......|......||.|-.-----------.-.......|-S----.....................|
|-+-S---------..---.||........................|...|.......................|
|......| |.-------------------.......|...|....--S----............|
@@ -302,6 +302,21 @@ des.object({ id = "boulder", coord = {72,16} });
des.object({ id = "boulder", coord = {73,16} });
des.trap({ type = "trap door", coord = { 73,15 } });
--
des.engraving({ coord = { 60,2 }, type = "engrave", text = "Spellcasting", degrade = false });
if (u.uenmax < 5) then
-- TODO: make sure hero has enough Pw to cast the spell (5 pw) instead?
-- TODO: ensure the first cast of this spell succeeds?
des.engraving({ coord = { 59,2 }, type = "engrave", text = "Unfortunately you don't have enough energy to cast spells.", degrade = false });
end
des.engraving({ coord = { 57,2 }, type = "engrave", text = "Pick up the spellbook with '" .. tut_key("pickup") .. "'", degrade = false });
des.object({ coord = { 57,2 }, id = "spellbook of light", buc = "blessed" });
des.engraving({ coord = { 55,2 }, type = "engrave", text = "Read the spellbook with '" .. tut_key("read") .. "'", degrade = false });
des.engraving({ coord = { 53,2 }, type = "engrave", text = "Use '" .. tut_key("cast") .. "' to cast a spell", degrade = false });
des.region(selection.area(53,01, 59, 3), "unlit");
----------------
-- entering and leaving tutorial _branch_ now handled by core

View File

@@ -423,6 +423,7 @@ struct instance_globals_g {
long gmst_moves;
struct obj *gmst_invent;
genericptr_t *gmst_ubak, *gmst_disco, *gmst_mvitals;
struct spell gmst_spl_book[MAXSPELL + 1];
/* pline.c */
struct gamelog_line *gamelog;

View File

@@ -372,6 +372,7 @@ static const struct instance_globals_g g_init_g = {
0L, /* gmst_moves */
NULL, /* gmst_invent */
NULL, NULL, NULL, /* gmst_ubak, gmst_disco, gmst_mvitals */
{ DUMMY }, /* gmst_spl_book */
/* pline.c */
UNDEFINED_PTR, /* gamelog */
/* region.c */

View File

@@ -1695,6 +1695,7 @@ nhl_gamestate(lua_State *L)
init_uhunger();
free_tutorial(); /* release gg.gmst_XYZ */
gg.gmst_stored = FALSE;
(void) memcpy(svs.spl_book, gg.gmst_spl_book, sizeof svs.spl_book);
} else if (!reststate && !gg.gmst_stored) {
/* store game state */
gg.gmst_moves = svm.moves;
@@ -1715,6 +1716,8 @@ nhl_gamestate(lua_State *L)
gg.gmst_mvitals = (genericptr_t) alloc(sizeof svm.mvitals);
(void) memcpy(gg.gmst_mvitals, (genericptr_t) &svm.mvitals,
sizeof svm.mvitals);
(void) memcpy(gg.gmst_spl_book, svs.spl_book, sizeof svs.spl_book);
(void) memset(svs.spl_book, 0, sizeof(svs.spl_book));
gg.gmst_stored = TRUE;
} else {
impossible("nhl_gamestate: inconsistent state (%s vs %s)",