1 | /* SCCS Id: @(#)minion.c 3.3 2000/06/05 */
2 | /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 | /* NetHack may be freely redistributed. See license for details. */
4 |
5 | #include "hack.h"
6 | #include "emin.h"
7 | #include "epri.h"
8 |
9 | void
10 | msummon(ptr) /* ptr summons a monster */
11 | register struct permonst *ptr;
12 | {
13 | register int dtype = NON_PM, cnt = 0;
14 | aligntyp atyp = sgn(ptr->maligntyp);
15 |
16 | if (is_dprince(ptr) || (ptr == &mons[PM_WIZARD_OF_YENDOR])) {
17 | dtype = (!rn2(20)) ? dprince(atyp) :
18 | (!rn2(4)) ? dlord(atyp) : ndemon(atyp);
19 | cnt = (!rn2(4) && is_ndemon(&mons[dtype])) ? 2 : 1;
20 | } else if (is_dlord(ptr)) {
21 | dtype = (!rn2(50)) ? dprince(atyp) :
22 | (!rn2(20)) ? dlord(atyp) : ndemon(atyp);
23 | cnt = (!rn2(4) && is_ndemon(&mons[dtype])) ? 2 : 1;
24 | } else if (is_ndemon(ptr)) {
25 | dtype = (!rn2(20)) ? dlord(atyp) :
26 | (!rn2(6)) ? ndemon(atyp) : monsndx(ptr);
27 | cnt = 1;
28 | } else if (is_lminion(ptr)) {
29 | dtype = (is_lord(ptr) && !rn2(20)) ? llord() :
30 | (is_lord(ptr) || !rn2(6)) ? lminion() : monsndx(ptr);
31 | cnt = (!rn2(4) && !is_lord(&mons[dtype])) ? 2 : 1;
32 | }
33 |
34 | if (dtype == NON_PM) return;
35 |
36 | /* sanity checks */
37 | if (cnt > 1 && (mons[dtype].geno & G_UNIQ)) cnt = 1;
38 | /*
39 | * If this daemon is unique and being re-summoned (the only way we
40 | * could get this far with an extinct dtype), try another.
41 | */
42 | if (mvitals[dtype].mvflags & G_GONE) {
43 | dtype = ndemon(atyp);
44 | if (dtype == NON_PM) return;
45 | }
46 |
47 | while (cnt > 0) {
48 | (void)makemon(&mons[dtype], u.ux, u.uy, NO_MM_FLAGS);
49 | cnt--;
50 | }
51 | return;
52 | }
53 |
54 | void
55 | summon_minion(alignment, talk)
56 | aligntyp alignment;
57 | boolean talk;
58 | {
59 | register struct monst *mon;
60 | int mnum;
61 |
62 | switch ((int)alignment) {
63 | case A_LAWFUL:
64 | mnum = lminion();
65 | break;
66 | case A_NEUTRAL:
67 | mnum = PM_AIR_ELEMENTAL + rn2(4);
68 | break;
69 | case A_CHAOTIC:
70 | case A_NONE:
71 | mnum = ndemon(alignment);
72 | break;
73 | default:
74 | impossible("unaligned player?");
75 | mnum = ndemon(A_NONE);
76 | break;
77 | }
78 | if (mnum == NON_PM) {
79 | mon = 0;
80 | } else if (mons[mnum].pxlth == 0) {
81 | struct permonst *pm = &mons[mnum];
82 | mon = makemon(pm, u.ux, u.uy, MM_EMIN);
83 | if (mon) {
84 | mon->isminion = TRUE;
85 | EMIN(mon)->min_align = alignment;
86 | }
87 | } else if (mnum == PM_ANGEL) {
88 | mon = makemon(&mons[mnum], u.ux, u.uy, NO_MM_FLAGS);
89 | if (mon) {
90 | mon->isminion = TRUE;
91 | EPRI(mon)->shralign = alignment; /* always A_LAWFUL here */
92 | }
93 | } else
94 | mon = makemon(&mons[mnum], u.ux, u.uy, NO_MM_FLAGS);
95 | if (mon) {
96 | if (talk) {
97 | pline_The("voice of %s booms:", align_gname(alignment));
98 | verbalize("Thou shalt pay for thy indiscretion!");
99 | if (!Blind)
100 | pline("%s appears before you.", Amonnam(mon));
101 | }
102 | mon->mpeaceful = FALSE;
103 | /* don't call set_malign(); player was naughty */
104 | }
105 | }
106 |
107 | #define Athome (Inhell && !mtmp->cham)
108 |
109 | int
110 | demon_talk(mtmp) /* returns 1 if it won't attack. */
111 | register struct monst *mtmp;
112 | {
113 | long demand, offer;
114 |
115 | if (uwep && uwep->oartifact == ART_EXCALIBUR) {
116 | pline("%s looks very angry.", Amonnam(mtmp));
117 | mtmp->mpeaceful = mtmp->mtame = 0;
118 | newsym(mtmp->mx, mtmp->my);
119 | return 0;
120 | }
121 |
122 | /* Slight advantage given. */
123 | if (is_dprince(mtmp->data) && mtmp->minvis) {
124 | mtmp->minvis = mtmp->perminvis = 0;
125 | if (!Blind) pline("%s appears before you.", Amonnam(mtmp));
126 | newsym(mtmp->mx,mtmp->my);
127 | }
128 | if (youmonst.data->mlet == S_DEMON) { /* Won't blackmail their own. */
129 | pline("%s says, \"Good hunting, %s.\"",
130 | Amonnam(mtmp), flags.female ? "Sister" : "Brother");
131 | if (!tele_restrict(mtmp)) rloc(mtmp);
132 | return(1);
133 | }
134 | demand = (u.ugold * (rnd(80) + 20 * Athome)) /
135 | 100 * (1 + (sgn(u.ualign.type) == sgn(mtmp->data->maligntyp)));
136 | if (!demand) /* you have no gold */
137 | return mtmp->mpeaceful = 0;
138 | else {
139 | pline("%s demands %ld zorkmid%s for safe passage.",
140 | Amonnam(mtmp), demand, plur(demand));
141 |
142 | if ((offer = bribe(mtmp)) >= demand) {
143 | pline("%s vanishes, laughing about cowardly mortals.",
144 | Amonnam(mtmp));
145 | } else {
146 | if ((long)rnd(40) > (demand - offer)) {
147 | pline("%s scowls at you menacingly, then vanishes.",
148 | Amonnam(mtmp));
149 | } else {
150 | pline("%s gets angry...", Amonnam(mtmp));
151 | return mtmp->mpeaceful = 0;
152 | }
153 | }
154 | }
155 | mongone(mtmp);
156 | return(1);
157 | }
158 |
159 | long
160 | bribe(mtmp)
161 | struct monst *mtmp;
162 | {
163 | char buf[BUFSZ];
164 | long offer;
165 |
166 | getlin("How much will you offer?", buf);
167 | (void) sscanf(buf, "%ld", &offer);
168 |
169 | /*Michael Paddon -- fix for negative offer to monster*/
170 | /*JAR880815 - */
171 | if (offer < 0L) {
172 | You("try to shortchange %s, but fumble.",
173 | mon_nam(mtmp));
174 | offer = 0L;
175 | } else if (offer == 0L) {
176 | You("refuse.");
177 | } else if (offer >= u.ugold) {
178 | You("give %s all your gold.", mon_nam(mtmp));
179 | offer = u.ugold;
180 | } else You("give %s %ld zorkmid%s.", mon_nam(mtmp), offer,
181 | plur(offer));
182 |
183 | u.ugold -= offer;
184 | mtmp->mgold += offer;
185 | flags.botl = 1;
186 | return(offer);
187 | }
188 |
189 | int
190 | dprince(atyp)
191 | aligntyp atyp;
192 | {
193 | int tryct, pm;
194 |
195 | for (tryct = 0; tryct < 20; tryct++) {
196 | pm = rn1(PM_DEMOGORGON + 1 - PM_ORCUS, PM_ORCUS);
197 | if (!(mvitals[pm].mvflags & G_GONE) &&
198 | (atyp == A_NONE || sgn(mons[pm].maligntyp) == sgn(atyp)))
199 | return(pm);
200 | }
201 | return(dlord(atyp)); /* approximate */
202 | }
203 |
204 | int
205 | dlord(atyp)
206 | aligntyp atyp;
207 | {
208 | int tryct, pm;
209 |
210 | for (tryct = 0; tryct < 20; tryct++) {
211 | pm = rn1(PM_YEENOGHU + 1 - PM_JUIBLEX, PM_JUIBLEX);
212 | if (!(mvitals[pm].mvflags & G_GONE) &&
213 | (atyp == A_NONE || sgn(mons[pm].maligntyp) == sgn(atyp)))
214 | return(pm);
215 | }
216 | return(ndemon(atyp)); /* approximate */
217 | }
218 |
219 | /* create lawful (good) lord */
220 | int
221 | llord()
222 | {
223 | if (!(mvitals[PM_ARCHON].mvflags & G_GONE))
224 | return(PM_ARCHON);
225 |
226 | return(lminion()); /* approximate */
227 | }
228 |
229 | int
230 | lminion()
231 | {
232 | int tryct;
233 | struct permonst *ptr;
234 |
235 | for (tryct = 0; tryct < 20; tryct++) {
236 | ptr = mkclass(S_ANGEL,0);
237 | if (ptr && !is_lord(ptr))
238 | return(monsndx(ptr));
239 | }
240 |
241 | return NON_PM;
242 | }
243 |
244 | int
245 | ndemon(atyp)
246 | aligntyp atyp;
247 | {
248 | int tryct;
249 | struct permonst *ptr;
250 |
251 | for (tryct = 0; tryct < 20; tryct++) {
252 | ptr = mkclass(S_DEMON, 0);
253 | if (ptr && is_ndemon(ptr) &&
254 | (atyp == A_NONE || sgn(ptr->maligntyp) == sgn(atyp)))
255 | return(monsndx(ptr));
256 | }
257 |
258 | return NON_PM;
259 | }
260 |
261 | /*minion.c*/