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-2018 */
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);
651 if (isok(sx - 1, sy) && !levl[sx - 1][sy].edge
652 && (int) levl[sx - 1][sy].roomno == rmno)
654 else if (isok(sx + 1, sy) && !levl[sx + 1][sy].edge
655 && (int) levl[sx + 1][sy].roomno == rmno)
657 else if (isok(sx, sy - 1) && !levl[sx][sy - 1].edge
658 && (int) levl[sx][sy - 1].roomno == rmno)
660 else if (isok(sx, sy + 1) && !levl[sx][sy + 1].edge
661 && (int) levl[sx][sy + 1].roomno == rmno)
665 } else if (sx == sroom->lx - 1)
667 else if (sx == sroom->hx + 1)
669 else if (sy == sroom->ly - 1)
671 else if (sy == sroom->hy + 1)
676 /* Said to happen sometimes, but I have never seen it. */
677 /* Supposedly fixed by fdoor change in mklev.c */
679 register int j = sroom->doorct;
681 pline("Where is shopdoor?");
682 pline("Room at (%d,%d),(%d,%d).", sroom->lx, sroom->ly, sroom->hx,
684 pline("doormax=%d doorct=%d fdoor=%d", doorindex, sroom->doorct,
687 pline("door [%d,%d]", doors[sh].x, doors[sh].y);
690 display_nhwindow(WIN_MESSAGE, FALSE);
697 (void) rloc(m_at(sx, sy), FALSE); /* insurance */
699 /* now initialize the shopkeeper monster structure */
700 if (!(shk = makemon(&mons[PM_SHOPKEEPER], sx, sy, MM_ESHK)))
702 eshkp = ESHK(shk); /* makemon(...,MM_ESHK) allocates this */
703 shk->isshk = shk->mpeaceful = 1;
706 shk->mtrapseen = ~0; /* we know all the traps already */
707 eshkp->shoproom = (schar) ((sroom - rooms) + ROOMOFFSET);
708 sroom->resident = shk;
709 eshkp->shoptype = sroom->rtype;
710 assign_level(&eshkp->shoplevel, &u.uz);
711 eshkp->shd = doors[sh];
714 eshkp->robbed = eshkp->credit = eshkp->debit = eshkp->loan = 0L;
715 eshkp->following = eshkp->surcharge = eshkp->dismiss_kops = FALSE;
716 eshkp->billct = eshkp->visitct = 0;
717 eshkp->bill_p = (struct bill_x *) 0;
718 eshkp->customer[0] = '\0';
719 mkmonmoney(shk, 1000L + 30L * (long) rnd(100)); /* initial capital */
720 if (shp->shknms == shkrings)
721 (void) mongets(shk, TOUCHSTONE);
722 nameshk(shk, shp->shknms);
728 stock_room_goodpos(sroom, rmno, sh, sx, sy)
729 struct mkroom *sroom;
732 if (sroom->irregular) {
733 if (levl[sx][sy].edge
734 || (int) levl[sx][sy].roomno != rmno
735 || distmin(sx, sy, doors[sh].x, doors[sh].y) <= 1)
737 } else if ((sx == sroom->lx && doors[sh].x == sx - 1)
738 || (sx == sroom->hx && doors[sh].x == sx + 1)
739 || (sy == sroom->ly && doors[sh].y == sy - 1)
740 || (sy == sroom->hy && doors[sh].y == sy + 1))
745 /* stock a newly-created room with objects */
747 stock_room(shp_indx, sroom)
749 register struct mkroom *sroom;
752 * Someday soon we'll dispatch on the shdist field of shclass to do
753 * different placements in this routine. Currently it only supports
754 * shop-style placement (all squares except a row nearest the first
758 int stockcount = 0, specialspot = 0;
760 int rmno = (int) ((sroom - rooms) + ROOMOFFSET);
761 const struct shclass *shp = &shtypes[shp_indx];
763 /* first, try to place a shopkeeper in the room */
764 if ((sh = shkinit(shp, sroom)) < 0)
767 /* make sure no doorways without doors, and no trapped doors, in shops */
768 sx = doors[sroom->fdoor].x;
769 sy = doors[sroom->fdoor].y;
770 if (levl[sx][sy].doormask == D_NODOOR) {
771 levl[sx][sy].doormask = D_ISOPEN;
774 if (levl[sx][sy].typ == SDOOR) {
775 cvt_sdoor_to_door(&levl[sx][sy]); /* .typ = DOOR */
778 if (levl[sx][sy].doormask & D_TRAPPED)
779 levl[sx][sy].doormask = D_LOCKED;
781 if (levl[sx][sy].doormask == D_LOCKED) {
782 register int m = sx, n = sy;
784 if (inside_shop(sx + 1, sy))
786 else if (inside_shop(sx - 1, sy))
788 if (inside_shop(sx, sy + 1))
790 else if (inside_shop(sx, sy - 1))
793 Sprintf(buf, "Closed for inventory");
795 Sprintf(buf, "
\92I
\89µ
\82µ
\82Ì
\82½
\82ß
\95Â
\93X");
796 make_engr_at(m, n, buf, 0L, DUST);
799 if (context.tribute.enabled && !context.tribute.bookstock) {
801 * Out of the number of spots where we're actually
802 * going to put stuff, randomly single out one in particular.
804 for (sx = sroom->lx; sx <= sroom->hx; sx++)
805 for (sy = sroom->ly; sy <= sroom->hy; sy++)
806 if (stock_room_goodpos(sroom, rmno, sh, sx,sy))
808 specialspot = rnd(stockcount);
812 for (sx = sroom->lx; sx <= sroom->hx; sx++)
813 for (sy = sroom->ly; sy <= sroom->hy; sy++)
814 if (stock_room_goodpos(sroom, rmno, sh, sx,sy)) {
816 mkshobj_at(shp, sx, sy,
817 ((stockcount) && (stockcount == specialspot)));
821 * Special monster placements (if any) should go here: that way,
822 * monsters will sit on top of objects and not the other way around.
825 level.flags.has_shop = TRUE;
828 /* does shkp's shop stock this item type? */
834 int i, shp_indx = ESHK(shkp)->shoptype - SHOPBASE;
835 const struct shclass *shp = &shtypes[shp_indx];
837 if (shp->symb == RANDOM_CLASS)
839 for (i = 0; i < SIZE(shtypes[0].iprobs) && shp->iprobs[i].iprob; i++) {
840 /* pseudo-class needs special handling */
841 if (shp->iprobs[i].itype == VEGETARIAN_CLASS) {
842 if (veggy_item(obj, 0))
844 } else if ((shp->iprobs[i].itype < 0)
845 ? shp->iprobs[i].itype == -obj->otyp
846 : shp->iprobs[i].itype == obj->oclass)
853 /* positive value: class; negative value: specific object type */
858 const struct shclass *shp = shtypes + type;
861 /* select an appropriate object type at random */
862 for (j = rnd(100), i = 0; (j -= shp->iprobs[i].iprob) > 0; i++)
865 return shp->iprobs[i].itype;
868 /* version of shkname() for beginning of sentence */
873 char *nam = shkname(mtmp);
875 /* 'nam[]' is almost certainly already capitalized, but be sure */
876 nam[0] = highc(nam[0]);
880 /* shopkeeper's name, without any visibility constraint; if hallucinating,
881 will yield some other shopkeeper's name (not necessarily one residing
882 in the current game's dungeon, or who keeps same type of shop) */
888 unsigned save_isshk = mtmp->isshk;
890 mtmp->isshk = 0; /* don't want mon_nam() calling shkname() */
891 /* get a modifiable name buffer along with fallback result */
892 nam = noit_mon_nam(mtmp);
893 mtmp->isshk = save_isshk;
896 impossible("shkname: \"%s\" is not a shopkeeper.", nam);
897 } else if (!has_eshk(mtmp)) {
898 panic("shkname: shopkeeper \"%s\" lacks 'eshk' data.", nam);
900 const char *shknm = ESHK(mtmp)->shknam;
902 if (Hallucination && !program_state.gameover) {
903 const char *const *nlp;
906 /* count the number of non-unique shop types;
907 pick one randomly, ignoring shop generation probabilities;
908 pick a name at random from that shop type's list */
909 for (num = 0; num < SIZE(shtypes); num++)
910 if (shtypes[num].prob == 0)
913 nlp = shtypes[rn2(num)].shknms;
914 for (num = 0; nlp[num]; num++)
917 shknm = nlp[rn2(num)];
920 /* strip prefix if present */
929 shkname_is_pname(mtmp)
932 const char *shknm = ESHK(mtmp)->shknam;
934 return (boolean) (*shknm == '-' || *shknm == '+' || *shknm == '=');
938 is_izchak(shkp, override_hallucination)
940 boolean override_hallucination;
944 if (Hallucination && !override_hallucination)
948 /* outside of town, Izchak becomes just an ordinary shopkeeper */
949 if (!in_town(shkp->mx, shkp->my))
951 shknm = ESHK(shkp)->shknam;
952 /* skip "+" prefix */
955 return (boolean) !strcmp(shknm, "Izchak");