1    | /*	SCCS Id: @(#)mplayer.c	3.3	97/02/04	*/
2    | /*	Copyright (c) Izchak Miller, 1992.			  */
3    | /* NetHack may be freely redistributed.  See license for details. */
4    | 
5    | #include "hack.h"
6    | 
7    | STATIC_DCL const char *NDECL(dev_name);
8    | STATIC_DCL void FDECL(get_mplname, (struct monst *, char *));
9    | STATIC_DCL void FDECL(mk_mplayer_armor, (struct monst *, SHORT_P));
10   | 
11   | /* These are the names of those who
12   |  * contributed to the development of NetHack 3.2/3.3.
13   |  *
14   |  * Keep in alphabetical order within teams.
15   |  * Same first name is entered once within each team.
16   |  */
17   | static const char *developers[] = {
18   | 	/* devteam */
19   | 	"Dave", "Dean", "Eric", "Izchak", "Janet", "Jessie",
20   | 	"Ken", "Kevin", "Michael", "Mike", "Pat", "Paul", "Steve", "Timo",
21   | 	/* PC team */
22   | 	"Bill", "Eric", "Keizo", "Ken", "Kevin", "Michael", "Mike", "Paul",
23   | 	"Stephen", "Steve", "Timo", "Yitzhak",
24   | 	/* Amiga team */
25   | 	"Andy", "Gregg", "Keni", "Mike", "Olaf", "Richard",
26   | 	/* Mac team */
27   | 	"Andy", "Chris", "Dean", "Jon", "Jonathan", "Kevin", "Wang",
28   | 	/* Atari team */
29   | 	"Eric", "Warwick",
30   | 	/* NT team */
31   | 	"Michael",
32   | 	/* OS/2 team */
33   | 	"Helge", "Ron", "Timo",
34   | 	/* VMS team */
35   | 	"Joshua", "Pat",
36   | 	""};
37   | 
38   | 
39   | /* return a randomly chosen developer name */
40   | STATIC_OVL const char *
41   | dev_name()
42   | {
43   | 	register int i, m = 0, n = SIZE(developers);
44   | 	register struct monst *mtmp;
45   | 	register boolean match;
46   | 
47   | 	do {
48   | 	    match = FALSE;
49   | 	    i = rn2(n);
50   | 	    for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
51   | 		if(!is_mplayer(mtmp->data)) continue;
52   | 		if(!strncmp(developers[i], NAME(mtmp),
53   | 			               strlen(developers[i]))) {
54   | 		    match = TRUE;
55   | 		    break;
56   | 	        }
57   | 	    }
58   | 	    m++;
59   | 	} while (match && m < 100); /* m for insurance */
60   | 
61   | 	if (match) return (const char *)0;
62   | 	return(developers[i]);
63   | }
64   | 
65   | STATIC_OVL void
66   | get_mplname(mtmp, nam)
67   | register struct monst *mtmp;
68   | char *nam;
69   | {
70   | 	boolean fmlkind = is_female(mtmp->data);
71   | 	const char *devnam;
72   | 
73   | 	devnam = dev_name();
74   | 	if (!devnam)
75   | 	    Strcpy(nam, fmlkind ? "Eve" : "Adam");
76   | 	else if (fmlkind && !!strcmp(devnam, "Janet"))
77   | 	    Strcpy(nam, rn2(2) ? "Maud" : "Eve");
78   | 	else Strcpy(nam, devnam);
79   | 
80   | 	if (fmlkind || !strcmp(nam, "Janet"))
81   | 	    mtmp->female = 1;
82   | 	else
83   | 	    mtmp->female = 0;
84   | 	Strcat(nam, " the ");
85   | 	Strcat(nam, rank_of((int)mtmp->m_lev,
86   | 			    monsndx(mtmp->data),
87   | 			    (boolean)mtmp->female));
88   | }
89   | 
90   | STATIC_OVL void
91   | mk_mplayer_armor(mon, typ)
92   | struct monst *mon;
93   | short typ;
94   | {
95   | 	struct obj *obj;
96   | 
97   | 	if (typ == STRANGE_OBJECT) return;
98   | 	obj = mksobj(typ, FALSE, FALSE);
99   | 	if (!rn2(3)) obj->oerodeproof = 1;
100  | 	if (!rn2(3)) curse(obj);
101  | 	if (!rn2(3)) bless(obj);
102  | 	/* Most players who get to the endgame who have cursed equipment
103  | 	 * have it because the wizard or other monsters cursed it, so its
104  | 	 * chances of having plusses is the same as usual....
105  | 	 */
106  | 	obj->spe = rn2(10) ? (rn2(3) ? rn2(5) : rn1(4,4)) : -rnd(3);
107  | 	(void) mpickobj(mon, obj);
108  | }
109  | 
110  | struct monst *
111  | mk_mplayer(ptr, x, y, special)
112  | register struct permonst *ptr;
113  | xchar x, y;
114  | register boolean special;
115  | {
116  | 	register struct monst *mtmp;
117  | 	char nam[PL_NSIZ];
118  | 
119  | 	if(!is_mplayer(ptr))
120  | 		return((struct monst *)0);
121  | 
122  | 	if(MON_AT(x, y))
123  | 		rloc(m_at(x, y)); /* insurance */
124  | 
125  | 	if(!In_endgame(&u.uz)) special = FALSE;
126  | 
127  | 	if ((mtmp = makemon(ptr, x, y, NO_MM_FLAGS)) != 0) {
128  | 	    short weapon = rn2(2) ? LONG_SWORD : rnd_class(SPEAR, BULLWHIP);
129  | 	    short armor = rnd_class(GRAY_DRAGON_SCALE_MAIL, YELLOW_DRAGON_SCALE_MAIL);
130  | 	    short cloak = !rn2(8) ? STRANGE_OBJECT :
131  | 	    		rnd_class(OILSKIN_CLOAK, CLOAK_OF_DISPLACEMENT);
132  | 	    short helm = !rn2(8) ? STRANGE_OBJECT :
133  | 	    		rnd_class(ELVEN_LEATHER_HELM, HELM_OF_TELEPATHY);
134  | 	    short shield = !rn2(8) ? STRANGE_OBJECT :
135  | 	    		rnd_class(ELVEN_SHIELD, SHIELD_OF_REFLECTION);
136  | 	    int quan;
137  | 	    struct obj *otmp;
138  | 
139  | 	    mtmp->m_lev = (special ? rn1(16,15) : rnd(16));
140  | 	    mtmp->mhp = mtmp->mhpmax = d((int)mtmp->m_lev,10) +
141  | 					(special ? (30 + rnd(30)) : 30);
142  | 	    if(special) {
143  | 	        get_mplname(mtmp, nam);
144  | 	        mtmp = christen_monst(mtmp, nam);
145  | 		/* that's why they are "stuck" in the endgame :-) */
146  | 		(void)mongets(mtmp, FAKE_AMULET_OF_YENDOR);
147  | 	    }
148  | 	    mtmp->mpeaceful = 0;
149  | 	    set_malign(mtmp); /* peaceful may have changed again */
150  | 
151  | 	    switch(monsndx(ptr)) {
152  | 		case PM_ARCHEOLOGIST:
153  | 		    if (rn2(2)) weapon = BULLWHIP;
154  | 		    break;
155  | 		case PM_BARBARIAN:
156  | 		    if (rn2(2)) {
157  | 		    	weapon = rn2(2) ? TWO_HANDED_SWORD : BATTLE_AXE;
158  | 		    	shield = STRANGE_OBJECT;
159  | 		    }
160  | 		    if (rn2(2)) armor = rnd_class(PLATE_MAIL, CHAIN_MAIL);
161  | 		    if (helm == HELM_OF_BRILLIANCE) helm = STRANGE_OBJECT;
162  | 		    break;
163  | 		case PM_CAVEMAN:
164  | 		case PM_CAVEWOMAN:
165  | 		    if (rn2(4)) weapon = MACE;
166  | 		    else if (rn2(2)) weapon = CLUB;
167  | 		    if (helm == HELM_OF_BRILLIANCE) helm = STRANGE_OBJECT;
168  | 		    break;
169  | 		case PM_HEALER:
170  | 		    if (rn2(4)) weapon = QUARTERSTAFF;
171  | 		    else if (rn2(2)) weapon = rn2(2) ? UNICORN_HORN : SCALPEL;
172  | 		    if (rn2(4)) helm = rn2(2) ? HELM_OF_BRILLIANCE : HELM_OF_TELEPATHY;
173  | 		    if (rn2(2)) shield = STRANGE_OBJECT;
174  | 		    break;
175  | 		case PM_KNIGHT:
176  | 		    if (rn2(4)) weapon = LONG_SWORD;
177  | 		    if (rn2(2)) armor = rnd_class(PLATE_MAIL, CHAIN_MAIL);
178  | 		    break;
179  | 		case PM_MONK:
180  | 		    weapon = STRANGE_OBJECT;
181  | 		    armor = STRANGE_OBJECT;
182  | 		    cloak = ROBE;
183  | 		    if (rn2(2)) shield = STRANGE_OBJECT;
184  | 		    break;
185  | 		case PM_PRIEST:
186  | 		case PM_PRIESTESS:
187  | 		    if (rn2(2)) weapon = MACE;
188  | 		    if (rn2(2)) armor = rnd_class(PLATE_MAIL, CHAIN_MAIL);
189  | 		    if (rn2(4)) cloak = ROBE;
190  | 		    if (rn2(4)) helm = rn2(2) ? HELM_OF_BRILLIANCE : HELM_OF_TELEPATHY;
191  | 		    if (rn2(2)) shield = STRANGE_OBJECT;
192  | 		    break;
193  | 		case PM_RANGER:
194  | 		    if (rn2(2)) weapon = ELVEN_DAGGER;
195  | 		    break;
196  | 		case PM_ROGUE:
197  | 		    if (rn2(2)) weapon = SHORT_SWORD;
198  | 		    break;
199  | 		case PM_SAMURAI:
200  | 		    if (rn2(2)) weapon = KATANA;
201  | 		    break;
202  | #ifdef TOURIST
203  | 		case PM_TOURIST:
204  | 		    /* Defaults are just fine */
205  | 		    break;
206  | #endif
207  | 		case PM_VALKYRIE:
208  | 		    if (rn2(2)) weapon = WAR_HAMMER;
209  | 		    if (rn2(2)) armor = rnd_class(PLATE_MAIL, CHAIN_MAIL);
210  | 		    break;
211  | 		case PM_WIZARD:
212  | 		    if (rn2(4)) weapon = rn2(2) ? QUARTERSTAFF : ATHAME;
213  | 		    if (rn2(2)) {
214  | 		    	armor = rn2(2) ? BLACK_DRAGON_SCALE_MAIL :
215  | 		    			SILVER_DRAGON_SCALE_MAIL;
216  | 		    	cloak = CLOAK_OF_MAGIC_RESISTANCE;
217  | 		    }
218  | 		    if (rn2(4)) helm = HELM_OF_BRILLIANCE;
219  | 		    shield = STRANGE_OBJECT;
220  | 		    break;
221  | 		default: impossible("bad mplayer monster");
222  | 		    weapon = 0;
223  | 		    break;
224  | 	    }
225  | 
226  | 	    if (weapon != STRANGE_OBJECT) {
227  | 		otmp = mksobj(weapon, TRUE, FALSE);
228  | 		otmp->spe = (special ? rn1(5,4) : rn2(4));
229  | 		if (!rn2(3)) otmp->oerodeproof = 1;
230  | 		else if (!rn2(2)) otmp->greased = 1;
231  | 		if (special && rn2(2))
232  | 		    otmp = mk_artifact(otmp, A_NONE);
233  | 		/* mplayers knew better than to overenchant Magicbane */
234  | 		if (otmp->oartifact == ART_MAGICBANE)
235  | 		    otmp->spe = rnd(4);
236  | 		(void) mpickobj(mtmp, otmp);
237  | 	    }
238  | 
239  | 	    if(special) {
240  | 		if (!rn2(10))
241  | 		    (void) mongets(mtmp, rn2(3) ? LUCKSTONE : LOADSTONE);
242  | 		mk_mplayer_armor(mtmp, armor);
243  | 		mk_mplayer_armor(mtmp, cloak);
244  | 		mk_mplayer_armor(mtmp, helm);
245  | 		mk_mplayer_armor(mtmp, shield);
246  | 		if (rn2(8))
247  | 		    mk_mplayer_armor(mtmp, rnd_class(LEATHER_GLOVES,
248  | 					       GAUNTLETS_OF_DEXTERITY));
249  | 		if (rn2(8))
250  | 		    mk_mplayer_armor(mtmp, rnd_class(LOW_BOOTS, LEVITATION_BOOTS));
251  | 		m_dowear(mtmp, TRUE);
252  | 
253  | 		quan = rn2(3) ? rn2(3) : rn2(16);
254  | 		while(quan--)
255  | 		    (void)mongets(mtmp, rnd_class(DILITHIUM_CRYSTAL, JADE));
256  | 		/* To get the gold "right" would mean a player can double his */
257  | 		/* gold supply by killing one mplayer.  Not good. */
258  | 		mtmp->mgold = rn2(1000);
259  | 		quan = rn2(10);
260  | 		while(quan--)
261  | 		    (void) mpickobj(mtmp, mkobj(RANDOM_CLASS, FALSE));
262  | 	    }
263  | 	    quan = rnd(3);
264  | 	    while(quan--)
265  | 		(void)mongets(mtmp, rnd_offensive_item(mtmp));
266  | 	    quan = rnd(3);
267  | 	    while(quan--)
268  | 		(void)mongets(mtmp, rnd_defensive_item(mtmp));
269  | 	    quan = rnd(3);
270  | 	    while(quan--)
271  | 		(void)mongets(mtmp, rnd_misc_item(mtmp));
272  | 	}
273  | 
274  | 	return(mtmp);
275  | }
276  | 
277  | /* create the indicated number (num) of monster-players,
278  |  * randomly chosen, and in randomly chosen (free) locations
279  |  * on the level.  If "special", the size of num should not
280  |  * be bigger than the number of _non-repeated_ names in the
281  |  * developers array, otherwise a bunch of Adams and Eves will
282  |  * fill up the overflow.
283  |  */
284  | void
285  | create_mplayers(num, special)
286  | register int num;
287  | boolean special;
288  | {
289  | 	int pm, x, y;
290  | 	struct monst fakemon;
291  | 
292  | 	while(num) {
293  | 		int tryct = 0;
294  | 
295  | 		/* roll for character class */
296  | 		pm = PM_ARCHEOLOGIST + rn2(PM_WIZARD - PM_ARCHEOLOGIST + 1);
297  | 		fakemon.data = &mons[pm];
298  | 
299  | 		/* roll for an available location */
300  | 		do {
301  | 		    x = rn1(COLNO-4, 2);
302  | 		    y = rnd(ROWNO-2);
303  | 		} while(!goodpos(x, y, &fakemon) && tryct++ <= 50);
304  | 
305  | 		/* if pos not found in 50 tries, don't bother to continue */
306  | 		if(tryct > 50) return;
307  | 
308  | 		(void) mk_mplayer(&mons[pm], (xchar)x, (xchar)y, special);
309  | 		num--;
310  | 	}
311  | }
312  | 
313  | void
314  | mplayer_talk(mtmp)
315  | register struct monst *mtmp;
316  | {
317  | 	static const char *same_class_msg[3] = {
318  | 		"I can't win, and neither will you!",
319  | 		"You don't deserve to win!",
320  | 		"Mine should be the honor, not yours!",
321  | 	},		  *other_class_msg[3] = {
322  | 		"The low-life wants to talk, eh?",
323  | 		"Fight, scum!",
324  | 		"Here is what I have to say!",
325  | 	};
326  | 
327  | 	if(mtmp->mpeaceful) return; /* will drop to humanoid talk */
328  | 
329  | 	pline("Talk? -- %s",
330  | 		(mtmp->data == &mons[urole.malenum] ||
331  | 		mtmp->data == &mons[urole.femalenum]) ?
332  | 		same_class_msg[rn2(3)] : other_class_msg[rn2(3)]);
333  | }
334  | 
335  | /*mplayer.c*/