1 #include <stdio.h>
2 #include <strings.h>
3
4 #include "handwave.h"
5 #include "internal.h"
6
7 static char bigbuf[2048];
8 static char bigbuf2[2048];
9
10 static void exec_monster_attack();
11
12 extern void InitBeing();
13
kuruk_name()14 void kuruk_name()
15 {
16 #define NUMKURUK (23)
17
18 static char kuruk_syl[NUMKURUK][5] = {"kur", "ak", "ral", "ki", "rel", "uk",
19 "kor", "kul", "kas", "lok", "luk", "las", "mak", "mok", "mas", "mos", "ga",
20 "tha", "gul", "lug", "mag", "mog", "ug"};
21
22 int ix, new, old=(-1);
23 int numsyl = random()%3+2;
24
25 strcpy(bigbuf, "");
26
27 for (ix=0; ix<numsyl; ix++) {
28 do
29 new = random()%NUMKURUK;
30 while (new==old);
31 strcat(bigbuf, kuruk_syl[new]);
32 old = new;
33 }
34
35 if (random()%3==0 && numsyl<4) {
36 strcat(bigbuf, " ");
37 numsyl = random()%3+1;
38 for (ix=0; ix<numsyl; ix++) {
39 do
40 new = random()%NUMKURUK;
41 while (new==old);
42 strcat(bigbuf, kuruk_syl[new]);
43 old = new;
44 }
45 }
46
47 for (ix=0; bigbuf[ix]; ix++)
48 if ((ix==0 || bigbuf[ix-1]==' ') && islower(bigbuf[ix]))
49 bigbuf[ix] = toupper(bigbuf[ix]);
50 }
51
snaffi_name()52 void snaffi_name()
53 {
54 #define NUMSNAFFI (18)
55
56 static char snaffi_syl[NUMSNAFFI][5] = {"sni", "sna", "fer", "fi", "fir",
57 "por", "per", "snu", "al", "an", "erl", "lep", "fru", "fri", "ig", "eg",
58 "thi", "tha"};
59
60 int ix, new, old=(-1);
61 int numsyl = random()%3+1;
62
63 strcpy(bigbuf, "");
64
65 for (ix=0; ix<numsyl; ix++) {
66 do
67 new = random()%NUMSNAFFI;
68 while (new==old);
69 strcat(bigbuf, snaffi_syl[new]);
70 old = new;
71 }
72
73 if (numsyl==1 || (random()%3==0 && numsyl<3)) {
74 strcat(bigbuf, " ");
75 numsyl = random()%2+1;
76 for (ix=0; ix<numsyl; ix++) {
77 do
78 new = random()%NUMSNAFFI;
79 while (new==old);
80 strcat(bigbuf, snaffi_syl[new]);
81 old = new;
82 }
83 }
84
85 for (ix=0; bigbuf[ix]; ix++)
86 if ((ix==0 || bigbuf[ix-1]==' ') && islower(bigbuf[ix]))
87 bigbuf[ix] = toupper(bigbuf[ix]);
88 }
89
create_creature(self,type,creator)90 void create_creature(self, type, creator)
91 struct realgame *self;
92 int type;
93 int creator;
94 {
95 struct creature *thud;
96
97 if (self->numcres+1 >= self->cre_size) {
98 self->cre_size *= 2;
99 self->cre = (struct creature *)realloc(self->cre, sizeof(struct creature) * self->cre_size);
100 }
101 thud = &self->cre[self->numcres];
102 self->numcres++;
103
104 InitBeing(thud);
105
106 thud->nocorpse = 0;
107 thud->gender = Gender_MALE;
108 thud->type = type;
109 thud->owner = creator;
110 thud->last_target = (-1);
111 thud->last_targettype = 0;
112 thud->nowm_spell = -1;
113
114 switch (type) {
115 case Creature_GOBLIN:
116 thud->max_hitpoints = 1;
117 snaffi_name();
118 strcat(bigbuf, " the Goblin");
119 break;
120 case Creature_OGRE:
121 thud->max_hitpoints = 2;
122 kuruk_name();
123 strcat(bigbuf, " the Ogre");
124 break;
125 case Creature_TROLL:
126 thud->max_hitpoints = 3;
127 kuruk_name();
128 strcat(bigbuf, " the Troll");
129 break;
130 case Creature_GIANT:
131 thud->max_hitpoints = 4;
132 kuruk_name();
133 strcat(bigbuf, " the Giant");
134 break;
135 case Creature_FIREL:
136 thud->max_hitpoints = 3;
137 thud->nocorpse = 1;
138 kuruk_name();
139 strcat(bigbuf, " the Fiery");
140 break;
141 case Creature_ICEL:
142 thud->max_hitpoints = 3;
143 thud->nocorpse = 1;
144 kuruk_name();
145 strcat(bigbuf, " the Icy");
146 break;
147 }
148 thud->hitpoints = thud->max_hitpoints;
149 thud->name = (char *)malloc(strlen(bigbuf)+1);
150 strcpy(thud->name, bigbuf);
151 }
152
execute_monsters(self)153 void execute_monsters(self)
154 struct realgame *self;
155 {
156 int ix, cx, jx, kx, numattacks, qtype, qnum;
157 int target, targettype;
158 struct creature *thud;
159
160 erase_queries(self);
161
162 for (ix=0; ix<self->numcres; ix++) {
163 thud = &(self->cre[ix]);
164 if (thud->alive) {
165 /* at this point, thud->haste is 5 if haste just cast this round;
166 3,2,1 if in effect; 4 if just cast but also previously in effect */
167 switch (self->turntype) {
168 case Turn_TIMESTOP:
169 if (thud->timestop==1)
170 numattacks = 1;
171 else
172 numattacks = 0;
173 break;
174 case Turn_NORMAL:
175 if (thud->haste>=1 && thud->haste<=4)
176 numattacks = 2;
177 else
178 numattacks = 1;
179 break;
180 default:
181 PrintMsg("ERROR: wrong type of turn in execute_monsters()\n");
182 break;
183 }
184 for (jx=0; jx<numattacks; jx++) {
185 if (thud->type==Creature_FIREL || thud->type==Creature_ICEL)
186 qtype = Qu_NoQuery;
187 else
188 qtype = Qu_MonsterTarget;
189
190 switch (thud->nowm_spell) {
191 case SP__CONFUSION:
192 qtype = Qu_NoQuery;
193 if (jx==0) {
194 sprintf(bigbuf, "%s suddenly looks confused.\n", thud->name);
195 PrintMsg(bigbuf);
196 }
197 break;
198 case SP__PARALYSIS:
199 qtype = Qu_NoQuery;
200 if (jx==0) {
201 sprintf(bigbuf, "%s is paralyzed and cannot attack.\n", thud->name);
202 PrintMsg(bigbuf);
203 }
204 break;
205 case SP__AMNESIA:
206 qtype = Qu_NoQuery;
207 if (jx==0) {
208 sprintf(bigbuf, "%s looks around blankly.\n", thud->name);
209 PrintMsg(bigbuf);
210 }
211 break;
212 default:
213 break;
214 }
215 if (thud->owner<0 || thud->owner>=self->numplayers ||
216 !self->wiz[thud->owner]->alive) {
217 qtype = Qu_NoQuery;
218 }
219
220 add_query(self, thud->owner, qtype, ix + 256*(jx+numattacks));
221 }
222 }
223 }
224 if (self->numqueries)
225 Queries(self->numqueries, self->querylist);
226
227 for (qnum=0; qnum<self->numqueries; qnum++) {
228 jx = (int)(self->querylist[qnum].rock);
229 numattacks = jx / 256;
230 ix = jx % 256;
231 thud = &(self->cre[ix]);
232 if (thud->type==Creature_FIREL || thud->type==Creature_ICEL) {
233 /* elementals are not affected by paralysis */
234 for (cx=0; cx<self->numplayers; cx++) {
235 if (self->wiz[cx]->alive)
236 exec_monster_attack(self, self->wiz[cx], cx, 1, thud);
237 }
238 for (cx=0; cx<self->numcres; cx++) {
239 if (self->cre[cx].alive)
240 exec_monster_attack(self, &self->cre[cx], cx, 0, thud);
241 }
242 }
243 else {
244 targettype = 0;
245 target = (-1);
246 if (thud->nowm_spell==SP__PARALYSIS) {
247 /* no attack */
248 targettype = 0;
249 }
250 else if (thud->nowm_spell==SP__CONFUSION) {
251 int numtwiz, numtcre;
252 if (thud->mind_caster==1 && thud->perm.mind_spell==SP__CONFUSION &&
253 thud->perm.mind_detail!=(-1)) {
254 /* grab from detail */
255 targettype = thud->perm.mind_detail & QuVal_Hand_MASK;
256 target = thud->perm.mind_detail & (~QuVal_Hand_MASK);
257 }
258 else {
259 /* grab randomly */
260 numtwiz = NumberOfTargets(self, QuVal_Target_Wizard);
261 numtcre = NumberOfTargets(self, QuVal_Target_Creature);
262 kx = random() % (numtwiz + numtcre);
263 if (kx<numtwiz) {
264 targettype = QuVal_Target_Wizard;
265 target = IndexOfTarget((game *)self, targettype, kx) &
266 (~QuVal_Target_MASK);
267 }
268 else {
269 targettype = QuVal_Target_Creature;
270 kx -= numtwiz;
271 target = IndexOfTarget((game *)self, targettype, kx) &
272 (~QuVal_Target_MASK);
273 }
274 }
275 if (thud->mind_caster==1 && thud->perm.mind_spell==SP__CONFUSION) {
276 /* set detail */
277 thud->perm.mind_detail = targettype | target;
278 }
279 }
280 else if (thud->nowm_spell==SP__AMNESIA) {
281 targettype = thud->last_targettype;
282 target = thud->last_target;
283 }
284 else {
285 int ival;
286 int tart = self->querylist[qnum].answer & QuVal_Target_MASK;
287 if (tart==0
288 || (thud->owner<0 || thud->owner>=self->numplayers ||
289 !self->wiz[thud->owner]->alive)) {
290 targettype = 0;
291 }
292 else {
293 kx = self->querylist[qnum].answer & (~QuVal_Target_MASK);
294 ival = IndexOfTarget((game *)self, tart, kx);
295 target = ival & (~QuVal_Target_MASK);
296 targettype = ival & QuVal_Target_MASK;
297 }
298 }
299 /*printf("### attack of %s: %d, %d\n", thud->name, targettype, target);*/
300 thud->last_targettype = targettype;
301 thud->last_target = target;
302 switch (targettype) {
303 case QuVal_Target_Wizard:
304 if (self->wiz[target]->alive)
305 exec_monster_attack(self, self->wiz[target], target, 1, thud);
306 break;
307 case QuVal_Target_Creature:
308 if (self->cre[target].alive)
309 exec_monster_attack(self, &self->cre[target], target, 0, thud);
310 break;
311 default:
312 break;
313 }
314 }
315 }
316
317 for (ix=0; ix<self->numcres; ix++) {
318 thud = &(self->cre[ix]);
319 if (thud->alive) {
320 /*printf("### cycling %s: %d => %d\n", thud->name, thud->mind_spell,
321 thud->nowm_spell);*/
322 if (self->turntype==Turn_TIMESTOP && !thud->timestop) {
323 /* do not cycle */
324 }
325 else {
326 thud->nowm_spell = thud->mind_spell;
327 thud->nowm_caster = thud->mind_caster;
328 thud->mind_spell = (-1);
329 thud->mind_caster = (-1);
330 }
331 }
332 }
333 }
334
exec_monster_attack(self,fred,cnum,wizflag,thud)335 static void exec_monster_attack(self, fred, cnum, wizflag, thud) /* dead not allowed */
336 struct realgame *self;
337 union being *fred;
338 int cnum;
339 int wizflag;
340 struct creature *thud;
341 {
342 int ix, jx;
343 int *zapl;
344
345 zapl = fred->both.zaplist;
346
347 if (fred==(union being *)thud) {
348 if (thud->type==Creature_FIREL || thud->type==Creature_ICEL) {
349 /* say nothing */
350 }
351 else {
352 sprintf(bigbuf, "%s refuses to attack %s.\n", thud->name,
353 pro_himself(fred->both.gender));
354 PrintMsg(bigbuf);
355 }
356 return;
357 }
358
359 if (!(thud->type==Creature_FIREL || thud->type==Creature_ICEL)
360 && fred->both.invisibility) {
361 sprintf(bigbuf, "%s tries to attack you, but cannot see you.\n", thud->name);
362 sprintf(bigbuf2, "%s tries to attack %s, but cannot see %s.\n", thud->name,
363 fred->both.name, pro_him(fred->both.gender));
364 if (wizflag)
365 PrintMsg2(cnum, bigbuf, bigbuf2);
366 else
367 PrintMsg(bigbuf2);
368 return;
369 }
370
371 if (zapl[SP__SHIELD]) {
372 sprintf(bigbuf, "The attack of %s is blocked by your Shield.\n", thud->name);
373 sprintf(bigbuf2, "The attack of %s is blocked by %s's Shield.\n", thud->name,
374 fred->both.name);
375 if (wizflag)
376 PrintMsg2(cnum, bigbuf, bigbuf2);
377 else
378 PrintMsg(bigbuf2);
379 return;
380 }
381
382 if (thud->type==Creature_FIREL) {
383 if (fred->both.fl_resist_heat) {
384 sprintf(bigbuf, "%s reaches towards you, but you feel only a warm breeze.\n",
385 thud->name);
386 sprintf(bigbuf2, "%s reaches toward %s, but cannot penetrate %s blue aura.\n",
387 thud->name, fred->both.name, pro_his(fred->both.gender));
388 if (wizflag)
389 PrintMsg2(cnum, bigbuf, bigbuf2);
390 else
391 PrintMsg(bigbuf2);
392 }
393 else {
394 sprintf(bigbuf, "%s hurls tongues of fire at you.\n", thud->name);
395 sprintf(bigbuf2, "%s hurls fire at %s.\n", thud->name, fred->both.name);
396 if (wizflag)
397 PrintMsg2(cnum, bigbuf, bigbuf2);
398 else
399 PrintMsg(bigbuf2);
400 fred->both.hitpoints -= 3;
401 }
402 }
403 else if (thud->type==Creature_ICEL) {
404 if (fred->both.fl_resist_cold) {
405 sprintf(bigbuf, "%s reaches towards you, but you feel only a chill breeze.\n",
406 thud->name);
407 sprintf(bigbuf2, "%s reaches toward %s, but cannot penetrate %s pink aura.\n",
408 thud->name, fred->both.name, pro_his(fred->both.gender));
409 if (wizflag)
410 PrintMsg2(cnum, bigbuf, bigbuf2);
411 else
412 PrintMsg(bigbuf2);
413 }
414 else {
415 sprintf(bigbuf, "%s hurls splinters of ice at you.\n", thud->name);
416 sprintf(bigbuf2, "%s hurls ice at %s.\n", thud->name, fred->both.name);
417 if (wizflag)
418 PrintMsg2(cnum, bigbuf, bigbuf2);
419 else
420 PrintMsg(bigbuf2);
421 fred->both.hitpoints -= 3;
422 }
423 }
424 else {
425 /* other creature types */
426 if (fred==(union being *)thud) {
427 sprintf(bigbuf, "%s attacks %s!\n", thud->name,
428 pro_himself(fred->both.gender));
429 PrintMsg(bigbuf);
430 }
431 else {
432 sprintf(bigbuf, "%s attacks you.\n", thud->name);
433 sprintf(bigbuf2, "%s attacks %s.\n", thud->name, fred->both.name);
434 if (wizflag)
435 PrintMsg2(cnum, bigbuf, bigbuf2);
436 else
437 PrintMsg(bigbuf2);
438 }
439 switch (thud->type) {
440 case Creature_GOBLIN:
441 fred->both.hitpoints -= 1;
442 break;
443 case Creature_OGRE:
444 fred->both.hitpoints -= 2;
445 break;
446 case Creature_TROLL:
447 fred->both.hitpoints -= 3;
448 break;
449 case Creature_GIANT:
450 fred->both.hitpoints -= 4;
451 break;
452 }
453 }
454 }
455