NHDT->ANH, in most cases
[aNetHack.git] / src / shknam.c
blob8e0bfb8318fbac364ea144fb36f7590676061472
1 /* NetHack 3.6 shknam.c $ANH-Date: 1454485432 2016/02/03 07:43:52 $ $ANH-Branch: master $:$ANH-Revision: 1.41 $ */
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 #include "hack.h"
9 STATIC_DCL boolean FDECL(stock_room_goodpos, (struct mkroom *, int, int, int, int));
10 STATIC_DCL boolean FDECL(veggy_item, (struct obj * obj, int));
11 STATIC_DCL int NDECL(shkveg);
12 STATIC_DCL void FDECL(mkveggy_at, (int, int));
13 STATIC_DCL void FDECL(mkshobj_at, (const struct shclass *, int, int,
14 BOOLEAN_P));
15 STATIC_DCL void FDECL(nameshk, (struct monst *, const char *const *));
16 STATIC_DCL int FDECL(shkinit, (const struct shclass *, struct mkroom *));
18 #define VEGETARIAN_CLASS (MAXOCLASSES + 1)
21 * Name prefix codes:
22 * dash - female, personal name
23 * underscore _ female, general name
24 * plus + male, personal name
25 * vertical bar | male, general name (implied for most of shktools)
26 * equals = gender not specified, personal name
28 * Personal names do not receive the honorific prefix "Mr." or "Ms.".
31 static const char *const shkliquors[] = {
32 /* Ukraine */
33 "Njezjin", "Tsjernigof", "Ossipewsk", "Gorlowka",
34 /* Belarus */
35 "Gomel",
36 /* N. Russia */
37 "Konosja", "Weliki Oestjoeg", "Syktywkar", "Sablja", "Narodnaja", "Kyzyl",
38 /* Silezie */
39 "Walbrzych", "Swidnica", "Klodzko", "Raciborz", "Gliwice", "Brzeg",
40 "Krnov", "Hradec Kralove",
41 /* Schweiz */
42 "Leuk", "Brig", "Brienz", "Thun", "Sarnen", "Burglen", "Elm", "Flims",
43 "Vals", "Schuls", "Zum Loch", 0
46 static const char *const shkbooks[] = {
47 /* Eire */
48 "Skibbereen", "Kanturk", "Rath Luirc", "Ennistymon",
49 "Lahinch", "Kinnegad", "Lugnaquillia", "Enniscorthy",
50 "Gweebarra", "Kittamagh", "Nenagh", "Sneem",
51 "Ballingeary", "Kilgarvan", "Cahersiveen", "Glenbeigh",
52 "Kilmihil", "Kiltamagh", "Droichead Atha", "Inniscrone",
53 "Clonegal", "Lisnaskea", "Culdaff", "Dunfanaghy",
54 "Inishbofin", "Kesh", 0
57 static const char *const shkarmors[] = {
58 /* Turquie */
59 "Demirci", "Kalecik", "Boyabai", "Yildizeli", "Gaziantep",
60 "Siirt", "Akhalataki", "Tirebolu", "Aksaray", "Ermenak",
61 "Iskenderun", "Kadirli", "Siverek", "Pervari", "Malasgirt",
62 "Bayburt", "Ayancik", "Zonguldak", "Balya", "Tefenni",
63 "Artvin", "Kars", "Makharadze", "Malazgirt", "Midyat",
64 "Birecik", "Kirikkale", "Alaca", "Polatli", "Nallihan",
68 static const char *const shkwands[] = {
69 /* Wales */
70 "Yr Wyddgrug", "Trallwng", "Mallwyd", "Pontarfynach", "Rhaeader",
71 "Llandrindod", "Llanfair-ym-muallt", "Y-Fenni", "Maesteg", "Rhydaman",
72 "Beddgelert", "Curig", "Llanrwst", "Llanerchymedd", "Caergybi",
73 /* Scotland */
74 "Nairn", "Turriff", "Inverurie", "Braemar", "Lochnagar", "Kerloch",
75 "Beinn a Ghlo", "Drumnadrochit", "Morven", "Uist", "Storr",
76 "Sgurr na Ciche", "Cannich", "Gairloch", "Kyleakin", "Dunvegan", 0
79 static const char *const shkrings[] = {
80 /* Hollandse familienamen */
81 "Feyfer", "Flugi", "Gheel", "Havic", "Haynin",
82 "Hoboken", "Imbyze", "Juyn", "Kinsky", "Massis",
83 "Matray", "Moy", "Olycan", "Sadelin", "Svaving",
84 "Tapper", "Terwen", "Wirix", "Ypey",
85 /* Skandinaviske navne */
86 "Rastegaisa", "Varjag Njarga", "Kautekeino", "Abisko", "Enontekis",
87 "Rovaniemi", "Avasaksa", "Haparanda", "Lulea", "Gellivare",
88 "Oeloe", "Kajaani", "Fauske", 0
91 static const char *const shkfoods[] = {
92 /* Indonesia */
93 "Djasinga", "Tjibarusa", "Tjiwidej", "Pengalengan",
94 "Bandjar", "Parbalingga", "Bojolali", "Sarangan",
95 "Ngebel", "Djombang", "Ardjawinangun", "Berbek",
96 "Papar", "Baliga", "Tjisolok", "Siboga",
97 "Banjoewangi", "Trenggalek", "Karangkobar", "Njalindoeng",
98 "Pasawahan", "Pameunpeuk", "Patjitan", "Kediri",
99 "Pemboeang", "Tringanoe", "Makin", "Tipor",
100 "Semai", "Berhala", "Tegal", "Samoe",
104 static const char *const shkweapons[] = {
105 /* Perigord */
106 "Voulgezac", "Rouffiac", "Lerignac", "Touverac", "Guizengeard",
107 "Melac", "Neuvicq", "Vanzac", "Picq", "Urignac",
108 "Corignac", "Fleac", "Lonzac", "Vergt", "Queyssac",
109 "Liorac", "Echourgnac", "Cazelon", "Eypau", "Carignan",
110 "Monbazillac", "Jonzac", "Pons", "Jumilhac", "Fenouilledes",
111 "Laguiolet", "Saujon", "Eymoutiers", "Eygurande", "Eauze",
112 "Labouheyre", 0
115 static const char *const shktools[] = {
116 /* Spmi */
117 "Ymla", "Eed-morra", "Elan Lapinski", "Cubask", "Nieb", "Bnowr Falr",
118 "Sperc", "Noskcirdneh", "Yawolloh", "Hyeghu", "Niskal", "Trahnil",
119 "Htargcm", "Enrobwem", "Kachzi Rellim", "Regien", "Donmyar", "Yelpur",
120 "Nosnehpets", "Stewe", "Renrut", "Senna Hut", "-Zlaw", "Nosalnef",
121 "Rewuorb", "Rellenk", "Yad", "Cire Htims", "Y-crad", "Nenilukah",
122 "Corsh", "Aned", "Dark Eery", "Niknar", "Lapu", "Lechaim",
123 "Rebrol-nek", "AlliWar Wickson", "Oguhmk", "Telloc Cyaj",
124 #ifdef OVERLAY
125 "Erreip", "Nehpets", "Mron", "Snivek", "Kahztiy",
126 #endif
127 #ifdef WIN32
128 "Lexa", "Niod",
129 #endif
130 #ifdef MAC
131 "Nhoj-lee", "Evad\'kh", "Ettaw-noj", "Tsew-mot", "Ydna-s", "Yao-hang",
132 "Tonbar", "Kivenhoug", "Llardom",
133 #endif
134 #ifdef AMIGA
135 "Falo", "Nosid-da\'r", "Ekim-p", "Noslo", "Yl-rednow", "Mured-oog",
136 "Ivrajimsal",
137 #endif
138 #ifdef TOS
139 "Nivram",
140 #endif
141 #ifdef OS2
142 "Nedraawi-nav",
143 #endif
144 #ifdef VMS
145 "Lez-tneg", "Ytnu-haled",
146 #endif
150 static const char *const shklight[] = {
151 /* Romania */
152 "Zarnesti", "Slanic", "Nehoiasu", "Ludus", "Sighisoara", "Nisipitu",
153 "Razboieni", "Bicaz", "Dorohoi", "Vaslui", "Fetesti", "Tirgu Neamt",
154 "Babadag", "Zimnicea", "Zlatna", "Jiu", "Eforie", "Mamaia",
155 /* Bulgaria */
156 "Silistra", "Tulovo", "Panagyuritshte", "Smolyan", "Kirklareli", "Pernik",
157 "Lom", "Haskovo", "Dobrinishte", "Varvara", "Oryahovo", "Troyan",
158 "Lovech", "Sliven", 0
161 static const char *const shkgeneral[] = {
162 /* Suriname */
163 "Hebiwerie", "Possogroenoe", "Asidonhopo", "Manlobbi",
164 "Adjama", "Pakka Pakka", "Kabalebo", "Wonotobo",
165 "Akalapi", "Sipaliwini",
166 /* Greenland */
167 "Annootok", "Upernavik", "Angmagssalik",
168 /* N. Canada */
169 "Aklavik", "Inuvik", "Tuktoyaktuk", "Chicoutimi",
170 "Ouiatchouane", "Chibougamau", "Matagami", "Kipawa",
171 "Kinojevis", "Abitibi", "Maganasipi",
172 /* Iceland */
173 "Akureyri", "Kopasker", "Budereyri", "Akranes",
174 "Bordeyri", "Holmavik", 0
177 static const char *const shkhealthfoods[] = {
178 /* Tibet */
179 "Ga'er", "Zhangmu", "Rikaze", "Jiangji", "Changdu",
180 "Linzhi", "Shigatse", "Gyantse", "Ganden", "Tsurphu",
181 "Lhasa", "Tsedong", "Drepung",
182 /* Hippie names */
183 "=Azura", "=Blaze", "=Breanna", "=Breezy", "=Dharma",
184 "=Feather", "=Jasmine", "=Luna", "=Melody", "=Moonjava",
185 "=Petal", "=Rhiannon", "=Starla", "=Tranquilla", "=Windsong",
186 "=Zennia", "=Zoe", "=Zora", 0
190 * To add new shop types, all that is necessary is to edit the shtypes[]
191 * array. See mkroom.h for the structure definition. Typically, you'll
192 * have to lower some or all of the probability fields in old entries to
193 * free up some percentage for the new type.
195 * The placement type field is not yet used but will be in the near future.
197 * The iprobs array in each entry defines the probabilities for various kinds
198 * of objects to be present in the given shop type. You can associate with
199 * each percentage either a generic object type (represented by one of the
200 * *_CLASS macros) or a specific object (represented by an onames.h define).
201 * In the latter case, prepend it with a unary minus so the code can know
202 * (by testing the sign) whether to use mkobj() or mksobj().
204 const struct shclass shtypes[] = {
205 { "general store",
206 RANDOM_CLASS,
208 D_SHOP,
209 { { 100, RANDOM_CLASS },
210 { 0, 0 },
211 { 0, 0 },
212 { 0, 0 },
213 { 0, 0 },
214 { 0, 0 } },
215 shkgeneral },
216 { "used armor dealership",
217 ARMOR_CLASS,
219 D_SHOP,
220 { { 90, ARMOR_CLASS },
221 { 10, WEAPON_CLASS },
222 { 0, 0 },
223 { 0, 0 },
224 { 0, 0 },
225 { 0, 0 } },
226 shkarmors },
227 { "second-hand bookstore",
228 SCROLL_CLASS,
230 D_SHOP,
231 { { 90, SCROLL_CLASS },
232 { 10, SPBOOK_CLASS },
233 { 0, 0 },
234 { 0, 0 },
235 { 0, 0 },
236 { 0, 0 } },
237 shkbooks },
238 { "liquor emporium",
239 POTION_CLASS,
241 D_SHOP,
242 { { 100, POTION_CLASS },
243 { 0, 0 },
244 { 0, 0 },
245 { 0, 0 },
246 { 0, 0 },
247 { 0, 0 } },
248 shkliquors },
249 { "antique weapons outlet",
250 WEAPON_CLASS,
252 D_SHOP,
253 { { 90, WEAPON_CLASS },
254 { 10, ARMOR_CLASS },
255 { 0, 0 },
256 { 0, 0 },
257 { 0, 0 },
258 { 0, 0 } },
259 shkweapons },
260 { "delicatessen",
261 FOOD_CLASS,
263 D_SHOP,
264 { { 83, FOOD_CLASS },
265 { 5, -POT_FRUIT_JUICE },
266 { 4, -POT_BOOZE },
267 { 5, -POT_WATER },
268 { 3, -ICE_BOX },
269 { 0, 0 } },
270 shkfoods },
271 { "jewelers",
272 RING_CLASS,
274 D_SHOP,
275 { { 85, RING_CLASS },
276 { 10, GEM_CLASS },
277 { 5, AMULET_CLASS },
278 { 0, 0 },
279 { 0, 0 },
280 { 0, 0 } },
281 shkrings },
282 { "quality apparel and accessories",
283 WAND_CLASS,
285 D_SHOP,
286 { { 90, WAND_CLASS },
287 { 5, -LEATHER_GLOVES },
288 { 5, -ELVEN_CLOAK },
289 { 0, 0 } },
290 shkwands },
291 { "hardware store",
292 TOOL_CLASS,
294 D_SHOP,
295 { { 100, TOOL_CLASS },
296 { 0, 0 },
297 { 0, 0 },
298 { 0, 0 },
299 { 0, 0 },
300 { 0, 0 } },
301 shktools },
302 { "rare books",
303 SPBOOK_CLASS,
305 D_SHOP,
306 { { 90, SPBOOK_CLASS },
307 { 10, SCROLL_CLASS },
308 { 0, 0 },
309 { 0, 0 },
310 { 0, 0 },
311 { 0, 0 } },
312 shkbooks },
313 { "health food store",
314 FOOD_CLASS,
316 D_SHOP,
317 { { 70, VEGETARIAN_CLASS },
318 { 20, -POT_FRUIT_JUICE },
319 { 4, -POT_HEALING },
320 { 3, -POT_FULL_HEALING },
321 { 2, -SCR_FOOD_DETECTION },
322 { 1, -LUMP_OF_ROYAL_JELLY } },
323 shkhealthfoods },
324 /* Shops below this point are "unique". That is they must all have a
325 * probability of zero. They are only created via the special level
326 * loader.
328 { "lighting store",
329 TOOL_CLASS,
331 D_SHOP,
332 { { 30, -WAX_CANDLE },
333 { 48, -TALLOW_CANDLE },
334 { 5, -BRASS_LANTERN },
335 { 9, -OIL_LAMP },
336 { 3, -MAGIC_LAMP },
337 { 5, -POT_OIL } },
338 shklight },
339 /* sentinel */
340 { (char *) 0,
344 { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
348 #if 0
349 /* validate shop probabilities; otherwise incorrect local changes could
350 end up provoking infinite loops or wild subscripts fetching garbage */
351 void
352 init_shop_selection()
354 register int i, j, item_prob, shop_prob;
356 for (shop_prob = 0, i = 0; i < SIZE(shtypes); i++) {
357 shop_prob += shtypes[i].prob;
358 for (item_prob = 0, j = 0; j < SIZE(shtypes[0].iprobs); j++)
359 item_prob += shtypes[i].iprobs[j].iprob;
360 if (item_prob != 100)
361 panic("item probabilities total to %d for %s shops!",
362 item_prob, shtypes[i].name);
364 if (shop_prob != 100)
365 panic("shop probabilities total to %d!", shop_prob);
367 #endif /*0*/
369 /* decide whether an object or object type is considered vegetarian;
370 for types, items which might go either way are assumed to be veggy */
371 STATIC_OVL boolean
372 veggy_item(obj, otyp)
373 struct obj *obj;
374 int otyp; /* used iff obj is null */
376 int corpsenm;
377 char oclass;
379 if (obj) {
380 /* actual object; will check tin content and corpse species */
381 otyp = (int) obj->otyp;
382 oclass = obj->oclass;
383 corpsenm = obj->corpsenm;
384 } else {
385 /* just a type; caller will have to handle tins and corpses */
386 oclass = objects[otyp].oc_class;
387 corpsenm = PM_LICHEN; /* veggy standin */
390 if (oclass == FOOD_CLASS) {
391 if (objects[otyp].oc_material == VEGGY || otyp == EGG)
392 return TRUE;
393 if (otyp == TIN && corpsenm == NON_PM) /* implies obj is non-null */
394 return (boolean) (obj->spe == 1); /* 0 = empty, 1 = spinach */
395 if (otyp == TIN || otyp == CORPSE)
396 return (boolean) (corpsenm >= LOW_PM
397 && vegetarian(&mons[corpsenm]));
399 return FALSE;
402 STATIC_OVL int
403 shkveg()
405 int i, j, maxprob, prob;
406 char oclass = FOOD_CLASS;
407 int ok[NUM_OBJECTS];
409 j = maxprob = 0;
410 ok[0] = 0; /* lint suppression */
411 for (i = bases[(int) oclass]; i < NUM_OBJECTS; ++i) {
412 if (objects[i].oc_class != oclass)
413 break;
415 if (veggy_item((struct obj *) 0, i)) {
416 ok[j++] = i;
417 maxprob += objects[i].oc_prob;
420 if (maxprob < 1)
421 panic("shkveg no veggy objects");
422 prob = rnd(maxprob);
424 j = 0;
425 i = ok[0];
426 while ((prob -= objects[i].oc_prob) > 0) {
427 j++;
428 i = ok[j];
431 if (objects[i].oc_class != oclass || !OBJ_NAME(objects[i]))
432 panic("shkveg probtype error, oclass=%d i=%d", (int) oclass, i);
433 return i;
436 /* make a random item for health food store */
437 STATIC_OVL void
438 mkveggy_at(sx, sy)
439 int sx, sy;
441 struct obj *obj = mksobj_at(shkveg(), sx, sy, TRUE, TRUE);
443 if (obj && obj->otyp == TIN)
444 set_tin_variety(obj, HEALTHY_TIN);
445 return;
448 /* make an object of the appropriate type for a shop square */
449 STATIC_OVL void
450 mkshobj_at(shp, sx, sy, mkspecl)
451 const struct shclass *shp;
452 int sx, sy;
453 boolean mkspecl;
455 struct monst *mtmp;
456 struct permonst *ptr;
457 int atype;
459 /* 3.6 tribute */
460 if (mkspecl && (!strcmp(shp->name, "rare books")
461 || !strcmp(shp->name, "second-hand bookstore"))) {
462 struct obj *novel = mksobj_at(SPE_NOVEL, sx, sy, FALSE, FALSE);
464 if (novel)
465 context.tribute.bookstock = TRUE;
466 return;
469 if (rn2(100) < depth(&u.uz) && !MON_AT(sx, sy)
470 && (ptr = mkclass(S_MIMIC, 0)) != 0
471 && (mtmp = makemon(ptr, sx, sy, NO_MM_FLAGS)) != 0) {
472 /* note: makemon will set the mimic symbol to a shop item */
473 if (rn2(10) >= depth(&u.uz)) {
474 mtmp->m_ap_type = M_AP_OBJECT;
475 mtmp->mappearance = STRANGE_OBJECT;
477 } else {
478 atype = get_shop_item((int) (shp - shtypes));
479 if (atype == VEGETARIAN_CLASS)
480 mkveggy_at(sx, sy);
481 else if (atype < 0)
482 (void) mksobj_at(-atype, sx, sy, TRUE, TRUE);
483 else
484 (void) mkobj_at(atype, sx, sy, TRUE);
488 /* extract a shopkeeper name for the given shop type */
489 STATIC_OVL void
490 nameshk(shk, nlp)
491 struct monst *shk;
492 const char *const *nlp;
494 int i, trycnt, names_avail;
495 const char *shname = 0;
496 struct monst *mtmp;
497 int name_wanted;
498 s_level *sptr;
500 if (nlp == shkfoods && In_mines(&u.uz) && Role_if(PM_MONK)
501 && (sptr = Is_special(&u.uz)) != 0 && sptr->flags.town) {
502 /* special-case override for minetown food store for monks */
503 nlp = shkhealthfoods;
506 if (nlp == shklight && In_mines(&u.uz) && (sptr = Is_special(&u.uz)) != 0
507 && sptr->flags.town) {
508 /* special-case minetown lighting shk */
509 shname = "+Izchak";
510 shk->female = FALSE;
511 } else {
512 /* We want variation from game to game, without needing the save
513 and restore support which would be necessary for randomization;
514 try not to make too many assumptions about time_t's internals;
515 use ledger_no rather than depth to keep mine town distinct. */
516 int nseed = (int) ((long) ubirthday / 257L);
518 name_wanted = ledger_no(&u.uz) + (nseed % 13) - (nseed % 5);
519 if (name_wanted < 0)
520 name_wanted += (13 + 5);
521 shk->female = name_wanted & 1;
523 for (names_avail = 0; nlp[names_avail]; names_avail++)
524 continue;
526 for (trycnt = 0; trycnt < 50; trycnt++) {
527 if (nlp == shktools) {
528 shname = shktools[rn2(names_avail)];
529 shk->female = 0; /* reversed below for '_' prefix */
530 } else if (name_wanted < names_avail) {
531 shname = nlp[name_wanted];
532 } else if ((i = rn2(names_avail)) != 0) {
533 shname = nlp[i - 1];
534 } else if (nlp != shkgeneral) {
535 nlp = shkgeneral; /* try general names */
536 for (names_avail = 0; nlp[names_avail]; names_avail++)
537 continue;
538 continue; /* next `trycnt' iteration */
539 } else {
540 shname = shk->female ? "-Lucrezia" : "+Dirk";
542 if (*shname == '_' || *shname == '-')
543 shk->female = 1;
544 else if (*shname == '|' || *shname == '+')
545 shk->female = 0;
547 /* is name already in use on this level? */
548 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
549 if (DEADMONSTER(mtmp) || (mtmp == shk) || !mtmp->isshk)
550 continue;
551 if (strcmp(ESHK(mtmp)->shknam, shname))
552 continue;
553 break;
555 if (!mtmp)
556 break; /* new name */
559 (void) strncpy(ESHK(shk)->shknam, shname, PL_NSIZ);
560 ESHK(shk)->shknam[PL_NSIZ - 1] = 0;
563 void
564 neweshk(mtmp)
565 struct monst *mtmp;
567 if (!mtmp->mextra)
568 mtmp->mextra = newmextra();
569 if (!ESHK(mtmp))
570 ESHK(mtmp) = (struct eshk *) alloc(sizeof(struct eshk));
571 (void) memset((genericptr_t) ESHK(mtmp), 0, sizeof(struct eshk));
572 ESHK(mtmp)->bill_p = (struct bill_x *) 0;
575 void
576 free_eshk(mtmp)
577 struct monst *mtmp;
579 if (mtmp->mextra && ESHK(mtmp)) {
580 free((genericptr_t) ESHK(mtmp));
581 ESHK(mtmp) = (struct eshk *) 0;
583 mtmp->isshk = 0;
586 /* create a new shopkeeper in the given room */
587 STATIC_OVL int
588 shkinit(shp, sroom)
589 const struct shclass *shp;
590 struct mkroom *sroom;
592 register int sh, sx, sy;
593 struct monst *shk;
594 struct eshk *eshkp;
596 /* place the shopkeeper in the given room */
597 sh = sroom->fdoor;
598 sx = doors[sh].x;
599 sy = doors[sh].y;
601 /* check that the shopkeeper placement is sane */
602 if (sroom->irregular) {
603 int rmno = (int) ((sroom - rooms) + ROOMOFFSET);
604 if (isok(sx - 1, sy) && !levl[sx - 1][sy].edge
605 && (int) levl[sx - 1][sy].roomno == rmno)
606 sx--;
607 else if (isok(sx + 1, sy) && !levl[sx + 1][sy].edge
608 && (int) levl[sx + 1][sy].roomno == rmno)
609 sx++;
610 else if (isok(sx, sy - 1) && !levl[sx][sy - 1].edge
611 && (int) levl[sx][sy - 1].roomno == rmno)
612 sy--;
613 else if (isok(sx, sy + 1) && !levl[sx][sy + 1].edge
614 && (int) levl[sx][sy + 1].roomno == rmno)
615 sx++;
616 else
617 goto shk_failed;
618 } else if (sx == sroom->lx - 1)
619 sx++;
620 else if (sx == sroom->hx + 1)
621 sx--;
622 else if (sy == sroom->ly - 1)
623 sy++;
624 else if (sy == sroom->hy + 1)
625 sy--;
626 else {
627 shk_failed:
628 #ifdef DEBUG
629 /* Said to happen sometimes, but I have never seen it. */
630 /* Supposedly fixed by fdoor change in mklev.c */
631 if (wizard) {
632 register int j = sroom->doorct;
634 pline("Where is shopdoor?");
635 pline("Room at (%d,%d),(%d,%d).", sroom->lx, sroom->ly, sroom->hx,
636 sroom->hy);
637 pline("doormax=%d doorct=%d fdoor=%d", doorindex, sroom->doorct,
638 sh);
639 while (j--) {
640 pline("door [%d,%d]", doors[sh].x, doors[sh].y);
641 sh++;
643 display_nhwindow(WIN_MESSAGE, FALSE);
645 #endif
646 return -1;
649 if (MON_AT(sx, sy))
650 (void) rloc(m_at(sx, sy), FALSE); /* insurance */
652 /* now initialize the shopkeeper monster structure */
653 if (!(shk = makemon(&mons[PM_SHOPKEEPER], sx, sy, MM_ESHK)))
654 return -1;
655 eshkp = ESHK(shk); /* makemon(...,MM_ESHK) allocates this */
656 shk->isshk = shk->mpeaceful = 1;
657 set_malign(shk);
658 shk->msleeping = 0;
659 shk->mtrapseen = ~0; /* we know all the traps already */
660 eshkp->shoproom = (schar) ((sroom - rooms) + ROOMOFFSET);
661 sroom->resident = shk;
662 eshkp->shoptype = sroom->rtype;
663 assign_level(&eshkp->shoplevel, &u.uz);
664 eshkp->shd = doors[sh];
665 eshkp->shk.x = sx;
666 eshkp->shk.y = sy;
667 eshkp->robbed = eshkp->credit = eshkp->debit = eshkp->loan = 0L;
668 eshkp->following = eshkp->surcharge = eshkp->dismiss_kops = FALSE;
669 eshkp->billct = eshkp->visitct = 0;
670 eshkp->bill_p = (struct bill_x *) 0;
671 eshkp->customer[0] = '\0';
672 mkmonmoney(shk, 1000L + 30L * (long) rnd(100)); /* initial capital */
673 if (shp->shknms == shkrings)
674 (void) mongets(shk, TOUCHSTONE);
675 nameshk(shk, shp->shknms);
677 return sh;
680 STATIC_OVL boolean
681 stock_room_goodpos(sroom, rmno, sh, sx, sy)
682 struct mkroom *sroom;
683 int rmno, sh, sx,sy;
685 if (sroom->irregular) {
686 if (levl[sx][sy].edge
687 || (int) levl[sx][sy].roomno != rmno
688 || distmin(sx, sy, doors[sh].x, doors[sh].y) <= 1)
689 return FALSE;
690 } else if ((sx == sroom->lx && doors[sh].x == sx - 1)
691 || (sx == sroom->hx && doors[sh].x == sx + 1)
692 || (sy == sroom->ly && doors[sh].y == sy - 1)
693 || (sy == sroom->hy && doors[sh].y == sy + 1))
694 return FALSE;
695 return TRUE;
698 /* stock a newly-created room with objects */
699 void
700 stock_room(shp_indx, sroom)
701 int shp_indx;
702 register struct mkroom *sroom;
705 * Someday soon we'll dispatch on the shdist field of shclass to do
706 * different placements in this routine. Currently it only supports
707 * shop-style placement (all squares except a row nearest the first
708 * door get objects).
710 int sx, sy, sh;
711 int stockcount = 0, specialspot = 0;
712 char buf[BUFSZ];
713 int rmno = (int) ((sroom - rooms) + ROOMOFFSET);
714 const struct shclass *shp = &shtypes[shp_indx];
716 /* first, try to place a shopkeeper in the room */
717 if ((sh = shkinit(shp, sroom)) < 0)
718 return;
720 /* make sure no doorways without doors, and no trapped doors, in shops */
721 sx = doors[sroom->fdoor].x;
722 sy = doors[sroom->fdoor].y;
723 if (levl[sx][sy].doormask == D_NODOOR) {
724 levl[sx][sy].doormask = D_ISOPEN;
725 newsym(sx, sy);
727 if (levl[sx][sy].typ == SDOOR) {
728 cvt_sdoor_to_door(&levl[sx][sy]); /* .typ = DOOR */
729 newsym(sx, sy);
731 if (levl[sx][sy].doormask & D_TRAPPED)
732 levl[sx][sy].doormask = D_LOCKED;
734 if (levl[sx][sy].doormask == D_LOCKED) {
735 register int m = sx, n = sy;
737 if (inside_shop(sx + 1, sy))
738 m--;
739 else if (inside_shop(sx - 1, sy))
740 m++;
741 if (inside_shop(sx, sy + 1))
742 n--;
743 else if (inside_shop(sx, sy - 1))
744 n++;
745 Sprintf(buf, "Closed for inventory");
746 make_engr_at(m, n, buf, 0L, DUST);
749 if (context.tribute.enabled && !context.tribute.bookstock) {
751 * Out of the number of spots where we're actually
752 * going to put stuff, randomly single out one in particular.
754 for (sx = sroom->lx; sx <= sroom->hx; sx++)
755 for (sy = sroom->ly; sy <= sroom->hy; sy++)
756 if (stock_room_goodpos(sroom, rmno, sh, sx,sy))
757 stockcount++;
758 specialspot = rnd(stockcount);
759 stockcount = 0;
762 for (sx = sroom->lx; sx <= sroom->hx; sx++)
763 for (sy = sroom->ly; sy <= sroom->hy; sy++)
764 if (stock_room_goodpos(sroom, rmno, sh, sx,sy)) {
765 stockcount++;
766 mkshobj_at(shp, sx, sy,
767 ((stockcount) && (stockcount == specialspot)));
771 * Special monster placements (if any) should go here: that way,
772 * monsters will sit on top of objects and not the other way around.
775 level.flags.has_shop = TRUE;
778 /* does shkp's shop stock this item type? */
779 boolean
780 saleable(shkp, obj)
781 struct monst *shkp;
782 struct obj *obj;
784 int i, shp_indx = ESHK(shkp)->shoptype - SHOPBASE;
785 const struct shclass *shp = &shtypes[shp_indx];
787 if (shp->symb == RANDOM_CLASS)
788 return TRUE;
789 for (i = 0; i < SIZE(shtypes[0].iprobs) && shp->iprobs[i].iprob; i++) {
790 /* pseudo-class needs special handling */
791 if (shp->iprobs[i].itype == VEGETARIAN_CLASS) {
792 if (veggy_item(obj, 0))
793 return TRUE;
794 } else if ((shp->iprobs[i].itype < 0)
795 ? shp->iprobs[i].itype == -obj->otyp
796 : shp->iprobs[i].itype == obj->oclass)
797 return TRUE;
799 /* not found */
800 return FALSE;
803 /* positive value: class; negative value: specific object type */
805 get_shop_item(type)
806 int type;
808 const struct shclass *shp = shtypes + type;
809 register int i, j;
811 /* select an appropriate object type at random */
812 for (j = rnd(100), i = 0; (j -= shp->iprobs[i].iprob) > 0; i++)
813 continue;
815 return shp->iprobs[i].itype;
818 /* version of shkname() for beginning of sentence */
819 char *
820 Shknam(mtmp)
821 struct monst *mtmp;
823 char *nam = shkname(mtmp);
825 /* 'nam[]' is almost certainly already capitalized, but be sure */
826 nam[0] = highc(nam[0]);
827 return nam;
830 /* shopkeeper's name, without any visibility constraint; if hallucinating,
831 will yield some other shopkeeper's name (not necessarily one residing
832 in the current game's dungeon, or who keeps same type of shop) */
833 char *
834 shkname(mtmp)
835 struct monst *mtmp;
837 char *nam;
838 unsigned save_isshk = mtmp->isshk;
840 mtmp->isshk = 0; /* don't want mon_nam() calling shkname() */
841 /* get a modifiable name buffer along with fallback result */
842 nam = noit_mon_nam(mtmp);
843 mtmp->isshk = save_isshk;
845 if (!mtmp->isshk) {
846 impossible("shkname: \"%s\" is not a shopkeeper.", nam);
847 } else if (!has_eshk(mtmp)) {
848 panic("shkname: shopkeeper \"%s\" lacks 'eshk' data.", nam);
849 } else {
850 const char *shknm = ESHK(mtmp)->shknam;
852 if (Hallucination && !program_state.gameover) {
853 const char *const *nlp;
854 int num;
856 /* count the number of non-unique shop types;
857 pick one randomly, ignoring shop generation probabilities;
858 pick a name at random from that shop type's list */
859 for (num = 0; num < SIZE(shtypes); num++)
860 if (shtypes[num].prob == 0)
861 break;
862 if (num > 0) {
863 nlp = shtypes[rn2(num)].shknms;
864 for (num = 0; nlp[num]; num++)
865 continue;
866 if (num > 0)
867 shknm = nlp[rn2(num)];
870 /* strip prefix if present */
871 if (!letter(*shknm))
872 ++shknm;
873 Strcpy(nam, shknm);
875 return nam;
878 boolean
879 shkname_is_pname(mtmp)
880 struct monst *mtmp;
882 const char *shknm = ESHK(mtmp)->shknam;
884 return (boolean) (*shknm == '-' || *shknm == '+' || *shknm == '=');
887 boolean
888 is_izchak(shkp, override_hallucination)
889 struct monst *shkp;
890 boolean override_hallucination;
892 const char *shknm;
894 if (Hallucination && !override_hallucination)
895 return FALSE;
896 if (!shkp->isshk)
897 return FALSE;
898 /* outside of town, Izchak becomes just an ordinary shopkeeper */
899 if (!in_town(shkp->mx, shkp->my))
900 return FALSE;
901 shknm = ESHK(shkp)->shknam;
902 /* skip "+" prefix */
903 if (!letter(*shknm))
904 ++shknm;
905 return (boolean) !strcmp(shknm, "Izchak");
908 /*shknam.c*/