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
11 extern const struct shclass shtypes[];
12
13 #else
14
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 *));
18 #ifdef BLACKMARKET
19 STATIC_DCL void FDECL(stock_blkmar,
20 (const struct shclass *, struct mkroom *, int));
21 #endif /* BLACKMARKET */
22
23 static const char * const shkliquors[] = {
24 /* Ukraine */
25 "Njezjin", "Tsjernigof", "Ossipewsk", "Gorlowka",
26 /* Belarus */
27 "Gomel",
28 /* N. Russia */
29 "Konosja", "Weliki Oestjoeg", "Syktywkar", "Sablja",
30 "Narodnaja", "Kyzyl",
31 /* Silezie */
32 "Walbrzych", "Swidnica", "Klodzko", "Raciborz", "Gliwice",
33 "Brzeg", "Krnov", "Hradec Kralove",
34 /* Schweiz */
35 "Leuk", "Brig", "Brienz", "Thun", "Sarnen", "Burglen", "Elm",
36 "Flims", "Vals", "Scuol",
37 "Chur", "Pagig",
38 0
39 };
40
41 static const char * const shkbooks[] = {
42 /* Eire */
43 "Skibbereen", "Kanturk", "Rath Luirc", "Ennistymon", "Lahinch",
44 "Kinnegad", "Lugnaquillia", "Enniscorthy", "Gweebarra",
45 "Kittamagh", "Nenagh", "Sneem", "Ballingeary", "Kilgarvan",
46 "Cahersiveen", "Glenbeigh", "Kilmihil", "Kiltamagh",
47 "Droichead Atha", "Inniscrone", "Clonegal", "Lisnaskea",
48 "Culdaff", "Dunfanaghy", "Inishbofin", "Kesh",
49 0
50 };
51
52 static const char * const shkarmors[] = {
53 /* Turquie */
54 "Demirci", "Kalecik", "Boyabai", "Yildizeli", "Gaziantep",
55 "Siirt", "Akhalataki", "Tirebolu", "Aksaray", "Ermenak",
56 "Iskenderun", "Kadirli", "Siverek", "Pervari", "Malasgirt",
57 "Bayburt", "Ayancik", "Zonguldak", "Balya", "Tefenni",
58 "Artvin", "Kars", "Makharadze", "Malazgirt", "Midyat",
59 "Birecik", "Kirikkale", "Alaca", "Polatli", "Nallihan",
60 0
61 };
62
63 static const char * const shkwands[] = {
64 /* Wales */
65 "Yr Wyddgrug", "Trallwng", "Mallwyd", "Pontarfynach",
66 "Rhaeader", "Llandrindod", "Llanfair-ym-muallt",
67 "Y-Fenni", "Maesteg", "Rhydaman", "Beddgelert",
68 "Curig", "Llanrwst", "Llanerchymedd", "Caergybi",
69 /* Scotland */
70 "Nairn", "Turriff", "Inverurie", "Braemar", "Lochnagar",
71 "Kerloch", "Beinn a Ghlo", "Drumnadrochit", "Morven",
72 "Uist", "Storr", "Sgurr na Ciche", "Cannich", "Gairloch",
73 "Kyleakin", "Dunvegan",
74 0
75 };
76
77 static const char * const shkrings[] = {
78 /* Hollandse familienamen */
79 "Feyfer", "Flugi", "Gheel", "Havic", "Haynin", "Hoboken",
80 "Imbyze", "Juyn", "Kinsky", "Massis", "Matray", "Moy",
81 "Olycan", "Sadelin", "Svaving", "Tapper", "Terwen", "Wirix",
82 "Ypey",
83 /* Skandinaviske navne */
84 "Rastegaisa", "Varjag Njarga", "Kautekeino", "Abisko",
85 "Enontekis", "Rovaniemi", "Avasaksa", "Haparanda",
86 "Lulea", "Gellivare", "Oeloe", "Kajaani", "Fauske",
87 0
88 };
89
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", "Banjoewangi",
96 "Trenggalek", "Karangkobar", "Njalindoeng", "Pasawahan",
97 "Pameunpeuk", "Patjitan", "Kediri", "Pemboeang", "Tringanoe",
98 "Makin", "Tipor", "Semai", "Berhala", "Tegal", "Samoe",
99 0
100 };
101
102 static const char * const shkweapons[] = {
103 /* Perigord */
104 "Voulgezac", "Rouffiac", "Lerignac", "Touverac", "Guizengeard",
105 "Melac", "Neuvicq", "Vanzac", "Picq", "Urignac", "Corignac",
106 "Fleac", "Lonzac", "Vergt", "Queyssac", "Liorac", "Echourgnac",
107 "Cazelon", "Eypau", "Carignan", "Monbazillac", "Jonzac",
108 "Pons", "Jumilhac", "Fenouilledes", "Laguiolet", "Saujon",
109 "Eymoutiers", "Eygurande", "Eauze", "Labouheyre",
110 0
111 };
112
113 static const char * const shktools[] = {
114 /* Spmi */
115 "Ymla", "Eed-morra", "Cubask", "Nieb", "Bnowr Falr", "Telloc Cyaj",
116 "Sperc", "Noskcirdneh", "Yawolloh", "Hyeghu", "Niskal", "Trahnil",
117 "Htargcm", "Enrobwem", "Kachzi Rellim", "Regien", "Donmyar",
118 "Yelpur", "Nosnehpets", "Stewe", "Renrut", "_Zlaw", "Nosalnef",
119 "Rewuorb", "Rellenk", "Yad", "Cire Htims", "Y-crad", "Nenilukah",
120 "Corsh", "Aned",
121 #ifdef OVERLAY
122 "Erreip", "Nehpets", "Mron", "Snivek", "Lapu", "Kahztiy",
123 #endif
124 #ifdef WIN32
125 "Lechaim", "Lexa", "Niod",
126 #endif
127 #ifdef MAC
128 "Nhoj-lee", "Evad\'kh", "Ettaw-noj", "Tsew-mot", "Ydna-s",
129 "Yao-hang", "Tonbar", "Kivenhoug",
130 #endif
131 #ifdef AMIGA
132 "Falo", "Nosid-da\'r", "Ekim-p", "Rebrol-nek", "Noslo", "Yl-rednow",
133 "Mured-oog", "Ivrajimsal",
134 #endif
135 #ifdef TOS
136 "Nivram",
137 #endif
138 #ifdef VMS
139 "Lez-tneg", "Ytnu-haled", "Niknar",
140 #endif
141 0
142 };
143
144 static const char * const shklight[] = {
145 /* Romania */
146 "Zarnesti", "Slanic", "Nehoiasu", "Ludus", "Sighisoara", "Nisipitu",
147 "Razboieni", "Bicaz", "Dorohoi", "Vaslui", "Fetesti", "Tirgu Neamt",
148 "Babadag", "Zimnicea", "Zlatna", "Jiu", "Eforie", "Mamaia",
149 /* Bulgaria */
150 "Silistra", "Tulovo", "Panagyuritshte", "Smolyan", "Kirklareli",
151 "Pernik", "Lom", "Haskovo", "Dobrinishte", "Varvara", "Oryahovo",
152 "Troyan", "Lovech", "Sliven",
153 0
154 };
155
156 static const char * const shkgeneral[] = {
157 /* Suriname */
158 "Hebiwerie", "Possogroenoe", "Asidonhopo", "Manlobbi",
159 "Adjama", "Pakka Pakka", "Kabalebo", "Wonotobo",
160 "Akalapi", "Sipaliwini",
161 /* Greenland */
162 "Annootok", "Upernavik", "Angmagssalik",
163 /* N. Canada */
164 "Aklavik", "Inuvik", "Tuktoyaktuk",
165 "Chicoutimi", "Ouiatchouane", "Chibougamau",
166 "Matagami", "Kipawa", "Kinojevis",
167 "Abitibi", "Maganasipi",
168 /* Iceland */
169 "Akureyri", "Kopasker", "Budereyri", "Akranes", "Bordeyri",
170 "Holmavik",
171 0
172 };
173
174 static const char *shkmusic[] = {
175 "John", "Paul", "George", "Ringo"
176 "Elvis", "Mick", "Keith", "Ron", "Charlie"
177 "Joseph", "Franz", "Richard", "Ludwig", "Wolfgang Amadeus",
178 "Johann Sebastian",
179 "Karlheinz", "Gyorgy",
180 "Luciano", "Placido", "Jose", "Enrico",
181 "Falco", "_Britney", "_Christina", "_Toni", "_Brandy",
182 0
183 };
184
185 #ifdef BLACKMARKET
186 static const char *shkblack[] = {
187 "One-eyed Sam", "One-eyed Sam", "One-eyed Sam",
188 "One-eyed Sam", "One-eyed Sam", "One-eyed Sam",
189 "One-eyed Sam", "One-eyed Sam", "One-eyed Sam",
190 "One-eyed Sam", "One-eyed Sam", "One-eyed Sam",
191 "One-eyed Sam", "One-eyed Sam", "One-eyed Sam",
192 "One-eyed Sam", "One-eyed Sam", "One-eyed Sam",
193 "One-eyed Sam", "One-eyed Sam", "One-eyed Sam",
194 "One-eyed Sam", "One-eyed Sam", "One-eyed Sam",
195 "One-eyed Sam", "One-eyed Sam", "One-eyed Sam",
196 "One-eyed Sam", "One-eyed Sam", "One-eyed Sam",
197 "One-eyed Sam", "One-eyed Sam", "One-eyed Sam",
198 0
199 };
200 #endif /* BLACKMARKET */
201
202 static const char *shkpet[] = {
203 /* Albania */
204 "Elbasan", "Vlore", "Shkoder", "Berat", "Kavaje", "Pogradec",
205 "Sarande", "Peshkopi", "Shijak", "Librazhd", "Tepelene",
206 "Fushe-Kruje", "Rreshen",
207 0
208 };
209
210 static const char *shktins[] = {
211 /* Sweden */
212 "Trosa", "Torshalla", "Morgongava", "Uppsala", "Norrkoping",
213 "Nybro", "Alingsas", "Vadstena", "Fagersta", "Skelleftea",
214 "Solleftea", "Ystad", "Avesta", "Sala", "Norrt�lje",
215 0
216 };
217
218 /*
219 * To add new shop types, all that is necessary is to edit the shtypes[] array.
220 * See mkroom.h for the structure definition. Typically, you'll have to lower
221 * some or all of the probability fields in old entries to free up some
222 * percentage for the new type.
223 *
224 * The placement type field is not yet used but will be in the near future.
225 *
226 * The iprobs array in each entry defines the probabilities for various kinds
227 * of objects to be present in the given shop type. You can associate with
228 * each percentage either a generic object type (represented by one of the
229 * *_CLASS macros) or a specific object (represented by an onames.h define).
230 * In the latter case, prepend it with a unary minus so the code can know
231 * (by testing the sign) whether to use mkobj() or mksobj().
232 */
233
234 const struct shclass shtypes[] = {
235 {"general store", RANDOM_CLASS, 41,
236 D_SHOP, {{100, RANDOM_CLASS}, {0, 0}, {0, 0}}, shkgeneral},
237 {"used armor dealership", ARMOR_CLASS, 14,
238 D_SHOP, {{90, ARMOR_CLASS}, {10, WEAPON_CLASS}, {0, 0}},
239 shkarmors},
240 {"second-hand bookstore", SCROLL_CLASS, 10, D_SHOP,
241 {{90, SCROLL_CLASS}, {10, SPBOOK_CLASS}, {0, 0}}, shkbooks},
242 {"liquor emporium", POTION_CLASS, 10, D_SHOP,
243 {{100, POTION_CLASS}, {0, 0}, {0, 0}}, shkliquors},
244 {"antique weapons outlet", WEAPON_CLASS, 5, D_SHOP,
245 {{90, WEAPON_CLASS}, {10, ARMOR_CLASS}, {0, 0}}, shkweapons},
246 {"delicatessen", FOOD_CLASS, 5, D_SHOP,
247 {{83, FOOD_CLASS}, {5, -POT_FRUIT_JUICE}, {4, -POT_BOOZE},
248 {5, -POT_WATER}, {3, -ICE_BOX}}, shkfoods},
249 {"jewelers", RING_CLASS, 3, D_SHOP,
250 {{85, RING_CLASS}, {10, GEM_CLASS}, {5, AMULET_CLASS}, {0, 0}},
251 shkrings},
252 {"quality apparel and accessories", WAND_CLASS, 3, D_SHOP,
253 {{90, WAND_CLASS}, {5, -LEATHER_GLOVES}, {5, -ELVEN_CLOAK}, {0, 0}},
254 shkwands},
255 {"hardware store", TOOL_CLASS, 3, D_SHOP,
256 {{100, TOOL_CLASS}, {0, 0}, {0, 0}}, shktools},
257 /* Actually shktools is ignored; the code specifically chooses a
258 * random implementor name (along with candle shops having
259 * random shopkeepers)
260 */
261 {"rare books", SPBOOK_CLASS, 3, D_SHOP,
262 {{90, SPBOOK_CLASS}, {10, SCROLL_CLASS}, {0, 0}}, shkbooks},
263 {"canned food factory", FOOD_CLASS, 1, D_SHOP,
264 {{10, -ICE_BOX}, {90, -TIN},
265 /* shopkeeper will pay for corpses, but they aren't generated */
266 /* on the shop floor */
267 {0, -CORPSE}, {0, 0}}, shktins},
268 {"rare instruments", TOOL_CLASS, 1, D_SHOP,
269 {{10, -TIN_WHISTLE }, { 3, -MAGIC_WHISTLE },
270 {10, -WOODEN_FLUTE }, { 3, -MAGIC_FLUTE },
271 {10, -TOOLED_HORN }, { 3, -FROST_HORN },
272 { 3, -FIRE_HORN }, { 3, -HORN_OF_PLENTY },
273 {10, -WOODEN_HARP }, { 3, -MAGIC_HARP },
274 {10, -BELL }, {10, -BUGLE },
275 {10, -LEATHER_DRUM }, { 2, -DRUM_OF_EARTHQUAKE},
276 #ifdef TOURIST
277 { 5, -T_SHIRT }, { 5, -LOCK_PICK },
278 #else
279 { 5, -TIN_WHISTLE }, { 5, -LOCK_PICK },
280 #endif
281 {0, 0}} , shkmusic},
282 {"pet store", FOOD_CLASS, 1, D_SHOP, {
283 #ifdef STEED
284 {67, -FIGURINE}, {5, -LEASH},{10, -TRIPE_RATION}, {5, -SADDLE},
285 #else
286 {72, -FIGURINE}, {5, -LEASH},{10, -TRIPE_RATION},
287 #endif
288 {10, -TIN_WHISTLE}, {3, -MAGIC_WHISTLE}}, shkpet},
289 /* Shops below this point are "unique". That is they must all have a
290 * probability of zero. They are only created via the special level
291 * loader.
292 */
293 {"lighting store", TOOL_CLASS, 0, D_SHOP,
294 {{32, -WAX_CANDLE}, {50, -TALLOW_CANDLE},
295 {5, -BRASS_LANTERN}, {10, -OIL_LAMP}, {3, -MAGIC_LAMP}}, shklight},
296 #ifdef BLACKMARKET
297 {"black market", RANDOM_CLASS, 0, D_SHOP,
298 {{100, RANDOM_CLASS}, {0, 0}, {0, 0}}, shkblack},
299 #endif /* BLACKMARKET */
300 {(char *)0, 0, 0, 0, {{0, 0}, {0, 0}, {0, 0}}, 0}
301 };
302
303 /* validate shop probabilities; otherwise incorrect local changes could
304 end up provoking infinite loops or wild subscripts fetching garbage */
305 void
shop_selection_init()306 shop_selection_init()
307 {
308 register int i, j, item_prob, shop_prob;
309
310 for (shop_prob = 0, i = 0; i < SIZE(shtypes)-1; i++) {
311 shop_prob += shtypes[i].prob;
312 for (item_prob = 0, j = 0; j < SIZE(shtypes[0].iprobs); j++)
313 item_prob += shtypes[i].iprobs[j].iprob;
314 if (item_prob != 100)
315 panic("item probabilities total to %d for %s shops!",
316 item_prob, shtypes[i].name);
317 }
318 if (shop_prob != 100)
319 panic("shop probabilities total to %d!", shop_prob);
320 }
321
322 STATIC_OVL void
mkshobj_at(shp,sx,sy)323 mkshobj_at(shp, sx, sy)
324 /* make an object of the appropriate type for a shop square */
325 const struct shclass *shp;
326 int sx, sy;
327 {
328 struct monst *mtmp;
329 int atype;
330 struct permonst *ptr;
331
332 if (rn2(100) < depth(&u.uz) &&
333 !MON_AT(sx, sy) && (ptr = mkclass(S_MIMIC,0)) &&
334 (mtmp = makemon(ptr,sx,sy,NO_MM_FLAGS)) != 0) {
335 /* note: makemon will set the mimic symbol to a shop item */
336 if (rn2(10) >= depth(&u.uz)) {
337 mtmp->m_ap_type = M_AP_OBJECT;
338 mtmp->mappearance = STRANGE_OBJECT;
339 }
340 } else {
341 atype = get_shop_item(shp - shtypes);
342 if (atype < 0)
343 (void) mksobj_at(-atype, sx, sy, TRUE, TRUE);
344 else
345 (void) mkobj_at(atype, sx, sy, TRUE);
346 }
347 }
348
349 /* extract a shopkeeper name for the given shop type */
350 STATIC_OVL void
nameshk(shk,nlp)351 nameshk(shk, nlp)
352 struct monst *shk;
353 const char * const *nlp;
354 {
355 int i, trycnt, names_avail;
356 const char *shname = 0;
357 struct monst *mtmp;
358 int name_wanted;
359 s_level *sptr;
360
361 if (nlp == shklight && In_mines(&u.uz)
362 && (sptr = Is_special(&u.uz)) != 0 && sptr->flags.town) {
363 /* special-case minetown lighting shk */
364 shname = "Izchak";
365 shk->female = FALSE;
366 #ifdef BLACKMARKET
367 } else if (nlp == shkblack) {
368 /* special-case black marketeer */
369 shname = "One-eyed Sam";
370 shk->female = TRUE;
371 #endif /* BLACKMARKET */
372 } else {
373 /* We want variation from game to game, without needing the save
374 and restore support which would be necessary for randomization;
375 try not to make too many assumptions about time_t's internals;
376 use ledger_no rather than depth to keep mine town distinct. */
377 int nseed = (int)((long)u.ubirthday / 257L);
378
379 name_wanted = ledger_no(&u.uz) + (nseed % 13) - (nseed % 5);
380 if (name_wanted < 0) name_wanted += (13 + 5);
381 shk->female = name_wanted & 1;
382
383 for (names_avail = 0; nlp[names_avail]; names_avail++)
384 continue;
385
386 for (trycnt = 0; trycnt < 50; trycnt++) {
387 if (nlp == shktools) {
388 shname = shktools[rn2(names_avail)];
389 shk->female = (*shname == '_');
390 if (shk->female) shname++;
391 } else if (nlp == shkmusic) {
392 shname = shkmusic[rn2(names_avail)];
393 shk->female = (*shname == '_');
394 if (shk->female) shname++;
395 } else if (name_wanted < names_avail) {
396 shname = nlp[name_wanted];
397 } else if ((i = rn2(names_avail)) != 0) {
398 shname = nlp[i - 1];
399 } else if (nlp != shkgeneral) {
400 nlp = shkgeneral; /* try general names */
401 for (names_avail = 0; nlp[names_avail]; names_avail++)
402 continue;
403 continue; /* next `trycnt' iteration */
404 } else {
405 shname = shk->female ? "Lucrezia" : "Dirk";
406 }
407
408 /* is name already in use on this level? */
409 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
410 if (DEADMONSTER(mtmp) || (mtmp == shk) || !mtmp->isshk) continue;
411 if (strcmp(ESHK(mtmp)->shknam, shname)) continue;
412 break;
413 }
414 if (!mtmp) break; /* new name */
415 }
416 }
417 (void) strncpy(ESHK(shk)->shknam, shname, PL_NSIZ);
418 ESHK(shk)->shknam[PL_NSIZ-1] = 0;
419 }
420
421 STATIC_OVL int
shkinit(shp,sroom)422 shkinit(shp, sroom) /* create a new shopkeeper in the given room */
423 const struct shclass *shp;
424 struct mkroom *sroom;
425 {
426 register int sh, sx, sy;
427 struct monst *shk;
428 long shkmoney; /* Temporary placeholder for Shopkeeper's initial capital */
429
430 /* place the shopkeeper in the given room */
431 sh = sroom->fdoor;
432 sx = doors[sh].x;
433 sy = doors[sh].y;
434
435 /* check that the shopkeeper placement is sane */
436 if(sroom->irregular) {
437 int rmno = (sroom - rooms) + ROOMOFFSET;
438 if (isok(sx-1,sy) && !levl[sx-1][sy].edge &&
439 (int) levl[sx-1][sy].roomno == rmno) sx--;
440 else if (isok(sx+1,sy) && !levl[sx+1][sy].edge &&
441 (int) levl[sx+1][sy].roomno == rmno) sx++;
442 else if (isok(sx,sy-1) && !levl[sx][sy-1].edge &&
443 (int) levl[sx][sy-1].roomno == rmno) sy--;
444 else if (isok(sx,sy+1) && !levl[sx][sy+1].edge &&
445 (int) levl[sx][sy+1].roomno == rmno) sx++;
446 else goto shk_failed;
447 }
448 else if(sx == sroom->lx-1) sx++;
449 else if(sx == sroom->hx+1) sx--;
450 else if(sy == sroom->ly-1) sy++;
451 else if(sy == sroom->hy+1) sy--; else {
452 shk_failed:
453 #ifdef DEBUG
454 # ifdef WIZARD
455 /* Said to happen sometimes, but I have never seen it. */
456 /* Supposedly fixed by fdoor change in mklev.c */
457 if(wizard) {
458 register int j = sroom->doorct;
459
460 pline("Where is shopdoor?");
461 pline("Room at (%d,%d),(%d,%d).",
462 sroom->lx, sroom->ly, sroom->hx, sroom->hy);
463 pline("doormax=%d doorct=%d fdoor=%d",
464 doorindex, sroom->doorct, sh);
465 while(j--) {
466 pline("door [%d,%d]", doors[sh].x, doors[sh].y);
467 sh++;
468 }
469 display_nhwindow(WIN_MESSAGE, FALSE);
470 }
471 # endif
472 #endif
473 return(-1);
474 }
475
476 if(MON_AT(sx, sy)) (void) rloc(m_at(sx, sy), FALSE); /* insurance */
477
478 /* now initialize the shopkeeper monster structure */
479
480 #ifdef BLACKMARKET
481 shk = 0;
482 if (Is_blackmarket(&u.uz)) {
483 shk = makemon(&mons[PM_BLACK_MARKETEER], sx, sy, NO_MM_FLAGS);
484 }
485 if (!shk) {
486 if(!(shk = makemon(&mons[PM_SHOPKEEPER], sx, sy, NO_MM_FLAGS)))
487 return(-1);
488 }
489 #else /* BLACKMARKET */
490 if(!(shk = makemon(&mons[PM_SHOPKEEPER], sx, sy, NO_MM_FLAGS)))
491 return(-1);
492 #endif /* BLACKMARKET */
493
494 shk->isshk = shk->mpeaceful = 1;
495 set_malign(shk);
496 shk->msleeping = 0;
497 shk->mtrapseen = ~0; /* we know all the traps already */
498 ESHK(shk)->shoproom = (sroom - rooms) + ROOMOFFSET;
499 sroom->resident = shk;
500 ESHK(shk)->shoptype = sroom->rtype;
501 assign_level(&(ESHK(shk)->shoplevel), &u.uz);
502 ESHK(shk)->shd = doors[sh];
503 ESHK(shk)->shk.x = sx;
504 ESHK(shk)->shk.y = sy;
505 ESHK(shk)->robbed = 0L;
506 ESHK(shk)->credit = 0L;
507 ESHK(shk)->debit = 0L;
508 ESHK(shk)->loan = 0L;
509 ESHK(shk)->visitct = 0;
510 ESHK(shk)->following = 0;
511 ESHK(shk)->cheapskate = (rn2(3)==0) ? TRUE : FALSE;
512 ESHK(shk)->billct = 0;
513 ESHK(shk)->bill_p = &ESHK(shk)->bill[0];
514
515 shkmoney = 1000L + 30L*(long)rnd(100); /* initial capital */
516 /* [CWC] Lets not create the money yet until we see if the
517 shk is a black marketeer, else we'll have to create
518 another money object, if GOLDOBJ is defined */
519
520 if (shp->shknms == shkrings)
521 (void) mongets(shk, TOUCHSTONE);
522 nameshk(shk, shp->shknms);
523
524 #ifdef BLACKMARKET
525 if (Is_blackmarket(&u.uz))
526 shkmoney = 7*shkmoney + rn2(3*shkmoney);
527 #endif
528 /* it's a poor town */
529 if (Is_town_level(&u.uz))
530 shkmoney /= 4;
531
532 #ifndef GOLDOBJ
533 shk->mgold = shkmoney;
534 #else
535 mkmonmoney(shk, shkmoney);
536 #endif
537
538 #ifdef BLACKMARKET
539 if (Is_blackmarket(&u.uz)) {
540 register struct obj *otmp;
541 /* make sure black marketeer can wield Thiefbane */
542 shk->data->maligntyp = -1;
543 /* black marketeer's equipment */
544 otmp = mksobj(TWO_HANDED_SWORD, FALSE, FALSE);
545 otmp = oname(otmp, artiname(ART_THIEFBANE));
546 mpickobj(shk, otmp);
547 if (otmp->spe < 5) otmp->spe += rnd(5);
548 otmp = mksobj(SHIELD_OF_REFLECTION, FALSE, FALSE);
549 mpickobj(shk, otmp);
550 if (otmp->spe < 5) otmp->spe += rnd(5);
551 otmp = mksobj(GRAY_DRAGON_SCALE_MAIL, FALSE, FALSE);
552 mpickobj(shk, otmp);
553 if (otmp->spe < 5) otmp->spe += rnd(5);
554 otmp = mksobj(SPEED_BOOTS, FALSE, FALSE);
555 mpickobj(shk, otmp);
556 if (otmp->spe < 5) otmp->spe += rnd(5);
557 otmp = mksobj(AMULET_OF_LIFE_SAVING, FALSE, FALSE);
558 mpickobj(shk, otmp);
559 /* wear armor and amulet */
560 m_dowear(shk, TRUE);
561 otmp = mksobj(SKELETON_KEY, FALSE, FALSE);
562 mpickobj(shk, otmp);
563 }
564 #endif /* BLACKMARKET */
565
566 return(sh);
567 }
568
569 /* stock a newly-created room with objects */
570 void
stock_room(shp_indx,sroom)571 stock_room(shp_indx, sroom)
572 int shp_indx;
573 register struct mkroom *sroom;
574 {
575 /*
576 * Someday soon we'll dispatch on the shdist field of shclass to do
577 * different placements in this routine. Currently it only supports
578 * shop-style placement (all squares except a row nearest the first
579 * door get objects).
580 */
581 register int sx, sy, sh;
582 char buf[BUFSZ];
583 int rmno = (sroom - rooms) + ROOMOFFSET;
584 const struct shclass *shp = &shtypes[shp_indx];
585
586 /* first, try to place a shopkeeper in the room */
587 if ((sh = shkinit(shp, sroom)) < 0)
588 return;
589
590 /* make sure no doorways without doors, and no */
591 /* trapped doors, in shops. */
592 sx = doors[sroom->fdoor].x;
593 sy = doors[sroom->fdoor].y;
594
595 if(levl[sx][sy].doormask == D_NODOOR) {
596 levl[sx][sy].doormask = D_ISOPEN;
597 newsym(sx,sy);
598 }
599 if(levl[sx][sy].typ == SDOOR) {
600 cvt_sdoor_to_door(&levl[sx][sy]); /* .typ = DOOR */
601 newsym(sx,sy);
602 }
603 if(levl[sx][sy].doormask & D_TRAPPED)
604 levl[sx][sy].doormask = D_LOCKED;
605
606 if(levl[sx][sy].doormask == D_LOCKED) {
607 register int m = sx, n = sy;
608
609 if(inside_shop(sx+1,sy)) m--;
610 else if(inside_shop(sx-1,sy)) m++;
611 if(inside_shop(sx,sy+1)) n--;
612 else if(inside_shop(sx,sy-1)) n++;
613 Sprintf(buf, "Closed for inventory");
614 make_engr_at(m, n, buf, 0L, DUST);
615 }
616
617 #ifdef BLACKMARKET
618 if (Is_blackmarket(&u.uz)) {
619 stock_blkmar(shp, sroom, sh);
620 level.flags.has_shop = TRUE;
621 return;
622 }
623 #endif /* BLACKMARKET */
624
625 for(sx = sroom->lx; sx <= sroom->hx; sx++)
626 for(sy = sroom->ly; sy <= sroom->hy; sy++) {
627 if(sroom->irregular) {
628 if (levl[sx][sy].edge || (int) levl[sx][sy].roomno != rmno ||
629 distmin(sx, sy, doors[sh].x, doors[sh].y) <= 1)
630 continue;
631 } else if((sx == sroom->lx && doors[sh].x == sx-1) ||
632 (sx == sroom->hx && doors[sh].x == sx+1) ||
633 (sy == sroom->ly && doors[sh].y == sy-1) ||
634 (sy == sroom->hy && doors[sh].y == sy+1)) continue;
635 mkshobj_at(shp, sx, sy);
636 }
637
638 /*
639 * Special monster placements (if any) should go here: that way,
640 * monsters will sit on top of objects and not the other way around.
641 */
642
643 level.flags.has_shop = TRUE;
644 }
645
646 #ifdef BLACKMARKET
647 /* stock a newly-created black market with objects */
648 static void
stock_blkmar(shp,sroom,sh)649 stock_blkmar(shp, sroom, sh)
650 const struct shclass *shp;
651 register struct mkroom *sroom;
652 register int sh;
653 {
654 /*
655 * Someday soon we'll dispatch on the shdist field of shclass to do
656 * different placements in this routine. Currently it only supports
657 * shop-style placement (all squares except a row nearest the first
658 * door get objects).
659 */
660 /* [max] removed register int cl, char buf[bufsz] */
661 int i, sx, sy, first = 0, next = 0, total, partial, typ;
662 struct obj *otmp;
663 int blkmar_gen[NUM_OBJECTS+2];
664 int *clp, *lastclp;
665 int goodcl[12];
666
667 goodcl[ 0] = WEAPON_CLASS;
668 goodcl[ 1] = ARMOR_CLASS;
669 goodcl[ 2] = RING_CLASS;
670 goodcl[ 3] = AMULET_CLASS;
671 goodcl[ 4] = TOOL_CLASS;
672 goodcl[ 5] = FOOD_CLASS;
673 goodcl[ 6] = POTION_CLASS;
674 goodcl[ 7] = SCROLL_CLASS;
675 goodcl[ 8] = SPBOOK_CLASS;
676 goodcl[ 9] = WAND_CLASS;
677 goodcl[10] = GEM_CLASS;
678 goodcl[11] = 0;
679
680 for (i=0; i < NUM_OBJECTS; i++) {
681 blkmar_gen[i] = 0;
682 }
683
684 total = 0;
685 for (clp=goodcl; *clp!=0; clp++) {
686 lastclp = clp;
687 first = bases[*clp];
688 /* this assumes that luckstone & loadstone comes just after the gems */
689 next = (*clp==GEM_CLASS) ? (LOADSTONE+1) : bases[(*clp)+1];
690 total += next-first;
691 }
692 if (total==0) return;
693
694 if (sroom->hx-sroom->lx<2) return;
695 clp = goodcl-1;
696 partial = 0;
697 for(sx = sroom->lx+1; sx <= sroom->hx; sx++) {
698 if (sx==sroom->lx+1 ||
699 ((sx-sroom->lx-2)*total)/(sroom->hx-sroom->lx-1)>partial) {
700 clp++;
701 if (clp>lastclp) clp = lastclp;
702 first = bases[*clp];
703 next = (*clp==GEM_CLASS) ? (LOADSTONE+1) : bases[(*clp)+1];
704 partial += next-first;
705 }
706
707 for(sy = sroom->ly; sy <= sroom->hy; sy++) {
708 if((sx == sroom->lx && doors[sh].x == sx-1) ||
709 (sx == sroom->hx && doors[sh].x == sx+1) ||
710 (sy == sroom->ly && doors[sh].y == sy-1) ||
711 (sy == sroom->hy && doors[sh].y == sy+1) || (rn2(3)))
712 continue;
713
714 for (i=0; i<50; i++) {
715 typ = rn2(next-first) + first;
716
717 /* forbidden objects */
718 if (typ==AMULET_OF_YENDOR || typ==CANDELABRUM_OF_INVOCATION ||
719 typ==BELL_OF_OPENING || typ==SPE_BOOK_OF_THE_DEAD ||
720 objects[typ].oc_nowish || typ==0)
721 continue;
722
723 otmp = mkobj_at(RANDOM_CLASS,sx,sy,TRUE);
724 /* generate multiple copies with decreasing probabilities */
725 /* if (rn2(blkmar_gen[typ]+1) && i<49) continue; */
726
727 /* otmp = mksobj_at(typ, sx, sy, TRUE, TRUE);
728 blkmar_gen[typ]++;*/
729
730 /* prevent wishing abuse */
731 if (typ==WAN_WISHING) {
732 otmp->spe = 0;
733 otmp->recharged = 1;
734 }
735 if (typ==MAGIC_LAMP) {
736 otmp->spe = 0;
737 }
738
739 break;
740 }
741
742 }
743 }
744
745 /*
746 * Special monster placements (if any) should go here: that way,
747 * monsters will sit on top of objects and not the other way around.
748 */
749 }
750 #endif /* BLACKMARKET */
751
752 #endif /* OVLB */
753 #ifdef OVL0
754
755 /* does shkp's shop stock this item type? */
756 boolean
saleable(shkp,obj)757 saleable(shkp, obj)
758 struct monst *shkp;
759 struct obj *obj;
760 {
761 int i, shp_indx = ESHK(shkp)->shoptype - SHOPBASE;
762 const struct shclass *shp = &shtypes[shp_indx];
763
764 if (shp->symb == RANDOM_CLASS) return TRUE;
765 else for (i = 0; i < SIZE(shtypes[0].iprobs) && shp->iprobs[i].iprob; i++)
766 if (shp->iprobs[i].itype < 0 ?
767 shp->iprobs[i].itype == - obj->otyp :
768 shp->iprobs[i].itype == obj->oclass) return TRUE;
769 /* not found */
770 return FALSE;
771 }
772
773 /* positive value: class; negative value: specific object type */
774 int
get_shop_item(type)775 get_shop_item(type)
776 int type;
777 {
778 const struct shclass *shp = shtypes+type;
779 register int i,j;
780
781 /* select an appropriate object type at random */
782 for(j = rnd(100), i = 0; (j -= shp->iprobs[i].iprob) > 0; i++)
783 continue;
784
785 return shp->iprobs[i].itype;
786 }
787
788 #endif /* OVL0 */
789
790 /*shknam.c*/
791