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  *              Originally written by Syn9 in FreeBASIC with SDL
23  *              http://syn9.thehideoutgames.com/index_backup.php
24  *
25  *            Ported to plain C for GCW-Zero handheld by Dmitry Smagin
26  *                http://github.com/dmitrysmagin/griffon_legend
27  *
28  *
29  *                 Programming/Graphics: Daniel "Syn9" Kennedy
30  *                     Music/Sound effects: David Turner
31  *
32  *                   Beta testing and gameplay design help:
33  *                    Deleter, Cha0s, Aether Fox, and Kiz
34  *
35  */
36 
37 #include "griffon/griffon.h"
38 
39 namespace Griffon {
40 
41 // memo
42 
43 /*
44  chests
45   0 - regular flask
46  11 - key chest
47  14 - blue flask chest
48  15 - lightning chest
49  16 - armour chest
50  17 - citadel master key
51  18 - sword3
52  19 - shield3
53  20 - armour3
54 
55 */
56 
57 // element tile locations
58 const int8 elementmap[15][20] = {
59 	{  2, 2, 2, 2, -1, -1, -1, 2, 2, 2, 2, 2, 2, -1, -1, -1, -1, -1, -1, -1 },
60 	{  2, -1, -1, -1, -1, -1, -1, 2, 2, 2, 2, 2, 2, -1, -1, -1, -1, -1, -1, -1 },
61 	{  2, -1, 2, 2, -1, -1, -1, 2, 2, 2, 2, 2, 2, -1, -1, -1, -1, -1, -1, -1 },
62 	{  2, -1, 2, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
63 	{  2, 2, 2, 2, 2, -1, -1, -1, 2, -1, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1 },
64 	{ -1, -1, -1, -1, 2, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
65 	{ -1, -1, -1, -1, -1, 0, 0, 2, 2, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
66 	{ -1, -1, -1, -1, -1, 2, 2, 2, 2, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
67 	{ -1, -1, -1, -1, -1, 2, 2, 2, 2, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
68 	{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
69 	{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
70 	{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
71 	{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
72 	{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
73 	{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }
74 };
75 
76 
updateAnims()77 void GriffonEngine::updateAnims() {
78 	for (int i = 0; i <= _lastObj; i++) {
79 		int nFrames = _objectInfo[i].nFrames;
80 		int objAnimSpeed = _objectInfo[i].speed;
81 		float frame = _objectFrame[i][0];
82 
83 		if (nFrames > 1) {
84 			frame += objAnimSpeed / 50 * _fpsr;
85 			while (frame >= nFrames)
86 				frame -= nFrames;
87 
88 			int cframe = (int)frame; // truncate fractional part
89 			if (cframe < 0)
90 				cframe = 0;
91 
92 			_objectFrame[i][0] = frame;
93 			_objectFrame[i][1] = cframe;
94 		}
95 	}
96 }
97 
updateY()98 void GriffonEngine::updateY() {
99 	for (int i = 0; i <= 2400; i++)
100 		_ysort[i] = -1;
101 
102 	int ff = (int)(_player.py * 10);
103 	if (ff < 0) // HACKFIX or _ysort[yy] may go out of bounds
104 		ff = 0;
105 	_player.ysort = ff;
106 	_ysort[ff] = 0;
107 
108 	_firsty = 2400;
109 	_lasty = 0;
110 
111 	for (int i = 1; i <= _lastNpc; i++) {
112 		if (!_npcInfo[i].onMap)
113 			continue;
114 
115 		int yy = (int)(_npcInfo[i].y * 10);
116 
117 		do {
118 			if (_ysort[yy] == -1 || yy == 2400)
119 				break;
120 			++yy;
121 		} while (1);
122 
123 		_ysort[yy] = i;
124 		if (yy < _firsty)
125 			_firsty = yy;
126 		if (yy > _lasty)
127 			_lasty = yy;
128 	}
129 }
130 
updateNPCs()131 void GriffonEngine::updateNPCs() {
132 	for (int i = 1; i <= _lastNpc; i++) {
133 		if (_npcInfo[i].hp > 0) {
134 			//  is npc walking
135 			int pass = 0;
136 			if (!_npcInfo[i].attacking)
137 				pass = 1;
138 			if (_npcInfo[i].spriteset == kMonsterFireHydra)
139 				pass = 1;
140 			if (pass == 1) {
141 				bool moveup = false;
142 				bool movedown = false;
143 				bool moveleft = false;
144 				bool moveright = false;
145 
146 				float npx = _npcInfo[i].x;
147 				float npy = _npcInfo[i].y;
148 
149 				float onpx = npx;
150 				float onpy = npy;
151 
152 				float wspd = _npcInfo[i].walkspd / 4;
153 
154 				if (_npcInfo[i].spriteset == kMonsterDragon2)
155 					wspd = wspd * 2;
156 				int wdir = _npcInfo[i].walkdir;
157 
158 				int mode = _npcInfo[i].movementmode;
159 
160 				float xdif = _player.px - npx;
161 				float ydif = _player.py - npy;
162 
163 				if (ABS(xdif) < 4 * 16 && ABS(ydif) < 4 * 16 && mode < 3)
164 					mode = 0;
165 				if (_npcInfo[i].hp < _npcInfo[i].maxhp * 0.25)
166 					mode = 3;
167 
168 				if (_npcInfo[i].pause > _ticks)
169 					mode = -1;
170 				if (_npcInfo[i].spriteset == kMonsterOneWing && _npcInfo[i].castPause > _ticks)
171 					mode = -1;
172 
173 				if (mode == 3) {
174 					mode = 1;
175 					if (ABS(xdif) < 4 * 16 && ABS(ydif) < 4 * 16)
176 						mode = 3;
177 				}
178 
179 				bool checkpass = false;
180 
181 				// npc  AI CODE
182 				// --------------
183 
184 				// *** aggressive
185 				if (mode == 0) {
186 					wspd = _npcInfo[i].walkspd / 2;
187 
188 					xdif = _player.px - npx;
189 					ydif = _player.py - npy;
190 
191 					if (ABS(xdif) > ABS(ydif)) {
192 						if (xdif < 4)
193 							wdir = 2;
194 						if (xdif > -4)
195 							wdir = 3;
196 					} else {
197 						if (ydif < 4)
198 							wdir = 0;
199 						if (ydif > -4)
200 							wdir = 1;
201 					}
202 
203 					if (xdif < 4)
204 						moveleft = true;
205 					if (xdif > -4)
206 						moveright = true;
207 					if (ydif < 4)
208 						moveup = true;
209 					if (ydif > -4)
210 						movedown = true;
211 				}
212 				// *******************
213 
214 				// *** defensive
215 				if (mode == 1) {
216 
217 					int movingdir = _npcInfo[i].movingdir;
218 
219 					if (_npcInfo[i].ticks > _ticks + 100000)
220 						_npcInfo[i].ticks = _ticks;
221 
222 					if (_npcInfo[i].ticks < _ticks) {
223 						_npcInfo[i].ticks = _ticks + 2000;
224 						movingdir = (int)(RND() * 8);
225 						_npcInfo[i].movingdir = movingdir;
226 					}
227 
228 					if (movingdir == 0) {
229 						wdir = 2; // left
230 						moveup = true;
231 						moveleft = true;
232 					} else if (movingdir == 1) {
233 						wdir = 0; // up
234 						moveup = true;
235 					} else if (movingdir == 2) {
236 						wdir = 3; // right
237 						moveup = true;
238 						moveright = true;
239 					} else if (movingdir == 3) {
240 						wdir = 3; // right
241 						moveright = true;
242 					} else if (movingdir == 4) {
243 						wdir = 3; // right
244 						moveright = true;
245 						movedown = true;
246 					} else if (movingdir == 5) {
247 						wdir = 1; // down
248 						movedown = true;
249 					} else if (movingdir == 6) {
250 						wdir = 2; // left
251 						movedown = true;
252 						moveleft = true;
253 					} else if (movingdir == 7) {
254 						wdir = 2; // left
255 						moveleft = true;
256 					}
257 
258 					checkpass = true;
259 				}
260 				// *******************
261 
262 				// *** run away
263 				if (mode == 3) {
264 					wspd = _npcInfo[i].walkspd / 2;
265 
266 					xdif = _player.px - npx;
267 					ydif = _player.py - npy;
268 
269 					if (ABS(xdif) > ABS(ydif)) {
270 						if (xdif < 4)
271 							wdir = 3;
272 						if (xdif > -4)
273 							wdir = 2;
274 					} else {
275 						if (ydif < 4)
276 							wdir = 1;
277 						if (ydif > -4)
278 							wdir = 0;
279 					}
280 
281 					if (xdif < 4)
282 						moveright = true;
283 					if (xdif > -4)
284 						moveleft = true;
285 					if (ydif < 4)
286 						movedown = true;
287 					if (ydif > -4)
288 						moveup = true;
289 				}
290 				// *******************
291 
292 				// -------------- ?? move*** vs movin***
293 				bool movinup = false;
294 				bool movindown = false;
295 				bool movinleft = false;
296 				bool movinright = false;
297 
298 				float xp = (npx / 2 + 6);
299 				float yp = (npy / 2 + 10);
300 
301 				if (_npcInfo[i].spriteset == kMonsterDragon2)
302 					wspd = wspd * 2;
303 
304 				float ii = wspd * _fpsr;
305 				if (ii < 1)
306 					ii = 1;
307 
308 				if (moveup) {
309 					int sx = xp;
310 					int sy = yp - ii;
311 					uint32 *temp = (uint32 *)_clipBg->getBasePtr(sx, sy);
312 					uint32 dq = *temp;
313 					if (_npcInfo[i].spriteset == kMonsterFinalBoss)
314 						dq = 0;
315 
316 					if (dq == 0)
317 						movinup = true;
318 					if (dq > 0) {
319 						sx = xp - ii;
320 						sy = yp - ii;
321 						temp = (uint32 *)_clipBg->getBasePtr(sx, sy);
322 						dq = *temp;
323 						if (_npcInfo[i].spriteset == kMonsterFinalBoss)
324 							dq = 0;
325 						if (dq == 0) {
326 							movinup = true;
327 							movinleft = true;
328 						}
329 					}
330 					if (dq > 0) {
331 						sx = xp + ii;
332 						sy = yp - ii;
333 						temp = (uint32 *)_clipBg->getBasePtr(sx, sy);
334 						dq = *temp;
335 						if (_npcInfo[i].spriteset == kMonsterFinalBoss)
336 							dq = 0;
337 						if (dq == 0) {
338 							movinup = true;
339 							movinright = true;
340 						}
341 					}
342 				}
343 
344 				if (movedown) {
345 					int sx = xp;
346 					int sy = yp + ii;
347 					uint32 *temp = (uint32 *)_clipBg->getBasePtr(sx, sy);
348 					uint32 dq = *temp;
349 					if (_npcInfo[i].spriteset == kMonsterFinalBoss)
350 						dq = 0;
351 					if (dq == 0)
352 						movindown = true;
353 					if (dq > 0) {
354 						sx = xp - ii;
355 						sy = yp + ii;
356 						temp = (uint32 *)_clipBg->getBasePtr(sx, sy);
357 						dq = *temp;
358 						if (_npcInfo[i].spriteset == kMonsterFinalBoss)
359 							dq = 0;
360 						if (dq == 0) {
361 							movindown = true;
362 							movinleft = true;
363 						}
364 					}
365 					if (dq > 0) {
366 						sx = xp + ii;
367 						sy = yp + ii;
368 						temp = (uint32 *)_clipBg->getBasePtr(sx, sy);
369 						dq = *temp;
370 						if (_npcInfo[i].spriteset == kMonsterFinalBoss)
371 							dq = 0;
372 						if (dq == 0) {
373 							movindown = true;
374 							movinright = true;
375 						}
376 					}
377 				}
378 
379 				if (moveleft) {
380 					int sx = xp - ii;
381 					int sy = yp;
382 					uint32 *temp = (uint32 *)_clipBg->getBasePtr(sx, sy);
383 					uint32 dq = *temp;
384 					if (_npcInfo[i].spriteset == kMonsterFinalBoss)
385 						dq = 0;
386 					if (dq == 0)
387 						movinleft = true;
388 					if (dq > 0) {
389 						sx = xp - ii;
390 						sy = yp - ii;
391 						temp = (uint32 *)_clipBg->getBasePtr(sx, sy);
392 						dq = *temp;
393 						if (_npcInfo[i].spriteset == kMonsterFinalBoss)
394 							dq = 0;
395 						if (dq == 0) {
396 							movinleft = true;
397 							movinup = true;
398 						}
399 					}
400 					if (dq > 0) {
401 						sx = xp - ii;
402 						sy = yp + ii;
403 						temp = (uint32 *)_clipBg->getBasePtr(sx, sy);
404 						dq = *temp;
405 						if (_npcInfo[i].spriteset == kMonsterFinalBoss)
406 							dq = 0;
407 						if (dq == 0) {
408 							movinleft = true;
409 							movindown = true;
410 						}
411 					}
412 				}
413 
414 				if (moveright) {
415 					int sx = xp + ii;
416 					int sy = yp;
417 					uint32 *temp = (uint32 *)_clipBg->getBasePtr(sx, sy);
418 					uint32 dq = *temp;
419 					if (_npcInfo[i].spriteset == kMonsterFinalBoss)
420 						dq = 0;
421 					if (dq == 0)
422 						movinright = true;
423 					if (dq > 0) {
424 						sx = xp + ii;
425 						sy = yp - ii;
426 						temp = (uint32 *)_clipBg->getBasePtr(sx, sy);
427 						dq = *temp;
428 						if (_npcInfo[i].spriteset == kMonsterFinalBoss)
429 							dq = 0;
430 						if (dq == 0) {
431 							movinright = true;
432 							movinup = true;
433 						}
434 					}
435 					if (dq > 0) {
436 						sx = xp + ii;
437 						sy = yp + ii;
438 						temp = (uint32 *)_clipBg->getBasePtr(sx, sy);
439 						dq = *temp;
440 						if (_npcInfo[i].spriteset == kMonsterFinalBoss)
441 							dq = 0;
442 						if (dq == 0) {
443 							movinright = true;
444 							movindown = true;
445 						}
446 					}
447 				}
448 
449 				if (movinup)
450 					npy -= wspd * _fpsr;
451 				if (movindown)
452 					npy += wspd * _fpsr;
453 				if (movinleft)
454 					npx -= wspd * _fpsr;
455 				if (movinright)
456 					npx += wspd * _fpsr;
457 
458 				if (checkpass) {
459 					pass = 0;
460 					if (npx >= _npcInfo[i].x1 * 16 - 8 && npx <= _npcInfo[i].x2 * 16 + 8 && npy >= _npcInfo[i].y1 * 16 - 8 && npy <= _npcInfo[i].y2 * 16 + 8)
461 						pass = 1;
462 					if (pass == 0) {
463 						npx = onpx;
464 						npy = onpy;
465 						_npcInfo[i].ticks = _ticks;
466 					}
467 				}
468 
469 				float aspd = wspd;
470 
471 				if (_npcInfo[i].spriteset == kMonsterDragon2)
472 					aspd = wspd / 2;
473 
474 				xp = (npx / 2 + 6);
475 				yp = (npy / 2 + 10);
476 
477 				int sx = xp;
478 				int sy = yp;
479 				uint32 *temp = (uint32 *)_clipBg->getBasePtr(sx, sy);
480 				uint32 bgc = *temp;
481 
482 				float anpx = npx + 12;
483 				float anpy = npy + 20;
484 
485 				int lx = (int)anpx / 16;
486 				int ly = (int)anpy / 16;
487 
488 				if (_triggerLoc[lx][ly] > -1)
489 					bgc = 1;
490 				if (_npcInfo[i].spriteset == kMonsterFinalBoss)
491 					bgc = 0;
492 
493 				bool rst = false;
494 
495 				if (_npcInfo[i].spriteset == kMonsterFinalBoss) {
496 					if (npx < 40 || npx > 280 || npy < 36 || npy > 204)
497 						rst = true;
498 				}
499 
500 				if (bgc > 0 || rst) {
501 					npx = onpx;
502 					npy = onpy;
503 				}
504 
505 				_npcInfo[i].x = npx;
506 				_npcInfo[i].y = npy;
507 
508 				_npcInfo[i].walkdir = wdir;
509 				_npcInfo[i].moving = false;
510 
511 				if (npx != onpx || npy != onpy)
512 					_npcInfo[i].moving = true;
513 
514 				if (_npcInfo[i].moving) {
515 					float frame = _npcInfo[i].frame;
516 
517 					frame += aspd * _fpsr;
518 					while (frame >= 16)
519 						frame -= 16;
520 
521 					int cframe = (int)(frame);
522 					if (cframe < 0)
523 						cframe = 0;
524 
525 					_npcInfo[i].frame = frame;
526 					_npcInfo[i].cframe = cframe;
527 				}
528 
529 				// spriteset1 specific
530 				if (_npcInfo[i].spriteset == kMonsterBabyDragon && _npcInfo[i].attackattempt < _ticks) {
531 					if (_npcInfo[i].attacknext < _ticks && _npcInfo[i].pause < _ticks && !_npcInfo[i].attacking) {
532 						npx = _npcInfo[i].x;
533 						npy = _npcInfo[i].y;
534 
535 						xdif = _player.px - npx;
536 						ydif = _player.py - npy;
537 
538 						if (ABS(xdif) < 20 && ABS(ydif) < 20) {
539 							_npcInfo[i].attackattempt = _ticks + 100;
540 							if ((int)(RND() * 2) == 0) {
541 								if (config.effects) {
542 									int snd = playSound(_sfx[kSndEnemyHit]);
543 									setChannelVolume(snd, config.effectsVol);
544 								}
545 
546 								_npcInfo[i].attacking = true;
547 								_npcInfo[i].attackframe = 0;
548 							}
549 						}
550 					}
551 				}
552 
553 				bool dospell = false;
554 
555 				// onewing specific
556 				if (_npcInfo[i].spriteset == kMonsterOneWing) {
557 					if (_npcInfo[i].attacknext < _ticks && _npcInfo[i].pause < _ticks && !_npcInfo[i].attacking) {
558 						npx = _npcInfo[i].x;
559 						npy = _npcInfo[i].y;
560 
561 						xdif = _player.px - npx;
562 						ydif = _player.py - npy;
563 
564 						if (ABS(xdif) < 24 && ABS(ydif) < 24) {
565 							float dist = sqrt(xdif * xdif + ydif * ydif);
566 
567 							if ((dist) < 24) {
568 								if (config.effects) {
569 									int snd = playSound(_sfx[kSndBite]);
570 									setChannelVolume(snd, config.effectsVol);
571 								}
572 
573 								_npcInfo[i].attacking = true;
574 								_npcInfo[i].attackframe = 0;
575 
576 								_npcInfo[i].headTargetX[0] = _player.px + 12;
577 								_npcInfo[i].headTargetY[0] = _player.py - 4;
578 							}
579 						}
580 
581 					}
582 
583 					dospell = false;
584 
585 					if (!_npcInfo[i].attacking && _npcInfo[i].castPause < _ticks) {
586 						_npcInfo[i].swaySpeed = _npcInfo[i].swaySpeed + _npcInfo[i].swaySpeed / 200 * _fpsr;
587 						if (_npcInfo[i].swaySpeed > 15) {
588 							dospell = true;
589 							_npcInfo[i].swaySpeed = 1;
590 						}
591 
592 						// sway code
593 						_npcInfo[i].swayAngle = _npcInfo[i].swayAngle + _npcInfo[i].swaySpeed * _fpsr;
594 						if (_npcInfo[i].swayAngle >= 360)
595 							_npcInfo[i].swayAngle = _npcInfo[i].swayAngle - 360;
596 
597 						_npcInfo[i].headTargetX[0] = _npcInfo[i].x + (24 - _npcInfo[i].swaySpeed / 2) * sin(3.14159 / 180 * _npcInfo[i].swayAngle) + 12;
598 						_npcInfo[i].headTargetY[0] = _npcInfo[i].y - 36 + 16 + 8 * sin(3.14159 * 2 / 180 * _npcInfo[i].swayAngle);
599 					}
600 
601 					if (dospell) {
602 						_npcInfo[i].pause = _ticks + 3000;
603 						_npcInfo[i].attacknext = _ticks + 4500;
604 						_npcInfo[i].castPause = _ticks + 4500;
605 
606 						castSpell(3, _npcInfo[i].x, _npcInfo[i].y, _npcInfo[i].x, _npcInfo[i].y, i);
607 
608 						_npcInfo[i].headTargetX[0] = _npcInfo[i].x;
609 						_npcInfo[i].headTargetY[0] = _npcInfo[i].y - 36 + 16;
610 					}
611 
612 					// targethead code
613 					xdif = _npcInfo[i].bodysection[7].x - _npcInfo[i].headTargetX[0];
614 					ydif = _npcInfo[i].bodysection[7].y - _npcInfo[i].headTargetY[0];
615 
616 
617 					_npcInfo[i].bodysection[7].x = _npcInfo[i].bodysection[7].x  - xdif * 0.4 * _fpsr;
618 					_npcInfo[i].bodysection[7].y = _npcInfo[i].bodysection[7].y  - ydif * 0.4 * _fpsr;
619 
620 
621 					_npcInfo[i].bodysection[0].x = _npcInfo[i].x + 12;
622 					_npcInfo[i].bodysection[0].y = _npcInfo[i].y + 12;
623 
624 					for (int f = 6; f >= 1; f--) {
625 						xdif = _npcInfo[i].bodysection[f + 1].x - _npcInfo[i].bodysection[f - 1].x;
626 						ydif = _npcInfo[i].bodysection[f + 1].y - _npcInfo[i].bodysection[f - 1].y;
627 
628 						float tx = _npcInfo[i].bodysection[f - 1].x + xdif / 2;
629 						float ty = _npcInfo[i].bodysection[f - 1].y + ydif / 2;
630 
631 						_npcInfo[i].bodysection[f].x = _npcInfo[i].bodysection[f].x - (_npcInfo[i].bodysection[f].x - tx) / 3;
632 						_npcInfo[i].bodysection[f].y = _npcInfo[i].bodysection[f].y - (_npcInfo[i].bodysection[f].y - ty) / 3;
633 					}
634 				}
635 
636 				// boss1 specific and blackknight
637 				if (_npcInfo[i].spriteset == kMonsterBoss1 || _npcInfo[i].spriteset == kMonsterBlackKnight) {
638 					if (_npcInfo[i].attacknext < _ticks && _npcInfo[i].pause < _ticks && !_npcInfo[i].attacking) {
639 						_npcInfo[i].attacking = true;
640 						_npcInfo[i].attackframe = 0;
641 
642 						castSpell(1, _npcInfo[i].x, _npcInfo[i].y, _player.px, _player.py, i);
643 					}
644 
645 					if (_npcInfo[i].castPause < _ticks) {
646 						castSpell(6, _npcInfo[i].x, _npcInfo[i].y, _player.px, _player.py, i);
647 						_npcInfo[i].castPause = _ticks + 12000;
648 					}
649 				}
650 
651 
652 				// firehydra specific
653 				if (_npcInfo[i].spriteset == kMonsterFireHydra) {
654 					_npcInfo[i].swaySpeed = 4;
655 
656 					// sway code
657 					_npcInfo[i].swayAngle = _npcInfo[i].swayAngle + _npcInfo[i].swaySpeed * _fpsr;
658 					if (_npcInfo[i].swayAngle >= 360)
659 						_npcInfo[i].swayAngle = _npcInfo[i].swayAngle - 360;
660 
661 					for (int ff = 0; ff <= 2; ff++) {
662 						if (_npcInfo[i].hp > 10 * ff * 20) {
663 							if (_npcInfo[i].pause < _ticks && _npcInfo[i].attacking2[ff] == 0 && _npcInfo[i].attacknext2[ff] < _ticks) {
664 								npx = _npcInfo[i].x;
665 								npy = _npcInfo[i].y;
666 
667 								xdif = _player.px - npx;
668 								ydif = _player.py - npy;
669 
670 								if (ABS(xdif) < 48 && ABS(ydif) < 48) {
671 									float dist = sqrt(xdif * xdif + ydif * ydif);
672 
673 									if ((dist) < 36) {
674 										if (config.effects) {
675 											int snd = playSound(_sfx[kSndBite]);
676 											setChannelVolume(snd, config.effectsVol);
677 										}
678 
679 										_npcInfo[i].attacking = true;
680 										_npcInfo[i].attacking2[ff] = 1;
681 										_npcInfo[i].attackframe2[ff] = 0;
682 
683 										_npcInfo[i].headTargetX[ff] = _player.px + 12;
684 										_npcInfo[i].headTargetY[ff] = _player.py - 4;
685 
686 										_npcInfo[i].swayAngle = 0;
687 									}
688 								}
689 
690 							}
691 
692 							if (_npcInfo[i].attacking2[ff] == 0) {
693 								_npcInfo[i].headTargetX[ff] = _npcInfo[i].x + 38 * sin(3.14159 / 180 * (_npcInfo[i].swayAngle + 120 * ff)) + 12;
694 								_npcInfo[i].headTargetY[ff] = _npcInfo[i].y - 46 + 16 + 16 * sin(3.14159 * 2 / 180 * (_npcInfo[i].swayAngle + 120 * ff));
695 							}
696 
697 							// targethead code
698 							xdif = _npcInfo[i].bodysection[10 * ff + 9].x - _npcInfo[i].headTargetX[ff];
699 							ydif = _npcInfo[i].bodysection[10 * ff + 9].y - _npcInfo[i].headTargetY[ff];
700 
701 							_npcInfo[i].bodysection[10 * ff + 9].x = _npcInfo[i].bodysection[10 * ff + 9].x  - xdif * 0.4 * _fpsr;
702 							_npcInfo[i].bodysection[10 * ff + 9].y = _npcInfo[i].bodysection[10 * ff + 9].y  - ydif * 0.4 * _fpsr;
703 
704 							_npcInfo[i].bodysection[10 * ff].x = _npcInfo[i].x + 12 + 8 * cos(3.141592 * 2 * (_itemyloc / 16 + ff * 120 / 360));
705 							_npcInfo[i].bodysection[10 * ff].y = _npcInfo[i].y + 12 + 8 * sin(3.141592 * 2 * (_itemyloc / 16 + ff * 120 / 360));
706 
707 							for (int f = 8; f >= 1; f--) {
708 								xdif = _npcInfo[i].bodysection[ff * 10 + f + 1].x - _npcInfo[i].bodysection[ff * 10 + f - 1].x;
709 								ydif = _npcInfo[i].bodysection[ff * 10 + f + 1].y - _npcInfo[i].bodysection[ff * 10 + f - 1].y;
710 
711 								float tx = _npcInfo[i].bodysection[ff * 10 + f - 1].x + xdif / 2;
712 								float ty = _npcInfo[i].bodysection[ff * 10 + f - 1].y + ydif / 2;
713 
714 								_npcInfo[i].bodysection[ff * 10 + f].x = _npcInfo[i].bodysection[ff * 10 + f].x - (_npcInfo[i].bodysection[ff * 10 + f].x - tx) / 3;
715 								_npcInfo[i].bodysection[ff * 10 + f].y = _npcInfo[i].bodysection[ff * 10 + f].y - (_npcInfo[i].bodysection[ff * 10 + f].y - ty) / 3;
716 							}
717 						}
718 					}
719 				}
720 
721 				// spriteset6 specific
722 				if (_npcInfo[i].spriteset == kMonsterRedDragon && _npcInfo[i].attackattempt < _ticks) {
723 					if (_npcInfo[i].attacknext < _ticks && _npcInfo[i].pause < _ticks && !_npcInfo[i].attacking) {
724 						npx = _npcInfo[i].x;
725 						npy = _npcInfo[i].y;
726 
727 						xdif = _player.px - npx;
728 						ydif = _player.py - npy;
729 
730 						pass = 0;
731 						if (ABS(xdif) < 48 && ABS(ydif) < 6)
732 							pass = 1;
733 						if (ABS(ydif) < 48 && ABS(xdif) < 6)
734 							pass = 2;
735 
736 						if (pass > 0) {
737 							_npcInfo[i].attackattempt = _ticks + 100;
738 							if ((int)(RND() * 2) == 0) {
739 								_npcInfo[i].attacking = true;
740 								_npcInfo[i].attackframe = 0;
741 								float nnxa = 0, nnya = 0, nnxb = 0, nnyb = 0;
742 
743 								if (pass == 1 && xdif < 0) {
744 									nnxa = npx - 8;
745 									nnya = npy + 4;
746 									nnxb = npx - 48 - 8;
747 									nnyb = npy + 4;
748 								} else if (pass == 1 && xdif > 0) {
749 									nnxa = npx + 16;
750 									nnya = npy + 4;
751 									nnxb = npx + 16 + 48;
752 									nnyb = npy + 4;
753 								} else if (pass == 2 && ydif < 0) {
754 									nnya = npy;
755 									nnxa = npx + 4;
756 									nnyb = npy - 48;
757 									nnxb = npx + 4;
758 								} else if (pass == 2 && ydif > 0) {
759 									nnya = npy + 20;
760 									nnxa = npx + 4;
761 									nnyb = npy + 20 + 48;
762 									nnxb = npx + 4;
763 								}
764 
765 								castSpell(7, nnxa, nnya, nnxb, nnyb, i);
766 							}
767 						}
768 					}
769 				}
770 
771 				// wizard1 specific
772 				if (_npcInfo[i].spriteset == kMonsterPriest) {
773 					if (_npcInfo[i].attacknext < _ticks && _npcInfo[i].pause < _ticks && !_npcInfo[i].attacking) {
774 						_npcInfo[i].attacking = true;
775 						_npcInfo[i].attackframe = 0;
776 
777 						castSpell(9, _npcInfo[i].x, _npcInfo[i].y, _player.px, _player.py, i);
778 					}
779 
780 					if (_npcInfo[i].castPause < _ticks) {
781 						// castSpell 6, _npcinfo[i].x, _npcinfo[i].y, _player.px, _player.py, i
782 						// _npcinfo[i].castpause = _ticks + 12000
783 					}
784 
785 				}
786 
787 				// spriteset6 specific
788 				if (_npcInfo[i].spriteset == kMonsterYellowDragon && _npcInfo[i].attackattempt < _ticks) {
789 					if (_npcInfo[i].attacknext < _ticks && _npcInfo[i].pause < _ticks && !_npcInfo[i].attacking) {
790 						npx = _npcInfo[i].x;
791 						npy = _npcInfo[i].y;
792 
793 						xdif = _player.px - npx;
794 						ydif = _player.py - npy;
795 
796 						pass = 0;
797 						if (ABS(xdif) < 56 && ABS(ydif) < 6)
798 							pass = 1;
799 						if (ABS(ydif) < 56 && ABS(xdif) < 6)
800 							pass = 2;
801 
802 						if (pass > 0) {
803 							_npcInfo[i].attackattempt = _ticks + 100;
804 							if ((int)(RND() * 2) == 0) {
805 								_npcInfo[i].attacking = true;
806 								_npcInfo[i].attackframe = 0;
807 
808 								float nnxa = 0, nnya = 0, nnxb = 0, nnyb = 0;
809 								if (pass == 1 && xdif < 0) {
810 									nnxa = npx - 8;
811 									nnya = npy + 4;
812 									nnxb = npx - 56 - 8;
813 									nnyb = npy + 4;
814 									_npcInfo[i].walkdir = 2;
815 								} else if (pass == 1 && xdif > 0) {
816 									nnxa = npx + 16;
817 									nnya = npy + 4;
818 									nnxb = npx + 16 + 56;
819 									nnyb = npy + 4;
820 									_npcInfo[i].walkdir = 3;
821 								} else if (pass == 2 && ydif < 0) {
822 									nnya = npy;
823 									nnxa = npx + 4;
824 									nnyb = npy - 56;
825 									nnxb = npx + 4;
826 									_npcInfo[i].walkdir = 0;
827 								} else if (pass == 2 && ydif > 0) {
828 									nnya = npy + 20;
829 									nnxa = npx + 4;
830 									nnyb = npy + 20 + 56;
831 									nnxb = npx + 4;
832 									_npcInfo[i].walkdir = 1;
833 								}
834 
835 								castSpell(7, nnxa, nnya, nnxb, nnyb, i);
836 							}
837 						}
838 					}
839 				}
840 
841 				// twowing specific
842 				if (_npcInfo[i].spriteset == kMonsterTwoWing) {
843 					if (_npcInfo[i].attacknext < _ticks && _npcInfo[i].pause < _ticks && !_npcInfo[i].attacking) {
844 						npx = _npcInfo[i].bodysection[7].x;
845 						npy = _npcInfo[i].bodysection[7].y;
846 
847 						xdif = _player.px - npx;
848 						ydif = _player.py - npy;
849 
850 						if (ABS(xdif) < 24 && ABS(ydif) < 24) {
851 							float dist = sqrt(xdif * xdif + ydif * ydif);
852 
853 							if ((dist) < 24) {
854 								if (config.effects) {
855 									int snd = playSound(_sfx[kSndBite]);
856 									setChannelVolume(snd, config.effectsVol);
857 								}
858 
859 								_npcInfo[i].attacking = true;
860 								_npcInfo[i].attackframe = 0;
861 
862 								_npcInfo[i].headTargetX[0] = _player.px + 12;
863 								_npcInfo[i].headTargetY[0] = _player.py - 4;
864 							}
865 						}
866 
867 					}
868 
869 					if (!_npcInfo[i].attacking && _npcInfo[i].castPause < _ticks) {
870 						_npcInfo[i].swaySpeed = 4;
871 
872 						// sway code
873 						_npcInfo[i].swayAngle = _npcInfo[i].swayAngle + _npcInfo[i].swaySpeed * _fpsr;
874 						if (_npcInfo[i].swayAngle >= 360)
875 							_npcInfo[i].swayAngle = _npcInfo[i].swayAngle - 360;
876 
877 						_npcInfo[i].headTargetX[0] = _npcInfo[i].x + (24 - _npcInfo[i].swaySpeed / 2) * sin(3.14159 / 180 * _npcInfo[i].swayAngle) + 12;
878 						_npcInfo[i].headTargetY[0] = _npcInfo[i].y - 36 + 16 + 8 * sin(3.14159 * 2 / 180 * _npcInfo[i].swayAngle);
879 					}
880 
881 					if (dospell) {
882 						_npcInfo[i].pause = _ticks + 3000;
883 						_npcInfo[i].attacknext = _ticks + 5000;
884 						_npcInfo[i].castPause = _ticks + 3000;
885 
886 						castSpell(3, _npcInfo[i].x, _npcInfo[i].y, _npcInfo[i].x, _npcInfo[i].y, i);
887 
888 						_npcInfo[i].headTargetX[0] = _npcInfo[i].x;
889 						_npcInfo[i].headTargetY[0] = _npcInfo[i].y - 36 + 16;
890 					}
891 
892 					// targethead code
893 					xdif = _npcInfo[i].bodysection[7].x - _npcInfo[i].headTargetX[0];
894 					ydif = _npcInfo[i].bodysection[7].y - _npcInfo[i].headTargetY[0];
895 
896 
897 					_npcInfo[i].bodysection[7].x = _npcInfo[i].bodysection[7].x  - xdif * 0.4 * _fpsr;
898 					_npcInfo[i].bodysection[7].y = _npcInfo[i].bodysection[7].y  - ydif * 0.4 * _fpsr;
899 
900 					_npcInfo[i].bodysection[0].x = _npcInfo[i].x + 12;
901 					_npcInfo[i].bodysection[0].y = _npcInfo[i].y + 12;
902 
903 					for (int f = 6; f >= 1; f--) {
904 						xdif = _npcInfo[i].bodysection[f + 1].x - _npcInfo[i].bodysection[f - 1].x;
905 						ydif = _npcInfo[i].bodysection[f + 1].y - _npcInfo[i].bodysection[f - 1].y;
906 
907 						float tx = _npcInfo[i].bodysection[f - 1].x + xdif / 2;
908 						float ty = _npcInfo[i].bodysection[f - 1].y + ydif / 2;
909 
910 						_npcInfo[i].bodysection[f].x = _npcInfo[i].bodysection[f].x - (_npcInfo[i].bodysection[f].x - tx) / 3;
911 						_npcInfo[i].bodysection[f].y = _npcInfo[i].bodysection[f].y - (_npcInfo[i].bodysection[f].y - ty) / 3;
912 					}
913 
914 				}
915 
916 				// dragon2 specific
917 				if (_npcInfo[i].spriteset == kMonsterDragon2 && _npcInfo[i].attackattempt < _ticks) {
918 					if (_npcInfo[i].attacknext < _ticks && _npcInfo[i].pause < _ticks && !_npcInfo[i].attacking) {
919 						npx = _npcInfo[i].x;
920 						npy = _npcInfo[i].y;
921 
922 						xdif = _player.px - npx;
923 						ydif = _player.py - npy;
924 
925 						if (ABS(xdif) < 32 && ABS(ydif) < 32) {
926 							_npcInfo[i].attackattempt = _ticks + 100;
927 							if ((int)(RND() * 2) == 0) {
928 								if (config.effects) {
929 									int snd = playSound(_sfx[kSndEnemyHit]);
930 									setChannelVolume(snd, config.effectsVol);
931 								}
932 
933 								_npcInfo[i].attacking = true;
934 								_npcInfo[i].attackframe = 0;
935 							}
936 						}
937 					}
938 				}
939 
940 
941 				// endboss specific
942 				if (_npcInfo[i].spriteset == kMonsterFinalBoss && _npcInfo[i].attackattempt < _ticks) {
943 					if (_npcInfo[i].attacknext < _ticks && _npcInfo[i].pause < _ticks && !_npcInfo[i].attacking) {
944 						npx = _npcInfo[i].x;
945 						npy = _npcInfo[i].y;
946 
947 						xdif = _player.px - npx;
948 						ydif = _player.py - npy;
949 
950 						if (ABS(xdif) < 38 && ABS(ydif) < 38) {
951 							_npcInfo[i].attackattempt = _ticks + 100;
952 							if ((int)(RND() * 2) == 0) {
953 								if (config.effects) {
954 									int snd = playSound(_sfx[kSndIce]);
955 									setChannelVolume(snd, config.effectsVol);
956 								}
957 								_npcInfo[i].attacking = true;
958 								_npcInfo[i].attackframe = 0;
959 							}
960 						}
961 					}
962 				}
963 			}
964 
965 
966 			float npx = _npcInfo[i].x;
967 			float npy = _npcInfo[i].y;
968 
969 			int xp = (npx / 2 + 6);
970 			int yp = (npy / 2 + 10);
971 
972 			rcSrc.left = xp - 1;
973 			rcSrc.top = yp - 1;
974 			rcSrc.setWidth(3);
975 			rcSrc.setHeight(3);
976 
977 			if (_npcInfo[i].pause < _ticks)
978 				_clipBg->fillRect(rcSrc, i);
979 
980 
981 			pass = 0;
982 			if (_npcInfo[i].attacking)
983 				pass = 1;
984 			if (_npcInfo[i].spriteset == kMonsterFireHydra) {
985 				if (_npcInfo[i].attacking2[0] || _npcInfo[i].attacking2[1] || _npcInfo[i].attacking2[2])
986 					pass = 1;
987 			}
988 
989 			if (pass == 1) {
990 				int dist;
991 				float damage;
992 				// spriteset1 specific
993 				if (_npcInfo[i].spriteset == kMonsterBabyDragon) {
994 					_npcInfo[i].attackframe = _npcInfo[i].attackframe + _npcInfo[i].attackspd * _fpsr;
995 					if (_npcInfo[i].attackframe >= 16) {
996 						_npcInfo[i].attackframe = 0;
997 						_npcInfo[i].attacking = false;
998 						_npcInfo[i].attacknext = _ticks + _npcInfo[i].attackdelay;
999 					}
1000 
1001 					_npcInfo[i].cattackframe = (int)(_npcInfo[i].attackframe);
1002 
1003 					npx = _npcInfo[i].x;
1004 					npy = _npcInfo[i].y;
1005 
1006 					float xdif = _player.px - npx;
1007 					float ydif = _player.py - npy;
1008 
1009 					dist = 10;
1010 
1011 					if (ABS(xdif) < dist && ABS(ydif) < dist && _player.pause < _ticks) {
1012 						_npcInfo[i].attacknext = _ticks + _npcInfo[i].attackdelay;
1013 						// _npcinfo[i].attackframe = 0;
1014 						// _npcinfo[i].attacking = false;
1015 
1016 						damage = (float)_npcInfo[i].attackDamage * (0.5 + RND() * 1.0);
1017 
1018 						if (_player.hp > 0)
1019 							damagePlayer(damage);
1020 					}
1021 				}
1022 
1023 				if (_npcInfo[i].spriteset == kMonsterOneWing) {
1024 					// targethead code
1025 					float xdif = _npcInfo[i].bodysection[7].x - _npcInfo[i].headTargetX[0];
1026 					float ydif = _npcInfo[i].bodysection[7].y - _npcInfo[i].headTargetY[0];
1027 
1028 					_npcInfo[i].bodysection[7].x = _npcInfo[i].bodysection[7].x  - xdif * 0.4 * _fpsr;
1029 					_npcInfo[i].bodysection[7].y = _npcInfo[i].bodysection[7].y  - ydif * 0.4 * _fpsr;
1030 
1031 					_npcInfo[i].bodysection[0].x = _npcInfo[i].x + 12;
1032 					_npcInfo[i].bodysection[0].y = _npcInfo[i].y + 12;
1033 
1034 					for (int f = 6; f >= 1; f--) {
1035 						xdif = _npcInfo[i].bodysection[f + 1].x - _npcInfo[i].bodysection[f - 1].x;
1036 						ydif = _npcInfo[i].bodysection[f + 1].y - _npcInfo[i].bodysection[f - 1].y;
1037 
1038 						float tx = _npcInfo[i].bodysection[f - 1].x + xdif / 2;
1039 						float ty = _npcInfo[i].bodysection[f - 1].y + ydif / 2;
1040 
1041 						_npcInfo[i].bodysection[f].x = _npcInfo[i].bodysection[f].x - (_npcInfo[i].bodysection[f].x - tx);
1042 						_npcInfo[i].bodysection[f].y = _npcInfo[i].bodysection[f].y - (_npcInfo[i].bodysection[f].y - ty);
1043 					}
1044 
1045 					_npcInfo[i].attackframe = _npcInfo[i].attackframe + _npcInfo[i].attackspd * _fpsr;
1046 					if (_npcInfo[i].attackframe >= 16) {
1047 						_npcInfo[i].attackframe = 0;
1048 						_npcInfo[i].attacking = false;
1049 						_npcInfo[i].attacknext = _ticks + _npcInfo[i].attackdelay;
1050 					}
1051 
1052 					_npcInfo[i].cattackframe = (int)(_npcInfo[i].attackframe);
1053 
1054 					npx = _npcInfo[i].bodysection[7].x;
1055 					npy = (_npcInfo[i].bodysection[7].y + 16);
1056 
1057 					xdif = (_player.px + 12) - npx;
1058 					ydif = (_player.py + 12) - npy;
1059 
1060 					dist = 8;
1061 
1062 					if (ABS(xdif) < dist && ABS(ydif) < dist && _player.pause < _ticks) {
1063 						_npcInfo[i].attacknext = _ticks + _npcInfo[i].attackdelay;
1064 						// _npcinfo[i].attackframe = 0
1065 						// _npcinfo[i].attacking = false
1066 						damage = (float)_npcInfo[i].attackDamage * (1.0 + (RND() * 0.5));
1067 						if (_player.hp > 0)
1068 							damagePlayer(damage);
1069 					}
1070 				}
1071 
1072 
1073 				// firehydra
1074 				if (_npcInfo[i].spriteset == kMonsterFireHydra) {
1075 					for (int ff = 0; ff <= 2; ff++) {
1076 						if (_npcInfo[i].attacking2[ff]) {
1077 							float xdif = _npcInfo[i].bodysection[10 * ff + 9].x - _npcInfo[i].headTargetX[ff];
1078 							float ydif = _npcInfo[i].bodysection[10 * ff + 9].y - _npcInfo[i].headTargetY[ff];
1079 
1080 							_npcInfo[i].bodysection[10 * ff + 9].x = _npcInfo[i].bodysection[10 * ff + 9].x  - xdif * .2 * _fpsr;
1081 							_npcInfo[i].bodysection[10 * ff + 9].y = _npcInfo[i].bodysection[10 * ff + 9].y  - ydif * .2 * _fpsr;
1082 
1083 							_npcInfo[i].bodysection[10 * ff].x = _npcInfo[i].x + 12 + 8 * cos(3.141592 * 2 * (_itemyloc / 16 + ff * 120 / 360));
1084 							_npcInfo[i].bodysection[10 * ff].y = _npcInfo[i].y + 12 + 8 * sin(3.141592 * 2 * (_itemyloc / 16 + ff * 120 / 360));
1085 
1086 							for (int f = 8; f >= 1; f--) {
1087 								xdif = _npcInfo[i].bodysection[ff * 10 + f + 1].x - _npcInfo[i].bodysection[ff * 10 + f - 1].x;
1088 								ydif = _npcInfo[i].bodysection[ff * 10 + f + 1].y - _npcInfo[i].bodysection[ff * 10 + f - 1].y;
1089 
1090 								float tx = _npcInfo[i].bodysection[ff * 10 + f - 1].x + xdif / 2;
1091 								float ty = _npcInfo[i].bodysection[ff * 10 + f - 1].y + ydif / 2;
1092 
1093 								_npcInfo[i].bodysection[ff * 10 + f].x = _npcInfo[i].bodysection[ff * 10 + f].x - (_npcInfo[i].bodysection[ff * 10 + f].x - tx) / 3;
1094 								_npcInfo[i].bodysection[ff * 10 + f].y = _npcInfo[i].bodysection[ff * 10 + f].y - (_npcInfo[i].bodysection[ff * 10 + f].y - ty) / 3;
1095 							}
1096 
1097 							_npcInfo[i].attackframe2[ff] = _npcInfo[i].attackframe2[ff] + _npcInfo[i].attackspd * _fpsr;
1098 							if (_npcInfo[i].attackframe2[ff] >= 16) {
1099 								_npcInfo[i].attackframe2[ff] = 0;
1100 								_npcInfo[i].attacking2[ff] = false;
1101 								_npcInfo[i].attacknext2[ff] = _ticks + _npcInfo[i].attackdelay;
1102 							}
1103 
1104 							_npcInfo[i].cattackframe = (int)(_npcInfo[i].attackframe);
1105 
1106 							npx = _npcInfo[i].bodysection[10 * ff + 9].x;
1107 							npy = (_npcInfo[i].bodysection[10 * ff + 9].y + 16);
1108 
1109 							xdif = (_player.px + 12) - npx;
1110 							ydif = (_player.py + 12) - npy;
1111 
1112 							dist = 8;
1113 
1114 							if (ABS(xdif) < dist && ABS(ydif) < dist && _player.pause < _ticks) {
1115 								_npcInfo[i].attacknext2[ff] = _ticks + _npcInfo[i].attackdelay;
1116 								// _npcinfo[i].attackframe2(ff) = 0
1117 								// _npcinfo[i].attacking2(ff) = false
1118 								damage = (float)_npcInfo[i].attackDamage * (1.0 + RND() * 0.5);
1119 								if (_player.hp > 0)
1120 									damagePlayer(damage);
1121 							}
1122 						}
1123 					}
1124 
1125 				}
1126 
1127 				// twowing specific
1128 				if (_npcInfo[i].spriteset == kMonsterTwoWing) {
1129 					// targethead code
1130 					float xdif = _npcInfo[i].bodysection[7].x - _npcInfo[i].headTargetX[0];
1131 					float ydif = _npcInfo[i].bodysection[7].y - _npcInfo[i].headTargetY[0];
1132 
1133 					_npcInfo[i].bodysection[7].x = _npcInfo[i].bodysection[7].x - xdif * 0.4 * _fpsr;
1134 					_npcInfo[i].bodysection[7].y = _npcInfo[i].bodysection[7].y - ydif * 0.4 * _fpsr;
1135 
1136 					_npcInfo[i].bodysection[0].x = _npcInfo[i].x + 12;
1137 					_npcInfo[i].bodysection[0].y = _npcInfo[i].y + 12;
1138 
1139 					for (int f = 6; f >= 1; f--) {
1140 						xdif = _npcInfo[i].bodysection[f + 1].x - _npcInfo[i].bodysection[f - 1].x;
1141 						ydif = _npcInfo[i].bodysection[f + 1].y - _npcInfo[i].bodysection[f - 1].y;
1142 
1143 						float tx = _npcInfo[i].bodysection[f - 1].x + xdif / 2;
1144 						float ty = _npcInfo[i].bodysection[f - 1].y + ydif / 2;
1145 
1146 						_npcInfo[i].bodysection[f].x = _npcInfo[i].bodysection[f].x - (_npcInfo[i].bodysection[f].x - tx);
1147 						_npcInfo[i].bodysection[f].y = _npcInfo[i].bodysection[f].y - (_npcInfo[i].bodysection[f].y - ty);
1148 					}
1149 
1150 					_npcInfo[i].attackframe = _npcInfo[i].attackframe + _npcInfo[i].attackspd * _fpsr;
1151 					if (_npcInfo[i].attackframe >= 16) {
1152 						_npcInfo[i].attackframe = 0;
1153 						_npcInfo[i].attacking = false;
1154 						_npcInfo[i].attacknext = _ticks + _npcInfo[i].attackdelay;
1155 					}
1156 
1157 					_npcInfo[i].cattackframe = (int)(_npcInfo[i].attackframe);
1158 
1159 					npx = _npcInfo[i].bodysection[7].x;
1160 					npy = (_npcInfo[i].bodysection[7].y + 16);
1161 
1162 					xdif = (_player.px + 12) - npx;
1163 					ydif = (_player.py + 12) - npy;
1164 
1165 					dist = 8;
1166 
1167 					if (ABS(xdif) < dist && ABS(ydif) < dist && _player.pause < _ticks) {
1168 						_npcInfo[i].attacknext = _ticks + _npcInfo[i].attackdelay;
1169 						// _npcinfo[i].attackframe = 0
1170 						// _npcinfo[i].attacking = false
1171 						damage = (float)_npcInfo[i].attackDamage * (1.0 + RND() * 0.5);
1172 						if (_player.hp > 0)
1173 							damagePlayer(damage);
1174 					}
1175 				}
1176 
1177 				// dragon 2 specific
1178 				if (_npcInfo[i].spriteset == kMonsterDragon2) {
1179 
1180 					_npcInfo[i].attackframe = _npcInfo[i].attackframe + _npcInfo[i].attackspd * _fpsr;
1181 					if (_npcInfo[i].attackframe >= 16) {
1182 						_npcInfo[i].attackframe = 0;
1183 						_npcInfo[i].attacking = false;
1184 						_npcInfo[i].attacknext = _ticks + _npcInfo[i].attackdelay;
1185 					}
1186 
1187 					_npcInfo[i].cattackframe = (int)(_npcInfo[i].attackframe);
1188 
1189 					npx = _npcInfo[i].x;
1190 					npy = _npcInfo[i].y;
1191 
1192 					float xdif = _player.px - npx;
1193 					float ydif = _player.py - npy;
1194 
1195 					dist = 16 + _npcInfo[i].attackframe;
1196 
1197 					if (ABS(xdif) < dist && ABS(ydif) < dist && _player.pause < _ticks) {
1198 						_npcInfo[i].attacknext = _ticks + _npcInfo[i].attackdelay;
1199 						// _npcinfo[i].attackframe = 0
1200 						// _npcinfo[i].attacking = false
1201 						damage = (float)_npcInfo[i].attackDamage * (0.5 + RND() * 1.0);
1202 						if (_player.hp > 0)
1203 							damagePlayer(damage);
1204 					}
1205 				}
1206 
1207 				// endboss specific
1208 				if (_npcInfo[i].spriteset == kMonsterFinalBoss) {
1209 					_npcInfo[i].attackframe = _npcInfo[i].attackframe + _npcInfo[i].attackspd * _fpsr;
1210 					if (_npcInfo[i].attackframe >= 16) {
1211 						_npcInfo[i].attackframe = 0;
1212 						_npcInfo[i].attacking = false;
1213 						_npcInfo[i].attacknext = _ticks + _npcInfo[i].attackdelay;
1214 					}
1215 
1216 					_npcInfo[i].cattackframe = (int)(_npcInfo[i].attackframe);
1217 
1218 					npx = _npcInfo[i].x;
1219 					npy = _npcInfo[i].y;
1220 
1221 					float xdif = _player.px - npx;
1222 					float ydif = _player.py - npy;
1223 
1224 					dist = 36;
1225 
1226 					if (ABS(xdif) < dist && ABS(ydif) < dist && _player.pause < _ticks) {
1227 						_npcInfo[i].attacknext = _ticks + _npcInfo[i].attackdelay;
1228 						// _npcinfo[i].attackframe = 0
1229 						// _npcinfo[i].attacking = false
1230 						damage = (float)_npcInfo[i].attackDamage * (0.5 + RND() * 1.0);
1231 						if (_player.hp > 0)
1232 							damagePlayer(damage);
1233 					}
1234 				}
1235 			}
1236 			// -------end fight code
1237 		}
1238 	}
1239 }
1240 
updateSpells()1241 void GriffonEngine::updateSpells() {
1242 	float xloc = 0, yloc = 0;
1243 
1244 	for (int i = 0; i < kMaxSpell; i++) {
1245 		if (_spellInfo[i].frame > 0) {
1246 			int spellnum = _spellInfo[i].spellnum;
1247 
1248 			// water
1249 			if (spellnum == 0 && !_forcePause) {
1250 				float fr = (32 - _spellInfo[i].frame);
1251 				int ll[4][2];
1252 
1253 				ll[0][0] = -2;
1254 				ll[0][1] = -3;
1255 				ll[1][0] = 2;
1256 				ll[1][1] = -3;
1257 				ll[2][0] = -4;
1258 				ll[2][1] = -2;
1259 				ll[3][0] = 4;
1260 				ll[3][1] = -2;
1261 
1262 				for (int f = 0; f <= 3; f++) {
1263 					if (fr > f * 4 && fr < f * 4 + 16) {
1264 						float alf = 255;
1265 
1266 						if (fr < f * 4 + 8) {
1267 							int fi = (int)((fr - f * 4) * 3) % 4;
1268 							rcSrc.left = 32 + fi * 16;
1269 							rcSrc.top = 80;
1270 							rcSrc.setWidth(16);
1271 							rcSrc.setHeight(16);
1272 
1273 							xloc = _spellInfo[i].enemyx + 12 + ll[f][0] * 16;
1274 							yloc = _spellInfo[i].enemyy + 16 + ll[f][1] * 16;
1275 
1276 							rcDest.left = xloc;
1277 							rcDest.top = yloc;
1278 
1279 							alf = 255 * ((fr - f * 4) / 8);
1280 						}
1281 
1282 						if (fr >= f * 4 + 8) {
1283 							int fi = 0; // ??
1284 
1285 							if (f == 0 || f == 2)
1286 								fi = 0;
1287 							if (f == 1 || f == 3)
1288 								fi = 1;
1289 							rcSrc.left = 32 + fi * 16;
1290 							rcSrc.top = 80;
1291 							rcSrc.setWidth(16);
1292 							rcSrc.setHeight(16);
1293 
1294 							float xst = _spellInfo[i].enemyx + 12 + ll[f][0] * 16;
1295 							float yst = _spellInfo[i].enemyy + 16 + ll[f][1] * 16;
1296 
1297 							float xi = (_spellInfo[i].enemyx - xst) * 2 / 8;
1298 							float yi = (_spellInfo[i].enemyy - yst) * 2 / 8;
1299 
1300 							float fl = (fr - f * 4 - 8) / 2;
1301 							xloc = xst + xi * fl * fl;
1302 							yloc = yst + yi * fl * fl;
1303 
1304 							rcDest.left = xloc;
1305 							rcDest.top = yloc;
1306 
1307 							alf = 255;
1308 						}
1309 
1310 						if (xloc > -16 && xloc < 304 && yloc > -16 && yloc < 224) {
1311 							_spellImg->blit(*_videoBuffer, rcDest.left, rcDest.top, Graphics::FLIP_NONE, &rcSrc, TS_ARGB((int)alf, 255, 255, 255));
1312 
1313 							if (_spellInfo[i].damagewho == 0) {
1314 								for (int e = 1; e <= _lastNpc; e++) {
1315 									float xdif = (xloc + 16) - (_npcInfo[e].x + 12);
1316 									float ydif = (yloc + 16) - (_npcInfo[e].y + 12);
1317 
1318 									if ((ABS(xdif) < 16 && ABS(ydif) < 16)) {
1319 										float damage = (float)_player.spellDamage * (1.0 + RND() * 0.5) * (float)_spellInfo[i].strength;
1320 
1321 										if (_npcInfo[e].hp > 0 && _npcInfo[e].pause < _ticks) {
1322 											damageNPC(e, damage, 1);
1323 											if (config.effects) {
1324 												int snd = playSound(_sfx[kSndIce]);
1325 												setChannelVolume(snd, config.effectsVol);
1326 											}
1327 										}
1328 									}
1329 								}
1330 							}
1331 
1332 							// check for post damage
1333 							if (_postInfoNbr > 0) {
1334 								for (int e = 0; e <= _postInfoNbr - 1; e++) {
1335 									float xdif = (xloc + 16) - (_postInfo[e][0] + 8);
1336 									float ydif = (yloc + 16) - (_postInfo[e][1] + 8);
1337 
1338 									if ((ABS(xdif) < 16 && ABS(ydif) < 16)) {
1339 										_objectMapFull[_curMap][(int)_postInfo[e][0] / 16][(int)_postInfo[e][1] / 16] = 1;
1340 										_objectMap[(int)_postInfo[e][0] / 16][(int)_postInfo[e][1] / 16] = -1;
1341 
1342 										rcSrc.left = _postInfo[e][0] / 2;
1343 										rcSrc.top = _postInfo[e][1] / 2;
1344 										rcSrc.setWidth(8);
1345 										rcSrc.setHeight(8);
1346 
1347 										_clipBg2->fillRect(rcSrc, 0);
1348 
1349 										addFloatIcon(99, _postInfo[e][0], _postInfo[e][1]);
1350 
1351 										if (config.effects) {
1352 											int snd = playSound(_sfx[kSndIce]);
1353 											setChannelVolume(snd, config.effectsVol);
1354 										}
1355 									}
1356 								}
1357 							}
1358 						}
1359 					}
1360 				}
1361 			}
1362 
1363 			// metal
1364 			if (spellnum == 1 && !_forcePause) {
1365 				int fr = (int)((32 - _spellInfo[i].frame) * 4) % 3;
1366 
1367 				rcSrc.left = fr * 48;
1368 				rcSrc.top = 0;
1369 				rcSrc.setWidth(48);
1370 				rcSrc.setHeight(48);
1371 
1372 				float c1 = (32 - _spellInfo[i].frame) / 16;
1373 
1374 				float halfx = (_spellInfo[i].homex - 12) + ((_spellInfo[i].enemyx - 12) - (_spellInfo[i].homex - 12)) / 2;
1375 				float halfy = (_spellInfo[i].homey - 12) + ((_spellInfo[i].enemyy - 12) - (_spellInfo[i].homey - 12)) / 2;
1376 
1377 				float wdth = (halfx - _spellInfo[i].homex) * 1.2;
1378 				float hight = (halfy - _spellInfo[i].homey) * 1.2;
1379 
1380 				xloc = halfx + wdth * cos(3.14159 + 3.14159 * 2 * c1);
1381 				yloc = halfy + hight * sin(3.14159 + 3.14159 * 2 * c1);
1382 
1383 				rcDest.left = xloc;
1384 				rcDest.top = yloc;
1385 
1386 				_spellImg->blit(*_videoBuffer, rcDest.left, rcDest.top, Graphics::FLIP_NONE, &rcSrc, TS_ARGB(255, 255, 255, 255));
1387 
1388 				_spellInfo[i].frame = _spellInfo[i].frame - 0.2 * _fpsr;
1389 				if (_spellInfo[i].frame < 0)
1390 					_spellInfo[i].frame = 0;
1391 
1392 				if (_spellInfo[i].damagewho == 0) {
1393 					for (int e = 1; e <= _lastNpc; e++) {
1394 						float xdif = (xloc + 24) - (_npcInfo[e].x + 12);
1395 						float ydif = (yloc + 24) - (_npcInfo[e].y + 12);
1396 
1397 						if ((ABS(xdif) < 24 && ABS(ydif) < 24)) {
1398 							float damage = (float)_player.spellDamage * (1.0 + RND() * 0.5) * (float)_spellInfo[i].strength;
1399 
1400 							if (_npcInfo[e].hp > 0 && _npcInfo[e].pause < _ticks) {
1401 								damageNPC(e, damage, 1);
1402 								if (config.effects) {
1403 									int snd = playSound(_sfx[kSndMetalHit]);
1404 									setChannelVolume(snd, config.effectsVol);
1405 								}
1406 							}
1407 						}
1408 					}
1409 				}
1410 
1411 				if (_spellInfo[i].damagewho == 1) {
1412 					// --------- boss 1 specific
1413 					if (ABS(_spellInfo[i].frame) < 0 && _npcInfo[_spellInfo[i].npc].spriteset == kMonsterBoss1) {
1414 						int npc = _spellInfo[i].npc;
1415 						_npcInfo[npc].attackframe = 0;
1416 						_npcInfo[npc].attacking = false;
1417 
1418 						_npcInfo[npc].pause = _ticks + 1000;
1419 						_npcInfo[npc].attacknext = _ticks + 4000;
1420 					}
1421 					// ---------------
1422 
1423 					// --------- blackknight specific
1424 					if (ABS(_spellInfo[i].frame) < 0 && _npcInfo[_spellInfo[i].npc].spriteset == kMonsterBlackKnight) {
1425 						int npc = _spellInfo[i].npc;
1426 						_npcInfo[npc].attackframe = 0;
1427 						_npcInfo[npc].attacking = false;
1428 
1429 						_npcInfo[npc].pause = _ticks + 1000;
1430 						_npcInfo[npc].attacknext = _ticks + 3500;
1431 					}
1432 					// ---------------
1433 
1434 					float xdif = (xloc + 24) - (_player.px + 12);
1435 					float ydif = (yloc + 24) - (_player.py + 12);
1436 
1437 					if ((ABS(xdif) < 24 && ABS(ydif) < 24) && _player.pause < _ticks) {
1438 						float damage = (float)_npcInfo[_spellInfo[i].npc].spellDamage * (1.0 + RND() * 0.5);
1439 
1440 						if (_player.hp > 0) {
1441 							damagePlayer(damage);
1442 							if (config.effects) {
1443 								int snd = playSound(_sfx[kSndMetalHit]);
1444 								setChannelVolume(snd, config.effectsVol);
1445 							}
1446 						}
1447 					}
1448 				}
1449 
1450 
1451 				// check for(int post damage
1452 				if (_postInfoNbr > 0) {
1453 					for (int e = 0; e <= _postInfoNbr - 1; e++) {
1454 						float xdif = (xloc + 24) - (_postInfo[e][0] + 8);
1455 						float ydif = (yloc + 24) - (_postInfo[e][1] + 8);
1456 
1457 						if ((ABS(xdif) < 24 && ABS(ydif) < 24)) {
1458 							_objectMapFull[_curMap][(int)_postInfo[e][0] / 16][(int)_postInfo[e][1] / 16] = 1;
1459 							_objectMap[(int)_postInfo[e][0] / 16][(int)_postInfo[e][1] / 16] = -1;
1460 
1461 							rcSrc.left = _postInfo[e][0] / 2;
1462 							rcSrc.top = _postInfo[e][1] / 2;
1463 							rcSrc.setWidth(8);
1464 							rcSrc.setHeight(8);
1465 
1466 							_clipBg2->fillRect(rcSrc, 0);
1467 
1468 							addFloatIcon(99, _postInfo[e][0], _postInfo[e][1]);
1469 
1470 							if (config.effects) {
1471 								int snd = playSound(_sfx[kSndMetalHit]);
1472 								setChannelVolume(snd, config.effectsVol);
1473 							}
1474 						}
1475 					}
1476 				}
1477 			}
1478 
1479 			// earth
1480 			if (spellnum == 2 && !_forcePause) {
1481 				float hght = 240 - _spellInfo[i].enemyy;
1482 
1483 				for (int f = 8; f >= 0; f--) {
1484 
1485 					float fr = (32 - _spellInfo[i].frame);
1486 
1487 					if (fr > f && fr < f + 16) {
1488 						rcSrc.left = 32 * _spellInfo[i].rockimg[f];
1489 						rcSrc.top = 48;
1490 						rcSrc.setWidth(32);
1491 						rcSrc.setHeight(32);
1492 
1493 						bool scatter = false;
1494 						if (fr < 8 + f) {
1495 							xloc = _spellInfo[i].enemyx - 4;
1496 							yloc = _spellInfo[i].enemyy * (1 - cos(3.14159 / 2 * (fr - f) / 8)); // ^ 2;
1497 							yloc *= yloc;
1498 						} else {
1499 							scatter = true;
1500 							xloc = _spellInfo[i].enemyx - 4 - _spellInfo[i].rockdeflect[f] * sin(3.14159 / 2 * ((fr - f) - 8) / 8);
1501 							yloc = _spellInfo[i].enemyy + hght * (1 - cos(3.14159 / 2 * ((fr - f) - 8) / 8));
1502 						}
1503 
1504 						rcDest.left = xloc;
1505 						rcDest.top = yloc;
1506 
1507 						if (xloc > -16 && xloc < 304 && yloc > -16 && yloc < 224) {
1508 							_spellImg->blit(*_videoBuffer, rcDest.left, rcDest.top, Graphics::FLIP_NONE, &rcSrc, TS_ARGB(255, 255, 255, 255));
1509 
1510 							if (scatter) {
1511 								if (_spellInfo[i].damagewho == 0) {
1512 									for (int e = 1; e <= _lastNpc; e++) {
1513 										float xdif = (xloc + 16) - (_npcInfo[e].x + 12);
1514 										float ydif = (yloc + 16) - (_npcInfo[e].y + 12);
1515 
1516 										if ((ABS(xdif) < 16 && ABS(ydif) < 16)) {
1517 											float damage = (float)_player.spellDamage * (1.0 + RND() * 0.5) * (float)_spellInfo[i].strength;
1518 
1519 											if (_npcInfo[e].hp > 0 && _npcInfo[e].pause < _ticks) {
1520 												damageNPC(e, damage, 1);
1521 												if (config.effects) {
1522 													int snd = playSound(_sfx[kSndRocks]);
1523 													setChannelVolume(snd, config.effectsVol);
1524 												}
1525 											}
1526 										}
1527 									}
1528 								}
1529 
1530 
1531 								// check for(int post damage
1532 								if (_postInfoNbr > 0) {
1533 									for (int e = 0; e <= _postInfoNbr - 1; e++) {
1534 										float xdif = (xloc + 16) - (_postInfo[e][0] + 8);
1535 										float ydif = (yloc + 16) - (_postInfo[e][1] + 8);
1536 
1537 										if ((ABS(xdif) < 16 && ABS(ydif) < 16)) {
1538 											_objectMapFull[_curMap][(int)_postInfo[e][0] / 16][(int)_postInfo[e][1] / 16] = 1;
1539 											_objectMap[(int)_postInfo[e][0] / 16][(int)_postInfo[e][1] / 16] = -1;
1540 
1541 											rcSrc.left = _postInfo[e][0] / 2;
1542 											rcSrc.top = _postInfo[e][1] / 2;
1543 											rcSrc.setWidth(8);
1544 											rcSrc.setHeight(8);
1545 
1546 											_clipBg2->fillRect(rcSrc, 0);
1547 
1548 											addFloatIcon(99, _postInfo[e][0], _postInfo[e][1]);
1549 
1550 											if (config.effects) {
1551 												int snd = playSound(_sfx[kSndRocks]);
1552 												setChannelVolume(snd, config.effectsVol);
1553 											}
1554 										}
1555 									}
1556 								}
1557 							}
1558 						}
1559 					}
1560 				}
1561 
1562 				_spellInfo[i].frame = _spellInfo[i].frame - 0.2 * _fpsr;
1563 				if (_spellInfo[i].frame < 0)
1564 					_spellInfo[i].frame = 0;
1565 			}
1566 
1567 			// crystal
1568 			if (spellnum == 5) {
1569 
1570 				float fra = (32 - _spellInfo[i].frame);
1571 				int fr = (int)((_spellInfo[i].frame) * 2) % 8;
1572 
1573 				rcSrc.left = fr * 32;
1574 				rcSrc.top = 96 + 48;
1575 				rcSrc.setWidth(32);
1576 				rcSrc.setHeight(64);
1577 
1578 				rcDest.left = _player.px - 4;
1579 				rcDest.top = _player.py + 16 - 48;
1580 
1581 				int f = 160;
1582 				if (fra < 8)
1583 					f = 192 * fra / 8;
1584 				if (fra > 24)
1585 					f = 192 * (1 - (fra - 24) / 8);
1586 
1587 				_spellImg->blit(*_videoBuffer, rcDest.left, rcDest.top, Graphics::FLIP_NONE, &rcSrc, TS_ARGB(f, 255, 255, 255));
1588 
1589 				_spellInfo[i].frame = _spellInfo[i].frame - 0.3 * _fpsr;
1590 				if (_spellInfo[i].frame < 0) {
1591 					_spellInfo[i].frame = 0;
1592 					_forcePause = false;
1593 
1594 					float npx = _player.px + 12;
1595 					float npy = _player.py + 20;
1596 
1597 					int lx = (int)npx / 16;
1598 					int ly = (int)npy / 16;
1599 
1600 					bool foundel[5];
1601 					for (int f1 = 0; f1 < 5; f1++) { // !! f < 5
1602 						foundel[f1] = false;
1603 					}
1604 
1605 					for (int xo = -2; xo <= 2; xo++) {
1606 						for (int yo = -2; yo <= 2; yo++) {
1607 
1608 							int sx = lx + xo;
1609 							int sy = ly + yo;
1610 
1611 							if (sx > -1 && sx < 20 && sy > -1 && sy < 15) {
1612 								for (int l = 0; l <= 2; l++) {
1613 									int curtile = _tileinfo[l][sx][sy][0];
1614 									int curtilel = _tileinfo[l][sx][sy][1];
1615 
1616 									if (curtile > 0) {
1617 										curtile = curtile - 1;
1618 										int curtilex = curtile % 20;
1619 										int curtiley = (curtile - curtilex) / 20;
1620 
1621 										int element = elementmap[curtiley][curtilex];
1622 										if (element > -1 && curtilel == 0)
1623 											foundel[element + 1] = true;
1624 									}
1625 								}
1626 
1627 								int o = _objectMap[sx][sy];
1628 								if (o > -1) {
1629 									if (_objectInfo[o].type == 1)
1630 										foundel[2] = true;
1631 									if (o == 1 || o == 2) {
1632 										foundel[2] = true;
1633 										foundel[4] = true;
1634 									}
1635 								}
1636 							}
1637 						}
1638 					}
1639 
1640 					char line[256];
1641 					strcpy(line, "Found... nothing...");
1642 
1643 					for (int f1 = 0; f1 < 5; f1++) {
1644 						if (foundel[f1] && !_player.foundSpell[f1]) {
1645 							_player.foundSpell[f1] = 1;
1646 							_player.spellCharge[f1] = 0;
1647 							if (f1 == 1)
1648 								strcpy(line, "Found... Water Essence");
1649 							if (f1 == 2)
1650 								strcpy(line, "Found... Metal Essence");
1651 							if (f1 == 3)
1652 								strcpy(line, "Found... Earth Essence");
1653 							if (f1 == 4)
1654 								strcpy(line, "Found... Fire Essence");
1655 							break;
1656 						}
1657 					}
1658 
1659 					eventText(line);
1660 				}
1661 			}
1662 
1663 			// room fireballs
1664 			if (spellnum == 6 && !_forcePause) {
1665 
1666 				if (_spellInfo[i].frame > 16) {
1667 					float fr = (32 - _spellInfo[i].frame);
1668 
1669 					int alpha = 192 * sin(3.14159 * fr / 4);
1670 
1671 					rcSrc.left = 16 * (int)(RND() * 2);
1672 					rcSrc.top = 80;
1673 					rcSrc.setWidth(16);
1674 					rcSrc.setHeight(16);
1675 
1676 					for (int ff = 0; ff <= _spellInfo[i].nfballs - 1; ff++) {
1677 
1678 						xloc = _spellInfo[i].fireballs[ff][0] + (int)(RND() * 3) - 1;
1679 						yloc = _spellInfo[i].fireballs[ff][1] + (int)(RND() * 3) - 1;
1680 
1681 						rcDest.left = xloc;
1682 						rcDest.top = yloc;
1683 
1684 						_spellImg->blit(*_videoBuffer, rcDest.left, rcDest.top, Graphics::FLIP_NONE, &rcSrc, TS_ARGB(alpha, 255, 255, 255));
1685 					}
1686 				} else {
1687 
1688 					rcSrc.left = 16 * (int)(RND() * 2);
1689 					rcSrc.top = 80;
1690 					rcSrc.setWidth(16);
1691 					rcSrc.setHeight(16);
1692 
1693 					for (int ff = 0; ff <= _spellInfo[i].nfballs - 1; ff++) {
1694 						float ax = _spellInfo[i].fireballs[ff][0];
1695 						float ay = _spellInfo[i].fireballs[ff][1];
1696 						float bx = _player.px + 4;
1697 						float by = _player.py + 4;
1698 						float d = sqrt((bx - ax) * (bx - ax) + (by - ay) * (by - ay));
1699 
1700 						float tx = (bx - ax) / d;
1701 						float ty = (by - ay) / d;
1702 
1703 						_spellInfo[i].fireballs[ff][2] += tx * 1.2 * _fpsr;
1704 						_spellInfo[i].fireballs[ff][3] += ty * 1.2 * _fpsr;
1705 
1706 						if (_spellInfo[i].ballon[ff] == 1) {
1707 							_spellInfo[i].fireballs[ff][0] = ax + _spellInfo[i].fireballs[ff][2] * 0.2 * _fpsr;
1708 							_spellInfo[i].fireballs[ff][1] = ay + _spellInfo[i].fireballs[ff][3] * 0.2 * _fpsr;
1709 
1710 							xloc = _spellInfo[i].fireballs[ff][0] + (int)(RND() * 3) - 1;
1711 							yloc = _spellInfo[i].fireballs[ff][1] + (int)(RND() * 3) - 1;
1712 
1713 							rcDest.left = xloc;
1714 							rcDest.top = yloc;
1715 
1716 							_spellImg->blit(*_videoBuffer, rcDest.left, rcDest.top, Graphics::FLIP_NONE, &rcSrc, TS_ARGB(192, 255, 255, 255));
1717 						}
1718 
1719 						if (xloc < -1 || yloc < -1 || xloc > 304 || yloc > 224)
1720 							_spellInfo[i].ballon[ff] = 0;
1721 					}
1722 				}
1723 
1724 				_spellInfo[i].frame = _spellInfo[i].frame - 0.2 * _fpsr;
1725 				if (_spellInfo[i].frame < 0)
1726 					_spellInfo[i].frame = 0;
1727 
1728 				if (_spellInfo[i].damagewho == 1) {
1729 					for (int ff = 0; ff <= _spellInfo[i].nfballs - 1; ff++) {
1730 						if (_spellInfo[i].ballon[ff] == 1) {
1731 							xloc = _spellInfo[i].fireballs[ff][0] + (int)(RND() * 3) - 1;
1732 							yloc = _spellInfo[i].fireballs[ff][1] + (int)(RND() * 3) - 1;
1733 
1734 							float xdif = (xloc + 8) - (_player.px + 12);
1735 							float ydif = (yloc + 8) - (_player.py + 12);
1736 
1737 							if ((ABS(xdif) < 8 && ABS(ydif) < 8) && _player.pause < _ticks) {
1738 								float damage = _npcInfo[_spellInfo[i].npc].spellDamage * (1 + RND() * 0.5) / 3;
1739 
1740 								if (_player.hp > 0)
1741 									damagePlayer(damage);
1742 
1743 								if (config.effects) {
1744 									int snd = playSound(_sfx[kSndFire]);
1745 									setChannelVolume(snd, config.effectsVol);
1746 								}
1747 							}
1748 						}
1749 					}
1750 				}
1751 			}
1752 
1753 			// lightning bomb
1754 			if (spellnum == 8) {
1755 				long cl1 = _videoBuffer->format.RGBToColor(0, 32, 204);
1756 				long cl2 = _videoBuffer->format.RGBToColor(142, 173, 191);
1757 				long cl3 = _videoBuffer->format.RGBToColor(240, 240, 240);
1758 
1759 				float px = _player.px + 12;
1760 				float py = _player.py + 12;
1761 
1762 				int apx = px + (int)(RND() * 5 - 2);
1763 				int apy = py + (int)(RND() * 5 - 2);
1764 
1765 				for (int f = 0; f <= 0; f++) { // ??
1766 					int y = apy;
1767 					int orn = 0;
1768 					for (int x = apx; x <= 319; x++) {
1769 						int rn = (int)(RND() * 3);
1770 
1771 						if (orn == 0)
1772 							--y;
1773 						else if (orn == 2)
1774 							++y;
1775 
1776 						drawLine(_videoBuffer, x, y - 1, x, y + 2, cl1);
1777 						drawLine(_videoBuffer, x, y, x, y + 1, cl3);
1778 
1779 						if (rn == 0)
1780 							drawLine(_videoBuffer, x, y + 1, x, y + 1, cl2);
1781 						if (rn == 2)
1782 							drawLine(_videoBuffer, x, y, x, y, cl2);
1783 
1784 						orn = rn;
1785 
1786 						if (_spellInfo[i].damagewho == 0) {
1787 							for (int e = 1; e <= _lastNpc; e++) {
1788 								float xdif = (x + 16) - (_npcInfo[e].x + 12);
1789 								float ydif = (y + 16) - (_npcInfo[e].y + 12);
1790 
1791 								if ((ABS(xdif) < 8 && ABS(ydif) < 8)) {
1792 									float damage = 30 * (1 + RND() * 0.5);
1793 
1794 									if (_npcInfo[e].hp > 0 && _npcInfo[e].pause < _ticks)
1795 										damageNPC(e, damage, 1);
1796 								}
1797 							}
1798 						}
1799 
1800 						// check for post damage
1801 						if (_postInfoNbr > 0) {
1802 							for (int e = 0; e <= _postInfoNbr - 1; e++) {
1803 								float xdif = (xloc + 16) - (_postInfo[e][0] + 8);
1804 								float ydif = (yloc + 16) - (_postInfo[e][1] + 8);
1805 
1806 								if ((ABS(xdif) < 16 && ABS(ydif) < 16)) {
1807 									_objectMapFull[_curMap][(int)_postInfo[e][0] / 16][(int)_postInfo[e][1] / 16] = 1;
1808 									_objectMap[(int)_postInfo[e][0] / 16][(int)_postInfo[e][1] / 16] = -1;
1809 
1810 									rcSrc.left = _postInfo[e][0] / 2;
1811 									rcSrc.top = _postInfo[e][1] / 2;
1812 									rcSrc.setWidth(8);
1813 									rcSrc.setHeight(8);
1814 
1815 									_clipBg2->fillRect(rcSrc, 0);
1816 
1817 									addFloatIcon(99, _postInfo[e][0], _postInfo[e][1]);
1818 								}
1819 							}
1820 						}
1821 					}
1822 
1823 					y = apy;
1824 					orn = 0;
1825 					for (int x = apx; x >= 0; x--) {
1826 						int rn = (int)(RND() * 3);
1827 
1828 						if (orn == 0)
1829 							--y;
1830 						else if (orn == 2)
1831 							++y;
1832 
1833 						drawLine(_videoBuffer, x, y - 1, x, y + 2, cl1);
1834 						drawLine(_videoBuffer, x, y, x, y + 1, cl3);
1835 
1836 						if (rn == 0)
1837 							drawLine(_videoBuffer, x, y + 1, x, y + 1, cl2);
1838 						if (rn == 2)
1839 							drawLine(_videoBuffer, x, y, x, y, cl2);
1840 
1841 						orn = rn;
1842 
1843 						if (_spellInfo[i].damagewho == 0) {
1844 							for (int e = 1; e <= _lastNpc; e++) {
1845 								float xdif = (x + 16) - (_npcInfo[e].x + 12);
1846 								float ydif = (y + 16) - (_npcInfo[e].y + 12);
1847 
1848 								if ((ABS(xdif) < 8 && ABS(ydif) < 8)) {
1849 									float damage = 30 * (1 + RND() * 0.5);
1850 
1851 									if (_npcInfo[e].hp > 0 && _npcInfo[e].pause < _ticks)
1852 										damageNPC(e, damage, 1);
1853 								}
1854 							}
1855 						}
1856 
1857 						// check for post damage
1858 						if (_postInfoNbr > 0) {
1859 							for (int e = 0; e <= _postInfoNbr - 1; e++) {
1860 								float xdif = (xloc + 16) - (_postInfo[e][0] + 8);
1861 								float ydif = (yloc + 16) - (_postInfo[e][1] + 8);
1862 
1863 								if ((ABS(xdif) < 16 && ABS(ydif) < 16)) {
1864 									_objectMapFull[_curMap][(int)_postInfo[e][0] / 16][(int)_postInfo[e][1] / 16] = 1;
1865 									_objectMap[(int)_postInfo[e][0] / 16][(int)_postInfo[e][1] / 16] = -1;
1866 
1867 									rcSrc.left = _postInfo[e][0] / 2;
1868 									rcSrc.top = _postInfo[e][1] / 2;
1869 									rcSrc.setWidth(8);
1870 									rcSrc.setHeight(8);
1871 
1872 									_clipBg2->fillRect(rcSrc, 0);
1873 
1874 									addFloatIcon(99, _postInfo[e][0], _postInfo[e][1]);
1875 								}
1876 							}
1877 						}
1878 					}
1879 
1880 					int x = apx;
1881 					orn = 0;
1882 					for (y = apy; y <= 239; y++) {
1883 						int rn = (int)(RND() * 3);
1884 
1885 						if (orn == 0)
1886 							x = x - 1;
1887 						if (orn == 2)
1888 							x = x + 1;
1889 
1890 						drawLine(_videoBuffer, x - 1, y, x + 2, y, cl1);
1891 						drawLine(_videoBuffer, x, y, x + 1, y, cl3);
1892 
1893 						if (rn == 0)
1894 							drawLine(_videoBuffer, x + 1, y, x + 1, y, cl2);
1895 						if (rn == 2)
1896 							drawLine(_videoBuffer, x, y, x, y, cl2);
1897 
1898 						orn = rn;
1899 
1900 						if (_spellInfo[i].damagewho == 0) {
1901 							for (int e = 1; e <= _lastNpc; e++) {
1902 								float xdif = (x + 16) - (_npcInfo[e].x + 12);
1903 								float ydif = (y + 16) - (_npcInfo[e].y + 12);
1904 
1905 								if ((ABS(xdif) < 8 && ABS(ydif) < 8)) {
1906 									float damage = 30 * (1 + RND() * 0.5);
1907 
1908 									if (_npcInfo[e].hp > 0 && _npcInfo[e].pause < _ticks)
1909 										damageNPC(e, damage, 1);
1910 								}
1911 							}
1912 						}
1913 
1914 						// check for post damage
1915 						if (_postInfoNbr > 0) {
1916 							for (int e = 0; e <= _postInfoNbr - 1; e++) {
1917 								float xdif = (xloc + 16) - (_postInfo[e][0] + 8);
1918 								float ydif = (yloc + 16) - (_postInfo[e][1] + 8);
1919 
1920 								if ((ABS(xdif) < 16 && ABS(ydif) < 16)) {
1921 									_objectMapFull[_curMap][(int)_postInfo[e][0] / 16][(int)_postInfo[e][1] / 16] = 1;
1922 									_objectMap[(int)_postInfo[e][0] / 16][(int)_postInfo[e][1] / 16] = -1;
1923 
1924 									rcSrc.left = _postInfo[e][0] / 2;
1925 									rcSrc.top = _postInfo[e][1] / 2;
1926 									rcSrc.setWidth(8);
1927 									rcSrc.setHeight(8);
1928 
1929 									_clipBg2->fillRect(rcSrc, 0);
1930 
1931 									addFloatIcon(99, _postInfo[e][0], _postInfo[e][1]);
1932 								}
1933 							}
1934 						}
1935 					}
1936 
1937 					x = apx;
1938 					orn = 0;
1939 					for (y = apy; y >= 0; y--) {
1940 						int rn = (int)(RND() * 3);
1941 
1942 						if (orn == 0)
1943 							x = x - 1;
1944 						if (orn == 2)
1945 							x = x + 1;
1946 
1947 						drawLine(_videoBuffer, x - 1, y, x + 2, y, cl1);
1948 						drawLine(_videoBuffer, x, y, x + 1, y, cl3);
1949 
1950 						if (rn == 0)
1951 							drawLine(_videoBuffer, x + 1, y, x + 1, y, cl2);
1952 						if (rn == 2)
1953 							drawLine(_videoBuffer, x, y, x, y, cl2);
1954 
1955 						orn = rn;
1956 
1957 						if (_spellInfo[i].damagewho == 0) {
1958 							for (int e = 1; e <= _lastNpc; e++) {
1959 								float xdif = (x + 16) - (_npcInfo[e].x + 12);
1960 								float ydif = (y + 16) - (_npcInfo[e].y + 12);
1961 
1962 								if ((ABS(xdif) < 8 && ABS(ydif) < 8)) {
1963 									float damage = 30 * (1 + RND() * 0.5);
1964 
1965 									if (_npcInfo[e].hp > 0 && _npcInfo[e].pause < _ticks)
1966 										damageNPC(e, damage, 1);
1967 								}
1968 							}
1969 						}
1970 
1971 						// check for post damage
1972 						if (_postInfoNbr > 0) {
1973 							for (int e = 0; e <= _postInfoNbr - 1; e++) {
1974 								float xdif = (xloc + 16) - (_postInfo[e][0] + 8);
1975 								float ydif = (yloc + 16) - (_postInfo[e][1] + 8);
1976 
1977 								if ((ABS(xdif) < 16 && ABS(ydif) < 16)) {
1978 									_objectMapFull[_curMap][(int)_postInfo[e][0] / 16][(int)_postInfo[e][1] / 16] = 1;
1979 									_objectMap[(int)_postInfo[e][0] / 16][(int)_postInfo[e][1] / 16] = -1;
1980 
1981 									rcSrc.left = _postInfo[e][0] / 2;
1982 									rcSrc.top = _postInfo[e][1] / 2;
1983 									rcSrc.setWidth(8);
1984 									rcSrc.setHeight(8);
1985 
1986 									_clipBg2->fillRect(rcSrc, 0);
1987 
1988 									addFloatIcon(99, _postInfo[e][0], _postInfo[e][1]);
1989 								}
1990 							}
1991 						}
1992 					}
1993 				}
1994 
1995 				_spellInfo[i].frame -= 0.5 * _fpsr;
1996 				if (_spellInfo[i].frame < 0) {
1997 					_spellInfo[i].frame = 0;
1998 					_forcePause = false;
1999 				}
2000 			}
2001 
2002 			// wizard 1 lightning
2003 			if (spellnum == 9) {
2004 				long cl1 = _videoBuffer->format.RGBToColor(0, 32, 204);
2005 				long cl2 = _videoBuffer->format.RGBToColor(142, 173, 191);
2006 				long cl3 = _videoBuffer->format.RGBToColor(240, 240, 240);
2007 
2008 				int px = _spellInfo[i].enemyx + 12;
2009 				int py = _spellInfo[i].enemyy + 24;
2010 
2011 				int apx = px + (int)(RND() * 20 - 10);
2012 				int apy = py + (int)(RND() * 20 - 10);
2013 
2014 				int x = apx;
2015 				int orn = 0;
2016 				for (int y = 0; y <= apy; y++) {
2017 					if (y < 240) {
2018 						int rn = (int)(RND() * 3);
2019 
2020 						if (orn == 0)
2021 							x = x - 1;
2022 						if (orn == 2)
2023 							x = x + 1;
2024 
2025 						drawLine(_videoBuffer, x - 1, y, x + 2, y, cl1);
2026 						drawLine(_videoBuffer, x, y, x + 1, y, cl3);
2027 
2028 						if (rn == 0)
2029 							drawLine(_videoBuffer, x + 1, y, x + 1, y, cl2);
2030 						if (rn == 2)
2031 							drawLine(_videoBuffer, x, y, x, y, cl2);
2032 
2033 						orn = rn;
2034 
2035 						if (_spellInfo[i].damagewho == 1) {
2036 							float xdif = (x + 8) - (_player.px + 12);
2037 							float ydif = (y + 8) - (_player.py + 12);
2038 
2039 							if ((ABS(xdif) < 8 && ABS(ydif) < 8) && _player.pause < _ticks) {
2040 								float damage = ((float)_player.hp * 0.75) * (RND() * 0.5 + 0.5);
2041 								if (damage < 5)
2042 									damage = 5;
2043 
2044 								if ((_npcInfo[_spellInfo[i].npc].spriteset == kMonsterBatKitty) && (damage < 50))
2045 									damage = 40 + (int)(RND() * 40);
2046 
2047 								if (_player.hp > 0)
2048 									damagePlayer(damage);
2049 							}
2050 						}
2051 					}
2052 				}
2053 
2054 				_spellInfo[i].frame -= 0.5 * _fpsr;
2055 				if (_spellInfo[i].frame < 0) {
2056 					_spellInfo[i].frame = 0;
2057 
2058 					_npcInfo[_spellInfo[i].npc].attacking = false;
2059 					_npcInfo[_spellInfo[i].npc].attacknext = _ticks + _npcInfo[_spellInfo[i].npc].attackdelay;
2060 				}
2061 			}
2062 		}
2063 	}
2064 }
2065 
updateSpellsUnder()2066 void GriffonEngine::updateSpellsUnder() {
2067 	if (_forcePause)
2068 		return;
2069 
2070 	for (int i = 0; i < kMaxSpell; i++) {
2071 		if (_spellInfo[i].frame > 0) {
2072 			int spellnum = _spellInfo[i].spellnum;
2073 
2074 			// water
2075 			if (spellnum == 0) {
2076 				int fra = (32 - _spellInfo[i].frame);
2077 				int fr = (int)((32 - _spellInfo[i].frame) * 2) % 4;
2078 
2079 				rcSrc.left = fr * 48;
2080 				rcSrc.top = 96;
2081 				rcSrc.setWidth(48);
2082 				rcSrc.setHeight(48);
2083 
2084 				rcDest.left = _spellInfo[i].enemyx - 12;
2085 				rcDest.top = _spellInfo[i].enemyy - 8;
2086 
2087 				int f = 160;
2088 				if (fra < 8)
2089 					f = 160 * fra / 8;
2090 				if (fra > 24)
2091 					f = 160 * (1 - (fra - 24) / 8);
2092 
2093 				_spellImg->blit(*_videoBuffer, rcDest.left, rcDest.top, Graphics::FLIP_NONE, &rcSrc, TS_ARGB(f, 255, 255, 255));
2094 
2095 				_spellInfo[i].frame = _spellInfo[i].frame - 0.2 * _fpsr;
2096 				if (_spellInfo[i].frame < 0)
2097 					_spellInfo[i].frame = 0;
2098 
2099 
2100 				for (f = 1; f <= _lastNpc; f++) {
2101 					int xdif = _spellInfo[i].enemyx - _npcInfo[f].x;
2102 					int ydif = _spellInfo[i].enemyy - _npcInfo[f].y;
2103 
2104 					float dist = sqrt((float)(xdif * xdif + ydif * ydif));
2105 
2106 					if (dist > 20)
2107 						dist = 20;
2108 
2109 					if (dist > 5) {
2110 						float ratio = (1 - dist / 25);
2111 
2112 						float newx = _npcInfo[f].x + ratio * xdif / 3 * _fpsr;
2113 						float newy = _npcInfo[f].y + ratio * ydif / 3 * _fpsr;
2114 
2115 						int sx = (newx / 2 + 6);
2116 						int sy = (newy / 2 + 10);
2117 
2118 						uint32 *temp = (uint32 *)_clipBg->getBasePtr(sx, sy);
2119 						uint32 dq = *temp;
2120 
2121 						if (dq == 0) {
2122 							_npcInfo[f].x = newx;
2123 							_npcInfo[f].y = newy;
2124 							// _npcinfo[f].castpause = _ticks + 200;
2125 						} else {
2126 							int xpass = 0;
2127 							int ypass = 0;
2128 
2129 							sx = (newx / 2 + 6);
2130 							sy = (_npcInfo[f].y / 2 + 10);
2131 							temp = (uint32 *)_clipBg->getBasePtr(sx, sy);
2132 							dq = *temp;
2133 
2134 							if (dq == 0)
2135 								xpass = 1;
2136 
2137 
2138 							sx = (_npcInfo[f].x / 2 + 6);
2139 							sy = (newy / 2 + 10);
2140 							temp = (uint32 *)_clipBg->getBasePtr(sx, sy);
2141 							dq = *temp;
2142 
2143 							if (dq == 0)
2144 								ypass = 1;
2145 
2146 							if (ypass == 1) {
2147 								newx = _npcInfo[f].x;
2148 							} else if (xpass == 1) {
2149 								newy = _npcInfo[f].y;
2150 							}
2151 
2152 							if (xpass == 1 || ypass == 1) {
2153 								_npcInfo[f].x = newx;
2154 								_npcInfo[f].y = newy;
2155 								// _npcinfo[f].castpause = _ticks + 200;
2156 							}
2157 						}
2158 					}
2159 				}
2160 			}
2161 
2162 			// fire
2163 			if (spellnum == 3) {
2164 				float fr = (32 - _spellInfo[i].frame);
2165 
2166 				fr = fr * fr * (1 - cos(3.14159 / 4 + 3.14159 / 4 * fr / 32));
2167 
2168 				if (fr > 32)
2169 					fr = 32;
2170 
2171 				float s = 8;
2172 				if (_spellInfo[i].frame < 8)
2173 					s = _spellInfo[i].frame;
2174 
2175 				int fra = (int)fr;
2176 
2177 				for (int f = 0; f <= 4; f++) {
2178 					for (int x = 0; x <= fra; x += 2) {
2179 						if (_spellInfo[i].legalive[f] >= x) {
2180 							int alpha = 192 * sin(3.14159 * x / 32) * s / 8;
2181 
2182 							float an = 360 / 5 * f + x / 32 * 180;
2183 
2184 							rcSrc.left = 16 * (int)(RND() * 2);
2185 							rcSrc.top = 80;
2186 							rcSrc.setWidth(16);
2187 							rcSrc.setHeight(16);
2188 
2189 							float xloc = (float)(_spellInfo[i].enemyx + 4 + x * 2 * cos(3.14159 / 180 * an) + (int)(RND() * 3) - 1);
2190 							float yloc = (float)(_spellInfo[i].enemyy + 4 + x * 2 * sin(3.14159 / 180 * an) + (int)(RND() * 3) - 1);
2191 							rcDest.left = (int)xloc;
2192 							rcDest.top = (int)yloc;
2193 
2194 							if (xloc > -1 && xloc < 304 && yloc > -1 && yloc < 224) {
2195 								_spellImg->blit(*_videoBuffer, rcDest.left, rcDest.top, Graphics::FLIP_NONE, &rcSrc, TS_ARGB(alpha, 255, 255, 255));
2196 
2197 								int sx = (xloc / 2 + 4);
2198 								int sy = (yloc / 2 + 8);
2199 
2200 								uint32 *temp = (uint32 *)_clipBg->getBasePtr(sx, sy);
2201 								uint32 dq = *temp;
2202 
2203 								if (dq > 1000 && x > 4)
2204 									_spellInfo[i].legalive[f] = x;
2205 
2206 								if (_spellInfo[i].damagewho == 0) {
2207 									for (int e = 1; e <= _lastNpc; e++) {
2208 										float xdif = (xloc + 8) - (_npcInfo[e].x + 12);
2209 										float ydif = (yloc + 8) - (_npcInfo[e].y + 12);
2210 
2211 										if ((ABS(xdif) < 8 && ABS(ydif) < 8)) {
2212 											float damage = (float)_player.spellDamage * (1.0 + RND() * 0.5) * (float)_spellInfo[i].strength;
2213 
2214 											if (_npcInfo[e].spriteset == kMonsterFireHydra)
2215 												damage = -damage;
2216 											if (_npcInfo[e].spriteset == kMonsterFinalBoss)
2217 												damage = -damage;
2218 											if (_npcInfo[e].hp > 0 && _npcInfo[e].pause < _ticks) {
2219 												damageNPC(e, damage, 1);
2220 												if (config.effects) {
2221 													int snd = playSound(_sfx[kSndFire]);
2222 													setChannelVolume(snd, config.effectsVol);
2223 												}
2224 											}
2225 										}
2226 									}
2227 								}
2228 
2229 								if (_spellInfo[i].damagewho == 1) {
2230 									float xdif = (xloc + 8) - (_player.px + 12);
2231 									float ydif = (yloc + 8) - (_player.py + 12);
2232 
2233 									if ((ABS(xdif) < 8 && ABS(ydif) < 8) && _player.pause < _ticks) {
2234 										float damage = (float)_npcInfo[_spellInfo[i].npc].spellDamage * (1.0 + RND() * 0.5);
2235 
2236 										if (_player.hp > 0) {
2237 											damagePlayer(damage);
2238 
2239 											if (config.effects) {
2240 												int snd = playSound(_sfx[kSndFire]);
2241 												setChannelVolume(snd, config.effectsVol);
2242 											}
2243 										}
2244 									}
2245 								}
2246 
2247 								// check for post damage
2248 								if (_postInfoNbr > 0) {
2249 									for (int e = 0; e <= _postInfoNbr - 1; e++) {
2250 										float xdif = (xloc + 8) - (_postInfo[e][0] + 8);
2251 										float ydif = (yloc + 8) - (_postInfo[e][1] + 8);
2252 
2253 										if ((ABS(xdif) < 8 && ABS(ydif) < 8)) {
2254 											_objectMapFull[_curMap][(int)_postInfo[e][0] / 16][(int)_postInfo[e][1] / 16] = 1;
2255 											_objectMap[(int)_postInfo[e][0] / 16][(int)_postInfo[e][1] / 16] = -1;
2256 
2257 											rcSrc.left = _postInfo[e][0] / 2;
2258 											rcSrc.top = _postInfo[e][1] / 2;
2259 											rcSrc.setWidth(8);
2260 											rcSrc.setHeight(8);
2261 
2262 											_clipBg2->fillRect(rcSrc, 0);
2263 
2264 											if (config.effects) {
2265 												int snd = playSound(_sfx[kSndFire]);
2266 												setChannelVolume(snd, config.effectsVol);
2267 											}
2268 
2269 											addFloatIcon(99, _postInfo[e][0], _postInfo[e][1]);
2270 										}
2271 									}
2272 								}
2273 							}
2274 						}
2275 					}
2276 				}
2277 
2278 				_spellInfo[i].frame = _spellInfo[i].frame - 0.2 * _fpsr;
2279 				if (_spellInfo[i].frame < 0)
2280 					_spellInfo[i].frame = 0;
2281 
2282 
2283 			}
2284 
2285 
2286 			// sprite 6 spitfire
2287 			if (spellnum == 7) {
2288 				float xspan = _spellInfo[i].enemyx - _spellInfo[i].homex;
2289 				float yspan = _spellInfo[i].enemyy - _spellInfo[i].homey;
2290 				float fr = (32 - _spellInfo[i].frame);
2291 
2292 				for (int f = 0; f <= 7; f++) {
2293 					int alpha = 0;
2294 					float xx = 0;
2295 					if (fr > f * 2 && fr < f * 2 + 16)
2296 						xx = fr - f * 2;
2297 					if (xx < 8)
2298 						alpha = 255 * xx / 8;
2299 					if (xx > 8)
2300 						alpha = 255 * (1 - (xx - 8) / 8);
2301 					float yy = 16 * sin(3.141592 / 2 * xx / 16) - 8;
2302 
2303 					alpha = CLIP(alpha, 0, 255);
2304 
2305 					rcSrc.left = 16 * (int)(RND() * 2);
2306 					rcSrc.top = 80;
2307 					rcSrc.setWidth(16);
2308 					rcSrc.setHeight(16);
2309 
2310 					float xloc = _spellInfo[i].homex + xspan / 7 * f;
2311 					float yloc = _spellInfo[i].homey + yspan / 7 * f - yy;
2312 
2313 					rcDest.left = xloc;
2314 					rcDest.top = yloc;
2315 
2316 					if (xloc > -16 && xloc < 320 && yloc > -16 && yloc < 240) {
2317 						_spellImg->blit(*_videoBuffer, rcDest.left, rcDest.top, Graphics::FLIP_NONE, &rcSrc, TS_ARGB(alpha, 255, 255, 255));
2318 
2319 						if (_spellInfo[i].damagewho == 1) {
2320 							float xdif = (xloc + 8) - (_player.px + 12);
2321 							float ydif = (yloc + 8) - (_player.py + 12);
2322 
2323 							if ((ABS(xdif) < 8 && ABS(ydif) < 8) && _player.pause < _ticks && alpha > 64) {
2324 								float damage = (float)_npcInfo[_spellInfo[i].npc].spellDamage * (1.0 + RND() * 0.5);
2325 
2326 								if (_player.hp > 0) {
2327 									damagePlayer(damage);
2328 									if (config.effects) {
2329 										int snd = playSound(_sfx[kSndFire]);
2330 										setChannelVolume(snd, config.effectsVol);
2331 									}
2332 								}
2333 
2334 							}
2335 						}
2336 
2337 					}
2338 
2339 				}
2340 
2341 				_spellInfo[i].frame = _spellInfo[i].frame - 0.5 * _fpsr;
2342 				if (_spellInfo[i].frame < 0)
2343 					_spellInfo[i].frame = 0;
2344 
2345 				if (ABS(_spellInfo[i].frame) < kEpsilon) {
2346 					_npcInfo[_spellInfo[i].npc].attacking = false;
2347 					_npcInfo[_spellInfo[i].npc].attacknext = _ticks + _npcInfo[_spellInfo[i].npc].attackdelay;
2348 				}
2349 			}
2350 		}
2351 	}
2352 }
2353 
2354 
2355 } // end of namespace Griffon
2356