dumplog message history groundwork
[aNetHack.git] / src / minion.c
blobd0394477ba3e9b87b69b36c8039f301cead807fd
1 /* NetHack 3.6 minion.c $NHDT-Date: 1432512773 2015/05/25 00:12:53 $ $NHDT-Branch: master $:$NHDT-Revision: 1.33 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 #include "hack.h"
7 void
8 newemin(mtmp)
9 struct monst *mtmp;
11 if (!mtmp->mextra)
12 mtmp->mextra = newmextra();
13 if (!EMIN(mtmp)) {
14 EMIN(mtmp) = (struct emin *) alloc(sizeof(struct emin));
15 (void) memset((genericptr_t) EMIN(mtmp), 0, sizeof(struct emin));
19 void
20 free_emin(mtmp)
21 struct monst *mtmp;
23 if (mtmp->mextra && EMIN(mtmp)) {
24 free((genericptr_t) EMIN(mtmp));
25 EMIN(mtmp) = (struct emin *) 0;
27 mtmp->isminion = 0;
30 /* count the number of monsters on the level */
31 int
32 monster_census(spotted)
33 boolean spotted; /* seen|sensed vs all */
35 struct monst *mtmp;
36 int count = 0;
38 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
39 if (DEADMONSTER(mtmp))
40 continue;
41 if (spotted && !canspotmon(mtmp))
42 continue;
43 ++count;
45 return count;
48 /* mon summons a monster */
49 int
50 msummon(mon)
51 struct monst *mon;
53 struct permonst *ptr;
54 int dtype = NON_PM, cnt = 0, result = 0, census;
55 aligntyp atyp;
56 struct monst *mtmp;
58 if (mon) {
59 ptr = mon->data;
61 if (uwep && uwep->oartifact == ART_DEMONBANE && is_demon(ptr)) {
62 if (canseemon(mon))
63 pline("%s looks puzzled for a moment.", Monnam(mon));
64 return 0;
67 atyp = mon->ispriest ? EPRI(mon)->shralign
68 : mon->isminion ? EMIN(mon)->min_align
69 : (ptr->maligntyp == A_NONE)
70 ? A_NONE
71 : sgn(ptr->maligntyp);
72 } else {
73 ptr = &mons[PM_WIZARD_OF_YENDOR];
74 atyp = (ptr->maligntyp == A_NONE) ? A_NONE : sgn(ptr->maligntyp);
77 if (is_dprince(ptr) || (ptr == &mons[PM_WIZARD_OF_YENDOR])) {
78 dtype = (!rn2(20)) ? dprince(atyp) : (!rn2(4)) ? dlord(atyp)
79 : ndemon(atyp);
80 cnt = (!rn2(4) && is_ndemon(&mons[dtype])) ? 2 : 1;
81 } else if (is_dlord(ptr)) {
82 dtype = (!rn2(50)) ? dprince(atyp) : (!rn2(20)) ? dlord(atyp)
83 : ndemon(atyp);
84 cnt = (!rn2(4) && is_ndemon(&mons[dtype])) ? 2 : 1;
85 } else if (is_ndemon(ptr)) {
86 dtype = (!rn2(20)) ? dlord(atyp) : (!rn2(6)) ? ndemon(atyp)
87 : monsndx(ptr);
88 cnt = 1;
89 } else if (is_lminion(mon)) {
90 dtype = (is_lord(ptr) && !rn2(20))
91 ? llord()
92 : (is_lord(ptr) || !rn2(6)) ? lminion() : monsndx(ptr);
93 cnt = (!rn2(4) && !is_lord(&mons[dtype])) ? 2 : 1;
94 } else if (ptr == &mons[PM_ANGEL]) {
95 /* non-lawful angels can also summon */
96 if (!rn2(6)) {
97 switch (atyp) { /* see summon_minion */
98 case A_NEUTRAL:
99 dtype = PM_AIR_ELEMENTAL + rn2(4);
100 break;
101 case A_CHAOTIC:
102 case A_NONE:
103 dtype = ndemon(atyp);
104 break;
106 } else {
107 dtype = PM_ANGEL;
109 cnt = (!rn2(4) && !is_lord(&mons[dtype])) ? 2 : 1;
112 if (dtype == NON_PM)
113 return 0;
115 /* sanity checks */
116 if (cnt > 1 && (mons[dtype].geno & G_UNIQ))
117 cnt = 1;
119 * If this daemon is unique and being re-summoned (the only way we
120 * could get this far with an extinct dtype), try another.
122 if (mvitals[dtype].mvflags & G_GONE) {
123 dtype = ndemon(atyp);
124 if (dtype == NON_PM)
125 return 0;
128 /* some candidates can generate a group of monsters, so simple
129 count of non-null makemon() result is not sufficient */
130 census = monster_census(FALSE);
132 while (cnt > 0) {
133 mtmp = makemon(&mons[dtype], u.ux, u.uy, MM_EMIN);
134 if (mtmp) {
135 result++;
136 /* an angel's alignment should match the summoner */
137 if (dtype == PM_ANGEL) {
138 mtmp->isminion = 1;
139 EMIN(mtmp)->min_align = atyp;
140 /* renegade if same alignment but not peaceful
141 or peaceful but different alignment */
142 EMIN(mtmp)->renegade =
143 (atyp != u.ualign.type) ^ !mtmp->mpeaceful;
146 cnt--;
149 /* how many monsters exist now compared to before? */
150 if (result)
151 result = monster_census(FALSE) - census;
153 return result;
156 void
157 summon_minion(alignment, talk)
158 aligntyp alignment;
159 boolean talk;
161 register struct monst *mon;
162 int mnum;
164 switch ((int) alignment) {
165 case A_LAWFUL:
166 mnum = lminion();
167 break;
168 case A_NEUTRAL:
169 mnum = PM_AIR_ELEMENTAL + rn2(4);
170 break;
171 case A_CHAOTIC:
172 case A_NONE:
173 mnum = ndemon(alignment);
174 break;
175 default:
176 impossible("unaligned player?");
177 mnum = ndemon(A_NONE);
178 break;
180 if (mnum == NON_PM) {
181 mon = 0;
182 } else if (mnum == PM_ANGEL) {
183 mon = makemon(&mons[mnum], u.ux, u.uy, MM_EMIN);
184 if (mon) {
185 mon->isminion = 1;
186 EMIN(mon)->min_align = alignment;
187 EMIN(mon)->renegade = FALSE;
189 } else if (mnum != PM_SHOPKEEPER && mnum != PM_GUARD
190 && mnum != PM_ALIGNED_PRIEST && mnum != PM_HIGH_PRIEST) {
191 /* This was mons[mnum].pxlth == 0 but is this restriction
192 appropriate or necessary now that the structures are separate? */
193 mon = makemon(&mons[mnum], u.ux, u.uy, MM_EMIN);
194 if (mon) {
195 mon->isminion = 1;
196 EMIN(mon)->min_align = alignment;
197 EMIN(mon)->renegade = FALSE;
199 } else {
200 mon = makemon(&mons[mnum], u.ux, u.uy, NO_MM_FLAGS);
202 if (mon) {
203 if (talk) {
204 pline_The("voice of %s booms:", align_gname(alignment));
205 verbalize("Thou shalt pay for thine indiscretion!");
206 if (!Blind)
207 pline("%s appears before you.", Amonnam(mon));
208 mon->mstrategy &= ~STRAT_APPEARMSG;
210 mon->mpeaceful = FALSE;
211 /* don't call set_malign(); player was naughty */
215 #define Athome (Inhell && (mtmp->cham == NON_PM))
217 /* returns 1 if it won't attack. */
219 demon_talk(mtmp)
220 register struct monst *mtmp;
222 long cash, demand, offer;
224 if (uwep && uwep->oartifact == ART_EXCALIBUR) {
225 pline("%s looks very angry.", Amonnam(mtmp));
226 mtmp->mpeaceful = mtmp->mtame = 0;
227 set_malign(mtmp);
228 newsym(mtmp->mx, mtmp->my);
229 return 0;
232 if (is_fainted()) {
233 reset_faint(); /* if fainted - wake up */
234 } else {
235 stop_occupation();
236 if (multi > 0) {
237 nomul(0);
238 unmul((char *) 0);
242 /* Slight advantage given. */
243 if (is_dprince(mtmp->data) && mtmp->minvis) {
244 boolean wasunseen = !canspotmon(mtmp);
246 mtmp->minvis = mtmp->perminvis = 0;
247 if (wasunseen && canspotmon(mtmp)) {
248 pline("%s appears before you.", Amonnam(mtmp));
249 mtmp->mstrategy &= ~STRAT_APPEARMSG;
251 newsym(mtmp->mx, mtmp->my);
253 if (youmonst.data->mlet == S_DEMON) { /* Won't blackmail their own. */
254 pline("%s says, \"Good hunting, %s.\"", Amonnam(mtmp),
255 flags.female ? "Sister" : "Brother");
256 if (!tele_restrict(mtmp))
257 (void) rloc(mtmp, TRUE);
258 return (1);
260 cash = money_cnt(invent);
261 demand =
262 (cash * (rnd(80) + 20 * Athome))
263 / (100 * (1 + (sgn(u.ualign.type) == sgn(mtmp->data->maligntyp))));
265 if (!demand || multi < 0) { /* you have no gold or can't move */
266 mtmp->mpeaceful = 0;
267 set_malign(mtmp);
268 return 0;
269 } else {
270 /* make sure that the demand is unmeetable if the monster
271 has the Amulet, preventing monster from being satisfied
272 and removed from the game (along with said Amulet...) */
273 if (mon_has_amulet(mtmp))
274 demand = cash + (long) rn1(1000, 40);
276 pline("%s demands %ld %s for safe passage.", Amonnam(mtmp), demand,
277 currency(demand));
279 if ((offer = bribe(mtmp)) >= demand) {
280 pline("%s vanishes, laughing about cowardly mortals.",
281 Amonnam(mtmp));
282 } else if (offer > 0L && (long) rnd(40) > (demand - offer)) {
283 pline("%s scowls at you menacingly, then vanishes.",
284 Amonnam(mtmp));
285 } else {
286 pline("%s gets angry...", Amonnam(mtmp));
287 mtmp->mpeaceful = 0;
288 set_malign(mtmp);
289 return 0;
292 mongone(mtmp);
293 return (1);
296 long
297 bribe(mtmp)
298 struct monst *mtmp;
300 char buf[BUFSZ];
301 long offer;
302 long umoney = money_cnt(invent);
304 getlin("How much will you offer?", buf);
305 if (sscanf(buf, "%ld", &offer) != 1)
306 offer = 0L;
308 /*Michael Paddon -- fix for negative offer to monster*/
309 /*JAR880815 - */
310 if (offer < 0L) {
311 You("try to shortchange %s, but fumble.", mon_nam(mtmp));
312 return 0L;
313 } else if (offer == 0L) {
314 You("refuse.");
315 return 0L;
316 } else if (offer >= umoney) {
317 You("give %s all your gold.", mon_nam(mtmp));
318 offer = umoney;
319 } else {
320 You("give %s %ld %s.", mon_nam(mtmp), offer, currency(offer));
322 (void) money2mon(mtmp, offer);
323 context.botl = 1;
324 return (offer);
328 dprince(atyp)
329 aligntyp atyp;
331 int tryct, pm;
333 for (tryct = !In_endgame(&u.uz) ? 20 : 0; tryct > 0; --tryct) {
334 pm = rn1(PM_DEMOGORGON + 1 - PM_ORCUS, PM_ORCUS);
335 if (!(mvitals[pm].mvflags & G_GONE)
336 && (atyp == A_NONE || sgn(mons[pm].maligntyp) == sgn(atyp)))
337 return (pm);
339 return (dlord(atyp)); /* approximate */
343 dlord(atyp)
344 aligntyp atyp;
346 int tryct, pm;
348 for (tryct = !In_endgame(&u.uz) ? 20 : 0; tryct > 0; --tryct) {
349 pm = rn1(PM_YEENOGHU + 1 - PM_JUIBLEX, PM_JUIBLEX);
350 if (!(mvitals[pm].mvflags & G_GONE)
351 && (atyp == A_NONE || sgn(mons[pm].maligntyp) == sgn(atyp)))
352 return (pm);
354 return (ndemon(atyp)); /* approximate */
357 /* create lawful (good) lord */
359 llord()
361 if (!(mvitals[PM_ARCHON].mvflags & G_GONE))
362 return (PM_ARCHON);
364 return (lminion()); /* approximate */
368 lminion()
370 int tryct;
371 struct permonst *ptr;
373 for (tryct = 0; tryct < 20; tryct++) {
374 ptr = mkclass(S_ANGEL, 0);
375 if (ptr && !is_lord(ptr))
376 return (monsndx(ptr));
379 return NON_PM;
383 ndemon(atyp)
384 aligntyp atyp;
386 int tryct;
387 struct permonst *ptr;
389 for (tryct = 0; tryct < 20; tryct++) {
390 ptr = mkclass(S_DEMON, 0);
391 if (ptr && is_ndemon(ptr)
392 && (atyp == A_NONE || sgn(ptr->maligntyp) == sgn(atyp)))
393 return (monsndx(ptr));
396 return NON_PM;
399 /* guardian angel has been affected by conflict so is abandoning hero */
400 void
401 lose_guardian_angel(mon)
402 struct monst *mon; /* if null, angel hasn't been created yet */
404 coord mm;
405 int i;
407 if (mon) {
408 if (canspotmon(mon)) {
409 if (!Deaf) {
410 pline("%s rebukes you, saying:", Monnam(mon));
411 verbalize("Since you desire conflict, have some more!");
412 } else {
413 pline("%s vanishes!", Monnam(mon));
416 mongone(mon);
418 /* create 2 to 4 hostile angels to replace the lost guardian */
419 for (i = rn1(3, 2); i > 0; --i) {
420 mm.x = u.ux;
421 mm.y = u.uy;
422 if (enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL]))
423 (void) mk_roamer(&mons[PM_ANGEL], u.ualign.type, mm.x, mm.y,
424 FALSE);
428 /* just entered the Astral Plane; receive tame guardian angel if worthy */
429 void
430 gain_guardian_angel()
432 struct monst *mtmp;
433 struct obj *otmp;
434 coord mm;
436 Hear_again(); /* attempt to cure any deafness now (divine
437 message will be heard even if that fails) */
438 if (Conflict) {
439 pline("A voice booms:");
440 verbalize("Thy desire for conflict shall be fulfilled!");
441 /* send in some hostile angels instead */
442 lose_guardian_angel((struct monst *) 0);
443 } else if (u.ualign.record > 8) { /* fervent */
444 pline("A voice whispers:");
445 verbalize("Thou hast been worthy of me!");
446 mm.x = u.ux;
447 mm.y = u.uy;
448 if (enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL])
449 && (mtmp = mk_roamer(&mons[PM_ANGEL], u.ualign.type, mm.x, mm.y,
450 TRUE)) != 0) {
451 mtmp->mstrategy &= ~STRAT_APPEARMSG;
452 if (!Blind)
453 pline("An angel appears near you.");
454 else
455 You_feel("the presence of a friendly angel near you.");
456 /* guardian angel -- the one case mtame doesn't
457 * imply an edog structure, so we don't want to
458 * call tamedog().
460 mtmp->mtame = 10;
461 /* make him strong enough vs. endgame foes */
462 mtmp->m_lev = rn1(8, 15);
463 mtmp->mhp = mtmp->mhpmax =
464 d((int) mtmp->m_lev, 10) + 30 + rnd(30);
465 if ((otmp = select_hwep(mtmp)) == 0) {
466 otmp = mksobj(SILVER_SABER, FALSE, FALSE);
467 if (mpickobj(mtmp, otmp))
468 panic("merged weapon?");
470 bless(otmp);
471 if (otmp->spe < 4)
472 otmp->spe += rnd(4);
473 if ((otmp = which_armor(mtmp, W_ARMS)) == 0
474 || otmp->otyp != SHIELD_OF_REFLECTION) {
475 (void) mongets(mtmp, AMULET_OF_REFLECTION);
476 m_dowear(mtmp, TRUE);
482 /*minion.c*/