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. */
4
5/* shknam.c -- initialize a shop */
6
7#include "hack.h"
8#include "eshk.h"
9
10#ifndef OVLB
11extern const struct shclass shtypes[];
12
13#else
14
15STATIC_DCL void FDECL(mkshobj_at, (const struct shclass *,int,int));
16STATIC_DCL void FDECL(nameshk, (struct monst *,const char * const *));
17STATIC_DCL int  FDECL(shkinit, (const struct shclass *,struct mkroom *));
18
19static const char * const shkliquors[] = {
20    /* Ukraine */
21    "Njezjin", "Tsjernigof", "Ossipewsk", "Gorlowka",
22    /* Belarus */
23    "Gomel",
24    /* N. Russia */
25    "Konosja", "Weliki Oestjoeg", "Syktywkar", "Sablja",
26    "Narodnaja", "Kyzyl",
27    /* Silezie */
28    "Walbrzych", "Swidnica", "Klodzko", "Raciborz", "Gliwice",
29    "Brzeg", "Krnov", "Hradec Kralove",
30    /* Schweiz */
31    "Leuk", "Brig", "Brienz", "Thun", "Sarnen", "Burglen", "Elm",
32    "Flims", "Vals", "Schuls", "Zum Loch",
33    0
34};
35
36static const char * const shkbooks[] = {
37    /* Eire */
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",
44    0
45};
46
47static const char * const shkarmors[] = {
48    /* Turquie */
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",
55    0
56};
57
58static const char * const shkwands[] = {
59    /* Wales */
60    "Yr Wyddgrug", "Trallwng", "Mallwyd", "Pontarfynach",
61    "Rhaeader", "Llandrindod", "Llanfair-ym-muallt",
62    "Y-Fenni", "Maesteg", "Rhydaman", "Beddgelert",
63    "Curig", "Llanrwst", "Llanerchymedd", "Caergybi",
64    /* Scotland */
65    "Nairn", "Turriff", "Inverurie", "Braemar", "Lochnagar",
66    "Kerloch", "Beinn a Ghlo", "Drumnadrochit", "Morven",
67    "Uist", "Storr", "Sgurr na Ciche", "Cannich", "Gairloch",
68    "Kyleakin", "Dunvegan",
69    0
70};
71
72static 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",
77    "Ypey",
78    /* Skandinaviske navne */
79    "Rastegaisa", "Varjag Njarga", "Kautekeino", "Abisko",
80    "Enontekis", "Rovaniemi", "Avasaksa", "Haparanda",
81    "Lulea", "Gellivare", "Oeloe", "Kajaani", "Fauske",
82    0
83};
84
85static const char * const shkfoods[] = {
86    /* Indonesia */
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",
94    0
95};
96
97static const char * const shkweapons[] = {
98    /* Perigord */
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",
105    0
106};
107
108static const char * const shktools[] = {
109    /* Spmi */
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",
115    "Corsh", "Aned",
116#ifdef OVERLAY
117    "Erreip", "Nehpets", "Mron", "Snivek", "Lapu", "Kahztiy",
118#endif
119#ifdef WIN32
120    "Lechaim", "Lexa", "Niod",
121#endif
122#ifdef MAC
123    "Nhoj-lee", "Evad\'kh", "Ettaw-noj", "Tsew-mot", "Ydna-s",
124    "Yao-hang", "Tonbar", "Kivenhoug",
125#endif
126#ifdef AMIGA
127    "Falo", "Nosid-da\'r", "Ekim-p", "Rebrol-nek", "Noslo", "Yl-rednow",
128    "Mured-oog", "Ivrajimsal",
129#endif
130#ifdef TOS
131    "Nivram",
132#endif
133#ifdef VMS
134    "Lez-tneg", "Ytnu-haled", "Niknar",
135#endif
136    0
137};
138
139static const char * const shklight[] = {
140    /* Romania */
141    "Zarnesti", "Slanic", "Nehoiasu", "Ludus", "Sighisoara", "Nisipitu",
142    "Razboieni", "Bicaz", "Dorohoi", "Vaslui", "Fetesti", "Tirgu Neamt",
143    "Babadag", "Zimnicea", "Zlatna", "Jiu", "Eforie", "Mamaia",
144    /* Bulgaria */
145    "Silistra", "Tulovo", "Panagyuritshte", "Smolyan", "Kirklareli",
146    "Pernik", "Lom", "Haskovo", "Dobrinishte", "Varvara", "Oryahovo",
147    "Troyan", "Lovech", "Sliven",
148    0
149};
150
151static const char * const shkgeneral[] = {
152    /* Suriname */
153    "Hebiwerie", "Possogroenoe", "Asidonhopo", "Manlobbi",
154    "Adjama", "Pakka Pakka", "Kabalebo", "Wonotobo",
155    "Akalapi", "Sipaliwini",
156    /* Greenland */
157    "Annootok", "Upernavik", "Angmagssalik",
158    /* N. Canada */
159    "Aklavik", "Inuvik", "Tuktoyaktuk",
160    "Chicoutimi", "Ouiatchouane", "Chibougamau",
161    "Matagami", "Kipawa", "Kinojevis",
162    "Abitibi", "Maganasipi",
163    /* Iceland */
164    "Akureyri", "Kopasker", "Budereyri", "Akranes", "Bordeyri",
165    "Holmavik",
166    0
167};
168
169/*
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.
174 *
175 * The placement type field is not yet used but will be in the near future.
176 *
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().
183 */
184
185const 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}},
190	     shkarmors},
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}},
202	    shkrings},
203	{"quality apparel and accessories", WAND_CLASS, 3, D_SHOP,
204	    {{90, WAND_CLASS}, {5, -LEATHER_GLOVES}, {5, -ELVEN_CLOAK}, {0, 0}},
205	     shkwands},
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)
211	 */
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
216	 * loader.
217	 */
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}
222};
223
224#if 0
225/* validate shop probabilities; otherwise incorrect local changes could
226   end up provoking infinite loops or wild subscripts fetching garbage */
227void
228init_shop_selection()
229{
230	register int i, j, item_prob, shop_prob;
231
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);
239	}
240	if (shop_prob != 100)
241		panic("shop probabilities total to %d!", shop_prob);
242}
243#endif /*0*/
244
245STATIC_OVL void
246mkshobj_at(shp, sx, sy)
247/* make an object of the appropriate type for a shop square */
248const struct shclass *shp;
249int sx, sy;
250{
251	struct monst *mtmp;
252	int atype;
253	struct permonst *ptr;
254
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;
262	    }
263	} else {
264	    atype = get_shop_item(shp - shtypes);
265	    if (atype < 0)
266		(void) mksobj_at(-atype, sx, sy, TRUE, TRUE);
267	    else
268		(void) mkobj_at(atype, sx, sy, TRUE);
269	}
270}
271
272/* extract a shopkeeper name for the given shop type */
273STATIC_OVL void
274nameshk(shk, nlp)
275struct monst *shk;
276const char * const *nlp;
277{
278	int i, trycnt, names_avail;
279	const char *shname = 0;
280	struct monst *mtmp;
281	int name_wanted;
282	s_level *sptr;
283
284	if (nlp == shklight && In_mines(&u.uz)
285		&& (sptr = Is_special(&u.uz)) != 0 && sptr->flags.town) {
286	    /* special-case minetown lighting shk */
287	    shname = "Izchak";
288	    shk->female = FALSE;
289	} else {
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);
295
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;
299
300	    for (names_avail = 0; nlp[names_avail]; names_avail++)
301		continue;
302
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) {
311		    shname = nlp[i - 1];
312		} else if (nlp != shkgeneral) {
313		    nlp = shkgeneral;	/* try general names */
314		    for (names_avail = 0; nlp[names_avail]; names_avail++)
315			continue;
316		    continue;		/* next `trycnt' iteration */
317		} else {
318		    shname = shk->female ? "Lucrezia" : "Dirk";
319		}
320
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;
325		    break;
326		}
327		if (!mtmp) break;	/* new name */
328	    }
329	}
330	(void) strncpy(ESHK(shk)->shknam, shname, PL_NSIZ);
331	ESHK(shk)->shknam[PL_NSIZ-1] = 0;
332}
333
334STATIC_OVL int
335shkinit(shp, sroom)	/* create a new shopkeeper in the given room */
336const struct shclass	*shp;
337struct mkroom	*sroom;
338{
339	register int sh, sx, sy;
340	struct monst *shk;
341
342	/* place the shopkeeper in the given room */
343	sh = sroom->fdoor;
344	sx = doors[sh].x;
345	sy = doors[sh].y;
346
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;
359	}
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 {
364	shk_failed:
365#ifdef NETHACK_DEBUG
366# ifdef WIZARD
367	    /* Said to happen sometimes, but I have never seen it. */
368	    /* Supposedly fixed by fdoor change in mklev.c */
369	    if(wizard) {
370		register int j = sroom->doorct;
371
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);
377		while(j--) {
378		    pline("door [%d,%d]", doors[sh].x, doors[sh].y);
379		    sh++;
380		}
381		display_nhwindow(WIN_MESSAGE, FALSE);
382	    }
383# endif
384#endif
385	    return(-1);
386	}
387
388	if(MON_AT(sx, sy)) (void) rloc(m_at(sx, sy), FALSE); /* insurance */
389
390	/* now initialize the shopkeeper monster structure */
391	if(!(shk = makemon(&mons[PM_SHOPKEEPER], sx, sy, NO_MM_FLAGS)))
392		return(-1);
393	shk->isshk = shk->mpeaceful = 1;
394	set_malign(shk);
395	shk->msleeping = 0;
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;
411#ifndef GOLDOBJ
412	shk->mgold = 1000L + 30L*(long)rnd(100);	/* initial capital */
413#else
414        mkmonmoney(shk, 1000L + 30L*(long)rnd(100));	/* initial capital */
415#endif
416	if (shp->shknms == shkrings)
417	    (void) mongets(shk, TOUCHSTONE);
418	nameshk(shk, shp->shknms);
419
420	return(sh);
421}
422
423/* stock a newly-created room with objects */
424void
425stock_room(shp_indx, sroom)
426int shp_indx;
427register struct mkroom *sroom;
428{
429    /*
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
433     * door get objects).
434     */
435    register int sx, sy, sh;
436    char buf[BUFSZ];
437    int rmno = (sroom - rooms) + ROOMOFFSET;
438    const struct shclass *shp = &shtypes[shp_indx];
439
440    /* first, try to place a shopkeeper in the room */
441    if ((sh = shkinit(shp, sroom)) < 0)
442	return;
443
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;
448
449    if(levl[sx][sy].doormask == D_NODOOR) {
450	    levl[sx][sy].doormask = D_ISOPEN;
451	    newsym(sx,sy);
452    }
453    if(levl[sx][sy].typ == SDOOR) {
454	    cvt_sdoor_to_door(&levl[sx][sy]);	/* .typ = DOOR */
455	    newsym(sx,sy);
456    }
457    if(levl[sx][sy].doormask & D_TRAPPED)
458	    levl[sx][sy].doormask = D_LOCKED;
459
460    if(levl[sx][sy].doormask == D_LOCKED) {
461	    register int m = sx, n = sy;
462
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);
469    }
470
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)
476		    continue;
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);
482	}
483
484    /*
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.
487     */
488
489    level.flags.has_shop = TRUE;
490}
491
492#endif /* OVLB */
493#ifdef OVL0
494
495/* does shkp's shop stock this item type? */
496boolean
497saleable(shkp, obj)
498struct monst *shkp;
499struct obj *obj;
500{
501    int i, shp_indx = ESHK(shkp)->shoptype - SHOPBASE;
502    const struct shclass *shp = &shtypes[shp_indx];
503
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;
509    /* not found */
510    return FALSE;
511}
512
513/* positive value: class; negative value: specific object type */
514int
515get_shop_item(type)
516int type;
517{
518	const struct shclass *shp = shtypes+type;
519	register int i,j;
520
521	/* select an appropriate object type at random */
522	for(j = rnd(100), i = 0; (j -= shp->iprobs[i].iprob) > 0; i++)
523		continue;
524
525	return shp->iprobs[i].itype;
526}
527
528#endif /* OVL0 */
529
530/*shknam.c*/
531