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

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

imlib: refactor dirty_rect clipping coordiantes so that the upper
bound is no longer inclusive. It will make things easier in the future.

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