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
This commit is contained in:
Eugene Sandulenko 2004-10-08 01:22:39 +00:00
parent 0850dbdaf2
commit 94d9a2149b
10 changed files with 202 additions and 117 deletions

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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 {

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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);

View file

@ -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
=======