Patch #1081904 ITE: MAC demo support

o Endianness-aware resource loading
o Removed ys_dl_list in favor of our object implementation
o Cleanup in actor code
o Partial support for ITE Mac rereleased demo

svn-id: r16051
This commit is contained in:
Eugene Sandulenko 2004-12-15 00:24:12 +00:00
parent 58eabb6a5f
commit 502b279d24
36 changed files with 928 additions and 954 deletions

View file

@ -28,6 +28,8 @@
#include "saga/console.h"
#include "saga/actionmap.h"
#include "saga/game_mod.h"
#include "saga/stream.h"
namespace Saga {
@ -39,10 +41,10 @@ ActionMap::ActionMap(SagaEngine *vm, const byte * exmap_res, size_t exmap_res_le
assert(exmap_res != NULL);
MemoryReadStream readS(exmap_res, exmap_res_len);
MemoryReadStreamEndian readS(exmap_res, exmap_res_len, IS_BIG_ENDIAN);
// Load exits
_nExits = readS.readSint16LE();
_nExits = readS.readSint16();
if (_nExits < 0) {
return;
}
@ -59,8 +61,8 @@ ActionMap::ActionMap(SagaEngine *vm, const byte * exmap_res, size_t exmap_res_le
exmap_entry->nClickareas = readS.readByte();
exmap_entry->defaultVerb = readS.readByte();
readS.readByte();
exmap_entry->exitScene = readS.readUint16LE();
exmap_entry->entranceNum = readS.readUint16LE();
exmap_entry->exitScene = readS.readUint16();
exmap_entry->entranceNum = readS.readUint16();
exmap_entry->clickareas = (CLICKAREA *)malloc(exmap_entry->nClickareas * sizeof *(exmap_entry->clickareas));
@ -72,7 +74,7 @@ ActionMap::ActionMap(SagaEngine *vm, const byte * exmap_res, size_t exmap_res_le
// 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();
clickarea->n_points = readS.readUint16();
assert(clickarea->n_points != 0);
clickarea->points = (Point *)malloc(clickarea->n_points * sizeof *(clickarea->points));
@ -84,8 +86,8 @@ ActionMap::ActionMap(SagaEngine *vm, const byte * exmap_res, size_t exmap_res_le
// 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();
point->x = readS.readSint16();
point->y = readS.readSint16();
}
}
}

View file

@ -22,7 +22,6 @@
*/
#include "saga/saga.h"
#include "saga/yslib.h"
#include "saga/gfx.h"
#include "saga/game_mod.h"
@ -39,10 +38,20 @@
#include "saga/actor.h"
#include "saga/actordata.h"
#include "saga/stream.h"
namespace Saga {
static int zCompare(const void *elem1, const void *elem2);
static int actorCompare(const ACTOR& actor1, const ACTOR& actor2) {
if (actor1.a_pt.y == actor2.a_pt.y) {
return 0;
} else if (actor1.a_pt.y < actor2.a_pt.y) {
return -1;
} else {
return 1;
}
}
static ActorList::iterator zeroActorIterator;
ACTIONTIMES ActionTDeltas[] = {
{ ACTION_IDLE, 80 },
@ -59,33 +68,12 @@ Actor::Actor(SagaEngine *vm) : _vm(vm), _initialized(false) {
error("Actor::Actor(): Couldn't load actor module resource context.");
}
// Create actor lookup table
_tbl = (YS_DL_NODE **)malloc(ACTORCOUNT * sizeof(*_tbl));
if (_tbl == NULL) {
error("Actor::Actor(): Memory allocation error.");
return;
}
for (i = 0; i < ACTORCOUNT; i++) {
_tbl[i] = NULL;
}
// Create actor alias table
_aliasTbl = (int *)malloc(ACTORCOUNT * sizeof(*_aliasTbl));
if (_aliasTbl == NULL) {
free(_tbl);
error("Actor::Actor(): Memory allocation error.");
return;
}
// Initialize alias table so each index contains itself
for (i = 0; i < ACTORCOUNT; i++) {
_aliasTbl[i] = i;
}
// Create actor list
_list = ys_dll_create();
_count = 0;
_initialized = true;
}
@ -94,29 +82,26 @@ Actor::~Actor() {
if (!_initialized) {
return;
}
if (_tbl) {
free(_tbl);
}
}
int Actor::direct(int msec) {
YS_DL_NODE *walk_p;
ActorList::iterator actorIterator;
ACTOR *actor;
YS_DL_NODE *a_inode;
ActorIntentList::iterator actorIntentIterator;
ACTORINTENT *a_intent;
int o_idx;
int action_tdelta;
// Walk down the actor list and direct each actor
for (walk_p = ys_dll_head(_list); walk_p != NULL; walk_p = ys_dll_next(walk_p)) {
actor = (ACTOR *)ys_dll_get_data(walk_p);
for (actorIterator = _list.begin(); actorIterator != _list.end(); ++actorIterator) {
actor = actorIterator.operator->();
// Process the actor intent list
a_inode = ys_dll_head(actor->a_intentlist);
if (a_inode != NULL) {
a_intent = (ACTORINTENT *)ys_dll_get_data(a_inode);
actorIntentIterator = actor->a_intentlist.begin();
if (actorIntentIterator != actor->a_intentlist.end()) {
a_intent = actorIntentIterator.operator->();
switch (a_intent->a_itype) {
case INTENT_NONE:
// Actor doesn't really feel like doing anything at all
@ -144,8 +129,8 @@ int Actor::direct(int msec) {
// If this actor intent was flagged as completed, remove it.
if (a_intent->a_idone) {
free(a_intent->a_data);
ys_dll_delete(a_inode);
a_intent->deleteData();
actor->a_intentlist.erase(actorIntentIterator);
actor->action = actor->def_action;
actor->action_flags = actor->def_action_flags;
actor->action_frame = 0;
@ -183,14 +168,14 @@ int Actor::direct(int msec) {
}
int Actor::drawList() {
YS_DL_NODE *walk_p;
ActorList::iterator actorIterator;
ACTOR *actor;
YS_DL_NODE *a_inode;
ActorIntentList::iterator actorIntentIterator;
ACTORINTENT *a_intent;
SPEAKINTENT *a_speakint;
YS_DL_NODE *a_dnode;
ActorDialogList::iterator actorDialogIterator;
ACTORDIALOGUE *a_dialogue;
int o_idx; //Orientation index
@ -202,8 +187,8 @@ int Actor::drawList() {
back_buf = _vm->_gfx->getBackBuffer();
for (walk_p = ys_dll_head(_list); walk_p != NULL; walk_p = ys_dll_next(walk_p)) {
actor = (ACTOR *)ys_dll_get_data(walk_p);
for (actorIterator = _list.begin(); actorIterator != _list.end(); ++actorIterator) {
actor = actorIterator.operator->();
o_idx = ActorOrientationLUT[actor->orient];
sprite_num = actor->act_tbl[actor->action].dir[o_idx].frame_index;
sprite_num += actor->action_frame;
@ -211,14 +196,14 @@ int Actor::drawList() {
// If actor's current intent is to speak, oblige him by
// displaying his dialogue
a_inode = ys_dll_head(actor->a_intentlist);
if (a_inode != NULL) {
a_intent = (ACTORINTENT *)ys_dll_get_data(a_inode);
actorIntentIterator = actor->a_intentlist.begin();
if (actorIntentIterator != actor->a_intentlist.end()) {
a_intent = actorIntentIterator.operator->();
if (a_intent->a_itype == INTENT_SPEAK) {
a_speakint = (SPEAKINTENT *)a_intent->a_data;
a_dnode = ys_dll_head(a_speakint->si_diaglist);
if (a_dnode != NULL) {
a_dialogue = (ACTORDIALOGUE *)ys_dll_get_data(a_dnode);
actorDialogIterator = a_speakint->si_diaglist.begin();
if (actorDialogIterator != a_speakint->si_diaglist.end()) {
a_dialogue = actorDialogIterator.operator->();
diag_x = actor->s_pt.x;
diag_y = actor->s_pt.y;
diag_y -= ACTOR_DIALOGUE_HEIGHT;
@ -237,37 +222,37 @@ int Actor::drawList() {
// dialogue entry if there is a current speak intent present.
int Actor::skipDialogue() {
YS_DL_NODE *walk_p;
ActorList::iterator actorIterator;
ACTOR *actor;
YS_DL_NODE *a_inode;
ActorIntentList::iterator actorIntentIterator;
ACTORINTENT *a_intent;
SPEAKINTENT *a_speakint;
YS_DL_NODE *a_dnode;
ActorDialogList::iterator actorDialogIterator;
ACTORDIALOGUE *a_dialogue;
if (!_initialized) {
return FAILURE;
}
for (walk_p = ys_dll_head(_list); walk_p != NULL; walk_p = ys_dll_next(walk_p)) {
actor = (ACTOR *)ys_dll_get_data(walk_p);
for (actorIterator = _list.begin(); actorIterator != _list.end(); ++actorIterator) {
actor = actorIterator.operator->();
// Check the actor's current intent for a speak intent
a_inode = ys_dll_head(actor->a_intentlist);
if (a_inode != NULL) {
a_intent = (ACTORINTENT *)ys_dll_get_data(a_inode);
actorIntentIterator = actor->a_intentlist.begin();
if (actorIntentIterator != actor->a_intentlist.end()) {
a_intent = actorIntentIterator.operator->();
if (a_intent->a_itype == INTENT_SPEAK) {
// Okay, found a speak intent. Remove one dialogue entry
// from it, releasing any semaphore */
a_speakint = (SPEAKINTENT *)a_intent->a_data;
a_dnode = ys_dll_head(a_speakint->si_diaglist);
if (a_dnode != NULL) {
a_dialogue = (ACTORDIALOGUE *)ys_dll_get_data(a_dnode);
actorDialogIterator = a_speakint->si_diaglist.begin();
if (actorDialogIterator != a_speakint->si_diaglist.end()) {
a_dialogue = actorDialogIterator.operator->();
if (a_dialogue->d_sem != NULL) {
_vm->_script->SThreadReleaseSem(a_dialogue->d_sem);
}
ys_dll_delete(a_dnode);
a_speakint->si_diaglist.erase(actorDialogIterator);
// And stop any currently playing voices
_vm->_sound->stopVoice();
}
@ -300,7 +285,7 @@ int Actor::create(int actor_id, int x, int y) {
}
int Actor::addActor(ACTOR * actor) {
YS_DL_NODE *new_node;
ActorList::iterator actorIterator;
int last_frame;
int i;
@ -312,7 +297,7 @@ int Actor::addActor(ACTOR * actor) {
return FAILURE;
}
if (_tbl[actor->id] != NULL) {
if (_tbl[actor->id] != zeroActorIterator) {
return FAILURE;
}
@ -340,7 +325,6 @@ int Actor::addActor(ACTOR * actor) {
actor->flags = ActorTable[i].flags;
actor->a_dcolor = ActorTable[i].color;
actor->orient = ACTOR_DEFAULT_ORIENT;
actor->a_intentlist = ys_dll_create();
actor->def_action = 0;
actor->def_action_flags = 0;
actor->action = 0;
@ -348,35 +332,34 @@ int Actor::addActor(ACTOR * actor) {
actor->action_time = 0;
actor->action_frame = 0;
new_node = ys_dll_insert(_list, actor, sizeof(*actor), zCompare);
actorIterator = _list.pushBack(*actor, actorCompare);
if (new_node == NULL) {
return FAILURE;
}
actor = actorIterator.operator->();
actor = (ACTOR *)ys_dll_get_data(new_node);
actor->node = new_node;
_tbl[i] = new_node;
_tbl[i] = actorIterator;
_count++;
return SUCCESS;
}
int Actor::getActorIndex(uint16 actor_id) {
uint16 actor_idx;
uint16 actorIdx;
if (actor_id == 1) {
actor_idx = 0;
actorIdx = 0;
} else {
actor_idx = actor_id & ~0x2000;
actorIdx = actor_id & ~0x2000;
}
if (_tbl[actor_idx] == NULL) {
if (actorIdx >= ACTORCOUNT) {
error("Wrong actorIdx=%i", actorIdx);
}
if (_tbl[actorIdx] == zeroActorIterator) {
return -1;
}
return actor_idx;
return actorIdx;
}
int Actor::actorExists(uint16 actor_id) {
@ -388,7 +371,7 @@ int Actor::actorExists(uint16 actor_id) {
actor_idx = actor_id & ~0x2000;
}
if (_tbl[actor_idx] == NULL) {
if (_tbl[actor_idx] == zeroActorIterator) {
return 0;
}
@ -396,9 +379,9 @@ int Actor::actorExists(uint16 actor_id) {
}
int Actor::speak(int index, const char *d_string, uint16 d_voice_rn, SEMAPHORE *sem) {
YS_DL_NODE *node;
ActorList::iterator actorIterator;
ACTOR *actor;
YS_DL_NODE *a_inode;
ActorIntentList::iterator actorIntentIterator;
ACTORINTENT *a_intent_p = NULL;
SPEAKINTENT *a_speakint;
ACTORINTENT a_intent;
@ -411,20 +394,21 @@ int Actor::speak(int index, const char *d_string, uint16 d_voice_rn, SEMAPHORE *
a_dialogue.d_sem_held = 1;
a_dialogue.d_sem = sem;
node = _tbl[index];
if (node == NULL) {
actorIterator = _tbl[index];
if (actorIterator == zeroActorIterator) {
return FAILURE;
}
actor = (ACTOR *)ys_dll_get_data(node);
actor = actorIterator.operator->();
// If actor's last registered intent is to speak, we can queue the
// requested dialogue on that intent context; so examine the last
// intent
a_inode = ys_dll_tail(actor->a_intentlist);
if (a_inode != NULL) {
a_intent_p = (ACTORINTENT *)ys_dll_get_data(a_inode);
actorIntentIterator = actor->a_intentlist.end();
--actorIntentIterator;
if (actorIntentIterator != actor->a_intentlist.end()) {
a_intent_p = actorIntentIterator.operator->();
if (a_intent_p->a_itype == INTENT_SPEAK) {
use_existing_ai = 1;
}
@ -433,25 +417,19 @@ int Actor::speak(int index, const char *d_string, uint16 d_voice_rn, SEMAPHORE *
if (use_existing_ai) {
// Store the current dialogue off the existing actor intent
a_speakint = (SPEAKINTENT *)a_intent_p->a_data;
ys_dll_add_tail(a_speakint->si_diaglist, &a_dialogue, sizeof(a_dialogue));
a_speakint->si_diaglist.push_back(a_dialogue);
} else {
// Create a new actor intent
a_intent.a_itype = INTENT_SPEAK;
a_intent.a_idone = 0;
a_intent.a_iflags = 0;
a_intent.createData();
a_speakint = (SPEAKINTENT *)malloc(sizeof(*a_speakint));
if (a_speakint == NULL) {
return FAILURE;
}
a_speakint->si_init = 0;
a_speakint->si_diaglist = ys_dll_create();
a_speakint = (SPEAKINTENT *)a_intent.a_data;
a_speakint->si_last_action = actor->action;
a_intent.a_data = a_speakint;
a_speakint->si_diaglist.push_back(a_dialogue);
ys_dll_add_tail(a_speakint->si_diaglist, &a_dialogue, sizeof(a_dialogue));
ys_dll_add_tail(actor->a_intentlist, &a_intent, sizeof(a_intent));
actor->a_intentlist.push_back(a_intent);
}
if (sem != NULL) {
@ -462,8 +440,8 @@ int Actor::speak(int index, const char *d_string, uint16 d_voice_rn, SEMAPHORE *
}
int Actor::handleSpeakIntent(ACTOR *actor, SPEAKINTENT *a_speakint, int *complete_p, int msec) {
YS_DL_NODE *a_dnode;
YS_DL_NODE *a_dnext;
ActorDialogList::iterator actorDialogIterator;
ActorDialogList::iterator nextActorDialogIterator;
ACTORDIALOGUE *a_dialogue;
ACTORDIALOGUE *a_dialogue2;
long carry_time;
@ -479,9 +457,9 @@ int Actor::handleSpeakIntent(ACTOR *actor, SPEAKINTENT *a_speakint, int *complet
}
// Process actor dialogue list
a_dnode = ys_dll_head(a_speakint->si_diaglist);
if (a_dnode != NULL) {
a_dialogue = (ACTORDIALOGUE *)ys_dll_get_data(a_dnode);
actorDialogIterator = a_speakint->si_diaglist.begin();
if (actorDialogIterator != a_speakint->si_diaglist.end()) {
a_dialogue = actorDialogIterator.operator->();
if (!a_dialogue->d_playing) {
// Dialogue voice hasn't played yet - play it now
_vm->_sndRes->playVoice(a_dialogue->d_voice_rn);
@ -502,19 +480,18 @@ int Actor::handleSpeakIntent(ACTOR *actor, SPEAKINTENT *a_speakint, int *complet
carry_time = a_dialogue->d_time;
a_dnext = ys_dll_next(a_dnode);
if (a_dnext != NULL) {
a_dialogue2 = (ACTORDIALOGUE *)ys_dll_get_data(a_dnode);
nextActorDialogIterator = actorDialogIterator;
++nextActorDialogIterator;
if (nextActorDialogIterator != a_speakint->si_diaglist.end()) {
a_dialogue2 = nextActorDialogIterator.operator->();
a_dialogue2->d_time -= carry_time;
}
ys_dll_delete(a_dnode);
// Check if there are any dialogue nodes left. If not,
// flag this speech intent as complete
a_dnode = ys_dll_head(a_speakint->si_diaglist);
if (a_dnode == NULL) {
actorDialogIterator = a_speakint->si_diaglist.erase(actorDialogIterator);
if (actorDialogIterator != a_speakint->si_diaglist.end()) {
intent_complete = 1;
}
}
@ -597,7 +574,7 @@ int Actor::setDefaultAction(int index, int action_n, uint16 action_flags) {
}
ACTOR *Actor::lookupActor(int index) {
YS_DL_NODE *node;
ActorList::iterator actorIterator;
ACTOR *actor;
if (!_initialized) {
@ -608,12 +585,12 @@ ACTOR *Actor::lookupActor(int index) {
return NULL;
}
if (_tbl[index] == NULL) {
if (_tbl[index] == zeroActorIterator) {
return NULL;
}
node = _tbl[index];
actor = (ACTOR *)ys_dll_get_data(node);
actorIterator = _tbl[index];
actor = actorIterator.operator->();
return actor;
}
@ -637,7 +614,7 @@ int Actor::loadActorSpriteIndex(ACTOR * actor, int si_rn, int *last_frame_p) {
debug(0, "Sprite resource contains %d sprite actions.", s_action_ct);
action_p = (ACTORACTION *)malloc(sizeof(ACTORACTION) * s_action_ct);
MemoryReadStream readS(res_p, res_len);
MemoryReadStreamEndian readS(res_p, res_len, IS_BIG_ENDIAN);
if (action_p == NULL) {
warning("Couldn't allocate memory for sprite actions");
@ -650,8 +627,8 @@ int Actor::loadActorSpriteIndex(ACTOR * actor, int si_rn, int *last_frame_p) {
for (i = 0; i < s_action_ct; i++) {
for (orient = 0; orient < 4; orient++) {
// Load all four orientations
action_p[i].dir[orient].frame_index = readS.readUint16LE();
action_p[i].dir[orient].frame_count = readS.readUint16LE();
action_p[i].dir[orient].frame_index = readS.readUint16();
action_p[i].dir[orient].frame_count = readS.readUint16();
if (action_p[i].dir[orient].frame_index > last_frame) {
last_frame = action_p[i].dir[orient].frame_index;
}
@ -671,7 +648,7 @@ int Actor::loadActorSpriteIndex(ACTOR * actor, int si_rn, int *last_frame_p) {
}
int Actor::deleteActor(int index) {
YS_DL_NODE *node;
ActorList::iterator actorIterator;
ACTOR *actor;
if (!_initialized) {
@ -682,18 +659,19 @@ int Actor::deleteActor(int index) {
return FAILURE;
}
if (_tbl[index] == NULL) {
actorIterator = _tbl[index];
if (actorIterator == zeroActorIterator) {
return FAILURE;
}
node = _tbl[index];
actor = (ACTOR *)ys_dll_get_data(node);
actor = actorIterator.operator->();
_vm->_sprite->freeSprite(actor->sl_p);
ys_dll_delete(node);
_list.erase(actorIterator);
_tbl[index] = NULL;
_tbl[index] = zeroActorIterator;
return SUCCESS;
}
@ -701,8 +679,7 @@ int Actor::deleteActor(int index) {
int Actor::walkTo(int id, const Point *walk_pt, uint16 flags, SEMAPHORE *sem) {
ACTORINTENT actor_intent;
WALKINTENT *walk_intent;
WALKINTENT zero_intent;
YS_DL_NODE *node;
ActorList::iterator actorIterator;
ACTOR *actor;
assert(_initialized);
@ -712,19 +689,18 @@ int Actor::walkTo(int id, const Point *walk_pt, uint16 flags, SEMAPHORE *sem) {
return FAILURE;
}
if (_tbl[id] == NULL) {
if (_tbl[id] == zeroActorIterator) {
return FAILURE;
}
node = _tbl[id];
actor = (ACTOR *)ys_dll_get_data(node);
actorIterator = _tbl[id];
actor = actorIterator.operator->();
walk_intent = (WALKINTENT *)malloc(sizeof(*walk_intent));
if (walk_intent == NULL) {
return MEM;
}
*walk_intent = zero_intent;
actor_intent.a_itype = INTENT_PATH;
actor_intent.a_iflags = 0;
actor_intent.createData();
walk_intent = (WALKINTENT*)actor_intent.a_data;
walk_intent->wi_flags = flags;
walk_intent->sem_held = 1;
@ -734,11 +710,7 @@ int Actor::walkTo(int id, const Point *walk_pt, uint16 flags, SEMAPHORE *sem) {
walk_intent->wi_init = 0;
walk_intent->dst_pt = *walk_pt;
actor_intent.a_itype = INTENT_PATH;
actor_intent.a_iflags = 0;
actor_intent.a_data = walk_intent;
ys_dll_add_tail(actor->a_intentlist, &actor_intent, sizeof(actor_intent));
actor->a_intentlist.push_back(actor_intent);
if (sem != NULL) {
_vm->_script->SThreadHoldSem(sem);
@ -754,19 +726,18 @@ int Actor::setPathNode(WALKINTENT *walk_int, Point *src_pt, Point *dst_pt, SEMAP
walk_int->org = *src_pt;
assert((walk_int != NULL) && (src_pt != NULL) && (dst_pt != NULL));
assert(walk_int->nodelist != NULL);
new_node.node_pt = *dst_pt;
new_node.calc_flag = 0;
ys_dll_add_tail(walk_int->nodelist, &new_node, sizeof(new_node));
walk_int->nodelist.push_back(new_node);
return SUCCESS;
}
int Actor::handleWalkIntent(ACTOR *actor, WALKINTENT *a_walkint, int *complete_p, int delta_time) {
YS_DL_NODE *walk_p;
YS_DL_NODE *next_p;
WalkNodeList::iterator walkNodeIterator;
WalkNodeList::iterator nextWalkNodeIterator;
WALKNODE *node_p;
int dx;
@ -790,7 +761,6 @@ int Actor::handleWalkIntent(ACTOR *actor, WALKINTENT *a_walkint, int *complete_p
// Initialize walk intent
if (!a_walkint->wi_init) {
a_walkint->nodelist = ys_dll_create();
setPathNode(a_walkint, &actor->a_pt, &a_walkint->dst_pt, a_walkint->sem);
setDefaultAction(actor->id, ACTION_IDLE, ACTION_NONE);
a_walkint->wi_init = 1;
@ -798,10 +768,10 @@ int Actor::handleWalkIntent(ACTOR *actor, WALKINTENT *a_walkint, int *complete_p
assert(a_walkint->wi_active);
walk_p = ys_dll_head(a_walkint->nodelist);
next_p = ys_dll_next(walk_p);
walkNodeIterator = a_walkint->nodelist.begin();
nextWalkNodeIterator = walkNodeIterator;
node_p = (WALKNODE *)ys_dll_get_data(walk_p);
node_p = walkNodeIterator.operator->();
if (node_p->calc_flag == 0) {
@ -814,7 +784,7 @@ int Actor::handleWalkIntent(ACTOR *actor, WALKINTENT *a_walkint, int *complete_p
debug(0, "Vertical paths not implemented.");
ys_dll_delete(walk_p);
a_walkint->nodelist.erase(walkNodeIterator);
a_walkint->wi_active = 0;
// Release path semaphore
@ -883,7 +853,7 @@ int Actor::handleWalkIntent(ACTOR *actor, WALKINTENT *a_walkint, int *complete_p
int exitNum;
debug(2, "Path complete.");
ys_dll_delete(walk_p);
a_walkint->nodelist.erase(walkNodeIterator);
a_walkint->wi_active = 0;
// Release path semaphore
@ -913,28 +883,32 @@ int Actor::handleWalkIntent(ACTOR *actor, WALKINTENT *a_walkint, int *complete_p
actor->s_pt.x = actor->a_pt.x >> 2;
actor->s_pt.y = actor->a_pt.y >> 2;
if (path_slope < 0) {
ys_dll_reorder_up(_list, actor->node, zCompare);
ActorList::iterator actorIterator;
if (_list.locate(actor, actorIterator)) {
if (path_slope < 0) {
_list.reorderUp(actorIterator, actorCompare);
} else {
_list.reorderDown(actorIterator, actorCompare);
}
} else {
ys_dll_reorder_down(_list, actor->node, zCompare);
error("Actor::handleWalkIntent() actor not found list");
}
return SUCCESS;
}
int Actor::move(int index, const Point *move_pt) {
YS_DL_NODE *node;
ActorList::iterator actorIterator;
ACTOR *actor;
int move_up = 0;
node = _tbl[index];
if (node == NULL) {
actorIterator = _tbl[index];
if (actorIterator == zeroActorIterator) {
return FAILURE;
}
actor = (ACTOR *)ys_dll_get_data(node);
actor = actorIterator.operator->();
if (move_pt->y < actor->a_pt.y) {
move_up = 1;
@ -946,25 +920,24 @@ int Actor::move(int index, const Point *move_pt) {
AtoS(&actor->s_pt, &actor->a_pt);
if (move_up) {
ys_dll_reorder_up(_list, actor->node, zCompare);
_list.reorderUp(actorIterator, actorCompare);
} else {
ys_dll_reorder_down(_list, actor->node, zCompare);
_list.reorderDown(actorIterator, actorCompare);
}
return SUCCESS;
}
int Actor::moveRelative(int index, const Point *move_pt) {
YS_DL_NODE *node;
ActorList::iterator actorIterator;
ACTOR *actor;
node = _tbl[index];
if (node == NULL) {
actorIterator = _tbl[index];
if (actorIterator == zeroActorIterator) {
return FAILURE;
}
actor = (ACTOR *)ys_dll_get_data(node);
actor = actorIterator.operator->();
actor->a_pt.x += move_pt->x;
actor->a_pt.y += move_pt->y;
@ -972,29 +945,14 @@ int Actor::moveRelative(int index, const Point *move_pt) {
AtoS(&actor->s_pt, &actor->a_pt);
if (actor->a_pt.y < 0) {
ys_dll_reorder_up(_list, actor->node, zCompare);
_list.reorderUp(actorIterator, actorCompare);
} else {
ys_dll_reorder_down(_list, actor->node, zCompare);
_list.reorderDown(actorIterator, actorCompare);
}
return SUCCESS;
}
static int zCompare(const void *elem1, const void *elem2) {
const ACTOR *actor1 = (const ACTOR *) elem1;
const ACTOR *actor2 = (const ACTOR *) elem2;
if (actor1->a_pt.y == actor2->a_pt.y) {
return 0;
} else if (actor1->a_pt.y < actor2->a_pt.y) {
return -1;
} else {
return 1;
}
}
int Actor::AtoS(Point *screen, const Point *actor) {
screen->x = (actor->x / ACTOR_LMULT);

View file

@ -26,8 +26,9 @@
#ifndef SAGA_ACTOR_H__
#define SAGA_ACTOR_H__
#include "saga/yslib.h"
#include "saga/sprite.h"
#include "saga/actordata.h"
#include "saga/list.h"
namespace Saga {
@ -87,6 +88,16 @@ struct ACTORACTION {
ACTORACTIONITEM dir[4];
};
struct WALKNODE {
int calc_flag;
Point node_pt;
WALKNODE() {
calc_flag = 0;
}
};
typedef Common::List<WALKNODE> WalkNodeList;
struct WALKINTENT {
int wi_active;
uint16 wi_flags;
@ -99,24 +110,48 @@ struct WALKINTENT {
Point cur;
Point dst_pt;
YS_DL_LIST *nodelist;
WalkNodeList nodelist;
int sem_held;
SEMAPHORE *sem;
WALKINTENT() { memset(this, 0, sizeof(*this)); }
WALKINTENT() {
wi_active = 0;
wi_flags = 0;
wi_init = 0;
time = 0;
slope = 0;
x_dir = 0;
sem_held = 0;
sem = NULL;
}
};
struct WALKNODE {
int calc_flag;
Point node_pt;
struct ACTORDIALOGUE {
int d_playing;
const char *d_string;
uint16 d_voice_rn;
long d_time;
int d_sem_held;
SEMAPHORE *d_sem;
ACTORDIALOGUE() { memset(this, 0, sizeof(*this)); }
};
typedef Common::List<ACTORDIALOGUE> ActorDialogList;
struct SPEAKINTENT {
int si_init;
uint16 si_flags;
int si_last_action;
YS_DL_LIST *si_diaglist; /* Actor dialogue list */
ActorDialogList si_diaglist; /* Actor dialogue list */
SPEAKINTENT() {
si_init = 0;
si_flags = 0;
si_last_action = 0;
}
};
struct ACTORINTENT {
@ -125,9 +160,42 @@ struct ACTORINTENT {
int a_idone;
void *a_data;
void createData() {
assert(a_data == NULL);
if(INTENT_SPEAK == a_itype) {
a_data = new SPEAKINTENT;
}
else
if(INTENT_PATH == a_itype) {
a_data = new WALKINTENT;
}
}
void deleteData() {
if(INTENT_SPEAK == a_itype) {
SPEAKINTENT *a_speakint;
assert(a_data);
a_speakint = (SPEAKINTENT *)a_data;
delete a_speakint;
}
else
if(INTENT_PATH == a_itype) {
WALKINTENT *a_walkint;
assert(a_data);
a_walkint = (WALKINTENT *)a_data;
delete a_walkint;
}
a_data = NULL;
}
ACTORINTENT() { memset(this, 0, sizeof(*this)); }
};
typedef Common::List<ACTORINTENT> ActorIntentList;
struct ACTOR {
int id; // Actor id
int name_i; // Actor's index in actor name string list
@ -151,7 +219,7 @@ struct ACTOR {
// intent before moving on to the next; thus actor movements, esp
// as described from scripts, can be serialized
YS_DL_LIST *a_intentlist;
ActorIntentList a_intentlist;
// WALKPATH path;
@ -165,19 +233,30 @@ struct ACTOR {
ACTORACTION *act_tbl; // Action lookup table
int action_ct; // Number of actions in the action LUT
YS_DL_NODE *node; // Actor's node in the actor list
ACTOR() { memset(this, 0, sizeof(*this)); }
ACTOR() {
id = 0;
name_i = 0;
flags = 0;
sl_rn = 0;
si_rn = 0;
sl_p = 0;
idle_time = 0;
orient = 0;
speaking = 0;
a_dcolor = 0;
def_action = 0;
def_action_flags = 0;
action = 0;
action_flags = 0;
action_frame = 0;
action_time = 0;
act_tbl = NULL;
action_ct = NULL;
}
};
struct ACTORDIALOGUE {
int d_playing;
const char *d_string;
uint16 d_voice_rn;
long d_time;
int d_sem_held;
SEMAPHORE *d_sem;
ACTORDIALOGUE() { memset(this, 0, sizeof(*this)); }
};
typedef SortedList<ACTOR> ActorList;
struct ACTIONTIMES {
int action;
@ -235,9 +314,9 @@ private:
bool _initialized;
RSCFILE_CONTEXT *_actorContext;
uint16 _count;
int *_aliasTbl;
YS_DL_NODE **_tbl;
YS_DL_LIST *_list;
int _aliasTbl[ACTORCOUNT];
ActorList::iterator _tbl[ACTORCOUNT];
ActorList _list;
};
} // End of namespace Saga

View file

@ -31,6 +31,7 @@
#include "saga/render.h"
#include "saga/animation.h"
#include "saga/stream.h"
namespace Saga {
@ -105,7 +106,7 @@ int Anim::load(const byte *anim_resdata, size_t anim_resdata_len, uint16 *anim_i
getFrameOffset(anim_resdata, anim_resdata_len, i + 1, &new_anim->frame_offsets[i]);
}
} else {
new_anim->cur_frame_p = anim_resdata + SAGA_FRAME_HEADER_LEN;
new_anim->cur_frame_p = anim_resdata + SAGA_FRAME_HEADER_LEN; // ? len - may vary
new_anim->cur_frame_len = anim_resdata_len - SAGA_FRAME_HEADER_LEN;
getNumFrames(anim_resdata, anim_resdata_len, &new_anim->n_frames);
}
@ -372,12 +373,13 @@ int Anim::getNumFrames(const byte *anim_resource, size_t anim_resource_len, uint
if (!_initialized) {
return FAILURE;
}
MemoryReadStream readS(anim_resource, anim_resource_len);
MemoryReadStreamEndian readS(anim_resource, anim_resource_len, IS_BIG_ENDIAN);
ah.magic = readS.readUint16LE();
ah.screen_w = readS.readUint16LE();
ah.screen_h = readS.readUint16LE();
ah.magic = readS.readUint16LE(); // cause ALWAYS LE
ah.screen_w = readS.readUint16();
ah.screen_h = readS.readUint16();
ah.unknown06 = readS.readByte();
ah.unknown07 = readS.readByte();
@ -394,7 +396,7 @@ int Anim::getNumFrames(const byte *anim_resource, size_t anim_resource_len, uint
}
magic = *(anim_resource + offset);
if (magic == SAGA_FRAME_HEADER_MAGIC) {
if (magic == SAGA_FRAME_START) {
*n_frames = x;
return SUCCESS;
}
@ -435,11 +437,11 @@ int Anim::ITE_DecodeFrame(const byte *resdata, size_t resdata_len, size_t frame_
return FAILURE;
}
MemoryReadStream headerReadS(resdata, resdata_len);
MemoryReadStreamEndian headerReadS(resdata, resdata_len, IS_BIG_ENDIAN);
// Read animation header
ah.magic = headerReadS.readUint16LE();
ah.screen_w = headerReadS.readUint16LE();
ah.screen_h = headerReadS.readUint16LE();
ah.screen_w = headerReadS.readUint16();
ah.screen_h = headerReadS.readUint16();
ah.unknown06 = headerReadS.readByte();
ah.unknown07 = headerReadS.readByte();
ah.nframes = headerReadS.readByte();
@ -456,22 +458,21 @@ int Anim::ITE_DecodeFrame(const byte *resdata, size_t resdata_len, size_t frame_
return FAILURE;
}
// Read frame header
MemoryReadStream readS(resdata + frame_offset, resdata_len - frame_offset);
// Check for frame magic byte
magic = readS.readByte();
if (magic != SAGA_FRAME_HEADER_MAGIC) {
if (magic != SAGA_FRAME_START) {
warning("ITE_DecodeFrame: Invalid frame offset");
return FAILURE;
}
// For some strange reason, the animation header is in little
// endian format, but the actual RLE encoded frame data,
// including the frame header, is in big endian format.
fh.x_start = readS.readUint16BE();
fh.y_start = readS.readByte();
if (IS_MAC_VERSION)
fh.y_start = readS.readUint16BE();
else
fh.y_start = readS.readByte();
readS.readByte(); /* Skip pad byte */
fh.x_pos = readS.readUint16BE();
fh.y_pos = readS.readUint16BE();
@ -481,14 +482,25 @@ int Anim::ITE_DecodeFrame(const byte *resdata, size_t resdata_len, size_t frame_
x_start = fh.x_start;
y_start = fh.y_start;
#if 1
#define VALIDATE_WRITE_POINTER \
if ((write_p < buf) || (write_p >= (buf + screen_w * screen_h))) { \
warning("VALIDATE_WRITE_POINTER: write_p=%x buf=%x", write_p, buf); \
return FAILURE; \
}
#else
#define VALIDATE_WRITE_POINTER
#endif
// Setup write pointer to the draw origin
write_p = (buf + (y_start * screen_w) + x_start);
VALIDATE_WRITE_POINTER;
// Begin RLE decompression to output buffer
do {
mark_byte = readS.readByte();
switch (mark_byte) {
case 0x10: // Long Unencoded Run
case SAGA_FRAME_LONG_UNCOMPRESSED_RUN: // Long Unencoded Run
runcount = readS.readSint16BE();
for (i = 0; i < runcount; i++) {
data_byte = readS.readByte();
@ -496,30 +508,39 @@ int Anim::ITE_DecodeFrame(const byte *resdata, size_t resdata_len, size_t frame_
*write_p = data_byte;
}
write_p++;
VALIDATE_WRITE_POINTER;
}
continue;
break;
case 0x20: // Long encoded run
case SAGA_FRAME_LONG_COMPRESSED_RUN: // Long encoded run
runcount = readS.readSint16BE();
data_byte = readS.readByte();
for (i = 0; i < runcount; i++) {
*write_p++ = data_byte;
VALIDATE_WRITE_POINTER;
}
continue;
break;
case 0x2F: // End of row
case SAGA_FRAME_ROW_END: // End of row
x_vector = readS.readSint16BE();
new_row = readS.readByte();
if (IS_MAC_VERSION)
new_row = readS.readSint16BE();
else
new_row = readS.readByte();
// Set write pointer to the new draw origin
write_p = buf + ((y_start + new_row) * screen_w) + x_start + x_vector;
VALIDATE_WRITE_POINTER;
continue;
break;
case 0x30: // Reposition command
case SAGA_FRAME_REPOSITION: // Reposition command
x_vector = readS.readSint16BE();
write_p += x_vector;
VALIDATE_WRITE_POINTER;
continue;
break;
case 0x3F: // End of frame marker
case SAGA_FRAME_END: // End of frame marker
return SUCCESS;
break;
default:
@ -530,22 +551,24 @@ int Anim::ITE_DecodeFrame(const byte *resdata, size_t resdata_len, size_t frame_
control_ch = mark_byte & 0xC0U;
param_ch = mark_byte & 0x3FU;
switch (control_ch) {
case 0xC0: // 1100 0000
case SAGA_FRAME_EMPTY_RUN: // 1100 0000
// Run of empty pixels
runcount = param_ch + 1;
write_p += runcount;
VALIDATE_WRITE_POINTER;
continue;
break;
case 0x80: // 1000 0000
case SAGA_FRAME_COMPRESSED_RUN: // 1000 0000
// Run of compressed data
runcount = param_ch + 1;
data_byte = readS.readByte();
for (i = 0; i < runcount; i++) {
*write_p++ = data_byte;
VALIDATE_WRITE_POINTER;
}
continue;
break;
case 0x40: // 0100 0000
case SAGA_FRAME_UNCOMPRESSED_RUN: // 0100 0000
// Uncompressed run
runcount = param_ch + 1;
for (i = 0; i < runcount; i++) {
@ -554,6 +577,7 @@ int Anim::ITE_DecodeFrame(const byte *resdata, size_t resdata_len, size_t frame_
*write_p = data_byte;
}
write_p++;
VALIDATE_WRITE_POINTER;
}
continue;
break;
@ -586,7 +610,7 @@ int Anim::IHNM_DecodeFrame(byte *decode_buf, size_t decode_buf_len, const byte *
size_t in_ch_offset;
MemoryReadStream readS(thisf_p, thisf_len);
MemoryReadStreamEndian readS(thisf_p, thisf_len, !IS_BIG_ENDIAN); // RLE has inversion BE<>LE
byte *outbuf_p = decode_buf;
byte *outbuf_endp = (decode_buf + decode_buf_len) - 1;
@ -616,13 +640,13 @@ int Anim::IHNM_DecodeFrame(byte *decode_buf, size_t decode_buf_len, const byte *
return FAILURE;
}
param1 = readS.readUint16BE();
param2 = readS.readUint16BE();
param1 = readS.readUint16();
param2 = readS.readUint16();
readS.readByte(); // skip 1?
param3 = readS.readUint16BE();
param4 = readS.readUint16BE();
param5 = readS.readUint16BE();
param6 = readS.readUint16BE();
param3 = readS.readUint16();
param4 = readS.readUint16();
param5 = readS.readUint16();
param6 = readS.readUint16();
x_origin = param1;
y_origin = param2;
@ -639,8 +663,8 @@ int Anim::IHNM_DecodeFrame(byte *decode_buf, size_t decode_buf_len, const byte *
continue;
}
break;
case 0x10: // Long Unencoded Run
runcount = readS.readSint16BE();
case SAGA_FRAME_LONG_UNCOMPRESSED_RUN: // Long Unencoded Run
runcount = readS.readSint16();
if (thisf_len - readS.pos() < runcount) {
warning("0x%02X: Input buffer underrun", in_ch);
return FAILURE;
@ -672,13 +696,13 @@ int Anim::IHNM_DecodeFrame(byte *decode_buf, size_t decode_buf_len, const byte *
readS.readByte();
continue;
break;
case 0x20: // Long compressed run
case SAGA_FRAME_LONG_COMPRESSED_RUN: // Long compressed run
if (thisf_len - readS.pos() <= 3) {
warning("0x%02X: Input buffer underrun", in_ch);
return FAILURE;
}
runcount = readS.readSint16BE();
runcount = readS.readSint16();
data_pixel = readS.readByte();
for (c = 0; c < runcount; c++) {
@ -689,27 +713,27 @@ int Anim::IHNM_DecodeFrame(byte *decode_buf, size_t decode_buf_len, const byte *
continue;
break;
case 0x2F: // End of row
case SAGA_FRAME_ROW_END: // End of row
if (thisf_len - readS.pos() <= 4) {
return FAILURE;
}
x_vector = readS.readSint16BE();
new_row = readS.readSint16BE();
x_vector = readS.readSint16();
new_row = readS.readSint16();
outbuf_p = decode_buf + ((y_origin + new_row) * di.logical_w) + x_origin + x_vector;
outbuf_remain = (outbuf_endp - outbuf_p) + 1;
continue;
break;
case 0x30: // Reposition command
case SAGA_FRAME_REPOSITION: // Reposition command
if (thisf_len - readS.pos() < 2) {
return FAILURE;
}
x_vector = readS.readSint16BE();
x_vector = readS.readSint16();
if (((x_vector > 0) && ((size_t) x_vector > outbuf_remain)) || (-x_vector > outbuf_p - decode_buf)) {
warning("0x30: Invalid x_vector");
warning("SAGA_FRAME_REPOSITION: Invalid x_vector");
return FAILURE;
}
@ -718,8 +742,8 @@ int Anim::IHNM_DecodeFrame(byte *decode_buf, size_t decode_buf_len, const byte *
continue;
break;
case 0x3F: // 68: Frame end marker
debug(1, "0x3F: Frame end marker");
case SAGA_FRAME_END: // Frame end marker
debug(1, "SAGA_FRAME_END: Frame end marker");
if (decoded_data && (thisf_len - readS.pos() > 0)) {
*nextf_p = thisf_p + readS.pos();
*nextf_len = thisf_len - readS.pos();
@ -740,7 +764,7 @@ int Anim::IHNM_DecodeFrame(byte *decode_buf, size_t decode_buf_len, const byte *
param_ch = in_ch & 0x3f;
switch (control_ch) {
case 0xC0: // Run of empty pixels
case SAGA_FRAME_EMPTY_RUN: // Run of empty pixels
runcount = param_ch + 1;
if (outbuf_remain < runcount) {
return FAILURE;
@ -750,7 +774,7 @@ int Anim::IHNM_DecodeFrame(byte *decode_buf, size_t decode_buf_len, const byte *
outbuf_remain -= runcount;
continue;
break;
case 0x80: // Run of compressed data
case SAGA_FRAME_COMPRESSED_RUN: // Run of compressed data
runcount = param_ch + 1;
if ((outbuf_remain < runcount) || (thisf_len - readS.pos() <= 1)) {
return FAILURE;
@ -765,7 +789,7 @@ int Anim::IHNM_DecodeFrame(byte *decode_buf, size_t decode_buf_len, const byte *
outbuf_remain -= runcount;
continue;
break;
case 0x40: // Uncompressed run
case SAGA_FRAME_UNCOMPRESSED_RUN: // Uncompressed run
runcount = param_ch + 1;
if ((outbuf_remain < runcount) || (thisf_len - readS.pos() < runcount)) {
return FAILURE;
@ -809,12 +833,13 @@ int Anim::getFrameOffset(const byte *resdata, size_t resdata_len, uint16 find_fr
return FAILURE;
}
MemoryReadStream readS(resdata, resdata_len);
MemoryReadStreamEndian readS(resdata, resdata_len, IS_BIG_ENDIAN);
// Read animation header
ah.magic = readS.readUint16LE();
ah.screen_w = readS.readUint16LE();
ah.screen_h = readS.readUint16LE();
ah.screen_w = readS.readUint16();
ah.screen_h = readS.readUint16();
ah.unknown06 = readS.readByte();
ah.unknown07 = readS.readByte();
ah.nframes = readS.readByte();
@ -828,9 +853,11 @@ int Anim::getFrameOffset(const byte *resdata, size_t resdata_len, uint16 find_fr
return FAILURE;
}
readS._bigEndian = !IS_BIG_ENDIAN; // RLE has inversion BE<>LE
for (current_frame = 1; current_frame < find_frame; current_frame++) {
magic = readS.readByte();
if (magic != SAGA_FRAME_HEADER_MAGIC) {
if (magic != SAGA_FRAME_START) {
// Frame sync failure. Magic Number not found
return FAILURE;
}
@ -839,33 +866,36 @@ int Anim::getFrameOffset(const byte *resdata, size_t resdata_len, uint16 find_fr
for (i = 0; i < SAGA_FRAME_HEADER_LEN; i++)
readS.readByte();
// For some strange reason, the animation header is in little
// endian format, but the actual RLE encoded frame data,
// including the frame header, is in big endian format. */
do {
mark_byte = readS.readByte();
// debug(7, "_pos=%x mark_byte=%x", readS.pos(), mark_byte);
switch (mark_byte) {
case 0x3F: // End of frame marker
case SAGA_FRAME_END: // End of frame marker
continue;
break;
case 0x30: // Reposition command
readS.readByte();
case SAGA_FRAME_REPOSITION: // Reposition command
readS.readSint16BE();
continue;
break;
case SAGA_FRAME_ROW_END: // End of row marker
readS.readSint16BE();
if (IS_MAC_VERSION)
readS.readSint16BE();
else
readS.readByte();
continue;
break;
case SAGA_FRAME_LONG_COMPRESSED_RUN: // Long compressed run marker
readS.readSint16BE();
readS.readByte();
continue;
break;
case 0x2F: // End of row marker
readS.readByte();
readS.readByte();
readS.readByte();
continue;
break;
case 0x20: // Long compressed run marker
readS.readByte();
readS.readByte();
readS.readByte();
continue;
break;
case 0x10: // (16) 0001 0000
case SAGA_FRAME_LONG_UNCOMPRESSED_RUN: // (16) 0001 0000
// Long Uncompressed Run
runcount = readS.readSint16BE();
for (i = 0; i < runcount; i++)
@ -879,16 +909,16 @@ int Anim::getFrameOffset(const byte *resdata, size_t resdata_len, uint16 find_fr
// Mask all but two high order (control) bits
control = mark_byte & 0xC0;
switch (control) {
case 0xC0:
case SAGA_FRAME_EMPTY_RUN:
// Run of empty pixels
continue;
break;
case 0x80:
case SAGA_FRAME_COMPRESSED_RUN:
// Run of compressed data
readS.readByte(); // Skip data byte
continue;
break;
case 0x40:
case SAGA_FRAME_UNCOMPRESSED_RUN:
// Uncompressed run
runcount = (mark_byte & 0x3f) + 1;
for (i = 0; i < runcount; i++)
@ -900,7 +930,7 @@ int Anim::getFrameOffset(const byte *resdata, size_t resdata_len, uint16 find_fr
return FAILURE;
break;
}
} while (mark_byte != 63);
} while (mark_byte != SAGA_FRAME_END);
}
*frame_offset_p = readS.pos();

View file

@ -31,8 +31,17 @@ namespace Saga {
#define MAX_ANIMATIONS 7
#define DEFAULT_FRAME_TIME 140
#define SAGA_FRAME_HEADER_MAGIC 15
#define SAGA_FRAME_HEADER_LEN 12
#define SAGA_FRAME_HEADER_LEN (IS_MAC_VERSION ? 13 : 12)
#define SAGA_FRAME_START 0xF
#define SAGA_FRAME_END 0x3F
#define SAGA_FRAME_REPOSITION 0x30
#define SAGA_FRAME_ROW_END 0x2F
#define SAGA_FRAME_LONG_COMPRESSED_RUN 0x20
#define SAGA_FRAME_LONG_UNCOMPRESSED_RUN 0x10
#define SAGA_FRAME_COMPRESSED_RUN 0x80
#define SAGA_FRAME_UNCOMPRESSED_RUN 0x40
#define SAGA_FRAME_EMPTY_RUN 0xC0
// All animation resources begin with an ANIMATION_HEADER
// at 0x00, followed by a RLE code stream

View file

@ -27,7 +27,6 @@
#include "saga/saga.h"
#include "saga/gfx.h"
#include "saga/yslib.h"
#include "saga/animation.h"
#include "saga/console.h"
@ -46,10 +45,7 @@ namespace Saga {
Events::Events(SagaEngine *vm) : _vm(vm), _initialized(false) {
debug(0, "Initializing event subsystem...");
_eventList = ys_dll_create();
if (_eventList)
_initialized = true;
_initialized = true;
}
Events::~Events(void) {
@ -61,9 +57,6 @@ Events::~Events(void) {
// First advances event times, then processes each event with the appropriate
// handler depending on the type of event.
int Events::handleEvents(long msec) {
YS_DL_NODE *walk_node;
YS_DL_NODE *next_node;
EVENT *event_p;
long delta_time;
@ -73,11 +66,8 @@ int Events::handleEvents(long msec) {
processEventTime(msec);
// Process each event in list
for (walk_node = ys_dll_head(_eventList); walk_node != NULL; walk_node = next_node) {
event_p = (EVENT *)ys_dll_get_data(walk_node);
// Save next event in case current event is handled and removed
next_node = ys_dll_next(walk_node);
for (EventList::iterator eventi = _eventList.begin(); eventi != _eventList.end(); ++eventi) {
event_p = (EVENT *)eventi.operator->();
// Call the appropriate event handler for the specific event type
switch (event_p->type) {
@ -109,19 +99,18 @@ int Events::handleEvents(long msec) {
if ((result == EVENT_DELETE) || (result == EVENT_INVALIDCODE)) {
// If there is no event chain, delete the base event.
if (event_p->chain == NULL) {
ys_dll_delete(walk_node);
eventi=_eventList.eraseAndPrev(eventi);
} else {
// If there is an event chain present, move the next event
// in the chain up, adjust it by the previous delta time,
// and reprocess the event by adjusting next_node. */
// and reprocess the event */
delta_time = event_p->time;
EVENT *from_chain=event_p->chain;
memcpy(event_p, from_chain,sizeof *event_p);
free(from_chain);
ys_dll_replace(walk_node, event_p->chain, sizeof *event_p);
event_p = (EVENT *)ys_dll_get_data(walk_node);
event_p->time += delta_time;
next_node = walk_node;
--eventi;
}
} else if (result == EVENT_BREAK) {
break;
@ -426,17 +415,10 @@ int Events::handleInterval(EVENT *event) {
// Schedules an event in the event list; returns a pointer to the scheduled
// event suitable for chaining if desired.
EVENT *Events::queue(EVENT *event) {
YS_DL_NODE *new_node;
EVENT *queued_event;
event->chain = NULL;
new_node = ys_dll_add_tail(_eventList, event, sizeof *event);
if (new_node == NULL) {
return NULL;
}
queued_event = (EVENT *)ys_dll_get_data(new_node);
queued_event = _eventList.pushBack(*event).operator->();
initializeEvent(queued_event);
@ -490,16 +472,13 @@ int Events::initializeEvent(EVENT *event) {
}
int Events::clearList() {
YS_DL_NODE *walk_node;
YS_DL_NODE *next_node;
EVENT *chain_walk;
EVENT *next_chain;
EVENT *event_p;
// Walk down event list
for (walk_node = ys_dll_head(_eventList); walk_node != NULL; walk_node = next_node) {
next_node = ys_dll_next(walk_node);
event_p = (EVENT *)ys_dll_get_data(walk_node);
for (EventList::iterator eventi = _eventList.begin(); eventi != _eventList.end(); ++eventi) {
event_p = (EVENT *)eventi.operator->();
// Only remove events not marked NODESTROY (engine events)
if (!(event_p->code & NODESTROY)) {
@ -508,7 +487,7 @@ int Events::clearList() {
next_chain = chain_walk->chain;
free(chain_walk);
}
ys_dll_delete(walk_node);
eventi=_eventList.eraseAndPrev(eventi);
}
}
@ -517,24 +496,21 @@ int Events::clearList() {
// Removes all events from the list (even NODESTROY)
int Events::freeList() {
YS_DL_NODE *walk_node;
YS_DL_NODE *next_node;
EVENT *chain_walk;
EVENT *next_chain;
EVENT *event_p;
// Walk down event list
for (walk_node = ys_dll_head(_eventList); walk_node != NULL; walk_node = next_node) {
event_p = (EVENT *)ys_dll_get_data(walk_node);
// Remove any events chained off current node
EventList::iterator eventi = _eventList.begin();
while (eventi != _eventList.end()) {
event_p = (EVENT *)eventi.operator->();
// Remove any events chained off this one */
for (chain_walk = event_p->chain; chain_walk != NULL; chain_walk = next_chain) {
next_chain = chain_walk->chain;
free(chain_walk);
}
// Delete current node
next_node = ys_dll_next(walk_node);
ys_dll_delete(walk_node);
eventi=_eventList.erase(eventi);
}
return SUCCESS;
@ -542,12 +518,12 @@ int Events::freeList() {
// Walks down the event list, updating event times by 'msec'.
int Events::processEventTime(long msec) {
YS_DL_NODE *walk_node;
EVENT *event_p;
uint16 event_count = 0;
for (walk_node = ys_dll_head(_eventList); walk_node != NULL; walk_node = ys_dll_next(walk_node)) {
event_p = (EVENT *)ys_dll_get_data(walk_node);
for (EventList::iterator eventi = _eventList.begin(); eventi != _eventList.end(); ++eventi) {
event_p = (EVENT *)eventi.operator->();
event_p->time -= msec;
event_count++;

View file

@ -26,7 +26,10 @@
#ifndef SAGA_EVENT_H
#define SAGA_EVENT_H
#include "saga/list.h"
namespace Saga {
enum EVENT_TYPES {
ONESHOT_EVENT,
CONTINUOUS_EVENT,
@ -119,6 +122,8 @@ struct EVENT {
EVENT() { memset(this, 0, sizeof(*this)); }
};
typedef SortedList<EVENT> EventList;
#define EVENT_WARNINGCOUNT 1000
#define EVENT_MASK 0x00FF
@ -151,7 +156,7 @@ class Events {
SagaEngine *_vm;
bool _initialized;
YS_DL_LIST *_eventList;
EventList _eventList;
};
} // End of namespace Saga

View file

@ -29,6 +29,7 @@
#include "saga/game_mod.h"
#include "saga/font.h"
#include "saga/stream.h"
namespace Saga {
@ -64,20 +65,20 @@ Font::~Font(void) {
debug(0, "Font::~Font(): Freeing fonts.");
/*
for ( i = 0 ; i < FONT_COUNT ; i ++ ) {
if ( _fonts[i] != NULL ) {
if ( _fonts[i]->normal_loaded ) {
free( _fonts[i]->normal->font_free_p );
free( _fonts[i]->normal );
for (i = 0 ; i < FONT_COUNT ; i++) {
if (_fonts[i] != NULL) {
if (_fonts[i]->normal_loaded) {
free(_fonts[i]->normal->font_free_p);
free(_fonts[i]->normal);
}
if ( _fonts[i]->outline_loaded ) {
free( _fonts[i]->outline->font_free_p );
free( _fonts[i]->outline );
if (_fonts[i]->outline_loaded) {
free(_fonts[i]->outline->font_free_p);
free(_fonts[i]->outline);
}
}
free( _fonts[i] );
free(_fonts[i]);
}
*/
}
@ -106,7 +107,7 @@ int Font::loadFont(uint32 font_rn, int font_id) {
return FAILURE;
}
MemoryReadStream readS(fontres_p, fontres_len);
MemoryReadStreamEndian readS(fontres_p, fontres_len, IS_BIG_ENDIAN);
// Create new font structure
font = (FONT *)malloc(sizeof *font);
@ -116,9 +117,9 @@ int Font::loadFont(uint32 font_rn, int font_id) {
}
// Read font header
fh.c_height = readS.readUint16LE();
fh.c_width = readS.readUint16LE();
fh.row_length = readS.readUint16LE();
fh.c_height = readS.readUint16();
fh.c_width = readS.readUint16();
fh.row_length = readS.readUint16();
debug(1, "Font::loadFont(): Reading font resource #%d...", font_rn);
@ -140,7 +141,7 @@ int Font::loadFont(uint32 font_rn, int font_id) {
normal_font->hdr.row_length = fh.row_length;
for (c = 0; c < FONT_CHARCOUNT; c++) {
normal_font->fce[c].index = readS.readUint16LE();
normal_font->fce[c].index = readS.readUint16();
}
for (c = 0; c < FONT_CHARCOUNT; c++) {

View file

@ -50,12 +50,26 @@ GAME_FILEDESC ITEDEMO_GameFiles[] = {
GAME_FONTDESC ITEDEMO_GameFonts[] = {
{GAME_FONT_SMALL, 0},
{GAME_FONT_MEDIUM, 1}
};
};
GAME_SOUNDINFO ITEDEMO_GameSound = {
GAME_SOUND_VOC, 0, 0, 0
};
// Inherit the Earth - MAC Wyrmkeep Demo version
GAME_FILEDESC ITEMACDEMO_GameFiles[] = {
{"ITED.RSC", GAME_RESOURCEFILE},
{"SCRIPTSD.RSC", GAME_SCRIPTFILE},
{"SOUNDSD.RSC", GAME_SOUNDFILE},
{"VOICESD.RSC", GAME_VOICEFILE},
{"MUSICD.RSC", GAME_MUSICFILE}
};
GAME_FONTDESC ITEMACDEMO_GameFonts[] = {
{GAME_FONT_MEDIUM, 0},
{GAME_FONT_SMALL, 2}
};
// Inherit the Earth - win32 Wyrmkeep Linux Demo version
GAME_FILEDESC ITEWINDEMO_GameFiles[] = {
{"ITED.RSC", GAME_RESOURCEFILE},
@ -65,6 +79,11 @@ GAME_FILEDESC ITEWINDEMO_GameFiles[] = {
{"MUSICD.RSC", GAME_MUSICFILE}
};
GAME_FONTDESC ITEWINDEMO_GameFonts[] = {
{GAME_FONT_MEDIUM, 0},
{GAME_FONT_SMALL, 2}
};
// Inherit the Earth - win32 Wyrmkeep Demo version older release
GAME_FILEDESC ITEWINDEMOOld_GameFiles[] = {
{"ITED.RSC", GAME_RESOURCEFILE},
@ -93,6 +112,13 @@ GAME_RESOURCEDESC ITE_Resources = {
ITE_DIALOGUE_PANEL
};
GAME_RESOURCEDESC ITEMACDEMO_Resources = {
ITEMACDEMO_SCENE_LUT, // Scene lookup table RN
ITE_SCRIPT_LUT, // Script lookup table RN
ITE_COMMAND_PANEL,
ITE_DIALOGUE_PANEL
};
GAME_SOUNDINFO ITE_GameSound = {
GAME_SOUND_VOC, 0, 0, 0
};
@ -179,7 +205,26 @@ GAMEDESC GameDescs[] = {
ARRAYSIZE(ITEDEMO_GameFonts),
ITEDEMO_GameFonts,
&ITEDEMO_GameSound,
0 // features
0, // features
},
// Inherit the earth - MAC Demo version
// Note: it should be before win32 version ???
{
"ite-demo",
GID_ITE,
GAME_ITE_MACDEMO,
"Inherit the Earth (MAC Demo)",
320, 200,
137,
ITE_DEFAULT_SCENE,
&ITEMACDEMO_Resources,
ARRAYSIZE(ITEMACDEMO_GameFiles),
ITEMACDEMO_GameFiles,
ARRAYSIZE(ITEMACDEMO_GameFonts),
ITEMACDEMO_GameFonts,
&ITECD_GameSound,
GF_VOX_VOICES | GF_BIG_ENDIAN_DATA
},
// Inherit the earth - Linux Demo version
@ -213,8 +258,8 @@ GAMEDESC GameDescs[] = {
&ITE_Resources,
ARRAYSIZE(ITEWINDEMOOld_GameFiles),
ITEWINDEMO_GameFiles,
ARRAYSIZE(ITECD_GameFonts),
ITECD_GameFonts,
ARRAYSIZE(ITEWINDEMO_GameFonts),
ITEWINDEMO_GameFonts,
&ITECD_GameSound,
GF_VOX_VOICES
},
@ -465,8 +510,11 @@ int LoadGame(uint16 game_n) {
return FAILURE;
}
game_filect = GameDescs[game_n].gd_filect;
GameModule.game_number = game_n;
GameModule.gamedesc = &GameDescs[game_n];
game_filect = GameDescs[game_n].gd_filect;
GameModule.gfile_data = (GAME_FILEDATA *)malloc(game_filect * sizeof *GameModule.gfile_data);
if (GameModule.gfile_data == NULL) {
return MEM;
@ -493,8 +541,6 @@ int LoadGame(uint16 game_n) {
GameModule.gd_fontdescs = GameDescs[game_n].gd_fontdescs;
// Finish initialization
GameModule.game_number = game_n;
GameModule.gamedesc = &GameDescs[game_n];
GameModule.game_init = 1;
return SUCCESS;
@ -552,11 +598,11 @@ int GAME_GetSceneInfo(GAME_SCENEDESC *gs_desc) {
return SUCCESS;
}
int GAME_GetGame() {
GAME_IDS GAME_GetGame() {
return GameModule.gamedesc->gd_game_id;
}
int GAME_GetGameType() {
SAGAGameId GAME_GetGameType() {
return GameModule.gamedesc->gd_game_type;
}

View file

@ -47,8 +47,8 @@ struct GAME_FILEDESC {
struct GAMEDESC {
const char *name;
int gd_game_type;
uint32 gd_game_id;
SAGAGameId gd_game_type;
GAME_IDS gd_game_id;
const char *gd_title;
int gd_logical_w;
int gd_logical_h;

View file

@ -30,13 +30,18 @@
namespace Saga {
#define IS_BIG_ENDIAN ((GAME_GetFeatures() & GF_BIG_ENDIAN_DATA) != 0)
#define IS_MAC_VERSION (GAME_GetGame() == GAME_ITE_MACDEMO)
enum GAME_IDS {
GAME_ITE_DEMO = 0,
GAME_ITE_DISK = 1,
GAME_ITE_CD = 2,
GAME_IHNM_DEMO = 3,
GAME_IHNM_CD = 4,
GAME_ITE_WINDEMO = 5
GAME_ITE_WINDEMO = 5,
GAME_ITE_MACDEMO = 6
};
enum GAME_FILETYPES {
@ -68,7 +73,8 @@ enum GAME_FONT_IDS {
};
enum GAME_FEATURES {
GF_VOX_VOICES = 1
GF_VOX_VOICES = 1,
GF_BIG_ENDIAN_DATA = 2
};
struct GAME_DISPLAYINFO {
@ -109,11 +115,10 @@ int GAME_GetResourceInfo(GAME_RESOURCEDESC *);
int GAME_GetSoundInfo(GAME_SOUNDINFO *);
int GAME_GetDisplayInfo(GAME_DISPLAYINFO *);
int GAME_GetSceneInfo(GAME_SCENEDESC *);
int GAME_GetGame();
int GAME_GetGameType();
GAME_IDS GAME_GetGame();
SAGAGameId GAME_GetGameType();
DetectedGameList GAME_ProbeGame(const FSList &fslist);
uint32 GAME_GetFeatures();
} // End of namespace Saga
#endif

View file

@ -24,7 +24,6 @@
// "I Have No Mouth" Intro sequence scene procedures
#include "saga/saga.h"
#include "saga/yslib.h"
#include "saga/gfx.h"
#include "saga/animation.h"

View file

@ -27,6 +27,7 @@
#include "saga/game_mod.h"
#include "saga/image.h"
#include "saga/stream.h"
namespace Saga {
@ -64,13 +65,13 @@ int SagaEngine::decodeBGImage(const byte *image_data, size_t image_size,
return FAILURE;
}
MemoryReadStream readS(image_data, image_size);
MemoryReadStreamEndian readS(image_data, image_size, IS_BIG_ENDIAN);
hdr.width = readS.readUint16LE();
hdr.height = readS.readUint16LE();
hdr.width = readS.readUint16();
hdr.height = readS.readUint16();
// The next four bytes of the image header aren't used.
readS.readUint16LE();
readS.readUint16LE();
readS.readUint16();
readS.readUint16();
RLE_data_ptr = image_data + SAGA_IMAGE_DATA_OFFSET;
RLE_data_len = image_size - SAGA_IMAGE_DATA_OFFSET;

View file

@ -28,6 +28,7 @@
#include "saga/gfx.h"
#include "saga/isomap.h"
#include "saga/stream.h"
namespace Saga {
@ -46,10 +47,10 @@ int IsoMap::loadTileset(const byte *tileres_p, size_t tileres_len) {
assert((_init) && (!_tiles_loaded));
assert((tileres_p != NULL) && (tileres_len > 0));
MemoryReadStream readS(tileres_p, tileres_len);
MemoryReadStreamEndian readS(tileres_p, tileres_len, IS_BIG_ENDIAN);
readS.readUint16LE(); // skip
first_entry.tile_offset = readS.readUint16LE();
readS.readUint16(); // skip
first_entry.tile_offset = readS.readUint16();
_tile_ct = first_entry.tile_offset / SAGA_ISOTILE_ENTRY_LEN;
@ -63,9 +64,9 @@ int IsoMap::loadTileset(const byte *tileres_p, size_t tileres_len) {
for (i = 0; i < _tile_ct; i++) {
tile_tbl[i].tile_h = readS.readByte();
tile_tbl[i].mask_rule = readS.readByte();
tile_tbl[i].tile_offset = readS.readUint16LE();
tile_tbl[i].terrain_mask = readS.readSint16LE();
tile_tbl[i].mask = readS.readSint16LE();
tile_tbl[i].tile_offset = readS.readUint16();
tile_tbl[i].terrain_mask = readS.readSint16();
tile_tbl[i].mask = readS.readSint16();
}
_tiles_loaded = 1;
@ -85,7 +86,7 @@ int IsoMap::loadMetaTileset(const byte *mtileres_p, size_t mtileres_len) {
assert(_init);
assert((mtileres_p != NULL) && (mtileres_len > 0));
MemoryReadStream readS(mtileres_p, mtileres_len);
MemoryReadStreamEndian readS(mtileres_p, mtileres_len, IS_BIG_ENDIAN);
mtile_ct = mtileres_len / SAGA_METATILE_ENTRY_LEN;
mtile_tbl = (ISO_METATILE_ENTRY *)malloc(mtile_ct * sizeof *mtile_tbl);
@ -94,13 +95,13 @@ int IsoMap::loadMetaTileset(const byte *mtileres_p, size_t mtileres_len) {
}
for (ct = 0; ct < mtile_ct; ct++) {
mtile_tbl[ct].mtile_n = readS.readUint16LE();
mtile_tbl[ct].height = readS.readSint16LE();
mtile_tbl[ct].highest_pixel = readS.readSint16LE();
mtile_tbl[ct].mtile_n = readS.readUint16();
mtile_tbl[ct].height = readS.readSint16();
mtile_tbl[ct].highest_pixel = readS.readSint16();
mtile_tbl[ct].v_bits = readS.readByte();
mtile_tbl[ct].u_bits = readS.readByte();
for (i = 0; i < SAGA_METATILE_SIZE; i++) {
mtile_tbl[ct].tile_tbl[i] = readS.readUint16LE();
mtile_tbl[ct].tile_tbl[i] = readS.readUint16();
}
}
@ -117,11 +118,11 @@ int IsoMap::loadMetaTileset(const byte *mtileres_p, size_t mtileres_len) {
int IsoMap::loadMetamap(const byte *mm_res_p, size_t mm_res_len) {
int i;
MemoryReadStream readS(mm_res_p, mm_res_len);
_metamap_n = readS.readSint16LE();
MemoryReadStreamEndian readS(mm_res_p, mm_res_len, IS_BIG_ENDIAN);
_metamap_n = readS.readSint16();
for (i = 0; i < SAGA_METAMAP_SIZE; i++) {
_metamap_tbl[i] = readS.readUint16LE();
_metamap_tbl[i] = readS.readUint16();
}
_mm_res_p = mm_res_p;

View file

@ -26,7 +26,6 @@
#include "saga/saga.h"
#include "saga/gfx.h"
#include "saga/yslib.h"
#include "saga/animation.h"
#include "saga/events.h"
@ -129,6 +128,7 @@ int Scene::ITEStartProc() {
SCENE_QUEUE first_scene;
GAME_SCENEDESC gs_desc;
int game_id = GAME_GetGame();
n_introscenes = ARRAYSIZE(ITE_IntroList);
for (i = 0; i < n_introscenes; i++) {

154
saga/list.h Normal file
View file

@ -0,0 +1,154 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2004 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 SAGA_LIST_H__
#define SAGA_LIST_H__
#include "common/list.h"
namespace Saga {
template <class T>
class SortedList : public Common::List<T> {
public:
typedef int ( CompareFunction ) (const T& , const T&);
typedef typename Common::List<T>::iterator iterator;
typedef typename Common::List<T>::const_iterator const_iterator;
public:
iterator pushFront(const T& element) {
return insert(begin(), element);
}
iterator pushBack(const T& element) {
return insert(end(), element);
}
iterator insert(iterator pos, const T& element) {
Common::List<T>::insert(pos, element);
return --pos;
}
iterator pushFront() {
return insert(begin());
}
iterator pushBack() {
return insert(end());
}
iterator insert(iterator pos) {
T init;
return insert(pos, init);
}
iterator pushFront(const T& element, CompareFunction* compareFunction) {
return insert(begin(), element, compareFunction);
}
iterator pushBack(const T& element, CompareFunction* compareFunction) {
return insert(end(), element, compareFunction);
}
iterator insert(iterator pos, const T& element, CompareFunction* compareFunction) {
int res;
for (iterator i = begin(); i != end(); ++i) {
res = compareFunction(element, i.operator*());
if (res < 0) {
return insert(i, element);
}
}
return pushBack(element);
}
void reorderUp(iterator pos, CompareFunction* compareFunction) {
iterator i(pos);
int res;
--i;
while (i != end()) {
res = compareFunction(i.operator*(), pos.operator*());
if (res <= 0) {
T temp(*pos);
erase(pos);
++i;
Common::List<T>::insert(i, temp);
return;
}
--i;
}
}
void reorderDown(iterator pos, CompareFunction* compareFunction) {
iterator i(pos);
int res;
++i;
while (i != end()) {
res = compareFunction(i.operator*(), pos.operator*());
if (res >= 0) {
T temp(*pos);
erase(pos);
Common::List<T>::insert(i, temp);
return;
}
++i;
}
}
iterator eraseAndPrev(iterator pos) {
assert(pos != end());
iterator res(pos);
--res;
erase(pos);
return res;
}
void remove(const T* val) {
for (iterator i = begin(); i != end(); ++i)
if(val == i.operator->()) {
erase(i);
return;
}
}
bool locate(const T* val, iterator& foundedIterator) {
for (iterator i = begin(); i != end(); ++i)
if (val == i.operator->())
{
foundedIterator = i;
return true;
}
return false;
}
};
} // End of namespace Saga
#endif

View file

@ -25,6 +25,7 @@
#include "saga/music.h"
#include "saga/rscfile_mod.h"
#include "saga/game_mod.h"
#include "saga/stream.h"
#include "sound/audiostream.h"
#include "sound/mididrv.h"
#include "sound/midiparser.h"
@ -123,6 +124,7 @@ void RAWInputStream::refill() {
uint32 len_left;
byte *ptr = (byte *) _buf;
_file->seek(_file_pos, SEEK_SET);
@ -137,6 +139,12 @@ void RAWInputStream::refill() {
if (len & 1)
len--;
if (GAME_GetFeatures() & GF_BIG_ENDIAN_DATA) {
uint16 *ptr16 = (uint16 *)ptr;
for (uint32 i = 0; i < (len / 2); i++)
ptr16[i] = TO_BE_16(ptr16[i]);
}
len_left -= len;
ptr += len;
@ -292,6 +300,7 @@ Music::Music(SoundMixer *mixer, MidiDriver *driver, int enabled) : _mixer(mixer)
if (GAME_GetGameType() == GID_ITE) {
File file;
byte footerBuf[ARRAYSIZE(_digiTableITECD) * 8];
// The lookup table is stored at the end of music.rsc. I don't
// know why it has 27 elements, but the last one represents a
@ -312,11 +321,17 @@ Music::Music(SoundMixer *mixer, MidiDriver *driver, int enabled) : _mixer(mixer)
_musicFname = RSC_FileName(_musicContext);
file.open(_musicFname);
assert(file.size() > sizeof(footerBuf));
file.seek(-ARRAYSIZE(_digiTableITECD) * 8, SEEK_END);
file.read(footerBuf, sizeof(footerBuf));
MemoryReadStreamEndian readS(footerBuf, sizeof(footerBuf), IS_BIG_ENDIAN);
for (int i = 0; i < ARRAYSIZE(_digiTableITECD); i++) {
_digiTableITECD[i].start = file.readUint32LE();
_digiTableITECD[i].length = file.readUint32LE();
_digiTableITECD[i].start = readS.readUint32();
_digiTableITECD[i].length = readS.readUint32();
}
file.close();
@ -478,7 +493,7 @@ int Music::play(uint32 music_rn, uint16 flags) {
}
if (RSC_LoadResource(rsc_ctxt, music_rn, &resource_data,
&resource_size) != SUCCESS ) {
&resource_size) != SUCCESS) {
warning("Music::play(): Resource load failed: %u", music_rn);
return FAILURE;
}

View file

@ -32,6 +32,8 @@
#include "saga/console.h"
#include "saga/font.h"
#include "saga/objectmap.h"
#include "saga/game_mod.h"
#include "saga/stream.h"
namespace Saga {
@ -56,14 +58,14 @@ int ObjectMap::load(const byte *om_res, size_t om_res_len) {
int i, k, m;
MemoryReadStream readS(om_res, om_res_len);
MemoryReadStreamEndian readS(om_res, om_res_len, IS_BIG_ENDIAN);
if (_objectsLoaded) {
freeMem();
}
// Obtain object count N and allocate space for N objects
_nObjects = readS.readUint16LE();
_nObjects = readS.readUint16();
_objectMaps = (OBJECTMAP_ENTRY *)malloc(_nObjects * sizeof *_objectMaps);
@ -79,8 +81,8 @@ int ObjectMap::load(const byte *om_res, size_t om_res_len) {
object_map->nClickareas = readS.readByte();
object_map->defaultVerb = readS.readByte();
readS.readByte();
object_map->objectNum = readS.readUint16LE();
object_map->scriptNum = readS.readUint16LE();
object_map->objectNum = readS.readUint16();
object_map->scriptNum = readS.readUint16();
object_map->clickareas = (CLICKAREA *)malloc(object_map->nClickareas * sizeof *(object_map->clickareas));
if (object_map->clickareas == NULL) {
@ -103,8 +105,8 @@ int ObjectMap::load(const byte *om_res, size_t om_res_len) {
// Load all points for this clickarea
for (m = 0; m < clickarea->n_points; m++) {
point = &clickarea->points[m];
point->x = readS.readSint16LE();
point->y = readS.readSint16LE();
point->x = readS.readSint16();
point->y = readS.readSint16();
}
debug(2, "ObjectMap::load(): Read %d points for clickarea %d in object %d.",
clickarea->n_points, k, object_map->objectNum);
@ -153,13 +155,13 @@ int ObjectMap::loadNames(const unsigned char *onl_res, size_t onl_res_len) {
int i;
MemoryReadStream readS(onl_res, onl_res_len);
MemoryReadStreamEndian readS(onl_res, onl_res_len, IS_BIG_ENDIAN);
if (_namesLoaded) {
freeNames();
}
table_len = readS.readUint16LE();
table_len = readS.readUint16();
n_names = table_len / 2 - 2;
_nNames = n_names;
@ -173,7 +175,7 @@ int ObjectMap::loadNames(const unsigned char *onl_res, size_t onl_res_len) {
}
for (i = 0; i < n_names; i++) {
name_offset = readS.readUint16LE();
name_offset = readS.readUint16();
_names[i] = (const char *)(onl_res + name_offset);
debug(3, "Loaded object name string: %s", _names[i]);

View file

@ -29,6 +29,7 @@
#include "saga/game_mod.h"
#include "saga/palanim.h"
#include "saga/stream.h"
namespace Saga {
@ -54,13 +55,13 @@ int PalAnim::loadPalAnim(const byte *resdata, size_t resdata_len) {
return FAILURE;
}
MemoryReadStream readS(resdata, resdata_len);
MemoryReadStreamEndian readS(resdata, resdata_len, IS_BIG_ENDIAN);
if (GAME_GetGameType() == GID_IHNM) {
return SUCCESS;
}
_entryCount = readS.readUint16LE();
_entryCount = readS.readUint16();
debug(0, "PalAnim::loadPalAnim(): Loading %d PALANIM entries.", _entryCount);
@ -77,8 +78,8 @@ int PalAnim::loadPalAnim(const byte *resdata, size_t resdata_len) {
int pal_count;
int p, c;
color_count = readS.readUint16LE();
pal_count = readS.readUint16LE();
color_count = readS.readUint16();
pal_count = readS.readUint16();
_entries[i].pal_count = pal_count;
_entries[i].color_count = color_count;

View file

@ -29,6 +29,7 @@
namespace Saga {
// Lookup tables
#define ITEMACDEMO_SCENE_LUT 1804
#define ITE_SCENE_LUT 1806
#define ITE_SCRIPT_LUT 216
@ -57,6 +58,7 @@ namespace Saga {
#define ITE_DEFAULT_PORTRAITS 125
// ITE Scene resource numbers
#define ITEMACDEMO_INTRO_ANIM_SCENE 1536
#define ITE_INTRO_ANIM_SCENE 1538
#define ITE_CAVE_SCENE_1 1542
#define ITE_CAVE_SCENE_2 1545

View file

@ -26,6 +26,8 @@
#include "saga/rscfile_mod.h"
#include "saga/rscfile.h"
#include "saga/game_mod.h"
#include "saga/stream.h"
namespace Saga {
@ -113,11 +115,11 @@ int RSC_LoadRSC(RSCFILE_CONTEXT *rsc) {
if (rsc->rc_file->read(tblinfo_buf, RSC_TABLEINFO_SIZE) != RSC_TABLEINFO_SIZE) {
return FAILURE;
}
MemoryReadStreamEndian readS(tblinfo_buf, RSC_TABLEINFO_SIZE, IS_BIG_ENDIAN);
MemoryReadStream readS(tblinfo_buf, RSC_TABLEINFO_SIZE);
res_tbl_offset = readS.readUint32LE();
res_tbl_ct = readS.readUint32LE();
res_tbl_offset = readS.readUint32();
res_tbl_ct = readS.readUint32();
// Check for sane table offset
if (res_tbl_offset != rsc->rc_file->size() - RSC_TABLEINFO_SIZE - RSC_TABLEENTRY_SIZE * res_tbl_ct) {
@ -146,11 +148,13 @@ int RSC_LoadRSC(RSCFILE_CONTEXT *rsc) {
return FAILURE;
}
MemoryReadStream readS1(tbl_buf, tbl_len);
MemoryReadStreamEndian readS1(tbl_buf, tbl_len, IS_BIG_ENDIAN);
debug(9, "RSC %s", rsc->rc_file_fspec);
for (i = 0; i < res_tbl_ct; i++) {
rsc_restbl[i].res_offset = readS1.readUint32LE();
rsc_restbl[i].res_size = readS1.readUint32LE();
rsc_restbl[i].res_offset = readS1.readUint32();
rsc_restbl[i].res_size = readS1.readUint32();
//debug(9, "#%x Offset:%x Size:%x", i, rsc_restbl[i].res_offset, rsc_restbl[i].res_size);
if ((rsc_restbl[i].res_offset > rsc->rc_file->size()) || (rsc_restbl[i].res_size > rsc->rc_file->size())) {
free(tbl_buf);
free(rsc_restbl);
@ -258,4 +262,18 @@ int RSC_FreeResource(byte *resource_ptr) {
return SUCCESS;
}
int RSC_ConvertID(int id) {
int res = id;
if (IS_MAC_VERSION) {
if (res > 1537)
res -= 2;
else if (res == 1535 || res == 1536) {
error ("Wrong resource number %d for Mac ITE");
}
}
return res;
}
} // End of namespace Saga

View file

@ -40,6 +40,7 @@ int RSC_GetResourceOffset(RSCFILE_CONTEXT *, uint32, uint32 *);
int RSC_LoadResource(RSCFILE_CONTEXT *, uint32, byte **, size_t *);
int RSC_FreeResource(byte *);
const char *RSC_FileName(RSCFILE_CONTEXT *rsc);
int RSC_ConvertID(int id);
} // End of namespace Saga

View file

@ -58,7 +58,6 @@ class Console;
class Events;
class PalAnim;
using Common::MemoryReadStream;
#define PBOUNDS(n,max) (((n)>=(0))&&((n)<(max)))
#define MAXPATH 512

View file

@ -23,7 +23,6 @@
// Scene management module
#include "saga/saga.h"
#include "saga/yslib.h"
#include "saga/gfx.h"
#include "saga/game_mod.h"
@ -43,6 +42,7 @@
#include "saga/music.h"
#include "saga/scene.h"
#include "saga/stream.h"
namespace Saga {
@ -63,11 +63,6 @@ Scene::Scene(SagaEngine *vm) : _vm(vm), _initialized(false) {
return;
}
// Initialize scene queue
_sceneQueue = ys_dll_create();
if (_sceneQueue == NULL) {
return;
}
// Load scene lookup table
debug(0, "Loading scene LUT from resource %u.", gs_desc.scene_lut_rn);
@ -76,7 +71,10 @@ Scene::Scene(SagaEngine *vm) : _vm(vm), _initialized(false) {
warning("Scene::Scene(): Error: couldn't load scene LUT");
return;
}
if (scene_lut_len==0) {
warning("Scene::Scene(): scene_lut_len==0");
return;
}
_sceneCount = scene_lut_len / 2;
_sceneMax = _sceneCount - 1;
_sceneLUT = (int *)malloc(_sceneMax * sizeof *_sceneLUT);
@ -85,10 +83,10 @@ Scene::Scene(SagaEngine *vm) : _vm(vm), _initialized(false) {
return;
}
MemoryReadStream readS(scene_lut_p, scene_lut_len);
MemoryReadStreamEndian readS(scene_lut_p, scene_lut_len, IS_BIG_ENDIAN);
for (i = 0; i < _sceneMax; i++) {
_sceneLUT[i] = readS.readUint16LE();
_sceneLUT[i] = readS.readUint16();
}
free(scene_lut_p);
@ -119,7 +117,6 @@ Scene::Scene(SagaEngine *vm) : _vm(vm), _initialized(false) {
_resListEntries = 0;
_resList = NULL;
_animEntries = 0;
_animList = NULL;
_sceneProc = NULL;
_objectMap = NULL;
_actionMap = NULL;
@ -140,21 +137,20 @@ int Scene::queueScene(SCENE_QUEUE *scene_queue) {
assert(_initialized);
assert(scene_queue != NULL);
ys_dll_add_tail(_sceneQueue, scene_queue, sizeof *scene_queue);
_sceneQueue.push_back(*scene_queue);
return SUCCESS;
}
int Scene::clearSceneQueue() {
assert(_initialized);
ys_dll_delete_all(_sceneQueue);
_sceneQueue.clear();
return SUCCESS;
}
int Scene::startScene() {
YS_DL_NODE *node;
SceneQueueList::iterator queueIterator;
SCENE_QUEUE *scene_qdat;
EVENT event;
@ -188,13 +184,13 @@ int Scene::startScene() {
break;
}
// Load the head node in scene queue
node = ys_dll_head(_sceneQueue);
if (node == NULL) {
// Load the head in scene queue
queueIterator = _sceneQueue.begin();
if (queueIterator == _sceneQueue.end()) {
return SUCCESS;
}
scene_qdat = (SCENE_QUEUE *)ys_dll_get_data(node);
scene_qdat = queueIterator.operator->();
assert(scene_qdat != NULL);
loadScene(scene_qdat->scene_n, scene_qdat->load_flag, scene_qdat->scene_proc, scene_qdat->scene_desc, scene_qdat->fadeType);
@ -203,7 +199,7 @@ int Scene::startScene() {
}
int Scene::nextScene() {
YS_DL_NODE *node;
SceneQueueList::iterator queueIterator;
SCENE_QUEUE *scene_qdat;
assert(_initialized);
@ -220,32 +216,29 @@ int Scene::nextScene() {
endScene();
// Delete the current head node in scene queue
node = ys_dll_head(_sceneQueue);
if (node == NULL) {
// Delete the current head in scene queue
queueIterator = _sceneQueue.begin();
if (queueIterator == _sceneQueue.end()) {
return SUCCESS;
}
queueIterator = _sceneQueue.erase(queueIterator);
if (queueIterator == _sceneQueue.end()) {
return SUCCESS;
}
ys_dll_delete(node);
// Load the head node in scene queue
node = ys_dll_head(_sceneQueue);
if (node == NULL) {
return SUCCESS;
}
scene_qdat = (SCENE_QUEUE *)ys_dll_get_data(node);
// Load the head in scene queue
scene_qdat = queueIterator.operator->();
assert(scene_qdat != NULL);
loadScene(scene_qdat->scene_n, scene_qdat->load_flag, scene_qdat->scene_proc, scene_qdat->scene_desc, scene_qdat->fadeType);
loadScene(RSC_ConvertID(scene_qdat->scene_n), scene_qdat->load_flag, scene_qdat->scene_proc, scene_qdat->scene_desc, scene_qdat->fadeType);
return SUCCESS;
}
int Scene::skipScene() {
YS_DL_NODE *node;
YS_DL_NODE *prev_node;
YS_DL_NODE *skip_node = NULL;
SceneQueueList::iterator queueIterator;
SCENE_QUEUE *scene_qdat = NULL;
SCENE_QUEUE *skip_qdat = NULL;
@ -263,29 +256,28 @@ int Scene::skipScene() {
}
// Walk down scene queue and try to find a skip target
node = ys_dll_head(_sceneQueue);
if (node == NULL) {
queueIterator = _sceneQueue.begin();
if (queueIterator == _sceneQueue.end()) {
warning("Scene::skip(): Error: Can't skip scene...no scenes in queue");
return FAILURE;
}
for (node = ys_dll_next(node); node != NULL; node = ys_dll_next(node)) {
scene_qdat = (SCENE_QUEUE *)ys_dll_get_data(node);
++queueIterator;
while (queueIterator != _sceneQueue.end()) {
scene_qdat = queueIterator.operator->();
assert(scene_qdat != NULL);
if (scene_qdat->scene_skiptarget) {
skip_node = node;
skip_qdat = scene_qdat;
break;
}
++queueIterator;
}
// If skip target found, remove preceding scenes and load
if (skip_node != NULL) {
for (node = ys_dll_prev(skip_node); node != NULL; node = prev_node) {
prev_node = ys_dll_prev(node);
ys_dll_delete(node);
}
if (skip_qdat != NULL) {
_sceneQueue.erase(_sceneQueue.begin(), queueIterator);
endScene();
loadScene(skip_qdat->scene_n, skip_qdat->load_flag, skip_qdat->scene_proc, skip_qdat->scene_desc, skip_qdat->fadeType);
}
@ -419,7 +411,6 @@ int Scene::loadScene(int scene_num, int load_flag, SCENE_PROC scene_proc, SCENE_
return FAILURE;
}
_animList = ys_dll_create();
_sceneMode = 0;
_loadDesc = true;
@ -576,21 +567,16 @@ int Scene::loadSceneDescriptor(uint32 res_number) {
return FAILURE;
}
if (scene_desc_len != SAGA_SCENE_DESC_LEN) {
warning("Scene::loadSceneDescriptor(): Error: scene descriptor length invalid");
return FAILURE;
}
MemoryReadStreamEndian readS(scene_desc_data, scene_desc_len, IS_BIG_ENDIAN);
MemoryReadStream readS(scene_desc_data, scene_desc_len);
_desc.flags = readS.readSint16LE();
_desc.resListRN = readS.readSint16LE();
_desc.endSlope = readS.readSint16LE();
_desc.beginSlope = readS.readSint16LE();
_desc.scriptNum = readS.readUint16LE();
_desc.sceneScriptNum = readS.readUint16LE();
_desc.startScriptNum = readS.readUint16LE();
_desc.musicRN = readS.readSint16LE();
_desc.flags = readS.readSint16();
_desc.resListRN = readS.readSint16();
_desc.endSlope = readS.readSint16();
_desc.beginSlope = readS.readSint16();
_desc.scriptNum = readS.readUint16();
_desc.sceneScriptNum = readS.readUint16();
_desc.startScriptNum = readS.readUint16();
_desc.musicRN = readS.readSint16();
RSC_FreeResource(scene_desc_data);
@ -610,7 +596,7 @@ int Scene::loadSceneResourceList(uint32 reslist_rn) {
return FAILURE;
}
MemoryReadStream readS(resource_list, resource_list_len);
MemoryReadStreamEndian readS(resource_list, resource_list_len, IS_BIG_ENDIAN);
// Allocate memory for scene resource list
_resListEntries = resource_list_len / SAGA_RESLIST_ENTRY_LEN;
@ -627,8 +613,8 @@ int Scene::loadSceneResourceList(uint32 reslist_rn) {
debug(0, "Loading scene resource list...");
for (i = 0; i < _resListEntries; i++) {
_resList[i].res_number = readS.readUint16LE();
_resList[i].res_type = readS.readUint16LE();
_resList[i].res_number = readS.readUint16();
_resList[i].res_type = readS.readUint16();
}
RSC_FreeResource(resource_list);
@ -754,26 +740,22 @@ int Scene::processSceneResources() {
case SAGA_ANIM_6:
case SAGA_ANIM_7:
{
SCENE_ANIMINFO *new_animinfo;
uint16 new_anim_id;
debug(0, "Loading animation resource...");
new_animinfo = (SCENE_ANIMINFO *)malloc(sizeof *new_animinfo);
if (new_animinfo == NULL) {
warning("Scene::ProcessSceneResources(): Memory allocation error");
return MEM;
}
if (_vm->_anim->load(_resList[i].res_data,
_resList[i].res_data_len, &new_anim_id) != SUCCESS) {
warning("Scene::ProcessSceneResources(): Error loading animation resource");
return FAILURE;
}
SCENE_ANIMINFO *new_animinfo;
new_animinfo = _animList.pushBack().operator->();
new_animinfo->anim_handle = new_anim_id;
new_animinfo->anim_res_number = _resList[i].res_number;
ys_dll_add_tail(_animList, new_animinfo, sizeof *new_animinfo);
_animEntries++;
}
break;
@ -874,7 +856,7 @@ int Scene::endScene() {
_objectMap = NULL;
_actionMap = NULL;
ys_dll_destroy(_animList);
_animList.clear();
_animEntries = 0;

View file

@ -27,6 +27,7 @@
#define SAGA_SCENE_H
#include "saga/text.h"
#include "saga/list.h"
namespace Saga {
@ -136,9 +137,11 @@ struct SCENE_IMAGE {
struct SCENE_ANIMINFO {
int anim_res_number;
int anim_handle;
SCENE_ANIMINFO *next;
//SCENE_ANIMINFO *next;
};
typedef SortedList<SCENE_ANIMINFO> SceneAnimInfoList;
enum SCENE_FADE_TYPES {
SCENE_NOFADE = 0,
SCENE_FADE = 1,
@ -154,6 +157,8 @@ struct SCENE_QUEUE {
int fadeType;
};
typedef Common::List<SCENE_QUEUE> SceneQueueList;
///// IHNM-specific stuff
#define IHNM_PALFADE_TIME 1000
#define IHNM_INTRO_FRAMETIME 80
@ -258,7 +263,7 @@ class Scene {
int *_sceneLUT;
int _sceneCount;
int _sceneMax;
YS_DL_LIST *_sceneQueue;
SceneQueueList _sceneQueue;
int _firstScene;
bool _sceneLoaded;
int _sceneMode;
@ -270,7 +275,7 @@ class Scene {
int _resListEntries;
SCENE_RESLIST *_resList;
int _animEntries;
YS_DL_LIST *_animList;
SceneAnimInfoList _animList;
SCENE_PROC *_sceneProc;
TEXTLIST *_textList;
SCENE_IMAGE _bg;

View file

@ -23,7 +23,6 @@
// Scripting module: Script resource handling functions
#include "saga/saga.h"
#include "saga/yslib.h"
#include "saga/gfx.h"
#include "saga/rscfile_mod.h"
@ -31,6 +30,7 @@
#include "saga/console.h"
#include "saga/script.h"
#include "saga/stream.h"
namespace Saga {
@ -51,7 +51,6 @@ Script::Script() {
_voiceLUTPresent = false;
_scriptLUTEntryLen = 0;
_currentScript = 0;
_threadList = 0;
_abortEnabled = true;
_skipSpeeches = false;
memset(_dataBuf, 0, sizeof(_dataBuf));
@ -98,12 +97,12 @@ Script::Script() {
}
// Convert LUT resource to logical LUT
MemoryReadStream scriptS(rsc_ptr, rsc_len);
MemoryReadStreamEndian scriptS(rsc_ptr, rsc_len, IS_BIG_ENDIAN);
for (i = 0; i < _scriptLUTMax; i++) {
prevTell = scriptS.pos();
_scriptLUT[i].script_rn = scriptS.readUint16LE();
_scriptLUT[i].diag_list_rn = scriptS.readUint16LE();
_scriptLUT[i].voice_lut_rn = scriptS.readUint16LE();
_scriptLUT[i].script_rn = scriptS.readUint16();
_scriptLUT[i].diag_list_rn = scriptS.readUint16();
_scriptLUT[i].voice_lut_rn = scriptS.readUint16();
// Skip the unused portion of the structure
for (j = scriptS.pos(); j < prevTell + _scriptLUTEntryLen; j++) {
@ -122,8 +121,6 @@ Script::Script() {
}
}
// Initialize script submodules
_threadList = ys_dll_create();
setupScriptFuncList();
@ -132,8 +129,6 @@ Script::Script() {
// Shut down script module gracefully; free all allocated module resources
Script::~Script() {
YS_DL_NODE *thread_node;
SCRIPT_THREAD *thread;
if (!_initialized) {
error("Script not initialized");
@ -143,15 +138,7 @@ Script::~Script() {
// Free script lookup table
free(_scriptLUT);
// Stop all threads and destroy them
for (thread_node = ys_dll_head(_threadList); thread_node != NULL;
thread_node = ys_dll_next(thread_node)) {
thread = (SCRIPT_THREAD *)ys_dll_get_data(thread_node);
SThreadDestroy(thread);
}
_initialized = false;
}
@ -322,12 +309,14 @@ SCRIPT_BYTECODE *Script::loadBytecode(byte *bytecode_p, size_t bytecode_len) {
debug(0, "Loading script bytecode...");
MemoryReadStream scriptS(bytecode_p, bytecode_len);
MemoryReadStreamEndian scriptS(bytecode_p, bytecode_len, IS_BIG_ENDIAN);
// The first two uint32 values are the number of entrypoints, and the
// offset to the entrypoint table, respectively.
n_entrypoints = scriptS.readUint32LE();
ep_tbl_offset = scriptS.readUint32LE();
n_entrypoints = scriptS.readUint16();
scriptS.readUint16(); //skip
ep_tbl_offset = scriptS.readUint16();
scriptS.readUint16(); //skip
// Check that the entrypoint table offset is valid.
if ((bytecode_len - ep_tbl_offset) < (n_entrypoints * SCRIPT_TBLENTRY_LEN)) {
@ -365,8 +354,8 @@ SCRIPT_BYTECODE *Script::loadBytecode(byte *bytecode_p, size_t bytecode_len) {
// First uint16 is the offset of the entrypoint name from the start
// of the bytecode resource, second uint16 is the offset of the
// bytecode itself for said entrypoint
bc_ep_tbl[i].name_offset = scriptS.readUint16LE();
bc_ep_tbl[i].offset = scriptS.readUint16LE();
bc_ep_tbl[i].name_offset = scriptS.readUint16();
bc_ep_tbl[i].offset = scriptS.readUint16();
// Perform a simple range check on offset values
if ((bc_ep_tbl[i].name_offset > bytecode_len) || (bc_ep_tbl[i].offset > bytecode_len)) {
@ -403,10 +392,10 @@ DIALOGUE_LIST *Script::loadDialogue(const byte *dialogue_p, size_t dialogue_len)
return NULL;
}
MemoryReadStream scriptS(dialogue_p, dialogue_len);
MemoryReadStreamEndian scriptS(dialogue_p, dialogue_len, IS_BIG_ENDIAN);
// First uint16 is the offset of the first string
offset = scriptS.readUint16LE();
offset = scriptS.readUint16();
if (offset > dialogue_len) {
warning("Error, invalid string offset");
return NULL;
@ -434,7 +423,7 @@ DIALOGUE_LIST *Script::loadDialogue(const byte *dialogue_p, size_t dialogue_len)
// Read in tables from dialogue list resource
scriptS.seek(0);
for (i = 0; i < n_dialogue; i++) {
offset = scriptS.readUint16LE();
offset = scriptS.readUint16();
if (offset > dialogue_len) {
warning("Error, invalid string offset");
free(dialogue_list->str);
@ -474,10 +463,10 @@ VOICE_LUT *Script::loadVoiceLUT(const byte *voicelut_p, size_t voicelut_len, SCR
return NULL;
}
MemoryReadStream scriptS(voicelut_p, voicelut_len);
MemoryReadStreamEndian scriptS(voicelut_p, voicelut_len, IS_BIG_ENDIAN);
for (i = 0; i < n_voices; i++) {
voice_lut->voices[i] = scriptS.readUint16LE();
voice_lut->voices[i] = scriptS.readUint16();
}
return voice_lut;

View file

@ -27,7 +27,7 @@
#define SAGA_SCRIPT_H
#include "saga/text.h"
#include "saga/yslib.h"
#include "saga/list.h"
namespace Saga {
@ -135,8 +135,12 @@ struct SCRIPT_THREAD {
assert(stackPtr < ARRAYSIZE(stackBuf));
return stackBuf[stackPtr++];
}
SCRIPT_THREAD() { memset(this, 0, sizeof(*this)); }
};
typedef SortedList<SCRIPT_THREAD> ScriptThreadList;
struct PROC_TBLENTRY {
size_t name_offset;
size_t offset;
@ -200,7 +204,7 @@ public:
SCRIPTDATA *currentScript() { return _currentScript; }
void setBuffer(int idx, SCRIPT_DATABUF *ptr) { _dataBuf[idx] = ptr; }
SCRIPT_DATABUF *dataBuffer(int idx) { return _dataBuf[idx]; }
YS_DL_LIST *threadList() { return _threadList; }
// YS_DL_LIST *threadList() { return _threadList; }
void scriptInfo();
void scriptExec(int argc, const char **argv);
@ -214,7 +218,7 @@ protected:
uint16 _scriptLUTEntryLen;
SCRIPTDATA *_currentScript;
SCRIPT_DATABUF *_dataBuf[SCRIPT_DATABUF_NUM];
YS_DL_LIST *_threadList;
ScriptThreadList _threadList;
bool _skipSpeeches;
bool _abortEnabled;

View file

@ -30,11 +30,13 @@
#include "saga/font.h"
#include "saga/script.h"
#include "saga/game_mod.h"
#include "saga/stream.h"
namespace Saga {
#define SD_DISPLAY_LEN 128
#define SD_ADDTXT( x ) strncat( disp_buf, x, SD_DISPLAY_LEN );
#define SD_ADDTXT(x) strncat(disp_buf, x, SD_DISPLAY_LEN);
int Script::SDebugPrintInstr(SCRIPT_THREAD *thread) {
TEXTLIST_ENTRY tl_e;
@ -64,10 +66,10 @@ int Script::SDebugPrintInstr(SCRIPT_THREAD *thread) {
tl_e.string = disp_buf;
tl_e.display = 1;
MemoryReadStream readS(currentScript()->bytecode->bytecode_p
MemoryReadStream/*Endian*/ readS(currentScript()->bytecode->bytecode_p
+ thread->i_offset,
currentScript()->bytecode->bytecode_len
- thread->i_offset);
- thread->i_offset/*, IS_BIG_ENDIAN*/);
in_char = readS.readByte();
sprintf(tmp_buf, "%04lX | %02X | ", thread->i_offset, in_char);
strncat(disp_buf, tmp_buf, SD_DISPLAY_LEN);
@ -103,11 +105,11 @@ int Script::SDebugPrintInstr(SCRIPT_THREAD *thread) {
sprintf(tmp_buf, "%02X", param);
SD_ADDTXT(tmp_buf);
/*
if(( param >= 0 ) && ( param < diag_list->n_dialogue )) {
debug(2, " ; \"%.*s\"", SCRIPT_STRINGLIMIT, diag_list->str[param] );
if((param >= 0) && (param < diag_list->n_dialogue)) {
debug(2, " ; \"%.*s\"", SCRIPT_STRINGLIMIT, diag_list->str[param]);
}
else {
debug(2, " ; Invalid dialogue string.\n" );
debug(2, " ; Invalid dialogue string.\n");
}
*/
}
@ -243,9 +245,9 @@ int Script::SDebugPrintInstr(SCRIPT_THREAD *thread) {
sprintf(tmp_buf, "%04X ", param);
SD_ADDTXT(tmp_buf);
/*
for( i = 0 ; i < script_list->n_scripts ; i++ ) {
if( op_offset == script_list->scripts[i].offset ) {
debug(2, "; Entrypoint \"%s\".", script_list->scriptl_p + script_list->scripts[i].name_offset );
for(i = 0 ; i < script_list->n_scripts ; i++) {
if(op_offset == script_list->scripts[i].offset) {
debug(2, "; Entrypoint \"%s\".", script_list->scriptl_p + script_list->scripts[i].name_offset);
break;
}
}
@ -328,10 +330,10 @@ int Script::SDebugPrintInstr(SCRIPT_THREAD *thread) {
for (i = 0; i < n_switch; i++) {
switch_num = readS.readUint16LE();
switch_jmp = readS.readUint16LE();
// printf( TAB "CASE %04X, %04X\n", switch_num, switch_jmp);
// printf(TAB "CASE %04X, %04X\n", switch_num, switch_jmp);
}
default_jmp = readS.readUint16LE();
//printf( TAB "DEF %04X", default_jmp);
//printf(TAB "DEF %04X", default_jmp);
}
break;
// Random branch

View file

@ -30,6 +30,7 @@
#include "saga/sndres.h"
#include "saga/sound.h"
#include "saga/stream.h"
#include "common/file.h"
@ -175,7 +176,7 @@ int SndRes::load(RSCFILE_CONTEXT *snd_ctxt, uint32 snd_rn, SOUNDBUFFER *snd_buf_
}
int SndRes::loadVocSound(byte *snd_res, size_t snd_res_len, SOUNDBUFFER *snd_buf_i) {
MemoryReadStream readS(snd_res, snd_res_len);
MemoryReadStreamEndian readS(snd_res, snd_res_len, IS_BIG_ENDIAN);
byte *data;
int rate;
int len;
@ -188,11 +189,11 @@ int SndRes::loadVocSound(byte *snd_res, size_t snd_res_len, SOUNDBUFFER *snd_buf
snd_buf_i->s_freq = rate;
snd_buf_i->s_samplebits = 8;
snd_buf_i->s_stereo = 0;
snd_buf_i->s_stereo = 0;
snd_buf_i->s_signed = 0;
snd_buf_i->s_buf = data;
snd_buf_i->s_buf_len = len;
return SUCCESS;
}
@ -200,7 +201,7 @@ int SndRes::loadVocSound(byte *snd_res, size_t snd_res_len, SOUNDBUFFER *snd_buf
int SndRes::loadWavSound(byte *snd_res, size_t snd_res_len, SOUNDBUFFER *snd_buf_i) {
// TODO: This function should, perhaps, be made more robust.
MemoryReadStream readS(snd_res, snd_res_len);
MemoryReadStreamEndian readS(snd_res, snd_res_len, IS_BIG_ENDIAN);
byte buf[4];
@ -209,7 +210,7 @@ int SndRes::loadWavSound(byte *snd_res, size_t snd_res_len, SOUNDBUFFER *snd_buf
return FAILURE;
}
readS.readUint32LE();
readS.readUint32();
readS.read(buf, sizeof(buf));
if (memcmp(buf, "WAVE", sizeof(buf)) != 0) {
@ -221,13 +222,13 @@ int SndRes::loadWavSound(byte *snd_res, size_t snd_res_len, SOUNDBUFFER *snd_buf
return FAILURE;
}
uint32 len = readS.readUint32LE();
uint32 len = readS.readUint32();
uint32 pos = readS.pos();
readS.readUint16LE();
readS.readUint16();
snd_buf_i->s_stereo = (readS.readUint16LE() == 2) ? 1 : 0;
snd_buf_i->s_freq = readS.readUint16LE();
snd_buf_i->s_stereo = (readS.readUint16() == 2) ? 1 : 0;
snd_buf_i->s_freq = readS.readUint16();
snd_buf_i->s_samplebits = 16;
snd_buf_i->s_signed = 1;
@ -239,11 +240,11 @@ int SndRes::loadWavSound(byte *snd_res, size_t snd_res_len, SOUNDBUFFER *snd_buf
break;
}
len = readS.readUint32LE();
len = readS.readUint32();
readS.seek(len, SEEK_CUR);
}
snd_buf_i->s_buf_len = readS.readUint32LE();
snd_buf_i->s_buf_len = readS.readUint32();
byte *data = (byte *)malloc(snd_buf_i->s_buf_len);
if (!data) {

View file

@ -33,6 +33,7 @@
#include "saga/font.h"
#include "saga/sprite.h"
#include "saga/stream.h"
namespace Saga {
@ -81,9 +82,9 @@ int Sprite::loadList(int resource_num, SPRITELIST **sprite_list_p) {
return FAILURE;
}
MemoryReadStream readS(spritelist_data, spritelist_len);
MemoryReadStreamEndian readS(spritelist_data, spritelist_len, IS_BIG_ENDIAN);
sprite_count = readS.readUint16LE();
sprite_count = readS.readUint16();
new_slist->sprite_count = sprite_count;
@ -95,7 +96,7 @@ int Sprite::loadList(int resource_num, SPRITELIST **sprite_list_p) {
for (i = 0; i < sprite_count; i++) {
new_slist->offset_list[i].data_idx = 0;
new_slist->offset_list[i].offset = readS.readUint16LE();
new_slist->offset_list[i].offset = readS.readUint16();
}
new_slist->slist_rn = resource_num;
@ -124,9 +125,9 @@ int Sprite::appendList(int resource_num, SPRITELIST *spritelist) {
return FAILURE;
}
MemoryReadStream readS(spritelist_data, spritelist_len);
MemoryReadStreamEndian readS(spritelist_data, spritelist_len, IS_BIG_ENDIAN);
sprite_count = readS.readUint16LE();
sprite_count = readS.readUint16();
old_sprite_count = spritelist->sprite_count;
new_sprite_count = spritelist->sprite_count + sprite_count;
@ -143,7 +144,7 @@ int Sprite::appendList(int resource_num, SPRITELIST *spritelist) {
for (i = old_sprite_count; i < spritelist->sprite_count; i++) {
spritelist->offset_list[i].data_idx = spritelist->append_count;
spritelist->offset_list[i].offset = readS.readUint16LE();
spritelist->offset_list[i].offset = readS.readUint16();
}
spritelist->sprite_data[spritelist->append_count] = spritelist_data;
@ -194,7 +195,8 @@ int Sprite::draw(SURFACE *ds, SPRITELIST *sprite_list, int sprite_num, int spr_x
sprite_p = sprite_list->sprite_data[offset_idx];
sprite_p += offset;
MemoryReadStream readS(sprite_p, 5);
assert(sprite_p);
MemoryReadStreamEndian readS(sprite_p, 5, IS_BIG_ENDIAN);
x_align = readS.readSByte();
y_align = readS.readSByte();
@ -302,7 +304,7 @@ int Sprite::drawOccluded(SURFACE *ds, SPRITELIST *sprite_list, int sprite_num, i
sprite_p = sprite_list->sprite_data[offset_idx];
sprite_p += offset;
MemoryReadStream readS(sprite_p, 5);
MemoryReadStreamEndian readS(sprite_p, 5, IS_BIG_ENDIAN);
// Read sprite dimensions -- should probably cache this stuff in
// sprite list
@ -383,7 +385,7 @@ int Sprite::drawOccluded(SURFACE *ds, SPRITELIST *sprite_list, int sprite_num, i
/*
{
char buf[1024] = { 0 };
sprintf( buf, "dw: %d, dh: %d.", ci.draw_w, ci.draw_h );
sprintf(buf, "dw: %d, dh: %d.", ci.draw_w, ci.draw_h);
_vm->textDraw(2, ds, buf, spr_x - x_align, spr_y - y_align, 255, 0, FONT_OUTLINE);
}

View file

@ -23,7 +23,6 @@
// Scripting module thread management component
#include "saga/saga.h"
#include "saga/yslib.h"
#include "saga/gfx.h"
#include "saga/actor.h"
@ -32,6 +31,8 @@
#include "saga/script.h"
#include "saga/sdata.h"
#include "saga/game_mod.h"
#include "saga/stream.h"
namespace Saga {
@ -42,22 +43,13 @@ void Script::setFramePtr(SCRIPT_THREAD *thread, int newPtr) {
}
SCRIPT_THREAD *Script::SThreadCreate() {
YS_DL_NODE *new_node;
SCRIPT_THREAD *new_thread;
if (!isInitialized()) {
return NULL;
}
new_thread = (SCRIPT_THREAD *)calloc(1, sizeof *new_thread);
if (new_thread == NULL) {
return NULL;
}
new_node = ys_dll_add_head(threadList(), new_thread, sizeof *new_thread);
free(new_thread);
new_thread = (SCRIPT_THREAD *)ys_dll_get_data(new_node);
new_thread = _threadList.pushFront().operator->();
new_thread->stackPtr = ARRAYSIZE(new_thread->stackBuf) - 1;
setFramePtr(new_thread, new_thread->stackPtr);
@ -71,45 +63,24 @@ SCRIPT_THREAD *Script::SThreadCreate() {
return new_thread;
}
int Script::SThreadDestroy(SCRIPT_THREAD *thread) {
YS_DL_NODE *walk_p;
SCRIPT_THREAD *th;
if (thread == NULL) {
return FAILURE;
}
for (walk_p = ys_dll_head(threadList()); walk_p != NULL; walk_p = ys_dll_next(walk_p)) {
th = (SCRIPT_THREAD *)ys_dll_get_data(walk_p);
if (thread == th) {
ys_dll_delete(walk_p);
break;
}
}
return SUCCESS;
}
int Script::SThreadExecThreads(uint msec) {
YS_DL_NODE *walk_p, *next_p;
SCRIPT_THREAD *thread;
if (!isInitialized()) {
return FAILURE;
}
walk_p = ys_dll_head(threadList());
ScriptThreadList::iterator threadi = _threadList.begin();
while (walk_p != NULL) {
next_p = ys_dll_next(walk_p);
thread = (SCRIPT_THREAD *)ys_dll_get_data(walk_p);
while (threadi != _threadList.end()) {
thread = (SCRIPT_THREAD *)threadi.operator->();
if (thread->flags & (kTFlagFinished | kTFlagAborted)) {
//if (thread->flags & kTFlagFinished) // FIXME. Missing function
SThreadDestroy(thread);
walk_p = next_p;
threadi = _threadList.erase(threadi);
continue;
}
@ -131,14 +102,14 @@ int Script::SThreadExecThreads(uint msec) {
if (!(thread->flags & kTFlagWaiting))
SThreadRun(thread, STHREAD_TIMESLICE);
walk_p = next_p;
++threadi;
}
return SUCCESS;
}
void Script::SThreadCompleteThread(void) {
for (int i = 0; i < 40 && (ys_dll_head(threadList()) != NULL); i++)
for (int i = 0; i < 40 && !_threadList.isEmpty() ; i++)
SThreadExecThreads(0);
}
@ -260,7 +231,7 @@ int Script::SThreadRun(SCRIPT_THREAD *thread, int instr_limit) {
}
}
MemoryReadStream scriptS(currentScript()->bytecode->bytecode_p, currentScript()->bytecode->bytecode_len);
MemoryReadStream/*Endian*/ scriptS(currentScript()->bytecode->bytecode_p, currentScript()->bytecode->bytecode_len/*, IS_BIG_ENDIAN*/);
dataBuffer(2)->len = currentScript()->bytecode->bytecode_len / sizeof(SDataWord_T);
dataBuffer(2)->data = (SDataWord_T *) currentScript()->bytecode->bytecode_p;
@ -275,7 +246,6 @@ int Script::SThreadRun(SCRIPT_THREAD *thread, int instr_limit) {
in_char = scriptS.readByte();
debug(2, "Executing thread offset: %lu (%x) stack: %d", thread->i_offset, in_char, thread->stackSize());
switch (in_char) {
case 0x01: // nextblock
// Some sort of "jump to the start of the next memory
@ -385,6 +355,7 @@ int Script::SThreadRun(SCRIPT_THREAD *thread, int instr_limit) {
if (func_num >= SFUNC_NUM) {
_vm->_console->DebugPrintf(S_ERROR_PREFIX "Invalid script function number: (%X)\n", func_num);
thread->flags |= kTFlagAborted;
debug(9, "Invalid script function number: (%X)\n", func_num);
break;
}
@ -392,6 +363,7 @@ int Script::SThreadRun(SCRIPT_THREAD *thread, int instr_limit) {
sfuncRetVal = (this->*sfunc)(thread, n_args);
if (sfuncRetVal != SUCCESS) {
_vm->_console->DebugPrintf(S_WARN_PREFIX "%X: Script function %d failed.\n", thread->i_offset, func_num);
debug(9, "%X: Script function %d failed.\n", thread->i_offset, func_num);
}
if (func_num == 16) { // SF_gotoScene
@ -421,6 +393,7 @@ int Script::SThreadRun(SCRIPT_THREAD *thread, int instr_limit) {
if (thread->stackSize() == 0) {
_vm->_console->DebugPrintf("Script execution complete.\n");
thread->flags |= kTFlagFinished;
debug(9, "Script execution complete.\n");
} else {
thread->i_offset = thread->pop();
/* int n_args = */ thread->pop();
@ -520,6 +493,7 @@ int Script::SThreadRun(SCRIPT_THREAD *thread, int instr_limit) {
}
if (!branch_found) {
_vm->_console->DebugPrintf(S_ERROR_PREFIX "%X: Random jump target out of bounds.\n", thread->i_offset);
debug(9, "%X: Random jump target out of bounds.\n", thread->i_offset);
}
}
break;
@ -758,6 +732,7 @@ int Script::SThreadRun(SCRIPT_THREAD *thread, int instr_limit) {
a_index = _vm->_actor->getActorIndex(param1);
if (a_index < 0) {
_vm->_console->DebugPrintf(S_WARN_PREFIX "%X: DLGP Actor id not found.\n", thread->i_offset);
debug(9, "%X: DLGP Actor id not found.\n", thread->i_offset);
}
for (i = 0; i < n_voices; i++) {
@ -806,6 +781,7 @@ int Script::SThreadRun(SCRIPT_THREAD *thread, int instr_limit) {
_vm->_console->DebugPrintf(S_ERROR_PREFIX "%X: Invalid opcode encountered: (%X).\n", thread->i_offset, in_char);
thread->flags |= kTFlagAborted;
debug(9, "%X: Invalid opcode encountered: (%X).\n", thread->i_offset, in_char);
break;
}
@ -813,11 +789,18 @@ int Script::SThreadRun(SCRIPT_THREAD *thread, int instr_limit) {
if (saved_offset == thread->i_offset) {
thread->i_offset = scriptS.pos();
} else {
scriptS.seek(thread->i_offset);
if (thread->i_offset >= scriptS.size()) {
_vm->_console->DebugPrintf("Out of range script execution at %x size %x\n", thread->i_offset, scriptS.size());
thread->flags |= kTFlagFinished;
debug(9, "Out of range script execution at %x size %x\n", thread->i_offset, scriptS.size());
}
else
scriptS.seek(thread->i_offset);
}
if (unhandled) {
_vm->_console->DebugPrintf(S_ERROR_PREFIX "%X: Unhandled opcode.\n", thread->i_offset);
thread->flags |= kTFlagAborted;
debug(9, "%X: Unhandled opcode.\n", thread->i_offset);
}
if ((thread->flags == kTFlagNone) && debug_print) {
SDebugPrintInstr(thread);

56
saga/stream.h Normal file
View file

@ -0,0 +1,56 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2004 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 SAGA_STREAM_H__
#define SAGA_STREAM_H__
#include "common/stream.h"
namespace Saga {
using Common::MemoryReadStream;
class MemoryReadStreamEndian : public Common::MemoryReadStream {
private:
public:
bool _bigEndian;
MemoryReadStreamEndian(const byte *buf, uint32 len, bool bigEndian = false) : MemoryReadStream(buf, len), _bigEndian(bigEndian) {}
uint16 readUint16() {
return (_bigEndian) ? readUint16BE(): readUint16LE();
}
uint32 readUint32() {
return (_bigEndian) ? readUint32BE(): readUint32LE();
}
inline int16 readSint16() {
return (int16)readUint16();
}
inline int32 readSint32() {
return (int32)readUint32();
}
};
} // End of namespace Saga
#endif

View file

@ -24,7 +24,6 @@
// Text / dialogue display management module
#include "saga/saga.h"
#include "saga/yslib.h"
#include "saga/gfx.h"
#include "saga/font.h"
@ -149,25 +148,18 @@ int SagaEngine::textDraw(int font_id, SURFACE *ds, const char *string, int text_
TEXTLIST *SagaEngine::textCreateList() {
TEXTLIST *new_textlist;
new_textlist = (TEXTLIST *)malloc(sizeof *new_textlist);
new_textlist = new TEXTLIST;
if (new_textlist == NULL) {
return NULL;
}
new_textlist->list = ys_dll_create();
if (new_textlist->list == NULL) {
free(new_textlist);
return NULL;
}
return new_textlist;
}
void SagaEngine::textClearList(TEXTLIST *tlist) {
if (tlist != NULL) {
ys_dll_delete_all(tlist->list);
tlist->clear();
}
return;
@ -175,21 +167,18 @@ void SagaEngine::textClearList(TEXTLIST *tlist) {
void SagaEngine::textDestroyList(TEXTLIST *tlist) {
if (tlist != NULL) {
ys_dll_destroy(tlist->list);
}
free(tlist);
delete tlist;
}
return;
}
int SagaEngine::textDrawList(TEXTLIST *textlist, SURFACE *ds) {
TEXTLIST_ENTRY *entry_p;
YS_DL_NODE *walk_p;
assert((textlist != NULL) && (ds != NULL));
for (walk_p = ys_dll_head(textlist->list); walk_p != NULL; walk_p = ys_dll_next(walk_p)) {
entry_p = (TEXTLIST_ENTRY *)ys_dll_get_data(walk_p);
for (TEXTLIST::iterator texti = textlist->begin(); texti != textlist->end(); ++texti) {
entry_p = (TEXTLIST_ENTRY *)texti.operator->();
if (entry_p->display != 0) {
textDraw(entry_p->font_id, ds, entry_p->string, entry_p->text_x, entry_p->text_y, entry_p->color,
entry_p->effect_color, entry_p->flags);
@ -201,16 +190,13 @@ int SagaEngine::textDrawList(TEXTLIST *textlist, SURFACE *ds) {
int SagaEngine::textProcessList(TEXTLIST *textlist, long ms) {
TEXTLIST_ENTRY *entry_p;
YS_DL_NODE *walk_p;
YS_DL_NODE *temp_p;
for (walk_p = ys_dll_head(textlist->list); walk_p != NULL; walk_p = temp_p) {
temp_p = ys_dll_next(walk_p);
entry_p = (TEXTLIST_ENTRY *)ys_dll_get_data(walk_p);
for (TEXTLIST::iterator texti = textlist->begin(); texti != textlist->end(); ++texti) {
entry_p = (TEXTLIST_ENTRY *)texti.operator->();
if (entry_p->flags & TEXT_TIMEOUT) {
entry_p->time -= ms;
if (entry_p->time <= 0) {
ys_dll_delete(walk_p);
texti=textlist->eraseAndPrev(texti);
}
}
}
@ -220,13 +206,10 @@ int SagaEngine::textProcessList(TEXTLIST *textlist, long ms) {
}
TEXTLIST_ENTRY *SagaEngine::textAddEntry(TEXTLIST *textlist, TEXTLIST_ENTRY *entry) {
YS_DL_NODE *new_node = NULL;
if (entry != NULL) {
new_node = ys_dll_add_tail(textlist->list, entry, sizeof *entry);
return textlist->pushBack(*entry).operator->();
}
return (new_node != NULL) ? (TEXTLIST_ENTRY *)new_node->data : NULL;
return NULL;
}
int SagaEngine::textSetDisplay(TEXTLIST_ENTRY *entry, int val) {
@ -239,18 +222,12 @@ int SagaEngine::textSetDisplay(TEXTLIST_ENTRY *entry, int val) {
}
int SagaEngine::textDeleteEntry(TEXTLIST *textlist, TEXTLIST_ENTRY *entry) {
YS_DL_NODE *walk_p;
if (entry == NULL) {
return FAILURE;
}
for (walk_p = ys_dll_head(textlist->list); walk_p != NULL; walk_p = ys_dll_next(walk_p)) {
if (entry == ys_dll_get_data(walk_p)) {
ys_dll_delete(walk_p);
break;
}
}
textlist->remove(entry);
return SUCCESS;
}

View file

@ -26,7 +26,7 @@
#ifndef SAGA_TEXT_H__
#define SAGA_TEXT_H__
#include "saga/yslib.h"
#include "saga/list.h"
namespace Saga {
@ -34,17 +34,12 @@ namespace Saga {
#define TEXT_MARGIN 10
#define TEXT_LINESPACING 2
struct TEXTLIST {
YS_DL_LIST *list;
};
enum TEXT_FLAGS {
TEXT_TIMEOUT = 0x01
};
struct TEXTLIST_ENTRY {
TEXTLIST_ENTRY *next;
TEXTLIST_ENTRY *prev;
int display;
int id;
int text_x;
@ -58,6 +53,9 @@ struct TEXTLIST_ENTRY {
TEXTLIST_ENTRY() { memset(this, 0, sizeof(*this)); }
};
typedef SortedList<TEXTLIST_ENTRY> TEXTLIST;
#define TEXTLISTITERATOR TEXTLIST::iterator
} // End of namespace Saga
#endif

View file

@ -1,239 +0,0 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2004 The ScummVM project
*
* The ReInherit Engine is (C)2000-2003 by Daniel Balsom.
*
* 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 "saga/saga.h"
#include "saga/yslib.h"
namespace Saga {
YS_DL_LIST *ys_dll_create() {
YS_DL_LIST *new_list;
new_list = (YS_DL_LIST *)malloc(sizeof *new_list);
if (new_list != NULL) {
new_list->next = new_list;
new_list->prev = new_list;
// Sentinel is marked by self-referential node data.
// No other link is permitted to do this
new_list->data = new_list;
}
return new_list;
}
void ys_dll_destroy(YS_DL_LIST *list) {
YS_DL_NODE *walk_p;
YS_DL_NODE *temp_p;
for (walk_p = list->next; walk_p != list; walk_p = temp_p) {
temp_p = walk_p->next;
free(walk_p->data);
free(walk_p);
}
free(list);
return;
}
void *ys_dll_get_data(YS_DL_NODE *node) {
return node->data;
}
YS_DL_NODE *ys_dll_head(YS_DL_LIST *list) {
return (list->next != list) ? list->next : NULL;
}
YS_DL_NODE *ys_dll_tail(YS_DL_LIST *list) {
return (list->prev != list) ? list->prev : NULL;
}
YS_DL_NODE *ys_dll_next(YS_DL_NODE *node) {
return (node->next != (YS_DL_LIST *) node->next->data) ? node->next : NULL;
}
YS_DL_NODE *ys_dll_prev(YS_DL_NODE *node) {
return (node->prev != (YS_DL_LIST *) node->prev->data) ? node->prev : NULL;
}
YS_DL_NODE *ys_dll_add_head(YS_DL_LIST *list, void *data, size_t size) {
YS_DL_NODE *new_node;
void *new_data;
new_node = (YS_DL_NODE *)malloc(sizeof *new_node);
if (new_node) {
new_data = malloc(size);
if (new_data) {
memcpy(new_data, data, size);
new_node->data = new_data;
new_node->prev = list;
new_node->next = list->next;
new_node->next->prev = new_node;
list->next = new_node;
}
}
return new_node;
}
YS_DL_NODE *ys_dll_add_tail(YS_DL_LIST *list, void *data, size_t size) {
YS_DL_NODE *new_node;
void *new_data;
new_node = (YS_DL_NODE *)malloc(sizeof *new_node);
if (new_node != NULL) {
new_data = malloc(size);
if (new_data != NULL) {
memcpy(new_data, data, size);
new_node->data = new_data;
new_node->next = list;
new_node->prev = list->prev;
new_node->prev->next = new_node;
list->prev = new_node;
}
}
return new_node;
}
YS_DL_NODE *ys_dll_insert(YS_DL_NODE *list, void *data, size_t size, YS_COMPARE_FUNC *compare) {
YS_DL_NODE *walk_p;
YS_DL_NODE *new_node;
int result;
for (walk_p = list->next; walk_p != list; walk_p = walk_p->next) {
result = compare(data, walk_p->data);
if (result < 0) {
new_node = ys_dll_preinsert(walk_p, data, size);
return new_node;
}
}
new_node = ys_dll_add_tail(list, data, size);
return new_node;
}
int ys_dll_delete(YS_DL_NODE *node) {
if (node == NULL) {
return YS_E_FAILURE;
}
node->next->prev = node->prev;
node->prev->next = node->next;
free(node->data);
free(node);
return YS_E_SUCCESS;
}
void ys_dll_delete_all(YS_DL_LIST *list) {
YS_DL_NODE *walk_p;
YS_DL_NODE *temp_p;
for (walk_p = list->next; walk_p != list; walk_p = temp_p) {
temp_p = walk_p->next;
free(walk_p->data);
free(walk_p);
}
list->next = list;
list->prev = list;
}
YS_DL_NODE *ys_dll_replace(YS_DL_NODE *node, void *data, size_t size) {
void *new_data;
if ((node == NULL) || (data == NULL) || (!size)) {
return NULL;
}
new_data = malloc(size);
if (new_data == NULL) {
return NULL;
}
free(node->data);
node->data = new_data;
memcpy(new_data, data, size);
return node;
}
int ys_dll_reorder_up(YS_DL_NODE *list, YS_DL_NODE *olink, YS_COMPARE_FUNC *compare) {
YS_DL_NODE *walk_p;
int result;
int reorder = 0;
for (walk_p = olink->prev; walk_p != list; walk_p = walk_p->prev) {
result = compare(walk_p->data, olink->data);
if (result <= 0) {
reorder = 1;
break;
}
}
if (reorder) {
// Unlink original link
olink->next->prev = olink->prev;
olink->prev->next = olink->next;
// Reinsert after walk link
olink->prev = walk_p;
olink->next = walk_p->next;
olink->next->prev = olink;
walk_p->next = olink;
}
return YS_E_SUCCESS;
}
int ys_dll_reorder_down(YS_DL_NODE *list, YS_DL_NODE *olink, YS_COMPARE_FUNC *compare) {
YS_DL_NODE *walk_p;
int result;
int reorder = 0;
for (walk_p = olink->next; walk_p != list; walk_p = walk_p->next) {
result = compare(walk_p->data, olink->data);
if (result >= 0) {
reorder = 1;
break;
}
}
if (reorder) {
// Unlink original link
olink->next->prev = olink->prev;
olink->prev->next = olink->next;
//Reinsert before walk link
olink->next = walk_p;
olink->prev = walk_p->prev;
olink->prev->next = olink;
walk_p->prev = olink;
}
return YS_E_SUCCESS;
}
} // End of namespace Saga

View file

@ -1,90 +0,0 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2004 The ScummVM project
*
* The ReInherit Engine is (C)2000-2003 by Daniel Balsom.
*
* 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 YSLIB_MAIN_H__
#define YSLIB_MAIN_H__
namespace Saga {
enum YS_ERROR_STATES {
YS_E_SUCCESS = 0,
YS_E_FAILURE,
YS_E_MEM
};
enum YS_CONFIRM_STATES {
YS_CONFIRM_NO = 0,
YS_CONFIRM_YES,
YS_CONFIRM_CANCEL
};
// General purpose quantity-comparison function
typedef int (YS_COMPARE_FUNC) (const void *, const void *);
// General-purpose utility macros
//#define YS_ASSUME_2S_COMP
// Shared declarations for list modules
enum YS_WALK_DIRECTIONS {
YS_WALK_BACKWARD = 0,
YS_WALK_FORWARD
};
typedef struct ys_dl_node_tag YS_DL_NODE;
typedef struct ys_dl_node_tag YS_DL_LIST;
struct ys_dl_node_tag {
void *data;
struct ys_dl_node_tag *next;
struct ys_dl_node_tag *prev;
};
YS_DL_LIST *ys_dll_create();
void ys_dll_destroy(YS_DL_LIST *);
void *ys_dll_get_data(YS_DL_NODE *);
YS_DL_NODE *ys_dll_head(YS_DL_LIST *);
YS_DL_NODE *ys_dll_tail(YS_DL_LIST *);
YS_DL_NODE *ys_dll_next(YS_DL_NODE *);
YS_DL_NODE *ys_dll_prev(YS_DL_NODE *);
YS_DL_NODE *ys_dll_add_head(YS_DL_LIST *, void *, size_t);
YS_DL_NODE *ys_dll_add_tail(YS_DL_LIST *, void *, size_t);
#define ys_dll_preinsert ys_dll_add_tail
#define ys_dll_postinsert ys_dll_add_head
YS_DL_NODE *ys_dll_insert(YS_DL_LIST *, void *, size_t, YS_COMPARE_FUNC *);
int ys_dll_delete(YS_DL_NODE *);
void ys_dll_delete_all(YS_DL_LIST *);
YS_DL_NODE *ys_dll_replace(YS_DL_NODE *, void *, size_t);
int ys_dll_reorder_up(YS_DL_LIST *, YS_DL_NODE *, YS_COMPARE_FUNC *);
int ys_dll_reorder_down(YS_DL_LIST *, YS_DL_NODE *, YS_COMPARE_FUNC *);
} // End of namespace Saga
#endif