1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "common/random.h"
24 
25 #include "hdb/hdb.h"
26 #include "hdb/ai.h"
27 #include "hdb/ai-player.h"
28 #include "hdb/file-manager.h"
29 #include "hdb/gfx.h"
30 #include "hdb/sound.h"
31 #include "hdb/menu.h"
32 #include "hdb/lua-script.h"
33 #include "hdb/map.h"
34 #include "hdb/mpc.h"
35 #include "hdb/window.h"
36 
37 namespace HDB {
38 
aiPlayerInit(AIEntity * e)39 void aiPlayerInit(AIEntity *e) {
40 	g_hdb->_ai->clearInventory();
41 	e->aiAction = aiPlayerAction;
42 	e->draw = g_hdb->_ai->getStandFrameDir(e);
43 
44 	switch (e->dir) {
45 	case DIR_UP:
46 		e->state = STATE_STANDUP;
47 		break;
48 	case DIR_DOWN:
49 		e->state = STATE_STANDDOWN;
50 		break;
51 	case DIR_LEFT:
52 		e->state = STATE_STANDLEFT;
53 		break;
54 	case DIR_RIGHT:
55 		e->state = STATE_STANDRIGHT;
56 		break;
57 	case DIR_NONE:
58 		break;
59 	}
60 
61 	e->moveSpeed = kPlayerMoveSpeed;
62 	strcpy(e->entityName, "player");
63 	g_hdb->_ai->assignPlayer(e);
64 }
65 
aiPlayerInit2(AIEntity * e)66 void aiPlayerInit2(AIEntity *e) {
67 	if (!g_hdb->_ai->_clubUpGfx[0]) {
68 		g_hdb->_ai->_weaponSelGfx = g_hdb->_gfx->loadTile(TILE_WEAPON_EQUIPPED);
69 		g_hdb->_ai->_clubUpGfx[0] = g_hdb->_gfx->getPicGfx(CLUBUP1, -1);
70 		g_hdb->_ai->_clubUpGfx[1] = g_hdb->_gfx->getPicGfx(CLUBUP2, -1);
71 		g_hdb->_ai->_clubUpGfx[2] = g_hdb->_gfx->getPicGfx(CLUBUP3, -1);
72 		g_hdb->_ai->_clubUpGfx[3] = g_hdb->_gfx->getPicGfx(CLUBUP3, -1);
73 
74 		g_hdb->_ai->_clubDownGfx[0] = g_hdb->_gfx->getPicGfx(CLUBDOWN1, -1);
75 		g_hdb->_ai->_clubDownGfx[1] = g_hdb->_gfx->getPicGfx(CLUBDOWN2, -1);
76 		g_hdb->_ai->_clubDownGfx[2] = g_hdb->_gfx->getPicGfx(CLUBDOWN3, -1);
77 		g_hdb->_ai->_clubDownGfx[3] = g_hdb->_gfx->getPicGfx(CLUBDOWN3, -1);
78 
79 		g_hdb->_ai->_clubLeftGfx[0] = g_hdb->_gfx->getPicGfx(CLUBLEFT1, -1);
80 		g_hdb->_ai->_clubLeftGfx[1] = g_hdb->_gfx->getPicGfx(CLUBLEFT2, -1);
81 		g_hdb->_ai->_clubLeftGfx[2] = g_hdb->_gfx->getPicGfx(CLUBLEFT3, -1);
82 		g_hdb->_ai->_clubLeftGfx[3] = g_hdb->_gfx->getPicGfx(CLUBLEFT3, -1);
83 
84 		g_hdb->_ai->_clubRightGfx[0] = g_hdb->_gfx->getPicGfx(CLUBRIGHT1, -1);
85 		g_hdb->_ai->_clubRightGfx[1] = g_hdb->_gfx->getPicGfx(CLUBRIGHT2, -1);
86 		g_hdb->_ai->_clubRightGfx[2] = g_hdb->_gfx->getPicGfx(CLUBRIGHT3, -1);
87 		g_hdb->_ai->_clubRightGfx[3] = g_hdb->_gfx->getPicGfx(CLUBRIGHT3, -1);
88 
89 		g_hdb->_ai->_clubUpFrames = g_hdb->_ai->_clubDownFrames =
90 			g_hdb->_ai->_clubLeftFrames = g_hdb->_ai->_clubRightFrames = 4;
91 
92 		g_hdb->_ai->_slugAttackGfx[0] = g_hdb->_gfx->loadPic(SLUG_SHOT1);
93 		g_hdb->_ai->_slugAttackGfx[1] = g_hdb->_gfx->loadPic(SLUG_SHOT2);
94 		g_hdb->_ai->_slugAttackGfx[2] = g_hdb->_gfx->loadPic(SLUG_SHOT3);
95 		g_hdb->_ai->_slugAttackGfx[3] = g_hdb->_gfx->loadPic(SLUG_SHOT4);
96 
97 		int32 size = g_hdb->_fileMan->getLength("shock_spark_sit01", TYPE_TILE32);
98 		g_hdb->_ai->_stunLightningGfx[0] = g_hdb->_gfx->getTileGfx("shock_spark_sit01", size);
99 		size = g_hdb->_fileMan->getLength("shock_spark_sit02", TYPE_TILE32);
100 		g_hdb->_ai->_stunLightningGfx[1] = g_hdb->_gfx->getTileGfx("shock_spark_sit02", size);
101 		size = g_hdb->_fileMan->getLength("shock_spark_sit03", TYPE_TILE32);
102 		g_hdb->_ai->_stunLightningGfx[2] = g_hdb->_gfx->getTileGfx("shock_spark_sit03", size);
103 		size = g_hdb->_fileMan->getLength("shock_spark_sit04", TYPE_TILE32);
104 		g_hdb->_ai->_stunLightningGfx[3] = g_hdb->_gfx->getTileGfx("shock_spark_sit04", size);
105 
106 		size = g_hdb->_fileMan->getLength("starstun_sit01", TYPE_TILE32);
107 		g_hdb->_ai->_stunnedGfx[0] = g_hdb->_gfx->getTileGfx("starstun_sit01", size);
108 		size = g_hdb->_fileMan->getLength("starstun_sit02", TYPE_TILE32);
109 		g_hdb->_ai->_stunnedGfx[1] = g_hdb->_gfx->getTileGfx("starstun_sit02", size);
110 		size = g_hdb->_fileMan->getLength("starstun_sit03", TYPE_TILE32);
111 		g_hdb->_ai->_stunnedGfx[2] = g_hdb->_gfx->getTileGfx("starstun_sit03", size);
112 		size = g_hdb->_fileMan->getLength("starstun_sit04", TYPE_TILE32);
113 		g_hdb->_ai->_stunnedGfx[3] = g_hdb->_gfx->getTileGfx("starstun_sit04", size);
114 	}
115 
116 	e->draw = g_hdb->_ai->getStandFrameDir(e);
117 }
118 
aiPlayerAction(AIEntity * e)119 void aiPlayerAction(AIEntity *e) {
120 	static const AIState stand[5] = {STATE_NONE, STATE_STANDUP, STATE_STANDDOWN, STATE_STANDLEFT, STATE_STANDRIGHT};
121 	static const int xvAhead[5] = {9, 0, 0, -1, 1};
122 	static const int yvAhead[5] = {9, -1, 1, 0, 0};
123 
124 	AIEntity *hit = NULL;
125 
126 	// Draw the STUN lightning if it exists
127 	if (e->sequence) {
128 		e->aiDraw = aiPlayerDraw;
129 		g_hdb->_sound->playSound(SND_STUNNER_FIRE);
130 		hit = g_hdb->_ai->findEntity(e->tileX + xvAhead[e->dir], e->tileY + yvAhead[e->dir]);
131 		if (hit)
132 			switch (hit->type) {
133 			case AI_MEERKAT:
134 				if (hit->sequence > 2)
135 					g_hdb->_ai->stunEnemy(hit, 8);
136 				break;
137 			case AI_ICEPUFF:
138 				if (hit->state == STATE_ICEP_APPEAR || hit->state == STATE_ICEP_THROWDOWN || hit->state == STATE_ICEP_THROWLEFT || hit->state == STATE_ICEP_THROWRIGHT) {
139 					g_hdb->_ai->addAnimateTarget(hit->x, hit->y, 0, 3, ANIM_NORMAL, false, false, GROUP_STEAM_PUFF_SIT);
140 					g_hdb->_ai->stunEnemy(hit, 8);
141 				}
142 				break;
143 			case AI_BADFAIRY:
144 			case AI_GOODFAIRY:
145 			case AI_CHICKEN:
146 			case AI_OMNIBOT:
147 			case AI_TURNBOT:
148 			case AI_PUSHBOT:
149 			case AI_DEADEYE:
150 			case AI_FATFROG:
151 			case AI_BUZZFLY:
152 			case AI_MAINTBOT:
153 			case AI_RIGHTBOT:
154 			case AI_GATEPUDDLE:
155 				g_hdb->_ai->stunEnemy(hit, 8);
156 				break;
157 			default:
158 				break;
159 			}
160 
161 		hit = g_hdb->_ai->findEntity(e->tileX + (xvAhead[e->dir] << 1), e->tileY + (yvAhead[e->dir] << 1));
162 		if (hit)
163 			switch (hit->type) {
164 			case AI_MEERKAT:
165 				if (hit->sequence > 2)
166 					g_hdb->_ai->stunEnemy(hit, 8);
167 				break;
168 			case AI_ICEPUFF:
169 				if (hit->state == STATE_ICEP_APPEAR || hit->state == STATE_ICEP_THROWDOWN || hit->state == STATE_ICEP_THROWLEFT || hit->state == STATE_ICEP_THROWRIGHT) {
170 					g_hdb->_ai->addAnimateTarget(hit->x, hit->y, 0, 3, ANIM_NORMAL, false, false, GROUP_STEAM_PUFF_SIT);
171 					g_hdb->_ai->stunEnemy(hit, 8);
172 				}
173 				break;
174 			case AI_BADFAIRY:
175 			case AI_GOODFAIRY:
176 			case AI_CHICKEN:
177 			case AI_OMNIBOT:
178 			case AI_TURNBOT:
179 			case AI_PUSHBOT:
180 			case AI_DEADEYE:
181 			case AI_FATFROG:
182 			case AI_BUZZFLY:
183 			case AI_MAINTBOT:
184 			case AI_RIGHTBOT:
185 			case AI_GATEPUDDLE:
186 				g_hdb->_ai->stunEnemy(hit, 8);
187 				break;
188 			default:
189 				break;
190 			}
191 	}
192 
193 	int xOff[] = {0, 0, -8,-16};
194 	int yOff[] = {-8,-24,-16,-16};
195 	// If the player is supposed to animate for abit, check for it here
196 	switch (e->state) {
197 	case STATE_GRABUP:
198 	case STATE_GRABDOWN:
199 	case STATE_GRABLEFT:
200 	case STATE_GRABRIGHT:
201 		if (!e->animFrame--) {
202 			// Done with the Grabbing Animation, switch to standing
203 			switch (e->state) {
204 			case STATE_GRABUP:
205 				e->draw = e->standupGfx[0];
206 				e->state = STATE_STANDUP;
207 				break;
208 			case STATE_GRABDOWN:
209 				e->draw = e->standdownGfx[0];
210 				e->state = STATE_STANDDOWN;
211 				break;
212 			case STATE_GRABLEFT:
213 				e->draw = e->standleftGfx[0];
214 				e->state = STATE_STANDLEFT;
215 				break;
216 			case STATE_GRABRIGHT:
217 				e->draw = e->standrightGfx[0];
218 				e->state = STATE_STANDRIGHT;
219 				break;
220 			default:
221 				break;
222 			}
223 			e->animDelay = 1;
224 			e->animCycle = 1;
225 		}
226 		break;
227 	case STATE_ATK_CLUB_UP:
228 	case STATE_ATK_CLUB_DOWN:
229 	case STATE_ATK_CLUB_LEFT:
230 	case STATE_ATK_CLUB_RIGHT:
231 		g_hdb->_ai->setPlayerInvisible(true);
232 		e->aiDraw = aiPlayerDraw;
233 		e->drawXOff = xOff[e->state - STATE_ATK_CLUB_UP];
234 		e->drawYOff = yOff[e->state - STATE_ATK_CLUB_UP];
235 		switch (e->state) {
236 		case STATE_ATK_CLUB_UP:
237 			cycleFrames(e, g_hdb->_ai->_clubUpFrames);
238 			break;
239 		case STATE_ATK_CLUB_DOWN:
240 			cycleFrames(e, g_hdb->_ai->_clubDownFrames);
241 			break;
242 		case STATE_ATK_CLUB_LEFT:
243 			cycleFrames(e, g_hdb->_ai->_clubLeftFrames);
244 			break;
245 		case STATE_ATK_CLUB_RIGHT:
246 			cycleFrames(e, g_hdb->_ai->_clubRightFrames);
247 			break;
248 		default:
249 			break;
250 		}
251 		// Whack!
252 		if ((e->animFrame >= 1) && (e->animDelay == e->animCycle)) {
253 			switch (e->dir) {
254 			case DIR_UP:
255 				hit = g_hdb->_ai->playerCollision(32, 0, 16, 16);
256 				break;
257 			case DIR_DOWN:
258 				hit = g_hdb->_ai->playerCollision(0, 32, 16, 16);
259 				break;
260 			case DIR_LEFT:
261 				hit = g_hdb->_ai->playerCollision(16, 16, 32, 0);
262 				break;
263 			case DIR_RIGHT:
264 				hit = g_hdb->_ai->playerCollision(16, 16, 0, 32);
265 				break;
266 			default:
267 				break;
268 			}
269 
270 			if (hit && hit->level == e->level && !hit->stunnedWait) {
271 				switch (hit->type) {
272 				case AI_MEERKAT:
273 					if (hit->sequence > 2)		// out of the ground?
274 						g_hdb->_ai->stunEnemy(hit, 2);
275 					break;
276 				case AI_ICEPUFF:
277 					if (hit->state == STATE_ICEP_APPEAR ||
278 						hit->state == STATE_ICEP_THROWDOWN ||
279 						hit->state == STATE_ICEP_THROWLEFT ||
280 						hit->state == STATE_ICEP_THROWRIGHT)
281 						g_hdb->_ai->stunEnemy(hit, 2);
282 					break;
283 				case AI_CHICKEN:
284 					g_hdb->_ai->addAnimateTarget(hit->x, hit->y, 0, 3, ANIM_NORMAL, false, false, GROUP_STEAM_PUFF_SIT);
285 					g_hdb->_ai->removeEntity(hit);
286 					break;
287 				case AI_BADFAIRY:
288 				case AI_GOODFAIRY:
289 				case AI_OMNIBOT:
290 				case AI_TURNBOT:
291 				case AI_PUSHBOT:
292 				case AI_DEADEYE:
293 				case AI_FATFROG:
294 				case AI_BUZZFLY:
295 				case AI_MAINTBOT:
296 				case AI_RIGHTBOT:
297 				case AI_SHOCKBOT:
298 				case AI_GATEPUDDLE:
299 					g_hdb->_ai->stunEnemy(hit, 2);
300 					g_hdb->_sound->playSound(g_hdb->_ai->metalOrFleshSND(hit));
301 					break;
302 				default:
303 					break;
304 				}
305 			}
306 		}
307 		if ((!e->animFrame) && (e->animDelay == e->animCycle)) {
308 			e->state = stand[e->dir];
309 			e->aiDraw = NULL;
310 			switch (e->state) {
311 			case STATE_ATK_CLUB_UP:
312 				e->draw = e->standupGfx[0];
313 				break;
314 			case STATE_ATK_CLUB_DOWN:
315 				e->draw = e->standdownGfx[0];
316 				break;
317 			case STATE_ATK_CLUB_LEFT:
318 				e->draw = e->standleftGfx[0];
319 				break;
320 			case STATE_ATK_CLUB_RIGHT:
321 				e->draw = e->standrightGfx[0];
322 				break;
323 			default:
324 				break;
325 			}
326 			g_hdb->_ai->setPlayerInvisible(false);
327 			e->drawXOff = e->drawYOff = 0;
328 		}
329 		return;
330 	case STATE_ATK_STUN_UP:
331 		e->draw = g_hdb->_ai->_stunUpGfx[e->animFrame];
332 		cycleFrames(e, g_hdb->_ai->_stunUpFrames);
333 		if (!e->animFrame && e->animDelay == e->animCycle) {
334 			e->state = stand[e->dir];
335 			e->aiDraw = NULL;
336 			e->sequence = 0;
337 		}
338 		return;
339 	case STATE_ATK_STUN_DOWN:
340 		e->draw = g_hdb->_ai->_stunDownGfx[e->animFrame];
341 		cycleFrames(e, g_hdb->_ai->_stunDownFrames);
342 		if (!e->animFrame && e->animDelay == e->animCycle) {
343 			e->state = stand[e->dir];
344 			e->aiDraw = NULL;
345 			e->sequence = 0;
346 		}
347 		return;
348 	case STATE_ATK_STUN_LEFT:
349 		e->draw = g_hdb->_ai->_stunLeftGfx[e->animFrame];
350 		cycleFrames(e, g_hdb->_ai->_stunLeftFrames);
351 		if (!e->animFrame && e->animDelay == e->animCycle) {
352 			e->state = stand[e->dir];
353 			e->aiDraw = NULL;
354 			e->sequence = 0;
355 		}
356 		return;
357 	case STATE_ATK_STUN_RIGHT:
358 		e->draw = g_hdb->_ai->_stunRightGfx[e->animFrame];
359 		cycleFrames(e, g_hdb->_ai->_stunRightFrames);
360 		if (!e->animFrame && e->animDelay == e->animCycle) {
361 			e->state = stand[e->dir];
362 			e->aiDraw = NULL;
363 			e->sequence = 0;
364 		}
365 		return;
366 	case STATE_ATK_SLUG_UP:
367 		e->draw = g_hdb->_ai->_slugUpGfx[e->animFrame];
368 		cycleFrames(e, g_hdb->_ai->_slugUpFrames);
369 		if (!e->animFrame && e->animDelay == e->animCycle) {
370 			e->state = stand[e->dir];
371 			e->sequence = 0;
372 		}
373 		return;
374 	case STATE_ATK_SLUG_DOWN:
375 		e->draw = g_hdb->_ai->_slugDownGfx[e->animFrame];
376 		cycleFrames(e, g_hdb->_ai->_slugDownFrames);
377 		if (!e->animFrame && e->animDelay == e->animCycle) {
378 			e->state = stand[e->dir];
379 			e->sequence = 0;
380 		}
381 		return;
382 	case STATE_ATK_SLUG_LEFT:
383 		e->draw = g_hdb->_ai->_slugLeftGfx[e->animFrame];
384 		cycleFrames(e, g_hdb->_ai->_slugLeftFrames);
385 		if (!e->animFrame && e->animDelay == e->animCycle) {
386 			e->state = stand[e->dir];
387 			e->sequence = 0;
388 		}
389 		return;
390 	case STATE_ATK_SLUG_RIGHT:
391 		e->draw = g_hdb->_ai->_slugRightGfx[e->animFrame];
392 		cycleFrames(e, g_hdb->_ai->_slugRightFrames);
393 		if (!e->animFrame && e->animDelay == e->animCycle) {
394 			e->state = stand[e->dir];
395 			e->sequence = 0;
396 		}
397 		return;
398 	default:
399 		break;
400 	}
401 
402 	// If the touchplate wait is on, keep it timing
403 	if (e->touchpWait) {
404 		e->touchpWait--;
405 		if (!e->touchpWait)
406 			e->touchpTile = -e->touchpTile;
407 	} else if (e->touchpTile < 0 && (e->touchpX != e->tileX || e->touchpY != e->tileY)) {
408 		g_hdb->_ai->checkActionList(e, e->touchpX, e->touchpY, false);
409 		g_hdb->_map->setMapBGTileIndex(e->touchpX, e->touchpY, -e->touchpTile);
410 		e->touchpX = e->touchpY = e->touchpTile = 0;
411 	}
412 
413 	// If the player is moving somewhere, animate him
414 	int bgFlags, fgFlags;
415 	if (e->goalX) {
416 		if (onEvenTile(e->x, e->y)) {
417 			g_hdb->_ai->playerOnIce() ? g_hdb->_sound->playSound(SND_STEPS_ICE) : g_hdb->_sound->playSound(SND_FOOTSTEPS);
418 
419 			// Did we just fall down a PLUMMET?
420 			bgFlags = g_hdb->_map->getMapBGTileFlags(e->tileX, e->tileY);
421 			fgFlags = g_hdb->_map->getMapFGTileFlags(e->tileX, e->tileY);
422 			if ((bgFlags & kFlagPlummet) && !(fgFlags & kFlagGrating) && !g_hdb->_ai->playerDead()) {
423 				g_hdb->_ai->killPlayer(DEATH_PLUMMET);
424 				g_hdb->_ai->animEntFrames(e);
425 				return;
426 			}
427 		}
428 		g_hdb->_ai->animateEntity(e);
429 	} else {
430 		// Sometimes the fading stays black
431 		if (!g_hdb->_ai->cinematicsActive() && g_hdb->_gfx->isFadeStaying())
432 			g_hdb->_gfx->turnOffFade();
433 
434 		// Did we just fall down a PLUMMET?
435 		bgFlags = g_hdb->_map->getMapBGTileFlags(e->tileX, e->tileY);
436 		fgFlags = g_hdb->_map->getMapFGTileFlags(e->tileX, e->tileY);
437 		if ((bgFlags & kFlagPlummet) && !(fgFlags & kFlagGrating) && !g_hdb->_ai->playerDead()) {
438 			g_hdb->_ai->killPlayer(DEATH_PLUMMET);
439 			g_hdb->_ai->animEntFrames(e);
440 			return;
441 		}
442 
443 		// Standing on a TouchPlate will activate something WHILE standing on it
444 		int bgTile = g_hdb->_ai->checkForTouchplate(e->tileX, e->tileY);
445 		if (bgTile && !e->touchpWait && !e->touchpTile) {
446 			if (g_hdb->_ai->checkActionList(e, e->tileX, e->tileY, false)) {
447 				e->touchpTile = bgTile;
448 				e->touchpX = e->tileX;
449 				e->touchpY = e->tileY;
450 				e->touchpWait = kPlayerTouchPWait;
451 				g_hdb->_ai->stopEntity(e);
452 			}
453 		}
454 		g_hdb->_ai->animEntFrames(e);
455 	}
456 }
457 
aiPlayerDraw(AIEntity * e,int mx,int my)458 void aiPlayerDraw(AIEntity *e, int mx, int my) {
459 	switch (e->state) {
460 	case STATE_ATK_CLUB_UP:
461 		g_hdb->_ai->_clubUpGfx[e->animFrame]->drawMasked(e->x + e->drawXOff - mx, e->y + e->drawYOff - my);
462 		break;
463 	case STATE_ATK_CLUB_DOWN:
464 		g_hdb->_ai->_clubDownGfx[e->animFrame]->drawMasked(e->x + e->drawXOff - mx, e->y + e->drawYOff - my);
465 		break;
466 	case STATE_ATK_CLUB_LEFT:
467 		g_hdb->_ai->_clubLeftGfx[e->animFrame]->drawMasked(e->x + e->drawXOff - mx, e->y + e->drawYOff - my);
468 		break;
469 	case STATE_ATK_CLUB_RIGHT:
470 		g_hdb->_ai->_clubRightGfx[e->animFrame]->drawMasked(e->x + e->drawXOff - mx, e->y + e->drawYOff - my);
471 		break;
472 	default:
473 		break;
474 	}
475 
476 	if (e->sequence) {
477 		static int frame = 0;
478 		switch (e->dir) {
479 		case DIR_UP:
480 			g_hdb->_ai->_stunLightningGfx[frame]->drawMasked(e->x - mx, e->y - 32 - my);
481 			g_hdb->_ai->_stunLightningGfx[frame]->drawMasked(e->x - mx, e->y - 64 - my);
482 			break;
483 		case DIR_DOWN:
484 			g_hdb->_ai->_stunLightningGfx[frame]->drawMasked(e->x - mx, e->y + 32 - my);
485 			g_hdb->_ai->_stunLightningGfx[frame]->drawMasked(e->x - mx, e->y + 64 - my);
486 			break;
487 		case DIR_LEFT:
488 			g_hdb->_ai->_stunLightningGfx[frame]->drawMasked(e->x - 32 - mx, e->y - my);
489 			g_hdb->_ai->_stunLightningGfx[frame]->drawMasked(e->x - 64 - mx, e->y - my);
490 			break;
491 		case DIR_RIGHT:
492 			g_hdb->_ai->_stunLightningGfx[frame]->drawMasked(e->x + 32 - mx, e->y - my);
493 			g_hdb->_ai->_stunLightningGfx[frame]->drawMasked(e->x + 64 - mx, e->y - my);
494 			break;
495 		case DIR_NONE:
496 			break;
497 		}
498 
499 		frame = (frame + 1) & 3;
500 	}
501 }
502 
aiGemAttackInit(AIEntity * e)503 void aiGemAttackInit(AIEntity *e) {
504 	static const int xv[5] = {9, 0, 0, -1, 1};
505 	static const int yv[5] = {9, -1, 1, 0, 0};
506 
507 	e->moveSpeed = kPlayerMoveSpeed << 1;
508 	g_hdb->_ai->setEntityGoal(e, e->tileX + xv[e->dir], e->tileY + yv[e->dir]);
509 	e->state = STATE_MOVEDOWN;		// so it will draw & animate
510 	e->sequence = 0;	// flying out at something
511 	e->aiAction = aiGemAttackAction;
512 	e->draw = e->movedownGfx[0];
513 	g_hdb->_sound->playSound(SND_GEM_THROW);
514 }
515 
aiGemAttackAction(AIEntity * e)516 void aiGemAttackAction(AIEntity *e) {
517 	static const int xv[5] = {9, 0, 0, -1, 1};
518 	static const int yv[5] = {9, -1, 1, 0, 0};
519 
520 	switch (e->sequence) {
521 		// flying out at something
522 	case 0:
523 		if (e->goalX)
524 			g_hdb->_ai->animateEntity(e);
525 		else {
526 			g_hdb->_ai->checkActionList(e, e->tileX, e->tileY, false);
527 			g_hdb->_ai->checkAutoList(e, e->tileX, e->tileY);
528 
529 			AIEntity *hit = g_hdb->_ai->findEntityIgnore(e->tileX, e->tileY, e);
530 			uint32 bgFlags = g_hdb->_map->getMapBGTileFlags(e->tileX, e->tileY);
531 			uint32 fgFlags = g_hdb->_map->getMapFGTileFlags(e->tileX, e->tileY);
532 			int result = (e->level == 1 ? (bgFlags & (kFlagSolid)) : !(fgFlags & kFlagGrating) && (bgFlags & (kFlagSolid)));
533 			if (hit) {
534 				switch (hit->type) {
535 				case AI_CHICKEN:
536 					g_hdb->_ai->addAnimateTarget(hit->x, hit->y, 0, 3, ANIM_NORMAL, false, false, GROUP_STEAM_PUFF_SIT);
537 					g_hdb->_ai->removeEntity(hit);
538 					g_hdb->_sound->playSound(SND_CHICKEN_BAGAWK);
539 					break;
540 				case AI_BADFAIRY:
541 					g_hdb->_ai->stunEnemy(hit, 2);
542 					g_hdb->_ai->addAnimateTarget(hit->x, hit->y, 0, 3, ANIM_NORMAL, false, false, GEM_FLASH);
543 					break;
544 				case AI_NONE:
545 					if (hit->value1 == (int)AI_DRAGON) {
546 						// pull dragon's coords out of "lua_func_use" string.
547 						char num1[4], num2[4];
548 						memset(num1, 0, 4);
549 						memset(num2, 0, 4);
550 						memcpy(num1, hit->luaFuncUse, 3);
551 						memcpy(num2, hit->luaFuncUse + 3, 3);
552 
553 						g_hdb->_sound->playSound(SND_CLUB_HIT_FLESH);
554 						AIEntity *found = g_hdb->_ai->findEntity(atoi(num1), atoi(num2));
555 						if (found)
556 							aiDragonWake(found);
557 					}
558 					g_hdb->_ai->addAnimateTarget(e->x, e->y, 0, 3, ANIM_NORMAL, false, false, GEM_FLASH);
559 					g_hdb->_sound->playSound(SND_INV_SELECT);
560 					break;
561 				case AI_DRAGON:
562 					g_hdb->_sound->playSound(SND_CLUB_HIT_FLESH);
563 					aiDragonWake(hit);
564 					// fallthrough
565 				default:
566 					g_hdb->_ai->addAnimateTarget(e->x, e->y, 0, 3, ANIM_NORMAL, false, false, GEM_FLASH);
567 					g_hdb->_sound->playSound(SND_CLUB_HIT_FLESH);
568 				}
569 				if (e->value1)
570 					e->sequence = 1;
571 				else
572 					g_hdb->_ai->removeEntity(e);	// bye bye!
573 				return;
574 			} else if (result) {		// hit a wall
575 					g_hdb->_ai->addAnimateTarget(e->x, e->y, 0, 3, ANIM_NORMAL, false, false, GEM_FLASH);
576 					g_hdb->_sound->playSound(SND_INV_SELECT);
577 					// come back to daddy?
578 					if (e->value1)
579 						e->sequence = 1;
580 					else {
581 						g_hdb->_ai->removeEntity(e);
582 						return;
583 					}
584 			} else {
585 					g_hdb->_ai->setEntityGoal(e, e->tileX + xv[e->dir], e->tileY + yv[e->dir]);
586 					e->state = STATE_MOVEDOWN;		// so it will draw & animate
587 			}
588 			g_hdb->_ai->animateEntity(e);
589 		}
590 		break;
591 		// coming back to daddy?
592 	case 1:
593 		AIEntity *p = g_hdb->_ai->getPlayer();
594 		if (e->x < p->x)
595 			e->x++;
596 		else
597 			e->x--;
598 
599 		if (e->y < p->y)
600 			e->y++;
601 		else
602 			e->y--;
603 
604 		if (abs(e->x - p->x) < 4 && abs(e->y - p->y) < 4)
605 		{
606 			int	amt = g_hdb->_ai->getGemAmount();
607 			g_hdb->_ai->setGemAmount(amt + 1);
608 			g_hdb->_ai->addAnimateTarget(e->x, e->y, 0, 3, ANIM_NORMAL, false, false, GEM_FLASH);
609 			g_hdb->_ai->removeEntity(e);
610 			g_hdb->_sound->playSound(SND_GET_GEM);
611 		}
612 		break;
613 	}
614 }
615 
aiChickenAction(AIEntity * e)616 void aiChickenAction(AIEntity *e) {
617 	static int delay = 64;
618 
619 	if (g_hdb->_map->checkEntOnScreen(e) && !delay) {
620 		g_hdb->_sound->playSound(SND_CHICKEN_AMBIENT);
621 		delay = g_hdb->_rnd->getRandomNumber(127) + 160;
622 		aiChickenUse(e);
623 	}
624 
625 	if (delay)
626 		delay--;
627 
628 	if (e->goalX)
629 		g_hdb->_ai->animateEntity(e);
630 	else
631 		g_hdb->_ai->animEntFrames(e);
632 }
633 
aiChickenUse(AIEntity * e)634 void aiChickenUse(AIEntity *e) {
635 	g_hdb->_sound->playSound(SND_CHICKEN_BAGAWK);
636 }
637 
aiChickenInit(AIEntity * e)638 void aiChickenInit(AIEntity *e) {
639 	e->aiUse = aiChickenUse;
640 	e->aiAction = aiChickenAction;
641 }
642 
aiChickenInit2(AIEntity * e)643 void aiChickenInit2(AIEntity *e) {
644 	e->draw = e->standdownGfx[0];
645 }
646 
aiDollyInit(AIEntity * e)647 void aiDollyInit(AIEntity *e) {
648 	e->moveSpeed = kPlayerMoveSpeed >> 1;
649 	e->aiAction = aiGenericAction;
650 }
651 
aiDollyInit2(AIEntity * e)652 void aiDollyInit2(AIEntity *e) {
653 	e->draw = e->movedownGfx[0];
654 }
655 
aiSergeantInit(AIEntity * e)656 void aiSergeantInit(AIEntity *e) {
657 	e->moveSpeed = kPlayerMoveSpeed >> 1;
658 	if (e->value1)
659 		e->aiAction = aiSergeantAction;
660 }
661 
aiSergeantInit2(AIEntity * e)662 void aiSergeantInit2(AIEntity *e) {
663 	e->draw = g_hdb->_ai->getStandFrameDir(e);
664 }
665 
aiSergeantAction(AIEntity * e)666 void aiSergeantAction(AIEntity *e) {
667 	if (e->goalX) {
668 		g_hdb->_sound->playSound(SND_FOOTSTEPS);
669 		g_hdb->_ai->animateEntity(e);
670 	} else
671 		g_hdb->_ai->animEntFrames(e);
672 }
673 
aiSpacedudeInit(AIEntity * e)674 void aiSpacedudeInit(AIEntity *e) {
675 	e->moveSpeed = kPlayerMoveSpeed >> 1;
676 	if (e->value1)
677 		e->aiAction = aiGenericAction;
678 }
679 
aiSpacedudeInit2(AIEntity * e)680 void aiSpacedudeInit2(AIEntity *e) {
681 	e->standdownFrames = 1;
682 	e->standdownGfx[0] = e->movedownGfx[0];
683 	e->standupFrames = 1;
684 	e->standupGfx[0] = e->moveupGfx[0];
685 	e->standleftFrames = 1;
686 	e->standleftGfx[0] = e->moveleftGfx[0];
687 	e->standrightFrames = 1;
688 	e->standrightGfx[0] = e->moverightGfx[0];
689 	e->draw = g_hdb->_ai->getStandFrameDir(e);
690 }
691 
aiCrateAction(AIEntity * e)692 void aiCrateAction(AIEntity *e) {
693 	// if crate isn't moving somewhere, don't move it
694 	if (!e->goalX) {
695 		// crate is stopped in the water... should it continue downstream?
696 		// not if it's marked by the Number of the Beast!
697 		if (e->state == STATE_FLOATING) {
698 			if (e->value1 != 0x666) {
699 				int flags = g_hdb->_map->getMapBGTileFlags(e->tileX, e->tileY);
700 				if (flags & (kFlagPushRight | kFlagPushLeft | kFlagPushUp | kFlagPushDown)) {
701 					g_hdb->_ai->setEntityGoal(e, e->tileX, e->tileY);
702 					g_hdb->_ai->animateEntity(e);
703 				} else
704 					g_hdb->_ai->animEntFrames(e);
705 			} else
706 				g_hdb->_ai->animEntFrames(e);
707 		}
708 		return;
709 	}
710 
711 	g_hdb->_ai->animateEntity(e);
712 }
713 
aiCrateInit2(AIEntity * e)714 void aiCrateInit2(AIEntity *e) {
715 	// point all crate move frames to the standing one
716 	e->movedownFrames =
717 		e->moveleftFrames =
718 		e->moverightFrames =
719 		e->moveupFrames = 1;
720 
721 	e->movedownGfx[0] =
722 		e->moveupGfx[0] =
723 		e->moveleftGfx[0] =
724 		e->moverightGfx[0] = e->standdownGfx[0];
725 
726 	e->draw = e->standdownGfx[0];			// standing frame - doesn't move
727 }
728 
aiCrateInit(AIEntity * e)729 void aiCrateInit(AIEntity *e) {
730 	e->moveSpeed = kPushMoveSpeed;
731 	e->aiAction = aiCrateAction;
732 	e->value1 = 0;
733 }
734 
aiBarrelLightAction(AIEntity * e)735 void aiBarrelLightAction(AIEntity *e) {
736 	if (!e->goalX) {
737 		if (e->state == STATE_FLOATING)
738 			g_hdb->_ai->animEntFrames(e);
739 		return;
740 	}
741 
742 	g_hdb->_ai->animateEntity(e);
743 }
744 
aiBarrelLightInit2(AIEntity * e)745 void aiBarrelLightInit2(AIEntity *e) {
746 	// point all light barrel move frames to the standing one
747 	e->movedownFrames =
748 		e->moveleftFrames =
749 		e->moverightFrames =
750 		e->moveupFrames = 1;
751 
752 	e->movedownGfx[0] =
753 		e->moveupGfx[0] =
754 		e->moveleftGfx[0] =
755 		e->moverightGfx[0] = e->standdownGfx[0];
756 
757 	e->draw = e->standdownGfx[0];			// standing frame - doesn't move
758 }
759 
aiBarrelLightInit(AIEntity * e)760 void aiBarrelLightInit(AIEntity *e) {
761 	e->moveSpeed = kPushMoveSpeed;
762 	e->aiAction = aiBarrelLightAction;
763 }
764 
aiBarrelHeavyAction(AIEntity * e)765 void aiBarrelHeavyAction(AIEntity *e) {
766 	if (!e->goalX) {
767 		if (e->state == STATE_FLOATING)
768 			g_hdb->_ai->animEntFrames(e);
769 		return;
770 	}
771 
772 	g_hdb->_ai->animateEntity(e);
773 }
774 
aiBarrelHeavyInit2(AIEntity * e)775 void aiBarrelHeavyInit2(AIEntity *e) {
776 	// point all heavy barrel move frames to the standing one
777 	e->movedownFrames =
778 		e->moveleftFrames =
779 		e->moverightFrames =
780 		e->moveupFrames = 1;
781 
782 	e->movedownGfx[0] =
783 		e->moveupGfx[0] =
784 		e->moveleftGfx[0] =
785 		e->moverightGfx[0] = e->standdownGfx[0];
786 
787 	e->draw = e->standdownGfx[0];			// standing frame - doesn't move
788 }
789 
aiBarrelHeavyInit(AIEntity * e)790 void aiBarrelHeavyInit(AIEntity *e) {
791 	e->moveSpeed = kPushMoveSpeed;
792 	e->aiAction = aiBarrelHeavyAction;
793 }
794 
aiBarrelExplode(AIEntity * e)795 void aiBarrelExplode(AIEntity *e) {
796 	e->state = STATE_EXPLODING;
797 	e->animDelay = e->animCycle;
798 	e->animFrame = 0;
799 
800 	if (!g_hdb->isDemo())
801 		g_hdb->_sound->playSound(SND_BARREL_EXPLODE);
802 
803 	g_hdb->_map->setBoomBarrel(e->tileX, e->tileY, 0);
804 }
805 
aiBarrelExplodeInit(AIEntity * e)806 void aiBarrelExplodeInit(AIEntity *e) {
807 	e->moveSpeed = kPushMoveSpeed;
808 	e->aiAction = aiBarrelExplodeAction;
809 	g_hdb->_map->setBoomBarrel(e->tileX, e->tileY, 1);
810 }
811 
aiBarrelExplodeInit2(AIEntity * e)812 void aiBarrelExplodeInit2(AIEntity *e) {
813 	// point all exploding barrel MOVE frames to the standing one
814 	e->blinkFrames =
815 		e->movedownFrames =
816 		e->moveleftFrames =
817 		e->moverightFrames =
818 		e->moveupFrames = 1;
819 
820 	e->blinkGfx[0] =
821 		e->movedownGfx[0] =
822 		e->moveupGfx[0] =
823 		e->moveleftGfx[0] =
824 		e->moverightGfx[0] = e->standdownGfx[0];
825 
826 	e->draw = e->standdownGfx[0];			// standing frame - doesn't move
827 }
828 
aiBarrelExplodeAction(AIEntity * e)829 void aiBarrelExplodeAction(AIEntity *e) {
830 	if (e->goalX)
831 		g_hdb->_ai->animateEntity(e);
832 	else if (e->state == STATE_EXPLODING)
833 		g_hdb->_ai->animEntFrames(e);
834 }
835 
aiBarrelExplodeSpread(AIEntity * e)836 void aiBarrelExplodeSpread(AIEntity *e) {
837 	static const int xv1[4] = {-1,  1, -1,  0};
838 	static const int yv1[4] = {-1, -1,  0, -1};
839 	static const int xv2[4] = {1,  0,  1, -1};
840 	static const int yv2[4] = {0,  1,  1,  1};
841 
842 	int	x = e->tileX;
843 	int	y = e->tileY;
844 	int	index = e->animFrame;
845 
846 	// are we just starting an explosion ring?
847 	if (e->animDelay != e->animCycle)
848 		return;
849 
850 	// the animation frame is the index into which set of 2 explosions to spawn
851 	int xv = xv1[index];
852 	int yv = yv1[index];
853 
854 	// explosion 1: check to see if we can explode (non-solid tile)
855 	// if so, spawn it and mark it in the explosion matrix
856 	if (!(g_hdb->_map->getMapBGTileFlags(x + xv, y + yv) & kFlagSolid) && !g_hdb->_map->explosionExist(x + xv, y + yv)) {
857 		aiBarrelBlowup(e, x + xv, y + yv);
858 		// are we blowing up on another BOOMBARREL?  if so, start it exploding.
859 		AIEntity *e2 = g_hdb->_ai->findEntity(x + xv, y + yv);
860 		if (e2 && e2->state != STATE_EXPLODING) {
861 			switch (e2->type) {
862 			case AI_GUY:
863 				g_hdb->_ai->killPlayer(DEATH_FRIED);
864 				break;
865 			case AI_BOOMBARREL:
866 				aiBarrelExplode(e2);
867 				break;
868 			case AI_OMNIBOT:
869 			case AI_TURNBOT:
870 			case AI_SHOCKBOT:
871 			case AI_RIGHTBOT:
872 			case AI_PUSHBOT:
873 			case AI_RAILRIDER:
874 			case AI_MAINTBOT:
875 			case AI_DEADEYE:
876 			case AI_FATFROG:
877 			case AI_ICEPUFF:
878 			case AI_MEERKAT:
879 			case AI_BUZZFLY:
880 			case AI_GOODFAIRY:
881 			case AI_GATEPUDDLE:
882 			case AI_BADFAIRY:
883 				g_hdb->_ai->addAnimateTarget(x * kTileWidth,
884 					y * kTileHeight, 0, 3, ANIM_NORMAL, false, false, GROUP_EXPLOSION_BOOM_SIT);
885 				if (e2->type != AI_LASERBEAM)
886 					g_hdb->_ai->removeEntity(e2);
887 				break;
888 			default:
889 				break;
890 			}
891 		}
892 	}
893 
894 	xv = xv2[index];
895 	yv = yv2[index];
896 
897 	// explosion 2: check to see if we can explode (non-solid tile)
898 	// if so, spawn it and mark it in the explosion matrix
899 
900 	if (!(g_hdb->_map->getMapBGTileFlags(x + xv, y + yv) & kFlagSolid) && !g_hdb->_map->explosionExist(x + xv, y + yv)) {
901 		aiBarrelBlowup(e, x + xv, y + yv);
902 		// are we blowing up on another BOOMBARREL?  if so, start it exploding.
903 		AIEntity *e2 = g_hdb->_ai->findEntity(x + xv, y + yv);
904 		if (e2 && e2->state != STATE_EXPLODING) {
905 			switch (e2->type) {
906 			case AI_GUY:
907 				g_hdb->_ai->killPlayer(DEATH_FRIED);
908 				break;
909 			case AI_BOOMBARREL:
910 				aiBarrelExplode(e2);
911 				break;
912 			case AI_OMNIBOT:
913 			case AI_TURNBOT:
914 			case AI_SHOCKBOT:
915 			case AI_RIGHTBOT:
916 			case AI_PUSHBOT:
917 			case AI_RAILRIDER:
918 			case AI_MAINTBOT:
919 			case AI_DEADEYE:
920 			case AI_FATFROG:
921 			case AI_ICEPUFF:
922 			case AI_MEERKAT:
923 			case AI_BUZZFLY:
924 			case AI_GOODFAIRY:
925 			case AI_GATEPUDDLE:
926 			case AI_BADFAIRY:
927 				g_hdb->_ai->addAnimateTarget(x * kTileWidth,
928 					y * kTileHeight, 0, 3, ANIM_NORMAL, false, false, GROUP_EXPLOSION_BOOM_SIT);
929 				if (e2->type != AI_LASERBEAM)
930 					g_hdb->_ai->removeEntity(e2);
931 				break;
932 			default:
933 				break;
934 			}
935 		}
936 	}
937 }
938 
aiBarrelExplosionEnd(int x,int y)939 void aiBarrelExplosionEnd(int x, int y) {
940 	g_hdb->_map->setExplosion(x, y, 0);
941 }
942 
aiBarrelBlowup(AIEntity * e,int x,int y)943 void aiBarrelBlowup(AIEntity *e, int x, int y) {
944 	g_hdb->_ai->addAnimateTarget(x * kTileWidth,
945 		y * kTileHeight, 0, 3, ANIM_NORMAL, false, false, GROUP_EXPLOSION_BOOM_SIT);
946 	g_hdb->_map->setExplosion(x, y, 1);
947 	g_hdb->_ai->addCallback(AI_BARREL_EXPLOSION_END, x, y, e->animCycle * 4);
948 }
949 
aiScientistInit(AIEntity * e)950 void aiScientistInit(AIEntity *e) {
951 	e->moveSpeed = kPlayerMoveSpeed >> 1;
952 	if (g_hdb->_ai->findPath(e))
953 		e->aiAction = aiGenericAction;
954 	else if (e->value1)
955 		e->aiAction = aiGenericAction;
956 }
957 
aiScientistInit2(AIEntity * e)958 void aiScientistInit2(AIEntity *e) {
959 	e->draw = g_hdb->_ai->getStandFrameDir(e);
960 }
961 
aiSlugAttackAction(AIEntity * e)962 void aiSlugAttackAction(AIEntity *e) {
963 	static const int xv[5] = {9, 0, 0, -1, 1};
964 	static const int yv[5] = {9, -1, 1, 0, 0};
965 
966 	if (e->goalX)
967 		g_hdb->_ai->animateEntity(e);
968 
969 	g_hdb->_ai->checkActionList(e, e->tileX, e->tileY, false);
970 	g_hdb->_ai->checkAutoList(e, e->tileX, e->tileY);
971 
972 	AIEntity *hit = g_hdb->_ai->findEntityIgnore(e->tileX, e->tileY, e);
973 	if (hit && hit->type == AI_GUY)
974 		hit = NULL;
975 
976 	// don't hit anything you can walk through...
977 	if (hit && true == g_hdb->_ai->getTableEnt(hit->type))
978 		hit = NULL;
979 
980 	// don't hit floating stuff
981 	if (hit && hit->state == STATE_FLOATING)
982 		hit = NULL;
983 
984 	uint32 bg_flags = g_hdb->_map->getMapBGTileFlags(e->tileX, e->tileY);
985 	uint32 fg_flags = g_hdb->_map->getMapFGTileFlags(e->tileX, e->tileY);
986 	int	result = (e->level == 1 ? (bg_flags & (kFlagSolid)) : !(fg_flags & kFlagGrating) && (bg_flags & (kFlagSolid)));
987 	if (hit) {
988 		g_hdb->_sound->playSound(SND_SLUG_HIT);
989 		g_hdb->_sound->playSound(g_hdb->_ai->metalOrFleshSND(hit));
990 		switch (hit->type) {
991 		case AI_MEERKAT:
992 			if (hit->sequence > 2) {		// out of the ground?
993 				g_hdb->_ai->addAnimateTarget(hit->x, hit->y, 0, 3, ANIM_NORMAL, false, false, GROUP_STEAM_PUFF_SIT);
994 				g_hdb->_ai->stunEnemy(hit, 8);
995 			} else {
996 				g_hdb->_ai->setEntityGoal(e, e->tileX + xv[e->dir], e->tileY + yv[e->dir]);
997 				e->state = STATE_MOVEDOWN;		// so it will draw & animate
998 				g_hdb->_ai->animateEntity(e);
999 				return;
1000 			}
1001 			break;
1002 		case AI_ICEPUFF:
1003 			if (hit->state == STATE_ICEP_APPEAR ||
1004 				hit->state == STATE_ICEP_THROWDOWN ||
1005 				hit->state == STATE_ICEP_THROWLEFT ||
1006 				hit->state == STATE_ICEP_THROWRIGHT) {
1007 				g_hdb->_ai->addAnimateTarget(hit->x, hit->y, 0, 3, ANIM_NORMAL, false, false, GROUP_STEAM_PUFF_SIT);
1008 				g_hdb->_ai->stunEnemy(hit, 8);
1009 			} else {
1010 				g_hdb->_ai->setEntityGoal(e, e->tileX + xv[e->dir], e->tileY + yv[e->dir]);
1011 				e->state = STATE_MOVEDOWN;		// so it will draw & animate
1012 				g_hdb->_ai->animateEntity(e);
1013 				return;
1014 			}
1015 			break;
1016 		case AI_OMNIBOT:
1017 		case AI_TURNBOT:
1018 		case AI_SHOCKBOT:
1019 		case AI_RIGHTBOT:
1020 		case AI_PUSHBOT:
1021 		case AI_LISTENBOT:
1022 		case AI_MAINTBOT:
1023 		case AI_FATFROG:
1024 		case AI_BADFAIRY:
1025 		case AI_BUZZFLY:
1026 			g_hdb->_ai->addAnimateTarget(e->x, e->y, 0, 3, ANIM_NORMAL, false, false, GROUP_STEAM_PUFF_SIT);
1027 			g_hdb->_ai->stunEnemy(hit, 8);
1028 			break;
1029 
1030 		case AI_CHICKEN:
1031 			g_hdb->_ai->addAnimateTarget(hit->x, hit->y, 0, 3, ANIM_NORMAL, false, false, GROUP_STEAM_PUFF_SIT);
1032 			g_hdb->_ai->removeEntity(hit);
1033 			break;
1034 		case AI_BOOMBARREL:
1035 			g_hdb->_sound->playSound(SND_CLUB_HIT_METAL);
1036 			aiBarrelExplode(hit);
1037 			aiBarrelBlowup(hit, hit->tileX, hit->tileY);
1038 			break;
1039 			// ACTION MODE entities go away - except the FOURFIRER
1040 		case AI_GATEPUDDLE:
1041 			g_hdb->_ai->addAnimateTarget(e->x, e->y, 0, 7, ANIM_NORMAL, false, false, TELEPORT_FLASH);
1042 			g_hdb->_ai->removeEntity(hit);
1043 			g_hdb->_sound->playSound(SND_TELEPORT);
1044 			break;
1045 		case AI_DEADEYE:
1046 			g_hdb->_ai->addAnimateTarget(e->tileX * kTileWidth,
1047 				e->tileY * kTileHeight, 0, 3, ANIM_NORMAL, false, false, GROUP_EXPLOSION_BOOM_SIT);
1048 			g_hdb->_ai->removeEntity(hit);
1049 			g_hdb->_sound->playSound(SND_BARREL_EXPLODE);
1050 			break;
1051 
1052 		case AI_NONE:
1053 			if (hit->value1 == (int)AI_DRAGON) {
1054 				// pull dragon's coords out of "lua_func_use" string.
1055 				char num1[4], num2[4];
1056 				memset(num1, 0, 4);
1057 				memset(num2, 0, 4);
1058 				memcpy(num1, hit->luaFuncUse, 3);
1059 				memcpy(num2, hit->luaFuncUse + 3, 3);
1060 
1061 				g_hdb->_sound->playSound(SND_CLUB_HIT_FLESH);
1062 				AIEntity *found = g_hdb->_ai->findEntity(atoi(num1), atoi(num2));
1063 				if (found)
1064 					aiDragonWake(found);
1065 				g_hdb->_ai->addAnimateTarget(e->x, e->y, 0, 3, ANIM_NORMAL, false, false, GEM_FLASH);
1066 			}
1067 			break;
1068 		case AI_DRAGON:
1069 			aiDragonWake(hit);
1070 			break;
1071 		default:
1072 			break;
1073 		}
1074 		g_hdb->_ai->removeEntity(e);	// bye bye!
1075 		return;
1076 	} else if (result) {		// hit a wall
1077 		g_hdb->_sound->playSound(SND_SLUG_HIT);
1078 		g_hdb->_ai->addAnimateTarget(e->x, e->y, 0, 3, ANIM_NORMAL, false, false, GROUP_STEAM_PUFF_SIT);
1079 		g_hdb->_ai->removeEntity(e);
1080 	} else {
1081 		g_hdb->_ai->setEntityGoal(e, e->tileX + xv[e->dir], e->tileY + yv[e->dir]);
1082 		e->state = STATE_MOVEDOWN;		// so it will draw & animate
1083 		g_hdb->_ai->animateEntity(e);
1084 	}
1085 }
1086 
aiSlugAttackDraw(AIEntity * e,int mx,int my)1087 void aiSlugAttackDraw(AIEntity *e, int mx, int my) {
1088 	g_hdb->_ai->_slugAttackGfx[e->animFrame]->drawMasked(e->x - mx + 8, e->y - my + 8);
1089 }
1090 
aiSlugAttackInit(AIEntity * e)1091 void aiSlugAttackInit(AIEntity *e) {
1092 	static const int xv[5] = {9,  0, 0, -1, 1};
1093 	static const int yv[5] = {9, -1, 1,  0, 0};
1094 
1095 	if (g_hdb->isDemo())
1096 		return;
1097 
1098 	e->moveSpeed = kPlayerMoveSpeed << 1;
1099 	g_hdb->_ai->setEntityGoal(e, e->tileX + xv[e->dir], e->tileY + yv[e->dir]);
1100 	e->draw = NULL;					// use custom draw function
1101 	e->aiDraw = aiSlugAttackDraw;
1102 	e->state = STATE_MOVEDOWN;		// so it will draw & animate
1103 	e->aiAction = aiSlugAttackAction;
1104 	g_hdb->_sound->playSound(SND_SLUG_FIRE);
1105 }
1106 
aiSlugAttackInit2(AIEntity * e)1107 void aiSlugAttackInit2(AIEntity *e) {
1108 	e->movedownFrames = 4;
1109 }
1110 
aiDeadWorkerInit(AIEntity * e)1111 void aiDeadWorkerInit(AIEntity *e) {
1112 }
1113 
aiDeadWorkerInit2(AIEntity * e)1114 void aiDeadWorkerInit2(AIEntity *e) {
1115 	e->draw = e->standdownGfx[0];
1116 }
1117 
aiWorkerInit(AIEntity * e)1118 void aiWorkerInit(AIEntity *e) {
1119 	if (e->value1)
1120 		e->aiAction = aiGenericAction;
1121 	e->moveSpeed = kPlayerMoveSpeed >> 1;
1122 }
1123 
aiWorkerInit2(AIEntity * e)1124 void aiWorkerInit2(AIEntity *e) {
1125 	e->draw = g_hdb->_ai->getStandFrameDir(e);
1126 }
1127 
aiAccountantInit(AIEntity * e)1128 void aiAccountantInit(AIEntity *e) {
1129 }
1130 
aiAccountantInit2(AIEntity * e)1131 void aiAccountantInit2(AIEntity *e) {
1132 	e->draw = g_hdb->_ai->getStandFrameDir(e);
1133 }
1134 
aiFrogStatueInit(AIEntity * e)1135 void aiFrogStatueInit(AIEntity *e) {
1136 	e->moveSpeed = kPushMoveSpeed;
1137 	e->aiAction = aiFrogStatueAction;
1138 }
1139 
aiFrogStatueInit2(AIEntity * e)1140 void aiFrogStatueInit2(AIEntity *e) {
1141 	// point all frog statue MOVE frames to the standing one
1142 	e->blinkFrames =
1143 		e->movedownFrames =
1144 		e->moveleftFrames =
1145 		e->moverightFrames =
1146 		e->moveupFrames = 1;
1147 
1148 	e->blinkGfx[0] =
1149 		e->movedownGfx[0] =
1150 		e->moveupGfx[0] =
1151 		e->moveleftGfx[0] =
1152 		e->moverightGfx[0] = e->standdownGfx[0];
1153 
1154 	e->draw = e->standdownGfx[0];			// standing frame - doesn't move
1155 }
1156 
aiFrogStatueAction(AIEntity * e)1157 void aiFrogStatueAction(AIEntity *e) {
1158 	// if frog statue isn't moving somewhere, don't move it
1159 	if (!e->goalX)
1160 		return;
1161 
1162 	g_hdb->_ai->animateEntity(e);
1163 }
1164 
aiRoboStunnerAction(AIEntity * e)1165 void aiRoboStunnerAction(AIEntity *e) {
1166 	aiAnimateStanddown(e, 1);
1167 	aiGetItemAction(e);
1168 }
1169 
aiRoboStunnerInit(AIEntity * e)1170 void aiRoboStunnerInit(AIEntity *e) {
1171 	e->aiAction = aiRoboStunnerAction;
1172 	strcpy(e->printedName, "Robostunner");
1173 }
1174 
aiRoboStunnerInit2(AIEntity * e)1175 void aiRoboStunnerInit2(AIEntity *e) {
1176 	e->draw = e->standdownGfx[0];
1177 }
1178 
aiClubInit(AIEntity * e)1179 void aiClubInit(AIEntity *e) {
1180 	strcpy(e->printedName, "Creature Clubber");
1181 	e->aiAction = aiGetItemAction;
1182 }
1183 
aiClubInit2(AIEntity * e)1184 void aiClubInit2(AIEntity *e) {
1185 	e->draw = e->standdownGfx[0];
1186 }
1187 
aiSlugSlingerInit(AIEntity * e)1188 void aiSlugSlingerInit(AIEntity *e) {
1189 	strcpy(e->printedName, "Slugslinger");
1190 	e->aiAction = aiGetItemAction;
1191 }
1192 
aiSlugSlingerInit2(AIEntity * e)1193 void aiSlugSlingerInit2(AIEntity *e) {
1194 	e->draw = e->standdownGfx[0];
1195 }
1196 
aiEnvelopeGreenInit(AIEntity * e)1197 void aiEnvelopeGreenInit(AIEntity *e) {
1198 	strcpy(e->printedName, "Green envelope");
1199 	e->aiAction = aiGetItemAction;
1200 }
1201 
aiEnvelopeGreenInit2(AIEntity * e)1202 void aiEnvelopeGreenInit2(AIEntity *e) {
1203 	e->draw = e->standdownGfx[0];
1204 }
1205 
aiGemBlueInit(AIEntity * e)1206 void aiGemBlueInit(AIEntity *e) {
1207 	e->aiAction = aiGemAction;
1208 }
1209 
aiGemBlueInit2(AIEntity * e)1210 void aiGemBlueInit2(AIEntity *e) {
1211 	e->draw = e->standdownGfx[0];
1212 }
1213 
aiGemRedInit(AIEntity * e)1214 void aiGemRedInit(AIEntity *e) {
1215 	e->aiAction = aiGemAction;
1216 }
1217 
aiGemRedInit2(AIEntity * e)1218 void aiGemRedInit2(AIEntity *e) {
1219 	e->draw = e->standdownGfx[0];
1220 }
1221 
aiGemGreenInit(AIEntity * e)1222 void aiGemGreenInit(AIEntity *e) {
1223 	e->aiAction = aiGemAction;
1224 }
1225 
aiGemGreenInit2(AIEntity * e)1226 void aiGemGreenInit2(AIEntity *e) {
1227 	e->draw = e->standdownGfx[0];
1228 }
1229 
aiTeaCupInit(AIEntity * e)1230 void aiTeaCupInit(AIEntity *e) {
1231 	strcpy(e->printedName, "a Teacup");
1232 	e->aiAction = aiGetItemAction;
1233 }
1234 
aiTeaCupInit2(AIEntity * e)1235 void aiTeaCupInit2(AIEntity *e) {
1236 	e->draw = e->standdownGfx[0];
1237 }
1238 
aiCookieInit(AIEntity * e)1239 void aiCookieInit(AIEntity *e) {
1240 	strcpy(e->printedName, "a Cookie");
1241 	e->aiAction = aiGetItemAction;
1242 }
1243 
aiCookieInit2(AIEntity * e)1244 void aiCookieInit2(AIEntity *e) {
1245 	e->draw = e->standdownGfx[0];
1246 }
1247 
aiBurgerInit(AIEntity * e)1248 void aiBurgerInit(AIEntity *e) {
1249 	strcpy(e->printedName, "a Burger");
1250 	e->aiAction = aiGetItemAction;
1251 }
1252 
aiBurgerInit2(AIEntity * e)1253 void aiBurgerInit2(AIEntity *e) {
1254 	e->draw = e->standdownGfx[0];
1255 }
1256 
aiBookInit(AIEntity * e)1257 void aiBookInit(AIEntity *e) {
1258 	strcpy(e->printedName, "a Book");
1259 	e->aiAction = aiGetItemAction;
1260 }
1261 
aiBookInit2(AIEntity * e)1262 void aiBookInit2(AIEntity *e) {
1263 	e->draw = e->standdownGfx[0];
1264 }
1265 
aiClipboardInit(AIEntity * e)1266 void aiClipboardInit(AIEntity *e) {
1267 	strcpy(e->printedName, "a Clipboard");
1268 	e->aiAction = aiGetItemAction;
1269 }
1270 
aiClipboardInit2(AIEntity * e)1271 void aiClipboardInit2(AIEntity *e) {
1272 	e->draw = e->standdownGfx[0];
1273 }
1274 
aiNoteInit(AIEntity * e)1275 void aiNoteInit(AIEntity *e) {
1276 	strcpy(e->printedName, "a Note");
1277 	e->aiAction = aiGetItemAction;
1278 }
1279 
aiNoteInit2(AIEntity * e)1280 void aiNoteInit2(AIEntity *e) {
1281 	e->draw = e->standdownGfx[0];
1282 }
1283 
aiKeycardWhiteInit(AIEntity * e)1284 void aiKeycardWhiteInit(AIEntity *e) {
1285 	strcpy(e->printedName, "a White keycard");
1286 	e->aiAction = aiGetItemAction;
1287 }
1288 
aiKeycardWhiteInit2(AIEntity * e)1289 void aiKeycardWhiteInit2(AIEntity *e) {
1290 	e->draw = e->standdownGfx[0];
1291 }
1292 
aiKeycardBlueInit(AIEntity * e)1293 void aiKeycardBlueInit(AIEntity *e) {
1294 	strcpy(e->printedName, "a Blue keycard");
1295 	e->aiAction = aiGetItemAction;
1296 }
1297 
aiKeycardBlueInit2(AIEntity * e)1298 void aiKeycardBlueInit2(AIEntity *e) {
1299 	e->draw = e->standdownGfx[0];
1300 }
1301 
aiKeycardRedInit(AIEntity * e)1302 void aiKeycardRedInit(AIEntity *e) {
1303 	strcpy(e->printedName, "a Red keycard");
1304 	e->aiAction = aiGetItemAction;
1305 }
1306 
aiKeycardRedInit2(AIEntity * e)1307 void aiKeycardRedInit2(AIEntity *e) {
1308 	e->draw = e->standdownGfx[0];
1309 }
1310 
aiKeycardGreenInit(AIEntity * e)1311 void aiKeycardGreenInit(AIEntity *e) {
1312 	strcpy(e->printedName, "a Green keycard");
1313 	e->aiAction = aiGetItemAction;
1314 }
1315 
aiKeycardGreenInit2(AIEntity * e)1316 void aiKeycardGreenInit2(AIEntity *e) {
1317 	e->draw = e->standdownGfx[0];
1318 }
1319 
aiKeycardPurpleInit(AIEntity * e)1320 void aiKeycardPurpleInit(AIEntity *e) {
1321 	strcpy(e->printedName, "a Purple keycard");
1322 	e->aiAction = aiGetItemAction;
1323 }
1324 
aiKeycardPurpleInit2(AIEntity * e)1325 void aiKeycardPurpleInit2(AIEntity *e) {
1326 	e->draw = e->standdownGfx[0];
1327 }
1328 
aiKeycardBlackInit(AIEntity * e)1329 void aiKeycardBlackInit(AIEntity *e) {
1330 	strcpy(e->printedName, "a Black keycard");
1331 	e->aiAction = aiGetItemAction;
1332 }
1333 
aiKeycardBlackInit2(AIEntity * e)1334 void aiKeycardBlackInit2(AIEntity *e) {
1335 	e->draw = e->standdownGfx[0];
1336 }
1337 
aiSeedInit(AIEntity * e)1338 void aiSeedInit(AIEntity *e) {
1339 	strcpy(e->printedName, "some Henscratch");
1340 	e->aiAction = aiGetItemAction;
1341 }
1342 
aiSeedInit2(AIEntity * e)1343 void aiSeedInit2(AIEntity *e) {
1344 	e->draw = e->standdownGfx[0];
1345 }
1346 
aiSodaInit(AIEntity * e)1347 void aiSodaInit(AIEntity *e) {
1348 	strcpy(e->printedName, "a Dr. Frostee");
1349 	e->aiAction = aiGetItemAction;
1350 }
1351 
aiSodaInit2(AIEntity * e)1352 void aiSodaInit2(AIEntity *e) {
1353 	e->draw = e->standdownGfx[0];
1354 }
1355 
aiDollyTool1Init(AIEntity * e)1356 void aiDollyTool1Init(AIEntity *e) {
1357 	strcpy(e->printedName, "Dolly's Wrench");
1358 	e->aiAction = aiGetItemAction;
1359 }
1360 
aiDollyTool1Init2(AIEntity * e)1361 void aiDollyTool1Init2(AIEntity *e) {
1362 	e->draw = e->standdownGfx[0];
1363 }
1364 
aiDollyTool2Init(AIEntity * e)1365 void aiDollyTool2Init(AIEntity *e) {
1366 	strcpy(e->printedName, "Dolly's Torch");
1367 	e->aiAction = aiGetItemAction;
1368 }
1369 
aiDollyTool2Init2(AIEntity * e)1370 void aiDollyTool2Init2(AIEntity *e) {
1371 	e->draw = e->standdownGfx[0];
1372 }
1373 
aiDollyTool3Init(AIEntity * e)1374 void aiDollyTool3Init(AIEntity *e) {
1375 	strcpy(e->printedName, "Dolly's EMF Resonator");
1376 	e->aiAction = aiGetItemAction;
1377 }
1378 
aiDollyTool3Init2(AIEntity * e)1379 void aiDollyTool3Init2(AIEntity *e) {
1380 	e->draw = e->standdownGfx[0];
1381 }
1382 
aiDollyTool4Init(AIEntity * e)1383 void aiDollyTool4Init(AIEntity *e) {
1384 	strcpy(e->printedName, "Dolly's Toolbox");
1385 	e->aiAction = aiGetItemAction;
1386 }
1387 
aiDollyTool4Init2(AIEntity * e)1388 void aiDollyTool4Init2(AIEntity *e) {
1389 	e->draw = e->standdownGfx[0];
1390 }
1391 
aiRouterInit(AIEntity * e)1392 void aiRouterInit(AIEntity *e) {
1393 	strcpy(e->printedName, "a Computer Router");
1394 	e->aiAction = aiGetItemAction;
1395 }
1396 
aiRouterInit2(AIEntity * e)1397 void aiRouterInit2(AIEntity *e) {
1398 	e->draw = e->standdownGfx[0];
1399 }
1400 
aiSlicerInit(AIEntity * e)1401 void aiSlicerInit(AIEntity *e) {
1402 	strcpy(e->printedName, "a Pizza Slicer");
1403 	e->aiAction = aiGetItemAction;
1404 }
1405 
aiSlicerInit2(AIEntity * e)1406 void aiSlicerInit2(AIEntity *e) {
1407 	e->draw = e->standdownGfx[0];
1408 }
1409 
aiPackageInit(AIEntity * e)1410 void aiPackageInit(AIEntity *e) {
1411 	strcpy(e->printedName, "a Package");
1412 	e->aiAction = aiGetItemAction;
1413 }
1414 
aiPackageInit2(AIEntity * e)1415 void aiPackageInit2(AIEntity *e) {
1416 	e->draw = e->standdownGfx[0];
1417 }
1418 
aiMagicEggAction(AIEntity * e)1419 void aiMagicEggAction(AIEntity *e) {
1420 	// if magic egg isn't moving somewhere, don't move it
1421 	if (!e->goalX)
1422 		return;
1423 
1424 	g_hdb->_ai->animateEntity(e);
1425 }
1426 
aiMagicEggInit(AIEntity * e)1427 void aiMagicEggInit(AIEntity *e) {
1428 	e->moveSpeed = kPushMoveSpeed;
1429 	e->aiAction = aiMagicEggAction;
1430 }
1431 
aiMagicEggInit2(AIEntity * e)1432 void aiMagicEggInit2(AIEntity *e) {
1433 	// point all magic egg move frames to the standing one
1434 	e->movedownFrames =
1435 		e->moveleftFrames =
1436 		e->moverightFrames =
1437 		e->moveupFrames = 1;
1438 
1439 	e->movedownGfx[0] =
1440 		e->moveupGfx[0] =
1441 		e->moveleftGfx[0] =
1442 		e->moverightGfx[0] = e->standdownGfx[0];
1443 
1444 	e->draw = e->standdownGfx[0];			// standing frame - doesn't move
1445 }
1446 
aiMagicEggUse(AIEntity * e)1447 void aiMagicEggUse(AIEntity *e) {
1448 	if (!scumm_strnicmp(e->luaFuncAction, "ai_", 3) || !scumm_strnicmp(e->luaFuncAction, "item_", 5)) {
1449 		AIEntity *spawned = NULL;
1450 		for (int i = 0; aiEntList[i].type != END_AI_TYPES; ++i) {
1451 			if (!scumm_stricmp(aiEntList[i].luaName, e->luaFuncAction)) {
1452 				spawned = g_hdb->_ai->spawn(aiEntList[i].type, e->dir, e->tileX, e->tileY, NULL, NULL, NULL, DIR_NONE, e->level, 0, 0, 1);
1453 				break;
1454 			}
1455 		}
1456 
1457 		if (spawned) {
1458 			g_hdb->_ai->addAnimateTarget(e->tileX * kTileWidth,
1459 			e->tileY * kTileHeight, 0, 3, ANIM_NORMAL, false, false, GROUP_EXPLOSION_BOOM_SIT);
1460 
1461 			if (!g_hdb->isDemo())
1462 				g_hdb->_sound->playSound(SND_BARREL_EXPLODE);
1463 
1464 			g_hdb->_ai->removeEntity(e);
1465 		}
1466 	}
1467 }
1468 
aiIceBlockAction(AIEntity * e)1469 void aiIceBlockAction(AIEntity *e) {
1470 	// if ice block isn't moving somewhere, don't move it
1471 	if (!e->goalX)
1472 		return;
1473 
1474 	g_hdb->_ai->animateEntity(e);
1475 }
1476 
aiIceBlockInit(AIEntity * e)1477 void aiIceBlockInit(AIEntity *e) {
1478 	e->moveSpeed = kPushMoveSpeed;
1479 	e->aiAction = aiIceBlockAction;
1480 }
1481 
aiIceBlockInit2(AIEntity * e)1482 void aiIceBlockInit2(AIEntity *e) {
1483 	// point all ice block move frames to the standing one
1484 	e->movedownFrames =
1485 		e->moveleftFrames =
1486 		e->moverightFrames =
1487 		e->moveupFrames = 1;
1488 
1489 	e->movedownGfx[0] =
1490 		e->moveupGfx[0] =
1491 		e->moveleftGfx[0] =
1492 		e->moverightGfx[0] = e->standdownGfx[0];
1493 
1494 	e->draw = e->standdownGfx[0];			// standing frame - doesn't move
1495 }
1496 
aiCabKeyInit(AIEntity * e)1497 void aiCabKeyInit(AIEntity *e) {
1498 	strcpy(e->printedName, "a Cabinet key");
1499 }
1500 
aiCabKeyInit2(AIEntity * e)1501 void aiCabKeyInit2(AIEntity *e) {
1502 	e->draw = e->standdownGfx[0];
1503 }
1504 
aiItemChickenInit(AIEntity * e)1505 void aiItemChickenInit(AIEntity *e) {
1506 	strcpy(e->printedName, "Cooper's chicken");
1507 }
1508 
aiItemChickenInit2(AIEntity * e)1509 void aiItemChickenInit2(AIEntity *e) {
1510 	e->draw = e->standdownGfx[0];
1511 }
1512 
aiPdaInit(AIEntity * e)1513 void aiPdaInit(AIEntity *e) {
1514 	strcpy(e->printedName, "a P.D.A.");
1515 	e->aiAction = aiGetItemAction;
1516 }
1517 
aiPdaInit2(AIEntity * e)1518 void aiPdaInit2(AIEntity *e) {
1519 	e->draw = e->standdownGfx[0];
1520 }
1521 
1522 #if 0
1523 void aiCellUse(AIEntity *e) {
1524 	g_hdb->_window->openMessageBar("You got the Energy Cell!", kMsgDelay);
1525 }
1526 #endif
1527 
aiCellInit2(AIEntity * e)1528 void aiCellInit2(AIEntity *e) {
1529 	e->draw = e->standdownGfx[0];
1530 }
1531 
aiCellInit(AIEntity * e)1532 void aiCellInit(AIEntity *e) {
1533 	strcpy(e->printedName, "Energy Cell");
1534 	e->aiAction = aiGetItemAction;
1535 }
1536 
aiEnvelopeWhiteInit(AIEntity * e)1537 void aiEnvelopeWhiteInit(AIEntity *e) {
1538 	strcpy(e->printedName, "White envelope");
1539 	e->aiAction = aiGetItemAction;
1540 }
1541 
aiEnvelopeWhiteInit2(AIEntity * e)1542 void aiEnvelopeWhiteInit2(AIEntity *e) {
1543 	e->draw = e->standdownGfx[0];
1544 }
1545 
aiEnvelopeBlueInit(AIEntity * e)1546 void aiEnvelopeBlueInit(AIEntity *e) {
1547 	strcpy(e->printedName, "Blue envelope");
1548 	e->aiAction = aiGetItemAction;
1549 }
1550 
aiEnvelopeBlueInit2(AIEntity * e)1551 void aiEnvelopeBlueInit2(AIEntity *e) {
1552 	e->draw = e->standdownGfx[0];
1553 }
1554 
aiEnvelopeRedInit(AIEntity * e)1555 void aiEnvelopeRedInit(AIEntity *e) {
1556 	strcpy(e->printedName, "Red envelope");
1557 	e->aiAction = aiGetItemAction;
1558 }
1559 
aiEnvelopeRedInit2(AIEntity * e)1560 void aiEnvelopeRedInit2(AIEntity *e) {
1561 	e->draw = e->standdownGfx[0];
1562 }
1563 
aiTransceiverInit(AIEntity * e)1564 void aiTransceiverInit(AIEntity *e) {
1565 	e->aiAction = aiTransceiverAction;
1566 	strcpy(e->printedName, "Transceiver");
1567 }
1568 
aiTransceiverInit2(AIEntity * e)1569 void aiTransceiverInit2(AIEntity *e) {
1570 	e->draw = e->standdownGfx[0];
1571 }
1572 
aiTransceiverAction(AIEntity * e)1573 void aiTransceiverAction(AIEntity *e) {
1574 	aiAnimateStanddown(e, 5);
1575 	if (e->onScreen)
1576 		aiGetItemAction(e);
1577 }
1578 
1579 #if 0
1580 void aiTransceiverUse(AIEntity *e) {
1581 	g_hdb->_window->openMessageBar("You got the Transceiver!", kMsgDelay);
1582 }
1583 #endif
1584 
aiMonkeystoneInit(AIEntity * e)1585 void aiMonkeystoneInit(AIEntity *e) {
1586 	e->aiUse = aiMonkeystoneUse;
1587 	e->aiAction = aiMonkeystoneAction;
1588 }
1589 
aiMonkeystoneAction(AIEntity * e)1590 void aiMonkeystoneAction(AIEntity *e) {
1591 	if (!e->onScreen)
1592 		return;
1593 
1594 	AIEntity *p = g_hdb->_ai->getPlayer();
1595 	if (abs(p->x - e->x) < 16 && abs(p->y - e->y) < 16 && e->level == p->level) {
1596 		if (e->luaFuncUse[0])
1597 			g_hdb->_lua->callFunction(e->luaFuncUse, 0);
1598 
1599 		g_hdb->_ai->addToInventory(e);
1600 		aiMonkeystoneUse(NULL);
1601 	}
1602 }
1603 
aiMonkeystoneInit2(AIEntity * e)1604 void aiMonkeystoneInit2(AIEntity *e) {
1605 	e->draw = e->standdownGfx[0];
1606 }
1607 
aiMonkeystoneUse(AIEntity * e)1608 void aiMonkeystoneUse(AIEntity *e) {
1609 	int	val = g_hdb->_ai->getMonkeystoneAmount();
1610 	Common::String monkString = Common::String::format("You have %d Monkeystone%s!", val, (val > 1) ? "s" : "");
1611 	g_hdb->_sound->playSound(SND_GET_MONKEYSTONE);
1612 	g_hdb->_window->openMessageBar(monkString.c_str(), kMsgDelay);
1613 
1614 	// have we unlocked a secret star(tm)???
1615 	if (val == 7) {
1616 		g_hdb->_window->openMessageBar("Red Star is Ready!", kMsgDelay * 2);
1617 		g_hdb->setStarsMonkeystone7(STARS_MONKEYSTONE_7);
1618 		g_hdb->_menu->writeConfig();
1619 		g_hdb->_gfx->turnOnBonusStars(0);
1620 	}
1621 	if (val == 14) {
1622 		g_hdb->_window->openMessageBar("Green Star is GO!", kMsgDelay * 2);
1623 		g_hdb->setStarsMonkeystone14(STARS_MONKEYSTONE_14);
1624 		g_hdb->_menu->writeConfig();
1625 		g_hdb->_gfx->turnOnBonusStars(1);
1626 	}
1627 	if (val == 21) {
1628 		g_hdb->_window->openMessageBar("Blue Star is Born!", kMsgDelay * 2);
1629 		g_hdb->setStarsMonkeystone21(STARS_MONKEYSTONE_21);
1630 		g_hdb->_menu->writeConfig();
1631 		g_hdb->_gfx->turnOnBonusStars(2);
1632 	}
1633 }
1634 
aiGemAction(AIEntity * e)1635 void aiGemAction(AIEntity *e) {
1636 	e->animFrame++;
1637 	if (e->animFrame >= e->standdownFrames) {
1638 		e->animFrame = 0;
1639 
1640 		// every 4th frame, check for player collision &
1641 		// add to inventory if it happens
1642 		AIEntity *p = g_hdb->_ai->getPlayer();
1643 		int tolerance = 16;
1644 		if (g_hdb->_ai->playerRunning())
1645 			tolerance = 24;
1646 
1647 		if (e->onScreen && abs(p->x - e->x) < tolerance && abs(p->y - e->y) < tolerance && e->level == p->level) {
1648 			g_hdb->_ai->addAnimateTarget(e->x, e->y, 0, 3, ANIM_NORMAL, false, false, GEM_FLASH);
1649 			g_hdb->_ai->addToInventory(e);
1650 			g_hdb->_sound->playSound(SND_GET_GEM);
1651 			return;
1652 		}
1653 	}
1654 	e->draw = e->standdownGfx[e->animFrame];
1655 }
1656 
aiGemWhiteInit(AIEntity * e)1657 void aiGemWhiteInit(AIEntity *e) {
1658 	e->aiAction = aiGemAction;
1659 }
1660 
aiGemWhiteInit2(AIEntity * e)1661 void aiGemWhiteInit2(AIEntity *e) {
1662 	e->draw = e->standdownGfx[0];
1663 }
1664 
aiGooCupUse(AIEntity * e)1665 void aiGooCupUse(AIEntity *e) {
1666 	g_hdb->_window->openMessageBar("Got a... cup of goo.", kMsgDelay);
1667 }
1668 
aiGooCupInit(AIEntity * e)1669 void aiGooCupInit(AIEntity *e) {
1670 	e->aiUse = aiGooCupUse;
1671 	e->aiAction = aiGetItemAction;
1672 }
1673 
aiGooCupInit2(AIEntity * e)1674 void aiGooCupInit2(AIEntity *e) {
1675 	e->draw = e->standdownGfx[0];
1676 }
1677 
aiVortexianAction(AIEntity * e)1678 void aiVortexianAction(AIEntity *e) {
1679 	// anim the alpha blending : down to 32, up to 180, back down...
1680 	e->value2 += e->value1;
1681 	if ((e->value2 & 0xff) > 128) {
1682 		e->value2 = (e->value2 & 0xff00) | 128;
1683 		e->value1 = -e->value1;
1684 	} else if ((e->value2 & 0xff) < 32) {
1685 		e->value2 = (e->value2 & 0xff00) | 32;
1686 		e->value1 = -e->value1;
1687 	}
1688 
1689 	// anim the shape
1690 	e->animFrame++;
1691 	if (e->animFrame >= e->standdownFrames) {
1692 		e->animFrame = 0;
1693 
1694 		// every 4th frame, check for player collision &
1695 		// do an autosave
1696 		AIEntity *p = g_hdb->_ai->getPlayer();
1697 		if (abs(p->x - e->x) < 4 && abs(p->y - e->y) < 4) {
1698 			if (!(e->value2 & 0xff00)) {
1699 				// let's make sure we don't autosave every frikken second!
1700 				e->value2 |= 0xff00;
1701 
1702 				g_hdb->saveWhenReady(kAutoSaveSlot);
1703 				g_hdb->_window->openMessageBar("Saving progress at Vortexian...", 1);
1704 			}
1705 		} else
1706 			e->value2 &= 0x00ff;
1707 	}
1708 	e->draw = e->standdownGfx[e->animFrame];
1709 }
1710 
aiVortexianUse(AIEntity * e)1711 void aiVortexianUse(AIEntity *e) {
1712 }
1713 
aiVortexianInit(AIEntity * e)1714 void aiVortexianInit(AIEntity *e) {
1715 	e->aiUse = aiVortexianUse;
1716 	e->aiAction = aiVortexianAction;
1717 	e->value1 = 5;
1718 	e->value2 = 128;
1719 }
1720 
aiVortexianInit2(AIEntity * e)1721 void aiVortexianInit2(AIEntity *e) {
1722 	e->draw = e->standdownGfx[0];
1723 }
1724 
aiNoneInit(AIEntity * e)1725 void aiNoneInit(AIEntity *e) {
1726 }
1727 
1728 // Utility Functions
aiAnimateStanddown(AIEntity * e,int speed)1729 void aiAnimateStanddown(AIEntity *e, int speed) {
1730 	if (e->value2-- > 0)
1731 		return;
1732 	e->value2 = speed;
1733 
1734 	if (e->type == AI_GUY && e->animFrame > 0)
1735 		e->value2 = 0;
1736 	e->draw = e->standdownGfx[e->animFrame];
1737 	e->animFrame++;
1738 	if (e->animFrame >= e->standdownFrames)
1739 		e->animFrame = 0;
1740 }
1741 
aiGenericAction(AIEntity * e)1742 void aiGenericAction(AIEntity *e) {
1743 	if (!e->goalX)
1744 		g_hdb->_ai->findPath(e);
1745 	else if (onEvenTile(e->x, e->y))
1746 		g_hdb->_sound->playSound(SND_FOOTSTEPS);
1747 	g_hdb->_ai->animateEntity(e);
1748 }
1749 
aiGetItemAction(AIEntity * e)1750 void aiGetItemAction(AIEntity *e) {
1751 	if (!e->onScreen)
1752 		return;
1753 
1754 	AIEntity *p = g_hdb->_ai->getPlayer();
1755 	if (abs(p->x - e->x) < 16 && abs(p->y - e->y) < 16 && e->level == p->level) {
1756 		if (e->aiUse)
1757 			e->aiUse(e);
1758 		if (e->luaFuncUse[0])
1759 			g_hdb->_lua->callFunction(e->luaFuncUse, 0);
1760 
1761 		g_hdb->_ai->getItemSound(e->type);
1762 		g_hdb->_ai->addToInventory(e);
1763 	}
1764 }
1765 
1766 } // End of Namespace
1767