OSDN Git Service

shrink mine
[nethackexpress/trunk.git] / src / shknam.c
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
19 static 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
36 static 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
47 static 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
58 static 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
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",
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
85 static 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
97 static 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
108 static 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
139 static 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
151 static 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
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}},
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 */
227 void
228 init_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
245 STATIC_OVL void
246 mkshobj_at(shp, sx, sy)
247 /* make an object of the appropriate type for a shop square */
248 const struct shclass *shp;
249 int 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 */
273 STATIC_OVL void
274 nameshk(shk, nlp)
275 struct monst *shk;
276 const 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
334 STATIC_OVL int
335 shkinit(shp, sroom)     /* create a new shopkeeper in the given room */
336 const struct shclass    *shp;
337 struct 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 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 */
424 void
425 stock_room(shp_indx, sroom)
426 int shp_indx;
427 register 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? */
496 boolean
497 saleable(shkp, obj)
498 struct monst *shkp;
499 struct 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 */
514 int
515 get_shop_item(type)
516 int 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*/