1 /* omega copyright (c) 1987,1988,1989 by Laurence Raphael Brothers */
2 /* mon.c */
3 /* various functions to do with monsters */
4 
5 #include "glob.h"
6 
7 
8 
9 /*               Revised function                   */
10 /* WDT: code contributed by David J. Robertson */
11 /* consider one monster's action */
m_pulse(m)12 void m_pulse(m)
13 struct monster *m;
14 {
15   int range = distance(m->x, m->y, Player.x,Player.y);
16   int STRIKE=FALSE;
17   pol prev;
18 
19   if (Time % 10 == 0)
20     if (m->hp < Monsters[m->id].hp)
21       m->hp++;
22 
23   if ((! m_statusp(m,AWAKE)) && (range <= m->wakeup)) {
24     m_status_set(m,AWAKE);
25     resetgamestatus(FAST_MOVE);
26   }
27 
28   if (m_statusp(m,AWAKE)) {
29     if (m_statusp(m,WANDERING)) {
30       if (m_statusp(m,MOBILE)) m_random_move(m);
31       if (range <= m->sense && (m_statusp(m, HOSTILE) ||
32           m_statusp(m, NEEDY)))
33         m_status_reset(m,WANDERING);
34     }
35     else /* not wandering */ {
36       if (m_statusp(m,HOSTILE))
37         if ((range > 2) && (range < m->sense) && (random_range(2) == 1))
38           if (los_p(m->x,m->y,Player.x,Player.y) &&
39               (Player.status[INVISIBLE] == 0)) {
40             STRIKE=TRUE;
41             monster_strike(m);
42           }
43 
44       if ((m_statusp(m,HOSTILE) || m_statusp(m,NEEDY))
45           && (range > 1) && m_statusp(m,MOBILE) &&
46           (!STRIKE || (random_range(2) == 1)))
47         monster_move(m);
48       else
49         if (m_statusp(m,HOSTILE) && (range ==1)) {
50           resetgamestatus(FAST_MOVE);
51           tacmonster(m);
52         }
53     }
54     /* if monster is greedy, picks up treasure it finds */
55     if (m_statusp(m,GREEDY) && (m->hp >0) )
56       while (Level->site[m->x][m->y].things != NULL) {
57         m_pickup(m,Level->site[m->x][m->y].things->thing);
58         prev = Level->site[m->x][m->y].things;
59         Level->site[m->x][m->y].things =
60           Level->site[m->x][m->y].things->next;
61         free((char *) prev);
62       }
63     /* prevents monsters from casting spells from other side of dungeon */
64     if ((range < max(5,m->level)) && (m->hp > 0) &&
65         (random_range(2) == 1))
66       monster_special(m);
67   }
68 }
69 
70 /* actually make a move */
movemonster(m,newx,newy)71 void movemonster(m,newx,newy)
72 struct monster *m;
73 int newx,newy;
74 {
75   if (Level->site[newx][newy].creature != NULL)
76     return;
77   if (Level->site[m->x][m->y].creature == m)
78     Level->site[m->x][m->y].creature = NULL;
79   m->x = newx;
80   m->y = newy;
81   Level->site[m->x][m->y].creature = m;
82   m_movefunction(m,Level->site[m->x][m->y].p_locf);
83 }
84 
85 
86 /* give object o to monster m */
m_pickup(m,o)87 void m_pickup(m,o)
88 struct monster *m;
89 struct object *o;
90 {
91   pol tmp = ((pol) checkmalloc(sizeof(oltype)));
92   tmp->thing = o;
93   tmp->next = m->possessions;
94   m->possessions = tmp;
95 }
96 
m_dropstuff(m)97 void m_dropstuff(m)
98 struct monster *m;
99 {
100   pol tmp = m->possessions;
101   if (tmp != NULL) {
102     while (tmp->next != NULL)
103       tmp = tmp->next;
104 
105     tmp->next = Level->site[m->x][m->y].things;
106     Level->site[m->x][m->y].things = m->possessions;
107     m->possessions = NULL;
108   }
109 }
110 
111 
112 
m_damage(m,dmg,dtype)113 void m_damage(m,dmg,dtype)
114 struct monster *m;
115 int dmg,dtype;
116 {
117   m_status_set(m,AWAKE);
118   m_status_set(m,HOSTILE);
119   if (m_immunityp(m,dtype)) {
120     if (los_p(Player.x,Player.y,m->x,m->y)) {
121       if (m->uniqueness != COMMON) strcpy(Str1,m->monstring);
122       else {
123 	strcpy(Str1,"The ");
124 	strcat(Str1,m->monstring);
125       }
126       strcat(Str1," ignores the attack!");
127       mprint(Str1);
128     }
129   }
130   else if ((m->hp -= dmg) < 1) m_death(m);
131 }
132 
133 
m_death(m)134 void m_death(m)
135 struct monster *m;
136 {
137   pob corpse;
138   pml ml;
139   int x,y,found=FALSE;
140   pol curr, prev = NULL;
141 
142   m->hp = -1;
143   if (los_p(Player.x,Player.y,m->x,m->y)) {
144     gain_experience(m->xpv);
145     calc_melee();
146     if (m->uniqueness != COMMON) strcpy(Str1,m->monstring);
147     else {
148       strcpy(Str1,"The ");
149       strcat(Str1,m->monstring);
150     }
151     strcat(Str1," is dead! ");
152     mprint(Str1);
153   }
154   m_dropstuff(m);
155   if (m->id == DEATH) { /* Death */
156     mprint("Death lies sprawled out on the ground......");
157     mprint("Death laughs ironically and gets back to its feet.");
158     mprint("It gestures and another scythe appears in its hands.");
159     switch(random_range(10)) {
160     case 0:
161       mprint("Death performs a little bow and goes back on guard.");
162       break;
163     case 1:
164       mprint("'A hit! A palpable hit!' Death goes back on the attack.");
165       break;
166     case 2:
167       mprint("'Ah, if only it could be so simple!' snickers Death.");
168       break;
169     case 3:
170       mprint("'You think Death can be slain?  What a jest!' says Death.");
171       break;
172     case 4:
173       mprint("'Your point is well taken.' says Death, attacking again.");
174       break;
175     case 5:
176       mprint("'Oh, come now, stop delaying the inevitable.' says Death.");
177       break;
178     case 6:
179       mprint("'Your destiny ends here with me.' says Death, scythe raised.");
180       break;
181     case 7:
182       mprint("'I almost felt that.' says Death, smiling.");
183       break;
184     case 8:
185       mprint("'Timeo Mortis?' asks Death quizzically, 'Not me!'");
186       break;
187     case 9:
188       mprint("Death sighs theatrically. 'They never learn.'");
189       break;
190     }
191     strengthen_death(m);
192   }
193   else {
194     Level->site[m->x][m->y].creature = NULL;
195     if (m == Arena_Monster)
196       Arena_Victory = TRUE;	/* won this round of arena combat */
197     if (random_range(2) || (m->uniqueness != COMMON)) {
198       corpse=((pob) checkmalloc(sizeof(objtype)));
199       make_corpse(corpse,m);
200       drop_at(m->x,m->y,corpse);
201     }
202     plotspot(m->x,m->y,FALSE);
203     switch(m->id) {
204     case HISCORE_NPC:
205       switch(m->aux2) {
206       case 0:
207 	mprint("You hear a faroff dirge. You feel a sense of triumph.");
208 	break;
209       case 1:case 2: case 3:case 4:case 5:case 6:
210 	mprint("You hear a faroff sound like angels crying....");
211 	strcpy(Priest[m->aux2],nameprint());
212 	Priestbehavior[m->aux2] = 2933;
213 	break;
214       case 7:
215       mprint("A furtive figure dashes out of the shadows, takes a look at");
216 	mprint("the corpse, and runs away!");
217 	strcpy(Shadowlord,nameprint());
218 	Shadowlordbehavior = 2912;
219 	break;
220       case 8:
221 	mprint("An aide-de-camp approaches, removes the corpse's insignia,");
222 	mprint("and departs.");
223 	strcpy(Commandant,nameprint());
224 	Commandantbehavior = 2912;
225 	break;
226       case 9:
227 	mprint("An odd glow surrounds the corpse, and slowly fades.");
228 	strcpy(Archmage,nameprint());
229 	Archmagebehavior = 2933;
230 	break;
231       case 10:
232 	mprint("A demon materializes, takes a quick look at the corpse,");
233 	mprint("and teleports away with a faint popping noise.");
234 	strcpy(Prime,nameprint());
235 	Primebehavior = 2932;
236 	break;
237       case 11:
238 	mprint("A sports columnist rushes forward and takes a quick photo");
239 	mprint("of the corpse and rushes off muttering about a deadline.");
240 	strcpy(Champion,nameprint());
241 	Championbehavior = 2913;
242 	break;
243       case 12:
244 	mprint("You hear a fanfare in the distance, and feel dismayed.");
245 	strcpy(Duke,nameprint());
246 	Dukebehavior = 2911;
247 	break;
248       case 13:
249 	if (Player.alignment > 10) mprint("You feel smug.");
250 	else if (Player.alignment < 10) mprint("You feel ashamed.");
251 	strcpy(Chaoslord,nameprint());
252 	Chaoslordbehavior = 2912;
253 	break;
254       case 14:
255 	if (Player.alignment < 10) mprint("You feel smug.");
256 	else if (Player.alignment > 10) mprint("You feel ashamed.");
257 	strcpy(Lawlord,nameprint());
258 	Lawlordbehavior = 2911;
259 	break;
260       case 15:
261 	/* just a tad complicated. Promote a new justiciar if any
262 	   guards are left in the city, otherwise Destroy the Order! */
263 	Player.alignment -= 100;
264 	if (! gamestatusp(DESTROYED_ORDER)) {
265 	  curr = Level->site[m->x][m->y].things;
266 	  while (curr && curr->thing->id != THINGID + 16) {
267 	    prev = curr;
268 	    curr = curr->next;
269 	  }
270 	  strcpy(Justiciar,nameprint());
271 	  Justiciarbehavior = 2911;
272 	  mprint("In the distance you hear a trumpet. A Servant of Law");
273 	  /* promote one of the city guards to be justiciar */
274 	  ml = City->mlist;
275 	  while ((! found) && (ml != NULL)) {
276 	    found = ((ml->m->id == GUARD) && (ml->m->hp > 0));
277 	    if (! found) ml=ml->next;
278 	  }
279 	  if (ml != NULL) {
280 	    if (curr) {
281 	      mprint("materializes, sheds a tear, picks up the badge, and leaves.");
282 	      m_pickup(ml->m, curr->thing);
283 	      if (prev)
284 		prev->next = curr->next;
285 	      else
286 		Level->site[m->x][m->y].things = curr->next;
287 	      free(curr);
288 	    }
289 	    else
290 	      mprint("materializes, sheds a tear, and leaves.");
291 	    mprint("A new justiciar has been promoted!");
292 	    x = ml->m->x; y = ml->m->y;
293 	    make_hiscore_npc(ml->m,15);
294 	    ml->m->x = x;
295 	    ml->m->y = y;
296 	    ml->m->click = (Tick + 1) % 60;
297 	    m_status_reset(ml->m,AWAKE);
298 	    m_status_reset(ml->m,HOSTILE);
299 	  }
300 	  else {
301 	    mprint("materializes, sheds a tear, and leaves.");
302 	    morewait();
303 	  }
304 	  alert_guards();
305 	  /* will cause order to be destroyed if no guards or justiciar*/
306 	}
307 	else {
308 	  mprint("A Servant of Chaos materializes, grabs the corpse,");
309 	  mprint("snickers a bit, and vanishes.");
310 	}
311 	break;
312       }
313       save_hiscore_npc(m->aux2);
314       break;
315     case GUARD: /* guard */
316       Player.alignment -= 10;
317       if ((Current_Environment == E_CITY) ||
318 	  (Current_Environment == E_VILLAGE))
319 	alert_guards();
320       break;
321     case GOBLIN_KING:
322       if (! gamestatusp(ATTACKED_ORACLE)) {
323 	mprint("You seem to hear a woman's voice from far off:");
324 	mprint("'Well done! Come to me now....'");
325       }
326       setgamestatus(COMPLETED_CAVES);
327       break; /* gob king */
328     case GREAT_WYRM:
329       if (! gamestatusp(ATTACKED_ORACLE)) {
330 	mprint("A female voice sounds from just behind your ear:");
331 	mprint("'Well fought! I have some new advice for you....'");
332       }
333       setgamestatus(COMPLETED_SEWERS);
334       break; /*grt worm */
335     case EATER:
336       setgamestatus(KILLED_EATER);
337       break;
338     case LAWBRINGER:
339       setgamestatus(KILLED_LAWBRINGER);
340       break;
341     case DRAGON_LORD:
342       setgamestatus(KILLED_DRAGONLORD);
343       break;
344     case DEMON_EMP:
345       setgamestatus(COMPLETED_VOLCANO);
346       if (! gamestatusp(ATTACKED_ORACLE)) {
347 	mprint("You feel a soft touch on your shoulder...");
348 	mprint("You turn around but there is no one there!");
349 	mprint("You turn back and see a note: 'See me soon.'");
350 	mprint("The note vanishes in a burst of blue fire!");
351       }
352       break;
353     case ELEM_MASTER:
354       if (! gamestatusp(ATTACKED_ORACLE)) {
355 	mprint("Words appear before you, traced in blue flame!");
356 	mprint("'Return to the Prime Plane via the Circle of Sorcerors....'");
357       }
358       break; /* elem mast */
359     }
360     switch (m->specialf) {
361       case M_SP_COURT:
362       case M_SP_LAIR:
363 	m_status_set(m,HOSTILE);
364 	monster_action(m, m->specialf);
365     }
366   }
367 }
368 
369 
370 
371 
372 
373 
374 
monster_move(m)375 void monster_move(m)
376 struct monster *m;
377 {
378   monster_action(m,m->movef);
379 }
380 
381 
382 
383 
384 
385 
386 
387 
388 
monster_strike(m)389 void monster_strike(m)
390 struct monster *m;
391 {
392   if (player_on_sanctuary())
393     print1("The aegis of your deity protects you!");
394   else {
395   /* It's lawful to wait to be attacked */
396     if (m->attacked==0) Player.alignment++;
397     m->attacked++;
398     monster_action(m,m->strikef);
399   }
400 }
401 
monster_special(m)402 void monster_special(m)
403 struct monster *m;
404 {
405   /* since many special functions are really attacks, cancel them
406      all if on sanctuary */
407   if (! player_on_sanctuary())
408     monster_action(m,m->specialf);
409 }
410 
411 
monster_talk(m)412 void monster_talk(m)
413 struct monster *m;
414 {
415   monster_action(m,m->talkf);
416 }
417 
monster_action(m,action)418 void monster_action(m,action)
419 struct monster *m;
420 int action;
421 {
422   int meleef;
423   if ((action >= M_MELEE_NORMAL) && (action < M_MOVE_NORMAL)) {
424     /* kluge allows multiple attack forms */
425     if (distance(m->x,m->y,Player.x,Player.y)<2) {
426       meleef = m->meleef;
427       m->meleef = action;
428       tacmonster(m);
429       m->meleef = meleef;
430     }
431   }
432   else switch(action) {
433 
434   case M_NO_OP:m_no_op(m); break;
435 
436   case M_MOVE_NORMAL:m_normal_move(m); break;
437   case M_MOVE_FLUTTER:m_flutter_move(m); break;
438   case M_MOVE_FOLLOW:m_follow_move(m); break;
439   case M_MOVE_TELEPORT:m_teleport(m); break;
440   case M_MOVE_RANDOM:m_random_move(m); break;
441   case M_MOVE_SMART:m_smart_move(m); break;
442   case M_MOVE_SPIRIT:m_spirit_move(m); break;
443   case M_MOVE_CONFUSED:m_confused_move(m); break;
444   case M_MOVE_SCAREDY:m_scaredy_move(m); break;
445   case M_MOVE_ANIMAL:m_move_animal(m); break;
446   case M_MOVE_LEASH:m_move_leash(m); break;
447 
448   case M_STRIKE_MISSILE:m_nbolt(m); break;
449   case M_STRIKE_FBOLT:m_firebolt(m); break;
450   case M_STRIKE_LBALL:m_lball(m); break;
451   case M_STRIKE_FBALL:m_fireball(m); break;
452   case M_STRIKE_SNOWBALL:m_snowball(m); break;
453   case M_STRIKE_BLIND:m_blind_strike(m); break;
454   case M_STRIKE_SONIC:m_strike_sonic(m); break;
455 
456   case M_TALK_HORSE:m_talk_horse(m); break;
457   case M_TALK_THIEF:m_talk_thief(m);break;
458   case M_TALK_STUPID:m_talk_stupid(m); break;
459   case M_TALK_SILENT:m_talk_silent(m); break;
460   case M_TALK_HUNGRY:m_talk_hungry(m); break;
461   case M_TALK_GREEDY:m_talk_greedy(m); break;
462   case M_TALK_TITTER:m_talk_titter(m); break;
463   case M_TALK_MP:m_talk_mp(m); break;
464   case M_TALK_IM:m_talk_im(m); break;
465   case M_TALK_MAN:m_talk_man(m); break;
466   case M_TALK_ROBOT:m_talk_robot(m); break;
467   case M_TALK_EVIL:m_talk_evil(m); break;
468   case M_TALK_GUARD:m_talk_guard(m); break;
469   case M_TALK_MIMSY:m_talk_mimsy(m); break;
470   case M_TALK_SLITHY:m_talk_slithy(m); break;
471   case M_TALK_BURBLE:m_talk_burble(m); break;
472   case M_TALK_BEG:m_talk_beg(m); break;
473   case M_TALK_HINT:m_talk_hint(m); break;
474   case M_TALK_EF:m_talk_ef(m); break;
475   case M_TALK_GF:m_talk_gf(m); break;
476   case M_TALK_SEDUCTOR:m_talk_seductor(m); break;
477   case M_TALK_DEMONLOVER:m_talk_demonlover(m); break;
478   case M_TALK_NINJA:m_talk_ninja(m); break;
479   case M_TALK_ASSASSIN:m_talk_assassin(m); break;
480   case M_TALK_SERVANT: m_talk_servant(m); break;
481   case M_TALK_ANIMAL: m_talk_animal(m); break;
482   case M_TALK_SCREAM: m_talk_scream(m); break;
483   case M_TALK_PARROT: m_talk_parrot(m); break;
484   case M_TALK_HYENA: m_talk_hyena(m); break;
485   case M_TALK_DRUID: m_talk_druid(m); break;
486   case M_TALK_ARCHMAGE: m_talk_archmage(m); break;
487   case M_TALK_MERCHANT: m_talk_merchant(m); break;
488   case M_TALK_PRIME: m_talk_prime(m); break;
489 
490   case M_SP_BOG:m_sp_bogthing(m); break;
491   case M_SP_WERE:m_sp_were(m); break;
492   case M_SP_WHISTLEBLOWER:m_sp_whistleblower(m); break;
493   case M_SP_MERCHANT:m_sp_merchant(m); break;
494   case M_SP_SURPRISE:m_sp_surprise(m); break;
495   case M_SP_MP:m_sp_mp(m); break;
496   case M_SP_THIEF:m_thief_f(m); break;
497   case M_SP_DEMONLOVER:m_sp_demonlover(m); break;
498   case M_SP_AGGRAVATE:m_aggravate(m); break;
499   case M_SP_POISON_CLOUD:m_sp_poison_cloud(m); break;
500   case M_SP_HUGE:m_huge_sounds(m); break;
501   case M_SP_SUMMON:m_summon(m); break;
502   case M_SP_ILLUSION:m_illusion(m); break;
503   case M_SP_ESCAPE:m_sp_escape(m); break;
504   case M_SP_FLUTTER:m_flutter_move(m); break;
505   case M_SP_EXPLODE:m_sp_explode(m); break;
506   case M_SP_DEMON:m_sp_demon(m); break;
507   case M_SP_ACID_CLOUD:m_sp_acid_cloud(m); break;
508   case M_SP_GHOST:m_sp_ghost(m); break;
509   case M_SP_SPELL:m_sp_spell(m); break;
510   case M_SP_SEDUCTOR:m_sp_seductor(m); break;
511   case M_SP_EATER:m_sp_eater(m); break;
512   case M_SP_DRAGONLORD:m_sp_dragonlord(m); break;
513   case M_SP_BLACKOUT:m_sp_blackout(m); break;
514   case M_SP_SWARM: m_sp_swarm(m); break;
515   case M_SP_ANGEL: m_sp_angel(m); break;
516   case M_SP_SERVANT: m_sp_servant(m); break;
517   case M_SP_AV: m_sp_av(m); break;
518   case M_SP_LW: m_sp_lw(m); break;
519   case M_SP_MB: m_sp_mb(m); break;
520   case M_SP_RAISE: m_sp_raise(m); break;
521   case M_SP_MIRROR: m_sp_mirror(m); break;
522   case M_SP_COURT: m_sp_court(m); break;
523   case M_SP_LAIR: m_sp_lair(m); break;
524   case M_SP_PRIME: m_sp_prime(m); break;
525   }
526 }
527 
528 /* makes one of the highscore npcs */
make_hiscore_npc(npc,npcid)529 void make_hiscore_npc(npc,npcid)
530 pmt npc;
531 int npcid;
532 {
533   int st = -1;
534   pob ob;
535   *npc = Monsters[HISCORE_NPC];
536   npc->aux2 = npcid;
537   /* each of the high score npcs can be created here */
538   switch(npcid) {
539   case 0:
540     strcpy(Str2,Hiscorer);
541     determine_npc_behavior(npc,Hilevel,Hibehavior);
542     break;
543   case 1: case 2: case 3: case 4: case 5: case 6:
544     strcpy(Str2,Priest[npcid]);
545     determine_npc_behavior(npc,Priestlevel[npcid],Priestbehavior[npcid]);
546     st = ARTIFACTID+13+npcid;	/* appropriate holy symbol... */
547     Objects[st].uniqueness = UNIQUE_MADE;
548     if (npcid == DRUID)
549       npc->talkf = M_TALK_DRUID;
550     if (Player.patron == npcid)
551       m_status_reset(npc, HOSTILE);
552     break;
553   case 7:
554     strcpy(Str2,Shadowlord);
555     determine_npc_behavior(npc,Shadowlordlevel,Shadowlordbehavior);
556     break;
557   case 8:
558     strcpy(Str2,Commandant);
559     determine_npc_behavior(npc,Commandantlevel,Commandantbehavior);
560     if (Player.rank[LEGION])
561       m_status_reset(npc, HOSTILE);
562     break;
563   case 9:
564     strcpy(Str2,Archmage);
565     determine_npc_behavior(npc,Archmagelevel,Archmagebehavior);
566     st = ARTIFACTID+9; /* kolwynia */
567     npc->talkf = M_TALK_ARCHMAGE;
568     m_status_reset(npc, WANDERING);
569     m_status_reset(npc, HOSTILE);
570     break;
571   case 10:
572     strcpy(Str2,Prime);
573     determine_npc_behavior(npc,Primelevel,Primebehavior);
574     npc->talkf = M_TALK_PRIME;
575     npc->specialf = M_SP_PRIME;
576     if (Player.alignment < 0)
577       m_status_reset(npc, HOSTILE);
578     break;
579   case 11:
580     strcpy(Str2,Champion);
581     determine_npc_behavior(npc,Championlevel,Championbehavior);
582     if (Player.rank[ARENA])
583       m_status_reset(npc, HOSTILE);
584     break;
585   case 12:
586     strcpy(Str2,Duke);
587     determine_npc_behavior(npc,Dukelevel,Dukebehavior);
588     break;
589   case 13:
590     strcpy(Str2,Chaoslord);
591     determine_npc_behavior(npc,Chaoslordlevel,Chaoslordbehavior);
592     if (Player.alignment < 0 && random_range(2))
593       m_status_reset(npc, HOSTILE);
594     break;
595   case 14:
596     strcpy(Str2,Lawlord);
597     determine_npc_behavior(npc,Lawlordlevel,Lawlordbehavior);
598     if (Player.alignment > 0)
599       m_status_reset(npc, HOSTILE);
600     break;
601   case 15:
602     strcpy(Str2,Justiciar);
603     determine_npc_behavior(npc,Justiciarlevel,Justiciarbehavior);
604     st = THINGID+16;	/* badge */
605     npc->talkf = M_TALK_GUARD;
606     npc->specialf = M_SP_WHISTLEBLOWER;
607     m_status_reset(npc, WANDERING);
608     m_status_reset(npc, HOSTILE);
609     break;
610   }
611   if (st > -1 && Objects[st].uniqueness == UNIQUE_MADE) {
612     ob = ((pob) checkmalloc(sizeof(objtype)));
613     *ob = Objects[st];
614     m_pickup(npc,ob);
615   }
616   npc->monstring = salloc(Str2);
617   strcpy(Str1,"The body of ");
618   strcat(Str1,Str2);
619   npc->corpsestr = salloc(Str1);
620 }
621 
622 
623 
624 
625 /* sets npc behavior given level and behavior code */
determine_npc_behavior(npc,level,behavior)626 void determine_npc_behavior(npc,level,behavior)
627 pmt npc;
628 int level,behavior;
629 {
630   int combatype,competence,talktype;
631   npc->hp = (level+1)*20;
632   npc->status = AWAKE+MOBILE+WANDERING;
633   combatype = (behavior % 100) / 10;
634   competence = (behavior % 1000) / 100;
635   talktype = behavior / 1000;
636   npc->level = competence;
637   if (npc->level < 2*difficulty()) npc->status += HOSTILE;
638   npc->xpv = npc->level*20;
639   switch (combatype) {
640   case 1: /* melee */
641     npc->meleef = M_MELEE_NORMAL;
642     npc->dmg = competence*5;
643     npc->hit = competence*3;
644     npc->speed = 3;
645     break;
646   case 2: /*missile*/
647     npc->meleef = M_MELEE_NORMAL;
648     npc->strikef = M_STRIKE_MISSILE;
649     npc->dmg = competence*3;
650     npc->hit = competence*2;
651     npc->speed = 4;
652     break;
653   case 3: /* spellcasting */
654     npc->meleef = M_MELEE_NORMAL;
655     npc->dmg = competence;
656     npc->hit = competence;
657     npc->specialf = M_SP_SPELL;
658     npc->speed = 6;
659     break;
660   case 4: /* thievery */
661     npc->meleef = M_MELEE_NORMAL;
662     npc->dmg = competence;
663     npc->hit = competence;
664     npc->specialf=M_SP_THIEF;
665     npc->speed = 3;
666     break;
667   case 5: /* flee */
668     npc->dmg = competence;
669     npc->hit = competence;
670     npc->meleef = M_MELEE_NORMAL;
671     npc->specialf = M_MOVE_SCAREDY;
672     npc->speed = 3;
673     break;
674   }
675   if (npc->talkf == M_TALK_MAN)
676     switch (talktype) {
677     case 1: npc->talkf = M_TALK_EVIL; break;
678     case 2: npc->talkf = M_TALK_MAN; break;
679     case 3: npc->talkf = M_TALK_HINT; break;
680     case 4: npc->talkf = M_TALK_BEG; break;
681     case 5: npc->talkf = M_TALK_SILENT; break;
682     default: mprint("Say Whutt? (npc talk weirdness)"); break;
683     }
684   npc->uniqueness = UNIQUE_MADE;
685 }
686 
687 
688 /* makes an ordinary npc (maybe undead) */
make_log_npc(npc)689 void make_log_npc(npc)
690 struct monster *npc;
691 {
692   int i,n;
693   int behavior,status,level;
694   FILE *fd;
695 
696   /* in case the log file is null */
697   behavior = 2718;
698   level = 1;
699   status = 2;
700   strcpy(Str2,"Malaprop the Misnamed");
701 
702   strcpy(Str1,Omegalib);
703   strcat(Str1,"omega.log");
704   fd = checkfopen(Str1,"r");
705   n = 1;
706   while(fgets(Str1,STRING_LEN, fd)) {
707     if (random_range(n) == 0) {	/* this algo. from Knuth 2 - cute, eh? */
708       sscanf(Str1,"%d %d %d",&status,&level,&behavior);
709       for (i = 0; (Str1[i] < 'a' || Str1[i] > 'z') &&
710 	(Str1[i] < 'A' || Str1[i] > 'Z'); i++)
711 	;
712       strcpy(Str2, Str1 + i);
713       Str2[strlen(Str2) - 1] = '\0';	/* 'cos fgets reads in the \n */
714     }
715     n++;
716   }
717   fclose(fd);
718   npc->hp = level*20;
719   if (status==1) {
720     if (level < 3) {
721       *npc = Monsters[GHOST];
722       strcpy(Str1,"ghost named ");
723     }
724     else if (level < 7) {
725       *npc = Monsters[HAUNT];
726       strcpy(Str1,"haunt named ");
727     }
728     else if (level < 12) {
729       *npc = Monsters[SPECTRE];
730       strcpy(Str1,"spectre named ");
731     }
732     else {
733       *npc = Monsters[LICHE];
734       strcpy(Str1,"lich named ");
735     }
736     strcat(Str1,Str2);
737     npc->monstring = salloc(Str1);
738     strcpy(Str3,"the mortal remains of ");
739     strcat(Str3,Str2);
740     npc->corpsestr = salloc(Str3);
741   }
742   else {
743     npc->monstring=salloc(Str2);
744     strcpy(Str3,"the corpse of ");
745     strcat(Str3,Str2);
746     npc->corpsestr = salloc(Str3);
747   }
748   determine_npc_behavior(npc,level,behavior);
749 }
750 
751 
752 
753 
754 
m_trap_dart(m)755 void m_trap_dart(m)
756 struct monster *m;
757 {
758   if (los_p(m->x,m->y,Player.x,Player.y)) {
759     if (m->uniqueness != COMMON) strcpy(Str1,m->monstring);
760     else {
761       strcpy(Str1,"The ");
762       strcat(Str1,m->monstring);
763     }
764     strcat(Str1," was hit by a dart!");
765     mprint(Str1);
766     Level->site[m->x][m->y].locchar = TRAP;
767     lset(m->x, m->y, CHANGED);
768   }
769   m_damage(m,difficulty()*2,NORMAL_DAMAGE);
770 }
771 
m_trap_pit(m)772 void m_trap_pit(m)
773 struct monster *m;
774 {
775   if (los_p(m->x,m->y,Player.x,Player.y)) {
776     if (m->uniqueness != COMMON) strcpy(Str1,m->monstring);
777     else {
778       strcpy(Str1,"The ");
779       strcat(Str1,m->monstring);
780     }
781     strcat(Str1," fell into a pit!");
782     mprint(Str1);
783     Level->site[m->x][m->y].locchar = TRAP;
784     lset(m->x, m->y, CHANGED);
785   }
786   if (! m_statusp(m,INTANGIBLE))
787     m_status_reset(m,MOBILE);
788   m_damage(m,difficulty()*5,NORMAL_DAMAGE);
789 
790 }
791 
m_trap_door(m)792 void m_trap_door(m)
793 struct monster *m;
794 {
795   if (los_p(m->x,m->y,Player.x,Player.y)) {
796     if (m->uniqueness != COMMON) strcpy(Str1,m->monstring);
797     else {
798       strcpy(Str1,"The ");
799       strcat(Str1,m->monstring);
800     }
801     strcat(Str1," fell into a trap door!");
802     mprint(Str1);
803     Level->site[m->x][m->y].locchar = TRAP;
804     lset(m->x, m->y, CHANGED);
805   }
806   m_vanish(m);
807 }
808 
m_trap_abyss(m)809 void m_trap_abyss(m)
810 struct monster *m;
811 {
812   char Str1[80];
813   if (los_p(m->x,m->y,Player.x,Player.y)) {
814     if (m->uniqueness != COMMON) strcpy(Str1,m->monstring);
815     else {
816       strcpy(Str1,"The ");
817       strcat(Str1,m->monstring);
818     }
819     strcat(Str1," fell into the infinite abyss!");
820     mprint(Str1);
821     Level->site[m->x][m->y].locchar = ABYSS;
822     lset(m->x, m->y, CHANGED);
823     Level->site[m->x][m->y].p_locf = L_ABYSS;
824     lset(m->x, m->y, CHANGED);
825   }
826   setgamestatus(SUPPRESS_PRINTING);
827   m_vanish(m);
828   resetgamestatus(SUPPRESS_PRINTING);
829 }
830 
m_trap_snare(m)831 void m_trap_snare(m)
832 struct monster *m;
833 {
834   char Str1[80];
835   Level->site[m->x][m->y].locchar = TRAP;
836   lset(m->x, m->y, CHANGED);
837   if (los_p(m->x,m->y,Player.x,Player.y)) {
838     if (m->uniqueness != COMMON) strcpy(Str1,m->monstring);
839     else {
840       strcpy(Str1,"The ");
841       strcat(Str1,m->monstring);
842     }
843     strcat(Str1," was caught in a snare!");
844     mprint(Str1);
845   }
846   if (! m_statusp(m,INTANGIBLE)) m_status_reset(m,MOBILE);
847 }
848 
m_trap_blade(m)849 void m_trap_blade(m)
850 struct monster *m;
851 {
852   char Str1[80];
853   Level->site[m->x][m->y].locchar = TRAP;
854   lset(m->x, m->y, CHANGED);
855   if (los_p(m->x,m->y,Player.x,Player.y)) {
856     if (m->uniqueness != COMMON) strcpy(Str1,m->monstring);
857     else {
858       strcpy(Str1,"The ");
859       strcat(Str1,m->monstring);
860     }
861     strcat(Str1," was hit by a blade trap!");
862     mprint(Str1); }
863   m_damage(m,(difficulty()+1)*7-Player.defense,NORMAL_DAMAGE);
864 }
865 
m_trap_fire(m)866 void m_trap_fire(m)
867 struct monster *m;
868 {
869   char Str1[80];
870   Level->site[m->x][m->y].locchar = TRAP;
871   lset(m->x, m->y, CHANGED);
872   if (los_p(m->x,m->y,Player.x,Player.y)) {
873     if (m->uniqueness != COMMON) strcpy(Str1,m->monstring);
874     else {
875       strcpy(Str1,"The ");
876       strcat(Str1,m->monstring);
877     }
878     strcat(Str1," was hit by a fire trap!");
879     mprint(Str1);
880   }
881   m_damage(m,(difficulty()+1)*5,FLAME);
882 }
883 
884 
m_fire(m)885 void m_fire(m)
886 struct monster *m;
887 {
888   char Str1[80];
889   if (los_p(m->x,m->y,Player.x,Player.y)) {
890     if (m->uniqueness != COMMON) strcpy(Str1,m->monstring);
891     else {
892       strcpy(Str1,"The ");
893       strcat(Str1,m->monstring);
894     }
895     strcat(Str1," was blasted by fire!");
896     mprint(Str1);
897   }
898   m_damage(m,random_range(100),FLAME);
899 }
900 
m_trap_teleport(m)901 void m_trap_teleport(m)
902 struct monster *m;
903 {
904   char Str1[80];
905   Level->site[m->x][m->y].locchar = TRAP;
906   lset(m->x, m->y, CHANGED);
907   if (los_p(m->x,m->y,Player.x,Player.y)) {
908     if (m->uniqueness != COMMON) strcpy(Str1,m->monstring);
909     else {
910       strcpy(Str1,"The ");
911       strcat(Str1,m->monstring);
912     }
913     strcat(Str1," walked into a teleport trap!");
914     mprint(Str1);
915   }
916   m_teleport(m);
917 }
918 
m_trap_disintegrate(m)919 void m_trap_disintegrate(m)
920 struct monster *m;
921 {
922   char Str1[80];
923   if (los_p(m->x,m->y,Player.x,Player.y)) {
924     if (m->uniqueness != COMMON) strcpy(Str1,m->monstring);
925     else {
926       strcpy(Str1,"The ");
927       strcat(Str1,m->monstring);
928     }
929     strcat(Str1," walked into a disintegration trap!");
930     mprint(Str1);
931     Level->site[m->x][m->y].locchar = TRAP;
932     lset(m->x, m->y, CHANGED);
933   }
934   disintegrate(m->x,m->y);
935 }
936 
m_trap_sleepgas(m)937 void m_trap_sleepgas(m)
938 struct monster *m;
939 {
940   char Str1[80];
941   if (los_p(m->x,m->y,Player.x,Player.y)) {
942     if (m->uniqueness != COMMON) strcpy(Str1,m->monstring);
943     else {
944       strcpy(Str1,"The ");
945       strcat(Str1,m->monstring);
946     }
947     strcat(Str1," walked into a sleepgas trap!");
948     mprint(Str1);
949     Level->site[m->x][m->y].locchar = TRAP;
950     lset(m->x, m->y, CHANGED);
951   }
952   if (! m_immunityp(m,SLEEP)) m_status_reset(m,AWAKE);
953 }
954 
m_trap_acid(m)955 void m_trap_acid(m)
956 struct monster *m;
957 {
958   char Str1[80];
959   if (los_p(m->x,m->y,Player.x,Player.y)) {
960     if (m->uniqueness != COMMON) strcpy(Str1,m->monstring);
961     else {
962       strcpy(Str1,"The ");
963       strcat(Str1,m->monstring);
964     }
965     strcat(Str1," walked into an acid bath trap!");
966     mprint(Str1);
967     Level->site[m->x][m->y].locchar = TRAP;
968     lset(m->x, m->y, CHANGED);
969   }
970   m_damage(m,random_range(difficulty()*difficulty()),ACID);
971 }
972 
m_trap_manadrain(m)973 void m_trap_manadrain(m)
974 struct monster *m;
975 {
976   char Str1[80];
977   if (los_p(m->x,m->y,Player.x,Player.y)) {
978     if (m->uniqueness != COMMON) strcpy(Str1,m->monstring);
979     else {
980       strcpy(Str1,"The ");
981       strcat(Str1,m->monstring);
982     }
983     strcat(Str1," walked into a manadrain trap!");
984     mprint(Str1);
985     Level->site[m->x][m->y].locchar = TRAP;
986     lset(m->x, m->y, CHANGED);
987   }
988   if (m->specialf == M_SP_SPELL) m->specialf = M_NO_OP;
989 }
990 
991 
m_water(m)992 void m_water(m)
993 struct monster *m;
994 {
995   char Str1[80];
996   if ((! m_statusp(m,INTANGIBLE)) &&
997       (! m_statusp(m,SWIMMING)) &&
998       (! m_statusp(m,ONLYSWIM))) {
999     if (los_p(m->x,m->y,Player.x,Player.y)) {
1000     if (m->uniqueness != COMMON) strcpy(Str1,m->monstring);
1001     else {
1002       strcpy(Str1,"The ");
1003       strcat(Str1,m->monstring);
1004     }
1005       strcat(Str1," drowned!");
1006       mprint(Str1);
1007     }
1008     m_death(m);
1009   }
1010 }
1011 
1012 
m_abyss(m)1013 void m_abyss(m)
1014 struct monster *m;
1015 {
1016   char Str1[80];
1017   if (los_p(m->x,m->y,Player.x,Player.y)) {
1018     if (m->uniqueness != COMMON) strcpy(Str1,m->monstring);
1019     else {
1020       strcpy(Str1,"The ");
1021       strcat(Str1,m->monstring);
1022     }
1023     strcat(Str1," fell into the infinite abyss!");
1024     mprint(Str1);
1025   }
1026   m_vanish(m);
1027 }
1028 
1029 
1030 
m_lava(m)1031 void m_lava(m)
1032 struct monster *m;
1033 {
1034   char Str1[80];
1035   if ((! m_immunityp(m,FLAME)) ||
1036       ((! m_statusp(m,SWIMMING))&& (! m_statusp(m,ONLYSWIM)))) {
1037     if (los_p(m->x,m->y,Player.x,Player.y)) {
1038     if (m->uniqueness != COMMON) strcpy(Str1,m->monstring);
1039     else {
1040       strcpy(Str1,"The ");
1041       strcat(Str1,m->monstring);
1042     }
1043       strcat(Str1," died in a pool of lava!");
1044       mprint(Str1);
1045     }
1046     m_death(m);
1047   }
1048 }
1049 
m_altar(m)1050 void m_altar(m)
1051 struct monster *m;
1052 {
1053   int visible = view_los_p(Player.x,Player.y,m->x,m->y);
1054   int reaction = 0;
1055   int altar = Level->site[m->x][m->y].aux;
1056 
1057   if (visible) {
1058     if (m->uniqueness != COMMON) strcpy(Str1,m->monstring);
1059     else {
1060       strcpy(Str1,"The ");
1061       strcat(Str1,m->monstring);
1062     }
1063     strcat(Str1," walks next to an altar...");
1064     mprint(Str1);
1065   }
1066   if (!m_statusp(m, HOSTILE))
1067     reaction = 0;
1068   else if (m->id == HISCORE_NPC && m->aux2 == altar)
1069     reaction = 1;	/* high priest of same deity */
1070   else if ((m->id == ANGEL || m->id == HIGH_ANGEL || m->id == ARCHANGEL) &&
1071       m->aux1 == altar)
1072     reaction = 1;	/* angel of same deity */
1073   else if (altar == Player.patron)
1074     reaction = -1;	/* friendly deity will zap hostile monster */
1075   else if (((Player.patron == ODIN || Player.patron == ATHENA) &&
1076       (altar == SET || altar == HECATE)) ||
1077       ((Player.patron == SET || Player.patron == HECATE) &&
1078       (altar == ODIN || altar == ATHENA)))
1079     reaction = 1;	/* hostile deity will help hostile monster */
1080   switch (reaction) {
1081     case -1:
1082       if (visible) {
1083 	mprint("Your deity is angry!");
1084 	mprint("A bolt of godsfire strikes the monster....");
1085       }
1086       disrupt(m->x,m->y,Player.rank[PRIESTHOOD]*50);
1087       break;
1088     case 1:
1089       if (visible) {
1090 	mprint("The deity of the altar smiles on the monster....");
1091 	mprint("A shaft of light zaps the altar...");
1092       }
1093       m->hp = Monsters[m->id].hp*2;
1094       break;
1095     default:
1096       if (visible)
1097 	mprint("but nothing much seems to happen");
1098       break;
1099   }
1100 }
1101 
1102 
mantype()1103 char *mantype()
1104 {
1105   switch(random_range(20)) {
1106     case 0: return "janitor";
1107     case 1: return "beggar";
1108     case 2: return "barbarian";
1109     case 3: return "hairdresser";
1110     case 4: return "accountant";
1111     case 5: return "lawyer";
1112     case 6: return "indian chief";
1113     case 7: return "tinker";
1114     case 8: return "tailor";
1115     case 9: return "soldier";
1116     case 10: return "spy";
1117     case 11: return "doctor";
1118     case 12: return "miner";
1119     case 13: return "noble";
1120     case 14: return "serf";
1121     case 15: return "neer-do-well";
1122     case 16: return "vendor";
1123     case 17: return "dilettante";
1124     case 18: return "surveyor";
1125     default:
1126     case 19: return "jongleur";
1127   }
1128 }
1129 
1130 
strengthen_death(m)1131 void strengthen_death(m)
1132 struct monster *m;
1133 {
1134   pol ol = ((pol)checkmalloc(sizeof(oltype)));
1135   pob scythe = ((pob)checkmalloc(sizeof(objtype)));
1136 #ifdef MSDOS_SUPPORTED_ANTIQUE
1137   unsigned tmp;
1138 #endif
1139   m->xpv += min(10000,m->xpv+1000);
1140   m->hit += min(1000,m->hit+10);
1141   m->dmg = min(10000,m->dmg*2);
1142   m->ac += min(1000,m->ac+10);
1143   m->speed = max(m->speed-1,1);
1144   m->movef = M_MOVE_SMART;
1145 #ifndef MSDOS_SUPPORTED_ANTIQUE
1146   m->hp = min(100000,100+m->dmg*10);
1147 #else
1148   /* In order not to have to make the hp's into longs or unsigned,
1149      which would involve lots of changes, I'll make it max out at 30000. */
1150   tmp = 100+m->dmg*10;
1151   m->hp = (tmp > 30000) ? 30000 : tmp;
1152 #endif
1153   *scythe = Objects[WEAPONID+39];
1154   ol->thing = scythe;
1155   ol->next = NULL;
1156   m->possessions = ol;
1157 }
1158 
1159 
1160 
1161 
m_no_op(m)1162 void m_no_op(m)
1163 struct monster *m;
1164 {
1165 }
1166