/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001  Ludvig Strigeus
 *
 * 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: /cvsroot/scummvm/scummvm/actor.cpp,v 1.10 2001/11/07 18:10:52 strigeus Exp $
 *
 */

#include "stdafx.h"
#include "scumm.h"

void Scumm::initActor(Actor *a, int mode) {
	if (mode==1) {
		a->costume = 0;
		a->room = 0;
		a->x = 0;
		a->y = 0;
		a->facing = 2;
	} else if (mode==2) {
		a->facing = 2;
	}

	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;
	a->moving = 0;

	setActorWalkSpeed(a, 8, 2);

	a->ignoreBoxes = 0;
	a->neverZClip = 0;
	a->new_3 = 0;
	a->initFrame = 1;
	a->walkFrame = 2;
	a->standFrame = 3;
	a->talkFrame1 = 4;
	a->talkFrame2 = 5;

	_classData[a->number] = 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::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;

	if (diffY != 0) {
		XYFactor = YXFactor * diffX / diffY;
	} else {
		XYFactor = YXFactor * diffX;
		YXFactor = 0;
	}

	if ((uint)abs(XYFactor >> 16) > a->speedx) {
		XYFactor = a->speedx<<16;
		if (diffX < 0)
			XYFactor = -XYFactor;

		if (diffX != 0) {
			YXFactor = XYFactor * diffY / diffX;
		} else {
			YXFactor = XYFactor * diffY;
			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;

	return actorWalkStep(a);
}

int Scumm::actorWalkStep(Actor *a) {
	int32 XYFactor, YXFactor;
	int actorX, actorY, newx, newy;
	int newXDist;
	int32 tmp,tmp2;

	byte direction;

	a->needRedraw = true;
	a->needBgReset = true;

	XYFactor = a->walkdata.XYFactor;
	YXFactor = a->walkdata.YXFactor;

	direction = XYFactor>0 ? 1 : 0;
	if (abs(YXFactor) * 2 > abs(XYFactor))
		direction = YXFactor>0 ? 2 : 3;
	a->newDirection = direction;

	direction = getProgrDirChange(a, 1);

	if (!(a->moving&2) || a->facing!=direction) {
		if (a->walkFrame != a->animIndex || a->facing != direction) {
			startAnimActor(a, a->walkFrame, direction);
		}
		a->moving|=2;
	}
	
	actorX = a->walkdata.x;
	actorY = a->walkdata.y;
	newx = a->walkdata.newx;
	newy = a->walkdata.newy;

	if (a->walkbox != a->walkdata.curbox) {
		if (checkXYInBoxBounds(a->walkdata.curbox, a->x, a->y)) {
			a->walkbox = a->walkdata.curbox;
			a->mask = getMaskFromBox(a->walkdata.curbox);
			setupActorScale(a);
		}
	}

	newXDist = abs(newx - actorX);
	
	if (newXDist <= abs(a->x - actorX) &&
		abs(newy - actorY) <= abs(a->y - actorY) ){
		a->moving&=~2;
		return 0;
	}

	XYFactor = (XYFactor>>8) * a->scalex;
	YXFactor = (YXFactor>>8) * a->scalex;
	
	tmp = ((a->x + 8000)<<16) + a->walkdata.xfrac + XYFactor;
	tmp2 = (a->y<<16) + a->walkdata.yfrac + YXFactor;

	a->x = (tmp>>16)-8000;
	a->y = tmp2>>16;

	if (abs(a->x - actorX) > newXDist) {
		a->x = newx;
	}

	if (abs(a->y - actorY) > abs(newy - actorY)) {
		a->y = newy;
	}

	a->walkdata.xfrac = tmp&0xFFFF;
	a->walkdata.yfrac = tmp2&0xFFFF;

	if (a->x == newx &&
		a->y == newy) {
		a->moving&=~2;
		return 0;
	}

	return 1;
}

void Scumm::setupActorScale(Actor *a) {
	uint16 scale;
	byte *resptr;

	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);
		if (a->y >= 0)
			resptr += a->y;
		scale = *resptr;
	}

	if (scale>255)
		error("Actor %d at %d, scale %d out of range", a->number, a->y, scale);
	
	a->scalex = (byte)scale;
	a->scaley = (byte)scale;
}

