From f3d340fb0ce72b9db59b8c701153bc82b595f75e Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Mon, 12 Apr 2004 21:40:49 +0000 Subject: 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 --- saga/actionmap.cpp | 252 ++++++++ saga/actionmap.h | 67 +++ saga/actionmap_mod.h | 49 ++ saga/actor.cpp | 1456 ++++++++++++++++++++++++++++++++++++++++++++++ saga/actor.h | 234 ++++++++ saga/actor_mod.h | 100 ++++ saga/actordata.cpp | 227 ++++++++ saga/actordata.h | 62 ++ saga/animation.cpp | 1192 +++++++++++++++++++++++++++++++++++++ saga/animation.h | 139 +++++ saga/animation_mod.h | 67 +++ saga/binread.cpp | 151 ----- saga/binread.h | 73 --- saga/cmdline.cpp | 95 +++ saga/console.cpp | 567 ++++++++++++++++++ saga/console.h | 96 +++ saga/console_mod.h | 59 ++ saga/cvar.cpp | 612 +++++++++++++++++++ saga/cvar.h | 100 ++++ saga/cvar_mod.h | 112 ++++ saga/events.cpp | 613 +++++++++++++++++++ saga/events.h | 63 ++ saga/events_mod.h | 143 +++++ saga/expr.cpp | 464 +++++++++++++++ saga/expr.h | 43 ++ saga/font.cpp | 721 +++++++++++++++++++++++ saga/font.h | 132 +++++ saga/font_map.cpp | 295 ++++++++++ saga/font_mod.h | 71 +++ saga/game.cpp | 839 ++++++++++++++++++++++++++ saga/game.h | 133 +++++ saga/game_mod.h | 148 +++++ saga/gamedesc.cpp | 449 -------------- saga/gamedesc.h | 129 ---- saga/gamedesc_priv.h | 82 ++- saga/gfx.cpp | 1098 ++++++++++++++++++++++++++++++++++ saga/gfx.h | 54 ++ saga/gfx_mod.h | 99 ++++ saga/ihnm_introproc.cpp | 360 ++++++++++++ saga/ihnm_introproc.h | 44 ++ saga/image.cpp | 510 ++++++++++++++++ saga/image.h | 64 ++ saga/image_mod.h | 46 ++ saga/interface.cpp | 756 ++++++++++++++++++++++++ saga/interface.h | 198 +++++++ saga/interface_mod.h | 57 ++ saga/isomap.cpp | 371 ++++++++++++ saga/isomap.h | 104 ++++ saga/isomap_mod.h | 48 ++ saga/ite_introproc.cpp | 1177 +++++++++++++++++++++++++++++++++++++ saga/ite_introproc.h | 92 +++ saga/ite_introproc_mod.h | 40 ++ saga/math.cpp | 72 +++ saga/math.h | 35 ++ saga/math_mod.h | 42 ++ saga/misc.cpp | 54 ++ saga/module.mk | 52 +- saga/objectmap.cpp | 556 ++++++++++++++++++ saga/objectmap.h | 75 +++ saga/objectmap_mod.h | 70 +++ saga/palanim.cpp | 266 +++++++++ saga/palanim.h | 63 ++ saga/palanim_mod.h | 46 ++ saga/reinherit.h | 333 +++++++++++ saga/render.cpp | 588 +++++++++++++++++++ saga/render.h | 84 +++ saga/render_mod.h | 92 +++ saga/resfile.cpp | 162 ------ saga/resfile.h | 107 ---- saga/resnames.h | 130 ----- saga/rscfile.cpp | 310 ++++++++++ saga/rscfile.h | 70 +++ saga/rscfile_mod.h | 59 ++ saga/saga.cpp | 250 +++++++- saga/saga.h | 20 +- saga/scene.cpp | 1159 ++++++++++++++++++++++++++++++++++++ saga/scene.h | 229 ++++++++ saga/scene_mod.h | 103 ++++ saga/sceneproc.cpp | 200 +++++++ saga/sceneproc.h | 40 ++ saga/script.cpp | 684 ++++++++++++++++++++++ saga/script.h | 157 +++++ saga/script_mod.h | 89 +++ saga/sdata.cpp | 210 +++++++ saga/sdata.h | 44 ++ saga/sdebug.cpp | 658 +++++++++++++++++++++ saga/sfuncs.cpp | 811 ++++++++++++++++++++++++++ saga/sfuncs.h | 103 ++++ saga/sndres.cpp | 353 +++++++++++ saga/sndres.h | 92 +++ saga/sndres_mod.h | 52 ++ saga/sprite.cpp | 567 ++++++++++++++++++ saga/sprite.h | 88 +++ saga/sprite_mod.h | 61 ++ saga/sstack.cpp | 199 +++++++ saga/sstack.h | 81 +++ saga/stack.cpp | 180 ++++++ saga/stack.h | 49 ++ saga/stack_mod.h | 69 +++ saga/sthread.cpp | 1120 +++++++++++++++++++++++++++++++++++ saga/sthread.h | 69 +++ saga/sys_fs.cpp | 82 +++ saga/sys_interface.h | 49 ++ saga/sysgfx.cpp | 548 +++++++++++++++++ saga/sysgfx.h | 51 ++ saga/sysinput.cpp | 238 ++++++++ saga/sysio.cpp | 65 +++ saga/sysmusic.cpp | 98 ++++ saga/syssound.cpp | 173 ++++++ saga/systimer.cpp | 144 +++++ saga/systimer.h | 54 ++ saga/text.cpp | 342 +++++++++++ saga/text.h | 46 ++ saga/text_mod.h | 70 +++ saga/transitions.cpp | 83 +++ saga/x86_32.h | 46 ++ saga/xmidi.cpp | 832 ++++++++++++++++++++++++++ saga/xmidi.h | 117 ++++ saga/xmidi_mod.h | 115 ++++ saga/ys_binread.cpp | 350 +++++++++++ saga/ys_binwrite.cpp | 296 ++++++++++ saga/ys_dl_list.cpp | 310 ++++++++++ saga/ys_file.cpp | 63 ++ saga/yslib.h | 219 +++++++ 124 files changed, 29263 insertions(+), 1284 deletions(-) create mode 100644 saga/actionmap.cpp create mode 100644 saga/actionmap.h create mode 100644 saga/actionmap_mod.h create mode 100644 saga/actor.cpp create mode 100644 saga/actor.h create mode 100644 saga/actor_mod.h create mode 100644 saga/actordata.cpp create mode 100644 saga/actordata.h create mode 100644 saga/animation.cpp create mode 100644 saga/animation.h create mode 100644 saga/animation_mod.h delete mode 100644 saga/binread.cpp delete mode 100644 saga/binread.h create mode 100644 saga/cmdline.cpp create mode 100644 saga/console.cpp create mode 100644 saga/console.h create mode 100644 saga/console_mod.h create mode 100644 saga/cvar.cpp create mode 100644 saga/cvar.h create mode 100644 saga/cvar_mod.h create mode 100644 saga/events.cpp create mode 100644 saga/events.h create mode 100644 saga/events_mod.h create mode 100644 saga/expr.cpp create mode 100644 saga/expr.h create mode 100644 saga/font.cpp create mode 100644 saga/font.h create mode 100644 saga/font_map.cpp create mode 100644 saga/font_mod.h create mode 100644 saga/game.cpp create mode 100644 saga/game.h create mode 100644 saga/game_mod.h delete mode 100644 saga/gamedesc.cpp delete mode 100644 saga/gamedesc.h create mode 100644 saga/gfx.cpp create mode 100644 saga/gfx.h create mode 100644 saga/gfx_mod.h create mode 100644 saga/ihnm_introproc.cpp create mode 100644 saga/ihnm_introproc.h create mode 100644 saga/image.cpp create mode 100644 saga/image.h create mode 100644 saga/image_mod.h create mode 100644 saga/interface.cpp create mode 100644 saga/interface.h create mode 100644 saga/interface_mod.h create mode 100644 saga/isomap.cpp create mode 100644 saga/isomap.h create mode 100644 saga/isomap_mod.h create mode 100644 saga/ite_introproc.cpp create mode 100644 saga/ite_introproc.h create mode 100644 saga/ite_introproc_mod.h create mode 100644 saga/math.cpp create mode 100644 saga/math.h create mode 100644 saga/math_mod.h create mode 100644 saga/misc.cpp create mode 100644 saga/objectmap.cpp create mode 100644 saga/objectmap.h create mode 100644 saga/objectmap_mod.h create mode 100644 saga/palanim.cpp create mode 100644 saga/palanim.h create mode 100644 saga/palanim_mod.h create mode 100644 saga/reinherit.h create mode 100644 saga/render.cpp create mode 100644 saga/render.h create mode 100644 saga/render_mod.h delete mode 100644 saga/resfile.cpp delete mode 100644 saga/resfile.h delete mode 100644 saga/resnames.h create mode 100644 saga/rscfile.cpp create mode 100644 saga/rscfile.h create mode 100644 saga/rscfile_mod.h create mode 100644 saga/scene.cpp create mode 100644 saga/scene.h create mode 100644 saga/scene_mod.h create mode 100644 saga/sceneproc.cpp create mode 100644 saga/sceneproc.h create mode 100644 saga/script.cpp create mode 100644 saga/script.h create mode 100644 saga/script_mod.h create mode 100644 saga/sdata.cpp create mode 100644 saga/sdata.h create mode 100644 saga/sdebug.cpp create mode 100644 saga/sfuncs.cpp create mode 100644 saga/sfuncs.h create mode 100644 saga/sndres.cpp create mode 100644 saga/sndres.h create mode 100644 saga/sndres_mod.h create mode 100644 saga/sprite.cpp create mode 100644 saga/sprite.h create mode 100644 saga/sprite_mod.h create mode 100644 saga/sstack.cpp create mode 100644 saga/sstack.h create mode 100644 saga/stack.cpp create mode 100644 saga/stack.h create mode 100644 saga/stack_mod.h create mode 100644 saga/sthread.cpp create mode 100644 saga/sthread.h create mode 100644 saga/sys_fs.cpp create mode 100644 saga/sys_interface.h create mode 100644 saga/sysgfx.cpp create mode 100644 saga/sysgfx.h create mode 100644 saga/sysinput.cpp create mode 100644 saga/sysio.cpp create mode 100644 saga/sysmusic.cpp create mode 100644 saga/syssound.cpp create mode 100644 saga/systimer.cpp create mode 100644 saga/systimer.h create mode 100644 saga/text.cpp create mode 100644 saga/text.h create mode 100644 saga/text_mod.h create mode 100644 saga/transitions.cpp create mode 100644 saga/x86_32.h create mode 100644 saga/xmidi.cpp create mode 100644 saga/xmidi.h create mode 100644 saga/xmidi_mod.h create mode 100644 saga/ys_binread.cpp create mode 100644 saga/ys_binwrite.cpp create mode 100644 saga/ys_dl_list.cpp create mode 100644 saga/ys_file.cpp create mode 100644 saga/yslib.h 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", + " ", R_CVAR_NONE, 3, 3); + + CVAR_RegisterFunc(CF_actor_del, "actor_del", + "", R_CVAR_NONE, 1, 1); + + CVAR_RegisterFunc(CF_actor_move, "actor_move", + " ", R_CVAR_NONE, 3, 3); + + CVAR_RegisterFunc(CF_actor_moverel, "actor_moverel", + " ", R_CVAR_NONE, 3, 3); + + CVAR_RegisterFunc(CF_actor_seto, "actor_seto", + " ", R_CVAR_NONE, 2, 2); + + CVAR_RegisterFunc(CF_actor_setact, "actor_setact", + " ", 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 -#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 +#include + +/* + 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/game_mod.h b/saga/game_mod.h new file mode 100644 index 0000000000..1292688b91 --- /dev/null +++ b/saga/game_mod.h @@ -0,0 +1,148 @@ +/* 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 - module header + + Notes: +*/ + +#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_IHNM_DEMO = 3, + 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 +}; + +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, + R_GAME_FONT_SMALL2, + R_GAME_FONT_MEDIUM2, + R_GAME_FONT_LARGE2, + R_GAME_FONT_LARGE3 +}; + +typedef struct R_GAME_DISPLAYINFO_tag { + + int logical_w; + int logical_h; + int scene_h; + +} R_GAME_DISPLAYINFO; + +typedef struct R_GAMESOUND_INFO_tag { + + int res_type; + long freq; + int sample_size; + int stereo; + +} R_GAME_SOUNDINFO; + +typedef struct R_GAMEFONT_DESC_tag { + + uint font_id; + ulong font_rn; + +} R_GAME_FONTDESC; + +typedef struct R_GAMESCENE_DESC_tag { + + ulong scene_lut_rn; + ulong first_scene; + +} R_GAME_SCENEDESC; + +typedef struct R_GAMERESOURCE_DESC_tag { + + ulong scene_lut_rn; + ulong script_lut_rn; + ulong command_panel_rn; + ulong dialogue_panel_rn; + +} R_GAME_RESOURCEDESC; + +int GAME_Register(void); + +int GAME_Init(void); + +int GAME_GetFileContext(R_RSCFILE_CONTEXT ** ctxt_p, uint r_type, int param); + +int GAME_GetFontInfo(R_GAME_FONTDESC **, int *); + +int GAME_GetResourceInfo(R_GAME_RESOURCEDESC *); + +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.h b/saga/gamedesc.h deleted file mode 100644 index 8a7cfbf3d3..0000000000 --- a/saga/gamedesc.h +++ /dev/null @@ -1,129 +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_GAMEDESC_H -#define SAGA_GAMEDESC_H - -#include "resfile.h" - -/* Public stuff */ - -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_IHNM_DEMO = 3, - 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 -}; - -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, - R_GAME_FONT_SMALL2, - R_GAME_FONT_MEDIUM2, - R_GAME_FONT_LARGE2, - R_GAME_FONT_LARGE3 -}; - -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; - long freq; - int sample_size; - int stereo; - -} R_GAME_SOUNDINFO; - -typedef struct R_GAMEFONT_DESC_tag { - unsigned int font_id; - unsigned long font_rn; - -} R_GAME_FONTDESC; - -typedef struct R_GAMESCENE_DESC_tag { - unsigned long scene_lut_rn; - unsigned long first_scene; - -} R_GAME_SCENEDESC; - -typedef struct R_GAME_RESOURCEINFO_tag { - unsigned long scene_lut_rn; - unsigned long script_lut_rn; - - unsigned long overlay_pal_rn; - - unsigned long command_panel_rn; - unsigned long command_buttons_rn; - - unsigned long dialogue_panel_rn; - unsigned long lportraits_rn; - - unsigned long actor_tbl_rn; - -} R_GAME_RESOURCEINFO; - - void setGameDirectory( const char *gamedir ); - int detectGame(); - bool openGame(); - -} // End of namespace Saga - -#endif - - - - - - 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 +#include +#include +#include + +#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 +#include +#include + +#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 +#include +#include + +#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 +#include + +#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 + +/* + * 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", "", 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 +#include +#include + +#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", "