1 /* NetHack 3.6 shknam.c $NHDT-Date: 1448094342 2015/11/21 08:25:42 $ $NHDT-Branch: master $:$NHDT-Revision: 1.38 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 /* shknam.c -- initialize a shop */
7 /* JNetHack Copyright */
8 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
9 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2016 */
10 /* JNetHack may be freely redistributed. See license for details. */
14 STATIC_DCL boolean FDECL(veggy_item, (struct obj * obj, int));
15 STATIC_DCL int NDECL(shkveg);
16 STATIC_DCL void FDECL(mkveggy_at, (int, int));
17 STATIC_DCL void FDECL(mkshobj_at, (const struct shclass *, int, int,
19 STATIC_DCL void FDECL(nameshk, (struct monst *, const char *const *));
20 STATIC_DCL int FDECL(shkinit, (const struct shclass *, struct mkroom *));
22 #define VEGETARIAN_CLASS (MAXOCLASSES + 1)
26 * dash - female, personal name
27 * underscore _ female, general name
28 * plus + male, personal name
29 * vertical bar | male, general name (implied for most of shktools)
30 * equals = gender not specified, personal name
32 * Personal names do not receive the honorific prefix "Mr." or "Ms.".
35 static const char *const shkliquors[] = {
37 "Njezjin", "Tsjernigof", "Ossipewsk", "Gorlowka",
41 "Konosja", "Weliki Oestjoeg", "Syktywkar", "Sablja", "Narodnaja", "Kyzyl",
43 "Walbrzych", "Swidnica", "Klodzko", "Raciborz", "Gliwice", "Brzeg",
44 "Krnov", "Hradec Kralove",
46 "Leuk", "Brig", "Brienz", "Thun", "Sarnen", "Burglen", "Elm", "Flims",
47 "Vals", "Schuls", "Zum Loch", 0
50 static const char *const shkbooks[] = {
52 "Skibbereen", "Kanturk", "Rath Luirc", "Ennistymon",
53 "Lahinch", "Kinnegad", "Lugnaquillia", "Enniscorthy",
54 "Gweebarra", "Kittamagh", "Nenagh", "Sneem",
55 "Ballingeary", "Kilgarvan", "Cahersiveen", "Glenbeigh",
56 "Kilmihil", "Kiltamagh", "Droichead Atha", "Inniscrone",
57 "Clonegal", "Lisnaskea", "Culdaff", "Dunfanaghy",
58 "Inishbofin", "Kesh", 0
61 static const char *const shkarmors[] = {
63 "Demirci", "Kalecik", "Boyabai", "Yildizeli", "Gaziantep",
64 "Siirt", "Akhalataki", "Tirebolu", "Aksaray", "Ermenak",
65 "Iskenderun", "Kadirli", "Siverek", "Pervari", "Malasgirt",
66 "Bayburt", "Ayancik", "Zonguldak", "Balya", "Tefenni",
67 "Artvin", "Kars", "Makharadze", "Malazgirt", "Midyat",
68 "Birecik", "Kirikkale", "Alaca", "Polatli", "Nallihan",
72 static const char *const shkwands[] = {
74 "Yr Wyddgrug", "Trallwng", "Mallwyd", "Pontarfynach", "Rhaeader",
75 "Llandrindod", "Llanfair-ym-muallt", "Y-Fenni", "Maesteg", "Rhydaman",
76 "Beddgelert", "Curig", "Llanrwst", "Llanerchymedd", "Caergybi",
78 "Nairn", "Turriff", "Inverurie", "Braemar", "Lochnagar", "Kerloch",
79 "Beinn a Ghlo", "Drumnadrochit", "Morven", "Uist", "Storr",
80 "Sgurr na Ciche", "Cannich", "Gairloch", "Kyleakin", "Dunvegan", 0
83 static const char *const shkrings[] = {
84 /* Hollandse familienamen */
85 "Feyfer", "Flugi", "Gheel", "Havic", "Haynin",
86 "Hoboken", "Imbyze", "Juyn", "Kinsky", "Massis",
87 "Matray", "Moy", "Olycan", "Sadelin", "Svaving",
88 "Tapper", "Terwen", "Wirix", "Ypey",
89 /* Skandinaviske navne */
90 "Rastegaisa", "Varjag Njarga", "Kautekeino", "Abisko", "Enontekis",
91 "Rovaniemi", "Avasaksa", "Haparanda", "Lulea", "Gellivare",
92 "Oeloe", "Kajaani", "Fauske", 0
95 static const char *const shkfoods[] = {
97 "Djasinga", "Tjibarusa", "Tjiwidej", "Pengalengan",
98 "Bandjar", "Parbalingga", "Bojolali", "Sarangan",
99 "Ngebel", "Djombang", "Ardjawinangun", "Berbek",
100 "Papar", "Baliga", "Tjisolok", "Siboga",
101 "Banjoewangi", "Trenggalek", "Karangkobar", "Njalindoeng",
102 "Pasawahan", "Pameunpeuk", "Patjitan", "Kediri",
103 "Pemboeang", "Tringanoe", "Makin", "Tipor",
104 "Semai", "Berhala", "Tegal", "Samoe",
108 static const char *const shkweapons[] = {
110 "Voulgezac", "Rouffiac", "Lerignac", "Touverac", "Guizengeard",
111 "Melac", "Neuvicq", "Vanzac", "Picq", "Urignac",
112 "Corignac", "Fleac", "Lonzac", "Vergt", "Queyssac",
113 "Liorac", "Echourgnac", "Cazelon", "Eypau", "Carignan",
114 "Monbazillac", "Jonzac", "Pons", "Jumilhac", "Fenouilledes",
115 "Laguiolet", "Saujon", "Eymoutiers", "Eygurande", "Eauze",
119 static const char *const shktools[] = {
121 "Ymla", "Eed-morra", "Cubask", "Nieb", "Bnowr Falr", "Telloc Cyaj",
122 "Sperc", "Noskcirdneh", "Yawolloh", "Hyeghu", "Niskal", "Trahnil",
123 "Htargcm", "Enrobwem", "Kachzi Rellim", "Regien", "Donmyar", "Yelpur",
124 "Nosnehpets", "Stewe", "Renrut", "-Zlaw", "Nosalnef", "Rewuorb",
125 "Rellenk", "Yad", "Cire Htims", "Y-crad", "Nenilukah", "Corsh", "Aned",
126 "Niknar", "Lapu", "Lechaim", "Rebrol-nek", "AlliWar Wickson", "Oguhmk",
128 "Erreip", "Nehpets", "Mron", "Snivek", "Kahztiy",
134 "Nhoj-lee", "Evad\'kh", "Ettaw-noj", "Tsew-mot", "Ydna-s", "Yao-hang",
135 "Tonbar", "Kivenhoug", "Llardom",
138 "Falo", "Nosid-da\'r", "Ekim-p", "Noslo", "Yl-rednow", "Mured-oog",
148 "Lez-tneg", "Ytnu-haled",
153 static const char *const shklight[] = {
155 "Zarnesti", "Slanic", "Nehoiasu", "Ludus", "Sighisoara", "Nisipitu",
156 "Razboieni", "Bicaz", "Dorohoi", "Vaslui", "Fetesti", "Tirgu Neamt",
157 "Babadag", "Zimnicea", "Zlatna", "Jiu", "Eforie", "Mamaia",
159 "Silistra", "Tulovo", "Panagyuritshte", "Smolyan", "Kirklareli", "Pernik",
160 "Lom", "Haskovo", "Dobrinishte", "Varvara", "Oryahovo", "Troyan",
161 "Lovech", "Sliven", 0
164 static const char *const shkgeneral[] = {
166 "Hebiwerie", "Possogroenoe", "Asidonhopo", "Manlobbi",
167 "Adjama", "Pakka Pakka", "Kabalebo", "Wonotobo",
168 "Akalapi", "Sipaliwini",
170 "Annootok", "Upernavik", "Angmagssalik",
172 "Aklavik", "Inuvik", "Tuktoyaktuk", "Chicoutimi",
173 "Ouiatchouane", "Chibougamau", "Matagami", "Kipawa",
174 "Kinojevis", "Abitibi", "Maganasipi",
176 "Akureyri", "Kopasker", "Budereyri", "Akranes",
177 "Bordeyri", "Holmavik", 0
180 static const char *const shkhealthfoods[] = {
182 "Ga'er", "Zhangmu", "Rikaze", "Jiangji", "Changdu",
183 "Linzhi", "Shigatse", "Gyantse", "Ganden", "Tsurphu",
184 "Lhasa", "Tsedong", "Drepung",
186 "=Azura", "=Blaze", "=Breanna", "=Breezy", "=Dharma",
187 "=Feather", "=Jasmine", "=Luna", "=Melody", "=Moonjava",
188 "=Petal", "=Rhiannon", "=Starla", "=Tranquilla", "=Windsong",
189 "=Zennia", "=Zoe", "=Zora", 0
193 * To add new shop types, all that is necessary is to edit the shtypes[]
194 * array. See mkroom.h for the structure definition. Typically, you'll
195 * have to lower some or all of the probability fields in old entries to
196 * free up some percentage for the new type.
198 * The placement type field is not yet used but will be in the near future.
200 * The iprobs array in each entry defines the probabilities for various kinds
201 * of objects to be present in the given shop type. You can associate with
202 * each percentage either a generic object type (represented by one of the
203 * *_CLASS macros) or a specific object (represented by an onames.h define).
204 * In the latter case, prepend it with a unary minus so the code can know
205 * (by testing the sign) whether to use mkobj() or mksobj().
207 const struct shclass shtypes[] = {
215 { { 100, RANDOM_CLASS },
223 { "used armor dealership",
225 { "
\92\86\8cÃ
\8aZ
\8f¤
\89ï",
229 { { 90, ARMOR_CLASS },
230 { 10, WEAPON_CLASS },
237 { "second-hand bookstore",
243 { { 90, SCROLL_CLASS },
244 { 10, SPBOOK_CLASS },
253 {"
\82¨
\8eð
\82Ì
\95S
\89Ý
\93X",
257 { { 100, POTION_CLASS },
265 { "antique weapons outlet",
267 { "
\8cÃ
\95\90\8aí
\90ê
\96å
\8f¬
\94\84\93X",
271 { { 90, WEAPON_CLASS },
285 { { 83, FOOD_CLASS },
286 { 5, -POT_FRUIT_JUICE },
299 { { 85, RING_CLASS },
307 { "quality apparel and accessories",
309 { "
\82¨
\83V
\83\83\83\8c\82È
\97m
\95i
\93X",
313 { { 90, WAND_CLASS },
314 { 5, -LEATHER_GLOVES },
325 { { 100, TOOL_CLASS },
335 { "
\8c¶
\82Ì
\96{
\89®",
339 { { 90, SPBOOK_CLASS },
340 { 10, SCROLL_CLASS },
347 { "health food store",
349 { "
\8c\92\8dN
\90H
\95i
\82Ì
\93X",
353 { { 70, VEGETARIAN_CLASS },
354 { 20, -POT_FRUIT_JUICE },
356 { 3, -POT_FULL_HEALING },
357 { 2, -SCR_FOOD_DETECTION },
358 { 1, -LUMP_OF_ROYAL_JELLY } },
360 /* Shops below this point are "unique". That is they must all have a
361 * probability of zero. They are only created via the special level
371 { { 30, -WAX_CANDLE },
372 { 48, -TALLOW_CANDLE },
373 { 5, -BRASS_LANTERN },
383 { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
388 /* validate shop probabilities; otherwise incorrect local changes could
389 end up provoking infinite loops or wild subscripts fetching garbage */
391 init_shop_selection()
393 register int i, j, item_prob, shop_prob;
395 for (shop_prob = 0, i = 0; i < SIZE(shtypes); i++) {
396 shop_prob += shtypes[i].prob;
397 for (item_prob = 0, j = 0; j < SIZE(shtypes[0].iprobs); j++)
398 item_prob += shtypes[i].iprobs[j].iprob;
399 if (item_prob != 100)
400 panic("item probabilities total to %d for %s shops!",
401 item_prob, shtypes[i].name);
403 if (shop_prob != 100)
404 panic("shop probabilities total to %d!", shop_prob);
408 /* decide whether an object or object type is considered vegetarian;
409 for types, items which might go either way are assumed to be veggy */
411 veggy_item(obj, otyp)
413 int otyp; /* used iff obj is null */
419 /* actual object; will check tin content and corpse species */
420 otyp = (int) obj->otyp;
421 oclass = obj->oclass;
422 corpsenm = obj->corpsenm;
424 /* just a type; caller will have to handle tins and corpses */
425 oclass = objects[otyp].oc_class;
426 corpsenm = PM_LICHEN; /* veggy standin */
429 if (oclass == FOOD_CLASS) {
430 if (objects[otyp].oc_material == VEGGY || otyp == EGG)
432 if (otyp == TIN && corpsenm == NON_PM) /* implies obj is non-null */
433 return (boolean) (obj->spe == 1); /* 0 = empty, 1 = spinach */
434 if (otyp == TIN || otyp == CORPSE)
435 return (boolean) (corpsenm >= LOW_PM
436 && vegetarian(&mons[corpsenm]));
444 int i, j, maxprob, prob;
445 char oclass = FOOD_CLASS;
449 ok[0] = 0; /* lint suppression */
450 for (i = bases[(int) oclass]; i < NUM_OBJECTS; ++i) {
451 if (objects[i].oc_class != oclass)
454 if (veggy_item((struct obj *) 0, i)) {
456 maxprob += objects[i].oc_prob;
460 panic("shkveg no veggy objects");
465 while ((prob -= objects[i].oc_prob) > 0) {
470 if (objects[i].oc_class != oclass || !OBJ_NAME(objects[i]))
471 panic("shkveg probtype error, oclass=%d i=%d", (int) oclass, i);
475 /* make a random item for health food store */
480 struct obj *obj = mksobj_at(shkveg(), sx, sy, TRUE, TRUE);
482 if (obj && obj->otyp == TIN)
483 set_tin_variety(obj, HEALTHY_TIN);
487 /* make an object of the appropriate type for a shop square */
489 mkshobj_at(shp, sx, sy, mkspecl)
490 const struct shclass *shp;
495 struct permonst *ptr;
499 if (mkspecl && (!strcmp(shp->name, "rare books")
500 || !strcmp(shp->name, "second-hand bookstore"))) {
501 struct obj *novel = mksobj_at(SPE_NOVEL, sx, sy, FALSE, FALSE);
504 context.tribute.bookstock = TRUE;
508 if (rn2(100) < depth(&u.uz) && !MON_AT(sx, sy)
509 && (ptr = mkclass(S_MIMIC, 0)) != 0
510 && (mtmp = makemon(ptr, sx, sy, NO_MM_FLAGS)) != 0) {
511 /* note: makemon will set the mimic symbol to a shop item */
512 if (rn2(10) >= depth(&u.uz)) {
513 mtmp->m_ap_type = M_AP_OBJECT;
514 mtmp->mappearance = STRANGE_OBJECT;
517 atype = get_shop_item((int) (shp - shtypes));
518 if (atype == VEGETARIAN_CLASS)
521 (void) mksobj_at(-atype, sx, sy, TRUE, TRUE);
523 (void) mkobj_at(atype, sx, sy, TRUE);
527 /* extract a shopkeeper name for the given shop type */
531 const char *const *nlp;
533 int i, trycnt, names_avail;
534 const char *shname = 0;
539 if (nlp == shkfoods && In_mines(&u.uz) && Role_if(PM_MONK)
540 && (sptr = Is_special(&u.uz)) != 0 && sptr->flags.town) {
541 /* special-case override for minetown food store for monks */
542 nlp = shkhealthfoods;
545 if (nlp == shklight && In_mines(&u.uz) && (sptr = Is_special(&u.uz)) != 0
546 && sptr->flags.town) {
547 /* special-case minetown lighting shk */
551 /* We want variation from game to game, without needing the save
552 and restore support which would be necessary for randomization;
553 try not to make too many assumptions about time_t's internals;
554 use ledger_no rather than depth to keep mine town distinct. */
555 int nseed = (int) ((long) ubirthday / 257L);
557 name_wanted = ledger_no(&u.uz) + (nseed % 13) - (nseed % 5);
559 name_wanted += (13 + 5);
560 shk->female = name_wanted & 1;
562 for (names_avail = 0; nlp[names_avail]; names_avail++)
565 for (trycnt = 0; trycnt < 50; trycnt++) {
566 if (nlp == shktools) {
567 shname = shktools[rn2(names_avail)];
568 shk->female = 0; /* reversed below for '_' prefix */
569 } else if (name_wanted < names_avail) {
570 shname = nlp[name_wanted];
571 } else if ((i = rn2(names_avail)) != 0) {
573 } else if (nlp != shkgeneral) {
574 nlp = shkgeneral; /* try general names */
575 for (names_avail = 0; nlp[names_avail]; names_avail++)
577 continue; /* next `trycnt' iteration */
579 shname = shk->female ? "-Lucrezia" : "+Dirk";
581 if (*shname == '_' || *shname == '-')
583 else if (*shname == '|' || *shname == '+')
586 /* is name already in use on this level? */
587 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
588 if (DEADMONSTER(mtmp) || (mtmp == shk) || !mtmp->isshk)
590 if (strcmp(ESHK(mtmp)->shknam, shname))
595 break; /* new name */
598 (void) strncpy(ESHK(shk)->shknam, shname, PL_NSIZ);
599 ESHK(shk)->shknam[PL_NSIZ - 1] = 0;
607 mtmp->mextra = newmextra();
609 ESHK(mtmp) = (struct eshk *) alloc(sizeof(struct eshk));
610 (void) memset((genericptr_t) ESHK(mtmp), 0, sizeof(struct eshk));
611 ESHK(mtmp)->bill_p = (struct bill_x *) 0;
618 if (mtmp->mextra && ESHK(mtmp)) {
619 free((genericptr_t) ESHK(mtmp));
620 ESHK(mtmp) = (struct eshk *) 0;
625 /* create a new shopkeeper in the given room */
628 const struct shclass *shp;
629 struct mkroom *sroom;
631 register int sh, sx, sy;
635 /* place the shopkeeper in the given room */
640 /* check that the shopkeeper placement is sane */
641 if (sroom->irregular) {
642 int rmno = (int) ((sroom - rooms) + ROOMOFFSET);
643 if (isok(sx - 1, sy) && !levl[sx - 1][sy].edge
644 && (int) levl[sx - 1][sy].roomno == rmno)
646 else if (isok(sx + 1, sy) && !levl[sx + 1][sy].edge
647 && (int) levl[sx + 1][sy].roomno == rmno)
649 else if (isok(sx, sy - 1) && !levl[sx][sy - 1].edge
650 && (int) levl[sx][sy - 1].roomno == rmno)
652 else if (isok(sx, sy + 1) && !levl[sx][sy + 1].edge
653 && (int) levl[sx][sy + 1].roomno == rmno)
657 } else if (sx == sroom->lx - 1)
659 else if (sx == sroom->hx + 1)
661 else if (sy == sroom->ly - 1)
663 else if (sy == sroom->hy + 1)
668 /* Said to happen sometimes, but I have never seen it. */
669 /* Supposedly fixed by fdoor change in mklev.c */
671 register int j = sroom->doorct;
673 pline("Where is shopdoor?");
674 pline("Room at (%d,%d),(%d,%d).", sroom->lx, sroom->ly, sroom->hx,
676 pline("doormax=%d doorct=%d fdoor=%d", doorindex, sroom->doorct,
679 pline("door [%d,%d]", doors[sh].x, doors[sh].y);
682 display_nhwindow(WIN_MESSAGE, FALSE);
689 (void) rloc(m_at(sx, sy), FALSE); /* insurance */
691 /* now initialize the shopkeeper monster structure */
692 if (!(shk = makemon(&mons[PM_SHOPKEEPER], sx, sy, MM_ESHK)))
694 eshkp = ESHK(shk); /* makemon(...,MM_ESHK) allocates this */
695 shk->isshk = shk->mpeaceful = 1;
698 shk->mtrapseen = ~0; /* we know all the traps already */
699 eshkp->shoproom = (schar) ((sroom - rooms) + ROOMOFFSET);
700 sroom->resident = shk;
701 eshkp->shoptype = sroom->rtype;
702 assign_level(&eshkp->shoplevel, &u.uz);
703 eshkp->shd = doors[sh];
706 eshkp->robbed = eshkp->credit = eshkp->debit = eshkp->loan = 0L;
707 eshkp->following = eshkp->surcharge = eshkp->dismiss_kops = FALSE;
708 eshkp->billct = eshkp->visitct = 0;
709 eshkp->bill_p = (struct bill_x *) 0;
710 eshkp->customer[0] = '\0';
711 mkmonmoney(shk, 1000L + 30L * (long) rnd(100)); /* initial capital */
712 if (shp->shknms == shkrings)
713 (void) mongets(shk, TOUCHSTONE);
714 nameshk(shk, shp->shknms);
719 /* stock a newly-created room with objects */
721 stock_room(shp_indx, sroom)
723 register struct mkroom *sroom;
726 * Someday soon we'll dispatch on the shdist field of shclass to do
727 * different placements in this routine. Currently it only supports
728 * shop-style placement (all squares except a row nearest the first
732 int stockcount = 0, specialspot = 0;
734 int rmno = (int) ((sroom - rooms) + ROOMOFFSET);
735 const struct shclass *shp = &shtypes[shp_indx];
737 /* first, try to place a shopkeeper in the room */
738 if ((sh = shkinit(shp, sroom)) < 0)
741 /* make sure no doorways without doors, and no trapped doors, in shops */
742 sx = doors[sroom->fdoor].x;
743 sy = doors[sroom->fdoor].y;
744 if (levl[sx][sy].doormask == D_NODOOR) {
745 levl[sx][sy].doormask = D_ISOPEN;
748 if (levl[sx][sy].typ == SDOOR) {
749 cvt_sdoor_to_door(&levl[sx][sy]); /* .typ = DOOR */
752 if (levl[sx][sy].doormask & D_TRAPPED)
753 levl[sx][sy].doormask = D_LOCKED;
755 if (levl[sx][sy].doormask == D_LOCKED) {
756 register int m = sx, n = sy;
758 if (inside_shop(sx + 1, sy))
760 else if (inside_shop(sx - 1, sy))
762 if (inside_shop(sx, sy + 1))
764 else if (inside_shop(sx, sy - 1))
767 Sprintf(buf, "Closed for inventory");
769 Sprintf(buf, "
\92I
\89µ
\82µ
\82Ì
\82½
\82ß
\95Â
\93X");
770 make_engr_at(m, n, buf, 0L, DUST);
773 if (context.tribute.enabled && !context.tribute.bookstock) {
775 * Out of the number of spots where we're actually
776 * going to put stuff, randomly single out one in particular.
778 for (sx = sroom->lx; sx <= sroom->hx; sx++)
779 for (sy = sroom->ly; sy <= sroom->hy; sy++) {
780 if (sroom->irregular) {
781 if (levl[sx][sy].edge
782 || (int) levl[sx][sy].roomno != rmno
783 || distmin(sx, sy, doors[sh].x, doors[sh].y) <= 1)
785 } else if ((sx == sroom->lx && doors[sh].x == sx - 1)
786 || (sx == sroom->hx && doors[sh].x == sx + 1)
787 || (sy == sroom->ly && doors[sh].y == sy - 1)
788 || (sy == sroom->hy && doors[sh].y == sy + 1))
792 specialspot = rnd(stockcount);
796 for (sx = sroom->lx; sx <= sroom->hx; sx++)
797 for (sy = sroom->ly; sy <= sroom->hy; sy++) {
798 if (sroom->irregular) {
799 if (levl[sx][sy].edge
800 || (int) levl[sx][sy].roomno != rmno
801 || distmin(sx, sy, doors[sh].x, doors[sh].y) <= 1)
803 } else if ((sx == sroom->lx && doors[sh].x == sx - 1)
804 || (sx == sroom->hx && doors[sh].x == sx + 1)
805 || (sy == sroom->ly && doors[sh].y == sy - 1)
806 || (sy == sroom->hy && doors[sh].y == sy + 1))
809 mkshobj_at(shp, sx, sy,
810 ((stockcount) && (stockcount == specialspot)));
814 * Special monster placements (if any) should go here: that way,
815 * monsters will sit on top of objects and not the other way around.
818 level.flags.has_shop = TRUE;
821 /* does shkp's shop stock this item type? */
827 int i, shp_indx = ESHK(shkp)->shoptype - SHOPBASE;
828 const struct shclass *shp = &shtypes[shp_indx];
830 if (shp->symb == RANDOM_CLASS)
832 for (i = 0; i < SIZE(shtypes[0].iprobs) && shp->iprobs[i].iprob; i++) {
833 /* pseudo-class needs special handling */
834 if (shp->iprobs[i].itype == VEGETARIAN_CLASS) {
835 if (veggy_item(obj, 0))
837 } else if ((shp->iprobs[i].itype < 0)
838 ? shp->iprobs[i].itype == -obj->otyp
839 : shp->iprobs[i].itype == obj->oclass)
846 /* positive value: class; negative value: specific object type */
851 const struct shclass *shp = shtypes + type;
854 /* select an appropriate object type at random */
855 for (j = rnd(100), i = 0; (j -= shp->iprobs[i].iprob) > 0; i++)
858 return shp->iprobs[i].itype;
865 const char *shknm = ESHK(mtmp)->shknam;
867 if (Hallucination && !program_state.gameover) {
868 const char *const *nlp;
871 /* count the number of non-unique shop types;
872 pick one randomly, ignoring shop generation probabilities;
873 pick a name at random from that shop type's list */
874 for (num = 0; num < SIZE(shtypes); num++)
875 if (shtypes[num].prob == 0)
878 nlp = shtypes[rn2(num)].shknms;
879 for (num = 0; nlp[num]; num++)
882 shknm = nlp[rn2(num)];
886 /* strip prefix if present */
893 shkname_is_pname(mtmp)
896 const char *shknm = ESHK(mtmp)->shknam;
898 return (boolean) (*shknm == '-' || *shknm == '+' || *shknm == '=');
902 is_izchak(shkp, override_hallucination)
904 boolean override_hallucination;
908 if (Hallucination && !override_hallucination)
912 /* outside of town, Izchak becomes just an ordinary shopkeeper */
913 if (!in_town(shkp->mx, shkp->my))
915 shknm = ESHK(shkp)->shknam;
916 /* skip "+" prefix */
919 return (boolean) !strcmp(shknm, "Izchak");