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*/