source: abuse/trunk/src/scene.cpp @ 555

Last change on this file since 555 was 555, checked in by Sam Hocevar, 11 years ago

ps3: make everything compile on the PS3. Of course, nothing links yet
because so much support is missing.

File size: 14.5 KB
Line 
1/*
2 *  Abuse - dark 2D side-scrolling platform game
3 *  Copyright (c) 1995 Crack dot Com
4 *  Copyright (c) 2005-2011 Sam Hocevar <sam@hocevar.net>
5 *
6 *  This software was released into the Public Domain. As with most public
7 *  domain software, no warranty is made or implied by Crack dot Com, by
8 *  Jonathan Clark, or by Sam Hocevar.
9 */
10
11#if defined HAVE_CONFIG_H
12#   include "config.h"
13#endif
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include <ctype.h>
19#include <fcntl.h>
20
21#include "specs.h"
22#include "jwindow.h"
23#include "fonts.h"
24#include "timing.h"
25#include "scene.h"
26#include "game.h"
27#include "parse.h"
28#include "cache.h"
29
30
31class string_node
32{
33  string_node *l,*r;
34  char *n;
35public :
36  string_node(char *Name, string_node *Left=NULL, string_node *Right=NULL)
37  { l = Left;
38    r = Right;
39    n = strdup(Name);
40  }
41  ~string_node() { free(n); }
42  char *name() { return n; }
43  string_node *left() { return l; }
44  string_node *right() { return r; }
45} ;
46
47
48/*class string_tree
49{
50  string_node *root;
51public :
52  string_tree() { root=NULL; }
53  void insert(char *name);
54
55} ; */
56
57
58
59char scene_filename[100];
60
61class scene_frame
62{
63public :
64  int picture;
65  long time,xc,yc;
66
67  scene_frame *next;
68  scene_frame(char *&s);
69  ~scene_frame() { cache.unreg(picture); }
70} ;
71
72
73scene_frame::scene_frame(char *&s)
74{
75  char tmp_name[50];
76  expect(get_token(s,tmp_name),sWORD,s);
77
78  picture=cache.reg(scene_filename,tmp_name);
79  if (picture<0)
80  {
81    printf("Frame image not found (%s)\n",tmp_name);
82    exit(0);
83  }
84
85
86  xc=yc=0;
87  time=-1;
88  if (token_type(s)==sLEFT_PAREN)  // is a descriptor included?
89  {
90    next_token(s);
91
92    xc=get_number(s);
93    if (token_type(s)!=sRIGHT_PAREN)
94    {
95      yc=get_number(s);
96      if (token_type(s)!=sRIGHT_PAREN)
97        time=get_number(s);
98    }
99    expect(get_token(s,tmp_name),sRIGHT_PAREN,s);
100  }
101
102  next=NULL;
103}
104
105
106
107class scene_sequence : public linked_node
108{
109public :
110  char *n;
111  scene_frame *first;
112  scene_sequence *next;
113  scene_sequence(char *&s);
114  ~scene_sequence();
115} ;
116
117
118
119scene_sequence::~scene_sequence()
120{ free(n);
121  while (first)
122  { scene_frame *p=first;
123    first=first->next;
124    delete p;
125  }
126}
127
128
129scene_sequence::scene_sequence(char *&s)
130{
131  scene_frame *cur;
132  char tmp_name[50];
133  expect(token_type(s),sLEFT_PAREN,s);
134  next_token(s);
135
136  expect(get_token(s,tmp_name),sWORD,s);
137  n = strdup(tmp_name);
138  cur = first=new scene_frame(s);
139
140  while (token_type(s)!=sRIGHT_PAREN)
141  {
142    cur->next=new scene_frame(s);
143    cur=cur->next;
144
145    next=NULL;
146  }
147  next_token(s);
148  next=NULL;
149}
150
151
152class scene_sequence_list
153{
154public :
155  scene_sequence *first;
156  scene_sequence_list(char *&s);
157  scene_sequence *get_seq(char *seq_name);
158  ~scene_sequence_list();
159} ;
160
161scene_sequence_list::~scene_sequence_list()
162{
163  scene_sequence *p;
164  while (first)
165  {
166    p=first;
167    first=first->next;
168    delete p;
169  }
170}
171
172scene_sequence_list::scene_sequence_list(char *&s)
173{
174  scene_sequence *cur;
175  expect(token_type(s),sLEFT_PAREN,s);
176  next_token(s);
177
178  cur=first=new scene_sequence(s);
179  while (token_type(s)!=sRIGHT_PAREN)
180  {
181    cur->next=new scene_sequence(s);
182    cur=cur->next;
183  }
184  next_token(s);
185}
186
187scene_sequence *scene_sequence_list::get_seq(char *seq_name)
188{
189  scene_sequence *s=first;
190  while (s && strcmp(s->n,seq_name)) s=s->next;
191  if (!s)
192  {
193    printf("No sequence named %s\n",seq_name);
194    exit(1);
195  }
196  return s;
197}
198
199
200class scene_character
201{
202  scene_sequence_list *seq_list;
203
204  game_object *me;
205
206public :
207  char *n;
208  scene_character *next;
209  scene_sequence *current_seq;
210  scene_frame *current_frame;
211
212  time_marker *last_frame;
213  void draw();
214  void area(int &x1, int &y1, int &x2, int &y2);
215  scene_character(char *&s);
216  void set_seq(char *seq_name)
217  { current_seq=seq_list->get_seq(seq_name); }
218  int x() { return the_game->screenx(me->x)-cache.fig(current_frame->picture)->xcfg; }
219  int y() { return the_game->screeny(me->y)-cache.fig(current_frame->picture)->forward->height(); }
220  int next_frame();  // true if sequence is done
221  ~scene_character() { free(n); delete seq_list; if (last_frame) delete last_frame; }
222} ;
223
224
225int scene_character::next_frame()
226{
227  me->x+=current_frame->xc;
228  me->y+=current_frame->yc;
229
230  current_frame=current_frame->next;        // advance the picture
231
232  if (last_frame)                           // save the time stamp, delete old one
233    delete last_frame;
234  last_frame=new time_marker;
235
236  if (!current_frame)                      // end of sequence?
237  {
238    current_frame=current_seq->first;       // reset and return 1
239    return 1;
240  }
241  else return 0;
242}
243
244
245void scene_character::area(int &x1, int &y1, int &x2, int &y2)
246{
247
248  x1=x();
249  y1=y();
250  y2=x2=0;
251
252  scene_frame *p=current_seq->first;
253  while (p)
254  {
255    if (x()+cache.fig(p->picture)->width()-1>x2)
256      x2=x()+cache.fig(p->picture)->width()-1;
257    if (y()+cache.fig(p->picture)->height()-1>y2)
258      y2=y()+cache.fig(p->picture)->height()-1;
259    p=p->next;
260  }
261}
262
263
264void scene_character::draw()
265{
266  cache.fig(current_frame->picture)->forward->put_image(screen,x(),y());
267
268}
269
270
271scene_character::scene_character(char *&s)
272{
273  char tmp[100];
274  expect(get_token(s,tmp),sLEFT_PAREN,s);
275  expect(get_token(s,tmp),sWORD,s);
276  n = strdup(tmp);
277  expect(get_token(s,tmp),sNUMBER,s);
278
279/*  if (atoi(tmp)==0) */
280
281  me=current_level->main_character();
282
283
284  seq_list=new scene_sequence_list(s);
285  current_seq=seq_list->first;
286  current_frame=current_seq->first;
287  expect(get_token(s,tmp),sRIGHT_PAREN,s);
288
289  last_frame=NULL;
290  next=NULL;
291}
292
293
294class scene_character_list
295{
296public :
297  scene_character *first;
298  scene_character_list(char *&s);
299  void inital_states(char *&s);
300  scene_character *get(char *name);
301 ~scene_character_list();
302} ;
303
304scene_character  *scene_character_list::get(char *name)
305{
306  scene_character *s=first;
307  while (s)
308  {
309    if (!strcmp(s->n,name)) return s;
310    s=s->next;
311  }
312  printf("Character %s not found!\n",name);
313  exit(1);
314}
315
316
317scene_character_list::~scene_character_list()
318{
319  scene_character *p;
320  while (first)
321  {
322    p=first;
323    first=first->next;
324    delete p;
325  }
326}
327
328scene_character_list::scene_character_list(char *&s)
329{
330  scene_character *cur;
331  expect(token_type(s),sLEFT_PAREN,s);
332  next_token(s);
333
334  cur=first=new scene_character(s);
335
336  while (token_type(s)!=sRIGHT_PAREN)
337  {
338    cur->next=new scene_character(s);
339    cur=cur->next;
340  }
341  next_token(s);
342}
343
344
345void scene_character_list::inital_states(char *&s)
346{
347  char ch[50],seq[50];
348
349  do
350  {
351    expect(get_token(s,ch),sLEFT_PAREN,s);
352    expect(get_token(s,ch),sWORD,s);
353    expect(get_token(s,seq),sWORD,s);
354    scene_character *c=first;
355    while (c && strcmp(c->n,ch)) c=c->next;
356    if (!c)
357    {
358      printf("No character named %s, at %s\n",ch,s);
359      exit(0);
360    } else c->set_seq(seq);
361    expect(get_token(s,ch),sRIGHT_PAREN,s);
362  } while (token_type(s)!=sRIGHT_PAREN);
363}
364
365class text_blocker
366{
367public :
368  int x1,y1,x2,y2;
369  text_blocker *next;
370  text_blocker(int X1, int Y1, int X2, int Y2, text_blocker *Next)
371  { x1=X1;
372    y1=Y1;
373    x2=X2;
374    y2=Y2;
375    next=Next;
376  }
377} ;
378
379
380int text_draw(int y, int x1, int y1, int x2, int y2, char const *buf,
381          text_blocker *first, JCFont *font)
382{
383  int cx1, cy1, cx2, cy2, word_size, word_len;
384  screen->GetClip(cx1, cy1, cx2, cy2);
385  screen->InClip(x1,y1,x2+1,y2+1);
386  int h=font->height()+2,w=font->width(),x=x1,dist;
387  y+=y1;
388  char const *word_start;
389
390  while (*buf)
391  {
392    do
393    {
394      if (*buf=='\\' && buf[1]=='n')
395      {
396    x=x1;
397    y+=h*2;
398    buf+=2;
399      }
400
401      // skip space
402      if (*buf==' ' || *buf=='\r' || *buf=='\n' || *buf=='\t')
403      {
404    x+=w;
405    while (*buf==' ' || *buf=='\r' || *buf=='\n' || *buf=='\t')   // skip space until next word
406          buf++;
407      }
408
409      word_start=buf;
410      for (word_len=0,word_start=buf,word_size=0; *buf && *buf!=' ' && *buf!='\r' && *buf!='\n' &&
411       *buf!='\t' && (*buf!='\\' || buf[1]!='n'); buf++,word_size+=w,word_len++);
412
413      if (word_size<x2-x1) // make sure the word can fit on the screen
414      {
415    if (word_size+x>x2)    // does word not fit on line?
416    {
417      y+=h;                // go to next line
418      x=x1;
419    }
420      }
421
422
423      if (y+h<y1)         // word on screen yet?
424    x+=word_size;
425
426    } while (y+h<y1);     // if not on screen yet, fetch next word
427
428/*    dist=100;
429    for (n=first; n; n=n->next)
430    {
431      if (x<n->x1)
432        minx=(n->x1-x);
433      else if (x>n->x2)
434        minx=(x-n->x2);
435      else minx=0;
436
437      if (y<n->y1)
438        miny=(n->y1-y);
439      else if (y>n->y2)
440        miny=(y-n->y2);
441      else miny=0;
442
443      dist=min(dist,max(minx,miny));
444    }
445
446
447    if (dist<=8) dist=8;
448    else if (dist>31) dist=31;      */
449
450    dist=31;
451    if (y-y1<dist)
452      if (y-y1<8) dist=8;
453      else dist=y-y1;
454    if (y2-y<dist)
455      if (y2-y<8) dist=8;
456      else dist=y2-y;
457
458    if (y>y2) return 0;
459
460    while (word_len--)
461    {
462      font->put_char(screen,x+1,y+1,*word_start,0);
463      font->put_char(screen,x,y,*word_start,32-dist);
464      word_start++;
465      x+=w;
466    }
467
468  }
469
470  screen->SetClip(cx1, cy1, cx2, cy2);
471  return (y<=y1);
472}
473
474
475struct scene_data_struct       // define a name for the structure so that we can inspect in gdb
476{
477  int x1,y1,x2,y2,
478      pan_vx,pan_yv,pan_steps,
479      frame_speed,scroll_speed,pan_speed;
480} scene_data;
481
482
483
484
485
486void play_scene(char *script, char *filename, JCFont *font)
487{
488  char *s=script;
489  char token[90];
490  text_blocker *text_blockers=NULL;
491
492  char *strng=(char *)malloc(MAX_SCROLL_DATA);
493  strcpy(scene_filename,filename);
494
495  int x1,y1,x2,y2,done,pan_xv=0,pan_yv=0,pan_steps=0,
496      text_loaded=0,frame_speed=100,scroll_speed=50,pan_speed=60,abort=0,text_step=-2;
497
498  int cx1, cy1, cx2, cy2;
499
500  the_game->draw(1);
501
502  screen->GetClip(cx1, cy1, cx2, cy2);
503  screen->SetClip(the_game->viewx1, the_game->viewy1,
504                   the_game->viewx2 + 1, the_game->viewy2 + 1);
505
506
507
508
509  expect(get_token(s,token),sLEFT_PAREN,s);
510  scene_character_list cl(s);
511  int y;
512
513  do
514  {
515    expect(get_token(s,token),sLEFT_PAREN,s);   // list of transitions start
516    // ACTIONS
517    time_marker *last_text_time=NULL;
518    time_marker *last_pan_time=NULL;
519    do
520    {
521      expect(get_token(s,token),sLEFT_PAREN,s);
522      expect(get_token(s,token),sWORD,s);
523
524      if (!strcmp(token,"pan"))
525      {
526    pan_xv=get_number(s);
527    pan_yv=get_number(s);
528        pan_steps=get_number(s);
529      }
530      else if (!strcmp(token,"states"))
531        cl.inital_states(s);
532      else if (!strcmp(token,"scroll_speed"))
533        scroll_speed=get_number(s);
534      else if (!strcmp(token,"pan_speed"))
535        pan_speed=get_number(s);
536      else if (!strcmp(token,"frame_speed"))
537        frame_speed=get_number(s);
538      else if (!strcmp(token,"text_region"))
539      {
540    x1=the_game->viewx1+get_number(s);
541    y1=the_game->viewy1+get_number(s);
542    x2=the_game->viewx1+get_number(s);
543    y2=the_game->viewy1+get_number(s);
544    y=y2-y1;
545      } else if (!strcmp(token,"text_block"))
546      {
547    int sx1=get_number(s)+the_game->viewx1;
548    int sy1=get_number(s)+the_game->viewy1;
549    int sx2=get_number(s)+the_game->viewx1;
550    int sy2=get_number(s)+the_game->viewy1;
551    text_blockers=new text_blocker(sx1,sy1,sx2,sy2,text_blockers);
552      } else if (!strcmp(token,"block"))
553      {
554    int sx1,sy1,sx2,sy2;
555    expect(get_token(s,token),sWORD,s);
556    cl.get(token)->area(sx1,sy1,sx2,sy2);
557    text_blockers=new text_blocker(sx1,sy1,sx2,sy2,text_blockers);
558      }
559      else if (!strcmp(token,"scroll"))
560      {
561    expect(get_token(s,strng),sSTRING,s);
562    text_loaded=1;
563    y=y2-y1;
564      } else if (!strcmp(token,"wait"))
565      {
566    expect(get_token(s,token),sWORD,s);
567    printf("waiting for %s\n",token);
568    done=0;
569
570
571
572
573    int old_dev=dev;
574    dev=dev&(0xffff-DRAW_PEOPLE_LAYER);
575
576
577    do
578    {
579      the_game->draw_map();
580
581      time_marker cur_time;
582      if (pan_steps)
583      {
584        if (last_pan_time)
585        {
586          if ((int)(cur_time.diff_time(last_pan_time)*1000)>pan_speed)
587          {
588        the_game->pan(pan_xv,pan_yv);
589        pan_steps--;
590        delete last_pan_time;
591        if (pan_steps)
592           last_pan_time=new time_marker;
593        else last_pan_time=NULL;
594          }
595        } else last_pan_time=new time_marker;
596      }
597
598      scene_character *first=cl.first;
599      while (first)
600      {
601        first->draw();
602
603        if (!first->last_frame)
604          first->last_frame=new time_marker;
605        else
606        {
607          int time=first->current_frame->time,advance=0;
608          if (time>=0)
609          {
610             if ((int)(cur_time.diff_time(first->last_frame)*1000)>time)
611          advance=1;
612          }
613          else
614          {
615        if ((int)(cur_time.diff_time(first->last_frame)*1000)>frame_speed)
616          advance=1;
617          }
618
619          if (advance)
620          {
621            if (!strcmp(token,first->n))      // is this the character we are waiting on?
622        {
623              if (first->next_frame())
624            done=1;
625        } else first->next_frame();
626          }
627        }
628        first=first->next;
629      }
630      if (text_loaded)
631      {
632        text_loaded=(!text_draw(y,x1,y1,x2,y2,strng,text_blockers,font));
633        if (last_text_time)
634        {
635          if ((int)(cur_time.diff_time(last_text_time)*1000)>scroll_speed)
636          {
637              y+=text_step;
638            delete last_text_time;
639        if (text_loaded)
640          last_text_time=new time_marker;
641        else
642          last_text_time=NULL;
643          }
644        } else last_text_time=new time_marker;
645      }
646
647
648
649      if (!strcmp(token,"pan"))
650        if (pan_steps<=0) done=1;
651
652      if (!strcmp(token,"text"))
653        if (!text_loaded) done=1;
654
655      wm->flush_screen();
656      while (wm->event_waiting())
657      {
658        event ev;
659        wm->get_event(ev);
660        if (ev.type==EV_KEY)
661        {
662          switch (ev.key)
663          {
664            case JK_UP :
665            case JK_LEFT :
666          if (scroll_speed>=20)
667            scroll_speed-=20;
668          else text_step--;
669          break;
670        case JK_RIGHT :
671        case JK_DOWN :
672          if (text_step<-2)
673            text_step++;
674          else if (scroll_speed<200) scroll_speed+=20;
675          break;
676        case JK_ESC : abort=done=1; break;
677        case JK_ENTER : done=1; break;
678          }
679        }
680      }
681
682
683    } while (!done);
684    dev=old_dev;
685      }
686
687      expect(get_token(s,token),sRIGHT_PAREN,s);
688
689    } while (!abort && token_type(s)!=sRIGHT_PAREN);
690
691
692    if (!abort)
693      next_token(s);
694
695    // free up memory allocated
696    while (text_blockers)
697    {
698      text_blocker *n=text_blockers->next;
699      delete text_blockers;
700      text_blockers=n;
701    }
702    if (last_text_time)
703      delete last_text_time;
704    if (last_pan_time)
705      delete last_pan_time;
706
707  } while (!abort && token_type(s)!=sRIGHT_PAREN);
708  if (!abort)
709    next_token(s);
710
711  free(strng);
712  screen->SetClip(cx1, cy1, cx2, cy2);
713
714  the_game->draw(0);
715}
716
Note: See TracBrowser for help on using the repository browser.