scummvm/actor.cpp

1338 lines
26 KiB
C++

/* ScummVM - Scumm Interpreter
* Copyright (C) 2001 Ludvig Strigeus
* Copyright (C) 2001/2002 The ScummVM project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
#include "stdafx.h"
#include "scumm.h"
#include "math.h"
void Scumm::initActor(Actor *a, int mode) {
if (a->init != 1) { /* Check if this is the first time we've */
a->costume = 0; /* used this actor. If so, init everything */
a->room = 0;
a->x = a->y = 0;
a->facing = 0;
a->newDirection = 0;
a->visible = 0;
a->mask = 0;
a->walkbox = 0;
a->animProgress = a->animSpeed = 0;
a->layer = 0;
a->init = 1;
}
if (mode==1) {
a->costume = 0;
a->room = 0;
a->x = 0;
a->y = 0;
a->facing = 180;
a->newDirection = 180;
} else if (mode==2) {
a->facing = 180;
a->newDirection = 180;
}
a->elevation = 0;
a->width = 24;
a->talkColor = 15;
a->new_2 = 0;
a->new_1 = -80;
a->scaley = a->scalex = 0xFF;
a->charset = 0;
a->sound[0] = 0;
a->sound[1] = 0;
a->sound[2] = 0;
a->sound[3] = 0;
a->sound[4] = 0;
a->sound[5] = 0;
a->sound[6] = 0;
a->sound[7] = 0;
a->newDirection = 0;
stopActorMoving(a);
a->shadow_mode = 0;
a->layer = 0;
setActorWalkSpeed(a, 8, 2);
a->ignoreBoxes = 0;
a->forceClip = 0;
a->new_3 = 0;
a->initFrame = 1;
a->walkFrame = 2;
a->standFrame = 3;
a->talkFrame1 = 4;
a->talkFrame2 = 5;
a->walk_script = 0;
a->talk_script = 0;
if (_features & GF_AFTER_V7) {
_classData[a->number] = _classData[0];
} else {
_classData[a->number] = 0;
}
}
void Scumm::stopActorMoving(Actor *a) {
stopScriptNr(a->walk_script);
a->moving = 0;
}
void Scumm::setActorWalkSpeed(Actor *a, uint speedx, uint speedy) {
if (speedx == a->speedx && speedy == a->speedy)
return;
a->speedx = speedx;
a->speedy = speedy;
if (a->moving) {
calcMovementFactor(a, a->walkdata.newx, a->walkdata.newy);
}
}
int Scumm::getAngleFromPos(int x, int y) {
if (abs(y)*2 < abs(x)) {
if (x>0)
return 90;
return 270;
} else {
if (y>0)
return 180;
return 0;
}
}
int Scumm::calcMovementFactor(Actor *a, int newX, int newY) {
int actorX, actorY;
int diffX, diffY;
int32 XYFactor, YXFactor;
actorX = a->x;
actorY = a->y;
if (actorX == newX && actorY == newY)
return 0;
diffX = newX - actorX;
diffY = newY - actorY;
YXFactor = a->speedy<<16;
if (diffY < 0)
YXFactor = -YXFactor;
XYFactor = YXFactor * diffX;
if (diffY != 0) {
XYFactor /= diffY;
} else {
YXFactor = 0;
}
if ((uint)abs(XYFactor >> 16) > a->speedx) {
XYFactor = a->speedx<<16;
if (diffX < 0)
XYFactor = -XYFactor;
YXFactor = XYFactor * diffY;
if (diffX != 0) {
YXFactor /= diffX;
} else {
XYFactor = 0;
}
}
a->walkdata.x = actorX;
a->walkdata.y = actorY;
a->walkdata.newx = newX;
a->walkdata.newy = newY;
a->walkdata.XYFactor = XYFactor;
a->walkdata.YXFactor = YXFactor;
a->walkdata.xfrac = 0;
a->walkdata.yfrac = 0;
if(_gameId==GID_DIG) {
double temp;
temp = atan2 (XYFactor, -YXFactor);
a->newDirection = normalizeAngle((int)(temp * 1.8e2 / 3.14));
} else {
a->newDirection = getAngleFromPos(XYFactor, YXFactor);
}
return actorWalkStep(a);
}
int Scumm::remapDirection(Actor *a, int dir) {
int specdir;
byte flags;
byte dirflag;
if (!a->ignoreBoxes) {
specdir = _extraBoxFlags[a->walkbox];
if (specdir) {
if (specdir & 0x8000) {
dir = specdir & 0x3FFF;
} else {
error("getProgrDirChange: special dir not implemented");
}
}
flags = getBoxFlags(a->walkbox);
dirflag = ((a->walkdata.XYFactor>0) ? 1 : 0) |
((a->walkdata.YXFactor>0) ? 2 : 0);
if ((flags&8) || getClass(a->number, 0x1E)) {
dir = 360 - dir;
dirflag ^= 1;
}
if ((flags&0x10) || getClass(a->number, 0x1D)) {
dir = 180 - dir;
dirflag ^= 2;
}
switch(flags & 7) {
case 1:
return (dirflag&1) ? 90 : 270;
case 2:
return (dirflag&2) ? 180 : 0;
case 3: return 270;
case 4: return 90;
case 5: return 0;
case 6: return 180;
}
}
return normalizeAngle(dir);
}
int Scumm::updateActorDirection(Actor *a) {
int from,to;
int diff;
int dirType;
int num;
dirType = akos_hasManyDirections(a);
from = toSimpleDir(dirType, a->facing);
to = toSimpleDir(dirType, remapDirection(a, a->newDirection));
diff = to - from;
num = numSimpleDirDirections(dirType);
if (abs(diff) > (num>>1))
diff = -diff;
if (diff==0) {
} else if (diff>0) {
from++;
} else {
from--;
}
return fromSimpleDir(dirType, from & (num-1));
}
void Scumm::setActorBox(Actor *a, int box) {
a->walkbox = box;
a->mask = getMaskFromBox(box);
setupActorScale(a);
}
int Scumm::actorWalkStep(Actor *a) {
int tmpX, tmpY;
int actorX, actorY;
int distX, distY;
int direction;
a->needRedraw = true;
a->needBgReset = true;
direction = updateActorDirection(a);
if (!(a->moving&MF_IN_LEG) || a->facing!=direction) {
if (a->walkFrame != a->frame || a->facing != direction) {
startWalkAnim(a, a->walkFrame==a->frame ? 2 : 1, direction);
}
a->moving|=MF_IN_LEG;
}
actorX = a->x;
actorY = a->y;
if (a->walkbox != a->walkdata.curbox &&
checkXYInBoxBounds(a->walkdata.curbox, actorX, actorY)) {
setActorBox(a, a->walkdata.curbox);
}
distX = abs(a->walkdata.newx - a->walkdata.x);
distY = abs(a->walkdata.newy - a->walkdata.y);
if (
abs(actorX - a->walkdata.x) >= distX &&
abs(actorY - a->walkdata.y) >= distY
) {
a->moving &= ~MF_IN_LEG;
return 0;
}
tmpX = ((actorX + 8000)<<16) + a->walkdata.xfrac +
(a->walkdata.XYFactor>>8) * a->scalex;
a->walkdata.xfrac = (uint16)tmpX;
actorX = (tmpX>>16) - 8000;
tmpY = (actorY<<16) + a->walkdata.yfrac +
(a->walkdata.YXFactor>>8) * a->scalex;
a->walkdata.yfrac = (uint16)tmpY;
actorY = (tmpY>>16);
if (abs(actorX - a->walkdata.x) > distX) {
actorX = a->walkdata.newx;
}
if (abs(actorY - a->walkdata.y) > distY) {
actorY = a->walkdata.newy;
}
a->x = actorX;
a->y = actorY;
return 1;
}
void Scumm::setupActorScale(Actor *a) {
uint16 scale;
byte *resptr;
int y;
if (_features & GF_NO_SCALLING) {
a->scalex = 0xFF;
a->scaley = 0xFF;
return;
}
if (a->ignoreBoxes != 0)
return;
scale = getBoxScale(a->walkbox);
if (scale & 0x8000) {
scale = (scale&0x7FFF)+1;
resptr = getResourceAddress(rtScaleTable, scale);
if (resptr==NULL)
error("Scale table %d not defined",scale);
y = a->y;
if (y>=200)
y=199;
if (y<0)
y=0;
scale = resptr[y];
}
if (scale>255)
warning("Actor %d at %d, scale %d out of range", a->number, a->y, scale);
a->scalex = (byte)scale;
a->scaley = (byte)scale;
}
void Scumm::startAnimActor(Actor *a, int frame) {
if (_features & GF_NEW_COSTUMES) {
switch(frame) {
case 1001: frame = a->initFrame; break;
case 1002: frame = a->walkFrame; break;
case 1003: frame = a->standFrame; break;
case 1004: frame = a->talkFrame1; break;
case 1005: frame = a->talkFrame2; break;
}
if (a->costume != 0) {
a->animProgress = 0;
a->needRedraw = true;
a->needBgReset = true;
if (frame == a->initFrame)
initActorCostumeData(a);
akos_decodeData(a, frame, (uint)-1);
}
} else {
if (frame==0x38)
frame = a->initFrame;
if (frame==0x39)
frame = a->walkFrame;
if (frame==0x3A)
frame = a->standFrame;
if (frame==0x3B)
frame = a->talkFrame1;
if (frame==0x3C)
frame = a->talkFrame2;
if (a->room == _currentRoom && a->costume) {
a->animProgress = 0;
a->cost.animCounter1 = 0;
a->needRedraw = true;
if (a->initFrame==frame)
initActorCostumeData(a);
if (frame!=0x3E) {
cost_decodeData(a, frame, (uint) -1);
}
}
a->needBgReset = true;
}
}
void Scumm::fixActorDirection(Actor *a, int direction) {
uint mask;
int i;
uint16 vald;
if (a->facing == direction)
return;
a->facing = direction;
if (a->costume==0)
return;
mask = 0x8000;
for (i=0; i<16; i++,mask>>=1) {
vald = a->cost.frame[i];
if (vald==0xFFFF)
continue;
if(_features & GF_AFTER_V7)
akos_decodeData(a, vald, mask);
else
cost_decodeData(a, vald, mask);
}
a->needRedraw = true;
a->needBgReset = true;
}
void Scumm::putActor(Actor *a, int x, int y, byte room) {
if (a->visible && _currentRoom!=room && _vars[VAR_TALK_ACTOR]==a->number) {
clearMsgQueue();
}
a->x = x;
a->y = y;
a->room = room;
a->needRedraw = true;
a->needBgReset = true;
if (_vars[VAR_EGO]==a->number) {
_egoPositioned = true;
}
if (a->visible) {
if (_currentRoom == room) {
if (a->moving) {
startAnimActor(a, a->standFrame);
a->moving = 0;
}
adjustActorPos(a);
} else {
hideActor(a);
}
} else {
if (_currentRoom == room)
showActor(a);
}
}
int Scumm::getActorXYPos(Actor *a) {
if (a->room != _currentRoom)
return -1;
_xPos = a->x;
_yPos = a->y;
return 0;
}
AdjustBoxResult Scumm::adjustXYToBeInBox(Actor *a, int x, int y, int pathfrom) {
// Yazoo: need to recheck with Loom for the class data flags (0x400000)
AdjustBoxResult abr,tmp;
uint threshold;
uint best;
int box, iterations = 0; /* Use inerations for those odd times we get stuck in the loop */
int firstValidBox,j;
byte flags, b;
if(_features & GF_SMALL_HEADER)
firstValidBox=0;
else
firstValidBox=1;
abr.x = x;
abr.y = y;
abr.dist = 0;
if (a && a->ignoreBoxes==0) {
threshold = 30;
if ((_features & GF_SMALL_HEADER) && (_classData[a->number] & 0x200000))
return abr;
while(1) {
iterations++;
if (iterations > 1000) return abr; /* Safety net */
box = getNumBoxes() - 1;
if (box == 0)
return abr;
best = (uint)0xFFFF;
b = 0;
if(((_features & GF_SMALL_HEADER) && box) || !(_features & GF_SMALL_HEADER))
for (j=box;j>=firstValidBox;j--) {
flags = getBoxFlags(j);
if (flags&0x80 && (!(flags&0x20) || getClass(a->number, 0x1F)) )
continue;
if (pathfrom && (getPathToDestBox(pathfrom, j)==-1))
continue;
if (!inBoxQuickReject(j, x, y, threshold))
continue;
if (checkXYInBoxBounds(j, x, y)) {
abr.x = x;
abr.y = y;
abr.dist = j;
return abr;
}
tmp = getClosestPtOnBox(j, x, y);
if (tmp.dist >= best)
continue;
abr.x = tmp.x;
abr.y = tmp.y;
if (tmp.dist==0) {
abr.dist = j;
return abr;
}
best = tmp.dist;
b = j;
}
if (threshold==0 || threshold * threshold >= best) {
abr.dist = b;
return abr;
}
threshold = (threshold==30) ? 80 : 0;
}
}
return abr;
}
void Scumm::adjustActorPos(Actor *a) {
AdjustBoxResult abr;
byte flags;
abr = adjustXYToBeInBox(a, a->x, a->y, 0);
a->x = abr.x;
a->y = abr.y;
a->walkdata.destbox = (byte)abr.dist;
setActorBox(a, abr.dist);
a->walkdata.destx = -1;
a->moving = 0;
a->cost.animCounter2 = 0;
flags = getBoxFlags(a->walkbox);
if (flags&7) {
turnToDirection(a, a->facing);
}
}
void Scumm::hideActor(Actor *a) {
if (!a->visible)
return;
if (a->moving) {
startAnimActor(a, a->standFrame);
a->moving = 0;
}
a->visible = false;
a->cost.animCounter2 = 0;
a->needRedraw = false;
a->needBgReset = true;
}
void Scumm::turnToDirection(Actor *a, int newdir) {
if (newdir==-1)
return;
a->moving &= ~4;
if (newdir != a->facing) {
a->moving = 4;
a->newDirection = newdir;
}
}
void Scumm::showActor(Actor *a) {
if (_currentRoom == 0 || a->visible)
return;
adjustActorPos(a);
ensureResourceLoaded(rtCostume, a->costume);
if (a->costumeNeedsInit) {
startAnimActor(a, a->initFrame);
a->costumeNeedsInit = false;
}
a->moving = 0;
a->visible = true;
a->needRedraw = true;
}
void Scumm::showActors() {
int i;
Actor *a;
for (i=1; i<NUM_ACTORS; i++) {
a = derefActor(i);
if (a->room == _currentRoom)
showActor(a);
}
}
void Scumm::stopTalk() {
int act;
stopTalkSound();
_haveMsg = 0;
_talkDelay = 0;
act = _vars[VAR_TALK_ACTOR];
if (act && act<0x80) {
Actor *a = derefActorSafe(act, "stopTalk");
if (_currentRoom == a->room && _useTalkAnims) {
startAnimActor(a, a->talkFrame2);
_useTalkAnims = false;
}
_vars[VAR_TALK_ACTOR] = 0xFF;
}
_keepText = false;
restoreCharsetBg();
}
void Scumm::clearMsgQueue() {
_messagePtr = (byte*)" ";
stopTalk();
}
void Scumm::walkActors() {
int i;
Actor *a;
for (i=1; i<NUM_ACTORS; i++) {
a = derefActor(i);
if (a->room==_currentRoom)
if(_features & GF_OLD256)
walkActorOld(a);
else
walkActor(a);
}
}
/* Used in Scumm v5 only. Play sounds associated with actors */
void Scumm::playActorSounds() {
int i;
Actor *a;
for (i=1; i<NUM_ACTORS; i++) {
a = derefActor(i);
if (a->cost.animCounter2 && a->room==_currentRoom && a->sound) {
_currentScript = 0xFF;
addSoundToQueue(a->sound[0]);
for (i=1; i<NUM_ACTORS; i++) {
a = derefActor(i);
a->cost.animCounter2 = 0;
}
return;
}
}
}
void Scumm::startWalkAnim(Actor *a, int cmd, int angle) {
int16 args[16];
if (angle == -1)
angle = a->facing;
if (a->walk_script != 0) {
args[2] = angle;
args[0] = a->number;
args[1] = cmd;
runScript(a->walk_script, 1, 0, args);
} else {
switch(cmd) {
case 1: /* start walk */
//a->facing = angle;
fixActorDirection(a, angle);
startAnimActor(a, a->walkFrame);
break;
case 2: /* change dir only */
fixActorDirection(a, angle);
break;
case 3: /* stop walk */
turnToDirection(a, angle);
startAnimActor(a, a->standFrame);
break;
}
}
}
void Scumm::walkActor(Actor *a) {
int j;
if (!a->moving)
return;
if (!(a->moving&1)) {
if (a->moving&2 && actorWalkStep(a))
return;
if (a->moving&8) {
a->moving = 0;
setActorBox(a, a->walkdata.destbox);
startWalkAnim(a, 3, a->walkdata.destdir);
return;
}
if (a->moving&4) {
j = updateActorDirection(a);
if (a->facing != j)
fixActorDirection(a,j);
else
a->moving = 0;
return;
}
setActorBox(a, a->walkdata.curbox);
a->moving &= 2;
}
#if OLD
a->moving &= ~1;
if (!a->walkbox) {
a->walkbox = a->walkdata.destbox;
a->walkdata.curbox = a->walkdata.destbox;
a->moving |= 8;
calcMovementFactor(a, a->walkdata.destx, a->walkdata.desty);
return;
}
if (a->ignoreBoxes || a->walkbox==a->walkdata.destbox) {
a->walkdata.curbox = a->walkbox;
a->moving |= 8;
calcMovementFactor(a, a->walkdata.destx, a->walkdata.desty);
return;
}
j = getPathToDestBox(a->walkbox,a->walkdata.destbox);
if (j==-1) {
error("walkActor: no path found between %d and %d", a->walkbox, a->walkdata.destbox);
}
a->walkdata.curbox = j;
if (findPathTowards(a, a->walkbox, j, a->walkdata.destbox)) {
a->moving |= 8;
calcMovementFactor(a, a->walkdata.destx, a->walkdata.desty);
return;
}
calcMovementFactor(a, _foundPathX, _foundPathY);
#endif
#if 1
do {
a->moving&=~1;
if ((!a->walkbox && (!(_features & GF_SMALL_HEADER))) ) {
setActorBox(a, a->walkdata.destbox);
a->walkdata.curbox = a->walkdata.destbox;
break;
}
if (a->walkbox == a->walkdata.destbox)
break;
j = getPathToDestBox(a->walkbox,a->walkdata.destbox);
if (j==-1 || j>0xF0) {
a->walkdata.destbox = a->walkbox;
a->moving |= 8;
return;
}
a->walkdata.curbox = j;
if(_features & GF_OLD256)
{
findPathTowardsOld(a, a->walkbox, j, a->walkdata.destbox);
if (p[2].x == 32000 && p[3].x == 32000)
{
a->moving |= 8;
calcMovementFactor(a, a->walkdata.destx, a->walkdata.desty);
return;
}
if (p[2].x != 32000) {
if (calcMovementFactor(a, p[2].x, p[2].y)){
a->walkdata.destx = p[3].x;
a->walkdata.desty = p[3].y;
return;
}
}
if (calcMovementFactor(a, p[3].x, p[3].y))
return;
} else {
if (findPathTowards(a, a->walkbox, j, a->walkdata.destbox))
break;
if (calcMovementFactor(a, _foundPathX, _foundPathY))
return;
}
setActorBox(a, a->walkdata.curbox);
} while (1);
a->moving |= 8;
calcMovementFactor(a, a->walkdata.destx, a->walkdata.desty);
#endif
}
void Scumm::processActors() {
int i;
Actor *actors[MAX_ACTORS], *a,**ac,**ac2,*tmp;
int numactors = 0, cnt,cnt2;
for (i=1; i<NUM_ACTORS; i++) {
a = derefActor(i);
if (a->room == _currentRoom)
actors[numactors++] = a;
}
if (!numactors)
return;
ac = actors;
cnt = numactors;
do {
ac2 = actors;
cnt2 = numactors;
do {
if ( (*ac2)->y - ((*ac2)->layer<<11) > (*ac)->y - ((*ac)->layer<<11) ) {
tmp = *ac;
*ac = *ac2;
*ac2 = tmp;
}
} while (ac2++, --cnt2);
} while (ac++,--cnt);
ac = actors;
cnt = numactors;
do {
a = *ac;
if (a->costume) {
CHECK_HEAP
getMaskFromBox(a->walkbox);
drawActorCostume(a);
CHECK_HEAP
actorAnimate(a);
}
} while (ac++,--cnt);
}
void Scumm::drawActorCostume(Actor *a) {
if(!(_features & GF_AFTER_V7)) {
CostumeRenderer cr;
if (a==NULL || !a->needRedraw)
return;
a->needRedraw = false;
setupActorScale(a);
cr._actorX = a->x - virtscr->xstart;
cr._actorY = a->y - a->elevation;
cr._scaleX = a->scalex;
cr._scaleY = a->scaley;
cr._outheight = virtscr->height;
cr._vm = this;
cr._zbuf = a->mask;
if (cr._zbuf > gdi._numZBuffer)
cr._zbuf = (byte)gdi._numZBuffer;
if (a->forceClip)
cr._zbuf = a->forceClip;
cr._shadow_table = _shadowPalette;
cost_setCostume(&cr, a->costume);
cost_setPalette(&cr, a->palette);
cost_setFacing(&cr, a);
a->top = 0xFF;
a->bottom = 0;
/* if the actor is partially hidden, redraw it next frame */
if(cr.drawCostume(a)&1) {
a->needBgReset = true;
a->needRedraw = true;
}
} else {
AkosRenderer ar;
if (a==NULL || !a->needRedraw)
return;
a->needRedraw = false;
setupActorScale(a);
ar.x = a->x - virtscr->xstart;
ar.y = a->y - a->elevation;
ar.scale_x = a->scalex;
ar.scale_y = a->scaley;
ar.clipping = a->forceClip;
if (ar.clipping == 100) {
ar.clipping = a->mask;
if (ar.clipping > (byte)gdi._numZBuffer)
ar.clipping = gdi._numZBuffer;
}
ar.charsetmask = _vars[VAR_CHARSET_MASK]!=0;
ar.outptr = virtscr->screenPtr + virtscr->xstart;
ar.outwidth = virtscr->width;
ar.outheight = virtscr->height;
ar.shadow_mode = a->shadow_mode;
ar.shadow_table = _shadowPalette;
akos_setCostume(&ar, a->costume);
akos_setPalette(&ar, a->palette);
akos_setFacing(&ar, a);
ar.dirty_id = a->number;
ar.cd = &a->cost;
ar.draw_top = a->top = 0x7fffffff;
ar.draw_bottom = a->bottom = 0;
akos_drawCostume(&ar);
a->top = ar.draw_top;
a->bottom = ar.draw_bottom;
}
}
void Scumm::actorAnimate(Actor *a) {
byte *akos;
LoadedCostume lc;
if (a==NULL || a->costume == 0)
return;
a->animProgress++;
if (a->animProgress >= a->animSpeed) {
a->animProgress = 0;
if (_features & GF_AFTER_V7) {
akos = getResourceAddress(rtCostume, a->costume);
assert(akos);
if (akos_increaseAnims(akos, a)) {
a->needRedraw = true;
a->needBgReset = true;
}
} else {
loadCostume(&lc, a->costume);
if (cost_increaseAnims(&lc, a)) {
a->needRedraw = true;
a->needBgReset = true;
}
}
}
}
void Scumm::setActorRedrawFlags() {
int i,j;
uint32 bits;
for (i=0; i<40; i++) {
bits = gfxUsageBits[_screenStartStrip+i];
if (bits&0x3FFFFFFF) {
for(j=0; j<NUM_ACTORS; j++) {
if ((bits&(1<<j)) && bits!=(uint32)(1<<j)) {
Actor *a = derefActor(j);
a->needRedraw = true;
a->needBgReset = true;
}
}
}
}
}
int Scumm::getActorFromPos(int x, int y) {
uint32 drawbits;
int i;
drawbits = gfxUsageBits[x>>3];
if (!(drawbits & 0x3FFFFFFF))
return 0;
for (i=1; i<NUM_ACTORS; i++) {
Actor *a = derefActor(i);
if (drawbits&(1<<i) && !getClass(i, 32) && y >= a->top && y <= a->bottom) {
return i;
}
}
return 0;
}
void Scumm::actorTalk() {
int oldact;
Actor *a;
_msgPtrToAdd = charset._buffer;
_messagePtr = addMessageToStack(_messagePtr);
assert((int)(_msgPtrToAdd - charset._buffer) < (int)(sizeof(charset._buffer)));
if (_actorToPrintStrFor==0xFF) {
if (!_keepText)
stopTalk();
_vars[VAR_TALK_ACTOR] = 0xFF;
oldact = 0;
} else {
a = derefActorSafe(_actorToPrintStrFor, "actorTalk");
if (a->room!=_currentRoom) {
oldact = 0xFF;
} else {
if (!_keepText)
stopTalk();
_vars[VAR_TALK_ACTOR] = a->number;
if (!string[0].no_talk_anim) {
startAnimActor(a,a->talkFrame1);
_useTalkAnims = true;
}
oldact = _vars[VAR_TALK_ACTOR];
}
}
if (oldact>=0x80)
return;
if (_vars[VAR_TALK_ACTOR]>0x7F) {
_charsetColor = (byte)string[0].color;
} else {
a = derefActorSafe(_vars[VAR_TALK_ACTOR], "actorTalk(2)");
_charsetColor = a->talkColor;
}
charset._bufPos = 0;
_talkDelay = 0;
_haveMsg = 0xFF;
_vars[VAR_HAVE_MSG] = 0xFF;
CHARSET_1();
}
void Scumm::setActorCostume(Actor *a, int c) {
int i;
a->costumeNeedsInit = true;
if (a->visible) {
hideActor(a);
initActorCostumeData(a);
a->costume = c;
showActor(a);
} else {
a->costume = c;
initActorCostumeData(a);
}
for (i=0; i<32; i++)
a->palette[i] = 0xFF;
}
void Scumm::startWalkActor(Actor *a, int x, int y, int dir) {
AdjustBoxResult abr;
abr = adjustXYToBeInBox(a, x, y, a->walkbox);
if (a->room != _currentRoom) {
a->x = abr.x;
a->y = abr.y;
if (dir != -1)
a->facing = dir;
return;
}
if (a->ignoreBoxes!=0) {
abr.dist = 0;
a->walkbox = 0;
} else {
if (checkXYInBoxBounds(a->walkdata.destbox, abr.x,abr.y)) {
abr.dist = a->walkdata.destbox;
} else {
abr = adjustXYToBeInBox(a, abr.x, abr.y, a->walkbox);
}
if (a->moving && a->walkdata.destdir == dir
&& a->walkdata.destx == abr.x
&& a->walkdata.desty == abr.y)
return;
}
if (a->x==abr.x && a->y==abr.y) {
turnToDirection(a, dir);
return;
}
a->walkdata.destx = abr.x;
a->walkdata.desty = abr.y;
a->walkdata.destbox = (byte)abr.dist; /* a box */
a->walkdata.destdir = dir;
a->moving = (a->moving&2)|1;
a->walkdata.point3x = 32000;
a->walkdata.curbox = a->walkbox;
}
byte *Scumm::getActorName(Actor *a) {
byte *ptr = getResourceAddress(rtActorName, a->number);
if(ptr==NULL)
return (byte*)" ";
return ptr;
}
bool Scumm::isCostumeInUse(int cost) {
int i;
Actor *a;
if (_roomResource!=0)
for (i=1; i<NUM_ACTORS; i++) {
a = derefActor(i);
if (a->room == _currentRoom && a->costume == cost)
return true;
}
return false;
}
void Scumm::remapActor(Actor *a, int r_fact, int g_fact, int b_fact, int threshold) {
byte *akos, *rgbs,*akpl;
int akpl_size, i;
int r,g,b;
byte akpl_color;
if (a->room != _currentRoom) {
warning("Remap actor %d not in current room",a->number);
return;
}
if (a->costume < 1 || a->costume >= _numCostumes-1){
warning("Remap actor %d invalid costume",a->number,a->costume);
return;
}
akos = getResourceAddress(rtCostume, a->costume);
akpl = findResource(MKID('AKPL'), akos);
//get num palette entries
akpl_size=RES_SIZE(akpl) - 8;
//skip resource header
akpl = RES_DATA(akpl);
rgbs = findResource(MKID('RGBS'), akos);
if (!rgbs) {
warning("Can't remap actor %d costume %d doesn't contain an RGB block",a->number,a->costume);
return;
}
// skip resource header
rgbs = RES_DATA(rgbs);
for(i=0; i<akpl_size; i++) {
r=*rgbs++;
g=*rgbs++;
b=*rgbs++;
akpl_color=*akpl++;
// allow remap of generic palette entry?
if (!a->shadow_mode || akpl_color>=16) {
if (r_fact!=256) r = (r*r_fact) >> 8;
if (g_fact!=256) g = (g*g_fact) >> 8;
if (b_fact!=256) b = (b*b_fact) >> 8;
a->palette[i]=remapPaletteColor(r,g,b,threshold);
}
}
}
void Scumm::setupShadowPalette(int slot,int rfact,int gfact,int bfact,int from,int to) {
byte *table;
int i,num;
byte *curpal;
if (slot<0 || slot > 7)
error("setupShadowPalette: invalid slot %d", slot);
if (from<0 || from>255 || to<0 || from>255 || to < from)
error("setupShadowPalette: invalid range from %d to %d", from, to);
table = _shadowPalette + slot * 256;
for(i=0; i<256; i++)
table[i] = i;
table += from;
curpal = _currentPalette + from*3;
num = to - from + 1;
do {
*table++ = remapPaletteColor(
curpal[0] * rfact >> 8,
curpal[1] * gfact >> 8,
curpal[2] * bfact >> 8,
(uint)-1);
curpal+=3;
} while (--num);
}
void Scumm::walkActorOld(Actor *a) {
int new_dir,next_box;
if(!a->moving)
return;
if(a->moving&1)
{
restart:
a->moving &= ~1;
if (a->walkbox==0xFF)
{
a->walkbox = a->walkdata.destbox;
a->walkdata.curbox = a->walkdata.destbox;
a->moving |=8;
calcMovementFactor(a, a->walkdata.destx, a->walkdata.desty);
return;
}
if (a->walkbox==a->walkdata.destbox)
{
a->moving |=8;
calcMovementFactor(a, a->walkdata.destx, a->walkdata.desty);
return;
}
next_box = getPathToDestBox(a->walkbox,a->walkdata.destbox);
if( next_box == -1)
{
a->moving |=8;
return;
}
a->walkdata.curbox = next_box;
findPathTowardsOld(a, a->walkbox, next_box, a->walkdata.destbox);
if(p[2].x == 32000 && p[3].x == 32000)
{
a->moving |=8;
calcMovementFactor(a, a->walkdata.destx, a->walkdata.desty);
return;
}
if(p[2].x != 32000)
{
if(calcMovementFactor(a, p[2].x, p[2].y))
{
actor->walkdata.point3x=p[3].x;
actor->walkdata.point3y=p[3].y;
return;
}
}
if(calcMovementFactor(a,p[3].x,p[3].y))
return;
a->walkbox = a->walkdata.destbox;
a->mask = getMaskFromBox(a->walkbox);
goto restart;
}
if(a->moving & 2)
{
if(actorWalkStep(a))
return;
}
if(a->moving & 8)
{
a->moving = 0;
startWalkAnim(a, 3, a->walkdata.destdir);
return;
}
if(a->moving & 4)
{
new_dir = updateActorDirection(a);
if (a->facing != new_dir)
{
fixActorDirection(a,new_dir);
return;
}
a->moving=0;
return;
}
if(a->walkdata.point3x != 32000)
{
if(calcMovementFactor(a,a->walkdata.point3x,a->walkdata.point3y))
{
a->walkdata.point3x=32000;
return;
}
a->walkdata.point3x=32000;
}
a->walkbox = a->walkdata.curbox;
a->mask = getMaskFromBox(a->walkbox);
a->moving &= 2;
a->moving |= 1;
goto restart;
}