1 /* SCCS Id: @(#)shknam.c 3.4 2003/01/09 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 /* shknam.c -- initialize a shop */
11 extern const struct shclass shtypes[];
15 STATIC_DCL void FDECL(mkshobj_at, (const struct shclass *,int,int));
16 STATIC_DCL void FDECL(nameshk, (struct monst *,const char * const *));
17 STATIC_DCL int FDECL(shkinit, (const struct shclass *,struct mkroom *));
19 static const char * const shkliquors[] = {
21 "Njezjin", "Tsjernigof", "Ossipewsk", "Gorlowka",
25 "Konosja", "Weliki Oestjoeg", "Syktywkar", "Sablja",
28 "Walbrzych", "Swidnica", "Klodzko", "Raciborz", "Gliwice",
29 "Brzeg", "Krnov", "Hradec Kralove",
31 "Leuk", "Brig", "Brienz", "Thun", "Sarnen", "Burglen", "Elm",
32 "Flims", "Vals", "Schuls", "Zum Loch",
36 static const char * const shkbooks[] = {
38 "Skibbereen", "Kanturk", "Rath Luirc", "Ennistymon", "Lahinch",
39 "Kinnegad", "Lugnaquillia", "Enniscorthy", "Gweebarra",
40 "Kittamagh", "Nenagh", "Sneem", "Ballingeary", "Kilgarvan",
41 "Cahersiveen", "Glenbeigh", "Kilmihil", "Kiltamagh",
42 "Droichead Atha", "Inniscrone", "Clonegal", "Lisnaskea",
43 "Culdaff", "Dunfanaghy", "Inishbofin", "Kesh",
47 static const char * const shkarmors[] = {
49 "Demirci", "Kalecik", "Boyabai", "Yildizeli", "Gaziantep",
50 "Siirt", "Akhalataki", "Tirebolu", "Aksaray", "Ermenak",
51 "Iskenderun", "Kadirli", "Siverek", "Pervari", "Malasgirt",
52 "Bayburt", "Ayancik", "Zonguldak", "Balya", "Tefenni",
53 "Artvin", "Kars", "Makharadze", "Malazgirt", "Midyat",
54 "Birecik", "Kirikkale", "Alaca", "Polatli", "Nallihan",
58 static const char * const shkwands[] = {
60 "Yr Wyddgrug", "Trallwng", "Mallwyd", "Pontarfynach",
61 "Rhaeader", "Llandrindod", "Llanfair-ym-muallt",
62 "Y-Fenni", "Maesteg", "Rhydaman", "Beddgelert",
63 "Curig", "Llanrwst", "Llanerchymedd", "Caergybi",
65 "Nairn", "Turriff", "Inverurie", "Braemar", "Lochnagar",
66 "Kerloch", "Beinn a Ghlo", "Drumnadrochit", "Morven",
67 "Uist", "Storr", "Sgurr na Ciche", "Cannich", "Gairloch",
68 "Kyleakin", "Dunvegan",
72 static const char * const shkrings[] = {
73 /* Hollandse familienamen */
74 "Feyfer", "Flugi", "Gheel", "Havic", "Haynin", "Hoboken",
75 "Imbyze", "Juyn", "Kinsky", "Massis", "Matray", "Moy",
76 "Olycan", "Sadelin", "Svaving", "Tapper", "Terwen", "Wirix",
78 /* Skandinaviske navne */
79 "Rastegaisa", "Varjag Njarga", "Kautekeino", "Abisko",
80 "Enontekis", "Rovaniemi", "Avasaksa", "Haparanda",
81 "Lulea", "Gellivare", "Oeloe", "Kajaani", "Fauske",
85 static const char * const shkfoods[] = {
87 "Djasinga", "Tjibarusa", "Tjiwidej", "Pengalengan",
88 "Bandjar", "Parbalingga", "Bojolali", "Sarangan",
89 "Ngebel", "Djombang", "Ardjawinangun", "Berbek",
90 "Papar", "Baliga", "Tjisolok", "Siboga", "Banjoewangi",
91 "Trenggalek", "Karangkobar", "Njalindoeng", "Pasawahan",
92 "Pameunpeuk", "Patjitan", "Kediri", "Pemboeang", "Tringanoe",
93 "Makin", "Tipor", "Semai", "Berhala", "Tegal", "Samoe",
97 static const char * const shkweapons[] = {
99 "Voulgezac", "Rouffiac", "Lerignac", "Touverac", "Guizengeard",
100 "Melac", "Neuvicq", "Vanzac", "Picq", "Urignac", "Corignac",
101 "Fleac", "Lonzac", "Vergt", "Queyssac", "Liorac", "Echourgnac",
102 "Cazelon", "Eypau", "Carignan", "Monbazillac", "Jonzac",
103 "Pons", "Jumilhac", "Fenouilledes", "Laguiolet", "Saujon",
104 "Eymoutiers", "Eygurande", "Eauze", "Labouheyre",
108 static const char * const shktools[] = {
110 "Ymla", "Eed-morra", "Cubask", "Nieb", "Bnowr Falr", "Telloc Cyaj",
111 "Sperc", "Noskcirdneh", "Yawolloh", "Hyeghu", "Niskal", "Trahnil",
112 "Htargcm", "Enrobwem", "Kachzi Rellim", "Regien", "Donmyar",
113 "Yelpur", "Nosnehpets", "Stewe", "Renrut", "_Zlaw", "Nosalnef",
114 "Rewuorb", "Rellenk", "Yad", "Cire Htims", "Y-crad", "Nenilukah",
117 "Erreip", "Nehpets", "Mron", "Snivek", "Lapu", "Kahztiy",
120 "Lechaim", "Lexa", "Niod",
123 "Nhoj-lee", "Evad\'kh", "Ettaw-noj", "Tsew-mot", "Ydna-s",
124 "Yao-hang", "Tonbar", "Kivenhoug",
127 "Falo", "Nosid-da\'r", "Ekim-p", "Rebrol-nek", "Noslo", "Yl-rednow",
128 "Mured-oog", "Ivrajimsal",
134 "Lez-tneg", "Ytnu-haled", "Niknar",
139 static const char * const shklight[] = {
141 "Zarnesti", "Slanic", "Nehoiasu", "Ludus", "Sighisoara", "Nisipitu",
142 "Razboieni", "Bicaz", "Dorohoi", "Vaslui", "Fetesti", "Tirgu Neamt",
143 "Babadag", "Zimnicea", "Zlatna", "Jiu", "Eforie", "Mamaia",
145 "Silistra", "Tulovo", "Panagyuritshte", "Smolyan", "Kirklareli",
146 "Pernik", "Lom", "Haskovo", "Dobrinishte", "Varvara", "Oryahovo",
147 "Troyan", "Lovech", "Sliven",
151 static const char * const shkgeneral[] = {
153 "Hebiwerie", "Possogroenoe", "Asidonhopo", "Manlobbi",
154 "Adjama", "Pakka Pakka", "Kabalebo", "Wonotobo",
155 "Akalapi", "Sipaliwini",
157 "Annootok", "Upernavik", "Angmagssalik",
159 "Aklavik", "Inuvik", "Tuktoyaktuk",
160 "Chicoutimi", "Ouiatchouane", "Chibougamau",
161 "Matagami", "Kipawa", "Kinojevis",
162 "Abitibi", "Maganasipi",
164 "Akureyri", "Kopasker", "Budereyri", "Akranes", "Bordeyri",
170 * To add new shop types, all that is necessary is to edit the shtypes[] array.
171 * See mkroom.h for the structure definition. Typically, you'll have to lower
172 * some or all of the probability fields in old entries to free up some
173 * percentage for the new type.
175 * The placement type field is not yet used but will be in the near future.
177 * The iprobs array in each entry defines the probabilities for various kinds
178 * of objects to be present in the given shop type. You can associate with
179 * each percentage either a generic object type (represented by one of the
180 * *_CLASS macros) or a specific object (represented by an onames.h define).
181 * In the latter case, prepend it with a unary minus so the code can know
182 * (by testing the sign) whether to use mkobj() or mksobj().
185 const struct shclass shtypes[] = {
186 {"general store", RANDOM_CLASS, 44,
187 D_SHOP, {{100, RANDOM_CLASS}, {0, 0}, {0, 0}}, shkgeneral},
188 {"used armor dealership", ARMOR_CLASS, 14,
189 D_SHOP, {{90, ARMOR_CLASS}, {10, WEAPON_CLASS}, {0, 0}},
191 {"second-hand bookstore", SCROLL_CLASS, 10, D_SHOP,
192 {{90, SCROLL_CLASS}, {10, SPBOOK_CLASS}, {0, 0}}, shkbooks},
193 {"liquor emporium", POTION_CLASS, 10, D_SHOP,
194 {{100, POTION_CLASS}, {0, 0}, {0, 0}}, shkliquors},
195 {"antique weapons outlet", WEAPON_CLASS, 5, D_SHOP,
196 {{90, WEAPON_CLASS}, {10, ARMOR_CLASS}, {0, 0}}, shkweapons},
197 {"delicatessen", FOOD_CLASS, 5, D_SHOP,
198 {{83, FOOD_CLASS}, {5, -POT_FRUIT_JUICE}, {4, -POT_BOOZE},
199 {5, -POT_WATER}, {3, -ICE_BOX}}, shkfoods},
200 {"jewelers", RING_CLASS, 3, D_SHOP,
201 {{85, RING_CLASS}, {10, GEM_CLASS}, {5, AMULET_CLASS}, {0, 0}},
203 {"quality apparel and accessories", WAND_CLASS, 3, D_SHOP,
204 {{90, WAND_CLASS}, {5, -LEATHER_GLOVES}, {5, -ELVEN_CLOAK}, {0, 0}},
206 {"hardware store", TOOL_CLASS, 3, D_SHOP,
207 {{100, TOOL_CLASS}, {0, 0}, {0, 0}}, shktools},
208 /* Actually shktools is ignored; the code specifically chooses a
209 * random implementor name (along with candle shops having
210 * random shopkeepers)
212 {"rare books", SPBOOK_CLASS, 3, D_SHOP,
213 {{90, SPBOOK_CLASS}, {10, SCROLL_CLASS}, {0, 0}}, shkbooks},
214 /* Shops below this point are "unique". That is they must all have a
215 * probability of zero. They are only created via the special level
218 {"lighting store", TOOL_CLASS, 0, D_SHOP,
219 {{32, -WAX_CANDLE}, {50, -TALLOW_CANDLE},
220 {5, -BRASS_LANTERN}, {10, -OIL_LAMP}, {3, -MAGIC_LAMP}}, shklight},
221 {(char *)0, 0, 0, 0, {{0, 0}, {0, 0}, {0, 0}}, 0}
225 /* validate shop probabilities; otherwise incorrect local changes could
226 end up provoking infinite loops or wild subscripts fetching garbage */
228 init_shop_selection()
230 register int i, j, item_prob, shop_prob;
232 for (shop_prob = 0, i = 0; i < SIZE(shtypes); i++) {
233 shop_prob += shtypes[i].prob;
234 for (item_prob = 0, j = 0; j < SIZE(shtypes[0].iprobs); j++)
235 item_prob += shtypes[i].iprobs[j].iprob;
236 if (item_prob != 100)
237 panic("item probabilities total to %d for %s shops!",
238 item_prob, shtypes[i].name);
240 if (shop_prob != 100)
241 panic("shop probabilities total to %d!", shop_prob);
246 mkshobj_at(shp, sx, sy)
247 /* make an object of the appropriate type for a shop square */
248 const struct shclass *shp;
253 struct permonst *ptr;
255 if (rn2(100) < depth(&u.uz) &&
256 !MON_AT(sx, sy) && (ptr = mkclass(S_MIMIC,0)) &&
257 (mtmp = makemon(ptr,sx,sy,NO_MM_FLAGS)) != 0) {
258 /* note: makemon will set the mimic symbol to a shop item */
259 if (rn2(10) >= depth(&u.uz)) {
260 mtmp->m_ap_type = M_AP_OBJECT;
261 mtmp->mappearance = STRANGE_OBJECT;
264 atype = get_shop_item(shp - shtypes);
266 (void) mksobj_at(-atype, sx, sy, TRUE, TRUE);
268 (void) mkobj_at(atype, sx, sy, TRUE);
272 /* extract a shopkeeper name for the given shop type */
276 const char * const *nlp;
278 int i, trycnt, names_avail;
279 const char *shname = 0;
284 if (nlp == shklight && In_mines(&u.uz)
285 && (sptr = Is_special(&u.uz)) != 0 && sptr->flags.town) {
286 /* special-case minetown lighting shk */
290 /* We want variation from game to game, without needing the save
291 and restore support which would be necessary for randomization;
292 try not to make too many assumptions about time_t's internals;
293 use ledger_no rather than depth to keep mine town distinct. */
294 int nseed = (int)((long)u.ubirthday / 257L);
296 name_wanted = ledger_no(&u.uz) + (nseed % 13) - (nseed % 5);
297 if (name_wanted < 0) name_wanted += (13 + 5);
298 shk->female = name_wanted & 1;
300 for (names_avail = 0; nlp[names_avail]; names_avail++)
303 for (trycnt = 0; trycnt < 50; trycnt++) {
304 if (nlp == shktools) {
305 shname = shktools[rn2(names_avail)];
306 shk->female = (*shname == '_');
307 if (shk->female) shname++;
308 } else if (name_wanted < names_avail) {
309 shname = nlp[name_wanted];
310 } else if ((i = rn2(names_avail)) != 0) {
312 } else if (nlp != shkgeneral) {
313 nlp = shkgeneral; /* try general names */
314 for (names_avail = 0; nlp[names_avail]; names_avail++)
316 continue; /* next `trycnt' iteration */
318 shname = shk->female ? "Lucrezia" : "Dirk";
321 /* is name already in use on this level? */
322 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
323 if (DEADMONSTER(mtmp) || (mtmp == shk) || !mtmp->isshk) continue;
324 if (strcmp(ESHK(mtmp)->shknam, shname)) continue;
327 if (!mtmp) break; /* new name */
330 (void) strncpy(ESHK(shk)->shknam, shname, PL_NSIZ);
331 ESHK(shk)->shknam[PL_NSIZ-1] = 0;
335 shkinit(shp, sroom) /* create a new shopkeeper in the given room */
336 const struct shclass *shp;
337 struct mkroom *sroom;
339 register int sh, sx, sy;
342 /* place the shopkeeper in the given room */
347 /* check that the shopkeeper placement is sane */
348 if(sroom->irregular) {
349 int rmno = (sroom - rooms) + ROOMOFFSET;
350 if (isok(sx-1,sy) && !levl[sx-1][sy].edge &&
351 (int) levl[sx-1][sy].roomno == rmno) sx--;
352 else if (isok(sx+1,sy) && !levl[sx+1][sy].edge &&
353 (int) levl[sx+1][sy].roomno == rmno) sx++;
354 else if (isok(sx,sy-1) && !levl[sx][sy-1].edge &&
355 (int) levl[sx][sy-1].roomno == rmno) sy--;
356 else if (isok(sx,sy+1) && !levl[sx][sy+1].edge &&
357 (int) levl[sx][sy+1].roomno == rmno) sx++;
358 else goto shk_failed;
360 else if(sx == sroom->lx-1) sx++;
361 else if(sx == sroom->hx+1) sx--;
362 else if(sy == sroom->ly-1) sy++;
363 else if(sy == sroom->hy+1) sy--; else {
367 /* Said to happen sometimes, but I have never seen it. */
368 /* Supposedly fixed by fdoor change in mklev.c */
370 register int j = sroom->doorct;
372 pline("Where is shopdoor?");
373 pline("Room at (%d,%d),(%d,%d).",
374 sroom->lx, sroom->ly, sroom->hx, sroom->hy);
375 pline("doormax=%d doorct=%d fdoor=%d",
376 doorindex, sroom->doorct, sh);
378 pline("door [%d,%d]", doors[sh].x, doors[sh].y);
381 display_nhwindow(WIN_MESSAGE, FALSE);
388 if(MON_AT(sx, sy)) (void) rloc(m_at(sx, sy), FALSE); /* insurance */
390 /* now initialize the shopkeeper monster structure */
391 if(!(shk = makemon(&mons[PM_SHOPKEEPER], sx, sy, NO_MM_FLAGS)))
393 shk->isshk = shk->mpeaceful = 1;
396 shk->mtrapseen = ~0; /* we know all the traps already */
397 ESHK(shk)->shoproom = (sroom - rooms) + ROOMOFFSET;
398 sroom->resident = shk;
399 ESHK(shk)->shoptype = sroom->rtype;
400 assign_level(&(ESHK(shk)->shoplevel), &u.uz);
401 ESHK(shk)->shd = doors[sh];
402 ESHK(shk)->shk.x = sx;
403 ESHK(shk)->shk.y = sy;
404 ESHK(shk)->robbed = 0L;
405 ESHK(shk)->credit = 0L;
406 ESHK(shk)->debit = 0L;
407 ESHK(shk)->loan = 0L;
408 ESHK(shk)->visitct = 0;
409 ESHK(shk)->following = 0;
410 ESHK(shk)->billct = 0;
412 shk->mgold = 1000L + 30L*(long)rnd(100); /* initial capital */
414 mkmonmoney(shk, 1000L + 30L*(long)rnd(100)); /* initial capital */
416 if (shp->shknms == shkrings)
417 (void) mongets(shk, TOUCHSTONE);
418 nameshk(shk, shp->shknms);
423 /* stock a newly-created room with objects */
425 stock_room(shp_indx, sroom)
427 register struct mkroom *sroom;
430 * Someday soon we'll dispatch on the shdist field of shclass to do
431 * different placements in this routine. Currently it only supports
432 * shop-style placement (all squares except a row nearest the first
435 register int sx, sy, sh;
437 int rmno = (sroom - rooms) + ROOMOFFSET;
438 const struct shclass *shp = &shtypes[shp_indx];
440 /* first, try to place a shopkeeper in the room */
441 if ((sh = shkinit(shp, sroom)) < 0)
444 /* make sure no doorways without doors, and no */
445 /* trapped doors, in shops. */
446 sx = doors[sroom->fdoor].x;
447 sy = doors[sroom->fdoor].y;
449 if(levl[sx][sy].doormask == D_NODOOR) {
450 levl[sx][sy].doormask = D_ISOPEN;
453 if(levl[sx][sy].typ == SDOOR) {
454 cvt_sdoor_to_door(&levl[sx][sy]); /* .typ = DOOR */
457 if(levl[sx][sy].doormask & D_TRAPPED)
458 levl[sx][sy].doormask = D_LOCKED;
460 if(levl[sx][sy].doormask == D_LOCKED) {
461 register int m = sx, n = sy;
463 if(inside_shop(sx+1,sy)) m--;
464 else if(inside_shop(sx-1,sy)) m++;
465 if(inside_shop(sx,sy+1)) n--;
466 else if(inside_shop(sx,sy-1)) n++;
467 Sprintf(buf, "Closed for inventory");
468 make_engr_at(m, n, buf, 0L, DUST);
471 for(sx = sroom->lx; sx <= sroom->hx; sx++)
472 for(sy = sroom->ly; sy <= sroom->hy; sy++) {
473 if(sroom->irregular) {
474 if (levl[sx][sy].edge || (int) levl[sx][sy].roomno != rmno ||
475 distmin(sx, sy, doors[sh].x, doors[sh].y) <= 1)
477 } else if((sx == sroom->lx && doors[sh].x == sx-1) ||
478 (sx == sroom->hx && doors[sh].x == sx+1) ||
479 (sy == sroom->ly && doors[sh].y == sy-1) ||
480 (sy == sroom->hy && doors[sh].y == sy+1)) continue;
481 mkshobj_at(shp, sx, sy);
485 * Special monster placements (if any) should go here: that way,
486 * monsters will sit on top of objects and not the other way around.
489 level.flags.has_shop = TRUE;
495 /* does shkp's shop stock this item type? */
501 int i, shp_indx = ESHK(shkp)->shoptype - SHOPBASE;
502 const struct shclass *shp = &shtypes[shp_indx];
504 if (shp->symb == RANDOM_CLASS) return TRUE;
505 else for (i = 0; i < SIZE(shtypes[0].iprobs) && shp->iprobs[i].iprob; i++)
506 if (shp->iprobs[i].itype < 0 ?
507 shp->iprobs[i].itype == - obj->otyp :
508 shp->iprobs[i].itype == obj->oclass) return TRUE;
513 /* positive value: class; negative value: specific object type */
518 const struct shclass *shp = shtypes+type;
521 /* select an appropriate object type at random */
522 for(j = rnd(100), i = 0; (j -= shp->iprobs[i].iprob) > 0; i++)
525 return shp->iprobs[i].itype;