1.  
  2. lib file = <file.ssz>;
  3. lib s = <string.ssz>;
  4. lib sdl = <alpha/sdlplugin.ssz>;
  5. lib consts = <consts.ssz>;
  6. lib m = <math.ssz>;
  7. lib tbl = <table.ssz>;
  8. lib cfg = "config.ssz";
  9. lib com = "common.ssz";
  10.  
  11.  
  12. const int NumCharPalletes = 12;
  13.  
  14. public &SffHeader
  15. {
  16.   public ubyte ver0, ver1, ver2, ver3;
  17.   public uint firstSpriteHeaderOffset, firstPaletteHeaderOffset;
  18.   public uint numberOfPalettes, numberOfSprites;
  19.   public bool read(&.file.File f=, uint lofs=, uint tofs=)
  20.   {
  21.     ubyte ub;
  22.     loop{
  23.       index i = 0;
  24.       %char s;
  25.     do:
  26.       if(!f.read!ubyte?(ub=)) ret false;
  27.       s .= (char)ub;
  28.       i++;
  29.     while i < 12:
  30.       if(!.s.equ(s, "ElecbyteSpr"\0)){
  31.         .com.error!self?("ElecbyteSprじゃない");
  32.         ret false;
  33.       }
  34.     }
  35.     if(!f.read!ubyte?(`ver3=)) ret false;
  36.     if(!f.read!ubyte?(`ver2=)) ret false;
  37.     if(!f.read!ubyte?(`ver1=)) ret false;
  38.     if(!f.read!ubyte?(`ver0=)) ret false;
  39.     uint dummy;
  40.     switch(`ver0){
  41.     case 0d1:
  42.       if(!f.read!uint?(dummy=)) ret false;
  43.       `numberOfPalettes = 0x0;
  44.       if(!f.read!uint?(`numberOfSprites=)) ret false;
  45.       if(!f.read!uint?(`firstSpriteHeaderOffset=)) ret false;
  46.       if(!f.read!uint?(dummy=)) ret false;
  47.       `firstPaletteHeaderOffset = 0x0;
  48.     case 0d2:
  49.       if(!f.read!uint?(dummy=)) ret false;
  50.       if(!f.read!uint?(dummy=)) ret false;
  51.       if(!f.read!uint?(dummy=)) ret false;
  52.       if(!f.read!uint?(dummy=)) ret false;
  53.       if(!f.read!uint?(dummy=)) ret false;
  54.       if(!f.read!uint?(`firstSpriteHeaderOffset=)) ret false;
  55.       if(!f.read!uint?(`numberOfSprites=)) ret false;
  56.       if(!f.read!uint?(`firstPaletteHeaderOffset=)) ret false;
  57.       if(!f.read!uint?(`numberOfPalettes=)) ret false;
  58.       if(!f.read!uint?(lofs=)) ret false;
  59.       if(!f.read!uint?(dummy=)) ret false;
  60.       if(!f.read!uint?(tofs=)) ret false;
  61.     default:
  62.       ret false;
  63.     }
  64.     ret true;
  65.   }
  66. }
  67.  
  68. &PalleteList
  69. {
  70.   %^uint palletes;
  71.   %index palidxs;
  72.   public &.tbl.IntTable!uint, index? palTable;
  73.   public void clear()
  74.   {
  75.     `palletes.new(0);
  76.     `palidxs.new(0);
  77.     `palTable.clear();
  78.   }
  79.   public ^uint newPal(index pi=)
  80.   {
  81.     `palidxs.new[#`palletes] = (pi = #`palletes);
  82.     `palletes.new[-1].new(256);
  83.     ret `palletes[-1];
  84.   }
  85.   public void setSource(index pi, ^uint pal)
  86.   {
  87.     `palidxs.new[pi] = pi;
  88.     `palletes.new[pi] = pal;
  89.   }
  90.   public ^uint get(index pi)
  91.   {
  92.     ret `palletes[`palidxs[pi]];
  93.   }
  94.   public void remap(index source, index dest)
  95.   {
  96.     `palidxs[source] = dest;
  97.   }
  98.   public void resetRemap()
  99.   {
  100.     loop{index i = 0; while; do: `palidxs[i] = i; i++; while i < #`palidxs:}
  101.   }
  102. }
  103.  
  104. public &Sprite
  105. {
  106.   public ^uint colorPallet;
  107.   public ^ubyte pxl;
  108.   public %byte pluginbuf;
  109.   public &.sdl.Rect rct;
  110.   public short imageGroup, imageNumber;
  111.   public index palidx = -1, link = -1;
  112.   public int rle = 0;
  113.   public void shareCopy(`self sp=)
  114.   {
  115.     `colorPallet = sp.colorPallet;
  116.     `pxl = sp.pxl;
  117.     `rct.w = sp.rct.w;
  118.     `rct.h = sp.rct.h;
  119.     `palidx = sp.palidx;
  120.     `rle = sp.rle;
  121.   }
  122.   public void copy(`self sp=)
  123.   {
  124.     `shareCopy(sp=);
  125.     `pluginbuf = sp.pluginbuf;
  126.     `rct = sp.rct;
  127.     `imageGroup = sp.imageGroup;
  128.     `imageNumber = sp.imageNumber;
  129.     `link = sp.link;
  130.   }
  131.   public ^uint getPal(&.PalleteList pl=)
  132.   {
  133.     if(#`colorPallet > 0) ret `colorPallet;
  134.     ret pl.get(`palidx);
  135.   }
  136.   public bool readHeader(&.file.File f=)
  137.   {
  138.     if(!f.read!short?(`rct.x=)) ret false;
  139.     if(!f.read!short?(`rct.y=)) ret false;
  140.     if(!f.read!short?(`imageGroup=)) ret false;
  141.     if(!f.read!short?(`imageNumber=)) ret false;
  142.     ret true;
  143.   }
  144.   public bool readPcxHeader(&.file.File f=, long offset)
  145.   {
  146.     f.seek(offset, .file.Seek::SET);
  147.     ubyte dummy, encoding, bpp;
  148.     if(!f.read!ubyte?(dummy=)) ret false;
  149.     if(!f.read!ubyte?(dummy=)) ret false;
  150.     if(!f.read!ubyte?(encoding=)) ret false;
  151.     if(!f.read!ubyte?(bpp=)) ret false;
  152.     if(bpp != 0d8){
  153.       .com.error!.self?("256色じゃない");
  154.       ret false;
  155.     }
  156.     ushort x, y, w, h;
  157.     if(!f.read!ushort?(x=)) ret false;
  158.     if(!f.read!ushort?(y=)) ret false;
  159.     if(!f.read!ushort?(w=)) ret false;
  160.     if(!f.read!ushort?(h=)) ret false;
  161.     f.seek(offset+66, .file.Seek::SET);
  162.     ushort bpl;
  163.     if(!f.read!ushort?(bpl=)) ret false;
  164.     `rct.w = w - x + 0x1;
  165.     `rct.h = h - y + 0x1;
  166.     `rle = encoding == 0x1 ? (int)bpl : 0;
  167.     ret true;
  168.   }
  169.   public bool readHeaderV2(
  170.     &.file.File f=, uint ofs=, uint siz=,
  171.     uint lofs, uint tofs, ushort idxlnked=)
  172.   {
  173.     if(!f.read!short?(`imageGroup=)) ret false;
  174.     if(!f.read!short?(`imageNumber=)) ret false;
  175.     if(!f.read!ushort?(`rct.w=)) ret false;
  176.     if(!f.read!ushort?(`rct.h=)) ret false;
  177.     if(!f.read!short?(`rct.x=)) ret false;
  178.     if(!f.read!short?(`rct.y=)) ret false;
  179.     if(!f.read!ushort?(idxlnked=)) ret false;
  180.     ubyte fmt, dummy;
  181.     if(!f.read!ubyte?(fmt=)) ret false;
  182.     `rle = -(int)fmt;
  183.     if(!f.read!ubyte?(dummy=)) ret false;
  184.     if(!f.read!uint?(ofs=)) ret false;
  185.     if(!f.read!uint?(siz=)) ret false;
  186.     ushort pali, flg;
  187.     if(!f.read!ushort?(pali=)) ret false;
  188.     `palidx = (index)pali;
  189.     if(!f.read!ushort?(flg=)) ret false;
  190.     ofs += (flg & 0d1) == 0x0 ? lofs : tofs;
  191.     ret true;
  192.   }
  193.   public bool read(
  194.     &.file.File f=, &.SffHeader sh=, long offset, uint loh, uint nsh,
  195.     ^`self prev, bool palletSame=, &.PalleteList pl=, bool c00)
  196.   {
  197.     uint lenghtOfSubheader = loh;
  198.     if(nsh > (uint)offset) lenghtOfSubheader = nsh - (uint)offset;//lohを無視
  199.     if(!f.read!bool?(palletSame=)) ret false;
  200.     if(#prev == 0) palletSame = false;
  201.     if(!`readPcxHeader(f=, offset)) ret false;
  202.     f.seek(offset + 128, .file.Seek::SET);
  203.     `pxl.new((index)lenghtOfSubheader - (128+(c00||palletSame?0:768)));
  204.     f.readAry!ubyte?(`pxl);
  205.     loop{
  206.       index i = 0;
  207.       ubyte r, g, b;
  208.       if(palletSame){
  209.         if(#prev > 0) `palidx = prev~palidx;
  210.         if(`palidx < 0) pl.newPal(`palidx=);
  211.         break, break;
  212.       }
  213.       ^uint pal = pl.newPal(`palidx=);
  214.       if(c00) f.seek(offset + (long)lenghtOfSubheader - 768, .file.Seek::SET);
  215.     do:
  216.       if(!f.read!ubyte?(r=)) ret false;
  217.       if(!f.read!ubyte?(g=)) ret false;
  218.       if(!f.read!ubyte?(b=)) ret false;
  219.       pal[i] = (uint)r<<0d16 | (uint)g<<0d8 | (uint)b;
  220.       i++;
  221.     while i < 256:
  222.     }
  223.     if(
  224.       !.cfg.SaveMemory
  225.       || (index)`rct.w*(index)`rct.h
  226.       < (`rct.w >= 0d256 ? (#`pxl/256)*(index)`rct.w : #`pxl))
  227.     {
  228.       `rlePcxDecode();
  229.     }
  230.     ret true;
  231.   }
  232.   public bool readV2(&.file.File f=, long ofs, uint dsz)
  233.   {
  234.     f.seek(ofs+4, .file.Seek::SET);
  235.     `pxl.new((index)dsz);
  236.     f.readAry!ubyte?(`pxl);
  237.     if(`rle < 0) switch(-`rle){
  238.     case 2:
  239.       `rle8Decode();
  240.     case 3:
  241.       `rle5Decode();
  242.     case 4:
  243.       `lz5Decode();
  244.     default:
  245.       ret false;
  246.     }
  247.     ret true;
  248.   }
  249.   public void rlePcxDecode()
  250.   {
  251.     if(#`pxl == 0 || `rle <= 0) ret;
  252.     ^/ubyte rle = `pxl;
  253.     `pxl.new((index)((uint)`rct.w * `rct.h));
  254.     loop{
  255.       int w = (int)`rct.w;
  256.       int leng = #`pxl;
  257.       index i = 0, j = 0, k = 0;
  258.     do:
  259.       loop{
  260.         int size;
  261.         ubyte d = rle[i++];
  262.         branch{
  263.         cond d >= 0xC0:
  264.           size = (int)(d & 0x3F);
  265.           d = rle[i++];
  266.         else:
  267.           size = 1;
  268.         }
  269.         while;
  270.       do:
  271.         `pxl[j] = d;
  272.         j += (int)(k < w);
  273.         if(++k == `rle){
  274.           k = 0;
  275.           size = 0;
  276.         }
  277.       while --size >= 0:
  278.       }
  279.     while j < leng:
  280.     }
  281.     `rle = 0;
  282.   }
  283.   public void rle8Decode()
  284.   {
  285.     if(#`pxl == 0) ret;
  286.     ^/ubyte rle = `pxl;
  287.     `pxl.new((index)((uint)`rct.w * `rct.h));
  288.     loop{
  289.       int leng = #`pxl;
  290.       index i = 0, j = 0;
  291.       while;
  292.     do:
  293.       loop{
  294.         int size;
  295.         ubyte d = rle[i++];
  296.         branch{
  297.         cond (d&0xC0) == 0x40:
  298.           size = (int)(d & 0x3F);
  299.           d = rle[i++];
  300.         else:
  301.           size = 1;
  302.         }
  303.         while;
  304.       do:
  305.         `pxl[j++] = d;
  306.       while --size >= 0:
  307.       }
  308.     while j < leng:
  309.     }
  310.     `rle = 0;
  311.   }
  312.   public void rle5Decode()
  313.   {
  314.     if(#`pxl == 0) ret;
  315.     ^/ubyte rle = `pxl;
  316.     `pxl.new((index)((uint)`rct.w * `rct.h));
  317.     loop{
  318.       int leng = #`pxl;
  319.       index i = 0, j = 0;
  320.       while;
  321.     do:
  322.       loop{
  323.         int rlen = (int)rle[i++];
  324.         int dlen = (int)(rle[i] & 0x7F);
  325.         ubyte c = rle[i++]>>0d7 != 0x0 ? rle[i++] : 0x0;
  326.       do:
  327.         `pxl[j++] = c;
  328.       while --rlen >= 0:
  329.         if(--dlen >= 0){
  330.           c = rle[i] & 0x1F;
  331.           rlen = (int)(rle[i++]>>0d5);
  332.           break, do;
  333.         }
  334.       }
  335.     while j < leng:
  336.     }
  337.     `rle = 0;
  338.   }
  339.   public void lz5Decode()
  340.   {
  341.     if(#`pxl == 0) ret;
  342.     ^/ubyte rle = `pxl;
  343.     `pxl.new((index)((uint)`rct.w * `rct.h));
  344.     loop{
  345.       int leng = #`pxl;
  346.       index i = 0, j = 0;
  347.       uint s = 0x0, rbc = 0x0;
  348.       ubyte ct = rle[i++], rb = 0x0;
  349.       while;
  350.     do:
  351.       branch{
  352.         int size;
  353.         uint d;
  354.       cond (ct & 0d1<<s) != 0x0:
  355.         loop{
  356.           d = rle[i++];
  357.           branch{
  358.           cond (d&0x3F) == 0x00:
  359.             d = (d<<0d2 | rle[i++]) + 0d1;
  360.             size = (int)rle[i++] + 2;
  361.           else:
  362.             rb |= (d&0xC0) >> rbc;
  363.             rbc += 0d2;
  364.             size = (int)(d & 0x3F);
  365.             branch{
  366.             cond rbc < 0d8:
  367.               d = (uint)rle[i++] + 0x1;
  368.             else:
  369.               d = (uint)rb + 0d1;
  370.               rbc = 0x0;
  371.               rb = 0x0;
  372.             }
  373.           }
  374.         do:
  375.           `pxl[j] = `pxl[j-(index)d];
  376.           j++;
  377.         while --size >= 0:
  378.         }
  379.       else:
  380.         loop{
  381.           d = rle[i++];
  382.           branch{
  383.           cond (d&0xE0) == 0x00:
  384.             size = (int)rle[i++] + 8;
  385.           else:
  386.             size = (int)(d >> 0d5);
  387.             d &= 0x1F;
  388.           }
  389.           while;
  390.         do:
  391.           `pxl[j++] = d;
  392.         while --size >= 0:
  393.         }
  394.       }
  395.       if(++s >= 0d8){
  396.         s = 0x0;
  397.         ct = rle[i++];
  398.       }
  399.     while j < leng:
  400.     }
  401.     `rle = 0;
  402.   }
  403.   public bool loadFromSff(^/char fn, short ig, short in)
  404.   {
  405.     &.file.File f;
  406.     if(!f.open(fn, "rb")) ret false;
  407.     &.SffHeader h;
  408.     uint lofs, tofs;
  409.     if(!h.read(f=, lofs=, tofs=)) ret false;
  410.     uint shofs = h.firstSpriteHeaderOffset, misc, size;
  411.     ushort indexOfPrevious;
  412.     &.PalleteList pl;
  413.     loop{
  414.       index i = 0;
  415.       %uint newSubHeaderOffset .= shofs;
  416.       bool palletSame;
  417.       ~$bool() foo = [bool(){
  418.         switch(h.ver0){
  419.         case 0d1:
  420.           if(!f.read!uint?(misc=)) ret false;
  421.           if(!f.read!uint?(size=)) ret false;
  422.           if(!`readHeader(f=)) ret false;
  423.           if(!f.read!ushort?(indexOfPrevious=)) ret false;
  424.         case 0d2:
  425.           if(
  426.             !`readHeaderV2(
  427.               f=, misc=, size=, lofs, tofs, indexOfPrevious=)) ret false;
  428.         }
  429.         ret true;
  430.       }];
  431.       ^`self dummy;
  432.       while;
  433.     do:
  434.       newSubHeaderOffset .= shofs;
  435.       f.seek((long)shofs, .file.Seek::SET);
  436.       if(!foo(::)) ret false;
  437.       if(`palidx >= 0 && (`imageGroup != ig || `imageNumber != in)) continue;
  438.       loop{
  439.         uint ip = !indexOfPrevious;
  440.         while;
  441.       do:
  442.         if(ip == indexOfPrevious) ret false;
  443.         ip = indexOfPrevious;
  444.         shofs =
  445.           h.ver0 == 0d1 ? newSubHeaderOffset[(index)ip]
  446.           : h.firstSpriteHeaderOffset + ip*0d28;
  447.         f.seek((long)shofs, .file.Seek::SET);
  448.         if(!foo(::)) ret false;
  449.       while size == 0d0:
  450.       }
  451.       switch(h.ver0){
  452.       case 0d1:
  453.         if(
  454.           !`read(
  455.             f=, h=, (long)(shofs + 0d32), size,
  456.             misc, dummy, palletSame=, pl=, false)) ret false;
  457.       case 0d2:
  458.         if(!`readV2(f=, (long)misc, size)) ret false;
  459.       }
  460.       if(`imageGroup == ig && `imageNumber == in) break;
  461.       dummy.new(1);
  462.       dummy~palidx = `palidx;
  463.     continue:
  464.       shofs = h.ver0 == 0d1 ? misc : shofs + 0d28;
  465.       i++;
  466.     while i < (index)h.numberOfSprites:
  467.       ret false;
  468.     }
  469.     if(h.ver0 == 0d1){
  470.       `colorPallet = pl.get(`palidx);
  471.       `palidx = -1;
  472.       ret true;
  473.     }
  474.     loop{
  475.       uint ip;
  476.       indexOfPrevious = (uint)`palidx;
  477.     do:
  478.       ip = indexOfPrevious;
  479.       shofs = h.firstPaletteHeaderOffset + ip*0d16;
  480.       f.seek((long)shofs + 6, .file.Seek::SET);
  481.       if(!f.read!ushort?(indexOfPrevious=)) ret false;
  482.       if(!f.read!uint?(misc=)) ret false;
  483.       if(!f.read!uint?(size=)) ret false;
  484.     while size == 0d0 && ip != indexOfPrevious:
  485.     }
  486.     f.seek((long)(lofs+misc), .file.Seek::SET);
  487.     `colorPallet.new(256);
  488.     loop{
  489.       index i = 0, l = (index)size / 4;
  490.       ubyte r, g, b, dummy;
  491.     do:
  492.       if(!f.read!ubyte?(r=)) ret false;
  493.       if(!f.read!ubyte?(g=)) ret false;
  494.       if(!f.read!ubyte?(b=)) ret false;
  495.       if(!f.read!ubyte?(dummy=)) ret false;
  496.       `colorPallet[i] = (uint)r<<0d16 | (uint)g<<0d8 | (uint)b;
  497.       i++;
  498.     while i < l:
  499.     }
  500.     if(#`colorPallet == 0) `colorPallet.new(256);
  501.     `palidx = -1;
  502.     ret true;
  503.   }
  504.   public void draw(float x, float y, float xscale, float yscale, ^uint pal)
  505.   {
  506.     &.sdl.Rect tile;
  507.     tile.set(0, 0, 0d0, 0d0);
  508.     float x2 = x - xscale*(float)`rct.x;
  509.     float y2 = y - yscale*(float)`rct.y;
  510.     if(xscale < 0.0) x2 *= -1.0;
  511.     if(yscale < 0.0) y2 = -y2 + 240.0;
  512.     .sdl.screen.renderMugenZoom(
  513.       .com.scrrect=, 0.0, 0.0,
  514.       `pxl, pal, 0, `rct=, -x2*.com.WidthScale, -y2*.com.HeightScale,
  515.       tile=, xscale*.com.WidthScale, xscale*.com.WidthScale,
  516.       yscale*.com.HeightScale, 0.0, 0x0, 255, `rle, `pluginbuf=);
  517.   }
  518. }
  519.  
  520.  
  521. public &Sff
  522. {
  523.   public &.SffHeader head;
  524.   public &.tbl.IntTable!uint, &.Sprite? spriteTable;
  525.   public &.PalleteList palList;
  526.   new()
  527.   {
  528.     `clear();
  529.   }
  530.   public void clear()
  531.   {
  532.     `spriteTable.clear();
  533.     `palList.clear();
  534.     loop{
  535.       index i = 0, foo;
  536.       ^index idx;
  537.       while;
  538.     do:
  539.       `palList.newPal(foo=);
  540.       i++;
  541.       idx.new(1);
  542.       idx<> = foo;
  543.       `palList.palTable.set(0d1<<0d16 | (uint)i, idx);
  544.     while i < .NumCharPalletes:
  545.     }
  546.   }
  547.   public bool loadFile(^/char filename, bool chr)
  548.   {
  549.     &.file.File f;
  550.     if(!f.open(filename, "rb")) ret false;
  551.     `clear();
  552.     uint lofs, tofs;
  553.     if(!`head.read(f=, lofs=, tofs=)) ret false;
  554.     if(`head.ver0 != 0d1)loop{
  555.        index i = 0;
  556.        ^uint pal;
  557.        ushort group, item, link, dummy;
  558.        uint ofs, siz;
  559.        ^index idx;
  560.        while;
  561.     do:
  562.       f.seek((long)`head.firstPaletteHeaderOffset + 16*i, .file.Seek::SET);
  563.       if(!f.read!ushort?(group=)) ret false;
  564.       if(!f.read!ushort?(item=)) ret false;
  565.       if(!f.read!ushort?(dummy=)) ret false;
  566.       if(!f.read!ushort?(link=)) ret false;
  567.       if(!f.read!uint?(ofs=)) ret false;
  568.       if(!f.read!uint?(siz=)) ret false;
  569.       idx.new(1);
  570.       branch{
  571.       cond siz == 0x0:
  572.         pal = `palList.get((index)link);
  573.         idx<> = (index)link;
  574.       else:
  575.         f.seek((long)(lofs+ofs), .file.Seek::SET);
  576.         pal.new(256);
  577.         loop{
  578.           index i = 0, l = (index)siz / 4;
  579.           ubyte r, g, b, dummy8;
  580.         do:
  581.           if(!f.read!ubyte?(r=)) ret false;
  582.           if(!f.read!ubyte?(g=)) ret false;
  583.           if(!f.read!ubyte?(b=)) ret false;
  584.           if(!f.read!ubyte?(dummy8=)) ret false;
  585.           pal[i] = (uint)r<<0d16 | (uint)g<<0d8 | (uint)b;
  586.           i++;
  587.         while i < l:
  588.         }
  589.         idx<> = i;
  590.       }
  591.       `palList.setSource(i, pal);
  592.       `palList.palTable.set((uint)group<<0d16 | item, idx);
  593.       i++;
  594.     while i < (index)`head.numberOfPalettes:
  595.     }
  596.     uint shofs = `head.firstSpriteHeaderOffset, size;
  597.     loop{
  598.       index i = 0;
  599.       uint misc;
  600.       ^&.Sprite spriteList;
  601.       spriteList.new((index)`head.numberOfSprites);
  602.       ushort indexOfPrevious;
  603.       index prev = -1;
  604.       while;
  605.     do:
  606.       f.seek((long)shofs, .file.Seek::SET);
  607.       switch(`head.ver0){
  608.       case 0d1:
  609.         if(!f.read!uint?(misc=)) ret false;
  610.         if(!f.read!uint?(size=)) ret false;
  611.         if(!spriteList[i].readHeader(f=)) ret false;
  612.         if(!f.read!ushort?(indexOfPrevious=)) ret false;
  613.       case 0d2:
  614.         if(
  615.           !spriteList[i].readHeaderV2(
  616.             f=, misc=, size=, lofs, tofs, indexOfPrevious=)) ret false;
  617.       }
  618.       branch{
  619.         bool ps;
  620.       cond size != 0d0:
  621.         switch(`head.ver0){
  622.         case 0d1:
  623.           if(
  624.             !spriteList[i].read(
  625.               f=, `head=, (long)(shofs + 0d32),
  626.               size, misc, spriteList[prev..prev+1], ps=, `palList=,
  627.               chr && spriteList[i].imageGroup == 0
  628.               && spriteList[i].imageNumber == 0)) ret false;
  629.         case 0d2:
  630.           if(!spriteList[i].readV2(f=, (long)misc, size)) ret false;
  631.         }
  632.         prev = i;
  633.       else:
  634.         spriteList[i].shareCopy(spriteList[(index)indexOfPrevious]=);
  635.         spriteList[i].link = (index)indexOfPrevious;
  636.       }
  637.       `spriteTable.operate(
  638.         (uint)spriteList[i].imageGroup
  639.         | (uint)spriteList[i].imageNumber<<0d16,
  640.         [void(^&.Sprite s=){if(#s == 0) s = spriteList[i..i+1];}]);
  641.       shofs = `head.ver0 == 0d1 ? misc : shofs + 0d28;
  642.       i++;
  643.     while i < (index)`head.numberOfSprites:
  644.     }
  645.     ret true;
  646.   }
  647.   public ^&.Sprite getSprite(short group, short number)
  648.   {
  649.     ret `spriteTable.get((uint)group | (uint)number<<0d16);
  650.   }
  651.   public ^&.Sprite getOwnPalSprite(short group, short number)
  652.   {
  653.     ^&.Sprite sp = `spriteTable.get((uint)group | (uint)number<<0d16);
  654.     if(#sp == 0) ret sp;
  655.     ^&.Sprite ops.new(1);
  656.     ops~copy(sp<>=);
  657.     ops~colorPallet = .s.clone!uint?(sp~getPal(`palList=));
  658.     ret ops;
  659.   }
  660. }
  661.  
  662. public &Anim<frame_t>
  663. {
  664.   public ^&.Sff sff;
  665.   public ^&.Sprite spr;
  666.   public %frame_t frames;
  667.   public &.sdl.Rect tile;
  668.   public index loopstart = 0, current = 0, drawidx = 0;
  669.   public int nrepeat = -1;
  670.   public int time = 0;
  671.   public int repeatcnt = 0;
  672.   public int mask = -1;
  673.   public short salpha = -1, dalpha = 0;
  674.   public byte h = 1, v = 1;
  675.   public bool newframe = true, loopend = false;
  676.   new()
  677.   {
  678.     `tile.set(0, 0, 0d0, 0d0);
  679.   }
  680.   public void reset()
  681.   {
  682.     `current = 0;
  683.     `drawidx = 0;
  684.     `time = 0;
  685.     `repeatcnt = 0;
  686.     `newframe = true;
  687.     `loopend = false;
  688.   }
  689.   public void copy(`self a=)
  690.   {
  691.     `sff = a.sff;
  692.     `spr = a.spr;
  693.     `frames = a.frames;
  694.     `tile = a.tile;
  695.     `loopstart = a.loopstart;
  696.     `current = a.current;
  697.     `drawidx = a.drawidx;
  698.     `nrepeat = a.nrepeat;
  699.     `time = a.time;
  700.     `repeatcnt = a.repeatcnt;
  701.     `mask = a.mask;
  702.     `salpha = a.salpha;
  703.     `dalpha = a.dalpha;
  704.     `h = a.h;
  705.     `v = a.v;
  706.     `newframe = a.newframe;
  707.     `loopend = a.loopend;
  708.   }
  709.   public void setFrames(%`frame_t f, index l, int r)
  710.   {
  711.     `frames = f;
  712.     `loopstart = l;
  713.     `nrepeat = r;
  714.   }
  715.   public ^frame_t currentFrame()
  716.   {
  717.     ret `frames[`current..`current+1];
  718.   }
  719.   public int animTime()
  720.   {
  721.     if(#`frames == 0) ret 0;
  722.     if(`loopend && `time == 0) loop{
  723.       index i = `loopstart;
  724.     do:
  725.       if(i == `current) ret 0;
  726.       if(`frames[i].time != 0) break;
  727.       i++;
  728.     while i < #`frames:
  729.     }
  730.     int at = `time;
  731.     branch{
  732.     cond `frames[-1].time < 0:
  733.       at++;
  734.       loop{index j = 0; while; do:
  735.         at += `frames[j].time;
  736.         j++;
  737.       while j < `current:
  738.       }
  739.     else:
  740.       loop{
  741.         index i = `current;
  742.         if(`frames[i].time == 0) at--;
  743.         while;
  744.       do:
  745.         at -= `frames[i].time;
  746.         i++;
  747.       while i < #`frames:
  748.       }
  749.     }
  750.     ret at;
  751.   }
  752.   public int animElemTime(int elem)
  753.   {
  754.     int t;
  755.     if(elem > #`frames){
  756.       t = `animTime();
  757.       ret t > 0 ? 0 : t;
  758.     }
  759.     int e = elem - 1;
  760.     if(`loopend && `time == 0 && `current == `loopstart){
  761.       t = 0;
  762.       loop{index i = e; while; do:
  763.         t += `frames[i].time;
  764.         i++;
  765.       while i < #`frames && `frames[i].time >= 0:
  766.       }
  767.       ret t;
  768.     }
  769.     t = `time;
  770.     loop{index i = e; while; do:
  771.       t += `frames[i].time;
  772.       i++;
  773.     while i < `current && `frames[i].time >= 0:
  774.     }
  775.     loop{index i = `current; while; do:
  776.       t -= `frames[i].time;
  777.       i++;
  778.     while i < e && `frames[i].time >= 0:
  779.     }
  780.     ret t;
  781.   }
  782.   public int animElemNo(int time)
  783.   {
  784.     if(time == 0 && `loopend && `time == 0 && `current == `loopstart){
  785.       ret #`frames;
  786.     }
  787.     branch{
  788.       int t = time, oldt = 0;
  789.     cond t < 0:
  790.       loop{
  791.         index i = `current;
  792.         t += `time;
  793.         bool lp = false;
  794.         continue;
  795.       do:
  796.         t += `frames[i].time;
  797.       continue:
  798.         if(lp && `frames[i].time < 0){
  799.           ret i + 1;
  800.         }
  801.         if(t >= 0){
  802.           if(t == 0 && `loopend && i == `loopstart) ret #`frames;
  803.           ret i + 1;
  804.         }
  805.         i--;
  806.       while i >= 0 && (`current < `loopstart || i >= `loopstart):
  807.         if(t == oldt) break;
  808.         oldt = t;
  809.         lp = true;
  810.         i = #`frames - 1;
  811.         do;
  812.       }
  813.     else:
  814.       loop{
  815.         index i = `current;
  816.         t -= `frames[i].time - `time;
  817.         continue;
  818.       do:
  819.         t -= `frames[i].time;
  820.       continue:
  821.         if(t <= 0 || `frames[i].time < 0){
  822.           if(t == 0 && `loopend && i == `loopstart) ret #`frames;
  823.           ret i + 1;
  824.         }
  825.         i++;
  826.         if(i >= #`frames){
  827.           if(t == oldt) break, break;
  828.           oldt = t;
  829.           i = `loopstart;
  830.         }
  831.       while true:
  832.       }
  833.     }
  834.     ret 1;
  835.   }
  836.   public void setAnimElem(int e)
  837.   {
  838.     `current = .m.max!index?(0, e-1);
  839.     if(`current  >= #`frames){
  840.       `current = `loopstart + `current % (#`frames-`loopstart);
  841.     }
  842.     `drawidx = `current;
  843.     `time = 0;
  844.     `newframe = true;
  845.     `updateSprite();
  846.     `loopend = false;
  847.   }
  848.   public void updateSprite()
  849.   {
  850.     if(#`frames == 0) ret;
  851.     if(`newframe){
  852.       `spr = `sff~getSprite(`frames[`current].group, `frames[`current].number);
  853.     }
  854.     `newframe = false;
  855.     `drawidx = `current;
  856.   }
  857.   public void action()
  858.   {
  859.     if(#`frames == 0) ret;
  860.     `updateSprite();
  861.     `frames[`current].action(`=);
  862.   }
  863.   int alphaFoo()
  864.   {
  865.     ubyte sa, da;
  866.     branch{
  867.     cond `salpha >= 0:
  868.       sa = (ubyte)`salpha;
  869.       da = (ubyte)`dalpha;
  870.     else:
  871.       sa = `frames[`drawidx].salpha;
  872.       da = `frames[`drawidx].dalpha;
  873.     }
  874.     branch{
  875.     cond sa == 0d1 && da == 0d255:
  876.       ret -2;
  877.     else:
  878.       sa = (ubyte)((int)sa * .com.brightness >> 8);
  879.       branch{
  880.       cond sa < 0d5 && da == 0d255:
  881.         ret 0;
  882.       cond sa == 0d255 && da == 0d255:
  883.         ret -1;
  884.       }
  885.     }
  886.     int alpha = (int)sa;
  887.     if((uint)sa+da < 0d254 || 0d256 < (uint)sa+da){
  888.       alpha |= (int)da << 10 | 1 << 9;
  889.     }
  890.     ret alpha;
  891.   }
  892.   ^uint palFoo(^&.com.PalFX fx)
  893.   {
  894.     if(#fx == 0 || fx~time == 0) ret `spr~getPal(`sff~palList=);
  895.     ret fx~getFxPal(`spr~getPal(`sff~palList=), `alphaFoo() == -2);
  896.   }
  897.   public void draw(
  898.     &.sdl.Rect rect=, float x, float y, float cscalex, float cscaley,
  899.     float xtscale, float xbscale, float yscale, float rasterxadd,
  900.     float rx, ^&.com.PalFX fx)
  901.   {
  902.     if(#`spr == 0 || #`spr~pxl == 0) ret;
  903.     int h = `h*`frames[`drawidx].h, v = `v*`frames[`drawidx].v;
  904.     float xs = (float)h*cscalex*xtscale, ys = (float)v*cscaley*yscale;
  905.     float bs = xbscale;
  906.     .m.limRange!float?(xs=, -16000.0/.com.WidthScale, 16000.0/.com.WidthScale);
  907.     .m.limRange!float?(
  908.       ys=, -16000.0/.com.HeightScale, 16000.0/.com.HeightScale);
  909.     .m.limRange!float?(bs=, -16000.0/.com.WidthScale, 16000.0/.com.WidthScale);
  910.     float x2 =
  911.       cscalex*x - xs*(float)(`spr~rct.x - `frames[`drawidx].x) + rx;
  912.     float y2 = cscaley*y - ys*(float)(`spr~rct.y - `frames[`drawidx].y);
  913.     if(xs < 0.0){
  914.       x2 *= -1.0;
  915.       x2 += rx*2.0;
  916.       if(rx != 0.0) x2 += xs;
  917.     }
  918.     if(ys < 0.0){
  919.       y2 *= -1.0;
  920.       y2 += 240.0;
  921.       if(rx != 0.0) y2 += ys;
  922.     }
  923.     if(`tile.w == 0x1){
  924.       float tmp =
  925.         xs * ((float)`tile.x + (`tile.x > 0 ? 0.0 : (float)`spr~rct.w));
  926.       x2 -= (float)(int)(x2 / tmp) * tmp;
  927.     }
  928.     if(`tile.h == 0x1){
  929.       float tmp =
  930.         ys * ((float)`tile.y + (`tile.y > 0 ? 0.0 : (float)`spr~rct.h));
  931.       y2 -= (float)(int)(y2 / tmp) * tmp;
  932.     }
  933.     .sdl.screen.renderMugenZoom(
  934.       rect=, rx*.com.WidthScale, 0.0, `spr~pxl, `palFoo(fx), `mask, `spr~rct=,
  935.       (rx-x2)*.com.WidthScale, -y2*.com.HeightScale,
  936.       `tile=, xs*.com.WidthScale,
  937.       cscalex*bs*(float)h*.com.WidthScale, ys*.com.HeightScale,
  938.       cscalex*rasterxadd*(.com.WidthScale/.com.HeightScale),
  939.       0x0, `alphaFoo(), `spr~rle, `spr~pluginbuf=);
  940.   }
  941.   public void angleDraw(
  942.     float x, float y, float xscale, float yscale,
  943.     float angle, bool angleset, float axscl, float ayscl, ^&.com.PalFX fx)
  944.   {
  945.     if(#`spr == 0 || #`spr~pxl == 0) ret;
  946.     float rx = x + 160.0;
  947.     int h = `h*`frames[`drawidx].h;
  948.     int v = `v*`frames[`drawidx].v;
  949.     float xs = xscale * axscl, ys = yscale * ayscl;
  950.     float agl =
  951.       angle*(float)(`h * `v * (xs < 0.0 ? -1: 1) * (ys < 0.0 ? -1: 1));
  952.     uint uagl = (uint)((512.0/.m.PI)*agl + 0.5) & 0x3ff;
  953.     if(uagl == 0x0) branch{
  954.     cond angleset:
  955.       `draw(
  956.         .com.scrrect=, x+160.0 - xs*(float)(h*`frames[`drawidx].x), y,
  957.         1.0, 1.0, xs, xs, ys, 0.0, 0.0, fx);
  958.     else:
  959.       `draw(
  960.         .com.scrrect=,
  961.         x - (float)h*xscale*(axscl - 1.0)*(float)`frames[`drawidx].x, y,
  962.         1.0, 1.0, xs, xs, ys, 0.0, 160.0, fx);
  963.     comm:
  964.       ret;
  965.     }
  966.     .sdl.screen.renderMugenZoom(
  967.       .com.scrrect=, rx*.com.WidthScale,
  968.       (y+ys*(float)(v*`frames[`drawidx].y))*.com.HeightScale,
  969.       `spr~pxl, `palFoo(fx), `mask, `spr~rct=,
  970.       #xs*(float)`spr~rct.x*.com.WidthScale,
  971.       #ys*(float)`spr~rct.y*.com.HeightScale,
  972.       `tile=, xs*(float)h*.com.WidthScale,
  973.       xs*(float)h*.com.WidthScale, ys*(float)v*.com.HeightScale,
  974.       0.0, uagl, `alphaFoo(), `spr~rle, `spr~pluginbuf=);
  975.   }
  976.   public void setup(^&.Sff sff)
  977.   {
  978.     `sff = sff;
  979.   }
  980. }