OSDN Git Service

patch src/
[jnethack/source.git] / src / shknam.c
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. */
4
5 /* shknam.c -- initialize a shop */
6
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. */
11
12 #include "hack.h"
13
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,
18                                    BOOLEAN_P));
19 STATIC_DCL void FDECL(nameshk, (struct monst *, const char *const *));
20 STATIC_DCL int FDECL(shkinit, (const struct shclass *, struct mkroom *));
21
22 #define VEGETARIAN_CLASS (MAXOCLASSES + 1)
23
24 /*
25  *  Name prefix codes:
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
31  *
32  *  Personal names do not receive the honorific prefix "Mr." or "Ms.".
33  */
34
35 static const char *const shkliquors[] = {
36     /* Ukraine */
37     "Njezjin", "Tsjernigof", "Ossipewsk", "Gorlowka",
38     /* Belarus */
39     "Gomel",
40     /* N. Russia */
41     "Konosja", "Weliki Oestjoeg", "Syktywkar", "Sablja", "Narodnaja", "Kyzyl",
42     /* Silezie */
43     "Walbrzych", "Swidnica", "Klodzko", "Raciborz", "Gliwice", "Brzeg",
44     "Krnov", "Hradec Kralove",
45     /* Schweiz */
46     "Leuk", "Brig", "Brienz", "Thun", "Sarnen", "Burglen", "Elm", "Flims",
47     "Vals", "Schuls", "Zum Loch", 0
48 };
49
50 static const char *const shkbooks[] = {
51     /* Eire */
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
59 };
60
61 static const char *const shkarmors[] = {
62     /* Turquie */
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",
69     0
70 };
71
72 static const char *const shkwands[] = {
73     /* Wales */
74     "Yr Wyddgrug", "Trallwng", "Mallwyd", "Pontarfynach", "Rhaeader",
75     "Llandrindod", "Llanfair-ym-muallt", "Y-Fenni", "Maesteg", "Rhydaman",
76     "Beddgelert", "Curig", "Llanrwst", "Llanerchymedd", "Caergybi",
77     /* Scotland */
78     "Nairn", "Turriff", "Inverurie", "Braemar", "Lochnagar", "Kerloch",
79     "Beinn a Ghlo", "Drumnadrochit", "Morven", "Uist", "Storr",
80     "Sgurr na Ciche", "Cannich", "Gairloch", "Kyleakin", "Dunvegan", 0
81 };
82
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
93 };
94
95 static const char *const shkfoods[] = {
96     /* Indonesia */
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",
105     0
106 };
107
108 static const char *const shkweapons[] = {
109     /* Perigord */
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",
116     "Labouheyre",  0
117 };
118
119 static const char *const shktools[] = {
120     /* Spmi */
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",
127 #ifdef OVERLAY
128     "Erreip", "Nehpets", "Mron", "Snivek", "Kahztiy",
129 #endif
130 #ifdef WIN32
131     "Lexa", "Niod",
132 #endif
133 #ifdef MAC
134     "Nhoj-lee", "Evad\'kh", "Ettaw-noj", "Tsew-mot", "Ydna-s", "Yao-hang",
135     "Tonbar", "Kivenhoug", "Llardom",
136 #endif
137 #ifdef AMIGA
138     "Falo", "Nosid-da\'r", "Ekim-p", "Noslo", "Yl-rednow", "Mured-oog",
139     "Ivrajimsal",
140 #endif
141 #ifdef TOS
142     "Nivram",
143 #endif
144 #ifdef OS2
145     "Nedraawi-nav",
146 #endif
147 #ifdef VMS
148     "Lez-tneg", "Ytnu-haled",
149 #endif
150     0
151 };
152
153 static const char *const shklight[] = {
154     /* Romania */
155     "Zarnesti", "Slanic", "Nehoiasu", "Ludus", "Sighisoara", "Nisipitu",
156     "Razboieni", "Bicaz", "Dorohoi", "Vaslui", "Fetesti", "Tirgu Neamt",
157     "Babadag", "Zimnicea", "Zlatna", "Jiu", "Eforie", "Mamaia",
158     /* Bulgaria */
159     "Silistra", "Tulovo", "Panagyuritshte", "Smolyan", "Kirklareli", "Pernik",
160     "Lom", "Haskovo", "Dobrinishte", "Varvara", "Oryahovo", "Troyan",
161     "Lovech", "Sliven", 0
162 };
163
164 static const char *const shkgeneral[] = {
165     /* Suriname */
166     "Hebiwerie",    "Possogroenoe", "Asidonhopo",   "Manlobbi",
167     "Adjama",       "Pakka Pakka",  "Kabalebo",     "Wonotobo",
168     "Akalapi",      "Sipaliwini",
169     /* Greenland */
170     "Annootok",     "Upernavik",    "Angmagssalik",
171     /* N. Canada */
172     "Aklavik",      "Inuvik",       "Tuktoyaktuk",  "Chicoutimi",
173     "Ouiatchouane", "Chibougamau",  "Matagami",     "Kipawa",
174     "Kinojevis",    "Abitibi",      "Maganasipi",
175     /* Iceland */
176     "Akureyri",     "Kopasker",     "Budereyri",    "Akranes",
177     "Bordeyri",     "Holmavik",     0
178 };
179
180 static const char *const shkhealthfoods[] = {
181     /* Tibet */
182     "Ga'er",    "Zhangmu",   "Rikaze",   "Jiangji",     "Changdu",
183     "Linzhi",   "Shigatse",  "Gyantse",  "Ganden",      "Tsurphu",
184     "Lhasa",    "Tsedong",   "Drepung",
185     /* Hippie names */
186     "=Azura",   "=Blaze",    "=Breanna", "=Breezy",     "=Dharma",
187     "=Feather", "=Jasmine",  "=Luna",    "=Melody",     "=Moonjava",
188     "=Petal",   "=Rhiannon", "=Starla",  "=Tranquilla", "=Windsong",
189     "=Zennia",  "=Zoe",      "=Zora",    0
190 };
191
192 /*
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.
197  *
198  * The placement type field is not yet used but will be in the near future.
199  *
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().
206  */
207 const struct shclass shtypes[] = {
208 /*JP
209     { "general store",
210 */
211     { "\8eG\89Ý\89®",
212       RANDOM_CLASS,
213       42,
214       D_SHOP,
215       { { 100, RANDOM_CLASS },
216         { 0, 0 },
217         { 0, 0 },
218         { 0, 0 },
219         { 0, 0 },
220         { 0, 0 } },
221       shkgeneral },
222 /*JP
223     { "used armor dealership",
224 */
225     { "\92\86\8cÃ\8aZ\8f¤\89ï",
226       ARMOR_CLASS,
227       14,
228       D_SHOP,
229       { { 90, ARMOR_CLASS },
230         { 10, WEAPON_CLASS },
231         { 0, 0 },
232         { 0, 0 },
233         { 0, 0 },
234         { 0, 0 } },
235       shkarmors },
236 /*JP
237     { "second-hand bookstore",
238 */
239     { "\8cÃ\8f\91\93X",
240       SCROLL_CLASS,
241       10,
242       D_SHOP,
243       { { 90, SCROLL_CLASS },
244         { 10, SPBOOK_CLASS },
245         { 0, 0 },
246         { 0, 0 },
247         { 0, 0 },
248         { 0, 0 } },
249       shkbooks },
250 /*JP
251     { "liquor emporium",
252 */
253     {"\82¨\8eð\82Ì\95S\89Ý\93X",
254       POTION_CLASS,
255       10,
256       D_SHOP,
257       { { 100, POTION_CLASS },
258         { 0, 0 },
259         { 0, 0 },
260         { 0, 0 },
261         { 0, 0 },
262         { 0, 0 } },
263       shkliquors },
264 /*JP
265     { "antique weapons outlet",
266 */
267     { "\8cÃ\95\90\8aí\90ê\96å\8f¬\94\84\93X",
268       WEAPON_CLASS,
269       5,
270       D_SHOP,
271       { { 90, WEAPON_CLASS },
272         { 10, ARMOR_CLASS },
273         { 0, 0 },
274         { 0, 0 },
275         { 0, 0 },
276         { 0, 0 } },
277       shkweapons },
278 /*JP
279     { "delicatessen",
280 */
281     { "\90H\95i\93X",
282       FOOD_CLASS,
283       5,
284       D_SHOP,
285       { { 83, FOOD_CLASS },
286         { 5, -POT_FRUIT_JUICE },
287         { 4, -POT_BOOZE },
288         { 5, -POT_WATER },
289         { 3, -ICE_BOX },
290         { 0, 0 } },
291       shkfoods },
292 /*JP
293     { "jewelers",
294 */
295     { "\95ó\90Î\93X",
296       RING_CLASS,
297       3,
298       D_SHOP,
299       { { 85, RING_CLASS },
300         { 10, GEM_CLASS },
301         { 5, AMULET_CLASS },
302         { 0, 0 },
303         { 0, 0 },
304         { 0, 0 } },
305       shkrings },
306 /*JP
307     { "quality apparel and accessories",
308 */
309     { "\82¨\83V\83\83\83\8c\82È\97m\95i\93X",
310       WAND_CLASS,
311       3,
312       D_SHOP,
313       { { 90, WAND_CLASS },
314         { 5, -LEATHER_GLOVES },
315         { 5, -ELVEN_CLOAK },
316         { 0, 0 } },
317       shkwands },
318 /*JP
319     { "hardware store",
320 */
321     { "\93¹\8bï\89®",
322       TOOL_CLASS,
323       3,
324       D_SHOP,
325       { { 100, TOOL_CLASS },
326         { 0, 0 },
327         { 0, 0 },
328         { 0, 0 },
329         { 0, 0 },
330         { 0, 0 } },
331       shktools },
332 /*JP
333     { "rare books",
334 */
335     { "\8c\82Ì\96{\89®",
336       SPBOOK_CLASS,
337       3,
338       D_SHOP,
339       { { 90, SPBOOK_CLASS },
340         { 10, SCROLL_CLASS },
341         { 0, 0 },
342         { 0, 0 },
343         { 0, 0 },
344         { 0, 0 } },
345       shkbooks },
346 /*JP
347     { "health food store",
348 */
349     { "\8c\92\8dN\90H\95i\82Ì\93X",
350       FOOD_CLASS,
351       2,
352       D_SHOP,
353       { { 70, VEGETARIAN_CLASS },
354         { 20, -POT_FRUIT_JUICE },
355         { 4, -POT_HEALING },
356         { 3, -POT_FULL_HEALING },
357         { 2, -SCR_FOOD_DETECTION },
358         { 1, -LUMP_OF_ROYAL_JELLY } },
359       shkhealthfoods },
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
362      * loader.
363      */
364 /*JP
365     { "lighting store",
366 */
367     { "\8fÆ\96¾\93X",
368       TOOL_CLASS,
369       0,
370       D_SHOP,
371       { { 30, -WAX_CANDLE },
372         { 48, -TALLOW_CANDLE },
373         { 5, -BRASS_LANTERN },
374         { 9, -OIL_LAMP },
375         { 3, -MAGIC_LAMP },
376         { 5, -POT_OIL } },
377       shklight },
378     /* sentinel */
379     { (char *) 0,
380       0,
381       0,
382       0,
383       { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
384       0 }
385 };
386
387 #if 0
388 /* validate shop probabilities; otherwise incorrect local changes could
389    end up provoking infinite loops or wild subscripts fetching garbage */
390 void
391 init_shop_selection()
392 {
393     register int i, j, item_prob, shop_prob;
394
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);
402     }
403     if (shop_prob != 100)
404         panic("shop probabilities total to %d!", shop_prob);
405 }
406 #endif /*0*/
407
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 */
410 STATIC_OVL boolean
411 veggy_item(obj, otyp)
412 struct obj *obj;
413 int otyp; /* used iff obj is null */
414 {
415     int corpsenm;
416     char oclass;
417
418     if (obj) {
419         /* actual object; will check tin content and corpse species */
420         otyp = (int) obj->otyp;
421         oclass = obj->oclass;
422         corpsenm = obj->corpsenm;
423     } else {
424         /* just a type; caller will have to handle tins and corpses */
425         oclass = objects[otyp].oc_class;
426         corpsenm = PM_LICHEN; /* veggy standin */
427     }
428
429     if (oclass == FOOD_CLASS) {
430         if (objects[otyp].oc_material == VEGGY || otyp == EGG)
431             return TRUE;
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]));
437     }
438     return FALSE;
439 }
440
441 STATIC_OVL int
442 shkveg()
443 {
444     int i, j, maxprob, prob;
445     char oclass = FOOD_CLASS;
446     int ok[NUM_OBJECTS];
447
448     j = maxprob = 0;
449     ok[0] = 0; /* lint suppression */
450     for (i = bases[(int) oclass]; i < NUM_OBJECTS; ++i) {
451         if (objects[i].oc_class != oclass)
452             break;
453
454         if (veggy_item((struct obj *) 0, i)) {
455             ok[j++] = i;
456             maxprob += objects[i].oc_prob;
457         }
458     }
459     if (maxprob < 1)
460         panic("shkveg no veggy objects");
461     prob = rnd(maxprob);
462
463     j = 0;
464     i = ok[0];
465     while ((prob -= objects[i].oc_prob) > 0) {
466         j++;
467         i = ok[j];
468     }
469
470     if (objects[i].oc_class != oclass || !OBJ_NAME(objects[i]))
471         panic("shkveg probtype error, oclass=%d i=%d", (int) oclass, i);
472     return i;
473 }
474
475 /* make a random item for health food store */
476 STATIC_OVL void
477 mkveggy_at(sx, sy)
478 int sx, sy;
479 {
480     struct obj *obj = mksobj_at(shkveg(), sx, sy, TRUE, TRUE);
481
482     if (obj && obj->otyp == TIN)
483         set_tin_variety(obj, HEALTHY_TIN);
484     return;
485 }
486
487 /* make an object of the appropriate type for a shop square */
488 STATIC_OVL void
489 mkshobj_at(shp, sx, sy, mkspecl)
490 const struct shclass *shp;
491 int sx, sy;
492 boolean mkspecl;
493 {
494     struct monst *mtmp;
495     struct permonst *ptr;
496     int atype;
497
498     /* 3.6.0 tribute */
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);
502
503         if (novel)
504             context.tribute.bookstock = TRUE;
505         return;
506     }
507
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;
515         }
516     } else {
517         atype = get_shop_item((int) (shp - shtypes));
518         if (atype == VEGETARIAN_CLASS)
519             mkveggy_at(sx, sy);
520         else if (atype < 0)
521             (void) mksobj_at(-atype, sx, sy, TRUE, TRUE);
522         else
523             (void) mkobj_at(atype, sx, sy, TRUE);
524     }
525 }
526
527 /* extract a shopkeeper name for the given shop type */
528 STATIC_OVL void
529 nameshk(shk, nlp)
530 struct monst *shk;
531 const char *const *nlp;
532 {
533     int i, trycnt, names_avail;
534     const char *shname = 0;
535     struct monst *mtmp;
536     int name_wanted;
537     s_level *sptr;
538
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;
543     }
544
545     if (nlp == shklight && In_mines(&u.uz) && (sptr = Is_special(&u.uz)) != 0
546         && sptr->flags.town) {
547         /* special-case minetown lighting shk */
548         shname = "+Izchak";
549         shk->female = FALSE;
550     } else {
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);
556
557         name_wanted = ledger_no(&u.uz) + (nseed % 13) - (nseed % 5);
558         if (name_wanted < 0)
559             name_wanted += (13 + 5);
560         shk->female = name_wanted & 1;
561
562         for (names_avail = 0; nlp[names_avail]; names_avail++)
563             continue;
564
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) {
572                 shname = nlp[i - 1];
573             } else if (nlp != shkgeneral) {
574                 nlp = shkgeneral; /* try general names */
575                 for (names_avail = 0; nlp[names_avail]; names_avail++)
576                     continue;
577                 continue; /* next `trycnt' iteration */
578             } else {
579                 shname = shk->female ? "-Lucrezia" : "+Dirk";
580             }
581             if (*shname == '_' || *shname == '-')
582                 shk->female = 1;
583             else if (*shname == '|' || *shname == '+')
584                 shk->female = 0;
585
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)
589                     continue;
590                 if (strcmp(ESHK(mtmp)->shknam, shname))
591                     continue;
592                 break;
593             }
594             if (!mtmp)
595                 break; /* new name */
596         }
597     }
598     (void) strncpy(ESHK(shk)->shknam, shname, PL_NSIZ);
599     ESHK(shk)->shknam[PL_NSIZ - 1] = 0;
600 }
601
602 void
603 neweshk(mtmp)
604 struct monst *mtmp;
605 {
606     if (!mtmp->mextra)
607         mtmp->mextra = newmextra();
608     if (!ESHK(mtmp))
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;
612 }
613
614 void
615 free_eshk(mtmp)
616 struct monst *mtmp;
617 {
618     if (mtmp->mextra && ESHK(mtmp)) {
619         free((genericptr_t) ESHK(mtmp));
620         ESHK(mtmp) = (struct eshk *) 0;
621     }
622     mtmp->isshk = 0;
623 }
624
625 /* create a new shopkeeper in the given room */
626 STATIC_OVL int
627 shkinit(shp, sroom)
628 const struct shclass *shp;
629 struct mkroom *sroom;
630 {
631     register int sh, sx, sy;
632     struct monst *shk;
633     struct eshk *eshkp;
634
635     /* place the shopkeeper in the given room */
636     sh = sroom->fdoor;
637     sx = doors[sh].x;
638     sy = doors[sh].y;
639
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)
645             sx--;
646         else if (isok(sx + 1, sy) && !levl[sx + 1][sy].edge
647                  && (int) levl[sx + 1][sy].roomno == rmno)
648             sx++;
649         else if (isok(sx, sy - 1) && !levl[sx][sy - 1].edge
650                  && (int) levl[sx][sy - 1].roomno == rmno)
651             sy--;
652         else if (isok(sx, sy + 1) && !levl[sx][sy + 1].edge
653                  && (int) levl[sx][sy + 1].roomno == rmno)
654             sx++;
655         else
656             goto shk_failed;
657     } else if (sx == sroom->lx - 1)
658         sx++;
659     else if (sx == sroom->hx + 1)
660         sx--;
661     else if (sy == sroom->ly - 1)
662         sy++;
663     else if (sy == sroom->hy + 1)
664         sy--;
665     else {
666     shk_failed:
667 #ifdef DEBUG
668         /* Said to happen sometimes, but I have never seen it. */
669         /* Supposedly fixed by fdoor change in mklev.c */
670         if (wizard) {
671             register int j = sroom->doorct;
672
673             pline("Where is shopdoor?");
674             pline("Room at (%d,%d),(%d,%d).", sroom->lx, sroom->ly, sroom->hx,
675                   sroom->hy);
676             pline("doormax=%d doorct=%d fdoor=%d", doorindex, sroom->doorct,
677                   sh);
678             while (j--) {
679                 pline("door [%d,%d]", doors[sh].x, doors[sh].y);
680                 sh++;
681             }
682             display_nhwindow(WIN_MESSAGE, FALSE);
683         }
684 #endif
685         return -1;
686     }
687
688     if (MON_AT(sx, sy))
689         (void) rloc(m_at(sx, sy), FALSE); /* insurance */
690
691     /* now initialize the shopkeeper monster structure */
692     if (!(shk = makemon(&mons[PM_SHOPKEEPER], sx, sy, MM_ESHK)))
693         return -1;
694     eshkp = ESHK(shk); /* makemon(...,MM_ESHK) allocates this */
695     shk->isshk = shk->mpeaceful = 1;
696     set_malign(shk);
697     shk->msleeping = 0;
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];
704     eshkp->shk.x = sx;
705     eshkp->shk.y = sy;
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);
715
716     return sh;
717 }
718
719 /* stock a newly-created room with objects */
720 void
721 stock_room(shp_indx, sroom)
722 int shp_indx;
723 register struct mkroom *sroom;
724 {
725     /*
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
729      * door get objects).
730      */
731     int sx, sy, sh;
732     int stockcount = 0, specialspot = 0;
733     char buf[BUFSZ];
734     int rmno = (int) ((sroom - rooms) + ROOMOFFSET);
735     const struct shclass *shp = &shtypes[shp_indx];
736
737     /* first, try to place a shopkeeper in the room */
738     if ((sh = shkinit(shp, sroom)) < 0)
739         return;
740
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;
746         newsym(sx, sy);
747     }
748     if (levl[sx][sy].typ == SDOOR) {
749         cvt_sdoor_to_door(&levl[sx][sy]); /* .typ = DOOR */
750         newsym(sx, sy);
751     }
752     if (levl[sx][sy].doormask & D_TRAPPED)
753         levl[sx][sy].doormask = D_LOCKED;
754
755     if (levl[sx][sy].doormask == D_LOCKED) {
756         register int m = sx, n = sy;
757
758         if (inside_shop(sx + 1, sy))
759             m--;
760         else if (inside_shop(sx - 1, sy))
761             m++;
762         if (inside_shop(sx, sy + 1))
763             n--;
764         else if (inside_shop(sx, sy - 1))
765             n++;
766 /*JP
767         Sprintf(buf, "Closed for inventory");
768 */
769         Sprintf(buf, "\92I\89µ\82µ\82Ì\82½\82ß\95Â\93X");
770         make_engr_at(m, n, buf, 0L, DUST);
771     }
772
773     if (context.tribute.enabled && !context.tribute.bookstock) {
774         /*
775          * Out of the number of spots where we're actually
776          * going to put stuff, randomly single out one in particular.
777          */
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)
784                         continue;
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))
789                     continue;
790                 stockcount++;
791             }
792         specialspot = rnd(stockcount);
793         stockcount = 0;
794     }
795
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)
802                     continue;
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))
807                 continue;
808             stockcount++;
809             mkshobj_at(shp, sx, sy,
810                        ((stockcount) && (stockcount == specialspot)));
811         }
812
813     /*
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.
816      */
817
818     level.flags.has_shop = TRUE;
819 }
820
821 /* does shkp's shop stock this item type? */
822 boolean
823 saleable(shkp, obj)
824 struct monst *shkp;
825 struct obj *obj;
826 {
827     int i, shp_indx = ESHK(shkp)->shoptype - SHOPBASE;
828     const struct shclass *shp = &shtypes[shp_indx];
829
830     if (shp->symb == RANDOM_CLASS)
831         return TRUE;
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))
836                 return TRUE;
837         } else if ((shp->iprobs[i].itype < 0)
838                        ? shp->iprobs[i].itype == -obj->otyp
839                        : shp->iprobs[i].itype == obj->oclass)
840             return TRUE;
841     }
842     /* not found */
843     return FALSE;
844 }
845
846 /* positive value: class; negative value: specific object type */
847 int
848 get_shop_item(type)
849 int type;
850 {
851     const struct shclass *shp = shtypes + type;
852     register int i, j;
853
854     /* select an appropriate object type at random */
855     for (j = rnd(100), i = 0; (j -= shp->iprobs[i].iprob) > 0; i++)
856         continue;
857
858     return shp->iprobs[i].itype;
859 }
860
861 const char *
862 shkname(mtmp)
863 struct monst *mtmp;
864 {
865     const char *shknm = ESHK(mtmp)->shknam;
866
867     if (Hallucination && !program_state.gameover) {
868         const char *const *nlp;
869         int num;
870
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)
876                 break;
877         if (num > 0) {
878             nlp = shtypes[rn2(num)].shknms;
879             for (num = 0; nlp[num]; num++)
880                 continue;
881             if (num > 0)
882                 shknm = nlp[rn2(num)];
883         }
884     }
885
886     /* strip prefix if present */
887     if (!letter(*shknm))
888         ++shknm;
889     return shknm;
890 }
891
892 boolean
893 shkname_is_pname(mtmp)
894 struct monst *mtmp;
895 {
896     const char *shknm = ESHK(mtmp)->shknam;
897
898     return (boolean) (*shknm == '-' || *shknm == '+' || *shknm == '=');
899 }
900
901 boolean
902 is_izchak(shkp, override_hallucination)
903 struct monst *shkp;
904 boolean override_hallucination;
905 {
906     const char *shknm;
907
908     if (Hallucination && !override_hallucination)
909         return FALSE;
910     if (!shkp->isshk)
911         return FALSE;
912     /* outside of town, Izchak becomes just an ordinary shopkeeper */
913     if (!in_town(shkp->mx, shkp->my))
914         return FALSE;
915     shknm = ESHK(shkp)->shknam;
916     /* skip "+" prefix */
917     if (!letter(*shknm))
918         ++shknm;
919     return (boolean) !strcmp(shknm, "Izchak");
920 }
921
922 /*shknam.c*/