int Scumm::getProgrDirChange(Actor *a, int mode) {
	int flags;
	byte facing, newdir;
	byte XYflag, YXflag;
	byte lookdir;

	const byte direction_transtab[] = {
		0,2,2,3,2,1,2,3,0,1,2,1,0,1,0,3
	};

	flags = 0;
	if (!a->ignoreBoxes)
		flags = getBoxFlags(a->walkbox);
		
	facing = a->facing;
	newdir = a->newDirection;
	
	XYflag = a->walkdata.XYFactor>0 ? 1 : 0;
	YXflag = a->walkdata.YXFactor>0 ? 1 : 0;

	if ((flags&8) || getClass(a->number, 0x1E)) {
		if (!(newdir&2))
			newdir^=1;
		XYflag = 1 - XYflag;
	}

	if ((flags&0x10) || getClass(a->number, 0x1D)) {
		if (newdir&2)
			newdir^=1;
		YXflag = 1 - YXflag;
	}

	lookdir = direction_transtab[facing*4+newdir];

	if (!(flags&=0x7))
		return lookdir;
	
	if (mode==0) {
		lookdir = newdir;
		if (flags==1 && newdir!=1)
			lookdir = 0;
		
		if (flags==2 && newdir!=3)
			lookdir = 2;
	} else {
		if (flags==1)
			lookdir = XYflag;
		if (flags==2)
			lookdir = 3 - YXflag;
	}
	if (flags==3)
		lookdir=0;
	if (flags==4)
		lookdir=1;
	if (flags==6)
		lookdir=2;
	if (flags==5)
		lookdir = 3;
	return lookdir;
}

void Scumm::startAnimActor(Actor *a, int frame, byte direction) {
	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;
	
		cost.loadCostume(a->costume);
		
		if (a->initFrame==frame)
			initActorCostumeData(a);

		if (frame!=0x3E) {
			decodeCostData(a, frame*4 + direction, -1);
		}

		if (a->facing != direction)
			fixActorDirection(a, direction);
	}

	a->facing = direction;
	a->needBgReset = true;
}

void Scumm::initActorCostumeData(Actor *a) {
	CostumeData *cd = &a->cost;
	int i;

	cd->hdr = 0;
	for (i=0; i<16; i++)
		cd->a[i] = cd->b[i] = cd->c[i] = cd->d[i] = 0xFFFF;
}

void Scumm::fixActorDirection(Actor *a, byte direction) {
	uint mask;
	int i;
	uint16 vald;

	if (a->facing == direction)
		return;

	mask = 0x8000;
	for (i=0; i<16; i++,mask>>=1) {
		vald = a->cost.d[i];
		if (vald==0xFFFF || (vald&3)==direction)
			continue;
		decodeCostData(a, (vald&0xFC)|direction, mask);
	}
	a->facing = direction;
}

