/* omega copyright (c) 1987,1988,1989 by Laurence Raphael Brothers */ /* mspec.c */ /* monster special functions */ #include "glob.h" void m_sp_mp(pmt m) { if (m->attacked && (random_range(3) == 1)) { mprint("You feel cursed!"); p_damage(10,UNSTOPPABLE,"a mendicant priest's curse"); m_vanish(m); } else if (! m_statusp(m,NEEDY)) { mprint("The mendicant priest makes a mystical gesture...."); mprint("You feel impressed..."); Player.alignment += 5; if (Player.alignment > 20) Player.hp = max(Player.hp,Player.maxhp); m_vanish(m); } } void m_sp_ng(pmt m) { if (distance(m->x,m->y,Player.x,Player.y) < 2) if ((random_range(5) == 1) || (Player.status[VULNERABLE]>0)) { mprint("The night gaunt grabs you and carries you off!"); mprint("Its leathery wings flap and flap, and it giggles insanely."); mprint("It tickles you cunningly to render you incapable of escape."); mprint("Finally, it deposits you in a strange place."); p_teleport(0); } } void m_sp_poison_cloud(pmt m) { if (distance(m->x,m->y,Player.x,Player.y) < 3) { mprint("A cloud of poison gas surrounds you!"); if (Player.status[BREATHING] > 0) mprint("You can breathe freely, however."); else p_poison(7); } } void m_sp_explode(pmt m) { if ((distance(Player.x,Player.y,m->x,m->y)<2) && (m-> hp > 0) && (m->hp < Monsters[m->id].hp)) fball(m->x,m->y,m->x,m->y,m->hp); } void m_sp_demon (pmt m) { int mid; if (random_range(2)) { if ((m->id != INCUBUS) /* succubi don't give fear */ && los_p(m->x, m->y, Player.x, Player.y) && (random_range(30) > (Player.level + 10)) && (0 == Player.status[AFRAID])) { mprint("You are stricken with fear!"); if (!p_immune(FEAR)) Player.status[AFRAID] += m->level; else mprint("You master your reptile brain and stand fast."); } else { m_sp_spell(m); } } if ((m->hp < (m->level * 5)) && (m->hp > 1)) { mprint("The demon uses its waning lifeforce to summon help!"); m->hp = 1; switch(m->level) { case 3: mid = NIGHT_GAUNT; break; case 4: case 5: mid = L_FDEMON; break; /* lesser frost demon */ case 6: mid = FROST_DEMON; break; case 7: mid = OUTER_DEMON; break; /* outer circle demon */ case 8: mid = DEMON_SERP; break; /* demon serpent */ case 9: mid = INNER_DEMON; break; /* inner circle demon */ default: mid = 0; assert(FALSE); /* bomb on error */ } summon(-1, mid); summon(-1, mid); } } void m_sp_acid_cloud(pmt m) { if (m_statusp(m,HOSTILE) && (distance(m->x,m->y,Player.x,Player.y) < 3)) acid_cloud(); } void m_sp_escape(pmt m) { if (m_statusp(m,HOSTILE)) m_vanish(m); } void m_sp_ghost(pmt m) { if (m_statusp(m,HOSTILE)) { mprint("The ghost moans horribly...."); p_damage(1,FEAR,"a ghost-inspired heart attack"); mprint("You've been terrorized!"); if (! p_immune(FEAR)) Player.status[AFRAID] += m->level; else mprint("You master your reptile brain and stand fast."); } } /* random spell cast by monster */ void m_sp_spell(pmt m) { char action[80]; if (m_statusp(m,HOSTILE) && los_p(Player.x,Player.y,m->x,m->y)) { if (m->uniqueness == COMMON) strcpy(action,"The "); else strcpy(action,""); strcat(action,m->monstring); strcat(action," casts a spell..."); mprint(action); if (! magic_resist(m->level)) switch (random_range(m->level+7)) { case 0: nbolt(m->x,m->y,Player.x,Player.y,m->hit,10); break; case 1: mprint("It seems stronger..."); m->hp += random_range(m->level*m->level); break; case 2: haste(-1); break; case 3: cure(-1); break; case 4: /* WDT: I'd like to make this (and "case 5" below) dependant on * the monster's IQ in some way -- dumb but powerful monsters * deserve what they get :). No rush. */ if (m_immunityp(m, ELECTRICITY) || distance(m->x,m->y,Player.x,Player.y) > 2) lball(m->x,m->y,Player.x,Player.y,20); else lbolt(m->x,m->y,Player.x,Player.y,m->hit,20); break; case 5: if (m_immunityp(m, COLD) || distance(m->x,m->y,Player.x,Player.y) > 2) snowball(m->x,m->y,Player.x,Player.y,30); else icebolt(m->x,m->y,Player.x,Player.y,m->hit,30); break; case 6: enchant(-1); break; case 7: bless(0-m->level); break; case 8: p_poison(m->level); break; case 9: sleep_player(m->level/2); break; case 10: fbolt(m->x,m->y,Player.x,Player.y,m->hit*3,50); break; case 11: acquire(0-m->level); break; case 12: dispel(-1); break; case 13: disrupt(Player.x,Player.y,50); break; case 14: if (m->uniqueness == COMMON) { strcpy(Str2,"a "); strcat(Str2,m->monstring); } else strcpy(Str2,m->monstring); level_drain(m->level,Str2); break; case 15: case 16: disintegrate(Player.x,Player.y); break; } } } /* monsters with this have some way to hide, camouflage, etc until they attack */ void m_sp_surprise(pmt m) { if (m->attacked) { if (m_statusp(m,HOSTILE) && (! Player.status[TRUESIGHT]) && m_statusp(m,M_INVISIBLE)) { m->monchar = Monsters[m->id].monchar; if (! Player.status[ALERT]) { switch(random_range(4)) { case 0: mprint("You are surprised by a sudden treacherous attack!"); break; case 1: mprint("You are shocked out of your reverie by the scream of battle!"); break; case 2: mprint("Suddenly, from out of the shadows, a surprise attack!"); break; case 3: mprint("A shriek of hatred causes you to momentarily freeze up!"); break; } morewait(); setgamestatus(SKIP_PLAYER); m_status_reset(m,M_INVISIBLE); } else { mprint("You alertly sense the presence of an attacker!"); m_status_reset(m,M_INVISIBLE); } } } } void m_sp_whistleblower(pmt m) { if (m_statusp(m,HOSTILE)) { alert_guards(); m->specialf = M_MELEE_NORMAL; } } void m_sp_seductor(pmt m) { if (m_statusp(m,HOSTILE)) { if (m->uniqueness == COMMON) { strcpy(Str2,"The "); strcat(Str2,m->monstring); } else strcpy(Str2,m->monstring); strcat(Str2," runs away screaming for help...."); mprint(Str2); m_vanish(m); summon(-1,-1); summon(-1,-1); summon(-1,-1); } else if (distance(Player.x,Player.y,m->x,m->y) < 2) m_talk_seductor(m); } void m_sp_demonlover(pmt m) { if (distance(Player.x,Player.y,m->x,m->y) < 2) m_talk_demonlover(m); } void m_sp_eater(pmt m) { if (Player.rank[COLLEGE]) m_status_set(m,HOSTILE); if (m_statusp(m,HOSTILE)) if (los_p(m->x,m->y,Player.x,Player.y)) { mprint("A strange numbing sensation comes over you..."); morewait(); Player.mana = Player.mana / 2; if (random_range(4)) enchant(-1); else dispel(-1); Player.pow--; if (--Player.pow < 1) p_death("the Eater of Magic"); } if (m->hp < 10) { mprint("The Eater explodes in a burst of mana!"); manastorm(m->x,m->y,1000); } } void m_sp_dragonlord(pmt m) { if (m_statusp(m,HOSTILE)) { if (distance(m->x,m->y,Player.x,Player.y)<2) { if (! Player.status[IMMOBILE]) { mprint("A gust of wind from the Dragonlord's wings knocks you down!"); p_damage(25,NORMAL_DAMAGE,"a gust of wind"); setgamestatus(SKIP_PLAYER); Player.status[IMMOBILE]+=2; } else if (! Constriction) { mprint("The Dragonlord grabs you with his tail!"); Constriction = 25; Player.status[IMMOBILE]+=1; } else if (random_range(2)) { mprint("The coils squeeze tighter and tighter..."); p_damage(Constriction,NORMAL_DAMAGE,"the Dragonlord"); Player.status[IMMOBILE]+=1; Constriction *=2; } else { mprint("The Dragonlord hurls you to the ground!"); p_damage(2*Constriction,NORMAL_DAMAGE,"the Dragonlord"); Constriction = 0; } m_sp_spell(m); } else { Constriction = 0; if (view_los_p(m->x,m->y,Player.x,Player.y)) { if ((! Player.immunity[FEAR]) && (! Player.status[AFRAID])) { mprint("You are awestruck at the sight of the Dragonlord."); Player.status[AFRAID]+=5; } if (random_range(3)) { m_sp_spell(m); m_sp_spell(m); } } } } else if (distance(m->x,m->y,Player.x,Player.y)<2) mprint("You are extremely impressed at the sight of the Dragonlord."); } void m_sp_blackout(pmt m) { if ((distance(m->x,m->y,Player.x,Player.y) < 4) && (Player.status[BLINDED] == 0)) { mprint("The fungus emits a burst of black spores. You've been blinded!"); if (Player.status[TRUESIGHT] > 0) mprint("The blindness quickly passes."); else Player.status[BLINDED]+=4; } if (loc_statusp(m->x,m->y,LIT)) { mprint("The fungus chirps.... "); mprint("The area is plunged into darkness."); torch_check();torch_check();torch_check(); torch_check();torch_check();torch_check(); spreadroomdark(m->x,m->y,Level->site[m->x][m->y].roomnumber); levelrefresh(); } } void m_sp_bogthing(pmt m) { if (Player.status[IMMOBILE] && (distance(Player.x,Player.y,m->x,m->y) < 2)) { if (! Player.status[AFRAID]) { mprint("As the bogthing touches you, you feel a frisson of terror...."); if (Player.immunity[FEAR]) mprint("which you shake off."); else Player.status[AFRAID]+=2; } else { mprint("The bogthing's touch causes you scream in agony!"); p_damage(50,UNSTOPPABLE,"fright"); mprint("Your struggles grow steadily weaker...."); Player.con--; Player.str--; if ((Player.con < 3) || (Player.str < 3)) p_death("congestive heart failure"); } } } void m_sp_were(pmt m) { int mid; if (m_statusp(m,HOSTILE) || (Phase == 6)) { do mid = random_range(ML9-NML_0)+ML1; /* log npc, 0th level npc, high score npc or were-creature */ while (mid == NPC || mid == ZERO_NPC || mid == HISCORE_NPC || mid == WEREHUMAN || (Monsters[mid].uniqueness != COMMON) || (! m_statusp(&(Monsters[mid]),MOBILE)) || (! m_statusp(&(Monsters[mid]),HOSTILE)) ); m->id = Monsters[mid].id; m->hp += Monsters[mid].hp; m->status |= Monsters[mid].status; m->ac = Monsters[mid].ac; m->dmg = Monsters[mid].dmg; m->speed = Monsters[mid].speed; m->immunity |= Monsters[mid].immunity; m->xpv += Monsters[mid].xpv; m->corpseweight = Monsters[mid].corpseweight; m->monchar = Monsters[mid].monchar; m->talkf = Monsters[mid].talkf; m->meleef = Monsters[mid].meleef; m->strikef = Monsters[mid].strikef; m->specialf = Monsters[mid].specialf; strcpy(Str1,"were-"); strcat(Str1,Monsters[mid].monstring); strcpy(Str2,"dead were-"); strcat(Str2,Monsters[mid].monstring); m->monstring = salloc(Str1); m->corpsestr = salloc(Str2); m_status_set( m, ALLOC ); m->immunity |= pow2(NORMAL_DAMAGE); /* WDT: not +=, rather |=. */ if (los_p(m->x,m->y,Player.x,Player.y)) mprint("You witness a hideous transformation!"); else mprint("You hear a distant howl."); } } void m_sp_servant(pmt m) { if ((m->id == SERV_LAW) && (Player.alignment < 0)) m_status_set(m,HOSTILE); else if ((m->id == SERV_CHAOS) && (Player.alignment > 0)) m_status_set(m,HOSTILE); } void m_sp_av(pmt m) { if (Player.mana > 0) { mprint("You feel a sudden loss of mana!"); Player.mana -= (max(0,10-distance(m->x,m->y,Player.x,Player.y))); dataprint(); } } void m_sp_lw(pmt m) { if (random_range(2)) { if (Level->site[m->x][m->y].locchar == FLOOR) { Level->site[m->x][m->y].locchar = LAVA; Level->site[m->x][m->y].p_locf = L_LAVA; lset(m->x, m->y, CHANGED); } else if (Level->site[m->x][m->y].locchar == WATER) { Level->site[m->x][m->y].locchar = FLOOR; Level->site[m->x][m->y].p_locf = L_NO_OP; lset(m->x, m->y, CHANGED); } } } void m_sp_angel(pmt m) { int mid,hostile = FALSE; switch(m->aux1) { case ATHENA: case ODIN: hostile = ((Player.patron == HECATE) || (Player.patron == SET)); break; case SET: case HECATE: hostile = ((Player.patron == ODIN) || (Player.patron == ATHENA)); break; case DESTINY: hostile = (Player.patron != DESTINY); break; } if (hostile) m_status_set(m,HOSTILE); if (m_statusp(m,HOSTILE)) { mprint("The angel summons a heavenly host!"); switch(m->level) { case 9: mid = HIGH_ANGEL; break; case 8: mid = ANGEL; break; default: case 6: mid = PHANTOM; break; } summon(-1,mid); summon(-1,mid); summon(-1,mid); /* prevent angel from summoning infinitely */ m->specialf = M_NO_OP; } } /* Could completely fill up level */ void m_sp_swarm(pmt m) { if (random_range(5)==1) { if (view_los_p(m->x,m->y,Player.x,Player.y)) mprint("The swarm expands!"); else mprint("You hear an aggravating humming noise."); summon(-1,SWARM); } } /* raise nearby corpses from the dead.... */ void m_sp_raise(pmt m) { int x,y; pol t; for(x=m->x-2;x<=m->x+2;x++) for(y=m->y-2;y<=m->y+2;y++) if (inbounds(x,y)) if (Level->site[x][y].things != NULL) if (Level->site[x][y].things->thing->id == CORPSEID) { mprint("The Zombie Overlord makes a mystical gesture..."); summon(-1,Level->site[x][y].things->thing->charge); t = Level->site[x][y].things; Level->site[x][y].things = Level->site[x][y].things->next; free_obj( t->thing, TRUE ); free((char *) t); } } void m_sp_mb(pmt m) { if (distance(m->x,m->y,Player.x,Player.y)==1) { mprint("The manaburst explodes!"); if (m_statusp(m,HOSTILE)) { mprint("You get blasted!"); p_damage(random_range(100),UNSTOPPABLE,"a manaburst"); mprint("You feel cold all over!"); Player.pow-=3; Player.iq--; Player.con--; Player.str-=2; Player.dex--; Player.agi--; dispel(-1); /* DAG -- need calc_melee/calcmana here, because of new stats */ calc_melee(); Player.maxmana = calcmana(); Player.mana = min( Player.mana, Player.maxmana ); } else { mprint("You feel toasty warm inside!"); Player.pow++; Player.mana = max(Player.mana,calcmana()); Player.hp = max(Player.hp,++Player.maxhp); } /* DAG -- to fix the explode but not die manaburst bug */ m_remove( m ); } } void m_sp_mirror(pmt m) { int i,x,y; if (view_los_p(m->x,m->y,Player.x,Player.y)) { if (random_range(20)+6 < m->level) { summon(-1,m->id); mprint("You hear the sound of a mirror shattering!"); } else for(i=0;i<5;i++) { x = m->x + random_range(13)-6; y = m->y + random_range(13)-6; if (inbounds(x,y)) { Level->site[x][y].showchar = m->monchar; putspot(x,y,m->monchar); } } } } void m_illusion(pmt m) { int i = random_range(NUMMONSTERS); if (i==NPC || i==HISCORE_NPC || i==ZERO_NPC) i = m->id; /* can't imitate NPC */ if (Player.status[TRUESIGHT]) { m->monchar = Monsters[m->id].monchar; m->monstring = Monsters[m->id].monstring; } else if (random_range(5) == 1) { m->monchar = Monsters[i].monchar; m->monstring = Monsters[i].monstring; } } void m_huge_sounds(pmt m) { if (m_statusp(m,AWAKE) && (! los_p(m->x,m->y,Player.x,Player.y)) && (random_range(10) == 1)) mprint("The dungeon shakes!"); } void m_thief_f(pmt m) { int i = stolen_item(); if (random_range(3) == 1) { if (distance(Player.x,Player.y,m->x,m->y) < 2) { if (p_immune(THEFT) || (Player.level > (m->level*2)+random_range(20))) mprint("You feel secure."); else { if (i == ABORT) mprint("You feel fortunate."); else if ((Player.possessions[i]->used) || (Player.dex < m->level*random_range(10))) { mprint("You feel a sharp tug.... You hold on!"); } else { mprint("You feel uneasy for a moment."); if (m->uniqueness == COMMON) { strcpy(Str2,"The "); strcat(Str2,m->monstring); } else strcpy(Str2,m->monstring); strcat(Str2," suddenly runs away for some reason."); mprint(Str2); m_teleport(m); m->movef = M_MOVE_SCAREDY; m->specialf = M_MOVE_SCAREDY; m_pickup(m,Player.possessions[i]); conform_unused_object(Player.possessions[i]); Player.possessions[i] = NULL; } } } } } void m_summon(pmt m) { if ((distance(Player.x,Player.y,m->x,m->y) < 2) && (random_range(3) == 1)) { summon(0,-1); summon(0,-1); } } void m_aggravate(pmt m) { if (m_statusp(m,HOSTILE)) { if (m->uniqueness == COMMON) { strcpy(Str2,"The "); strcat(Str2,m->monstring); } else strcpy(Str2,m->monstring); strcat(Str2," emits an irritating humming sound."); mprint(Str2); aggravate(); m_status_reset(m,HOSTILE); } } void m_sp_merchant(pmt m) { pml ml; if (m_statusp(m,HOSTILE)) if (Current_Environment == E_VILLAGE) { mprint("The merchant screams: 'Help! Murder! Guards! Help!'"); mprint("You hear the sound of police whistles and running feet."); for (ml=Level->mlist;ml!=NULL;ml=ml->next) { m_status_set(ml->m,AWAKE); m_status_set(ml->m,HOSTILE); } m->specialf = M_NO_OP; } } /* The special function of the various people in the court of the archmage */ /* and the sorcerors' circle */ void m_sp_court(pmt m) { pml ml; if (m_statusp(m,HOSTILE)) { mprint("A storm of spells hits you!"); for(ml=Level->mlist;ml!=NULL;ml=ml->next) { m_status_set(ml->m,HOSTILE); m_sp_spell(ml->m); if (ml->m->specialf == M_SP_COURT) ml->m->specialf = M_SP_SPELL; } } } /* The special function of the dragons in the dragons' lair */ void m_sp_lair(pmt m) { pml ml; if (m_statusp(m,HOSTILE)) { mprint("You notice a number of dragons waking up...."); mprint("You are struck by a quantity of firebolts."); morewait(); for(ml=Level->mlist;ml!=NULL;ml=ml->next) if (ml->m->hp > 0 && ml->m->specialf == M_SP_LAIR) { m_status_set(ml->m,HOSTILE); fbolt(ml->m->x,ml->m->y,Player.x,Player.y,100,100); if (ml->m->id == DRAGON_LORD) ml->m->specialf = M_SP_DRAGONLORD; else ml->m->specialf = M_STRIKE_FBOLT; } } } void m_sp_prime(pmt m) { if (m_statusp(m,HOSTILE)) { mprint("The prime sorceror gestures and a pentacular gate opens!"); mprint("You are surrounded by demons!"); summon(-1,DEMON_PRINCE); summon(-1,DEMON_PRINCE); summon(-1,DEMON_PRINCE); summon(-1,DEMON_PRINCE); } m->specialf = M_SP_SPELL; }