aboutsummaryrefslogtreecommitdiff
path: root/queen
diff options
context:
space:
mode:
authorGregory Montoir2003-10-09 09:09:40 +0000
committerGregory Montoir2003-10-09 09:09:40 +0000
commit91aaef03bc57bdf1284c3404b96b983d03695194 (patch)
tree9d68fc8818198ac7a5ec2eacf4c05dcdd5599e68 /queen
parentefef7ff6a26c4cff4736a9f463a965c211075144 (diff)
downloadscummvm-rg350-91aaef03bc57bdf1284c3404b96b983d03695194.tar.gz
scummvm-rg350-91aaef03bc57bdf1284c3404b96b983d03695194.tar.bz2
scummvm-rg350-91aaef03bc57bdf1284c3404b96b983d03695194.zip
added walking functions
svn-id: r10695
Diffstat (limited to 'queen')
-rw-r--r--queen/cutaway.cpp8
-rw-r--r--queen/graphics.cpp143
-rw-r--r--queen/graphics.h26
-rw-r--r--queen/logic.cpp130
-rw-r--r--queen/logic.h37
-rw-r--r--queen/module.mk3
-rw-r--r--queen/resource.h2
-rw-r--r--queen/structs.h26
-rw-r--r--queen/walk.cpp396
-rw-r--r--queen/walk.h129
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