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