home *** CD-ROM | disk | FTP | other *** search
/ hobbes.nmsu.edu 2008 / 2008-06-02_hobbes.nmsu.edu.zip / new / scummc-0.2.0-os2.zip / ScummC / src / scc_roobj.c < prev    next >
Encoding:
C/C++ Source or Header  |  2007-11-27  |  35.8 KB  |  1,584 lines

  1. /* ScummC
  2.  * Copyright (C) 2004-2006  Alban Bedel
  3.  *
  4.  * This program is free software; you can redistribute it and/or
  5.  * modify it under the terms of the GNU General Public License
  6.  * as published by the Free Software Foundation; either version 2
  7.  * of the License, or (at your option) any later version.
  8.  
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  17.  *
  18.  */
  19.  
  20. /**
  21.  * @file scc_roobj.c
  22.  * @ingroup scc
  23.  * @brief ScummC object files
  24.  */
  25.  
  26. #include "config.h"
  27.  
  28. #include <stdlib.h>
  29. #include <stdio.h>
  30. #include <string.h>
  31. #include <inttypes.h>
  32. #include <errno.h>
  33.  
  34. #include "scc_util.h"
  35. #include "scc_parse.h"
  36. #include "scc_ns.h"
  37.  
  38. #include <sys/types.h>
  39. #include <sys/stat.h>
  40. #include <fcntl.h>
  41. #include "scc_fd.h"
  42.  
  43. #include "scc_img.h"
  44.  
  45. #include "scc_cost.h"
  46. #include "scc_codec.h"
  47. #include "scc.h"
  48. #include "scc_roobj.h"
  49. #include "scc_code.h"
  50.  
  51.  
  52. static int scc_roobj_set_image(scc_roobj_t* ro,scc_ns_t* ns,char* val);
  53. static int scc_roobj_set_boxd(scc_roobj_t* ro,scc_ns_t* ns,char* val);
  54. static int scc_roobj_set_boxm(scc_roobj_t* ro,scc_ns_t* ns,char* val);
  55. static int scc_roobj_set_scal(scc_roobj_t* ro,scc_ns_t* ns,char* val);
  56.  
  57. struct {
  58.   char* name;
  59.   int (*set)(scc_roobj_t* ro,scc_ns_t* ns,char* val);
  60. } roobj_params[] = {
  61.   { "image", scc_roobj_set_image },
  62.   { "boxd", scc_roobj_set_boxd },
  63.   { "boxm", scc_roobj_set_boxm },
  64.   { "scal", scc_roobj_set_scal },
  65.   { NULL, NULL }
  66. };
  67.  
  68. static struct scc_res_types {
  69.   int type;
  70.   uint32_t id;
  71.   uint32_t fixid;
  72. } scc_res_types[] = {
  73.   { SCC_RES_SOUND, MKID('S','O','U','N'), MKID('s','o','u','n') },
  74.   { SCC_RES_COST, MKID('C','O','S','T'), MKID('c','o','s','t') },
  75.   { SCC_RES_COST, MKID('A','K','O','S'), MKID('a','k','o','s') },
  76.   { SCC_RES_CHSET, MKID('C','H','A','R'), MKID('c','h','a','r') },
  77.   { SCC_RES_VOICE, MKID('v','o','i','c'), MKID('v','o','i','c') },
  78.   { -1, 0, 0 }
  79. };
  80.  
  81. scc_roobj_t* scc_roobj_new(scc_target_t* target, scc_symbol_t* sym) {
  82.   scc_roobj_t* ro = calloc(1,sizeof(scc_roobj_t));
  83.  
  84.   ro->target = target;
  85.   ro->sym = sym;
  86.  
  87.   return ro;
  88. }
  89.  
  90. static void scc_roobj_res_free(scc_roobj_res_t* r) {
  91.   if(r->data) free(r->data);
  92.   free(r);
  93. }
  94.  
  95. void scc_roobj_free(scc_roobj_t* ro) {
  96.   scc_roobj_cycl_t* cycl;
  97.   scc_script_t* scr;
  98.   scc_roobj_obj_t* obj;
  99.   scc_roobj_res_t* res;
  100.   scc_boxd_t* box;
  101.   int i;
  102.  
  103.   SCC_LIST_FREE_CB(ro->scr,scr,scc_script_free);
  104.   SCC_LIST_FREE_CB(ro->lscr,scr,scc_script_free);
  105.  
  106.   SCC_LIST_FREE(ro->cycl,cycl);
  107.   SCC_LIST_FREE_CB(ro->obj,obj,scc_roobj_obj_free);
  108.   SCC_LIST_FREE_CB(ro->res,res,scc_roobj_res_free);
  109.  
  110.   if(ro->image) scc_img_free(ro->image);
  111.   for(i = 0 ; i < SCC_MAX_IM_PLANES ; i++)
  112.     if(ro->zplane[i]) scc_img_free(ro->zplane[i]);
  113.   SCC_LIST_FREE(ro->boxd,box);
  114.   if(ro->boxm) free(ro->boxm);
  115.   if(ro->scal) free(ro->scal);
  116.   free(ro);
  117. }
  118.  
  119. scc_script_t* scc_roobj_get_scr(scc_roobj_t* ro, scc_symbol_t* sym) {
  120.   scc_script_t* s;
  121.  
  122.   for(s = (sym->type == SCC_RES_SCR ? ro->scr : ro->lscr) ; s ; s = s->next) {
  123.     if(!strcmp(sym->sym,s->sym->sym)) return s;
  124.   }
  125.  
  126.   return NULL;
  127. }
  128.  
  129. int scc_roobj_add_scr(scc_roobj_t* ro,scc_script_t* scr) {
  130.  
  131.   if(scc_roobj_get_scr(ro,scr->sym)) {
  132.     scc_log(LOG_ERR,"Why are we trying to add a script we already have????\n");
  133.     return 0;
  134.   }
  135.   
  136.   if(scr->sym->type == SCC_RES_SCR) {
  137.     scr->next = ro->scr;
  138.     ro->scr = scr;
  139.   } else {
  140.     scr->next = ro->lscr;
  141.     ro->lscr = scr;
  142.   }
  143.   return 1;
  144. }
  145.  
  146. scc_roobj_res_t* scc_roobj_get_res(scc_roobj_t* ro,scc_symbol_t* sym) {
  147.   scc_roobj_res_t* r;
  148.  
  149.   for(r = ro->res ; r ; r = r->next) {
  150.     if(sym == r->sym) return r;
  151.   }
  152.  
  153.   return NULL;
  154. }
  155.  
  156. scc_roobj_obj_t* scc_roobj_get_obj(scc_roobj_t* ro,scc_symbol_t* sym) {
  157.   scc_roobj_obj_t* obj;
  158.  
  159.   for(obj = ro->obj ; obj ; obj = obj->next) {
  160.     if(obj->sym == sym) return obj;
  161.   }
  162.  
  163.   return NULL;
  164. }
  165.  
  166. scc_roobj_cycl_t* scc_roobj_get_cycl(scc_roobj_t* ro,scc_symbol_t* sym) {
  167.   scc_roobj_cycl_t* c;
  168.  
  169.   for(c = ro->cycl ; c ; c = c->next)
  170.     if(c->sym == sym) return c;
  171.   return NULL;
  172. }
  173.  
  174. int scc_roobj_add_obj(scc_roobj_t* ro,scc_roobj_obj_t* obj) {
  175.   scc_roobj_obj_t* o = scc_roobj_get_obj(ro,obj->sym);
  176.  
  177.   if(o) {
  178.     scc_log(LOG_ERR,"%s is already defined.\n",obj->sym->sym);
  179.     return 0;
  180.   }
  181.  
  182.   if(obj->trans >= 0) {
  183.     int x,y;
  184.     scc_roobj_state_t* state;
  185.     for(state = obj->states ; state ; state = state->next) {
  186.       uint8_t *optr = state->img->data;
  187.       uint8_t *rptr = ro->image->data+obj->y*ro->image->w+obj->x;
  188.       for(y = 0 ; y < state->img->h ; y++) {
  189.         for(x = 0 ; x < state->img->w ; x++)
  190.           if(optr[x] == obj->trans)
  191.             optr[x] = rptr[x];
  192.         optr += state->img->w;
  193.         rptr += ro->image->w;
  194.       }
  195.     }
  196.   }
  197.  
  198.   SCC_LIST_ADD(ro->obj,ro->last_obj,obj);
  199.  
  200.   return 1;
  201. }
  202.  
  203. // add costume, sound, etc
  204. scc_roobj_res_t* scc_roobj_add_res(scc_roobj_t* ro,scc_symbol_t* sym, 
  205.                    char* val) {
  206.   scc_roobj_res_t* r = scc_roobj_get_res(ro,sym);
  207.   scc_fd_t* fd;
  208.   int len,flen,rt;
  209.   uint32_t ft;
  210.   
  211.   for(rt = 0 ; scc_res_types[rt].type >= 0 ; rt++) {
  212.     if(scc_res_types[rt].type == sym->type) break;
  213.   }
  214.  
  215.   if(scc_res_types[rt].type < 0) {
  216.     scc_log(LOG_ERR,"Unknown resource type!!!!\n");
  217.     return NULL;
  218.   }    
  219.  
  220.   if(r) {
  221.     scc_log(LOG_ERR,"Room symbol %s is already defined.\n",sym->sym);
  222.     return NULL;
  223.   }
  224.  
  225.   fd = new_scc_fd(val,O_RDONLY,0);
  226.   if(!fd) {
  227.     scc_log(LOG_ERR,"Failed to open %s.\n",val);
  228.     return NULL;
  229.   }
  230.   // get file size
  231.   scc_fd_seek(fd,0,SEEK_END);
  232.   flen = scc_fd_pos(fd);
  233.   scc_fd_seek(fd,0,SEEK_SET);
  234.  
  235.   // get the header
  236.   ft = scc_fd_r32(fd);
  237.   while(ft != scc_res_types[rt].id) {
  238.     if(scc_res_types[rt+1].type == sym->type) {
  239.       rt++;
  240.       continue;
  241.     }
  242.     scc_log(LOG_ERR,"The file %s doesn't seem to contain what we want.\n",val);
  243.     scc_fd_close(fd);
  244.     return NULL;
  245.   }
  246.   len = scc_fd_r32be(fd);
  247.   if(len <= 8 || len < flen) {
  248.     scc_log(LOG_ERR,"The file %s seems to be invalid.\n",val);
  249.     scc_fd_close(fd);
  250.     return NULL;
  251.   }
  252.  
  253.   r = calloc(1,sizeof(scc_roobj_res_t));
  254.   r->type = ft;
  255.   r->sym = sym;
  256.   r->data = scc_fd_load(fd,len-8);
  257.   r->data_len = len-8;
  258.  
  259.   r->next = ro->res;
  260.   ro->res = r;
  261.  
  262.   scc_fd_close(fd);
  263.   
  264.   return r;
  265. }
  266.  
  267. static int scc_check_voc(char* file,unsigned char* data,unsigned size) {
  268.   int hsize,ver,magic,pos,type,len,pack;
  269.  
  270.   if(strncmp(data,"Creative Voice File",19)) {
  271.     scc_log(LOG_ERR,"%s is not a creative voice file.\n",file);
  272.     return 0;
  273.   }
  274.  
  275.   hsize = SCC_GET_16LE(data,20);
  276.   ver = SCC_GET_16LE(data,22);
  277.   magic = SCC_GET_16LE(data,24);
  278.   if(hsize < 0x1A) {
  279.     scc_log(LOG_ERR,"%s: voc header is too small.\n",file);
  280.     return 0;
  281.   }
  282.  
  283.   if(~ver + 0x1234 != magic) {
  284.     scc_log(LOG_ERR,"%s: Invalid voc header.\n",file);
  285.     return 0;
  286.   }
  287.  
  288.   pos = hsize;
  289.   while(pos < size) {
  290.     type = data[pos]; pos++;
  291.  
  292.     // terminator
  293.     if(type == 0) {
  294.       if(pos != size)
  295.         scc_log(LOG_WARN,"%s: Warning, garbage after terminator???\n",file);
  296.       return 1;
  297.     }
  298.  
  299.     len = data[pos]; pos++;
  300.     len |= data[pos] << 8; pos++;
  301.     len |= data[pos] << 16; pos++;
  302.  
  303.     switch(type) {
  304.     case 1:
  305.       pos++; // srate
  306.       pack = data[pos]; pos++;
  307.       len -= 2;
  308.  
  309.       if(pack != 0) {
  310.         scc_log(LOG_ERR,"%s: Unsupported packing format: %x\n",file,pack);
  311.         return 0;
  312.       }
  313.     case 6:
  314.     case 7:
  315.       break;
  316.     default:
  317.       scc_log(LOG_ERR,"%s: Unsupported block type: %x\n",file,type);
  318.       return 0;
  319.     }
  320.  
  321.     pos += len;
  322.   }
  323.  
  324.   scc_log(LOG_ERR,"%s: Truncated file, or the terminator is missing.\n",file);
  325.   return 0;
  326. }
  327.  
  328. int scc_roobj_add_voice(scc_roobj_t* ro, scc_symbol_t* sym, char* file,
  329.                         int nsync, int* sync) {
  330.   scc_fd_t* fd = new_scc_fd(file,O_RDONLY,0);
  331.   off_t vsize;
  332.   scc_roobj_res_t* r;
  333.   int i;
  334.   
  335.   if(!fd) {
  336.     scc_log(LOG_ERR,"Failed to open %s.\n",file);
  337.     return 0;
  338.   }
  339.   // get the voc file size
  340.   vsize = scc_fd_seek(fd,0,SEEK_END);
  341.   if(vsize < 0x1A) {
  342.     scc_log(LOG_ERR,"%s is too small to be voc file.\n",file);
  343.     scc_fd_close(fd);
  344.     return 0;
  345.   }
  346.   scc_fd_seek(fd,0,SEEK_SET);
  347.  
  348.   // alloc the res
  349.   r = malloc(sizeof(scc_roobj_res_t));
  350.   r->type = MKID('v','o','i','c');
  351.   r->sym = sym;
  352.   r->data_len = 8 + 2*nsync + vsize;
  353.   r->data = malloc(r->data_len);
  354.  
  355.   // write the sync point table
  356.   SCC_SET_32(r->data,0,MKID('V','C','T','L'));
  357.   SCC_SET_32BE(r->data,4,8 + 2*nsync);
  358.   for(i = 0 ; i < nsync ; i++) {
  359.     SCC_SET_16BE(r->data,8+2*i,sync[i]);
  360.   }
  361.   // load the voc data
  362.   if(scc_fd_read(fd,r->data+8+2*nsync,vsize) != vsize) {
  363.     scc_log(LOG_ERR,"Error while reading voc file.\n");
  364.     free(r->data);
  365.     free(r);
  366.     scc_fd_close(fd);
  367.     return 0;
  368.   }
  369.  
  370.   scc_fd_close(fd);
  371.  
  372.   if(!scc_check_voc(file,r->data+8+2*nsync,vsize)) {
  373.     free(r->data);
  374.     free(r);
  375.     return 0;
  376.   }
  377.  
  378.   // add the res to the list
  379.   r->next = ro->res;
  380.   ro->res = r;
  381.  
  382.   return 1;
  383. }
  384.  
  385. int scc_roobj_add_cycl(scc_roobj_t* ro, scc_symbol_t* sym,
  386.                        int delay, int flags, int start, int end) {
  387.   scc_roobj_cycl_t* c = scc_roobj_get_cycl(ro,sym);
  388.   int freq;
  389.  
  390.   if(c) {
  391.     scc_log(LOG_ERR,"Cycle %s is already defined.\n",sym->sym);
  392.     return 0;
  393.   }
  394.  
  395.   if(delay < 0) {
  396.     scc_log(LOG_ERR,"Cycl delay must be >= 0.\n");
  397.     return 0;
  398.   }
  399.  
  400.   freq = 16384/delay;
  401.  
  402.   if(freq < 1 || freq > 0xffff) {
  403.     scc_log(LOG_ERR,"Error invalid cycle frequency.\n");
  404.     return 0;
  405.   }
  406.   if(start < 0 || start > 0xFF) {
  407.     scc_log(LOG_ERR,"Error invalid cycle start point.\n");
  408.     return 0;
  409.   }
  410.   if(end < 0 || end > 0xFF) {
  411.     scc_log(LOG_ERR,"Error invalid cycle end point.\n");
  412.     return 0;
  413.   }
  414.   if(start > end) {
  415.     scc_log(LOG_ERR,"Error: cycle start point is after the end point.\n");
  416.     return 0;
  417.   }
  418.  
  419.   c = calloc(1,sizeof(scc_roobj_cycl_t));
  420.   c->sym = sym;
  421.   c->freq = freq;
  422.   c->flags = flags;
  423.   c->start = start;
  424.   c->end = end;
  425.  
  426.   c->next = ro->cycl;
  427.   ro->cycl = c;
  428.  
  429.   return 1;
  430. }
  431.  
  432. int scc_roobj_set_param(scc_roobj_t* ro,scc_ns_t* ns,
  433.             char* p,char* val) {
  434.   int i;
  435.   
  436.   for(i = 0 ; roobj_params[i].name ; i++) {
  437.     if(strcmp(roobj_params[i].name,p)) continue;
  438.  
  439.     return roobj_params[i].set(ro,ns,val);
  440.   }
  441.  
  442.   scc_log(LOG_ERR,"Rooms have no parameter named %s.\n",p);
  443.   return 0;
  444. }
  445.  
  446.  
  447. static int scc_roobj_set_image(scc_roobj_t* ro,scc_ns_t* ns,char* val) {
  448.  
  449.   if(ro->image) {
  450.     scc_log(LOG_ERR,"Room image has already been set.\n");
  451.     return 0;
  452.   }
  453.  
  454.   ro->image = scc_img_open(val);
  455.   if(!ro->image) {
  456.     scc_log(LOG_ERR,"Failed to parse image %s.\n",val);
  457.     return 0;
  458.   }
  459.  
  460.   if(ro->image->w%8 != 0) {
  461.     scc_log(LOG_ERR,"Images must have w%%8==0 !!!\n");
  462.     scc_img_free(ro->image);
  463.     ro->image = NULL;
  464.     return 0;
  465.   }
  466.   
  467.   return 1;
  468. }
  469.  
  470. int scc_roobj_set_zplane(scc_roobj_t* ro, int idx,char* val) {
  471.  
  472.   if(idx < 0) {
  473.     scc_log(LOG_ERR,"Z-planes need a subscript.\n");
  474.     return 0;
  475.   }
  476.   if(idx < 1 || idx >= SCC_MAX_IM_PLANES) {
  477.     scc_log(LOG_ERR,"Z-plane index is out of range.\n");
  478.     return 0;
  479.   }
  480.  
  481.   if(ro->zplane[idx]) {
  482.     scc_log(LOG_ERR,"Z-plane %d has already been set.\n",idx);
  483.     return 0;
  484.   }
  485.  
  486.   ro->zplane[idx] = scc_img_open(val);
  487.   if(!ro->zplane[idx]) {
  488.     scc_log(LOG_ERR,"Failed to open zplane image %s.\n",val);
  489.     return 0;
  490.   }
  491.  
  492.   if(ro->zplane[idx]->w%8 != 0) {
  493.     scc_log(LOG_ERR,"Images must have w%%8==0 !!!\n");
  494.     scc_img_free(ro->zplane[idx]);
  495.     ro->zplane[idx] = NULL;
  496.     return 0;
  497.   }
  498.  
  499.   if(ro->zplane[idx]->ncol != 2)
  500.     scc_log(LOG_WARN,"Warning: zplanes should have only 2 colors.\n");
  501.   
  502.   return 1;
  503. }
  504.  
  505.  
  506. static int scc_roobj_set_data_param(scc_data_t** ptr,char* name,char* val) {
  507.   
  508.   if(ptr[0]) {
  509.     scc_log(LOG_ERR,"Room %s has already been set.\n",name);
  510.     return 0;
  511.   }
  512.  
  513.   ptr[0] = scc_data_load(val);
  514.  
  515.   return (ptr[0] ? 1 : 0);
  516. }
  517.  
  518. static int scc_roobj_set_boxd(scc_roobj_t* ro,scc_ns_t* ns,char* path) {
  519.   scc_fd_t* fd;
  520.   uint32_t type,len,named=1;
  521.   int pos = 8, boxn = 0,nlen = 0;
  522.   scc_boxd_t* boxes=NULL,*last=NULL,*b;
  523.  
  524.   fd = new_scc_fd(path,O_RDONLY,0);
  525.   if(!fd) {
  526.     scc_log(LOG_ERR,"Failed to open %s.\n",path);
  527.     return 0;
  528.   }
  529.  
  530.   type = scc_fd_r32(fd);
  531.   len = scc_fd_r32be(fd);
  532.  
  533.   if(type == MKID('B','O','X','D')) {
  534.     named = 0;
  535.     scc_fd_r16(fd); pos += 2; // skip num box
  536.   } else if(type != MKID('b','o','x','d')) {
  537.     scc_log(LOG_ERR,"%s is not a boxd file.\n",path);
  538.     scc_fd_close(fd);
  539.     return 0;
  540.   }
  541.  
  542.   while(pos < len) {
  543.     if(named) nlen = scc_fd_r8(fd), pos++;
  544.     if(pos + nlen + 20 > len) {
  545.       scc_log(LOG_ERR,"Invalid box entry.\n");
  546.       break;
  547.     }
  548.     boxn++;
  549.     if(nlen > 0) {
  550.       char name[nlen+1];
  551.       scc_fd_read(fd,name,nlen); pos += nlen;
  552.       name[nlen] = '\0';
  553.       if(!scc_ns_decl(ns,NULL,name,SCC_RES_BOX,0,boxn)) {
  554.     scc_log(LOG_ERR,"Failed to declare room box %s.\n",name);
  555.     break;
  556.       }
  557.     }
  558.     b = malloc(sizeof(scc_boxd_t));
  559.     b->next = NULL;
  560.     b->ulx = (int16_t)scc_fd_r16le(fd); pos += 2;
  561.     b->uly = (int16_t)scc_fd_r16le(fd); pos += 2;
  562.     b->urx = (int16_t)scc_fd_r16le(fd); pos += 2;
  563.     b->ury = (int16_t)scc_fd_r16le(fd); pos += 2;
  564.     b->lrx = (int16_t)scc_fd_r16le(fd); pos += 2;
  565.     b->lry = (int16_t)scc_fd_r16le(fd); pos += 2;
  566.     b->llx = (int16_t)scc_fd_r16le(fd); pos += 2;
  567.     b->lly = (int16_t)scc_fd_r16le(fd); pos += 2;
  568.     b->mask = scc_fd_r8(fd); pos++;
  569.     b->flags = scc_fd_r8(fd); pos++;
  570.     b->scale = scc_fd_r16le(fd); pos += 2;
  571.  
  572.     SCC_LIST_ADD(boxes,last,b);
  573.  
  574.     // we are done
  575.     if(pos == len) {
  576.       // prepend the strange box 0
  577.       if(named) {
  578.     b = malloc(sizeof(scc_boxd_t));
  579.     b->next = boxes;
  580.     b->ulx = -32000;
  581.     b->uly = -32000;
  582.     b->urx = -32000;
  583.     b->ury = -32000;
  584.     b->lrx = -32000;
  585.     b->lry = -32000;
  586.     b->llx = -32000;
  587.     b->lly = -32000;
  588.     b->mask = 0;
  589.     b->flags = 0;
  590.     b->scale = 255;
  591.     ro->boxd = b;
  592.       
  593.     // now the matrix should follow with the scal
  594.  
  595.     type = scc_fd_r32(fd);
  596.     len = scc_fd_r32be(fd);
  597.     if(type != MKID('B','O','X','M') || len <= 8) {
  598.       scc_log(LOG_ERR,"The box file is missing the matrix????\n");
  599.       break;
  600.     }
  601.     ro->boxm = malloc(sizeof(scc_data_t)+len);
  602.     ro->boxm->size = len;
  603.     SCC_SET_32(ro->boxm->data,0,MKID('B','O','X','M'));
  604.     SCC_SET_32BE(ro->boxm->data,4,len);
  605.     if(scc_fd_read(fd,&ro->boxm->data[8],len - 8) != len - 8) {
  606.       scc_log(LOG_ERR,"Error while reading the box matrix.\n");
  607.       break;
  608.     }
  609.         
  610.     type = scc_fd_r32(fd);
  611.     len = scc_fd_r32be(fd);
  612.     if(type != MKID('S','C','A','L') || len != 40) {
  613.       scc_log(LOG_ERR,"The box file is missing the scal block????\n");
  614.       break;
  615.     }
  616.     ro->scal = malloc(sizeof(scc_data_t)+len);
  617.     ro->scal->size = len;
  618.     SCC_SET_32(ro->scal->data,0,MKID('S','C','A','L'));
  619.     SCC_SET_32BE(ro->scal->data,4,len);
  620.     if(scc_fd_read(fd,&ro->scal->data[8],len - 8) != len - 8) {
  621.       scc_log(LOG_ERR,"Error while reading the scal block.\n");
  622.       break;
  623.     }
  624.       } else
  625.     ro->boxd = boxes;
  626.       return 1;
  627.     }
  628.   }
  629.   
  630.   SCC_LIST_FREE(boxes,last);
  631.   scc_fd_close(fd);
  632.   return 0;
  633. }
  634.  
  635. static int scc_roobj_set_boxm(scc_roobj_t* ro,scc_ns_t* ns,char* val) {
  636.   return scc_roobj_set_data_param(&ro->boxm,"boxm",val);
  637. }
  638.  
  639. static int scc_roobj_set_scal(scc_roobj_t* ro,scc_ns_t* ns,char* val) {
  640.   return scc_roobj_set_data_param(&ro->scal,"scal",val);
  641. }
  642.  
  643. ////////////////////////// objects ////////////////////////////
  644.  
  645.  
  646. scc_roobj_obj_t* scc_roobj_obj_new(scc_symbol_t* sym) {
  647.   scc_roobj_obj_t* obj = calloc(1,sizeof(scc_roobj_obj_t));
  648.   obj->sym = sym;
  649.   obj->trans = -1;
  650.   return obj;
  651. }
  652.  
  653. static void scc_roobj_obj_state_free(scc_roobj_state_t* st) {
  654.   int l;
  655.  
  656.   if(st->img) scc_img_free(st->img);
  657.   for(l = 0 ; l < SCC_MAX_IM_PLANES ; l++)
  658.     if(st->zp[l]) scc_img_free(st->zp[l]);
  659.  
  660.   free(st);
  661. }
  662.  
  663. void scc_roobj_obj_free(scc_roobj_obj_t* obj) {
  664.   scc_roobj_state_t *st;
  665.   scc_script_t *scr;
  666.  
  667.   if(obj->name) free(obj->name);
  668.   SCC_LIST_FREE_CB(obj->states,st,scc_roobj_obj_state_free);
  669.   SCC_LIST_FREE_CB(obj->verb,scr,scc_script_free);
  670.   //if(obj->im) TODO
  671.   free(obj);
  672. }
  673.  
  674. int scc_roobj_obj_add_state(scc_roobj_obj_t* obj,int x, int y,
  675.                 char *img_path,char** zp_paths) {
  676.   scc_img_t* img = NULL;
  677.   scc_roobj_state_t* st,*s;
  678.   int i;
  679.  
  680.   if(img_path) {
  681.     img = scc_img_open(img_path);
  682.     if(!img) return 0;
  683.  
  684.     if(img->w%8 || img->h%8) {
  685.       scc_log(LOG_ERR,"Image width and height must be multiples of 8.\n");
  686.       scc_img_free(img);
  687.       return 0;
  688.     }
  689.  
  690.     if(!obj->w) obj->w = img->w;
  691.     if(!obj->h) obj->h = img->h;
  692.     if(obj->w != img->w || obj->h != img->h) {
  693.       scc_log(LOG_ERR,"Image size doesn't match the previously defined size.\n");
  694.       scc_img_free(img);
  695.       return 0;
  696.     }
  697.   }
  698.  
  699.   st = calloc(1,sizeof(scc_roobj_state_t));
  700.   st->hs_x = x;
  701.   st->hs_y = y;
  702.   st->img = img;
  703.  
  704.   if(zp_paths) {
  705.     for(i = 0 ; zp_paths[i] ; i++) {
  706.       if(zp_paths[i][0] == '\0')
  707.         st->zp[i] = scc_img_new(img->w,img->h,2);
  708.       else {
  709.         st->zp[i] = scc_img_open(zp_paths[i]);
  710.         if(!st->zp[i]) {
  711.           scc_roobj_obj_state_free(st);
  712.           return 0;
  713.         }
  714.         if(st->zp[i]->w != img->w ||
  715.            st->zp[i]->h != img->h) {
  716.           scc_log(LOG_ERR,"ZPlane %d has the wrong size.\n",i+1);
  717.           scc_roobj_obj_state_free(st);
  718.           return 0;
  719.         }
  720.       }
  721.     }
  722.   }
  723.    
  724.   if(obj->states) {
  725.     for(s = obj->states ; s->next ; s = s->next);
  726.     s->next = st;
  727.   } else
  728.     obj->states = st;    
  729.   
  730.   return 1;
  731. }
  732.  
  733.  
  734. int scc_roobj_obj_add_verb(scc_roobj_obj_t* obj,scc_script_t* scr) {
  735.   scc_script_t* s;
  736.  
  737.   for(s = obj->verb ; s ; s = s->next) {
  738.     if(scr->sym == s->sym) {
  739.       scc_log(LOG_ERR,"Why are we trying to add a verb we already have????\n");
  740.       return 0;
  741.     }
  742.     if(!s->next) break;
  743.   }
  744.  
  745.   if(s) s->next = scr;
  746.   else obj->verb = scr;
  747.  
  748.   return 1;
  749. }
  750.  
  751. int scc_roobj_obj_set_param(scc_roobj_obj_t* obj,char* sym, char* val) {
  752.   if(!strcmp(sym,"name")) {
  753.     if(obj->name) {
  754.       scc_log(LOG_ERR,"Object name is already defined.\n");
  755.       return 0;
  756.     }
  757.     obj->name = strdup(val);
  758.     return 1;
  759.   } 
  760.   
  761.   scc_log(LOG_ERR,"Unknown object parameter: %s\n",sym);
  762.   return 0;
  763. }
  764.  
  765. int scc_roobj_obj_set_int_param(scc_roobj_obj_t* obj,char* sym,int val) {
  766.  
  767.   if(!strcmp(sym,"x"))
  768.     obj->x = val;
  769.   else if(!strcmp(sym,"y"))
  770.     obj->y = val;
  771.   else if(!strcmp(sym,"w"))
  772.     obj->w = val;
  773.   else if(!strcmp(sym,"h"))
  774.     obj->h = val;
  775.   else if(!strcmp(sym,"hs_x"))
  776.     obj->hs_x = val;
  777.   else if(!strcmp(sym,"hs_y"))
  778.     obj->hs_y = val;
  779.   else if(!strcmp(sym,"dir"))
  780.     obj->dir = val;
  781.   else if(!strcmp(sym,"trans"))
  782.     obj->trans = val;
  783.   else if(!strcmp(sym,"state")) {
  784.     scc_roobj_state_t* s;
  785.     int i;
  786.     if(val < 0) {
  787.       scc_log(LOG_ERR,"Invalid object state: %d\n",val);
  788.       return 0;
  789.     }
  790.     if(!val) {
  791.       obj->state = 0;
  792.       return 1;
  793.     }
  794.     for(i = 1, s = obj->states ; s && i != val ; i++, s = s->next);
  795.     if(!s) {
  796.       scc_log(LOG_ERR,"Invalid object state: %d\n",val);
  797.       return 0;
  798.     }
  799.     obj->state = val;
  800.   } else if(!strcmp(sym,"parent_state")) {
  801.     if(val < 0) {
  802.       scc_log(LOG_ERR,"Invalid parent state: %d.\n",val);
  803.       return 0;
  804.     }
  805.     obj->parent_state = val;
  806.   } else {
  807.     scc_log(LOG_ERR,"Unknown integer object parameter: %s\n",sym);
  808.     return 0;
  809.   }
  810.   
  811.   return 1;
  812. }
  813.  
  814. int scc_roobj_obj_set_class(scc_roobj_obj_t* obj, scc_symbol_t* sym) {
  815.   int i;
  816.  
  817.   // look if that class is alredy set
  818.   for(i = 0 ; i < SCC_MAX_CLASS ; i++) {
  819.     if(!obj->class[i]) continue;
  820.     if(obj->class[i] == sym) return 1;
  821.   }
  822.   // add it
  823.   for(i = 0 ; i < SCC_MAX_CLASS ; i++) {
  824.     if(obj->class[i]) continue;
  825.     obj->class[i] = sym;
  826.     return 1;
  827.   }
  828.   // no space left ???
  829.   return 0;
  830. }
  831.  
  832. //////////////////////////// Writing ///////////////////////////////
  833.  
  834. scc_pal_t* scc_roobj_gen_pals(scc_roobj_t* ro) {
  835.   scc_pal_t* pal;
  836.   int i;
  837.  
  838.   if(!ro->image) {
  839.     scc_log(LOG_V,"Room has no image, using dummy one!!!!\n");
  840.     ro->image = scc_img_new(8,8,256);
  841.   }
  842.  
  843.   pal = calloc(1,sizeof(scc_pal_t));
  844.  
  845.   for(i = 0 ; i < ro->image->ncol ; i++) {
  846.     pal->r[i] = ro->image->pal[3*i];
  847.     pal->g[i] = ro->image->pal[3*i+1];
  848.     pal->b[i] = ro->image->pal[3*i+2];
  849.   }
  850.  
  851.   return pal;
  852. }
  853.  
  854. scc_rmim_t* scc_roobj_gen_rmim(scc_roobj_t* ro) {
  855.   scc_rmim_t* rmim;
  856.   int i,j,d,nz = 0;
  857.   uint8_t* zd;
  858.  
  859.   if(!ro->image) {
  860.     scc_log(LOG_V,"Room has no image, using dummy one!!!!\n");
  861.     ro->image = scc_img_new(8,8,256);
  862.   }
  863.  
  864.   for(i = 1 ; i < SCC_MAX_IM_PLANES ; i++) {
  865.     if(ro->zplane[i]) nz++;
  866.     else break;
  867.   }
  868.  
  869.   rmim = calloc(1,sizeof(scc_rmim_t));
  870.   rmim->num_z_buf = nz;
  871.  
  872.   rmim->smap_size = scc_code_image(ro->image->data,ro->image->w,
  873.                    ro->image->w,ro->image->h,
  874.                    -1,&rmim->smap);
  875.  
  876.   for(i = 1 ; i < nz+1 ; i++) {
  877.     // pack the zplane data
  878.     zd = malloc(ro->zplane[i]->w/8*ro->zplane[i]->h);
  879.     d = 0;
  880.     for(j = 0 ; j < ro->zplane[i]->w*ro->zplane[i]->h ; j++) {
  881.       if(ro->zplane[i]->data[j])
  882.     d |= (1<<(7-(j%8)));
  883.  
  884.       if(j % 8 == 7) {
  885.     zd[j/8] = d;
  886.     d = 0;
  887.       }
  888.     }
  889.     // code it
  890.     rmim->z_buf_size[i] = scc_code_zbuf(zd,ro->zplane[i]->w/8,
  891.                     ro->zplane[i]->w,ro->zplane[i]->h,
  892.                     &rmim->z_buf[i]);
  893.     free(zd);
  894.   }
  895.  
  896.   return rmim;
  897.  
  898. }
  899.  
  900. static scc_imnn_t* scc_roobj_state_gen_imnn(scc_roobj_state_t* st,int idx) {
  901.   scc_imnn_t* imnn;
  902.   scc_img_t* i = st->img;
  903.   scc_img_t** z = st->zp;
  904.   int l;
  905.  
  906.   imnn = calloc(1,sizeof(scc_imnn_t));
  907.   imnn->idx = idx;
  908.   imnn->smap_size = scc_code_image(i->data,i->w,
  909.                   i->w,i->h,
  910.                   -1,&imnn->smap);
  911.     
  912.   for(l = 0 ; l < SCC_MAX_IM_PLANES && z[l] ; l++) {
  913.     // pack the zplane data
  914.     uint8_t* zd = malloc(z[l]->w/8*z[l]->h);
  915.     int j,d = 0;
  916.     for(j = 0 ; j < z[l]->w*z[l]->h ; j++) {
  917.       if(z[l]->data[j])
  918.     d |= (1<<(7-(j%8)));
  919.       
  920.       if(j % 8 == 7) {
  921.     zd[j/8] = d;
  922.     d = 0;
  923.       }
  924.     }
  925.     // code it
  926.     imnn->z_buf_size[l+1] = scc_code_zbuf(zd,z[l]->w/8,
  927.                      z[l]->w,z[l]->h,
  928.                      &imnn->z_buf[l+1]);
  929.     free(zd);
  930.   }
  931.  
  932.   return imnn;
  933. }
  934.  
  935. static scc_imnn_t* scc_roobj_obj_gen_imnn(scc_roobj_obj_t* obj) {
  936.   scc_imnn_t *imnn = NULL,*last = NULL,*new;
  937.   scc_roobj_state_t* st;
  938.   int idx = 1;
  939.  
  940.   for(st = obj->states ; st ; idx++, st = st->next) {
  941.     new = scc_roobj_state_gen_imnn(st,idx);
  942.     SCC_LIST_ADD(imnn,last,new);
  943.   }
  944.  
  945.   return imnn;
  946. }
  947.  
  948. static int scc_roobj_make_obj_parent(scc_roobj_t* ro) {
  949.   scc_roobj_obj_t* obj,*iter;
  950.   int idx;
  951.   
  952.   for(obj = ro->obj ; obj ; obj = obj->next) {
  953.     if(!obj->parent) continue;
  954.     // find the parent
  955.     for(iter = ro->obj, idx = 1 ;
  956.         iter && iter->sym != obj->parent ;
  957.         iter = iter->next, idx++);
  958.     if(!iter) {
  959.       scc_log(LOG_ERR,"Failed to find the parent of object %s\n",
  960.              obj->sym->sym);
  961.       return 0;
  962.     }
  963.     obj->parent_id = idx;
  964.   }
  965.   return 1;
  966. }
  967.  
  968. static int scc_scob_size(scc_script_t* scr) {
  969.   int size = 8 + scr->code_len;
  970.   scc_sym_fix_t* f;
  971.  
  972.   if(scr->sym_fix) {
  973.     size += 8;
  974.     for(f = scr->sym_fix ; f ; f = f->next)
  975.       size += 8;
  976.   }
  977.  
  978.   return size;
  979. }
  980.  
  981. static int scc_write_scob(scc_fd_t* fd, scc_script_t* scr) {
  982.   int n;
  983.   scc_sym_fix_t* f;
  984.  
  985.   if(scr->sym_fix) {
  986.     for(n = 0, f = scr->sym_fix ; f ; n++, f = f->next);
  987.  
  988.     scc_fd_w32(fd,MKID('S','F','I','X'));
  989.     scc_fd_w32be(fd,8 + n*8);
  990.  
  991.     for(f = scr->sym_fix ; f ; f = f->next) {
  992.       scc_fd_w8(fd,f->sym->type);
  993.       scc_fd_w8(fd,f->sym->subtype);      
  994.       scc_fd_w16le(fd,f->sym->rid);
  995.       scc_fd_w32le(fd,f->off);
  996.     }
  997.   }
  998.  
  999.   scc_fd_w32(fd,MKID('s','c','o','b'));
  1000.   scc_fd_w32be(fd,8 + scr->code_len);
  1001.   if(scr->code_len) scc_fd_write(fd,scr->code,scr->code_len);
  1002.  
  1003.   return 1;
  1004. }
  1005.  
  1006. static int scc_write_sym(scc_fd_t* fd, scc_symbol_t* s, char status) {
  1007.   // status: import/export
  1008.   scc_fd_w8(fd,status);
  1009.   // name
  1010.   scc_fd_w8(fd,strlen(s->sym));
  1011.   scc_fd_write(fd,s->sym,strlen(s->sym));
  1012.   // type
  1013.   scc_fd_w8(fd,s->type);
  1014.   // subtype
  1015.   scc_fd_w8(fd,s->subtype);
  1016.   // rid
  1017.   scc_fd_w16le(fd,s->rid);
  1018.   // addr
  1019.   scc_fd_w16le(fd,s->addr);
  1020.  
  1021.   return 1;
  1022. }
  1023.  
  1024. static int scc_sym_block_size(scc_symbol_t* s) {
  1025.   int size = 0;
  1026.  
  1027.   while(s) {
  1028.     if(s->rid && s->type != SCC_RES_LSCR)
  1029.       size += 1 + 1+strlen(s->sym) + 1 + 1 + 2 + 2;
  1030.     s = s->next;
  1031.   }
  1032.     
  1033.   return size;
  1034. }
  1035.  
  1036.  
  1037. static int scc_write_stab(scc_fd_t* fd, scc_roobj_t* ro, scc_ns_t* ns) {
  1038.   scc_symbol_t* s, *c;
  1039.   char status;
  1040.   int len = scc_sym_block_size(ns->glob_sym);
  1041.  
  1042.   // no sym at all
  1043.   if(!len) return 1;
  1044.   
  1045.   // first the global ns
  1046.   scc_fd_w32(fd,MKID('G','S','Y','M'));
  1047.   scc_fd_w32be(fd,8 + len);
  1048.  
  1049.   for(s = ns->glob_sym ; s ; s = s->next) {
  1050.     if(!s->rid) continue;
  1051.  
  1052.     // everything is imported except ourself
  1053.     scc_write_sym(fd,s,(s == ro->sym ? 'E' : 'I'));
  1054.   }
  1055.  
  1056.   // then the 
  1057.   for(s = ns->glob_sym ; s ; s = s->next) {
  1058.     if(!s->rid || s->type != SCC_RES_ROOM) continue;
  1059.     
  1060.     len = scc_sym_block_size(s->childs);
  1061.     if(!len) continue;
  1062.  
  1063.     // again stuff in our room is exported, the rest is imported
  1064.     status = (s == ro->sym ? 'E' : 'I');
  1065.  
  1066.     scc_fd_w32(fd,MKID('R','S','Y','M'));
  1067.     scc_fd_w32be(fd,8 + 2 + len);
  1068.  
  1069.     // rid
  1070.     scc_fd_w16le(fd,s->rid);
  1071.  
  1072.     for(c = s->childs ; c ; c = c->next) {
  1073.       if(!c->rid || c->type == SCC_RES_LSCR) continue;
  1074.  
  1075.       scc_write_sym(fd,c,status);
  1076.     }
  1077.  
  1078.   }
  1079.     
  1080.   return 1;
  1081. }
  1082.  
  1083. static int scc_stab_size(scc_ns_t* ns) {
  1084.   int size = 0;
  1085.   scc_symbol_t* s;
  1086.   int len = scc_sym_block_size(ns->glob_sym);
  1087.  
  1088.   if(!len) return 0;
  1089.  
  1090.   size += 8 + len;
  1091.  
  1092.   for(s = ns->glob_sym ; s ; s = s->next) {
  1093.     if(!s->rid || s->type != SCC_RES_ROOM) continue;
  1094.  
  1095.     len = scc_sym_block_size(s->childs);
  1096.     if(!len) continue;
  1097.  
  1098.     size += 8 + 2 + len;
  1099.   }
  1100.  
  1101.   return size;
  1102. }
  1103.  
  1104. int scc_lscr_block_size(scc_roobj_t* ro) {
  1105.   scc_script_t *scr;
  1106.   int en = 0,ex = 0;
  1107.   int size = 8 + 2; // NLSC
  1108.  
  1109.   for(scr = ro->lscr ; scr ; scr = scr->next) {
  1110.     if(!strcmp(scr->sym->sym,"entry")) en = 1;
  1111.     else if(!strcmp(scr->sym->sym,"exit")) ex = 1;
  1112.     else size += 2;
  1113.     size += 8 + scc_scob_size(scr);
  1114.   }
  1115.  
  1116.   if(!en) size += 8 + 1;
  1117.   if(!ex) size += 8 + 1;
  1118.  
  1119.   return size;
  1120. }
  1121.  
  1122. int scc_write_lscr_block(scc_roobj_t* ro, scc_fd_t* fd) {
  1123.   scc_script_t *scr,*en = NULL,*ex = NULL;
  1124.   int n = 0;
  1125.  
  1126.   for(scr = ro->lscr ; scr ; scr = scr->next) {
  1127.     if(!strcmp(scr->sym->sym,"entry")) en = scr;
  1128.     else if(!strcmp(scr->sym->sym,"exit")) ex = scr;
  1129.     else {
  1130.       n++;
  1131.       if(scr->sym->addr < 0)
  1132.     scc_log(LOG_WARN,"Warning: a local script is missing its address.\n");
  1133.     }
  1134.   }
  1135.  
  1136.   if(ex) {
  1137.     scc_fd_w32(fd,MKID('e','x','c','d'));
  1138.     scc_fd_w32be(fd,8 + scc_scob_size(ex));
  1139.     scc_write_scob(fd,ex);
  1140.   } else {
  1141.     scc_fd_w32(fd,MKID('E','X','C','D'));
  1142.     scc_fd_w32be(fd,8 + 1);
  1143.     scc_fd_w8(fd,0x65);
  1144.   }
  1145.  
  1146.   if(en) {
  1147.     scc_fd_w32(fd,MKID('e','n','c','d'));
  1148.     scc_fd_w32be(fd,8 + scc_scob_size(en));
  1149.     scc_write_scob(fd,en);
  1150.   } else {
  1151.     scc_fd_w32(fd,MKID('E','N','C','D'));
  1152.     scc_fd_w32be(fd,8 + 1);
  1153.     scc_fd_w8(fd,0x65);
  1154.   }
  1155.  
  1156.   scc_fd_w32(fd,MKID('N','L','S','C'));
  1157.   scc_fd_w32be(fd,8 + 2);
  1158.   scc_fd_w16le(fd,n);
  1159.  
  1160.   for(scr = ro->lscr ; scr ; scr = scr->next) {
  1161.     if(scr == en || scr == ex) continue;
  1162.     scc_fd_w32(fd,MKID('l','s','c','r'));
  1163.     scc_fd_w32be(fd,8 + 2 + scc_scob_size(scr));
  1164.     scc_fd_w16le(fd,scr->sym->addr);
  1165.     scc_write_scob(fd,scr);
  1166.   }
  1167.  
  1168.   return 1;
  1169. }
  1170.  
  1171. static int scc_imob_size(int version,scc_roobj_obj_t* obj) {
  1172.   scc_imnn_t* i;
  1173.   int base_size = version == 7 ? 20 : 16;
  1174.   int size = 8 + base_size +2;
  1175.   int ni = 0;
  1176.  
  1177.   for(i = obj->im ; i ; i = i->next) {
  1178.     size += 8 + scc_imnn_size(i);
  1179.     ni++;
  1180.   }
  1181.  
  1182.   if(!ni) ni++;
  1183.   size += 4*ni;
  1184.  
  1185.   return size;
  1186. }
  1187.  
  1188. static int scc_write_imob(int version,scc_roobj_obj_t* obj,scc_fd_t* fd) {
  1189.   int j,ni=0,nz=0;
  1190.   scc_imnn_t* i;
  1191.   scc_roobj_state_t* st;
  1192.   int base_size = version == 7 ? 20 : 16;
  1193.  
  1194.   for(i = obj->im ; i ; i = i->next) {
  1195.     int z = 0;
  1196.     ni++;
  1197.     for(j = 0 ; j < SCC_MAX_IM_PLANES ; j++) {
  1198.       if(i->z_buf[j]) z++;
  1199.     }
  1200.     if(z > nz) nz = z;
  1201.   }
  1202.  
  1203.   scc_fd_w32(fd,MKID('i','m','h','d'));
  1204.   scc_fd_w32be(fd,8 + base_size + 2 + (ni ? 4*ni : 4));
  1205.  
  1206.   if(version == 7) {
  1207.     // version
  1208.     scc_fd_w32le(fd,730);
  1209.     // obj id
  1210.     scc_fd_w16le(fd,obj->sym->rid);
  1211.     // number of image
  1212.     scc_fd_w16le(fd,ni);
  1213.     // x,y
  1214.     scc_fd_w16le(fd,obj->x);
  1215.     scc_fd_w16le(fd,obj->y);
  1216.     // w,h
  1217.     scc_fd_w16le(fd,obj->w);
  1218.     scc_fd_w16le(fd,obj->h);
  1219.     // num zpnn
  1220.     scc_fd_w16le(fd,nz);
  1221.     // unk
  1222.     scc_fd_w8(fd,0);
  1223.     // direction
  1224.     scc_fd_w8(fd,obj->dir);
  1225.   } else {
  1226.     // obj id
  1227.     scc_fd_w16le(fd,obj->sym->rid);
  1228.  
  1229.     // write number of image and zplanes
  1230.     scc_fd_w16le(fd,ni);
  1231.     scc_fd_w16le(fd,nz);
  1232.     // unk
  1233.     scc_fd_w16le(fd,0);
  1234.     // x,y
  1235.     scc_fd_w16le(fd,obj->x);
  1236.     scc_fd_w16le(fd,obj->y);
  1237.  
  1238.     // w,h
  1239.     scc_fd_w16le(fd,obj->w);
  1240.     scc_fd_w16le(fd,obj->h);
  1241.   }
  1242.  
  1243.   // num hotspot
  1244.   if(ni) {
  1245.     scc_fd_w16le(fd,ni);
  1246.     for(st = obj->states ; st ; st = st->next) {
  1247.       scc_fd_w16le(fd,st->hs_x);
  1248.       scc_fd_w16le(fd,st->hs_y);
  1249.     }
  1250.   } else {
  1251.     scc_fd_w16le(fd,1);
  1252.     scc_fd_w16le(fd,obj->hs_x);
  1253.     scc_fd_w16le(fd,obj->hs_y);
  1254.   }
  1255.  
  1256.   for(i = obj->im ; i ; i = i->next) {  
  1257.     scc_fd_w32(fd,MKID('I','M','0','0'+i->idx));
  1258.     scc_fd_w32be(fd,8 + scc_imnn_size(i));
  1259.     scc_write_imnn(fd,i);
  1260.   }
  1261.  
  1262.   return 1;
  1263. }
  1264.  
  1265. int scc_verb_block_size(scc_script_t* scr) {
  1266.   int size = 0;
  1267.  
  1268.   while(scr) {
  1269.     size += 8 + 2 + scc_scob_size(scr);
  1270.     scr = scr->next;
  1271.   }
  1272.   
  1273.   return size;
  1274. }
  1275.  
  1276. int scc_write_verb_block(scc_script_t* scr,scc_fd_t* fd) {
  1277.  
  1278.   while(scr) {
  1279.     scc_fd_w32(fd,MKID('v','e','r','b'));
  1280.     scc_fd_w32be(fd,8 + 2 +scc_scob_size(scr));
  1281.     if(scr->sym) scc_fd_w16le(fd,scr->sym->rid);
  1282.     else scc_fd_w16le(fd,0);
  1283.     scc_write_scob(fd,scr);
  1284.     scr = scr->next;
  1285.   }
  1286.   return 1;
  1287. }
  1288.  
  1289. int scc_obob_size(int version,scc_roobj_obj_t* obj) {
  1290.   int body_size = version == 7 ? 4+1+1 : 2+2 +2+2 +1+1 +2*2 +1;
  1291.   int size = 8 + 2 +1+2+2*SCC_MAX_CLASS + body_size;
  1292.  
  1293.   size += scc_verb_block_size(obj->verb);
  1294.  
  1295.   size += 8 + (obj->name ? strlen(obj->name) : 0) + 1;
  1296.  
  1297.   return size;
  1298. }
  1299.  
  1300.  
  1301. int scc_write_obob(int version,scc_roobj_obj_t* obj,scc_fd_t* fd) {
  1302.   int body_size = version == 7 ? 4+1+1 : 2+2 +2+2 +1+1 +2*2 +1;
  1303.   int i;
  1304.  
  1305.   scc_fd_w32(fd,MKID('c','d','h','d'));
  1306.   scc_fd_w32be(fd,8 + 2 +1+2+2*SCC_MAX_CLASS + body_size);
  1307.  
  1308.   // rid
  1309.   scc_fd_w16le(fd,obj->sym->rid);
  1310.  
  1311.   // initial state
  1312.   scc_fd_w8(fd,obj->state);
  1313.   // owner
  1314.   if(obj->owner)
  1315.     scc_fd_w16le(fd,obj->owner->rid);
  1316.   else
  1317.     scc_fd_w16le(fd,0);
  1318.   // classes
  1319.   for(i = 0 ; i < SCC_MAX_CLASS ; i++) {
  1320.     if(obj->class[i])
  1321.       scc_fd_w16le(fd,obj->class[i]->rid);
  1322.     else
  1323.       scc_fd_w16le(fd,0);
  1324.   }
  1325.  
  1326.   if(version == 7) {
  1327.     // version
  1328.     scc_fd_w32le(fd,732);
  1329.     // parent
  1330.     scc_fd_w8(fd,obj->parent_id);
  1331.     // parent state
  1332.     scc_fd_w8(fd,obj->parent_state);
  1333.   } else {
  1334.     scc_fd_w16le(fd,obj->x);
  1335.     scc_fd_w16le(fd,obj->y);
  1336.  
  1337.     scc_fd_w16le(fd,obj->w);
  1338.     scc_fd_w16le(fd,obj->h);
  1339.  
  1340.     // parent state
  1341.     scc_fd_w8(fd,obj->parent_state);
  1342.     // parent
  1343.     scc_fd_w8(fd,obj->parent_id);
  1344.     // unk
  1345.     scc_fd_w32(fd,0);
  1346.     // actor dir
  1347.     scc_fd_w8(fd,obj->dir);
  1348.   }
  1349.  
  1350.   // VERBS
  1351.   scc_write_verb_block(obj->verb,fd);
  1352.  
  1353.   
  1354.   scc_fd_w32(fd,MKID('O','B','N','A'));
  1355.   scc_fd_w32be(fd,8 + (obj->name ? strlen(obj->name) : 0) + 1);
  1356.   if(obj->name)
  1357.     scc_fd_write(fd,obj->name,strlen(obj->name));
  1358.   scc_fd_w8(fd,0);
  1359.     
  1360.   return 1;
  1361. }
  1362.  
  1363. int scc_roobj_write_res(scc_roobj_res_t* res, scc_fd_t* fd) {
  1364.   int rt;
  1365.  
  1366.   for(rt = 0 ; scc_res_types[rt].type >= 0 ; rt++) {
  1367.     if(res->type && scc_res_types[rt].id == res->type) break;
  1368.   }
  1369.  
  1370.   if(scc_res_types[rt].type < 0) {
  1371.     scc_log(LOG_ERR,"Unknown resource type !!!!\n");
  1372.     return 0;
  1373.   }
  1374.   
  1375.   scc_fd_w32(fd,scc_res_types[rt].fixid);
  1376.   scc_fd_w32be(fd,8 + 2 + res->data_len);
  1377.   scc_fd_w16le(fd,res->sym->rid);
  1378.   scc_fd_write(fd,res->data,res->data_len);
  1379.  
  1380.   return 1;
  1381. }
  1382.  
  1383.  
  1384. int scc_roobj_cycl_size(scc_roobj_cycl_t* c) {
  1385.   int size = 1;
  1386.   while(c) {
  1387.     size += 9;
  1388.     c = c->next;
  1389.   }
  1390.   return size;
  1391. }
  1392.   
  1393.  
  1394. int scc_roobj_write_cycl(scc_roobj_cycl_t* c, scc_fd_t* fd) {
  1395.   
  1396.   while(c) {
  1397.     scc_fd_w8(fd,c->sym->addr);
  1398.     scc_fd_w16(fd,0);
  1399.     scc_fd_w16be(fd,c->freq);
  1400.     scc_fd_w16be(fd,c->flags);
  1401.     scc_fd_w8(fd,c->start);
  1402.     scc_fd_w8(fd,c->end);
  1403.     c = c->next;
  1404.   }
  1405.   scc_fd_w8(fd,0);
  1406.   return 1;
  1407. }
  1408.  
  1409. int scc_roobj_write(scc_roobj_t* ro, scc_ns_t* ns, scc_fd_t* fd) {
  1410.   scc_pal_t* pals;
  1411.   scc_rmim_t* rmim;
  1412.   scc_script_t* scr;
  1413.   scc_roobj_obj_t* obj;
  1414.   scc_roobj_res_t* res;
  1415.   int i;
  1416.   int num_obj = 0;
  1417.   int stab_len;
  1418.   int rmhd_size = ro->target->version == 7 ? 10 : 6;
  1419.   int size = 8 + rmhd_size;
  1420.  
  1421.   stab_len = scc_stab_size(ns);
  1422.   if(stab_len) size += 8 + stab_len;
  1423.   
  1424.   // CYCL
  1425.   size += 8 + scc_roobj_cycl_size(ro->cycl);
  1426.   // TRNS
  1427.   size += 8 + 2;
  1428.   // PALS
  1429.   pals = scc_roobj_gen_pals(ro);
  1430.   if(!pals) return 0;
  1431.   size += 8 + scc_pals_size(pals);
  1432.   // RMIM
  1433.   rmim = scc_roobj_gen_rmim(ro);
  1434.   if(!rmim) return 0;
  1435.   size += 8 + scc_rmim_size(rmim);
  1436.   // OBIM/OBCD
  1437.   if(!scc_roobj_make_obj_parent(ro)) return 0;
  1438.   for(obj = ro->obj ; obj ; obj = obj->next) {
  1439.     obj->im = scc_roobj_obj_gen_imnn(obj);
  1440.     size += 8 + scc_imob_size(ro->target->version,obj);
  1441.     size += 8 + scc_obob_size(ro->target->version,obj);
  1442.     num_obj++;
  1443.   }
  1444.   // local scripts
  1445.   size += scc_lscr_block_size(ro);
  1446.   // BOXD
  1447.   if(!ro->boxd)
  1448.     size += 8 + 42;
  1449.   else
  1450.     size += 8 + scc_boxd_size(ro->boxd);
  1451.   // BOXM
  1452.   if(!ro->boxm)
  1453.     size += 8 + 8;
  1454.   else
  1455.     size += ro->boxm->size;
  1456.   // SCAL
  1457.   if(!ro->scal)
  1458.     size += 8 + 20;
  1459.   else
  1460.     size += ro->scal->size;
  1461.  
  1462.   // global scripts
  1463.   for(scr = ro->scr ; scr ; scr = scr->next)
  1464.     size += 8 + 2 + scc_scob_size(scr);
  1465.  
  1466.   // ressources
  1467.   for(res = ro->res ; res ; res = res->next)
  1468.     size += 8 + 2 + res->data_len;
  1469.  
  1470.   // Now write all that  
  1471.   // the block header
  1472.   scc_fd_w32(fd,MKID('r','o','o','m'));
  1473.   scc_fd_w32be(fd,size + 1 + 8);
  1474.  
  1475.   scc_fd_w8(fd,ro->target->version);
  1476.  
  1477.   scc_fd_w32(fd,MKID('R','M','H','D'));
  1478.   scc_fd_w32be(fd,8 + rmhd_size);
  1479.   if(ro->target->version == 7)
  1480.       scc_fd_w32le(fd,730); // version
  1481.   scc_fd_w16le(fd,ro->image->w);
  1482.   scc_fd_w16le(fd,ro->image->h);
  1483.   scc_fd_w16le(fd,num_obj);
  1484.  
  1485.   if(stab_len) {
  1486.     scc_fd_w32(fd,MKID('S','T','A','B'));
  1487.     scc_fd_w32be(fd,stab_len + 8);
  1488.     scc_write_stab(fd,ro,ns);
  1489.   }
  1490.  
  1491.   scc_fd_w32(fd,MKID('C','Y','C','L'));
  1492.   scc_fd_w32be(fd,8 + scc_roobj_cycl_size(ro->cycl));
  1493.   scc_roobj_write_cycl(ro->cycl,fd);
  1494.  
  1495.   scc_fd_w32(fd,MKID('T','R','N','S'));
  1496.   scc_fd_w32be(fd,8 + 2);
  1497.   scc_fd_w16le(fd,ro->trans);
  1498.  
  1499.   scc_fd_w32(fd,MKID('P','A','L','S'));
  1500.   scc_fd_w32be(fd,8 + scc_pals_size(pals));
  1501.   scc_write_pals(fd,pals);
  1502.  
  1503.   scc_fd_w32(fd,MKID('R','M','I','M'));
  1504.   scc_fd_w32be(fd,8 + scc_rmim_size(rmim));
  1505.   scc_write_rmim(fd,rmim);
  1506.  
  1507.   // OBIM
  1508.   for(obj = ro->obj ; obj ; obj = obj->next) {
  1509.     scc_fd_w32(fd,MKID('o','b','i','m'));
  1510.     scc_fd_w32be(fd,8 + scc_imob_size(ro->target->version,obj));
  1511.     scc_write_imob(ro->target->version,obj,fd);
  1512.   }
  1513.   // OBCD
  1514.   for(obj = ro->obj ; obj ; obj = obj->next) {
  1515.     scc_fd_w32(fd,MKID('o','b','c','d'));
  1516.     scc_fd_w32be(fd,8 + scc_obob_size(ro->target->version,obj));
  1517.     scc_write_obob(ro->target->version,obj,fd);
  1518.   }
  1519.  
  1520.   // All the stuff needed for local scripts
  1521.   scc_write_lscr_block(ro,fd);
  1522.  
  1523.  
  1524.  
  1525.   // BOXD
  1526.   scc_fd_w32(fd,MKID('B','O','X','D'));
  1527.   if(ro->boxd) {
  1528.     scc_fd_w32be(fd,8 + scc_boxd_size(ro->boxd));
  1529.     scc_write_boxd(fd,ro->boxd);
  1530.   } else {
  1531.     scc_fd_w32be(fd,8 + 42);
  1532.     scc_fd_w16le(fd,2);      // num box
  1533.     // box 0
  1534.     for(i = 0 ; i < 8 ; i++) // coords
  1535.       scc_fd_w16le(fd,-32000);
  1536.     scc_fd_w16(fd,0); // mask, flags
  1537.     scc_fd_w16le(fd,255); // scale
  1538.     // dummy box
  1539.     scc_fd_w16le(fd,2); // ulx
  1540.     scc_fd_w16le(fd,2); // uly
  1541.     scc_fd_w16le(fd,4); // urx
  1542.     scc_fd_w16le(fd,2); // ury
  1543.     scc_fd_w16le(fd,4); // lrx
  1544.     scc_fd_w16le(fd,4); // lry
  1545.     scc_fd_w16le(fd,2); // llx
  1546.     scc_fd_w16le(fd,4); // lly
  1547.     scc_fd_w16(fd,0); // mask, flags
  1548.     scc_fd_w16le(fd,255); // scale
  1549.   }
  1550.   // BOXM
  1551.   if(ro->boxm)
  1552.     scc_fd_write(fd,ro->boxm->data,ro->boxm->size);
  1553.   else {
  1554.     scc_fd_w32(fd,MKID('B','O','X','M'));
  1555.     scc_fd_w32be(fd,8 + 8);
  1556.     scc_fd_w32be(fd,0x000000FF);
  1557.     scc_fd_w32be(fd,0x010101FF);
  1558.   }
  1559.  
  1560.   // SCAL
  1561.   if(ro->scal)
  1562.     scc_fd_write(fd,ro->scal->data,ro->scal->size);
  1563.   else {
  1564.     scc_fd_w32(fd,MKID('S','C','A','L'));
  1565.     scc_fd_w32be(fd,8 + 20);
  1566.     for(i = 0 ; i < 5 ; i++)
  1567.       scc_fd_w32(fd,0);
  1568.   }
  1569.  
  1570.   // SCOB
  1571.   for(scr = ro->scr ; scr ; scr = scr->next) {
  1572.     scc_fd_w32(fd,MKID('s','c','r','p'));
  1573.     scc_fd_w32be(fd,8 + 2 + scc_scob_size(scr));
  1574.     scc_fd_w16le(fd,scr->sym->rid);
  1575.     scc_write_scob(fd,scr);
  1576.   }
  1577.  
  1578.   // write ressources
  1579.   for(res = ro->res ; res ; res = res->next)
  1580.     scc_roobj_write_res(res,fd);
  1581.  
  1582.   return 1;
  1583. }
  1584.