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