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