diff options
author | Gregory Montoir | 2003-10-09 09:09:40 +0000 |
---|---|---|
committer | Gregory Montoir | 2003-10-09 09:09:40 +0000 |
commit | 91aaef03bc57bdf1284c3404b96b983d03695194 (patch) | |
tree | 9d68fc8818198ac7a5ec2eacf4c05dcdd5599e68 | |
parent | efef7ff6a26c4cff4736a9f463a965c211075144 (diff) | |
download | scummvm-rg350-91aaef03bc57bdf1284c3404b96b983d03695194.tar.gz scummvm-rg350-91aaef03bc57bdf1284c3404b96b983d03695194.tar.bz2 scummvm-rg350-91aaef03bc57bdf1284c3404b96b983d03695194.zip |
added walking functions
svn-id: r10695
-rw-r--r-- | queen/cutaway.cpp | 8 | ||||
-rw-r--r-- | queen/graphics.cpp | 143 | ||||
-rw-r--r-- | queen/graphics.h | 26 | ||||
-rw-r--r-- | queen/logic.cpp | 130 | ||||
-rw-r--r-- | queen/logic.h | 37 | ||||
-rw-r--r-- | queen/module.mk | 3 | ||||
-rw-r--r-- | queen/resource.h | 2 | ||||
-rw-r--r-- | queen/structs.h | 26 | ||||
-rw-r--r-- | queen/walk.cpp | 396 | ||||
-rw-r--r-- | queen/walk.h | 129 |
10 files changed, 827 insertions, 73 deletions
diff --git a/queen/cutaway.cpp b/queen/cutaway.cpp index e8190817bc..248acb952a 100644 --- a/queen/cutaway.cpp +++ b/queen/cutaway.cpp @@ -984,12 +984,12 @@ void Cutaway::updateGameState() { // Turn area on or off if (areaSubIndex > 0) { - int16 *area = _logic->area(areaIndex, areaSubIndex); - area[0] = abs(area[0]); + Area *area = _logic->area(areaIndex, areaSubIndex); + area->mapNeighbours = abs(area->mapNeighbours); } else { - int16 *area = _logic->area(areaIndex, abs(areaSubIndex)); - area[0] = -abs(area[0]); + Area *area = _logic->area(areaIndex, abs(areaSubIndex)); + area->mapNeighbours = -abs(area->mapNeighbours); } } diff --git a/queen/graphics.cpp b/queen/graphics.cpp index 81a831201d..65afe85871 100644 --- a/queen/graphics.cpp +++ b/queen/graphics.cpp @@ -276,7 +276,10 @@ Graphics::Graphics(Resource *resource) _shrinkBuffer.data = new uint8[ BOB_SHRINK_BUF_SIZE ]; _backdrop = new uint8[ BACKDROP_W * BACKDROP_H ]; _panel = new uint8[ PANEL_W * PANEL_H ]; - + _screen = new uint8[ SCREEN_W * SCREEN_H ]; + _fullscreen = true; + _horizontalScroll = 0; + _palette = new uint8[ 256 * 4 ]; } @@ -285,10 +288,12 @@ Graphics::~Graphics() { for(i = 0; i < ARRAYSIZE(_banks); ++i) { delete _banks[i].data; } -// frameClearAll(); + frameEraseAll(true); delete[] _shrinkBuffer.data; delete[] _backdrop; delete[] _panel; + delete[] _screen; + delete[] _palette; } @@ -369,6 +374,16 @@ void Graphics::bankErase(uint32 bankslot) { } +void Graphics::bobSetupControl() { + + bankLoad("control.BBK",17); + bankUnpack(1, 1, 17); // Mouse pointer + bankUnpack(3, 3, 17); // Up arrow dialogue + bankUnpack(4, 4, 17); // Down arrow dialogue + bankErase(17); +} + + void Graphics::bobAnimString(uint32 bobnum, uint8* animBuf) { BobSlot *pbs = &_bobs[bobnum]; @@ -400,6 +415,8 @@ void Graphics::bobAnimNormal(uint32 bobnum, uint16 firstFrame, uint16 lastFrame, void Graphics::bobMove(uint32 bobnum, uint16 endx, uint16 endy, int16 speed) { + debug(5, "Graphics::bobMove(%d, %d, %d, %d)", bobnum, endx, endy, speed); + BobSlot *pbs = &_bobs[bobnum]; pbs->active = true; @@ -408,7 +425,6 @@ void Graphics::bobMove(uint32 bobnum, uint16 endx, uint16 endy, int16 speed) { pbs->endx = endx; pbs->endy = endy; - // FIXME: can speed be negative or =0 ? the original sources does the check pbs->speed = (speed < 1) ? 1 : speed; int16 dx = endx - pbs->x; @@ -513,23 +529,23 @@ void BobSlot::animOneStep() { frameDir *= -1; } else { - frameNum = anim.normal.lastFrame - 1; + frameNum = anim.normal.firstFrame - 1; } - frameNum += frameDir; } + frameNum += frameDir; } } } - + void Graphics::bobDraw(uint32 bobnum, uint16 x, uint16 y, uint16 scale, bool xflip, const Box& box) { uint16 w, h; - debug(5, "Preparing to draw frame %d, scale = %d", bobnum, scale); + debug(5, "Preparing to draw frame %d, scale = %d, coords = (%d,%d)", bobnum, scale, x, y); BobFrame *pbf = &_frames[bobnum]; - if (scale < 100) { // Note: scale is unsigned, hence always >= 0 + if (scale < 100) { bobShrink(pbf, scale); pbf = &_shrinkBuffer; } @@ -565,18 +581,15 @@ void Graphics::bobDraw(uint32 bobnum, uint16 x, uint16 y, uint16 scale, bool xfl h_new = box.y2 - y + 1; } -// _display->ulines(w_new / 16, h_new, 2); - - // FIXME: original code blits to 'hidden' buffer src += w * y_skip; if (!xflip) { src += x_skip; - displayBlit(_backdrop, x, y, BACKDROP_W, src, w_new, h_new, w, xflip, true); + displayBlit(_screen, x, y, SCREEN_W, src, w_new, h_new, w, xflip, true); } else { src += w - w_new - x_skip; x += w_new - 1; - displayBlit(_backdrop, x, y, BACKDROP_W, src, w_new, h_new, w, xflip, true); + displayBlit(_screen, x, y, SCREEN_W, src, w_new, h_new, w, xflip, true); } } @@ -836,8 +849,6 @@ void Graphics::frameEraseAll(bool joe) { void Graphics::backdropLoad(const char* name, uint16 room) { -// _display->ulines(2); - // init Dynalum char roomPrefix[20]; strcpy(roomPrefix, name); @@ -849,14 +860,14 @@ void Graphics::backdropLoad(const char* name, uint16 room) { error("Unable to load backdrop : '%s'", name); } -// uint32 size = _resource->fileSize(name); -// _display->setPal(pcxbuf + size - 768, 0, (room <= 144) ? 144 : 256); + uint32 size = _resource->fileSize(name); + displaySetPal(pcxbuf + size - 768, 0, (room <= 144) ? 144 : 256); _backdropWidth = READ_LE_UINT16(pcxbuf + 12); _backdropHeight = READ_LE_UINT16(pcxbuf + 14); if (_backdropHeight == 150) { -// _display->_fullscreen = 0; + _fullscreen = false; } if (room >= 90) { @@ -868,19 +879,43 @@ void Graphics::backdropLoad(const char* name, uint16 room) { } +void Graphics::backdropDraw() { + + int n = 3; + if (_fullscreen) { + n = 4; + } + uint8 *dst = _screen; + uint8 *src = _backdrop + _horizontalScroll; + while (n--) { + int i; + for (i = 0; i < 50; ++i) { + memcpy(dst, src, SCREEN_W); + dst += SCREEN_W; + src += BACKDROP_W; + } + } +} + + void Graphics::panelLoad() { uint8 *pcxbuf = _resource->loadFile("panel.pcx"); if (pcxbuf == NULL) { error("Unable to open panel file"); } -// uint32 size = _resource->fileSize("panel.pcx"); -// _display->setPal(pcxbuf + size - 768, 144, 256); + uint32 size = _resource->fileSize("panel.pcx"); + displaySetPal(pcxbuf + size - 768, 144, 256); readPCX(pcxbuf + 128, _panel + PANEL_W * 10, PANEL_W, PANEL_W, PANEL_H - 10); delete[] pcxbuf; } +void Graphics::panelDraw() { + memcpy(_screen + SCREEN_W * ROOM_ZONE_HEIGHT, _panel, PANEL_W * PANEL_H); +} + + void Graphics::readPCX(const uint8 *src, uint8 *dst, uint16 dstPitch, uint16 w, uint16 h) { while (h--) { @@ -901,6 +936,21 @@ void Graphics::readPCX(const uint8 *src, uint8 *dst, uint16 dstPitch, uint16 w, } +void Graphics::boxDraw(const Box &b, uint8 color) { + + int x, y; + + for (y = b.y1; y <= b.y2; ++y) { + *(_backdrop + y * 640 + b.x1) = color; + *(_backdrop + y * 640 + b.x2) = color; + } + for (x = b.x1; x <= b.x2; ++x) { + *(_backdrop + b.y1 * 640 + x) = color; + *(_backdrop + b.y2 * 640 + x) = color; + } +} + + void Graphics::useJournal() { // GameSettings* pgs int i; @@ -959,20 +1009,19 @@ void Graphics::journalBobPreDraw() { // GameSettings* pgs } - void Graphics::update() { // FIXME: incomplete ! bobSortAll(); -// panelDraw(); -// backdropDraw(); + panelDraw(); + backdropDraw(); bobDrawAll(); textDrawAll(); + displayScreen(); } void Graphics::displayText(const TextSlot *pts, uint16 y) { - // FIXME: original source uses hidden buffer (instead of _backdrop) uint16 x = pts->x; uint8 *str = (uint8*)pts->text; while (*str && x < GAME_SCREEN_WIDTH) { @@ -980,18 +1029,17 @@ void Graphics::displayText(const TextSlot *pts, uint16 y) { // if (_resource->_gameVersion->versionString[1] == 'F' && *str == 150) { // chr = 251; // } -// _display->ulines(2); if (pts->outlined) { - displayChar(_backdrop, BACKDROP_W, x - 1, y - 1, INK_OUTLINED_TEXT, pchr); - displayChar(_backdrop, BACKDROP_W, x , y - 1, INK_OUTLINED_TEXT, pchr); - displayChar(_backdrop, BACKDROP_W, x + 1, y - 1, INK_OUTLINED_TEXT, pchr); - displayChar(_backdrop, BACKDROP_W, x + 1, y , INK_OUTLINED_TEXT, pchr); - displayChar(_backdrop, BACKDROP_W, x + 1, y + 1, INK_OUTLINED_TEXT, pchr); - displayChar(_backdrop, BACKDROP_W, x , y + 1, INK_OUTLINED_TEXT, pchr); - displayChar(_backdrop, BACKDROP_W, x - 1, y + 1, INK_OUTLINED_TEXT, pchr); - displayChar(_backdrop, BACKDROP_W, x - 1, y , INK_OUTLINED_TEXT, pchr); + displayChar(x - 1, y - 1, INK_OUTLINED_TEXT, pchr); + displayChar(x , y - 1, INK_OUTLINED_TEXT, pchr); + displayChar(x + 1, y - 1, INK_OUTLINED_TEXT, pchr); + displayChar(x + 1, y , INK_OUTLINED_TEXT, pchr); + displayChar(x + 1, y + 1, INK_OUTLINED_TEXT, pchr); + displayChar(x , y + 1, INK_OUTLINED_TEXT, pchr); + displayChar(x - 1, y + 1, INK_OUTLINED_TEXT, pchr); + displayChar(x - 1, y , INK_OUTLINED_TEXT, pchr); } - displayChar(_backdrop, BACKDROP_W, x, y, pts->color, pchr); + displayChar(x, y, pts->color, pchr); x += FONT_SIZES[ *str ]; ++str; @@ -999,10 +1047,10 @@ void Graphics::displayText(const TextSlot *pts, uint16 y) { } -void Graphics::displayChar(uint8 *dst, uint16 dstPitch, uint16 x, uint16 y, uint8 color, const uint8 *chr) { +void Graphics::displayChar(uint16 x, uint16 y, uint8 color, const uint8 *chr) { int i, j; - dst += y * dstPitch + x; + uint8 *dst = _screen + y * SCREEN_W + x; for (j = 0; j < 8; ++j) { uint8* p = dst; uint8 c = *chr++; @@ -1015,7 +1063,7 @@ void Graphics::displayChar(uint8 *dst, uint16 dstPitch, uint16 x, uint16 y, uint c <<= 1; } } - dst += dstPitch; + dst += SCREEN_W; } } @@ -1059,5 +1107,26 @@ void Graphics::displayBlit(uint8 *dst_buf, uint16 dst_x, uint16 dst_y, uint16 ds } +void Graphics::displaySetPal(uint8 *pal, int start, int end) { + int i; + pal += start * 3; + for (i = start; i < end; ++i, pal += 3) { + _palette[i << 2 | 0] = *(pal + 0); + _palette[i << 2 | 1] = *(pal + 1); + _palette[i << 2 | 2] = *(pal + 2); + _palette[i << 2 | 3] = 0; + } +} + + +void Graphics::displayScreen() { + // FIXME: temporary code ; cleanup/move to Display class. + OSystem *psys = g_engine->_system; + psys->set_palette(_palette, 0, 256); + psys->copy_rect(_screen, SCREEN_W, 0, 0, SCREEN_W, SCREEN_H); + psys->update_screen(); +} + + } // End of namespace Queen diff --git a/queen/graphics.h b/queen/graphics.h index 4033bf8a33..ee0c97dab6 100644 --- a/queen/graphics.h +++ b/queen/graphics.h @@ -114,6 +114,7 @@ public: void bankOverpack(uint32 srcframe, uint32 dstframe, uint32 bankslot); // overpackbank() void bankErase(uint32 bankslot); // erase() + void bobSetupControl(); void bobAnimString(uint32 bobnum, uint8* animBuf); // stringanim() void bobAnimNormal(uint32 bobnum, uint16 firstFrame, uint16 lastFrame, uint16 speed, bool rebound, bool xflip); // makeanim() void bobMove(uint32 bobnum, uint16 endx, uint16 endy, int16 speed); // movebob() @@ -136,28 +137,33 @@ public: void frameErase(uint32 fslot); void frameEraseAll(bool joe); // freeframes, freeallframes - void backdropLoad(const char* name, uint16 room); // loadbackdrop -// void backdropDraw(); + void backdropLoad(const char *name, uint16 room); // loadbackdrop + void backdropDraw(); void panelLoad(); // loadpanel -// void panelDraw(); + void panelDraw(); + + void boxDraw(const Box &b, uint8 color); void useJournal(); void journalBobSetup(uint32 bobnum, uint16 x, uint16 y, uint16 frame); void journalBobPreDraw(); void update(); - + void displayText(const TextSlot *pts, uint16 y); // FIXME: move to Display class - void displayChar(uint8 *dst, uint16 dstPitch, uint16 x, uint16 y, uint8 color, const uint8 *chr); // FIXME: move to Display class + void displayChar(uint16 x, uint16 y, uint8 color, const uint8 *chr); // FIXME: move to Display class static void displayBlit(uint8 *dst_buf, uint16 dst_x, uint16 dst_y, uint16 dst_pitch, const uint8 *src_buf, uint16 src_w, uint16 src_h, uint16 src_pitch, bool xflip, bool masked); // FIXME: move to Display class - + void displaySetPal(uint8 *pal, int start, int end); + void displayScreen(); private: enum { BACKDROP_W = 640, BACKDROP_H = 200, + SCREEN_W = 320, + SCREEN_H = 200, PANEL_W = 320, PANEL_H = 50, BOB_SHRINK_BUF_SIZE = 60000 @@ -195,6 +201,14 @@ private: //! current room bitmap uint8 *_backdrop; + uint8 *_screen; + + bool _fullscreen; + + uint16 _horizontalScroll; + + uint8 *_palette; + //! panel storage area uint8 *_panel; diff --git a/queen/logic.cpp b/queen/logic.cpp index a018880772..0c14adf345 100644 --- a/queen/logic.cpp +++ b/queen/logic.cpp @@ -20,6 +20,7 @@ */ #include "queen/logic.h" +#include "queen/defs.h" namespace Queen { @@ -36,7 +37,7 @@ Logic::~Logic() { } void Logic::initialise() { - int16 i, j, k; + int16 i, j; uint8 *ptr = _jas; //_display->loadFont(); @@ -144,7 +145,7 @@ void Logic::initialise() { _objMax = new int16[_numRooms + 1]; _areaMax = new int16[_numRooms + 1]; - _area = new int16[_numRooms + 1][11][8]; + _area = new Area[_numRooms + 1][11]; for (i = 1; i <= _numRooms; i++) { _objMax[i] = (int16)READ_BE_UINT16(ptr); @@ -152,12 +153,17 @@ void Logic::initialise() { _areaMax[i] = (int16)READ_BE_UINT16(ptr); ptr += 2; - for (j = 1; j <= _areaMax[i]; j++) - for (k = 0; k < 8; k++) { - assert(j < 11); - _area[i][j][k] = READ_BE_UINT16(ptr); - ptr += 2; - } + for (j = 1; j <= _areaMax[i]; j++) { + assert(j < 11); + _area[i][j].mapNeighbours = READ_BE_UINT16(ptr); ptr += 2; + _area[i][j].box.x1 = READ_BE_UINT16(ptr); ptr += 2; + _area[i][j].box.y1 = READ_BE_UINT16(ptr); ptr += 2; + _area[i][j].box.x2 = READ_BE_UINT16(ptr); ptr += 2; + _area[i][j].box.y2 = READ_BE_UINT16(ptr); ptr += 2; + _area[i][j].bottomScaleFactor = READ_BE_UINT16(ptr); ptr += 2; + _area[i][j].topScaleFactor = READ_BE_UINT16(ptr); ptr += 2; + _area[i][j].object = READ_BE_UINT16(ptr); ptr += 2; + } } _objectBox = new Box[_numObjects + 1]; @@ -206,6 +212,8 @@ void Logic::initialise() { //Command List Data + + memset(_zones, 0, sizeof(_zones)); } uint16 Logic::currentRoom() { @@ -232,8 +240,8 @@ uint16 Logic::objMax(int room) { return _objMax[room]; } -int16 *Logic::area(int index, int subIndex) { - return _area[index][subIndex]; +Area *Logic::area(int index, int subIndex) { + return &_area[index][subIndex]; } uint16 Logic::walkOffCount() { @@ -360,7 +368,7 @@ uint16 Logic::findFrame(uint16 obj) { } } if(bobnum <= 3) { - framenum = 29 + FRAME_XTRA; + framenum = 29 + FRAMES_JOE_XTRA; } } else { @@ -414,7 +422,7 @@ uint16 Logic::findFrame(uint16 obj) { // calculate only if there are person frames if(idx > 0) { - framenum = 36 + _maxStaticFrame + _maxAnimatedFrameLen + idx + FRAME_XTRA; + framenum = 36 + _maxStaticFrame + _maxAnimatedFrameLen + idx + FRAMES_JOE_XTRA; } } return framenum; @@ -432,6 +440,10 @@ void Logic::joeY(uint16 y) { _joe.y = y; } +void Logic::joeWalk(uint16 walk) { + _joe.walk = walk; +} + int16 Logic::gameState(int index) { if (index >= 0 && index < GAME_STATE_COUNT) return _gameState[index]; @@ -447,5 +459,99 @@ void Logic::gameState(int index, int16 newValue) { } +void Logic::zoneSet(uint16 screen, uint16 zone, uint16 x1, uint16 y1, uint16 x2, uint16 y2) { + + ZoneSlot *pzs = &_zones[screen][zone]; + pzs->valid = true; + pzs->box.x1 = x1; + pzs->box.y1 = y1; + pzs->box.x2 = x2; + pzs->box.y2 = y2; +} + + +void Logic::zoneSet(uint16 screen, uint16 zone, const Box& box) { + + debug(9, "Logic::zoneSet(%d, %d, (%d,%d), (%d,%d))", screen, zone, box.x1, box.y1, box.x2, box.y2); + + ZoneSlot *pzs = &_zones[screen][zone]; + pzs->valid = true; + pzs->box = box; +} + + +uint16 Logic::zoneIn(uint16 screen, uint16 x, uint16 y) { + + int i; + if (screen == ZONE_PANEL) { + y -= ROOM_ZONE_HEIGHT; + } + for(i = 1; i < MAX_ZONES_NUMBER; ++i) { + ZoneSlot *pzs = &_zones[screen][i]; + if (pzs->valid && pzs->box.contains(x, y)) { + return i; + } + } + return 0; +} + + +uint16 Logic::zoneInArea(uint16 screen, uint16 x, uint16 y) { + uint16 zone = zoneIn(screen, x, y); + if (zone <= _objMax[_currentRoom]) { + zone = 0; + } + else { + zone -= _objMax[_currentRoom]; + } + return zone; +} + + +void Logic::zoneClearAll(uint16 screen) { + + int i; + for(i = 1; i < MAX_ZONES_NUMBER; ++i) { + _zones[screen][i].valid = false; + } +} + + +void Logic::zoneSetup() { + + zoneClearAll(ZONE_ROOM); + + int i; + int zoneNum; + + // setup objects zones + uint16 maxObjRoom = _objMax[_currentRoom]; + uint16 objRoomNum = _roomData[_currentRoom]; + zoneNum = 1; + for (i = objRoomNum + 1; i <= objRoomNum + maxObjRoom; ++i) { + if (_objectData[i].name != 0) { + zoneSet(ZONE_ROOM, zoneNum, _objectBox[i]); + } + ++zoneNum; + } + + // setup room zones (areas) + uint16 maxAreaRoom = _areaMax[_currentRoom]; + for (zoneNum = 1; zoneNum <= maxAreaRoom; ++zoneNum) { + zoneSet(ZONE_ROOM, maxObjRoom + zoneNum, _area[_currentRoom][zoneNum].box); + } +} + + +uint16 Logic::findScale(uint16 x, uint16 y) { + uint16 scale = 100; + uint16 areaNum = zoneInArea(ZONE_ROOM, x, y); + if(areaNum != 0) { + scale = _area[_currentRoom][areaNum].calcScale(y); + } + return scale; +} + + } // End of namespace Queen diff --git a/queen/logic.h b/queen/logic.h index 226a53d9f8..d895ffe50e 100644 --- a/queen/logic.h +++ b/queen/logic.h @@ -27,17 +27,8 @@ namespace Queen { +#define MAX_ZONES_NUMBER 32 -enum { - FRAME_XTRA = 2 -}; - -enum { - LEFT = 1, - RIGHT = 2, - FRONT = 3, - BACK = 4 -}; enum Language { ENGLISH = 'E', @@ -46,6 +37,14 @@ enum Language { ITALIAN = 'I' }; +struct ZoneSlot { + bool valid; + Box box; +}; + + +class Graphics; + class Logic { public: @@ -63,23 +62,35 @@ public: uint16 findBob(uint16 obj); // FIXME: move that to QueenDisplay ? uint16 findFrame(uint16 obj); // FIXME: move that to QueenDisplay ? - int16 *area(int index, int subIndex); + Area *area(int index, int subIndex); uint16 walkOffCount(); WalkOffData *walkOffData(int index); uint16 joeFacing() { return _joe.facing; } uint16 joeX() { return _joe.x; } uint16 joeY() { return _joe.y; } + uint16 joeWalk() { return _joe.walk; } void joeFacing(uint16 dir); void joeX(uint16 x); void joeY(uint16 y); + void joeWalk(uint16 walk); int16 gameState(int index); void gameState(int index, int16 newValue); Language language() { return ENGLISH; } // FIXME: get from queen.jas + void zoneSet(uint16 screen, uint16 zone, uint16 x1, uint16 y1, uint16 x2, uint16 y2); + void zoneSet(uint16 screen, uint16 zone, const Box& box); + uint16 zoneIn(uint16 screen, uint16 x, uint16 y); + uint16 zoneInArea(uint16 screen, uint16 x, uint16 y); + void zoneClearAll(uint16 screen); + void zoneSetup(); + + uint16 findScale(uint16 x, uint16 y); + + protected: uint8 *_jas; uint16 _numRooms; @@ -106,8 +117,9 @@ protected: ObjectData *_objectData; ObjectDescription *_objectDescription; uint16 (*_actorData)[12]; // FIXME: ActorData *_actorData; - int16 (*_area)[11][8]; // FIXME: Area *_area[11]; + Area (*_area)[11]; WalkOffData *_walkOffData; + ZoneSlot _zones[2][MAX_ZONES_NUMBER]; enum { GAME_STATE_COUNT = 211 @@ -116,6 +128,7 @@ protected: struct { uint16 x, y; uint16 facing; + uint16 walk; } _joe; int16 _gameState[GAME_STATE_COUNT]; diff --git a/queen/module.mk b/queen/module.mk index 4ac2854f9c..b1e5235429 100644 --- a/queen/module.mk +++ b/queen/module.mk @@ -7,7 +7,8 @@ MODULE_OBJS = \ queen/queen.o \ queen/resource.o \ queen/restables.o \ - queen/talk.o + queen/talk.o \ + queen/walk.o MODULE_DIRS += \ queen diff --git a/queen/resource.h b/queen/resource.h index 41b6943941..8440b303af 100644 --- a/queen/resource.h +++ b/queen/resource.h @@ -62,6 +62,7 @@ public: uint8 *loadFile(const char *filename, uint32 skipBytes = 0); bool exists(const char *filename); bool isDemo(); + uint32 fileSize(const char *filename); protected: File *_resourceFile; @@ -73,7 +74,6 @@ protected: static ResourceEntry _resourceTablePEM10[]; int32 resourceIndex(const char *filename); - uint32 fileSize(const char *filename); uint32 fileOffset(const char *filename); const char *JASVersion(); bool readTableFile(); diff --git a/queen/structs.h b/queen/structs.h index 6add058d03..37ebcb72e5 100644 --- a/queen/structs.h +++ b/queen/structs.h @@ -28,9 +28,21 @@ namespace Queen { struct Box { uint16 x1, y1, x2, y2; + int16 xDiff() const { + return (int16)(x1 - x2); + } + + int16 yDiff() const { + return (int16)(y1 - y2); + } + bool intersects(uint16 x, uint16 y, uint16 w, uint16 h) const { return (x + w > x1) && (y + h > y1) && (x <= x2) && (y <= y2); } + + bool contains(uint16 x, uint16 y) const { + return (x >= x1) && (x <= x2) && (y >= y1) && (y <= y2); + } }; @@ -40,6 +52,20 @@ struct Area { uint16 bottomScaleFactor; uint16 topScaleFactor; uint16 object; + + uint16 calcScale(int16 y) const { + uint16 dy = box.y2 - box.y1; + uint16 ds = topScaleFactor - bottomScaleFactor; + uint16 scale = ((((y - box.y1) * 100) / dy) * ds) / 100 + bottomScaleFactor; + if (scale == 0) { + scale = 100; + } + return scale; + } + + int16 scaleDiff() const { + return (int16)(topScaleFactor - bottomScaleFactor); + } }; diff --git a/queen/walk.cpp b/queen/walk.cpp new file mode 100644 index 0000000000..13a60e5f1e --- /dev/null +++ b/queen/walk.cpp @@ -0,0 +1,396 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2003 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#include "queen/walk.h" +#include "queen/logic.h" +#include "queen/graphics.h" +#include "queen/defs.h" + +namespace Queen { + + +Walk::Walk(Logic *logic, Graphics *graphics) + : _logic(logic), _graphics(graphics) { +} + + +uint16 Walk::joeFace(uint16 prevFacing, uint16 scale) { + BobSlot *pbs = _graphics->bob(0); + uint16 frame; + if (_logic->currentRoom() == 108) { + frame = 1; + } + else { + frame = 33; + if (_logic->joeFacing() == DIR_FRONT) { + frame = 34; + } + if (_logic->joeFacing() == DIR_BACK) { + frame = 35; + } + // FIXME: handle prevFacing + pbs->frameNum = frame + FRAMES_JOE_XTRA; + pbs->scale = scale; + pbs->xflip = (_logic->joeFacing() == DIR_LEFT); + _graphics->update(); + // joePrevFacing = joeFacing; + switch (frame) { + case 33: frame = 1; break; + case 34: frame = 3; break; + case 35: frame = 5; break; + } + } + pbs->frameNum = 29 + FRAMES_JOE_XTRA; + _graphics->bankUnpack(frame, pbs->frameNum, 7); + return frame; +} + + +void Walk::joeMoveBlock() { + warning("Walk::moveJoeBlock() unimplemented"); +} + + +void Walk::animatePersonPrepare() { + // queen.c l.2748-2788 + int i; + for (i = 1; i <= _walkDataCount; ++i) { + + MovePersonAnim *mpa = &_moveAnim[i]; + WalkData *pwd = &_walkData[i]; + mpa->wx = pwd->dx; + mpa->wy = pwd->dy; + mpa->walkingArea = &_roomAreas[ pwd->area ]; + + if (mpa->wx < 0) { + mpa->setFrames(11, 16 + FRAMES_JOE_XTRA, DIR_LEFT); + } + else { + mpa->setFrames(11, 16 + FRAMES_JOE_XTRA, DIR_RIGHT); + } + + int16 k = ABS(mpa->wy); + int16 ds = mpa->walkingArea->scaleDiff(); + if (ds > 0) { + k *= ((k * ds) / mpa->walkingArea->box.yDiff()) / 2; + } + + if (ABS(mpa->wx) < k) { + if ((mpa->wy < 0 && ds < 0) || (mpa->wy > 0 && ds > 0)) { + mpa->setFrames(17 + FRAMES_JOE_XTRA, 22 + FRAMES_JOE_XTRA, DIR_FRONT); + } + else { + mpa->setFrames(23 + FRAMES_JOE_XTRA, 28 + FRAMES_JOE_XTRA, DIR_BACK); + } + } + } +} + + +void Walk::animatePerson() { + // queen.c l.2789-2835 + uint16 lastDirection = 0; + uint16 i; + BobSlot *pbs = _graphics->bob(0); + _logic->joeFacing(_moveAnim[1].facing); + joeFace(_logic->joeFacing(), _moveAnim[1].walkingArea->calcScale(pbs->y)); + bool interrupted = false; + for (i = 1; i <= _walkDataCount && !interrupted; ++i) { + MovePersonAnim *mpa = &_moveAnim[i]; + if (mpa->walkingArea->mapNeighbours < 0) { + joeMoveBlock(); + return; + } + if (lastDirection != mpa->facing) { + _graphics->bobAnimNormal(0, mpa->firstFrame, mpa->lastFrame, 1, false, false); + } + uint16 scale = _logic->findScale(pbs->x, pbs->y); + _graphics->bobMove(0, pbs->x + mpa->wx, pbs->y + mpa->wy, scale * 6 / 100); + pbs->xflip = (pbs->xdir < 0); + while (pbs->moving) { + // adjust Joe's movespeed according to scale + pbs->scale = mpa->walkingArea->calcScale(pbs->y); + if (pbs->xmajor) { + pbs->speed = pbs->scale * 6 / 100; + } + else { + pbs->speed = pbs->scale * 3 / 100; + } + if (pbs->speed == 0) { + pbs->speed = 1; + } + _graphics->update(); // CHECK_PLAYER(); + if (_logic->joeWalk() == 2) { // || cutQuit + // we are about to do something else, so stop walking + interrupted = true; + pbs->moving = false; + } + } + lastDirection = mpa->facing; + } +// if (!cutQuit) { + pbs->animating = false; + _logic->joeFacing(lastDirection); +// } +} + + +void Walk::joeSetup() { + int i; + + _graphics->bankLoad("joe_a.BBK", 13); + for (i = 11; i <= 28 + FRAMES_JOE_XTRA; ++i) { + _graphics->bankUnpack(i - 10, i, 13); + } + _graphics->bankErase(13); + + _graphics->bankLoad("joe_b.BBK", 7); + _graphics->bankUnpack(1, 33 + FRAMES_JOE_XTRA, 7); + _graphics->bankUnpack(3, 34 + FRAMES_JOE_XTRA, 7); + _graphics->bankUnpack(5, 35 + FRAMES_JOE_XTRA, 7); + + _logic->joeFacing(DIR_FRONT); +} + +void Walk::joeMove(int direction, uint16 oldx, uint16 oldy, uint16 newx, uint16 newy, bool inCutaway) { + + +// CAN=0 + initWalkData(); + + _logic->joeWalk(1); + + uint16 oldPos = _logic->zoneInArea(ZONE_ROOM, oldx, oldy); + uint16 newPos = _logic->zoneInArea(ZONE_ROOM, newx, newy); + + debug(9, "Walk::joeMove(%d, %d, %d, %d, %d), old = %d, new = %d", direction, oldx, oldy, newx, newy, oldPos, newPos); + + // if in cutaway, allow Joe to walk anywhere + if(newPos == 0 && inCutaway) { + incWalkData(oldx, oldy, newx, newy, oldPos); + } + else { + calc(oldPos, newPos, oldx, oldy, newx, newy); + } + + if (_walkDataCount > 0) { +//MOVE_JOE2: + animatePersonPrepare(); + animatePerson(); + } + else { +// SPEAK(JOE_RESPstr[4],"JOE",find_cd_desc(4)) + } +//MOVE_JOE_EXIT: +} + + +void Walk::setCurrentRoomAreas(const Area* roomAreas, uint16 roomAreasCount) { + + _roomAreas = roomAreas; + _roomAreasCount = roomAreasCount; +} + + +void Walk::calc(uint16 oldPos, uint16 newPos, uint16 oldx, uint16 oldy, uint16 x, uint16 y) { + + // if newPos is outside of an AREA then travers Y axis until an AREA is found + if (newPos == 0) { + newPos = findAreaPosition(&x, &y, true); + } + + // do the same for oldPos in case Joe somehow sits on the border of an AREA + // and does not register + if (oldPos == 0) { + oldPos = findAreaPosition(&oldx, &oldy, false); + } + + if (oldPos == newPos) { + incWalkData(oldx, oldy, x, y, newPos); + } + else if (calcPath(oldPos, newPos)) { + uint16 i; + uint16 px = oldx; + uint16 py = oldy; + for (i = 2; i <= _areaListCount; ++i) { + uint16 a1 = _areaList[i - 1]; + uint16 a2 = _areaList[i]; + const Area *pa1 = &_roomAreas[ a1 ]; + const Area *pa2 = &_roomAreas[ a2 ]; + uint16 x1 = calcC(pa1->box.x1, pa1->box.x2, pa2->box.x1, pa2->box.x2, px); + uint16 y1 = calcC(pa1->box.y1, pa1->box.y2, pa2->box.y1, pa2->box.y2, py); + incWalkData(px, py, x1, y1, a1); + px = x1; + py = y1; + } + incWalkData(px, py, x, y, newPos); + } +} + + +uint16 Walk::calcC(uint16 c1, uint16 c2, uint16 c3, uint16 c4, uint16 lastc) { + uint16 s1 = MAX(c1, c3); + uint16 s2 = MIN(c2, c4); + uint16 c = (s1 + s2) / 2; + if ((lastc >= s1 && lastc <= s2) || (lastc >= s2 && lastc <= s1)) { + c = lastc; + } + return c; +} + + +int16 Walk::findAreaPosition(uint16 *x, uint16 *y, bool recalibrate) { + uint16 i; + uint16 pos = 1; + const Box *b = &_roomAreas[1].box; + uint16 tx = b->x1; + uint16 bx = b->x2; + uint16 ty = b->y1; + uint16 by = b->y2; + uint16 prevClosestFace = 640; + for (i = 1; i <= _roomAreasCount; ++i) { + b = &_roomAreas[i].box; + uint16 dx1 = ABS(b->x1 - *x); + uint16 dx2 = ABS(b->x2 - *x); + uint16 dy1 = ABS(b->y1 - *y); + uint16 dy2 = ABS(b->y2 - *y); + uint16 csx = MIN(dx1, dx2); + uint16 csy = MIN(dy1, dy2); + uint16 curClosestFace = 640; + // check to see if X lies in X range + if (*x >= b->x1 && *x <= b->x2) { + // it is, so record closest Y face distance + curClosestFace = csy; + } + else if (*y >= b->y1 && *y <= b->y2) { + // record, closest X face distance + curClosestFace = csx; + } + if (curClosestFace < prevClosestFace) { + tx = dx1; + ty = dy1; + bx = dx2; + by = dy2; + pos = i; + prevClosestFace = curClosestFace; + } + } + // we now have the closest area near X,Y, so we can recalibrate + // the X,Y coord to be in this area + if (recalibrate) { + b = &_roomAreas[pos].box; + if(*x < b->x1) *x = b->x1; + if(*x > b->x2) *x = b->x2; + if(*y < b->y1) *y = b->y1; + if(*y > b->y2) *y = b->y2; + } + return pos; +} + + +uint16 Walk::findFreeArea(uint16 area) const { + + uint16 testArea; + uint16 freeArea = 0; + uint16 map = ABS(_roomAreas[area].mapNeighbours); + for (testArea = 1; testArea <= _roomAreasCount; ++testArea) { + int b = _roomAreasCount - testArea; + if (map & (1 << b)) { + // connecting area, check if it's been struck off + if(!isAreaStruck(testArea)) { + // legitimate connecting area, keep it + freeArea = testArea; + break; + } + } + } + return freeArea; +} + + +bool Walk::isAreaStruck(uint16 area) const { + + uint16 i; + bool found = false; + for (i = 1; i <= _areaStrikeCount; ++i) { + if (_areaStrike[i] == area) { + found = true; + break; + } + } + return found; +} + + +bool Walk::calcPath(uint16 oldArea, uint16 newArea) { + + debug(9, "Walk::calcPath(%d, %d)", oldArea, newArea); + _areaList[1] = _areaStrike[1] = oldArea; + _areaListCount = _areaStrikeCount = 1; + uint16 area = oldArea; + while (_areaListCount > 0 && area != newArea) { + area = findFreeArea(area); + if (!area) { + // wrong path, rolling back + _areaList[_areaListCount] = 0; + --_areaListCount; + area = _areaList[_areaListCount]; + } + else { + ++_areaListCount; + _areaList[_areaListCount] = area; + if(!isAreaStruck(area)) { + ++_areaStrikeCount; + _areaStrike[_areaStrikeCount] = area; + } + } + } + // CAN = -1 if no connection is made, else 0 + return _areaList[1] != 0; +} + + +void Walk::initWalkData() { + _walkDataCount = 0; + memset(_walkData, 0, sizeof(_walkData)); + _areaStrikeCount = 0; + memset(_areaStrike, 0, sizeof(_areaStrike)); + _areaListCount = 0; + memset(_areaList, 0, sizeof(_areaList)); +} + + +void Walk::incWalkData(uint16 px, uint16 py, uint16 x, uint16 y, uint16 area) { + + debug(9, "Walk::incWalkData(%d, %d, %d)", (int16)(x - px), (int16)(y - py), area); + + if (px != x || py != y) { + ++_walkDataCount; + WalkData *pwd = &_walkData[_walkDataCount]; + pwd->dx = x - px; + pwd->dy = y - py; + pwd->area = area; +// pwd->sign = ((pwd->dx < 0) ? -1 : ((pwd->dx > 0) ? 1 : 0)) ; + } +} + + +} // End of namespace Queen diff --git a/queen/walk.h b/queen/walk.h new file mode 100644 index 0000000000..4f6e57624b --- /dev/null +++ b/queen/walk.h @@ -0,0 +1,129 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2003 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#ifndef QUEENWALK_H +#define QUEENWALK_H + +#include "queen/queen.h" +#include "queen/structs.h" + +namespace Queen { + + +#define MAX_AREAS 11 + + +struct WalkData { +// int16 sign; // never used + int16 dx, dy; + int16 area; +}; + +struct MovePersonAnim { + int16 wx; + int16 wy; + uint16 firstFrame; + uint16 lastFrame; + uint16 facing; + const Area *walkingArea; + + void setFrames(uint16 ff, uint16 lf, uint16 face) { + firstFrame = ff; + lastFrame = lf; + facing = face; + } +}; + + +class Logic; +class Graphics; + +class Walk { +public: + + Walk(Logic* logic, Graphics* graphics); + + void joeSetup(); + + void setCurrentRoomAreas(const Area* roomAreas, uint16 roomAreasCount); + + //! MOVE_JOE() + void joeMove(int dir, uint16 oldx, uint16 oldy, uint16 newx, uint16 newy, bool inCutaway); + + //! FACE_JOE() + uint16 joeFace(uint16 prevFacing, uint16 scale); + + +private: + + + void joeMoveBlock(); + + void animatePersonPrepare(); + + void animatePerson(); + + //! CALC_X, CALC_Y + static uint16 calcC(uint16 c1, uint16 c2, uint16 c3, uint16 c4, uint16 lastc); + + //! FIND_OLDP, FIND_NEWP + int16 findAreaPosition(uint16 *x, uint16 *y, bool recalibrate); + + //! FIND_FREE_AREA, find an area not already struck + uint16 findFreeArea(uint16 area) const; + + //! + bool isAreaStruck(uint16 area) const; + + //! CALC_PATH, calculates the path list from oldArea to newArea + bool calcPath(uint16 oldArea, uint16 newArea); + + //! resets path computed in calcPath() + void initWalkData(); + + //! CALC_WALK + void incWalkData(uint16 px, uint16 py, uint16 x, uint16 y, uint16 area); + + //! equivalent to l.2432,2469 MOVE_OTHER() and l.2696,2744 MOVE_JOE() + void calc(uint16 oldPos, uint16 newPos, uint16 oldx, uint16 oldy, uint16 x, uint16 y); + + + MovePersonAnim _moveAnim[15]; + + uint16 _walkDataCount; + WalkData _walkData[16]; + + uint16 _roomAreasCount; + const Area* _roomAreas; + uint16 _areaStrikeCount; + uint16 _areaStrike[MAX_AREAS + 1]; + uint16 _areaListCount; + uint16 _areaList[MAX_AREAS + 1]; + + Logic *_logic; + Graphics *_graphics; + +}; + + +} // End of namespace Queen + +#endif |