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

Last change on this file since 541 was 541, checked in by Sam Hocevar, 12 years ago

imlib: rename TImage to TransImage? for readability.

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