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