home *** CD-ROM | disk | FTP | other *** search
/ Acorn User 10 / AU_CD10.iso / Archived / Updates / Flash / flashplayer / flashlib / c++ / program < prev    next >
Encoding:
Text File  |  2000-06-04  |  20.6 KB  |  920 lines

  1. /////////////////////////////////////////////////////////////
  2. // Flash Plugin and Player
  3. // Copyright (C) 1998,1999 Olivier Debon
  4. //
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU General Public License
  7. // as published by the Free Software Foundation; either version 2
  8. // of the License, or (at your option) any later version.
  9. //
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. // GNU General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program; if not, write to the Free Software
  17. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18. //
  19. ///////////////////////////////////////////////////////////////
  20. //  Author : Olivier Debon  <odebon@club-internet.fr>
  21. //
  22.  
  23. #include "swf.h"
  24.  
  25. #if defined(RISCOS)
  26. #include "os.h"
  27. #endif
  28.  
  29. #define NOTHING  0x0
  30. #define WAKEUP   0x1
  31. #define GOTO     0x2
  32. #define REFRESH  0x4
  33.  
  34. #ifdef RCSID
  35. static char *rcsid = "$Id: program.cc,v 1.4 1999/09/03 15:17:41 ode Exp $";
  36. #endif
  37.  
  38. #define PRINT 0
  39.  
  40. int debug = 0;
  41.  
  42. Program::Program(FlashMovie *movie, long n)
  43. {
  44.     long f;
  45.  
  46.         this->movie = movie;
  47.  
  48.     totalFrames = 0;
  49.  
  50.     dl = new DisplayList(movie);
  51.     if (dl == NULL) return;
  52.     frames = new Frame[n];
  53.     if (frames == NULL) {
  54.         delete dl;
  55.         return;
  56.     }
  57.  
  58.     nbFrames = 0;
  59.     totalFrames = n;
  60.     currentFrame = 0;
  61.     loadingFrame = 0;
  62.     movieWait = 1;
  63.     nextFrame = currentFrame;
  64.     for(f = 0; f < n; f++)
  65.     {
  66.         frames[f].controls = 0;
  67.         frames[f].label = NULL;
  68.     }
  69.  
  70.     movieStatus = MoviePlay;
  71.     settings = 0;
  72. }
  73.  
  74. Program::~Program()
  75. {
  76.     int i;
  77.     Control *ctrl, *ctrl1;
  78.  
  79.     delete dl;
  80.  
  81.     if (frames != NULL) {
  82.         for(i=0;i<nbFrames;i++) {
  83.         ctrl = frames[i].controls;
  84.         if (frames[i].label) free(frames[i].label);
  85.         while (ctrl != NULL) {
  86.             ctrl1 = ctrl->next;
  87.             ctrl->next = NULL;
  88.             delete ctrl;
  89.             ctrl = ctrl1;
  90.         }
  91.         }
  92.  
  93.         delete[] frames;
  94.     }
  95. }
  96.  
  97. void
  98. Program::validateLoadingFrame()
  99. {
  100.     nbFrames = loadingFrame;
  101.     loadingFrame++;
  102.     movieWait = 0;
  103. }
  104.  
  105. Frame    *
  106. Program::getFrames()
  107. {
  108.     return frames;
  109. }
  110.  
  111. long
  112. Program::getNbFrames()
  113. {
  114.     return nbFrames;
  115. }
  116.  
  117. DisplayList *
  118. Program::getDisplayList()
  119. {
  120.     return dl;
  121. }
  122.  
  123. void
  124. Program::gotoFrame(GraphicDevice *gd, long frame)
  125. {
  126.     long f;
  127.  
  128.     //printf("GotoFrame %d  (Current = %d)\n", frame, currentFrame);
  129.     dl->clearList();
  130.  
  131.     for(f=0; f <= frame; f++) {
  132.         runFrame(gd, 0, f, 0);
  133.     }
  134. }
  135.  
  136. long
  137. Program::runFrame(GraphicDevice *gd, SoundMixer *sm, long f, long action)
  138. {
  139.     Control        *ctrl;
  140.     Character    *character;
  141.     Matrix        *matrix;
  142.     Cxform        *cxform;
  143.     long         status = NOTHING;
  144.     long         update = 0;
  145.     char        *name;
  146.  
  147. #if PRINT&1
  148.     if (action) printf("Prog %x (dl=%x): Frame N° %d/%d\n", this, this->dl, f, nbFrames-1);
  149. #endif
  150.         movie->buttons_updated = 0;
  151.  
  152.     for(ctrl = frames[f].controls; ctrl; ctrl = ctrl->next)
  153.     {
  154.         switch (ctrl->type)
  155.         {
  156.             case ctrlPlaceObject:
  157.             case ctrlPlaceObject2:
  158.                 character = 0;
  159.                 matrix = 0;
  160.                 cxform = 0;
  161.                 name = "";
  162.                 if (ctrl->flags & placeHasCharacter) {
  163.                     character = ctrl->character;
  164.                 }
  165.                 if (ctrl->flags & placeHasMatrix) {
  166.                     matrix = &ctrl->matrix;
  167.                 }
  168.                 if (ctrl->flags & placeHasColorXform) {
  169.                     cxform = &ctrl->cxform;
  170.                 }
  171.                 if (ctrl->flags & placeHasName) {
  172.                     name = ctrl->name;
  173.                 }
  174.                 if (!ctrl->clipDepth) {    // Ignore
  175.                     dl->placeObject(gd,character, ctrl->depth, matrix, cxform, name);
  176.                     update = 1;
  177.                 }
  178.                 break;
  179.             case ctrlRemoveObject:
  180.                 character = ctrl->character;
  181.  
  182.                 if (!character) break;    // Should not happen
  183.  
  184.                 dl->removeObject(gd, character, ctrl->depth);
  185.                 if (action) {
  186.                     character->reset();
  187.                     update = 1;
  188.                 }
  189.                 break;
  190.             case ctrlRemoveObject2:
  191.                 character = dl->removeObject(gd,NULL, ctrl->depth);
  192.                 if (character && action) {
  193.                     character->reset();
  194.                     update = 1;
  195.                 }
  196.                 break;
  197.         // Actions
  198.             case ctrlDoAction:
  199.                 if (action) {
  200.                     status = doAction(gd, ctrl->actionRecords, sm);
  201.                 }
  202.                 break;
  203.             case ctrlStartSound:
  204.                 if (action && sm) {
  205.                     sm->startSound( (Sound *)ctrl->character, ctrl->loops, ctrl->syncflags );
  206.                 }
  207.                 break;
  208.             case ctrlStopSound:
  209.                 if (action && sm) {
  210.                     sm->stopSounds();
  211.                 }
  212.                 break;
  213.             case ctrlBackgroundColor:
  214.                 if (action) {
  215.                     if (gd->setBackgroundColor(ctrl->color)) {
  216.                         dl->bbox.xmin = -32768;
  217.                         dl->bbox.ymin = -32768;
  218.                         dl->bbox.xmax =  32768;
  219.                         dl->bbox.ymax =  32768;
  220.                     }
  221.                 }
  222.                 break;
  223.         }
  224.     }
  225.         if (movie->buttons_updated) {
  226.             dl->updateButtons(movie);
  227.         }
  228.  
  229.     if (status & GOTO) {
  230.         if (nextFrame < nbFrames) {
  231.             gotoFrame(gd,nextFrame);
  232.             if (nextFrame != f)
  233.             if (movieStatus == MoviePaused) runFrame(gd,sm,nextFrame);
  234.             update = 1;
  235.         }
  236.     }
  237.  
  238. #if PRINT&1
  239.     if (action) printf("Frame N° %d ready\n", f);
  240. #endif
  241.     return update;
  242. }
  243.  
  244. long
  245. Program::nestedMovie(GraphicDevice *gd, SoundMixer *sm, Matrix *mat, Cxform *cxform)
  246. {
  247.     if (movieStatus == MoviePlay) {
  248.         // Movie Beeing Played
  249.         advanceFrame();
  250.         if (currentFrame == 0) {
  251.             dl->clearList();
  252.         }
  253.         runFrame(gd, sm, currentFrame);
  254.         if (nbFrames == 1) {
  255.             pauseMovie();
  256.         }
  257.     }
  258.  
  259.     return (movieStatus == MoviePlay);
  260. }
  261.  
  262. long
  263. Program::processMovie(GraphicDevice *gd, SoundMixer *sm)
  264. {
  265.     int wakeUp = 0;
  266.  
  267. #if PRINT&1
  268.     printf("Prog %x (dl=%x): Current = %d     Next = %d    Wait = %d  Status = %d\n", this, this->dl, currentFrame, nextFrame, movieWait, movieStatus);
  269. #endif
  270.  
  271.     if (movieStatus == MoviePlay && movieWait == 0) {
  272.         // Movie Beeing Played
  273.         advanceFrame();
  274.         if (currentFrame == 0) {
  275.             dl->clearList();
  276.         }
  277.         wakeUp |= runFrame(gd, sm, currentFrame);
  278.         wakeUp |= dl->updateSprites();
  279.         if (nextFrame == nbFrames) {
  280.             if (nbFrames != totalFrames) {
  281.                 movieWait = 1;
  282.             } else if ((settings & PLAYER_LOOP) == 0) {
  283.                 pauseMovie();
  284.             }
  285.         }
  286.     } else {
  287.         wakeUp |= dl->updateSprites();
  288.     }
  289.  
  290.     if (wakeUp) {
  291.         render = 1;
  292.     }
  293.  
  294.     return (wakeUp || movieStatus == MoviePlay);
  295. }
  296.  
  297. /* timer (ms) -1 = delete timer */
  298. void setFlashTimer(struct timeval *tv, int time_ms)
  299. {
  300.     if (time_ms == -1) {
  301.         tv->tv_sec = -1;
  302.     } else {
  303. #if defined(RISCOS)
  304.         tv->tv_sec = os_read_monotonic_time() + time_ms * 100;
  305. #else
  306.         gettimeofday(tv,0);
  307.  
  308.         tv->tv_usec += time_ms*1000;
  309.         while (tv->tv_usec > 1000000) {
  310.             tv->tv_usec -= 1000000;
  311.             tv->tv_sec++;
  312.         }
  313. #endif
  314.     }
  315. }
  316.  
  317. int checkFlashTimer(struct timeval *tv)
  318. {
  319.     struct timeval now;
  320.  
  321.     if (tv->tv_sec == -1) return 0;
  322.  
  323. #if defined(RISCOS)
  324.     now.tv_sec = os_read_monotonic_time();
  325.     return now.tv_sec >= tv->tv_sec;
  326. #else
  327.     gettimeofday(&now,0);
  328.     return (now.tv_sec > tv->tv_sec ||
  329.             (now.tv_sec == tv->tv_sec && now.tv_usec >= tv->tv_usec));
  330. #endif
  331. }
  332.  
  333. /* bbox */
  334. typedef struct {
  335.     long x1,y1,x2,y2;
  336. } ButtonBoundingBox;
  337.  
  338.  
  339. static void button_bbox_func(void *id, long y, long start, long end)
  340. {
  341.     ButtonBoundingBox *h = (ButtonBoundingBox *) id;
  342.  
  343.     if (y < h->y1) h->y1 = y;
  344.     if (y > h->y2) h->y2 = y;
  345.     if (start < h->x1) h->x1 = start;
  346.     if (end > h->x2) h->x2 = end;
  347. }
  348.  
  349. void computeBBox(FlashMovie *movie, Rect *rect, DisplayListEntry *e)
  350. {
  351.     ButtonBoundingBox bb;
  352.  
  353.     bb.x1 = LONG_MAX;
  354.     bb.y1 = LONG_MAX;
  355.     bb.x2 = LONG_MIN;
  356.     bb.y2 = LONG_MIN;
  357.  
  358.     e->character->getRegion(movie->gd,&e->renderMatrix,&bb,button_bbox_func);
  359.  
  360.     rect->xmin = bb.x1 / FRAC;
  361.     rect->xmax = bb.x2 / FRAC;
  362.     rect->ymin = bb.y1;
  363.     rect->ymax = bb.y2;
  364. }
  365.  
  366. void transform_coords(long *x_ptr,long *y_ptr, long cx, long cy, long dx, long dy)
  367. {
  368.     long x,y,x1,y1;
  369.     x = *x_ptr;
  370.     y = *y_ptr;
  371.  
  372.     x -= cx;
  373.     y -= cy;
  374.  
  375.     if (dx < 0) {
  376.         /* left */
  377.         x1 = - x;
  378.         y1 = y;
  379.     } else if (dy < 0) {
  380.         /* up */
  381.         y1 = x;
  382.         x1 = -y;
  383.     } else if (dy > 0) {
  384.         /* down */
  385.         y1 = x;
  386.         x1 = y;
  387.     } else {
  388.         /* right */
  389.         x1 = x;
  390.         y1 = y;
  391.     }
  392.  
  393.     *x_ptr = x1;
  394.     *y_ptr = y1;
  395. }
  396.  
  397. typedef struct {
  398.     FlashMovie *movie;
  399.     DisplayListEntry *emin,*cur_focus;
  400.     long dmin;
  401.     long w,cx,cy,dx,dy;
  402. } ButtonFocus;
  403.  
  404. static int button_focus(void *opaque, Program *prg, DisplayListEntry *e)
  405. {
  406.     ButtonFocus *h=(ButtonFocus *)opaque;
  407.     Rect rect;
  408.     long d,x,y;
  409.  
  410.     if (e != h->cur_focus) {
  411.         computeBBox(h->movie,&rect,e);
  412.         x = (rect.xmin + rect.xmax) / 2;
  413.         y = (rect.ymin + rect.ymax) / 2;
  414.  
  415.         /* transform the coords so that the angular sector is directed to the right */
  416.         transform_coords(&x,&y,h->cx,h->cy,h->dx,h->dy);
  417.  
  418.         /* inside it ? */
  419.         if ( x >= 0 &&
  420.              (y - x - h->w) <= 0 &&
  421.              (y + x + h->w) >= 0) {
  422.             d = x*x + y*y;
  423.  
  424.             if (d < h->dmin) {
  425.                 h->dmin = d;
  426.                 h->emin = e;
  427.             }
  428.         }
  429.     }
  430.     return 0;
  431. }
  432.  
  433. DisplayListEntry *moveFocus(FlashMovie *movie, long dx, long dy,
  434.                             DisplayListEntry *cur_focus)
  435. {
  436.     Rect cur_rect;
  437.     ButtonFocus h;
  438.  
  439.     h.movie = movie;
  440.     h.dx = dx;
  441.     h.dy = dy;
  442.  
  443.     computeBBox(movie,&cur_rect,cur_focus);
  444.     /* center */
  445.     h.cx = (cur_rect.xmin + cur_rect.xmax) / 2;
  446.     h.cy = (cur_rect.ymin + cur_rect.ymax) / 2;
  447.  
  448.     /* width/2 of the 45 degrees angular sector */
  449.     if (dy != 0) {
  450.         /* for vertical displacement, we have a larger width */
  451.         h.w = (cur_rect.xmax - cur_rect.xmin) / 2;
  452.     } else {
  453.         /* zero width for horizontal displacement */
  454.         h.w = 0;
  455.     }
  456.  
  457.     /* now we select the nearest button in the angular sector */
  458.     h.dmin = LONG_MAX;
  459.     h.emin = NULL;
  460.     h.cur_focus = cur_focus;
  461.  
  462.     exploreButtons(movie, &h, button_focus);
  463.  
  464.     return h.emin;
  465. }
  466.  
  467. static int button_newfocus(void *opaque, Program *prg, DisplayListEntry *e)
  468. {
  469.     * (DisplayListEntry **)opaque = e;
  470.     return 2;
  471. }
  472.  
  473. static int button_nextfocus(void *opaque, Program *prg, DisplayListEntry *e)
  474. {
  475.     static int found = 0;
  476.     DisplayListEntry **focus;
  477.  
  478.     focus = (DisplayListEntry **)opaque;
  479.     if (found) {
  480.         *focus = e;
  481.     found = 0;
  482.     return 2;
  483.     }
  484.     if (e == *focus) {
  485.         found = 1;
  486.     }
  487.     return 0;
  488. }
  489.  
  490.  
  491. /* XXX: should not be here (one level upper) */
  492. long
  493. Program::handleEvent(GraphicDevice *gd, SoundMixer *sm, FlashEvent *fe)
  494. {
  495.     ActionRecord    *action;
  496.     Program        *prog;
  497.     long         status = 0;
  498.     DisplayListEntry *cur_focus, *new_focus;
  499.     long dx,dy;
  500.     int             refresh;
  501.  
  502.     refresh = 0;
  503.  
  504.     switch(fe->type) {
  505.  
  506.     case FeKeyRelease:
  507.         if (movie->mouse_active == 0) {
  508.  
  509.             if (movie->cur_focus) {
  510.         movie->cur_focus->owner->updateBoundingBox(movie->cur_focus);
  511.                 movie->cur_focus->renderState = stateOver;
  512.         movie->cur_focus->owner->updateBoundingBox(movie->cur_focus);
  513.             }
  514.         }
  515.         break;
  516.  
  517.     case FeKeyPress:
  518.  
  519.         movie->mouse_active = 0;
  520.  
  521.         /* find the button which has the focus */
  522.         cur_focus = movie->cur_focus;
  523.  
  524.         if (fe->key == FeKeyEnter) {
  525.             /* selection */
  526.             if (cur_focus) {
  527.                 /* select the button */
  528.         cur_focus->owner->updateBoundingBox(cur_focus);
  529.                 cur_focus->renderState = stateDown;
  530.             ((Button *)cur_focus->character)->updateButtonState(cur_focus);
  531.         cur_focus->owner->updateBoundingBox(cur_focus);
  532.  
  533.                 movie->scheduledEvent.type = FeKeyRelease;
  534.                 movie->scheduledEvent.key = FeKeyEnter;
  535.  
  536.                 setFlashTimer(&movie->scheduledTime, 250); /* 250 ms down */
  537.             }
  538.         } else {
  539.             /* displacement */
  540.  
  541.             if (cur_focus == NULL) {
  542.                 /* no current focus : set one */
  543.                 exploreButtons(movie, &cur_focus, button_newfocus);
  544.                 if (cur_focus) {
  545.                     cur_focus->renderState = stateOver;
  546.             ((Button *)cur_focus->character)->updateButtonState(cur_focus);
  547.             cur_focus->owner->updateBoundingBox(cur_focus);
  548.                 }
  549.                 movie->cur_focus = cur_focus;
  550.             } else {
  551.                 /* move the focus (test) */
  552.                 switch(fe->key) {
  553.                 case FeKeyNext:
  554.                     /* Next available */
  555.             cur_focus->owner->updateBoundingBox(cur_focus);
  556.                     cur_focus->renderState = stateUp;
  557.             ((Button *)cur_focus->character)->updateButtonState(cur_focus);
  558.             cur_focus->owner->updateBoundingBox(cur_focus);
  559.                     exploreButtons(movie, &cur_focus, button_nextfocus);
  560.                     if (cur_focus) {
  561.                         cur_focus->renderState = stateOver;
  562.                 ((Button *)cur_focus->character)->updateButtonState(cur_focus);
  563.                 cur_focus->owner->updateBoundingBox(cur_focus);
  564.                     }
  565.                     movie->cur_focus = cur_focus;
  566.                     dx = 0;
  567.                     dy = 0;
  568.             break;
  569.                 case FeKeyUp:
  570.                     dx = 0;
  571.                     dy = -1;
  572.                     break;
  573.                 case FeKeyDown:
  574.                     dx = 0;
  575.                     dy = 1;
  576.                     break;
  577.                 case FeKeyLeft:
  578.                     dx = -1;
  579.                     dy = 0;
  580.                     break;
  581.                 case FeKeyRight:
  582.                     dx = 1;
  583.                     dy = 0;
  584.                     break;
  585.                 default:
  586.                     /* should not happen */
  587.                     dx = 0;
  588.                     dy = 0;
  589.                     break;
  590.                 }
  591.  
  592.                 if (dx != 0 || dy != 0) {
  593.  
  594.                     new_focus = moveFocus(movie, dx, dy, cur_focus);
  595.                     if (new_focus) {
  596.             cur_focus->owner->updateBoundingBox(cur_focus);
  597.                         cur_focus->renderState = stateUp;
  598.             ((Button *)cur_focus->character)->updateButtonState(cur_focus);
  599.             cur_focus->owner->updateBoundingBox(cur_focus);
  600.  
  601.                 if (computeActions(movie, &prog, &action)) {
  602.                 status |= prog->doAction(gd, action, sm);
  603.                 }
  604.  
  605.                         new_focus->renderState = stateOver;
  606.             ((Button *)new_focus->character)->updateButtonState(new_focus);
  607.                         movie->cur_focus = new_focus;
  608.             new_focus->owner->updateBoundingBox(new_focus);
  609.                     } else {
  610.                 return 0;
  611.             }
  612.                 }
  613.             }
  614.         if (movie->cur_focus == NULL) return 0;
  615.         }
  616.         break;
  617.  
  618.     case FeMouseMove:
  619.         movie->mouse_active = 1;
  620.         movie->mouse_x = fe->x * FRAC;
  621.         movie->mouse_y = fe->y * FRAC;
  622.         dl->updateButtons(movie);
  623.         break;
  624.  
  625.     case FeButtonPress:
  626.         movie->mouse_active = 1;
  627.         movie->button_pressed = 1;
  628.         dl->updateButtons(movie);
  629.         break;
  630.  
  631.     case FeButtonRelease:
  632.         movie->mouse_active = 1;
  633.         movie->button_pressed = 0;
  634.         dl->updateButtons(movie);
  635.         break;
  636.  
  637.     default:
  638.         return 0;
  639.     }
  640.  
  641.     if (computeActions(movie, &prog, &action)) {
  642.         status |= prog->doAction(gd, action, sm);
  643.     }
  644.  
  645.     if (status & REFRESH) {
  646.         status |= WAKEUP;
  647.         refresh = 1;
  648.     }
  649.     if (status & GOTO) {
  650.         if (nextFrame < nbFrames) {
  651.         gotoFrame(gd, nextFrame);
  652.         if (movieStatus == MoviePaused) runFrame(gd,sm,nextFrame);
  653.         refresh = 1;
  654.     }
  655.     }
  656.  
  657.     if (refresh) {
  658.         dl->updateSprites();
  659.         render = 1;
  660.     }
  661.     return (refresh || movieStatus == MoviePlay);
  662. }
  663.  
  664. long
  665. Program::doAction(GraphicDevice *gd, ActionRecord *action, SoundMixer *sm)
  666. {
  667.     long status = NOTHING;
  668.         long f;
  669.     char *target = "";
  670.     long skip = 0;
  671.  
  672.     while(action)
  673.     {
  674.         if (skip) skip--;
  675.         else
  676.         switch (action->action)
  677.         {
  678.             case ActionPlaySound:
  679. #if PRINT&2
  680.                 printf("Prog %x : PlaySound\n", this);
  681. #endif
  682.                                 if (sm) {
  683.                                   sm->startSound(action->sound, 1, 0);
  684.                                 }
  685.                 status |= WAKEUP;
  686.                 break;
  687.             case ActionRefresh:
  688. #if PRINT&2
  689.                 printf("Prog %x : Refresh\n", this);
  690. #endif
  691.                 status |= REFRESH;
  692.                 break;
  693.             case ActionGotoFrame:
  694. #if PRINT&2
  695.                 printf("Prog %x : GotoFrame %d\n", this, action->frameIndex);
  696. #endif
  697.                 if (target[0] == 0) {
  698.                     if (action->frameIndex < nbFrames) {
  699.                         currentFrame = action->frameIndex;
  700.                         pauseMovie();
  701.                         status |= WAKEUP|GOTO;
  702.                     }
  703.                 }
  704.                 break;
  705.             case ActionGetURL:
  706. #if PRINT&2
  707.                 printf("Prog %x : GetURL %s target = %s\n", this, action->url, action->target);
  708. #endif
  709.                                 {
  710.                                     int len,level;
  711.                                     len = strlen(action->target);
  712.  
  713.                                     if (len > 6 && memcmp(action->target,"_level", 6) == 0) {
  714.                                         level = atoi(action->target + 6);
  715.                                         loadNewSwf(movie, action->url, level);
  716.                                     } else {
  717.                                         if (movie->getUrl) {
  718.                                             movie->getUrl(action->url, action->target, movie->getUrlClientData);
  719.                                         }
  720.                                     }
  721.                                 }
  722.                 break;
  723.             case ActionNextFrame:
  724.                 nextFrame = currentFrame+1;
  725.                 movieStatus = MoviePlay;
  726.                 status |= WAKEUP;
  727.                 break;
  728.             case ActionPrevFrame:
  729.                 nextFrame = currentFrame-1;
  730.                 status |= WAKEUP|GOTO;
  731.                 break;
  732.             case ActionPlay:
  733. #if PRINT&2
  734.                 printf("Prog %x : Play\n", this);
  735. #endif
  736.                 if (target[0] == 0) {
  737.                     movieStatus = MoviePlay;
  738.                     if ((status & GOTO) == 0) {
  739.                         if (currentFrame == nextFrame) advanceFrame();
  740.                     }
  741.                     status |= WAKEUP;
  742.                 }
  743.                 break;
  744.             case ActionStop:
  745. #if PRINT&2
  746.                 printf("Prog %x : Stop\n", this);
  747. #endif
  748.                 if (target[0] == 0) {
  749.                     movieStatus = MoviePaused;
  750.                     nextFrame = currentFrame;
  751.                 }
  752.                 break;
  753.             case ActionToggleQuality:
  754.                 break;
  755.             case ActionStopSounds:
  756.                 if (sm) {
  757.                     sm->stopSounds();
  758.                 }
  759.                 break;
  760.             case ActionWaitForFrame:
  761.                 if (action->frameIndex >= nbFrames) {
  762.                     skip = action->skipCount;
  763.                 }
  764.                 break;
  765.             case ActionSetTarget:
  766. #if PRINT&2
  767.                 printf("Prog %x : SetTarget '%s'\n", this, action->target);
  768. #endif
  769.                 target = action->target;
  770.                 break;
  771.             case ActionGoToLabel:
  772. #if PRINT&2
  773.                 printf("Prog %x : GotoFrame '%s'\n", this, action->frameLabel);
  774. #endif
  775.                                 f = searchFrame(gd, action->frameLabel, target);
  776.                                 if (f >= 0) {
  777.                     currentFrame = f;
  778.                     pauseMovie();
  779.                                     status |= WAKEUP|GOTO;
  780.                                 } else {
  781.                                     status |= REFRESH;
  782.                                 }
  783.                 break;
  784.         }
  785.         action = action->next;
  786.     }
  787.     return status;
  788. }
  789.  
  790. void
  791. Program::setCurrentFrameLabel(char *label)
  792. {
  793.     frames[loadingFrame].label = label;
  794. }
  795.  
  796. void
  797. Program::rewindMovie()
  798. {
  799.     currentFrame = 0;
  800.     nextFrame = 0;
  801. }
  802.  
  803. void
  804. Program::pauseMovie()
  805. {
  806.     movieStatus = MoviePaused;
  807.     nextFrame = currentFrame;
  808. }
  809.  
  810. void
  811. Program::continueMovie()
  812. {
  813.     movieStatus = MoviePlay;
  814. }
  815.  
  816. void
  817. Program::nextStepMovie()
  818. {
  819.     if (movieStatus == MoviePaused) {
  820.         advanceFrame();
  821.     }
  822. }
  823.  
  824. void
  825. Program::advanceFrame()
  826. {
  827.     currentFrame = nextFrame;
  828.     nextFrame = currentFrame+1;
  829.     if (currentFrame == nbFrames) {
  830.         currentFrame = 0;
  831.         nextFrame = 1;
  832.     }
  833. }
  834.  
  835. void
  836. Program::addControlInCurrentFrame(Control *ctrl)
  837. {
  838.     Control *c;
  839.  
  840.     ctrl->next = 0;
  841.     if (frames[loadingFrame].controls == 0) {
  842.         frames[loadingFrame].controls = ctrl;
  843.     } else {
  844.         for(c = frames[loadingFrame].controls; c->next; c = c->next);
  845.         c->next = ctrl;
  846.     }
  847. }
  848.  
  849. void
  850. Program::modifySettings(long flags)
  851. {
  852.     settings = flags;
  853. }
  854.  
  855. long
  856. Program::searchFrame(GraphicDevice *gd, char *label, char *target)
  857. {
  858.     long f;
  859.         DisplayListEntry *e;
  860.         Program *prg;
  861.  
  862.     // Current movie
  863.     if (target[0] == 0) {
  864.         for(f=0; f < nbFrames; f++)
  865.         {
  866.             if (frames[f].label && !strcmp(label,frames[f].label)) {
  867.             return f;
  868.             }
  869.         }
  870.     }
  871.  
  872.     // Kludge !!!
  873.     for (e = dl->list; e; e = e->next) {
  874.         if (e->character->isSprite()) {
  875.         prg = ((Sprite *)e->character)->program;
  876.         f = prg->searchFrame(gd,label,"");
  877.         if (f >= 0 && f < prg->nbFrames) {
  878.             prg->dl->updateBoundingBox(e);
  879.             prg->gotoFrame(gd, f);
  880.             prg->nextFrame = f;
  881.             prg->dl->updateBoundingBox(e);
  882.             return -1;
  883.         }
  884.         }
  885.     }
  886.  
  887.     return -1;
  888. }
  889.  
  890. void loadNewSwf(FlashMovie *movie, char *url, int level)
  891. {
  892.     CInputScript *s,*prev,**l;
  893.  
  894.     if (movie->getSwf == NULL) return;
  895.  
  896.     for(s = movie->main, prev = 0; s != NULL; prev = s, s = s->next) {
  897.         if (s->level == level) {
  898.         // Mark movie to be deleted
  899.         s->level = -1;
  900.         break;
  901.     }
  902.     }
  903.  
  904.     //printf("Unload movie @ %d\n", level);
  905.  
  906.     if (*url == 0) return;    // Just UnloadMovie
  907.  
  908.     s = new CInputScript(level);
  909.     if (s == NULL) return;
  910.  
  911.     /* insert it in the right order */
  912.     l = &movie->main;
  913.     while (*l != NULL && (*l)->level < level) l = &(*l)->next;
  914.     s->next = *l;
  915.     *l = s;
  916.  
  917.     // Notify the external loader of a new movie to load
  918.     movie->getSwf(url, level, movie->getSwfClientData);
  919. }
  920.