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

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