1 /* omega copyright (c) 1987,1988,1989 by Laurence Raphael Brothers */
2 /* mmelee */
3 /* various functions to do with monster melee */
4 
5 #include "glob.h"
6 
7 
m_hit(m,dtype)8 void m_hit(m,dtype)
9 struct monster *m;
10 int dtype;
11 {
12   if (m->uniqueness == COMMON) {
13     strcpy(Str3,"a ");
14     strcat(Str3,m->monstring);
15   }
16   else strcpy(Str3,m->monstring);
17   if ((Player.status[DISPLACED] > 0) && (random_range(2) == 1))
18     mprint("The attack was displaced!");
19   else  p_damage(random_range(m->dmg),dtype,Str3);
20 }
21 
22 
23 
24 /* execute monster attacks versus player */
tacmonster(m)25 void tacmonster(m)
26 struct monster *m;
27 {
28   int i=0;
29   drawvision(Player.x,Player.y);
30   transcribe_monster_actions(m);
31   while ((i < strlen(m->meleestr)) && (m->hp > 0)) {
32     if (m->uniqueness == COMMON) {
33       strcpy(Str4,"The ");
34       strcat(Str4,m->monstring);
35     }
36     else strcpy(Str4,m->monstring);
37     if (m->meleestr[i] == 'A') {
38       strcat(Str4," attacks ");
39       strcat(Str4,actionlocstr(m->meleestr[i+1]));
40       if (Verbosity == VERBOSE) mprint(Str4);
41       monster_melee(m,m->meleestr[i+1],0);
42     }
43     else if (m->meleestr[i] == 'L') {
44       strcat(Str4," lunges ");
45       strcat(Str4,actionlocstr(m->meleestr[i+1]));
46       if (Verbosity == VERBOSE) mprint(Str4);
47       monster_melee(m,m->meleestr[i+1],m->level);
48     }
49     i+=2;
50   }
51 }
52 
53 
54 
monster_melee(m,hitloc,bonus)55 void monster_melee(m,hitloc,bonus)
56 struct monster *m;
57 char hitloc;
58 int bonus;
59 {
60   if (player_on_sanctuary())
61     print1("The aegis of your deity protects you!");
62   else {
63     /* It's lawful to wait to be attacked */
64     if (m->attacked==0) Player.alignment++;
65     m->attacked++;
66     if (m->uniqueness == COMMON) {
67       strcpy(Str2,"The ");
68       strcat(Str2,m->monstring);
69     }
70     else strcpy(Str2,m->monstring);
71     if (monster_hit(m,hitloc,bonus))
72       switch(m->meleef) {
73       case M_NO_OP:
74 	strcat(Str2," touches you.");
75 	mprint(Str2);
76 	break;
77       case M_MELEE_NORMAL:
78 	strcat(Str2," hits you.");
79 	mprint(Str2);
80 	m_hit(m,NORMAL_DAMAGE);
81 	break;
82       case M_MELEE_NG:
83 	strcat(Str2," hits you.");
84 	mprint(Str2);
85 	m_hit(m,NORMAL_DAMAGE);
86 	if (random_range(5)==3) m_sp_ng(m);
87 	break;
88       case M_MELEE_FIRE:
89 	strcat(Str2," blasts you with fire.");
90 	mprint(Str2);
91 	m_hit(m,FLAME);
92 	break;
93       case M_MELEE_DRAGON:
94 	strcat(Str2," hits you and blasts you with fire.");
95 	mprint(Str2);
96 	m_hit(m,NORMAL_DAMAGE);
97 	m_hit(m,FLAME);
98 	break;
99       case M_MELEE_ELEC:
100 	strcat(Str2," lashes you with electricity.");
101 	mprint(Str2);
102 	m_hit(m,ELECTRICITY);
103 	break;
104       case M_MELEE_COLD:
105 	strcat(Str2," freezes you with cold.");
106 	mprint(Str2);
107 	m_hit(m,ELECTRICITY);
108 	break;
109       case M_MELEE_POISON:
110 	strcat(Str2," hits you.");
111 	mprint(Str2);
112 	m_hit(m,NORMAL_DAMAGE);
113 	if (random_range(10) < m->level) {
114 	  mprint("You've been poisoned!");
115 	  p_poison(m->dmg);
116 	}
117 	break;
118       case M_MELEE_GRAPPLE:
119 	strcat(Str2," grabs you.");
120 	mprint(Str2);
121 	m_hit(m,NORMAL_DAMAGE);
122 	Player.status[IMMOBILE]++;
123 	break;
124       case M_MELEE_SPIRIT:
125 	strcat(Str2," touches you.");
126 	mprint(Str2);
127 	m_hit(m,NORMAL_DAMAGE);
128 	drain_life(m->level);
129 	break;
130       case M_MELEE_DISEASE:
131 	strcat(Str2," hits you.");
132 	mprint(Str2);
133 	m_hit(m,NORMAL_DAMAGE);
134 	if (random_range(10) < m->level) {
135 	  mprint("You've been infected!");
136 	  disease(m->level);
137 	}
138 	break;
139       case M_MELEE_SLEEP:
140 	strcat(Str2," hit you.");
141 	mprint(Str2);
142 	m_hit(m,NORMAL_DAMAGE);
143 	if (random_range(10) < m->level) {
144 	  mprint("You feel drowsy");
145 	  sleep_player(m->level);
146 	}
147 	break;
148       }
149     else {
150       if (random_range(10)) strcat(Str2," missed you.");
151       else {
152 	if (Verbosity == TERSE) {
153 	  switch(random_range(10)) {
154 	    case 0:
155 	      strcat(Str2," blundered severely.");
156 	      m_damage(m,m->dmg,UNSTOPPABLE); break;
157 	    case 1:
158 	      strcat(Str2," tripped while attacking.");m_dropstuff(m);break;
159 	    case 2:
160 	      strcat(Str2," seems seriously confused.");
161 	      m->speed = min(30,m->speed*2); break;
162 	    default:
163 	      strcat(Str2," missed you.");
164 	  }
165 	}
166 	switch(random_range(10)) {
167 	  case 0: strcat(Str2," flailed stupidly at you."); break;
168 	  case 1: strcat(Str2," made you laugh."); break;
169 	  case 2: strcat(Str2," blundered severely.");
170 	    m_damage(m,m->dmg,UNSTOPPABLE); break;
171 	  case 3: strcat(Str2," tripped while attacking.");m_dropstuff(m);break;
172 	  case 4: strcat(Str2," seems seriously confused.");
173 	    m->speed = min(30,m->speed*2); break;
174 	  case 5: strcat(Str2," is seriously ashamed."); break;
175 	  case 6: strcat(Str2," made a boo-boo."); break;
176 	  case 7: strcat(Str2," blundered."); break;
177 	  case 8: strcat(Str2," cries out in anger and frustration."); break;
178 	  case 9: strcat(Str2," curses your ancestry."); break;
179 	}
180       }
181       mprint(Str2);
182     }
183   }
184 }
185 
186 
187 
188 /* checks to see if player hits with hitmod vs. monster m at location hitloc */
monster_hit(m,hitloc,bonus)189 int monster_hit(m,hitloc,bonus)
190 struct monster *m;
191 char hitloc;
192 int bonus;
193 {
194   int i=0,blocks=FALSE,goodblocks=0,hit,riposte=FALSE;
195   while (i<strlen(Player.meleestr)) {
196     if ((Player.meleestr[i] == 'B') || (Player.meleestr[i] == 'R')) {
197       blocks = TRUE;
198       if (hitloc == Player.meleestr[i+1]) {
199 	goodblocks++;
200 	if (Player.meleestr[i] == 'R') riposte = TRUE;
201       }
202     }
203     i+=2;
204   }
205   if (! blocks) goodblocks = -1;
206   hit = hitp(m->hit+bonus,Player.defense+goodblocks*10);
207   if ((! hit) && (goodblocks > 0)) {
208     if (Verbosity == VERBOSE) mprint("You blocked it!");
209     if (riposte) {
210       if (Verbosity != TERSE) mprint("You got a riposte!");
211       if (hitp(Player.hit,m->ac)) {
212 	mprint("You hit!");
213 	weapon_use(0,Player.possessions[O_WEAPON_HAND],m);
214       }
215       else mprint("You missed.");
216     }
217   }
218   return(hit);
219 }
220 
221 
222 
223 /* decide monster actions in tactical combat mode */
224 /* if monster is skilled, it can try see the player's attacks coming and
225    try to block appropriately. */
226 
transcribe_monster_actions(m)227 void transcribe_monster_actions(m)
228 struct monster *m;
229 {
230   int i;
231   char attack_loc,block_loc;
232   static char mmstr[80];
233 
234   int p_blocks[3];
235   int p_attacks[3];
236 
237   for(i=0;i<3;i++)p_blocks[i] = p_attacks[i] = 0;
238 
239   /* Find which area player blocks and attacks least in */
240   i = 0;
241   while (i<strlen(Player.meleestr)) {
242     if ((Player.meleestr[i] == 'B') ||
243 	(Player.meleestr[i] == 'R')) {
244       if (Player.meleestr[i+1] == 'H') p_blocks[0]++;
245       if (Player.meleestr[i+1] == 'C') p_blocks[1]++;
246       if (Player.meleestr[i+1] == 'L') p_blocks[2]++;
247     }
248     else if ((Player.meleestr[i] == 'A') ||
249 	     (Player.meleestr[i] == 'L')) {
250       if (Player.meleestr[i+1] == 'H') p_attacks[0]++;
251       if (Player.meleestr[i+1] == 'C') p_attacks[1]++;
252       if (Player.meleestr[i+1] == 'L') p_attacks[2]++;
253     }
254     i+=2;
255   }
256 
257   if ((p_blocks[2] <= p_blocks[1]) &&
258       (p_blocks[2] <= p_blocks[0]))
259     attack_loc = 'L';
260   else if ((p_blocks[1] <= p_blocks[2]) &&
261 	   (p_blocks[1] <= p_blocks[0]))
262     attack_loc = 'C'; /* DG 12/31/98 */
263   else attack_loc = 'H';
264   if ((p_attacks[2] <= p_attacks[1]) &&
265       (p_attacks[2] <= p_attacks[0]))
266     block_loc = 'L';
267   else if ((p_attacks[1] <= p_attacks[2]) &&
268 	   (p_attacks[1] <= p_attacks[0]))
269     block_loc = 'C';
270   else block_loc = 'H';
271 
272   m->meleestr = mmstr;
273 
274   if (m->id != NPC)
275     strcpy(m->meleestr,Monsters[m->id].meleestr);
276   else {
277     strcpy(m->meleestr,"");
278     for(i=0;i<m->level;i+=2)
279       strcat(m->meleestr,"L?R?");
280   }
281 
282   i = 0;
283   while (i<strlen(m->meleestr)) {
284     if ((m->meleestr[i] == 'A') || (m->meleestr[i] == 'L')) {
285       if (m->meleestr[i+1] == '?') {
286 	if (m->level+random_range(30) > Player.level+random_range(20))
287 	  m->meleestr[i+1] = attack_loc;
288 	else m->meleestr[i+1] = random_loc();
289       }
290       else if (m->meleestr[i+1] == 'X') m->meleestr[i+1] = random_loc();
291     }
292     else if ((m->meleestr[i] == 'B') || (m->meleestr[i] == 'R')) {
293       if (m->meleestr[i+1] == '?') {
294 	if (m->level+random_range(30) > Player.level+random_range(20))
295 	  m->meleestr[i+1] = block_loc;
296 	else m->meleestr[i+1] = random_loc();
297       }
298       else if (m->meleestr[i+1] == 'X') m->meleestr[i+1] = random_loc();
299     }
300     i+=2;
301   }
302 }
303 
random_loc()304 char random_loc()
305 {
306   switch(random_range(3)) {
307   case 0:return('H');
308   case 1:return('C');
309   default:return('L');
310   }
311 }
312