void Scumm::decodeCostData(Actor *a, int frame, uint usemask) {
	byte *p,*r;
	uint mask,j;
	int i;
	byte extra,cmd;
	byte *dataptr;

	p = cost._ptr;
	if (frame > p[6])
		return;

	r = p + READ_LE_UINT16(p + frame*2 + cost._numColors + 42);
	if (r==p)
		return;

	dataptr = p + READ_LE_UINT16(p + cost._numColors + 8);

	mask = READ_LE_UINT16(r);
	r+=2;
	i = 0;
	do {
		if (mask&0x8000) {
			j = READ_LE_UINT16(r);
			r+=2;
			if (usemask&0x8000) {
				if (j==0xFFFF) {
					a->cost.a[i] = 0xFFFF;
					a->cost.b[i] = 0;
					a->cost.d[i] = frame;
				} else {
					extra = *r++;
					cmd = dataptr[j];
					if (cmd==0x7A) {
						a->cost.hdr &= ~(1<<i);
					} else if (cmd==0x79) {
						a->cost.hdr |= (1<<i);
					} else {
						a->cost.a[i] = a->cost.b[i] = j;
						a->cost.c[i] = j + (extra&0x7F);
						if (extra&0x80)
							a->cost.a[i] |= 0x8000;
						a->cost.d[i] = frame;
					}
				}
			} else {
				if (j!=0xFFFF)
					r++;
			}
		}
		i++;
		usemask <<= 1;
		mask <<= 1;
	} while ((uint16)mask);
}

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->facing);
				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) {
	AdjustBoxResult abr,tmp;
	uint threshold;
	uint best;
	int box;
	byte flags, b;
	
	abr.x = x;
	abr.y = y;
	abr.dist = 0;

	if (a && a->ignoreBoxes==0) {
		threshold = 30;
		
		while(1) {
			box = getNumBoxes() - 1;
			best = (uint)0xFFFF;
			b = 0;

			do {
				flags = getBoxFlags(box);
				if (flags&0x80 && (!(flags&0x20) || getClass(a->number, 0x1F)) )
					continue;
				
				if (!inBoxQuickReject(box, x, y, threshold))
					continue;
				
				if (checkXYInBoxBounds(box, x, y)) {
					abr.x = x;
					abr.y = y;
					abr.dist = box;
					return abr;
				}

				tmp = getClosestPtOnBox(box, x, y);

				if (tmp.dist >= best)
					continue;

				abr.x = tmp.x;
				abr.y = tmp.y;

				if (tmp.dist==0) {
					abr.dist = box;
					return abr;
				}
				best = tmp.dist;
				b = box;
			} while (--box);
			
			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);

	a->x = abr.x;
	a->y = abr.y;
	a->walkbox = (byte)abr.dist; /* not a dist */
	a->walkdata.destbox = (byte)abr.dist;
	a->mask = getMaskFromBox(abr.dist);
	a->walkdata.destx = -1;
	setupActorScale(a);

	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->facing);
		a->moving = 0;
	}
	a->visible = false;
	a->cost.animCounter2 = 0;
	a->needRedraw = false;
	a->needBgReset = true;
}

void Scumm::turnToDirection(Actor *a, int newdir) {
	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->facing);
		a->costumeNeedsInit = false;
	}
	a->moving = 0;
	a->visible = true;
	a->needRedraw = true;
}

void Scumm::showActors() {
	int i;
	Actor *a;
	
	for (i=1; i<13; i++) {
		a = derefActor(i);
		if (a->room == _currentRoom)
			showActor(a);
	}
}

void Scumm::stopTalk() {
	int act;

	_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, a->facing);
			_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<13; i++) {
		a = derefActor(i);	
		if (a->room==_currentRoom)
			walkActor(a);
	}
}

/* Used in Scumm v5 only. Play sounds associated with actors */
void Scumm::playActorSounds() {
	int i;
	Actor *a;
	
	for (i=1; i<13; i++) {
		a = derefActor(i);
		if (a->cost.animCounter2 && a->room==_currentRoom && a->sound) {
			_currentScript = 0xFF;
			addSoundToQueue(a->sound[0]);
			for (i=1; i<13; i++) {
				a = derefActor(i);
				a->cost.animCounter2 = 0;
			}
			return;
		}
	}
}

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;

			j = a->walkdata.destbox;
			if (j) {
				a->walkbox = j;
				a->mask = getMaskFromBox(j);
			}
			startAnimActor(a, a->standFrame, a->facing);
			if (a->walkdata.destdir==0xFF ||
				  a->walkdata.destdir==a->newDirection)
						return;
			a->newDirection = a->walkdata.destdir;
			a->moving = 4;
			return;
		}

		if (a->moving&4) {
			j = getProgrDirChange(a, 0);
			if (a->facing != j) 
				startAnimActor(a, 0x3E, j);
			else
				a->moving = 0;
			return;
		}

		a->walkbox = a->walkdata.curbox;
		a->mask = getMaskFromBox(a->walkdata.curbox);

		setupActorScale(a);
		a->moving = (a->moving&2)|1;
	}

	do {
		a->moving&=~1;
		if (!a->walkbox) {
			a->walkbox = 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==0) {
			a->walkdata.destbox = a->walkbox;
			a->moving |= 8;
			return;
		}
		a->walkdata.curbox = j;
		if (findPathTowards(a, a->walkbox, j, a->walkdata.destbox))
			break;
		if (calcMovementFactor(a, _foundPathX, _foundPathY))
			return;

		a->walkbox = a->walkdata.curbox;
		a->mask = getMaskFromBox(a->walkdata.curbox);
		setupActorScale(a);
	} while (1);
	a->moving |= 8;
	calcMovementFactor(a, a->walkdata.destx, a->walkdata.desty);
}

