diff options
Diffstat (limited to 'saga')
-rw-r--r-- | saga/actionmap.cpp | 159 | ||||
-rw-r--r-- | saga/actionmap.h | 26 | ||||
-rw-r--r-- | saga/actor.cpp | 33 | ||||
-rw-r--r-- | saga/gfx.cpp | 25 | ||||
-rw-r--r-- | saga/gfx.h | 2 | ||||
-rw-r--r-- | saga/interface.cpp | 4 | ||||
-rw-r--r-- | saga/objectmap.cpp | 30 | ||||
-rw-r--r-- | saga/objectmap.h | 22 | ||||
-rw-r--r-- | saga/saga.h | 5 | ||||
-rw-r--r-- | saga/xref.txt | 11 |
10 files changed, 201 insertions, 116 deletions
diff --git a/saga/actionmap.cpp b/saga/actionmap.cpp index b3e647f0e0..613aa5e0b1 100644 --- a/saga/actionmap.cpp +++ b/saga/actionmap.cpp @@ -35,112 +35,157 @@ 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); - return; - } + exmap_entry->clickareas = (R_CLICKAREA *)malloc(exmap_entry->nClickareas * sizeof *(exmap_entry->clickareas)); - exmap_pt_tbl = (Point *)malloc(exmap_entry[i].pt_count * sizeof *exmap_pt_tbl); - if (exmap_pt_tbl == NULL) { - warning("Memory allocation failure"); + if (exmap_entry->clickareas == NULL) { + warning("Error: Memory allocation failed"); return; } - for (pt = 0; pt < exmap_entry[i].pt_count; pt++) { - exmap_pt_tbl[pt].x = readS.readSint16LE(); - exmap_pt_tbl[pt].y = readS.readSint16LE(); + // 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); + + clickarea->points = (Point *)malloc(clickarea->n_points * sizeof *(clickarea->points)); + if (clickarea->points == NULL) { + warning("Error: Memory allocation failed"); + return; + } + + // 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(); + } } - - exmap_entry[i].pt_tbl = exmap_pt_tbl; } - - _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); } } -int ActionMap::draw(R_SURFACE *ds, int color) { - int i; +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++) { - 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]; + + // 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 R_SUCCESS; + return -1; } -void ActionMap::info(void) { - Point *pt; - - int i; - int pt_i; +int ActionMap::draw(R_SURFACE *ds, int color) { + R_ACTIONMAP_ENTRY *exmap_entry; + R_CLICKAREA *clickarea; - _vm->_console->print("%d exits loaded.\n", _nExits); + int i, k; 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); + 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); + } + } + } - for (pt_i = 0; pt_i < _exitsTbl[i].pt_count; pt_i++) { - pt = &_exitsTbl[i].pt_tbl[pt_i]; + return R_SUCCESS; +} - _vm->_console->print(" pt: %d (%d, %d)", pt_i, pt->x, pt->y); - } +void ActionMap::info(void) { + _vm->_console->print("%d exits loaded.\n", _nExits); + + 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 594ce24006..f9b3e643e2 100644 --- a/saga/actionmap.h +++ b/saga/actionmap.h @@ -28,14 +28,28 @@ namespace Saga { +enum ACTION_FLAGS { + ACTION_ENABLED = (1<<0), // Zone is enabled + ACTION_EXIT = (1<<1), // Causes char to exit + + // 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 unknown00; - int unknown02; + int flags; + int nClickareas; + int defaultVerb; int exitScene; - int unknown06; + int entranceNum; - int pt_count; - Point *pt_tbl; + 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 94793ac5e1..8afafdc3b2 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 78712dc485..978cfc29e6 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 24247a3507..e70b0c077d 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 9abfc01de2..3d999658f3 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 47a20ee175..7f943577f9 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 cdeaa2823f..dff64993b6 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 -}; - -struct R_CLICKAREA { - int n_points; - Point *points; +enum OBJECT_FLAGS { + OBJECT_ENABLED = (1<<0), // Object is enabled + OBJECT_EXIT = (1<<1), // Causes char to exit + + // 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 d5c906917c..e1fd36763e 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 4668e3a067..4a26f4a2d3 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 ======= |