home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 February / chip_20022115.iso / amiga / chipgame / scummvm_aga.lha / ScummVM_AGA / src / actor.cpp next >
Encoding:
C/C++ Source or Header  |  2002-01-05  |  19.3 KB  |  976 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/actor.cpp,v 1.10 2001/11/07 18:10:52 strigeus Exp $
  19.  *
  20.  */
  21.  
  22. #include "stdafx.h"
  23. #include "scumm.h"
  24.  
  25. void Scumm::initActor(Actor *a, int mode) {
  26.     if (mode==1) {
  27.         a->costume = 0;
  28.         a->room = 0;
  29.         a->x = 0;
  30.         a->y = 0;
  31.         a->facing = 2;
  32.     } else if (mode==2) {
  33.         a->facing = 2;
  34.     }
  35.  
  36.     a->elevation = 0;
  37.     a->width = 24;
  38.     a->talkColor = 15;
  39.     a->new_2 = 0;
  40.     a->new_1 = -80;
  41.     a->scaley = a->scalex = 0xFF;
  42.     a->charset = 0;
  43.     a->sound[0] = 0;
  44.     a->sound[1] = 0;
  45.     a->sound[2] = 0;
  46.     a->sound[3] = 0;
  47.     a->sound[4] = 0;
  48.     a->sound[5] = 0;
  49.     a->sound[6] = 0;
  50.     a->sound[7] = 0;
  51.     a->newDirection = 0;
  52.     a->moving = 0;
  53.  
  54.     setActorWalkSpeed(a, 8, 2);
  55.  
  56.     a->ignoreBoxes = 0;
  57.     a->neverZClip = 0;
  58.     a->new_3 = 0;
  59.     a->initFrame = 1;
  60.     a->walkFrame = 2;
  61.     a->standFrame = 3;
  62.     a->talkFrame1 = 4;
  63.     a->talkFrame2 = 5;
  64.  
  65.     _classData[a->number] = 0;
  66. }
  67.  
  68. void Scumm::setActorWalkSpeed(Actor *a, uint speedx, uint speedy) {
  69.     if (speedx == a->speedx && speedy == a->speedy)
  70.         return;
  71.  
  72.     a->speedx = speedx;
  73.     a->speedy = speedy;
  74.  
  75.     if (a->moving) {
  76.         calcMovementFactor(a, a->walkdata.newx, a->walkdata.newy);
  77.     }
  78. }
  79.  
  80. int Scumm::calcMovementFactor(Actor *a, int newX, int newY) {
  81.     int actorX, actorY;
  82.     int diffX, diffY;
  83.     int32 XYFactor, YXFactor;
  84.  
  85.     actorX = a->x;
  86.     actorY = a->y;
  87.  
  88.     if (actorX == newX && actorY == newY)
  89.         return 0;
  90.  
  91.     diffX = newX - actorX;
  92.     diffY = newY - actorY;
  93.     YXFactor = a->speedy<<16;
  94.  
  95.     if (diffY < 0)
  96.         YXFactor = -YXFactor;
  97.  
  98.     if (diffY != 0) {
  99.         XYFactor = YXFactor * diffX / diffY;
  100.     } else {
  101.         XYFactor = YXFactor * diffX;
  102.         YXFactor = 0;
  103.     }
  104.  
  105.     if ((uint)abs(XYFactor >> 16) > a->speedx) {
  106.         XYFactor = a->speedx<<16;
  107.         if (diffX < 0)
  108.             XYFactor = -XYFactor;
  109.  
  110.         if (diffX != 0) {
  111.             YXFactor = XYFactor * diffY / diffX;
  112.         } else {
  113.             YXFactor = XYFactor * diffY;
  114.             XYFactor = 0;
  115.         }
  116.     }
  117.  
  118.     a->walkdata.x = actorX;
  119.     a->walkdata.y = actorY;
  120.     a->walkdata.newx = newX;
  121.     a->walkdata.newy = newY;
  122.     a->walkdata.XYFactor = XYFactor;
  123.     a->walkdata.YXFactor = YXFactor;
  124.     a->walkdata.xfrac = 0;
  125.     a->walkdata.yfrac = 0;
  126.  
  127.     return actorWalkStep(a);
  128. }
  129.  
  130. int Scumm::actorWalkStep(Actor *a) {
  131.     int32 XYFactor, YXFactor;
  132.     int actorX, actorY, newx, newy;
  133.     int newXDist;
  134.     int32 tmp,tmp2;
  135.  
  136.     byte direction;
  137.  
  138.     a->needRedraw = true;
  139.     a->needBgReset = true;
  140.  
  141.     XYFactor = a->walkdata.XYFactor;
  142.     YXFactor = a->walkdata.YXFactor;
  143.  
  144.     direction = XYFactor>0 ? 1 : 0;
  145.     if (abs(YXFactor) * 2 > abs(XYFactor))
  146.         direction = YXFactor>0 ? 2 : 3;
  147.     a->newDirection = direction;
  148.  
  149.     direction = getProgrDirChange(a, 1);
  150.  
  151.     if (!(a->moving&2) || a->facing!=direction) {
  152.         if (a->walkFrame != a->animIndex || a->facing != direction) {
  153.             startAnimActor(a, a->walkFrame, direction);
  154.         }
  155.         a->moving|=2;
  156.     }
  157.     
  158.     actorX = a->walkdata.x;
  159.     actorY = a->walkdata.y;
  160.     newx = a->walkdata.newx;
  161.     newy = a->walkdata.newy;
  162.  
  163.     if (a->walkbox != a->walkdata.curbox) {
  164.         if (checkXYInBoxBounds(a->walkdata.curbox, a->x, a->y)) {
  165.             a->walkbox = a->walkdata.curbox;
  166.             a->mask = getMaskFromBox(a->walkdata.curbox);
  167.             setupActorScale(a);
  168.         }
  169.     }
  170.  
  171.     newXDist = abs(newx - actorX);
  172.     
  173.     if (newXDist <= abs(a->x - actorX) &&
  174.         abs(newy - actorY) <= abs(a->y - actorY) ){
  175.         a->moving&=~2;
  176.         return 0;
  177.     }
  178.  
  179.     XYFactor = (XYFactor>>8) * a->scalex;
  180.     YXFactor = (YXFactor>>8) * a->scalex;
  181.     
  182.     tmp = ((a->x + 8000)<<16) + a->walkdata.xfrac + XYFactor;
  183.     tmp2 = (a->y<<16) + a->walkdata.yfrac + YXFactor;
  184.  
  185.     a->x = (tmp>>16)-8000;
  186.     a->y = tmp2>>16;
  187.  
  188.     if (abs(a->x - actorX) > newXDist) {
  189.         a->x = newx;
  190.     }
  191.  
  192.     if (abs(a->y - actorY) > abs(newy - actorY)) {
  193.         a->y = newy;
  194.     }
  195.  
  196.     a->walkdata.xfrac = tmp&0xFFFF;
  197.     a->walkdata.yfrac = tmp2&0xFFFF;
  198.  
  199.     if (a->x == newx &&
  200.         a->y == newy) {
  201.         a->moving&=~2;
  202.         return 0;
  203.     }
  204.  
  205.     return 1;
  206. }
  207.  
  208. void Scumm::setupActorScale(Actor *a) {
  209.     uint16 scale;
  210.     byte *resptr;
  211.  
  212.     if (a->ignoreBoxes != 0)
  213.         return;
  214.  
  215.     scale = getBoxScale(a->walkbox);
  216.  
  217.     if (scale & 0x8000) {
  218.         scale = (scale&0x7FFF)+1;
  219.         resptr = getResourceAddress(rtScaleTable, scale);
  220.         if (resptr==NULL)
  221.             error("Scale table %d not defined",scale);
  222.         if (a->y >= 0)
  223.             resptr += a->y;
  224.         scale = *resptr;
  225.     }
  226.  
  227.     if (scale>255)
  228.         error("Actor %d at %d, scale %d out of range", a->number, a->y, scale);
  229.     
  230.     a->scalex = (byte)scale;
  231.     a->scaley = (byte)scale;
  232. }
  233.  
  234. int Scumm::getProgrDirChange(Actor *a, int mode) {
  235.     int flags;
  236.     byte facing, newdir;
  237.     byte XYflag, YXflag;
  238.     byte lookdir;
  239.  
  240.     const byte direction_transtab[] = {
  241.         0,2,2,3,2,1,2,3,0,1,2,1,0,1,0,3
  242.     };
  243.  
  244.     flags = 0;
  245.     if (!a->ignoreBoxes)
  246.         flags = getBoxFlags(a->walkbox);
  247.         
  248.     facing = a->facing;
  249.     newdir = a->newDirection;
  250.     
  251.     XYflag = a->walkdata.XYFactor>0 ? 1 : 0;
  252.     YXflag = a->walkdata.YXFactor>0 ? 1 : 0;
  253.  
  254.     if ((flags&8) || getClass(a->number, 0x1E)) {
  255.         if (!(newdir&2))
  256.             newdir^=1;
  257.         XYflag = 1 - XYflag;
  258.     }
  259.  
  260.     if ((flags&0x10) || getClass(a->number, 0x1D)) {
  261.         if (newdir&2)
  262.             newdir^=1;
  263.         YXflag = 1 - YXflag;
  264.     }
  265.  
  266.     lookdir = direction_transtab[facing*4+newdir];
  267.  
  268.     if (!(flags&=0x7))
  269.         return lookdir;
  270.     
  271.     if (mode==0) {
  272.         lookdir = newdir;
  273.         if (flags==1 && newdir!=1)
  274.             lookdir = 0;
  275.         
  276.         if (flags==2 && newdir!=3)
  277.             lookdir = 2;
  278.     } else {
  279.         if (flags==1)
  280.             lookdir = XYflag;
  281.         if (flags==2)
  282.             lookdir = 3 - YXflag;
  283.     }
  284.     if (flags==3)
  285.         lookdir=0;
  286.     if (flags==4)
  287.         lookdir=1;
  288.     if (flags==6)
  289.         lookdir=2;
  290.     if (flags==5)
  291.         lookdir = 3;
  292.     return lookdir;
  293. }
  294.  
  295. void Scumm::startAnimActor(Actor *a, int frame, byte direction) {
  296.     if (frame==0x38)
  297.         frame = a->initFrame;
  298.  
  299.     if (frame==0x39)
  300.         frame = a->walkFrame;
  301.  
  302.     if (frame==0x3A)
  303.         frame = a->standFrame;
  304.  
  305.     if (frame==0x3B)
  306.         frame = a->talkFrame1;
  307.  
  308.     if (frame==0x3C)
  309.         frame = a->talkFrame2;
  310.  
  311.     if (a->room == _currentRoom && a->costume) {
  312.         a->animProgress = 0;
  313.         a->cost.animCounter1 = 0;
  314.         a->needRedraw = true;
  315.     
  316.         cost.loadCostume(a->costume);
  317.         
  318.         if (a->initFrame==frame)
  319.             initActorCostumeData(a);
  320.  
  321.         if (frame!=0x3E) {
  322.             decodeCostData(a, frame*4 + direction, -1);
  323.         }
  324.  
  325.         if (a->facing != direction)
  326.             fixActorDirection(a, direction);
  327.     }
  328.  
  329.     a->facing = direction;
  330.     a->needBgReset = true;
  331. }
  332.  
  333. void Scumm::initActorCostumeData(Actor *a) {
  334.     CostumeData *cd = &a->cost;
  335.     int i;
  336.  
  337.     cd->hdr = 0;
  338.     for (i=0; i<16; i++)
  339.         cd->a[i] = cd->b[i] = cd->c[i] = cd->d[i] = 0xFFFF;
  340. }
  341.  
  342. void Scumm::fixActorDirection(Actor *a, byte direction) {
  343.     uint mask;
  344.     int i;
  345.     uint16 vald;
  346.  
  347.     if (a->facing == direction)
  348.         return;
  349.  
  350.     mask = 0x8000;
  351.     for (i=0; i<16; i++,mask>>=1) {
  352.         vald = a->cost.d[i];
  353.         if (vald==0xFFFF || (vald&3)==direction)
  354.             continue;
  355.         decodeCostData(a, (vald&0xFC)|direction, mask);
  356.     }
  357.     a->facing = direction;
  358. }
  359.  
  360. void Scumm::decodeCostData(Actor *a, int frame, uint usemask) {
  361.     byte *p,*r;
  362.     uint mask,j;
  363.     int i;
  364.     byte extra,cmd;
  365.     byte *dataptr;
  366.  
  367.     p = cost._ptr;
  368.     if (frame > p[6])
  369.         return;
  370.  
  371.     r = p + READ_LE_UINT16(p + frame*2 + cost._numColors + 42);
  372.     if (r==p)
  373.         return;
  374.  
  375.     dataptr = p + READ_LE_UINT16(p + cost._numColors + 8);
  376.  
  377.     mask = READ_LE_UINT16(r);
  378.     r+=2;
  379.     i = 0;
  380.     do {
  381.         if (mask&0x8000) {
  382.             j = READ_LE_UINT16(r);
  383.             r+=2;
  384.             if (usemask&0x8000) {
  385.                 if (j==0xFFFF) {
  386.                     a->cost.a[i] = 0xFFFF;
  387.                     a->cost.b[i] = 0;
  388.                     a->cost.d[i] = frame;
  389.                 } else {
  390.                     extra = *r++;
  391.                     cmd = dataptr[j];
  392.                     if (cmd==0x7A) {
  393.                         a->cost.hdr &= ~(1<<i);
  394.                     } else if (cmd==0x79) {
  395.                         a->cost.hdr |= (1<<i);
  396.                     } else {
  397.                         a->cost.a[i] = a->cost.b[i] = j;
  398.                         a->cost.c[i] = j + (extra&0x7F);
  399.                         if (extra&0x80)
  400.                             a->cost.a[i] |= 0x8000;
  401.                         a->cost.d[i] = frame;
  402.                     }
  403.                 }
  404.             } else {
  405.                 if (j!=0xFFFF)
  406.                     r++;
  407.             }
  408.         }
  409.         i++;
  410.         usemask <<= 1;
  411.         mask <<= 1;
  412.     } while ((uint16)mask);
  413. }
  414.  
  415. void Scumm::putActor(Actor *a, int x, int y, byte room) {
  416.     if (a->visible && _currentRoom!=room && _vars[VAR_TALK_ACTOR]==a->number) {
  417.         clearMsgQueue();
  418.     }
  419.  
  420.     a->x = x;
  421.     a->y = y;
  422.     a->room = room;
  423.     a->needRedraw = true;
  424.     a->needBgReset = true;
  425.  
  426.     if (_vars[VAR_EGO]==a->number) {
  427.         _egoPositioned = true;
  428.     }
  429.  
  430.     if (a->visible) {
  431.         if (_currentRoom == room) {
  432.             if (a->moving) {
  433.                 startAnimActor(a, a->standFrame, a->facing);
  434.                 a->moving = 0;
  435.             }
  436.             adjustActorPos(a);
  437.         } else {
  438.             hideActor(a);
  439.         }
  440.     } else {
  441.         if (_currentRoom == room)
  442.             showActor(a);
  443.     }
  444. }
  445.  
  446. int Scumm::getActorXYPos(Actor *a) {
  447.     if (a->room != _currentRoom)
  448.         return -1;
  449.     _xPos = a->x;
  450.     _yPos = a->y;
  451.     return 0;
  452. }
  453.  
  454. AdjustBoxResult Scumm::adjustXYToBeInBox(Actor *a, int x, int y) {
  455.     AdjustBoxResult abr,tmp;
  456.     uint threshold;
  457.     uint best;
  458.     int box;
  459.     byte flags, b;
  460.     
  461.     abr.x = x;
  462.     abr.y = y;
  463.     abr.dist = 0;
  464.  
  465.     if (a && a->ignoreBoxes==0) {
  466.         threshold = 30;
  467.         
  468.         while(1) {
  469.             box = getNumBoxes() - 1;
  470.             best = (uint)0xFFFF;
  471.             b = 0;
  472.  
  473.             do {
  474.                 flags = getBoxFlags(box);
  475.                 if (flags&0x80 && (!(flags&0x20) || getClass(a->number, 0x1F)) )
  476.                     continue;
  477.                 
  478.                 if (!inBoxQuickReject(box, x, y, threshold))
  479.                     continue;
  480.                 
  481.                 if (checkXYInBoxBounds(box, x, y)) {
  482.                     abr.x = x;
  483.                     abr.y = y;
  484.                     abr.dist = box;
  485.                     return abr;
  486.                 }
  487.  
  488.                 tmp = getClosestPtOnBox(box, x, y);
  489.  
  490.                 if (tmp.dist >= best)
  491.                     continue;
  492.  
  493.                 abr.x = tmp.x;
  494.                 abr.y = tmp.y;
  495.  
  496.                 if (tmp.dist==0) {
  497.                     abr.dist = box;
  498.                     return abr;
  499.                 }
  500.                 best = tmp.dist;
  501.                 b = box;
  502.             } while (--box);
  503.             
  504.             if (threshold==0 || threshold * threshold >= best) {
  505.                 abr.dist = b;
  506.                 return abr;
  507.             }
  508.             threshold = (threshold==30) ? 80 : 0;
  509.         }
  510.     }
  511.     return abr;
  512. }
  513.  
  514. void Scumm::adjustActorPos(Actor *a) {
  515.     AdjustBoxResult abr;
  516.     byte flags;
  517.     
  518.     abr = adjustXYToBeInBox(a, a->x, a->y);
  519.  
  520.     a->x = abr.x;
  521.     a->y = abr.y;
  522.     a->walkbox = (byte)abr.dist; /* not a dist */
  523.     a->walkdata.destbox = (byte)abr.dist;
  524.     a->mask = getMaskFromBox(abr.dist);
  525.     a->walkdata.destx = -1;
  526.     setupActorScale(a);
  527.  
  528.     a->moving = 0;
  529.     a->cost.animCounter2 = 0;
  530.  
  531.     flags = getBoxFlags(a->walkbox);
  532.     if (flags&7) {
  533.         turnToDirection(a, a->facing);
  534.     }
  535. }
  536.  
  537. void Scumm::hideActor(Actor *a) {
  538.     if (!a->visible)
  539.         return;
  540.  
  541.     if (a->moving) {
  542.         startAnimActor(a, a->standFrame, a->facing);
  543.         a->moving = 0;
  544.     }
  545.     a->visible = false;
  546.     a->cost.animCounter2 = 0;
  547.     a->needRedraw = false;
  548.     a->needBgReset = true;
  549. }
  550.  
  551. void Scumm::turnToDirection(Actor *a, int newdir) {
  552.     a->moving = 4;
  553.     a->newDirection = newdir;
  554. }
  555.  
  556. void Scumm::showActor(Actor *a) {
  557.     if (_currentRoom == 0 || a->visible)
  558.         return;
  559.  
  560.     adjustActorPos(a);
  561.  
  562.     ensureResourceLoaded(rtCostume, a->costume);
  563.  
  564.     if (a->costumeNeedsInit) {
  565.         startAnimActor(a, a->initFrame, a->facing);
  566.         a->costumeNeedsInit = false;
  567.     }
  568.     a->moving = 0;
  569.     a->visible = true;
  570.     a->needRedraw = true;
  571. }
  572.  
  573. void Scumm::showActors() {
  574.     int i;
  575.     Actor *a;
  576.     
  577.     for (i=1; i<13; i++) {
  578.         a = derefActor(i);
  579.         if (a->room == _currentRoom)
  580.             showActor(a);
  581.     }
  582. }
  583.  
  584. void Scumm::stopTalk() {
  585.     int act;
  586.  
  587.     _haveMsg = 0;
  588.     _talkDelay = 0;
  589.  
  590.     act = _vars[VAR_TALK_ACTOR];
  591.     if (act && act<0x80) {
  592.         Actor *a = derefActorSafe(act, "stopTalk");
  593.         if (_currentRoom == a->room && _useTalkAnims) {
  594.             startAnimActor(a, a->talkFrame2, a->facing);
  595.             _useTalkAnims = false;
  596.         }
  597.         _vars[VAR_TALK_ACTOR] = 0xFF;
  598.     }
  599.     _keepText = false;
  600.     restoreCharsetBg();
  601. }
  602.  
  603. void Scumm::clearMsgQueue() {
  604.     _messagePtr = (byte*)" ";
  605.     stopTalk();
  606. }
  607.  
  608. void Scumm::walkActors() {
  609.     int i;
  610.     Actor *a;
  611.     for (i=1; i<13; i++) {
  612.         a = derefActor(i);    
  613.         if (a->room==_currentRoom)
  614.             walkActor(a);
  615.     }
  616. }
  617.  
  618. /* Used in Scumm v5 only. Play sounds associated with actors */
  619. void Scumm::playActorSounds() {
  620.     int i;
  621.     Actor *a;
  622.     
  623.     for (i=1; i<13; i++) {
  624.         a = derefActor(i);
  625.         if (a->cost.animCounter2 && a->room==_currentRoom && a->sound) {
  626.             _currentScript = 0xFF;
  627.             addSoundToQueue(a->sound[0]);
  628.             for (i=1; i<13; i++) {
  629.                 a = derefActor(i);
  630.                 a->cost.animCounter2 = 0;
  631.             }
  632.             return;
  633.         }
  634.     }
  635. }
  636.  
  637. void Scumm::walkActor(Actor *a) {
  638.     int j;
  639.  
  640.     if (!a->moving)
  641.         return;
  642.     
  643.     if (!(a->moving&1)) {
  644.         if (a->moving&2 && actorWalkStep(a))
  645.             return;
  646.     
  647.         if (a->moving&8) {
  648.             a->moving = 0;
  649.  
  650.             j = a->walkdata.destbox;
  651.             if (j) {
  652.                 a->walkbox = j;
  653.                 a->mask = getMaskFromBox(j);
  654.             }
  655.             startAnimActor(a, a->standFrame, a->facing);
  656.             if (a->walkdata.destdir==0xFF ||
  657.                   a->walkdata.destdir==a->newDirection)
  658.                         return;
  659.             a->newDirection = a->walkdata.destdir;
  660.             a->moving = 4;
  661.             return;
  662.         }
  663.  
  664.         if (a->moving&4) {
  665.             j = getProgrDirChange(a, 0);
  666.             if (a->facing != j) 
  667.                 startAnimActor(a, 0x3E, j);
  668.             else
  669.                 a->moving = 0;
  670.             return;
  671.         }
  672.  
  673.         a->walkbox = a->walkdata.curbox;
  674.         a->mask = getMaskFromBox(a->walkdata.curbox);
  675.  
  676.         setupActorScale(a);
  677.         a->moving = (a->moving&2)|1;
  678.     }
  679.  
  680.     do {
  681.         a->moving&=~1;
  682.         if (!a->walkbox) {
  683.             a->walkbox = a->walkdata.destbox;
  684.             a->walkdata.curbox = a->walkdata.destbox;
  685.             break;
  686.         }
  687.         if (a->walkbox == a->walkdata.destbox)
  688.             break;
  689.         j = getPathToDestBox(a->walkbox,a->walkdata.destbox);
  690.         if (j==0) {
  691.             a->walkdata.destbox = a->walkbox;
  692.             a->moving |= 8;
  693.             return;
  694.         }
  695.         a->walkdata.curbox = j;
  696.         if (findPathTowards(a, a->walkbox, j, a->walkdata.destbox))
  697.             break;
  698.         if (calcMovementFactor(a, _foundPathX, _foundPathY))
  699.             return;
  700.  
  701.         a->walkbox = a->walkdata.curbox;
  702.         a->mask = getMaskFromBox(a->walkdata.curbox);
  703.         setupActorScale(a);
  704.     } while (1);
  705.     a->moving |= 8;
  706.     calcMovementFactor(a, a->walkdata.destx, a->walkdata.desty);
  707. }
  708.  
  709. void Scumm::processActors() {
  710.     int i;
  711.     Actor *actors[13],*a,**ac,**ac2,*tmp;
  712.     int numactors = 0, cnt,cnt2;
  713.  
  714.     for (i=1; i<13; i++) {
  715.         a = derefActor(i);
  716.         if (a->room == _currentRoom)
  717.             actors[numactors++] = a;
  718.     }
  719.     if (!numactors)
  720.         return;
  721.  
  722.     ac = actors;
  723.     cnt = numactors;
  724.     do {
  725.         ac2 = actors;
  726.         cnt2 = numactors;
  727.         do {
  728.             if ( (*ac2)->y > (*ac)->y ) {
  729.                 tmp = *ac;
  730.                 *ac = *ac2;
  731.                 *ac2 = tmp;
  732.             }
  733.         } while (ac2++, --cnt2);
  734.     } while (ac++,--cnt);
  735.  
  736.     ac = actors;
  737.     cnt = numactors;
  738.     do {
  739.         a = *ac;
  740.         if (a->costume) {
  741.             setupActorScale(a);
  742.             setupCostumeRenderer(&cost, a);
  743.             setActorCostPalette(a);
  744.             CHECK_HEAP
  745.             drawActorCostume(a);
  746.             CHECK_HEAP
  747.             actorAnimate(a);
  748.         }
  749.     } while (ac++,--cnt);
  750. }
  751.  
  752. void Scumm::setupCostumeRenderer(CostumeRenderer *c, Actor *a) {
  753.     c->_actorX = a->x - virtscr->xstart;
  754.     c->_actorY = a->y - a->elevation;
  755.     c->_zbuf = a->mask;
  756.     if (c->_zbuf > gdi._numZBuffer)
  757.         c->_zbuf = (byte)gdi._numZBuffer;
  758.     if (a->neverZClip)
  759.         c->_zbuf = a->neverZClip;
  760.     
  761.     c->_scaleX = a->scalex;
  762.     c->_scaleY = a->scaley;
  763. }
  764.  
  765. void Scumm::setActorCostPalette(Actor *a) {
  766.     int i;
  767.     byte color;
  768.  
  769.     cost.loadCostume(a->costume);
  770.     
  771.     for (i=0; i<cost._numColors; i++) {
  772.         color = a->palette[i];
  773.         if (color==255)
  774.             color = cost._ptr[8+i];
  775.         cost._palette[i] = color;
  776.     }
  777. }
  778.  
  779. void Scumm::drawActorCostume(Actor *a) {
  780.     if (a==NULL || !a->needRedraw)
  781.         return;
  782.     
  783.     a->top = 0xFF;
  784.     a->needRedraw = 0;
  785.     a->bottom = 0;
  786.     cost.loadCostume(a->costume);
  787.     cost._mirror = a->facing!=0 || (cost._ptr[7]&0x80);
  788.  
  789.     if (cost.drawCostume(a)) {
  790.         a->needRedraw = true;
  791.         a->needBgReset = true;;
  792.     }
  793. }
  794.  
  795. void Scumm::actorAnimate(Actor *a) {
  796.     if (a==NULL)
  797.         return;
  798.     
  799.     a->animProgress++;
  800.     if (a->animProgress >= a->animSpeed) {
  801.         a->animProgress = 0;
  802.         cost.loadCostume(a->costume);
  803.         if (cost.animate(a)) {
  804.             a->needRedraw = true;
  805.             a->needBgReset = true;
  806.         }
  807.     }
  808. }
  809.  
  810. void Scumm::setActorRedrawFlags() {
  811.     int i,j;
  812.     int bits;
  813.  
  814.     for (i=0; i<40; i++) {
  815.         bits = actorDrawBits[_screenStartStrip+i];
  816.         if (bits&0x3FFF) {
  817.             for(j=0; j<13; j++) {
  818.                 if ((bits&(1<<j)) && bits!=(1<<j)) {
  819.                     Actor *a = derefActor(j);
  820.                     a->needRedraw = true;
  821.                     a->needBgReset = true;
  822.                 }
  823.             }
  824.         }
  825.     }
  826. }
  827.  
  828. int Scumm::getActorFromPos(int x, int y) {
  829.     uint16 drawbits;
  830.     int i;
  831.  
  832.     drawbits = actorDrawBits[x>>3];
  833.     if (!(drawbits & 0x3FFF))
  834.         return 0;
  835.     for (i=1; i<13; i++) {
  836.         Actor *a = derefActor(i);
  837.         if (drawbits&(1<<i) && !getClass(i, 32) && y >= a->top && y <= a->bottom) {
  838.             return i;
  839.         }
  840.     }
  841.     return 0;
  842. }
  843.  
  844. void Scumm::actorTalk() {
  845.     int oldact;
  846.     Actor *a;
  847.  
  848.     _msgPtrToAdd = charset._buffer;
  849.     _messagePtr = addMessageToStack(_messagePtr);
  850.     
  851.     if (_actorToPrintStrFor==0xFF) {
  852.         if (!_keepText)
  853.             stopTalk();
  854.         _vars[VAR_TALK_ACTOR] = 0xFF;
  855.         oldact = 0;
  856.     } else {
  857.         a = derefActorSafe(_actorToPrintStrFor, "actorTalk");
  858.         if (a->room!=_currentRoom) {
  859.             oldact = 0xFF;
  860.         } else {
  861.             if (!_keepText)
  862.                 stopTalk();
  863.             _vars[VAR_TALK_ACTOR] = a->number;
  864.             if (!string[0].no_talk_anim) {
  865.                 startAnimActor(a,a->talkFrame1,a->facing);
  866.                 _useTalkAnims = true;
  867.             }
  868.             oldact = _vars[VAR_TALK_ACTOR];
  869.         }
  870.     }
  871.     if (oldact>=0x80)
  872.         return;
  873.     
  874.     if (_vars[VAR_TALK_ACTOR]>0x7F) {
  875.         _charsetColor = (byte)string[0].color;
  876.     } else {
  877.         a = derefActorSafe(_vars[VAR_TALK_ACTOR], "actorTalk(2)");
  878.         _charsetColor = a->talkColor;
  879.     }
  880.     charset._bufPos = 0;
  881.     _talkDelay = 0;
  882.     _haveMsg = 0xFF;
  883.     _vars[VAR_HAVE_MSG] = 0xFF;
  884.     CHARSET_1();
  885. }
  886.  
  887. void Scumm::setActorCostume(Actor *a, int c) {
  888.     int i;
  889.  
  890.     a->costumeNeedsInit = true;
  891.     
  892.     if (a->visible) {
  893.         hideActor(a);
  894.         initActorCostumeData(a);
  895.         a->costume = c;
  896.         showActor(a);
  897.     } else {
  898.         a->costume = c;
  899.         initActorCostumeData(a);
  900.     }
  901.  
  902.     for (i=0; i<32; i++)
  903.         a->palette[i] = 0xFF;
  904. }
  905.  
  906. void Scumm::startWalkActor(Actor *a, int x, int y, int dir) {
  907.     AdjustBoxResult abr;
  908.  
  909.     abr = adjustXYToBeInBox(a, x, y);
  910.  
  911.     _xPos = abr.x;
  912.     _yPos = abr.y;
  913.  
  914.     if (a->room != _currentRoom) {
  915.         a->x = _xPos;
  916.         a->y = _yPos;
  917.         if (dir != 0xFF)
  918.             a->facing = dir;
  919.         return;
  920.     }
  921.  
  922.     if (a->ignoreBoxes!=0) {
  923.         abr.x = _xPos;
  924.         abr.y = _yPos;
  925.         abr.dist = 0;
  926.         a->walkbox = 0;
  927.     } else {
  928.         if (checkXYInBoxBounds(a->walkdata.destbox, _xPos,_yPos)) {
  929.             abr.x = _xPos;
  930.             abr.y = _yPos;
  931.             abr.dist = a->walkdata.destbox;
  932.         } else {
  933.             abr = adjustXYToBeInBox(a, _xPos, _yPos);
  934.         }
  935.         if (a->moving && a->walkdata.destdir == dir
  936.             && a->walkdata.destx == abr.x
  937.             && a->walkdata.desty == abr.y)
  938.                 return;
  939.     }
  940.  
  941.     if (a->x==abr.x && a->y==abr.y) {
  942.         if (dir!=0xFF && dir!=a->facing) {
  943.             a->newDirection = dir;
  944.             a->moving = 4;
  945.         }
  946.         return;
  947.     }
  948.  
  949.     a->walkdata.destx = abr.x;
  950.     a->walkdata.desty = abr.y;
  951.     a->walkdata.destbox = (byte)abr.dist; /* a box */
  952.     a->walkdata.destdir = dir;
  953.     a->moving = (a->moving&2)|1;
  954.     a->walkdata.curbox = a->walkbox;
  955. }
  956.  
  957. byte *Scumm::getActorName(Actor *a) {
  958.     byte *ptr = getResourceAddress(rtActorName, a->number);
  959.     if(ptr==NULL)
  960.         return (byte*)" ";
  961.     return ptr;
  962. }
  963.  
  964. bool Scumm::isCostumeInUse(int cost) {
  965.     int i;
  966.     Actor *a;
  967.  
  968.     if (_roomResource!=0)
  969.         for (i=1; i<13; i++) {
  970.             a = derefActor(i);
  971.             if (a->room == _currentRoom && a->costume == cost)
  972.                 return true;
  973.         }
  974.  
  975.     return false;
  976. }