home *** CD-ROM | disk | FTP | other *** search
/ Revista do CD-ROM 123 / cdrom123.iso / edu / tux / Tuxtype2-1.5.3-installer.exe / src / scripting.c < prev    next >
Encoding:
C/C++ Source or Header  |  2004-03-25  |  19.9 KB  |  591 lines

  1. /***************************************************************************
  2.  -  file: scripting.c
  3.  -  description: scripting for lessons & instructions ...
  4.                              -------------------
  5.     begin                : Sun Dec 28, 2003
  6.     copyright            : Jesse Andrews (C) 2003
  7.     email                : tuxtype-dev@tux4kids.net
  8. ***************************************************************************/
  9.  
  10. /***************************************************************************
  11. *                                                                         *
  12. *   This program is free software; you can redistribute it and/or modify  *
  13. *   it under the terms of the GNU General Public License as published by  *
  14. *   the Free Software Foundation; either version 2 of the License, or     *
  15. *   (at your option) any later version.                                   *
  16. *                                                                         *
  17. ***************************************************************************/
  18.  
  19. #include "scripting.h"
  20.  
  21. char *getQuote(const char *in) {
  22.     int start, finish;
  23.     char *out;
  24.  
  25.     for (start=0; start<strlen(in) && in[start] != '"'; start++);  // find the first "
  26.  
  27.     if (start >= strlen(in)) return 0; // return null string if no " found
  28.  
  29.     start++; // move past the "
  30.     
  31.     for (finish=start; finish<strlen(in) && in[finish] != '"'; finish++); // find the next "
  32.  
  33.     if (finish >= strlen(in)) return 0; // return null string if no " found
  34.     
  35.     out = malloc(finish-start+2);
  36.     
  37.     snprintf(out, finish-start+1, &in[start]);
  38.     out[finish-start]=0;
  39.     
  40.     return out;
  41. }
  42.  
  43. int getInt(const char *in) {
  44.     char *t = getQuote(in);
  45.     int ans=-1;
  46.     if (t) {
  47.         ans = atoi(t);
  48.         free(t);
  49.     }
  50.     return ans;
  51. }
  52.  
  53. char hex2int(char b, char s) {
  54.     char ans=0;
  55.         
  56.     if      ((b>='0') && (b<='9'))       ans=16*(b-'0');
  57.     else if ((b>='A') && (b<='F'))       ans=16*(b-'A'+10);
  58.     else if ((b>='a') && (b<='f'))       ans=16*(b-'a'+10);
  59.     
  60.     if      ((s>='0') && (s<='9'))       ans+=(s-'0');
  61.     else if ((s>='A') && (s<='F'))       ans+=(s-'A'+10);
  62.     else if ((s>='a') && (s<='f'))       ans+=(s-'a'+10);
  63.  
  64.     return ans;
  65. }
  66.  
  67. SDL_Color *getColor(const char *in) {
  68.     char *col;
  69.     SDL_Color *out=malloc(sizeof(SDL_Color));
  70.     col = getQuote(in);
  71.     
  72.     if ((strlen(col)==7) && (col[0] == '#')) {
  73.         out->r = hex2int( col[1], col[2] );
  74.         out->g = hex2int( col[3], col[4] );
  75.         out->b = hex2int( col[5], col[6] );
  76.     }
  77.     
  78.     free(col);
  79.     
  80.     return out;
  81. }
  82.  
  83. scriptType *curScript=NULL;
  84. pageType *curPage=NULL;
  85. itemType *curItem=NULL;
  86.  
  87. int loadScript( const char *fn ) {
  88.     int i;
  89.     char str[FNLEN];
  90.     FILE *f;
  91.     
  92.     LOG( "loadScript()\n" );
  93.     
  94.     if (curScript) {
  95.         LOG( "script already in memory, removing now!\n");
  96.         closeScript();
  97.     }
  98.     
  99.     f = fopen( fn, "r" );
  100.  
  101.     if (f == NULL) { fprintf(stderr, "error loading script %s\n", fn);  return -1; }
  102.  
  103.     do {
  104.         fscanf(f, "%[^\n]\n", str);
  105.         if (strncmp("<script", str, 7)==0) {
  106.         
  107.             /* -- allocate space for the lesson info -- */
  108.             curScript = (scriptType *)calloc(1,sizeof(scriptType));
  109.             for (i=7; i<strlen(str) && str[i]!='>'; i++) {
  110.                 if ((str[i]=='t') && strncmp("title", &str[i], 5)==0)
  111.                     curScript->title = getQuote(&str[i+5]);
  112.  
  113.                 if ((str[i]=='b') && strncmp("bgcolor", &str[i], 7)==0)
  114.                     curScript->bgcolor = getColor(&str[i+7]);
  115.  
  116.                 if ((str[i]=='b') && strncmp("background", &str[i], 10)==0)
  117.                     curScript->background = getQuote(&str[i+10]);
  118.  
  119.                 if ((str[i]=='f') && strncmp("fgcolor", &str[i], 7)==0) 
  120.                     curScript->fgcolor = getColor(&str[i+7]); 
  121.             }
  122.         } else if (strncmp("<page", str, 5)==0) {
  123.             if (curScript==NULL) { fprintf(stderr, "CRITICAL XML ERROR: <page> should be in a <script> in file %s line (todo)", fn); exit(1); }
  124.  
  125.             if (curScript->pages==NULL) {
  126.                 curPage = (pageType *)calloc(1,sizeof(pageType));
  127.                 curPage->prev = curPage;
  128.                 curScript->pages = curPage; 
  129.             } else {
  130.                 curPage->next = (pageType *)calloc(1,sizeof(pageType));
  131.                 curPage->next->prev = curPage;
  132.                 curPage = curPage->next;
  133.             }
  134.  
  135.             for (i=5; i<strlen(str) && str[i]!='>'; i++) {
  136.                 if ((str[i]=='b') && strncmp("background", &str[i], 10)==0) 
  137.                     curPage->background = getQuote(&str[i+10]);
  138.  
  139.                 if ((str[i]=='t') && strncmp("title", &str[i], 5)==0) 
  140.                     curPage->title = getQuote(&str[i+5]);
  141.  
  142.                 if ((str[i]=='b') && strncmp("bgcolor", &str[i], 7)==0) 
  143.                     curPage->bgcolor = getColor(&str[i+7]);
  144.  
  145.                 if ((str[i]=='f') && strncmp("fgcolor", &str[i], 7)==0) 
  146.                     curPage->fgcolor = getColor(&str[i+7]);
  147.             }
  148.         } else if (strncmp("<text", str, 5)==0) {
  149.             if (curPage==NULL) { fprintf(stderr, "CRITICAL XML ERROR: <text> should be in a <page> in file %s line (todo)", fn); exit(1); }
  150.             if (curPage->items==NULL) {
  151.                 curItem = (itemType *)calloc(1,sizeof(itemType));
  152.                 curPage->items = curItem;
  153.             } else {
  154.                 curItem->next = (itemType *)calloc(1,sizeof(itemType));
  155.                 curItem = curItem->next;
  156.             }
  157.             
  158.             curItem->type = itemTEXT;
  159.             
  160.             for (i=5; i<strlen(str) && str[i]!='>'; i++) {
  161.             
  162.                 if ((str[i]=='s') && strncmp("size", &str[i], 4)==0) 
  163.             curItem->size = (char)getInt( &str[i+4] );
  164.  
  165.                 if ((str[i]=='a') && strncmp("align", &str[i], 5)==0) {
  166.                     char *t = getQuote(&str[i+5]);
  167.                     
  168.                     if (strlen(t)>=1) {
  169.                         if ((t[0] == 'l') || (t[0]=='L')) curItem->align='l';    // left
  170.                         if ((t[0] == 'c') || (t[0]=='C')) curItem->align='c';    // center
  171.                         if ((t[0] == 'r') || (t[0]=='R')) curItem->align='r';    // right
  172.  
  173.                         if ((t[0] == 'm') || (t[0]=='M')) curItem->align='c';    // let 'm'iddle work as "center"
  174.                     }
  175.                     
  176.                     free(t);
  177.                 }
  178.  
  179.                 if ((str[i]=='c') && strncmp("color", &str[i], 5)==0)
  180.                     curItem->color = getColor(&str[i+5]);
  181.             }
  182.             
  183.             /* --- grab the text between <text> and </text> --- */
  184.             {
  185.                 int start, finish;
  186.  
  187.                 for (start=5; start<strlen(str)-5 && str[start]!='>'; start++);
  188.  
  189.                 start++; // advance passed the '>'
  190.                 
  191.                 for (finish=strlen(str)-6; finish>5; finish--)
  192.                     if (strncmp( "</text>", &str[finish], 7)==0) break;
  193.                     
  194.                 finish--; // advance passed the '<'
  195.                 
  196.                 if (start<=finish) {
  197.                     curItem->data = (char *)calloc(1,finish-start+2);
  198.                     strncpy( curItem->data, &str[start], finish-start+1 );
  199.                 }else{
  200.             if (start == finish+1){
  201.                     curItem->data = (char *)calloc(1,2);
  202.                     curItem->data[0]=' ';
  203.             }
  204.                 }
  205.             }
  206.         } else if (strncmp("<img", str, 4)==0) {
  207.             if (curPage==NULL) { fprintf(stderr, "CRITICAL XML ERROR: <img> should be in a <page> in file %s line (todo)", fn); exit(1); }
  208.             if (curPage->items==NULL) {
  209.                 curItem = (itemType *)calloc(1,sizeof(itemType));
  210.                 curPage->items = curItem;
  211.             } else {
  212.                 curItem->next = (itemType *)calloc(1,sizeof(itemType));
  213.                 curItem = curItem->next;
  214.             }
  215.             
  216.             curItem->type = itemIMG;
  217.         curItem->x = curItem->y = -1;
  218.  
  219.             for (i=5; i<strlen(str); i++) {
  220.                 if ((str[i]=='o') && strncmp("onclickplay", &str[i], 11)==0) {
  221.                     curItem->onclick = getQuote(&str[i+3]);
  222.         }
  223.  
  224.                 if ((str[i]=='x') && strncmp(" x=", &str[i-1], 3)==0)
  225.                     curItem->x = getInt(&str[i+2]);
  226.  
  227.                 if ((str[i]=='y') && strncmp(" y=", &str[i-1], 3)==0)
  228.                     curItem->y = getInt(&str[i+2]);
  229.  
  230.                 if ((str[i]=='s') && strncmp("src", &str[i], 3)==0)
  231.                     curItem->data = getQuote(&str[i+3]);
  232.                     
  233.                 if ((str[i]=='a') && strncmp("align", &str[i], 5)==0) {
  234.                     char *t = getQuote(&str[i+5]);
  235.                     
  236.                     if (strlen(t)>=1) {
  237.                         if ((t[0] == 'l') || (t[0]=='L')) curItem->align='l';    // left
  238.                         if ((t[0] == 'c') || (t[0]=='C')) curItem->align='c';    // center
  239.                         if ((t[0] == 'r') || (t[0]=='R')) curItem->align='r';    // right
  240.  
  241.                         if ((t[0] == 'm') || (t[0]=='M')) curItem->align='c';    // let 'm'iddle work as "center"
  242.                     }
  243.                     
  244.                     free(t);
  245.                 }
  246.             }
  247.             
  248.         } else if (strncmp("<wav", str, 4)==0) {
  249.             if (curPage==NULL) { fprintf(stderr, "CRITICAL XML ERROR: <wav> should be in a <page> in file %s line (todo)", fn); exit(1); }
  250.             if (curPage->items==NULL) {
  251.                 curItem = (itemType *)calloc(1,sizeof(itemType));
  252.                 curPage->items = curItem;
  253.             } else {
  254.                 curItem->next = (itemType *)calloc(1,sizeof(itemType));
  255.                 curItem = curItem->next;
  256.             }
  257.             
  258.             curItem->type = itemWAV;
  259.         curItem->loop = 0;
  260.  
  261.             for (i=5; i<strlen(str); i++) {
  262.                 if ((str[i]=='s') && strncmp("src", &str[i], 3)==0)
  263.                     curItem->data = getQuote(&str[i+3]);
  264.  
  265.                 if ((str[i]=='l') && strncmp("loop", &str[i], 4)==0) {
  266.                     char *t = getQuote(&str[i+4]);
  267.                     
  268.                     if (strlen(t)>=1)
  269.                         if ((t[0] == 't') || (t[0]=='T')) curItem->loop=1;
  270.                         
  271.                     free(t);
  272.                 }
  273.             }
  274.         } else if (strncmp("</",str,2)==0);
  275.         else printf("not recognized: %s\n", str);
  276.     } while( !feof(f) );
  277.  
  278.     fclose(f);
  279.     
  280.     return 0;
  281. }
  282.  
  283. void runScript( void ) {
  284.  
  285.     Mix_Chunk *sounds[FNLEN];
  286.  
  287.     /* --- for on mouse click on an image --- */
  288.     Mix_Chunk *clickWavs[FNLEN];
  289.     SDL_Rect   clickRects[FNLEN];
  290.     
  291.  
  292.     curPage = curScript->pages;
  293.     while (curPage) {
  294.         int y = 0;
  295.  
  296.     int numWavs = 0;
  297.     int numClicks = 0;
  298.     
  299.         curItem = curPage->items;
  300.         
  301.         /* --- setup background color --- */
  302.         
  303.         if (curPage->bgcolor) SDL_FillRect( screen, NULL, COL2RGB(curPage->bgcolor) );
  304.         else if (curScript->bgcolor) SDL_FillRect( screen, NULL, COL2RGB(curScript->bgcolor) );
  305.         else SDL_FillRect( screen, NULL, 0 );
  306.   
  307.         /* --- setup background image --- */      
  308.         
  309.         if (curPage->background) {
  310.             SDL_Surface *img = LoadImage( curPage->background, IMG_ALPHA|IMG_NOT_REQUIRED );
  311.             SDL_BlitSurface( img, NULL, screen, NULL );
  312.             SDL_FreeSurface( img );
  313.         } else if (curScript->background) {
  314.             SDL_Surface *img = LoadImage( curScript->background, IMG_ALPHA|IMG_NOT_REQUIRED );
  315.             SDL_BlitSurface( img, NULL, screen, NULL );
  316.             SDL_FreeSurface( img );
  317.         }
  318.         
  319.         /* --- go through all the items in the page --- */
  320.         
  321.         while (curItem) {
  322.             switch (curItem->type) {
  323.                 case itemIMG:  printf(" |-> image\n"); {
  324.                 
  325.                     SDL_Surface *img = LoadImage( curItem->data, IMG_ALPHA|IMG_NOT_REQUIRED );
  326.                     if (img) {
  327.                     
  328.                         /* --- figure out where to put it! --- */
  329.                         SDL_Rect loc;
  330.  
  331.                         loc.w=img->w; loc.h=img->h;
  332.  
  333.                         /* --- if user specifies y location, use it --- */
  334.             if (curItem->y >= 0) {
  335.                 loc.y = curItem->y;
  336.             } else {
  337.                             loc.y=y; y+=loc.h;
  338.             }
  339.                         
  340.                         /* --- if user specifies x location, use it --- */
  341.             printf("%d\n", curItem->x);
  342.             if (curItem->x >= 0) {
  343.                 loc.x = curItem->x;
  344.             } else {
  345.                             switch (curItem->align) {
  346.                                 case 'r': loc.x = (screen->w)-(loc.w); break;
  347.                                 case 'c': loc.x = ((screen->w)-(loc.w))/2; break;
  348.                                 default:  loc.x = 0; break;
  349.                             }
  350.             }
  351.                         
  352.                         /* --- and blit! --- */
  353.                         SDL_BlitSurface( img, NULL, screen, &loc );
  354.  
  355.             /* --- does it do click and play --- */
  356.             if (curItem->onclick) {
  357.                 if (sys_sound)
  358.                     clickWavs[numClicks] = LoadSound( curItem->onclick );
  359.                 clickRects[numClicks].x = loc.x;
  360.                 clickRects[numClicks].y = loc.y;
  361.                 clickRects[numClicks].w = loc.w;
  362.                 clickRects[numClicks].h = loc.h;
  363.                 numClicks++;
  364.             }
  365.                     }
  366.                     SDL_FreeSurface(img);
  367.                 
  368.                 } break;
  369.                 
  370.                 case itemTEXT: printf(" |-> text\n"); {
  371.                 
  372.                     TTF_Font *myFont;
  373.                     SDL_Surface *img;
  374.                     SDL_Color *col;
  375.                     
  376.                     int shown, toshow, w, h; // used to wrap text
  377.                     char tmp[FNLEN];   // used to hold temp text for wrapping
  378.                     
  379.                     /* --- create font & render text --- */
  380.                     
  381.                     if (curItem->size > 0)
  382.                         myFont = LoadFont( ttf_font, (int)curItem->size );
  383.                     else
  384.                         myFont = LoadFont( ttf_font, 24 ); // default size is 24
  385.                     
  386.                     if      (curItem->color)     col = curItem->color;
  387.                     else if (curPage->fgcolor)   col = curPage->fgcolor;
  388.                     else if (curScript->fgcolor) col = curScript->fgcolor;
  389.                     else                         col = &white;
  390.  
  391.                     shown=0;
  392.                     
  393.                     do {
  394.                         int ok=0;
  395.                         
  396.                         if ((shown > 0) && (curItem->data[shown] == ' ')) shown++;
  397.             
  398.                     strncpy( tmp, &curItem->data[shown], FNLEN-1 );
  399.                         
  400.                         tmp[FNLEN-1]=0;
  401.                         tmp[strlen(curItem->data)-shown]=0;
  402.                         
  403.                         for ( toshow=strlen(&curItem->data[shown]); !ok; toshow--) {
  404.                             if (toshow+1>FNLEN) continue;
  405.                             tmp[toshow]=0;
  406.                             TTF_SizeText( myFont, tmp, &w, &h);
  407.                             
  408.                             if (w+20<screen->w) ok=1;
  409.                         }
  410.                         
  411.                         shown += toshow + 1;
  412.  
  413.                         img = TTF_RenderText_Blended( myFont, tmp, *col );
  414.  
  415.                         if (img) {
  416.                     
  417.                             /* --- figure out where to put it! --- */
  418.                             SDL_Rect loc;
  419.                             loc.w=img->w; loc.h=img->h;
  420.                             loc.y=y; y+=loc.h;
  421.                         
  422.                             switch (curItem->align) {
  423.                                 case 'r': loc.x = (screen->w)-(loc.w)-10; break;
  424.                                 case 'c': loc.x = ((screen->w)-(loc.w))/2; break;
  425.                                 default:  loc.x = 10; break;
  426.                             }
  427.                         
  428.                             /* --- and blit! --- */
  429.                             SDL_BlitSurface( img, NULL, screen, &loc );
  430.                             SDL_FreeSurface( img );
  431.                         }
  432.                     
  433.                     } while (shown+1 < strlen(curItem->data));
  434.                     TTF_CloseFont( myFont );
  435.                 } break;
  436.                 case itemWAV: {
  437.             printf(" |-> wav\n"); 
  438.             // HACK, we need to make sure no more than 8 sounds or so..
  439.             sounds[numWavs] = LoadSound( curItem->data );
  440.             Mix_PlayChannel( numWavs, sounds[numWavs], -curItem->loop );
  441.             numWavs++;
  442.         } break;
  443.             }
  444.             curItem=curItem->next;
  445.         }
  446.         
  447.         SDL_Flip( screen );
  448.         
  449.         { int done=0;
  450.         while (!done) {
  451.             SDL_Delay(100);
  452.             while (SDL_PollEvent(&event)) {
  453.                 switch (event.type) {
  454.                 
  455.                     case SDL_MOUSEBUTTONDOWN: {
  456.                 int j;
  457.             for (j=0; j<numClicks; j++) 
  458.                 if (inRect( clickRects[j], event.button.x, event.button.y ))
  459.  
  460.             Mix_PlayChannel( numWavs+j, clickWavs[j], 0 );
  461.                        break;
  462.             }
  463.                     case SDL_QUIT:
  464.                         curPage = NULL; done=1; break;
  465.                     
  466.                     case SDL_KEYDOWN: 
  467.                         switch (event.key.keysym.sym) {
  468.                             case SDLK_ESCAPE: 
  469.                                 curPage = NULL; done=1; break;  // quit
  470.                                 
  471.                             case SDLK_LEFT: 
  472.                                 curPage = curPage->prev; done=1; break;
  473.                                 
  474.                             case SDLK_RIGHT:
  475.                             case SDLK_SPACE:
  476.                             case SDLK_RETURN:
  477.                                 curPage = curPage->next; done=1; break;
  478.                 default: break;
  479.                         };
  480.                         break;
  481.                 }
  482.             }
  483.         };
  484.         }
  485.     /* --- cleanup memory --- changing pages --- */
  486.     { 
  487.         int i;
  488.         if (sys_sound){
  489.         for (i=0; i<numWavs; i++) {
  490.             Mix_HaltChannel( i );
  491.             Mix_FreeChunk( sounds[i] );
  492.         }
  493.         for (i=0; i<numClicks; i++) {
  494.             Mix_HaltChannel( i + numWavs );
  495.             Mix_FreeChunk( clickWavs[i] );
  496.         }
  497.         }
  498.     }
  499.     }
  500. }
  501.  
  502. void InstructCascade(void) {
  503.     char fn[FNLEN];
  504.     sprintf( fn, "%s/scripts/cascade.xml", realPath[useEnglish] );
  505.     if (loadScript( fn ) != 0) return; // bail if any errors occur
  506.     runScript();
  507. }
  508.  
  509. void InstructLaser(void) {
  510.     char fn[FNLEN];
  511.     sprintf( fn, "%s/scripts/laser.xml", realPath[useEnglish] );
  512.     if (loadScript( fn ) != 0) return; // bail if any errors occur
  513.     { int i; for (i=0; i<20; i++) {
  514.     runScript(); SDL_Delay(500); }}
  515. }
  516.  
  517. void clearItems( itemType *i ) {
  518.     itemType *n;
  519.     while (i) {
  520.         n = i->next;  // remember the next guy
  521.  
  522.         /* -- remove any data we are pointing to -- */
  523.         free(i->data);
  524.         free(i->onclick);
  525.         free(i->color);
  526.  
  527.         /* -- remove ourselves --*/
  528.         free(i);
  529.  
  530.         /* -- on to the next guy! -- */
  531.         i = n;
  532.     }
  533. }
  534.  
  535. void clearPages( pageType *p ) {
  536.     pageType *n;
  537.     while (p) {
  538.         n = p->next;  // remember the next guy
  539.  
  540.         /* -- remove all of our sub elements -- */
  541.         clearItems(p->items);
  542.  
  543.         /* -- free anything we are pointing to --- */
  544.         free(p->background);
  545.         free(p->title);
  546.         free(p->bgcolor);
  547.         free(p->fgcolor);
  548.  
  549.         /* -- free ourselves -- */
  550.         free(p);
  551.  
  552.         /* -- on to the next --*/
  553.         p = n;
  554.     }
  555. }
  556.  
  557. void closeScript( void ) {
  558.     if (curScript) {
  559.  
  560.         /* -- remove all the pages we have --*/
  561.         clearPages(curScript->pages);
  562.  
  563.         /* -- remove attributes we are pointing to -- */
  564.         free(curScript->title);
  565.         free(curScript->bgcolor);
  566.         free(curScript->fgcolor);
  567.         free(curScript->background);
  568.  
  569.         /* -- free yourself -- */
  570.         free(curScript); 
  571.  
  572.         /* -- and remember you did -- */
  573.         curScript = NULL;
  574.     }
  575. }
  576.  
  577. void testLesson( void ) {
  578.     char fn[FNLEN]; 
  579.     sprintf( fn, "%s/scripts/test.xml", realPath[1]);
  580.     if (loadScript( fn ) != 0) return; // bail if any errors occur
  581.     runScript();
  582. }
  583.  
  584. void projectInfo( void ) {
  585.     char fn[FNLEN]; 
  586.     sprintf( fn, "%s/scripts/projectInfo.xml", realPath[1]);
  587.     if (loadScript( fn ) != 0) return; // bail if any errors occur
  588.     runScript();
  589. }
  590.  
  591.