Skip to content

Commit a8de188

Browse files
authored
Merge branch 'NetHack:NetHack-3.7' into test-actions
2 parents 1ed02ea + 7ff7679 commit a8de188

17 files changed

+145
-57
lines changed

Diff for: DEVEL/nhgitset.pl

+1
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,7 @@ sub do_dir_hooksdir {
353353

354354
sub do_file_nhgitset {
355355
my $infile = "DEVEL/nhgitset.pl";
356+
$infile = "$DEVhooksdir/../nhgitset.pl" unless(-f $infile);
356357
my $outfile = ".git/hooks/gitsetdocs";
357358
open IN, "<", $infile or die "Can't open $infile:$!";
358359
open OUT, ">", $outfile or die "Can't open $outfile:$!";

Diff for: doc/lua.adoc

+1-1
Original file line numberDiff line numberDiff line change
@@ -793,7 +793,7 @@ The hash parameter accepts the following keys:
793793
| adjacentok | boolean | is adjacent location ok, if given one is not suitable?
794794
| ignorewater | boolean | ignore water when choosing location for the monster
795795
| countbirth | boolean | do we count this monster as generated
796-
| appear_as | string | monster can appear as object, monster, or terrain. Add "obj:", "mon:", or "ter:" prefix to the value. |
796+
| appear_as | string | monster can appear as object, monster, or terrain. Add "obj:", "mon:", or "ter:" prefix to the value.
797797
| inventory | function | objects generated in the function are given to the monster (any random inventory it gets is discarded unless keep_default_invent is true)
798798
| keep_default_invent | boolean | if inventory is specified and this is true, those items are in addition to random inventory for this species; if inventory is not specified and this is false, monster gets no starting inventory
799799
|===

Diff for: src/artifact.c

+43-15
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ staticfn uchar abil_to_adtyp(long *) NONNULLARG1;
3535
staticfn int glow_strength(int);
3636
staticfn boolean untouchable(struct obj *, boolean);
3737
staticfn int count_surround_traps(coordxy, coordxy);
38+
staticfn void dispose_of_orig_obj(struct obj *);
3839

3940
/* The amount added to the victim's total hit points to insure that the
4041
victim will be killed even after damage bonus/penalty adjustments.
@@ -149,7 +150,8 @@ artiname(int artinum)
149150
*/
150151
struct obj *
151152
mk_artifact(
152-
struct obj *otmp, /* existing object; ignored if alignment specified */
153+
struct obj *otmp, /* existing object; ignored and disposed of
154+
* if alignment specified */
153155
aligntyp alignment, /* target alignment, or A_NONE */
154156
uchar max_giftvalue, /* cap on generated giftvalue */
155157
boolean adjust_spe) /* whether to add spe to situational artifacts */
@@ -238,36 +240,62 @@ mk_artifact(
238240
a = &artilist[m];
239241

240242
/* make an appropriate object if necessary, then christen it */
241-
otmp = mksobj((int) a->otyp, TRUE, FALSE);
242-
243+
if (by_align) {
244+
/* 'by_align' indicates that an alignment was passed as
245+
* an argument, but also that the 'otmp' argument is not
246+
* relevant */
247+
struct obj *artiobj = mksobj((int) a->otyp, TRUE, FALSE);
248+
249+
/* nonnull value of 'otmp' is unexpected. Cope. */
250+
if (otmp) /* just in case; avoid orphaning */
251+
dispose_of_orig_obj(otmp);
252+
otmp = artiobj;
253+
}
254+
/*
255+
* otmp should be nonnull at this point:
256+
* either the passed argument (if !by_align == A_NONE), or
257+
* the result of mksobj() just above if by_align is an alignment. */
258+
assert(otmp != 0);
259+
/* prevent erosion from generating */
260+
otmp->oeroded = otmp->oeroded2 = 0;
261+
otmp = oname(otmp, a->name, ONAME_NO_FLAGS);
262+
otmp->oartifact = m; /* probably already set by this point, but */
263+
/* set existence and reason for creation bits */
264+
artifact_origin(otmp, ONAME_RANDOM); /* 'random' is default */
243265
if (adjust_spe) {
244266
int new_spe;
245267

246-
/* Adjust otmp->spe by a->gen_spe. (This is a no-op for
268+
/* Adjust artiobj->spe by a->gen_spe. (This is a no-op for
247269
non-weapons, which always have a gen_spe of 0, and for many
248270
weapons, too.) The result is clamped into the "normal" range to
249271
prevent an outside chance of +12 artifacts generating. */
250272
new_spe = (int)otmp->spe + a->gen_spe;
251273
if (new_spe >= -10 && new_spe < 10)
252274
otmp->spe = new_spe;
253275
}
254-
255-
if (otmp) {
256-
/* prevent erosion from generating */
257-
otmp->oeroded = otmp->oeroded2 = 0;
258-
otmp = oname(otmp, a->name, ONAME_NO_FLAGS);
259-
otmp->oartifact = m;
260-
/* set existence and reason for creation bits */
261-
artifact_origin(otmp, ONAME_RANDOM); /* 'random' is default */
262-
}
263276
} else {
264277
/* nothing appropriate could be found; return original object */
265-
if (by_align)
266-
otmp = 0; /* (there was no original object) */
278+
if (by_align && otmp) {
279+
/* (there shouldn't have been an original object). Deal with it.
280+
* The callers that passed an alignment and a NULL otmp are
281+
* prepared to get a potential NULL return value, so this is okay */
282+
dispose_of_orig_obj(otmp);
283+
otmp = 0;
284+
} /* otherwise, otmp has not changed; just fallthrough to return it */
267285
}
268286
return otmp;
269287
}
270288

289+
staticfn void
290+
dispose_of_orig_obj(struct obj *obj)
291+
{
292+
if (!obj)
293+
return;
294+
295+
obj_extract_self(obj);
296+
obfree(obj, (struct obj *) 0);
297+
}
298+
271299
/*
272300
* Returns the full name (with articles and correct capitalization) of an
273301
* artifact named "name" if one exists, or NULL, it not.

Diff for: src/dogmove.c

+9-1
Original file line numberDiff line numberDiff line change
@@ -311,9 +311,16 @@ dog_eat(struct monst *mtmp,
311311
} else {
312312
/* It's a reward if it's DOGFOOD and the player dropped/threw it.
313313
We know the player had it if invlet is set. -dlc */
314-
if (dogfood(mtmp, obj) == DOGFOOD && obj->invlet)
314+
if (dogfood(mtmp, obj) == DOGFOOD && obj->invlet) {
315315
edog->apport += (int) (200L / ((long) edog->dropdist + svm.moves
316316
- edog->droptime));
317+
if (edog->apport <= 0) {
318+
impossible("dog_eat: pet apport <= 0 (%d, %d, %ld, %ld)",
319+
edog->apport, edog->dropdist, edog->droptime,
320+
svm.moves);
321+
edog->apport = 1;
322+
}
323+
}
317324
if (obj->unpaid) {
318325
/* edible item owned by shop has been thrown or kicked
319326
by hero and caught by tame or food-tameable monst */
@@ -399,6 +406,7 @@ dog_invent(struct monst *mtmp, struct edog *edog, int udist)
399406
* Use udist+1 so steed won't cause divide by zero.
400407
*/
401408
if (droppables(mtmp)) {
409+
assert(edog->apport > 0);
402410
if (!rn2(udist + 1) || !rn2(edog->apport))
403411
if (rn2(10) < edog->apport) {
404412
relobj(mtmp, (int) mtmp->minvis, TRUE);

Diff for: src/lock.c

+8
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,14 @@ pick_lock(
432432
boolean it;
433433
int count;
434434

435+
/*
436+
* FIXME:
437+
* (chest->otrapped && chest->tknown) is handled, to skip
438+
* checking for a trap and continue with asking about disarm;
439+
* (chest->tknown && !chest->otrapped) ignores tknown and will
440+
* ask about checking for non-existant trap.
441+
*/
442+
435443
if (u.dz < 0 && !autounlock) { /* beware stale u.dz value */
436444
There("isn't any sort of lock up %s.",
437445
Levitation ? "here" : "there");

Diff for: src/mkobj.c

+15-6
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ staticfn boolean may_generate_eroded(struct obj *);
99
staticfn void mkobj_erosions(struct obj *);
1010
staticfn void mkbox_cnts(struct obj *);
1111
staticfn unsigned nextoid(struct obj *, struct obj *);
12-
staticfn void mksobj_init(struct obj *, boolean);
12+
staticfn void mksobj_init(struct obj **, boolean);
1313
staticfn int item_on_ice(struct obj *);
1414
staticfn void shrinking_glob_gone(struct obj *);
1515
staticfn void obj_timer_checks(struct obj *, coordxy, coordxy, int);
@@ -861,9 +861,10 @@ unknow_object(struct obj *obj)
861861

862862
/* do some initialization to newly created object; otyp must already be set */
863863
staticfn void
864-
mksobj_init(struct obj *otmp, boolean artif)
864+
mksobj_init(struct obj **obj, boolean artif)
865865
{
866866
int mndx, tryct;
867+
struct obj *otmp = *obj;
867868
char let = objects[otmp->otyp].oc_class;
868869

869870
switch (let) {
@@ -880,8 +881,11 @@ mksobj_init(struct obj *otmp, boolean artif)
880881
if (is_poisonable(otmp) && !rn2(100))
881882
otmp->opoisoned = 1;
882883

883-
if (artif && !rn2(20 + (10 * nartifact_exist())))
884+
if (artif && !rn2(20 + (10 * nartifact_exist()))) {
885+
/* mk_artifact() with otmp and A_NONE will never return NULL */
884886
otmp = mk_artifact(otmp, (aligntyp) A_NONE, 99, TRUE);
887+
*obj = otmp;
888+
}
885889
break;
886890
case FOOD_CLASS:
887891
otmp->oeaten = 0;
@@ -1085,8 +1089,11 @@ mksobj_init(struct obj *otmp, boolean artif)
10851089
otmp->spe = rne(3);
10861090
} else
10871091
blessorcurse(otmp, 10);
1088-
if (artif && !rn2(40 + (10 * nartifact_exist())))
1092+
if (artif && !rn2(40 + (10 * nartifact_exist()))) {
1093+
/* mk_artifact() with otmp and A_NONE will never return NULL */
10891094
otmp = mk_artifact(otmp, (aligntyp) A_NONE, 99, TRUE);
1095+
*obj = otmp;
1096+
}
10901097
/* simulate lacquered armor for samurai */
10911098
if (Role_if(PM_SAMURAI) && otmp->otyp == SPLINT_MAIL
10921099
&& (svm.moves <= 1 || In_quest(&u.uz))) {
@@ -1176,7 +1183,7 @@ mksobj(int otyp, boolean init, boolean artif)
11761183
otmp->pickup_prev = 0;
11771184

11781185
if (init)
1179-
mksobj_init(otmp, artif);
1186+
mksobj_init(&otmp, artif);
11801187

11811188
/* some things must get done (corpsenm, timers) even if init = 0 */
11821189
switch ((otmp->oclass == POTION_CLASS && otmp->otyp != POT_OIL)
@@ -1231,8 +1238,10 @@ mksobj(int otyp, boolean init, boolean artif)
12311238
}
12321239

12331240
/* unique objects may have an associated artifact entry */
1234-
if (objects[otyp].oc_unique && !otmp->oartifact)
1241+
if (objects[otyp].oc_unique && !otmp->oartifact) {
1242+
/* mk_artifact() with otmp and A_NONE will never return NULL */
12351243
otmp = mk_artifact(otmp, (aligntyp) A_NONE, 99, FALSE);
1244+
}
12361245
otmp->owt = weight(otmp);
12371246
return otmp;
12381247
}

Diff for: src/mplayer.c

+1
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ mk_mplayer(struct permonst *ptr, coordxy x, coordxy y, boolean special)
261261
otmp->oerodeproof = 1;
262262
else if (!rn2(2))
263263
otmp->greased = 1;
264+
/* mk_artifact() with otmp and A_NONE will never return NULL */
264265
if (special && rn2(2))
265266
otmp = mk_artifact(otmp, A_NONE, 99, FALSE);
266267
/* usually increase stack size if stackable weapon */

Diff for: src/objnam.c

+21-3
Original file line numberDiff line numberDiff line change
@@ -1338,7 +1338,11 @@ doname_base(
13381338
Strcat(prefix, "uncursed ");
13391339
}
13401340

1341-
/* "a large trapped box" would perhaps be more correct */
1341+
/* "a large trapped box" would perhaps be more correct; [no!]
1342+
what about ``(obj->tknown && !obj->otrapped)''? shouldn't that
1343+
yield "a non-trapped large box"? (not "an untrapped large box");
1344+
TODO: this should be ``(Is_box(obj) || obj->otyp == TIN) && ...''
1345+
but at present there's no way to set obj->tknown for tins */
13421346
if (Is_box(obj) && obj->otrapped && obj->tknown && obj->dknown)
13431347
Strcat(prefix,"trapped ");
13441348
if (lknown && Is_box(obj)) {
@@ -2382,6 +2386,22 @@ Ysimple_name2(struct obj *obj)
23822386
return s;
23832387
}
23842388

2389+
/*
2390+
* FIXME:
2391+
* simpleonames(), ansimpleoname(), and thesimpleoname() need to
2392+
* know the beginning of the obuf[] they use so that they can
2393+
* guard against buffer overflow when pluralizing (is that an
2394+
* actual word?) or inserting "an" or "the".
2395+
*
2396+
* minimal_xname() returns a call to xname() which writes into
2397+
* the middle of its obuf[] then backs up to accomodate a prefix,
2398+
* so BUFSZ is not a reliable limit for the length of the result.
2399+
*
2400+
* [Overflow likely moot. Since the formatted object name has
2401+
* user-supplied name suppressed, the length is sure to be short
2402+
* enough to added plural suffix or "an" or "the" prefix.]
2403+
*/
2404+
23852405
/* "scroll" or "scrolls" */
23862406
char *
23872407
simpleonames(struct obj *obj)
@@ -2407,8 +2427,6 @@ ansimpleoname(struct obj *obj)
24072427
char *obufp, *simpleoname = simpleonames(obj);
24082428
int otyp = obj->otyp;
24092429

2410-
if (strlen(simpleoname) > BUFSZ - sizeof "the ")
2411-
simpleoname[sizeof "the "] = '\0';
24122430
/* prefix with "the" if a unique item, or a fake one imitating same,
24132431
has been formatted with its actual name (we let minimal_xname() handle
24142432
any `known' and `dknown' checking necessary) */

Diff for: src/pray.c

+1
Original file line numberDiff line numberDiff line change
@@ -1793,6 +1793,7 @@ bestow_artifact(uchar max_giftvalue)
17931793

17941794
if (do_bestow) {
17951795
struct obj *otmp;
1796+
/* mk_artifact() with NULL obj and a_align() arg can return NULL */
17961797
otmp = mk_artifact((struct obj *) 0, a_align(u.ux, u.uy),
17971798
max_giftvalue, TRUE);
17981799
if (otmp) {

Diff for: src/restore.c

+4
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,10 @@ restmon(NHFILE *nhfp, struct monst *mtmp)
365365
newedog(mtmp);
366366
if (nhfp->structlevel)
367367
Mread(nhfp->fd, EDOG(mtmp), sizeof (struct edog));
368+
/* sanity check to prevent rn2(0) */
369+
if (EDOG(mtmp)->apport <= 0) {
370+
EDOG(mtmp)->apport = 1;
371+
}
368372
}
369373
/* mcorpsenm - obj->corpsenm for mimic posing as corpse or
370374
statue (inline int rather than pointer to something) */

Diff for: sys/share/pmatchregex.c

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* NetHack 3.7 pmatchregex.c $NHDT-Date: 1596498285 2020/08/03 23:44:45 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.4 $ */
1+
/* NetHack 3.7 pmatchregex.c $NHDT-Date: 1737691300 2025/01/23 20:01:40 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.10 $ */
22
/* Copyright (c) Sean Hunt 2015. */
33
/* NetHack may be freely redistributed. See license for details. */
44

@@ -59,11 +59,11 @@ regex_match(const char *s, struct nhregex *re)
5959
void
6060
regex_free(struct nhregex *re)
6161
{
62-
if (re) {
63-
if (re->pat)
64-
free((genericptr_t) re->pat);
65-
free((genericptr_t) re);
66-
}
62+
assert(re != NULL); /* regex_free() is declared with NONNULLPTR1 */
63+
64+
if (re->pat)
65+
free((genericptr_t) re->pat);
66+
free((genericptr_t) re);
6767
}
6868

6969
/*pmatchregex.c*/

Diff for: win/curses/cursdial.c

+7-9
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,6 @@ curses_ext_cmd(void)
449449
letter = pgetchar(); /* pgetchar(cmd.c) implements do-again */
450450
curs_set(0);
451451
prompt_width = (int) strlen(cur_choice);
452-
matches = 0;
453452

454453
if (letter == '\033' || letter == ERR) {
455454
ret = -1;
@@ -667,7 +666,7 @@ curs_pad_menu(
667666
boolean do_pad UNUSED)
668667
{
669668
nhmenu_item *menu_item_ptr;
670-
int numpages = current_menu->num_pages;
669+
int numpages;
671670

672671
/* caller has already called menu_win_size() */
673672
menu_determine_pages(current_menu); /* sets 'menu->num_pages' */
@@ -942,7 +941,7 @@ menu_is_multipage(nhmenu *menu, int width, int height)
942941
int curline = 0, accel_per_page = 0;
943942
nhmenu_item *menu_item_ptr = menu->entries;
944943

945-
if (*menu->prompt) {
944+
if (menu->prompt && *menu->prompt) {
946945
curline += curses_num_lines(menu->prompt, width) + 1;
947946
}
948947

@@ -978,13 +977,12 @@ menu_determine_pages(nhmenu *menu)
978977
int tmpline, num_lines, accel_per_page;
979978
int curline = 0;
980979
int page_num = 1;
981-
nhmenu_item *menu_item_ptr = menu->entries;
980+
nhmenu_item *menu_item_ptr;
982981
int width = menu->width;
983982
int height = menu->height;
984983
int page_end = height;
985984

986-
987-
if (*menu->prompt) {
985+
if (menu->prompt && *menu->prompt) {
988986
curline += curses_num_lines(menu->prompt, width) + 1;
989987
}
990988
tmpline = curline;
@@ -1032,6 +1030,7 @@ menu_win_size(nhmenu *menu)
10321030
int maxheaderwidth = menu->prompt ? (int) strlen(menu->prompt) : 0;
10331031
nhmenu_item *menu_item_ptr, *last_item_ptr = NULL;
10341032

1033+
#if 0 /* maxwidth is set below, so the value calculated here isn't used */
10351034
if (program_state.gameover) {
10361035
/* for final inventory disclosure, use full width */
10371036
maxwidth = term_cols - 2; /* +2: borders assumed */
@@ -1046,6 +1045,7 @@ menu_win_size(nhmenu *menu)
10461045
if ((term_cols / 2) > maxwidth)
10471046
maxwidth = (term_cols / 2); /* Half the screen */
10481047
}
1048+
#endif
10491049
maxheight = menu_max_height();
10501050

10511051
/* First, determine the width of the longest menu entry */
@@ -1475,8 +1475,6 @@ curs_nonselect_menu_action(
14751475
}
14761476
menu_item_ptr = menu_item_ptr->next_item;
14771477
}
1478-
1479-
menu_item_ptr = menu->entries;
14801478
break;
14811479
} /* case MENU_SEARCH */
14821480
default:
@@ -1500,7 +1498,7 @@ menu_get_selections(WINDOW *win, nhmenu *menu, int how)
15001498
int num_selected = 0;
15011499
boolean dismiss = FALSE;
15021500
char selectors[256], groupaccels[256];
1503-
nhmenu_item *menu_item_ptr = menu->entries;
1501+
nhmenu_item *menu_item_ptr;
15041502

15051503
activemenu = win;
15061504
menu_display_page(win, menu, curpage, selectors, groupaccels);

0 commit comments

Comments
 (0)