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:
parent
0850dbdaf2
commit
94d9a2149b
10 changed files with 202 additions and 117 deletions
|
@ -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");
|
||||
// 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;
|
||||
}
|
||||
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,6 +910,9 @@ 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))) {
|
||||
Point endpoint;
|
||||
int exitNum;
|
||||
|
||||
debug(2, "Path complete.");
|
||||
ys_dll_delete(walk_p);
|
||||
a_walkint->wi_active = 0;
|
||||
|
@ -919,6 +924,12 @@ int Actor::handleWalkIntent(R_ACTOR *actor, R_WALKINTENT *a_walkint, int *comple
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
25
saga/gfx.cpp
25
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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
=======
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue