aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Sandulenko2004-04-12 21:40:49 +0000
committerEugene Sandulenko2004-04-12 21:40:49 +0000
commitf3d340fb0ce72b9db59b8c701153bc82b595f75e (patch)
treebf250cf3a1e6aee35c7f40d766994b0c2c188e5c
parent0a0a0c7b0609d8774cef849e7511e7b21d12c5db (diff)
downloadscummvm-rg350-f3d340fb0ce72b9db59b8c701153bc82b595f75e.tar.gz
scummvm-rg350-f3d340fb0ce72b9db59b8c701153bc82b595f75e.tar.bz2
scummvm-rg350-f3d340fb0ce72b9db59b8c701153bc82b595f75e.zip
WIP for SAGA engine.
o text formatting is not consistent with rules, just indent utility is too dumb for that o it does not use OSystem, i.e. it runs on direct SDL calls o it may not even compile on your box o if you enable it, expect zillions of warnings o no sound Now it runs ITE intro as reinherit did svn-id: r13564
-rw-r--r--saga/actionmap.cpp252
-rw-r--r--saga/actionmap.h67
-rw-r--r--saga/actionmap_mod.h49
-rw-r--r--saga/actor.cpp1456
-rw-r--r--saga/actor.h234
-rw-r--r--saga/actor_mod.h100
-rw-r--r--saga/actordata.cpp227
-rw-r--r--saga/actordata.h62
-rw-r--r--saga/animation.cpp1192
-rw-r--r--saga/animation.h139
-rw-r--r--saga/animation_mod.h67
-rw-r--r--saga/binread.cpp151
-rw-r--r--saga/binread.h73
-rw-r--r--saga/cmdline.cpp95
-rw-r--r--saga/console.cpp567
-rw-r--r--saga/console.h96
-rw-r--r--saga/console_mod.h59
-rw-r--r--saga/cvar.cpp612
-rw-r--r--saga/cvar.h100
-rw-r--r--saga/cvar_mod.h112
-rw-r--r--saga/events.cpp613
-rw-r--r--saga/events.h63
-rw-r--r--saga/events_mod.h143
-rw-r--r--saga/expr.cpp464
-rw-r--r--saga/expr.h43
-rw-r--r--saga/font.cpp721
-rw-r--r--saga/font.h132
-rw-r--r--saga/font_map.cpp295
-rw-r--r--saga/font_mod.h71
-rw-r--r--saga/game.cpp839
-rw-r--r--saga/game.h133
-rw-r--r--saga/game_mod.h (renamed from saga/gamedesc.h)109
-rw-r--r--saga/gamedesc.cpp449
-rw-r--r--saga/gamedesc_priv.h82
-rw-r--r--saga/gfx.cpp1098
-rw-r--r--saga/gfx.h54
-rw-r--r--saga/gfx_mod.h99
-rw-r--r--saga/ihnm_introproc.cpp360
-rw-r--r--saga/ihnm_introproc.h44
-rw-r--r--saga/image.cpp510
-rw-r--r--saga/image.h64
-rw-r--r--saga/image_mod.h46
-rw-r--r--saga/interface.cpp756
-rw-r--r--saga/interface.h198
-rw-r--r--saga/interface_mod.h57
-rw-r--r--saga/isomap.cpp371
-rw-r--r--saga/isomap.h104
-rw-r--r--saga/isomap_mod.h48
-rw-r--r--saga/ite_introproc.cpp1177
-rw-r--r--saga/ite_introproc.h92
-rw-r--r--saga/ite_introproc_mod.h40
-rw-r--r--saga/math.cpp72
-rw-r--r--saga/math.h35
-rw-r--r--saga/math_mod.h42
-rw-r--r--saga/misc.cpp54
-rw-r--r--saga/module.mk52
-rw-r--r--saga/objectmap.cpp556
-rw-r--r--saga/objectmap.h75
-rw-r--r--saga/objectmap_mod.h70
-rw-r--r--saga/palanim.cpp266
-rw-r--r--saga/palanim.h63
-rw-r--r--saga/palanim_mod.h46
-rw-r--r--saga/reinherit.h333
-rw-r--r--saga/render.cpp588
-rw-r--r--saga/render.h84
-rw-r--r--saga/render_mod.h92
-rw-r--r--saga/resfile.cpp162
-rw-r--r--saga/resfile.h107
-rw-r--r--saga/resnames.h130
-rw-r--r--saga/rscfile.cpp310
-rw-r--r--saga/rscfile.h70
-rw-r--r--saga/rscfile_mod.h59
-rw-r--r--saga/saga.cpp250
-rw-r--r--saga/saga.h20
-rw-r--r--saga/scene.cpp1159
-rw-r--r--saga/scene.h229
-rw-r--r--saga/scene_mod.h103
-rw-r--r--saga/sceneproc.cpp200
-rw-r--r--saga/sceneproc.h40
-rw-r--r--saga/script.cpp684
-rw-r--r--saga/script.h157
-rw-r--r--saga/script_mod.h89
-rw-r--r--saga/sdata.cpp210
-rw-r--r--saga/sdata.h44
-rw-r--r--saga/sdebug.cpp658
-rw-r--r--saga/sfuncs.cpp811
-rw-r--r--saga/sfuncs.h103
-rw-r--r--saga/sndres.cpp353
-rw-r--r--saga/sndres.h92
-rw-r--r--saga/sndres_mod.h52
-rw-r--r--saga/sprite.cpp567
-rw-r--r--saga/sprite.h88
-rw-r--r--saga/sprite_mod.h61
-rw-r--r--saga/sstack.cpp199
-rw-r--r--saga/sstack.h81
-rw-r--r--saga/stack.cpp180
-rw-r--r--saga/stack.h49
-rw-r--r--saga/stack_mod.h69
-rw-r--r--saga/sthread.cpp1120
-rw-r--r--saga/sthread.h69
-rw-r--r--saga/sys_fs.cpp82
-rw-r--r--saga/sys_interface.h49
-rw-r--r--saga/sysgfx.cpp548
-rw-r--r--saga/sysgfx.h51
-rw-r--r--saga/sysinput.cpp238
-rw-r--r--saga/sysio.cpp65
-rw-r--r--saga/sysmusic.cpp98
-rw-r--r--saga/syssound.cpp173
-rw-r--r--saga/systimer.cpp144
-rw-r--r--saga/systimer.h54
-rw-r--r--saga/text.cpp342
-rw-r--r--saga/text.h46
-rw-r--r--saga/text_mod.h70
-rw-r--r--saga/transitions.cpp83
-rw-r--r--saga/x86_32.h46
-rw-r--r--saga/xmidi.cpp832
-rw-r--r--saga/xmidi.h117
-rw-r--r--saga/xmidi_mod.h115
-rw-r--r--saga/ys_binread.cpp350
-rw-r--r--saga/ys_binwrite.cpp296
-rw-r--r--saga/ys_dl_list.cpp310
-rw-r--r--saga/ys_file.cpp63
-rw-r--r--saga/yslib.h219
123 files changed, 29179 insertions, 1200 deletions
diff --git a/saga/actionmap.cpp b/saga/actionmap.cpp
new file mode 100644
index 0000000000..20b3a7f250
--- /dev/null
+++ b/saga/actionmap.cpp
@@ -0,0 +1,252 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ Action map module
+
+ Notes:
+*/
+
+#include "reinherit.h"
+
+#include "yslib.h"
+
+
+/*
+ * Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "cvar_mod.h"
+#include "console_mod.h"
+#include "gfx_mod.h"
+
+/*
+ * Begin module component
+\*--------------------------------------------------------------------------*/
+#include "actionmap_mod.h"
+#include "actionmap.h"
+
+namespace Saga {
+
+static R_ACTIONMAP_INFO ActmapModule;
+
+int ACTIONMAP_Register(void)
+{
+
+ CVAR_RegisterFunc(CF_action_info,
+ "action_info", NULL, R_CVAR_NONE, 0, 0);
+
+ return R_SUCCESS;
+}
+
+int ACTIONMAP_Init(void)
+{
+ R_printf(R_STDOUT, "ACTIONMAP Module: Initializing...\n");
+
+ ActmapModule.init = 1;
+ return R_SUCCESS;
+}
+
+int ACTIONMAP_Load(const uchar * exmap_res, size_t exmap_res_len)
+/*--------------------------------------------------------------------------*\
+ * Loads exit map data from specified exit map resource
+\*--------------------------------------------------------------------------*/
+{
+
+ R_ACTIONMAP_ENTRY *exmap_entry;
+ R_POINT *exmap_pt_tbl;
+
+ int exit_ct;
+ int i, pt;
+
+ const uchar *read_p = exmap_res;
+ size_t read_len = exmap_res_len;
+
+ assert(ActmapModule.init);
+ assert(exmap_res != NULL);
+
+ (void)read_len;
+
+ /* Load exits
+ * \*------------------------------------------------------------- */
+ exit_ct = ys_read_s16_le(read_p, &read_p);
+ if (exit_ct < 0) {
+ return R_FAILURE;
+ }
+
+ exmap_entry = (R_ACTIONMAP_ENTRY *)malloc(exit_ct * sizeof *exmap_entry);
+ if (exmap_entry == NULL) {
+
+ R_printf(R_STDERR, "Memory allocation failure.\n");
+ return R_MEM;
+ }
+
+ for (i = 0; i < exit_ct; i++) {
+
+ exmap_entry[i].unknown00 = ys_read_s16_le(read_p, &read_p);
+ exmap_entry[i].unknown02 = ys_read_s16_le(read_p, &read_p);
+ exmap_entry[i].exit_scene = ys_read_s16_le(read_p, &read_p);
+ exmap_entry[i].unknown06 = ys_read_s16_le(read_p, &read_p);
+
+ exmap_entry[i].pt_count = ys_read_s16_le(read_p, &read_p);
+ if (exmap_entry[i].pt_count < 0) {
+
+ free(exmap_entry);
+ return R_FAILURE;
+ }
+
+ exmap_pt_tbl =
+ (R_POINT *)malloc(exmap_entry[i].pt_count * sizeof *exmap_pt_tbl);
+ if (exmap_pt_tbl == NULL) {
+
+ R_printf(R_STDERR, "Memory allocation failure.\n");
+ return R_MEM;
+ }
+
+ for (pt = 0; pt < exmap_entry[i].pt_count; pt++) {
+
+ exmap_pt_tbl[pt].x = ys_read_s16_le(read_p, &read_p);
+ exmap_pt_tbl[pt].y = ys_read_s16_le(read_p, &read_p);
+ }
+
+ exmap_entry[i].pt_tbl = exmap_pt_tbl;
+ }
+
+ ActmapModule.exits_loaded = 1;
+ ActmapModule.n_exits = exit_ct;
+ ActmapModule.exits_tbl = exmap_entry;
+
+ ActmapModule.exmap_res = exmap_res;
+ ActmapModule.exmap_res_len = exmap_res_len;
+
+ return R_SUCCESS;
+}
+
+int ACTIONMAP_Free(void)
+/*--------------------------------------------------------------------------*\
+ * Frees the currently loaded exit map data
+\*--------------------------------------------------------------------------*/
+{
+
+ R_ACTIONMAP_ENTRY *exmap_entry;
+ int i;
+
+ if (!ActmapModule.exits_loaded) {
+ return R_SUCCESS;
+ }
+
+ for (i = 0; i < ActmapModule.n_exits; i++) {
+
+ exmap_entry = &ActmapModule.exits_tbl[i];
+
+ free(exmap_entry->pt_tbl);
+ }
+
+ free(ActmapModule.exits_tbl);
+
+ ActmapModule.exits_loaded = 0;
+ ActmapModule.exits_tbl = NULL;
+ ActmapModule.n_exits = 0;
+
+ return R_SUCCESS;
+}
+
+int ACTIONMAP_Shutdown(void)
+/*--------------------------------------------------------------------------*\
+\*--------------------------------------------------------------------------*/
+{
+
+ return R_SUCCESS;
+}
+
+int ACTIONMAP_Draw(R_SURFACE * ds, int color)
+{
+
+ int i;
+
+ assert(ActmapModule.init);
+
+ if (!ActmapModule.exits_loaded) {
+ return R_FAILURE;
+ }
+
+ for (i = 0; i < ActmapModule.n_exits; i++) {
+
+ if (ActmapModule.exits_tbl[i].pt_count == 2) {
+
+ GFX_DrawFrame(ds,
+ &ActmapModule.exits_tbl[i].pt_tbl[0],
+ &ActmapModule.exits_tbl[i].pt_tbl[1], color);
+
+ } else if (ActmapModule.exits_tbl[i].pt_count > 2) {
+
+ GFX_DrawPolyLine(ds,
+ ActmapModule.exits_tbl[i].pt_tbl,
+ ActmapModule.exits_tbl[i].pt_count, color);
+
+ }
+ }
+
+ return R_SUCCESS;
+}
+
+void CF_action_info(int argc, char *argv[])
+{
+ R_POINT *pt;
+
+ int i;
+ int pt_i;
+
+ YS_IGNORE_PARAM(argc);
+ YS_IGNORE_PARAM(argv);
+
+ if (!ActmapModule.exits_loaded) {
+ return;
+ }
+
+ CON_Print("%d exits loaded.\n", ActmapModule.n_exits);
+
+ for (i = 0; i < ActmapModule.n_exits; i++) {
+
+ CON_Print
+ ("Action %d: Exit to: %d; Pts: %d; Unk0: %d Unk2: %d Scr_N: %d",
+ i, ActmapModule.exits_tbl[i].exit_scene,
+ ActmapModule.exits_tbl[i].pt_count,
+ ActmapModule.exits_tbl[i].unknown00,
+ ActmapModule.exits_tbl[i].unknown02,
+ ActmapModule.exits_tbl[i].unknown06);
+
+ for (pt_i = 0; pt_i < ActmapModule.exits_tbl[i].pt_count;
+ pt_i++) {
+
+ pt = &ActmapModule.exits_tbl[i].pt_tbl[pt_i];
+
+ CON_Print(" pt: %d (%d, %d)", pt_i, pt->x, pt->y);
+ }
+ }
+
+ return;
+}
+
+} // End of namespace Saga
diff --git a/saga/actionmap.h b/saga/actionmap.h
new file mode 100644
index 0000000000..5760bf2fb8
--- /dev/null
+++ b/saga/actionmap.h
@@ -0,0 +1,67 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ Action map module - private header
+
+ Notes:
+*/
+
+#ifndef SAGA_ACTIONMAP_H_
+#define SAGA_ACTIONMAP_H_
+
+namespace Saga {
+
+typedef struct R_ACTIONMAP_ENTRY_tag {
+
+ int unknown00;
+ int unknown02;
+ int exit_scene;
+ int unknown06;
+
+ int pt_count;
+ R_POINT *pt_tbl;
+
+} R_ACTIONMAP_ENTRY;
+
+typedef struct R_ACTIONMAP_INFO_tag {
+
+ int init;
+
+ int exits_loaded;
+ int n_exits;
+ R_ACTIONMAP_ENTRY *exits_tbl;
+
+ const uchar *exmap_res;
+ size_t exmap_res_len;
+
+} R_ACTIONMAP_INFO;
+
+void CF_action_info(int argc, char *argv[]);
+
+} // End of namespace Saga
+
+#endif /* R_ACTIONMAP_H_ */
+/* end "r_actionmap.h" */
diff --git a/saga/actionmap_mod.h b/saga/actionmap_mod.h
new file mode 100644
index 0000000000..f424ef1304
--- /dev/null
+++ b/saga/actionmap_mod.h
@@ -0,0 +1,49 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ Action map module - public module header
+
+ Notes:
+*/
+
+#ifndef SAGA_ACTIONMAP_MOD_H_
+#define SAGA_ACTIONMAP_MOD_H_
+
+namespace Saga {
+
+int ACTIONMAP_Register(void);
+int ACTIONMAP_Init(void);
+
+int ACTIONMAP_Load(const uchar * exmap_res, size_t exmap_res_len);
+int ACTIONMAP_Draw(R_SURFACE * ds, int color);
+
+int ACTIONMAP_Free(void);
+int ACTIONMAP_Shutdown(void);
+
+} // End of namespace Saga
+
+#endif /* R_ACTIONMAP_MOD_H_ */
+/* end "r_actionmap_mod.h" */
diff --git a/saga/actor.cpp b/saga/actor.cpp
new file mode 100644
index 0000000000..1400dcd1a1
--- /dev/null
+++ b/saga/actor.cpp
@@ -0,0 +1,1456 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Actor management module
+
+ Notes:
+
+ Hardcoded actor table present in r_actordata.c
+*/
+
+#include "reinherit.h"
+
+#include "yslib.h"
+
+/*
+ * Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "game_mod.h"
+#include "cvar_mod.h"
+#include "console_mod.h"
+#include "rscfile_mod.h"
+#include "script_mod.h"
+#include "sndres_mod.h"
+#include "sprite_mod.h"
+#include "font_mod.h"
+#include "text_mod.h"
+
+/*
+ * Begin module component
+\*--------------------------------------------------------------------------*/
+#include "actor_mod.h"
+#include "actor.h"
+#include "actordata.h"
+
+namespace Saga {
+
+static R_ACTOR_MODULE ActorModule;
+
+R_ACTIONTIMES ActionTDeltas[] = {
+
+ {ACTION_IDLE, 80},
+ {ACTION_WALK, 80},
+ {ACTION_SPEAK, 200}
+};
+
+int ACTOR_Register(void)
+{
+
+ CVAR_RegisterFunc(CF_actor_add, "actor_add",
+ "<Actor id> <lx> <ly>", R_CVAR_NONE, 3, 3);
+
+ CVAR_RegisterFunc(CF_actor_del, "actor_del",
+ "<Actor id>", R_CVAR_NONE, 1, 1);
+
+ CVAR_RegisterFunc(CF_actor_move, "actor_move",
+ "<Actor id> <lx> <ly>", R_CVAR_NONE, 3, 3);
+
+ CVAR_RegisterFunc(CF_actor_moverel, "actor_moverel",
+ "<Actor id> <lx> <ly>", R_CVAR_NONE, 3, 3);
+
+ CVAR_RegisterFunc(CF_actor_seto, "actor_seto",
+ "<Actor id> <Orientation>", R_CVAR_NONE, 2, 2);
+
+ CVAR_RegisterFunc(CF_actor_setact, "actor_setact",
+ "<Actor id> <Action #>", R_CVAR_NONE, 2, 2);
+
+ return R_SUCCESS;
+}
+
+int ACTOR_Init(void)
+{
+ int result;
+ int i;
+
+ if (ActorModule.init) {
+
+ ActorModule.err_str = "Actor module already initialized.";
+
+ return R_FAILURE;
+ }
+
+ /* Get actor resource file context
+ * \*------------------------------------------------------------- */
+ result = GAME_GetFileContext(&ActorModule.actor_ctxt,
+ R_GAME_RESOURCEFILE, 0);
+ if (result != R_SUCCESS) {
+
+ ActorModule.err_str =
+ "Couldn't load actor module resource context.";
+
+ return R_FAILURE;
+ }
+
+ /* Create actor lookup table
+ * \*------------------------------------------------------------- */
+ ActorModule.tbl = (YS_DL_NODE **)malloc(R_ACTORCOUNT * sizeof *ActorModule.tbl);
+ if (ActorModule.tbl == NULL) {
+
+ ActorModule.err_str = R_MEMFAIL_MSG;
+
+ return R_MEM;
+ }
+
+ for (i = 0; i < R_ACTORCOUNT; i++) {
+ ActorModule.tbl[i] = NULL;
+ }
+
+ /* Create actor alias table
+ * \*------------------------------------------------------------- */
+ ActorModule.alias_tbl = (int *)malloc(R_ACTORCOUNT *
+ sizeof *ActorModule.alias_tbl);
+ if (ActorModule.alias_tbl == NULL) {
+ free(ActorModule.tbl);
+
+ ActorModule.err_str = R_MEMFAIL_MSG;
+
+ return R_MEM;
+ }
+
+ /* Initialize alias table so each index contains itself */
+ for (i = 0; i < R_ACTORCOUNT; i++) {
+
+ ActorModule.alias_tbl[i] = i;
+ }
+
+ /* Create actor list
+ * \*------------------------------------------------------------- */
+ ActorModule.list = ys_dll_create();
+
+ ActorModule.init = 1;
+
+ return R_SUCCESS;
+}
+
+int ACTOR_Shutdown(void)
+{
+
+ if (!ActorModule.init) {
+ return R_FAILURE;
+ }
+
+ if (ActorModule.tbl) {
+ free(ActorModule.tbl);
+ }
+
+ return R_SUCCESS;
+
+}
+
+int ACTOR_Direct(int msec)
+{
+
+ YS_DL_NODE *walk_p;
+ R_ACTOR *actor;
+
+ YS_DL_NODE *a_inode;
+ R_ACTORINTENT *a_intent;
+
+ int o_idx;
+ int action_tdelta;
+
+ /* Walk down the actor list and direct each actor
+ * \*------------------------------------------------------------- */
+ for (walk_p = ys_dll_head(ActorModule.list);
+ walk_p != NULL; walk_p = ys_dll_next(walk_p)) {
+
+ actor = (R_ACTOR *)ys_dll_get_data(walk_p);
+
+ /* Process the actor intent list
+ * \*--------------------------------------------------------- */
+ a_inode = ys_dll_head(actor->a_intentlist);
+
+ if (a_inode != NULL) {
+
+ a_intent = (R_ACTORINTENT *)ys_dll_get_data(a_inode);
+
+ switch (a_intent->a_itype) {
+
+ case INTENT_NONE:
+ /* Actor doesn't really feel like doing anything at all */
+ break;
+
+ case INTENT_PATH:
+ /* Actor intends to go somewhere. Well good for him */
+ {
+ R_WALKINTENT *a_walkint;
+
+ a_walkint = (R_WALKINTENT *)a_intent->a_data;
+
+ HandleWalkIntent(actor,
+ a_walkint,
+ &a_intent->a_idone, msec);
+ }
+ break;
+
+ case INTENT_SPEAK:
+ /* Actor wants to blab */
+ {
+ R_SPEAKINTENT *a_speakint;
+
+ a_speakint = (R_SPEAKINTENT *)a_intent->a_data;
+
+ HandleSpeakIntent(actor,
+ a_speakint,
+ &a_intent->a_idone, msec);
+ }
+ break;
+
+ default:
+ break;
+ } /* end switch() */
+
+ /* 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);
+
+ actor->action = actor->def_action;
+ actor->action_flags = actor->def_action_flags;
+ actor->action_frame = 0;
+ actor->action_time = 0;
+ }
+
+ } else {
+ /* Actor has no intent, idle? */
+ }
+
+ /* Process actor actions
+ * \*--------------------------------------------------------- */
+ actor->action_time += msec;
+
+ if (actor->action >= ACTION_COUNT) {
+ action_tdelta = ACTOR_ACTIONTIME;
+ } else {
+ action_tdelta = ActionTDeltas[actor->action].time;
+ }
+
+ if (actor->action_time >= action_tdelta) {
+
+ actor->action_time -= action_tdelta;
+ actor->action_frame++;
+
+ o_idx = ActorOrientationLUT[actor->orient];
+
+ if (actor->act_tbl[actor->action].dir[o_idx].
+ frame_count <= actor->action_frame) {
+
+ if (actor->action_flags & ACTION_LOOP) {
+
+ actor->action_frame = 0;
+ } else {
+ actor->action_frame--;
+ }
+ }
+ }
+
+ } /* end for () */
+
+ return R_SUCCESS;
+}
+
+int ACTOR_DrawList(void)
+{
+
+ YS_DL_NODE *walk_p;
+ R_ACTOR *actor;
+
+ YS_DL_NODE *a_inode;
+ R_ACTORINTENT *a_intent;
+ R_SPEAKINTENT *a_speakint;
+
+ YS_DL_NODE *a_dnode;
+ R_ACTORDIALOGUE *a_dialogue;
+
+ int o_idx; /* Orientation index */
+ int sprite_num;
+
+ int diag_x, diag_y; /* dialog coordinates */
+
+ R_SURFACE *back_buf;
+
+ back_buf = SYSGFX_GetBackBuffer();
+
+ for (walk_p = ys_dll_head(ActorModule.list);
+ walk_p != NULL; walk_p = ys_dll_next(walk_p)) {
+
+ actor = (R_ACTOR *)ys_dll_get_data(walk_p);
+
+ o_idx = ActorOrientationLUT[actor->orient];
+
+ sprite_num =
+ actor->act_tbl[actor->action].dir[o_idx].frame_index;
+ sprite_num += actor->action_frame;
+
+ SPRITE_DrawOccluded(back_buf,
+ actor->sl_p, sprite_num, actor->s_pt.x, actor->s_pt.y);
+
+ /* 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 = (R_ACTORINTENT *)ys_dll_get_data(a_inode);
+
+ if (a_intent->a_itype == INTENT_SPEAK) {
+
+ a_speakint = (R_SPEAKINTENT *)a_intent->a_data;
+
+ a_dnode = ys_dll_head(a_speakint->si_diaglist);
+
+ if (a_dnode != NULL) {
+
+ a_dialogue = (R_ACTORDIALOGUE *)ys_dll_get_data(a_dnode);
+
+ diag_x = actor->s_pt.x;
+ diag_y = actor->s_pt.y;
+
+ diag_y -= ACTOR_DIALOGUE_HEIGHT;
+
+ TEXT_Draw(MEDIUM_FONT_ID,
+ back_buf,
+ a_dialogue->d_string,
+ diag_x, diag_y,
+ actor->a_dcolor, 0,
+ FONT_OUTLINE | FONT_CENTERED);
+ }
+ }
+ }
+ }
+
+ return R_SUCCESS;
+}
+
+int ACTOR_SkipDialogue(void)
+/*--------------------------------------------------------------------------*\
+ * Called if the user wishes to skip a line of dialogue (spacebar in the
+ * original game). Will find all actors currently talking and remove one
+ * dialogue entry if there is a current speak intent present.
+\*--------------------------------------------------------------------------*/
+{
+
+ YS_DL_NODE *walk_p;
+ R_ACTOR *actor;
+
+ YS_DL_NODE *a_inode;
+ R_ACTORINTENT *a_intent;
+ R_SPEAKINTENT *a_speakint;
+
+ YS_DL_NODE *a_dnode;
+ R_ACTORDIALOGUE *a_dialogue;
+
+ if (!ActorModule.init) {
+ return R_FAILURE;
+ }
+
+ for (walk_p = ys_dll_head(ActorModule.list);
+ walk_p != NULL; walk_p = ys_dll_next(walk_p)) {
+
+ actor = (R_ACTOR *)ys_dll_get_data(walk_p);
+
+ /* Check the actor's current intent for a speak intent
+ * \*--------------------------------------------------------- */
+ a_inode = ys_dll_head(actor->a_intentlist);
+
+ if (a_inode != NULL) {
+
+ a_intent = (R_ACTORINTENT *)ys_dll_get_data(a_inode);
+
+ if (a_intent->a_itype == INTENT_SPEAK) {
+
+ /* Okay, found a speak intent. Remove one dialogue entry
+ * from it, releasing any semaphore */
+
+ a_speakint = (R_SPEAKINTENT *)a_intent->a_data;
+
+ a_dnode = ys_dll_head(a_speakint->si_diaglist);
+
+ if (a_dnode != NULL) {
+
+ a_dialogue = (R_ACTORDIALOGUE *)ys_dll_get_data(a_dnode);
+
+ if (a_dialogue->d_sem != NULL) {
+
+ STHREAD_ReleaseSem(a_dialogue->
+ d_sem);
+ }
+
+ ys_dll_delete(a_dnode);
+
+ /* And stop any currently playing voices */
+ SYSSOUND_StopVoice();
+ }
+ }
+ }
+ }
+
+ return R_SUCCESS;
+}
+
+int ACTOR_Create(int actor_id, int x, int y)
+{
+ R_ACTOR actor = { 0 };
+
+ if (actor_id == 1) {
+ actor_id = 0;
+ } else {
+ actor_id = actor_id & ~0x2000;
+ }
+
+ actor.id = actor_id;
+ actor.a_pt.x = x;
+ actor.a_pt.y = y;
+
+ if (AddActor(&actor) != R_SUCCESS) {
+
+ return R_FAILURE;
+ }
+
+ return R_SUCCESS;
+}
+
+int AddActor(R_ACTOR * actor)
+{
+
+ YS_DL_NODE *new_node;
+
+ int last_frame;
+ int i;
+
+ if (!ActorModule.init) {
+ return R_FAILURE;
+ }
+
+ if ((actor->id < 0) || (actor->id >= R_ACTORCOUNT)) {
+ return R_FAILURE;
+ }
+
+ if (ActorModule.tbl[actor->id] != NULL) {
+ return R_FAILURE;
+ }
+
+ ACTOR_AtoS(&actor->s_pt, &actor->a_pt);
+
+ i = actor->id;
+
+ actor->sl_rn = ActorTable[i].spritelist_rn;
+ actor->si_rn = ActorTable[i].spriteindex_rn;
+
+ LoadActorSpriteIndex(actor, actor->si_rn, &last_frame);
+
+ if (SPRITE_LoadList(actor->sl_rn, &actor->sl_p) != R_SUCCESS) {
+
+ return R_FAILURE;
+ }
+
+ if (last_frame >= SPRITE_GetListLen(actor->sl_p)) {
+
+ R_printf(R_STDOUT,
+ "Appending to sprite list %d.\n", actor->sl_rn);
+
+ if (SPRITE_AppendList(actor->sl_rn + 1,
+ actor->sl_p) != R_SUCCESS) {
+ return R_FAILURE;
+ }
+ }
+
+ 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;
+ actor->action_flags = 0;
+ actor->action_time = 0;
+ actor->action_frame = 0;
+
+ new_node = ys_dll_insert(ActorModule.list,
+ actor, sizeof *actor, Z_Compare);
+
+ if (new_node == NULL) {
+ return R_FAILURE;
+ }
+
+ actor = (R_ACTOR *)ys_dll_get_data(new_node);
+ actor->node = new_node;
+
+ ActorModule.tbl[i] = new_node;
+
+ ActorModule.count++;
+
+ return R_SUCCESS;
+}
+
+int ACTOR_GetActorIndex(uint actor_id)
+{
+ uint actor_idx;
+
+ if (actor_id == 1) {
+ actor_idx = 0;
+ } else {
+ actor_idx = actor_id & ~0x2000;
+ }
+
+ if (ActorModule.tbl[actor_idx] == NULL) {
+ return -1;
+ }
+
+ return actor_idx;
+}
+
+int ACTOR_ActorExists(uint actor_id)
+{
+ uint actor_idx;
+
+ if (actor_id == 1) {
+ actor_idx = 0;
+ } else {
+ actor_idx = actor_id & ~0x2000;
+ }
+
+ if (ActorModule.tbl[actor_idx] == NULL) {
+ return 0;
+ }
+
+ return 1;
+}
+
+int ACTOR_Speak(int index, char *d_string, uint d_voice_rn, R_SEMAPHORE * sem)
+{
+
+ YS_DL_NODE *node;
+ R_ACTOR *actor;
+
+ YS_DL_NODE *a_inode;
+ R_ACTORINTENT *a_intent_p = NULL;
+ R_SPEAKINTENT *a_speakint;
+
+ R_ACTORINTENT a_intent;
+
+ int use_existing_ai = 0;
+
+ R_ACTORDIALOGUE a_dialogue = { 0 };
+
+ a_dialogue.d_string = d_string;
+ a_dialogue.d_voice_rn = d_voice_rn;
+ a_dialogue.d_time = ACTOR_GetSpeechTime(d_string, d_voice_rn);
+ a_dialogue.d_sem_held = 1;
+ a_dialogue.d_sem = sem;
+
+ node = ActorModule.tbl[index];
+ if (node == NULL) {
+ return R_FAILURE;
+ }
+
+ actor = (R_ACTOR *)ys_dll_get_data(node);
+
+ /* 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 = (R_ACTORINTENT *)ys_dll_get_data(a_inode);
+
+ if (a_intent_p->a_itype == INTENT_SPEAK) {
+
+ use_existing_ai = 1;
+ }
+ }
+
+ if (use_existing_ai) {
+
+ /* Store the current dialogue off the existing actor intent */
+ a_speakint = (R_SPEAKINTENT *)a_intent_p->a_data;
+
+ ys_dll_add_tail(a_speakint->si_diaglist,
+ &a_dialogue, sizeof 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_speakint = (R_SPEAKINTENT *)malloc(sizeof *a_speakint);
+ if (a_speakint == NULL) {
+
+ return R_FAILURE;
+ }
+
+ a_speakint->si_init = 0;
+ a_speakint->si_diaglist = ys_dll_create();
+ a_speakint->si_last_action = actor->action;
+
+ a_intent.a_data = a_speakint;
+
+ 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);
+ }
+
+ if (sem != NULL) {
+ STHREAD_HoldSem(sem);
+ }
+
+ return R_SUCCESS;
+}
+
+int
+HandleSpeakIntent(R_ACTOR * actor,
+ R_SPEAKINTENT * a_speakint, int *complete_p, int msec)
+{
+
+ YS_DL_NODE *a_dnode;
+ YS_DL_NODE *a_dnext;
+
+ R_ACTORDIALOGUE *a_dialogue;
+ R_ACTORDIALOGUE *a_dialogue2;
+
+ long carry_time;
+ int intent_complete = 0;
+
+ if (!a_speakint->si_init) {
+
+ /* Initialize speak intent by setting up action */
+
+ actor->action = ACTION_SPEAK;
+ actor->action_frame = 0;
+ actor->action_time = 0;
+ actor->action_flags = ACTION_LOOP;
+
+ a_speakint->si_init = 1;
+ }
+
+ /* Process actor dialogue list
+ * \*--------------------------------------------------------- */
+ a_dnode = ys_dll_head(a_speakint->si_diaglist);
+
+ if (a_dnode != NULL) {
+
+ a_dialogue = (R_ACTORDIALOGUE *)ys_dll_get_data(a_dnode);
+
+ if (!a_dialogue->d_playing) {
+ /* Dialogue voice hasn't played yet - play it now */
+
+ SND_PlayVoice(a_dialogue->d_voice_rn);
+ a_dialogue->d_playing = 1;
+ }
+
+ a_dialogue->d_time -= msec;
+
+ if (a_dialogue->d_time <= 0) {
+
+ /* Dialogue time has expired; carry negative time to next
+ * dialogue entry if present, release any semaphores and
+ * delete the expired entry */
+
+ /*actor->action = ACTION_IDLE; */
+
+ if (a_dialogue->d_sem != NULL) {
+ STHREAD_ReleaseSem(a_dialogue->d_sem);
+ }
+
+ carry_time = a_dialogue->d_time;
+
+ a_dnext = ys_dll_next(a_dnode);
+ if (a_dnext != NULL) {
+
+ a_dialogue2 = (R_ACTORDIALOGUE *)ys_dll_get_data(a_dnode);
+ 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) {
+ intent_complete = 1;
+ }
+
+ }
+ } else {
+ intent_complete = 1;
+ }
+
+ if (intent_complete) {
+
+ *complete_p = 1;
+ }
+
+ return R_SUCCESS;
+}
+
+int ACTOR_GetSpeechTime(const char *d_string, uint d_voice_rn)
+{
+ int voice_len;
+
+ voice_len = SND_GetVoiceLength(d_voice_rn);
+
+ if (voice_len < 0) {
+ voice_len = strlen(d_string) * ACTOR_DIALOGUE_LETTERTIME;
+ }
+
+ return voice_len;
+}
+
+int ACTOR_SetOrientation(int index, int orient)
+{
+
+ R_ACTOR *actor;
+
+ if (!ActorModule.init) {
+ return R_FAILURE;
+ }
+
+ if ((orient < 0) || (orient > 7)) {
+ return R_FAILURE;
+ }
+
+ actor = LookupActor(index);
+ if (actor == NULL) {
+
+ return R_FAILURE;
+ }
+
+ actor->orient = orient;
+
+ return R_SUCCESS;
+}
+
+int ACTOR_SetAction(int index, int action_n, uint action_flags)
+{
+ R_ACTOR *actor;
+
+ if (!ActorModule.init) {
+
+ return R_FAILURE;
+ }
+
+ actor = LookupActor(index);
+ if (actor == NULL) {
+
+ return R_FAILURE;
+ }
+
+ if ((action_n < 0) || (action_n >= actor->action_ct)) {
+
+ return R_FAILURE;
+ }
+
+ actor->action = action_n;
+ actor->action_flags = action_flags;
+ actor->action_frame = 0;
+ actor->action_time = 0;
+
+ return R_SUCCESS;
+}
+
+int ACTOR_SetDefaultAction(int index, int action_n, uint action_flags)
+{
+ R_ACTOR *actor;
+
+ if (!ActorModule.init) {
+
+ return R_FAILURE;
+ }
+
+ actor = LookupActor(index);
+ if (actor == NULL) {
+
+ return R_FAILURE;
+ }
+
+ if ((action_n < 0) || (action_n >= actor->action_ct)) {
+
+ return R_FAILURE;
+ }
+
+ actor->def_action = action_n;
+ actor->def_action_flags = action_flags;
+
+ return R_SUCCESS;
+}
+
+R_ACTOR *LookupActor(int index)
+{
+ YS_DL_NODE *node;
+ R_ACTOR *actor;
+
+ if (!ActorModule.init) {
+ return NULL;
+ }
+
+ if ((index < 0) || (index >= R_ACTORCOUNT)) {
+ return NULL;
+ }
+
+ if (ActorModule.tbl[index] == NULL) {
+ return NULL;
+ }
+
+ node = ActorModule.tbl[index];
+ actor = (R_ACTOR *)ys_dll_get_data(node);
+
+ return actor;
+}
+
+int LoadActorSpriteIndex(R_ACTOR * actor, int si_rn, int *last_frame_p)
+{
+
+ uchar *res_p;
+ size_t res_len;
+
+ const uchar *read_p;
+
+ int s_action_ct;
+ R_ACTORACTION *action_p;
+ int last_frame;
+
+ int i, orient;
+ int result;
+
+ result = RSC_LoadResource(ActorModule.actor_ctxt,
+ si_rn, &res_p, &res_len);
+ if (result != R_SUCCESS) {
+
+ R_printf(R_STDERR,
+ "Couldn't load sprite action index resource.\n");
+
+ return R_FAILURE;
+ }
+
+ read_p = res_p;
+
+ s_action_ct = res_len / 16;
+
+ R_printf(R_STDOUT,
+ "Sprite resource contains %d sprite actions.\n", s_action_ct);
+
+ action_p = (R_ACTORACTION *)malloc(sizeof(R_ACTORACTION) * s_action_ct);
+
+ if (action_p == NULL) {
+
+ R_printf(R_STDERR,
+ "Couldn't allocate memory for sprite actions.\n");
+
+ RSC_FreeResource(res_p);
+
+ return R_MEM;
+ }
+
+ last_frame = 0;
+
+ 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 =
+ ys_read_u16_le(read_p, &read_p);
+
+ action_p[i].dir[orient].frame_count =
+ ys_read_u16_le(read_p, &read_p);
+
+ if (action_p[i].dir[orient].frame_index > last_frame) {
+ last_frame =
+ action_p[i].dir[orient].frame_index;
+ }
+ }
+ }
+
+ actor->act_tbl = action_p;
+ actor->action_ct = s_action_ct;
+
+ RSC_FreeResource(res_p);
+
+ if (last_frame_p != NULL) {
+ *last_frame_p = last_frame;
+ }
+
+ return R_SUCCESS;
+}
+
+int DeleteActor(int index)
+{
+
+ YS_DL_NODE *node;
+ R_ACTOR *actor;
+
+ if (!ActorModule.init) {
+ return R_FAILURE;
+ }
+
+ if ((index < 0) || (index >= R_ACTORCOUNT)) {
+ return R_FAILURE;
+ }
+
+ if (ActorModule.tbl[index] == NULL) {
+ return R_FAILURE;
+ }
+
+ node = ActorModule.tbl[index];
+ actor = (R_ACTOR *)ys_dll_get_data(node);
+
+ SPRITE_Free(actor->sl_p);
+
+ ys_dll_delete(node);
+
+ ActorModule.tbl[index] = NULL;
+
+ return R_SUCCESS;
+}
+
+int ACTOR_WalkTo(int id, R_POINT * walk_pt, uint flags, R_SEMAPHORE * sem)
+/*--------------------------------------------------------------------------*\
+\*--------------------------------------------------------------------------*/
+{
+ R_ACTORINTENT actor_intent = { 0 };
+
+ R_WALKINTENT *walk_intent;
+ R_WALKINTENT zero_intent = { 0 };
+
+ YS_DL_NODE *node;
+ R_ACTOR *actor;
+
+ assert(ActorModule.init);
+ assert(walk_pt != NULL);
+
+ if ((id < 0) || (id >= R_ACTORCOUNT)) {
+ return R_FAILURE;
+ }
+
+ if (ActorModule.tbl[id] == NULL) {
+ return R_FAILURE;
+ }
+
+ node = ActorModule.tbl[id];
+ actor = (R_ACTOR *)ys_dll_get_data(node);
+
+ walk_intent = (R_WALKINTENT *)malloc(sizeof *walk_intent);
+ if (walk_intent == NULL) {
+
+ return R_MEM;
+ }
+
+ *walk_intent = zero_intent;
+
+ walk_intent->wi_flags = flags;
+ walk_intent->sem_held = 1;
+ walk_intent->sem = sem;
+
+ /* HandleWalkIntent() will create path on initialization */
+ 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);
+
+ if (sem != NULL) {
+ STHREAD_HoldSem(sem);
+ }
+
+ return R_SUCCESS;
+}
+
+int
+ACTOR_SetPathNode(R_WALKINTENT * walk_int,
+ R_POINT * src_pt, R_POINT * dst_pt, R_SEMAPHORE * sem)
+{
+
+ R_WALKNODE new_node;
+
+ walk_int->wi_active = 1;
+ 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);
+
+ return R_SUCCESS;
+}
+
+int
+HandleWalkIntent(R_ACTOR * actor,
+ R_WALKINTENT * a_walkint, int *complete_p, int delta_time)
+{
+
+ YS_DL_NODE *walk_p;
+ YS_DL_NODE *next_p;
+
+ R_WALKNODE *node_p;
+ int dx;
+ int dy;
+
+ double path_a;
+ double path_b;
+ double path_slope;
+
+ double path_x;
+ double path_y;
+ int path_time;
+
+ double new_a_x;
+ double new_a_y;
+
+ int actor_x;
+ int actor_y;
+
+ char buf[100];
+
+ /* Initialize walk intent
+ * \*------------------------------------------------------------- */
+ if (!a_walkint->wi_init) {
+
+ a_walkint->nodelist = ys_dll_create();
+
+ ACTOR_SetPathNode(a_walkint,
+ &actor->a_pt, &a_walkint->dst_pt, a_walkint->sem);
+
+ ACTOR_SetDefaultAction(actor->id, ACTION_IDLE, ACTION_NONE);
+
+ a_walkint->wi_init = 1;
+ }
+
+ assert(a_walkint->wi_active);
+
+ walk_p = ys_dll_head(a_walkint->nodelist);
+ next_p = ys_dll_next(walk_p);
+
+ node_p = (R_WALKNODE *)ys_dll_get_data(walk_p);
+
+ if (node_p->calc_flag == 0) {
+
+# if 0
+ R_printf(R_STDOUT,
+ "Calculating new path vector to point (%d, %d)\n",
+ node_p->node_pt.x, node_p->node_pt.y);
+# endif
+
+ dx = a_walkint->org.x - node_p->node_pt.x;
+ dy = a_walkint->org.y - node_p->node_pt.y;
+
+ if (dx == 0) {
+
+ R_printf(R_STDOUT,
+ "Vertical paths not implemented.\n");
+
+ ys_dll_delete(walk_p);
+ a_walkint->wi_active = 0;
+
+ /* Release path semaphore... */
+ if ((a_walkint->sem != NULL) && a_walkint->sem_held) {
+
+ STHREAD_ReleaseSem(a_walkint->sem);
+ }
+
+ *complete_p = 1;
+
+ return R_FAILURE;
+ }
+
+ a_walkint->slope = (float)dy / dx;
+
+ if (dx > 0) {
+
+ a_walkint->x_dir = -1;
+
+ if (!(a_walkint->wi_flags & WALK_NOREORIENT)) {
+
+ if (a_walkint->slope > 1.0) {
+ actor->orient = ORIENT_N;
+ } else if (a_walkint->slope < -1.0) {
+ actor->orient = ORIENT_S;
+ } else {
+ actor->orient = ORIENT_W;
+ }
+ }
+ } else {
+
+ a_walkint->x_dir = 1;
+
+ if (!(a_walkint->wi_flags & WALK_NOREORIENT)) {
+
+ if (a_walkint->slope > 1.0) {
+ actor->orient = ORIENT_S;
+ } else if (a_walkint->slope < -1.0) {
+ actor->orient = ORIENT_N;
+ } else {
+ actor->orient = ORIENT_E;
+ }
+ }
+ }
+
+ sprintf(buf, "%f", a_walkint->slope);
+
+# if 0
+ R_printf(R_STDOUT, "Path slope: %s.\n", buf);
+# endif
+
+ actor->action = ACTION_WALK;
+ actor->action_flags = ACTION_LOOP;
+ a_walkint->time = 0;
+ node_p->calc_flag = 1;
+ }
+
+ a_walkint->time += delta_time;
+ path_time = a_walkint->time;
+
+ path_a = ACTOR_BASE_SPEED * path_time;
+ path_b = ACTOR_BASE_SPEED * path_time * ACTOR_BASE_ZMOD;
+ path_slope = a_walkint->slope * a_walkint->x_dir;
+
+ path_x = (path_a * path_b) /
+ sqrt((path_a * path_a) *
+ (path_slope * path_slope) + (path_b * path_b));
+
+ path_y = path_slope * path_x;
+ path_x = path_x * a_walkint->x_dir;
+
+ new_a_x = path_x + a_walkint->org.x;
+ new_a_y = path_y + a_walkint->org.y;
+
+ if (a_walkint->x_dir == 1) {
+
+ if (new_a_x >= node_p->node_pt.x) {
+
+# if 0
+ R_printf(R_STDOUT, "Path complete.\n");
+# endif
+
+ ys_dll_delete(walk_p);
+
+ a_walkint->wi_active = 0;
+
+ /* Release path semaphore... */
+ if (a_walkint->sem != NULL) {
+ STHREAD_ReleaseSem(a_walkint->sem);
+ }
+
+ actor->action_frame = 0;
+ actor->action = ACTION_IDLE;
+
+ *complete_p = 1;
+
+ return R_FAILURE;
+ }
+ } else {
+
+ if (new_a_x <= node_p->node_pt.x) {
+
+# if 0
+ R_printf(R_STDOUT, "Path complete.\n");
+# endif
+
+ ys_dll_delete(walk_p);
+
+ a_walkint->wi_active = 0;
+
+ /* Release path semaphore... */
+ if (a_walkint->sem != NULL) {
+ STHREAD_ReleaseSem(a_walkint->sem);
+ }
+
+ actor->action_frame = 0;
+ actor->action = ACTION_IDLE;
+
+ *complete_p = 1;
+
+ return R_FAILURE;
+
+ }
+ }
+
+ actor_x = (int)new_a_x;
+ actor_y = (int)new_a_y;
+
+ actor->a_pt.x = (int)new_a_x;
+ actor->a_pt.y = (int)new_a_y;
+
+ 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(ActorModule.list, actor->node, Z_Compare);
+
+ } else {
+ ys_dll_reorder_down(ActorModule.list, actor->node, Z_Compare);
+ }
+
+ return R_SUCCESS;
+}
+
+int ACTOR_Move(int index, R_POINT * move_pt)
+{
+
+ YS_DL_NODE *node;
+ R_ACTOR *actor;
+
+ int move_up = 0;
+
+ node = ActorModule.tbl[index];
+ if (node == NULL) {
+ return R_FAILURE;
+ }
+
+ actor = (R_ACTOR *)ys_dll_get_data(node);
+
+ if (move_pt->y < actor->a_pt.y) {
+ move_up = 1;
+ }
+
+ actor->a_pt.x = move_pt->x;
+ actor->a_pt.y = move_pt->y;
+
+ ACTOR_AtoS(&actor->s_pt, &actor->a_pt);
+
+ if (move_up) {
+ ys_dll_reorder_up(ActorModule.list, actor->node, Z_Compare);
+ } else {
+
+ ys_dll_reorder_down(ActorModule.list, actor->node, Z_Compare);
+ }
+
+ return R_SUCCESS;
+}
+
+int ACTOR_MoveRelative(int index, R_POINT * move_pt)
+{
+
+ YS_DL_NODE *node;
+ R_ACTOR *actor;
+
+ node = ActorModule.tbl[index];
+ if (node == NULL) {
+ return R_FAILURE;
+ }
+
+ actor = (R_ACTOR *)ys_dll_get_data(node);
+
+ actor->a_pt.x += move_pt->x;
+ actor->a_pt.y += move_pt->y;
+
+ ACTOR_AtoS(&actor->s_pt, &actor->a_pt);
+
+ if (actor->a_pt.y < 0) {
+
+ ys_dll_reorder_up(ActorModule.list, actor->node, Z_Compare);
+ } else {
+
+ ys_dll_reorder_down(ActorModule.list, actor->node, Z_Compare);
+
+ }
+
+ return R_SUCCESS;
+}
+
+int Z_Compare(const void *elem1, const void *elem2)
+{
+
+ R_ACTOR *actor1 = (R_ACTOR *) elem1;
+ R_ACTOR *actor2 = (R_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(R_POINT * screen, const R_POINT * actor)
+{
+
+ screen->x = (actor->x / R_ACTOR_LMULT);
+ screen->y = (actor->y / R_ACTOR_LMULT);
+
+ return R_SUCCESS;
+}
+
+int ACTOR_StoA(R_POINT * actor, const R_POINT * screen)
+{
+
+ actor->x = (screen->x * R_ACTOR_LMULT);
+ actor->y = (screen->y * R_ACTOR_LMULT);
+
+ return R_SUCCESS;
+}
+
+static void CF_actor_add(int argc, char *argv[])
+{
+ R_ACTOR actor = { 0 };
+
+ if (argc < 3)
+ return;
+
+ actor.id = (uint) atoi(argv[0]);
+
+ actor.a_pt.x = atoi(argv[1]);
+ actor.a_pt.y = atoi(argv[2]);
+
+ AddActor(&actor);
+
+ return;
+}
+
+static void CF_actor_del(int argc, char *argv[])
+{
+ int id;
+
+ if (argc < 0)
+ return;
+
+ id = atoi(argv[0]);
+
+ DeleteActor(id);
+
+ return;
+}
+
+static void CF_actor_move(int argc, char *argv[])
+{
+ int id;
+ R_POINT move_pt;
+
+ if (argc < 2)
+ return;
+
+ id = atoi(argv[0]);
+
+ move_pt.x = atoi(argv[1]);
+ move_pt.y = atoi(argv[2]);
+
+ ACTOR_Move(id, &move_pt);
+
+ return;
+}
+
+static void CF_actor_moverel(int argc, char *argv[])
+{
+ int id;
+ R_POINT move_pt;
+
+ if (argc < 3)
+ return;
+
+ id = atoi(argv[0]);
+
+ move_pt.x = atoi(argv[1]);
+ move_pt.y = atoi(argv[2]);
+
+ ACTOR_MoveRelative(id, &move_pt);
+
+ return;
+}
+
+static void CF_actor_seto(int argc, char *argv[])
+{
+
+ int id;
+ int orient;
+
+ if (argc < 2)
+ return;
+
+ id = atoi(argv[0]);
+ orient = atoi(argv[1]);
+
+ ACTOR_SetOrientation(id, orient);
+
+ return;
+}
+
+static void CF_actor_setact(int argc, char *argv[])
+{
+ int index = 0;
+ int action_n = 0;
+
+ R_ACTOR *actor;
+
+ if (argc < 2)
+ return;
+
+ index = atoi(argv[0]);
+ action_n = atoi(argv[1]);
+
+ actor = LookupActor(index);
+ if (actor == NULL) {
+ CON_Print("Invalid actor index.");
+
+ return;
+ }
+
+ if ((action_n < 0) || (action_n >= actor->action_ct)) {
+ CON_Print("Invalid action number.");
+
+ return;
+ }
+
+ CON_Print("Action frame counts: %d %d %d %d.",
+ actor->act_tbl[action_n].dir[0].frame_count,
+ actor->act_tbl[action_n].dir[1].frame_count,
+ actor->act_tbl[action_n].dir[2].frame_count,
+ actor->act_tbl[action_n].dir[3].frame_count);
+
+ ACTOR_SetAction(index, action_n, ACTION_LOOP);
+
+ return;
+}
+
+} // End of namespace Saga
diff --git a/saga/actor.h b/saga/actor.h
new file mode 100644
index 0000000000..32942d4a44
--- /dev/null
+++ b/saga/actor.h
@@ -0,0 +1,234 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Actor management module header file
+
+ Notes:
+
+ Hardcoded actor table present in r_actordata.c
+*/
+
+#ifndef SAGA_ACTOR_H__
+#define SAGA_ACTOR_H__
+
+namespace Saga {
+
+#define ACTOR_BASE_SPEED 0.25
+#define ACTOR_BASE_ZMOD 0.5
+
+#define ACTOR_DEFAULT_ORIENT 2
+#define ACTOR_ORIENTMAX 7
+
+#define ACTOR_ACTIONTIME 80
+
+#define ACTOR_DIALOGUE_LETTERTIME 50
+#define ACTOR_DIALOGUE_HEIGHT 100
+
+#define R_ACTOR_LMULT 4
+
+enum R_ACTOR_INTENTS {
+
+ INTENT_NONE = 0,
+ INTENT_PATH = 1,
+ INTENT_SPEAK = 2
+};
+
+typedef struct R_ACTORACTIONITEM_tag {
+
+ int frame_index;
+ int frame_count;
+
+} R_ACTORACTIONITEM;
+
+typedef struct R_ACTORACTION_tag {
+
+ R_ACTORACTIONITEM dir[4];
+
+} R_ACTORACTION;
+
+typedef struct R_WALKINTENT_tag {
+
+ int wi_active;
+ uint wi_flags;
+ int wi_init;
+
+ int time;
+ float slope;
+ int x_dir;
+ R_POINT org;
+ R_POINT cur;
+
+ R_POINT dst_pt;
+ YS_DL_LIST *nodelist;
+
+ int sem_held;
+ R_SEMAPHORE *sem;
+
+} R_WALKINTENT;
+
+typedef struct R_WALKNODE_tag {
+
+ int calc_flag;
+ R_POINT node_pt;
+
+} R_WALKNODE;
+
+typedef struct R_SPEAKINTENT_tag {
+
+ int si_init;
+ uint si_flags;
+ int si_last_action;
+
+ YS_DL_LIST *si_diaglist; /* Actor dialogue list */
+
+} R_SPEAKINTENT;
+
+typedef struct R_ACTORINTENT_tag {
+
+ int a_itype;
+ uint a_iflags;
+ int a_idone;
+
+ void *a_data;
+
+} R_ACTORINTENT;
+
+typedef struct R_ACTOR_tag {
+
+ int id; /* Actor id */
+ int name_i; /* Actor's index in actor name string list */
+ uint flags;
+
+ R_POINT a_pt; /* Actor's logical coordinates */
+ R_POINT s_pt; /* Actor's screen coordinates */
+
+ int sl_rn; /* Actor's sprite list res # */
+ int si_rn; /* Actor's sprite index res # */
+ R_SPRITELIST *sl_p; /* Actor's sprite list data */
+
+ int idle_time;
+ int orient;
+ int speaking;
+
+ int a_dcolor; /* Actor dialogue color */
+
+ /* The actor intent list describes what the actor intends to do;
+ * multiple intents can be queued. The actor must complete an
+ * intent before moving on to the next; thus actor movements, esp
+ * as described from scripts, can be serialized */
+
+ YS_DL_LIST *a_intentlist;
+/*
+ R_WALKPATH path;
+*/
+
+ int def_action;
+ uint def_action_flags;
+
+ int action;
+ uint action_flags;
+
+ int action_frame;
+ int action_time;
+
+ R_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 */
+
+} R_ACTOR;
+
+typedef struct R_ACTORDIALOGUE_tag {
+
+ int d_playing;
+ char *d_string;
+ uint d_voice_rn;
+
+ long d_time;
+ int d_sem_held;
+ R_SEMAPHORE *d_sem;
+
+} R_ACTORDIALOGUE;
+
+typedef struct R_ACTIONTIMES_tag {
+
+ int action;
+ int time;
+
+} R_ACTIONTIMES;
+
+typedef struct R_ACTOR_MODULE_tag {
+
+ int init;
+
+ R_RSCFILE_CONTEXT *actor_ctxt;
+
+ uint count;
+
+ int *alias_tbl;
+ YS_DL_NODE **tbl;
+ YS_DL_LIST *list;
+
+ int err_n;
+ const char *err_str;
+
+} R_ACTOR_MODULE;
+
+R_ACTOR *LookupActor(int index);
+
+int AddActor(R_ACTOR * actor);
+
+int Z_Compare(const void *elem1, const void *elem2);
+
+int
+HandleWalkIntent(R_ACTOR * actor,
+ R_WALKINTENT * a_walk_int, int *complete_p, int msec);
+
+int
+HandleSpeakIntent(R_ACTOR * actor,
+ R_SPEAKINTENT * a_speakint, int *complete_p, int msec);
+
+int
+ACTOR_SetPathNode(R_WALKINTENT * walk_int,
+ R_POINT * src_pt, R_POINT * dst_pt, R_SEMAPHORE * sem);
+
+int LoadActorSpriteIndex(R_ACTOR * actor, int si_rn, int *last_frame_p);
+
+static void CF_actor_add(int argc, char *argv[]);
+
+static void CF_actor_del(int argc, char *argv[]);
+
+static void CF_actor_move(int argc, char *argv[]);
+
+static void CF_actor_moverel(int argc, char *argv[]);
+
+static void CF_actor_seto(int argc, char *argv[]);
+
+static void CF_actor_setact(int argc, char *argv[]);
+
+} // End of namespace Saga
+
+#endif /* R_ACTOR_H__ */
+/* end "r_actor.h" */
diff --git a/saga/actor_mod.h b/saga/actor_mod.h
new file mode 100644
index 0000000000..ebd2881d70
--- /dev/null
+++ b/saga/actor_mod.h
@@ -0,0 +1,100 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Actor management module public header file
+
+ Notes:
+*/
+
+#ifndef SAGA_ACTOR_MOD_H
+#define SAGA_ACTOR_MOD_H
+
+namespace Saga {
+
+enum R_ACTOR_WALKFLAGS {
+
+ WALK_NONE = 0x00,
+ WALK_NOREORIENT = 0x01
+};
+
+enum R_ACTOR_ORIENTATIONS {
+
+ ORIENT_N = 0,
+ ORIENT_NE = 1,
+ ORIENT_E = 2,
+ ORIENT_SE = 3,
+ ORIENT_S = 4,
+ ORIENT_SW = 5,
+ ORIENT_W = 6,
+ ORIENT_NW = 7
+};
+
+enum R_ACTOR_ACTIONS {
+
+ ACTION_IDLE = 0,
+ ACTION_WALK = 1,
+ ACTION_SPEAK = 2,
+ ACTION_COUNT
+};
+
+enum R_ACTOR_ACTIONFLAGS {
+
+ ACTION_NONE = 0x00,
+ ACTION_LOOP = 0x01
+};
+
+int ACTOR_Register(void);
+int ACTOR_Init(void);
+int ACTOR_Shutdown(void);
+
+int ACTOR_Direct(int msec);
+
+int ACTOR_Create(int actor_id, int x, int y);
+int ACTOR_ActorExists(uint actor_id);
+
+int ACTOR_DrawList(void);
+int ACTOR_AtoS(R_POINT * logical, const R_POINT * actor);
+int ACTOR_StoA(R_POINT * actor, const R_POINT * screen);
+
+int ACTOR_Move(int index, R_POINT * move_pt);
+int ACTOR_MoveRelative(int index, R_POINT * move_pt);
+
+int ACTOR_WalkTo(int index, R_POINT * walk_pt, uint flags, R_SEMAPHORE * sem);
+
+int ACTOR_GetActorIndex(uint actor_id);
+
+int ACTOR_Speak(int index, char *d_string, uint d_voice_rn, R_SEMAPHORE * sem);
+
+int ACTOR_SkipDialogue(void);
+
+int ACTOR_GetSpeechTime(const char *d_string, uint d_voice_rn);
+int ACTOR_SetOrientation(int index, int orient);
+int ACTOR_SetAction(int index, int action_n, uint action_flags);
+int ACTOR_SetDefaultAction(int index, int action_n, uint action_flags);
+
+} // End of namespace Saga
+
+#endif /* R_ACTOR_MOD_H */
+/* end "r_actor_mod.h" */
diff --git a/saga/actordata.cpp b/saga/actordata.cpp
new file mode 100644
index 0000000000..5342d2d9b8
--- /dev/null
+++ b/saga/actordata.cpp
@@ -0,0 +1,227 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Actor data table
+
+ Notes:
+*/
+
+#include "actordata.h"
+
+namespace Saga {
+
+/* Lookup table to convert 8 cardinal directions to 4 */
+int ActorOrientationLUT[] = { 2, 0, 0, 0, 3, 1, 1, 1 };
+
+R_ACTORTABLE ActorTable[R_ACTORCOUNT] = {
+
+/* namei sl_rn si_rn col
+ ----- ----- ----- --- */
+ {0, 1, 0, 0, 0, 37, 135, 0, 1, 0, 0, 0},
+ /* original okk entry
+ * { 1, 0, 0, 0, 0, 0, 0, 1, 132, 0, 0, 0 }, */
+ {1, 0, 0, 0, 0, 45, 144, 1, 132, 0, 0, 0},
+ {2, 0, 0, 0, 0, 48, 143, 2, 161, 0, 0, 0},
+ {3, 0, 240, 480, 0, 115, 206, 0, 25, 0, 0, 0},
+ {4, 17, 368, 400, 0, 115, 206, 4, 49, 0, 0, 0},
+ {5, 11, 552, 412, 0, 54, 152, 1, 171, 0, 0, 0},
+ {17, 2, 1192, 888, 0, 57, 153, 17, 49, 0, 0, 0},
+ {17, 2, 816, 1052, 0, 57, 153, 18, 49, 0, 0, 0},
+ {17, 2, 928, 932, 0, 58, 153, 19, 49, 0, 0, 0},
+ {17, 2, 1416, 1160, 0, 58, 153, 20, 49, 0, 0, 0},
+ {19, 49, 1592, 1336, 0, 92, 175, 15, 162, 0, 0, 0},
+ {20, 49, 744, 824, 0, 63, 156, 19, 112, 0, 4, 4},
+ {19, 0, 1592, 1336, 0, 92, 175, 0, 171, 0, 0, 0},
+ {19, 0, 1592, 1336, 0, 92, 175, 0, 171, 0, 0, 0},
+ {9, 49, 1560, 1624, 0, 94, 147, 18, 132, 0, 4, 4},
+ {56, 49, 1384, 792, 0, 95, 193, 20, 72, 0, 0, 0},
+ {19, 0, 1592, 1336, 0, 92, 175, 0, 171, 0, 0, 0},
+ {19, 0, 1592, 1336, 0, 92, 175, 0, 171, 0, 0, 0},
+ {19, 0, 1592, 1336, 0, 92, 175, 0, 171, 0, 0, 0},
+ {19, 0, 1592, 1336, 0, 92, 175, 0, 171, 0, 0, 0},
+ {19, 0, 1592, 1336, 0, 92, 175, 0, 171, 0, 0, 0},
+ {19, 0, 1592, 1336, 0, 92, 175, 0, 171, 0, 0, 0},
+ {18, 32, 764, 448, 0, 55, 150, 0, 48, 10, 4, 4},
+ {35, 32, 0, 0, 0, 56, 151, 0, 112, 0, 0, 0},
+ {36, 32, 0, 0, 0, 105, 142, 0, 155, 0, 0, 0},
+ {32, 32, 0, 0, 0, 91, 190, 0, 98, 0, 0, 0},
+ {31, 32, 0, 0, 0, 90, 189, 0, 171, 0, 0, 0},
+ {31, 32, 0, 0, 0, 90, 189, 0, 171, 0, 0, 0},
+ {31, 32, 0, 0, 0, 90, 189, 0, 171, 0, 0, 0},
+ {31, 32, 0, 0, 0, 79, 172, 0, 18, 0, 0, 0},
+ {21, 50, 664, 400, 0, 76, 171, 2, 74, 0, 4, 4},
+ {21, 50, 892, 428, 0, 76, 171, 2, 74, 0, 4, 4},
+ {9, 51, 904, 936, 0, 51, 145, 35, 5, 0, 0, 0},
+ {9, 51, 872, 840, 0, 51, 145, 36, 5, 0, 0, 0},
+ {9, 51, 1432, 344, 0, 51, 145, 37, 5, 0, 0, 0},
+ {9, 51, 664, 472, 0, 51, 145, 38, 5, 0, 0, 0},
+ {10, 51, 1368, 1464, 0, 80, 146, 39, 147, 0, 0, 0},
+ {10, 51, 1416, 1624, 0, 80, 146, 40, 147, 0, 0, 0},
+ {10, 51, 1752, 120, 0, 80, 146, 41, 147, 0, 0, 0},
+ {10, 51, 984, 408, 0, 80, 146, 42, 147, 0, 0, 0},
+ {14, 52, 856, 376, 0, 82, 174, 8, 73, 0, 0, 0},
+ {14, 52, 808, 664, 0, 82, 174, 9, 73, 0, 0, 0},
+ {14, 52, 440, 568, 0, 82, 174, 10, 73, 0, 0, 0},
+ {14, 52, 392, 776, 0, 82, 174, 11, 73, 0, 0, 0},
+ {21, 4, 240, 384, 0, 79, 172, 0, 18, 0, 2, 2},
+ {23, 4, 636, 268, 0, 77, 173, 0, 74, 0, 4, 4},
+ {22, 4, 900, 320, 0, 78, 179, 0, 60, 0, 4, 4},
+ {14, 4, 788, 264, 0, 75, 170, 0, 171, 0, 2, 2},
+ {14, 4, 1088, 264, 0, 75, 170, 0, 171, 0, 6, 6},
+ {24, 19, 728, 396, 0, 65, 181, 47, 146, 0, 6, 6},
+ {24, 21, -20, -20, 0, 66, 182, 0, 146, 0, 4, 4},
+ {25, 19, 372, 464, 0, 67, 183, 73, 146, 0, 2, 2},
+ {26, 5, 564, 476, 27, 53, 149, 1, 5, 0, 4, 4},
+ {27, 31, 868, 344, 0, 81, 180, 0, 171, 0, 4, 4},
+ {28, 73, 568, 380, 0, 83, 176, 30, 120, 0, 4, 4},
+ {14, 7, 808, 480, 0, 82, 174, 9, 73, 0, 0, 0},
+ {29, 10, 508, 432, 0, 84, 186, 6, 112, 0, 4, 4},
+ {33, 10, 676, 420, 0, 86, 184, 6, 171, 0, 4, 4},
+ {30, 10, 388, 452, 0, 88, 185, 6, 171, 0, 4, 4},
+ {30, 10, 608, 444, 0, 89, 185, 6, 171, 0, 4, 4},
+ {31, 10, 192, 468, 0, 90, 189, 6, 171, 0, 4, 4},
+ {31, 10, 772, 432, 0, 90, 189, 6, 171, 0, 4, 4},
+ {14, 10, 1340, 444, 0, 87, 188, 6, 171, 0, 4, 4},
+ {20, 18, 808, 360, 7, 60, 154, 64, 88, 0, 4, 4},
+ {34, 49, 1128, 1256, 0, 96, 191, 16, 35, 0, 4, 4},
+ {34, 49, 1384, 792, 0, 93, 192, 17, 66, 0, 4, 4},
+ {24, 21, 0, -40, 0, 65, 181, 50, 146, 0, 6, 6},
+ {3, 21, 0, -40, 0, 64, 158, 49, 112, 0, 0, 0},
+ {17, 21, 0, -40, 0, 62, 157, 74, 48, 0, 0, 0},
+ {17, 21, 0, -40, 0, 62, 157, 74, 49, 0, 0, 0},
+ {17, 21, 0, -40, 0, 62, 157, 74, 50, 0, 0, 0},
+ {12, 244, 1056, 504, 0, 107, 167, 21, 124, 0, 6, 6},
+ {8, 33, 248, 440, 0, 68, 169, 14, 112, 0, 0, 0},
+ {11, 23, 308, 424, 0, 106, 166, 6, 48, 0, 2, 2},
+ {17, 2, 1864, 1336, 0, 58, 153, 21, 49, 0, 0, 0},
+ {17, 2, 760, 216, 0, 58, 153, 22, 49, 0, 0, 0},
+ {44, 29, 0, 0, 0, 72, 159, 0, 112, 0, 0, 0},
+ {45, 29, 0, 0, 0, 71, 163, 0, 146, 0, 6, 6},
+ {45, 29, 0, 0, 0, 71, 163, 0, 124, 0, 2, 2},
+ {45, 29, 0, 0, 0, 71, 163, 0, 169, 0, 0, 0},
+ {7, 29, 0, 0, 0, 69, 164, 0, 4, 0, 0, 0},
+ {7, 29, 0, 0, 0, 70, 165, 0, 4, 0, 0, 0},
+ {7, 257, 552, 408, 0, 70, 165, 0, 4, 0, 2, 2},
+ {7, 29, 0, 0, 0, 70, 165, 0, 4, 0, 0, 0},
+ {7, 29, 0, 0, 0, 70, 165, 0, 4, 0, 0, 0},
+ {7, 257, 712, 380, 0, 69, 164, 0, 4, 0, 4, 4},
+ {7, 29, 0, 0, 0, 69, 164, 0, 4, 0, 0, 0},
+ {7, 29, 0, 0, 0, 69, 164, 0, 4, 0, 0, 0},
+ {7, 29, 0, 0, 0, 69, 164, 0, 4, 0, 0, 0},
+ {7, 29, 0, 0, 0, 69, 164, 0, 4, 0, 0, 0},
+ {7, 0, 0, 0, 0, 69, 164, 0, 4, 0, 0, 0},
+ {7, 29, 0, 0, 0, 70, 165, 0, 4, 0, 0, 0},
+ {47, 30, 0, 0, 0, 102, 199, 1, 186, 0, 0, 0},
+ {48, 69, 0, 0, 0, 109, 202, 35, 26, 0, 0, 0},
+ {49, 69, 0, 0, 0, 109, 202, 35, 26, 0, 0, 0},
+ {50, 69, 0, 0, 0, 111, 203, 16, 67, 0, 0, 0},
+ {51, 20, 0, 0, 0, 112, 204, 15, 26, 0, 0, 0},
+ {50, 20, 0, 0, 0, 111, 203, 14, 67, 0, 0, 0},
+ {49, 20, 0, 0, 0, 109, 202, 35, 26, 0, 0, 0},
+ {48, 256, 0, 0, 0, 109, 202, 35, 26, 0, 0, 0},
+ {21, 32, 0, 0, 0, 76, 171, 0, 171, 0, 0, 0},
+ {21, 32, 0, 0, 0, 76, 171, 0, 171, 0, 0, 0},
+ {21, 32, 0, 0, 0, 76, 171, 0, 171, 0, 0, 0},
+ {52, 15, 152, 400, 0, 108, 168, 19, 48, 10, 2, 2},
+ {47, 251, 640, 360, 0, 113, 205, 5, 186, 10, 2, 2},
+ {41, 75, 152, 400, 0, 100, 197, 5, 81, 0, 0, 0},
+ {44, 9, 0, 0, 0, 73, 160, 54, 112, 0, 0, 0},
+ {0, 22, -20, -20, 0, 118, 209, 0, 171, 0, 0, 0},
+ {1, 22, 0, 0, 0, 119, 210, 0, 171, 0, 0, 0},
+ {0, 22, -20, -20, 0, 118, 209, 0, 171, 0, 0, 0},
+ {1, 22, 0, 0, 0, 119, 210, 0, 171, 0, 0, 0},
+ {53, 42, 640, 400, 0, 104, 201, 8, 141, 0, 0, 0},
+ {54, 21, -20, -20, 0, 120, 211, 48, 238, 0, 0, 0},
+ {0, 4, -20, -20, 0, 42, 140, 0, 1, 0, 0, 0},
+ {26, 5, -20, -20, 27, 52, 148, 1, 5, 0, 4, 4},
+ {36, 4, -20, -20, 0, 116, 207, 0, 155, 0, 0, 0},
+ {36, 0, -20, -20, 0, 117, 208, 0, 155, 0, 0, 0},
+ {46, 252, -20, -20, 0, 74, 162, 29, 34, 0, 0, 0},
+ {0, 32, -20, -20, 0, 41, 137, 0, 1, 0, 0, 0},
+ {0, 259, -20, -20, 0, 44, 138, 0, 1, 0, 0, 0},
+ {0, 5, -20, -20, 0, 43, 139, 0, 1, 0, 0, 0},
+ {0, 31, -20, -20, 0, 39, 136, 0, 1, 0, 0, 0},
+ {0, 252, -20, -20, 0, 39, 136, 0, 1, 0, 0, 0},
+ {0, 15, -20, -20, 0, 39, 136, 0, 1, 0, 0, 0},
+ {0, 20, -20, -20, 0, 39, 136, 0, 1, 0, 0, 0},
+ {0, 25, -20, -20, 0, 39, 136, 0, 1, 0, 0, 0},
+ {0, 272, -20, -20, 0, 40, 141, 0, 1, 0, 0, 0},
+ {0, 50, -20, -20, 0, 39, 136, 0, 1, 0, 0, 0},
+ {50, 71, -20, -20, 0, 111, 203, 0, 67, 0, 0, 0},
+ {50, 274, -20, -20, 0, 111, 203, 0, 67, 0, 0, 0},
+ {50, 274, -20, -20, 0, 110, 212, 0, 171, 0, 0, 0},
+ {50, 274, -20, -20, 0, 110, 212, 0, 171, 0, 0, 0},
+ {50, 274, -20, -20, 0, 110, 212, 0, 171, 0, 0, 0},
+ {57, 272, 909, 909, 48, 121, 213, 0, 171, 0, 0, 0},
+ {58, 15, -20, -20, 0, 122, 214, 0, 171, 0, 0, 0},
+ {37, 246, -20, -20, 0, 97, 194, 0, 141, 0, 0, 0},
+ {38, 246, -20, -20, 0, 98, 195, 0, 27, 0, 0, 0},
+ {59, 246, -20, -20, 0, 103, 200, 0, 26, 0, 0, 0},
+ {41, 245, -20, -20, 0, 100, 197, 0, 81, 0, 0, 0},
+ {47, 250, 640, 360, 0, 114, 205, 0, 186, 10, 2, 2},
+ {0, 278, -20, -20, 0, 40, 141, 0, 1, 0, 0, 0},
+ {0, 272, -20, -20, 0, 40, 141, 0, 1, 0, 0, 0},
+ {41, 77, -20, -20, 0, 100, 197, 24, 81, 0, 0, 0},
+ {37, 261, -20, -20, 0, 97, 194, 0, 141, 0, 0, 0},
+ {38, 261, -20, -20, 0, 98, 195, 0, 27, 0, 0, 0},
+ {39, 261, -20, -20, 0, 99, 196, 0, 5, 0, 0, 0},
+ {39, 261, -20, -20, 0, 99, 196, 0, 5, 0, 0, 0},
+ {39, 261, -20, -20, 0, 99, 196, 0, 5, 0, 0, 0},
+ {39, 261, -20, -20, 0, 99, 196, 0, 5, 0, 0, 0},
+ {59, 279, -20, -20, 0, 103, 200, 0, 26, 0, 0, 0},
+ {38, 279, -20, -20, 0, 98, 195, 0, 27, 0, 0, 0},
+ {42, 77, -20, -20, 0, 101, 198, 25, 171, 0, 0, 0},
+ {59, 281, -20, -20, 0, 103, 200, 26, 26, 0, 0, 0},
+ {59, 279, -20, -20, 0, 123, 215, 0, 1, 0, 0, 0},
+ {59, 279, -20, -20, 0, 123, 215, 0, 132, 0, 0, 0},
+ {59, 279, -20, -20, 0, 123, 215, 0, 161, 0, 0, 0},
+ {54, 279, -20, -20, 0, 120, 211, 0, 133, 0, 6, 6},
+ {44, 9, -20, -20, 0, 124, 161, 0, 171, 0, 6, 6},
+ {7, 255, 588, 252, 0, 70, 165, 0, 3, 0, 2, 2},
+ {7, 255, 696, 252, 0, 70, 165, 0, 5, 0, 6, 6},
+ {36, 4, 0, 0, 0, 105, 142, 0, 155, 0, 0, 0},
+ {44, 272, 1124, 1124, 120, 72, 159, 0, 112, 0, 0, 0},
+ {7, 272, 1124, 1108, 120, 70, 165, 0, 4, 0, 0, 0},
+ {7, 272, 1108, 1124, 120, 70, 165, 0, 4, 0, 0, 0},
+ {29, 288, 508, 432, 0, 85, 187, 0, 112, 0, 4, 4},
+ {29, 0, 508, 432, 0, 84, 186, 0, 99, 0, 4, 4},
+ {29, 0, 508, 432, 0, 84, 186, 0, 98, 0, 4, 4},
+ {29, 0, 508, 432, 0, 84, 186, 0, 104, 0, 4, 4},
+ {29, 0, 508, 432, 0, 84, 186, 0, 99, 0, 4, 4},
+ {36, 288, 0, 0, 0, 105, 142, 0, 155, 0, 0, 0},
+ {1, 27, -20, -20, 0, 47, 178, 0, 132, 0, 0, 0},
+ {1, 252, -20, -20, 0, 47, 178, 0, 132, 0, 0, 0},
+ {1, 25, -20, -20, 0, 47, 178, 0, 132, 0, 0, 0},
+ {1, 259, -20, -20, 0, 47, 178, 0, 132, 0, 0, 0},
+ {1, 279, -20, -20, 0, 47, 178, 0, 132, 0, 0, 0},
+ {1, 273, -20, -20, 0, 47, 178, 0, 132, 0, 0, 0},
+ {1, 26, -20, -20, 0, 8, 178, 0, 171, 0, 0, 0},
+ {1, 0, -20, -20, 0, 0, 0, 0, 50, 0, 0, 0},
+ {1, 0, -20, -20, 0, 0, 0, 0, 82, 0, 0, 0},
+ {1, 0, -20, -20, 0, 0, 0, 0, 35, 0, 0, 0},
+ {9, 74, -20, -20, 0, 51, 145, 0, 5, 0, 0, 0}
+};
+
+} // End of namespace Saga
diff --git a/saga/actordata.h b/saga/actordata.h
new file mode 100644
index 0000000000..9fc4c4db41
--- /dev/null
+++ b/saga/actordata.h
@@ -0,0 +1,62 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Actor data table header file
+
+ Notes:
+*/
+
+#ifndef SAGA_ACTORDATA_H
+#define SAGA_ACTORDATA_H
+
+namespace Saga {
+
+typedef struct R_ACTORTABLE_tag {
+
+ int name_index;
+ int unknown1;
+ int unknown2;
+ int unknown3;
+ int unknown4;
+ int spritelist_rn;
+ int spriteindex_rn;
+ int unknown5;
+ unsigned char color;
+ unsigned char unknown6;
+ unsigned char unknown7;
+ unsigned char unknown8;
+
+} R_ACTORTABLE;
+
+#define R_ACTORCOUNT 181
+
+extern int ActorOrientationLUT[];
+extern R_ACTORTABLE ActorTable[R_ACTORCOUNT];
+
+} // End of namespace Saga
+
+#endif /* R_ACTORDATA_H */
+
+/* end "r_actordata.h" */
diff --git a/saga/animation.cpp b/saga/animation.cpp
new file mode 100644
index 0000000000..70f6d8dac0
--- /dev/null
+++ b/saga/animation.cpp
@@ -0,0 +1,1192 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Background animation management module
+
+ Notes:
+*/
+
+#include "reinherit.h"
+
+#include "yslib.h"
+
+/*
+ * Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "cvar_mod.h"
+#include "console_mod.h"
+#include "game_mod.h"
+#include "events_mod.h"
+#include "render_mod.h"
+
+/*
+ * Begin module
+\*--------------------------------------------------------------------------*/
+#include "animation_mod.h"
+#include "animation.h"
+
+namespace Saga {
+
+static R_ANIMINFO AnimInfo;
+
+int ANIM_Register(void)
+{
+ CVAR_RegisterFunc(CF_anim_info, "anim_info", NULL, R_CVAR_NONE, 0, 0);
+
+ return R_SUCCESS;
+}
+
+int ANIM_Init(void)
+{
+
+ AnimInfo.anim_limit = R_MAX_ANIMATIONS;
+ AnimInfo.anim_count = 0;
+
+ AnimInfo.initialized = 1;
+
+ return R_SUCCESS;
+}
+
+int ANIM_Shutdown(void)
+{
+ uint i;
+
+ for (i = 0; i < R_MAX_ANIMATIONS; i++) {
+
+ free(AnimInfo.anim_tbl[i]);
+ }
+
+ AnimInfo.initialized = 0;
+
+ return R_SUCCESS;
+}
+
+int
+ANIM_Load(const uchar * anim_resdata,
+ size_t anim_resdata_len, uint * anim_id_p)
+{
+ R_ANIMATION *new_anim;
+
+ uint anim_id = 0;
+ uint i;
+
+ if (!AnimInfo.initialized) {
+ return R_FAILURE;
+ }
+
+ /* Find an unused animation slot
+ * \*------------------------------------------------------------- */
+ for (i = 0; i < R_MAX_ANIMATIONS; i++) {
+
+ if (AnimInfo.anim_tbl[i] == NULL) {
+
+ anim_id = i;
+ break;
+ }
+ }
+
+ if (i == R_MAX_ANIMATIONS) {
+ return R_FAILURE;
+ }
+
+ new_anim = (R_ANIMATION *)malloc(sizeof *new_anim);
+ if (new_anim == NULL) {
+ R_printf(R_STDERR, "Error: Allocation failure.\n");
+
+ return R_MEM;
+ }
+
+ new_anim->resdata = anim_resdata;
+ new_anim->resdata_len = anim_resdata_len;
+
+ if (GAME_GetGameType() == R_GAMETYPE_ITE) {
+
+ if (ANIM_GetNumFrames(anim_resdata,
+ &new_anim->n_frames) != R_SUCCESS) {
+
+ R_printf(R_STDERR,
+ "Error: Couldn't get animation frame count.\n");
+
+ return R_FAILURE;
+ }
+
+ /* Cache frame offsets
+ * \*------------------------------------------------------------- */
+ new_anim->frame_offsets = (size_t *)malloc(new_anim->n_frames *
+ sizeof *new_anim->frame_offsets);
+ if (new_anim->frame_offsets == NULL) {
+ R_printf(R_STDERR, "Error: Allocation failure.\n");
+
+ return R_MEM;
+ }
+
+ for (i = 0; i < new_anim->n_frames; i++) {
+
+ ANIM_GetFrameOffset(anim_resdata,
+ i + 1, &new_anim->frame_offsets[i]);
+ }
+ } else {
+ new_anim->cur_frame_p = anim_resdata + SAGA_FRAME_HEADER_LEN;
+ new_anim->cur_frame_len =
+ anim_resdata_len - SAGA_FRAME_HEADER_LEN;
+
+ ANIM_GetNumFrames(anim_resdata, &new_anim->n_frames);
+ }
+
+ /* Set animation data
+ * \*------------------------------------------------------------- */
+ new_anim->current_frame = 1;
+ new_anim->end_frame = new_anim->n_frames;
+ new_anim->stop_frame = new_anim->end_frame;
+
+ new_anim->frame_time = R_DEFAULT_FRAME_TIME;
+ new_anim->flags = 0;
+ new_anim->play_flag = 0;
+ new_anim->link_flag = 0;
+ new_anim->link_id = 0;
+
+ AnimInfo.anim_tbl[anim_id] = new_anim;
+
+ *anim_id_p = anim_id;
+
+ AnimInfo.anim_count++;
+
+ return R_SUCCESS;
+}
+
+int ANIM_Link(uint anim_id1, uint anim_id2)
+{
+ R_ANIMATION *anim1;
+ R_ANIMATION *anim2;
+
+ if ((anim_id1 >= AnimInfo.anim_count) ||
+ (anim_id2 >= AnimInfo.anim_count)) {
+
+ return R_FAILURE;
+ }
+
+ anim1 = AnimInfo.anim_tbl[anim_id1];
+ anim2 = AnimInfo.anim_tbl[anim_id2];
+
+ if ((anim1 == NULL) || (anim2 == NULL)) {
+ return R_FAILURE;
+ }
+
+ anim1->link_id = anim_id2;
+ anim1->link_flag = 1;
+
+ anim2->frame_time = anim1->frame_time;
+
+ return R_SUCCESS;
+}
+
+int ANIM_Play(uint anim_id, int vector_time)
+{
+
+ R_EVENT event;
+ R_ANIMATION *anim;
+ R_ANIMATION *link_anim;
+ uint link_anim_id;
+
+ R_BUFFER_INFO buf_info;
+
+ uchar *display_buf;
+
+ const uchar *nextf_p;
+ size_t nextf_len;
+
+ uint frame;
+ int result;
+
+ R_GAME_DISPLAYINFO disp_info;
+
+ if (anim_id >= AnimInfo.anim_count) {
+
+ return R_FAILURE;
+ }
+
+ GAME_GetDisplayInfo(&disp_info);
+
+ RENDER_GetBufferInfo(&buf_info);
+ display_buf = buf_info.r_bg_buf;
+
+ anim = AnimInfo.anim_tbl[anim_id];
+ if (anim == NULL) {
+
+ return R_FAILURE;
+ }
+
+ if (anim->play_flag) {
+
+ frame = anim->current_frame;
+
+ if (GAME_GetGameType() == R_GAMETYPE_ITE) {
+
+ result = ITE_DecodeFrame(anim->resdata,
+ anim->frame_offsets[frame - 1],
+ display_buf,
+ disp_info.logical_w * disp_info.logical_h);
+
+ if (result != R_SUCCESS) {
+
+ R_printf(R_STDERR,
+ "ANIM_Play: Error decoding frame %u",
+ anim->current_frame);
+
+ anim->play_flag = 0;
+ return R_FAILURE;
+ }
+ } else {
+
+ if (anim->cur_frame_p == NULL) {
+ R_printf(R_STDERR,
+ "ANIM_Play: Frames exhausted.\n");
+
+ return R_FAILURE;
+ }
+
+ result = IHNM_DecodeFrame(display_buf,
+ disp_info.logical_w *
+ disp_info.logical_h,
+ anim->cur_frame_p,
+ anim->cur_frame_len, &nextf_p, &nextf_len);
+
+ if (result != R_SUCCESS) {
+
+ R_printf(R_STDERR,
+ "ANIM_Play: Error decoding frame %u",
+ anim->current_frame);
+
+ anim->play_flag = 0;
+ return R_FAILURE;
+ }
+
+ anim->cur_frame_p = nextf_p;
+ anim->cur_frame_len = nextf_len;
+ }
+
+ anim->current_frame++;
+ }
+
+ anim->play_flag = 1;
+
+ if (anim->current_frame > anim->n_frames) {
+
+ /* Animation done playing */
+
+ if (anim->link_flag) {
+
+ /* If this animation has a link, follow it */
+ anim->play_flag = 0;
+ anim->current_frame = 1;
+
+ link_anim_id = anim->link_id;
+ link_anim = AnimInfo.anim_tbl[link_anim_id];
+
+ if (link_anim != NULL) {
+
+ link_anim->current_frame = 1;
+ link_anim->play_flag = 1;
+ }
+
+ anim_id = link_anim_id;
+ } else if (anim->flags & ANIM_LOOP) {
+
+ /* Loop animation */
+ anim->current_frame = 1;
+
+ anim->cur_frame_p =
+ anim->resdata + SAGA_FRAME_HEADER_LEN;
+ anim->cur_frame_len =
+ anim->resdata_len - SAGA_FRAME_HEADER_LEN;
+ } else {
+
+ /* No link, stop playing */
+ anim->current_frame = anim->n_frames;
+ anim->play_flag = 0;
+
+ if (anim->flags & ANIM_ENDSCENE) {
+
+ /* This animation ends the scene */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_SCENE_EVENT;
+ event.op = EVENT_END;
+ event.time = anim->frame_time + vector_time;
+
+ EVENT_Queue(&event);
+ }
+ return R_SUCCESS;
+ }
+ }
+
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_ANIM_EVENT;
+ event.op = EVENT_FRAME;
+ event.param = anim_id;
+ event.time = anim->frame_time + vector_time;
+
+ EVENT_Queue(&event);
+
+ return R_SUCCESS;
+}
+
+int ANIM_Reset(void)
+{
+ uint i;
+
+ for (i = 0; i < R_MAX_ANIMATIONS; i++) {
+
+ ANIM_Free(i);
+ }
+
+ AnimInfo.anim_count = 0;
+
+ return R_SUCCESS;
+}
+
+int ANIM_SetFlag(uint anim_id, uint flag)
+{
+ R_ANIMATION *anim;
+
+ if (anim_id > AnimInfo.anim_count) {
+
+ return R_FAILURE;
+ }
+
+ anim = AnimInfo.anim_tbl[anim_id];
+ if (anim == NULL) {
+
+ return R_FAILURE;
+ }
+
+ anim->flags |= flag;
+
+ return R_SUCCESS;
+}
+
+int ANIM_SetFrameTime(uint anim_id, int time)
+{
+ R_ANIMATION *anim;
+
+ if (anim_id > AnimInfo.anim_count) {
+
+ return R_FAILURE;
+ }
+
+ anim = AnimInfo.anim_tbl[anim_id];
+ if (anim == NULL) {
+
+ return R_FAILURE;
+ }
+
+ anim->frame_time = time;
+
+ return R_SUCCESS;
+}
+
+int ANIM_Free(uint anim_id)
+{
+ R_ANIMATION *anim;
+
+ if (anim_id > AnimInfo.anim_count) {
+
+ return R_FAILURE;
+ }
+
+ anim = AnimInfo.anim_tbl[anim_id];
+ if (anim == NULL) {
+
+ return R_FAILURE;
+ }
+
+ if (GAME_GetGameType() == R_GAMETYPE_ITE) {
+
+ free(anim->frame_offsets);
+ anim->frame_offsets = NULL;
+ }
+
+ free(anim);
+ AnimInfo.anim_tbl[anim_id] = NULL;
+ AnimInfo.anim_count--;
+
+ return R_SUCCESS;
+}
+
+int ANIM_GetNumFrames(const uchar * anim_resource, uint * n_frames)
+/*--------------------------------------------------------------------------*\
+ * The actual number of frames present in an animation resource is
+ * sometimes less than number present in the .nframes member of the
+ * animation header. For this reason, the function attempts to find
+ * the last valid frame number, which it returns via 'n_frames'
+\*--------------------------------------------------------------------------*/
+{
+ R_ANIMATION_HEADER ah;
+
+ size_t offset;
+ int magic;
+
+ int x;
+
+ const uchar *read_p = anim_resource;
+
+ if (!AnimInfo.initialized) {
+
+ return R_FAILURE;
+ }
+
+ ah.magic = ys_read_u16_le(read_p, &read_p);
+ ah.screen_w = ys_read_u16_le(read_p, &read_p);
+ ah.screen_h = ys_read_u16_le(read_p, &read_p);
+
+ ah.unknown06 = ys_read_u8(read_p, &read_p);
+ ah.unknown07 = ys_read_u8(read_p, &read_p);
+ ah.nframes = ys_read_u8(read_p, NULL);
+
+ if (GAME_GetGameType() == R_GAMETYPE_IHNM) {
+
+ *n_frames = ah.nframes;
+ }
+
+ if (ah.magic == 68) {
+
+ for (x = ah.nframes; x > 0; x--) {
+
+ if (ANIM_GetFrameOffset(anim_resource,
+ x, &offset) != R_SUCCESS) {
+
+ return R_FAILURE;
+ }
+
+ magic = *(anim_resource + offset);
+
+ if (magic == SAGA_FRAME_HEADER_MAGIC) {
+ *n_frames = x;
+
+ return R_SUCCESS;
+ }
+ }
+
+ return R_FAILURE;
+ }
+
+ return R_FAILURE;
+}
+
+int
+ITE_DecodeFrame(const uchar * resdata,
+ size_t frame_offset, uchar * buf, size_t buf_len)
+{
+
+ R_ANIMATION_HEADER ah;
+ R_FRAME_HEADER fh;
+
+ const uchar *read_p = resdata;
+ uchar *write_p;
+
+ uint magic;
+
+ uint x_start;
+ uint y_start;
+ ulong screen_w;
+ ulong screen_h;
+
+ int mark_byte;
+ uchar data_byte;
+ int new_row;
+
+ uint control_ch;
+ uint param_ch;
+
+ uint runcount;
+ int x_vector;
+
+ uint i;
+
+ if (!AnimInfo.initialized) {
+
+ return R_FAILURE;
+ }
+
+ /* Read animation header
+ * \*------------------------------------------------------------- */
+ ah.magic = ys_read_u16_le(read_p, &read_p);
+ ah.screen_w = ys_read_u16_le(read_p, &read_p);
+ ah.screen_h = ys_read_u16_le(read_p, &read_p);
+ ah.unknown06 = ys_read_u8(read_p, &read_p);
+ ah.unknown07 = ys_read_u8(read_p, &read_p);
+ ah.nframes = ys_read_u8(read_p, &read_p);
+ ah.flags = ys_read_u8(read_p, &read_p);
+ ah.unknown10 = ys_read_u8(read_p, &read_p);
+ ah.unknown11 = ys_read_u8(read_p, &read_p);
+
+ screen_w = ah.screen_w;
+ screen_h = ah.screen_h;
+
+ if ((screen_w * screen_h) > buf_len) {
+ /* Buffer argument is too small to hold decoded frame, abort. */
+ R_printf(R_STDERR,
+ "ITE_DecodeFrame: Buffer size inadequate.\n");
+
+ return R_FAILURE;
+ }
+
+ /* Read frame header
+ * \*------------------------------------------------------------- */
+ read_p = resdata + frame_offset;
+
+ /* Check for frame magic byte */
+ magic = ys_read_u8(read_p, &read_p);
+ if (magic != SAGA_FRAME_HEADER_MAGIC) {
+
+ R_printf(R_STDERR, "ITE_DecodeFrame: Invalid frame offset.\n");
+
+ return R_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 = ys_read_u16_be(read_p, &read_p);
+ fh.y_start = ys_read_u8(read_p, &read_p);
+ read_p++; /* Skip pad byte */
+ fh.x_pos = ys_read_u16_be(read_p, &read_p);
+ fh.y_pos = ys_read_u16_be(read_p, &read_p);
+ fh.width = ys_read_u16_be(read_p, &read_p);
+ fh.height = ys_read_u16_be(read_p, &read_p);
+
+ x_start = fh.x_start;
+ y_start = fh.y_start;
+
+ /* Setup write pointer to the draw origin
+ * \*------------------------------------------------------------- */
+ write_p = (buf + (y_start * screen_w) + x_start);
+
+ /* Begin RLE decompression to output buffer
+ * \*------------------------------------------------------------- */
+ do {
+
+ mark_byte = ys_read_u8(read_p, &read_p);
+
+ switch (mark_byte) {
+
+ case 0x10: /* Long Unencoded Run */
+
+ runcount = ys_read_s16_be(read_p, &read_p);
+
+ for (i = 0; i < runcount; i++) {
+ if (*read_p != 0) {
+ *write_p = *read_p;
+ }
+ write_p++;
+ read_p++;
+ }
+ continue;
+ break;
+
+ case 0x20: /* Long encoded run */
+
+ runcount = ys_read_s16_be(read_p, &read_p);
+
+ data_byte = *read_p++;
+
+ for (i = 0; i < runcount; i++) {
+ *write_p++ = data_byte;
+ }
+ continue;
+ break;
+
+ case 0x2F: /* End of row */
+
+ x_vector = ys_read_s16_be(read_p, &read_p);
+ new_row = ys_read_u8(read_p, &read_p);
+
+ /* Set write pointer to the new draw origin */
+ write_p = buf + ((y_start + new_row) * screen_w)
+ + x_start + x_vector;
+ continue;
+ break;
+
+ case 0x30: /* Reposition command */
+
+ x_vector = ys_read_s16_be(read_p, &read_p);
+
+ write_p += x_vector;
+ continue;
+ break;
+
+ case 0x3F: /* End of frame marker */
+
+ return R_SUCCESS;
+ break;
+
+ default:
+ break;
+ }
+
+ /* Mask all but two high order control bits */
+ control_ch = mark_byte & 0xC0U;
+ param_ch = mark_byte & 0x3FU;
+
+ switch (control_ch) {
+
+ case 0xC0: /* 1100 0000 */
+
+ /* Run of empty pixels */
+ runcount = param_ch + 1;
+ write_p += runcount;
+ continue;
+ break;
+
+ case 0x80: /* 1000 0000 */
+
+ /* Run of compressed data */
+ runcount = param_ch + 1;
+
+ data_byte = *read_p++;
+
+ for (i = 0; i < runcount; i++) {
+ *write_p++ = data_byte;
+ }
+ continue;
+ break;
+
+ case 0x40: /* 0100 0000 */
+
+ /* Uncompressed run */
+ runcount = param_ch + 1;
+
+ for (i = 0; i < runcount; i++) {
+ if (*read_p != 0) {
+ *write_p = *read_p;
+ }
+ write_p++;
+ read_p++;
+ }
+ continue;
+ break;
+
+ default:
+ /* Unknown marker found - abort */
+
+ R_printf(R_STDERR,
+ "ITE_DecodeFrame: Invalid RLE marker "
+ "encountered.\n");
+
+ return R_FAILURE;
+ break;
+ }
+
+ } while (mark_byte != 63); /* end of frame marker */
+
+ return R_SUCCESS;
+}
+
+int
+IHNM_DecodeFrame(uchar * decode_buf,
+ size_t decode_buf_len,
+ const uchar * thisf_p,
+ size_t thisf_len, const uchar ** nextf_p, size_t * nextf_len)
+{
+
+ int in_ch;
+
+ int decoded_data = 0;
+ int cont_flag = 1;
+
+ int control_ch;
+ int param_ch;
+
+ uchar data_pixel;
+
+ int x_origin = 0;
+ int y_origin = 0;
+ int x_vector;
+ int new_row;
+
+ uint runcount;
+ uint c;
+
+ size_t in_ch_offset;
+
+ const uchar *inbuf_p = thisf_p;
+ size_t inbuf_remain = thisf_len;
+
+ uchar *outbuf_p = decode_buf;
+ uchar *outbuf_endp = (decode_buf + decode_buf_len) - 1;
+ size_t outbuf_remain = decode_buf_len;
+
+ R_GAME_DISPLAYINFO di;
+
+ GAME_GetDisplayInfo(&di);
+
+ *nextf_p = NULL;
+
+ for (; cont_flag; decoded_data = 1) {
+
+ in_ch_offset = (size_t) (inbuf_p - thisf_p);
+
+ in_ch = *inbuf_p++;
+ inbuf_remain--;
+
+ switch (in_ch) {
+
+ case 0x0F: /* 15: Frame header */
+ {
+ int param1;
+ int param2;
+ int param3;
+ int param4;
+ int param5;
+ int param6;
+
+ if (inbuf_remain < 13) {
+ R_printf(R_STDERR,
+ "0x%02X: Input buffer underrun.",
+ in_ch);
+
+ return R_FAILURE;
+ }
+
+ param1 = ys_read_u16_be(inbuf_p, &inbuf_p);
+ param2 = ys_read_u16_be(inbuf_p, &inbuf_p);
+ inbuf_p++; /* skip 1? */
+ param3 = ys_read_u16_be(inbuf_p, &inbuf_p);
+ param4 = ys_read_u16_be(inbuf_p, &inbuf_p);
+ param5 = ys_read_u16_be(inbuf_p, &inbuf_p);
+ param6 = ys_read_u16_be(inbuf_p, &inbuf_p);
+
+ inbuf_remain -= 13;
+
+ x_origin = param1;
+ y_origin = param2;
+
+ outbuf_p = decode_buf + x_origin +
+ (y_origin * di.logical_w);
+
+ if (outbuf_p > outbuf_endp) {
+
+ R_printf(R_STDERR,
+ "0x%02X: (0x%X) Invalid output position. "
+ "(x: %d, y: %d)\n",
+ in_ch,
+ in_ch_offset, x_origin, y_origin);
+
+ return R_FAILURE;
+ }
+
+ outbuf_remain = (outbuf_endp - outbuf_p) + 1;
+
+ continue;
+ }
+ break;
+
+ case 0x10: /* Long Unencoded Run */
+
+ runcount = ys_read_s16_be(inbuf_p, &inbuf_p);
+
+ if (inbuf_remain < runcount) {
+
+ R_printf(R_STDERR,
+ "0x%02X: Input buffer underrun.", in_ch);
+
+ return R_FAILURE;
+ }
+
+ if (outbuf_remain < runcount) {
+
+ R_printf(R_STDERR,
+ "0x%02X: Output buffer overrun.", in_ch);
+
+ return R_FAILURE;
+ }
+
+ for (c = 0; c < runcount; c++) {
+ if (*inbuf_p != 0) {
+ *outbuf_p = *inbuf_p;
+ }
+ outbuf_p++;
+ inbuf_p++;
+ }
+
+ inbuf_remain -= runcount;
+ outbuf_remain -= runcount;
+
+ continue;
+ break;
+
+ case 0x1F: /* 31: Unusued? */
+
+ if (inbuf_remain < 3) {
+
+ R_printf(R_STDERR,
+ "0x%02X: Input buffer underrun.", in_ch);
+
+ return R_FAILURE;
+ }
+
+ inbuf_p += 3;
+ inbuf_remain -= 3;
+
+ continue;
+ break;
+
+ case 0x20: /* Long compressed run */
+
+ if (inbuf_remain <= 3) {
+
+ R_printf(R_STDERR,
+ "0x%02X: Input buffer underrun.", in_ch);
+
+ return R_FAILURE;
+ }
+
+ runcount = ys_read_s16_be(inbuf_p, &inbuf_p);
+ data_pixel = *inbuf_p++;
+
+ for (c = 0; c < runcount; c++) {
+ *outbuf_p++ = data_pixel;
+ }
+
+ outbuf_remain -= runcount;
+ inbuf_remain -= 1;
+
+ continue;
+ break;
+
+ case 0x2F: /* End of row */
+
+ if (inbuf_remain <= 4) {
+ return R_FAILURE;
+ }
+
+ x_vector = ys_read_s16_be(inbuf_p, &inbuf_p);
+ new_row = ys_read_s16_be(inbuf_p, &inbuf_p);
+
+ outbuf_p =
+ decode_buf + ((y_origin + new_row) * di.logical_w)
+ + x_origin + x_vector;
+
+ inbuf_remain -= 4;
+ outbuf_remain = (outbuf_endp - outbuf_p) + 1;
+
+ continue;
+ break;
+
+ case 0x30: /* Reposition command */
+ if (inbuf_remain < 2) {
+ return R_FAILURE;
+ }
+
+ x_vector = ys_read_s16_be(inbuf_p, &inbuf_p);
+
+ if (((x_vector > 0)
+ && ((size_t) x_vector > outbuf_remain))
+ || (-x_vector > outbuf_p - decode_buf)) {
+
+ R_printf(R_STDERR,
+ "0x30: Invalid x_vector.\n");
+
+ return R_FAILURE;
+ }
+
+ outbuf_p += x_vector;
+ outbuf_remain -= x_vector;
+ inbuf_remain -= 2;
+
+ continue;
+ break;
+
+ case 0x3F: /* 68: Frame end marker */
+
+ printf("0x3F: Frame end marker\n");
+
+ if (decoded_data && inbuf_remain > 0) {
+
+ *nextf_p = inbuf_p;
+ *nextf_len = inbuf_remain;
+ } else {
+
+ *nextf_p = NULL;
+ *nextf_len = 0;
+ }
+
+ cont_flag = 0;
+ continue;
+ break;
+
+ default:
+ break;
+
+ } /* end switch() */
+
+ control_ch = in_ch & 0xC0;
+ param_ch = in_ch & 0x3f;
+
+ switch (control_ch) {
+
+ case 0xC0: /* Run of empty pixels */
+
+ runcount = param_ch + 1;
+
+ if (outbuf_remain < runcount) {
+ return R_FAILURE;
+ }
+
+ outbuf_p += runcount;
+ outbuf_remain -= runcount;
+
+ continue;
+ break;
+
+ case 0x80: /* Run of compressed data */
+
+ runcount = param_ch + 1;
+
+ if ((outbuf_remain < runcount) || (inbuf_remain <= 1)) {
+
+ return R_FAILURE;
+ }
+
+ data_pixel = *inbuf_p++;
+ inbuf_remain--;
+
+ for (c = 0; c < runcount; c++) {
+
+ *outbuf_p++ = data_pixel;
+ }
+
+ outbuf_remain -= runcount;
+
+ continue;
+ break;
+
+ case 0x40: /* Uncompressed run */
+
+ runcount = param_ch + 1;
+
+ if ((outbuf_remain < runcount) ||
+ (inbuf_remain < runcount)) {
+
+ return R_FAILURE;
+ }
+
+ for (c = 0; c < runcount; c++) {
+ if (*inbuf_p != 0) {
+ *outbuf_p = *inbuf_p;
+ }
+ outbuf_p++;
+ inbuf_p++;
+ }
+
+ inbuf_remain -= runcount;
+ outbuf_remain -= runcount;
+
+ continue;
+ break;
+
+ default:
+ break;
+ } /* end switch */
+
+ } /* end while() */
+
+ return R_SUCCESS;
+}
+
+int
+ANIM_GetFrameOffset(const uchar * resdata,
+ uint find_frame, size_t * frame_offset_p)
+{
+ R_ANIMATION_HEADER ah;
+
+ uint num_frames;
+ uint current_frame;
+
+ const uchar *read_p = resdata;
+ const uchar *search_ptr;
+
+ uchar mark_byte;
+ uint control;
+ uint runcount;
+
+ uint magic;
+
+ if (!AnimInfo.initialized) {
+
+ return R_FAILURE;
+ }
+
+ /* Read animation header
+ * \*------------------------------------------------------------- */
+ ah.magic = ys_read_u16_le(read_p, &read_p);
+ ah.screen_w = ys_read_u16_le(read_p, &read_p);
+ ah.screen_h = ys_read_u16_le(read_p, &read_p);
+ ah.unknown06 = ys_read_u8(read_p, &read_p);
+ ah.unknown07 = ys_read_u8(read_p, &read_p);
+ ah.nframes = ys_read_u8(read_p, &read_p);
+ ah.flags = ys_read_u8(read_p, &read_p);
+ ah.unknown10 = ys_read_u8(read_p, &read_p);
+ ah.unknown11 = ys_read_u8(read_p, &read_p);
+
+ num_frames = ah.nframes;
+
+ if ((find_frame < 1) || (find_frame > num_frames)) {
+
+ return R_FAILURE;
+ }
+
+ search_ptr = read_p;
+
+ for (current_frame = 1; current_frame < find_frame; current_frame++) {
+
+ magic = ys_read_u8(search_ptr, &search_ptr);
+
+ if (magic != SAGA_FRAME_HEADER_MAGIC) {
+
+ /* Frame sync failure. Magic Number not found */
+ return R_FAILURE;
+ }
+
+ search_ptr += SAGA_FRAME_HEADER_LEN;
+
+ /* 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 = *search_ptr;
+
+ switch (mark_byte) {
+
+ case 0x3F: /* End of frame marker */
+
+ search_ptr++;
+ continue;
+ break;
+
+ case 0x30: /* Reposition command */
+
+ search_ptr += 3;
+ continue;
+ break;
+
+ case 0x2F: /* End of row marker */
+
+ search_ptr += 4;
+ continue;
+ break;
+
+ case 0x20: /* Long compressed run marker */
+
+ search_ptr += 4;
+ continue;
+ break;
+
+ case 0x10: /* (16) 0001 0000 */
+ /* Long Uncompressed Run */
+ search_ptr++;
+ runcount =
+ ys_read_s16_be(search_ptr, &search_ptr);
+ search_ptr += runcount;
+ continue;
+ break;
+
+ default:
+ break;
+
+ }
+
+ /* Mask all but two high order (control) bits */
+ control = mark_byte & 0xC0;
+
+ switch (control) {
+
+ case 0xC0:
+ /* Run of empty pixels */
+ search_ptr++;
+ continue;
+ break;
+
+ case 0x80:
+ /* Run of compressed data */
+ search_ptr += 2; /* Skip data byte */
+ continue;
+ break;
+
+ case 0x40:
+ /* Uncompressed run */
+ search_ptr++;
+ runcount = (mark_byte & 0x3f) + 1;
+ search_ptr += runcount;
+ continue;
+ break;
+
+ default:
+ /* Encountered unknown RLE marker, abort */
+ return R_FAILURE;
+ break;
+
+ } /* end switch ( test_byte ) */
+
+ } while (mark_byte != 63); /* end of frame marker */
+
+ } /* end for( i = 0 ; i < find_frame ; i ++ ) */
+
+ *frame_offset_p = (search_ptr - resdata);
+
+ return R_SUCCESS;
+}
+
+static void CF_anim_info(int argc, char *argv[])
+{
+ uint anim_ct;
+ uint i;
+ uint idx;
+
+ YS_IGNORE_PARAM(argc);
+ YS_IGNORE_PARAM(argv);
+
+ anim_ct = AnimInfo.anim_count;
+
+ CON_Print("There are %d animations loaded:", anim_ct);
+
+ for (idx = 0, i = 0; i < anim_ct; idx++, i++) {
+
+ while (AnimInfo.anim_tbl[idx] == NULL) {
+ idx++;
+ }
+
+ CON_Print("%02d: Frames: %u Flags: %u",
+ i,
+ AnimInfo.anim_tbl[idx]->n_frames,
+ AnimInfo.anim_tbl[idx]->flags);
+ }
+
+ return;
+}
+
+} // End of namespace Saga
diff --git a/saga/animation.h b/saga/animation.h
new file mode 100644
index 0000000000..b448f75b10
--- /dev/null
+++ b/saga/animation.h
@@ -0,0 +1,139 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Background animation management module private header
+
+ Notes:
+*/
+
+#ifndef SAGA_ANIMATION_H_
+#define SAGA_ANIMATION_H_
+
+namespace Saga {
+
+#define R_MAX_ANIMATIONS 7
+#define R_DEFAULT_FRAME_TIME 140
+
+#define SAGA_FRAME_HEADER_MAGIC 15
+#define SAGA_FRAME_HEADER_LEN 12
+
+/* All animation resources begin with an ANIMATION_HEADER
+ * at 0x00, followed by a RLE code stream
+\*--------------------------------------------------------------------------*/
+
+typedef struct R_ANIMATION_HEADER_tag {
+
+ uint magic;
+
+ uint screen_w;
+ uint screen_h;
+
+ uint unknown06;
+ uint unknown07;
+
+ uint nframes;
+ uint flags;
+
+ uint unknown10;
+ uint unknown11;
+
+} R_ANIMATION_HEADER;
+
+/* A byte from the code stream of FRAME_HEADER_MAGIC signifies that a
+ * FRAME_HEADER structure follows
+\*--------------------------------------------------------------------------*/
+
+typedef struct R_FRAME_HEADER_tag {
+
+ int x_start;
+ int y_start;
+
+ int x_pos;
+ int y_pos;
+
+ int width;
+ int height;
+
+} R_FRAME_HEADER;
+
+/* Animation info array member */
+typedef struct R_ANIMATION_tag {
+
+ const uchar *resdata;
+ size_t resdata_len;
+
+ uint n_frames;
+ size_t *frame_offsets;
+
+ uint current_frame;
+ uint end_frame;
+ uint stop_frame;
+
+ const uchar *cur_frame_p;
+ size_t cur_frame_len;
+
+ int frame_time;
+
+ uint play_flag;
+ int link_flag;
+ uint link_id;
+
+ uint flags;
+
+} R_ANIMATION;
+
+typedef struct R_ANIMINFO_tag {
+
+ int initialized;
+
+ uint anim_count;
+ uint anim_limit;
+
+ R_ANIMATION *anim_tbl[R_MAX_ANIMATIONS];
+
+} R_ANIMINFO;
+
+int ANIM_GetNumFrames(const uchar * anim_resource, uint * n_frames);
+
+int
+ITE_DecodeFrame(const uchar * anim_resource,
+ size_t frame_offset, uchar * buf, size_t buf_len);
+
+int
+IHNM_DecodeFrame(uchar * decode_buf,
+ size_t decode_buf_len,
+ const uchar * thisf_p,
+ size_t thisf_len, const uchar ** nextf_p, size_t * nextf_len);
+
+int
+ANIM_GetFrameOffset(const uchar * anim_resource,
+ uint find_frame, size_t * frame_offset);
+
+static void CF_anim_info(int argc, char *argv[]);
+
+} // End of namespace Saga
+
+#endif /* R_ANIMATION_H_ */
+/* end "r_animation.h" */
diff --git a/saga/animation_mod.h b/saga/animation_mod.h
new file mode 100644
index 0000000000..6bb8a1fcd6
--- /dev/null
+++ b/saga/animation_mod.h
@@ -0,0 +1,67 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Background animation management module public header
+
+ Notes:
+*/
+
+#ifndef SAGA_ANIMATION_MOD_H__
+#define SAGA_ANIMATION_MOD_H__
+
+namespace Saga {
+
+enum ANIM_FLAGS {
+
+ ANIM_LOOP = 0x01,
+ ANIM_ENDSCENE = 0x80 /* When animation ends, dispatch scene end event */
+};
+
+int ANIM_Register(void);
+
+int ANIM_Init(void);
+
+int ANIM_Shutdown(void);
+
+int
+ANIM_Load(const uchar * anim_resdata,
+ size_t anim_resdata_len, uint * anim_id_p);
+
+int ANIM_Free(uint anim_id);
+
+int ANIM_Play(uint anim_id, int vector_time);
+
+int ANIM_Link(uint anim_id1, uint anim_id2);
+
+int ANIM_SetFlag(uint anim_id, uint flag);
+
+int ANIM_SetFrameTime(uint anim_id, int time);
+
+int ANIM_Reset(void);
+
+} // End of namespace Saga
+
+#endif /* R_ANIMATION_MOD_H__ */
+/* end "r_animation_mod.h__ */
diff --git a/saga/binread.cpp b/saga/binread.cpp
deleted file mode 100644
index 71d0ed83ba..0000000000
--- a/saga/binread.cpp
+++ /dev/null
@@ -1,151 +0,0 @@
-/* ScummVM - Scumm Interpreter
- * Copyright (C) 2003 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$
- *
- */
-
-#include "common/stdafx.h"
-
-#include "binread.h"
-
-namespace Saga {
-
-BinReader::BinReader() {
- _buf = NULL;
- _bufPtr = NULL;
- _bufEnd = NULL;
- _bufLen = 0;
-}
-
-BinReader::BinReader(const byte *buf, size_t buflen) {
- _buf = buf;
- _bufPtr = buf;
- _bufEnd = buf + buflen;
- _bufLen = buflen;
-}
-
-BinReader::~BinReader() {
-}
-
-void BinReader::setBuf(const byte *buf, size_t buflen) {
- _buf = buf;
- _bufPtr = buf;
- _bufEnd = buf + buflen;
- _bufLen = buflen;
-}
-
-void BinReader::skip(size_t skip_ct) {
- assert((_bufPtr + skip_ct) <= _bufEnd );
-
- _bufPtr += skip_ct;
-}
-
-unsigned int BinReader::readUint16LE() {
- assert((_bufPtr + 2) <= _bufEnd);
-
- unsigned int u16_le = ((unsigned int)_bufPtr[1] << 8) | _bufPtr[0];
-
- _bufPtr += 2;
-
- return u16_le;
-}
-
-unsigned int BinReader::readUint16BE() {
- assert((_bufPtr + 2) <= _bufEnd);
-
- unsigned int u16_be = ((unsigned int)_bufPtr[0] << 8) | _bufPtr[1];
-
- _bufPtr += 2;
-
- return u16_be;
-}
-
-int BinReader::readSint16LE() {
- assert((_bufPtr + 2) <= _bufEnd);
-
- unsigned int u16_le = ((unsigned int)_bufPtr[1] << 8) | _bufPtr[0];
-
- _bufPtr += 2;
-
- return u16_le;
-}
-
-int BinReader::readSint16BE() {
- assert((_bufPtr + 2) <= _bufEnd);
-
- unsigned int u16_be = ((unsigned int)_bufPtr[0] << 8) | _bufPtr[1];
-
- _bufPtr += 2;
-
- return u16_be;
-}
-
-
-uint32 BinReader::readUint32LE() {
- assert((_bufPtr + 4) <= _bufEnd);
-
- unsigned long u32_le = ((unsigned long)_bufPtr[3] << 24) |
- ((unsigned long)_bufPtr[2] << 16) |
- ((unsigned long)_bufPtr[1] << 8 ) |
- _bufPtr[0];
-
- _bufPtr += 4;
-
- return u32_le;
-}
-
-uint32 BinReader::readUint32BE() {
- assert((_bufPtr + 4) <= _bufEnd);
-
- unsigned long u32_be = ((unsigned long)_bufPtr[0] << 24) |
- ((unsigned long)_bufPtr[1] << 16) |
- ((unsigned long)_bufPtr[2] << 8 ) |
- _bufPtr[3];
-
- _bufPtr += 4;
-
- return u32_be;
-}
-
-int32 BinReader::readSint32LE() {
- assert((_bufPtr + 4) <= _bufEnd);
-
- unsigned long u32_le = ((unsigned long)_bufPtr[3] << 24) |
- ((unsigned long)_bufPtr[2] << 16) |
- ((unsigned long)_bufPtr[1] << 8 ) |
- _bufPtr[0];
-
- _bufPtr += 4;
-
- return u32_le;
-}
-
-int32 BinReader::readSint32BE() {
- assert((_bufPtr + 4) <= _bufEnd);
-
- unsigned long u32_be = ((unsigned long)_bufPtr[0] << 24) |
- ((unsigned long)_bufPtr[1] << 16) |
- ((unsigned long)_bufPtr[2] << 8 ) |
- _bufPtr[3];
-
- _bufPtr += 4;
-
- return u32_be;
-}
-
-} // End of namespace Saga
diff --git a/saga/binread.h b/saga/binread.h
deleted file mode 100644
index 7a4567df9b..0000000000
--- a/saga/binread.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/* ScummVM - Scumm Interpreter
- * Copyright (C) 2003 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_BINREAD_H
-#define SAGA_BINREAD_H
-
-#include <stddef.h>
-#include "common/scummsys.h"
-
-namespace Saga {
-
-class BinReader {
-
-protected:
-
- const byte *_buf;
- const byte *_bufPtr;
- const byte *_bufEnd;
- size_t _bufLen;
-
-public:
-
- BinReader();
- BinReader( const byte *buf, size_t buflen );
- virtual ~BinReader();
-
- void setBuf( const byte *buf, size_t buflen );
-
- size_t getOffset() const;
- bool setOffset( size_t offset );
- bool setROffset( ptrdiff_t offset );
- void skip( size_t skip_ct );
-
- bool setPtr( const byte *buf_pos );
- byte *getPtr() const;
-
- unsigned int readUint16LE();
- unsigned int readUint16BE();
- int readSint16LE();
- int readSint16BE();
- uint32 readUint32LE();
- uint32 readUint32BE();
- int32 readSint32LE();
- int32 readSint32BE();
-};
-
-} // End of namespace Saga
-
-#endif
-
-
-
-
-
-
diff --git a/saga/cmdline.cpp b/saga/cmdline.cpp
new file mode 100644
index 0000000000..6848230190
--- /dev/null
+++ b/saga/cmdline.cpp
@@ -0,0 +1,95 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Command line parser
+
+ Notes:
+
+*/
+
+#include "reinherit.h"
+
+namespace Saga {
+
+int R_ReadCommandLine(int argc, char **argv, R_EXECINFO * execinfo)
+{
+
+ int arg;
+ int intparam;
+
+ for (arg = 1; arg < argc; arg++) {
+
+ if (strcmp(argv[arg], "-scene") == 0) {
+ arg++;
+ if (arg <= argc) {
+ intparam = atoi(argv[arg]);
+ execinfo->start_scene = intparam;
+ if (intparam == 0) {
+ R_printf(R_STDERR,
+ "Error: Invalid parameter to '-scene'.\n");
+ return -1;
+ }
+ } else {
+ R_printf(R_STDERR,
+ "Error: '-scene' requires a parameter.\n");
+ return -1;
+ }
+ }
+
+ if (strcmp(argv[arg], "-gamedir") == 0) {
+ arg++;
+ if (arg <= argc) {
+
+ execinfo->game_dir = argv[arg];
+ } else {
+ R_printf(R_STDERR,
+ "Error: '-gamedir' requires a parameter.\n");
+ return -1;
+ }
+ }
+
+ if (strcmp(argv[arg], "-noverify") == 0) {
+ execinfo->no_verify = 1;
+ }
+
+ if (strcmp(argv[arg], "-nosound") == 0) {
+ execinfo->no_sound = 1;
+ }
+
+ if (strcmp(argv[arg], "-nomusic") == 0) {
+ execinfo->no_music = 1;
+ }
+
+ if (strcmp(argv[arg], "-windowed") == 0) {
+ execinfo->windowed = 1;
+ }
+
+ }
+
+ return 0;
+
+}
+
+} // End of namespace Saga
diff --git a/saga/console.cpp b/saga/console.cpp
new file mode 100644
index 0000000000..5310953f31
--- /dev/null
+++ b/saga/console.cpp
@@ -0,0 +1,567 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Console module
+
+ Notes:
+*/
+
+#include "reinherit.h"
+
+/*
+ Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "font_mod.h"
+#include "cvar_mod.h"
+#include "events_mod.h"
+#include "gfx_mod.h"
+
+/*
+ Begin module
+\*--------------------------------------------------------------------------*/
+#include "console_mod.h"
+#include "console.h"
+
+namespace Saga {
+
+static R_CONSOLEINFO ConInfo = {
+
+ 0,
+ R_CON_DEFAULTPOS,
+ R_CON_DEFAULTLINES,
+ R_CON_DEFAULTCMDS
+};
+
+static char InputBuf[R_CON_INPUTBUF_LEN];
+
+static R_CON_SCROLLBACK ConScrollback;
+static R_CON_SCROLLBACK ConHistory;
+
+static int CV_ConResize = R_CON_DEFAULTPOS;
+static int CV_ConDroptime = R_CON_DROPTIME;
+
+int CON_Register(void)
+{
+
+ CVAR_Register_I(&CV_ConResize, "con_h",
+ NULL, R_CVAR_NONE, 12, R_CON_DEFAULTPOS);
+
+ CVAR_Register_I(&CV_ConDroptime, "con_droptime",
+ NULL, R_CVAR_NONE, 0, 5000);
+
+ CVAR_Register_I(&ConInfo.line_max, "con_lines",
+ NULL, R_CVAR_NONE, 5, 5000);
+
+ return R_SUCCESS;
+}
+
+int CON_Init(void)
+{
+ return R_SUCCESS;
+}
+
+int CON_Shutdown(void)
+{
+
+ R_printf(R_STDOUT,
+ "CON_Shutdown(): Deleting console scrollback and command history.\n");
+
+ CON_DeleteScroll(&ConScrollback);
+ CON_DeleteScroll(&ConHistory);
+
+ return R_SUCCESS;
+}
+
+int CON_Activate(void)
+{
+ R_EVENT con_event;
+
+ if (ConInfo.active) {
+ return R_FAILURE;
+ }
+
+ con_event.type = R_CONTINUOUS_EVENT;
+ con_event.code = R_CONSOLE_EVENT | R_NODESTROY;
+ con_event.op = EVENT_ACTIVATE;
+ con_event.time = 0;
+ con_event.duration = CV_ConDroptime;
+
+ EVENT_Queue(&con_event);
+
+ ConInfo.active = 1;
+
+ return R_SUCCESS;
+}
+
+int CON_Deactivate(void)
+{
+ R_EVENT con_event;
+
+ if (!ConInfo.active) {
+ return R_FAILURE;
+ }
+
+ con_event.type = R_CONTINUOUS_EVENT;
+ con_event.code = R_CONSOLE_EVENT | R_NODESTROY;
+ con_event.op = EVENT_DEACTIVATE;
+ con_event.time = 0;
+ con_event.duration = CV_ConDroptime;
+
+ EVENT_Queue(&con_event);
+
+ return R_SUCCESS;
+}
+
+int CON_IsActive(void)
+{
+
+ return ConInfo.active;
+}
+
+int CON_Type(int in_char)
+/****************************************************************************\
+ Responsible for processing character input to the console and maintaining
+ the console input buffer.
+ Input buffer is processed by EXPR_Parse on enter.
+ High ASCII characters are ignored.
+\****************************************************************************/
+{
+
+ int input_pos = ConInfo.input_pos;
+ const char *expr;
+ int expr_len;
+ int result;
+ /*char *lvalue; */
+
+ char *rvalue = NULL;
+ R_CVAR_P con_cvar = NULL;
+
+ char *expr_err;
+ char *err_str;
+
+ if (ConInfo.y_pos != ConInfo.y_max) {
+ /* Ignore keypress until console fully down */
+ return R_SUCCESS;
+ }
+
+ if ((in_char > 127) || (!in_char)) {
+ /* Ignore non-ascii codes */
+ return R_SUCCESS;
+ }
+
+ switch (in_char) {
+
+ case '\r':
+
+ expr = ConInfo.input_buf;
+ CON_Print("> %s", ConInfo.input_buf);
+
+ expr_len = strlen(ConInfo.input_buf);
+ result = EXPR_Parse(&expr, &expr_len, &con_cvar, &rvalue);
+
+ CON_AddLine(&ConHistory, ConInfo.hist_max, ConInfo.input_buf);
+
+ memset(ConInfo.input_buf, 0, R_CON_INPUTBUF_LEN);
+ ConInfo.input_pos = 0;
+ ConInfo.hist_pos = 0;
+ if (result != R_SUCCESS) {
+ EXPR_GetError(&expr_err);
+ CON_Print("Parse error: %s", expr_err);
+ break;
+ }
+
+ if (rvalue == NULL) {
+ CVAR_Print(con_cvar);
+ break;
+ }
+
+ if (CVAR_IsFunc(con_cvar)) {
+ CVAR_Exec(con_cvar, rvalue);
+ } else if (CVAR_SetValue(con_cvar, rvalue) != R_SUCCESS) {
+ CVAR_GetError(&err_str);
+ CON_Print("Illegal assignment: %s.", err_str);
+ }
+
+ break;
+
+ case '\b':
+ ConInfo.input_buf[input_pos] = 0;
+
+ if (input_pos > 0) {
+ ConInfo.input_pos--;
+ ConInfo.input_buf[ConInfo.input_pos] = 0;
+ }
+ break;
+
+ default:
+ if (input_pos < R_CON_INPUTBUF_LEN) {
+ ConInfo.input_buf[input_pos] = (char)in_char;
+ ConInfo.input_pos++;
+ }
+ break;
+ }
+
+ if (rvalue)
+ free(rvalue);
+
+ return R_SUCCESS;
+}
+
+int CON_Draw(R_SURFACE * ds)
+{
+
+ int line_y;
+
+ R_CONSOLE_LINE *walk_ptr;
+ R_CONSOLE_LINE *start_ptr;
+
+ int txt_fgcolor;
+ int txt_shcolor;
+
+ R_RECT fill_rect;
+
+ int i;
+
+ if (!ConInfo.active) {
+ return R_FAILURE;
+ }
+
+ if (CV_ConResize != ConInfo.y_max) {
+ ConInfo.y_max = CV_ConResize;
+ ConInfo.y_pos = CV_ConResize;
+ }
+
+ fill_rect.x1 = 0;
+ fill_rect.y1 = 0;
+
+ fill_rect.x2 = ds->buf_w - 1;
+ fill_rect.y2 = ConInfo.y_pos;
+
+ GFX_DrawRect(ds, &fill_rect, SYSGFX_MatchColor(R_CONSOLE_BGCOLOR));
+
+ txt_fgcolor = SYSGFX_MatchColor(R_CONSOLE_TXTCOLOR);
+ txt_shcolor = SYSGFX_MatchColor(R_CONSOLE_TXTSHADOW);
+
+ FONT_Draw(SMALL_FONT_ID,
+ ds,
+ ">", 1,
+ 2, ConInfo.y_pos - 10, txt_fgcolor, txt_shcolor, FONT_SHADOW);
+
+ FONT_Draw(SMALL_FONT_ID,
+ ds,
+ ConInfo.input_buf, strlen(ConInfo.input_buf),
+ 10, ConInfo.y_pos - 10, txt_fgcolor, txt_shcolor, FONT_SHADOW);
+
+ line_y = ConInfo.y_pos - (R_CON_INPUT_H + R_CON_LINE_H);
+
+ start_ptr = ConScrollback.head;
+
+ for (i = 0; i < ConInfo.line_pos; i++) {
+ if (start_ptr->next) {
+ start_ptr = start_ptr->next;
+ } else {
+ break;
+ }
+ }
+
+ for (walk_ptr = start_ptr; walk_ptr; walk_ptr = walk_ptr->next) {
+
+ FONT_Draw(SMALL_FONT_ID,
+ ds,
+ walk_ptr->str_p,
+ walk_ptr->str_len,
+ 2, line_y, txt_fgcolor, txt_shcolor, FONT_SHADOW);
+
+ line_y -= R_CON_LINE_H;
+
+ if (line_y < -R_CON_LINE_H)
+ break;
+ }
+
+ return R_SUCCESS;
+}
+
+int CON_Print(const char *fmt_str, ...)
+{
+
+ char vsstr_p[R_CON_PRINTFLIMIT + 1];
+ va_list argptr;
+ int ret_val;
+
+ va_start(argptr, fmt_str);
+
+ ret_val = vsprintf(vsstr_p, fmt_str, argptr);
+
+ CON_AddLine(&ConScrollback, ConInfo.line_max, vsstr_p);
+
+ va_end(argptr);
+
+ ConInfo.line_pos = 0;
+
+ return ret_val;
+}
+
+int CON_CmdUp(void)
+{
+
+ R_CONSOLE_LINE *start_ptr = ConHistory.head;
+ int i;
+
+ if (!start_ptr) {
+ return R_SUCCESS;
+ }
+
+ if (ConInfo.hist_pos < ConHistory.lines) {
+ ConInfo.hist_pos++;
+ }
+
+ for (i = 1; (i < ConInfo.hist_pos); i++) {
+ if (start_ptr->next) {
+ start_ptr = start_ptr->next;
+ } else {
+ break;
+ }
+ }
+
+ memset(ConInfo.input_buf, 0, R_CON_INPUTBUF_LEN);
+ strcpy(ConInfo.input_buf, start_ptr->str_p);
+ ConInfo.input_pos = start_ptr->str_len - 1;
+
+ R_printf(R_STDOUT, "History pos: %d/%d", ConInfo.hist_pos,
+ ConHistory.lines);
+
+ return R_SUCCESS;
+}
+
+int CON_CmdDown(void)
+{
+
+ R_CONSOLE_LINE *start_ptr = ConHistory.head;
+ int i;
+
+ if (ConInfo.hist_pos == 1) {
+ R_printf(R_STDOUT, "Erased input buffer.");
+ memset(ConInfo.input_buf, 0, R_CON_INPUTBUF_LEN);
+ ConInfo.input_pos = 0;
+ ConInfo.hist_pos--;
+ return R_SUCCESS;
+ } else if (ConInfo.hist_pos) {
+ ConInfo.hist_pos--;
+ } else {
+ return R_SUCCESS;
+ }
+
+ for (i = 1; i < ConInfo.hist_pos; i++) {
+ if (start_ptr->next) {
+ start_ptr = start_ptr->next;
+ } else {
+ break;
+ }
+ }
+
+ memset(ConInfo.input_buf, 0, R_CON_INPUTBUF_LEN);
+ strcpy(ConInfo.input_buf, start_ptr->str_p);
+ ConInfo.input_pos = start_ptr->str_len - 1;
+
+ R_printf(R_STDOUT, "History pos: %d/%d", ConInfo.hist_pos,
+ ConHistory.lines);
+
+ return R_SUCCESS;
+}
+
+int CON_PageUp(void)
+{
+
+ int n_lines;
+
+ n_lines = (ConInfo.y_max - R_CON_INPUT_H) / R_CON_LINE_H;
+
+ if (ConInfo.line_pos < (ConScrollback.lines - n_lines)) {
+ ConInfo.line_pos += n_lines;
+ }
+
+ R_printf(R_STDOUT, "Line pos: %d", ConInfo.line_pos);
+
+ return R_SUCCESS;
+}
+
+int CON_PageDown(void)
+{
+
+ int n_lines;
+
+ n_lines = (ConInfo.y_max - R_CON_INPUT_H) / R_CON_LINE_H;
+
+ if (ConInfo.line_pos > n_lines) {
+ ConInfo.line_pos -= n_lines;
+ } else {
+ ConInfo.line_pos = 0;
+ }
+
+ return R_SUCCESS;
+}
+
+int CON_DropConsole(double percent)
+{
+
+ R_SURFACE *back_buf;
+
+ if (percent > 1.0) {
+ percent = 1.0;
+ }
+
+ back_buf = SYSGFX_GetBackBuffer();
+ CON_SetDropPos(percent);
+
+ CON_Draw(back_buf);
+
+ return R_SUCCESS;
+}
+
+int CON_RaiseConsole(double percent)
+{
+
+ R_SURFACE *back_buf;
+
+ if (percent >= 1.0) {
+ percent = 1.0;
+ ConInfo.active = 0;
+ }
+
+ back_buf = SYSGFX_GetBackBuffer();
+
+ CON_SetDropPos(1.0 - percent);
+
+ CON_Draw(back_buf);
+
+ return R_SUCCESS;
+}
+
+static int CON_SetDropPos(double percent)
+{
+
+ double exp_percent;
+
+ if (percent > 1.0)
+ percent = 1.0;
+ if (percent < 0.0)
+ percent = 0.0;
+
+ exp_percent = percent * percent;
+
+ ConInfo.y_pos = (int)(ConInfo.y_max * exp_percent);
+
+ return R_SUCCESS;
+}
+
+static int
+CON_AddLine(R_CON_SCROLLBACK * scroll, int line_max, const char *constr_p)
+{
+
+ int constr_len;
+ char *newstr_p;
+ R_CONSOLE_LINE *newline_p;
+ int del_lines;
+ int i;
+
+ constr_len = strlen(constr_p) + 1;
+
+ newstr_p = (char *)malloc(constr_len);
+ if (newstr_p == NULL) {
+ return R_MEM;
+ }
+
+ newline_p = (R_CONSOLE_LINE *)malloc(sizeof(R_CONSOLE_LINE));
+ if (newline_p == NULL) {
+ return R_MEM;
+ }
+ newline_p->next = NULL;
+ newline_p->prev = NULL;
+
+ strcpy(newstr_p, constr_p);
+ newline_p->str_p = newstr_p;
+ newline_p->str_len = constr_len;
+
+ if (scroll->head == NULL) {
+ scroll->head = newline_p;
+ scroll->tail = newline_p;
+ } else {
+ scroll->head->prev = newline_p;
+ newline_p->next = scroll->head;
+ scroll->head = newline_p;
+ }
+
+ scroll->lines++;
+
+ if (scroll->lines > line_max) {
+ del_lines = scroll->lines - line_max;
+
+ for (i = 0; i < del_lines; i++) {
+ CON_DeleteLine(scroll);
+ }
+ }
+
+ return R_SUCCESS;
+}
+
+static int CON_DeleteLine(R_CON_SCROLLBACK * scroll)
+{
+
+ R_CONSOLE_LINE *temp_p = scroll->tail;
+
+ if (temp_p->prev == NULL) {
+ scroll->head = NULL;
+ scroll->tail = NULL;
+ } else {
+ temp_p->prev->next = NULL;
+ scroll->tail = temp_p->prev;
+ }
+
+ if (temp_p->str_p)
+ free(temp_p->str_p);
+ free(temp_p);
+ scroll->lines--;
+
+ return R_SUCCESS;
+}
+
+static int CON_DeleteScroll(R_CON_SCROLLBACK * scroll)
+{
+
+ R_CONSOLE_LINE *walk_ptr;
+ R_CONSOLE_LINE *temp_ptr;
+
+ for (walk_ptr = scroll->head; walk_ptr; walk_ptr = temp_ptr) {
+
+ if (walk_ptr->str_p)
+ free(walk_ptr->str_p);
+ temp_ptr = walk_ptr->next;
+ free(walk_ptr);
+ }
+
+ return R_SUCCESS;
+}
+
+} // End of namespace Saga
diff --git a/saga/console.h b/saga/console.h
new file mode 100644
index 0000000000..12a0b7ebf7
--- /dev/null
+++ b/saga/console.h
@@ -0,0 +1,96 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Console module header file
+
+ Notes:
+*/
+
+#ifndef SAGA_CONSOLE_H_
+#define SAGA_CONSOLE_H_
+
+namespace Saga {
+
+#define R_CON_INPUTBUF_LEN 80
+
+#define R_CONSOLE_BGCOLOR 0x00A0A0A0UL
+#define R_CONSOLE_TXTCOLOR 0x00FFFFFFUL
+#define R_CONSOLE_TXTSHADOW 0x00202020UL
+
+typedef struct R_CONSOLEINFO_tag {
+
+ int active;
+ int y_max;
+ int line_max;
+ int hist_max;
+ int hist_pos;
+ int line_pos;
+ int y_pos;
+ char *prompt;
+ int prompt_w;
+ char input_buf[R_CON_INPUTBUF_LEN + 1];
+ int input_pos;
+
+} R_CONSOLEINFO;
+
+typedef struct R_CONSOLE_LINE_tag {
+
+ struct R_CONSOLE_LINE_tag *next;
+ struct R_CONSOLE_LINE_tag *prev;
+ char *str_p;
+ int str_len;
+
+} R_CONSOLE_LINE;
+
+typedef struct R_CON_SCROLLBACK_tag {
+
+ struct R_CONSOLE_LINE_tag *head;
+ struct R_CONSOLE_LINE_tag *tail;
+ int lines;
+
+} R_CON_SCROLLBACK;
+
+static int
+CON_AddLine(R_CON_SCROLLBACK * scroll, int line_max, const char *constr_p);
+
+static int CON_DeleteLine(R_CON_SCROLLBACK * scroll);
+
+static int CON_DeleteScroll(R_CON_SCROLLBACK * scroll);
+
+static int CON_SetDropPos(double percent);
+
+#define R_CON_DEFAULTPOS 136
+#define R_CON_DEFAULTLINES 100
+#define R_CON_DEFAULTCMDS 10
+#define R_CON_DROPTIME 400
+#define R_CON_PRINTFLIMIT 1024
+#define R_CON_LINE_H 10
+#define R_CON_INPUT_H 10
+
+} // End of namespace Saga
+
+#endif /* R_CONSOLE_H_ */
+
+/* end "r_console.h" */
diff --git a/saga/console_mod.h b/saga/console_mod.h
new file mode 100644
index 0000000000..62ec7efd48
--- /dev/null
+++ b/saga/console_mod.h
@@ -0,0 +1,59 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Console module public header file
+
+ Notes:
+*/
+
+#ifndef SAGA_CONSOLE_MOD_H_
+#define SAGA_CONSOLE_MOD_H_
+
+namespace Saga {
+
+int CON_Register(void);
+int CON_Init(void);
+int CON_Shutdown(void);
+
+int CON_Activate(void);
+int CON_Deactivate(void);
+int CON_IsActive(void);
+
+int CON_Type(int in_char);
+int CON_Draw(R_SURFACE * ds);
+int CON_Print(const char *fmt_str, ...);
+
+int CON_CmdUp(void);
+int CON_CmdDown(void);
+int CON_PageUp(void);
+int CON_PageDown(void);
+
+int CON_DropConsole(double percent);
+int CON_RaiseConsole(double percent);
+
+} // End of namespace Saga
+
+#endif /* R_CONSOLE_MOD_H_ */
+/* end "r_console_mod.h" */
diff --git a/saga/cvar.cpp b/saga/cvar.cpp
new file mode 100644
index 0000000000..5f69faf3a9
--- /dev/null
+++ b/saga/cvar.cpp
@@ -0,0 +1,612 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Configuration Variable Module
+
+ Notes:
+*/
+
+#include "reinherit.h"
+
+#include <limits.h>
+#include <stddef.h>
+
+/*
+ Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "console_mod.h"
+
+/*
+ Begin module
+\*--------------------------------------------------------------------------*/
+#include "cvar_mod.h"
+#include "cvar.h"
+
+namespace Saga {
+
+R_CVAR *CVHashTbl[R_CVAR_HASHLEN];
+
+char *CVAR_ErrMsg[] = {
+
+ "No Error",
+ "Not implememented.",
+ "Memory allocation failed",
+ "Value overflowed while parsing",
+ "Invalid numeric constant",
+ "Value overflows destination type",
+ "Assignment of negative value to unsigned variable",
+ "Value outside of specified bounds",
+ "Invalid string literal",
+ "Invalid type for assignment",
+ "Variable is read-only",
+ "Not a valid function"
+};
+
+enum CVAR_Errors {
+
+ CVERR_NONE,
+ CVERR_NOTIMPL,
+ CVERR_MEM,
+ CVERR_PARSEOVERFLOW,
+ CVERR_INVALID,
+ CVERR_DESTOVERFLOW,
+ CVERR_SIGN,
+ CVERR_BOUND,
+ CVERR_STRING,
+ CVERR_TYPE,
+ CVERR_READONLY,
+ CVERR_NOTFUNC
+};
+
+static enum CVAR_Errors CVAR_ErrorState;
+
+int CVAR_GetError(char **err_str)
+/****************************************************************************\
+ Returns the appropriate cvar error string
+\****************************************************************************/
+{
+
+ *err_str = CVAR_ErrMsg[CVAR_ErrorState];
+
+ return CVAR_ErrorState;
+}
+
+int CVAR_Shutdown(void)
+/****************************************************************************\
+ Frees the cvar hash table
+\****************************************************************************/
+{
+
+ R_CVAR *walk_ptr;
+ R_CVAR *temp_ptr;
+ int i;
+
+ R_printf(R_STDOUT, "CVAR_Shutdown(): Deleting cvar hash table.\n");
+
+ for (i = 0; i < R_CVAR_HASHLEN; i++) {
+
+ for (walk_ptr = CVHashTbl[i]; walk_ptr; walk_ptr = temp_ptr) {
+
+ temp_ptr = walk_ptr->next;
+ free(walk_ptr);
+ }
+ }
+
+ return R_SUCCESS;
+}
+
+unsigned int CVAR_HashString(const char *str)
+/****************************************************************************\
+ Returns hash index for string 'str'.
+ Cannot fail.
+\****************************************************************************/
+{
+
+ unsigned int index;
+
+ for (index = 0; *str != '\0'; str++) {
+ index = *str + 31 * index;
+ }
+
+ return index % R_CVAR_HASHLEN;
+}
+
+int CVAR_Add(int index, R_CVAR * cvar)
+/****************************************************************************\
+ Adds a copy of the given cvar into the hash table.
+ Returns R_SUCCESS if cvar was added, R_MEM if allocation failed.
+\****************************************************************************/
+{
+
+ R_CVAR *new_cvar;
+ R_CVAR *temp_ptr;
+
+ new_cvar = (R_CVAR *)malloc(sizeof(R_CVAR));
+
+ if (new_cvar == NULL) {
+ CVAR_ErrorState = CVERR_MEM;
+ return R_MEM;
+ }
+
+ memcpy(new_cvar, cvar, sizeof(R_CVAR));
+
+ if (CVHashTbl[index] == NULL) {
+ CVHashTbl[index] = new_cvar;
+ new_cvar->next = NULL;
+ } else {
+ temp_ptr = CVHashTbl[index];
+ CVHashTbl[index] = new_cvar;
+ new_cvar->next = temp_ptr;
+ }
+
+ CVAR_ErrorState = CVERR_NONE;
+ return R_SUCCESS;
+}
+
+int CVAR_Exec(R_CVAR_P cvar_func, char *r_value)
+/****************************************************************************\
+ Attempts to execute the specified console function with the given argument
+ string.
+ Returns R_FAILURE if cvar_func is not a valid console function
+\****************************************************************************/
+{
+
+ int cf_argc = 0;
+ char **cf_argv = NULL;
+ int max_args;
+
+ if (cvar_func->type != R_CVAR_FUNC) {
+ CVAR_ErrorState = CVERR_NOTFUNC;
+ return R_FAILURE;
+ }
+
+ cf_argc = EXPR_GetArgs(r_value, &cf_argv);
+
+ if (cf_argc < cvar_func->t.func.min_args) {
+ CON_Print("Too few arguments to function.");
+ if (cf_argv)
+ free(cf_argv);
+ return R_FAILURE;
+ }
+
+ max_args = cvar_func->t.func.max_args;
+ if ((max_args > -1) && (cf_argc > max_args)) {
+ CON_Print("Too many arguments to function.");
+ if (cf_argv)
+ free(cf_argv);
+ return R_FAILURE;
+ }
+
+ /* Call function */
+ (cvar_func->t.func.func_p) (cf_argc, cf_argv);
+
+ if (cf_argv)
+ free(cf_argv);
+
+ return R_SUCCESS;
+}
+
+int CVAR_SetValue(R_CVAR_P cvar, char *r_value)
+/****************************************************************************\
+ Attempts to assign the value contained in the string 'r_value' to cvar.
+ Returns R_FAILURE if there was an error parsing 'r_value'
+\****************************************************************************/
+{
+
+ long int int_param;
+ unsigned long uint_param;
+
+ char *end_p;
+ ptrdiff_t scan_len;
+ int r_value_len;
+
+ r_value_len = strlen(r_value);
+
+ if (cvar->flags & R_CVAR_READONLY) {
+ CVAR_ErrorState = CVERR_READONLY;
+ return R_FAILURE;
+ }
+
+ switch (cvar->type) {
+
+ case R_CVAR_INT:
+
+ int_param = strtol(r_value, &end_p, 10);
+
+ if ((int_param == LONG_MIN) || (int_param == LONG_MAX)) {
+ CVAR_ErrorState = CVERR_PARSEOVERFLOW;
+ return R_FAILURE;
+ }
+
+ scan_len = end_p - r_value;
+
+ if (int_param == 0) {
+ if (!scan_len || r_value[scan_len - 1] != '0') {
+ /* strtol() returned 0, but string isn't "0". Invalid. */
+ CVAR_ErrorState = CVERR_INVALID;
+ return R_FAILURE;
+ }
+ }
+
+ if (scan_len != r_value_len) {
+ /* Entire string wasn't converted...Invalid */
+ CVAR_ErrorState = CVERR_INVALID;
+ return R_FAILURE;
+ }
+
+ if ((int_param < CV_INTMIN) || (int_param > CV_INTMAX)) {
+ /* Overflows destination type */
+ CVAR_ErrorState = CVERR_DESTOVERFLOW;
+ return R_FAILURE;
+ }
+
+ /* Ignore bounds if equal */
+ if (cvar->t.i.lbound != cvar->t.i.ubound) {
+
+ if ((int_param < cvar->t.i.lbound) ||
+ (int_param > cvar->t.i.ubound)) {
+ /* Value is outside of cvar bounds */
+ CVAR_ErrorState = CVERR_BOUND;
+ return R_FAILURE;
+ }
+ }
+
+ *(cvar->t.i.var_p) = (cv_int_t) int_param;
+
+#ifdef R_CVAR_TRACE
+ printf("Set cvar to value %ld.\n", int_param);
+#endif
+
+ break;
+
+ case R_CVAR_UINT:
+
+ if (*r_value == '-') {
+ CVAR_ErrorState = CVERR_SIGN;
+ return R_FAILURE;
+ }
+
+ uint_param = strtoul(r_value, &end_p, 10);
+
+ if (uint_param == ULONG_MAX) {
+ CVAR_ErrorState = CVERR_PARSEOVERFLOW;
+ return R_FAILURE;
+ }
+
+ scan_len = end_p - r_value;
+
+ if (uint_param == 0) {
+
+ if (!scan_len || r_value[scan_len - 1] != '0') {
+ /* strtol() returned 0, but string isn't "0". Invalid. */
+ CVAR_ErrorState = CVERR_INVALID;
+ return R_FAILURE;
+ }
+ }
+
+ if (scan_len != r_value_len) {
+ /* Entire string wasn't converted...Invalid */
+ CVAR_ErrorState = CVERR_INVALID;
+ return R_FAILURE;
+ }
+
+ if (uint_param > CV_UINTMAX) {
+ /* Overflows destination type */
+ CVAR_ErrorState = CVERR_DESTOVERFLOW;
+ return R_FAILURE;
+ }
+
+ /* Ignore bounds if equal */
+ if (cvar->t.ui.lbound != cvar->t.ui.ubound) {
+
+ if ((uint_param < cvar->t.ui.lbound) ||
+ (uint_param > cvar->t.ui.ubound)) {
+ /* Value is outside cvar bounds */
+ CVAR_ErrorState = CVERR_BOUND;
+ return R_FAILURE;
+ }
+ }
+
+ *(cvar->t.ui.var_p) = (cv_uint_t) uint_param;
+
+#ifdef R_CVAR_TRACE
+ printf("Set cvar to value %lu.\n", uint_param);
+#endif
+
+ break;
+
+ case R_CVAR_FLOAT:
+
+ CVAR_ErrorState = CVERR_NOTIMPL;
+ return R_FAILURE;
+ break;
+
+ case R_CVAR_STRING:
+
+ if (strrchr(r_value, '\"') != NULL) {
+ CVAR_ErrorState = CVERR_STRING;
+ return R_FAILURE;
+ }
+
+ strncpy(cvar->t.s.var_str, r_value, cvar->t.s.ubound);
+ if (cvar->t.s.ubound < r_value_len) {
+ cvar->t.s.var_str[cvar->t.s.ubound] = 0;
+ }
+#ifdef R_CVAR_TRACE
+ printf("Set cvar to value \"%s\".\n", cvar->t.s.var_str);
+#endif
+
+ break;
+
+ default:
+
+ CVAR_ErrorState = CVERR_TYPE;
+ return R_FAILURE;
+ break;
+ }
+
+ CVAR_ErrorState = CVERR_NONE;
+ return R_SUCCESS;
+}
+
+R_CVAR_P CVAR_Find(const char *var_str)
+/****************************************************************************\
+ Given a cvar name this function returns a pointer to the appropriate
+ cvar structure or NULL if no match was found.
+\****************************************************************************/
+{
+
+ R_CVAR *walk_ptr;
+ int hash;
+
+ hash = CVAR_HashString(var_str);
+
+#ifdef R_CVAR_TRACE
+ printf("Performing lookup on hash bucket %d.\n", hash);
+#endif
+
+ walk_ptr = CVHashTbl[hash];
+
+ while (walk_ptr != NULL) {
+
+ if (strcmp(var_str, walk_ptr->name) == 0) {
+ return walk_ptr;
+ }
+
+ walk_ptr = walk_ptr->next;
+ }
+
+ return NULL;
+}
+
+int CVAR_IsFunc(R_CVAR_P cvar_func)
+{
+
+ if (cvar_func->type == R_CVAR_FUNC)
+ return 1;
+ else
+ return 0;
+}
+
+int
+CVAR_RegisterFunc(cv_func_t func,
+ const char *func_name,
+ const char *func_argstr, uint flags, int min_args, int max_args)
+/****************************************************************************\
+ Registers a console function 'cvar'
+ (could think of a better place to put these...?)
+\****************************************************************************/
+{
+
+ R_CVAR new_cvar;
+ int hash;
+
+ new_cvar.name = func_name;
+ new_cvar.type = R_CVAR_FUNC;
+ new_cvar.section = NULL;
+ new_cvar.flags = flags;
+
+ new_cvar.t.func.func_p = func;
+ new_cvar.t.func.func_argstr = func_argstr;
+ new_cvar.t.func.min_args = min_args;
+ new_cvar.t.func.max_args = max_args;
+ hash = CVAR_HashString(func_name);
+
+#ifdef R_CVAR_TRACE
+ printf("Added FUNC cvar to hash bucket %d.\n", hash);
+#endif
+
+ return CVAR_Add(hash, &new_cvar);
+}
+
+int
+CVAR_Register_I(cv_int_t * var_p,
+ const char *var_name,
+ const char *section, uint flags, cv_int_t lbound, cv_int_t ubound)
+/****************************************************************************\
+ Registers an integer type cvar.
+\****************************************************************************/
+{
+
+ R_CVAR new_cvar;
+ int hash;
+
+ new_cvar.name = var_name;
+ new_cvar.type = R_CVAR_INT;
+ new_cvar.section = section;
+ new_cvar.flags = flags;
+
+ new_cvar.t.i.var_p = var_p;
+
+ new_cvar.t.i.lbound = lbound;
+ new_cvar.t.i.ubound = ubound;
+
+ hash = CVAR_HashString(var_name);
+
+#ifdef R_CVAR_TRACE
+ printf("Added INT cvar to hash bucket %d.\n", hash);
+#endif
+
+ return CVAR_Add(hash, &new_cvar);
+}
+
+int
+CVAR_Register_UI(cv_uint_t * var_p,
+ const char *var_name,
+ const char *section, uint flags, cv_uint_t lbound, cv_uint_t ubound)
+/****************************************************************************\
+ Registers an unsigned integer type cvar.
+\****************************************************************************/
+{
+
+ R_CVAR new_cvar;
+ int hash;
+
+ new_cvar.name = var_name;
+ new_cvar.type = R_CVAR_UINT;
+ new_cvar.section = section;
+ new_cvar.flags = flags;
+
+ new_cvar.t.ui.var_p = var_p;
+
+ new_cvar.t.ui.lbound = lbound;
+ new_cvar.t.ui.ubound = ubound;
+
+ hash = CVAR_HashString(var_name);
+
+#ifdef R_CVAR_TRACE
+ printf("Added UNSIGNED INT ccvar to hash bucket %d.\n", hash);
+#endif
+
+ return CVAR_Add(hash, &new_cvar);
+}
+
+int
+CVAR_Register_F(cv_float_t * var_p,
+ const char *var_name,
+ const char *section, uint flags, cv_float_t lbound, cv_float_t ubound)
+/****************************************************************************\
+ Registers a floating point type cvar.
+\****************************************************************************/
+{
+
+ R_CVAR new_cvar;
+ int hash;
+
+ new_cvar.name = var_name;
+ new_cvar.type = R_CVAR_FLOAT;
+ new_cvar.section = section;
+ new_cvar.flags = flags;
+
+ new_cvar.t.f.var_p = var_p;
+
+ new_cvar.t.f.lbound = lbound;
+ new_cvar.t.f.ubound = ubound;
+
+ hash = CVAR_HashString(var_name);
+
+#ifdef R_CVAR_TRACE
+ printf("Added FLOAT cvar to hash bucket %d.\n", hash);
+#endif
+
+ return CVAR_Add(hash, &new_cvar);
+}
+
+int
+CVAR_Register_S(cv_char_t * var_str,
+ const char *var_name, const char *section, uint flags, int ubound)
+/****************************************************************************\
+ Registers a string type cvar. Storage must be provided in var_p for 'ubound'
+ characters plus 1 for NUL char.
+\****************************************************************************/
+{
+
+ R_CVAR new_cvar;
+ int hash;
+
+ new_cvar.name = var_name;
+ new_cvar.type = R_CVAR_STRING;
+ new_cvar.section = section;
+ new_cvar.flags = flags;
+
+ new_cvar.t.s.var_str = var_str;
+ new_cvar.t.s.ubound = ubound;
+
+ hash = CVAR_HashString(var_name);
+
+#ifdef R_CVAR_TRACE
+ printf("Added UNSIGNED INT var to hash bucket %d.\n", hash);
+#endif
+
+ return CVAR_Add(hash, &new_cvar);
+}
+
+int CVAR_Print(R_CVAR_P con_cvar)
+/****************************************************************************\
+ Displays the value and type of the given cvar to the console.
+\****************************************************************************/
+{
+
+ switch (con_cvar->type) {
+
+ case R_CVAR_INT:
+ CON_Print("\"%s\"(i) = %d",
+ con_cvar->name, *(con_cvar->t.i.var_p));
+ break;
+
+ case R_CVAR_UINT:
+ CON_Print("\"%s\"(ui) = %u",
+ con_cvar->name, *(con_cvar->t.ui.var_p));
+ break;
+
+ case R_CVAR_FLOAT:
+ CON_Print("\"%s\"(ui) = %f",
+ con_cvar->name, *(con_cvar->t.f.var_p));
+ break;
+
+ case R_CVAR_STRING:
+ CON_Print("\"%s\"(s) = \"%s\"", con_cvar->name,
+ con_cvar->t.s.var_str);
+ break;
+
+ case R_CVAR_FUNC:
+ if (con_cvar->t.func.func_argstr) {
+ CON_Print("\"%s\"(func) Args: %s", con_cvar->name,
+ con_cvar->t.func.func_argstr);
+ } else {
+ CON_Print("\"%s\"(func) No arguments.",
+ con_cvar->name);
+ }
+ break;
+
+ default:
+ CON_Print("Invalid variable type.\n");
+ break;
+ }
+
+ return R_SUCCESS;
+}
+
+} // End of namespace Saga
diff --git a/saga/cvar.h b/saga/cvar.h
new file mode 100644
index 0000000000..b1009bb21f
--- /dev/null
+++ b/saga/cvar.h
@@ -0,0 +1,100 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Configuration Variable Module
+
+ Notes:
+*/
+
+#ifndef SAGA_CVAR_H_
+#define SAGA_CVAR_H_
+
+namespace Saga {
+
+#define R_CVAR_HASHLEN 32
+
+typedef struct R_SUBCVAR_INT_tag {
+
+ cv_int_t *var_p;
+ cv_int_t ubound;
+ cv_int_t lbound;
+
+} R_SUBCVAR_INT;
+
+typedef struct R_SUBCVAR_UINT_tag {
+
+ cv_uint_t *var_p;
+ cv_uint_t ubound;
+ cv_uint_t lbound;
+
+} R_SUBCVAR_UINT;
+
+typedef struct R_SUBCVAR_FLOAT_tag {
+
+ cv_float_t *var_p;
+ cv_float_t ubound;
+ cv_float_t lbound;
+
+} R_SUBCVAR_FLOAT;
+
+typedef struct R_SUBCVAR_STRING_tag {
+
+ cv_char_t *var_str;
+ int ubound;
+
+} R_SUBCVAR_STRING;
+
+typedef struct R_SUBCVAR_FUNC_tag {
+
+ cv_func_t func_p;
+ const char *func_argstr;
+ int min_args;
+ int max_args;
+
+} R_SUBCVAR_FUNC;
+
+typedef struct R_CVAR_tag {
+
+ int type;
+ const char *name;
+ const char *section;
+ uint flags;
+
+ union {
+ R_SUBCVAR_INT i;
+ R_SUBCVAR_UINT ui;
+ R_SUBCVAR_FLOAT f;
+ R_SUBCVAR_STRING s;
+ R_SUBCVAR_FUNC func;
+ } t;
+
+ struct R_CVAR_tag *next;
+
+} R_CVAR;
+
+} // End of namespace Saga
+
+#endif /* R_CVAR_H_ */
+/* end "r_cvar.h" */
diff --git a/saga/cvar_mod.h b/saga/cvar_mod.h
new file mode 100644
index 0000000000..a341ff494e
--- /dev/null
+++ b/saga/cvar_mod.h
@@ -0,0 +1,112 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Configuration variable module public header file
+
+ Notes:
+*/
+
+#ifndef SAGA_CVAR_MOD_H_
+#define SAGA_CVAR_MOD_H_
+
+namespace Saga {
+
+/* Modify these to change base cvar types */
+#define CV_INTMAX INT_MAX
+#define CV_INTMIN INT_MIN
+
+#define CV_UINTMAX UINT_MAX
+typedef int cv_int_t;
+typedef unsigned int cv_uint_t;
+typedef float cv_float_t;
+typedef char cv_char_t;
+typedef void (*cv_func_t) (int cv_argc, char *cv_argv[]);
+/******************************************/
+
+typedef struct R_CVAR_tag *R_CVAR_P; /* opaque typedef */
+
+typedef enum R_CVAR_TYPES_tag {
+
+ R_CVAR_INVALID,
+ R_CVAR_INT,
+ R_CVAR_UINT,
+ R_CVAR_FLOAT,
+ R_CVAR_STRING,
+ R_CVAR_FUNC
+} R_CVAR_TYPES;
+
+typedef enum R_CVAR_FLAGS_tag {
+
+ R_CVAR_NONE,
+ R_CVAR_READONLY,
+ R_CVAR_LBOUND,
+ R_CVAR_UBOUND,
+ R_CVAR_CFG,
+ R_CVAR_SECTION
+} R_CVAR_FLAGS;
+
+#define R_CVAR_BOUNDED ( R_CVAR_LBOUND | R_CVAR_UBOUND )
+
+int CVAR_Shutdown(void);
+R_CVAR_P CVAR_Find(const char *var_str);
+int CVAR_SetValue(R_CVAR_P cvar, char *r_value);
+int CVAR_Print(R_CVAR_P con_cvar);
+int CVAR_GetError(char **err_str);
+int CVAR_IsFunc(R_CVAR_P cvar_func);
+int CVAR_Exec(R_CVAR_P cvar_func, char *r_value);
+
+int
+CVAR_RegisterFunc(cv_func_t func,
+ const char *func_name,
+ const char *func_argstr, uint flags, int min_args, int max_args);
+
+int CVAR_Register_I(cv_int_t * var_p,
+ const char *var_name,
+ const char *section, uint flags, cv_int_t lbound, cv_int_t ubound);
+
+int CVAR_Register_UI(cv_uint_t * var_p,
+ const char *var_name,
+ const char *section, uint flags, cv_uint_t lbound, cv_uint_t ubound);
+
+int CVAR_Register_F(cv_float_t * var_p,
+ const char *var_name,
+ const char *section, uint flags, cv_float_t lbound, cv_float_t ubound);
+
+int CVAR_Register_S(cv_char_t * var_str,
+ const char *var_name, const char *section, uint flags, int ubound);
+
+int EXPR_Parse(const char **exp_pp, int *len, R_CVAR_P * expr_cvar,
+ char **rvalue);
+
+char *EXPR_ReadString(const char **string_p, int *len, int term_char);
+
+int EXPR_GetError(char **err_str);
+
+int EXPR_GetArgs(char *cmd_str, char ***expr_argv);
+
+} // End of namespace Saga
+
+#endif /* R_CVAR_MOD_H_ */
+/* end r_cvar_mod.h_ */
diff --git a/saga/events.cpp b/saga/events.cpp
new file mode 100644
index 0000000000..6dcfe4ff06
--- /dev/null
+++ b/saga/events.cpp
@@ -0,0 +1,613 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ Event management module
+
+ Notes:
+*/
+
+#include "reinherit.h"
+
+#include "yslib.h"
+
+/*
+ * Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "animation_mod.h"
+#include "console_mod.h"
+#include "scene_mod.h"
+#include "gfx_mod.h"
+#include "interface_mod.h"
+#include "text_mod.h"
+#include "palanim_mod.h"
+#include "render_mod.h"
+#include "sndres_mod.h"
+
+/*
+ * Begin module
+\*--------------------------------------------------------------------------*/
+#include "events_mod.h"
+#include "events.h"
+
+namespace Saga {
+
+static YS_DL_LIST *EventList;
+
+int EVENT_Init(void)
+{
+ R_printf(R_STDOUT, "Initializing event subsystem...\n");
+
+ EventList = ys_dll_create();
+
+ return (EventList != NULL) ? R_SUCCESS : R_FAILURE;
+}
+
+int EVENT_Shutdown(void)
+{
+ R_printf(R_STDOUT, "Shutting down event subsystem...\n");
+
+ EVENT_FreeList();
+
+ return R_SUCCESS;
+}
+
+int EVENT_HandleEvents(long msec)
+/*--------------------------------------------------------------------------*\
+ * Function to process event list once per frame.
+ * First advances event times, then processes each event with the appropriate
+ * handler depending on the type of event.
+\*--------------------------------------------------------------------------*/
+{
+ YS_DL_NODE *walk_node;
+ YS_DL_NODE *next_node;
+
+ R_EVENT *event_p;
+
+ long delta_time;
+ int result;
+
+ /* Advance event times
+ * \*------------------------------------------------------------- */
+ ProcessEventTime(msec);
+
+ /* Process each event in list
+ * \*------------------------------------------------------------- */
+ for (walk_node = ys_dll_head(EventList);
+ walk_node != NULL; walk_node = next_node) {
+
+ event_p = (R_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);
+
+ /* Call the appropriate event handler for the specific event type */
+ switch (event_p->type) {
+
+ case R_ONESHOT_EVENT:
+ result = HandleOneShot(event_p);
+ break;
+
+ case R_CONTINUOUS_EVENT:
+ result = HandleContinuous(event_p);
+ break;
+
+ case R_INTERVAL_EVENT:
+ result = HandleInterval(event_p);
+ break;
+
+ default:
+ result = R_EVENT_INVALIDCODE;
+ R_printf(R_STDERR,
+ "Invalid event code encountered.\n");
+ break;
+ }
+
+ /* Process the event appropriately based on result code from
+ * handler */
+ if ((result == R_EVENT_DELETE) ||
+ (result == R_EVENT_INVALIDCODE)) {
+
+ /* If there is no event chain, delete the base event. */
+ if (event_p->chain == NULL) {
+ ys_dll_delete(walk_node);
+ } 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. */
+ delta_time = event_p->time;
+
+ ys_dll_replace(walk_node, event_p->chain,
+ sizeof *event_p);
+
+ event_p = (R_EVENT *)ys_dll_get_data(walk_node);
+ event_p->time += delta_time;
+
+ next_node = walk_node;
+ }
+ } else if (result == R_EVENT_BREAK) {
+
+ break;
+ }
+
+ } /* end for () */
+
+ return R_SUCCESS;
+}
+
+int HandleContinuous(R_EVENT * event)
+{
+
+ double event_pc = 0.0; /* Event completion percentage */
+ int event_done = 0;
+
+ R_BUFFER_INFO buf_info;
+ SCENE_BGINFO bg_info;
+ R_SURFACE *back_buf;
+
+ event_pc = ((double)event->duration - event->time) / event->duration;
+
+ if (event_pc >= 1.0) {
+ /* Cap percentage to 100 */
+ event_pc = 1.0;
+ event_done = 1;
+ }
+
+ if (event_pc < 0.0) {
+ /* Event not signaled, skip it */
+ return R_EVENT_CONTINUE;
+ } else if (!(event->code & R_SIGNALED)) {
+ /* Signal event */
+ event->code |= R_SIGNALED;
+ event_pc = 0.0;
+ }
+
+ switch (event->code & R_EVENT_MASK) {
+
+ case R_PAL_EVENT:
+
+ switch (event->op) {
+
+ case EVENT_BLACKTOPAL:
+
+ back_buf = SYSGFX_GetBackBuffer();
+
+ SYSGFX_BlackToPal(back_buf, (PALENTRY *)event->data, event_pc);
+ break;
+
+ case EVENT_PALTOBLACK:
+
+ back_buf = SYSGFX_GetBackBuffer();
+
+ SYSGFX_PalToBlack(back_buf, (PALENTRY *)event->data, event_pc);
+ break;
+
+ default:
+ break;
+ } /* end switch() */
+
+ break;
+
+ case R_TRANSITION_EVENT:
+
+ switch (event->op) {
+
+ case EVENT_DISSOLVE:
+
+ RENDER_GetBufferInfo(&buf_info);
+ SCENE_GetBGInfo(&bg_info);
+
+ TRANSITION_Dissolve(buf_info.r_bg_buf,
+ buf_info.r_bg_buf_w,
+ buf_info.r_bg_buf_h,
+ buf_info.r_bg_buf_w,
+ bg_info.bg_buf, bg_info.bg_p, 0, event_pc);
+
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ case R_CONSOLE_EVENT:
+
+ switch (event->op) {
+
+ case EVENT_ACTIVATE:
+
+ CON_DropConsole(event_pc);
+ break;
+
+ case EVENT_DEACTIVATE:
+
+ CON_RaiseConsole(event_pc);
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ default:
+ break;
+
+ } /* end switch( event->event_code ) */
+
+ if (event_done) {
+ return R_EVENT_DELETE;
+ }
+
+ return R_EVENT_CONTINUE;
+}
+
+static int HandleOneShot(R_EVENT * event)
+{
+
+ R_SURFACE *back_buf;
+
+ static SCENE_BGINFO bginfo;
+
+ if (event->time > 0) {
+ return R_EVENT_CONTINUE;
+ }
+
+ /* Event has been signaled */
+
+ switch (event->code & R_EVENT_MASK) {
+
+ case R_TEXT_EVENT:
+
+ switch (event->op) {
+
+ case EVENT_DISPLAY:
+
+ TEXT_SetDisplay((R_TEXTLIST_ENTRY *)event->data, 1);
+ break;
+
+ case EVENT_REMOVE:
+ {
+ R_SCENE_INFO scene_info;
+
+ SCENE_GetInfo(&scene_info);
+
+ TEXT_DeleteEntry(scene_info.text_list,
+ (R_TEXTLIST_ENTRY *)event->data);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ case R_VOICE_EVENT:
+
+ SND_PlayVoice(event->param);
+ break;
+
+ case R_MUSIC_EVENT:
+
+ SYSMUSIC_Play(event->param, event->param2);
+ break;
+
+ case R_BG_EVENT:
+ {
+ R_BUFFER_INFO rbuf_info;
+ R_POINT bg_pt;
+
+ if (SCENE_GetMode() == R_SCENE_MODE_NORMAL) {
+
+ back_buf = SYSGFX_GetBackBuffer();
+
+ RENDER_GetBufferInfo(&rbuf_info);
+ SCENE_GetBGInfo(&bginfo);
+
+ bg_pt.x = bginfo.bg_x;
+ bg_pt.y = bginfo.bg_y;
+
+ GFX_BufToBuffer(rbuf_info.r_bg_buf,
+ rbuf_info.r_bg_buf_w,
+ rbuf_info.r_bg_buf_h,
+ bginfo.bg_buf,
+ bginfo.bg_w, bginfo.bg_h, NULL, &bg_pt);
+
+ if (event->param == SET_PALETTE) {
+
+ PALENTRY *pal_p;
+
+ SCENE_GetBGPal(&pal_p);
+ SYSGFX_SetPalette(back_buf, pal_p);
+ }
+ }
+ }
+ break;
+
+ case R_ANIM_EVENT:
+
+ switch (event->op) {
+
+ case EVENT_FRAME:
+
+ ANIM_Play(event->param, event->time);
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ case R_SCENE_EVENT:
+
+ switch (event->op) {
+
+ case EVENT_END:
+
+ SCENE_Next();
+
+ return R_EVENT_BREAK;
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ case R_PALANIM_EVENT:
+
+ switch (event->op) {
+
+ case EVENT_CYCLESTART:
+
+ PALANIM_CycleStart();
+ break;
+
+ case EVENT_CYCLESTEP:
+
+ PALANIM_CycleStep(event->time);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case R_INTERFACE_EVENT:
+
+ switch (event->op) {
+
+ case EVENT_ACTIVATE:
+
+ INTERFACE_Activate();
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ default:
+ break;
+
+ } /* end switch( event->code ) */
+
+ return R_EVENT_DELETE;
+}
+
+static int HandleInterval(R_EVENT * event)
+{
+ YS_IGNORE_PARAM(event);
+
+ return R_EVENT_DELETE;
+}
+
+R_EVENT *EVENT_Queue(R_EVENT * event)
+/*--------------------------------------------------------------------------*\
+ * Schedules an event in the event list; returns a pointer to the scheduled
+ * event suitable for chaining if desired.
+\*--------------------------------------------------------------------------*/
+{
+ YS_DL_NODE *new_node;
+ R_EVENT *queued_event;
+
+ event->chain = NULL;
+
+ new_node = ys_dll_add_tail(EventList, event, sizeof *event);
+
+ if (new_node == NULL) {
+ return NULL;
+ }
+
+ queued_event = (R_EVENT *)ys_dll_get_data(new_node);
+
+ InitializeEvent(queued_event);
+
+ return queued_event;
+}
+
+R_EVENT *EVENT_Chain(R_EVENT * head_event, R_EVENT * add_event)
+/*--------------------------------------------------------------------------*\
+ * Places a 'add_event' on the end of an event chain given by 'head_event'
+ * (head_event may be in any position in the event chain)
+\*--------------------------------------------------------------------------*/
+{
+ R_EVENT *walk_event;
+ R_EVENT *new_event;
+
+ /* Allocate space for new event */
+ new_event = (R_EVENT *)malloc(sizeof *new_event);
+ if (new_event == NULL) {
+ return NULL;
+ }
+
+ /* Copy event data to new event */
+ *new_event = *add_event;
+
+ /* Walk to end of chain */
+ for (walk_event = head_event;
+ walk_event->chain != NULL; walk_event = walk_event->chain) {
+
+ continue;
+ }
+
+ /* Place new event */
+ walk_event->chain = new_event;
+ new_event->chain = NULL;
+
+ InitializeEvent(new_event);
+
+ return new_event;
+}
+
+static int InitializeEvent(R_EVENT * event)
+{
+
+ switch (event->type) {
+
+ case R_ONESHOT_EVENT:
+ break;
+
+ case R_CONTINUOUS_EVENT:
+ event->time += event->duration;
+ break;
+
+ case R_INTERVAL_EVENT:
+ break;
+
+ default:
+ return R_FAILURE;
+ break;
+ }
+
+ return R_SUCCESS;
+}
+
+int EVENT_ClearList(void)
+/*--------------------------------------------------------------------------*\
+ * Removes all events from the list except NODESTROY (engine) events
+\*--------------------------------------------------------------------------*/
+{
+ YS_DL_NODE *walk_node;
+ YS_DL_NODE *next_node;
+
+ struct R_EVENT_tag *chain_walk;
+ struct R_EVENT_tag *next_chain;
+
+ R_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 = (R_EVENT *)ys_dll_get_data(walk_node);
+
+ /* Only remove events not marked R_NODESTROY (engine events) */
+ if (!(event_p->code & R_NODESTROY)) {
+
+ /* 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);
+ }
+
+ ys_dll_delete(walk_node);
+ }
+ }
+
+ return R_SUCCESS;
+}
+
+int EVENT_FreeList(void)
+/*--------------------------------------------------------------------------*\
+ * Removes all events from the list (even R_NODESTROY)
+\*--------------------------------------------------------------------------*/
+{
+ YS_DL_NODE *walk_node;
+ YS_DL_NODE *next_node;
+
+ struct R_EVENT_tag *chain_walk;
+ struct R_EVENT_tag *next_chain;
+
+ R_EVENT *event_p;
+
+ /* Walk down event list */
+ for (walk_node = ys_dll_head(EventList);
+ walk_node != NULL; walk_node = next_node) {
+
+ event_p = (R_EVENT *)ys_dll_get_data(walk_node);
+
+ /* Remove any events chained off current node */
+ 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);
+ }
+
+ return R_SUCCESS;
+}
+
+static int ProcessEventTime(long msec)
+/*--------------------------------------------------------------------------*\
+ * Walks down the event list, updating event times by 'msec'.
+\*--------------------------------------------------------------------------*/
+{
+ YS_DL_NODE *walk_node;
+ R_EVENT *event_p;
+
+ uint event_count = 0;
+
+ for (walk_node = ys_dll_head(EventList);
+ walk_node != NULL; walk_node = ys_dll_next(walk_node)) {
+
+ event_p = (R_EVENT *)ys_dll_get_data(walk_node);
+ event_p->time -= msec;
+
+ event_count++;
+
+ if (event_count > R_EVENT_WARNINGCOUNT) {
+ R_printf(R_STDERR,
+ "WARNING: Event list exceeds %u.\n");
+ }
+ }
+
+ return R_SUCCESS;
+}
+
+} // End of namespace Saga
diff --git a/saga/events.h b/saga/events.h
new file mode 100644
index 0000000000..75c670db2f
--- /dev/null
+++ b/saga/events.h
@@ -0,0 +1,63 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ Event management module header file
+
+ Notes:
+*/
+
+#ifndef SAGA_EVENT_H
+#define SAGA_EVENT_H
+
+namespace Saga {
+
+#define R_EVENT_DBGLVL R_DEBUG_NONE
+
+#define R_EVENT_WARNINGCOUNT 1000
+
+#define R_EVENT_MASK 0x00FF
+
+enum R_EVENT_STATUSCODE {
+
+ R_EVENT_INVALIDCODE = 0,
+ R_EVENT_DELETE,
+ R_EVENT_CONTINUE,
+ R_EVENT_BREAK
+};
+
+static int HandleContinuous(R_EVENT * event);
+
+static int HandleOneShot(R_EVENT * event);
+
+static int HandleInterval(R_EVENT * event);
+
+static int ProcessEventTime(long msec);
+
+static int InitializeEvent(R_EVENT * event);
+
+} // End of namespace Saga
+
+#endif /* R_EVENT_H */
diff --git a/saga/events_mod.h b/saga/events_mod.h
new file mode 100644
index 0000000000..e086d37c2d
--- /dev/null
+++ b/saga/events_mod.h
@@ -0,0 +1,143 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ Event module public header
+
+ Notes:
+*/
+
+#ifndef SAGA_EVENTS_MOD_H
+#define SAGA_EVENTS_MOD_H
+
+namespace Saga {
+
+enum R_EVENT_TYPES {
+
+ R_ONESHOT_EVENT,
+ R_CONTINUOUS_EVENT,
+ R_INTERVAL_EVENT
+};
+
+enum R_EVENT_FLAGS {
+
+ R_SIGNALED = 0x8000,
+ R_NODESTROY = 0x4000
+};
+
+enum R_EVENT_CODES {
+
+ R_BG_EVENT = 1,
+ R_ANIM_EVENT,
+ R_MUSIC_EVENT,
+ R_VOICE_EVENT,
+ R_SOUND_EVENT,
+ R_SCENE_EVENT,
+ R_TEXT_EVENT,
+ R_PAL_EVENT,
+ R_PALANIM_EVENT,
+ R_TRANSITION_EVENT,
+ R_INTERFACE_EVENT,
+ R_CONSOLE_EVENT,
+ R_ACTOR_EVENT
+};
+
+enum R_EVENT_OPS {
+
+ /* INSTANTANEOUS events
+ * \*------------------------------------------------------------- */
+ /* BG events */
+ EVENT_DISPLAY = 1,
+ /* ANIM events */
+ EVENT_FRAME = 1,
+ /* MUISC & SOUND events */
+ EVENT_PLAY = 1,
+ EVENT_STOP = 2,
+ /* SCENE events */
+ EVENT_END = 2,
+ /* TEXT events */
+ EVENT_HIDE = 2,
+ EVENT_REMOVE = 3,
+ /* PALANIM events */
+ EVENT_CYCLESTART = 1,
+ EVENT_CYCLESTEP = 2,
+ /* INTERFACE events */
+ EVENT_ACTIVATE = 1,
+ EVENT_DEACTIVATE,
+ /* ACTOR events */
+ EVENT_MOVE = 1,
+
+ /* CONTINUOUS events
+ * \*------------------------------------------------------------- */
+ /* PALETTE events */
+ EVENT_PALTOBLACK = 1,
+ EVENT_BLACKTOPAL = 2,
+ /* TRANSITION events */
+ EVENT_DISSOLVE = 1
+};
+
+enum R_EVENT_PARAMS {
+
+ NO_SET_PALETTE,
+ SET_PALETTE
+};
+
+typedef struct R_EVENT_tag {
+
+ unsigned int type;
+ unsigned int code; /* Event operation category & flags */
+ int op; /* Event operation */
+
+ long param; /* Optional event parameter */
+ long param2;
+
+ void *data; /* Optional event data */
+
+ long time; /* Elapsed time until event */
+ long duration; /* Duration of event */
+ long d_reserved;
+
+ struct R_EVENT_tag *chain; /* Event chain
+ * (For consecutive events) */
+
+} R_EVENT;
+
+int EVENT_Init(void);
+
+int EVENT_Shutdown(void);
+
+int EVENT_HandleEvents(long msec);
+
+int EVENT_ClearList(void);
+
+int EVENT_FreeList(void);
+
+R_EVENT *EVENT_Queue(R_EVENT * event);
+
+R_EVENT *EVENT_Chain(R_EVENT * head_event, R_EVENT * add_event);
+
+} // End of namespace Saga
+
+#endif /* R_EVENTS_MOD_H */
diff --git a/saga/expr.cpp b/saga/expr.cpp
new file mode 100644
index 0000000000..32aca92b7f
--- /dev/null
+++ b/saga/expr.cpp
@@ -0,0 +1,464 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Expression parsing module, and string handling functions
+
+ Notes:
+
+ EXPR_ParseArgs() lifted wholesale from SDL win32 initialization code by
+ Sam Lantinga
+*/
+
+#include "reinherit.h"
+
+/*
+ Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "cvar_mod.h"
+
+/*
+ Begin module
+\*--------------------------------------------------------------------------*/
+#include "expr.h"
+
+namespace Saga {
+
+char *EXPR_ErrMsg[] = {
+
+ "Invalid error state.",
+ "No Error",
+ "Memory allocation failed",
+ "Illegal variable name",
+ "Expected \'=\' or \'(\' in expression",
+ "Expected \'(\' in function call",
+ "Illegal \'(\', identifier is not function",
+ "Expected a value to assign",
+ "Unterminated string literal",
+ "Unmatched parenthesis in function call",
+ "Error reading value string",
+ "Expected a number or boolean",
+ "Unknown variable or function"
+};
+
+enum EXPR_Errors {
+
+ EXERR_ASSERT,
+ EXERR_NONE,
+ EXERR_MEM,
+ EXERR_ILLEGAL,
+ EXERR_EXPR,
+ EXERR_FUNC,
+ EXERR_NOTFUNC,
+ EXERR_RVALUE,
+ EXERR_LITERAL,
+ EXERR_PAREN,
+ EXERR_STRING,
+ EXERR_NUMBER,
+ EXERR_NOTFOUND
+};
+
+static enum EXPR_Errors EXPR_ErrorState;
+
+int EXPR_GetError(char **err_str)
+/*--------------------------------------------------------------------------*\
+ Returns the appropriate expression parser error string given an error code.
+\*--------------------------------------------------------------------------*/
+{
+
+ *err_str = EXPR_ErrMsg[EXPR_ErrorState];
+
+ return EXPR_ErrorState;
+}
+
+int
+EXPR_Parse(const char **exp_pp, int *len, R_CVAR_P * expr_cvar, char **rvalue)
+/*--------------------------------------------------------------------------*\
+ Parses an interactive expression.
+ Sets 'expr_cvar' to the cvar/cfunction identifier input by the user, and
+ 'rvalue' to the corresponding rvalue ( in an expression ) or argument string
+ ( in a function call ).
+
+ Memory pointed to by rvalue after return must be explicitly freed by the
+ caller.
+\*--------------------------------------------------------------------------*/
+{
+
+ int i;
+ int in_char;
+ int equ_offset;
+ int rvalue_offset;
+
+ char *lvalue_str;
+ int lvalue_len;
+
+ char *rvalue_str;
+ int rvalue_len;
+
+ const char *scan_p;
+ int scan_len;
+
+ const char *expr_p;
+ int expr_len;
+ int test_char = '\0';
+ int have_func = 0;
+
+ R_CVAR_P lvalue_cvar;
+
+ expr_p = *exp_pp;
+ expr_len = strlen(*exp_pp);
+
+ scan_p = *exp_pp;
+ scan_len = expr_len;
+
+ /**lvalue = NULL;*/
+ *rvalue = NULL;
+
+ EXPR_ErrorState = EXERR_ASSERT;
+
+ for (i = 0; i <= scan_len; i++, scan_p++) {
+
+ in_char = *scan_p;
+
+ if ((i == 0) && isdigit(in_char)) {
+ /* First character of a valid identifier cannot be a digit */
+ EXPR_ErrorState = EXERR_ILLEGAL;
+ return R_FAILURE;
+ }
+
+ /* If we reach a character that isn't valid in an identifier... */
+ if ((!isalnum(in_char)) && ((in_char != '_'))) {
+
+ /* then eat remaining whitespace, if any */
+ equ_offset = strspn(scan_p, R_EXPR_WHITESPACE);
+
+ test_char = scan_p[equ_offset];
+ /* and test for the only valid characters after an identifier */
+ if ((test_char != '=') &&
+ (test_char != '\0') && (test_char != '(')) {
+
+ if ((equ_offset == 0)
+ && ((scan_p - expr_p) != expr_len)) {
+ EXPR_ErrorState = EXERR_ILLEGAL;
+ } else {
+ EXPR_ErrorState = EXERR_EXPR;
+ }
+ return R_FAILURE;
+ }
+
+ break;
+ }
+ }
+
+ lvalue_len = (scan_p - expr_p);
+ lvalue_str = (char *)malloc(lvalue_len + 1);
+
+ if (lvalue_str == NULL) {
+ EXPR_ErrorState = EXERR_MEM;
+ return R_FAILURE;
+ }
+
+ strncpy(lvalue_str, expr_p, lvalue_len);
+ lvalue_str[lvalue_len] = 0;
+
+ /* We now have the lvalue, so attempt to find it */
+ lvalue_cvar = CVAR_Find(lvalue_str);
+ if (lvalue_cvar == NULL) {
+ EXPR_ErrorState = EXERR_NOTFOUND;
+ return R_FAILURE;
+ }
+ if (lvalue_str) {
+ free(lvalue_str);
+ lvalue_str = NULL;
+ }
+
+ /* Skip parsed character, if any */
+ scan_p += equ_offset + 1;
+ scan_len = (scan_p - expr_p);
+
+ /* Check if the 'cvar' is really a function */
+ have_func = CVAR_IsFunc(lvalue_cvar);
+
+ if (test_char == '(') {
+
+ if (have_func) {
+
+ rvalue_str =
+ EXPR_ReadString(&scan_p, &rvalue_len, ')');
+ if (rvalue_str != NULL) {
+ /* Successfully read string */
+ /*CON_Print( "Read function parameters \"%s\".", rvalue_str ); */
+ *expr_cvar = lvalue_cvar;
+ *rvalue = rvalue_str;
+
+ scan_len = (scan_p - expr_p);
+
+ *exp_pp = scan_p;
+ *len -= scan_len;
+
+ EXPR_ErrorState = EXERR_NONE;
+ return R_SUCCESS;
+ } else {
+ EXPR_ErrorState = EXERR_PAREN;
+ return R_FAILURE;
+ }
+ } else {
+ EXPR_ErrorState = EXERR_NOTFUNC;
+ return R_FAILURE;
+ }
+
+ }
+
+ /* Eat more whitespace */
+ rvalue_offset = strspn(scan_p, R_EXPR_WHITESPACE);
+
+ if (rvalue_offset + i == expr_len) {
+ /* Only found single lvalue */
+ *expr_cvar = lvalue_cvar;
+ *exp_pp = scan_p;
+ *len -= scan_len;
+ return R_SUCCESS;
+ }
+
+ scan_p += rvalue_offset;
+ scan_len = (scan_p - expr_p) + 1;
+
+ in_char = *scan_p;
+
+ in_char = toupper(in_char);
+
+ switch (in_char) {
+
+ case '\"':
+ scan_p++;
+ scan_len--;
+ rvalue_str = EXPR_ReadString(&scan_p, &rvalue_len, '\"');
+
+ if (rvalue_str != NULL) {
+ /* Successfully read string */
+ break;
+ } else {
+ EXPR_ErrorState = EXERR_LITERAL;
+ return R_FAILURE;
+ }
+ break;
+
+#if 0
+ case 'Y': /* Y[es] */
+ case 'T': /* T[rue] */
+
+ break;
+
+ case 'N': /* N[o] */
+ case 'F': /* F[alse] */
+
+ break;
+#endif
+
+ default:
+
+ if (isdigit(in_char) || (in_char == '-') || (in_char == '+')) {
+
+ rvalue_str = EXPR_ReadString(&scan_p, &rvalue_len, 0);
+
+ if (rvalue_str != NULL) {
+ /* Successfully read string */
+ break;
+ } else {
+ EXPR_ErrorState = EXERR_STRING;
+ return R_FAILURE;
+ }
+ } else {
+ EXPR_ErrorState = EXERR_NUMBER;
+ return R_FAILURE;
+ }
+
+ break;
+
+ }
+
+ *expr_cvar = lvalue_cvar;
+ *rvalue = rvalue_str;
+
+ scan_len = (scan_p - expr_p);
+
+ *exp_pp = scan_p;
+ *len -= scan_len;
+
+ EXPR_ErrorState = EXERR_NONE;
+ return R_SUCCESS;
+
+}
+
+char *EXPR_ReadString(const char **string_p, int *len, int term_char)
+/****************************************************************************\
+ Reads in a string of characters from '*string_p' until 'term_char' is
+ encountered. If 'term_char' == 0, the function reads characters until
+ whitespace is encountered.
+ Upon reading a string, the function modifies *string_p and len based on
+ the number of characters read.
+\****************************************************************************/
+{
+
+ int string_len;
+ char *str_p;
+ char *term_p;
+
+ const char *scan_p;
+ int in_char;
+
+ if (term_char > 0) {
+
+ term_p = strchr(*string_p, term_char);
+
+ if (term_p == NULL) {
+ return NULL;
+ }
+
+ string_len = (int)(term_p - *string_p);
+
+ str_p = (char *)malloc(string_len + 1);
+
+ if (str_p == NULL) {
+ return NULL;
+ }
+
+ strncpy(str_p, *string_p, string_len);
+ str_p[string_len] = 0;
+
+ *string_p += (string_len + 1); /* Add 1 for terminating char */
+ *len -= (string_len + 1);
+
+ } else {
+
+ scan_p = *string_p;
+ string_len = 0;
+
+ while (scan_p) {
+
+ in_char = *scan_p++;
+
+ if (!isspace(in_char)) {
+ string_len++;
+ } else if (string_len) {
+
+ str_p = (char *)malloc(string_len + 1);
+
+ if (str_p == NULL) {
+ return NULL;
+ }
+
+ strncpy(str_p, *string_p, string_len);
+ str_p[string_len] = 0;
+
+ *string_p += string_len;
+ *len -= string_len;
+ break;
+
+ } else {
+ return NULL;
+ }
+ }
+
+ }
+
+ return str_p;
+}
+
+int EXPR_GetArgs(char *cmd_str, char ***expr_argv)
+/****************************************************************************\
+ Parses the string 'cmd_str' into argc/argv format, returning argc.
+ The resulting argv pointers point into the 'cmd_str' string, so any argv
+ entries should not be used after cmd_str is deallocated.
+
+ Memory pointed to by expr_argv must be explicitly freed by the caller.
+\****************************************************************************/
+{
+
+ int expr_argc;
+
+ expr_argc = EXPR_ParseArgs(cmd_str, NULL);
+ *expr_argv = (char **)malloc((expr_argc + 1) * sizeof(**expr_argv));
+
+ if (expr_argv == NULL) {
+ return R_FAILURE;
+ }
+
+ EXPR_ParseArgs(cmd_str, *expr_argv);
+
+ return expr_argc;
+
+}
+
+int EXPR_ParseArgs(char *cmd_str, char **argv)
+{
+
+ char *bufp;
+ int argc;
+
+ argc = 0;
+ for (bufp = cmd_str; *bufp;) {
+ /* Skip leading whitespace */
+ while (isspace(*bufp)) {
+ ++bufp;
+ }
+ /* Skip over argument */
+ if (*bufp == '"') {
+ ++bufp;
+ if (*bufp) {
+ if (argv) {
+ argv[argc] = bufp;
+ }
+ ++argc;
+ }
+ /* Skip over word */
+ while (*bufp && (*bufp != '"')) {
+ ++bufp;
+ }
+ } else {
+ if (*bufp) {
+ if (argv) {
+ argv[argc] = bufp;
+ }
+ ++argc;
+ }
+ /* Skip over word */
+ while (*bufp && !isspace(*bufp)) {
+ ++bufp;
+ }
+ }
+ if (*bufp) {
+ if (argv) {
+ *bufp = '\0';
+ }
+ ++bufp;
+ }
+ }
+ if (argv) {
+ argv[argc] = NULL;
+ }
+ return (argc);
+}
+
+} // End of namespace Saga
diff --git a/saga/expr.h b/saga/expr.h
new file mode 100644
index 0000000000..3a648ecb4d
--- /dev/null
+++ b/saga/expr.h
@@ -0,0 +1,43 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Expression parsing module header file
+
+ Notes:
+*/
+
+#ifndef SAGA_EXPR_H_
+#define SAGA_EXPR_H_
+
+namespace Saga {
+
+#define R_EXPR_WHITESPACE "\t\n "
+
+int EXPR_ParseArgs(char *cmd_str, char **argv);
+
+} // End of namespace Saga
+
+#endif /* R_EXPR_H_ */
+/* end "r_expr.h" */
diff --git a/saga/font.cpp b/saga/font.cpp
new file mode 100644
index 0000000000..18f2aaf276
--- /dev/null
+++ b/saga/font.cpp
@@ -0,0 +1,721 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ Font management and font drawing module
+
+ Notes:
+*/
+
+#include "reinherit.h"
+
+#include "yslib.h"
+
+/*
+ * Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "rscfile_mod.h"
+#include "game_mod.h"
+
+/*
+ * Begin module
+\*--------------------------------------------------------------------------*/
+#include "font_mod.h"
+#include "font.h"
+
+namespace Saga {
+
+static R_FONT_MODULE FontModule;
+
+int FONT_Init(void)
+{
+
+ R_GAME_FONTDESC *gamefonts;
+ int i;
+
+ if (FontModule.init) {
+
+ FontModule.err_str = "Font module already initialized.";
+
+ return R_FAILURE;
+ }
+
+ /* Load font module resource context
+ * \*------------------------------------------------------------ */
+ if (GAME_GetFileContext(&FontModule.font_ctxt,
+ R_GAME_RESOURCEFILE, 0) != R_SUCCESS) {
+
+ FontModule.err_str = "Couldn't get resource context.";
+
+ return R_FAILURE;
+ }
+
+ /* Allocate font table
+ * \*------------------------------------------------------------ */
+ GAME_GetFontInfo(&gamefonts, &FontModule.n_fonts);
+
+ assert(FontModule.n_fonts > 0);
+
+ FontModule.fonts = (R_FONT **)malloc(FontModule.n_fonts *
+ sizeof *FontModule.fonts);
+ if (FontModule.fonts == NULL) {
+
+ FontModule.err_str = "Memory allocation failure.";
+
+ return R_MEM;
+ }
+
+ for (i = 0; i < FontModule.n_fonts; i++) {
+
+ FONT_Load(gamefonts[i].font_rn, gamefonts[i].font_id);
+ }
+
+ FontModule.init = 1;
+
+ return R_SUCCESS;
+}
+
+int FONT_Shutdown(void)
+{
+
+ int i;
+
+ R_printf(R_STDOUT, "FONT_Shutdown(): Freeing fonts.\n");
+/*
+ for ( i = 0 ; i < R_FONT_COUNT ; i ++ ) {
+
+ if ( FontModule.fonts[i] != NULL ) {
+
+ if ( FontModule.fonts[i]->normal_loaded ) {
+ free( FontModule.fonts[i]->normal->font_free_p );
+ free( FontModule.fonts[i]->normal );
+ }
+
+ if ( FontModule.fonts[i]->outline_loaded ) {
+ free( FontModule.fonts[i]->outline->font_free_p );
+ free( FontModule.fonts[i]->outline );
+ }
+ }
+
+ free( FontModule.fonts[i] );
+ }
+*/
+ return R_SUCCESS;
+}
+
+int FONT_Load(ulong font_rn, int font_id)
+{
+
+ R_FONT_HEADER fh;
+ R_FONT *font;
+ R_FONT_STYLE *normal_font;
+
+ uchar *fontres_p;
+ size_t fontres_len;
+ size_t remain;
+
+ const uchar *read_p;
+
+ int nbits;
+ int c;
+
+ if ((font_id < 0) || (font_id >= FontModule.n_fonts)) {
+ return R_FAILURE;
+ }
+
+ /* Load font resource
+ * \*------------------------------------------------------------- */
+ if (RSC_LoadResource(FontModule.font_ctxt,
+ font_rn, &fontres_p, &fontres_len) != R_SUCCESS) {
+
+ FontModule.err_str = "Couldn't load font resource.";
+
+ return R_FAILURE;
+ }
+
+ if (fontres_len < R_FONT_DESCSIZE) {
+
+ FontModule.err_str = "Invalid font length.";
+ }
+
+ read_p = fontres_p;
+ remain = fontres_len;
+
+ /* Create new font structure
+ * \*------------------------------------------------------------- */
+ font = (R_FONT *)malloc(sizeof *font);
+ if (font == NULL) {
+ FontModule.err_str = "Memory allocation error.";
+
+ return R_MEM;
+ }
+
+ /* Read font header
+ * \*------------------------------------------------------------- */
+ fh.c_height = ys_read_u16_le(read_p, &read_p);
+ fh.c_width = ys_read_u16_le(read_p, &read_p);
+ fh.row_length = ys_read_u16_le(read_p, &read_p);
+
+#if R_FONT_DBGLVL >= R_DEBUG_INFO
+ R_printf(R_STDOUT, "FONT_Load(): Reading font resource...\n");
+#endif
+
+#if R_FONT_DBGLVL >= R_DEBUG_VERBOSE
+ R_printf(R_STDOUT, "Character width:\t%d\n", fh.c_width);
+ R_printf(R_STDOUT, "Character height:\t%d\n", fh.c_height);
+ R_printf(R_STDOUT, "Row padding:\t%d\n", fh.row_length);
+#endif
+
+ /* Create normal font style
+ * \*------------------------------------------------------------- */
+ normal_font = (R_FONT_STYLE *)malloc(sizeof *normal_font);
+ if (normal_font == NULL) {
+
+ FontModule.err_str = "Memory allocation error.";
+ free(font);
+
+ return R_MEM;
+ }
+
+ normal_font->font_free_p = fontres_p;
+ normal_font->hdr.c_height = fh.c_height;
+ normal_font->hdr.c_width = fh.c_width;
+ normal_font->hdr.row_length = fh.row_length;
+
+ for (c = 0; c < R_FONT_CHARCOUNT; c++) {
+ normal_font->fce[c].index = ys_read_u16_le(read_p, &read_p);
+ }
+
+ for (c = 0; c < R_FONT_CHARCOUNT; c++) {
+ nbits = normal_font->fce[c].width =
+ ys_read_u8(read_p, &read_p);
+ normal_font->fce[c].byte_width = GetByteLen(nbits);
+ }
+
+ for (c = 0; c < R_FONT_CHARCOUNT; c++) {
+ normal_font->fce[c].flag = ys_read_u8(read_p, &read_p);
+ }
+
+ for (c = 0; c < R_FONT_CHARCOUNT; c++) {
+ normal_font->fce[c].tracking = ys_read_u8(read_p, &read_p);
+ }
+
+ if ((read_p - fontres_p) != R_FONT_DESCSIZE) {
+
+ R_printf(R_STDERR, "Invalid font resource size.\n");
+ return R_FAILURE;
+ }
+
+ normal_font->font_p = (uchar *) read_p;
+
+ font->normal = normal_font;
+ font->normal_loaded = 1;
+
+ /* Create outline font style
+ * \*------------------------------------------------------------- */
+ font->outline = FONT_CreateOutline(normal_font);
+ font->outline_loaded = 1;
+
+ /* Set font data
+ * \*------------------------------------------------------------- */
+
+ FontModule.fonts[font_id] = font;
+
+ return R_SUCCESS;
+}
+
+int FONT_GetHeight(int font_id)
+{
+
+ R_FONT *font;
+
+ if (!FontModule.init) {
+ return R_FAILURE;
+ }
+
+ if ((font_id < 0) ||
+ (font_id >= FontModule.n_fonts) ||
+ (FontModule.fonts[font_id] == NULL)) {
+
+ FontModule.err_str = "Invalid font id.";
+
+ return R_FAILURE;
+ }
+
+ font = FontModule.fonts[font_id];
+
+ return font->normal->hdr.c_height;
+}
+
+static R_FONT_STYLE *FONT_CreateOutline(R_FONT_STYLE * src_font)
+{
+
+ R_FONT_STYLE *new_font;
+ unsigned char *new_font_data;
+ size_t new_font_data_len;
+
+ int s_width = src_font->hdr.c_width;
+ int s_height = src_font->hdr.c_height;
+
+ int new_row_len = 0;
+ int row;
+ int i;
+
+ int index;
+ size_t index_offset = 0;
+
+ int new_byte_width;
+ int old_byte_width;
+
+ int current_byte;
+
+ unsigned char *base_ptr;
+ unsigned char *src_ptr;
+ unsigned char *dest_ptr1;
+ unsigned char *dest_ptr2;
+ unsigned char *dest_ptr3;
+
+ unsigned char c_rep;
+
+ /* Create new font style structure
+ * \*------------------------------------------------------------- */
+ new_font = (R_FONT_STYLE *)malloc(sizeof *new_font);
+
+ if (new_font == NULL) {
+ FontModule.err_str = "Memory allocation error.";
+
+ return NULL;
+ }
+
+ memset(new_font, 0, sizeof *new_font);
+
+ /* Populate new font style character data
+ * \*------------------------------------------------------------- */
+ for (i = 0; i < R_FONT_CHARCOUNT; i++) {
+
+ new_byte_width = 0;
+ old_byte_width = 0;
+
+ index = src_font->fce[i].index;
+ if ((index > 0) || (i == R_FONT_FIRSTCHAR)) {
+ index += index_offset;
+ }
+
+ new_font->fce[i].index = index;
+ new_font->fce[i].tracking = src_font->fce[i].tracking;
+ new_font->fce[i].flag = src_font->fce[i].flag;
+
+ if (src_font->fce[i].width != 0) {
+
+ new_byte_width =
+ GetByteLen(src_font->fce[i].width + 2);
+ old_byte_width = GetByteLen(src_font->fce[i].width);
+
+ if (new_byte_width > old_byte_width) {
+ index_offset++;
+ }
+ }
+
+ new_font->fce[i].width = src_font->fce[i].width + 2;
+ new_font->fce[i].byte_width = new_byte_width;
+ new_row_len += new_byte_width;
+ }
+
+#if R_FONT_DBGLVL >= R_DEBUG_VERBOSE
+ R_printf(R_STDOUT, "New row length: %d\n", new_row_len);
+#endif
+
+ new_font->hdr.c_width = s_width + 2;
+ new_font->hdr.c_height = s_height + 2;
+ new_font->hdr.row_length = new_row_len;
+
+ /* Allocate new font representation storage
+ * \*------------------------------------------------------------- */
+ new_font_data_len = new_row_len * (s_height + 2);
+ new_font_data = (unsigned char *)malloc(new_font_data_len);
+
+ if (new_font_data == NULL) {
+ FontModule.err_str = "Memory allocation error.";
+
+ return NULL;
+ }
+
+ memset(new_font_data, 0, new_font_data_len);
+
+ new_font->font_free_p = new_font_data;
+ new_font->font_p = new_font_data;
+
+ /* Generate outline font representation
+ * \*------------------------------------------------------------- */
+ for (i = 0; i < R_FONT_CHARCOUNT; i++) {
+
+ for (row = 0; row < s_height; row++) {
+
+ for (current_byte = 0;
+ current_byte < new_font->fce[i].byte_width;
+ current_byte++) {
+
+ base_ptr =
+ new_font->font_p + new_font->fce[i].index +
+ current_byte;
+
+ dest_ptr1 =
+ base_ptr + new_font->hdr.row_length * row;
+ dest_ptr2 =
+ base_ptr +
+ new_font->hdr.row_length * (row + 1);
+ dest_ptr3 =
+ base_ptr +
+ new_font->hdr.row_length * (row + 2);
+
+ if (current_byte > 0) {
+
+ /* Get last two columns from previous byte */
+ src_ptr = src_font->font_p +
+ src_font->hdr.row_length * row +
+ src_font->fce[i].index +
+ (current_byte - 1);
+
+ c_rep = *src_ptr;
+ *dest_ptr1 |=
+ ((c_rep << 6) | (c_rep << 7));
+ *dest_ptr2 |=
+ ((c_rep << 6) | (c_rep << 7));
+ *dest_ptr3 |=
+ ((c_rep << 6) | (c_rep << 7));
+ }
+
+ if (current_byte < src_font->fce[i].byte_width) {
+
+ src_ptr = src_font->font_p +
+ src_font->hdr.row_length * row +
+ src_font->fce[i].index +
+ current_byte;
+
+ c_rep = *src_ptr;
+ *dest_ptr1 |=
+ c_rep | (c_rep >> 1) | (c_rep >>
+ 2);
+ *dest_ptr2 |=
+ c_rep | (c_rep >> 1) | (c_rep >>
+ 2);
+ *dest_ptr3 |=
+ c_rep | (c_rep >> 1) | (c_rep >>
+ 2);
+ }
+ }
+ }
+
+ /* "Hollow out" character to prevent overdraw */
+ for (row = 0; row < s_height; row++) {
+
+ for (current_byte = 0;
+ current_byte < new_font->fce[i].byte_width;
+ current_byte++) {
+
+ dest_ptr2 = new_font->font_p +
+ new_font->hdr.row_length * (row + 1) +
+ new_font->fce[i].index + current_byte;
+
+ if (current_byte > 0) {
+
+ /* Get last two columns from previous byte */
+ src_ptr = src_font->font_p +
+ src_font->hdr.row_length * row +
+ src_font->fce[i].index +
+ (current_byte - 1);
+
+ *dest_ptr2 &=
+ ((*src_ptr << 7) ^ 0xFFU);
+ }
+
+ if (current_byte < src_font->fce[i].byte_width) {
+
+ src_ptr = src_font->font_p +
+ src_font->hdr.row_length * row +
+ src_font->fce[i].index +
+ current_byte;
+
+ *dest_ptr2 &=
+ ((*src_ptr >> 1) ^ 0xFFU);
+ }
+ }
+ }
+ }
+
+ return new_font;
+
+}
+
+static int GetByteLen(int num_bits)
+{
+
+ int byte_len;
+
+ byte_len = num_bits / 8;
+
+ if (num_bits % 8) {
+ byte_len++;
+ }
+
+ return byte_len;
+}
+
+int
+FONT_GetStringWidth(int font_id,
+ const char *test_str, size_t test_str_ct, int flags)
+/*--------------------------------------------------------------------------*\
+ * Returns the horizontal length in pixels of the graphical representation
+ * of at most 'test_str_ct' characters of the string 'test_str', taking
+ * into account any formatting options specified by 'flags'.
+ * If 'test_str_ct' is 0, all characters of 'test_str' are counted.
+\*--------------------------------------------------------------------------*/
+{
+
+ R_FONT *font;
+ size_t ct;
+ int width = 0;
+ int ch;
+ uchar *txt_p;
+
+ if (!FontModule.init) {
+ return R_FAILURE;
+ }
+
+ if ((font_id < 0) ||
+ (font_id >= FontModule.n_fonts) ||
+ (FontModule.fonts[font_id] == NULL)) {
+
+ FontModule.err_str = "Invalid font id.";
+
+ return R_FAILURE;
+ }
+
+ font = FontModule.fonts[font_id];
+ assert(font != NULL);
+
+ txt_p = (uchar *) test_str;
+
+ for (ct = test_str_ct;
+ *txt_p && (!test_str_ct || ct > 0); txt_p++, ct--) {
+
+ ch = *txt_p & 0xFFU;
+
+ /* Translate character */
+ ch = CharMap[ch];
+ assert(ch < R_FONT_CHARCOUNT);
+
+ width += font->normal->fce[ch].tracking;
+ }
+
+ if ((flags & FONT_BOLD) || (flags & FONT_OUTLINE)) {
+ width += 1;
+ }
+
+ return width;
+}
+
+int
+FONT_Draw(int font_id,
+ R_SURFACE * ds,
+ const char *draw_str,
+ size_t draw_str_ct,
+ int text_x, int text_y, int color, int effect_color, int flags)
+{
+
+ R_FONT *font;
+
+ if (!FontModule.init) {
+ FontModule.err_str = "Font Module not initialized.";
+
+ return R_FAILURE;
+ }
+
+ if ((font_id < 0) ||
+ (font_id >= FontModule.n_fonts) ||
+ (FontModule.fonts[font_id] == NULL)) {
+
+ FontModule.err_str = "Invalid font id.";
+
+ return R_FAILURE;
+ }
+
+ font = FontModule.fonts[font_id];
+
+ if (flags & FONT_OUTLINE) {
+
+ FONT_Out(font->outline,
+ ds,
+ draw_str,
+ draw_str_ct, text_x - 1, text_y - 1, effect_color);
+
+ FONT_Out(font->normal,
+ ds, draw_str, draw_str_ct, text_x, text_y, color);
+ } else if (flags & FONT_SHADOW) {
+
+ FONT_Out(font->normal,
+ ds,
+ draw_str,
+ draw_str_ct, text_x - 1, text_y + 1, effect_color);
+
+ FONT_Out(font->normal,
+ ds, draw_str, draw_str_ct, text_x, text_y, color);
+ } else { /* FONT_NORMAL */
+
+ FONT_Out(font->normal,
+ ds, draw_str, draw_str_ct, text_x, text_y, color);
+ }
+
+ return R_SUCCESS;
+}
+
+int
+FONT_Out(R_FONT_STYLE * draw_font,
+ R_SURFACE * ds,
+ const char *draw_str,
+ size_t draw_str_ct, int text_x, int text_y, int color)
+{
+
+ const uchar *draw_str_p;
+
+ uchar *c_data_ptr;
+ int c_code;
+
+ int char_row;
+
+ uchar *output_ptr;
+ uchar *output_ptr_min;
+ uchar *output_ptr_max;
+
+ int row;
+ int row_limit;
+
+ int c_byte_len;
+ int c_byte;
+ int c_bit;
+
+ int ct;
+
+ if ((text_x > ds->buf_w) || (text_y > ds->buf_h)) {
+ /* Output string can't be visible */
+ return R_SUCCESS;
+ }
+
+ draw_str_p = (uchar *) draw_str;
+ ct = draw_str_ct;
+
+ /* Draw string one character at a time, maximum of 'draw_str'_ct
+ * characters, or no limit if 'draw_str_ct' is 0 */
+ for (; *draw_str_p && (!draw_str_ct || ct); draw_str_p++, ct--) {
+
+ c_code = *draw_str_p & 0xFFU;
+
+ /* Translate character */
+ c_code = CharMap[c_code];
+ assert(c_code < R_FONT_CHARCOUNT);
+
+ /* Check if character is defined */
+ if ((draw_font->fce[c_code].index == 0) &&
+ (c_code != R_FONT_FIRSTCHAR)) {
+
+# if R_FONT_SHOWUNDEFINED
+
+ if (c_code == R_FONT_CH_SPACE) {
+ text_x += draw_font->fce[c_code].tracking;
+ continue;
+ }
+ c_code = R_FONT_CH_QMARK;
+
+# else
+
+ /* Character code is not defined, but advance tracking
+ * ( Not defined if offset is 0, except for 33 ('!') which
+ * is defined ) */
+ text_x += draw_font->fce[c_code].tracking;
+ continue;
+
+#endif
+ }
+
+ /* Get length of character in bytes */
+ c_byte_len = ((draw_font->fce[c_code].width - 1) / 8) + 1;
+
+ row_limit = (ds->buf_h < (text_y + draw_font->hdr.c_height))
+ ? ds->buf_h : text_y + draw_font->hdr.c_height;
+
+ char_row = 0;
+
+ for (row = text_y; row < row_limit; row++, char_row++) {
+
+ /* Clip negative rows */
+ if (row < 0) {
+ continue;
+ }
+
+ output_ptr = ds->buf + (ds->buf_pitch * row) + text_x;
+
+ output_ptr_min = ds->buf + (ds->buf_pitch * row) +
+ (text_x > 0 ? text_x : 0);
+
+ output_ptr_max = output_ptr + (ds->buf_pitch - text_x);
+
+ /* If character starts off the screen, jump to next character */
+ if (output_ptr < output_ptr_min) {
+ break;
+ }
+
+ c_data_ptr = draw_font->font_p +
+ char_row * draw_font->hdr.row_length +
+ draw_font->fce[c_code].index;
+
+ for (c_byte = 0; c_byte < c_byte_len;
+ c_byte++, c_data_ptr++) {
+
+ /* Check each bit, draw pixel if bit is set */
+ for (c_bit = 7;
+ c_bit >= 0
+ && (output_ptr < output_ptr_max);
+ c_bit--) {
+
+ if ((*c_data_ptr >> c_bit) & 0x01) {
+ *output_ptr = (uchar) color;
+ }
+ output_ptr++;
+
+ } /* end per-bit processing */
+
+ } /* end per-byte processing */
+
+ } /* end per-row processing */
+
+ /* Advance tracking position */
+ text_x += draw_font->fce[c_code].tracking;
+
+ } /* end per-character processing */
+
+ return R_SUCCESS;
+}
+
+} // End of namespace Saga
diff --git a/saga/font.h b/saga/font.h
new file mode 100644
index 0000000000..a72322c804
--- /dev/null
+++ b/saga/font.h
@@ -0,0 +1,132 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ Font management and font drawing header file
+
+ Notes:
+*/
+
+#ifndef SAGA_FONT_H__
+#define SAGA_FONT_H__
+
+namespace Saga {
+
+#define R_FONT_DBGLVL R_DEBUG_NONE
+
+#define R_FONT_SHOWUNDEFINED 1 /* Define to draw undefined characters
+ * as ?'s */
+
+/* The first defined character (!) is the only one that may
+ have a valid offset of '0' */
+#define R_FONT_FIRSTCHAR 33
+
+#define R_FONT_CH_SPACE 32
+#define R_FONT_CH_QMARK 63
+
+/* Minimum font header size without font data
+ (6 + 512 + 256 + 256 + 256 ) */
+#define R_FONT_DESCSIZE 1286
+
+#define R_FONT_CHARCOUNT 256
+#define R_FONT_CHARMASK 0xFFU
+
+#define SAGA_FONT_HEADER_LEN 6
+
+typedef struct R_FONT_HEADER_tag {
+
+ int c_height;
+ int c_width;
+ int row_length;
+
+} R_FONT_HEADER;
+
+typedef struct FONT_CHAR_ENTRY_TAG {
+
+ int index;
+ int byte_width;
+ int width;
+ int flag;
+ int tracking;
+
+} FONT_CHAR_ENTRY;
+
+typedef struct R_FONT_STYLE_tag {
+
+ R_FONT_HEADER hdr;
+ FONT_CHAR_ENTRY fce[256];
+
+ uchar *font_free_p;
+ uchar *font_p;
+
+} R_FONT_STYLE;
+
+typedef struct R_FONT_tag {
+
+ ulong font_rn;
+ int font_id;
+
+ int normal_loaded;
+ R_FONT_STYLE *normal;
+ int outline_loaded;
+ R_FONT_STYLE *outline;
+
+ uchar *res_data;
+ size_t res_len;
+
+} R_FONT;
+
+typedef struct R_FONT_MODULE_tag {
+
+ int init;
+
+ R_RSCFILE_CONTEXT *font_ctxt;
+
+ int n_fonts;
+ R_FONT **fonts;
+
+ int err_n;
+ const char *err_str;
+
+} R_FONT_MODULE;
+
+int FONT_Load(ulong font_rn, int font_id);
+
+static R_FONT_STYLE *FONT_CreateOutline(R_FONT_STYLE * src_font);
+
+int
+FONT_Out(R_FONT_STYLE * font,
+ R_SURFACE * ds,
+ const char *draw_str,
+ size_t draw_str_ct, int text_x, int text_y, int color);
+
+static int GetByteLen(int num_bits);
+
+extern int CharMap[];
+
+} // End of namespace Saga
+
+#endif /* R_FONT_H__ */
+/* end "r_font.h" */
diff --git a/saga/font_map.cpp b/saga/font_map.cpp
new file mode 100644
index 0000000000..fc070d4c36
--- /dev/null
+++ b/saga/font_map.cpp
@@ -0,0 +1,295 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ Font module character mapping table ( MS CP-850 to ISO 8859-1 )
+
+ Notes:
+
+ Translation table derived from http://www.kostis.net/charsets/
+*/
+
+namespace Saga {
+
+int CharMap[] = {
+ 0, /* 0 */
+ 1, /* 1 */
+ 2, /* 2 */
+ 3, /* 3 */
+ 4, /* 4 */
+ 5, /* 5 */
+ 6, /* 6 */
+ 7, /* 7 */
+ 8, /* 8 */
+ 9, /* 9 */
+ 10, /* 10 */
+ 11, /* 11 */
+ 12, /* 12 */
+ 13, /* 13 */
+ 14, /* 14 */
+ 15, /* 15 */
+ 16, /* 16 */
+ 17, /* 17 */
+ 18, /* 18 */
+ 19, /* 19 */
+ 20, /* 20 */
+ 21, /* 21 */
+ 22, /* 22 */
+ 23, /* 23 */
+ 24, /* 24 */
+ 25, /* 25 */
+ 26, /* 26 */
+ 27, /* 27 */
+ 28, /* 28 */
+ 29, /* 29 */
+ 30, /* 30 */
+ 31, /* 31 */
+ 32, /* 32 */
+ 33, /* 33 */
+ 34, /* 34 */
+ 35, /* 35 */
+ 36, /* 36 */
+ 37, /* 37 */
+ 38, /* 38 */
+ 39, /* 39 */
+ 40, /* 40 */
+ 41, /* 41 */
+ 42, /* 42 */
+ 43, /* 43 */
+ 44, /* 44 */
+ 45, /* 45 */
+ 46, /* 46 */
+ 47, /* 47 */
+ 48, /* 48 */
+ 49, /* 49 */
+ 50, /* 50 */
+ 51, /* 51 */
+ 52, /* 52 */
+ 53, /* 53 */
+ 54, /* 54 */
+ 55, /* 55 */
+ 56, /* 56 */
+ 57, /* 57 */
+ 58, /* 58 */
+ 59, /* 59 */
+ 60, /* 60 */
+ 61, /* 61 */
+ 62, /* 62 */
+ 63, /* 63 */
+ 64, /* 64 */
+ 65, /* 65 */
+ 66, /* 66 */
+ 67, /* 67 */
+ 68, /* 68 */
+ 69, /* 69 */
+ 70, /* 70 */
+ 71, /* 71 */
+ 72, /* 72 */
+ 73, /* 73 */
+ 74, /* 74 */
+ 75, /* 75 */
+ 76, /* 76 */
+ 77, /* 77 */
+ 78, /* 78 */
+ 79, /* 79 */
+ 80, /* 80 */
+ 81, /* 81 */
+ 82, /* 82 */
+ 83, /* 83 */
+ 84, /* 84 */
+ 85, /* 85 */
+ 86, /* 86 */
+ 87, /* 87 */
+ 88, /* 88 */
+ 89, /* 89 */
+ 90, /* 90 */
+ 91, /* 91 */
+ 92, /* 92 */
+ 93, /* 93 */
+ 94, /* 94 */
+ 95, /* 95 */
+ 96, /* 96 */
+ 97, /* 97 */
+ 98, /* 98 */
+ 99, /* 99 */
+ 100, /* 100 */
+ 101, /* 101 */
+ 102, /* 102 */
+ 103, /* 103 */
+ 104, /* 104 */
+ 105, /* 105 */
+ 106, /* 106 */
+ 107, /* 107 */
+ 108, /* 108 */
+ 109, /* 109 */
+ 110, /* 110 */
+ 111, /* 111 */
+ 112, /* 112 */
+ 113, /* 113 */
+ 114, /* 114 */
+ 115, /* 115 */
+ 116, /* 116 */
+ 117, /* 117 */
+ 118, /* 118 */
+ 119, /* 119 */
+ 120, /* 120 */
+ 121, /* 121 */
+ 122, /* 122 */
+ 123, /* 123 */
+ 124, /* 124 */
+ 125, /* 125 */
+ 126, /* 126 */
+ 127, /* 127 */
+ 199, /* 128 LATIN CAPITAL LETTER C WITH CEDILLA */
+ 252, /* 129 LATIN SMALL LETTER U WITH DIAERESIS */
+ 233, /* 130 LATIN SMALL LETTER E WITH ACUTE */
+ 226, /* 131 LATIN SMALL LETTER A WITH CIRCUMFLEX */
+ 228, /* 132 LATIN SMALL LETTER A WITH DIAERESIS */
+ 224, /* 133 LATIN SMALL LETTER A WITH GRAVE */
+ 229, /* 134 LATIN SMALL LETTER A WITH RING ABOVE */
+ 231, /* 135 LATIN SMALL LETTER C WITH CEDILLA */
+ 234, /* 136 LATIN SMALL LETTER E WITH CIRCUMFLEX */
+ 235, /* 137 LATIN SMALL LETTER E WITH DIAERESIS */
+ 232, /* 138 LATIN SMALL LETTER E WITH GRAVE */
+ 239, /* 139 LATIN SMALL LETTER I WITH DIAERESIS */
+ 238, /* 140 LATIN SMALL LETTER I WITH CIRCUMFLEX */
+ 236, /* 141 LATIN SMALL LETTER I WITH GRAVE */
+ 196, /* 142 LATIN CAPITAL LETTER A WITH DIAERESIS */
+ 197, /* 143 LATIN CAPITAL LETTER A WITH RING ABOVE */
+ 201, /* 144 LATIN CAPITAL LETTER E WITH ACUTE */
+ 230, /* 145 LATIN SMALL LETTER AE */
+ 198, /* 146 LATIN CAPITAL LETTER AE */
+ 244, /* 147 LATIN SMALL LETTER O WITH CIRCUMFLEX */
+ 246, /* 148 LATIN SMALL LETTER O WITH DIAERESIS */
+ 242, /* 149 LATIN SMALL LETTER O WITH GRAVE */
+ 251, /* 150 LATIN SMALL LETTER U WITH CIRCUMFLEX */
+ 249, /* 151 LATIN SMALL LETTER U WITH GRAVE */
+ 255, /* 152 LATIN SMALL LETTER Y WITH DIAERESIS */
+ 214, /* 153 LATIN CAPITAL LETTER O WITH DIAERESIS */
+ 220, /* 154 LATIN CAPITAL LETTER U WITH DIAERESIS */
+ 248, /* 155 LATIN SMALL LETTER O WITH STROKE */
+ 163, /* 156 POUND SIGN */
+ 216, /* 157 LATIN CAPITAL LETTER O WITH STROKE */
+ 215, /* 158 MULTIPLICATION SIGN */
+ 0, /* 159 LATIN SMALL LETTER F WITH HOOK */
+ 225, /* 160 LATIN SMALL LETTER A WITH ACUTE */
+ 237, /* 161 LATIN SMALL LETTER I WITH ACUTE */
+ 243, /* 162 LATIN SMALL LETTER O WITH ACUTE */
+ 250, /* 163 LATIN SMALL LETTER U WITH ACUTE */
+ 241, /* 164 LATIN SMALL LETTER N WITH TILDE */
+ 209, /* 165 LATIN CAPITAL LETTER N WITH TILDE */
+ 170, /* 166 FEMININE ORDINAL INDICATOR */
+ 186, /* 167 MASCULINE ORDINAL INDICATOR */
+ 191, /* 168 INVERTED QUESTION MARK */
+ 174, /* 169 REGISTERED SIGN */
+ 172, /* 170 NOT SIGN */
+ 189, /* 171 VULGAR FRACTION ONE HALF */
+ 188, /* 172 VULGAR FRACTION ONE QUARTER */
+ 161, /* 173 INVERTED EXCLAMATION MARK */
+ 171, /* 174 LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
+ 187, /* 175 RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */
+ 0, /* 176 LIGHT SHADE */
+ 0, /* 177 MEDIUM SHADE */
+ 0, /* 178 DARK SHADE */
+ 0, /* 179 BOX DRAWINGS LIGHT VERTICAL */
+ 0, /* 180 BOX DRAWINGS LIGHT VERTICAL AND LEFT */
+ 193, /* 181 LATIN CAPITAL LETTER A WITH ACUTE */
+ 194, /* 182 LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
+ 192, /* 183 LATIN CAPITAL LETTER A WITH GRAVE */
+ 169, /* 184 COPYRIGHT SIGN */
+ 0, /* 185 BOX DRAWINGS DOUBLE VERTICAL AND LEFT */
+ 0, /* 186 BOX DRAWINGS DOUBLE VERTICAL */
+ 0, /* 187 BOX DRAWINGS DOUBLE DOWN AND LEFT */
+ 0, /* 188 BOX DRAWINGS DOUBLE UP AND LEFT */
+ 162, /* 189 CENT SIGN */
+ 165, /* 190 YEN SIGN */
+ 0, /* 191 BOX DRAWINGS LIGHT DOWN AND LEFT */
+ 0, /* 192 BOX DRAWINGS LIGHT UP AND RIGHT */
+ 0, /* 193 BOX DRAWINGS LIGHT UP AND HORIZONTAL */
+ 0, /* 194 BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */
+ 0, /* 195 BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
+ 0, /* 196 BOX DRAWINGS LIGHT HORIZONTAL */
+ 0, /* 197 BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */
+ 227, /* 198 LATIN SMALL LETTER A WITH TILDE */
+ 195, /* 199 LATIN CAPITAL LETTER A WITH TILDE */
+ 0, /* 200 BOX DRAWINGS DOUBLE UP AND RIGHT */
+ 0, /* 201 BOX DRAWINGS DOUBLE DOWN AND RIGHT */
+ 0, /* 202 BOX DRAWINGS DOUBLE UP AND HORIZONTAL */
+ 0, /* 203 BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL */
+ 0, /* 204 BOX DRAWINGS DOUBLE VERTICAL AND RIGHT */
+ 0, /* 205 BOX DRAWINGS DOUBLE HORIZONTAL */
+ 0, /* 206 BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL */
+ 164, /* 207 CURRENCY SIGN */
+ 240, /* 208 LATIN SMALL LETTER ETH */
+ 208, /* 209 LATIN CAPITAL LETTER ETH */
+ 202, /* 210 LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
+ 203, /* 211 LATIN CAPITAL LETTER E WITH DIAERESIS */
+ 200, /* 212 LATIN CAPITAL LETTER E WITH GRAVE */
+ 305, /* 213 LATIN SMALL LETTER DOTLESS I */
+ 205, /* 214 LATIN CAPITAL LETTER I WITH ACUTE */
+ 206, /* 215 LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
+ 207, /* 216 LATIN CAPITAL LETTER I WITH DIAERESIS */
+ 0, /* 217 BOX DRAWINGS LIGHT UP AND LEFT */
+ 0, /* 218 BOX DRAWINGS LIGHT DOWN AND RIGHT */
+ 0, /* 219 FULL BLOCK */
+ 0, /* 220 LOWER HALF BLOCK */
+ 166, /* 221 BROKEN BAR */
+ 204, /* 222 LATIN CAPITAL LETTER I WITH GRAVE */
+ 0, /* 223 UPPER HALF BLOCK */
+ 211, /* 224 LATIN CAPITAL LETTER O WITH ACUTE */
+ 223, /* 225 LATIN SMALL LETTER SHARP S */
+ 212, /* 226 LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
+ 210, /* 227 LATIN CAPITAL LETTER O WITH GRAVE */
+ 245, /* 228 LATIN SMALL LETTER O WITH TILDE */
+ 213, /* 229 LATIN CAPITAL LETTER O WITH TILDE */
+ 181, /* 230 MICRO SIGN */
+ 254, /* 231 LATIN SMALL LETTER THORN */
+ 222, /* 232 LATIN CAPITAL LETTER THORN */
+ 218, /* 233 LATIN CAPITAL LETTER U WITH ACUTE */
+ 219, /* 234 LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
+ 217, /* 235 LATIN CAPITAL LETTER U WITH GRAVE */
+ 253, /* 236 LATIN SMALL LETTER Y WITH ACUTE */
+ 221, /* 237 LATIN CAPITAL LETTER Y WITH ACUTE */
+ 175, /* 238 MACRON */
+ 180, /* 239 ACUTE ACCENT */
+ 173, /* 240 SOFT HYPHEN */
+ 177, /* 241 PLUS-MINUS SIGN */
+ 0, /* 242 DOUBLE LOW LINE */
+ 190, /* 243 VULGAR FRACTION THREE QUARTERS */
+ 182, /* 244 PILCROW SIGN */
+ 167, /* 245 SECTION SIGN */
+ 247, /* 246 DIVISION SIGN */
+ 184, /* 247 CEDILLA */
+ 176, /* 248 DEGREE SIGN */
+ 168, /* 249 DIAERESIS */
+ 183, /* 250 MIDDLE DOT */
+ 185, /* 251 SUPERSCRIPT ONE */
+ 179, /* 252 SUPERSCRIPT THREE */
+ 178, /* 253 SUPERSCRIPT TWO */
+ 0, /* 254 BLACK SQUARE */
+ 160 /* 255 NO-BREAK SPACE */
+};
+
+} // End of namespace Saga
diff --git a/saga/font_mod.h b/saga/font_mod.h
new file mode 100644
index 0000000000..dd3bbe887f
--- /dev/null
+++ b/saga/font_mod.h
@@ -0,0 +1,71 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ Font management and font drawing module public header
+
+ Notes:
+*/
+
+#ifndef SAGA_FONT_MOD_H_
+#define SAGA_FONT_MOD_H_
+
+namespace Saga {
+
+enum FONT_ID {
+
+ SMALL_FONT_ID,
+ MEDIUM_FONT_ID,
+ BIG_FONT_ID
+};
+
+enum FONT_EFFECT_FLAGS {
+
+ FONT_NORMAL = 0x00,
+ FONT_OUTLINE = 0x01,
+ FONT_SHADOW = 0x02,
+ FONT_BOLD = 0x04,
+ FONT_CENTERED = 0x08
+};
+
+int FONT_Init(void);
+
+int FONT_Shutdown(void);
+
+int FONT_Draw(int font_id,
+ R_SURFACE * ds,
+ const char *draw_str,
+ size_t draw_str_len,
+ int text_x, int text_y, int color, int effect_color, int flags);
+
+int FONT_GetStringWidth(int font_id,
+ const char *test_str, size_t test_str_ct, int flags);
+
+int FONT_GetHeight(int font_id);
+
+} // End of namespace Saga
+
+#endif /* R_FONT_MOD_H_ */
+/* end "r_font_mod.h" */
diff --git a/saga/game.cpp b/saga/game.cpp
new file mode 100644
index 0000000000..2f07cee1cd
--- /dev/null
+++ b/saga/game.cpp
@@ -0,0 +1,839 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Game detection, general game parameters
+
+ Notes:
+*/
+
+#include "reinherit.h"
+
+#include "yslib.h"
+
+/*
+ * Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "rscfile_mod.h"
+#include "cvar_mod.h"
+#include "ite_introproc_mod.h"
+#include "interface_mod.h"
+
+/*
+ * Begin module component
+\*--------------------------------------------------------------------------*/
+#include "game_mod.h"
+#include "game.h"
+
+namespace Saga {
+
+/*--------------------------------------------------------------------------*\
+ * Inherit the Earth - Demo version
+\*--------------------------------------------------------------------------*/
+
+R_GAME_FILEDESC ITEDEMO_GameFiles[] = {
+
+ {"ITE.RSC", R_GAME_RESOURCEFILE}
+ ,
+ {"ITE.DMO", R_GAME_DEMOFILE}
+ ,
+ {"SCRIPTS.RSC", R_GAME_SCRIPTFILE}
+ ,
+ {"VOICES.RSC", R_GAME_SOUNDFILE | R_GAME_VOICEFILE}
+};
+
+R_GAME_FONTDESC ITEDEMO_GameFonts[] = {
+
+ {R_GAME_FONT_SMALL, 0}
+ ,
+ {R_GAME_FONT_MEDIUM, 1}
+};
+
+R_GAME_SOUNDINFO ITEDEMO_GameSound = {
+
+ R_GAME_SOUND_VOC
+};
+
+/*--------------------------------------------------------------------------*\
+ * Inherit the Earth - Diskette version
+\*--------------------------------------------------------------------------*/
+
+R_GAME_FILEDESC ITEDISK_GameFiles[] = {
+
+ {"ITE.RSC", R_GAME_RESOURCEFILE}
+ ,
+ {"SCRIPTS.RSC", R_GAME_SCRIPTFILE}
+ ,
+ {"VOICES.RSC", R_GAME_SOUNDFILE | R_GAME_VOICEFILE}
+};
+
+R_GAME_FONTDESC ITEDISK_GameFonts[] = {
+
+ {R_GAME_FONT_MEDIUM, 0}
+ ,
+ {R_GAME_FONT_LARGE, 1}
+ ,
+ {R_GAME_FONT_SMALL, 2}
+};
+
+R_GAME_RESOURCEDESC ITE_Resources = {
+ ITE_SCENE_LUT, /* Scene lookup table RN */
+ ITE_SCRIPT_LUT, /* Script lookup table RN */
+
+ ITE_COMMAND_PANEL,
+ ITE_DIALOGUE_PANEL
+};
+
+R_GAME_SOUNDINFO ITE_GameSound = {
+
+ R_GAME_SOUND_VOC
+};
+
+/*--------------------------------------------------------------------------*\
+ * Inherit the Earth - CD Enhanced version
+\*--------------------------------------------------------------------------*/
+
+R_GAME_FILEDESC ITECD_GameFiles[] = {
+
+ {"ITE.RSC", R_GAME_RESOURCEFILE}
+ ,
+ {"SCRIPTS.RSC", R_GAME_SCRIPTFILE}
+ ,
+ {"SOUNDS.RSC", R_GAME_SOUNDFILE}
+ ,
+ {"VOICES.RSC", R_GAME_VOICEFILE}
+};
+
+R_GAME_FONTDESC ITECD_GameFonts[] = {
+
+ {R_GAME_FONT_MEDIUM, 0}
+ ,
+ {R_GAME_FONT_LARGE, 1}
+ ,
+ {R_GAME_FONT_SMALL, 2}
+};
+
+R_GAME_SOUNDINFO ITECD_GameSound = {
+
+ R_GAME_SOUND_PCM,
+ 22050,
+ 16,
+ 0
+};
+
+/*--------------------------------------------------------------------------*\
+ * I Have No Mouth and I Must Scream - Demo version
+\*--------------------------------------------------------------------------*/
+
+R_GAME_FILEDESC IHNMDEMO_GameFiles[] = {
+
+ {"SCREAM.RES", R_GAME_RESOURCEFILE}
+ ,
+ {"SCRIPTS.RES", R_GAME_SCRIPTFILE}
+ ,
+ {"SFX.RES", R_GAME_SOUNDFILE}
+ ,
+ {"VOICESD.RES", R_GAME_VOICEFILE}
+};
+
+/*--------------------------------------------------------------------------*\
+ * I Have No Mouth and I Must Scream - Retail CD version
+\*--------------------------------------------------------------------------*/
+
+R_GAME_FILEDESC IHNMCD_GameFiles[] = {
+
+ {"MUSICFM.RES", R_GAME_MUSICFILE}
+ ,
+ {"MUSICGM.RES", R_GAME_MUSICFILE}
+ ,
+ {"SCREAM.RES", R_GAME_RESOURCEFILE}
+ ,
+ {"SCRIPTS.RES", R_GAME_SCRIPTFILE}
+ ,
+ {"SFX.RES", R_GAME_SOUNDFILE}
+ ,
+ {"VOICES1.RES", R_GAME_VOICEFILE}
+ ,
+ {"VOICES2.RES", R_GAME_VOICEFILE}
+ ,
+ {"VOICES3.RES", R_GAME_VOICEFILE}
+ ,
+ {"VOICES4.RES", R_GAME_VOICEFILE}
+ ,
+ {"VOICES5.RES", R_GAME_VOICEFILE}
+ ,
+ {"VOICES6.RES", R_GAME_VOICEFILE}
+ ,
+ {"VOICESS.RES", R_GAME_VOICEFILE}
+};
+
+R_GAME_FONTDESC IHNMCD_GameFonts[] = {
+
+ {R_GAME_FONT_MEDIUM, 2}
+ ,
+ {R_GAME_FONT_LARGE, 3}
+ ,
+ {R_GAME_FONT_SMALL, 4}
+ ,
+ {R_GAME_FONT_SMALL2, 5}
+ ,
+ {R_GAME_FONT_MEDIUM2, 6}
+ ,
+ {R_GAME_FONT_LARGE2, 7}
+ ,
+ {R_GAME_FONT_LARGE3, 8}
+};
+
+R_GAME_RESOURCEDESC IHNM_Resources[] = {
+ IHNM_SCENE_LUT, /* Scene lookup table RN */
+ IHNM_SCRIPT_LUT, /* Script lookup table RN */
+
+ IHNM_COMMAND_PANEL,
+ IHNM_DIALOGUE_PANEL
+};
+
+R_GAME_SOUNDINFO IHNM_GameSound = {
+
+ R_GAME_SOUND_WAV
+};
+
+R_GAMEDESC GameDescs[] = {
+
+ /* Inherit the earth - Demo version
+ * \*------------------------------------------------------------- */
+ {
+ R_GAMETYPE_ITE,
+ R_GAME_ITE_DEMO, /* Game id */
+ "Inherit the Earth - Demo version", /* Game title */
+ 320, 200, /* Logical resolution */
+ 137, /* Scene viewport height */
+
+ ITE_DEFAULT_SCENE, /* Starting scene number */
+
+ &ITE_Resources,
+
+ YS_NELEMS(ITEDEMO_GameFiles), /* Game datafiles */
+ ITEDEMO_GameFiles,
+
+ YS_NELEMS(ITEDEMO_GameFonts),
+ ITEDEMO_GameFonts,
+
+ &ITEDEMO_GameSound,
+
+ Verify_ITEDEMO, /* Game verification func */
+ 0 /* Game supported flag */
+ }
+ ,
+
+ /* Inherit the earth - Disk version
+ * \*------------------------------------------------------------- */
+ {
+ R_GAMETYPE_ITE,
+ R_GAME_ITE_DISK,
+ "Inherit the Earth - Disk version",
+ 320, 200,
+ 137,
+
+ ITE_DEFAULT_SCENE,
+
+ &ITE_Resources,
+
+ YS_NELEMS(ITEDISK_GameFiles),
+ ITEDISK_GameFiles,
+
+ YS_NELEMS(ITEDISK_GameFonts),
+ ITEDISK_GameFonts,
+
+ &ITE_GameSound,
+
+ Verify_ITEDISK,
+ 1}
+ ,
+
+ /* Inherit the earth - CD version
+ * \*------------------------------------------------------------- */
+ {
+ R_GAMETYPE_ITE,
+ R_GAME_ITE_CD,
+ "Inherit the Earth - CD version",
+ 320, 200,
+ 137,
+
+ ITE_DEFAULT_SCENE,
+
+ &ITE_Resources,
+
+ YS_NELEMS(ITECD_GameFiles),
+ ITECD_GameFiles,
+
+ YS_NELEMS(ITECD_GameFonts),
+ ITECD_GameFonts,
+
+ &ITECD_GameSound,
+
+ NULL,
+ 1}
+ ,
+
+ /* I Have No Mouth And I Must Scream - Demo version
+ * \*------------------------------------------------------------- */
+ {
+ R_GAMETYPE_IHNM,
+ R_GAME_IHNM_DEMO,
+ "I Have No Mouth - Demo version",
+ 640, 480,
+ 304,
+
+ 0,
+
+ IHNM_Resources,
+
+ YS_NELEMS(IHNMDEMO_GameFiles),
+ IHNMDEMO_GameFiles,
+
+ 0,
+ NULL,
+
+ &IHNM_GameSound,
+
+ NULL,
+ 0}
+ ,
+
+ /* I Have No Mouth And I Must Scream - CD version
+ * \*------------------------------------------------------------- */
+ {
+ R_GAMETYPE_IHNM,
+ R_GAME_IHNM_CD,
+ "I Have No Mouth - CD version",
+ 640, 480,
+ 304,
+
+ 1,
+
+ IHNM_Resources,
+
+ YS_NELEMS(IHNMCD_GameFiles),
+ IHNMCD_GameFiles,
+
+ YS_NELEMS(IHNMCD_GameFonts),
+ IHNMCD_GameFonts,
+
+ &IHNM_GameSound,
+
+ NULL,
+ 1}
+};
+
+static R_GAMEMODULE GameModule;
+
+void GAME_setGameDirectory(const char *gamedir) {
+ assert(gamedir != NULL);
+
+ debug(0, "Using game data path: %s", gamedir);
+
+ strcpy(GameModule.game_dir, gamedir);
+ strcpy(GameModule.data_dir, ".");
+}
+
+int GAME_Register(void)
+{
+
+ return R_SUCCESS;
+
+ /* Register "gamedir" cfg cvar
+ * \*----------------------------------------- */
+ strncpy(GameModule.game_dir, "./", R_MAXPATH);
+
+ if (CVAR_Register_S(GameModule.game_dir,
+ "gamedir", NULL, R_CVAR_CFG, R_MAXPATH) != R_SUCCESS) {
+
+ return R_FAILURE;
+ }
+
+ /* Register "datadir" cfg cvar
+ * \*----------------------------------------- */
+ strncpy(GameModule.data_dir, "./", R_MAXPATH);
+
+ if (CVAR_Register_S(GameModule.data_dir,
+ "datadir", NULL, R_CVAR_CFG, R_MAXPATH) != R_SUCCESS) {
+
+ return R_FAILURE;
+ }
+
+ /* Register "g_language" cfg cvar
+ * \*----------------------------------------- */
+ strncpy(GameModule.game_dir, "us", R_MAXPATH);
+
+ if (CVAR_Register_S(GameModule.game_language,
+ "g_language",
+ NULL, R_CVAR_CFG, R_GAME_LANGSTR_LIMIT) != R_SUCCESS) {
+
+ return R_FAILURE;
+ }
+
+ /* Register "g_skipintro" cfg cvar
+ * \*----------------------------------------- */
+ if (CVAR_Register_I(&GameModule.g_skipintro,
+ "g_skipintro", NULL, R_CVAR_CFG, 0, 1) != R_SUCCESS) {
+ return R_FAILURE;
+ }
+
+ return R_SUCCESS;
+}
+
+int GAME_Init(void)
+{
+ uint game_n;
+ char *game_dir;
+
+ game_dir = GameModule.game_dir;
+
+ if (DetectGame(game_dir, &game_n) != R_SUCCESS) {
+
+ GameModule.err_str = "No valid games were found in the "
+ "specified directory.";
+
+ return R_FAILURE;
+ }
+
+ if (!GameDescs[game_n].gd_supported) {
+
+ GameModule.err_str = "This game is not currently supported.";
+
+ return R_FAILURE;
+ }
+
+ if (LoadGame(game_dir, game_n) != R_SUCCESS) {
+
+ GameModule.err_str = "Error loading game resource files.";
+
+ return R_FAILURE;
+ }
+
+ /* Load dialogue file
+ * \*------------------------------------------------------------- */
+ LoadLanguage();
+
+ return R_SUCCESS;
+}
+
+int LoadLanguage(void)
+{
+
+ char lang_file[R_MAXPATH];
+ char lang_path[R_MAXPATH];
+ uint game_n;
+
+ FILE *test_fp;
+
+ game_n = GameModule.game_number;
+
+ if (GameDescs[game_n].gd_game_type == R_GAMETYPE_ITE) {
+
+ snprintf(lang_file, R_MAXPATH,
+ "%s%s.%s",
+ R_GAME_ITE_LANG_PREFIX,
+ GameModule.game_language, R_GAME_LANG_EXT);
+
+ SYSFS_GetFQFN(GameModule.data_dir,
+ lang_file, lang_path, R_MAXPATH);
+
+ test_fp = fopen(lang_path, "r");
+ if (test_fp == NULL) {
+
+ R_printf(R_STDOUT,
+ "Couldn't open language file %s. "
+ "Using default (US English)\n", lang_path);
+
+ return R_SUCCESS;
+ }
+
+ fclose(test_fp);
+
+ if (INTERFACE_RegisterLang() != R_SUCCESS) {
+ R_printf(R_STDERR,
+ "Error registering interface language cvars.");
+
+ return R_FAILURE;
+ }
+
+ if (ITE_IntroRegisterLang() != R_SUCCESS) {
+
+ R_printf(R_STDERR,
+ "Error registering intro sequence language cvars.");
+
+ return R_FAILURE;
+ }
+
+ R_printf(R_STDOUT, "Using language file %s.\n", lang_path);
+
+ // FIXME
+ //CFG_Read(lang_path);
+ } else {
+
+ R_printf(R_STDOUT,
+ "Language support for this game not implemented.\n");
+ }
+
+ return R_SUCCESS;
+}
+
+int GAME_GetErrN(void)
+{
+ return 0;
+}
+
+const char *GAME_GetErrS(void)
+{
+
+ return GameModule.err_str == NULL
+ ? "No error description." : GameModule.err_str;
+}
+
+int GAME_GetFileContext(R_RSCFILE_CONTEXT ** ctxt_p, uint r_type, int param)
+{
+
+ R_RSCFILE_CONTEXT *found_ctxt = NULL;
+ uint i;
+
+ YS_IGNORE_PARAM(param);
+
+ if (ctxt_p == NULL) {
+
+ return R_FAILURE;
+ }
+
+ for (i = 0; i < GameModule.gfile_n; i++) {
+
+ if (GameModule.gfile_data[i].file_types & r_type) {
+
+ found_ctxt = GameModule.gfile_data[i].file_ctxt;
+ }
+ }
+
+ if (found_ctxt != NULL) {
+
+ *ctxt_p = found_ctxt;
+ } else {
+
+ *ctxt_p = NULL;
+ }
+
+ return R_SUCCESS;
+}
+
+int DetectGame(const char *game_dir, uint * game_n_p)
+{
+ char game_fpath[R_GAME_PATH_LIMIT] = { 0 };
+
+ uint game_count = YS_NELEMS(GameDescs);
+ uint game_n;
+
+ uint file_count;
+ uint file_n;
+
+ FILE *test_fp;
+
+ int file_missing = 0;
+ int found_game = 0;
+ int error;
+
+ if ((game_dir == NULL) || (game_n_p == NULL)) {
+
+ return R_FAILURE;
+ }
+
+ for (game_n = 0; (game_n < game_count) && !found_game; game_n++) {
+
+ file_count = GameDescs[game_n].gd_filect;
+
+ file_missing = 0;
+
+ /* Try to open all files for this game */
+ for (file_n = 0; file_n < file_count; file_n++) {
+
+ SYSFS_GetFQFN(game_dir,
+ GameDescs[game_n].gd_filedescs[file_n].gf_fname,
+ game_fpath, R_GAME_PATH_LIMIT);
+ test_fp = fopen(game_fpath, "rb");
+ if (test_fp == NULL) {
+
+ file_missing = 1;
+
+ break;
+ }
+
+ fclose(test_fp);
+ }
+
+ /* Try the next game, couldn't find all files for the current
+ * game */
+ if (file_missing) {
+ continue;
+ }
+
+ /* If there's a verification function for this game, use it,
+ * otherwise assume we've found the game if all files are found. */
+ found_game = 1;
+
+ if (GameDescs[game_n].gd_verifyf != NULL &&
+ GameDescs[game_n].gd_verifyf(game_dir) != R_SUCCESS) {
+
+ found_game = 0;
+ }
+
+ if (found_game) {
+ R_printf(R_STDOUT,
+ "Found game: %s\n", GameDescs[game_n].gd_title);
+
+ *game_n_p = game_n;
+
+ return R_SUCCESS;
+ }
+ }
+
+ return R_FAILURE;
+}
+
+int LoadGame(const char *game_dir, uint game_n)
+{
+
+ R_RSCFILE_CONTEXT *load_ctxt;
+
+ uint game_count = YS_NELEMS(GameDescs);
+
+ char game_fpath[R_GAME_PATH_LIMIT] = { 0 };
+ const char *game_fname;
+ uint game_filect;
+
+ uint i;
+
+ if ((game_dir == NULL) || (game_n >= game_count)) {
+
+ return R_FAILURE;
+ }
+
+ game_filect = GameDescs[game_n].gd_filect;
+
+ GameModule.gfile_data = (R_GAME_FILEDATA *)malloc(game_filect *
+ sizeof *GameModule.gfile_data);
+ if (GameModule.gfile_data == NULL) {
+
+ return R_MEM;
+ }
+
+ GameModule.gfile_n = game_filect;
+
+ /* Load game resource files
+ * \*------------------------------------------------------------- */
+ for (i = 0; i < game_filect; i++) {
+
+ load_ctxt = RSC_CreateContext();
+
+ game_fname = GameDescs[game_n].gd_filedescs[i].gf_fname;
+
+ SYSFS_GetFQFN(game_dir,
+ game_fname, game_fpath, R_GAME_PATH_LIMIT);
+
+ if (RSC_OpenContext(load_ctxt, game_fpath) != R_SUCCESS) {
+
+ return R_FAILURE;
+ }
+
+ R_printf(R_STDOUT, "Opened resource file: %s\n", game_fname);
+
+ GameModule.gfile_data[i].file_ctxt = load_ctxt;
+ GameModule.gfile_data[i].file_types =
+ GameDescs[game_n].gd_filedescs[i].gf_type;
+
+ GameModule.gfile_data[i].file_flags = 0;
+ }
+
+ /* Load game font data
+ * \*------------------------------------------------------------- */
+ GameModule.gd_fontct = GameDescs[game_n].gd_fontct;
+ 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 R_SUCCESS;
+}
+
+int GAME_GetResourceInfo(R_GAME_RESOURCEDESC * rsc_desc)
+{
+ assert(rsc_desc != NULL);
+
+ *rsc_desc = *GameModule.gamedesc->gd_resource_desc;
+
+ return R_SUCCESS;
+}
+
+int GAME_GetSoundInfo(R_GAME_SOUNDINFO * snd_info)
+{
+ assert(snd_info != NULL);
+
+ *snd_info = *GameModule.gamedesc->gd_soundinfo;
+
+ return R_SUCCESS;
+}
+
+int GAME_GetDisplayInfo(R_GAME_DISPLAYINFO * disp_info)
+{
+
+ int game_n;
+
+ assert(disp_info != NULL);
+
+ if (!GameModule.game_init) {
+ return R_FAILURE;
+ }
+
+ game_n = GameModule.game_number;
+
+ disp_info->logical_w = GameDescs[game_n].gd_logical_w;
+ disp_info->logical_h = GameDescs[game_n].gd_logical_h;
+ disp_info->scene_h = GameDescs[game_n].gd_scene_h;
+
+ return R_SUCCESS;
+}
+
+int GAME_GetFontInfo(R_GAME_FONTDESC ** gf_desc, int *font_n)
+{
+
+ assert((gf_desc != NULL) && (font_n != NULL));
+
+ *gf_desc = GameModule.gd_fontdescs;
+ *font_n = GameModule.gd_fontct;
+
+ return R_SUCCESS;
+}
+
+int GAME_GetSceneInfo(R_GAME_SCENEDESC * gs_desc)
+{
+
+ assert(gs_desc != NULL);
+
+ gs_desc->first_scene = GameModule.gamedesc->gd_startscene;
+ gs_desc->scene_lut_rn =
+ GameModule.gamedesc->gd_resource_desc->scene_lut_rn;
+
+ return R_SUCCESS;
+}
+
+int GAME_GetGame(void)
+{
+
+ return GameModule.gamedesc->gd_game_id;
+}
+
+int GAME_GetGameType(void)
+{
+
+ return GameModule.gamedesc->gd_game_type;
+}
+
+int Verify_ITEDEMO(const char *game_dir)
+{
+
+ YS_IGNORE_PARAM(game_dir);
+
+ return R_SUCCESS;
+}
+
+int Verify_ITEDISK(const char *game_dir)
+{
+
+ R_RSCFILE_CONTEXT *test_ctx;
+
+ char fpath[R_GAME_PATH_LIMIT] = { 0 };
+
+ ulong script_lut_len;
+ ulong script_lut_rn;
+
+ int verified = 0;
+
+ test_ctx = RSC_CreateContext();
+
+ SYSFS_GetFQFN(game_dir, "ITE.RSC", fpath, R_GAME_PATH_LIMIT);
+
+ if (RSC_OpenContext(test_ctx, fpath) != R_SUCCESS) {
+ return R_FAILURE;
+ }
+
+ script_lut_rn =
+ GameDescs[R_GAME_ITE_DISK].gd_resource_desc->script_lut_rn;
+
+ if (RSC_GetResourceSize(test_ctx,
+ script_lut_rn, &script_lut_len) != R_SUCCESS) {
+
+ RSC_DestroyContext(test_ctx);
+
+ return R_FAILURE;
+ }
+
+ RSC_DestroyContext(test_ctx);
+
+ if (script_lut_len % R_SCR_LUT_ENTRYLEN_ITEDISK == 0) {
+
+ verified = 1;
+ }
+
+ if (!verified) {
+ return R_FAILURE;
+ }
+
+ return R_SUCCESS;
+}
+
+int Verify_ITECD(const char *game_dir)
+{
+
+ YS_IGNORE_PARAM(game_dir);
+
+ return R_SUCCESS;
+}
+
+int Verify_IHNMDEMO(const char *game_dir)
+{
+
+ YS_IGNORE_PARAM(game_dir);
+
+ return R_SUCCESS;
+}
+
+int Verify_IHNMCD(const char *game_dir)
+{
+
+ YS_IGNORE_PARAM(game_dir);
+
+ return R_SUCCESS;
+}
+
+} // End of namespace Saga
diff --git a/saga/game.h b/saga/game.h
new file mode 100644
index 0000000000..1c16b9b5fa
--- /dev/null
+++ b/saga/game.h
@@ -0,0 +1,133 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Game detection, general game parameters
+
+ Notes:
+*/
+
+#ifndef SAGA_GAME_H_
+#define SAGA_GAME_H_
+
+namespace Saga {
+
+#define R_GAME_LANGSTR_LIMIT 3
+#define R_GAME_PATH_LIMIT 512
+
+#define R_GAME_ITE_LANG_PREFIX "ite_"
+#define R_GAME_LANG_EXT "lng"
+
+/* Script lookup table entry sizes for game verification */
+#define R_SCR_LUT_ENTRYLEN_ITECD 22
+#define R_SCR_LUT_ENTRYLEN_ITEDISK 16
+
+typedef int (*R_GAME_VERIFYFUNC) (const char *);
+
+typedef struct R_GAME_FILEDESC_tag {
+
+ const char *gf_fname;
+ uint gf_type;
+
+} R_GAME_FILEDESC;
+
+typedef struct R_GAMEDESC_tag {
+
+ int gd_game_type;
+ int gd_game_id;
+
+ const char *gd_title;
+
+ int gd_logical_w;
+ int gd_logical_h;
+ int gd_scene_h;
+
+ int gd_startscene;
+
+ R_GAME_RESOURCEDESC *gd_resource_desc;
+
+ int gd_filect;
+ R_GAME_FILEDESC *gd_filedescs;
+
+ int gd_fontct;
+ R_GAME_FONTDESC *gd_fontdescs;
+
+ R_GAME_SOUNDINFO *gd_soundinfo;
+
+ R_GAME_VERIFYFUNC gd_verifyf;
+
+ int gd_supported;
+
+} R_GAMEDESC;
+
+typedef struct R_GAME_FILEDATA_tag {
+
+ R_RSCFILE_CONTEXT *file_ctxt;
+
+ uint file_types;
+ uint file_flags;
+
+} R_GAME_FILEDATA;
+
+typedef struct R_GAMEMODULE_tag {
+
+ int game_init;
+ int game_number;
+
+ R_GAMEDESC *gamedesc;
+
+ int g_skipintro;
+
+ char game_dir[R_MAXPATH];
+ char data_dir[R_MAXPATH];
+
+ char game_language[R_GAME_LANGSTR_LIMIT];
+
+ uint gfile_n;
+ R_GAME_FILEDATA *gfile_data;
+
+ uint gd_fontct;
+ R_GAME_FONTDESC *gd_fontdescs;
+
+ int err_n;
+ const char *err_str;
+
+} R_GAMEMODULE;
+
+int LoadLanguage(void);
+
+int DetectGame(const char *game_dir, uint * game_n_p);
+
+int LoadGame(const char *game_dir, uint game_n_p);
+
+int Verify_ITEDEMO(const char *game_dir);
+int Verify_ITEDISK(const char *game_dir);
+int Verify_ITECD(const char *game_dir);
+int Verify_IHNMDEMO(const char *game_dir);
+int Verify_IHNMCD(const char *game_dit);
+
+} // End of namespace Saga
+
+#endif /* R_GAME_H_ */
+/* end "r_game.h" */
diff --git a/saga/gamedesc.h b/saga/game_mod.h
index 8a7cfbf3d3..1292688b91 100644
--- a/saga/gamedesc.h
+++ b/saga/game_mod.h
@@ -1,5 +1,7 @@
/* ScummVM - Scumm Interpreter
- * Copyright (C) 2003 The ScummVM project
+ * 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
@@ -8,7 +10,7 @@
* 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
+ * 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
@@ -18,47 +20,53 @@
* $Header$
*
*/
+/*
+ Description:
+
+ Game detection, general game parameters - module header
-#ifndef SAGA_GAMEDESC_H
-#define SAGA_GAMEDESC_H
-
-#include "resfile.h"
+ Notes:
+*/
-/* Public stuff */
+#ifndef SAGA_GAME_MOD_H__
+#define SAGA_GAME_MOD_H__
namespace Saga {
enum R_GAME_BASETYPES {
+
R_GAMETYPE_ITE,
R_GAMETYPE_IHNM
};
enum R_GAME_IDS {
- R_GAME_ITE_DEMO = 0,
- R_GAME_ITE_DISK = 1,
- R_GAME_ITE_CD = 2,
+
+ R_GAME_ITE_DEMO = 0,
+ R_GAME_ITE_DISK = 1,
+ R_GAME_ITE_CD = 2,
R_GAME_IHNM_DEMO = 3,
- R_GAME_IHNM_CD = 4
+ R_GAME_IHNM_CD = 4
};
enum R_GAME_FILETYPES {
+
R_GAME_RESOURCEFILE = 0x01,
- R_GAME_SCRIPTFILE = 0x02,
- R_GAME_SOUNDFILE = 0x04,
- R_GAME_VOICEFILE = 0x08,
- R_GAME_DEMOFILE = 0x10,
- R_GAME_MUSICFILE = 0x20,
-
- R_GAME_EXCLUDE = 0x8000
+ R_GAME_SCRIPTFILE = 0x02,
+ R_GAME_SOUNDFILE = 0x04,
+ R_GAME_VOICEFILE = 0x08,
+ R_GAME_DEMOFILE = 0x10,
+ R_GAME_MUSICFILE = 0x20
};
enum R_GAME_SOUNDINFO_TYPES {
+
R_GAME_SOUND_PCM = 0,
R_GAME_SOUND_VOC,
R_GAME_SOUND_WAV
};
enum R_GAME_FONT_IDS {
+
R_GAME_FONT_SMALL = 0,
R_GAME_FONT_MEDIUM,
R_GAME_FONT_LARGE,
@@ -69,61 +77,72 @@ enum R_GAME_FONT_IDS {
};
typedef struct R_GAME_DISPLAYINFO_tag {
+
int logical_w;
int logical_h;
int scene_h;
- int ovl_pal_start;
- int ovl_pal_end;
-
} R_GAME_DISPLAYINFO;
typedef struct R_GAMESOUND_INFO_tag {
- int res_type;
+
+ int res_type;
long freq;
- int sample_size;
- int stereo;
-
+ int sample_size;
+ int stereo;
+
} R_GAME_SOUNDINFO;
typedef struct R_GAMEFONT_DESC_tag {
- unsigned int font_id;
- unsigned long font_rn;
-
+
+ uint font_id;
+ ulong font_rn;
+
} R_GAME_FONTDESC;
typedef struct R_GAMESCENE_DESC_tag {
- unsigned long scene_lut_rn;
- unsigned long first_scene;
+
+ ulong scene_lut_rn;
+ ulong first_scene;
} R_GAME_SCENEDESC;
-typedef struct R_GAME_RESOURCEINFO_tag {
- unsigned long scene_lut_rn;
- unsigned long script_lut_rn;
+typedef struct R_GAMERESOURCE_DESC_tag {
- unsigned long overlay_pal_rn;
+ ulong scene_lut_rn;
+ ulong script_lut_rn;
+ ulong command_panel_rn;
+ ulong dialogue_panel_rn;
- unsigned long command_panel_rn;
- unsigned long command_buttons_rn;
+} R_GAME_RESOURCEDESC;
- unsigned long dialogue_panel_rn;
- unsigned long lportraits_rn;
+int GAME_Register(void);
- unsigned long actor_tbl_rn;
+int GAME_Init(void);
-} R_GAME_RESOURCEINFO;
+int GAME_GetFileContext(R_RSCFILE_CONTEXT ** ctxt_p, uint r_type, int param);
- void setGameDirectory( const char *gamedir );
- int detectGame();
- bool openGame();
+int GAME_GetFontInfo(R_GAME_FONTDESC **, int *);
-} // End of namespace Saga
+int GAME_GetResourceInfo(R_GAME_RESOURCEDESC *);
-#endif
+int GAME_GetSoundInfo(R_GAME_SOUNDINFO *);
+int GAME_GetDisplayInfo(R_GAME_DISPLAYINFO *);
+int GAME_GetSceneInfo(R_GAME_SCENEDESC *);
+int GAME_GetGame(void);
+int GAME_GetGameType(void);
+int GAME_GetErrN(void);
+
+void GAME_setGameDirectory(const char *gamedir);
+
+const char *GAME_GetErrS(void);
+
+} // End of namespace Saga
+#endif /* R_GAME_MOD_H__ */
+/* end "r_game_mod.h" */
diff --git a/saga/gamedesc.cpp b/saga/gamedesc.cpp
deleted file mode 100644
index 7464ad6d2f..0000000000
--- a/saga/gamedesc.cpp
+++ /dev/null
@@ -1,449 +0,0 @@
-/* ScummVM - Scumm Interpreter
- * Copyright (C) 2003 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$
- *
- */
-
-#include "stdafx.h"
-
-#include "common/scummsys.h"
-#include "base/engine.h"
-#include "common/util.h"
-#include "common/file.h"
-
-#include "resfile.h"
-#include "resnames.h"
-#include "gamedesc.h"
-#include "gamedesc_priv.h"
-
-namespace Saga {
-
-/*--------------------------------------------------------------------------*\
- * Inherit the Earth - Demo version
-\*--------------------------------------------------------------------------*/
-
-R_GAME_FILEDESC ITEDEMO_GameFiles[] = {
- { "ITE.RSC", R_GAME_RESOURCEFILE },
- { "ITE.DMO", R_GAME_DEMOFILE },
- { "SCRIPTS.RSC", R_GAME_SCRIPTFILE },
- { "VOICES.RSC", R_GAME_SOUNDFILE | R_GAME_VOICEFILE }
-};
-
-R_GAME_FONTDESC ITEDEMO_GameFonts[] = {
- { R_GAME_FONT_SMALL, 0 },
- { R_GAME_FONT_MEDIUM, 1 }
-};
-
-R_GAME_SOUNDINFO ITEDEMO_GameSound = {
- R_GAME_SOUND_VOC, 0, 0, 0
-};
-
-/*--------------------------------------------------------------------------*\
- * Inherit the Earth - Diskette version
-\*--------------------------------------------------------------------------*/
-
-R_GAME_FILEDESC ITEDISK_GameFiles[] = {
- { "ITE.RSC", R_GAME_RESOURCEFILE },
- { "SCRIPTS.RSC", R_GAME_SCRIPTFILE },
- { "VOICES.RSC", R_GAME_SOUNDFILE | R_GAME_VOICEFILE }
-};
-
-R_GAME_FONTDESC ITEDISK_GameFonts[] = {
- { R_GAME_FONT_MEDIUM, 0 },
- { R_GAME_FONT_LARGE, 1 },
- { R_GAME_FONT_SMALL, 2 }
-};
-
-R_GAME_DISPLAYINFO ITE_DisplayInfo = {
- 320, 200, /* Logical width and height */
- 137, /* Scene playfield height */
- 0, 0 /* Overlay palette start index and length */
-};
-
-R_GAME_RESOURCEINFO ITE_Resources = {
- ITE_SCENE_LUT, /* Scene lookup table RN */
- ITE_SCRIPT_LUT, /* Script lookup table RN */
-
- ITE_OVERLAY_PAL, /* Overlay palette RN */
-
- ITE_COMMAND_PANEL,
- ITE_COMMAND_BUTTONSPRITES,
-
- ITE_DIALOGUE_PANEL,
- ITE_DEFAULT_PORTRAITS,
-
- ITE_ACTOR_PERSONA_TBL
-};
-
-R_GAME_SOUNDINFO ITE_GameSound = {
- R_GAME_SOUND_VOC, 0, 0, 0
-};
-
-/*--------------------------------------------------------------------------*\
- * Inherit the Earth - CD Enhanced version
-\*--------------------------------------------------------------------------*/
-
-R_GAME_FILEDESC ITECD_GameFiles[] = {
- { "ITE.RSC", R_GAME_RESOURCEFILE },
- { "SCRIPTS.RSC", R_GAME_SCRIPTFILE },
- { "SOUNDS.RSC", R_GAME_SOUNDFILE },
- { "VOICES.RSC", R_GAME_VOICEFILE }
-};
-
-R_GAME_FONTDESC ITECD_GameFonts[] = {
- { R_GAME_FONT_MEDIUM, 0 },
- { R_GAME_FONT_LARGE, 1 },
- { R_GAME_FONT_SMALL, 2 }
-};
-
-R_GAME_SOUNDINFO ITECD_GameSound = {
- R_GAME_SOUND_PCM,
- 22050,
- 16,
- 0
-};
-
-/*--------------------------------------------------------------------------*\
- * I Have No Mouth and I Must Scream - Demo version
-\*--------------------------------------------------------------------------*/
-
-R_GAME_FILEDESC IHNMDEMO_GameFiles[] = {
- { "SCREAM.RES", R_GAME_RESOURCEFILE },
- { "SCRIPTS.RES", R_GAME_SCRIPTFILE },
- { "SFX.RES", R_GAME_SOUNDFILE },
- { "VOICESD.RES", R_GAME_VOICEFILE }
-};
-
-/*--------------------------------------------------------------------------*\
- * I Have No Mouth and I Must Scream - Retail CD version
-\*--------------------------------------------------------------------------*/
-
-R_GAME_FILEDESC IHNMCD_GameFiles[] = {
- { "MUSICFM.RES", R_GAME_MUSICFILE },
- { "MUSICGM.RES", R_GAME_MUSICFILE },
- { "SCREAM.RES", R_GAME_RESOURCEFILE },
- { "SCRIPTS.RES", R_GAME_SCRIPTFILE },
- { "SFX.RES", R_GAME_SOUNDFILE },
- { "VOICES1.RES", R_GAME_VOICEFILE },
- { "VOICES2.RES", R_GAME_VOICEFILE },
- { "VOICES3.RES", R_GAME_VOICEFILE },
- { "VOICES4.RES", R_GAME_VOICEFILE },
- { "VOICES5.RES", R_GAME_VOICEFILE },
- { "VOICES6.RES", R_GAME_VOICEFILE },
- { "VOICESS.RES", R_GAME_VOICEFILE }
-};
-
-R_GAME_FONTDESC IHNMCD_GameFonts[] = {
- { R_GAME_FONT_MEDIUM, 2 },
- { R_GAME_FONT_LARGE, 3 },
- { R_GAME_FONT_SMALL, 4 },
- { R_GAME_FONT_SMALL2, 5 },
- { R_GAME_FONT_MEDIUM2, 6 },
- { R_GAME_FONT_LARGE2, 7 },
- { R_GAME_FONT_LARGE3, 8 }
-};
-
-R_GAME_DISPLAYINFO IHNM_DisplayInfo = {
- 640, 480, /* Logical width and height */
- 304, /* Scene playfield height */
- 248, 255 /* Overlay palette start index and length */
-};
-
-R_GAME_RESOURCEINFO IHNM_Resources = {
- IHNM_SCENE_LUT, /* Scene lookup table RN */
- IHNM_SCRIPT_LUT, /* Script lookup table RN */
-
- IHNM_OVERLAY_PAL, /* Overlay palette RN */
-
- IHNM_COMMAND_PANEL,
- IHNM_COMMAND_BUTTONSPRITES,
-
- IHNM_DIALOGUE_PANEL,
- IHNM_DEFAULT_PORTRAITS,
-
- IHNM_ACTOR_PERSONA_TBL
-};
-
-
-R_GAME_SOUNDINFO IHNM_GameSound = {
- R_GAME_SOUND_WAV, 0, 0, 0
-};
-
-R_GAMEDESC GameDescs[] = {
- /* Inherit the earth - Demo version
- \*-------------------------------------------------------------*/
- {
- R_GAMETYPE_ITE,
- R_GAME_ITE_DEMO, /* Game id */
- "Inherit the Earth - Demo version", /* Game title */
-
- &ITE_DisplayInfo,
-
- ITE_DEFAULT_SCENE, /* Starting scene number */
-
- &ITE_Resources,
-
- ARRAYSIZE(ITEDEMO_GameFiles), /* Game datafiles */
- ITEDEMO_GameFiles,
-
- ARRAYSIZE(ITEDEMO_GameFonts),
- ITEDEMO_GameFonts,
-
- &ITEDEMO_GameSound,
-
- 0 /* Game supported flag */
- },
-
- /* Inherit the earth - Disk version
- \*-------------------------------------------------------------*/
- {
- R_GAMETYPE_ITE,
- R_GAME_ITE_DISK,
- "Inherit the Earth - Disk version",
-
- &ITE_DisplayInfo,
-
- ITE_DEFAULT_SCENE,
-
- &ITE_Resources,
-
- ARRAYSIZE(ITEDISK_GameFiles),
- ITEDISK_GameFiles,
-
- ARRAYSIZE(ITEDISK_GameFonts),
- ITEDISK_GameFonts,
-
- &ITE_GameSound,
-
- 1
- },
-
- /* Inherit the earth - CD version
- \*-------------------------------------------------------------*/
- {
- R_GAMETYPE_ITE,
- R_GAME_ITE_CD,
- "Inherit the Earth - CD version",
-
- &ITE_DisplayInfo,
-
- ITE_DEFAULT_SCENE,
-
- &ITE_Resources,
-
- ARRAYSIZE( ITECD_GameFiles ),
- ITECD_GameFiles,
-
- ARRAYSIZE( ITECD_GameFonts ),
- ITECD_GameFonts,
-
- &ITECD_GameSound,
-
- 1
- },
-
- /* I Have No Mouth And I Must Scream - Demo version
- \*-------------------------------------------------------------*/
- {
- R_GAMETYPE_IHNM,
- R_GAME_IHNM_DEMO,
- "I Have No Mouth - Demo version",
-
- &IHNM_DisplayInfo,
-
- 0,
-
- &IHNM_Resources,
-
- ARRAYSIZE(IHNMDEMO_GameFiles),
- IHNMDEMO_GameFiles,
-
- 0,
- NULL,
-
- &IHNM_GameSound,
-
- 0
- },
-
- /* I Have No Mouth And I Must Scream - CD version
- \*-------------------------------------------------------------*/
- {
- R_GAMETYPE_IHNM,
- R_GAME_IHNM_CD,
- "I Have No Mouth - CD version",
-
- &IHNM_DisplayInfo,
-
- 1,
-
- &IHNM_Resources,
-
- ARRAYSIZE(IHNMCD_GameFiles),
- IHNMCD_GameFiles,
-
- ARRAYSIZE(IHNMCD_GameFonts),
- IHNMCD_GameFonts,
-
- &IHNM_GameSound,
-
- 1
- }
-};
-
-static R_GAMEMODULE GameModule;
-
-void setGameDirectory(const char *gamedir) {
- assert(gamedir != NULL);
-
- debug(1, "Using game data path: %s", gamedir);
-
- GameModule.game_dir = gamedir;
-}
-
-int detectGame() {
- File test_file;
-
- bool disqualified = false;
- bool found_game = false;
-
- int file_n;
- int file_ct;
- const char *file_name;
-
- int game_n;
- int game_ct = ARRAYSIZE(GameDescs);
-
- assert(GameModule.game_dir != NULL);
-
- for (game_n = 0; game_n < game_ct; game_n++) {
- disqualified = false;
-
- /* Attempt to open all files for this game
- * If we can open them all, then try to open all files on the
- * exclude list
- */
- file_ct = GameDescs[game_n].gd_filect;
-
- for (file_n = 0; file_n < file_ct; file_n++) {
- file_name = GameDescs[game_n].gd_filedescs[file_n].gf_fname;
- if (!test_file.open(file_name, GameModule.game_dir)) {
- disqualified = true;
- break;
- }
-
- test_file.close();
- }
-
- if (disqualified) {
- continue;
- }
-
- switch (GameDescs[game_n].gd_game_id) {
-
- case R_GAME_ITE_DEMO:
- disqualified = !verifyITEDEMO();
- break;
- case R_GAME_ITE_DISK:
- disqualified = !verifyITEDISK();
- break;
-
- default:
- break;
- }
-
- if (!disqualified) {
- found_game = true;
- break;
- }
- }
-
- if (found_game) {
- debug(1, "Found SAGA game: %s\n", GameDescs[game_n].gd_title);
- return game_n;
- }
-
- return -1;
-}
-
-bool openGame() {
- int game_filect;
-
- if ((GameModule.game_index = detectGame()) < 0) {
- error("Couldn't locate any valid SAGA games");
- return false;
- }
-
- assert(GameModule.game_index < ARRAYSIZE(GameDescs));
-
- if (!GameModule.game_dir) {
- return false;
- }
-
- game_filect = GameDescs[GameModule.game_index].gd_filect;
-
- GameModule.gfile_data = new R_GAME_FILEDATA[game_filect];
-
- return true;
-}
-
-bool verifyITEDEMO() {
- return true;
-}
-
-bool verifyITEDISK() {
- ResourceFile test_file;
- int32 script_lut_rn;
- int32 script_lut_len;
-
- /* Attempt to verify the disk version of Inherit the Earth
- * by examining the length of entries in the script lookup
- * table, which differs from the disk version and the CD
- * version.
- */
-
- assert (GameModule.game_dir != NULL);
-
- if (!test_file.open("ITE.RSC", GameModule.game_dir)) {
- return false;
- }
-
- script_lut_rn = GameDescs[R_GAME_ITE_DISK].gd_resource_info->script_lut_rn;
-
- script_lut_len = test_file.getResourceLen(script_lut_rn);
-
- if (script_lut_len % R_SCR_LUT_ENTRYLEN_ITEDISK == 0) {
- return true;
- }
-
- return false;
-}
-
-bool verifyITECD() {
- return true;
-}
-
-bool verifyIHNMDEMO() {
- return true;
-}
-
-bool verifyIHNMCD() {
- return true;
-}
-
-} // End of namespace Saga
diff --git a/saga/gamedesc_priv.h b/saga/gamedesc_priv.h
index b017ba7a90..ee8dd36909 100644
--- a/saga/gamedesc_priv.h
+++ b/saga/gamedesc_priv.h
@@ -1,5 +1,7 @@
/* ScummVM - Scumm Interpreter
- * Copyright (C) 2003 The ScummVM project
+ * 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
@@ -40,68 +42,64 @@ namespace Saga {
#define R_SCR_LUT_ENTRYLEN_ITECD 22
#define R_SCR_LUT_ENTRYLEN_ITEDISK 16
-typedef bool (ResourceFile::*R_GAME_VERIFYFUNC)();
+typedef bool(ResourceFile::*R_GAME_VERIFYFUNC) ();
typedef struct R_GAME_FILEDESC_tag {
- const char *gf_fname;
- unsigned int gf_type;
+ const char *gf_fname;
+ unsigned int gf_type;
} R_GAME_FILEDESC;
typedef struct R_GAMEDESC_tag {
- int gd_game_type;
- int gd_game_id;
+ int gd_game_type;
+ int gd_game_id;
- const char *gd_title;
+ const char *gd_title;
- R_GAME_DISPLAYINFO *gd_display_info;
+ R_GAME_DISPLAYINFO *gd_display_info;
- int gd_startscene;
+ int gd_startscene;
- R_GAME_RESOURCEINFO *gd_resource_info;
+ R_GAME_RESOURCEINFO *gd_resource_info;
- int gd_filect;
- R_GAME_FILEDESC *gd_filedescs;
-
- int gd_fontct;
- R_GAME_FONTDESC *gd_fontdescs;
-
- R_GAME_SOUNDINFO *gd_soundinfo;
+ int gd_filect;
+ R_GAME_FILEDESC *gd_filedescs;
- int gd_supported;
+ int gd_fontct;
+ R_GAME_FONTDESC *gd_fontdescs;
-} R_GAMEDESC;
+ R_GAME_SOUNDINFO *gd_soundinfo;
+ int gd_supported;
+} R_GAMEDESC;
typedef struct R_GAME_FILEDATA_tag {
- ResourceFile *file_ctxt;
-
- unsigned int file_types;
- unsigned int file_flags;
+ ResourceFile *file_ctxt;
+ unsigned int file_types;
+ unsigned int file_flags;
} R_GAME_FILEDATA;
-
typedef struct R_GAMEMODULE_tag {
- int game_init;
- int game_index;
-
- R_GAMEDESC *gamedesc;
+ int game_init;
+ int game_index;
+
+ R_GAMEDESC *gamedesc;
- int g_skipintro;
+ int g_skipintro;
- const char *game_dir;
-
- char game_language[R_GAME_LANGSTR_LIMIT];
+ const char *game_dir;
- unsigned int gfile_n;
- R_GAME_FILEDATA *gfile_data;
+ char game_language[R_GAME_LANGSTR_LIMIT];
- unsigned int gd_fontct;
- R_GAME_FONTDESC *gd_fontdescs;
+ unsigned int gfile_n;
+ R_GAME_FILEDATA *gfile_data;
- int err_n;
- const char *err_str;
+ unsigned int gd_fontct;
+ R_GAME_FONTDESC *gd_fontdescs;
+
+ int err_n;
+ const char *err_str;
} R_GAMEMODULE;
@@ -111,9 +109,5 @@ bool verifyITECD();
bool verifyIHNMDEMO();
bool verifyIHNMCD();
-} // End of namespace Saga
-
-#endif // SAGA_GAMEDESC_PRIV_H
-
-
-
+} // End of namespace Saga
+#endif // SAGA_GAMEDESC_PRIV_H
diff --git a/saga/gfx.cpp b/saga/gfx.cpp
new file mode 100644
index 0000000000..7ea6a5f342
--- /dev/null
+++ b/saga/gfx.cpp
@@ -0,0 +1,1098 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Misc. graphics routines
+
+ Notes:
+
+ Line drawing code utilizes Bresenham's run-length slice algorithm
+ described in "Michael Abrash's Graphics Programming Black Book",
+ Coriolis Group Books, 1997
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "yslib.h"
+
+#include "reinherit.h"
+
+/*
+ * Begin module component
+\*--------------------------------------------------------------------------*/
+#include "gfx_mod.h"
+#include "gfx.h"
+
+namespace Saga {
+
+int GFX_ClearSurface(char *buf, int w, int h, int p)
+{
+
+ int y;
+
+ for (y = 0; y < h; y++) {
+ memset(buf, 0, w);
+ buf += p;
+ }
+
+ return R_SUCCESS;
+}
+
+int GFX_ClearSurface16(char *buf, int w, int h, int p)
+{
+
+ int y;
+ w <<= 1;
+
+ for (y = 0; y < h; y++) {
+ memset(buf, 0, w);
+ buf += p;
+ }
+
+ return R_SUCCESS;
+}
+
+int GFX_DrawPalette(R_SURFACE * dst_s)
+{
+ int x;
+ int y;
+
+ int color = 0;
+
+ R_RECT pal_rect;
+
+ for (y = 0; y < 16; y++) {
+
+ pal_rect.y1 = (y * 8) + 4;
+ pal_rect.y2 = pal_rect.y1 + 8;
+
+ for (x = 0; x < 16; x++) {
+
+ pal_rect.x1 = (x * 8) + 4;
+ pal_rect.x2 = pal_rect.x1 + 8;
+
+ GFX_DrawRect(dst_s, &pal_rect, color);
+ color++;
+ }
+ }
+
+ return 0;
+}
+
+int GFX_SimpleBlit(R_SURFACE * dst_s, R_SURFACE * src_s)
+{
+ uchar *src_p;
+ uchar *dst_p;
+ int y, w, p;
+
+ assert((dst_s != NULL) && (src_s != NULL));
+ assert(dst_s->buf_w == src_s->buf_w);
+ assert(dst_s->buf_h == src_s->buf_h);
+
+ src_p = src_s->buf;
+ dst_p = dst_s->buf;
+
+ w = src_s->buf_w * (dst_s->bpp / 8);
+ p = src_s->buf_pitch;
+
+ for (y = 0; y < src_s->buf_h; y++) {
+
+ memcpy(dst_p, src_p, w);
+
+ dst_p += p;
+ src_p += p;
+ }
+
+ return R_SUCCESS;
+}
+
+int GFX_Scale2x(R_SURFACE * dst_s, R_SURFACE * src_s)
+{
+
+ assert((dst_s != NULL) && (src_s != NULL));
+ assert((dst_s->bpp == src_s->bpp));
+
+ switch (dst_s->bpp) {
+
+ case 8:
+ return GFX_Scale2x8(dst_s, src_s);
+ break;
+
+ case 16:
+ return GFX_Scale2x16(dst_s, src_s);
+ break;
+
+ default:
+ break;
+
+ }
+
+ return R_FAILURE;
+}
+
+int GFX_Scale2x8(R_SURFACE * dst_s, R_SURFACE * src_s)
+{
+
+ int y, x;
+
+ int src_skip = src_s->buf_pitch - src_s->buf_w;
+ int dst_skip = dst_s->buf_pitch - dst_s->buf_w;
+
+ uchar *src_ptr = src_s->buf;
+ uchar *dst_ptr = dst_s->buf;
+
+ uchar *src_row;
+ uchar *dst_row;
+
+ assert(dst_s->buf_w == (src_s->buf_w * 2));
+ assert(dst_s->buf_h == (src_s->buf_h * 2));
+
+ for (y = 0; y < src_s->buf_h; y++) {
+
+ src_row = src_ptr;
+ dst_row = dst_ptr;
+
+ for (x = 0; x < src_s->buf_w; x++) {
+ *dst_ptr++ = *src_ptr;
+ *dst_ptr++ = *src_ptr++;
+ }
+
+ dst_ptr += dst_skip;
+
+ memcpy(dst_ptr, dst_row, dst_s->buf_w);
+
+ dst_ptr += dst_s->buf_pitch;
+ src_ptr += src_skip;
+ }
+
+ return R_SUCCESS;
+}
+
+int GFX_Scale2x16(R_SURFACE * dst_s, R_SURFACE * src_s)
+{
+ int y, x;
+
+ int src_skip;
+ int dest_skip;
+
+ uchar *src_ptr = src_s->buf;
+ uchar *dest_ptr = dst_s->buf;
+
+ short *src_row;
+ short *dest_row;
+
+ assert((dst_s != NULL) && (src_s != NULL));
+
+ src_skip = (src_s->buf_pitch - src_s->buf_w) / sizeof(short);
+ dest_skip = (dst_s->buf_pitch - dst_s->buf_w) / sizeof(short);
+
+ for (y = 0; y < src_s->buf_h; y++) {
+
+ src_row = (short *)src_ptr;
+ dest_row = (short *)dest_ptr;
+
+ for (x = 0; x < src_s->buf_w; x++) {
+ *dest_row++ = *src_row;
+ *dest_row++ = *src_row++;
+ }
+
+ src_ptr += src_s->buf_pitch;
+
+ memcpy(dest_ptr + dst_s->buf_pitch, dest_ptr,
+ dst_s->buf_w << 1);
+
+ dest_ptr += dst_s->buf_pitch;
+ dest_ptr += dst_s->buf_pitch;
+ }
+
+ return R_SUCCESS;
+}
+
+int
+GFX_BufToSurface(R_SURFACE * ds,
+ const uchar * src,
+ int src_w, int src_h, R_RECT * src_rect, R_POINT * dst_pt)
+/*--------------------------------------------------------------------------*\
+ * Copies a rectangle from a raw 8 bit pixel buffer to the specified surface.
+ * The buffer is of width 'src_w' and height 'src_h'. The rectangle to be
+ * copied is defined by 'src_rect'.
+ * The rectangle is copied to the destination surface at point 'dst_pt'.
+ * - If dst_pt is NULL, the buffer is rectangle is copied to the destination
+ * origin.
+ * - If src_rect is NULL, the entire buffer is copied.
+ * - The surface must match the logical dimensions of the buffer exactly.
+ * - Returns R_FAILURE on error
+\*--------------------------------------------------------------------------*/
+{
+
+ const uchar *read_p;
+ uchar *write_p;
+
+ int row;
+
+ int s_x1, s_y1, s_x2, s_y2;
+ int d_x, d_y;
+
+ int clip_x1, clip_y1, clip_x2, clip_y2;
+
+ int dst_off_x, dst_off_y;
+ int src_off_x, src_off_y;
+ int src_draw_w, src_draw_h;
+
+ /* Clamp source rectangle to source buffer
+ * \*------------------------------------------------------------- */
+ if (src_rect != NULL) {
+
+ R_CLAMP_RECT(src_rect, 0, (src_w - 1), 0, (src_h - 1));
+
+ s_x1 = src_rect->x1;
+ s_y1 = src_rect->y1;
+ s_x2 = src_rect->x2;
+ s_y2 = src_rect->y2;
+
+ if ((s_x1 >= s_x2) || (s_y1 >= s_y2)) {
+ /* Empty or negative region */
+ return R_FAILURE;
+ }
+ } else {
+ s_x1 = 0;
+ s_y1 = 0;
+ s_x2 = src_w - 1;
+ s_y2 = src_h - 1;
+ }
+
+ /* Get destination origin and clip rectangle
+ * \*------------------------------------------------------------- */
+ if (dst_pt != NULL) {
+ d_x = dst_pt->x;
+ d_y = dst_pt->y;
+ } else {
+ d_x = 0;
+ d_y = 0;
+ }
+
+ clip_x1 = ds->clip_rect.x1;
+ clip_y1 = ds->clip_rect.y1;
+ clip_x2 = ds->clip_rect.x2;
+ clip_y2 = ds->clip_rect.y2;
+
+ if (clip_x1 == clip_x2) {
+ clip_x1 = 0;
+ clip_x2 = ds->buf_w - 1;
+ }
+
+ if (clip_y1 == clip_y2) {
+ clip_y1 = 0;
+ clip_y2 = ds->buf_h - 1;
+ }
+
+ /* Clip source rectangle to destination surface
+ * \*------------------------------------------------------------- */
+ dst_off_x = d_x;
+ dst_off_y = d_y;
+ src_off_x = s_x1;
+ src_off_y = s_y1;
+ src_draw_w = (s_x2 - s_x1) + 1;
+ src_draw_h = (s_y2 - s_y1) + 1;
+
+ /* Clip to left edge */
+
+ if (d_x < clip_x1) {
+ if (d_x <= (-src_draw_w)) {
+ /* dst rect completely off left edge */
+ return R_SUCCESS;
+ }
+
+ src_off_x += (clip_x1 - d_x);
+ src_draw_w -= (clip_x1 - d_x);
+
+ dst_off_x = clip_x1;
+ }
+
+ /* Clip to top edge */
+
+ if (d_y < clip_y1) {
+ if (d_y >= (-src_draw_h)) {
+ /* dst rect completely off top edge */
+ return R_SUCCESS;
+ }
+
+ src_off_y += (clip_y1 - d_y);
+ src_draw_h -= (clip_y1 - d_y);
+
+ dst_off_y = clip_y1;
+ }
+
+ /* Clip to right edge */
+
+ if (d_x > clip_x2) {
+ /* dst rect completely off right edge */
+ return R_SUCCESS;
+ }
+
+ if ((d_x + src_draw_w - 1) > clip_x2) {
+ src_draw_w -= (clip_x2 - (d_x + src_draw_w - 1));
+ }
+
+ /* Clip to bottom edge */
+
+ if (d_x > clip_y2) {
+ /* dst rect completely off bottom edge */
+ return R_SUCCESS;
+ }
+
+ if ((d_y + src_draw_h - 1) > clip_y2) {
+ src_draw_h -= (clip_y2 - (d_y + src_draw_h - 1));
+ }
+
+ /* Transfer buffer data to surface
+ * \*------------------------------------------------------------- */
+ read_p = (src + src_off_x) + (src_w * src_off_y);
+ write_p = (ds->buf + dst_off_x) + (ds->buf_pitch * dst_off_y);
+
+ for (row = 0; row < src_draw_h; row++) {
+
+ memcpy(write_p, read_p, src_draw_w);
+
+ write_p += ds->buf_pitch;
+ read_p += src_w;
+ }
+
+ return R_SUCCESS;
+}
+
+int
+GFX_BufToBuffer(uchar * dst_buf,
+ int dst_w,
+ int dst_h,
+ const uchar * src,
+ int src_w, int src_h, R_RECT * src_rect, R_POINT * dst_pt)
+/*--------------------------------------------------------------------------*\
+\*--------------------------------------------------------------------------*/
+{
+
+ const uchar *read_p;
+ uchar *write_p;
+
+ int row;
+
+ int s_x1, s_y1, s_x2, s_y2;
+ int d_x, d_y;
+
+ int clip_x1, clip_y1, clip_x2, clip_y2;
+
+ int dst_off_x, dst_off_y;
+ int src_off_x, src_off_y;
+ int src_draw_w, src_draw_h;
+
+ /* Clamp source rectangle to source buffer
+ * \*------------------------------------------------------------- */
+ if (src_rect != NULL) {
+
+ R_CLAMP_RECT(src_rect, 0, (src_w - 1), 0, (src_h - 1));
+
+ s_x1 = src_rect->x1;
+ s_y1 = src_rect->y1;
+ s_x2 = src_rect->x2;
+ s_y2 = src_rect->y2;
+
+ if ((s_x1 >= s_x2) || (s_y1 >= s_y2)) {
+ /* Empty or negative region */
+ return R_FAILURE;
+ }
+ } else {
+ s_x1 = 0;
+ s_y1 = 0;
+ s_x2 = src_w - 1;
+ s_y2 = src_h - 1;
+ }
+
+ /* Get destination origin and clip rectangle
+ * \*------------------------------------------------------------- */
+ if (dst_pt != NULL) {
+ d_x = dst_pt->x;
+ d_y = dst_pt->y;
+ } else {
+ d_x = 0;
+ d_y = 0;
+ }
+
+ clip_x1 = 0;
+ clip_y1 = 0;
+ clip_x2 = dst_w - 1;
+ clip_y2 = dst_h - 1;
+
+ /* Clip source rectangle to destination surface
+ * \*------------------------------------------------------------- */
+ dst_off_x = d_x;
+ dst_off_y = d_y;
+ src_off_x = s_x1;
+ src_off_y = s_y1;
+ src_draw_w = (s_x2 - s_x1) + 1;
+ src_draw_h = (s_y2 - s_y1) + 1;
+
+ /* Clip to left edge */
+
+ if (d_x < clip_x1) {
+ if (d_x <= (-src_draw_w)) {
+ /* dst rect completely off left edge */
+ return R_SUCCESS;
+ }
+
+ src_off_x += (clip_x1 - d_x);
+ src_draw_w -= (clip_x1 - d_x);
+
+ dst_off_x = clip_x1;
+ }
+
+ /* Clip to top edge */
+
+ if (d_y < clip_y1) {
+ if (d_y >= (-src_draw_h)) {
+ /* dst rect completely off top edge */
+ return R_SUCCESS;
+ }
+
+ src_off_y += (clip_y1 - d_y);
+ src_draw_h -= (clip_y1 - d_y);
+
+ dst_off_y = clip_y1;
+ }
+
+ /* Clip to right edge */
+
+ if (d_x > clip_x2) {
+ /* dst rect completely off right edge */
+ return R_SUCCESS;
+ }
+
+ if ((d_x + src_draw_w - 1) > clip_x2) {
+ src_draw_w -= (clip_x2 - (d_x + src_draw_w - 1));
+ }
+
+ /* Clip to bottom edge */
+
+ if (d_x > clip_y2) {
+ /* dst rect completely off bottom edge */
+ return R_SUCCESS;
+ }
+
+ if ((d_y + src_draw_h - 1) > clip_y2) {
+ src_draw_h -= (clip_y2 - (d_y + src_draw_h - 1));
+ }
+
+ /* Transfer buffer data to surface
+ * \*------------------------------------------------------------- */
+ read_p = (src + src_off_x) + (src_w * src_off_y);
+ write_p = (dst_buf + dst_off_x) + (dst_w * dst_off_y);
+
+ for (row = 0; row < src_draw_h; row++) {
+
+ memcpy(write_p, read_p, src_draw_w);
+
+ write_p += dst_w;
+ read_p += src_w;
+ }
+
+ return R_SUCCESS;
+}
+
+int GFX_DrawCursor(R_SURFACE * ds, R_POINT * p1)
+{
+
+ static uchar cursor_img[R_CURSOR_W * R_CURSOR_H] = {
+
+ 0, 0, 0, 255, 0, 0, 0,
+ 0, 0, 0, 255, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+ 255, 255, 0, 0, 0, 255, 255,
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 255, 0, 0, 0,
+ 0, 0, 0, 255, 0, 0, 0
+ };
+
+ R_CLIPINFO ci;
+
+ uchar *src_p, *dst_p;
+
+ int x, y;
+ int src_skip, dst_skip;
+
+ R_POINT cur_pt;
+ R_RECT cur_rect;
+
+ /* Clamp point to surface */
+ cur_pt.x = YS_MAX(p1->x, 0);
+ cur_pt.y = YS_MAX(p1->y, 0);
+
+ cur_pt.x = YS_MIN(p1->x, ds->buf_w - 1);
+ cur_pt.y = YS_MIN(p1->y, ds->buf_h - 1);
+
+ cur_pt.x -= R_CURSOR_ORIGIN_X;
+ cur_pt.y -= R_CURSOR_ORIGIN_Y;
+
+ /* Clip cursor to surface */
+
+ cur_rect.x1 = 0;
+ cur_rect.y1 = 0;
+ cur_rect.x2 = R_CURSOR_W - 1;
+ cur_rect.y2 = R_CURSOR_H - 1;
+
+ ci.dst_rect = &ds->clip_rect;
+ ci.src_rect = &cur_rect;
+ ci.dst_pt = &cur_pt;
+
+ GFX_GetClipInfo(&ci);
+
+ src_p = cursor_img + ci.src_draw_x + (ci.src_draw_y * R_CURSOR_W);
+ dst_p = ds->buf + ci.dst_draw_x + (ci.dst_draw_y * ds->buf_pitch);
+
+ src_skip = R_CURSOR_W - ci.draw_w;
+ dst_skip = ds->buf_pitch - ci.draw_w;
+
+ for (y = 0; y < ci.draw_h; y++) {
+
+ for (x = 0; x < ci.draw_w; x++) {
+
+ if (*src_p != 0) {
+ *dst_p = *src_p;
+ }
+
+ dst_p++;
+ src_p++;
+ }
+
+ src_p += src_skip;
+ dst_p += dst_skip;
+ }
+
+ return R_SUCCESS;
+
+}
+
+int GFX_DrawRect(R_SURFACE * ds, R_RECT * dst_rect, int color)
+/*--------------------------------------------------------------------------*\
+ * Fills a rectangle in the surface ds from point 'p1' to point 'p2' using
+ * the specified color.
+\*--------------------------------------------------------------------------*/
+{
+ uchar *write_p;
+
+ int w;
+ int h;
+ int row;
+
+ int x1, y1, x2, y2;
+
+ if (dst_rect != NULL) {
+
+ R_CLAMP_RECT(dst_rect, 0, (ds->buf_w - 1), 0, (ds->buf_h - 1));
+
+ x1 = dst_rect->x1;
+ y1 = dst_rect->y1;
+ x2 = dst_rect->x2;
+ y2 = dst_rect->y2;
+
+ if ((x1 >= x2) || (y1 >= y2)) {
+ /* Empty or negative region */
+ return R_FAILURE;
+ }
+ } else {
+ x1 = 0;
+ y1 = 0;
+ x2 = ds->buf_w - 1;
+ y2 = ds->buf_h - 1;
+ }
+
+ w = (x2 - x1) + 1;
+ h = (y2 - y1) + 1;
+
+ write_p = ds->buf + (ds->buf_pitch * y1) + x1;
+
+ for (row = 0; row < h; row++) {
+ memset(write_p, color, w);
+ write_p += ds->buf_pitch;
+ }
+
+ return R_SUCCESS;
+}
+
+int GFX_DrawFrame(R_SURFACE * ds, R_POINT * p1, R_POINT * p2, int color)
+{
+ int x1, y1, x2, y2;
+
+ int min_x;
+ int max_x;
+ int min_y;
+ int max_y;
+
+ R_POINT n_p1; /* 1 .. 2 */
+ R_POINT n_p2; /* . . */
+ R_POINT n_p3; /* . . */
+ R_POINT n_p4; /* 4 .. 3 */
+
+ assert((ds != NULL) && (p1 != NULL) && (p2 != NULL));
+
+ x1 = p1->x;
+ y1 = p1->y;
+ x2 = p2->x;
+ y2 = p2->y;
+
+ min_x = YS_MIN(x1, x2);
+ min_y = YS_MIN(y1, y2);
+ max_x = YS_MAX(x1, x2);
+ max_y = YS_MAX(y1, y2);
+
+ n_p1.x = min_x;
+ n_p1.y = min_y;
+ n_p2.x = max_x;
+ n_p2.y = min_y;
+ n_p3.x = max_x;
+ n_p3.y = max_y;
+ n_p4.x = min_x;
+ n_p4.y = max_y;
+
+ GFX_DrawLine(ds, &n_p1, &n_p2, color);
+ GFX_DrawLine(ds, &n_p2, &n_p3, color);
+ GFX_DrawLine(ds, &n_p3, &n_p4, color);
+ GFX_DrawLine(ds, &n_p4, &n_p1, color);
+
+ return R_SUCCESS;
+}
+
+int GFX_DrawPolyLine(R_SURFACE * ds, R_POINT * pts, int pt_ct, int draw_color)
+{
+
+ R_POINT *first_pt = pts;
+ int last_i = 1;
+ int i;
+
+ assert((ds != NULL) & (pts != NULL));
+
+ if (pt_ct < 3) {
+ return R_FAILURE;
+ }
+
+ for (i = 1; i < pt_ct; i++) {
+
+ GFX_DrawLine(ds, &pts[i], &pts[i - 1], draw_color);
+ last_i = i;
+ }
+
+ GFX_DrawLine(ds, &pts[last_i], first_pt, draw_color);
+
+ return R_SUCCESS;
+}
+
+int GFX_GetClipInfo(R_CLIPINFO * clipinfo)
+{
+
+ int s_x1, s_y1, s_x2, s_y2;
+ int d_x, d_y;
+
+ int clip_x1, clip_y1, clip_x2, clip_y2;
+
+ if (clipinfo == NULL) {
+ return R_FAILURE;
+ }
+
+ if (clipinfo->dst_pt != NULL) {
+ d_x = clipinfo->dst_pt->x;
+ d_y = clipinfo->dst_pt->y;
+ } else {
+ d_x = 0;
+ d_y = 0;
+ }
+
+ s_x1 = clipinfo->src_rect->x1;
+ s_y1 = clipinfo->src_rect->y1;
+ s_x2 = clipinfo->src_rect->x2;
+ s_y2 = clipinfo->src_rect->y2;
+
+ clip_x1 = clipinfo->dst_rect->x1;
+ clip_y1 = clipinfo->dst_rect->y1;
+ clip_x2 = clipinfo->dst_rect->x2;
+ clip_y2 = clipinfo->dst_rect->y2;
+
+ /* Clip source rectangle to destination surface
+ * \*------------------------------------------------------------- */
+ clipinfo->dst_draw_x = d_x;
+ clipinfo->dst_draw_y = d_y;
+ clipinfo->src_draw_x = s_x1;
+ clipinfo->src_draw_y = s_y1;
+ clipinfo->draw_w = (s_x2 - s_x1) + 1;
+ clipinfo->draw_h = (s_y2 - s_y1) + 1;
+
+ clipinfo->nodraw = 0;
+
+ /* Clip to left edge */
+
+ if (d_x < clip_x1) {
+ if (d_x <= -(clipinfo->draw_w)) {
+ /* dst rect completely off left edge */
+ clipinfo->nodraw = 1;
+
+ return R_SUCCESS;
+ }
+
+ clipinfo->src_draw_x += (clip_x1 - d_x);
+ clipinfo->draw_w -= (clip_x1 - d_x);
+
+ clipinfo->dst_draw_x = clip_x1;
+ }
+
+ /* Clip to top edge */
+
+ if (d_y < clip_y1) {
+ if (d_y <= -(clipinfo->draw_h)) {
+ /* dst rect completely off top edge */
+ clipinfo->nodraw = 1;
+
+ return R_SUCCESS;
+ }
+
+ clipinfo->src_draw_y += (clip_y1 - d_y);
+ clipinfo->draw_h -= (clip_y1 - d_y);
+
+ clipinfo->dst_draw_y = clip_y1;
+ }
+
+ /* Clip to right edge */
+
+ if (d_x > clip_x2) {
+ /* dst rect completely off right edge */
+ clipinfo->nodraw = 1;
+
+ return R_SUCCESS;
+ }
+
+ if ((d_x + clipinfo->draw_w - 1) > clip_x2) {
+ clipinfo->draw_w += (clip_x2 - (d_x + clipinfo->draw_w - 1));
+ }
+
+ /* Clip to bottom edge */
+
+ if (d_y > clip_y2) {
+ /* dst rect completely off bottom edge */
+ clipinfo->nodraw = 1;
+
+ return R_SUCCESS;
+ }
+
+ if ((d_y + clipinfo->draw_h - 1) > clip_y2) {
+ clipinfo->draw_h += (clip_y2 - (d_y + clipinfo->draw_h - 1));
+ }
+
+ return R_SUCCESS;
+}
+
+int
+GFX_ClipLine(R_SURFACE * ds,
+ const R_POINT * src_p1,
+ const R_POINT * src_p2, R_POINT * dst_p1, R_POINT * dst_p2)
+{
+
+ const R_POINT *n_p1;
+ const R_POINT *n_p2;
+
+ int clip_x1, clip_y1, clip_x2, clip_y2;
+ int x1, y1, x2, y2;
+ int dx, dy;
+
+ float m;
+ int y_icpt_l, y_icpt_r;
+
+ clip_x1 = ds->clip_rect.x1;
+ clip_y1 = ds->clip_rect.y1;
+ clip_x2 = ds->clip_rect.x2;
+ clip_y2 = ds->clip_rect.y2;
+
+ /* Normalize points by x */
+ if (src_p1->x < src_p2->x) {
+ n_p1 = src_p1;
+ n_p2 = src_p2;
+ } else {
+ n_p1 = src_p2;
+ n_p2 = src_p1;
+ }
+
+ dst_p1->x = n_p1->x;
+ dst_p1->y = n_p1->y;
+
+ dst_p2->x = n_p2->x;
+ dst_p2->y = n_p2->y;
+
+ x1 = n_p1->x;
+ y1 = n_p1->y;
+
+ x2 = n_p2->x;
+ y2 = n_p2->y;
+
+ dx = x2 - x1;
+ dy = y2 - y1;
+
+ if (x1 < 0) {
+
+ if (x2 < 0) {
+ /* Line completely off left edge */
+ return -1;
+ }
+
+ /* Clip to left edge */
+ m = ((float)y2 - y1) / (x2 - x1);
+ y_icpt_l = (int)(y1 - (x1 * m) + 0.5f);
+
+ dst_p1->x = 0;
+ dst_p1->y = y_icpt_l;
+ }
+
+ if (y2 > clip_x2) {
+
+ if (x1 > clip_x2) {
+ /* Line completely off right edge */
+ return -1;
+ }
+
+ /* Clip to right edge */
+ m = ((float)y1 - y2) / (x2 - x1);
+ y_icpt_r = (int)(y1 - ((clip_x2 - x1) * m) + 0.5f);
+
+ dst_p1->y = y_icpt_r;
+ dst_p2->x = clip_x2;
+ }
+
+ return 1;
+}
+
+void GFX_DrawLine(R_SURFACE * ds, R_POINT * p1, R_POINT * p2, int color)
+/*--------------------------------------------------------------------------*\
+ * Utilizes Bresenham's run-length slice algorithm described in
+ * "Michael Abrash's Graphics Programming Black Book",
+ * Coriolis Group Books, 1997
+ *
+ * Performs no clipping
+\*--------------------------------------------------------------------------*/
+{
+
+ uchar *write_p;
+
+ int clip_result;
+
+ int temp;
+
+ int error_up, error_down;
+ int error;
+
+ int x_vector;
+ int dx, dy;
+
+ int min_run;
+ int init_run;
+ int run;
+ int end_run;
+
+ R_POINT clip_p1, clip_p2;
+ int x1, y1, x2, y2;
+ int i, k;
+
+ clip_result = GFX_ClipLine(ds, p1, p2, &clip_p1, &clip_p2);
+ if (clip_result < 0) {
+ /* Line not visible */
+ return;
+ }
+
+ x1 = clip_p1.x;
+ y1 = clip_p1.y;
+
+ x2 = clip_p2.x;
+ y2 = clip_p2.y;
+
+ if ((x1 < ds->clip_rect.x1) || (x2 < ds->clip_rect.x1) ||
+ (x1 > ds->clip_rect.x2) || (x2 > ds->clip_rect.x2)) {
+
+ return;
+ }
+
+ if ((y1 < ds->clip_rect.y1) || (y2 < ds->clip_rect.y1) ||
+ (y1 > ds->clip_rect.y2) || (y2 > ds->clip_rect.y2)) {
+
+ return;
+ }
+
+ if (y1 > y2) {
+
+ temp = y1;
+ y1 = y2;
+ y2 = temp;
+
+ temp = x1;
+ x1 = x2;
+ x2 = temp;
+ }
+
+ write_p = ds->buf + (y1 * ds->buf_pitch) + x1;
+
+ dx = x2 - x1;
+
+ if (dx < 0) {
+ x_vector = -1;
+ dx = -dx;
+ } else {
+ x_vector = 1;
+ }
+
+ dy = y2 - y1;
+
+ if (dx == 0) {
+ for (i = 0; i <= dy; i++) {
+ *write_p = (uchar) color;
+ write_p += ds->buf_pitch;
+ }
+ return;
+ }
+ if (dy == 0) {
+ for (i = 0; i <= dx; i++) {
+ *write_p = (uchar) color;
+ write_p += x_vector;
+ }
+ return;
+ }
+ if (dx == dy) {
+ for (i = 0; i <= dx; i++) {
+ *write_p = (uchar) color;
+ write_p += x_vector + ds->buf_pitch;
+ }
+ return;
+ }
+
+ if (dx >= dy) {
+
+ min_run = dx / dy;
+ error_up = (dx % dy) * 2;
+ error_down = dy * 2;
+ error = (dx % dy) - (dy * 2);
+ init_run = (min_run / 2) + 1;
+ end_run = init_run;
+
+ if ((error_up == 0) && (min_run & 0x01) == 0) {
+ init_run--;
+ }
+
+ error += dy;
+
+ /* Horiz. seg */
+ for (k = 0; k < init_run; k++) {
+ *write_p = (uchar) color;
+ write_p += x_vector;
+ }
+ write_p += ds->buf_pitch;
+ /**********/
+
+ for (i = 0; i < (dy - 1); i++) {
+ run = min_run;
+ if ((error += error_up) > 0) {
+
+ run++;
+ error -= error_down;
+ }
+
+ /* Horiz. seg */
+ for (k = 0; k < run; k++) {
+ *write_p = (uchar) color;
+ write_p += x_vector;
+ }
+ write_p += ds->buf_pitch;
+ /**********/
+ }
+
+ /* Horiz. seg */
+ for (k = 0; k < end_run; k++) {
+ *write_p = (uchar) color;
+ write_p += x_vector;
+ }
+ write_p += ds->buf_pitch;
+ /**********/
+ return;
+
+ } else {
+
+ min_run = dy / dx;
+
+ error_up = (dy % dx) * 2;
+
+ error_down = dx * 2;
+ error = (dy % dx) - (dx * 2);
+
+ init_run = (min_run / 2) + 1;
+ end_run = init_run;
+
+ if ((error_up == 0) && ((min_run & 0x01) == 0)) {
+ init_run--;
+ }
+
+ if ((min_run & 0x01) != 0) {
+ error += dx;
+ }
+
+ /* Vertical seg */
+ for (k = 0; k < init_run; k++) {
+ *write_p = (uchar) color;
+ write_p += ds->buf_pitch;
+ }
+ write_p += x_vector;
+ /***********/
+
+ for (i = 0; i < (dx - 1); i++) {
+ run = min_run;
+ if ((error += error_up) > 0) {
+ run++;
+ error -= error_down;
+ }
+
+ /* Vertical seg */
+ for (k = 0; k < run; k++) {
+ *write_p = (uchar) color;
+ write_p += ds->buf_pitch;
+ }
+ write_p += x_vector;
+ /***********/
+ }
+
+ /* Vertical seg */
+ for (k = 0; k < end_run; k++) {
+ *write_p = (uchar) color;
+ write_p += ds->buf_pitch;
+ }
+ write_p += x_vector;
+ /***********/
+ return;
+ }
+
+ return;
+}
+
+} // End of namespace Saga
diff --git a/saga/gfx.h b/saga/gfx.h
new file mode 100644
index 0000000000..99389e91d2
--- /dev/null
+++ b/saga/gfx.h
@@ -0,0 +1,54 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Graphics maniuplation routines - private header file
+
+ Notes:
+*/
+
+#ifndef SAGA_GFX_H_
+#define SAGA_GFX_H_
+
+namespace Saga {
+
+#define R_CURSOR_W 7
+#define R_CURSOR_H 7
+
+#define R_CURSOR_ORIGIN_X 4
+#define R_CURSOR_ORIGIN_Y 4
+
+#define R_CLAMP(a, min, max) \
+ (a = (a < (min)) ? (min) : ((a > max) ? (max) : a ))
+
+#define R_CLAMP_RECT( rect, xmin, xmax, ymin, ymax ) \
+ R_CLAMP( rect->x1, xmin, xmax ); \
+ R_CLAMP( rect->x2, xmin, xmax ); \
+ R_CLAMP( rect->y1, ymin, ymax ); \
+ R_CLAMP( rect->y2, ymin, ymax )
+
+} // End of namespace Saga
+
+#endif /* R_GFX_H_ */
+/* end "r_gfx_h_ */
diff --git a/saga/gfx_mod.h b/saga/gfx_mod.h
new file mode 100644
index 0000000000..bfb0fc76a5
--- /dev/null
+++ b/saga/gfx_mod.h
@@ -0,0 +1,99 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Graphics manipulation routines - module header file
+
+ Notes:
+*/
+
+#ifndef SAGA_GFX_MOD_H_
+#define SAGA_GFX_MOD_H_
+
+namespace Saga {
+
+typedef struct R_CLIPINFO_tag {
+
+ /* input members */
+ const R_RECT *src_rect;
+ const R_RECT *dst_rect;
+ const R_POINT *dst_pt;
+
+ /* output members */
+ int nodraw;
+ int src_draw_x;
+ int src_draw_y;
+ int dst_draw_x;
+ int dst_draw_y;
+ int draw_w;
+ int draw_h;
+
+} R_CLIPINFO;
+
+int GFX_SimpleBlit(R_SURFACE * dst_s, R_SURFACE * src_s);
+
+int GFX_Scale2x(R_SURFACE * dst_s, R_SURFACE * src_s);
+
+int GFX_Scale2x8(R_SURFACE * dst_s, R_SURFACE * src_s);
+
+int GFX_Scale2x16(R_SURFACE * dst_s, R_SURFACE * src_s);
+
+int GFX_SLScale2x16(char *dest_buf,
+ int dest_w,
+ int dest_p, int dst_h, char *src_buf, int src_w, int src_p, int src_h);
+
+int GFX_ClearSurface(char *buf, int w, int h, int p);
+int GFX_ClearSurface16(char *buf, int w, int h, int p);
+
+int GFX_DrawPalette(R_SURFACE * dst_s);
+
+int GFX_BufToSurface(R_SURFACE * ds,
+ const uchar * src,
+ int src_w, int src_h, R_RECT * src_rect, R_POINT * dst_pt);
+
+int
+GFX_BufToBuffer(uchar * dst_buf,
+ int dst_w,
+ int dst_h,
+ const uchar * src,
+ int src_w, int src_h, R_RECT * src_rect, R_POINT * dst_pt);
+
+int GFX_DrawCursor(R_SURFACE * ds, R_POINT * p1);
+int GFX_DrawRect(R_SURFACE * ds, R_RECT * dst_rect, int color);
+int GFX_DrawFrame(R_SURFACE * ds, R_POINT * p1, R_POINT * p2, int color);
+int GFX_DrawPolyLine(R_SURFACE * ds, R_POINT * pts, int pt_ct, int draw_color);
+
+int GFX_GetClipInfo(R_CLIPINFO * clipinfo);
+
+int
+GFX_ClipLine(R_SURFACE * ds,
+ const R_POINT * src_p1,
+ const R_POINT * src_p2, R_POINT * dst_p1, R_POINT * dst_p2);
+
+void GFX_DrawLine(R_SURFACE * ds, R_POINT * p1, R_POINT * p2, int color);
+
+} // End of namespace Saga
+
+#endif /* R_GFX_MOD_H_ */
+/* end "r_gfx_mod.h" */
diff --git a/saga/ihnm_introproc.cpp b/saga/ihnm_introproc.cpp
new file mode 100644
index 0000000000..8656881f14
--- /dev/null
+++ b/saga/ihnm_introproc.cpp
@@ -0,0 +1,360 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ "I Have No Mouth" Intro sequence scene procedures
+
+ Notes:
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "yslib.h"
+
+#include "reinherit.h"
+
+/*
+ * Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "animation_mod.h"
+#include "cvar_mod.h"
+#include "events_mod.h"
+#include "font_mod.h"
+#include "rscfile_mod.h"
+#include "scene_mod.h"
+#include "text_mod.h"
+#include "palanim_mod.h"
+
+/*
+ * Begin module:
+\*--------------------------------------------------------------------------*/
+#include "scene.h"
+#include "ihnm_introproc.h"
+
+namespace Saga {
+
+R_SCENE_RESLIST IHNM_IntroMovie1RL[] = {
+
+ {30, SAGA_BG_IMAGE}
+ ,
+ {31, SAGA_ANIM_1}
+};
+
+R_SCENE_DESC IHNM_IntroMovie1Desc = {
+
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ IHNM_IntroMovie1RL,
+ YS_NELEMS(IHNM_IntroMovie1RL)
+
+};
+
+R_SCENE_RESLIST IHNM_IntroMovie2RL[] = {
+
+ {32, SAGA_BG_IMAGE}
+ ,
+ {33, SAGA_ANIM_1}
+};
+
+R_SCENE_DESC IHNM_IntroMovie2Desc = {
+
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ IHNM_IntroMovie2RL,
+ YS_NELEMS(IHNM_IntroMovie2RL)
+
+};
+
+R_SCENE_RESLIST IHNM_IntroMovie3RL[] = {
+
+ {34, SAGA_BG_IMAGE}
+ ,
+ {35, SAGA_ANIM_1}
+};
+
+R_SCENE_DESC IHNM_IntroMovie3Desc = {
+
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ IHNM_IntroMovie3RL,
+ YS_NELEMS(IHNM_IntroMovie3RL)
+
+};
+
+R_SCENE_RESLIST IHNM_IntroMovie4RL[] = {
+
+ {1227, SAGA_BG_IMAGE}
+ ,
+ {1226, SAGA_ANIM_1}
+};
+
+R_SCENE_DESC IHNM_IntroMovie4Desc = {
+
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ IHNM_IntroMovie4RL,
+ YS_NELEMS(IHNM_IntroMovie4RL)
+
+};
+
+R_SCENE_QUEUE IHNM_IntroList[] = {
+ {0, &IHNM_IntroMovie1Desc, BY_DESC, IHNM_IntroMovieProc1, 0}
+ ,
+ {0, &IHNM_IntroMovie2Desc, BY_DESC, IHNM_IntroMovieProc2, 0}
+ ,
+ {0, &IHNM_IntroMovie3Desc, BY_DESC, IHNM_IntroMovieProc3, 0}
+ ,
+ {0, &IHNM_IntroMovie4Desc, BY_DESC, IHNM_HateProc, 0}
+};
+
+int IHNM_StartProc(void)
+{
+ size_t n_introscenes;
+ size_t i;
+
+ n_introscenes = YS_NELEMS(IHNM_IntroList);
+
+ for (i = 0; i < n_introscenes; i++) {
+
+ SCENE_Queue(&IHNM_IntroList[i]);
+ }
+
+ return R_SUCCESS;
+}
+
+int IHNM_IntroMovieProc1(int param, R_SCENE_INFO * scene_info)
+{
+
+ R_EVENT event = { 0 };
+
+ YS_IGNORE_PARAM(scene_info);
+
+ switch (param) {
+
+ case SCENE_BEGIN:
+
+ /* Background for intro scene is the first frame of the
+ * intro animation; display it and set the palette
+ \*-----------------------------------------------------*/
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_BG_EVENT;
+ event.op = EVENT_DISPLAY;
+ event.param = SET_PALETTE;
+ event.time = 0;
+
+ EVENT_Queue(&event);
+
+ ANIM_SetFrameTime(0, R_IHNM_INTRO_FRAMETIME);
+ ANIM_SetFlag(0, ANIM_ENDSCENE);
+ ANIM_Play(0, 0);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int IHNM_IntroMovieProc2(int param, R_SCENE_INFO * scene_info)
+{
+
+ R_EVENT event = { 0 };
+ R_EVENT *q_event;
+
+ PALENTRY *pal;
+
+ static PALENTRY current_pal[R_PAL_ENTRIES];
+
+ YS_IGNORE_PARAM(scene_info);
+
+ switch (param) {
+
+ case SCENE_BEGIN:
+
+ /* Fade to black out of the intro CyberDreams logo anim
+ * \*----------------------------------------------------- */
+ SYSGFX_GetCurrentPal(current_pal);
+
+ event.type = R_CONTINUOUS_EVENT;
+ event.code = R_PAL_EVENT;
+ event.op = EVENT_PALTOBLACK;
+ event.time = 0;
+ event.duration = R_IHNM_PALFADE_TIME;
+ event.data = current_pal;
+
+ q_event = EVENT_Queue(&event);
+
+ /* Background for intro scene is the first frame of the
+ * intro animation; display it but don't set palette
+ \*-----------------------------------------------------*/
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_BG_EVENT;
+ event.op = EVENT_DISPLAY;
+ event.param = NO_SET_PALETTE;
+ event.time = 0;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ /* Fade in from black to the scene background palette
+ * \*----------------------------------------------------- */
+ SCENE_GetBGPal(&pal);
+
+ event.type = R_CONTINUOUS_EVENT;
+ event.code = R_PAL_EVENT;
+ event.op = EVENT_BLACKTOPAL;
+ event.time = 0;
+ event.duration = R_IHNM_PALFADE_TIME;
+ event.data = pal;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ ANIM_SetFlag(0, ANIM_LOOP);
+ ANIM_Play(0, R_IHNM_PALFADE_TIME * 2);
+
+ /* Queue end of scene after looping animation for a while
+ * \*----------------------------------------------------- */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_SCENE_EVENT;
+ event.op = EVENT_END;
+ event.time = R_IHNM_DGLOGO_TIME;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int IHNM_IntroMovieProc3(int param, R_SCENE_INFO * scene_info)
+{
+
+ R_EVENT event = { 0 };
+ R_EVENT *q_event;
+
+ PALENTRY *pal;
+
+ static PALENTRY current_pal[R_PAL_ENTRIES];
+
+ YS_IGNORE_PARAM(scene_info);
+
+ switch (param) {
+
+ case SCENE_BEGIN:
+
+ /* Fade to black out of the intro DG logo anim
+ * \*----------------------------------------------------- */
+ SYSGFX_GetCurrentPal(current_pal);
+
+ event.type = R_CONTINUOUS_EVENT;
+ event.code = R_PAL_EVENT;
+ event.op = EVENT_PALTOBLACK;
+ event.time = 0;
+ event.duration = R_IHNM_PALFADE_TIME;
+ event.data = current_pal;
+
+ q_event = EVENT_Queue(&event);
+
+ /* Background for intro scene is the first frame of the
+ * intro animation; display it but don't set palette
+ \*-----------------------------------------------------*/
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_BG_EVENT;
+ event.op = EVENT_DISPLAY;
+ event.param = NO_SET_PALETTE;
+ event.time = 0;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ /* Fade in from black to the scene background palette
+ * \*----------------------------------------------------- */
+ SCENE_GetBGPal(&pal);
+
+ event.type = R_CONTINUOUS_EVENT;
+ event.code = R_PAL_EVENT;
+ event.op = EVENT_BLACKTOPAL;
+ event.time = 0;
+ event.duration = R_IHNM_PALFADE_TIME;
+ event.data = pal;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ ANIM_Play(0, 0);
+
+ /* Queue end of scene after a while
+ * \*----------------------------------------------------- */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_SCENE_EVENT;
+ event.op = EVENT_END;
+ event.time = R_IHNM_TITLE_TIME;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int IHNM_HateProc(int param, R_SCENE_INFO * scene_info)
+{
+
+ R_EVENT event = { 0 };
+ R_EVENT *q_event;
+
+ YS_IGNORE_PARAM(scene_info);
+
+ switch (param) {
+
+ case SCENE_BEGIN:
+
+ /* Background for intro scene is the first frame of the
+ * intro animation; display it and set the palette
+ \*-----------------------------------------------------*/
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_BG_EVENT;
+ event.op = EVENT_DISPLAY;
+ event.param = SET_PALETTE;
+ event.time = 0;
+
+ q_event = EVENT_Queue(&event);
+
+ ANIM_SetFlag(0, ANIM_LOOP);
+ ANIM_Play(0, 0);
+
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+} // End of namespace Saga
diff --git a/saga/ihnm_introproc.h b/saga/ihnm_introproc.h
new file mode 100644
index 0000000000..7bfffa3fba
--- /dev/null
+++ b/saga/ihnm_introproc.h
@@ -0,0 +1,44 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Intro sequence scene procedures header file
+
+ Notes:
+*/
+
+#ifndef SAGA_ITE_INTRO_H_
+#define SAGA_ITE_INTRO_H_
+
+namespace Saga {
+
+#define R_IHNM_PALFADE_TIME 1000
+#define R_IHNM_INTRO_FRAMETIME 80
+#define R_IHNM_DGLOGO_TIME 8000
+#define R_IHNM_TITLE_TIME 16000
+
+} // End of namespace Saga
+
+#endif /* R_IHNM_INTRO_H_ */
+/* end "r_ihnm_introproc.h */
diff --git a/saga/image.cpp b/saga/image.cpp
new file mode 100644
index 0000000000..d63e6c1088
--- /dev/null
+++ b/saga/image.cpp
@@ -0,0 +1,510 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ SAGA Image resource management routines
+
+ Notes:
+*/
+
+#include "reinherit.h"
+
+#include "yslib.h"
+
+/*
+ * Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "game_mod.h"
+
+/*
+ * Begin module
+\*--------------------------------------------------------------------------*/
+#include "image_mod.h"
+#include "image.h"
+
+namespace Saga {
+
+int
+IMG_DecodeBGImage(const uchar * image_data,
+ size_t image_size,
+ uchar ** output_buf, size_t * output_buf_len, int *w, int *h)
+{
+
+ R_IMAGE_HEADER hdr;
+ int modex_height;
+
+ const uchar *RLE_data_ptr;
+ size_t RLE_data_len;
+
+ uchar *decode_buf;
+ size_t decode_buf_len;
+
+ uchar *out_buf;
+ size_t out_buf_len;
+
+ const uchar *read_p = image_data;
+
+ if (image_size <= SAGA_IMAGE_DATA_OFFSET) {
+ /* Image size is way too small */
+ return R_FAILURE;
+ }
+
+ hdr.width = ys_read_u16_le(read_p, &read_p);
+ hdr.height = ys_read_u16_le(read_p, &read_p);
+ hdr.unknown4 = ys_read_u16_le(read_p, &read_p);
+ hdr.unknown6 = ys_read_u16_le(read_p, &read_p);
+
+ RLE_data_ptr = image_data + SAGA_IMAGE_DATA_OFFSET;
+ RLE_data_len = image_size - SAGA_IMAGE_DATA_OFFSET;
+
+ modex_height = Granulate(hdr.height, 4);
+
+ decode_buf_len = hdr.width * modex_height;
+ decode_buf = (uchar *)malloc(decode_buf_len);
+
+ out_buf_len = hdr.width * hdr.height;
+ out_buf = (uchar *)malloc(out_buf_len);
+
+ if (DecodeBGImageRLE(RLE_data_ptr,
+ RLE_data_len, decode_buf, decode_buf_len) != R_SUCCESS) {
+
+ free(decode_buf);
+ free(out_buf);
+
+ return R_FAILURE;
+ }
+
+ UnbankBGImage(out_buf, decode_buf, hdr.width, hdr.height);
+
+ /* For some reason bg images in IHNM are upside down
+ * \*------------------------------------------------------------- */
+ if (GAME_GetGameType() == R_GAMETYPE_IHNM) {
+
+ FlipImage(out_buf, hdr.width, hdr.height);
+ }
+
+ free(decode_buf);
+
+ *output_buf_len = out_buf_len;
+ *output_buf = out_buf;
+
+ *w = hdr.width;
+ *h = hdr.height;
+
+ return R_SUCCESS;
+}
+
+int
+DecodeBGImageRLE(const uchar * inbuf,
+ size_t inbuf_len, uchar * outbuf, size_t outbuf_len)
+{
+
+ const uchar *inbuf_ptr;
+ uchar *outbuf_ptr;
+ size_t inbuf_remain;
+
+ const uchar *inbuf_end;
+ uchar *outbuf_end;
+ size_t outbuf_remain;
+
+ uchar mark_byte;
+ int test_byte;
+
+ uint runcount;
+
+ uchar bitfield;
+ uchar bitfield_byte1;
+ uchar bitfield_byte2;
+
+ uchar *backtrack_ptr;
+ int backtrack_amount;
+
+ uint c, b;
+
+ int decode_err = 0;
+
+ inbuf_ptr = inbuf;
+ inbuf_remain = inbuf_len;
+
+ outbuf_ptr = outbuf;
+ outbuf_remain = outbuf_len;
+
+ inbuf_end = (inbuf + inbuf_len) - 1;
+ outbuf_end = (outbuf + outbuf_len) - 1;
+
+ memset(outbuf, 0, outbuf_len);
+
+ while ((inbuf_remain > 1) && (outbuf_remain > 0) && !decode_err) {
+
+ if ((inbuf_ptr > inbuf_end) || (outbuf_ptr > outbuf_end)) {
+ return R_FAILURE;
+ }
+
+ mark_byte = *inbuf_ptr++;
+ inbuf_remain--;
+
+ test_byte = mark_byte & 0xC0; /* Mask all but two high order bits */
+
+ switch (test_byte) {
+
+ case 0xC0: /* 1100 0000 */
+
+ /* Uncompressed run follows: Max runlength 63 */
+ runcount = mark_byte & 0x3f;
+
+ if ((inbuf_remain < runcount) ||
+ (outbuf_remain < runcount)) {
+ return R_FAILURE;
+ }
+
+ for (c = 0; c < runcount; c++) {
+ *outbuf_ptr++ = *inbuf_ptr++;
+ }
+
+ inbuf_remain -= runcount;
+ outbuf_remain -= runcount;
+ continue;
+
+ break;
+
+ case 0x80: /* 1000 0000 */
+
+ /* Compressed run follows: Max runlength 63 */
+ runcount = (mark_byte & 0x3f) + 3;
+
+ if (!inbuf_remain || (outbuf_remain < runcount)) {
+ return R_FAILURE;
+ }
+
+ for (c = 0; c < runcount; c++) {
+ *outbuf_ptr++ = *inbuf_ptr;
+ }
+
+ inbuf_ptr++;
+ inbuf_remain--;
+ outbuf_remain -= runcount;
+ continue;
+
+ break;
+
+ case 0x40: /* 0100 0000 */
+
+ /* Repeat decoded sequence from output stream:
+ * Max runlength 10 */
+
+ runcount = ((mark_byte >> 3) & 0x07U) + 3;
+
+ backtrack_amount = *inbuf_ptr;
+
+ if (!inbuf_remain ||
+ (backtrack_amount > (outbuf_ptr - outbuf)) ||
+ (runcount > outbuf_remain)) {
+ return R_FAILURE;
+ }
+
+ inbuf_ptr++;
+ inbuf_remain--;
+
+ backtrack_ptr = outbuf_ptr - backtrack_amount;
+
+ for (c = 0; c < runcount; c++) {
+ *outbuf_ptr++ = *backtrack_ptr++;
+ }
+
+ outbuf_remain -= runcount;
+ continue;
+
+ break;
+
+ default: /* 0000 0000 */
+ break;
+ }
+
+ /* Mask all but the third and fourth highest order bits */
+ test_byte = mark_byte & 0x30;
+
+ switch (test_byte) {
+
+ case 0x30: /* 0011 0000 */
+ /* Bitfield compression */
+
+ runcount = (mark_byte & 0x0F) + 1;
+
+ if ((inbuf_remain < (runcount + 2)) ||
+ (outbuf_remain < (runcount * 8))) {
+ return R_FAILURE;
+ }
+
+ bitfield_byte1 = *inbuf_ptr++;
+ bitfield_byte2 = *inbuf_ptr++;
+
+ for (c = 0; c < runcount; c++) {
+
+ bitfield = *inbuf_ptr;
+
+ for (b = 0; b < 8; b++) {
+
+ if (bitfield & 0x80) {
+ *outbuf_ptr = bitfield_byte2;
+ } else {
+ *outbuf_ptr = bitfield_byte1;
+ }
+
+ bitfield <<= 1;
+
+ outbuf_ptr++;
+ }
+ inbuf_ptr++;
+ }
+
+ inbuf_remain -= (runcount + 2);
+ outbuf_remain -= (runcount * 8);
+ continue;
+
+ break;
+
+ case 0x20: /* 0010 0000 */
+ /* Uncompressed run follows */
+
+ runcount = ((mark_byte & 0x0F) << 8) + *inbuf_ptr;
+
+ if ((inbuf_remain < (runcount + 1)) ||
+ (outbuf_remain < runcount)) {
+ return R_FAILURE;
+ }
+
+ inbuf_ptr++;
+
+ for (c = 0; c < runcount; c++) {
+ *outbuf_ptr++ = *inbuf_ptr++;
+ }
+
+ inbuf_remain -= (runcount + 1);
+ outbuf_remain -= runcount;
+ continue;
+
+ break;
+
+ case 0x10: /* 0001 0000 */
+ /* Repeat decoded sequence from output stream */
+
+ backtrack_amount =
+ ((mark_byte & 0x0F) << 8) + *inbuf_ptr;
+
+ if (inbuf_remain < 2) {
+ return R_FAILURE;
+ }
+
+ inbuf_ptr++;
+ runcount = *inbuf_ptr++;
+
+ if ((backtrack_amount > (outbuf_ptr - outbuf)) ||
+ (outbuf_remain < runcount)) {
+ return R_FAILURE;
+ }
+
+ backtrack_ptr = outbuf_ptr - backtrack_amount;
+
+ for (c = 0; c < runcount; c++) {
+ *outbuf_ptr++ = *backtrack_ptr++;
+ }
+
+ inbuf_remain -= 2;
+ outbuf_remain -= runcount;
+ continue;
+
+ break;
+
+ default:
+ return R_FAILURE;
+ break;
+
+ }
+
+ } /* end while */
+
+ return R_SUCCESS;
+}
+
+int FlipImage(uchar * img_buf, int columns, int scanlines)
+{
+
+ int line;
+ uchar *tmp_scan;
+
+ uchar *flip_p1;
+ uchar *flip_p2;
+
+ int flipcount = scanlines / 2;
+
+ tmp_scan = (uchar *)malloc(columns);
+ if (tmp_scan == NULL) {
+ return R_FAILURE;
+ }
+
+ flip_p1 = img_buf;
+ flip_p2 = img_buf + (columns * (scanlines - 1));
+
+ for (line = 0; line < flipcount; line++) {
+
+ memcpy(tmp_scan, flip_p1, columns);
+ memcpy(flip_p1, flip_p2, columns);
+ memcpy(flip_p2, tmp_scan, columns);
+
+ flip_p1 += columns;
+ flip_p2 -= columns;
+ }
+
+ free(tmp_scan);
+
+ return R_SUCCESS;
+}
+
+int
+UnbankBGImage(uchar * dst_buf,
+ const uchar * src_buf, int columns, int scanlines)
+{
+
+ int x, y;
+ int temp;
+
+ int quadruple_rows;
+ int remain_rows;
+
+ int rowjump_src;
+ int rowjump_dest;
+
+ const uchar *src_p;
+ uchar *dst_p;
+
+ const uchar *srcptr1, *srcptr2, *srcptr3, *srcptr4;
+ uchar *dstptr1, *dstptr2, *dstptr3, *dstptr4;
+
+ quadruple_rows = scanlines - (scanlines % 4);
+ remain_rows = scanlines - quadruple_rows;
+
+ assert(scanlines > 0);
+
+ src_p = src_buf;
+ dst_p = dst_buf + columns;
+
+ srcptr1 = src_p;
+ srcptr2 = src_p + 1;
+ srcptr3 = src_p + 2;
+ srcptr4 = src_p + 3;
+
+ dstptr1 = dst_buf;
+ dstptr2 = dst_buf + columns;
+ dstptr3 = dst_buf + columns * 2;
+ dstptr4 = dst_buf + columns * 3;
+
+ rowjump_src = columns * 4;
+ rowjump_dest = columns * 4;
+
+ /* Unbank groups of 4 first */
+ for (y = 0; y < quadruple_rows; y += 4) {
+
+ for (x = 0; x < columns; x++) {
+ temp = x * 4;
+ dstptr1[x] = srcptr1[temp];
+ dstptr2[x] = srcptr2[temp];
+ dstptr3[x] = srcptr3[temp];
+ dstptr4[x] = srcptr4[temp];
+ }
+
+ /* This is to avoid generating invalid pointers -
+ * usually innocuous, but undefined */
+ if (y < quadruple_rows - 4) {
+
+ dstptr1 += rowjump_dest;
+ dstptr2 += rowjump_dest;
+ dstptr3 += rowjump_dest;
+ dstptr4 += rowjump_dest;
+ srcptr1 += rowjump_src;
+ srcptr2 += rowjump_src;
+ srcptr3 += rowjump_src;
+ srcptr4 += rowjump_src;
+ }
+
+ }
+
+ /* Unbank rows remaining */
+ switch (remain_rows) {
+
+ case 1:
+ dstptr1 += rowjump_dest;
+ srcptr1 += rowjump_src;
+
+ for (x = 0; x < columns; x++) {
+ temp = x * 4;
+ dstptr1[x] = srcptr1[temp];
+ }
+ break;
+
+ case 2:
+ dstptr1 += rowjump_dest;
+ dstptr2 += rowjump_dest;
+ srcptr1 += rowjump_src;
+ srcptr2 += rowjump_src;
+
+ for (x = 0; x < columns; x++) {
+ temp = x * 4;
+ dstptr1[x] = srcptr1[temp];
+ dstptr2[x] = srcptr2[temp];
+ }
+ break;
+
+ case 3:
+ dstptr1 += rowjump_dest;
+ dstptr2 += rowjump_dest;
+ dstptr3 += rowjump_dest;
+ srcptr1 += rowjump_src;
+ srcptr2 += rowjump_src;
+ srcptr3 += rowjump_src;
+
+ for (x = 0; x < columns; x++) {
+ temp = x * 4;
+ dstptr1[x] = srcptr1[temp];
+ dstptr2[x] = srcptr2[temp];
+ dstptr3[x] = srcptr3[temp];
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return R_SUCCESS;
+}
+
+const uchar *IMG_GetImagePal(const uchar * image_data, size_t image_size)
+{
+ if (image_size <= SAGA_IMAGE_HEADER_LEN) {
+ return NULL;
+ }
+
+ return image_data + SAGA_IMAGE_HEADER_LEN;
+}
+
+} // End of namespace Saga
diff --git a/saga/image.h b/saga/image.h
new file mode 100644
index 0000000000..95ade8877c
--- /dev/null
+++ b/saga/image.h
@@ -0,0 +1,64 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ SAGA Image resource management header file
+
+ Notes:
+*/
+
+#ifndef SAGA_IMAGE_H__
+#define SAGA_IMAGE_H__
+
+namespace Saga {
+
+#define R_MIN_IMG_RLECODE 3
+#define MODEX_SCANLINE_LIMIT 200
+
+#define SAGA_IMAGE_DATA_OFFSET 776
+#define SAGA_IMAGE_HEADER_LEN 8
+
+typedef struct R_IMAGE_HEADER_tag {
+
+ int width;
+ int height;
+ int unknown4;
+ int unknown6;
+
+} R_IMAGE_HEADER;
+
+int
+DecodeBGImageRLE(const uchar * inbuf,
+ size_t inbuf_len, uchar * outbuf, size_t outbuf_len);
+
+int FlipImage(uchar * img_buf, int columns, int scanlines);
+
+int
+UnbankBGImage(uchar * dest_buf,
+ const uchar * src_buf, int columns, int scanlines);
+
+} // End of namespace Saga
+
+#endif /* R_IMAGE_H__ */
+/* end "r_image.h" */
diff --git a/saga/image_mod.h b/saga/image_mod.h
new file mode 100644
index 0000000000..290a9ae1da
--- /dev/null
+++ b/saga/image_mod.h
@@ -0,0 +1,46 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ SAGA Image resource management routines
+
+ Notes:
+*/
+
+#ifndef SAGA_IMAGE_MOD_H_
+#define SAGA_IMAGE_MOD_H_
+
+namespace Saga {
+
+int
+IMG_DecodeBGImage(const uchar * image_data,
+ size_t image_size,
+ uchar ** output_buf, size_t * output_buf_len, int *w, int *h);
+
+const uchar *IMG_GetImagePal(const uchar * image_data, size_t image_size);
+
+} // End of namespace Saga
+
+#endif /* R_IMAGE_MOD_H_ */
+/* end "r_image_mod.h" */
diff --git a/saga/interface.cpp b/saga/interface.cpp
new file mode 100644
index 0000000000..22b02db58a
--- /dev/null
+++ b/saga/interface.cpp
@@ -0,0 +1,756 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Game interface module
+
+ Notes:
+*/
+
+#include "reinherit.h"
+
+#include "yslib.h"
+
+/*
+ * Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "game_mod.h"
+#include "cvar_mod.h"
+#include "actor_mod.h"
+#include "console_mod.h"
+#include "font_mod.h"
+#include "gfx_mod.h"
+#include "image_mod.h"
+#include "objectmap_mod.h"
+#include "rscfile_mod.h"
+#include "script_mod.h"
+#include "sprite_mod.h"
+
+/*
+ * Begin module
+\*--------------------------------------------------------------------------*/
+#include "interface_mod.h"
+#include "interface.h"
+
+namespace Saga {
+
+static R_INTERFACE_MODULE IfModule;
+
+static R_VERB_DATA I_VerbData[] = {
+
+ {I_VERB_WALKTO, "verb_walkto", "Walk to", S_VERB_WALKTO},
+ {I_VERB_LOOKAT, "verb_lookat", "Look at", S_VERB_LOOKAT},
+ {I_VERB_PICKUP, "verb_pickup", "Pick up", S_VERB_PICKUP},
+ {I_VERB_TALKTO, "verb_talkto", "Talk to", S_VERB_TALKTO},
+ {I_VERB_OPEN, "verb_open", "Open", S_VERB_OPEN},
+ {I_VERB_CLOSE, "verb_close", "Close", S_VERB_CLOSE},
+ {I_VERB_USE, "verb_use", "Use", S_VERB_USE},
+ {I_VERB_GIVE, "verb_give", "Give", S_VERB_GIVE}
+};
+
+static R_INTERFACE_DESC ITE_interface = {
+
+ ITE_STATUS_Y,
+ ITE_STATUS_W,
+ ITE_STATUS_H,
+ ITE_STATUS_TEXT_Y,
+ ITE_STATUS_TXTCOL,
+ ITE_STATUS_BGCOL,
+
+ ITE_CMD_TEXT_COL,
+ ITE_CMD_TEXT_SHADOWCOL,
+ ITE_CMD_TEXT_HILITECOL,
+
+ COMMAND_DEFAULT_BUTTON,
+
+ ITE_LPORTRAIT_X,
+ ITE_LPORTRAIT_Y
+};
+
+static R_INTERFACE_BUTTON ITE_c_buttons[] = {
+
+ {5, 4, 46, 47, "Portrait", 0, 0, BUTTON_NONE, 0},
+ /* "Walk To" and "Talk To" share button sprites */
+ {52, 4, 109, 14, "Walk To", 1, 2, BUTTON_VERB, I_VERB_WALKTO},
+ {52, 15, 109, 25, "Look At", 3, 4, BUTTON_VERB, I_VERB_LOOKAT},
+ {52, 26, 109, 36, "Pick Up", 5, 6, BUTTON_VERB, I_VERB_PICKUP},
+ {52, 37, 109, 47, "Talk To", 1, 2, BUTTON_VERB, I_VERB_TALKTO},
+ {110, 4, 166, 14, "Open", 7, 8, BUTTON_VERB, I_VERB_OPEN},
+ {110, 15, 166, 25, "Close", 9, 10, BUTTON_VERB, I_VERB_CLOSE},
+ {110, 26, 166, 36, "Use", 11, 12, BUTTON_VERB, I_VERB_USE},
+ {110, 37, 166, 47, "Give", 13, 14, BUTTON_VERB, I_VERB_GIVE},
+
+ {181, 6, 206, 24, "Inv1", 0, 0, BUTTON_NONE, 0},
+ {213, 6, 240, 24, "Inv2", 0, 0, BUTTON_NONE, 0},
+ {245, 6, 272, 24, "Inv3", 0, 0, BUTTON_NONE, 0},
+ {277, 6, 304, 24, "Inv4", 0, 0, BUTTON_NONE, 0},
+ {181, 27, 208, 45, "Inv5", 0, 0, BUTTON_NONE, 0},
+ {213, 27, 240, 45, "Inv6", 0, 0, BUTTON_NONE, 0},
+ {245, 27, 272, 45, "Inv7", 0, 0, BUTTON_NONE, 0},
+ {277, 27, 304, 45, "Inv8", 0, 0, BUTTON_NONE, 0},
+ {306, 6, 314, 11, "InvUp", 0, 0, BUTTON_NONE, 0},
+ {306, 41, 314, 45, "InvDown", 0, 0, BUTTON_NONE, 0}
+};
+
+static R_INTERFACE_DESC IHNM_interface = {
+
+ IHNM_STATUS_Y,
+ IHNM_STATUS_W,
+ IHNM_STATUS_H,
+ IHNM_STATUS_TEXT_Y,
+ IHNM_STATUS_TXTCOL,
+ IHNM_STATUS_BGCOL,
+
+ IHNM_CMD_TEXT_COL,
+ IHNM_CMD_TEXT_SHADOWCOL,
+ IHNM_CMD_TEXT_HILITECOL,
+
+ COMMAND_DEFAULT_BUTTON,
+
+ IHNM_LPORTRAIT_X,
+ IHNM_LPORTRAIT_Y
+};
+
+static R_INTERFACE_BUTTON IHNM_c_buttons[] = {
+
+ {5, 4, 46, 47, "Portrait", 0, 0, 0, 0}
+};
+
+int INTERFACE_RegisterLang(void)
+{
+ size_t i;
+
+ for (i = 0; i < YS_NELEMS(I_VerbData); i++) {
+
+ if (CVAR_Register_S(I_VerbData[i].verb_str,
+ I_VerbData[i].verb_cvar,
+ NULL, R_CVAR_CFG, R_VERB_STRLIMIT) != R_SUCCESS) {
+
+ return R_FAILURE;
+ }
+
+ assert(CVAR_Find(I_VerbData[i].verb_cvar) != NULL);
+ }
+
+ return R_SUCCESS;
+}
+
+int INTERFACE_Init(void)
+{
+
+ R_GAME_RESOURCEDESC g_resdesc;
+
+ int game_type;
+ int result;
+
+ if (IfModule.init) {
+ return R_FAILURE;
+ }
+
+ IfModule.i_thread = STHREAD_Create();
+ if (IfModule.i_thread == NULL) {
+
+ R_printf(R_STDERR,
+ "Error creating script thread for game interface "
+ "module.\n");
+
+ return R_FAILURE;
+ }
+
+ /* Load interface module resource file context
+ * \*------------------------------------------------------------- */
+ result = GAME_GetFileContext(&IfModule.i_file_ctxt,
+ R_GAME_RESOURCEFILE, 0);
+ if (result != R_SUCCESS) {
+
+ return R_FAILURE;
+ }
+
+ /* Initialize interface data by game type
+ * \*------------------------------------------------------------- */
+ game_type = GAME_GetGameType();
+
+ if (game_type == R_GAMETYPE_ITE) {
+
+ /* Load Inherit the Earth interface desc */
+
+ IfModule.c_panel.buttons = ITE_c_buttons;
+ IfModule.c_panel.nbuttons = YS_NELEMS(ITE_c_buttons);
+
+ IfModule.i_desc = ITE_interface;
+ } else if (game_type == R_GAMETYPE_IHNM) {
+
+ /* Load I Have No Mouth interface desc */
+ IfModule.c_panel.buttons = IHNM_c_buttons;
+ IfModule.c_panel.nbuttons = YS_NELEMS(IHNM_c_buttons);
+
+ IfModule.i_desc = IHNM_interface;
+ } else {
+ return R_FAILURE;
+ }
+
+ /* Load interface resources
+ * \*------------------------------------------------------------- */
+ GAME_GetResourceInfo(&g_resdesc);
+
+ /* Load command panel resource */
+ result = RSC_LoadResource(IfModule.i_file_ctxt,
+ g_resdesc.command_panel_rn,
+ &IfModule.c_panel.res, &IfModule.c_panel.res_len);
+ if (result != R_SUCCESS) {
+
+ return R_FAILURE;
+ }
+
+ /* Load dialogue panel resource */
+ result = RSC_LoadResource(IfModule.i_file_ctxt,
+ g_resdesc.dialogue_panel_rn,
+ &IfModule.d_panel.res, &IfModule.d_panel.res_len);
+ if (result != R_SUCCESS) {
+
+ return R_FAILURE;
+ }
+
+ SPRITE_LoadList(ITE_COMMAND_BUTTONSPRITES, &IfModule.c_panel.sprites);
+
+ SPRITE_LoadList(ITE_DEFAULT_PORTRAITS, &IfModule.def_portraits);
+
+ IMG_DecodeBGImage(IfModule.c_panel.res,
+ IfModule.c_panel.res_len,
+ &IfModule.c_panel.img,
+ &IfModule.c_panel.img_len,
+ &IfModule.c_panel.img_w, &IfModule.c_panel.img_h);
+
+ IMG_DecodeBGImage(IfModule.d_panel.res,
+ IfModule.d_panel.res_len,
+ &IfModule.d_panel.img,
+ &IfModule.d_panel.img_len,
+ &IfModule.d_panel.img_w, &IfModule.d_panel.img_h);
+
+ IfModule.c_panel.x = 0;
+ IfModule.c_panel.y = 149;
+
+ IfModule.d_panel.x = 0;
+ IfModule.d_panel.y = 149;
+
+ IfModule.c_panel.set_button = COMMAND_DEFAULT_BUTTON;
+ IfModule.active_portrait = 0;
+
+ IfModule.active_verb = I_VERB_WALKTO;
+
+ IfModule.init = 1;
+
+ return R_SUCCESS;
+}
+
+int INTERFACE_Activate(void)
+{
+
+ IfModule.active = 1;
+ INTERFACE_Draw();
+
+ return R_SUCCESS;
+}
+
+int INTERFACE_Deactivate(void)
+{
+
+ IfModule.active = 0;
+
+ return R_SUCCESS;
+}
+
+int INTERFACE_SetStatusText(const char *new_txt)
+{
+
+ assert(new_txt != NULL);
+
+ strncpy(IfModule.status_txt, new_txt, R_STATUS_TEXT_LEN);
+
+ return R_SUCCESS;
+}
+
+int INTERFACE_Draw(void)
+{
+
+ R_GAME_DISPLAYINFO g_di;
+
+ R_SURFACE *back_buf;
+
+ int xbase;
+ int ybase;
+ int lportrait_x;
+ int lportrait_y;
+
+ R_RECT rect;
+ R_POINT origin;
+
+ back_buf = SYSGFX_GetBackBuffer();
+
+ if (!IfModule.active) {
+ return R_SUCCESS;
+ }
+
+ /* Get game display info
+ * \*------------------------------------------------------------- */
+ GAME_GetDisplayInfo(&g_di);
+
+ /* Erase background of status bar
+ * \*------------------------------------------------------------- */
+ rect.x1 = 0;
+ rect.y1 = IfModule.i_desc.status_y;
+
+ rect.x2 = g_di.logical_w - 1;
+ rect.y2 = IfModule.i_desc.status_h - 1;
+
+ GFX_DrawRect(back_buf, &rect, IfModule.i_desc.status_bgcol);
+
+ /* Draw command panel background
+ * \*------------------------------------------------------------- */
+ if (IfModule.panel_mode == PANEL_COMMAND) {
+
+ xbase = IfModule.c_panel.x;
+ ybase = IfModule.c_panel.y;
+
+ origin.x = 0;
+ origin.y = g_di.logical_h - IfModule.c_panel.img_h;
+
+ GFX_BufToSurface(back_buf,
+ IfModule.c_panel.img,
+ IfModule.c_panel.img_w,
+ IfModule.c_panel.img_h, NULL, &origin);
+ } else {
+
+ xbase = IfModule.d_panel.x;
+ ybase = IfModule.d_panel.y;
+
+ origin.x = 0;
+ origin.y = g_di.logical_h - IfModule.c_panel.img_h;
+
+ GFX_BufToSurface(back_buf,
+ IfModule.d_panel.img,
+ IfModule.d_panel.img_w,
+ IfModule.d_panel.img_h, NULL, &origin);
+ }
+
+ /* Draw character portrait
+ * \*------------------------------------------------------------- */
+ lportrait_x = xbase + IfModule.i_desc.lportrait_x;
+ lportrait_y = ybase + IfModule.i_desc.lportrait_y;
+
+ SPRITE_Draw(back_buf,
+ IfModule.def_portraits,
+ IfModule.active_portrait, lportrait_x, lportrait_y);
+
+ return R_SUCCESS;
+}
+
+int INTERFACE_Update(R_POINT * imouse_pt, int update_flag)
+{
+
+ R_GAME_DISPLAYINFO g_di;
+
+ R_SURFACE *back_buf;
+
+ int imouse_x, imouse_y;
+
+ assert(imouse_pt != NULL);
+
+ if (!IfModule.active) {
+ return R_SUCCESS;
+ }
+
+ imouse_x = imouse_pt->x;
+ imouse_y = imouse_pt->y;
+
+ back_buf = SYSGFX_GetBackBuffer();
+
+ /* Get game display info
+ * \*------------------------------------------------------------- */
+ GAME_GetDisplayInfo(&g_di);
+
+ /* Update playfield space ( only if cursor is inside )
+ * \*------------------------------------------------------------- */
+ if (imouse_y < g_di.scene_h) {
+
+ /* Mouse is in playfield space */
+
+ if (update_flag == UPDATE_MOUSEMOVE) {
+
+ HandlePlayfieldUpdate(back_buf, imouse_pt);
+ } else if (update_flag == UPDATE_MOUSECLICK) {
+
+ HandlePlayfieldClick(back_buf, imouse_pt);
+ }
+ }
+
+ /* Update command space
+ * \*------------------------------------------------------------- */
+
+ if (update_flag == UPDATE_MOUSEMOVE) {
+
+ HandleCommandUpdate(back_buf, imouse_pt);
+ } else if (update_flag == UPDATE_MOUSECLICK) {
+
+ HandleCommandClick(back_buf, imouse_pt);
+ }
+
+ DrawStatusBar(back_buf);
+
+ return R_SUCCESS;
+}
+
+int DrawStatusBar(R_SURFACE * ds)
+{
+
+ R_GAME_DISPLAYINFO g_di;
+ R_RECT rect;
+
+ int string_w;
+
+ /* Get game display info
+ * \*------------------------------------------------------------- */
+ GAME_GetDisplayInfo(&g_di);
+
+ /* Erase background of status bar
+ * \*------------------------------------------------------------- */
+ rect.x1 = 0;
+ rect.y1 = IfModule.i_desc.status_y;
+ rect.x2 = g_di.logical_w - 1;
+ rect.y2 = IfModule.i_desc.status_y + IfModule.i_desc.status_h - 1;
+
+ GFX_DrawRect(ds, &rect, IfModule.i_desc.status_bgcol);
+
+ string_w = FONT_GetStringWidth(SMALL_FONT_ID,
+ IfModule.status_txt, 0, 0);
+
+ FONT_Draw(SMALL_FONT_ID,
+ ds,
+ IfModule.status_txt,
+ 0,
+ (IfModule.i_desc.status_w / 2) - (string_w / 2),
+ IfModule.i_desc.status_y + IfModule.i_desc.status_txt_y,
+ IfModule.i_desc.status_txt_col, 0, 0);
+
+ return R_SUCCESS;
+
+}
+
+int HandleCommandClick(R_SURFACE * ds, R_POINT * imouse_pt)
+{
+
+ int hit_button;
+ int ibutton_num;
+
+ int x_base;
+ int y_base;
+
+ int button_x = 0;
+ int button_y = 0;
+
+ int old_set_button;
+ int set_button;
+
+ hit_button = INTERFACE_HitTest(imouse_pt, &ibutton_num);
+ if (hit_button != R_SUCCESS) {
+
+ /* Clicking somewhere other than a button doesn't do anything */
+ return R_SUCCESS;
+ }
+
+ x_base = IfModule.c_panel.x;
+ y_base = IfModule.c_panel.y;
+
+ if (IfModule.c_panel.buttons[ibutton_num].flags & BUTTON_SET) {
+
+ old_set_button = IfModule.c_panel.set_button;
+ set_button = ibutton_num;
+ IfModule.c_panel.set_button = set_button;
+
+ if (IfModule.c_panel.buttons[set_button].flags & BUTTON_VERB) {
+
+ IfModule.active_verb =
+ IfModule.c_panel.buttons[ibutton_num].data;
+ }
+
+ if (IfModule.c_panel.buttons[set_button].flags & BUTTON_BITMAP) {
+
+ button_x =
+ x_base + IfModule.c_panel.buttons[set_button].x1;
+ button_y =
+ y_base + IfModule.c_panel.buttons[set_button].y1;
+
+ SPRITE_Draw(ds,
+ IfModule.c_panel.sprites,
+ IfModule.c_panel.buttons[set_button].
+ active_sprite - 1, button_x, button_y);
+ }
+
+ if (IfModule.c_panel.buttons[old_set_button].
+ flags & BUTTON_BITMAP) {
+
+ button_x =
+ x_base +
+ IfModule.c_panel.buttons[old_set_button].x1;
+ button_y =
+ y_base +
+ IfModule.c_panel.buttons[old_set_button].y1;
+
+ SPRITE_Draw(ds,
+ IfModule.c_panel.sprites,
+ IfModule.c_panel.buttons[old_set_button].
+ inactive_sprite - 1, button_x, button_y);
+ }
+ }
+
+ return R_SUCCESS;
+}
+
+int HandleCommandUpdate(R_SURFACE * ds, R_POINT * imouse_pt)
+{
+
+ int hit_button;
+ int ibutton_num;
+
+ int button_x = 0;
+ int button_y = 0;
+ int button_w = 0;
+
+ int verb_idx = 0;
+ int string_w = 0;
+
+ int color;
+
+ int i;
+
+ hit_button = INTERFACE_HitTest(imouse_pt, &ibutton_num);
+ if (hit_button == R_SUCCESS) {
+
+ /* Hovering over a command panel button */
+ INTERFACE_SetStatusText(I_VerbData[IfModule.active_verb].
+ verb_str);
+ }
+
+ for (i = 0; i < IfModule.c_panel.nbuttons; i++) {
+
+ if (!(IfModule.c_panel.buttons[i].flags & BUTTON_LABEL)) {
+ continue;
+ }
+
+ button_w = IfModule.c_panel.buttons[i].x2 -
+ IfModule.c_panel.buttons[i].x1;
+
+ verb_idx = IfModule.c_panel.buttons[i].data;
+
+ string_w = FONT_GetStringWidth(SMALL_FONT_ID,
+ I_VerbData[verb_idx].verb_str, 0, 0);
+
+ if (i == hit_button) {
+ color = IfModule.i_desc.cmd_txt_hilitecol;
+ } else {
+ color = IfModule.i_desc.cmd_txt_col;
+ }
+
+ button_x = IfModule.c_panel.x + IfModule.c_panel.buttons[i].x1;
+ button_y = IfModule.c_panel.y + IfModule.c_panel.buttons[i].y1;
+
+ FONT_Draw(SMALL_FONT_ID,
+ ds,
+ I_VerbData[verb_idx].verb_str,
+ 0,
+ button_x + ((button_w / 2) - (string_w / 2)),
+ button_y + 1,
+ color, IfModule.i_desc.cmd_txt_shadowcol, FONT_SHADOW);
+
+ if ((i == IfModule.c_panel.set_button) &&
+ (IfModule.c_panel.buttons[i].flags & BUTTON_BITMAP)) {
+
+ SPRITE_Draw(ds,
+ IfModule.c_panel.sprites,
+ IfModule.c_panel.buttons[i].active_sprite - 1,
+ button_x, button_y);
+ }
+ }
+
+ return R_SUCCESS;
+}
+
+int HandlePlayfieldClick(R_SURFACE * ds, R_POINT * imouse_pt)
+{
+
+ int hit_object;
+ int object_num;
+ uint object_flags = 0;
+
+ int script_num;
+ R_POINT iactor_pt;
+
+ hit_object = OBJECTMAP_HitTest(imouse_pt, &object_num);
+
+ if (hit_object != R_SUCCESS) {
+
+ /* Player clicked on empty spot - walk here regardless of verb */
+
+ ACTOR_StoA(&iactor_pt, imouse_pt);
+ ACTOR_WalkTo(0, &iactor_pt, 0, NULL);
+
+ return R_SUCCESS;
+ }
+
+ if (OBJECTMAP_GetFlags(object_num, &object_flags) != R_SUCCESS) {
+
+ CON_Print("Invalid object number: %d\n", object_num);
+
+ return R_FAILURE;
+ }
+
+ if (object_flags & R_OBJECT_NORMAL) {
+
+ if (OBJECTMAP_GetEPNum(object_num, &script_num) == R_SUCCESS) {
+
+ /* Set active verb in script module */
+ SDATA_PutWord(4, 4,
+ I_VerbData[IfModule.active_verb].s_verb);
+
+ /* Execute object script if present */
+ if (script_num != 0) {
+ STHREAD_Execute(IfModule.i_thread, script_num);
+ }
+ }
+ } else {
+
+ /* Not a normal scene object - walk to it as if it weren't there */
+
+ ACTOR_StoA(&iactor_pt, imouse_pt);
+ ACTOR_WalkTo(0, &iactor_pt, 0, NULL);
+
+ }
+
+ return R_SUCCESS;
+}
+
+int HandlePlayfieldUpdate(R_SURFACE * ds, R_POINT * imouse_pt)
+{
+
+ const char *object_name;
+ int object_num;
+ uint object_flags = 0;
+
+ char new_status[R_STATUS_TEXT_LEN];
+
+ int hit_object;
+
+ new_status[0] = 0;
+
+ hit_object = OBJECTMAP_HitTest(imouse_pt, &object_num);
+
+ if (hit_object != R_SUCCESS) {
+
+ /* Cursor over nothing - just display current verb */
+ INTERFACE_SetStatusText(I_VerbData[IfModule.active_verb].
+ verb_str);
+
+ return R_SUCCESS;
+ }
+
+ if (OBJECTMAP_GetFlags(object_num, &object_flags) != R_SUCCESS) {
+
+ CON_Print("Invalid object number: %d\n", object_num);
+
+ return R_FAILURE;
+ }
+
+ OBJECTMAP_GetName(object_num, &object_name);
+
+ if (object_flags & R_OBJECT_NORMAL) {
+
+ /* Normal scene object - display as subject of verb */
+
+ snprintf(new_status,
+ R_STATUS_TEXT_LEN,
+ "%s %s",
+ I_VerbData[IfModule.active_verb].verb_str, object_name);
+ } else {
+
+ /* Not normal scene object - override verb as we can only
+ * walk to this object */
+
+ snprintf(new_status,
+ R_STATUS_TEXT_LEN,
+ "%s %s", I_VerbData[I_VERB_WALKTO].verb_str, object_name);
+ }
+
+ INTERFACE_SetStatusText(new_status);
+
+ return R_SUCCESS;
+}
+
+int INTERFACE_HitTest(R_POINT * imouse_pt, int *ibutton)
+{
+
+ R_INTERFACE_BUTTON *buttons;
+
+ int nbuttons;
+ int xbase;
+ int ybase;
+
+ int i;
+
+ buttons = IfModule.c_panel.buttons;
+ nbuttons = IfModule.c_panel.nbuttons;
+
+ xbase = IfModule.c_panel.x;
+ ybase = IfModule.c_panel.y;
+
+ for (i = 0; i < nbuttons; i++) {
+
+ if ((imouse_pt->x >= (xbase + buttons[i].x1)) &&
+ (imouse_pt->x < (xbase + buttons[i].x2)) &&
+ (imouse_pt->y >= (ybase + buttons[i].y1)) &&
+ (imouse_pt->y < (ybase + buttons[i].y2))) {
+
+ *ibutton = i;
+
+ return R_SUCCESS;
+ }
+ }
+
+ *ibutton = -1;
+ return R_FAILURE;
+}
+
+int INTERFACE_Shutdown(void)
+{
+
+ if (!IfModule.init) {
+
+ return R_FAILURE;
+ }
+
+ IfModule.init = 0;
+
+ return R_SUCCESS;
+}
+
+} // End of namespace Saga
diff --git a/saga/interface.h b/saga/interface.h
new file mode 100644
index 0000000000..d8e8e24dbb
--- /dev/null
+++ b/saga/interface.h
@@ -0,0 +1,198 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Game interface module private header file
+
+ Notes:
+
+ Module dependencies:
+ - r_script_mod
+ - r_sprite_mod
+*/
+
+#ifndef SAGA_INTERFACE_H__
+#define SAGA_INTERFACE_H__
+
+namespace Saga {
+
+#define R_VERB_STRLIMIT 32
+
+#define R_STATUS_TEXT_LEN 128
+
+#define COMMAND_DEFAULT_BUTTON 1
+
+/* Inherit the Earth interface values */
+#define ITE_STATUS_Y 137
+#define ITE_STATUS_W 320
+#define ITE_STATUS_H 12
+#define ITE_STATUS_TEXT_Y 2
+#define ITE_STATUS_TXTCOL 186
+#define ITE_STATUS_BGCOL 15
+
+#define ITE_CMD_TEXT_COL 147
+#define ITE_CMD_TEXT_SHADOWCOL 15
+#define ITE_CMD_TEXT_HILITECOL 96
+
+#define ITE_LPORTRAIT_X 5
+#define ITE_LPORTRAIT_Y 4
+
+/* IHNMAIMS interface values */
+#define IHNM_STATUS_Y 304
+#define IHNM_STATUS_W 640
+#define IHNM_STATUS_H 24
+#define IHNM_STATUS_TEXT_Y 8
+#define IHNM_STATUS_TXTCOL 186
+#define IHNM_STATUS_BGCOL 0
+
+#define IHNM_CMD_TEXT_COL 147
+#define IHNM_CMD_TEXT_SHADOWCOL 15
+#define IHNM_CMD_TEXT_HILITECOL 96
+
+#define IHNM_LPORTRAIT_X 5
+#define IHNM_LPORTRAIT_Y 4
+
+typedef enum R_PANEL_MODES_tag {
+
+ PANEL_COMMAND,
+ PANEL_DIALOGUE
+} R_PANEL_MODES;
+
+typedef enum R_BUTTON_FLAGS_tag {
+
+ BUTTON_NONE = 0x0,
+ BUTTON_LABEL = 0x01,
+ BUTTON_BITMAP = 0x02,
+ BUTTON_SET = 0x04
+
+} R_BUTTON_FLAGS;
+
+#define BUTTON_VERB ( BUTTON_LABEL | BUTTON_BITMAP | BUTTON_SET )
+
+typedef struct R_INTERFACE_BUTTON_tag {
+
+ int x1;
+ int y1;
+ int x2;
+ int y2;
+ char *label;
+ int inactive_sprite;
+ int active_sprite;
+ int flags;
+ int data;
+
+} R_INTERFACE_BUTTON;
+
+typedef struct R_INTERFACE_PANEL_tag {
+
+ uchar *res;
+ size_t res_len;
+ int x;
+ int y;
+ uchar *img;
+ size_t img_len;
+ int img_w;
+ int img_h;
+ int set_button;
+ int nbuttons;
+ R_INTERFACE_BUTTON *buttons;
+ R_SPRITELIST *sprites;
+
+} R_INTERFACE_PANEL;
+
+typedef struct R_INTERFACE_DESC_tag {
+
+ int status_y;
+ int status_w;
+ int status_h;
+ int status_txt_y;
+ int status_txt_col;
+ int status_bgcol;
+
+ int cmd_txt_col;
+ int cmd_txt_shadowcol;
+ int cmd_txt_hilitecol;
+ int cmd_defaultbutton;
+
+ int lportrait_x;
+ int lportrait_y;
+
+} R_INTERFACE_DESC;
+
+typedef struct R_INTERFACE_MODULE_tag {
+
+ int init;
+ int active;
+
+ R_RSCFILE_CONTEXT *i_file_ctxt;
+
+ R_INTERFACE_DESC i_desc;
+
+ R_PANEL_MODES panel_mode;
+ R_INTERFACE_PANEL c_panel;
+ R_INTERFACE_PANEL d_panel;
+
+ char status_txt[R_STATUS_TEXT_LEN];
+
+ int active_portrait;
+ R_SPRITELIST *def_portraits;
+ int active_verb;
+
+ R_SCRIPT_THREAD *i_thread;
+
+} R_INTERFACE_MODULE;
+
+enum INTERFACE_VERBS {
+
+ I_VERB_WALKTO,
+ I_VERB_LOOKAT,
+ I_VERB_PICKUP,
+ I_VERB_TALKTO,
+ I_VERB_OPEN,
+ I_VERB_CLOSE,
+ I_VERB_USE,
+ I_VERB_GIVE
+};
+
+typedef struct R_VERB_DATA_tag {
+
+ int i_verb;
+ const char *verb_cvar;
+ char verb_str[R_VERB_STRLIMIT];
+ int s_verb;
+
+} R_VERB_DATA;
+
+int INTERFACE_HitTest(R_POINT * imouse_pt, int *ibutton);
+
+int DrawStatusBar(R_SURFACE * ds);
+int HandleCommandUpdate(R_SURFACE * ds, R_POINT * imouse_pt);
+int HandleCommandClick(R_SURFACE * ds, R_POINT * imouse_pt);
+int HandlePlayfieldUpdate(R_SURFACE * ds, R_POINT * imouse_pt);
+int HandlePlayfieldClick(R_SURFACE * ds, R_POINT * imouse_pt);
+
+} // End of namespace Saga
+
+#endif /* R_INTERFACE_H__ */
+/* end "r_interface.h" */
diff --git a/saga/interface_mod.h b/saga/interface_mod.h
new file mode 100644
index 0000000000..77de1dae75
--- /dev/null
+++ b/saga/interface_mod.h
@@ -0,0 +1,57 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Game interface module public header file
+
+ Notes:
+*/
+
+#ifndef SAGA_INTERFACE_MOD_H
+#define SAGA_INTERFACE_MOD_H
+
+namespace Saga {
+
+typedef enum INTERFACE_UPDATE_FLAGS_tag {
+
+ UPDATE_MOUSEMOVE = 1,
+ UPDATE_MOUSECLICK
+
+} INTERFACE_UPDATE_FLAGS;
+
+int INTERFACE_RegisterLang(void);
+
+int INTERFACE_Init(void);
+int INTERFACE_Shutdown(void);
+
+int INTERFACE_Activate(void);
+int INTERFACE_Deactivate(void);
+
+int INTERFACE_SetStatusText(const char *new_txt);
+int INTERFACE_Draw(void);
+int INTERFACE_Update(R_POINT * imouse_pt, int update_flag);
+
+} // End of namespace Saga
+
+#endif /* SAGA_INTERFACE_MOD_H */
diff --git a/saga/isomap.cpp b/saga/isomap.cpp
new file mode 100644
index 0000000000..0f895b8082
--- /dev/null
+++ b/saga/isomap.cpp
@@ -0,0 +1,371 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Isometric level module
+
+ Notes:
+*/
+
+#include "reinherit.h"
+
+#include "yslib.h"
+
+/*
+ * Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "game_mod.h"
+#include "gfx_mod.h"
+
+/*
+ * Begin module component
+\*--------------------------------------------------------------------------*/
+#include "isomap_mod.h"
+#include "isomap.h"
+
+namespace Saga {
+
+static R_ISOMAP_MODULE IsoModule;
+
+int ISOMAP_Init(void)
+{
+ IsoModule.init = 1;
+
+ return R_SUCCESS;
+}
+
+int ISOMAP_LoadTileset(const uchar * tileres_p, size_t tileres_len)
+{
+
+ R_ISOTILE_ENTRY first_entry;
+ R_ISOTILE_ENTRY *tile_tbl;
+
+ uint i;
+
+ const uchar *read_p = tileres_p;
+ size_t read_len = tileres_len;
+
+ assert((IsoModule.init) && (!IsoModule.tiles_loaded));
+ assert((tileres_p != NULL) && (tileres_len > 0));
+
+ read_p += 2;
+ first_entry.tile_offset = ys_read_u16_le(read_p, &read_p);
+
+ IsoModule.tile_ct = first_entry.tile_offset / SAGA_ISOTILE_ENTRY_LEN;
+
+ read_p = tileres_p;
+ read_len = tileres_len;
+
+ tile_tbl = (R_ISOTILE_ENTRY *)malloc(IsoModule.tile_ct * sizeof *tile_tbl);
+ if (tile_tbl == NULL) {
+ return R_MEM;
+ }
+
+ for (i = 0; i < IsoModule.tile_ct; i++) {
+
+ tile_tbl[i].tile_h = ys_read_u8(read_p, &read_p);
+ tile_tbl[i].unknown01 = ys_read_u8(read_p, &read_p);
+
+ tile_tbl[i].tile_offset = ys_read_u16_le(read_p, &read_p);
+ tile_tbl[i].unknown04 = ys_read_s16_le(read_p, &read_p);
+ tile_tbl[i].unknown06 = ys_read_s16_le(read_p, &read_p);
+ }
+
+ IsoModule.tiles_loaded = 1;
+ IsoModule.tile_tbl = tile_tbl;
+ IsoModule.tileres_p = tileres_p;
+ IsoModule.tileres_len = tileres_len;
+
+ return R_SUCCESS;
+}
+
+int ISOMAP_LoadMetaTileset(const uchar * mtileres_p, size_t mtileres_len)
+{
+
+ R_ISO_METATILE_ENTRY *mtile_tbl;
+
+ const uchar *read_p = mtileres_p;
+ size_t read_len = mtileres_len;
+
+ uint mtile_ct;
+ uint ct;
+
+ int i;
+
+ assert(IsoModule.init);
+ assert((mtileres_p != NULL) && (mtileres_len > 0));
+
+ (void)read_len;
+
+ mtile_ct = mtileres_len / SAGA_METATILE_ENTRY_LEN;
+
+ mtile_tbl = (R_ISO_METATILE_ENTRY *)malloc(mtile_ct * sizeof *mtile_tbl);
+ if (mtile_tbl == NULL) {
+ return R_MEM;
+ }
+
+ for (ct = 0; ct < mtile_ct; ct++) {
+
+ mtile_tbl[ct].mtile_n = ys_read_u16_le(read_p, &read_p);
+ mtile_tbl[ct].unknown02 = ys_read_s16_le(read_p, &read_p);
+ mtile_tbl[ct].unknown04 = ys_read_s16_le(read_p, &read_p);
+ mtile_tbl[ct].unknown06 = ys_read_s16_le(read_p, &read_p);
+
+ for (i = 0; i < SAGA_METATILE_SIZE; i++) {
+ mtile_tbl[ct].tile_tbl[i] =
+ ys_read_u16_le(read_p, &read_p);
+ }
+ }
+
+ IsoModule.mtile_ct = mtile_ct;
+ IsoModule.mtile_tbl = mtile_tbl;
+ IsoModule.mtileres_p = mtileres_p;
+ IsoModule.mtileres_len = mtileres_len;
+
+ IsoModule.mtiles_loaded = 1;
+
+ return R_SUCCESS;
+}
+
+int ISOMAP_LoadMetamap(const uchar * mm_res_p, size_t mm_res_len)
+{
+
+ const uchar *read_p = mm_res_p;
+ size_t read_len = mm_res_len;
+
+ int i;
+
+ (void)read_len;
+
+ IsoModule.metamap_n = ys_read_s16_le(read_p, &read_p);
+
+ for (i = 0; i < SAGA_METAMAP_SIZE; i++) {
+
+ IsoModule.metamap_tbl[i] = ys_read_u16_le(read_p, &read_p);
+ }
+
+ IsoModule.mm_res_p = mm_res_p;
+ IsoModule.mm_res_len = mm_res_len;
+ IsoModule.metamap_loaded = 1;
+
+ return R_SUCCESS;
+}
+
+int ISOMAP_Draw(R_SURFACE * dst_s)
+{
+
+ R_GAME_DISPLAYINFO disp_info;
+ R_RECT iso_rect;
+
+ GAME_GetDisplayInfo(&disp_info);
+
+ iso_rect.x1 = 0;
+ iso_rect.y1 = 0;
+ iso_rect.x2 = disp_info.logical_w - 1;
+ iso_rect.y2 = disp_info.scene_h - 1;
+
+ GFX_DrawRect(dst_s, &iso_rect, 0);
+
+ ISOMAP_DrawMetamap(dst_s, -1000, -500);
+
+ return R_SUCCESS;
+}
+
+int ISOMAP_DrawMetamap(R_SURFACE * dst_s, int map_x, int map_y)
+{
+ int meta_base_x = map_x;
+ int meta_base_y = map_y;
+
+ int meta_xi;
+ int meta_yi;
+
+ int meta_x;
+ int meta_y;
+
+ int meta_idx;
+
+ for (meta_yi = SAGA_METAMAP_H - 1; meta_yi >= 0; meta_yi--) {
+
+ meta_x = meta_base_x;
+ meta_y = meta_base_y;
+
+ for (meta_xi = SAGA_METAMAP_W - 1; meta_xi >= 0; meta_xi--) {
+
+ meta_idx = meta_xi + (meta_yi * 16);
+
+ ISOMAP_DrawMetaTile(dst_s,
+ IsoModule.metamap_tbl[meta_idx], meta_x, meta_y);
+
+ meta_x += 128;
+ meta_y += 64;
+ }
+
+ meta_base_x -= 128;
+ meta_base_y += 64;
+ }
+
+ return R_SUCCESS;
+}
+
+int
+ISOMAP_DrawMetaTile(R_SURFACE * dst_s, uint mtile_i, int mtile_x, int mtile_y)
+{
+
+ int tile_xi;
+ int tile_yi;
+
+ int tile_x;
+ int tile_y;
+
+ int tile_base_x;
+ int tile_base_y;
+
+ int tile_i;
+
+ R_ISO_METATILE_ENTRY *mtile_p;
+ assert(IsoModule.init && IsoModule.mtiles_loaded);
+
+ if (mtile_i >= IsoModule.mtile_ct) {
+ return R_FAILURE;
+ }
+
+ mtile_p = &IsoModule.mtile_tbl[mtile_i];
+
+ tile_base_x = mtile_x;
+ tile_base_y = mtile_y;
+
+ for (tile_yi = SAGA_METATILE_H - 1; tile_yi >= 0; tile_yi--) {
+
+ tile_y = tile_base_y;
+ tile_x = tile_base_x;
+
+ for (tile_xi = SAGA_METATILE_W - 1; tile_xi >= 0; tile_xi--) {
+
+ tile_i = tile_xi + (tile_yi * SAGA_METATILE_W);
+
+ ISOMAP_DrawTile(dst_s,
+ mtile_p->tile_tbl[tile_i], tile_x, tile_y);
+
+ tile_x += SAGA_ISOTILE_WIDTH / 2;
+ tile_y += SAGA_ISOTILE_BASEHEIGHT / 2 + 1;
+
+ }
+
+ tile_base_x -= SAGA_ISOTILE_WIDTH / 2;
+ tile_base_y += SAGA_ISOTILE_BASEHEIGHT / 2 + 1;
+
+ }
+
+ return R_SUCCESS;
+}
+
+int ISOMAP_DrawTile(R_SURFACE * dst_s, uint tile_i, int tile_x, int tile_y)
+{
+
+ const uchar *tile_p;
+ const uchar *read_p;
+
+ uchar *draw_p;
+
+ int draw_x;
+ int draw_y;
+
+ int tile_h;
+ int w_count = 0;
+ int row;
+
+ int bg_runct;
+ int fg_runct;
+ int ct;
+
+ assert(IsoModule.init && IsoModule.tiles_loaded);
+
+ if (tile_i >= IsoModule.tile_ct) {
+ return R_FAILURE;
+ }
+
+ /* temporary x clip */
+ if (tile_x < 0) {
+ return R_SUCCESS;
+ }
+
+ /* temporary x clip */
+ if (tile_x >= 320 - 32) {
+ return R_SUCCESS;
+ }
+
+ tile_p = IsoModule.tileres_p + IsoModule.tile_tbl[tile_i].tile_offset;
+ tile_h = IsoModule.tile_tbl[tile_i].tile_h;
+
+ read_p = tile_p;
+ draw_p = dst_s->buf + tile_x + (tile_y * dst_s->buf_pitch);
+
+ draw_x = tile_x;
+ draw_y = tile_y;
+
+ if (tile_h > SAGA_ISOTILE_BASEHEIGHT) {
+ draw_y = tile_y - (tile_h - SAGA_ISOTILE_BASEHEIGHT);
+ }
+
+ /* temporary y clip */
+ if (draw_y < 0) {
+ return R_SUCCESS;
+ }
+
+ for (row = 0; row < tile_h; row++) {
+
+ draw_p =
+ dst_s->buf + draw_x + ((draw_y + row) * dst_s->buf_pitch);
+ w_count = 0;
+
+ /* temporary y clip */
+ if ((draw_y + row) >= 137) {
+ return R_SUCCESS;
+ }
+
+ for (;;) {
+
+ bg_runct = *read_p++;
+ w_count += bg_runct;
+
+ if (w_count >= SAGA_ISOTILE_WIDTH) {
+ break;
+ }
+
+ draw_p += bg_runct;
+
+ fg_runct = *read_p++;
+ w_count += fg_runct;
+
+ for (ct = 0; ct < fg_runct; ct++) {
+
+ *draw_p++ = *read_p++;
+ }
+ }
+ }
+
+ return R_SUCCESS;
+}
+
+} // End of namespace Saga
diff --git a/saga/isomap.h b/saga/isomap.h
new file mode 100644
index 0000000000..dfd9daa33f
--- /dev/null
+++ b/saga/isomap.h
@@ -0,0 +1,104 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Isometric level module - private header
+
+ Notes:
+*/
+
+#ifndef SAGA_ISOMAP_H_
+#define SAGA_ISOMAP_H_
+
+namespace Saga {
+
+typedef struct R_ISOTILE_ENTRY_tag {
+
+ int tile_h;
+ int unknown01;
+ size_t tile_offset;
+ int unknown04;
+ int unknown06;
+
+} R_ISOTILE_ENTRY;
+
+#define SAGA_ISOTILE_ENTRY_LEN 8
+#define SAGA_ISOTILE_WIDTH 32
+#define SAGA_ISOTILE_BASEHEIGHT 15
+
+#define SAGA_METATILE_W 8
+#define SAGA_METATILE_H 8
+#define SAGA_METATILE_SIZE 64
+
+#define SAGA_METAMAP_W 16
+#define SAGA_METAMAP_H 16
+#define SAGA_METAMAP_SIZE 256
+
+typedef struct R_ISO_METATILE_ENTRY_tag {
+
+ int mtile_n;
+ int unknown02;
+ int unknown04;
+ int unknown06;
+
+ int tile_tbl[SAGA_METATILE_SIZE];
+
+} R_ISO_METATILE_ENTRY;
+
+#define SAGA_METATILE_ENTRY_LEN 136
+
+typedef struct R_ISOMAP_MODULE_tag {
+
+ int init;
+
+ int tiles_loaded;
+ const uchar *tileres_p;
+ size_t tileres_len;
+ uint tile_ct;
+ R_ISOTILE_ENTRY *tile_tbl;
+
+ int mtiles_loaded;
+ const uchar *mtileres_p;
+ size_t mtileres_len;
+ uint mtile_ct;
+ R_ISO_METATILE_ENTRY *mtile_tbl;
+
+ int metamap_loaded;
+ int metamap_n;
+ uint metamap_tbl[SAGA_METAMAP_SIZE];
+ const uchar *mm_res_p;
+ size_t mm_res_len;
+
+} R_ISOMAP_MODULE;
+
+int ISOMAP_DrawTile(R_SURFACE * dst_s, uint tile_i, int tile_x, int tile_y);
+
+int
+ISOMAP_DrawMetaTile(R_SURFACE * dst_s, uint mtile_i, int mtile_x, int mtile_y);
+
+int ISOMAP_DrawMetamap(R_SURFACE * dst_s, int map_x, int map_y);
+
+} // End of namespace Saga
+
+#endif /* SAGA_ISOMAP_H_ */
diff --git a/saga/isomap_mod.h b/saga/isomap_mod.h
new file mode 100644
index 0000000000..f18200758a
--- /dev/null
+++ b/saga/isomap_mod.h
@@ -0,0 +1,48 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Isometric level module - public module header
+
+ Notes:
+*/
+
+#ifndef SAGA_ISOMAP_MOD_H_
+#define SAGA_ISOMAP_MOD_H_
+
+namespace Saga {
+
+int ISOMAP_Init(void);
+
+int ISOMAP_LoadTileset(const uchar *, size_t);
+
+int ISOMAP_LoadMetaTileset(const uchar *, size_t);
+
+int ISOMAP_LoadMetamap(const uchar * mm_res_p, size_t mm_res_len);
+
+int ISOMAP_Draw(R_SURFACE * dst_s);
+
+} // End of namespace Saga
+
+#endif /* SAGA_ISOMAP_MOD_H_ */
diff --git a/saga/ite_introproc.cpp b/saga/ite_introproc.cpp
new file mode 100644
index 0000000000..8190472af9
--- /dev/null
+++ b/saga/ite_introproc.cpp
@@ -0,0 +1,1177 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Intro sequence scene procedures
+
+ Notes:
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "yslib.h"
+
+#include "reinherit.h"
+
+/*
+ * Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "animation_mod.h"
+#include "cvar_mod.h"
+#include "events_mod.h"
+#include "font_mod.h"
+#include "game_mod.h"
+#include "rscfile_mod.h"
+#include "scene_mod.h"
+#include "sndres_mod.h"
+#include "text_mod.h"
+#include "palanim_mod.h"
+
+/*
+ * Begin module:
+\*--------------------------------------------------------------------------*/
+#include "scene.h"
+#include "ite_introproc.h"
+
+namespace Saga {
+
+static R_INTRO_DIALOGUE IntroDiag[] = {
+
+ {
+ CAVE_VOICE_0, "intro1a",
+ "We see the sky, we see the land, we see the water, "
+ "and we wonder: Are we the only ones?"},
+ {
+ CAVE_VOICE_1, "intro2a",
+ "Long before we came to exist, the humans ruled "
+ "the Earth."},
+ {
+ CAVE_VOICE_2, "intro3a",
+ "They made marvelous things, and moved whole " "mountains."},
+ {
+ CAVE_VOICE_3, "intro4a",
+ "They knew the Secret of Flight, the Secret of "
+ "Happiness, and other secrets beyond our imagining."},
+ {
+ CAVE_VOICE_4, "intro1b",
+ "The humans also knew the Secret of Life, "
+ "and used it to give us the Four Great Gifts:"},
+ {
+ CAVE_VOICE_5, "intro2b",
+ "Thinking minds, feeling hearts, speaking "
+ "mouths, and reaching hands."},
+ {
+ CAVE_VOICE_6, "intro3b",
+ "We are their children."},
+ {
+ CAVE_VOICE_7, "intro1c",
+ "They taught us how to use our hands, and how " "to speak."},
+ {
+ CAVE_VOICE_8, "intro2c",
+ "They showed us the joy of using our minds."},
+ {
+ CAVE_VOICE_9, "intro3c",
+ "They loved us, and when we were ready, they "
+ "surely would have given us the Secret of Happiness."},
+
+ {
+ CAVE_VOICE_10, "intro1d",
+ "And now we see the sky, the land, and the water "
+ "that we are heirs to, and we wonder: why did "
+ "they leave?"},
+
+ {
+ CAVE_VOICE_11, "intro2d",
+ "Do they live still, in the stars? In the oceans "
+ "depths? In the wind?"},
+ {
+ CAVE_VOICE_12, "intro3d",
+ "We wonder, was their fate good or evil?"},
+
+ {
+ CAVE_VOICE_13, "intro4d",
+ "And will we also share the same fate one day?"},
+};
+
+R_SCENE_QUEUE ITE_IntroList[] = {
+ {ITE_INTRO_ANIM_SCENE, NULL, BY_RESOURCE, ITE_IntroAnimProc, 0},
+ {ITE_CAVE_SCENE_1, NULL, BY_RESOURCE, ITE_IntroCave1Proc, 1},
+ {ITE_CAVE_SCENE_2, NULL, BY_RESOURCE, ITE_IntroCave2Proc, 0},
+ {ITE_CAVE_SCENE_3, NULL, BY_RESOURCE, ITE_IntroCave3Proc, 0},
+ {ITE_CAVE_SCENE_4, NULL, BY_RESOURCE, ITE_IntroCave4Proc, 0},
+ {ITE_VALLEY_SCENE, NULL, BY_RESOURCE, ITE_IntroValleyProc, 0},
+ {ITE_TREEHOUSE_SCENE, NULL, BY_RESOURCE, ITE_IntroTreeHouseProc, 0},
+ {ITE_FAIREPATH_SCENE, NULL, BY_RESOURCE, ITE_IntroFairePathProc, 0},
+ {ITE_FAIRETENT_SCENE, NULL, BY_RESOURCE, ITE_IntroFaireTentProc, 0}
+};
+
+int ITE_StartProc(void)
+{
+ size_t n_introscenes;
+ size_t i;
+
+ R_SCENE_QUEUE first_scene;
+ R_GAME_SCENEDESC gs_desc;
+
+ n_introscenes = YS_NELEMS(ITE_IntroList);
+
+ for (i = 0; i < n_introscenes; i++) {
+
+ SCENE_Queue(&ITE_IntroList[i]);
+ }
+
+ GAME_GetSceneInfo(&gs_desc);
+
+ first_scene.load_flag = BY_SCENE;
+ first_scene.scene_n = gs_desc.first_scene;
+ first_scene.scene_skiptarget = 1;
+ first_scene.scene_proc = InitialSceneProc;
+
+ SCENE_Queue(&first_scene);
+
+ return R_SUCCESS;
+}
+
+int ITE_IntroRegisterLang(void)
+{
+
+ size_t i;
+
+ for (i = 0; i < YS_NELEMS(IntroDiag); i++) {
+
+ if (CVAR_Register_S(IntroDiag[i].i_str,
+ IntroDiag[i].i_cvar_name,
+ NULL, R_CVAR_CFG, R_INTRO_STRMAX) != R_SUCCESS) {
+
+ R_printf(R_STDERR,
+ "Error registering intro text cvars.");
+
+ return R_FAILURE;
+ }
+ }
+
+ return R_SUCCESS;
+}
+
+int ITE_IntroAnimProc(int param, R_SCENE_INFO * scene_info)
+/*--------------------------------------------------------------------------*\
+ * Handles the introductory Dreamer's Guild / NWC logo animation scene.
+\*--------------------------------------------------------------------------*/
+{
+ R_EVENT event;
+
+ YS_IGNORE_PARAM(scene_info);
+
+ switch (param) {
+
+ case SCENE_BEGIN:
+
+ /* Background for intro scene is the first frame of the
+ * intro animation; display it and set the palette
+ \*-----------------------------------------------------*/
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_BG_EVENT;
+ event.op = EVENT_DISPLAY;
+ event.param = SET_PALETTE;
+ event.time = 0;
+
+ EVENT_Queue(&event);
+
+ R_printf(R_STDOUT, "Intro animation procedure started.\n");
+ R_printf(R_STDOUT, "Linking animation resources...\n");
+
+ ANIM_SetFrameTime(0, ITE_INTRO_FRAMETIME);
+
+ /* Link this scene's animation resources for continuous
+ * playback
+ \*-----------------------------------------------------*/
+ ANIM_Link(0, 1);
+ ANIM_Link(1, 2);
+ ANIM_Link(2, 3);
+ ANIM_Link(3, 4);
+ ANIM_Link(4, 5);
+ ANIM_Link(5, 6);
+
+ /* Scene should end on display of last animation frame
+ * \*----------------------------------------------------- */
+ ANIM_SetFlag(6, ANIM_ENDSCENE);
+
+ R_printf(R_STDOUT, "Beginning animation playback.\n");
+
+ ANIM_Play(0, 0);
+
+ /* Queue intro music playback
+ * \*----------------------------------------------------- */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_MUSIC_EVENT;
+ event.param = MUSIC_1;
+ event.param2 = R_MUSIC_LOOP;
+ event.op = EVENT_PLAY;
+ event.time = 0;
+
+ EVENT_Queue(&event);
+ break;
+
+ case SCENE_END:
+ break;
+
+ default:
+ R_printf(R_STDERR, "Illegal scene procedure parameter.\n");
+ break;
+
+ }
+
+ return 0;
+}
+
+int ITE_IntroCave1Proc(int param, R_SCENE_INFO * scene_info)
+/*--------------------------------------------------------------------------*\
+ * Handles first introductory cave painting scene
+\*--------------------------------------------------------------------------*/
+{
+ R_EVENT event = { 0 };
+ R_EVENT *q_event;
+
+ int event_time = 0;
+ int voice_len;
+ int voice_pad = 50;
+
+ R_TEXTLIST_ENTRY text_entry = { 0 };
+ R_TEXTLIST_ENTRY *entry_p;
+
+ PALENTRY *pal;
+
+ static PALENTRY current_pal[R_PAL_ENTRIES];
+
+ int i;
+
+ int font_flags = FONT_OUTLINE | FONT_CENTERED;
+
+ switch (param) {
+
+ case SCENE_BEGIN:
+
+ /* Fade to black out of the intro DG/NWC logo animation
+ * \*----------------------------------------------------- */
+ SYSGFX_GetCurrentPal(current_pal);
+
+ event.type = R_CONTINUOUS_EVENT;
+ event.code = R_PAL_EVENT;
+ event.op = EVENT_PALTOBLACK;
+ event.time = 0;
+ event.duration = PALETTE_FADE_DURATION;
+ event.data = current_pal;
+
+ q_event = EVENT_Queue(&event);
+
+ /* Display scene background, but stay with black palette
+ * \*----------------------------------------------------- */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_BG_EVENT;
+ event.op = EVENT_DISPLAY;
+ event.param = NO_SET_PALETTE;
+ event.time = 0;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ /* Fade in from black to the scene background palette
+ * \*----------------------------------------------------- */
+ SCENE_GetBGPal(&pal);
+
+ event.type = R_CONTINUOUS_EVENT;
+ event.code = R_PAL_EVENT;
+ event.op = EVENT_BLACKTOPAL;
+ event.time = 0;
+ event.duration = PALETTE_FADE_DURATION;
+ event.data = pal;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ /* Begin palette cycling animation for candles
+ * \*----------------------------------------------------- */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_PALANIM_EVENT;
+ event.op = EVENT_CYCLESTART;
+ event.time = 0;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ /* Queue narrator dialogue list
+ * \*----------------------------------------------------- */
+ text_entry.color = 255;
+ text_entry.effect_color = 0;
+ text_entry.text_x = 320 / 2;
+ text_entry.text_y = INTRO_CAPTION_Y;
+ text_entry.font_id = MEDIUM_FONT_ID;
+ text_entry.flags = font_flags;
+
+ for (i = INTRO_CAVE1_START; i < INTRO_CAVE1_END; i++) {
+
+ text_entry.string = IntroDiag[i].i_str;
+
+ entry_p = TEXT_AddEntry(scene_info->text_list,
+ &text_entry);
+
+ /* Display text */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_TEXT_EVENT;
+ event.op = EVENT_DISPLAY;
+ event.data = entry_p;
+ event.time = event_time;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ /* Play voice */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_VOICE_EVENT;
+ event.op = EVENT_PLAY;
+ event.param = IntroDiag[i].i_voice_rn;
+ event.time = event_time;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ voice_len =
+ SND_GetVoiceLength(IntroDiag[i].i_voice_rn);
+ if (voice_len < 0) {
+ voice_len = strlen(IntroDiag[i].i_str) *
+ VOICE_LETTERLEN;
+ }
+
+ /* Remove text */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_TEXT_EVENT;
+ event.op = EVENT_REMOVE;
+ event.data = entry_p;
+ event.time = voice_len;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ event_time = voice_pad;
+
+ }
+
+ /* End scene after last dialogue over
+ * \*----------------------------------------------------- */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_SCENE_EVENT;
+ event.op = EVENT_END;
+ event.time = 0;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ break;
+
+ case SCENE_END:
+ break;
+
+ default:
+ R_printf(R_STDERR, "Illegal scene procedure paramater.\n");
+ break;
+
+ }
+
+ return 0;
+}
+
+int ITE_IntroCave2Proc(int param, R_SCENE_INFO * scene_info)
+/*--------------------------------------------------------------------------*\
+ * Handles second introductory cave painting scene
+\*--------------------------------------------------------------------------*/
+{
+
+ R_EVENT event = { 0 };
+ R_EVENT *q_event;
+
+ int event_time = 0;
+ int voice_len;
+ int voice_pad = 50;
+
+ R_TEXTLIST_ENTRY text_entry = { 0 };
+ R_TEXTLIST_ENTRY *entry_p;
+
+ int i;
+
+ int font_flags = FONT_OUTLINE | FONT_CENTERED;
+
+ switch (param) {
+
+ case SCENE_BEGIN:
+
+ /* Start 'dissolve' transition to new scene background
+ * \*----------------------------------------------------- */
+ event.type = R_CONTINUOUS_EVENT;
+ event.code = R_TRANSITION_EVENT;
+ event.op = EVENT_DISSOLVE;
+ event.time = 0;
+ event.duration = DISSOLVE_DURATION;
+
+ q_event = EVENT_Queue(&event);
+
+ /* Begin palette cycling animation for candles
+ * \*----------------------------------------------------- */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_PALANIM_EVENT;
+ event.op = EVENT_CYCLESTART;
+ event.time = 0;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ /* Queue narrator dialogue list
+ * \*----------------------------------------------------- */
+ text_entry.color = 255;
+ text_entry.effect_color = 0;
+ text_entry.text_x = 320 / 2;
+ text_entry.text_y = INTRO_CAPTION_Y;
+ text_entry.font_id = MEDIUM_FONT_ID;
+ text_entry.flags = font_flags;
+
+ for (i = INTRO_CAVE2_START; i < INTRO_CAVE2_END; i++) {
+
+ text_entry.string = IntroDiag[i].i_str;
+
+ entry_p = TEXT_AddEntry(scene_info->text_list,
+ &text_entry);
+
+ /* Display text */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_TEXT_EVENT;
+ event.op = EVENT_DISPLAY;
+ event.data = entry_p;
+ event.time = event_time;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ /* Play voice */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_VOICE_EVENT;
+ event.op = EVENT_PLAY;
+ event.param = IntroDiag[i].i_voice_rn;
+ event.time = event_time;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ voice_len =
+ SND_GetVoiceLength(IntroDiag[i].i_voice_rn);
+ if (voice_len < 0) {
+ voice_len = strlen(IntroDiag[i].i_str) *
+ VOICE_LETTERLEN;
+ }
+
+ /* Remove text */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_TEXT_EVENT;
+ event.op = EVENT_REMOVE;
+ event.data = entry_p;
+ event.time = voice_len;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ event_time = voice_pad;
+ }
+
+ /* End scene after last dialogue over
+ * \*----------------------------------------------------- */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_SCENE_EVENT;
+ event.op = EVENT_END;
+ event.time = event_time;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ break;
+
+ case SCENE_END:
+ break;
+
+ default:
+ R_printf(R_STDERR, "Illegal scene procedure paramater.\n");
+ break;
+
+ }
+
+ return 0;
+}
+
+int ITE_IntroCave3Proc(int param, R_SCENE_INFO * scene_info)
+/*--------------------------------------------------------------------------*\
+ * Handles third introductory cave painting scene
+\*--------------------------------------------------------------------------*/
+{
+ R_EVENT event = { 0 };
+ R_EVENT *q_event;
+
+ int event_time = 0;
+ int voice_len;
+ int voice_pad = 50;
+
+ R_TEXTLIST_ENTRY text_entry = { 0 };
+ R_TEXTLIST_ENTRY *entry_p;
+
+ int i;
+
+ int font_flags = FONT_OUTLINE | FONT_CENTERED;
+
+ switch (param) {
+
+ case SCENE_BEGIN:
+
+ /* Start 'dissolve' transition to new scene background
+ * \*----------------------------------------------------- */
+ event.type = R_CONTINUOUS_EVENT;
+ event.code = R_TRANSITION_EVENT;
+ event.op = EVENT_DISSOLVE;
+ event.time = 0;
+ event.duration = DISSOLVE_DURATION;
+
+ q_event = EVENT_Queue(&event);
+
+ /* Begin palette cycling animation for candles
+ * \*----------------------------------------------------- */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_PALANIM_EVENT;
+ event.op = EVENT_CYCLESTART;
+ event.time = 0;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ /* Queue narrator dialogue list
+ * \*----------------------------------------------------- */
+ text_entry.color = 255;
+ text_entry.effect_color = 0;
+ text_entry.text_x = 320 / 2;
+ text_entry.text_y = INTRO_CAPTION_Y;
+ text_entry.font_id = MEDIUM_FONT_ID;
+ text_entry.flags = font_flags;
+
+ for (i = INTRO_CAVE3_START; i < INTRO_CAVE3_END; i++) {
+
+ text_entry.string = IntroDiag[i].i_str;
+
+ entry_p = TEXT_AddEntry(scene_info->text_list,
+ &text_entry);
+
+ /* Display text */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_TEXT_EVENT;
+ event.op = EVENT_DISPLAY;
+ event.data = entry_p;
+ event.time = event_time;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ /* Play voice */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_VOICE_EVENT;
+ event.op = EVENT_PLAY;
+ event.param = IntroDiag[i].i_voice_rn;
+ event.time = event_time;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ voice_len =
+ SND_GetVoiceLength(IntroDiag[i].i_voice_rn);
+ if (voice_len < 0) {
+ voice_len = strlen(IntroDiag[i].i_str) *
+ VOICE_LETTERLEN;
+ }
+
+ /* Remove text */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_TEXT_EVENT;
+ event.op = EVENT_REMOVE;
+ event.data = entry_p;
+ event.time = voice_len;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ event_time = voice_pad;
+ }
+
+ /* End scene after last dialogue over
+ * \*----------------------------------------------------- */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_SCENE_EVENT;
+ event.op = EVENT_END;
+ event.time = event_time;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ break;
+
+ case SCENE_END:
+ break;
+
+ default:
+ R_printf(R_STDERR, "Illegal scene procedure paramater.\n");
+ break;
+
+ }
+
+ return 0;
+}
+
+int ITE_IntroCave4Proc(int param, R_SCENE_INFO * scene_info)
+/*--------------------------------------------------------------------------*\
+ * Handles fourth introductory cave painting scene
+\*--------------------------------------------------------------------------*/
+{
+ R_EVENT event = { 0 };
+ R_EVENT *q_event;
+
+ int event_time = 0;
+ int voice_len;
+ int voice_pad = 50;
+
+ R_TEXTLIST_ENTRY text_entry = { 0 };
+ R_TEXTLIST_ENTRY *entry_p;
+
+ int i;
+
+ int font_flags = FONT_OUTLINE | FONT_CENTERED;
+
+ switch (param) {
+
+ case SCENE_BEGIN:
+
+ /* Start 'dissolve' transition to new scene background
+ * \*----------------------------------------------------- */
+ event.type = R_CONTINUOUS_EVENT;
+ event.code = R_TRANSITION_EVENT;
+ event.op = EVENT_DISSOLVE;
+ event.time = 0;
+ event.duration = DISSOLVE_DURATION;
+
+ q_event = EVENT_Queue(&event);
+
+ /* Begin palette cycling animation for candles
+ * \*----------------------------------------------------- */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_PALANIM_EVENT;
+ event.op = EVENT_CYCLESTART;
+ event.time = 0;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ /* Queue narrator dialogue list
+ * \*----------------------------------------------------- */
+ text_entry.color = 255;
+ text_entry.effect_color = 0;
+ text_entry.text_x = 320 / 2;
+ text_entry.text_y = INTRO_CAPTION_Y;
+ text_entry.font_id = MEDIUM_FONT_ID;
+ text_entry.flags = font_flags;
+
+ for (i = INTRO_CAVE4_START; i < INTRO_CAVE4_END; i++) {
+
+ text_entry.string = IntroDiag[i].i_str;
+ entry_p = TEXT_AddEntry(scene_info->text_list,
+ &text_entry);
+
+ /* Display text */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_TEXT_EVENT;
+ event.op = EVENT_DISPLAY;
+ event.data = entry_p;
+ event.time = event_time;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ /* Play voice */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_VOICE_EVENT;
+ event.op = EVENT_PLAY;
+ event.param = IntroDiag[i].i_voice_rn;
+ event.time = event_time;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ voice_len =
+ SND_GetVoiceLength(IntroDiag[i].i_voice_rn);
+ if (voice_len < 0) {
+ voice_len = strlen(IntroDiag[i].i_str) *
+ VOICE_LETTERLEN;
+ }
+
+ /* Remove text */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_TEXT_EVENT;
+ event.op = EVENT_REMOVE;
+ event.data = entry_p;
+ event.time = voice_len;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ event_time = voice_pad;
+
+ }
+
+ /* End scene after last dialogue over
+ * \*----------------------------------------------------- */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_SCENE_EVENT;
+ event.op = EVENT_END;
+ event.time = event_time;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ break;
+
+ case SCENE_END:
+ break;
+
+ default:
+ R_printf(R_STDERR, "Illegal scene procedure paramater.\n");
+ break;
+
+ }
+
+ return 0;
+
+}
+
+int ITE_IntroValleyProc(int param, R_SCENE_INFO * scene_info)
+/*--------------------------------------------------------------------------*\
+ * Handles intro title scene (valley overlook)
+\*--------------------------------------------------------------------------*/
+{
+ R_TEXTLIST_ENTRY text_entry = { 0 };
+ R_TEXTLIST_ENTRY *entry_p;
+
+ R_EVENT event;
+ R_EVENT *q_event;
+
+ int i;
+
+ const INTRO_CREDIT credits[] = {
+ {160, 44, 9000, CREDIT_DURATION1,
+ "Producer", SMALL_FONT_ID},
+ {160, 56, 0, CREDIT_DURATION1,
+ "Walter Hochbrueckner", MEDIUM_FONT_ID},
+ {160, 88, 0, CREDIT_DURATION1,
+ "Executive Producer", SMALL_FONT_ID},
+ {160, 100, 0, CREDIT_DURATION1,
+ "Robert McNally", MEDIUM_FONT_ID},
+ {160, 132, 0, CREDIT_DURATION1,
+ "Publisher", SMALL_FONT_ID},
+ {160, 144, 0, CREDIT_DURATION1,
+ "Jon Van Caneghem", MEDIUM_FONT_ID}
+ };
+
+ int n_credits = sizeof credits / sizeof credits[0];
+
+ int event_delay = 0;
+
+ switch (param) {
+
+ case SCENE_BEGIN:
+
+ /* Display ITE title screen background
+ * \*----------------------------------------------------- */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_BG_EVENT;
+ event.op = EVENT_DISPLAY;
+ event.param = SET_PALETTE;
+ event.time = 0;
+
+ q_event = EVENT_Queue(&event);
+
+ R_printf(R_STDOUT, "Beginning animation playback.\n");
+
+ /* Begin title screen background animation
+ * \*----------------------------------------------------- */
+ ANIM_SetFlag(0, ANIM_LOOP);
+ ANIM_Play(0, 0);
+
+ /* Begin ITE title theme music
+ * \*----------------------------------------------------- */
+ SYSMUSIC_Stop();
+
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_MUSIC_EVENT;
+ event.param = MUSIC_2;
+ event.op = EVENT_PLAY;
+ event.time = 0;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ /* Queue game credits list
+ * \*----------------------------------------------------- */
+ text_entry.color = 255;
+ text_entry.effect_color = 0;
+ text_entry.flags = FONT_OUTLINE | FONT_CENTERED;
+
+ for (i = 0; i < n_credits; i++) {
+
+ text_entry.string = credits[i].string;
+ text_entry.font_id = credits[i].font_id;
+ text_entry.text_x = credits[i].text_x;
+ text_entry.text_y = credits[i].text_y;
+
+ entry_p = TEXT_AddEntry(scene_info->text_list,
+ &text_entry);
+
+ /* Display text */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_TEXT_EVENT;
+ event.op = EVENT_DISPLAY;
+ event.data = entry_p;
+ event.time = event_delay += credits[i].delta_time;
+
+ q_event = EVENT_Queue(&event);
+
+ /* Remove text */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_TEXT_EVENT;
+ event.op = EVENT_REMOVE;
+ event.data = entry_p;
+ event.time = credits[i].duration;
+
+ q_event = EVENT_Chain(q_event, &event);
+ }
+
+ /* End scene after credit display
+ * \*----------------------------------------------------- */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_SCENE_EVENT;
+ event.op = EVENT_END;
+ event.time = 1000;
+
+ q_event = EVENT_Chain(q_event, &event);
+ break;
+
+ case SCENE_END:
+ break;
+
+ default:
+ R_printf(R_STDERR, "Illegal scene procedure parameter.\n");
+ break;
+
+ }
+
+ return 0;
+}
+
+int ITE_IntroTreeHouseProc(int param, R_SCENE_INFO * scene_info)
+/*--------------------------------------------------------------------------*\
+ * Handles second intro credit screen (treehouse view)
+\*--------------------------------------------------------------------------*/
+{
+ R_TEXTLIST_ENTRY text_entry = { 0 };
+ R_TEXTLIST_ENTRY *entry_p;
+
+ R_EVENT event = { 0 };
+ R_EVENT *q_event;
+
+ int i;
+
+ const INTRO_CREDIT credits[] = {
+ {160, 58, 2000, CREDIT_DURATION1,
+ "Game Design", SMALL_FONT_ID},
+ {160, 70, 0, CREDIT_DURATION1,
+ "Talin, Joe Pearce, Robert McNally", MEDIUM_FONT_ID},
+ {160, 80, 0, CREDIT_DURATION1,
+ "and Carolly Hauksdottir", MEDIUM_FONT_ID},
+ {160, 119, 0, CREDIT_DURATION1,
+ "Screenplay and Dialog", SMALL_FONT_ID},
+ {160, 131, 0, CREDIT_DURATION1,
+ "Robert Leh, Len Wein, and Bill Rotsler",
+ MEDIUM_FONT_ID},
+ {160, 54, 5000, CREDIT_DURATION1,
+ "Art", SMALL_FONT_ID},
+ {160, 66, 0, CREDIT_DURATION1,
+ "Edward Lacabanne, Glenn Price, April Lee,",
+ MEDIUM_FONT_ID},
+ {160, 76, 0, CREDIT_DURATION1,
+ "Lisa Iennaco, Brian Dowrick, Reed", MEDIUM_FONT_ID},
+ {160, 86, 0, CREDIT_DURATION1,
+ "Waller, Allison Hershey and Talin", MEDIUM_FONT_ID},
+ {160, 123, 0, CREDIT_DURATION1,
+ "Art Direction", SMALL_FONT_ID},
+ {160, 135, 0, CREDIT_DURATION1,
+ "Allison Hershey", MEDIUM_FONT_ID}
+ };
+
+ int n_credits = YS_NELEMS(credits);
+
+ int event_delay = 0;
+
+ switch (param) {
+
+ case SCENE_BEGIN:
+
+ /* Start 'dissolve' transition to new scene background
+ * \*----------------------------------------------------- */
+ event.type = R_CONTINUOUS_EVENT;
+ event.code = R_TRANSITION_EVENT;
+ event.op = EVENT_DISSOLVE;
+ event.time = 0;
+ event.duration = DISSOLVE_DURATION;
+
+ q_event = EVENT_Queue(&event);
+
+ event_delay = DISSOLVE_DURATION;
+
+ /* Begin title screen background animation
+ * \*----------------------------------------------------- */
+ ANIM_SetFrameTime(0, 100);
+ ANIM_Play(0, event_delay);
+
+ /* Queue game credits list
+ * \*----------------------------------------------------- */
+ text_entry.color = 255;
+ text_entry.effect_color = 0;
+ text_entry.flags = FONT_OUTLINE | FONT_CENTERED;
+
+ for (i = 0; i < n_credits; i++) {
+
+ text_entry.string = credits[i].string;
+ text_entry.font_id = credits[i].font_id;
+ text_entry.text_x = credits[i].text_x;
+ text_entry.text_y = credits[i].text_y;
+
+ entry_p = TEXT_AddEntry(scene_info->text_list,
+ &text_entry);
+
+ /* Display text */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_TEXT_EVENT;
+ event.op = EVENT_DISPLAY;
+ event.data = entry_p;
+ event.time = event_delay += credits[i].delta_time;
+
+ q_event = EVENT_Queue(&event);
+
+ /* Remove text */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_TEXT_EVENT;
+ event.op = EVENT_REMOVE;
+ event.data = entry_p;
+ event.time = credits[i].duration;
+
+ q_event = EVENT_Chain(q_event, &event);
+ }
+
+ /* End scene after credit display
+ * \*----------------------------------------------------- */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_SCENE_EVENT;
+ event.op = EVENT_END;
+ event.time = 1000;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ break;
+
+ case SCENE_END:
+
+ break;
+
+ default:
+ R_printf(R_STDERR, "Illegal scene procedure parameter.\n");
+ break;
+
+ }
+
+ return 0;
+
+}
+
+int ITE_IntroFairePathProc(int param, R_SCENE_INFO * scene_info)
+/*--------------------------------------------------------------------------*\
+ * Handles third intro credit screen (path to puzzle tent)
+\*--------------------------------------------------------------------------*/
+{
+ R_TEXTLIST_ENTRY text_entry = { 0 };
+ R_TEXTLIST_ENTRY *entry_p;
+
+ R_EVENT event = { 0 };
+ R_EVENT *q_event;
+
+ long event_delay = 0;
+
+ int i;
+
+ INTRO_CREDIT credits[] = {
+ {160, 58, 2000, CREDIT_DURATION1,
+ "Original Game Engine Programming", SMALL_FONT_ID},
+
+ {160, 70, 0, CREDIT_DURATION1,
+ "Talin, Walter Hochbrueckner,", MEDIUM_FONT_ID},
+
+ {160, 80, 0, CREDIT_DURATION1,
+ "Joe Burks and Robert Wiggins", MEDIUM_FONT_ID},
+
+ {160, 119, 0, CREDIT_DURATION1,
+ "Music and Sound", SMALL_FONT_ID},
+
+ {160, 131, 0, CREDIT_DURATION1,
+ "Matt Nathan", MEDIUM_FONT_ID},
+
+ {160, 58, 5000, CREDIT_DURATION1,
+ "Directed by", SMALL_FONT_ID},
+
+ {160, 70, 0, CREDIT_DURATION1,
+ "Talin", MEDIUM_FONT_ID},
+
+ {160, 119, 0, CREDIT_DURATION1,
+ "Game Engine Reconstruction", SMALL_FONT_ID},
+
+ {160, 131, 0, CREDIT_DURATION1,
+ "Alpha software - Use at your own risk.",
+ MEDIUM_FONT_ID}
+ };
+
+ int n_credits = sizeof credits / sizeof credits[0];
+
+ switch (param) {
+
+ case SCENE_BEGIN:
+
+ /* Start 'dissolve' transition to new scene background
+ * \*----------------------------------------------------- */
+ event.type = R_CONTINUOUS_EVENT;
+ event.code = R_TRANSITION_EVENT;
+ event.op = EVENT_DISSOLVE;
+ event.time = 0;
+ event.duration = DISSOLVE_DURATION;
+
+ q_event = EVENT_Queue(&event);
+
+ event_delay = DISSOLVE_DURATION;
+
+ /* Begin title screen background animation
+ * \*----------------------------------------------------- */
+ ANIM_SetFlag(0, ANIM_LOOP);
+ ANIM_Play(0, event_delay);
+
+ /* Queue game credits list
+ * \*----------------------------------------------------- */
+ text_entry.color = 255;
+ text_entry.effect_color = 0;
+ text_entry.flags = FONT_OUTLINE | FONT_CENTERED;
+
+ for (i = 0; i < n_credits; i++) {
+
+ text_entry.string = credits[i].string;
+ text_entry.font_id = credits[i].font_id;
+ text_entry.text_x = credits[i].text_x;
+ text_entry.text_y = credits[i].text_y;
+
+ entry_p = TEXT_AddEntry(scene_info->text_list,
+ &text_entry);
+
+ /* Display text */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_TEXT_EVENT;
+ event.op = EVENT_DISPLAY;
+ event.data = entry_p;
+ event.time = event_delay += credits[i].delta_time;
+
+ q_event = EVENT_Queue(&event);
+
+ /* Remove text */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_TEXT_EVENT;
+ event.op = EVENT_REMOVE;
+ event.data = entry_p;
+ event.time = credits[i].duration;
+
+ q_event = EVENT_Chain(q_event, &event);
+ }
+
+ /* End scene after credit display
+ * \*----------------------------------------------------- */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_SCENE_EVENT;
+ event.op = EVENT_END;
+ event.time = 1000;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ break;
+
+ case SCENE_END:
+ break;
+
+ default:
+ R_printf(R_STDERR, "Illegal scene procedure parameter.\n");
+ break;
+
+ }
+
+ return 0;
+}
+
+int ITE_IntroFaireTentProc(int param, R_SCENE_INFO * scene_info)
+/*--------------------------------------------------------------------------*\
+ * Handles fourth intro credit screen (treehouse view)
+\*--------------------------------------------------------------------------*/
+{
+ R_EVENT event = { 0 };
+ R_EVENT *q_event;
+ R_EVENT *q_event_start;
+
+ YS_IGNORE_PARAM(scene_info);
+
+ switch (param) {
+
+ case SCENE_BEGIN:
+
+ /* Start 'dissolve' transition to new scene background
+ * \*----------------------------------------------------- */
+ event.type = R_CONTINUOUS_EVENT;
+ event.code = R_TRANSITION_EVENT;
+ event.op = EVENT_DISSOLVE;
+ event.time = 0;
+ event.duration = DISSOLVE_DURATION;
+
+ q_event_start = EVENT_Queue(&event);
+
+ /* End scene after momentary pause
+ * \*----------------------------------------------------- */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_SCENE_EVENT;
+ event.op = EVENT_END;
+ event.time = 5000;
+
+ q_event = EVENT_Chain(q_event_start, &event);
+
+ break;
+
+ case SCENE_END:
+
+ break;
+
+ default:
+ R_printf(R_STDERR, "Illegal scene procedure parameter.\n");
+ break;
+
+ }
+
+ return 0;
+}
+
+} // End of namespace Saga
diff --git a/saga/ite_introproc.h b/saga/ite_introproc.h
new file mode 100644
index 0000000000..77c2035280
--- /dev/null
+++ b/saga/ite_introproc.h
@@ -0,0 +1,92 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Intro sequence scene procedures header file
+
+ Notes:
+*/
+
+#ifndef SAGA_ITE_INTRO_H_
+#define SAGA_ITE_INTRO_H_
+
+namespace Saga {
+
+#define R_INTRO_STRMAX 256
+
+#define ITE_INTRO_FRAMETIME 90
+
+#define INTRO_CAPTION_Y 170
+#define VOICE_PAD 50
+#define VOICE_LETTERLEN 90
+
+#define PALETTE_FADE_DURATION 1000
+#define DISSOLVE_DURATION 3000
+
+#define CREDIT_DURATION1 4000
+
+enum R_INTRO_SCENE_DIALOGUE_INFO {
+
+ INTRO_CAVE1_START = 0,
+ INTRO_CAVE1_END = 4,
+
+ INTRO_CAVE2_START = 4,
+ INTRO_CAVE2_END = 7,
+
+ INTRO_CAVE3_START = 7,
+ INTRO_CAVE3_END = 10,
+
+ INTRO_CAVE4_START = 10,
+ INTRO_CAVE4_END = 14
+};
+
+typedef struct R_INTRO_DIALOGUE_tag {
+
+ ulong i_voice_rn;
+ char *i_cvar_name;
+ char i_str[R_INTRO_STRMAX];
+
+} R_INTRO_DIALOGUE;
+
+typedef struct INTRO_CAPTION_tag {
+
+ int res_n;
+ char *caption;
+
+} INTRO_CAPTION;
+
+typedef struct INTRO_CREDIT_tag {
+
+ int text_x;
+ int text_y;
+ int delta_time;
+ int duration;
+ char *string;
+ int font_id;
+
+} INTRO_CREDIT;
+
+} // End of namespace Saga
+
+#endif /* SAGA_ITE_INTRO_H_ */
diff --git a/saga/ite_introproc_mod.h b/saga/ite_introproc_mod.h
new file mode 100644
index 0000000000..d90a7783ec
--- /dev/null
+++ b/saga/ite_introproc_mod.h
@@ -0,0 +1,40 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Intro sequence scene procedures - public header file
+
+ Notes:
+*/
+
+#ifndef SAGA_ITE_INTROPROC_MOD_H_
+#define SAGA_ITE_INTROPROC_MOD_H_
+
+namespace Saga {
+
+int ITE_IntroRegisterLang(void);
+
+} // End of namespace Saga
+
+#endif /* SAGA_ITE_INTROPROC_MOD_H_ */
diff --git a/saga/math.cpp b/saga/math.cpp
new file mode 100644
index 0000000000..1c3b12fc93
--- /dev/null
+++ b/saga/math.cpp
@@ -0,0 +1,72 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ Math routines
+
+ Notes:
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "reinherit.h"
+
+namespace Saga {
+
+int
+MATH_HitTestPoly(R_POINT * points, unsigned int npoints, R_POINT test_point)
+{
+ int yflag0;
+ int yflag1;
+ int inside_flag = 0;
+ unsigned int pt;
+
+ R_POINT *vtx0 = &points[npoints - 1];
+ R_POINT *vtx1 = &points[0];
+
+ yflag0 = (vtx0->y >= test_point.y);
+
+ for (pt = 0; pt < npoints; pt++, vtx1++) {
+
+ yflag1 = (vtx1->y >= test_point.y);
+
+ if (yflag0 != yflag1) {
+
+ if (((vtx1->y - test_point.y) * (vtx0->x - vtx1->x) >=
+ (vtx1->x - test_point.x) * (vtx0->y -
+ vtx1->y)) == yflag1) {
+
+ inside_flag = !inside_flag;
+ }
+ }
+ yflag0 = yflag1;
+ vtx0 = vtx1;
+ }
+
+ return inside_flag;
+}
+
+} // End of namespace Saga
diff --git a/saga/math.h b/saga/math.h
new file mode 100644
index 0000000000..645fd33bd7
--- /dev/null
+++ b/saga/math.h
@@ -0,0 +1,35 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ Math routines implementation header
+
+ Notes:
+*/
+
+#ifndef SAGA_MATH_H__
+#define SAGA_MATH_H__
+
+#endif /* SAGA_MATH_H__ */
diff --git a/saga/math_mod.h b/saga/math_mod.h
new file mode 100644
index 0000000000..13219fbebd
--- /dev/null
+++ b/saga/math_mod.h
@@ -0,0 +1,42 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ Math routines public header
+
+ Notes:
+*/
+
+#ifndef SAGA_MATH_MOD_H__
+#define SAGA_MATH_MOD_H__
+
+namespace Saga {
+
+int
+MATH_HitTestPoly(R_POINT * points, unsigned int npoints, R_POINT test_point);
+
+} // End of namespace Saga
+
+#endif /* SAGA_MATH_MOD_H__ */
diff --git a/saga/misc.cpp b/saga/misc.cpp
new file mode 100644
index 0000000000..e7a2c185ca
--- /dev/null
+++ b/saga/misc.cpp
@@ -0,0 +1,54 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Misc. routines
+
+ Notes:
+*/
+
+namespace Saga {
+
+int Granulate(int value, int granularity)
+{
+
+ int remainder;
+
+ if (value == 0)
+ return 0;
+
+ if (granularity == 0)
+ return 0;
+
+ remainder = value % granularity;
+
+ if (remainder == 0) {
+ return value;
+ } else {
+ return (granularity - remainder + value);
+ }
+
+}
+
+} // End of namespace Saga
diff --git a/saga/module.mk b/saga/module.mk
index 0f7e4d3b2c..430a9912bc 100644
--- a/saga/module.mk
+++ b/saga/module.mk
@@ -1,10 +1,56 @@
MODULE := saga
MODULE_OBJS = \
+ saga/actionmap.o \
+ saga/actor.o \
+ saga/actordata.o \
+ saga/animation.o \
+ saga/cmdline.o \
+ saga/console.o \
+ saga/cvar.o \
+ saga/events.o \
+ saga/expr.o \
+ saga/font.o \
+ saga/font_map.o \
+ saga/game.o \
+ saga/gfx.o \
+ saga/ihnm_introproc.o \
+ saga/image.o \
+ saga/interface.o \
+ saga/isomap.o \
+ saga/ite_introproc.o \
+ saga/math.o \
+ saga/misc.o \
+ saga/objectmap.o \
+ saga/palanim.o \
+ saga/render.o \
+ saga/rscfile.o \
saga/saga.o \
- saga/binread.o \
- saga/gamedesc.o \
- saga/resfile.o
+ saga/scene.o \
+ saga/sceneproc.o \
+ saga/script.o \
+ saga/sdata.o \
+ saga/sdebug.o \
+ saga/sfuncs.o \
+ saga/sndres.o \
+ saga/sprite.o \
+ saga/sstack.o \
+ saga/stack.o \
+ saga/sthread.o \
+ saga/text.o \
+ saga/transitions.o \
+ saga/xmidi.o \
+ saga/ys_binread.o \
+ saga/ys_binwrite.o \
+ saga/ys_dl_list.o \
+ saga/ys_file.o \
+ saga/sysgfx.o \
+ saga/sysinput.o \
+ saga/systimer.o \
+ saga/sysmusic.o \
+ saga/syssound.o \
+ saga/sysio.o \
+ saga/sys_fs.o
MODULE_DIRS += \
saga
diff --git a/saga/objectmap.cpp b/saga/objectmap.cpp
new file mode 100644
index 0000000000..bd3ec1df8b
--- /dev/null
+++ b/saga/objectmap.cpp
@@ -0,0 +1,556 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ Object map / Object click-area module
+
+ Notes:
+
+ Polygon Hit Test code ( HitTestPoly() ) adapted from code (C) Eric Haines
+ appearing in Graphics Gems IV, "Point in Polygon Strategies."
+ p. 24-46, code: p. 34-45
+*/
+
+#include "reinherit.h"
+
+#include "yslib.h"
+
+/*
+ * Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "cvar_mod.h"
+#include "console_mod.h"
+#include "gfx_mod.h"
+#include "math_mod.h"
+#include "font_mod.h"
+
+/*
+ * Module options
+\*--------------------------------------------------------------------------*/
+
+#define R_OBJECTMAP_DEBUG R_DEBUG_INFO
+
+/*
+ * Begin module
+\*--------------------------------------------------------------------------*/
+#include "objectmap_mod.h"
+#include "objectmap.h"
+
+namespace Saga {
+
+static R_OBJECTMAP_INFO OMInfo;
+
+int OBJECTMAP_Register(void)
+{
+
+ CVAR_RegisterFunc(CF_object_info,
+ "object_info", NULL, R_CVAR_NONE, 0, 0);
+
+ return R_SUCCESS;
+}
+
+int OBJECTMAP_Init(void)
+/*--------------------------------------------------------------------------*\
+ * Initializes the object map module, creates module allocation context
+\*--------------------------------------------------------------------------*/
+{
+ R_printf(R_STDOUT, "OBJECTMAP Module: Initializing...\n");
+
+ OMInfo.initialized = 1;
+ return R_SUCCESS;
+}
+
+int OBJECTMAP_Shutdown(void)
+/*--------------------------------------------------------------------------*\
+ * Shuts down the object map module, destroys module allocation context
+\*--------------------------------------------------------------------------*/
+{
+ if (!OMInfo.initialized) {
+ return R_FAILURE;
+ }
+
+ R_printf(R_STDOUT, "OBJECTMAP Module: Shutting down...\n");
+
+ OBJECTMAP_Free();
+ OBJECTMAP_FreeNames();
+
+ R_printf(R_STDOUT, "OBJECTMAP Module: Shutdown AOK.\n");
+
+ OMInfo.initialized = 0;
+ return R_SUCCESS;
+}
+
+int OBJECTMAP_Load(const uchar * om_res, size_t om_res_len)
+/*--------------------------------------------------------------------------*\
+ * Loads an object map resource ( objects ( clickareas ( points ) ) )
+\*--------------------------------------------------------------------------*/
+{
+ const unsigned char *read_p = om_res;
+
+ R_OBJECTMAP_ENTRY *object_map;
+ R_CLICKAREA *clickarea;
+ R_POINT *point;
+
+ int i, k, m;
+
+ YS_IGNORE_PARAM(om_res_len);
+
+ if (!OMInfo.initialized) {
+ R_printf(R_STDERR,
+ "Error: Object map module not initialized!\n");
+ return R_FAILURE;
+ }
+
+ if (OMInfo.objects_loaded) {
+ OBJECTMAP_Free();
+ }
+
+ /* Obtain object count N and allocate space for N objects
+ * \*------------------------------------------------------------- */
+ OMInfo.n_objects = ys_read_u16_le(read_p, &read_p);
+
+ OMInfo.object_maps =
+ (R_OBJECTMAP_ENTRY *)malloc(OMInfo.n_objects * sizeof *OMInfo.object_maps);
+
+ if (OMInfo.object_maps == NULL) {
+ R_printf(R_STDERR, "Error: Memory allocation failed.\n");
+ return R_MEM;
+ }
+
+ /* Load all N objects
+ * \*------------------------------------------------------------- */
+ for (i = 0; i < OMInfo.n_objects; i++) {
+
+ object_map = &OMInfo.object_maps[i];
+ object_map->unknown0 = ys_read_u8(read_p, &read_p);
+ object_map->n_clickareas = ys_read_u8(read_p, &read_p);
+ object_map->flags = ys_read_u16_le(read_p, &read_p);
+ object_map->object_num = ys_read_u16_le(read_p, &read_p);
+ object_map->script_num = ys_read_u16_le(read_p, &read_p);
+
+ object_map->clickareas =
+ (R_CLICKAREA *)malloc(object_map->n_clickareas *
+ sizeof *(object_map->clickareas));
+
+ if (object_map->clickareas == NULL) {
+ R_printf(R_STDERR,
+ "Error: Memory allocation failed.\n");
+ return R_MEM;
+ }
+
+ /* Load all clickareas for this object */
+ for (k = 0; k < object_map->n_clickareas; k++) {
+
+ clickarea = &object_map->clickareas[k];
+ clickarea->n_points = ys_read_u16_le(read_p, &read_p);
+ assert(clickarea->n_points != 0);
+
+ clickarea->points =
+ (R_POINT *)malloc(clickarea->n_points * sizeof *(clickarea->points));
+
+ if (clickarea->points == NULL) {
+ R_printf(R_STDERR,
+ "Error: Memory allocation failed.\n");
+ return R_MEM;
+ }
+
+ /* Load all points for this clickarea */
+ for (m = 0; m < clickarea->n_points; m++) {
+
+ point = &clickarea->points[m];
+ point->x = ys_read_s16_le(read_p, &read_p);
+ point->y = ys_read_s16_le(read_p, &read_p);
+ }
+
+# if R_OBJECTMAP_DEBUG >= R_DEBUG_PARANOID
+ R_printf(R_STDOUT,
+ "OBJECTMAP_Load(): "
+ "Read %d points for clickarea %d in object %d.\n",
+ clickarea->n_points, k, object_map->object_num);
+# endif
+ } /* End load all clickareas */
+ } /* End load all objects */
+
+ /*-------------------------------------------------------------*/
+ OMInfo.objects_loaded = 1;
+
+ return R_SUCCESS;
+}
+
+int OBJECTMAP_Free(void)
+/*--------------------------------------------------------------------------*\
+ * Frees all storage allocated for the current object map data
+\*--------------------------------------------------------------------------*/
+{
+ R_OBJECTMAP_ENTRY *object_map;
+ R_CLICKAREA *clickarea;
+
+ int i, k;
+
+ if (!OMInfo.objects_loaded) {
+ return R_FAILURE;
+ }
+
+ for (i = 0; i < OMInfo.n_objects; i++) {
+ object_map = &OMInfo.object_maps[i];
+
+ for (k = 0; k < object_map->n_clickareas; k++) {
+ clickarea = &object_map->clickareas[k];
+ free(clickarea->points);
+ }
+ free(object_map->clickareas);
+ }
+
+ if (OMInfo.n_objects) {
+ free(OMInfo.object_maps);
+ }
+
+ OMInfo.objects_loaded = 0;
+
+ return R_SUCCESS;
+}
+
+int OBJECTMAP_LoadNames(const unsigned char *onl_res, size_t onl_res_len)
+/*--------------------------------------------------------------------------*\
+ * Loads an object name list resource
+\*--------------------------------------------------------------------------*/
+{
+ YS_REG_FUNC(OBJECTMAP_LoadNames);
+ const unsigned char *read_p = onl_res;
+
+ int table_len;
+ int n_names;
+ size_t name_offset;
+
+ int i;
+
+ YS_IGNORE_PARAM(onl_res_len);
+
+ if (OMInfo.names_loaded) {
+ OBJECTMAP_FreeNames();
+ }
+
+ table_len = ys_read_u16_le(read_p, &read_p);
+
+ n_names = table_len / 2 - 2;
+ OMInfo.n_names = n_names;
+
+#if 0
+# if R_OBJECTMAP_DEBUG >= R_DEBUG_INFO
+ R_printf(R_STDOUT, "%s: Loading %d object names.\n", YS_FUNC, n_names);
+# endif
+#endif
+ OMInfo.names = (char **)malloc(n_names * sizeof *OMInfo.names);
+
+ if (OMInfo.names == NULL) {
+ R_printf(R_STDERR, "Error: Memory allocation failed.\n");
+ return R_MEM;
+ }
+
+ for (i = 0; i < n_names; i++) {
+ name_offset = ys_read_u16_le(read_p, &read_p);
+ OMInfo.names[i] = (char *)(onl_res + name_offset);
+
+# if R_OBJECTMAP_DEBUG >= R_DEBUG_VERBOSE
+ R_printf(R_STDOUT,
+ "Loaded object name string: %s\n", OMInfo.names[i]);
+# endif
+ }
+
+ OMInfo.names_loaded = 1;
+
+ return R_SUCCESS;
+}
+
+int OBJECTMAP_FreeNames(void)
+/*--------------------------------------------------------------------------*\
+ * Frees all storage allocated for the current object name list data
+\*--------------------------------------------------------------------------*/
+{
+ if (!OMInfo.names_loaded) {
+ return R_FAILURE;
+ }
+
+ if (OMInfo.n_names) {
+ free(OMInfo.names);
+ }
+
+ OMInfo.names_loaded = 0;
+ return R_SUCCESS;
+}
+
+int OBJECTMAP_GetName(int object, const char **name)
+/*--------------------------------------------------------------------------*\
+ * If 'object' is a valid object number in the currently loaded object
+ * name list resource, the funciton sets '*name' to the descriptive string
+ * corresponding to 'object' and returns R_SUCCESS. Otherwise it returns
+ * R_FAILURE.
+\*--------------------------------------------------------------------------*/
+{
+ if (!OMInfo.names_loaded) {
+ return R_FAILURE;
+ }
+
+ if ((object <= 0) || (object > OMInfo.n_names)) {
+ return R_FAILURE;
+ }
+
+ *name = OMInfo.names[object - 1];
+
+ return R_SUCCESS;
+}
+
+int OBJECTMAP_GetFlags(int object, uint * flags)
+{
+ int i;
+
+ if (!OMInfo.names_loaded) {
+ return R_FAILURE;
+ }
+
+ if ((object <= 0) || (object > OMInfo.n_names)) {
+ return R_FAILURE;
+ }
+
+ for (i = 0; i < OMInfo.n_objects; i++) {
+
+ if (OMInfo.object_maps[i].object_num == object) {
+
+ *flags = OMInfo.object_maps[i].flags;
+ return R_SUCCESS;
+ }
+ }
+
+ return R_FAILURE;
+}
+
+int OBJECTMAP_GetEPNum(int object, int *ep_num)
+/*--------------------------------------------------------------------------*\
+ * If 'object' is a valid object number in the currently loaded object
+ * name list resource, the funciton sets '*ep_num' to the entrypoint number
+ * corresponding to 'object' and returns R_SUCCESS. Otherwise, it returns
+ * R_FAILURE.
+\*--------------------------------------------------------------------------*/
+{
+ int i;
+
+ if (!OMInfo.names_loaded) {
+ return R_FAILURE;
+ }
+
+ if ((object < 0) || (object > (OMInfo.n_objects + 1))) {
+ return R_FAILURE;
+ }
+
+ for (i = 0; i < OMInfo.n_objects; i++) {
+
+ if (OMInfo.object_maps[i].object_num == object) {
+
+ *ep_num = OMInfo.object_maps[i].script_num;
+ return R_SUCCESS;
+ }
+ }
+
+ return R_FAILURE;
+}
+
+int OBJECTMAP_Draw(R_SURFACE * ds, R_POINT * imouse_pt, int color, int color2)
+/*--------------------------------------------------------------------------*\
+ * Uses GFX_DrawLine to display all clickareas for each object in the
+ * currently loaded object map resource.
+\*--------------------------------------------------------------------------*/
+{
+
+ R_OBJECTMAP_ENTRY *object_map;
+ R_CLICKAREA *clickarea;
+
+ char txt_buf[32];
+
+ int draw_color = color;
+ int draw_txt = 0;
+
+ int hit_object = 0;
+ int object_num = 0;
+
+ int pointcount = 0;
+ int i, k;
+
+ assert(OMInfo.initialized);
+
+ if (!OMInfo.objects_loaded) {
+ return R_FAILURE;
+ }
+
+ if (imouse_pt != NULL) {
+
+ if (OBJECTMAP_HitTest(imouse_pt, &object_num) == R_SUCCESS) {
+ hit_object = 1;
+ }
+ }
+
+ for (i = 0; i < OMInfo.n_objects; i++) {
+
+ draw_color = color;
+
+ if (hit_object &&
+ (object_num == OMInfo.object_maps[i].object_num)) {
+
+ snprintf(txt_buf,
+ sizeof txt_buf,
+ "obj %d: ? %d, f %X",
+ OMInfo.object_maps[i].object_num,
+ OMInfo.object_maps[i].unknown0,
+ OMInfo.object_maps[i].flags);
+
+ draw_txt = 1;
+ draw_color = color2;
+ }
+
+ object_map = &OMInfo.object_maps[i];
+
+ for (k = 0; k < object_map->n_clickareas; k++) {
+
+ clickarea = &object_map->clickareas[k];
+ pointcount = 0;
+
+ if (clickarea->n_points == 2) {
+
+ /* 2 points represent a box */
+ GFX_DrawFrame(ds,
+ &clickarea->points[0],
+ &clickarea->points[1], draw_color);
+ } else if (clickarea->n_points > 2) {
+
+ /* Otherwise draw a polyline */
+
+ GFX_DrawPolyLine(ds,
+ clickarea->points,
+ clickarea->n_points, draw_color);
+
+ }
+
+ } /* end for() clickareas */
+ } /* end for() objects */
+
+ if (draw_txt) {
+
+ FONT_Draw(SMALL_FONT_ID,
+ ds,
+ txt_buf,
+ 0,
+ 2, 2, SYSGFX_GetWhite(), SYSGFX_GetBlack(), FONT_OUTLINE);
+ }
+
+ return R_SUCCESS;
+}
+
+int OBJECTMAP_HitTest(R_POINT * imouse_pt, int *object_num)
+{
+
+ R_POINT imouse;
+ R_OBJECTMAP_ENTRY *object_map;
+ R_CLICKAREA *clickarea;
+ R_POINT *points;
+ int n_points;
+
+ int i, k;
+
+ assert((imouse_pt != NULL) && (object_num != NULL));
+
+ imouse.x = imouse_pt->x;
+ imouse.y = imouse_pt->y;
+
+ /* Loop through all scene objects */
+ for (i = 0; i < OMInfo.n_objects; i++) {
+
+ object_map = &OMInfo.object_maps[i];
+
+ /* Hit-test all clickareas for this object */
+ for (k = 0; k < object_map->n_clickareas; k++) {
+
+ clickarea = &object_map->clickareas[k];
+
+ n_points = clickarea->n_points;
+ points = clickarea->points;
+
+ if (n_points == 2) {
+ /* Hit-test a box region */
+ if ((imouse.x > points[0].x) &&
+ (imouse.x <= points[1].x) &&
+ (imouse.y > points[0].y) &&
+ (imouse.y <= points[1].y)) {
+
+ *object_num = object_map->object_num;
+
+ return R_SUCCESS;
+ }
+ } else if (n_points > 2) {
+ /* Hit-test a polygon */
+ if (MATH_HitTestPoly(points, n_points, imouse)) {
+
+ *object_num = object_map->object_num;
+
+ return R_SUCCESS;
+ }
+ }
+
+ } /* end for() clickareas */
+ } /* end for() objects */
+
+ *object_num = 0;
+
+ return R_FAILURE;
+}
+
+static void CF_object_info(int argc, char *argv[])
+{
+ int i;
+
+ YS_IGNORE_PARAM(argc);
+ YS_IGNORE_PARAM(argv);
+
+ if (!OMInfo.initialized) {
+ return;
+ }
+
+ CON_Print("%d objects loaded.", OMInfo.n_objects);
+
+ for (i = 0; i < OMInfo.n_objects; i++) {
+
+ CON_Print("%s:", OMInfo.names[i]);
+ CON_Print
+ ("%d. Unk1: %d, flags: %X, name_i: %d, scr_n: %d, ca_ct: %d",
+ i, OMInfo.object_maps[i].unknown0,
+ OMInfo.object_maps[i].flags,
+ OMInfo.object_maps[i].object_num,
+ OMInfo.object_maps[i].script_num,
+ OMInfo.object_maps[i].n_clickareas);
+
+ }
+
+ return;
+}
+
+} // End of namespace Saga
diff --git a/saga/objectmap.h b/saga/objectmap.h
new file mode 100644
index 0000000000..f5f1f92b25
--- /dev/null
+++ b/saga/objectmap.h
@@ -0,0 +1,75 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ Object map / Object click-area module header file
+
+ Notes:
+*/
+
+#ifndef SAGA_OBJECTMAP_H_
+#define SAGA_OBJECTMAP_H_
+
+namespace Saga {
+
+typedef struct R_CLICKAREA_tag {
+
+ int n_points;
+ R_POINT *points;
+
+} R_CLICKAREA;
+
+typedef struct R_OBJECTMAP_ENTRY_tag {
+
+ int unknown0;
+ uint flags;
+
+ int object_num;
+ int script_num;
+
+ int n_clickareas;
+ R_CLICKAREA *clickareas;
+
+} R_OBJECTMAP_ENTRY;
+
+typedef struct R_OBJECTMAP_INFO_tag {
+
+ int initialized;
+
+ int objects_loaded;
+ int n_objects;
+ R_OBJECTMAP_ENTRY *object_maps;
+
+ int names_loaded;
+ int n_names;
+ char **names;
+
+} R_OBJECTMAP_INFO;
+
+static void CF_object_info(int argc, char *argv[]);
+
+} // End of namespace Saga
+
+#endif /* SAGA_OBJECTMAP_H_ */
diff --git a/saga/objectmap_mod.h b/saga/objectmap_mod.h
new file mode 100644
index 0000000000..b1a1c13ae6
--- /dev/null
+++ b/saga/objectmap_mod.h
@@ -0,0 +1,70 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ Object map module public header file
+
+ Notes:
+*/
+
+#ifndef SAGA_OBJECTMAP_MOD_H__
+#define SAGA_OBJECTMAP_MOD_H__
+
+namespace Saga {
+
+enum R_OBJECT_FLAGS {
+
+ R_OBJECT_NORMAL = 0x02
+};
+
+int OBJECTMAP_Register(void);
+
+int OBJECTMAP_Init(void);
+
+int OBJECTMAP_Shutdown(void);
+
+int OBJECTMAP_Load(const uchar * om_res, size_t om_res_len);
+
+int OBJECTMAP_Free(void);
+
+int OBJECTMAP_LoadNames(const uchar * onl_res, size_t onl_res_len);
+
+int OBJECTMAP_FreeNames(void);
+
+int OBJECTMAP_GetName(int object, const char **name);
+
+int OBJECTMAP_GetFlags(int object, uint * flags);
+
+int OBJECTMAP_GetEPNum(int object, int *ep_num);
+
+int
+OBJECTMAP_Draw(R_SURFACE * draw_surface,
+ R_POINT * imouse_pt, int color, int color2);
+
+int OBJECTMAP_HitTest(R_POINT * imouse_pt, int *object_num);
+
+} // End of namespace Saga
+
+#endif /* SAGA_OBJECTMAP_MOD_H__ */
diff --git a/saga/palanim.cpp b/saga/palanim.cpp
new file mode 100644
index 0000000000..b24f3a35c0
--- /dev/null
+++ b/saga/palanim.cpp
@@ -0,0 +1,266 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Palette animation module
+
+ Notes:
+*/
+
+#include "reinherit.h"
+
+#include "yslib.h"
+
+/*
+ * Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "events_mod.h"
+#include "game_mod.h"
+
+/*
+ * Begin module:
+\*--------------------------------------------------------------------------*/
+#include "palanim_mod.h"
+#include "palanim.h"
+
+namespace Saga {
+
+static PALANIM_DATA PAnimData;
+
+int PALANIM_Load(const uchar * resdata, size_t resdata_len)
+{
+ const uchar *read_p = resdata;
+ void *test_p;
+
+ uint i;
+
+ YS_IGNORE_PARAM(resdata_len);
+
+ if (PAnimData.loaded) {
+ PALANIM_Free();
+ }
+
+ if (resdata == NULL) {
+ return R_FAILURE;
+ }
+
+ if (GAME_GetGameType() == R_GAMETYPE_IHNM) {
+ return R_SUCCESS;
+ }
+
+ PAnimData.entry_count = ys_read_u16_le(read_p, &read_p);
+
+ R_printf(R_STDOUT,
+ "PALANIM_Load(): Loading %d PALANIM entries.\n",
+ PAnimData.entry_count);
+
+ test_p = calloc(PAnimData.entry_count, sizeof(PALANIM_ENTRY));
+ if (test_p == NULL) {
+ R_printf(R_STDERR, "PALANIM_Load(): Allocation failure.\n");
+ return R_MEM;
+ }
+
+ PAnimData.entries = (PALANIM_ENTRY *)test_p;
+
+ for (i = 0; i < PAnimData.entry_count; i++) {
+
+ int color_count;
+ int pal_count;
+ int p, c;
+
+ color_count = ys_read_u16_le(read_p, &read_p);
+ pal_count = ys_read_u16_le(read_p, &read_p);
+
+ PAnimData.entries[i].pal_count = pal_count;
+ PAnimData.entries[i].color_count = color_count;
+
+# if 0
+ R_printf(R_STDOUT,
+ "PALANIM_Load(): Entry %d: Loading %d palette indices.\n",
+ i, pal_count);
+#endif
+
+ test_p = calloc(1, sizeof(char) * pal_count);
+ if (test_p == NULL) {
+ R_printf(R_STDERR,
+ "PALANIM_Load(): Allocation failure.\n");
+ return R_MEM;
+ }
+
+ PAnimData.entries[i].pal_index = (uchar *)test_p;
+
+# if 0
+ R_printf(R_STDOUT,
+ "PALANIM_Load(): Entry %d: Loading %d SAGA_COLOR "
+ "structures.\n", i, color_count);
+# endif
+
+ test_p = calloc(1, sizeof(R_COLOR) * color_count);
+ if (test_p == NULL) {
+ R_printf(R_STDERR,
+ "PALANIM_Load(): Allocation failure.\n");
+ return R_MEM;
+ }
+
+ PAnimData.entries[i].colors = (R_COLOR *)test_p;
+
+ for (p = 0; p < pal_count; p++) {
+ PAnimData.entries[i].pal_index[p] =
+ (uchar) ys_read_u8(read_p, &read_p);
+ }
+
+ for (c = 0; c < color_count; c++) {
+ PAnimData.entries[i].colors[c].red =
+ (uchar) ys_read_u8(read_p, &read_p);
+
+ PAnimData.entries[i].colors[c].green =
+ (uchar) ys_read_u8(read_p, &read_p);
+
+ PAnimData.entries[i].colors[c].blue =
+ (uchar) ys_read_u8(read_p, &read_p);
+ }
+ }
+
+ PAnimData.loaded = 1;
+ return R_SUCCESS;
+
+}
+
+int PALANIM_CycleStart(void)
+{
+
+ R_EVENT event;
+
+ if (!PAnimData.loaded) {
+ return R_FAILURE;
+ }
+
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_PALANIM_EVENT;
+ event.op = EVENT_CYCLESTEP;
+ event.time = PALANIM_CYCLETIME;
+
+ EVENT_Queue(&event);
+
+ return R_SUCCESS;
+
+}
+
+int PALANIM_CycleStep(int vectortime)
+{
+ R_SURFACE *back_buf;
+
+ static PALENTRY pal[256];
+ uint pal_index;
+ uint col_index;
+
+ uint i, j;
+ uint cycle;
+ uint cycle_limit;
+
+ R_EVENT event;
+
+ if (!PAnimData.loaded) {
+ return R_FAILURE;
+ }
+
+ SYSGFX_GetCurrentPal(pal);
+ back_buf = SYSGFX_GetBackBuffer();
+
+ for (i = 0; i < PAnimData.entry_count; i++) {
+
+ cycle = PAnimData.entries[i].cycle;
+ cycle_limit = PAnimData.entries[i].color_count;
+
+ for (j = 0; j < PAnimData.entries[i].pal_count; j++) {
+
+ pal_index =
+ (unsigned char)PAnimData.entries[i].pal_index[j];
+ col_index = (cycle + j) % cycle_limit;
+
+ pal[pal_index].red =
+ (uchar) PAnimData.entries[i].colors[col_index].red;
+
+ pal[pal_index].green =
+ (uchar) PAnimData.entries[i].colors[col_index].
+ green;
+
+ pal[pal_index].blue =
+ (uchar) PAnimData.entries[i].colors[col_index].
+ blue;
+ }
+
+ PAnimData.entries[i].cycle++;
+
+ if (PAnimData.entries[i].cycle == cycle_limit) {
+ PAnimData.entries[i].cycle = 0;
+ }
+ }
+
+ SYSGFX_SetPalette(back_buf, pal);
+
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_PALANIM_EVENT;
+ event.op = EVENT_CYCLESTEP;
+ event.time = vectortime + PALANIM_CYCLETIME;
+
+ EVENT_Queue(&event);
+
+ return R_SUCCESS;
+
+}
+
+int PALANIM_Free(void)
+{
+
+ uint i;
+
+ if (!PAnimData.loaded) {
+ return R_FAILURE;
+ }
+
+ for (i = 0; i < PAnimData.entry_count; i++) {
+#if 0
+ R_printf(R_STDOUT,
+ "PALANIM_Free(): Entry %d: Freeing colors.\n", i);
+#endif
+ free(PAnimData.entries[i].colors);
+#if 0
+ R_printf(R_STDOUT,
+ "PALANIM_Free(): Entry %d: Freeing indices.\n", i);
+#endif
+ free(PAnimData.entries[i].pal_index);
+
+ }
+
+ R_printf(R_STDOUT, "PALANIM_Free(): Freeing entries.\n", i);
+
+ free(PAnimData.entries);
+
+ PAnimData.loaded = 0;
+
+ return R_SUCCESS;
+}
+
+} // End of namespace Saga
diff --git a/saga/palanim.h b/saga/palanim.h
new file mode 100644
index 0000000000..ededaf2449
--- /dev/null
+++ b/saga/palanim.h
@@ -0,0 +1,63 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Palette animation module header file
+
+ Notes:
+*/
+
+#ifndef SAGA_PALANIM_H
+#define SAGA_PALANIM_H
+
+#include "reinherit.h"
+
+namespace Saga {
+
+#define PALANIM_CYCLETIME 100
+
+typedef struct PALANIM_ENTRY_tag {
+
+ uint pal_count;
+ uint color_count;
+ uint cycle;
+
+ uchar *pal_index;
+ R_COLOR *colors;
+
+} PALANIM_ENTRY;
+
+typedef struct PALANIM_DATA_tag {
+
+ int loaded;
+ uint entry_count;
+
+ PALANIM_ENTRY *entries;
+
+} PALANIM_DATA;
+
+} // End of namespace Saga
+
+#endif
+
diff --git a/saga/palanim_mod.h b/saga/palanim_mod.h
new file mode 100644
index 0000000000..516af1374c
--- /dev/null
+++ b/saga/palanim_mod.h
@@ -0,0 +1,46 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Palette animation module public header file
+
+ Notes:
+*/
+
+#ifndef SAGA_PALANIM_MOD_H__
+#define SAGA_PALANIM_MOD_H__
+
+namespace Saga {
+
+int PALANIM_Load(const uchar *, size_t);
+
+int PALANIM_CycleStart(void);
+
+int PALANIM_CycleStep(int vectortime);
+
+int PALANIM_Free(void);
+
+} // End of namespace Saga
+
+#endif /* SAGA_PALANIM_MOD_H__ */
diff --git a/saga/reinherit.h b/saga/reinherit.h
new file mode 100644
index 0000000000..567340b232
--- /dev/null
+++ b/saga/reinherit.h
@@ -0,0 +1,333 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Main Header File
+
+ Notes:
+*/
+
+#ifndef SAGA_REINHERIT_H_
+#define SAGA_REINHERIT_H_
+
+#include "stdafx.h"
+
+#include "base/engine.h"
+
+/*
+ * Architecture conditionals
+\*--------------------------------------------------------------------------*/
+#include "x86_32.h"
+
+/*
+ * Implementation conditionals
+\*--------------------------------------------------------------------------*/
+#define R_ENV_LINUX
+#include "sys_interface.h"
+
+namespace Saga {
+
+#define R_MAXPATH 512
+
+/* For debug message processing */
+#define R_DEBUG_NONE 0
+#define R_DEBUG_INFO 1
+#define R_DEBUG_VERBOSE 2
+#define R_DEBUG_PARANOID 3
+
+#define R_MEMFAIL_MSG "Memory allocation error."
+
+/*
+ * Define opaque types
+\*--------------------------------------------------------------------------*/
+
+/* r_rscfile */
+typedef struct R_RSCFILE_CONTEXT_tag R_RSCFILE_CONTEXT;
+
+/* r_script */
+typedef struct R_SEMAPHORE_tag R_SEMAPHORE;
+
+/*
+ * Define common data types
+\*--------------------------------------------------------------------------*/
+
+#ifndef HAVE_UCHAR
+typedef unsigned char uchar;
+#endif
+#ifndef HAVE_ULONG
+typedef unsigned long ulong;
+#endif
+#ifndef HAVE_UINT
+typedef unsigned int uint;
+#endif
+
+typedef struct R_POINT_tag {
+
+ int x;
+ int y;
+
+} R_POINT;
+
+typedef struct R_RECT_tag {
+
+ int x1;
+ int y1;
+ int x2;
+ int y2;
+
+} R_RECT;
+
+#define R_MAKERECT( rect, x1, y1, x2, y2 ) \
+ ( rect.x1 = x1, rect.y1 = y1, rect.x2 = x2, rect.y2 = y2, &rect )
+
+typedef struct R_COLOR_tag {
+
+ int red;
+ int green;
+ int blue;
+ int alpha;
+
+} R_COLOR;
+
+typedef struct R_SURFACE_tag {
+
+ uchar *buf;
+ int buf_w;
+ int buf_h;
+ int buf_pitch;
+
+ int bpp;
+
+ R_RECT clip_rect;
+
+ void *impl_src;
+
+} R_SURFACE;
+
+typedef struct R_SOUNDBUFFER_tag {
+
+ uchar *res_data;
+ size_t res_len;
+
+ long s_freq;
+ int s_samplebits;
+ int s_stereo;
+ int s_signed;
+
+ uchar *s_buf;
+ size_t s_buf_len;
+
+} R_SOUNDBUFFER;
+
+#define R_RGB_RED 0x00FF0000UL
+#define R_RGB_GREEN 0x0000FF00UL
+#define R_RGB_BLUE 0x000000FFUL
+
+typedef struct SAGA_COLOR_tag {
+
+ R_UINT8 r;
+ R_UINT8 g;
+ R_UINT8 b;
+
+} SAGA_COLOR;
+
+#define SAGA_COLOR_LEN 3
+
+typedef struct PALENTRY_TAG {
+
+ R_UINT8 red;
+ R_UINT8 green;
+ R_UINT8 blue;
+
+} PALENTRY;
+
+enum R_ERRORCODE {
+
+ R_STOP = -3,
+ R_MEM = -2,
+ R_FAILURE = -1,
+ R_SUCCESS = 0
+
+};
+
+
+/*
+ * r_cmdline.c
+\*--------------------------------------------------------------------------*/
+typedef struct R_EXECINFO_tag {
+
+ int start_scene;
+ int no_verify;
+ int no_sound;
+ int no_music;
+ int windowed;
+ char *game_dir;
+
+} R_EXECINFO;
+
+int R_ReadCommandLine(int argc, char **argv, R_EXECINFO * execinfo);
+
+/*
+ * r_main.c
+\*--------------------------------------------------------------------------*/
+int main(int argc, char *argv[]);
+
+void R_Shutdown(int param);
+
+/*
+ * r_misc.c
+\*--------------------------------------------------------------------------*/
+int Granulate(int value, int granularity);
+
+/*
+ * r_transitions.c
+\*--------------------------------------------------------------------------*/
+int TRANSITION_Dissolve(uchar * dst_img,
+ int dst_w,
+ int dst_h,
+ int dst_p, const uchar * src_img, int src_p, int flags, double percent);
+
+/*--------------------------------------------------------------------------*\
+ * System specific routines
+\*--------------------------------------------------------------------------*/
+
+/*
+ * System : IO
+\*--------------------------------------------------------------------------*/
+
+int SYSIO_Init(void);
+int SYSIO_Shutdown(void);
+
+/*
+ * System : Filesystem
+\*--------------------------------------------------------------------------*/
+
+int SYSFS_GetFileLen(FILE * file_p, ulong * len);
+int SYSFS_GetFQFN(const char *f_dir,
+ const char *f_name, char *buf, size_t buf_len);
+
+/*
+ * System : Sound
+\*--------------------------------------------------------------------------*/
+int SYSSOUND_Init(int enabled);
+int SYSSOUND_Shutdown(void);
+
+int SYSSOUND_Play(int sound_rn, int channel);
+int SYSSOUND_Pause(int channel);
+int SYSSOUND_Resume(int channel);
+int SYSSOUND_Stop(int channel);
+
+int SYSSOUND_PlayVoice(R_SOUNDBUFFER *);
+int SYSSOUND_PauseVoice(void);
+int SYSSOUND_ResumeVoice(void);
+int SYSSOUND_StopVoice(void);
+
+/*
+ * System : Music
+\*--------------------------------------------------------------------------*/
+enum SYSMUSIC_FLAGS {
+
+ R_MUSIC_LOOP = 0x01
+};
+
+int SYSMUSIC_Init(int enabled);
+int SYSMUSIC_Shutdown(void);
+
+int SYSMUSIC_Play(ulong music_rn, uint flags);
+int SYSMUSIC_Pause(void);
+int SYSMUSIC_Resume(void);
+int SYSMUSIC_Stop(void);
+
+/*
+ * System : Graphics
+\*--------------------------------------------------------------------------*/
+#define R_PAL_ENTRIES 256
+
+typedef struct R_SYSGFX_INIT_tag {
+
+ int backbuf_w;
+ int backbuf_h;
+ int backbuf_bpp;
+
+ int screen_w;
+ int screen_h;
+ int screen_bpp;
+
+ int fullscreen;
+
+} R_SYSGFX_INIT;
+
+int SYSGFX_Init(R_SYSGFX_INIT *);
+
+R_SURFACE *SYSGFX_GetScreenSurface(void);
+R_SURFACE *SYSGFX_GetBackBuffer(void);
+
+int SYSGFX_LockSurface(R_SURFACE * surface);
+int SYSGFX_UnlockSurface(R_SURFACE * surface);
+
+R_SURFACE *SYSGFX_CreateSurface(int w, int h, int bpp);
+R_SURFACE *SYSGFX_FormatToDisplay(R_SURFACE * surface);
+int SYSGFX_DestroySurface(R_SURFACE * surface);
+
+int SYSGFX_GetWhite(void);
+int SYSGFX_GetBlack(void);
+int SYSGFX_MatchColor(unsigned long colormask);
+int SYSGFX_SetPalette(R_SURFACE * surface, PALENTRY * pal);
+int SYSGFX_GetCurrentPal(PALENTRY * src_pal);
+
+int SYSGFX_PalToBlack(R_SURFACE * surface, PALENTRY * src_pal, double percent);
+
+int SYSGFX_BlackToPal(R_SURFACE * surface, PALENTRY * src_pal, double percent);
+
+/*
+ * System : Timer
+\*--------------------------------------------------------------------------*/
+typedef struct R_SYSTIMER_tag R_SYSTIMER;
+
+typedef void (*R_SYSTIMER_CALLBACK) (unsigned long, void *);
+
+int SYSTIMER_InitMSCounter(void);
+unsigned long SYSTIMER_ReadMSCounter(void);
+
+int SYSTIMER_ResetMSCounter(void);
+int SYSTIMER_Sleep(uint msec);
+int SYSTIMER_CreateTimer(R_SYSTIMER **,
+ unsigned long, void *, R_SYSTIMER_CALLBACK);
+int SYSTIMER_DestroyTimer(R_SYSTIMER *);
+
+/*
+ * System : Input
+\*--------------------------------------------------------------------------*/
+int SYSINPUT_Init(void);
+int SYSINPUT_ProcessInput(void);
+int SYSINPUT_GetMousePos(int *mouse_x, int *mouse_y);
+int SYSINPUT_HideMouse(void);
+int SYSINPUT_ShowMouse(void);
+
+/*** sys_signal.c ***/
+int ITESYS_CheckSignal(void);
+
+} // End of namespace Saga
+
+#endif /* SAGA_REINHERIT_H_ */
diff --git a/saga/render.cpp b/saga/render.cpp
new file mode 100644
index 0000000000..4797659721
--- /dev/null
+++ b/saga/render.cpp
@@ -0,0 +1,588 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Main rendering loop
+
+ Notes:
+*/
+
+#include "reinherit.h"
+
+#include "yslib.h"
+
+#include <SDL.h>
+
+/*
+ * Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "actor_mod.h"
+#include "console_mod.h"
+#include "cvar_mod.h"
+#include "font_mod.h"
+#include "game_mod.h"
+#include "gfx_mod.h"
+#include "interface_mod.h"
+#include "scene_mod.h"
+#include "sprite_mod.h"
+#include "text_mod.h"
+
+#include "actionmap_mod.h"
+#include "objectmap_mod.h"
+
+/*
+ * Begin module
+\*--------------------------------------------------------------------------*/
+#include "render_mod.h"
+#include "render.h"
+
+namespace Saga {
+
+static R_RENDER_MODULE RenderModule;
+
+const char *test_txt = "The quick brown fox jumped over the lazy dog. "
+ "She sells sea shells down by the sea shore.";
+
+int RENDER_Register(void)
+{
+
+ /* Register "r_fullscreen" cfg cvar
+ * \*----------------------------------------- */
+ RenderModule.r_fullscreen = R_FULLSCREEN_DEFAULT;
+
+ if (CVAR_Register_I(&RenderModule.r_fullscreen,
+ "r_fullscreen", NULL, R_CVAR_CFG, 0, 1) != R_SUCCESS) {
+
+ return R_FAILURE;
+ }
+
+ /* Register "r_doubleres" cfg cvar
+ * \*----------------------------------------- */
+ RenderModule.r_doubleres = R_DOUBLERES_DEFAULT;
+
+ if (CVAR_Register_I(&RenderModule.r_doubleres,
+ "r_doubleres", NULL, R_CVAR_CFG, 0, 1) != R_SUCCESS) {
+
+ return R_FAILURE;
+ }
+
+ /* Register "r_hicolor" cfg cvar
+ * \*----------------------------------------- */
+ RenderModule.r_hicolor = R_HICOLOR_DEFAULT;
+
+ if (CVAR_Register_I(&RenderModule.r_hicolor,
+ "r_hicolor", NULL, R_CVAR_CFG, 0, 1) != R_SUCCESS) {
+
+ return R_FAILURE;
+ }
+
+ /* Register "r_softcursor" cfg cvar
+ * \*----------------------------------------- */
+ RenderModule.r_softcursor = R_SOFTCURSOR_DEFAULT;
+
+ if (CVAR_Register_I(&RenderModule.r_softcursor,
+ "r_softcursor", NULL, R_CVAR_CFG, 0, 1) != R_SUCCESS) {
+
+ return R_FAILURE;
+ }
+
+ return R_SUCCESS;
+}
+
+int RENDER_Init(void)
+{
+
+ R_GAME_DISPLAYINFO disp_info = { 0 };
+ R_SYSGFX_INIT gfx_init = { 0 };
+
+ int result;
+
+ int tmp_w, tmp_h, tmp_bytepp;
+
+ /* Initialize system graphics
+ * \*------------------------------------------------------------- */
+ GAME_GetDisplayInfo(&disp_info);
+
+ gfx_init.backbuf_bpp = 8; /* all games are 8 bpp so far */
+ gfx_init.backbuf_w = disp_info.logical_w;
+ gfx_init.backbuf_h = disp_info.logical_h;
+
+ if (RenderModule.r_hicolor) {
+ gfx_init.screen_bpp = 16;
+ } else {
+ gfx_init.screen_bpp = 8;
+ }
+
+ gfx_init.screen_w = disp_info.logical_w;
+ gfx_init.screen_h = disp_info.logical_h;
+
+ /* Don't try to double a game exceeding the resolution limit
+ * (640x480 would get doubled to 1280 x 960!) */
+ if (disp_info.logical_w > R_DOUBLE_RESLIMIT) {
+ RenderModule.r_doubleres = 0;
+ }
+
+ if (RenderModule.r_doubleres) {
+
+ gfx_init.screen_w *= 2;
+ gfx_init.screen_h *= 2;
+ }
+
+ gfx_init.fullscreen = RenderModule.r_fullscreen;
+
+ if (SYSGFX_Init(&gfx_init) != R_SUCCESS) {
+
+ return R_FAILURE;
+ }
+
+ /* Initialize FPS timer callback
+ * \*------------------------------------------------------------- */
+ result = SYSTIMER_CreateTimer(&RenderModule.r_fps_timer,
+ 1000, NULL, RENDER_FpsTimer);
+ if (result != R_SUCCESS) {
+ return R_FAILURE;
+ }
+
+ /* Create background buffer
+ * \*------------------------------------------------------------- */
+ RenderModule.r_bg_buf_w = disp_info.logical_w;
+ RenderModule.r_bg_buf_h = disp_info.logical_h;
+
+ RenderModule.r_bg_buf = (uchar *)calloc(disp_info.logical_w,
+ disp_info.logical_h);
+
+ if (RenderModule.r_bg_buf == NULL) {
+ return R_MEM;
+ }
+
+ /* Allocate temp buffer for animation decoding,
+ * graphics scalers (2xSaI), etc.
+ \*-------------------------------------------------------------*/
+ tmp_w = disp_info.logical_w;
+ tmp_h = disp_info.logical_h + 4; /* BG unbanking requres extra rows */
+ tmp_bytepp = 1;
+
+ if (RenderModule.r_doubleres) {
+ tmp_w *= 2;
+ tmp_h *= 2;
+ }
+
+ if (RenderModule.r_hicolor) {
+ tmp_bytepp = 2;
+ }
+
+ RenderModule.r_tmp_buf = (uchar *)calloc(1, tmp_w * tmp_h * tmp_bytepp);
+ if (RenderModule.r_tmp_buf == NULL) {
+
+ free(RenderModule.r_bg_buf);
+ return R_MEM;
+ }
+
+ RenderModule.r_tmp_buf_w = tmp_w;
+ RenderModule.r_tmp_buf_h = tmp_h;
+
+ RenderModule.r_screen_surface = SYSGFX_GetScreenSurface();
+ RenderModule.r_backbuf_surface = SYSGFX_GetBackBuffer();
+
+ /* Initialize cursor state
+ * \*------------------------------------------------------------- */
+ if (RenderModule.r_softcursor) {
+ SYSINPUT_HideMouse();
+ }
+
+ RenderModule.initialized = 1;
+
+ return R_SUCCESS;
+}
+
+int RENDER_DrawScene(void)
+{
+
+ R_SURFACE *screen_surface;
+ R_SURFACE *backbuf_surface;
+ R_SURFACE *display_surface;
+
+ R_GAME_DISPLAYINFO disp_info = { 0 };
+ R_SCENE_INFO scene_info;
+ SCENE_BGINFO bg_info;
+
+ R_POINT bg_pt;
+
+ char txt_buf[20];
+ int fps_width;
+
+ R_POINT mouse_pt;
+ int mouse_x, mouse_y;
+
+ int surface_converted = 0;
+
+ if (!RenderModule.initialized) {
+ return R_FAILURE;
+ }
+
+ RenderModule.r_framecount++;
+
+ screen_surface = RenderModule.r_screen_surface;
+ backbuf_surface = RenderModule.r_backbuf_surface;
+
+ /* Get mouse coordinates
+ * \*------------------------------------------------------------- */
+ SYSINPUT_GetMousePos(&mouse_x, &mouse_y);
+
+ mouse_pt.x = mouse_x;
+ mouse_pt.y = mouse_y;
+
+ if (RenderModule.r_doubleres) {
+ mouse_pt.x /= 2;
+ mouse_pt.y /= 2;
+ }
+
+ SCENE_GetBGInfo(&bg_info);
+ GAME_GetDisplayInfo(&disp_info);
+ bg_pt.x = 0;
+ bg_pt.y = 0;
+
+ /* Display scene background
+ * \*--------------------------------------------------------- */
+ SCENE_Draw(backbuf_surface);
+
+ /* Display scene maps, if applicable
+ * \*--------------------------------------------------------- */
+ if (RENDER_GetFlags() & RF_OBJECTMAP_TEST) {
+
+ OBJECTMAP_Draw(backbuf_surface,
+ &mouse_pt, SYSGFX_GetWhite(), SYSGFX_GetBlack());
+
+ ACTIONMAP_Draw(backbuf_surface, SYSGFX_MatchColor(R_RGB_RED));
+ }
+
+ /* Draw queued actors
+ * \*--------------------------------------------------------- */
+ ACTOR_DrawList();
+
+ /* Draw queued text strings
+ * \*--------------------------------------------------------- */
+ SCENE_GetInfo(&scene_info);
+
+ TEXT_DrawList(scene_info.text_list, backbuf_surface);
+
+ /* Handle user input
+ * \*--------------------------------------------------------- */
+ SYSINPUT_ProcessInput();
+
+ /* Display rendering information
+ * \*--------------------------------------------------------- */
+ if (RenderModule.r_flags & RF_SHOW_FPS) {
+
+ sprintf(txt_buf, "%d", RenderModule.r_fps);
+
+ fps_width = FONT_GetStringWidth(SMALL_FONT_ID,
+ txt_buf, 0, FONT_NORMAL);
+
+ FONT_Draw(SMALL_FONT_ID,
+ backbuf_surface,
+ txt_buf,
+ 0,
+ backbuf_surface->buf_w - fps_width, 2,
+ SYSGFX_GetWhite(), SYSGFX_GetBlack(), FONT_OUTLINE);
+
+ switch (RenderModule.r_mode) {
+
+ case RM_SCANLINES:
+ FONT_Draw(SMALL_FONT_ID,
+ backbuf_surface,
+ "Scanlines",
+ 0,
+ 2, 2,
+ SYSGFX_GetWhite(),
+ SYSGFX_GetBlack(), FONT_OUTLINE);
+ break;
+
+ case RM_2XSAI:
+ FONT_Draw(SMALL_FONT_ID,
+ backbuf_surface,
+ "2xSaI",
+ 0,
+ 2, 2,
+ SYSGFX_GetWhite(),
+ SYSGFX_GetBlack(), FONT_OUTLINE);
+ break;
+
+ case RM_SUPER2XSAI:
+ FONT_Draw(SMALL_FONT_ID,
+ backbuf_surface,
+ "Super2xSaI",
+ 0,
+ 2, 2,
+ SYSGFX_GetWhite(),
+ SYSGFX_GetBlack(), FONT_OUTLINE);
+ break;
+
+ case RM_SUPEREAGLE:
+ FONT_Draw(SMALL_FONT_ID,
+ backbuf_surface,
+ "SuperEagle",
+ 0,
+ 2, 2,
+ SYSGFX_GetWhite(),
+ SYSGFX_GetBlack(), FONT_OUTLINE);
+ break;
+ }
+
+ }
+
+ /* Display "paused game" message, if applicable
+ * \*--------------------------------------------------------- */
+ if (RenderModule.r_flags & RF_RENDERPAUSE) {
+
+ int msg_len = strlen(R_PAUSEGAME_MSG);
+ int msg_w = FONT_GetStringWidth(BIG_FONT_ID,
+ R_PAUSEGAME_MSG,
+ msg_len,
+ FONT_OUTLINE);
+
+ FONT_Draw(BIG_FONT_ID,
+ backbuf_surface,
+ R_PAUSEGAME_MSG,
+ msg_len,
+ (backbuf_surface->buf_w - msg_w) / 2, 90,
+ SYSGFX_GetWhite(), SYSGFX_GetBlack(), FONT_OUTLINE);
+ }
+
+ /* Update user interface
+ * \*--------------------------------------------------------- */
+
+ INTERFACE_Update(&mouse_pt, UPDATE_MOUSEMOVE);
+
+ if (RenderModule.r_softcursor) {
+ GFX_DrawCursor(backbuf_surface, &mouse_pt);
+ }
+
+ /* Display text formatting test, if applicable
+ * \*--------------------------------------------------------- */
+ if (RenderModule.r_flags & RF_TEXT_TEST) {
+
+ TEXT_Draw(MEDIUM_FONT_ID,
+ backbuf_surface,
+ test_txt,
+ mouse_pt.x, mouse_pt.y,
+ SYSGFX_GetWhite(),
+ SYSGFX_GetBlack(), FONT_OUTLINE | FONT_CENTERED);
+ }
+
+ /* Display palette test, if applicable
+ * \*--------------------------------------------------------- */
+ if (RenderModule.r_flags & RF_PALETTE_TEST) {
+
+ GFX_DrawPalette(backbuf_surface);
+ }
+
+ /* Draw console
+ * \*--------------------------------------------------------- */
+ CON_Draw(backbuf_surface);
+
+ /* Display the current frame
+ * \*--------------------------------------------------------- */
+
+ if (RenderModule.r_hicolor) {
+
+ display_surface = SYSGFX_FormatToDisplay(backbuf_surface);
+
+ if (display_surface == NULL) {
+ R_printf(R_STDERR,
+ "Error: Back buffer conversion failed!\n");
+
+ return R_FAILURE;
+ }
+
+ surface_converted = 1;
+ } else {
+
+ display_surface = backbuf_surface;
+ }
+
+ SYSGFX_LockSurface(screen_surface);
+ SYSGFX_LockSurface(display_surface);
+
+ switch (RenderModule.r_mode) {
+
+ case RM_SCANLINES:
+
+ break;
+
+ default:
+
+ if (RenderModule.r_doubleres) {
+
+ GFX_Scale2x(screen_surface, display_surface);
+ } else {
+
+ GFX_SimpleBlit(screen_surface, display_surface);
+ }
+
+ break;
+ }
+
+ SYSGFX_UnlockSurface(display_surface);
+ SYSGFX_UnlockSurface(screen_surface);
+
+ if (surface_converted) {
+
+ SYSGFX_DestroySurface(display_surface);
+ }
+
+ // FIXME
+ SDL_UpdateRect((SDL_Surface *)screen_surface->impl_src, 0, 0, 0, 0);
+
+ return R_SUCCESS;
+}
+
+unsigned int RENDER_GetFrameCount(void)
+{
+
+ return RenderModule.r_framecount;
+}
+
+unsigned int RENDER_ResetFrameCount(void)
+{
+ unsigned int framecount = RenderModule.r_framecount;
+
+ RenderModule.r_framecount = 0;
+
+ return framecount;
+}
+
+void RENDER_FpsTimer(unsigned long interval, void *param)
+{
+ YS_IGNORE_PARAM(interval);
+ YS_IGNORE_PARAM(param);
+
+ RenderModule.r_fps = RenderModule.r_framecount;
+ RenderModule.r_framecount = 0;
+
+ return;
+}
+
+void RENDER_ConvertMousePt(R_POINT * mouse_pt)
+{
+ assert(mouse_pt != NULL);
+
+ if (RenderModule.r_doubleres) {
+
+ mouse_pt->x /= 2;
+ mouse_pt->y /= 2;
+ }
+
+ return;
+}
+
+unsigned int RENDER_GetFlags(void)
+{
+ return RenderModule.r_flags;
+}
+
+void RENDER_SetFlag(unsigned int flag)
+{
+
+ RenderModule.r_flags |= flag;
+
+ return;
+}
+
+void RENDER_ToggleFlag(unsigned int flag)
+{
+
+ RenderModule.r_flags ^= flag;
+
+ return;
+}
+
+int RENDER_SetMode(int mode)
+{
+
+ switch (mode) {
+
+ case RM_SCANLINES:
+
+ if (!RenderModule.r_doubleres) {
+
+ return R_FAILURE;
+ }
+
+ break;
+
+ case RM_2XSAI:
+
+ if (!RenderModule.r_doubleres || !RenderModule.r_hicolor) {
+
+ return R_FAILURE;
+ }
+
+ break;
+
+ case RM_SUPER2XSAI:
+
+ if (!RenderModule.r_doubleres || !RenderModule.r_hicolor) {
+
+ return R_FAILURE;
+ }
+
+ break;
+
+ case RM_SUPEREAGLE:
+
+ if (!RenderModule.r_doubleres || !RenderModule.r_hicolor) {
+
+ return R_FAILURE;
+ }
+
+ break;
+
+ default:
+ break;
+
+ }
+
+ RenderModule.r_mode = mode;
+
+ return R_SUCCESS;
+}
+
+int RENDER_GetBufferInfo(R_BUFFER_INFO * r_bufinfo)
+{
+
+ assert(r_bufinfo != NULL);
+
+ r_bufinfo->r_bg_buf = RenderModule.r_bg_buf;
+ r_bufinfo->r_bg_buf_w = RenderModule.r_bg_buf_w;
+ r_bufinfo->r_bg_buf_h = RenderModule.r_bg_buf_h;
+
+ r_bufinfo->r_tmp_buf = RenderModule.r_tmp_buf;
+ r_bufinfo->r_tmp_buf_w = RenderModule.r_tmp_buf_w;
+ r_bufinfo->r_tmp_buf_h = RenderModule.r_tmp_buf_h;
+
+ return R_SUCCESS;
+}
+
+} // End of namespace Saga
diff --git a/saga/render.h b/saga/render.h
new file mode 100644
index 0000000000..f7db7b0fe1
--- /dev/null
+++ b/saga/render.h
@@ -0,0 +1,84 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Main rendering loop - private header
+
+ Notes:
+*/
+
+#ifndef SAGA_RENDER_H_
+#define SAGA_RENDER_H_
+
+namespace Saga {
+
+/* Render module CVAR defaults */
+#define R_FULLSCREEN_DEFAULT 0
+#define R_DOUBLERES_DEFAULT 1
+#define R_HICOLOR_DEFAULT 1
+#define R_SOFTCURSOR_DEFAULT 1
+
+#define R_DOUBLE_RESLIMIT 320
+
+#define R_PAUSEGAME_MSG "PAWS GAME"
+
+typedef struct R_RENDER_MODULE_tag {
+
+ int initialized;
+
+ /* Init cvars */
+ int r_fullscreen;
+ int r_doubleres;
+ int r_hicolor;
+ int r_softcursor;
+
+ /* Module data */
+ R_SURFACE *r_screen_surface;
+ R_SURFACE *r_display_surface;
+ R_SURFACE *r_backbuf_surface;
+
+ uchar *r_bg_buf;
+ int r_bg_buf_w;
+ int r_bg_buf_h;
+
+ uchar *r_tmp_buf;
+ int r_tmp_buf_w;
+ int r_tmp_buf_h;
+
+ R_SYSTIMER *r_fps_timer;
+ R_SPRITELIST *r_test_sprite;
+
+ unsigned int r_fps;
+ unsigned int r_framecount;
+
+ unsigned int r_flags;
+ int r_mode;
+
+} R_RENDER_MODULE;
+
+void RENDER_FpsTimer(unsigned long interval, void *param);
+
+} // End of namespace Saga
+
+#endif /* SAGA_RENDER_H_ */
diff --git a/saga/render_mod.h b/saga/render_mod.h
new file mode 100644
index 0000000000..b3c353f3b5
--- /dev/null
+++ b/saga/render_mod.h
@@ -0,0 +1,92 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Main rendering loop - public header
+
+ Notes:
+*/
+
+#ifndef SAGA_RENDER_MOD_H__
+#define SAGA_RENDER_MOD_H__
+
+namespace Saga {
+
+enum RENDER_FLAGS {
+
+ RF_SHOW_FPS = 0x01,
+ RF_PALETTE_TEST = 0x02,
+ RF_TEXT_TEST = 0x04,
+ RF_OBJECTMAP_TEST = 0x08,
+ RF_RENDERPAUSE = 0x10,
+ RF_GAMEPAUSE = 0x20
+};
+
+enum RENDER_MODES {
+ RM_NORMAL,
+ RM_SCANLINES,
+ RM_SCANLINES50,
+ RM_2XSAI,
+ RM_SUPER2XSAI,
+ RM_SUPEREAGLE,
+ RM_BILINEAR
+};
+
+typedef struct R_BUFFER_INFO_tag {
+
+ uchar *r_bg_buf;
+ int r_bg_buf_w;
+ int r_bg_buf_h;
+
+ uchar *r_tmp_buf;
+ int r_tmp_buf_w;
+ int r_tmp_buf_h;
+
+} R_BUFFER_INFO;
+
+int RENDER_Register(void);
+
+int RENDER_Init(void);
+
+int RENDER_DrawScene(void);
+
+void RENDER_ConvertMousePt(R_POINT *);
+
+unsigned int RENDER_GetFlags(void);
+
+void RENDER_SetFlag(unsigned int);
+
+void RENDER_ToggleFlag(unsigned int);
+
+int RENDER_SetMode(int);
+
+unsigned int RENDER_GetFrameCount(void);
+
+unsigned int RENDER_ResetFrameCount(void);
+
+int RENDER_GetBufferInfo(R_BUFFER_INFO *);
+
+} // End of namespace Saga
+
+#endif /* SAGA_RENDER_MOD_H__ */
diff --git a/saga/resfile.cpp b/saga/resfile.cpp
deleted file mode 100644
index 5b3a345644..0000000000
--- a/saga/resfile.cpp
+++ /dev/null
@@ -1,162 +0,0 @@
-/* ScummVM - Scumm Interpreter
- * Copyright (C) 2003 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$
- *
- */
-
-#include "common/file.h"
-
-#include "saga.h"
-
-#include "resfile.h"
-#include "binread.h"
-
-namespace Saga {
-
-ResourceFile::ResourceFile() {
- _resTblOffset = 0;
- _resTblCt = 0;
- _resTblLoaded = false;
- _resTbl = NULL;
-}
-
-ResourceFile::~ResourceFile() {
- close();
-}
-
-bool ResourceFile::open(const char *filename, const char *directory) {
- byte * temp_tbl;
- uint32 tbl_len;
-
- if (!File::open(filename, directory)) {
- return false;
- }
-
- /* Seek to end of file to read resource table 'trailer' */
- _file_len = size();
-
- seek(_file_len - RSC_TABLEINFO_SIZE, SEEK_SET);
-
- _resTblOffset = readSint32LE();
- _resTblCt = readSint32LE();
-
- /* Check for sane values */
- if (_resTblOffset != _file_len - RSC_TABLEINFO_SIZE -
- (RSC_TABLEENTRY_SIZE * _resTblCt)) {
- return false;
- }
-
- /* Load resource table */
- _resTbl = new Resource[_resTblCt];
-
- seek(_resTblOffset, SEEK_SET);
-
- tbl_len = _resTblCt * RSC_TABLEENTRY_SIZE;
- temp_tbl = new byte[tbl_len];
-
- if (read(temp_tbl, tbl_len) != tbl_len) {
- delete [] _resTbl;
- delete [] temp_tbl;
- return false;
- }
-
- BinReader bread(temp_tbl, tbl_len);
-
- for (int i = 0; i < _resTblCt; i++) {
- _resTbl[i].res_offset = bread.readSint32LE();
- _resTbl[i].res_len = bread.readSint32LE();
- }
-
- delete[] temp_tbl;
-
- _resTblLoaded = true;
-
- return true;
-}
-
-
-void ResourceFile::close() {
- if ( _resTblLoaded) {
- delete [] _resTbl;
- _resTblLoaded = false;
- _resTbl = NULL;
- }
-
- _resTblOffset = 0;
- _resTblCt = 0;
-
- if (File::isOpen()) {
- File::close();
- }
-}
-
-int32 ResourceFile::getResourceCt() {
- return (_resTblLoaded) ? _resTblCt : -1;
-}
-
-int32 ResourceFile::getResourceOffset(int32 rn) {
- if (!R_PBOUNDS(rn, _resTblCt))
- return -1;
-
- return _resTbl[rn].res_offset;
-}
-
-int32 ResourceFile::getResourceLen(int32 rn) {
- if (!R_PBOUNDS(rn, _resTblCt))
- return -1;
-
- return _resTbl[rn].res_len;
-}
-
-bool ResourceFile::loadResource(int32 rn, byte **res, int32 *res_len) {
- byte *new_res;
- uint32 new_res_len;
-
- assert(res != NULL && res_len != NULL);
- *res = NULL;
- *res_len = 0;
-
- if (!R_PBOUNDS(rn, _resTblCt)) {
- return false;
- }
-
- new_res_len = _resTbl[rn].res_len;
- new_res = new byte[new_res_len];
-
- if (!new_res) {
- return false;
- }
-
- seek(_resTbl[rn].res_offset, SEEK_SET);
-
- if (read(new_res, new_res_len) != new_res_len) {
- delete[] new_res;
- return false;
- }
-
- *res = new_res;
- *res_len = new_res_len;
-
- return true;
-}
-
-void ResourceFile::freeResource(byte *res) {
- delete[] res;
-}
-
-} // End of namespace Saga
diff --git a/saga/resfile.h b/saga/resfile.h
deleted file mode 100644
index 40ad8f7898..0000000000
--- a/saga/resfile.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/* ScummVM - Scumm Interpreter
- * Copyright (C) 2003 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_RESFILE_H
-#define SAGA_RESFILE_H
-
-/* The 'RSC' resource file format used by SAGA is quite simple.
- * At the end of the resource file is an 8 byte structure. The first
- * 32 bit value specifies the offset of the resource table, the
- * second specifies the number of entries in the resource table.
- * Each entry in the resource table is itself 32 bytes, the first
- * 32 bit value of which specifies the offset of the resource, the
- * second specifies the length of the resource.
- */
-
-#include "common/file.h"
-
-namespace Saga {
-
-class ResourceFile : public File {
-
-public:
-
- struct Resource {
- int32 res_offset;
- int32 res_len;
- };
-
-private:
-
- long _file_len;
-
-protected:
-
- enum ResourceConstants {
- RSC_TABLEINFO_SIZE = 8,
- RSC_TABLEENTRY_SIZE = 8
- };
-
- const char *_resDirectory;
-
- int32 _resTblOffset;
- int32 _resTblCt;
-
- bool _resTblLoaded;
- Resource *_resTbl;
-
-public:
-
- ResourceFile();
- virtual ~ResourceFile();
-
- bool open(const char *filename, const char *directory);
- void close();
-
- inline int16 readSint16LE() {
- return readUint16LE();
- }
-
- inline int32 readSint32LE() {
- return readUint32LE();
- }
-
- inline int16 readSint16BE() {
- return readUint16BE();
- }
-
- inline int32 readSint32BE() {
- return readUint32BE();
- }
-
- int32 getResourceCt();
- int32 getResourceOffset( int32 rn );
- int32 getResourceLen( int32 rn );
-
- bool loadResource( int32 rn, byte **res, int32 *res_len );
- void freeResource( byte *res );
-
-};
-
-} // End of namespace Saga
-
-
-#endif
-
-
-
-
-
diff --git a/saga/resnames.h b/saga/resnames.h
deleted file mode 100644
index 596e1cefaf..0000000000
--- a/saga/resnames.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/* ScummVM - Scumm Interpreter
- * Copyright (C) 2003 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_RESNAMES_H
-#define SAGA_RESNAMES_H
-
-namespace Saga {
-
-/* Lookup tables
-\*-----------------------------------------------------------------*/
-#define ITE_SCENE_LUT 1806
-#define ITE_SCRIPT_LUT 216
-
-#define IHNM_SCENE_LUT 1272
-#define IHNM_SCRIPT_LUT 0
-
-/* SCENES */
-#define ITE_DEFAULT_SCENE 32
-
-/* FONTS */
-#define RN_MEDIUM_FONT 0
-#define RN_BIG_FONT 1
-#define RN_SMALL_FONT 2
-
-#define ITE_OVERLAY_PAL ((unsigned long)-1)
-#define IHNM_OVERLAY_PAL 1
-
-#define ITE_ACTOR_PERSONA_TBL ((unsigned long)-1)
-#define IHNM_ACTOR_PERSONA_TBL 80
-
-/* Interface resources
-\*-----------------------------------------------------------------*/
-#define ITE_COMMAND_PANEL 3
-#define ITE_COMMAND_BUTTONSPRITES 7
-
-#define ITE_DIALOGUE_PANEL 4
-#define ITE_DEFAULT_PORTRAITS 125
-
-#define ITE_SETUP_PANEL 5
-
-#define IHNM_COMMAND_PANEL 9
-#define IHNM_COMMAND_BUTTONSPRITES 12
-
-#define IHNM_DIALOGUE_PANEL 10
-
-/* No real "default" portraits for IHNM, but provide one for now */
-#define IHNM_DEFAULT_PORTRAITS 45
-
-/* ITE Scene resource numbers */
-#define ITE_INTRO_ANIM_SCENE 1538
-#define ITE_CAVE_SCENE_1 1542
-#define ITE_CAVE_SCENE_2 1545
-#define ITE_CAVE_SCENE_3 1548
-#define ITE_CAVE_SCENE_4 1551
-
-#define ITE_VALLEY_SCENE 1556
-#define ITE_TREEHOUSE_SCENE 1560
-#define ITE_FAIREPATH_SCENE 1564
-#define ITE_FAIRETENT_SCENE 1567
-
-#define ITE_INTRO_ANIM_STARTFRAME 1529
-
-/* ITE_VOICES */
-#define CAVE_VOICE_0 0
-#define CAVE_VOICE_1 1
-#define CAVE_VOICE_2 2
-#define CAVE_VOICE_3 3
-#define CAVE_VOICE_4 4
-#define CAVE_VOICE_5 5
-#define CAVE_VOICE_6 6
-#define CAVE_VOICE_7 7
-#define CAVE_VOICE_8 8
-#define CAVE_VOICE_9 9
-#define CAVE_VOICE_10 10
-#define CAVE_VOICE_11 11
-#define CAVE_VOICE_12 12
-#define CAVE_VOICE_13 13
-
-/* MUSIC */
-#define MUSIC_1 9
-#define MUSIC_2 10
-#define MUSIC_3 11
-#define MUSIC_4 12
-#define MUSIC_5 13
-#define MUSIC_6 14
-#define MUSIC_7 15
-#define MUSIC_8 16
-#define MUSIC_9 17
-#define MUSIC_10 18
-#define MUSIC_11 19
-#define MUSIC_12 20
-#define MUSIC_13 21
-#define MUSIC_14 22
-#define MUSIC_15 23
-#define MUSIC_16 24
-#define MUSIC_17 25
-#define MUSIC_18 26
-#define MUSIC_19 27
-#define MUSIC_20 28
-#define MUSIC_21 29
-#define MUSIC_22 30
-#define MUSIC_23 31
-#define MUSIC_24 32
-#define MUSIC_25 33
-#define MUSIC_26 34
-
-} // End of namespace Saga
-
-#endif
-
-
-
diff --git a/saga/rscfile.cpp b/saga/rscfile.cpp
new file mode 100644
index 0000000000..b96a694b32
--- /dev/null
+++ b/saga/rscfile.cpp
@@ -0,0 +1,310 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ RSC Resource file management module
+
+ Notes:
+*/
+
+#include "reinherit.h"
+
+#include "yslib.h"
+
+/*
+ * Uses the following modules:
+\*--------------------------------------------------------------------------*/
+
+/*
+ * Begin module
+\*--------------------------------------------------------------------------*/
+#include "rscfile_mod.h"
+#include "rscfile.h"
+
+namespace Saga {
+
+R_RSCFILE_CONTEXT *RSC_CreateContext(void)
+{
+ R_RSCFILE_CONTEXT empty_context = { 0 };
+ R_RSCFILE_CONTEXT *new_context;
+
+ new_context = (R_RSCFILE_CONTEXT *)malloc(sizeof *new_context);
+ if (new_context == NULL) {
+ return NULL;
+ }
+
+ *new_context = empty_context;
+
+ return new_context;
+}
+
+int RSC_OpenContext(R_RSCFILE_CONTEXT * rsc_context, const char *fspec)
+{
+ FILE *rsc_fp;
+ int result;
+
+ rsc_fp = fopen(fspec, "rb");
+ if (rsc_fp == NULL) {
+ return R_FAILURE;
+ }
+
+ if (rsc_context->rc_file_open) {
+ return R_FAILURE;
+ }
+
+ rsc_context->rc_file_fspec = fspec;
+ rsc_context->rc_file_p = rsc_fp;
+
+ result = ys_get_filesize(rsc_fp, &rsc_context->rc_file_size, NULL);
+ if (result != YS_E_SUCCESS) {
+ fclose(rsc_fp);
+ return R_FAILURE;
+ }
+
+ if (RSC_LoadRSC(rsc_context) != R_SUCCESS) {
+ return R_FAILURE;
+ }
+
+ rsc_context->rc_file_open = 1;
+ rsc_context->rc_file_loaded = 1;
+
+ return R_SUCCESS;
+}
+
+int RSC_CloseContext(R_RSCFILE_CONTEXT * rsc_context)
+{
+ if (rsc_context->rc_file_open) {
+ fclose(rsc_context->rc_file_p);
+ }
+
+ rsc_context->rc_file_open = 0;
+
+ RSC_FreeRSC(rsc_context);
+
+ rsc_context->rc_file_loaded = 0;
+
+ return R_SUCCESS;
+}
+
+int RSC_DestroyContext(R_RSCFILE_CONTEXT * rsc_context)
+{
+ RSC_CloseContext(rsc_context);
+
+ if (rsc_context->rc_file_loaded) {
+ free(rsc_context->rc_res_table);
+ }
+
+ free(rsc_context);
+
+ return R_SUCCESS;
+}
+
+int RSC_LoadRSC(R_RSCFILE_CONTEXT * rsc)
+{
+ ulong res_tbl_ct;
+ ulong res_tbl_offset;
+
+ uchar tblinfo_buf[RSC_TABLEINFO_SIZE];
+ uchar *tbl_buf;
+ size_t tbl_len;
+ ulong i;
+
+ R_RSCFILE_RESOURCE *rsc_restbl;
+
+ const uchar *read_p;
+
+ read_p = tblinfo_buf;
+
+ if (rsc->rc_file_size < RSC_MIN_FILESIZE) {
+ return R_FAILURE;
+ }
+
+ /* Read resource table info from the rear end of file
+ * \*------------------------------------------------------------- */
+ fseek(rsc->rc_file_p, (long)(rsc->rc_file_size - 8), SEEK_SET);
+
+ if (fread(tblinfo_buf,
+ 1, RSC_TABLEINFO_SIZE, rsc->rc_file_p) != RSC_TABLEINFO_SIZE) {
+
+ return R_FAILURE;
+ }
+
+ res_tbl_offset = ys_read_u32_le(read_p, &read_p);
+ res_tbl_ct = ys_read_u32_le(read_p, NULL);
+
+ /* Check for sane table offset
+ * \*------------------------------------------------------------- */
+ if (res_tbl_offset != rsc->rc_file_size - RSC_TABLEINFO_SIZE -
+ RSC_TABLEENTRY_SIZE * res_tbl_ct) {
+
+ return R_FAILURE;
+ }
+
+ /* Load resource table
+ * \*------------------------------------------------------------- */
+ tbl_len = RSC_TABLEENTRY_SIZE * res_tbl_ct;
+
+ tbl_buf = (uchar *)malloc(tbl_len);
+ if (tbl_buf == NULL) {
+ return R_FAILURE;
+ }
+
+ fseek(rsc->rc_file_p, (long)res_tbl_offset, SEEK_SET);
+
+ if (fread(tbl_buf, 1, tbl_len, rsc->rc_file_p) != tbl_len) {
+ free(tbl_buf);
+ return R_FAILURE;
+ }
+
+ rsc_restbl = (R_RSCFILE_RESOURCE *)malloc(res_tbl_ct * sizeof *rsc_restbl);
+ if (rsc_restbl == NULL) {
+ free(tbl_buf);
+ return R_FAILURE;
+ }
+
+ read_p = tbl_buf;
+
+ for (i = 0; i < res_tbl_ct; i++) {
+
+ rsc_restbl[i].res_offset = ys_read_u32_le(read_p, &read_p);
+ rsc_restbl[i].res_size = ys_read_u32_le(read_p, &read_p);
+
+ 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);
+ return R_FAILURE;
+ }
+ }
+
+ rsc->rc_res_table = rsc_restbl;
+ rsc->rc_res_ct = res_tbl_ct;
+
+ free(tbl_buf);
+
+ return R_SUCCESS;
+}
+
+int RSC_FreeRSC(R_RSCFILE_CONTEXT * rsc)
+{
+ if (!rsc->rc_file_loaded) {
+ return R_FAILURE;
+ }
+
+ free(rsc->rc_res_table);
+
+ return R_SUCCESS;
+}
+
+ulong RSC_GetResourceCount(R_RSCFILE_CONTEXT * rsc)
+{
+ return (rsc == NULL) ? 0 : rsc->rc_res_ct;
+}
+
+int
+RSC_GetResourceSize(R_RSCFILE_CONTEXT * rsc, ulong res_num, ulong * res_size)
+{
+ if ((rsc == NULL) || (res_size == NULL)) {
+ return R_FAILURE;
+ }
+
+ if (res_num > (rsc->rc_res_ct - 1)) {
+ return R_FAILURE;
+ }
+
+ *res_size = rsc->rc_res_table[res_num].res_size;
+
+ return R_SUCCESS;
+}
+
+int
+RSC_GetResourceOffset(R_RSCFILE_CONTEXT * rsc,
+ ulong res_num, ulong * res_offset)
+{
+ if ((rsc == NULL) || (res_offset == NULL)) {
+ return R_FAILURE;
+ }
+
+ if (res_num > (rsc->rc_res_ct - 1)) {
+ return R_FAILURE;
+ }
+
+ *res_offset = rsc->rc_res_table[res_num].res_offset;
+
+ return R_SUCCESS;
+}
+
+int
+RSC_LoadResource(R_RSCFILE_CONTEXT * rsc,
+ ulong res_num, uchar ** res_p, size_t * res_size_p)
+{
+ ulong res_offset;
+ size_t res_size;
+ uchar *res_buf;
+
+ if ((rsc == NULL) || (res_p == NULL)) {
+ return R_FAILURE;
+ }
+
+ if (res_num > (rsc->rc_res_ct - 1)) {
+ return R_FAILURE;
+ }
+
+ res_offset = rsc->rc_res_table[res_num].res_offset;
+ res_size = rsc->rc_res_table[res_num].res_size;
+
+ if (fseek(rsc->rc_file_p, (long)res_offset, SEEK_SET) != 0) {
+ return R_FAILURE;
+ }
+
+ res_buf = (uchar *)malloc(res_size);
+ if (res_buf == NULL) {
+ return R_MEM;
+ }
+
+ if (fread(res_buf, 1, res_size, rsc->rc_file_p) != res_size) {
+ free(res_buf);
+ return R_FAILURE;
+ }
+
+ *res_p = res_buf;
+
+ if (res_size_p != NULL) {
+ *res_size_p = res_size;
+ }
+
+ return R_SUCCESS;
+}
+
+int RSC_FreeResource(uchar * resource_ptr)
+{
+
+ free(resource_ptr);
+
+ return R_SUCCESS;
+}
+
+} // End of namespace Saga
diff --git a/saga/rscfile.h b/saga/rscfile.h
new file mode 100644
index 0000000000..6a9e7e423f
--- /dev/null
+++ b/saga/rscfile.h
@@ -0,0 +1,70 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ RSC Resource file management header file
+
+ Notes:
+*/
+
+#ifndef SAGA_RSCFILE_H__
+#define SAGA_RSCFILE_H__
+
+namespace Saga {
+
+#define RSC_TABLEINFO_SIZE 8
+#define RSC_TABLEENTRY_SIZE 8
+
+#define RSC_MIN_FILESIZE (RSC_TABLEINFO_SIZE + RSC_TABLEENTRY_SIZE + 1)
+
+typedef struct R_RSCFILE_RESOURCE_tag {
+
+ int res_type;
+
+ size_t res_offset;
+ size_t res_size;
+
+} R_RSCFILE_RESOURCE;
+
+struct R_RSCFILE_CONTEXT_tag {
+
+ const char *rc_file_fspec;
+ FILE *rc_file_p;
+ int rc_file_open;
+ unsigned long rc_file_size;
+
+ int rc_file_loaded;
+ R_RSCFILE_RESOURCE *rc_res_table;
+ size_t rc_res_ct;
+
+};
+
+int RSC_LoadRSC(R_RSCFILE_CONTEXT * rsc_context);
+
+int RSC_FreeRSC(R_RSCFILE_CONTEXT * rsc);
+
+} // End of namespace Saga
+
+#endif /* SAGA_RSCFILE_H__ */
diff --git a/saga/rscfile_mod.h b/saga/rscfile_mod.h
new file mode 100644
index 0000000000..c337ff41e0
--- /dev/null
+++ b/saga/rscfile_mod.h
@@ -0,0 +1,59 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ RSC Resource file management module public header file
+
+ Notes:
+*/
+
+#ifndef SAGA_RSCFILE_MOD_H__
+#define SAGA_RSCFILE_MOD_H__
+
+#include "resnames.h"
+
+namespace Saga {
+
+R_RSCFILE_CONTEXT *RSC_CreateContext(void);
+
+int RSC_DestroyContext(R_RSCFILE_CONTEXT *);
+
+int RSC_OpenContext(R_RSCFILE_CONTEXT *, const char *);
+
+int RSC_CloseContext(R_RSCFILE_CONTEXT *);
+
+ulong RSC_GetResourceCount(R_RSCFILE_CONTEXT *);
+
+int RSC_GetResourceSize(R_RSCFILE_CONTEXT *, ulong, ulong *);
+
+int RSC_GetResourceOffset(R_RSCFILE_CONTEXT *, ulong, ulong *);
+
+int RSC_LoadResource(R_RSCFILE_CONTEXT *, ulong, uchar **, size_t *);
+
+int RSC_FreeResource(uchar *);
+
+} // End of namespace Saga
+
+#endif /* SAGA_RSCFILE_MOD_H__ */
diff --git a/saga/saga.cpp b/saga/saga.cpp
index 9d3e11296b..729249a63b 100644
--- a/saga/saga.cpp
+++ b/saga/saga.cpp
@@ -1,24 +1,3 @@
-/* ScummVM - Scumm Interpreter
- * Copyright (C) 2003 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$
- *
- */
-
#include "stdafx.h"
#include "base/gameDetector.h"
@@ -31,7 +10,26 @@
#include "saga.h"
-#include "gamedesc.h"
+#include "reinherit.h"
+
+#include "rscfile_mod.h"
+#include "render_mod.h"
+#include "actor_mod.h"
+#include "animation_mod.h"
+#include "console_mod.h"
+#include "cvar_mod.h"
+#include "events_mod.h"
+#include "actionmap_mod.h"
+#include "font_mod.h"
+#include "game_mod.h"
+#include "interface_mod.h"
+#include "isomap_mod.h"
+#include "script_mod.h"
+#include "scene_mod.h"
+#include "sndres_mod.h"
+#include "sprite_mod.h"
+#include "text_mod.h"
+#include "objectmap_mod.h"
struct SAGAGameSettings {
const char *name;
@@ -96,11 +94,24 @@ REGISTER_PLUGIN("SAGA Engine", Engine_SAGA_gameList, Engine_SAGA_create, Engine_
namespace Saga {
+#define R_MAX_TIME_DELTA 100
+
+typedef struct R_MAIN_DATA_tag {
+
+ int sound_enabled;
+ int music_enabled;
+
+} R_MAIN_DATA;
+
+static void CF_quitfunc(int argc, char *argv[]);
+static void CF_testfunc(int argc, char *argv[]);
+
+static R_MAIN_DATA MainData;
+
SagaEngine::SagaEngine(GameDetector *detector, OSystem *syst)
: Engine(syst) {
- setGameDirectory(getGameDataPath());
- openGame();
+ GAME_setGameDirectory(getGameDataPath());
// Setup mixer
if (!_mixer->isReady()) {
@@ -110,7 +121,7 @@ SagaEngine::SagaEngine(GameDetector *detector, OSystem *syst)
_mixer->setVolume(ConfMan.getInt("sfx_volume") * ConfMan.getInt("master_volume") / 255);
// Initialize backend
- syst->initSize(320, 240);
+ //syst->initSize(320, 240);
}
SagaEngine::~SagaEngine() {
@@ -122,13 +133,200 @@ void SagaEngine::errorString(const char *buf1, char *buf2) {
}
void SagaEngine::go() {
+ int msec = 0;
+
+ /* Register engine modules
+ * \*------------------------------------------------------------- */
+ CON_Register(); /* Register console cvars first */
+
+ RENDER_Register();
+ GAME_Register();
+
+ ANIM_Register();
+ ACTIONMAP_Register();
+ OBJECTMAP_Register();
+ SCRIPT_Register();
+ ACTOR_Register();
+ SCENE_Register();
+
+ MainData.sound_enabled = 1;
+
+ CVAR_RegisterFunc(CF_testfunc,
+ "testfunc", "foo [ optional foo ]", R_CVAR_NONE, 0, -1);
+
+ CVAR_Register_I(&MainData.sound_enabled,
+ "sound", NULL, R_CVAR_CFG, 0, 1);
+
+ CVAR_Register_I(&MainData.music_enabled,
+ "music", NULL, R_CVAR_CFG, 0, 1);
+
+ CVAR_RegisterFunc(CF_quitfunc, "quit", NULL, R_CVAR_NONE, 0, 0);
+
+ /* Process config file
+ * \*------------------------------------------------------------- */
+ // FIXME
+ /*
+ if (CFG_Read(NULL) != R_SUCCESS) {
+ R_printf(R_STDERR, "Couldn't read configuration file.\n");
+ }
+ */
+
+ /* Process command line
+ * \*------------------------------------------------------------- */
+
+ /* Detect game and open resource files
+ * \*------------------------------------------------------------- */
+ if (GAME_Init() != R_SUCCESS) {
+
+ R_printf(R_STDERR,
+ "Couldn't start the game: %s\n", GAME_GetErrS());
+
+ return;
+ }
+
+ /* Initialize engine modules
+ * \*------------------------------------------------------------- */
+ SND_Init();
+ EVENT_Init();
+ FONT_Init();
+ SPRITE_Init();
+ ANIM_Init();
+ ACTIONMAP_Init();
+ OBJECTMAP_Init();
+ ISOMAP_Init();
+ SCRIPT_Init();
+ INTERFACE_Init(); /* requires script module */
+ ACTOR_Init();
+
+ if (SCENE_Init() != R_SUCCESS) {
+
+ R_printf(R_STDERR, "Couldn't initialize scene module.\n");
+ return;
+ }
+
+ /* System initialization
+ * \*------------------------------------------------------------- */
+
+ if (SYSIO_Init() != R_SUCCESS) {
+
+ return;
+ }
+
+ /* Must initialize system timer module first */
+ if (SYSTIMER_InitMSCounter() != R_SUCCESS) {
+
+ return;
+ }
+
+ /* On some platforms, graphics initialization also initializes sound
+ * ( Win32 DirectX )... Music must be initialized before sound for
+ * native midi support */
+ SYSMUSIC_Init(MainData.music_enabled);
+ if (!MainData.music_enabled) {
+ R_printf(R_STDOUT, "Music disabled.\n");
+ }
+ /* Initialize graphics */
+ if (RENDER_Init() != R_SUCCESS) {
+ return;
+ }
+
+ /* Initialize system specific sound */
+ SYSSOUND_Init(MainData.sound_enabled);
+ if (!MainData.sound_enabled) {
+ R_printf(R_STDOUT, "Sound disabled.\n");
+ }
+
+ SYSINPUT_Init();
+
+ SYSTIMER_ResetMSCounter();
+
+ /* Begin Main Engine Loop
+ * \*------------------------------------------------------------- */
+
+ SCENE_Start();
+
+ for (;;) {
+
+#ifdef R_USE_CUSTOM_WININIT
+
+ if (ITESYS_CheckSignal()) {
+ break;
+ }
+#endif
+
+ if (RENDER_GetFlags() & RF_RENDERPAUSE) {
+ /* Freeze time while paused */
+ SYSTIMER_ResetMSCounter();
+ } else {
+ msec = SYSTIMER_ReadMSCounter();
+
+ if (msec > R_MAX_TIME_DELTA) {
+ msec = R_MAX_TIME_DELTA;
+ }
+
+ ACTOR_Direct(msec);
+ EVENT_HandleEvents(msec);
+ STHREAD_ExecThreads(msec);
+ }
+
+ /* Per frame processing
+ * \*--------------------------------------------------------- */
+ RENDER_DrawScene();
+
+ SYSTIMER_Sleep(0);
+ } /* end main game engine loop */
+
+ R_Shutdown(0);
+
+ return;
}
void SagaEngine::shutdown() {
-
_system->quit();
}
+void R_Shutdown(int param) {
+ SCENE_Shutdown();
+ ACTOR_Shutdown();
+ SCRIPT_Shutdown();
+ ANIM_Shutdown();
+ SPRITE_Shutdown();
+ OBJECTMAP_Shutdown();
+
+ FONT_Shutdown();
+
+ CON_Shutdown();
+ CVAR_Shutdown();
+ EVENT_Shutdown();
+
+ /* Shutdown system modules */
+ SYSMUSIC_Shutdown();
+ SYSSOUND_Shutdown();
+
+ SYSIO_Shutdown();
+
+ /* exit(param); */
+}
+
+static void CF_quitfunc(int argc, char *argv[])
+{
+ R_Shutdown(0);
+ exit(0);
+}
+
+static void CF_testfunc(int argc, char *argv[])
+{
+ int i;
+
+ CON_Print("Test function invoked: Got %d arguments.", argc);
+
+ for (i = 0; i < argc; i++) {
+ CON_Print("Arg %d: %s", i, argv[i]);
+ }
+
+ return;
+}
+
} // End of namespace Saga
diff --git a/saga/saga.h b/saga/saga.h
index edaa24c979..a97294b2e5 100644
--- a/saga/saga.h
+++ b/saga/saga.h
@@ -1,5 +1,7 @@
/* ScummVM - Scumm Interpreter
- * Copyright (C) 2003 The ScummVM project
+ * 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
@@ -27,7 +29,7 @@
#include "base/gameDetector.h"
#include "common/util.h"
-#include "gamedesc.h"
+//#include "gamedesc.h"
namespace Saga {
@@ -39,18 +41,16 @@ enum SAGAGameId {
GID_IHNM
};
-class SagaEngine : public Engine {
-
- void errorString( const char *buf_input, char *buf_output);
+class SagaEngine:public Engine {
+ void errorString(const char *buf_input, char *buf_output);
-protected:
+ protected:
void go();
void shutdown();
-public:
-
- SagaEngine(GameDetector *detector, OSystem *syst);
- virtual ~SagaEngine();
+ public:
+ SagaEngine(GameDetector * detector, OSystem * syst);
+ virtual ~ SagaEngine();
};
diff --git a/saga/scene.cpp b/saga/scene.cpp
new file mode 100644
index 0000000000..3fc9bda076
--- /dev/null
+++ b/saga/scene.cpp
@@ -0,0 +1,1159 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Scene management module
+
+ Notes:
+*/
+
+#include "reinherit.h"
+
+#include "yslib.h"
+
+/*
+ * Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "game_mod.h"
+#include "animation_mod.h"
+#include "console_mod.h"
+#include "cvar_mod.h"
+#include "events_mod.h"
+#include "actionmap_mod.h"
+#include "gfx_mod.h"
+#include "image_mod.h"
+#include "isomap_mod.h"
+#include "script_mod.h"
+#include "objectmap_mod.h"
+#include "palanim_mod.h"
+#include "render_mod.h"
+#include "rscfile_mod.h"
+#include "text_mod.h"
+
+/*
+ * Begin module component
+\*--------------------------------------------------------------------------*/
+#include "scene_mod.h"
+#include "scene.h"
+
+namespace Saga {
+
+static R_SCENE_MODULE SceneModule;
+
+int SCENE_Register(void)
+{
+
+ CVAR_Register_I(&SceneModule.scene_number,
+ "scene", NULL, R_CVAR_READONLY, 0, 0);
+
+ CVAR_RegisterFunc(CF_scenechange,
+ "scene_change", "<Scene number>", R_CVAR_NONE, 1, 1);
+
+ CVAR_RegisterFunc(CF_sceneinfo, "scene_info", NULL, R_CVAR_NONE, 0, 0);
+
+ return R_SUCCESS;
+}
+
+int SCENE_Init(void)
+{
+
+ R_GAME_SCENEDESC gs_desc;
+
+ uchar *scene_lut_p;
+ size_t scene_lut_len;
+
+ const uchar *read_p;
+
+ int result;
+ int i;
+
+ /* Load game-specific scene data
+ * \*------------------------------------------------------------ */
+ GAME_GetSceneInfo(&gs_desc);
+
+ /* Load scene module resource context
+ * \*------------------------------------------------------------ */
+ result = GAME_GetFileContext(&SceneModule.scene_ctxt,
+ R_GAME_RESOURCEFILE, 0);
+ if (result != R_SUCCESS) {
+
+ R_printf(R_STDERR, "Couldn't load scene resource context.\n");
+
+ return R_FAILURE;
+ }
+
+ /* Initialize scene queue
+ * \*------------------------------------------------------------ */
+ SceneModule.scene_queue = ys_dll_create();
+ if (SceneModule.scene_queue == NULL) {
+
+ return R_FAILURE;
+ }
+
+ /* Load scene lookup table
+ * \*------------------------------------------------------------ */
+ R_printf(R_STDOUT,
+ "SCENE_Init(): Loading scene LUT from resource %d.\n",
+ gs_desc.scene_lut_rn);
+
+ result = RSC_LoadResource(SceneModule.scene_ctxt,
+ gs_desc.scene_lut_rn, &scene_lut_p, &scene_lut_len);
+ if (result != R_SUCCESS) {
+
+ R_printf(R_STDERR, "Error: couldn't load scene LUT.\n");
+
+ return R_FAILURE;
+ }
+
+ SceneModule.scene_count = scene_lut_len / 2;
+ SceneModule.scene_max = SceneModule.scene_count - 1;
+
+ SceneModule.scene_lut = (int *)malloc(SceneModule.scene_max *
+ sizeof *SceneModule.scene_lut);
+ if (SceneModule.scene_lut == NULL) {
+ R_printf(R_STDERR,
+ "SCENE_Init(): Memory allocation failed.\n");
+ return R_MEM;
+ }
+
+ read_p = scene_lut_p;
+
+ for (i = 0; i < SceneModule.scene_max; i++) {
+
+ SceneModule.scene_lut[i] = ys_read_u16_le(read_p, &read_p);
+ }
+
+ free(scene_lut_p);
+
+ if (gs_desc.first_scene != 0) {
+ SceneModule.first_scene = gs_desc.first_scene;
+ }
+
+ R_printf(R_STDOUT,
+ "SCENE_Init(): First scene set to %d.\n", SceneModule.first_scene);
+
+ R_printf(R_STDOUT,
+ "SCENE_Init(): LUT has %d entries.\n", SceneModule.scene_max);
+
+ /* Create scene module text list
+ * \*------------------------------------------------------------ */
+ SceneModule.text_list = TEXT_CreateList();
+
+ if (SceneModule.text_list == NULL) {
+ R_printf(R_STDERR,
+ "Error: Couldn't create scene text list.\n");
+
+ return R_FAILURE;
+ }
+
+ SceneModule.init = 1;
+
+ return R_SUCCESS;
+}
+
+int SCENE_Shutdown(void)
+{
+
+ if (SceneModule.init) {
+ SCENE_End();
+ free(SceneModule.scene_lut);
+ }
+
+ return R_SUCCESS;
+}
+
+int SCENE_Queue(R_SCENE_QUEUE * scene_queue)
+{
+ assert(SceneModule.init);
+ assert(scene_queue != NULL);
+
+ ys_dll_add_tail(SceneModule.scene_queue,
+ scene_queue, sizeof *scene_queue);
+
+ return R_SUCCESS;
+}
+
+int SCENE_ClearQueue(void)
+{
+ assert(SceneModule.init);
+
+ ys_dll_delete_all(SceneModule.scene_queue);
+
+ return R_SUCCESS;
+}
+
+int SCENE_Start(void)
+{
+
+ YS_DL_NODE *node;
+ R_SCENE_QUEUE *scene_qdat;
+
+ assert(SceneModule.init);
+
+ if (SceneModule.scene_loaded) {
+ R_printf(R_STDERR,
+ "Error: Can't start game...scene already loaded!\n");
+
+ return R_FAILURE;
+ }
+
+ if (SceneModule.in_game) {
+ R_printf(R_STDERR,
+ "Error: Can't start game...game already started!\n");
+
+ return R_FAILURE;
+ }
+
+ switch (GAME_GetGameType()) {
+
+ case R_GAMETYPE_ITE:
+ ITE_StartProc();
+ break;
+
+ case R_GAMETYPE_IHNM:
+ IHNM_StartProc();
+ break;
+
+ default:
+ R_printf(R_STDERR,
+ "Error: Can't start game... gametype not supported.\n");
+ break;
+ }
+
+ /* Load the head node in scene queue
+ * \*------------------------------------------------------------- */
+ node = ys_dll_head(SceneModule.scene_queue);
+ if (node == NULL) {
+ return R_SUCCESS;
+ }
+
+ scene_qdat = (R_SCENE_QUEUE *)ys_dll_get_data(node);
+ assert(scene_qdat != NULL);
+
+ SCENE_Load(scene_qdat->scene_n,
+ scene_qdat->load_flag,
+ scene_qdat->scene_proc, scene_qdat->scene_desc);
+
+ return R_SUCCESS;
+}
+
+int SCENE_Next(void)
+{
+
+ YS_DL_NODE *node;
+ R_SCENE_QUEUE *scene_qdat;
+
+ assert(SceneModule.init);
+
+ if (!SceneModule.scene_loaded) {
+ R_printf(R_STDERR,
+ "Error: Can't advance scene...no scene loaded!\n");
+
+ return R_FAILURE;
+ }
+
+ if (SceneModule.in_game) {
+ R_printf(R_STDERR,
+ "Error: Can't advance scene...game already started!\n");
+
+ return R_FAILURE;
+ }
+
+ SCENE_End();
+
+ /* Delete the current head node in scene queue
+ * \*------------------------------------------------------------- */
+ node = ys_dll_head(SceneModule.scene_queue);
+ if (node == NULL) {
+ return R_SUCCESS;
+ }
+
+ ys_dll_delete(node);
+
+ /* Load the head node in scene queue
+ * \*------------------------------------------------------------- */
+ node = ys_dll_head(SceneModule.scene_queue);
+ if (node == NULL) {
+ return R_SUCCESS;
+ }
+
+ scene_qdat = (R_SCENE_QUEUE *)ys_dll_get_data(node);
+ assert(scene_qdat != NULL);
+
+ SCENE_Load(scene_qdat->scene_n,
+ scene_qdat->load_flag,
+ scene_qdat->scene_proc, scene_qdat->scene_desc);
+
+ return R_SUCCESS;
+}
+
+int SCENE_Skip(void)
+{
+
+ YS_DL_NODE *node;
+ YS_DL_NODE *prev_node;
+ YS_DL_NODE *skip_node = NULL;
+
+ R_SCENE_QUEUE *scene_qdat = NULL;
+ R_SCENE_QUEUE *skip_qdat = NULL;
+
+ assert(SceneModule.init);
+
+ if (!SceneModule.scene_loaded) {
+
+ R_printf(R_STDERR,
+ "Error: Can't skip scene...no scene loaded.\n");
+
+ return R_FAILURE;
+ }
+
+ if (SceneModule.in_game) {
+
+ R_printf(R_STDERR,
+ "Error: Can't skip scene...game already started.\n");
+
+ return R_FAILURE;
+ }
+
+ /* Walk down scene queue and try to find a skip target
+ * \*------------------------------------------------------------- */
+ node = ys_dll_head(SceneModule.scene_queue);
+ if (node == NULL) {
+
+ R_printf(R_STDERR,
+ "Error: Can't skip scene...no scenes in queue.\n");
+
+ return R_FAILURE;
+ }
+
+ for (node = ys_dll_next(node); node != NULL; node = ys_dll_next(node)) {
+
+ scene_qdat = (R_SCENE_QUEUE *)ys_dll_get_data(node);
+ assert(scene_qdat != NULL);
+
+ if (scene_qdat->scene_skiptarget) {
+
+ skip_node = node;
+ skip_qdat = scene_qdat;
+ break;
+ }
+ }
+
+ /* 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);
+ }
+
+ SCENE_End();
+
+ SCENE_Load(skip_qdat->scene_n,
+ skip_qdat->load_flag,
+ skip_qdat->scene_proc, skip_qdat->scene_desc);
+ }
+
+ /* Search for a scene to skip to */
+
+ return R_SUCCESS;
+}
+
+int SCENE_Change(int scene_num)
+{
+
+ assert(SceneModule.init);
+
+ if (!SceneModule.scene_loaded) {
+ R_printf(R_STDERR,
+ "Error: Can't change scene. No scene currently loaded. "
+ "Game in invalid state.\n");
+
+ return R_FAILURE;
+ }
+
+ if ((scene_num < 0) || (scene_num > SceneModule.scene_max)) {
+
+ R_printf(R_STDERR,
+ "Error: Can't change scene. Invalid scene number.\n");
+
+ return R_FAILURE;
+ }
+
+ if (SceneModule.scene_lut[scene_num] == 0) {
+
+ R_printf(R_STDERR,
+ "Error: Can't change scene; invalid scene descriptor "
+ "resource number (0)\n");
+
+ return R_FAILURE;
+ }
+
+ SCENE_End();
+ SCENE_Load(scene_num, BY_SCENE, DefaultSceneProc, NULL);
+
+ return R_SUCCESS;
+}
+
+int SCENE_GetMode(void)
+{
+ assert(SceneModule.init);
+
+ return SceneModule.scene_mode;
+}
+
+int SCENE_GetZInfo(SCENE_ZINFO * zinfo)
+{
+
+ assert(SceneModule.init);
+
+ zinfo->begin_slope = SceneModule.desc.begin_slope;
+ zinfo->end_slope = SceneModule.desc.end_slope;
+
+ return R_SUCCESS;
+}
+
+int SCENE_GetBGInfo(SCENE_BGINFO * bginfo)
+{
+ R_GAME_DISPLAYINFO di;
+ int x, y;
+
+ assert(SceneModule.init);
+
+ bginfo->bg_buf = SceneModule.bg.buf;
+ bginfo->bg_buflen = SceneModule.bg.buf_len;
+ bginfo->bg_w = SceneModule.bg.w;
+ bginfo->bg_h = SceneModule.bg.h;
+ bginfo->bg_p = SceneModule.bg.p;
+
+ GAME_GetDisplayInfo(&di);
+ x = 0;
+ y = 0;
+
+ if (SceneModule.bg.w < di.logical_w) {
+ x = (di.logical_w - SceneModule.bg.w) / 2;
+ }
+
+ if (SceneModule.bg.h < di.scene_h) {
+ y = (di.scene_h - SceneModule.bg.h) / 2;
+ }
+
+ bginfo->bg_x = x;
+ bginfo->bg_y = y;
+
+ return R_SUCCESS;
+}
+
+int SCENE_GetBGPal(PALENTRY ** pal)
+{
+ assert(SceneModule.init);
+
+ *pal = SceneModule.bg.pal;
+
+ return R_SUCCESS;
+}
+
+int SCENE_GetBGMaskInfo(int *w, int *h, uchar ** buf, size_t * buf_len)
+{
+
+ assert(SceneModule.init);
+
+ if (!SceneModule.bg_mask.loaded) {
+ return R_FAILURE;
+ }
+
+ *w = SceneModule.bg_mask.w;
+ *h = SceneModule.bg_mask.h;
+ *buf = SceneModule.bg_mask.buf;
+ *buf_len = SceneModule.bg_mask.buf_len;
+
+ return R_SUCCESS;
+}
+
+int SCENE_IsBGMaskPresent(void)
+{
+
+ assert(SceneModule.init);
+
+ return SceneModule.bg_mask.loaded;
+}
+
+int SCENE_GetInfo(R_SCENE_INFO * si)
+{
+ assert(SceneModule.init);
+ assert(si != NULL);
+
+ si->text_list = SceneModule.text_list;
+
+ return R_SUCCESS;
+}
+
+int
+SCENE_Load(int scene_num,
+ int load_flag, R_SCENE_PROC scene_proc, R_SCENE_DESC * scene_desc_param)
+{
+
+ R_SCENE_INFO scene_info;
+ ulong res_number = 0;
+ int result;
+ int i;
+
+ assert(SceneModule.init);
+
+ if (SceneModule.scene_loaded == 1) {
+
+ R_printf(R_STDERR, "Error, a scene is already loaded.\n");
+ return R_FAILURE;
+ }
+
+ SceneModule.anim_list = ys_dll_create();
+ SceneModule.scene_mode = 0;
+ SceneModule.load_desc = 1;
+
+ switch (load_flag) {
+
+ case BY_RESOURCE:
+ res_number = scene_num;
+ break;
+
+ case BY_SCENE:
+ assert((scene_num > 0) && (scene_num < SceneModule.scene_max));
+
+ res_number = SceneModule.scene_lut[scene_num];
+ SceneModule.scene_number = scene_num;
+ break;
+
+ case BY_DESC:
+
+ assert(scene_desc_param != NULL);
+ assert(scene_desc_param->res_list != NULL);
+
+ SceneModule.load_desc = 0;
+
+ SceneModule.desc = *scene_desc_param;
+ SceneModule.reslist = scene_desc_param->res_list;
+ SceneModule.reslist_entries = scene_desc_param->res_list_ct;
+ break;
+
+ default:
+ R_printf(R_STDERR, "Error: Invalid scene load flag.\n");
+ return R_FAILURE;
+ break;
+
+ }
+
+ /*
+ * Load scene descriptor and resource list resources
+ \*-------------------------------------------------------------*/
+ if (SceneModule.load_desc) {
+
+ SceneModule.scene_rn = res_number;
+ assert(SceneModule.scene_rn != 0);
+
+ R_printf(R_STDOUT, "Loading scene resource %d:\n", res_number);
+
+ if (LoadSceneDescriptor(res_number) != R_SUCCESS) {
+ R_printf(R_STDERR,
+ "Error reading scene descriptor.\n");
+
+ return R_FAILURE;
+ }
+
+ if (LoadSceneResourceList(SceneModule.desc.res_list_rn)
+ != R_SUCCESS) {
+
+ R_printf(R_STDERR,
+ "Error reading scene resource list.\n");
+
+ return R_FAILURE;
+ }
+ } else {
+
+ R_printf(R_STDOUT, "Loading memory scene resource.\n");
+ }
+
+ /*
+ * Load resources from scene resource list
+ \*-------------------------------------------------------------*/
+ for (i = 0; i < SceneModule.reslist_entries; i++) {
+
+ result = RSC_LoadResource(SceneModule.scene_ctxt,
+ SceneModule.reslist[i].res_number,
+ &SceneModule.reslist[i].res_data,
+ &SceneModule.reslist[i].res_data_len);
+ if (result != R_SUCCESS) {
+
+ R_printf(R_STDERR,
+ "Error: Allocation failure loading scene "
+ "resource list.\n");
+
+ return R_FAILURE;
+ }
+
+ }
+
+ /*
+ * Process resources from scene resource list
+ \*-------------------------------------------------------------*/
+ if (ProcessSceneResources() != R_SUCCESS) {
+
+ R_printf(R_STDERR, "Error loading scene resources.\n");
+
+ return R_FAILURE;
+ }
+
+ /* Load scene script data */
+ if (SceneModule.desc.script_num > 0) {
+
+ if (SCRIPT_Load(SceneModule.desc.script_num) != R_SUCCESS) {
+
+ R_printf(R_STDERR, "Error loading scene script.\n");
+ return R_FAILURE;
+ }
+ }
+
+ SceneModule.scene_loaded = 1;
+
+ if (scene_proc == NULL) {
+ SceneModule.scene_proc = DefaultSceneProc;
+ } else {
+ SceneModule.scene_proc = scene_proc;
+ }
+
+ SCENE_GetInfo(&scene_info);
+
+ SceneModule.scene_proc(SCENE_BEGIN, &scene_info);
+
+ return R_SUCCESS;
+}
+
+int LoadSceneDescriptor(ulong res_number)
+{
+
+ uchar *scene_desc_data;
+ size_t scene_desc_len;
+
+ const uchar *read_p;
+
+ int result;
+
+ result = RSC_LoadResource(SceneModule.scene_ctxt,
+ res_number, &scene_desc_data, &scene_desc_len);
+ if (result != R_SUCCESS) {
+ R_printf(R_STDERR, "Error: couldn't load scene descriptor.\n");
+
+ return R_FAILURE;
+ }
+
+ if (scene_desc_len != SAGA_SCENE_DESC_LEN) {
+ R_printf(R_STDERR,
+ "Error: scene descriptor length invalid.\n");
+
+ return R_FAILURE;
+ }
+
+ read_p = scene_desc_data;
+
+ SceneModule.desc.unknown0 = ys_read_u16_le(read_p, &read_p);
+ SceneModule.desc.res_list_rn = ys_read_u16_le(read_p, &read_p);
+ SceneModule.desc.end_slope = ys_read_u16_le(read_p, &read_p);
+ SceneModule.desc.begin_slope = ys_read_u16_le(read_p, &read_p);
+ SceneModule.desc.script_num = ys_read_u16_le(read_p, &read_p);
+ SceneModule.desc.scene_scriptnum = ys_read_u16_le(read_p, &read_p);
+ SceneModule.desc.start_scriptnum = ys_read_u16_le(read_p, &read_p);
+
+ SceneModule.desc.music_rn = ys_read_s16_le(read_p, &read_p);
+
+ RSC_FreeResource(scene_desc_data);
+
+ return R_SUCCESS;
+}
+
+int LoadSceneResourceList(ulong reslist_rn)
+{
+
+ uchar *resource_list;
+ size_t resource_list_len;
+
+ const uchar *read_p;
+
+ int result;
+ int i;
+
+ /*
+ * Load the scene resource table
+ \*-------------------------------------------------------------*/
+ result = RSC_LoadResource(SceneModule.scene_ctxt,
+ reslist_rn, &resource_list, &resource_list_len);
+ if (result != R_SUCCESS) {
+
+ R_printf(R_STDERR,
+ "Error: couldn't load scene resource list.\n");
+
+ return R_FAILURE;
+ }
+
+ read_p = resource_list;
+
+ /* Allocate memory for scene resource list
+ * \*----------------------------------------- */
+ SceneModule.reslist_entries =
+ resource_list_len / SAGA_RESLIST_ENTRY_LEN;
+
+ R_printf(R_STDOUT,
+ "Scene resource list contains %d entries.\n",
+ SceneModule.reslist_entries);
+
+ SceneModule.reslist =
+ (R_SCENE_RESLIST *)calloc(SceneModule.reslist_entries, sizeof *SceneModule.reslist);
+
+ if (SceneModule.reslist == NULL) {
+ R_printf(R_STDERR, "Error: Memory allocation failed.\n");
+
+ return R_MEM;
+ }
+
+ /* Load scene resource list from raw scene
+ * resource table
+ \*-----------------------------------------*/
+ R_printf(R_STDOUT, "Loading scene resource list...\n");
+
+ for (i = 0; i < SceneModule.reslist_entries; i++) {
+
+ SceneModule.reslist[i].res_number =
+ ys_read_u16_le(read_p, &read_p);
+ SceneModule.reslist[i].res_type =
+ ys_read_u16_le(read_p, &read_p);
+ }
+
+ RSC_FreeResource(resource_list);
+
+ return R_SUCCESS;
+}
+
+int ProcessSceneResources(void)
+{
+
+ const uchar *res_data;
+ size_t res_data_len;
+
+ const uchar *pal_p;
+
+ int i;
+
+ /*
+ * Process the scene resource list
+ \*-------------------------------------------------------------*/
+ for (i = 0; i < SceneModule.reslist_entries; i++) {
+
+ res_data = SceneModule.reslist[i].res_data;
+ res_data_len = SceneModule.reslist[i].res_data_len;
+
+ switch (SceneModule.reslist[i].res_type) {
+
+ /* Scene background resource */
+ case SAGA_BG_IMAGE:
+
+ if (SceneModule.bg.loaded) {
+
+ R_printf(R_STDERR,
+ "Error: Multiple background resources "
+ "encountered.\n");
+ return R_FAILURE;
+ }
+
+ R_printf(R_STDOUT, "Loading background resource.\n");
+
+ SceneModule.bg.res_buf =
+ SceneModule.reslist[i].res_data;
+ SceneModule.bg.res_len =
+ SceneModule.reslist[i].res_data_len;
+ SceneModule.bg.loaded = 1;
+
+ if (IMG_DecodeBGImage(SceneModule.bg.res_buf,
+ SceneModule.bg.res_len,
+ &SceneModule.bg.buf,
+ &SceneModule.bg.buf_len,
+ &SceneModule.bg.w,
+ &SceneModule.bg.h) != R_SUCCESS) {
+ R_printf(R_STDERR,
+ "Error loading background resource: %lu\n",
+ SceneModule.reslist[i].res_number);
+
+ return R_FAILURE;
+ }
+
+ pal_p = IMG_GetImagePal(SceneModule.bg.res_buf,
+ SceneModule.bg.res_len);
+
+ memcpy(SceneModule.bg.pal,
+ pal_p, sizeof SceneModule.bg.pal);
+
+ SceneModule.scene_mode = R_SCENE_MODE_NORMAL;
+
+ break;
+
+ /* Scene background mask resource */
+ case SAGA_BG_MASK:
+
+ if (SceneModule.bg_mask.loaded) {
+ R_printf(R_STDERR,
+ "Error: Duplicate background mask resource "
+ "encountered.\n");
+ }
+
+ R_printf(R_STDOUT,
+ "Loading BACKGROUND MASK resource.\n");
+
+ SceneModule.bg_mask.res_buf =
+ SceneModule.reslist[i].res_data;
+ SceneModule.bg_mask.res_len =
+ SceneModule.reslist[i].res_data_len;
+ SceneModule.bg_mask.loaded = 1;
+
+ IMG_DecodeBGImage(SceneModule.bg_mask.res_buf,
+ SceneModule.bg_mask.res_len,
+ &SceneModule.bg_mask.buf,
+ &SceneModule.bg_mask.buf_len,
+ &SceneModule.bg_mask.w, &SceneModule.bg_mask.h);
+ break;
+
+ case SAGA_OBJECT_NAME_LIST:
+
+ R_printf(R_STDOUT,
+ "Loading object name list resource...\n");
+
+ OBJECTMAP_LoadNames(SceneModule.reslist[i].res_data,
+ SceneModule.reslist[i].res_data_len);
+ break;
+
+ case SAGA_OBJECT_MAP:
+
+ R_printf(R_STDOUT, "Loading object map resource...\n");
+
+ if (OBJECTMAP_Load(res_data,
+ res_data_len) != R_SUCCESS) {
+
+ R_printf(R_STDERR,
+ "Error loading object map resource.\n");
+ return R_FAILURE;
+ }
+ break;
+
+ case SAGA_ACTION_MAP:
+
+ R_printf(R_STDOUT, "Loading exit map resource...\n");
+
+ if (ACTIONMAP_Load(res_data,
+ res_data_len) != R_SUCCESS) {
+ R_printf(R_STDERR,
+ "Error loading exit map resource.\n");
+ return R_FAILURE;
+ }
+ break;
+
+ case SAGA_ISO_TILESET:
+
+ if (SceneModule.scene_mode == R_SCENE_MODE_NORMAL) {
+ R_printf(R_STDERR,
+ "Isometric tileset incompatible with normal "
+ "scene mode.\n");
+ return R_FAILURE;
+ }
+
+ R_printf(R_STDOUT,
+ "Loading isometric tileset resource.\n");
+
+ if (ISOMAP_LoadTileset(res_data,
+ res_data_len) != R_SUCCESS) {
+ R_printf(R_STDERR,
+ "Error loading isometric tileset resource.\n");
+ return R_FAILURE;
+ }
+
+ SceneModule.scene_mode = R_SCENE_MODE_ISO;
+ break;
+
+ case SAGA_ISO_METAMAP:
+
+ if (SceneModule.scene_mode == R_SCENE_MODE_NORMAL) {
+ R_printf(R_STDERR,
+ "Isometric metamap incompatible with normal "
+ "scene mode.\n");
+ return R_FAILURE;
+ }
+
+ R_printf(R_STDOUT,
+ "Loading isometric metamap resource.\n");
+
+ if (ISOMAP_LoadMetamap(res_data,
+ res_data_len) != R_SUCCESS) {
+ R_printf(R_STDERR,
+ "Error loading isometric metamap resource.\n");
+ return R_FAILURE;
+ }
+
+ SceneModule.scene_mode = R_SCENE_MODE_ISO;
+ break;
+
+ case SAGA_ISO_METATILESET:
+ if (SceneModule.scene_mode == R_SCENE_MODE_NORMAL) {
+ R_printf(R_STDERR,
+ "Isometric metatileset incompatible with "
+ "normal scene mode.\n");
+ return R_FAILURE;
+ }
+
+ R_printf(R_STDOUT,
+ "Loading isometric metatileset resource.\n");
+
+ if (ISOMAP_LoadMetaTileset(res_data,
+ res_data_len) != R_SUCCESS) {
+ R_printf(R_STDERR,
+ "Error loading isometric tileset resource.\n");
+ return R_FAILURE;
+ }
+
+ SceneModule.scene_mode = R_SCENE_MODE_ISO;
+ break;
+
+ case SAGA_ANIM_1:
+ case SAGA_ANIM_2:
+ case SAGA_ANIM_3:
+ case SAGA_ANIM_4:
+ case SAGA_ANIM_5:
+ case SAGA_ANIM_6:
+ case SAGA_ANIM_7:
+ {
+ SCENE_ANIMINFO *new_animinfo;
+ uint new_anim_id;
+
+ R_printf(R_STDOUT,
+ "Loading animation resource...\n");
+
+ new_animinfo = (SCENE_ANIMINFO *)malloc(sizeof *new_animinfo);
+ if (new_animinfo == NULL) {
+
+ R_printf(R_STDERR,
+ "Memory allocation error.\n");
+
+ return R_MEM;
+ }
+
+ if (ANIM_Load(SceneModule.reslist[i].res_data,
+ SceneModule.reslist[i].res_data_len,
+ &new_anim_id) == R_SUCCESS) {
+ } else {
+ R_printf(R_STDERR,
+ "Error loading animation resource\n");
+
+ return R_FAILURE;
+ }
+
+ new_animinfo->anim_handle = new_anim_id;
+ new_animinfo->anim_res_number =
+ SceneModule.reslist[i].res_number;
+
+ ys_dll_add_tail(SceneModule.anim_list,
+ new_animinfo, sizeof *new_animinfo);
+
+ SceneModule.anim_entries++;
+ }
+ break;
+
+ case SAGA_PAL_ANIM:
+
+ R_printf(R_STDOUT,
+ "Loading palette animation resource.\n");
+
+ PALANIM_Load(SceneModule.reslist[i].res_data,
+ SceneModule.reslist[i].res_data_len);
+ break;
+
+ default:
+
+ R_printf(R_STDERR,
+ "Encountered unknown resource type: %d\n",
+ SceneModule.reslist[i].res_type);
+ break;
+
+ }
+ }
+
+ return R_SUCCESS;
+}
+
+int SCENE_Draw(R_SURFACE * dst_s)
+{
+ R_GAME_DISPLAYINFO disp_info;
+ R_BUFFER_INFO buf_info;
+ R_POINT bg_pt;
+
+ assert(SceneModule.init);
+
+ RENDER_GetBufferInfo(&buf_info);
+ GAME_GetDisplayInfo(&disp_info);
+
+ bg_pt.x = 0;
+ bg_pt.y = 0;
+
+ switch (SceneModule.scene_mode) {
+
+ case R_SCENE_MODE_NORMAL:
+
+ GFX_BufToSurface(dst_s,
+ buf_info.r_bg_buf,
+ disp_info.logical_w,
+ YS_MAX(disp_info.scene_h, SceneModule.bg.h), NULL, &bg_pt);
+ break;
+
+ case R_SCENE_MODE_ISO:
+
+ ISOMAP_Draw(dst_s);
+ break;
+
+ default:
+ /* Unknown scene mode */
+ return R_FAILURE;
+ break;
+
+ };
+
+ return R_SUCCESS;
+}
+
+int SCENE_End(void)
+{
+ R_SCENE_INFO scene_info;
+
+ assert(SceneModule.init);
+
+ if (SceneModule.scene_loaded != 1) {
+ R_printf(R_STDERR, "SCENE_End(): No scene to end.\n");
+ return -1;
+ }
+
+ R_printf(R_STDOUT, "SCENE_End(): Ending scene...\n");
+
+ SCENE_GetInfo(&scene_info);
+
+ SceneModule.scene_proc(SCENE_END, &scene_info);
+
+ if (SceneModule.desc.script_num > 0) {
+
+ SCRIPT_Free();
+ }
+
+ /* Free scene background */
+ if (SceneModule.bg.loaded) {
+ free(SceneModule.bg.buf);
+ SceneModule.bg.loaded = 0;
+ }
+
+ /* Free scene background mask */
+ if (SceneModule.bg_mask.loaded) {
+ free(SceneModule.bg_mask.buf);
+ SceneModule.bg_mask.loaded = 0;
+ }
+
+ /* Free scene resource list */
+ if (SceneModule.load_desc) {
+
+ free(SceneModule.reslist);
+ }
+
+ /* Free animation info list */
+ ANIM_Reset();
+
+ PALANIM_Free();
+ OBJECTMAP_Free();
+ ACTIONMAP_Free();
+
+ ys_dll_destroy(SceneModule.anim_list);
+
+ SceneModule.anim_entries = 0;
+
+ EVENT_ClearList();
+ TEXT_ClearList(SceneModule.text_list);
+
+ SceneModule.scene_loaded = 0;
+
+ return R_SUCCESS;
+}
+
+void CF_scenechange(int argc, char *argv[])
+{
+
+ int scene_num = 0;
+
+ if ((argc == 0) || (argc > 1)) {
+ return;
+ }
+
+ scene_num = atoi(argv[0]);
+
+ if ((scene_num < 1) || (scene_num > SceneModule.scene_max)) {
+ CON_Print("Invalid scene number.");
+ return;
+ }
+
+ SCENE_ClearQueue();
+
+ if (SCENE_Change(scene_num) == R_SUCCESS) {
+ CON_Print("Scene changed.");
+ } else {
+ CON_Print("Couldn't change scene!");
+ }
+
+ return;
+}
+
+void CF_sceneinfo(int argc, char *argv[])
+{
+
+ const char *fmt = "%-20s %d";
+
+ YS_IGNORE_PARAM(argc);
+ YS_IGNORE_PARAM(argv);
+
+ CON_Print(fmt, "Scene number:", SceneModule.scene_number);
+ CON_Print(fmt, "Descriptor R#:", SceneModule.scene_rn);
+ CON_Print("-------------------------");
+ CON_Print(fmt, "Unknown:", SceneModule.desc.unknown0);
+ CON_Print(fmt, "Resource list R#:", SceneModule.desc.res_list_rn);
+ CON_Print(fmt, "End slope:", SceneModule.desc.end_slope);
+ CON_Print(fmt, "Begin slope:", SceneModule.desc.begin_slope);
+ CON_Print(fmt, "Script resource:", SceneModule.desc.script_num);
+ CON_Print(fmt, "Scene script:", SceneModule.desc.scene_scriptnum);
+ CON_Print(fmt, "Start script:", SceneModule.desc.start_scriptnum);
+ CON_Print(fmt, "Music R#", SceneModule.desc.music_rn);
+
+ return;
+}
+
+} // End of namespace Saga
diff --git a/saga/scene.h b/saga/scene.h
new file mode 100644
index 0000000000..21478c64c1
--- /dev/null
+++ b/saga/scene.h
@@ -0,0 +1,229 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Scene management module private header file
+
+ Notes:
+*/
+
+#ifndef SAGA_SCENE_H
+#define SAGA_SCENE_H
+
+namespace Saga {
+
+enum SCENE_LOAD_FLAGS {
+
+ BY_RESOURCE = 0,
+ BY_SCENE,
+ BY_DESC
+};
+
+enum SCENE_PROC_PARAMS {
+
+ SCENE_BEGIN = 0,
+ SCENE_END
+};
+
+/* Resource type numbers */
+enum SAGA_RESOURCE_TYPES {
+
+ SAGA_BG_IMAGE = 2,
+ SAGA_BG_MASK = 3,
+ SAGA_OBJECT_NAME_LIST = 5,
+ SAGA_OBJECT_MAP = 6,
+ SAGA_ACTION_MAP = 7,
+ SAGA_ISO_TILESET = 8,
+ SAGA_ISO_METAMAP = 9,
+ SAGA_ISO_METATILESET = 10,
+ SAGA_ANIM_1 = 14,
+ SAGA_ANIM_2,
+ SAGA_ANIM_3,
+ SAGA_ANIM_4,
+ SAGA_ANIM_5,
+ SAGA_ANIM_6,
+ SAGA_ANIM_7,
+ SAGA_PAL_ANIM = 23
+};
+
+#define SAGA_SCENE_DESC_LEN 16
+
+typedef struct R_SCENE_DESC_tag {
+
+ int unknown0;
+ int res_list_rn;
+ int end_slope;
+ int begin_slope;
+ int script_num;
+ int scene_scriptnum;
+ int start_scriptnum;
+ int music_rn;
+
+ struct R_SCENE_RESLIST_tag *res_list;
+ size_t res_list_ct;
+
+} R_SCENE_DESC;
+
+#define SAGA_RESLIST_ENTRY_LEN 4
+
+typedef struct R_SCENE_RESLIST_tag {
+
+ ulong res_number;
+ int res_type;
+
+ uchar *res_data;
+ size_t res_data_len;
+
+} R_SCENE_RESLIST;
+
+typedef struct SCENE_IMAGE_tag {
+
+ int loaded;
+
+ int w;
+ int h;
+ int p;
+
+ uchar *buf;
+ size_t buf_len;
+
+ uchar *res_buf;
+ size_t res_len;
+
+ PALENTRY pal[256];
+
+} SCENE_IMAGE;
+
+typedef struct SCENE_ANIMINFO_tag {
+
+ int anim_res_number;
+ int anim_handle;
+
+ struct SCENE_ANIMINFO_tag *next;
+
+} SCENE_ANIMINFO;
+
+typedef struct R_SCENE_QUEUE_tag {
+
+ ulong scene_n;
+ R_SCENE_DESC *scene_desc;
+ int load_flag;
+
+ R_SCENE_PROC *scene_proc;
+ int scene_skiptarget;
+
+} R_SCENE_QUEUE;
+
+typedef struct R_SCENE_MODULE_tag {
+
+ int init;
+
+ R_RSCFILE_CONTEXT *scene_ctxt;
+
+ int *scene_lut;
+ int scene_count;
+ int scene_max;
+
+ YS_DL_LIST *scene_queue;
+
+ int first_scene;
+
+ int scene_loaded;
+ int scene_mode;
+ int scene_number;
+ int scene_rn;
+ int in_game;
+
+ int load_desc;
+ R_SCENE_DESC desc;
+
+ int reslist_loaded;
+ int reslist_entries;
+ R_SCENE_RESLIST *reslist;
+
+ int anim_entries;
+ YS_DL_LIST *anim_list;
+
+ R_SCENE_PROC *scene_proc;
+
+ R_TEXTLIST *text_list;
+
+ SCENE_IMAGE bg;
+ SCENE_IMAGE bg_mask;
+
+} R_SCENE_MODULE;
+
+int SCENE_Queue(R_SCENE_QUEUE * scene_queue);
+int SCENE_ClearQueue(void);
+
+int
+SCENE_Load(int scene,
+ int load_flag, R_SCENE_PROC scene_proc, struct R_SCENE_DESC_tag *);
+
+int LoadSceneDescriptor(ulong res_number);
+
+int LoadSceneResourceList(ulong res_number);
+
+int ProcessSceneResources(void);
+
+void CF_scenechange(int argc, char *argv[]);
+
+void CF_sceneinfo(int argc, char *argv[]);
+
+/*
+ * r_sceneproc.c
+\*--------------------------------------------------------------------------*/
+
+int IHNM_StartProc(void);
+
+int InitialSceneProc(int param, R_SCENE_INFO * scene_info);
+int DefaultSceneProc(int param, R_SCENE_INFO * scene_info);
+
+/*
+ * r_ite_introproc.c
+\*--------------------------------------------------------------------------*/
+
+int ITE_StartProc(void);
+int ITE_IntroAnimProc(int param, R_SCENE_INFO * scene_info);
+int ITE_IntroCave1Proc(int param, R_SCENE_INFO * scene_info);
+int ITE_IntroCave2Proc(int param, R_SCENE_INFO * scene_info);
+int ITE_IntroCave3Proc(int param, R_SCENE_INFO * scene_info);
+int ITE_IntroCave4Proc(int param, R_SCENE_INFO * scene_info);
+int ITE_IntroValleyProc(int param, R_SCENE_INFO * scene_info);
+int ITE_IntroTreeHouseProc(int param, R_SCENE_INFO * scene_info);
+int ITE_IntroFairePathProc(int param, R_SCENE_INFO * scene_info);
+int ITE_IntroFaireTentProc(int param, R_SCENE_INFO * scene_info);
+
+/*
+ * r_ihnm_introproc.c
+\*--------------------------------------------------------------------------*/
+int IHNM_StartProc(void);
+int IHNM_IntroMovieProc1(int param, R_SCENE_INFO * scene_info);
+int IHNM_IntroMovieProc2(int param, R_SCENE_INFO * scene_info);
+int IHNM_IntroMovieProc3(int param, R_SCENE_INFO * scene_info);
+int IHNM_HateProc(int param, R_SCENE_INFO * scene_info);
+
+} // End of namespace Saga
+
+#endif /* SAGA_SCENE_H_ */
diff --git a/saga/scene_mod.h b/saga/scene_mod.h
new file mode 100644
index 0000000000..2a8fcc705a
--- /dev/null
+++ b/saga/scene_mod.h
@@ -0,0 +1,103 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Scene management module public header file
+
+ Notes:
+*/
+
+#ifndef SAGA_SCENE_MOD_H__
+#define SAGA_SCENE_MOD_H__
+
+#include "text_mod.h"
+
+namespace Saga {
+
+/*
+ * r_scene.c
+\*--------------------------------------------------------------------------*/
+enum R_SCENE_MODES {
+
+ R_SCENE_MODE_INVALID,
+ R_SCENE_MODE_NORMAL,
+ R_SCENE_MODE_ISO
+};
+
+typedef struct SCENE_ZINFO_tag {
+
+ int begin_slope;
+ int end_slope;
+
+} SCENE_ZINFO;
+
+typedef struct SCENE_BGINFO_tag {
+
+ int bg_x;
+ int bg_y;
+
+ int bg_w;
+ int bg_h;
+ int bg_p;
+
+ uchar *bg_buf;
+ size_t bg_buflen;
+
+} SCENE_BGINFO;
+
+typedef struct R_SCENE_INFO_tag {
+
+ SCENE_ZINFO z_info;
+ SCENE_BGINFO bg_info;
+
+ R_TEXTLIST *text_list;
+
+} R_SCENE_INFO;
+
+typedef int (R_SCENE_PROC) (int, R_SCENE_INFO *);
+
+int SCENE_Register(void);
+int SCENE_Init(void);
+int SCENE_Shutdown(void);
+
+int SCENE_Start(void);
+int SCENE_Next(void);
+int SCENE_Skip(void);
+int SCENE_End(void);
+
+int SCENE_Draw(R_SURFACE *);
+
+int SCENE_GetMode(void);
+int SCENE_GetBGMaskInfo(int *w, int *h, uchar ** buf, size_t * buf_len);
+
+int SCENE_IsBGMaskPresent(void);
+int SCENE_GetBGInfo(SCENE_BGINFO * bginfo);
+int SCENE_GetZInfo(SCENE_ZINFO * zinfo);
+int SCENE_GetBGPal(PALENTRY ** pal);
+
+int SCENE_GetInfo(R_SCENE_INFO * si);
+
+} // End of namespace Saga
+
+#endif /* SAGA_SCENE_MOD_H__ */
diff --git a/saga/sceneproc.cpp b/saga/sceneproc.cpp
new file mode 100644
index 0000000000..e07c7bc741
--- /dev/null
+++ b/saga/sceneproc.cpp
@@ -0,0 +1,200 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Initial and default scene procedures
+
+ Notes:
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "reinherit.h"
+
+#include "yslib.h"
+
+/*
+ * Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "animation_mod.h"
+#include "events_mod.h"
+#include "scene_mod.h"
+#include "palanim_mod.h"
+
+/*
+ * Begin module
+\*--------------------------------------------------------------------------*/
+#include "scene.h"
+#include "sceneproc.h"
+
+namespace Saga {
+
+int InitialSceneProc(int param, R_SCENE_INFO * scene_info)
+{
+ R_EVENT event = { 0 };
+ R_EVENT *q_event;
+
+ int delay_time = 0;
+
+ static PALENTRY current_pal[R_PAL_ENTRIES];
+ PALENTRY *pal;
+
+ YS_IGNORE_PARAM(scene_info);
+
+ switch (param) {
+
+ case SCENE_BEGIN:
+
+ SYSMUSIC_Stop();
+ SYSSOUND_StopVoice();
+
+ /* Fade palette to black from intro scene
+ * \*----------------------------------------------------- */
+ SYSGFX_GetCurrentPal(current_pal);
+
+ event.type = R_CONTINUOUS_EVENT;
+ event.code = R_PAL_EVENT;
+ event.op = EVENT_PALTOBLACK;
+ event.time = 0;
+ event.duration = PALETTE_FADE_DURATION;
+ event.data = current_pal;
+
+ delay_time += PALETTE_FADE_DURATION;
+
+ q_event = EVENT_Queue(&event);
+
+ /* Activate user interface
+ * \*----------------------------------------------------- */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_INTERFACE_EVENT;
+ event.op = EVENT_ACTIVATE;
+ event.time = 0;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ /* Set first scene background w/o changing palette
+ * \*----------------------------------------------------- */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_BG_EVENT;
+ event.op = EVENT_DISPLAY;
+ event.param = NO_SET_PALETTE;
+ event.time = 0;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ /* Fade in to first scene background palette
+ * \*----------------------------------------------------- */
+ SCENE_GetBGPal(&pal);
+
+ event.type = R_CONTINUOUS_EVENT;
+ event.code = R_PAL_EVENT;
+ event.op = EVENT_BLACKTOPAL;
+ event.time = delay_time;
+ event.duration = PALETTE_FADE_DURATION;
+ event.data = pal;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ event.code = R_PALANIM_EVENT;
+ event.op = EVENT_CYCLESTART;
+ event.time = 0;
+
+ q_event = EVENT_Chain(q_event, &event);
+
+ ANIM_SetFlag(0, ANIM_LOOP);
+ ANIM_Play(0, delay_time);
+
+ break;
+
+ case SCENE_END:
+
+ break;
+
+ default:
+ R_printf(R_STDERR, "Illegal scene procedure parameter.\n");
+ break;
+
+ }
+
+ return 0;
+}
+
+int DefaultSceneProc(int param, R_SCENE_INFO * scene_info)
+{
+
+ R_EVENT event;
+
+ YS_IGNORE_PARAM(scene_info);
+
+ switch (param) {
+
+ case SCENE_BEGIN:
+
+ /* Set scene background
+ * \*----------------------------------------------------- */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_BG_EVENT;
+ event.op = EVENT_DISPLAY;
+ event.param = SET_PALETTE;
+ event.time = 0;
+
+ EVENT_Queue(&event);
+
+ /* Activate user interface
+ * \*----------------------------------------------------- */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_INTERFACE_EVENT;
+ event.op = EVENT_ACTIVATE;
+ event.time = 0;
+
+ EVENT_Queue(&event);
+
+ /* Begin palette cycle animation if present
+ * \*----------------------------------------------------- */
+ event.type = R_ONESHOT_EVENT;
+ event.code = R_PALANIM_EVENT;
+ event.op = EVENT_CYCLESTART;
+ event.time = 0;
+
+ EVENT_Queue(&event);
+
+ break;
+
+ case SCENE_END:
+
+ break;
+
+ default:
+ R_printf(R_STDERR, "Illegal scene procedure parameter.\n");
+ break;
+
+ }
+
+ return 0;
+}
+
+} // End of namespace Saga
+
diff --git a/saga/sceneproc.h b/saga/sceneproc.h
new file mode 100644
index 0000000000..53e36ad687
--- /dev/null
+++ b/saga/sceneproc.h
@@ -0,0 +1,40 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Initial and default scene procedures header file
+
+ Notes:
+*/
+
+#ifndef SAGA_SCENEPROC_H
+#define SAGA_SCENEPROC_H
+
+namespace Saga {
+
+#define PALETTE_FADE_DURATION 1000
+
+} // End of namespace Saga
+
+#endif
diff --git a/saga/script.cpp b/saga/script.cpp
new file mode 100644
index 0000000000..4c84a9e069
--- /dev/null
+++ b/saga/script.cpp
@@ -0,0 +1,684 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ Scripting module: Script resource handling functions
+
+ Notes:
+*/
+
+#include "reinherit.h"
+
+#include "yslib.h"
+
+/*
+ * Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "rscfile_mod.h"
+#include "game_mod.h"
+#include "text_mod.h"
+#include "console_mod.h"
+#include "cvar_mod.h"
+
+/*
+ * Begin module component
+\*--------------------------------------------------------------------------*/
+#include "script_mod.h"
+#include "script.h"
+#include "sstack.h"
+#include "sthread.h"
+
+namespace Saga {
+
+R_SCRIPT_MODULE ScriptModule;
+
+int SCRIPT_Register(void)
+{
+
+ CVAR_RegisterFunc(CF_script_info,
+ "script_info", NULL, R_CVAR_NONE, 0, 0);
+
+ CVAR_RegisterFunc(CF_script_exec,
+ "script_exec", "<Script number>", R_CVAR_NONE, 1, 1);
+
+ CVAR_RegisterFunc(CF_script_togglestep,
+ "script_togglestep", NULL, R_CVAR_NONE, 0, 0);
+
+ return R_SUCCESS;
+}
+
+int SCRIPT_Init(void)
+/*--------------------------------------------------------------------------*\
+ * Initializes the scripting module.
+ * Loads script resource look-up table, initializes script data system
+\*--------------------------------------------------------------------------*/
+{
+ R_RSCFILE_CONTEXT *s_lut_ctxt;
+
+ uchar *rsc_ptr;
+ size_t rsc_len;
+
+ const uchar *read_ptr;
+ const uchar *read_ptr2;
+
+ int result;
+ int i;
+
+ R_printf(R_STDOUT, "Initializing scripting subsystem.\n");
+
+ /* Load script resource file context
+ * \*---------------------------------------------------------------------- */
+ result = GAME_GetFileContext(&ScriptModule.script_ctxt,
+ R_GAME_SCRIPTFILE, 0);
+ if (result != R_SUCCESS) {
+
+ R_printf(R_STDERR, "Couldn't get script file context.\n");
+
+ return R_FAILURE;
+ }
+
+ /* Load script LUT resource
+ * \*---------------------------------------------------------------------- */
+ result = GAME_GetFileContext(&s_lut_ctxt, R_GAME_RESOURCEFILE, 0);
+ if (result != R_SUCCESS) {
+
+ R_printf(R_STDERR, "Couldn't get resource file context.\n");
+
+ return R_FAILURE;
+ }
+
+ result = RSC_LoadResource(s_lut_ctxt,
+ ITE_SCRIPT_LUT, &rsc_ptr, &rsc_len);
+ if (result != R_SUCCESS) {
+
+ R_printf(R_STDERR,
+ "Error: Couldn't load script resource look-up table.\n");
+
+ return R_FAILURE;
+ }
+
+ /* Create logical script LUT from resource
+ * \*---------------------------------------------------------------------- */
+ if (rsc_len % R_S_LUT_ENTRYLEN_ITECD == 0) {
+
+ ScriptModule.script_lut_entrylen = R_S_LUT_ENTRYLEN_ITECD;
+ } else if (rsc_len % R_S_LUT_ENTRYLEN_ITEDISK == 0) {
+
+ ScriptModule.script_lut_entrylen = R_S_LUT_ENTRYLEN_ITEDISK;
+ } else {
+ R_printf(R_STDERR,
+ "Error: Invalid script lookup table length.\n");
+ return R_FAILURE;
+ }
+
+ /* Calculate number of entries */
+ ScriptModule.script_lut_max =
+ rsc_len / ScriptModule.script_lut_entrylen;
+
+ /* Allocate space for logical LUT */
+ ScriptModule.script_lut = (R_SCRIPT_LUT_ENTRY *)malloc(ScriptModule.script_lut_max *
+ sizeof(R_SCRIPT_LUT_ENTRY));
+ if (ScriptModule.script_lut == NULL) {
+ R_printf(R_STDERR,
+ "Error: Couldn't allocate memory for script resource "
+ "look-up table.\n");
+ return R_MEM;
+ }
+
+ /* Convert LUT resource to logical LUT */
+ read_ptr = rsc_ptr;
+ for (i = 0; i < ScriptModule.script_lut_max; i++) {
+
+ read_ptr2 = read_ptr;
+
+ ScriptModule.script_lut[i].script_rn =
+ ys_read_u16_le(read_ptr2, &read_ptr2);
+
+ ScriptModule.script_lut[i].diag_list_rn =
+ ys_read_u16_le(read_ptr2, &read_ptr2);
+
+ ScriptModule.script_lut[i].voice_lut_rn =
+ ys_read_u16_le(read_ptr2, &read_ptr2);
+
+ /* Skip the unused portion of the structure */
+ read_ptr += ScriptModule.script_lut_entrylen;
+ }
+
+ RSC_FreeResource(rsc_ptr);
+
+ /* Any voice lookup table resources present? */
+ for (i = 0; i < ScriptModule.script_lut_max; i++) {
+
+ if (ScriptModule.script_lut[i].voice_lut_rn) {
+
+ ScriptModule.voice_lut_present = 1;
+ break;
+ }
+ }
+
+ /* Initialize script submodules
+ * \*---------------------------------------------------------------------- */
+ ScriptModule.thread_list = ys_dll_create();
+
+ if (SDATA_Init() != R_SUCCESS) {
+ free(ScriptModule.script_lut);
+ return R_FAILURE;
+ }
+
+ ScriptModule.initialized = 1;
+ return R_SUCCESS;
+}
+
+int SCRIPT_Shutdown(void)
+/*--------------------------------------------------------------------------*\
+ * Shut down script module gracefully; free all allocated module resources
+\*--------------------------------------------------------------------------*/
+{
+ YS_DL_NODE *thread_node;
+ R_SCRIPT_THREAD *thread;
+
+ if (!ScriptModule.initialized) {
+
+ return R_FAILURE;
+ }
+
+ R_printf(R_STDOUT, "Shutting down scripting subsystem.\n");
+
+ /* Free script lookup table */
+ free(ScriptModule.script_lut);
+
+ /* Stop all threads and destroy them */
+
+ for (thread_node = ys_dll_head(ScriptModule.thread_list);
+ thread_node != NULL; thread_node = ys_dll_next(thread_node)) {
+
+ thread = (R_SCRIPT_THREAD *)ys_dll_get_data(thread_node);
+
+ STHREAD_Destroy(thread);
+ }
+
+ ScriptModule.initialized = 0;
+
+ return R_SUCCESS;
+}
+
+int SCRIPT_Load(int script_num)
+/*--------------------------------------------------------------------------*\
+ * Loads a script; including script bytecode and dialogue list
+\*--------------------------------------------------------------------------*/
+{
+
+ R_SCRIPTDATA *script_data;
+
+ uchar *bytecode_p;
+ size_t bytecode_len;
+ ulong scriptl_rn;
+
+ uchar *diagl_p;
+ size_t diagl_len;
+ ulong diagl_rn;
+
+ uchar *voicelut_p;
+ size_t voicelut_len;
+ ulong voicelut_rn;
+
+ int result;
+
+ if (GAME_GetGameType() == R_GAMETYPE_IHNM) {
+ return R_SUCCESS;
+ }
+
+ /* Validate script number */
+ if ((script_num < 0) || (script_num > ScriptModule.script_lut_max)) {
+ R_printf(R_STDERR, "SCRIPT_Load(): Invalid script number!\n");
+ return R_FAILURE;
+ }
+
+ /* Release old script data if present */
+ SCRIPT_Free();
+
+ /* Initialize script data structure
+ * \*---------------------------------------------------------------------- */
+ R_printf(R_STDOUT, "Loading script data for script #%d.\n",
+ script_num);
+
+ script_data = (R_SCRIPTDATA *)malloc(sizeof *script_data);
+ if (script_data == NULL) {
+ R_printf(R_STDERR, "Memory allocation failed.\n");
+ return R_MEM;
+ }
+
+ script_data->loaded = 0;
+
+ /* Initialize script pointers */
+ script_data->diag = NULL;
+ script_data->bytecode = NULL;
+ script_data->voice = NULL;
+
+ /* Load script bytecode
+ * \*---------------------------------------------------------------------- */
+ scriptl_rn = ScriptModule.script_lut[script_num].script_rn;
+
+ result = RSC_LoadResource(ScriptModule.script_ctxt,
+ scriptl_rn, &bytecode_p, &bytecode_len);
+ if (result != R_SUCCESS) {
+ R_printf(R_STDERR,
+ "Error loading script bytecode resource.\n");
+ free(script_data);
+ return R_FAILURE;
+ }
+
+ script_data->bytecode = SCRIPT_LoadBytecode(bytecode_p, bytecode_len);
+
+ if (script_data->bytecode == NULL) {
+ R_printf(R_STDERR,
+ "Error interpreting script bytecode resource.\n");
+ free(script_data);
+ RSC_FreeResource(bytecode_p);
+ return R_FAILURE;
+ }
+
+ /* Load script dialogue list
+ * \*---------------------------------------------------------------------- */
+ diagl_rn = ScriptModule.script_lut[script_num].diag_list_rn;
+
+ /* Load dialogue list resource */
+ result = RSC_LoadResource(ScriptModule.script_ctxt,
+ diagl_rn, &diagl_p, &diagl_len);
+ if (result != R_SUCCESS) {
+ R_printf(R_STDERR, "Error loading dialogue list resource.\n");
+ free(script_data);
+ RSC_FreeResource(bytecode_p);
+ return R_FAILURE;
+ }
+
+ /* Convert dialogue list resource to logical dialogue list */
+ script_data->diag = SCRIPT_LoadDialogue(diagl_p, diagl_len);
+ if (script_data->diag == NULL) {
+ R_printf(R_STDERR,
+ "Error interpreting dialogue list resource.\n");
+ free(script_data);
+ RSC_FreeResource(bytecode_p);
+ RSC_FreeResource(diagl_p);
+ return R_FAILURE;
+ }
+
+ /* Load voice resource lookup table
+ * \*---------------------------------------------------------------------- */
+ if (ScriptModule.voice_lut_present) {
+
+ voicelut_rn = ScriptModule.script_lut[script_num].voice_lut_rn;
+
+ /* Load voice LUT resource */
+ result = RSC_LoadResource(ScriptModule.script_ctxt,
+ voicelut_rn, &voicelut_p, &voicelut_len);
+ if (result != R_SUCCESS) {
+
+ R_printf(R_STDERR,
+ "Error loading voice LUT resource.\n");
+
+ free(script_data);
+ RSC_FreeResource(bytecode_p);
+ RSC_FreeResource(diagl_p);
+
+ return R_FAILURE;
+ }
+
+ /* Convert voice LUT resource to logical voice LUT */
+ script_data->voice = SCRIPT_LoadVoiceLUT(voicelut_p,
+ voicelut_len, script_data);
+ if (script_data->voice == NULL) {
+ R_printf(R_STDERR,
+ "Error interpreting voice LUT resource.\n");
+
+ free(script_data);
+ RSC_FreeResource(bytecode_p);
+ RSC_FreeResource(diagl_p);
+ RSC_FreeResource(voicelut_p);
+
+ return R_FAILURE;
+ }
+
+ }
+
+ /* Finish initialization
+ * \*---------------------------------------------------------------------- */
+ script_data->loaded = 1;
+ ScriptModule.current_script = script_data;
+
+ return R_SUCCESS;
+}
+
+int SCRIPT_Free(void)
+/*--------------------------------------------------------------------------*\
+ * Frees all resources associated with current script.
+\*--------------------------------------------------------------------------*/
+{
+
+ if (ScriptModule.current_script == NULL) {
+ return R_FAILURE;
+ }
+
+ if (!ScriptModule.current_script->loaded) {
+ return R_FAILURE;
+ }
+
+ R_printf(R_STDOUT, "Releasing script data.\n");
+
+ /* Finish initialization
+ * \*---------------------------------------------------------------------- */
+ if (ScriptModule.current_script->diag != NULL) {
+ free(ScriptModule.current_script->diag->str);
+ free(ScriptModule.current_script->diag->str_off);
+ }
+ free(ScriptModule.current_script->diag);
+
+ if (ScriptModule.current_script->bytecode != NULL) {
+ free(ScriptModule.current_script->bytecode->entrypoints);
+ RSC_FreeResource(ScriptModule.current_script->bytecode->
+ bytecode_p);
+ }
+
+ free(ScriptModule.current_script->bytecode);
+
+ if (ScriptModule.voice_lut_present) {
+ free(ScriptModule.current_script->voice->voices);
+ free(ScriptModule.current_script->voice);
+ }
+
+ free(ScriptModule.current_script);
+
+ ScriptModule.current_script = NULL;
+
+ return R_SUCCESS;
+}
+
+R_SCRIPT_BYTECODE *SCRIPT_LoadBytecode(const uchar * bytecode_p,
+ size_t bytecode_len)
+/*--------------------------------------------------------------------------*\
+ * Reads the entrypoint table from a script bytecode resource in memory.
+ * Returns NULL on failure.
+\*--------------------------------------------------------------------------*/
+{
+
+ const uchar *read_p = bytecode_p;
+ R_PROC_TBLENTRY *bc_ep_tbl = NULL;
+ R_SCRIPT_BYTECODE *bc_new_data = NULL;
+
+ unsigned long n_entrypoints; /* Number of entrypoints */
+ size_t ep_tbl_offset; /* Offset of bytecode entrypoint table */
+
+ unsigned long i;
+
+ R_printf(R_STDOUT, "Loading script bytecode...\n");
+
+ /* The first two uint32 values are the number of entrypoints, and the
+ * offset to the entrypoint table, respectively. */
+
+ n_entrypoints = ys_read_u32_le(read_p, &read_p);
+ ep_tbl_offset = ys_read_u32_le(read_p, &read_p);
+
+ /* Check that the entrypoint table offset is valid. */
+ if ((bytecode_len - ep_tbl_offset) <
+ (n_entrypoints * R_SCRIPT_TBLENTRY_LEN)) {
+
+ R_printf(R_STDERR, "Invalid table offset.\n");
+ return NULL;
+ }
+
+ if (n_entrypoints > R_SCRIPT_MAX) {
+ R_printf(R_STDERR, "Script limit exceeded.\n");
+ return NULL;
+ }
+
+ /* Allocate a new bytecode resource information structure and table of
+ * entrypoints */
+
+ bc_new_data = (R_SCRIPT_BYTECODE *)malloc(sizeof *bc_new_data);
+ if (bc_new_data == NULL) {
+ R_printf(R_STDERR,
+ "Memory allocation failure loading script bytecode.\n");
+ return NULL;
+ }
+
+ bc_ep_tbl = (R_PROC_TBLENTRY *)malloc(n_entrypoints * sizeof *bc_ep_tbl);
+ if (bc_ep_tbl == NULL) {
+ R_printf(R_STDERR,
+ "Memory allocation failure creating script entrypoint table.\n");
+ free(bc_new_data);
+ return NULL;
+ }
+
+ /* Read in the entrypoint table */
+
+ read_p = bytecode_p + ep_tbl_offset;
+
+ for (i = 0; i < n_entrypoints; i++) {
+ /* 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 = ys_read_u16_le(read_p, &read_p);
+ bc_ep_tbl[i].offset = ys_read_u16_le(read_p, &read_p);
+
+ /* Perform a simple range check on offset values */
+ if ((bc_ep_tbl[i].name_offset > bytecode_len) ||
+ (bc_ep_tbl[i].offset > bytecode_len)) {
+
+ R_printf(R_STDERR,
+ "Invalid offset encountered in script entrypoint table.\n");
+ free(bc_new_data);
+ free(bc_ep_tbl);
+ return NULL;
+ }
+ }
+
+ bc_new_data->bytecode_p = (uchar *) bytecode_p;
+ bc_new_data->bytecode_len = bytecode_len;
+
+ bc_new_data->n_entrypoints = n_entrypoints;
+ bc_new_data->entrypoints = bc_ep_tbl;
+ bc_new_data->ep_tbl_offset = ep_tbl_offset;
+
+ return bc_new_data;
+}
+
+R_DIALOGUE_LIST *SCRIPT_LoadDialogue(const uchar * dialogue_p,
+ size_t dialogue_len)
+/*--------------------------------------------------------------------------*\
+ * Reads a logical dialogue list from a dialogue list resource in memory.
+ * Returns NULL on failure.
+\*--------------------------------------------------------------------------*/
+{
+ const uchar *read_p = dialogue_p;
+
+ R_DIALOGUE_LIST *dialogue_list;
+ uint n_dialogue;
+
+ uint i;
+ size_t offset;
+
+ R_printf(R_STDOUT, "Loading dialogue list...\n");
+
+ /* Allocate dialogue list structure */
+ dialogue_list = (R_DIALOGUE_LIST *)malloc(sizeof *dialogue_list);
+ if (dialogue_list == NULL) {
+ return NULL;
+ }
+
+ /* First uint16 is the offset of the first string */
+ offset = ys_read_u16_le(read_p, &read_p);
+ if (offset > dialogue_len) {
+ R_printf(R_STDERR, "Error, invalid string offset.\n");
+ return NULL;
+ }
+
+ /* Calculate table length */
+ n_dialogue = offset / 2;
+ dialogue_list->n_dialogue = n_dialogue;
+
+ /* Allocate table of string pointers */
+ dialogue_list->str = (char **)malloc(n_dialogue * sizeof(char *));
+ if (dialogue_list->str == NULL) {
+ free(dialogue_list);
+ return NULL;
+ }
+
+ /* Allocate table of string offsets */
+ dialogue_list->str_off = (size_t *)malloc(n_dialogue * sizeof(size_t));
+ if (dialogue_list->str_off == NULL) {
+ free(dialogue_list->str);
+ free(dialogue_list);
+ return NULL;
+ }
+
+ /* Read in tables from dialogue list resource */
+ read_p = dialogue_p;
+ for (i = 0; i < n_dialogue; i++) {
+ offset = ys_read_u16_le(read_p, &read_p);
+
+ if (offset > dialogue_len) {
+ R_printf(R_STDERR, "Error, invalid string offset.\n");
+ free(dialogue_list->str);
+ free(dialogue_list->str_off);
+ free(dialogue_list);
+ return NULL;
+ }
+ dialogue_list->str[i] = (char *)dialogue_p + offset;
+ dialogue_list->str_off[i] = offset;
+ }
+
+ return dialogue_list;
+}
+
+R_VOICE_LUT *SCRIPT_LoadVoiceLUT(const uchar * voicelut_p,
+ size_t voicelut_len, R_SCRIPTDATA * script)
+/*--------------------------------------------------------------------------*\
+ * Reads a logical voice LUT from a voice LUT resource in memory.
+ * Returns NULL on failure.
+\*--------------------------------------------------------------------------*/
+{
+ const uchar *read_p = voicelut_p;
+
+ R_VOICE_LUT *voice_lut;
+
+ uint n_voices;
+ uint i;
+
+ voice_lut = (R_VOICE_LUT *)malloc(sizeof *voice_lut);
+ if (voice_lut == NULL) {
+ return NULL;
+ }
+
+ n_voices = voicelut_len / 2;
+ if (n_voices != script->diag->n_dialogue) {
+ R_printf(R_STDERR, "Error: Voice LUT entries do not match "
+ "dialogue entries.\n");
+ return NULL;
+ }
+
+ voice_lut->voices = (int *)malloc(n_voices * sizeof *voice_lut->voices);
+ if (voice_lut->voices == NULL) {
+
+ return NULL;
+ }
+
+ for (i = 0; i < n_voices; i++) {
+
+ voice_lut->voices[i] = ys_read_u16_le(read_p, &read_p);
+ }
+
+ return voice_lut;
+}
+
+void CF_script_info(int argc, char *argv[])
+{
+
+ ulong n_entrypoints;
+ ulong i;
+ char *name_ptr;
+
+ if (ScriptModule.current_script == NULL) {
+ return;
+ }
+
+ if (!ScriptModule.current_script->loaded) {
+ return;
+ }
+
+ n_entrypoints = ScriptModule.current_script->bytecode->n_entrypoints;
+
+ CON_Print("Current script contains %d entrypoints:", n_entrypoints);
+
+ for (i = 0; i < n_entrypoints; i++) {
+ name_ptr = (char *)
+ ScriptModule.current_script->bytecode->bytecode_p +
+ ScriptModule.current_script->bytecode->entrypoints[i].
+ name_offset;
+
+ CON_Print("%lu: %s", i, name_ptr);
+ }
+
+ return;
+}
+
+void CF_script_exec(int argc, char *argv[])
+{
+ uint ep_num;
+
+ if (argc < 1) {
+ return;
+ }
+
+ ep_num = atoi(argv[0]);
+
+ if (ScriptModule.dbg_thread == NULL) {
+
+ CON_Print("Creating debug thread...");
+ ScriptModule.dbg_thread = STHREAD_Create();
+
+ if (ScriptModule.dbg_thread == NULL) {
+ CON_Print("Thread creation failed.");
+ return;
+ }
+ }
+
+ if (ep_num >= ScriptModule.current_script->bytecode->n_entrypoints) {
+ CON_Print("Invalid entrypoint.");
+ return;
+ }
+
+ STHREAD_Execute(ScriptModule.dbg_thread, ep_num);
+
+ return;
+}
+
+void CF_script_togglestep(int argc, char *argv[])
+{
+ ScriptModule.dbg_singlestep = !ScriptModule.dbg_singlestep;
+
+ return;
+}
+
+} // End of namespace Saga
diff --git a/saga/script.h b/saga/script.h
new file mode 100644
index 0000000000..bff544e636
--- /dev/null
+++ b/saga/script.h
@@ -0,0 +1,157 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ Scripting module private header
+
+ Notes:
+*/
+
+#ifndef SAGA_SCRIPT_H
+#define SAGA_SCRIPT_H
+
+#include "sstack.h"
+#include "sdata.h"
+
+namespace Saga {
+
+#define R_S_LUT_ENTRYLEN_ITECD 22
+#define R_S_LUT_ENTRYLEN_ITEDISK 16
+
+#define R_SCRIPT_TBLENTRY_LEN 4
+
+#define R_SCRIPT_MAX 5000
+#define R_SCRIPTLIST_HDR 12
+#define R_SCRIPT_STRINGLIMIT 255
+#define R_TAB " "
+
+#define R_DEF_THREAD_STACKSIZE 16
+
+#define S_ERROR_PREFIX "SError: "
+#define S_WARN_PREFIX "SWarning: "
+
+typedef struct R_PROC_TBLENTRY_tag {
+
+ size_t name_offset;
+ size_t offset;
+
+} R_PROC_TBLENTRY;
+
+typedef struct R_SCRIPT_BYTECODE_tag {
+
+ unsigned char *bytecode_p;
+ size_t bytecode_len;
+
+ size_t ep_tbl_offset;
+ unsigned long n_entrypoints;
+ R_PROC_TBLENTRY *entrypoints;
+
+} R_SCRIPT_BYTECODE;
+
+typedef struct R_DIALOGUE_LIST_tag {
+
+ unsigned int n_dialogue;
+ char **str;
+ size_t *str_off;
+
+} R_DIALOGUE_LIST;
+
+typedef struct R_VOICE_LUT_tag {
+
+ int n_voices;
+ int *voices;
+
+} R_VOICE_LUT;
+
+typedef struct R_SCRIPTDATA_tag {
+
+ int loaded;
+ R_SCRIPT_BYTECODE *bytecode;
+ R_DIALOGUE_LIST *diag;
+ R_VOICE_LUT *voice;
+
+} R_SCRIPTDATA;
+
+typedef struct R_SCRIPT_LUT_ENTRY_tag {
+
+ int script_rn;
+ int diag_list_rn;
+ int voice_lut_rn;
+
+} R_SCRIPT_LUT_ENTRY;
+
+typedef struct R_SCRIPT_DATABUF_tag {
+
+ SDataWord_T *data;
+ int len;
+
+} R_SCRIPT_DATABUF;
+
+typedef struct R_SCRIPT_MODULE_tag {
+
+ int initialized;
+
+ R_RSCFILE_CONTEXT *script_ctxt;
+
+ int voice_lut_present;
+ R_SCRIPT_LUT_ENTRY *script_lut;
+ int script_lut_max;
+ uint script_lut_entrylen;
+
+ R_SCRIPTDATA *current_script;
+ YS_DL_LIST *thread_list;
+ R_SCRIPT_DATABUF *data_buf[R_SCRIPT_DATABUF_NUM];
+
+ int dbg_singlestep;
+ int dbg_dostep;
+ R_SCRIPT_THREAD *dbg_thread;
+ R_TEXTLIST_ENTRY *dbg_txtentry;
+
+} R_SCRIPT_MODULE;
+
+extern R_SCRIPT_MODULE ScriptModule;
+
+R_SCRIPT_BYTECODE *SCRIPT_LoadBytecode(const uchar * bytecode_p,
+ size_t bytecode_len);
+
+R_DIALOGUE_LIST *SCRIPT_LoadDialogue(const uchar * dialogue_p,
+ size_t dialogue_len);
+
+R_VOICE_LUT *SCRIPT_LoadVoiceLUT(const uchar * voicelut_p,
+ size_t voicelut_len, R_SCRIPTDATA * script);
+
+int
+SCRIPT_Disassemble(R_SCRIPT_BYTECODE * script_list,
+ R_DIALOGUE_LIST * diag_list);
+
+void CF_script_info(int argc, char *argv[]);
+
+void CF_script_exec(int argc, char *argv[]);
+
+void CF_script_togglestep(int argc, char *argv[]);
+
+} // End of namespace Saga
+
+#endif
diff --git a/saga/script_mod.h b/saga/script_mod.h
new file mode 100644
index 0000000000..ec824e6ce2
--- /dev/null
+++ b/saga/script_mod.h
@@ -0,0 +1,89 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ Scripting module public header
+
+ Notes:
+*/
+
+#ifndef SAGA_SCRIPT_MOD_H
+#define SAGA_SCRIPT_MOD_H
+
+namespace Saga {
+
+typedef unsigned int SDataWord_T;
+
+typedef struct R_SCRIPT_THREAD_tag R_SCRIPT_THREAD;
+
+enum R_SCRIPT_VERBS {
+
+ S_VERB_WALKTO = 0,
+ S_VERB_LOOKAT = 2,
+ S_VERB_PICKUP = 1,
+ S_VERB_TALKTO,
+ S_VERB_OPEN = 5,
+ S_VERB_CLOSE = 6,
+ S_VERB_USE = 8,
+ S_VERB_GIVE
+};
+
+int SCRIPT_Register(void);
+
+int SCRIPT_Init(void);
+
+int SCRIPT_Shutdown(void);
+
+int SCRIPT_Load(int script_num);
+
+int SCRIPT_Free(void);
+
+int SDATA_GetWord(int n_buf, int n_word, SDataWord_T * data);
+
+int SDATA_PutWord(int n_buf, int n_word, SDataWord_T data);
+
+int SDATA_SetBit(int n_buf, SDataWord_T n_bit, int bitstate);
+
+int SDATA_GetBit(int n_buf, SDataWord_T n_bit, int *bitstate);
+
+int SDATA_ReadWordS(SDataWord_T word);
+
+uint SDATA_ReadWordU(SDataWord_T word);
+
+R_SCRIPT_THREAD *STHREAD_Create(void);
+
+int STHREAD_Execute(R_SCRIPT_THREAD * thread, int ep_num);
+
+int STHREAD_ExecThreads(int msec);
+
+int STHREAD_HoldSem(R_SEMAPHORE * sem);
+
+int STHREAD_ReleaseSem(R_SEMAPHORE * sem);
+
+int STHREAD_DebugStep(void);
+
+} // End of namespace Saga
+
+#endif /* SAGA_SCRIPT_MOD_H */
diff --git a/saga/sdata.cpp b/saga/sdata.cpp
new file mode 100644
index 0000000000..7ab9e4c056
--- /dev/null
+++ b/saga/sdata.cpp
@@ -0,0 +1,210 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ Scripting module data management component
+
+ Notes:
+
+ Type SDataWord_T must be unpadded
+*/
+
+#include "reinherit.h"
+
+#include "yslib.h"
+
+#include <limits.h>
+
+/*
+ * Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "text_mod.h"
+
+/*
+ * Begin module component
+\*--------------------------------------------------------------------------*/
+#include "script_mod.h"
+#include "script.h"
+#include "sdata.h"
+
+namespace Saga {
+
+int SDATA_Init(void)
+{
+
+ unsigned int i;
+ void *alloc_ptr;
+
+ R_printf(R_STDOUT, "Initializing script data buffers.\n");
+
+ for (i = 0; i < R_SCRIPT_DATABUF_NUM; i++) {
+
+ alloc_ptr = malloc(sizeof *ScriptModule.data_buf[0]);
+
+ if (alloc_ptr == NULL) {
+ R_printf(R_STDERR,
+ "Error allocating memory for script data buffer %d.\n",
+ i);
+ return R_MEM;
+ }
+
+ ScriptModule.data_buf[i] = (R_SCRIPT_DATABUF *)alloc_ptr;
+
+ alloc_ptr = calloc(R_SCRIPT_DATABUF_LEN, sizeof(SDataWord_T));
+
+ if (alloc_ptr == NULL) {
+ R_printf(R_STDERR,
+ "Error allocating memory for script data buffer %d.\n",
+ i);
+ return R_MEM;
+ }
+
+ ScriptModule.data_buf[i]->len = R_SCRIPT_DATABUF_LEN;
+ ScriptModule.data_buf[i]->data = (SDataWord_T *)alloc_ptr;
+ }
+
+ return R_SUCCESS;
+}
+
+int SDATA_GetWord(int n_buf, int n_word, SDataWord_T * data)
+{
+
+ if ((n_buf < 0) || (n_buf >= R_SCRIPT_DATABUF_NUM)) {
+ return R_FAILURE;
+ }
+
+ if ((n_word < 0) || (n_word >= ScriptModule.data_buf[n_buf]->len)) {
+ return R_FAILURE;
+ }
+
+ if (data == NULL) {
+ return R_FAILURE;
+ }
+
+ *data = ScriptModule.data_buf[n_buf]->data[n_word];
+
+ return R_SUCCESS;
+}
+
+int SDATA_PutWord(int n_buf, int n_word, SDataWord_T data)
+{
+
+ if ((n_buf < 0) || (n_buf >= R_SCRIPT_DATABUF_NUM)) {
+ return R_FAILURE;
+ }
+
+ if ((n_word < 0) || (n_word >= ScriptModule.data_buf[n_buf]->len)) {
+ return R_FAILURE;
+ }
+
+ ScriptModule.data_buf[n_buf]->data[n_word] = data;
+
+ return R_SUCCESS;
+}
+
+int SDATA_SetBit(int n_buf, SDataWord_T n_bit, int bitstate)
+{
+
+ int n_word;
+ int n_bitpos;
+
+ SDataWord_T bit_pattern = 0x01;
+
+ if ((n_buf < 0) || (n_buf >= R_SCRIPT_DATABUF_NUM)) {
+ return R_FAILURE;
+ }
+
+ if (n_bit >= (unsigned long)ScriptModule.data_buf[n_buf]->len *
+ (sizeof(SDataWord_T) * CHAR_BIT)) {
+
+ return R_FAILURE;
+ }
+
+ n_word = n_bit / (sizeof(SDataWord_T) * CHAR_BIT);
+ n_bitpos = n_bit % (sizeof(SDataWord_T) * CHAR_BIT);
+
+ bit_pattern <<= ((sizeof(SDataWord_T) * CHAR_BIT) - (n_bitpos + 1));
+
+ if (bitstate) {
+ ScriptModule.data_buf[n_buf]->data[n_word] |= bit_pattern;
+ } else {
+ ScriptModule.data_buf[n_buf]->data[n_word] &= ~bit_pattern;
+ }
+
+ return R_SUCCESS;
+}
+
+int SDATA_GetBit(int n_buf, SDataWord_T n_bit, int *bitstate)
+{
+
+ int n_word;
+ int n_bitpos;
+
+ SDataWord_T bit_pattern = 0x01;
+
+ if ((n_buf < 0) || (n_buf >= R_SCRIPT_DATABUF_NUM)) {
+
+ return R_FAILURE;
+ }
+
+ if (n_bit >= (SDataWord_T) ScriptModule.data_buf[n_buf]->len *
+ (sizeof(SDataWord_T) * CHAR_BIT)) {
+
+ return R_FAILURE;
+ }
+
+ n_word = n_bit / (sizeof(SDataWord_T) * CHAR_BIT);
+ n_bitpos = n_bit % (sizeof(SDataWord_T) * CHAR_BIT);
+
+ bit_pattern <<= ((sizeof(SDataWord_T) * CHAR_BIT) - (n_bitpos + 1));
+
+ *bitstate = (ScriptModule.data_buf[n_buf]->data[n_word] &
+ bit_pattern) ? 1 : 0;
+
+ return R_SUCCESS;
+}
+
+int SDATA_ReadWordS(SDataWord_T word)
+{
+ uint u_int = word;
+ int s_int;
+
+ if (u_int & 0x8000U) {
+ s_int = (int)(u_int - 0x8000U) - 0x7FFF - 1;
+ } else {
+ s_int = u_int;
+ }
+
+ return s_int;
+}
+
+uint SDATA_ReadWordU(SDataWord_T word)
+{
+ uint u_int = (uint) word;
+
+ return u_int;
+}
+
+} // End of namespace Saga
diff --git a/saga/sdata.h b/saga/sdata.h
new file mode 100644
index 0000000000..3c9805de45
--- /dev/null
+++ b/saga/sdata.h
@@ -0,0 +1,44 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ Scripting module data management component header file
+
+ Notes:
+*/
+
+#ifndef SAGA_SDATA_H
+#define SAGA_SDATA_H
+
+namespace Saga {
+
+#define R_SCRIPT_DATABUF_NUM 5U
+#define R_SCRIPT_DATABUF_LEN 1024U
+
+int SDATA_Init(void);
+
+} // End of namespace Saga
+
+#endif /* SAGA_SDATA_H */
diff --git a/saga/sdebug.cpp b/saga/sdebug.cpp
new file mode 100644
index 0000000000..fa8986238e
--- /dev/null
+++ b/saga/sdebug.cpp
@@ -0,0 +1,658 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ Scripting module simple thread debugging support
+
+ Notes:
+*/
+
+#include "reinherit.h"
+
+#include "yslib.h"
+
+/*
+ * Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "actor_mod.h"
+#include "console_mod.h"
+#include "text_mod.h"
+#include "scene_mod.h"
+#include "font_mod.h"
+
+/*
+ * Begin module component
+\*--------------------------------------------------------------------------*/
+#include "script.h"
+#include "sthread.h"
+
+namespace Saga {
+
+#define SD_DISPLAY_LEN 128
+
+#define SD_ADDTXT( x ) strncat( disp_buf, x, SD_DISPLAY_LEN );
+
+int SDEBUG_PrintInstr(R_SCRIPT_THREAD * thread)
+{
+
+ R_TEXTLIST_ENTRY tl_e;
+
+ const uchar *start_p;
+ const uchar *read_p;
+
+ char tmp_buf[80] = { 0 };
+ static char disp_buf[SD_DISPLAY_LEN] = { 0 };
+
+ int in_char;
+ /*int op_offset; */
+
+ int n_switch;
+ int i;
+
+ R_SCENE_INFO si;
+
+ SCENE_GetInfo(&si);
+
+ disp_buf[0] = 0;
+
+ if (ScriptModule.dbg_txtentry != NULL) {
+
+ TEXT_DeleteEntry(si.text_list, ScriptModule.dbg_txtentry);
+ ScriptModule.dbg_txtentry = NULL;
+ }
+
+ tl_e.color = 1;
+ tl_e.effect_color = 0;
+ tl_e.text_x = 2;
+ tl_e.text_y = 20;
+ tl_e.font_id = SMALL_FONT_ID;
+ tl_e.flags = FONT_OUTLINE;
+ tl_e.string = disp_buf;
+ tl_e.display = 1;
+
+ read_p = ScriptModule.current_script->bytecode->bytecode_p +
+ thread->i_offset;
+
+ start_p = read_p;
+
+ in_char = ys_read_u8(read_p, &read_p);
+
+ sprintf(tmp_buf, "%04lX | %02X | ", thread->i_offset, in_char);
+ strncat(disp_buf, tmp_buf, SD_DISPLAY_LEN);
+
+ switch (in_char) {
+
+ /* Align */
+ case 0x01:
+
+ SD_ADDTXT("ALGN |");
+ break;
+
+ /* Push nothing */
+ case 0x02:
+
+ SD_ADDTXT("PSHN |");
+ break;
+
+ /* Pop nothing */
+ case 0x03:
+
+ SD_ADDTXT("POPN |");
+ break;
+
+ /* Push false (0) */
+ case 0x04:
+
+ SD_ADDTXT("PSHF |");
+ break;
+
+ /* Push true (1) */
+ case 0x05:
+
+ SD_ADDTXT("PSHT |");
+ break;
+
+ /* Push word (dialogue string index) */
+ case 0x08:
+ {
+ int param;
+
+ SD_ADDTXT("PSHD | ");
+
+ param = ys_read_u16_le(read_p, &read_p);
+ sprintf(tmp_buf, "%02X", param);
+ SD_ADDTXT(tmp_buf);
+/*
+ if(( param >= 0 ) && ( param < diag_list->n_dialogue )) {
+ printf(" ; \"%.*s\"", R_SCRIPT_STRINGLIMIT, diag_list->str[param] );
+ }
+ else {
+ printf(" ; Invalid dialogue string.\n" );
+ }
+*/
+ }
+ break;
+
+ /* Push word */
+ case 0x06:
+ {
+ int param;
+
+ SD_ADDTXT("PUSH | ");
+ param = ys_read_u16_le(read_p, &read_p);
+ sprintf(tmp_buf, "%04X", param);
+ SD_ADDTXT(tmp_buf);
+ }
+ break;
+
+ /* Test flag */
+ case 0x0B:
+ {
+ int param1;
+ int param2;
+
+ SD_ADDTXT("TSTF | ");
+ param1 = *read_p++;
+ param2 = ys_read_u16_le(read_p, &read_p);
+
+ sprintf(tmp_buf, "%02X %04X", param1, param2);
+ SD_ADDTXT(tmp_buf);
+ }
+ break;
+
+ /* Get word */
+ case 0x0C:
+ {
+ int param1;
+ int param2;
+
+ SD_ADDTXT("GETW | ");
+ param1 = *read_p++;
+ param2 = ys_read_u16_le(read_p, &read_p);
+
+ sprintf(tmp_buf, "%02X %04X", param1, param2);
+ SD_ADDTXT(tmp_buf);
+ }
+ break;
+
+ /* Modify flag */
+ case 0x0F:
+ {
+ int param1;
+ int param2;
+
+ SD_ADDTXT("MODF | ");
+ param1 = *read_p++;
+ param2 = ys_read_u16_le(read_p, &read_p);
+
+ sprintf(tmp_buf, "%02X %04X", param1, param2);
+ SD_ADDTXT(tmp_buf);
+ }
+ break;
+
+ /* Put word */
+ case 0x10:
+ {
+ int param1;
+ int param2;
+
+ SD_ADDTXT("PUTW | ");
+ param1 = *read_p++;
+ param2 = ys_read_u16_le(read_p, &read_p);
+
+ sprintf(tmp_buf, "%02X %04X", param1, param2);
+ SD_ADDTXT(tmp_buf);
+ }
+ break;
+
+ /* Modify flag and pop */
+ case 0x13:
+ {
+ int param1;
+ int param2;
+
+ SD_ADDTXT("MDFP | ");
+ param1 = *read_p++;
+ param2 = ys_read_u16_le(read_p, &read_p);
+
+ sprintf(tmp_buf, "%02X %04X", param1, param2);
+ SD_ADDTXT(tmp_buf);
+ }
+ break;
+
+ /* Put word and pop */
+ case 0x14:
+ {
+ int param1;
+ int param2;
+
+ SD_ADDTXT("PTWP | ");
+ param1 = *read_p++;
+ param2 = ys_read_u16_le(read_p, &read_p);
+
+ sprintf(tmp_buf, "%02X %04X", param1, param2);
+ SD_ADDTXT(tmp_buf);
+ }
+ break;
+
+ /* Call subscript ? */
+ case 0x17:
+ {
+ int param1;
+ int param2;
+ int param3;
+
+ SD_ADDTXT("GOSB | ");
+ param1 = *read_p++;
+ param2 = *read_p++;
+ param3 = ys_read_u16_le(read_p, &read_p);
+
+ sprintf(tmp_buf, "%02X %02X %04X", param1, param2,
+ param3);
+ SD_ADDTXT(tmp_buf);
+ }
+ break;
+
+ /* Call function */
+ case 0x19:
+ case 0x18:
+ {
+ int func_num;
+ int param;
+
+ SD_ADDTXT("CALL | ");
+
+ func_num = *read_p++;
+ sprintf(tmp_buf, "%02X ", func_num);
+ SD_ADDTXT(tmp_buf);
+
+ param = ys_read_u16_le(read_p, &read_p);
+ sprintf(tmp_buf, "%04X ", param);
+ SD_ADDTXT(tmp_buf);
+ }
+ break;
+
+ /* Begin subscript */
+ case 0x1A:
+ {
+ int param;
+
+ SD_ADDTXT("ENTR | ");
+ param = ys_read_u16_le(read_p, &read_p);
+
+ 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 ) {
+ printf("; Entrypoint \"%s\".", script_list->scriptl_p +
+ script_list->scripts[i].name_offset );
+
+ break;
+ }
+ }
+*/
+ }
+ break;
+
+ case 0x1B:
+ SD_ADDTXT("??? ");
+ break;
+
+ /* End subscript */
+ case 0x1C:
+ SD_ADDTXT("EXIT |");
+ break;
+
+ /* Unconditional jump */
+ case 0x1D:
+ {
+ int param1;
+
+ SD_ADDTXT("JMP | ");
+ param1 = ys_read_u16_le(read_p, &read_p);
+
+ sprintf(tmp_buf, "%04X", param1);
+ SD_ADDTXT(tmp_buf);
+ }
+ break;
+
+ /* Jump if nonzero + POP */
+ case 0x1E:
+ {
+ int param1;
+
+ SD_ADDTXT("JNZP | ");
+ param1 = ys_read_u16_le(read_p, &read_p);
+
+ sprintf(tmp_buf, "%04X", param1);
+ SD_ADDTXT(tmp_buf);
+ }
+ break;
+
+ /* Jump if zero + POP */
+ case 0x1F:
+ {
+ int param1;
+
+ SD_ADDTXT("JZP | ");
+ param1 = ys_read_u16_le(read_p, &read_p);
+
+ sprintf(tmp_buf, "%04X", param1);
+ SD_ADDTXT(tmp_buf);
+ }
+ break;
+
+ /* Jump if nonzero */
+ case 0x20:
+ {
+ int param1;
+
+ SD_ADDTXT("JNZ | ");
+ param1 = ys_read_u16_le(read_p, &read_p);
+
+ sprintf(tmp_buf, "%04X", param1);
+ SD_ADDTXT(tmp_buf);
+ }
+ break;
+
+ /* Jump if zero */
+ case 0x21:
+ {
+ int param1;
+
+ SD_ADDTXT("JZ | ");
+ param1 = ys_read_u16_le(read_p, &read_p);
+
+ sprintf(tmp_buf, "%04X", param1);
+ SD_ADDTXT(tmp_buf);
+
+ }
+ break;
+
+ /* Switch */
+ case 0x22:
+ {
+ int switch_num;
+ int switch_jmp;
+ int default_jmp;
+
+ SD_ADDTXT("SWCH | ");
+ n_switch = ys_read_u16_le(read_p, &read_p);
+
+ sprintf(tmp_buf, "%02X\n", n_switch);
+ SD_ADDTXT(tmp_buf);
+
+ for (i = 0; i < n_switch; i++) {
+ switch_num = ys_read_u16_le(read_p, &read_p);
+ switch_jmp = ys_read_u16_le(read_p, &read_p);
+
+ /*
+ * printf( R_TAB "CASE %04X, %04X\n", switch_num, switch_jmp );
+ */
+ }
+
+ default_jmp = ys_read_u16_le(read_p, &read_p);
+
+ /*
+ * printf( R_TAB "DEF %04X", default_jmp );
+ */
+ }
+ break;
+
+ /* Random branch */
+ case 0x24:
+ {
+ int n_switch2;
+ int switch_num;
+ int switch_jmp;
+
+ SD_ADDTXT("RJMP | ");
+
+ /* Ignored? */
+ ys_read_u16_le(read_p, &read_p);
+
+ n_switch2 = ys_read_u16_le(read_p, &read_p);
+
+ sprintf(tmp_buf, "%04X", n_switch2);
+ SD_ADDTXT(tmp_buf);
+
+ for (i = 0; i < n_switch2; i++) {
+ /*printf("\n"); */
+ switch_num = ys_read_u16_le(read_p, &read_p);
+ switch_jmp = ys_read_u16_le(read_p, &read_p);
+ /*
+ * printf( R_TAB "WEIGHT %04X, %04X", switch_num, switch_jmp );
+ */
+ }
+ }
+ break;
+
+ case 0x25:
+ SD_ADDTXT("NEG |");
+ break;
+
+ case 0x26:
+ SD_ADDTXT("TSTZ |");
+ break;
+
+ case 0x27:
+ SD_ADDTXT("NOT |");
+ break;
+
+ case 0x28:
+ SD_ADDTXT("??? ");
+ read_p++;
+ ys_read_u16_le(read_p, &read_p);
+ break;
+
+ case 0x29:
+ SD_ADDTXT("??? ");
+ read_p++;
+ ys_read_u16_le(read_p, &read_p);
+ break;
+
+ case 0x2A:
+ SD_ADDTXT("??? ");
+ read_p++;
+ ys_read_u16_le(read_p, &read_p);
+ break;
+
+ case 0x2B:
+ SD_ADDTXT("??? ");
+ read_p++;
+ ys_read_u16_le(read_p, &read_p);
+ break;
+
+ /* Addition */
+ case 0x2C:
+ SD_ADDTXT("ADD |");
+ break;
+
+ /* Subtraction */
+ case 0x2D:
+ SD_ADDTXT("SUB |");
+ break;
+
+ /* Integer multiplication */
+ case 0x2E:
+ SD_ADDTXT("MULT |");
+ break;
+
+ /* Integer division */
+ case 0x2F:
+ SD_ADDTXT("DIV |");
+ break;
+
+ /* Modulus */
+ case 0x30:
+ SD_ADDTXT("MOD |");
+ break;
+
+ /* Test equality */
+ case 0x33:
+ SD_ADDTXT("EQU |");
+ break;
+
+ /* Test inequality */
+ case 0x34:
+ SD_ADDTXT("NEQU |");
+ break;
+
+ /* Test Greater-than */
+ case 0x35:
+ SD_ADDTXT("GRT |");
+ break;
+
+ /* Test Less-than */
+ case 0x36:
+ SD_ADDTXT("LST |");
+ break;
+
+ /* Test Greater-than or Equal to */
+ case 0x37:
+ SD_ADDTXT("GRTE |");
+ break;
+
+ /* Test Less-than or Equal to */
+ case 0x38:
+ SD_ADDTXT("LSTE |");
+ break;
+
+ case 0x3F:
+ SD_ADDTXT("SHR |");
+ break;
+
+ case 0x40:
+ SD_ADDTXT("SHL |");
+ break;
+
+ case 0x41:
+ SD_ADDTXT("AND |");
+ break;
+
+ case 0x42:
+ SD_ADDTXT("OR |");
+ break;
+
+ case 0x43:
+ SD_ADDTXT("XOR |");
+ break;
+
+ case 0x44:
+ SD_ADDTXT("LAND |");
+ break;
+
+ case 0x45:
+ SD_ADDTXT("LOR |");
+ break;
+
+ case 0x46:
+ SD_ADDTXT("LXOR |");
+ break;
+
+ case 0x53:
+ {
+ int n_voices;
+ int param1;
+ int param2;
+
+ SD_ADDTXT("DLGP | ");
+
+ n_voices = *read_p++;
+ param1 = ys_read_u16_le(read_p, &read_p);
+ param2 = *read_p++;
+
+ /* ignored ? */
+ ys_read_u16_le(read_p, &read_p);
+
+ sprintf(tmp_buf, "%02X %04X %02X", n_voices, param1,
+ param2);
+ SD_ADDTXT(tmp_buf);
+ }
+ break;
+
+ case 0x54:
+ SD_ADDTXT("DLGS |");
+ break;
+
+ case 0x55:
+ SD_ADDTXT("DLGX |");
+ break;
+
+ case 0x56:
+ {
+ int param1;
+ int param2;
+ int param3;
+
+ SD_ADDTXT("DLGO | ");
+ param1 = *read_p++;
+ param2 = *read_p++;
+
+ sprintf(tmp_buf, "%02X %02X ", param1, param2);
+ SD_ADDTXT(tmp_buf);
+
+ if (param2 > 0) {
+ param3 = ys_read_u16_le(read_p, &read_p);
+
+ sprintf(tmp_buf, "%04X", param3);
+ SD_ADDTXT(tmp_buf);
+ }
+ }
+ break;
+
+ case 0x57:
+ {
+ int param1;
+ int param2;
+ int param3;
+
+ SD_ADDTXT("JMPS | ");
+
+ param1 = ys_read_u16_le(read_p, &read_p);
+ param2 = ys_read_u16_le(read_p, &read_p);
+ param3 = *read_p++;
+
+ sprintf(tmp_buf, "%04X %04X %02X", param1, param2,
+ param3);
+ SD_ADDTXT(tmp_buf);
+ }
+ break;
+
+ default:
+ sprintf(tmp_buf, "Invalid opcode.\n");
+ SD_ADDTXT(tmp_buf);
+ break;
+
+ } /* end switch( in_char ) */
+
+ ScriptModule.dbg_txtentry = TEXT_AddEntry(si.text_list, &tl_e);
+ TEXT_SetDisplay(ScriptModule.dbg_txtentry, 1);
+
+ return R_SUCCESS;
+}
+
+} // End of namespace Saga
diff --git a/saga/sfuncs.cpp b/saga/sfuncs.cpp
new file mode 100644
index 0000000000..782fa56878
--- /dev/null
+++ b/saga/sfuncs.cpp
@@ -0,0 +1,811 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ Scripting module script function component
+
+ Notes:
+*/
+
+#include "reinherit.h"
+
+#include "yslib.h"
+
+/*
+ * Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "actor_mod.h"
+#include "animation_mod.h"
+#include "console_mod.h"
+#include "interface_mod.h"
+#include "text_mod.h"
+
+/*
+\*--------------------------------------------------------------------------*/
+#include "script.h"
+#include "sfuncs.h"
+
+namespace Saga {
+
+R_SFUNC_ENTRY SFuncList[R_SFUNC_NUM] = {
+
+ {0, 0, NULL}
+ ,
+ {1, 1, SF_Sleep}
+ ,
+ {2, 0, NULL}
+ ,
+ {3, 1, SF_3}
+ ,
+ {4, 1, SF_SetCommandText}
+ ,
+ {5, 0, NULL}
+ ,
+ {6, 3, SF_ActorWalkTo}
+ ,
+ {7, 0, NULL}
+ ,
+ {8, 2, SF_SetActorOrient}
+ ,
+ {9, 0, NULL}
+ ,
+ {10, 0, NULL}
+ ,
+ {11, 1, SF_FreezeInterface}
+ ,
+ {12, 0, NULL}
+ ,
+ {13, 0, NULL}
+ ,
+ {14, 0, NULL}
+ ,
+ {15, 0, NULL}
+ ,
+ {16, 0, NULL}
+ ,
+ {17, 0, NULL}
+ ,
+ {18, 0, NULL}
+ ,
+ {19, 0, NULL}
+ ,
+ {20, 0, NULL}
+ ,
+ {21, 0, NULL}
+ ,
+ {22, 0, NULL}
+ ,
+ {23, 0, NULL}
+ ,
+ {24, 0, NULL}
+ ,
+ {25, 0, NULL}
+ ,
+ {26, 3, SF_StartAnim}
+ ,
+ {27, 3, SF_ActorWalkToAsync}
+ ,
+ {28, 0, NULL}
+ ,
+ {29, 0, NULL}
+ ,
+ {30, 3, SF_PlaceActor}
+ ,
+ {31, 0, NULL}
+ ,
+ {32, 0, NULL}
+ ,
+ {33, 0, NULL}
+ ,
+ {34, 0, NULL}
+ ,
+ {35, 0, NULL}
+ ,
+ {36, 4, SF_ActorWalkTo2}
+ ,
+ {37, 4, SF_SetActorAct}
+ ,
+ {38, 3, SF_SetActorAct2}
+ ,
+ {39, 0, NULL}
+ ,
+ {40, 0, NULL}
+ ,
+ {41, 4, SF_LinkAnim}
+ ,
+ {42, 0, NULL}
+ ,
+ {43, 6, SF_PlaceActorEx}
+ ,
+ {44, 0, SF_CheckUserInterrupt}
+ ,
+ {45, 0, NULL}
+ ,
+ {46, 0, NULL}
+ ,
+ {47, 0, NULL}
+ ,
+ {48, 0, NULL}
+ ,
+ {49, 0, NULL}
+ ,
+ {50, 0, NULL}
+ ,
+ {51, 0, NULL}
+ ,
+ {52, 0, NULL}
+ ,
+ {53, 0, NULL}
+ ,
+ {54, 0, NULL}
+ ,
+ {55, 0, NULL}
+ ,
+ {56, 0, NULL}
+ ,
+ {57, 0, NULL}
+ ,
+ {58, 0, NULL}
+ ,
+ {59, 0, NULL}
+ ,
+ {60, 0, NULL}
+ ,
+ {61, 0, NULL}
+ ,
+ {62, 0, NULL}
+ ,
+ {63, 0, NULL}
+ ,
+ {64, 0, NULL}
+ ,
+ {65, 0, NULL}
+ ,
+ {66, 0, NULL}
+ ,
+ {67, 0, NULL}
+ ,
+ {68, 0, NULL}
+ ,
+ {69, 0, NULL}
+ ,
+ {70, 0, NULL}
+ ,
+ {71, 0, NULL}
+ ,
+ {72, 0, NULL}
+ ,
+ {73, 0, NULL}
+ ,
+ {74, 0, NULL}
+ ,
+ {75, 0, NULL}
+ ,
+ {76, 0, NULL}
+ ,
+ {77, 0, NULL}
+};
+
+int SF_Sleep(R_SCRIPTFUNC_PARAMS)
+/*--------------------------------------------------------------------------*\
+ *
+ * Script function #1 (0x01) blocking
+ *
+ * Suspends thread execution for the specified time period
+ *
+ * Param1: time to suspend ( units? )
+ *
+\*--------------------------------------------------------------------------*/
+{
+ SDataWord_T time_param;
+
+ int time;
+
+ SSTACK_Pop(thread->stack, &time_param);
+
+ time = SDATA_ReadWordU(time_param);
+
+ thread->sleep_time = time * 10;
+
+ return R_SUCCESS;
+}
+
+int SF_3(R_SCRIPTFUNC_PARAMS)
+/*--------------------------------------------------------------------------*\
+ *
+ * Script function #3 (0x03)
+ *
+ * Unknown function; pops a parameter and pushes a return value
+ *
+ * Param1: unknown
+ *
+\*--------------------------------------------------------------------------*/
+{
+ /* INCOMPLETE */
+
+ SDataWord_T param1;
+
+ SSTACK_Pop(thread->stack, &param1);
+
+ SSTACK_Push(thread->stack, 0); /* push for now to allow intro faire
+ * setup to run completely */
+
+ return R_SUCCESS;
+}
+
+int SF_SetCommandText(R_SCRIPTFUNC_PARAMS)
+/*--------------------------------------------------------------------------*\
+ *
+ * Script function #4 (0x04) nonblocking
+ *
+ * Set the command display to the specified text string
+ *
+ * Param1: dialogue index of string
+ *
+\*--------------------------------------------------------------------------*/
+{
+ SDataWord_T s_idx_parm;
+
+ SSTACK_Pop(thread->stack, &s_idx_parm);
+
+ /* INCOMPLETE */
+
+ return R_SUCCESS;
+}
+
+int SF_ActorWalkTo(R_SCRIPTFUNC_PARAMS)
+/*--------------------------------------------------------------------------*\
+ *
+ * Script function #6 (0x06) blocking
+ *
+ * Commands the specified actor to walk to the given position
+ *
+ * Param1: actor id
+ * Param2: actor destination x
+ * Param3: actor destination y
+ *
+\*--------------------------------------------------------------------------*/
+{
+ SDataWord_T actor_parm;
+
+ SDataWord_T x_parm;
+ SDataWord_T y_parm;
+
+ int actor_id;
+ int actor_idx;
+
+ R_POINT pt;
+
+ SSTACK_Pop(thread->stack, &actor_parm);
+
+ SSTACK_Pop(thread->stack, &x_parm);
+ SSTACK_Pop(thread->stack, &y_parm);
+
+ actor_id = SDATA_ReadWordS(actor_parm);
+
+ actor_idx = ACTOR_GetActorIndex(actor_id);
+ if (actor_idx < 0) {
+ CON_Print(S_WARN_PREFIX "SF.08: Actor id 0x%X not found.",
+ actor_id);
+ return R_FAILURE;
+ }
+
+ pt.x = SDATA_ReadWordS(x_parm);
+ pt.y = SDATA_ReadWordS(y_parm);
+
+ ACTOR_WalkTo(actor_idx, &pt, 0, &thread->sem);
+
+ return R_SUCCESS;
+}
+
+int SF_SetActorOrient(R_SCRIPTFUNC_PARAMS)
+/*--------------------------------------------------------------------------*\
+ *
+ * Script function #8 (0x08) nonblocking
+ *
+ * Sets the orientation of the specified actor.
+ *
+ * Param1: actor id
+ * Param2: actor orientation
+ *
+\*--------------------------------------------------------------------------*/
+{
+ SDataWord_T actor_parm;
+ SDataWord_T orient_parm;
+
+ int actor_id;
+ int actor_idx;
+ int orientation;
+
+ SSTACK_Pop(thread->stack, &actor_parm);
+ SSTACK_Pop(thread->stack, &orient_parm);
+
+ actor_id = SDATA_ReadWordS(actor_parm);
+ orientation = SDATA_ReadWordS(orient_parm);
+
+ actor_idx = ACTOR_GetActorIndex(actor_id);
+ if (actor_idx < 0) {
+ CON_Print(S_WARN_PREFIX "SF.08: Actor id 0x%X not found.",
+ actor_id);
+
+ return R_FAILURE;
+ }
+
+ ACTOR_SetOrientation(actor_idx, orientation);
+ return R_SUCCESS;
+}
+
+int SF_FreezeInterface(R_SCRIPTFUNC_PARAMS)
+/*--------------------------------------------------------------------------*\
+ *
+ * Script function #11 (0x0B) nonblocking
+ *
+ * If the parameter is true, the user interface is disabled while script
+ * continues to run. If the parameter is false, the user interface is
+ * reenabled.
+ *
+ * Param1: boolean
+ *
+\*--------------------------------------------------------------------------*/
+{
+ SDataWord_T b_param;
+
+ SSTACK_Pop(thread->stack, &b_param);
+
+ if (b_param) {
+ INTERFACE_Deactivate();
+ } else {
+ INTERFACE_Activate();
+ }
+
+ return R_SUCCESS;
+}
+
+int SF_StartAnim(R_SCRIPTFUNC_PARAMS)
+/*--------------------------------------------------------------------------*\
+ *
+ * Script function #26 (0x1A) nonblocking
+ *
+ * Starts the specified animation
+ *
+ * Param1: ?
+ * Param2: frames of animation to play or -1 to loop
+ * Param3: animation id
+ *
+\*--------------------------------------------------------------------------*/
+{
+ SDataWord_T unk_parm;
+ SDataWord_T frame_parm;
+ SDataWord_T anim_id_parm;
+
+ int frame_count;
+ int anim_id;
+
+ SSTACK_Pop(thread->stack, &anim_id_parm);
+ SSTACK_Pop(thread->stack, &frame_parm);
+ SSTACK_Pop(thread->stack, &unk_parm);
+
+ frame_count = SDATA_ReadWordS(frame_parm);
+ anim_id = SDATA_ReadWordS(anim_id_parm);
+
+ if (ANIM_Play(anim_id, 0) != R_SUCCESS) {
+
+ CON_Print(S_WARN_PREFIX
+ "SF.26: ANIM_Play() failed. Anim id: %u\n", anim_id);
+
+ return R_FAILURE;
+ }
+
+ return R_SUCCESS;
+}
+
+int SF_ActorWalkToAsync(R_SCRIPTFUNC_PARAMS)
+/*--------------------------------------------------------------------------*\
+ *
+ * Script function #27 (0x1B) nonblocking
+ *
+ * Commands the specified actor to walk to the given position
+ *
+ * Param1: actor id
+ * Param2: actor destination x
+ * Param3: actor destination y
+ *
+\*--------------------------------------------------------------------------*/
+{
+ SDataWord_T actor_parm;
+
+ SDataWord_T x_parm;
+ SDataWord_T y_parm;
+
+ int actor_id;
+ int actor_idx;
+
+ R_POINT pt;
+
+ SSTACK_Pop(thread->stack, &actor_parm);
+
+ SSTACK_Pop(thread->stack, &x_parm);
+ SSTACK_Pop(thread->stack, &y_parm);
+
+ actor_id = SDATA_ReadWordS(actor_parm);
+
+ actor_idx = ACTOR_GetActorIndex(actor_id);
+ if (actor_idx < 0) {
+ CON_Print(S_WARN_PREFIX "SF.08: Actor id 0x%X not found.",
+ actor_id);
+ return R_FAILURE;
+ }
+
+ pt.x = SDATA_ReadWordS(x_parm);
+ pt.y = SDATA_ReadWordS(y_parm);
+
+ ACTOR_WalkTo(actor_idx, &pt, 0, NULL);
+
+ return R_SUCCESS;
+}
+
+int SF_PlaceActor(R_SCRIPTFUNC_PARAMS)
+/*--------------------------------------------------------------------------*\
+ *
+ * Script function #30 (0x1E) nonblocking
+ *
+ * Positions an actor at the specified location; actor is created if the
+ * actor does not already exist.
+ *
+ * Param1: actor id
+ * Param2: actor pos x
+ * Param3: actor pos y
+ *
+\*--------------------------------------------------------------------------*/
+{
+ SDataWord_T actor_parm;
+
+ SDataWord_T x_parm;
+ SDataWord_T y_parm;
+
+ int actor_id;
+ int actor_idx;
+ int result;
+
+ R_POINT pt;
+
+ SSTACK_Pop(thread->stack, &actor_parm);
+
+ SSTACK_Pop(thread->stack, &x_parm);
+ SSTACK_Pop(thread->stack, &y_parm);
+
+ actor_id = SDATA_ReadWordS(actor_parm);
+
+ pt.x = SDATA_ReadWordS(x_parm);
+ pt.y = SDATA_ReadWordS(y_parm);
+
+ if (!ACTOR_ActorExists(actor_id)) {
+
+ result = ACTOR_Create(actor_id, pt.x, pt.y);
+
+ if (result != R_SUCCESS) {
+
+ CON_Print(S_WARN_PREFIX
+ "SF.30: Couldn't create actor 0x%X.", actor_id);
+ return R_FAILURE;
+ }
+ } else {
+
+ actor_idx = ACTOR_GetActorIndex(actor_id);
+
+ ACTOR_Move(actor_idx, &pt);
+ }
+
+ return R_SUCCESS;
+}
+
+int SF_ActorWalkTo2(R_SCRIPTFUNC_PARAMS)
+/*--------------------------------------------------------------------------*\
+ *
+ * Script function #36 (0x24) ?
+ *
+ * Commands the specified actor to walk to the given position
+ *
+ * Param1: actor id
+ * Param2: actor destination x
+ * Param3: actor destination y
+ * Param4: unknown
+ *
+\*--------------------------------------------------------------------------*/
+{
+ /* INCOMPLETE */
+
+ SDataWord_T actor_parm;
+
+ SDataWord_T x_parm;
+ SDataWord_T y_parm;
+ SDataWord_T unk_parm;
+
+ int actor_idx;
+
+ R_POINT pt;
+
+ SSTACK_Pop(thread->stack, &actor_parm);
+
+ SSTACK_Pop(thread->stack, &x_parm);
+ SSTACK_Pop(thread->stack, &y_parm);
+ SSTACK_Pop(thread->stack, &unk_parm);
+
+ actor_idx = ACTOR_GetActorIndex(SDATA_ReadWordS(actor_parm));
+ if (actor_idx < 0) {
+ CON_Print(S_WARN_PREFIX "SF.36: Actor id 0x%X not found.",
+ (int)actor_parm);
+ return R_FAILURE;
+ }
+
+ pt.x = SDATA_ReadWordS(x_parm);
+ pt.y = SDATA_ReadWordS(y_parm);
+
+#if 1
+ ACTOR_WalkTo(actor_idx, &pt, 0, NULL);
+#else
+ ACTOR_WalkTo(actor_idx, &pt, 0, &thread->sem);
+#endif
+
+ return R_SUCCESS;
+}
+
+int SF_SetActorAct(R_SCRIPTFUNC_PARAMS)
+/*--------------------------------------------------------------------------*\
+ *
+ * Script function #37 (0x25) nonblocking
+ *
+ * Sets an actor to the specified action state
+ *
+ * Param1: actor id
+ * Param2: unknown
+ * Param3: actor action state
+ * Param4: unknown
+ *
+\*--------------------------------------------------------------------------*/
+{
+ /* INCOMPLETE */
+
+ SDataWord_T actor_parm;
+
+ SDataWord_T unk1_parm;
+ SDataWord_T unk2_parm;
+ SDataWord_T action_parm;
+
+ int actor_id;
+ int actor_idx;
+
+ int action;
+ /*uint flags; */
+
+ SSTACK_Pop(thread->stack, &actor_parm);
+
+ SSTACK_Pop(thread->stack, &unk1_parm);
+ SSTACK_Pop(thread->stack, &action_parm);
+ SSTACK_Pop(thread->stack, &unk2_parm);
+
+ actor_id = SDATA_ReadWordS(actor_parm);
+ action = SDATA_ReadWordS(action_parm);
+
+ actor_idx = ACTOR_GetActorIndex(actor_id);
+
+ if (ACTOR_SetAction(actor_idx, action, ACTION_NONE) != R_SUCCESS) {
+ CON_Print(S_WARN_PREFIX "SF.37: ACTOR_SetAction() failed.");
+
+ return R_FAILURE;
+ }
+
+ return R_SUCCESS;
+}
+
+int SF_SetActorAct2(R_SCRIPTFUNC_PARAMS)
+/*--------------------------------------------------------------------------*\
+ *
+ * Script function #38 (0x26) nonblocking
+ *
+ * Sets an actor to the specified action state
+ *
+ * Param1: actor id
+ * Param2: actor action state
+ * Param3: unknown
+ *
+\*--------------------------------------------------------------------------*/
+{
+ /* INCOMPLETE */
+
+ SDataWord_T actor_parm;
+
+ SDataWord_T unk1_parm;
+ SDataWord_T action_parm;
+
+ int actor_id;
+ int actor_idx;
+
+ int action;
+ /*uint flags; */
+
+ SSTACK_Pop(thread->stack, &actor_parm);
+
+ SSTACK_Pop(thread->stack, &action_parm);
+ SSTACK_Pop(thread->stack, &unk1_parm);
+
+ actor_id = SDATA_ReadWordS(actor_parm);
+ action = SDATA_ReadWordS(action_parm);
+
+ actor_idx = ACTOR_GetActorIndex(actor_id);
+
+ if (ACTOR_SetAction(actor_idx, action, ACTION_NONE) != R_SUCCESS) {
+ CON_Print(S_WARN_PREFIX "SF.38: ACTOR_SetAction() failed.");
+
+ return R_FAILURE;
+ }
+
+ return R_SUCCESS;
+}
+
+int SF_LinkAnim(R_SCRIPTFUNC_PARAMS)
+/*--------------------------------------------------------------------------*\
+ *
+ * Script function #41 (0x29) nonblocking
+ *
+ * Links the specified animations for playback
+ *
+ * Param1: ?
+ * Param2: total linked frame count
+ * Param3: animation id link target
+ * Param4: animation id link source
+ *
+\*--------------------------------------------------------------------------*/
+{
+ SDataWord_T unk_parm;
+
+ SDataWord_T tframes_parm;
+ SDataWord_T anim1_parm;
+ SDataWord_T anim2_parm;
+
+ int tframes;
+
+ uint anim_id1;
+ uint anim_id2;
+
+ SSTACK_Pop(thread->stack, &anim1_parm);
+ SSTACK_Pop(thread->stack, &anim2_parm);
+
+ SSTACK_Pop(thread->stack, &tframes_parm);
+ SSTACK_Pop(thread->stack, &unk_parm);
+
+ tframes = SDATA_ReadWordS(tframes_parm);
+
+ anim_id1 = SDATA_ReadWordU(anim1_parm);
+ anim_id2 = SDATA_ReadWordU(anim2_parm);
+
+ if (ANIM_Link(anim_id1, anim_id2) != R_SUCCESS) {
+
+ CON_Print(S_WARN_PREFIX
+ "SF.41: ANIM_Link() failed. (%u->%u)\n", anim_id1,
+ anim_id2);
+
+ return R_FAILURE;
+ }
+
+ return R_SUCCESS;
+}
+
+int SF_PlaceActorEx(R_SCRIPTFUNC_PARAMS)
+/*--------------------------------------------------------------------------*\
+ *
+ * Script function #43 (0x2B) nonblocking
+ *
+ * Positions an actor at the specified location; actor is created if the
+ * actor does not already exist.
+ *
+ * Param1: actor id
+ * Param2: actor pos x
+ * Param3: actor pos y
+ * Param4: ?
+ * Param5: actor action
+ * Param6: ?
+ *
+\*--------------------------------------------------------------------------*/
+{
+ /* INCOMPLETE */
+
+ SDataWord_T actor_parm;
+
+ SDataWord_T x_parm;
+ SDataWord_T y_parm;
+
+ SDataWord_T action_parm;
+
+ SDataWord_T unknown_parm;
+
+ int actor_id;
+ int actor_idx;
+ int action_state;
+ int result;
+
+ R_POINT pt;
+
+ SSTACK_Pop(thread->stack, &actor_parm);
+
+ SSTACK_Pop(thread->stack, &x_parm);
+ SSTACK_Pop(thread->stack, &y_parm);
+
+ SSTACK_Pop(thread->stack, &unknown_parm);
+ SSTACK_Pop(thread->stack, &action_parm);
+ SSTACK_Pop(thread->stack, &unknown_parm);
+
+ actor_id = SDATA_ReadWordS(actor_parm);
+
+ pt.x = SDATA_ReadWordS(x_parm);
+ pt.y = SDATA_ReadWordS(y_parm);
+
+ action_state = SDATA_ReadWordU(action_parm);
+
+ if (!ACTOR_ActorExists(actor_id)) {
+
+ result = ACTOR_Create(actor_id, pt.x, pt.y);
+
+ if (result != R_SUCCESS) {
+
+ CON_Print(S_WARN_PREFIX
+ "SF.43: Couldn't create actor 0x%X.", actor_id);
+
+ return R_FAILURE;
+ }
+ } else {
+
+ actor_idx = ACTOR_GetActorIndex(actor_id);
+
+ ACTOR_Move(actor_idx, &pt);
+ }
+
+ actor_idx = ACTOR_GetActorIndex(actor_id);
+
+ ACTOR_SetDefaultAction(actor_idx, action_state, ACTION_NONE);
+ ACTOR_SetAction(actor_idx, action_state, ACTION_NONE);
+
+ return R_SUCCESS;
+}
+
+int SF_CheckUserInterrupt(R_SCRIPTFUNC_PARAMS)
+/*--------------------------------------------------------------------------*\
+ *
+ * Script function #44 (0x2C) nonblocking
+ *
+ * Checks to see if the user has interrupted a currently playing
+ * game cinematic. Pushes a zero or positive value if the game
+ * has not been interrupted.
+ *
+\*--------------------------------------------------------------------------*/
+{
+ SSTACK_Push(thread->stack, 0);
+
+ /* INCOMPLETE */
+
+ return R_SUCCESS;
+}
+
+} // End of namespace Saga
diff --git a/saga/sfuncs.h b/saga/sfuncs.h
new file mode 100644
index 0000000000..75d7339420
--- /dev/null
+++ b/saga/sfuncs.h
@@ -0,0 +1,103 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ Scripting module script function component header file
+
+ Notes:
+*/
+
+#ifndef SAGA_SFUNCS_H
+#define SAGA_SFUNCS_H
+
+#include "sthread.h"
+
+namespace Saga {
+
+#define R_SFUNC_NUM 78
+
+
+#define R_SCRIPTFUNC_PARAMS R_SCRIPT_THREAD * thread
+
+typedef int (*SFunc_T) (R_SCRIPTFUNC_PARAMS);
+
+typedef struct R_SFUNC_ENTRY_tag {
+
+ int sfunc_num;
+ int sfunc_argc;
+ SFunc_T sfunc_fp;
+
+} R_SFUNC_ENTRY;
+
+extern R_SFUNC_ENTRY SFuncList[];
+
+/* SF 1 */
+int SF_Sleep(R_SCRIPTFUNC_PARAMS);
+
+/* SF 3 */
+int SF_3(R_SCRIPTFUNC_PARAMS);
+
+/* SF 4 */
+int SF_SetCommandText(R_SCRIPTFUNC_PARAMS);
+
+/* SF 6 */
+int SF_ActorWalkTo(R_SCRIPTFUNC_PARAMS);
+
+/* SF 8 */
+int SF_SetActorOrient(R_SCRIPTFUNC_PARAMS);
+
+/* SF 11 */
+int SF_FreezeInterface(R_SCRIPTFUNC_PARAMS);
+
+/* SF 26 */
+int SF_StartAnim(R_SCRIPTFUNC_PARAMS);
+
+/* SF 27 */
+int SF_ActorWalkToAsync(R_SCRIPTFUNC_PARAMS);
+
+/* SF 30 */
+int SF_PlaceActor(R_SCRIPTFUNC_PARAMS);
+
+/* SF 36 */
+int SF_ActorWalkTo2(R_SCRIPTFUNC_PARAMS);
+
+/* SF 37 */
+int SF_SetActorAct(R_SCRIPTFUNC_PARAMS);
+
+/* SF 38 */
+int SF_SetActorAct2(R_SCRIPTFUNC_PARAMS);
+
+/* SF 41 */
+int SF_LinkAnim(R_SCRIPTFUNC_PARAMS);
+
+/* SF 43 */
+int SF_PlaceActorEx(R_SCRIPTFUNC_PARAMS);
+
+/* SF 44 */
+int SF_CheckUserInterrupt(R_SCRIPTFUNC_PARAMS);
+
+} // End of namespace Saga
+
+#endif /* SAGA_SFUNCS_H */
diff --git a/saga/sndres.cpp b/saga/sndres.cpp
new file mode 100644
index 0000000000..3592095578
--- /dev/null
+++ b/saga/sndres.cpp
@@ -0,0 +1,353 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Sound resource management module
+
+ Notes:
+*/
+
+#include "reinherit.h"
+
+#include "yslib.h"
+
+#include <limits.h>
+
+/*
+ * Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "game_mod.h"
+#include "rscfile_mod.h"
+
+/*
+ * Begin module component
+\*--------------------------------------------------------------------------*/
+#include "sndres_mod.h"
+#include "sndres.h"
+
+namespace Saga {
+
+R_SNDRES_MODULE SndModule;
+
+int SND_Init(void)
+{
+ int result;
+
+ /* Load sound module resource file contexts
+ * \*------------------------------------------------------------- */
+ result = GAME_GetFileContext(&SndModule.sfx_ctxt, R_GAME_SOUNDFILE, 0);
+ if (result != R_SUCCESS) {
+ return R_FAILURE;
+ }
+
+ result = GAME_GetFileContext(&SndModule.voice_ctxt,
+ R_GAME_VOICEFILE, 0);
+ if (result != R_SUCCESS) {
+ return R_FAILURE;
+ }
+
+ /* Grab sound resource information for the current game
+ * \*------------------------------------------------------------- */
+ GAME_GetSoundInfo(&SndModule.snd_info);
+
+ SndModule.init = 1;
+
+ return R_SUCCESS;
+}
+
+int SND_PlayVoice(ulong voice_rn)
+{
+ R_SOUNDBUFFER snd_buffer;
+ int result;
+
+ result = SND_Load(SndModule.voice_ctxt, voice_rn, &snd_buffer);
+ if (result != R_SUCCESS) {
+ return R_FAILURE;
+ }
+
+ SYSSOUND_PlayVoice(&snd_buffer);
+
+ return R_SUCCESS;
+}
+
+int
+SND_Load(R_RSCFILE_CONTEXT * snd_ctxt, ulong snd_rn, R_SOUNDBUFFER * snd_buf_i)
+{
+
+ uchar *snd_res;
+ size_t snd_res_len;
+
+ int result;
+
+ assert((snd_ctxt != NULL) && (snd_buf_i != NULL));
+
+ result = RSC_LoadResource(snd_ctxt, snd_rn, &snd_res, &snd_res_len);
+ if (result != R_SUCCESS) {
+ return R_FAILURE;
+ }
+
+ switch (SndModule.snd_info.res_type) {
+
+ case R_GAME_SOUND_PCM:
+
+ snd_buf_i->s_freq = SndModule.snd_info.freq;
+ snd_buf_i->s_samplebits = SndModule.snd_info.sample_size;
+ snd_buf_i->s_stereo = SndModule.snd_info.stereo;
+
+ snd_buf_i->res_data = snd_res;
+ snd_buf_i->res_len = snd_res_len;
+
+ snd_buf_i->s_buf = snd_res;
+ snd_buf_i->s_buf_len = snd_res_len;
+
+ snd_buf_i->s_signed = 1;
+
+ break;
+
+ case R_GAME_SOUND_VOC:
+
+ if (LoadVocSound(snd_res, snd_res_len, snd_buf_i) != R_SUCCESS) {
+
+ RSC_FreeResource(snd_res);
+
+ return R_FAILURE;
+ }
+
+ break;
+
+ default:
+ /* Unknown sound type */
+
+ RSC_FreeResource(snd_res);
+
+ return R_FAILURE;
+ break;
+ }
+
+ return R_SUCCESS;
+}
+
+int
+LoadVocSound(const uchar * snd_res,
+ size_t snd_res_len, R_SOUNDBUFFER * snd_buf_i)
+{
+
+ R_VOC_HEADER_BLOCK voc_hb;
+ R_VOC_GENBLOCK voc_gb;
+ R_VOC_BLOCK1 voc_b1;
+
+ long byte_rate;
+
+ const uchar *read_p;
+ size_t read_len;
+
+ read_p = snd_res;
+ read_len = snd_res_len;
+
+ if (read_len < R_VOC_HEADER_BLOCK_LEN) {
+ return R_FAILURE;
+ }
+
+ memcpy(voc_hb.ft_desc, read_p, R_VOC_FILE_DESC_LEN);
+ read_p += R_VOC_FILE_DESC_LEN;
+ read_len -= R_VOC_FILE_DESC_LEN;
+
+ if (memcmp(voc_hb.ft_desc, R_VOC_FILE_DESC, R_VOC_FILE_DESC_LEN) != 0) {
+
+ /* Voc file desc string not found */
+ return R_FAILURE;
+ }
+
+ voc_hb.db_offset = ys_read_u16_le(read_p, &read_p);
+ voc_hb.voc_version = ys_read_u16_le(read_p, &read_p);
+ voc_hb.voc_fileid = ys_read_u16_le(read_p, &read_p);
+
+ if (read_len < voc_hb.db_offset + R_VOC_GENBLOCK_LEN) {
+
+ return R_FAILURE;
+ }
+
+ read_p = snd_res + voc_hb.db_offset;
+ read_len = snd_res_len - voc_hb.db_offset;
+
+ for (;;) {
+
+ /* Read generic block header
+ * \*--------------------------------------------------------- */
+ if (read_len < R_VOC_GENBLOCK_LEN) {
+ return R_FAILURE;
+ }
+
+ voc_gb.block_id = ys_read_u8(read_p, &read_p);
+ if (voc_gb.block_id == 0) {
+ return R_FAILURE;
+ }
+
+ voc_gb.block_len = ys_read_u24_le(read_p, &read_p);
+
+ read_len -= R_VOC_GENBLOCK_LEN;
+
+ /* Process block
+ * \*--------------------------------------------------------- */
+ switch (voc_gb.block_id) {
+
+ case 1: /* Sound data block */
+
+ voc_b1.time_constant = ys_read_u8(read_p, &read_p);
+ voc_b1.pack_method = ys_read_u8(read_p, &read_p);
+ read_len -= 2;
+
+ if (voc_b1.pack_method != 0) {
+ /* Packed VOC files not supported */
+ return R_FAILURE;
+ }
+
+ byte_rate = R_VOC_TIME_BASE / (R_VOC_TIME_CBASE -
+ (voc_b1.time_constant << 8));
+
+ snd_buf_i->s_stereo = 0;
+ snd_buf_i->s_samplebits = 8;
+ snd_buf_i->s_freq = byte_rate;
+
+ snd_buf_i->res_data = (uchar *) snd_res;
+ snd_buf_i->res_len = snd_res_len;
+
+ snd_buf_i->s_buf = (uchar *) read_p;
+ snd_buf_i->s_buf_len = read_len - 1; /* -1 for end block */
+
+ snd_buf_i->s_signed = 0;
+
+ return R_SUCCESS;
+
+ break;
+
+ default:
+
+ read_p += voc_gb.block_len;
+ read_len -= voc_gb.block_len;
+ break;
+ }
+ }
+
+ return R_SUCCESS;
+}
+
+int SND_GetVoiceLength(ulong voice_rn)
+{
+
+ ulong length;
+
+ double ms_f;
+ int ms_i = -1;
+
+ int result;
+
+ assert(SndModule.init);
+
+ result = RSC_GetResourceSize(SndModule.voice_ctxt, voice_rn, &length);
+ if (result != R_SUCCESS) {
+ return -1;
+ }
+
+ if (SndModule.snd_info.res_type == R_GAME_SOUND_PCM) {
+
+ ms_f = (double)length /
+ (SndModule.snd_info.sample_size / CHAR_BIT) /
+ (SndModule.snd_info.freq) * 1000.0;
+
+ ms_i = (int)ms_f;
+ } else if (SndModule.snd_info.res_type == R_GAME_SOUND_VOC) {
+
+ /* Rough hack, fix this to be accurate */
+
+ ms_f = (double)length / 14705 * 1000.0;
+ ms_i = (int)ms_f;
+ } else {
+ return -1;
+ }
+
+ return ms_i;
+}
+
+int
+SND_ITEVOC_Resample(long src_freq,
+ long dst_freq,
+ uchar * src_buf,
+ size_t src_buf_len, uchar ** dst_buf, size_t * dst_buf_len)
+{
+ uchar *resamp_buf;
+ size_t resamp_len;
+
+ uchar src_samp_a;
+ uchar src_samp_b;
+
+ const uchar *read_pa;
+ const uchar *read_pb;
+
+ uchar *write_pa;
+ uchar *write_pb;
+ uchar *write_pc;
+
+ size_t src_i;
+
+ assert(src_freq == 14705);
+ assert(dst_freq == 22050);
+
+ resamp_len = (size_t) (src_buf_len * 1.5);
+ resamp_buf = (uchar *)malloc(resamp_len);
+ if (resamp_buf == NULL) {
+ return R_FAILURE;
+ }
+
+ read_pa = src_buf;
+ read_pb = src_buf + 1;
+
+ write_pa = resamp_buf;
+ write_pb = resamp_buf + 1;
+ write_pc = resamp_buf + 2;
+
+ for (src_i = 0; src_i < src_buf_len / 2; src_i++) {
+
+ src_samp_a = *read_pa;
+ src_samp_b = *read_pb;
+
+ read_pa += 2;
+ read_pb += 2;
+
+ *write_pa = src_samp_a;
+ *write_pb = (uchar) ((src_samp_a / 2) + (src_samp_b / 2));
+ *write_pc = src_samp_b;
+
+ write_pa += 3;
+ write_pb += 3;
+ write_pc += 3;
+ }
+
+ *dst_buf = resamp_buf;
+ *dst_buf_len = resamp_len;
+
+ return R_SUCCESS;
+}
+
+} // End of namespace Saga
diff --git a/saga/sndres.h b/saga/sndres.h
new file mode 100644
index 0000000000..1bdfc577a8
--- /dev/null
+++ b/saga/sndres.h
@@ -0,0 +1,92 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Sound resource management module - private header
+
+ Notes:
+*/
+
+#ifndef SAGA_SNDRES_H_
+#define SAGA_SNDRES_H_
+
+namespace Saga {
+
+#define R_VOC_TIME_BASE 256000000L
+#define R_VOC_TIME_CBASE 65536L
+
+#define R_VOC_FILE_DESC_LEN 20
+#define R_VOC_FILE_DESC "Creative Voice File\x1A"
+
+typedef struct R_VOC_HEADER_BLOCK_tag {
+
+ char ft_desc[20]; /* BYTE [20] */
+ uint db_offset; /* WORD */
+ uint voc_version; /* WORD */
+ uint voc_fileid; /* WORD */
+
+} R_VOC_HEADER_BLOCK;
+
+#define R_VOC_HEADER_BLOCK_LEN 26
+
+typedef struct R_VOC_GENBLOCK_tag {
+
+ int block_id; /* BYTE */
+ ulong block_len; /* BYTE[3] */
+
+} R_VOC_GENBLOCK;
+
+#define R_VOC_GENBLOCK_LEN 4
+
+typedef struct R_VOC_BLOCK1_tag {
+
+ int block_id; /* BYTE */
+ ulong block_len; /* BYTE[3] */
+ uint time_constant; /* BYTE */
+ int pack_method; /* BYTE */
+
+} R_VOC_BLOCK1;
+
+typedef struct R_SNDRES_MODULE_tag {
+
+ int init;
+
+ R_RSCFILE_CONTEXT *sfx_ctxt;
+ R_RSCFILE_CONTEXT *voice_ctxt;
+
+ R_GAME_SOUNDINFO snd_info;
+
+} R_SNDRES_MODULE;
+
+int
+SND_Load(R_RSCFILE_CONTEXT * snd_ctxt,
+ ulong snd_rn, R_SOUNDBUFFER * snd_buf_i);
+
+int
+LoadVocSound(const uchar * snd_res,
+ size_t snd_res_len, R_SOUNDBUFFER * snd_buf_i);
+
+} // End of namespace Saga
+
+#endif /* SAGA_SNDRES_H_ */
diff --git a/saga/sndres_mod.h b/saga/sndres_mod.h
new file mode 100644
index 0000000000..245727dd34
--- /dev/null
+++ b/saga/sndres_mod.h
@@ -0,0 +1,52 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Sound resource management module - public header
+
+ Notes:
+*/
+
+#ifndef SAGA_SNDRES_MOD_H_
+#define SAGA_SNDRES_MOD_H_
+
+namespace Saga {
+
+int SND_Init(void);
+
+int SND_LoadSound(ulong sound_rn);
+
+int SND_PlayVoice(ulong voice_rn);
+
+int SND_GetVoiceLength(ulong voice_rn);
+
+int
+SND_ITEVOC_Resample(long src_freq,
+ long dst_freq,
+ uchar * src_buf,
+ size_t src_buf_len, uchar ** dst_buf, size_t * dst_buf_len);
+
+} // End of namespace Saga
+
+#endif /* SAGA_SNDRES_MOD_H_ */
diff --git a/saga/sprite.cpp b/saga/sprite.cpp
new file mode 100644
index 0000000000..975d79ec00
--- /dev/null
+++ b/saga/sprite.cpp
@@ -0,0 +1,567 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Sprite management module
+
+ Notes:
+*/
+
+#include "reinherit.h"
+
+#include "yslib.h"
+
+/*
+ * Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "game_mod.h"
+#include "gfx_mod.h"
+#include "scene_mod.h"
+#include "rscfile_mod.h"
+
+#include "text_mod.h"
+#include "font_mod.h"
+
+/*
+ * Begin module component
+\*--------------------------------------------------------------------------*/
+#include "sprite_mod.h"
+#include "sprite.h"
+
+namespace Saga {
+
+R_SPRITE_MODULE SpriteModule = { 0 };
+
+int SPRITE_Init(void)
+{
+ int result;
+
+ if (SpriteModule.init) {
+ return R_FAILURE;
+ }
+
+ R_printf(R_STDOUT, "Initializing sprite subsystem...\n");
+
+ /* Load sprite module resource context
+ * \*------------------------------------------------------------- */
+ result = GAME_GetFileContext(&SpriteModule.sprite_ctxt,
+ R_GAME_RESOURCEFILE, 0);
+ if (result != R_SUCCESS) {
+
+ return R_FAILURE;
+ }
+
+ SpriteModule.decode_buf_len = R_DECODE_BUF_LEN;
+
+ SpriteModule.decode_buf = (uchar *)malloc(R_DECODE_BUF_LEN);
+ if (SpriteModule.decode_buf == NULL) {
+ return R_MEM;
+ }
+
+ SpriteModule.init = 1;
+
+ return R_SUCCESS;
+}
+
+int SPRITE_Shutdown(void)
+{
+ if (!SpriteModule.init) {
+ return R_FAILURE;
+ }
+
+ R_printf(R_STDOUT, "Shutting down sprite subsystem...\n");
+
+ free(SpriteModule.decode_buf);
+
+ return R_SUCCESS;
+}
+
+int SPRITE_LoadList(int resource_num, R_SPRITELIST ** sprite_list_p)
+{
+ R_SPRITELIST *new_slist;
+
+ uchar *spritelist_data;
+ size_t spritelist_len;
+
+ const uchar *read_p;
+
+ uint sprite_count;
+ uint i;
+
+ new_slist = (R_SPRITELIST *)malloc(sizeof *new_slist);
+ if (new_slist == NULL) {
+
+ return R_MEM;
+ }
+
+ if (RSC_LoadResource(SpriteModule.sprite_ctxt,
+ resource_num,
+ &spritelist_data, &spritelist_len) != R_SUCCESS) {
+
+ return R_FAILURE;
+ }
+
+ read_p = spritelist_data;
+
+ sprite_count = ys_read_u16_le(read_p, &read_p);
+
+ new_slist->sprite_count = sprite_count;
+
+ new_slist->offset_list = (R_SPRITELIST_OFFSET *)malloc(sprite_count *
+ sizeof *new_slist->offset_list);
+ if (new_slist->offset_list == NULL) {
+ free(new_slist);
+
+ return R_MEM;
+ }
+
+ for (i = 0; i < sprite_count; i++) {
+ new_slist->offset_list[i].data_idx = 0;
+ new_slist->offset_list[i].offset =
+ ys_read_u16_le(read_p, &read_p);
+ }
+
+ new_slist->slist_rn = resource_num;
+ new_slist->sprite_data[0] = spritelist_data;
+ new_slist->append_count = 0;
+
+ *sprite_list_p = new_slist;
+
+ return R_SUCCESS;
+}
+
+int SPRITE_AppendList(int resource_num, R_SPRITELIST * spritelist)
+{
+ uchar *spritelist_data;
+ size_t spritelist_len;
+
+ const uchar *read_p;
+
+ void *test_p;
+
+ uint old_sprite_count;
+ uint new_sprite_count;
+ uint sprite_count;
+
+ int i;
+
+ if (spritelist->append_count >= (R_APPENDMAX - 1)) {
+
+ return R_FAILURE;
+ }
+
+ if (RSC_LoadResource(SpriteModule.sprite_ctxt,
+ resource_num,
+ &spritelist_data, &spritelist_len) != R_SUCCESS) {
+
+ return R_FAILURE;
+ }
+
+ read_p = spritelist_data;
+
+ sprite_count = ys_read_u16_le(read_p, &read_p);
+
+ old_sprite_count = spritelist->sprite_count;
+ new_sprite_count = spritelist->sprite_count + sprite_count;
+
+ test_p = realloc(spritelist->offset_list,
+ new_sprite_count * sizeof *spritelist->offset_list);
+ if (test_p == NULL) {
+ return R_MEM;
+ }
+
+ spritelist->offset_list = (R_SPRITELIST_OFFSET *)test_p;
+
+ spritelist->sprite_count = new_sprite_count;
+ spritelist->append_count++;
+
+ for (i = old_sprite_count; i < spritelist->sprite_count; i++) {
+ spritelist->offset_list[i].data_idx = spritelist->append_count;
+ spritelist->offset_list[i].offset =
+ ys_read_u16_le(read_p, &read_p);
+ }
+
+ spritelist->sprite_data[spritelist->append_count] = spritelist_data;
+
+ return R_SUCCESS;
+}
+
+int SPRITE_GetListLen(R_SPRITELIST * spritelist)
+{
+
+ return spritelist->sprite_count;
+}
+
+int SPRITE_Free(R_SPRITELIST * spritelist)
+{
+ int i;
+
+ for (i = 0; i <= spritelist->append_count; i++) {
+
+ RSC_FreeResource(spritelist->sprite_data[i]);
+ }
+
+ free(spritelist->offset_list);
+ free(spritelist);
+
+ return R_SUCCESS;
+}
+
+int
+SPRITE_Draw(R_SURFACE * ds,
+ R_SPRITELIST * sprite_list, int sprite_num, int spr_x, int spr_y)
+{
+
+ int offset;
+ int offset_idx;
+
+ uchar *sprite_p;
+
+ const uchar *sprite_data_p;
+ const uchar *read_p;
+
+ int i, j;
+
+ uchar *buf_row_p;
+ uchar *src_row_p;
+
+ int s_width;
+ int s_height;
+
+ int clip_width;
+ int clip_height;
+
+ int x_align;
+ int y_align;
+
+ if (!SpriteModule.init) {
+ return R_FAILURE;
+ }
+
+ offset = sprite_list->offset_list[sprite_num].offset;
+ offset_idx = sprite_list->offset_list[sprite_num].data_idx;
+
+ sprite_p = sprite_list->sprite_data[offset_idx];
+ sprite_p += offset;
+
+ read_p = (uchar *) sprite_p;
+
+ x_align = ys_read_s8(read_p, &read_p);
+ y_align = ys_read_s8(read_p, &read_p);
+
+ s_width = ys_read_u8(read_p, &read_p);
+ s_height = ys_read_u8(read_p, &read_p);
+
+ sprite_data_p = read_p;
+
+ spr_x += x_align;
+ spr_y += y_align;
+
+ if (spr_x < 0) {
+ return 0;
+ }
+
+ if (spr_y < 0) {
+ return 0;
+ }
+
+ DecodeRLESprite(sprite_data_p,
+ 64000, SpriteModule.decode_buf, s_width * s_height);
+
+ buf_row_p = ds->buf + ds->buf_pitch * spr_y;
+ src_row_p = SpriteModule.decode_buf;
+
+ /* Clip to right side of surface */
+ clip_width = s_width;
+ if (s_width > (ds->buf_w - spr_x)) {
+ clip_width = (ds->buf_w - spr_x);
+ }
+
+ /* Clip to bottom side of surface */
+ clip_height = s_height;
+ if (s_height > (ds->buf_h - spr_y)) {
+ clip_height = (ds->buf_h - spr_y);
+ }
+
+ for (i = 0; i < clip_height; i++) {
+
+ for (j = 0; j < clip_width; j++) {
+ if (*(src_row_p + j) != 0) {
+ *(buf_row_p + j + spr_x) = *(src_row_p + j);
+ }
+ }
+
+ buf_row_p += ds->buf_pitch;
+ src_row_p += s_width;
+ }
+
+ return R_SUCCESS;
+}
+
+int
+SPRITE_DrawOccluded(R_SURFACE * ds,
+ R_SPRITELIST * sprite_list, int sprite_num, int spr_x, int spr_y)
+{
+ int offset;
+ int offset_idx;
+
+ uchar *sprite_p;
+ const uchar *sprite_data_p;
+ const uchar *read_p;
+
+ int i;
+
+ int x, y;
+ uchar *dst_row_p;
+ uchar *src_row_p;
+ uchar *src_p;
+ uchar *dst_p;
+ uchar *mask_p;
+
+ int s_width;
+ int s_height;
+ int x_align;
+ int y_align;
+
+ int z_lut[R_SPRITE_ZMAX];
+ int e_slope;
+
+ /* Clipinfo variables */
+ R_POINT spr_pt;
+ R_RECT spr_src_rect;
+ R_RECT spr_dst_rect;
+
+ R_CLIPINFO ci;
+
+ /* BG mask variables */
+ int mask_w;
+ int mask_h;
+ uchar *mask_buf;
+ size_t mask_buf_len;
+
+ uchar *mask_row_p;
+ int mask_z;
+
+ /* Z info variables */
+ SCENE_ZINFO zinfo;
+ int actor_z;
+
+ if (!SpriteModule.init) {
+ return R_FAILURE;
+ }
+
+ if (!SCENE_IsBGMaskPresent()) {
+ return SPRITE_Draw(ds, sprite_list, sprite_num, spr_x, spr_y);
+ }
+
+ if (sprite_num >= sprite_list->sprite_count) {
+
+ R_printf(R_STDOUT,
+ "Invalid sprite number (%d) for sprite list %d.\n",
+ sprite_num, sprite_list->slist_rn);
+
+ return R_FAILURE;
+ }
+
+ /* Get sprite data from list
+ * \*------------------------------------------------------------- */
+ offset = sprite_list->offset_list[sprite_num].offset;
+ offset_idx = sprite_list->offset_list[sprite_num].data_idx;
+
+ sprite_p = sprite_list->sprite_data[offset_idx];
+ sprite_p += offset;
+
+ read_p = sprite_p;
+
+ /* Read sprite dimensions -- should probably cache this stuff in
+ * sprite list */
+ x_align = ys_read_s8(read_p, &read_p);
+ y_align = ys_read_s8(read_p, &read_p);
+
+ s_width = ys_read_u8(read_p, &read_p);
+ s_height = ys_read_u8(read_p, &read_p);
+
+ sprite_data_p = read_p;
+
+ /* Create actor Z occlusion LUT
+ * \*---------------------------------------------------------------------- */
+ SCENE_GetZInfo(&zinfo);
+
+ e_slope = zinfo.end_slope;
+
+ for (i = 0; i < R_SPRITE_ZMAX; i++) {
+
+ z_lut[i] =
+ (int)(e_slope + ((137.0 - e_slope) / 14.0) * (15.0 - i));
+ }
+
+ actor_z = spr_y;
+
+ SCENE_GetBGMaskInfo(&mask_w, &mask_h, &mask_buf, &mask_buf_len);
+
+ spr_src_rect.x1 = 0;
+ spr_src_rect.y1 = 0;
+ spr_src_rect.x2 = s_width - 1;
+ spr_src_rect.y2 = s_height - 1;
+
+ spr_dst_rect.x1 = 0;
+ spr_dst_rect.y1 = 0;
+ spr_dst_rect.x2 = ds->clip_rect.x2;
+ spr_dst_rect.y2 = YS_MIN(ds->clip_rect.y2, mask_h - 1);
+
+ spr_pt.x = spr_x + x_align;
+ spr_pt.y = spr_y + y_align;
+
+ spr_x += x_align;
+ spr_y += y_align;
+
+ ci.dst_rect = &spr_dst_rect;
+ ci.src_rect = &spr_src_rect;
+ ci.dst_pt = &spr_pt;
+
+ GFX_GetClipInfo(&ci);
+
+ if (ci.nodraw) {
+ return R_SUCCESS;
+ }
+
+ DecodeRLESprite(sprite_data_p,
+ 64000, SpriteModule.decode_buf, s_width * s_height);
+
+ /* Finally, draw the occluded sprite
+ * \*---------------------------------------------------------------------- */
+ src_row_p = SpriteModule.decode_buf + ci.src_draw_x +
+ (ci.src_draw_y * s_width);
+
+ dst_row_p = ds->buf + ci.dst_draw_x + (ci.dst_draw_y * ds->buf_pitch);
+ mask_row_p = mask_buf + ci.dst_draw_x + (ci.dst_draw_y * mask_w);
+
+ for (y = 0; y < ci.draw_h; y++) {
+
+ src_p = src_row_p;
+ dst_p = dst_row_p;
+ mask_p = mask_row_p;
+
+ for (x = 0; x < ci.draw_w; x++) {
+
+ if (*src_p != 0) {
+
+ mask_z = *mask_p & R_SPRITE_ZMASK;
+
+ if (actor_z > z_lut[mask_z]) {
+ *dst_p = *src_p;
+ }
+ }
+ src_p++;
+ dst_p++;
+ mask_p++;
+ }
+ dst_row_p += ds->buf_pitch;
+ mask_row_p += mask_w;
+ src_row_p += s_width;
+ }
+/*
+ {
+ char buf[1024] = { 0 };
+
+ sprintf( buf, "dw: %d, dh: %d.", ci.draw_w, ci.draw_h );
+
+ TEXT_Draw( 2,
+ ds,
+ buf,
+ spr_x - x_align, spr_y - y_align,
+ 255, 0,
+ FONT_OUTLINE );
+ }
+*/
+ return R_SUCCESS;
+}
+
+int
+DecodeRLESprite(const uchar * inbuf,
+ size_t inbuf_len, uchar * outbuf, size_t outbuf_len)
+{
+
+ int bg_runcount;
+ int fg_runcount;
+
+ const uchar *inbuf_ptr;
+ uchar *outbuf_ptr;
+
+ const uchar *inbuf_end;
+ uchar *outbuf_end;
+
+ int c;
+
+ inbuf_ptr = inbuf;
+ outbuf_ptr = outbuf;
+
+ inbuf_end = inbuf + (inbuf_len);
+ inbuf_end--;
+
+ outbuf_end = outbuf + outbuf_len;
+ outbuf_end--;
+
+ memset(outbuf, 0, outbuf_len);
+
+ while ((inbuf_ptr < inbuf_end) && (outbuf_ptr < outbuf_end)) {
+
+ bg_runcount = *inbuf_ptr;
+ if (inbuf_ptr < inbuf_end)
+ inbuf_ptr++;
+ else
+ return 0;
+ fg_runcount = *inbuf_ptr;
+ if (inbuf_ptr < inbuf_end)
+ inbuf_ptr++;
+ else
+ return 0;
+
+ for (c = 0; c < bg_runcount; c++) {
+
+ *outbuf_ptr = (uchar) 0;
+ if (outbuf_ptr < outbuf_end)
+ outbuf_ptr++;
+ else
+ return 0;
+ }
+
+ for (c = 0; c < fg_runcount; c++) {
+
+ *outbuf_ptr = *inbuf_ptr;
+ if (inbuf_ptr < inbuf_end)
+ inbuf_ptr++;
+ else
+ return 0;
+ if (outbuf_ptr < outbuf_end)
+ outbuf_ptr++;
+ else
+ return 0;
+ }
+ }
+
+ return R_SUCCESS;
+}
+
+} // End of namespace Saga
diff --git a/saga/sprite.h b/saga/sprite.h
new file mode 100644
index 0000000000..d90d5e0800
--- /dev/null
+++ b/saga/sprite.h
@@ -0,0 +1,88 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Sprite management module private header file
+
+ Notes:
+*/
+
+#ifndef SAGA_SPRITE_H__
+#define SAGA_SPRITE_H__
+
+namespace Saga {
+
+#define R_APPENDMAX 4
+
+#define R_SPRITE_ZMAX 16
+#define R_SPRITE_ZMASK 0x0F
+
+#define R_DECODE_BUF_LEN 64000
+
+typedef struct R_SPRITELIST_ENTRY_tag {
+
+ int x_align;
+ int y_align;
+ int width;
+ int height;
+
+} R_SPRITELIST_ENTRY;
+
+typedef struct R_SPRITELIST_OFFSET_tag {
+
+ uint data_idx;
+ size_t offset;
+
+} R_SPRITELIST_OFFSET;
+
+struct R_SPRITELIST_tag {
+
+ int append_count;
+ int sprite_count;
+
+ R_SPRITELIST_OFFSET *offset_list;
+
+ int slist_rn;
+ uchar *sprite_data[R_APPENDMAX];
+
+};
+
+typedef struct R_SPRITE_MODULE_tag {
+
+ int init;
+
+ R_RSCFILE_CONTEXT *sprite_ctxt;
+
+ uchar *decode_buf;
+ size_t decode_buf_len;
+
+} R_SPRITE_MODULE;
+
+int
+DecodeRLESprite(const uchar * inbuf,
+ size_t inbuf_len, uchar * outbuf, size_t outbuf_len);
+
+} // End of namespace Saga
+
+#endif /* SAGA_SPRITE_H__ */
diff --git a/saga/sprite_mod.h b/saga/sprite_mod.h
new file mode 100644
index 0000000000..e93eec0513
--- /dev/null
+++ b/saga/sprite_mod.h
@@ -0,0 +1,61 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ Sprite management module public header file
+
+ Notes:
+*/
+
+#ifndef SAGA_SPRITE_MOD_H__
+#define SAGA_SPRITE_MOD_H__
+
+namespace Saga {
+
+typedef struct R_SPRITELIST_tag R_SPRITELIST;
+
+int SPRITE_Init(void);
+
+int SPRITE_Shutdown(void);
+
+int SPRITE_LoadList(int resource_num, R_SPRITELIST ** sprite_list_p);
+
+int SPRITE_AppendList(int resource_num, R_SPRITELIST * spritelist);
+
+int SPRITE_GetListLen(R_SPRITELIST * spritelist);
+
+int SPRITE_Free(R_SPRITELIST * spritelist);
+
+int
+SPRITE_Draw(R_SURFACE * ds,
+ R_SPRITELIST * sprite_list, int sprite_num, int spr_x, int spr_y);
+
+int
+SPRITE_DrawOccluded(R_SURFACE * ds,
+ R_SPRITELIST * sprite_list, int sprite_num, int spr_x, int spr_y);
+
+} // End of namespace Saga
+
+#endif /* SAGA_SPRITE_MOD_H__ */
diff --git a/saga/sstack.cpp b/saga/sstack.cpp
new file mode 100644
index 0000000000..99741ac632
--- /dev/null
+++ b/saga/sstack.cpp
@@ -0,0 +1,199 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ Scripting engine stack component
+
+ Notes:
+*/
+
+#include "reinherit.h"
+
+#include "yslib.h"
+
+/*
+ * Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "console_mod.h"
+#include "text_mod.h"
+
+/*
+ * Begin module component
+\*--------------------------------------------------------------------------*/
+#include "script.h"
+#include "sstack.h"
+
+namespace Saga {
+
+int SSTACK_Create(SSTACK * stack, int stack_len, int flags)
+{
+
+ SSTACK new_stack;
+ SDataWord_T *new_stack_data;
+
+ *stack = NULL;
+
+ new_stack = (SSTACK_tag *)malloc(sizeof(struct SSTACK_tag));
+ if (new_stack == NULL) {
+
+ return STACK_MEM;
+ }
+
+ new_stack_data = (SDataWord_T *)calloc(stack_len, sizeof *new_stack_data);
+ if (new_stack_data == NULL) {
+ free(new_stack);
+
+ return STACK_MEM;
+ }
+
+ new_stack->data = new_stack_data;
+
+ new_stack->flags = flags;
+ new_stack->len = stack_len;
+ new_stack->top = -1;
+
+ *stack = new_stack;
+
+ return STACK_SUCCESS;
+}
+
+int SSTACK_Destroy(SSTACK stack)
+{
+ if (stack != NULL) {
+ free(stack->data);
+ }
+
+ free(stack);
+
+ return STACK_SUCCESS;
+}
+
+int SSTACK_Clear(SSTACK stack)
+{
+
+ stack->top = -1;
+
+ return STACK_SUCCESS;
+}
+
+int SSTACK_PushNull(SSTACK stack)
+{
+
+ if (stack->top >= (stack->len - 1)) {
+
+ if (stack->flags & STACK_FIXED) {
+
+ return STACK_OVERFLOW;
+ } else if (SSTACK_Grow(stack) != STACK_SUCCESS) {
+
+ return STACK_MEM;
+ }
+ }
+
+ stack->top++;
+
+ return STACK_SUCCESS;
+}
+
+int SSTACK_Push(SSTACK stack, SDataWord_T value)
+{
+
+ if (stack->top >= (stack->len - 1)) {
+
+ if (stack->flags & STACK_FIXED) {
+
+ return STACK_OVERFLOW;
+ } else if (SSTACK_Grow(stack) != STACK_SUCCESS) {
+
+ return STACK_MEM;
+ }
+ }
+
+ stack->top++;
+ stack->data[stack->top] = value;
+
+ return STACK_SUCCESS;
+}
+
+int SSTACK_Pop(SSTACK stack, SDataWord_T * value)
+{
+
+ if (stack->top <= -1) {
+
+ return STACK_UNDERFLOW;
+ }
+
+ if (value == NULL) {
+
+ stack->top--;
+ return STACK_SUCCESS;
+ }
+
+ *value = stack->data[stack->top];
+ stack->top--;
+
+ return STACK_SUCCESS;
+}
+
+int SSTACK_Top(SSTACK stack, SDataWord_T * value)
+{
+
+ *value = 0;
+
+ if (stack->top <= -1) {
+
+ return STACK_UNDERFLOW;
+ }
+
+ *value = stack->data[stack->top];
+
+ return STACK_SUCCESS;
+}
+
+int SSTACK_Grow(SSTACK stack)
+{
+
+ SDataWord_T *new_data;
+
+ if ((stack->len * 2) > R_STACK_SIZE_LIMIT) {
+
+ CON_Print(S_ERROR_PREFIX "Stack fault: growing beyond limit.");
+ return STACK_OVERFLOW;
+ }
+
+ new_data = (SDataWord_T *)realloc(stack->data, (stack->len * 2) * sizeof *new_data);
+ if (new_data == NULL) {
+
+ return STACK_MEM;
+ }
+
+ stack->data = new_data;
+ stack->len *= 2;
+
+ return STACK_SUCCESS;
+}
+
+} // End of namespace Saga
+
diff --git a/saga/sstack.h b/saga/sstack.h
new file mode 100644
index 0000000000..669d0b0423
--- /dev/null
+++ b/saga/sstack.h
@@ -0,0 +1,81 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ Scripting engine stack component header file
+
+ Notes:
+*/
+
+#ifndef SAGA_SSTACK_H
+#define SAGA_SSTACK_H
+
+#include "script_mod.h"
+
+namespace Saga {
+
+#define R_STACK_SIZE_LIMIT 16384
+
+struct SSTACK_tag {
+ int flags;
+ int len;
+ int top;
+ SDataWord_T *data;
+};
+
+typedef struct SSTACK_tag *SSTACK;
+
+typedef enum SSTACK_ERR_enum {
+ STACK_SUCCESS = 0,
+ STACK_ERROR,
+ STACK_MEM,
+ STACK_UNDERFLOW,
+ STACK_OVERFLOW
+} SSTACK_ERR_CODE;
+
+typedef enum SSTACK_FLAGS_enum {
+ STACK_FIXED = 0x00,
+ STACK_GROW = 0x01
+} SSTACK_FLAGS;
+
+int SSTACK_Create(SSTACK * stack, int stack_len, int flags);
+
+int SSTACK_Destroy(SSTACK stack);
+
+int SSTACK_Clear(SSTACK stack);
+
+int SSTACK_Push(SSTACK stack, SDataWord_T value);
+
+int SSTACK_PushNull(SSTACK stack);
+
+int SSTACK_Pop(SSTACK stack, SDataWord_T * value);
+
+int SSTACK_Top(SSTACK stack, SDataWord_T * value);
+
+int SSTACK_Grow(SSTACK stack);
+
+} // End of namespace Saga
+
+#endif /* SAGA_SSTACK_H */
diff --git a/saga/stack.cpp b/saga/stack.cpp
new file mode 100644
index 0000000000..ef5552d4a1
--- /dev/null
+++ b/saga/stack.cpp
@@ -0,0 +1,180 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Simple integer stack module
+
+ Notes:
+*/
+
+#include "reinherit.h"
+
+#include "stack.h"
+#include "stack_mod.h"
+
+namespace Saga {
+
+int ISTACK_Create(R_ISTACK * stack, int stack_len, int flags)
+{
+
+ R_ISTACK new_stack;
+ int *new_stack_data;
+
+ *stack = NULL;
+
+ new_stack = (R_ISTACK_tag *)malloc(sizeof(struct R_ISTACK_tag));
+
+ if (new_stack == NULL) {
+ return STACK_MEM;
+ }
+
+ new_stack_data = (int *)calloc(stack_len, sizeof(int));
+
+ if (new_stack_data == NULL) {
+
+ free(new_stack);
+ return STACK_MEM;
+ }
+
+ new_stack->flags = flags;
+ new_stack->len = stack_len;
+ new_stack->top = -1;
+
+ return STACK_SUCCESS;
+}
+
+int ISTACK_Destroy(R_ISTACK * stack)
+{
+
+ if (stack != NULL) {
+ free((*stack)->data);
+ }
+
+ free(stack);
+
+ *stack = NULL;
+
+ return STACK_SUCCESS;
+}
+
+int ISTACK_Clear(R_ISTACK stack)
+{
+
+ stack->top = -1;
+ return STACK_SUCCESS;
+}
+
+int ISTACK_PushNull(R_ISTACK stack)
+{
+
+ if (stack->top >= (stack->len - 1)) {
+
+ if (stack->flags & STACK_FIXED) {
+
+ return STACK_OVERFLOW;
+ } else if (ISTACK_Grow(stack) != STACK_SUCCESS) {
+
+ return STACK_MEM;
+ }
+ }
+
+ stack->top++;
+
+}
+
+int ISTACK_Push(R_ISTACK stack, int value)
+{
+
+ if (stack->top >= (stack->len - 1)) {
+
+ if (stack->flags & STACK_FIXED) {
+
+ return STACK_OVERFLOW;
+ } else if (ISTACK_Grow(stack) != STACK_SUCCESS) {
+
+ return STACK_MEM;
+ }
+ }
+
+ stack->top++;
+ stack->data[stack->top] = value;
+
+ return STACK_SUCCESS;
+}
+
+int ISTACK_Pop(R_ISTACK stack, int *value)
+{
+
+ if (stack->top <= -1) {
+
+ return STACK_UNDERFLOW;
+ }
+
+ if (value == NULL) {
+
+ stack->top--;
+ return STACK_SUCCESS;
+ }
+
+ *value = stack->data[stack->top];
+ stack->top--;
+
+ return STACK_SUCCESS;
+}
+
+int ISTACK_Top(R_ISTACK stack, int *value)
+{
+ *value = 0;
+
+ if (stack->top <= -1) {
+
+ return STACK_UNDERFLOW;
+ }
+
+ *value = stack->data[stack->top];
+
+ return STACK_SUCCESS;
+
+}
+
+int ISTACK_Grow(R_ISTACK stack)
+{
+
+ int *new_data;
+
+ new_data = (int *)realloc(stack->data, (stack->len * 2) * sizeof(int));
+
+ if (new_data == NULL) {
+
+ return STACK_MEM;
+ };
+
+ stack->data = new_data;
+ stack->len *= 2;
+
+ return STACK_SUCCESS;
+}
+
+} // End of namespace Saga
+
diff --git a/saga/stack.h b/saga/stack.h
new file mode 100644
index 0000000000..474d2d865c
--- /dev/null
+++ b/saga/stack.h
@@ -0,0 +1,49 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Simple integer stack module private header
+
+ Notes:
+*/
+
+#ifndef SAGA_STACK_H
+#define SAGA_STACK_H
+
+namespace Saga {
+
+#define ISTACK_MAX
+
+struct R_ISTACK_tag {
+
+ int flags;
+ int len;
+ int top;
+ int *data;
+
+};
+
+} // End of namespace Saga
+
+#endif /* SAGA_STACK_H */
diff --git a/saga/stack_mod.h b/saga/stack_mod.h
new file mode 100644
index 0000000000..09e2711c89
--- /dev/null
+++ b/saga/stack_mod.h
@@ -0,0 +1,69 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Simple integer stack module public header
+
+ Notes:
+*/
+
+#ifndef SAGA_STACK_MOD_H
+#define SAGA_STACK_MOD_H
+
+#include "stack.h"
+
+namespace Saga {
+
+typedef enum STACK_ERR_enum {
+ STACK_SUCCESS = 0,
+ STACK_ERROR,
+ STACK_MEM,
+ STACK_UNDERFLOW,
+ STACK_OVERFLOW
+} STACK_ERR_CODE;
+
+typedef enum STACK_FLAGS_enum {
+ STACK_FIXED = 0x00,
+ STACK_GROW = 0x01
+} STACK_FLAGS;
+
+typedef struct R_ISTACK_tag *R_ISTACK;
+
+int ISTACK_Create(R_ISTACK * stack, int stack_len, int flags);
+
+int ISTACK_Destroy(R_ISTACK * stack);
+
+int ISTACK_Clear(R_ISTACK stack);
+
+int ISTACK_Push(R_ISTACK stack, int value);
+
+int ISTACK_PushNull(R_ISTACK stack);
+
+int ISTACK_Pop(R_ISTACK stack, int *value);
+
+int ISTACK_Grow(R_ISTACK stack);
+
+} // End of namespace Saga
+
+#endif /* SAGA_STACK_MOD_H */
diff --git a/saga/sthread.cpp b/saga/sthread.cpp
new file mode 100644
index 0000000000..04407a1eec
--- /dev/null
+++ b/saga/sthread.cpp
@@ -0,0 +1,1120 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ Scripting module thread management component
+
+ Notes:
+*/
+
+#include "reinherit.h"
+
+#include "yslib.h"
+
+#include <limits.h>
+
+/*
+ * Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "actor_mod.h"
+#include "console_mod.h"
+#include "text_mod.h"
+
+/*
+ * Begin module component
+\*--------------------------------------------------------------------------*/
+#include "script.h"
+#include "script_mod.h"
+
+#include "sdata.h"
+#include "sstack.h"
+#include "sthread.h"
+#include "sfuncs.h"
+
+namespace Saga {
+
+R_SCRIPT_THREAD *STHREAD_Create(void)
+{
+ YS_DL_NODE *new_node;
+ R_SCRIPT_THREAD *new_thread;
+
+ int result;
+
+ if (!ScriptModule.initialized) {
+
+ return NULL;
+ }
+
+ new_thread = (R_SCRIPT_THREAD *)calloc(1, sizeof *new_thread);
+ if (new_thread == NULL) {
+ return NULL;
+ }
+
+ result = SSTACK_Create(&(new_thread->stack),
+ R_DEF_THREAD_STACKSIZE, STACK_GROW);
+
+ if (result != STACK_SUCCESS) {
+ return NULL;
+ }
+
+ new_node = ys_dll_add_head(ScriptModule.thread_list,
+ new_thread, sizeof *new_thread);
+
+ free(new_thread);
+
+ return (R_SCRIPT_THREAD *)ys_dll_get_data(new_node);
+
+}
+
+int STHREAD_Destroy(R_SCRIPT_THREAD * thread)
+{
+ if (thread == NULL) {
+ return R_FAILURE;
+ }
+
+ SSTACK_Destroy(thread->stack);
+
+ return R_SUCCESS;
+}
+
+int STHREAD_ExecThreads(int msec)
+{
+ YS_DL_NODE *walk_p;
+ R_SCRIPT_THREAD *thread;
+
+ if (!ScriptModule.initialized) {
+
+ return R_FAILURE;
+ }
+
+ for (walk_p = ys_dll_head(ScriptModule.thread_list);
+ walk_p != NULL; walk_p = ys_dll_next(walk_p)) {
+
+ thread = (R_SCRIPT_THREAD *)ys_dll_get_data(walk_p);
+
+ if (thread->executing) {
+
+ STHREAD_Run(thread, STHREAD_DEF_INSTR_COUNT, msec);
+ }
+ }
+
+ return R_SUCCESS;
+}
+
+int STHREAD_SetEntrypoint(R_SCRIPT_THREAD * thread, int ep_num)
+{
+
+ R_SCRIPT_BYTECODE *bytecode;
+ int max_entrypoint;
+
+ assert(ScriptModule.initialized);
+
+ bytecode = ScriptModule.current_script->bytecode;
+ max_entrypoint = bytecode->n_entrypoints;
+
+ if ((ep_num < 0) || (ep_num >= max_entrypoint)) {
+ return R_FAILURE;
+ }
+
+ thread->ep_num = ep_num;
+ thread->ep_offset = bytecode->entrypoints[ep_num].offset;
+
+ return R_SUCCESS;
+}
+
+int STHREAD_Execute(R_SCRIPT_THREAD * thread, int ep_num)
+{
+
+ assert(ScriptModule.initialized);
+
+ if ((ScriptModule.current_script == NULL) ||
+ (!ScriptModule.current_script->loaded)) {
+
+ return R_FAILURE;
+ }
+
+ STHREAD_SetEntrypoint(thread, ep_num);
+
+ thread->i_offset = thread->ep_offset;
+ thread->executing = 1;
+
+ return R_SUCCESS;
+}
+
+unsigned char *GetReadPtr(R_SCRIPT_THREAD * thread)
+{
+
+ return ScriptModule.current_script->bytecode->bytecode_p +
+ thread->i_offset;
+}
+
+unsigned long GetReadOffset(const uchar * read_p)
+{
+
+ return (unsigned long)(read_p - (unsigned char *)
+ ScriptModule.current_script->bytecode->bytecode_p);
+}
+
+int STHREAD_HoldSem(R_SEMAPHORE * sem)
+{
+ if (sem == NULL) {
+ return R_FAILURE;
+ }
+
+ sem->hold_count++;
+
+ return R_SUCCESS;
+}
+
+int STHREAD_ReleaseSem(R_SEMAPHORE * sem)
+{
+ if (sem == NULL) {
+ return R_FAILURE;
+ }
+
+ sem->hold_count--;
+ if (sem->hold_count < 0) {
+ sem->hold_count = 0;
+ }
+
+ return R_SUCCESS;
+}
+
+int STHREAD_DebugStep(void)
+{
+
+ if (ScriptModule.dbg_singlestep) {
+ ScriptModule.dbg_dostep = 1;
+ }
+
+ return R_SUCCESS;
+}
+
+int STHREAD_Run(R_SCRIPT_THREAD * thread, int instr_limit, int msec)
+{
+
+ int instr_count;
+
+ const uchar *read_p;
+ ulong saved_offset;
+
+ SDataWord_T param1;
+ SDataWord_T param2;
+
+ long iparam1;
+ long iparam2;
+ long iresult;
+
+ SDataWord_T data;
+
+ int debug_print = 0;
+ int n_buf;
+ int bitstate;
+
+ int result;
+ int in_char;
+ int i;
+
+ int unhandled = 0;
+
+ /* Handle debug single-stepping */
+ if ((thread == ScriptModule.dbg_thread) && ScriptModule.dbg_singlestep) {
+
+ if (ScriptModule.dbg_dostep) {
+
+ debug_print = 1;
+
+ thread->sleep_time = 0;
+ instr_limit = 1;
+ ScriptModule.dbg_dostep = 0;
+ } else {
+
+ return R_SUCCESS;
+ }
+ }
+
+ for (instr_count = 0; instr_count < instr_limit; instr_count++) {
+
+ if ((!thread->executing) || (thread->sem.hold_count)) {
+ break;
+ }
+
+ thread->sleep_time -= msec;
+ if (thread->sleep_time < 0) {
+ thread->sleep_time = 0;
+ }
+
+ if (thread->sleep_time) {
+ break;
+ }
+
+ saved_offset = thread->i_offset;
+#if 0
+ R_printf(R_STDOUT, "Executing thread offset: %lu",
+ thread->i_offset);
+#endif
+ read_p = GetReadPtr(thread);
+
+ in_char = ys_read_u8(read_p, &read_p);
+
+ switch (in_char) {
+
+ /* Align (ALGN) */
+ case 0x01:
+ break;
+
+ /*-------------------------------------------------------------*\
+ * STACK INSTRUCTIONS
+ \*-------------------------------------------------------------*/
+
+ /* Push nothing (PSHN) */
+ case 0x02:
+
+ SSTACK_PushNull(thread->stack);
+
+ break;
+
+ /* Pop nothing (POPN) */
+ case 0x03:
+
+ SSTACK_Pop(thread->stack, NULL);
+
+ break;
+
+ /* Push false (PSHF) */
+ case 0x04:
+
+ SSTACK_Push(thread->stack, 0);
+
+ break;
+
+ /* Push true (PSHT) */
+ case 0x05:
+
+ SSTACK_Push(thread->stack, 1);
+
+ break;
+
+ /* Push word (PUSH) */
+ case 0x06:
+
+ param1 = (SDataWord_T) ys_read_u16_le(read_p, &read_p);
+ SSTACK_Push(thread->stack, param1);
+
+ break;
+
+ /* Push word (PSHD) (dialogue string index) */
+ case 0x08:
+
+ param1 = (SDataWord_T) ys_read_u16_le(read_p, &read_p);
+ SSTACK_Push(thread->stack, param1);
+
+ break;
+
+ /*-------------------------------------------------------------*\
+ * DATA INSTRUCTIONS
+ \*-------------------------------------------------------------*/
+
+ /* Test flag (TSTF) */
+ case 0x0B:
+
+ n_buf = *read_p++;
+ param1 = (SDataWord_T) ys_read_u16_le(read_p, &read_p);
+
+ SDATA_GetBit(n_buf, param1, &bitstate);
+ SSTACK_Push(thread->stack, bitstate);
+
+ break;
+
+ /* Get word (GETW) */
+ case 0x0C:
+
+ n_buf = *read_p++;
+ param1 = ys_read_u16_le(read_p, &read_p);
+
+ SDATA_GetWord(n_buf, param1, &data);
+ SSTACK_Push(thread->stack, data);
+
+ break;
+
+ /* Modify flag (MODF) */
+ case 0x0F:
+
+ n_buf = *read_p++;
+ param1 = (SDataWord_T) ys_read_u16_le(read_p, &read_p);
+
+ bitstate = SDATA_ReadWordU(param1);
+
+ SSTACK_Top(thread->stack, &data);
+
+ if (bitstate) {
+ SDATA_SetBit(n_buf, data, 1);
+ } else {
+ SDATA_SetBit(n_buf, data, 0);
+ }
+
+ break;
+
+ /* Put word (PUTW) */
+ case 0x10:
+
+ n_buf = *read_p++;
+ param1 = (SDataWord_T) ys_read_u16_le(read_p, &read_p);
+
+ SSTACK_Top(thread->stack, &data);
+ SDATA_PutWord(n_buf, param1, data);
+
+ break;
+
+ /* Modify flag and pop (MDFP) */
+ case 0x13:
+
+ n_buf = *read_p++;
+ param1 = (SDataWord_T) ys_read_u16_le(read_p, &read_p);
+
+ SSTACK_Pop(thread->stack, &param1);
+
+ bitstate = SDATA_ReadWordU(param1);
+
+ if (bitstate) {
+ SDATA_SetBit(n_buf, param1, 1);
+ } else {
+ SDATA_SetBit(n_buf, param1, 0);
+ }
+
+ break;
+
+ /* Put word and pop (PTWP) */
+ case 0x14:
+
+ n_buf = *read_p++;
+ param1 = (SDataWord_T) ys_read_u16_le(read_p, &read_p);
+
+ SSTACK_Top(thread->stack, &data);
+ SDATA_PutWord(n_buf, param1, data);
+
+ break;
+
+ /*-------------------------------------------------------------*\
+ * CONTROL INSTRUCTIONS
+ \*-------------------------------------------------------------*/
+
+ /* (GOSB): Call subscript ? */
+ case 0x17:
+ {
+
+ int temp;
+ int temp2;
+
+ temp = *read_p++;
+ temp2 = *read_p++;
+
+ param1 =
+ (SDataWord_T) ys_read_u16_le(read_p,
+ &read_p);
+ data = GetReadOffset(read_p);
+
+ /*SSTACK_Push( thread->stack, (SDataWord_T)temp ); */
+ SSTACK_Push(thread->stack, data);
+
+ thread->i_offset = (unsigned long)param1;
+ }
+ break;
+
+ /* (CALL): Call function */
+ case 0x19:
+ case 0x18:
+ {
+ int n_args;
+ uint func_num;
+ int result;
+
+ SFunc_T sfunc;
+
+ n_args = ys_read_u8(read_p, &read_p);
+ func_num = ys_read_u16_le(read_p, &read_p);
+
+ if (func_num >= R_SFUNC_NUM) {
+
+ CON_Print(S_ERROR_PREFIX
+ "Invalid script function number: (%X)\n",
+ func_num);
+
+ thread->executing = 0;
+ break;
+ }
+
+ sfunc = SFuncList[func_num].sfunc_fp;
+
+ if (sfunc == NULL) {
+
+ CON_Print(S_WARN_PREFIX
+ "%X: Undefined script function number: (%X)\n",
+ thread->i_offset, func_num);
+
+ CON_Print(S_WARN_PREFIX
+ "Removing %d operand(s) from stack.\n",
+ n_args);
+
+ for (i = 0; i < n_args; i++) {
+
+ SSTACK_Pop(thread->stack,
+ NULL);
+ }
+ } else {
+
+ result = sfunc(thread);
+
+ if (result != R_SUCCESS) {
+ CON_Print(S_WARN_PREFIX
+ "%X: Script function %d failed.\n",
+ thread->i_offset,
+ func_num);
+ }
+ }
+
+ }
+ break;
+
+ /* (ENTR) Enter the dragon */
+ case 0x1A:
+
+ param1 = ys_read_u16_le(read_p, &read_p);
+
+ break;
+
+ /* (?) Unknown */
+ case 0x1B:
+
+ unhandled = 1;
+ break;
+
+ /* (EXIT) End subscript */
+ case 0x1C:
+
+ result = SSTACK_Pop(thread->stack, &data);
+
+ if (result != STACK_SUCCESS) {
+
+ CON_Print("Script execution complete.");
+ thread->executing = 0;
+ } else {
+
+ thread->i_offset = data;
+ }
+ break;
+
+ /*-------------------------------------------------------------*\
+ * BRANCH INSTRUCTIONS
+ \*-------------------------------------------------------------*/
+
+ /* (JMP): Unconditional jump */
+ case 0x1D:
+
+ param1 = ys_read_u16_le(read_p, &read_p);
+ thread->i_offset = (unsigned long)param1;
+
+ break;
+
+ /* (JNZP): Jump if nonzero + POP */
+ case 0x1E:
+
+ param1 = ys_read_u16_le(read_p, &read_p);
+
+ SSTACK_Pop(thread->stack, &data);
+ if (data) {
+ thread->i_offset = (unsigned long)param1;
+ }
+
+ break;
+
+ /* (JZP): Jump if zero + POP */
+ case 0x1F:
+
+ param1 = ys_read_u16_le(read_p, &read_p);
+
+ SSTACK_Pop(thread->stack, &data);
+ if (!data) {
+ thread->i_offset = (unsigned long)param1;
+ }
+
+ break;
+
+ /* (JNZ): Jump if nonzero */
+ case 0x20:
+
+ param1 = ys_read_u16_le(read_p, &read_p);
+
+ SSTACK_Top(thread->stack, &data);
+ if (data) {
+ thread->i_offset = (unsigned long)param1;
+ }
+
+ break;
+
+ /* (JZ): Jump if zero */
+ case 0x21:
+
+ param1 = ys_read_u16_le(read_p, &read_p);
+
+ SSTACK_Top(thread->stack, &data);
+ if (!data) {
+ thread->i_offset = (unsigned long)param1;
+ }
+
+ break;
+
+ /* (JMPR): Relative jump */
+ case 0x57:
+
+ /* ignored? */
+ ys_read_u16_le(read_p, &read_p);
+ ys_read_u16_le(read_p, &read_p);
+
+ iparam1 = (long)*read_p++;
+
+ thread->i_offset += iparam1;
+ break;
+
+ /* (SWCH): Switch */
+ case 0x22:
+ {
+
+ int n_switch;
+ unsigned int switch_num;
+ unsigned int switch_jmp;
+ unsigned int default_jmp;
+ int case_found = 0;
+
+ SSTACK_Pop(thread->stack, &data);
+
+ n_switch = ys_read_u16_le(read_p, &read_p);
+
+ for (i = 0; i < n_switch; i++) {
+
+ switch_num =
+ ys_read_u16_le(read_p, &read_p);
+ switch_jmp =
+ ys_read_u16_le(read_p, &read_p);
+
+ /* Found the specified case */
+ if (data == (SDataWord_T) switch_num) {
+
+ thread->i_offset = switch_jmp;
+ case_found = 1;
+ break;
+ }
+ }
+
+ /* Jump to default case */
+ if (!case_found) {
+
+ default_jmp =
+ ys_read_u16_le(read_p, &read_p);
+ thread->i_offset = default_jmp;
+ }
+
+ }
+ break;
+
+ /* (RJMP): Random branch */
+ case 0x24:
+ {
+ int n_branch;
+ unsigned int branch_wt;
+ unsigned int branch_jmp;
+
+ int rand_sel = 0;
+ int branch_found = 0;
+
+ /* Ignored? */
+ ys_read_u16_le(read_p, &read_p);
+
+ n_branch = ys_read_u16_le(read_p, &read_p);
+
+ for (i = 0; i < n_branch; i++) {
+
+ branch_wt =
+ ys_read_u16_le(read_p, &read_p);
+ branch_jmp =
+ ys_read_u16_le(read_p, &read_p);
+
+ if (rand_sel == i) {
+
+ thread->i_offset = branch_jmp;
+ branch_found = 1;
+ break;
+ }
+ }
+
+ if (!branch_found) {
+ CON_Print(S_ERROR_PREFIX
+ "%X: Random jump target out of "
+ "bounds.", thread->i_offset);
+ }
+
+ }
+ break;
+
+ /*-------------------------------------------------------------*\
+ * MISC. INSTRUCTIONS
+ \*-------------------------------------------------------------*/
+
+ /* (NEG) Negate stack by 2's complement */
+ case 0x25:
+
+ SSTACK_Pop(thread->stack, &data);
+ data = ~data;
+ data++;
+ SSTACK_Push(thread->stack, data);
+
+ break;
+
+ /* (TSTZ) Test for zero */
+ case 0x26:
+
+ SSTACK_Pop(thread->stack, &data);
+ data = data ? 0 : 1;
+ SSTACK_Push(thread->stack, data);
+
+ break;
+
+ /* (NOT) Binary not */
+ case 0x27:
+
+ SSTACK_Pop(thread->stack, &data);
+ data = ~data;
+ SSTACK_Push(thread->stack, data);
+
+ break;
+
+ /* (?) */
+ case 0x28:
+ unhandled = 1;
+ printf("??? ");
+ read_p++;
+ ys_read_u16_le(read_p, &read_p);
+ break;
+
+ /* (?) */
+ case 0x29:
+ unhandled = 1;
+ printf("??? ");
+ read_p++;
+ ys_read_u16_le(read_p, &read_p);
+ break;
+
+ /* (?) */
+ case 0x2A:
+ unhandled = 1;
+ printf("??? ");
+ read_p++;
+ ys_read_u16_le(read_p, &read_p);
+ break;
+
+ /* (?) */
+ case 0x2B:
+ unhandled = 1;
+ printf("??? ");
+ read_p++;
+ ys_read_u16_le(read_p, &read_p);
+ break;
+
+ /*-------------------------------------------------------------*\
+ * ARITHMETIC INSTRUCTIONS
+ \*-------------------------------------------------------------*/
+
+ /* (ADD): Addition */
+ case 0x2C:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+ iparam2 = (long)param2;
+ iparam1 = (long)param1;
+
+ iresult = iparam1 + iparam2;
+
+ SSTACK_Push(thread->stack, (SDataWord_T) iresult);
+ break;
+
+ /* (SUB): Subtraction */
+ case 0x2D:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+ iparam2 = (long)param2;
+ iparam1 = (long)param1;
+
+ iresult = iparam1 - iparam2;
+
+ SSTACK_Push(thread->stack, (SDataWord_T) iresult);
+ break;
+
+ /* (MULT): Integer multiplication */
+ case 0x2E:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+ iparam2 = (long)param2;
+ iparam1 = (long)param1;
+
+ iresult = iparam1 * iparam2;
+
+ SSTACK_Push(thread->stack, (SDataWord_T) iresult);
+ break;
+
+ /* (DIB): Integer division */
+ case 0x2F:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+ iparam2 = (long)param2;
+ iparam1 = (long)param1;
+
+ iresult = iparam1 / iparam2;
+
+ SSTACK_Push(thread->stack, (SDataWord_T) iresult);
+ break;
+
+ /* (MOD) Modulus */
+ case 0x30:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+ iparam2 = (long)param2;
+ iparam1 = (long)param1;
+
+ iresult = iparam1 % iparam2;
+
+ SSTACK_Push(thread->stack, (SDataWord_T) iresult);
+ break;
+
+ /* (EQU) Test equality */
+ case 0x33:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+ iparam2 = (long)param2;
+ iparam1 = (long)param1;
+
+ data = (iparam1 == iparam2) ? 1 : 0;
+
+ SSTACK_Push(thread->stack, data);
+ break;
+
+ /* (NEQU) Test inequality */
+ case 0x34:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+ iparam2 = (long)param2;
+ iparam1 = (long)param1;
+
+ data = (iparam1 != iparam2) ? 1 : 0;
+
+ SSTACK_Push(thread->stack, data);
+ break;
+
+ /* (GRT) Test Greater-than */
+ case 0x35:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+ iparam2 = (long)param2;
+ iparam1 = (long)param1;
+
+ data = (iparam1 > iparam2) ? 1 : 0;
+
+ SSTACK_Push(thread->stack, data);
+ break;
+
+ /* (LST) Test Less-than */
+ case 0x36:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+ iparam2 = (long)param2;
+ iparam1 = (long)param1;
+
+ data = (iparam1 < iparam2) ? 1 : 0;
+
+ SSTACK_Push(thread->stack, data);
+ break;
+
+ /* (GRTE) Test Greater-than or Equal to */
+ case 0x37:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+ iparam2 = (long)param2;
+ iparam1 = (long)param1;
+
+ data = (iparam1 >= iparam2) ? 1 : 0;
+
+ SSTACK_Push(thread->stack, data);
+ break;
+
+ /* (LSTE) Test Less-than or Equal to */
+ case 0x38:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+ iparam2 = (long)param2;
+ iparam1 = (long)param1;
+
+ data = (iparam1 <= iparam2) ? 1 : 0;
+
+ SSTACK_Push(thread->stack, data);
+ break;
+
+ /* (SHR): Arithmetic binary shift right */
+ case 0x3F:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+
+ iparam2 = (long)param2;
+
+ /* Preserve most significant bit */
+ data =
+ (0x01 << ((sizeof param1 * CHAR_BIT) -
+ 1)) & param1;
+
+ for (i = 0; i < (int)iparam2; i++) {
+ param1 >>= 1;
+ param1 |= data;
+ }
+
+ SSTACK_Push(thread->stack, param1);
+ break;
+
+ /*-------------------------------------------------------------*\
+ * BITWISE INSTRUCTIONS
+ \*-------------------------------------------------------------*/
+
+ /* (SHL) Binary shift left */
+ case 0x40:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+
+ param1 <<= param2;
+
+ SSTACK_Push(thread->stack, param1);
+ break;
+
+ /* (AND) Binary AND */
+ case 0x41:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+
+ param1 &= param2;
+
+ SSTACK_Push(thread->stack, param1);
+ break;
+
+ /* (OR) Binary OR */
+ case 0x42:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+
+ param1 |= param2;
+
+ SSTACK_Push(thread->stack, param1);
+ break;
+
+ /* (XOR) Binary XOR */
+ case 0x43:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+
+ param1 ^= param2;
+
+ SSTACK_Push(thread->stack, param1);
+ break;
+
+ /*-------------------------------------------------------------*\
+ * BOOLEAN LOGIC INSTRUCTIONS
+ \*-------------------------------------------------------------*/
+
+ /* (LAND): Logical AND */
+ case 0x44:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+
+ data = (param1 && param2) ? 1 : 0;
+
+ SSTACK_Push(thread->stack, data);
+ break;
+
+ /* (LOR): Logical OR */
+ case 0x45:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+
+ data = (param1 || param2) ? 1 : 0;
+
+ SSTACK_Push(thread->stack, data);
+ break;
+
+ /* (LXOR): Logical XOR */
+ case 0x46:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+
+ data = ((param1) ? !(param2) : !!(param2));
+
+ SSTACK_Push(thread->stack, data);
+ break;
+
+ /*-------------------------------------------------------------*\
+ * GAME INSTRUCTIONS
+ \*-------------------------------------------------------------*/
+
+ /* (DLGP): Play Character Dialogue */
+ case 0x53:
+ {
+ int n_voices;
+ int a_index;
+ int voice_rn;
+
+ n_voices = *read_p++;
+ param1 =
+ (SDataWord_T) ys_read_u16_le(read_p,
+ &read_p);
+
+ /* ignored ? */
+ *read_p++;
+ ys_read_u16_le(read_p, &read_p);
+
+ a_index = ACTOR_GetActorIndex(param1);
+
+ if (a_index < 0) {
+ CON_Print(S_WARN_PREFIX
+ "%X: DLGP Actor id not found.",
+ thread->i_offset);
+ }
+
+ for (i = 0; i < n_voices; i++) {
+
+ SSTACK_Pop(thread->stack, &data);
+
+ if (a_index < 0)
+ continue;
+
+ if (!ScriptModule.voice_lut_present) {
+ voice_rn = -1;
+ } else {
+ voice_rn =
+ ScriptModule.
+ current_script->voice->
+ voices[data];
+ }
+
+ ACTOR_Speak(a_index,
+ ScriptModule.current_script->diag->
+ str[data], voice_rn, &thread->sem);
+
+ }
+
+ }
+ break;
+
+ /* (DLGS): Initialize dialogue interface */
+ case 0x54:
+ break;
+
+ /* (DLGX): Run dialogue interface */
+ case 0x55:
+ break;
+
+ /* (DLGO): Add a dialogue option to interface */
+ case 0x56:
+ {
+ int param1;
+ int param2;
+ int param3;
+
+ printf("DLGO | ");
+ param1 = *read_p++;
+ param2 = *read_p++;
+
+ printf("%02X %02X ", param1, param2);
+
+ if (param2 > 0) {
+ param3 =
+ ys_read_u16_le(read_p, &read_p);
+
+ printf("%04X", param3);
+ }
+ }
+ break;
+
+ /*-------------------------------------------------------------*\
+ * End instruction list
+ \*-------------------------------------------------------------*/
+
+ default:
+
+ CON_Print(S_ERROR_PREFIX
+ "%X: Invalid opcode encountered: " "(%X).\n",
+ thread->i_offset, in_char);
+ thread->executing = 0;
+
+ break;
+
+ } /* end switch( in_char ) */
+
+ /* Set instruction offset only if a previous instruction didn't
+ * branch */
+ if (saved_offset == thread->i_offset) {
+
+ thread->i_offset = GetReadOffset(read_p);
+ }
+
+ if (unhandled) {
+
+ CON_Print(S_ERROR_PREFIX "%X: Unhandled opcode.\n",
+ thread->i_offset);
+ thread->executing = 0;
+ }
+
+ if (thread->executing && debug_print) {
+ SDEBUG_PrintInstr(thread);
+ }
+
+ }
+
+ return R_SUCCESS;
+}
+
+} // End of namespace Saga
+
diff --git a/saga/sthread.h b/saga/sthread.h
new file mode 100644
index 0000000000..0ab86dfff1
--- /dev/null
+++ b/saga/sthread.h
@@ -0,0 +1,69 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ Scripting module thread management component header file
+
+ Notes:
+*/
+
+#ifndef SAGA_STHREAD_H__
+#define SAGA_STHREAD_H__
+
+#include "sstack.h"
+
+namespace Saga {
+
+#define STHREAD_DEF_INSTR_COUNT 7
+
+struct R_SEMAPHORE_tag {
+ int hold_count;
+};
+
+struct R_SCRIPT_THREAD_tag {
+ int executing;
+
+ int sleep_time;
+ int ep_num; /* Entrypoint number */
+ unsigned long ep_offset; /* Entrypoint offset */
+ unsigned long i_offset; /* Instruction offset */
+
+ R_SEMAPHORE sem;
+
+ SSTACK stack;
+};
+
+R_SCRIPT_THREAD *STHREAD_Create(void);
+int STHREAD_Destroy(R_SCRIPT_THREAD *thread);
+int STHREAD_SetEntrypoint(R_SCRIPT_THREAD *thread, int ep_num);
+int STHREAD_Execute(R_SCRIPT_THREAD *thread, int ep_num);
+int STHREAD_Run(R_SCRIPT_THREAD *thread, int instr_limit, int msec);
+unsigned long GetReadOffset(const uchar *read_p);
+unsigned char *GetReadPtr(R_SCRIPT_THREAD *thread);
+int SDEBUG_PrintInstr(R_SCRIPT_THREAD *thread);
+
+} // End of namespace Saga
+
+#endif /* SAGA_STHREAD_H__ */
diff --git a/saga/sys_fs.cpp b/saga/sys_fs.cpp
new file mode 100644
index 0000000000..4fd26c5356
--- /dev/null
+++ b/saga/sys_fs.cpp
@@ -0,0 +1,82 @@
+/* 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 "reinherit.h"
+
+namespace Saga {
+
+int
+SYSFS_GetFQFN(const char *f_dir, const char *f_name, char *buf, size_t buf_len)
+{
+ size_t f_dir_len;
+ size_t f_name_len;
+ char sep_buf[2] = { R_DIRECTORY_SEP };
+
+ size_t i;
+
+ if ((f_dir == NULL) || (f_name == NULL) || (buf == NULL)) {
+
+ return R_FAILURE;
+ }
+
+ f_dir_len = strlen(f_dir);
+ f_name_len = strlen(f_name);
+
+ buf[0] = 0;
+
+ strncat(buf, f_dir, buf_len);
+
+#if R_DIRECTORY_SEP != '/'
+ /* Convert frontslashes to backslashes */
+ for (i = 0; i < f_dir_len; i++) {
+ if (buf[i] == '/') {
+ buf[i] = R_DIRECTORY_SEP;
+ }
+ }
+#endif
+
+ for (i = f_dir_len - 1; i > 0; i--) {
+
+ /* Remove any trailing whitespace */
+ if (isspace(buf[i])) {
+ buf[i] = 0;
+ } else {
+ break;
+ }
+ }
+
+ f_dir_len = strlen(buf);
+
+ if (buf[f_dir_len - 1] != R_DIRECTORY_SEP) {
+
+ /* Append a proper directory separator if req. */
+ strncat(buf, sep_buf, buf_len);
+ }
+
+ strncat(buf, f_name, buf_len);
+
+ return R_SUCCESS;
+}
+
+} // End of namespace Saga
+
+
diff --git a/saga/sys_interface.h b/saga/sys_interface.h
new file mode 100644
index 0000000000..51391ccbdd
--- /dev/null
+++ b/saga/sys_interface.h
@@ -0,0 +1,49 @@
+/****************************************************************************\
+ ____ ___ _ _ _
+| _ \ ___|_ _|_ __ | |__ ___ _ __(_) |_
+| |_) / _ \| || '_ \| '_ \ / _ \ '__| | __|
+| _ < __/| || | | | | | | __/ | | | |_
+|_| \_\___|___|_| |_|_| |_|\___|_| |_|\__|
+
+ ----------------------------------------------------------------------------
+ Project: ReInherit Engine
+ Version: .1a
+
+ The ReInherit Engine is (C)2000-2001 by Daniel Balsom
+ This code is subject to the terms and conditions of the General Public
+ License (GPL).
+
+ ----------------------------------------------------------------------------
+
+ File: sys_interface.h
+ Revision: $Revision$
+
+ Description:
+
+ (Linux) System-specific interface data
+
+ Notes:
+
+\****************************************************************************/
+#ifndef REINHERIT_SYSINTERFACE_H
+#define REINHERIT_SYSINTERFACE_H
+
+namespace Saga {
+
+#define BYTE unsigned char
+#define WORD unsigned short
+#define DWORD unsigned int
+
+#define R_CFGFILE_NAME ".reinheritrc"
+
+#define R_DIRECTORY_SEP '/'
+
+#define R_STDOUT stdout
+#define R_STDERR stderr
+
+#define R_printf fprintf
+#define R_vprintf vfprintf
+
+} // End of namespace Saga
+
+#endif /* REINHERIT_SYSTYPES_H */
diff --git a/saga/sysgfx.cpp b/saga/sysgfx.cpp
new file mode 100644
index 0000000000..bcdcd6dc6d
--- /dev/null
+++ b/saga/sysgfx.cpp
@@ -0,0 +1,548 @@
+/* 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 "reinherit.h"
+
+#include <SDL.h>
+#include <limits.h>
+
+/*
+ * Begin module component
+\*--------------------------------------------------------------------------*/
+#include "sysgfx.h"
+
+namespace Saga {
+
+R_SYSGFX_MODULE SGfxModule;
+
+static SDL_Color cur_pal[R_PAL_ENTRIES];
+
+int SYSGFX_Init(R_SYSGFX_INIT * gfx_init)
+{
+ SDL_Surface *sdl_screen;
+ R_SURFACE r_screen;
+
+ SDL_Surface *sdl_back_buf;
+ R_SURFACE r_back_buf;
+
+ int result;
+ Uint32 flags;
+
+ assert(gfx_init != NULL);
+
+ if (gfx_init->fullscreen) {
+ flags = SDL_FULLSCREEN | SDL_HWPALETTE;
+ } else {
+ flags = SDL_HWPALETTE;
+ }
+
+ /* Test video mode availability
+ * \*------------------------------------------------------------- */
+ result = SDL_VideoModeOK(gfx_init->screen_w,
+ gfx_init->screen_h, gfx_init->screen_bpp, flags);
+ if (result == 0) {
+ R_printf(R_STDERR,
+ "Requested video mode (%d x %d @ %d bpp) "
+ "is unavailable.\n",
+ gfx_init->screen_w,
+ gfx_init->screen_h, gfx_init->screen_bpp);
+
+ return R_FAILURE;
+ }
+
+ /* Set the video mode
+ * \*------------------------------------------------------------- */
+ sdl_screen = SDL_SetVideoMode(gfx_init->screen_w,
+ gfx_init->screen_h, gfx_init->screen_bpp, flags);
+ if (sdl_screen == NULL) {
+
+ R_printf(R_STDERR,
+ "Unable to set video mode (%d x %d @ %d bpp).\n",
+ gfx_init->screen_w,
+ gfx_init->screen_h, gfx_init->screen_bpp);
+
+ R_printf(R_STDERR, "SDL reports: %s\n", SDL_GetError());
+
+ return R_FAILURE;
+ }
+
+ R_printf(R_STDOUT,
+ "Set video mode: (%d x %d @ %d bpp)\n",
+ sdl_screen->w, sdl_screen->h, sdl_screen->format->BitsPerPixel);
+
+ /* Convert sdl surface data to R surface data */
+ r_screen.buf = (uchar *)sdl_screen->pixels;
+ r_screen.buf_w = sdl_screen->w;
+ r_screen.buf_h = sdl_screen->h;
+ r_screen.buf_pitch = sdl_screen->pitch;
+ r_screen.bpp = gfx_init->screen_bpp;
+
+ r_screen.clip_rect.x1 = 0;
+ r_screen.clip_rect.y1 = 0;
+ r_screen.clip_rect.x2 = sdl_screen->w - 1;
+ r_screen.clip_rect.y2 = sdl_screen->h - 1;
+
+ r_screen.impl_src = sdl_screen;
+
+ /* Create the back buffer
+ * \*------------------------------------------------------------- */
+ sdl_back_buf = SDL_CreateRGBSurface(SDL_SWSURFACE,
+ gfx_init->backbuf_w,
+ gfx_init->backbuf_h, gfx_init->backbuf_bpp, 0, 0, 0, 0);
+ if (sdl_back_buf == NULL) {
+
+ R_printf(R_STDERR,
+ "Unable to create back buffer (%d x %d @ %d bpp).\n",
+ gfx_init->backbuf_w,
+ gfx_init->backbuf_h, gfx_init->backbuf_bpp);
+
+ R_printf(R_STDERR, "SDL reports: %s.\n", SDL_GetError());
+
+ return R_FAILURE;
+ }
+
+ /* Convert sdl surface data to R surface data
+ * \*------------------------------------------------------------- */
+ r_back_buf.buf = (uchar *)sdl_back_buf->pixels;
+ r_back_buf.buf_w = sdl_back_buf->w;
+ r_back_buf.buf_h = sdl_back_buf->h;
+ r_back_buf.buf_pitch = sdl_back_buf->pitch;
+ r_back_buf.bpp = gfx_init->backbuf_bpp;
+
+ r_back_buf.clip_rect.x1 = 0;
+ r_back_buf.clip_rect.y1 = 0;
+ r_back_buf.clip_rect.x2 = sdl_back_buf->w - 1;
+ r_back_buf.clip_rect.y2 = sdl_back_buf->h - 1;
+
+ r_back_buf.impl_src = sdl_back_buf;
+
+ /* Set module data
+ * \*------------------------------------------------------------- */
+ SGfxModule.sdl_screen = sdl_screen;
+ SGfxModule.r_screen = r_screen;
+ SGfxModule.sdl_back_buf = sdl_back_buf;
+ SGfxModule.r_back_buf = r_back_buf;
+
+ SGfxModule.init = 1;
+
+ return R_SUCCESS;
+}
+
+R_SURFACE *SYSGFX_GetScreenSurface(void)
+{
+ return &SGfxModule.r_screen;
+}
+
+R_SURFACE *SYSGFX_GetBackBuffer(void)
+{
+ return &SGfxModule.r_back_buf;
+}
+
+int SYSGFX_LockSurface(R_SURFACE * surface)
+{
+ int result;
+
+ assert(surface != NULL);
+
+ result = SDL_LockSurface((SDL_Surface *) surface->impl_src);
+
+ return (result == 0) ? R_SUCCESS : R_FAILURE;
+}
+
+int SYSGFX_UnlockSurface(R_SURFACE * surface)
+{
+ assert(surface != NULL);
+
+ SDL_UnlockSurface((SDL_Surface *) surface->impl_src);
+
+ return R_SUCCESS;
+}
+
+R_SURFACE *SYSGFX_FormatToDisplay(R_SURFACE * surface)
+{
+ R_SURFACE *new_r_surface;
+ SDL_Surface *new_sdl_surface;
+
+ new_r_surface = (R_SURFACE *)malloc(sizeof *new_r_surface);
+ if (new_r_surface == NULL) {
+ return NULL;
+ }
+
+ new_sdl_surface = SDL_DisplayFormat((SDL_Surface *)surface->impl_src);
+ if (new_sdl_surface == NULL) {
+ free(new_r_surface);
+ return NULL;
+ }
+
+ new_r_surface->buf = (uchar *)new_sdl_surface->pixels;
+ new_r_surface->buf_w = new_sdl_surface->w;
+ new_r_surface->buf_h = new_sdl_surface->h;
+ new_r_surface->buf_pitch = new_sdl_surface->pitch;
+ new_r_surface->bpp = new_sdl_surface->format->BitsPerPixel;
+
+ new_r_surface->clip_rect.x1 = 0;
+ new_r_surface->clip_rect.y1 = 0;
+ new_r_surface->clip_rect.x2 = new_sdl_surface->w - 1;
+ new_r_surface->clip_rect.y2 = new_sdl_surface->h - 1;
+
+ new_r_surface->impl_src = new_sdl_surface;
+
+ return new_r_surface;
+}
+
+R_SURFACE *SYSGFX_CreateSurface(int w, int h, int bpp)
+{
+ R_SURFACE *new_surface;
+ SDL_Surface *new_sdl_surface;
+
+ assert(bpp == 8); /* 16bpp not supported, maybe not necessary? */
+ assert((w > 0) && (h > 0));
+
+ new_surface = (R_SURFACE *)malloc(sizeof *new_surface);
+ if (new_surface == NULL) {
+ return NULL;
+ }
+
+ new_sdl_surface =
+ SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, bpp, 0, 0, 0, 0);
+ if (new_sdl_surface == NULL) {
+
+ free(new_surface);
+ return NULL;
+ }
+
+ new_surface->buf_w = new_sdl_surface->w;
+ new_surface->buf_h = new_sdl_surface->h;
+ new_surface->buf_pitch = new_sdl_surface->pitch;
+ new_surface->bpp = new_sdl_surface->format->BitsPerPixel;
+
+ new_surface->clip_rect.x1 = 0;
+ new_surface->clip_rect.y1 = 0;
+ new_surface->clip_rect.x2 = w - 1;
+ new_surface->clip_rect.y2 = h - 1;
+
+ new_surface->impl_src = new_sdl_surface;
+
+ return new_surface;
+}
+
+int SYSGFX_DestroySurface(R_SURFACE * surface)
+{
+ SDL_FreeSurface((SDL_Surface *) surface->impl_src);
+
+ free(surface);
+
+ return R_SUCCESS;
+}
+
+int SYSGFX_GetWhite(void)
+{
+ return SGfxModule.white_index;
+}
+
+int SYSGFX_GetBlack(void)
+{
+ return SGfxModule.black_index;
+}
+
+int SYSGFX_MatchColor(unsigned long colormask)
+{
+
+ int i;
+
+ int red = (colormask & 0x0FF0000UL) >> 16;
+ int green = (colormask & 0x000FF00UL) >> 8;
+ int blue = colormask & 0x00000FFUL;
+
+ int dr;
+ int dg;
+ int db;
+
+ long color_delta;
+ long best_delta = LONG_MAX;
+ int best_index = 0;
+
+ for (i = 0; i < R_PAL_ENTRIES; i++) {
+
+ dr = cur_pal[i].r - red;
+ dr = ABS(dr);
+
+ dg = cur_pal[i].g - green;
+ dg = ABS(dg);
+
+ db = cur_pal[i].b - blue;
+ db = ABS(db);
+
+#if R_COLORSEARCH_SQUARE
+ color_delta = (long)((dr * dr) * R_RED_WEIGHT +
+ (dg * dg) * R_GREEN_WEIGHT + (db * db) * R_BLUE_WEIGHT);
+#else
+ color_delta = (long)(dr * R_RED_WEIGHT +
+ dg * R_GREEN_WEIGHT + db * R_BLUE_WEIGHT);
+#endif
+ if (color_delta == 0) {
+ return i;
+ }
+
+ if (color_delta < best_delta) {
+ best_delta = color_delta;
+ best_index = i;
+ }
+ }
+
+ return best_index;
+}
+
+int SYSGFX_SetPalette(R_SURFACE *surface, PALENTRY *pal)
+{
+
+ uchar red;
+ uchar green;
+ uchar blue;
+
+ int color_delta;
+ int best_wdelta = 0;
+ int best_windex = 0;
+ int best_bindex = 0;
+ int best_bdelta = 1000;
+
+ int i;
+
+ for (i = 0; i < R_PAL_ENTRIES; i++) {
+
+ red = pal[i].red;
+ cur_pal[i].r = red;
+
+ color_delta = red;
+
+ green = pal[i].green;
+ cur_pal[i].g = green;
+
+ color_delta += green;
+
+ blue = pal[i].blue;
+ cur_pal[i].b = blue;
+
+ color_delta += blue;
+
+ if (color_delta < best_bdelta) {
+ best_bindex = i;
+ best_bdelta = color_delta;
+ }
+
+ if (color_delta > best_wdelta) {
+ best_windex = i;
+ best_wdelta = color_delta;
+ }
+ }
+
+ /* Set whitest and blackest color indices */
+ SGfxModule.white_index = best_windex;
+ SGfxModule.black_index = best_bindex;
+
+ /* If the screen surface is palettized, set the screen palette.
+ * If the screen surface is not palettized, set the palette of
+ * the surface parameter */
+ if (SGfxModule.r_screen.bpp < 16) {
+
+ SDL_SetColors(SGfxModule.sdl_screen, cur_pal, 0,
+ R_PAL_ENTRIES);
+ } else {
+
+ SDL_SetColors((SDL_Surface *) surface->impl_src,
+ cur_pal, 0, R_PAL_ENTRIES);
+ }
+
+ return R_SUCCESS;
+}
+
+int SYSGFX_GetCurrentPal(PALENTRY * src_pal)
+{
+
+ int i;
+
+ for (i = 0; i < R_PAL_ENTRIES; i++) {
+
+ src_pal[i].red = cur_pal[i].r;
+ src_pal[i].green = cur_pal[i].g;
+ src_pal[i].blue = cur_pal[i].b;
+ }
+
+ return R_SUCCESS;
+}
+
+int SYSGFX_PalToBlack(R_SURFACE * surface, PALENTRY * src_pal, double percent)
+{
+
+ int i;
+
+ /*int fade_max = 255; */
+ int new_entry;
+
+ double fpercent;
+
+ if (percent > 1.0) {
+ percent = 1.0;
+ }
+
+ /* Exponential fade */
+ fpercent = percent * percent;
+
+ fpercent = 1.0 - fpercent;
+
+ /* Use the correct percentage change per frame for each palette entry */
+ for (i = 0; i < R_PAL_ENTRIES; i++) {
+
+ new_entry = (int)(src_pal[i].red * fpercent);
+
+ if (new_entry < 0) {
+ cur_pal[i].r = 0;
+ } else {
+ cur_pal[i].r = (uchar) new_entry;
+ }
+
+ new_entry = (int)(src_pal[i].green * fpercent);
+
+ if (new_entry < 0) {
+ cur_pal[i].g = 0;
+ } else {
+ cur_pal[i].g = (uchar) new_entry;
+ }
+
+ new_entry = (int)(src_pal[i].blue * fpercent);
+
+ if (new_entry < 0) {
+ cur_pal[i].b = 0;
+ } else {
+ cur_pal[i].b = (uchar) new_entry;
+ }
+ }
+
+ /* If the screen surface is palettized, set the screen palette.
+ * If the screen surface is not palettized, set the palette of
+ * the surface parameter */
+ if (SGfxModule.r_screen.bpp < 16) {
+
+ SDL_SetColors(SGfxModule.sdl_screen, cur_pal, 0,
+ R_PAL_ENTRIES);
+ } else {
+
+ SDL_SetColors((SDL_Surface *) surface->impl_src,
+ cur_pal, 0, R_PAL_ENTRIES);
+ }
+
+ return R_SUCCESS;
+
+}
+
+int SYSGFX_BlackToPal(R_SURFACE * surface, PALENTRY * src_pal, double percent)
+{
+
+ int new_entry;
+ double fpercent;
+
+ int color_delta;
+ int best_wdelta = 0;
+ int best_windex = 0;
+ int best_bindex = 0;
+ int best_bdelta = 1000;
+
+ int i;
+
+ if (percent > 1.0) {
+ percent = 1.0;
+ }
+
+ /* Exponential fade */
+ fpercent = percent * percent;
+
+ fpercent = 1.0 - fpercent;
+
+ /* Use the correct percentage change per frame for each palette entry */
+ for (i = 0; i < R_PAL_ENTRIES; i++) {
+
+ new_entry = (int)(src_pal[i].red - src_pal[i].red * fpercent);
+
+ if (new_entry < 0) {
+ cur_pal[i].r = 0;
+ } else {
+ cur_pal[i].r = (uchar) new_entry;
+ }
+
+ new_entry =
+ (int)(src_pal[i].green - src_pal[i].green * fpercent);
+
+ if (new_entry < 0) {
+ cur_pal[i].g = 0;
+ } else {
+ cur_pal[i].g = (uchar) new_entry;
+ }
+
+ new_entry =
+ (int)(src_pal[i].blue - src_pal[i].blue * fpercent);
+
+ if (new_entry < 0) {
+ cur_pal[i].b = 0;
+ } else {
+ cur_pal[i].b = (uchar) new_entry;
+ }
+ }
+
+ /* Find the best white and black color indices again */
+ if (percent >= 1.0) {
+
+ for (i = 0; i < R_PAL_ENTRIES; i++) {
+
+ color_delta = cur_pal[i].r;
+ color_delta += cur_pal[i].g;
+ color_delta += cur_pal[i].b;
+
+ if (color_delta < best_bdelta) {
+ best_bindex = i;
+ best_bdelta = color_delta;
+ }
+
+ if (color_delta > best_wdelta) {
+ best_windex = i;
+ best_wdelta = color_delta;
+ }
+ }
+ }
+
+ /* If the screen surface is palettized, set the screen palette.
+ * If the screen surface is not palettized, set the palette of
+ * the surface parameter */
+ if (SGfxModule.r_screen.bpp < 16) {
+
+ SDL_SetColors(SGfxModule.sdl_screen, cur_pal, 0,
+ R_PAL_ENTRIES);
+ } else {
+
+ SDL_SetColors((SDL_Surface *) surface->impl_src,
+ cur_pal, 0, R_PAL_ENTRIES);
+ }
+
+ return R_SUCCESS;
+}
+
+} // End of namespace Saga
+
diff --git a/saga/sysgfx.h b/saga/sysgfx.h
new file mode 100644
index 0000000000..3d37e29fdb
--- /dev/null
+++ b/saga/sysgfx.h
@@ -0,0 +1,51 @@
+/* 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 SYSGFX_H_
+#define SYSGFX_H_
+
+namespace Saga {
+
+#define R_COLORSEARCH_SQUARE 0
+
+#define R_RED_WEIGHT 0.299
+#define R_GREEN_WEIGHT 0.587
+#define R_BLUE_WEIGHT 0.114
+
+typedef struct R_SYSGFX_MODULE_tag {
+
+ int init;
+
+ SDL_Surface *sdl_screen; /* Screen surface */
+ R_SURFACE r_screen;
+
+ SDL_Surface *sdl_back_buf; /* Double buffer surface */
+ R_SURFACE r_back_buf;
+
+ int white_index;
+ int black_index;
+
+} R_SYSGFX_MODULE;
+
+} // End of namespace Saga
+
+#endif /* SYSGFX_H_ */
diff --git a/saga/sysinput.cpp b/saga/sysinput.cpp
new file mode 100644
index 0000000000..4edab7ce22
--- /dev/null
+++ b/saga/sysinput.cpp
@@ -0,0 +1,238 @@
+/* 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 "reinherit.h"
+
+#include <SDL.h>
+
+/*
+ * Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "actor_mod.h"
+#include "console_mod.h"
+#include "interface_mod.h"
+#include "render_mod.h"
+#include "scene_mod.h"
+#include "script_mod.h"
+
+namespace Saga {
+
+/*
+ * Begin module component
+\*--------------------------------------------------------------------------*/
+
+int SYSINPUT_Init(void)
+{
+
+ SDL_EnableUNICODE(1);
+ SDL_EnableKeyRepeat(200, 30);
+
+ return R_SUCCESS;
+}
+
+int SYSINPUT_ProcessInput(void)
+{
+ SDL_Event sdl_event;
+
+ int mouse_x, mouse_y;
+ R_POINT imouse_pt;
+
+ SYSINPUT_GetMousePos(&mouse_x, &mouse_y);
+
+ imouse_pt.x = mouse_x;
+ imouse_pt.y = mouse_y;
+
+ RENDER_ConvertMousePt(&imouse_pt);
+
+ while (SDL_PollEvent(&sdl_event)) {
+
+ int in_char;
+
+ switch (sdl_event.type) {
+
+ case SDL_KEYDOWN:
+
+ if (CON_IsActive()) {
+
+ in_char = sdl_event.key.keysym.sym;
+
+ switch (sdl_event.key.keysym.sym) {
+
+ case SDLK_BACKQUOTE:
+ CON_Deactivate();
+ break;
+
+ case SDLK_PAGEUP:
+ CON_PageUp();
+ break;
+
+ case SDLK_PAGEDOWN:
+ CON_PageDown();
+ break;
+
+ case SDLK_UP:
+ case SDLK_KP8:
+ CON_CmdUp();
+ break;
+
+ case SDLK_DOWN:
+ case SDLK_KP2:
+ CON_CmdDown();
+ break;
+
+ default:
+
+ if ((sdl_event.key.keysym.
+ unicode & 0xFF80) == 0) {
+
+ in_char =
+ sdl_event.key.keysym.
+ unicode & 0x7F;
+ if (in_char) {
+ CON_Type(in_char);
+ }
+ } else {
+ R_printf(R_STDOUT,
+ "Ignored UNICODE character.\n");
+ }
+
+ break;
+ }
+
+ break;
+ }
+
+ switch (sdl_event.key.keysym.sym) {
+
+ case SDLK_BACKQUOTE:
+ CON_Activate();
+ break;
+
+ case SDLK_q:
+ R_printf(R_STDOUT, "Quit key pressed.\n");
+ /*goto done; */
+ break;
+
+ case SDLK_r:
+ INTERFACE_Draw();
+ break;
+
+ case SDLK_F1:
+ RENDER_ToggleFlag(RF_SHOW_FPS);
+ break;
+
+ case SDLK_F2:
+ RENDER_ToggleFlag(RF_PALETTE_TEST);
+ break;
+
+ case SDLK_F3:
+ RENDER_ToggleFlag(RF_TEXT_TEST);
+ break;
+
+ case SDLK_F4:
+ RENDER_ToggleFlag(RF_OBJECTMAP_TEST);
+ break;
+
+ case SDLK_1:
+ RENDER_SetMode(RM_NORMAL);
+ break;
+
+ case SDLK_4:
+ RENDER_SetMode(RM_2XSAI);
+ break;
+
+ case SDLK_5:
+ RENDER_SetMode(RM_SUPER2XSAI);
+ break;
+
+ case SDLK_6:
+ RENDER_SetMode(RM_SUPEREAGLE);
+ break;
+
+ case SDLK_TAB:
+ STHREAD_DebugStep();
+ break;
+
+ /* Actual game keys */
+
+ case SDLK_SPACE:
+
+ ACTOR_SkipDialogue();
+ break;
+
+ case SDLK_PAUSE:
+ case SDLK_p:
+ RENDER_ToggleFlag(RF_RENDERPAUSE);
+ break;
+
+ case SDLK_ESCAPE:
+ /* Skip to next scene skip target */
+ SCENE_Skip();
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ case SDL_KEYUP:
+ break;
+
+ case SDL_MOUSEBUTTONDOWN:
+ INTERFACE_Update(&imouse_pt, UPDATE_MOUSECLICK);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return R_SUCCESS;
+}
+
+int SYSINPUT_GetMousePos(int *mouse_x, int *mouse_y)
+{
+
+ SDL_GetMouseState(mouse_x, mouse_y);
+
+ return R_SUCCESS;
+}
+
+int SYSINPUT_HideMouse(void)
+{
+
+ SDL_ShowCursor(SDL_DISABLE);
+
+ return R_SUCCESS;
+}
+
+int SYSINPUT_ShowMouse(void)
+{
+
+ SDL_ShowCursor(SDL_ENABLE);
+
+ return R_SUCCESS;
+}
+
+} // End of namespace Saga
+
diff --git a/saga/sysio.cpp b/saga/sysio.cpp
new file mode 100644
index 0000000000..4f688ba607
--- /dev/null
+++ b/saga/sysio.cpp
@@ -0,0 +1,65 @@
+/* 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 "reinherit.h"
+
+#include "SDL.h"
+
+namespace Saga {
+
+/*
+ * Uses the following modules:
+\*--------------------------------------------------------------------------*/
+
+/*
+ * Begin module component
+\*--------------------------------------------------------------------------*/
+
+int SYSIO_Init(void)
+{
+
+ int result;
+
+ /* Initialize SDL library */
+ result = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_AUDIO);
+
+ if (result != 0) {
+
+ R_printf(R_STDERR, "SDL library initialization failed.\n");
+
+ return R_FAILURE;
+ }
+
+ R_printf(R_STDOUT, "SDL library initialized.\n");
+
+ return R_SUCCESS;
+}
+
+int SYSIO_Shutdown(void)
+{
+
+ return R_SUCCESS;
+}
+
+} // End of namespace Saga
+
diff --git a/saga/sysmusic.cpp b/saga/sysmusic.cpp
new file mode 100644
index 0000000000..2c230679bf
--- /dev/null
+++ b/saga/sysmusic.cpp
@@ -0,0 +1,98 @@
+/* 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 "reinherit.h"
+
+#include "yslib.h"
+
+namespace Saga {
+
+static int MusicInitialized = 0;
+
+int SYSMUSIC_Init(int enabled)
+{
+ YS_IGNORE_PARAM(enabled);
+
+ if (MusicInitialized) {
+ return R_FAILURE;
+ }
+
+ MusicInitialized = 1;
+ return R_SUCCESS;
+}
+
+int SYSMUSIC_Shutdown(void)
+{
+ if (!MusicInitialized) {
+ return R_FAILURE;
+ }
+
+ MusicInitialized = 0;
+ return R_SUCCESS;
+}
+
+int SYSMUSIC_Play(ulong music_rn, uint flags)
+{
+ if (!MusicInitialized) {
+ return R_FAILURE;
+ }
+
+ YS_IGNORE_PARAM(music_rn);
+ YS_IGNORE_PARAM(flags);
+
+ return R_SUCCESS;
+
+}
+
+int SYSMUSIC_Pause(void)
+{
+ if (!MusicInitialized) {
+ return R_FAILURE;
+ }
+
+ return R_SUCCESS;
+
+}
+
+int SYSMUSIC_Resume(void)
+{
+ if (!MusicInitialized) {
+ return R_FAILURE;
+ }
+
+ return R_SUCCESS;
+
+}
+
+int SYSMUSIC_Stop(void)
+{
+
+ if (!MusicInitialized) {
+ return R_FAILURE;
+ }
+
+ return R_SUCCESS;
+
+}
+
+} // End of namespace Saga
+
diff --git a/saga/syssound.cpp b/saga/syssound.cpp
new file mode 100644
index 0000000000..ca50536ffa
--- /dev/null
+++ b/saga/syssound.cpp
@@ -0,0 +1,173 @@
+/* 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 "reinherit.h"
+
+#include "yslib.h"
+
+/*
+ * Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "game_mod.h"
+#include "rscfile_mod.h"
+
+namespace Saga {
+
+/*
+ * Begin module component
+\*--------------------------------------------------------------------------*/
+
+static int SoundInitialized = 0;
+
+static R_RSCFILE_CONTEXT *SoundContext;
+static R_RSCFILE_CONTEXT *VoiceContext;
+
+int SYSSOUND_Init(int enabled)
+{
+
+ int result;
+
+ YS_IGNORE_PARAM(enabled);
+
+ if (SoundInitialized) {
+ return R_FAILURE;
+ }
+
+ /* Load sound module resource file contexts
+ * \*------------------------------------------------------------- */
+ result = GAME_GetFileContext(&SoundContext, R_GAME_SOUNDFILE, 0);
+ if (result != R_SUCCESS) {
+ return R_FAILURE;
+ }
+
+ result = GAME_GetFileContext(&VoiceContext, R_GAME_VOICEFILE, 0);
+ if (result != R_SUCCESS) {
+ return R_FAILURE;
+ }
+
+ SoundInitialized = 1;
+ return R_SUCCESS;
+}
+
+int SYSSOUND_Shutdown()
+{
+ if (!SoundInitialized) {
+ return R_FAILURE;
+ }
+
+ SoundInitialized = 0;
+
+ return R_SUCCESS;
+}
+
+int SYSSOUND_Play(int sound_rn, int channel)
+{
+
+ (void)sound_rn;
+ (void)channel;
+
+ if (!SoundInitialized) {
+ return R_FAILURE;
+ }
+
+ return R_SUCCESS;
+}
+
+int SYSSOUND_Pause(int channel)
+{
+
+ (void)channel;
+
+ if (!SoundInitialized) {
+ return R_FAILURE;
+ }
+
+ return R_SUCCESS;
+}
+
+int SYSSOUND_Resume(int channel)
+{
+
+ (void)channel;
+
+ if (!SoundInitialized) {
+ return R_FAILURE;
+ }
+
+ return R_SUCCESS;
+}
+
+int SYSSOUND_Stop(int channel)
+{
+
+ (void)channel;
+
+ if (!SoundInitialized) {
+ return R_FAILURE;
+ }
+
+ return R_SUCCESS;
+}
+
+int SYSSOUND_PlayVoice(R_SOUNDBUFFER * buf)
+{
+
+ (void)buf;
+
+ if (!SoundInitialized) {
+ return R_FAILURE;
+ }
+
+ return R_SUCCESS;
+}
+
+int SYSSOUND_PauseVoice(void)
+{
+
+ if (!SoundInitialized) {
+ return R_FAILURE;
+ }
+
+ return R_SUCCESS;
+}
+
+int SYSSOUND_ResumeVoice(void)
+{
+
+ if (!SoundInitialized) {
+ return R_FAILURE;
+ }
+
+ return R_SUCCESS;
+}
+
+int SYSSOUND_StopVoice(void)
+{
+
+ if (!SoundInitialized) {
+ return R_FAILURE;
+ }
+
+ return R_SUCCESS;
+}
+
+} // End of namespace Saga
diff --git a/saga/systimer.cpp b/saga/systimer.cpp
new file mode 100644
index 0000000000..dd76f43849
--- /dev/null
+++ b/saga/systimer.cpp
@@ -0,0 +1,144 @@
+/* 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 "reinherit.h"
+
+#include <SDL.h>
+
+/*
+ * Begin module
+\*--------------------------------------------------------------------------*/
+#include "systimer.h"
+
+namespace Saga {
+
+R_SYSTIMER_DATA R_TimerData;
+
+int SYSTIMER_InitMSCounter(void)
+{
+
+ if (R_TimerData.initialized) {
+ return R_FAILURE;
+ }
+
+ R_TimerData.t_previous_ticks = SDL_GetTicks();
+
+ R_TimerData.initialized = 1;
+
+ return R_SUCCESS;
+}
+
+unsigned long SYSTIMER_ReadMSCounter(void)
+{
+
+ Uint32 ms_elapsed = 0;
+
+ if (!R_TimerData.initialized) {
+ return 0;
+ }
+
+ R_TimerData.t_current_ticks = SDL_GetTicks();
+
+ if (R_TimerData.t_current_ticks < R_TimerData.t_previous_ticks) {
+ /* Timer has rolled over after 49 days... */
+ } else {
+ ms_elapsed = R_TimerData.t_current_ticks -
+ R_TimerData.t_previous_ticks;
+
+ R_TimerData.t_previous_ticks = R_TimerData.t_current_ticks;
+ }
+
+ return ms_elapsed;
+}
+
+int SYSTIMER_ResetMSCounter(void)
+{
+
+ if (!R_TimerData.initialized) {
+ return R_FAILURE;
+ }
+
+ R_TimerData.t_previous_ticks = SDL_GetTicks();
+
+ return R_SUCCESS;
+}
+
+int SYSTIMER_Sleep(uint msec)
+{
+ SDL_Delay(msec);
+
+ return R_SUCCESS;
+}
+
+int
+SYSTIMER_CreateTimer(R_SYSTIMER ** timer,
+ unsigned long interval, void *param, R_SYSTIMER_CALLBACK callback)
+{
+ R_SYSTIMER *new_timer = (R_SYSTIMER *)malloc(sizeof *new_timer);
+ if (new_timer == NULL) {
+ return R_MEM;
+ }
+
+ new_timer->t_interval = interval;
+ new_timer->t_param = param;
+ new_timer->t_callback_f = callback;
+
+ *timer = new_timer;
+
+ new_timer->t_sdl_timerid = SDL_AddTimer(interval,
+ SYSTIMER_Callback, new_timer);
+
+ if (new_timer->t_sdl_timerid == NULL) {
+ free(new_timer);
+ *timer = NULL;
+
+ return R_FAILURE;
+ }
+
+ return R_SUCCESS;
+}
+
+int SYSTIMER_DestroyTimer(R_SYSTIMER * timer)
+{
+ if (timer == NULL) {
+ return R_FAILURE;
+ }
+
+ timer->t_running = 0;
+
+ SDL_RemoveTimer(timer->t_sdl_timerid);
+
+ free(timer);
+
+ return R_SUCCESS;
+}
+
+Uint32 SYSTIMER_Callback(Uint32 interval, void *param)
+{
+ R_SYSTIMER *timer_p = (R_SYSTIMER *)param;
+
+ timer_p->t_callback_f(timer_p->t_interval, timer_p->t_param);
+
+ return timer_p->t_interval;
+}
+
+} // End of namespace Saga
diff --git a/saga/systimer.h b/saga/systimer.h
new file mode 100644
index 0000000000..19398ba567
--- /dev/null
+++ b/saga/systimer.h
@@ -0,0 +1,54 @@
+/* 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 SAGA_SYSTIMER_H__
+#define SAGA_SYSTIMER_H__
+
+namespace Saga {
+
+typedef struct R_SYSTIMER_DATA_tag {
+
+ int initialized;
+
+ Uint32 t_start_ticks;
+
+ Uint32 t_current_ticks;
+ Uint32 t_previous_ticks;
+
+} R_SYSTIMER_DATA;
+
+struct R_SYSTIMER_tag {
+
+ int t_running;
+
+ unsigned long t_interval;
+ void *t_param;
+
+ R_SYSTIMER_CALLBACK t_callback_f;
+ SDL_TimerID t_sdl_timerid;
+};
+
+Uint32 SYSTIMER_Callback(Uint32 interval, void *param);
+
+} // End of namespace Saga
+
+#endif /* SAGA_SYSTIMER_H__ */
diff --git a/saga/text.cpp b/saga/text.cpp
new file mode 100644
index 0000000000..80367169c9
--- /dev/null
+++ b/saga/text.cpp
@@ -0,0 +1,342 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Text / dialogue display management module
+
+ Notes:
+*/
+
+#include "reinherit.h"
+
+#include "yslib.h"
+
+/*
+ * Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "font_mod.h"
+
+/*
+ * Begin module
+\*--------------------------------------------------------------------------*/
+#include "text_mod.h"
+#include "text.h"
+
+namespace Saga {
+
+int
+TEXT_Draw(int font_id,
+ R_SURFACE * ds,
+ const char *string,
+ int text_x, int text_y, int color, int effect_color, int flags)
+{
+
+ int string_w;
+ int string_len;
+
+ int fit_w;
+
+ const char *start_p;
+ const char *search_p;
+ const char *measure_p;
+ const char *found_p;
+ int len;
+ int w;
+ const char *end_p;
+ int h;
+ int wc;
+
+ int w_total;
+ int len_total;
+
+ string_len = strlen(string);
+
+ if (flags & FONT_CENTERED) {
+
+ /* Text is centered... format output */
+
+ /* Enforce minimum and maximum center points for centered text */
+ if (text_x < R_TEXT_CENTERLIMIT) {
+ text_x = R_TEXT_CENTERLIMIT;
+ }
+
+ if (text_x > ds->buf_w - R_TEXT_CENTERLIMIT) {
+ text_x = ds->buf_w - R_TEXT_CENTERLIMIT;
+ }
+
+ if (text_x < (R_TEXT_MARGIN * 2)) {
+ /* Text can't be centered if it's too close to the margin */
+ return R_FAILURE;
+ }
+
+ string_w =
+ FONT_GetStringWidth(font_id, string, string_len, flags);
+
+ if (text_x < (ds->buf_w / 2)) {
+ /* Fit to right side */
+ fit_w = (text_x - R_TEXT_MARGIN) * 2;
+ } else {
+ /* Fit to left side */
+ fit_w = ((ds->buf_w - R_TEXT_MARGIN) - text_x) * 2;
+ }
+
+ if (fit_w >= string_w) {
+
+ /* Entire string fits, draw it */
+ text_x = text_x - (string_w / 2);
+
+ FONT_Draw(font_id,
+ ds,
+ string,
+ string_len,
+ text_x, text_y, color, effect_color, flags);
+
+ return R_SUCCESS;
+ }
+
+ /* String won't fit on one line ... */
+
+ h = FONT_GetHeight(font_id);
+ w_total = 0;
+ len_total = 0;
+ wc = 0;
+
+ start_p = string;
+ measure_p = string;
+ search_p = string;
+ end_p = string + string_len;
+
+ for (;;) {
+
+ found_p = strchr(search_p, ' ');
+
+ if (found_p == NULL) {
+ /* Ran to the end of the buffer */
+ len = end_p - measure_p;
+ } else {
+ len = found_p - measure_p;
+ }
+
+ w = FONT_GetStringWidth(font_id, measure_p, len,
+ flags);
+ measure_p = found_p;
+
+ if ((w_total + w) > fit_w) {
+ /* This word won't fit */
+ if (wc == 0) {
+ /* The first word in the line didn't fit. abort */
+ return R_SUCCESS;
+ }
+
+ /* Wrap what we've got and restart */
+ FONT_Draw(font_id,
+ ds,
+ start_p,
+ len_total,
+ text_x - (w_total / 2),
+ text_y, color, effect_color, flags);
+
+ text_y += h + R_TEXT_LINESPACING;
+ w_total = 0;
+ len_total = 0;
+ wc = 0;
+ measure_p = search_p;
+ start_p = search_p;
+
+ } else {
+ /* Word will fit ok */
+ w_total += w;
+ len_total += len;
+ wc++;
+
+ if (found_p == NULL) {
+ /* Since word hit NULL but fit, we are done */
+ FONT_Draw(font_id,
+ ds,
+ start_p,
+ len_total,
+ text_x - (w_total / 2),
+ text_y,
+ color, effect_color, flags);
+
+ return R_SUCCESS;
+ }
+
+ search_p = measure_p + 1;
+ }
+ } /* End for (;;) */
+
+ } else {
+
+ /* Text is not centered; No formatting required */
+
+ FONT_Draw(font_id,
+ ds,
+ string,
+ string_len, text_x, text_y, color, effect_color, flags);
+
+ }
+
+ return R_SUCCESS;
+}
+
+R_TEXTLIST *TEXT_CreateList(void)
+{
+ R_TEXTLIST *new_textlist;
+
+ new_textlist = (R_TEXTLIST *)malloc(sizeof *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 TEXT_ClearList(R_TEXTLIST * tlist)
+{
+ if (tlist != NULL) {
+ ys_dll_delete_all(tlist->list);
+ }
+
+ return;
+}
+
+void TEXT_DestroyList(R_TEXTLIST * tlist)
+{
+ if (tlist != NULL) {
+ ys_dll_destroy(tlist->list);
+ }
+ free(tlist);
+
+ return;
+}
+
+int TEXT_DrawList(R_TEXTLIST * textlist, R_SURFACE * ds)
+{
+
+ R_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 = (R_TEXTLIST_ENTRY *)ys_dll_get_data(walk_p);
+
+ if (entry_p->display != 0) {
+
+ TEXT_Draw(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);
+ }
+ }
+
+ return R_SUCCESS;
+}
+
+int TEXT_ProcessList(R_TEXTLIST * textlist, long ms)
+{
+ R_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 = (R_TEXTLIST_ENTRY *)ys_dll_get_data(walk_p);
+
+ if (entry_p->flags & TEXT_TIMEOUT) {
+
+ entry_p->time -= ms;
+ if (entry_p->time <= 0) {
+
+ ys_dll_delete(walk_p);
+ }
+ }
+ }
+
+ return R_SUCCESS;
+
+}
+
+R_TEXTLIST_ENTRY *TEXT_AddEntry(R_TEXTLIST * textlist,
+ R_TEXTLIST_ENTRY * entry)
+{
+ YS_DL_NODE *new_node = NULL;
+
+ if (entry != NULL) {
+ new_node =
+ ys_dll_add_tail(textlist->list, entry, sizeof *entry);
+ }
+
+ return (new_node != NULL) ? (R_TEXTLIST_ENTRY *)new_node->data : NULL;
+}
+
+int TEXT_SetDisplay(R_TEXTLIST_ENTRY * entry, int val)
+{
+ if (entry != NULL) {
+ entry->display = !!val;
+ return R_SUCCESS;
+ }
+
+ return R_FAILURE;
+}
+
+int TEXT_DeleteEntry(R_TEXTLIST * textlist, R_TEXTLIST_ENTRY * entry)
+{
+ YS_DL_NODE *walk_p;
+
+ if (entry == NULL) {
+ return R_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;
+ }
+ }
+
+ return R_SUCCESS;
+}
+
+} // End of namespace Saga
+
diff --git a/saga/text.h b/saga/text.h
new file mode 100644
index 0000000000..49adac7053
--- /dev/null
+++ b/saga/text.h
@@ -0,0 +1,46 @@
+/* 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$
+ *
+ */
+/*
+
+ Description:
+
+ Text / dialogue display management module private header
+
+ Notes:
+*/
+
+#ifndef SAGA_TEXT_H__
+#define SAGA_TEXT_H__
+
+namespace Saga {
+
+#define R_TEXT_CENTERLIMIT 50
+#define R_TEXT_MARGIN 10
+#define R_TEXT_LINESPACING 2
+
+struct R_TEXTLIST_tag {
+ YS_DL_LIST *list;
+};
+
+} // End of namespace Saga
+#endif /* SAGA_TEXT_H__ */
diff --git a/saga/text_mod.h b/saga/text_mod.h
new file mode 100644
index 0000000000..b136a3b34a
--- /dev/null
+++ b/saga/text_mod.h
@@ -0,0 +1,70 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Text / dialogue display management module public header
+
+ Notes:
+*/
+
+#ifndef SAGA_TEXT_MOD_H_
+#define SAGA_TEXT_MOD_H_
+
+namespace Saga {
+
+enum R_TEXT_FLAGS {
+ TEXT_TIMEOUT = 0x01
+};
+
+typedef struct R_TEXTLIST_ENTRY_tag {
+ struct R_TEXTLIST_ENTRY_tag *next;
+ struct R_TEXTLIST_ENTRY_tag *prev;
+ int display;
+ int id;
+ int text_x;
+ int text_y;
+ int color;
+ int effect_color;
+ int flags;
+ int font_id;
+ long time;
+ char *string;
+} R_TEXTLIST_ENTRY;
+
+typedef struct R_TEXTLIST_tag R_TEXTLIST;
+
+R_TEXTLIST *TEXT_CreateList(void);
+void TEXT_DestroyList(R_TEXTLIST *textlist);
+void TEXT_ClearList(R_TEXTLIST *textlist);
+int TEXT_DrawList(R_TEXTLIST *textlist, R_SURFACE *ds);
+R_TEXTLIST_ENTRY *TEXT_AddEntry(R_TEXTLIST *textlist, R_TEXTLIST_ENTRY *entry);
+int TEXT_DeleteEntry(R_TEXTLIST *textlist, R_TEXTLIST_ENTRY *entry);
+int TEXT_SetDisplay(R_TEXTLIST_ENTRY *entry, int val);
+int TEXT_Draw(int font_id, R_SURFACE *ds, const char *string, int text_x,
+ int text_y, int color, int effect_color, int flags);
+int TEXT_ProcessList(R_TEXTLIST *textlist, long ms);
+
+} // End of namespace Saga
+
+#endif /* SAGA_TEXT_MOD_H_ */
diff --git a/saga/transitions.cpp b/saga/transitions.cpp
new file mode 100644
index 0000000000..759652593d
--- /dev/null
+++ b/saga/transitions.cpp
@@ -0,0 +1,83 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ Background transition routines
+
+ Notes:
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "yslib.h"
+
+#include "reinherit.h"
+
+namespace Saga {
+
+int
+TRANSITION_Dissolve(uchar * dst_img,
+ int dst_w,
+ int dst_h,
+ int dst_p, const uchar * src_img, int src_p, int flags, double percent)
+{
+#define XOR_MASK 0xB400;
+
+ int pixelcount = dst_w * dst_h;
+ int seqlimit = (int)(65535 * percent);
+
+ int seq = 1;
+ int i;
+
+ YS_IGNORE_PARAM(flags);
+ YS_IGNORE_PARAM(src_p);
+ YS_IGNORE_PARAM(dst_p);
+
+ for (i = 0; i < seqlimit; i++) {
+
+ if (seq & 1) {
+ seq = (seq >> 1) ^ XOR_MASK;
+ } else {
+ seq = seq >> 1;
+ }
+
+ if (seq == 1) {
+ return 0;
+ }
+
+ if (seq >= pixelcount) {
+ continue;
+ } else {
+
+ dst_img[seq] = src_img[seq];
+
+ }
+ }
+
+ return 1;
+}
+
+} // End of namespace Saga
+
diff --git a/saga/x86_32.h b/saga/x86_32.h
new file mode 100644
index 0000000000..503d0cd777
--- /dev/null
+++ b/saga/x86_32.h
@@ -0,0 +1,46 @@
+/****************************************************************************\
+ ____ ___ _ _ _
+| _ \ ___|_ _|_ __ | |__ ___ _ __(_) |_
+| |_) / _ \| || '_ \| '_ \ / _ \ '__| | __|
+| _ < __/| || | | | | | | __/ | | | |_
+|_| \_\___|___|_| |_|_| |_|\___|_| |_|\__|
+
+ ----------------------------------------------------------------------------
+ Project: ReInherit Engine
+ Version: .1a
+
+ The ReInherit Engine is (C)2000-2001 by Daniel Balsom
+ This code is subject to the terms and conditions of the General Public
+ License (GPL).
+
+ ----------------------------------------------------------------------------
+
+ File: x86-32.h
+ Revision: $Revision$
+
+ Description:
+
+ Architecture-specific typedefs for Intel(tm) compatible 32 bit processors
+
+ Notes:
+
+\****************************************************************************/
+#ifndef R_ARCH_H
+#define R_ARCH_H
+
+namespace Saga {
+
+#define R_LITTLE_ENDIAN
+
+typedef unsigned int R_UINT32;
+typedef signed int R_SINT32;
+
+typedef unsigned short R_UINT16;
+typedef signed short R_SINT16;
+
+typedef unsigned char R_UINT8;
+typedef signed char R_SINT8;
+
+} // End of namespace Saga
+
+#endif /* R_ARCH_H */
diff --git a/saga/xmidi.cpp b/saga/xmidi.cpp
new file mode 100644
index 0000000000..4767a6b849
--- /dev/null
+++ b/saga/xmidi.cpp
@@ -0,0 +1,832 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ XMIDI conversion routines
+
+ Notes:
+
+ Code adapted from XMILoader by Keet ( fox@foxpaws.net ), (C)2000
+*/
+
+#include "reinherit.h"
+
+#include "yslib.h"
+
+/* Begin module component
+\*--------------------------------------------------------------------------*/
+#include "xmidi_mod.h"
+#include "xmidi.h"
+
+namespace Saga {
+
+int
+ConvertEventListToSMF(XMIDIEVENT_LIST * event_list,
+ uchar ** smf_ptr, size_t * smf_len)
+/*--------------------------------------------------------------------------*\
+ * Given a pointer to an event list structure, this function creates and
+ * returns a pointer to a Standard Midi File (SMF) image and the image's
+ * length in bytes.
+\*--------------------------------------------------------------------------*/
+{
+ YS_IGNORE_PARAM(event_list);
+ YS_IGNORE_PARAM(smf_ptr);
+ YS_IGNORE_PARAM(smf_len);
+
+#if 0
+ SMF_HEADER_CHUNK smfh;
+ SMF_TRACK_CHUNK smft;
+
+ XMIDIEVENT *event_p;
+
+ uchar *write_p = NULL;
+ uchar *smf_buf = NULL;
+
+ size_t alloc_size;
+
+ int vlq_len;
+
+ if ((smf_ptr == NULL) || (smf_len == NULL)) {
+
+ return R_FAILURE;
+ }
+
+ /* Allocate memory for SMF image
+ * \*---------------------------------------------------------------------- */
+ alloc_size = event_list->smf_size + MIDI_HEADER_LEN +
+ MIDI_TRACK_CHUNK_LEN;
+
+ /* SMF requires an even size */
+ if (alloc_size % 2) {
+ alloc_size++;
+ }
+
+ smf_buf = malloc(alloc_size);
+ if (smf_buf == NULL) {
+ R_printf(R_STDERR, "Memory allocation error.\n");
+
+ return R_FAILURE;
+ }
+
+ memset(smf_ptr, 0, alloc_size);
+
+ /* Write header chunk
+ * \*---------------------------------------------------------------------- */
+ write_p = smf_buf;
+
+ smfh.smf_header_len = MIDI_HEADER_CHUNK_LEN;
+ smfh.smf_format = 0;
+ smfh.smf_ntracks = 1;
+ smfh.time_division.ppqn = XMIDI_TIMEDIV;
+
+ memcpy(write_p, MIDI_HEADER_TAG, 4);
+ write_p += 4;
+
+ ys_write_u32_be(smfh.smf_header_len, write_p, &write_p);
+ ys_write_u16_be(smfh.smf_format, write_p, &write_p);
+ ys_write_u16_be(smfh.smf_ntracks, write_p, &write_p);
+ ys_write_u16_be(smfh.time_division.ppqn, write_p, &write_p);
+
+ /* Write track chunk
+ * \*---------------------------------------------------------------------- */
+ memcpy(write_p, MIDI_TRACK_TAG, 4);
+ write_p += 4;
+
+ smft.smf_track_len = event_list->smf_size;
+
+ ys_write_u32_be(smft.smf_track_len, write_p, &write_p);
+
+ /* Write MIDI events
+ * \*---------------------------------------------------------------------- */
+ event_p = event_list->head;
+
+ while (event_p != NULL) {
+
+ vlq_len = WriteVLQ_DW(write_p, event_p->delta_time);
+ write_p += vlq_len;
+
+ /*
+ * R_printf( R_STDOUT,
+ * "Wrote %d len VLQ. (%d)\n",
+ * vlq_len,
+ * event_p->delta_time );
+ */
+
+ switch (event_p->event) {
+
+ case MIDI_NOTE_ON:
+ case MIDI_NOTE_OFF:
+ case MIDI_AFTERTOUCH:
+ case MIDI_CONTROLCHANGE:
+ case MIDI_PITCHWHEEL:
+
+ *write_p++ =
+ (uchar) (event_p->event | (uchar) event_p->
+ channel);
+ *write_p++ = event_p->op1;
+ *write_p++ = event_p->op2;
+ break;
+
+ case MIDI_PROGRAMCHANGE:
+ case MIDI_CHANNELPRESSURE:
+
+ *write_p =
+ (uchar) (event_p->event | (uchar) event_p->
+ channel);
+ *write_p = event_p->op1;
+ break;
+
+ case MIDI_SYSTEMEXCLUSIVE:
+
+ *write_p = (uchar) MIDI_NONMIDI;
+
+ switch (event_p->sysex_op) {
+
+ case MIDI_SYSEX_TRACKEND:
+
+ *write_p++ = event_p->sysex_op;
+ *write_p++ = (uchar) 0;
+ break;
+
+ case MIDI_SYSEX_TEMPO:
+
+ *write_p++ = event_p->sysex_op;
+ *write_p++ = (uchar) 3;
+ /*
+ *write_p++ = event_p->op1;
+ *write_p++ = event_p->op2;
+ *write_p++ = event_p->op3;
+ */
+
+ /* Override tempo change */
+ *write_p++ = (uchar) 0x07;
+ *write_p++ = (uchar) 0xA1;
+ *write_p++ = (uchar) 0x20;
+ break;
+
+ case MIDI_SYSEX_TIMESIG:
+
+ *write_p++ = event_p->sysex_op;
+ *write_p++ = (uchar) 4;
+ *write_p++ = event_p->op1;
+ *write_p++ = event_p->op2;
+ *write_p++ = event_p->op3;
+ *write_p++ = event_p->op4;
+ break;
+
+ default:
+
+ R_printf(R_STDERR,
+ "Error, invalid sysex event type (%d): "
+ "Aborting.\n", event_p->sysex_op);
+
+ return R_FAILURE;
+ break;
+
+ }
+ break;
+
+ default:
+ R_printf(R_STDERR,
+ "Invalid event code encountered; " "aborting.\n");
+
+ return R_FAILURE;
+ break;
+ }
+
+ event_p = event_p->next_event;
+ }
+
+ *smf_ptr = smf_buf;
+ *smf_len = alloc_size;
+#endif
+ return R_SUCCESS;
+}
+
+int WriteVLQ_DW(char *write_ptr, DWORD value)
+{
+
+ int vlq_len = 1;
+ DWORD pack = value & 0x7F;
+ int x;
+
+ while (value >>= 7) {
+ pack <<= 8;
+ pack |= ((value & 0x7F) | 0x80);
+ vlq_len++;
+ }
+ for (x = 0; x < sizeof(DWORD); x++) {
+ *write_ptr++ = ((char *)(&pack))[x];
+ }
+
+ return vlq_len;
+}
+
+int XMIDI_Read(const uchar * XMI_img, XMIDIEVENT_LIST * event_list)
+{
+ /* XMI header data */
+ const uchar *XMIDI_data;
+ uint n_tracks;
+
+ /* XMIDI data */
+ IFF_ID_CHUNK cat_chunk;
+ IFF_ID_CHUNK id_chunk; /* Present after categeory chunk */
+ XMI_TIMB_CHUNK timbre_chunk; /* Present after id chunk */
+ XMI_EVENT_CHUNK event_chunk;
+
+ const uchar *read_p;
+
+ const uchar *event_data;
+ size_t event_data_len;
+
+ if (XMIDI_ReadXMIHeader(XMI_img, &XMIDI_data, &n_tracks) != R_SUCCESS) {
+
+ return R_FAILURE;
+ }
+
+ read_p = XMIDI_data;
+
+ /* Read category chunk
+ * \*------------------------------------------------------------- */
+ ReadIFF_IDChunk(&cat_chunk, read_p, &read_p);
+
+ if (memcmp(cat_chunk.id_4cc, IFF_CATEGORY_4CC, 4) != 0) {
+
+ R_printf(R_STDERR, "Error: Category chunk not present.\n");
+ Print4CC(cat_chunk.id_4cc);
+
+ return R_FAILURE;
+ }
+
+ if (memcmp(cat_chunk.desc_4cc, XMIDI_DESC_4CC, 4) != 0) {
+
+ R_printf(R_STDERR,
+ "Error: Incorrect category description field.\n");
+ Print4CC(cat_chunk.desc_4cc);
+
+ return R_FAILURE;
+ }
+
+ /* Read XMIDI ID Chunk
+ * \*------------------------------------------------------------- */
+ ReadIFF_IDChunk(&id_chunk, read_p, &read_p);
+
+ if (memcmp(id_chunk.id_4cc, IFF_FORMAT_4CC, 4) != 0) {
+
+ R_printf(R_STDERR, "Error: ID chunk not present.\n");
+ Print4CC(id_chunk.id_4cc);
+
+ return R_FAILURE;
+ }
+
+ if (memcmp(id_chunk.desc_4cc, XMIDI_DESC_4CC, 4) != 0) {
+
+ R_printf(R_STDERR,
+ "Error: XMID tag not present in ID chunk: "
+ "Not XMIDI data.\n");
+ Print4CC(id_chunk.desc_4cc);
+
+ return R_FAILURE;
+ }
+
+ /* Read XMIDI Timbre Chunk
+ * \*------------------------------------------------------------- */
+ ys_read_4cc(timbre_chunk.id_4cc, read_p, &read_p);
+ timbre_chunk.chunk_len = ys_read_u32_be(read_p, &read_p);
+
+ if (memcmp(timbre_chunk.id_4cc, XMIDI_TIMBRE_4CC, 4) != 0) {
+
+ R_printf(R_STDERR, "Error: Timbre chunk not present.\n");
+ Print4CC(timbre_chunk.id_4cc);
+
+ return R_FAILURE;
+ }
+
+ /* Read XMIDI Event Chunk
+ * \*------------------------------------------------------------- */
+ read_p += timbre_chunk.chunk_len;
+
+ ys_read_4cc(event_chunk.id_4cc, read_p, &read_p);
+ event_chunk.chunk_len = ys_read_u32_be(read_p, &read_p);
+
+ if (memcmp(event_chunk.id_4cc, XMIDI_EVENT_4CC, 4) != 0) {
+
+ R_printf(R_STDERR, "Error: Event chunk not present.\n");
+ Print4CC(event_chunk.id_4cc);
+
+ return R_FAILURE;
+ }
+
+ /* Read XMIDI Event data
+ * \*------------------------------------------------------------- */
+ event_data = read_p;
+ event_data_len = event_chunk.chunk_len;
+
+ R_printf(R_STDOUT,
+ "Converting %d bytes of event data:\n", event_data_len);
+
+ XMIDI_ReadEvents(event_list, event_data, event_data_len, n_tracks);
+
+ /* Process XMIDI Event data
+ * \*------------------------------------------------------------- */
+ ProcessEventList(event_list);
+
+ return R_SUCCESS;
+}
+
+int
+ReadIFF_IDChunk(IFF_ID_CHUNK * chunk,
+ const uchar * read_p, const uchar ** read_pp)
+{
+ const uchar *chunk_p = read_p;
+
+ ys_read_4cc(chunk->id_4cc, chunk_p, &chunk_p);
+
+ chunk->chunk_len = ys_read_u32_be(chunk_p, &chunk_p);
+
+ ys_read_4cc(chunk->desc_4cc, chunk_p, &chunk_p);
+
+ if (read_pp != NULL) {
+ *read_pp = chunk_p;
+ }
+
+ return R_SUCCESS;
+}
+
+int Print4CC(char *fourcc)
+{
+ R_printf(R_STDERR,
+ "FourCC: %c%c%c%c (%X %X %X %X)\n",
+ fourcc[0], fourcc[1], fourcc[2], fourcc[3],
+ fourcc[0], fourcc[1], fourcc[2], fourcc[3]);
+
+ return R_SUCCESS;
+}
+
+int
+XMIDI_ReadXMIHeader(const uchar * XMI_img,
+ const uchar ** XMIDI_data, uint * n_tracks)
+{
+ const uchar *read_p;
+
+ IFF_ID_CHUNK id_chunk;
+ XMI_INFO_CHUNK info_chunk;
+
+ *n_tracks = 0;
+ *XMIDI_data = NULL;
+
+ /* Read ID chunk
+ * \*------------------------------------------------------------ */
+ read_p = XMI_img;
+
+ ys_read_4cc(id_chunk.id_4cc, read_p, &read_p);
+ id_chunk.chunk_len = ys_read_u32_be(read_p, &read_p);
+ ys_read_4cc(id_chunk.desc_4cc, read_p, &read_p);
+
+ if (memcmp(id_chunk.id_4cc, IFF_FORMAT_4CC, 4) != 0) {
+ R_printf(R_STDERR, "Error: ID chunk not present.\n");
+
+ return R_FAILURE;
+ }
+
+ if (memcmp(id_chunk.desc_4cc, XMI_DESC_4CC, 4) != 0) {
+ R_printf(R_STDERR,
+ "Error: XDIR tag not present in ID chunk.\n");
+
+ return R_FAILURE;
+ }
+
+ /* Read INFO chunk
+ * \*------------------------------------------------------------ */
+ ys_read_4cc(info_chunk.id_4cc, read_p, &read_p);
+ info_chunk.chunk_len = ys_read_u32_be(read_p, &read_p);
+ info_chunk.n_tracks = ys_read_u16_le(read_p, &read_p);
+
+ if (memcmp(info_chunk.id_4cc, XMI_INFO_4CC, 4) != 0) {
+
+ R_printf(R_STDERR, "Error: INFO chunk not present.\n");
+
+ return R_FAILURE;
+ }
+
+ *n_tracks = info_chunk.n_tracks;
+
+ *XMIDI_data = XMI_img +
+ (id_chunk.chunk_len + IFF_ID_CHUNK_HEADERLEN - 4);
+
+ return R_SUCCESS;
+}
+
+int
+XMIDI_ReadEvents(XMIDIEVENT_LIST * event_list,
+ const uchar * event_data, size_t event_data_len, uint n_tracks)
+{
+
+ const uchar *event_data_ptr = event_data;
+ size_t event_bytes_left = event_data_len;
+
+ ulong new_event_time = 0;
+ ulong event_time = 0;
+ ulong event_len;
+
+ ulong vlq_len;
+ uint data_byte;
+
+ int channel;
+ int event;
+
+ /*int tempo = MIDI_STD_TEMPO; */
+
+ unsigned int sysex_op;
+ unsigned int op1;
+ unsigned int op2;
+ unsigned int op3;
+ unsigned int op4;
+
+ /* Set initial tempo */
+ /*
+ * AddEventToList( event_list, MIDI_SYSEX_TEMPO_LEN + GetLengthAsVLQ( 0 ), 0, MIDI_SYSTEMEXCLUSIVE, 0, MIDI_SYSEX_TEMPO, 0, );
+ */
+
+ while (event_bytes_left > 0) {
+
+ vlq_len = ReadVLQ2_DW((char *)event_data_ptr,
+ (DWORD)event_bytes_left, (DWORD *)&new_event_time);
+
+ event_time += new_event_time;
+ event_data_ptr += vlq_len;
+ event_bytes_left -= vlq_len;
+
+ /*
+ * vlq_len = GetLengthAsVLQ( new_event_time );
+ * R_printf( R_STDOUT, "Count: %d len VLQ (%d)\n", vlq_len, new_event_time );
+ */
+
+ data_byte = *event_data_ptr++;
+
+ channel = data_byte & 0x0FU;
+ event = data_byte & 0xF0U;
+
+ switch (event) {
+
+ case MIDI_NOTE_ON:
+
+#ifdef XMIPLAY_VERBOSE
+ R_printf(R_STDOUT, "MIDI_NOTE_ON event:\n");
+#endif
+
+ op1 = *(event_data_ptr++);
+ op2 = *(event_data_ptr++);
+
+ AddEventToList(event_list,
+ MIDI_NOTE_ON_LEN,
+ event_time, event, channel, 0, op1, op2, 0, 0);
+
+ vlq_len =
+ ReadVLQ_DW((char *)event_data_ptr, (DWORD)event_bytes_left,
+ (DWORD *)&event_len);
+ AddEventToList(event_list, MIDI_NOTE_OFF_LEN,
+ event_time + event_len, MIDI_NOTE_OFF, channel, 0,
+ op1, MIDI_STD_VELOCITY, 0, 0);
+
+ event_data_ptr += (vlq_len);
+ event_bytes_left -= (2 + vlq_len);
+ break;
+
+ case MIDI_AFTERTOUCH:
+#ifdef XMIPLAY_VERBOSE
+ R_printf(R_STDOUT, "MIDI_AFTERTOUCH event:\n");
+#endif
+ op1 = *(event_data_ptr++);
+ op2 = *(event_data_ptr++);
+
+ AddEventToList(event_list,
+ MIDI_AFTERTOUCH_LEN,
+ event_time, event, channel, 0, op1, op2, 0, 0);
+
+ event_bytes_left -= 2;
+ break;
+
+ case MIDI_CONTROLCHANGE:
+#ifdef XMIPLAY_VERBOSE
+ R_printf(R_STDOUT, "MIDI_CONTROLCHANGE event:\n");
+#endif
+ op1 = *(event_data_ptr++);
+ op2 = *(event_data_ptr++);
+
+ AddEventToList(event_list,
+ MIDI_CONTROLCHANGE_LEN,
+ event_time, event, channel, 0, op1, op2, 0, 0);
+
+ event_bytes_left -= 2;
+ break;
+
+ case MIDI_PITCHWHEEL:
+#ifdef XMIPLAY_VERBOSE
+ R_printf(R_STDOUT, "MIDI_PITCHWHEEL event:\n");
+#endif
+ op1 = *(event_data_ptr++);
+ op2 = *(event_data_ptr++);
+
+ AddEventToList(event_list,
+ MIDI_PITCHWHEEL_LEN,
+ event_time, event, channel, 0, op1, op2, 0, 0);
+
+ event_bytes_left -= 2;
+ break;
+
+ case MIDI_PROGRAMCHANGE:
+#ifdef XMIPLAY_VERBOSE
+ R_printf(R_STDOUT, "MIDI_PROGRAMCHANGE event:\n");
+#endif
+ op1 = *(event_data_ptr++);
+ AddEventToList(event_list, MIDI_PROGRAMCHANGE_LEN,
+ event_time, event, channel, 0, op1, 0, 0, 0);
+
+ event_bytes_left--;
+ break;
+
+ case MIDI_CHANNELPRESSURE:
+#ifdef XMIPLAY_VERBOSE
+ R_printf(R_STDOUT, "MIDI_CHANNELPRESSURE event:\n");
+#endif
+ op1 = *(event_data_ptr++);
+ AddEventToList(event_list, MIDI_CHANNELPRESSURE_LEN,
+ event_time, event, channel, 0, op1, 0, 0, 0);
+
+ event_bytes_left--;
+ break;
+
+ case MIDI_SYSTEMEXCLUSIVE:
+
+ sysex_op = (BYTE) * event_data_ptr++;
+ event_bytes_left--;
+
+ if (data_byte == MIDI_NONMIDI) {
+
+ switch (sysex_op) {
+
+ case MIDI_SYSEX_TRACKEND:
+ R_printf(R_STDOUT,
+ "Track end encountered.\n");
+ AddEventToList(event_list,
+ MIDI_SYSEX_TRACKEND_LEN,
+ event_time, event, channel,
+ sysex_op, op1, op2, 0, 0);
+ event_bytes_left = 0;
+ break;
+
+ case MIDI_SYSEX_TEMPO:
+ event_data_ptr++; /*(skip length VLQ) (always 3) */
+
+ op1 = (BYTE) * event_data_ptr++;
+ op2 = (BYTE) * event_data_ptr++;
+ op3 = (BYTE) * event_data_ptr++;
+ AddEventToList(event_list,
+ MIDI_SYSEX_TEMPO_LEN, event_time,
+ event, channel, sysex_op, op1, op2,
+ op3, 0);
+ /*
+ * R_printf( R_STDOUT, "Adding tempo change event. :%X %X %X\n", op1, op2, op3 );
+ */
+ event_bytes_left -= 4;
+ break;
+
+ case MIDI_SYSEX_TIMESIG:
+ event_data_ptr++; /*(skip length VLQ) (always 4) */
+
+ op1 = (BYTE) * event_data_ptr++;
+ op2 = (BYTE) * event_data_ptr++;
+ op3 = (BYTE) * event_data_ptr++;
+ op4 = (BYTE) * event_data_ptr++;
+ AddEventToList(event_list,
+ MIDI_SYSEX_TIMESIG_LEN, event_time,
+ event, channel, sysex_op, op1, op2,
+ op3, op4);
+
+ /*
+ * R_printf( R_STDOUT, "Adding time signature event. :%X %X %X %X\n", op1, op2, op3, op4 );
+ */
+ event_bytes_left -= 5;
+ break;
+
+ default:
+ R_printf(R_STDERR,
+ "Unhandled sysex nonmidi event, aborting.\n");
+ R_printf(R_STDERR, "%X %X %X %X",
+ *event_data_ptr,
+ *(event_data_ptr + 1),
+ *(event_data_ptr + 2),
+ *(event_data_ptr + 3));
+
+ event_bytes_left = 0;
+ break;
+
+ }
+ } else {
+ R_printf(R_STDERR,
+ "Unhandled sysex event, aborting.\n");
+ event_bytes_left = 0;
+ }
+
+ break;
+
+ default:
+ R_printf(R_STDERR,
+ "Invalid event code encountered; aborting.\n");
+ event_bytes_left = 0;
+ break;
+ }
+
+ } /* end while ( event_bytes_left > 0 ) */
+
+ return R_SUCCESS;
+}
+
+int GetLengthAsVLQ(DWORD data)
+{
+
+ int len = 1;
+
+ while (data >>= 7)
+ len++;
+ return len;
+
+}
+
+DWORD ReadVLQ_DW(char *data, DWORD bytes_left, DWORD * value)
+{
+ BYTE byte;
+ DWORD vlq_len = 0;
+ *value = 0;
+
+ do {
+ if (bytes_left <= 0)
+ return 0;
+ byte = *data++;
+ bytes_left--;
+ vlq_len++;
+ *value = (*value << 7) | (byte & 0x7F);
+ } while (byte & 0x80);
+
+ return vlq_len;
+}
+
+DWORD ReadVLQ2_DW(char *data, DWORD bytes_left, DWORD * value)
+{
+
+ BYTE byte;
+ DWORD vlq_len = 0;
+ *value = 0;
+
+ while (!((byte = *data++) & 0x80)) {
+ if (bytes_left <= 0)
+ return 0;
+ bytes_left--;
+ vlq_len++;
+ (*value) += byte;
+ }
+
+ return vlq_len;
+}
+
+int
+AddEventToList(XMIDIEVENT_LIST * event_list, int smf_size, int time, int event,
+ int channel, int sysex_op, int op1, int op2, int op3, int op4)
+{
+
+ XMIDIEVENT *new_event;
+ XMIDIEVENT *search_ptr = event_list->tail;
+
+ new_event = (XMIDIEVENT *)malloc(sizeof(XMIDIEVENT));
+
+ if (new_event == NULL) {
+ R_printf(R_STDERR,
+ "Error: Out of memory allocating XMIDI event list entry.");
+ return -1;
+ }
+
+ new_event->next_event = NULL;
+ new_event->prev_event = NULL;
+
+ if (event_list->head == NULL) {
+ /* Set up new list */
+ event_list->head = new_event;
+ event_list->tail = new_event;
+ } else {
+ /* List isn't empty */
+ if ((unsigned int)time >= event_list->tail->delta_time) {
+
+ /* If this is the most recent event, append */
+ event_list->tail->next_event = new_event;
+ new_event->prev_event = event_list->tail;
+ event_list->tail = new_event;
+
+ } else {
+ /* Otherwise scan list backwards and insert in proper position */
+ while (search_ptr != NULL) {
+
+ if ((unsigned int)time >=
+ search_ptr->delta_time) {
+ /* Insert entry */
+ new_event->next_event =
+ search_ptr->next_event;
+ new_event->prev_event = search_ptr;
+
+ search_ptr->next_event->prev_event =
+ new_event;
+ search_ptr->next_event = new_event;
+ break;
+ }
+ search_ptr = search_ptr->prev_event;
+ }
+ }
+ }
+
+ new_event->smf_size = smf_size;
+ new_event->delta_time = time;
+
+ new_event->sysex_op = sysex_op;
+ new_event->event = (BYTE) event;
+ new_event->channel = (BYTE) channel;
+ new_event->op1 = (BYTE) op1;
+ new_event->op2 = (BYTE) op2;
+ new_event->op3 = (BYTE) op3;
+ new_event->op4 = (BYTE) op4;
+
+#ifdef XMIPLAY_VERBOSE
+ R_printf(R_STDOUT,
+ "Added event: Time: %d Tempo: %d Event: %d Chan: %d Op1: %d Op2: %d\n",
+ new_event->delta_time, new_event->tempo, new_event->event,
+ new_event->channel, new_event->op1, new_event->op2);
+#endif
+ return 0;
+}
+
+int ProcessEventList(XMIDIEVENT_LIST * event_list)
+{
+ XMIDIEVENT *convert_ptr = event_list->head;
+ int last_time = 0;
+ int delta = 0;
+
+ while (convert_ptr != NULL) {
+
+ delta = convert_ptr->delta_time - last_time;
+ if (delta < 0)
+ R_printf(R_STDERR,
+ "Error: Negative delta time found.");
+ last_time = convert_ptr->delta_time;
+ convert_ptr->delta_time = delta;
+
+ /* Update smf size count */
+ event_list->smf_size +=
+ (convert_ptr->smf_size + GetLengthAsVLQ(delta));
+ convert_ptr = convert_ptr->next_event;
+ }
+
+ R_printf(R_STDOUT,
+ "ProcessEventList(): %d bytes of SMF data processed.\n",
+ event_list->smf_size);
+
+ return 0;
+}
+
+int XMIDI_Free(XMIDIEVENT_LIST * event_list)
+{
+
+ XMIDIEVENT *free_ptr = event_list->head;
+ XMIDIEVENT *temp_ptr;
+
+ while (free_ptr != NULL) {
+ temp_ptr = free_ptr->next_event;
+ free(free_ptr);
+ free_ptr = temp_ptr;
+ }
+
+ return 0;
+
+}
+
+} // End of namespace Saga
+
diff --git a/saga/xmidi.h b/saga/xmidi.h
new file mode 100644
index 0000000000..a408cfc74e
--- /dev/null
+++ b/saga/xmidi.h
@@ -0,0 +1,117 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ XMIDI conversion routines
+
+ Notes:
+
+ Code adapted from XMILoader by Keet ( fox@foxpaws.net ), (C)2000
+*/
+
+#ifndef SAGA_XMIDI_H_
+#define SAGA_XMIDI_H_
+
+namespace Saga {
+
+#define XMIDI_TIMEDIV 0x3C
+
+/* XMIDI/IFF 4CC codes
+\*--------------------------------------------------------------------------*/
+#define IFF_FORMAT_4CC "FORM"
+#define IFF_CATEGORY_4CC "CAT "
+
+#define XMI_DESC_4CC "XDIR"
+#define XMI_INFO_4CC "INFO"
+
+#define XMIDI_DESC_4CC "XMID"
+#define XMIDI_TIMBRE_4CC "TIMB"
+#define XMIDI_EVENT_4CC "EVNT"
+
+/* IFF/XMI Data structures
+\*--------------------------------------------------------------------------*/
+
+typedef struct IFF_ID_CHUNK_tag {
+ char id_4cc[4]; /* 4cc */
+ ulong chunk_len; /* u32_be */
+ char desc_4cc[4]; /* 4cc */
+} IFF_ID_CHUNK;
+
+#define IFF_ID_CHUNK_HEADERLEN 12
+
+typedef struct XMI_INFO_CHUNK_tag {
+ char id_4cc[4]; /* 4cc */
+ ulong chunk_len; /* u32_be */
+ uint n_tracks; /* u16_le */
+} XMI_INFO_CHUNK;
+
+typedef struct XMI_TIMB_CHUNK_tag {
+ char id_4cc[4]; /* 4cc */
+ ulong chunk_len; /* u32_be */
+} XMI_TIMB_CHUNK;
+
+typedef struct XMI_EVENT_CHUNK_tag {
+ char id_4cc[4]; /* 4cc */
+ ulong chunk_len; /* u32_be */
+} XMI_EVENT_CHUNK;
+
+typedef struct SMF_HEADER_CHUNK_tag {
+ char smf_id[4]; /* u8 */
+ unsigned int smf_header_len; /* u32_be */
+ unsigned short smf_format; /* u16_be */
+ unsigned short smf_ntracks; /* u16_be */
+ union {
+ unsigned short ppqn; /* u16_be */
+ signed char smpte[2];
+ } time_division;
+} SMF_HEADER_CHUNK;
+
+typedef struct SMF_TRACK_CHUNK_tag {
+ char smf_track_id[4];
+ unsigned int smf_track_len;
+} SMF_TRACK_CHUNK;
+
+#define MIDI_HEADER_LEN 14
+#define MIDI_HEADER_CHUNK_LEN 6
+#define MIDI_TRACK_CHUNK_LEN 8
+
+#define MIDI_HEADER_TAG "MThd"
+#define MIDI_TRACK_TAG "MTrk"
+
+int XMIDI_ReadXMIHeader(const uchar *XMI_img, const uchar **XMIDI_data, uint *n_tracks);
+int ReadIFF_IDChunk(IFF_ID_CHUNK *chunk, const uchar *read_p, const uchar **read_pp);
+int Print4CC(char *fourcc);
+int XMIDI_ReadEvents(XMIDIEVENT_LIST *event_list, const uchar *event_data,
+ size_t event_data_len, uint n_tracks);
+int WriteVLQ_DW(char *write_ptr, DWORD value);
+DWORD ReadVLQ_DW(char *data, DWORD bytes_left, DWORD *value);
+DWORD ReadVLQ2_DW(char *data, DWORD bytes_left, DWORD *value);
+int GetLengthAsVLQ(DWORD data);
+int AddEventToList(XMIDIEVENT_LIST *event_list, int smf_size, int time,
+ int event, int channel, int sysex_op, int op1, int op2, int op3, int op4);
+int ProcessEventList(XMIDIEVENT_LIST *event_list);
+void PrintMidiOutError(unsigned long err);
+} // End of namespace Saga
+
+#endif /* SAGA_XMIDI_H_ */
diff --git a/saga/xmidi_mod.h b/saga/xmidi_mod.h
new file mode 100644
index 0000000000..4d093072a7
--- /dev/null
+++ b/saga/xmidi_mod.h
@@ -0,0 +1,115 @@
+/* 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$
+ *
+ */
+/*
+ Description:
+
+ XMIDI conversion routines - module header
+
+ Notes:
+*/
+
+#ifndef SAGA_XMIDI_MOD_H_
+#define SAGA_XMIDI_MOD_H_
+
+namespace Saga {
+
+#define MIDI_STD_VELOCITY 0x7F
+#define MIDI_STD_TEMPO 0x0007A120L /* 500000 */
+
+/* MIDI Events
+\*--------------------------------------------------------------------------*/
+enum R_MIDI_EVENTS {
+ MIDI_NOTE_ON = 0x90,
+ MIDI_NOTE_OFF = 0x80,
+ MIDI_AFTERTOUCH = 0xA0,
+ MIDI_CONTROLCHANGE = 0xB0,
+ MIDI_PROGRAMCHANGE = 0xC0,
+ MIDI_CHANNELPRESSURE = 0xD0,
+ MIDI_PITCHWHEEL = 0xE0,
+ MIDI_SYSTEMEXCLUSIVE = 0xF0,
+
+ MIDI_NONMIDI = 0xFF,
+
+ MIDI_SYSEX_SEQNUM = 0x00,
+ MIDI_SYSEX_TEXT = 0x01,
+ MIDI_SYSEX_COPYRIGHT = 0x02,
+ MIDI_SYSEX_SEQNAME = 0x03,
+ MIDI_SYSEX_INSTRUMENT = 0x04,
+ MIDI_SYSEX_LYRIC = 0x05,
+ MIDI_SYSEX_MARKER = 0x06,
+ MIDI_SYSEX_CUEPOINT = 0x07,
+
+ MIDI_SYSEX_CHANNEL = 0x20,
+ MIDI_SYSEX_PORTNUM = 0x21,
+ MIDI_SYSEX_TRACKEND = 0x2F,
+ MIDI_SYSEX_TEMPO = 0x51,
+ MIDI_SYSEX_TIMESIG = 0x58,
+
+ MIDI_SYSEX_PROPRIETARY = 0x7F
+};
+
+enum MIDI_EVENT_LENGTHS {
+ MIDI_NOTE_ON_LEN = 3,
+ MIDI_NOTE_OFF_LEN = 3,
+ MIDI_AFTERTOUCH_LEN = 3,
+ MIDI_CONTROLCHANGE_LEN = 3,
+ MIDI_PITCHWHEEL_LEN = 3,
+
+ MIDI_PROGRAMCHANGE_LEN = 2,
+ MIDI_CHANNELPRESSURE_LEN = 2,
+
+ MIDI_SYSEX_TRACKEND_LEN = 3,
+ MIDI_SYSEX_TEMPO_LEN = 6,
+ MIDI_SYSEX_TIMESIG_LEN = 7
+};
+
+typedef struct XMIDIEVENT_tag {
+ struct XMIDIEVENT_tag *prev_event;
+ struct XMIDIEVENT_tag *next_event;
+
+ size_t smf_size; /* Size of event in SMF format */
+
+ ulong delta_time;
+
+ uchar event;
+ uchar channel;
+ uchar sysex_op;
+ uchar op1;
+ uchar op2;
+ uchar op3;
+ uchar op4;
+ uchar pad;
+} XMIDIEVENT;
+
+typedef struct XMIDIEVENT_LIST_tag {
+ XMIDIEVENT *head;
+ XMIDIEVENT *tail;
+ int smf_size;
+} XMIDIEVENT_LIST;
+
+int XMIDI_Read(const uchar *XMI_img, XMIDIEVENT_LIST *event_list);
+int XMIDI_Free(XMIDIEVENT_LIST *event_list);
+
+} // End of namespace Saga
+
+#endif /* SAGA_XMIDI_MOD_H_ */
diff --git a/saga/ys_binread.cpp b/saga/ys_binread.cpp
new file mode 100644
index 0000000000..4f363bbc8f
--- /dev/null
+++ b/saga/ys_binread.cpp
@@ -0,0 +1,350 @@
+/* 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 <stdio.h>
+#include "yslib.h"
+
+namespace Saga {
+
+void
+ys_read_4cc(char *fourcc,
+ const unsigned char *data_p, const unsigned char **data_pp)
+{
+ fourcc[0] = (char)data_p[0];
+ fourcc[1] = (char)data_p[1];
+ fourcc[2] = (char)data_p[2];
+ fourcc[3] = (char)data_p[3];
+
+ if (data_pp) {
+
+ *data_pp = data_p + 4;
+ }
+
+ return;
+}
+
+unsigned int
+ys_read_u8(const unsigned char *data_p, const unsigned char **data_pp)
+/*---------------------------------------------------------------------------*\
+ * Reads an unsigned 8 bit integer in from the array of bytes pointed to by
+ * 'data_p'. If 'data_pp' is not null, it will set '*data_pp' to point past
+ * the integer read.
+\*---------------------------------------------------------------------------*/
+{
+ unsigned int u8 = *data_p;
+
+ if (data_pp != NULL) {
+ *data_pp = data_p + 1;
+ }
+
+ return u8;
+}
+
+int ys_read_s8(const unsigned char *data_p, const unsigned char **data_pp)
+/*---------------------------------------------------------------------------*\
+ * Reads a signed 8 bit integer in two's complement notation from the array
+ * of bytes pointed to by 'data_p'. If 'data_pp' is not null, it will set
+ * '*data_pp' to point past the integer read.
+\*---------------------------------------------------------------------------*/
+{
+ unsigned int u8 = *data_p;
+ int s8;
+
+#ifndef YS_ASSUME_2S_COMP
+ if (u8 & 0x80U) {
+ s8 = (int)(u8 - 0x80U) - 0x7F - 1;
+ } else
+#endif
+ s8 = u8;
+
+ if (data_pp != NULL) {
+ *data_pp = data_p + 1;
+ }
+
+ return s8;
+}
+
+unsigned int
+ys_read_u16_be(const unsigned char *data_p, const unsigned char **data_pp)
+/*---------------------------------------------------------------------------*\
+ * Reads an unsigned 16 bit integer in big-endian format from the array of
+ * bytes pointed to by 'data_p'. If 'data_pp' is not null, it will set
+ * '*data_pp' to point past the integer read.
+\*---------------------------------------------------------------------------*/
+{
+ unsigned int u16_be = ((unsigned int)data_p[0] << 8) | data_p[1];
+
+ if (data_pp != NULL) {
+ *data_pp = (unsigned char *)(data_p + 2);
+ }
+
+ return u16_be;
+}
+
+unsigned int
+ys_read_u16_le(const unsigned char *data_p, const unsigned char **data_pp)
+/*---------------------------------------------------------------------------*\
+ * Reads an unsigned 16 bit integer in little-endian format from the array of
+ * bytes pointed to by 'data_p'. If 'data_pp' is not null, it will set
+ * '*data_pp' to point past the integer read.
+\*---------------------------------------------------------------------------*/
+{
+ unsigned int u16_le = ((unsigned int)data_p[1] << 8) | data_p[0];
+
+ if (data_pp != NULL) {
+ *data_pp = (unsigned char *)(data_p + 2);
+ }
+
+ return u16_le;
+}
+
+int ys_read_s16_be(const unsigned char *data_p, const unsigned char **data_pp)
+/*---------------------------------------------------------------------------*\
+ * Reads a signed 16 bit integer in big-endian, 2's complement format from
+ * the array of bytes pointed to by 'data_p'.
+ * If 'data_pp' is not null, it will set '*data_pp' to point past the integer
+ * read.
+\*---------------------------------------------------------------------------*/
+{
+ unsigned int u16_be = ((unsigned int)data_p[0] << 8) | data_p[1];
+ int s16_be;
+
+#ifndef YS_ASSUME_2S_COMP
+ if (u16_be & 0x8000U) {
+ s16_be = (int)(u16_be - 0x8000U) - 0x7FFF - 1;
+ } else
+#endif
+ s16_be = u16_be;
+
+ if (data_pp != NULL) {
+ *data_pp = (unsigned char *)(data_p + 2);
+ }
+
+ return s16_be;
+}
+
+int ys_read_s16_le(const unsigned char *data_p, const unsigned char **data_pp)
+/*---------------------------------------------------------------------------*\
+ * Reads a signed 16 bit integer in little-endian, 2's complement format from
+ * the array of bytes pointed to by 'data_p'.
+ * If 'data_pp' is not null, it will set '*data_pp' to point past the integer
+ * read.
+\*---------------------------------------------------------------------------*/
+{
+ unsigned int u16_le = ((unsigned int)data_p[1] << 8) | data_p[0];
+ int s16_le;
+
+#ifndef YS_ASSUME_2S_COMP
+ if (u16_le & 0x8000U) {
+ s16_le = (int)(u16_le - 0x8000U) - 0x7FFF - 1;
+ } else
+#endif
+ s16_le = u16_le;
+
+ if (data_pp != NULL) {
+ *data_pp = (unsigned char *)(data_p + 2);
+ }
+
+ return s16_le;
+}
+
+unsigned long
+ys_read_u24_be(const unsigned char *data_p, const unsigned char **data_pp)
+/*---------------------------------------------------------------------------*\
+ * Reads an unsigned 24 bit integer in big-endian format from the array of
+ * bytes pointed to by 'data_p'. If 'data_pp' is not null, it will set
+ * '*data_pp' to point past the integer read.
+\*---------------------------------------------------------------------------*/
+{
+ unsigned long u24_be = ((unsigned long)data_p[0] << 16) |
+ ((unsigned long)data_p[1] << 8) | data_p[2];
+
+ if (data_pp != NULL) {
+ *data_pp = (unsigned char *)(data_p + 3);
+ }
+
+ return u24_be;
+}
+
+unsigned long
+ys_read_u24_le(const unsigned char *data_p, const unsigned char **data_pp)
+/*---------------------------------------------------------------------------*\
+ * Reads an unsigned 24 bit integer in big-endian format from the array of
+ * bytes pointed to by 'data_p'. If 'data_pp' is not null, it will set
+ * '*data_pp' to point past the integer read.
+\*---------------------------------------------------------------------------*/
+{
+ unsigned long u24_le = ((unsigned long)data_p[3] << 16) |
+ ((unsigned long)data_p[2] << 8) | data_p[0];
+
+ if (data_pp != NULL) {
+ *data_pp = (unsigned char *)(data_p + 3);
+ }
+
+ return u24_le;
+}
+
+long ys_read_s24_be(const unsigned char *data_p, const unsigned char **data_pp)
+/*---------------------------------------------------------------------------*\
+ * Reads a signed 24 bit integer in big-endian, 2's complement format from
+ * the array of bytes pointed to by 'data_p'.
+ * If 'data_pp' is not null, it will set '*data_pp' to point past the integer
+ * read.
+\*---------------------------------------------------------------------------*/
+{
+ unsigned long u24_be = ((unsigned long)data_p[0] << 16) |
+ ((unsigned long)data_p[1] << 8) | data_p[2];
+ long s24_be;
+
+#ifndef YS_ASSUME_2S_COMP
+ if (u24_be & 0x800000UL) {
+ s24_be = (long)(u24_be - 0x800000UL) - 0x800000;
+ } else
+#endif
+ s24_be = u24_be;
+
+ if (data_pp != NULL) {
+ *data_pp = (unsigned char *)(data_p + 3);
+ }
+
+ return s24_be;
+}
+
+long ys_read_s24_le(const unsigned char *data_p, const unsigned char **data_pp)
+/*---------------------------------------------------------------------------*\
+ * Reads a signed 24 bit integer in little-endian, 2's complement format from
+ * the array of bytes pointed to by 'data_p'.
+ * If 'data_pp' is not null, it will set '*data_pp' to point past the integer
+ * read.
+\*---------------------------------------------------------------------------*/
+{
+ unsigned long u24_be = ((unsigned long)data_p[2] << 16) |
+ ((unsigned long)data_p[1] << 8) | data_p[0];
+ long s24_be;
+
+#ifndef YS_ASSUME_2S_COMP
+ if (u24_be & 0x800000UL) {
+ s24_be = (long)(u24_be - 0x800000UL) - 0x800000;
+ } else
+#endif
+ s24_be = u24_be;
+
+ if (data_pp != NULL) {
+ *data_pp = (unsigned char *)(data_p + 3);
+ }
+
+ return s24_be;
+}
+
+unsigned long
+ys_read_u32_be(const unsigned char *data_p, const unsigned char **data_pp)
+/*---------------------------------------------------------------------------*\
+ * Reads an unsigned 32 bit integer in big-endian format from the array of
+ * bytes pointed to by 'data_p'. If 'data_pp' is not null, it will set
+ * '*data_pp' to point past the integer read.
+\*---------------------------------------------------------------------------*/
+{
+ unsigned long u32_be = ((unsigned long)data_p[0] << 24) |
+ ((unsigned long)data_p[1] << 16) |
+ ((unsigned long)data_p[2] << 8) | data_p[3];
+
+ if (data_pp != NULL) {
+ *data_pp = (unsigned char *)(data_p + 4);
+ }
+
+ return u32_be;
+}
+
+unsigned long
+ys_read_u32_le(const unsigned char *data_p, const unsigned char **data_pp)
+/*---------------------------------------------------------------------------*\
+ * Reads an unsigned 32 bit integer in little-endian format from the array of
+ * bytes pointed to by 'data_p'. If 'data_pp' is not null, it will set
+ * '*data_pp' to point past the integer read.
+\*---------------------------------------------------------------------------*/
+{
+ unsigned long u32_le = ((unsigned long)data_p[3] << 24) |
+ ((unsigned long)data_p[2] << 16) |
+ ((unsigned long)data_p[1] << 8) | data_p[0];
+
+ if (data_pp != NULL) {
+ *data_pp = (unsigned char *)(data_p + 4);
+ }
+
+ return u32_le;
+}
+
+long ys_read_s32_be(const unsigned char *data_p, const unsigned char **data_pp)
+/*---------------------------------------------------------------------------*\
+ * Reads a signed 32 bit integer in big-endian, 2's complement format from
+ * the array of bytes pointed to by 'data_p'.
+ * If 'data_pp' is not null, it will set '*data_pp' to point past the integer
+ * read.
+\*---------------------------------------------------------------------------*/
+{
+ unsigned long u32_be = ((unsigned long)data_p[0] << 24) |
+ ((unsigned long)data_p[1] << 16) |
+ ((unsigned long)data_p[2] << 8) | data_p[3];
+ long s32_be;
+
+#ifndef YS_ASSUME_2S_COMP
+ if (u32_be & 0x80000000UL) {
+ s32_be = (long)(u32_be - 0x80000000UL) - 0x7FFFFFFF - 1;
+ } else
+#endif
+ s32_be = u32_be;
+
+ if (data_pp != NULL) {
+ *data_pp = (unsigned char *)(data_p + 4);
+ }
+
+ return s32_be;
+}
+
+long ys_read_s32_le(const unsigned char *data_p, const unsigned char **data_pp)
+/*---------------------------------------------------------------------------*\
+ * Reads a signed 32 bit integer in little-endian, 2's complement format from
+ * the array of bytes pointed to by 'data_p'.
+ * If 'data_pp' is not null, it will set '*data_pp' to point past the integer
+ * read.
+\*---------------------------------------------------------------------------*/
+{
+ unsigned long u32_le = ((unsigned long)data_p[3] << 24) |
+ ((unsigned long)data_p[2] << 16) |
+ ((unsigned long)data_p[1] << 8) | data_p[0];
+ long s32_le;
+
+#ifndef YS_ASSUME_2S_COMP
+ if (u32_le & 0x80000000UL) {
+ s32_le = (long)(u32_le - 0x80000000UL) - 0x7FFFFFFF - 1;
+ } else
+#endif
+ s32_le = u32_le;
+
+ if (data_pp != NULL) {
+ *data_pp = (unsigned char *)(data_p + 4);
+ }
+
+ return s32_le;
+}
+
+} // End of namespace Saga
diff --git a/saga/ys_binwrite.cpp b/saga/ys_binwrite.cpp
new file mode 100644
index 0000000000..ae10e364a2
--- /dev/null
+++ b/saga/ys_binwrite.cpp
@@ -0,0 +1,296 @@
+/* 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 <stddef.h>
+
+namespace Saga {
+void
+ys_write_u8(unsigned int u8, unsigned char *data_p, unsigned char **data_pp)
+{
+ *data_p = (unsigned char)(u8 & 0xFFU);
+
+ if (data_pp != NULL) {
+ *data_pp = data_p + 1;
+ }
+
+ return;
+}
+
+void
+ys_write_u16_be(unsigned int u16_be,
+ unsigned char *data_p, unsigned char **data_pp)
+/*---------------------------------------------------------------------------*\
+ * Writes an unsigned 16 bit integer in big-endian format to the buffer
+ * pointed to by 'data_p'.
+ * If 'data_pp' is not null, the function will set it to point just beyond
+ * the integer written.
+\*---------------------------------------------------------------------------*/
+{
+ data_p[0] = (unsigned char)((u16_be >> 8) & 0xFFU);
+ data_p[1] = (unsigned char)(u16_be & 0xFFU);
+
+ if (data_pp != NULL) {
+ *data_pp = data_p + 2;
+ }
+
+ return;
+}
+
+void
+ys_write_u16_le(unsigned int u16_le,
+ unsigned char *data_p, unsigned char **data_pp)
+/*---------------------------------------------------------------------------*\
+ * Writes an unsigned 16 bit integer in little-endian format to the buffer
+ * pointed to by 'data_p'.
+ * If 'data_pp' is not null, the function will set it to point just beyond
+ * the integer written.
+\*---------------------------------------------------------------------------*/
+{
+ data_p[0] = (unsigned char)(u16_le & 0xFFU);
+ data_p[1] = (unsigned char)((u16_le >> 8) & 0xFFU);
+
+ if (data_pp != NULL) {
+ *data_pp = data_p + 2;
+ }
+
+ return;
+}
+
+void
+ys_write_s16_be(int s16_be, unsigned char *data_p, unsigned char **data_pp)
+/*---------------------------------------------------------------------------*\
+ * Writes an signed 16 bit integer in big-endian format and two's
+ * complement representation to the buffer pointed to by 'data_p'.
+ * If 'data_pp' is not null, the function will set it to point just beyond
+ * the integer written.
+\*---------------------------------------------------------------------------*/
+{
+ unsigned int u16_be = s16_be;
+
+ data_p[0] = (unsigned char)((u16_be >> 8) & 0xFFU);
+ data_p[1] = (unsigned char)(u16_be & 0xFFU);
+
+ if (data_pp != NULL) {
+ *data_pp = data_p + 2;
+ }
+
+ return;
+}
+
+void
+ys_write_s16_le(int s16_le, unsigned char *data_p, unsigned char **data_pp)
+/*---------------------------------------------------------------------------*\
+ * Writes an signed 16 bit integer in little-endian format and two's
+ * complement representation to the buffer pointed to by 'data_p'.
+ * If 'data_pp' is not null, the function will set it to point just beyond
+ * the integer written.
+\*---------------------------------------------------------------------------*/
+{
+ unsigned int u16_le = s16_le;
+
+ data_p[0] = (unsigned char)(u16_le & 0xFFU);
+ data_p[1] = (unsigned char)((u16_le >> 8) & 0xFFU);
+
+ if (data_pp != NULL) {
+ *data_pp = data_p + 2;
+ }
+
+ return;
+}
+
+void
+ys_write_u24_be(unsigned long u24_be,
+ unsigned char *data_p, unsigned char **data_pp)
+/*---------------------------------------------------------------------------*\
+ * Writes an unsigned 24 bit integer in big-endian format to the buffer
+ * pointed to by 'data_p'.
+ * If 'data_pp' is not null, the function will set it to point just beyond
+ * the integer written.
+\*---------------------------------------------------------------------------*/
+{
+ data_p[0] = (unsigned char)((u24_be >> 16) & 0xFFU);
+ data_p[1] = (unsigned char)((u24_be >> 8) & 0xFFU);
+ data_p[2] = (unsigned char)(u24_be & 0xFFU);
+
+ if (data_pp != NULL) {
+ *data_pp = data_p + 3;
+ }
+
+ return;
+}
+
+void
+ys_write_u24_le(unsigned long u24_le,
+ unsigned char *data_p, unsigned char **data_pp)
+/*---------------------------------------------------------------------------*\
+ * Writes an unsigned 24 bit integer in little-endian format to the buffer
+ * pointed to by 'data_p'.
+ * If 'data_pp' is not null, the function will set it to point just beyond
+ * the integer written.
+\*---------------------------------------------------------------------------*/
+{
+ data_p[0] = (unsigned char)(u24_le & 0xFFU);
+ data_p[1] = (unsigned char)((u24_le >> 8) & 0xFFU);
+ data_p[2] = (unsigned char)((u24_le >> 16) & 0xFFU);
+
+ if (data_pp != NULL) {
+ *data_pp = data_p + 3;
+ }
+
+ return;
+}
+
+void
+ys_write_s24_be(long s24_be, unsigned char *data_p, unsigned char **data_pp)
+/*---------------------------------------------------------------------------*\
+ * Writes an signed 24 bit integer in big-endian format and two's
+ * complement representation to the buffer pointed to by 'data_p'.
+ * If 'data_pp' is not null, the function will set it to point just beyond
+ * the integer written.
+\*---------------------------------------------------------------------------*/
+{
+ unsigned long u24_be = s24_be;
+
+ data_p[0] = (unsigned char)((u24_be >> 16) & 0xFFU);
+ data_p[1] = (unsigned char)((u24_be >> 8) & 0xFFU);
+ data_p[2] = (unsigned char)(u24_be & 0xFFU);
+
+ if (data_pp != NULL) {
+ *data_pp = data_p + 3;
+ }
+
+ return;
+}
+
+void
+ys_write_s24_le(long s24_le, unsigned char *data_p, unsigned char **data_pp)
+/*---------------------------------------------------------------------------*\
+ * Writes an signed 24 bit integer in little-endian format and two's
+ * complement representation to the buffer pointed to by 'data_p'.
+ * If 'data_pp' is not null, the function will set it to point just beyond
+ * the integer written.
+\*---------------------------------------------------------------------------*/
+{
+ unsigned long u24_le = s24_le;
+
+ data_p[0] = (unsigned char)(u24_le & 0xFFU);
+ data_p[1] = (unsigned char)((u24_le >> 8) & 0xFFU);
+ data_p[2] = (unsigned char)((u24_le >> 16) & 0xFFU);
+
+ if (data_pp != NULL) {
+ *data_pp = (unsigned char *)(data_p + 3);
+ }
+
+ return;
+}
+
+void
+ys_write_u32_be(unsigned long u32_be,
+ unsigned char *data_p, unsigned char **data_pp)
+/*---------------------------------------------------------------------------*\
+ * Writes an unsigned 32 bit integer in big-endian format to the buffer
+ * pointed to by 'data_p'.
+ * If 'data_pp' is not null, the function will set it to point just beyond
+ * the integer written.
+\*---------------------------------------------------------------------------*/
+{
+ data_p[0] = (unsigned char)((u32_be >> 24) & 0xFFU);
+ data_p[1] = (unsigned char)((u32_be >> 16) & 0xFFU);
+ data_p[2] = (unsigned char)((u32_be >> 8) & 0xFFU);
+ data_p[3] = (unsigned char)(u32_be & 0xFFU);
+
+ if (data_pp != NULL) {
+ *data_pp = data_p + 4;
+ }
+
+ return;
+}
+
+void
+ys_write_u32_le(unsigned long u32_le,
+ unsigned char *data_p, unsigned char **data_pp)
+/*---------------------------------------------------------------------------*\
+ * Writes an unsigned 32 bit integer in little-endian format to the buffer
+ * pointed to by 'data_p'.
+ * If 'data_pp' is not null, the function will set it to point just beyond
+ * the integer written.
+\*---------------------------------------------------------------------------*/
+{
+ data_p[0] = (unsigned char)(u32_le & 0xFFU);
+ data_p[1] = (unsigned char)((u32_le >> 8) & 0xFFU);
+ data_p[2] = (unsigned char)((u32_le >> 16) & 0xFFU);
+ data_p[3] = (unsigned char)((u32_le >> 24) & 0xFFU);
+
+ if (data_pp != NULL) {
+ *data_pp = data_p + 4;
+ }
+
+ return;
+}
+
+void
+ys_write_s32_be(long s32_be, unsigned char *data_p, unsigned char **data_pp)
+/*---------------------------------------------------------------------------*\
+ * Writes an signed 32 bit integer in big-endian format and two's
+ * complement representation to the buffer pointed to by 'data_p'.
+ * If 'data_pp' is not null, the function will set it to point just beyond
+ * the integer written.
+\*---------------------------------------------------------------------------*/
+{
+ unsigned long u32_be = s32_be;
+
+ data_p[0] = (unsigned char)((u32_be >> 24) & 0xFFU);
+ data_p[1] = (unsigned char)((u32_be >> 16) & 0xFFU);
+ data_p[2] = (unsigned char)((u32_be >> 8) & 0xFFU);
+ data_p[3] = (unsigned char)(u32_be & 0xFFU);
+
+ if (data_pp != NULL) {
+ *data_pp = data_p + 4;
+ }
+
+ return;
+}
+
+void
+ys_write_s32_le(long s32_le, unsigned char *data_p, unsigned char **data_pp)
+/*---------------------------------------------------------------------------*\
+ * Writes an signed 32 bit integer in little-endian format and two's
+ * complement representation to the buffer pointed to by 'data_p'.
+ * If 'data_pp' is not null, the function will set it to point just beyond
+ * the integer written.
+\*---------------------------------------------------------------------------*/
+{
+ unsigned long u32_le = s32_le;
+
+ data_p[0] = (unsigned char)(u32_le & 0xFFU);
+ data_p[1] = (unsigned char)((u32_le >> 8) & 0xFFU);
+ data_p[2] = (unsigned char)((u32_le >> 16) & 0xFFU);
+ data_p[3] = (unsigned char)((u32_le >> 24) & 0xFFU);
+
+ if (data_pp != NULL) {
+ *data_pp = data_p + 4;
+ }
+
+ return;
+}
+
+} // End of namespace Saga
diff --git a/saga/ys_dl_list.cpp b/saga/ys_dl_list.cpp
new file mode 100644
index 0000000000..116f52e8ea
--- /dev/null
+++ b/saga/ys_dl_list.cpp
@@ -0,0 +1,310 @@
+/* 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 "reinherit.h"
+
+#include "yslib.h"
+
+namespace Saga {
+
+YS_DL_LIST *ys_dll_create(void)
+{
+
+ 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;
+
+ return;
+}
+
+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;
+}
+
+int
+ys_dll_foreach(YS_DL_NODE * list,
+ int direction,
+ void *param,
+ int (*ys_dll_proc) (void *data, void *param), YS_DL_NODE ** t_node)
+{
+ YS_DL_NODE *walk_p;
+
+ /* Only walk bakcward if explicitly requested to */
+ if (direction == YS_WALK_BACKWARD) {
+ for (walk_p = list->prev; walk_p != list;
+ walk_p = walk_p->prev) {
+
+ if (ys_dll_proc(walk_p->data, param) == 0) {
+ break;
+ }
+
+ }
+ } else {
+ /* Default behavior is to walk forwards */
+ for (walk_p = list->next; walk_p != list;
+ walk_p = walk_p->next) {
+
+ if (ys_dll_proc(walk_p->data, param) == 0) {
+ break;
+ }
+ }
+ }
+
+ if (t_node) {
+ *t_node = (walk_p != list) ? walk_p : NULL;
+ }
+
+ return YS_E_SUCCESS;
+}
+
+} // End of namespace Saga
diff --git a/saga/ys_file.cpp b/saga/ys_file.cpp
new file mode 100644
index 0000000000..39cb84cff0
--- /dev/null
+++ b/saga/ys_file.cpp
@@ -0,0 +1,63 @@
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "yslib.h"
+
+namespace Saga {
+
+int ys_get_filesize(FILE * file_p, unsigned long *len_p, int *p_errno)
+/*--------------------------------------------------------------------------*\
+ * Returns the 'size' of the specified file. The file must be opened in
+ * binary mode. Note that not all operating systems support determing the
+ * exact end of a binary file stream, so this function is limited in
+ * portability.
+\*--------------------------------------------------------------------------*/
+{
+ long f_pos;
+ long f_len;
+
+ f_pos = ftell(file_p);
+ if (f_pos == -1) {
+ *p_errno = errno;
+ return YS_E_FAILURE;
+ }
+
+ fseek(file_p, 0, SEEK_END);
+
+ f_len = ftell(file_p);
+ if (f_pos == -1) {
+ *p_errno = errno;
+ return YS_E_FAILURE;
+ }
+
+ fseek(file_p, f_pos, SEEK_SET);
+
+ *len_p = (unsigned long)f_len;
+
+ return YS_E_SUCCESS;;
+}
+
+} // End of namespace Saga
diff --git a/saga/yslib.h b/saga/yslib.h
new file mode 100644
index 0000000000..b5bc464d2c
--- /dev/null
+++ b/saga/yslib.h
@@ -0,0 +1,219 @@
+/* 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
+\*------------------------------------------------------------------*/
+
+/* Ignore a parameter (Supress warnings) */
+#define YS_IGNORE_PARAM( param ) ( void )( param )
+
+/* Calculate the number of elements in an array */
+#define YS_NELEMS( arr ) (( sizeof arr ) / ( sizeof *arr ))
+
+#define YS_DUMMY_DECL /* C99 permits statements before declarations */
+
+#define YS_REG_FUNC( arr ) YS_DUMMY_DECL
+#define YS_FUNC __func__
+
+#define YS_FLEX_ARRAY
+#define YS_FLEX_ARRAY_MOD 0
+
+/* Minimum and maximum of two values */
+#define YS_MIN(a,b) (((a) < (b)) ? (a) : (b))
+#define YS_MAX(a,b) (((a) > (b)) ? (a) : (b))
+
+/* Minimum and maximum of two objects, convert to lvalue */
+#define YS_LV_MIN(a,b) (*((a) < (b)) ? &(a) : &(b))
+#define YS_LV_MAX(a,b) (*((a) < (b)) ? &(a) : &(b))
+
+#define YS_ABS(n) ((n < 0) ? -n : n)
+
+/* ys_binread.c : Binary input functions (buffer oriented)
+\*------------------------------------------------------------------*/
+
+/* #define YS_ASSUME_2S_COMP */
+
+/* Read a 4CC ( Four characater code ) */
+void
+ys_read_4cc(char *fourcc,
+ const unsigned char *data_p, const unsigned char **data_pp);
+
+/* Read 8 bit unsigned integer */
+unsigned int ys_read_u8(const unsigned char *, const unsigned char **);
+
+/* Read 8 bit signed integer */
+int ys_read_s8(const unsigned char *, const unsigned char **);
+
+/* Read 16 bit unsigned integer, big-endian */
+unsigned int ys_read_u16_be(const unsigned char *, const unsigned char **);
+
+/* Read 16 bit unsigned integer, little-endian */
+unsigned int ys_read_u16_le(const unsigned char *, const unsigned char **);
+
+/* Read 16 bit signed integer, 2's complement, big-endian */
+int ys_read_s16_be(const unsigned char *, const unsigned char **);
+
+/* Read 16 bit signed integer, 2's complement, little-endian */
+int ys_read_s16_le(const unsigned char *, const unsigned char **);
+
+/* Read 24 bit unsigned integer, big-endian */
+unsigned long ys_read_u24_be(const unsigned char *, const unsigned char **);
+
+/* Read 24 bit unsigned integer, little-endian */
+unsigned long ys_read_u24_le(const unsigned char *, const unsigned char **);
+
+/* Read 24 bit signed integer, 2's complement, big-endian */
+long ys_read_s24_be(const unsigned char *, const unsigned char **);
+
+/* Read 24 bit signed integer, 2's complement, little-endian */
+long ys_read_s24_le(const unsigned char *, const unsigned char **);
+
+/* Read 32 bit unsigned integer, big-endian */
+unsigned long ys_read_u32_be(const unsigned char *, const unsigned char **);
+
+/* Read 32 bit unsigned integer, little-endian */
+unsigned long ys_read_u32_le(const unsigned char *, const unsigned char **);
+
+/* Read 32 bit signed integer, 2's complement, big-endian */
+long ys_read_s32_be(const unsigned char *, const unsigned char **);
+
+/* Read 32 bit signed integer, 2's complement, little-endian */
+long ys_read_s32_le(const unsigned char *, const unsigned char **);
+
+/* ys_binwrite.c : Binary output functions ( buffer oriented )
+\*------------------------------------------------------------------*/
+
+void ys_write_u8(unsigned int, unsigned char *, unsigned char **);
+
+/* Write 16 bit unsigned integer, big-endian */
+void ys_write_u16_be(unsigned int, unsigned char *, unsigned char **);
+
+/* Write 16 bit unsigned integer, little-endian */
+void ys_write_u16_le(unsigned int, unsigned char *, unsigned char **);
+
+/* Write 16 bit signed integer, 2's complement, big-endian */
+void ys_write_s16_be(int, unsigned char *, unsigned char **);
+
+/* Write 16 bit signed integer, 2's complement, little-endian */
+void ys_write_s16_le(int, unsigned char *, unsigned char **);
+
+/* Write 24 bit unsigned integer, big-endian */
+void ys_write_u24_be(unsigned long, unsigned char *, unsigned char **);
+
+/* Write 24 bit unsigned integer, little-endian */
+void ys_write_u24_le(unsigned long, unsigned char *, unsigned char **);
+
+/* Write 24 bit signed integer, 2's complement, big-endian */
+void ys_write_s24_be(long, unsigned char *, unsigned char **);
+
+/* Write 24 bit signed integer, 2's complement, little-endian */
+void ys_write_s24_le(long, unsigned char *, unsigned char **);
+
+/* Write 32 bit unsigned integer, big-endian */
+void ys_write_u32_be(unsigned long, unsigned char *, unsigned char **);
+
+/* Write 32 bit unsigned integer, little-endian */
+void ys_write_u32_le(unsigned long, unsigned char *, unsigned char **);
+
+/* Write 32 bit signed integer, 2's complement, big-endian */
+void ys_write_s32_be(long, unsigned char *, unsigned char **);
+
+/* Write 32 bit signed integer, 2's complement, little-endian */
+void ys_write_s32_le(long, unsigned char *, unsigned char **);
+
+
+/* ys_file.c : File management functions
+\*------------------------------------------------------------------*/
+int ys_get_filesize(FILE *, unsigned long *, int *);
+
+/* Shared declarations for list modules
+\*------------------------------------------------------------------*/
+enum YS_WALK_DIRECTIONS {
+ YS_WALK_BACKWARD = 0,
+ YS_WALK_FORWARD
+};
+
+/* ys_dl_list.c : Doubly-linked list functions
+\*------------------------------------------------------------------*/
+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);
+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 *);
+
+int ys_dll_foreach(YS_DL_LIST *,
+ int, void *, int (*)(void *, void *), YS_DL_NODE **);
+
+
+} // End of namespace Saga
+
+#endif /* YSLIB_MAIN_H__ */