home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 February / chip_20022115.iso / amiga / chipgame / scummvm_aga.lha / ScummVM_AGA / src / string.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2002-01-05  |  16.5 KB  |  807 lines

  1. /* ScummVM - Scumm Interpreter
  2.  * Copyright (C) 2001  Ludvig Strigeus
  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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  17.  *
  18.  * $Header: /cvsroot/scummvm/scummvm/string.cpp,v 1.9 2001/11/09 18:54:15 strigeus Exp $
  19.  *
  20.  */
  21.  
  22. #include "stdafx.h"
  23. #include "scumm.h"
  24.  
  25. int CharsetRenderer::getStringWidth(int arg, byte *text, int pos) {
  26.     byte *ptr;
  27.     int width,offs,w;
  28.     byte chr;
  29.  
  30.     width = 1;
  31.     ptr = _vm->getResourceAddress(rtCharset, _curId) + 29;
  32.  
  33.     while ( (chr = text[pos++]) != 0) {
  34.         if (chr==0xD)
  35.             break;
  36.         if (chr=='@')
  37.             continue;
  38.         if (chr==254) chr=255;
  39.         if (chr==255) {
  40.             chr=text[pos++];
  41.             if (chr==3)
  42.                 break;
  43.             if (chr==8) {
  44.                 if (arg==1)
  45.                     break;
  46.                 while (text[pos]==' ')
  47.                     text[pos++] = '@';
  48.                 continue;
  49.             }
  50.             if (chr==10 || chr==21 || chr==12 || chr==13) {
  51.                 pos += 2;
  52.                 continue;
  53.             }
  54.             if (chr==9 || chr==1 || chr==2)
  55.                 break;
  56.             if (chr==14) {
  57.                 int set = text[pos] | (text[pos+1]<<8);
  58.                 pos+=2;
  59.                 ptr = _vm->getResourceAddress(rtCharset, set) + 29;
  60.                 continue;
  61.             }
  62.         }
  63.  
  64.         offs = READ_LE_UINT32(ptr + chr*4 + 4);
  65.         if (offs) {
  66.             if (ptr[offs+2]>=0x80) {
  67.                 w = ptr[offs+2] - 0x100;
  68.             } else {
  69.                 w = ptr[offs+2];
  70.             }
  71.             width += ptr[offs] + w;
  72.         }
  73.     }
  74.     return width;
  75. }
  76.  
  77. void CharsetRenderer::addLinebreaks(int a, byte *str, int pos, int maxwidth) {
  78.     int lastspace = -1;
  79.     int curw = 1;
  80.     int offs,w;
  81.     byte *ptr;
  82.     byte chr;
  83.  
  84.     ptr = _vm->getResourceAddress(rtCharset, _curId) + 29;
  85.  
  86.     while ( (chr=str[pos++]) != 0) {
  87.         if (chr=='@')
  88.             continue;
  89.         if (chr==254) chr=255;
  90.         if (chr==255) {
  91.             chr = str[pos++];
  92.             if (chr==3)
  93.                 break;
  94.             if (chr==8) {
  95.                 if (a==1) {
  96.                     curw = 1;
  97.                 } else {
  98.                     while (str[pos]==' ')
  99.                         str[pos++] = '@';
  100.                 }
  101.                 continue;
  102.             }
  103.             if (chr==10 || chr==21 || chr==12 || chr==13) {
  104.                 pos += 2;
  105.                 continue;
  106.             }
  107.             if (chr==1) {
  108.                 curw = 1;
  109.                 continue;
  110.             }
  111.             if (chr==2)
  112.                 break;
  113.             if (chr==14) {
  114.                 int set = str[pos] | (str[pos+1]<<8);
  115.                 pos+=2;
  116.                 ptr = _vm->getResourceAddress(rtCharset, set) + 29;
  117.                 continue;
  118.             }
  119.         }
  120.  
  121.         if (chr==' ')
  122.             lastspace = pos - 1;
  123.  
  124.         offs = READ_LE_UINT32(ptr + chr*4 + 4);
  125.         if (offs) {
  126.             if (ptr[offs+2]>=0x80) {
  127.                 w = ptr[offs+2] - 0x100;
  128.             } else {
  129.                 w = ptr[offs+2];
  130.             }
  131.             curw += w + ptr[offs];
  132.         }
  133.         if (lastspace==-1)
  134.                 continue;
  135.         if (curw > maxwidth) {
  136.             str[lastspace] = 0xD;
  137.             curw = 1;
  138.             pos = lastspace + 1;
  139.             lastspace = -1;
  140.         }
  141.     }
  142. }
  143.  
  144. void Scumm::unkMessage1() {
  145.     byte buffer[100];
  146.     _msgPtrToAdd = buffer;
  147.     _messagePtr = addMessageToStack(_messagePtr);
  148.  
  149.     if (buffer[0] == 0xFF && buffer[1]==10) {
  150.         uint32 a,b;
  151.  
  152.         a = buffer[2] | (buffer[3]<<8) | (buffer[6]<<16) | (buffer[7]<<24);
  153.         b = buffer[10] | (buffer[11]<<8) | (buffer[14]<<16) | (buffer[15]<<24);
  154.         talkSound(a,b,1);
  155.     }
  156.  
  157. //    warning("unkMessage1(\"%s\")", buf);
  158. }
  159.  
  160. void Scumm::unkMessage2() {
  161.     byte buf[100], *tmp;
  162.  
  163.     _msgPtrToAdd = buf;
  164.     tmp = _messagePtr = addMessageToStack(_messagePtr);
  165.  
  166.     if (string[3].color==0)
  167.         string[3].color = 4;
  168.  
  169.     warning("unkMessage2(\"%s\")", buf);
  170.     _messagePtr = tmp;
  171. }
  172.  
  173.  
  174. void Scumm::CHARSET_1() {
  175.     int s, i, t, c;
  176.     int frme;
  177.     Actor *a;
  178.     byte *buffer;
  179.  
  180.     if (!_haveMsg || (camera._destPos>>3) != (camera._curPos>>3) ||
  181.             camera._curPos != camera._lastPos 
  182.         ) return;
  183.  
  184.     a = NULL;
  185.     if (_vars[VAR_TALK_ACTOR] != 0xFF)
  186.         a = derefActorSafe(_vars[VAR_TALK_ACTOR], "CHARSET_1");
  187.  
  188.     if (a && string[0].overhead!=0) {
  189.         if (_majorScummVersion==5) {
  190.             string[0].xpos = a->x - camera._curPos + 160;
  191.  
  192.             if (_vars[VAR_V5_TALK_STRING_Y] < 0) {
  193.                 s = (a->scaley * (int)_vars[VAR_V5_TALK_STRING_Y]) / 0xFF;
  194.                 string[0].ypos = ((_vars[VAR_V5_TALK_STRING_Y]-s)>>1) + s - a->elevation + a->y;
  195.             } else {
  196.                 string[0].ypos = _vars[VAR_V5_TALK_STRING_Y];
  197.             }
  198.             if (string[0].ypos < 1)
  199.                 string[0].ypos = 1;
  200.  
  201.             if (string[0].xpos < 80)
  202.                 string[0].xpos = 80;
  203.             if (string[0].xpos > 240)
  204.                 string[0].xpos = 240;
  205.         } else {
  206.             s = a->scaley * a->new_1 / 0xFF;
  207.             string[0].ypos = ((a->new_1 - s)>>1) + s - a->elevation + a->y;
  208.             if (string[0].ypos<1)
  209.                 string[0].ypos = 1;
  210.             
  211.             s = a->scalex * a->new_2 / 0xFF;
  212.             string[0].xpos = ((a->new_2 - s)>>1) + s + a->x - camera._curPos + 160;
  213.             if (string[0].xpos < 80)
  214.                 string[0].xpos = 80;
  215.             if (string[0].xpos > 240)
  216.                 string[0].xpos = 240;
  217.         }
  218.     }
  219.  
  220.     charset._top = string[0].ypos;
  221.     charset._left = string[0].xpos;
  222.     charset._left2 = string[0].xpos;
  223.     charset._curId = string[0].charset;
  224.  
  225.     if (a && a->charset)
  226.         charset._curId = a->charset;
  227.  
  228.     charset._center = string[0].center;
  229.     charset._right = string[0].right;
  230.     charset._color = _charsetColor;
  231.     _bkColor = 0;
  232.  
  233.     for (i=0; i<4; i++)
  234.         charset._colorMap[i] = _charsetData[charset._curId][i];
  235.     
  236.     if (_keepText) {
  237.         charset._strLeft = gdi._mask_left;
  238.         charset._strRight = gdi._mask_right;
  239.         charset._strTop = gdi._mask_top;
  240.         charset._strBottom = gdi._mask_bottom;
  241.     }
  242.  
  243.     if (!_haveMsg || _talkDelay)
  244.         return;
  245.     
  246.     if (_haveMsg!=0xFF) {
  247.         if (_sfxMode==0)
  248.             stopTalk();
  249.         return;
  250.     }
  251.  
  252.     if (a && !string[0].no_talk_anim) {
  253.         startAnimActor(a, a->talkFrame1, a->facing);
  254.         _useTalkAnims = true;
  255.     }
  256.  
  257.     _talkDelay = _defaultTalkDelay;
  258.  
  259.     if (!_keepText) {
  260.         restoreCharsetBg();
  261.         charset._xpos2 = string[0].xpos;
  262.         charset._ypos2 = string[0].ypos;
  263.     }
  264.     
  265.     t = charset._right - string[0].xpos - 1;
  266.     if (charset._center) {
  267.         if (t > charset._xpos2)
  268.             t = charset._xpos2;
  269.         t <<= 1;
  270.     }
  271.  
  272.     buffer = charset._buffer + charset._bufPos;
  273.     
  274.     charset.addLinebreaks(0, buffer,0, t);
  275.  
  276.     _lastXstart = virtscr[0].xstart;
  277.     if (charset._center) {
  278.         charset._xpos2 -= charset.getStringWidth(0, buffer,0) >> 1;
  279.     }
  280.  
  281.     charset._disableOffsX = charset._unk12 = !_keepText;
  282.  
  283.     do {
  284.         c = *buffer++;
  285.         if (c==0) {
  286.             _haveMsg = 1;
  287.             _keepText = false;
  288.             break;
  289.         }
  290.         if (c == 13) {
  291. newLine:;
  292.             charset._xpos2 = string[0].xpos;
  293.             if (charset._center) {
  294.                 charset._xpos2 -= charset.getStringWidth(0, buffer, 0)>>1;
  295.             }
  296.             charset._ypos2 += getResourceAddress(rtCharset,charset._curId)[30];
  297.             charset._disableOffsX = 1;
  298.             continue;
  299.         }
  300.  
  301.         if (c==0xFE) c=0xFF;
  302.  
  303.         if (c!=0xFF) {
  304.             charset._left = charset._xpos2;
  305.             charset._top = charset._ypos2;
  306.             
  307.             if (_majorScummVersion==5) {
  308.                 if (!_vars[VAR_V5_CHARFLAG]) {
  309.                     charset.printChar(c);
  310.                 }
  311.             } else {
  312.                 charset.printChar(c);
  313.             }
  314.  
  315.             charset._xpos2 = charset._left;
  316.             charset._ypos2 = charset._top;
  317.  
  318.             _talkDelay += _vars[VAR_CHARINC];
  319.             continue;
  320.         }
  321.  
  322.         c = *buffer++;
  323.         if (c==3) {
  324.             _haveMsg = 0xFF;
  325.             _keepText = false;
  326.             break;
  327.         } else if (c==1) { 
  328.             goto newLine;
  329.         } else if (c==2) {
  330.             _haveMsg = 0;
  331.             _keepText = true;
  332.             break;
  333.         } else if (c==9) {
  334.             frme = *buffer++;
  335.             frme |= *buffer++<<8;
  336.             if (a)
  337.                 startAnimActor(a, frme, a->facing);
  338.         } else if (c==10) {
  339.             uint32 a,b;
  340.  
  341.             a = buffer[0] | (buffer[1]<<8) | (buffer[4]<<16) | (buffer[5]<<24);
  342.             b = buffer[8] | (buffer[9]<<8) | (buffer[12]<<16) | (buffer[13]<<24);
  343.             talkSound(a,b,2);
  344.             buffer += 14;
  345.         } else if (c==14) {
  346.             int oldy = getResourceAddress(rtCharset,charset._curId)[30];
  347.  
  348.             charset._curId = *buffer++;
  349.             buffer += 2;
  350.             for (i=0; i<4; i++)
  351.                 charset._colorMap[i] = _charsetData[charset._curId][i];
  352.             charset._ypos2 -= getResourceAddress(rtCharset,charset._curId)[30] - oldy;
  353.         } else if (c==12) {
  354.             int color;
  355.             color = *buffer++;
  356.             color |= *buffer++<<8;
  357.             if (color==0xFF)
  358.                 charset._color = _charsetColor;
  359.             else
  360.                 charset._color = color;
  361.         } else if (c==13) {
  362.             buffer += 2;
  363.         } else {
  364.             warning("CHARSET_1: invalid code %d", c);
  365.         }
  366.     } while (1);
  367.  
  368.     charset._bufPos = buffer - charset._buffer;
  369.  
  370.     gdi._mask_left = charset._strLeft;
  371.     gdi._mask_right = charset._strRight;
  372.     gdi._mask_top = charset._strTop;
  373.     gdi._mask_bottom = charset._strBottom;
  374. }
  375.  
  376. void Scumm::drawString(int a) {
  377.     byte buf[256];
  378.     byte *charsetptr,*space;
  379.     int i;
  380.     byte byte1, chr;
  381.     uint color;
  382.     
  383.     _msgPtrToAdd = buf;
  384.     _messagePtr = addMessageToStack(_messagePtr);
  385.  
  386.     charset._left2 = charset._left = string[a].xpos;
  387.     charset._top = string[a].ypos;
  388.     charset._curId = string[a].charset;
  389.     charset._center = string[a].center;
  390.     charset._right = string[a].right;
  391.     charset._color = string[a].color;
  392.     _bkColor = 0;
  393.     charset._unk12 = 1;
  394.     charset._disableOffsX = 1;
  395.  
  396.     charsetptr = getResourceAddress(rtCharset, charset._curId);
  397.     assert(charsetptr);
  398.     charsetptr += 29;
  399.  
  400.     for(i=0; i<4; i++)
  401.         charset._colorMap[i] = _charsetData[charset._curId][i];
  402.  
  403.     byte1 = charsetptr[1];
  404.     
  405.     _msgPtrToAdd = buf;
  406.  
  407.     /* trim from the right */
  408.     space = NULL;
  409.     while (*_msgPtrToAdd){
  410.         if (*_msgPtrToAdd==' ') {
  411.             if (!space) space = _msgPtrToAdd;
  412.         } else {
  413.             space = NULL;
  414.         }
  415.         _msgPtrToAdd++;
  416.     }
  417.     if(space) *space='\0';
  418.  
  419.     if (charset._center) {
  420.         charset._left -= charset.getStringWidth(a, buf, 0) >> 1;
  421.     }
  422.  
  423.     charset._ignoreCharsetMask = 1;
  424.  
  425.     if (!buf[0]) {
  426.         buf[0] = ' ';
  427.         buf[1] = 0;
  428.     }
  429.  
  430.     for (i=0; (chr=buf[i++]) != 0; ) {
  431.         if (chr==254) chr=255;
  432.         if (chr==255) {
  433.             chr = buf[i++];
  434.             switch(chr) {
  435.             case 9:
  436.             case 10: case 13: case 14:
  437.                 i += 2;
  438.                 break;
  439.             case 1: case 8:
  440.                 if (charset._center) {
  441.                     charset._left = charset._left2 - charset.getStringWidth(a, buf, i);
  442.                 } else {
  443.                     charset._left = charset._left2;
  444.                 }
  445.                 charset._top += byte1;
  446.                 break;
  447.             case 12:
  448.                 color = buf[i] + (buf[i+1]<<8);
  449.                 i+=2;
  450.                 if (color==0xFF)
  451.                     charset._color = string[a].color;
  452.                 else
  453.                     charset._color = color;
  454.                 break;
  455.             }
  456.         } else {
  457.             if (a==1 && _majorScummVersion==6)
  458.                 charset._blitAlso = true;
  459.             charset.printChar(chr);
  460.             charset._blitAlso = false;
  461.         }
  462.     }
  463.  
  464.     charset._ignoreCharsetMask = 0;
  465.     
  466.     if (a==0) {
  467.         charset._xpos2 = charset._left;
  468.         charset._ypos2 = charset._top;
  469.     }
  470. }
  471.  
  472. byte *Scumm::addMessageToStack(byte *msg) {
  473.     int num, numorg;
  474.     byte *ptr, chr;
  475.  
  476.     numorg = num = _numInMsgStack;
  477.     ptr = getResourceAddress(rtTemp, 6);
  478.  
  479.     if (ptr==NULL)
  480.         error("Message stack not allocated");
  481.  
  482.     while ( (chr=*msg++) != 0) {
  483.         if (num > 500)
  484.             error("Message stack overflow");
  485.  
  486.         ptr[num++] = chr;
  487.         
  488.         if (chr==255) {
  489.             ptr[num++] = chr = *msg++;
  490.  
  491.             if (chr!=1 && chr!=2 && chr!=3 && chr!=8) {
  492.                 ptr[num++] = chr = *msg++;
  493.                 ptr[num++] = chr = *msg++;
  494.             }
  495.         }
  496.     }
  497.     ptr[num++] = 0;
  498.     
  499.     _numInMsgStack = num;
  500.     num = numorg;
  501.  
  502.     while (1) {
  503.         ptr = getResourceAddress(rtTemp, 6);
  504.         chr = ptr[num++];
  505.         if (chr == 0) 
  506.             break;
  507.         if (chr == 0xFF) {
  508.             chr = ptr[num++];
  509.             switch(chr) {
  510.             case 4:
  511.                 unkAddMsgToStack2(READ_LE_UINT16(ptr + num));
  512.                 num+=2;
  513.                 break;
  514.             case 5:
  515.                 unkAddMsgToStack3(READ_LE_UINT16(ptr + num));
  516.                 num+=2;
  517.                 break;
  518.             case 6:
  519.                 unkAddMsgToStack4(READ_LE_UINT16(ptr + num));
  520.                 num+=2;
  521.                 break;
  522.             case 7:
  523.                 unkAddMsgToStack5(READ_LE_UINT16(ptr + num));
  524.                 num+=2;
  525.                 break;
  526.             case 9: 
  527. //#if defined(DOTT)
  528.             case 10: case 12: case 13: case 14:
  529. //#endif
  530.                 *_msgPtrToAdd++ = 0xFF;
  531.                 *_msgPtrToAdd++ = chr;
  532.                 *_msgPtrToAdd++ = ptr[num++];
  533.                 *_msgPtrToAdd++ = ptr[num++];
  534.                 break;
  535.             default:
  536.                 *_msgPtrToAdd++ = 0xFF;
  537.                 *_msgPtrToAdd++ = chr;
  538.             }
  539.         } else {
  540.             if (chr!='@') {
  541.                 *_msgPtrToAdd++ = chr;
  542.             }
  543.         }
  544.     }
  545.     *_msgPtrToAdd = 0;
  546.     _numInMsgStack = numorg;
  547.     
  548.     return msg;
  549. }
  550.  
  551. void Scumm::unkAddMsgToStack2(int var) {
  552.     int num,max;    
  553.     byte flag;
  554.     
  555.     num = readVar(var);
  556.     if (num < 0) {
  557.         *_msgPtrToAdd++ = '-';
  558.         num = -num;
  559.     }
  560.  
  561.     flag = 0;
  562.     max = 10000;
  563.     do {
  564.         if (num>=max || flag) {
  565.             *_msgPtrToAdd++ = num/max + '0';
  566.             num -= (num/max)*max;
  567.             flag=1;
  568.         }
  569.         max/=10;
  570.         if (max==1) flag=1;
  571.     } while (max);
  572. }
  573.  
  574. void Scumm::unkAddMsgToStack3(int var) {
  575.     int num,i;
  576.     
  577.     num = readVar(var);
  578.     if (num) {
  579.         for (i=1; i<_maxVerbs; i++) {
  580.             if (num==_verbs[i].verbid && !_verbs[i].type && !_verbs[i].saveid) {
  581.                 addMessageToStack(getResourceAddress(rtVerb, i));
  582.                 break;
  583.             }
  584.         }
  585.     } else {
  586.         addMessageToStack((byte*)"");
  587.     }
  588. }
  589.  
  590. void Scumm::unkAddMsgToStack4(int var) {
  591.     int num;
  592.  
  593.     num = readVar(var);
  594.     if (num) {
  595.         addMessageToStack(getObjOrActorName(num));    
  596.     } else {
  597.         addMessageToStack((byte*)"");
  598.     }
  599. }
  600.  
  601. void Scumm::unkAddMsgToStack5(int var) {
  602.     byte *ptr;
  603.  
  604.     if (_majorScummVersion==6)
  605.         var = readVar(var);
  606.     
  607.     if (var) {
  608.         ptr = getStringAddress(var);
  609.         if (ptr) {
  610.             addMessageToStack(ptr);
  611.             return;
  612.         }
  613.     }
  614.     addMessageToStack((byte*)"");
  615. }
  616.  
  617. void Scumm::initCharset(int charsetno) {
  618.     int i;
  619.  
  620.     if (!getResourceAddress(rtCharset, charsetno))
  621.         loadCharset(charsetno);
  622.  
  623.     string[0].t_charset = charsetno;
  624.     string[1].t_charset = charsetno;
  625.  
  626.     for (i=0; i<0x10; i++)
  627.         charset._colorMap[i] = _charsetData[charsetno][i];
  628. }
  629.  
  630. void CharsetRenderer::printChar(int chr) {
  631.     int d,right;
  632.     VirtScreen *vs;
  633.     
  634.     _vm->checkRange(_vm->_maxCharsets-1, 1, _curId, "Printing with bad charset %d");
  635.     if ((vs=_vm->findVirtScreen(_top)) == NULL)
  636.         return;
  637.  
  638.     if (chr=='@')
  639.         return;
  640.  
  641.     _ptr = _vm->getResourceAddress(rtCharset, _curId) + 29;
  642.  
  643.     _bpp = _unk2 = *_ptr;
  644.     _invNumBits = 8 - _bpp;
  645.     _bitMask = 0xFF << _invNumBits;
  646.     _colorMap[1] = _color;
  647.  
  648.     _charOffs = READ_LE_UINT32(_ptr + chr*4 + 4);
  649.  
  650.     if (!_charOffs)
  651.         return;
  652.  
  653.     assert(_charOffs < 0x10000);
  654.  
  655.     _charPtr = _ptr + _charOffs;
  656.  
  657.     _width = _charPtr[0];
  658.     _height = _charPtr[1];
  659.     if (_unk12) {
  660.         _strLeft = 0;
  661.         _strTop = 0;
  662.         _strRight = 0;
  663.         _strBottom = 0;
  664.     }
  665.  
  666.     if (_disableOffsX) {
  667.         _offsX = 0;
  668.     } else {
  669.         d = _charPtr[2];
  670.         if (d>=0x80)
  671.             d -= 0x100;
  672.         _offsX = d;
  673.     }
  674.  
  675.     d = _charPtr[3];
  676.     if(d>=0x80)
  677.         d -= 0x100;
  678.     _offsY = d;
  679.  
  680.     _top += _offsY;
  681.     _left += _offsX;
  682.  
  683.     right = _left + _width;
  684.  
  685.     if (right>_right+1 || _left < 0) {
  686.         _left = right;
  687.         _top -= _offsY;
  688.         return;
  689.     }
  690.  
  691.     _disableOffsX = 0;
  692.  
  693.     if (_unk12) {
  694.         _strLeft = _left;
  695.         _strTop = _top;
  696.         _strRight = _left;
  697.         _strBottom = _top;
  698.         _unk12 = 0;
  699.     }
  700.  
  701.     if (_left < _strLeft)
  702.         _strLeft = _left;
  703.  
  704.     if (_top < _strTop)
  705.         _strTop = _top;
  706.  
  707.     _drawTop = _top - vs->topline;
  708.     if (_drawTop<0) _drawTop = 0;
  709.  
  710.     _bottom = _drawTop + _height + _offsY;
  711.  
  712.     _vm->updateDirtyRect(vs->number, _left, right, _drawTop, _bottom, 0);
  713.  
  714. #if defined(OLD)
  715.     if (vs->number==0)
  716.         _hasMask = true;
  717. #else
  718.     if (vs->number!=0)
  719.         _blitAlso = false;
  720.     if (vs->number==0 && _blitAlso==0)
  721.         _hasMask = true;
  722. #endif
  723.  
  724.     _bg_ptr2 = _backbuff_ptr = _vm->getResourceAddress(rtBuffer, vs->number+1) 
  725.         + vs->xstart + _drawTop * 320 + _left;
  726.  
  727. #if !defined(OLD)
  728.     if (_blitAlso) {
  729. #else
  730.     if (1) {
  731. #endif
  732.         _bg_ptr2 = _bgbak_ptr = _vm->getResourceAddress(rtBuffer, vs->number+5)
  733.             + vs->xstart + _drawTop * 320 + _left;
  734.     }
  735.  
  736.     _mask_ptr = _vm->getResourceAddress(rtBuffer, 9)
  737.         + _drawTop * 40 + _left/8 
  738.         + _vm->_screenStartStrip;
  739.  
  740.     _revBitMask = revBitMask[_left&7];
  741.  
  742.     _virtScreenHeight = vs->height;
  743.     _charPtr += 4;
  744.  
  745.     drawBits();
  746.  
  747. #if !defined(OLD)
  748.     if (_blitAlso)
  749.         blit(_backbuff_ptr, _bgbak_ptr, _width, _height);
  750. #endif
  751.  
  752.     _left += _width;
  753.     if (_left  > _strRight)
  754.         _strRight = _left;
  755.  
  756.     if (_top + _height > _strBottom)
  757.         _strBottom = _top + _height;
  758.  
  759.     _top -= _offsY;
  760. }
  761.  
  762. void CharsetRenderer::drawBits() {
  763.     bool usemask;
  764.     byte *dst, *mask,maskmask;
  765.     int y,x;
  766.     int maskpos;
  767.     int color;
  768.     byte numbits,bits;
  769.  
  770.     usemask = (_vm->_curVirtScreen->number==0 && _ignoreCharsetMask==0);
  771.  
  772.     bits = *_charPtr++;
  773.     numbits = 8;
  774.  
  775.     dst = _bg_ptr2;
  776.     mask = _mask_ptr;
  777.     y = 0;
  778.  
  779.     for(y=0; y<_height && y+_drawTop < _virtScreenHeight;) {
  780.         maskmask = _revBitMask;
  781.         maskpos = 0;
  782.  
  783.         for (x=0; x<_width; x++) {
  784.             color = (bits&_bitMask)>>_invNumBits;
  785.             if (color) {
  786.                 if (usemask) {
  787.                     mask[maskpos] |= maskmask;
  788.                 }
  789.                 *dst = _colorMap[color];
  790.             }
  791.             dst++;
  792.             bits <<= _bpp;
  793.             if ((numbits -= _bpp)==0) {
  794.                 bits = *_charPtr++;
  795.                 numbits = 8;
  796.             }
  797.             if ((maskmask>>=1)==0) {
  798.                 maskmask = 0x80;
  799.                 maskpos++;
  800.             }
  801.         }
  802.         dst = (_bg_ptr2 += 320);
  803.         mask += 40;
  804.         y++;
  805.     }
  806. }
  807.