1 /*
2  * Holotz's Castle
3  * Copyright (C) 2004 Juan Carlos Seijo P�rez
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the Free
7  * Software Foundation; either version 2 of the License, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc., 59
17  * Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  * Juan Carlos Seijo P�rez
20  * jacob@mainreactor.net
21  */
22 
23 /** Definition of script actions.
24  * @file    HCScriptAction.cpp
25  * @author  Juan Carlos Seijo P�rez
26  * @date    03/07/2004
27  * @version 0.0.1 - 03/07/2004 - Primera versi�n.
28  */
29 
30 #include <HCScriptAction.h>
31 #include <HolotzCastle.h>
32 
Update()33 s32 HCScriptAction::Update()
34 {
35 	finished = true;
36 	return 0;
37 }
38 
Character(const char * name,s32 index)39 HCCharacter * HCScriptAction::Character(const char *name, s32 index)
40 {
41 	HCApp *app = (HCApp *)JApp::App();
42 
43 	if (0 == strcmp(name, "main"))
44 	{
45 		return app->Level()->Character();
46 	}
47 	else
48 	if (0 == strcmp(name, "enemy"))
49 	{
50 		if (index >= app->Level()->NumEnemies())
51 		{
52 			fprintf(stderr, "No such enemy: %d\n", index);
53 		}
54 
55 		return app->Level()->Enemies()[index];
56 	}
57 	else
58 	{
59 		fprintf(stderr,
60 						"HCScriptAction: Unknown character %s!\n"
61 						"Available are main and enemy\n", name);
62 	}
63 
64 	return 0;
65 }
66 
Load(JTextFile & f)67 HCScriptAction * HCScriptAction::Load(JTextFile &f)
68 {
69 	char str[1024];
70 
71 	if (f.FindNext("["))
72 	{
73 		s8 * start = f.GetPos();
74 
75 		if (f.SkipNextWord())
76 		{
77 			if (f.ReadWord(str))
78 			{
79 				if (strcmp(str, "MOVE") == 0)
80 				{
81 					// Move action
82 					HCScriptActionMove *action = new HCScriptActionMove;
83 					f.SetPos(start);
84 
85 					if (action->Load(f))
86 					{
87 						f.FindNext("]");
88 
89 						return action;
90 					}
91 				}
92 				else
93 				if (strcmp(str, "DIALOG") == 0)
94 				{
95 					// Dialog action
96 					HCScriptActionDialog *action = new HCScriptActionDialog;
97 					f.SetPos(start);
98 
99 					if (action->Load(f))
100 					{
101 						f.FindNext("]");
102 
103 						return action;
104 					}
105 				}
106 				else
107 				if (strcmp(str, "NARRATIVE") == 0)
108 				{
109 					// Narrative action
110 					HCScriptActionNarrative *action = new HCScriptActionNarrative;
111 					f.SetPos(start);
112 
113 					if (action->Load(f))
114 					{
115 						f.FindNext("]");
116 
117 						return action;
118 					}
119 				}
120 				else
121 				if (strcmp(str, "SOUND") == 0)
122 				{
123 					// Sound action
124 					HCScriptActionSound *action = new HCScriptActionSound;
125 					f.SetPos(start);
126 
127 					if (action->Load(f))
128 					{
129 						f.FindNext("]");
130 
131 						return action;
132 					}
133 				}
134 				else
135 				if (strcmp(str, "WAIT") == 0)
136 				{
137 					// Wait action
138 					HCScriptActionWait *action = new HCScriptActionWait;
139 					f.SetPos(start);
140 
141 					if (action->Load(f))
142 					{
143 						f.FindNext("]");
144 
145 						return action;
146 					}
147 				}
148 				else
149 				{
150 					// Unknown action
151 					fprintf(stderr, "Unknown action found!\n");
152 
153 					return 0;
154 				}
155 			}
156 		}
157 	}
158 	else
159 	{
160 		fprintf(stderr, "HCScriptAction: No action found!\n");
161 	}
162 
163 	return 0;
164 }
165 
Init(HCCharacter * _character,s32 dir,s32 amount)166 bool HCScriptActionMove::Init(HCCharacter *_character, s32 dir, s32 amount)
167 {
168 	if (0 == _character)
169 	{
170 		return false;
171 	}
172 
173 	character = _character;
174 	totalAmount = amount;
175 	direction = dir;
176 
177 	return true;
178 }
179 
Load(JTextFile & f)180 bool HCScriptActionMove::Load(JTextFile &f)
181 {
182 	char charName[32];
183 	s32 index;
184 
185 	if (4 == sscanf(f.GetPos(), "[ MOVE %[A-Za-z] ( %d ) dir=%d amount=%d ]",
186 									charName, &index, &direction, &totalAmount))
187 	{
188 		HCCharacter *tmpChar;
189 
190 		tmpChar = Character(charName, index);
191 
192 		if (0 == tmpChar)
193 		{
194 			return false;
195 		}
196 
197 		if (direction != 2 && (direction < 4 || direction > 9))
198 		{
199 			fprintf(stderr, "HCScriptActionMove: Direction must be one of 2 or 4 to 9!\n");
200 
201 			return false;
202 		}
203 
204 		return Init(tmpChar, direction, totalAmount);
205 	}
206 
207 	fprintf(stderr, "HCScriptActionMove: Failed to load!\n");
208 
209 	return false;
210 }
211 
Update()212 s32 HCScriptActionMove::Update()
213 {
214 	if (finished)
215 	{
216 		return 0;
217 	}
218 
219 	// Finished if not moving leftright or updown.
220 	switch (direction)
221 	{
222 	case 2:
223 		character->Act(HCCA_DOWN);
224 		if (character->State() != HCCS_DOWN)
225 		{
226 			character->State(HCCS_STOP);
227 			character->Veloccity().y = 0;
228 			finished = true;
229 			return 0;
230 		}
231 		break;
232 
233 	case 4:
234 		character->Act(HCCA_LEFT);
235 		if (character->Acceleration().x > -0.001f/* || character->State() != HCCS_LEFT*/)
236 		{
237 			character->Veloccity().x = character->Acceleration().x = 0;
238 			character->State(HCCS_STOP);
239 			finished = true;
240 			return 0;
241 		}
242 		break;
243 
244 	case 5:
245 		character->Act(HCCA_JUMP);
246 		if (character->Veloccity().y > 0.0f || character->State() != HCCS_JUMP)
247 		{
248 			finished = true;
249 			return 0;
250 		}
251 		break;
252 
253 	case 6:
254 		character->Act(HCCA_RIGHT);
255 		if (character->Acceleration().x < 0.001f /*|| character->State() != HCCS_RIGHT*/)
256 		{
257 			character->Veloccity().x = character->Acceleration().x = 0;
258 			character->State(HCCS_STOP);
259 			finished = true;
260 			return 0;
261 		}
262 		break;
263 
264 	case 7:
265 		character->Act(HCCA_JUMP | HCCA_LEFT);
266 		if (character->Acceleration().x > -0.001f || character->State() != HCCS_JUMPLEFT)
267 		{
268 			finished = true;
269 			return 0;
270 		}
271 		break;
272 
273 	case 8:
274 		character->Act(HCCA_UP);
275 		if (character->State() != HCCS_UP)
276 		{
277 			character->Veloccity().y = 0;
278 			character->State(HCCS_STOP);
279 			finished = true;
280 			return 0;
281 		}
282 		break;
283 
284 	case 9:
285 		character->Act(HCCA_JUMP | HCCA_RIGHT);
286 		if (character->Acceleration().x < 0.001f || character->State() != HCCS_JUMPRIGHT)
287 		{
288 			finished = true;
289 			return 0;
290 		}
291 		break;
292 
293 	default:
294 		character->Veloccity().y = 0;
295 		character->Veloccity().x = character->Acceleration().x = 0;
296 		character->Act(HCCA_STOP);
297 		break;
298 	}
299 
300 	s32 row = character->Row();
301 	s32 col = character->Col();
302 
303 	// Cell changed?
304 	if (row != lastRow)
305 	{
306 		lastRow = row;
307 		switch (direction)
308 		{
309 			// Only counts for up and down actions
310 		case 8:
311 		case 2:
312 			++curAmount;
313 			break;
314 
315 		default:
316 			break;
317 		}
318 	}
319 
320 	if (col != lastCol)
321 	{
322 		// This governs also the jumpxxx actions
323 		lastCol = col;
324 		++curAmount;
325 	}
326 
327 	// Travelled the specified amount of cells
328 	if (curAmount >= totalAmount)
329 	{
330 		finished = true;
331 	}
332 
333 	if (finished)
334 	{
335 		switch (direction)
336 		{
337 		case 5:
338 			character->Act(HCCA_JUMP);
339 			break;
340 
341 		default:
342 			character->Act(HCCA_STOP);
343 			break;
344 		}
345 
346 		direction = 0;
347 		return 0;
348 	}
349 
350 	return 1;
351 }
352 
Current()353 void HCScriptActionMove::Current()
354 {
355 	lastRow = orgRow = character->Row();
356 	lastCol = orgCol = character->Col();
357 	curAmount = 0;
358 }
359 
Init(HCCharacter * _character,const char * text,HCTheme * theme,JFont * font,JFontAlign align,bool left,s32 subtype,u8 r,u8 g,u8 b)360 bool HCScriptActionDialog::Init(HCCharacter *_character,
361 																const char *text,
362 																HCTheme *theme,
363 																JFont *font,
364 																JFontAlign align,
365 																bool left,
366 																s32 subtype,
367 																u8 r, u8 g, u8 b)
368 {
369 	if (0 == _character || 0 == theme || 0 == font)
370 	{
371 		return false;
372 	}
373 
374 	character = _character;
375 	if (!dialog.Init(HCTEXTTYPE_DIALOG, text, theme, font, align, left, subtype, r, g, b))
376 	{
377 		fprintf(stderr, "Couldn't initialize dialog action.\n");
378 		return false;
379 	}
380 
381 	float *x = (float*)&((character->JDrawable::Pos()).x);
382 	float *y = (float*)&((character->JDrawable::Pos()).y);
383 
384 	dialog.Track(x, y);
385 	if (left)
386 		dialog.Pos(character->CurSprite()->MaxW()/2, -character->CurSprite()->MaxH()/2);
387 	else
388 		dialog.Pos(-character->CurSprite()->MaxH()/2, -character->CurSprite()->MaxH()/2);
389 
390 
391 	return true;
392 }
393 
Load(JTextFile & f)394 bool HCScriptActionDialog::Load(JTextFile &f)
395 {
396 	char charName[32];
397 	char text[256];
398 	s32 index, left, speed, r, g, b, size, txtAlign, st;
399 	JFontAlign fontAlign;
400 
401 	memset(text, 0, sizeof(text));
402 	memset(charName, 0, sizeof(charName));
403 
404 	if (11 == sscanf(f.GetPos(), "[ DIALOG %[A-Za-z](%d) text=\"%[^\"]\" txtAlign=%d speed=%d size=%d align=%d r=%d g=%d b=%d subtype=%d ]", charName, &index, text, &txtAlign, &speed, &size, &left, &r, &g, &b, &st))
405 	{
406 		HCApp *app = (HCApp*)JApp::App();
407 		HCCharacter *tmpChar = Character(charName, index);
408 
409 		JClamp(size, 1, 3);
410 		JFont *fnt;
411 
412 		switch (size)
413 		{
414 		default:
415 		case 1: fnt = app->FontSmall(); break;
416 		case 2: fnt = app->FontMedium(); break;
417 		case 3: fnt = app->FontLarge(); break;
418 		}
419 
420 		s32 oldSpeed = HCText::Speed();
421 
422 		switch (txtAlign % 3)
423 		{
424 		case 0:
425 			fontAlign = JFONTALIGN_RIGHT;
426 			break;
427     default:
428 		case 1:
429 			fontAlign = JFONTALIGN_LEFT;
430 			break;
431 		case 2:
432 			fontAlign = JFONTALIGN_CENTER;
433 			break;
434 		}
435 
436 		Init(tmpChar, text, &app->Level()->Theme(), fnt, fontAlign, left != 0, st, r, g, b);
437 
438 		HCText::Speed(oldSpeed);
439 	}
440 	else
441 	{
442 		fprintf(stderr, "HCScriptActionDialog: Failed to load!\n");
443 
444 		return false;
445 	}
446 
447 	return true;
448 }
449 
Update()450 s32 HCScriptActionDialog::Update()
451 {
452 	if (!finished)
453 	{
454 		if (!dialog.Visible())
455 		{
456 			finished = true;
457 		}
458 
459 		return 1;
460 	}
461 
462 	return 0;
463 }
464 
Current()465 void HCScriptActionDialog::Current()
466 {
467 	dialog.Reset();
468 	character->Dialog(&dialog);
469 }
470 
Init(s32 alignment,const char * text,HCTheme * theme,JFont * font,JFontAlign align,s32 subtype,u8 r,u8 g,u8 b)471 bool HCScriptActionNarrative::Init(s32 alignment,
472 																	 const char *text,
473 																	 HCTheme *theme,
474 																	 JFont *font,
475 																	 JFontAlign align,
476 																	 s32 subtype,
477 																	 u8 r, u8 g, u8 b)
478 {
479 	if (0 == theme || 0 == font)
480 	{
481 		return false;
482 	}
483 
484 	if (!narrative.Init(HCTEXTTYPE_NARRATIVE, text, theme, font, align, false, subtype, r, g, b))
485 	{
486 		fprintf(stderr, "Couldn't initialize narrative action.\n");
487 		return false;
488 	}
489 
490 	// Aligns the frame within the screen
491 	s32 x, y;
492 	switch (alignment)
493 	{
494 	case 1:
495 		x = 0;
496 		y = JApp::App()->Height() - narrative.Image().Height();
497 		break;
498 	case 2:
499 		x = (JApp::App()->Width() - narrative.Image().Width())/2;
500 		y = JApp::App()->Height() - narrative.Image().Height();
501 		break;
502 	case 3:
503 		x = JApp::App()->Width() - narrative.Image().Width();
504 		y = JApp::App()->Height() - narrative.Image().Height();
505 		break;
506 	case 4:
507 		x = 0;
508 		y = (JApp::App()->Height() - narrative.Image().Height())/2;
509 		break;
510 	case 5:
511 		x = (JApp::App()->Width() - narrative.Image().Width())/2;
512 		y = (JApp::App()->Height() - narrative.Image().Height())/2;
513 		break;
514 	case 6:
515 		x = JApp::App()->Width() - narrative.Image().Width();
516 		y = (JApp::App()->Height() - narrative.Image().Height())/2;
517 		break;
518 	default:
519 	case 7:
520 		x = 0;
521 		y = 0;
522 		break;
523 	case 8:
524 		x = (JApp::App()->Width() - narrative.Image().Width())/2;
525 		y = 0;
526 		break;
527 	case 9:
528 		x = JApp::App()->Width() - narrative.Image().Width();
529 		y = 0;
530 		break;
531 	}
532 
533 	narrative.Pos(x, y);
534 
535 	return true;
536 }
537 
Load(JTextFile & f)538 bool HCScriptActionNarrative::Load(JTextFile &f)
539 {
540 	char text[256];
541 	s32 align, speed, r, g, b, size, txtAlign, st;
542 	JFontAlign fontAlign;
543 	memset(text, 0, sizeof(text));
544 
545 	if (9 == sscanf(f.GetPos(),
546 									"[ NARRATIVE text=\"%[^\"]\" txtAlign=%d speed=%d size=%d align=%d r=%d g=%d b=%d subtype=%d ]",
547 									text, &txtAlign, &speed, &size, &align, &r, &g, &b, &st))
548 	{
549 		HCApp *app = (HCApp*)JApp::App();
550 
551 		JClamp(size, 1, 3);
552 		JFont *fnt;
553 
554 		switch (size)
555 		{
556 		default:
557 		case 1: fnt = app->FontSmall(); break;
558 		case 2: fnt = app->FontMedium(); break;
559 		case 3: fnt = app->FontLarge(); break;
560 		}
561 
562 		s32 oldSpeed = HCText::Speed();
563 
564 		switch (txtAlign % 3)
565 		{
566 		case 0:
567 			fontAlign = JFONTALIGN_RIGHT;
568 			break;
569     default:
570 		case 1:
571 			fontAlign = JFONTALIGN_LEFT;
572 			break;
573 		case 2:
574 			fontAlign = JFONTALIGN_CENTER;
575 			break;
576 		}
577 
578 		Init(align, text, &app->Level()->Theme(), fnt, fontAlign, st, r, g, b);
579 
580 		HCText::Speed(oldSpeed);
581 	}
582 	else
583 	{
584 		fprintf(stderr, "HCScriptActionNarrative: Failed to load!\n");
585 
586 		return false;
587 	}
588 
589 	return true;
590 }
591 
Update()592 s32 HCScriptActionNarrative::Update()
593 {
594 	if (!finished)
595 	{
596 		if (!narrative.Visible())
597 		{
598 			finished = true;
599 		}
600 
601 		return 1;
602 	}
603 
604 	return 0;
605 }
606 
Current()607 void HCScriptActionNarrative::Current()
608 {
609 	narrative.Reset();
610 	((HCApp*)JApp::App())->Level()->Narrative(&narrative);
611 }
612 
Init(const char * filename,s32 loops,bool waitToEnd)613 bool HCScriptActionSound::Init(const char *filename, s32 loops, bool waitToEnd)
614 {
615 	numLoops = loops;
616 
617 	if (!waitToEnd)
618 	{
619 		finished = true;
620 	}
621 
622 	if (JApp::App()->SoundEnabled())
623 	{
624 		return (sound.LoadWave(filename));
625 	}
626 	else
627 	{
628 		return true;
629 	}
630 
631 	return false;
632 }
633 
Current()634 void HCScriptActionSound::Current()
635 {
636 	if (JApp::App()->SoundEnabled())
637 	{
638 		sound.Play(-1, numLoops);
639 	}
640 }
641 
Load(JTextFile & f)642 bool HCScriptActionSound::Load(JTextFile &f)
643 {
644 	s32 waitToEnd, loops;
645   char file[1024];
646 
647 	if (3 == sscanf(f.GetPos(), "[ SOUND file=\"%[^\"]\" loops=%d waitToEnd=%d ]",
648 									file, &loops, &waitToEnd))
649 	{
650 		char filename[1024];
651 		snprintf(filename, sizeof(filename), "%s%s", HC_DATA_DIR, file);
652 		return Init(filename, loops, waitToEnd != 0);
653 	}
654 
655 	return false;
656 }
657 
Update()658 s32 HCScriptActionSound::Update()
659 {
660 	if (!finished)
661 	{
662 		if (!sound.IsPlaying())
663 		{
664 			finished = true;
665 		}
666 	}
667 
668 	return 0;
669 }
670 
Current()671 void HCScriptActionWait::Current()
672 {
673 	timer.Start(ms);
674 }
675 
Init(s32 millis)676 bool HCScriptActionWait::Init(s32 millis)
677 {
678 	ms = millis;
679 
680 	return true;
681 }
682 
Load(JTextFile & f)683 bool HCScriptActionWait::Load(JTextFile &f)
684 {
685 	s32 millis;
686 
687 	if (1 == sscanf(f.GetPos(), "[ WAIT millis=%d ]", &millis))
688 	{
689 		return Init(millis);
690 	}
691 
692 	return false;
693 }
694 
Update()695 s32 HCScriptActionWait::Update()
696 {
697 	if (!finished)
698 	{
699 		if (timer.Changed())
700 		{
701 			finished = true;
702 		}
703 	}
704 
705 	return 0;
706 }
707