void Scumm::processActors() {
	int i;
	Actor *actors[13],*a,**ac,**ac2,*tmp;
	int numactors = 0, cnt,cnt2;

	for (i=1; i<13; 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 > (*ac)->y ) {
				tmp = *ac;
				*ac = *ac2;
				*ac2 = tmp;
			}
		} while (ac2++, --cnt2);
	} while (ac++,--cnt);

	ac = actors;
	cnt = numactors;
	do {
		a = *ac;
		if (a->costume) {
			setupActorScale(a);
			setupCostumeRenderer(&cost, a);
			setActorCostPalette(a);
			CHECK_HEAP
			drawActorCostume(a);
			CHECK_HEAP
			actorAnimate(a);
		}
	} while (ac++,--cnt);
}

void Scumm::setupCostumeRenderer(CostumeRenderer *c, Actor *a) {
	c->_actorX = a->x - virtscr->xstart;
	c->_actorY = a->y - a->elevation;
	c->_zbuf = a->mask;
	if (c->_zbuf > gdi._numZBuffer)
		c->_zbuf = (byte)gdi._numZBuffer;
	if (a->neverZClip)
		c->_zbuf = a->neverZClip;
	
	c->_scaleX = a->scalex;
	c->_scaleY = a->scaley;
}

void Scumm::setActorCostPalette(Actor *a) {
	int i;
	byte color;

	cost.loadCostume(a->costume);
	
	for (i=0; i<cost._numColors; i++) {
		color = a->palette[i];
		if (color==255)
			color = cost._ptr[8+i];
		cost._palette[i] = color;
	}
}

void Scumm::drawActorCostume(Actor *a) {
	if (a==NULL || !a->needRedraw)
		return;
	
	a->top = 0xFF;
	a->needRedraw = 0;
	a->bottom = 0;
	cost.loadCostume(a->costume);
	cost._mirror = a->facing!=0 || (cost._ptr[7]&0x80);

	if (cost.drawCostume(a)) {
		a->needRedraw = true;
		a->needBgReset = true;;
	}
}

void Scumm::actorAnimate(Actor *a) {
	if (a==NULL)
		return;
	
	a->animProgress++;
	if (a->animProgress >= a->animSpeed) {
		a->animProgress = 0;
		cost.loadCostume(a->costume);
		if (cost.animate(a)) {
			a->needRedraw = true;
			a->needBgReset = true;
		}
	}
}

void Scumm::setActorRedrawFlags() {
	int i,j;
	int bits;

	for (i=0; i<40; i++) {
		bits = actorDrawBits[_screenStartStrip+i];
		if (bits&0x3FFF) {
			for(j=0; j<13; j++) {
				if ((bits&(1<<j)) && bits!=(1<<j)) {
					Actor *a = derefActor(j);
					a->needRedraw = true;
					a->needBgReset = true;
				}
			}
		}
	}
}

int Scumm::getActorFromPos(int x, int y) {
	uint16 drawbits;
	int i;

	drawbits = actorDrawBits[x>>3];
	if (!(drawbits & 0x3FFF))
		return 0;
	for (i=1; i<13; 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);
	
	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,a->facing);
				_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);

	_xPos = abr.x;
	_yPos = abr.y;

	if (a->room != _currentRoom) {
		a->x = _xPos;
		a->y = _yPos;
		if (dir != 0xFF)
			a->facing = dir;
		return;
	}

	if (a->ignoreBoxes!=0) {
		abr.x = _xPos;
		abr.y = _yPos;
		abr.dist = 0;
		a->walkbox = 0;
	} else {
		if (checkXYInBoxBounds(a->walkdata.destbox, _xPos,_yPos)) {
			abr.x = _xPos;
			abr.y = _yPos;
			abr.dist = a->walkdata.destbox;
		} else {
			abr = adjustXYToBeInBox(a, _xPos, _yPos);
		}
		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) {
		if (dir!=0xFF && dir!=a->facing) {
			a->newDirection = dir;
			a->moving = 4;
		}
		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.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<13; i++) {
			a = derefActor(i);
			if (a->room == _currentRoom && a->costume == cost)
				return true;
		}

	return false;
}