diff options
author | Ludvig Strigeus | 2001-10-09 14:30:12 +0000 |
---|---|---|
committer | Ludvig Strigeus | 2001-10-09 14:30:12 +0000 |
commit | c30932afbe1af874e3a2aeb95fa4ee5de4d6e38e (patch) | |
tree | 192b56f3908880c5a513a366f616341bcb47056e | |
download | scummvm-rg350-c30932afbe1af874e3a2aeb95fa4ee5de4d6e38e.tar.gz scummvm-rg350-c30932afbe1af874e3a2aeb95fa4ee5de4d6e38e.tar.bz2 scummvm-rg350-c30932afbe1af874e3a2aeb95fa4ee5de4d6e38e.zip |
Initial revision
svn-id: r3408
-rw-r--r-- | Makefile | 26 | ||||
-rw-r--r-- | actor.cpp | 953 | ||||
-rw-r--r-- | boxes.cpp | 839 | ||||
-rw-r--r-- | copying.txt | 341 | ||||
-rw-r--r-- | costume.cpp | 701 | ||||
-rw-r--r-- | gfx.cpp | 1645 | ||||
-rw-r--r-- | object.cpp | 584 | ||||
-rw-r--r-- | readme.txt | 48 | ||||
-rw-r--r-- | resource.cpp | 647 | ||||
-rw-r--r-- | saveload.cpp | 59 | ||||
-rw-r--r-- | script.cpp | 2857 | ||||
-rw-r--r-- | scumm.h | 1234 | ||||
-rw-r--r-- | scummsys.h | 152 | ||||
-rw-r--r-- | scummvm.cpp | 810 | ||||
-rw-r--r-- | scummvm.dsp | 175 | ||||
-rw-r--r-- | scummvm.dsw | 29 | ||||
-rw-r--r-- | sdl.cpp | 213 | ||||
-rw-r--r-- | sound.cpp | 86 | ||||
-rw-r--r-- | stdafx.cpp | 8 | ||||
-rw-r--r-- | stdafx.h | 58 | ||||
-rw-r--r-- | string.cpp | 697 | ||||
-rw-r--r-- | sys.cpp | 164 | ||||
-rw-r--r-- | verbs.cpp | 288 | ||||
-rw-r--r-- | whatsnew.txt | 4 | ||||
-rw-r--r-- | windows.cpp | 787 |
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; +} + |