/* omega copyright (c) 1987,1988,1989 by Laurence Raphael Brothers */ /* mon.c */ /* various functions to do with monsters */ #include "glob.h" /* Revised function */ /* WDT: code contributed by David J. Robertson */ /* consider one monster's action */ void m_pulse(pmt m) { int range = distance(m->x, m->y, Player.x,Player.y); int STRIKE=FALSE; pol prev; if (Time % 10 == 0) if (m->hp < Monsters[m->id].hp) m->hp++; if ((! m_statusp(m,AWAKE)) && (range <= m->wakeup)) { m_status_set(m,AWAKE); resetgamestatus(FAST_MOVE); } if (m_statusp(m,AWAKE)) { if (m_statusp(m,WANDERING)) { if (m_statusp(m,MOBILE)) m_random_move(m); if (range <= m->sense && (m_statusp(m, HOSTILE) || m_statusp(m, NEEDY))) m_status_reset(m,WANDERING); } else /* not wandering */ { if (m_statusp(m,HOSTILE)) if ((range > 2) && (range < m->sense) && (random_range(2) == 1)) if (los_p(m->x,m->y,Player.x,Player.y) && (Player.status[INVISIBLE] == 0)) { STRIKE=TRUE; monster_strike(m); } if ((m_statusp(m,HOSTILE) || m_statusp(m,NEEDY)) && (range > 1) && m_statusp(m,MOBILE) && (!STRIKE || (random_range(2) == 1))) monster_move(m); else if (m_statusp(m,HOSTILE) && (range ==1)) { resetgamestatus(FAST_MOVE); tacmonster(m); } } /* if monster is greedy, picks up treasure it finds */ if (m_statusp(m,GREEDY) && (m->hp >0) ) while (Level->site[m->x][m->y].things != NULL) { m_pickup(m,Level->site[m->x][m->y].things->thing); prev = Level->site[m->x][m->y].things; Level->site[m->x][m->y].things = Level->site[m->x][m->y].things->next; free((char *) prev); } /* prevents monsters from casting spells from other side of dungeon */ if ((range < max(5,m->level)) && (m->hp > 0) && (random_range(2) == 1)) monster_special(m); } } /* actually make a move */ void movemonster(pmt m, int newx, int newy) { if (Level->site[newx][newy].creature != NULL) return; if (Level->site[m->x][m->y].creature == m) Level->site[m->x][m->y].creature = NULL; m->x = newx; m->y = newy; Level->site[m->x][m->y].creature = m; m_movefunction(m,Level->site[m->x][m->y].p_locf); } /* give object o to monster m */ void m_pickup(pmt m, pob o) { pol tmp = ((pol) checkmalloc(sizeof(oltype))); tmp->thing = o; tmp->next = m->possessions; m->possessions = tmp; } void m_dropstuff(pmt m) { pol tmp = m->possessions; if (tmp != NULL) { while (tmp->next != NULL) tmp = tmp->next; tmp->next = Level->site[m->x][m->y].things; Level->site[m->x][m->y].things = m->possessions; m->possessions = NULL; } } void m_damage(pmt m, int dmg, int dtype) { m_status_set(m,AWAKE); m_status_set(m,HOSTILE); if (m_immunityp(m,dtype)) { if (los_p(Player.x,Player.y,m->x,m->y)) { if (m->uniqueness != COMMON) strcpy(Str1,m->monstring); else { strcpy(Str1,"The "); strcat(Str1,m->monstring); } strcat(Str1," ignores the attack!"); mprint(Str1); } } else if ((m->hp -= dmg) < 1) m_death(m); } /* remove a monster -- death without crediting player */ void m_remove(pmt m) { Level->site[m->x][m->y].creature = NULL; erase_monster(m); m->hp = -1; /* signals "death" -- no credit to player, though */ /* DAG -- monster structure will be "cleaned up" in time_clock() which */ /* walks through all the monsters each "tick". (Or on level free.) */ } void m_death(pmt m) { pob corpse; pml ml; int x,y,found=FALSE; pol curr, prev = NULL; m->hp = -1; if (los_p(Player.x,Player.y,m->x,m->y)) { gain_experience(m->xpv); calc_melee(); if (m->uniqueness != COMMON) strcpy(Str1,m->monstring); else { strcpy(Str1,"The "); strcat(Str1,m->monstring); } strcat(Str1," is dead! "); mprint(Str1); } m_dropstuff(m); if (m->id == DEATH) { /* Death */ mprint("Death lies sprawled out on the ground......"); mprint("Death laughs ironically and gets back to its feet."); mprint("It gestures and another scythe appears in its hands."); switch(random_range(10)) { case 0: mprint("Death performs a little bow and goes back on guard."); break; case 1: mprint("'A hit! A palpable hit!' Death goes back on the attack."); break; case 2: mprint("'Ah, if only it could be so simple!' snickers Death."); break; case 3: mprint("'You think Death can be slain? What a jest!' says Death."); break; case 4: mprint("'Your point is well taken.' says Death, attacking again."); break; case 5: mprint("'Oh, come now, stop delaying the inevitable.' says Death."); break; case 6: mprint("'Your destiny ends here with me.' says Death, scythe raised."); break; case 7: mprint("'I almost felt that.' says Death, smiling."); break; case 8: mprint("'Timeo Mortis?' asks Death quizzically, 'Not me!'"); break; case 9: mprint("Death sighs theatrically. 'They never learn.'"); break; } strengthen_death(m); } else { Level->site[m->x][m->y].creature = NULL; if (m == Arena_Monster) Arena_Victory = TRUE; /* won this round of arena combat */ if (random_range(2) || (m->uniqueness != COMMON)) { corpse=((pob) checkmalloc(sizeof(objtype))); make_corpse(corpse,m); drop_at(m->x,m->y,corpse); } plotspot(m->x,m->y,FALSE); switch(m->id) { case HISCORE_NPC: switch(m->aux2) { case 0: mprint("You hear a faroff dirge. You feel a sense of triumph."); break; case 1:case 2: case 3:case 4:case 5:case 6: mprint("You hear a faroff sound like angels crying...."); strcpy(Priest[m->aux2],nameprint()); Priestbehavior[m->aux2] = 2933; break; case 7: mprint("A furtive figure dashes out of the shadows, takes a look at"); mprint("the corpse, and runs away!"); strcpy(Shadowlord,nameprint()); Shadowlordbehavior = 2912; break; case 8: mprint("An aide-de-camp approaches, removes the corpse's insignia,"); mprint("and departs."); strcpy(Commandant,nameprint()); Commandantbehavior = 2912; break; case 9: mprint("An odd glow surrounds the corpse, and slowly fades."); strcpy(Archmage,nameprint()); Archmagebehavior = 2933; break; case 10: mprint("A demon materializes, takes a quick look at the corpse,"); mprint("and teleports away with a faint popping noise."); strcpy(Prime,nameprint()); Primebehavior = 2932; break; case 11: mprint("A sports columnist rushes forward and takes a quick photo"); mprint("of the corpse and rushes off muttering about a deadline."); strcpy(Champion,nameprint()); Championbehavior = 2913; break; case 12: mprint("You hear a fanfare in the distance, and feel dismayed."); strcpy(Duke,nameprint()); Dukebehavior = 2911; break; case 13: if (Player.alignment > 10) mprint("You feel smug."); else if (Player.alignment < 10) mprint("You feel ashamed."); strcpy(Chaoslord,nameprint()); Chaoslordbehavior = 2912; break; case 14: if (Player.alignment < 10) mprint("You feel smug."); else if (Player.alignment > 10) mprint("You feel ashamed."); strcpy(Lawlord,nameprint()); Lawlordbehavior = 2911; break; case 15: /* just a tad complicated. Promote a new justiciar if any guards are left in the city, otherwise Destroy the Order! */ Player.alignment -= 100; if (! gamestatusp(DESTROYED_ORDER)) { curr = Level->site[m->x][m->y].things; while (curr && curr->thing->id != OB_JUSTICIAR_BADGE) { prev = curr; curr = curr->next; } strcpy(Justiciar,nameprint()); Justiciarbehavior = 2911; mprint("In the distance you hear a trumpet. A Servant of Law"); /* promote one of the city guards to be justiciar */ ml = City->mlist; while ((! found) && (ml != NULL)) { found = ((ml->m->id == GUARD) && (ml->m->hp > 0)); if (! found) ml=ml->next; } if (ml != NULL) { if (curr) { mprint("materializes, sheds a tear, picks up the badge, and leaves."); m_pickup(ml->m, curr->thing); if (prev) prev->next = curr->next; else Level->site[m->x][m->y].things = curr->next; free(curr); } else mprint("materializes, sheds a tear, and leaves."); mprint("A new justiciar has been promoted!"); x = ml->m->x; y = ml->m->y; make_hiscore_npc(ml->m,15); ml->m->x = x; ml->m->y = y; ml->m->click = (Tick + 1) % 60; m_status_reset(ml->m,AWAKE); m_status_reset(ml->m,HOSTILE); } else { mprint("materializes, sheds a tear, and leaves."); morewait(); } alert_guards(); /* will cause order to be destroyed if no guards or justiciar*/ } else { mprint("A Servant of Chaos materializes, grabs the corpse,"); mprint("snickers a bit, and vanishes."); } break; case 16: #ifdef TRADEMARK_VIOLATION /* paraphrase of harlan ellison... ? PGM */ mprint("It doesn't rain this day, anywhere in the known universe."); #else mprint("The universal equilibrium slides down a notch."); #endif strcpy(Grandmaster,nameprint()); Grandmasterbehavior = 2933; break; } save_hiscore_npc(m->aux2); break; case GUARD: /* guard */ Player.alignment -= 10; if ((Current_Environment == E_CITY) || (Current_Environment == E_VILLAGE)) alert_guards(); break; case GOBLIN_KING: if (! gamestatusp(ATTACKED_ORACLE)) { mprint("You seem to hear a woman's voice from far off:"); mprint("'Well done! Come to me now....'"); } setgamestatus(COMPLETED_CAVES); break; /* gob king */ case GREAT_WYRM: if (! gamestatusp(ATTACKED_ORACLE)) { mprint("A female voice sounds from just behind your ear:"); mprint("'Well fought! I have some new advice for you....'"); } setgamestatus(COMPLETED_SEWERS); break; /*grt worm */ case EATER: setgamestatus(KILLED_EATER); break; case LAWBRINGER: setgamestatus(KILLED_LAWBRINGER); break; case DRAGON_LORD: setgamestatus(KILLED_DRAGONLORD); break; case DEMON_EMP: setgamestatus(COMPLETED_VOLCANO); if (! gamestatusp(ATTACKED_ORACLE)) { mprint("You feel a soft touch on your shoulder..."); mprint("You turn around but there is no one there!"); mprint("You turn back and see a note: 'See me soon.'"); mprint("The note vanishes in a burst of blue fire!"); } break; case ELEM_MASTER: if (! gamestatusp(ATTACKED_ORACLE)) { mprint("Words appear before you, traced in blue flame!"); mprint("'Return to the Prime Plane via the Circle of Sorcerors....'"); } break; /* elem mast */ } switch (m->specialf) { case M_SP_COURT: case M_SP_LAIR: m_status_set(m,HOSTILE); monster_action(m, m->specialf); } } } void monster_move(pmt m) { monster_action(m,m->movef); } void monster_strike(pmt m) { if (player_on_sanctuary()) print1("The aegis of your deity protects you!"); else { /* being attacked wakes you up/stops fast move */ resetgamestatus(FAST_MOVE); /* It's lawful to wait to be attacked */ if (m->attacked==0) Player.alignment++; m->attacked++; monster_action(m,m->strikef); } } void monster_special(pmt m) { /* since many special functions are really attacks, cancel them all if on sanctuary */ if (! player_on_sanctuary()) { /* being attacked wakes you up/stops fast move */ resetgamestatus(FAST_MOVE); monster_action(m,m->specialf); } } void monster_talk(pmt m) { monster_action(m,m->talkf); } void monster_action(pmt m, int action) { int meleef; if ((action >= M_MELEE_NORMAL) && (action < M_MOVE_NORMAL)) { /* kluge allows multiple attack forms */ if (distance(m->x,m->y,Player.x,Player.y)<2) { meleef = m->meleef; m->meleef = action; tacmonster(m); m->meleef = meleef; } } else switch(action) { case M_NO_OP:m_no_op(m); break; case M_MOVE_NORMAL:m_normal_move(m); break; case M_MOVE_FLUTTER:m_flutter_move(m); break; case M_MOVE_FOLLOW:m_follow_move(m); break; case M_MOVE_TELEPORT:m_teleport(m); break; case M_MOVE_RANDOM:m_random_move(m); break; case M_MOVE_SMART:m_smart_move(m); break; case M_MOVE_SPIRIT:m_spirit_move(m); break; case M_MOVE_CONFUSED:m_confused_move(m); break; case M_MOVE_SCAREDY:m_scaredy_move(m); break; case M_MOVE_ANIMAL:m_move_animal(m); break; case M_MOVE_LEASH:m_move_leash(m); break; case M_STRIKE_MISSILE:m_nbolt(m); break; case M_STRIKE_FBOLT:m_firebolt(m); break; case M_STRIKE_LBALL:m_lball(m); break; case M_STRIKE_FBALL:m_fireball(m); break; case M_STRIKE_SNOWBALL:m_snowball(m); break; case M_STRIKE_BLIND:m_blind_strike(m); break; case M_STRIKE_SONIC:m_strike_sonic(m); break; case M_TALK_HORSE:m_talk_horse(m); break; case M_TALK_THIEF:m_talk_thief(m);break; case M_TALK_STUPID:m_talk_stupid(m); break; case M_TALK_SILENT:m_talk_silent(m); break; case M_TALK_HUNGRY:m_talk_hungry(m); break; case M_TALK_GREEDY:m_talk_greedy(m); break; case M_TALK_TITTER:m_talk_titter(m); break; case M_TALK_MP:m_talk_mp(m); break; case M_TALK_IM:m_talk_im(m); break; case M_TALK_MAN:m_talk_man(m); break; case M_TALK_ROBOT:m_talk_robot(m); break; case M_TALK_EVIL:m_talk_evil(m); break; case M_TALK_GUARD:m_talk_guard(m); break; case M_TALK_MIMSY:m_talk_mimsy(m); break; case M_TALK_SLITHY:m_talk_slithy(m); break; case M_TALK_BURBLE:m_talk_burble(m); break; case M_TALK_BEG:m_talk_beg(m); break; case M_TALK_HINT:m_talk_hint(m); break; case M_TALK_EF:m_talk_ef(m); break; case M_TALK_GF:m_talk_gf(m); break; case M_TALK_SEDUCTOR:m_talk_seductor(m); break; case M_TALK_DEMONLOVER:m_talk_demonlover(m); break; case M_TALK_NINJA:m_talk_ninja(m); break; case M_TALK_ASSASSIN:m_talk_assassin(m); break; case M_TALK_SERVANT: m_talk_servant(m); break; case M_TALK_ANIMAL: m_talk_animal(m); break; case M_TALK_SCREAM: m_talk_scream(m); break; case M_TALK_PARROT: m_talk_parrot(m); break; case M_TALK_HYENA: m_talk_hyena(m); break; case M_TALK_DRUID: m_talk_druid(m); break; case M_TALK_ARCHMAGE: m_talk_archmage(m); break; case M_TALK_MERCHANT: m_talk_merchant(m); break; case M_TALK_PRIME: m_talk_prime(m); break; case M_TALK_MAHARAJA: m_talk_maharaja(m); break; case M_SP_BOG:m_sp_bogthing(m); break; case M_SP_WERE:m_sp_were(m); break; case M_SP_WHISTLEBLOWER:m_sp_whistleblower(m); break; case M_SP_MERCHANT:m_sp_merchant(m); break; case M_SP_SURPRISE:m_sp_surprise(m); break; case M_SP_MP:m_sp_mp(m); break; case M_SP_THIEF:m_thief_f(m); break; case M_SP_DEMONLOVER:m_sp_demonlover(m); break; case M_SP_AGGRAVATE:m_aggravate(m); break; case M_SP_POISON_CLOUD:m_sp_poison_cloud(m); break; case M_SP_HUGE:m_huge_sounds(m); break; case M_SP_SUMMON:m_summon(m); break; case M_SP_ILLUSION:m_illusion(m); break; case M_SP_ESCAPE:m_sp_escape(m); break; case M_SP_FLUTTER:m_flutter_move(m); break; case M_SP_EXPLODE:m_sp_explode(m); break; case M_SP_DEMON:m_sp_demon(m); break; case M_SP_ACID_CLOUD:m_sp_acid_cloud(m); break; case M_SP_GHOST:m_sp_ghost(m); break; case M_SP_SPELL:m_sp_spell(m); break; case M_SP_SEDUCTOR:m_sp_seductor(m); break; case M_SP_EATER:m_sp_eater(m); break; case M_SP_DRAGONLORD:m_sp_dragonlord(m); break; case M_SP_BLACKOUT:m_sp_blackout(m); break; case M_SP_SWARM: m_sp_swarm(m); break; case M_SP_ANGEL: m_sp_angel(m); break; case M_SP_SERVANT: m_sp_servant(m); break; case M_SP_AV: m_sp_av(m); break; case M_SP_LW: m_sp_lw(m); break; case M_SP_MB: m_sp_mb(m); break; case M_SP_RAISE: m_sp_raise(m); break; case M_SP_MIRROR: m_sp_mirror(m); break; case M_SP_COURT: m_sp_court(m); break; case M_SP_LAIR: m_sp_lair(m); break; case M_SP_PRIME: m_sp_prime(m); break; } } /* makes one of the highscore npcs */ void make_hiscore_npc(pmt npc, int npcid) { int st = -1; pob ob; *npc = Monsters[HISCORE_NPC]; npc->aux2 = npcid; /* each of the high score npcs can be created here */ switch(npcid) { case 0: strcpy(Str2,Hiscorer); determine_npc_behavior(npc,Hilevel,Hibehavior); break; case 1: case 2: case 3: case 4: case 5: case 6: strcpy(Str2,Priest[npcid]); determine_npc_behavior(npc,Priestlevel[npcid],Priestbehavior[npcid]); st = ARTIFACTID+13+npcid; /* appropriate holy symbol... */ Objects[st].uniqueness = UNIQUE_MADE; if (npcid == DRUID) npc->talkf = M_TALK_DRUID; if (Player.patron == npcid) m_status_reset(npc, HOSTILE); break; case 7: strcpy(Str2,Shadowlord); determine_npc_behavior(npc,Shadowlordlevel,Shadowlordbehavior); break; case 8: strcpy(Str2,Commandant); determine_npc_behavior(npc,Commandantlevel,Commandantbehavior); if (Player.rank[LEGION]) m_status_reset(npc, HOSTILE); break; case 9: strcpy(Str2,Archmage); determine_npc_behavior(npc,Archmagelevel,Archmagebehavior); st = OB_KOLWYNIA; /* kolwynia */ npc->talkf = M_TALK_ARCHMAGE; m_status_reset(npc, WANDERING); m_status_reset(npc, HOSTILE); break; case 10: strcpy(Str2,Prime); determine_npc_behavior(npc,Primelevel,Primebehavior); npc->talkf = M_TALK_PRIME; npc->specialf = M_SP_PRIME; if (Player.alignment < 0) m_status_reset(npc, HOSTILE); break; case 11: strcpy(Str2,Champion); determine_npc_behavior(npc,Championlevel,Championbehavior); if (Player.rank[ARENA]) m_status_reset(npc, HOSTILE); break; case 12: strcpy(Str2,Duke); determine_npc_behavior(npc,Dukelevel,Dukebehavior); break; case 13: strcpy(Str2,Chaoslord); determine_npc_behavior(npc,Chaoslordlevel,Chaoslordbehavior); if (Player.alignment < 0 && random_range(2)) m_status_reset(npc, HOSTILE); break; case 14: strcpy(Str2,Lawlord); determine_npc_behavior(npc,Lawlordlevel,Lawlordbehavior); if (Player.alignment > 0) m_status_reset(npc, HOSTILE); break; case 15: strcpy(Str2,Justiciar); determine_npc_behavior(npc,Justiciarlevel,Justiciarbehavior); st = OB_JUSTICIAR_BADGE; /* badge */ npc->talkf = M_TALK_GUARD; npc->specialf = M_SP_WHISTLEBLOWER; m_status_reset(npc, WANDERING); m_status_reset(npc, HOSTILE); break; case 16: /* PGM TODO */ strcpy(Str2,Grandmaster); determine_npc_behavior(npc,Grandmasterlevel,Grandmasterbehavior); break; } if (st > -1 && Objects[st].uniqueness == UNIQUE_MADE) { ob = ((pob) checkmalloc(sizeof(objtype))); *ob = Objects[st]; m_pickup(npc,ob); } npc->monstring = salloc(Str2); strcpy(Str1,"The body of "); strcat(Str1,Str2); npc->corpsestr = salloc(Str1); m_status_set( npc, ALLOC ); } /* sets npc behavior given level and behavior code */ void determine_npc_behavior(pmt npc, int level, int behavior) { int combatype,competence,talktype; npc->hp = (level+1)*20; npc->status = AWAKE+MOBILE+WANDERING; combatype = (behavior % 100) / 10; competence = (behavior % 1000) / 100; talktype = behavior / 1000; npc->level = competence; if (npc->level < 2*difficulty()) npc->status += HOSTILE; npc->xpv = npc->level*20; switch (combatype) { case 1: /* melee */ npc->meleef = M_MELEE_NORMAL; npc->dmg = competence*5; npc->hit = competence*3; npc->speed = 3; break; case 2: /*missile*/ npc->meleef = M_MELEE_NORMAL; npc->strikef = M_STRIKE_MISSILE; npc->dmg = competence*3; npc->hit = competence*2; npc->speed = 4; break; case 3: /* spellcasting */ npc->meleef = M_MELEE_NORMAL; npc->dmg = competence; npc->hit = competence; npc->specialf = M_SP_SPELL; npc->speed = 6; break; case 4: /* thievery */ npc->meleef = M_MELEE_NORMAL; npc->dmg = competence; npc->hit = competence; npc->specialf=M_SP_THIEF; npc->speed = 3; break; case 5: /* flee */ npc->dmg = competence; npc->hit = competence; npc->meleef = M_MELEE_NORMAL; npc->specialf = M_MOVE_SCAREDY; npc->speed = 3; break; } if (npc->talkf == M_TALK_MAN) switch (talktype) { case 1: npc->talkf = M_TALK_EVIL; break; case 2: npc->talkf = M_TALK_MAN; break; case 3: npc->talkf = M_TALK_HINT; break; case 4: npc->talkf = M_TALK_BEG; break; case 5: npc->talkf = M_TALK_SILENT; break; default: mprint("Say Whutt? (npc talk weirdness)"); break; } npc->uniqueness = UNIQUE_MADE; } /* makes an ordinary npc (maybe undead) */ void make_log_npc(pmt npc) { int i,n; int behavior,status,level; FILE *fd; /* in case the log file is null */ behavior = 2718; level = 1; status = 2; strcpy(Str2,"Malaprop the Misnamed"); strcpy(Str1,Omegalib); strcat(Str1,"omega.log"); fd = checkfopen(Str1,"r"); n = 1; while(fgets(Str1,STRING_LEN, fd)) { if (random_range(n) == 0) { /* this algo. from Knuth 2 - cute, eh? */ sscanf(Str1,"%d %d %d",&status,&level,&behavior); for (i = 0; (Str1[i] < 'a' || Str1[i] > 'z') && (Str1[i] < 'A' || Str1[i] > 'Z'); i++) ; strcpy(Str2, Str1 + i); Str2[strlen(Str2) - 1] = '\0'; /* 'cos fgets reads in the \n */ } n++; } fclose(fd); npc->hp = level*20; if (status==1) { if (level < 3) { *npc = Monsters[GHOST]; strcpy(Str1,"ghost named "); } else if (level < 7) { *npc = Monsters[HAUNT]; strcpy(Str1,"haunt named "); } else if (level < 12) { *npc = Monsters[SPECTRE]; strcpy(Str1,"spectre named "); } else { *npc = Monsters[LICHE]; strcpy(Str1,"lich named "); } strcat(Str1,Str2); npc->monstring = salloc(Str1); strcpy(Str3,"the mortal remains of "); strcat(Str3,Str2); npc->corpsestr = salloc(Str3); m_status_set( npc, ALLOC ); } else { npc->monstring=salloc(Str2); strcpy(Str3,"the corpse of "); strcat(Str3,Str2); npc->corpsestr = salloc(Str3); m_status_set( npc, ALLOC ); } determine_npc_behavior(npc,level,behavior); } void m_trap_dart(pmt m) { if (los_p(m->x,m->y,Player.x,Player.y)) { if (m->uniqueness != COMMON) strcpy(Str1,m->monstring); else { strcpy(Str1,"The "); strcat(Str1,m->monstring); } strcat(Str1," was hit by a dart!"); mprint(Str1); Level->site[m->x][m->y].locchar = TRAP; lset(m->x, m->y, CHANGED); } m_damage(m,difficulty()*2,NORMAL_DAMAGE); } void m_trap_pit(pmt m) { if (los_p(m->x,m->y,Player.x,Player.y)) { if (m->uniqueness != COMMON) strcpy(Str1,m->monstring); else { strcpy(Str1,"The "); strcat(Str1,m->monstring); } strcat(Str1," fell into a pit!"); mprint(Str1); Level->site[m->x][m->y].locchar = TRAP; lset(m->x, m->y, CHANGED); } if (! m_statusp(m,INTANGIBLE)) m_status_reset(m,MOBILE); m_damage(m,difficulty()*5,NORMAL_DAMAGE); } void m_trap_door(pmt m) { if (los_p(m->x,m->y,Player.x,Player.y)) { if (m->uniqueness != COMMON) strcpy(Str1,m->monstring); else { strcpy(Str1,"The "); strcat(Str1,m->monstring); } strcat(Str1," fell into a trap door!"); mprint(Str1); Level->site[m->x][m->y].locchar = TRAP; lset(m->x, m->y, CHANGED); } m_vanish(m); } void m_trap_abyss(pmt m) { char Str1[80]; if (los_p(m->x,m->y,Player.x,Player.y)) { if (m->uniqueness != COMMON) strcpy(Str1,m->monstring); else { strcpy(Str1,"The "); strcat(Str1,m->monstring); } strcat(Str1," fell into the infinite abyss!"); mprint(Str1); Level->site[m->x][m->y].locchar = ABYSS; lset(m->x, m->y, CHANGED); Level->site[m->x][m->y].p_locf = L_ABYSS; lset(m->x, m->y, CHANGED); } setgamestatus(SUPPRESS_PRINTING); m_vanish(m); resetgamestatus(SUPPRESS_PRINTING); } void m_trap_snare(pmt m) { char Str1[80]; Level->site[m->x][m->y].locchar = TRAP; lset(m->x, m->y, CHANGED); if (los_p(m->x,m->y,Player.x,Player.y)) { if (m->uniqueness != COMMON) strcpy(Str1,m->monstring); else { strcpy(Str1,"The "); strcat(Str1,m->monstring); } strcat(Str1," was caught in a snare!"); mprint(Str1); } if (! m_statusp(m,INTANGIBLE)) m_status_reset(m,MOBILE); } void m_trap_blade(pmt m) { char Str1[80]; Level->site[m->x][m->y].locchar = TRAP; lset(m->x, m->y, CHANGED); if (los_p(m->x,m->y,Player.x,Player.y)) { if (m->uniqueness != COMMON) strcpy(Str1,m->monstring); else { strcpy(Str1,"The "); strcat(Str1,m->monstring); } strcat(Str1," was hit by a blade trap!"); mprint(Str1); } m_damage(m,(difficulty()+1)*7-Player.defense,NORMAL_DAMAGE); } void m_trap_fire(pmt m) { char Str1[80]; Level->site[m->x][m->y].locchar = TRAP; lset(m->x, m->y, CHANGED); if (los_p(m->x,m->y,Player.x,Player.y)) { if (m->uniqueness != COMMON) strcpy(Str1,m->monstring); else { strcpy(Str1,"The "); strcat(Str1,m->monstring); } strcat(Str1," was hit by a fire trap!"); mprint(Str1); } m_damage(m,(difficulty()+1)*5,FLAME); } void m_fire(pmt m) { char Str1[80]; if (los_p(m->x,m->y,Player.x,Player.y)) { if (m->uniqueness != COMMON) strcpy(Str1,m->monstring); else { strcpy(Str1,"The "); strcat(Str1,m->monstring); } strcat(Str1," was blasted by fire!"); mprint(Str1); } m_damage(m,random_range(100),FLAME); } void m_trap_teleport(pmt m) { char Str1[80]; Level->site[m->x][m->y].locchar = TRAP; lset(m->x, m->y, CHANGED); if (los_p(m->x,m->y,Player.x,Player.y)) { if (m->uniqueness != COMMON) strcpy(Str1,m->monstring); else { strcpy(Str1,"The "); strcat(Str1,m->monstring); } strcat(Str1," walked into a teleport trap!"); mprint(Str1); } m_teleport(m); } void m_trap_disintegrate(pmt m) { char Str1[80]; if (los_p(m->x,m->y,Player.x,Player.y)) { if (m->uniqueness != COMMON) strcpy(Str1,m->monstring); else { strcpy(Str1,"The "); strcat(Str1,m->monstring); } strcat(Str1," walked into a disintegration trap!"); mprint(Str1); Level->site[m->x][m->y].locchar = TRAP; lset(m->x, m->y, CHANGED); } disintegrate(m->x,m->y); } void m_trap_sleepgas(pmt m) { char Str1[80]; if (los_p(m->x,m->y,Player.x,Player.y)) { if (m->uniqueness != COMMON) strcpy(Str1,m->monstring); else { strcpy(Str1,"The "); strcat(Str1,m->monstring); } strcat(Str1," walked into a sleepgas trap!"); mprint(Str1); Level->site[m->x][m->y].locchar = TRAP; lset(m->x, m->y, CHANGED); } if (! m_immunityp(m,SLEEP)) m_status_reset(m,AWAKE); } void m_trap_acid(pmt m) { char Str1[80]; if (los_p(m->x,m->y,Player.x,Player.y)) { if (m->uniqueness != COMMON) strcpy(Str1,m->monstring); else { strcpy(Str1,"The "); strcat(Str1,m->monstring); } strcat(Str1," walked into an acid bath trap!"); mprint(Str1); Level->site[m->x][m->y].locchar = TRAP; lset(m->x, m->y, CHANGED); } m_damage(m,random_range(difficulty()*difficulty()),ACID); } void m_trap_manadrain(pmt m) { char Str1[80]; if (los_p(m->x,m->y,Player.x,Player.y)) { if (m->uniqueness != COMMON) strcpy(Str1,m->monstring); else { strcpy(Str1,"The "); strcat(Str1,m->monstring); } strcat(Str1," walked into a manadrain trap!"); mprint(Str1); Level->site[m->x][m->y].locchar = TRAP; lset(m->x, m->y, CHANGED); } if (m->specialf == M_SP_SPELL) m->specialf = M_NO_OP; } void m_water(pmt m) { char Str1[80]; if ((! m_statusp(m,INTANGIBLE)) && (! m_statusp(m,SWIMMING)) && (! m_statusp(m,ONLYSWIM))) { if (los_p(m->x,m->y,Player.x,Player.y)) { if (m->uniqueness != COMMON) strcpy(Str1,m->monstring); else { strcpy(Str1,"The "); strcat(Str1,m->monstring); } strcat(Str1," drowned!"); mprint(Str1); } m_death(m); } } void m_abyss(pmt m) { char Str1[80]; if (los_p(m->x,m->y,Player.x,Player.y)) { if (m->uniqueness != COMMON) strcpy(Str1,m->monstring); else { strcpy(Str1,"The "); strcat(Str1,m->monstring); } strcat(Str1," fell into the infinite abyss!"); mprint(Str1); } m_vanish(m); } void m_lava(pmt m) { char Str1[80]; if ((! m_immunityp(m,FLAME)) || ((! m_statusp(m,SWIMMING))&& (! m_statusp(m,ONLYSWIM)))) { if (los_p(m->x,m->y,Player.x,Player.y)) { if (m->uniqueness != COMMON) strcpy(Str1,m->monstring); else { strcpy(Str1,"The "); strcat(Str1,m->monstring); } strcat(Str1," died in a pool of lava!"); mprint(Str1); } m_death(m); } } void m_altar(pmt m) { int visible = view_los_p(Player.x,Player.y,m->x,m->y); int reaction = 0; int altar = Level->site[m->x][m->y].aux; if (visible) { if (m->uniqueness != COMMON) strcpy(Str1,m->monstring); else { strcpy(Str1,"The "); strcat(Str1,m->monstring); } strcat(Str1," walks next to an altar..."); mprint(Str1); } if (!m_statusp(m, HOSTILE)) reaction = 0; else if (m->id == HISCORE_NPC && m->aux2 == altar) reaction = 1; /* high priest of same deity */ else if ((m->id == ANGEL || m->id == HIGH_ANGEL || m->id == ARCHANGEL) && m->aux1 == altar) reaction = 1; /* angel of same deity */ else if (altar == Player.patron) reaction = -1; /* friendly deity will zap hostile monster */ else if (((Player.patron == ODIN || Player.patron == ATHENA) && (altar == SET || altar == HECATE)) || ((Player.patron == SET || Player.patron == HECATE) && (altar == ODIN || altar == ATHENA))) reaction = 1; /* hostile deity will help hostile monster */ switch (reaction) { case -1: if (visible) { mprint("Your deity is angry!"); mprint("A bolt of godsfire strikes the monster...."); } disrupt(m->x,m->y,Player.rank[PRIESTHOOD]*50); break; case 1: if (visible) { mprint("The deity of the altar smiles on the monster...."); mprint("A shaft of light zaps the altar..."); } m->hp = Monsters[m->id].hp*2; break; default: if (visible) mprint("but nothing much seems to happen"); break; } } char *mancorpse(void) { switch(random_range(20)) { case 0: return "dead janitor"; case 1: return "dead beggar"; case 2: return "dead barbarian"; case 3: return "dead hairdresser"; case 4: return "dead accountant"; case 5: return "dead lawyer"; case 6: return "dead indian chief"; case 7: return "dead tinker"; case 8: return "dead tailor"; case 9: return "dead soldier"; case 10: return "dead spy"; case 11: return "dead doctor"; case 12: return "dead miner"; case 13: return "dead noble"; case 14: return "dead serf"; case 15: return "dead neer-do-well"; case 16: return "dead vendor"; case 17: return "dead dilettante"; case 18: return "dead surveyor"; default: case 19: return "dead jongleur"; } } char *angeltype(int mid, int deity) { if (ANGEL == mid ) { switch (deity) { case ODIN: return "angel of Odin";break; case SET: return "angel of Set";break; case HECATE: return "angel of Hecate";break; case ATHENA: return "angel of Athena";break; case DESTINY: return "angel of Destiny";break; case DRUID: return "angel of the Balance";break; } } else if (HIGH_ANGEL == mid ) { switch (deity) { case ODIN: return "high angel of Odin";break; case SET: return "high angel of Set";break; case HECATE: return "high angel of Hecate";break; case ATHENA: return "high angel of Athena";break; case DESTINY: return "high angel of Destiny";break; case DRUID: return "high angel of the Balance";break; } } else /* ARCHANGEL */ { switch (deity) { case ODIN: return "archangel of Odin";break; case SET: return "archangel of Set";break; case HECATE: return "archangel of Hecate";break; case ATHENA: return "archangel of Athena";break; case DESTINY: return "archangel of Destiny";break; case DRUID: return "archangel of the Balance";break; } } /* And, if none of those work, this function's broken -- I'm gonna die. */ return "angel of Death"; } void strengthen_death(pmt m) { pol ol = ((pol)checkmalloc(sizeof(oltype))); pob scythe = ((pob)checkmalloc(sizeof(objtype))); #ifdef MSDOS_SUPPORTED_ANTIQUE unsigned tmp; #endif m->xpv += min(10000,m->xpv+1000); m->hit += min(1000,m->hit+10); m->dmg = min(10000,m->dmg*2); m->ac += min(1000,m->ac+10); m->speed = max(m->speed-1,1); m->movef = M_MOVE_SMART; #ifndef MSDOS_SUPPORTED_ANTIQUE m->hp = min(100000,100+m->dmg*10); #else /* In order not to have to make the hp's into longs or unsigned, which would involve lots of changes, I'll make it max out at 30000. */ tmp = 100+m->dmg*10; m->hp = (tmp > 30000) ? 30000 : tmp; #endif *scythe = Objects[OB_SCYTHE_DEATH]; ol->thing = scythe; ol->next = NULL; m->possessions = ol; } void m_no_op(pmt m) { }