From 0abcae9bbd393d196c42b454312caf8f9a4d7cd0 Mon Sep 17 00:00:00 2001 From: Michael Meyer Date: Wed, 19 Jan 2022 17:10:04 -0500 Subject: [PATCH] Hide plastic babies in slices of king cake Sometimes the hero will find a plastic baby inside a piece of king cake, just like in real life. In order to make this apply to 'real' king cake created during Mardi Gras, and not to user-defined fruit with an identical name, change holiday fruits to use a negative fruit ID as their spe. To enable this, add a new macro, fruit_id() -- which provides the absolute value of fruit->spe -- and use it in most cases the fruit ID needs to be accessed. Negative fruit IDs are already used when saving bones, to mark fruits which don't exist on the current level and therefore don't need to be included in the bones file, but those are negative fids in the g.ffruit linked list, not negative spe on individual items. These changes shouldn't interfere with that process as long as the possible negative spe is taken into consideration when saving and loading bones, which it now should be. --- include/obj.h | 5 +++++ src/bones.c | 4 ++-- src/eat.c | 28 ++++++++++++++++++++++++++++ src/mkobj.c | 3 ++- src/objnam.c | 2 +- src/options.c | 2 +- src/restore.c | 11 ++++++++--- 7 files changed, 47 insertions(+), 8 deletions(-) diff --git a/include/obj.h b/include/obj.h index 670b3ee60..c8f05cf50 100644 --- a/include/obj.h +++ b/include/obj.h @@ -476,6 +476,11 @@ struct obj { #define thiefstone_ledger_valid(stone) \ ((stone)->keyed_ledger > 0 && (stone)->keyed_ledger <= maxledgerno()) +/* special holiday fruits are differentiated from user-defined fruits by + * negative spe */ +#define is_holiday_fruit(obj) ((obj)->otyp == SLIME_MOLD && (obj)->spe < 0) +#define fruit_id(obj) (abs((obj)->spe)) + /* * Notes for adding new oextra structures: * diff --git a/src/bones.c b/src/bones.c index c1b2c8154..ab616af8a 100644 --- a/src/bones.c +++ b/src/bones.c @@ -137,7 +137,7 @@ resetobjs(struct obj *ochain, boolean restore) } if (otmp->otyp == SLIME_MOLD) { - goodfruit(otmp->spe); + goodfruit(fruit_id(otmp)); #ifdef MAIL_STRUCTURES } else if (otmp->otyp == SCR_MAIL) { /* 0: delivered in-game via external event; @@ -321,7 +321,7 @@ drop_upon_death(struct monst *mtmp, /* monster if hero turned into one (other th otmp->owt = weight(otmp); if (otmp->otyp == SLIME_MOLD) - goodfruit(otmp->spe); + goodfruit(fruit_id(otmp)); if (rn2(5)) curse(otmp); diff --git a/src/eat.c b/src/eat.c index 8523e170c..0fe3077e2 100644 --- a/src/eat.c +++ b/src/eat.c @@ -2385,6 +2385,34 @@ fpostfx(struct obj *otmp) if (!u.uconduct.literate++) livelog_printf(LL_CONDUCT, "became literate by reading the fortune inside a cookie"); break; + case SLIME_MOLD: + if (is_holiday_fruit(otmp)) { + struct fruit *f = fruit_from_indx(fruit_id(otmp)); + if (!rn2(15) && f && !strcmp("slice of king cake", f->fname)) { + static const int babies[] = { + PM_BABY_CROCODILE, + PM_BABY_LONG_WORM, + PM_BABY_PURPLE_WORM, + PM_BABY_GRAY_DRAGON, + PM_BABY_GOLD_DRAGON, + PM_BABY_SILVER_DRAGON, + PM_BABY_RED_DRAGON, + PM_BABY_WHITE_DRAGON, + PM_BABY_ORANGE_DRAGON, + PM_BABY_BLACK_DRAGON, + PM_BABY_BLUE_DRAGON, + PM_BABY_GREEN_DRAGON, + PM_BABY_YELLOW_DRAGON, + }; + struct obj *feve = mksobj(FIGURINE, TRUE, FALSE); + set_corpsenm(feve, babies[rn2(SIZE(babies))]); + set_material(feve, PLASTIC); + There("is a plastic baby inside the slice of king cake!"); + hold_another_object(feve, "It falls to the floor.", + (const char *) 0, (const char *) 0); + } + } + break; case LUMP_OF_ROYAL_JELLY: /* This stuff seems to be VERY healthy! */ gainstr(otmp, 1, TRUE); /* will -1 if cursed */ diff --git a/src/mkobj.c b/src/mkobj.c index 57c12f687..cb73aac93 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -990,7 +990,8 @@ mksobj(int otyp, boolean init, boolean artif) /* fruitadd requires a modifiable string */ char foodbuf[BUFSZ]; Strcpy(foodbuf, foods[rn2(idx)]); - otmp->spe = fruitadd(foodbuf, NULL); + /* holiday fruits have negative spe */ + otmp->spe = -fruitadd(foodbuf, NULL); } } flags.made_fruit = TRUE; diff --git a/src/objnam.c b/src/objnam.c index 3ae21629f..93653daf1 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -631,7 +631,7 @@ xname_flags( case FOOD_CLASS: /* we could include partly-eaten-hack on fruit but don't need to */ if (typ == SLIME_MOLD) { - struct fruit *f = fruit_from_indx(obj->spe); + struct fruit *f = fruit_from_indx(fruit_id(obj)); if (!f) { impossible("Bad fruit #%d?", obj->spe); diff --git a/src/options.c b/src/options.c index 5e2f2d861..32de4bec8 100644 --- a/src/options.c +++ b/src/options.c @@ -7172,7 +7172,7 @@ fruitadd(char *str, struct fruit *replace_fruit) char buf[PL_FSIZ], altname[PL_FSIZ]; boolean user_specified = (str == g.pl_fruit); /* if not user-specified, then it's a fruit name for a fruit on - * a bones level or from orctown raider's loot... + * a bones level, a holiday food, or from orctown raider's loot... */ /* Note: every fruit has an id (kept in obj->spe) of at least 1; diff --git a/src/restore.c b/src/restore.c index 9e25f8ed9..77b279f70 100644 --- a/src/restore.c +++ b/src/restore.c @@ -507,13 +507,18 @@ ghostfruit(register struct obj* otmp) register struct fruit *oldf; for (oldf = g.oldfruit; oldf; oldf = oldf->nextf) - if (oldf->fid == otmp->spe) + if (oldf->fid == fruit_id(otmp)) break; - if (!oldf) + if (!oldf) { impossible("no old fruit?"); - else + } else { + boolean holiday_food = is_holiday_fruit(otmp); otmp->spe = fruitadd(oldf->fname, (struct fruit *) 0); + if (holiday_food) { + otmp->spe = -(otmp->spe); + } + } } #ifdef SYSCF