/* returns 1 if it won't attack. */ int demon_talk(struct monst *mtmp) { long cash, demand, offer; if (uwep && uwep->oartifact == ART_EXCALIBUR) { pline("%s looks very angry.", Amonnam(mtmp)); msethostility(mtmp, TRUE, TRUE); return 0; } /* Slight advantage given. */ if (is_dprince(mtmp->data) && mtmp->minvis) { mtmp->minvis = mtmp->perminvis = 0; if (!Blind) pline("%s appears before you.", Amonnam(mtmp)); newsym(mtmp->mx, mtmp->my); } if (youmonst.data->mlet == S_DEMON) { /* Won't blackmail their own. */ pline("%s says, \"Good hunting, %s.\"", Amonnam(mtmp), u.ufemale ? "Sister" : "Brother"); if (!tele_restrict(mtmp)) rloc(mtmp, TRUE); return 1; } cash = money_cnt(invent); /* don't bother with a custom RNG here, too much unpredictability is involved */ demand = (cash * (rnd(80) + 20 * Athome)) / (100 * (1 + (sgn(u.ualign.type) == sgn(mtmp->data->maligntyp)))); if (!demand) { /* you have no gold */ msethostility(mtmp, TRUE, TRUE); return 0; } else { /* make sure that the demand is unmeetable if the monster has the Amulet, preventing monster from being satisified and removed from the game (along with said Amulet...) */ if (mon_has_amulet(mtmp)) demand = cash + (long)rn1(1000, 40); pline("%s demands %ld %s for safe passage.", Amonnam(mtmp), demand, currency(demand)); if ((offer = bribe(mtmp)) >= demand) { pline("%s vanishes, laughing about cowardly %s.", Amonnam(mtmp), makeplural(mortal_or_creature(youmonst.data, FALSE))); } else if (offer > 0L && (long)rnd(40) > (demand - offer)) { pline("%s scowls at you menacingly, then vanishes.", Amonnam(mtmp)); } else { pline("%s gets angry...", Amonnam(mtmp)); msethostility(mtmp, TRUE, TRUE); return 0; } } mongone(mtmp); return 1; }
struct monst * mk_roamer(const struct permonst *ptr, aligntyp alignment, struct level *lev, xchar x, xchar y, boolean peaceful, int mm_flags) { struct monst *roamer; boolean coaligned = (u.ualign.type == alignment); if (ptr != &mons[PM_ALIGNED_PRIEST] && ptr != &mons[PM_ANGEL]) return NULL; if (MON_AT(lev, x, y)) rloc(m_at(lev, x, y), FALSE); /* insurance */ if (!(roamer = makemon(ptr, lev, x, y, mm_flags))) return NULL; EPRI(roamer)->shralign = alignment; if (coaligned && !peaceful) EPRI(roamer)->renegade = TRUE; /* roamer->ispriest == FALSE naturally */ roamer->isminion = TRUE; /* borrowing this bit */ roamer->mtrapseen = ~0; /* traps are known */ msethostility(roamer, !peaceful, TRUE); /* TODO: handle in_mklev */ roamer->msleeping = 0; /* MORE TO COME */ return roamer; }
/* Charm snakes in range. Note that the snakes are NOT tamed. */ static void charm_snakes(int distance) { struct monst *mtmp = level->monlist; int could_see_mon, was_peaceful; while (mtmp) { if (!DEADMONSTER(mtmp) && mtmp->data->mlet == S_SNAKE && mtmp->mcanmove && distu(mtmp->mx, mtmp->my) < distance) { was_peaceful = mtmp->mpeaceful; mtmp->mavenge = 0; could_see_mon = canspotmon(mtmp); mtmp->mundetected = 0; msethostility(mtmp, FALSE, FALSE); /* does a newsym() */ if (canseemon(mtmp)) { if (!could_see_mon) pline(msgc_youdiscover, "You notice %s, swaying with the music.", a_monnam(mtmp)); else pline(msgc_actionok, "%s freezes, then sways with the music%s.", Monnam(mtmp), was_peaceful ? "" : ", and now seems quieter"); } } mtmp = mtmp->nmon; } }
void reset_hostility(struct monst *roamer) { if (! (roamer->isminion && (roamer->data == &mons[PM_ALIGNED_PRIEST] || roamer->data == &mons[PM_ANGEL]))) return; if (EPRI(roamer)->shralign != u.ualign.type) msethostility(roamer, TRUE, TRUE); }
void summon_minion(aligntyp alignment, boolean talk) { struct monst *mon; int mnum; switch ((int)alignment) { case A_LAWFUL: mnum = lminion(); break; case A_NEUTRAL: mnum = PM_AIR_ELEMENTAL + rn2(4); break; case A_CHAOTIC: case A_NONE: mnum = ndemon(&u.uz, alignment); break; default: impossible("unaligned player?"); mnum = ndemon(&u.uz, A_NONE); break; } if (mnum == NON_PM) { mon = 0; } else if (mons[mnum].pxtyp == MX_NONE) { const struct permonst *pm = &mons[mnum]; mon = makemon(pm, level, u.ux, u.uy, MM_EMIN); if (mon) { mon->isminion = TRUE; EMIN(mon)->min_align = alignment; } } else if (roamer_type(&mons[mnum])) { mon = makemon(&mons[mnum], level, u.ux, u.uy, NO_MM_FLAGS); if (mon) { mon->isminion = TRUE; EPRI(mon)->shralign = alignment; } } else mon = makemon(&mons[mnum], level, u.ux, u.uy, NO_MM_FLAGS); if (mon) { if (talk) { pline("The voice of %s booms:", align_gname(alignment)); verbalize("Thou shalt pay for thy indiscretion!"); if (!Blind) pline("%s appears before you.", Amonnam(mon)); } msethostility(mon, TRUE, FALSE); /* don't call set_malign(); player was naughty */ } }
/* Calm nymphs in range. */ static void calm_nymphs(int distance) { struct monst *mtmp = level->monlist; while (mtmp) { if (!DEADMONSTER(mtmp) && mtmp->data->mlet == S_NYMPH && mtmp->mcanmove && distu(mtmp->mx, mtmp->my) < distance) { mtmp->msleeping = 0; msethostility(mtmp, FALSE, FALSE); mtmp->mavenge = 0; if (canseemon(mtmp)) pline(msgc_actionok, "%s listens cheerfully to the music, then seems quieter.", Monnam(mtmp)); } mtmp = mtmp->nmon; } }
static void prisoner_speaks(struct monst *mtmp) { if (mtmp->data == &mons[PM_PRISONER] && (mtmp->mstrategy & STRAT_WAITMASK)) { /* Awaken the prisoner */ if (canseemon(mtmp)) pline("%s speaks:", Monnam(mtmp)); verbalize("I'm finally free!"); mtmp->mstrategy &= ~STRAT_WAITMASK; msethostility(mtmp, FALSE, FALSE); /* TODO: reset alignment? */ /* Your god is happy... */ adjalign(3); /* ...But the guards are not */ angry_guards(FALSE); } return; }
/* Awake only soldiers of the level. */ void awaken_soldiers(struct monst *culprit) { struct monst *mtmp; for (mtmp = level->monlist; mtmp; mtmp = mtmp->nmon) { if (!DEADMONSTER(mtmp) && is_mercenary(mtmp->data) && !mx_egd(mtmp)) { mtmp->mfrozen = 0; msethostility(mtmp, TRUE, FALSE); mtmp->mcanmove = 1; mtmp->msleeping = 0; if (canseemon(mtmp)) pline(culprit == &youmonst ? msgc_actionok : msgc_moncombatbad, "%s is now ready for battle!", Monnam(mtmp)); else pline_once(msgc_levelsound, "You hear the rattle of battle gear being readied."); } } }
/* create a new shopkeeper in the given room; uses level creation RNG */ static int shkinit(const struct shclass *shp, struct level *lev, struct mkroom *sroom) { int sh, sx, sy; struct monst *shk; /* place the shopkeeper in the given room */ sh = sroom->fdoor; sx = lev->doors[sh].x; sy = lev->doors[sh].y; /* check that the shopkeeper placement is sane */ if (sroom->irregular) { int rmno = (sroom - lev->rooms) + ROOMOFFSET; if (isok(sx - 1, sy) && !lev->locations[sx - 1][sy].edge && (int)lev->locations[sx - 1][sy].roomno == rmno) sx--; else if (isok(sx + 1, sy) && !lev->locations[sx + 1][sy].edge && (int)lev->locations[sx + 1][sy].roomno == rmno) sx++; else if (isok(sx, sy - 1) && !lev->locations[sx][sy - 1].edge && (int)lev->locations[sx][sy - 1].roomno == rmno) sy--; else if (isok(sx, sy + 1) && !lev->locations[sx][sy + 1].edge && (int)lev->locations[sx][sy + 1].roomno == rmno) sx++; else goto shk_failed; } else if (sx == sroom->lx - 1) sx++; else if (sx == sroom->hx + 1) sx--; else if (sy == sroom->ly - 1) sy++; else if (sy == sroom->hy + 1) sy--; else { shk_failed: return -1; } if (MON_AT(lev, sx, sy)) rloc(m_at(lev, sx, sy), FALSE); /* insurance */ /* now initialize the shopkeeper monster structure */ if (!(shk = makemon(&mons[PM_SHOPKEEPER], lev, sx, sy, MM_ALLLEVRNG))) return -1; shk->isshk = 1; msethostility(shk, FALSE, TRUE); shk->msleeping = 0; shk->mtrapseen = ~0; /* we know all the traps already */ ESHK(shk)->shoproom = (sroom - lev->rooms) + ROOMOFFSET; sroom->resident = shk; ESHK(shk)->shoptype = sroom->rtype; assign_level(&(ESHK(shk)->shoplevel), &lev->z); ESHK(shk)->shd = lev->doors[sh]; ESHK(shk)->shk.x = sx; ESHK(shk)->shk.y = sy; ESHK(shk)->robbed = 0L; ESHK(shk)->credit = 0L; ESHK(shk)->debit = 0L; ESHK(shk)->loan = 0L; ESHK(shk)->visitct = 0; ESHK(shk)->following = 0; ESHK(shk)->billct = 0; ESHK(shk)->bill_inactive = FALSE; /* initial capital */ mkmonmoney(shk, 1030L + 30L * mklev_rn2(100, lev), rng_for_level(&lev->z)); if (shp->shknms == shkrings) mongets(shk, TOUCHSTONE, rng_for_level(&lev->z)); nameshk(shk, shp->shknms, lev); return sh; }
void priest_talk(struct monst *priest) { boolean coaligned = p_coaligned(priest); boolean strayed = (u.ualign.record < 0); /* KMH, conduct */ break_conduct(conduct_gnostic); if (priest->mflee || (!priest->ispriest && coaligned && strayed)) { pline("%s doesn't want anything to do with you!", Monnam(priest)); msethostility(priest, TRUE, FALSE); return; } /* priests don't chat unless peaceful and in their own temple */ if (!histemple_at(priest, priest->mx, priest->my) || !priest->mpeaceful || !priest->mcanmove || priest->msleeping) { static const char *const cranky_msg[3] = { "Thou wouldst have words, eh? I'll give thee a word or two!", "Talk? Here is what I have to say!", "Pilgrim, I would speak no longer with thee." }; if (!priest->mcanmove || priest->msleeping) { pline("%s breaks out of %s reverie!", Monnam(priest), mhis(priest)); priest->mfrozen = priest->msleeping = 0; priest->mcanmove = 1; } msethostility(priest, TRUE, FALSE); verbalize("%s", cranky_msg[rn2(3)]); return; } /* you desecrated the temple and now you want to chat? */ if (priest->mpeaceful && *in_rooms(level, priest->mx, priest->my, TEMPLE) && !has_shrine(priest)) { verbalize ("Begone! Thou desecratest this holy place with thy presence."); msethostility(priest, TRUE, FALSE); return; } if (!money_cnt(invent)) { if (coaligned && !strayed) { long pmoney = money_cnt(priest->minvent); if (pmoney > 0L) { /* Note: two bits is actually 25 cents. Hmm. */ pline("%s gives you %s for an ale.", Monnam(priest), (pmoney == 1L) ? "one bit" : "two bits"); money2u(priest, pmoney > 1L ? 2 : 1); } else pline("%s preaches the virtues of poverty.", Monnam(priest)); } else pline("%s is not interested.", Monnam(priest)); return; } else { long offer; pline("%s asks you for a contribution for the temple.", Monnam(priest)); if ((offer = bribe(priest)) == 0) { verbalize("Thou shalt regret thine action!"); if (coaligned) adjalign(-1); } else if (offer < (u.ulevel * 200)) { if (money_cnt(invent) > (offer * 2L)) verbalize("Cheapskate."); else { verbalize("I thank thee for thy contribution."); } } else if (offer < (u.ulevel * 400)) { verbalize("Thou art indeed a pious individual."); if (money_cnt(invent) < (offer * 2L)) { if (coaligned && u.ualign.record <= ALGN_SINNED) adjalign(1); verbalize("I bestow upon thee a blessing."); incr_itimeout(&HClairvoyant, rn1(500, 500)); } } else if (offer < (u.ulevel * 600) && u.ublessed < 20 && (u.ublessed < 9 || !rn2(u.ublessed))) { verbalize("Thy devotion has been rewarded."); if (!(HProtection & INTRINSIC)) { HProtection |= FROMOUTSIDE; if (!u.ublessed) u.ublessed = rn1(3, 2); } else u.ublessed++; } else { verbalize("Thy selfless generosity is deeply appreciated."); if (money_cnt(invent) < (offer * 2L) && coaligned) { if (strayed && (moves - u.ucleansed) > 5000L) { u.ualign.record = 0; /* cleanse thee */ u.ucleansed = moves; } else { adjalign(2); } } } } }
/* called from check_special_room() when the player enters the temple room */ void intemple(int roomno) { struct monst *priest = findpriest((char)roomno); boolean tended = (priest != NULL); boolean sanctum, can_speak; xchar shrined; const char *msg1, *msg2; if (In_mines(&u.uz) && !historysearch("entered the Minetown temple", TRUE)) historic_event(FALSE, TRUE, "entered the Minetown temple"); if (!temple_occupied(u.urooms0)) { if (tended) { shrined = has_shrine(priest); sanctum = (priest->data == &mons[PM_HIGH_PRIEST] && (shrined & AM_SANCTUM)); can_speak = (priest->mcanmove && !priest->msleeping && canhear()); if (can_speak) { unsigned save_priest = priest->ispriest; /* don't reveal the altar's owner upon temple entry in the endgame; for the Sanctum, the next message names Moloch so suppress the "of Moloch" for him here too */ if (sanctum && !Hallucination) priest->ispriest = 0; pline("%s intones:", canseemon(priest) ? Monnam(priest) : "A nearby voice"); priest->ispriest = save_priest; } msg2 = 0; if (sanctum && CONST_EPRI(priest)->shralign == A_NONE) { if (priest->mpeaceful) { msg1 = "Infidel, you have entered Moloch's Sanctum!"; msg2 = "Be gone!"; msethostility(priest, TRUE, TRUE); } else msg1 = "You desecrate this place by your presence!"; } else { msg1 = msgprintf("Pilgrim, you enter a %s place!", !shrined ? "desecrated" : "sacred"); } if (can_speak) { verbalize("%s", msg1); if (msg2) verbalize("%s", msg2); } if (!sanctum) { /* !tended -> !shrined */ if (!shrined || !p_coaligned(priest) || u.ualign.record <= ALGN_SINNED) pline("You have a%s forbidding feeling...", (!shrined) ? "" : " strange"); else pline("You experience a strange sense of peace."); } } else { switch (rn2(3)) { case 0: pline("You have an eerie feeling..."); break; case 1: pline("You feel like you are being watched."); break; default: pline("A shiver runs down your %s.", body_part(SPINE)); break; } if (!rn2(5)) { struct monst *mtmp; if (!((mtmp = makemon(&mons[PM_GHOST], level, u.ux, u.uy, NO_MM_FLAGS)))) return; if (!Blind || sensemon(mtmp)) pline("An enormous ghost appears next to you!"); else pline("You sense a presence close by!"); msethostility(mtmp, TRUE, TRUE); if (flags.verbose) pline("You are frightened to death, and unable to move."); helpless(3, hr_afraid, "frightened to death", "You regain your composure."); } } } }
/* * return 1: guard moved, 0: guard didn't, -1: let m_move do it, -2: died */ int gd_move(struct monst *grd) { int x, y, nx, ny, m, n; int dx, dy, gx = 0, gy = 0, fci; uchar typ; struct fakecorridor *fcp; struct egd *egrd = EGD(grd); struct rm *crm; boolean goldincorridor = FALSE, u_in_vault = vault_occupied(u.urooms) ? TRUE : FALSE, grd_in_vault = *in_rooms(level, grd->mx, grd->my, VAULT) ? TRUE : FALSE; boolean disappear_msg_seen = FALSE, semi_dead = (grd->mhp <= 0); long umoney = money_cnt(invent); boolean u_carry_gold = ((umoney + hidden_gold()) > 0L); boolean see_guard; if (!on_level(&(egrd->gdlevel), &u.uz)) return -1; nx = ny = m = n = 0; if (!u_in_vault && !grd_in_vault) wallify_vault(grd); if (!grd->mpeaceful) { if (semi_dead) { egrd->gddone = 1; goto newpos; } if (!u_in_vault && (grd_in_vault || (in_fcorridor(grd, grd->mx, grd->my) && !in_fcorridor(grd, u.ux, u.uy)))) { rloc(grd, FALSE); wallify_vault(grd); clear_fcorr(grd, TRUE); goto letknow; } if (!in_fcorridor(grd, grd->mx, grd->my)) clear_fcorr(grd, TRUE); return -1; } if (abs(egrd->ogx - grd->mx) > 1 || abs(egrd->ogy - grd->my) > 1) return -1; /* teleported guard - treat as monster */ if (egrd->fcend == 1) { if (u_in_vault && (u_carry_gold || um_dist(grd->mx, grd->my, 1))) { if (egrd->warncnt == 3) verbalize("I repeat, %sfollow me!", u_carry_gold ? (!umoney ? "drop that hidden money and " : "drop that money and ") : ""); if (egrd->warncnt == 7) { m = grd->mx; n = grd->my; verbalize("You've been warned, knave!"); mnexto(grd); level->locations[m][n].typ = egrd->fakecorr[0].ftyp; newsym(m, n); msethostility(grd, TRUE, FALSE); return -1; } /* not fair to get mad when (s)he's fainted or paralyzed */ if (!u_helpless(hm_all)) egrd->warncnt++; return 0; } if (!u_in_vault) { if (u_carry_gold) { /* player teleported */ m = grd->mx; n = grd->my; rloc(grd, FALSE); level->locations[m][n].typ = egrd->fakecorr[0].ftyp; newsym(m, n); msethostility(grd, TRUE, FALSE); letknow: if (!cansee(grd->mx, grd->my) || !mon_visible(grd)) You_hear("the shrill sound of a guard's whistle."); else pline(um_dist(grd->mx, grd->my, 2) ? "You see an angry guard approaching." : "You are confronted by an angry guard."); return -1; } else { verbalize("Well, begone."); wallify_vault(grd); egrd->gddone = 1; goto cleanup; } } } if (egrd->fcend > 1) { if (egrd->fcend > 2 && in_fcorridor(grd, grd->mx, grd->my) && !egrd->gddone && !in_fcorridor(grd, u.ux, u.uy) && level->locations[egrd->fakecorr[0].fx][egrd->fakecorr[0].fy].typ == egrd->fakecorr[0].ftyp) { if (canseemon(grd)) { pline("%s, confused, disappears.", Monnam(grd)); disappear_msg_seen = TRUE; } goto cleanup; } if (u_carry_gold && (in_fcorridor(grd, u.ux, u.uy) || /* cover a 'blind' spot */ (egrd->fcend > 1 && u_in_vault))) { if (!grd->mx) { restfakecorr(grd); return -2; } if (egrd->warncnt < 6) { egrd->warncnt = 6; verbalize("Drop all your gold, scoundrel!"); return 0; } else { verbalize("So be it, rogue!"); msethostility(grd, TRUE, FALSE); return -1; } } } for (fci = egrd->fcbeg; fci < egrd->fcend; fci++) if (gold_at(level, egrd->fakecorr[fci].fx, egrd->fakecorr[fci].fy)) { m = egrd->fakecorr[fci].fx; n = egrd->fakecorr[fci].fy; goldincorridor = TRUE; } if (goldincorridor && !egrd->gddone) { boolean yours = FALSE; x = grd->mx; y = grd->my; if (m == u.ux && n == u.uy) { struct obj *gold = gold_at(level, m, n); yours = TRUE; /* Grab the gold from between the hero's feet. */ obj_extract_self(gold); add_to_minv(grd, gold); newsym(m, n); } else if (m == x && n == y) { mpickgold(grd); /* does a newsym */ } else { /* just for insurance... */ if (MON_AT(level, m, n) && m != grd->mx && n != grd->my) { verbalize("Out of my way, scum!"); rloc(m_at(level, m, n), FALSE); } remove_monster(level, grd->mx, grd->my); newsym(grd->mx, grd->my); place_monster(grd, m, n); mpickgold(grd); /* does a newsym */ } if (cansee(m, n)) { if (yours) { pline("%s%s picks up the gold.", Monnam(grd), grd->mpeaceful ? " calms down and" : ""); } else { pline("%s picks up some gold.", Monnam(grd)); } } if (x != grd->mx || y != grd->my) { remove_monster(level, grd->mx, grd->my); newsym(grd->mx, grd->my); place_monster(grd, x, y); newsym(x, y); } if (!grd->mpeaceful) return -1; else { egrd->warncnt = 5; return 0; } } if (um_dist(grd->mx, grd->my, 1) || egrd->gddone) { if (!egrd->gddone && !rn2(10)) verbalize("Move along!"); restfakecorr(grd); return 0; /* didn't move */ } x = grd->mx; y = grd->my; if (u_in_vault) goto nextpos; /* look around (hor & vert only) for accessible places */ for (nx = x - 1; nx <= x + 1; nx++) for (ny = y - 1; ny <= y + 1; ny++) { if ((nx == x || ny == y) && (nx != x || ny != y) && isok(nx, ny)) { typ = (crm = &level->locations[nx][ny])->typ; if (!IS_STWALL(typ) && !IS_POOL(typ)) { if (in_fcorridor(grd, nx, ny)) goto nextnxy; if (*in_rooms(level, nx, ny, VAULT)) continue; /* seems we found a good place to leave him alone */ egrd->gddone = 1; if (ACCESSIBLE(typ)) goto newpos; crm->typ = (typ == SCORR) ? CORR : DOOR; if (crm->typ == DOOR) crm->doormask = D_NODOOR; goto proceed; } } nextnxy:; } nextpos: nx = x; ny = y; gx = egrd->gdx; gy = egrd->gdy; dx = (gx > x) ? 1 : (gx < x) ? -1 : 0; dy = (gy > y) ? 1 : (gy < y) ? -1 : 0; if (abs(gx - x) >= abs(gy - y)) nx += dx; else ny += dy; while ((typ = (crm = &level->locations[nx][ny])->typ) != 0) { /* in view of the above we must have IS_WALL(typ) or typ == POOL */ /* must be a wall here */ if (isok(nx + nx - x, ny + ny - y) && !IS_POOL(typ) && IS_ROOM(level->locations[nx + nx - x][ny + ny - y].typ)) { crm->typ = DOOR; crm->doormask = D_NODOOR; goto proceed; } if (dy && nx != x) { nx = x; ny = y + dy; continue; } if (dx && ny != y) { ny = y; nx = x + dx; dy = 0; continue; } /* I don't like this, but ... */ if (IS_ROOM(typ)) { crm->typ = DOOR; crm->doormask = D_NODOOR; goto proceed; } break; } crm->typ = CORR; proceed: unblock_point(nx, ny); /* doesn't block light */ if (cansee(nx, ny)) newsym(nx, ny); if ((nx != gx || ny != gy) || (grd->mx != gx || grd->my != gy)) { fcp = &(egrd->fakecorr[egrd->fcend]); if (egrd->fcend++ == FCSIZ) panic("fakecorr overflow"); fcp->fx = nx; fcp->fy = ny; fcp->ftyp = typ; } else if (!egrd->gddone) { /* We're stuck, so try to find a new destination. */ if (!find_guard_dest(grd, &egrd->gdx, &egrd->gdy) || (egrd->gdx == gx && egrd->gdy == gy)) { pline("%s, confused, disappears.", Monnam(grd)); disappear_msg_seen = TRUE; goto cleanup; } else goto nextpos; } newpos: if (egrd->gddone) { /* The following is a kludge. We need to keep the guard around in order to be able to make the fake corridor disappear as the player moves out of it, but we also need the guard out of the way. We send the guard to never-never land. We set ogx ogy to mx my in order to avoid a check at the top of this function. At the end of the process, the guard is killed in restfakecorr(). */ cleanup: x = grd->mx; y = grd->my; see_guard = canspotmon(grd); wallify_vault(grd); remove_monster(level, grd->mx, grd->my); newsym(grd->mx, grd->my); grd->mx = COLNO; grd->my = ROWNO; egrd->ogx = grd->mx; egrd->ogy = grd->my; restfakecorr(grd); if (!semi_dead && (in_fcorridor(grd, u.ux, u.uy) || cansee(x, y))) { if (!disappear_msg_seen && see_guard) pline("Suddenly, %s disappears.", noit_mon_nam(grd)); return 1; } return -2; } egrd->ogx = grd->mx; /* update old positions */ egrd->ogy = grd->my; remove_monster(level, grd->mx, grd->my); place_monster(grd, nx, ny); newsym(grd->mx, grd->my); restfakecorr(grd); return 1; }
/* * Called during pet revival or pet life-saving. * If you killed the pet, it revives wild. * If you abused the pet a lot while alive, it revives wild. * If you abused the pet at all while alive, it revives untame. * If the pet wasn't abused and was very tame, it might revive tame. */ void wary_dog(struct monst *mtmp, boolean was_dead) { struct edog *edog; boolean quietly = was_dead; mtmp->meating = 0; if (!mtmp->mtame) return; edog = !mtmp->isminion ? EDOG(mtmp) : 0; /* if monster was starving when it died, undo that now */ if (edog && edog->mhpmax_penalty) { mtmp->mhpmax += edog->mhpmax_penalty; mtmp->mhp += edog->mhpmax_penalty; /* heal it */ edog->mhpmax_penalty = 0; } if (edog && (edog->killed_by_u == 1 || edog->abuse > 2)) { msethostility(mtmp, TRUE, FALSE); if (edog->abuse >= 0 && edog->abuse < 10) if (!rn2_on_rng(edog->abuse + 1, rng_dog_untame)) msethostility(mtmp, FALSE, FALSE); if (!quietly && cansee(mtmp->mx, mtmp->my)) { if (haseyes(youmonst.data)) { if (haseyes(mtmp->data)) pline("%s %s to look you in the %s.", Monnam(mtmp), mtmp->mpeaceful ? "seems unable" : "refuses", body_part(EYE)); else pline("%s avoids your gaze.", Monnam(mtmp)); } } } else { /* chance it goes wild anyway - Pet Semetary */ if (rn2_on_rng(mtmp->mtame, rng_dog_untame) == mtmp->mtame - 1) msethostility(mtmp, TRUE, FALSE); } if (!mtmp->mtame) { newsym(mtmp->mx, mtmp->my); /* a life-saved monster might be leashed; don't leave it that way if it's no longer tame */ if (mtmp->mleashed) m_unleash(mtmp, TRUE); } /* if its still a pet, start a clean pet-slate now */ if (edog && mtmp->mtame) { edog->revivals++; edog->killed_by_u = 0; edog->abuse = 0; if (was_dead || edog->hungrytime < moves + 500L) edog->hungrytime = moves + 500L; if (was_dead) { edog->droptime = 0L; edog->dropdist = 10000; edog->whistletime = 0L; edog->apport = 5; } /* else lifesaved, so retain current values */ } }
struct monst * tamedog(struct monst *mtmp, struct obj *obj) { struct monst *mtmp2; /* The Wiz, Medusa and the quest nemeses aren't even made peaceful. */ if (mtmp->iswiz || mtmp->data == &mons[PM_MEDUSA] || (mtmp->data->mflags3 & M3_WANTSARTI)) return NULL; /* worst case, at least it'll be peaceful; this uses the main RNG because realtime effects means that this won't really sync anyway; this also calls set_malign (thus there's no need for the caller to call it after calling tamedog()) */ msethostility(mtmp, FALSE, TRUE); if (flags.moonphase == FULL_MOON && night() && rn2(6) && obj && mtmp->data->mlet == S_DOG) return NULL; /* If we cannot tame it, at least it's no longer afraid. */ mtmp->mflee = 0; mtmp->mfleetim = 0; /* make grabber let go now, whether it becomes tame or not */ if (mtmp == u.ustuck) { if (Engulfed) expels(mtmp, mtmp->data, TRUE); else if (!(Upolyd && sticks(youmonst.data))) unstuck(mtmp); } /* feeding it treats makes it tamer */ if (mtmp->mtame && obj) { int tasty; if (mtmp->mcanmove && !mtmp->mconf && !mtmp->meating && ((tasty = dogfood(mtmp, obj)) == DOGFOOD || (tasty <= ACCFOOD && CONST_EDOG(mtmp)->hungrytime <= moves))) { /* pet will "catch" and eat this thrown food */ if (canseemon(mtmp)) { boolean big_corpse = (obj->otyp == CORPSE && obj->corpsenm >= LOW_PM && mons[obj->corpsenm].msize > mtmp->data->msize); pline("%s catches %s%s", Monnam(mtmp), the(xname(obj)), !big_corpse ? "." : ", or vice versa!"); } else if (cansee(mtmp->mx, mtmp->my)) pline("%s.", Tobjnam(obj, "stop")); /* dog_eat expects a floor object */ place_object(obj, level, mtmp->mx, mtmp->my); dog_eat(mtmp, obj, mtmp->mx, mtmp->my, FALSE); /* eating might have killed it, but that doesn't matter here; a non-null result suppresses "miss" message for thrown food and also implies that the object has been deleted */ return mtmp; } else return NULL; } if (mtmp->mtame || !mtmp->mcanmove || /* monsters with conflicting structures cannot be tamed */ mtmp->isshk || mtmp->isgd || mtmp->ispriest || mtmp->isminion || is_covetous(mtmp->data) || is_human(mtmp->data) || (is_demon(mtmp->data) && !is_demon(youmonst.data)) || (obj && dogfood(mtmp, obj) >= MANFOOD)) return NULL; if (mtmp->m_id == u.quest_status.leader_m_id) return NULL; /* make a new monster which has the pet extension */ mtmp2 = newmonst(MX_EDOG, mtmp->mnamelth); *mtmp2 = *mtmp; mtmp2->mxtyp = MX_EDOG; mtmp2->mxlth = sizeof (struct edog); if (mtmp->mnamelth) strcpy(NAME_MUTABLE(mtmp2), NAME(mtmp)); initedog(mtmp2); replmon(mtmp, mtmp2); /* `mtmp' is now obsolete */ if (obj) { /* thrown food */ /* defer eating until the edog extension has been set up */ place_object(obj, level, mtmp2->mx, mtmp2->my); /* put on floor */ /* devour the food (might grow into larger, genocided monster) */ if (dog_eat(mtmp2, obj, mtmp2->mx, mtmp2->my, TRUE) == 2) return mtmp2; /* oops, it died... */ /* `obj' is now obsolete */ } if (mtmp2->dlevel == level) newsym(mtmp2->mx, mtmp2->my); if (attacktype(mtmp2->data, AT_WEAP)) { mtmp2->weapon_check = NEED_HTH_WEAPON; mon_wield_item(mtmp2); } return mtmp2; }
struct monst * make_familiar(struct obj *otmp, xchar x, xchar y, boolean quietly) { const struct permonst *pm; struct monst *mtmp = 0; int chance, trycnt = 100; do { if (otmp) { /* figurine; otherwise spell */ int mndx = otmp->corpsenm; pm = &mons[mndx]; /* activating a figurine provides one way to exceed the maximum number of the target critter created--unless it has a special limit (erinys, Nazgul) */ if ((mvitals[mndx].mvflags & G_EXTINCT) && mbirth_limit(mndx) != MAXMONNO) { if (!quietly) /* have just been given "You <do something with> the figurine and it transforms." message */ pline("... into a pile of dust."); break; /* mtmp is null */ } } else if (!rn2(3)) { pm = &mons[pet_type(NULL)]; } else { pm = rndmonst(&u.uz, rng_t_create_monster); if (!pm) { if (!quietly) pline ("There seems to be nothing available for a familiar."); break; } } mtmp = makemon(pm, level, x, y, MM_EDOG | MM_IGNOREWATER | (otmp ? 0 : (MM_CREATEMONSTER | MM_CMONSTER_T))); if (otmp && !mtmp) { /* monster was genocided or square occupied */ if (!quietly) pline("The figurine writhes and then shatters into pieces!"); break; } } while (!mtmp && --trycnt > 0); if (!mtmp) return NULL; if (is_pool(level, mtmp->mx, mtmp->my) && minliquid(mtmp)) return NULL; initedog(mtmp); mtmp->msleeping = 0; if (otmp) { /* figurine; resulting monster might not become a pet */ chance = rn2_on_rng(10, rng_figurine_effect); /* 0: tame, 1: peaceful, 2: hostile, 3+: matching BCU; this gives an 80% chance of the desired effect, 10% of each other effect */ if (chance > 2) chance = otmp->blessed ? 0 : !otmp->cursed ? 1 : 2; if (chance > 0) { mtmp->mtame = 0; /* not tame after all */ if (chance == 2) { /* hostile (cursed figurine) */ if (!quietly) pline("You get a bad feeling about this."); msethostility(mtmp, TRUE, TRUE); } } /* if figurine has been named, give same name to the monster */ if (otmp->onamelth) mtmp = christen_monst(mtmp, ONAME(otmp)); } set_malign(mtmp); /* more alignment changes */ newsym(mtmp->mx, mtmp->my); /* must wield weapon immediately since pets will otherwise drop it */ if (mtmp->mtame && attacktype(mtmp->data, AT_WEAP)) { mtmp->weapon_check = NEED_HTH_WEAPON; mon_wield_item(mtmp); } return mtmp; }
void fill_zoo(struct level *lev, struct mkroom *sroom, enum rng rng) { struct monst *mon; int sx, sy, i; int sh, tx, ty, goldlim, type = sroom->rtype; int rmno = (sroom - lev->rooms) + ROOMOFFSET; coord mm; tx = ty = goldlim = 0; sh = sroom->fdoor; switch (type) { case COURT: if (lev->flags.is_maze_lev) { for (tx = sroom->lx; tx <= sroom->hx; tx++) for (ty = sroom->ly; ty <= sroom->hy; ty++) if (IS_THRONE(lev->locations[tx][ty].typ)) goto throne_placed; } i = 100; do { /* don't place throne on top of stairs */ somexy(lev, sroom, &mm, rng); tx = mm.x; ty = mm.y; } while (occupied(lev, tx, ty) && --i > 0); throne_placed: /* TODO: try to ensure the enthroned monster is an M2_PRINCE */ break; case BEEHIVE: tx = sroom->lx + (sroom->hx - sroom->lx + 1) / 2; ty = sroom->ly + (sroom->hy - sroom->ly + 1) / 2; if (sroom->irregular) { /* center might not be valid, so put queen elsewhere */ if ((int)lev->locations[tx][ty].roomno != rmno || lev->locations[tx][ty].edge) { somexy(lev, sroom, &mm, rng); tx = mm.x; ty = mm.y; } } break; case ZOO: case LEPREHALL: goldlim = 500 * level_difficulty(&lev->z); break; } for (sx = sroom->lx; sx <= sroom->hx; sx++) for (sy = sroom->ly; sy <= sroom->hy; sy++) { if (sroom->irregular) { if ((int)lev->locations[sx][sy].roomno != rmno || lev->locations[sx][sy].edge || (sroom->doorct && distmin(sx, sy, lev->doors[sh].x, lev->doors[sh].y) <= 1)) continue; } else if (!SPACE_POS(lev->locations[sx][sy].typ) || (sroom->doorct && ((sx == sroom->lx && lev->doors[sh].x == sx - 1) || (sx == sroom->hx && lev->doors[sh].x == sx + 1) || (sy == sroom->ly && lev->doors[sh].y == sy - 1) || (sy == sroom->hy && lev->doors[sh].y == sy + 1)))) continue; /* don't place monster on explicitly placed throne */ if (type == COURT && IS_THRONE(lev->locations[sx][sy].typ)) continue; mon = makemon((type == COURT) ? courtmon(&lev->z, rng) : (type == BARRACKS) ? squadmon(&lev->z) : (type == MORGUE) ? morguemon(&lev->z, rng) : (type == BEEHIVE) ? (sx == tx && sy == ty ? &mons[PM_QUEEN_BEE] : &mons[PM_KILLER_BEE]) : (type == LEPREHALL) ? &mons[PM_LEPRECHAUN] : (type == COCKNEST) ? &mons[PM_COCKATRICE] : (type == ANTHOLE) ? antholemon(&lev->z) : NULL, lev, sx, sy, rng == rng_main ? NO_MM_FLAGS : MM_ALLLEVRNG); if (mon) { mon->msleeping = 1; if (type == COURT && mon->mpeaceful) msethostility(mon, TRUE, TRUE); } switch (type) { case ZOO: case LEPREHALL: if (sroom->doorct) { int distval = dist2(sx, sy, lev->doors[sh].x, lev->doors[sh].y); i = sq(distval); } else i = goldlim; if (i >= goldlim) i = 5 * level_difficulty(&lev->z); goldlim -= i; mkgold(10 + rn2_on_rng(i, rng), lev, sx, sy, rng); break; case MORGUE: if (!rn2_on_rng(5, rng)) mk_tt_object(lev, CORPSE, sx, sy); if (!rn2_on_rng(10, rng)) /* lots of treasure */ mksobj_at(rn2_on_rng(3, rng) ? LARGE_BOX : CHEST, lev, sx, sy, TRUE, FALSE, rng); if (!rn2_on_rng(5, rng)) make_grave(lev, sx, sy, NULL); break; case BEEHIVE: if (!rn2_on_rng(3, rng)) mksobj_at(LUMP_OF_ROYAL_JELLY, lev, sx, sy, TRUE, FALSE, rng); break; case BARRACKS: if (!rn2_on_rng(20, rng)) /* the payroll and some loot */ mksobj_at((rn2(3)) ? LARGE_BOX : CHEST, lev, sx, sy, TRUE, FALSE, rng); break; case COCKNEST: if (!rn2_on_rng(3, rng)) { struct obj *sobj = mk_tt_object(lev, STATUE, sx, sy); if (sobj) { for (i = rn2_on_rng(5, rng); i; i--) add_to_container(sobj, mkobj(lev, RANDOM_CLASS, FALSE, rng)); sobj->owt = weight(sobj); } } break; case ANTHOLE: if (!rn2_on_rng(3, rng)) mkobj_at(FOOD_CLASS, lev, sx, sy, FALSE, rng); break; } } if (type == COURT) { struct obj *chest; lev->locations[tx][ty].typ = THRONE; somexy(lev, sroom, &mm, rng); mkgold(10 + rn2_on_rng(50 * level_difficulty(&lev->z), rng), lev, mm.x, mm.y, rng); /* the royal coffers */ chest = mksobj_at(CHEST, lev, mm.x, mm.y, TRUE, FALSE, rng); chest->spe = 2; /* so it can be found later */ } }
/* special effects for The Book of the Dead */ void deadbook(struct obj *book2, boolean invoked) { struct monst *mtmp, *mtmp2; coord mm; if (!invoked) pline("You turn the pages of the Book of the Dead..."); makeknown(SPE_BOOK_OF_THE_DEAD); /* KMH -- Need ->known to avoid "_a_ Book of the Dead" */ book2->known = 1; if (invocation_pos(&u.uz, u.ux, u.uy) && !On_stairs(u.ux, u.uy)) { struct obj *otmp; boolean arti1_primed = FALSE, arti2_primed = FALSE, arti_cursed = FALSE; if (invoked) { if (Blind) You_hear("a crisp flicker..."); else pline("The Book of the Dead opens of its own accord..."); } if (book2->cursed) { if (invoked) { if (Hallucination) You_hear("gratuitous bleeping."); else You_hear("a mumbled curse."); } else pline("The runes appear scrambled. You can't read them!"); return; } if (!Uhave_bell || !Uhave_menorah) { pline("A chill runs down your %s.", body_part(SPINE)); if (!Uhave_bell) { if (Hallucination) pline("You feel like a tuning fork!"); else You_hear("a faint chime..."); } if (!Uhave_menorah) { if (Hallucination) { pline("Nosferatu giggles."); } else if (mvitals[PM_DOPPELGANGER].mvflags & G_GENOD) { /* suggestion by b_jonas: can't talk about doppelgangers if they don't exist */ if (Uhave_bell) pline("Nothing seems to happen."); /* otherwise no message, we already printed one. */ } else { pline("Vlad's doppelganger is amused."); } } return; } for (otmp = invent; otmp; otmp = otmp->nobj) { if (otmp->otyp == CANDELABRUM_OF_INVOCATION && otmp->spe == 7 && otmp->lamplit) { if (!otmp->cursed) arti1_primed = TRUE; else arti_cursed = TRUE; } if (otmp->otyp == BELL_OF_OPENING && (moves - otmp->age) < 5L) { /* you rang it recently */ if (!otmp->cursed) arti2_primed = TRUE; else arti_cursed = TRUE; } } if (arti_cursed) { pline("The invocation fails!"); if (Hallucination) pline("At least one of your heirlooms is in a tizzy!"); else pline("At least one of your artifacts is cursed..."); } else if (arti1_primed && arti2_primed) { unsigned soon = (unsigned)dice(2, 6); /* time til next intervene */ /* successful invocation */ mkinvokearea(); u.uevent.invoked = 1; historic_event(FALSE, TRUE, "performed the invocation."); /* in case you haven't killed the Wizard yet, behave as if you just did */ u.uevent.udemigod = 1; /* wizdead() */ if (!u.udg_cnt || u.udg_cnt > soon) u.udg_cnt = soon; } else { /* at least one artifact not prepared properly */ pline("You have a feeling that something is amiss..."); goto raise_dead; } return; } /* when not an invocation situation */ if (invoked) { pline("Nothing happens."); return; } if (book2->cursed) { raise_dead: if (Hallucination) You_hear("Michael Jackson dancing!"); else pline("You raised the dead!"); /* first maybe place a dangerous adversary; don't bother with MM_CREATEMONSTER, that's mostly used to ensure that consistent species of monsters generate */ if (!rn2(3) && ((mtmp = makemon(&mons[PM_MASTER_LICH], level, u.ux, u.uy, NO_MINVENT)) != 0 || (mtmp = makemon(&mons[PM_NALFESHNEE], level, u.ux, u.uy, NO_MINVENT)) != 0)) { msethostility(mtmp, TRUE, TRUE); } /* next handle the effect on things you're carrying */ unturn_dead(&youmonst); /* last place some monsters around you */ mm.x = u.ux; mm.y = u.uy; mkundead(level, &mm, TRUE, NO_MINVENT); } else if (book2->blessed) { for (mtmp = level->monlist; mtmp; mtmp = mtmp2) { mtmp2 = mtmp->nmon; /* tamedog() changes chain */ if (DEADMONSTER(mtmp)) continue; if (is_undead(mtmp->data) && cansee(mtmp->mx, mtmp->my)) { msethostility(mtmp, FALSE, FALSE); /* TODO: reset alignment? */ if (sgn(mtmp->data->maligntyp) == sgn(u.ualign.type) && distu(mtmp->mx, mtmp->my) < 4) if (mtmp->mtame) { if (mtmp->mtame < 20) mtmp->mtame++; } else tamedog(mtmp, NULL); else monflee(mtmp, 0, FALSE, TRUE); } } } else { switch (rn2(3)) { case 0: pline("Your ancestors are annoyed with you!"); break; case 1: pline("The headstones in the cemetery begin to move!"); break; default: pline("Oh my! Your name appears in the book!"); } } return; }
void invault(void) { struct monst *guard; int trycount, vaultroom = (int)vault_occupied(u.urooms); boolean messages = TRUE; if (!vaultroom) { u.uinvault = 0; return; } vaultroom -= ROOMOFFSET; guard = findgd(); if (++u.uinvault % 30 == 0 && !guard) { /* if time ok and no guard now. */ int x, y, gx, gy; xchar rx, ry; long umoney; const char *buf; /* first find the goal for the guard */ if (!find_guard_dest(NULL, &rx, &ry)) return; gx = rx; gy = ry; /* next find a good place for a door in the wall */ x = u.ux; y = u.uy; if (level->locations[x][y].typ != ROOM) { /* player dug a door and is in it */ if (level->locations[x + 1][y].typ == ROOM) x = x + 1; else if (level->locations[x][y + 1].typ == ROOM) y = y + 1; else if (level->locations[x - 1][y].typ == ROOM) x = x - 1; else if (level->locations[x][y - 1].typ == ROOM) y = y - 1; else if (level->locations[x + 1][y + 1].typ == ROOM) { x = x + 1; y = y + 1; } else if (level->locations[x - 1][y - 1].typ == ROOM) { x = x - 1; y = y - 1; } else if (level->locations[x + 1][y - 1].typ == ROOM) { x = x + 1; y = y - 1; } else if (level->locations[x - 1][y + 1].typ == ROOM) { x = x - 1; y = y + 1; } } while (level->locations[x][y].typ == ROOM) { int dx, dy; dx = (gx > x) ? 1 : (gx < x) ? -1 : 0; dy = (gy > y) ? 1 : (gy < y) ? -1 : 0; if (abs(gx - x) >= abs(gy - y)) x += dx; else y += dy; } if (x == u.ux && y == u.uy) { if (level->locations[x + 1][y].typ == HWALL || level->locations[x + 1][y].typ == DOOR) x = x + 1; else if (level->locations[x - 1][y].typ == HWALL || level->locations[x - 1][y].typ == DOOR) x = x - 1; else if (level->locations[x][y + 1].typ == VWALL || level->locations[x][y + 1].typ == DOOR) y = y + 1; else if (level->locations[x][y - 1].typ == VWALL || level->locations[x][y - 1].typ == DOOR) y = y - 1; else return; } /* make something interesting happen */ if (!(guard = makemon(&mons[PM_GUARD], level, x, y, NO_MM_FLAGS))) return; guard->isgd = 1; msethostility(guard, FALSE, TRUE); EGD(guard)->gddone = 0; EGD(guard)->ogx = x; EGD(guard)->ogy = y; assign_level(&(EGD(guard)->gdlevel), &u.uz); EGD(guard)->vroom = vaultroom; EGD(guard)->warncnt = 0; /* We used to reset fainted status here, but that doesn't really make sense; instead, that's treated like normal helplessness */ if (canspotmon(guard)) pline("Suddenly one of the Vault's guards enters!"); else if (canhear()) You_hear("someone else enter the Vault."); else messages = FALSE; newsym(guard->mx, guard->my); if (youmonst.m_ap_type == M_AP_OBJECT || u.uundetected || u.uburied) { if (youmonst.m_ap_type == M_AP_OBJECT && youmonst.mappearance != GOLD_PIECE) verbalize("Hey! Who left that %s in here?", mimic_obj_name(&youmonst)); /* You're mimicking some object or you're hidden. */ if (messages) pline("Puzzled, %s turns around and leaves.", mhe(guard)); mongone(guard); return; } if (Engulfed) { if ((!u.ustuck->minvis || perceives(guard->data))) verbalize("How did that %s get in here?", m_monnam(u.ustuck)); if (messages) pline("Puzzled, %s turns around and leaves.", mhe(guard)); mongone(guard); return; } if (Strangled || is_silent(youmonst.data) || u_helpless(hm_all)) { /* [we ought to record whether this this message has already been given in order to vary it upon repeat visits, but discarding the monster and its egd data renders that hard] */ verbalize("I'll be back when you're ready to speak to me!"); mongone(guard); return; } action_interrupted(); trycount = 5; do { buf = getlin("\"Hello stranger, who are you?\" -", FALSE); buf = msgmungspaces(buf); } while (!letter(buf[0]) && --trycount > 0); if (u.ualign.type == A_LAWFUL && /* ignore trailing text, in case player includes character's rank */ strncmpi(buf, u.uplname, (int)strlen(u.uplname)) != 0) { adjalign(-1); /* Liar! */ } if (!strcmpi(buf, "Croesus") || !strcmpi(buf, "Kroisos") || !strcmpi(buf, "Creosote")) { if (!mvitals[PM_CROESUS].died) { verbalize("Oh, yes, of course. Sorry to have disturbed you."); mongone(guard); } else { setmangry(guard); verbalize("Back from the dead, are you? I'll remedy that!"); /* don't want guard to waste next turn wielding a weapon */ if (!MON_WEP(guard)) { guard->weapon_check = NEED_HTH_WEAPON; mon_wield_item(guard); } } return; } verbalize("I don't know you."); umoney = money_cnt(invent); if (!umoney && !hidden_gold()) verbalize("Please follow me."); else { if (!umoney) verbalize("You have hidden money."); verbalize("Most likely all your money was stolen from this vault."); verbalize("Please drop that money and follow me."); } EGD(guard)->gdx = gx; EGD(guard)->gdy = gy; EGD(guard)->fcbeg = 0; EGD(guard)->fakecorr[0].fx = x; EGD(guard)->fakecorr[0].fy = y; if (IS_WALL(level->locations[x][y].typ)) EGD(guard)->fakecorr[0].ftyp = level->locations[x][y].typ; else { /* the initial guard location is a dug door */ int vlt = EGD(guard)->vroom; xchar lowx = level->rooms[vlt].lx, hix = level->rooms[vlt].hx; xchar lowy = level->rooms[vlt].ly, hiy = level->rooms[vlt].hy; if (x == lowx - 1 && y == lowy - 1) EGD(guard)->fakecorr[0].ftyp = TLCORNER; else if (x == hix + 1 && y == lowy - 1) EGD(guard)->fakecorr[0].ftyp = TRCORNER; else if (x == lowx - 1 && y == hiy + 1) EGD(guard)->fakecorr[0].ftyp = BLCORNER; else if (x == hix + 1 && y == hiy + 1) EGD(guard)->fakecorr[0].ftyp = BRCORNER; else if (y == lowy - 1 || y == hiy + 1) EGD(guard)->fakecorr[0].ftyp = HWALL; else if (x == lowx - 1 || x == hix + 1) EGD(guard)->fakecorr[0].ftyp = VWALL; } level->locations[x][y].typ = DOOR; level->locations[x][y].doormask = D_NODOOR; unblock_point(x, y); /* doesn't block light */ EGD(guard)->fcend = 1; EGD(guard)->warncnt = 1; } }