1 /* NetHack 3.6 shknam.c $NHDT-Date: 1454485432 2016/02/03 07:43:52 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.41 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Robert Patrick Rankin, 2011. */
4 /* NetHack may be freely redistributed. See license for details. */
6 /* shknam.c -- initialize a shop */
8 /* JNetHack Copyright */
9 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
10 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2020 */
11 /* JNetHack may be freely redistributed. See license for details. */
15 STATIC_DCL boolean FDECL(stock_room_goodpos, (struct mkroom *, int, int, int, int));
16 STATIC_DCL boolean FDECL(veggy_item, (struct obj * obj, int));
17 STATIC_DCL int NDECL(shkveg);
18 STATIC_DCL void FDECL(mkveggy_at, (int, int));
19 STATIC_DCL void FDECL(mkshobj_at, (const struct shclass *, int, int,
21 STATIC_DCL void FDECL(nameshk, (struct monst *, const char *const *));
22 STATIC_DCL int FDECL(shkinit, (const struct shclass *, struct mkroom *));
24 #define VEGETARIAN_CLASS (MAXOCLASSES + 1)
28 * dash - female, personal name
29 * underscore _ female, general name
30 * plus + male, personal name
31 * vertical bar | male, general name (implied for most of shktools)
32 * equals = gender not specified, personal name
34 * Personal names do not receive the honorific prefix "Mr." or "Ms.".
37 static const char *const shkliquors[] = {
39 "Njezjin", "Tsjernigof", "Ossipewsk", "Gorlowka",
43 "Konosja", "Weliki Oestjoeg", "Syktywkar", "Sablja", "Narodnaja", "Kyzyl",
45 "Walbrzych", "Swidnica", "Klodzko", "Raciborz", "Gliwice", "Brzeg",
46 "Krnov", "Hradec Kralove",
48 "Leuk", "Brig", "Brienz", "Thun", "Sarnen", "Burglen", "Elm", "Flims",
49 "Vals", "Schuls", "Zum Loch", 0
52 static const char *const shkbooks[] = {
54 "Skibbereen", "Kanturk", "Rath Luirc", "Ennistymon",
55 "Lahinch", "Kinnegad", "Lugnaquillia", "Enniscorthy",
56 "Gweebarra", "Kittamagh", "Nenagh", "Sneem",
57 "Ballingeary", "Kilgarvan", "Cahersiveen", "Glenbeigh",
58 "Kilmihil", "Kiltamagh", "Droichead Atha", "Inniscrone",
59 "Clonegal", "Lisnaskea", "Culdaff", "Dunfanaghy",
60 "Inishbofin", "Kesh", 0
63 static const char *const shkarmors[] = {
65 "Demirci", "Kalecik", "Boyabai", "Yildizeli", "Gaziantep",
66 "Siirt", "Akhalataki", "Tirebolu", "Aksaray", "Ermenak",
67 "Iskenderun", "Kadirli", "Siverek", "Pervari", "Malasgirt",
68 "Bayburt", "Ayancik", "Zonguldak", "Balya", "Tefenni",
69 "Artvin", "Kars", "Makharadze", "Malazgirt", "Midyat",
70 "Birecik", "Kirikkale", "Alaca", "Polatli", "Nallihan",
74 static const char *const shkwands[] = {
76 "Yr Wyddgrug", "Trallwng", "Mallwyd", "Pontarfynach", "Rhaeader",
77 "Llandrindod", "Llanfair-ym-muallt", "Y-Fenni", "Maesteg", "Rhydaman",
78 "Beddgelert", "Curig", "Llanrwst", "Llanerchymedd", "Caergybi",
80 "Nairn", "Turriff", "Inverurie", "Braemar", "Lochnagar", "Kerloch",
81 "Beinn a Ghlo", "Drumnadrochit", "Morven", "Uist", "Storr",
82 "Sgurr na Ciche", "Cannich", "Gairloch", "Kyleakin", "Dunvegan", 0
85 static const char *const shkrings[] = {
86 /* Hollandse familienamen */
87 "Feyfer", "Flugi", "Gheel", "Havic", "Haynin",
88 "Hoboken", "Imbyze", "Juyn", "Kinsky", "Massis",
89 "Matray", "Moy", "Olycan", "Sadelin", "Svaving",
90 "Tapper", "Terwen", "Wirix", "Ypey",
91 /* Skandinaviske navne */
92 "Rastegaisa", "Varjag Njarga", "Kautekeino", "Abisko", "Enontekis",
93 "Rovaniemi", "Avasaksa", "Haparanda", "Lulea", "Gellivare",
94 "Oeloe", "Kajaani", "Fauske", 0
97 static const char *const shkfoods[] = {
99 "Djasinga", "Tjibarusa", "Tjiwidej", "Pengalengan",
100 "Bandjar", "Parbalingga", "Bojolali", "Sarangan",
101 "Ngebel", "Djombang", "Ardjawinangun", "Berbek",
102 "Papar", "Baliga", "Tjisolok", "Siboga",
103 "Banjoewangi", "Trenggalek", "Karangkobar", "Njalindoeng",
104 "Pasawahan", "Pameunpeuk", "Patjitan", "Kediri",
105 "Pemboeang", "Tringanoe", "Makin", "Tipor",
106 "Semai", "Berhala", "Tegal", "Samoe",
110 static const char *const shkweapons[] = {
112 "Voulgezac", "Rouffiac", "Lerignac", "Touverac", "Guizengeard",
113 "Melac", "Neuvicq", "Vanzac", "Picq", "Urignac",
114 "Corignac", "Fleac", "Lonzac", "Vergt", "Queyssac",
115 "Liorac", "Echourgnac", "Cazelon", "Eypau", "Carignan",
116 "Monbazillac", "Jonzac", "Pons", "Jumilhac", "Fenouilledes",
117 "Laguiolet", "Saujon", "Eymoutiers", "Eygurande", "Eauze",
121 static const char *const shktools[] = {
123 "Ymla", "Eed-morra", "Elan Lapinski", "Cubask", "Nieb", "Bnowr Falr",
124 "Sperc", "Noskcirdneh", "Yawolloh", "Hyeghu", "Niskal", "Trahnil",
125 "Htargcm", "Enrobwem", "Kachzi Rellim", "Regien", "Donmyar", "Yelpur",
126 "Nosnehpets", "Stewe", "Renrut", "Senna Hut", "-Zlaw", "Nosalnef",
127 "Rewuorb", "Rellenk", "Yad", "Cire Htims", "Y-crad", "Nenilukah",
128 "Corsh", "Aned", "Dark Eery", "Niknar", "Lapu", "Lechaim",
129 "Rebrol-nek", "AlliWar Wickson", "Oguhmk", "Telloc Cyaj",
131 "Erreip", "Nehpets", "Mron", "Snivek", "Kahztiy",
137 "Nhoj-lee", "Evad\'kh", "Ettaw-noj", "Tsew-mot", "Ydna-s", "Yao-hang",
138 "Tonbar", "Kivenhoug", "Llardom",
141 "Falo", "Nosid-da\'r", "Ekim-p", "Noslo", "Yl-rednow", "Mured-oog",
151 "Lez-tneg", "Ytnu-haled",
156 static const char *const shklight[] = {
158 "Zarnesti", "Slanic", "Nehoiasu", "Ludus", "Sighisoara", "Nisipitu",
159 "Razboieni", "Bicaz", "Dorohoi", "Vaslui", "Fetesti", "Tirgu Neamt",
160 "Babadag", "Zimnicea", "Zlatna", "Jiu", "Eforie", "Mamaia",
162 "Silistra", "Tulovo", "Panagyuritshte", "Smolyan", "Kirklareli", "Pernik",
163 "Lom", "Haskovo", "Dobrinishte", "Varvara", "Oryahovo", "Troyan",
164 "Lovech", "Sliven", 0
167 static const char *const shkgeneral[] = {
169 "Hebiwerie", "Possogroenoe", "Asidonhopo", "Manlobbi",
170 "Adjama", "Pakka Pakka", "Kabalebo", "Wonotobo",
171 "Akalapi", "Sipaliwini",
173 "Annootok", "Upernavik", "Angmagssalik",
175 "Aklavik", "Inuvik", "Tuktoyaktuk", "Chicoutimi",
176 "Ouiatchouane", "Chibougamau", "Matagami", "Kipawa",
177 "Kinojevis", "Abitibi", "Maganasipi",
179 "Akureyri", "Kopasker", "Budereyri", "Akranes",
180 "Bordeyri", "Holmavik", 0
183 static const char *const shkhealthfoods[] = {
185 "Ga'er", "Zhangmu", "Rikaze", "Jiangji", "Changdu",
186 "Linzhi", "Shigatse", "Gyantse", "Ganden", "Tsurphu",
187 "Lhasa", "Tsedong", "Drepung",
189 "=Azura", "=Blaze", "=Breanna", "=Breezy", "=Dharma",
190 "=Feather", "=Jasmine", "=Luna", "=Melody", "=Moonjava",
191 "=Petal", "=Rhiannon", "=Starla", "=Tranquilla", "=Windsong",
192 "=Zennia", "=Zoe", "=Zora", 0
196 * To add new shop types, all that is necessary is to edit the shtypes[]
197 * array. See mkroom.h for the structure definition. Typically, you'll
198 * have to lower some or all of the probability fields in old entries to
199 * free up some percentage for the new type.
201 * The placement type field is not yet used but will be in the near future.
203 * The iprobs array in each entry defines the probabilities for various kinds
204 * of objects to be present in the given shop type. You can associate with
205 * each percentage either a generic object type (represented by one of the
206 * *_CLASS macros) or a specific object (represented by an onames.h define).
207 * In the latter case, prepend it with a unary minus so the code can know
208 * (by testing the sign) whether to use mkobj() or mksobj().
210 const struct shclass shtypes[] = {
218 { { 100, RANDOM_CLASS },
226 { "used armor dealership",
228 { "
\92\86\8cÃ
\8aZ
\8f¤
\89ï",
232 { { 90, ARMOR_CLASS },
233 { 10, WEAPON_CLASS },
240 { "second-hand bookstore",
246 { { 90, SCROLL_CLASS },
247 { 10, SPBOOK_CLASS },
256 {"
\82¨
\8eð
\82Ì
\95S
\89Ý
\93X",
260 { { 100, POTION_CLASS },
268 { "antique weapons outlet",
270 { "
\8cÃ
\95\90\8aí
\90ê
\96å
\8f¬
\94\84\93X",
274 { { 90, WEAPON_CLASS },
288 { { 83, FOOD_CLASS },
289 { 5, -POT_FRUIT_JUICE },
302 { { 85, RING_CLASS },
310 { "quality apparel and accessories",
312 { "
\82¨
\83V
\83\83\83\8c\82È
\97m
\95i
\93X",
316 { { 90, WAND_CLASS },
317 { 5, -LEATHER_GLOVES },
328 { { 100, TOOL_CLASS },
338 { "
\8c¶
\82Ì
\96{
\89®",
342 { { 90, SPBOOK_CLASS },
343 { 10, SCROLL_CLASS },
350 { "health food store",
352 { "
\8c\92\8dN
\90H
\95i
\82Ì
\93X",
356 { { 70, VEGETARIAN_CLASS },
357 { 20, -POT_FRUIT_JUICE },
359 { 3, -POT_FULL_HEALING },
360 { 2, -SCR_FOOD_DETECTION },
361 { 1, -LUMP_OF_ROYAL_JELLY } },
363 /* Shops below this point are "unique". That is they must all have a
364 * probability of zero. They are only created via the special level
374 { { 30, -WAX_CANDLE },
375 { 48, -TALLOW_CANDLE },
376 { 5, -BRASS_LANTERN },
386 { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
391 /* validate shop probabilities; otherwise incorrect local changes could
392 end up provoking infinite loops or wild subscripts fetching garbage */
394 init_shop_selection()
396 register int i, j, item_prob, shop_prob;
398 for (shop_prob = 0, i = 0; i < SIZE(shtypes); i++) {
399 shop_prob += shtypes[i].prob;
400 for (item_prob = 0, j = 0; j < SIZE(shtypes[0].iprobs); j++)
401 item_prob += shtypes[i].iprobs[j].iprob;
402 if (item_prob != 100)
403 panic("item probabilities total to %d for %s shops!",
404 item_prob, shtypes[i].name);
406 if (shop_prob != 100)
407 panic("shop probabilities total to %d!", shop_prob);
411 /* decide whether an object or object type is considered vegetarian;
412 for types, items which might go either way are assumed to be veggy */
414 veggy_item(obj, otyp)
416 int otyp; /* used iff obj is null */
422 /* actual object; will check tin content and corpse species */
423 otyp = (int) obj->otyp;
424 oclass = obj->oclass;
425 corpsenm = obj->corpsenm;
427 /* just a type; caller will have to handle tins and corpses */
428 oclass = objects[otyp].oc_class;
429 corpsenm = PM_LICHEN; /* veggy standin */
432 if (oclass == FOOD_CLASS) {
433 if (objects[otyp].oc_material == VEGGY || otyp == EGG)
435 if (otyp == TIN && corpsenm == NON_PM) /* implies obj is non-null */
436 return (boolean) (obj->spe == 1); /* 0 = empty, 1 = spinach */
437 if (otyp == TIN || otyp == CORPSE)
438 return (boolean) (corpsenm >= LOW_PM
439 && vegetarian(&mons[corpsenm]));
447 int i, j, maxprob, prob;
448 char oclass = FOOD_CLASS;
452 ok[0] = 0; /* lint suppression */
453 for (i = bases[(int) oclass]; i < NUM_OBJECTS; ++i) {
454 if (objects[i].oc_class != oclass)
457 if (veggy_item((struct obj *) 0, i)) {
459 maxprob += objects[i].oc_prob;
463 panic("shkveg no veggy objects");
468 while ((prob -= objects[i].oc_prob) > 0) {
473 if (objects[i].oc_class != oclass || !OBJ_NAME(objects[i]))
474 panic("shkveg probtype error, oclass=%d i=%d", (int) oclass, i);
478 /* make a random item for health food store */
483 struct obj *obj = mksobj_at(shkveg(), sx, sy, TRUE, TRUE);
485 if (obj && obj->otyp == TIN)
486 set_tin_variety(obj, HEALTHY_TIN);
490 /* make an object of the appropriate type for a shop square */
492 mkshobj_at(shp, sx, sy, mkspecl)
493 const struct shclass *shp;
498 struct permonst *ptr;
503 if (mkspecl && (!strcmp(shp->name, "rare books")
504 || !strcmp(shp->name, "second-hand bookstore"))) {
506 if (mkspecl && (!strcmp(shp->name, "
\8c¶
\82Ì
\96{
\89®")
507 || !strcmp(shp->name, "
\8cÃ
\8f\91\93X"))) {
509 struct obj *novel = mksobj_at(SPE_NOVEL, sx, sy, FALSE, FALSE);
512 context.tribute.bookstock = TRUE;
516 if (rn2(100) < depth(&u.uz) && !MON_AT(sx, sy)
517 && (ptr = mkclass(S_MIMIC, 0)) != 0
518 && (mtmp = makemon(ptr, sx, sy, NO_MM_FLAGS)) != 0) {
519 /* note: makemon will set the mimic symbol to a shop item */
520 if (rn2(10) >= depth(&u.uz)) {
521 mtmp->m_ap_type = M_AP_OBJECT;
522 mtmp->mappearance = STRANGE_OBJECT;
525 atype = get_shop_item((int) (shp - shtypes));
526 if (atype == VEGETARIAN_CLASS)
529 (void) mksobj_at(-atype, sx, sy, TRUE, TRUE);
531 (void) mkobj_at(atype, sx, sy, TRUE);
535 /* extract a shopkeeper name for the given shop type */
539 const char *const *nlp;
541 int i, trycnt, names_avail;
542 const char *shname = 0;
547 if (nlp == shkfoods && In_mines(&u.uz) && Role_if(PM_MONK)
548 && (sptr = Is_special(&u.uz)) != 0 && sptr->flags.town) {
549 /* special-case override for minetown food store for monks */
550 nlp = shkhealthfoods;
553 if (nlp == shklight && In_mines(&u.uz) && (sptr = Is_special(&u.uz)) != 0
554 && sptr->flags.town) {
555 /* special-case minetown lighting shk */
559 /* We want variation from game to game, without needing the save
560 and restore support which would be necessary for randomization;
561 try not to make too many assumptions about time_t's internals;
562 use ledger_no rather than depth to keep mine town distinct. */
563 int nseed = (int) ((long) ubirthday / 257L);
565 name_wanted = ledger_no(&u.uz) + (nseed % 13) - (nseed % 5);
567 name_wanted += (13 + 5);
568 shk->female = name_wanted & 1;
570 for (names_avail = 0; nlp[names_avail]; names_avail++)
573 for (trycnt = 0; trycnt < 50; trycnt++) {
574 if (nlp == shktools) {
575 shname = shktools[rn2(names_avail)];
576 shk->female = 0; /* reversed below for '_' prefix */
577 } else if (name_wanted < names_avail) {
578 shname = nlp[name_wanted];
579 } else if ((i = rn2(names_avail)) != 0) {
581 } else if (nlp != shkgeneral) {
582 nlp = shkgeneral; /* try general names */
583 for (names_avail = 0; nlp[names_avail]; names_avail++)
585 continue; /* next `trycnt' iteration */
587 shname = shk->female ? "-Lucrezia" : "+Dirk";
589 if (*shname == '_' || *shname == '-')
591 else if (*shname == '|' || *shname == '+')
594 /* is name already in use on this level? */
595 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
596 if (DEADMONSTER(mtmp) || (mtmp == shk) || !mtmp->isshk)
598 if (strcmp(ESHK(mtmp)->shknam, shname))
603 break; /* new name */
606 (void) strncpy(ESHK(shk)->shknam, shname, PL_NSIZ);
607 ESHK(shk)->shknam[PL_NSIZ - 1] = 0;
615 mtmp->mextra = newmextra();
617 ESHK(mtmp) = (struct eshk *) alloc(sizeof(struct eshk));
618 (void) memset((genericptr_t) ESHK(mtmp), 0, sizeof(struct eshk));
619 ESHK(mtmp)->bill_p = (struct bill_x *) 0;
626 if (mtmp->mextra && ESHK(mtmp)) {
627 free((genericptr_t) ESHK(mtmp));
628 ESHK(mtmp) = (struct eshk *) 0;
633 /* create a new shopkeeper in the given room */
636 const struct shclass *shp;
637 struct mkroom *sroom;
639 register int sh, sx, sy;
643 /* place the shopkeeper in the given room */
648 /* check that the shopkeeper placement is sane */
649 if (sroom->irregular) {
650 int rmno = (int) ((sroom - rooms) + ROOMOFFSET);
652 if (isok(sx - 1, sy) && !levl[sx - 1][sy].edge
653 && (int) levl[sx - 1][sy].roomno == rmno)
655 else if (isok(sx + 1, sy) && !levl[sx + 1][sy].edge
656 && (int) levl[sx + 1][sy].roomno == rmno)
658 else if (isok(sx, sy - 1) && !levl[sx][sy - 1].edge
659 && (int) levl[sx][sy - 1].roomno == rmno)
661 else if (isok(sx, sy + 1) && !levl[sx][sy + 1].edge
662 && (int) levl[sx][sy + 1].roomno == rmno)
666 } else if (sx == sroom->lx - 1) {
668 } else if (sx == sroom->hx + 1) {
670 } else if (sy == sroom->ly - 1) {
672 } else if (sy == sroom->hy + 1) {
677 /* Said to happen sometimes, but I have never seen it. */
678 /* Supposedly fixed by fdoor change in mklev.c */
680 register int j = sroom->doorct;
682 pline("Where is shopdoor?");
683 pline("Room at (%d,%d),(%d,%d).", sroom->lx, sroom->ly, sroom->hx,
685 pline("doormax=%d doorct=%d fdoor=%d", doorindex, sroom->doorct,
688 pline("door [%d,%d]", doors[sh].x, doors[sh].y);
691 display_nhwindow(WIN_MESSAGE, FALSE);
698 (void) rloc(m_at(sx, sy), FALSE); /* insurance */
700 /* now initialize the shopkeeper monster structure */
701 if (!(shk = makemon(&mons[PM_SHOPKEEPER], sx, sy, MM_ESHK)))
703 eshkp = ESHK(shk); /* makemon(...,MM_ESHK) allocates this */
704 shk->isshk = shk->mpeaceful = 1;
707 shk->mtrapseen = ~0; /* we know all the traps already */
708 eshkp->shoproom = (schar) ((sroom - rooms) + ROOMOFFSET);
709 sroom->resident = shk;
710 eshkp->shoptype = sroom->rtype;
711 assign_level(&eshkp->shoplevel, &u.uz);
712 eshkp->shd = doors[sh];
715 eshkp->robbed = eshkp->credit = eshkp->debit = eshkp->loan = 0L;
716 eshkp->following = eshkp->surcharge = eshkp->dismiss_kops = FALSE;
717 eshkp->billct = eshkp->visitct = 0;
718 eshkp->bill_p = (struct bill_x *) 0;
719 eshkp->customer[0] = '\0';
720 mkmonmoney(shk, 1000L + 30L * (long) rnd(100)); /* initial capital */
721 if (shp->shknms == shkrings)
722 (void) mongets(shk, TOUCHSTONE);
723 nameshk(shk, shp->shknms);
729 stock_room_goodpos(sroom, rmno, sh, sx, sy)
730 struct mkroom *sroom;
733 if (sroom->irregular) {
734 if (levl[sx][sy].edge
735 || (int) levl[sx][sy].roomno != rmno
736 || distmin(sx, sy, doors[sh].x, doors[sh].y) <= 1)
738 } else if ((sx == sroom->lx && doors[sh].x == sx - 1)
739 || (sx == sroom->hx && doors[sh].x == sx + 1)
740 || (sy == sroom->ly && doors[sh].y == sy - 1)
741 || (sy == sroom->hy && doors[sh].y == sy + 1))
746 /* stock a newly-created room with objects */
748 stock_room(shp_indx, sroom)
750 register struct mkroom *sroom;
753 * Someday soon we'll dispatch on the shdist field of shclass to do
754 * different placements in this routine. Currently it only supports
755 * shop-style placement (all squares except a row nearest the first
759 int stockcount = 0, specialspot = 0;
761 int rmno = (int) ((sroom - rooms) + ROOMOFFSET);
762 const struct shclass *shp = &shtypes[shp_indx];
764 /* first, try to place a shopkeeper in the room */
765 if ((sh = shkinit(shp, sroom)) < 0)
768 /* make sure no doorways without doors, and no trapped doors, in shops */
769 sx = doors[sroom->fdoor].x;
770 sy = doors[sroom->fdoor].y;
771 if (levl[sx][sy].doormask == D_NODOOR) {
772 levl[sx][sy].doormask = D_ISOPEN;
775 if (levl[sx][sy].typ == SDOOR) {
776 cvt_sdoor_to_door(&levl[sx][sy]); /* .typ = DOOR */
779 if (levl[sx][sy].doormask & D_TRAPPED)
780 levl[sx][sy].doormask = D_LOCKED;
782 if (levl[sx][sy].doormask == D_LOCKED) {
783 register int m = sx, n = sy;
785 if (inside_shop(sx + 1, sy))
787 else if (inside_shop(sx - 1, sy))
789 if (inside_shop(sx, sy + 1))
791 else if (inside_shop(sx, sy - 1))
794 Sprintf(buf, "Closed for inventory");
796 Sprintf(buf, "
\92I
\89µ
\82µ
\82Ì
\82½
\82ß
\95Â
\93X");
797 make_engr_at(m, n, buf, 0L, DUST);
800 if (context.tribute.enabled && !context.tribute.bookstock) {
802 * Out of the number of spots where we're actually
803 * going to put stuff, randomly single out one in particular.
805 for (sx = sroom->lx; sx <= sroom->hx; sx++)
806 for (sy = sroom->ly; sy <= sroom->hy; sy++)
807 if (stock_room_goodpos(sroom, rmno, sh, sx,sy))
809 specialspot = rnd(stockcount);
813 for (sx = sroom->lx; sx <= sroom->hx; sx++)
814 for (sy = sroom->ly; sy <= sroom->hy; sy++)
815 if (stock_room_goodpos(sroom, rmno, sh, sx,sy)) {
817 mkshobj_at(shp, sx, sy,
818 ((stockcount) && (stockcount == specialspot)));
822 * Special monster placements (if any) should go here: that way,
823 * monsters will sit on top of objects and not the other way around.
826 level.flags.has_shop = TRUE;
829 /* does shkp's shop stock this item type? */
835 int i, shp_indx = ESHK(shkp)->shoptype - SHOPBASE;
836 const struct shclass *shp = &shtypes[shp_indx];
838 if (shp->symb == RANDOM_CLASS)
840 for (i = 0; i < SIZE(shtypes[0].iprobs) && shp->iprobs[i].iprob; i++) {
841 /* pseudo-class needs special handling */
842 if (shp->iprobs[i].itype == VEGETARIAN_CLASS) {
843 if (veggy_item(obj, 0))
845 } else if ((shp->iprobs[i].itype < 0)
846 ? shp->iprobs[i].itype == -obj->otyp
847 : shp->iprobs[i].itype == obj->oclass)
854 /* positive value: class; negative value: specific object type */
859 const struct shclass *shp = shtypes + type;
862 /* select an appropriate object type at random */
863 for (j = rnd(100), i = 0; (j -= shp->iprobs[i].iprob) > 0; i++)
866 return shp->iprobs[i].itype;
869 /* version of shkname() for beginning of sentence */
874 char *nam = shkname(mtmp);
876 /* 'nam[]' is almost certainly already capitalized, but be sure */
877 nam[0] = highc(nam[0]);
881 /* shopkeeper's name, without any visibility constraint; if hallucinating,
882 will yield some other shopkeeper's name (not necessarily one residing
883 in the current game's dungeon, or who keeps same type of shop) */
889 unsigned save_isshk = mtmp->isshk;
891 mtmp->isshk = 0; /* don't want mon_nam() calling shkname() */
892 /* get a modifiable name buffer along with fallback result */
893 nam = noit_mon_nam(mtmp);
894 mtmp->isshk = save_isshk;
897 impossible("shkname: \"%s\" is not a shopkeeper.", nam);
898 } else if (!has_eshk(mtmp)) {
899 panic("shkname: shopkeeper \"%s\" lacks 'eshk' data.", nam);
901 const char *shknm = ESHK(mtmp)->shknam;
903 if (Hallucination && !program_state.gameover) {
904 const char *const *nlp;
907 /* count the number of non-unique shop types;
908 pick one randomly, ignoring shop generation probabilities;
909 pick a name at random from that shop type's list */
910 for (num = 0; num < SIZE(shtypes); num++)
911 if (shtypes[num].prob == 0)
914 nlp = shtypes[rn2(num)].shknms;
915 for (num = 0; nlp[num]; num++)
918 shknm = nlp[rn2(num)];
921 /* strip prefix if present */
930 shkname_is_pname(mtmp)
933 const char *shknm = ESHK(mtmp)->shknam;
935 return (boolean) (*shknm == '-' || *shknm == '+' || *shknm == '=');
939 is_izchak(shkp, override_hallucination)
941 boolean override_hallucination;
945 if (Hallucination && !override_hallucination)
949 /* outside of town, Izchak becomes just an ordinary shopkeeper */
950 if (!in_town(shkp->mx, shkp->my))
952 shknm = ESHK(shkp)->shknam;
953 /* skip "+" prefix */
956 return (boolean) !strcmp(shknm, "Izchak");