From 94d9a2149b8b757ed36cb0f315cd281d1447d1a0 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Fri, 8 Oct 2004 01:22:39 +0000 Subject: [PATCH] Implement scene change via exits. You still cannot leave first scene because it goes to now buggy isometric level. Use debugger to switch to some word, say, in Dog Castle and there you may go between rooms. svn-id: r15462 --- saga/actionmap.cpp | 159 +++++++++++++++++++++++++++++---------------- saga/actionmap.h | 30 +++++++-- saga/actor.cpp | 33 ++++++---- saga/gfx.cpp | 25 +++++++ saga/gfx.h | 2 + saga/interface.cpp | 4 +- saga/objectmap.cpp | 30 +-------- saga/objectmap.h | 20 +++--- saga/saga.h | 5 ++ saga/xref.txt | 11 +++- 10 files changed, 202 insertions(+), 117 deletions(-) diff --git a/saga/actionmap.cpp b/saga/actionmap.cpp index b3e647f0e02..613aa5e0b1b 100644 --- a/saga/actionmap.cpp +++ b/saga/actionmap.cpp @@ -35,85 +35,146 @@ namespace Saga { ActionMap::ActionMap(SagaEngine *vm, const byte * exmap_res, size_t exmap_res_len) : _vm(vm) { // Loads exit map data from specified exit map resource R_ACTIONMAP_ENTRY *exmap_entry; - Point *exmap_pt_tbl; - - int exit_ct; - int i, pt; + R_CLICKAREA *clickarea; + Point *point; assert(exmap_res != NULL); MemoryReadStream readS(exmap_res, exmap_res_len); // Load exits - exit_ct = readS.readSint16LE(); - if (exit_ct < 0) { + _nExits = readS.readSint16LE(); + if (_nExits < 0) { return; } - exmap_entry = (R_ACTIONMAP_ENTRY *)malloc(exit_ct * sizeof *exmap_entry); - if (exmap_entry == NULL) { + _exitsTbl = (R_ACTIONMAP_ENTRY *)malloc(_nExits * sizeof *_exitsTbl); + if (_exitsTbl == NULL) { warning("Memory allocation failure"); return; } - for (i = 0; i < exit_ct; i++) { - exmap_entry[i].unknown00 = readS.readSint16LE(); - exmap_entry[i].unknown02 = readS.readSint16LE(); - exmap_entry[i].exitScene = readS.readSint16LE(); - exmap_entry[i].unknown06 = readS.readSint16LE(); + for (int i = 0; i < _nExits; i++) { + exmap_entry = &_exitsTbl[i]; + exmap_entry->flags = readS.readByte(); + exmap_entry->nClickareas = readS.readByte(); + exmap_entry->defaultVerb = readS.readByte(); + readS.readByte(); + exmap_entry->exitScene = readS.readUint16LE(); + exmap_entry->entranceNum = readS.readUint16LE(); - exmap_entry[i].pt_count = readS.readSint16LE(); - if (exmap_entry[i].pt_count < 0) { - free(exmap_entry); + exmap_entry->clickareas = (R_CLICKAREA *)malloc(exmap_entry->nClickareas * sizeof *(exmap_entry->clickareas)); + + if (exmap_entry->clickareas == NULL) { + warning("Error: Memory allocation failed"); return; } - exmap_pt_tbl = (Point *)malloc(exmap_entry[i].pt_count * sizeof *exmap_pt_tbl); - if (exmap_pt_tbl == NULL) { - warning("Memory allocation failure"); - return; - } + // Load all clickareas for this object + for (int k = 0; k < exmap_entry->nClickareas; k++) { + clickarea = &exmap_entry->clickareas[k]; + clickarea->n_points = readS.readUint16LE(); + assert(clickarea->n_points != 0); - for (pt = 0; pt < exmap_entry[i].pt_count; pt++) { - exmap_pt_tbl[pt].x = readS.readSint16LE(); - exmap_pt_tbl[pt].y = readS.readSint16LE(); - } + clickarea->points = (Point *)malloc(clickarea->n_points * sizeof *(clickarea->points)); + if (clickarea->points == NULL) { + warning("Error: Memory allocation failed"); + return; + } - exmap_entry[i].pt_tbl = exmap_pt_tbl; + // Load all points for this clickarea + for (int m = 0; m < clickarea->n_points; m++) { + point = &clickarea->points[m]; + point->x = readS.readSint16LE(); + point->y = readS.readSint16LE(); + } + } } - - _nExits = exit_ct; - _exitsTbl = exmap_entry; } ActionMap::~ActionMap(void) { // Frees the currently loaded exit map data R_ACTIONMAP_ENTRY *exmap_entry; + R_CLICKAREA *clickarea; int i; if (_exitsTbl) { for (i = 0; i < _nExits; i++) { exmap_entry = &_exitsTbl[i]; - if (exmap_entry != NULL) - free(exmap_entry->pt_tbl); + for (int k = 0; k < exmap_entry->nClickareas; k++) { + clickarea = &exmap_entry->clickareas[k]; + free(clickarea->points); + } + free(exmap_entry->clickareas); } free(_exitsTbl); } } +const int ActionMap::getExitScene(int exitNum) { + assert(exitNum < _nExits); + + return _exitsTbl[exitNum].exitScene; +} + + +int ActionMap::hitTest(Point imouse) { + R_ACTIONMAP_ENTRY *exmap_entry; + R_CLICKAREA *clickarea; + Point *points; + int n_points; + + int i, k; + + // Loop through all scene objects + for (i = 0; i < _nExits; i++) { + exmap_entry = &_exitsTbl[i]; + + // Hit-test all clickareas for this object + for (k = 0; k < exmap_entry->nClickareas; k++) { + clickarea = &exmap_entry->clickareas[k]; + n_points = clickarea->n_points; + points = clickarea->points; + + if (n_points == 2) { + // Hit-test a box region + if ((imouse.x > points[0].x) && (imouse.x <= points[1].x) && + (imouse.y > points[0].y) && + (imouse.y <= points[1].y)) { + return i; + } + } else if (n_points > 2) { + // Hit-test a polygon + if (_vm->_gfx->hitTestPoly(points, n_points, imouse)) { + return i; + } + } + } + } + + return -1; +} + int ActionMap::draw(R_SURFACE *ds, int color) { - int i; + R_ACTIONMAP_ENTRY *exmap_entry; + R_CLICKAREA *clickarea; + + int i, k; for (i = 0; i < _nExits; i++) { - if (_exitsTbl[i].pt_count == 2) { - _vm->_gfx->drawFrame(ds, - &_exitsTbl[i].pt_tbl[0], - &_exitsTbl[i].pt_tbl[1], color); - } else if (_exitsTbl[i].pt_count > 2) { - _vm->_gfx->drawPolyLine(ds, _exitsTbl[i].pt_tbl, - _exitsTbl[i].pt_count, color); + exmap_entry = &_exitsTbl[i]; + + for (k = 0; k < exmap_entry->nClickareas; k++) { + clickarea = &exmap_entry->clickareas[k]; + if (clickarea->n_points == 2) { + // 2 points represent a box + _vm->_gfx->drawFrame(ds, &clickarea->points[0], &clickarea->points[1], color); + } else if (clickarea->n_points > 2) { + // Otherwise draw a polyline + _vm->_gfx->drawPolyLine(ds, clickarea->points, clickarea->n_points, color); + } } } @@ -121,26 +182,10 @@ int ActionMap::draw(R_SURFACE *ds, int color) { } void ActionMap::info(void) { - Point *pt; - - int i; - int pt_i; - _vm->_console->print("%d exits loaded.\n", _nExits); - for (i = 0; i < _nExits; i++) { - _vm->_console->print ("Action %d: Exit to: %d; Pts: %d; Unk0: %d Unk2: %d Scr_N: %d", - i, _exitsTbl[i].exitScene, - _exitsTbl[i].pt_count, - _exitsTbl[i].unknown00, - _exitsTbl[i].unknown02, - _exitsTbl[i].unknown06); - - for (pt_i = 0; pt_i < _exitsTbl[i].pt_count; pt_i++) { - pt = &_exitsTbl[i].pt_tbl[pt_i]; - - _vm->_console->print(" pt: %d (%d, %d)", pt_i, pt->x, pt->y); - } + for (int i = 0; i < _nExits; i++) { + _vm->_console->print ("Action %d: Exit to: %d", i, _exitsTbl[i].exitScene); } } diff --git a/saga/actionmap.h b/saga/actionmap.h index 594ce240062..f9b3e643e20 100644 --- a/saga/actionmap.h +++ b/saga/actionmap.h @@ -28,14 +28,28 @@ namespace Saga { -struct R_ACTIONMAP_ENTRY { - int unknown00; - int unknown02; - int exitScene; - int unknown06; +enum ACTION_FLAGS { + ACTION_ENABLED = (1<<0), // Zone is enabled + ACTION_EXIT = (1<<1), // Causes char to exit - int pt_count; - Point *pt_tbl; + // The following flag causes the zone to act differently. + // When the actor hits the zone, it will immediately begin walking + // in the specified direction, and the actual specified effect of + // the zone will be delayed until the actor leaves the zone. + ACTION_AUTOWALK = (1<<2), + + // zone activates only when character stops walking + ACTION_TERMINUS = (1<<3) +}; + +struct R_ACTIONMAP_ENTRY { + int flags; + int nClickareas; + int defaultVerb; + int exitScene; + int entranceNum; + + R_CLICKAREA *clickareas; }; class ActionMap { @@ -44,6 +58,8 @@ class ActionMap { ActionMap(SagaEngine *vm, const byte *exmap_res, size_t exmap_res_len); ~ActionMap(void); + const int getExitScene(int exitNum); + int hitTest(Point imousePt); int draw(R_SURFACE *ds, int color); void info(void); diff --git a/saga/actor.cpp b/saga/actor.cpp index 94793ac5e1c..8afafdc3b23 100644 --- a/saga/actor.cpp +++ b/saga/actor.cpp @@ -35,6 +35,8 @@ #include "saga/font.h" #include "saga/text.h" #include "saga/sound.h" +#include "saga/scene.h" +#include "saga/actionmap.h" #include "saga/actor.h" #include "saga/actordata.h" @@ -908,19 +910,28 @@ int Actor::handleWalkIntent(R_ACTOR *actor, R_WALKINTENT *a_walkint, int *comple if (((a_walkint->x_dir == 1) && new_a_x >= node_p->node_pt.x) || ((a_walkint->x_dir != 1) && (new_a_x <= node_p->node_pt.x))) { - debug(2, "Path complete."); - ys_dll_delete(walk_p); - a_walkint->wi_active = 0; + Point endpoint; + int exitNum; - // Release path semaphore - if (a_walkint->sem != NULL) { - _vm->_script->SThreadReleaseSem(a_walkint->sem); - } + debug(2, "Path complete."); + ys_dll_delete(walk_p); + a_walkint->wi_active = 0; - actor->action_frame = 0; - actor->action = ACTION_IDLE; - *complete_p = 1; - return R_FAILURE; + // Release path semaphore + if (a_walkint->sem != NULL) { + _vm->_script->SThreadReleaseSem(a_walkint->sem); + } + + actor->action_frame = 0; + actor->action = ACTION_IDLE; + + endpoint.x = (int)new_a_x / R_ACTOR_LMULT; + endpoint.y = (int)new_a_y / R_ACTOR_LMULT; + if ((exitNum = _vm->_scene->_actionMap->hitTest(endpoint)) != -1) { + _vm->_scene->changeScene(_vm->_scene->_actionMap->getExitScene(exitNum)); + } + *complete_p = 1; + return R_FAILURE; } actor_x = (int)new_a_x; diff --git a/saga/gfx.cpp b/saga/gfx.cpp index 78712dc4852..978cfc29e6f 100644 --- a/saga/gfx.cpp +++ b/saga/gfx.cpp @@ -1076,4 +1076,29 @@ void Gfx::setCursor(int best_white) { _system->setMouseCursor(cursor_img, R_CURSOR_W, R_CURSOR_H, 4, 4, keycolor); } +bool Gfx::hitTestPoly(Point *points, unsigned int npoints, Point test_point) { + int yflag0; + int yflag1; + bool inside_flag = false; + unsigned int pt; + + Point *vtx0 = &points[npoints - 1]; + Point *vtx1 = &points[0]; + + yflag0 = (vtx0->y >= test_point.y); + for (pt = 0; pt < npoints; pt++, vtx1++) { + yflag1 = (vtx1->y >= test_point.y); + if (yflag0 != yflag1) { + if (((vtx1->y - test_point.y) * (vtx0->x - vtx1->x) >= + (vtx1->x - test_point.x) * (vtx0->y - vtx1->y)) == yflag1) { + inside_flag = !inside_flag; + } + } + yflag0 = yflag1; + vtx0 = vtx1; + } + + return inside_flag; +} + } // End of namespace Saga diff --git a/saga/gfx.h b/saga/gfx.h index 24247a35070..e70b0c077de 100644 --- a/saga/gfx.h +++ b/saga/gfx.h @@ -107,6 +107,8 @@ public: int getCurrentPal(PALENTRY *src_pal); int palToBlack(R_SURFACE *surface, PALENTRY *src_pal, double percent); int blackToPal(R_SURFACE *surface, PALENTRY *src_pal, double percent); + bool hitTestPoly(Point *points, unsigned int npoints, Point test_point); + private: void setCursor(int best_white); int _init; diff --git a/saga/interface.cpp b/saga/interface.cpp index 9abfc01de25..3d999658f3e 100644 --- a/saga/interface.cpp +++ b/saga/interface.cpp @@ -492,7 +492,7 @@ int Interface::handlePlayfieldClick(R_SURFACE *ds, Point imousePt) { object_flags = _vm->_scene->_objectMap->getFlags(objectNum); - if (object_flags & R_OBJECT_NORMAL) { + if (object_flags & OBJECT_EXIT) { // FIXME. This is wrong if ((script_num = _vm->_scene->_objectMap->getEPNum(objectNum)) != -1) { // Set active verb in script module _vm->_sdata->putWord(4, 4, I_VerbData[_activeVerb].s_verb); @@ -532,7 +532,7 @@ int Interface::handlePlayfieldUpdate(R_SURFACE *ds, Point imousePt) { object_name = _vm->_scene->_objectMap->getName(objectNum); - if (object_flags & R_OBJECT_NORMAL) { + if (object_flags & OBJECT_EXIT) { // FIXME. This is wrong // Normal scene object - display as subject of verb snprintf(new_status, R_STATUS_TEXT_LEN, "%s %s", I_VerbData[_activeVerb].verb_str, object_name); } else { diff --git a/saga/objectmap.cpp b/saga/objectmap.cpp index 47a20ee1752..7f943577f94 100644 --- a/saga/objectmap.cpp +++ b/saga/objectmap.cpp @@ -214,7 +214,6 @@ const uint16 ObjectMap::getFlags(int object) { int i; assert(_namesLoaded); - debug(0, "object: %d nnames: %d", object, _nNames); assert((object > 0) && (object <= _nNames)); for (i = 0; i < _nObjects; i++) { @@ -259,7 +258,6 @@ int ObjectMap::draw(R_SURFACE *ds, Point imousePt, int color, int color2) { bool hitObject = false; int objectNum = 0; - int pointcount = 0; int i, k; if (!_objectsLoaded) { @@ -285,7 +283,6 @@ int ObjectMap::draw(R_SURFACE *ds, Point imousePt, int color, int color2) { for (k = 0; k < object_map->nClickareas; k++) { clickarea = &object_map->clickareas[k]; - pointcount = 0; if (clickarea->n_points == 2) { // 2 points represent a box _vm->_gfx->drawFrame(ds, &clickarea->points[0], &clickarea->points[1], draw_color); @@ -304,31 +301,6 @@ int ObjectMap::draw(R_SURFACE *ds, Point imousePt, int color, int color2) { return R_SUCCESS; } -static bool MATH_HitTestPoly(Point *points, unsigned int npoints, Point test_point) { - int yflag0; - int yflag1; - bool inside_flag = false; - unsigned int pt; - - Point *vtx0 = &points[npoints - 1]; - Point *vtx1 = &points[0]; - - yflag0 = (vtx0->y >= test_point.y); - for (pt = 0; pt < npoints; pt++, vtx1++) { - yflag1 = (vtx1->y >= test_point.y); - if (yflag0 != yflag1) { - if (((vtx1->y - test_point.y) * (vtx0->x - vtx1->x) >= - (vtx1->x - test_point.x) * (vtx0->y - vtx1->y)) == yflag1) { - inside_flag = !inside_flag; - } - } - yflag0 = yflag1; - vtx0 = vtx1; - } - - return inside_flag; -} - int ObjectMap::hitTest(Point imousePt) { Point imouse; R_OBJECTMAP_ENTRY *object_map; @@ -360,7 +332,7 @@ int ObjectMap::hitTest(Point imousePt) { } } else if (n_points > 2) { // Hit-test a polygon - if (MATH_HitTestPoly(points, n_points, imouse)) { + if (_vm->_gfx->hitTestPoly(points, n_points, imouse)) { return object_map->objectNum; } } diff --git a/saga/objectmap.h b/saga/objectmap.h index cdeaa2823f7..dff64993b66 100644 --- a/saga/objectmap.h +++ b/saga/objectmap.h @@ -28,14 +28,18 @@ namespace Saga { -enum R_OBJECT_FLAGS { - R_OBJECT_EXIT = 0x01, - R_OBJECT_NORMAL = 0x02 -}; +enum OBJECT_FLAGS { + OBJECT_ENABLED = (1<<0), // Object is enabled + OBJECT_EXIT = (1<<1), // Causes char to exit -struct R_CLICKAREA { - int n_points; - Point *points; + // Causes the character not to walk to the object (but they will + // look at it). + OBJECT_NOWALK = (1<<2), + + // When the object is clicked on it projects the + // click point downwards from the middle of the object until it + // reaches the lowest point in the zone. + OBJECT_PROJECT = (1<<3) }; struct R_OBJECTMAP_ENTRY { @@ -49,8 +53,6 @@ struct R_OBJECTMAP_ENTRY { R_CLICKAREA *clickareas; }; -class Gfx; - class ObjectMap{ public: int reg(void); diff --git a/saga/saga.h b/saga/saga.h index d5c906917ce..e1fd36763e6 100644 --- a/saga/saga.h +++ b/saga/saga.h @@ -78,6 +78,11 @@ enum SAGAGameId { GID_IHNM }; +struct R_CLICKAREA { + int n_points; + Point *points; +}; + class SagaEngine : public Engine { void errorString(const char *buf_input, char *buf_output); diff --git a/saga/xref.txt b/saga/xref.txt index 4668e3a067f..4a26f4a2d33 100644 --- a/saga/xref.txt +++ b/saga/xref.txt @@ -35,8 +35,15 @@ Sceneres.h LOADREQ_FACES SAGA_FACES LOADREQ_PALETTE - HZONE_EXIT R_OBJECT_EXIT - HZONEF_AUTOWALK R_OBJECT_NORMAL + hitZone ObjectMap + stepZone ActionMap + + HZONEF_EXIT OBJECT_EXIT (in Verb.c), ACTION_EXIT (in Actor.c) + HZONEF_ENABLED OBJECT_ENABLED (in Verb.c), ACTION_ENABLED (in Actor.c) + HZONEF_NOWALK OBJECT_NOWALK + HZONEF_PROJECT OBJECT_PROJECT + HZONEF_AUTOWALK ACTION_AUTOWALK + HZONEF_TERMINUS ACTION_TERMINUS Scene.c =======