aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLudvig Strigeus2001-10-09 14:30:12 +0000
committerLudvig Strigeus2001-10-09 14:30:12 +0000
commitc30932afbe1af874e3a2aeb95fa4ee5de4d6e38e (patch)
tree192b56f3908880c5a513a366f616341bcb47056e
downloadscummvm-rg350-c30932afbe1af874e3a2aeb95fa4ee5de4d6e38e.tar.gz
scummvm-rg350-c30932afbe1af874e3a2aeb95fa4ee5de4d6e38e.tar.bz2
scummvm-rg350-c30932afbe1af874e3a2aeb95fa4ee5de4d6e38e.zip
Initial revision
svn-id: r3408
-rw-r--r--Makefile26
-rw-r--r--actor.cpp953
-rw-r--r--boxes.cpp839
-rw-r--r--copying.txt341
-rw-r--r--costume.cpp701
-rw-r--r--gfx.cpp1645
-rw-r--r--object.cpp584
-rw-r--r--readme.txt48
-rw-r--r--resource.cpp647
-rw-r--r--saveload.cpp59
-rw-r--r--script.cpp2857
-rw-r--r--scumm.h1234
-rw-r--r--scummsys.h152
-rw-r--r--scummvm.cpp810
-rw-r--r--scummvm.dsp175
-rw-r--r--scummvm.dsw29
-rw-r--r--sdl.cpp213
-rw-r--r--sound.cpp86
-rw-r--r--stdafx.cpp8
-rw-r--r--stdafx.h58
-rw-r--r--string.cpp697
-rw-r--r--sys.cpp164
-rw-r--r--verbs.cpp288
-rw-r--r--whatsnew.txt4
-rw-r--r--windows.cpp787
25 files changed, 13405 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000000..933772a4bf
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,26 @@
+CC = gcc
+CFLAGS = -g -O2 -Wno-multichar
+DEFINES = -DUNIX -DSCUMM_BIG_ENDIAN -DSCUMM_NEED_ALIGNMENT
+LDFLAGS = `sdl-config --libs`
+INCLUDES= `sdl-config --cflags`
+CPPFLAGS= $(DEFINES) $(INCLUDES)
+
+INCS = scumm.h scummsys.h stdafx.h
+
+OBJS = actor.o boxes.o costume.o gfx.o object.o resource.o \
+ saveload.o script.o scummvm.o sound.o string.o \
+ sys.o verbs.o sdl.o
+
+.cpp.o:
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c $(<)
+
+all: scummvm
+
+scummvm: $(OBJS)
+ $(CC) $(LDFLAGS) -o $(@) $(OBJS) $(LIBS)
+
+clean:
+ rm -f $(OBJS) scummvm
+
+check:
+$(OBJS): $(INCS)
diff --git a/actor.cpp b/actor.cpp
new file mode 100644
index 0000000000..ccf1435817
--- /dev/null
+++ b/actor.cpp
@@ -0,0 +1,953 @@
+/* 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.
+ *
+ * Change Log:
+ * $Log$
+ * Revision 1.1 2001/10/09 14:30:14 strigeus
+ * Initial revision
+ *
+ *
+ */
+
+#include "stdafx.h"
+#include "scumm.h"
+
+void Scumm::initActor(Actor *a, int mode) {
+ if (mode) {
+ a->facing = 2;
+ a->costume = 0;
+ a->room = 0;
+ a->x = 0;
+ a->y = 0;
+ }
+
+ a->elevation = 0;
+ a->width = 0x18;
+ a->talkColor = 0xF;
+ a->scaley = a->scalex = 0xFF;
+ a->charset = 0;
+ a->sound = 0;
+ a->moving = 0;
+
+ setActorWalkSpeed(a, 8, 2);
+
+ a->ignoreBoxes = 0;
+ a->neverZClip = 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, int speedx, int 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;
+ int32 tmp;
+
+ 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;
+ }
+
+ tmp = XYFactor >> 16;
+ if (tmp<0)
+ tmp = -tmp;
+
+ if (tmp > 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) * 3 > 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(0xB, 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 && vm.vars[VAR_TALK_ACTOR]==a->number) {
+ clearMsgQueue();
+ }
+
+ a->x = x;
+ a->y = y;
+ a->room = room;
+ a->needRedraw = true;
+ a->needBgReset = true;
+
+ if (vm.vars[VAR_UNK_ACTOR]==a->number) {
+ dseg_3A76 = 1;
+ }
+
+ 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;
+ int threshold;
+ uint best;
+ int box;
+ byte flags, b;
+
+ 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;
+ }
+ } else {
+ abr.x = x;
+ abr.y = y;
+ abr.dist = 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 = abr.dist; /* not a dist */
+ a->walkdata.destbox = 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(3, 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 = vm.vars[VAR_TALK_ACTOR];
+ if (act && act<0x80) {
+ Actor *a = derefActorSafe(act, "stopTalk");
+ if (_currentRoom == a->room) {
+ startAnimActor(a, a->talkFrame2, a->facing);
+ }
+ vm.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);
+ }
+}
+
+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);
+ 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);
+ checkHeap();
+ drawActorCostume(a);
+ checkHeap();
+ 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 > _numZBuffer)
+ c->_zbuf = _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->cost)) {
+ 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();
+ vm.vars[VAR_TALK_ACTOR] = 0xFF;
+ oldact = 0;
+ } else {
+ a = derefActorSafe(_actorToPrintStrFor, "actorTalk");
+ if (a->room!=_currentRoom) {
+ oldact = 0xFF;
+ } else {
+ if (!_keepText)
+ stopTalk();
+ vm.vars[VAR_TALK_ACTOR] = a->number;
+ startAnimActor(a,a->talkFrame1,a->facing);
+ oldact = vm.vars[VAR_TALK_ACTOR];
+ }
+ }
+ if (oldact>=0x80)
+ return;
+
+ if (vm.vars[VAR_TALK_ACTOR]>0x7F) {
+ _charsetColor = _stringColor[0];
+ } else {
+ a = derefActorSafe(vm.vars[VAR_TALK_ACTOR], "actorTalk(2)");
+ _charsetColor = a->talkColor;
+ }
+ charset._bufPos = 0;
+ _talkDelay = 0;
+ _haveMsg = 0xFF;
+ vm.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 = 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(9, a->number);
+ if(ptr==NULL)
+ return (byte*)" ";
+ return ptr;
+}
diff --git a/boxes.cpp b/boxes.cpp
new file mode 100644
index 0000000000..ad64695734
--- /dev/null
+++ b/boxes.cpp
@@ -0,0 +1,839 @@
+/* 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.
+ *
+ * Change Log:
+ * $Log$
+ * Revision 1.1 2001/10/09 14:30:14 strigeus
+ * Initial revision
+ *
+ *
+ */
+
+#include "stdafx.h"
+#include "scumm.h"
+
+byte Scumm::getMaskFromBox(int box) {
+ Box *ptr = getBoxBaseAddr(box);
+ return ptr->mask;
+}
+
+byte Scumm::getBoxFlags(int box) {
+ Box *ptr = getBoxBaseAddr(box);
+ return ptr->flags;
+}
+
+int Scumm::getBoxScale(int box) {
+ Box *ptr = getBoxBaseAddr(box);
+ return FROM_LE_16(ptr->scale);
+}
+
+byte Scumm::getNumBoxes() {
+ byte *ptr = getResourceAddress(0xE, 2);
+ return ptr[8];
+}
+
+Box *Scumm::getBoxBaseAddr(int box) {
+ byte *ptr = getResourceAddress(0xE, 2);
+ checkRange(ptr[8]-1, 0, box, "Illegal box %d");
+ return (Box*)(ptr + box*SIZEOF_BOX + 10);
+}
+
+bool Scumm::checkXYInBoxBounds(int b, int x, int y) {
+ if (b==0)
+ return 0;
+
+ getBoxCoordinates(b);
+
+ if (x < box.upperLeftX && x < box.upperRightX &&
+ x < box.lowerLeftX && x < box.lowerRightX)
+ return 0;
+
+ if (x > box.upperLeftX && x > box.upperRightX &&
+ x > box.lowerLeftX && x > box.lowerRightX)
+ return 0;
+
+ if (y < box.upperLeftY && y < box.upperRightY &&
+ y < box.lowerLeftY && y < box.lowerRightY)
+ return 0;
+
+ if (y > box.upperLeftY && y > box.upperRightY &&
+ y > box.lowerLeftY && y > box.lowerRightY)
+ return 0;
+
+ if (box.upperLeftX == box.upperRightX &&
+ box.upperLeftY == box.upperRightY &&
+ box.lowerLeftX == box.lowerRightX &&
+ box.lowerLeftY == box.lowerRightY ||
+ box.upperLeftX == box.lowerRightX &&
+ box.upperLeftY == box.lowerRightY &&
+ box.upperRightX== box.lowerLeftX &&
+ box.upperRightY== box.lowerLeftY) {
+
+ Point pt;
+ pt = closestPtOnLine(box.upperLeftX, box.upperLeftY, box.lowerLeftX, box.lowerLeftY, x, y);
+ if (distanceFromPt(x, y, pt.x,pt.y) <= 4)
+ return 1;
+ }
+
+ if (!getSideOfLine(
+ box.upperLeftX, box.upperLeftY, box.upperRightX, box.upperRightY, x,y,b))
+ return 0;
+
+ if (!getSideOfLine(
+ box.upperRightX, box.upperRightY, box.lowerLeftX, box.lowerLeftY, x,y,b))
+ return 0;
+
+ if (!getSideOfLine(
+ box.lowerLeftX, box.lowerLeftY, box.lowerRightX, box.lowerRightY, x,y,b))
+ return 0;
+
+ if (!getSideOfLine(
+ box.lowerRightX, box.lowerRightY, box.upperLeftX, box.upperLeftY, x,y,b))
+ return 0;
+
+ return 1;
+}
+
+void Scumm::getBoxCoordinates(int b) {
+ Box *bp = getBoxBaseAddr(b);
+ box.upperLeftX = FROM_LE_16(bp->ulx);
+ box.upperRightX = FROM_LE_16(bp->urx);
+ box.lowerLeftX = FROM_LE_16(bp->llx);
+ box.lowerRightX = FROM_LE_16(bp->lrx);
+ box.upperLeftY = FROM_LE_16(bp->uly);
+ box.upperRightY = FROM_LE_16(bp->ury);
+ box.lowerLeftY = FROM_LE_16(bp->lly);
+ box.lowerRightY = FROM_LE_16(bp->lry);
+}
+
+uint Scumm::distanceFromPt(int x, int y, int ptx, int pty) {
+ int diffx, diffy;
+
+ diffx = ptx - x;
+ if (ptx < x) diffx = x - ptx;
+
+ if (diffx >= 0x100)
+ return 0xFFFF;
+
+ diffy = pty - y;
+ if (pty < y) diffy = y - pty;
+
+ if (diffy >= 0x100)
+ return 0xFFFF;
+ diffx *= diffx;
+ diffy *= diffy;
+ return diffx + diffy;
+}
+
+bool Scumm::getSideOfLine(int x1,int y1, int x2, int y2, int x, int y, int box) {
+ return (x-x1)*(y2-y1) <= (y-y1)*(x2-x1);
+}
+
+Point Scumm::closestPtOnLine(int ulx, int uly, int llx, int lly, int x, int y) {
+ int lydiff,lxdiff;
+ int32 dist,a,b,c;
+ int x2,y2;
+ Point pt;
+
+ if (llx==ulx) {
+ x2 = ulx;
+ y2 = y;
+ } else if (lly==uly) {
+ x2 = x;
+ y2 = uly;
+ } else {
+ lydiff = lly - uly;
+
+ lxdiff = llx - ulx;
+
+ if (abs(lxdiff) > abs(lydiff)) {
+ dist = lxdiff * lxdiff + lydiff * lydiff;
+
+ a = ulx * lydiff / lxdiff;
+ b = x * lxdiff / lydiff;
+
+ c = (a + b - uly + y) * lydiff * lxdiff / dist;
+
+ x2 = c;
+ y2 = c * lydiff / lxdiff - a + uly;
+ } else {
+ dist = lydiff * lydiff + lxdiff * lxdiff;
+
+ a = uly * lxdiff / lydiff;
+ b = y * lydiff / lxdiff;
+
+ c = (a + b - ulx + x) * lydiff * lxdiff / dist;
+
+ y2 = c;
+ x2 = c * lxdiff / lydiff - a + ulx;
+ }
+ }
+
+ lxdiff = llx - ulx;
+ lydiff = lly - uly;
+
+ if (abs(lydiff) < abs(lxdiff)) {
+ if (lxdiff > 0) {
+ if (x2 < ulx) {
+type1:;
+ x2 = ulx;
+ y2 = uly;
+ } else if (x2 > llx) {
+type2:;
+ x2 = llx;
+ y2 = lly;
+ }
+ } else {
+ if (x2 > ulx) goto type1;
+ if (x2 < llx) goto type2;
+ }
+ } else {
+ if (lydiff > 0) {
+ if (y2 < uly) goto type1;
+ if (y2 > lly) goto type2;
+ } else {
+ if (y2 > uly) goto type1;
+ if (y2 < lly) goto type2;
+ }
+ }
+
+ pt.x = x2;
+ pt.y = y2;
+ return pt;
+}
+
+bool Scumm::inBoxQuickReject(int b, int x, int y, int threshold) {
+ int t;
+
+ getBoxCoordinates(b);
+
+ if (threshold==0)
+ return 1;
+
+ t = x - threshold;
+ if (t > box.upperLeftX && t > box.upperRightX &&
+ t > box.lowerLeftX && t > box.lowerRightX)
+ return 0;
+
+ t = x + threshold;
+ if (t < box.upperLeftX && t < box.upperRightX &&
+ t < box.lowerLeftX && t < box.lowerRightX)
+ return 0;
+
+ t = y - threshold;
+ if (t > box.upperLeftY && t > box.upperRightY &&
+ t > box.lowerLeftY && t > box.lowerRightY)
+ return 0;
+
+ t = y + threshold;
+ if (t < box.upperLeftY && t < box.upperRightY &&
+ t < box.lowerLeftY && t < box.lowerRightY)
+ return 0;
+
+ return 1;
+}
+
+AdjustBoxResult Scumm::getClosestPtOnBox(int b, int x, int y) {
+ Point pt;
+ AdjustBoxResult best;
+ uint dist;
+ uint bestdist = (uint)0xFFFF;
+
+ getBoxCoordinates(b);
+
+ pt = closestPtOnLine(box.upperLeftX,box.upperLeftY,box.upperRightX,box.upperRightY,x,y);
+ dist = distanceFromPt(x, y, pt.x, pt.y);
+ if (dist < bestdist) {
+ bestdist = dist;
+ best.x = pt.x;
+ best.y = pt.y;
+ }
+
+ pt = closestPtOnLine(box.upperRightX,box.upperRightY,box.lowerLeftX,box.lowerLeftY,x,y);
+ dist = distanceFromPt(x, y, pt.x, pt.y);
+ if (dist < bestdist) {
+ bestdist = dist;
+ best.x = pt.x;
+ best.y = pt.y;
+ }
+
+ pt = closestPtOnLine(box.lowerLeftX,box.lowerLeftY,box.lowerRightX,box.lowerRightY,x,y);
+ dist = distanceFromPt(x, y, pt.x, pt.y);
+ if (dist < bestdist) {
+ bestdist = dist;
+ best.x = pt.x;
+ best.y = pt.y;
+ }
+
+ pt = closestPtOnLine(box.lowerRightX,box.lowerRightY,box.upperLeftX,box.upperLeftY,x,y);
+ dist = distanceFromPt(x, y, pt.x, pt.y);
+ if (dist < bestdist) {
+ bestdist = dist;
+ best.x = pt.x;
+ best.y = pt.y;
+ }
+
+ best.dist = bestdist;
+ return best;
+}
+
+byte *Scumm::getBoxMatrixBaseAddr() {
+ byte *ptr = getResourceAddress(0xE, 1) + 8;
+ if (*ptr==0xFF) ptr++;
+ return ptr;
+}
+
+int Scumm::getPathToDestBox(int from, int to) {
+ byte *boxm;
+ int i;
+
+ if (from==to)
+ return to;
+
+ boxm = getBoxMatrixBaseAddr();
+
+ i=0;
+ while (i != from) {
+ while (*boxm != 0xFF)
+ boxm += 3;
+ i++;
+ boxm++;
+ }
+
+ while (boxm[0]!=0xFF) {
+ if (boxm[0] <= to && boxm[1]>=to)
+ return boxm[2];
+ boxm+=3;
+ }
+ return 0;
+}
+
+int Scumm::findPathTowards(Actor *a, int box1, int box2, int box3) {
+ int upperLeftX, upperLeftY;
+ int upperRightX, upperRightY;
+ int lowerLeftX, lowerLeftY;
+ int lowerRightX, lowerRightY;
+ int i,j,m,n,p,q,r;
+ int tmp_x, tmp_y;
+ int tmp;
+
+ getBoxCoordinates(box1);
+ upperLeftX = box.upperLeftX;
+ upperLeftY = box.upperLeftY;
+ upperRightX = box.upperRightX;
+ upperRightY = box.upperRightY;
+ lowerLeftX = box.lowerLeftX;
+ lowerLeftY = box.lowerLeftY;
+ lowerRightX = box.lowerRightX;
+ lowerRightY = box.lowerRightY;
+ getBoxCoordinates(box2);
+
+ i = 0;
+ do {
+ if (i >= 4) goto ExitPos;
+ for (j=0; j<4; j++) {
+ if (upperRightX==upperLeftX &&
+ box.upperLeftX==upperLeftX &&
+ box.upperRightX==upperRightX) {
+
+ExitPos:;
+ n = m = 0;
+ if (upperRightY < upperLeftY) {
+ m = 1;
+ SWAP(upperRightY, upperLeftY);
+ }
+ if (box.upperRightY < box.upperLeftY) {
+ n = 1;
+ SWAP(box.upperRightY, box.upperLeftY);
+ }
+ if (box.upperRightY >= upperLeftY &&
+ box.upperLeftY <= upperRightY &&
+ (box.upperLeftY != upperRightY &&
+ box.upperRightY!= upperLeftY ||
+ upperRightY==upperLeftY ||
+ box.upperRightY==box.upperLeftY)) {
+ if (box2==box3) {
+ m = a->walkdata.destx - a->x;
+ p = a->walkdata.desty - a->y;
+ tmp = upperLeftX - a->x;
+ i = a->y;
+ if (m) {
+ q = tmp * p;
+ r = q/m;
+ if (r==0 && (q<=0 || m<=0) && (q>=0 || m>=0)) {
+ r = -1;
+ }
+ i += r;
+ }
+ } else {
+ i = a->y;
+ }
+ q = i;
+ if (q < box.upperLeftY)
+ q = box.upperLeftY;
+ if (q > box.upperRightY)
+ q = box.upperRightY;
+ if (q < upperLeftY)
+ q = upperLeftY;
+ if (q > upperRightY)
+ q = upperRightY;
+ if (q==i && box2==box3)
+ return 1;
+ _foundPathX = upperLeftX;
+ _foundPathY = q;
+ return 0;
+ } else {
+ if (m) {
+ SWAP(upperRightY, upperLeftY);
+ }
+ if (n) {
+ SWAP(box.upperRightY, box.upperLeftY);
+ }
+ }
+ }
+ if (upperLeftY==upperRightY &&
+ box.upperLeftY==upperLeftY &&
+ box.upperRightY==upperRightY) {
+ n = m = 0;
+ if(upperRightX < upperLeftX) {
+ m = 1;
+ SWAP(upperRightX, upperLeftX);
+ }
+ if (box.upperRightX < box.upperLeftX) {
+ n = 1;
+ SWAP(box.upperRightX, box.upperLeftX);
+ }
+ if (box.upperRightX >= upperLeftX &&
+ box.upperLeftX <= upperRightX &&
+ (box.upperLeftX != upperRightX &&
+ box.upperRightX!= upperLeftX ||
+ upperRightX==upperLeftX ||
+ box.upperRightX==box.upperLeftX)) {
+ if (box2==box3) {
+ m = a->walkdata.destx - a->x;
+ p = a->walkdata.desty - a->y;
+ i = upperLeftY - a->y;
+ tmp = a->x;
+ if (p) {
+ tmp += i * m / p;
+ }
+ } else {
+ tmp = a->x;
+ }
+ q = tmp;
+ if (q < box.upperLeftX)
+ q = box.upperLeftX;
+ if (q > box.upperRightX)
+ q = box.upperRightX;
+ if (q < upperLeftX)
+ q = upperLeftX;
+ if (q > upperRightX)
+ q = upperRightX;
+ if (tmp==q && box2==box3)
+ return 1;
+ _foundPathX = q;
+ _foundPathY = upperLeftY;
+ return 0;
+ } else {
+ if (m != 0) {
+ SWAP(upperRightX, upperLeftX);
+ }
+ if (n != 0) {
+ SWAP(box.upperRightX, box.upperLeftX);
+ }
+ }
+ }
+ tmp_x = upperLeftX;
+ tmp_y = upperLeftY;
+ upperLeftX = upperRightX;
+ upperLeftY = upperRightY;
+ upperRightX = lowerLeftX;
+ upperRightY = lowerLeftY;
+ lowerLeftX = lowerRightX;
+ lowerLeftY = lowerRightY;
+ lowerRightX = tmp_x;
+ lowerRightY = tmp_y;
+ }
+
+ tmp_x = box.upperLeftX;
+ tmp_y = box.upperLeftY;
+ box.upperLeftX = box.upperRightX;
+ box.upperLeftY = box.upperRightY;
+ box.upperRightX = box.lowerLeftX;
+ box.upperRightY = box.lowerLeftY;
+ box.lowerLeftX = box.lowerRightX;
+ box.lowerLeftY = box.lowerRightY;
+ box.lowerRightX = tmp_x;
+ box.lowerRightY = tmp_y;
+ i++;
+ } while (1);
+}
+
+
+void Scumm::setBoxFlags(int box, int val) {
+ Box *b = getBoxBaseAddr(box);
+ b->flags = val;
+}
+
+void Scumm::setBoxScale(int box, int scale) {
+ Box *b = getBoxBaseAddr(box);
+ b->scale = scale;
+}
+
+#define BOX_MATRIX_SIZE 2000
+
+void Scumm::createBoxMatrix() {
+ byte *matrix_ptr;
+ int num,i,j;
+ byte flags;
+ int table_1[66],table_2[66];
+ int counter,val;
+ int code;
+
+ PathVertex *vtx;
+ PathNode *node, *node2;
+
+ _maxBoxVertexHeap = 1000;
+
+ createResource(0xE, 4, 1000);
+ createResource(0xE, 3, 4160); //65 items of something of size 64
+ createResource(0xE, 1, BOX_MATRIX_SIZE+8);
+
+ matrix_ptr = getResourceAddress(0xE, 1);
+
+ /* endian & alignment safe */
+ ((uint32*)matrix_ptr)[1] = TO_BE_32(BOX_MATRIX_SIZE+8);
+ ((uint32*)matrix_ptr)[0] = MKID('BOXM');
+
+ _boxMatrixPtr4 = getResourceAddress(0xE, 4);
+ _boxMatrixPtr1 = getResourceAddress(0xE, 1) + 8;
+ _boxMatrixPtr3 = getResourceAddress(0xE, 3);
+
+ _boxPathVertexHeapIndex = _boxMatrixItem = 0;
+
+ num = getNumBoxes();
+
+ for (i=0; i<num; i++) {
+ for (j=0; j<num; j++) {
+ if (i==j) {
+ _boxMatrixPtr3[i*64+j] = 0;
+ } else if (areBoxesNeighbours(i, j)) {
+ _boxMatrixPtr3[i*64+j] = 1;
+ } else {
+ _boxMatrixPtr3[i*64+j] = 250;
+ }
+ }
+ }
+
+ for (j=0; j<num; j++) {
+ flags = getBoxFlags(j);
+ if (flags & 0x80) {
+ addToBoxMatrix(0xFF);
+ addToBoxMatrix(j);
+ addToBoxMatrix(j);
+ addToBoxMatrix(j);
+ } else {
+ vtx = addPathVertex();
+ for (i=0; i<num; i++) {
+ flags = getBoxFlags(j);
+ if (!(flags&0x80)) {
+ node = unkMatrixProc2(vtx, i);
+ if (i==j)
+ node2 = node;
+ }
+ }
+ table_1[j] = 0;
+ table_2[j] = j;
+ vtx = unkMatrixProc1(vtx, node2);
+ node = vtx ? vtx->left : NULL;
+
+ counter = 250;
+ while (node) {
+ val = _boxMatrixPtr3[j*64 + node->index];
+ table_1[node->index] = val;
+ if (val<counter) counter=val;
+
+ if (table_1[node->index]!=250)
+ table_2[node->index] = node->index;
+ else
+ table_2[node->index] = -1;
+
+ node = node->left;
+ }
+
+ while (vtx) {
+ counter = 250;
+ node2 = node = vtx->left;
+
+ while (node) {
+ if ( table_1[node->index] < counter ) {
+ counter = table_1[node->index];
+ node2 = node;
+ }
+ node = node->left;
+ }
+ vtx = unkMatrixProc1(vtx, node2);
+ node = vtx ? vtx->left : NULL;
+ while (node) {
+ code = _boxMatrixPtr3[node2->index * 64 + node->index];
+ code += table_1[node2->index];
+ if (code < table_1[node->index]) {
+ table_1[node->index] = code;
+ table_2[node->index] = table_2[node2->index];
+ }
+ node = node->left;
+ }
+ }
+
+ addToBoxMatrix(0xFF);
+ for (i=1; i<num;) {
+ if (table_2[i-1]!=-1) {
+ addToBoxMatrix(i-1); /* lo */
+ if (table_2[i-1] != table_2[i]) {
+ addToBoxMatrix(i-1); /* hi */
+ addToBoxMatrix(table_2[i-1]); /* dst */
+ } else {
+ while (table_2[i-1] == table_2[i]) {
+ if (++i==num)
+ break;
+ }
+ addToBoxMatrix(i-1); /* hi */
+ addToBoxMatrix(table_2[i-1]); /* dst */
+ }
+ }
+ if (++i==num && table_2[i-1]!=-1) {
+ addToBoxMatrix(i-1); /* lo */
+ addToBoxMatrix(i-1); /* hi */
+ addToBoxMatrix(table_2[i-1]); /* dest */
+ }
+ }
+ }
+ }
+
+ addToBoxMatrix(0xFF);
+ nukeResource(0xE, 4);
+ nukeResource(0xE, 3);
+}
+
+PathVertex *Scumm::unkMatrixProc1(PathVertex *vtx, PathNode *node) {
+ if (node==NULL || vtx==NULL)
+ return NULL;
+
+ if (!node->right) {
+ vtx->left = node->left;
+ } else {
+ node->right->left = node->left;
+ }
+
+ if (!node->left) {
+ vtx->right = node->right;
+ } else {
+ node->left->right = node->right;
+ }
+
+ if (vtx->left)
+ return vtx;
+
+ return NULL;
+}
+
+PathNode *Scumm::unkMatrixProc2(PathVertex *vtx, int i) {
+ PathNode *node;
+
+ if (vtx==NULL)
+ return NULL;
+
+ if (!vtx->right) {
+ node = (PathNode*)addToBoxVertexHeap(sizeof(PathNode));
+ vtx->left = vtx->right = node;
+
+ node->index = i;
+ node->left = 0;
+ node->right = 0;
+ } else {
+ node = (PathNode*)addToBoxVertexHeap(sizeof(PathNode));
+ vtx->right->left = node;
+
+ node->right = vtx->right;
+ node->index = i;
+ node->left = 0;
+
+ vtx->right = node;
+ }
+
+ return vtx->right;
+}
+
+/* Check if two boxes are neighbours */
+bool Scumm::areBoxesNeighbours(int box1, int box2) {
+ int upperLeftX, upperLeftY;
+ int upperRightX, upperRightY;
+ int lowerLeftX, lowerLeftY;
+ int lowerRightX, lowerRightY;
+ int j,k,m,n;
+ int tmp_x, tmp_y;
+ bool result;
+
+ if (getBoxFlags(box1)&0x80 || getBoxFlags(box2)&0x80)
+ return false;
+
+ getBoxCoordinates(box1);
+
+ upperLeftX = box.upperLeftX;
+ upperLeftY = box.upperLeftY;
+ upperRightX = box.upperRightX;
+ upperRightY = box.upperRightY;
+ lowerLeftX = box.lowerLeftX;
+ lowerLeftY = box.lowerLeftY;
+ lowerRightX = box.lowerRightX;
+ lowerRightY = box.lowerRightY;
+
+ getBoxCoordinates(box2);
+
+ result = false;
+ j = 4;
+
+ do {
+ k = 4;
+ do {
+ if (upperRightX == upperLeftX &&
+ box.upperLeftX == upperLeftX &&
+ box.upperRightX == upperRightX) {
+ /* 5b74 */
+ n = m = 0;
+ if (upperRightY < upperLeftY) {
+ n = 1;
+ SWAP(upperRightY, upperLeftY);
+ }
+ if (box.upperRightY < box.upperLeftY) {
+ m = 1;
+ SWAP(box.upperRightY, box.upperLeftY);
+ }
+ if (box.upperRightY < upperLeftY ||
+ box.upperLeftY > upperRightY ||
+ (box.upperLeftY == upperRightY ||
+ box.upperRightY==upperLeftY) &&
+ upperRightY != upperLeftY &&
+ box.upperLeftY!=box.upperRightY) {
+ /* if_1_if */
+ if (n) {
+ SWAP(upperRightY, upperLeftY);
+ }
+ if (m) {
+ SWAP(box.upperRightY, box.upperLeftY);
+ }
+ } else {
+ /* if_1_else */
+ if (n) {
+ SWAP(upperRightY, upperLeftY);
+ }
+ if (m) {
+ SWAP(box.upperRightY, box.upperLeftY);
+ }
+ result = true;
+ }
+ }
+
+ /* do_it_for_y */
+ if (upperRightY == upperLeftY &&
+ box.upperLeftY == upperLeftY &&
+ box.upperRightY == upperRightY) {
+ n = m = 0;
+ if (upperRightX < upperLeftX) {
+ n = 1;
+ SWAP(upperRightX, upperLeftX);
+ }
+ if (box.upperRightX < box.upperLeftX) {
+ m = 1;
+ SWAP(box.upperRightX, box.upperLeftX);
+ }
+ if (box.upperRightX < upperLeftX ||
+ box.upperLeftX > upperRightX ||
+ (box.upperLeftX == upperRightX ||
+ box.upperRightX==upperLeftX) &&
+ upperRightX != upperLeftX &&
+ box.upperLeftX!=box.upperRightX) {
+
+ /* if_2_if */
+ if (n) {
+ SWAP(upperRightX, upperLeftX);
+ }
+ if (m) {
+ SWAP(box.upperRightX, box.upperLeftX);
+ }
+ } else {
+ /* if_2_else */
+ if (n) {
+ SWAP(upperRightX, upperLeftX);
+ }
+ if (m) {
+ SWAP(box.upperRightX, box.upperLeftX);
+ }
+ result = true;
+ }
+ }
+
+ tmp_x = upperLeftX;
+ tmp_y = upperLeftY;
+ upperLeftX = upperRightX;
+ upperLeftY = upperRightY;
+ upperRightX = lowerLeftX;
+ upperRightY = lowerLeftY;
+ lowerLeftX = lowerRightX;
+ lowerLeftY = lowerRightY;
+ lowerRightX = tmp_x;
+ lowerRightY = tmp_y;
+ } while (--k);
+
+ tmp_x = box.upperLeftX;
+ tmp_y = box.upperLeftY;
+ box.upperLeftX = box.upperRightX;
+ box.upperLeftY = box.upperRightY;
+ box.upperRightX = box.lowerLeftX;
+ box.upperRightY = box.lowerLeftY;
+ box.lowerLeftX = box.lowerRightX;
+ box.lowerLeftY = box.lowerRightY;
+ box.lowerRightX = tmp_x;
+ box.lowerRightY = tmp_y;
+ } while (--j);
+
+ return result;
+}
+
+void Scumm::addToBoxMatrix(byte b) {
+ if (++_boxMatrixItem > BOX_MATRIX_SIZE)
+ error("Box matrix overflow");
+ *_boxMatrixPtr1++ = b;
+}
+
+void *Scumm::addToBoxVertexHeap(int size) {
+ byte *ptr = _boxMatrixPtr4;
+
+ _boxMatrixPtr4 += size;
+ _boxPathVertexHeapIndex += size;
+
+ if (_boxPathVertexHeapIndex >= _maxBoxVertexHeap)
+ error("Box path vertex heap overflow");
+
+ return ptr;
+}
+
+PathVertex *Scumm::addPathVertex() {
+ _boxMatrixPtr4 = getResourceAddress(0xE, 4);
+ _boxPathVertexHeapIndex = 0;
+ return (PathVertex*)addToBoxVertexHeap(sizeof(PathVertex));
+}
diff --git a/copying.txt b/copying.txt
new file mode 100644
index 0000000000..bf35a23684
--- /dev/null
+++ b/copying.txt
@@ -0,0 +1,341 @@
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/costume.cpp b/costume.cpp
new file mode 100644
index 0000000000..6fa98e8165
--- /dev/null
+++ b/costume.cpp
@@ -0,0 +1,701 @@
+/* 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.
+ *
+ * Change Log:
+ * $Log$
+ * Revision 1.1 2001/10/09 14:30:14 strigeus
+ * Initial revision
+ *
+ *
+ */
+
+#include "stdafx.h"
+#include "scumm.h"
+
+const byte revBitMask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
+
+void CostumeRenderer::ignorePakCols(int a) {
+ int n;
+ n = _height;
+ if (a>1) n *= a;
+ do {
+ _repcolor = *_srcptr++;
+ _replen = _repcolor&_maskval;
+ if (_replen==0) {
+ _replen = *_srcptr++;
+ }
+ do {
+ if (!--n) {
+ _repcolor >>= _shrval;
+ return;
+ }
+ } while (--_replen);
+ } while (1);
+}
+
+const byte cost_scaleTable[256] = {
+255, 253, 125, 189, 61, 221, 93, 157, 29, 237,
+109, 173, 45, 205, 77, 141, 13, 245, 117, 181,
+53, 213, 85, 149, 21, 229, 101, 165, 37, 197, 69,
+133, 5, 249, 121, 185, 57, 217, 89, 153, 25, 233,
+105, 169, 41, 201, 73, 137, 9, 241, 113, 177, 49,
+209, 81, 145, 17, 225, 97, 161, 33, 193, 65, 129,
+1, 251, 123, 187, 59, 219, 91, 155, 27, 235, 107,
+171, 43, 203, 75, 139, 11, 243, 115, 179, 51, 211,
+83, 147, 19, 227, 99, 163, 35, 195, 67, 131, 3,
+247, 119, 183, 55, 215, 87, 151, 23, 231, 103,
+167, 39, 199, 71, 135, 7, 239, 111, 175, 47, 207,
+79, 143, 15, 223, 95, 159, 31, 191, 63, 127, 0,
+128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208,
+48, 176, 112, 240, 8, 136, 72, 200, 40, 168, 104,
+232, 24, 152, 88, 216, 56, 184, 120, 248, 4, 132,
+68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52,
+180, 116, 244, 12, 140, 76, 204, 44, 172, 108,
+236, 28, 156, 92, 220, 60, 188, 124, 252, 2, 130,
+66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50,
+178, 114, 242, 10, 138, 74, 202, 42, 170, 106,
+234, 26, 154, 90, 218, 58, 186, 122, 250, 6, 134,
+70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54,
+182, 118, 246, 14, 142, 78, 206, 46, 174, 110,
+238, 30, 158, 94, 222, 62, 190, 126, 254
+};
+
+byte CostumeRenderer::mainRoutine(Actor *a, int slot, int frame) {
+ int xmove, ymove, i,b,s;
+ uint scal;
+ byte scaling;
+ byte charsetmask, masking;
+ byte unk19;
+
+ checkHeap();
+
+ _maskval = 0xF;
+ _shrval = 4;
+ if (_numColors == 32) {
+ _maskval = 7;
+ _shrval = 3;
+ }
+
+ _width2 = _srcptr[0];
+ _width = _width2;
+ _height2 = _srcptr[2];
+ _height = _height2;
+ xmove = (int16)READ_LE_UINT16(_srcptr+4) + _xmove;
+ ymove = (int16)READ_LE_UINT16(_srcptr+6) + _ymove;
+ _xmove += (int16)READ_LE_UINT16(_srcptr+8);
+ _ymove -= (int16)READ_LE_UINT16(_srcptr+10);
+ _srcptr += 12;
+
+ _xpos = _actorX;
+ _ypos = _actorY;
+
+ scaling = _scaleX==255 && _scaleY==255 ? 0 : 1;
+ s = 0;
+
+ if (scaling) {
+ _scaleIndexXStep = -1;
+ if (xmove < 0) {
+ xmove = -xmove;
+ _scaleIndexXStep = 1;
+ }
+
+ if(_mirror) {
+ unk19 = _scaleIndexX = 128 - xmove;
+ for (i=0; i<xmove; i++) {
+ scal = cost_scaleTable[_scaleIndexX++];
+ if (scal < _scaleX)
+ _xpos -= _scaleIndexXStep;
+ }
+ _right = _left = _xpos;
+ _scaleIndexX = unk19;
+ for (i=0; i<_width; i++) {
+ if (_right < 0) {
+ s++;
+ unk19 = _scaleIndexX;
+ }
+ scal = cost_scaleTable[_scaleIndexX++];
+ if (scal < _scaleX)
+ _right++;
+ }
+ } else {
+ unk19 = _scaleIndexX = xmove + 128;
+ for (i=0; i<xmove; i++) {
+ scal = cost_scaleTable[_scaleIndexX--];
+ if (scal < _scaleX)
+ _xpos += _scaleIndexXStep;
+ }
+ _right = _left = _xpos;
+ _scaleIndexX = unk19;
+ for (i=0; i<_width; i++) {
+ if (_left > 319) {
+ s++;
+ unk19 = _scaleIndexX;
+ }
+ scal = cost_scaleTable[_scaleIndexX--];
+ if(scal < _scaleX)
+ _left--;
+ }
+ }
+ _scaleIndexX = unk19;
+ if (s)
+ s--;
+ _scaleIndexYStep = -1;
+ if (ymove < 0) {
+ ymove = -ymove;
+ _scaleIndexYStep = 1;
+ }
+ _scaleIndexY = 128 - ymove;
+ for (i=0; i<ymove; i++) {
+ scal = cost_scaleTable[_scaleIndexY++];
+ if (scal < _scaleY)
+ _ypos -= _scaleIndexYStep;
+ }
+ _top = _bottom = _ypos;
+ _scaleIndexY = 128 - ymove;
+ for (i=0; i<_height; i++) {
+ scal = cost_scaleTable[_scaleIndexY++];
+ if (scal < _scaleY)
+ _bottom++;
+ }
+ _scaleIndexY = _scaleIndexYTop = 128 - ymove;
+ } else {
+ if(_mirror==0)
+ xmove = -xmove;
+ _xpos += xmove;
+ _ypos += ymove;
+ if (_mirror) {
+ _left = _xpos;
+ _right = _xpos + _width;
+ } else {
+ _left = _xpos - _width;
+ _right = _xpos;
+ }
+ _top = _ypos;
+ _bottom = _top + _height;
+ }
+
+ _scaleIndexXStep = -1;
+ if (_mirror)
+ _scaleIndexXStep = 1;
+ _ypostop = _ypos;
+ _vscreenheight = _vm->virtscr[0].height;
+ _vm->updateDirtyRect(0, _left, _right+1,_top,_bottom,1<<a->number);
+
+ if ((int)_top >= (int)_vscreenheight || _bottom <= 0) {
+ checkHeap();
+ return 0;
+ }
+
+ _ypitch = _height * 320;
+ _docontinue = 0;
+ b = 1;
+ if (_left > 319 || _right <= 0)
+ return 0;
+ if (_mirror) {
+ _ypitch--;
+ if (scaling==0) {
+ s = -_xpos;
+ }
+ if (s > 0) {
+ _width2 -= s;
+ ignorePakCols(s);
+ _xpos = 0;
+ _docontinue = 1;
+ } else {
+ s = _right - 320;
+ if (s<=0) {
+ b = 2;
+ } else {
+ _width2 -= s;
+ }
+ }
+ } else {
+ _ypitch++;
+ if(scaling==0)
+ s = _right - 320;
+ if (s > 0) {
+ _width2 -= s;
+ ignorePakCols(s);
+ _xpos = 319;
+ _docontinue = 1;
+ } else {
+ s = -1 - _left;
+ if (s <= 0)
+ b = 2;
+ else
+ _width2 -= s;
+ }
+ }
+
+ if (_top > _vscreenheight || _top < 0)
+ _top = 0;
+
+ if (_bottom > _vscreenheight)
+ _bottom = _vscreenheight;
+
+ if (a->top > _top)
+ a->top = _top;
+
+ if (a->bottom < _bottom)
+ a->bottom = _bottom;
+
+ if (_height2 + _top >= 256) {
+ checkHeap();
+ return 2;
+ }
+
+ _where_to_draw_ptr = _vm->getResourceAddress(0xA, 5) + _vm->virtscr[0].xstart + _ypos*320 + _xpos;
+ _bg_ptr = _vm->getResourceAddress(0xA, 1) + _vm->virtscr[0].xstart + _ypos*320 + _xpos;
+ charsetmask = _vm->hasCharsetMask(_left, _top + _vm->virtscr[0].topline, _right, _vm->virtscr[0].topline + _bottom);
+ masking = 0;
+
+ if (_zbuf) {
+ masking = _vm->isMaskActiveAt(_left, _top, _right, _bottom,
+ _vm->getResourceAddress(0xA, 9) + _vm->_imgBufOffs[_zbuf] + _vm->_screenStartStrip
+ );
+ }
+
+ if (_zbuf || charsetmask) {
+ _mask_ptr = _vm->getResourceAddress(0xA, 9) + _ypos*40 + _vm->_screenStartStrip;
+
+ _imgbufoffs = _vm->_imgBufOffs[_zbuf];
+ if (!charsetmask && _zbuf!=0)
+ _mask_ptr += _imgbufoffs;
+ _mask_ptr_dest = _mask_ptr + _xpos / 8;
+ }
+
+ checkHeap();
+
+ switch ((scaling<<2)|(masking<<1)|charsetmask) {
+ case 0:
+ proc6();
+ break;
+ case 1: case 2:
+ proc5();
+ break;
+ case 3:
+ proc4();
+ break;
+ case 4:
+ proc1();
+ break;
+ case 5:case 6:
+ proc2();
+ break;
+ case 7:
+ proc3();
+ break;
+ }
+
+ checkHeap();
+ return b;
+}
+
+void CostumeRenderer::proc6() {
+ byte len;
+ byte *src, *dst;
+ byte width,height,pcolor;
+ int color;
+ uint y;
+ uint scrheight;
+
+ y = _ypos;
+ len = _replen;
+ src = _srcptr;
+ dst = _bg_ptr;
+ color = _repcolor;
+ scrheight = _vscreenheight;
+ width = _width2;
+ height = _height2;
+
+ if (_docontinue) goto StartPos;
+
+ do {
+ len = *src++;
+ color = len>>_shrval;
+ len &= _maskval;
+ if (!len) len = *src++;
+
+ do {
+ if (color && y < scrheight) {
+ pcolor = _palette[color];
+ if (pcolor==13) {
+ pcolor = _transEffect[*dst];
+ }
+ *dst = pcolor;
+ }
+
+ dst += 320;
+ y++;
+ if (!--height) {
+ if (!--width)
+ return;
+ height = _height;
+ dst -= _ypitch;
+ y = _ypostop;
+ }
+StartPos:;
+ } while (--len);
+ } while (1);
+}
+
+void CostumeRenderer::proc5() {
+ byte *mask,*src,*dst;
+ byte maskbit,len,height,pcolor;
+ uint y,scrheight;
+ int color;
+
+ mask = _mask_ptr = _mask_ptr_dest;
+ maskbit = revBitMask[_xpos&7];
+ y = _ypos;
+ src = _srcptr;
+ dst = _bg_ptr;
+ len = _replen;
+ color = _repcolor;
+ scrheight = _vscreenheight;
+ height = _height2;
+
+ if (_docontinue) goto StartPos;
+
+ do {
+ len = *src++;
+ color = len>>_shrval;
+ len &= _maskval;
+ if (!len) len = *src++;
+
+ do {
+ if (color && y<scrheight && !(*mask&maskbit)) {
+ pcolor = _palette[color];
+ if (pcolor==13)
+ pcolor = _transEffect[*dst];
+ *dst = pcolor;
+ }
+ dst += 320;
+ y++;
+ mask += 40;
+ if (!--height) {
+ if(!--_width2)
+ return;
+ height = _height;
+ dst -= _ypitch;
+ y = _ypostop;
+ if(_scaleIndexXStep!=1) {
+ maskbit<<=1;
+ if (!maskbit) {
+ maskbit=1;
+ _mask_ptr--;
+ }
+ } else {
+ maskbit>>=1;
+ if (!maskbit) {
+ maskbit=0x80;
+ _mask_ptr++;
+ }
+ }
+ mask = _mask_ptr;
+ }
+StartPos:;
+ } while (--len);
+ } while(1);
+}
+
+void CostumeRenderer::proc4() {
+ byte *mask,*src,*dst;
+ byte maskbit,len,height,pcolor;
+ uint y,scrheight;
+ int color;
+
+ mask = _mask_ptr = _mask_ptr_dest;
+ maskbit = revBitMask[_xpos&7];
+ y = _ypos;
+ src = _srcptr;
+ dst = _bg_ptr;
+ len = _replen;
+ color = _repcolor;
+ scrheight = _vscreenheight;
+ height = _height2;
+
+ if (_docontinue) goto StartPos;
+
+ do {
+ len = *src++;
+ color = len>>_shrval;
+ len &= _maskval;
+ if (!len) len = *src++;
+
+ do {
+ if (color && y<scrheight && !((*mask|mask[_imgbufoffs])&maskbit)) {
+ pcolor = _palette[color];
+ if (pcolor==13)
+ pcolor = _transEffect[*dst];
+ *dst = pcolor;
+ }
+ dst += 320;
+ y++;
+ mask += 40;
+ if (!--height) {
+ if(!--_width2)
+ return;
+ height = _height;
+ dst -= _ypitch;
+ y = _ypostop;
+ if(_scaleIndexXStep!=1) {
+ maskbit<<=1;
+ if (!maskbit) {
+ maskbit=1;
+ _mask_ptr--;
+ }
+ } else {
+ maskbit>>=1;
+ if (!maskbit) {
+ maskbit=0x80;
+ _mask_ptr++;
+ }
+ }
+ mask = _mask_ptr;
+ }
+StartPos:;
+ } while (--len);
+ } while(1);
+}
+
+void CostumeRenderer::proc3() {
+ warning("COST_Proc3: not implemented");
+}
+
+void CostumeRenderer::proc2() {
+ byte *mask,*src,*dst;
+ byte maskbit,len,height,pcolor,width;
+ int color,t;
+ uint y;
+
+ mask = _mask_ptr_dest;
+ dst = _bg_ptr;
+ height = _height2;
+ width = _width2;
+ len = _replen;
+ color = _repcolor;
+ src = _srcptr;
+ maskbit = revBitMask[_xpos&7];
+ y = _ypos;
+
+ if (_docontinue) goto StartPos;
+
+ do {
+ len = *src++;
+ color = len>>_shrval;
+ len &= _maskval;
+ if (!len) len = *src++;
+ do {
+ if (cost_scaleTable[_scaleIndexY++] < _scaleY) {
+ if (color && y < _vscreenheight && !(*mask&maskbit)) {
+ pcolor = _palette[color];
+ if (pcolor==13)
+ pcolor = _transEffect[*dst];
+ *dst = pcolor;
+ }
+ dst += 320;
+ mask += 40;
+ y++;
+ }
+ if (!--height) {
+ if(!--width)
+ return;
+ height = _height;
+ y = _ypostop;
+ _scaleIndexY = _scaleIndexYTop;
+ t = _scaleIndexX;
+ _scaleIndexX = t + _scaleIndexXStep;
+ if (cost_scaleTable[t] < _scaleX) {
+ _xpos += _scaleIndexXStep;
+ if (_xpos >= 320)
+ return;
+ maskbit = revBitMask[_xpos&7];
+ _bg_ptr += _scaleIndexXStep;
+ }
+ dst = _bg_ptr;
+ mask = _mask_ptr + (_xpos>>3);
+ }
+StartPos:;
+ } while (--len);
+ } while(1);
+
+}
+
+void CostumeRenderer::proc1() {
+ byte *mask,*src,*dst;
+ byte maskbit,len,height,pcolor,width;
+ uint y;
+ int color;
+ int t;
+
+#if 0
+ debug(1, "proc1(): (%d %d),(%d %d %d),(%d %d %d),(%d %d,%d %d,%d %d),(%d %d)",
+ _xpos, _ypos,
+ _width2, _height2, _height,
+ _replen,_repcolor,_docontinue,
+ _scaleX, _scaleY, _scaleIndexX, _scaleIndexY,
+ _scaleIndexXStep, _scaleIndexYStep,
+ _scaleIndexYTop,_vscreenheight
+ );
+#endif
+
+ mask = _mask_ptr = _mask_ptr_dest;
+ maskbit = revBitMask[_xpos&7];
+ y = _ypos;
+
+ dst = _bg_ptr;
+ height = _height2;
+ width = _width2;
+ len = _replen;
+ color = _repcolor;
+ src = _srcptr;
+
+ if (_docontinue) goto StartPos;
+
+ do {
+ len = *src++;
+ color = len>>_shrval;
+ len &= _maskval;
+ if (!len) len = *src++;
+
+ do {
+ if (cost_scaleTable[_scaleIndexY++] < _scaleY) {
+ if (color && y < _vscreenheight) {
+ pcolor = _palette[color];
+ if (pcolor==13)
+ pcolor = _transEffect[*dst];
+ *dst = pcolor;
+ }
+ dst += 320;
+ y++;
+ }
+ if (!--height) {
+ if(!--width)
+ return;
+ height = _height;
+ y = _ypostop;
+ _scaleIndexY = _scaleIndexYTop;
+ t = _scaleIndexX;
+ _scaleIndexX = t + _scaleIndexXStep;
+ if (cost_scaleTable[t] < _scaleX) {
+ _xpos += _scaleIndexXStep;
+ if (_xpos >= 320)
+ return;
+ _bg_ptr += _scaleIndexXStep;
+ }
+ dst = _bg_ptr;
+ }
+StartPos:;
+ } while (--len);
+ } while(1);
+}
+
+void CostumeRenderer::loadCostume(int id) {
+ _ptr = _vm->getResourceAddress(3, id) + 2;
+ switch(_ptr[7]&0x7F) {
+ case 0x58:
+ _numColors = 16;
+ break;
+ case 0x59:
+ _numColors = 32;
+ break;
+ default:
+ error("Costume %d is invalid", id);
+ }
+
+ _dataptr = _ptr + READ_LE_UINT16(_ptr + _numColors + 8);
+}
+
+byte CostumeRenderer::drawOneSlot(Actor *a, int slot) {
+ int i;
+ int code;
+ CostumeData *cd = &a->cost;
+
+ if (cd->a[slot]==0xFFFF || cd->hdr & (1<<slot))
+ return 0;
+
+ i = cd->a[slot]&0x7FFF;
+ _frameptr = _ptr + READ_LE_UINT16(_ptr + _numColors + slot*2 + 10);
+ code = _dataptr[i]&0x7F;
+ _srcptr = _ptr + READ_LE_UINT16(_frameptr + code*2);
+
+ if (code != 0x7B) {
+ return mainRoutine(a, slot, code);
+ }
+
+ return 0;
+}
+
+byte CostumeRenderer::drawCostume(Actor *a) {
+ int i;
+ byte r = 0;
+ _xmove = _ymove = 0;
+ for (i=0; i<16; i++)
+ r|=drawOneSlot(a, i);
+ return r;
+}
+
+byte CostumeRenderer::animateOneSlot(CostumeData *cd, int slot) {
+ int highflag;
+ int i,end,code;
+
+ if (cd->a[slot]==0xFFFF)
+ return 0;
+
+ highflag = cd->a[slot]&0x8000;
+ i = cd->a[slot]&0x7FFF;
+ end = cd->c[slot];
+ code=_dataptr[i]&0x7F;
+
+ do {
+ if (!highflag) {
+ if (i++ >= end)
+ i = cd->b[slot];
+ } else {
+ if (i != end)
+ i++;
+ }
+
+ if (_dataptr[i]==0x7C) {
+ cd->animCounter1++;
+ if(cd->b[slot] != end)
+ continue;
+ }
+
+ if (_dataptr[i]==0x78) {
+ cd->animCounter2++;
+ if(cd->b[slot] != end)
+ continue;
+ }
+
+ cd->a[slot] = i|highflag;
+ return (_dataptr[i]&0x7F) != code;
+ } while(1);
+}
+
+byte CostumeRenderer::animate(CostumeData *cd) {
+ int i;
+ byte r = 0;
+
+ for (i=0; i<16; i++) {
+ if(cd->a[i]!=0xFFFF)
+ r+=animateOneSlot(cd, i);
+ }
+ return r;
+}
+
diff --git a/gfx.cpp b/gfx.cpp
new file mode 100644
index 0000000000..bbb5014d0f
--- /dev/null
+++ b/gfx.cpp
@@ -0,0 +1,1645 @@
+/* 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.
+ *
+ * Change Log:
+ * $Log$
+ * Revision 1.1 2001/10/09 14:30:14 strigeus
+ * Initial revision
+ *
+ *
+ */
+
+#include "stdafx.h"
+#include "scumm.h"
+
+void Scumm::getGraphicsPerformance() {
+ int i;
+ _scummTimer = 0;
+
+ for (i=10; i!=0; i--) {
+ initScreens(0, 0, 320, 200);
+ }
+
+ vm.vars[VAR_PERFORMANCE_1] = _scummTimer;
+ _scummTimer = 0;
+
+ for (i=10; i!=0; i--) {
+ setDirtyRange(0, 0, 200);
+ unkVirtScreen2();
+ }
+
+ vm.vars[VAR_PERFORMANCE_2] = _scummTimer;
+
+ initScreens(0, 16, 320, 144);
+}
+
+void Scumm::initScreens(int a, int b, int w, int h) {
+ int i;
+
+ for (i=0; i<3; i++) {
+ nukeResource(10, i+1);
+ nukeResource(10, i+5);
+ }
+
+ if (!getResourceAddress(10,4)) {
+ initVirtScreen(3, 80, 13, false, false);
+ }
+ initVirtScreen(0, b, h-b, true, true);
+ initVirtScreen(1, 0, b, false, false);
+ initVirtScreen(2, h, 200-h, false, false);
+}
+
+void Scumm::initVirtScreen(int slot, int top, int height, bool twobufs, bool fourextra) {
+ VirtScreen *vs = &virtscr[slot];
+ int size;
+
+ assert(height>=0);
+ assert(slot>=0 && slot<4);
+
+ vs->unk1 = 0;
+ vs->width = 320;
+ vs->topline = top;
+ vs->height = height;
+ vs->alloctwobuffers = twobufs;
+ vs->fourlinesextra = fourextra;
+ vs->xstart = 0;
+ size = vs->width * vs->height;
+ vs->size = size;
+ if (vs->fourlinesextra)
+ size += 320*4;
+
+ memset(
+ createResource(10, slot+1, size),
+ 0,size);
+
+ if (twobufs) {
+ memset(
+ createResource(10, slot+5, size),
+ 0x23,size);
+ }
+
+ if (slot != 3) {
+ setDirtyRange(slot, 0, height);
+ }
+}
+
+void Scumm::setDirtyRange(int slot, int top, int bottom) {
+ int i;
+ VirtScreen *vs = &virtscr[slot];
+ for (i=0; i<40; i++) {
+ vs->tdirty[i] = top;
+ vs->bdirty[i] = bottom;
+ }
+}
+
+void Scumm::unkVirtScreen2() {
+ removeMouseCursor();
+
+ dseg_3DB6 = 1;
+
+ updateDirtyScreen(2);
+
+ if (_currentRoom != dseg_2456) {
+ dseg_2456 = (byte)_currentRoom;
+ dseg_4E8A = 1;
+ }
+
+ if (camera._lastPos == camera._curPos) {
+ updateDirtyScreen(0);
+ dseg_4E8A = 1;
+ dseg_4F8C = _screenStartStrip;
+ } else {
+ gdi.readPtr = getResourceAddress(10, 1);
+ gdi.readOffs = _screenStartStrip;
+ gdi.drawY = virtscr[0].topline;
+ gdi.drawHeight = virtscr[0].height;
+
+ blitToScreen(this, gdi.readPtr + gdi.readOffs*8, 0, gdi.drawY, 320, gdi.drawHeight);
+
+ for (gdi.draw8xPos = 0; gdi.draw8xPos<40; gdi.draw8xPos++) {
+ virtscr[0].tdirty[gdi.draw8xPos] = (byte)gdi.drawHeight;
+ virtscr[0].bdirty[gdi.draw8xPos] = 0;
+ }
+ }
+ showMouseCursor();
+}
+
+void Scumm::updateDirtyScreen(int slot) {
+ VirtScreen *vs = &virtscr[slot];
+ int i;
+
+ if (vs->height==0)
+ return;
+
+ gdi.virtScreen = slot;
+ gdi.drawY = vs->topline;
+ gdi.drawHeight = vs->height;
+ gdi.readOffs = 0;
+ if (vs->fourlinesextra)
+ gdi.readOffs = _screenStartStrip;
+
+ if (_videoMode==0xE) {
+ for (i=0; i<40; i++) {
+ gdi.draw8xPos = i;
+ gdi.drawBottom = vs->bdirty[i];
+ if (gdi.drawBottom) {
+ gdi.drawTop = vs->tdirty[i];
+ drawStripToScreen();
+ vs->tdirty[i] = (byte)gdi.drawHeight;
+ vs->bdirty[i] = 0;
+ }
+ }
+ } else {
+ gdi.drawWidth = 8;
+ gdi.draw8xPos = 0;
+
+ for (i=0; i<40; i++) {
+ gdi.drawBottom = vs->bdirty[i];
+ if (gdi.drawBottom) {
+ gdi.drawTop = vs->tdirty[i];
+ vs->tdirty[i] = (byte)gdi.drawHeight;
+ vs->bdirty[i] = 0;
+ if (i!=39) {
+ if (vs->bdirty[i+1] == gdi.drawBottom &&
+ vs->tdirty[i+1] == gdi.drawTop) {
+ gdi.drawWidth += 8;
+ continue;
+ }
+ drawStripToScreen();
+ gdi.drawWidth = 8;
+ } else {
+ drawStripToScreen();
+ }
+ }
+ gdi.draw8xPos = i+1;
+ }
+ }
+}
+
+void Scumm::drawStripToScreen() {
+ if (gdi.drawBottom <= gdi.drawTop)
+ return;
+
+ if (_videoMode==0xE) {
+ gdi.drawTop &= 0xFE;
+ if (gdi.drawBottom&1)
+ gdi.drawBottom++;
+ }
+
+ if (gdi.drawBottom <= gdi.drawTop) {
+ gdi.drawBottom = gdi.drawTop + 4;
+ }
+
+ if (gdi.drawHeight < gdi.drawTop) {
+ gdi.drawTop = 0;
+ }
+
+ if (gdi.drawHeight < gdi.drawBottom) {
+ gdi.drawBottom = gdi.drawHeight;
+ }
+
+ gdi.readPtr = getResourceAddress(10, gdi.virtScreen+1) + (gdi.drawTop*40+gdi.readOffs+gdi.draw8xPos)*8;
+
+ blitToScreen(this, gdi.readPtr, gdi.draw8xPos*8, gdi.drawY+gdi.drawTop, gdi.drawWidth, gdi.drawBottom-gdi.drawTop);
+}
+
+void Scumm::showMouseCursor() {
+ gdi.unk3 = 1;
+}
+
+void blit(byte *dst, byte *src, int w, int h) {
+ do {
+ memcpy(dst, src, w);
+ dst += 320;
+ src += 320;
+ } while (--h);
+}
+
+/* TODO: writes are being done to this data */
+MouseCursor mouse_cursors[4] = {
+ 8,7,{15,15,7,8},
+ {
+ 0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,
+ 0x00,0x80,0x00,0x80,0x00,0x00,0x7E,0x3F,
+ 0x00,0x00,0x00,0x80,0x00,0x80,0x00,0x80,
+ 0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x00,
+ },
+ 8,7,{15,15,7,8},
+ {
+ 0x00,0x00,0x7F,0xFE,0x60,0x06,0x30,0x0C,
+ 0x18,0x18,0x0C,0x30,0x06,0x60,0x03,0xC0,
+ 0x06,0x60,0x0C,0x30,0x19,0x98,0x33,0xCC,
+ 0x67,0xE6,0x7F,0xFE,0x00,0x00,0x00,0x00,
+ },
+
+ 8,7,{15,15,7,8},
+ {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ },
+ 8,7,{15,15,7,8},
+ {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ },
+
+};
+
+void Scumm::setCursor(int cursor) {
+ MouseCursor *cur = &mouse_cursors[cursor];
+ int i,j;
+ byte *mask;
+ const byte *src;
+ byte shramount;
+ uint32 data;
+
+ debug(1,"Loading cursor %d", cursor);
+ gdi.hotspot_x = cur->hotspot_x;
+ gdi.hotspot_y = cur->hotspot_y;
+ gdi.currentCursor = cursor;
+
+ for (i=0; i<4; i++)
+ gdi.mouseColors[i] = cur->colors[i];
+
+ mask = gdi.mouseMask;
+ shramount = 0;
+
+ for(j=0; j<8; j++) {
+ src = cur->data;
+ i=16;
+ do {
+/* TODO: endian trouble */
+ data = ((src[0]<<16) | (src[1]<<8))>>shramount;
+ src += 2;
+ mask[0] = (byte)(data>>24);
+ mask[1] = (byte)(data>>16);
+ mask[2] = (byte)(data>>8);
+ mask[3] = (byte)(data);
+ mask += 4;
+ } while (--i);
+ shramount++;
+ }
+}
+
+void Scumm::setCameraAt(int dest) {
+ int t;
+ CameraData *cd = &camera;
+
+ if (cd->_mode!=2 || abs(dest - cd->_curPos) > 160) {
+ cd->_curPos = dest;
+ }
+ cd->_destPos = dest;
+
+ t = vm.vars[VAR_CAMERA_MIN];
+ if (cd->_curPos < t) cd->_curPos = t;
+
+ t = vm.vars[VAR_CAMERA_MAX];
+ if (cd->_curPos > t) cd->_curPos = t;
+
+ if (vm.vars[VAR_SCROLL_SCRIPT]) {
+ vm.vars[VAR_CAMERA_CUR_POS] = cd->_curPos;
+ runScript(vm.vars[VAR_SCROLL_SCRIPT], 0, 0, 0);
+ }
+
+ if (cd->_curPos != cd->_lastPos && charset._hasMask)
+ stopTalk();
+}
+
+void Scumm::setCameraFollows(Actor *a) {
+ int t,i;
+ CameraData *cd = &camera;
+
+ cd->_mode = 2;
+ cd->_follows = a->number;
+
+ if (a->room != _currentRoom) {
+ startScene(a->room, 0, 0);
+ cd->_mode = 2;
+ cd->_curPos = a->x;
+ setCameraAt(cd->_curPos);
+ }
+
+ t = (a->x >> 3);
+
+ if (t-_screenStartStrip < cd->_leftTrigger ||
+ t-_screenStartStrip > cd->_rightTrigger)
+ setCameraAt(a->x);
+
+ for (i=1,a=getFirstActor(); ++a,i<13; i++) {
+ if (a->room==_currentRoom)
+ a->needRedraw = true;
+ }
+ runHook(0);
+}
+
+void Scumm::initBGBuffers() {
+ byte *ptr;
+ int size, itemsize, i;
+ byte *room;
+
+ room = getResourceAddress(1, _roomResource);
+
+ ptr = findResource(MKID('RMIH'), findResource(MKID('RMIM'), room));
+
+ _numZBuffer = READ_LE_UINT16(ptr+8) + 1;
+
+ assert(_numZBuffer>=1 && _numZBuffer<=4);
+
+ itemsize = (_scrHeight + 4) * 40;
+ size = itemsize * _numZBuffer;
+
+ memset(createResource(0xA, 9, size), 0, size);
+
+ for (i=0; i<4; i++)
+ _imgBufOffs[i] = i*itemsize;
+}
+
+void Scumm::setPaletteFromRes() {
+ byte *ptr = getResourceAddress(1, _roomResource) + _CLUT_offs;
+ uint32 size = READ_BE_UINT32_UNALIGNED(ptr+4);
+ int i, r, g, b;
+ byte *dest, *epal;
+
+ _colorsInPalette = (size-8) / 3;
+
+ ptr += 8;
+
+ checkRange(256, 0, _colorsInPalette, "Too many colors (%d) in Palette");
+
+ dest = _currentPalette;
+
+ if (_videoMode==0x13) {
+ for (i=0; i<_colorsInPalette; i++) {
+ r = *ptr++;
+ g = *ptr++;
+ b = *ptr++;
+ if (i<=15 || r<252 || g<252 || b<252) {
+ *dest++ = r>>2;
+ *dest++ = g>>2;
+ *dest++ = b>>2;
+ } else {
+ dest += 3;
+ }
+ }
+ }
+
+ if (_videoMode==0xE) {
+ epal = getResourceAddress(1, _roomResource) + _EPAL_offs + 8;
+ for (i=0; i<256; i++,epal++) {
+ _currentPalette[i] = *epal&0xF;
+ _currentPalette[i+256] = *epal>>4;
+ }
+ }
+
+ setDirtyColors(0, _colorsInPalette-1);
+}
+
+
+void Scumm::setDirtyColors(int min, int max) {
+ if (_palDirtyMin > min)
+ _palDirtyMin = min;
+ if (_palDirtyMax < max)
+ _palDirtyMax = max;
+}
+
+void Scumm::initCycl(byte *ptr) {
+ int i, j;
+
+ for (i=1; i<=16; i++)
+ _colorCycleDelays[i] = 0;
+
+ while ((j=*ptr++) != 0) {
+ assert(j>=1 && j<=16);
+ ptr += 2;
+ _colorCycleCounter[j] = 0;
+ _colorCycleDelays[j] = 16384 / READ_BE_UINT16_UNALIGNED(ptr);
+ ptr += 2;
+ _colorCycleFlags[j] = READ_BE_UINT16_UNALIGNED(ptr);
+ ptr += 2;
+ _colorCycleStart[j] = *ptr++;
+ _colorCycleEnd[j] = *ptr++;
+ }
+}
+
+void Scumm::stopCycle(int i) {
+ checkRange(16, 0, i, "Stop Cycle %d Out Of Range");
+ if (i!=0) {
+ _colorCycleDelays[i] = 0;
+ return;
+ }
+ for (i=1; i<=16; i++)
+ _colorCycleDelays[i] = 0;
+}
+
+void Scumm::cyclePalette() {
+ int valueToAdd;
+ int i, num;
+ byte *start, *end;
+ byte tmp[3];
+
+ if(_videoMode != 0x13)
+ return;
+
+ valueToAdd = vm.vars[VAR_TIMER];
+ if (valueToAdd < vm.vars[VAR_TIMER_NEXT])
+ valueToAdd = vm.vars[VAR_TIMER_NEXT];
+
+ for (i=1; i<=16; i++) {
+ if (_colorCycleDelays[i] &&
+ (_colorCycleCounter[i]+=valueToAdd) >=
+ _colorCycleDelays[i]) {
+ do {
+ _colorCycleCounter[i] -= _colorCycleDelays[i];
+ } while (_colorCycleDelays[i] <= _colorCycleCounter[i]);
+
+ setDirtyColors(_colorCycleStart[i], _colorCycleEnd[i]);
+ moveMemInPalRes(_colorCycleStart[i], _colorCycleEnd[i],
+ _colorCycleFlags[i]&2);
+ start = &_currentPalette[_colorCycleStart[i]*3];
+ end = &_currentPalette[_colorCycleEnd[i]*3];
+
+ num = _colorCycleEnd[i] - _colorCycleStart[i];
+
+ if (!(_colorCycleFlags[i]&2)) {
+ memmove(tmp, end, 3);
+ memmove(start+3, start, num*3);
+ memmove(start, tmp, 3);
+ } else {
+ memmove(tmp, start, 3);
+ memmove(start, start+3, num*3);
+ memmove(end, tmp, 3);
+ }
+ }
+ }
+}
+
+void Scumm::moveMemInPalRes(int start, int end, byte direction) {
+ byte *startptr, *endptr;
+ byte *startptr2, *endptr2;
+ int num;
+ byte tmp[6];
+ byte tmp2[6];
+
+ if (!_palManipCounter)
+ return;
+
+ startptr = getResourceAddress(0xC, 4) + start * 6;
+ endptr = getResourceAddress(0xC, 4) + end * 6;
+
+ startptr2 = getResourceAddress(0xC, 5) + start * 6;
+ endptr2 = getResourceAddress(0xC, 5) + end * 6;
+
+ num = end - start;
+
+ if (!direction) {
+ memmove(tmp, endptr, 6);
+ memmove(startptr+6, startptr, num*6);
+ memmove(startptr, tmp, 6);
+ memmove(tmp2, endptr2, 6);
+ memmove(startptr2+6, startptr2, num*6);
+ memmove(startptr2, tmp2, 6);
+ } else {
+ memmove(tmp, startptr, 6);
+ memmove(startptr, startptr+6, num*6);
+ memmove(endptr, tmp, 6);
+ memmove(tmp2, startptr2, 6);
+ memmove(startptr2, startptr2+6, num*6);
+ memmove(endptr2, tmp2, 6);
+ }
+}
+
+void Scumm::unkVirtScreen4(int a) {
+ VirtScreen *vs;
+
+ setDirtyRange(0, 0, 0);
+ camera._lastPos = camera._curPos;
+ removeMouseCursor();
+ dseg_3DB6 = 2;
+ dseg_3DB6 = 1;
+ if (dseg_4EA0 == 0)
+ return;
+ dseg_4EA0 = 0;
+
+ if (a==0)
+ return;
+
+ vs = &virtscr[0];
+ gdi.bg_ptr = getResourceAddress(0xA, 1) + vs->xstart;
+
+ memset(gdi.bg_ptr, 0, vs->size);
+
+ switch(a) {
+ case 1: case 2: case 3:
+ unkVirtScreen5(a-1);
+ break;
+ case 128:
+ unkScreenEffect6();
+ break;
+ case 129:
+ setDirtyRange(0, 0, vs->height);
+ dseg_3DB6 = 2;
+ updateDirtyScreen(0);
+ /* XXX: EGA_proc4(0); */
+ break;
+ case 134:
+ unkScreenEffect5(0);
+ break;
+ case 135:
+ unkScreenEffect5(1);
+ break;
+ }
+}
+
+void Scumm::redrawBGAreas() {
+ int i;
+ int val;
+ CameraData *cd = &camera;
+
+ if (cd->_curPos!=cd->_lastPos && charset._hasMask)
+ stopTalk();
+
+ val = 0;
+
+ if (_fullRedraw==0 && _BgNeedsRedraw) {
+ for (i=0; i<40; i++) {
+ if (actorDrawBits[_screenStartStrip + i]&0x8000) {
+ redrawBGStrip(i, 1);
+ }
+ }
+ }
+
+ if (_fullRedraw==0 && cd->_curPos - cd->_lastPos == 8) {
+ val = 2;
+ redrawBGStrip(39, 1);
+ } else if (_fullRedraw==0 && cd->_curPos - cd->_lastPos == -8) {
+ val = 1;
+ redrawBGStrip(0, 1);
+ } else if (_fullRedraw!=0 || cd->_curPos != cd->_lastPos) {
+ dseg_719E = 0;
+ _BgNeedsRedraw = 0;
+ redrawBGStrip(0, 40);
+ }
+
+ drawRoomObjects(val);
+ _BgNeedsRedraw = 0;
+}
+
+const uint32 zplane_tags[] = {
+ MKID('ZP00'),
+ MKID('ZP01'),
+ MKID('ZP02'),
+ MKID('ZP03')
+};
+
+
+void Scumm::drawBmp(byte *ptr, int a, int b, int c, const char *str, int objnr) {
+ byte *smap_ptr;
+ int i;
+ byte *zplane_list[4];
+ int t;
+ VirtScreen *vs;
+ byte twobufs;
+ int x;
+ byte *where_draw_ptr;
+
+ smap_ptr = findResource(MKID('SMAP'), ptr);
+
+ if (objnr==209) {
+ warning("tst");
+ }
+
+ for(i=1; i<_numZBuffer; i++) {
+ zplane_list[i] = findResource(zplane_tags[i], ptr);
+ }
+
+ t = gdi.numLinesToProcess + _drawBmpY;
+
+ vs = &virtscr[gdi.virtScreen];
+ if (t > vs->height) {
+ error("%s %d strip drawn to %d below window bottom %d",
+ str, objnr, t, vs->height);
+ }
+
+ twobufs = vs->alloctwobuffers;
+
+ dseg_4174 = vs->size;
+
+ if (vs->fourlinesextra)
+ dseg_4174 += 5*256;
+
+ gdi.vertStripNextInc = gdi.numLinesToProcess * 320 - 1;
+
+ do {
+ gdi.smap_ptr = smap_ptr + READ_LE_UINT32(smap_ptr + a*4 + 8);
+
+ x = _drawBmpX;
+ if (vs->fourlinesextra)
+ x -= _screenStartStrip;
+
+ if (x >= 40)
+ return;
+
+ if (_drawBmpY < vs->tdirty[x])
+ vs->tdirty[x]=_drawBmpY;
+
+ if (t > vs->bdirty[x])
+ vs->bdirty[x]=t;
+
+ gdi.bg_ptr = getResourceAddress(0xA, gdi.virtScreen+1) + (_drawBmpY*40+_drawBmpX)*8;
+ gdi.where_to_draw_ptr = getResourceAddress(0xA, gdi.virtScreen+5) + (_drawBmpY*40+_drawBmpX)*8;
+ if (!twobufs) {
+ gdi.where_to_draw_ptr = gdi.bg_ptr;
+ }
+ gdi.mask_ptr = getResourceAddress(0xA, 9) + (_drawBmpY*40+_drawBmpX);
+
+ where_draw_ptr = gdi.where_to_draw_ptr;
+ decompressBitmap();
+
+ if (twobufs) {
+ gdi.where_to_draw_ptr = where_draw_ptr;
+ if (vm.vars[VAR_DRAWFLAGS]&2) {
+ if (hasCharsetMask(x<<3, _drawBmpY, (x+1)<<3, t))
+ draw8ColWithMasking();
+ else {
+ blit(gdi.bg_ptr, gdi.where_to_draw_ptr, 8, gdi.numLinesToProcess);
+ }
+ } else {
+ if (hasCharsetMask(x<<3, _drawBmpY, (x+1)<<3, t))
+ clear8ColWithMasking();
+ else
+ clear8Col();
+ }
+ }
+
+ for (i=1; i<_numZBuffer; i++) {
+ if (!zplane_list[i])
+ continue;
+ gdi.z_plane_ptr = zplane_list[i] + READ_LE_UINT16(zplane_list[i] + a*2 + 8);
+ gdi.mask_ptr_dest = getResourceAddress(0xA, 9) + _drawBmpY*40 + _drawBmpX + _imgBufOffs[i];
+ if (dseg_4E3B!=0 && c!=0)
+ decompressMaskImgOr();
+ else
+ decompressMaskImg();
+ }
+ _drawBmpX++;
+ a++;
+ } while (--b);
+}
+
+
+void Scumm::decompressBitmap() {
+ const byte decompress_table[] = {
+ 0x0, 0x1, 0x3, 0x7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, 0x0,
+ };
+
+ byte code = *gdi.smap_ptr++;
+
+ switch(code) {
+ case 1:
+ GDI_UnkDecode7();
+ break;
+ case 14: case 15: case 16: case 17: case 18:
+ gdi.decomp_shr = code - 10;
+ gdi.decomp_mask = decompress_table[code - 10];
+ GDI_UnkDecode6();
+ break;
+
+ case 24: case 25: case 26: case 27: case 28:
+ gdi.decomp_shr = code - 20;
+ gdi.decomp_mask = decompress_table[code - 20];
+ GDI_UnkDecode5();
+ break;
+
+ case 34: case 35: case 36: case 37: case 38:
+ dseg_4E3B = 1;
+ gdi.decomp_shr = code - 30;
+ gdi.decomp_mask = decompress_table[code - 30];
+ GDI_UnkDecode4();
+ break;
+
+ case 44: case 45: case 46: case 47: case 48:
+ dseg_4E3B = 1;
+ gdi.decomp_shr = code - 40;
+ gdi.decomp_mask = decompress_table[code - 40];
+ GDI_UnkDecode2();
+ break;
+
+ case 64: case 65: case 66: case 67: case 68:
+ gdi.decomp_shr = code - 60;
+ gdi.decomp_mask = decompress_table[code - 60];
+ GDI_UnkDecode1();
+ break;
+
+ case 84: case 85: case 86: case 87: case 88:
+ dseg_4E3B = 1;
+ gdi.decomp_shr = code - 80;
+ gdi.decomp_mask = decompress_table[code - 80];
+ GDI_UnkDecode3();
+ break;
+ }
+}
+
+int Scumm::hasCharsetMask(int x, int y, int x2, int y2) {
+ if (!charset._hasMask || y > charset._mask_bottom || x > charset._mask_right ||
+ y2 < charset._mask_top || x2 < charset._mask_left )
+ return 0;
+ return 1;
+}
+
+void Scumm::draw8ColWithMasking() {
+ int height = gdi.numLinesToProcess;
+ byte *mask = gdi.mask_ptr;
+ byte *dst = gdi.bg_ptr;
+ byte *src = gdi.where_to_draw_ptr;
+ byte maskbits;
+
+ do {
+ maskbits = *mask;
+ if (maskbits) {
+ if (!(maskbits&0x80)) dst[0] = src[0];
+ if (!(maskbits&0x40)) dst[1] = src[1];
+ if (!(maskbits&0x20)) dst[2] = src[2];
+ if (!(maskbits&0x10)) dst[3] = src[3];
+ if (!(maskbits&0x08)) dst[4] = src[4];
+ if (!(maskbits&0x04)) dst[5] = src[5];
+ if (!(maskbits&0x02)) dst[6] = src[6];
+ if (!(maskbits&0x01)) dst[7] = src[7];
+ } else {
+/* alignment safe */
+ ((uint32*)dst)[0] = ((uint32*)src)[0];
+ ((uint32*)dst)[1] = ((uint32*)src)[1];
+ }
+ src += 320;
+ dst += 320;
+ mask += 40;
+ } while (--height);
+}
+
+void Scumm::clear8ColWithMasking() {
+ int height = gdi.numLinesToProcess;
+ byte *mask = gdi.mask_ptr;
+ byte *dst = gdi.bg_ptr;
+ byte maskbits;
+
+ do {
+ maskbits = *mask;
+ if (!maskbits) {
+ ((uint32*)dst)[1] = ((uint32*)dst)[0] = 0;
+ } else {
+ if (!(maskbits&0x80)) dst[0] = 0;
+ if (!(maskbits&0x40)) dst[1] = 0;
+ if (!(maskbits&0x20)) dst[2] = 0;
+ if (!(maskbits&0x10)) dst[3] = 0;
+ if (!(maskbits&0x08)) dst[4] = 0;
+ if (!(maskbits&0x04)) dst[5] = 0;
+ if (!(maskbits&0x02)) dst[6] = 0;
+ if (!(maskbits&0x01)) dst[7] = 0;
+ }
+ dst += 320;
+ mask += 40;
+ } while (--height);
+}
+
+void Scumm::clear8Col() {
+ int height = gdi.numLinesToProcess;
+ byte *dst = gdi.bg_ptr;
+ do {
+ ((uint32*)dst)[1] = ((uint32*)dst)[0] = 0;
+ dst += 320;
+ } while (--height);
+}
+
+void Scumm::decompressMaskImg() {
+ byte *src = gdi.z_plane_ptr;
+ byte *dst = gdi.mask_ptr_dest;
+ int height = gdi.numLinesToProcess;
+ byte b, c;
+
+ while(1) {
+ b = *src++;
+
+ if (b&0x80) {
+ b&=0x7F;
+ c = *src++;
+
+ do {
+ *dst = c;
+ dst += 40;
+ if (!--height)
+ return;
+ } while (--b);
+ } else {
+ do {
+ *dst = *src++;
+ dst += 40;
+ if (!--height)
+ return;
+ } while (--b);
+ }
+ }
+}
+
+void Scumm::decompressMaskImgOr() {
+ byte *src = gdi.z_plane_ptr;
+ byte *dst = gdi.mask_ptr_dest;
+ int height = gdi.numLinesToProcess;
+ byte b, c;
+
+ while(1) {
+ b = *src++;
+ if (b&0x80) {
+ b&=0x7F;
+ c = *src++;
+
+ do {
+ *dst |= c;
+ dst += 40;
+ if (!--height)
+ return;
+ } while (--b);
+ } else {
+ do {
+ *dst |= *src++;
+ dst += 40;
+ if (!--height)
+ return;
+ } while (--b);
+ }
+ }
+}
+
+void Scumm::redrawBGStrip(int start, int num) {
+ int s = _screenStartStrip + start;
+
+ gdi.virtScreen = 0;
+ actorDrawBits[s]|=0x8000;
+ _drawBmpX = s;
+ _drawBmpY = 0;
+ gdi.numLinesToProcess = virtscr[0].height;
+ if (gdi.numLinesToProcess > _scrHeight) {
+ error("Screen Y size %d > Room height %d",
+ gdi.numLinesToProcess,
+ _scrHeight);
+ }
+
+ drawBmp(
+ getResourceAddress(1, _roomResource) + _IM00_offs,
+ s,
+ num,
+ 0,
+ "Room",
+ _roomResource);
+}
+
+#define READ_BIT (cl--,bit = bits&1, bits>>=1,bit)
+#define FILL_BITS if (cl <= 8) { bits |= (*src++ << cl); cl += 8;}
+
+void Scumm::GDI_UnkDecode1() {
+ byte *src = gdi.smap_ptr;
+ byte *dst = gdi.where_to_draw_ptr;
+ byte color = *src++;
+ uint bits = *src++;
+ byte cl = 8;
+ byte bit;
+ gdi.tempNumLines = gdi.numLinesToProcess;
+
+ do {
+ gdi.currentX = 8;
+ do {
+ FILL_BITS
+ *dst++=color;
+
+ if (!READ_BIT) {}
+ else if (READ_BIT) {
+ color += (bits&7)-4;
+ cl-=3;
+ bits>>=3;
+ } else {
+ FILL_BITS
+ color = bits&gdi.decomp_mask;
+ cl -= gdi.decomp_shr;
+ bits >>= gdi.decomp_shr;
+ }
+ } while (--gdi.currentX);
+ dst += 312;
+ } while (--gdi.tempNumLines);
+
+}
+
+void Scumm::GDI_UnkDecode2() {
+ byte *src = gdi.smap_ptr;
+ byte *dst = gdi.where_to_draw_ptr;
+ byte color = *src++;
+ int8 inc = -1;
+ uint bits = *src++;
+ byte cl = 8;
+ byte bit;
+
+ gdi.tempNumLines = gdi.numLinesToProcess;
+
+ do {
+ gdi.currentX = 8;
+ do {
+ FILL_BITS
+ if (color!=gdi.transparency)
+ *dst=color;
+ dst++;
+ if (!READ_BIT) {}
+ else if (!READ_BIT) {
+ FILL_BITS
+ color = bits&gdi.decomp_mask;
+ bits >>= gdi.decomp_shr;
+ cl -= gdi.decomp_shr;
+ inc = -1;
+ } else if (!READ_BIT) {
+ color += inc;
+ } else {
+ inc = -inc;
+ color += inc;
+ }
+ } while (--gdi.currentX);
+ dst += 312;
+ } while (--gdi.tempNumLines);
+}
+
+void Scumm::GDI_UnkDecode3() {
+ byte *src = gdi.smap_ptr;
+ byte *dst = gdi.where_to_draw_ptr;
+ byte color = *src++;
+ uint bits = *src++;
+ byte cl = 8;
+ byte bit;
+
+ gdi.tempNumLines = gdi.numLinesToProcess;
+
+ do {
+ gdi.currentX = 8;
+ do {
+ FILL_BITS
+ if (color!=gdi.transparency) *dst=color;
+ dst++;
+
+ if (!READ_BIT) {}
+ else if (READ_BIT) {
+ color += (bits&7)-4;
+ cl-=3;
+ bits>>=3;
+ } else {
+ FILL_BITS
+ color = bits&gdi.decomp_mask;
+ cl -= gdi.decomp_shr;
+ bits >>= gdi.decomp_shr;
+ }
+ } while (--gdi.currentX);
+ dst += 312;
+ } while (--gdi.tempNumLines);
+}
+
+void Scumm::GDI_UnkDecode4() {
+ byte *src = gdi.smap_ptr;
+ byte *dst = gdi.where_to_draw_ptr;
+ byte color = *src++;
+ int8 inc = -1;
+ uint bits = *src++;
+ byte cl = 8;
+ byte bit;
+
+ gdi.currentX = 8;
+ do {
+ gdi.tempNumLines = gdi.numLinesToProcess;
+ do {
+ FILL_BITS
+ if (color!=gdi.transparency)
+ *dst=color;
+ dst+=320;
+ if (!READ_BIT) {}
+ else if (!READ_BIT) {
+ FILL_BITS
+ color = bits&gdi.decomp_mask;
+ bits >>= gdi.decomp_shr;
+ cl -= gdi.decomp_shr;
+ inc = -1;
+ } else if (!READ_BIT) {
+ color += inc;
+ } else {
+ inc = -inc;
+ color += inc;
+ }
+ } while (--gdi.tempNumLines);
+ dst -= gdi.vertStripNextInc;
+ } while (--gdi.currentX);
+}
+
+void Scumm::GDI_UnkDecode5() {
+ byte *src = gdi.smap_ptr;
+ byte *dst = gdi.where_to_draw_ptr;
+ byte color = *src++;
+ int8 inc = -1;
+ uint bits = *src++;
+ byte cl = 8;
+ byte bit;
+
+ gdi.tempNumLines = gdi.numLinesToProcess;
+
+ do {
+ gdi.currentX = 8;
+ do {
+ FILL_BITS
+ *dst++=color;
+ if (!READ_BIT) {}
+ else if (!READ_BIT) {
+ FILL_BITS
+ color = bits&gdi.decomp_mask;
+ bits >>= gdi.decomp_shr;
+ cl -= gdi.decomp_shr;
+ inc = -1;
+ } else if (!READ_BIT) {
+ color += inc;
+ } else {
+ inc = -inc;
+ color += inc;
+ }
+ } while (--gdi.currentX);
+ dst += 312;
+ } while (--gdi.tempNumLines);
+}
+
+void Scumm::GDI_UnkDecode6() {
+ byte *src = gdi.smap_ptr;
+ byte *dst = gdi.where_to_draw_ptr;
+ byte color = *src++;
+ int8 inc = -1;
+ uint bits = *src++;
+ byte cl = 8;
+ byte bit;
+
+ gdi.currentX = 8;
+ do {
+ gdi.tempNumLines = gdi.numLinesToProcess;
+ do {
+ FILL_BITS
+ *dst=color;
+ dst+=320;
+ if (!READ_BIT) {}
+ else if (!READ_BIT) {
+ FILL_BITS
+ color = bits&gdi.decomp_mask;
+ bits >>= gdi.decomp_shr;
+ cl -= gdi.decomp_shr;
+ inc = -1;
+ } else if (!READ_BIT) {
+ color += inc;
+ } else {
+ inc = -inc;
+ color += inc;
+ }
+ } while (--gdi.tempNumLines);
+ dst -= gdi.vertStripNextInc;
+ } while (--gdi.currentX);
+}
+
+void Scumm::GDI_UnkDecode7() {
+ byte *src = gdi.smap_ptr;
+ byte *dst = gdi.where_to_draw_ptr;
+ int height = gdi.numLinesToProcess;
+ do {
+ /* Endian safe */
+#if defined(SCUMM_NEED_ALIGNMENT)
+ memcpy(dst, src, 8);
+#else
+ ((uint32*)dst)[0] = ((uint32*)src)[0];
+ ((uint32*)dst)[1] = ((uint32*)src)[1];
+#endif
+ dst += 320;
+ } while (--height);
+}
+
+#undef READ_BIT
+#undef FILL_BITS
+
+void Scumm::restoreCharsetBg() {
+ dseg_4E3C = 0;
+ if (charset._mask_left != -1) {
+ restoreBG(charset._mask_left, charset._mask_top, charset._mask_right, charset._mask_bottom);
+ charset._hasMask = false;
+ charset._mask_left = -1;
+ }
+ _stringXpos2[0] = _stringXPos[0];
+ _stringYpos2[0] = _stringYPos[0];
+}
+
+void Scumm::restoreBG(int left, int top, int right, int bottom) {
+ VirtScreen *vs;
+ int topline, height, width, widthmod;
+
+ if (left==right || top==bottom)
+ return;
+ if (top<0) top=0;
+
+ if (findVirtScreen(top) == -1)
+ return;
+
+ vs = &virtscr[gdi.virtScreen];
+
+ topline = vs->topline;
+ height = topline + vs->height;
+ if (gdi.virtScreen==0) {
+ left += _lastXstart - vs->xstart;
+ right += _lastXstart - vs->xstart;
+ }
+
+ right++;
+ if (left<0) left=0;
+ if (right<0)right=0;
+ if (left>320)
+ return;
+ if (right>320)
+ right=320;
+ if (bottom>=height)
+ bottom=height;
+
+ updateDirtyRect(gdi.virtScreen, left, right, top-topline,bottom-topline, 0x4000);
+
+ vs = &virtscr[gdi.virtScreen];
+ height = (top-topline) * 320 + vs->xstart + left;
+
+ gdi.bg_ptr = getResourceAddress(0xA, gdi.virtScreen+1) + height;
+ gdi.where_to_draw_ptr = getResourceAddress(0xA, gdi.virtScreen+5) + height;
+ gdi.mask_ptr = getResourceAddress(0xA, 9) + top * 40 + (left>>3) + _screenStartStrip;
+ if (gdi.virtScreen==0) {
+ gdi.mask_ptr += vs->topline * 216;
+ }
+
+ height = bottom - top;
+ width = right - left;
+ widthmod = (width >> 2) + 2;
+
+ if (vs->alloctwobuffers && _currentRoom!=0 && vm.vars[VAR_DRAWFLAGS]&2) {
+ blit(gdi.bg_ptr, gdi.where_to_draw_ptr, width, height);
+ if (gdi.virtScreen==0 && charset._hasMask && height) {
+ do {
+ memset(gdi.mask_ptr, 0, widthmod);
+ gdi.mask_ptr += 40;
+ } while (--height);
+ }
+ } else {
+ if (height) {
+ do {
+ memset(gdi.bg_ptr, dseg_4E3C, width);
+ gdi.bg_ptr+=320;
+ } while (--height);
+ }
+ }
+}
+
+void Scumm::updateDirtyRect(int virt, int left, int right, int top, int bottom, uint16 dirtybits) {
+ VirtScreen *vs = &virtscr[virt];
+ int lp,rp;
+ uint16 *sp;
+ int num;
+
+ if (top > vs->height || bottom < 0)
+ return;
+
+ if (top<0)
+ top=0;
+ if (bottom > vs->height)
+ bottom = vs->height;
+
+ if (virt==0 && dirtybits) {
+ rp = (right >> 3) + _screenStartStrip;
+ lp = (left >> 3) + _screenStartStrip;
+ if (lp<0) lp=0;
+ if (rp >= 160)
+ rp = 159;
+ if (lp <= rp) {
+ num = rp - lp + 1;
+ sp = &actorDrawBits[lp];
+ do {
+ *sp++ |= dirtybits;
+ } while (--num);
+ }
+ }
+
+ rp = right >> 3;
+ lp = left >> 3;
+
+ if (lp>=40 || rp<0)
+ return;
+ if (lp<0) lp=0;
+ if (rp>=40) rp=39;
+
+ while (lp<=rp) {
+ if (top < vs->tdirty[lp])
+ vs->tdirty[lp] = top;
+ if (bottom > vs->bdirty[lp])
+ vs->bdirty[lp] = bottom;
+ lp++;
+ }
+}
+
+int Scumm::findVirtScreen(int y) {
+ VirtScreen *vs = virtscr;
+ int i;
+
+ gdi.virtScreen=-1;
+
+ for(i=0; i<3; i++,vs++) {
+ if (y >= vs->topline && y <= vs->topline+vs->height) {
+ gdi.virtScreen = i;
+ return i;
+ }
+ }
+ return -1;
+}
+
+void Scumm::unkVirtScreen5(int a) {
+ /* XXX: not implemented */
+ warning("stub unkVirtScreen5(%d)", a);
+}
+
+void Scumm::unkScreenEffect6() {
+ /* XXX: not implemented */
+ warning("stub unkScreenEffect6");
+}
+
+void Scumm::unkScreenEffect5(int a) {
+ /* XXX: not implemented */
+ warning("stub unkScreenEffect5(%d)",a);
+}
+
+void Scumm::setShake(int mode) {
+ if (mode!=-1)
+ _shakeMode = mode;
+ else
+ mode = 0;
+ /* XXX: not implemented */
+ warning("stub setShake(%d)",mode);
+}
+
+void Scumm::clearUpperMask() {
+ memset(
+ getResourceAddress(0xA, 9),
+ 0,
+ _imgBufOffs[1] - _imgBufOffs[0]
+ );
+}
+
+void Scumm::moveCamera() {
+ CameraData *cd = &camera;
+ int pos = cd->_curPos;
+ int actorx, t;
+ Actor *a;
+
+ cd->_curPos &= 0xFFF8;
+
+ if (cd->_curPos < vm.vars[VAR_CAMERA_MIN]) {
+ if (vm.vars[VAR_CAMERA_FAST])
+ cd->_curPos = vm.vars[VAR_CAMERA_MIN];
+ else
+ cd->_curPos += 8;
+ cameraMoved();
+ return;
+ }
+
+ if (cd->_curPos > vm.vars[VAR_CAMERA_MAX]) {
+ if (vm.vars[VAR_CAMERA_FAST])
+ cd->_curPos = vm.vars[VAR_CAMERA_MAX];
+ else
+ cd->_curPos-=8;
+ cameraMoved();
+ return;
+ }
+
+ if (cd->_mode==2) {
+ a = derefActorSafe(cd->_follows, "moveCamera");
+
+ actorx = a->x;
+ t = (actorx>>3) - _screenStartStrip;
+
+ if (t < cd->_leftTrigger || t > cd->_rightTrigger) {
+ if (vm.vars[VAR_CAMERA_FAST]) {
+ if (t > 35)
+ cd->_destPos = actorx + 80;
+ if (t < 5)
+ cd->_destPos = actorx - 80;
+ } else
+ cd->_movingToActor = 1;
+ }
+ }
+
+ if (cd->_movingToActor) {
+ a = derefActorSafe(cd->_follows, "moveCamera(2)");
+ cd->_destPos = a->x;
+ }
+
+ if (cd->_destPos < vm.vars[VAR_CAMERA_MIN])
+ cd->_destPos = vm.vars[VAR_CAMERA_MIN];
+
+ if (cd->_destPos > vm.vars[VAR_CAMERA_MAX])
+ cd->_destPos = vm.vars[VAR_CAMERA_MAX];
+
+ if (vm.vars[VAR_CAMERA_FAST]) {
+ cd->_curPos = cd->_destPos;
+ } else {
+ if (cd->_curPos < cd->_destPos)
+ cd->_curPos+=8;
+ if (cd->_curPos > cd->_destPos)
+ cd->_curPos-=8;
+ }
+
+ /* a is set a bit above */
+ if (cd->_movingToActor && cd->_curPos>>3 == a->x>>3) {
+ cd->_movingToActor = 0;
+ }
+
+ cameraMoved();
+
+ if (pos != cd->_curPos && vm.vars[VAR_SCROLL_SCRIPT]) {
+ vm.vars[VAR_CAMERA_CUR_POS] = cd->_curPos;
+ runScript(vm.vars[VAR_SCROLL_SCRIPT], 0, 0, 0);
+ }
+}
+
+void Scumm::cameraMoved() {
+ CameraData *cd = &camera;
+
+ if (cd->_curPos < 160) {
+ cd->_curPos = 160;
+ } else if (cd->_curPos + 160 >= _scrWidthIn8Unit<<3) {
+ cd->_curPos = (_scrWidthIn8Unit-20)<<3;
+ }
+
+ _screenStartStrip = (cd->_curPos >> 3) - 20;
+ _screenEndStrip = _screenStartStrip + 39;
+ virtscr[0].xstart = _screenStartStrip << 3;
+}
+
+void Scumm::palManipulate() {
+ byte *srcptr, *destptr;
+ byte *pal;
+ int i,j;
+
+ if (!_palManipCounter)
+ return;
+ srcptr = getResourceAddress(0xC, 4) + _palManipStart*6;
+ destptr = getResourceAddress(0xC, 5) + _palManipStart*6;
+ pal = _currentPalette + _palManipStart * 3;
+
+ i = _palManipStart;
+ while (i < _palManipEnd) {
+ j = (*((uint16*)srcptr) += *(uint16*)destptr );
+ *pal++ = j>>8;
+ srcptr += 2;
+ destptr += 2;
+
+ j = (*((uint16*)srcptr) += *(uint16*)destptr );
+ *pal++ = j>>8;
+ srcptr += 2;
+ destptr += 2;
+
+ j = (*((uint16*)srcptr) += *(uint16*)destptr );
+ *pal++ = j>>8;
+ srcptr += 2;
+ destptr += 2;
+
+ i++;
+ }
+ setDirtyColors(_palManipStart, _palManipEnd);
+ if (!--_palManipCounter) {
+ nukeResource(0xC, 4);
+ nukeResource(0xC, 5);
+ }
+}
+
+void Scumm::screenEffect(int effect) {
+ removeMouseCursor();
+ dseg_3DB6 = 1;
+ warning("stub screenEffect(%d)",effect);
+ /* TODO: not implemented */
+ dseg_4EA0 = 1;
+}
+
+void Scumm::resetActorBgs() {
+ Actor *a;
+ int i,bitpos;
+ int top,bottom;
+
+ for(i=0; i<40; i++) {
+ _onlyActorFlags = (actorDrawBits[_screenStartStrip + i]&=0x3FFF);
+ a = getFirstActor();
+ bitpos = 1;
+
+ while (_onlyActorFlags) {
+ if(_onlyActorFlags&1 && a->top!=0xFF && a->needBgReset) {
+ top = a->top;
+ bottom = a->bottom;
+ if (a->top < virtscr[0].tdirty[i])
+ virtscr[0].tdirty[i] = a->top;
+
+ if (a->bottom > virtscr[0].bdirty[i])
+ virtscr[0].bdirty[i] = a->bottom;
+ actorDrawBits[_screenStartStrip + i] ^= bitpos;
+
+ gdi.where_to_draw_ptr = getResourceAddress(0xA, 5)
+ + ((top * 40 + _screenStartStrip + i)<<3);
+ gdi.bg_ptr = getResourceAddress(0xA, 1)
+ + ((top * 40 + _screenStartStrip + i)<<3);
+ gdi.mask_ptr = getResourceAddress(0xA, 9)
+ + (top * 40 + _screenStartStrip + i);
+ gdi.numLinesToProcess = bottom - top;
+ if (gdi.numLinesToProcess) {
+ if (vm.vars[VAR_DRAWFLAGS]&2) {
+ if(hasCharsetMask(i<<3, top, (i+1)<<3, bottom))
+ draw8ColWithMasking();
+ else
+ blit(gdi.bg_ptr, gdi.where_to_draw_ptr, 8, gdi.numLinesToProcess);
+ } else {
+ clear8Col();
+ }
+ }
+ }
+ bitpos<<=1;
+ _onlyActorFlags>>=1;
+ a++;
+ }
+ }
+
+ for(i=1,a=getFirstActor(); ++a,i<13; i++) {
+ a->needBgReset = false;
+ }
+}
+
+void Scumm::setPalColor(int index, int r, int g, int b) {
+ if(_videoMode==0x13) {
+ _currentPalette[index*3+0] = r>>2;
+ _currentPalette[index*3+1] = g>>2;
+ _currentPalette[index*3+2] = b>>2;
+ }
+ if (_videoMode==0xE) {
+ /* TODO: implement this */
+ warning("stub setPalColor(%d,%d,%d,%d)",index,r,g,b);
+ }
+}
+
+void Scumm::removeMouseCursor() {
+ gdi.unk3 = 0;
+ drawMouse();
+}
+
+void Scumm::drawMouse() {
+ /* TODO: handle shake here */
+
+ GDI_removeMouse();
+ if (gdi.unk3 && gdi.unk4>0) {
+ gdi.mouseColor = gdi.mouseColors[((++gdi.mouseColorIndex)>>2)&3];
+ gdi.drawMouseX = mouse.x - gdi.hotspot_x;
+ gdi.drawMouseY = mouse.y - gdi.hotspot_y;
+ gdi.mouseMaskPtr = gdi.mouseMask + ((gdi.drawMouseX&7)<<6);
+ gdi.mouseClipMask1 = (gdi.drawMouseX<0) ? 0 : 0xFF;
+ gdi.mouseClipMask2 = (gdi.drawMouseX>=312) ? 0 : 0xFF;
+ gdi.mouseClipMask3 = (gdi.drawMouseX>=304) ? 0 : 0xFF;
+ GDI_drawMouse();
+ }
+}
+
+void Scumm::setCursorHotspot(int cursor, int x, int y) {
+ MouseCursor *cur = &mouse_cursors[cursor];
+ cur->hotspot_x = x;
+ cur->hotspot_y = y;
+}
+
+void Scumm::setCursorImg(int cursor, int img) {
+ MouseCursor *cur = &mouse_cursors[cursor];
+ byte *ptr;
+
+ ptr = getResourceAddress(6, 1);
+
+// offs = ((uint32*)ptr)[img+1];
+// if (!offs)
+// return;
+
+ warning("setCursorImg: not fully implemented");
+}
+
+byte Scumm::isMaskActiveAt(int l, int t, int r, int b, byte *mem) {
+ int w,h,inc,i;
+
+ mem += b*40 + (l>>3);
+
+ w = (r>>3) - (l>>3) + 1;
+ inc = w+40;
+ h = b-t-1;
+
+ do {
+ for(i=0; i<w; i++)
+ if (mem[i])
+ return true;
+ mem -= 40;
+ } while (--h);
+
+ return false;
+}
+
+void Scumm::GDI_drawMouse() {
+#if 0
+ byte *dst,*src,*dstorg;
+ int y,h;
+ byte color,val;
+
+ byte mask1,mask2,mask3;
+
+ int offs = gdi.drawMouseY*320 + (gdi.drawMouseX&0xFFF8);
+
+ /* XXX: check bounds here */
+ if (offs<0 || offs > 320*200 - 16*320)
+ return;
+
+ gdi.backupIsWhere = _vgabuf + offs;
+
+ src = gdi.backupIsWhere;
+ dst = gdi.mouseBackup;
+
+ h=16;
+ do {
+ memcpy(dst,src,24);
+ dst+=24;
+ src+=320;
+ } while (--h);
+
+ src = gdi.mouseMaskPtr;
+ color = gdi.mouseColor;
+ dstorg = gdi.backupIsWhere;
+
+ h=16;
+ do {
+ src++;
+ mask1 = *src++;
+ mask2 = *src++;
+ mask3 = *src++;
+
+ y = gdi.drawMouseY++;
+ if (y>199)
+ mask1 = mask2 = 0;
+
+ val = mask1 & gdi.mouseClipMask1;
+ dst = dstorg;
+ do {
+ if(val&0x80)
+ *dst = color;
+ dst++;
+ } while (val<<=1);
+
+ val = mask2 & gdi.mouseClipMask2;
+ dst = dstorg + 8;
+ do {
+ if(val&0x80)
+ *dst = color;
+ dst++;
+ } while (val<<=1);
+
+ val = mask3 & gdi.mouseClipMask3;
+ dst = dstorg + 16;
+ do {
+ if(val&0x80)
+ *dst = color;
+ dst++;
+ } while (val<<=1);
+
+ dstorg += 320;
+ } while (--h);
+#endif
+}
+
+void Scumm::GDI_removeMouse() {
+ byte *dst,*src,h;
+ if (gdi.backupIsWhere) {
+ dst = gdi.backupIsWhere;
+ gdi.backupIsWhere = NULL;
+ src = gdi.mouseBackup;
+ h=16;
+ do {
+ memcpy(dst,src,24);
+ dst+=320;
+ src+=24;
+ } while (--h);
+ }
+}
diff --git a/object.cpp b/object.cpp
new file mode 100644
index 0000000000..6590d0ffaa
--- /dev/null
+++ b/object.cpp
@@ -0,0 +1,584 @@
+/* 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.
+ *
+ * Change Log:
+ * $Log$
+ * Revision 1.1 2001/10/09 14:30:14 strigeus
+ * Initial revision
+ *
+ *
+ */
+
+#include "stdafx.h"
+#include "scumm.h"
+
+bool Scumm::getClass(int obj, int cls) {
+ checkRange(_maxNrObjects-1, 0, obj, "Object %d out of range in getClass");
+
+ cls &= 0x7F;
+ checkRange(32,1,cls,"Class %d out of range in getClass");
+
+ return (_classData[obj] & (1<<(cls-1))) != 0;
+}
+
+void Scumm::putClass(int obj, int cls, bool set) {
+ checkRange(_maxNrObjects-1, 0, obj, "Object %d out of range in getClass");
+
+ cls &= 0x7F;
+ checkRange(32,1,cls,"Class %d out of range in getClass");
+
+ if (set)
+ _classData[obj] |= (1<<(cls-1));
+ else
+ _classData[obj] &= ~(1<<(cls-1));
+}
+
+int Scumm::getOwner(int obj) {
+ checkRange(_maxNrObjects-1, 0, obj, "Object %d out of range in getOwner");
+ return _objectFlagTable[obj]&0xF;
+}
+
+void Scumm::putOwner(int act, int owner) {
+ checkRange(_maxNrObjects-1, 0, act, "Object %d out of range in putOwner");
+ checkRange(15, 0, owner, "Owner %d out of range in putOwner");
+ _objectFlagTable[act] = (_objectFlagTable[act]&0xF0) | owner;
+}
+
+int Scumm::getState(int act) {
+ checkRange(_maxNrObjects-1, 0, act, "Object %d out of range in getState");
+ return _objectFlagTable[act]>>4;
+}
+
+void Scumm::putState(int act, int state) {
+ checkRange(_maxNrObjects-1, 0, act, "Object %d out of range in putState");
+ checkRange(15, 0, state, "State %d out of range in putState");
+ _objectFlagTable[act] = (_objectFlagTable[act]&0x0F) | (state<<4);
+}
+
+int Scumm::getObjectIndex(int object) {
+ int i;
+
+ if ((_objectFlagTable[object]&0xF)!=0xF) {
+ for (i=0; i<_maxInventoryItems; i++)
+ if (_inventory[i] == object)
+ return i;
+ return -1;
+ } else {
+ for (i=_numObjectsInRoom; i>0; i--) {
+ if (objs[i].obj_nr==object)
+ return i;
+ }
+ return -1;
+ }
+}
+
+int Scumm::whereIsObject(int object) {
+ int i;
+
+ if ((_objectFlagTable[object]&0xF)!=0xF) {
+ for (i=0; i<_maxInventoryItems; i++)
+ if (_inventory[i] == object)
+ return 0;
+ return -1;
+ }
+
+ for (i=_numObjectsInRoom; i>0; i--)
+ if (objs[i].obj_nr == object) {
+ if (objs[i].fl_object_index)
+ return 4;
+ return 1;
+ }
+ return -1;
+}
+
+int Scumm::getObjectOrActorXY(int object) {
+ if (object <= vm.vars[VAR_NUM_ACTOR]) {
+ return getActorXYPos(derefActorSafe(object, "getObjectOrActorXY"));
+ }
+ switch(whereIsObject(object)) {
+ case -1:
+ return -1;
+ case 0:
+ return getActorXYPos(derefActorSafe(_objectFlagTable[object]&0xF,"getObjectOrActorXY(2)"));
+ }
+ getObjectXYPos(object);
+ return 0;
+}
+
+void Scumm::getObjectXYPos(int object) {
+ ObjectData *od = &objs[getObjectIndex(object)];
+ AdjustBoxResult abr;
+ abr = adjustXYToBeInBox(0, od->cdhd_10, od->cdhd_12);
+ _xPos = abr.x;
+ _yPos = abr.y;
+ _dir = od->actordir&3;
+}
+
+int Scumm::getObjActToObjActDist(int a, int b) {
+ int x,y;
+ Actor *acta = NULL;
+ Actor *actb = NULL;
+
+ if (a<=vm.vars[VAR_NUM_ACTOR])
+ acta = derefActorSafe(a, "getObjActToObjActDist");
+
+ if (b<=vm.vars[VAR_NUM_ACTOR])
+ actb = derefActorSafe(b, "getObjActToObjActDist(2)");
+
+ if (acta && actb && acta->room==actb->room && acta->room &&
+ acta->room != _currentRoom)
+ return 0xFF;
+
+ if (getObjectOrActorXY(a)==-1)
+ return 0xFF;
+
+ x = _xPos;
+ y = _yPos;
+
+ if (getObjectOrActorXY(b)==-1)
+ return 0xFF;
+
+ /* XXX: bug here? should be <= */
+ if (acta) {
+ AdjustBoxResult r = adjustXYToBeInBox(acta, _xPos, _yPos);
+ _xPos = r.x;
+ _yPos = r.y;
+ }
+
+ y = abs(y-_yPos);
+ x = abs(x-_xPos);
+
+ if (y>x) x=y;
+ return x;
+}
+
+int Scumm::findObject(int x, int y) {
+ int i,a,b;
+
+ for (i=1; i<=_numObjectsInRoom; i++) {
+ if (!objs[i].obj_nr || getClass(objs[i].obj_nr, 32))
+ continue;
+ b = i;
+ do {
+ a = objs[b].cdhd_0e;
+ b = objs[b].cdhd_0f;
+ if (b==0) {
+ if (objs[i].x_pos <= (x>>3) &&
+ objs[i].numstrips + objs[i].x_pos > (x>>3) &&
+ objs[i].y_pos <= (y>>3) &&
+ objs[i].height + objs[i].y_pos > (y>>3))
+ return objs[i].obj_nr;
+ break;
+ }
+ } while ( (objs[b].ownerstate&0xF0) == a);
+ }
+ return 0;
+}
+
+void Scumm::drawRoomObjects(int arg) {
+ int num = _numObjectsInRoom;
+ ObjectData *od;
+ int a;
+
+ if (num==0)
+ return;
+
+ do {
+ od = &objs[num];
+ if (!od->obj_nr || !(od->ownerstate&0xF0))
+ continue;
+
+ do {
+ a = od->cdhd_0e;
+ if (!od->cdhd_0f) {
+ drawObject(num, arg);
+ break;
+ }
+ od = &objs[od->cdhd_0f];
+ } while ((od->ownerstate & 0xF0)==a);
+
+ } while (--num);
+}
+
+const uint32 state_tags[] = {
+ MKID('IM00'),
+ MKID('IM01'),
+ MKID('IM02'),
+ MKID('IM03'),
+ MKID('IM04'),
+ MKID('IM05'),
+ MKID('IM06'),
+ MKID('IM07'),
+ MKID('IM08'),
+ MKID('IM09'),
+ MKID('IM0A'),
+ MKID('IM0B'),
+ MKID('IM0C'),
+ MKID('IM0D'),
+ MKID('IM0E'),
+ MKID('IM0F')
+};
+
+void Scumm::drawObject(int obj, int arg) {
+ ObjectData *od;
+ int xpos, ypos, height, width;
+ byte *ptr;
+ int x,a,b;
+
+ if (_BgNeedsRedraw)
+ arg = 0;
+
+ gdi.virtScreen = 0;
+
+ od = &objs[obj];
+
+ xpos = od->x_pos;
+ ypos = od->y_pos;
+ width = od->numstrips;
+ height = od->height;
+
+ if (width==0 || xpos > _screenEndStrip || xpos + width < _screenStartStrip)
+ return;
+
+ if (od->fl_object_index) {
+ ptr = getResourceAddress(0xD, od->fl_object_index);
+ ptr = findResource(MKID('OBIM'), ptr);
+ } else {
+ ptr = getResourceAddress(1, _roomResource);
+ ptr = ptr + od->offs_obim_to_room;
+ }
+
+ ptr = findResource(state_tags[getState(od->obj_nr)], ptr);
+ if (!ptr)
+ return;
+
+ x = 0xFFFF;
+
+ for (a=b=0; a<width; a++) {
+ _drawBmpX = xpos + a;
+ if (arg==1 && _screenStartStrip!=_drawBmpX)
+ continue;
+ if (arg==2 && _screenEndStrip!=_drawBmpX)
+ continue;
+ if (_screenStartStrip > _drawBmpX || _drawBmpX > _screenEndStrip)
+ continue;
+ actorDrawBits[_drawBmpX] |= 0x8000;
+ if (_drawBmpX < x)
+ x = _drawBmpX;
+ b++;
+ }
+
+ if (b==0)
+ return;
+
+ _drawBmpY = ypos << 3;
+ gdi.numLinesToProcess = height << 3;
+
+ _drawBmpX = x;
+ drawBmp(ptr, x - xpos, b, 1, "Object", od->obj_nr);
+}
+
+void Scumm::loadRoomObjects() {
+ int i,j;
+ ObjectData *od;
+ byte *ptr;
+ uint16 obim_id;
+ byte *room,*tmp_room;
+ ImageHeader *imhd;
+ RoomHeader *roomhdr;
+
+ CodeHeader *cdhd;
+
+ checkHeap();
+
+ room = getResourceAddress(1, _roomResource);
+ roomhdr = (RoomHeader*)findResource(MKID('RMHD'), room);
+
+ _numObjectsInRoom = READ_LE_UINT16(&roomhdr->numObjects);
+
+ if (_numObjectsInRoom == 0)
+ return;
+
+ if (_numObjectsInRoom > 200)
+ error("More than %d objects in room %d", 200, _roomResource);
+
+ tmp_room = room;
+
+ od = &objs[1];
+ for (i=1; i<=_numObjectsInRoom; i++,od++) {
+ ptr = findResource(MKID('OBCD'), tmp_room);
+ if (ptr==NULL)
+ error("Room %d missing object code block(s)", _roomResource);
+
+ od->offs_obcd_to_room = ptr - room;
+ cdhd = (CodeHeader*)findResource2(MKID('CDHD'), ptr);
+ od->obj_nr = READ_LE_UINT16(&cdhd->obj_id);
+
+#ifdef DUMP_SCRIPTS
+ do {
+ char buf[32];
+ sprintf(buf,"roomobj-%d-",_roomResource);
+ dumpResource(buf, od->obj_nr, ptr);
+ } while (0);
+#endif
+ tmp_room = NULL;
+ }
+
+ tmp_room = room;
+ for (i=1; i<=_numObjectsInRoom; i++) {
+ ptr = findResource(MKID('OBIM'), tmp_room);
+ if (ptr==NULL)
+ error("Room %d missing image blocks(s)", _roomResource);
+
+ imhd = (ImageHeader*)findResource2(MKID('IMHD'), ptr);
+ obim_id = READ_LE_UINT16(&imhd->obj_id);
+
+ for(j=1; j<=_numObjectsInRoom; j++) {
+ if (objs[j].obj_nr==obim_id)
+ objs[j].offs_obim_to_room = ptr - room;
+ }
+ tmp_room = NULL;
+ }
+
+ od = &objs[1];
+ for (i=1; i<=_numObjectsInRoom; i++,od++) {
+ ptr = room + objs[i].offs_obcd_to_room;
+ cdhd = (CodeHeader*)findResource2(MKID('CDHD'), ptr);
+ objs[i].obj_nr = READ_LE_UINT16(&cdhd->obj_id);
+ objs[i].numstrips = cdhd->w;
+ objs[i].height = cdhd->h;
+ objs[i].x_pos = cdhd->x;
+ objs[i].y_pos = cdhd->y;
+
+ if (!(cdhd->flags&0x80)) {
+ objs[i].cdhd_0e = 0x10;
+ } else {
+ objs[i].cdhd_0e = cdhd->flags;
+ }
+ objs[i].cdhd_0f = cdhd->unk1;
+ objs[i].cdhd_10 = READ_LE_UINT16(&cdhd->unk2);
+ objs[i].cdhd_12 = READ_LE_UINT16(&cdhd->unk3);
+ objs[i].actordir = cdhd->unk4;
+ objs[i].fl_object_index = 0;
+ }
+
+ checkHeap();
+}
+
+void Scumm::fixObjectFlags() {
+ int i;
+ ObjectData *od = &objs[1];
+ for (i=1; i<=_numObjectsInRoom; i++,od++) {
+ od->ownerstate = _objectFlagTable[od->obj_nr];
+ }
+}
+
+void Scumm::processDrawQue() {
+ int i, j;
+ for (i=0; i<_drawObjectQueNr; i++) {
+ j = _drawObjectQue[i];
+ if (j)
+ drawObject(j,0);
+ }
+ _drawObjectQueNr = 0;
+}
+
+void Scumm::clearOwnerOf(int obj) {
+ int i,j;
+ uint16 *a;
+ byte *ptr;
+
+ stopObjectScript(obj);
+
+ if (getOwner(obj)==0xF) {
+ i = 0;
+ do {
+ if (objs[i].obj_nr==obj) {
+ if (!objs[i].fl_object_index)
+ return;
+ nukeResource(0xD, objs[i].fl_object_index);
+ objs[i].obj_nr = 0;
+ objs[i].fl_object_index = 0;
+ }
+ } while(++i <= _numObjectsInRoom);
+ return;
+ }
+ for (i=1; i<_maxInventoryItems; i++) {
+ if (_inventory[i] == obj) {
+ j = whereIsObject(obj);
+ if (j==0) {
+ nukeResource(5, i);
+ _inventory[i] = 0;
+ }
+ a = &_inventory[2];
+ for (i=1; i < _maxInventoryItems-1; i++) {
+ if (!a[-1] && a[0]) {
+ a[-1] = a[0];
+ ptr = getResourceAddress(5, i+1);
+ _baseInventoryItems[i] = _baseInventoryItems[i+1];
+ /* TODO: some wacky write is done here */
+ error("clearOwnerOf: not fully implemented");
+ }
+ }
+ return;
+ }
+ }
+}
+
+void Scumm::removeObjectFromRoom(int obj) {
+ int i,cnt;
+ uint16 *ptr;
+
+ for(i=1; i<=_numObjectsInRoom; i++) {
+ if (objs[i].obj_nr==obj) {
+ if (objs[i].numstrips != 0) {
+ ptr = &actorDrawBits[objs[i].x_pos];
+ cnt = objs[i].numstrips;
+ do {
+ *ptr++ |= 0x8000;
+ } while (--cnt);
+ }
+ _BgNeedsRedraw = 1;
+ return;
+ }
+ }
+}
+
+void Scumm::addObjectToDrawQue(int object) {
+ _drawObjectQue[_drawObjectQueNr++] = object;
+ if (_drawObjectQueNr > 200)
+ error("Draw Object Que overflow");
+}
+
+void Scumm::clearDrawObjectQueue() {
+ _drawObjectQueNr = 0;
+}
+
+byte *Scumm::getObjOrActorName(int obj) {
+ byte *objptr;
+
+ if (obj <= vm.vars[VAR_NUM_ACTOR])
+ return getActorName(derefActorSafe(obj, "getObjOrActorName"));
+
+ objptr = getObjectAddress(obj);
+ if (objptr==NULL)
+ return (byte*)" ";
+
+ return findResource(MKID('OBNA'), objptr) + 8;
+}
+
+uint32 Scumm::getOBCDOffs(int object) {
+ int i;
+
+ if ((_objectFlagTable[object]&0xF)!=0xF)
+ return 0;
+ for (i=_numObjectsInRoom; i>0; i--) {
+ if (objs[i].obj_nr == object) {
+ if (objs[i].fl_object_index!=0)
+ return 8;
+ return objs[i].offs_obcd_to_room;
+ }
+ }
+ return 0;
+}
+
+byte *Scumm::getObjectAddress(int obj) {
+ int i;
+
+ if ((_objectFlagTable[obj]&0xF)!=0xF) {
+ for(i=0; i<_maxInventoryItems; i++) {
+ if (_inventory[i] == obj)
+ return getResourceAddress(5, i);
+ }
+ } else {
+ for(i=_numObjectsInRoom; i>0; --i) {
+ if (objs[i].obj_nr==obj) {
+ if (objs[i].fl_object_index)
+ return getResourceAddress(0xD, objs[i].fl_object_index)+8;
+ return getResourceAddress(1, _roomResource) + objs[i].offs_obcd_to_room;
+ }
+ }
+ }
+ return 0;
+}
+
+void Scumm::addObjectToInventory(int obj, int room) {
+ int i, slot;
+ byte *ptr,*obcdptr;
+ uint32 size,cdoffs;
+ int numobj;
+ byte *tmp_roomptr,*roomptr;
+ CodeHeader *cdhd;
+ RoomHeader *roomhdr;
+
+ debug(1,"Adding object %d from room %d into inventory", obj, room);
+
+ checkHeap();
+
+ if (whereIsObject(obj)==4) {
+ i = getObjectIndex(obj);
+ ptr = getResourceAddress(0xD, objs[i].fl_object_index) + 64;
+ size = READ_BE_UINT32_UNALIGNED(ptr+4);
+ slot = getInventorySlot();
+ _inventory[slot] = obj;
+ createResource(5, slot, size);
+ ptr = getResourceAddress(0xD, objs[i].fl_object_index) + 64;
+ memcpy(getResourceAddress(5, slot), ptr, size);
+ checkHeap();
+ return;
+ }
+ ensureResourceLoaded(1, room);
+ roomptr = getResourceAddress(1, room);
+ roomhdr = (RoomHeader*)findResource(MKID('RMHD'), roomptr);
+ numobj = READ_LE_UINT16(&roomhdr->numObjects);
+ if (numobj==0)
+ error("addObjectToInventory: No object found in room %d", room);
+ if (numobj > 200)
+ error("addObjectToInventory: More (%d) than %d objects in room %d", numobj, 200, room);
+
+ tmp_roomptr = roomptr;
+ for (i=1; i<=numobj; i++) {
+ obcdptr = findResource(MKID('OBCD'), tmp_roomptr);
+ if(obcdptr==NULL)
+ error("addObjectToInventory: Not enough code blocks in room %d", room);
+ cdhd = (CodeHeader*)findResource2(MKID('CDHD'), obcdptr);
+ if ( READ_LE_UINT16(&cdhd->obj_id) == obj) {
+ cdoffs = obcdptr - roomptr;
+ size = READ_BE_UINT32_UNALIGNED(obcdptr+4);
+ slot = getInventorySlot();
+ _inventory[slot] = obj;
+ createResource(5, slot, size);
+ obcdptr = getResourceAddress(1, room) + cdoffs;
+ memcpy(getResourceAddress(5,slot),obcdptr,size);
+ checkHeap();
+ return;
+ }
+ tmp_roomptr = NULL;
+ }
+
+ error("addObjectToInventory: Object %d not found in room %d", obj, room);
+}
+
+int Scumm::getInventorySlot() {
+ int i;
+ for (i=1; i<=_maxInventoryItems; i++) {
+ if (_inventory[i]==0)
+ return i;
+ }
+ error("Inventory full, %d max items", _maxInventoryItems);
+}
+
diff --git a/readme.txt b/readme.txt
new file mode 100644
index 0000000000..afeb7b5d58
--- /dev/null
+++ b/readme.txt
@@ -0,0 +1,48 @@
+2001-10-08
+
+This is the first pre-alpha release of ScummVM. It is an implementation of the SCUMM engine used in various Lucas Arts games such as Monkey Island and Day of the Tentacle.
+
+The engine is far from complete, and thus only Monkey Island 2 is supported at the moment.
+
+Please be aware that the engine contains bugs and non-implemented-features that make it impossible to finish the game. Other stuff that's missing is sound and savegames.
+
+Compiling:
+--------
+You need SDL-1.2.2 (maybe older versions will work), and a supported compiler. At the moment only GCC and Microsoft Visual C++ are supported.
+
+GCC:
+----
+* Edit the makefile and replace /usr/local/include/SDL/ with the path to your SDL include files.
+ If your processor architecture is big endian, replace -DSCUMM_LITTLE_ENDIAN by -DSCUMM_BIG_ENDIAN -DSCUMM_NEED_ALIGNMENT
+* Now type make (or gmake if that's what GNU make is called on your system) and hopefully ScummVM will compile for you.
+
+Please note that big endian support is preliminary and contains bugs.
+
+
+Microsoft Visual C++:
+---------------------
+* Open the workspace, scummwm.dsw
+* If you want to compile the GDI version, remove sdl.cpp from the project and add windows.cpp.
+ for the SDL version, remove windows.cpp from the project and add sdl.cpp.
+* Enter the path to the SDL include files in Tools|Options|Directories
+* Now it should compile successfully.
+
+
+Running:
+--------
+Before you run the engine, you need to put the game's datafiles in the same directory as the scummvm executable. The filenames must be in lowercase (monkey2.000 and monkey2.001).
+
+
+Good Luck,
+Ludvig Strigeus
+
+
+
+
+
+
+
+
+
+
+
diff --git a/resource.cpp b/resource.cpp
new file mode 100644
index 0000000000..603311b951
--- /dev/null
+++ b/resource.cpp
@@ -0,0 +1,647 @@
+/* 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.
+ *
+ * Change Log:
+ * $Log$
+ * Revision 1.1 2001/10/09 14:30:14 strigeus
+ * Initial revision
+ *
+ *
+ */
+
+#include "stdafx.h"
+#include "scumm.h"
+
+/* Open a room */
+void Scumm::openRoom(int room) {
+ uint room_offs;
+ char buf[256];
+
+ debug(9, "openRoom(%d)",room);
+
+ /* Don't load the same room again */
+ if (_lastLoadedRoom == room)
+ return;
+ _lastLoadedRoom = room;
+
+ /* Room -1 means close file */
+ if (room==-1) {
+ _encbyte = 0;
+ deleteRoomOffsets();
+ fileClose(_fileHandle);
+ _fileHandle = NULL;
+ return;
+ }
+
+ /* Either xxx.lfl or monkey.xxx file name */
+ while (!_resFilePrefix) {
+#if REAL_CODE
+ room_offs = _roomFileOffsets[room];
+#else
+ room_offs = room ? _roomFileOffsets[room] : 0;
+#endif
+
+ if (room_offs == 0xFFFFFFFF)
+ break;
+
+ if (room_offs != 0 && room != 0) {
+ _fileOffset = _roomFileOffsets[room];
+ return;
+ }
+ if (room==0) {
+ sprintf(buf, "%s.000", _exe_name);
+ } else {
+ sprintf(buf, "%s.%.3d", _exe_name, res.roomno[1][room]);
+ }
+ _encbyte = 0x69;
+ if (openResourceFile(buf)) {
+ if (room==0)
+ return;
+ readRoomsOffsets();
+ _fileOffset = _roomFileOffsets[room];
+
+ if (_fileOffset != 8)
+ return;
+
+ error("Room %d not in %s", room, buf);
+ return;
+ }
+ askForDisk();
+ }
+
+ do {
+ sprintf(buf, "%.3d.lfl", room);
+ _encbyte = 0;
+ if (openResourceFile(buf))
+ break;
+ askForDisk();
+ } while(1);
+
+ deleteRoomOffsets();
+ _fileOffset = 0; /* start of file */
+}
+
+/* Delete the currently loaded room offsets */
+void Scumm::deleteRoomOffsets() {
+ if (!_dynamicRoomOffsets)
+ return;
+
+ for (int i=0; i<_maxRooms; i++) {
+ if (_roomFileOffsets[i]!=0xFFFFFFFF)
+ _roomFileOffsets[i] = 0;
+ }
+}
+
+/* Read room offsets */
+void Scumm::readRoomsOffsets() {
+ int num,room;
+
+ debug(9, "readRoomOffsets()");
+
+ deleteRoomOffsets();
+ if (!_dynamicRoomOffsets)
+ return;
+
+ fileSeek(_fileHandle, 16, SEEK_SET);
+
+ num = fileReadByte();
+ while (num) {
+ num--;
+
+ room = fileReadByte();
+ if (_roomFileOffsets[room]!=0xFFFFFFFF) {
+ _roomFileOffsets[room] = fileReadDwordLE();
+ } else {
+ fileReadDwordLE();
+ }
+ }
+}
+
+bool Scumm::openResourceFile(const char *filename) {
+ char buf[256];
+
+ debug(9, "openResourceFile(%s)",filename);
+
+ if (_resFilePath) {
+ sprintf(buf, "%s.%d\\%s", _resFilePath, _resFilePathId, filename);
+ } else if (_resFilePrefix) {
+ sprintf(buf, "%s%s", _resFilePrefix, filename);
+ } else {
+ strcpy(buf, filename);
+ }
+
+ if (_fileHandle != NULL) {
+ fileClose(_fileHandle);
+ _fileHandle = NULL;
+ }
+
+ _fileHandle = fileOpen(buf, 1);
+
+ return _fileHandle != NULL;
+}
+
+void Scumm::askForDisk() {
+ /* TODO: Not yet implemented */
+ error("askForDisk: not yet implemented");
+}
+
+
+void Scumm::readIndexFile(int mode) {
+ uint32 blocktype,itemsize;
+ int numblock = 0;
+#if defined(SCUMM_BIG_ENDIAN)
+ int i;
+#endif
+
+ debug(9, "readIndexFile(%d)",mode);
+
+ openRoom(-1);
+ openRoom(0);
+
+ while (1) {
+ blocktype = fileReadDword();
+
+ if (fileReadFailed(_fileHandle))
+ break;
+ itemsize = fileReadDwordBE();
+
+ numblock++;
+
+ switch(blocktype) {
+ case MKID('DCHR'):
+ readResTypeList(6,MKID('CHAR'),"charset");
+ break;
+
+ case MKID('DOBJ'):
+ _maxNrObjects = fileReadWordLE();
+ _objectFlagTable = (byte*)alloc(_maxNrObjects);
+ if (mode==1) {
+ fileSeek(_fileHandle, itemsize - 10, 1);
+ break;
+ }
+
+ _classData = (uint32*)alloc(_maxNrObjects * sizeof(uint32));
+ fileRead(_fileHandle, _objectFlagTable, _maxNrObjects);
+ fileRead(_fileHandle, _classData, _maxNrObjects * sizeof(uint32));
+#if defined(SCUMM_BIG_ENDIAN)
+ for (i=0; i<_maxNrObjects; i++)
+ _classData[i] = FROM_LE_32(_classData[i]);
+#endif
+ break;
+
+ case MKID('RNAM'):
+ fileSeek(_fileHandle, itemsize-8,1);
+ break;
+
+ case MKID('DROO'):
+ readResTypeList(1,MKID('ROOM'),"room");
+ break;
+
+ case MKID('DSCR'):
+ readResTypeList(2,MKID('SCRP'),"script");
+ break;
+
+ case MKID('DCOS'):
+ readResTypeList(3,MKID('COST'),"costume");
+ break;
+
+ case MKID('MAXS'):
+ fileReadWordLE();
+ fileReadWordLE();
+ fileReadWordLE();
+ fileReadWordLE();
+ fileReadWordLE();
+ fileReadWordLE();
+ fileReadWordLE();
+ fileReadWordLE();
+ fileReadWordLE();
+ break;
+
+ case MKID('DSOU'):
+ readResTypeList(4,MKID('SOUN'),"sound");
+ break;
+
+ default:
+ error("Bad ID %c%c%c%c found in directory!", blocktype&0xFF, blocktype>>8, blocktype>>16, blocktype>>24);
+ return;
+ }
+ }
+
+ clearFileReadFailed(_fileHandle);
+
+ if (numblock!=8)
+ error("Not enough blocks read from directory");
+
+ openRoom(-1);
+
+ _numGlobalScriptsUsed = _maxScripts;
+ _dynamicRoomOffsets = true;
+}
+
+void Scumm::readResTypeList(int id, uint32 tag, const char *name) {
+ int num;
+#if defined(SCUMM_BIG_ENDIAN)
+ int i;
+#endif
+
+ debug(9, "readResTypeList(%d,%x,%s)",id,FROM_LE_32(tag),name);
+
+ num = fileReadWordLE();
+
+ if (num>0xFF) {
+ error("Too many %ss (%d) in directory", name, num);
+ }
+
+ allocResTypeData(id, tag, num, name, 1);
+
+ fileRead(_fileHandle, res.roomno[id], num);
+ fileRead(_fileHandle, res.roomoffs[id], num*sizeof(uint32));
+
+#if defined(SCUMM_BIG_ENDIAN)
+ for (i=0; i<num; i++)
+ res.roomoffs[id][i] = FROM_LE_32(res.roomoffs[id][i]);
+#endif
+}
+
+void Scumm::allocResTypeData(int id, uint32 tag, int num, const char *name, int mode) {
+ debug(9, "allocResTypeData(%d,%x,%d,%s,%d)",id,FROM_LE_32(tag),num,name,mode);
+ res.mode[id] = mode;
+ res.num[id] = num;
+ res.tags[id] = tag;
+ res.name[id] = name;
+ res.address[id] = (byte**)alloc(num*sizeof(void*));
+ res.flags[id] = (byte*)alloc(num*sizeof(byte));
+
+ if (mode) {
+ res.roomno[id] = (byte*)alloc(num*sizeof(byte));
+ res.roomoffs[id] = (uint32*)alloc(num*sizeof(uint32));
+ }
+}
+
+void Scumm::loadCharset(int no) {
+ int i;
+ byte *ptr;
+
+ debug(9, "loadCharset(%d)",no);
+
+ checkRange(_maxCharsets-1, 1, no, "Loading illegal charset %d");
+ ensureResourceLoaded(6, no);
+ ptr = getResourceAddress(6, no);
+
+ for (i=0; i<15; i++) {
+ _charsetData[no][i+1] = ptr[i+14];
+ }
+}
+
+void Scumm::nukeCharset(int i) {
+ checkRange(_maxCharsets-1, 1, i, "Nuking illegal charset %d");
+ nukeResource(6, i);
+}
+
+void Scumm::ensureResourceLoaded(int type, int i) {
+ void *addr;
+
+ debug(9, "ensureResourceLoaded(%d,%d)", type, i);
+
+ if (type==1 && i>127) {
+ i = _resourceMapper[i&127];
+ }
+
+ if (i==0)
+ return;
+
+ addr = res.address[type][i];
+ if (addr)
+ return;
+
+ loadResource(type, i);
+
+ if (type==1 && i==_roomResource)
+ vm.vars[VAR_ROOM_FLAG] = 1;
+}
+
+int Scumm::loadResource(int type, int index) {
+ int roomNr, i;
+ uint32 fileOffs;
+ uint32 size, tag;
+
+ debug(9, "loadResource(%d,%d)", type,index);
+
+ roomNr = getResourceRoomNr(type, index);
+ if (roomNr == 0 || index >= res.num[type]) {
+ error("%s %d undefined",
+ res.name[type],index);
+ }
+
+ if (type==1) {
+ fileOffs = 0;
+ } else {
+ fileOffs = res.roomoffs[type][index];
+ if (fileOffs==0xFFFFFFFF)
+ return 0;
+ }
+
+ do {
+ for (i=0; i<5; i++) {
+ _resIndexToLoad = index;
+ _resTypeToLoad = type;
+ openRoom(roomNr);
+
+ fileSeek(_fileHandle, fileOffs + _fileOffset, SEEK_SET);
+ if (type==4) {
+ fileReadDwordLE();
+ fileReadDwordLE();
+ return readSoundResource(type, index);
+ }
+
+ tag = fileReadDword();
+
+ if (tag != res.tags[type]) {
+ error("%s %d not in room %d at %d+%d",
+ res.name[type], type, roomNr, _fileOffset, fileOffs);
+ }
+
+ size = fileReadDwordBE();
+ fileSeek(_fileHandle, -8, SEEK_CUR);
+
+ fileRead(_fileHandle, createResource(type, index, size), size);
+
+ /* dump the resource */
+#ifdef DUMP_SCRIPTS
+ if(type==2) {
+ dumpResource("script-", index, getResourceAddress(2, index));
+ }
+#endif
+
+ if (!fileReadFailed(_fileHandle)) {
+ _scummTimer = 0;
+ return 1;
+ }
+
+ nukeResource(type, index);
+ }
+
+ error("Cannot read resource");
+ } while(1);
+}
+
+int Scumm::readSoundResource(int type, int index) {
+ uint32 resStart, size, tag, size2;
+ byte *ptr;
+ int i;
+
+ debug(9, "readSoundResource(%d,%d)", type, index);
+
+ resStart = 0;
+
+ fileReadDwordLE();
+ size = fileReadDwordBE();
+
+ while (size>resStart) {
+ tag = fileReadDword();
+ size2 = fileReadDwordBE();
+
+ resStart += size2 + 8;
+
+ for (i=0,ptr=_soundTagTable; i<_numSoundTags; i++,ptr+=5) {
+/* endian OK, tags are in native format */
+ if (READ_UINT32_UNALIGNED(ptr) == tag) {
+ fileSeek(_fileHandle, -8, SEEK_CUR);
+ fileRead(_fileHandle,createResource(type, index, size2+8), size+8);
+ return 1;
+ }
+ }
+
+ fileSeek(_fileHandle, size2, SEEK_CUR);
+ }
+
+ res.roomoffs[type][index] = 0xFFFFFFFF;
+ return 0;
+}
+
+
+int Scumm::getResourceRoomNr(int type, int index) {
+ if (type==1)
+ return index;
+ return res.roomno[type][index];
+}
+
+byte *Scumm::getResourceAddress(int type, int index) {
+ byte *ptr;
+
+ debug(9, "getResourceAddress(%d,%d)", type, index);
+
+ checkHeap();
+
+ validateResource("getResourceAddress", type, index);
+
+ if (res.mode[type] && !res.address[type][index]) {
+ ensureResourceLoaded(type, index);
+ }
+
+ setResourceFlags(type, index, 1);
+
+ ptr=(byte*)res.address[type][index];
+ if (!ptr)
+ return NULL;
+
+ return ptr + 8;
+}
+
+void Scumm::setResourceFlags(int type, int index, byte flag) {
+ res.flags[type][index] &= 0x80;
+ res.flags[type][index] |= flag;
+}
+
+byte *Scumm::createResource(int type, int index, uint32 size) {
+ byte *ptr;
+
+ checkHeap();
+
+ debug(9, "createResource(%d,%d,%d)", type, index,size);
+
+ if (size > 65536*4+37856)
+ error("Invalid size allocating");
+
+ validateResource("allocating", type, index);
+ nukeResource(type, index);
+
+ ptr = (byte*)alloc(size + 8);
+ if (ptr==NULL) {
+ error("Out of memory while allocating %d", size);
+ }
+
+ res.address[type][index] = ptr;
+
+ setResourceFlags(type, index, 1);
+
+ return ptr + 8; /* skip header */
+}
+
+void Scumm::validateResource(const char *str, int type, int index) {
+ if (type<1 || type>15 || index<0 || index >= res.num[type]) {
+ error("%d Illegal Glob type %d num %d", str, type, index);
+ }
+}
+
+void Scumm::nukeResource(int type, int index) {
+
+ debug(9, "nukeResource(%d,%d)", type, index);
+
+ checkHeap();
+ assert( res.address[type] );
+ assert( index>=0 && index < res.num[type]);
+
+ if (res.address[type][index]) {
+ free(res.address[type][index]);
+ res.address[type][index] = 0;
+ }
+}
+
+void Scumm::unkResourceProc() {
+ int i;
+ for (i=1; i<16; i++) {
+ }
+ /* TODO: not implemented */
+ warning("unkResourceProc: not implemented");
+}
+
+
+byte *Scumm::findResource(uint32 tag, byte *searchin) {
+ uint32 size;
+
+ if (searchin) {
+ searchin+=4;
+ _findResSize = READ_BE_UINT32_UNALIGNED(searchin);
+ _findResHeaderSize = 8;
+ _findResPos = searchin+4;
+ goto startScan;
+ }
+
+ do {
+ size = READ_BE_UINT32_UNALIGNED(_findResPos+4);
+ if ((int32)size <= 0) {
+ error("(%c%c%c%c) Not found in %d... illegal block len %d",
+ tag&0xFF,(tag>>8)&0xFF,(tag>>16)&0xFF,(tag>>24)&0xFF,
+ 0,
+ size);
+ return NULL;
+ }
+ _findResHeaderSize += size;
+ _findResPos += size;
+
+startScan:;
+ if (_findResHeaderSize >= _findResSize)
+ return NULL;
+/* endian OK, tags are in native format */
+ } while (READ_UINT32_UNALIGNED(_findResPos) != tag);
+
+ return _findResPos;
+}
+
+byte *Scumm::findResource2(uint32 tag, byte *searchin) {
+ uint32 size;
+
+ if (searchin) {
+ searchin+=4;
+ _findResSize2 = READ_BE_UINT32_UNALIGNED(searchin);
+ _findResHeaderSize2 = 8;
+ _findResPos2 = searchin+4;
+ goto startScan;
+ }
+
+ do {
+ size = READ_BE_UINT32_UNALIGNED(_findResPos2+4);
+ if ((int32)size <= 0) {
+ error("(%c%c%c%c) Not found in %d... illegal block len %d",
+ tag&0xFF,(tag>>8)&0xFF,(tag>>16)&0xFF,(tag>>24)&0xFF,
+ 0,
+ size);
+ return NULL;
+ }
+ _findResHeaderSize2 += size;
+ _findResPos2 += size;
+
+startScan:;
+ if (_findResHeaderSize2 >= _findResSize2)
+ return NULL;
+/* endian OK, tags are in native format */
+ } while (READ_UINT32_UNALIGNED(_findResPos2) != tag);
+ return _findResPos2;
+}
+
+void Scumm::lock(int type, int i) {
+ validateResource("Locking", type, i);
+ res.flags[type][i] |= 0x80;
+
+}
+
+void Scumm::unlock(int type, int i) {
+ validateResource("Unlocking", type, i);
+ res.flags[type][i] &= ~0x7F;
+}
+
+void Scumm::loadPtrToResource(int type, int resindex, byte *source) {
+ byte *ptr, *alloced;
+ int i,len;
+
+ nukeResource(type, resindex);
+ if (!source) {
+ ptr = _scriptPointer;
+ } else {
+ ptr = source;
+ }
+
+ len = 0;
+ do {
+ i = *ptr++;
+ if (!i) break;
+ len++;
+ if (i==0xFF)
+ ptr += 3, len += 3;
+ } while (1);
+
+ if (++len <= 1)
+ return;
+
+ alloced = createResource(type, resindex, len);
+
+ if (!source) {
+ alloced[0] = fetchScriptByte();
+ for (i=1; i<len; i++)
+ alloced[i] = *_scriptPointer++;
+ } else {
+ for(i=0; i<len; i++)
+ alloced[i] = source[i];
+ }
+}
+
+void Scumm::heapClear(int mode) {
+ /* TODO: implement this */
+ warning("heapClear: not implemented");
+}
+
+
+void Scumm::unkHeapProc2(int a, int b) {
+ warning("unkHeapProc2: not implemented");
+}
+
+void Scumm::unkResProc(int a, int b) {
+ error("unkResProc:not implemented");
+}
+
+
diff --git a/saveload.cpp b/saveload.cpp
new file mode 100644
index 0000000000..c7f46504aa
--- /dev/null
+++ b/saveload.cpp
@@ -0,0 +1,59 @@
+/* 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.
+ *
+ * Change Log:
+ * $Log$
+ * Revision 1.1 2001/10/09 14:30:13 strigeus
+ * Initial revision
+ *
+ *
+ */
+
+#include "stdafx.h"
+#include "scumm.h"
+
+
+bool Scumm::saveState(const char *filename) {
+ FILE *out = fopen(filename,"wb");
+ if (out==NULL)
+ return false;
+ saveOrLoad(out,true);
+ fclose(out);
+ return true;
+}
+
+bool Scumm::loadState(const char *filename) {
+ FILE *out = fopen(filename,"rb");
+ if (out==NULL)
+ return false;
+ saveOrLoad(out,false);
+ fclose(out);
+ return true;
+}
+
+void Scumm::saveOrLoad(FILE *inout, bool mode) {
+ _saveLoadStream = inout;
+ _saveOrLoad = mode;
+}
+
+
+void Scumm::saveLoadBytes(void *b, int len) {
+ if (_saveOrLoad)
+ fwrite(b, 1, len, _saveLoadStream);
+ else
+ fread(b, 1, len, _saveLoadStream);
+}
diff --git a/script.cpp b/script.cpp
new file mode 100644
index 0000000000..df92f2f0d9
--- /dev/null
+++ b/script.cpp
@@ -0,0 +1,2857 @@
+/* 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.
+ *
+ * Change Log:
+ * $Log$
+ * Revision 1.1 2001/10/09 14:30:13 strigeus
+ * Initial revision
+ *
+ *
+ */
+
+#include "stdafx.h"
+#include "scumm.h"
+
+void Scumm::runScript(int script, int a, int b, int16 *lvarptr) {
+ byte *scriptPtr;
+ uint32 scriptOffs;
+ byte scriptType;
+ int slot,i;
+ ScriptSlot *s;
+
+ if (script==0)
+ return;
+
+ if (b==0)
+ stopScriptNr(script);
+
+ if (script < _numGlobalScriptsUsed) {
+ scriptPtr = getResourceAddress(2, script);
+ scriptOffs = 8;
+ scriptType = 2;
+ } else {
+ scriptOffs = _localScriptList[script - _numGlobalScriptsUsed];
+ if (scriptOffs == 0)
+ error("Local script %d is not in room %d", script, _roomResource);
+ scriptOffs += 9;
+ scriptType = 3;
+ }
+
+ slot = getScriptSlot();
+
+ s = &vm.slot[slot];
+ s->number = script;
+ s->offs = scriptOffs;
+ s->status = 2;
+ s->type = scriptType;
+ s->unk1 = a;
+ s->unk2 = b;
+ s->freezeCount = 0;
+
+ if (lvarptr==NULL) {
+ for(i=0; i<16; i++)
+ vm.localvar[slot * 0x11 + i] = 0;
+ } else {
+ for(i=0; i<16; i++)
+ vm.localvar[slot * 0x11 + i] = lvarptr[i];
+ }
+
+ runScriptNested(slot);
+}
+
+void Scumm::stopScriptNr(int script) {
+ ScriptSlot *ss;
+ NestedScript *nest;
+ int i,num;
+
+ if (script==0)
+ return;
+
+ ss = &vm.slot[1];
+
+ for (i=1; i<20; i++,ss++) {
+ if (script!=ss->number || ss->type!=2 && ss->type!=3 || ss->status==0)
+ continue;
+
+ if (ss->cutsceneOverride)
+ error("Script %d stopped with active cutscene/override", script);
+ ss->number = 0;
+ ss->status = 0;
+ if (_currentScript == i)
+ _currentScript = 0xFF;
+ }
+
+ if (_numNestedScripts==0)
+ return;
+
+ nest = &vm.nest[0];
+ num = _numNestedScripts;
+
+ do {
+ if (nest->number == script && (nest->type==2 || nest->type==3)) {
+ nest->number = 0xFFFF;
+ nest->slot = 0xFF;
+ nest->type = 0xFF;
+ }
+ } while(nest++,--num);
+}
+
+void Scumm::stopObjectScript(int script) {
+ ScriptSlot *ss;
+ NestedScript *nest;
+ int i,num;
+
+ if (script==0)
+ return;
+
+ ss = &vm.slot[1];
+
+ for (i=1; i<20; i++,ss++) {
+ if (script!=ss->number || ss->type!=1 && ss->type!=0 && ss->type!=4 || ss->status==0)
+ continue;
+
+ if (ss->cutsceneOverride)
+ error("Object %d stopped with active cutscene/override", script);
+ ss->number = 0;
+ ss->status = 0;
+ if (_currentScript == i)
+ _currentScript = 0xFF;
+ }
+
+ if (_numNestedScripts==0)
+ return;
+
+ nest = &vm.nest[0];
+ num = _numNestedScripts;
+
+ do {
+ if (nest->number == script && (nest->type==1 || nest->type==4 || nest->type==0)) {
+ nest->number = 0xFFFF;
+ nest->slot = 0xFF;
+ nest->type = 0xFF;
+ }
+ } while(nest++,--num);
+}
+
+int Scumm::getScriptSlot() {
+ ScriptSlot *ss;
+ int i;
+ ss = &vm.slot[1];
+
+ for (i=1; i<20; i++,ss++) {
+ if(ss->status==0)
+ return i;
+ }
+ error("Too many scripts running, %d max", 20);
+}
+
+void Scumm::runScriptNested(int script) {
+ NestedScript *nest;
+ ScriptSlot *slot;
+
+ updateScriptPtr();
+
+ nest = &vm.nest[_numNestedScripts];
+
+ if (_currentScript==0xFF) {
+ nest->number = 0xFF;
+ nest->type = 0xFF;
+ } else {
+ slot = &vm.slot[_currentScript];
+ nest->number = slot->number;
+ nest->type = slot->type;
+ /* scumm is buggy here */
+ nest->slot = _currentScript;
+ }
+
+ if (++_numNestedScripts>=0x10)
+ error("Too many nested scripts");
+
+ _currentScript = script;
+
+ getScriptBaseAddress();
+ getScriptEntryPoint();
+ executeScript();
+
+ _numNestedScripts--;
+
+ nest = &vm.nest[_numNestedScripts];
+
+ if (nest->number != 0xFF) {
+ slot = &vm.slot[nest->slot];
+ if (slot->number == nest->number && slot->type==nest->type &&
+ slot->status != 0 && slot->freezeCount==0) {
+ _currentScript = nest->slot;
+ getScriptBaseAddress();
+ getScriptEntryPoint();
+ return;
+ }
+ }
+ _currentScript = 0xFF;
+}
+
+void Scumm::updateScriptPtr() {
+ if (_currentScript == 0xFF)
+ return;
+
+ vm.slot[_currentScript].offs = _scriptPointer - _scriptOrgPointer;
+}
+
+void Scumm::getScriptBaseAddress() {
+ ScriptSlot *ss;
+ int index;
+
+ if (_currentScript == 0xFF)
+ return;
+
+ ss = &vm.slot[_currentScript];
+ switch(ss->type) {
+ case 0: /* inventory script **/
+ index = getObjectIndex(ss->number);
+ _scriptOrgPointer = getResourceAddress(5, index);
+ _lastCodePtr = &_baseInventoryItems[index];
+ break;
+
+ case 3:
+ case 1: /* room script */
+ _scriptOrgPointer = getResourceAddress(1, _roomResource);
+ _lastCodePtr = &_baseRooms[_roomResource];
+ break;
+
+ case 2: /* global script */
+ _scriptOrgPointer = getResourceAddress(2, ss->number);
+ _lastCodePtr = &_baseScripts[ss->number];
+ break;
+
+ case 4: /* flobject script */
+ index = getObjectIndex(ss->number);
+ _scriptOrgPointer = getResourceAddress(13,objs[index].fl_object_index);
+ _lastCodePtr = &_baseFLObject[ss->number];
+ break;
+ default:
+ error("Bad type while getting base address");
+ }
+}
+
+
+void Scumm::getScriptEntryPoint() {
+ if (_currentScript == 0xFF)
+ return;
+ _scriptPointer = _scriptOrgPointer + vm.slot[_currentScript].offs;
+}
+
+OpcodeProc FORCEINLINE Scumm::getOpcode(int i) {
+ static const OpcodeProc opcode_list[] = {
+ /* 00 */
+ &Scumm::o_stopObjectCode,
+ &Scumm::o_putActor,
+ &Scumm::o_startMusic,
+ &Scumm::o_getActorRoom,
+ /* 04 */
+ &Scumm::o_isGreaterEqual, /* hmm, seems to be less or equal */
+ &Scumm::o_drawObject,
+ &Scumm::o_getActorElevation,
+ &Scumm::o_setState,
+ /* 08 */
+ &Scumm::o_isNotEqual,
+ &Scumm::o_faceActor,
+ &Scumm::o_startScript,
+ &Scumm::o_getVerbEntrypoint,
+ /* 0C */
+ &Scumm::o_resourceRoutines,
+ &Scumm::o_walkActorToActor,
+ &Scumm::o_putActorAtObject,
+ &Scumm::o_getObjectState,
+ /* 10 */
+ &Scumm::o_getObjectOwner,
+ &Scumm::o_animateActor,
+ &Scumm::o_panCameraTo,
+ &Scumm::o_actorSet,
+ /* 14 */
+ &Scumm::o_print,
+ &Scumm::o_actorFromPos,
+ &Scumm::o_getRandomNr,
+ &Scumm::o_and,
+ /* 18 */
+ &Scumm::o_jumpRelative,
+ &Scumm::o_doSentence,
+ &Scumm::o_move,
+ &Scumm::o_multiply,
+ /* 1C */
+ &Scumm::o_startSound,
+ &Scumm::o_ifClassOfIs,
+ &Scumm::o_walkActorTo,
+ &Scumm::o_isActorInBox,
+ /* 20 */
+ &Scumm::o_stopMusic,
+ &Scumm::o_putActor,
+ &Scumm::o_getAnimCounter,
+ &Scumm::o_getActorY,
+ /* 24 */
+ &Scumm::o_loadRoomWithEgo,
+ &Scumm::o_pickupObject,
+ &Scumm::o_setVarRange,
+ &Scumm::o_stringOps,
+ /* 28 */
+ &Scumm::o_equalZero,
+ &Scumm::o_setOwnerOf,
+ &Scumm::o_startScript,
+ &Scumm::o_delayVariable,
+ /* 2C */
+ &Scumm::o_cursorCommand,
+ &Scumm::o_putActorInRoom,
+ &Scumm::o_delay,
+ &Scumm::o_badOpcode,
+ /* 30 */
+ &Scumm::o_matrixOps,
+ &Scumm::o_getInventoryCount,
+ &Scumm::o_setCameraAt,
+ &Scumm::o_roomOps,
+ /* 34 */
+ &Scumm::o_getDist,
+ &Scumm::o_findObject,
+ &Scumm::o_walkActorToObject,
+ &Scumm::o_startObject,
+ /* 38 */
+ &Scumm::o_lessOrEqual,
+ &Scumm::o_doSentence,
+ &Scumm::o_subtract,
+ &Scumm::o_getActorScale,
+ /* 3C */
+ &Scumm::o_stopSound,
+ &Scumm::o_findInventory,
+ &Scumm::o_walkActorTo,
+ &Scumm::o_drawBox,
+ /* 40 */
+ &Scumm::o_cutscene,
+ &Scumm::o_putActor,
+ &Scumm::o_chainScript,
+ &Scumm::o_getActorX,
+ /* 44 */
+ &Scumm::o_isLess,
+ &Scumm::o_badOpcode,
+ &Scumm::o_increment,
+ &Scumm::o_setState,
+ /* 48 */
+ &Scumm::o_isEqual,
+ &Scumm::o_faceActor,
+ &Scumm::o_startScript,
+ &Scumm::o_getVerbEntrypoint,
+ /* 4C */
+ &Scumm::o_soundKludge,
+ &Scumm::o_walkActorToActor,
+ &Scumm::o_putActorAtObject,
+ &Scumm::o_badOpcode,
+ /* 50 */
+ &Scumm::o_badOpcode,
+ &Scumm::o_animateActor,
+ &Scumm::o_actorFollowCamera,
+ &Scumm::o_actorSet,
+ /* 54 */
+ &Scumm::o_setObjectName,
+ &Scumm::o_actorFromPos,
+ &Scumm::o_getActorMoving,
+ &Scumm::o_or,
+ /* 58 */
+ &Scumm::o_overRide,
+ &Scumm::o_doSentence,
+ &Scumm::o_add,
+ &Scumm::o_divide,
+ /* 5C */
+ &Scumm::o_badOpcode,
+ &Scumm::o_actorSetClass,
+ &Scumm::o_walkActorTo,
+ &Scumm::o_isActorInBox,
+ /* 60 */
+ &Scumm::o_freezeScripts,
+ &Scumm::o_putActor,
+ &Scumm::o_stopScript,
+ &Scumm::o_getActorFacing,
+ /* 64 */
+ &Scumm::o_loadRoomWithEgo,
+ &Scumm::o_pickupObject,
+ &Scumm::o_getClosestObjActor,
+ &Scumm::o_dummy,
+ /* 68 */
+ &Scumm::o_getScriptRunning,
+ &Scumm::o_setOwnerOf,
+ &Scumm::o_startScript,
+ &Scumm::o_debug,
+ /* 6C */
+ &Scumm::o_getActorWidth,
+ &Scumm::o_putActorInRoom,
+ &Scumm::o_stopObjectScript,
+ &Scumm::o_badOpcode,
+ /* 70 */
+ &Scumm::o_lights,
+ &Scumm::o_getActorCostume,
+ &Scumm::o_loadRoom,
+ &Scumm::o_roomOps,
+ /* 74 */
+ &Scumm::o_getDist,
+ &Scumm::o_findObject,
+ &Scumm::o_walkActorToObject,
+ &Scumm::o_startObject,
+ /* 78 */
+ &Scumm::o_isGreater, /* less? */
+ &Scumm::o_doSentence,
+ &Scumm::o_verbOps,
+ &Scumm::o_getActorWalkBox,
+ /* 7C */
+ &Scumm::o_isSoundRunning,
+ &Scumm::o_findInventory,
+ &Scumm::o_walkActorTo,
+ &Scumm::o_drawBox,
+ /* 80 */
+ &Scumm::o_breakHere,
+ &Scumm::o_putActor,
+ &Scumm::o_startMusic,
+ &Scumm::o_getActorRoom,
+ /* 84 */
+ &Scumm::o_isGreaterEqual, /* less equal? */
+ &Scumm::o_drawObject,
+ &Scumm::o_getActorElevation,
+ &Scumm::o_setState,
+ /* 88 */
+ &Scumm::o_isNotEqual,
+ &Scumm::o_faceActor,
+ &Scumm::o_startScript,
+ &Scumm::o_getVerbEntrypoint,
+ /* 8C */
+ &Scumm::o_resourceRoutines,
+ &Scumm::o_walkActorToActor,
+ &Scumm::o_putActorAtObject,
+ &Scumm::o_getObjectState,
+ /* 90 */
+ &Scumm::o_getObjectOwner,
+ &Scumm::o_animateActor,
+ &Scumm::o_panCameraTo,
+ &Scumm::o_actorSet,
+ /* 94 */
+ &Scumm::o_print,
+ &Scumm::o_actorFromPos,
+ &Scumm::o_getRandomNr,
+ &Scumm::o_and,
+ /* 98 */
+ &Scumm::o_quitPauseRestart,
+ &Scumm::o_doSentence,
+ &Scumm::o_move,
+ &Scumm::o_multiply,
+ /* 9C */
+ &Scumm::o_startSound,
+ &Scumm::o_ifClassOfIs,
+ &Scumm::o_walkActorTo,
+ &Scumm::o_isActorInBox,
+ /* A0 */
+ &Scumm::o_stopObjectCode,
+ &Scumm::o_putActor,
+ &Scumm::o_getAnimCounter,
+ &Scumm::o_getActorY,
+ /* A4 */
+ &Scumm::o_loadRoomWithEgo,
+ &Scumm::o_pickupObject,
+ &Scumm::o_setVarRange,
+ &Scumm::o_dummy,
+ /* A8 */
+ &Scumm::o_notEqualZero,
+ &Scumm::o_setOwnerOf,
+ &Scumm::o_startScript,
+ &Scumm::o_saveRestoreVerbs,
+ /* AC */
+ &Scumm::o_expression,
+ &Scumm::o_putActorInRoom,
+ &Scumm::o_wait,
+ &Scumm::o_badOpcode,
+ /* B0 */
+ &Scumm::o_matrixOps,
+ &Scumm::o_getInventoryCount,
+ &Scumm::o_setCameraAt,
+ &Scumm::o_roomOps,
+ /* B4 */
+ &Scumm::o_getDist,
+ &Scumm::o_findObject,
+ &Scumm::o_walkActorToObject,
+ &Scumm::o_startObject,
+ /* B8 */
+ &Scumm::o_lessOrEqual,
+ &Scumm::o_doSentence,
+ &Scumm::o_subtract,
+ &Scumm::o_getActorScale,
+ /* BC */
+ &Scumm::o_stopSound,
+ &Scumm::o_findInventory,
+ &Scumm::o_walkActorTo,
+ &Scumm::o_drawBox,
+ /* C0 */
+ &Scumm::o_endCutscene,
+ &Scumm::o_putActor,
+ &Scumm::o_chainScript,
+ &Scumm::o_getActorX,
+ /* C4 */
+ &Scumm::o_isLess,
+ &Scumm::o_badOpcode,
+ &Scumm::o_decrement,
+ &Scumm::o_setState,
+ /* C8 */
+ &Scumm::o_isEqual,
+ &Scumm::o_faceActor,
+ &Scumm::o_startScript,
+ &Scumm::o_getVerbEntrypoint,
+ /* CC */
+ &Scumm::o_pseudoRoom,
+ &Scumm::o_walkActorToActor,
+ &Scumm::o_putActorAtObject,
+ &Scumm::o_badOpcode,
+ /* D0 */
+ &Scumm::o_badOpcode,
+ &Scumm::o_animateActor,
+ &Scumm::o_actorFollowCamera,
+ &Scumm::o_actorSet,
+ /* D4 */
+ &Scumm::o_setObjectName,
+ &Scumm::o_actorFromPos,
+ &Scumm::o_getActorMoving,
+ &Scumm::o_or,
+ /* D8 */
+ &Scumm::o_printEgo,
+ &Scumm::o_doSentence,
+ &Scumm::o_add,
+ &Scumm::o_divide,
+ /* DC */
+ &Scumm::o_badOpcode,
+ &Scumm::o_actorSetClass,
+ &Scumm::o_walkActorTo,
+ &Scumm::o_isActorInBox,
+ /* E0 */
+ &Scumm::o_freezeScripts,
+ &Scumm::o_putActor,
+ &Scumm::o_stopScript,
+ &Scumm::o_getActorFacing,
+ /* E4 */
+ &Scumm::o_loadRoomWithEgo,
+ &Scumm::o_pickupObject,
+ &Scumm::o_getClosestObjActor,
+ &Scumm::o_dummy,
+ /* E8 */
+ &Scumm::o_getScriptRunning,
+ &Scumm::o_setOwnerOf,
+ &Scumm::o_startScript,
+ &Scumm::o_debug,
+ /* EC */
+ &Scumm::o_getActorWidth,
+ &Scumm::o_putActorInRoom,
+ &Scumm::o_stopObjectScript,
+ &Scumm::o_badOpcode,
+ /* F0 */
+ &Scumm::o_lights,
+ &Scumm::o_getActorCostume,
+ &Scumm::o_loadRoom,
+ &Scumm::o_roomOps,
+ /* F4 */
+ &Scumm::o_getDist,
+ &Scumm::o_findObject,
+ &Scumm::o_walkActorToObject,
+ &Scumm::o_startObject,
+ /* F8 */
+ &Scumm::o_isGreater,
+ &Scumm::o_doSentence,
+ &Scumm::o_verbOps,
+ &Scumm::o_getActorWalkBox,
+ /* FC */
+ &Scumm::o_isSoundRunning,
+ &Scumm::o_findInventory,
+ &Scumm::o_walkActorTo,
+ &Scumm::o_drawBox
+ };
+
+ return opcode_list[i];
+}
+
+
+void Scumm::executeScript() {
+ OpcodeProc op;
+ while (_currentScript != 0xFF) {
+ _opcode = fetchScriptByte();
+ _scriptPointerStart = _scriptPointer;
+ vm.slot[_currentScript].didexec = 1;
+ debug(9, "%X", _opcode);
+ op = getOpcode(_opcode);
+ (this->*op)();
+ }
+ checkHeap();
+}
+
+byte Scumm::fetchScriptByte() {
+ if (*_lastCodePtr != _scriptOrgPointer + 6) {
+ uint32 oldoffs = _scriptPointer - _scriptOrgPointer;
+ getScriptBaseAddress();
+ _scriptPointer = _scriptOrgPointer + oldoffs;
+ }
+ return *_scriptPointer++;
+}
+
+int Scumm::fetchScriptWord() {
+ int a;
+
+ if (*_lastCodePtr != _scriptOrgPointer + 6) {
+ uint32 oldoffs = _scriptPointer - _scriptOrgPointer;
+ getScriptBaseAddress();
+ _scriptPointer = _scriptOrgPointer + oldoffs;
+ }
+
+ a = READ_LE_UINT16(_scriptPointer);
+ _scriptPointer += 2;
+
+ debug(9, "fetchword=%d", a);
+ return a;
+}
+
+void Scumm::ignoreScriptWord() {
+ fetchScriptWord();
+}
+
+void Scumm::ignoreScriptByte() {
+ fetchScriptByte();
+}
+
+int Scumm::getVarOrDirectWord(byte mask) {
+ if (_opcode&mask)
+ return readVar(fetchScriptWord());
+ return (int16)fetchScriptWord();
+}
+
+int Scumm::getVarOrDirectByte(byte mask) {
+ if (_opcode&mask)
+ return readVar(fetchScriptWord());
+ return fetchScriptByte();
+}
+
+int Scumm::readVar(uint var) {
+ int a;
+#ifdef BYPASS_COPY_PROT
+ static byte copyprotbypassed;
+#endif
+ debug(9, "readvar=%d", var);
+ if (!(var&0xF000)) {
+ checkRange(0x31F, 0, var, "Variable %d out of range(r)");
+ return vm.vars[var];
+ }
+
+ if (var&0x2000) {
+ a = fetchScriptWord();
+ if (a&0x2000)
+ var = (var+readVar(a&~0x2000))&~0x2000;
+ else
+ var = (var+(a&0xFFF))&~0x2000;
+ }
+
+ if (!(var&0xF000))
+ return vm.vars[var];
+
+ if (var&0x8000) {
+ var &= 0xFFF;
+ checkRange(0x7FF, 0, var, "Bit variable %d out of range(r)");
+ return (vm.bitvars[var>>3] & (1<<(var&7))) ? 1 : 0;
+ }
+
+ if (var&0x4000) {
+ var &= 0xFFF;
+ checkRange(0x10, 0, var, "Local variable %d out of range(r)");
+
+#ifdef BYPASS_COPY_PROT
+ if (!copyprotbypassed && _currentScript==1) {
+ copyprotbypassed=1;
+ return 1;
+ }
+#endif
+ return vm.localvar[_currentScript * 17 + var];
+ }
+
+ error("Illegal varbits (r)");
+}
+
+void Scumm::getResultPos() {
+ int a;
+
+ _resultVarNumber = fetchScriptWord();
+ if (_resultVarNumber&0x2000) {
+ a = fetchScriptWord();
+ if (a&0x2000) {
+ _resultVarNumber += readVar(a&~0x2000);
+ } else {
+ _resultVarNumber += a&0xFFF;
+ }
+ _resultVarNumber&=~0x2000;
+ }
+
+ debug(9, "getResultPos=%d", _resultVarNumber);
+}
+
+void Scumm::setResult(int value) {
+ int var = _resultVarNumber;
+ debug(9, "setResult %d,%d", var,value);
+
+ if (!(var&0xF000)) {
+ checkRange(0x31F, 0, var, "Variable %d out of range(w)");
+ vm.vars[var] = value;
+
+ if (var==518) {
+ printf("The answer is %d\n", value);
+ }
+ return;
+ }
+
+ if(var&0x8000) {
+ var&=0xFFF;
+ checkRange(0x7FF, 0, var, "Bit variable %d out of range(w)");
+ if (value)
+ vm.bitvars[var>>3] |= (1<<(var&7));
+ else
+ vm.bitvars[var>>3] &= ~(1<<(var&7));
+ return;
+ }
+
+ if (var&0x4000) {
+ var &= 0xFFF;
+ checkRange(0x10, 0, var, "Local variable %d out of range(w)");
+ vm.localvar[_currentScript * 17 + var] = value;
+ return;
+ }
+ error("Illegal varbits (w)");
+}
+
+void Scumm::o_actorFollowCamera() {
+ int a = camera._follows;
+
+ setCameraFollows(derefActorSafe(getVarOrDirectByte(0x80), "actorFollowCamera"));
+
+ if (camera._follows != a)
+ runHook(0);
+
+ camera._movingToActor = 0;
+}
+
+void Scumm::o_actorFromPos() {
+ int x,y;
+ getResultPos();
+ x = getVarOrDirectWord(0x80);
+ y = getVarOrDirectWord(0x40);
+ setResult(getActorFromPos(x,y));
+}
+
+void Scumm::o_actorSet() {
+ int act = getVarOrDirectByte(0x80);
+ Actor *a = derefActorSafe(act, "actorSet");
+ int i,j;
+
+ while ( (_opcode = fetchScriptByte()) != 0xFF) {
+ switch(_opcode&0x1F) {
+ case 1: /* costume */
+ setActorCostume(a, getVarOrDirectByte(0x80));
+ break;
+ case 2: /* walkspeed */
+ i = getVarOrDirectByte(0x80);
+ j = getVarOrDirectByte(0x40);
+ setActorWalkSpeed(a, i, j);
+ break;
+ case 3: /* sound */
+ a->sound = getVarOrDirectByte(0x80);
+ break;
+ case 4: /* walkanim */
+ a->walkFrame = getVarOrDirectByte(0x80);
+ break;
+ case 5: /* talkanim */
+ a->talkFrame1 = getVarOrDirectByte(0x80);
+ a->talkFrame2 = getVarOrDirectByte(0x40);
+ break;
+ case 6: /* standanim */
+ a->standFrame = getVarOrDirectByte(0x80);
+ break;
+ case 7: /* ignore */
+ getVarOrDirectByte(0x80);
+ getVarOrDirectByte(0x40);
+ getVarOrDirectByte(0x20);
+ break;
+ case 8: /* init */
+ initActor(a, 0);
+ break;
+ case 9: /* elevation */
+ a->elevation = getVarOrDirectWord(0x80);
+ a->needRedraw = true;
+ a->needBgReset = true;
+ break;
+ case 10: /* defaultanims */
+ a->initFrame = 1;
+ a->walkFrame = 2;
+ a->standFrame = 3;
+ a->talkFrame1 = 4;
+ a->talkFrame2 = 4;
+ break;
+ case 11: /* palette */
+ i = getVarOrDirectByte(0x80);
+ j = getVarOrDirectByte(0x40);
+ checkRange(32, 0, i, "Illegal palet slot %d");
+ a->palette[i] = j;
+ a->needRedraw = 1;
+ break;
+ case 12: /* talk color */
+ a->talkColor = getVarOrDirectByte(0x80);
+ break;
+ case 13: /* name */
+ loadPtrToResource(9, a->number, NULL);
+ break;
+ case 14: /* initanim */
+ a->initFrame = getVarOrDirectByte(0x80);
+ break;
+ case 15: /* unk */
+ error("o_actorset:unk not implemented");
+ break;
+ case 16: /* width */
+ a->width = getVarOrDirectByte(0x80);
+ break;
+ case 17: /* scale */
+ a->scalex = getVarOrDirectByte(0x80);
+ a->scaley = getVarOrDirectByte(0x40);
+ break;
+ case 18: /* neverzclip */
+ a->neverZClip = 0;
+ break;
+ case 19: /* setzclip */
+ a->neverZClip = getVarOrDirectByte(0x80);
+ break;
+ case 20: /* ignoreboxes */
+ a->ignoreBoxes = 1;
+ a->neverZClip = 0;
+FixRoom:
+ if (a->room==_currentRoom)
+ putActor(a, a->x, a->y, a->room);
+ break;
+ case 21: /* followboxes */
+ a->ignoreBoxes = 0;
+ a->neverZClip = 0;
+ goto FixRoom;
+
+ case 22: /* animspeed */
+ a->animSpeed = getVarOrDirectByte(0x80);
+ break;
+ case 23: /* unk2 */
+ a->data8 = getVarOrDirectByte(0x80); /* unused */
+ break;
+ default:
+ error("o_actorSet: default case");
+ }
+ }
+}
+
+void Scumm::o_actorSetClass() {
+ int act = getVarOrDirectWord(0x80);
+ int i;
+
+ while ( (_opcode=fetchScriptByte()) != 0xFF) {
+ i = getVarOrDirectWord(0x80);
+ if (i==0) {
+ _classData[act] = 0;
+ continue;
+ }
+ if (i&0x80)
+ putClass(act, i, 1);
+ else
+ putClass(act, i, 0);
+ }
+}
+
+void Scumm::o_add() {
+ int a;
+ getResultPos();
+ a = getVarOrDirectWord(0x80);
+ setResult(readVar(_resultVarNumber) + a);
+}
+
+void Scumm::o_and() {
+ int a;
+ getResultPos();
+ a = getVarOrDirectWord(0x80);
+ setResult(readVar(_resultVarNumber) & a);
+}
+
+void Scumm::o_animateActor() {
+ int anim,shr,dir;
+ bool inRoom;
+ Actor *a;
+
+ a = derefActorSafe(getVarOrDirectByte(0x80), "animateActor");
+ anim = getVarOrDirectByte(0x40);
+
+ shr = anim>>2;
+ dir = anim&3;
+
+ inRoom = (a->room == _currentRoom);
+
+ if (shr == 0x3F) {
+ if (inRoom) {
+ startAnimActor(a, a->standFrame, a->facing);
+ a->moving = 0;
+ }
+ return;
+ }
+
+ if (shr == 0x3E) {
+ if (inRoom) {
+ startAnimActor(a, 0x3E, dir);
+ a->moving &= ~4;
+ }
+ a->facing = dir;
+ return;
+ }
+
+ if (shr == 0x3D) {
+ if (inRoom) {
+ turnToDirection(a, dir);
+ } else {
+ a->facing = dir;
+ }
+ return;
+ }
+
+ startAnimActor(a, anim, a->facing);
+}
+
+void Scumm::o_badOpcode() {
+ error("Scumm opcode %d illegal", _opcode);
+}
+
+void Scumm::o_breakHere() {
+ updateScriptPtr();
+ _currentScript = 0xFF;
+}
+
+void Scumm::o_chainScript() {
+ int16 vars[16];
+ int data;
+ int cur;
+
+ data = getVarOrDirectByte(0x80);
+
+ getWordVararg(vars);
+
+ cur = _currentScript;
+
+ if (vm.slot[cur].cutsceneOverride != 0) {
+ error("Script %d chaining with active cutscene/override");
+ }
+
+ vm.slot[cur].number = 0;
+ vm.slot[cur].status = 0;
+ _currentScript = 0xFF;
+
+ runScript(data, vm.slot[cur].unk1, vm.slot[cur].unk2, vars);
+}
+
+void Scumm::o_cursorCommand() {
+ int i,j,k;
+ int16 table[16];
+
+ switch((_opcode=fetchScriptByte())&0x1F) {
+ case 1: /* cursor show */
+ _cursorState = 1;
+ verbMouseOver(0);
+ break;
+ case 2: /* cursor hide */
+ _cursorState = 0;
+ verbMouseOver(0);
+ break;
+ case 3: /* userput on */
+ _userPut = 1;
+ break;
+ case 4: /* userput off */
+ _userPut = 0;
+ break;
+ case 5: /* cursor soft on */
+ _cursorState++;
+ if (_cursorState > 1) {
+ error("Cursor state greater than 1 in script");
+ }
+ break;
+ case 6: /* cursor soft off */
+ _cursorState--;
+ break;
+ case 7: /* userput soft on */
+ _userPut++;
+ break;
+ case 8: /* userput soft off */
+ _userPut--;
+ break;
+ case 10: /* set cursor img */
+ i = getVarOrDirectByte(0x80);
+ j = getVarOrDirectByte(0x40);
+ setCursorImg(i, j);
+ break;
+ case 11: /* set cursor hotspot */
+ i = getVarOrDirectByte(0x80);
+ j = getVarOrDirectByte(0x40);
+ k = getVarOrDirectByte(0x20);
+ setCursorHotspot(i, j, k);
+ break;
+
+ case 12: /* init cursor */
+ setCursor(getVarOrDirectByte(0x80));
+ break;
+ case 13: /* init charset */
+ initCharset(getVarOrDirectByte(0x80));
+ break;
+ case 14: /* unk */
+ getWordVararg(table);
+ for (i=0; i<16; i++)
+ charset._colorMap[i] = _charsetData[textslot.charset[1]][i] = table[i];
+ break;
+ }
+
+ vm.vars[VAR_CURSORSTATE] = _cursorState;
+ vm.vars[VAR_USERPUT] = _userPut;
+}
+
+void Scumm::o_cutscene() {
+ int scr = _currentScript;
+
+ getWordVararg(_vararg_temp_pos);
+
+ vm.slot[scr].cutsceneOverride++;
+
+ if (++vm.cutSceneStackPointer > 5)
+ error("Cutscene stack overflow");
+
+ vm.cutSceneData[vm.cutSceneStackPointer] = _vararg_temp_pos[0];
+ vm.cutSceneScript[vm.cutSceneStackPointer] = 0;
+ vm.cutScenePtr[vm.cutSceneStackPointer] = 0;
+
+ vm.cutSceneScriptIndex = scr;
+ if (vm.vars[VAR_CUTSCENE_START_SCRIPT])
+ runScript(vm.vars[VAR_CUTSCENE_START_SCRIPT], 0, 0, _vararg_temp_pos);
+ vm.cutSceneScriptIndex = 0xFF;
+}
+
+void Scumm::o_endCutscene() {
+ ScriptSlot *ss = &vm.slot[_currentScript];
+ uint32 *csptr;
+
+ ss->cutsceneOverride--;
+
+ _vararg_temp_pos[0] = vm.cutSceneData[vm.cutSceneStackPointer];
+ vm.vars[VAR_OVERRIDE] = 0;
+
+ csptr = &vm.cutScenePtr[vm.cutSceneStackPointer];
+ if (*csptr)
+ ss->cutsceneOverride--;
+
+ vm.cutSceneScript[vm.cutSceneStackPointer] = 0;
+ *csptr = 0;
+ vm.cutSceneStackPointer--;
+
+ if (vm.vars[VAR_CUTSCENE_END_SCRIPT])
+ runScript(vm.vars[VAR_CUTSCENE_END_SCRIPT], 0, 0, _vararg_temp_pos);
+}
+
+
+void Scumm::o_debug() {
+ getVarOrDirectWord(0x80);
+}
+
+void Scumm::o_decrement() {
+ getResultPos();
+ setResult(readVar(_resultVarNumber)-1);
+}
+
+void Scumm::o_delay() {
+ int delay = fetchScriptByte();
+ delay |= fetchScriptByte()<<8;
+ delay |= fetchScriptByte()<<16;
+ vm.slot[_currentScript].delay = delay;
+ vm.slot[_currentScript].status = 1;
+ o_breakHere();
+}
+
+void Scumm::o_delayVariable() {
+ vm.slot[_currentScript].delay = readVar(fetchScriptWord());
+ vm.slot[_currentScript].status = 1;
+ o_breakHere();
+}
+
+void Scumm::o_divide() {
+ int a;
+ getResultPos();
+ a = getVarOrDirectWord(0x80);
+ if(a==0) {
+ error("Divide by zero");
+ setResult(0);
+ } else
+ setResult(readVar(_resultVarNumber) / a);
+}
+
+void Scumm::o_doSentence() {
+ int a,b;
+ _sentenceIndex++;
+
+ a = getVarOrDirectByte(0x80);
+ if (a==0xFE) {
+ _sentenceIndex = 0xFF;
+ stopScriptNr(vm.vars[VAR_SENTENCE_SCRIPT]);
+ clearClickedStatus();
+ return;
+ }
+ _sentenceTab5[_sentenceIndex] = a;
+ _sentenceTab4[_sentenceIndex] = getVarOrDirectWord(0x40);
+ b = _sentenceTab3[_sentenceIndex] = getVarOrDirectWord(0x20);
+ if (b==0) {
+ _sentenceTab2[_sentenceIndex] = 0;
+ } else {
+ _sentenceTab2[_sentenceIndex] = 1;
+ }
+ _sentenceTab[_sentenceIndex] = 0;
+}
+
+void Scumm::o_drawBox() {
+ int x,y,x2,y2,color;
+
+ x = getVarOrDirectWord(0x80);
+ y = getVarOrDirectWord(0x40);
+
+ _opcode = fetchScriptByte();
+ x2 = getVarOrDirectWord(0x80);
+ y2 = getVarOrDirectWord(0x40);
+ color = getVarOrDirectByte(0x20);
+
+ drawBox(x, y, x2, y2, color);
+}
+
+void Scumm::drawBox(int x, int y, int x2, int y2, int color) {
+ int top,bottom,count;
+
+ if (findVirtScreen(y)==-1)
+ return;
+
+ top = virtscr[gdi.virtScreen].topline;
+ bottom = top + virtscr[gdi.virtScreen].height;
+
+ if (x > x2)
+ SWAP(x,x2);
+
+ if (y > y2)
+ SWAP(y,y2);
+
+ x2++;
+ y2++;
+
+ if (x>319) return;
+ if (x<0) x=0;
+ if (x2<0) return;
+ if (x2>320) x2=320;
+ if (y2 > bottom) y2=bottom;
+
+ updateDirtyRect(gdi.virtScreen, x, x2, y-top, y2-top, 0);
+
+ gdi.bg_ptr = getResourceAddress(0xA, gdi.virtScreen+1)
+ + virtscr[gdi.virtScreen].xstart
+ + (y-top)*320 + x;
+
+ count = y2 - y;
+ while (count) {
+ memset(gdi.bg_ptr, color, x2 - x);
+ gdi.bg_ptr += 320;
+ count--;
+ }
+}
+
+void Scumm::o_drawObject() {
+ int state,obj,index,i;
+ ObjectData *od;
+ byte x,y,w,h;
+
+ state = 1;
+ _xPos = _yPos = 255;
+ obj = getVarOrDirectWord(0x80);
+
+ switch((_opcode = fetchScriptByte())&0x1F) {
+ case 1: /* draw at */
+ _xPos = getVarOrDirectWord(0x80);
+ _yPos = getVarOrDirectWord(0x40);
+ break;
+ case 2: /* set state */
+ state = getVarOrDirectWord(0x80);
+ break;
+ case 0x1F: /* neither */
+ break;
+ default:
+ error("o_drawObject: default case");
+ }
+ index = getObjectIndex(obj);
+ if (index==-1)
+ return;
+ od = &objs[index];
+ if (_xPos!=0xFF) {
+ od->cdhd_10 += (_xPos - od->x_pos)<<3;
+ od->x_pos = _xPos;
+ od->cdhd_12 += (_yPos - od->y_pos)<<3;
+ od->y_pos = _yPos;
+ }
+ addObjectToDrawQue(index);
+
+ x = od->x_pos;
+ y = od->y_pos;
+ w = od->numstrips;
+ h = od->height;
+
+ i = _numObjectsInRoom;
+ do {
+ if (objs[i].x_pos == x && objs[i].y_pos == y
+ && objs[i].numstrips == w && objs[i].height==h)
+ putState(objs[i].obj_nr, 0);
+ } while (--i);
+
+ putState(obj, state);
+}
+
+void Scumm::o_dummy() {
+ /* nothing */
+}
+
+
+void Scumm::o_expression() {
+ int dst, i;
+
+ _scummStackPos = 0;
+ getResultPos();
+ dst = _resultVarNumber;
+
+ while ((_opcode = fetchScriptByte())!=0xFF) {
+ switch(_opcode&0x1F) {
+ case 1: /* varordirect */
+ stackPush(getVarOrDirectWord(0x80));
+ break;
+ case 2: /* add */
+ i = stackPop();
+ stackPush(i + stackPop());
+ break;
+ case 3: /* sub */
+ i = stackPop();
+ stackPush(stackPop() - i);
+ break;
+ case 4: /* mul */
+ i = stackPop();
+ stackPush(i * stackPop());
+ break;
+ case 5: /* div */
+ i = stackPop();
+ if (i==0)
+ error("Divide by zero");
+ stackPush(stackPop() / i);
+ break;
+ case 6: /* normal opcode */
+ _opcode = fetchScriptByte();
+ (this->*(getOpcode(_opcode)))();
+ stackPush(vm.vars[0]);
+ break;
+ }
+ }
+
+ _resultVarNumber = dst;
+ setResult(stackPop());
+}
+
+void Scumm::o_faceActor() {
+ int act, obj;
+ int x;
+ byte dir;
+
+ act = getVarOrDirectByte(0x80);
+ obj = getVarOrDirectWord(0x40);
+
+ if (getObjectOrActorXY(act)==-1)
+ return;
+
+ x = _xPos;
+
+ if (getObjectOrActorXY(obj)==-1)
+ return;
+
+ dir = (_xPos > x) ? 1 : 0;
+ turnToDirection(derefActorSafe(act, "o_faceActor"), dir);
+}
+
+void Scumm::o_findInventory() {
+ int owner, b, count, i, obj;
+
+ getResultPos();
+ owner = getVarOrDirectByte(0x80);
+ b = getVarOrDirectByte(0x40);
+ count = 1;
+ for (i=0; i!=_maxInventoryItems; i++) {
+ obj = _inventory[i];
+ if (obj && getOwner(obj)==owner && count++ == b) {
+ setResult(obj);
+ return;
+ }
+ }
+ setResult(0);
+}
+
+void Scumm::o_findObject() {
+ int t;
+ getResultPos();
+ t = getVarOrDirectWord(0x80);
+ setResult(findObject(t, getVarOrDirectWord(0x40)));
+}
+
+void Scumm::o_freezeScripts() {
+ int scr = getVarOrDirectByte(0x80);
+
+ if (scr!=0)
+ freezeScripts(scr);
+ else
+ unfreezeScripts();
+}
+
+void Scumm::o_getActorCostume() {
+ getResultPos();
+ setResult(derefActorSafe(getVarOrDirectByte(0x80),"o_getActorCostume")->costume);
+}
+
+void Scumm::o_getActorElevation() {
+ getResultPos();
+ setResult(derefActorSafe(getVarOrDirectByte(0x80),"o_getActorElevation")->elevation);
+}
+
+void Scumm::o_getActorFacing() {
+ getResultPos();
+ setResult(derefActorSafe(getVarOrDirectByte(0x80),"o_getActorFacing")->facing);
+}
+
+void Scumm::o_getActorMoving() {
+ getResultPos();
+ setResult(derefActorSafe(getVarOrDirectByte(0x80),"o_getActorMoving")->moving);
+}
+
+void Scumm::o_getActorRoom() {
+ getResultPos();
+ setResult(derefActorSafe(getVarOrDirectByte(0x80),"o_getActorRoom")->room);
+}
+
+void Scumm::o_getActorScale() {
+ getResultPos();
+ setResult(derefActorSafe(getVarOrDirectByte(0x80),"o_getActorScale")->scalex);
+}
+
+void Scumm::o_getActorWalkBox() {
+ getResultPos();
+ setResult(derefActorSafe(getVarOrDirectByte(0x80),"o_getActorWalkbox")->walkbox);
+}
+
+void Scumm::o_getActorWidth() {
+ getResultPos();
+ setResult(derefActorSafe(getVarOrDirectByte(0x80),"o_getActorWidth")->width);
+}
+
+void Scumm::o_getActorX() {
+ int index;
+ getResultPos();
+ index = getVarOrDirectWord(0x80);
+ if (index <= vm.vars[VAR_NUM_ACTOR]) {
+ setResult(derefActorSafe(index,"o_getActorX")->x);
+ } else {
+ if (whereIsObject(index)==-1)
+ setResult(-1);
+ else {
+ getObjectOrActorXY(index);
+ setResult(_xPos);
+ }
+ }
+}
+
+void Scumm::o_getActorY() {
+ int index;
+ getResultPos();
+ index = getVarOrDirectWord(0x80);
+ if (index <= vm.vars[VAR_NUM_ACTOR]) {
+ setResult(derefActorSafe(index,"o_getActorY")->y);
+ } else {
+ if (whereIsObject(index)==-1)
+ setResult(-1);
+ else {
+ getObjectOrActorXY(index);
+ setResult(_yPos);
+ }
+ }
+}
+
+void Scumm::o_getAnimCounter() {
+ getResultPos();
+ setResult(derefActorSafe(getVarOrDirectByte(0x80),"o_getActorAnimCounter")->cost.animCounter1);
+}
+
+void Scumm::o_getClosestObjActor() {
+ int obj;
+ int act;
+ int closobj=-1, closnum=-1;
+ int dist;
+
+ getResultPos();
+
+ act = getVarOrDirectWord(0x80);
+ obj = vm.vars[VAR_OBJECT_HI];
+
+ do {
+ dist = getObjActToObjActDist(obj,act);
+ if (dist < closnum) {
+ closnum = dist;
+ closobj = obj;
+ }
+ } while (--obj >= vm.vars[VAR_OBJECT_LO]);
+
+ setResult(closnum);
+}
+
+void Scumm::o_getDist() {
+ int o1,o2;
+ getResultPos();
+ o1 = getVarOrDirectWord(0x80);
+ o2 = getVarOrDirectWord(0x40);
+ setResult(getObjActToObjActDist(o1,o2));
+}
+
+void Scumm::o_getInventoryCount() {
+ int owner, count, i, obj;
+
+ getResultPos();
+
+ owner = getVarOrDirectByte(0x80);
+ count = 0;
+ for (i=0; i!=_maxInventoryItems; i++) {
+ obj = _inventory[i];
+ if (obj && getOwner(obj)==owner)
+ count++;
+ }
+ setResult(count);
+}
+
+void Scumm::o_getObjectOwner() {
+ getResultPos();
+ setResult(getOwner(getVarOrDirectWord(0x80)));
+}
+
+void Scumm::o_getObjectState() {
+ getResultPos();
+ setResult(getState(getVarOrDirectWord(0x80)));
+}
+
+void Scumm::o_getRandomNr() {
+ getResultPos();
+ setResult(getRandomNumber(getVarOrDirectByte(0x80)));
+}
+
+void Scumm::o_getScriptRunning() {
+ int i;
+ ScriptSlot *ss;
+ int script;
+
+ getResultPos();
+ script = getVarOrDirectByte(0x80);
+
+ ss = vm.slot;
+ for (i=0; i<20; i++,ss++) {
+ if (ss->number==script && (ss->type==2 || ss->type==3) && ss->status) {
+ setResult(1);
+ return;
+ }
+ }
+ setResult(0);
+}
+
+void Scumm::o_getVerbEntrypoint() {
+ int a,b;
+ getResultPos();
+ a = getVarOrDirectWord(0x80);
+ b = getVarOrDirectWord(0x40);
+ setResult(getVerbEntrypoint(a, b));
+}
+
+void Scumm::o_ifClassOfIs() {
+ int act,cls;
+ bool cond = true, b;
+
+ act = getVarOrDirectWord(0x80);
+ while ( (_opcode = fetchScriptByte()) != 0xFF) {
+ cls = getVarOrDirectWord(0x80);
+ b = getClass(act, cls);
+
+ if (cls&0x80 && !b)
+ cond = false;
+ if (!(cls&0x80) && b)
+ cond = false;
+ }
+ if (cond)
+ ignoreScriptWord();
+ else
+ o_jumpRelative();
+}
+
+void Scumm::o_increment() {
+ getResultPos();
+ setResult(readVar(_resultVarNumber)+1);
+}
+
+void Scumm::o_isActorInBox() {
+ int box;
+ Actor *a;
+
+ a = derefActorSafe(getVarOrDirectByte(0x80), "o_isActorInBox");
+ box = getVarOrDirectByte(0x40);
+
+ if (!checkXYInBoxBounds(box, a->x, a->y))
+ o_jumpRelative();
+ else
+ ignoreScriptWord();
+}
+
+void Scumm::o_isEqual() {
+ int16 a = readVar(fetchScriptWord());
+ int16 b = getVarOrDirectWord(0x80);
+ if (b == a) ignoreScriptWord();
+ else o_jumpRelative();
+
+}
+
+void Scumm::o_isGreater() {
+ int16 a = readVar(fetchScriptWord());
+ int16 b = getVarOrDirectWord(0x80);
+ if (b > a) ignoreScriptWord();
+ else o_jumpRelative();
+}
+
+void Scumm::o_isGreaterEqual() {
+ int16 a = readVar(fetchScriptWord());
+ int16 b = getVarOrDirectWord(0x80);
+ if (b >= a) ignoreScriptWord();
+ else o_jumpRelative();
+}
+
+void Scumm::o_isLess() {
+ int16 a = readVar(fetchScriptWord());
+ int16 b = getVarOrDirectWord(0x80);
+ if (b < a) ignoreScriptWord();
+ else o_jumpRelative();
+}
+
+void Scumm::o_lessOrEqual() {
+ int16 a = readVar(fetchScriptWord());
+ int16 b = getVarOrDirectWord(0x80);
+ if (b <= a) ignoreScriptWord();
+ else o_jumpRelative();
+}
+
+void Scumm::o_isNotEqual() {
+ int16 a = readVar(fetchScriptWord());
+ int16 b = getVarOrDirectWord(0x80);
+ if (b != a) ignoreScriptWord();
+ else o_jumpRelative();
+}
+
+void Scumm::o_notEqualZero() {
+ int a = readVar(fetchScriptWord());
+ if (a != 0) ignoreScriptWord();
+ else o_jumpRelative();
+}
+
+void Scumm::o_equalZero() {
+ int a = readVar(fetchScriptWord());
+ if (a == 0) ignoreScriptWord();
+ else o_jumpRelative();
+}
+
+void Scumm::o_isSoundRunning() {
+ int snd;
+ getResultPos();
+ snd = getVarOrDirectByte(0x80);
+ if (snd)
+ setResult(unkSoundProc23(snd));
+ else
+ setResult(0);
+}
+
+void Scumm::o_jumpRelative() {
+ _scriptPointer += (int16)fetchScriptWord();
+}
+
+void Scumm::o_lights() {
+ int a,b,c;
+
+ a = getVarOrDirectByte(0x80);
+ b = fetchScriptByte();
+ c = fetchScriptByte();
+ if (c==0)
+ vm.vars[VAR_DRAWFLAGS] = a;
+ else if (c==1) {
+ _lightsValueA = a;
+ _lightsValueB = b;
+ }
+ _fullRedraw=1;
+}
+
+void Scumm::o_loadRoom() {
+ int room = getVarOrDirectByte(0x80);
+ debug(1,"Loading room %d", room);
+ startScene(room, 0, 0);
+ _fullRedraw = 1;
+}
+
+void Scumm::o_loadRoomWithEgo() {
+ int obj, room, x,y;
+ Actor *a;
+
+ obj = getVarOrDirectWord(0x80);
+ room = getVarOrDirectByte(0x40);
+
+ a = derefActorSafe(vm.vars[VAR_UNK_ACTOR], "o_loadRoomWithEgo");
+
+ /* Warning: uses _xPos, _yPos from a previous update of those */
+ putActor(a, _xPos, _yPos, room);
+
+ x = (int16)fetchScriptWord();
+ y = (int16)fetchScriptWord();
+
+ dseg_3A76 = 0;
+
+ vm.vars[VAR_WALKTO_OBJ] = obj;
+
+ startScene(a->room, a, obj);
+
+ vm.vars[VAR_WALKTO_OBJ] = 0;
+ camera._destPos = camera._curPos = a->x;
+ setCameraFollows(a);
+ _fullRedraw=1;
+
+ if (x != -1) {
+ startWalkActor(a, x, y, 0xFF);
+ }
+}
+
+void Scumm::o_matrixOps() {
+ int a,b;
+
+ _opcode = fetchScriptByte();
+ switch(_opcode & 0x1F) {
+ case 1:
+ a = getVarOrDirectByte(0x80);
+ b = getVarOrDirectByte(0x40);
+ setBoxFlags(a,b);
+ break;
+ case 2:
+ a = getVarOrDirectByte(0x80);
+ b = getVarOrDirectByte(0x40);
+ setBoxScale(a,b);
+ break;
+ case 3:
+ a = getVarOrDirectByte(0x80);
+ b = getVarOrDirectByte(0x40);
+ setBoxScale(a,(b-1)|0x8000);
+ break;
+ case 4:
+ createBoxMatrix();
+ break;
+ }
+}
+
+void Scumm::o_move() {
+ getResultPos();
+ setResult(getVarOrDirectWord(0x80));
+}
+
+void Scumm::o_multiply() {
+ int a;
+ getResultPos();
+ a = getVarOrDirectWord(0x80);
+ setResult(readVar(_resultVarNumber) * a);
+}
+
+
+void Scumm::o_or() {
+ int a;
+ getResultPos();
+ a = getVarOrDirectWord(0x80);
+ setResult(readVar(_resultVarNumber) | a);
+}
+
+void Scumm::o_overRide() {
+ byte b;
+ int index;
+ uint32 *ptr;
+
+ b = fetchScriptByte();
+ if(b!=0) {
+ index = vm.cutSceneStackPointer;
+ ptr = &vm.cutScenePtr[index];
+ if (!*ptr) {
+ vm.slot[_currentScript].cutsceneOverride++;
+ }
+ *ptr = _scriptPointer - _scriptOrgPointer;
+ vm.cutSceneScript[index] = _currentScript;
+
+ ignoreScriptByte();
+ ignoreScriptWord();
+ } else {
+ index = vm.cutSceneStackPointer;
+ ptr = &vm.cutScenePtr[index];
+ if (*ptr) {
+ vm.slot[_currentScript].cutsceneOverride--;
+ }
+ *ptr = 0;
+ vm.cutSceneScript[index] = 0;
+ }
+ vm.vars[VAR_OVERRIDE] = 0;
+}
+
+void Scumm::o_panCameraTo() {
+ CameraData *cd = &camera;
+ cd->_destPos = getVarOrDirectWord(0x80);
+ cd->_mode = 3;
+ cd->_movingToActor = 0;
+}
+
+void Scumm::o_pickupObject() {
+ int obj, room;
+
+ obj = getVarOrDirectWord(0x80);
+ room = getVarOrDirectByte(0x40);
+ if (room==0)
+ room = _roomResource;
+ addObjectToInventory(obj, room);
+ putOwner(obj, vm.vars[VAR_UNK_ACTOR]);
+ putClass(obj, 32, 1);
+ putState(obj, 1);
+ removeObjectFromRoom(obj);
+ clearDrawObjectQueue();
+ runHook(1);
+}
+
+void Scumm::o_print() {
+ _actorToPrintStrFor = getVarOrDirectByte(0x80);
+ decodeParseString();
+}
+
+void Scumm::o_printEgo() {
+ _actorToPrintStrFor = vm.vars[VAR_UNK_ACTOR];
+ decodeParseString();
+}
+
+void Scumm::o_pseudoRoom() {
+ int i = fetchScriptByte(), j;
+ while ((j = fetchScriptByte()) != 0) {
+ if (j >= 0x80) {
+ _resourceMapper[j&0x7F] = i;
+ }
+ }
+}
+
+void Scumm::o_putActor() {
+ int x,y;
+ Actor *a;
+
+ a = derefActorSafe(getVarOrDirectByte(0x80), "o_putActor");
+ x = getVarOrDirectWord(0x40);
+ y = getVarOrDirectWord(0x20);
+
+ putActor(a, x, y, a->room);
+}
+
+
+void Scumm::o_putActorAtObject() {
+ int obj;
+ Actor *a;
+
+ a = derefActorSafe(getVarOrDirectByte(0x80), "o_putActorAtObject");
+ obj = getVarOrDirectWord(0x40);
+ if (whereIsObject(obj)!=-1)
+ getObjectXYPos(obj);
+ else {
+ _xPos = 240;
+ _yPos = 120;
+ }
+ putActor(a, _xPos, _yPos, a->room);
+}
+
+void Scumm::o_putActorInRoom() {
+ int room;
+ Actor *a;
+
+ a = derefActorSafe(getVarOrDirectByte(0x80), "o_putActorInRoom");
+ room = getVarOrDirectByte(0x40);
+ if (a->visible && _currentRoom!=room && vm.vars[VAR_TALK_ACTOR]==a->number) {
+ clearMsgQueue();
+ }
+ a->room = room;
+ if (!room)
+ putActor(a, 0, 0, 0);
+}
+
+void Scumm::o_quitPauseRestart() {
+ switch(fetchScriptByte()) {
+ case 1:
+ pauseGame(0);
+ break;
+ case 3:
+ shutDown(0);
+ break;
+ }
+}
+
+void Scumm::o_resourceRoutines() {
+ int res;
+
+ _opcode = fetchScriptByte();
+ if (_opcode != 17)
+ res = getVarOrDirectByte(0x80);
+ switch(_opcode&0x1F) {
+ case 1: /* load script */
+ ensureResourceLoaded(2, res);
+ break;
+ case 2: /* load sound */
+ ensureResourceLoaded(4, res);
+ break;
+ case 3: /* load costume */
+ ensureResourceLoaded(3, res);
+ break;
+ case 4: /* load room */
+ ensureResourceLoaded(1, res);
+ break;
+ case 5: /* nuke script */
+ setResourceFlags(2, res, 0x7F);
+ break;
+ case 6: /* nuke sound */
+ setResourceFlags(4, res, 0x7F);
+ break;
+ case 7: /* nuke costume */
+ setResourceFlags(3, res, 0x7F);
+ break;
+ case 8: /* nuke room */
+ setResourceFlags(1, res, 0x7F);
+ break;
+ case 9: /* lock script */
+ if (res >= _numGlobalScriptsUsed)
+ break;
+ lock(2,res);
+ break;
+ case 10:/* lock sound */
+ lock(4,res);
+ break;
+ case 11:/* lock costume */
+ lock(3,res);
+ break;
+ case 12:/* lock room */
+ if (res > 0x7F)
+ res = _resourceMapper[res&0x7F];
+ lock(1,res);
+ break;
+ case 13:/* unlock script */
+ if (res >= _numGlobalScriptsUsed)
+ break;
+ unlock(2,res);
+ break;
+ case 14:/* unlock sound */
+ unlock(4,res);
+ break;
+ case 15:/* unlock costume */
+ unlock(3,res);
+ break;
+ case 16:/* unlock room */
+ if (res > 0x7F)
+ res = _resourceMapper[res&0x7F];
+ unlock(1,res);
+ break;
+ case 17:/* clear heap */
+ heapClear(0);
+ unkHeapProc2(0,0);
+ break;
+ case 18:/* load charset */
+ loadCharset(res);
+ break;
+ case 19:/* nuke charset */
+ nukeCharset(res);
+ break;
+ case 20:/* ? */
+ unkResProc(getVarOrDirectWord(0x40), res);
+ break;
+ }
+}
+
+void Scumm::o_roomOps() {
+ int a,b,c,d,e;
+
+ _opcode = fetchScriptByte();
+
+ switch(_opcode & 0x1F) {
+ case 1: /* room scroll */
+ a = getVarOrDirectWord(0x80);
+ b = getVarOrDirectWord(0x40);
+ if (a < 160) a=160;
+ if (a > ((_scrWidthIn8Unit-20)<<3)) a=((_scrWidthIn8Unit-20)<<3);
+ if (b < 160) b=160;
+ if (b > ((_scrWidthIn8Unit-20)<<3)) b=((_scrWidthIn8Unit-20)<<3);
+ vm.vars[VAR_CAMERA_MIN] = a;
+ vm.vars[VAR_CAMERA_MAX] = b;
+ break;
+ case 2: /* room color */
+ error("room-color is no longer a valid command");
+ break;
+
+ case 3: /* set screen */
+ a = getVarOrDirectWord(0x80);
+ b = getVarOrDirectWord(0x40);
+ initScreens(0,a,320,b);
+ break;
+ case 4: /* set palette color */
+ a = getVarOrDirectWord(0x80);
+ b = getVarOrDirectWord(0x40);
+ c = getVarOrDirectWord(0x20);
+ _opcode = fetchScriptByte();
+ d = getVarOrDirectByte(0x80);
+ setPalColor(d, a, b, c); /* index, r, g, b */
+ break;
+ case 5: /* shake on */
+ setShake(1);
+ break;
+ case 6: /* shake off */
+ setShake(0);
+ break;
+ case 8: /* room scale? */
+ a = getVarOrDirectByte(0x80);
+ b = getVarOrDirectByte(0x40);
+ c = getVarOrDirectByte(0x20);
+ unkRoomFunc2(b, c, a, a, a);
+ break;
+ case 9: /* ? */
+ _saveLoadFlag = getVarOrDirectByte(0x80);
+ _saveLoadData = getVarOrDirectByte(0x40);
+ _saveLoadData = 0; /* TODO: weird behaviour */
+ break;
+ case 10: /* ? */
+ a = getVarOrDirectWord(0x80);
+ if (a) {
+ _switchRoomEffect = (byte)(a);
+ _switchRoomEffect2 = (byte)(a>>8);
+ } else {
+ screenEffect(_newEffect);
+ }
+ break;
+ case 11: /* ? */
+ a = getVarOrDirectWord(0x80);
+ b = getVarOrDirectWord(0x40);
+ c = getVarOrDirectWord(0x20);
+ _opcode = fetchScriptByte();
+ d = getVarOrDirectByte(0x80);
+ e = getVarOrDirectByte(0x40);
+ unkRoomFunc2(d, e, a, b, c);
+ break;
+ case 12: /* ? */
+ a = getVarOrDirectWord(0x80);
+ b = getVarOrDirectWord(0x40);
+ c = getVarOrDirectWord(0x20);
+ _opcode = fetchScriptByte();
+ d = getVarOrDirectByte(0x80);
+ e = getVarOrDirectByte(0x40);
+ unkRoomFunc3(d, e, a, b, c);
+ break;
+
+ case 13: /* ? */
+ error("roomops:13 not implemented");
+ break;
+ case 14: /* ? */
+ error("roomops:14 not implemented");
+ break;
+ case 15: /* palmanip? */
+ a = getVarOrDirectByte(0x80);
+ _opcode = fetchScriptByte();
+ b = getVarOrDirectByte(0x80);
+ c = getVarOrDirectByte(0x40);
+ _opcode = fetchScriptByte();
+ d = getVarOrDirectByte(0x80);
+ unkRoomFunc4(b, c, a, d, 1);
+ break;
+
+ case 16: /* ? */
+ a = getVarOrDirectByte(0x80);
+ b = getVarOrDirectByte(0x40);
+ if (b!=0)
+ _colorCycleDelays[a] = 0x4000 / (b*0x4C);
+ else
+ _colorCycleDelays[a] = 0;
+ break;
+ }
+}
+
+void Scumm::o_saveRestoreVerbs() {
+ int a,b,c,slot, slot2;
+
+ _opcode = fetchScriptByte();
+
+ a = getVarOrDirectByte(0x80);
+ b = getVarOrDirectByte(0x40);
+ c = getVarOrDirectByte(0x20);
+
+ switch(_opcode) {
+ case 1: /* hide verbs */
+ while (a<=b) {
+ slot = getVerbSlot(a,0);
+ if (slot && verbs[slot].saveid==0) {
+ verbs[slot].saveid = c;
+ drawVerb(slot, 0);
+ verbMouseOver(0);
+ }
+ a++;
+ }
+ break;
+ case 2: /* show verbs */
+ while (a<=b) {
+ slot = getVerbSlot(a, c);
+ if (slot) {
+ slot2 = getVerbSlot(a,0);
+ if (slot2)
+ killVerb(slot2);
+ slot = getVerbSlot(a,c);
+ verbs[slot].saveid = 0;
+ drawVerb(slot, 0);
+ verbMouseOver(0);
+ }
+ a++;
+ }
+ break;
+ case 3: /* kill verbs */
+ while (a<=b) {
+ slot = getVerbSlot(a,c);
+ if (slot)
+ killVerb(slot);
+ a++;
+ }
+ break;
+ default:
+ error("o_saveRestoreVerbs: invalid opcode");
+ }
+}
+
+void Scumm::o_setCameraAt() {
+ CameraData *cd = &camera;
+ cd->_curPos = getVarOrDirectWord(0x80);
+ cd->_mode = 1;
+ setCameraAt(cd->_curPos);
+ cd->_movingToActor = 0;
+}
+
+void Scumm::o_setObjectName() {
+ int act = getVarOrDirectWord(0x80);
+ int size;
+ int a;
+ int i;
+
+ if (vm.vars[VAR_NUM_ACTOR] >= act)
+ error("Can't set actor %d name with new-name-of", act);
+
+ if (!getObjectAddress(act))
+ error("Can't set name of object %d", act);
+
+ size = READ_BE_UINT32_UNALIGNED(getObjOrActorName(act) - 4)-9;
+ i = 0;
+
+ while ((a = fetchScriptByte()) != 0) {
+ getObjOrActorName(act)[i++] = a;
+
+ if (a==0xFF) {
+ getObjOrActorName(act)[i++] = fetchScriptByte();
+ getObjOrActorName(act)[i++] = fetchScriptByte();
+ getObjOrActorName(act)[i++] = fetchScriptByte();
+ }
+
+ if (i > size)
+ error("New name of object %d too long", act);
+ }
+
+ getObjOrActorName(act)[i] = 0;
+ runHook(0);
+}
+
+void Scumm::o_setOwnerOf() {
+ int obj, owner;
+ ScriptSlot *ss;
+
+ obj = getVarOrDirectWord(0x80);
+ owner = getVarOrDirectByte(0x40);
+
+ if (owner==0) {
+ clearOwnerOf(obj);
+ ss = &vm.slot[_currentScript];
+ if (ss->type==0 && _inventory[ss->number]==obj) {
+ putOwner(obj, owner);
+ runHook(0);
+ stopObjectCode();
+ return;
+ }
+ }
+ putOwner(obj, owner);
+ runHook(0);
+}
+
+void Scumm::o_setState() {
+ int obj, state;
+ obj = getVarOrDirectWord(0x80);
+ state = getVarOrDirectByte(0x40);
+ putState(obj, state);
+ removeObjectFromRoom(obj);
+ if (_BgNeedsRedraw)
+ clearDrawObjectQueue();
+}
+
+void Scumm::o_setVarRange() {
+ int a,b;
+
+ getResultPos();
+ a=fetchScriptByte();
+ do {
+ if (_opcode&0x80)
+ b=fetchScriptWord();
+ else
+ b=fetchScriptByte();
+
+ setResult(b);
+ _resultVarNumber++;
+ } while (--a);
+}
+
+void Scumm::o_soundKludge() {
+ int16 items[15];
+ int i;
+ int16 *ptr;
+
+ for (i=0; i<15; i++)
+ items[i] = 0;
+
+ getWordVararg(items);
+ if (items[0]==-1)
+ unkSoundProc22();
+ else {
+ _soundQue[_soundQuePos++] = 8;
+
+ ptr = _soundQue + _soundQuePos;
+ _soundQuePos += 8;
+
+ for (i=0; i<8; i++)
+ *ptr++ = items[i];
+ if (_soundQuePos > 0x100)
+ error("Sound que buffer overflow");
+ }
+}
+
+void Scumm::o_startMusic() {
+ addSoundToQueue(getVarOrDirectByte(0x80));
+}
+
+void Scumm::o_startObject() {
+ int obj, script;
+ int16 data[16];
+
+ obj = getVarOrDirectWord(0x80);
+ script = getVarOrDirectByte(0x40);
+
+ getWordVararg(data);
+ runVERBCode(obj, script, 0, 0, data);
+}
+
+void Scumm::o_startScript() {
+ int op,script;
+ int16 data[16];
+ int a,b;
+
+ op = _opcode;
+ script = getVarOrDirectByte(0x80);
+
+ getWordVararg(data);
+
+ a = b = 0;
+ if (op&0x40) b=1;
+ if (op&0x20) a=1;
+
+ runScript(script, a, b, data);
+}
+
+void Scumm::o_startSound() {
+ addSoundToQueue(getVarOrDirectByte(0x80));
+}
+
+void Scumm::o_stopMusic() {
+ /* TODO: not implemented */
+ warning("o_stopMusic: not implemented");
+}
+
+void Scumm::o_stopObjectCode() {
+ stopObjectCode();
+}
+
+void Scumm::o_stopObjectScript() {
+ stopObjectScript(getVarOrDirectWord(0x80));
+}
+
+void Scumm::o_stopScript() {
+ int script;
+
+ script = getVarOrDirectByte(0x80);
+ if (script==0)
+ stopObjectCode();
+ else
+ stopScriptNr(script);
+}
+
+void Scumm::o_stopSound() {
+ unkSoundProc1(getVarOrDirectByte(0x80));
+}
+
+void Scumm::o_stringOps() {
+ int a,b,c,i;
+ byte *ptr;
+
+ _opcode = fetchScriptByte();
+ switch(_opcode&0x1F) {
+ case 1: /* loadstring */
+ loadPtrToResource(7, getVarOrDirectByte(0x80), NULL);
+ break;
+ case 2: /* copystring */
+ a = getVarOrDirectByte(0x80);
+ b = getVarOrDirectByte(0x40);
+ nukeResource(7, a);
+ ptr = getResourceAddress(7, b);
+ if (ptr) loadPtrToResource(7, a, ptr);
+ break;
+ case 3: /* set string char */
+ a = getVarOrDirectByte(0x80);
+ b = getVarOrDirectByte(0x40);
+ ptr = getResourceAddress(7, a);
+ if (ptr==NULL) error("String %d does not exist", a);
+ c = getVarOrDirectByte(0x20);
+ ptr[b] = c;
+ break;
+
+ case 4: /* get string char */
+ getResultPos();
+ a = getVarOrDirectByte(0x80);
+ b = getVarOrDirectByte(0x40);
+ ptr = getResourceAddress(7, a);
+ if (ptr==NULL) error("String %d does not exist", a);
+ setResult(ptr[b]);
+ break;
+
+ case 5: /* create empty string */
+ a = getVarOrDirectByte(0x80);
+ b = getVarOrDirectByte(0x40);
+ nukeResource(7, a);
+ if (b) {
+ ptr = createResource(7, a, b);
+ if (ptr) {
+ for(i=0; i<b; i++)
+ ptr[i] = 0;
+ }
+ }
+ break;
+ }
+}
+
+void Scumm::o_subtract() {
+ int a;
+ getResultPos();
+ a = getVarOrDirectWord(0x80);
+ setResult(readVar(_resultVarNumber) - a);
+}
+
+void Scumm::o_verbOps() {
+ int verb,slot;
+ VerbSlot *vs;
+ int a,b;
+ byte *ptr;
+
+ verb = getVarOrDirectByte(0x80);
+
+ slot = getVerbSlot(verb,0);
+ checkRange(_maxVerbs-1, 0, slot, "Illegal new verb slot %d");
+
+ vs = &verbs[slot];
+ vs->verbid = verb;
+
+ while ((_opcode=fetchScriptByte()) != 0xFF) {
+ switch(_opcode&0x1F) {
+ case 1: /* load image */
+ a = getVarOrDirectWord(0x80);
+ if (verb) {
+ setVerbObject(_roomResource, a, verb);
+ vs->type = 1;
+ }
+ break;
+ case 2: /* load from code */
+ loadPtrToResource(8, slot, NULL);
+ if (slot==0)
+ nukeResource(8, slot);
+ vs->type = 0;
+ vs->imgindex = 0;
+ break;
+ case 3: /* color */
+ vs->color = getVarOrDirectByte(0x80);
+ break;
+ case 4: /* set hi color */
+ vs->hicolor = getVarOrDirectByte(0x80);
+ break;
+ case 5: /* set xy */
+ vs->x = getVarOrDirectWord(0x80);
+ vs->y = getVarOrDirectWord(0x40);
+ break;
+ case 6: /* set on */
+ vs->curmode=1;
+ break;
+ case 7: /* set off */
+ vs->curmode=0;
+ break;
+ case 8: /* delete */
+ killVerb(slot);
+ break;
+ case 9: /* new */
+ slot = getVerbSlot(verb, 0);
+ if (slot==0) {
+ for (slot=1; slot<_maxVerbs; slot++) {
+ if(verbs[slot].verbid==0)
+ break;
+ }
+ if (slot==_maxVerbs)
+ error("Too many verbs");
+ }
+ vs = &verbs[slot];
+ vs->verbid = verb;
+ vs->color = 2;
+ vs->hicolor = 0;
+ vs->dimcolor = 8;
+ vs->type = 0;
+ vs->charset_nr = textslot.charset[0];
+ vs->curmode = 0;
+ vs->saveid = 0;
+ vs->key = 0;
+ vs->center = 0;
+ vs->imgindex = 0;
+ break;
+
+ case 16: /* set dim color */
+ vs->dimcolor = getVarOrDirectByte(0x80);
+ break;
+ case 17: /* dim */
+ vs->curmode = 2;
+ break;
+ case 18: /* set key */
+ vs->key = getVarOrDirectByte(0x80);
+ break;
+ case 19: /* set center */
+ vs->center = 1;
+ break;
+ case 20: /* set to string */
+ ptr = getResourceAddress(7, getVarOrDirectWord(0x80));
+ if (!ptr)
+ nukeResource(8, slot);
+ else {
+ loadPtrToResource(8, slot, ptr);
+ }
+ if (slot==0)
+ nukeResource(8, slot);
+ vs->type = 0;
+ vs->imgindex = 0;
+ break;
+ case 22: /* assign object */
+ a = getVarOrDirectWord(0x80);
+ b = getVarOrDirectByte(0x40);
+ if (slot && vs->imgindex!=a) {
+ setVerbObject(b, a, slot);
+ vs->type = 1;
+ vs->imgindex = a;
+ }
+ break;
+ case 23: /* set back color */
+ vs->bkcolor = getVarOrDirectByte(0x80);
+ break;
+ }
+ }
+ drawVerb(slot, 0);
+ verbMouseOver(0);
+}
+
+void Scumm::o_wait() {
+ byte *oldaddr;
+
+ oldaddr = _scriptPointer - 1;
+
+ _opcode = fetchScriptByte();
+ switch(_opcode&0x1F) {
+ case 1: /* wait for actor */
+ if (derefActorSafe(getVarOrDirectByte(0x80), "o_wait")->moving)
+ break;
+ return;
+ case 2: /* wait for message */
+ if (vm.vars[VAR_HAVE_MSG])
+ break;
+ return;
+ case 3: /* wait for camera */
+ if (camera._curPos>>3 != camera._destPos>>3)
+ break;
+ return;
+ case 4: /* wait for sentence */
+ if (_sentenceIndex!=0xFF) {
+ if (_sentenceTab[_sentenceIndex] &&
+ !isScriptLoaded(vm.vars[VAR_SENTENCE_SCRIPT]) )
+ return;
+ break;
+ }
+ if (!isScriptLoaded(vm.vars[VAR_SENTENCE_SCRIPT]))
+ return;
+ break;
+
+ default:
+ return;
+ }
+
+ _scriptPointer = oldaddr;
+ o_breakHere();
+}
+
+void Scumm::o_walkActorTo() {
+ int x, y;
+ Actor *a;
+ a = derefActorSafe(getVarOrDirectByte(0x80), "o_walkActorTo");
+ x = getVarOrDirectWord(0x40);
+ y = getVarOrDirectWord(0x20);
+ startWalkActor(a, x, y, 0xFF);
+}
+
+void Scumm::o_walkActorToActor() {
+ int b,x,y;
+ Actor *a, *a2;
+
+ a = derefActorSafe(getVarOrDirectByte(0x80), "o_walkActorToActor");
+ if (a->room != _currentRoom) {
+ getVarOrDirectByte(0x40);
+ fetchScriptByte();
+ return;
+ }
+
+ a2 = derefActorSafe(getVarOrDirectByte(0x40), "o_walkActorToActor(2)");
+ if (a2->room != _currentRoom) {
+ fetchScriptByte();
+ return;
+ }
+ b = fetchScriptByte(); /* distance from actor */
+ if (b==0xFF) {
+ b = a2->scalex * a->width / 0xFF;
+ b = b + b/2;
+ }
+ y = a2->x;
+ x = a2->y;
+ if (x < a->x)
+ x += b;
+ else
+ x -= b;
+
+ startWalkActor(a, x, y, 0xFF);
+}
+
+void Scumm::o_walkActorToObject() {
+ int obj;
+ Actor *a;
+
+ a = derefActorSafe(getVarOrDirectByte(0x80), "o_walkActorToObject");
+ obj = getVarOrDirectWord(0x40);
+ if (whereIsObject(obj)!=-1) {
+ getObjectXYPos(obj);
+ startWalkActor(a, _xPos, _yPos, _dir);
+ }
+}
+
+void Scumm::stopObjectCode() {
+ ScriptSlot *ss;
+
+ ss = &vm.slot[_currentScript];
+
+ if (ss->type!=2 && ss->type!=3) {
+ stopObjectScript(ss->number);
+ } else {
+ if (ss->cutsceneOverride)
+ error("Script %d ending with active cutscene/override", ss->number);
+ ss->number = 0;
+ ss->status = 0;
+ }
+ _currentScript = 0xFF;
+}
+
+int Scumm::getWordVararg(int16 *ptr) {
+ int i;
+ for (i=0; i<16; i++)
+ ptr[i] = 0;
+
+ i = 0;
+ while ((_opcode = fetchScriptByte()) != 0xFF) {
+ ptr[i++] = getVarOrDirectWord(0x80);
+ }
+ return i;
+}
+
+bool Scumm::isScriptLoaded(int script) {
+ ScriptSlot *ss;
+ int i;
+
+ ss = vm.slot;
+ for (i=0; i<20; i++,ss++) {
+ if (ss->number == script)
+ return true;
+ }
+ return false;
+}
+
+void Scumm::runHook(int i) {
+ int16 tmp[16];
+ tmp[0] = i;
+ if (vm.vars[VAR_HOOK_SCRIPT]) {
+ runScript(vm.vars[VAR_HOOK_SCRIPT], 0, 0, tmp);
+ }
+}
+
+void Scumm::freezeScripts(int flag) {
+ int i;
+
+ for(i=1; i<20; i++) {
+ if (_currentScript!=i && vm.slot[i].status!=0 && (vm.slot[i].unk1==0 || flag>=0x80)) {
+ vm.slot[i].status |= 0x80;
+ vm.slot[i].freezeCount++;
+ }
+ }
+
+ for (i=0; i<6; i++)
+ _sentenceTab[i]++;
+
+ if(vm.cutSceneScriptIndex != 0xFF) {
+ vm.slot[vm.cutSceneScriptIndex].status&=0x7F;
+ vm.slot[vm.cutSceneScriptIndex].freezeCount=0;
+ }
+}
+
+void Scumm::unfreezeScripts() {
+ int i;
+ for (i=1; i<20; i++) {
+ if (vm.slot[i].status&0x80) {
+ if (!--vm.slot[i].freezeCount) {
+ vm.slot[i].status&=0x7F;
+ }
+ }
+ }
+
+ for (i=0; i<6; i++) {
+ if (((int8)--_sentenceTab[i])<0)
+ _sentenceTab[i] = 0;
+ }
+}
+
+void Scumm::runAllScripts() {
+ int i;
+
+ for (i=0; i<20; i++)
+ vm.slot[i].didexec = 0;
+
+ _currentScript = 0xFF;
+ for(_curExecScript = 0; _curExecScript<20; _curExecScript++) {
+ if (vm.slot[_curExecScript].status == 2 &&
+ vm.slot[_curExecScript].didexec == 0) {
+ _currentScript = _curExecScript;
+ getScriptBaseAddress();
+ getScriptEntryPoint();
+ executeScript();
+ }
+ }
+}
+
+void Scumm::runExitScript() {
+ if (vm.vars[VAR_EXIT_SCRIPT])
+ runScript(vm.vars[VAR_EXIT_SCRIPT], 0, 0, 0);
+ if (_EXCD_offs) {
+ int slot = getScriptSlot();
+ vm.slot[slot].status = 2;
+ vm.slot[slot].number = 10001;
+ vm.slot[slot].type = 1;
+ vm.slot[slot].offs = _EXCD_offs + 8;
+ vm.slot[slot].unk1 = 0;
+ vm.slot[slot].unk2 = 0;
+ vm.slot[slot].freezeCount = 0;
+ runScriptNested(slot);
+ }
+ if (vm.vars[VAR_EXIT_SCRIPT2])
+ runScript(vm.vars[VAR_EXIT_SCRIPT2], 0, 0, 0);
+}
+
+void Scumm::runEntryScript() {
+ if (vm.vars[VAR_ENTRY_SCRIPT])
+ runScript(vm.vars[VAR_ENTRY_SCRIPT], 0, 0, 0);
+ if (_ENCD_offs) {
+ int slot = getScriptSlot();
+ vm.slot[slot].status = 2;
+ vm.slot[slot].number = 10002;
+ vm.slot[slot].type = 1;
+ vm.slot[slot].offs = _ENCD_offs + 8;
+ vm.slot[slot].unk1 = 0;
+ vm.slot[slot].unk2 = 0;
+ vm.slot[slot].freezeCount = 0;
+ runScriptNested(slot);
+ }
+ if (vm.vars[VAR_ENTRY_SCRIPT2])
+ runScript(vm.vars[VAR_ENTRY_SCRIPT2], 0, 0, 0);
+}
+
+void Scumm::killScriptsAndResources() {
+ ScriptSlot *ss;
+ int i;
+
+ ss = &vm.slot[1];
+
+ for (i=1; i<20; i++,ss++) {
+ if (ss->type==1 || ss->type==4) {
+ if(ss->cutsceneOverride)
+ error("Object %d stopped with active cutscene/override in exit", ss->number);
+ ss->status = 0;
+ } else if (ss->type==3) {
+ if(ss->cutsceneOverride)
+ error("Script %d stopped with active cutscene/override in exit", ss->number);
+ ss->status = 0;
+ }
+ }
+
+ i = 0;
+ do {
+ if (objs[i].fl_object_index)
+ nukeResource(0xD, objs[i].fl_object_index);
+ } while (++i <= _numObjectsInRoom);
+}
+
+void Scumm::checkAndRunVar33() {
+ int i;
+ ScriptSlot *ss;
+
+ memset(_localParamList, 0, sizeof(_localParamList));
+ if (isScriptLoaded(vm.vars[VAR_SENTENCE_SCRIPT])) {
+ ss = vm.slot;
+ for (i=0; i<20; i++,ss++)
+ if (ss->number==vm.vars[VAR_SENTENCE_SCRIPT] && ss->status!=0 && ss->freezeCount==0)
+ return;
+ }
+
+ if (_sentenceIndex > 0x7F || _sentenceTab[_sentenceIndex])
+ return;
+
+ if (_sentenceTab2[_sentenceIndex] &&
+ _sentenceTab3[_sentenceIndex]==_sentenceTab4[_sentenceIndex]) {
+ _sentenceIndex--;
+ return;
+ }
+
+ _localParamList[0] = _sentenceTab5[_sentenceIndex];
+ _localParamList[1] = _sentenceTab4[_sentenceIndex];
+ _localParamList[2] = _sentenceTab3[_sentenceIndex];
+ _sentenceIndex--;
+ _currentScript = 0xFF;
+ if (vm.vars[VAR_SENTENCE_SCRIPT])
+ runScript(vm.vars[VAR_SENTENCE_SCRIPT], 0, 0, _localParamList);
+}
+
+void Scumm::runInputScript(int a, int cmd, int mode) {
+ memset(_localParamList, 0, sizeof(_localParamList));
+ _localParamList[0] = a;
+ _localParamList[1] = cmd;
+ _localParamList[2] = mode;
+ if (vm.vars[VAR_VERB_SCRIPT])
+ runScript(vm.vars[VAR_VERB_SCRIPT], 0, 0, _localParamList);
+}
+
+void Scumm::decreaseScriptDelay(int amount) {
+ ScriptSlot *ss = &vm.slot[0];
+ int i;
+ for (i=0; i<20; i++,ss++) {
+ if(ss->status==1) {
+ ss->delay -= amount;
+ if (ss->delay < 0){
+ ss->status = 2;
+ ss->delay = 0;
+ }
+ }
+ }
+}
+
+void Scumm::decodeParseString() {
+ int textSlot;
+
+ switch(_actorToPrintStrFor) {
+ case 252:
+ textSlot = 3;
+ break;
+ case 253:
+ textSlot = 2;
+ break;
+ case 254:
+ textSlot = 1;
+ break;
+ default:
+ textSlot = 0;
+ }
+
+ _stringXpos[textSlot] = textslot.x[textSlot];
+ _stringYpos[textSlot] = textslot.y[textSlot];
+ _stringCenter[textSlot] = textslot.center[textSlot];
+ _stringOverhead[textSlot] = textslot.overhead[textSlot];
+ _stringRight[textSlot] = textslot.right[textSlot];
+ _stringColor[textSlot] = textslot.color[textSlot];
+ _stringCharset[textSlot] = textslot.charset[textSlot];
+
+ while((_opcode=fetchScriptByte()) != 0xFF) {
+ switch(_opcode&0xF) {
+ case 0: /* set string xy */
+ _stringXpos[textSlot] = getVarOrDirectWord(0x80);
+ _stringYpos[textSlot] = getVarOrDirectWord(0x40);
+ _stringOverhead[textSlot] = 0;
+ break;
+ case 1: /* color */
+ _stringColor[textSlot] = getVarOrDirectByte(0x80);
+ break;
+ case 2: /* right */
+ _stringRight[textSlot] = getVarOrDirectWord(0x80);
+ break;
+ case 4: /* center*/
+ _stringCenter[textSlot] = 1;
+ _stringOverhead[textSlot] = 0;
+ break;
+ case 6: /* left */
+ _stringCenter[textSlot] = 0;
+ _stringOverhead[textSlot] = 0;
+ break;
+ case 7: /* overhead */
+ _stringOverhead[textSlot] = 1;
+ break;
+ case 8: /* ignore */
+ getVarOrDirectWord(0x80);
+ getVarOrDirectWord(0x40);
+ break;
+ case 15:
+ _messagePtr = _scriptPointer;
+ switch(textSlot) {
+ case 0: actorTalk(); break;
+ case 1: drawString(1); break;
+ case 2: unkMessage1(); break;
+ case 3: unkMessage2(); break;
+ }
+ _scriptPointer = _messagePtr;
+ return;
+ default:
+ return;
+ }
+ }
+
+ textslot.x[textSlot] = _stringXpos[textSlot];
+ textslot.y[textSlot] = _stringYpos[textSlot];
+ textslot.center[textSlot] = _stringCenter[textSlot];
+ textslot.overhead[textSlot] = _stringOverhead[textSlot];
+ textslot.right[textSlot] = _stringRight[textSlot];
+ textslot.color[textSlot] = _stringColor[textSlot];
+ textslot.charset[textSlot] = _stringCharset[textSlot];
+}
+
+
+void Scumm::runVERBCode(int object, int entry, int a, int b, int16 *vars) {
+ uint32 obcd;
+ int slot, where, offs,i;
+
+ if (!object)
+ return;
+ if (!b)
+ stopObjectScript(object);
+
+ where = whereIsObject(object);
+
+ if (where == -1) {
+ error("Code for object %d not in room %d", object, _roomResource);
+ }
+
+ obcd = getOBCDOffs(object);
+ slot = getScriptSlot();
+
+ offs = getVerbEntrypoint(object, entry);
+ if (offs==0)
+ return;
+
+ vm.slot[slot].number = object;
+ vm.slot[slot].offs = obcd + offs;
+ vm.slot[slot].status = 2;
+ vm.slot[slot].type = where;
+ vm.slot[slot].unk1 = a;
+ vm.slot[slot].unk2 = b;
+ vm.slot[slot].freezeCount = 0;
+
+ if (!vars) {
+ for(i=0; i<16; i++)
+ vm.localvar[slot * 17 + i] = 0;
+ } else {
+ for (i=0; i<16; i++)
+ vm.localvar[slot * 17 + i] = vars[i];
+ }
+
+ runScriptNested(slot);
+}
+
+void Scumm::stackPush(int a) {
+ assert(_scummStackPos >=0 && _scummStackPos < sizeof(_scummStack)-1);
+ _scummStack[_scummStackPos++] = a;
+}
+
+int Scumm::stackPop() {
+ assert(_scummStackPos >0 && _scummStackPos < sizeof(_scummStack));
+ return _scummStack[--_scummStackPos];
+}
+
+int Scumm::getVerbEntrypoint(int obj, int entry) {
+ byte *objptr, *verbptr;
+ int verboffs;
+
+ if (whereIsObject(obj)==-1)
+ return 0;
+
+ objptr = getObjectAddress(obj);
+
+ verbptr = findResource(MKID('VERB'), objptr);
+ if (verbptr==NULL)
+ error("No verb block in object %d", obj);
+
+ verboffs = verbptr - objptr;
+
+ verbptr += 8;
+ do {
+ if (!*verbptr)
+ return 0;
+ if (*verbptr==entry || *verbptr==0xFF)
+ break;
+ verbptr += 3;
+ } while (1);
+
+ return verboffs + READ_LE_UINT16(verbptr+1);
+}
+
diff --git a/scumm.h b/scumm.h
new file mode 100644
index 0000000000..78be39c15e
--- /dev/null
+++ b/scumm.h
@@ -0,0 +1,1234 @@
+/* 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.
+ *
+ * Change Log:
+ * $Log$
+ * Revision 1.1 2001/10/09 14:30:12 strigeus
+ * Initial revision
+ *
+ *
+ */
+
+#include "scummsys.h"
+
+#ifdef WIN32
+#pragma warning (disable: 4018)
+#pragma warning (disable: 4244)
+#endif
+
+#define SWAP(a,b) do{int tmp=a; a=b; b=tmp; } while(0)
+
+#define BYPASS_COPY_PROT
+#define DUMP_SCRIPTS
+
+struct Scumm;
+struct Actor;
+
+typedef void (Scumm::*OpcodeProc)();
+
+#pragma START_PACK_STRUCTS
+
+struct Point {
+ int x,y;
+};
+
+struct AdjustBoxResult {
+ int16 x,y;
+ uint16 dist;
+};
+
+#define SIZEOF_BOX 20
+struct Box { /* file format */
+ int16 ulx,uly;
+ int16 urx,ury;
+ int16 llx,lly;
+ int16 lrx,lry;
+ byte mask;
+ byte flags;
+ uint16 scale;
+};
+
+struct VerbSlot {
+ int16 x,y;
+ int16 right, bottom;
+ int16 oldleft, oldtop, oldright,oldbottom;
+ uint8 verbid;
+ uint8 color,hicolor,dimcolor,bkcolor,type;
+ uint8 charset_nr,curmode;
+ uint8 saveid;
+ uint8 key,center;
+ uint8 field_1B;
+ uint16 imgindex;
+};
+
+struct VirtScreen {
+ uint16 unk1;
+ uint16 topline;
+ uint16 width,height;
+ uint16 size;
+ byte alloctwobuffers;
+ byte fourlinesextra;
+ uint16 xstart;
+ byte tdirty[40];
+ byte bdirty[40];
+};
+
+struct ActorWalkData {
+ int16 destx,desty;
+ byte destbox;
+ byte destdir;
+ byte curbox;
+ byte field_7;
+ int16 x,y,newx,newy;
+ int32 XYFactor, YXFactor;
+ uint16 xfrac,yfrac;
+};
+
+struct CostumeData {
+ uint16 hdr;
+ uint16 animCounter1;
+ byte animCounter2;
+ byte x_1;
+ uint16 a[16], b[16], c[16], d[16];
+};
+
+struct MouseCursor {
+ int8 hotspot_x, hotspot_y;
+ byte colors[4];
+ byte data[32];
+};
+
+struct ScriptSlot {
+ uint32 offs;
+ int32 delay;
+ uint16 number;
+ byte status;
+ byte type;
+ byte unk1,unk2,freezeCount,didexec;
+ byte cutsceneOverride;
+ byte unk5;
+};
+
+struct NestedScript {
+ uint16 number;
+ uint8 type;
+ uint8 slot;
+};
+
+struct ObjectData {
+ uint32 offs_obim_to_room;
+ uint32 offs_obcd_to_room;
+ uint16 cdhd_10, cdhd_12;
+ uint16 obj_nr;
+ byte x_pos;
+ byte y_pos;
+ byte numstrips;
+ byte height;
+ byte actordir;
+ byte cdhd_0f;
+ byte cdhd_0e;
+ byte ownerstate;
+ byte fl_object_index;
+ byte unk_3;
+};
+
+struct RoomHeader {
+ uint32 tag, size;
+ uint16 width,height;
+ uint16 numObjects;
+};
+
+struct CodeHeader { /* file format */
+ uint32 id;
+ uint32 size;
+ uint16 obj_id;
+ byte x,y,w,h;
+ byte flags;
+ byte unk1;
+ uint16 unk2;
+ uint16 unk3;
+ byte unk4;
+};
+
+struct ImageHeader { /* file format */
+ uint32 id;
+ uint32 size;
+ uint16 obj_id;
+};
+
+struct PathNode {
+ uint index;
+ struct PathNode *left, *right;
+};
+
+struct PathVertex {
+ PathNode *left;
+ PathNode *right;
+};
+
+#pragma END_PACK_STRUCTS
+
+enum ScummVars {
+ VAR_UNK_ACTOR = 1,
+ VAR_WALKTO_OBJ = 38,
+ VAR_OVERRIDE = 5,
+ VAR_NUM_ACTOR = 8,
+ VAR_OBJECT_LO = 15,
+ VAR_OBJECT_HI = 16,
+ VAR_CURRENTDRIVE = 10,
+ VAR_TALK_ACTOR = 25,
+ VAR_DEBUGMODE = 39,
+ VAR_VERSION = 75,
+ VAR_FIXEDDISK = 51,
+ VAR_CURSORSTATE = 52,
+ VAR_USERPUT = 53,
+ VAR_SOUNDCARD = 48,
+ VAR_VIDEOMODE = 49,
+ VAR_HEAPSPACE = 40,
+ VAR_MOUSEPRESENT = 67,
+ VAR_SOUNDPARAM = 64,
+ VAR_SOUNDPARAM2 = 65,
+ VAR_SOUNDPARAM3 = 66,
+ VAR_GAME_LOADED = 71,
+ VAR_VIRT_MOUSE_X = 20,
+ VAR_VIRT_MOUSE_Y = 21,
+ VAR_PERFORMANCE_1 = 68,
+ VAR_PERFORMANCE_2 = 69,
+ VAR_ROOM_FLAG = 70,
+ VAR_HAVE_MSG = 3,
+ VAR_ENTRY_SCRIPT = 28,
+ VAR_ENTRY_SCRIPT2 = 29,
+ VAR_EXIT_SCRIPT = 30,
+ VAR_EXIT_SCRIPT2 = 31,
+ VAR_VERB_SCRIPT = 32,
+ VAR_SENTENCE_SCRIPT = 33,
+ VAR_LAST_SOUND = 23,
+ VAR_HOOK_SCRIPT = 34,
+ VAR_CUTSCENE_START_SCRIPT = 35,
+ VAR_CUTSCENE_END_SCRIPT = 36,
+ VAR_SCROLL_SCRIPT = 27,
+ VAR_CAMERA_MIN = 17,
+ VAR_CAMERA_MAX = 18,
+ VAR_CAMERA_FAST = 26,
+ VAR_CAMERA_CUR_POS = 2,
+ VAR_NEW_ROOM = 72,
+ VAR_ROOM = 4,
+ VAR_ROOM_RESOURCE = 22,
+
+ VAR_MOUSE_X = 44,
+ VAR_MOUSE_Y = 45,
+
+ VAR_TIMER = 46,
+ VAR_TIMER_NEXT = 19,
+
+ VAR_TMR_1 = 11,
+ VAR_TMR_2 = 12,
+ VAR_TMR_3 = 13,
+ VAR_TMR_4 = 47,
+
+ VAR_DRAWFLAGS = 9,
+
+ VAR_SOUNDRESULT = 56,
+
+ VAR_PLAYBACKTIMER = 19,
+
+ VAR_TALK_STRING_Y = 54,
+ VAR_CHARFLAG = 60,
+ VAR_CHARINC = 37,
+
+ VAR_RESTART_KEY = 42,
+ VAR_PAUSE_KEY = 43,
+ VAR_CUTSCENEEXIT_KEY = 24,
+ VAR_TALKSTOP_KEY = 57,
+ VAR_SAVELOADDIALOG_KEY = 50,
+};
+
+#define _maxRooms res.num[1]
+#define _maxScripts res.num[2]
+#define _maxCostumes res.num[3]
+#define _maxInventoryItems res.num[5]
+#define _maxCharsets res.num[6]
+#define _maxStrings res.num[7]
+#define _maxVerbs res.num[8]
+#define _maxActorNames res.num[9]
+#define _maxBuffer res.num[10]
+#define _maxScaleTable res.num[11]
+#define _maxTemp res.num[12]
+#define _maxFLObject res.num[13]
+#define _maxMatrixes res.num[14]
+#define _maxBoxes res.num[15]
+
+#define _baseRooms res.address[1]
+#define _baseScripts res.address[2]
+#define _baseInventoryItems res.address[5]
+#define _baseFLObject res.address[13]
+
+#define _roomFileOffsets res.roomoffs[1]
+
+struct CharsetRenderer {
+ Scumm *_vm;
+ int _top;
+ int _drawTop;
+ int _left, _left2;
+ byte _center;
+ uint _right;
+ byte _color;
+ bool _hasMask;
+
+ int _strLeft, _strRight, _strTop, _strBottom;
+ int _mask_bottom, _mask_right, _mask_top, _mask_left;
+ byte _curId;
+
+ byte _bufPos;
+ byte _unk12,_disableOffsX;
+ byte *_ptr;
+ byte _unk2, _bpp;
+ byte _invNumBits;
+ uint32 _charOffs;
+ byte *_charPtr;
+ int _width, _height;
+ int _offsX,_offsY;
+ byte _bitMask, _revBitMask;
+ int _bottom;
+ int _virtScreenHeight;
+
+ byte _ignoreCharsetMask;
+
+ byte *_bg_ptr, *_where_to_draw_ptr;
+ byte *_mask_ptr;
+
+ byte _colorMap[16];
+ byte _buffer[256];
+
+ void drawBits();
+ void printChar(int chr);
+ int getStringWidth(int a, byte *str, int pos);
+ void addLinebreaks(int a, byte *str, int pos, int maxwidth);
+};
+
+struct CostumeRenderer {
+ Scumm *_vm;
+ byte *_ptr;
+ byte _numColors;
+ byte *_dataptr;
+ byte *_frameptr;
+ byte *_srcptr;
+ byte *_where_to_draw_ptr, *_bg_ptr, *_mask_ptr, *_mask_ptr_dest;
+ int _actorX, _actorY;
+ byte _zbuf;
+ uint _scaleX, _scaleY;
+ int _xmove, _ymove;
+ bool _mirror;
+ byte _maskval;
+ byte _shrval;
+ byte _width2;
+ int _width;
+ byte _height2;
+ int _height;
+ int _xpos, _ypos;
+ int _scaleIndexXStep;
+ int _scaleIndexYStep;
+ byte _scaleIndexX; /* must wrap at 256*/
+ byte _scaleIndexY, _scaleIndexYTop;
+ int _left,_right;
+ int _dir2;
+ int _top,_bottom;
+ int _ypostop;
+ uint _vscreenheight;
+ int _ypitch;
+ byte _docontinue;
+ int _imgbufoffs;
+ byte _repcolor;
+ byte _replen;
+ byte _palette[32];
+ byte _transEffect[0x100];
+
+ void proc6();
+ void proc5();
+ void proc4();
+ void proc3();
+ void proc2();
+ void proc1();
+ byte mainRoutine(Actor *a, int slot, int frame);
+ void ignorePakCols(int num);
+
+ void loadCostume(int id);
+ byte drawOneSlot(Actor *a, int slot);
+ byte drawCostume(Actor *a);
+
+ byte animateOneSlot(CostumeData *cd, int slot);
+ byte animate(CostumeData *cd);
+};
+
+struct Actor {
+ int16 x,y,top,bottom;
+ int16 elevation;
+ uint16 width;
+ byte number;
+ byte facing;
+ byte costume;
+ byte room;
+ byte talkColor;
+ byte scalex,scaley;
+ byte charset,sound;
+ byte newDirection;
+ byte moving;
+ byte ignoreBoxes;
+ byte neverZClip;
+ byte initFrame,walkFrame,standFrame,talkFrame1,talkFrame2;
+ bool needRedraw, needBgReset,costumeNeedsInit,visible;
+ uint16 speedx,speedy;
+ byte data8; /* unused */
+ byte animIndex;
+ byte walkbox;
+ byte mask;
+ byte animProgress, animSpeed;
+ ActorWalkData walkdata;
+ CostumeData cost;
+ byte palette[32];
+};
+
+struct CameraData {
+ int16 _destPos, _curPos, _lastPos;
+ int16 _leftTrigger, _rightTrigger;
+ byte _follows, _mode;
+ uint16 _movingToActor;
+};
+
+struct Scumm {
+ int _lastLoadedRoom;
+ int _roomResource;
+ byte _encbyte;
+ void *_fileHandle;
+ char *_exe_name;
+
+ bool _dynamicRoomOffsets;
+ byte _resFilePathId;
+
+ char *_resFilePrefix;
+ char *_resFilePath;
+
+ int _keyPressed;
+
+ uint8 *_roomFileIndexes;
+ byte *_objectFlagTable;
+ uint32 *_classData;
+
+ byte _numGlobalScriptsUsed;
+
+ uint16 _maxNrObjects;
+
+ uint16 _numZBuffer;
+
+ uint32 _randSeed1;
+ uint32 _randSeed2;
+
+ uint16 dseg_3A76;
+ uint16 _defaultTalkDelay;
+ uint16 _lightsValueA,_lightsValueB;
+ byte _haveMsg;
+ byte _newEffect;
+ uint16 _fullRedraw;
+ uint16 dseg_3DB6;
+ uint16 dseg_2456; /* lastDrawnRoom */
+ uint16 dseg_4E8A;
+ uint16 _soundParam,_soundParam2,_soundParam3;
+ uint16 dseg_4F8C;
+
+ byte _switchRoomEffect2, _switchRoomEffect;
+ uint16 dseg_4AC2;
+ uint16 dseg_4F8A;
+
+ uint16 _drawBmpX;
+ uint16 dseg_719E;
+ uint16 _drawBmpY;
+ uint16 dseg_4174;
+ byte dseg_4E3C;
+ uint16 _lastXstart;
+ uint16 dseg_4EA0;
+
+ bool _keepText;
+
+ int16 _talkDelay;
+ int16 _shakeMode;
+
+ int16 _virtual_mouse_x, _virtual_mouse_y;
+
+ byte _charsetColor;
+
+ uint32 _localScriptList[0x39];
+
+ uint16 _inventory[0x50];
+
+ uint16 _debugMode;
+
+ byte *_messagePtr;
+
+ byte _numNestedScripts;
+ byte _unkTabIndex;
+ byte _currentScript;
+
+ byte _currentRoom;
+ byte _numObjectsInRoom;
+ byte _actorToPrintStrFor;
+
+ int16 _screenStartStrip;
+ int16 _screenEndStrip;
+
+ int16 _scummTimer;
+
+ byte _playBackFile;
+ byte _fastMode;
+
+ uint16 _completeScreenRedraw;
+
+ byte _saveLoadFlag;
+
+ int8 _userPut;
+ int8 _cursorState;
+
+
+ uint16 _mouseButStat;
+ byte _leftBtnPressed, _rightBtnPressed;
+
+ int _numInMsgStack;
+
+ VerbSlot verbs[102];
+ VirtScreen virtscr[4];
+
+ uint32 _ENCD_offs, _EXCD_offs;
+ uint32 _CLUT_offs, _EPAL_offs;
+
+ int _drawObjectQueNr;
+ byte _drawObjectQue[0xC8];
+
+ uint16 _currentDrive;
+ uint16 _soundCardType;
+ uint16 _videoMode;
+ uint16 _heapSpace;
+ byte _mousePresent;
+
+ int16 _palManipStart;
+ int16 _palManipEnd;
+ int16 _palManipCounter;
+
+ struct {
+ byte mode[16];
+ uint16 num[16];
+ uint32 tags[16];
+ const char *name[16];
+ byte **address[16];
+ byte *flags[16];
+ byte *roomno[16];
+ uint32 *roomoffs[16];
+ } res;
+
+ struct {
+ int16 vars[801];
+ byte bitvars[256];
+ uint16 scriptoffs[180];
+ uint16 inventory[80];
+ uint32 cutScenePtr[5];
+ byte cutSceneScript[5];
+ int16 cutSceneData[5];
+ int16 cutSceneScriptIndex;
+ byte cutSceneStackPointer;
+ ScriptSlot slot[20];
+ NestedScript nest[15];
+ int16 localvar[20*17];
+ } vm;
+
+ struct {
+ int16 x,y;
+ } mouse;
+
+
+ struct {
+ int16 x[6];
+ int16 y[6];
+ int16 center[6];
+ int16 overhead[6];
+ int16 right[6];
+ int16 color[6];
+ int16 charset[6];
+ } textslot;
+
+ struct {
+ byte *readPtr;
+ uint16 readOffs;
+ uint16 drawY;
+ uint16 drawHeight;
+ uint16 drawWidth;
+ uint16 draw8xPos;
+ uint16 unk3;
+ int16 virtScreen;
+ uint16 drawBottom;
+ uint16 drawTop;
+
+ int8 unk4;
+
+ byte numLinesToProcess;
+ byte tempNumLines;
+ byte currentX;
+ byte hotspot_x;
+ byte hotspot_y;
+ int16 drawMouseX;
+ int16 drawMouseY;
+ byte currentCursor;
+ byte mouseColors[4];
+ byte mouseColor;
+ byte mouseClipMask1, mouseClipMask2, mouseClipMask3;
+ byte mouseColorIndex;
+ byte mouseMask[0x200];
+ byte *mouseMaskPtr;
+ byte *smap_ptr;
+ byte *bg_ptr;
+ byte *where_to_draw_ptr;
+ byte *mask_ptr;
+ byte *mask_ptr_dest;
+ byte *z_plane_ptr;
+
+ byte decomp_shr, decomp_mask;
+ byte transparency;
+ uint16 vertStripNextInc;
+ byte *backupIsWhere;
+ byte mouseBackup[16*24];
+ } gdi;
+
+ Actor actor[13];
+
+ uint16 actorDrawBits[160];
+
+ struct {
+ int upperLeftX;
+ int upperRightX;
+ int lowerLeftX;
+ int lowerRightX;
+ int upperLeftY;
+ int upperRightY;
+ int lowerLeftY;
+ int lowerRightY;
+ } box;
+
+ CharsetRenderer charset;
+
+ byte _charsetData[10][16];
+
+ byte _resourceMapper[128];
+
+ uint16 _resIndexToLoad, _resTypeToLoad;
+
+ byte **_lastCodePtr;
+ byte _dir;
+
+ int _numSoundTags;
+ byte *_soundTagTable;
+
+ int16 _bootParam;
+
+ uint32 _fileOffset;
+
+ byte _fileReadFailed;
+ byte _fileMode;
+
+ uint32 _whereInResToRead;
+
+ byte *_scriptPointer, *_scriptOrgPointer;
+ byte *_scriptPointerStart;
+ byte _opcode;
+
+ int _xPos, _yPos;
+
+ CameraData camera;
+
+ int _resultVarNumber;
+
+ uint16 _imgBufOffs[4];
+
+ byte _sentenceIndex;
+ byte _sentenceTab[6];
+ byte _sentenceTab2[6];
+ uint16 _sentenceTab3[6];
+ uint16 _sentenceTab4[6];
+ byte _sentenceTab5[6];
+
+ uint16 _stringOverhead[6];
+ uint16 _stringCenter[6];
+ uint16 _stringRight[6];
+ uint16 _stringColor[6];
+
+ int16 _stringXpos[6];
+ int16 _stringYpos[6];
+ uint16 _stringCharset[6];
+
+ int16 _stringXpos2[6];
+ int16 _stringYpos2[6];
+
+ CostumeRenderer cost;
+
+ ObjectData objs[184];
+
+ int16 _soundQuePos;
+ int16 _soundQue[0x100];
+
+ byte _soundQue2Pos;
+ byte _soundQue2[10];
+
+ int16 _vararg_temp_pos[16];
+
+ int16 _curExecScript;
+
+ int _scrWidthIn8Unit;
+ int _scrHeight;
+
+ uint32 _IM00_offs;
+
+ int _colorsInPalette;
+
+ byte _currentPalette[0x300];
+
+ int _palDirtyMin, _palDirtyMax;
+
+ byte _saveLoadData;
+
+ uint16 _colorCycleDelays[17];
+ uint16 _colorCycleCounter[17];
+ uint16 _colorCycleFlags[17];
+ byte _colorCycleStart[17];
+ byte _colorCycleEnd[17];
+
+ byte dseg_4E3B;
+
+ uint32 _findResSize, _findResHeaderSize;
+ byte *_findResPos;
+
+ uint32 _findResSize2, _findResHeaderSize2;
+ byte *_findResPos2;
+
+ bool _BgNeedsRedraw;
+
+ int _stringXPos[4], _stringYPos[4];
+
+ int16 _localParamList[16];
+
+ uint16 _verbMouseOver;
+
+ int16 _foundPathX;
+ int16 _foundPathY;
+
+ uint16 _onlyActorFlags;
+
+ uint16 _lastKeyHit;
+
+ int _scummStackPos;
+ int16 _scummStack[0x15];
+
+ int _maxBoxVertexHeap;
+ byte *_boxMatrixPtr4, *_boxMatrixPtr1, *_boxMatrixPtr3;
+ int _boxPathVertexHeapIndex;
+ int _boxMatrixItem;
+
+ /* all these can be made local */
+ byte *_msgPtrToAdd;
+
+ void openRoom(int room);
+ void deleteRoomOffsets();
+ void readRoomsOffsets();
+ void askForDisk();
+
+ void readIndexFile(int i);
+ bool openResourceFile(const char *filename);
+
+ void fileClose(void *file);
+ void *fileOpen(const char *filename, int mode);
+ void fileSeek(void *file, long offs, int whence);
+ void fileRead(void *handle, void *ptr, uint32 size);
+ bool fileEof(void *handle);
+
+ int fileReadByte();
+ uint32 fileReadDwordLE();
+ uint32 fileReadDwordBE();
+#if defined(SCUMM_LITTLE_ENDIAN)
+ uint32 fileReadDword() { return fileReadDwordLE(); }
+#elif defined(SCUMM_BIG_ENDIAN)
+ uint32 fileReadDword() { return fileReadDwordBE(); }
+#endif
+ uint fileReadWordLE();
+ uint fileReadWordBE();
+
+ byte *alloc(int size);
+ void free(void *mem);
+
+ void readResTypeList(int id, uint32 tag, const char *name);
+ void allocResTypeData(int id, uint32 tag, int num, const char *name, int mode);
+
+ void initThings();
+
+ void initVideoMode();
+ void initKbdAndMouse();
+ void detectSound();
+ void initRandSeeds();
+
+ uint getRandomNumber(uint max);
+
+ void loadCharset(int i);
+ void nukeCharset(int i);
+ void initScreens(int a, int b, int w, int h);
+
+ void setShake(int mode);
+ void setCursor(int cursor);
+
+ void clearDrawObjectQueue();
+
+ byte *createResource(int type, int index, uint32 size);
+
+ void initScummVars();
+ void getGraphicsPerformance();
+
+ void nukeResource(int type, int i);
+ byte *getResourceAddress(int type, int i);
+ void ensureResourceLoaded(int type, int i);
+ int loadResource(int type, int i);
+ int getResourceRoomNr(int type, int index);
+ int readSoundResource(int type, int index);
+ void setResourceFlags(int type, int index, byte flag);
+ void validateResource(const char *str, int type, int index);
+
+ void initVirtScreen(int slot, int top, int height, bool twobufs, bool fourextra);
+ void setDirtyRange(int slot, int a, int height);
+ void unkVirtScreen2();
+ void updateDirtyScreen(int slot);
+ void unkVirtScreen4(int a);
+ void unkVirtScreen5(int a);
+
+ void removeMouseCursor();
+
+ void showMouseCursor();
+ void drawStripToScreen();
+ void restoreMouse();
+ void initActor(Actor *a, int mode);
+ bool checkFixedDisk();
+
+ void setActorWalkSpeed(Actor *a, int speed1, int speed2);
+ int calcMovementFactor(Actor *a, int newx, int newy);
+ int actorWalkStep(Actor *a);
+ int getProgrDirChange(Actor *a, int mode);
+
+ bool checkXYInBoxBounds(int box, int x, int y);
+ void setupActorScale(Actor *a);
+
+ void checkRange(int max, int min, int no, const char *str);
+
+ bool fileReadFailed(void *handle);
+ void clearFileReadFailed(void *handle);
+
+ bool getClass(int obj, int cls);
+ void putClass(int obj, int cls, bool set);
+ int getState(int obj);
+ void putState(int obj, int state);
+ int getOwner(int obj);
+ void putOwner(int obj, int owner);
+
+ void main();
+
+ uint distanceFromPt(int x, int y, int ptx, int pty);
+ Point closestPtOnLine(int ulx, int uly, int llx, int lly, int x, int y);
+ bool getSideOfLine(int x1,int y1, int x2, int y2, int x, int y, int box);
+ void getBoxCoordinates(int box);
+ byte getMaskFromBox(int box);
+ Box *getBoxBaseAddr(int box);
+ byte getBoxFlags(int box);
+ int getBoxScale(int box);
+ byte getNumBoxes();
+ byte *getBoxMatrixBaseAddr();
+
+ void startAnimActor(Actor *a, int frame, byte direction);
+ void initActorCostumeData(Actor *a);
+ void fixActorDirection(Actor *a, byte direction);
+ void decodeCostData(Actor *a, int frame, uint mask);
+
+ void scummInit();
+ void scummMain();
+
+ void runScript(int script, int a, int b, int16 *lvarptr);
+ void stopScriptNr(int script);
+ int getScriptSlot();
+ void runScriptNested(int script);
+ void updateScriptPtr();
+ void getScriptBaseAddress();
+ void getScriptEntryPoint();
+ void executeScript();
+ byte fetchScriptByte();
+ int fetchScriptWord();
+ void ignoreScriptWord();
+ void ignoreScriptByte();
+ int getVarOrDirectWord(byte mask);
+ int getVarOrDirectByte(byte mask);
+ int readVar(uint var);
+ void getResultPos();
+ void setResult(int result);
+
+ int getObjectIndex(int object);
+
+ void o_actorFollowCamera();
+ void o_actorFromPos();
+ void o_actorSet();
+ void o_actorSetClass();
+ void o_add();
+ void o_and();
+ void o_animateActor();
+ void o_badOpcode();
+ void o_breakHere();
+ void o_chainScript();
+ void o_cursorCommand();
+ void o_cutscene();
+ void o_debug();
+ void o_decrement();
+ void o_delay();
+ void o_delayVariable();
+ void o_divide();
+ void o_doSentence();
+ void o_drawBox();
+ void o_drawObject();
+ void o_dummy();
+ void o_endCutscene();
+ void o_equalZero();
+ void o_expression();
+ void o_faceActor();
+ void o_findInventory();
+ void o_findObject();
+ void o_freezeScripts();
+ void o_getActorCostume();
+ void o_getActorElevation();
+ void o_getActorFacing();
+ void o_getActorMoving();
+ void o_getActorRoom();
+ void o_getActorScale();
+ void o_getActorWalkBox();
+ void o_getActorWidth();
+ void o_getActorX();
+ void o_getActorY();
+ void o_getAnimCounter();
+ void o_getClosestObjActor();
+ void o_getDist();
+ void o_getInventoryCount();
+ void o_getObjectOwner();
+ void o_getObjectState();
+ void o_getRandomNr();
+ void o_getScriptRunning();
+ void o_getVerbEntrypoint();
+ void o_ifClassOfIs();
+ void o_increment();
+ void o_isActorInBox();
+ void o_isEqual();
+ void o_isGreater();
+ void o_isGreaterEqual();
+ void o_isLess();
+ void o_isNotEqual();
+ void o_isSoundRunning();
+ void o_jumpRelative();
+ void o_lessOrEqual();
+ void o_lights();
+ void o_loadRoom();
+ void o_loadRoomWithEgo();
+ void o_matrixOps();
+ void o_move();
+ void o_multiply();
+ void o_notEqualZero();
+ void o_or();
+ void o_overRide();
+ void o_panCameraTo();
+ void o_pickupObject();
+ void o_print();
+ void o_printEgo();
+ void o_pseudoRoom();
+ void o_putActor();
+ void o_putActorAtObject();
+ void o_putActorInRoom();
+ void o_quitPauseRestart();
+ void o_resourceRoutines();
+ void o_roomOps();
+ void o_saveRestoreVerbs();
+ void o_setCameraAt();
+ void o_setObjectName();
+ void o_setOwnerOf();
+ void o_setState();
+ void o_setVarRange();
+ void o_soundKludge();
+ void o_startMusic();
+ void o_startObject();
+ void o_startScript();
+ void o_startSound();
+ void o_stopMusic();
+ void o_stopObjectCode();
+ void o_stopObjectScript();
+ void o_stopScript();
+ void o_stopSound();
+ void o_stringOps();
+ void o_subtract();
+ void o_verbOps();
+ void o_wait();
+ void o_walkActorTo();
+ void o_walkActorToActor();
+ void o_walkActorToObject();
+
+ void stopObjectCode();
+ void stopObjectScript(int script);
+ void putActor(Actor *a, int x, int y, byte room);
+ void clearMsgQueue();
+ void adjustActorPos(Actor *a);
+
+ void hideActor(Actor *a);
+ void showActor(Actor *a);
+ void showActors();
+ void turnToDirection(Actor *a, int newdir);
+
+ int whereIsObject(int object);
+ int getObjectOrActorXY(int object);
+ void addSoundToQueue(int sound);
+ void addSoundToQueue2(int sound);
+ bool isScriptLoaded(int script);
+ int getActorXYPos(Actor *a);
+ void getObjectXYPos(int object);
+ AdjustBoxResult adjustXYToBeInBox(Actor *a, int x, int y);
+
+ int getWordVararg(int16 *ptr);
+
+ int getObjActToObjActDist(int a, int b);
+ void unkSoundProc22();
+ bool inBoxQuickReject(int box, int x, int y, int threshold);
+ AdjustBoxResult getClosestPtOnBox(int box, int x, int y);
+
+ void setCameraAt(int dest);
+ void stopTalk();
+ void restoreCharsetBg();
+
+ void setCameraFollows(Actor *a);
+ void runHook(int i);
+ void startScene(int room, Actor *a, int b);
+
+ void freezeScripts(int scr);
+ void unfreezeScripts();
+
+ void runAllScripts();
+
+ int findObject(int x, int y);
+ void stopCycle(int i);
+ void killScriptsAndResources();
+ void runExitScript();
+ void runEntryScript();
+
+ void unkResourceProc();
+ void initRoomSubBlocks();
+ void loadRoomObjects();
+
+ void setPaletteFromRes();
+ void initCycl(byte *ptr);
+ void initBGBuffers();
+ void setDirtyColors(int min, int max);
+
+ byte *findResource(uint32 tag, byte *searchin);
+ byte *findResource2(uint32 tag, byte *searchin);
+
+ void setScaleItem(int slot, int a, int b, int c, int d);
+
+ void cyclePalette();
+
+ void moveMemInPalRes(int start, int end, byte direction);
+
+ void redrawBGAreas();
+ void drawRoomObjects(int arg);
+ void redrawBGStrip(int start, int num);
+ void drawObject(int obj, int arg);
+
+ void drawBmp(byte *ptr, int a, int b, int c, const char *str, int objnr);
+ void decompressBitmap();
+ int hasCharsetMask(int x, int y, int x2, int y2);
+ void draw8ColWithMasking();
+ void clear8ColWithMasking();
+ void clear8Col();
+ void decompressMaskImgOr();
+ void decompressMaskImg();
+
+ void GDI_UnkDecode1();
+ void GDI_UnkDecode2();
+ void GDI_UnkDecode3();
+ void GDI_UnkDecode4();
+ void GDI_UnkDecode5();
+ void GDI_UnkDecode6();
+ void GDI_UnkDecode7();
+
+ void restoreBG(int left, int top, int right, int bottom);
+ void updateDirtyRect(int virt, int left, int right, int top, int bottom, uint16 dirtybits);
+ int findVirtScreen(int y);
+
+ void unkScreenEffect6();
+ void unkScreenEffect5(int a);
+
+ void playSound(int sound);
+
+ void decreaseScriptDelay(int amount);
+ void processKbd();
+
+ void clearUpperMask();
+ void redrawVerbs();
+ void checkExecVerbs();
+ void checkAndRunVar33();
+ void CHARSET_1();
+ void walkActors();
+ void moveCamera();
+ void fixObjectFlags();
+ void clear_fullRedraw();
+ void palManipulate();
+ void screenEffect(int effect);
+ void clearClickedStatus();
+ void verbMouseOver(int verb);
+ int checkMouseOver(int x, int y);
+ void playActorSounds();
+ void processDrawQue();
+ void setActorRedrawFlags();
+ void resetActorBgs();
+ void processActors();
+ void drawVerb(int verb, int mode);
+
+ void runInputScript(int a, int cmd, int mode);
+
+ void cameraMoved();
+
+ void walkActor(Actor *a);
+
+ int checkKeyHit();
+
+ int getPathToDestBox(int from, int to);
+ int findPathTowards(Actor *a, int box, int box2, int box3);
+
+ void setActorCostPalette(Actor *a);
+ void drawActorCostume(Actor *a);
+ void actorAnimate(Actor *a);
+
+ int getActorFromPos(int x, int y);
+
+ void restoreVerbBG(int verb);
+
+ void drawString(int a);
+ void drawVerbBitmap(int vrb, int x, int y);
+
+ void setActorCostume(Actor *a, int c);
+ void loadPtrToResource(int type, int i, byte *ptr);
+
+ void stackPush(int a);
+ int stackPop();
+
+ void walkActorTo(Actor *a, int x, int y, int direction);
+
+ void setCursorImg(int cursor, int img);
+ void setCursorHotspot(int cursor, int x, int y);
+ void initCharset(int charset);
+ void addObjectToDrawQue(int object);
+ int getVerbEntrypoint(int obj, int entry);
+ int unkSoundProc23(int a);
+ void startWalkActor(Actor *a, int x, int y, int dir);
+ void setBoxFlags(int box, int val);
+ void setBoxScale(int box, int b);
+ void createBoxMatrix();
+ void addObjectToInventory(int obj, int room);
+ void removeObjectFromRoom(int obj);
+ void decodeParseString();
+ void pauseGame(int i);
+ void shutDown(int i);
+ void lock(int type, int i);
+ void unlock(int type, int i);
+ void heapClear(int mode);
+ void unkHeapProc2(int a, int b);
+ void unkResProc(int a, int b);
+ void setPalColor(int index, int r, int g, int b);
+ void unkRoomFunc2(int a, int b, int c, int d, int e);
+ void unkRoomFunc3(int a, int b, int c, int d, int e);
+ void unkRoomFunc4(int a, int b, int c, int d, int e);
+ int getVerbSlot(int id, int mode);
+ void killVerb(int slot);
+ byte *getObjectAddress(int obj);
+ byte *getObjOrActorName(int obj);
+ void clearOwnerOf(int obj);
+ void runVERBCode(int script, int entry, int a, int b, int16 *vars);
+ void unkSoundProc1(int a);
+ void setVerbObject(int room, int object, int verb);
+ void unkMessage1();
+ void unkMessage2();
+ void actorTalk();
+
+ byte *addMessageToStack(byte *msg);
+
+ void unkAddMsgToStack2(int var);
+ void unkAddMsgToStack3(int var);
+ void unkAddMsgToStack4(int var);
+ void unkAddMsgToStack5(int var);
+
+ byte *getActorName(Actor *a);
+ uint32 getOBCDOffs(int object);
+
+ byte isMaskActiveAt(int l, int t, int r, int b, byte *mem);
+
+ int getInventorySlot();
+
+
+ int getKeyInput(int a);
+ void convertKeysToClicks();
+
+ OpcodeProc getOpcode(int i);
+
+ void drawBox(int x, int y, int x2, int y2, int color);
+
+ void drawMouse();
+
+ void GDI_drawMouse();
+ void GDI_removeMouse();
+
+ void dumpResource(char *tag, int index, byte *ptr);
+
+ FILE *_saveLoadStream;
+ bool _saveOrLoad;
+ bool saveState(const char *filename);
+ bool loadState(const char *filename);
+ void saveOrLoad(FILE *inout, bool mode);
+ void saveLoadBytes(void *b, int len);
+
+ Actor *derefActor(int id) { return &actor[id]; }
+ Actor *derefActorSafe(int id, const char *errmsg);
+ Actor *getFirstActor() { return actor; }
+
+ void setupCostumeRenderer(CostumeRenderer *c, Actor *a);
+
+ PathVertex *unkMatrixProc1(PathVertex *vtx, PathNode *node);
+ PathNode *unkMatrixProc2(PathVertex *vtx, int i);
+ bool areBoxesNeighbours(int i, int j);
+ void addToBoxMatrix(byte b);
+ PathVertex *addPathVertex();
+ void *addToBoxVertexHeap(int size);
+};
+
+void waitForTimer(Scumm *s);
+void outputdisplay2(Scumm *s, int disp);
+extern const byte revBitMask[8];
+void blitToScreen(Scumm *s, byte *src, int x, int y, int w, int h);
+
+void NORETURN CDECL error(const char *s, ...);
+void CDECL warning(const char *s, ...);
+void CDECL debug(int level, const char *s, ...);
+void checkHeap();
+
+void updateScreen(Scumm *s);
diff --git a/scummsys.h b/scummsys.h
new file mode 100644
index 0000000000..ae91e1e3e5
--- /dev/null
+++ b/scummsys.h
@@ -0,0 +1,152 @@
+/* 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.
+ *
+ * Change Log:
+ * $Log$
+ * Revision 1.1 2001/10/09 14:30:14 strigeus
+ * Initial revision
+ *
+ *
+ */
+
+#if defined(WIN32)
+
+#define SCUMM_LITTLE_ENDIAN
+
+#define FORCEINLINE __forceinline
+#define NORETURN _declspec(noreturn)
+
+typedef unsigned char byte;
+typedef unsigned char uint8;
+typedef unsigned short uint16;
+typedef unsigned long uint32;
+typedef unsigned int uint;
+typedef signed char int8;
+typedef signed short int16;
+typedef signed long int32;
+
+#define START_PACK_STRUCTS pack (push,1)
+#define END_PACK_STRUCTS pack(pop)
+
+#elif defined(UNIX)
+
+#define FORCEINLINE inline
+#define NORETURN
+#define CDECL
+
+typedef unsigned char byte;
+typedef unsigned char uint8;
+typedef unsigned short uint16;
+typedef unsigned long uint32;
+typedef unsigned int uint;
+typedef signed char int8;
+typedef signed short int16;
+typedef signed long int32;
+
+#define START_PACK_STRUCTS pack (1)
+#define END_PACK_STRUCTS pack ()
+
+#else
+#error No system type defined
+#endif
+
+
+#if defined(SCUMM_LITTLE_ENDIAN)
+
+#if defined(SCUMM_NEED_ALIGNMENT)
+#error Little endian processors that need alignment is not implemented
+#endif
+
+#define MKID(a) ((((a)>>24)&0xFF) | (((a)>>8)&0xFF00) | (((a)<<8)&0xFF0000) | (((a)<<24)&0xFF000000))
+
+int FORCEINLINE READ_LE_UINT16(void *ptr) {
+ return *(uint16*)(ptr);
+}
+
+int FORCEINLINE READ_BE_UINT16(void *ptr) {
+ return (((byte*)ptr)[0]<<8)|((byte*)ptr)[1];
+}
+
+uint32 FORCEINLINE READ_LE_UINT32(void *ptr) {
+ return *(uint32*)(ptr);
+}
+
+uint32 FORCEINLINE READ_BE_UINT32(void *ptr) {
+ byte *b = (byte*)ptr;
+ return (b[0]<<24)+(b[1]<<16)+(b[2]<<8)+(b[3]);
+}
+
+#define READ_BE_UINT32_UNALIGNED READ_BE_UINT32
+#define READ_BE_UINT16_UNALIGNED READ_BE_UINT16
+
+#define READ_UINT32_UNALIGNED(a) (*((uint32*)a))
+
+#define FROM_LE_32(__a__) __a__
+#define FROM_LE_16(__a__) __a__
+
+#define TO_BE_32(a) ((((a)>>24)&0xFF) | (((a)>>8)&0xFF00) | (((a)<<8)&0xFF0000) | (((a)<<24)&0xFF000000))
+
+#elif defined(SCUMM_BIG_ENDIAN)
+
+#define MKID(a) (a)
+
+uint32 FORCEINLINE FROM_LE_32(uint32 a) {
+ return ((a>>24)&0xFF) + ((a>>8)&0xFF00) + ((a<<8)&0xFF0000) + ((a<<24)&0xFF000000);
+}
+
+uint16 FORCEINLINE FROM_LE_16(uint16 a) {
+ return ((a>>8)&0xFF) + ((a<<8)&0xFF00);
+}
+
+uint32 FORCEINLINE READ_LE_UINT32(void *ptr) {
+ byte *b = (byte*)ptr;
+ return (b[3]<<24)+(b[2]<<16)+(b[1]<<8)+(b[0]);
+}
+
+uint32 FORCEINLINE READ_BE_UINT32(void *ptr) {
+ return *(uint32*)(ptr);
+}
+
+int FORCEINLINE READ_LE_UINT16(void *ptr) {
+ byte *b = (byte*)ptr;
+ return (b[1]<<8) + b[0];
+}
+
+int FORCEINLINE READ_BE_UINT16(void *ptr) {
+ return *(uint16*)(ptr);
+}
+
+int FORCEINLINE READ_BE_UINT16_UNALIGNED(void *ptr) {
+ return (((byte*)ptr)[0]<<8)|((byte*)ptr)[1];
+}
+
+
+uint32 FORCEINLINE READ_BE_UINT32_UNALIGNED(void *ptr) {
+ byte *b = (byte*)ptr;
+ return (b[0]<<24)+(b[1]<<16)+(b[2]<<8)+(b[3]);
+}
+
+#define READ_UINT32_UNALIGNED READ_BE_UINT32_UNALIGNED
+
+#define TO_BE_32(a) (a)
+
+#else
+
+#error No endianness defined
+
+#endif
+
diff --git a/scummvm.cpp b/scummvm.cpp
new file mode 100644
index 0000000000..5e5de9a0fa
--- /dev/null
+++ b/scummvm.cpp
@@ -0,0 +1,810 @@
+/* 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.
+ *
+ * Change Log:
+ * $Log$
+ * Revision 1.1 2001/10/09 14:30:13 strigeus
+ * Initial revision
+ *
+ *
+ */
+
+#include "stdafx.h"
+#include "scumm.h"
+
+void Scumm::initThings() {
+ readIndexFile(1);
+
+ allocResTypeData(5, MKID('NONE'), 0x50, "inventory", 0);
+ allocResTypeData(12,MKID('NONE'),10, "temp", 0);
+ allocResTypeData(11,MKID('NONE'),5, "scale table", 0);
+ allocResTypeData(9, MKID('NONE'),13,"actor name", 0);
+ allocResTypeData(10, MKID('NONE'),10,"buffer", 0);
+ allocResTypeData(8, MKID('NONE'),100,"verb", 0);
+ allocResTypeData(7, MKID('NONE'),0x32,"string", 0);
+ allocResTypeData(13, MKID('NONE'),0x32,"flobject", 0);
+ allocResTypeData(14, MKID('NONE'),10,"boxes", 0);
+
+ readIndexFile(2);
+
+ initVideoMode();
+ initKbdAndMouse();
+ detectSound();
+
+ initRandSeeds();
+}
+
+void Scumm::initVideoMode() {
+}
+
+void Scumm::initKbdAndMouse() {
+}
+
+void Scumm::detectSound() {
+}
+
+void Scumm::initRandSeeds() {
+ _randSeed1 = 0xA943DE35;
+ _randSeed2 = 0x37A9ED27;
+}
+
+uint Scumm::getRandomNumber(uint max) {
+ /* TODO: my own random number generator */
+ _randSeed1 = 0xDEADBEEF * (_randSeed1 + 1);
+ _randSeed1 = (_randSeed1>>13) | (_randSeed1<<19);
+ return _randSeed1%(max+1);
+}
+
+void Scumm::scummInit() {
+ int i;
+ Actor *a;
+
+ debug(9, "scummInit");
+ readIndexFile(3);
+ loadCharset(1);
+ initScreens(0, 16, 320, 144);
+
+ setShake(0);
+ setCursor(0);
+
+ for (i=1,a=getFirstActor(); ++a,i<13; i++) {
+ a->number = i;
+ initActor(a, 1);
+ }
+
+ memset(vm.vars, 0, sizeof(vm.vars));
+ memset(vm.bitvars, 0, sizeof(vm.bitvars));
+ memset(vm.scriptoffs, 0, sizeof(vm.scriptoffs));
+ memset(vm.inventory, 0, sizeof(vm.inventory));
+
+ _defaultTalkDelay = 60;
+ vm.vars[37] = 4;
+
+ _numNestedScripts = 0;
+ vm.cutSceneStackPointer = 0;
+
+ memset(vm.cutScenePtr, 0, sizeof(vm.cutScenePtr));
+ memset(vm.cutSceneData, 0, sizeof(vm.cutSceneData));
+
+ for (i=0; i<_maxVerbs; i++) {
+ verbs[i].verbid = 0;
+ verbs[i].right = 319;
+ verbs[i].oldleft = -1;
+ verbs[i].type = 0;
+ verbs[i].color = 2;
+ verbs[i].hicolor = 0;
+ verbs[i].charset_nr = 1;
+ verbs[i].curmode = 0;
+ verbs[i].saveid = 0;
+ verbs[i].center=0;
+ verbs[i].key = 0;
+ }
+
+ camera._leftTrigger = 10;
+ camera._rightTrigger = 30;
+ camera._mode = 0;
+ camera._follows = 0;
+
+
+ virtscr[0].xstart = 0;
+
+ vm.vars[9] = 11;
+
+ _lightsValueA = _lightsValueB = 7;
+
+ vm.vars[59] = 3;
+
+ mouse.x = 104;
+ mouse.y = 56;
+
+ _ENCD_offs = 0;
+ _EXCD_offs = 0;
+
+ _unkTabIndex = 0xFF;
+ _currentScript = 0xFF;
+
+ _currentRoom = 0;
+ _numObjectsInRoom = 0;
+ _actorToPrintStrFor = 0;
+
+ charset._bufPos = 0;
+ _haveMsg = 0;
+
+ _screenStartStrip = 0;
+
+ vm.vars[25] = 0;
+
+ _talkDelay = 0;
+ _keepText = false;
+
+ _cursorState = 0;
+ _userPut = 0;
+
+ _newEffect = 129;
+ _fullRedraw = 1;
+
+ clearDrawObjectQueue();
+
+ for (i=0; i<6; i++) {
+ textslot.x[i] = 2;
+ textslot.y[i] = 5;
+ textslot.right[i] = 319;
+ textslot.color[i] = 0xF;
+ textslot.center[i] = 0;
+ textslot.charset[i] = 0;
+ }
+
+ _numInMsgStack = 0;
+
+ createResource(0xC, 6, 500);
+
+ initScummVars();
+
+ vm.vars[54] = -0x50;
+
+ getGraphicsPerformance();
+}
+
+
+void Scumm::initScummVars() {
+ vm.vars[VAR_CURRENTDRIVE] = _currentDrive;
+ vm.vars[VAR_FIXEDDISK] = checkFixedDisk();
+ vm.vars[VAR_SOUNDCARD] = _soundCardType;
+ vm.vars[VAR_VIDEOMODE] = _videoMode;
+ vm.vars[VAR_HEAPSPACE] = _heapSpace;
+ vm.vars[VAR_MOUSEPRESENT] = _mousePresent;
+ vm.vars[VAR_SOUNDPARAM] = _soundParam;
+ vm.vars[VAR_SOUNDPARAM2] = _soundParam2;
+ vm.vars[VAR_SOUNDPARAM3] = _soundParam3;
+}
+
+void Scumm::checkRange(int max, int min, int no, const char *str) {
+ if (no < min || no > max) {
+ error("Value %d is out of bounds (%d,%d) msg %s", no, min,max, str);
+ }
+}
+
+void Scumm::scummMain() {
+ int tmr, i;
+ Actor *a;
+
+ charset._vm = this;
+ cost._vm = this;
+
+ _exe_name = "monkey2";
+
+ _fileHandle = NULL;
+
+ _bootParam = 0;
+ _debugMode = 1;
+
+ initThings();
+ scummInit();
+
+ vm.vars[VAR_VERSION] = 21;
+ vm.vars[VAR_DEBUGMODE] = _debugMode;
+
+ runScript(1,0,0,&_bootParam);
+ _scummTimer = 0;
+
+ do {
+ if (_playBackFile) {
+ while ((_scummTimer>>2) < vm.vars[VAR_PLAYBACKTIMER]) {}
+ _scummTimer = vm.vars[VAR_PLAYBACKTIMER] << 2;
+ }
+
+ updateScreen(this);
+
+ vm.vars[VAR_TIMER] = _scummTimer >> 2;
+ do {
+ waitForTimer(this);
+ tmr = _scummTimer >> 2;
+ if (_fastMode)
+ tmr += 15;
+ } while (tmr < vm.vars[VAR_TIMER_NEXT]);
+ _scummTimer = 0;
+
+ vm.vars[VAR_TMR_1] += tmr;
+ vm.vars[VAR_TMR_2] += tmr;
+ vm.vars[VAR_TMR_3] += tmr;
+ vm.vars[VAR_TMR_4] += tmr;
+
+ if (tmr > 15)
+ tmr = 15;
+
+ decreaseScriptDelay(tmr);
+
+ _talkDelay -= tmr;
+ if (_talkDelay<0) _talkDelay=0;
+
+ processKbd();
+
+ /* XXX: memory low check skipped */
+ vm.vars[VAR_CAMERA_CUR_POS] = camera._curPos;
+ vm.vars[VAR_HAVE_MSG] = _haveMsg;
+ vm.vars[VAR_VIRT_MOUSE_X] = _virtual_mouse_x;
+ vm.vars[VAR_VIRT_MOUSE_Y] = _virtual_mouse_y;
+ vm.vars[VAR_MOUSE_X] = mouse.x;
+ vm.vars[VAR_MOUSE_Y] = mouse.y;
+ vm.vars[VAR_DEBUGMODE] = _debugMode;
+
+ if (_saveLoadFlag) {
+ error("Loading/saving not implemented");
+ }
+
+ if (_completeScreenRedraw) {
+ _completeScreenRedraw = 0;
+ clearUpperMask();
+ charset._hasMask = false;
+ redrawVerbs();
+ _fullRedraw = 1;
+ for (i=0,a=getFirstActor(); i<13; i++,a++)
+ a->needRedraw = 1;
+ }
+
+ runAllScripts();
+ checkExecVerbs();
+ checkAndRunVar33();
+
+ if (_currentRoom==0) {
+ gdi.unk4 = 0;
+ CHARSET_1();
+ unkVirtScreen2();
+ unkSoundProc22();
+ camera._lastPos = camera._curPos;
+ continue;
+ }
+
+ walkActors();
+ moveCamera();
+ fixObjectFlags();
+ CHARSET_1();
+ if (camera._curPos != camera._lastPos || _BgNeedsRedraw || _fullRedraw) {
+ redrawBGAreas();
+ }
+ processDrawQue();
+ setActorRedrawFlags();
+ resetActorBgs();
+
+ if (!(vm.vars[VAR_DRAWFLAGS]&2) && vm.vars[VAR_DRAWFLAGS]&4) {
+ error("Flashlight not implemented in this version");
+ }
+
+ processActors(); /* process actors makes the heap invalid */
+ clear_fullRedraw();
+ cyclePalette();
+ palManipulate();
+
+ if (dseg_4F8A) {
+ screenEffect(_newEffect);
+ dseg_4F8A = 0;
+ clearClickedStatus();
+ }
+
+ if (_cursorState > 0) {
+ verbMouseOver(checkMouseOver(mouse.x, mouse.y));
+ }
+
+ gdi.unk4 = _cursorState > 0;
+
+ unkVirtScreen2();
+
+ playActorSounds();
+ unkSoundProc22();
+ camera._lastPos = camera._curPos;
+ } while (1);
+}
+
+void Scumm::startScene(int room, Actor *a, int objectNr) {
+ int i;
+ Actor *at;
+
+ checkHeap();
+
+ removeMouseCursor();
+ clearMsgQueue();
+
+ unkVirtScreen4(_switchRoomEffect2);
+ _newEffect = _switchRoomEffect;
+
+ if (_currentScript!=0xFF) {
+ if (vm.slot[_currentScript].type==1 || vm.slot[_currentScript].type==4) {
+ if(vm.slot[_currentScript].cutsceneOverride!=0)
+ error("Object %d stopped with active cutscene/override in exit", vm.slot[_currentScript].number);
+ _currentScript = 0xFF;
+ } else if (vm.slot[_currentScript].type==3) {
+ if (vm.slot[_currentScript].cutsceneOverride!=0)
+ error("Script %d stopped with active cutscene/override in exit", vm.slot[_currentScript].number);
+ _currentScript = 0xFF;
+ }
+ }
+
+ vm.vars[VAR_NEW_ROOM] = room;
+ runExitScript();
+ killScriptsAndResources();
+ stopCycle(0);
+
+ for(i=1,at=getFirstActor(); ++at,i<13; i++) {
+ if (at->visible)
+ hideActor(at);
+ }
+
+ for (i=0; i<0x100; i++)
+ cost._transEffect[i] = i;
+
+ clearDrawObjectQueue();
+
+ vm.vars[VAR_ROOM] = room;
+ _fullRedraw = 1;
+
+ _roomResource = _currentRoom = 0xFF;
+
+ unkResourceProc();
+
+ _currentRoom = room;
+ vm.vars[VAR_ROOM] = room;
+
+ if (room >= 0x80)
+ _roomResource = _resourceMapper[room&0x7F];
+ else
+ _roomResource = room;
+
+ vm.vars[VAR_ROOM_RESOURCE] = _roomResource;
+
+ if (room!=0)
+ ensureResourceLoaded(1, room);
+
+ if (_currentRoom == 0) {
+ _ENCD_offs = _EXCD_offs = 0;
+ _numObjectsInRoom = 0;
+ return;
+ }
+
+ initRoomSubBlocks();
+
+ loadRoomObjects();
+
+ camera._mode = 1;
+ camera._curPos = camera._destPos = 160;
+
+ if (_roomResource == 0)
+ return;
+
+ vm.vars[VAR_CAMERA_MAX] = (_scrWidthIn8Unit<<3) - 160;
+ vm.vars[VAR_CAMERA_MIN] = 160;
+
+ memset(actorDrawBits, 0, sizeof(actorDrawBits));
+
+ if (a) {
+ if (whereIsObject(objectNr)!=1 &&
+ whereIsObject(objectNr)!=4)
+ error("startScene: Object %d is not in room %d", objectNr, _currentRoom);
+ getObjectXYPos(objectNr);
+ putActor(a, _xPos, _yPos, _currentRoom);
+ startAnimActor(a, 0x3E, _dir^1);
+ a->moving = 0;
+ }
+
+ showActors();
+ dseg_3A76 = 0;
+ runEntryScript();
+
+
+ if (a && dseg_3A76==0) {
+ getObjectXYPos(objectNr);
+ putActor(a, _xPos, _yPos, _currentRoom);
+ a->moving = 0;
+ }
+
+ dseg_4F8A = 1;
+
+ checkHeap();
+}
+
+void Scumm::initRoomSubBlocks() {
+ int i,offs;
+ byte *ptr;
+ byte *roomptr;
+
+ _ENCD_offs = 0;
+ _EXCD_offs = 0;
+
+ nukeResource(0xE, 1);
+ nukeResource(0xE, 2);
+
+ for (i=1; i<_maxScaleTable; i++)
+ nukeResource(0xB, i);
+
+ roomptr = getResourceAddress(1, _roomResource);
+
+ ptr = findResource(MKID('RMHD'), roomptr);
+ _scrWidthIn8Unit = READ_LE_UINT16(&((RoomHeader*)ptr)->width) >> 3;
+ _scrHeight = READ_LE_UINT16(&((RoomHeader*)ptr)->height);
+
+ _IM00_offs = findResource(MKID('IM00'), findResource(MKID('RMIM'), roomptr)) -
+ roomptr;
+
+ ptr = findResource(MKID('EXCD'), roomptr);
+ if (ptr) {
+ _EXCD_offs = ptr - roomptr;
+#ifdef DUMP_SCRIPTS
+ dumpResource("exit-", _roomResource, ptr);
+#endif
+ }
+
+ ptr = findResource(MKID('ENCD'), roomptr);
+ if (ptr) {
+ _ENCD_offs = ptr - roomptr;
+#ifdef DUMP_SCRIPTS
+ dumpResource("entry-", _roomResource, ptr);
+#endif
+ }
+
+ ptr = findResource(MKID('BOXD'), roomptr);
+ if (ptr) {
+ int size = READ_BE_UINT32_UNALIGNED(ptr+4);
+ createResource(0xE, 2, size);
+ roomptr = getResourceAddress(1, _roomResource);
+ ptr = findResource(MKID('BOXD'), roomptr);
+ memcpy(getResourceAddress(0xE, 2), ptr, size);
+ }
+
+ ptr = findResource(MKID('BOXM'), roomptr);
+ if (ptr) {
+ int size = READ_BE_UINT32_UNALIGNED(ptr+4);
+ createResource(0xE, 1, size);
+ roomptr = getResourceAddress(1, _roomResource);
+ ptr = findResource(MKID('BOXM'), roomptr);
+ memcpy(getResourceAddress(0xE, 1), ptr, size);
+ }
+
+ ptr = findResource(MKID('SCAL'), roomptr);
+ if (ptr) {
+ offs = ptr - roomptr;
+ for (i=1; i<_maxScaleTable; i++, offs+=8) {
+ int a = READ_LE_UINT16(roomptr + offs + 8);
+ int b = READ_LE_UINT16(roomptr + offs + 10);
+ int c = READ_LE_UINT16(roomptr + offs + 12);
+ int d = READ_LE_UINT16(roomptr + offs + 14);
+ if (a || b || c || d) {
+ setScaleItem(i, b, a, d, c);
+ roomptr = getResourceAddress(1, _roomResource);
+ }
+ }
+ }
+ memset(_localScriptList, 0, (0x100 - _numGlobalScriptsUsed) * 4);
+
+ roomptr = getResourceAddress(1, _roomResource);
+ ptr = findResource(MKID('LSCR'), roomptr);
+ while (ptr) {
+ _localScriptList[ptr[8] - _numGlobalScriptsUsed] = ptr - roomptr;
+
+#ifdef DUMP_SCRIPTS
+ do {
+ char buf[32];
+ sprintf(buf,"room-%d-",_roomResource);
+ dumpResource(buf, ptr[8], ptr);
+ } while (0);
+#endif
+
+ ptr = findResource(MKID('LSCR'), NULL);
+ }
+
+ _CLUT_offs = findResource(MKID('CLUT'), roomptr) - roomptr;
+ ptr = findResource(MKID('EPAL'), roomptr);
+ if (ptr)
+ _EPAL_offs = ptr - roomptr;
+
+ setPaletteFromRes();
+ initCycl(findResource(MKID('CYCL'), roomptr) + 8);
+
+ ptr = findResource(MKID('TRNS'), roomptr);
+ if (ptr)
+ gdi.transparency = ptr[8];
+ else
+ gdi.transparency = 255;
+
+ initBGBuffers();
+}
+
+void Scumm::setScaleItem(int slot, int a, int b, int c, int d) {
+ byte *ptr;
+ int cur,amounttoadd,i,tmp;
+
+ ptr = createResource(0xB, slot, 200);
+
+ if (a==c)
+ return;
+
+ cur = (b-d)*a;
+ amounttoadd = d - b;
+
+ for (i=200; i>0; i--) {
+ tmp = cur / (c - a) + b;
+ if (tmp<1) tmp=1;
+ if (tmp>255) tmp=255;
+ *ptr++ = tmp;
+ cur += amounttoadd;
+ }
+}
+
+void Scumm::dumpResource(char *tag, int index, byte *ptr) {
+ char buf[256];
+ FILE *out;
+
+ return;
+
+ uint32 size = READ_BE_UINT32_UNALIGNED(ptr+4);
+
+ sprintf(buf, "d:\\monkey2\\dumps\\%s%d.dmp", tag,index);
+
+ out = fopen(buf,"rb");
+ if (!out) {
+ out = fopen(buf, "wb");
+ if (!out)
+ return;
+ fwrite(ptr, size, 1, out);
+ }
+ fclose(out);
+}
+
+
+void Scumm::clear_fullRedraw() {
+ _fullRedraw = 0;
+}
+
+void Scumm::clearClickedStatus() {
+ checkKeyHit();
+ _mouseButStat = 0;
+ _leftBtnPressed = 0;
+ _rightBtnPressed = 0;
+}
+
+int Scumm::checkKeyHit() {
+ int a = _keyPressed;
+ _keyPressed = 0;
+ return a;
+}
+
+void Scumm::unkRoomFunc3(int a, int b, int c, int d, int e) {
+ warning("stub unkRoomFunc3(%d,%d,%d,%d,%d)",a,b,c,d,e);
+}
+
+void Scumm::unkRoomFunc2(int a, int b, int c, int d, int e) {
+ byte *cptr, *cur;
+ int num;
+ byte color;
+
+ if (_videoMode==0xE) {
+ warning("stub unkRoomFunc2(%d,%d,%d,%d,%d)",a,b,c,d,e);
+ }
+
+ if (_videoMode==0x13) {
+ cptr = getResourceAddress(1, _roomResource) + _CLUT_offs + 8 + a*3;
+ cur = _currentPalette + a*3;
+ if (a <= b) {
+ num = b - a + 1;
+
+ do {
+ if (c != 0xFF) {
+ color = *cptr++ * (c>>2) / 0xFF;
+ } else {
+ color = *cptr++ >> 2;
+ }
+ if(color>63) color = 63;
+ *cur++=color;
+
+ if (d != 0xFF) {
+ color = *cptr++ * (d>>2) / 0xFF;
+ } else {
+ color = *cptr++ >> 2;
+ }
+ if(color>63) color = 63;
+ *cur++=color;
+
+ if (e != 0xFF) {
+ color = *cptr++ * (e>>2) / 0xFF;
+ } else {
+ color = *cptr++ >> 2;
+ }
+ if(color>63) color = 63;
+ *cur++=color;
+ } while (--num);
+ }
+ setDirtyColors(a,b);
+ }
+}
+
+
+void Scumm::unkRoomFunc4(int a, int b, int c, int d, int e) {
+ /* TODO: implement this */
+ warning("unkRoomFunc4: not implemented");
+}
+
+
+void Scumm::pauseGame(int i) {
+ /* TODO: implement this */
+ warning("pauseGame: not implemented");
+}
+
+void Scumm::shutDown(int i) {
+ /* TODO: implement this */
+ warning("shutDown: not implemented");
+}
+
+void Scumm::processKbd() {
+ getKeyInput(0);
+
+ _virtual_mouse_x = mouse.x + virtscr[0].xstart;
+ _virtual_mouse_y = mouse.y + virtscr[0].topline;
+ if (_virtual_mouse_y < 0)
+ _virtual_mouse_y = -1;
+ if (_virtual_mouse_y >= virtscr[0].height)
+ _virtual_mouse_y = -1;
+
+ if (!_lastKeyHit)
+ return;
+
+ if (_lastKeyHit==vm.vars[VAR_RESTART_KEY]) {
+ warning("Restart not implemented");
+ pauseGame(1);
+ return;
+ }
+
+ if (_lastKeyHit==vm.vars[VAR_PAUSE_KEY]) {
+ warning("Pause not implemented");
+ /* pause */
+ return;
+ }
+
+ if (_lastKeyHit==vm.vars[VAR_CUTSCENEEXIT_KEY]) {
+ uint32 offs = vm.cutScenePtr[vm.cutSceneStackPointer];
+ if (offs) {
+ ScriptSlot *ss = &vm.slot[vm.cutSceneScript[vm.cutSceneStackPointer]];
+ ss->offs = offs;
+ ss->status = 2;
+ ss->freezeCount = 0;
+ ss->cutsceneOverride--;
+ vm.vars[VAR_OVERRIDE] = 1;
+ vm.cutScenePtr[vm.cutSceneStackPointer] = 0;
+ }
+ }
+
+ if (_lastKeyHit==vm.vars[VAR_TALKSTOP_KEY]) {
+ _talkDelay = 0;
+ return;
+ }
+
+ _mouseButStat = _lastKeyHit;
+}
+
+int Scumm::getKeyInput(int a) {
+ _mouseButStat = 0;
+
+ _lastKeyHit = checkKeyHit();
+ if (a==0)
+ convertKeysToClicks();
+
+ if (mouse.x<0) mouse.x=0;
+ if (mouse.x>319) mouse.x=319;
+ if (mouse.y<0) mouse.y=0;
+ if (mouse.y>199) mouse.y=199;
+
+ if (_leftBtnPressed&1 && _rightBtnPressed&1) {
+ _mouseButStat = 0;
+ _lastKeyHit = vm.vars[VAR_CUTSCENEEXIT_KEY];
+ } else if (_leftBtnPressed&1) {
+ _mouseButStat = 0x8000;
+ } else if (_rightBtnPressed&1) {
+ _mouseButStat = 0x4000;
+ }
+
+ _leftBtnPressed &= ~1;
+ _rightBtnPressed &= ~1;
+
+ return _lastKeyHit;
+}
+
+void Scumm::convertKeysToClicks() {
+ if (_lastKeyHit && _cursorState>0) {
+ if (_lastKeyHit==9) {
+ _mouseButStat = 0x4000;
+ } else if (_lastKeyHit==13) {
+ _mouseButStat = 0x8000;
+ } else
+ return;
+ _lastKeyHit = 0;
+ }
+}
+
+Actor *Scumm::derefActorSafe(int id, const char *errmsg) {
+ if (id<1 || id>=13)
+ error("Invalid actor %d in %s", id, errmsg);
+ return derefActor(id);
+}
+
+extern Scumm scumm;
+
+void NORETURN CDECL error(const char *s, ...) {
+ char buf[1024];
+ va_list va;
+
+ va_start(va, s);
+ vsprintf(buf, s, va);
+ va_end(va);
+
+ if (scumm._currentScript != 0xFF) {
+ fprintf(stderr, "Error(%d): %s!\nPress a key to quit.\n", scumm.vm.slot[scumm._currentScript].number, buf);
+ } else {
+ fprintf(stderr, "Error: %s!\nPress a key to quit.\n", buf);
+ }
+ exit(1);
+}
+
+void CDECL warning(const char *s, ...) {
+ char buf[1024];
+ va_list va;
+
+ va_start(va,s);
+ vsprintf(buf, s, va);
+ va_end(va);
+
+ fprintf(stderr, "WARNING: %s!\n", buf);
+}
+
+void CDECL debug(int level, const char *s, ...) {
+ char buf[1024];
+ va_list va;
+
+ if (level>5)
+ return;
+
+ va_start(va,s);
+ vsprintf(buf, s, va);
+ va_end(va);
+ printf("%s\n", buf);
+ fflush(stdout);
+}
+
+void checkHeap() {
+#if 0
+ if (_heapchk() != _HEAPOK) {
+ error("Heap is invalid!");
+ }
+#endif
+}
+
diff --git a/scummvm.dsp b/scummvm.dsp
new file mode 100644
index 0000000000..64daceb22b
--- /dev/null
+++ b/scummvm.dsp
@@ -0,0 +1,175 @@
+# Microsoft Developer Studio Project File - Name="scummvm" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=scummvm - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "scummvm.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "scummvm.mak" CFG="scummvm - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "scummvm - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "scummvm - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "scummvm - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c
+# ADD CPP /nologo /Zp4 /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c
+# ADD BASE RSC /l 0x41d /d "NDEBUG"
+# ADD RSC /l 0x41d /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib sdl.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "scummvm - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c
+# ADD BASE RSC /l 0x41d /d "_DEBUG"
+# ADD RSC /l 0x41d /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib sdl.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "scummvm - Win32 Release"
+# Name "scummvm - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\actor.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\boxes.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\costume.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\gfx.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\object.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\resource.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\saveload.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\script.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\scummvm.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sdl.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sound.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.cpp
+# ADD CPP /Yc"stdafx.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\string.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sys.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\verbs.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\scumm.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\scummsys.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# Begin Source File
+
+SOURCE=.\ReadMe.txt
+# End Source File
+# End Target
+# End Project
diff --git a/scummvm.dsw b/scummvm.dsw
new file mode 100644
index 0000000000..e4c72042dc
--- /dev/null
+++ b/scummvm.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "scummvm"=.\scummvm.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/sdl.cpp b/sdl.cpp
new file mode 100644
index 0000000000..9d2d6db5ac
--- /dev/null
+++ b/sdl.cpp
@@ -0,0 +1,213 @@
+/* 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.
+ *
+ * Change Log:
+ * $Log$
+ * Revision 1.1 2001/10/09 14:30:13 strigeus
+ * Initial revision
+ *
+ *
+ */
+
+#include "stdafx.h"
+#include "scumm.h"
+
+#define SCALEUP_2x2
+
+Scumm scumm;
+
+static SDL_Surface *screen;
+
+void updatePalette(Scumm *s) {
+ SDL_Color colors[256];
+ int first = s->_palDirtyMin;
+ int num = s->_palDirtyMax - first + 1;
+ int i;
+ byte *data = s->_currentPalette;
+
+ data += first*3;
+ for (i=0; i<num; i++,data+=3) {
+ colors[i].r = data[0]<<2;
+ colors[i].g = data[1]<<2;
+ colors[i].b = data[2]<<2;
+ colors[i].unused = 0;
+ }
+
+ SDL_SetColors(screen, colors, first, num);
+
+ s->_palDirtyMax = -1;
+ s->_palDirtyMin = 0x3E8;
+}
+
+void waitForTimer(Scumm *s) {
+ SDL_Event event;
+ byte dontPause = true;
+
+ do {
+ while (SDL_PollEvent(&event)) {
+ switch(event.type) {
+ case SDL_KEYDOWN:
+ s->_keyPressed = event.key.keysym.sym;
+ break;
+ case SDL_MOUSEMOTION:
+#if !defined(SCALEUP_2x2)
+ s->mouse.x = event.motion.x;
+ s->mouse.y = event.motion.y;
+#else
+ s->mouse.x = event.motion.x>>1;
+ s->mouse.y = event.motion.y>>1;
+#endif
+ break;
+ case SDL_MOUSEBUTTONDOWN:
+ if (event.button.button==SDL_BUTTON_LEFT)
+ s->_leftBtnPressed |= 1;
+ else if (event.button.button==SDL_BUTTON_RIGHT)
+ s->_rightBtnPressed |= 1;
+ break;
+#if 0
+ case SDL_ACTIVEEVENT:
+ if (event.active.state & SDL_APPINPUTFOCUS) {
+ dontPause = event.active.gain;
+ }
+ break;
+#endif
+ case SDL_QUIT:
+ exit(1);
+ break;
+ }
+ }
+ SDL_Delay(dontPause ? 10 : 100);
+ } while (!dontPause);
+
+ s->_scummTimer+=3;
+}
+
+#define MAX_DIRTY_RECTS 40
+SDL_Rect dirtyRects[MAX_DIRTY_RECTS];
+int numDirtyRects;
+bool fullRedraw;
+
+/* Copy part of bitmap */
+void blitToScreen(Scumm *s, byte *src,int x, int y, int w, int h) {
+ byte *dst;
+ SDL_Rect *r;
+ int i;
+
+ if (SDL_LockSurface(screen)==-1)
+ error("SDL_LockSurface failed: %s.\n", SDL_GetError());
+
+#if !defined(SCALEUP_2x2)
+ dst = (byte*)screen->pixels + y*320 + x;
+
+ if (numDirtyRects==MAX_DIRTY_RECTS)
+ fullRedraw = true;
+ else if (!fullRedraw) {
+ r = &dirtyRects[numDirtyRects++];
+ r->x = x;
+ r->y = y;
+ r->w = w;
+ r->h = h;
+ }
+
+ do {
+ memcpy(dst, src, w);
+ dst += 640;
+ src += 320;
+ } while (--h);
+#else
+ dst = (byte*)screen->pixels + y*640*2 + x*2;
+
+ if (numDirtyRects==MAX_DIRTY_RECTS)
+ fullRedraw = true;
+ else if (!fullRedraw) {
+ r = &dirtyRects[numDirtyRects++];
+ r->x = x*2;
+ r->y = y*2;
+ r->w = w*2;
+ r->h = h*2;
+ }
+
+ do {
+ i=0;
+ do {
+ dst[i*2] = dst[i*2+1] = src[i];
+ } while (++i!=w);
+ memcpy(dst+640, dst, w*2);
+ dst += 640*2;
+ src += 320;
+ } while (--h);
+
+#endif
+
+ SDL_UnlockSurface(screen);
+}
+
+void updateScreen(Scumm *s) {
+
+ if(s->_palDirtyMax != -1) {
+ updatePalette(s);
+ }
+
+ if (fullRedraw) {
+ SDL_UpdateRect(screen, 0,0,0,0);
+#if defined(SHOW_AREA)
+ debug(2,"update area 100 %%");
+#endif
+ } else if (numDirtyRects) {
+#if defined(SHOW_AREA)
+ int area = 0,i;
+ for (i=0; i<numDirtyRects; i++)
+ area += (dirtyRects[i].w * dirtyRects[i].h);
+ debug(2,"update area %f %%", (float)area/640);
+#endif
+ SDL_UpdateRects(screen, numDirtyRects, dirtyRects);
+ }
+
+
+ numDirtyRects = 0;
+}
+
+#undef main
+int main(int argc, char* argv[]) {
+ if (SDL_Init(SDL_INIT_VIDEO)==-1) {
+ printf("Could not initialize SDL: %s.\n", SDL_GetError());
+ return -1;
+ }
+
+ printf("%d %d, %d %d, %d %d %d, %d %d %d %d %d\n",
+ sizeof(int8), sizeof(uint8),
+ sizeof(int16), sizeof(uint16),
+ sizeof(int32), sizeof(uint32),
+ sizeof(void*),
+ sizeof(Box), sizeof(MouseCursor),sizeof(CodeHeader),
+ sizeof(ImageHeader),
+ &((CodeHeader*)0)->unk4
+ );
+
+ /* Clean up on exit */
+ atexit(SDL_Quit);
+
+#if !defined(SCALEUP_2x2)
+ screen = SDL_SetVideoMode(320, 200, 8, SDL_SWSURFACE);
+#else
+ screen = SDL_SetVideoMode(640, 400, 8, SDL_SWSURFACE);
+#endif
+ scumm._videoMode = 0x13;
+ scumm.scummMain();
+
+ return 0;
+}
diff --git a/sound.cpp b/sound.cpp
new file mode 100644
index 0000000000..35f855529f
--- /dev/null
+++ b/sound.cpp
@@ -0,0 +1,86 @@
+/* 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.
+ *
+ * Change Log:
+ * $Log$
+ * Revision 1.1 2001/10/09 14:30:13 strigeus
+ * Initial revision
+ *
+ *
+ */
+
+#include "stdafx.h"
+#include "scumm.h"
+
+void Scumm::addSoundToQueue(int sound) {
+ vm.vars[VAR_LAST_SOUND] = sound;
+ ensureResourceLoaded(4, sound);
+ addSoundToQueue2(sound);
+}
+
+void Scumm::addSoundToQueue2(int sound) {
+ if (_soundQue2Pos < 10) {
+ _soundQue2[_soundQue2Pos++] = sound;
+ }
+}
+
+void Scumm::unkSoundProc22() {
+ byte d;
+ int i,j;
+ int num;
+ int16 data[16];
+
+ while (_soundQue2Pos){
+ d=_soundQue2[--_soundQue2Pos];
+ if (d)
+ playSound(d);
+ }
+
+#if 0
+ for (i=0; i<_soundQuePos; ) {
+ num = _soundQue[i++];
+ for (j=0; j<16; j++)
+ data[j] = 0;
+ if (num>0) {
+ for (j=0; j<num; j++)
+ _soundQue[i+j] = data[j];
+ i += num;
+ /* XXX: not implemented */
+ warning("unkSoundProc22: not implemented");
+// vm.vars[VAR_SOUNDRESULT] = soundProcPtr1(...);
+ }
+ }
+ #endif
+ _soundQuePos = 0;
+}
+
+void Scumm::playSound(int sound) {
+ getResourceAddress(4, sound);
+ /* XXX: not implemented */
+ warning("stub playSound(%d)", sound);
+}
+
+int Scumm::unkSoundProc23(int a) {
+ /* TODO: implement this */
+ warning("unkSoundProc23: not implemented");
+ return 0;
+}
+
+void Scumm::unkSoundProc1(int a) {
+ /* TODO: implement this */
+ warning("unkSoundProc: not implemented");
+}
diff --git a/stdafx.cpp b/stdafx.cpp
new file mode 100644
index 0000000000..fb2b30bab7
--- /dev/null
+++ b/stdafx.cpp
@@ -0,0 +1,8 @@
+// stdafx.cpp : source file that includes just the standard includes
+// scummvm.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
diff --git a/stdafx.h b/stdafx.h
new file mode 100644
index 0000000000..1416fa4210
--- /dev/null
+++ b/stdafx.h
@@ -0,0 +1,58 @@
+#if defined(WIN32)
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+#define NOGDICAPMASKS
+#define OEMRESOURCE
+#define NONLS
+#define NOICONS
+#define NOMCX
+#define NOPROFILER
+#define NOKANJI
+#define NOSERVICE
+#define NOMETAFILE
+#define NOCOMM
+#define NOCRYPT
+#define NOIME
+#define NOATOM
+#define NOCTLMGR
+#define NOCLIPBOARD
+#define NOMEMMGR
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOOPENFILE
+#define NOWH
+#define NOSOUND
+#define NODRAWTEXT
+
+#include <SDL.h>
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <io.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <conio.h>
+#include <malloc.h>
+#include <assert.h>
+
+#else
+
+#include <SDL.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <assert.h>
+
+
+
+#endif \ No newline at end of file
diff --git a/string.cpp b/string.cpp
new file mode 100644
index 0000000000..f7785e5f88
--- /dev/null
+++ b/string.cpp
@@ -0,0 +1,697 @@
+/* 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.
+ *
+ * Change Log:
+ * $Log$
+ * Revision 1.1 2001/10/09 14:30:13 strigeus
+ * Initial revision
+ *
+ *
+ */
+
+#include "stdafx.h"
+#include "scumm.h"
+
+int CharsetRenderer::getStringWidth(int arg, byte *text, int pos) {
+ byte *ptr;
+ int width,offs,w;
+ byte chr;
+
+ width = 1;
+ ptr = _vm->getResourceAddress(6, _curId) + 29;
+
+ while ( (chr = text[pos++]) != 0) {
+ if (chr==0xD)
+ break;
+ if (chr=='@')
+ continue;
+ if (chr==254) chr=255;
+ if (chr==255) {
+ chr=text[pos++];
+ if (chr==3)
+ break;
+ if (chr==8) {
+ if (arg==1)
+ break;
+ while (text[pos]==' ')
+ text[pos++] = '@';
+ continue;
+ }
+ if (chr==1 || chr==2)
+ break;
+ }
+
+ offs = READ_LE_UINT32(ptr + chr*4 + 4);
+ if (offs) {
+ if (ptr[offs+2]>=0x80) {
+ w = ptr[offs+2] - 0x100;
+ } else {
+ w = ptr[offs+2];
+ }
+ width += ptr[offs] + w;
+ }
+ }
+ return width;
+}
+
+void CharsetRenderer::addLinebreaks(int a, byte *str, int pos, int maxwidth) {
+ int lastspace = -1;
+ int curw = 1;
+ int offs,w;
+ byte *ptr;
+ byte chr;
+
+ ptr = _vm->getResourceAddress(6, _curId) + 29;
+
+ while ( (chr=str[pos++]) != 0) {
+ if (chr=='@')
+ continue;
+ if (chr==254) chr=255;
+ if (chr==255) {
+ chr = str[pos++];
+ if (chr==3)
+ break;
+ if (chr==8) {
+ if (a==1) {
+ curw = 1;
+ } else {
+ while (str[pos]==' ')
+ str[pos++] = '@';
+ }
+ continue;
+ }
+ if (chr==1) {
+ curw = 1;
+ continue;
+ }
+ if (chr==2)
+ break;
+ }
+
+ if (chr==' ')
+ lastspace = pos - 1;
+
+ offs = READ_LE_UINT32(ptr + chr*4 + 4);
+ if (offs) {
+ if (ptr[offs+2]>=0x80) {
+ w = ptr[offs+2] - 0x100;
+ } else {
+ w = ptr[offs+2];
+ }
+ curw += w + ptr[offs];
+ }
+ if (lastspace==-1)
+ continue;
+ if (curw > maxwidth) {
+ str[lastspace] = 0xD;
+ curw = 1;
+ pos = lastspace + 1;
+ lastspace = -1;
+ }
+ }
+}
+
+void Scumm::unkMessage1() {
+ byte buf[100];
+ _msgPtrToAdd = buf;
+ _messagePtr = addMessageToStack(_messagePtr);
+}
+
+void Scumm::unkMessage2() {
+ byte buf[100], *tmp;
+
+ _msgPtrToAdd = buf;
+ tmp = _messagePtr = addMessageToStack(_messagePtr);
+
+ if (_stringColor[3]==0)
+ _stringColor[3] = 4;
+
+ error("unkMessage2: call to printScummMessage(%s)", buf);
+ vm.vars[0] = 0;
+ _messagePtr = tmp;
+}
+
+
+void Scumm::CHARSET_1() {
+ int s, i, t, c;
+ int frme;
+ Actor *a;
+
+ if (!_haveMsg || (camera._destPos>>3) != (camera._curPos>>3) ||
+ camera._curPos != camera._lastPos
+ ) return;
+
+ a = NULL;
+ if (vm.vars[VAR_TALK_ACTOR] != 0xFF)
+ a = derefActorSafe(vm.vars[VAR_TALK_ACTOR], "CHARSET_1");
+
+ if (a && _stringOverhead[0]!=0) {
+ _stringXpos[0] = a->x - camera._curPos + 160;
+
+ if (vm.vars[VAR_TALK_STRING_Y] < 0) {
+ s = (a->scaley * (int)vm.vars[VAR_TALK_STRING_Y]) / 0xFF;
+ _stringYpos[0] = ((vm.vars[VAR_TALK_STRING_Y]-s)>>1) + s - a->elevation + a->y;
+ } else {
+ _stringYpos[0] = vm.vars[VAR_TALK_STRING_Y];
+ }
+ if (_stringYpos[0] < 1)
+ _stringYpos[0] = 1;
+
+ if (_stringXpos[0] < 80)
+ _stringXpos[0] = 80;
+ if (_stringXpos[0] > 240)
+ _stringXpos[0] = 240;
+ }
+
+ charset._top = _stringYpos[0];
+ charset._left = _stringXpos[0];
+ charset._left2 = _stringXpos[0];
+ charset._curId = _stringCharset[0];
+
+ if (a && a->charset)
+ charset._curId = a->charset;
+
+ charset._center = _stringCenter[0];
+ charset._right = _stringRight[0];
+ charset._color = _charsetColor;
+ dseg_4E3C = 0;
+
+ for (i=0; i<4; i++)
+ charset._colorMap[i] = _charsetData[charset._curId][i];
+
+ if (_keepText) {
+ charset._strLeft = charset._mask_left;
+ charset._strRight = charset._mask_right;
+ charset._strTop = charset._mask_top;
+ charset._strBottom = charset._mask_bottom;
+ }
+
+ if (!_haveMsg || _talkDelay)
+ return;
+
+ if (_haveMsg!=0xFF) {
+ stopTalk();
+ return;
+ }
+
+ if (a) {
+ startAnimActor(a, a->talkFrame1, a->facing);
+ }
+
+ _talkDelay = _defaultTalkDelay;
+
+ if (!_keepText) {
+ restoreCharsetBg();
+ _stringXpos2[0] = _stringXpos[0];
+ _stringYpos2[0] = _stringYpos[0];
+ }
+
+ t = charset._right - _stringXpos2[0] - 1;
+ if (charset._center) {
+ if (t > _stringXpos2[0])
+ t = _stringXpos2[0];
+ t <<= 1;
+ }
+ charset.addLinebreaks(0, charset._buffer, charset._bufPos, t);
+
+ _lastXstart = virtscr[0].xstart;
+ if (charset._center) {
+ _stringXpos2[0] -= charset.getStringWidth(0, charset._buffer, charset._bufPos) >> 1;
+ }
+
+ charset._disableOffsX = charset._unk12 = !_keepText;
+
+ do {
+ c = charset._buffer[charset._bufPos++];
+ if (c==0) {
+ _haveMsg = 1;
+ _keepText = false;
+ break;
+ }
+ if (c != 13) {
+ if (c==0xFE)
+ c=0xFF;
+
+ if (c!=0xFF) {
+PrintChar:;
+ charset._left = _stringXpos2[0];
+ charset._top = _stringYpos2[0];
+
+ if (!vm.vars[VAR_CHARFLAG]) {
+ charset.printChar(c);
+ }
+ _stringXpos2[0] = charset._left;
+ _stringYpos2[0] = charset._top;
+
+ _talkDelay += vm.vars[VAR_CHARINC];
+ continue;
+ }
+
+ c = charset._buffer[charset._bufPos++];
+ if (c==3) {
+ _haveMsg = 0xFF;
+ _keepText = false;
+ break;
+ }
+ if (c!=1) {
+ if (c==2) {
+ _haveMsg = 0;
+ _keepText = true;
+ break;
+ }
+ if (c==9) {
+ frme = charset._buffer[charset._bufPos++];
+ frme |= charset._buffer[charset._bufPos++]<<8;
+ if (a)
+ startAnimActor(a, frme, a->facing);
+ }
+ goto PrintChar;
+ }
+ }
+ _stringXpos2[0] = _stringXpos[0];
+ if (charset._center) {
+ _stringXpos2[0] -= charset.getStringWidth(0, charset._buffer, charset._bufPos)>>1;
+ }
+ _stringYpos2[0] += getResourceAddress(6,charset._curId)[30];
+ charset._disableOffsX = 1;
+ } while (1);
+
+ charset._mask_left = charset._strLeft;
+ charset._mask_right = charset._strRight;
+ charset._mask_top = charset._strTop;
+ charset._mask_bottom = charset._strBottom;
+}
+
+void Scumm::drawString(int a) {
+ byte buf[256];
+ byte *charsetptr,*space;
+ int i;
+ byte byte1, chr;
+
+ _msgPtrToAdd = buf;
+ _messagePtr = addMessageToStack(_messagePtr);
+
+ charset._left2 = charset._left = _stringXpos[a];
+ charset._top = _stringYpos[a];
+ charset._curId = _stringCharset[a];
+ charset._center = _stringCenter[a];
+ charset._right = _stringRight[a];
+ charset._color = _stringColor[a];
+ dseg_4E3C = 0;
+ charset._unk12 = 1;
+ charset._disableOffsX = 1;
+
+ charsetptr = getResourceAddress(6, charset._curId);
+ assert(charsetptr);
+ charsetptr += 29;
+
+ for(i=0; i<4; i++)
+ charset._colorMap[i] = _charsetData[charset._curId][i];
+
+ byte1 = charsetptr[1];
+
+ _msgPtrToAdd = buf;
+
+ /* trim from the right */
+ space = NULL;
+ while (*_msgPtrToAdd){
+ if (*_msgPtrToAdd==' ') {
+ if (!space) space = _msgPtrToAdd;
+ } else {
+ space = NULL;
+ }
+ _msgPtrToAdd++;
+ }
+ if(space) *space='\0';
+
+ if (charset._center) {
+ charset._left -= charset.getStringWidth(a, buf, 0) >> 1;
+ }
+
+ charset._ignoreCharsetMask = 1;
+
+ if (!buf[0]) {
+ buf[0] = ' ';
+ buf[1] = 0;
+ }
+
+ for (i=0; (chr=buf[i++]) != 0; ) {
+ if (chr==254) chr=255;
+ if (chr==255) {
+ chr = buf[i++];
+ switch(chr) {
+ case 9:
+ i += 2;
+ break;
+ case 1: case 8:
+ if (charset._center) {
+ charset._left = charset._left2 - charset.getStringWidth(a, buf, i);
+ } else {
+ charset._left = charset._left2;
+ }
+ charset._top += byte1;
+ }
+ } else {
+ charset.printChar(chr);
+ }
+ }
+
+ charset._ignoreCharsetMask = 0;
+ _stringXpos2[a] = charset._left;
+ _stringYpos2[a] = charset._top;
+}
+
+byte *Scumm::addMessageToStack(byte *msg) {
+ int num, numorg;
+ byte *ptr, chr;
+
+ numorg = num = _numInMsgStack;
+ ptr = getResourceAddress(0xC, 6);
+
+ if (ptr==NULL)
+ error("Message stack not allocated");
+
+ while ( (chr=*msg++) != 0) {
+ if (num > 500)
+ error("Message stack overflow");
+
+ ptr[num++] = chr;
+
+ if (chr==255) {
+ ptr[num++] = chr = *msg++;
+
+ if (chr==0 || chr!=2 && chr!=3 && chr!=8) {
+ ptr[num++] = chr = *msg++;
+ ptr[num++] = chr = *msg++;
+ }
+ }
+ }
+ ptr[num++] = 0;
+
+ _numInMsgStack = num;
+ num = numorg;
+
+ while (1) {
+ ptr = getResourceAddress(0xC, 6);
+ chr = ptr[num++];
+ if (chr == 0)
+ break;
+ if (chr == 0xFF) {
+ ptr = getResourceAddress(0xC, 6);
+ chr = ptr[num++];
+ switch(chr) {
+ case 4:
+ unkAddMsgToStack2(
+ READ_LE_UINT16(getResourceAddress(0xC, 6)+ num)
+ );
+ num+=2;
+ break;
+ case 5:
+ unkAddMsgToStack3(
+ READ_LE_UINT16(getResourceAddress(0xC, 6)+ num)
+ );
+ num+=2;
+ break;
+ case 6:
+ unkAddMsgToStack4(
+ READ_LE_UINT16(getResourceAddress(0xC, 6)+ num)
+ );
+ num+=2;
+ break;
+ case 7:
+ unkAddMsgToStack5(
+ READ_LE_UINT16(getResourceAddress(0xC, 6)+num)
+ );
+ num+=2;
+ break;
+ case 9:
+ *_msgPtrToAdd++ = 0xFF;
+ *_msgPtrToAdd++ = chr;
+ *_msgPtrToAdd++ = getResourceAddress(0xC, 6)[num++];
+ *_msgPtrToAdd++ = getResourceAddress(0xC, 6)[num++];
+ break;
+ default:
+ *_msgPtrToAdd++ = 0xFF;
+ *_msgPtrToAdd++ = chr;
+ }
+ } else {
+ if (chr!='@') {
+ *_msgPtrToAdd++ = chr;
+ }
+ }
+ }
+ *_msgPtrToAdd = 0;
+ _numInMsgStack = numorg;
+
+ return msg;
+}
+
+void Scumm::unkAddMsgToStack2(int var) {
+ int num,max;
+ byte flag;
+
+ num = readVar(var);
+ if (num < 0) {
+ *_msgPtrToAdd++ = '-';
+ num = -num;
+ }
+
+ flag = 0;
+ max = 10000;
+ do {
+ if (num>=max || flag) {
+ *_msgPtrToAdd++ = num/max + '0';
+ num -= (num/max)*max;
+ flag=1;
+ }
+ max/=10;
+ if (max==1) flag=1;
+ } while (max);
+}
+
+void Scumm::unkAddMsgToStack3(int var) {
+ int num,i;
+
+ num = readVar(var);
+ if (num) {
+ for (i=1; i<_maxVerbs; i++) {
+ if (num==verbs[i].verbid && !verbs[i].type && !verbs[i].saveid) {
+ addMessageToStack(getResourceAddress(8, i));
+ break;
+ }
+ }
+ } else {
+ addMessageToStack((byte*)"");
+ }
+}
+
+void Scumm::unkAddMsgToStack4(int var) {
+ int num;
+
+ num = readVar(var);
+ if (num) {
+ addMessageToStack(getObjOrActorName(num));
+ } else {
+ addMessageToStack((byte*)"");
+ }
+}
+
+void Scumm::unkAddMsgToStack5(int var) {
+ byte *ptr;
+ if (var) {
+ ptr = getResourceAddress(7, var);
+ if (ptr) {
+ addMessageToStack(ptr);
+ return;
+ }
+ }
+ addMessageToStack((byte*)"");
+}
+
+void Scumm::initCharset(int charsetno) {
+ int i;
+
+ if (!getResourceAddress(6, charsetno))
+ loadCharset(charsetno);
+
+ textslot.charset[0] = charsetno;
+ textslot.charset[1] = charsetno;
+
+ for (i=0; i<0x10; i++)
+ charset._colorMap[i] = _charsetData[charsetno][i];
+}
+
+void CharsetRenderer::printChar(int chr) {
+ int d,right;
+ VirtScreen *vs;
+
+ _vm->checkRange(_vm->_maxCharsets-1, 1, _curId, "Printing with bad charset %d");
+ if (_vm->findVirtScreen(_top)==-1)
+ return;
+
+ vs = &_vm->virtscr[_vm->gdi.virtScreen];
+
+ if (chr=='@')
+ return;
+
+ _ptr = _vm->getResourceAddress(6, _curId) + 29;
+
+ _bpp = _unk2 = *_ptr;
+ _invNumBits = 8 - _bpp;
+ _bitMask = 0xFF << _invNumBits;
+ _colorMap[1] = _color;
+
+ _charOffs = READ_LE_UINT32(_ptr + chr*4 + 4);
+
+ if (!_charOffs)
+ return;
+
+ assert(_charOffs < 0x10000);
+
+ _charPtr = _ptr + _charOffs;
+
+ _width = _charPtr[0];
+ _height = _charPtr[1];
+ if (_unk12) {
+ _strLeft = 0;
+ _strTop = 0;
+ _strRight = 0;
+ _strBottom = 0;
+ }
+
+ if (_disableOffsX) {
+ _offsX = 0;
+ } else {
+ d = _charPtr[2];
+ if (d>=0x80)
+ d -= 0x100;
+ _offsX = d;
+ }
+
+ d = _charPtr[3];
+ if(d>=0x80)
+ d -= 0x100;
+ _offsY = d;
+
+ _top += _offsY;
+ _left += _offsX;
+
+ right = _left + _width;
+
+ if (right>_right+1 || _left < 0) {
+ _left = right;
+ _top -= _offsY;
+ return;
+ }
+
+ _disableOffsX = 0;
+
+ if (_unk12) {
+ _strLeft = _left;
+ _strTop = _top;
+ _strRight = _left;
+ _strBottom = _top;
+ _unk12 = 0;
+ }
+
+ if (_left < _strLeft)
+ _strLeft = _left;
+
+ if (_top < _strTop)
+ _strTop = _top;
+
+ _drawTop = _top - vs->topline;
+ _bottom = _drawTop + _height + _offsY;
+
+ _vm->updateDirtyRect(_vm->gdi.virtScreen, _left, right, _drawTop, _bottom, 0);
+
+ if (_vm->gdi.virtScreen==0)
+ _hasMask = true;
+
+ _bg_ptr = _vm->getResourceAddress(0xA, _vm->gdi.virtScreen+1)
+ + vs->xstart + _drawTop * 320 + _left;
+
+ _where_to_draw_ptr = _vm->getResourceAddress(0xA, _vm->gdi.virtScreen+5)
+ + vs->xstart + _drawTop * 320 + _left;
+
+ _mask_ptr = _vm->getResourceAddress(0xA, 9)
+ + _drawTop * 40 + _left/8
+ + _vm->_screenStartStrip;
+
+ _revBitMask = revBitMask[_left&7];
+
+ _virtScreenHeight = vs->height;
+ _charPtr += 4;
+
+ drawBits();
+
+ _left += _width;
+ if (_left > _strRight)
+ _strRight = _left;
+
+ if (_top + _height > _strBottom)
+ _strBottom = _top + _height;
+
+ _top -= _offsY;
+}
+
+
+void CharsetRenderer::drawBits() {
+ bool usemask;
+ byte *dst, *mask,maskmask;
+ int y,x;
+ int maskpos;
+ int color;
+ byte numbits,bits;
+
+ usemask = (_vm->gdi.virtScreen==0 && _ignoreCharsetMask==0);
+
+ bits = *_charPtr++;
+ numbits = 8;
+
+ dst = _bg_ptr;
+ mask = _mask_ptr;
+ y = 0;
+
+ for(y=0; y<_height && y+_drawTop < _virtScreenHeight;) {
+ maskmask = _revBitMask;
+ maskpos = 0;
+
+ for (x=0; x<_width; x++) {
+ color = (bits&_bitMask)>>_invNumBits;
+ if (color) {
+ if (usemask) {
+ mask[maskpos] |= maskmask;
+ }
+ *dst = _colorMap[color];
+ }
+ dst++;
+ bits <<= _bpp;
+ if ((numbits -= _bpp)==0) {
+ bits = *_charPtr++;
+ numbits = 8;
+ }
+ if ((maskmask>>=1)==0) {
+ maskmask = 0x80;
+ maskpos++;
+ }
+ }
+ dst = (_bg_ptr += 320);
+ mask += 40;
+ y++;
+ }
+}
diff --git a/sys.cpp b/sys.cpp
new file mode 100644
index 0000000000..5b75bbf1c4
--- /dev/null
+++ b/sys.cpp
@@ -0,0 +1,164 @@
+/* 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.
+ *
+ * Change Log:
+ * $Log$
+ * Revision 1.1 2001/10/09 14:30:13 strigeus
+ * Initial revision
+ *
+ *
+ */
+
+#include "stdafx.h"
+#include "scumm.h"
+
+void *Scumm::fileOpen(const char *filename, int mode) {
+ _fileMode = mode;
+ _whereInResToRead = 0;
+ clearFileReadFailed(_fileHandle);
+
+ if (mode==1)
+ return fopen(filename, "rb");
+
+ if (mode==2) {
+ error("fileOpen: write not supported");
+ }
+
+ return NULL;
+}
+
+void Scumm::fileClose(void *file) {
+ if (_fileMode==1 || _fileMode==2)
+ fclose((FILE*)file);
+}
+
+bool Scumm::fileReadFailed(void *file) {
+ return _fileReadFailed != 0;
+}
+
+void Scumm::clearFileReadFailed(void *file) {
+ _fileReadFailed = false;
+}
+
+bool Scumm::fileEof(void *file) {
+ FILE *a = (FILE*)file;
+ return feof((FILE*)file) != 0;
+}
+
+void Scumm::fileSeek(void *file, long offs, int whence) {
+ switch(_fileMode) {
+ case 1: case 2:
+ fseek((FILE*)file, offs, whence);
+ return;
+ case 3:
+ _whereInResToRead = offs;
+ return;
+ }
+}
+
+void Scumm::fileRead(void *file, void *ptr, uint32 size) {
+ byte *ptr2 = (byte*)ptr, *src;
+
+ switch(_fileMode) {
+ case 1:
+ if (size==0)
+ return;
+
+ if ((uint32)fread(ptr2, size, 1, (FILE*)file) != 1)
+ _fileReadFailed = true;
+
+ do {
+ *ptr2++ ^= _encbyte;
+ } while(--size);
+
+ return;
+
+ case 3:
+ if (size==0)
+ return;
+
+ src = getResourceAddress(0xC, 3) + _whereInResToRead;
+ _whereInResToRead += size;
+ do {
+ *ptr2++ = *src++ ^ _encbyte;
+ } while (--size);
+ return;
+ }
+}
+
+int Scumm::fileReadByte() {
+ byte b;
+ byte *src;
+
+ switch(_fileMode) {
+ case 1:
+ if (fread(&b,1,1,(FILE*)_fileHandle) != 1)
+ _fileReadFailed = true;
+ return b ^ _encbyte;
+
+ case 3:
+ src = getResourceAddress(0xC, 3) + _whereInResToRead;
+ _whereInResToRead++;
+ return *src ^ _encbyte;
+ }
+ return 0;
+}
+
+uint Scumm::fileReadWordLE() {
+ uint a = fileReadByte();
+ uint b = fileReadByte();
+ return a|(b<<8);
+}
+
+uint32 Scumm::fileReadDwordLE() {
+ uint a = fileReadWordLE();
+ uint b = fileReadWordLE();
+ return (b<<16)|a;
+}
+
+uint Scumm::fileReadWordBE() {
+ uint b = fileReadByte();
+ uint a = fileReadByte();
+ return a|(b<<8);
+}
+
+uint32 Scumm::fileReadDwordBE() {
+ uint b = fileReadWordBE();
+ uint a = fileReadWordBE();
+ return (b<<16)|a;
+}
+
+byte *Scumm::alloc(int size) {
+ byte *me = (byte*)::calloc(size+4,1);
+ *((uint32*)me) = 0xDEADBEEF;
+ return me + 4;
+}
+
+void Scumm::free(void *mem) {
+ byte *me = (byte*)mem - 4;
+ if ( *((uint32*)me) != 0xDEADBEEF) {
+ error("Freeing invalid block.");
+ }
+
+ *((uint32*)me) = 0xC007CAFE;
+ ::free(me);
+}
+
+bool Scumm::checkFixedDisk() {
+ return true;
+}
+
diff --git a/verbs.cpp b/verbs.cpp
new file mode 100644
index 0000000000..a439270ec6
--- /dev/null
+++ b/verbs.cpp
@@ -0,0 +1,288 @@
+/* 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.
+ *
+ * Change Log:
+ * $Log$
+ * Revision 1.1 2001/10/09 14:30:13 strigeus
+ * Initial revision
+ *
+ *
+ */
+
+#include "stdafx.h"
+#include "scumm.h"
+
+void Scumm::redrawVerbs() {
+ int i;
+ for (i=0; i<_maxVerbs; i++)
+ drawVerb(i, 0);
+ verbMouseOver(0);
+}
+
+void Scumm::checkExecVerbs() {
+ int i,over;
+ VerbSlot *vs;
+
+ if (_userPut<=0 || _mouseButStat==0)
+ return;
+
+ if (_mouseButStat < 0x200) {
+ /* Check keypresses */
+ vs = &verbs[1];
+ for (i=1; i<_maxVerbs; i++,vs++) {
+ if (vs->verbid && vs->saveid && vs->curmode==1) {
+ if (_mouseButStat == vs->key) {
+ runInputScript(1, vs->verbid, 1);
+ return;
+ }
+ }
+ }
+ runInputScript(4, _mouseButStat, 1);
+ } else if (_mouseButStat&0xC000) {
+ byte code = _mouseButStat&0x8000 ? 1 : 2;
+ if (virtscr[0].topline <= mouse.y || virtscr[0].topline + virtscr[0].height > mouse.y) {
+ over = checkMouseOver(mouse.x, mouse.y);
+ if (over != 0) {
+ runInputScript(1,verbs[over].verbid,code);
+ return;
+ }
+ runInputScript(2, 0, code);
+ } else {
+ over=checkMouseOver(mouse.x, mouse.y);
+ runInputScript(1, over!=0 ? verbs[over].verbid : 0, code);
+ }
+ }
+}
+
+void Scumm::verbMouseOver(int verb) {
+ if (_verbMouseOver==verb)
+ return;
+
+ if (verbs[_verbMouseOver].type!=1) {
+ drawVerb(_verbMouseOver, 0);
+ _verbMouseOver = verb;
+ }
+
+ if (verbs[verb].type!=1 && verbs[verb].hicolor) {
+ drawVerb(verb, 1);
+ _verbMouseOver = verb;
+ }
+}
+
+int Scumm::checkMouseOver(int x, int y) {
+ VerbSlot *vs;
+ int i = _maxVerbs;
+
+ vs = &verbs[i];
+ do {
+ if (vs->curmode!=1 || !vs->verbid || vs->saveid ||
+ y < vs->y || y >= vs->bottom)
+ continue;
+ if (vs->center) {
+ if (x < -(vs->right - vs->x - vs->x) || x >= vs->right)
+ continue;
+ } else {
+ if (x < vs->x || x >= vs->right)
+ continue;
+ }
+ return i;
+ } while (--vs, i--);
+ return 0;
+}
+
+void Scumm::drawVerb(int vrb, int mode) {
+ VerbSlot *vs;
+ byte color;
+ byte tmp;
+
+ if (!vrb)
+ return;
+
+ vs = &verbs[vrb];
+
+ if (!vs->saveid && vs->curmode && vs->verbid) {
+ if (vs->type==1) {
+ drawVerbBitmap(vrb, vs->x, vs->y);
+ return;
+ }
+ restoreVerbBG(vrb);
+
+ _stringCharset[4] = vs->charset_nr;
+ _stringXpos[4] = vs->x;
+ _stringYpos[4] = vs->y;
+ _stringRight[4] = 319;
+ _stringCenter[4] = vs->center;
+ if (mode && vs->hicolor)
+ color = vs->hicolor;
+ else
+ color = vs->color;
+ _stringColor[4] = color;
+ if (vs->curmode==2)
+ _stringColor[4] = vs->dimcolor;
+ _messagePtr = getResourceAddress(8, vrb);
+ assert(_messagePtr);
+ tmp = charset._center;
+ charset._center = 0;
+ drawString(4);
+ charset._center = tmp;
+ vs->right = charset._strRight;
+ vs->bottom = charset._strBottom;
+ vs->oldleft = charset._strLeft;
+ vs->oldright = charset._strRight;
+ vs->oldtop = charset._strTop;
+ vs->oldbottom = charset._strBottom;
+ charset._strLeft = charset._strRight;
+ } else {
+ restoreVerbBG(vrb);
+ }
+}
+
+void Scumm::restoreVerbBG(int verb) {
+ VerbSlot *vs;
+
+ vs = &verbs[verb];
+
+ if (vs->oldleft != -1) {
+ dseg_4E3C = vs->bkcolor;
+ restoreBG(vs->oldleft, vs->oldtop, vs->oldright, vs->oldbottom);
+ vs->oldleft = -1;
+ }
+}
+
+void Scumm::drawVerbBitmap(int vrb, int x, int y) {
+ int nozbufs;
+ VirtScreen *vs;
+ VerbSlot *vst;
+ byte twobufs, *imptr;
+ int ydiff, xstrip;
+ int imgw, imgh;
+ int i;
+ byte *IMHD_ptr;
+
+ if (findVirtScreen(y) == -1)
+ return;
+
+ _lastXstart = virtscr[0].xstart;
+ nozbufs = _numZBuffer;
+ _numZBuffer = 0;
+
+ vs = &virtscr[gdi.virtScreen];
+
+ twobufs = vs->alloctwobuffers;
+ vs->alloctwobuffers = 0;
+
+ xstrip = x>>3;
+ ydiff = y - vs->topline;
+
+ IMHD_ptr = findResource2(MKID('IMHD'), getResourceAddress(8, vrb));
+
+ imgw = READ_LE_UINT16(IMHD_ptr+0x14) >> 3;
+ imgh = READ_LE_UINT16(IMHD_ptr+0x16) >> 3;
+
+ imptr = findResource2(MKID('IM01'), NULL);
+ if (!imptr)
+ error("No image for verb %d", vrb);
+
+ for (i=0; i<imgw; i++) {
+ _drawBmpX = xstrip + i;
+ if (_drawBmpX < 40) {
+ _drawBmpY = ydiff;
+ gdi.numLinesToProcess = imgh<<3;
+ drawBmp(imptr, i, 1, 1, "Verb", READ_LE_UINT16(IMHD_ptr+8));
+ }
+ }
+
+ vst = &verbs[vrb];
+ vst->right = vst->x + imgw*8;
+ vst->bottom = vst->y + imgh*8;
+ vst->oldleft = vst->x;
+ vst->oldright = vst->right;
+ vst->oldtop = vst->y;
+ vst->oldbottom = vst->bottom;
+ _numZBuffer = nozbufs;
+
+ vs->alloctwobuffers = twobufs;
+}
+
+int Scumm::getVerbSlot(int id, int mode) {
+ int i;
+ for (i=1; i<_maxVerbs; i++) {
+ if (verbs[i].verbid == id && verbs[i].saveid == mode) {
+ return i;
+ }
+ }
+ return 0;
+}
+
+void Scumm::killVerb(int slot) {
+ VerbSlot *vs;
+
+ if (slot==0)
+ return;
+
+ vs = &verbs[slot];
+ vs->verbid = 0;
+ vs->curmode = 0;
+
+ nukeResource(8, slot);
+
+ if (vs->saveid==0) {
+ drawVerb(slot, 0);
+ verbMouseOver(0);
+ }
+ vs->saveid = 0;
+}
+
+void Scumm::setVerbObject(int room, int object, int verb) {
+ int numobj, i;
+ byte *obimptr;
+ uint32 imoffs,size;
+ byte *roomptr,*tmp_roomptr;
+ ImageHeader *imhd;
+ RoomHeader *roomhdr;
+
+ if (whereIsObject(object) == 4)
+ error("Can't grab verb image from flobject");
+
+ ensureResourceLoaded(1,room);
+ roomptr = getResourceAddress(1, room);
+ roomhdr = (RoomHeader*)findResource(MKID('RMHD'), roomptr);
+
+ numobj = READ_LE_UINT16(&roomhdr->numObjects);
+ if (numobj==0)
+ error("No images found in room %d", room);
+ if (numobj > 200)
+ error("More (%d) than %d objects in room %d", numobj, 200, room);
+
+ tmp_roomptr = roomptr;
+ for (i=1; i<=numobj; i++) {
+ obimptr = findResource(MKID('OBIM'), tmp_roomptr);
+ if (obimptr==NULL)
+ error("Not enough image blocks in room %d", room);
+ imhd = (ImageHeader*)findResource2(MKID('IMHD'), obimptr);
+ if ( READ_LE_UINT16(&imhd->obj_id) == object) {
+ imoffs = obimptr - roomptr;
+ size = READ_BE_UINT32_UNALIGNED(obimptr+4);
+ createResource(8, verb, size);
+ obimptr = getResourceAddress(1, room) + imoffs;
+ memcpy(getResourceAddress(8, verb), obimptr, size);
+ return;
+ }
+ tmp_roomptr = NULL;
+ }
+ error("Image %d not found in room %d", object, room);
+}
diff --git a/whatsnew.txt b/whatsnew.txt
new file mode 100644
index 0000000000..d59d2d3ec5
--- /dev/null
+++ b/whatsnew.txt
@@ -0,0 +1,4 @@
+0.0.1 (2001-10-08):
+- initial version
+
+
diff --git a/windows.cpp b/windows.cpp
new file mode 100644
index 0000000000..03b61a3108
--- /dev/null
+++ b/windows.cpp
@@ -0,0 +1,787 @@
+/* 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.
+ *
+ * Change Log:
+ * $Log$
+ * Revision 1.1 2001/10/09 14:30:13 strigeus
+ * Initial revision
+ *
+ *
+ */
+
+#if USE_DIRECTX
+#define INITGUID
+#include <ddraw.h>
+#endif
+
+#include "stdafx.h"
+#include <assert.h>
+
+#if USE_DRAWDIB
+#include <vfw.h>
+#endif
+
+#include "scumm.h"
+
+#define SRC_WIDTH 320
+#define SRC_HEIGHT 200
+#define SRC_PITCH (320)
+
+#define DEST_WIDTH 320
+#define DEST_HEIGHT 200
+
+#define USE_DIRECTX 0
+#define USE_DRAWDIB 0
+#define USE_GDI 1
+
+#if USE_GDI
+typedef struct DIB {
+ HBITMAP hSect;
+ byte *buf;
+ RGBQUAD *pal;
+ bool new_pal;
+} DIB;
+#endif
+
+class WndMan {
+ HMODULE hInst;
+ HWND hWnd;
+
+
+ bool terminated;
+
+#if USE_GDI
+// BITMAPINFO *biHeader;
+// byte *BmpBG;
+public:
+ DIB dib;
+private:
+#endif
+
+#if USE_DRAWDIB
+ BITMAPINFOHEADER *biHeader;
+ HDRAWDIB hdb;
+#endif
+
+public:
+ byte *_vgabuf;
+
+ Scumm *_scumm;
+
+#if USE_DIRECTX
+ IDirectDrawSurface4 *MainSurf,*Surf2;
+ IDirectDraw *DxObject;
+ IDirectDraw4 *Dx4Object;
+ IDirectDrawPalette *DxPal;
+ bool OutOfGame;
+ void InitDirectX();
+#endif
+
+public:
+ void init();
+
+ bool handleMessage();
+ void run();
+ void setPalette(byte *ctab, int first, int num);
+ void writeToScreen();
+
+#if USE_GDI
+ bool allocateDIB(int w, int h);
+#endif
+};
+
+void Error(const char *msg) {
+ OutputDebugString(msg);
+ MessageBoxA(0, msg, "Error", MB_ICONSTOP);
+ exit(1);
+}
+
+int sel;
+Scumm scumm;
+WndMan wm[1];
+
+
+
+void modifyslot(int sel, int what);
+
+
+static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
+ WndMan *wm = (WndMan*)GetWindowLong(hWnd, GWL_USERDATA);
+
+ switch (message)
+ {
+ case WM_DESTROY:
+ case WM_CLOSE:
+ PostQuitMessage(0);
+ break;
+ case WM_CHAR:
+ wm->_scumm->_keyPressed = wParam;
+ break;
+ case WM_MOUSEMOVE:
+ wm->_scumm->mouse.x = ((int16*)&lParam)[0];
+ wm->_scumm->mouse.y = ((int16*)&lParam)[1];
+ break;
+ case WM_LBUTTONDOWN:
+ wm->_scumm->_leftBtnPressed |= 1;
+ break;
+ case WM_RBUTTONDOWN:
+ wm->_scumm->_rightBtnPressed |= 1;
+ break;
+ default:
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ }
+ return 0;
+}
+
+#if USE_GDI
+
+void copy_320x200_to_640x400(byte *s, byte *d) {
+ _asm {
+ push ebp
+
+ mov esi,s
+ mov edi,d
+
+ mov ebp,SRC_HEIGHT
+ againouter:
+
+ mov ebx,320/4
+ againinner:
+ mov eax,[esi]
+ mov dl,ah
+ mov dh,ah
+ shl edx,16
+ mov dl,al
+ mov dh,al
+ shr eax,16
+ mov cl,ah
+ mov ch,ah
+ shl ecx,16
+ mov cl,al
+ mov ch,al
+
+ mov [edi],edx
+ mov [edi+4],ecx
+ mov [edi+640],edx
+ mov [edi+644],ecx
+
+ add esi,4
+ add edi,8
+
+ dec ebx
+ jnz againinner
+// add esi,15
+ add edi,640
+ dec ebp
+ jnz againouter
+ pop ebp
+ }
+}
+
+
+bool WndMan::allocateDIB(int w, int h) {
+ struct {
+ BITMAPINFOHEADER bih;
+ RGBQUAD rgb[256];
+ } d;
+
+ if (dib.hSect)
+ return true;
+
+ memset(&d.bih, 0, sizeof(d.bih));
+ d.bih.biSize = sizeof(d.bih);
+ d.bih.biWidth = w;
+ d.bih.biHeight = -h;
+ d.bih.biPlanes = 1;
+ d.bih.biBitCount = 8;
+ d.bih.biCompression = BI_RGB;
+
+ memcpy(d.rgb, dib.pal, 256*sizeof(RGBQUAD));
+ dib.new_pal=false;
+
+ dib.hSect = CreateDIBSection(0, (BITMAPINFO*)&d, DIB_RGB_COLORS, (void**)&dib.buf,
+ NULL, NULL);
+
+ return dib.hSect != NULL;
+}
+
+void WndMan::writeToScreen() {
+ RECT r;
+ HDC dc,bmpdc;
+ HBITMAP bmpOld;
+// if (!BmpBG)
+// BmpBG = (byte*)LocalAlloc(LMEM_FIXED, DEST_WIDTH*DEST_HEIGHT);
+#if DEST_WIDTH==640
+ copy_320x200_to_640x400(_vgabuf, dib.buf);
+#endif
+#if DEST_WIDTH==320
+ if (_vgabuf) {
+ for (int y=0; y<200; y++) {
+ memcpy(dib.buf + y*320,_vgabuf + y*320, 320);
+ }
+ }
+#endif
+
+// setsel(dib.buf);
+
+ r.left = r.top = 0;
+ r.right = DEST_WIDTH;
+ r.bottom = DEST_HEIGHT;
+
+ dc = GetDC(hWnd);
+
+ bmpdc = CreateCompatibleDC(dc);
+ bmpOld = (HBITMAP)SelectObject(bmpdc, dib.hSect);
+
+ if (dib.new_pal) {
+ dib.new_pal = false;
+ SetDIBColorTable(bmpdc, 0, 256, dib.pal);
+ }
+
+ SetStretchBltMode(dc, BLACKONWHITE);
+#if DEST_WIDTH==640
+ StretchBlt(dc, r.left, r.top, r.right-r.left, r.bottom-r.top, bmpdc, 0, 0, 640,480, SRCCOPY);
+#endif
+
+#if DEST_WIDTH==320
+ StretchBlt(dc, r.left, r.top, r.right-r.left, r.bottom-r.top, bmpdc, 0, 0, 320,200, SRCCOPY);
+#endif
+// //StretchDIBits(dc, r.left, r.top, r.right - r.left, r.bottom - r.top, 0, 0, DEST_WIDTH, DEST_HEIGHT, BmpBG, biHeader, DIB_RGB_COLORS, SRCCOPY);
+
+
+ SelectObject(bmpdc, bmpOld);
+ DeleteDC(bmpdc);
+ ReleaseDC(hWnd, dc);
+}
+
+void WndMan::setPalette(byte *ctab, int first, int num) {
+ int i;
+
+#if 1
+ for (i=0; i<256; i++) {
+ dib.pal[i].rgbRed = ctab[i*3+0]<<2;
+ dib.pal[i].rgbGreen = ctab[i*3+1]<<2;
+ dib.pal[i].rgbBlue = ctab[i*3+2]<<2;
+ }
+#else
+ for (i=0; i<256; i++) {
+ dib.pal[i].rgbRed = i;
+ dib.pal[i].rgbGreen = i;
+ dib.pal[i].rgbBlue = i;
+ }
+#endif
+
+ dib.new_pal = true;
+}
+
+#endif
+
+#if USE_DIRECTX
+
+void WndMan::writeToScreen() {
+ RECT r;
+ DDSURFACEDESC2 dd;
+
+ r.left = r.top = 0;
+ r.right = SRC_WIDTH;
+ r.bottom = SRC_HEIGHT;
+
+ if (OutOfGame) {
+ if (GetForegroundWindow() != hWnd) return;
+ OutOfGame = false;
+ }
+
+ dd.dwSize = sizeof(dd);
+
+ int j;
+ do {
+ j = MainSurf->Lock(NULL, &dd, DDLOCK_WRITEONLY, NULL);
+ if (j!=DDERR_SURFACELOST) break;
+ if (MainSurf->Restore() != DD_OK) {
+ OutOfGame = true;
+ return;
+ }
+ } while (1);
+
+ if (j == DD_OK) {
+ byte *d = (byte*)dd.lpSurface;
+ byte *s = _vgabuf;
+
+ for(int h=SRC_HEIGHT;--h>=0; ) {
+ memcpy(d, s, SRC_WIDTH);
+ d+=dd.lPitch;
+ s+=SRC_PITCH;
+ }
+
+ MainSurf->Unlock(NULL);
+ }
+}
+
+void WndMan::setPalette(byte *ctab, int first, int num) {
+ PALETTEENTRY pal[256];
+
+ for (int i=0; i<256; i++) {
+ pal[i].peFlags = 0;
+ pal[i].peRed = *ctab++;
+ pal[i].peGreen = *ctab++;
+ pal[i].peBlue = *ctab++;
+ }
+
+ DxPal->SetEntries(0, 0, 256, (PALETTEENTRY*)&pal);
+}
+
+IDirectDrawSurface4 *CreateMainSurface(IDirectDraw4 *dd);
+
+void WndMan::InitDirectX() {
+
+ if (DirectDrawCreate(NULL, &DxObject, NULL) != DD_OK) Error("DirectDrawCreate failed!");
+ if (DxObject->QueryInterface(IID_IDirectDraw4, (void**)&Dx4Object) != DD_OK) Error("QueryInterface failed!");
+
+if (Dx4Object->SetCooperativeLevel(hWnd,DDSCL_NORMAL) != DD_OK) Error("SetCooperativeLevel failed!");
+
+ DDCAPS ddcaps;
+ BOOL bHasOverlay, bHasColorKey, bCanStretch;
+ ddcaps.dwSize = sizeof( ddcaps );
+ if (Dx4Object->GetCaps(&ddcaps, NULL ) != DD_OK) Error("GetCaps failed!");
+
+ /* Determine if the hardware supports overlay surfaces */
+ bHasOverlay = ddcaps.dwCaps & DDCAPS_OVERLAY;
+
+ /* Determine if the hardware supports colorkeying */
+ bHasColorKey = ((ddcaps.dwCaps & DDCAPS_COLORKEY) == DDCAPS_COLORKEY) ? TRUE : FALSE;
+
+ /* Determine if the hardware supports scaling of the overlay surface */
+ bCanStretch = ((ddcaps.dwCaps & DDCAPS_OVERLAYSTRETCH) == DDCAPS_OVERLAYSTRETCH) ? TRUE : FALSE;
+
+ if ( ( ddcaps.dwCaps & DDCAPS_ALIGNBOUNDARYDEST ) ||
+ ( ddcaps.dwCaps & DDCAPS_ALIGNBOUNDARYSRC ) ||
+ ( ddcaps.dwCaps & DDCAPS_ALIGNSIZEDEST ) ||
+ ( ddcaps.dwCaps & DDCAPS_ALIGNSIZESRC ) ) {
+
+ Error("Alignment restriction!");
+ }
+
+ // Are any overlays available for use?
+ if ( ddcaps.dwMaxVisibleOverlays ==
+ ddcaps.dwCurrVisibleOverlays )
+ {
+ Error("No overlay free");
+
+ }
+
+
+ if (!bHasOverlay || !bHasColorKey || !bCanStretch) {
+ Error("Bad hardware!");
+ }
+
+ /* Create primary surface */
+
+ DDSURFACEDESC2 ddsd;
+ DDSCAPS ddscaps;
+ LPDIRECTDRAWSURFACE4 lpFrontBuffer;
+ LPDIRECTDRAWSURFACE4 lpBackBuffer;
+ LPDIRECTDRAWSURFACE4 lpPrimary;
+ HRESULT LastError;
+ RECT rectOverlaySource, rectOverlayDest;
+ DDOVERLAYFX ddofx;
+
+
+
+// if (!CreateMainSurface(Dx4Object))
+// Error("sad");
+
+ /* Create the primary surface */
+ memset(&ddsd, 0, sizeof(ddsd));
+ ddsd.dwSize = sizeof(ddsd);
+ ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE|DDSCAPS_FLIP |
+ DDSCAPS_COMPLEX |
+ DDSCAPS_VIDEOMEMORY;
+ ddsd.dwBackBufferCount = 1;
+
+ if (Dx4Object->CreateSurface(&ddsd, &lpPrimary, NULL) != DD_OK)
+ Error("Main surface creation failed!");
+
+ /* Create a flippable scaleable overlay surface */
+ ddsd.dwSize = sizeof(ddsd);
+ ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_BACKBUFFERCOUNT | DDSD_PIXELFORMAT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_FLIP | DDSCAPS_COMPLEX | DDSCAPS_VIDEOMEMORY;
+ ddsd.dwBackBufferCount = 1; /* One back buffer for triple buffering, set to 2 */
+ ddsd.dwWidth = 320;
+ ddsd.dwHeight = 240;
+// ddsd.ddckCKDestOverlay.dwColorSpaceLowValue = 0x123456;
+// ddsd.ddckCKDestOverlay.dwColorSpaceHighValue = 0x123456;
+
+
+ ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
+
+ ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
+ ddsd.ddpfPixelFormat.dwFourCC = 0;
+ ddsd.ddpfPixelFormat.dwRGBBitCount = 16;
+ ddsd.ddpfPixelFormat.dwRBitMask = 0x7C00; //0x7C00 is a hexadecimal memory address
+ ddsd.ddpfPixelFormat.dwGBitMask = 0x03e0;
+ ddsd.ddpfPixelFormat.dwBBitMask = 0x001F;
+ ddsd.ddpfPixelFormat.dwRGBAlphaBitMask = 0;
+
+// ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_PALETTEINDEXED8;
+// ddsd.ddpfPixelFormat.dwRGBBitCount = 8;
+
+ if ((LastError = Dx4Object->CreateSurface(&ddsd, &lpFrontBuffer, NULL)) != DD_OK) {
+ if (LastError==DDERR_NOOVERLAYHW )
+ Error("No hardware!");
+ else
+ Error("2nd surface failed");
+ }
+
+#if 0
+ if (Dx4Object->SetCooperativeLevel(hWnd, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE) != DD_OK) Error("SetCooperativeLevel failed!");
+ // if (Dx4Object->SetDisplayMode(SRC_WIDTH,SRC_HEIGHT,8,0,DDSDM_STANDARDVGAMODE) != DD_OK) Error("SetDisplayMode failed!");
+ if (!(MainSurf = CreateMainSurface(Dx4Object))) Error("CreateMainSurface failed!");
+ if (!(Surf2 = Create2ndSurface(Dx4Object, _vgabuf))) Error("Create 2ndSurface failed!");
+ if (!(DxPal = CreateGamePalette(Dx4Object))) Error("CreateGamePalette failed!");
+ if (MainSurf->SetPalette(DxPal) != DD_OK) Error("SetPalette Failed!");
+#endif
+
+}
+
+
+IDirectDrawSurface4 *CreateMainSurface(IDirectDraw4 *dd) {
+ DDSURFACEDESC2 d;
+ IDirectDrawSurface4 *ds;
+
+// if(dd->GetGDISurface(&ds) != DD_OK)
+// return NULL;
+
+ memset(&d, 0, sizeof(d));
+
+ d.dwSize = sizeof(d);
+ d.dwFlags = DDSD_CAPS;
+ d.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+
+ int i;
+ if ((i = dd->CreateSurface(&d, &ds, NULL)) != DD_OK)
+ return NULL;
+
+ return ds;
+}
+
+
+IDirectDrawSurface4 *Create2ndSurface(IDirectDraw4 *dd, byte *surfmem) {
+ DDSURFACEDESC2 d;
+ IDirectDrawSurface4 *ds;
+
+ memset(&d, 0, sizeof(d));
+
+ d.dwSize = sizeof(d);
+ d.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PITCH | /*DDSD_LPSURFACE |*/ DDSD_PIXELFORMAT;
+ d.dwWidth = 640/*SRC_WIDTH*/;
+ d.dwHeight = 480/*SRC_HEIGHT*/;
+ d.lPitch = 640;
+ d.lpSurface = surfmem;
+
+ d.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
+ d.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_PALETTEINDEXED8;
+ d.ddpfPixelFormat.dwRGBBitCount = 8;
+
+ d.ddsCaps.dwCaps = DDSCAPS_OVERLAY;
+
+ int i;
+ if ((i = dd->CreateSurface(&d, &ds, NULL)) != DD_OK)
+ return NULL;
+ return ds;
+}
+
+IDirectDrawPalette *CreateGamePalette(IDirectDraw4 *dd) {
+ PALETTEENTRY pal[256];
+ int i;
+ IDirectDrawPalette *p;
+
+ memset(&pal, 0, sizeof(pal));
+ if ((i=dd->CreatePalette(DDPCAPS_8BIT | DDPCAPS_ALLOW256, pal, &p, NULL)) != DD_OK)
+ return NULL;
+
+ return p;
+}
+
+#endif
+
+#if USE_DRAWDIB
+void WndMan::writeToScreen() {
+ RECT r;
+ HDC dc;
+
+ r.left = r.top = 0;
+ r.right = DEST_WIDTH/2;
+ r.bottom = DEST_HEIGHT/2;
+
+ dc = GetDC(hWnd);
+
+ DrawDibRealize(hdb, dc, TRUE);
+ DrawDibDraw(hdb, dc, r.left, r.top, r.right-r.left, r.bottom-r.top, biHeader, _vgabuf, 0, 0, 320, 240, 0);
+
+// StretchDIBits(dc, r.left, r.top, r.right - r.left, r.bottom - r.top, 0, 0, DEST_WIDTH, DEST_HEIGHT, BmpBG, biHeader, DIB_RGB_COLORS, SRCCOPY);
+ ReleaseDC(hWnd, dc);
+}
+
+void WndMan::setPalette(byte *ctab, int first, int num) {
+ PALETTEENTRY pal[256];
+ for (int i=0; i < num; i++,ctab+=3) {
+ pal[i].peFlags = 0;
+ pal[i].peRed = ctab[0];
+ pal[i].peGreen = ctab[1];
+ pal[i].peBlue = ctab[2];
+ }
+
+ DrawDibChangePalette(hdb, 0, 16, pal);
+
+ GetLastError();
+}
+
+
+#endif
+HWND globWnd;
+
+void WndMan::init() {
+
+ /* Retrieve the handle of this module */
+ hInst = GetModuleHandle(NULL);
+
+ /* Register the window class */
+ WNDCLASSEX wcex;
+ wcex.cbSize = sizeof(WNDCLASSEX);
+ wcex.style = CS_HREDRAW | CS_VREDRAW;
+ wcex.lpfnWndProc = (WNDPROC)WndProc;
+ wcex.cbClsExtra = 0;
+ wcex.cbWndExtra = 0;
+ wcex.hInstance = hInst;
+ wcex.hIcon = 0;
+ wcex.hCursor = ::LoadCursor(NULL, IDC_ARROW);
+ wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+ wcex.lpszMenuName = 0;
+ wcex.lpszClassName = "ScummVM";
+ wcex.hIconSm = 0;
+ if (!RegisterClassEx(&wcex))
+ Error("Cannot register window class!");
+
+#if USE_DIRECTX
+ hWnd = CreateWindow("ScummVM", "ScummVM", 0,
+ CW_USEDEFAULT, CW_USEDEFAULT, SRC_WIDTH, SRC_HEIGHT, NULL, NULL, hInst, NULL);
+
+ SetWindowLong(hWnd, GWL_USERDATA, (long)this);
+ SetWindowLong(hWnd, GWL_STYLE, 0);
+ ShowCursor(false);
+
+
+ InitDirectX();
+
+ ShowWindow(hWnd, SW_SHOW);
+#endif
+
+#if USE_GDI
+ globWnd = hWnd = CreateWindow("ScummVM", "ScummVM", WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT, CW_USEDEFAULT, DEST_WIDTH+10, DEST_HEIGHT+30, NULL, NULL, hInst, NULL);
+ SetWindowLong(hWnd, GWL_USERDATA, (long)this);
+// ShowCursor(false);
+
+ dib.pal = (RGBQUAD*)calloc(sizeof(RGBQUAD),256);
+ dib.new_pal = false;
+
+ if (!allocateDIB(DEST_WIDTH, DEST_HEIGHT))
+ Error("allocateDIB failed!");
+
+#if 0
+ biHeader = (BITMAPINFO*)LocalAlloc(LMEM_FIXED, sizeof(BITMAPINFOHEADER) + 1024 );
+ memset(biHeader, 0, sizeof(BITMAPINFOHEADER) + 1024);
+
+ biHeader->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ biHeader->bmiHeader.biWidth = DEST_WIDTH;
+ biHeader->bmiHeader.biHeight = -DEST_HEIGHT; /* top down */
+ biHeader->bmiHeader.biPlanes = 1;
+ biHeader->bmiHeader.biBitCount = 8; /* 256 colors */
+ biHeader->bmiHeader.biCompression = BI_RGB; /* uncompressed */
+#endif
+
+ ShowWindow(hWnd, SW_SHOW);
+#endif
+
+#if USE_DRAWDIB
+ hdb = DrawDibOpen();
+
+ hWnd = CreateWindow("ScummVM", "ScummVM", WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT, CW_USEDEFAULT, DEST_WIDTH+10, DEST_HEIGHT+30, NULL, NULL, hInst, NULL);
+ SetWindowLong(hWnd, GWL_USERDATA, (long)this);
+ ShowCursor(false);
+
+ biHeader = (BITMAPINFOHEADER*)LocalAlloc(LMEM_FIXED, sizeof(BITMAPINFOHEADER));
+ memset(biHeader, 0, sizeof(BITMAPINFOHEADER));
+
+ biHeader->biSize = sizeof(BITMAPINFOHEADER);
+ biHeader->biWidth = SRC_PITCH;
+ biHeader->biHeight = SRC_HEIGHT; /* top down */
+ biHeader->biPlanes = 1;
+ biHeader->biBitCount = 8; /* 256 colors */
+ biHeader->biCompression = BI_RGB; /* uncompressed */
+
+ ShowWindow(hWnd, SW_SHOW);
+
+// int k = DrawDibProfileDisplay(biHeader);
+// printf("%d\n", k&PD_CAN_STRETCHDIB);
+
+
+#endif
+}
+
+
+bool WndMan::handleMessage() {
+ MSG msg;
+
+ if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+ return false;
+
+ if (msg.message==WM_QUIT) {
+ terminated=true;
+ exit(1);
+ return true;
+ }
+
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+
+ return true;
+}
+
+
+unsigned long rdtsc_timer;
+
+void _declspec(naked) beginpentiumtest() {
+ _asm {
+ rdtsc
+ mov rdtsc_timer,eax
+ ret
+ }
+}
+
+int _declspec(naked) endpentiumtest() {
+ _asm {
+ rdtsc
+ sub eax,rdtsc_timer
+ ret
+ }
+}
+
+
+
+#ifdef _DEBUG
+
+void decompressMask(byte *d, byte *s) {
+ int x,y;
+ byte bits = 0x80, bdata = *s++;
+
+ for (y=0; y<144; y++)
+ for (x=0; x<320; x++) {
+ *d++ = (bdata & bits) ? 128 : 0;
+ bits>>=1;
+ if (!bits) {
+ bdata = *s++;
+ bits=0x80;
+ }
+ }
+}
+
+
+
+void outputdisplay2(Scumm *s, int disp) {
+ byte *old = wm->_vgabuf;
+ switch(disp) {
+ case 0:
+ wm->_vgabuf = s->getResourceAddress(0xA, 5);
+ break;
+ case 1:
+ wm->_vgabuf = s->getResourceAddress(0xA, 1);
+ break;
+ case 2:
+ wm->_vgabuf = NULL;
+ decompressMask(wm->dib.buf, s->getResourceAddress(0xA, 9)+s->_screenStartStrip);
+ break;
+ case 3:
+ wm->_vgabuf = NULL;
+ decompressMask(wm->dib.buf, s->getResourceAddress(0xA, 9)+5920+s->_screenStartStrip);
+ break;
+ case 4:
+ wm->_vgabuf = NULL;
+ decompressMask(wm->dib.buf, s->getResourceAddress(0xA, 9)+5920*2+s->_screenStartStrip);
+ break;
+ case 5:
+ wm->_vgabuf = NULL;
+ decompressMask(wm->dib.buf, s->getResourceAddress(0xA, 9)+5920*3+s->_screenStartStrip);
+ break;
+ }
+ wm->writeToScreen();
+ wm->_vgabuf = old;
+}
+#endif
+
+#if 0
+void outputdisplay(Scumm *s) {
+ s->drawMouse();
+ wm->writeToScreen();
+}
+#endif
+
+void blitToScreen(Scumm *s, byte *src,int x, int y, int w, int h) {
+ byte *dst;
+ SDL_Rect *r;
+ int i;
+
+ dst = (byte*)wm->_vgabuf + y*320 + x;
+
+ do {
+ memcpy(dst, src, w);
+ dst += 320;
+ src += 320;
+ } while (--h);
+
+}
+
+void updateScreen(Scumm *s) {
+ if (s->_palDirtyMax != -1) {
+ wm->setPalette(s->_currentPalette, 0, 256);
+ s->_palDirtyMax = -1;
+ }
+
+ wm->writeToScreen();
+}
+
+void waitForTimer(Scumm *s) {
+ Sleep(10);
+ s->_scummTimer+=2;
+ wm->handleMessage();
+}
+
+#undef main
+int main(int argc, char* argv[]) {
+ scumm._videoMode = 0x13;
+
+ wm->init();
+ wm->_vgabuf = (byte*)calloc(320,200);
+ wm->_scumm = &scumm;
+
+ scumm.scummMain();
+
+ return 0;
+}
+