diff options
author | Eugene Sandulenko | 2004-04-12 21:40:49 +0000 |
---|---|---|
committer | Eugene Sandulenko | 2004-04-12 21:40:49 +0000 |
commit | f3d340fb0ce72b9db59b8c701153bc82b595f75e (patch) | |
tree | bf250cf3a1e6aee35c7f40d766994b0c2c188e5c | |
parent | 0a0a0c7b0609d8774cef849e7511e7b21d12c5db (diff) | |
download | scummvm-rg350-f3d340fb0ce72b9db59b8c701153bc82b595f75e.tar.gz scummvm-rg350-f3d340fb0ce72b9db59b8c701153bc82b595f75e.tar.bz2 scummvm-rg350-f3d340fb0ce72b9db59b8c701153bc82b595f75e.zip |
WIP for SAGA engine.
o text formatting is not consistent with rules, just indent utility is too
dumb for that
o it does not use OSystem, i.e. it runs on direct SDL calls
o it may not even compile on your box
o if you enable it, expect zillions of warnings
o no sound
Now it runs ITE intro as reinherit did
svn-id: r13564
123 files changed, 29179 insertions, 1200 deletions
diff --git a/saga/actionmap.cpp b/saga/actionmap.cpp new file mode 100644 index 0000000000..20b3a7f250 --- /dev/null +++ b/saga/actionmap.cpp @@ -0,0 +1,252 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Action map module + + Notes: +*/ + +#include "reinherit.h" + +#include "yslib.h" + + +/* + * Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "cvar_mod.h" +#include "console_mod.h" +#include "gfx_mod.h" + +/* + * Begin module component +\*--------------------------------------------------------------------------*/ +#include "actionmap_mod.h" +#include "actionmap.h" + +namespace Saga { + +static R_ACTIONMAP_INFO ActmapModule; + +int ACTIONMAP_Register(void) +{ + + CVAR_RegisterFunc(CF_action_info, + "action_info", NULL, R_CVAR_NONE, 0, 0); + + return R_SUCCESS; +} + +int ACTIONMAP_Init(void) +{ + R_printf(R_STDOUT, "ACTIONMAP Module: Initializing...\n"); + + ActmapModule.init = 1; + return R_SUCCESS; +} + +int ACTIONMAP_Load(const uchar * exmap_res, size_t exmap_res_len) +/*--------------------------------------------------------------------------*\ + * Loads exit map data from specified exit map resource +\*--------------------------------------------------------------------------*/ +{ + + R_ACTIONMAP_ENTRY *exmap_entry; + R_POINT *exmap_pt_tbl; + + int exit_ct; + int i, pt; + + const uchar *read_p = exmap_res; + size_t read_len = exmap_res_len; + + assert(ActmapModule.init); + assert(exmap_res != NULL); + + (void)read_len; + + /* Load exits + * \*------------------------------------------------------------- */ + exit_ct = ys_read_s16_le(read_p, &read_p); + if (exit_ct < 0) { + return R_FAILURE; + } + + exmap_entry = (R_ACTIONMAP_ENTRY *)malloc(exit_ct * sizeof *exmap_entry); + if (exmap_entry == NULL) { + + R_printf(R_STDERR, "Memory allocation failure.\n"); + return R_MEM; + } + + for (i = 0; i < exit_ct; i++) { + + exmap_entry[i].unknown00 = ys_read_s16_le(read_p, &read_p); + exmap_entry[i].unknown02 = ys_read_s16_le(read_p, &read_p); + exmap_entry[i].exit_scene = ys_read_s16_le(read_p, &read_p); + exmap_entry[i].unknown06 = ys_read_s16_le(read_p, &read_p); + + exmap_entry[i].pt_count = ys_read_s16_le(read_p, &read_p); + if (exmap_entry[i].pt_count < 0) { + + free(exmap_entry); + return R_FAILURE; + } + + exmap_pt_tbl = + (R_POINT *)malloc(exmap_entry[i].pt_count * sizeof *exmap_pt_tbl); + if (exmap_pt_tbl == NULL) { + + R_printf(R_STDERR, "Memory allocation failure.\n"); + return R_MEM; + } + + for (pt = 0; pt < exmap_entry[i].pt_count; pt++) { + + exmap_pt_tbl[pt].x = ys_read_s16_le(read_p, &read_p); + exmap_pt_tbl[pt].y = ys_read_s16_le(read_p, &read_p); + } + + exmap_entry[i].pt_tbl = exmap_pt_tbl; + } + + ActmapModule.exits_loaded = 1; + ActmapModule.n_exits = exit_ct; + ActmapModule.exits_tbl = exmap_entry; + + ActmapModule.exmap_res = exmap_res; + ActmapModule.exmap_res_len = exmap_res_len; + + return R_SUCCESS; +} + +int ACTIONMAP_Free(void) +/*--------------------------------------------------------------------------*\ + * Frees the currently loaded exit map data +\*--------------------------------------------------------------------------*/ +{ + + R_ACTIONMAP_ENTRY *exmap_entry; + int i; + + if (!ActmapModule.exits_loaded) { + return R_SUCCESS; + } + + for (i = 0; i < ActmapModule.n_exits; i++) { + + exmap_entry = &ActmapModule.exits_tbl[i]; + + free(exmap_entry->pt_tbl); + } + + free(ActmapModule.exits_tbl); + + ActmapModule.exits_loaded = 0; + ActmapModule.exits_tbl = NULL; + ActmapModule.n_exits = 0; + + return R_SUCCESS; +} + +int ACTIONMAP_Shutdown(void) +/*--------------------------------------------------------------------------*\ +\*--------------------------------------------------------------------------*/ +{ + + return R_SUCCESS; +} + +int ACTIONMAP_Draw(R_SURFACE * ds, int color) +{ + + int i; + + assert(ActmapModule.init); + + if (!ActmapModule.exits_loaded) { + return R_FAILURE; + } + + for (i = 0; i < ActmapModule.n_exits; i++) { + + if (ActmapModule.exits_tbl[i].pt_count == 2) { + + GFX_DrawFrame(ds, + &ActmapModule.exits_tbl[i].pt_tbl[0], + &ActmapModule.exits_tbl[i].pt_tbl[1], color); + + } else if (ActmapModule.exits_tbl[i].pt_count > 2) { + + GFX_DrawPolyLine(ds, + ActmapModule.exits_tbl[i].pt_tbl, + ActmapModule.exits_tbl[i].pt_count, color); + + } + } + + return R_SUCCESS; +} + +void CF_action_info(int argc, char *argv[]) +{ + R_POINT *pt; + + int i; + int pt_i; + + YS_IGNORE_PARAM(argc); + YS_IGNORE_PARAM(argv); + + if (!ActmapModule.exits_loaded) { + return; + } + + CON_Print("%d exits loaded.\n", ActmapModule.n_exits); + + for (i = 0; i < ActmapModule.n_exits; i++) { + + CON_Print + ("Action %d: Exit to: %d; Pts: %d; Unk0: %d Unk2: %d Scr_N: %d", + i, ActmapModule.exits_tbl[i].exit_scene, + ActmapModule.exits_tbl[i].pt_count, + ActmapModule.exits_tbl[i].unknown00, + ActmapModule.exits_tbl[i].unknown02, + ActmapModule.exits_tbl[i].unknown06); + + for (pt_i = 0; pt_i < ActmapModule.exits_tbl[i].pt_count; + pt_i++) { + + pt = &ActmapModule.exits_tbl[i].pt_tbl[pt_i]; + + CON_Print(" pt: %d (%d, %d)", pt_i, pt->x, pt->y); + } + } + + return; +} + +} // End of namespace Saga diff --git a/saga/actionmap.h b/saga/actionmap.h new file mode 100644 index 0000000000..5760bf2fb8 --- /dev/null +++ b/saga/actionmap.h @@ -0,0 +1,67 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Action map module - private header + + Notes: +*/ + +#ifndef SAGA_ACTIONMAP_H_ +#define SAGA_ACTIONMAP_H_ + +namespace Saga { + +typedef struct R_ACTIONMAP_ENTRY_tag { + + int unknown00; + int unknown02; + int exit_scene; + int unknown06; + + int pt_count; + R_POINT *pt_tbl; + +} R_ACTIONMAP_ENTRY; + +typedef struct R_ACTIONMAP_INFO_tag { + + int init; + + int exits_loaded; + int n_exits; + R_ACTIONMAP_ENTRY *exits_tbl; + + const uchar *exmap_res; + size_t exmap_res_len; + +} R_ACTIONMAP_INFO; + +void CF_action_info(int argc, char *argv[]); + +} // End of namespace Saga + +#endif /* R_ACTIONMAP_H_ */ +/* end "r_actionmap.h" */ diff --git a/saga/actionmap_mod.h b/saga/actionmap_mod.h new file mode 100644 index 0000000000..f424ef1304 --- /dev/null +++ b/saga/actionmap_mod.h @@ -0,0 +1,49 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Action map module - public module header + + Notes: +*/ + +#ifndef SAGA_ACTIONMAP_MOD_H_ +#define SAGA_ACTIONMAP_MOD_H_ + +namespace Saga { + +int ACTIONMAP_Register(void); +int ACTIONMAP_Init(void); + +int ACTIONMAP_Load(const uchar * exmap_res, size_t exmap_res_len); +int ACTIONMAP_Draw(R_SURFACE * ds, int color); + +int ACTIONMAP_Free(void); +int ACTIONMAP_Shutdown(void); + +} // End of namespace Saga + +#endif /* R_ACTIONMAP_MOD_H_ */ +/* end "r_actionmap_mod.h" */ diff --git a/saga/actor.cpp b/saga/actor.cpp new file mode 100644 index 0000000000..1400dcd1a1 --- /dev/null +++ b/saga/actor.cpp @@ -0,0 +1,1456 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Actor management module + + Notes: + + Hardcoded actor table present in r_actordata.c +*/ + +#include "reinherit.h" + +#include "yslib.h" + +/* + * Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "game_mod.h" +#include "cvar_mod.h" +#include "console_mod.h" +#include "rscfile_mod.h" +#include "script_mod.h" +#include "sndres_mod.h" +#include "sprite_mod.h" +#include "font_mod.h" +#include "text_mod.h" + +/* + * Begin module component +\*--------------------------------------------------------------------------*/ +#include "actor_mod.h" +#include "actor.h" +#include "actordata.h" + +namespace Saga { + +static R_ACTOR_MODULE ActorModule; + +R_ACTIONTIMES ActionTDeltas[] = { + + {ACTION_IDLE, 80}, + {ACTION_WALK, 80}, + {ACTION_SPEAK, 200} +}; + +int ACTOR_Register(void) +{ + + CVAR_RegisterFunc(CF_actor_add, "actor_add", + "<Actor id> <lx> <ly>", R_CVAR_NONE, 3, 3); + + CVAR_RegisterFunc(CF_actor_del, "actor_del", + "<Actor id>", R_CVAR_NONE, 1, 1); + + CVAR_RegisterFunc(CF_actor_move, "actor_move", + "<Actor id> <lx> <ly>", R_CVAR_NONE, 3, 3); + + CVAR_RegisterFunc(CF_actor_moverel, "actor_moverel", + "<Actor id> <lx> <ly>", R_CVAR_NONE, 3, 3); + + CVAR_RegisterFunc(CF_actor_seto, "actor_seto", + "<Actor id> <Orientation>", R_CVAR_NONE, 2, 2); + + CVAR_RegisterFunc(CF_actor_setact, "actor_setact", + "<Actor id> <Action #>", R_CVAR_NONE, 2, 2); + + return R_SUCCESS; +} + +int ACTOR_Init(void) +{ + int result; + int i; + + if (ActorModule.init) { + + ActorModule.err_str = "Actor module already initialized."; + + return R_FAILURE; + } + + /* Get actor resource file context + * \*------------------------------------------------------------- */ + result = GAME_GetFileContext(&ActorModule.actor_ctxt, + R_GAME_RESOURCEFILE, 0); + if (result != R_SUCCESS) { + + ActorModule.err_str = + "Couldn't load actor module resource context."; + + return R_FAILURE; + } + + /* Create actor lookup table + * \*------------------------------------------------------------- */ + ActorModule.tbl = (YS_DL_NODE **)malloc(R_ACTORCOUNT * sizeof *ActorModule.tbl); + if (ActorModule.tbl == NULL) { + + ActorModule.err_str = R_MEMFAIL_MSG; + + return R_MEM; + } + + for (i = 0; i < R_ACTORCOUNT; i++) { + ActorModule.tbl[i] = NULL; + } + + /* Create actor alias table + * \*------------------------------------------------------------- */ + ActorModule.alias_tbl = (int *)malloc(R_ACTORCOUNT * + sizeof *ActorModule.alias_tbl); + if (ActorModule.alias_tbl == NULL) { + free(ActorModule.tbl); + + ActorModule.err_str = R_MEMFAIL_MSG; + + return R_MEM; + } + + /* Initialize alias table so each index contains itself */ + for (i = 0; i < R_ACTORCOUNT; i++) { + + ActorModule.alias_tbl[i] = i; + } + + /* Create actor list + * \*------------------------------------------------------------- */ + ActorModule.list = ys_dll_create(); + + ActorModule.init = 1; + + return R_SUCCESS; +} + +int ACTOR_Shutdown(void) +{ + + if (!ActorModule.init) { + return R_FAILURE; + } + + if (ActorModule.tbl) { + free(ActorModule.tbl); + } + + return R_SUCCESS; + +} + +int ACTOR_Direct(int msec) +{ + + YS_DL_NODE *walk_p; + R_ACTOR *actor; + + YS_DL_NODE *a_inode; + R_ACTORINTENT *a_intent; + + int o_idx; + int action_tdelta; + + /* Walk down the actor list and direct each actor + * \*------------------------------------------------------------- */ + for (walk_p = ys_dll_head(ActorModule.list); + walk_p != NULL; walk_p = ys_dll_next(walk_p)) { + + actor = (R_ACTOR *)ys_dll_get_data(walk_p); + + /* Process the actor intent list + * \*--------------------------------------------------------- */ + a_inode = ys_dll_head(actor->a_intentlist); + + if (a_inode != NULL) { + + a_intent = (R_ACTORINTENT *)ys_dll_get_data(a_inode); + + switch (a_intent->a_itype) { + + case INTENT_NONE: + /* Actor doesn't really feel like doing anything at all */ + break; + + case INTENT_PATH: + /* Actor intends to go somewhere. Well good for him */ + { + R_WALKINTENT *a_walkint; + + a_walkint = (R_WALKINTENT *)a_intent->a_data; + + HandleWalkIntent(actor, + a_walkint, + &a_intent->a_idone, msec); + } + break; + + case INTENT_SPEAK: + /* Actor wants to blab */ + { + R_SPEAKINTENT *a_speakint; + + a_speakint = (R_SPEAKINTENT *)a_intent->a_data; + + HandleSpeakIntent(actor, + a_speakint, + &a_intent->a_idone, msec); + } + break; + + default: + break; + } /* end switch() */ + + /* If this actor intent was flagged as completed, remove it. */ + if (a_intent->a_idone) { + + free(a_intent->a_data); + ys_dll_delete(a_inode); + + actor->action = actor->def_action; + actor->action_flags = actor->def_action_flags; + actor->action_frame = 0; + actor->action_time = 0; + } + + } else { + /* Actor has no intent, idle? */ + } + + /* Process actor actions + * \*--------------------------------------------------------- */ + actor->action_time += msec; + + if (actor->action >= ACTION_COUNT) { + action_tdelta = ACTOR_ACTIONTIME; + } else { + action_tdelta = ActionTDeltas[actor->action].time; + } + + if (actor->action_time >= action_tdelta) { + + actor->action_time -= action_tdelta; + actor->action_frame++; + + o_idx = ActorOrientationLUT[actor->orient]; + + if (actor->act_tbl[actor->action].dir[o_idx]. + frame_count <= actor->action_frame) { + + if (actor->action_flags & ACTION_LOOP) { + + actor->action_frame = 0; + } else { + actor->action_frame--; + } + } + } + + } /* end for () */ + + return R_SUCCESS; +} + +int ACTOR_DrawList(void) +{ + + YS_DL_NODE *walk_p; + R_ACTOR *actor; + + YS_DL_NODE *a_inode; + R_ACTORINTENT *a_intent; + R_SPEAKINTENT *a_speakint; + + YS_DL_NODE *a_dnode; + R_ACTORDIALOGUE *a_dialogue; + + int o_idx; /* Orientation index */ + int sprite_num; + + int diag_x, diag_y; /* dialog coordinates */ + + R_SURFACE *back_buf; + + back_buf = SYSGFX_GetBackBuffer(); + + for (walk_p = ys_dll_head(ActorModule.list); + walk_p != NULL; walk_p = ys_dll_next(walk_p)) { + + actor = (R_ACTOR *)ys_dll_get_data(walk_p); + + o_idx = ActorOrientationLUT[actor->orient]; + + sprite_num = + actor->act_tbl[actor->action].dir[o_idx].frame_index; + sprite_num += actor->action_frame; + + SPRITE_DrawOccluded(back_buf, + actor->sl_p, sprite_num, actor->s_pt.x, actor->s_pt.y); + + /* If actor's current intent is to speak, oblige him by + * displaying his dialogue + \*---------------------------------------------------------*/ + a_inode = ys_dll_head(actor->a_intentlist); + + if (a_inode != NULL) { + + a_intent = (R_ACTORINTENT *)ys_dll_get_data(a_inode); + + if (a_intent->a_itype == INTENT_SPEAK) { + + a_speakint = (R_SPEAKINTENT *)a_intent->a_data; + + a_dnode = ys_dll_head(a_speakint->si_diaglist); + + if (a_dnode != NULL) { + + a_dialogue = (R_ACTORDIALOGUE *)ys_dll_get_data(a_dnode); + + diag_x = actor->s_pt.x; + diag_y = actor->s_pt.y; + + diag_y -= ACTOR_DIALOGUE_HEIGHT; + + TEXT_Draw(MEDIUM_FONT_ID, + back_buf, + a_dialogue->d_string, + diag_x, diag_y, + actor->a_dcolor, 0, + FONT_OUTLINE | FONT_CENTERED); + } + } + } + } + + return R_SUCCESS; +} + +int ACTOR_SkipDialogue(void) +/*--------------------------------------------------------------------------*\ + * Called if the user wishes to skip a line of dialogue (spacebar in the + * original game). Will find all actors currently talking and remove one + * dialogue entry if there is a current speak intent present. +\*--------------------------------------------------------------------------*/ +{ + + YS_DL_NODE *walk_p; + R_ACTOR *actor; + + YS_DL_NODE *a_inode; + R_ACTORINTENT *a_intent; + R_SPEAKINTENT *a_speakint; + + YS_DL_NODE *a_dnode; + R_ACTORDIALOGUE *a_dialogue; + + if (!ActorModule.init) { + return R_FAILURE; + } + + for (walk_p = ys_dll_head(ActorModule.list); + walk_p != NULL; walk_p = ys_dll_next(walk_p)) { + + actor = (R_ACTOR *)ys_dll_get_data(walk_p); + + /* Check the actor's current intent for a speak intent + * \*--------------------------------------------------------- */ + a_inode = ys_dll_head(actor->a_intentlist); + + if (a_inode != NULL) { + + a_intent = (R_ACTORINTENT *)ys_dll_get_data(a_inode); + + if (a_intent->a_itype == INTENT_SPEAK) { + + /* Okay, found a speak intent. Remove one dialogue entry + * from it, releasing any semaphore */ + + a_speakint = (R_SPEAKINTENT *)a_intent->a_data; + + a_dnode = ys_dll_head(a_speakint->si_diaglist); + + if (a_dnode != NULL) { + + a_dialogue = (R_ACTORDIALOGUE *)ys_dll_get_data(a_dnode); + + if (a_dialogue->d_sem != NULL) { + + STHREAD_ReleaseSem(a_dialogue-> + d_sem); + } + + ys_dll_delete(a_dnode); + + /* And stop any currently playing voices */ + SYSSOUND_StopVoice(); + } + } + } + } + + return R_SUCCESS; +} + +int ACTOR_Create(int actor_id, int x, int y) +{ + R_ACTOR actor = { 0 }; + + if (actor_id == 1) { + actor_id = 0; + } else { + actor_id = actor_id & ~0x2000; + } + + actor.id = actor_id; + actor.a_pt.x = x; + actor.a_pt.y = y; + + if (AddActor(&actor) != R_SUCCESS) { + + return R_FAILURE; + } + + return R_SUCCESS; +} + +int AddActor(R_ACTOR * actor) +{ + + YS_DL_NODE *new_node; + + int last_frame; + int i; + + if (!ActorModule.init) { + return R_FAILURE; + } + + if ((actor->id < 0) || (actor->id >= R_ACTORCOUNT)) { + return R_FAILURE; + } + + if (ActorModule.tbl[actor->id] != NULL) { + return R_FAILURE; + } + + ACTOR_AtoS(&actor->s_pt, &actor->a_pt); + + i = actor->id; + + actor->sl_rn = ActorTable[i].spritelist_rn; + actor->si_rn = ActorTable[i].spriteindex_rn; + + LoadActorSpriteIndex(actor, actor->si_rn, &last_frame); + + if (SPRITE_LoadList(actor->sl_rn, &actor->sl_p) != R_SUCCESS) { + + return R_FAILURE; + } + + if (last_frame >= SPRITE_GetListLen(actor->sl_p)) { + + R_printf(R_STDOUT, + "Appending to sprite list %d.\n", actor->sl_rn); + + if (SPRITE_AppendList(actor->sl_rn + 1, + actor->sl_p) != R_SUCCESS) { + return R_FAILURE; + } + } + + actor->a_dcolor = ActorTable[i].color; + + actor->orient = ACTOR_DEFAULT_ORIENT; + + actor->a_intentlist = ys_dll_create(); + + actor->def_action = 0; + actor->def_action_flags = 0; + + actor->action = 0; + actor->action_flags = 0; + actor->action_time = 0; + actor->action_frame = 0; + + new_node = ys_dll_insert(ActorModule.list, + actor, sizeof *actor, Z_Compare); + + if (new_node == NULL) { + return R_FAILURE; + } + + actor = (R_ACTOR *)ys_dll_get_data(new_node); + actor->node = new_node; + + ActorModule.tbl[i] = new_node; + + ActorModule.count++; + + return R_SUCCESS; +} + +int ACTOR_GetActorIndex(uint actor_id) +{ + uint actor_idx; + + if (actor_id == 1) { + actor_idx = 0; + } else { + actor_idx = actor_id & ~0x2000; + } + + if (ActorModule.tbl[actor_idx] == NULL) { + return -1; + } + + return actor_idx; +} + +int ACTOR_ActorExists(uint actor_id) +{ + uint actor_idx; + + if (actor_id == 1) { + actor_idx = 0; + } else { + actor_idx = actor_id & ~0x2000; + } + + if (ActorModule.tbl[actor_idx] == NULL) { + return 0; + } + + return 1; +} + +int ACTOR_Speak(int index, char *d_string, uint d_voice_rn, R_SEMAPHORE * sem) +{ + + YS_DL_NODE *node; + R_ACTOR *actor; + + YS_DL_NODE *a_inode; + R_ACTORINTENT *a_intent_p = NULL; + R_SPEAKINTENT *a_speakint; + + R_ACTORINTENT a_intent; + + int use_existing_ai = 0; + + R_ACTORDIALOGUE a_dialogue = { 0 }; + + a_dialogue.d_string = d_string; + a_dialogue.d_voice_rn = d_voice_rn; + a_dialogue.d_time = ACTOR_GetSpeechTime(d_string, d_voice_rn); + a_dialogue.d_sem_held = 1; + a_dialogue.d_sem = sem; + + node = ActorModule.tbl[index]; + if (node == NULL) { + return R_FAILURE; + } + + actor = (R_ACTOR *)ys_dll_get_data(node); + + /* If actor's last registered intent is to speak, we can queue the + * requested dialogue on that intent context; so examine the last + * intent */ + + a_inode = ys_dll_tail(actor->a_intentlist); + + if (a_inode != NULL) { + + a_intent_p = (R_ACTORINTENT *)ys_dll_get_data(a_inode); + + if (a_intent_p->a_itype == INTENT_SPEAK) { + + use_existing_ai = 1; + } + } + + if (use_existing_ai) { + + /* Store the current dialogue off the existing actor intent */ + a_speakint = (R_SPEAKINTENT *)a_intent_p->a_data; + + ys_dll_add_tail(a_speakint->si_diaglist, + &a_dialogue, sizeof a_dialogue); + + } else { + + /* Create a new actor intent */ + + a_intent.a_itype = INTENT_SPEAK; + a_intent.a_idone = 0; + a_intent.a_iflags = 0; + + a_speakint = (R_SPEAKINTENT *)malloc(sizeof *a_speakint); + if (a_speakint == NULL) { + + return R_FAILURE; + } + + a_speakint->si_init = 0; + a_speakint->si_diaglist = ys_dll_create(); + a_speakint->si_last_action = actor->action; + + a_intent.a_data = a_speakint; + + ys_dll_add_tail(a_speakint->si_diaglist, + &a_dialogue, sizeof a_dialogue); + + ys_dll_add_tail(actor->a_intentlist, + &a_intent, sizeof a_intent); + } + + if (sem != NULL) { + STHREAD_HoldSem(sem); + } + + return R_SUCCESS; +} + +int +HandleSpeakIntent(R_ACTOR * actor, + R_SPEAKINTENT * a_speakint, int *complete_p, int msec) +{ + + YS_DL_NODE *a_dnode; + YS_DL_NODE *a_dnext; + + R_ACTORDIALOGUE *a_dialogue; + R_ACTORDIALOGUE *a_dialogue2; + + long carry_time; + int intent_complete = 0; + + if (!a_speakint->si_init) { + + /* Initialize speak intent by setting up action */ + + actor->action = ACTION_SPEAK; + actor->action_frame = 0; + actor->action_time = 0; + actor->action_flags = ACTION_LOOP; + + a_speakint->si_init = 1; + } + + /* Process actor dialogue list + * \*--------------------------------------------------------- */ + a_dnode = ys_dll_head(a_speakint->si_diaglist); + + if (a_dnode != NULL) { + + a_dialogue = (R_ACTORDIALOGUE *)ys_dll_get_data(a_dnode); + + if (!a_dialogue->d_playing) { + /* Dialogue voice hasn't played yet - play it now */ + + SND_PlayVoice(a_dialogue->d_voice_rn); + a_dialogue->d_playing = 1; + } + + a_dialogue->d_time -= msec; + + if (a_dialogue->d_time <= 0) { + + /* Dialogue time has expired; carry negative time to next + * dialogue entry if present, release any semaphores and + * delete the expired entry */ + + /*actor->action = ACTION_IDLE; */ + + if (a_dialogue->d_sem != NULL) { + STHREAD_ReleaseSem(a_dialogue->d_sem); + } + + carry_time = a_dialogue->d_time; + + a_dnext = ys_dll_next(a_dnode); + if (a_dnext != NULL) { + + a_dialogue2 = (R_ACTORDIALOGUE *)ys_dll_get_data(a_dnode); + a_dialogue2->d_time -= carry_time; + } + + ys_dll_delete(a_dnode); + + /* Check if there are any dialogue nodes left. If not, + * flag this speech intent as complete */ + + a_dnode = ys_dll_head(a_speakint->si_diaglist); + if (a_dnode == NULL) { + intent_complete = 1; + } + + } + } else { + intent_complete = 1; + } + + if (intent_complete) { + + *complete_p = 1; + } + + return R_SUCCESS; +} + +int ACTOR_GetSpeechTime(const char *d_string, uint d_voice_rn) +{ + int voice_len; + + voice_len = SND_GetVoiceLength(d_voice_rn); + + if (voice_len < 0) { + voice_len = strlen(d_string) * ACTOR_DIALOGUE_LETTERTIME; + } + + return voice_len; +} + +int ACTOR_SetOrientation(int index, int orient) +{ + + R_ACTOR *actor; + + if (!ActorModule.init) { + return R_FAILURE; + } + + if ((orient < 0) || (orient > 7)) { + return R_FAILURE; + } + + actor = LookupActor(index); + if (actor == NULL) { + + return R_FAILURE; + } + + actor->orient = orient; + + return R_SUCCESS; +} + +int ACTOR_SetAction(int index, int action_n, uint action_flags) +{ + R_ACTOR *actor; + + if (!ActorModule.init) { + + return R_FAILURE; + } + + actor = LookupActor(index); + if (actor == NULL) { + + return R_FAILURE; + } + + if ((action_n < 0) || (action_n >= actor->action_ct)) { + + return R_FAILURE; + } + + actor->action = action_n; + actor->action_flags = action_flags; + actor->action_frame = 0; + actor->action_time = 0; + + return R_SUCCESS; +} + +int ACTOR_SetDefaultAction(int index, int action_n, uint action_flags) +{ + R_ACTOR *actor; + + if (!ActorModule.init) { + + return R_FAILURE; + } + + actor = LookupActor(index); + if (actor == NULL) { + + return R_FAILURE; + } + + if ((action_n < 0) || (action_n >= actor->action_ct)) { + + return R_FAILURE; + } + + actor->def_action = action_n; + actor->def_action_flags = action_flags; + + return R_SUCCESS; +} + +R_ACTOR *LookupActor(int index) +{ + YS_DL_NODE *node; + R_ACTOR *actor; + + if (!ActorModule.init) { + return NULL; + } + + if ((index < 0) || (index >= R_ACTORCOUNT)) { + return NULL; + } + + if (ActorModule.tbl[index] == NULL) { + return NULL; + } + + node = ActorModule.tbl[index]; + actor = (R_ACTOR *)ys_dll_get_data(node); + + return actor; +} + +int LoadActorSpriteIndex(R_ACTOR * actor, int si_rn, int *last_frame_p) +{ + + uchar *res_p; + size_t res_len; + + const uchar *read_p; + + int s_action_ct; + R_ACTORACTION *action_p; + int last_frame; + + int i, orient; + int result; + + result = RSC_LoadResource(ActorModule.actor_ctxt, + si_rn, &res_p, &res_len); + if (result != R_SUCCESS) { + + R_printf(R_STDERR, + "Couldn't load sprite action index resource.\n"); + + return R_FAILURE; + } + + read_p = res_p; + + s_action_ct = res_len / 16; + + R_printf(R_STDOUT, + "Sprite resource contains %d sprite actions.\n", s_action_ct); + + action_p = (R_ACTORACTION *)malloc(sizeof(R_ACTORACTION) * s_action_ct); + + if (action_p == NULL) { + + R_printf(R_STDERR, + "Couldn't allocate memory for sprite actions.\n"); + + RSC_FreeResource(res_p); + + return R_MEM; + } + + last_frame = 0; + + for (i = 0; i < s_action_ct; i++) { + + for (orient = 0; orient < 4; orient++) { + + /* Load all four orientations */ + action_p[i].dir[orient].frame_index = + ys_read_u16_le(read_p, &read_p); + + action_p[i].dir[orient].frame_count = + ys_read_u16_le(read_p, &read_p); + + if (action_p[i].dir[orient].frame_index > last_frame) { + last_frame = + action_p[i].dir[orient].frame_index; + } + } + } + + actor->act_tbl = action_p; + actor->action_ct = s_action_ct; + + RSC_FreeResource(res_p); + + if (last_frame_p != NULL) { + *last_frame_p = last_frame; + } + + return R_SUCCESS; +} + +int DeleteActor(int index) +{ + + YS_DL_NODE *node; + R_ACTOR *actor; + + if (!ActorModule.init) { + return R_FAILURE; + } + + if ((index < 0) || (index >= R_ACTORCOUNT)) { + return R_FAILURE; + } + + if (ActorModule.tbl[index] == NULL) { + return R_FAILURE; + } + + node = ActorModule.tbl[index]; + actor = (R_ACTOR *)ys_dll_get_data(node); + + SPRITE_Free(actor->sl_p); + + ys_dll_delete(node); + + ActorModule.tbl[index] = NULL; + + return R_SUCCESS; +} + +int ACTOR_WalkTo(int id, R_POINT * walk_pt, uint flags, R_SEMAPHORE * sem) +/*--------------------------------------------------------------------------*\ +\*--------------------------------------------------------------------------*/ +{ + R_ACTORINTENT actor_intent = { 0 }; + + R_WALKINTENT *walk_intent; + R_WALKINTENT zero_intent = { 0 }; + + YS_DL_NODE *node; + R_ACTOR *actor; + + assert(ActorModule.init); + assert(walk_pt != NULL); + + if ((id < 0) || (id >= R_ACTORCOUNT)) { + return R_FAILURE; + } + + if (ActorModule.tbl[id] == NULL) { + return R_FAILURE; + } + + node = ActorModule.tbl[id]; + actor = (R_ACTOR *)ys_dll_get_data(node); + + walk_intent = (R_WALKINTENT *)malloc(sizeof *walk_intent); + if (walk_intent == NULL) { + + return R_MEM; + } + + *walk_intent = zero_intent; + + walk_intent->wi_flags = flags; + walk_intent->sem_held = 1; + walk_intent->sem = sem; + + /* HandleWalkIntent() will create path on initialization */ + walk_intent->wi_init = 0; + walk_intent->dst_pt = *walk_pt; + + actor_intent.a_itype = INTENT_PATH; + actor_intent.a_iflags = 0; + actor_intent.a_data = walk_intent; + + ys_dll_add_tail(actor->a_intentlist, + &actor_intent, sizeof actor_intent); + + if (sem != NULL) { + STHREAD_HoldSem(sem); + } + + return R_SUCCESS; +} + +int +ACTOR_SetPathNode(R_WALKINTENT * walk_int, + R_POINT * src_pt, R_POINT * dst_pt, R_SEMAPHORE * sem) +{ + + R_WALKNODE new_node; + + walk_int->wi_active = 1; + walk_int->org = *src_pt; + + assert((walk_int != NULL) && (src_pt != NULL) && (dst_pt != NULL)); + assert(walk_int->nodelist != NULL); + + new_node.node_pt = *dst_pt; + new_node.calc_flag = 0; + + ys_dll_add_tail(walk_int->nodelist, &new_node, sizeof new_node); + + return R_SUCCESS; +} + +int +HandleWalkIntent(R_ACTOR * actor, + R_WALKINTENT * a_walkint, int *complete_p, int delta_time) +{ + + YS_DL_NODE *walk_p; + YS_DL_NODE *next_p; + + R_WALKNODE *node_p; + int dx; + int dy; + + double path_a; + double path_b; + double path_slope; + + double path_x; + double path_y; + int path_time; + + double new_a_x; + double new_a_y; + + int actor_x; + int actor_y; + + char buf[100]; + + /* Initialize walk intent + * \*------------------------------------------------------------- */ + if (!a_walkint->wi_init) { + + a_walkint->nodelist = ys_dll_create(); + + ACTOR_SetPathNode(a_walkint, + &actor->a_pt, &a_walkint->dst_pt, a_walkint->sem); + + ACTOR_SetDefaultAction(actor->id, ACTION_IDLE, ACTION_NONE); + + a_walkint->wi_init = 1; + } + + assert(a_walkint->wi_active); + + walk_p = ys_dll_head(a_walkint->nodelist); + next_p = ys_dll_next(walk_p); + + node_p = (R_WALKNODE *)ys_dll_get_data(walk_p); + + if (node_p->calc_flag == 0) { + +# if 0 + R_printf(R_STDOUT, + "Calculating new path vector to point (%d, %d)\n", + node_p->node_pt.x, node_p->node_pt.y); +# endif + + dx = a_walkint->org.x - node_p->node_pt.x; + dy = a_walkint->org.y - node_p->node_pt.y; + + if (dx == 0) { + + R_printf(R_STDOUT, + "Vertical paths not implemented.\n"); + + ys_dll_delete(walk_p); + a_walkint->wi_active = 0; + + /* Release path semaphore... */ + if ((a_walkint->sem != NULL) && a_walkint->sem_held) { + + STHREAD_ReleaseSem(a_walkint->sem); + } + + *complete_p = 1; + + return R_FAILURE; + } + + a_walkint->slope = (float)dy / dx; + + if (dx > 0) { + + a_walkint->x_dir = -1; + + if (!(a_walkint->wi_flags & WALK_NOREORIENT)) { + + if (a_walkint->slope > 1.0) { + actor->orient = ORIENT_N; + } else if (a_walkint->slope < -1.0) { + actor->orient = ORIENT_S; + } else { + actor->orient = ORIENT_W; + } + } + } else { + + a_walkint->x_dir = 1; + + if (!(a_walkint->wi_flags & WALK_NOREORIENT)) { + + if (a_walkint->slope > 1.0) { + actor->orient = ORIENT_S; + } else if (a_walkint->slope < -1.0) { + actor->orient = ORIENT_N; + } else { + actor->orient = ORIENT_E; + } + } + } + + sprintf(buf, "%f", a_walkint->slope); + +# if 0 + R_printf(R_STDOUT, "Path slope: %s.\n", buf); +# endif + + actor->action = ACTION_WALK; + actor->action_flags = ACTION_LOOP; + a_walkint->time = 0; + node_p->calc_flag = 1; + } + + a_walkint->time += delta_time; + path_time = a_walkint->time; + + path_a = ACTOR_BASE_SPEED * path_time; + path_b = ACTOR_BASE_SPEED * path_time * ACTOR_BASE_ZMOD; + path_slope = a_walkint->slope * a_walkint->x_dir; + + path_x = (path_a * path_b) / + sqrt((path_a * path_a) * + (path_slope * path_slope) + (path_b * path_b)); + + path_y = path_slope * path_x; + path_x = path_x * a_walkint->x_dir; + + new_a_x = path_x + a_walkint->org.x; + new_a_y = path_y + a_walkint->org.y; + + if (a_walkint->x_dir == 1) { + + if (new_a_x >= node_p->node_pt.x) { + +# if 0 + R_printf(R_STDOUT, "Path complete.\n"); +# endif + + ys_dll_delete(walk_p); + + a_walkint->wi_active = 0; + + /* Release path semaphore... */ + if (a_walkint->sem != NULL) { + STHREAD_ReleaseSem(a_walkint->sem); + } + + actor->action_frame = 0; + actor->action = ACTION_IDLE; + + *complete_p = 1; + + return R_FAILURE; + } + } else { + + if (new_a_x <= node_p->node_pt.x) { + +# if 0 + R_printf(R_STDOUT, "Path complete.\n"); +# endif + + ys_dll_delete(walk_p); + + a_walkint->wi_active = 0; + + /* Release path semaphore... */ + if (a_walkint->sem != NULL) { + STHREAD_ReleaseSem(a_walkint->sem); + } + + actor->action_frame = 0; + actor->action = ACTION_IDLE; + + *complete_p = 1; + + return R_FAILURE; + + } + } + + actor_x = (int)new_a_x; + actor_y = (int)new_a_y; + + actor->a_pt.x = (int)new_a_x; + actor->a_pt.y = (int)new_a_y; + + actor->s_pt.x = actor->a_pt.x >> 2; + actor->s_pt.y = actor->a_pt.y >> 2; + + if (path_slope < 0) { + ys_dll_reorder_up(ActorModule.list, actor->node, Z_Compare); + + } else { + ys_dll_reorder_down(ActorModule.list, actor->node, Z_Compare); + } + + return R_SUCCESS; +} + +int ACTOR_Move(int index, R_POINT * move_pt) +{ + + YS_DL_NODE *node; + R_ACTOR *actor; + + int move_up = 0; + + node = ActorModule.tbl[index]; + if (node == NULL) { + return R_FAILURE; + } + + actor = (R_ACTOR *)ys_dll_get_data(node); + + if (move_pt->y < actor->a_pt.y) { + move_up = 1; + } + + actor->a_pt.x = move_pt->x; + actor->a_pt.y = move_pt->y; + + ACTOR_AtoS(&actor->s_pt, &actor->a_pt); + + if (move_up) { + ys_dll_reorder_up(ActorModule.list, actor->node, Z_Compare); + } else { + + ys_dll_reorder_down(ActorModule.list, actor->node, Z_Compare); + } + + return R_SUCCESS; +} + +int ACTOR_MoveRelative(int index, R_POINT * move_pt) +{ + + YS_DL_NODE *node; + R_ACTOR *actor; + + node = ActorModule.tbl[index]; + if (node == NULL) { + return R_FAILURE; + } + + actor = (R_ACTOR *)ys_dll_get_data(node); + + actor->a_pt.x += move_pt->x; + actor->a_pt.y += move_pt->y; + + ACTOR_AtoS(&actor->s_pt, &actor->a_pt); + + if (actor->a_pt.y < 0) { + + ys_dll_reorder_up(ActorModule.list, actor->node, Z_Compare); + } else { + + ys_dll_reorder_down(ActorModule.list, actor->node, Z_Compare); + + } + + return R_SUCCESS; +} + +int Z_Compare(const void *elem1, const void *elem2) +{ + + R_ACTOR *actor1 = (R_ACTOR *) elem1; + R_ACTOR *actor2 = (R_ACTOR *) elem2; + + if (actor1->a_pt.y == actor2->a_pt.y) { + return 0; + } else if (actor1->a_pt.y < actor2->a_pt.y) { + return -1; + } else { + return 1; + } +} + +int ACTOR_AtoS(R_POINT * screen, const R_POINT * actor) +{ + + screen->x = (actor->x / R_ACTOR_LMULT); + screen->y = (actor->y / R_ACTOR_LMULT); + + return R_SUCCESS; +} + +int ACTOR_StoA(R_POINT * actor, const R_POINT * screen) +{ + + actor->x = (screen->x * R_ACTOR_LMULT); + actor->y = (screen->y * R_ACTOR_LMULT); + + return R_SUCCESS; +} + +static void CF_actor_add(int argc, char *argv[]) +{ + R_ACTOR actor = { 0 }; + + if (argc < 3) + return; + + actor.id = (uint) atoi(argv[0]); + + actor.a_pt.x = atoi(argv[1]); + actor.a_pt.y = atoi(argv[2]); + + AddActor(&actor); + + return; +} + +static void CF_actor_del(int argc, char *argv[]) +{ + int id; + + if (argc < 0) + return; + + id = atoi(argv[0]); + + DeleteActor(id); + + return; +} + +static void CF_actor_move(int argc, char *argv[]) +{ + int id; + R_POINT move_pt; + + if (argc < 2) + return; + + id = atoi(argv[0]); + + move_pt.x = atoi(argv[1]); + move_pt.y = atoi(argv[2]); + + ACTOR_Move(id, &move_pt); + + return; +} + +static void CF_actor_moverel(int argc, char *argv[]) +{ + int id; + R_POINT move_pt; + + if (argc < 3) + return; + + id = atoi(argv[0]); + + move_pt.x = atoi(argv[1]); + move_pt.y = atoi(argv[2]); + + ACTOR_MoveRelative(id, &move_pt); + + return; +} + +static void CF_actor_seto(int argc, char *argv[]) +{ + + int id; + int orient; + + if (argc < 2) + return; + + id = atoi(argv[0]); + orient = atoi(argv[1]); + + ACTOR_SetOrientation(id, orient); + + return; +} + +static void CF_actor_setact(int argc, char *argv[]) +{ + int index = 0; + int action_n = 0; + + R_ACTOR *actor; + + if (argc < 2) + return; + + index = atoi(argv[0]); + action_n = atoi(argv[1]); + + actor = LookupActor(index); + if (actor == NULL) { + CON_Print("Invalid actor index."); + + return; + } + + if ((action_n < 0) || (action_n >= actor->action_ct)) { + CON_Print("Invalid action number."); + + return; + } + + CON_Print("Action frame counts: %d %d %d %d.", + actor->act_tbl[action_n].dir[0].frame_count, + actor->act_tbl[action_n].dir[1].frame_count, + actor->act_tbl[action_n].dir[2].frame_count, + actor->act_tbl[action_n].dir[3].frame_count); + + ACTOR_SetAction(index, action_n, ACTION_LOOP); + + return; +} + +} // End of namespace Saga diff --git a/saga/actor.h b/saga/actor.h new file mode 100644 index 0000000000..32942d4a44 --- /dev/null +++ b/saga/actor.h @@ -0,0 +1,234 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Actor management module header file + + Notes: + + Hardcoded actor table present in r_actordata.c +*/ + +#ifndef SAGA_ACTOR_H__ +#define SAGA_ACTOR_H__ + +namespace Saga { + +#define ACTOR_BASE_SPEED 0.25 +#define ACTOR_BASE_ZMOD 0.5 + +#define ACTOR_DEFAULT_ORIENT 2 +#define ACTOR_ORIENTMAX 7 + +#define ACTOR_ACTIONTIME 80 + +#define ACTOR_DIALOGUE_LETTERTIME 50 +#define ACTOR_DIALOGUE_HEIGHT 100 + +#define R_ACTOR_LMULT 4 + +enum R_ACTOR_INTENTS { + + INTENT_NONE = 0, + INTENT_PATH = 1, + INTENT_SPEAK = 2 +}; + +typedef struct R_ACTORACTIONITEM_tag { + + int frame_index; + int frame_count; + +} R_ACTORACTIONITEM; + +typedef struct R_ACTORACTION_tag { + + R_ACTORACTIONITEM dir[4]; + +} R_ACTORACTION; + +typedef struct R_WALKINTENT_tag { + + int wi_active; + uint wi_flags; + int wi_init; + + int time; + float slope; + int x_dir; + R_POINT org; + R_POINT cur; + + R_POINT dst_pt; + YS_DL_LIST *nodelist; + + int sem_held; + R_SEMAPHORE *sem; + +} R_WALKINTENT; + +typedef struct R_WALKNODE_tag { + + int calc_flag; + R_POINT node_pt; + +} R_WALKNODE; + +typedef struct R_SPEAKINTENT_tag { + + int si_init; + uint si_flags; + int si_last_action; + + YS_DL_LIST *si_diaglist; /* Actor dialogue list */ + +} R_SPEAKINTENT; + +typedef struct R_ACTORINTENT_tag { + + int a_itype; + uint a_iflags; + int a_idone; + + void *a_data; + +} R_ACTORINTENT; + +typedef struct R_ACTOR_tag { + + int id; /* Actor id */ + int name_i; /* Actor's index in actor name string list */ + uint flags; + + R_POINT a_pt; /* Actor's logical coordinates */ + R_POINT s_pt; /* Actor's screen coordinates */ + + int sl_rn; /* Actor's sprite list res # */ + int si_rn; /* Actor's sprite index res # */ + R_SPRITELIST *sl_p; /* Actor's sprite list data */ + + int idle_time; + int orient; + int speaking; + + int a_dcolor; /* Actor dialogue color */ + + /* The actor intent list describes what the actor intends to do; + * multiple intents can be queued. The actor must complete an + * intent before moving on to the next; thus actor movements, esp + * as described from scripts, can be serialized */ + + YS_DL_LIST *a_intentlist; +/* + R_WALKPATH path; +*/ + + int def_action; + uint def_action_flags; + + int action; + uint action_flags; + + int action_frame; + int action_time; + + R_ACTORACTION *act_tbl; /* Action lookup table */ + int action_ct; /* Number of actions in the action LUT */ + + YS_DL_NODE *node; /* Actor's node in the actor list */ + +} R_ACTOR; + +typedef struct R_ACTORDIALOGUE_tag { + + int d_playing; + char *d_string; + uint d_voice_rn; + + long d_time; + int d_sem_held; + R_SEMAPHORE *d_sem; + +} R_ACTORDIALOGUE; + +typedef struct R_ACTIONTIMES_tag { + + int action; + int time; + +} R_ACTIONTIMES; + +typedef struct R_ACTOR_MODULE_tag { + + int init; + + R_RSCFILE_CONTEXT *actor_ctxt; + + uint count; + + int *alias_tbl; + YS_DL_NODE **tbl; + YS_DL_LIST *list; + + int err_n; + const char *err_str; + +} R_ACTOR_MODULE; + +R_ACTOR *LookupActor(int index); + +int AddActor(R_ACTOR * actor); + +int Z_Compare(const void *elem1, const void *elem2); + +int +HandleWalkIntent(R_ACTOR * actor, + R_WALKINTENT * a_walk_int, int *complete_p, int msec); + +int +HandleSpeakIntent(R_ACTOR * actor, + R_SPEAKINTENT * a_speakint, int *complete_p, int msec); + +int +ACTOR_SetPathNode(R_WALKINTENT * walk_int, + R_POINT * src_pt, R_POINT * dst_pt, R_SEMAPHORE * sem); + +int LoadActorSpriteIndex(R_ACTOR * actor, int si_rn, int *last_frame_p); + +static void CF_actor_add(int argc, char *argv[]); + +static void CF_actor_del(int argc, char *argv[]); + +static void CF_actor_move(int argc, char *argv[]); + +static void CF_actor_moverel(int argc, char *argv[]); + +static void CF_actor_seto(int argc, char *argv[]); + +static void CF_actor_setact(int argc, char *argv[]); + +} // End of namespace Saga + +#endif /* R_ACTOR_H__ */ +/* end "r_actor.h" */ diff --git a/saga/actor_mod.h b/saga/actor_mod.h new file mode 100644 index 0000000000..ebd2881d70 --- /dev/null +++ b/saga/actor_mod.h @@ -0,0 +1,100 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Actor management module public header file + + Notes: +*/ + +#ifndef SAGA_ACTOR_MOD_H +#define SAGA_ACTOR_MOD_H + +namespace Saga { + +enum R_ACTOR_WALKFLAGS { + + WALK_NONE = 0x00, + WALK_NOREORIENT = 0x01 +}; + +enum R_ACTOR_ORIENTATIONS { + + ORIENT_N = 0, + ORIENT_NE = 1, + ORIENT_E = 2, + ORIENT_SE = 3, + ORIENT_S = 4, + ORIENT_SW = 5, + ORIENT_W = 6, + ORIENT_NW = 7 +}; + +enum R_ACTOR_ACTIONS { + + ACTION_IDLE = 0, + ACTION_WALK = 1, + ACTION_SPEAK = 2, + ACTION_COUNT +}; + +enum R_ACTOR_ACTIONFLAGS { + + ACTION_NONE = 0x00, + ACTION_LOOP = 0x01 +}; + +int ACTOR_Register(void); +int ACTOR_Init(void); +int ACTOR_Shutdown(void); + +int ACTOR_Direct(int msec); + +int ACTOR_Create(int actor_id, int x, int y); +int ACTOR_ActorExists(uint actor_id); + +int ACTOR_DrawList(void); +int ACTOR_AtoS(R_POINT * logical, const R_POINT * actor); +int ACTOR_StoA(R_POINT * actor, const R_POINT * screen); + +int ACTOR_Move(int index, R_POINT * move_pt); +int ACTOR_MoveRelative(int index, R_POINT * move_pt); + +int ACTOR_WalkTo(int index, R_POINT * walk_pt, uint flags, R_SEMAPHORE * sem); + +int ACTOR_GetActorIndex(uint actor_id); + +int ACTOR_Speak(int index, char *d_string, uint d_voice_rn, R_SEMAPHORE * sem); + +int ACTOR_SkipDialogue(void); + +int ACTOR_GetSpeechTime(const char *d_string, uint d_voice_rn); +int ACTOR_SetOrientation(int index, int orient); +int ACTOR_SetAction(int index, int action_n, uint action_flags); +int ACTOR_SetDefaultAction(int index, int action_n, uint action_flags); + +} // End of namespace Saga + +#endif /* R_ACTOR_MOD_H */ +/* end "r_actor_mod.h" */ diff --git a/saga/actordata.cpp b/saga/actordata.cpp new file mode 100644 index 0000000000..5342d2d9b8 --- /dev/null +++ b/saga/actordata.cpp @@ -0,0 +1,227 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Actor data table + + Notes: +*/ + +#include "actordata.h" + +namespace Saga { + +/* Lookup table to convert 8 cardinal directions to 4 */ +int ActorOrientationLUT[] = { 2, 0, 0, 0, 3, 1, 1, 1 }; + +R_ACTORTABLE ActorTable[R_ACTORCOUNT] = { + +/* namei sl_rn si_rn col + ----- ----- ----- --- */ + {0, 1, 0, 0, 0, 37, 135, 0, 1, 0, 0, 0}, + /* original okk entry + * { 1, 0, 0, 0, 0, 0, 0, 1, 132, 0, 0, 0 }, */ + {1, 0, 0, 0, 0, 45, 144, 1, 132, 0, 0, 0}, + {2, 0, 0, 0, 0, 48, 143, 2, 161, 0, 0, 0}, + {3, 0, 240, 480, 0, 115, 206, 0, 25, 0, 0, 0}, + {4, 17, 368, 400, 0, 115, 206, 4, 49, 0, 0, 0}, + {5, 11, 552, 412, 0, 54, 152, 1, 171, 0, 0, 0}, + {17, 2, 1192, 888, 0, 57, 153, 17, 49, 0, 0, 0}, + {17, 2, 816, 1052, 0, 57, 153, 18, 49, 0, 0, 0}, + {17, 2, 928, 932, 0, 58, 153, 19, 49, 0, 0, 0}, + {17, 2, 1416, 1160, 0, 58, 153, 20, 49, 0, 0, 0}, + {19, 49, 1592, 1336, 0, 92, 175, 15, 162, 0, 0, 0}, + {20, 49, 744, 824, 0, 63, 156, 19, 112, 0, 4, 4}, + {19, 0, 1592, 1336, 0, 92, 175, 0, 171, 0, 0, 0}, + {19, 0, 1592, 1336, 0, 92, 175, 0, 171, 0, 0, 0}, + {9, 49, 1560, 1624, 0, 94, 147, 18, 132, 0, 4, 4}, + {56, 49, 1384, 792, 0, 95, 193, 20, 72, 0, 0, 0}, + {19, 0, 1592, 1336, 0, 92, 175, 0, 171, 0, 0, 0}, + {19, 0, 1592, 1336, 0, 92, 175, 0, 171, 0, 0, 0}, + {19, 0, 1592, 1336, 0, 92, 175, 0, 171, 0, 0, 0}, + {19, 0, 1592, 1336, 0, 92, 175, 0, 171, 0, 0, 0}, + {19, 0, 1592, 1336, 0, 92, 175, 0, 171, 0, 0, 0}, + {19, 0, 1592, 1336, 0, 92, 175, 0, 171, 0, 0, 0}, + {18, 32, 764, 448, 0, 55, 150, 0, 48, 10, 4, 4}, + {35, 32, 0, 0, 0, 56, 151, 0, 112, 0, 0, 0}, + {36, 32, 0, 0, 0, 105, 142, 0, 155, 0, 0, 0}, + {32, 32, 0, 0, 0, 91, 190, 0, 98, 0, 0, 0}, + {31, 32, 0, 0, 0, 90, 189, 0, 171, 0, 0, 0}, + {31, 32, 0, 0, 0, 90, 189, 0, 171, 0, 0, 0}, + {31, 32, 0, 0, 0, 90, 189, 0, 171, 0, 0, 0}, + {31, 32, 0, 0, 0, 79, 172, 0, 18, 0, 0, 0}, + {21, 50, 664, 400, 0, 76, 171, 2, 74, 0, 4, 4}, + {21, 50, 892, 428, 0, 76, 171, 2, 74, 0, 4, 4}, + {9, 51, 904, 936, 0, 51, 145, 35, 5, 0, 0, 0}, + {9, 51, 872, 840, 0, 51, 145, 36, 5, 0, 0, 0}, + {9, 51, 1432, 344, 0, 51, 145, 37, 5, 0, 0, 0}, + {9, 51, 664, 472, 0, 51, 145, 38, 5, 0, 0, 0}, + {10, 51, 1368, 1464, 0, 80, 146, 39, 147, 0, 0, 0}, + {10, 51, 1416, 1624, 0, 80, 146, 40, 147, 0, 0, 0}, + {10, 51, 1752, 120, 0, 80, 146, 41, 147, 0, 0, 0}, + {10, 51, 984, 408, 0, 80, 146, 42, 147, 0, 0, 0}, + {14, 52, 856, 376, 0, 82, 174, 8, 73, 0, 0, 0}, + {14, 52, 808, 664, 0, 82, 174, 9, 73, 0, 0, 0}, + {14, 52, 440, 568, 0, 82, 174, 10, 73, 0, 0, 0}, + {14, 52, 392, 776, 0, 82, 174, 11, 73, 0, 0, 0}, + {21, 4, 240, 384, 0, 79, 172, 0, 18, 0, 2, 2}, + {23, 4, 636, 268, 0, 77, 173, 0, 74, 0, 4, 4}, + {22, 4, 900, 320, 0, 78, 179, 0, 60, 0, 4, 4}, + {14, 4, 788, 264, 0, 75, 170, 0, 171, 0, 2, 2}, + {14, 4, 1088, 264, 0, 75, 170, 0, 171, 0, 6, 6}, + {24, 19, 728, 396, 0, 65, 181, 47, 146, 0, 6, 6}, + {24, 21, -20, -20, 0, 66, 182, 0, 146, 0, 4, 4}, + {25, 19, 372, 464, 0, 67, 183, 73, 146, 0, 2, 2}, + {26, 5, 564, 476, 27, 53, 149, 1, 5, 0, 4, 4}, + {27, 31, 868, 344, 0, 81, 180, 0, 171, 0, 4, 4}, + {28, 73, 568, 380, 0, 83, 176, 30, 120, 0, 4, 4}, + {14, 7, 808, 480, 0, 82, 174, 9, 73, 0, 0, 0}, + {29, 10, 508, 432, 0, 84, 186, 6, 112, 0, 4, 4}, + {33, 10, 676, 420, 0, 86, 184, 6, 171, 0, 4, 4}, + {30, 10, 388, 452, 0, 88, 185, 6, 171, 0, 4, 4}, + {30, 10, 608, 444, 0, 89, 185, 6, 171, 0, 4, 4}, + {31, 10, 192, 468, 0, 90, 189, 6, 171, 0, 4, 4}, + {31, 10, 772, 432, 0, 90, 189, 6, 171, 0, 4, 4}, + {14, 10, 1340, 444, 0, 87, 188, 6, 171, 0, 4, 4}, + {20, 18, 808, 360, 7, 60, 154, 64, 88, 0, 4, 4}, + {34, 49, 1128, 1256, 0, 96, 191, 16, 35, 0, 4, 4}, + {34, 49, 1384, 792, 0, 93, 192, 17, 66, 0, 4, 4}, + {24, 21, 0, -40, 0, 65, 181, 50, 146, 0, 6, 6}, + {3, 21, 0, -40, 0, 64, 158, 49, 112, 0, 0, 0}, + {17, 21, 0, -40, 0, 62, 157, 74, 48, 0, 0, 0}, + {17, 21, 0, -40, 0, 62, 157, 74, 49, 0, 0, 0}, + {17, 21, 0, -40, 0, 62, 157, 74, 50, 0, 0, 0}, + {12, 244, 1056, 504, 0, 107, 167, 21, 124, 0, 6, 6}, + {8, 33, 248, 440, 0, 68, 169, 14, 112, 0, 0, 0}, + {11, 23, 308, 424, 0, 106, 166, 6, 48, 0, 2, 2}, + {17, 2, 1864, 1336, 0, 58, 153, 21, 49, 0, 0, 0}, + {17, 2, 760, 216, 0, 58, 153, 22, 49, 0, 0, 0}, + {44, 29, 0, 0, 0, 72, 159, 0, 112, 0, 0, 0}, + {45, 29, 0, 0, 0, 71, 163, 0, 146, 0, 6, 6}, + {45, 29, 0, 0, 0, 71, 163, 0, 124, 0, 2, 2}, + {45, 29, 0, 0, 0, 71, 163, 0, 169, 0, 0, 0}, + {7, 29, 0, 0, 0, 69, 164, 0, 4, 0, 0, 0}, + {7, 29, 0, 0, 0, 70, 165, 0, 4, 0, 0, 0}, + {7, 257, 552, 408, 0, 70, 165, 0, 4, 0, 2, 2}, + {7, 29, 0, 0, 0, 70, 165, 0, 4, 0, 0, 0}, + {7, 29, 0, 0, 0, 70, 165, 0, 4, 0, 0, 0}, + {7, 257, 712, 380, 0, 69, 164, 0, 4, 0, 4, 4}, + {7, 29, 0, 0, 0, 69, 164, 0, 4, 0, 0, 0}, + {7, 29, 0, 0, 0, 69, 164, 0, 4, 0, 0, 0}, + {7, 29, 0, 0, 0, 69, 164, 0, 4, 0, 0, 0}, + {7, 29, 0, 0, 0, 69, 164, 0, 4, 0, 0, 0}, + {7, 0, 0, 0, 0, 69, 164, 0, 4, 0, 0, 0}, + {7, 29, 0, 0, 0, 70, 165, 0, 4, 0, 0, 0}, + {47, 30, 0, 0, 0, 102, 199, 1, 186, 0, 0, 0}, + {48, 69, 0, 0, 0, 109, 202, 35, 26, 0, 0, 0}, + {49, 69, 0, 0, 0, 109, 202, 35, 26, 0, 0, 0}, + {50, 69, 0, 0, 0, 111, 203, 16, 67, 0, 0, 0}, + {51, 20, 0, 0, 0, 112, 204, 15, 26, 0, 0, 0}, + {50, 20, 0, 0, 0, 111, 203, 14, 67, 0, 0, 0}, + {49, 20, 0, 0, 0, 109, 202, 35, 26, 0, 0, 0}, + {48, 256, 0, 0, 0, 109, 202, 35, 26, 0, 0, 0}, + {21, 32, 0, 0, 0, 76, 171, 0, 171, 0, 0, 0}, + {21, 32, 0, 0, 0, 76, 171, 0, 171, 0, 0, 0}, + {21, 32, 0, 0, 0, 76, 171, 0, 171, 0, 0, 0}, + {52, 15, 152, 400, 0, 108, 168, 19, 48, 10, 2, 2}, + {47, 251, 640, 360, 0, 113, 205, 5, 186, 10, 2, 2}, + {41, 75, 152, 400, 0, 100, 197, 5, 81, 0, 0, 0}, + {44, 9, 0, 0, 0, 73, 160, 54, 112, 0, 0, 0}, + {0, 22, -20, -20, 0, 118, 209, 0, 171, 0, 0, 0}, + {1, 22, 0, 0, 0, 119, 210, 0, 171, 0, 0, 0}, + {0, 22, -20, -20, 0, 118, 209, 0, 171, 0, 0, 0}, + {1, 22, 0, 0, 0, 119, 210, 0, 171, 0, 0, 0}, + {53, 42, 640, 400, 0, 104, 201, 8, 141, 0, 0, 0}, + {54, 21, -20, -20, 0, 120, 211, 48, 238, 0, 0, 0}, + {0, 4, -20, -20, 0, 42, 140, 0, 1, 0, 0, 0}, + {26, 5, -20, -20, 27, 52, 148, 1, 5, 0, 4, 4}, + {36, 4, -20, -20, 0, 116, 207, 0, 155, 0, 0, 0}, + {36, 0, -20, -20, 0, 117, 208, 0, 155, 0, 0, 0}, + {46, 252, -20, -20, 0, 74, 162, 29, 34, 0, 0, 0}, + {0, 32, -20, -20, 0, 41, 137, 0, 1, 0, 0, 0}, + {0, 259, -20, -20, 0, 44, 138, 0, 1, 0, 0, 0}, + {0, 5, -20, -20, 0, 43, 139, 0, 1, 0, 0, 0}, + {0, 31, -20, -20, 0, 39, 136, 0, 1, 0, 0, 0}, + {0, 252, -20, -20, 0, 39, 136, 0, 1, 0, 0, 0}, + {0, 15, -20, -20, 0, 39, 136, 0, 1, 0, 0, 0}, + {0, 20, -20, -20, 0, 39, 136, 0, 1, 0, 0, 0}, + {0, 25, -20, -20, 0, 39, 136, 0, 1, 0, 0, 0}, + {0, 272, -20, -20, 0, 40, 141, 0, 1, 0, 0, 0}, + {0, 50, -20, -20, 0, 39, 136, 0, 1, 0, 0, 0}, + {50, 71, -20, -20, 0, 111, 203, 0, 67, 0, 0, 0}, + {50, 274, -20, -20, 0, 111, 203, 0, 67, 0, 0, 0}, + {50, 274, -20, -20, 0, 110, 212, 0, 171, 0, 0, 0}, + {50, 274, -20, -20, 0, 110, 212, 0, 171, 0, 0, 0}, + {50, 274, -20, -20, 0, 110, 212, 0, 171, 0, 0, 0}, + {57, 272, 909, 909, 48, 121, 213, 0, 171, 0, 0, 0}, + {58, 15, -20, -20, 0, 122, 214, 0, 171, 0, 0, 0}, + {37, 246, -20, -20, 0, 97, 194, 0, 141, 0, 0, 0}, + {38, 246, -20, -20, 0, 98, 195, 0, 27, 0, 0, 0}, + {59, 246, -20, -20, 0, 103, 200, 0, 26, 0, 0, 0}, + {41, 245, -20, -20, 0, 100, 197, 0, 81, 0, 0, 0}, + {47, 250, 640, 360, 0, 114, 205, 0, 186, 10, 2, 2}, + {0, 278, -20, -20, 0, 40, 141, 0, 1, 0, 0, 0}, + {0, 272, -20, -20, 0, 40, 141, 0, 1, 0, 0, 0}, + {41, 77, -20, -20, 0, 100, 197, 24, 81, 0, 0, 0}, + {37, 261, -20, -20, 0, 97, 194, 0, 141, 0, 0, 0}, + {38, 261, -20, -20, 0, 98, 195, 0, 27, 0, 0, 0}, + {39, 261, -20, -20, 0, 99, 196, 0, 5, 0, 0, 0}, + {39, 261, -20, -20, 0, 99, 196, 0, 5, 0, 0, 0}, + {39, 261, -20, -20, 0, 99, 196, 0, 5, 0, 0, 0}, + {39, 261, -20, -20, 0, 99, 196, 0, 5, 0, 0, 0}, + {59, 279, -20, -20, 0, 103, 200, 0, 26, 0, 0, 0}, + {38, 279, -20, -20, 0, 98, 195, 0, 27, 0, 0, 0}, + {42, 77, -20, -20, 0, 101, 198, 25, 171, 0, 0, 0}, + {59, 281, -20, -20, 0, 103, 200, 26, 26, 0, 0, 0}, + {59, 279, -20, -20, 0, 123, 215, 0, 1, 0, 0, 0}, + {59, 279, -20, -20, 0, 123, 215, 0, 132, 0, 0, 0}, + {59, 279, -20, -20, 0, 123, 215, 0, 161, 0, 0, 0}, + {54, 279, -20, -20, 0, 120, 211, 0, 133, 0, 6, 6}, + {44, 9, -20, -20, 0, 124, 161, 0, 171, 0, 6, 6}, + {7, 255, 588, 252, 0, 70, 165, 0, 3, 0, 2, 2}, + {7, 255, 696, 252, 0, 70, 165, 0, 5, 0, 6, 6}, + {36, 4, 0, 0, 0, 105, 142, 0, 155, 0, 0, 0}, + {44, 272, 1124, 1124, 120, 72, 159, 0, 112, 0, 0, 0}, + {7, 272, 1124, 1108, 120, 70, 165, 0, 4, 0, 0, 0}, + {7, 272, 1108, 1124, 120, 70, 165, 0, 4, 0, 0, 0}, + {29, 288, 508, 432, 0, 85, 187, 0, 112, 0, 4, 4}, + {29, 0, 508, 432, 0, 84, 186, 0, 99, 0, 4, 4}, + {29, 0, 508, 432, 0, 84, 186, 0, 98, 0, 4, 4}, + {29, 0, 508, 432, 0, 84, 186, 0, 104, 0, 4, 4}, + {29, 0, 508, 432, 0, 84, 186, 0, 99, 0, 4, 4}, + {36, 288, 0, 0, 0, 105, 142, 0, 155, 0, 0, 0}, + {1, 27, -20, -20, 0, 47, 178, 0, 132, 0, 0, 0}, + {1, 252, -20, -20, 0, 47, 178, 0, 132, 0, 0, 0}, + {1, 25, -20, -20, 0, 47, 178, 0, 132, 0, 0, 0}, + {1, 259, -20, -20, 0, 47, 178, 0, 132, 0, 0, 0}, + {1, 279, -20, -20, 0, 47, 178, 0, 132, 0, 0, 0}, + {1, 273, -20, -20, 0, 47, 178, 0, 132, 0, 0, 0}, + {1, 26, -20, -20, 0, 8, 178, 0, 171, 0, 0, 0}, + {1, 0, -20, -20, 0, 0, 0, 0, 50, 0, 0, 0}, + {1, 0, -20, -20, 0, 0, 0, 0, 82, 0, 0, 0}, + {1, 0, -20, -20, 0, 0, 0, 0, 35, 0, 0, 0}, + {9, 74, -20, -20, 0, 51, 145, 0, 5, 0, 0, 0} +}; + +} // End of namespace Saga diff --git a/saga/actordata.h b/saga/actordata.h new file mode 100644 index 0000000000..9fc4c4db41 --- /dev/null +++ b/saga/actordata.h @@ -0,0 +1,62 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Actor data table header file + + Notes: +*/ + +#ifndef SAGA_ACTORDATA_H +#define SAGA_ACTORDATA_H + +namespace Saga { + +typedef struct R_ACTORTABLE_tag { + + int name_index; + int unknown1; + int unknown2; + int unknown3; + int unknown4; + int spritelist_rn; + int spriteindex_rn; + int unknown5; + unsigned char color; + unsigned char unknown6; + unsigned char unknown7; + unsigned char unknown8; + +} R_ACTORTABLE; + +#define R_ACTORCOUNT 181 + +extern int ActorOrientationLUT[]; +extern R_ACTORTABLE ActorTable[R_ACTORCOUNT]; + +} // End of namespace Saga + +#endif /* R_ACTORDATA_H */ + +/* end "r_actordata.h" */ diff --git a/saga/animation.cpp b/saga/animation.cpp new file mode 100644 index 0000000000..70f6d8dac0 --- /dev/null +++ b/saga/animation.cpp @@ -0,0 +1,1192 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Background animation management module + + Notes: +*/ + +#include "reinherit.h" + +#include "yslib.h" + +/* + * Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "cvar_mod.h" +#include "console_mod.h" +#include "game_mod.h" +#include "events_mod.h" +#include "render_mod.h" + +/* + * Begin module +\*--------------------------------------------------------------------------*/ +#include "animation_mod.h" +#include "animation.h" + +namespace Saga { + +static R_ANIMINFO AnimInfo; + +int ANIM_Register(void) +{ + CVAR_RegisterFunc(CF_anim_info, "anim_info", NULL, R_CVAR_NONE, 0, 0); + + return R_SUCCESS; +} + +int ANIM_Init(void) +{ + + AnimInfo.anim_limit = R_MAX_ANIMATIONS; + AnimInfo.anim_count = 0; + + AnimInfo.initialized = 1; + + return R_SUCCESS; +} + +int ANIM_Shutdown(void) +{ + uint i; + + for (i = 0; i < R_MAX_ANIMATIONS; i++) { + + free(AnimInfo.anim_tbl[i]); + } + + AnimInfo.initialized = 0; + + return R_SUCCESS; +} + +int +ANIM_Load(const uchar * anim_resdata, + size_t anim_resdata_len, uint * anim_id_p) +{ + R_ANIMATION *new_anim; + + uint anim_id = 0; + uint i; + + if (!AnimInfo.initialized) { + return R_FAILURE; + } + + /* Find an unused animation slot + * \*------------------------------------------------------------- */ + for (i = 0; i < R_MAX_ANIMATIONS; i++) { + + if (AnimInfo.anim_tbl[i] == NULL) { + + anim_id = i; + break; + } + } + + if (i == R_MAX_ANIMATIONS) { + return R_FAILURE; + } + + new_anim = (R_ANIMATION *)malloc(sizeof *new_anim); + if (new_anim == NULL) { + R_printf(R_STDERR, "Error: Allocation failure.\n"); + + return R_MEM; + } + + new_anim->resdata = anim_resdata; + new_anim->resdata_len = anim_resdata_len; + + if (GAME_GetGameType() == R_GAMETYPE_ITE) { + + if (ANIM_GetNumFrames(anim_resdata, + &new_anim->n_frames) != R_SUCCESS) { + + R_printf(R_STDERR, + "Error: Couldn't get animation frame count.\n"); + + return R_FAILURE; + } + + /* Cache frame offsets + * \*------------------------------------------------------------- */ + new_anim->frame_offsets = (size_t *)malloc(new_anim->n_frames * + sizeof *new_anim->frame_offsets); + if (new_anim->frame_offsets == NULL) { + R_printf(R_STDERR, "Error: Allocation failure.\n"); + + return R_MEM; + } + + for (i = 0; i < new_anim->n_frames; i++) { + + ANIM_GetFrameOffset(anim_resdata, + i + 1, &new_anim->frame_offsets[i]); + } + } else { + new_anim->cur_frame_p = anim_resdata + SAGA_FRAME_HEADER_LEN; + new_anim->cur_frame_len = + anim_resdata_len - SAGA_FRAME_HEADER_LEN; + + ANIM_GetNumFrames(anim_resdata, &new_anim->n_frames); + } + + /* Set animation data + * \*------------------------------------------------------------- */ + new_anim->current_frame = 1; + new_anim->end_frame = new_anim->n_frames; + new_anim->stop_frame = new_anim->end_frame; + + new_anim->frame_time = R_DEFAULT_FRAME_TIME; + new_anim->flags = 0; + new_anim->play_flag = 0; + new_anim->link_flag = 0; + new_anim->link_id = 0; + + AnimInfo.anim_tbl[anim_id] = new_anim; + + *anim_id_p = anim_id; + + AnimInfo.anim_count++; + + return R_SUCCESS; +} + +int ANIM_Link(uint anim_id1, uint anim_id2) +{ + R_ANIMATION *anim1; + R_ANIMATION *anim2; + + if ((anim_id1 >= AnimInfo.anim_count) || + (anim_id2 >= AnimInfo.anim_count)) { + + return R_FAILURE; + } + + anim1 = AnimInfo.anim_tbl[anim_id1]; + anim2 = AnimInfo.anim_tbl[anim_id2]; + + if ((anim1 == NULL) || (anim2 == NULL)) { + return R_FAILURE; + } + + anim1->link_id = anim_id2; + anim1->link_flag = 1; + + anim2->frame_time = anim1->frame_time; + + return R_SUCCESS; +} + +int ANIM_Play(uint anim_id, int vector_time) +{ + + R_EVENT event; + R_ANIMATION *anim; + R_ANIMATION *link_anim; + uint link_anim_id; + + R_BUFFER_INFO buf_info; + + uchar *display_buf; + + const uchar *nextf_p; + size_t nextf_len; + + uint frame; + int result; + + R_GAME_DISPLAYINFO disp_info; + + if (anim_id >= AnimInfo.anim_count) { + + return R_FAILURE; + } + + GAME_GetDisplayInfo(&disp_info); + + RENDER_GetBufferInfo(&buf_info); + display_buf = buf_info.r_bg_buf; + + anim = AnimInfo.anim_tbl[anim_id]; + if (anim == NULL) { + + return R_FAILURE; + } + + if (anim->play_flag) { + + frame = anim->current_frame; + + if (GAME_GetGameType() == R_GAMETYPE_ITE) { + + result = ITE_DecodeFrame(anim->resdata, + anim->frame_offsets[frame - 1], + display_buf, + disp_info.logical_w * disp_info.logical_h); + + if (result != R_SUCCESS) { + + R_printf(R_STDERR, + "ANIM_Play: Error decoding frame %u", + anim->current_frame); + + anim->play_flag = 0; + return R_FAILURE; + } + } else { + + if (anim->cur_frame_p == NULL) { + R_printf(R_STDERR, + "ANIM_Play: Frames exhausted.\n"); + + return R_FAILURE; + } + + result = IHNM_DecodeFrame(display_buf, + disp_info.logical_w * + disp_info.logical_h, + anim->cur_frame_p, + anim->cur_frame_len, &nextf_p, &nextf_len); + + if (result != R_SUCCESS) { + + R_printf(R_STDERR, + "ANIM_Play: Error decoding frame %u", + anim->current_frame); + + anim->play_flag = 0; + return R_FAILURE; + } + + anim->cur_frame_p = nextf_p; + anim->cur_frame_len = nextf_len; + } + + anim->current_frame++; + } + + anim->play_flag = 1; + + if (anim->current_frame > anim->n_frames) { + + /* Animation done playing */ + + if (anim->link_flag) { + + /* If this animation has a link, follow it */ + anim->play_flag = 0; + anim->current_frame = 1; + + link_anim_id = anim->link_id; + link_anim = AnimInfo.anim_tbl[link_anim_id]; + + if (link_anim != NULL) { + + link_anim->current_frame = 1; + link_anim->play_flag = 1; + } + + anim_id = link_anim_id; + } else if (anim->flags & ANIM_LOOP) { + + /* Loop animation */ + anim->current_frame = 1; + + anim->cur_frame_p = + anim->resdata + SAGA_FRAME_HEADER_LEN; + anim->cur_frame_len = + anim->resdata_len - SAGA_FRAME_HEADER_LEN; + } else { + + /* No link, stop playing */ + anim->current_frame = anim->n_frames; + anim->play_flag = 0; + + if (anim->flags & ANIM_ENDSCENE) { + + /* This animation ends the scene */ + event.type = R_ONESHOT_EVENT; + event.code = R_SCENE_EVENT; + event.op = EVENT_END; + event.time = anim->frame_time + vector_time; + + EVENT_Queue(&event); + } + return R_SUCCESS; + } + } + + event.type = R_ONESHOT_EVENT; + event.code = R_ANIM_EVENT; + event.op = EVENT_FRAME; + event.param = anim_id; + event.time = anim->frame_time + vector_time; + + EVENT_Queue(&event); + + return R_SUCCESS; +} + +int ANIM_Reset(void) +{ + uint i; + + for (i = 0; i < R_MAX_ANIMATIONS; i++) { + + ANIM_Free(i); + } + + AnimInfo.anim_count = 0; + + return R_SUCCESS; +} + +int ANIM_SetFlag(uint anim_id, uint flag) +{ + R_ANIMATION *anim; + + if (anim_id > AnimInfo.anim_count) { + + return R_FAILURE; + } + + anim = AnimInfo.anim_tbl[anim_id]; + if (anim == NULL) { + + return R_FAILURE; + } + + anim->flags |= flag; + + return R_SUCCESS; +} + +int ANIM_SetFrameTime(uint anim_id, int time) +{ + R_ANIMATION *anim; + + if (anim_id > AnimInfo.anim_count) { + + return R_FAILURE; + } + + anim = AnimInfo.anim_tbl[anim_id]; + if (anim == NULL) { + + return R_FAILURE; + } + + anim->frame_time = time; + + return R_SUCCESS; +} + +int ANIM_Free(uint anim_id) +{ + R_ANIMATION *anim; + + if (anim_id > AnimInfo.anim_count) { + + return R_FAILURE; + } + + anim = AnimInfo.anim_tbl[anim_id]; + if (anim == NULL) { + + return R_FAILURE; + } + + if (GAME_GetGameType() == R_GAMETYPE_ITE) { + + free(anim->frame_offsets); + anim->frame_offsets = NULL; + } + + free(anim); + AnimInfo.anim_tbl[anim_id] = NULL; + AnimInfo.anim_count--; + + return R_SUCCESS; +} + +int ANIM_GetNumFrames(const uchar * anim_resource, uint * n_frames) +/*--------------------------------------------------------------------------*\ + * The actual number of frames present in an animation resource is + * sometimes less than number present in the .nframes member of the + * animation header. For this reason, the function attempts to find + * the last valid frame number, which it returns via 'n_frames' +\*--------------------------------------------------------------------------*/ +{ + R_ANIMATION_HEADER ah; + + size_t offset; + int magic; + + int x; + + const uchar *read_p = anim_resource; + + if (!AnimInfo.initialized) { + + return R_FAILURE; + } + + ah.magic = ys_read_u16_le(read_p, &read_p); + ah.screen_w = ys_read_u16_le(read_p, &read_p); + ah.screen_h = ys_read_u16_le(read_p, &read_p); + + ah.unknown06 = ys_read_u8(read_p, &read_p); + ah.unknown07 = ys_read_u8(read_p, &read_p); + ah.nframes = ys_read_u8(read_p, NULL); + + if (GAME_GetGameType() == R_GAMETYPE_IHNM) { + + *n_frames = ah.nframes; + } + + if (ah.magic == 68) { + + for (x = ah.nframes; x > 0; x--) { + + if (ANIM_GetFrameOffset(anim_resource, + x, &offset) != R_SUCCESS) { + + return R_FAILURE; + } + + magic = *(anim_resource + offset); + + if (magic == SAGA_FRAME_HEADER_MAGIC) { + *n_frames = x; + + return R_SUCCESS; + } + } + + return R_FAILURE; + } + + return R_FAILURE; +} + +int +ITE_DecodeFrame(const uchar * resdata, + size_t frame_offset, uchar * buf, size_t buf_len) +{ + + R_ANIMATION_HEADER ah; + R_FRAME_HEADER fh; + + const uchar *read_p = resdata; + uchar *write_p; + + uint magic; + + uint x_start; + uint y_start; + ulong screen_w; + ulong screen_h; + + int mark_byte; + uchar data_byte; + int new_row; + + uint control_ch; + uint param_ch; + + uint runcount; + int x_vector; + + uint i; + + if (!AnimInfo.initialized) { + + return R_FAILURE; + } + + /* Read animation header + * \*------------------------------------------------------------- */ + ah.magic = ys_read_u16_le(read_p, &read_p); + ah.screen_w = ys_read_u16_le(read_p, &read_p); + ah.screen_h = ys_read_u16_le(read_p, &read_p); + ah.unknown06 = ys_read_u8(read_p, &read_p); + ah.unknown07 = ys_read_u8(read_p, &read_p); + ah.nframes = ys_read_u8(read_p, &read_p); + ah.flags = ys_read_u8(read_p, &read_p); + ah.unknown10 = ys_read_u8(read_p, &read_p); + ah.unknown11 = ys_read_u8(read_p, &read_p); + + screen_w = ah.screen_w; + screen_h = ah.screen_h; + + if ((screen_w * screen_h) > buf_len) { + /* Buffer argument is too small to hold decoded frame, abort. */ + R_printf(R_STDERR, + "ITE_DecodeFrame: Buffer size inadequate.\n"); + + return R_FAILURE; + } + + /* Read frame header + * \*------------------------------------------------------------- */ + read_p = resdata + frame_offset; + + /* Check for frame magic byte */ + magic = ys_read_u8(read_p, &read_p); + if (magic != SAGA_FRAME_HEADER_MAGIC) { + + R_printf(R_STDERR, "ITE_DecodeFrame: Invalid frame offset.\n"); + + return R_FAILURE; + } + + /* For some strange reason, the animation header is in little + * endian format, but the actual RLE encoded frame data, + * including the frame header, is in big endian format. */ + + fh.x_start = ys_read_u16_be(read_p, &read_p); + fh.y_start = ys_read_u8(read_p, &read_p); + read_p++; /* Skip pad byte */ + fh.x_pos = ys_read_u16_be(read_p, &read_p); + fh.y_pos = ys_read_u16_be(read_p, &read_p); + fh.width = ys_read_u16_be(read_p, &read_p); + fh.height = ys_read_u16_be(read_p, &read_p); + + x_start = fh.x_start; + y_start = fh.y_start; + + /* Setup write pointer to the draw origin + * \*------------------------------------------------------------- */ + write_p = (buf + (y_start * screen_w) + x_start); + + /* Begin RLE decompression to output buffer + * \*------------------------------------------------------------- */ + do { + + mark_byte = ys_read_u8(read_p, &read_p); + + switch (mark_byte) { + + case 0x10: /* Long Unencoded Run */ + + runcount = ys_read_s16_be(read_p, &read_p); + + for (i = 0; i < runcount; i++) { + if (*read_p != 0) { + *write_p = *read_p; + } + write_p++; + read_p++; + } + continue; + break; + + case 0x20: /* Long encoded run */ + + runcount = ys_read_s16_be(read_p, &read_p); + + data_byte = *read_p++; + + for (i = 0; i < runcount; i++) { + *write_p++ = data_byte; + } + continue; + break; + + case 0x2F: /* End of row */ + + x_vector = ys_read_s16_be(read_p, &read_p); + new_row = ys_read_u8(read_p, &read_p); + + /* Set write pointer to the new draw origin */ + write_p = buf + ((y_start + new_row) * screen_w) + + x_start + x_vector; + continue; + break; + + case 0x30: /* Reposition command */ + + x_vector = ys_read_s16_be(read_p, &read_p); + + write_p += x_vector; + continue; + break; + + case 0x3F: /* End of frame marker */ + + return R_SUCCESS; + break; + + default: + break; + } + + /* Mask all but two high order control bits */ + control_ch = mark_byte & 0xC0U; + param_ch = mark_byte & 0x3FU; + + switch (control_ch) { + + case 0xC0: /* 1100 0000 */ + + /* Run of empty pixels */ + runcount = param_ch + 1; + write_p += runcount; + continue; + break; + + case 0x80: /* 1000 0000 */ + + /* Run of compressed data */ + runcount = param_ch + 1; + + data_byte = *read_p++; + + for (i = 0; i < runcount; i++) { + *write_p++ = data_byte; + } + continue; + break; + + case 0x40: /* 0100 0000 */ + + /* Uncompressed run */ + runcount = param_ch + 1; + + for (i = 0; i < runcount; i++) { + if (*read_p != 0) { + *write_p = *read_p; + } + write_p++; + read_p++; + } + continue; + break; + + default: + /* Unknown marker found - abort */ + + R_printf(R_STDERR, + "ITE_DecodeFrame: Invalid RLE marker " + "encountered.\n"); + + return R_FAILURE; + break; + } + + } while (mark_byte != 63); /* end of frame marker */ + + return R_SUCCESS; +} + +int +IHNM_DecodeFrame(uchar * decode_buf, + size_t decode_buf_len, + const uchar * thisf_p, + size_t thisf_len, const uchar ** nextf_p, size_t * nextf_len) +{ + + int in_ch; + + int decoded_data = 0; + int cont_flag = 1; + + int control_ch; + int param_ch; + + uchar data_pixel; + + int x_origin = 0; + int y_origin = 0; + int x_vector; + int new_row; + + uint runcount; + uint c; + + size_t in_ch_offset; + + const uchar *inbuf_p = thisf_p; + size_t inbuf_remain = thisf_len; + + uchar *outbuf_p = decode_buf; + uchar *outbuf_endp = (decode_buf + decode_buf_len) - 1; + size_t outbuf_remain = decode_buf_len; + + R_GAME_DISPLAYINFO di; + + GAME_GetDisplayInfo(&di); + + *nextf_p = NULL; + + for (; cont_flag; decoded_data = 1) { + + in_ch_offset = (size_t) (inbuf_p - thisf_p); + + in_ch = *inbuf_p++; + inbuf_remain--; + + switch (in_ch) { + + case 0x0F: /* 15: Frame header */ + { + int param1; + int param2; + int param3; + int param4; + int param5; + int param6; + + if (inbuf_remain < 13) { + R_printf(R_STDERR, + "0x%02X: Input buffer underrun.", + in_ch); + + return R_FAILURE; + } + + param1 = ys_read_u16_be(inbuf_p, &inbuf_p); + param2 = ys_read_u16_be(inbuf_p, &inbuf_p); + inbuf_p++; /* skip 1? */ + param3 = ys_read_u16_be(inbuf_p, &inbuf_p); + param4 = ys_read_u16_be(inbuf_p, &inbuf_p); + param5 = ys_read_u16_be(inbuf_p, &inbuf_p); + param6 = ys_read_u16_be(inbuf_p, &inbuf_p); + + inbuf_remain -= 13; + + x_origin = param1; + y_origin = param2; + + outbuf_p = decode_buf + x_origin + + (y_origin * di.logical_w); + + if (outbuf_p > outbuf_endp) { + + R_printf(R_STDERR, + "0x%02X: (0x%X) Invalid output position. " + "(x: %d, y: %d)\n", + in_ch, + in_ch_offset, x_origin, y_origin); + + return R_FAILURE; + } + + outbuf_remain = (outbuf_endp - outbuf_p) + 1; + + continue; + } + break; + + case 0x10: /* Long Unencoded Run */ + + runcount = ys_read_s16_be(inbuf_p, &inbuf_p); + + if (inbuf_remain < runcount) { + + R_printf(R_STDERR, + "0x%02X: Input buffer underrun.", in_ch); + + return R_FAILURE; + } + + if (outbuf_remain < runcount) { + + R_printf(R_STDERR, + "0x%02X: Output buffer overrun.", in_ch); + + return R_FAILURE; + } + + for (c = 0; c < runcount; c++) { + if (*inbuf_p != 0) { + *outbuf_p = *inbuf_p; + } + outbuf_p++; + inbuf_p++; + } + + inbuf_remain -= runcount; + outbuf_remain -= runcount; + + continue; + break; + + case 0x1F: /* 31: Unusued? */ + + if (inbuf_remain < 3) { + + R_printf(R_STDERR, + "0x%02X: Input buffer underrun.", in_ch); + + return R_FAILURE; + } + + inbuf_p += 3; + inbuf_remain -= 3; + + continue; + break; + + case 0x20: /* Long compressed run */ + + if (inbuf_remain <= 3) { + + R_printf(R_STDERR, + "0x%02X: Input buffer underrun.", in_ch); + + return R_FAILURE; + } + + runcount = ys_read_s16_be(inbuf_p, &inbuf_p); + data_pixel = *inbuf_p++; + + for (c = 0; c < runcount; c++) { + *outbuf_p++ = data_pixel; + } + + outbuf_remain -= runcount; + inbuf_remain -= 1; + + continue; + break; + + case 0x2F: /* End of row */ + + if (inbuf_remain <= 4) { + return R_FAILURE; + } + + x_vector = ys_read_s16_be(inbuf_p, &inbuf_p); + new_row = ys_read_s16_be(inbuf_p, &inbuf_p); + + outbuf_p = + decode_buf + ((y_origin + new_row) * di.logical_w) + + x_origin + x_vector; + + inbuf_remain -= 4; + outbuf_remain = (outbuf_endp - outbuf_p) + 1; + + continue; + break; + + case 0x30: /* Reposition command */ + if (inbuf_remain < 2) { + return R_FAILURE; + } + + x_vector = ys_read_s16_be(inbuf_p, &inbuf_p); + + if (((x_vector > 0) + && ((size_t) x_vector > outbuf_remain)) + || (-x_vector > outbuf_p - decode_buf)) { + + R_printf(R_STDERR, + "0x30: Invalid x_vector.\n"); + + return R_FAILURE; + } + + outbuf_p += x_vector; + outbuf_remain -= x_vector; + inbuf_remain -= 2; + + continue; + break; + + case 0x3F: /* 68: Frame end marker */ + + printf("0x3F: Frame end marker\n"); + + if (decoded_data && inbuf_remain > 0) { + + *nextf_p = inbuf_p; + *nextf_len = inbuf_remain; + } else { + + *nextf_p = NULL; + *nextf_len = 0; + } + + cont_flag = 0; + continue; + break; + + default: + break; + + } /* end switch() */ + + control_ch = in_ch & 0xC0; + param_ch = in_ch & 0x3f; + + switch (control_ch) { + + case 0xC0: /* Run of empty pixels */ + + runcount = param_ch + 1; + + if (outbuf_remain < runcount) { + return R_FAILURE; + } + + outbuf_p += runcount; + outbuf_remain -= runcount; + + continue; + break; + + case 0x80: /* Run of compressed data */ + + runcount = param_ch + 1; + + if ((outbuf_remain < runcount) || (inbuf_remain <= 1)) { + + return R_FAILURE; + } + + data_pixel = *inbuf_p++; + inbuf_remain--; + + for (c = 0; c < runcount; c++) { + + *outbuf_p++ = data_pixel; + } + + outbuf_remain -= runcount; + + continue; + break; + + case 0x40: /* Uncompressed run */ + + runcount = param_ch + 1; + + if ((outbuf_remain < runcount) || + (inbuf_remain < runcount)) { + + return R_FAILURE; + } + + for (c = 0; c < runcount; c++) { + if (*inbuf_p != 0) { + *outbuf_p = *inbuf_p; + } + outbuf_p++; + inbuf_p++; + } + + inbuf_remain -= runcount; + outbuf_remain -= runcount; + + continue; + break; + + default: + break; + } /* end switch */ + + } /* end while() */ + + return R_SUCCESS; +} + +int +ANIM_GetFrameOffset(const uchar * resdata, + uint find_frame, size_t * frame_offset_p) +{ + R_ANIMATION_HEADER ah; + + uint num_frames; + uint current_frame; + + const uchar *read_p = resdata; + const uchar *search_ptr; + + uchar mark_byte; + uint control; + uint runcount; + + uint magic; + + if (!AnimInfo.initialized) { + + return R_FAILURE; + } + + /* Read animation header + * \*------------------------------------------------------------- */ + ah.magic = ys_read_u16_le(read_p, &read_p); + ah.screen_w = ys_read_u16_le(read_p, &read_p); + ah.screen_h = ys_read_u16_le(read_p, &read_p); + ah.unknown06 = ys_read_u8(read_p, &read_p); + ah.unknown07 = ys_read_u8(read_p, &read_p); + ah.nframes = ys_read_u8(read_p, &read_p); + ah.flags = ys_read_u8(read_p, &read_p); + ah.unknown10 = ys_read_u8(read_p, &read_p); + ah.unknown11 = ys_read_u8(read_p, &read_p); + + num_frames = ah.nframes; + + if ((find_frame < 1) || (find_frame > num_frames)) { + + return R_FAILURE; + } + + search_ptr = read_p; + + for (current_frame = 1; current_frame < find_frame; current_frame++) { + + magic = ys_read_u8(search_ptr, &search_ptr); + + if (magic != SAGA_FRAME_HEADER_MAGIC) { + + /* Frame sync failure. Magic Number not found */ + return R_FAILURE; + } + + search_ptr += SAGA_FRAME_HEADER_LEN; + + /* For some strange reason, the animation header is in little + * endian format, but the actual RLE encoded frame data, + * including the frame header, is in big endian format. */ + + do { + + mark_byte = *search_ptr; + + switch (mark_byte) { + + case 0x3F: /* End of frame marker */ + + search_ptr++; + continue; + break; + + case 0x30: /* Reposition command */ + + search_ptr += 3; + continue; + break; + + case 0x2F: /* End of row marker */ + + search_ptr += 4; + continue; + break; + + case 0x20: /* Long compressed run marker */ + + search_ptr += 4; + continue; + break; + + case 0x10: /* (16) 0001 0000 */ + /* Long Uncompressed Run */ + search_ptr++; + runcount = + ys_read_s16_be(search_ptr, &search_ptr); + search_ptr += runcount; + continue; + break; + + default: + break; + + } + + /* Mask all but two high order (control) bits */ + control = mark_byte & 0xC0; + + switch (control) { + + case 0xC0: + /* Run of empty pixels */ + search_ptr++; + continue; + break; + + case 0x80: + /* Run of compressed data */ + search_ptr += 2; /* Skip data byte */ + continue; + break; + + case 0x40: + /* Uncompressed run */ + search_ptr++; + runcount = (mark_byte & 0x3f) + 1; + search_ptr += runcount; + continue; + break; + + default: + /* Encountered unknown RLE marker, abort */ + return R_FAILURE; + break; + + } /* end switch ( test_byte ) */ + + } while (mark_byte != 63); /* end of frame marker */ + + } /* end for( i = 0 ; i < find_frame ; i ++ ) */ + + *frame_offset_p = (search_ptr - resdata); + + return R_SUCCESS; +} + +static void CF_anim_info(int argc, char *argv[]) +{ + uint anim_ct; + uint i; + uint idx; + + YS_IGNORE_PARAM(argc); + YS_IGNORE_PARAM(argv); + + anim_ct = AnimInfo.anim_count; + + CON_Print("There are %d animations loaded:", anim_ct); + + for (idx = 0, i = 0; i < anim_ct; idx++, i++) { + + while (AnimInfo.anim_tbl[idx] == NULL) { + idx++; + } + + CON_Print("%02d: Frames: %u Flags: %u", + i, + AnimInfo.anim_tbl[idx]->n_frames, + AnimInfo.anim_tbl[idx]->flags); + } + + return; +} + +} // End of namespace Saga diff --git a/saga/animation.h b/saga/animation.h new file mode 100644 index 0000000000..b448f75b10 --- /dev/null +++ b/saga/animation.h @@ -0,0 +1,139 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Background animation management module private header + + Notes: +*/ + +#ifndef SAGA_ANIMATION_H_ +#define SAGA_ANIMATION_H_ + +namespace Saga { + +#define R_MAX_ANIMATIONS 7 +#define R_DEFAULT_FRAME_TIME 140 + +#define SAGA_FRAME_HEADER_MAGIC 15 +#define SAGA_FRAME_HEADER_LEN 12 + +/* All animation resources begin with an ANIMATION_HEADER + * at 0x00, followed by a RLE code stream +\*--------------------------------------------------------------------------*/ + +typedef struct R_ANIMATION_HEADER_tag { + + uint magic; + + uint screen_w; + uint screen_h; + + uint unknown06; + uint unknown07; + + uint nframes; + uint flags; + + uint unknown10; + uint unknown11; + +} R_ANIMATION_HEADER; + +/* A byte from the code stream of FRAME_HEADER_MAGIC signifies that a + * FRAME_HEADER structure follows +\*--------------------------------------------------------------------------*/ + +typedef struct R_FRAME_HEADER_tag { + + int x_start; + int y_start; + + int x_pos; + int y_pos; + + int width; + int height; + +} R_FRAME_HEADER; + +/* Animation info array member */ +typedef struct R_ANIMATION_tag { + + const uchar *resdata; + size_t resdata_len; + + uint n_frames; + size_t *frame_offsets; + + uint current_frame; + uint end_frame; + uint stop_frame; + + const uchar *cur_frame_p; + size_t cur_frame_len; + + int frame_time; + + uint play_flag; + int link_flag; + uint link_id; + + uint flags; + +} R_ANIMATION; + +typedef struct R_ANIMINFO_tag { + + int initialized; + + uint anim_count; + uint anim_limit; + + R_ANIMATION *anim_tbl[R_MAX_ANIMATIONS]; + +} R_ANIMINFO; + +int ANIM_GetNumFrames(const uchar * anim_resource, uint * n_frames); + +int +ITE_DecodeFrame(const uchar * anim_resource, + size_t frame_offset, uchar * buf, size_t buf_len); + +int +IHNM_DecodeFrame(uchar * decode_buf, + size_t decode_buf_len, + const uchar * thisf_p, + size_t thisf_len, const uchar ** nextf_p, size_t * nextf_len); + +int +ANIM_GetFrameOffset(const uchar * anim_resource, + uint find_frame, size_t * frame_offset); + +static void CF_anim_info(int argc, char *argv[]); + +} // End of namespace Saga + +#endif /* R_ANIMATION_H_ */ +/* end "r_animation.h" */ diff --git a/saga/animation_mod.h b/saga/animation_mod.h new file mode 100644 index 0000000000..6bb8a1fcd6 --- /dev/null +++ b/saga/animation_mod.h @@ -0,0 +1,67 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Background animation management module public header + + Notes: +*/ + +#ifndef SAGA_ANIMATION_MOD_H__ +#define SAGA_ANIMATION_MOD_H__ + +namespace Saga { + +enum ANIM_FLAGS { + + ANIM_LOOP = 0x01, + ANIM_ENDSCENE = 0x80 /* When animation ends, dispatch scene end event */ +}; + +int ANIM_Register(void); + +int ANIM_Init(void); + +int ANIM_Shutdown(void); + +int +ANIM_Load(const uchar * anim_resdata, + size_t anim_resdata_len, uint * anim_id_p); + +int ANIM_Free(uint anim_id); + +int ANIM_Play(uint anim_id, int vector_time); + +int ANIM_Link(uint anim_id1, uint anim_id2); + +int ANIM_SetFlag(uint anim_id, uint flag); + +int ANIM_SetFrameTime(uint anim_id, int time); + +int ANIM_Reset(void); + +} // End of namespace Saga + +#endif /* R_ANIMATION_MOD_H__ */ +/* end "r_animation_mod.h__ */ diff --git a/saga/binread.cpp b/saga/binread.cpp deleted file mode 100644 index 71d0ed83ba..0000000000 --- a/saga/binread.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2003 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * $Header$ - * - */ - -#include "common/stdafx.h" - -#include "binread.h" - -namespace Saga { - -BinReader::BinReader() { - _buf = NULL; - _bufPtr = NULL; - _bufEnd = NULL; - _bufLen = 0; -} - -BinReader::BinReader(const byte *buf, size_t buflen) { - _buf = buf; - _bufPtr = buf; - _bufEnd = buf + buflen; - _bufLen = buflen; -} - -BinReader::~BinReader() { -} - -void BinReader::setBuf(const byte *buf, size_t buflen) { - _buf = buf; - _bufPtr = buf; - _bufEnd = buf + buflen; - _bufLen = buflen; -} - -void BinReader::skip(size_t skip_ct) { - assert((_bufPtr + skip_ct) <= _bufEnd ); - - _bufPtr += skip_ct; -} - -unsigned int BinReader::readUint16LE() { - assert((_bufPtr + 2) <= _bufEnd); - - unsigned int u16_le = ((unsigned int)_bufPtr[1] << 8) | _bufPtr[0]; - - _bufPtr += 2; - - return u16_le; -} - -unsigned int BinReader::readUint16BE() { - assert((_bufPtr + 2) <= _bufEnd); - - unsigned int u16_be = ((unsigned int)_bufPtr[0] << 8) | _bufPtr[1]; - - _bufPtr += 2; - - return u16_be; -} - -int BinReader::readSint16LE() { - assert((_bufPtr + 2) <= _bufEnd); - - unsigned int u16_le = ((unsigned int)_bufPtr[1] << 8) | _bufPtr[0]; - - _bufPtr += 2; - - return u16_le; -} - -int BinReader::readSint16BE() { - assert((_bufPtr + 2) <= _bufEnd); - - unsigned int u16_be = ((unsigned int)_bufPtr[0] << 8) | _bufPtr[1]; - - _bufPtr += 2; - - return u16_be; -} - - -uint32 BinReader::readUint32LE() { - assert((_bufPtr + 4) <= _bufEnd); - - unsigned long u32_le = ((unsigned long)_bufPtr[3] << 24) | - ((unsigned long)_bufPtr[2] << 16) | - ((unsigned long)_bufPtr[1] << 8 ) | - _bufPtr[0]; - - _bufPtr += 4; - - return u32_le; -} - -uint32 BinReader::readUint32BE() { - assert((_bufPtr + 4) <= _bufEnd); - - unsigned long u32_be = ((unsigned long)_bufPtr[0] << 24) | - ((unsigned long)_bufPtr[1] << 16) | - ((unsigned long)_bufPtr[2] << 8 ) | - _bufPtr[3]; - - _bufPtr += 4; - - return u32_be; -} - -int32 BinReader::readSint32LE() { - assert((_bufPtr + 4) <= _bufEnd); - - unsigned long u32_le = ((unsigned long)_bufPtr[3] << 24) | - ((unsigned long)_bufPtr[2] << 16) | - ((unsigned long)_bufPtr[1] << 8 ) | - _bufPtr[0]; - - _bufPtr += 4; - - return u32_le; -} - -int32 BinReader::readSint32BE() { - assert((_bufPtr + 4) <= _bufEnd); - - unsigned long u32_be = ((unsigned long)_bufPtr[0] << 24) | - ((unsigned long)_bufPtr[1] << 16) | - ((unsigned long)_bufPtr[2] << 8 ) | - _bufPtr[3]; - - _bufPtr += 4; - - return u32_be; -} - -} // End of namespace Saga diff --git a/saga/binread.h b/saga/binread.h deleted file mode 100644 index 7a4567df9b..0000000000 --- a/saga/binread.h +++ /dev/null @@ -1,73 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2003 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * $Header$ - * - */ - -#ifndef SAGA_BINREAD_H -#define SAGA_BINREAD_H - -#include <stddef.h> -#include "common/scummsys.h" - -namespace Saga { - -class BinReader { - -protected: - - const byte *_buf; - const byte *_bufPtr; - const byte *_bufEnd; - size_t _bufLen; - -public: - - BinReader(); - BinReader( const byte *buf, size_t buflen ); - virtual ~BinReader(); - - void setBuf( const byte *buf, size_t buflen ); - - size_t getOffset() const; - bool setOffset( size_t offset ); - bool setROffset( ptrdiff_t offset ); - void skip( size_t skip_ct ); - - bool setPtr( const byte *buf_pos ); - byte *getPtr() const; - - unsigned int readUint16LE(); - unsigned int readUint16BE(); - int readSint16LE(); - int readSint16BE(); - uint32 readUint32LE(); - uint32 readUint32BE(); - int32 readSint32LE(); - int32 readSint32BE(); -}; - -} // End of namespace Saga - -#endif - - - - - - diff --git a/saga/cmdline.cpp b/saga/cmdline.cpp new file mode 100644 index 0000000000..6848230190 --- /dev/null +++ b/saga/cmdline.cpp @@ -0,0 +1,95 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Command line parser + + Notes: + +*/ + +#include "reinherit.h" + +namespace Saga { + +int R_ReadCommandLine(int argc, char **argv, R_EXECINFO * execinfo) +{ + + int arg; + int intparam; + + for (arg = 1; arg < argc; arg++) { + + if (strcmp(argv[arg], "-scene") == 0) { + arg++; + if (arg <= argc) { + intparam = atoi(argv[arg]); + execinfo->start_scene = intparam; + if (intparam == 0) { + R_printf(R_STDERR, + "Error: Invalid parameter to '-scene'.\n"); + return -1; + } + } else { + R_printf(R_STDERR, + "Error: '-scene' requires a parameter.\n"); + return -1; + } + } + + if (strcmp(argv[arg], "-gamedir") == 0) { + arg++; + if (arg <= argc) { + + execinfo->game_dir = argv[arg]; + } else { + R_printf(R_STDERR, + "Error: '-gamedir' requires a parameter.\n"); + return -1; + } + } + + if (strcmp(argv[arg], "-noverify") == 0) { + execinfo->no_verify = 1; + } + + if (strcmp(argv[arg], "-nosound") == 0) { + execinfo->no_sound = 1; + } + + if (strcmp(argv[arg], "-nomusic") == 0) { + execinfo->no_music = 1; + } + + if (strcmp(argv[arg], "-windowed") == 0) { + execinfo->windowed = 1; + } + + } + + return 0; + +} + +} // End of namespace Saga diff --git a/saga/console.cpp b/saga/console.cpp new file mode 100644 index 0000000000..5310953f31 --- /dev/null +++ b/saga/console.cpp @@ -0,0 +1,567 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Console module + + Notes: +*/ + +#include "reinherit.h" + +/* + Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "font_mod.h" +#include "cvar_mod.h" +#include "events_mod.h" +#include "gfx_mod.h" + +/* + Begin module +\*--------------------------------------------------------------------------*/ +#include "console_mod.h" +#include "console.h" + +namespace Saga { + +static R_CONSOLEINFO ConInfo = { + + 0, + R_CON_DEFAULTPOS, + R_CON_DEFAULTLINES, + R_CON_DEFAULTCMDS +}; + +static char InputBuf[R_CON_INPUTBUF_LEN]; + +static R_CON_SCROLLBACK ConScrollback; +static R_CON_SCROLLBACK ConHistory; + +static int CV_ConResize = R_CON_DEFAULTPOS; +static int CV_ConDroptime = R_CON_DROPTIME; + +int CON_Register(void) +{ + + CVAR_Register_I(&CV_ConResize, "con_h", + NULL, R_CVAR_NONE, 12, R_CON_DEFAULTPOS); + + CVAR_Register_I(&CV_ConDroptime, "con_droptime", + NULL, R_CVAR_NONE, 0, 5000); + + CVAR_Register_I(&ConInfo.line_max, "con_lines", + NULL, R_CVAR_NONE, 5, 5000); + + return R_SUCCESS; +} + +int CON_Init(void) +{ + return R_SUCCESS; +} + +int CON_Shutdown(void) +{ + + R_printf(R_STDOUT, + "CON_Shutdown(): Deleting console scrollback and command history.\n"); + + CON_DeleteScroll(&ConScrollback); + CON_DeleteScroll(&ConHistory); + + return R_SUCCESS; +} + +int CON_Activate(void) +{ + R_EVENT con_event; + + if (ConInfo.active) { + return R_FAILURE; + } + + con_event.type = R_CONTINUOUS_EVENT; + con_event.code = R_CONSOLE_EVENT | R_NODESTROY; + con_event.op = EVENT_ACTIVATE; + con_event.time = 0; + con_event.duration = CV_ConDroptime; + + EVENT_Queue(&con_event); + + ConInfo.active = 1; + + return R_SUCCESS; +} + +int CON_Deactivate(void) +{ + R_EVENT con_event; + + if (!ConInfo.active) { + return R_FAILURE; + } + + con_event.type = R_CONTINUOUS_EVENT; + con_event.code = R_CONSOLE_EVENT | R_NODESTROY; + con_event.op = EVENT_DEACTIVATE; + con_event.time = 0; + con_event.duration = CV_ConDroptime; + + EVENT_Queue(&con_event); + + return R_SUCCESS; +} + +int CON_IsActive(void) +{ + + return ConInfo.active; +} + +int CON_Type(int in_char) +/****************************************************************************\ + Responsible for processing character input to the console and maintaining + the console input buffer. + Input buffer is processed by EXPR_Parse on enter. + High ASCII characters are ignored. +\****************************************************************************/ +{ + + int input_pos = ConInfo.input_pos; + const char *expr; + int expr_len; + int result; + /*char *lvalue; */ + + char *rvalue = NULL; + R_CVAR_P con_cvar = NULL; + + char *expr_err; + char *err_str; + + if (ConInfo.y_pos != ConInfo.y_max) { + /* Ignore keypress until console fully down */ + return R_SUCCESS; + } + + if ((in_char > 127) || (!in_char)) { + /* Ignore non-ascii codes */ + return R_SUCCESS; + } + + switch (in_char) { + + case '\r': + + expr = ConInfo.input_buf; + CON_Print("> %s", ConInfo.input_buf); + + expr_len = strlen(ConInfo.input_buf); + result = EXPR_Parse(&expr, &expr_len, &con_cvar, &rvalue); + + CON_AddLine(&ConHistory, ConInfo.hist_max, ConInfo.input_buf); + + memset(ConInfo.input_buf, 0, R_CON_INPUTBUF_LEN); + ConInfo.input_pos = 0; + ConInfo.hist_pos = 0; + if (result != R_SUCCESS) { + EXPR_GetError(&expr_err); + CON_Print("Parse error: %s", expr_err); + break; + } + + if (rvalue == NULL) { + CVAR_Print(con_cvar); + break; + } + + if (CVAR_IsFunc(con_cvar)) { + CVAR_Exec(con_cvar, rvalue); + } else if (CVAR_SetValue(con_cvar, rvalue) != R_SUCCESS) { + CVAR_GetError(&err_str); + CON_Print("Illegal assignment: %s.", err_str); + } + + break; + + case '\b': + ConInfo.input_buf[input_pos] = 0; + + if (input_pos > 0) { + ConInfo.input_pos--; + ConInfo.input_buf[ConInfo.input_pos] = 0; + } + break; + + default: + if (input_pos < R_CON_INPUTBUF_LEN) { + ConInfo.input_buf[input_pos] = (char)in_char; + ConInfo.input_pos++; + } + break; + } + + if (rvalue) + free(rvalue); + + return R_SUCCESS; +} + +int CON_Draw(R_SURFACE * ds) +{ + + int line_y; + + R_CONSOLE_LINE *walk_ptr; + R_CONSOLE_LINE *start_ptr; + + int txt_fgcolor; + int txt_shcolor; + + R_RECT fill_rect; + + int i; + + if (!ConInfo.active) { + return R_FAILURE; + } + + if (CV_ConResize != ConInfo.y_max) { + ConInfo.y_max = CV_ConResize; + ConInfo.y_pos = CV_ConResize; + } + + fill_rect.x1 = 0; + fill_rect.y1 = 0; + + fill_rect.x2 = ds->buf_w - 1; + fill_rect.y2 = ConInfo.y_pos; + + GFX_DrawRect(ds, &fill_rect, SYSGFX_MatchColor(R_CONSOLE_BGCOLOR)); + + txt_fgcolor = SYSGFX_MatchColor(R_CONSOLE_TXTCOLOR); + txt_shcolor = SYSGFX_MatchColor(R_CONSOLE_TXTSHADOW); + + FONT_Draw(SMALL_FONT_ID, + ds, + ">", 1, + 2, ConInfo.y_pos - 10, txt_fgcolor, txt_shcolor, FONT_SHADOW); + + FONT_Draw(SMALL_FONT_ID, + ds, + ConInfo.input_buf, strlen(ConInfo.input_buf), + 10, ConInfo.y_pos - 10, txt_fgcolor, txt_shcolor, FONT_SHADOW); + + line_y = ConInfo.y_pos - (R_CON_INPUT_H + R_CON_LINE_H); + + start_ptr = ConScrollback.head; + + for (i = 0; i < ConInfo.line_pos; i++) { + if (start_ptr->next) { + start_ptr = start_ptr->next; + } else { + break; + } + } + + for (walk_ptr = start_ptr; walk_ptr; walk_ptr = walk_ptr->next) { + + FONT_Draw(SMALL_FONT_ID, + ds, + walk_ptr->str_p, + walk_ptr->str_len, + 2, line_y, txt_fgcolor, txt_shcolor, FONT_SHADOW); + + line_y -= R_CON_LINE_H; + + if (line_y < -R_CON_LINE_H) + break; + } + + return R_SUCCESS; +} + +int CON_Print(const char *fmt_str, ...) +{ + + char vsstr_p[R_CON_PRINTFLIMIT + 1]; + va_list argptr; + int ret_val; + + va_start(argptr, fmt_str); + + ret_val = vsprintf(vsstr_p, fmt_str, argptr); + + CON_AddLine(&ConScrollback, ConInfo.line_max, vsstr_p); + + va_end(argptr); + + ConInfo.line_pos = 0; + + return ret_val; +} + +int CON_CmdUp(void) +{ + + R_CONSOLE_LINE *start_ptr = ConHistory.head; + int i; + + if (!start_ptr) { + return R_SUCCESS; + } + + if (ConInfo.hist_pos < ConHistory.lines) { + ConInfo.hist_pos++; + } + + for (i = 1; (i < ConInfo.hist_pos); i++) { + if (start_ptr->next) { + start_ptr = start_ptr->next; + } else { + break; + } + } + + memset(ConInfo.input_buf, 0, R_CON_INPUTBUF_LEN); + strcpy(ConInfo.input_buf, start_ptr->str_p); + ConInfo.input_pos = start_ptr->str_len - 1; + + R_printf(R_STDOUT, "History pos: %d/%d", ConInfo.hist_pos, + ConHistory.lines); + + return R_SUCCESS; +} + +int CON_CmdDown(void) +{ + + R_CONSOLE_LINE *start_ptr = ConHistory.head; + int i; + + if (ConInfo.hist_pos == 1) { + R_printf(R_STDOUT, "Erased input buffer."); + memset(ConInfo.input_buf, 0, R_CON_INPUTBUF_LEN); + ConInfo.input_pos = 0; + ConInfo.hist_pos--; + return R_SUCCESS; + } else if (ConInfo.hist_pos) { + ConInfo.hist_pos--; + } else { + return R_SUCCESS; + } + + for (i = 1; i < ConInfo.hist_pos; i++) { + if (start_ptr->next) { + start_ptr = start_ptr->next; + } else { + break; + } + } + + memset(ConInfo.input_buf, 0, R_CON_INPUTBUF_LEN); + strcpy(ConInfo.input_buf, start_ptr->str_p); + ConInfo.input_pos = start_ptr->str_len - 1; + + R_printf(R_STDOUT, "History pos: %d/%d", ConInfo.hist_pos, + ConHistory.lines); + + return R_SUCCESS; +} + +int CON_PageUp(void) +{ + + int n_lines; + + n_lines = (ConInfo.y_max - R_CON_INPUT_H) / R_CON_LINE_H; + + if (ConInfo.line_pos < (ConScrollback.lines - n_lines)) { + ConInfo.line_pos += n_lines; + } + + R_printf(R_STDOUT, "Line pos: %d", ConInfo.line_pos); + + return R_SUCCESS; +} + +int CON_PageDown(void) +{ + + int n_lines; + + n_lines = (ConInfo.y_max - R_CON_INPUT_H) / R_CON_LINE_H; + + if (ConInfo.line_pos > n_lines) { + ConInfo.line_pos -= n_lines; + } else { + ConInfo.line_pos = 0; + } + + return R_SUCCESS; +} + +int CON_DropConsole(double percent) +{ + + R_SURFACE *back_buf; + + if (percent > 1.0) { + percent = 1.0; + } + + back_buf = SYSGFX_GetBackBuffer(); + CON_SetDropPos(percent); + + CON_Draw(back_buf); + + return R_SUCCESS; +} + +int CON_RaiseConsole(double percent) +{ + + R_SURFACE *back_buf; + + if (percent >= 1.0) { + percent = 1.0; + ConInfo.active = 0; + } + + back_buf = SYSGFX_GetBackBuffer(); + + CON_SetDropPos(1.0 - percent); + + CON_Draw(back_buf); + + return R_SUCCESS; +} + +static int CON_SetDropPos(double percent) +{ + + double exp_percent; + + if (percent > 1.0) + percent = 1.0; + if (percent < 0.0) + percent = 0.0; + + exp_percent = percent * percent; + + ConInfo.y_pos = (int)(ConInfo.y_max * exp_percent); + + return R_SUCCESS; +} + +static int +CON_AddLine(R_CON_SCROLLBACK * scroll, int line_max, const char *constr_p) +{ + + int constr_len; + char *newstr_p; + R_CONSOLE_LINE *newline_p; + int del_lines; + int i; + + constr_len = strlen(constr_p) + 1; + + newstr_p = (char *)malloc(constr_len); + if (newstr_p == NULL) { + return R_MEM; + } + + newline_p = (R_CONSOLE_LINE *)malloc(sizeof(R_CONSOLE_LINE)); + if (newline_p == NULL) { + return R_MEM; + } + newline_p->next = NULL; + newline_p->prev = NULL; + + strcpy(newstr_p, constr_p); + newline_p->str_p = newstr_p; + newline_p->str_len = constr_len; + + if (scroll->head == NULL) { + scroll->head = newline_p; + scroll->tail = newline_p; + } else { + scroll->head->prev = newline_p; + newline_p->next = scroll->head; + scroll->head = newline_p; + } + + scroll->lines++; + + if (scroll->lines > line_max) { + del_lines = scroll->lines - line_max; + + for (i = 0; i < del_lines; i++) { + CON_DeleteLine(scroll); + } + } + + return R_SUCCESS; +} + +static int CON_DeleteLine(R_CON_SCROLLBACK * scroll) +{ + + R_CONSOLE_LINE *temp_p = scroll->tail; + + if (temp_p->prev == NULL) { + scroll->head = NULL; + scroll->tail = NULL; + } else { + temp_p->prev->next = NULL; + scroll->tail = temp_p->prev; + } + + if (temp_p->str_p) + free(temp_p->str_p); + free(temp_p); + scroll->lines--; + + return R_SUCCESS; +} + +static int CON_DeleteScroll(R_CON_SCROLLBACK * scroll) +{ + + R_CONSOLE_LINE *walk_ptr; + R_CONSOLE_LINE *temp_ptr; + + for (walk_ptr = scroll->head; walk_ptr; walk_ptr = temp_ptr) { + + if (walk_ptr->str_p) + free(walk_ptr->str_p); + temp_ptr = walk_ptr->next; + free(walk_ptr); + } + + return R_SUCCESS; +} + +} // End of namespace Saga diff --git a/saga/console.h b/saga/console.h new file mode 100644 index 0000000000..12a0b7ebf7 --- /dev/null +++ b/saga/console.h @@ -0,0 +1,96 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Console module header file + + Notes: +*/ + +#ifndef SAGA_CONSOLE_H_ +#define SAGA_CONSOLE_H_ + +namespace Saga { + +#define R_CON_INPUTBUF_LEN 80 + +#define R_CONSOLE_BGCOLOR 0x00A0A0A0UL +#define R_CONSOLE_TXTCOLOR 0x00FFFFFFUL +#define R_CONSOLE_TXTSHADOW 0x00202020UL + +typedef struct R_CONSOLEINFO_tag { + + int active; + int y_max; + int line_max; + int hist_max; + int hist_pos; + int line_pos; + int y_pos; + char *prompt; + int prompt_w; + char input_buf[R_CON_INPUTBUF_LEN + 1]; + int input_pos; + +} R_CONSOLEINFO; + +typedef struct R_CONSOLE_LINE_tag { + + struct R_CONSOLE_LINE_tag *next; + struct R_CONSOLE_LINE_tag *prev; + char *str_p; + int str_len; + +} R_CONSOLE_LINE; + +typedef struct R_CON_SCROLLBACK_tag { + + struct R_CONSOLE_LINE_tag *head; + struct R_CONSOLE_LINE_tag *tail; + int lines; + +} R_CON_SCROLLBACK; + +static int +CON_AddLine(R_CON_SCROLLBACK * scroll, int line_max, const char *constr_p); + +static int CON_DeleteLine(R_CON_SCROLLBACK * scroll); + +static int CON_DeleteScroll(R_CON_SCROLLBACK * scroll); + +static int CON_SetDropPos(double percent); + +#define R_CON_DEFAULTPOS 136 +#define R_CON_DEFAULTLINES 100 +#define R_CON_DEFAULTCMDS 10 +#define R_CON_DROPTIME 400 +#define R_CON_PRINTFLIMIT 1024 +#define R_CON_LINE_H 10 +#define R_CON_INPUT_H 10 + +} // End of namespace Saga + +#endif /* R_CONSOLE_H_ */ + +/* end "r_console.h" */ diff --git a/saga/console_mod.h b/saga/console_mod.h new file mode 100644 index 0000000000..62ec7efd48 --- /dev/null +++ b/saga/console_mod.h @@ -0,0 +1,59 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Console module public header file + + Notes: +*/ + +#ifndef SAGA_CONSOLE_MOD_H_ +#define SAGA_CONSOLE_MOD_H_ + +namespace Saga { + +int CON_Register(void); +int CON_Init(void); +int CON_Shutdown(void); + +int CON_Activate(void); +int CON_Deactivate(void); +int CON_IsActive(void); + +int CON_Type(int in_char); +int CON_Draw(R_SURFACE * ds); +int CON_Print(const char *fmt_str, ...); + +int CON_CmdUp(void); +int CON_CmdDown(void); +int CON_PageUp(void); +int CON_PageDown(void); + +int CON_DropConsole(double percent); +int CON_RaiseConsole(double percent); + +} // End of namespace Saga + +#endif /* R_CONSOLE_MOD_H_ */ +/* end "r_console_mod.h" */ diff --git a/saga/cvar.cpp b/saga/cvar.cpp new file mode 100644 index 0000000000..5f69faf3a9 --- /dev/null +++ b/saga/cvar.cpp @@ -0,0 +1,612 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Configuration Variable Module + + Notes: +*/ + +#include "reinherit.h" + +#include <limits.h> +#include <stddef.h> + +/* + Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "console_mod.h" + +/* + Begin module +\*--------------------------------------------------------------------------*/ +#include "cvar_mod.h" +#include "cvar.h" + +namespace Saga { + +R_CVAR *CVHashTbl[R_CVAR_HASHLEN]; + +char *CVAR_ErrMsg[] = { + + "No Error", + "Not implememented.", + "Memory allocation failed", + "Value overflowed while parsing", + "Invalid numeric constant", + "Value overflows destination type", + "Assignment of negative value to unsigned variable", + "Value outside of specified bounds", + "Invalid string literal", + "Invalid type for assignment", + "Variable is read-only", + "Not a valid function" +}; + +enum CVAR_Errors { + + CVERR_NONE, + CVERR_NOTIMPL, + CVERR_MEM, + CVERR_PARSEOVERFLOW, + CVERR_INVALID, + CVERR_DESTOVERFLOW, + CVERR_SIGN, + CVERR_BOUND, + CVERR_STRING, + CVERR_TYPE, + CVERR_READONLY, + CVERR_NOTFUNC +}; + +static enum CVAR_Errors CVAR_ErrorState; + +int CVAR_GetError(char **err_str) +/****************************************************************************\ + Returns the appropriate cvar error string +\****************************************************************************/ +{ + + *err_str = CVAR_ErrMsg[CVAR_ErrorState]; + + return CVAR_ErrorState; +} + +int CVAR_Shutdown(void) +/****************************************************************************\ + Frees the cvar hash table +\****************************************************************************/ +{ + + R_CVAR *walk_ptr; + R_CVAR *temp_ptr; + int i; + + R_printf(R_STDOUT, "CVAR_Shutdown(): Deleting cvar hash table.\n"); + + for (i = 0; i < R_CVAR_HASHLEN; i++) { + + for (walk_ptr = CVHashTbl[i]; walk_ptr; walk_ptr = temp_ptr) { + + temp_ptr = walk_ptr->next; + free(walk_ptr); + } + } + + return R_SUCCESS; +} + +unsigned int CVAR_HashString(const char *str) +/****************************************************************************\ + Returns hash index for string 'str'. + Cannot fail. +\****************************************************************************/ +{ + + unsigned int index; + + for (index = 0; *str != '\0'; str++) { + index = *str + 31 * index; + } + + return index % R_CVAR_HASHLEN; +} + +int CVAR_Add(int index, R_CVAR * cvar) +/****************************************************************************\ + Adds a copy of the given cvar into the hash table. + Returns R_SUCCESS if cvar was added, R_MEM if allocation failed. +\****************************************************************************/ +{ + + R_CVAR *new_cvar; + R_CVAR *temp_ptr; + + new_cvar = (R_CVAR *)malloc(sizeof(R_CVAR)); + + if (new_cvar == NULL) { + CVAR_ErrorState = CVERR_MEM; + return R_MEM; + } + + memcpy(new_cvar, cvar, sizeof(R_CVAR)); + + if (CVHashTbl[index] == NULL) { + CVHashTbl[index] = new_cvar; + new_cvar->next = NULL; + } else { + temp_ptr = CVHashTbl[index]; + CVHashTbl[index] = new_cvar; + new_cvar->next = temp_ptr; + } + + CVAR_ErrorState = CVERR_NONE; + return R_SUCCESS; +} + +int CVAR_Exec(R_CVAR_P cvar_func, char *r_value) +/****************************************************************************\ + Attempts to execute the specified console function with the given argument + string. + Returns R_FAILURE if cvar_func is not a valid console function +\****************************************************************************/ +{ + + int cf_argc = 0; + char **cf_argv = NULL; + int max_args; + + if (cvar_func->type != R_CVAR_FUNC) { + CVAR_ErrorState = CVERR_NOTFUNC; + return R_FAILURE; + } + + cf_argc = EXPR_GetArgs(r_value, &cf_argv); + + if (cf_argc < cvar_func->t.func.min_args) { + CON_Print("Too few arguments to function."); + if (cf_argv) + free(cf_argv); + return R_FAILURE; + } + + max_args = cvar_func->t.func.max_args; + if ((max_args > -1) && (cf_argc > max_args)) { + CON_Print("Too many arguments to function."); + if (cf_argv) + free(cf_argv); + return R_FAILURE; + } + + /* Call function */ + (cvar_func->t.func.func_p) (cf_argc, cf_argv); + + if (cf_argv) + free(cf_argv); + + return R_SUCCESS; +} + +int CVAR_SetValue(R_CVAR_P cvar, char *r_value) +/****************************************************************************\ + Attempts to assign the value contained in the string 'r_value' to cvar. + Returns R_FAILURE if there was an error parsing 'r_value' +\****************************************************************************/ +{ + + long int int_param; + unsigned long uint_param; + + char *end_p; + ptrdiff_t scan_len; + int r_value_len; + + r_value_len = strlen(r_value); + + if (cvar->flags & R_CVAR_READONLY) { + CVAR_ErrorState = CVERR_READONLY; + return R_FAILURE; + } + + switch (cvar->type) { + + case R_CVAR_INT: + + int_param = strtol(r_value, &end_p, 10); + + if ((int_param == LONG_MIN) || (int_param == LONG_MAX)) { + CVAR_ErrorState = CVERR_PARSEOVERFLOW; + return R_FAILURE; + } + + scan_len = end_p - r_value; + + if (int_param == 0) { + if (!scan_len || r_value[scan_len - 1] != '0') { + /* strtol() returned 0, but string isn't "0". Invalid. */ + CVAR_ErrorState = CVERR_INVALID; + return R_FAILURE; + } + } + + if (scan_len != r_value_len) { + /* Entire string wasn't converted...Invalid */ + CVAR_ErrorState = CVERR_INVALID; + return R_FAILURE; + } + + if ((int_param < CV_INTMIN) || (int_param > CV_INTMAX)) { + /* Overflows destination type */ + CVAR_ErrorState = CVERR_DESTOVERFLOW; + return R_FAILURE; + } + + /* Ignore bounds if equal */ + if (cvar->t.i.lbound != cvar->t.i.ubound) { + + if ((int_param < cvar->t.i.lbound) || + (int_param > cvar->t.i.ubound)) { + /* Value is outside of cvar bounds */ + CVAR_ErrorState = CVERR_BOUND; + return R_FAILURE; + } + } + + *(cvar->t.i.var_p) = (cv_int_t) int_param; + +#ifdef R_CVAR_TRACE + printf("Set cvar to value %ld.\n", int_param); +#endif + + break; + + case R_CVAR_UINT: + + if (*r_value == '-') { + CVAR_ErrorState = CVERR_SIGN; + return R_FAILURE; + } + + uint_param = strtoul(r_value, &end_p, 10); + + if (uint_param == ULONG_MAX) { + CVAR_ErrorState = CVERR_PARSEOVERFLOW; + return R_FAILURE; + } + + scan_len = end_p - r_value; + + if (uint_param == 0) { + + if (!scan_len || r_value[scan_len - 1] != '0') { + /* strtol() returned 0, but string isn't "0". Invalid. */ + CVAR_ErrorState = CVERR_INVALID; + return R_FAILURE; + } + } + + if (scan_len != r_value_len) { + /* Entire string wasn't converted...Invalid */ + CVAR_ErrorState = CVERR_INVALID; + return R_FAILURE; + } + + if (uint_param > CV_UINTMAX) { + /* Overflows destination type */ + CVAR_ErrorState = CVERR_DESTOVERFLOW; + return R_FAILURE; + } + + /* Ignore bounds if equal */ + if (cvar->t.ui.lbound != cvar->t.ui.ubound) { + + if ((uint_param < cvar->t.ui.lbound) || + (uint_param > cvar->t.ui.ubound)) { + /* Value is outside cvar bounds */ + CVAR_ErrorState = CVERR_BOUND; + return R_FAILURE; + } + } + + *(cvar->t.ui.var_p) = (cv_uint_t) uint_param; + +#ifdef R_CVAR_TRACE + printf("Set cvar to value %lu.\n", uint_param); +#endif + + break; + + case R_CVAR_FLOAT: + + CVAR_ErrorState = CVERR_NOTIMPL; + return R_FAILURE; + break; + + case R_CVAR_STRING: + + if (strrchr(r_value, '\"') != NULL) { + CVAR_ErrorState = CVERR_STRING; + return R_FAILURE; + } + + strncpy(cvar->t.s.var_str, r_value, cvar->t.s.ubound); + if (cvar->t.s.ubound < r_value_len) { + cvar->t.s.var_str[cvar->t.s.ubound] = 0; + } +#ifdef R_CVAR_TRACE + printf("Set cvar to value \"%s\".\n", cvar->t.s.var_str); +#endif + + break; + + default: + + CVAR_ErrorState = CVERR_TYPE; + return R_FAILURE; + break; + } + + CVAR_ErrorState = CVERR_NONE; + return R_SUCCESS; +} + +R_CVAR_P CVAR_Find(const char *var_str) +/****************************************************************************\ + Given a cvar name this function returns a pointer to the appropriate + cvar structure or NULL if no match was found. +\****************************************************************************/ +{ + + R_CVAR *walk_ptr; + int hash; + + hash = CVAR_HashString(var_str); + +#ifdef R_CVAR_TRACE + printf("Performing lookup on hash bucket %d.\n", hash); +#endif + + walk_ptr = CVHashTbl[hash]; + + while (walk_ptr != NULL) { + + if (strcmp(var_str, walk_ptr->name) == 0) { + return walk_ptr; + } + + walk_ptr = walk_ptr->next; + } + + return NULL; +} + +int CVAR_IsFunc(R_CVAR_P cvar_func) +{ + + if (cvar_func->type == R_CVAR_FUNC) + return 1; + else + return 0; +} + +int +CVAR_RegisterFunc(cv_func_t func, + const char *func_name, + const char *func_argstr, uint flags, int min_args, int max_args) +/****************************************************************************\ + Registers a console function 'cvar' + (could think of a better place to put these...?) +\****************************************************************************/ +{ + + R_CVAR new_cvar; + int hash; + + new_cvar.name = func_name; + new_cvar.type = R_CVAR_FUNC; + new_cvar.section = NULL; + new_cvar.flags = flags; + + new_cvar.t.func.func_p = func; + new_cvar.t.func.func_argstr = func_argstr; + new_cvar.t.func.min_args = min_args; + new_cvar.t.func.max_args = max_args; + hash = CVAR_HashString(func_name); + +#ifdef R_CVAR_TRACE + printf("Added FUNC cvar to hash bucket %d.\n", hash); +#endif + + return CVAR_Add(hash, &new_cvar); +} + +int +CVAR_Register_I(cv_int_t * var_p, + const char *var_name, + const char *section, uint flags, cv_int_t lbound, cv_int_t ubound) +/****************************************************************************\ + Registers an integer type cvar. +\****************************************************************************/ +{ + + R_CVAR new_cvar; + int hash; + + new_cvar.name = var_name; + new_cvar.type = R_CVAR_INT; + new_cvar.section = section; + new_cvar.flags = flags; + + new_cvar.t.i.var_p = var_p; + + new_cvar.t.i.lbound = lbound; + new_cvar.t.i.ubound = ubound; + + hash = CVAR_HashString(var_name); + +#ifdef R_CVAR_TRACE + printf("Added INT cvar to hash bucket %d.\n", hash); +#endif + + return CVAR_Add(hash, &new_cvar); +} + +int +CVAR_Register_UI(cv_uint_t * var_p, + const char *var_name, + const char *section, uint flags, cv_uint_t lbound, cv_uint_t ubound) +/****************************************************************************\ + Registers an unsigned integer type cvar. +\****************************************************************************/ +{ + + R_CVAR new_cvar; + int hash; + + new_cvar.name = var_name; + new_cvar.type = R_CVAR_UINT; + new_cvar.section = section; + new_cvar.flags = flags; + + new_cvar.t.ui.var_p = var_p; + + new_cvar.t.ui.lbound = lbound; + new_cvar.t.ui.ubound = ubound; + + hash = CVAR_HashString(var_name); + +#ifdef R_CVAR_TRACE + printf("Added UNSIGNED INT ccvar to hash bucket %d.\n", hash); +#endif + + return CVAR_Add(hash, &new_cvar); +} + +int +CVAR_Register_F(cv_float_t * var_p, + const char *var_name, + const char *section, uint flags, cv_float_t lbound, cv_float_t ubound) +/****************************************************************************\ + Registers a floating point type cvar. +\****************************************************************************/ +{ + + R_CVAR new_cvar; + int hash; + + new_cvar.name = var_name; + new_cvar.type = R_CVAR_FLOAT; + new_cvar.section = section; + new_cvar.flags = flags; + + new_cvar.t.f.var_p = var_p; + + new_cvar.t.f.lbound = lbound; + new_cvar.t.f.ubound = ubound; + + hash = CVAR_HashString(var_name); + +#ifdef R_CVAR_TRACE + printf("Added FLOAT cvar to hash bucket %d.\n", hash); +#endif + + return CVAR_Add(hash, &new_cvar); +} + +int +CVAR_Register_S(cv_char_t * var_str, + const char *var_name, const char *section, uint flags, int ubound) +/****************************************************************************\ + Registers a string type cvar. Storage must be provided in var_p for 'ubound' + characters plus 1 for NUL char. +\****************************************************************************/ +{ + + R_CVAR new_cvar; + int hash; + + new_cvar.name = var_name; + new_cvar.type = R_CVAR_STRING; + new_cvar.section = section; + new_cvar.flags = flags; + + new_cvar.t.s.var_str = var_str; + new_cvar.t.s.ubound = ubound; + + hash = CVAR_HashString(var_name); + +#ifdef R_CVAR_TRACE + printf("Added UNSIGNED INT var to hash bucket %d.\n", hash); +#endif + + return CVAR_Add(hash, &new_cvar); +} + +int CVAR_Print(R_CVAR_P con_cvar) +/****************************************************************************\ + Displays the value and type of the given cvar to the console. +\****************************************************************************/ +{ + + switch (con_cvar->type) { + + case R_CVAR_INT: + CON_Print("\"%s\"(i) = %d", + con_cvar->name, *(con_cvar->t.i.var_p)); + break; + + case R_CVAR_UINT: + CON_Print("\"%s\"(ui) = %u", + con_cvar->name, *(con_cvar->t.ui.var_p)); + break; + + case R_CVAR_FLOAT: + CON_Print("\"%s\"(ui) = %f", + con_cvar->name, *(con_cvar->t.f.var_p)); + break; + + case R_CVAR_STRING: + CON_Print("\"%s\"(s) = \"%s\"", con_cvar->name, + con_cvar->t.s.var_str); + break; + + case R_CVAR_FUNC: + if (con_cvar->t.func.func_argstr) { + CON_Print("\"%s\"(func) Args: %s", con_cvar->name, + con_cvar->t.func.func_argstr); + } else { + CON_Print("\"%s\"(func) No arguments.", + con_cvar->name); + } + break; + + default: + CON_Print("Invalid variable type.\n"); + break; + } + + return R_SUCCESS; +} + +} // End of namespace Saga diff --git a/saga/cvar.h b/saga/cvar.h new file mode 100644 index 0000000000..b1009bb21f --- /dev/null +++ b/saga/cvar.h @@ -0,0 +1,100 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Configuration Variable Module + + Notes: +*/ + +#ifndef SAGA_CVAR_H_ +#define SAGA_CVAR_H_ + +namespace Saga { + +#define R_CVAR_HASHLEN 32 + +typedef struct R_SUBCVAR_INT_tag { + + cv_int_t *var_p; + cv_int_t ubound; + cv_int_t lbound; + +} R_SUBCVAR_INT; + +typedef struct R_SUBCVAR_UINT_tag { + + cv_uint_t *var_p; + cv_uint_t ubound; + cv_uint_t lbound; + +} R_SUBCVAR_UINT; + +typedef struct R_SUBCVAR_FLOAT_tag { + + cv_float_t *var_p; + cv_float_t ubound; + cv_float_t lbound; + +} R_SUBCVAR_FLOAT; + +typedef struct R_SUBCVAR_STRING_tag { + + cv_char_t *var_str; + int ubound; + +} R_SUBCVAR_STRING; + +typedef struct R_SUBCVAR_FUNC_tag { + + cv_func_t func_p; + const char *func_argstr; + int min_args; + int max_args; + +} R_SUBCVAR_FUNC; + +typedef struct R_CVAR_tag { + + int type; + const char *name; + const char *section; + uint flags; + + union { + R_SUBCVAR_INT i; + R_SUBCVAR_UINT ui; + R_SUBCVAR_FLOAT f; + R_SUBCVAR_STRING s; + R_SUBCVAR_FUNC func; + } t; + + struct R_CVAR_tag *next; + +} R_CVAR; + +} // End of namespace Saga + +#endif /* R_CVAR_H_ */ +/* end "r_cvar.h" */ diff --git a/saga/cvar_mod.h b/saga/cvar_mod.h new file mode 100644 index 0000000000..a341ff494e --- /dev/null +++ b/saga/cvar_mod.h @@ -0,0 +1,112 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Configuration variable module public header file + + Notes: +*/ + +#ifndef SAGA_CVAR_MOD_H_ +#define SAGA_CVAR_MOD_H_ + +namespace Saga { + +/* Modify these to change base cvar types */ +#define CV_INTMAX INT_MAX +#define CV_INTMIN INT_MIN + +#define CV_UINTMAX UINT_MAX +typedef int cv_int_t; +typedef unsigned int cv_uint_t; +typedef float cv_float_t; +typedef char cv_char_t; +typedef void (*cv_func_t) (int cv_argc, char *cv_argv[]); +/******************************************/ + +typedef struct R_CVAR_tag *R_CVAR_P; /* opaque typedef */ + +typedef enum R_CVAR_TYPES_tag { + + R_CVAR_INVALID, + R_CVAR_INT, + R_CVAR_UINT, + R_CVAR_FLOAT, + R_CVAR_STRING, + R_CVAR_FUNC +} R_CVAR_TYPES; + +typedef enum R_CVAR_FLAGS_tag { + + R_CVAR_NONE, + R_CVAR_READONLY, + R_CVAR_LBOUND, + R_CVAR_UBOUND, + R_CVAR_CFG, + R_CVAR_SECTION +} R_CVAR_FLAGS; + +#define R_CVAR_BOUNDED ( R_CVAR_LBOUND | R_CVAR_UBOUND ) + +int CVAR_Shutdown(void); +R_CVAR_P CVAR_Find(const char *var_str); +int CVAR_SetValue(R_CVAR_P cvar, char *r_value); +int CVAR_Print(R_CVAR_P con_cvar); +int CVAR_GetError(char **err_str); +int CVAR_IsFunc(R_CVAR_P cvar_func); +int CVAR_Exec(R_CVAR_P cvar_func, char *r_value); + +int +CVAR_RegisterFunc(cv_func_t func, + const char *func_name, + const char *func_argstr, uint flags, int min_args, int max_args); + +int CVAR_Register_I(cv_int_t * var_p, + const char *var_name, + const char *section, uint flags, cv_int_t lbound, cv_int_t ubound); + +int CVAR_Register_UI(cv_uint_t * var_p, + const char *var_name, + const char *section, uint flags, cv_uint_t lbound, cv_uint_t ubound); + +int CVAR_Register_F(cv_float_t * var_p, + const char *var_name, + const char *section, uint flags, cv_float_t lbound, cv_float_t ubound); + +int CVAR_Register_S(cv_char_t * var_str, + const char *var_name, const char *section, uint flags, int ubound); + +int EXPR_Parse(const char **exp_pp, int *len, R_CVAR_P * expr_cvar, + char **rvalue); + +char *EXPR_ReadString(const char **string_p, int *len, int term_char); + +int EXPR_GetError(char **err_str); + +int EXPR_GetArgs(char *cmd_str, char ***expr_argv); + +} // End of namespace Saga + +#endif /* R_CVAR_MOD_H_ */ +/* end r_cvar_mod.h_ */ diff --git a/saga/events.cpp b/saga/events.cpp new file mode 100644 index 0000000000..6dcfe4ff06 --- /dev/null +++ b/saga/events.cpp @@ -0,0 +1,613 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Event management module + + Notes: +*/ + +#include "reinherit.h" + +#include "yslib.h" + +/* + * Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "animation_mod.h" +#include "console_mod.h" +#include "scene_mod.h" +#include "gfx_mod.h" +#include "interface_mod.h" +#include "text_mod.h" +#include "palanim_mod.h" +#include "render_mod.h" +#include "sndres_mod.h" + +/* + * Begin module +\*--------------------------------------------------------------------------*/ +#include "events_mod.h" +#include "events.h" + +namespace Saga { + +static YS_DL_LIST *EventList; + +int EVENT_Init(void) +{ + R_printf(R_STDOUT, "Initializing event subsystem...\n"); + + EventList = ys_dll_create(); + + return (EventList != NULL) ? R_SUCCESS : R_FAILURE; +} + +int EVENT_Shutdown(void) +{ + R_printf(R_STDOUT, "Shutting down event subsystem...\n"); + + EVENT_FreeList(); + + return R_SUCCESS; +} + +int EVENT_HandleEvents(long msec) +/*--------------------------------------------------------------------------*\ + * Function to process event list once per frame. + * First advances event times, then processes each event with the appropriate + * handler depending on the type of event. +\*--------------------------------------------------------------------------*/ +{ + YS_DL_NODE *walk_node; + YS_DL_NODE *next_node; + + R_EVENT *event_p; + + long delta_time; + int result; + + /* Advance event times + * \*------------------------------------------------------------- */ + ProcessEventTime(msec); + + /* Process each event in list + * \*------------------------------------------------------------- */ + for (walk_node = ys_dll_head(EventList); + walk_node != NULL; walk_node = next_node) { + + event_p = (R_EVENT *)ys_dll_get_data(walk_node); + + /* Save next event in case current event is handled and removed */ + next_node = ys_dll_next(walk_node); + + /* Call the appropriate event handler for the specific event type */ + switch (event_p->type) { + + case R_ONESHOT_EVENT: + result = HandleOneShot(event_p); + break; + + case R_CONTINUOUS_EVENT: + result = HandleContinuous(event_p); + break; + + case R_INTERVAL_EVENT: + result = HandleInterval(event_p); + break; + + default: + result = R_EVENT_INVALIDCODE; + R_printf(R_STDERR, + "Invalid event code encountered.\n"); + break; + } + + /* Process the event appropriately based on result code from + * handler */ + if ((result == R_EVENT_DELETE) || + (result == R_EVENT_INVALIDCODE)) { + + /* If there is no event chain, delete the base event. */ + if (event_p->chain == NULL) { + ys_dll_delete(walk_node); + } else { + /* If there is an event chain present, move the next event + * in the chain up, adjust it by the previous delta time, + * and reprocess the event by adjusting next_node. */ + delta_time = event_p->time; + + ys_dll_replace(walk_node, event_p->chain, + sizeof *event_p); + + event_p = (R_EVENT *)ys_dll_get_data(walk_node); + event_p->time += delta_time; + + next_node = walk_node; + } + } else if (result == R_EVENT_BREAK) { + + break; + } + + } /* end for () */ + + return R_SUCCESS; +} + +int HandleContinuous(R_EVENT * event) +{ + + double event_pc = 0.0; /* Event completion percentage */ + int event_done = 0; + + R_BUFFER_INFO buf_info; + SCENE_BGINFO bg_info; + R_SURFACE *back_buf; + + event_pc = ((double)event->duration - event->time) / event->duration; + + if (event_pc >= 1.0) { + /* Cap percentage to 100 */ + event_pc = 1.0; + event_done = 1; + } + + if (event_pc < 0.0) { + /* Event not signaled, skip it */ + return R_EVENT_CONTINUE; + } else if (!(event->code & R_SIGNALED)) { + /* Signal event */ + event->code |= R_SIGNALED; + event_pc = 0.0; + } + + switch (event->code & R_EVENT_MASK) { + + case R_PAL_EVENT: + + switch (event->op) { + + case EVENT_BLACKTOPAL: + + back_buf = SYSGFX_GetBackBuffer(); + + SYSGFX_BlackToPal(back_buf, (PALENTRY *)event->data, event_pc); + break; + + case EVENT_PALTOBLACK: + + back_buf = SYSGFX_GetBackBuffer(); + + SYSGFX_PalToBlack(back_buf, (PALENTRY *)event->data, event_pc); + break; + + default: + break; + } /* end switch() */ + + break; + + case R_TRANSITION_EVENT: + + switch (event->op) { + + case EVENT_DISSOLVE: + + RENDER_GetBufferInfo(&buf_info); + SCENE_GetBGInfo(&bg_info); + + TRANSITION_Dissolve(buf_info.r_bg_buf, + buf_info.r_bg_buf_w, + buf_info.r_bg_buf_h, + buf_info.r_bg_buf_w, + bg_info.bg_buf, bg_info.bg_p, 0, event_pc); + + break; + + default: + break; + } + + break; + + case R_CONSOLE_EVENT: + + switch (event->op) { + + case EVENT_ACTIVATE: + + CON_DropConsole(event_pc); + break; + + case EVENT_DEACTIVATE: + + CON_RaiseConsole(event_pc); + break; + + default: + break; + } + + break; + + default: + break; + + } /* end switch( event->event_code ) */ + + if (event_done) { + return R_EVENT_DELETE; + } + + return R_EVENT_CONTINUE; +} + +static int HandleOneShot(R_EVENT * event) +{ + + R_SURFACE *back_buf; + + static SCENE_BGINFO bginfo; + + if (event->time > 0) { + return R_EVENT_CONTINUE; + } + + /* Event has been signaled */ + + switch (event->code & R_EVENT_MASK) { + + case R_TEXT_EVENT: + + switch (event->op) { + + case EVENT_DISPLAY: + + TEXT_SetDisplay((R_TEXTLIST_ENTRY *)event->data, 1); + break; + + case EVENT_REMOVE: + { + R_SCENE_INFO scene_info; + + SCENE_GetInfo(&scene_info); + + TEXT_DeleteEntry(scene_info.text_list, + (R_TEXTLIST_ENTRY *)event->data); + } + break; + + default: + break; + } + + break; + + case R_VOICE_EVENT: + + SND_PlayVoice(event->param); + break; + + case R_MUSIC_EVENT: + + SYSMUSIC_Play(event->param, event->param2); + break; + + case R_BG_EVENT: + { + R_BUFFER_INFO rbuf_info; + R_POINT bg_pt; + + if (SCENE_GetMode() == R_SCENE_MODE_NORMAL) { + + back_buf = SYSGFX_GetBackBuffer(); + + RENDER_GetBufferInfo(&rbuf_info); + SCENE_GetBGInfo(&bginfo); + + bg_pt.x = bginfo.bg_x; + bg_pt.y = bginfo.bg_y; + + GFX_BufToBuffer(rbuf_info.r_bg_buf, + rbuf_info.r_bg_buf_w, + rbuf_info.r_bg_buf_h, + bginfo.bg_buf, + bginfo.bg_w, bginfo.bg_h, NULL, &bg_pt); + + if (event->param == SET_PALETTE) { + + PALENTRY *pal_p; + + SCENE_GetBGPal(&pal_p); + SYSGFX_SetPalette(back_buf, pal_p); + } + } + } + break; + + case R_ANIM_EVENT: + + switch (event->op) { + + case EVENT_FRAME: + + ANIM_Play(event->param, event->time); + break; + + default: + break; + } + + break; + + case R_SCENE_EVENT: + + switch (event->op) { + + case EVENT_END: + + SCENE_Next(); + + return R_EVENT_BREAK; + break; + + default: + break; + } + + break; + + case R_PALANIM_EVENT: + + switch (event->op) { + + case EVENT_CYCLESTART: + + PALANIM_CycleStart(); + break; + + case EVENT_CYCLESTEP: + + PALANIM_CycleStep(event->time); + break; + + default: + break; + } + break; + + case R_INTERFACE_EVENT: + + switch (event->op) { + + case EVENT_ACTIVATE: + + INTERFACE_Activate(); + break; + + default: + break; + } + + break; + + default: + break; + + } /* end switch( event->code ) */ + + return R_EVENT_DELETE; +} + +static int HandleInterval(R_EVENT * event) +{ + YS_IGNORE_PARAM(event); + + return R_EVENT_DELETE; +} + +R_EVENT *EVENT_Queue(R_EVENT * event) +/*--------------------------------------------------------------------------*\ + * Schedules an event in the event list; returns a pointer to the scheduled + * event suitable for chaining if desired. +\*--------------------------------------------------------------------------*/ +{ + YS_DL_NODE *new_node; + R_EVENT *queued_event; + + event->chain = NULL; + + new_node = ys_dll_add_tail(EventList, event, sizeof *event); + + if (new_node == NULL) { + return NULL; + } + + queued_event = (R_EVENT *)ys_dll_get_data(new_node); + + InitializeEvent(queued_event); + + return queued_event; +} + +R_EVENT *EVENT_Chain(R_EVENT * head_event, R_EVENT * add_event) +/*--------------------------------------------------------------------------*\ + * Places a 'add_event' on the end of an event chain given by 'head_event' + * (head_event may be in any position in the event chain) +\*--------------------------------------------------------------------------*/ +{ + R_EVENT *walk_event; + R_EVENT *new_event; + + /* Allocate space for new event */ + new_event = (R_EVENT *)malloc(sizeof *new_event); + if (new_event == NULL) { + return NULL; + } + + /* Copy event data to new event */ + *new_event = *add_event; + + /* Walk to end of chain */ + for (walk_event = head_event; + walk_event->chain != NULL; walk_event = walk_event->chain) { + + continue; + } + + /* Place new event */ + walk_event->chain = new_event; + new_event->chain = NULL; + + InitializeEvent(new_event); + + return new_event; +} + +static int InitializeEvent(R_EVENT * event) +{ + + switch (event->type) { + + case R_ONESHOT_EVENT: + break; + + case R_CONTINUOUS_EVENT: + event->time += event->duration; + break; + + case R_INTERVAL_EVENT: + break; + + default: + return R_FAILURE; + break; + } + + return R_SUCCESS; +} + +int EVENT_ClearList(void) +/*--------------------------------------------------------------------------*\ + * Removes all events from the list except NODESTROY (engine) events +\*--------------------------------------------------------------------------*/ +{ + YS_DL_NODE *walk_node; + YS_DL_NODE *next_node; + + struct R_EVENT_tag *chain_walk; + struct R_EVENT_tag *next_chain; + + R_EVENT *event_p; + + /* Walk down event list */ + for (walk_node = ys_dll_head(EventList); + walk_node != NULL; walk_node = next_node) { + + next_node = ys_dll_next(walk_node); + event_p = (R_EVENT *)ys_dll_get_data(walk_node); + + /* Only remove events not marked R_NODESTROY (engine events) */ + if (!(event_p->code & R_NODESTROY)) { + + /* Remove any events chained off this one */ + for (chain_walk = event_p->chain; + chain_walk != NULL; chain_walk = next_chain) { + + next_chain = chain_walk->chain; + free(chain_walk); + } + + ys_dll_delete(walk_node); + } + } + + return R_SUCCESS; +} + +int EVENT_FreeList(void) +/*--------------------------------------------------------------------------*\ + * Removes all events from the list (even R_NODESTROY) +\*--------------------------------------------------------------------------*/ +{ + YS_DL_NODE *walk_node; + YS_DL_NODE *next_node; + + struct R_EVENT_tag *chain_walk; + struct R_EVENT_tag *next_chain; + + R_EVENT *event_p; + + /* Walk down event list */ + for (walk_node = ys_dll_head(EventList); + walk_node != NULL; walk_node = next_node) { + + event_p = (R_EVENT *)ys_dll_get_data(walk_node); + + /* Remove any events chained off current node */ + for (chain_walk = event_p->chain; + chain_walk != NULL; chain_walk = next_chain) { + + next_chain = chain_walk->chain; + free(chain_walk); + } + + /* Delete current node */ + next_node = ys_dll_next(walk_node); + ys_dll_delete(walk_node); + } + + return R_SUCCESS; +} + +static int ProcessEventTime(long msec) +/*--------------------------------------------------------------------------*\ + * Walks down the event list, updating event times by 'msec'. +\*--------------------------------------------------------------------------*/ +{ + YS_DL_NODE *walk_node; + R_EVENT *event_p; + + uint event_count = 0; + + for (walk_node = ys_dll_head(EventList); + walk_node != NULL; walk_node = ys_dll_next(walk_node)) { + + event_p = (R_EVENT *)ys_dll_get_data(walk_node); + event_p->time -= msec; + + event_count++; + + if (event_count > R_EVENT_WARNINGCOUNT) { + R_printf(R_STDERR, + "WARNING: Event list exceeds %u.\n"); + } + } + + return R_SUCCESS; +} + +} // End of namespace Saga diff --git a/saga/events.h b/saga/events.h new file mode 100644 index 0000000000..75c670db2f --- /dev/null +++ b/saga/events.h @@ -0,0 +1,63 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Event management module header file + + Notes: +*/ + +#ifndef SAGA_EVENT_H +#define SAGA_EVENT_H + +namespace Saga { + +#define R_EVENT_DBGLVL R_DEBUG_NONE + +#define R_EVENT_WARNINGCOUNT 1000 + +#define R_EVENT_MASK 0x00FF + +enum R_EVENT_STATUSCODE { + + R_EVENT_INVALIDCODE = 0, + R_EVENT_DELETE, + R_EVENT_CONTINUE, + R_EVENT_BREAK +}; + +static int HandleContinuous(R_EVENT * event); + +static int HandleOneShot(R_EVENT * event); + +static int HandleInterval(R_EVENT * event); + +static int ProcessEventTime(long msec); + +static int InitializeEvent(R_EVENT * event); + +} // End of namespace Saga + +#endif /* R_EVENT_H */ diff --git a/saga/events_mod.h b/saga/events_mod.h new file mode 100644 index 0000000000..e086d37c2d --- /dev/null +++ b/saga/events_mod.h @@ -0,0 +1,143 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Event module public header + + Notes: +*/ + +#ifndef SAGA_EVENTS_MOD_H +#define SAGA_EVENTS_MOD_H + +namespace Saga { + +enum R_EVENT_TYPES { + + R_ONESHOT_EVENT, + R_CONTINUOUS_EVENT, + R_INTERVAL_EVENT +}; + +enum R_EVENT_FLAGS { + + R_SIGNALED = 0x8000, + R_NODESTROY = 0x4000 +}; + +enum R_EVENT_CODES { + + R_BG_EVENT = 1, + R_ANIM_EVENT, + R_MUSIC_EVENT, + R_VOICE_EVENT, + R_SOUND_EVENT, + R_SCENE_EVENT, + R_TEXT_EVENT, + R_PAL_EVENT, + R_PALANIM_EVENT, + R_TRANSITION_EVENT, + R_INTERFACE_EVENT, + R_CONSOLE_EVENT, + R_ACTOR_EVENT +}; + +enum R_EVENT_OPS { + + /* INSTANTANEOUS events + * \*------------------------------------------------------------- */ + /* BG events */ + EVENT_DISPLAY = 1, + /* ANIM events */ + EVENT_FRAME = 1, + /* MUISC & SOUND events */ + EVENT_PLAY = 1, + EVENT_STOP = 2, + /* SCENE events */ + EVENT_END = 2, + /* TEXT events */ + EVENT_HIDE = 2, + EVENT_REMOVE = 3, + /* PALANIM events */ + EVENT_CYCLESTART = 1, + EVENT_CYCLESTEP = 2, + /* INTERFACE events */ + EVENT_ACTIVATE = 1, + EVENT_DEACTIVATE, + /* ACTOR events */ + EVENT_MOVE = 1, + + /* CONTINUOUS events + * \*------------------------------------------------------------- */ + /* PALETTE events */ + EVENT_PALTOBLACK = 1, + EVENT_BLACKTOPAL = 2, + /* TRANSITION events */ + EVENT_DISSOLVE = 1 +}; + +enum R_EVENT_PARAMS { + + NO_SET_PALETTE, + SET_PALETTE +}; + +typedef struct R_EVENT_tag { + + unsigned int type; + unsigned int code; /* Event operation category & flags */ + int op; /* Event operation */ + + long param; /* Optional event parameter */ + long param2; + + void *data; /* Optional event data */ + + long time; /* Elapsed time until event */ + long duration; /* Duration of event */ + long d_reserved; + + struct R_EVENT_tag *chain; /* Event chain + * (For consecutive events) */ + +} R_EVENT; + +int EVENT_Init(void); + +int EVENT_Shutdown(void); + +int EVENT_HandleEvents(long msec); + +int EVENT_ClearList(void); + +int EVENT_FreeList(void); + +R_EVENT *EVENT_Queue(R_EVENT * event); + +R_EVENT *EVENT_Chain(R_EVENT * head_event, R_EVENT * add_event); + +} // End of namespace Saga + +#endif /* R_EVENTS_MOD_H */ diff --git a/saga/expr.cpp b/saga/expr.cpp new file mode 100644 index 0000000000..32aca92b7f --- /dev/null +++ b/saga/expr.cpp @@ -0,0 +1,464 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Expression parsing module, and string handling functions + + Notes: + + EXPR_ParseArgs() lifted wholesale from SDL win32 initialization code by + Sam Lantinga +*/ + +#include "reinherit.h" + +/* + Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "cvar_mod.h" + +/* + Begin module +\*--------------------------------------------------------------------------*/ +#include "expr.h" + +namespace Saga { + +char *EXPR_ErrMsg[] = { + + "Invalid error state.", + "No Error", + "Memory allocation failed", + "Illegal variable name", + "Expected \'=\' or \'(\' in expression", + "Expected \'(\' in function call", + "Illegal \'(\', identifier is not function", + "Expected a value to assign", + "Unterminated string literal", + "Unmatched parenthesis in function call", + "Error reading value string", + "Expected a number or boolean", + "Unknown variable or function" +}; + +enum EXPR_Errors { + + EXERR_ASSERT, + EXERR_NONE, + EXERR_MEM, + EXERR_ILLEGAL, + EXERR_EXPR, + EXERR_FUNC, + EXERR_NOTFUNC, + EXERR_RVALUE, + EXERR_LITERAL, + EXERR_PAREN, + EXERR_STRING, + EXERR_NUMBER, + EXERR_NOTFOUND +}; + +static enum EXPR_Errors EXPR_ErrorState; + +int EXPR_GetError(char **err_str) +/*--------------------------------------------------------------------------*\ + Returns the appropriate expression parser error string given an error code. +\*--------------------------------------------------------------------------*/ +{ + + *err_str = EXPR_ErrMsg[EXPR_ErrorState]; + + return EXPR_ErrorState; +} + +int +EXPR_Parse(const char **exp_pp, int *len, R_CVAR_P * expr_cvar, char **rvalue) +/*--------------------------------------------------------------------------*\ + Parses an interactive expression. + Sets 'expr_cvar' to the cvar/cfunction identifier input by the user, and + 'rvalue' to the corresponding rvalue ( in an expression ) or argument string + ( in a function call ). + + Memory pointed to by rvalue after return must be explicitly freed by the + caller. +\*--------------------------------------------------------------------------*/ +{ + + int i; + int in_char; + int equ_offset; + int rvalue_offset; + + char *lvalue_str; + int lvalue_len; + + char *rvalue_str; + int rvalue_len; + + const char *scan_p; + int scan_len; + + const char *expr_p; + int expr_len; + int test_char = '\0'; + int have_func = 0; + + R_CVAR_P lvalue_cvar; + + expr_p = *exp_pp; + expr_len = strlen(*exp_pp); + + scan_p = *exp_pp; + scan_len = expr_len; + + /**lvalue = NULL;*/ + *rvalue = NULL; + + EXPR_ErrorState = EXERR_ASSERT; + + for (i = 0; i <= scan_len; i++, scan_p++) { + + in_char = *scan_p; + + if ((i == 0) && isdigit(in_char)) { + /* First character of a valid identifier cannot be a digit */ + EXPR_ErrorState = EXERR_ILLEGAL; + return R_FAILURE; + } + + /* If we reach a character that isn't valid in an identifier... */ + if ((!isalnum(in_char)) && ((in_char != '_'))) { + + /* then eat remaining whitespace, if any */ + equ_offset = strspn(scan_p, R_EXPR_WHITESPACE); + + test_char = scan_p[equ_offset]; + /* and test for the only valid characters after an identifier */ + if ((test_char != '=') && + (test_char != '\0') && (test_char != '(')) { + + if ((equ_offset == 0) + && ((scan_p - expr_p) != expr_len)) { + EXPR_ErrorState = EXERR_ILLEGAL; + } else { + EXPR_ErrorState = EXERR_EXPR; + } + return R_FAILURE; + } + + break; + } + } + + lvalue_len = (scan_p - expr_p); + lvalue_str = (char *)malloc(lvalue_len + 1); + + if (lvalue_str == NULL) { + EXPR_ErrorState = EXERR_MEM; + return R_FAILURE; + } + + strncpy(lvalue_str, expr_p, lvalue_len); + lvalue_str[lvalue_len] = 0; + + /* We now have the lvalue, so attempt to find it */ + lvalue_cvar = CVAR_Find(lvalue_str); + if (lvalue_cvar == NULL) { + EXPR_ErrorState = EXERR_NOTFOUND; + return R_FAILURE; + } + if (lvalue_str) { + free(lvalue_str); + lvalue_str = NULL; + } + + /* Skip parsed character, if any */ + scan_p += equ_offset + 1; + scan_len = (scan_p - expr_p); + + /* Check if the 'cvar' is really a function */ + have_func = CVAR_IsFunc(lvalue_cvar); + + if (test_char == '(') { + + if (have_func) { + + rvalue_str = + EXPR_ReadString(&scan_p, &rvalue_len, ')'); + if (rvalue_str != NULL) { + /* Successfully read string */ + /*CON_Print( "Read function parameters \"%s\".", rvalue_str ); */ + *expr_cvar = lvalue_cvar; + *rvalue = rvalue_str; + + scan_len = (scan_p - expr_p); + + *exp_pp = scan_p; + *len -= scan_len; + + EXPR_ErrorState = EXERR_NONE; + return R_SUCCESS; + } else { + EXPR_ErrorState = EXERR_PAREN; + return R_FAILURE; + } + } else { + EXPR_ErrorState = EXERR_NOTFUNC; + return R_FAILURE; + } + + } + + /* Eat more whitespace */ + rvalue_offset = strspn(scan_p, R_EXPR_WHITESPACE); + + if (rvalue_offset + i == expr_len) { + /* Only found single lvalue */ + *expr_cvar = lvalue_cvar; + *exp_pp = scan_p; + *len -= scan_len; + return R_SUCCESS; + } + + scan_p += rvalue_offset; + scan_len = (scan_p - expr_p) + 1; + + in_char = *scan_p; + + in_char = toupper(in_char); + + switch (in_char) { + + case '\"': + scan_p++; + scan_len--; + rvalue_str = EXPR_ReadString(&scan_p, &rvalue_len, '\"'); + + if (rvalue_str != NULL) { + /* Successfully read string */ + break; + } else { + EXPR_ErrorState = EXERR_LITERAL; + return R_FAILURE; + } + break; + +#if 0 + case 'Y': /* Y[es] */ + case 'T': /* T[rue] */ + + break; + + case 'N': /* N[o] */ + case 'F': /* F[alse] */ + + break; +#endif + + default: + + if (isdigit(in_char) || (in_char == '-') || (in_char == '+')) { + + rvalue_str = EXPR_ReadString(&scan_p, &rvalue_len, 0); + + if (rvalue_str != NULL) { + /* Successfully read string */ + break; + } else { + EXPR_ErrorState = EXERR_STRING; + return R_FAILURE; + } + } else { + EXPR_ErrorState = EXERR_NUMBER; + return R_FAILURE; + } + + break; + + } + + *expr_cvar = lvalue_cvar; + *rvalue = rvalue_str; + + scan_len = (scan_p - expr_p); + + *exp_pp = scan_p; + *len -= scan_len; + + EXPR_ErrorState = EXERR_NONE; + return R_SUCCESS; + +} + +char *EXPR_ReadString(const char **string_p, int *len, int term_char) +/****************************************************************************\ + Reads in a string of characters from '*string_p' until 'term_char' is + encountered. If 'term_char' == 0, the function reads characters until + whitespace is encountered. + Upon reading a string, the function modifies *string_p and len based on + the number of characters read. +\****************************************************************************/ +{ + + int string_len; + char *str_p; + char *term_p; + + const char *scan_p; + int in_char; + + if (term_char > 0) { + + term_p = strchr(*string_p, term_char); + + if (term_p == NULL) { + return NULL; + } + + string_len = (int)(term_p - *string_p); + + str_p = (char *)malloc(string_len + 1); + + if (str_p == NULL) { + return NULL; + } + + strncpy(str_p, *string_p, string_len); + str_p[string_len] = 0; + + *string_p += (string_len + 1); /* Add 1 for terminating char */ + *len -= (string_len + 1); + + } else { + + scan_p = *string_p; + string_len = 0; + + while (scan_p) { + + in_char = *scan_p++; + + if (!isspace(in_char)) { + string_len++; + } else if (string_len) { + + str_p = (char *)malloc(string_len + 1); + + if (str_p == NULL) { + return NULL; + } + + strncpy(str_p, *string_p, string_len); + str_p[string_len] = 0; + + *string_p += string_len; + *len -= string_len; + break; + + } else { + return NULL; + } + } + + } + + return str_p; +} + +int EXPR_GetArgs(char *cmd_str, char ***expr_argv) +/****************************************************************************\ + Parses the string 'cmd_str' into argc/argv format, returning argc. + The resulting argv pointers point into the 'cmd_str' string, so any argv + entries should not be used after cmd_str is deallocated. + + Memory pointed to by expr_argv must be explicitly freed by the caller. +\****************************************************************************/ +{ + + int expr_argc; + + expr_argc = EXPR_ParseArgs(cmd_str, NULL); + *expr_argv = (char **)malloc((expr_argc + 1) * sizeof(**expr_argv)); + + if (expr_argv == NULL) { + return R_FAILURE; + } + + EXPR_ParseArgs(cmd_str, *expr_argv); + + return expr_argc; + +} + +int EXPR_ParseArgs(char *cmd_str, char **argv) +{ + + char *bufp; + int argc; + + argc = 0; + for (bufp = cmd_str; *bufp;) { + /* Skip leading whitespace */ + while (isspace(*bufp)) { + ++bufp; + } + /* Skip over argument */ + if (*bufp == '"') { + ++bufp; + if (*bufp) { + if (argv) { + argv[argc] = bufp; + } + ++argc; + } + /* Skip over word */ + while (*bufp && (*bufp != '"')) { + ++bufp; + } + } else { + if (*bufp) { + if (argv) { + argv[argc] = bufp; + } + ++argc; + } + /* Skip over word */ + while (*bufp && !isspace(*bufp)) { + ++bufp; + } + } + if (*bufp) { + if (argv) { + *bufp = '\0'; + } + ++bufp; + } + } + if (argv) { + argv[argc] = NULL; + } + return (argc); +} + +} // End of namespace Saga diff --git a/saga/expr.h b/saga/expr.h new file mode 100644 index 0000000000..3a648ecb4d --- /dev/null +++ b/saga/expr.h @@ -0,0 +1,43 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Expression parsing module header file + + Notes: +*/ + +#ifndef SAGA_EXPR_H_ +#define SAGA_EXPR_H_ + +namespace Saga { + +#define R_EXPR_WHITESPACE "\t\n " + +int EXPR_ParseArgs(char *cmd_str, char **argv); + +} // End of namespace Saga + +#endif /* R_EXPR_H_ */ +/* end "r_expr.h" */ diff --git a/saga/font.cpp b/saga/font.cpp new file mode 100644 index 0000000000..18f2aaf276 --- /dev/null +++ b/saga/font.cpp @@ -0,0 +1,721 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Font management and font drawing module + + Notes: +*/ + +#include "reinherit.h" + +#include "yslib.h" + +/* + * Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "rscfile_mod.h" +#include "game_mod.h" + +/* + * Begin module +\*--------------------------------------------------------------------------*/ +#include "font_mod.h" +#include "font.h" + +namespace Saga { + +static R_FONT_MODULE FontModule; + +int FONT_Init(void) +{ + + R_GAME_FONTDESC *gamefonts; + int i; + + if (FontModule.init) { + + FontModule.err_str = "Font module already initialized."; + + return R_FAILURE; + } + + /* Load font module resource context + * \*------------------------------------------------------------ */ + if (GAME_GetFileContext(&FontModule.font_ctxt, + R_GAME_RESOURCEFILE, 0) != R_SUCCESS) { + + FontModule.err_str = "Couldn't get resource context."; + + return R_FAILURE; + } + + /* Allocate font table + * \*------------------------------------------------------------ */ + GAME_GetFontInfo(&gamefonts, &FontModule.n_fonts); + + assert(FontModule.n_fonts > 0); + + FontModule.fonts = (R_FONT **)malloc(FontModule.n_fonts * + sizeof *FontModule.fonts); + if (FontModule.fonts == NULL) { + + FontModule.err_str = "Memory allocation failure."; + + return R_MEM; + } + + for (i = 0; i < FontModule.n_fonts; i++) { + + FONT_Load(gamefonts[i].font_rn, gamefonts[i].font_id); + } + + FontModule.init = 1; + + return R_SUCCESS; +} + +int FONT_Shutdown(void) +{ + + int i; + + R_printf(R_STDOUT, "FONT_Shutdown(): Freeing fonts.\n"); +/* + for ( i = 0 ; i < R_FONT_COUNT ; i ++ ) { + + if ( FontModule.fonts[i] != NULL ) { + + if ( FontModule.fonts[i]->normal_loaded ) { + free( FontModule.fonts[i]->normal->font_free_p ); + free( FontModule.fonts[i]->normal ); + } + + if ( FontModule.fonts[i]->outline_loaded ) { + free( FontModule.fonts[i]->outline->font_free_p ); + free( FontModule.fonts[i]->outline ); + } + } + + free( FontModule.fonts[i] ); + } +*/ + return R_SUCCESS; +} + +int FONT_Load(ulong font_rn, int font_id) +{ + + R_FONT_HEADER fh; + R_FONT *font; + R_FONT_STYLE *normal_font; + + uchar *fontres_p; + size_t fontres_len; + size_t remain; + + const uchar *read_p; + + int nbits; + int c; + + if ((font_id < 0) || (font_id >= FontModule.n_fonts)) { + return R_FAILURE; + } + + /* Load font resource + * \*------------------------------------------------------------- */ + if (RSC_LoadResource(FontModule.font_ctxt, + font_rn, &fontres_p, &fontres_len) != R_SUCCESS) { + + FontModule.err_str = "Couldn't load font resource."; + + return R_FAILURE; + } + + if (fontres_len < R_FONT_DESCSIZE) { + + FontModule.err_str = "Invalid font length."; + } + + read_p = fontres_p; + remain = fontres_len; + + /* Create new font structure + * \*------------------------------------------------------------- */ + font = (R_FONT *)malloc(sizeof *font); + if (font == NULL) { + FontModule.err_str = "Memory allocation error."; + + return R_MEM; + } + + /* Read font header + * \*------------------------------------------------------------- */ + fh.c_height = ys_read_u16_le(read_p, &read_p); + fh.c_width = ys_read_u16_le(read_p, &read_p); + fh.row_length = ys_read_u16_le(read_p, &read_p); + +#if R_FONT_DBGLVL >= R_DEBUG_INFO + R_printf(R_STDOUT, "FONT_Load(): Reading font resource...\n"); +#endif + +#if R_FONT_DBGLVL >= R_DEBUG_VERBOSE + R_printf(R_STDOUT, "Character width:\t%d\n", fh.c_width); + R_printf(R_STDOUT, "Character height:\t%d\n", fh.c_height); + R_printf(R_STDOUT, "Row padding:\t%d\n", fh.row_length); +#endif + + /* Create normal font style + * \*------------------------------------------------------------- */ + normal_font = (R_FONT_STYLE *)malloc(sizeof *normal_font); + if (normal_font == NULL) { + + FontModule.err_str = "Memory allocation error."; + free(font); + + return R_MEM; + } + + normal_font->font_free_p = fontres_p; + normal_font->hdr.c_height = fh.c_height; + normal_font->hdr.c_width = fh.c_width; + normal_font->hdr.row_length = fh.row_length; + + for (c = 0; c < R_FONT_CHARCOUNT; c++) { + normal_font->fce[c].index = ys_read_u16_le(read_p, &read_p); + } + + for (c = 0; c < R_FONT_CHARCOUNT; c++) { + nbits = normal_font->fce[c].width = + ys_read_u8(read_p, &read_p); + normal_font->fce[c].byte_width = GetByteLen(nbits); + } + + for (c = 0; c < R_FONT_CHARCOUNT; c++) { + normal_font->fce[c].flag = ys_read_u8(read_p, &read_p); + } + + for (c = 0; c < R_FONT_CHARCOUNT; c++) { + normal_font->fce[c].tracking = ys_read_u8(read_p, &read_p); + } + + if ((read_p - fontres_p) != R_FONT_DESCSIZE) { + + R_printf(R_STDERR, "Invalid font resource size.\n"); + return R_FAILURE; + } + + normal_font->font_p = (uchar *) read_p; + + font->normal = normal_font; + font->normal_loaded = 1; + + /* Create outline font style + * \*------------------------------------------------------------- */ + font->outline = FONT_CreateOutline(normal_font); + font->outline_loaded = 1; + + /* Set font data + * \*------------------------------------------------------------- */ + + FontModule.fonts[font_id] = font; + + return R_SUCCESS; +} + +int FONT_GetHeight(int font_id) +{ + + R_FONT *font; + + if (!FontModule.init) { + return R_FAILURE; + } + + if ((font_id < 0) || + (font_id >= FontModule.n_fonts) || + (FontModule.fonts[font_id] == NULL)) { + + FontModule.err_str = "Invalid font id."; + + return R_FAILURE; + } + + font = FontModule.fonts[font_id]; + + return font->normal->hdr.c_height; +} + +static R_FONT_STYLE *FONT_CreateOutline(R_FONT_STYLE * src_font) +{ + + R_FONT_STYLE *new_font; + unsigned char *new_font_data; + size_t new_font_data_len; + + int s_width = src_font->hdr.c_width; + int s_height = src_font->hdr.c_height; + + int new_row_len = 0; + int row; + int i; + + int index; + size_t index_offset = 0; + + int new_byte_width; + int old_byte_width; + + int current_byte; + + unsigned char *base_ptr; + unsigned char *src_ptr; + unsigned char *dest_ptr1; + unsigned char *dest_ptr2; + unsigned char *dest_ptr3; + + unsigned char c_rep; + + /* Create new font style structure + * \*------------------------------------------------------------- */ + new_font = (R_FONT_STYLE *)malloc(sizeof *new_font); + + if (new_font == NULL) { + FontModule.err_str = "Memory allocation error."; + + return NULL; + } + + memset(new_font, 0, sizeof *new_font); + + /* Populate new font style character data + * \*------------------------------------------------------------- */ + for (i = 0; i < R_FONT_CHARCOUNT; i++) { + + new_byte_width = 0; + old_byte_width = 0; + + index = src_font->fce[i].index; + if ((index > 0) || (i == R_FONT_FIRSTCHAR)) { + index += index_offset; + } + + new_font->fce[i].index = index; + new_font->fce[i].tracking = src_font->fce[i].tracking; + new_font->fce[i].flag = src_font->fce[i].flag; + + if (src_font->fce[i].width != 0) { + + new_byte_width = + GetByteLen(src_font->fce[i].width + 2); + old_byte_width = GetByteLen(src_font->fce[i].width); + + if (new_byte_width > old_byte_width) { + index_offset++; + } + } + + new_font->fce[i].width = src_font->fce[i].width + 2; + new_font->fce[i].byte_width = new_byte_width; + new_row_len += new_byte_width; + } + +#if R_FONT_DBGLVL >= R_DEBUG_VERBOSE + R_printf(R_STDOUT, "New row length: %d\n", new_row_len); +#endif + + new_font->hdr.c_width = s_width + 2; + new_font->hdr.c_height = s_height + 2; + new_font->hdr.row_length = new_row_len; + + /* Allocate new font representation storage + * \*------------------------------------------------------------- */ + new_font_data_len = new_row_len * (s_height + 2); + new_font_data = (unsigned char *)malloc(new_font_data_len); + + if (new_font_data == NULL) { + FontModule.err_str = "Memory allocation error."; + + return NULL; + } + + memset(new_font_data, 0, new_font_data_len); + + new_font->font_free_p = new_font_data; + new_font->font_p = new_font_data; + + /* Generate outline font representation + * \*------------------------------------------------------------- */ + for (i = 0; i < R_FONT_CHARCOUNT; i++) { + + for (row = 0; row < s_height; row++) { + + for (current_byte = 0; + current_byte < new_font->fce[i].byte_width; + current_byte++) { + + base_ptr = + new_font->font_p + new_font->fce[i].index + + current_byte; + + dest_ptr1 = + base_ptr + new_font->hdr.row_length * row; + dest_ptr2 = + base_ptr + + new_font->hdr.row_length * (row + 1); + dest_ptr3 = + base_ptr + + new_font->hdr.row_length * (row + 2); + + if (current_byte > 0) { + + /* Get last two columns from previous byte */ + src_ptr = src_font->font_p + + src_font->hdr.row_length * row + + src_font->fce[i].index + + (current_byte - 1); + + c_rep = *src_ptr; + *dest_ptr1 |= + ((c_rep << 6) | (c_rep << 7)); + *dest_ptr2 |= + ((c_rep << 6) | (c_rep << 7)); + *dest_ptr3 |= + ((c_rep << 6) | (c_rep << 7)); + } + + if (current_byte < src_font->fce[i].byte_width) { + + src_ptr = src_font->font_p + + src_font->hdr.row_length * row + + src_font->fce[i].index + + current_byte; + + c_rep = *src_ptr; + *dest_ptr1 |= + c_rep | (c_rep >> 1) | (c_rep >> + 2); + *dest_ptr2 |= + c_rep | (c_rep >> 1) | (c_rep >> + 2); + *dest_ptr3 |= + c_rep | (c_rep >> 1) | (c_rep >> + 2); + } + } + } + + /* "Hollow out" character to prevent overdraw */ + for (row = 0; row < s_height; row++) { + + for (current_byte = 0; + current_byte < new_font->fce[i].byte_width; + current_byte++) { + + dest_ptr2 = new_font->font_p + + new_font->hdr.row_length * (row + 1) + + new_font->fce[i].index + current_byte; + + if (current_byte > 0) { + + /* Get last two columns from previous byte */ + src_ptr = src_font->font_p + + src_font->hdr.row_length * row + + src_font->fce[i].index + + (current_byte - 1); + + *dest_ptr2 &= + ((*src_ptr << 7) ^ 0xFFU); + } + + if (current_byte < src_font->fce[i].byte_width) { + + src_ptr = src_font->font_p + + src_font->hdr.row_length * row + + src_font->fce[i].index + + current_byte; + + *dest_ptr2 &= + ((*src_ptr >> 1) ^ 0xFFU); + } + } + } + } + + return new_font; + +} + +static int GetByteLen(int num_bits) +{ + + int byte_len; + + byte_len = num_bits / 8; + + if (num_bits % 8) { + byte_len++; + } + + return byte_len; +} + +int +FONT_GetStringWidth(int font_id, + const char *test_str, size_t test_str_ct, int flags) +/*--------------------------------------------------------------------------*\ + * Returns the horizontal length in pixels of the graphical representation + * of at most 'test_str_ct' characters of the string 'test_str', taking + * into account any formatting options specified by 'flags'. + * If 'test_str_ct' is 0, all characters of 'test_str' are counted. +\*--------------------------------------------------------------------------*/ +{ + + R_FONT *font; + size_t ct; + int width = 0; + int ch; + uchar *txt_p; + + if (!FontModule.init) { + return R_FAILURE; + } + + if ((font_id < 0) || + (font_id >= FontModule.n_fonts) || + (FontModule.fonts[font_id] == NULL)) { + + FontModule.err_str = "Invalid font id."; + + return R_FAILURE; + } + + font = FontModule.fonts[font_id]; + assert(font != NULL); + + txt_p = (uchar *) test_str; + + for (ct = test_str_ct; + *txt_p && (!test_str_ct || ct > 0); txt_p++, ct--) { + + ch = *txt_p & 0xFFU; + + /* Translate character */ + ch = CharMap[ch]; + assert(ch < R_FONT_CHARCOUNT); + + width += font->normal->fce[ch].tracking; + } + + if ((flags & FONT_BOLD) || (flags & FONT_OUTLINE)) { + width += 1; + } + + return width; +} + +int +FONT_Draw(int font_id, + R_SURFACE * ds, + const char *draw_str, + size_t draw_str_ct, + int text_x, int text_y, int color, int effect_color, int flags) +{ + + R_FONT *font; + + if (!FontModule.init) { + FontModule.err_str = "Font Module not initialized."; + + return R_FAILURE; + } + + if ((font_id < 0) || + (font_id >= FontModule.n_fonts) || + (FontModule.fonts[font_id] == NULL)) { + + FontModule.err_str = "Invalid font id."; + + return R_FAILURE; + } + + font = FontModule.fonts[font_id]; + + if (flags & FONT_OUTLINE) { + + FONT_Out(font->outline, + ds, + draw_str, + draw_str_ct, text_x - 1, text_y - 1, effect_color); + + FONT_Out(font->normal, + ds, draw_str, draw_str_ct, text_x, text_y, color); + } else if (flags & FONT_SHADOW) { + + FONT_Out(font->normal, + ds, + draw_str, + draw_str_ct, text_x - 1, text_y + 1, effect_color); + + FONT_Out(font->normal, + ds, draw_str, draw_str_ct, text_x, text_y, color); + } else { /* FONT_NORMAL */ + + FONT_Out(font->normal, + ds, draw_str, draw_str_ct, text_x, text_y, color); + } + + return R_SUCCESS; +} + +int +FONT_Out(R_FONT_STYLE * draw_font, + R_SURFACE * ds, + const char *draw_str, + size_t draw_str_ct, int text_x, int text_y, int color) +{ + + const uchar *draw_str_p; + + uchar *c_data_ptr; + int c_code; + + int char_row; + + uchar *output_ptr; + uchar *output_ptr_min; + uchar *output_ptr_max; + + int row; + int row_limit; + + int c_byte_len; + int c_byte; + int c_bit; + + int ct; + + if ((text_x > ds->buf_w) || (text_y > ds->buf_h)) { + /* Output string can't be visible */ + return R_SUCCESS; + } + + draw_str_p = (uchar *) draw_str; + ct = draw_str_ct; + + /* Draw string one character at a time, maximum of 'draw_str'_ct + * characters, or no limit if 'draw_str_ct' is 0 */ + for (; *draw_str_p && (!draw_str_ct || ct); draw_str_p++, ct--) { + + c_code = *draw_str_p & 0xFFU; + + /* Translate character */ + c_code = CharMap[c_code]; + assert(c_code < R_FONT_CHARCOUNT); + + /* Check if character is defined */ + if ((draw_font->fce[c_code].index == 0) && + (c_code != R_FONT_FIRSTCHAR)) { + +# if R_FONT_SHOWUNDEFINED + + if (c_code == R_FONT_CH_SPACE) { + text_x += draw_font->fce[c_code].tracking; + continue; + } + c_code = R_FONT_CH_QMARK; + +# else + + /* Character code is not defined, but advance tracking + * ( Not defined if offset is 0, except for 33 ('!') which + * is defined ) */ + text_x += draw_font->fce[c_code].tracking; + continue; + +#endif + } + + /* Get length of character in bytes */ + c_byte_len = ((draw_font->fce[c_code].width - 1) / 8) + 1; + + row_limit = (ds->buf_h < (text_y + draw_font->hdr.c_height)) + ? ds->buf_h : text_y + draw_font->hdr.c_height; + + char_row = 0; + + for (row = text_y; row < row_limit; row++, char_row++) { + + /* Clip negative rows */ + if (row < 0) { + continue; + } + + output_ptr = ds->buf + (ds->buf_pitch * row) + text_x; + + output_ptr_min = ds->buf + (ds->buf_pitch * row) + + (text_x > 0 ? text_x : 0); + + output_ptr_max = output_ptr + (ds->buf_pitch - text_x); + + /* If character starts off the screen, jump to next character */ + if (output_ptr < output_ptr_min) { + break; + } + + c_data_ptr = draw_font->font_p + + char_row * draw_font->hdr.row_length + + draw_font->fce[c_code].index; + + for (c_byte = 0; c_byte < c_byte_len; + c_byte++, c_data_ptr++) { + + /* Check each bit, draw pixel if bit is set */ + for (c_bit = 7; + c_bit >= 0 + && (output_ptr < output_ptr_max); + c_bit--) { + + if ((*c_data_ptr >> c_bit) & 0x01) { + *output_ptr = (uchar) color; + } + output_ptr++; + + } /* end per-bit processing */ + + } /* end per-byte processing */ + + } /* end per-row processing */ + + /* Advance tracking position */ + text_x += draw_font->fce[c_code].tracking; + + } /* end per-character processing */ + + return R_SUCCESS; +} + +} // End of namespace Saga diff --git a/saga/font.h b/saga/font.h new file mode 100644 index 0000000000..a72322c804 --- /dev/null +++ b/saga/font.h @@ -0,0 +1,132 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Font management and font drawing header file + + Notes: +*/ + +#ifndef SAGA_FONT_H__ +#define SAGA_FONT_H__ + +namespace Saga { + +#define R_FONT_DBGLVL R_DEBUG_NONE + +#define R_FONT_SHOWUNDEFINED 1 /* Define to draw undefined characters + * as ?'s */ + +/* The first defined character (!) is the only one that may + have a valid offset of '0' */ +#define R_FONT_FIRSTCHAR 33 + +#define R_FONT_CH_SPACE 32 +#define R_FONT_CH_QMARK 63 + +/* Minimum font header size without font data + (6 + 512 + 256 + 256 + 256 ) */ +#define R_FONT_DESCSIZE 1286 + +#define R_FONT_CHARCOUNT 256 +#define R_FONT_CHARMASK 0xFFU + +#define SAGA_FONT_HEADER_LEN 6 + +typedef struct R_FONT_HEADER_tag { + + int c_height; + int c_width; + int row_length; + +} R_FONT_HEADER; + +typedef struct FONT_CHAR_ENTRY_TAG { + + int index; + int byte_width; + int width; + int flag; + int tracking; + +} FONT_CHAR_ENTRY; + +typedef struct R_FONT_STYLE_tag { + + R_FONT_HEADER hdr; + FONT_CHAR_ENTRY fce[256]; + + uchar *font_free_p; + uchar *font_p; + +} R_FONT_STYLE; + +typedef struct R_FONT_tag { + + ulong font_rn; + int font_id; + + int normal_loaded; + R_FONT_STYLE *normal; + int outline_loaded; + R_FONT_STYLE *outline; + + uchar *res_data; + size_t res_len; + +} R_FONT; + +typedef struct R_FONT_MODULE_tag { + + int init; + + R_RSCFILE_CONTEXT *font_ctxt; + + int n_fonts; + R_FONT **fonts; + + int err_n; + const char *err_str; + +} R_FONT_MODULE; + +int FONT_Load(ulong font_rn, int font_id); + +static R_FONT_STYLE *FONT_CreateOutline(R_FONT_STYLE * src_font); + +int +FONT_Out(R_FONT_STYLE * font, + R_SURFACE * ds, + const char *draw_str, + size_t draw_str_ct, int text_x, int text_y, int color); + +static int GetByteLen(int num_bits); + +extern int CharMap[]; + +} // End of namespace Saga + +#endif /* R_FONT_H__ */ +/* end "r_font.h" */ diff --git a/saga/font_map.cpp b/saga/font_map.cpp new file mode 100644 index 0000000000..fc070d4c36 --- /dev/null +++ b/saga/font_map.cpp @@ -0,0 +1,295 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Font module character mapping table ( MS CP-850 to ISO 8859-1 ) + + Notes: + + Translation table derived from http://www.kostis.net/charsets/ +*/ + +namespace Saga { + +int CharMap[] = { + 0, /* 0 */ + 1, /* 1 */ + 2, /* 2 */ + 3, /* 3 */ + 4, /* 4 */ + 5, /* 5 */ + 6, /* 6 */ + 7, /* 7 */ + 8, /* 8 */ + 9, /* 9 */ + 10, /* 10 */ + 11, /* 11 */ + 12, /* 12 */ + 13, /* 13 */ + 14, /* 14 */ + 15, /* 15 */ + 16, /* 16 */ + 17, /* 17 */ + 18, /* 18 */ + 19, /* 19 */ + 20, /* 20 */ + 21, /* 21 */ + 22, /* 22 */ + 23, /* 23 */ + 24, /* 24 */ + 25, /* 25 */ + 26, /* 26 */ + 27, /* 27 */ + 28, /* 28 */ + 29, /* 29 */ + 30, /* 30 */ + 31, /* 31 */ + 32, /* 32 */ + 33, /* 33 */ + 34, /* 34 */ + 35, /* 35 */ + 36, /* 36 */ + 37, /* 37 */ + 38, /* 38 */ + 39, /* 39 */ + 40, /* 40 */ + 41, /* 41 */ + 42, /* 42 */ + 43, /* 43 */ + 44, /* 44 */ + 45, /* 45 */ + 46, /* 46 */ + 47, /* 47 */ + 48, /* 48 */ + 49, /* 49 */ + 50, /* 50 */ + 51, /* 51 */ + 52, /* 52 */ + 53, /* 53 */ + 54, /* 54 */ + 55, /* 55 */ + 56, /* 56 */ + 57, /* 57 */ + 58, /* 58 */ + 59, /* 59 */ + 60, /* 60 */ + 61, /* 61 */ + 62, /* 62 */ + 63, /* 63 */ + 64, /* 64 */ + 65, /* 65 */ + 66, /* 66 */ + 67, /* 67 */ + 68, /* 68 */ + 69, /* 69 */ + 70, /* 70 */ + 71, /* 71 */ + 72, /* 72 */ + 73, /* 73 */ + 74, /* 74 */ + 75, /* 75 */ + 76, /* 76 */ + 77, /* 77 */ + 78, /* 78 */ + 79, /* 79 */ + 80, /* 80 */ + 81, /* 81 */ + 82, /* 82 */ + 83, /* 83 */ + 84, /* 84 */ + 85, /* 85 */ + 86, /* 86 */ + 87, /* 87 */ + 88, /* 88 */ + 89, /* 89 */ + 90, /* 90 */ + 91, /* 91 */ + 92, /* 92 */ + 93, /* 93 */ + 94, /* 94 */ + 95, /* 95 */ + 96, /* 96 */ + 97, /* 97 */ + 98, /* 98 */ + 99, /* 99 */ + 100, /* 100 */ + 101, /* 101 */ + 102, /* 102 */ + 103, /* 103 */ + 104, /* 104 */ + 105, /* 105 */ + 106, /* 106 */ + 107, /* 107 */ + 108, /* 108 */ + 109, /* 109 */ + 110, /* 110 */ + 111, /* 111 */ + 112, /* 112 */ + 113, /* 113 */ + 114, /* 114 */ + 115, /* 115 */ + 116, /* 116 */ + 117, /* 117 */ + 118, /* 118 */ + 119, /* 119 */ + 120, /* 120 */ + 121, /* 121 */ + 122, /* 122 */ + 123, /* 123 */ + 124, /* 124 */ + 125, /* 125 */ + 126, /* 126 */ + 127, /* 127 */ + 199, /* 128 LATIN CAPITAL LETTER C WITH CEDILLA */ + 252, /* 129 LATIN SMALL LETTER U WITH DIAERESIS */ + 233, /* 130 LATIN SMALL LETTER E WITH ACUTE */ + 226, /* 131 LATIN SMALL LETTER A WITH CIRCUMFLEX */ + 228, /* 132 LATIN SMALL LETTER A WITH DIAERESIS */ + 224, /* 133 LATIN SMALL LETTER A WITH GRAVE */ + 229, /* 134 LATIN SMALL LETTER A WITH RING ABOVE */ + 231, /* 135 LATIN SMALL LETTER C WITH CEDILLA */ + 234, /* 136 LATIN SMALL LETTER E WITH CIRCUMFLEX */ + 235, /* 137 LATIN SMALL LETTER E WITH DIAERESIS */ + 232, /* 138 LATIN SMALL LETTER E WITH GRAVE */ + 239, /* 139 LATIN SMALL LETTER I WITH DIAERESIS */ + 238, /* 140 LATIN SMALL LETTER I WITH CIRCUMFLEX */ + 236, /* 141 LATIN SMALL LETTER I WITH GRAVE */ + 196, /* 142 LATIN CAPITAL LETTER A WITH DIAERESIS */ + 197, /* 143 LATIN CAPITAL LETTER A WITH RING ABOVE */ + 201, /* 144 LATIN CAPITAL LETTER E WITH ACUTE */ + 230, /* 145 LATIN SMALL LETTER AE */ + 198, /* 146 LATIN CAPITAL LETTER AE */ + 244, /* 147 LATIN SMALL LETTER O WITH CIRCUMFLEX */ + 246, /* 148 LATIN SMALL LETTER O WITH DIAERESIS */ + 242, /* 149 LATIN SMALL LETTER O WITH GRAVE */ + 251, /* 150 LATIN SMALL LETTER U WITH CIRCUMFLEX */ + 249, /* 151 LATIN SMALL LETTER U WITH GRAVE */ + 255, /* 152 LATIN SMALL LETTER Y WITH DIAERESIS */ + 214, /* 153 LATIN CAPITAL LETTER O WITH DIAERESIS */ + 220, /* 154 LATIN CAPITAL LETTER U WITH DIAERESIS */ + 248, /* 155 LATIN SMALL LETTER O WITH STROKE */ + 163, /* 156 POUND SIGN */ + 216, /* 157 LATIN CAPITAL LETTER O WITH STROKE */ + 215, /* 158 MULTIPLICATION SIGN */ + 0, /* 159 LATIN SMALL LETTER F WITH HOOK */ + 225, /* 160 LATIN SMALL LETTER A WITH ACUTE */ + 237, /* 161 LATIN SMALL LETTER I WITH ACUTE */ + 243, /* 162 LATIN SMALL LETTER O WITH ACUTE */ + 250, /* 163 LATIN SMALL LETTER U WITH ACUTE */ + 241, /* 164 LATIN SMALL LETTER N WITH TILDE */ + 209, /* 165 LATIN CAPITAL LETTER N WITH TILDE */ + 170, /* 166 FEMININE ORDINAL INDICATOR */ + 186, /* 167 MASCULINE ORDINAL INDICATOR */ + 191, /* 168 INVERTED QUESTION MARK */ + 174, /* 169 REGISTERED SIGN */ + 172, /* 170 NOT SIGN */ + 189, /* 171 VULGAR FRACTION ONE HALF */ + 188, /* 172 VULGAR FRACTION ONE QUARTER */ + 161, /* 173 INVERTED EXCLAMATION MARK */ + 171, /* 174 LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */ + 187, /* 175 RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */ + 0, /* 176 LIGHT SHADE */ + 0, /* 177 MEDIUM SHADE */ + 0, /* 178 DARK SHADE */ + 0, /* 179 BOX DRAWINGS LIGHT VERTICAL */ + 0, /* 180 BOX DRAWINGS LIGHT VERTICAL AND LEFT */ + 193, /* 181 LATIN CAPITAL LETTER A WITH ACUTE */ + 194, /* 182 LATIN CAPITAL LETTER A WITH CIRCUMFLEX */ + 192, /* 183 LATIN CAPITAL LETTER A WITH GRAVE */ + 169, /* 184 COPYRIGHT SIGN */ + 0, /* 185 BOX DRAWINGS DOUBLE VERTICAL AND LEFT */ + 0, /* 186 BOX DRAWINGS DOUBLE VERTICAL */ + 0, /* 187 BOX DRAWINGS DOUBLE DOWN AND LEFT */ + 0, /* 188 BOX DRAWINGS DOUBLE UP AND LEFT */ + 162, /* 189 CENT SIGN */ + 165, /* 190 YEN SIGN */ + 0, /* 191 BOX DRAWINGS LIGHT DOWN AND LEFT */ + 0, /* 192 BOX DRAWINGS LIGHT UP AND RIGHT */ + 0, /* 193 BOX DRAWINGS LIGHT UP AND HORIZONTAL */ + 0, /* 194 BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */ + 0, /* 195 BOX DRAWINGS LIGHT VERTICAL AND RIGHT */ + 0, /* 196 BOX DRAWINGS LIGHT HORIZONTAL */ + 0, /* 197 BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */ + 227, /* 198 LATIN SMALL LETTER A WITH TILDE */ + 195, /* 199 LATIN CAPITAL LETTER A WITH TILDE */ + 0, /* 200 BOX DRAWINGS DOUBLE UP AND RIGHT */ + 0, /* 201 BOX DRAWINGS DOUBLE DOWN AND RIGHT */ + 0, /* 202 BOX DRAWINGS DOUBLE UP AND HORIZONTAL */ + 0, /* 203 BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL */ + 0, /* 204 BOX DRAWINGS DOUBLE VERTICAL AND RIGHT */ + 0, /* 205 BOX DRAWINGS DOUBLE HORIZONTAL */ + 0, /* 206 BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL */ + 164, /* 207 CURRENCY SIGN */ + 240, /* 208 LATIN SMALL LETTER ETH */ + 208, /* 209 LATIN CAPITAL LETTER ETH */ + 202, /* 210 LATIN CAPITAL LETTER E WITH CIRCUMFLEX */ + 203, /* 211 LATIN CAPITAL LETTER E WITH DIAERESIS */ + 200, /* 212 LATIN CAPITAL LETTER E WITH GRAVE */ + 305, /* 213 LATIN SMALL LETTER DOTLESS I */ + 205, /* 214 LATIN CAPITAL LETTER I WITH ACUTE */ + 206, /* 215 LATIN CAPITAL LETTER I WITH CIRCUMFLEX */ + 207, /* 216 LATIN CAPITAL LETTER I WITH DIAERESIS */ + 0, /* 217 BOX DRAWINGS LIGHT UP AND LEFT */ + 0, /* 218 BOX DRAWINGS LIGHT DOWN AND RIGHT */ + 0, /* 219 FULL BLOCK */ + 0, /* 220 LOWER HALF BLOCK */ + 166, /* 221 BROKEN BAR */ + 204, /* 222 LATIN CAPITAL LETTER I WITH GRAVE */ + 0, /* 223 UPPER HALF BLOCK */ + 211, /* 224 LATIN CAPITAL LETTER O WITH ACUTE */ + 223, /* 225 LATIN SMALL LETTER SHARP S */ + 212, /* 226 LATIN CAPITAL LETTER O WITH CIRCUMFLEX */ + 210, /* 227 LATIN CAPITAL LETTER O WITH GRAVE */ + 245, /* 228 LATIN SMALL LETTER O WITH TILDE */ + 213, /* 229 LATIN CAPITAL LETTER O WITH TILDE */ + 181, /* 230 MICRO SIGN */ + 254, /* 231 LATIN SMALL LETTER THORN */ + 222, /* 232 LATIN CAPITAL LETTER THORN */ + 218, /* 233 LATIN CAPITAL LETTER U WITH ACUTE */ + 219, /* 234 LATIN CAPITAL LETTER U WITH CIRCUMFLEX */ + 217, /* 235 LATIN CAPITAL LETTER U WITH GRAVE */ + 253, /* 236 LATIN SMALL LETTER Y WITH ACUTE */ + 221, /* 237 LATIN CAPITAL LETTER Y WITH ACUTE */ + 175, /* 238 MACRON */ + 180, /* 239 ACUTE ACCENT */ + 173, /* 240 SOFT HYPHEN */ + 177, /* 241 PLUS-MINUS SIGN */ + 0, /* 242 DOUBLE LOW LINE */ + 190, /* 243 VULGAR FRACTION THREE QUARTERS */ + 182, /* 244 PILCROW SIGN */ + 167, /* 245 SECTION SIGN */ + 247, /* 246 DIVISION SIGN */ + 184, /* 247 CEDILLA */ + 176, /* 248 DEGREE SIGN */ + 168, /* 249 DIAERESIS */ + 183, /* 250 MIDDLE DOT */ + 185, /* 251 SUPERSCRIPT ONE */ + 179, /* 252 SUPERSCRIPT THREE */ + 178, /* 253 SUPERSCRIPT TWO */ + 0, /* 254 BLACK SQUARE */ + 160 /* 255 NO-BREAK SPACE */ +}; + +} // End of namespace Saga diff --git a/saga/font_mod.h b/saga/font_mod.h new file mode 100644 index 0000000000..dd3bbe887f --- /dev/null +++ b/saga/font_mod.h @@ -0,0 +1,71 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Font management and font drawing module public header + + Notes: +*/ + +#ifndef SAGA_FONT_MOD_H_ +#define SAGA_FONT_MOD_H_ + +namespace Saga { + +enum FONT_ID { + + SMALL_FONT_ID, + MEDIUM_FONT_ID, + BIG_FONT_ID +}; + +enum FONT_EFFECT_FLAGS { + + FONT_NORMAL = 0x00, + FONT_OUTLINE = 0x01, + FONT_SHADOW = 0x02, + FONT_BOLD = 0x04, + FONT_CENTERED = 0x08 +}; + +int FONT_Init(void); + +int FONT_Shutdown(void); + +int FONT_Draw(int font_id, + R_SURFACE * ds, + const char *draw_str, + size_t draw_str_len, + int text_x, int text_y, int color, int effect_color, int flags); + +int FONT_GetStringWidth(int font_id, + const char *test_str, size_t test_str_ct, int flags); + +int FONT_GetHeight(int font_id); + +} // End of namespace Saga + +#endif /* R_FONT_MOD_H_ */ +/* end "r_font_mod.h" */ diff --git a/saga/game.cpp b/saga/game.cpp new file mode 100644 index 0000000000..2f07cee1cd --- /dev/null +++ b/saga/game.cpp @@ -0,0 +1,839 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Game detection, general game parameters + + Notes: +*/ + +#include "reinherit.h" + +#include "yslib.h" + +/* + * Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "rscfile_mod.h" +#include "cvar_mod.h" +#include "ite_introproc_mod.h" +#include "interface_mod.h" + +/* + * Begin module component +\*--------------------------------------------------------------------------*/ +#include "game_mod.h" +#include "game.h" + +namespace Saga { + +/*--------------------------------------------------------------------------*\ + * Inherit the Earth - Demo version +\*--------------------------------------------------------------------------*/ + +R_GAME_FILEDESC ITEDEMO_GameFiles[] = { + + {"ITE.RSC", R_GAME_RESOURCEFILE} + , + {"ITE.DMO", R_GAME_DEMOFILE} + , + {"SCRIPTS.RSC", R_GAME_SCRIPTFILE} + , + {"VOICES.RSC", R_GAME_SOUNDFILE | R_GAME_VOICEFILE} +}; + +R_GAME_FONTDESC ITEDEMO_GameFonts[] = { + + {R_GAME_FONT_SMALL, 0} + , + {R_GAME_FONT_MEDIUM, 1} +}; + +R_GAME_SOUNDINFO ITEDEMO_GameSound = { + + R_GAME_SOUND_VOC +}; + +/*--------------------------------------------------------------------------*\ + * Inherit the Earth - Diskette version +\*--------------------------------------------------------------------------*/ + +R_GAME_FILEDESC ITEDISK_GameFiles[] = { + + {"ITE.RSC", R_GAME_RESOURCEFILE} + , + {"SCRIPTS.RSC", R_GAME_SCRIPTFILE} + , + {"VOICES.RSC", R_GAME_SOUNDFILE | R_GAME_VOICEFILE} +}; + +R_GAME_FONTDESC ITEDISK_GameFonts[] = { + + {R_GAME_FONT_MEDIUM, 0} + , + {R_GAME_FONT_LARGE, 1} + , + {R_GAME_FONT_SMALL, 2} +}; + +R_GAME_RESOURCEDESC ITE_Resources = { + ITE_SCENE_LUT, /* Scene lookup table RN */ + ITE_SCRIPT_LUT, /* Script lookup table RN */ + + ITE_COMMAND_PANEL, + ITE_DIALOGUE_PANEL +}; + +R_GAME_SOUNDINFO ITE_GameSound = { + + R_GAME_SOUND_VOC +}; + +/*--------------------------------------------------------------------------*\ + * Inherit the Earth - CD Enhanced version +\*--------------------------------------------------------------------------*/ + +R_GAME_FILEDESC ITECD_GameFiles[] = { + + {"ITE.RSC", R_GAME_RESOURCEFILE} + , + {"SCRIPTS.RSC", R_GAME_SCRIPTFILE} + , + {"SOUNDS.RSC", R_GAME_SOUNDFILE} + , + {"VOICES.RSC", R_GAME_VOICEFILE} +}; + +R_GAME_FONTDESC ITECD_GameFonts[] = { + + {R_GAME_FONT_MEDIUM, 0} + , + {R_GAME_FONT_LARGE, 1} + , + {R_GAME_FONT_SMALL, 2} +}; + +R_GAME_SOUNDINFO ITECD_GameSound = { + + R_GAME_SOUND_PCM, + 22050, + 16, + 0 +}; + +/*--------------------------------------------------------------------------*\ + * I Have No Mouth and I Must Scream - Demo version +\*--------------------------------------------------------------------------*/ + +R_GAME_FILEDESC IHNMDEMO_GameFiles[] = { + + {"SCREAM.RES", R_GAME_RESOURCEFILE} + , + {"SCRIPTS.RES", R_GAME_SCRIPTFILE} + , + {"SFX.RES", R_GAME_SOUNDFILE} + , + {"VOICESD.RES", R_GAME_VOICEFILE} +}; + +/*--------------------------------------------------------------------------*\ + * I Have No Mouth and I Must Scream - Retail CD version +\*--------------------------------------------------------------------------*/ + +R_GAME_FILEDESC IHNMCD_GameFiles[] = { + + {"MUSICFM.RES", R_GAME_MUSICFILE} + , + {"MUSICGM.RES", R_GAME_MUSICFILE} + , + {"SCREAM.RES", R_GAME_RESOURCEFILE} + , + {"SCRIPTS.RES", R_GAME_SCRIPTFILE} + , + {"SFX.RES", R_GAME_SOUNDFILE} + , + {"VOICES1.RES", R_GAME_VOICEFILE} + , + {"VOICES2.RES", R_GAME_VOICEFILE} + , + {"VOICES3.RES", R_GAME_VOICEFILE} + , + {"VOICES4.RES", R_GAME_VOICEFILE} + , + {"VOICES5.RES", R_GAME_VOICEFILE} + , + {"VOICES6.RES", R_GAME_VOICEFILE} + , + {"VOICESS.RES", R_GAME_VOICEFILE} +}; + +R_GAME_FONTDESC IHNMCD_GameFonts[] = { + + {R_GAME_FONT_MEDIUM, 2} + , + {R_GAME_FONT_LARGE, 3} + , + {R_GAME_FONT_SMALL, 4} + , + {R_GAME_FONT_SMALL2, 5} + , + {R_GAME_FONT_MEDIUM2, 6} + , + {R_GAME_FONT_LARGE2, 7} + , + {R_GAME_FONT_LARGE3, 8} +}; + +R_GAME_RESOURCEDESC IHNM_Resources[] = { + IHNM_SCENE_LUT, /* Scene lookup table RN */ + IHNM_SCRIPT_LUT, /* Script lookup table RN */ + + IHNM_COMMAND_PANEL, + IHNM_DIALOGUE_PANEL +}; + +R_GAME_SOUNDINFO IHNM_GameSound = { + + R_GAME_SOUND_WAV +}; + +R_GAMEDESC GameDescs[] = { + + /* Inherit the earth - Demo version + * \*------------------------------------------------------------- */ + { + R_GAMETYPE_ITE, + R_GAME_ITE_DEMO, /* Game id */ + "Inherit the Earth - Demo version", /* Game title */ + 320, 200, /* Logical resolution */ + 137, /* Scene viewport height */ + + ITE_DEFAULT_SCENE, /* Starting scene number */ + + &ITE_Resources, + + YS_NELEMS(ITEDEMO_GameFiles), /* Game datafiles */ + ITEDEMO_GameFiles, + + YS_NELEMS(ITEDEMO_GameFonts), + ITEDEMO_GameFonts, + + &ITEDEMO_GameSound, + + Verify_ITEDEMO, /* Game verification func */ + 0 /* Game supported flag */ + } + , + + /* Inherit the earth - Disk version + * \*------------------------------------------------------------- */ + { + R_GAMETYPE_ITE, + R_GAME_ITE_DISK, + "Inherit the Earth - Disk version", + 320, 200, + 137, + + ITE_DEFAULT_SCENE, + + &ITE_Resources, + + YS_NELEMS(ITEDISK_GameFiles), + ITEDISK_GameFiles, + + YS_NELEMS(ITEDISK_GameFonts), + ITEDISK_GameFonts, + + &ITE_GameSound, + + Verify_ITEDISK, + 1} + , + + /* Inherit the earth - CD version + * \*------------------------------------------------------------- */ + { + R_GAMETYPE_ITE, + R_GAME_ITE_CD, + "Inherit the Earth - CD version", + 320, 200, + 137, + + ITE_DEFAULT_SCENE, + + &ITE_Resources, + + YS_NELEMS(ITECD_GameFiles), + ITECD_GameFiles, + + YS_NELEMS(ITECD_GameFonts), + ITECD_GameFonts, + + &ITECD_GameSound, + + NULL, + 1} + , + + /* I Have No Mouth And I Must Scream - Demo version + * \*------------------------------------------------------------- */ + { + R_GAMETYPE_IHNM, + R_GAME_IHNM_DEMO, + "I Have No Mouth - Demo version", + 640, 480, + 304, + + 0, + + IHNM_Resources, + + YS_NELEMS(IHNMDEMO_GameFiles), + IHNMDEMO_GameFiles, + + 0, + NULL, + + &IHNM_GameSound, + + NULL, + 0} + , + + /* I Have No Mouth And I Must Scream - CD version + * \*------------------------------------------------------------- */ + { + R_GAMETYPE_IHNM, + R_GAME_IHNM_CD, + "I Have No Mouth - CD version", + 640, 480, + 304, + + 1, + + IHNM_Resources, + + YS_NELEMS(IHNMCD_GameFiles), + IHNMCD_GameFiles, + + YS_NELEMS(IHNMCD_GameFonts), + IHNMCD_GameFonts, + + &IHNM_GameSound, + + NULL, + 1} +}; + +static R_GAMEMODULE GameModule; + +void GAME_setGameDirectory(const char *gamedir) { + assert(gamedir != NULL); + + debug(0, "Using game data path: %s", gamedir); + + strcpy(GameModule.game_dir, gamedir); + strcpy(GameModule.data_dir, "."); +} + +int GAME_Register(void) +{ + + return R_SUCCESS; + + /* Register "gamedir" cfg cvar + * \*----------------------------------------- */ + strncpy(GameModule.game_dir, "./", R_MAXPATH); + + if (CVAR_Register_S(GameModule.game_dir, + "gamedir", NULL, R_CVAR_CFG, R_MAXPATH) != R_SUCCESS) { + + return R_FAILURE; + } + + /* Register "datadir" cfg cvar + * \*----------------------------------------- */ + strncpy(GameModule.data_dir, "./", R_MAXPATH); + + if (CVAR_Register_S(GameModule.data_dir, + "datadir", NULL, R_CVAR_CFG, R_MAXPATH) != R_SUCCESS) { + + return R_FAILURE; + } + + /* Register "g_language" cfg cvar + * \*----------------------------------------- */ + strncpy(GameModule.game_dir, "us", R_MAXPATH); + + if (CVAR_Register_S(GameModule.game_language, + "g_language", + NULL, R_CVAR_CFG, R_GAME_LANGSTR_LIMIT) != R_SUCCESS) { + + return R_FAILURE; + } + + /* Register "g_skipintro" cfg cvar + * \*----------------------------------------- */ + if (CVAR_Register_I(&GameModule.g_skipintro, + "g_skipintro", NULL, R_CVAR_CFG, 0, 1) != R_SUCCESS) { + return R_FAILURE; + } + + return R_SUCCESS; +} + +int GAME_Init(void) +{ + uint game_n; + char *game_dir; + + game_dir = GameModule.game_dir; + + if (DetectGame(game_dir, &game_n) != R_SUCCESS) { + + GameModule.err_str = "No valid games were found in the " + "specified directory."; + + return R_FAILURE; + } + + if (!GameDescs[game_n].gd_supported) { + + GameModule.err_str = "This game is not currently supported."; + + return R_FAILURE; + } + + if (LoadGame(game_dir, game_n) != R_SUCCESS) { + + GameModule.err_str = "Error loading game resource files."; + + return R_FAILURE; + } + + /* Load dialogue file + * \*------------------------------------------------------------- */ + LoadLanguage(); + + return R_SUCCESS; +} + +int LoadLanguage(void) +{ + + char lang_file[R_MAXPATH]; + char lang_path[R_MAXPATH]; + uint game_n; + + FILE *test_fp; + + game_n = GameModule.game_number; + + if (GameDescs[game_n].gd_game_type == R_GAMETYPE_ITE) { + + snprintf(lang_file, R_MAXPATH, + "%s%s.%s", + R_GAME_ITE_LANG_PREFIX, + GameModule.game_language, R_GAME_LANG_EXT); + + SYSFS_GetFQFN(GameModule.data_dir, + lang_file, lang_path, R_MAXPATH); + + test_fp = fopen(lang_path, "r"); + if (test_fp == NULL) { + + R_printf(R_STDOUT, + "Couldn't open language file %s. " + "Using default (US English)\n", lang_path); + + return R_SUCCESS; + } + + fclose(test_fp); + + if (INTERFACE_RegisterLang() != R_SUCCESS) { + R_printf(R_STDERR, + "Error registering interface language cvars."); + + return R_FAILURE; + } + + if (ITE_IntroRegisterLang() != R_SUCCESS) { + + R_printf(R_STDERR, + "Error registering intro sequence language cvars."); + + return R_FAILURE; + } + + R_printf(R_STDOUT, "Using language file %s.\n", lang_path); + + // FIXME + //CFG_Read(lang_path); + } else { + + R_printf(R_STDOUT, + "Language support for this game not implemented.\n"); + } + + return R_SUCCESS; +} + +int GAME_GetErrN(void) +{ + return 0; +} + +const char *GAME_GetErrS(void) +{ + + return GameModule.err_str == NULL + ? "No error description." : GameModule.err_str; +} + +int GAME_GetFileContext(R_RSCFILE_CONTEXT ** ctxt_p, uint r_type, int param) +{ + + R_RSCFILE_CONTEXT *found_ctxt = NULL; + uint i; + + YS_IGNORE_PARAM(param); + + if (ctxt_p == NULL) { + + return R_FAILURE; + } + + for (i = 0; i < GameModule.gfile_n; i++) { + + if (GameModule.gfile_data[i].file_types & r_type) { + + found_ctxt = GameModule.gfile_data[i].file_ctxt; + } + } + + if (found_ctxt != NULL) { + + *ctxt_p = found_ctxt; + } else { + + *ctxt_p = NULL; + } + + return R_SUCCESS; +} + +int DetectGame(const char *game_dir, uint * game_n_p) +{ + char game_fpath[R_GAME_PATH_LIMIT] = { 0 }; + + uint game_count = YS_NELEMS(GameDescs); + uint game_n; + + uint file_count; + uint file_n; + + FILE *test_fp; + + int file_missing = 0; + int found_game = 0; + int error; + + if ((game_dir == NULL) || (game_n_p == NULL)) { + + return R_FAILURE; + } + + for (game_n = 0; (game_n < game_count) && !found_game; game_n++) { + + file_count = GameDescs[game_n].gd_filect; + + file_missing = 0; + + /* Try to open all files for this game */ + for (file_n = 0; file_n < file_count; file_n++) { + + SYSFS_GetFQFN(game_dir, + GameDescs[game_n].gd_filedescs[file_n].gf_fname, + game_fpath, R_GAME_PATH_LIMIT); + test_fp = fopen(game_fpath, "rb"); + if (test_fp == NULL) { + + file_missing = 1; + + break; + } + + fclose(test_fp); + } + + /* Try the next game, couldn't find all files for the current + * game */ + if (file_missing) { + continue; + } + + /* If there's a verification function for this game, use it, + * otherwise assume we've found the game if all files are found. */ + found_game = 1; + + if (GameDescs[game_n].gd_verifyf != NULL && + GameDescs[game_n].gd_verifyf(game_dir) != R_SUCCESS) { + + found_game = 0; + } + + if (found_game) { + R_printf(R_STDOUT, + "Found game: %s\n", GameDescs[game_n].gd_title); + + *game_n_p = game_n; + + return R_SUCCESS; + } + } + + return R_FAILURE; +} + +int LoadGame(const char *game_dir, uint game_n) +{ + + R_RSCFILE_CONTEXT *load_ctxt; + + uint game_count = YS_NELEMS(GameDescs); + + char game_fpath[R_GAME_PATH_LIMIT] = { 0 }; + const char *game_fname; + uint game_filect; + + uint i; + + if ((game_dir == NULL) || (game_n >= game_count)) { + + return R_FAILURE; + } + + game_filect = GameDescs[game_n].gd_filect; + + GameModule.gfile_data = (R_GAME_FILEDATA *)malloc(game_filect * + sizeof *GameModule.gfile_data); + if (GameModule.gfile_data == NULL) { + + return R_MEM; + } + + GameModule.gfile_n = game_filect; + + /* Load game resource files + * \*------------------------------------------------------------- */ + for (i = 0; i < game_filect; i++) { + + load_ctxt = RSC_CreateContext(); + + game_fname = GameDescs[game_n].gd_filedescs[i].gf_fname; + + SYSFS_GetFQFN(game_dir, + game_fname, game_fpath, R_GAME_PATH_LIMIT); + + if (RSC_OpenContext(load_ctxt, game_fpath) != R_SUCCESS) { + + return R_FAILURE; + } + + R_printf(R_STDOUT, "Opened resource file: %s\n", game_fname); + + GameModule.gfile_data[i].file_ctxt = load_ctxt; + GameModule.gfile_data[i].file_types = + GameDescs[game_n].gd_filedescs[i].gf_type; + + GameModule.gfile_data[i].file_flags = 0; + } + + /* Load game font data + * \*------------------------------------------------------------- */ + GameModule.gd_fontct = GameDescs[game_n].gd_fontct; + GameModule.gd_fontdescs = GameDescs[game_n].gd_fontdescs; + + /* Finish initialization + * \*------------------------------------------------------------- */ + GameModule.game_number = game_n; + GameModule.gamedesc = &GameDescs[game_n]; + + GameModule.game_init = 1; + + return R_SUCCESS; +} + +int GAME_GetResourceInfo(R_GAME_RESOURCEDESC * rsc_desc) +{ + assert(rsc_desc != NULL); + + *rsc_desc = *GameModule.gamedesc->gd_resource_desc; + + return R_SUCCESS; +} + +int GAME_GetSoundInfo(R_GAME_SOUNDINFO * snd_info) +{ + assert(snd_info != NULL); + + *snd_info = *GameModule.gamedesc->gd_soundinfo; + + return R_SUCCESS; +} + +int GAME_GetDisplayInfo(R_GAME_DISPLAYINFO * disp_info) +{ + + int game_n; + + assert(disp_info != NULL); + + if (!GameModule.game_init) { + return R_FAILURE; + } + + game_n = GameModule.game_number; + + disp_info->logical_w = GameDescs[game_n].gd_logical_w; + disp_info->logical_h = GameDescs[game_n].gd_logical_h; + disp_info->scene_h = GameDescs[game_n].gd_scene_h; + + return R_SUCCESS; +} + +int GAME_GetFontInfo(R_GAME_FONTDESC ** gf_desc, int *font_n) +{ + + assert((gf_desc != NULL) && (font_n != NULL)); + + *gf_desc = GameModule.gd_fontdescs; + *font_n = GameModule.gd_fontct; + + return R_SUCCESS; +} + +int GAME_GetSceneInfo(R_GAME_SCENEDESC * gs_desc) +{ + + assert(gs_desc != NULL); + + gs_desc->first_scene = GameModule.gamedesc->gd_startscene; + gs_desc->scene_lut_rn = + GameModule.gamedesc->gd_resource_desc->scene_lut_rn; + + return R_SUCCESS; +} + +int GAME_GetGame(void) +{ + + return GameModule.gamedesc->gd_game_id; +} + +int GAME_GetGameType(void) +{ + + return GameModule.gamedesc->gd_game_type; +} + +int Verify_ITEDEMO(const char *game_dir) +{ + + YS_IGNORE_PARAM(game_dir); + + return R_SUCCESS; +} + +int Verify_ITEDISK(const char *game_dir) +{ + + R_RSCFILE_CONTEXT *test_ctx; + + char fpath[R_GAME_PATH_LIMIT] = { 0 }; + + ulong script_lut_len; + ulong script_lut_rn; + + int verified = 0; + + test_ctx = RSC_CreateContext(); + + SYSFS_GetFQFN(game_dir, "ITE.RSC", fpath, R_GAME_PATH_LIMIT); + + if (RSC_OpenContext(test_ctx, fpath) != R_SUCCESS) { + return R_FAILURE; + } + + script_lut_rn = + GameDescs[R_GAME_ITE_DISK].gd_resource_desc->script_lut_rn; + + if (RSC_GetResourceSize(test_ctx, + script_lut_rn, &script_lut_len) != R_SUCCESS) { + + RSC_DestroyContext(test_ctx); + + return R_FAILURE; + } + + RSC_DestroyContext(test_ctx); + + if (script_lut_len % R_SCR_LUT_ENTRYLEN_ITEDISK == 0) { + + verified = 1; + } + + if (!verified) { + return R_FAILURE; + } + + return R_SUCCESS; +} + +int Verify_ITECD(const char *game_dir) +{ + + YS_IGNORE_PARAM(game_dir); + + return R_SUCCESS; +} + +int Verify_IHNMDEMO(const char *game_dir) +{ + + YS_IGNORE_PARAM(game_dir); + + return R_SUCCESS; +} + +int Verify_IHNMCD(const char *game_dir) +{ + + YS_IGNORE_PARAM(game_dir); + + return R_SUCCESS; +} + +} // End of namespace Saga diff --git a/saga/game.h b/saga/game.h new file mode 100644 index 0000000000..1c16b9b5fa --- /dev/null +++ b/saga/game.h @@ -0,0 +1,133 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Game detection, general game parameters + + Notes: +*/ + +#ifndef SAGA_GAME_H_ +#define SAGA_GAME_H_ + +namespace Saga { + +#define R_GAME_LANGSTR_LIMIT 3 +#define R_GAME_PATH_LIMIT 512 + +#define R_GAME_ITE_LANG_PREFIX "ite_" +#define R_GAME_LANG_EXT "lng" + +/* Script lookup table entry sizes for game verification */ +#define R_SCR_LUT_ENTRYLEN_ITECD 22 +#define R_SCR_LUT_ENTRYLEN_ITEDISK 16 + +typedef int (*R_GAME_VERIFYFUNC) (const char *); + +typedef struct R_GAME_FILEDESC_tag { + + const char *gf_fname; + uint gf_type; + +} R_GAME_FILEDESC; + +typedef struct R_GAMEDESC_tag { + + int gd_game_type; + int gd_game_id; + + const char *gd_title; + + int gd_logical_w; + int gd_logical_h; + int gd_scene_h; + + int gd_startscene; + + R_GAME_RESOURCEDESC *gd_resource_desc; + + int gd_filect; + R_GAME_FILEDESC *gd_filedescs; + + int gd_fontct; + R_GAME_FONTDESC *gd_fontdescs; + + R_GAME_SOUNDINFO *gd_soundinfo; + + R_GAME_VERIFYFUNC gd_verifyf; + + int gd_supported; + +} R_GAMEDESC; + +typedef struct R_GAME_FILEDATA_tag { + + R_RSCFILE_CONTEXT *file_ctxt; + + uint file_types; + uint file_flags; + +} R_GAME_FILEDATA; + +typedef struct R_GAMEMODULE_tag { + + int game_init; + int game_number; + + R_GAMEDESC *gamedesc; + + int g_skipintro; + + char game_dir[R_MAXPATH]; + char data_dir[R_MAXPATH]; + + char game_language[R_GAME_LANGSTR_LIMIT]; + + uint gfile_n; + R_GAME_FILEDATA *gfile_data; + + uint gd_fontct; + R_GAME_FONTDESC *gd_fontdescs; + + int err_n; + const char *err_str; + +} R_GAMEMODULE; + +int LoadLanguage(void); + +int DetectGame(const char *game_dir, uint * game_n_p); + +int LoadGame(const char *game_dir, uint game_n_p); + +int Verify_ITEDEMO(const char *game_dir); +int Verify_ITEDISK(const char *game_dir); +int Verify_ITECD(const char *game_dir); +int Verify_IHNMDEMO(const char *game_dir); +int Verify_IHNMCD(const char *game_dit); + +} // End of namespace Saga + +#endif /* R_GAME_H_ */ +/* end "r_game.h" */ diff --git a/saga/gamedesc.h b/saga/game_mod.h index 8a7cfbf3d3..1292688b91 100644 --- a/saga/gamedesc.h +++ b/saga/game_mod.h @@ -1,5 +1,7 @@ /* ScummVM - Scumm Interpreter - * Copyright (C) 2003 The ScummVM project + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -8,7 +10,7 @@ * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License @@ -18,47 +20,53 @@ * $Header$ * */ +/* + Description: + + Game detection, general game parameters - module header -#ifndef SAGA_GAMEDESC_H -#define SAGA_GAMEDESC_H - -#include "resfile.h" + Notes: +*/ -/* Public stuff */ +#ifndef SAGA_GAME_MOD_H__ +#define SAGA_GAME_MOD_H__ namespace Saga { enum R_GAME_BASETYPES { + R_GAMETYPE_ITE, R_GAMETYPE_IHNM }; enum R_GAME_IDS { - R_GAME_ITE_DEMO = 0, - R_GAME_ITE_DISK = 1, - R_GAME_ITE_CD = 2, + + R_GAME_ITE_DEMO = 0, + R_GAME_ITE_DISK = 1, + R_GAME_ITE_CD = 2, R_GAME_IHNM_DEMO = 3, - R_GAME_IHNM_CD = 4 + R_GAME_IHNM_CD = 4 }; enum R_GAME_FILETYPES { + R_GAME_RESOURCEFILE = 0x01, - R_GAME_SCRIPTFILE = 0x02, - R_GAME_SOUNDFILE = 0x04, - R_GAME_VOICEFILE = 0x08, - R_GAME_DEMOFILE = 0x10, - R_GAME_MUSICFILE = 0x20, - - R_GAME_EXCLUDE = 0x8000 + R_GAME_SCRIPTFILE = 0x02, + R_GAME_SOUNDFILE = 0x04, + R_GAME_VOICEFILE = 0x08, + R_GAME_DEMOFILE = 0x10, + R_GAME_MUSICFILE = 0x20 }; enum R_GAME_SOUNDINFO_TYPES { + R_GAME_SOUND_PCM = 0, R_GAME_SOUND_VOC, R_GAME_SOUND_WAV }; enum R_GAME_FONT_IDS { + R_GAME_FONT_SMALL = 0, R_GAME_FONT_MEDIUM, R_GAME_FONT_LARGE, @@ -69,61 +77,72 @@ enum R_GAME_FONT_IDS { }; typedef struct R_GAME_DISPLAYINFO_tag { + int logical_w; int logical_h; int scene_h; - int ovl_pal_start; - int ovl_pal_end; - } R_GAME_DISPLAYINFO; typedef struct R_GAMESOUND_INFO_tag { - int res_type; + + int res_type; long freq; - int sample_size; - int stereo; - + int sample_size; + int stereo; + } R_GAME_SOUNDINFO; typedef struct R_GAMEFONT_DESC_tag { - unsigned int font_id; - unsigned long font_rn; - + + uint font_id; + ulong font_rn; + } R_GAME_FONTDESC; typedef struct R_GAMESCENE_DESC_tag { - unsigned long scene_lut_rn; - unsigned long first_scene; + + ulong scene_lut_rn; + ulong first_scene; } R_GAME_SCENEDESC; -typedef struct R_GAME_RESOURCEINFO_tag { - unsigned long scene_lut_rn; - unsigned long script_lut_rn; +typedef struct R_GAMERESOURCE_DESC_tag { - unsigned long overlay_pal_rn; + ulong scene_lut_rn; + ulong script_lut_rn; + ulong command_panel_rn; + ulong dialogue_panel_rn; - unsigned long command_panel_rn; - unsigned long command_buttons_rn; +} R_GAME_RESOURCEDESC; - unsigned long dialogue_panel_rn; - unsigned long lportraits_rn; +int GAME_Register(void); - unsigned long actor_tbl_rn; +int GAME_Init(void); -} R_GAME_RESOURCEINFO; +int GAME_GetFileContext(R_RSCFILE_CONTEXT ** ctxt_p, uint r_type, int param); - void setGameDirectory( const char *gamedir ); - int detectGame(); - bool openGame(); +int GAME_GetFontInfo(R_GAME_FONTDESC **, int *); -} // End of namespace Saga +int GAME_GetResourceInfo(R_GAME_RESOURCEDESC *); -#endif +int GAME_GetSoundInfo(R_GAME_SOUNDINFO *); +int GAME_GetDisplayInfo(R_GAME_DISPLAYINFO *); +int GAME_GetSceneInfo(R_GAME_SCENEDESC *); +int GAME_GetGame(void); +int GAME_GetGameType(void); +int GAME_GetErrN(void); + +void GAME_setGameDirectory(const char *gamedir); + +const char *GAME_GetErrS(void); + +} // End of namespace Saga +#endif /* R_GAME_MOD_H__ */ +/* end "r_game_mod.h" */ diff --git a/saga/gamedesc.cpp b/saga/gamedesc.cpp deleted file mode 100644 index 7464ad6d2f..0000000000 --- a/saga/gamedesc.cpp +++ /dev/null @@ -1,449 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2003 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * $Header$ - * - */ - -#include "stdafx.h" - -#include "common/scummsys.h" -#include "base/engine.h" -#include "common/util.h" -#include "common/file.h" - -#include "resfile.h" -#include "resnames.h" -#include "gamedesc.h" -#include "gamedesc_priv.h" - -namespace Saga { - -/*--------------------------------------------------------------------------*\ - * Inherit the Earth - Demo version -\*--------------------------------------------------------------------------*/ - -R_GAME_FILEDESC ITEDEMO_GameFiles[] = { - { "ITE.RSC", R_GAME_RESOURCEFILE }, - { "ITE.DMO", R_GAME_DEMOFILE }, - { "SCRIPTS.RSC", R_GAME_SCRIPTFILE }, - { "VOICES.RSC", R_GAME_SOUNDFILE | R_GAME_VOICEFILE } -}; - -R_GAME_FONTDESC ITEDEMO_GameFonts[] = { - { R_GAME_FONT_SMALL, 0 }, - { R_GAME_FONT_MEDIUM, 1 } -}; - -R_GAME_SOUNDINFO ITEDEMO_GameSound = { - R_GAME_SOUND_VOC, 0, 0, 0 -}; - -/*--------------------------------------------------------------------------*\ - * Inherit the Earth - Diskette version -\*--------------------------------------------------------------------------*/ - -R_GAME_FILEDESC ITEDISK_GameFiles[] = { - { "ITE.RSC", R_GAME_RESOURCEFILE }, - { "SCRIPTS.RSC", R_GAME_SCRIPTFILE }, - { "VOICES.RSC", R_GAME_SOUNDFILE | R_GAME_VOICEFILE } -}; - -R_GAME_FONTDESC ITEDISK_GameFonts[] = { - { R_GAME_FONT_MEDIUM, 0 }, - { R_GAME_FONT_LARGE, 1 }, - { R_GAME_FONT_SMALL, 2 } -}; - -R_GAME_DISPLAYINFO ITE_DisplayInfo = { - 320, 200, /* Logical width and height */ - 137, /* Scene playfield height */ - 0, 0 /* Overlay palette start index and length */ -}; - -R_GAME_RESOURCEINFO ITE_Resources = { - ITE_SCENE_LUT, /* Scene lookup table RN */ - ITE_SCRIPT_LUT, /* Script lookup table RN */ - - ITE_OVERLAY_PAL, /* Overlay palette RN */ - - ITE_COMMAND_PANEL, - ITE_COMMAND_BUTTONSPRITES, - - ITE_DIALOGUE_PANEL, - ITE_DEFAULT_PORTRAITS, - - ITE_ACTOR_PERSONA_TBL -}; - -R_GAME_SOUNDINFO ITE_GameSound = { - R_GAME_SOUND_VOC, 0, 0, 0 -}; - -/*--------------------------------------------------------------------------*\ - * Inherit the Earth - CD Enhanced version -\*--------------------------------------------------------------------------*/ - -R_GAME_FILEDESC ITECD_GameFiles[] = { - { "ITE.RSC", R_GAME_RESOURCEFILE }, - { "SCRIPTS.RSC", R_GAME_SCRIPTFILE }, - { "SOUNDS.RSC", R_GAME_SOUNDFILE }, - { "VOICES.RSC", R_GAME_VOICEFILE } -}; - -R_GAME_FONTDESC ITECD_GameFonts[] = { - { R_GAME_FONT_MEDIUM, 0 }, - { R_GAME_FONT_LARGE, 1 }, - { R_GAME_FONT_SMALL, 2 } -}; - -R_GAME_SOUNDINFO ITECD_GameSound = { - R_GAME_SOUND_PCM, - 22050, - 16, - 0 -}; - -/*--------------------------------------------------------------------------*\ - * I Have No Mouth and I Must Scream - Demo version -\*--------------------------------------------------------------------------*/ - -R_GAME_FILEDESC IHNMDEMO_GameFiles[] = { - { "SCREAM.RES", R_GAME_RESOURCEFILE }, - { "SCRIPTS.RES", R_GAME_SCRIPTFILE }, - { "SFX.RES", R_GAME_SOUNDFILE }, - { "VOICESD.RES", R_GAME_VOICEFILE } -}; - -/*--------------------------------------------------------------------------*\ - * I Have No Mouth and I Must Scream - Retail CD version -\*--------------------------------------------------------------------------*/ - -R_GAME_FILEDESC IHNMCD_GameFiles[] = { - { "MUSICFM.RES", R_GAME_MUSICFILE }, - { "MUSICGM.RES", R_GAME_MUSICFILE }, - { "SCREAM.RES", R_GAME_RESOURCEFILE }, - { "SCRIPTS.RES", R_GAME_SCRIPTFILE }, - { "SFX.RES", R_GAME_SOUNDFILE }, - { "VOICES1.RES", R_GAME_VOICEFILE }, - { "VOICES2.RES", R_GAME_VOICEFILE }, - { "VOICES3.RES", R_GAME_VOICEFILE }, - { "VOICES4.RES", R_GAME_VOICEFILE }, - { "VOICES5.RES", R_GAME_VOICEFILE }, - { "VOICES6.RES", R_GAME_VOICEFILE }, - { "VOICESS.RES", R_GAME_VOICEFILE } -}; - -R_GAME_FONTDESC IHNMCD_GameFonts[] = { - { R_GAME_FONT_MEDIUM, 2 }, - { R_GAME_FONT_LARGE, 3 }, - { R_GAME_FONT_SMALL, 4 }, - { R_GAME_FONT_SMALL2, 5 }, - { R_GAME_FONT_MEDIUM2, 6 }, - { R_GAME_FONT_LARGE2, 7 }, - { R_GAME_FONT_LARGE3, 8 } -}; - -R_GAME_DISPLAYINFO IHNM_DisplayInfo = { - 640, 480, /* Logical width and height */ - 304, /* Scene playfield height */ - 248, 255 /* Overlay palette start index and length */ -}; - -R_GAME_RESOURCEINFO IHNM_Resources = { - IHNM_SCENE_LUT, /* Scene lookup table RN */ - IHNM_SCRIPT_LUT, /* Script lookup table RN */ - - IHNM_OVERLAY_PAL, /* Overlay palette RN */ - - IHNM_COMMAND_PANEL, - IHNM_COMMAND_BUTTONSPRITES, - - IHNM_DIALOGUE_PANEL, - IHNM_DEFAULT_PORTRAITS, - - IHNM_ACTOR_PERSONA_TBL -}; - - -R_GAME_SOUNDINFO IHNM_GameSound = { - R_GAME_SOUND_WAV, 0, 0, 0 -}; - -R_GAMEDESC GameDescs[] = { - /* Inherit the earth - Demo version - \*-------------------------------------------------------------*/ - { - R_GAMETYPE_ITE, - R_GAME_ITE_DEMO, /* Game id */ - "Inherit the Earth - Demo version", /* Game title */ - - &ITE_DisplayInfo, - - ITE_DEFAULT_SCENE, /* Starting scene number */ - - &ITE_Resources, - - ARRAYSIZE(ITEDEMO_GameFiles), /* Game datafiles */ - ITEDEMO_GameFiles, - - ARRAYSIZE(ITEDEMO_GameFonts), - ITEDEMO_GameFonts, - - &ITEDEMO_GameSound, - - 0 /* Game supported flag */ - }, - - /* Inherit the earth - Disk version - \*-------------------------------------------------------------*/ - { - R_GAMETYPE_ITE, - R_GAME_ITE_DISK, - "Inherit the Earth - Disk version", - - &ITE_DisplayInfo, - - ITE_DEFAULT_SCENE, - - &ITE_Resources, - - ARRAYSIZE(ITEDISK_GameFiles), - ITEDISK_GameFiles, - - ARRAYSIZE(ITEDISK_GameFonts), - ITEDISK_GameFonts, - - &ITE_GameSound, - - 1 - }, - - /* Inherit the earth - CD version - \*-------------------------------------------------------------*/ - { - R_GAMETYPE_ITE, - R_GAME_ITE_CD, - "Inherit the Earth - CD version", - - &ITE_DisplayInfo, - - ITE_DEFAULT_SCENE, - - &ITE_Resources, - - ARRAYSIZE( ITECD_GameFiles ), - ITECD_GameFiles, - - ARRAYSIZE( ITECD_GameFonts ), - ITECD_GameFonts, - - &ITECD_GameSound, - - 1 - }, - - /* I Have No Mouth And I Must Scream - Demo version - \*-------------------------------------------------------------*/ - { - R_GAMETYPE_IHNM, - R_GAME_IHNM_DEMO, - "I Have No Mouth - Demo version", - - &IHNM_DisplayInfo, - - 0, - - &IHNM_Resources, - - ARRAYSIZE(IHNMDEMO_GameFiles), - IHNMDEMO_GameFiles, - - 0, - NULL, - - &IHNM_GameSound, - - 0 - }, - - /* I Have No Mouth And I Must Scream - CD version - \*-------------------------------------------------------------*/ - { - R_GAMETYPE_IHNM, - R_GAME_IHNM_CD, - "I Have No Mouth - CD version", - - &IHNM_DisplayInfo, - - 1, - - &IHNM_Resources, - - ARRAYSIZE(IHNMCD_GameFiles), - IHNMCD_GameFiles, - - ARRAYSIZE(IHNMCD_GameFonts), - IHNMCD_GameFonts, - - &IHNM_GameSound, - - 1 - } -}; - -static R_GAMEMODULE GameModule; - -void setGameDirectory(const char *gamedir) { - assert(gamedir != NULL); - - debug(1, "Using game data path: %s", gamedir); - - GameModule.game_dir = gamedir; -} - -int detectGame() { - File test_file; - - bool disqualified = false; - bool found_game = false; - - int file_n; - int file_ct; - const char *file_name; - - int game_n; - int game_ct = ARRAYSIZE(GameDescs); - - assert(GameModule.game_dir != NULL); - - for (game_n = 0; game_n < game_ct; game_n++) { - disqualified = false; - - /* Attempt to open all files for this game - * If we can open them all, then try to open all files on the - * exclude list - */ - file_ct = GameDescs[game_n].gd_filect; - - for (file_n = 0; file_n < file_ct; file_n++) { - file_name = GameDescs[game_n].gd_filedescs[file_n].gf_fname; - if (!test_file.open(file_name, GameModule.game_dir)) { - disqualified = true; - break; - } - - test_file.close(); - } - - if (disqualified) { - continue; - } - - switch (GameDescs[game_n].gd_game_id) { - - case R_GAME_ITE_DEMO: - disqualified = !verifyITEDEMO(); - break; - case R_GAME_ITE_DISK: - disqualified = !verifyITEDISK(); - break; - - default: - break; - } - - if (!disqualified) { - found_game = true; - break; - } - } - - if (found_game) { - debug(1, "Found SAGA game: %s\n", GameDescs[game_n].gd_title); - return game_n; - } - - return -1; -} - -bool openGame() { - int game_filect; - - if ((GameModule.game_index = detectGame()) < 0) { - error("Couldn't locate any valid SAGA games"); - return false; - } - - assert(GameModule.game_index < ARRAYSIZE(GameDescs)); - - if (!GameModule.game_dir) { - return false; - } - - game_filect = GameDescs[GameModule.game_index].gd_filect; - - GameModule.gfile_data = new R_GAME_FILEDATA[game_filect]; - - return true; -} - -bool verifyITEDEMO() { - return true; -} - -bool verifyITEDISK() { - ResourceFile test_file; - int32 script_lut_rn; - int32 script_lut_len; - - /* Attempt to verify the disk version of Inherit the Earth - * by examining the length of entries in the script lookup - * table, which differs from the disk version and the CD - * version. - */ - - assert (GameModule.game_dir != NULL); - - if (!test_file.open("ITE.RSC", GameModule.game_dir)) { - return false; - } - - script_lut_rn = GameDescs[R_GAME_ITE_DISK].gd_resource_info->script_lut_rn; - - script_lut_len = test_file.getResourceLen(script_lut_rn); - - if (script_lut_len % R_SCR_LUT_ENTRYLEN_ITEDISK == 0) { - return true; - } - - return false; -} - -bool verifyITECD() { - return true; -} - -bool verifyIHNMDEMO() { - return true; -} - -bool verifyIHNMCD() { - return true; -} - -} // End of namespace Saga diff --git a/saga/gamedesc_priv.h b/saga/gamedesc_priv.h index b017ba7a90..ee8dd36909 100644 --- a/saga/gamedesc_priv.h +++ b/saga/gamedesc_priv.h @@ -1,5 +1,7 @@ /* ScummVM - Scumm Interpreter - * Copyright (C) 2003 The ScummVM project + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -40,68 +42,64 @@ namespace Saga { #define R_SCR_LUT_ENTRYLEN_ITECD 22 #define R_SCR_LUT_ENTRYLEN_ITEDISK 16 -typedef bool (ResourceFile::*R_GAME_VERIFYFUNC)(); +typedef bool(ResourceFile::*R_GAME_VERIFYFUNC) (); typedef struct R_GAME_FILEDESC_tag { - const char *gf_fname; - unsigned int gf_type; + const char *gf_fname; + unsigned int gf_type; } R_GAME_FILEDESC; typedef struct R_GAMEDESC_tag { - int gd_game_type; - int gd_game_id; + int gd_game_type; + int gd_game_id; - const char *gd_title; + const char *gd_title; - R_GAME_DISPLAYINFO *gd_display_info; + R_GAME_DISPLAYINFO *gd_display_info; - int gd_startscene; + int gd_startscene; - R_GAME_RESOURCEINFO *gd_resource_info; + R_GAME_RESOURCEINFO *gd_resource_info; - int gd_filect; - R_GAME_FILEDESC *gd_filedescs; - - int gd_fontct; - R_GAME_FONTDESC *gd_fontdescs; - - R_GAME_SOUNDINFO *gd_soundinfo; + int gd_filect; + R_GAME_FILEDESC *gd_filedescs; - int gd_supported; + int gd_fontct; + R_GAME_FONTDESC *gd_fontdescs; -} R_GAMEDESC; + R_GAME_SOUNDINFO *gd_soundinfo; + int gd_supported; +} R_GAMEDESC; typedef struct R_GAME_FILEDATA_tag { - ResourceFile *file_ctxt; - - unsigned int file_types; - unsigned int file_flags; + ResourceFile *file_ctxt; + unsigned int file_types; + unsigned int file_flags; } R_GAME_FILEDATA; - typedef struct R_GAMEMODULE_tag { - int game_init; - int game_index; - - R_GAMEDESC *gamedesc; + int game_init; + int game_index; + + R_GAMEDESC *gamedesc; - int g_skipintro; + int g_skipintro; - const char *game_dir; - - char game_language[R_GAME_LANGSTR_LIMIT]; + const char *game_dir; - unsigned int gfile_n; - R_GAME_FILEDATA *gfile_data; + char game_language[R_GAME_LANGSTR_LIMIT]; - unsigned int gd_fontct; - R_GAME_FONTDESC *gd_fontdescs; + unsigned int gfile_n; + R_GAME_FILEDATA *gfile_data; - int err_n; - const char *err_str; + unsigned int gd_fontct; + R_GAME_FONTDESC *gd_fontdescs; + + int err_n; + const char *err_str; } R_GAMEMODULE; @@ -111,9 +109,5 @@ bool verifyITECD(); bool verifyIHNMDEMO(); bool verifyIHNMCD(); -} // End of namespace Saga - -#endif // SAGA_GAMEDESC_PRIV_H - - - +} // End of namespace Saga +#endif // SAGA_GAMEDESC_PRIV_H diff --git a/saga/gfx.cpp b/saga/gfx.cpp new file mode 100644 index 0000000000..7ea6a5f342 --- /dev/null +++ b/saga/gfx.cpp @@ -0,0 +1,1098 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Misc. graphics routines + + Notes: + + Line drawing code utilizes Bresenham's run-length slice algorithm + described in "Michael Abrash's Graphics Programming Black Book", + Coriolis Group Books, 1997 +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "yslib.h" + +#include "reinherit.h" + +/* + * Begin module component +\*--------------------------------------------------------------------------*/ +#include "gfx_mod.h" +#include "gfx.h" + +namespace Saga { + +int GFX_ClearSurface(char *buf, int w, int h, int p) +{ + + int y; + + for (y = 0; y < h; y++) { + memset(buf, 0, w); + buf += p; + } + + return R_SUCCESS; +} + +int GFX_ClearSurface16(char *buf, int w, int h, int p) +{ + + int y; + w <<= 1; + + for (y = 0; y < h; y++) { + memset(buf, 0, w); + buf += p; + } + + return R_SUCCESS; +} + +int GFX_DrawPalette(R_SURFACE * dst_s) +{ + int x; + int y; + + int color = 0; + + R_RECT pal_rect; + + for (y = 0; y < 16; y++) { + + pal_rect.y1 = (y * 8) + 4; + pal_rect.y2 = pal_rect.y1 + 8; + + for (x = 0; x < 16; x++) { + + pal_rect.x1 = (x * 8) + 4; + pal_rect.x2 = pal_rect.x1 + 8; + + GFX_DrawRect(dst_s, &pal_rect, color); + color++; + } + } + + return 0; +} + +int GFX_SimpleBlit(R_SURFACE * dst_s, R_SURFACE * src_s) +{ + uchar *src_p; + uchar *dst_p; + int y, w, p; + + assert((dst_s != NULL) && (src_s != NULL)); + assert(dst_s->buf_w == src_s->buf_w); + assert(dst_s->buf_h == src_s->buf_h); + + src_p = src_s->buf; + dst_p = dst_s->buf; + + w = src_s->buf_w * (dst_s->bpp / 8); + p = src_s->buf_pitch; + + for (y = 0; y < src_s->buf_h; y++) { + + memcpy(dst_p, src_p, w); + + dst_p += p; + src_p += p; + } + + return R_SUCCESS; +} + +int GFX_Scale2x(R_SURFACE * dst_s, R_SURFACE * src_s) +{ + + assert((dst_s != NULL) && (src_s != NULL)); + assert((dst_s->bpp == src_s->bpp)); + + switch (dst_s->bpp) { + + case 8: + return GFX_Scale2x8(dst_s, src_s); + break; + + case 16: + return GFX_Scale2x16(dst_s, src_s); + break; + + default: + break; + + } + + return R_FAILURE; +} + +int GFX_Scale2x8(R_SURFACE * dst_s, R_SURFACE * src_s) +{ + + int y, x; + + int src_skip = src_s->buf_pitch - src_s->buf_w; + int dst_skip = dst_s->buf_pitch - dst_s->buf_w; + + uchar *src_ptr = src_s->buf; + uchar *dst_ptr = dst_s->buf; + + uchar *src_row; + uchar *dst_row; + + assert(dst_s->buf_w == (src_s->buf_w * 2)); + assert(dst_s->buf_h == (src_s->buf_h * 2)); + + for (y = 0; y < src_s->buf_h; y++) { + + src_row = src_ptr; + dst_row = dst_ptr; + + for (x = 0; x < src_s->buf_w; x++) { + *dst_ptr++ = *src_ptr; + *dst_ptr++ = *src_ptr++; + } + + dst_ptr += dst_skip; + + memcpy(dst_ptr, dst_row, dst_s->buf_w); + + dst_ptr += dst_s->buf_pitch; + src_ptr += src_skip; + } + + return R_SUCCESS; +} + +int GFX_Scale2x16(R_SURFACE * dst_s, R_SURFACE * src_s) +{ + int y, x; + + int src_skip; + int dest_skip; + + uchar *src_ptr = src_s->buf; + uchar *dest_ptr = dst_s->buf; + + short *src_row; + short *dest_row; + + assert((dst_s != NULL) && (src_s != NULL)); + + src_skip = (src_s->buf_pitch - src_s->buf_w) / sizeof(short); + dest_skip = (dst_s->buf_pitch - dst_s->buf_w) / sizeof(short); + + for (y = 0; y < src_s->buf_h; y++) { + + src_row = (short *)src_ptr; + dest_row = (short *)dest_ptr; + + for (x = 0; x < src_s->buf_w; x++) { + *dest_row++ = *src_row; + *dest_row++ = *src_row++; + } + + src_ptr += src_s->buf_pitch; + + memcpy(dest_ptr + dst_s->buf_pitch, dest_ptr, + dst_s->buf_w << 1); + + dest_ptr += dst_s->buf_pitch; + dest_ptr += dst_s->buf_pitch; + } + + return R_SUCCESS; +} + +int +GFX_BufToSurface(R_SURFACE * ds, + const uchar * src, + int src_w, int src_h, R_RECT * src_rect, R_POINT * dst_pt) +/*--------------------------------------------------------------------------*\ + * Copies a rectangle from a raw 8 bit pixel buffer to the specified surface. + * The buffer is of width 'src_w' and height 'src_h'. The rectangle to be + * copied is defined by 'src_rect'. + * The rectangle is copied to the destination surface at point 'dst_pt'. + * - If dst_pt is NULL, the buffer is rectangle is copied to the destination + * origin. + * - If src_rect is NULL, the entire buffer is copied. + * - The surface must match the logical dimensions of the buffer exactly. + * - Returns R_FAILURE on error +\*--------------------------------------------------------------------------*/ +{ + + const uchar *read_p; + uchar *write_p; + + int row; + + int s_x1, s_y1, s_x2, s_y2; + int d_x, d_y; + + int clip_x1, clip_y1, clip_x2, clip_y2; + + int dst_off_x, dst_off_y; + int src_off_x, src_off_y; + int src_draw_w, src_draw_h; + + /* Clamp source rectangle to source buffer + * \*------------------------------------------------------------- */ + if (src_rect != NULL) { + + R_CLAMP_RECT(src_rect, 0, (src_w - 1), 0, (src_h - 1)); + + s_x1 = src_rect->x1; + s_y1 = src_rect->y1; + s_x2 = src_rect->x2; + s_y2 = src_rect->y2; + + if ((s_x1 >= s_x2) || (s_y1 >= s_y2)) { + /* Empty or negative region */ + return R_FAILURE; + } + } else { + s_x1 = 0; + s_y1 = 0; + s_x2 = src_w - 1; + s_y2 = src_h - 1; + } + + /* Get destination origin and clip rectangle + * \*------------------------------------------------------------- */ + if (dst_pt != NULL) { + d_x = dst_pt->x; + d_y = dst_pt->y; + } else { + d_x = 0; + d_y = 0; + } + + clip_x1 = ds->clip_rect.x1; + clip_y1 = ds->clip_rect.y1; + clip_x2 = ds->clip_rect.x2; + clip_y2 = ds->clip_rect.y2; + + if (clip_x1 == clip_x2) { + clip_x1 = 0; + clip_x2 = ds->buf_w - 1; + } + + if (clip_y1 == clip_y2) { + clip_y1 = 0; + clip_y2 = ds->buf_h - 1; + } + + /* Clip source rectangle to destination surface + * \*------------------------------------------------------------- */ + dst_off_x = d_x; + dst_off_y = d_y; + src_off_x = s_x1; + src_off_y = s_y1; + src_draw_w = (s_x2 - s_x1) + 1; + src_draw_h = (s_y2 - s_y1) + 1; + + /* Clip to left edge */ + + if (d_x < clip_x1) { + if (d_x <= (-src_draw_w)) { + /* dst rect completely off left edge */ + return R_SUCCESS; + } + + src_off_x += (clip_x1 - d_x); + src_draw_w -= (clip_x1 - d_x); + + dst_off_x = clip_x1; + } + + /* Clip to top edge */ + + if (d_y < clip_y1) { + if (d_y >= (-src_draw_h)) { + /* dst rect completely off top edge */ + return R_SUCCESS; + } + + src_off_y += (clip_y1 - d_y); + src_draw_h -= (clip_y1 - d_y); + + dst_off_y = clip_y1; + } + + /* Clip to right edge */ + + if (d_x > clip_x2) { + /* dst rect completely off right edge */ + return R_SUCCESS; + } + + if ((d_x + src_draw_w - 1) > clip_x2) { + src_draw_w -= (clip_x2 - (d_x + src_draw_w - 1)); + } + + /* Clip to bottom edge */ + + if (d_x > clip_y2) { + /* dst rect completely off bottom edge */ + return R_SUCCESS; + } + + if ((d_y + src_draw_h - 1) > clip_y2) { + src_draw_h -= (clip_y2 - (d_y + src_draw_h - 1)); + } + + /* Transfer buffer data to surface + * \*------------------------------------------------------------- */ + read_p = (src + src_off_x) + (src_w * src_off_y); + write_p = (ds->buf + dst_off_x) + (ds->buf_pitch * dst_off_y); + + for (row = 0; row < src_draw_h; row++) { + + memcpy(write_p, read_p, src_draw_w); + + write_p += ds->buf_pitch; + read_p += src_w; + } + + return R_SUCCESS; +} + +int +GFX_BufToBuffer(uchar * dst_buf, + int dst_w, + int dst_h, + const uchar * src, + int src_w, int src_h, R_RECT * src_rect, R_POINT * dst_pt) +/*--------------------------------------------------------------------------*\ +\*--------------------------------------------------------------------------*/ +{ + + const uchar *read_p; + uchar *write_p; + + int row; + + int s_x1, s_y1, s_x2, s_y2; + int d_x, d_y; + + int clip_x1, clip_y1, clip_x2, clip_y2; + + int dst_off_x, dst_off_y; + int src_off_x, src_off_y; + int src_draw_w, src_draw_h; + + /* Clamp source rectangle to source buffer + * \*------------------------------------------------------------- */ + if (src_rect != NULL) { + + R_CLAMP_RECT(src_rect, 0, (src_w - 1), 0, (src_h - 1)); + + s_x1 = src_rect->x1; + s_y1 = src_rect->y1; + s_x2 = src_rect->x2; + s_y2 = src_rect->y2; + + if ((s_x1 >= s_x2) || (s_y1 >= s_y2)) { + /* Empty or negative region */ + return R_FAILURE; + } + } else { + s_x1 = 0; + s_y1 = 0; + s_x2 = src_w - 1; + s_y2 = src_h - 1; + } + + /* Get destination origin and clip rectangle + * \*------------------------------------------------------------- */ + if (dst_pt != NULL) { + d_x = dst_pt->x; + d_y = dst_pt->y; + } else { + d_x = 0; + d_y = 0; + } + + clip_x1 = 0; + clip_y1 = 0; + clip_x2 = dst_w - 1; + clip_y2 = dst_h - 1; + + /* Clip source rectangle to destination surface + * \*------------------------------------------------------------- */ + dst_off_x = d_x; + dst_off_y = d_y; + src_off_x = s_x1; + src_off_y = s_y1; + src_draw_w = (s_x2 - s_x1) + 1; + src_draw_h = (s_y2 - s_y1) + 1; + + /* Clip to left edge */ + + if (d_x < clip_x1) { + if (d_x <= (-src_draw_w)) { + /* dst rect completely off left edge */ + return R_SUCCESS; + } + + src_off_x += (clip_x1 - d_x); + src_draw_w -= (clip_x1 - d_x); + + dst_off_x = clip_x1; + } + + /* Clip to top edge */ + + if (d_y < clip_y1) { + if (d_y >= (-src_draw_h)) { + /* dst rect completely off top edge */ + return R_SUCCESS; + } + + src_off_y += (clip_y1 - d_y); + src_draw_h -= (clip_y1 - d_y); + + dst_off_y = clip_y1; + } + + /* Clip to right edge */ + + if (d_x > clip_x2) { + /* dst rect completely off right edge */ + return R_SUCCESS; + } + + if ((d_x + src_draw_w - 1) > clip_x2) { + src_draw_w -= (clip_x2 - (d_x + src_draw_w - 1)); + } + + /* Clip to bottom edge */ + + if (d_x > clip_y2) { + /* dst rect completely off bottom edge */ + return R_SUCCESS; + } + + if ((d_y + src_draw_h - 1) > clip_y2) { + src_draw_h -= (clip_y2 - (d_y + src_draw_h - 1)); + } + + /* Transfer buffer data to surface + * \*------------------------------------------------------------- */ + read_p = (src + src_off_x) + (src_w * src_off_y); + write_p = (dst_buf + dst_off_x) + (dst_w * dst_off_y); + + for (row = 0; row < src_draw_h; row++) { + + memcpy(write_p, read_p, src_draw_w); + + write_p += dst_w; + read_p += src_w; + } + + return R_SUCCESS; +} + +int GFX_DrawCursor(R_SURFACE * ds, R_POINT * p1) +{ + + static uchar cursor_img[R_CURSOR_W * R_CURSOR_H] = { + + 0, 0, 0, 255, 0, 0, 0, + 0, 0, 0, 255, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 255, 255, 0, 0, 0, 255, 255, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 255, 0, 0, 0, + 0, 0, 0, 255, 0, 0, 0 + }; + + R_CLIPINFO ci; + + uchar *src_p, *dst_p; + + int x, y; + int src_skip, dst_skip; + + R_POINT cur_pt; + R_RECT cur_rect; + + /* Clamp point to surface */ + cur_pt.x = YS_MAX(p1->x, 0); + cur_pt.y = YS_MAX(p1->y, 0); + + cur_pt.x = YS_MIN(p1->x, ds->buf_w - 1); + cur_pt.y = YS_MIN(p1->y, ds->buf_h - 1); + + cur_pt.x -= R_CURSOR_ORIGIN_X; + cur_pt.y -= R_CURSOR_ORIGIN_Y; + + /* Clip cursor to surface */ + + cur_rect.x1 = 0; + cur_rect.y1 = 0; + cur_rect.x2 = R_CURSOR_W - 1; + cur_rect.y2 = R_CURSOR_H - 1; + + ci.dst_rect = &ds->clip_rect; + ci.src_rect = &cur_rect; + ci.dst_pt = &cur_pt; + + GFX_GetClipInfo(&ci); + + src_p = cursor_img + ci.src_draw_x + (ci.src_draw_y * R_CURSOR_W); + dst_p = ds->buf + ci.dst_draw_x + (ci.dst_draw_y * ds->buf_pitch); + + src_skip = R_CURSOR_W - ci.draw_w; + dst_skip = ds->buf_pitch - ci.draw_w; + + for (y = 0; y < ci.draw_h; y++) { + + for (x = 0; x < ci.draw_w; x++) { + + if (*src_p != 0) { + *dst_p = *src_p; + } + + dst_p++; + src_p++; + } + + src_p += src_skip; + dst_p += dst_skip; + } + + return R_SUCCESS; + +} + +int GFX_DrawRect(R_SURFACE * ds, R_RECT * dst_rect, int color) +/*--------------------------------------------------------------------------*\ + * Fills a rectangle in the surface ds from point 'p1' to point 'p2' using + * the specified color. +\*--------------------------------------------------------------------------*/ +{ + uchar *write_p; + + int w; + int h; + int row; + + int x1, y1, x2, y2; + + if (dst_rect != NULL) { + + R_CLAMP_RECT(dst_rect, 0, (ds->buf_w - 1), 0, (ds->buf_h - 1)); + + x1 = dst_rect->x1; + y1 = dst_rect->y1; + x2 = dst_rect->x2; + y2 = dst_rect->y2; + + if ((x1 >= x2) || (y1 >= y2)) { + /* Empty or negative region */ + return R_FAILURE; + } + } else { + x1 = 0; + y1 = 0; + x2 = ds->buf_w - 1; + y2 = ds->buf_h - 1; + } + + w = (x2 - x1) + 1; + h = (y2 - y1) + 1; + + write_p = ds->buf + (ds->buf_pitch * y1) + x1; + + for (row = 0; row < h; row++) { + memset(write_p, color, w); + write_p += ds->buf_pitch; + } + + return R_SUCCESS; +} + +int GFX_DrawFrame(R_SURFACE * ds, R_POINT * p1, R_POINT * p2, int color) +{ + int x1, y1, x2, y2; + + int min_x; + int max_x; + int min_y; + int max_y; + + R_POINT n_p1; /* 1 .. 2 */ + R_POINT n_p2; /* . . */ + R_POINT n_p3; /* . . */ + R_POINT n_p4; /* 4 .. 3 */ + + assert((ds != NULL) && (p1 != NULL) && (p2 != NULL)); + + x1 = p1->x; + y1 = p1->y; + x2 = p2->x; + y2 = p2->y; + + min_x = YS_MIN(x1, x2); + min_y = YS_MIN(y1, y2); + max_x = YS_MAX(x1, x2); + max_y = YS_MAX(y1, y2); + + n_p1.x = min_x; + n_p1.y = min_y; + n_p2.x = max_x; + n_p2.y = min_y; + n_p3.x = max_x; + n_p3.y = max_y; + n_p4.x = min_x; + n_p4.y = max_y; + + GFX_DrawLine(ds, &n_p1, &n_p2, color); + GFX_DrawLine(ds, &n_p2, &n_p3, color); + GFX_DrawLine(ds, &n_p3, &n_p4, color); + GFX_DrawLine(ds, &n_p4, &n_p1, color); + + return R_SUCCESS; +} + +int GFX_DrawPolyLine(R_SURFACE * ds, R_POINT * pts, int pt_ct, int draw_color) +{ + + R_POINT *first_pt = pts; + int last_i = 1; + int i; + + assert((ds != NULL) & (pts != NULL)); + + if (pt_ct < 3) { + return R_FAILURE; + } + + for (i = 1; i < pt_ct; i++) { + + GFX_DrawLine(ds, &pts[i], &pts[i - 1], draw_color); + last_i = i; + } + + GFX_DrawLine(ds, &pts[last_i], first_pt, draw_color); + + return R_SUCCESS; +} + +int GFX_GetClipInfo(R_CLIPINFO * clipinfo) +{ + + int s_x1, s_y1, s_x2, s_y2; + int d_x, d_y; + + int clip_x1, clip_y1, clip_x2, clip_y2; + + if (clipinfo == NULL) { + return R_FAILURE; + } + + if (clipinfo->dst_pt != NULL) { + d_x = clipinfo->dst_pt->x; + d_y = clipinfo->dst_pt->y; + } else { + d_x = 0; + d_y = 0; + } + + s_x1 = clipinfo->src_rect->x1; + s_y1 = clipinfo->src_rect->y1; + s_x2 = clipinfo->src_rect->x2; + s_y2 = clipinfo->src_rect->y2; + + clip_x1 = clipinfo->dst_rect->x1; + clip_y1 = clipinfo->dst_rect->y1; + clip_x2 = clipinfo->dst_rect->x2; + clip_y2 = clipinfo->dst_rect->y2; + + /* Clip source rectangle to destination surface + * \*------------------------------------------------------------- */ + clipinfo->dst_draw_x = d_x; + clipinfo->dst_draw_y = d_y; + clipinfo->src_draw_x = s_x1; + clipinfo->src_draw_y = s_y1; + clipinfo->draw_w = (s_x2 - s_x1) + 1; + clipinfo->draw_h = (s_y2 - s_y1) + 1; + + clipinfo->nodraw = 0; + + /* Clip to left edge */ + + if (d_x < clip_x1) { + if (d_x <= -(clipinfo->draw_w)) { + /* dst rect completely off left edge */ + clipinfo->nodraw = 1; + + return R_SUCCESS; + } + + clipinfo->src_draw_x += (clip_x1 - d_x); + clipinfo->draw_w -= (clip_x1 - d_x); + + clipinfo->dst_draw_x = clip_x1; + } + + /* Clip to top edge */ + + if (d_y < clip_y1) { + if (d_y <= -(clipinfo->draw_h)) { + /* dst rect completely off top edge */ + clipinfo->nodraw = 1; + + return R_SUCCESS; + } + + clipinfo->src_draw_y += (clip_y1 - d_y); + clipinfo->draw_h -= (clip_y1 - d_y); + + clipinfo->dst_draw_y = clip_y1; + } + + /* Clip to right edge */ + + if (d_x > clip_x2) { + /* dst rect completely off right edge */ + clipinfo->nodraw = 1; + + return R_SUCCESS; + } + + if ((d_x + clipinfo->draw_w - 1) > clip_x2) { + clipinfo->draw_w += (clip_x2 - (d_x + clipinfo->draw_w - 1)); + } + + /* Clip to bottom edge */ + + if (d_y > clip_y2) { + /* dst rect completely off bottom edge */ + clipinfo->nodraw = 1; + + return R_SUCCESS; + } + + if ((d_y + clipinfo->draw_h - 1) > clip_y2) { + clipinfo->draw_h += (clip_y2 - (d_y + clipinfo->draw_h - 1)); + } + + return R_SUCCESS; +} + +int +GFX_ClipLine(R_SURFACE * ds, + const R_POINT * src_p1, + const R_POINT * src_p2, R_POINT * dst_p1, R_POINT * dst_p2) +{ + + const R_POINT *n_p1; + const R_POINT *n_p2; + + int clip_x1, clip_y1, clip_x2, clip_y2; + int x1, y1, x2, y2; + int dx, dy; + + float m; + int y_icpt_l, y_icpt_r; + + clip_x1 = ds->clip_rect.x1; + clip_y1 = ds->clip_rect.y1; + clip_x2 = ds->clip_rect.x2; + clip_y2 = ds->clip_rect.y2; + + /* Normalize points by x */ + if (src_p1->x < src_p2->x) { + n_p1 = src_p1; + n_p2 = src_p2; + } else { + n_p1 = src_p2; + n_p2 = src_p1; + } + + dst_p1->x = n_p1->x; + dst_p1->y = n_p1->y; + + dst_p2->x = n_p2->x; + dst_p2->y = n_p2->y; + + x1 = n_p1->x; + y1 = n_p1->y; + + x2 = n_p2->x; + y2 = n_p2->y; + + dx = x2 - x1; + dy = y2 - y1; + + if (x1 < 0) { + + if (x2 < 0) { + /* Line completely off left edge */ + return -1; + } + + /* Clip to left edge */ + m = ((float)y2 - y1) / (x2 - x1); + y_icpt_l = (int)(y1 - (x1 * m) + 0.5f); + + dst_p1->x = 0; + dst_p1->y = y_icpt_l; + } + + if (y2 > clip_x2) { + + if (x1 > clip_x2) { + /* Line completely off right edge */ + return -1; + } + + /* Clip to right edge */ + m = ((float)y1 - y2) / (x2 - x1); + y_icpt_r = (int)(y1 - ((clip_x2 - x1) * m) + 0.5f); + + dst_p1->y = y_icpt_r; + dst_p2->x = clip_x2; + } + + return 1; +} + +void GFX_DrawLine(R_SURFACE * ds, R_POINT * p1, R_POINT * p2, int color) +/*--------------------------------------------------------------------------*\ + * Utilizes Bresenham's run-length slice algorithm described in + * "Michael Abrash's Graphics Programming Black Book", + * Coriolis Group Books, 1997 + * + * Performs no clipping +\*--------------------------------------------------------------------------*/ +{ + + uchar *write_p; + + int clip_result; + + int temp; + + int error_up, error_down; + int error; + + int x_vector; + int dx, dy; + + int min_run; + int init_run; + int run; + int end_run; + + R_POINT clip_p1, clip_p2; + int x1, y1, x2, y2; + int i, k; + + clip_result = GFX_ClipLine(ds, p1, p2, &clip_p1, &clip_p2); + if (clip_result < 0) { + /* Line not visible */ + return; + } + + x1 = clip_p1.x; + y1 = clip_p1.y; + + x2 = clip_p2.x; + y2 = clip_p2.y; + + if ((x1 < ds->clip_rect.x1) || (x2 < ds->clip_rect.x1) || + (x1 > ds->clip_rect.x2) || (x2 > ds->clip_rect.x2)) { + + return; + } + + if ((y1 < ds->clip_rect.y1) || (y2 < ds->clip_rect.y1) || + (y1 > ds->clip_rect.y2) || (y2 > ds->clip_rect.y2)) { + + return; + } + + if (y1 > y2) { + + temp = y1; + y1 = y2; + y2 = temp; + + temp = x1; + x1 = x2; + x2 = temp; + } + + write_p = ds->buf + (y1 * ds->buf_pitch) + x1; + + dx = x2 - x1; + + if (dx < 0) { + x_vector = -1; + dx = -dx; + } else { + x_vector = 1; + } + + dy = y2 - y1; + + if (dx == 0) { + for (i = 0; i <= dy; i++) { + *write_p = (uchar) color; + write_p += ds->buf_pitch; + } + return; + } + if (dy == 0) { + for (i = 0; i <= dx; i++) { + *write_p = (uchar) color; + write_p += x_vector; + } + return; + } + if (dx == dy) { + for (i = 0; i <= dx; i++) { + *write_p = (uchar) color; + write_p += x_vector + ds->buf_pitch; + } + return; + } + + if (dx >= dy) { + + min_run = dx / dy; + error_up = (dx % dy) * 2; + error_down = dy * 2; + error = (dx % dy) - (dy * 2); + init_run = (min_run / 2) + 1; + end_run = init_run; + + if ((error_up == 0) && (min_run & 0x01) == 0) { + init_run--; + } + + error += dy; + + /* Horiz. seg */ + for (k = 0; k < init_run; k++) { + *write_p = (uchar) color; + write_p += x_vector; + } + write_p += ds->buf_pitch; + /**********/ + + for (i = 0; i < (dy - 1); i++) { + run = min_run; + if ((error += error_up) > 0) { + + run++; + error -= error_down; + } + + /* Horiz. seg */ + for (k = 0; k < run; k++) { + *write_p = (uchar) color; + write_p += x_vector; + } + write_p += ds->buf_pitch; + /**********/ + } + + /* Horiz. seg */ + for (k = 0; k < end_run; k++) { + *write_p = (uchar) color; + write_p += x_vector; + } + write_p += ds->buf_pitch; + /**********/ + return; + + } else { + + min_run = dy / dx; + + error_up = (dy % dx) * 2; + + error_down = dx * 2; + error = (dy % dx) - (dx * 2); + + init_run = (min_run / 2) + 1; + end_run = init_run; + + if ((error_up == 0) && ((min_run & 0x01) == 0)) { + init_run--; + } + + if ((min_run & 0x01) != 0) { + error += dx; + } + + /* Vertical seg */ + for (k = 0; k < init_run; k++) { + *write_p = (uchar) color; + write_p += ds->buf_pitch; + } + write_p += x_vector; + /***********/ + + for (i = 0; i < (dx - 1); i++) { + run = min_run; + if ((error += error_up) > 0) { + run++; + error -= error_down; + } + + /* Vertical seg */ + for (k = 0; k < run; k++) { + *write_p = (uchar) color; + write_p += ds->buf_pitch; + } + write_p += x_vector; + /***********/ + } + + /* Vertical seg */ + for (k = 0; k < end_run; k++) { + *write_p = (uchar) color; + write_p += ds->buf_pitch; + } + write_p += x_vector; + /***********/ + return; + } + + return; +} + +} // End of namespace Saga diff --git a/saga/gfx.h b/saga/gfx.h new file mode 100644 index 0000000000..99389e91d2 --- /dev/null +++ b/saga/gfx.h @@ -0,0 +1,54 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Graphics maniuplation routines - private header file + + Notes: +*/ + +#ifndef SAGA_GFX_H_ +#define SAGA_GFX_H_ + +namespace Saga { + +#define R_CURSOR_W 7 +#define R_CURSOR_H 7 + +#define R_CURSOR_ORIGIN_X 4 +#define R_CURSOR_ORIGIN_Y 4 + +#define R_CLAMP(a, min, max) \ + (a = (a < (min)) ? (min) : ((a > max) ? (max) : a )) + +#define R_CLAMP_RECT( rect, xmin, xmax, ymin, ymax ) \ + R_CLAMP( rect->x1, xmin, xmax ); \ + R_CLAMP( rect->x2, xmin, xmax ); \ + R_CLAMP( rect->y1, ymin, ymax ); \ + R_CLAMP( rect->y2, ymin, ymax ) + +} // End of namespace Saga + +#endif /* R_GFX_H_ */ +/* end "r_gfx_h_ */ diff --git a/saga/gfx_mod.h b/saga/gfx_mod.h new file mode 100644 index 0000000000..bfb0fc76a5 --- /dev/null +++ b/saga/gfx_mod.h @@ -0,0 +1,99 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Graphics manipulation routines - module header file + + Notes: +*/ + +#ifndef SAGA_GFX_MOD_H_ +#define SAGA_GFX_MOD_H_ + +namespace Saga { + +typedef struct R_CLIPINFO_tag { + + /* input members */ + const R_RECT *src_rect; + const R_RECT *dst_rect; + const R_POINT *dst_pt; + + /* output members */ + int nodraw; + int src_draw_x; + int src_draw_y; + int dst_draw_x; + int dst_draw_y; + int draw_w; + int draw_h; + +} R_CLIPINFO; + +int GFX_SimpleBlit(R_SURFACE * dst_s, R_SURFACE * src_s); + +int GFX_Scale2x(R_SURFACE * dst_s, R_SURFACE * src_s); + +int GFX_Scale2x8(R_SURFACE * dst_s, R_SURFACE * src_s); + +int GFX_Scale2x16(R_SURFACE * dst_s, R_SURFACE * src_s); + +int GFX_SLScale2x16(char *dest_buf, + int dest_w, + int dest_p, int dst_h, char *src_buf, int src_w, int src_p, int src_h); + +int GFX_ClearSurface(char *buf, int w, int h, int p); +int GFX_ClearSurface16(char *buf, int w, int h, int p); + +int GFX_DrawPalette(R_SURFACE * dst_s); + +int GFX_BufToSurface(R_SURFACE * ds, + const uchar * src, + int src_w, int src_h, R_RECT * src_rect, R_POINT * dst_pt); + +int +GFX_BufToBuffer(uchar * dst_buf, + int dst_w, + int dst_h, + const uchar * src, + int src_w, int src_h, R_RECT * src_rect, R_POINT * dst_pt); + +int GFX_DrawCursor(R_SURFACE * ds, R_POINT * p1); +int GFX_DrawRect(R_SURFACE * ds, R_RECT * dst_rect, int color); +int GFX_DrawFrame(R_SURFACE * ds, R_POINT * p1, R_POINT * p2, int color); +int GFX_DrawPolyLine(R_SURFACE * ds, R_POINT * pts, int pt_ct, int draw_color); + +int GFX_GetClipInfo(R_CLIPINFO * clipinfo); + +int +GFX_ClipLine(R_SURFACE * ds, + const R_POINT * src_p1, + const R_POINT * src_p2, R_POINT * dst_p1, R_POINT * dst_p2); + +void GFX_DrawLine(R_SURFACE * ds, R_POINT * p1, R_POINT * p2, int color); + +} // End of namespace Saga + +#endif /* R_GFX_MOD_H_ */ +/* end "r_gfx_mod.h" */ diff --git a/saga/ihnm_introproc.cpp b/saga/ihnm_introproc.cpp new file mode 100644 index 0000000000..8656881f14 --- /dev/null +++ b/saga/ihnm_introproc.cpp @@ -0,0 +1,360 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + "I Have No Mouth" Intro sequence scene procedures + + Notes: +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "yslib.h" + +#include "reinherit.h" + +/* + * Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "animation_mod.h" +#include "cvar_mod.h" +#include "events_mod.h" +#include "font_mod.h" +#include "rscfile_mod.h" +#include "scene_mod.h" +#include "text_mod.h" +#include "palanim_mod.h" + +/* + * Begin module: +\*--------------------------------------------------------------------------*/ +#include "scene.h" +#include "ihnm_introproc.h" + +namespace Saga { + +R_SCENE_RESLIST IHNM_IntroMovie1RL[] = { + + {30, SAGA_BG_IMAGE} + , + {31, SAGA_ANIM_1} +}; + +R_SCENE_DESC IHNM_IntroMovie1Desc = { + + 0, 0, 0, 0, 0, 0, 0, 0, + IHNM_IntroMovie1RL, + YS_NELEMS(IHNM_IntroMovie1RL) + +}; + +R_SCENE_RESLIST IHNM_IntroMovie2RL[] = { + + {32, SAGA_BG_IMAGE} + , + {33, SAGA_ANIM_1} +}; + +R_SCENE_DESC IHNM_IntroMovie2Desc = { + + 0, 0, 0, 0, 0, 0, 0, 0, + IHNM_IntroMovie2RL, + YS_NELEMS(IHNM_IntroMovie2RL) + +}; + +R_SCENE_RESLIST IHNM_IntroMovie3RL[] = { + + {34, SAGA_BG_IMAGE} + , + {35, SAGA_ANIM_1} +}; + +R_SCENE_DESC IHNM_IntroMovie3Desc = { + + 0, 0, 0, 0, 0, 0, 0, 0, + IHNM_IntroMovie3RL, + YS_NELEMS(IHNM_IntroMovie3RL) + +}; + +R_SCENE_RESLIST IHNM_IntroMovie4RL[] = { + + {1227, SAGA_BG_IMAGE} + , + {1226, SAGA_ANIM_1} +}; + +R_SCENE_DESC IHNM_IntroMovie4Desc = { + + 0, 0, 0, 0, 0, 0, 0, 0, + IHNM_IntroMovie4RL, + YS_NELEMS(IHNM_IntroMovie4RL) + +}; + +R_SCENE_QUEUE IHNM_IntroList[] = { + {0, &IHNM_IntroMovie1Desc, BY_DESC, IHNM_IntroMovieProc1, 0} + , + {0, &IHNM_IntroMovie2Desc, BY_DESC, IHNM_IntroMovieProc2, 0} + , + {0, &IHNM_IntroMovie3Desc, BY_DESC, IHNM_IntroMovieProc3, 0} + , + {0, &IHNM_IntroMovie4Desc, BY_DESC, IHNM_HateProc, 0} +}; + +int IHNM_StartProc(void) +{ + size_t n_introscenes; + size_t i; + + n_introscenes = YS_NELEMS(IHNM_IntroList); + + for (i = 0; i < n_introscenes; i++) { + + SCENE_Queue(&IHNM_IntroList[i]); + } + + return R_SUCCESS; +} + +int IHNM_IntroMovieProc1(int param, R_SCENE_INFO * scene_info) +{ + + R_EVENT event = { 0 }; + + YS_IGNORE_PARAM(scene_info); + + switch (param) { + + case SCENE_BEGIN: + + /* Background for intro scene is the first frame of the + * intro animation; display it and set the palette + \*-----------------------------------------------------*/ + event.type = R_ONESHOT_EVENT; + event.code = R_BG_EVENT; + event.op = EVENT_DISPLAY; + event.param = SET_PALETTE; + event.time = 0; + + EVENT_Queue(&event); + + ANIM_SetFrameTime(0, R_IHNM_INTRO_FRAMETIME); + ANIM_SetFlag(0, ANIM_ENDSCENE); + ANIM_Play(0, 0); + break; + + default: + break; + } + + return 0; +} + +int IHNM_IntroMovieProc2(int param, R_SCENE_INFO * scene_info) +{ + + R_EVENT event = { 0 }; + R_EVENT *q_event; + + PALENTRY *pal; + + static PALENTRY current_pal[R_PAL_ENTRIES]; + + YS_IGNORE_PARAM(scene_info); + + switch (param) { + + case SCENE_BEGIN: + + /* Fade to black out of the intro CyberDreams logo anim + * \*----------------------------------------------------- */ + SYSGFX_GetCurrentPal(current_pal); + + event.type = R_CONTINUOUS_EVENT; + event.code = R_PAL_EVENT; + event.op = EVENT_PALTOBLACK; + event.time = 0; + event.duration = R_IHNM_PALFADE_TIME; + event.data = current_pal; + + q_event = EVENT_Queue(&event); + + /* Background for intro scene is the first frame of the + * intro animation; display it but don't set palette + \*-----------------------------------------------------*/ + event.type = R_ONESHOT_EVENT; + event.code = R_BG_EVENT; + event.op = EVENT_DISPLAY; + event.param = NO_SET_PALETTE; + event.time = 0; + + q_event = EVENT_Chain(q_event, &event); + + /* Fade in from black to the scene background palette + * \*----------------------------------------------------- */ + SCENE_GetBGPal(&pal); + + event.type = R_CONTINUOUS_EVENT; + event.code = R_PAL_EVENT; + event.op = EVENT_BLACKTOPAL; + event.time = 0; + event.duration = R_IHNM_PALFADE_TIME; + event.data = pal; + + q_event = EVENT_Chain(q_event, &event); + + ANIM_SetFlag(0, ANIM_LOOP); + ANIM_Play(0, R_IHNM_PALFADE_TIME * 2); + + /* Queue end of scene after looping animation for a while + * \*----------------------------------------------------- */ + event.type = R_ONESHOT_EVENT; + event.code = R_SCENE_EVENT; + event.op = EVENT_END; + event.time = R_IHNM_DGLOGO_TIME; + + q_event = EVENT_Chain(q_event, &event); + + break; + + default: + break; + } + + return 0; +} + +int IHNM_IntroMovieProc3(int param, R_SCENE_INFO * scene_info) +{ + + R_EVENT event = { 0 }; + R_EVENT *q_event; + + PALENTRY *pal; + + static PALENTRY current_pal[R_PAL_ENTRIES]; + + YS_IGNORE_PARAM(scene_info); + + switch (param) { + + case SCENE_BEGIN: + + /* Fade to black out of the intro DG logo anim + * \*----------------------------------------------------- */ + SYSGFX_GetCurrentPal(current_pal); + + event.type = R_CONTINUOUS_EVENT; + event.code = R_PAL_EVENT; + event.op = EVENT_PALTOBLACK; + event.time = 0; + event.duration = R_IHNM_PALFADE_TIME; + event.data = current_pal; + + q_event = EVENT_Queue(&event); + + /* Background for intro scene is the first frame of the + * intro animation; display it but don't set palette + \*-----------------------------------------------------*/ + event.type = R_ONESHOT_EVENT; + event.code = R_BG_EVENT; + event.op = EVENT_DISPLAY; + event.param = NO_SET_PALETTE; + event.time = 0; + + q_event = EVENT_Chain(q_event, &event); + + /* Fade in from black to the scene background palette + * \*----------------------------------------------------- */ + SCENE_GetBGPal(&pal); + + event.type = R_CONTINUOUS_EVENT; + event.code = R_PAL_EVENT; + event.op = EVENT_BLACKTOPAL; + event.time = 0; + event.duration = R_IHNM_PALFADE_TIME; + event.data = pal; + + q_event = EVENT_Chain(q_event, &event); + + ANIM_Play(0, 0); + + /* Queue end of scene after a while + * \*----------------------------------------------------- */ + event.type = R_ONESHOT_EVENT; + event.code = R_SCENE_EVENT; + event.op = EVENT_END; + event.time = R_IHNM_TITLE_TIME; + + q_event = EVENT_Chain(q_event, &event); + + break; + + default: + break; + } + + return 0; +} + +int IHNM_HateProc(int param, R_SCENE_INFO * scene_info) +{ + + R_EVENT event = { 0 }; + R_EVENT *q_event; + + YS_IGNORE_PARAM(scene_info); + + switch (param) { + + case SCENE_BEGIN: + + /* Background for intro scene is the first frame of the + * intro animation; display it and set the palette + \*-----------------------------------------------------*/ + event.type = R_ONESHOT_EVENT; + event.code = R_BG_EVENT; + event.op = EVENT_DISPLAY; + event.param = SET_PALETTE; + event.time = 0; + + q_event = EVENT_Queue(&event); + + ANIM_SetFlag(0, ANIM_LOOP); + ANIM_Play(0, 0); + + break; + + default: + break; + } + + return 0; +} + +} // End of namespace Saga diff --git a/saga/ihnm_introproc.h b/saga/ihnm_introproc.h new file mode 100644 index 0000000000..7bfffa3fba --- /dev/null +++ b/saga/ihnm_introproc.h @@ -0,0 +1,44 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Intro sequence scene procedures header file + + Notes: +*/ + +#ifndef SAGA_ITE_INTRO_H_ +#define SAGA_ITE_INTRO_H_ + +namespace Saga { + +#define R_IHNM_PALFADE_TIME 1000 +#define R_IHNM_INTRO_FRAMETIME 80 +#define R_IHNM_DGLOGO_TIME 8000 +#define R_IHNM_TITLE_TIME 16000 + +} // End of namespace Saga + +#endif /* R_IHNM_INTRO_H_ */ +/* end "r_ihnm_introproc.h */ diff --git a/saga/image.cpp b/saga/image.cpp new file mode 100644 index 0000000000..d63e6c1088 --- /dev/null +++ b/saga/image.cpp @@ -0,0 +1,510 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + SAGA Image resource management routines + + Notes: +*/ + +#include "reinherit.h" + +#include "yslib.h" + +/* + * Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "game_mod.h" + +/* + * Begin module +\*--------------------------------------------------------------------------*/ +#include "image_mod.h" +#include "image.h" + +namespace Saga { + +int +IMG_DecodeBGImage(const uchar * image_data, + size_t image_size, + uchar ** output_buf, size_t * output_buf_len, int *w, int *h) +{ + + R_IMAGE_HEADER hdr; + int modex_height; + + const uchar *RLE_data_ptr; + size_t RLE_data_len; + + uchar *decode_buf; + size_t decode_buf_len; + + uchar *out_buf; + size_t out_buf_len; + + const uchar *read_p = image_data; + + if (image_size <= SAGA_IMAGE_DATA_OFFSET) { + /* Image size is way too small */ + return R_FAILURE; + } + + hdr.width = ys_read_u16_le(read_p, &read_p); + hdr.height = ys_read_u16_le(read_p, &read_p); + hdr.unknown4 = ys_read_u16_le(read_p, &read_p); + hdr.unknown6 = ys_read_u16_le(read_p, &read_p); + + RLE_data_ptr = image_data + SAGA_IMAGE_DATA_OFFSET; + RLE_data_len = image_size - SAGA_IMAGE_DATA_OFFSET; + + modex_height = Granulate(hdr.height, 4); + + decode_buf_len = hdr.width * modex_height; + decode_buf = (uchar *)malloc(decode_buf_len); + + out_buf_len = hdr.width * hdr.height; + out_buf = (uchar *)malloc(out_buf_len); + + if (DecodeBGImageRLE(RLE_data_ptr, + RLE_data_len, decode_buf, decode_buf_len) != R_SUCCESS) { + + free(decode_buf); + free(out_buf); + + return R_FAILURE; + } + + UnbankBGImage(out_buf, decode_buf, hdr.width, hdr.height); + + /* For some reason bg images in IHNM are upside down + * \*------------------------------------------------------------- */ + if (GAME_GetGameType() == R_GAMETYPE_IHNM) { + + FlipImage(out_buf, hdr.width, hdr.height); + } + + free(decode_buf); + + *output_buf_len = out_buf_len; + *output_buf = out_buf; + + *w = hdr.width; + *h = hdr.height; + + return R_SUCCESS; +} + +int +DecodeBGImageRLE(const uchar * inbuf, + size_t inbuf_len, uchar * outbuf, size_t outbuf_len) +{ + + const uchar *inbuf_ptr; + uchar *outbuf_ptr; + size_t inbuf_remain; + + const uchar *inbuf_end; + uchar *outbuf_end; + size_t outbuf_remain; + + uchar mark_byte; + int test_byte; + + uint runcount; + + uchar bitfield; + uchar bitfield_byte1; + uchar bitfield_byte2; + + uchar *backtrack_ptr; + int backtrack_amount; + + uint c, b; + + int decode_err = 0; + + inbuf_ptr = inbuf; + inbuf_remain = inbuf_len; + + outbuf_ptr = outbuf; + outbuf_remain = outbuf_len; + + inbuf_end = (inbuf + inbuf_len) - 1; + outbuf_end = (outbuf + outbuf_len) - 1; + + memset(outbuf, 0, outbuf_len); + + while ((inbuf_remain > 1) && (outbuf_remain > 0) && !decode_err) { + + if ((inbuf_ptr > inbuf_end) || (outbuf_ptr > outbuf_end)) { + return R_FAILURE; + } + + mark_byte = *inbuf_ptr++; + inbuf_remain--; + + test_byte = mark_byte & 0xC0; /* Mask all but two high order bits */ + + switch (test_byte) { + + case 0xC0: /* 1100 0000 */ + + /* Uncompressed run follows: Max runlength 63 */ + runcount = mark_byte & 0x3f; + + if ((inbuf_remain < runcount) || + (outbuf_remain < runcount)) { + return R_FAILURE; + } + + for (c = 0; c < runcount; c++) { + *outbuf_ptr++ = *inbuf_ptr++; + } + + inbuf_remain -= runcount; + outbuf_remain -= runcount; + continue; + + break; + + case 0x80: /* 1000 0000 */ + + /* Compressed run follows: Max runlength 63 */ + runcount = (mark_byte & 0x3f) + 3; + + if (!inbuf_remain || (outbuf_remain < runcount)) { + return R_FAILURE; + } + + for (c = 0; c < runcount; c++) { + *outbuf_ptr++ = *inbuf_ptr; + } + + inbuf_ptr++; + inbuf_remain--; + outbuf_remain -= runcount; + continue; + + break; + + case 0x40: /* 0100 0000 */ + + /* Repeat decoded sequence from output stream: + * Max runlength 10 */ + + runcount = ((mark_byte >> 3) & 0x07U) + 3; + + backtrack_amount = *inbuf_ptr; + + if (!inbuf_remain || + (backtrack_amount > (outbuf_ptr - outbuf)) || + (runcount > outbuf_remain)) { + return R_FAILURE; + } + + inbuf_ptr++; + inbuf_remain--; + + backtrack_ptr = outbuf_ptr - backtrack_amount; + + for (c = 0; c < runcount; c++) { + *outbuf_ptr++ = *backtrack_ptr++; + } + + outbuf_remain -= runcount; + continue; + + break; + + default: /* 0000 0000 */ + break; + } + + /* Mask all but the third and fourth highest order bits */ + test_byte = mark_byte & 0x30; + + switch (test_byte) { + + case 0x30: /* 0011 0000 */ + /* Bitfield compression */ + + runcount = (mark_byte & 0x0F) + 1; + + if ((inbuf_remain < (runcount + 2)) || + (outbuf_remain < (runcount * 8))) { + return R_FAILURE; + } + + bitfield_byte1 = *inbuf_ptr++; + bitfield_byte2 = *inbuf_ptr++; + + for (c = 0; c < runcount; c++) { + + bitfield = *inbuf_ptr; + + for (b = 0; b < 8; b++) { + + if (bitfield & 0x80) { + *outbuf_ptr = bitfield_byte2; + } else { + *outbuf_ptr = bitfield_byte1; + } + + bitfield <<= 1; + + outbuf_ptr++; + } + inbuf_ptr++; + } + + inbuf_remain -= (runcount + 2); + outbuf_remain -= (runcount * 8); + continue; + + break; + + case 0x20: /* 0010 0000 */ + /* Uncompressed run follows */ + + runcount = ((mark_byte & 0x0F) << 8) + *inbuf_ptr; + + if ((inbuf_remain < (runcount + 1)) || + (outbuf_remain < runcount)) { + return R_FAILURE; + } + + inbuf_ptr++; + + for (c = 0; c < runcount; c++) { + *outbuf_ptr++ = *inbuf_ptr++; + } + + inbuf_remain -= (runcount + 1); + outbuf_remain -= runcount; + continue; + + break; + + case 0x10: /* 0001 0000 */ + /* Repeat decoded sequence from output stream */ + + backtrack_amount = + ((mark_byte & 0x0F) << 8) + *inbuf_ptr; + + if (inbuf_remain < 2) { + return R_FAILURE; + } + + inbuf_ptr++; + runcount = *inbuf_ptr++; + + if ((backtrack_amount > (outbuf_ptr - outbuf)) || + (outbuf_remain < runcount)) { + return R_FAILURE; + } + + backtrack_ptr = outbuf_ptr - backtrack_amount; + + for (c = 0; c < runcount; c++) { + *outbuf_ptr++ = *backtrack_ptr++; + } + + inbuf_remain -= 2; + outbuf_remain -= runcount; + continue; + + break; + + default: + return R_FAILURE; + break; + + } + + } /* end while */ + + return R_SUCCESS; +} + +int FlipImage(uchar * img_buf, int columns, int scanlines) +{ + + int line; + uchar *tmp_scan; + + uchar *flip_p1; + uchar *flip_p2; + + int flipcount = scanlines / 2; + + tmp_scan = (uchar *)malloc(columns); + if (tmp_scan == NULL) { + return R_FAILURE; + } + + flip_p1 = img_buf; + flip_p2 = img_buf + (columns * (scanlines - 1)); + + for (line = 0; line < flipcount; line++) { + + memcpy(tmp_scan, flip_p1, columns); + memcpy(flip_p1, flip_p2, columns); + memcpy(flip_p2, tmp_scan, columns); + + flip_p1 += columns; + flip_p2 -= columns; + } + + free(tmp_scan); + + return R_SUCCESS; +} + +int +UnbankBGImage(uchar * dst_buf, + const uchar * src_buf, int columns, int scanlines) +{ + + int x, y; + int temp; + + int quadruple_rows; + int remain_rows; + + int rowjump_src; + int rowjump_dest; + + const uchar *src_p; + uchar *dst_p; + + const uchar *srcptr1, *srcptr2, *srcptr3, *srcptr4; + uchar *dstptr1, *dstptr2, *dstptr3, *dstptr4; + + quadruple_rows = scanlines - (scanlines % 4); + remain_rows = scanlines - quadruple_rows; + + assert(scanlines > 0); + + src_p = src_buf; + dst_p = dst_buf + columns; + + srcptr1 = src_p; + srcptr2 = src_p + 1; + srcptr3 = src_p + 2; + srcptr4 = src_p + 3; + + dstptr1 = dst_buf; + dstptr2 = dst_buf + columns; + dstptr3 = dst_buf + columns * 2; + dstptr4 = dst_buf + columns * 3; + + rowjump_src = columns * 4; + rowjump_dest = columns * 4; + + /* Unbank groups of 4 first */ + for (y = 0; y < quadruple_rows; y += 4) { + + for (x = 0; x < columns; x++) { + temp = x * 4; + dstptr1[x] = srcptr1[temp]; + dstptr2[x] = srcptr2[temp]; + dstptr3[x] = srcptr3[temp]; + dstptr4[x] = srcptr4[temp]; + } + + /* This is to avoid generating invalid pointers - + * usually innocuous, but undefined */ + if (y < quadruple_rows - 4) { + + dstptr1 += rowjump_dest; + dstptr2 += rowjump_dest; + dstptr3 += rowjump_dest; + dstptr4 += rowjump_dest; + srcptr1 += rowjump_src; + srcptr2 += rowjump_src; + srcptr3 += rowjump_src; + srcptr4 += rowjump_src; + } + + } + + /* Unbank rows remaining */ + switch (remain_rows) { + + case 1: + dstptr1 += rowjump_dest; + srcptr1 += rowjump_src; + + for (x = 0; x < columns; x++) { + temp = x * 4; + dstptr1[x] = srcptr1[temp]; + } + break; + + case 2: + dstptr1 += rowjump_dest; + dstptr2 += rowjump_dest; + srcptr1 += rowjump_src; + srcptr2 += rowjump_src; + + for (x = 0; x < columns; x++) { + temp = x * 4; + dstptr1[x] = srcptr1[temp]; + dstptr2[x] = srcptr2[temp]; + } + break; + + case 3: + dstptr1 += rowjump_dest; + dstptr2 += rowjump_dest; + dstptr3 += rowjump_dest; + srcptr1 += rowjump_src; + srcptr2 += rowjump_src; + srcptr3 += rowjump_src; + + for (x = 0; x < columns; x++) { + temp = x * 4; + dstptr1[x] = srcptr1[temp]; + dstptr2[x] = srcptr2[temp]; + dstptr3[x] = srcptr3[temp]; + } + break; + + default: + break; + } + + return R_SUCCESS; +} + +const uchar *IMG_GetImagePal(const uchar * image_data, size_t image_size) +{ + if (image_size <= SAGA_IMAGE_HEADER_LEN) { + return NULL; + } + + return image_data + SAGA_IMAGE_HEADER_LEN; +} + +} // End of namespace Saga diff --git a/saga/image.h b/saga/image.h new file mode 100644 index 0000000000..95ade8877c --- /dev/null +++ b/saga/image.h @@ -0,0 +1,64 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + SAGA Image resource management header file + + Notes: +*/ + +#ifndef SAGA_IMAGE_H__ +#define SAGA_IMAGE_H__ + +namespace Saga { + +#define R_MIN_IMG_RLECODE 3 +#define MODEX_SCANLINE_LIMIT 200 + +#define SAGA_IMAGE_DATA_OFFSET 776 +#define SAGA_IMAGE_HEADER_LEN 8 + +typedef struct R_IMAGE_HEADER_tag { + + int width; + int height; + int unknown4; + int unknown6; + +} R_IMAGE_HEADER; + +int +DecodeBGImageRLE(const uchar * inbuf, + size_t inbuf_len, uchar * outbuf, size_t outbuf_len); + +int FlipImage(uchar * img_buf, int columns, int scanlines); + +int +UnbankBGImage(uchar * dest_buf, + const uchar * src_buf, int columns, int scanlines); + +} // End of namespace Saga + +#endif /* R_IMAGE_H__ */ +/* end "r_image.h" */ diff --git a/saga/image_mod.h b/saga/image_mod.h new file mode 100644 index 0000000000..290a9ae1da --- /dev/null +++ b/saga/image_mod.h @@ -0,0 +1,46 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + SAGA Image resource management routines + + Notes: +*/ + +#ifndef SAGA_IMAGE_MOD_H_ +#define SAGA_IMAGE_MOD_H_ + +namespace Saga { + +int +IMG_DecodeBGImage(const uchar * image_data, + size_t image_size, + uchar ** output_buf, size_t * output_buf_len, int *w, int *h); + +const uchar *IMG_GetImagePal(const uchar * image_data, size_t image_size); + +} // End of namespace Saga + +#endif /* R_IMAGE_MOD_H_ */ +/* end "r_image_mod.h" */ diff --git a/saga/interface.cpp b/saga/interface.cpp new file mode 100644 index 0000000000..22b02db58a --- /dev/null +++ b/saga/interface.cpp @@ -0,0 +1,756 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Game interface module + + Notes: +*/ + +#include "reinherit.h" + +#include "yslib.h" + +/* + * Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "game_mod.h" +#include "cvar_mod.h" +#include "actor_mod.h" +#include "console_mod.h" +#include "font_mod.h" +#include "gfx_mod.h" +#include "image_mod.h" +#include "objectmap_mod.h" +#include "rscfile_mod.h" +#include "script_mod.h" +#include "sprite_mod.h" + +/* + * Begin module +\*--------------------------------------------------------------------------*/ +#include "interface_mod.h" +#include "interface.h" + +namespace Saga { + +static R_INTERFACE_MODULE IfModule; + +static R_VERB_DATA I_VerbData[] = { + + {I_VERB_WALKTO, "verb_walkto", "Walk to", S_VERB_WALKTO}, + {I_VERB_LOOKAT, "verb_lookat", "Look at", S_VERB_LOOKAT}, + {I_VERB_PICKUP, "verb_pickup", "Pick up", S_VERB_PICKUP}, + {I_VERB_TALKTO, "verb_talkto", "Talk to", S_VERB_TALKTO}, + {I_VERB_OPEN, "verb_open", "Open", S_VERB_OPEN}, + {I_VERB_CLOSE, "verb_close", "Close", S_VERB_CLOSE}, + {I_VERB_USE, "verb_use", "Use", S_VERB_USE}, + {I_VERB_GIVE, "verb_give", "Give", S_VERB_GIVE} +}; + +static R_INTERFACE_DESC ITE_interface = { + + ITE_STATUS_Y, + ITE_STATUS_W, + ITE_STATUS_H, + ITE_STATUS_TEXT_Y, + ITE_STATUS_TXTCOL, + ITE_STATUS_BGCOL, + + ITE_CMD_TEXT_COL, + ITE_CMD_TEXT_SHADOWCOL, + ITE_CMD_TEXT_HILITECOL, + + COMMAND_DEFAULT_BUTTON, + + ITE_LPORTRAIT_X, + ITE_LPORTRAIT_Y +}; + +static R_INTERFACE_BUTTON ITE_c_buttons[] = { + + {5, 4, 46, 47, "Portrait", 0, 0, BUTTON_NONE, 0}, + /* "Walk To" and "Talk To" share button sprites */ + {52, 4, 109, 14, "Walk To", 1, 2, BUTTON_VERB, I_VERB_WALKTO}, + {52, 15, 109, 25, "Look At", 3, 4, BUTTON_VERB, I_VERB_LOOKAT}, + {52, 26, 109, 36, "Pick Up", 5, 6, BUTTON_VERB, I_VERB_PICKUP}, + {52, 37, 109, 47, "Talk To", 1, 2, BUTTON_VERB, I_VERB_TALKTO}, + {110, 4, 166, 14, "Open", 7, 8, BUTTON_VERB, I_VERB_OPEN}, + {110, 15, 166, 25, "Close", 9, 10, BUTTON_VERB, I_VERB_CLOSE}, + {110, 26, 166, 36, "Use", 11, 12, BUTTON_VERB, I_VERB_USE}, + {110, 37, 166, 47, "Give", 13, 14, BUTTON_VERB, I_VERB_GIVE}, + + {181, 6, 206, 24, "Inv1", 0, 0, BUTTON_NONE, 0}, + {213, 6, 240, 24, "Inv2", 0, 0, BUTTON_NONE, 0}, + {245, 6, 272, 24, "Inv3", 0, 0, BUTTON_NONE, 0}, + {277, 6, 304, 24, "Inv4", 0, 0, BUTTON_NONE, 0}, + {181, 27, 208, 45, "Inv5", 0, 0, BUTTON_NONE, 0}, + {213, 27, 240, 45, "Inv6", 0, 0, BUTTON_NONE, 0}, + {245, 27, 272, 45, "Inv7", 0, 0, BUTTON_NONE, 0}, + {277, 27, 304, 45, "Inv8", 0, 0, BUTTON_NONE, 0}, + {306, 6, 314, 11, "InvUp", 0, 0, BUTTON_NONE, 0}, + {306, 41, 314, 45, "InvDown", 0, 0, BUTTON_NONE, 0} +}; + +static R_INTERFACE_DESC IHNM_interface = { + + IHNM_STATUS_Y, + IHNM_STATUS_W, + IHNM_STATUS_H, + IHNM_STATUS_TEXT_Y, + IHNM_STATUS_TXTCOL, + IHNM_STATUS_BGCOL, + + IHNM_CMD_TEXT_COL, + IHNM_CMD_TEXT_SHADOWCOL, + IHNM_CMD_TEXT_HILITECOL, + + COMMAND_DEFAULT_BUTTON, + + IHNM_LPORTRAIT_X, + IHNM_LPORTRAIT_Y +}; + +static R_INTERFACE_BUTTON IHNM_c_buttons[] = { + + {5, 4, 46, 47, "Portrait", 0, 0, 0, 0} +}; + +int INTERFACE_RegisterLang(void) +{ + size_t i; + + for (i = 0; i < YS_NELEMS(I_VerbData); i++) { + + if (CVAR_Register_S(I_VerbData[i].verb_str, + I_VerbData[i].verb_cvar, + NULL, R_CVAR_CFG, R_VERB_STRLIMIT) != R_SUCCESS) { + + return R_FAILURE; + } + + assert(CVAR_Find(I_VerbData[i].verb_cvar) != NULL); + } + + return R_SUCCESS; +} + +int INTERFACE_Init(void) +{ + + R_GAME_RESOURCEDESC g_resdesc; + + int game_type; + int result; + + if (IfModule.init) { + return R_FAILURE; + } + + IfModule.i_thread = STHREAD_Create(); + if (IfModule.i_thread == NULL) { + + R_printf(R_STDERR, + "Error creating script thread for game interface " + "module.\n"); + + return R_FAILURE; + } + + /* Load interface module resource file context + * \*------------------------------------------------------------- */ + result = GAME_GetFileContext(&IfModule.i_file_ctxt, + R_GAME_RESOURCEFILE, 0); + if (result != R_SUCCESS) { + + return R_FAILURE; + } + + /* Initialize interface data by game type + * \*------------------------------------------------------------- */ + game_type = GAME_GetGameType(); + + if (game_type == R_GAMETYPE_ITE) { + + /* Load Inherit the Earth interface desc */ + + IfModule.c_panel.buttons = ITE_c_buttons; + IfModule.c_panel.nbuttons = YS_NELEMS(ITE_c_buttons); + + IfModule.i_desc = ITE_interface; + } else if (game_type == R_GAMETYPE_IHNM) { + + /* Load I Have No Mouth interface desc */ + IfModule.c_panel.buttons = IHNM_c_buttons; + IfModule.c_panel.nbuttons = YS_NELEMS(IHNM_c_buttons); + + IfModule.i_desc = IHNM_interface; + } else { + return R_FAILURE; + } + + /* Load interface resources + * \*------------------------------------------------------------- */ + GAME_GetResourceInfo(&g_resdesc); + + /* Load command panel resource */ + result = RSC_LoadResource(IfModule.i_file_ctxt, + g_resdesc.command_panel_rn, + &IfModule.c_panel.res, &IfModule.c_panel.res_len); + if (result != R_SUCCESS) { + + return R_FAILURE; + } + + /* Load dialogue panel resource */ + result = RSC_LoadResource(IfModule.i_file_ctxt, + g_resdesc.dialogue_panel_rn, + &IfModule.d_panel.res, &IfModule.d_panel.res_len); + if (result != R_SUCCESS) { + + return R_FAILURE; + } + + SPRITE_LoadList(ITE_COMMAND_BUTTONSPRITES, &IfModule.c_panel.sprites); + + SPRITE_LoadList(ITE_DEFAULT_PORTRAITS, &IfModule.def_portraits); + + IMG_DecodeBGImage(IfModule.c_panel.res, + IfModule.c_panel.res_len, + &IfModule.c_panel.img, + &IfModule.c_panel.img_len, + &IfModule.c_panel.img_w, &IfModule.c_panel.img_h); + + IMG_DecodeBGImage(IfModule.d_panel.res, + IfModule.d_panel.res_len, + &IfModule.d_panel.img, + &IfModule.d_panel.img_len, + &IfModule.d_panel.img_w, &IfModule.d_panel.img_h); + + IfModule.c_panel.x = 0; + IfModule.c_panel.y = 149; + + IfModule.d_panel.x = 0; + IfModule.d_panel.y = 149; + + IfModule.c_panel.set_button = COMMAND_DEFAULT_BUTTON; + IfModule.active_portrait = 0; + + IfModule.active_verb = I_VERB_WALKTO; + + IfModule.init = 1; + + return R_SUCCESS; +} + +int INTERFACE_Activate(void) +{ + + IfModule.active = 1; + INTERFACE_Draw(); + + return R_SUCCESS; +} + +int INTERFACE_Deactivate(void) +{ + + IfModule.active = 0; + + return R_SUCCESS; +} + +int INTERFACE_SetStatusText(const char *new_txt) +{ + + assert(new_txt != NULL); + + strncpy(IfModule.status_txt, new_txt, R_STATUS_TEXT_LEN); + + return R_SUCCESS; +} + +int INTERFACE_Draw(void) +{ + + R_GAME_DISPLAYINFO g_di; + + R_SURFACE *back_buf; + + int xbase; + int ybase; + int lportrait_x; + int lportrait_y; + + R_RECT rect; + R_POINT origin; + + back_buf = SYSGFX_GetBackBuffer(); + + if (!IfModule.active) { + return R_SUCCESS; + } + + /* Get game display info + * \*------------------------------------------------------------- */ + GAME_GetDisplayInfo(&g_di); + + /* Erase background of status bar + * \*------------------------------------------------------------- */ + rect.x1 = 0; + rect.y1 = IfModule.i_desc.status_y; + + rect.x2 = g_di.logical_w - 1; + rect.y2 = IfModule.i_desc.status_h - 1; + + GFX_DrawRect(back_buf, &rect, IfModule.i_desc.status_bgcol); + + /* Draw command panel background + * \*------------------------------------------------------------- */ + if (IfModule.panel_mode == PANEL_COMMAND) { + + xbase = IfModule.c_panel.x; + ybase = IfModule.c_panel.y; + + origin.x = 0; + origin.y = g_di.logical_h - IfModule.c_panel.img_h; + + GFX_BufToSurface(back_buf, + IfModule.c_panel.img, + IfModule.c_panel.img_w, + IfModule.c_panel.img_h, NULL, &origin); + } else { + + xbase = IfModule.d_panel.x; + ybase = IfModule.d_panel.y; + + origin.x = 0; + origin.y = g_di.logical_h - IfModule.c_panel.img_h; + + GFX_BufToSurface(back_buf, + IfModule.d_panel.img, + IfModule.d_panel.img_w, + IfModule.d_panel.img_h, NULL, &origin); + } + + /* Draw character portrait + * \*------------------------------------------------------------- */ + lportrait_x = xbase + IfModule.i_desc.lportrait_x; + lportrait_y = ybase + IfModule.i_desc.lportrait_y; + + SPRITE_Draw(back_buf, + IfModule.def_portraits, + IfModule.active_portrait, lportrait_x, lportrait_y); + + return R_SUCCESS; +} + +int INTERFACE_Update(R_POINT * imouse_pt, int update_flag) +{ + + R_GAME_DISPLAYINFO g_di; + + R_SURFACE *back_buf; + + int imouse_x, imouse_y; + + assert(imouse_pt != NULL); + + if (!IfModule.active) { + return R_SUCCESS; + } + + imouse_x = imouse_pt->x; + imouse_y = imouse_pt->y; + + back_buf = SYSGFX_GetBackBuffer(); + + /* Get game display info + * \*------------------------------------------------------------- */ + GAME_GetDisplayInfo(&g_di); + + /* Update playfield space ( only if cursor is inside ) + * \*------------------------------------------------------------- */ + if (imouse_y < g_di.scene_h) { + + /* Mouse is in playfield space */ + + if (update_flag == UPDATE_MOUSEMOVE) { + + HandlePlayfieldUpdate(back_buf, imouse_pt); + } else if (update_flag == UPDATE_MOUSECLICK) { + + HandlePlayfieldClick(back_buf, imouse_pt); + } + } + + /* Update command space + * \*------------------------------------------------------------- */ + + if (update_flag == UPDATE_MOUSEMOVE) { + + HandleCommandUpdate(back_buf, imouse_pt); + } else if (update_flag == UPDATE_MOUSECLICK) { + + HandleCommandClick(back_buf, imouse_pt); + } + + DrawStatusBar(back_buf); + + return R_SUCCESS; +} + +int DrawStatusBar(R_SURFACE * ds) +{ + + R_GAME_DISPLAYINFO g_di; + R_RECT rect; + + int string_w; + + /* Get game display info + * \*------------------------------------------------------------- */ + GAME_GetDisplayInfo(&g_di); + + /* Erase background of status bar + * \*------------------------------------------------------------- */ + rect.x1 = 0; + rect.y1 = IfModule.i_desc.status_y; + rect.x2 = g_di.logical_w - 1; + rect.y2 = IfModule.i_desc.status_y + IfModule.i_desc.status_h - 1; + + GFX_DrawRect(ds, &rect, IfModule.i_desc.status_bgcol); + + string_w = FONT_GetStringWidth(SMALL_FONT_ID, + IfModule.status_txt, 0, 0); + + FONT_Draw(SMALL_FONT_ID, + ds, + IfModule.status_txt, + 0, + (IfModule.i_desc.status_w / 2) - (string_w / 2), + IfModule.i_desc.status_y + IfModule.i_desc.status_txt_y, + IfModule.i_desc.status_txt_col, 0, 0); + + return R_SUCCESS; + +} + +int HandleCommandClick(R_SURFACE * ds, R_POINT * imouse_pt) +{ + + int hit_button; + int ibutton_num; + + int x_base; + int y_base; + + int button_x = 0; + int button_y = 0; + + int old_set_button; + int set_button; + + hit_button = INTERFACE_HitTest(imouse_pt, &ibutton_num); + if (hit_button != R_SUCCESS) { + + /* Clicking somewhere other than a button doesn't do anything */ + return R_SUCCESS; + } + + x_base = IfModule.c_panel.x; + y_base = IfModule.c_panel.y; + + if (IfModule.c_panel.buttons[ibutton_num].flags & BUTTON_SET) { + + old_set_button = IfModule.c_panel.set_button; + set_button = ibutton_num; + IfModule.c_panel.set_button = set_button; + + if (IfModule.c_panel.buttons[set_button].flags & BUTTON_VERB) { + + IfModule.active_verb = + IfModule.c_panel.buttons[ibutton_num].data; + } + + if (IfModule.c_panel.buttons[set_button].flags & BUTTON_BITMAP) { + + button_x = + x_base + IfModule.c_panel.buttons[set_button].x1; + button_y = + y_base + IfModule.c_panel.buttons[set_button].y1; + + SPRITE_Draw(ds, + IfModule.c_panel.sprites, + IfModule.c_panel.buttons[set_button]. + active_sprite - 1, button_x, button_y); + } + + if (IfModule.c_panel.buttons[old_set_button]. + flags & BUTTON_BITMAP) { + + button_x = + x_base + + IfModule.c_panel.buttons[old_set_button].x1; + button_y = + y_base + + IfModule.c_panel.buttons[old_set_button].y1; + + SPRITE_Draw(ds, + IfModule.c_panel.sprites, + IfModule.c_panel.buttons[old_set_button]. + inactive_sprite - 1, button_x, button_y); + } + } + + return R_SUCCESS; +} + +int HandleCommandUpdate(R_SURFACE * ds, R_POINT * imouse_pt) +{ + + int hit_button; + int ibutton_num; + + int button_x = 0; + int button_y = 0; + int button_w = 0; + + int verb_idx = 0; + int string_w = 0; + + int color; + + int i; + + hit_button = INTERFACE_HitTest(imouse_pt, &ibutton_num); + if (hit_button == R_SUCCESS) { + + /* Hovering over a command panel button */ + INTERFACE_SetStatusText(I_VerbData[IfModule.active_verb]. + verb_str); + } + + for (i = 0; i < IfModule.c_panel.nbuttons; i++) { + + if (!(IfModule.c_panel.buttons[i].flags & BUTTON_LABEL)) { + continue; + } + + button_w = IfModule.c_panel.buttons[i].x2 - + IfModule.c_panel.buttons[i].x1; + + verb_idx = IfModule.c_panel.buttons[i].data; + + string_w = FONT_GetStringWidth(SMALL_FONT_ID, + I_VerbData[verb_idx].verb_str, 0, 0); + + if (i == hit_button) { + color = IfModule.i_desc.cmd_txt_hilitecol; + } else { + color = IfModule.i_desc.cmd_txt_col; + } + + button_x = IfModule.c_panel.x + IfModule.c_panel.buttons[i].x1; + button_y = IfModule.c_panel.y + IfModule.c_panel.buttons[i].y1; + + FONT_Draw(SMALL_FONT_ID, + ds, + I_VerbData[verb_idx].verb_str, + 0, + button_x + ((button_w / 2) - (string_w / 2)), + button_y + 1, + color, IfModule.i_desc.cmd_txt_shadowcol, FONT_SHADOW); + + if ((i == IfModule.c_panel.set_button) && + (IfModule.c_panel.buttons[i].flags & BUTTON_BITMAP)) { + + SPRITE_Draw(ds, + IfModule.c_panel.sprites, + IfModule.c_panel.buttons[i].active_sprite - 1, + button_x, button_y); + } + } + + return R_SUCCESS; +} + +int HandlePlayfieldClick(R_SURFACE * ds, R_POINT * imouse_pt) +{ + + int hit_object; + int object_num; + uint object_flags = 0; + + int script_num; + R_POINT iactor_pt; + + hit_object = OBJECTMAP_HitTest(imouse_pt, &object_num); + + if (hit_object != R_SUCCESS) { + + /* Player clicked on empty spot - walk here regardless of verb */ + + ACTOR_StoA(&iactor_pt, imouse_pt); + ACTOR_WalkTo(0, &iactor_pt, 0, NULL); + + return R_SUCCESS; + } + + if (OBJECTMAP_GetFlags(object_num, &object_flags) != R_SUCCESS) { + + CON_Print("Invalid object number: %d\n", object_num); + + return R_FAILURE; + } + + if (object_flags & R_OBJECT_NORMAL) { + + if (OBJECTMAP_GetEPNum(object_num, &script_num) == R_SUCCESS) { + + /* Set active verb in script module */ + SDATA_PutWord(4, 4, + I_VerbData[IfModule.active_verb].s_verb); + + /* Execute object script if present */ + if (script_num != 0) { + STHREAD_Execute(IfModule.i_thread, script_num); + } + } + } else { + + /* Not a normal scene object - walk to it as if it weren't there */ + + ACTOR_StoA(&iactor_pt, imouse_pt); + ACTOR_WalkTo(0, &iactor_pt, 0, NULL); + + } + + return R_SUCCESS; +} + +int HandlePlayfieldUpdate(R_SURFACE * ds, R_POINT * imouse_pt) +{ + + const char *object_name; + int object_num; + uint object_flags = 0; + + char new_status[R_STATUS_TEXT_LEN]; + + int hit_object; + + new_status[0] = 0; + + hit_object = OBJECTMAP_HitTest(imouse_pt, &object_num); + + if (hit_object != R_SUCCESS) { + + /* Cursor over nothing - just display current verb */ + INTERFACE_SetStatusText(I_VerbData[IfModule.active_verb]. + verb_str); + + return R_SUCCESS; + } + + if (OBJECTMAP_GetFlags(object_num, &object_flags) != R_SUCCESS) { + + CON_Print("Invalid object number: %d\n", object_num); + + return R_FAILURE; + } + + OBJECTMAP_GetName(object_num, &object_name); + + if (object_flags & R_OBJECT_NORMAL) { + + /* Normal scene object - display as subject of verb */ + + snprintf(new_status, + R_STATUS_TEXT_LEN, + "%s %s", + I_VerbData[IfModule.active_verb].verb_str, object_name); + } else { + + /* Not normal scene object - override verb as we can only + * walk to this object */ + + snprintf(new_status, + R_STATUS_TEXT_LEN, + "%s %s", I_VerbData[I_VERB_WALKTO].verb_str, object_name); + } + + INTERFACE_SetStatusText(new_status); + + return R_SUCCESS; +} + +int INTERFACE_HitTest(R_POINT * imouse_pt, int *ibutton) +{ + + R_INTERFACE_BUTTON *buttons; + + int nbuttons; + int xbase; + int ybase; + + int i; + + buttons = IfModule.c_panel.buttons; + nbuttons = IfModule.c_panel.nbuttons; + + xbase = IfModule.c_panel.x; + ybase = IfModule.c_panel.y; + + for (i = 0; i < nbuttons; i++) { + + if ((imouse_pt->x >= (xbase + buttons[i].x1)) && + (imouse_pt->x < (xbase + buttons[i].x2)) && + (imouse_pt->y >= (ybase + buttons[i].y1)) && + (imouse_pt->y < (ybase + buttons[i].y2))) { + + *ibutton = i; + + return R_SUCCESS; + } + } + + *ibutton = -1; + return R_FAILURE; +} + +int INTERFACE_Shutdown(void) +{ + + if (!IfModule.init) { + + return R_FAILURE; + } + + IfModule.init = 0; + + return R_SUCCESS; +} + +} // End of namespace Saga diff --git a/saga/interface.h b/saga/interface.h new file mode 100644 index 0000000000..d8e8e24dbb --- /dev/null +++ b/saga/interface.h @@ -0,0 +1,198 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Game interface module private header file + + Notes: + + Module dependencies: + - r_script_mod + - r_sprite_mod +*/ + +#ifndef SAGA_INTERFACE_H__ +#define SAGA_INTERFACE_H__ + +namespace Saga { + +#define R_VERB_STRLIMIT 32 + +#define R_STATUS_TEXT_LEN 128 + +#define COMMAND_DEFAULT_BUTTON 1 + +/* Inherit the Earth interface values */ +#define ITE_STATUS_Y 137 +#define ITE_STATUS_W 320 +#define ITE_STATUS_H 12 +#define ITE_STATUS_TEXT_Y 2 +#define ITE_STATUS_TXTCOL 186 +#define ITE_STATUS_BGCOL 15 + +#define ITE_CMD_TEXT_COL 147 +#define ITE_CMD_TEXT_SHADOWCOL 15 +#define ITE_CMD_TEXT_HILITECOL 96 + +#define ITE_LPORTRAIT_X 5 +#define ITE_LPORTRAIT_Y 4 + +/* IHNMAIMS interface values */ +#define IHNM_STATUS_Y 304 +#define IHNM_STATUS_W 640 +#define IHNM_STATUS_H 24 +#define IHNM_STATUS_TEXT_Y 8 +#define IHNM_STATUS_TXTCOL 186 +#define IHNM_STATUS_BGCOL 0 + +#define IHNM_CMD_TEXT_COL 147 +#define IHNM_CMD_TEXT_SHADOWCOL 15 +#define IHNM_CMD_TEXT_HILITECOL 96 + +#define IHNM_LPORTRAIT_X 5 +#define IHNM_LPORTRAIT_Y 4 + +typedef enum R_PANEL_MODES_tag { + + PANEL_COMMAND, + PANEL_DIALOGUE +} R_PANEL_MODES; + +typedef enum R_BUTTON_FLAGS_tag { + + BUTTON_NONE = 0x0, + BUTTON_LABEL = 0x01, + BUTTON_BITMAP = 0x02, + BUTTON_SET = 0x04 + +} R_BUTTON_FLAGS; + +#define BUTTON_VERB ( BUTTON_LABEL | BUTTON_BITMAP | BUTTON_SET ) + +typedef struct R_INTERFACE_BUTTON_tag { + + int x1; + int y1; + int x2; + int y2; + char *label; + int inactive_sprite; + int active_sprite; + int flags; + int data; + +} R_INTERFACE_BUTTON; + +typedef struct R_INTERFACE_PANEL_tag { + + uchar *res; + size_t res_len; + int x; + int y; + uchar *img; + size_t img_len; + int img_w; + int img_h; + int set_button; + int nbuttons; + R_INTERFACE_BUTTON *buttons; + R_SPRITELIST *sprites; + +} R_INTERFACE_PANEL; + +typedef struct R_INTERFACE_DESC_tag { + + int status_y; + int status_w; + int status_h; + int status_txt_y; + int status_txt_col; + int status_bgcol; + + int cmd_txt_col; + int cmd_txt_shadowcol; + int cmd_txt_hilitecol; + int cmd_defaultbutton; + + int lportrait_x; + int lportrait_y; + +} R_INTERFACE_DESC; + +typedef struct R_INTERFACE_MODULE_tag { + + int init; + int active; + + R_RSCFILE_CONTEXT *i_file_ctxt; + + R_INTERFACE_DESC i_desc; + + R_PANEL_MODES panel_mode; + R_INTERFACE_PANEL c_panel; + R_INTERFACE_PANEL d_panel; + + char status_txt[R_STATUS_TEXT_LEN]; + + int active_portrait; + R_SPRITELIST *def_portraits; + int active_verb; + + R_SCRIPT_THREAD *i_thread; + +} R_INTERFACE_MODULE; + +enum INTERFACE_VERBS { + + I_VERB_WALKTO, + I_VERB_LOOKAT, + I_VERB_PICKUP, + I_VERB_TALKTO, + I_VERB_OPEN, + I_VERB_CLOSE, + I_VERB_USE, + I_VERB_GIVE +}; + +typedef struct R_VERB_DATA_tag { + + int i_verb; + const char *verb_cvar; + char verb_str[R_VERB_STRLIMIT]; + int s_verb; + +} R_VERB_DATA; + +int INTERFACE_HitTest(R_POINT * imouse_pt, int *ibutton); + +int DrawStatusBar(R_SURFACE * ds); +int HandleCommandUpdate(R_SURFACE * ds, R_POINT * imouse_pt); +int HandleCommandClick(R_SURFACE * ds, R_POINT * imouse_pt); +int HandlePlayfieldUpdate(R_SURFACE * ds, R_POINT * imouse_pt); +int HandlePlayfieldClick(R_SURFACE * ds, R_POINT * imouse_pt); + +} // End of namespace Saga + +#endif /* R_INTERFACE_H__ */ +/* end "r_interface.h" */ diff --git a/saga/interface_mod.h b/saga/interface_mod.h new file mode 100644 index 0000000000..77de1dae75 --- /dev/null +++ b/saga/interface_mod.h @@ -0,0 +1,57 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Game interface module public header file + + Notes: +*/ + +#ifndef SAGA_INTERFACE_MOD_H +#define SAGA_INTERFACE_MOD_H + +namespace Saga { + +typedef enum INTERFACE_UPDATE_FLAGS_tag { + + UPDATE_MOUSEMOVE = 1, + UPDATE_MOUSECLICK + +} INTERFACE_UPDATE_FLAGS; + +int INTERFACE_RegisterLang(void); + +int INTERFACE_Init(void); +int INTERFACE_Shutdown(void); + +int INTERFACE_Activate(void); +int INTERFACE_Deactivate(void); + +int INTERFACE_SetStatusText(const char *new_txt); +int INTERFACE_Draw(void); +int INTERFACE_Update(R_POINT * imouse_pt, int update_flag); + +} // End of namespace Saga + +#endif /* SAGA_INTERFACE_MOD_H */ diff --git a/saga/isomap.cpp b/saga/isomap.cpp new file mode 100644 index 0000000000..0f895b8082 --- /dev/null +++ b/saga/isomap.cpp @@ -0,0 +1,371 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Isometric level module + + Notes: +*/ + +#include "reinherit.h" + +#include "yslib.h" + +/* + * Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "game_mod.h" +#include "gfx_mod.h" + +/* + * Begin module component +\*--------------------------------------------------------------------------*/ +#include "isomap_mod.h" +#include "isomap.h" + +namespace Saga { + +static R_ISOMAP_MODULE IsoModule; + +int ISOMAP_Init(void) +{ + IsoModule.init = 1; + + return R_SUCCESS; +} + +int ISOMAP_LoadTileset(const uchar * tileres_p, size_t tileres_len) +{ + + R_ISOTILE_ENTRY first_entry; + R_ISOTILE_ENTRY *tile_tbl; + + uint i; + + const uchar *read_p = tileres_p; + size_t read_len = tileres_len; + + assert((IsoModule.init) && (!IsoModule.tiles_loaded)); + assert((tileres_p != NULL) && (tileres_len > 0)); + + read_p += 2; + first_entry.tile_offset = ys_read_u16_le(read_p, &read_p); + + IsoModule.tile_ct = first_entry.tile_offset / SAGA_ISOTILE_ENTRY_LEN; + + read_p = tileres_p; + read_len = tileres_len; + + tile_tbl = (R_ISOTILE_ENTRY *)malloc(IsoModule.tile_ct * sizeof *tile_tbl); + if (tile_tbl == NULL) { + return R_MEM; + } + + for (i = 0; i < IsoModule.tile_ct; i++) { + + tile_tbl[i].tile_h = ys_read_u8(read_p, &read_p); + tile_tbl[i].unknown01 = ys_read_u8(read_p, &read_p); + + tile_tbl[i].tile_offset = ys_read_u16_le(read_p, &read_p); + tile_tbl[i].unknown04 = ys_read_s16_le(read_p, &read_p); + tile_tbl[i].unknown06 = ys_read_s16_le(read_p, &read_p); + } + + IsoModule.tiles_loaded = 1; + IsoModule.tile_tbl = tile_tbl; + IsoModule.tileres_p = tileres_p; + IsoModule.tileres_len = tileres_len; + + return R_SUCCESS; +} + +int ISOMAP_LoadMetaTileset(const uchar * mtileres_p, size_t mtileres_len) +{ + + R_ISO_METATILE_ENTRY *mtile_tbl; + + const uchar *read_p = mtileres_p; + size_t read_len = mtileres_len; + + uint mtile_ct; + uint ct; + + int i; + + assert(IsoModule.init); + assert((mtileres_p != NULL) && (mtileres_len > 0)); + + (void)read_len; + + mtile_ct = mtileres_len / SAGA_METATILE_ENTRY_LEN; + + mtile_tbl = (R_ISO_METATILE_ENTRY *)malloc(mtile_ct * sizeof *mtile_tbl); + if (mtile_tbl == NULL) { + return R_MEM; + } + + for (ct = 0; ct < mtile_ct; ct++) { + + mtile_tbl[ct].mtile_n = ys_read_u16_le(read_p, &read_p); + mtile_tbl[ct].unknown02 = ys_read_s16_le(read_p, &read_p); + mtile_tbl[ct].unknown04 = ys_read_s16_le(read_p, &read_p); + mtile_tbl[ct].unknown06 = ys_read_s16_le(read_p, &read_p); + + for (i = 0; i < SAGA_METATILE_SIZE; i++) { + mtile_tbl[ct].tile_tbl[i] = + ys_read_u16_le(read_p, &read_p); + } + } + + IsoModule.mtile_ct = mtile_ct; + IsoModule.mtile_tbl = mtile_tbl; + IsoModule.mtileres_p = mtileres_p; + IsoModule.mtileres_len = mtileres_len; + + IsoModule.mtiles_loaded = 1; + + return R_SUCCESS; +} + +int ISOMAP_LoadMetamap(const uchar * mm_res_p, size_t mm_res_len) +{ + + const uchar *read_p = mm_res_p; + size_t read_len = mm_res_len; + + int i; + + (void)read_len; + + IsoModule.metamap_n = ys_read_s16_le(read_p, &read_p); + + for (i = 0; i < SAGA_METAMAP_SIZE; i++) { + + IsoModule.metamap_tbl[i] = ys_read_u16_le(read_p, &read_p); + } + + IsoModule.mm_res_p = mm_res_p; + IsoModule.mm_res_len = mm_res_len; + IsoModule.metamap_loaded = 1; + + return R_SUCCESS; +} + +int ISOMAP_Draw(R_SURFACE * dst_s) +{ + + R_GAME_DISPLAYINFO disp_info; + R_RECT iso_rect; + + GAME_GetDisplayInfo(&disp_info); + + iso_rect.x1 = 0; + iso_rect.y1 = 0; + iso_rect.x2 = disp_info.logical_w - 1; + iso_rect.y2 = disp_info.scene_h - 1; + + GFX_DrawRect(dst_s, &iso_rect, 0); + + ISOMAP_DrawMetamap(dst_s, -1000, -500); + + return R_SUCCESS; +} + +int ISOMAP_DrawMetamap(R_SURFACE * dst_s, int map_x, int map_y) +{ + int meta_base_x = map_x; + int meta_base_y = map_y; + + int meta_xi; + int meta_yi; + + int meta_x; + int meta_y; + + int meta_idx; + + for (meta_yi = SAGA_METAMAP_H - 1; meta_yi >= 0; meta_yi--) { + + meta_x = meta_base_x; + meta_y = meta_base_y; + + for (meta_xi = SAGA_METAMAP_W - 1; meta_xi >= 0; meta_xi--) { + + meta_idx = meta_xi + (meta_yi * 16); + + ISOMAP_DrawMetaTile(dst_s, + IsoModule.metamap_tbl[meta_idx], meta_x, meta_y); + + meta_x += 128; + meta_y += 64; + } + + meta_base_x -= 128; + meta_base_y += 64; + } + + return R_SUCCESS; +} + +int +ISOMAP_DrawMetaTile(R_SURFACE * dst_s, uint mtile_i, int mtile_x, int mtile_y) +{ + + int tile_xi; + int tile_yi; + + int tile_x; + int tile_y; + + int tile_base_x; + int tile_base_y; + + int tile_i; + + R_ISO_METATILE_ENTRY *mtile_p; + assert(IsoModule.init && IsoModule.mtiles_loaded); + + if (mtile_i >= IsoModule.mtile_ct) { + return R_FAILURE; + } + + mtile_p = &IsoModule.mtile_tbl[mtile_i]; + + tile_base_x = mtile_x; + tile_base_y = mtile_y; + + for (tile_yi = SAGA_METATILE_H - 1; tile_yi >= 0; tile_yi--) { + + tile_y = tile_base_y; + tile_x = tile_base_x; + + for (tile_xi = SAGA_METATILE_W - 1; tile_xi >= 0; tile_xi--) { + + tile_i = tile_xi + (tile_yi * SAGA_METATILE_W); + + ISOMAP_DrawTile(dst_s, + mtile_p->tile_tbl[tile_i], tile_x, tile_y); + + tile_x += SAGA_ISOTILE_WIDTH / 2; + tile_y += SAGA_ISOTILE_BASEHEIGHT / 2 + 1; + + } + + tile_base_x -= SAGA_ISOTILE_WIDTH / 2; + tile_base_y += SAGA_ISOTILE_BASEHEIGHT / 2 + 1; + + } + + return R_SUCCESS; +} + +int ISOMAP_DrawTile(R_SURFACE * dst_s, uint tile_i, int tile_x, int tile_y) +{ + + const uchar *tile_p; + const uchar *read_p; + + uchar *draw_p; + + int draw_x; + int draw_y; + + int tile_h; + int w_count = 0; + int row; + + int bg_runct; + int fg_runct; + int ct; + + assert(IsoModule.init && IsoModule.tiles_loaded); + + if (tile_i >= IsoModule.tile_ct) { + return R_FAILURE; + } + + /* temporary x clip */ + if (tile_x < 0) { + return R_SUCCESS; + } + + /* temporary x clip */ + if (tile_x >= 320 - 32) { + return R_SUCCESS; + } + + tile_p = IsoModule.tileres_p + IsoModule.tile_tbl[tile_i].tile_offset; + tile_h = IsoModule.tile_tbl[tile_i].tile_h; + + read_p = tile_p; + draw_p = dst_s->buf + tile_x + (tile_y * dst_s->buf_pitch); + + draw_x = tile_x; + draw_y = tile_y; + + if (tile_h > SAGA_ISOTILE_BASEHEIGHT) { + draw_y = tile_y - (tile_h - SAGA_ISOTILE_BASEHEIGHT); + } + + /* temporary y clip */ + if (draw_y < 0) { + return R_SUCCESS; + } + + for (row = 0; row < tile_h; row++) { + + draw_p = + dst_s->buf + draw_x + ((draw_y + row) * dst_s->buf_pitch); + w_count = 0; + + /* temporary y clip */ + if ((draw_y + row) >= 137) { + return R_SUCCESS; + } + + for (;;) { + + bg_runct = *read_p++; + w_count += bg_runct; + + if (w_count >= SAGA_ISOTILE_WIDTH) { + break; + } + + draw_p += bg_runct; + + fg_runct = *read_p++; + w_count += fg_runct; + + for (ct = 0; ct < fg_runct; ct++) { + + *draw_p++ = *read_p++; + } + } + } + + return R_SUCCESS; +} + +} // End of namespace Saga diff --git a/saga/isomap.h b/saga/isomap.h new file mode 100644 index 0000000000..dfd9daa33f --- /dev/null +++ b/saga/isomap.h @@ -0,0 +1,104 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Isometric level module - private header + + Notes: +*/ + +#ifndef SAGA_ISOMAP_H_ +#define SAGA_ISOMAP_H_ + +namespace Saga { + +typedef struct R_ISOTILE_ENTRY_tag { + + int tile_h; + int unknown01; + size_t tile_offset; + int unknown04; + int unknown06; + +} R_ISOTILE_ENTRY; + +#define SAGA_ISOTILE_ENTRY_LEN 8 +#define SAGA_ISOTILE_WIDTH 32 +#define SAGA_ISOTILE_BASEHEIGHT 15 + +#define SAGA_METATILE_W 8 +#define SAGA_METATILE_H 8 +#define SAGA_METATILE_SIZE 64 + +#define SAGA_METAMAP_W 16 +#define SAGA_METAMAP_H 16 +#define SAGA_METAMAP_SIZE 256 + +typedef struct R_ISO_METATILE_ENTRY_tag { + + int mtile_n; + int unknown02; + int unknown04; + int unknown06; + + int tile_tbl[SAGA_METATILE_SIZE]; + +} R_ISO_METATILE_ENTRY; + +#define SAGA_METATILE_ENTRY_LEN 136 + +typedef struct R_ISOMAP_MODULE_tag { + + int init; + + int tiles_loaded; + const uchar *tileres_p; + size_t tileres_len; + uint tile_ct; + R_ISOTILE_ENTRY *tile_tbl; + + int mtiles_loaded; + const uchar *mtileres_p; + size_t mtileres_len; + uint mtile_ct; + R_ISO_METATILE_ENTRY *mtile_tbl; + + int metamap_loaded; + int metamap_n; + uint metamap_tbl[SAGA_METAMAP_SIZE]; + const uchar *mm_res_p; + size_t mm_res_len; + +} R_ISOMAP_MODULE; + +int ISOMAP_DrawTile(R_SURFACE * dst_s, uint tile_i, int tile_x, int tile_y); + +int +ISOMAP_DrawMetaTile(R_SURFACE * dst_s, uint mtile_i, int mtile_x, int mtile_y); + +int ISOMAP_DrawMetamap(R_SURFACE * dst_s, int map_x, int map_y); + +} // End of namespace Saga + +#endif /* SAGA_ISOMAP_H_ */ diff --git a/saga/isomap_mod.h b/saga/isomap_mod.h new file mode 100644 index 0000000000..f18200758a --- /dev/null +++ b/saga/isomap_mod.h @@ -0,0 +1,48 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Isometric level module - public module header + + Notes: +*/ + +#ifndef SAGA_ISOMAP_MOD_H_ +#define SAGA_ISOMAP_MOD_H_ + +namespace Saga { + +int ISOMAP_Init(void); + +int ISOMAP_LoadTileset(const uchar *, size_t); + +int ISOMAP_LoadMetaTileset(const uchar *, size_t); + +int ISOMAP_LoadMetamap(const uchar * mm_res_p, size_t mm_res_len); + +int ISOMAP_Draw(R_SURFACE * dst_s); + +} // End of namespace Saga + +#endif /* SAGA_ISOMAP_MOD_H_ */ diff --git a/saga/ite_introproc.cpp b/saga/ite_introproc.cpp new file mode 100644 index 0000000000..8190472af9 --- /dev/null +++ b/saga/ite_introproc.cpp @@ -0,0 +1,1177 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Intro sequence scene procedures + + Notes: +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "yslib.h" + +#include "reinherit.h" + +/* + * Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "animation_mod.h" +#include "cvar_mod.h" +#include "events_mod.h" +#include "font_mod.h" +#include "game_mod.h" +#include "rscfile_mod.h" +#include "scene_mod.h" +#include "sndres_mod.h" +#include "text_mod.h" +#include "palanim_mod.h" + +/* + * Begin module: +\*--------------------------------------------------------------------------*/ +#include "scene.h" +#include "ite_introproc.h" + +namespace Saga { + +static R_INTRO_DIALOGUE IntroDiag[] = { + + { + CAVE_VOICE_0, "intro1a", + "We see the sky, we see the land, we see the water, " + "and we wonder: Are we the only ones?"}, + { + CAVE_VOICE_1, "intro2a", + "Long before we came to exist, the humans ruled " + "the Earth."}, + { + CAVE_VOICE_2, "intro3a", + "They made marvelous things, and moved whole " "mountains."}, + { + CAVE_VOICE_3, "intro4a", + "They knew the Secret of Flight, the Secret of " + "Happiness, and other secrets beyond our imagining."}, + { + CAVE_VOICE_4, "intro1b", + "The humans also knew the Secret of Life, " + "and used it to give us the Four Great Gifts:"}, + { + CAVE_VOICE_5, "intro2b", + "Thinking minds, feeling hearts, speaking " + "mouths, and reaching hands."}, + { + CAVE_VOICE_6, "intro3b", + "We are their children."}, + { + CAVE_VOICE_7, "intro1c", + "They taught us how to use our hands, and how " "to speak."}, + { + CAVE_VOICE_8, "intro2c", + "They showed us the joy of using our minds."}, + { + CAVE_VOICE_9, "intro3c", + "They loved us, and when we were ready, they " + "surely would have given us the Secret of Happiness."}, + + { + CAVE_VOICE_10, "intro1d", + "And now we see the sky, the land, and the water " + "that we are heirs to, and we wonder: why did " + "they leave?"}, + + { + CAVE_VOICE_11, "intro2d", + "Do they live still, in the stars? In the oceans " + "depths? In the wind?"}, + { + CAVE_VOICE_12, "intro3d", + "We wonder, was their fate good or evil?"}, + + { + CAVE_VOICE_13, "intro4d", + "And will we also share the same fate one day?"}, +}; + +R_SCENE_QUEUE ITE_IntroList[] = { + {ITE_INTRO_ANIM_SCENE, NULL, BY_RESOURCE, ITE_IntroAnimProc, 0}, + {ITE_CAVE_SCENE_1, NULL, BY_RESOURCE, ITE_IntroCave1Proc, 1}, + {ITE_CAVE_SCENE_2, NULL, BY_RESOURCE, ITE_IntroCave2Proc, 0}, + {ITE_CAVE_SCENE_3, NULL, BY_RESOURCE, ITE_IntroCave3Proc, 0}, + {ITE_CAVE_SCENE_4, NULL, BY_RESOURCE, ITE_IntroCave4Proc, 0}, + {ITE_VALLEY_SCENE, NULL, BY_RESOURCE, ITE_IntroValleyProc, 0}, + {ITE_TREEHOUSE_SCENE, NULL, BY_RESOURCE, ITE_IntroTreeHouseProc, 0}, + {ITE_FAIREPATH_SCENE, NULL, BY_RESOURCE, ITE_IntroFairePathProc, 0}, + {ITE_FAIRETENT_SCENE, NULL, BY_RESOURCE, ITE_IntroFaireTentProc, 0} +}; + +int ITE_StartProc(void) +{ + size_t n_introscenes; + size_t i; + + R_SCENE_QUEUE first_scene; + R_GAME_SCENEDESC gs_desc; + + n_introscenes = YS_NELEMS(ITE_IntroList); + + for (i = 0; i < n_introscenes; i++) { + + SCENE_Queue(&ITE_IntroList[i]); + } + + GAME_GetSceneInfo(&gs_desc); + + first_scene.load_flag = BY_SCENE; + first_scene.scene_n = gs_desc.first_scene; + first_scene.scene_skiptarget = 1; + first_scene.scene_proc = InitialSceneProc; + + SCENE_Queue(&first_scene); + + return R_SUCCESS; +} + +int ITE_IntroRegisterLang(void) +{ + + size_t i; + + for (i = 0; i < YS_NELEMS(IntroDiag); i++) { + + if (CVAR_Register_S(IntroDiag[i].i_str, + IntroDiag[i].i_cvar_name, + NULL, R_CVAR_CFG, R_INTRO_STRMAX) != R_SUCCESS) { + + R_printf(R_STDERR, + "Error registering intro text cvars."); + + return R_FAILURE; + } + } + + return R_SUCCESS; +} + +int ITE_IntroAnimProc(int param, R_SCENE_INFO * scene_info) +/*--------------------------------------------------------------------------*\ + * Handles the introductory Dreamer's Guild / NWC logo animation scene. +\*--------------------------------------------------------------------------*/ +{ + R_EVENT event; + + YS_IGNORE_PARAM(scene_info); + + switch (param) { + + case SCENE_BEGIN: + + /* Background for intro scene is the first frame of the + * intro animation; display it and set the palette + \*-----------------------------------------------------*/ + event.type = R_ONESHOT_EVENT; + event.code = R_BG_EVENT; + event.op = EVENT_DISPLAY; + event.param = SET_PALETTE; + event.time = 0; + + EVENT_Queue(&event); + + R_printf(R_STDOUT, "Intro animation procedure started.\n"); + R_printf(R_STDOUT, "Linking animation resources...\n"); + + ANIM_SetFrameTime(0, ITE_INTRO_FRAMETIME); + + /* Link this scene's animation resources for continuous + * playback + \*-----------------------------------------------------*/ + ANIM_Link(0, 1); + ANIM_Link(1, 2); + ANIM_Link(2, 3); + ANIM_Link(3, 4); + ANIM_Link(4, 5); + ANIM_Link(5, 6); + + /* Scene should end on display of last animation frame + * \*----------------------------------------------------- */ + ANIM_SetFlag(6, ANIM_ENDSCENE); + + R_printf(R_STDOUT, "Beginning animation playback.\n"); + + ANIM_Play(0, 0); + + /* Queue intro music playback + * \*----------------------------------------------------- */ + event.type = R_ONESHOT_EVENT; + event.code = R_MUSIC_EVENT; + event.param = MUSIC_1; + event.param2 = R_MUSIC_LOOP; + event.op = EVENT_PLAY; + event.time = 0; + + EVENT_Queue(&event); + break; + + case SCENE_END: + break; + + default: + R_printf(R_STDERR, "Illegal scene procedure parameter.\n"); + break; + + } + + return 0; +} + +int ITE_IntroCave1Proc(int param, R_SCENE_INFO * scene_info) +/*--------------------------------------------------------------------------*\ + * Handles first introductory cave painting scene +\*--------------------------------------------------------------------------*/ +{ + R_EVENT event = { 0 }; + R_EVENT *q_event; + + int event_time = 0; + int voice_len; + int voice_pad = 50; + + R_TEXTLIST_ENTRY text_entry = { 0 }; + R_TEXTLIST_ENTRY *entry_p; + + PALENTRY *pal; + + static PALENTRY current_pal[R_PAL_ENTRIES]; + + int i; + + int font_flags = FONT_OUTLINE | FONT_CENTERED; + + switch (param) { + + case SCENE_BEGIN: + + /* Fade to black out of the intro DG/NWC logo animation + * \*----------------------------------------------------- */ + SYSGFX_GetCurrentPal(current_pal); + + event.type = R_CONTINUOUS_EVENT; + event.code = R_PAL_EVENT; + event.op = EVENT_PALTOBLACK; + event.time = 0; + event.duration = PALETTE_FADE_DURATION; + event.data = current_pal; + + q_event = EVENT_Queue(&event); + + /* Display scene background, but stay with black palette + * \*----------------------------------------------------- */ + event.type = R_ONESHOT_EVENT; + event.code = R_BG_EVENT; + event.op = EVENT_DISPLAY; + event.param = NO_SET_PALETTE; + event.time = 0; + + q_event = EVENT_Chain(q_event, &event); + + /* Fade in from black to the scene background palette + * \*----------------------------------------------------- */ + SCENE_GetBGPal(&pal); + + event.type = R_CONTINUOUS_EVENT; + event.code = R_PAL_EVENT; + event.op = EVENT_BLACKTOPAL; + event.time = 0; + event.duration = PALETTE_FADE_DURATION; + event.data = pal; + + q_event = EVENT_Chain(q_event, &event); + + /* Begin palette cycling animation for candles + * \*----------------------------------------------------- */ + event.type = R_ONESHOT_EVENT; + event.code = R_PALANIM_EVENT; + event.op = EVENT_CYCLESTART; + event.time = 0; + + q_event = EVENT_Chain(q_event, &event); + + /* Queue narrator dialogue list + * \*----------------------------------------------------- */ + text_entry.color = 255; + text_entry.effect_color = 0; + text_entry.text_x = 320 / 2; + text_entry.text_y = INTRO_CAPTION_Y; + text_entry.font_id = MEDIUM_FONT_ID; + text_entry.flags = font_flags; + + for (i = INTRO_CAVE1_START; i < INTRO_CAVE1_END; i++) { + + text_entry.string = IntroDiag[i].i_str; + + entry_p = TEXT_AddEntry(scene_info->text_list, + &text_entry); + + /* Display text */ + event.type = R_ONESHOT_EVENT; + event.code = R_TEXT_EVENT; + event.op = EVENT_DISPLAY; + event.data = entry_p; + event.time = event_time; + + q_event = EVENT_Chain(q_event, &event); + + /* Play voice */ + event.type = R_ONESHOT_EVENT; + event.code = R_VOICE_EVENT; + event.op = EVENT_PLAY; + event.param = IntroDiag[i].i_voice_rn; + event.time = event_time; + + q_event = EVENT_Chain(q_event, &event); + + voice_len = + SND_GetVoiceLength(IntroDiag[i].i_voice_rn); + if (voice_len < 0) { + voice_len = strlen(IntroDiag[i].i_str) * + VOICE_LETTERLEN; + } + + /* Remove text */ + event.type = R_ONESHOT_EVENT; + event.code = R_TEXT_EVENT; + event.op = EVENT_REMOVE; + event.data = entry_p; + event.time = voice_len; + + q_event = EVENT_Chain(q_event, &event); + + event_time = voice_pad; + + } + + /* End scene after last dialogue over + * \*----------------------------------------------------- */ + event.type = R_ONESHOT_EVENT; + event.code = R_SCENE_EVENT; + event.op = EVENT_END; + event.time = 0; + + q_event = EVENT_Chain(q_event, &event); + + break; + + case SCENE_END: + break; + + default: + R_printf(R_STDERR, "Illegal scene procedure paramater.\n"); + break; + + } + + return 0; +} + +int ITE_IntroCave2Proc(int param, R_SCENE_INFO * scene_info) +/*--------------------------------------------------------------------------*\ + * Handles second introductory cave painting scene +\*--------------------------------------------------------------------------*/ +{ + + R_EVENT event = { 0 }; + R_EVENT *q_event; + + int event_time = 0; + int voice_len; + int voice_pad = 50; + + R_TEXTLIST_ENTRY text_entry = { 0 }; + R_TEXTLIST_ENTRY *entry_p; + + int i; + + int font_flags = FONT_OUTLINE | FONT_CENTERED; + + switch (param) { + + case SCENE_BEGIN: + + /* Start 'dissolve' transition to new scene background + * \*----------------------------------------------------- */ + event.type = R_CONTINUOUS_EVENT; + event.code = R_TRANSITION_EVENT; + event.op = EVENT_DISSOLVE; + event.time = 0; + event.duration = DISSOLVE_DURATION; + + q_event = EVENT_Queue(&event); + + /* Begin palette cycling animation for candles + * \*----------------------------------------------------- */ + event.type = R_ONESHOT_EVENT; + event.code = R_PALANIM_EVENT; + event.op = EVENT_CYCLESTART; + event.time = 0; + + q_event = EVENT_Chain(q_event, &event); + + /* Queue narrator dialogue list + * \*----------------------------------------------------- */ + text_entry.color = 255; + text_entry.effect_color = 0; + text_entry.text_x = 320 / 2; + text_entry.text_y = INTRO_CAPTION_Y; + text_entry.font_id = MEDIUM_FONT_ID; + text_entry.flags = font_flags; + + for (i = INTRO_CAVE2_START; i < INTRO_CAVE2_END; i++) { + + text_entry.string = IntroDiag[i].i_str; + + entry_p = TEXT_AddEntry(scene_info->text_list, + &text_entry); + + /* Display text */ + event.type = R_ONESHOT_EVENT; + event.code = R_TEXT_EVENT; + event.op = EVENT_DISPLAY; + event.data = entry_p; + event.time = event_time; + + q_event = EVENT_Chain(q_event, &event); + + /* Play voice */ + event.type = R_ONESHOT_EVENT; + event.code = R_VOICE_EVENT; + event.op = EVENT_PLAY; + event.param = IntroDiag[i].i_voice_rn; + event.time = event_time; + + q_event = EVENT_Chain(q_event, &event); + + voice_len = + SND_GetVoiceLength(IntroDiag[i].i_voice_rn); + if (voice_len < 0) { + voice_len = strlen(IntroDiag[i].i_str) * + VOICE_LETTERLEN; + } + + /* Remove text */ + event.type = R_ONESHOT_EVENT; + event.code = R_TEXT_EVENT; + event.op = EVENT_REMOVE; + event.data = entry_p; + event.time = voice_len; + + q_event = EVENT_Chain(q_event, &event); + + event_time = voice_pad; + } + + /* End scene after last dialogue over + * \*----------------------------------------------------- */ + event.type = R_ONESHOT_EVENT; + event.code = R_SCENE_EVENT; + event.op = EVENT_END; + event.time = event_time; + + q_event = EVENT_Chain(q_event, &event); + + break; + + case SCENE_END: + break; + + default: + R_printf(R_STDERR, "Illegal scene procedure paramater.\n"); + break; + + } + + return 0; +} + +int ITE_IntroCave3Proc(int param, R_SCENE_INFO * scene_info) +/*--------------------------------------------------------------------------*\ + * Handles third introductory cave painting scene +\*--------------------------------------------------------------------------*/ +{ + R_EVENT event = { 0 }; + R_EVENT *q_event; + + int event_time = 0; + int voice_len; + int voice_pad = 50; + + R_TEXTLIST_ENTRY text_entry = { 0 }; + R_TEXTLIST_ENTRY *entry_p; + + int i; + + int font_flags = FONT_OUTLINE | FONT_CENTERED; + + switch (param) { + + case SCENE_BEGIN: + + /* Start 'dissolve' transition to new scene background + * \*----------------------------------------------------- */ + event.type = R_CONTINUOUS_EVENT; + event.code = R_TRANSITION_EVENT; + event.op = EVENT_DISSOLVE; + event.time = 0; + event.duration = DISSOLVE_DURATION; + + q_event = EVENT_Queue(&event); + + /* Begin palette cycling animation for candles + * \*----------------------------------------------------- */ + event.type = R_ONESHOT_EVENT; + event.code = R_PALANIM_EVENT; + event.op = EVENT_CYCLESTART; + event.time = 0; + + q_event = EVENT_Chain(q_event, &event); + + /* Queue narrator dialogue list + * \*----------------------------------------------------- */ + text_entry.color = 255; + text_entry.effect_color = 0; + text_entry.text_x = 320 / 2; + text_entry.text_y = INTRO_CAPTION_Y; + text_entry.font_id = MEDIUM_FONT_ID; + text_entry.flags = font_flags; + + for (i = INTRO_CAVE3_START; i < INTRO_CAVE3_END; i++) { + + text_entry.string = IntroDiag[i].i_str; + + entry_p = TEXT_AddEntry(scene_info->text_list, + &text_entry); + + /* Display text */ + event.type = R_ONESHOT_EVENT; + event.code = R_TEXT_EVENT; + event.op = EVENT_DISPLAY; + event.data = entry_p; + event.time = event_time; + + q_event = EVENT_Chain(q_event, &event); + + /* Play voice */ + event.type = R_ONESHOT_EVENT; + event.code = R_VOICE_EVENT; + event.op = EVENT_PLAY; + event.param = IntroDiag[i].i_voice_rn; + event.time = event_time; + + q_event = EVENT_Chain(q_event, &event); + + voice_len = + SND_GetVoiceLength(IntroDiag[i].i_voice_rn); + if (voice_len < 0) { + voice_len = strlen(IntroDiag[i].i_str) * + VOICE_LETTERLEN; + } + + /* Remove text */ + event.type = R_ONESHOT_EVENT; + event.code = R_TEXT_EVENT; + event.op = EVENT_REMOVE; + event.data = entry_p; + event.time = voice_len; + + q_event = EVENT_Chain(q_event, &event); + + event_time = voice_pad; + } + + /* End scene after last dialogue over + * \*----------------------------------------------------- */ + event.type = R_ONESHOT_EVENT; + event.code = R_SCENE_EVENT; + event.op = EVENT_END; + event.time = event_time; + + q_event = EVENT_Chain(q_event, &event); + + break; + + case SCENE_END: + break; + + default: + R_printf(R_STDERR, "Illegal scene procedure paramater.\n"); + break; + + } + + return 0; +} + +int ITE_IntroCave4Proc(int param, R_SCENE_INFO * scene_info) +/*--------------------------------------------------------------------------*\ + * Handles fourth introductory cave painting scene +\*--------------------------------------------------------------------------*/ +{ + R_EVENT event = { 0 }; + R_EVENT *q_event; + + int event_time = 0; + int voice_len; + int voice_pad = 50; + + R_TEXTLIST_ENTRY text_entry = { 0 }; + R_TEXTLIST_ENTRY *entry_p; + + int i; + + int font_flags = FONT_OUTLINE | FONT_CENTERED; + + switch (param) { + + case SCENE_BEGIN: + + /* Start 'dissolve' transition to new scene background + * \*----------------------------------------------------- */ + event.type = R_CONTINUOUS_EVENT; + event.code = R_TRANSITION_EVENT; + event.op = EVENT_DISSOLVE; + event.time = 0; + event.duration = DISSOLVE_DURATION; + + q_event = EVENT_Queue(&event); + + /* Begin palette cycling animation for candles + * \*----------------------------------------------------- */ + event.type = R_ONESHOT_EVENT; + event.code = R_PALANIM_EVENT; + event.op = EVENT_CYCLESTART; + event.time = 0; + + q_event = EVENT_Chain(q_event, &event); + + /* Queue narrator dialogue list + * \*----------------------------------------------------- */ + text_entry.color = 255; + text_entry.effect_color = 0; + text_entry.text_x = 320 / 2; + text_entry.text_y = INTRO_CAPTION_Y; + text_entry.font_id = MEDIUM_FONT_ID; + text_entry.flags = font_flags; + + for (i = INTRO_CAVE4_START; i < INTRO_CAVE4_END; i++) { + + text_entry.string = IntroDiag[i].i_str; + entry_p = TEXT_AddEntry(scene_info->text_list, + &text_entry); + + /* Display text */ + event.type = R_ONESHOT_EVENT; + event.code = R_TEXT_EVENT; + event.op = EVENT_DISPLAY; + event.data = entry_p; + event.time = event_time; + + q_event = EVENT_Chain(q_event, &event); + + /* Play voice */ + event.type = R_ONESHOT_EVENT; + event.code = R_VOICE_EVENT; + event.op = EVENT_PLAY; + event.param = IntroDiag[i].i_voice_rn; + event.time = event_time; + + q_event = EVENT_Chain(q_event, &event); + + voice_len = + SND_GetVoiceLength(IntroDiag[i].i_voice_rn); + if (voice_len < 0) { + voice_len = strlen(IntroDiag[i].i_str) * + VOICE_LETTERLEN; + } + + /* Remove text */ + event.type = R_ONESHOT_EVENT; + event.code = R_TEXT_EVENT; + event.op = EVENT_REMOVE; + event.data = entry_p; + event.time = voice_len; + + q_event = EVENT_Chain(q_event, &event); + + event_time = voice_pad; + + } + + /* End scene after last dialogue over + * \*----------------------------------------------------- */ + event.type = R_ONESHOT_EVENT; + event.code = R_SCENE_EVENT; + event.op = EVENT_END; + event.time = event_time; + + q_event = EVENT_Chain(q_event, &event); + + break; + + case SCENE_END: + break; + + default: + R_printf(R_STDERR, "Illegal scene procedure paramater.\n"); + break; + + } + + return 0; + +} + +int ITE_IntroValleyProc(int param, R_SCENE_INFO * scene_info) +/*--------------------------------------------------------------------------*\ + * Handles intro title scene (valley overlook) +\*--------------------------------------------------------------------------*/ +{ + R_TEXTLIST_ENTRY text_entry = { 0 }; + R_TEXTLIST_ENTRY *entry_p; + + R_EVENT event; + R_EVENT *q_event; + + int i; + + const INTRO_CREDIT credits[] = { + {160, 44, 9000, CREDIT_DURATION1, + "Producer", SMALL_FONT_ID}, + {160, 56, 0, CREDIT_DURATION1, + "Walter Hochbrueckner", MEDIUM_FONT_ID}, + {160, 88, 0, CREDIT_DURATION1, + "Executive Producer", SMALL_FONT_ID}, + {160, 100, 0, CREDIT_DURATION1, + "Robert McNally", MEDIUM_FONT_ID}, + {160, 132, 0, CREDIT_DURATION1, + "Publisher", SMALL_FONT_ID}, + {160, 144, 0, CREDIT_DURATION1, + "Jon Van Caneghem", MEDIUM_FONT_ID} + }; + + int n_credits = sizeof credits / sizeof credits[0]; + + int event_delay = 0; + + switch (param) { + + case SCENE_BEGIN: + + /* Display ITE title screen background + * \*----------------------------------------------------- */ + event.type = R_ONESHOT_EVENT; + event.code = R_BG_EVENT; + event.op = EVENT_DISPLAY; + event.param = SET_PALETTE; + event.time = 0; + + q_event = EVENT_Queue(&event); + + R_printf(R_STDOUT, "Beginning animation playback.\n"); + + /* Begin title screen background animation + * \*----------------------------------------------------- */ + ANIM_SetFlag(0, ANIM_LOOP); + ANIM_Play(0, 0); + + /* Begin ITE title theme music + * \*----------------------------------------------------- */ + SYSMUSIC_Stop(); + + event.type = R_ONESHOT_EVENT; + event.code = R_MUSIC_EVENT; + event.param = MUSIC_2; + event.op = EVENT_PLAY; + event.time = 0; + + q_event = EVENT_Chain(q_event, &event); + + /* Queue game credits list + * \*----------------------------------------------------- */ + text_entry.color = 255; + text_entry.effect_color = 0; + text_entry.flags = FONT_OUTLINE | FONT_CENTERED; + + for (i = 0; i < n_credits; i++) { + + text_entry.string = credits[i].string; + text_entry.font_id = credits[i].font_id; + text_entry.text_x = credits[i].text_x; + text_entry.text_y = credits[i].text_y; + + entry_p = TEXT_AddEntry(scene_info->text_list, + &text_entry); + + /* Display text */ + event.type = R_ONESHOT_EVENT; + event.code = R_TEXT_EVENT; + event.op = EVENT_DISPLAY; + event.data = entry_p; + event.time = event_delay += credits[i].delta_time; + + q_event = EVENT_Queue(&event); + + /* Remove text */ + event.type = R_ONESHOT_EVENT; + event.code = R_TEXT_EVENT; + event.op = EVENT_REMOVE; + event.data = entry_p; + event.time = credits[i].duration; + + q_event = EVENT_Chain(q_event, &event); + } + + /* End scene after credit display + * \*----------------------------------------------------- */ + event.type = R_ONESHOT_EVENT; + event.code = R_SCENE_EVENT; + event.op = EVENT_END; + event.time = 1000; + + q_event = EVENT_Chain(q_event, &event); + break; + + case SCENE_END: + break; + + default: + R_printf(R_STDERR, "Illegal scene procedure parameter.\n"); + break; + + } + + return 0; +} + +int ITE_IntroTreeHouseProc(int param, R_SCENE_INFO * scene_info) +/*--------------------------------------------------------------------------*\ + * Handles second intro credit screen (treehouse view) +\*--------------------------------------------------------------------------*/ +{ + R_TEXTLIST_ENTRY text_entry = { 0 }; + R_TEXTLIST_ENTRY *entry_p; + + R_EVENT event = { 0 }; + R_EVENT *q_event; + + int i; + + const INTRO_CREDIT credits[] = { + {160, 58, 2000, CREDIT_DURATION1, + "Game Design", SMALL_FONT_ID}, + {160, 70, 0, CREDIT_DURATION1, + "Talin, Joe Pearce, Robert McNally", MEDIUM_FONT_ID}, + {160, 80, 0, CREDIT_DURATION1, + "and Carolly Hauksdottir", MEDIUM_FONT_ID}, + {160, 119, 0, CREDIT_DURATION1, + "Screenplay and Dialog", SMALL_FONT_ID}, + {160, 131, 0, CREDIT_DURATION1, + "Robert Leh, Len Wein, and Bill Rotsler", + MEDIUM_FONT_ID}, + {160, 54, 5000, CREDIT_DURATION1, + "Art", SMALL_FONT_ID}, + {160, 66, 0, CREDIT_DURATION1, + "Edward Lacabanne, Glenn Price, April Lee,", + MEDIUM_FONT_ID}, + {160, 76, 0, CREDIT_DURATION1, + "Lisa Iennaco, Brian Dowrick, Reed", MEDIUM_FONT_ID}, + {160, 86, 0, CREDIT_DURATION1, + "Waller, Allison Hershey and Talin", MEDIUM_FONT_ID}, + {160, 123, 0, CREDIT_DURATION1, + "Art Direction", SMALL_FONT_ID}, + {160, 135, 0, CREDIT_DURATION1, + "Allison Hershey", MEDIUM_FONT_ID} + }; + + int n_credits = YS_NELEMS(credits); + + int event_delay = 0; + + switch (param) { + + case SCENE_BEGIN: + + /* Start 'dissolve' transition to new scene background + * \*----------------------------------------------------- */ + event.type = R_CONTINUOUS_EVENT; + event.code = R_TRANSITION_EVENT; + event.op = EVENT_DISSOLVE; + event.time = 0; + event.duration = DISSOLVE_DURATION; + + q_event = EVENT_Queue(&event); + + event_delay = DISSOLVE_DURATION; + + /* Begin title screen background animation + * \*----------------------------------------------------- */ + ANIM_SetFrameTime(0, 100); + ANIM_Play(0, event_delay); + + /* Queue game credits list + * \*----------------------------------------------------- */ + text_entry.color = 255; + text_entry.effect_color = 0; + text_entry.flags = FONT_OUTLINE | FONT_CENTERED; + + for (i = 0; i < n_credits; i++) { + + text_entry.string = credits[i].string; + text_entry.font_id = credits[i].font_id; + text_entry.text_x = credits[i].text_x; + text_entry.text_y = credits[i].text_y; + + entry_p = TEXT_AddEntry(scene_info->text_list, + &text_entry); + + /* Display text */ + event.type = R_ONESHOT_EVENT; + event.code = R_TEXT_EVENT; + event.op = EVENT_DISPLAY; + event.data = entry_p; + event.time = event_delay += credits[i].delta_time; + + q_event = EVENT_Queue(&event); + + /* Remove text */ + event.type = R_ONESHOT_EVENT; + event.code = R_TEXT_EVENT; + event.op = EVENT_REMOVE; + event.data = entry_p; + event.time = credits[i].duration; + + q_event = EVENT_Chain(q_event, &event); + } + + /* End scene after credit display + * \*----------------------------------------------------- */ + event.type = R_ONESHOT_EVENT; + event.code = R_SCENE_EVENT; + event.op = EVENT_END; + event.time = 1000; + + q_event = EVENT_Chain(q_event, &event); + + break; + + case SCENE_END: + + break; + + default: + R_printf(R_STDERR, "Illegal scene procedure parameter.\n"); + break; + + } + + return 0; + +} + +int ITE_IntroFairePathProc(int param, R_SCENE_INFO * scene_info) +/*--------------------------------------------------------------------------*\ + * Handles third intro credit screen (path to puzzle tent) +\*--------------------------------------------------------------------------*/ +{ + R_TEXTLIST_ENTRY text_entry = { 0 }; + R_TEXTLIST_ENTRY *entry_p; + + R_EVENT event = { 0 }; + R_EVENT *q_event; + + long event_delay = 0; + + int i; + + INTRO_CREDIT credits[] = { + {160, 58, 2000, CREDIT_DURATION1, + "Original Game Engine Programming", SMALL_FONT_ID}, + + {160, 70, 0, CREDIT_DURATION1, + "Talin, Walter Hochbrueckner,", MEDIUM_FONT_ID}, + + {160, 80, 0, CREDIT_DURATION1, + "Joe Burks and Robert Wiggins", MEDIUM_FONT_ID}, + + {160, 119, 0, CREDIT_DURATION1, + "Music and Sound", SMALL_FONT_ID}, + + {160, 131, 0, CREDIT_DURATION1, + "Matt Nathan", MEDIUM_FONT_ID}, + + {160, 58, 5000, CREDIT_DURATION1, + "Directed by", SMALL_FONT_ID}, + + {160, 70, 0, CREDIT_DURATION1, + "Talin", MEDIUM_FONT_ID}, + + {160, 119, 0, CREDIT_DURATION1, + "Game Engine Reconstruction", SMALL_FONT_ID}, + + {160, 131, 0, CREDIT_DURATION1, + "Alpha software - Use at your own risk.", + MEDIUM_FONT_ID} + }; + + int n_credits = sizeof credits / sizeof credits[0]; + + switch (param) { + + case SCENE_BEGIN: + + /* Start 'dissolve' transition to new scene background + * \*----------------------------------------------------- */ + event.type = R_CONTINUOUS_EVENT; + event.code = R_TRANSITION_EVENT; + event.op = EVENT_DISSOLVE; + event.time = 0; + event.duration = DISSOLVE_DURATION; + + q_event = EVENT_Queue(&event); + + event_delay = DISSOLVE_DURATION; + + /* Begin title screen background animation + * \*----------------------------------------------------- */ + ANIM_SetFlag(0, ANIM_LOOP); + ANIM_Play(0, event_delay); + + /* Queue game credits list + * \*----------------------------------------------------- */ + text_entry.color = 255; + text_entry.effect_color = 0; + text_entry.flags = FONT_OUTLINE | FONT_CENTERED; + + for (i = 0; i < n_credits; i++) { + + text_entry.string = credits[i].string; + text_entry.font_id = credits[i].font_id; + text_entry.text_x = credits[i].text_x; + text_entry.text_y = credits[i].text_y; + + entry_p = TEXT_AddEntry(scene_info->text_list, + &text_entry); + + /* Display text */ + event.type = R_ONESHOT_EVENT; + event.code = R_TEXT_EVENT; + event.op = EVENT_DISPLAY; + event.data = entry_p; + event.time = event_delay += credits[i].delta_time; + + q_event = EVENT_Queue(&event); + + /* Remove text */ + event.type = R_ONESHOT_EVENT; + event.code = R_TEXT_EVENT; + event.op = EVENT_REMOVE; + event.data = entry_p; + event.time = credits[i].duration; + + q_event = EVENT_Chain(q_event, &event); + } + + /* End scene after credit display + * \*----------------------------------------------------- */ + event.type = R_ONESHOT_EVENT; + event.code = R_SCENE_EVENT; + event.op = EVENT_END; + event.time = 1000; + + q_event = EVENT_Chain(q_event, &event); + + break; + + case SCENE_END: + break; + + default: + R_printf(R_STDERR, "Illegal scene procedure parameter.\n"); + break; + + } + + return 0; +} + +int ITE_IntroFaireTentProc(int param, R_SCENE_INFO * scene_info) +/*--------------------------------------------------------------------------*\ + * Handles fourth intro credit screen (treehouse view) +\*--------------------------------------------------------------------------*/ +{ + R_EVENT event = { 0 }; + R_EVENT *q_event; + R_EVENT *q_event_start; + + YS_IGNORE_PARAM(scene_info); + + switch (param) { + + case SCENE_BEGIN: + + /* Start 'dissolve' transition to new scene background + * \*----------------------------------------------------- */ + event.type = R_CONTINUOUS_EVENT; + event.code = R_TRANSITION_EVENT; + event.op = EVENT_DISSOLVE; + event.time = 0; + event.duration = DISSOLVE_DURATION; + + q_event_start = EVENT_Queue(&event); + + /* End scene after momentary pause + * \*----------------------------------------------------- */ + event.type = R_ONESHOT_EVENT; + event.code = R_SCENE_EVENT; + event.op = EVENT_END; + event.time = 5000; + + q_event = EVENT_Chain(q_event_start, &event); + + break; + + case SCENE_END: + + break; + + default: + R_printf(R_STDERR, "Illegal scene procedure parameter.\n"); + break; + + } + + return 0; +} + +} // End of namespace Saga diff --git a/saga/ite_introproc.h b/saga/ite_introproc.h new file mode 100644 index 0000000000..77c2035280 --- /dev/null +++ b/saga/ite_introproc.h @@ -0,0 +1,92 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Intro sequence scene procedures header file + + Notes: +*/ + +#ifndef SAGA_ITE_INTRO_H_ +#define SAGA_ITE_INTRO_H_ + +namespace Saga { + +#define R_INTRO_STRMAX 256 + +#define ITE_INTRO_FRAMETIME 90 + +#define INTRO_CAPTION_Y 170 +#define VOICE_PAD 50 +#define VOICE_LETTERLEN 90 + +#define PALETTE_FADE_DURATION 1000 +#define DISSOLVE_DURATION 3000 + +#define CREDIT_DURATION1 4000 + +enum R_INTRO_SCENE_DIALOGUE_INFO { + + INTRO_CAVE1_START = 0, + INTRO_CAVE1_END = 4, + + INTRO_CAVE2_START = 4, + INTRO_CAVE2_END = 7, + + INTRO_CAVE3_START = 7, + INTRO_CAVE3_END = 10, + + INTRO_CAVE4_START = 10, + INTRO_CAVE4_END = 14 +}; + +typedef struct R_INTRO_DIALOGUE_tag { + + ulong i_voice_rn; + char *i_cvar_name; + char i_str[R_INTRO_STRMAX]; + +} R_INTRO_DIALOGUE; + +typedef struct INTRO_CAPTION_tag { + + int res_n; + char *caption; + +} INTRO_CAPTION; + +typedef struct INTRO_CREDIT_tag { + + int text_x; + int text_y; + int delta_time; + int duration; + char *string; + int font_id; + +} INTRO_CREDIT; + +} // End of namespace Saga + +#endif /* SAGA_ITE_INTRO_H_ */ diff --git a/saga/ite_introproc_mod.h b/saga/ite_introproc_mod.h new file mode 100644 index 0000000000..d90a7783ec --- /dev/null +++ b/saga/ite_introproc_mod.h @@ -0,0 +1,40 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Intro sequence scene procedures - public header file + + Notes: +*/ + +#ifndef SAGA_ITE_INTROPROC_MOD_H_ +#define SAGA_ITE_INTROPROC_MOD_H_ + +namespace Saga { + +int ITE_IntroRegisterLang(void); + +} // End of namespace Saga + +#endif /* SAGA_ITE_INTROPROC_MOD_H_ */ diff --git a/saga/math.cpp b/saga/math.cpp new file mode 100644 index 0000000000..1c3b12fc93 --- /dev/null +++ b/saga/math.cpp @@ -0,0 +1,72 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Math routines + + Notes: +*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "reinherit.h" + +namespace Saga { + +int +MATH_HitTestPoly(R_POINT * points, unsigned int npoints, R_POINT test_point) +{ + int yflag0; + int yflag1; + int inside_flag = 0; + unsigned int pt; + + R_POINT *vtx0 = &points[npoints - 1]; + R_POINT *vtx1 = &points[0]; + + yflag0 = (vtx0->y >= test_point.y); + + for (pt = 0; pt < npoints; pt++, vtx1++) { + + yflag1 = (vtx1->y >= test_point.y); + + if (yflag0 != yflag1) { + + if (((vtx1->y - test_point.y) * (vtx0->x - vtx1->x) >= + (vtx1->x - test_point.x) * (vtx0->y - + vtx1->y)) == yflag1) { + + inside_flag = !inside_flag; + } + } + yflag0 = yflag1; + vtx0 = vtx1; + } + + return inside_flag; +} + +} // End of namespace Saga diff --git a/saga/math.h b/saga/math.h new file mode 100644 index 0000000000..645fd33bd7 --- /dev/null +++ b/saga/math.h @@ -0,0 +1,35 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Math routines implementation header + + Notes: +*/ + +#ifndef SAGA_MATH_H__ +#define SAGA_MATH_H__ + +#endif /* SAGA_MATH_H__ */ diff --git a/saga/math_mod.h b/saga/math_mod.h new file mode 100644 index 0000000000..13219fbebd --- /dev/null +++ b/saga/math_mod.h @@ -0,0 +1,42 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Math routines public header + + Notes: +*/ + +#ifndef SAGA_MATH_MOD_H__ +#define SAGA_MATH_MOD_H__ + +namespace Saga { + +int +MATH_HitTestPoly(R_POINT * points, unsigned int npoints, R_POINT test_point); + +} // End of namespace Saga + +#endif /* SAGA_MATH_MOD_H__ */ diff --git a/saga/misc.cpp b/saga/misc.cpp new file mode 100644 index 0000000000..e7a2c185ca --- /dev/null +++ b/saga/misc.cpp @@ -0,0 +1,54 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Misc. routines + + Notes: +*/ + +namespace Saga { + +int Granulate(int value, int granularity) +{ + + int remainder; + + if (value == 0) + return 0; + + if (granularity == 0) + return 0; + + remainder = value % granularity; + + if (remainder == 0) { + return value; + } else { + return (granularity - remainder + value); + } + +} + +} // End of namespace Saga diff --git a/saga/module.mk b/saga/module.mk index 0f7e4d3b2c..430a9912bc 100644 --- a/saga/module.mk +++ b/saga/module.mk @@ -1,10 +1,56 @@ MODULE := saga MODULE_OBJS = \ + saga/actionmap.o \ + saga/actor.o \ + saga/actordata.o \ + saga/animation.o \ + saga/cmdline.o \ + saga/console.o \ + saga/cvar.o \ + saga/events.o \ + saga/expr.o \ + saga/font.o \ + saga/font_map.o \ + saga/game.o \ + saga/gfx.o \ + saga/ihnm_introproc.o \ + saga/image.o \ + saga/interface.o \ + saga/isomap.o \ + saga/ite_introproc.o \ + saga/math.o \ + saga/misc.o \ + saga/objectmap.o \ + saga/palanim.o \ + saga/render.o \ + saga/rscfile.o \ saga/saga.o \ - saga/binread.o \ - saga/gamedesc.o \ - saga/resfile.o + saga/scene.o \ + saga/sceneproc.o \ + saga/script.o \ + saga/sdata.o \ + saga/sdebug.o \ + saga/sfuncs.o \ + saga/sndres.o \ + saga/sprite.o \ + saga/sstack.o \ + saga/stack.o \ + saga/sthread.o \ + saga/text.o \ + saga/transitions.o \ + saga/xmidi.o \ + saga/ys_binread.o \ + saga/ys_binwrite.o \ + saga/ys_dl_list.o \ + saga/ys_file.o \ + saga/sysgfx.o \ + saga/sysinput.o \ + saga/systimer.o \ + saga/sysmusic.o \ + saga/syssound.o \ + saga/sysio.o \ + saga/sys_fs.o MODULE_DIRS += \ saga diff --git a/saga/objectmap.cpp b/saga/objectmap.cpp new file mode 100644 index 0000000000..bd3ec1df8b --- /dev/null +++ b/saga/objectmap.cpp @@ -0,0 +1,556 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Object map / Object click-area module + + Notes: + + Polygon Hit Test code ( HitTestPoly() ) adapted from code (C) Eric Haines + appearing in Graphics Gems IV, "Point in Polygon Strategies." + p. 24-46, code: p. 34-45 +*/ + +#include "reinherit.h" + +#include "yslib.h" + +/* + * Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "cvar_mod.h" +#include "console_mod.h" +#include "gfx_mod.h" +#include "math_mod.h" +#include "font_mod.h" + +/* + * Module options +\*--------------------------------------------------------------------------*/ + +#define R_OBJECTMAP_DEBUG R_DEBUG_INFO + +/* + * Begin module +\*--------------------------------------------------------------------------*/ +#include "objectmap_mod.h" +#include "objectmap.h" + +namespace Saga { + +static R_OBJECTMAP_INFO OMInfo; + +int OBJECTMAP_Register(void) +{ + + CVAR_RegisterFunc(CF_object_info, + "object_info", NULL, R_CVAR_NONE, 0, 0); + + return R_SUCCESS; +} + +int OBJECTMAP_Init(void) +/*--------------------------------------------------------------------------*\ + * Initializes the object map module, creates module allocation context +\*--------------------------------------------------------------------------*/ +{ + R_printf(R_STDOUT, "OBJECTMAP Module: Initializing...\n"); + + OMInfo.initialized = 1; + return R_SUCCESS; +} + +int OBJECTMAP_Shutdown(void) +/*--------------------------------------------------------------------------*\ + * Shuts down the object map module, destroys module allocation context +\*--------------------------------------------------------------------------*/ +{ + if (!OMInfo.initialized) { + return R_FAILURE; + } + + R_printf(R_STDOUT, "OBJECTMAP Module: Shutting down...\n"); + + OBJECTMAP_Free(); + OBJECTMAP_FreeNames(); + + R_printf(R_STDOUT, "OBJECTMAP Module: Shutdown AOK.\n"); + + OMInfo.initialized = 0; + return R_SUCCESS; +} + +int OBJECTMAP_Load(const uchar * om_res, size_t om_res_len) +/*--------------------------------------------------------------------------*\ + * Loads an object map resource ( objects ( clickareas ( points ) ) ) +\*--------------------------------------------------------------------------*/ +{ + const unsigned char *read_p = om_res; + + R_OBJECTMAP_ENTRY *object_map; + R_CLICKAREA *clickarea; + R_POINT *point; + + int i, k, m; + + YS_IGNORE_PARAM(om_res_len); + + if (!OMInfo.initialized) { + R_printf(R_STDERR, + "Error: Object map module not initialized!\n"); + return R_FAILURE; + } + + if (OMInfo.objects_loaded) { + OBJECTMAP_Free(); + } + + /* Obtain object count N and allocate space for N objects + * \*------------------------------------------------------------- */ + OMInfo.n_objects = ys_read_u16_le(read_p, &read_p); + + OMInfo.object_maps = + (R_OBJECTMAP_ENTRY *)malloc(OMInfo.n_objects * sizeof *OMInfo.object_maps); + + if (OMInfo.object_maps == NULL) { + R_printf(R_STDERR, "Error: Memory allocation failed.\n"); + return R_MEM; + } + + /* Load all N objects + * \*------------------------------------------------------------- */ + for (i = 0; i < OMInfo.n_objects; i++) { + + object_map = &OMInfo.object_maps[i]; + object_map->unknown0 = ys_read_u8(read_p, &read_p); + object_map->n_clickareas = ys_read_u8(read_p, &read_p); + object_map->flags = ys_read_u16_le(read_p, &read_p); + object_map->object_num = ys_read_u16_le(read_p, &read_p); + object_map->script_num = ys_read_u16_le(read_p, &read_p); + + object_map->clickareas = + (R_CLICKAREA *)malloc(object_map->n_clickareas * + sizeof *(object_map->clickareas)); + + if (object_map->clickareas == NULL) { + R_printf(R_STDERR, + "Error: Memory allocation failed.\n"); + return R_MEM; + } + + /* Load all clickareas for this object */ + for (k = 0; k < object_map->n_clickareas; k++) { + + clickarea = &object_map->clickareas[k]; + clickarea->n_points = ys_read_u16_le(read_p, &read_p); + assert(clickarea->n_points != 0); + + clickarea->points = + (R_POINT *)malloc(clickarea->n_points * sizeof *(clickarea->points)); + + if (clickarea->points == NULL) { + R_printf(R_STDERR, + "Error: Memory allocation failed.\n"); + return R_MEM; + } + + /* Load all points for this clickarea */ + for (m = 0; m < clickarea->n_points; m++) { + + point = &clickarea->points[m]; + point->x = ys_read_s16_le(read_p, &read_p); + point->y = ys_read_s16_le(read_p, &read_p); + } + +# if R_OBJECTMAP_DEBUG >= R_DEBUG_PARANOID + R_printf(R_STDOUT, + "OBJECTMAP_Load(): " + "Read %d points for clickarea %d in object %d.\n", + clickarea->n_points, k, object_map->object_num); +# endif + } /* End load all clickareas */ + } /* End load all objects */ + + /*-------------------------------------------------------------*/ + OMInfo.objects_loaded = 1; + + return R_SUCCESS; +} + +int OBJECTMAP_Free(void) +/*--------------------------------------------------------------------------*\ + * Frees all storage allocated for the current object map data +\*--------------------------------------------------------------------------*/ +{ + R_OBJECTMAP_ENTRY *object_map; + R_CLICKAREA *clickarea; + + int i, k; + + if (!OMInfo.objects_loaded) { + return R_FAILURE; + } + + for (i = 0; i < OMInfo.n_objects; i++) { + object_map = &OMInfo.object_maps[i]; + + for (k = 0; k < object_map->n_clickareas; k++) { + clickarea = &object_map->clickareas[k]; + free(clickarea->points); + } + free(object_map->clickareas); + } + + if (OMInfo.n_objects) { + free(OMInfo.object_maps); + } + + OMInfo.objects_loaded = 0; + + return R_SUCCESS; +} + +int OBJECTMAP_LoadNames(const unsigned char *onl_res, size_t onl_res_len) +/*--------------------------------------------------------------------------*\ + * Loads an object name list resource +\*--------------------------------------------------------------------------*/ +{ + YS_REG_FUNC(OBJECTMAP_LoadNames); + const unsigned char *read_p = onl_res; + + int table_len; + int n_names; + size_t name_offset; + + int i; + + YS_IGNORE_PARAM(onl_res_len); + + if (OMInfo.names_loaded) { + OBJECTMAP_FreeNames(); + } + + table_len = ys_read_u16_le(read_p, &read_p); + + n_names = table_len / 2 - 2; + OMInfo.n_names = n_names; + +#if 0 +# if R_OBJECTMAP_DEBUG >= R_DEBUG_INFO + R_printf(R_STDOUT, "%s: Loading %d object names.\n", YS_FUNC, n_names); +# endif +#endif + OMInfo.names = (char **)malloc(n_names * sizeof *OMInfo.names); + + if (OMInfo.names == NULL) { + R_printf(R_STDERR, "Error: Memory allocation failed.\n"); + return R_MEM; + } + + for (i = 0; i < n_names; i++) { + name_offset = ys_read_u16_le(read_p, &read_p); + OMInfo.names[i] = (char *)(onl_res + name_offset); + +# if R_OBJECTMAP_DEBUG >= R_DEBUG_VERBOSE + R_printf(R_STDOUT, + "Loaded object name string: %s\n", OMInfo.names[i]); +# endif + } + + OMInfo.names_loaded = 1; + + return R_SUCCESS; +} + +int OBJECTMAP_FreeNames(void) +/*--------------------------------------------------------------------------*\ + * Frees all storage allocated for the current object name list data +\*--------------------------------------------------------------------------*/ +{ + if (!OMInfo.names_loaded) { + return R_FAILURE; + } + + if (OMInfo.n_names) { + free(OMInfo.names); + } + + OMInfo.names_loaded = 0; + return R_SUCCESS; +} + +int OBJECTMAP_GetName(int object, const char **name) +/*--------------------------------------------------------------------------*\ + * If 'object' is a valid object number in the currently loaded object + * name list resource, the funciton sets '*name' to the descriptive string + * corresponding to 'object' and returns R_SUCCESS. Otherwise it returns + * R_FAILURE. +\*--------------------------------------------------------------------------*/ +{ + if (!OMInfo.names_loaded) { + return R_FAILURE; + } + + if ((object <= 0) || (object > OMInfo.n_names)) { + return R_FAILURE; + } + + *name = OMInfo.names[object - 1]; + + return R_SUCCESS; +} + +int OBJECTMAP_GetFlags(int object, uint * flags) +{ + int i; + + if (!OMInfo.names_loaded) { + return R_FAILURE; + } + + if ((object <= 0) || (object > OMInfo.n_names)) { + return R_FAILURE; + } + + for (i = 0; i < OMInfo.n_objects; i++) { + + if (OMInfo.object_maps[i].object_num == object) { + + *flags = OMInfo.object_maps[i].flags; + return R_SUCCESS; + } + } + + return R_FAILURE; +} + +int OBJECTMAP_GetEPNum(int object, int *ep_num) +/*--------------------------------------------------------------------------*\ + * If 'object' is a valid object number in the currently loaded object + * name list resource, the funciton sets '*ep_num' to the entrypoint number + * corresponding to 'object' and returns R_SUCCESS. Otherwise, it returns + * R_FAILURE. +\*--------------------------------------------------------------------------*/ +{ + int i; + + if (!OMInfo.names_loaded) { + return R_FAILURE; + } + + if ((object < 0) || (object > (OMInfo.n_objects + 1))) { + return R_FAILURE; + } + + for (i = 0; i < OMInfo.n_objects; i++) { + + if (OMInfo.object_maps[i].object_num == object) { + + *ep_num = OMInfo.object_maps[i].script_num; + return R_SUCCESS; + } + } + + return R_FAILURE; +} + +int OBJECTMAP_Draw(R_SURFACE * ds, R_POINT * imouse_pt, int color, int color2) +/*--------------------------------------------------------------------------*\ + * Uses GFX_DrawLine to display all clickareas for each object in the + * currently loaded object map resource. +\*--------------------------------------------------------------------------*/ +{ + + R_OBJECTMAP_ENTRY *object_map; + R_CLICKAREA *clickarea; + + char txt_buf[32]; + + int draw_color = color; + int draw_txt = 0; + + int hit_object = 0; + int object_num = 0; + + int pointcount = 0; + int i, k; + + assert(OMInfo.initialized); + + if (!OMInfo.objects_loaded) { + return R_FAILURE; + } + + if (imouse_pt != NULL) { + + if (OBJECTMAP_HitTest(imouse_pt, &object_num) == R_SUCCESS) { + hit_object = 1; + } + } + + for (i = 0; i < OMInfo.n_objects; i++) { + + draw_color = color; + + if (hit_object && + (object_num == OMInfo.object_maps[i].object_num)) { + + snprintf(txt_buf, + sizeof txt_buf, + "obj %d: ? %d, f %X", + OMInfo.object_maps[i].object_num, + OMInfo.object_maps[i].unknown0, + OMInfo.object_maps[i].flags); + + draw_txt = 1; + draw_color = color2; + } + + object_map = &OMInfo.object_maps[i]; + + for (k = 0; k < object_map->n_clickareas; k++) { + + clickarea = &object_map->clickareas[k]; + pointcount = 0; + + if (clickarea->n_points == 2) { + + /* 2 points represent a box */ + GFX_DrawFrame(ds, + &clickarea->points[0], + &clickarea->points[1], draw_color); + } else if (clickarea->n_points > 2) { + + /* Otherwise draw a polyline */ + + GFX_DrawPolyLine(ds, + clickarea->points, + clickarea->n_points, draw_color); + + } + + } /* end for() clickareas */ + } /* end for() objects */ + + if (draw_txt) { + + FONT_Draw(SMALL_FONT_ID, + ds, + txt_buf, + 0, + 2, 2, SYSGFX_GetWhite(), SYSGFX_GetBlack(), FONT_OUTLINE); + } + + return R_SUCCESS; +} + +int OBJECTMAP_HitTest(R_POINT * imouse_pt, int *object_num) +{ + + R_POINT imouse; + R_OBJECTMAP_ENTRY *object_map; + R_CLICKAREA *clickarea; + R_POINT *points; + int n_points; + + int i, k; + + assert((imouse_pt != NULL) && (object_num != NULL)); + + imouse.x = imouse_pt->x; + imouse.y = imouse_pt->y; + + /* Loop through all scene objects */ + for (i = 0; i < OMInfo.n_objects; i++) { + + object_map = &OMInfo.object_maps[i]; + + /* Hit-test all clickareas for this object */ + for (k = 0; k < object_map->n_clickareas; k++) { + + clickarea = &object_map->clickareas[k]; + + n_points = clickarea->n_points; + points = clickarea->points; + + if (n_points == 2) { + /* Hit-test a box region */ + if ((imouse.x > points[0].x) && + (imouse.x <= points[1].x) && + (imouse.y > points[0].y) && + (imouse.y <= points[1].y)) { + + *object_num = object_map->object_num; + + return R_SUCCESS; + } + } else if (n_points > 2) { + /* Hit-test a polygon */ + if (MATH_HitTestPoly(points, n_points, imouse)) { + + *object_num = object_map->object_num; + + return R_SUCCESS; + } + } + + } /* end for() clickareas */ + } /* end for() objects */ + + *object_num = 0; + + return R_FAILURE; +} + +static void CF_object_info(int argc, char *argv[]) +{ + int i; + + YS_IGNORE_PARAM(argc); + YS_IGNORE_PARAM(argv); + + if (!OMInfo.initialized) { + return; + } + + CON_Print("%d objects loaded.", OMInfo.n_objects); + + for (i = 0; i < OMInfo.n_objects; i++) { + + CON_Print("%s:", OMInfo.names[i]); + CON_Print + ("%d. Unk1: %d, flags: %X, name_i: %d, scr_n: %d, ca_ct: %d", + i, OMInfo.object_maps[i].unknown0, + OMInfo.object_maps[i].flags, + OMInfo.object_maps[i].object_num, + OMInfo.object_maps[i].script_num, + OMInfo.object_maps[i].n_clickareas); + + } + + return; +} + +} // End of namespace Saga diff --git a/saga/objectmap.h b/saga/objectmap.h new file mode 100644 index 0000000000..f5f1f92b25 --- /dev/null +++ b/saga/objectmap.h @@ -0,0 +1,75 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Object map / Object click-area module header file + + Notes: +*/ + +#ifndef SAGA_OBJECTMAP_H_ +#define SAGA_OBJECTMAP_H_ + +namespace Saga { + +typedef struct R_CLICKAREA_tag { + + int n_points; + R_POINT *points; + +} R_CLICKAREA; + +typedef struct R_OBJECTMAP_ENTRY_tag { + + int unknown0; + uint flags; + + int object_num; + int script_num; + + int n_clickareas; + R_CLICKAREA *clickareas; + +} R_OBJECTMAP_ENTRY; + +typedef struct R_OBJECTMAP_INFO_tag { + + int initialized; + + int objects_loaded; + int n_objects; + R_OBJECTMAP_ENTRY *object_maps; + + int names_loaded; + int n_names; + char **names; + +} R_OBJECTMAP_INFO; + +static void CF_object_info(int argc, char *argv[]); + +} // End of namespace Saga + +#endif /* SAGA_OBJECTMAP_H_ */ diff --git a/saga/objectmap_mod.h b/saga/objectmap_mod.h new file mode 100644 index 0000000000..b1a1c13ae6 --- /dev/null +++ b/saga/objectmap_mod.h @@ -0,0 +1,70 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Object map module public header file + + Notes: +*/ + +#ifndef SAGA_OBJECTMAP_MOD_H__ +#define SAGA_OBJECTMAP_MOD_H__ + +namespace Saga { + +enum R_OBJECT_FLAGS { + + R_OBJECT_NORMAL = 0x02 +}; + +int OBJECTMAP_Register(void); + +int OBJECTMAP_Init(void); + +int OBJECTMAP_Shutdown(void); + +int OBJECTMAP_Load(const uchar * om_res, size_t om_res_len); + +int OBJECTMAP_Free(void); + +int OBJECTMAP_LoadNames(const uchar * onl_res, size_t onl_res_len); + +int OBJECTMAP_FreeNames(void); + +int OBJECTMAP_GetName(int object, const char **name); + +int OBJECTMAP_GetFlags(int object, uint * flags); + +int OBJECTMAP_GetEPNum(int object, int *ep_num); + +int +OBJECTMAP_Draw(R_SURFACE * draw_surface, + R_POINT * imouse_pt, int color, int color2); + +int OBJECTMAP_HitTest(R_POINT * imouse_pt, int *object_num); + +} // End of namespace Saga + +#endif /* SAGA_OBJECTMAP_MOD_H__ */ diff --git a/saga/palanim.cpp b/saga/palanim.cpp new file mode 100644 index 0000000000..b24f3a35c0 --- /dev/null +++ b/saga/palanim.cpp @@ -0,0 +1,266 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Palette animation module + + Notes: +*/ + +#include "reinherit.h" + +#include "yslib.h" + +/* + * Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "events_mod.h" +#include "game_mod.h" + +/* + * Begin module: +\*--------------------------------------------------------------------------*/ +#include "palanim_mod.h" +#include "palanim.h" + +namespace Saga { + +static PALANIM_DATA PAnimData; + +int PALANIM_Load(const uchar * resdata, size_t resdata_len) +{ + const uchar *read_p = resdata; + void *test_p; + + uint i; + + YS_IGNORE_PARAM(resdata_len); + + if (PAnimData.loaded) { + PALANIM_Free(); + } + + if (resdata == NULL) { + return R_FAILURE; + } + + if (GAME_GetGameType() == R_GAMETYPE_IHNM) { + return R_SUCCESS; + } + + PAnimData.entry_count = ys_read_u16_le(read_p, &read_p); + + R_printf(R_STDOUT, + "PALANIM_Load(): Loading %d PALANIM entries.\n", + PAnimData.entry_count); + + test_p = calloc(PAnimData.entry_count, sizeof(PALANIM_ENTRY)); + if (test_p == NULL) { + R_printf(R_STDERR, "PALANIM_Load(): Allocation failure.\n"); + return R_MEM; + } + + PAnimData.entries = (PALANIM_ENTRY *)test_p; + + for (i = 0; i < PAnimData.entry_count; i++) { + + int color_count; + int pal_count; + int p, c; + + color_count = ys_read_u16_le(read_p, &read_p); + pal_count = ys_read_u16_le(read_p, &read_p); + + PAnimData.entries[i].pal_count = pal_count; + PAnimData.entries[i].color_count = color_count; + +# if 0 + R_printf(R_STDOUT, + "PALANIM_Load(): Entry %d: Loading %d palette indices.\n", + i, pal_count); +#endif + + test_p = calloc(1, sizeof(char) * pal_count); + if (test_p == NULL) { + R_printf(R_STDERR, + "PALANIM_Load(): Allocation failure.\n"); + return R_MEM; + } + + PAnimData.entries[i].pal_index = (uchar *)test_p; + +# if 0 + R_printf(R_STDOUT, + "PALANIM_Load(): Entry %d: Loading %d SAGA_COLOR " + "structures.\n", i, color_count); +# endif + + test_p = calloc(1, sizeof(R_COLOR) * color_count); + if (test_p == NULL) { + R_printf(R_STDERR, + "PALANIM_Load(): Allocation failure.\n"); + return R_MEM; + } + + PAnimData.entries[i].colors = (R_COLOR *)test_p; + + for (p = 0; p < pal_count; p++) { + PAnimData.entries[i].pal_index[p] = + (uchar) ys_read_u8(read_p, &read_p); + } + + for (c = 0; c < color_count; c++) { + PAnimData.entries[i].colors[c].red = + (uchar) ys_read_u8(read_p, &read_p); + + PAnimData.entries[i].colors[c].green = + (uchar) ys_read_u8(read_p, &read_p); + + PAnimData.entries[i].colors[c].blue = + (uchar) ys_read_u8(read_p, &read_p); + } + } + + PAnimData.loaded = 1; + return R_SUCCESS; + +} + +int PALANIM_CycleStart(void) +{ + + R_EVENT event; + + if (!PAnimData.loaded) { + return R_FAILURE; + } + + event.type = R_ONESHOT_EVENT; + event.code = R_PALANIM_EVENT; + event.op = EVENT_CYCLESTEP; + event.time = PALANIM_CYCLETIME; + + EVENT_Queue(&event); + + return R_SUCCESS; + +} + +int PALANIM_CycleStep(int vectortime) +{ + R_SURFACE *back_buf; + + static PALENTRY pal[256]; + uint pal_index; + uint col_index; + + uint i, j; + uint cycle; + uint cycle_limit; + + R_EVENT event; + + if (!PAnimData.loaded) { + return R_FAILURE; + } + + SYSGFX_GetCurrentPal(pal); + back_buf = SYSGFX_GetBackBuffer(); + + for (i = 0; i < PAnimData.entry_count; i++) { + + cycle = PAnimData.entries[i].cycle; + cycle_limit = PAnimData.entries[i].color_count; + + for (j = 0; j < PAnimData.entries[i].pal_count; j++) { + + pal_index = + (unsigned char)PAnimData.entries[i].pal_index[j]; + col_index = (cycle + j) % cycle_limit; + + pal[pal_index].red = + (uchar) PAnimData.entries[i].colors[col_index].red; + + pal[pal_index].green = + (uchar) PAnimData.entries[i].colors[col_index]. + green; + + pal[pal_index].blue = + (uchar) PAnimData.entries[i].colors[col_index]. + blue; + } + + PAnimData.entries[i].cycle++; + + if (PAnimData.entries[i].cycle == cycle_limit) { + PAnimData.entries[i].cycle = 0; + } + } + + SYSGFX_SetPalette(back_buf, pal); + + event.type = R_ONESHOT_EVENT; + event.code = R_PALANIM_EVENT; + event.op = EVENT_CYCLESTEP; + event.time = vectortime + PALANIM_CYCLETIME; + + EVENT_Queue(&event); + + return R_SUCCESS; + +} + +int PALANIM_Free(void) +{ + + uint i; + + if (!PAnimData.loaded) { + return R_FAILURE; + } + + for (i = 0; i < PAnimData.entry_count; i++) { +#if 0 + R_printf(R_STDOUT, + "PALANIM_Free(): Entry %d: Freeing colors.\n", i); +#endif + free(PAnimData.entries[i].colors); +#if 0 + R_printf(R_STDOUT, + "PALANIM_Free(): Entry %d: Freeing indices.\n", i); +#endif + free(PAnimData.entries[i].pal_index); + + } + + R_printf(R_STDOUT, "PALANIM_Free(): Freeing entries.\n", i); + + free(PAnimData.entries); + + PAnimData.loaded = 0; + + return R_SUCCESS; +} + +} // End of namespace Saga diff --git a/saga/palanim.h b/saga/palanim.h new file mode 100644 index 0000000000..ededaf2449 --- /dev/null +++ b/saga/palanim.h @@ -0,0 +1,63 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Palette animation module header file + + Notes: +*/ + +#ifndef SAGA_PALANIM_H +#define SAGA_PALANIM_H + +#include "reinherit.h" + +namespace Saga { + +#define PALANIM_CYCLETIME 100 + +typedef struct PALANIM_ENTRY_tag { + + uint pal_count; + uint color_count; + uint cycle; + + uchar *pal_index; + R_COLOR *colors; + +} PALANIM_ENTRY; + +typedef struct PALANIM_DATA_tag { + + int loaded; + uint entry_count; + + PALANIM_ENTRY *entries; + +} PALANIM_DATA; + +} // End of namespace Saga + +#endif + diff --git a/saga/palanim_mod.h b/saga/palanim_mod.h new file mode 100644 index 0000000000..516af1374c --- /dev/null +++ b/saga/palanim_mod.h @@ -0,0 +1,46 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Palette animation module public header file + + Notes: +*/ + +#ifndef SAGA_PALANIM_MOD_H__ +#define SAGA_PALANIM_MOD_H__ + +namespace Saga { + +int PALANIM_Load(const uchar *, size_t); + +int PALANIM_CycleStart(void); + +int PALANIM_CycleStep(int vectortime); + +int PALANIM_Free(void); + +} // End of namespace Saga + +#endif /* SAGA_PALANIM_MOD_H__ */ diff --git a/saga/reinherit.h b/saga/reinherit.h new file mode 100644 index 0000000000..567340b232 --- /dev/null +++ b/saga/reinherit.h @@ -0,0 +1,333 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Main Header File + + Notes: +*/ + +#ifndef SAGA_REINHERIT_H_ +#define SAGA_REINHERIT_H_ + +#include "stdafx.h" + +#include "base/engine.h" + +/* + * Architecture conditionals +\*--------------------------------------------------------------------------*/ +#include "x86_32.h" + +/* + * Implementation conditionals +\*--------------------------------------------------------------------------*/ +#define R_ENV_LINUX +#include "sys_interface.h" + +namespace Saga { + +#define R_MAXPATH 512 + +/* For debug message processing */ +#define R_DEBUG_NONE 0 +#define R_DEBUG_INFO 1 +#define R_DEBUG_VERBOSE 2 +#define R_DEBUG_PARANOID 3 + +#define R_MEMFAIL_MSG "Memory allocation error." + +/* + * Define opaque types +\*--------------------------------------------------------------------------*/ + +/* r_rscfile */ +typedef struct R_RSCFILE_CONTEXT_tag R_RSCFILE_CONTEXT; + +/* r_script */ +typedef struct R_SEMAPHORE_tag R_SEMAPHORE; + +/* + * Define common data types +\*--------------------------------------------------------------------------*/ + +#ifndef HAVE_UCHAR +typedef unsigned char uchar; +#endif +#ifndef HAVE_ULONG +typedef unsigned long ulong; +#endif +#ifndef HAVE_UINT +typedef unsigned int uint; +#endif + +typedef struct R_POINT_tag { + + int x; + int y; + +} R_POINT; + +typedef struct R_RECT_tag { + + int x1; + int y1; + int x2; + int y2; + +} R_RECT; + +#define R_MAKERECT( rect, x1, y1, x2, y2 ) \ + ( rect.x1 = x1, rect.y1 = y1, rect.x2 = x2, rect.y2 = y2, &rect ) + +typedef struct R_COLOR_tag { + + int red; + int green; + int blue; + int alpha; + +} R_COLOR; + +typedef struct R_SURFACE_tag { + + uchar *buf; + int buf_w; + int buf_h; + int buf_pitch; + + int bpp; + + R_RECT clip_rect; + + void *impl_src; + +} R_SURFACE; + +typedef struct R_SOUNDBUFFER_tag { + + uchar *res_data; + size_t res_len; + + long s_freq; + int s_samplebits; + int s_stereo; + int s_signed; + + uchar *s_buf; + size_t s_buf_len; + +} R_SOUNDBUFFER; + +#define R_RGB_RED 0x00FF0000UL +#define R_RGB_GREEN 0x0000FF00UL +#define R_RGB_BLUE 0x000000FFUL + +typedef struct SAGA_COLOR_tag { + + R_UINT8 r; + R_UINT8 g; + R_UINT8 b; + +} SAGA_COLOR; + +#define SAGA_COLOR_LEN 3 + +typedef struct PALENTRY_TAG { + + R_UINT8 red; + R_UINT8 green; + R_UINT8 blue; + +} PALENTRY; + +enum R_ERRORCODE { + + R_STOP = -3, + R_MEM = -2, + R_FAILURE = -1, + R_SUCCESS = 0 + +}; + + +/* + * r_cmdline.c +\*--------------------------------------------------------------------------*/ +typedef struct R_EXECINFO_tag { + + int start_scene; + int no_verify; + int no_sound; + int no_music; + int windowed; + char *game_dir; + +} R_EXECINFO; + +int R_ReadCommandLine(int argc, char **argv, R_EXECINFO * execinfo); + +/* + * r_main.c +\*--------------------------------------------------------------------------*/ +int main(int argc, char *argv[]); + +void R_Shutdown(int param); + +/* + * r_misc.c +\*--------------------------------------------------------------------------*/ +int Granulate(int value, int granularity); + +/* + * r_transitions.c +\*--------------------------------------------------------------------------*/ +int TRANSITION_Dissolve(uchar * dst_img, + int dst_w, + int dst_h, + int dst_p, const uchar * src_img, int src_p, int flags, double percent); + +/*--------------------------------------------------------------------------*\ + * System specific routines +\*--------------------------------------------------------------------------*/ + +/* + * System : IO +\*--------------------------------------------------------------------------*/ + +int SYSIO_Init(void); +int SYSIO_Shutdown(void); + +/* + * System : Filesystem +\*--------------------------------------------------------------------------*/ + +int SYSFS_GetFileLen(FILE * file_p, ulong * len); +int SYSFS_GetFQFN(const char *f_dir, + const char *f_name, char *buf, size_t buf_len); + +/* + * System : Sound +\*--------------------------------------------------------------------------*/ +int SYSSOUND_Init(int enabled); +int SYSSOUND_Shutdown(void); + +int SYSSOUND_Play(int sound_rn, int channel); +int SYSSOUND_Pause(int channel); +int SYSSOUND_Resume(int channel); +int SYSSOUND_Stop(int channel); + +int SYSSOUND_PlayVoice(R_SOUNDBUFFER *); +int SYSSOUND_PauseVoice(void); +int SYSSOUND_ResumeVoice(void); +int SYSSOUND_StopVoice(void); + +/* + * System : Music +\*--------------------------------------------------------------------------*/ +enum SYSMUSIC_FLAGS { + + R_MUSIC_LOOP = 0x01 +}; + +int SYSMUSIC_Init(int enabled); +int SYSMUSIC_Shutdown(void); + +int SYSMUSIC_Play(ulong music_rn, uint flags); +int SYSMUSIC_Pause(void); +int SYSMUSIC_Resume(void); +int SYSMUSIC_Stop(void); + +/* + * System : Graphics +\*--------------------------------------------------------------------------*/ +#define R_PAL_ENTRIES 256 + +typedef struct R_SYSGFX_INIT_tag { + + int backbuf_w; + int backbuf_h; + int backbuf_bpp; + + int screen_w; + int screen_h; + int screen_bpp; + + int fullscreen; + +} R_SYSGFX_INIT; + +int SYSGFX_Init(R_SYSGFX_INIT *); + +R_SURFACE *SYSGFX_GetScreenSurface(void); +R_SURFACE *SYSGFX_GetBackBuffer(void); + +int SYSGFX_LockSurface(R_SURFACE * surface); +int SYSGFX_UnlockSurface(R_SURFACE * surface); + +R_SURFACE *SYSGFX_CreateSurface(int w, int h, int bpp); +R_SURFACE *SYSGFX_FormatToDisplay(R_SURFACE * surface); +int SYSGFX_DestroySurface(R_SURFACE * surface); + +int SYSGFX_GetWhite(void); +int SYSGFX_GetBlack(void); +int SYSGFX_MatchColor(unsigned long colormask); +int SYSGFX_SetPalette(R_SURFACE * surface, PALENTRY * pal); +int SYSGFX_GetCurrentPal(PALENTRY * src_pal); + +int SYSGFX_PalToBlack(R_SURFACE * surface, PALENTRY * src_pal, double percent); + +int SYSGFX_BlackToPal(R_SURFACE * surface, PALENTRY * src_pal, double percent); + +/* + * System : Timer +\*--------------------------------------------------------------------------*/ +typedef struct R_SYSTIMER_tag R_SYSTIMER; + +typedef void (*R_SYSTIMER_CALLBACK) (unsigned long, void *); + +int SYSTIMER_InitMSCounter(void); +unsigned long SYSTIMER_ReadMSCounter(void); + +int SYSTIMER_ResetMSCounter(void); +int SYSTIMER_Sleep(uint msec); +int SYSTIMER_CreateTimer(R_SYSTIMER **, + unsigned long, void *, R_SYSTIMER_CALLBACK); +int SYSTIMER_DestroyTimer(R_SYSTIMER *); + +/* + * System : Input +\*--------------------------------------------------------------------------*/ +int SYSINPUT_Init(void); +int SYSINPUT_ProcessInput(void); +int SYSINPUT_GetMousePos(int *mouse_x, int *mouse_y); +int SYSINPUT_HideMouse(void); +int SYSINPUT_ShowMouse(void); + +/*** sys_signal.c ***/ +int ITESYS_CheckSignal(void); + +} // End of namespace Saga + +#endif /* SAGA_REINHERIT_H_ */ diff --git a/saga/render.cpp b/saga/render.cpp new file mode 100644 index 0000000000..4797659721 --- /dev/null +++ b/saga/render.cpp @@ -0,0 +1,588 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Main rendering loop + + Notes: +*/ + +#include "reinherit.h" + +#include "yslib.h" + +#include <SDL.h> + +/* + * Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "actor_mod.h" +#include "console_mod.h" +#include "cvar_mod.h" +#include "font_mod.h" +#include "game_mod.h" +#include "gfx_mod.h" +#include "interface_mod.h" +#include "scene_mod.h" +#include "sprite_mod.h" +#include "text_mod.h" + +#include "actionmap_mod.h" +#include "objectmap_mod.h" + +/* + * Begin module +\*--------------------------------------------------------------------------*/ +#include "render_mod.h" +#include "render.h" + +namespace Saga { + +static R_RENDER_MODULE RenderModule; + +const char *test_txt = "The quick brown fox jumped over the lazy dog. " + "She sells sea shells down by the sea shore."; + +int RENDER_Register(void) +{ + + /* Register "r_fullscreen" cfg cvar + * \*----------------------------------------- */ + RenderModule.r_fullscreen = R_FULLSCREEN_DEFAULT; + + if (CVAR_Register_I(&RenderModule.r_fullscreen, + "r_fullscreen", NULL, R_CVAR_CFG, 0, 1) != R_SUCCESS) { + + return R_FAILURE; + } + + /* Register "r_doubleres" cfg cvar + * \*----------------------------------------- */ + RenderModule.r_doubleres = R_DOUBLERES_DEFAULT; + + if (CVAR_Register_I(&RenderModule.r_doubleres, + "r_doubleres", NULL, R_CVAR_CFG, 0, 1) != R_SUCCESS) { + + return R_FAILURE; + } + + /* Register "r_hicolor" cfg cvar + * \*----------------------------------------- */ + RenderModule.r_hicolor = R_HICOLOR_DEFAULT; + + if (CVAR_Register_I(&RenderModule.r_hicolor, + "r_hicolor", NULL, R_CVAR_CFG, 0, 1) != R_SUCCESS) { + + return R_FAILURE; + } + + /* Register "r_softcursor" cfg cvar + * \*----------------------------------------- */ + RenderModule.r_softcursor = R_SOFTCURSOR_DEFAULT; + + if (CVAR_Register_I(&RenderModule.r_softcursor, + "r_softcursor", NULL, R_CVAR_CFG, 0, 1) != R_SUCCESS) { + + return R_FAILURE; + } + + return R_SUCCESS; +} + +int RENDER_Init(void) +{ + + R_GAME_DISPLAYINFO disp_info = { 0 }; + R_SYSGFX_INIT gfx_init = { 0 }; + + int result; + + int tmp_w, tmp_h, tmp_bytepp; + + /* Initialize system graphics + * \*------------------------------------------------------------- */ + GAME_GetDisplayInfo(&disp_info); + + gfx_init.backbuf_bpp = 8; /* all games are 8 bpp so far */ + gfx_init.backbuf_w = disp_info.logical_w; + gfx_init.backbuf_h = disp_info.logical_h; + + if (RenderModule.r_hicolor) { + gfx_init.screen_bpp = 16; + } else { + gfx_init.screen_bpp = 8; + } + + gfx_init.screen_w = disp_info.logical_w; + gfx_init.screen_h = disp_info.logical_h; + + /* Don't try to double a game exceeding the resolution limit + * (640x480 would get doubled to 1280 x 960!) */ + if (disp_info.logical_w > R_DOUBLE_RESLIMIT) { + RenderModule.r_doubleres = 0; + } + + if (RenderModule.r_doubleres) { + + gfx_init.screen_w *= 2; + gfx_init.screen_h *= 2; + } + + gfx_init.fullscreen = RenderModule.r_fullscreen; + + if (SYSGFX_Init(&gfx_init) != R_SUCCESS) { + + return R_FAILURE; + } + + /* Initialize FPS timer callback + * \*------------------------------------------------------------- */ + result = SYSTIMER_CreateTimer(&RenderModule.r_fps_timer, + 1000, NULL, RENDER_FpsTimer); + if (result != R_SUCCESS) { + return R_FAILURE; + } + + /* Create background buffer + * \*------------------------------------------------------------- */ + RenderModule.r_bg_buf_w = disp_info.logical_w; + RenderModule.r_bg_buf_h = disp_info.logical_h; + + RenderModule.r_bg_buf = (uchar *)calloc(disp_info.logical_w, + disp_info.logical_h); + + if (RenderModule.r_bg_buf == NULL) { + return R_MEM; + } + + /* Allocate temp buffer for animation decoding, + * graphics scalers (2xSaI), etc. + \*-------------------------------------------------------------*/ + tmp_w = disp_info.logical_w; + tmp_h = disp_info.logical_h + 4; /* BG unbanking requres extra rows */ + tmp_bytepp = 1; + + if (RenderModule.r_doubleres) { + tmp_w *= 2; + tmp_h *= 2; + } + + if (RenderModule.r_hicolor) { + tmp_bytepp = 2; + } + + RenderModule.r_tmp_buf = (uchar *)calloc(1, tmp_w * tmp_h * tmp_bytepp); + if (RenderModule.r_tmp_buf == NULL) { + + free(RenderModule.r_bg_buf); + return R_MEM; + } + + RenderModule.r_tmp_buf_w = tmp_w; + RenderModule.r_tmp_buf_h = tmp_h; + + RenderModule.r_screen_surface = SYSGFX_GetScreenSurface(); + RenderModule.r_backbuf_surface = SYSGFX_GetBackBuffer(); + + /* Initialize cursor state + * \*------------------------------------------------------------- */ + if (RenderModule.r_softcursor) { + SYSINPUT_HideMouse(); + } + + RenderModule.initialized = 1; + + return R_SUCCESS; +} + +int RENDER_DrawScene(void) +{ + + R_SURFACE *screen_surface; + R_SURFACE *backbuf_surface; + R_SURFACE *display_surface; + + R_GAME_DISPLAYINFO disp_info = { 0 }; + R_SCENE_INFO scene_info; + SCENE_BGINFO bg_info; + + R_POINT bg_pt; + + char txt_buf[20]; + int fps_width; + + R_POINT mouse_pt; + int mouse_x, mouse_y; + + int surface_converted = 0; + + if (!RenderModule.initialized) { + return R_FAILURE; + } + + RenderModule.r_framecount++; + + screen_surface = RenderModule.r_screen_surface; + backbuf_surface = RenderModule.r_backbuf_surface; + + /* Get mouse coordinates + * \*------------------------------------------------------------- */ + SYSINPUT_GetMousePos(&mouse_x, &mouse_y); + + mouse_pt.x = mouse_x; + mouse_pt.y = mouse_y; + + if (RenderModule.r_doubleres) { + mouse_pt.x /= 2; + mouse_pt.y /= 2; + } + + SCENE_GetBGInfo(&bg_info); + GAME_GetDisplayInfo(&disp_info); + bg_pt.x = 0; + bg_pt.y = 0; + + /* Display scene background + * \*--------------------------------------------------------- */ + SCENE_Draw(backbuf_surface); + + /* Display scene maps, if applicable + * \*--------------------------------------------------------- */ + if (RENDER_GetFlags() & RF_OBJECTMAP_TEST) { + + OBJECTMAP_Draw(backbuf_surface, + &mouse_pt, SYSGFX_GetWhite(), SYSGFX_GetBlack()); + + ACTIONMAP_Draw(backbuf_surface, SYSGFX_MatchColor(R_RGB_RED)); + } + + /* Draw queued actors + * \*--------------------------------------------------------- */ + ACTOR_DrawList(); + + /* Draw queued text strings + * \*--------------------------------------------------------- */ + SCENE_GetInfo(&scene_info); + + TEXT_DrawList(scene_info.text_list, backbuf_surface); + + /* Handle user input + * \*--------------------------------------------------------- */ + SYSINPUT_ProcessInput(); + + /* Display rendering information + * \*--------------------------------------------------------- */ + if (RenderModule.r_flags & RF_SHOW_FPS) { + + sprintf(txt_buf, "%d", RenderModule.r_fps); + + fps_width = FONT_GetStringWidth(SMALL_FONT_ID, + txt_buf, 0, FONT_NORMAL); + + FONT_Draw(SMALL_FONT_ID, + backbuf_surface, + txt_buf, + 0, + backbuf_surface->buf_w - fps_width, 2, + SYSGFX_GetWhite(), SYSGFX_GetBlack(), FONT_OUTLINE); + + switch (RenderModule.r_mode) { + + case RM_SCANLINES: + FONT_Draw(SMALL_FONT_ID, + backbuf_surface, + "Scanlines", + 0, + 2, 2, + SYSGFX_GetWhite(), + SYSGFX_GetBlack(), FONT_OUTLINE); + break; + + case RM_2XSAI: + FONT_Draw(SMALL_FONT_ID, + backbuf_surface, + "2xSaI", + 0, + 2, 2, + SYSGFX_GetWhite(), + SYSGFX_GetBlack(), FONT_OUTLINE); + break; + + case RM_SUPER2XSAI: + FONT_Draw(SMALL_FONT_ID, + backbuf_surface, + "Super2xSaI", + 0, + 2, 2, + SYSGFX_GetWhite(), + SYSGFX_GetBlack(), FONT_OUTLINE); + break; + + case RM_SUPEREAGLE: + FONT_Draw(SMALL_FONT_ID, + backbuf_surface, + "SuperEagle", + 0, + 2, 2, + SYSGFX_GetWhite(), + SYSGFX_GetBlack(), FONT_OUTLINE); + break; + } + + } + + /* Display "paused game" message, if applicable + * \*--------------------------------------------------------- */ + if (RenderModule.r_flags & RF_RENDERPAUSE) { + + int msg_len = strlen(R_PAUSEGAME_MSG); + int msg_w = FONT_GetStringWidth(BIG_FONT_ID, + R_PAUSEGAME_MSG, + msg_len, + FONT_OUTLINE); + + FONT_Draw(BIG_FONT_ID, + backbuf_surface, + R_PAUSEGAME_MSG, + msg_len, + (backbuf_surface->buf_w - msg_w) / 2, 90, + SYSGFX_GetWhite(), SYSGFX_GetBlack(), FONT_OUTLINE); + } + + /* Update user interface + * \*--------------------------------------------------------- */ + + INTERFACE_Update(&mouse_pt, UPDATE_MOUSEMOVE); + + if (RenderModule.r_softcursor) { + GFX_DrawCursor(backbuf_surface, &mouse_pt); + } + + /* Display text formatting test, if applicable + * \*--------------------------------------------------------- */ + if (RenderModule.r_flags & RF_TEXT_TEST) { + + TEXT_Draw(MEDIUM_FONT_ID, + backbuf_surface, + test_txt, + mouse_pt.x, mouse_pt.y, + SYSGFX_GetWhite(), + SYSGFX_GetBlack(), FONT_OUTLINE | FONT_CENTERED); + } + + /* Display palette test, if applicable + * \*--------------------------------------------------------- */ + if (RenderModule.r_flags & RF_PALETTE_TEST) { + + GFX_DrawPalette(backbuf_surface); + } + + /* Draw console + * \*--------------------------------------------------------- */ + CON_Draw(backbuf_surface); + + /* Display the current frame + * \*--------------------------------------------------------- */ + + if (RenderModule.r_hicolor) { + + display_surface = SYSGFX_FormatToDisplay(backbuf_surface); + + if (display_surface == NULL) { + R_printf(R_STDERR, + "Error: Back buffer conversion failed!\n"); + + return R_FAILURE; + } + + surface_converted = 1; + } else { + + display_surface = backbuf_surface; + } + + SYSGFX_LockSurface(screen_surface); + SYSGFX_LockSurface(display_surface); + + switch (RenderModule.r_mode) { + + case RM_SCANLINES: + + break; + + default: + + if (RenderModule.r_doubleres) { + + GFX_Scale2x(screen_surface, display_surface); + } else { + + GFX_SimpleBlit(screen_surface, display_surface); + } + + break; + } + + SYSGFX_UnlockSurface(display_surface); + SYSGFX_UnlockSurface(screen_surface); + + if (surface_converted) { + + SYSGFX_DestroySurface(display_surface); + } + + // FIXME + SDL_UpdateRect((SDL_Surface *)screen_surface->impl_src, 0, 0, 0, 0); + + return R_SUCCESS; +} + +unsigned int RENDER_GetFrameCount(void) +{ + + return RenderModule.r_framecount; +} + +unsigned int RENDER_ResetFrameCount(void) +{ + unsigned int framecount = RenderModule.r_framecount; + + RenderModule.r_framecount = 0; + + return framecount; +} + +void RENDER_FpsTimer(unsigned long interval, void *param) +{ + YS_IGNORE_PARAM(interval); + YS_IGNORE_PARAM(param); + + RenderModule.r_fps = RenderModule.r_framecount; + RenderModule.r_framecount = 0; + + return; +} + +void RENDER_ConvertMousePt(R_POINT * mouse_pt) +{ + assert(mouse_pt != NULL); + + if (RenderModule.r_doubleres) { + + mouse_pt->x /= 2; + mouse_pt->y /= 2; + } + + return; +} + +unsigned int RENDER_GetFlags(void) +{ + return RenderModule.r_flags; +} + +void RENDER_SetFlag(unsigned int flag) +{ + + RenderModule.r_flags |= flag; + + return; +} + +void RENDER_ToggleFlag(unsigned int flag) +{ + + RenderModule.r_flags ^= flag; + + return; +} + +int RENDER_SetMode(int mode) +{ + + switch (mode) { + + case RM_SCANLINES: + + if (!RenderModule.r_doubleres) { + + return R_FAILURE; + } + + break; + + case RM_2XSAI: + + if (!RenderModule.r_doubleres || !RenderModule.r_hicolor) { + + return R_FAILURE; + } + + break; + + case RM_SUPER2XSAI: + + if (!RenderModule.r_doubleres || !RenderModule.r_hicolor) { + + return R_FAILURE; + } + + break; + + case RM_SUPEREAGLE: + + if (!RenderModule.r_doubleres || !RenderModule.r_hicolor) { + + return R_FAILURE; + } + + break; + + default: + break; + + } + + RenderModule.r_mode = mode; + + return R_SUCCESS; +} + +int RENDER_GetBufferInfo(R_BUFFER_INFO * r_bufinfo) +{ + + assert(r_bufinfo != NULL); + + r_bufinfo->r_bg_buf = RenderModule.r_bg_buf; + r_bufinfo->r_bg_buf_w = RenderModule.r_bg_buf_w; + r_bufinfo->r_bg_buf_h = RenderModule.r_bg_buf_h; + + r_bufinfo->r_tmp_buf = RenderModule.r_tmp_buf; + r_bufinfo->r_tmp_buf_w = RenderModule.r_tmp_buf_w; + r_bufinfo->r_tmp_buf_h = RenderModule.r_tmp_buf_h; + + return R_SUCCESS; +} + +} // End of namespace Saga diff --git a/saga/render.h b/saga/render.h new file mode 100644 index 0000000000..f7db7b0fe1 --- /dev/null +++ b/saga/render.h @@ -0,0 +1,84 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Main rendering loop - private header + + Notes: +*/ + +#ifndef SAGA_RENDER_H_ +#define SAGA_RENDER_H_ + +namespace Saga { + +/* Render module CVAR defaults */ +#define R_FULLSCREEN_DEFAULT 0 +#define R_DOUBLERES_DEFAULT 1 +#define R_HICOLOR_DEFAULT 1 +#define R_SOFTCURSOR_DEFAULT 1 + +#define R_DOUBLE_RESLIMIT 320 + +#define R_PAUSEGAME_MSG "PAWS GAME" + +typedef struct R_RENDER_MODULE_tag { + + int initialized; + + /* Init cvars */ + int r_fullscreen; + int r_doubleres; + int r_hicolor; + int r_softcursor; + + /* Module data */ + R_SURFACE *r_screen_surface; + R_SURFACE *r_display_surface; + R_SURFACE *r_backbuf_surface; + + uchar *r_bg_buf; + int r_bg_buf_w; + int r_bg_buf_h; + + uchar *r_tmp_buf; + int r_tmp_buf_w; + int r_tmp_buf_h; + + R_SYSTIMER *r_fps_timer; + R_SPRITELIST *r_test_sprite; + + unsigned int r_fps; + unsigned int r_framecount; + + unsigned int r_flags; + int r_mode; + +} R_RENDER_MODULE; + +void RENDER_FpsTimer(unsigned long interval, void *param); + +} // End of namespace Saga + +#endif /* SAGA_RENDER_H_ */ diff --git a/saga/render_mod.h b/saga/render_mod.h new file mode 100644 index 0000000000..b3c353f3b5 --- /dev/null +++ b/saga/render_mod.h @@ -0,0 +1,92 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Main rendering loop - public header + + Notes: +*/ + +#ifndef SAGA_RENDER_MOD_H__ +#define SAGA_RENDER_MOD_H__ + +namespace Saga { + +enum RENDER_FLAGS { + + RF_SHOW_FPS = 0x01, + RF_PALETTE_TEST = 0x02, + RF_TEXT_TEST = 0x04, + RF_OBJECTMAP_TEST = 0x08, + RF_RENDERPAUSE = 0x10, + RF_GAMEPAUSE = 0x20 +}; + +enum RENDER_MODES { + RM_NORMAL, + RM_SCANLINES, + RM_SCANLINES50, + RM_2XSAI, + RM_SUPER2XSAI, + RM_SUPEREAGLE, + RM_BILINEAR +}; + +typedef struct R_BUFFER_INFO_tag { + + uchar *r_bg_buf; + int r_bg_buf_w; + int r_bg_buf_h; + + uchar *r_tmp_buf; + int r_tmp_buf_w; + int r_tmp_buf_h; + +} R_BUFFER_INFO; + +int RENDER_Register(void); + +int RENDER_Init(void); + +int RENDER_DrawScene(void); + +void RENDER_ConvertMousePt(R_POINT *); + +unsigned int RENDER_GetFlags(void); + +void RENDER_SetFlag(unsigned int); + +void RENDER_ToggleFlag(unsigned int); + +int RENDER_SetMode(int); + +unsigned int RENDER_GetFrameCount(void); + +unsigned int RENDER_ResetFrameCount(void); + +int RENDER_GetBufferInfo(R_BUFFER_INFO *); + +} // End of namespace Saga + +#endif /* SAGA_RENDER_MOD_H__ */ diff --git a/saga/resfile.cpp b/saga/resfile.cpp deleted file mode 100644 index 5b3a345644..0000000000 --- a/saga/resfile.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2003 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * $Header$ - * - */ - -#include "common/file.h" - -#include "saga.h" - -#include "resfile.h" -#include "binread.h" - -namespace Saga { - -ResourceFile::ResourceFile() { - _resTblOffset = 0; - _resTblCt = 0; - _resTblLoaded = false; - _resTbl = NULL; -} - -ResourceFile::~ResourceFile() { - close(); -} - -bool ResourceFile::open(const char *filename, const char *directory) { - byte * temp_tbl; - uint32 tbl_len; - - if (!File::open(filename, directory)) { - return false; - } - - /* Seek to end of file to read resource table 'trailer' */ - _file_len = size(); - - seek(_file_len - RSC_TABLEINFO_SIZE, SEEK_SET); - - _resTblOffset = readSint32LE(); - _resTblCt = readSint32LE(); - - /* Check for sane values */ - if (_resTblOffset != _file_len - RSC_TABLEINFO_SIZE - - (RSC_TABLEENTRY_SIZE * _resTblCt)) { - return false; - } - - /* Load resource table */ - _resTbl = new Resource[_resTblCt]; - - seek(_resTblOffset, SEEK_SET); - - tbl_len = _resTblCt * RSC_TABLEENTRY_SIZE; - temp_tbl = new byte[tbl_len]; - - if (read(temp_tbl, tbl_len) != tbl_len) { - delete [] _resTbl; - delete [] temp_tbl; - return false; - } - - BinReader bread(temp_tbl, tbl_len); - - for (int i = 0; i < _resTblCt; i++) { - _resTbl[i].res_offset = bread.readSint32LE(); - _resTbl[i].res_len = bread.readSint32LE(); - } - - delete[] temp_tbl; - - _resTblLoaded = true; - - return true; -} - - -void ResourceFile::close() { - if ( _resTblLoaded) { - delete [] _resTbl; - _resTblLoaded = false; - _resTbl = NULL; - } - - _resTblOffset = 0; - _resTblCt = 0; - - if (File::isOpen()) { - File::close(); - } -} - -int32 ResourceFile::getResourceCt() { - return (_resTblLoaded) ? _resTblCt : -1; -} - -int32 ResourceFile::getResourceOffset(int32 rn) { - if (!R_PBOUNDS(rn, _resTblCt)) - return -1; - - return _resTbl[rn].res_offset; -} - -int32 ResourceFile::getResourceLen(int32 rn) { - if (!R_PBOUNDS(rn, _resTblCt)) - return -1; - - return _resTbl[rn].res_len; -} - -bool ResourceFile::loadResource(int32 rn, byte **res, int32 *res_len) { - byte *new_res; - uint32 new_res_len; - - assert(res != NULL && res_len != NULL); - *res = NULL; - *res_len = 0; - - if (!R_PBOUNDS(rn, _resTblCt)) { - return false; - } - - new_res_len = _resTbl[rn].res_len; - new_res = new byte[new_res_len]; - - if (!new_res) { - return false; - } - - seek(_resTbl[rn].res_offset, SEEK_SET); - - if (read(new_res, new_res_len) != new_res_len) { - delete[] new_res; - return false; - } - - *res = new_res; - *res_len = new_res_len; - - return true; -} - -void ResourceFile::freeResource(byte *res) { - delete[] res; -} - -} // End of namespace Saga diff --git a/saga/resfile.h b/saga/resfile.h deleted file mode 100644 index 40ad8f7898..0000000000 --- a/saga/resfile.h +++ /dev/null @@ -1,107 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2003 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * $Header$ - * - */ - -#ifndef SAGA_RESFILE_H -#define SAGA_RESFILE_H - -/* The 'RSC' resource file format used by SAGA is quite simple. - * At the end of the resource file is an 8 byte structure. The first - * 32 bit value specifies the offset of the resource table, the - * second specifies the number of entries in the resource table. - * Each entry in the resource table is itself 32 bytes, the first - * 32 bit value of which specifies the offset of the resource, the - * second specifies the length of the resource. - */ - -#include "common/file.h" - -namespace Saga { - -class ResourceFile : public File { - -public: - - struct Resource { - int32 res_offset; - int32 res_len; - }; - -private: - - long _file_len; - -protected: - - enum ResourceConstants { - RSC_TABLEINFO_SIZE = 8, - RSC_TABLEENTRY_SIZE = 8 - }; - - const char *_resDirectory; - - int32 _resTblOffset; - int32 _resTblCt; - - bool _resTblLoaded; - Resource *_resTbl; - -public: - - ResourceFile(); - virtual ~ResourceFile(); - - bool open(const char *filename, const char *directory); - void close(); - - inline int16 readSint16LE() { - return readUint16LE(); - } - - inline int32 readSint32LE() { - return readUint32LE(); - } - - inline int16 readSint16BE() { - return readUint16BE(); - } - - inline int32 readSint32BE() { - return readUint32BE(); - } - - int32 getResourceCt(); - int32 getResourceOffset( int32 rn ); - int32 getResourceLen( int32 rn ); - - bool loadResource( int32 rn, byte **res, int32 *res_len ); - void freeResource( byte *res ); - -}; - -} // End of namespace Saga - - -#endif - - - - - diff --git a/saga/resnames.h b/saga/resnames.h deleted file mode 100644 index 596e1cefaf..0000000000 --- a/saga/resnames.h +++ /dev/null @@ -1,130 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2003 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * $Header$ - * - */ - -#ifndef SAGA_RESNAMES_H -#define SAGA_RESNAMES_H - -namespace Saga { - -/* Lookup tables -\*-----------------------------------------------------------------*/ -#define ITE_SCENE_LUT 1806 -#define ITE_SCRIPT_LUT 216 - -#define IHNM_SCENE_LUT 1272 -#define IHNM_SCRIPT_LUT 0 - -/* SCENES */ -#define ITE_DEFAULT_SCENE 32 - -/* FONTS */ -#define RN_MEDIUM_FONT 0 -#define RN_BIG_FONT 1 -#define RN_SMALL_FONT 2 - -#define ITE_OVERLAY_PAL ((unsigned long)-1) -#define IHNM_OVERLAY_PAL 1 - -#define ITE_ACTOR_PERSONA_TBL ((unsigned long)-1) -#define IHNM_ACTOR_PERSONA_TBL 80 - -/* Interface resources -\*-----------------------------------------------------------------*/ -#define ITE_COMMAND_PANEL 3 -#define ITE_COMMAND_BUTTONSPRITES 7 - -#define ITE_DIALOGUE_PANEL 4 -#define ITE_DEFAULT_PORTRAITS 125 - -#define ITE_SETUP_PANEL 5 - -#define IHNM_COMMAND_PANEL 9 -#define IHNM_COMMAND_BUTTONSPRITES 12 - -#define IHNM_DIALOGUE_PANEL 10 - -/* No real "default" portraits for IHNM, but provide one for now */ -#define IHNM_DEFAULT_PORTRAITS 45 - -/* ITE Scene resource numbers */ -#define ITE_INTRO_ANIM_SCENE 1538 -#define ITE_CAVE_SCENE_1 1542 -#define ITE_CAVE_SCENE_2 1545 -#define ITE_CAVE_SCENE_3 1548 -#define ITE_CAVE_SCENE_4 1551 - -#define ITE_VALLEY_SCENE 1556 -#define ITE_TREEHOUSE_SCENE 1560 -#define ITE_FAIREPATH_SCENE 1564 -#define ITE_FAIRETENT_SCENE 1567 - -#define ITE_INTRO_ANIM_STARTFRAME 1529 - -/* ITE_VOICES */ -#define CAVE_VOICE_0 0 -#define CAVE_VOICE_1 1 -#define CAVE_VOICE_2 2 -#define CAVE_VOICE_3 3 -#define CAVE_VOICE_4 4 -#define CAVE_VOICE_5 5 -#define CAVE_VOICE_6 6 -#define CAVE_VOICE_7 7 -#define CAVE_VOICE_8 8 -#define CAVE_VOICE_9 9 -#define CAVE_VOICE_10 10 -#define CAVE_VOICE_11 11 -#define CAVE_VOICE_12 12 -#define CAVE_VOICE_13 13 - -/* MUSIC */ -#define MUSIC_1 9 -#define MUSIC_2 10 -#define MUSIC_3 11 -#define MUSIC_4 12 -#define MUSIC_5 13 -#define MUSIC_6 14 -#define MUSIC_7 15 -#define MUSIC_8 16 -#define MUSIC_9 17 -#define MUSIC_10 18 -#define MUSIC_11 19 -#define MUSIC_12 20 -#define MUSIC_13 21 -#define MUSIC_14 22 -#define MUSIC_15 23 -#define MUSIC_16 24 -#define MUSIC_17 25 -#define MUSIC_18 26 -#define MUSIC_19 27 -#define MUSIC_20 28 -#define MUSIC_21 29 -#define MUSIC_22 30 -#define MUSIC_23 31 -#define MUSIC_24 32 -#define MUSIC_25 33 -#define MUSIC_26 34 - -} // End of namespace Saga - -#endif - - - diff --git a/saga/rscfile.cpp b/saga/rscfile.cpp new file mode 100644 index 0000000000..b96a694b32 --- /dev/null +++ b/saga/rscfile.cpp @@ -0,0 +1,310 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + RSC Resource file management module + + Notes: +*/ + +#include "reinherit.h" + +#include "yslib.h" + +/* + * Uses the following modules: +\*--------------------------------------------------------------------------*/ + +/* + * Begin module +\*--------------------------------------------------------------------------*/ +#include "rscfile_mod.h" +#include "rscfile.h" + +namespace Saga { + +R_RSCFILE_CONTEXT *RSC_CreateContext(void) +{ + R_RSCFILE_CONTEXT empty_context = { 0 }; + R_RSCFILE_CONTEXT *new_context; + + new_context = (R_RSCFILE_CONTEXT *)malloc(sizeof *new_context); + if (new_context == NULL) { + return NULL; + } + + *new_context = empty_context; + + return new_context; +} + +int RSC_OpenContext(R_RSCFILE_CONTEXT * rsc_context, const char *fspec) +{ + FILE *rsc_fp; + int result; + + rsc_fp = fopen(fspec, "rb"); + if (rsc_fp == NULL) { + return R_FAILURE; + } + + if (rsc_context->rc_file_open) { + return R_FAILURE; + } + + rsc_context->rc_file_fspec = fspec; + rsc_context->rc_file_p = rsc_fp; + + result = ys_get_filesize(rsc_fp, &rsc_context->rc_file_size, NULL); + if (result != YS_E_SUCCESS) { + fclose(rsc_fp); + return R_FAILURE; + } + + if (RSC_LoadRSC(rsc_context) != R_SUCCESS) { + return R_FAILURE; + } + + rsc_context->rc_file_open = 1; + rsc_context->rc_file_loaded = 1; + + return R_SUCCESS; +} + +int RSC_CloseContext(R_RSCFILE_CONTEXT * rsc_context) +{ + if (rsc_context->rc_file_open) { + fclose(rsc_context->rc_file_p); + } + + rsc_context->rc_file_open = 0; + + RSC_FreeRSC(rsc_context); + + rsc_context->rc_file_loaded = 0; + + return R_SUCCESS; +} + +int RSC_DestroyContext(R_RSCFILE_CONTEXT * rsc_context) +{ + RSC_CloseContext(rsc_context); + + if (rsc_context->rc_file_loaded) { + free(rsc_context->rc_res_table); + } + + free(rsc_context); + + return R_SUCCESS; +} + +int RSC_LoadRSC(R_RSCFILE_CONTEXT * rsc) +{ + ulong res_tbl_ct; + ulong res_tbl_offset; + + uchar tblinfo_buf[RSC_TABLEINFO_SIZE]; + uchar *tbl_buf; + size_t tbl_len; + ulong i; + + R_RSCFILE_RESOURCE *rsc_restbl; + + const uchar *read_p; + + read_p = tblinfo_buf; + + if (rsc->rc_file_size < RSC_MIN_FILESIZE) { + return R_FAILURE; + } + + /* Read resource table info from the rear end of file + * \*------------------------------------------------------------- */ + fseek(rsc->rc_file_p, (long)(rsc->rc_file_size - 8), SEEK_SET); + + if (fread(tblinfo_buf, + 1, RSC_TABLEINFO_SIZE, rsc->rc_file_p) != RSC_TABLEINFO_SIZE) { + + return R_FAILURE; + } + + res_tbl_offset = ys_read_u32_le(read_p, &read_p); + res_tbl_ct = ys_read_u32_le(read_p, NULL); + + /* Check for sane table offset + * \*------------------------------------------------------------- */ + if (res_tbl_offset != rsc->rc_file_size - RSC_TABLEINFO_SIZE - + RSC_TABLEENTRY_SIZE * res_tbl_ct) { + + return R_FAILURE; + } + + /* Load resource table + * \*------------------------------------------------------------- */ + tbl_len = RSC_TABLEENTRY_SIZE * res_tbl_ct; + + tbl_buf = (uchar *)malloc(tbl_len); + if (tbl_buf == NULL) { + return R_FAILURE; + } + + fseek(rsc->rc_file_p, (long)res_tbl_offset, SEEK_SET); + + if (fread(tbl_buf, 1, tbl_len, rsc->rc_file_p) != tbl_len) { + free(tbl_buf); + return R_FAILURE; + } + + rsc_restbl = (R_RSCFILE_RESOURCE *)malloc(res_tbl_ct * sizeof *rsc_restbl); + if (rsc_restbl == NULL) { + free(tbl_buf); + return R_FAILURE; + } + + read_p = tbl_buf; + + for (i = 0; i < res_tbl_ct; i++) { + + rsc_restbl[i].res_offset = ys_read_u32_le(read_p, &read_p); + rsc_restbl[i].res_size = ys_read_u32_le(read_p, &read_p); + + if ((rsc_restbl[i].res_offset > rsc->rc_file_size) || + (rsc_restbl[i].res_size > rsc->rc_file_size)) { + + free(tbl_buf); + free(rsc_restbl); + return R_FAILURE; + } + } + + rsc->rc_res_table = rsc_restbl; + rsc->rc_res_ct = res_tbl_ct; + + free(tbl_buf); + + return R_SUCCESS; +} + +int RSC_FreeRSC(R_RSCFILE_CONTEXT * rsc) +{ + if (!rsc->rc_file_loaded) { + return R_FAILURE; + } + + free(rsc->rc_res_table); + + return R_SUCCESS; +} + +ulong RSC_GetResourceCount(R_RSCFILE_CONTEXT * rsc) +{ + return (rsc == NULL) ? 0 : rsc->rc_res_ct; +} + +int +RSC_GetResourceSize(R_RSCFILE_CONTEXT * rsc, ulong res_num, ulong * res_size) +{ + if ((rsc == NULL) || (res_size == NULL)) { + return R_FAILURE; + } + + if (res_num > (rsc->rc_res_ct - 1)) { + return R_FAILURE; + } + + *res_size = rsc->rc_res_table[res_num].res_size; + + return R_SUCCESS; +} + +int +RSC_GetResourceOffset(R_RSCFILE_CONTEXT * rsc, + ulong res_num, ulong * res_offset) +{ + if ((rsc == NULL) || (res_offset == NULL)) { + return R_FAILURE; + } + + if (res_num > (rsc->rc_res_ct - 1)) { + return R_FAILURE; + } + + *res_offset = rsc->rc_res_table[res_num].res_offset; + + return R_SUCCESS; +} + +int +RSC_LoadResource(R_RSCFILE_CONTEXT * rsc, + ulong res_num, uchar ** res_p, size_t * res_size_p) +{ + ulong res_offset; + size_t res_size; + uchar *res_buf; + + if ((rsc == NULL) || (res_p == NULL)) { + return R_FAILURE; + } + + if (res_num > (rsc->rc_res_ct - 1)) { + return R_FAILURE; + } + + res_offset = rsc->rc_res_table[res_num].res_offset; + res_size = rsc->rc_res_table[res_num].res_size; + + if (fseek(rsc->rc_file_p, (long)res_offset, SEEK_SET) != 0) { + return R_FAILURE; + } + + res_buf = (uchar *)malloc(res_size); + if (res_buf == NULL) { + return R_MEM; + } + + if (fread(res_buf, 1, res_size, rsc->rc_file_p) != res_size) { + free(res_buf); + return R_FAILURE; + } + + *res_p = res_buf; + + if (res_size_p != NULL) { + *res_size_p = res_size; + } + + return R_SUCCESS; +} + +int RSC_FreeResource(uchar * resource_ptr) +{ + + free(resource_ptr); + + return R_SUCCESS; +} + +} // End of namespace Saga diff --git a/saga/rscfile.h b/saga/rscfile.h new file mode 100644 index 0000000000..6a9e7e423f --- /dev/null +++ b/saga/rscfile.h @@ -0,0 +1,70 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + RSC Resource file management header file + + Notes: +*/ + +#ifndef SAGA_RSCFILE_H__ +#define SAGA_RSCFILE_H__ + +namespace Saga { + +#define RSC_TABLEINFO_SIZE 8 +#define RSC_TABLEENTRY_SIZE 8 + +#define RSC_MIN_FILESIZE (RSC_TABLEINFO_SIZE + RSC_TABLEENTRY_SIZE + 1) + +typedef struct R_RSCFILE_RESOURCE_tag { + + int res_type; + + size_t res_offset; + size_t res_size; + +} R_RSCFILE_RESOURCE; + +struct R_RSCFILE_CONTEXT_tag { + + const char *rc_file_fspec; + FILE *rc_file_p; + int rc_file_open; + unsigned long rc_file_size; + + int rc_file_loaded; + R_RSCFILE_RESOURCE *rc_res_table; + size_t rc_res_ct; + +}; + +int RSC_LoadRSC(R_RSCFILE_CONTEXT * rsc_context); + +int RSC_FreeRSC(R_RSCFILE_CONTEXT * rsc); + +} // End of namespace Saga + +#endif /* SAGA_RSCFILE_H__ */ diff --git a/saga/rscfile_mod.h b/saga/rscfile_mod.h new file mode 100644 index 0000000000..c337ff41e0 --- /dev/null +++ b/saga/rscfile_mod.h @@ -0,0 +1,59 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + RSC Resource file management module public header file + + Notes: +*/ + +#ifndef SAGA_RSCFILE_MOD_H__ +#define SAGA_RSCFILE_MOD_H__ + +#include "resnames.h" + +namespace Saga { + +R_RSCFILE_CONTEXT *RSC_CreateContext(void); + +int RSC_DestroyContext(R_RSCFILE_CONTEXT *); + +int RSC_OpenContext(R_RSCFILE_CONTEXT *, const char *); + +int RSC_CloseContext(R_RSCFILE_CONTEXT *); + +ulong RSC_GetResourceCount(R_RSCFILE_CONTEXT *); + +int RSC_GetResourceSize(R_RSCFILE_CONTEXT *, ulong, ulong *); + +int RSC_GetResourceOffset(R_RSCFILE_CONTEXT *, ulong, ulong *); + +int RSC_LoadResource(R_RSCFILE_CONTEXT *, ulong, uchar **, size_t *); + +int RSC_FreeResource(uchar *); + +} // End of namespace Saga + +#endif /* SAGA_RSCFILE_MOD_H__ */ diff --git a/saga/saga.cpp b/saga/saga.cpp index 9d3e11296b..729249a63b 100644 --- a/saga/saga.cpp +++ b/saga/saga.cpp @@ -1,24 +1,3 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2003 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * $Header$ - * - */ - #include "stdafx.h" #include "base/gameDetector.h" @@ -31,7 +10,26 @@ #include "saga.h" -#include "gamedesc.h" +#include "reinherit.h" + +#include "rscfile_mod.h" +#include "render_mod.h" +#include "actor_mod.h" +#include "animation_mod.h" +#include "console_mod.h" +#include "cvar_mod.h" +#include "events_mod.h" +#include "actionmap_mod.h" +#include "font_mod.h" +#include "game_mod.h" +#include "interface_mod.h" +#include "isomap_mod.h" +#include "script_mod.h" +#include "scene_mod.h" +#include "sndres_mod.h" +#include "sprite_mod.h" +#include "text_mod.h" +#include "objectmap_mod.h" struct SAGAGameSettings { const char *name; @@ -96,11 +94,24 @@ REGISTER_PLUGIN("SAGA Engine", Engine_SAGA_gameList, Engine_SAGA_create, Engine_ namespace Saga { +#define R_MAX_TIME_DELTA 100 + +typedef struct R_MAIN_DATA_tag { + + int sound_enabled; + int music_enabled; + +} R_MAIN_DATA; + +static void CF_quitfunc(int argc, char *argv[]); +static void CF_testfunc(int argc, char *argv[]); + +static R_MAIN_DATA MainData; + SagaEngine::SagaEngine(GameDetector *detector, OSystem *syst) : Engine(syst) { - setGameDirectory(getGameDataPath()); - openGame(); + GAME_setGameDirectory(getGameDataPath()); // Setup mixer if (!_mixer->isReady()) { @@ -110,7 +121,7 @@ SagaEngine::SagaEngine(GameDetector *detector, OSystem *syst) _mixer->setVolume(ConfMan.getInt("sfx_volume") * ConfMan.getInt("master_volume") / 255); // Initialize backend - syst->initSize(320, 240); + //syst->initSize(320, 240); } SagaEngine::~SagaEngine() { @@ -122,13 +133,200 @@ void SagaEngine::errorString(const char *buf1, char *buf2) { } void SagaEngine::go() { + int msec = 0; + + /* Register engine modules + * \*------------------------------------------------------------- */ + CON_Register(); /* Register console cvars first */ + + RENDER_Register(); + GAME_Register(); + + ANIM_Register(); + ACTIONMAP_Register(); + OBJECTMAP_Register(); + SCRIPT_Register(); + ACTOR_Register(); + SCENE_Register(); + + MainData.sound_enabled = 1; + + CVAR_RegisterFunc(CF_testfunc, + "testfunc", "foo [ optional foo ]", R_CVAR_NONE, 0, -1); + + CVAR_Register_I(&MainData.sound_enabled, + "sound", NULL, R_CVAR_CFG, 0, 1); + + CVAR_Register_I(&MainData.music_enabled, + "music", NULL, R_CVAR_CFG, 0, 1); + + CVAR_RegisterFunc(CF_quitfunc, "quit", NULL, R_CVAR_NONE, 0, 0); + + /* Process config file + * \*------------------------------------------------------------- */ + // FIXME + /* + if (CFG_Read(NULL) != R_SUCCESS) { + R_printf(R_STDERR, "Couldn't read configuration file.\n"); + } + */ + + /* Process command line + * \*------------------------------------------------------------- */ + + /* Detect game and open resource files + * \*------------------------------------------------------------- */ + if (GAME_Init() != R_SUCCESS) { + + R_printf(R_STDERR, + "Couldn't start the game: %s\n", GAME_GetErrS()); + + return; + } + + /* Initialize engine modules + * \*------------------------------------------------------------- */ + SND_Init(); + EVENT_Init(); + FONT_Init(); + SPRITE_Init(); + ANIM_Init(); + ACTIONMAP_Init(); + OBJECTMAP_Init(); + ISOMAP_Init(); + SCRIPT_Init(); + INTERFACE_Init(); /* requires script module */ + ACTOR_Init(); + + if (SCENE_Init() != R_SUCCESS) { + + R_printf(R_STDERR, "Couldn't initialize scene module.\n"); + return; + } + + /* System initialization + * \*------------------------------------------------------------- */ + + if (SYSIO_Init() != R_SUCCESS) { + + return; + } + + /* Must initialize system timer module first */ + if (SYSTIMER_InitMSCounter() != R_SUCCESS) { + + return; + } + + /* On some platforms, graphics initialization also initializes sound + * ( Win32 DirectX )... Music must be initialized before sound for + * native midi support */ + SYSMUSIC_Init(MainData.music_enabled); + if (!MainData.music_enabled) { + R_printf(R_STDOUT, "Music disabled.\n"); + } + /* Initialize graphics */ + if (RENDER_Init() != R_SUCCESS) { + return; + } + + /* Initialize system specific sound */ + SYSSOUND_Init(MainData.sound_enabled); + if (!MainData.sound_enabled) { + R_printf(R_STDOUT, "Sound disabled.\n"); + } + + SYSINPUT_Init(); + + SYSTIMER_ResetMSCounter(); + + /* Begin Main Engine Loop + * \*------------------------------------------------------------- */ + + SCENE_Start(); + + for (;;) { + +#ifdef R_USE_CUSTOM_WININIT + + if (ITESYS_CheckSignal()) { + break; + } +#endif + + if (RENDER_GetFlags() & RF_RENDERPAUSE) { + /* Freeze time while paused */ + SYSTIMER_ResetMSCounter(); + } else { + msec = SYSTIMER_ReadMSCounter(); + + if (msec > R_MAX_TIME_DELTA) { + msec = R_MAX_TIME_DELTA; + } + + ACTOR_Direct(msec); + EVENT_HandleEvents(msec); + STHREAD_ExecThreads(msec); + } + + /* Per frame processing + * \*--------------------------------------------------------- */ + RENDER_DrawScene(); + + SYSTIMER_Sleep(0); + } /* end main game engine loop */ + + R_Shutdown(0); + + return; } void SagaEngine::shutdown() { - _system->quit(); } +void R_Shutdown(int param) { + SCENE_Shutdown(); + ACTOR_Shutdown(); + SCRIPT_Shutdown(); + ANIM_Shutdown(); + SPRITE_Shutdown(); + OBJECTMAP_Shutdown(); + + FONT_Shutdown(); + + CON_Shutdown(); + CVAR_Shutdown(); + EVENT_Shutdown(); + + /* Shutdown system modules */ + SYSMUSIC_Shutdown(); + SYSSOUND_Shutdown(); + + SYSIO_Shutdown(); + + /* exit(param); */ +} + +static void CF_quitfunc(int argc, char *argv[]) +{ + R_Shutdown(0); + exit(0); +} + +static void CF_testfunc(int argc, char *argv[]) +{ + int i; + + CON_Print("Test function invoked: Got %d arguments.", argc); + + for (i = 0; i < argc; i++) { + CON_Print("Arg %d: %s", i, argv[i]); + } + + return; +} + } // End of namespace Saga diff --git a/saga/saga.h b/saga/saga.h index edaa24c979..a97294b2e5 100644 --- a/saga/saga.h +++ b/saga/saga.h @@ -1,5 +1,7 @@ /* ScummVM - Scumm Interpreter - * Copyright (C) 2003 The ScummVM project + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -27,7 +29,7 @@ #include "base/gameDetector.h" #include "common/util.h" -#include "gamedesc.h" +//#include "gamedesc.h" namespace Saga { @@ -39,18 +41,16 @@ enum SAGAGameId { GID_IHNM }; -class SagaEngine : public Engine { - - void errorString( const char *buf_input, char *buf_output); +class SagaEngine:public Engine { + void errorString(const char *buf_input, char *buf_output); -protected: + protected: void go(); void shutdown(); -public: - - SagaEngine(GameDetector *detector, OSystem *syst); - virtual ~SagaEngine(); + public: + SagaEngine(GameDetector * detector, OSystem * syst); + virtual ~ SagaEngine(); }; diff --git a/saga/scene.cpp b/saga/scene.cpp new file mode 100644 index 0000000000..3fc9bda076 --- /dev/null +++ b/saga/scene.cpp @@ -0,0 +1,1159 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Scene management module + + Notes: +*/ + +#include "reinherit.h" + +#include "yslib.h" + +/* + * Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "game_mod.h" +#include "animation_mod.h" +#include "console_mod.h" +#include "cvar_mod.h" +#include "events_mod.h" +#include "actionmap_mod.h" +#include "gfx_mod.h" +#include "image_mod.h" +#include "isomap_mod.h" +#include "script_mod.h" +#include "objectmap_mod.h" +#include "palanim_mod.h" +#include "render_mod.h" +#include "rscfile_mod.h" +#include "text_mod.h" + +/* + * Begin module component +\*--------------------------------------------------------------------------*/ +#include "scene_mod.h" +#include "scene.h" + +namespace Saga { + +static R_SCENE_MODULE SceneModule; + +int SCENE_Register(void) +{ + + CVAR_Register_I(&SceneModule.scene_number, + "scene", NULL, R_CVAR_READONLY, 0, 0); + + CVAR_RegisterFunc(CF_scenechange, + "scene_change", "<Scene number>", R_CVAR_NONE, 1, 1); + + CVAR_RegisterFunc(CF_sceneinfo, "scene_info", NULL, R_CVAR_NONE, 0, 0); + + return R_SUCCESS; +} + +int SCENE_Init(void) +{ + + R_GAME_SCENEDESC gs_desc; + + uchar *scene_lut_p; + size_t scene_lut_len; + + const uchar *read_p; + + int result; + int i; + + /* Load game-specific scene data + * \*------------------------------------------------------------ */ + GAME_GetSceneInfo(&gs_desc); + + /* Load scene module resource context + * \*------------------------------------------------------------ */ + result = GAME_GetFileContext(&SceneModule.scene_ctxt, + R_GAME_RESOURCEFILE, 0); + if (result != R_SUCCESS) { + + R_printf(R_STDERR, "Couldn't load scene resource context.\n"); + + return R_FAILURE; + } + + /* Initialize scene queue + * \*------------------------------------------------------------ */ + SceneModule.scene_queue = ys_dll_create(); + if (SceneModule.scene_queue == NULL) { + + return R_FAILURE; + } + + /* Load scene lookup table + * \*------------------------------------------------------------ */ + R_printf(R_STDOUT, + "SCENE_Init(): Loading scene LUT from resource %d.\n", + gs_desc.scene_lut_rn); + + result = RSC_LoadResource(SceneModule.scene_ctxt, + gs_desc.scene_lut_rn, &scene_lut_p, &scene_lut_len); + if (result != R_SUCCESS) { + + R_printf(R_STDERR, "Error: couldn't load scene LUT.\n"); + + return R_FAILURE; + } + + SceneModule.scene_count = scene_lut_len / 2; + SceneModule.scene_max = SceneModule.scene_count - 1; + + SceneModule.scene_lut = (int *)malloc(SceneModule.scene_max * + sizeof *SceneModule.scene_lut); + if (SceneModule.scene_lut == NULL) { + R_printf(R_STDERR, + "SCENE_Init(): Memory allocation failed.\n"); + return R_MEM; + } + + read_p = scene_lut_p; + + for (i = 0; i < SceneModule.scene_max; i++) { + + SceneModule.scene_lut[i] = ys_read_u16_le(read_p, &read_p); + } + + free(scene_lut_p); + + if (gs_desc.first_scene != 0) { + SceneModule.first_scene = gs_desc.first_scene; + } + + R_printf(R_STDOUT, + "SCENE_Init(): First scene set to %d.\n", SceneModule.first_scene); + + R_printf(R_STDOUT, + "SCENE_Init(): LUT has %d entries.\n", SceneModule.scene_max); + + /* Create scene module text list + * \*------------------------------------------------------------ */ + SceneModule.text_list = TEXT_CreateList(); + + if (SceneModule.text_list == NULL) { + R_printf(R_STDERR, + "Error: Couldn't create scene text list.\n"); + + return R_FAILURE; + } + + SceneModule.init = 1; + + return R_SUCCESS; +} + +int SCENE_Shutdown(void) +{ + + if (SceneModule.init) { + SCENE_End(); + free(SceneModule.scene_lut); + } + + return R_SUCCESS; +} + +int SCENE_Queue(R_SCENE_QUEUE * scene_queue) +{ + assert(SceneModule.init); + assert(scene_queue != NULL); + + ys_dll_add_tail(SceneModule.scene_queue, + scene_queue, sizeof *scene_queue); + + return R_SUCCESS; +} + +int SCENE_ClearQueue(void) +{ + assert(SceneModule.init); + + ys_dll_delete_all(SceneModule.scene_queue); + + return R_SUCCESS; +} + +int SCENE_Start(void) +{ + + YS_DL_NODE *node; + R_SCENE_QUEUE *scene_qdat; + + assert(SceneModule.init); + + if (SceneModule.scene_loaded) { + R_printf(R_STDERR, + "Error: Can't start game...scene already loaded!\n"); + + return R_FAILURE; + } + + if (SceneModule.in_game) { + R_printf(R_STDERR, + "Error: Can't start game...game already started!\n"); + + return R_FAILURE; + } + + switch (GAME_GetGameType()) { + + case R_GAMETYPE_ITE: + ITE_StartProc(); + break; + + case R_GAMETYPE_IHNM: + IHNM_StartProc(); + break; + + default: + R_printf(R_STDERR, + "Error: Can't start game... gametype not supported.\n"); + break; + } + + /* Load the head node in scene queue + * \*------------------------------------------------------------- */ + node = ys_dll_head(SceneModule.scene_queue); + if (node == NULL) { + return R_SUCCESS; + } + + scene_qdat = (R_SCENE_QUEUE *)ys_dll_get_data(node); + assert(scene_qdat != NULL); + + SCENE_Load(scene_qdat->scene_n, + scene_qdat->load_flag, + scene_qdat->scene_proc, scene_qdat->scene_desc); + + return R_SUCCESS; +} + +int SCENE_Next(void) +{ + + YS_DL_NODE *node; + R_SCENE_QUEUE *scene_qdat; + + assert(SceneModule.init); + + if (!SceneModule.scene_loaded) { + R_printf(R_STDERR, + "Error: Can't advance scene...no scene loaded!\n"); + + return R_FAILURE; + } + + if (SceneModule.in_game) { + R_printf(R_STDERR, + "Error: Can't advance scene...game already started!\n"); + + return R_FAILURE; + } + + SCENE_End(); + + /* Delete the current head node in scene queue + * \*------------------------------------------------------------- */ + node = ys_dll_head(SceneModule.scene_queue); + if (node == NULL) { + return R_SUCCESS; + } + + ys_dll_delete(node); + + /* Load the head node in scene queue + * \*------------------------------------------------------------- */ + node = ys_dll_head(SceneModule.scene_queue); + if (node == NULL) { + return R_SUCCESS; + } + + scene_qdat = (R_SCENE_QUEUE *)ys_dll_get_data(node); + assert(scene_qdat != NULL); + + SCENE_Load(scene_qdat->scene_n, + scene_qdat->load_flag, + scene_qdat->scene_proc, scene_qdat->scene_desc); + + return R_SUCCESS; +} + +int SCENE_Skip(void) +{ + + YS_DL_NODE *node; + YS_DL_NODE *prev_node; + YS_DL_NODE *skip_node = NULL; + + R_SCENE_QUEUE *scene_qdat = NULL; + R_SCENE_QUEUE *skip_qdat = NULL; + + assert(SceneModule.init); + + if (!SceneModule.scene_loaded) { + + R_printf(R_STDERR, + "Error: Can't skip scene...no scene loaded.\n"); + + return R_FAILURE; + } + + if (SceneModule.in_game) { + + R_printf(R_STDERR, + "Error: Can't skip scene...game already started.\n"); + + return R_FAILURE; + } + + /* Walk down scene queue and try to find a skip target + * \*------------------------------------------------------------- */ + node = ys_dll_head(SceneModule.scene_queue); + if (node == NULL) { + + R_printf(R_STDERR, + "Error: Can't skip scene...no scenes in queue.\n"); + + return R_FAILURE; + } + + for (node = ys_dll_next(node); node != NULL; node = ys_dll_next(node)) { + + scene_qdat = (R_SCENE_QUEUE *)ys_dll_get_data(node); + assert(scene_qdat != NULL); + + if (scene_qdat->scene_skiptarget) { + + skip_node = node; + skip_qdat = scene_qdat; + break; + } + } + + /* If skip target found, remove preceding scenes and load + * \*------------------------------------------------------------- */ + if (skip_node != NULL) { + + for (node = ys_dll_prev(skip_node); + node != NULL; node = prev_node) { + + prev_node = ys_dll_prev(node); + + ys_dll_delete(node); + } + + SCENE_End(); + + SCENE_Load(skip_qdat->scene_n, + skip_qdat->load_flag, + skip_qdat->scene_proc, skip_qdat->scene_desc); + } + + /* Search for a scene to skip to */ + + return R_SUCCESS; +} + +int SCENE_Change(int scene_num) +{ + + assert(SceneModule.init); + + if (!SceneModule.scene_loaded) { + R_printf(R_STDERR, + "Error: Can't change scene. No scene currently loaded. " + "Game in invalid state.\n"); + + return R_FAILURE; + } + + if ((scene_num < 0) || (scene_num > SceneModule.scene_max)) { + + R_printf(R_STDERR, + "Error: Can't change scene. Invalid scene number.\n"); + + return R_FAILURE; + } + + if (SceneModule.scene_lut[scene_num] == 0) { + + R_printf(R_STDERR, + "Error: Can't change scene; invalid scene descriptor " + "resource number (0)\n"); + + return R_FAILURE; + } + + SCENE_End(); + SCENE_Load(scene_num, BY_SCENE, DefaultSceneProc, NULL); + + return R_SUCCESS; +} + +int SCENE_GetMode(void) +{ + assert(SceneModule.init); + + return SceneModule.scene_mode; +} + +int SCENE_GetZInfo(SCENE_ZINFO * zinfo) +{ + + assert(SceneModule.init); + + zinfo->begin_slope = SceneModule.desc.begin_slope; + zinfo->end_slope = SceneModule.desc.end_slope; + + return R_SUCCESS; +} + +int SCENE_GetBGInfo(SCENE_BGINFO * bginfo) +{ + R_GAME_DISPLAYINFO di; + int x, y; + + assert(SceneModule.init); + + bginfo->bg_buf = SceneModule.bg.buf; + bginfo->bg_buflen = SceneModule.bg.buf_len; + bginfo->bg_w = SceneModule.bg.w; + bginfo->bg_h = SceneModule.bg.h; + bginfo->bg_p = SceneModule.bg.p; + + GAME_GetDisplayInfo(&di); + x = 0; + y = 0; + + if (SceneModule.bg.w < di.logical_w) { + x = (di.logical_w - SceneModule.bg.w) / 2; + } + + if (SceneModule.bg.h < di.scene_h) { + y = (di.scene_h - SceneModule.bg.h) / 2; + } + + bginfo->bg_x = x; + bginfo->bg_y = y; + + return R_SUCCESS; +} + +int SCENE_GetBGPal(PALENTRY ** pal) +{ + assert(SceneModule.init); + + *pal = SceneModule.bg.pal; + + return R_SUCCESS; +} + +int SCENE_GetBGMaskInfo(int *w, int *h, uchar ** buf, size_t * buf_len) +{ + + assert(SceneModule.init); + + if (!SceneModule.bg_mask.loaded) { + return R_FAILURE; + } + + *w = SceneModule.bg_mask.w; + *h = SceneModule.bg_mask.h; + *buf = SceneModule.bg_mask.buf; + *buf_len = SceneModule.bg_mask.buf_len; + + return R_SUCCESS; +} + +int SCENE_IsBGMaskPresent(void) +{ + + assert(SceneModule.init); + + return SceneModule.bg_mask.loaded; +} + +int SCENE_GetInfo(R_SCENE_INFO * si) +{ + assert(SceneModule.init); + assert(si != NULL); + + si->text_list = SceneModule.text_list; + + return R_SUCCESS; +} + +int +SCENE_Load(int scene_num, + int load_flag, R_SCENE_PROC scene_proc, R_SCENE_DESC * scene_desc_param) +{ + + R_SCENE_INFO scene_info; + ulong res_number = 0; + int result; + int i; + + assert(SceneModule.init); + + if (SceneModule.scene_loaded == 1) { + + R_printf(R_STDERR, "Error, a scene is already loaded.\n"); + return R_FAILURE; + } + + SceneModule.anim_list = ys_dll_create(); + SceneModule.scene_mode = 0; + SceneModule.load_desc = 1; + + switch (load_flag) { + + case BY_RESOURCE: + res_number = scene_num; + break; + + case BY_SCENE: + assert((scene_num > 0) && (scene_num < SceneModule.scene_max)); + + res_number = SceneModule.scene_lut[scene_num]; + SceneModule.scene_number = scene_num; + break; + + case BY_DESC: + + assert(scene_desc_param != NULL); + assert(scene_desc_param->res_list != NULL); + + SceneModule.load_desc = 0; + + SceneModule.desc = *scene_desc_param; + SceneModule.reslist = scene_desc_param->res_list; + SceneModule.reslist_entries = scene_desc_param->res_list_ct; + break; + + default: + R_printf(R_STDERR, "Error: Invalid scene load flag.\n"); + return R_FAILURE; + break; + + } + + /* + * Load scene descriptor and resource list resources + \*-------------------------------------------------------------*/ + if (SceneModule.load_desc) { + + SceneModule.scene_rn = res_number; + assert(SceneModule.scene_rn != 0); + + R_printf(R_STDOUT, "Loading scene resource %d:\n", res_number); + + if (LoadSceneDescriptor(res_number) != R_SUCCESS) { + R_printf(R_STDERR, + "Error reading scene descriptor.\n"); + + return R_FAILURE; + } + + if (LoadSceneResourceList(SceneModule.desc.res_list_rn) + != R_SUCCESS) { + + R_printf(R_STDERR, + "Error reading scene resource list.\n"); + + return R_FAILURE; + } + } else { + + R_printf(R_STDOUT, "Loading memory scene resource.\n"); + } + + /* + * Load resources from scene resource list + \*-------------------------------------------------------------*/ + for (i = 0; i < SceneModule.reslist_entries; i++) { + + result = RSC_LoadResource(SceneModule.scene_ctxt, + SceneModule.reslist[i].res_number, + &SceneModule.reslist[i].res_data, + &SceneModule.reslist[i].res_data_len); + if (result != R_SUCCESS) { + + R_printf(R_STDERR, + "Error: Allocation failure loading scene " + "resource list.\n"); + + return R_FAILURE; + } + + } + + /* + * Process resources from scene resource list + \*-------------------------------------------------------------*/ + if (ProcessSceneResources() != R_SUCCESS) { + + R_printf(R_STDERR, "Error loading scene resources.\n"); + + return R_FAILURE; + } + + /* Load scene script data */ + if (SceneModule.desc.script_num > 0) { + + if (SCRIPT_Load(SceneModule.desc.script_num) != R_SUCCESS) { + + R_printf(R_STDERR, "Error loading scene script.\n"); + return R_FAILURE; + } + } + + SceneModule.scene_loaded = 1; + + if (scene_proc == NULL) { + SceneModule.scene_proc = DefaultSceneProc; + } else { + SceneModule.scene_proc = scene_proc; + } + + SCENE_GetInfo(&scene_info); + + SceneModule.scene_proc(SCENE_BEGIN, &scene_info); + + return R_SUCCESS; +} + +int LoadSceneDescriptor(ulong res_number) +{ + + uchar *scene_desc_data; + size_t scene_desc_len; + + const uchar *read_p; + + int result; + + result = RSC_LoadResource(SceneModule.scene_ctxt, + res_number, &scene_desc_data, &scene_desc_len); + if (result != R_SUCCESS) { + R_printf(R_STDERR, "Error: couldn't load scene descriptor.\n"); + + return R_FAILURE; + } + + if (scene_desc_len != SAGA_SCENE_DESC_LEN) { + R_printf(R_STDERR, + "Error: scene descriptor length invalid.\n"); + + return R_FAILURE; + } + + read_p = scene_desc_data; + + SceneModule.desc.unknown0 = ys_read_u16_le(read_p, &read_p); + SceneModule.desc.res_list_rn = ys_read_u16_le(read_p, &read_p); + SceneModule.desc.end_slope = ys_read_u16_le(read_p, &read_p); + SceneModule.desc.begin_slope = ys_read_u16_le(read_p, &read_p); + SceneModule.desc.script_num = ys_read_u16_le(read_p, &read_p); + SceneModule.desc.scene_scriptnum = ys_read_u16_le(read_p, &read_p); + SceneModule.desc.start_scriptnum = ys_read_u16_le(read_p, &read_p); + + SceneModule.desc.music_rn = ys_read_s16_le(read_p, &read_p); + + RSC_FreeResource(scene_desc_data); + + return R_SUCCESS; +} + +int LoadSceneResourceList(ulong reslist_rn) +{ + + uchar *resource_list; + size_t resource_list_len; + + const uchar *read_p; + + int result; + int i; + + /* + * Load the scene resource table + \*-------------------------------------------------------------*/ + result = RSC_LoadResource(SceneModule.scene_ctxt, + reslist_rn, &resource_list, &resource_list_len); + if (result != R_SUCCESS) { + + R_printf(R_STDERR, + "Error: couldn't load scene resource list.\n"); + + return R_FAILURE; + } + + read_p = resource_list; + + /* Allocate memory for scene resource list + * \*----------------------------------------- */ + SceneModule.reslist_entries = + resource_list_len / SAGA_RESLIST_ENTRY_LEN; + + R_printf(R_STDOUT, + "Scene resource list contains %d entries.\n", + SceneModule.reslist_entries); + + SceneModule.reslist = + (R_SCENE_RESLIST *)calloc(SceneModule.reslist_entries, sizeof *SceneModule.reslist); + + if (SceneModule.reslist == NULL) { + R_printf(R_STDERR, "Error: Memory allocation failed.\n"); + + return R_MEM; + } + + /* Load scene resource list from raw scene + * resource table + \*-----------------------------------------*/ + R_printf(R_STDOUT, "Loading scene resource list...\n"); + + for (i = 0; i < SceneModule.reslist_entries; i++) { + + SceneModule.reslist[i].res_number = + ys_read_u16_le(read_p, &read_p); + SceneModule.reslist[i].res_type = + ys_read_u16_le(read_p, &read_p); + } + + RSC_FreeResource(resource_list); + + return R_SUCCESS; +} + +int ProcessSceneResources(void) +{ + + const uchar *res_data; + size_t res_data_len; + + const uchar *pal_p; + + int i; + + /* + * Process the scene resource list + \*-------------------------------------------------------------*/ + for (i = 0; i < SceneModule.reslist_entries; i++) { + + res_data = SceneModule.reslist[i].res_data; + res_data_len = SceneModule.reslist[i].res_data_len; + + switch (SceneModule.reslist[i].res_type) { + + /* Scene background resource */ + case SAGA_BG_IMAGE: + + if (SceneModule.bg.loaded) { + + R_printf(R_STDERR, + "Error: Multiple background resources " + "encountered.\n"); + return R_FAILURE; + } + + R_printf(R_STDOUT, "Loading background resource.\n"); + + SceneModule.bg.res_buf = + SceneModule.reslist[i].res_data; + SceneModule.bg.res_len = + SceneModule.reslist[i].res_data_len; + SceneModule.bg.loaded = 1; + + if (IMG_DecodeBGImage(SceneModule.bg.res_buf, + SceneModule.bg.res_len, + &SceneModule.bg.buf, + &SceneModule.bg.buf_len, + &SceneModule.bg.w, + &SceneModule.bg.h) != R_SUCCESS) { + R_printf(R_STDERR, + "Error loading background resource: %lu\n", + SceneModule.reslist[i].res_number); + + return R_FAILURE; + } + + pal_p = IMG_GetImagePal(SceneModule.bg.res_buf, + SceneModule.bg.res_len); + + memcpy(SceneModule.bg.pal, + pal_p, sizeof SceneModule.bg.pal); + + SceneModule.scene_mode = R_SCENE_MODE_NORMAL; + + break; + + /* Scene background mask resource */ + case SAGA_BG_MASK: + + if (SceneModule.bg_mask.loaded) { + R_printf(R_STDERR, + "Error: Duplicate background mask resource " + "encountered.\n"); + } + + R_printf(R_STDOUT, + "Loading BACKGROUND MASK resource.\n"); + + SceneModule.bg_mask.res_buf = + SceneModule.reslist[i].res_data; + SceneModule.bg_mask.res_len = + SceneModule.reslist[i].res_data_len; + SceneModule.bg_mask.loaded = 1; + + IMG_DecodeBGImage(SceneModule.bg_mask.res_buf, + SceneModule.bg_mask.res_len, + &SceneModule.bg_mask.buf, + &SceneModule.bg_mask.buf_len, + &SceneModule.bg_mask.w, &SceneModule.bg_mask.h); + break; + + case SAGA_OBJECT_NAME_LIST: + + R_printf(R_STDOUT, + "Loading object name list resource...\n"); + + OBJECTMAP_LoadNames(SceneModule.reslist[i].res_data, + SceneModule.reslist[i].res_data_len); + break; + + case SAGA_OBJECT_MAP: + + R_printf(R_STDOUT, "Loading object map resource...\n"); + + if (OBJECTMAP_Load(res_data, + res_data_len) != R_SUCCESS) { + + R_printf(R_STDERR, + "Error loading object map resource.\n"); + return R_FAILURE; + } + break; + + case SAGA_ACTION_MAP: + + R_printf(R_STDOUT, "Loading exit map resource...\n"); + + if (ACTIONMAP_Load(res_data, + res_data_len) != R_SUCCESS) { + R_printf(R_STDERR, + "Error loading exit map resource.\n"); + return R_FAILURE; + } + break; + + case SAGA_ISO_TILESET: + + if (SceneModule.scene_mode == R_SCENE_MODE_NORMAL) { + R_printf(R_STDERR, + "Isometric tileset incompatible with normal " + "scene mode.\n"); + return R_FAILURE; + } + + R_printf(R_STDOUT, + "Loading isometric tileset resource.\n"); + + if (ISOMAP_LoadTileset(res_data, + res_data_len) != R_SUCCESS) { + R_printf(R_STDERR, + "Error loading isometric tileset resource.\n"); + return R_FAILURE; + } + + SceneModule.scene_mode = R_SCENE_MODE_ISO; + break; + + case SAGA_ISO_METAMAP: + + if (SceneModule.scene_mode == R_SCENE_MODE_NORMAL) { + R_printf(R_STDERR, + "Isometric metamap incompatible with normal " + "scene mode.\n"); + return R_FAILURE; + } + + R_printf(R_STDOUT, + "Loading isometric metamap resource.\n"); + + if (ISOMAP_LoadMetamap(res_data, + res_data_len) != R_SUCCESS) { + R_printf(R_STDERR, + "Error loading isometric metamap resource.\n"); + return R_FAILURE; + } + + SceneModule.scene_mode = R_SCENE_MODE_ISO; + break; + + case SAGA_ISO_METATILESET: + if (SceneModule.scene_mode == R_SCENE_MODE_NORMAL) { + R_printf(R_STDERR, + "Isometric metatileset incompatible with " + "normal scene mode.\n"); + return R_FAILURE; + } + + R_printf(R_STDOUT, + "Loading isometric metatileset resource.\n"); + + if (ISOMAP_LoadMetaTileset(res_data, + res_data_len) != R_SUCCESS) { + R_printf(R_STDERR, + "Error loading isometric tileset resource.\n"); + return R_FAILURE; + } + + SceneModule.scene_mode = R_SCENE_MODE_ISO; + break; + + case SAGA_ANIM_1: + case SAGA_ANIM_2: + case SAGA_ANIM_3: + case SAGA_ANIM_4: + case SAGA_ANIM_5: + case SAGA_ANIM_6: + case SAGA_ANIM_7: + { + SCENE_ANIMINFO *new_animinfo; + uint new_anim_id; + + R_printf(R_STDOUT, + "Loading animation resource...\n"); + + new_animinfo = (SCENE_ANIMINFO *)malloc(sizeof *new_animinfo); + if (new_animinfo == NULL) { + + R_printf(R_STDERR, + "Memory allocation error.\n"); + + return R_MEM; + } + + if (ANIM_Load(SceneModule.reslist[i].res_data, + SceneModule.reslist[i].res_data_len, + &new_anim_id) == R_SUCCESS) { + } else { + R_printf(R_STDERR, + "Error loading animation resource\n"); + + return R_FAILURE; + } + + new_animinfo->anim_handle = new_anim_id; + new_animinfo->anim_res_number = + SceneModule.reslist[i].res_number; + + ys_dll_add_tail(SceneModule.anim_list, + new_animinfo, sizeof *new_animinfo); + + SceneModule.anim_entries++; + } + break; + + case SAGA_PAL_ANIM: + + R_printf(R_STDOUT, + "Loading palette animation resource.\n"); + + PALANIM_Load(SceneModule.reslist[i].res_data, + SceneModule.reslist[i].res_data_len); + break; + + default: + + R_printf(R_STDERR, + "Encountered unknown resource type: %d\n", + SceneModule.reslist[i].res_type); + break; + + } + } + + return R_SUCCESS; +} + +int SCENE_Draw(R_SURFACE * dst_s) +{ + R_GAME_DISPLAYINFO disp_info; + R_BUFFER_INFO buf_info; + R_POINT bg_pt; + + assert(SceneModule.init); + + RENDER_GetBufferInfo(&buf_info); + GAME_GetDisplayInfo(&disp_info); + + bg_pt.x = 0; + bg_pt.y = 0; + + switch (SceneModule.scene_mode) { + + case R_SCENE_MODE_NORMAL: + + GFX_BufToSurface(dst_s, + buf_info.r_bg_buf, + disp_info.logical_w, + YS_MAX(disp_info.scene_h, SceneModule.bg.h), NULL, &bg_pt); + break; + + case R_SCENE_MODE_ISO: + + ISOMAP_Draw(dst_s); + break; + + default: + /* Unknown scene mode */ + return R_FAILURE; + break; + + }; + + return R_SUCCESS; +} + +int SCENE_End(void) +{ + R_SCENE_INFO scene_info; + + assert(SceneModule.init); + + if (SceneModule.scene_loaded != 1) { + R_printf(R_STDERR, "SCENE_End(): No scene to end.\n"); + return -1; + } + + R_printf(R_STDOUT, "SCENE_End(): Ending scene...\n"); + + SCENE_GetInfo(&scene_info); + + SceneModule.scene_proc(SCENE_END, &scene_info); + + if (SceneModule.desc.script_num > 0) { + + SCRIPT_Free(); + } + + /* Free scene background */ + if (SceneModule.bg.loaded) { + free(SceneModule.bg.buf); + SceneModule.bg.loaded = 0; + } + + /* Free scene background mask */ + if (SceneModule.bg_mask.loaded) { + free(SceneModule.bg_mask.buf); + SceneModule.bg_mask.loaded = 0; + } + + /* Free scene resource list */ + if (SceneModule.load_desc) { + + free(SceneModule.reslist); + } + + /* Free animation info list */ + ANIM_Reset(); + + PALANIM_Free(); + OBJECTMAP_Free(); + ACTIONMAP_Free(); + + ys_dll_destroy(SceneModule.anim_list); + + SceneModule.anim_entries = 0; + + EVENT_ClearList(); + TEXT_ClearList(SceneModule.text_list); + + SceneModule.scene_loaded = 0; + + return R_SUCCESS; +} + +void CF_scenechange(int argc, char *argv[]) +{ + + int scene_num = 0; + + if ((argc == 0) || (argc > 1)) { + return; + } + + scene_num = atoi(argv[0]); + + if ((scene_num < 1) || (scene_num > SceneModule.scene_max)) { + CON_Print("Invalid scene number."); + return; + } + + SCENE_ClearQueue(); + + if (SCENE_Change(scene_num) == R_SUCCESS) { + CON_Print("Scene changed."); + } else { + CON_Print("Couldn't change scene!"); + } + + return; +} + +void CF_sceneinfo(int argc, char *argv[]) +{ + + const char *fmt = "%-20s %d"; + + YS_IGNORE_PARAM(argc); + YS_IGNORE_PARAM(argv); + + CON_Print(fmt, "Scene number:", SceneModule.scene_number); + CON_Print(fmt, "Descriptor R#:", SceneModule.scene_rn); + CON_Print("-------------------------"); + CON_Print(fmt, "Unknown:", SceneModule.desc.unknown0); + CON_Print(fmt, "Resource list R#:", SceneModule.desc.res_list_rn); + CON_Print(fmt, "End slope:", SceneModule.desc.end_slope); + CON_Print(fmt, "Begin slope:", SceneModule.desc.begin_slope); + CON_Print(fmt, "Script resource:", SceneModule.desc.script_num); + CON_Print(fmt, "Scene script:", SceneModule.desc.scene_scriptnum); + CON_Print(fmt, "Start script:", SceneModule.desc.start_scriptnum); + CON_Print(fmt, "Music R#", SceneModule.desc.music_rn); + + return; +} + +} // End of namespace Saga diff --git a/saga/scene.h b/saga/scene.h new file mode 100644 index 0000000000..21478c64c1 --- /dev/null +++ b/saga/scene.h @@ -0,0 +1,229 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Scene management module private header file + + Notes: +*/ + +#ifndef SAGA_SCENE_H +#define SAGA_SCENE_H + +namespace Saga { + +enum SCENE_LOAD_FLAGS { + + BY_RESOURCE = 0, + BY_SCENE, + BY_DESC +}; + +enum SCENE_PROC_PARAMS { + + SCENE_BEGIN = 0, + SCENE_END +}; + +/* Resource type numbers */ +enum SAGA_RESOURCE_TYPES { + + SAGA_BG_IMAGE = 2, + SAGA_BG_MASK = 3, + SAGA_OBJECT_NAME_LIST = 5, + SAGA_OBJECT_MAP = 6, + SAGA_ACTION_MAP = 7, + SAGA_ISO_TILESET = 8, + SAGA_ISO_METAMAP = 9, + SAGA_ISO_METATILESET = 10, + SAGA_ANIM_1 = 14, + SAGA_ANIM_2, + SAGA_ANIM_3, + SAGA_ANIM_4, + SAGA_ANIM_5, + SAGA_ANIM_6, + SAGA_ANIM_7, + SAGA_PAL_ANIM = 23 +}; + +#define SAGA_SCENE_DESC_LEN 16 + +typedef struct R_SCENE_DESC_tag { + + int unknown0; + int res_list_rn; + int end_slope; + int begin_slope; + int script_num; + int scene_scriptnum; + int start_scriptnum; + int music_rn; + + struct R_SCENE_RESLIST_tag *res_list; + size_t res_list_ct; + +} R_SCENE_DESC; + +#define SAGA_RESLIST_ENTRY_LEN 4 + +typedef struct R_SCENE_RESLIST_tag { + + ulong res_number; + int res_type; + + uchar *res_data; + size_t res_data_len; + +} R_SCENE_RESLIST; + +typedef struct SCENE_IMAGE_tag { + + int loaded; + + int w; + int h; + int p; + + uchar *buf; + size_t buf_len; + + uchar *res_buf; + size_t res_len; + + PALENTRY pal[256]; + +} SCENE_IMAGE; + +typedef struct SCENE_ANIMINFO_tag { + + int anim_res_number; + int anim_handle; + + struct SCENE_ANIMINFO_tag *next; + +} SCENE_ANIMINFO; + +typedef struct R_SCENE_QUEUE_tag { + + ulong scene_n; + R_SCENE_DESC *scene_desc; + int load_flag; + + R_SCENE_PROC *scene_proc; + int scene_skiptarget; + +} R_SCENE_QUEUE; + +typedef struct R_SCENE_MODULE_tag { + + int init; + + R_RSCFILE_CONTEXT *scene_ctxt; + + int *scene_lut; + int scene_count; + int scene_max; + + YS_DL_LIST *scene_queue; + + int first_scene; + + int scene_loaded; + int scene_mode; + int scene_number; + int scene_rn; + int in_game; + + int load_desc; + R_SCENE_DESC desc; + + int reslist_loaded; + int reslist_entries; + R_SCENE_RESLIST *reslist; + + int anim_entries; + YS_DL_LIST *anim_list; + + R_SCENE_PROC *scene_proc; + + R_TEXTLIST *text_list; + + SCENE_IMAGE bg; + SCENE_IMAGE bg_mask; + +} R_SCENE_MODULE; + +int SCENE_Queue(R_SCENE_QUEUE * scene_queue); +int SCENE_ClearQueue(void); + +int +SCENE_Load(int scene, + int load_flag, R_SCENE_PROC scene_proc, struct R_SCENE_DESC_tag *); + +int LoadSceneDescriptor(ulong res_number); + +int LoadSceneResourceList(ulong res_number); + +int ProcessSceneResources(void); + +void CF_scenechange(int argc, char *argv[]); + +void CF_sceneinfo(int argc, char *argv[]); + +/* + * r_sceneproc.c +\*--------------------------------------------------------------------------*/ + +int IHNM_StartProc(void); + +int InitialSceneProc(int param, R_SCENE_INFO * scene_info); +int DefaultSceneProc(int param, R_SCENE_INFO * scene_info); + +/* + * r_ite_introproc.c +\*--------------------------------------------------------------------------*/ + +int ITE_StartProc(void); +int ITE_IntroAnimProc(int param, R_SCENE_INFO * scene_info); +int ITE_IntroCave1Proc(int param, R_SCENE_INFO * scene_info); +int ITE_IntroCave2Proc(int param, R_SCENE_INFO * scene_info); +int ITE_IntroCave3Proc(int param, R_SCENE_INFO * scene_info); +int ITE_IntroCave4Proc(int param, R_SCENE_INFO * scene_info); +int ITE_IntroValleyProc(int param, R_SCENE_INFO * scene_info); +int ITE_IntroTreeHouseProc(int param, R_SCENE_INFO * scene_info); +int ITE_IntroFairePathProc(int param, R_SCENE_INFO * scene_info); +int ITE_IntroFaireTentProc(int param, R_SCENE_INFO * scene_info); + +/* + * r_ihnm_introproc.c +\*--------------------------------------------------------------------------*/ +int IHNM_StartProc(void); +int IHNM_IntroMovieProc1(int param, R_SCENE_INFO * scene_info); +int IHNM_IntroMovieProc2(int param, R_SCENE_INFO * scene_info); +int IHNM_IntroMovieProc3(int param, R_SCENE_INFO * scene_info); +int IHNM_HateProc(int param, R_SCENE_INFO * scene_info); + +} // End of namespace Saga + +#endif /* SAGA_SCENE_H_ */ diff --git a/saga/scene_mod.h b/saga/scene_mod.h new file mode 100644 index 0000000000..2a8fcc705a --- /dev/null +++ b/saga/scene_mod.h @@ -0,0 +1,103 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Scene management module public header file + + Notes: +*/ + +#ifndef SAGA_SCENE_MOD_H__ +#define SAGA_SCENE_MOD_H__ + +#include "text_mod.h" + +namespace Saga { + +/* + * r_scene.c +\*--------------------------------------------------------------------------*/ +enum R_SCENE_MODES { + + R_SCENE_MODE_INVALID, + R_SCENE_MODE_NORMAL, + R_SCENE_MODE_ISO +}; + +typedef struct SCENE_ZINFO_tag { + + int begin_slope; + int end_slope; + +} SCENE_ZINFO; + +typedef struct SCENE_BGINFO_tag { + + int bg_x; + int bg_y; + + int bg_w; + int bg_h; + int bg_p; + + uchar *bg_buf; + size_t bg_buflen; + +} SCENE_BGINFO; + +typedef struct R_SCENE_INFO_tag { + + SCENE_ZINFO z_info; + SCENE_BGINFO bg_info; + + R_TEXTLIST *text_list; + +} R_SCENE_INFO; + +typedef int (R_SCENE_PROC) (int, R_SCENE_INFO *); + +int SCENE_Register(void); +int SCENE_Init(void); +int SCENE_Shutdown(void); + +int SCENE_Start(void); +int SCENE_Next(void); +int SCENE_Skip(void); +int SCENE_End(void); + +int SCENE_Draw(R_SURFACE *); + +int SCENE_GetMode(void); +int SCENE_GetBGMaskInfo(int *w, int *h, uchar ** buf, size_t * buf_len); + +int SCENE_IsBGMaskPresent(void); +int SCENE_GetBGInfo(SCENE_BGINFO * bginfo); +int SCENE_GetZInfo(SCENE_ZINFO * zinfo); +int SCENE_GetBGPal(PALENTRY ** pal); + +int SCENE_GetInfo(R_SCENE_INFO * si); + +} // End of namespace Saga + +#endif /* SAGA_SCENE_MOD_H__ */ diff --git a/saga/sceneproc.cpp b/saga/sceneproc.cpp new file mode 100644 index 0000000000..e07c7bc741 --- /dev/null +++ b/saga/sceneproc.cpp @@ -0,0 +1,200 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Initial and default scene procedures + + Notes: +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> + +#include "reinherit.h" + +#include "yslib.h" + +/* + * Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "animation_mod.h" +#include "events_mod.h" +#include "scene_mod.h" +#include "palanim_mod.h" + +/* + * Begin module +\*--------------------------------------------------------------------------*/ +#include "scene.h" +#include "sceneproc.h" + +namespace Saga { + +int InitialSceneProc(int param, R_SCENE_INFO * scene_info) +{ + R_EVENT event = { 0 }; + R_EVENT *q_event; + + int delay_time = 0; + + static PALENTRY current_pal[R_PAL_ENTRIES]; + PALENTRY *pal; + + YS_IGNORE_PARAM(scene_info); + + switch (param) { + + case SCENE_BEGIN: + + SYSMUSIC_Stop(); + SYSSOUND_StopVoice(); + + /* Fade palette to black from intro scene + * \*----------------------------------------------------- */ + SYSGFX_GetCurrentPal(current_pal); + + event.type = R_CONTINUOUS_EVENT; + event.code = R_PAL_EVENT; + event.op = EVENT_PALTOBLACK; + event.time = 0; + event.duration = PALETTE_FADE_DURATION; + event.data = current_pal; + + delay_time += PALETTE_FADE_DURATION; + + q_event = EVENT_Queue(&event); + + /* Activate user interface + * \*----------------------------------------------------- */ + event.type = R_ONESHOT_EVENT; + event.code = R_INTERFACE_EVENT; + event.op = EVENT_ACTIVATE; + event.time = 0; + + q_event = EVENT_Chain(q_event, &event); + + /* Set first scene background w/o changing palette + * \*----------------------------------------------------- */ + event.type = R_ONESHOT_EVENT; + event.code = R_BG_EVENT; + event.op = EVENT_DISPLAY; + event.param = NO_SET_PALETTE; + event.time = 0; + + q_event = EVENT_Chain(q_event, &event); + + /* Fade in to first scene background palette + * \*----------------------------------------------------- */ + SCENE_GetBGPal(&pal); + + event.type = R_CONTINUOUS_EVENT; + event.code = R_PAL_EVENT; + event.op = EVENT_BLACKTOPAL; + event.time = delay_time; + event.duration = PALETTE_FADE_DURATION; + event.data = pal; + + q_event = EVENT_Chain(q_event, &event); + + event.code = R_PALANIM_EVENT; + event.op = EVENT_CYCLESTART; + event.time = 0; + + q_event = EVENT_Chain(q_event, &event); + + ANIM_SetFlag(0, ANIM_LOOP); + ANIM_Play(0, delay_time); + + break; + + case SCENE_END: + + break; + + default: + R_printf(R_STDERR, "Illegal scene procedure parameter.\n"); + break; + + } + + return 0; +} + +int DefaultSceneProc(int param, R_SCENE_INFO * scene_info) +{ + + R_EVENT event; + + YS_IGNORE_PARAM(scene_info); + + switch (param) { + + case SCENE_BEGIN: + + /* Set scene background + * \*----------------------------------------------------- */ + event.type = R_ONESHOT_EVENT; + event.code = R_BG_EVENT; + event.op = EVENT_DISPLAY; + event.param = SET_PALETTE; + event.time = 0; + + EVENT_Queue(&event); + + /* Activate user interface + * \*----------------------------------------------------- */ + event.type = R_ONESHOT_EVENT; + event.code = R_INTERFACE_EVENT; + event.op = EVENT_ACTIVATE; + event.time = 0; + + EVENT_Queue(&event); + + /* Begin palette cycle animation if present + * \*----------------------------------------------------- */ + event.type = R_ONESHOT_EVENT; + event.code = R_PALANIM_EVENT; + event.op = EVENT_CYCLESTART; + event.time = 0; + + EVENT_Queue(&event); + + break; + + case SCENE_END: + + break; + + default: + R_printf(R_STDERR, "Illegal scene procedure parameter.\n"); + break; + + } + + return 0; +} + +} // End of namespace Saga + diff --git a/saga/sceneproc.h b/saga/sceneproc.h new file mode 100644 index 0000000000..53e36ad687 --- /dev/null +++ b/saga/sceneproc.h @@ -0,0 +1,40 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Initial and default scene procedures header file + + Notes: +*/ + +#ifndef SAGA_SCENEPROC_H +#define SAGA_SCENEPROC_H + +namespace Saga { + +#define PALETTE_FADE_DURATION 1000 + +} // End of namespace Saga + +#endif diff --git a/saga/script.cpp b/saga/script.cpp new file mode 100644 index 0000000000..4c84a9e069 --- /dev/null +++ b/saga/script.cpp @@ -0,0 +1,684 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Scripting module: Script resource handling functions + + Notes: +*/ + +#include "reinherit.h" + +#include "yslib.h" + +/* + * Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "rscfile_mod.h" +#include "game_mod.h" +#include "text_mod.h" +#include "console_mod.h" +#include "cvar_mod.h" + +/* + * Begin module component +\*--------------------------------------------------------------------------*/ +#include "script_mod.h" +#include "script.h" +#include "sstack.h" +#include "sthread.h" + +namespace Saga { + +R_SCRIPT_MODULE ScriptModule; + +int SCRIPT_Register(void) +{ + + CVAR_RegisterFunc(CF_script_info, + "script_info", NULL, R_CVAR_NONE, 0, 0); + + CVAR_RegisterFunc(CF_script_exec, + "script_exec", "<Script number>", R_CVAR_NONE, 1, 1); + + CVAR_RegisterFunc(CF_script_togglestep, + "script_togglestep", NULL, R_CVAR_NONE, 0, 0); + + return R_SUCCESS; +} + +int SCRIPT_Init(void) +/*--------------------------------------------------------------------------*\ + * Initializes the scripting module. + * Loads script resource look-up table, initializes script data system +\*--------------------------------------------------------------------------*/ +{ + R_RSCFILE_CONTEXT *s_lut_ctxt; + + uchar *rsc_ptr; + size_t rsc_len; + + const uchar *read_ptr; + const uchar *read_ptr2; + + int result; + int i; + + R_printf(R_STDOUT, "Initializing scripting subsystem.\n"); + + /* Load script resource file context + * \*---------------------------------------------------------------------- */ + result = GAME_GetFileContext(&ScriptModule.script_ctxt, + R_GAME_SCRIPTFILE, 0); + if (result != R_SUCCESS) { + + R_printf(R_STDERR, "Couldn't get script file context.\n"); + + return R_FAILURE; + } + + /* Load script LUT resource + * \*---------------------------------------------------------------------- */ + result = GAME_GetFileContext(&s_lut_ctxt, R_GAME_RESOURCEFILE, 0); + if (result != R_SUCCESS) { + + R_printf(R_STDERR, "Couldn't get resource file context.\n"); + + return R_FAILURE; + } + + result = RSC_LoadResource(s_lut_ctxt, + ITE_SCRIPT_LUT, &rsc_ptr, &rsc_len); + if (result != R_SUCCESS) { + + R_printf(R_STDERR, + "Error: Couldn't load script resource look-up table.\n"); + + return R_FAILURE; + } + + /* Create logical script LUT from resource + * \*---------------------------------------------------------------------- */ + if (rsc_len % R_S_LUT_ENTRYLEN_ITECD == 0) { + + ScriptModule.script_lut_entrylen = R_S_LUT_ENTRYLEN_ITECD; + } else if (rsc_len % R_S_LUT_ENTRYLEN_ITEDISK == 0) { + + ScriptModule.script_lut_entrylen = R_S_LUT_ENTRYLEN_ITEDISK; + } else { + R_printf(R_STDERR, + "Error: Invalid script lookup table length.\n"); + return R_FAILURE; + } + + /* Calculate number of entries */ + ScriptModule.script_lut_max = + rsc_len / ScriptModule.script_lut_entrylen; + + /* Allocate space for logical LUT */ + ScriptModule.script_lut = (R_SCRIPT_LUT_ENTRY *)malloc(ScriptModule.script_lut_max * + sizeof(R_SCRIPT_LUT_ENTRY)); + if (ScriptModule.script_lut == NULL) { + R_printf(R_STDERR, + "Error: Couldn't allocate memory for script resource " + "look-up table.\n"); + return R_MEM; + } + + /* Convert LUT resource to logical LUT */ + read_ptr = rsc_ptr; + for (i = 0; i < ScriptModule.script_lut_max; i++) { + + read_ptr2 = read_ptr; + + ScriptModule.script_lut[i].script_rn = + ys_read_u16_le(read_ptr2, &read_ptr2); + + ScriptModule.script_lut[i].diag_list_rn = + ys_read_u16_le(read_ptr2, &read_ptr2); + + ScriptModule.script_lut[i].voice_lut_rn = + ys_read_u16_le(read_ptr2, &read_ptr2); + + /* Skip the unused portion of the structure */ + read_ptr += ScriptModule.script_lut_entrylen; + } + + RSC_FreeResource(rsc_ptr); + + /* Any voice lookup table resources present? */ + for (i = 0; i < ScriptModule.script_lut_max; i++) { + + if (ScriptModule.script_lut[i].voice_lut_rn) { + + ScriptModule.voice_lut_present = 1; + break; + } + } + + /* Initialize script submodules + * \*---------------------------------------------------------------------- */ + ScriptModule.thread_list = ys_dll_create(); + + if (SDATA_Init() != R_SUCCESS) { + free(ScriptModule.script_lut); + return R_FAILURE; + } + + ScriptModule.initialized = 1; + return R_SUCCESS; +} + +int SCRIPT_Shutdown(void) +/*--------------------------------------------------------------------------*\ + * Shut down script module gracefully; free all allocated module resources +\*--------------------------------------------------------------------------*/ +{ + YS_DL_NODE *thread_node; + R_SCRIPT_THREAD *thread; + + if (!ScriptModule.initialized) { + + return R_FAILURE; + } + + R_printf(R_STDOUT, "Shutting down scripting subsystem.\n"); + + /* Free script lookup table */ + free(ScriptModule.script_lut); + + /* Stop all threads and destroy them */ + + for (thread_node = ys_dll_head(ScriptModule.thread_list); + thread_node != NULL; thread_node = ys_dll_next(thread_node)) { + + thread = (R_SCRIPT_THREAD *)ys_dll_get_data(thread_node); + + STHREAD_Destroy(thread); + } + + ScriptModule.initialized = 0; + + return R_SUCCESS; +} + +int SCRIPT_Load(int script_num) +/*--------------------------------------------------------------------------*\ + * Loads a script; including script bytecode and dialogue list +\*--------------------------------------------------------------------------*/ +{ + + R_SCRIPTDATA *script_data; + + uchar *bytecode_p; + size_t bytecode_len; + ulong scriptl_rn; + + uchar *diagl_p; + size_t diagl_len; + ulong diagl_rn; + + uchar *voicelut_p; + size_t voicelut_len; + ulong voicelut_rn; + + int result; + + if (GAME_GetGameType() == R_GAMETYPE_IHNM) { + return R_SUCCESS; + } + + /* Validate script number */ + if ((script_num < 0) || (script_num > ScriptModule.script_lut_max)) { + R_printf(R_STDERR, "SCRIPT_Load(): Invalid script number!\n"); + return R_FAILURE; + } + + /* Release old script data if present */ + SCRIPT_Free(); + + /* Initialize script data structure + * \*---------------------------------------------------------------------- */ + R_printf(R_STDOUT, "Loading script data for script #%d.\n", + script_num); + + script_data = (R_SCRIPTDATA *)malloc(sizeof *script_data); + if (script_data == NULL) { + R_printf(R_STDERR, "Memory allocation failed.\n"); + return R_MEM; + } + + script_data->loaded = 0; + + /* Initialize script pointers */ + script_data->diag = NULL; + script_data->bytecode = NULL; + script_data->voice = NULL; + + /* Load script bytecode + * \*---------------------------------------------------------------------- */ + scriptl_rn = ScriptModule.script_lut[script_num].script_rn; + + result = RSC_LoadResource(ScriptModule.script_ctxt, + scriptl_rn, &bytecode_p, &bytecode_len); + if (result != R_SUCCESS) { + R_printf(R_STDERR, + "Error loading script bytecode resource.\n"); + free(script_data); + return R_FAILURE; + } + + script_data->bytecode = SCRIPT_LoadBytecode(bytecode_p, bytecode_len); + + if (script_data->bytecode == NULL) { + R_printf(R_STDERR, + "Error interpreting script bytecode resource.\n"); + free(script_data); + RSC_FreeResource(bytecode_p); + return R_FAILURE; + } + + /* Load script dialogue list + * \*---------------------------------------------------------------------- */ + diagl_rn = ScriptModule.script_lut[script_num].diag_list_rn; + + /* Load dialogue list resource */ + result = RSC_LoadResource(ScriptModule.script_ctxt, + diagl_rn, &diagl_p, &diagl_len); + if (result != R_SUCCESS) { + R_printf(R_STDERR, "Error loading dialogue list resource.\n"); + free(script_data); + RSC_FreeResource(bytecode_p); + return R_FAILURE; + } + + /* Convert dialogue list resource to logical dialogue list */ + script_data->diag = SCRIPT_LoadDialogue(diagl_p, diagl_len); + if (script_data->diag == NULL) { + R_printf(R_STDERR, + "Error interpreting dialogue list resource.\n"); + free(script_data); + RSC_FreeResource(bytecode_p); + RSC_FreeResource(diagl_p); + return R_FAILURE; + } + + /* Load voice resource lookup table + * \*---------------------------------------------------------------------- */ + if (ScriptModule.voice_lut_present) { + + voicelut_rn = ScriptModule.script_lut[script_num].voice_lut_rn; + + /* Load voice LUT resource */ + result = RSC_LoadResource(ScriptModule.script_ctxt, + voicelut_rn, &voicelut_p, &voicelut_len); + if (result != R_SUCCESS) { + + R_printf(R_STDERR, + "Error loading voice LUT resource.\n"); + + free(script_data); + RSC_FreeResource(bytecode_p); + RSC_FreeResource(diagl_p); + + return R_FAILURE; + } + + /* Convert voice LUT resource to logical voice LUT */ + script_data->voice = SCRIPT_LoadVoiceLUT(voicelut_p, + voicelut_len, script_data); + if (script_data->voice == NULL) { + R_printf(R_STDERR, + "Error interpreting voice LUT resource.\n"); + + free(script_data); + RSC_FreeResource(bytecode_p); + RSC_FreeResource(diagl_p); + RSC_FreeResource(voicelut_p); + + return R_FAILURE; + } + + } + + /* Finish initialization + * \*---------------------------------------------------------------------- */ + script_data->loaded = 1; + ScriptModule.current_script = script_data; + + return R_SUCCESS; +} + +int SCRIPT_Free(void) +/*--------------------------------------------------------------------------*\ + * Frees all resources associated with current script. +\*--------------------------------------------------------------------------*/ +{ + + if (ScriptModule.current_script == NULL) { + return R_FAILURE; + } + + if (!ScriptModule.current_script->loaded) { + return R_FAILURE; + } + + R_printf(R_STDOUT, "Releasing script data.\n"); + + /* Finish initialization + * \*---------------------------------------------------------------------- */ + if (ScriptModule.current_script->diag != NULL) { + free(ScriptModule.current_script->diag->str); + free(ScriptModule.current_script->diag->str_off); + } + free(ScriptModule.current_script->diag); + + if (ScriptModule.current_script->bytecode != NULL) { + free(ScriptModule.current_script->bytecode->entrypoints); + RSC_FreeResource(ScriptModule.current_script->bytecode-> + bytecode_p); + } + + free(ScriptModule.current_script->bytecode); + + if (ScriptModule.voice_lut_present) { + free(ScriptModule.current_script->voice->voices); + free(ScriptModule.current_script->voice); + } + + free(ScriptModule.current_script); + + ScriptModule.current_script = NULL; + + return R_SUCCESS; +} + +R_SCRIPT_BYTECODE *SCRIPT_LoadBytecode(const uchar * bytecode_p, + size_t bytecode_len) +/*--------------------------------------------------------------------------*\ + * Reads the entrypoint table from a script bytecode resource in memory. + * Returns NULL on failure. +\*--------------------------------------------------------------------------*/ +{ + + const uchar *read_p = bytecode_p; + R_PROC_TBLENTRY *bc_ep_tbl = NULL; + R_SCRIPT_BYTECODE *bc_new_data = NULL; + + unsigned long n_entrypoints; /* Number of entrypoints */ + size_t ep_tbl_offset; /* Offset of bytecode entrypoint table */ + + unsigned long i; + + R_printf(R_STDOUT, "Loading script bytecode...\n"); + + /* The first two uint32 values are the number of entrypoints, and the + * offset to the entrypoint table, respectively. */ + + n_entrypoints = ys_read_u32_le(read_p, &read_p); + ep_tbl_offset = ys_read_u32_le(read_p, &read_p); + + /* Check that the entrypoint table offset is valid. */ + if ((bytecode_len - ep_tbl_offset) < + (n_entrypoints * R_SCRIPT_TBLENTRY_LEN)) { + + R_printf(R_STDERR, "Invalid table offset.\n"); + return NULL; + } + + if (n_entrypoints > R_SCRIPT_MAX) { + R_printf(R_STDERR, "Script limit exceeded.\n"); + return NULL; + } + + /* Allocate a new bytecode resource information structure and table of + * entrypoints */ + + bc_new_data = (R_SCRIPT_BYTECODE *)malloc(sizeof *bc_new_data); + if (bc_new_data == NULL) { + R_printf(R_STDERR, + "Memory allocation failure loading script bytecode.\n"); + return NULL; + } + + bc_ep_tbl = (R_PROC_TBLENTRY *)malloc(n_entrypoints * sizeof *bc_ep_tbl); + if (bc_ep_tbl == NULL) { + R_printf(R_STDERR, + "Memory allocation failure creating script entrypoint table.\n"); + free(bc_new_data); + return NULL; + } + + /* Read in the entrypoint table */ + + read_p = bytecode_p + ep_tbl_offset; + + for (i = 0; i < n_entrypoints; i++) { + /* First uint16 is the offset of the entrypoint name from the start + * of the bytecode resource, second uint16 is the offset of the + * bytecode itself for said entrypoint */ + bc_ep_tbl[i].name_offset = ys_read_u16_le(read_p, &read_p); + bc_ep_tbl[i].offset = ys_read_u16_le(read_p, &read_p); + + /* Perform a simple range check on offset values */ + if ((bc_ep_tbl[i].name_offset > bytecode_len) || + (bc_ep_tbl[i].offset > bytecode_len)) { + + R_printf(R_STDERR, + "Invalid offset encountered in script entrypoint table.\n"); + free(bc_new_data); + free(bc_ep_tbl); + return NULL; + } + } + + bc_new_data->bytecode_p = (uchar *) bytecode_p; + bc_new_data->bytecode_len = bytecode_len; + + bc_new_data->n_entrypoints = n_entrypoints; + bc_new_data->entrypoints = bc_ep_tbl; + bc_new_data->ep_tbl_offset = ep_tbl_offset; + + return bc_new_data; +} + +R_DIALOGUE_LIST *SCRIPT_LoadDialogue(const uchar * dialogue_p, + size_t dialogue_len) +/*--------------------------------------------------------------------------*\ + * Reads a logical dialogue list from a dialogue list resource in memory. + * Returns NULL on failure. +\*--------------------------------------------------------------------------*/ +{ + const uchar *read_p = dialogue_p; + + R_DIALOGUE_LIST *dialogue_list; + uint n_dialogue; + + uint i; + size_t offset; + + R_printf(R_STDOUT, "Loading dialogue list...\n"); + + /* Allocate dialogue list structure */ + dialogue_list = (R_DIALOGUE_LIST *)malloc(sizeof *dialogue_list); + if (dialogue_list == NULL) { + return NULL; + } + + /* First uint16 is the offset of the first string */ + offset = ys_read_u16_le(read_p, &read_p); + if (offset > dialogue_len) { + R_printf(R_STDERR, "Error, invalid string offset.\n"); + return NULL; + } + + /* Calculate table length */ + n_dialogue = offset / 2; + dialogue_list->n_dialogue = n_dialogue; + + /* Allocate table of string pointers */ + dialogue_list->str = (char **)malloc(n_dialogue * sizeof(char *)); + if (dialogue_list->str == NULL) { + free(dialogue_list); + return NULL; + } + + /* Allocate table of string offsets */ + dialogue_list->str_off = (size_t *)malloc(n_dialogue * sizeof(size_t)); + if (dialogue_list->str_off == NULL) { + free(dialogue_list->str); + free(dialogue_list); + return NULL; + } + + /* Read in tables from dialogue list resource */ + read_p = dialogue_p; + for (i = 0; i < n_dialogue; i++) { + offset = ys_read_u16_le(read_p, &read_p); + + if (offset > dialogue_len) { + R_printf(R_STDERR, "Error, invalid string offset.\n"); + free(dialogue_list->str); + free(dialogue_list->str_off); + free(dialogue_list); + return NULL; + } + dialogue_list->str[i] = (char *)dialogue_p + offset; + dialogue_list->str_off[i] = offset; + } + + return dialogue_list; +} + +R_VOICE_LUT *SCRIPT_LoadVoiceLUT(const uchar * voicelut_p, + size_t voicelut_len, R_SCRIPTDATA * script) +/*--------------------------------------------------------------------------*\ + * Reads a logical voice LUT from a voice LUT resource in memory. + * Returns NULL on failure. +\*--------------------------------------------------------------------------*/ +{ + const uchar *read_p = voicelut_p; + + R_VOICE_LUT *voice_lut; + + uint n_voices; + uint i; + + voice_lut = (R_VOICE_LUT *)malloc(sizeof *voice_lut); + if (voice_lut == NULL) { + return NULL; + } + + n_voices = voicelut_len / 2; + if (n_voices != script->diag->n_dialogue) { + R_printf(R_STDERR, "Error: Voice LUT entries do not match " + "dialogue entries.\n"); + return NULL; + } + + voice_lut->voices = (int *)malloc(n_voices * sizeof *voice_lut->voices); + if (voice_lut->voices == NULL) { + + return NULL; + } + + for (i = 0; i < n_voices; i++) { + + voice_lut->voices[i] = ys_read_u16_le(read_p, &read_p); + } + + return voice_lut; +} + +void CF_script_info(int argc, char *argv[]) +{ + + ulong n_entrypoints; + ulong i; + char *name_ptr; + + if (ScriptModule.current_script == NULL) { + return; + } + + if (!ScriptModule.current_script->loaded) { + return; + } + + n_entrypoints = ScriptModule.current_script->bytecode->n_entrypoints; + + CON_Print("Current script contains %d entrypoints:", n_entrypoints); + + for (i = 0; i < n_entrypoints; i++) { + name_ptr = (char *) + ScriptModule.current_script->bytecode->bytecode_p + + ScriptModule.current_script->bytecode->entrypoints[i]. + name_offset; + + CON_Print("%lu: %s", i, name_ptr); + } + + return; +} + +void CF_script_exec(int argc, char *argv[]) +{ + uint ep_num; + + if (argc < 1) { + return; + } + + ep_num = atoi(argv[0]); + + if (ScriptModule.dbg_thread == NULL) { + + CON_Print("Creating debug thread..."); + ScriptModule.dbg_thread = STHREAD_Create(); + + if (ScriptModule.dbg_thread == NULL) { + CON_Print("Thread creation failed."); + return; + } + } + + if (ep_num >= ScriptModule.current_script->bytecode->n_entrypoints) { + CON_Print("Invalid entrypoint."); + return; + } + + STHREAD_Execute(ScriptModule.dbg_thread, ep_num); + + return; +} + +void CF_script_togglestep(int argc, char *argv[]) +{ + ScriptModule.dbg_singlestep = !ScriptModule.dbg_singlestep; + + return; +} + +} // End of namespace Saga diff --git a/saga/script.h b/saga/script.h new file mode 100644 index 0000000000..bff544e636 --- /dev/null +++ b/saga/script.h @@ -0,0 +1,157 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Scripting module private header + + Notes: +*/ + +#ifndef SAGA_SCRIPT_H +#define SAGA_SCRIPT_H + +#include "sstack.h" +#include "sdata.h" + +namespace Saga { + +#define R_S_LUT_ENTRYLEN_ITECD 22 +#define R_S_LUT_ENTRYLEN_ITEDISK 16 + +#define R_SCRIPT_TBLENTRY_LEN 4 + +#define R_SCRIPT_MAX 5000 +#define R_SCRIPTLIST_HDR 12 +#define R_SCRIPT_STRINGLIMIT 255 +#define R_TAB " " + +#define R_DEF_THREAD_STACKSIZE 16 + +#define S_ERROR_PREFIX "SError: " +#define S_WARN_PREFIX "SWarning: " + +typedef struct R_PROC_TBLENTRY_tag { + + size_t name_offset; + size_t offset; + +} R_PROC_TBLENTRY; + +typedef struct R_SCRIPT_BYTECODE_tag { + + unsigned char *bytecode_p; + size_t bytecode_len; + + size_t ep_tbl_offset; + unsigned long n_entrypoints; + R_PROC_TBLENTRY *entrypoints; + +} R_SCRIPT_BYTECODE; + +typedef struct R_DIALOGUE_LIST_tag { + + unsigned int n_dialogue; + char **str; + size_t *str_off; + +} R_DIALOGUE_LIST; + +typedef struct R_VOICE_LUT_tag { + + int n_voices; + int *voices; + +} R_VOICE_LUT; + +typedef struct R_SCRIPTDATA_tag { + + int loaded; + R_SCRIPT_BYTECODE *bytecode; + R_DIALOGUE_LIST *diag; + R_VOICE_LUT *voice; + +} R_SCRIPTDATA; + +typedef struct R_SCRIPT_LUT_ENTRY_tag { + + int script_rn; + int diag_list_rn; + int voice_lut_rn; + +} R_SCRIPT_LUT_ENTRY; + +typedef struct R_SCRIPT_DATABUF_tag { + + SDataWord_T *data; + int len; + +} R_SCRIPT_DATABUF; + +typedef struct R_SCRIPT_MODULE_tag { + + int initialized; + + R_RSCFILE_CONTEXT *script_ctxt; + + int voice_lut_present; + R_SCRIPT_LUT_ENTRY *script_lut; + int script_lut_max; + uint script_lut_entrylen; + + R_SCRIPTDATA *current_script; + YS_DL_LIST *thread_list; + R_SCRIPT_DATABUF *data_buf[R_SCRIPT_DATABUF_NUM]; + + int dbg_singlestep; + int dbg_dostep; + R_SCRIPT_THREAD *dbg_thread; + R_TEXTLIST_ENTRY *dbg_txtentry; + +} R_SCRIPT_MODULE; + +extern R_SCRIPT_MODULE ScriptModule; + +R_SCRIPT_BYTECODE *SCRIPT_LoadBytecode(const uchar * bytecode_p, + size_t bytecode_len); + +R_DIALOGUE_LIST *SCRIPT_LoadDialogue(const uchar * dialogue_p, + size_t dialogue_len); + +R_VOICE_LUT *SCRIPT_LoadVoiceLUT(const uchar * voicelut_p, + size_t voicelut_len, R_SCRIPTDATA * script); + +int +SCRIPT_Disassemble(R_SCRIPT_BYTECODE * script_list, + R_DIALOGUE_LIST * diag_list); + +void CF_script_info(int argc, char *argv[]); + +void CF_script_exec(int argc, char *argv[]); + +void CF_script_togglestep(int argc, char *argv[]); + +} // End of namespace Saga + +#endif diff --git a/saga/script_mod.h b/saga/script_mod.h new file mode 100644 index 0000000000..ec824e6ce2 --- /dev/null +++ b/saga/script_mod.h @@ -0,0 +1,89 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Scripting module public header + + Notes: +*/ + +#ifndef SAGA_SCRIPT_MOD_H +#define SAGA_SCRIPT_MOD_H + +namespace Saga { + +typedef unsigned int SDataWord_T; + +typedef struct R_SCRIPT_THREAD_tag R_SCRIPT_THREAD; + +enum R_SCRIPT_VERBS { + + S_VERB_WALKTO = 0, + S_VERB_LOOKAT = 2, + S_VERB_PICKUP = 1, + S_VERB_TALKTO, + S_VERB_OPEN = 5, + S_VERB_CLOSE = 6, + S_VERB_USE = 8, + S_VERB_GIVE +}; + +int SCRIPT_Register(void); + +int SCRIPT_Init(void); + +int SCRIPT_Shutdown(void); + +int SCRIPT_Load(int script_num); + +int SCRIPT_Free(void); + +int SDATA_GetWord(int n_buf, int n_word, SDataWord_T * data); + +int SDATA_PutWord(int n_buf, int n_word, SDataWord_T data); + +int SDATA_SetBit(int n_buf, SDataWord_T n_bit, int bitstate); + +int SDATA_GetBit(int n_buf, SDataWord_T n_bit, int *bitstate); + +int SDATA_ReadWordS(SDataWord_T word); + +uint SDATA_ReadWordU(SDataWord_T word); + +R_SCRIPT_THREAD *STHREAD_Create(void); + +int STHREAD_Execute(R_SCRIPT_THREAD * thread, int ep_num); + +int STHREAD_ExecThreads(int msec); + +int STHREAD_HoldSem(R_SEMAPHORE * sem); + +int STHREAD_ReleaseSem(R_SEMAPHORE * sem); + +int STHREAD_DebugStep(void); + +} // End of namespace Saga + +#endif /* SAGA_SCRIPT_MOD_H */ diff --git a/saga/sdata.cpp b/saga/sdata.cpp new file mode 100644 index 0000000000..7ab9e4c056 --- /dev/null +++ b/saga/sdata.cpp @@ -0,0 +1,210 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Scripting module data management component + + Notes: + + Type SDataWord_T must be unpadded +*/ + +#include "reinherit.h" + +#include "yslib.h" + +#include <limits.h> + +/* + * Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "text_mod.h" + +/* + * Begin module component +\*--------------------------------------------------------------------------*/ +#include "script_mod.h" +#include "script.h" +#include "sdata.h" + +namespace Saga { + +int SDATA_Init(void) +{ + + unsigned int i; + void *alloc_ptr; + + R_printf(R_STDOUT, "Initializing script data buffers.\n"); + + for (i = 0; i < R_SCRIPT_DATABUF_NUM; i++) { + + alloc_ptr = malloc(sizeof *ScriptModule.data_buf[0]); + + if (alloc_ptr == NULL) { + R_printf(R_STDERR, + "Error allocating memory for script data buffer %d.\n", + i); + return R_MEM; + } + + ScriptModule.data_buf[i] = (R_SCRIPT_DATABUF *)alloc_ptr; + + alloc_ptr = calloc(R_SCRIPT_DATABUF_LEN, sizeof(SDataWord_T)); + + if (alloc_ptr == NULL) { + R_printf(R_STDERR, + "Error allocating memory for script data buffer %d.\n", + i); + return R_MEM; + } + + ScriptModule.data_buf[i]->len = R_SCRIPT_DATABUF_LEN; + ScriptModule.data_buf[i]->data = (SDataWord_T *)alloc_ptr; + } + + return R_SUCCESS; +} + +int SDATA_GetWord(int n_buf, int n_word, SDataWord_T * data) +{ + + if ((n_buf < 0) || (n_buf >= R_SCRIPT_DATABUF_NUM)) { + return R_FAILURE; + } + + if ((n_word < 0) || (n_word >= ScriptModule.data_buf[n_buf]->len)) { + return R_FAILURE; + } + + if (data == NULL) { + return R_FAILURE; + } + + *data = ScriptModule.data_buf[n_buf]->data[n_word]; + + return R_SUCCESS; +} + +int SDATA_PutWord(int n_buf, int n_word, SDataWord_T data) +{ + + if ((n_buf < 0) || (n_buf >= R_SCRIPT_DATABUF_NUM)) { + return R_FAILURE; + } + + if ((n_word < 0) || (n_word >= ScriptModule.data_buf[n_buf]->len)) { + return R_FAILURE; + } + + ScriptModule.data_buf[n_buf]->data[n_word] = data; + + return R_SUCCESS; +} + +int SDATA_SetBit(int n_buf, SDataWord_T n_bit, int bitstate) +{ + + int n_word; + int n_bitpos; + + SDataWord_T bit_pattern = 0x01; + + if ((n_buf < 0) || (n_buf >= R_SCRIPT_DATABUF_NUM)) { + return R_FAILURE; + } + + if (n_bit >= (unsigned long)ScriptModule.data_buf[n_buf]->len * + (sizeof(SDataWord_T) * CHAR_BIT)) { + + return R_FAILURE; + } + + n_word = n_bit / (sizeof(SDataWord_T) * CHAR_BIT); + n_bitpos = n_bit % (sizeof(SDataWord_T) * CHAR_BIT); + + bit_pattern <<= ((sizeof(SDataWord_T) * CHAR_BIT) - (n_bitpos + 1)); + + if (bitstate) { + ScriptModule.data_buf[n_buf]->data[n_word] |= bit_pattern; + } else { + ScriptModule.data_buf[n_buf]->data[n_word] &= ~bit_pattern; + } + + return R_SUCCESS; +} + +int SDATA_GetBit(int n_buf, SDataWord_T n_bit, int *bitstate) +{ + + int n_word; + int n_bitpos; + + SDataWord_T bit_pattern = 0x01; + + if ((n_buf < 0) || (n_buf >= R_SCRIPT_DATABUF_NUM)) { + + return R_FAILURE; + } + + if (n_bit >= (SDataWord_T) ScriptModule.data_buf[n_buf]->len * + (sizeof(SDataWord_T) * CHAR_BIT)) { + + return R_FAILURE; + } + + n_word = n_bit / (sizeof(SDataWord_T) * CHAR_BIT); + n_bitpos = n_bit % (sizeof(SDataWord_T) * CHAR_BIT); + + bit_pattern <<= ((sizeof(SDataWord_T) * CHAR_BIT) - (n_bitpos + 1)); + + *bitstate = (ScriptModule.data_buf[n_buf]->data[n_word] & + bit_pattern) ? 1 : 0; + + return R_SUCCESS; +} + +int SDATA_ReadWordS(SDataWord_T word) +{ + uint u_int = word; + int s_int; + + if (u_int & 0x8000U) { + s_int = (int)(u_int - 0x8000U) - 0x7FFF - 1; + } else { + s_int = u_int; + } + + return s_int; +} + +uint SDATA_ReadWordU(SDataWord_T word) +{ + uint u_int = (uint) word; + + return u_int; +} + +} // End of namespace Saga diff --git a/saga/sdata.h b/saga/sdata.h new file mode 100644 index 0000000000..3c9805de45 --- /dev/null +++ b/saga/sdata.h @@ -0,0 +1,44 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Scripting module data management component header file + + Notes: +*/ + +#ifndef SAGA_SDATA_H +#define SAGA_SDATA_H + +namespace Saga { + +#define R_SCRIPT_DATABUF_NUM 5U +#define R_SCRIPT_DATABUF_LEN 1024U + +int SDATA_Init(void); + +} // End of namespace Saga + +#endif /* SAGA_SDATA_H */ diff --git a/saga/sdebug.cpp b/saga/sdebug.cpp new file mode 100644 index 0000000000..fa8986238e --- /dev/null +++ b/saga/sdebug.cpp @@ -0,0 +1,658 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Scripting module simple thread debugging support + + Notes: +*/ + +#include "reinherit.h" + +#include "yslib.h" + +/* + * Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "actor_mod.h" +#include "console_mod.h" +#include "text_mod.h" +#include "scene_mod.h" +#include "font_mod.h" + +/* + * Begin module component +\*--------------------------------------------------------------------------*/ +#include "script.h" +#include "sthread.h" + +namespace Saga { + +#define SD_DISPLAY_LEN 128 + +#define SD_ADDTXT( x ) strncat( disp_buf, x, SD_DISPLAY_LEN ); + +int SDEBUG_PrintInstr(R_SCRIPT_THREAD * thread) +{ + + R_TEXTLIST_ENTRY tl_e; + + const uchar *start_p; + const uchar *read_p; + + char tmp_buf[80] = { 0 }; + static char disp_buf[SD_DISPLAY_LEN] = { 0 }; + + int in_char; + /*int op_offset; */ + + int n_switch; + int i; + + R_SCENE_INFO si; + + SCENE_GetInfo(&si); + + disp_buf[0] = 0; + + if (ScriptModule.dbg_txtentry != NULL) { + + TEXT_DeleteEntry(si.text_list, ScriptModule.dbg_txtentry); + ScriptModule.dbg_txtentry = NULL; + } + + tl_e.color = 1; + tl_e.effect_color = 0; + tl_e.text_x = 2; + tl_e.text_y = 20; + tl_e.font_id = SMALL_FONT_ID; + tl_e.flags = FONT_OUTLINE; + tl_e.string = disp_buf; + tl_e.display = 1; + + read_p = ScriptModule.current_script->bytecode->bytecode_p + + thread->i_offset; + + start_p = read_p; + + in_char = ys_read_u8(read_p, &read_p); + + sprintf(tmp_buf, "%04lX | %02X | ", thread->i_offset, in_char); + strncat(disp_buf, tmp_buf, SD_DISPLAY_LEN); + + switch (in_char) { + + /* Align */ + case 0x01: + + SD_ADDTXT("ALGN |"); + break; + + /* Push nothing */ + case 0x02: + + SD_ADDTXT("PSHN |"); + break; + + /* Pop nothing */ + case 0x03: + + SD_ADDTXT("POPN |"); + break; + + /* Push false (0) */ + case 0x04: + + SD_ADDTXT("PSHF |"); + break; + + /* Push true (1) */ + case 0x05: + + SD_ADDTXT("PSHT |"); + break; + + /* Push word (dialogue string index) */ + case 0x08: + { + int param; + + SD_ADDTXT("PSHD | "); + + param = ys_read_u16_le(read_p, &read_p); + sprintf(tmp_buf, "%02X", param); + SD_ADDTXT(tmp_buf); +/* + if(( param >= 0 ) && ( param < diag_list->n_dialogue )) { + printf(" ; \"%.*s\"", R_SCRIPT_STRINGLIMIT, diag_list->str[param] ); + } + else { + printf(" ; Invalid dialogue string.\n" ); + } +*/ + } + break; + + /* Push word */ + case 0x06: + { + int param; + + SD_ADDTXT("PUSH | "); + param = ys_read_u16_le(read_p, &read_p); + sprintf(tmp_buf, "%04X", param); + SD_ADDTXT(tmp_buf); + } + break; + + /* Test flag */ + case 0x0B: + { + int param1; + int param2; + + SD_ADDTXT("TSTF | "); + param1 = *read_p++; + param2 = ys_read_u16_le(read_p, &read_p); + + sprintf(tmp_buf, "%02X %04X", param1, param2); + SD_ADDTXT(tmp_buf); + } + break; + + /* Get word */ + case 0x0C: + { + int param1; + int param2; + + SD_ADDTXT("GETW | "); + param1 = *read_p++; + param2 = ys_read_u16_le(read_p, &read_p); + + sprintf(tmp_buf, "%02X %04X", param1, param2); + SD_ADDTXT(tmp_buf); + } + break; + + /* Modify flag */ + case 0x0F: + { + int param1; + int param2; + + SD_ADDTXT("MODF | "); + param1 = *read_p++; + param2 = ys_read_u16_le(read_p, &read_p); + + sprintf(tmp_buf, "%02X %04X", param1, param2); + SD_ADDTXT(tmp_buf); + } + break; + + /* Put word */ + case 0x10: + { + int param1; + int param2; + + SD_ADDTXT("PUTW | "); + param1 = *read_p++; + param2 = ys_read_u16_le(read_p, &read_p); + + sprintf(tmp_buf, "%02X %04X", param1, param2); + SD_ADDTXT(tmp_buf); + } + break; + + /* Modify flag and pop */ + case 0x13: + { + int param1; + int param2; + + SD_ADDTXT("MDFP | "); + param1 = *read_p++; + param2 = ys_read_u16_le(read_p, &read_p); + + sprintf(tmp_buf, "%02X %04X", param1, param2); + SD_ADDTXT(tmp_buf); + } + break; + + /* Put word and pop */ + case 0x14: + { + int param1; + int param2; + + SD_ADDTXT("PTWP | "); + param1 = *read_p++; + param2 = ys_read_u16_le(read_p, &read_p); + + sprintf(tmp_buf, "%02X %04X", param1, param2); + SD_ADDTXT(tmp_buf); + } + break; + + /* Call subscript ? */ + case 0x17: + { + int param1; + int param2; + int param3; + + SD_ADDTXT("GOSB | "); + param1 = *read_p++; + param2 = *read_p++; + param3 = ys_read_u16_le(read_p, &read_p); + + sprintf(tmp_buf, "%02X %02X %04X", param1, param2, + param3); + SD_ADDTXT(tmp_buf); + } + break; + + /* Call function */ + case 0x19: + case 0x18: + { + int func_num; + int param; + + SD_ADDTXT("CALL | "); + + func_num = *read_p++; + sprintf(tmp_buf, "%02X ", func_num); + SD_ADDTXT(tmp_buf); + + param = ys_read_u16_le(read_p, &read_p); + sprintf(tmp_buf, "%04X ", param); + SD_ADDTXT(tmp_buf); + } + break; + + /* Begin subscript */ + case 0x1A: + { + int param; + + SD_ADDTXT("ENTR | "); + param = ys_read_u16_le(read_p, &read_p); + + sprintf(tmp_buf, "%04X ", param); + SD_ADDTXT(tmp_buf); +/* + for( i = 0 ; i < script_list->n_scripts ; i++ ) { + if( op_offset == script_list->scripts[i].offset ) { + printf("; Entrypoint \"%s\".", script_list->scriptl_p + + script_list->scripts[i].name_offset ); + + break; + } + } +*/ + } + break; + + case 0x1B: + SD_ADDTXT("??? "); + break; + + /* End subscript */ + case 0x1C: + SD_ADDTXT("EXIT |"); + break; + + /* Unconditional jump */ + case 0x1D: + { + int param1; + + SD_ADDTXT("JMP | "); + param1 = ys_read_u16_le(read_p, &read_p); + + sprintf(tmp_buf, "%04X", param1); + SD_ADDTXT(tmp_buf); + } + break; + + /* Jump if nonzero + POP */ + case 0x1E: + { + int param1; + + SD_ADDTXT("JNZP | "); + param1 = ys_read_u16_le(read_p, &read_p); + + sprintf(tmp_buf, "%04X", param1); + SD_ADDTXT(tmp_buf); + } + break; + + /* Jump if zero + POP */ + case 0x1F: + { + int param1; + + SD_ADDTXT("JZP | "); + param1 = ys_read_u16_le(read_p, &read_p); + + sprintf(tmp_buf, "%04X", param1); + SD_ADDTXT(tmp_buf); + } + break; + + /* Jump if nonzero */ + case 0x20: + { + int param1; + + SD_ADDTXT("JNZ | "); + param1 = ys_read_u16_le(read_p, &read_p); + + sprintf(tmp_buf, "%04X", param1); + SD_ADDTXT(tmp_buf); + } + break; + + /* Jump if zero */ + case 0x21: + { + int param1; + + SD_ADDTXT("JZ | "); + param1 = ys_read_u16_le(read_p, &read_p); + + sprintf(tmp_buf, "%04X", param1); + SD_ADDTXT(tmp_buf); + + } + break; + + /* Switch */ + case 0x22: + { + int switch_num; + int switch_jmp; + int default_jmp; + + SD_ADDTXT("SWCH | "); + n_switch = ys_read_u16_le(read_p, &read_p); + + sprintf(tmp_buf, "%02X\n", n_switch); + SD_ADDTXT(tmp_buf); + + for (i = 0; i < n_switch; i++) { + switch_num = ys_read_u16_le(read_p, &read_p); + switch_jmp = ys_read_u16_le(read_p, &read_p); + + /* + * printf( R_TAB "CASE %04X, %04X\n", switch_num, switch_jmp ); + */ + } + + default_jmp = ys_read_u16_le(read_p, &read_p); + + /* + * printf( R_TAB "DEF %04X", default_jmp ); + */ + } + break; + + /* Random branch */ + case 0x24: + { + int n_switch2; + int switch_num; + int switch_jmp; + + SD_ADDTXT("RJMP | "); + + /* Ignored? */ + ys_read_u16_le(read_p, &read_p); + + n_switch2 = ys_read_u16_le(read_p, &read_p); + + sprintf(tmp_buf, "%04X", n_switch2); + SD_ADDTXT(tmp_buf); + + for (i = 0; i < n_switch2; i++) { + /*printf("\n"); */ + switch_num = ys_read_u16_le(read_p, &read_p); + switch_jmp = ys_read_u16_le(read_p, &read_p); + /* + * printf( R_TAB "WEIGHT %04X, %04X", switch_num, switch_jmp ); + */ + } + } + break; + + case 0x25: + SD_ADDTXT("NEG |"); + break; + + case 0x26: + SD_ADDTXT("TSTZ |"); + break; + + case 0x27: + SD_ADDTXT("NOT |"); + break; + + case 0x28: + SD_ADDTXT("??? "); + read_p++; + ys_read_u16_le(read_p, &read_p); + break; + + case 0x29: + SD_ADDTXT("??? "); + read_p++; + ys_read_u16_le(read_p, &read_p); + break; + + case 0x2A: + SD_ADDTXT("??? "); + read_p++; + ys_read_u16_le(read_p, &read_p); + break; + + case 0x2B: + SD_ADDTXT("??? "); + read_p++; + ys_read_u16_le(read_p, &read_p); + break; + + /* Addition */ + case 0x2C: + SD_ADDTXT("ADD |"); + break; + + /* Subtraction */ + case 0x2D: + SD_ADDTXT("SUB |"); + break; + + /* Integer multiplication */ + case 0x2E: + SD_ADDTXT("MULT |"); + break; + + /* Integer division */ + case 0x2F: + SD_ADDTXT("DIV |"); + break; + + /* Modulus */ + case 0x30: + SD_ADDTXT("MOD |"); + break; + + /* Test equality */ + case 0x33: + SD_ADDTXT("EQU |"); + break; + + /* Test inequality */ + case 0x34: + SD_ADDTXT("NEQU |"); + break; + + /* Test Greater-than */ + case 0x35: + SD_ADDTXT("GRT |"); + break; + + /* Test Less-than */ + case 0x36: + SD_ADDTXT("LST |"); + break; + + /* Test Greater-than or Equal to */ + case 0x37: + SD_ADDTXT("GRTE |"); + break; + + /* Test Less-than or Equal to */ + case 0x38: + SD_ADDTXT("LSTE |"); + break; + + case 0x3F: + SD_ADDTXT("SHR |"); + break; + + case 0x40: + SD_ADDTXT("SHL |"); + break; + + case 0x41: + SD_ADDTXT("AND |"); + break; + + case 0x42: + SD_ADDTXT("OR |"); + break; + + case 0x43: + SD_ADDTXT("XOR |"); + break; + + case 0x44: + SD_ADDTXT("LAND |"); + break; + + case 0x45: + SD_ADDTXT("LOR |"); + break; + + case 0x46: + SD_ADDTXT("LXOR |"); + break; + + case 0x53: + { + int n_voices; + int param1; + int param2; + + SD_ADDTXT("DLGP | "); + + n_voices = *read_p++; + param1 = ys_read_u16_le(read_p, &read_p); + param2 = *read_p++; + + /* ignored ? */ + ys_read_u16_le(read_p, &read_p); + + sprintf(tmp_buf, "%02X %04X %02X", n_voices, param1, + param2); + SD_ADDTXT(tmp_buf); + } + break; + + case 0x54: + SD_ADDTXT("DLGS |"); + break; + + case 0x55: + SD_ADDTXT("DLGX |"); + break; + + case 0x56: + { + int param1; + int param2; + int param3; + + SD_ADDTXT("DLGO | "); + param1 = *read_p++; + param2 = *read_p++; + + sprintf(tmp_buf, "%02X %02X ", param1, param2); + SD_ADDTXT(tmp_buf); + + if (param2 > 0) { + param3 = ys_read_u16_le(read_p, &read_p); + + sprintf(tmp_buf, "%04X", param3); + SD_ADDTXT(tmp_buf); + } + } + break; + + case 0x57: + { + int param1; + int param2; + int param3; + + SD_ADDTXT("JMPS | "); + + param1 = ys_read_u16_le(read_p, &read_p); + param2 = ys_read_u16_le(read_p, &read_p); + param3 = *read_p++; + + sprintf(tmp_buf, "%04X %04X %02X", param1, param2, + param3); + SD_ADDTXT(tmp_buf); + } + break; + + default: + sprintf(tmp_buf, "Invalid opcode.\n"); + SD_ADDTXT(tmp_buf); + break; + + } /* end switch( in_char ) */ + + ScriptModule.dbg_txtentry = TEXT_AddEntry(si.text_list, &tl_e); + TEXT_SetDisplay(ScriptModule.dbg_txtentry, 1); + + return R_SUCCESS; +} + +} // End of namespace Saga diff --git a/saga/sfuncs.cpp b/saga/sfuncs.cpp new file mode 100644 index 0000000000..782fa56878 --- /dev/null +++ b/saga/sfuncs.cpp @@ -0,0 +1,811 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Scripting module script function component + + Notes: +*/ + +#include "reinherit.h" + +#include "yslib.h" + +/* + * Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "actor_mod.h" +#include "animation_mod.h" +#include "console_mod.h" +#include "interface_mod.h" +#include "text_mod.h" + +/* +\*--------------------------------------------------------------------------*/ +#include "script.h" +#include "sfuncs.h" + +namespace Saga { + +R_SFUNC_ENTRY SFuncList[R_SFUNC_NUM] = { + + {0, 0, NULL} + , + {1, 1, SF_Sleep} + , + {2, 0, NULL} + , + {3, 1, SF_3} + , + {4, 1, SF_SetCommandText} + , + {5, 0, NULL} + , + {6, 3, SF_ActorWalkTo} + , + {7, 0, NULL} + , + {8, 2, SF_SetActorOrient} + , + {9, 0, NULL} + , + {10, 0, NULL} + , + {11, 1, SF_FreezeInterface} + , + {12, 0, NULL} + , + {13, 0, NULL} + , + {14, 0, NULL} + , + {15, 0, NULL} + , + {16, 0, NULL} + , + {17, 0, NULL} + , + {18, 0, NULL} + , + {19, 0, NULL} + , + {20, 0, NULL} + , + {21, 0, NULL} + , + {22, 0, NULL} + , + {23, 0, NULL} + , + {24, 0, NULL} + , + {25, 0, NULL} + , + {26, 3, SF_StartAnim} + , + {27, 3, SF_ActorWalkToAsync} + , + {28, 0, NULL} + , + {29, 0, NULL} + , + {30, 3, SF_PlaceActor} + , + {31, 0, NULL} + , + {32, 0, NULL} + , + {33, 0, NULL} + , + {34, 0, NULL} + , + {35, 0, NULL} + , + {36, 4, SF_ActorWalkTo2} + , + {37, 4, SF_SetActorAct} + , + {38, 3, SF_SetActorAct2} + , + {39, 0, NULL} + , + {40, 0, NULL} + , + {41, 4, SF_LinkAnim} + , + {42, 0, NULL} + , + {43, 6, SF_PlaceActorEx} + , + {44, 0, SF_CheckUserInterrupt} + , + {45, 0, NULL} + , + {46, 0, NULL} + , + {47, 0, NULL} + , + {48, 0, NULL} + , + {49, 0, NULL} + , + {50, 0, NULL} + , + {51, 0, NULL} + , + {52, 0, NULL} + , + {53, 0, NULL} + , + {54, 0, NULL} + , + {55, 0, NULL} + , + {56, 0, NULL} + , + {57, 0, NULL} + , + {58, 0, NULL} + , + {59, 0, NULL} + , + {60, 0, NULL} + , + {61, 0, NULL} + , + {62, 0, NULL} + , + {63, 0, NULL} + , + {64, 0, NULL} + , + {65, 0, NULL} + , + {66, 0, NULL} + , + {67, 0, NULL} + , + {68, 0, NULL} + , + {69, 0, NULL} + , + {70, 0, NULL} + , + {71, 0, NULL} + , + {72, 0, NULL} + , + {73, 0, NULL} + , + {74, 0, NULL} + , + {75, 0, NULL} + , + {76, 0, NULL} + , + {77, 0, NULL} +}; + +int SF_Sleep(R_SCRIPTFUNC_PARAMS) +/*--------------------------------------------------------------------------*\ + * + * Script function #1 (0x01) blocking + * + * Suspends thread execution for the specified time period + * + * Param1: time to suspend ( units? ) + * +\*--------------------------------------------------------------------------*/ +{ + SDataWord_T time_param; + + int time; + + SSTACK_Pop(thread->stack, &time_param); + + time = SDATA_ReadWordU(time_param); + + thread->sleep_time = time * 10; + + return R_SUCCESS; +} + +int SF_3(R_SCRIPTFUNC_PARAMS) +/*--------------------------------------------------------------------------*\ + * + * Script function #3 (0x03) + * + * Unknown function; pops a parameter and pushes a return value + * + * Param1: unknown + * +\*--------------------------------------------------------------------------*/ +{ + /* INCOMPLETE */ + + SDataWord_T param1; + + SSTACK_Pop(thread->stack, ¶m1); + + SSTACK_Push(thread->stack, 0); /* push for now to allow intro faire + * setup to run completely */ + + return R_SUCCESS; +} + +int SF_SetCommandText(R_SCRIPTFUNC_PARAMS) +/*--------------------------------------------------------------------------*\ + * + * Script function #4 (0x04) nonblocking + * + * Set the command display to the specified text string + * + * Param1: dialogue index of string + * +\*--------------------------------------------------------------------------*/ +{ + SDataWord_T s_idx_parm; + + SSTACK_Pop(thread->stack, &s_idx_parm); + + /* INCOMPLETE */ + + return R_SUCCESS; +} + +int SF_ActorWalkTo(R_SCRIPTFUNC_PARAMS) +/*--------------------------------------------------------------------------*\ + * + * Script function #6 (0x06) blocking + * + * Commands the specified actor to walk to the given position + * + * Param1: actor id + * Param2: actor destination x + * Param3: actor destination y + * +\*--------------------------------------------------------------------------*/ +{ + SDataWord_T actor_parm; + + SDataWord_T x_parm; + SDataWord_T y_parm; + + int actor_id; + int actor_idx; + + R_POINT pt; + + SSTACK_Pop(thread->stack, &actor_parm); + + SSTACK_Pop(thread->stack, &x_parm); + SSTACK_Pop(thread->stack, &y_parm); + + actor_id = SDATA_ReadWordS(actor_parm); + + actor_idx = ACTOR_GetActorIndex(actor_id); + if (actor_idx < 0) { + CON_Print(S_WARN_PREFIX "SF.08: Actor id 0x%X not found.", + actor_id); + return R_FAILURE; + } + + pt.x = SDATA_ReadWordS(x_parm); + pt.y = SDATA_ReadWordS(y_parm); + + ACTOR_WalkTo(actor_idx, &pt, 0, &thread->sem); + + return R_SUCCESS; +} + +int SF_SetActorOrient(R_SCRIPTFUNC_PARAMS) +/*--------------------------------------------------------------------------*\ + * + * Script function #8 (0x08) nonblocking + * + * Sets the orientation of the specified actor. + * + * Param1: actor id + * Param2: actor orientation + * +\*--------------------------------------------------------------------------*/ +{ + SDataWord_T actor_parm; + SDataWord_T orient_parm; + + int actor_id; + int actor_idx; + int orientation; + + SSTACK_Pop(thread->stack, &actor_parm); + SSTACK_Pop(thread->stack, &orient_parm); + + actor_id = SDATA_ReadWordS(actor_parm); + orientation = SDATA_ReadWordS(orient_parm); + + actor_idx = ACTOR_GetActorIndex(actor_id); + if (actor_idx < 0) { + CON_Print(S_WARN_PREFIX "SF.08: Actor id 0x%X not found.", + actor_id); + + return R_FAILURE; + } + + ACTOR_SetOrientation(actor_idx, orientation); + return R_SUCCESS; +} + +int SF_FreezeInterface(R_SCRIPTFUNC_PARAMS) +/*--------------------------------------------------------------------------*\ + * + * Script function #11 (0x0B) nonblocking + * + * If the parameter is true, the user interface is disabled while script + * continues to run. If the parameter is false, the user interface is + * reenabled. + * + * Param1: boolean + * +\*--------------------------------------------------------------------------*/ +{ + SDataWord_T b_param; + + SSTACK_Pop(thread->stack, &b_param); + + if (b_param) { + INTERFACE_Deactivate(); + } else { + INTERFACE_Activate(); + } + + return R_SUCCESS; +} + +int SF_StartAnim(R_SCRIPTFUNC_PARAMS) +/*--------------------------------------------------------------------------*\ + * + * Script function #26 (0x1A) nonblocking + * + * Starts the specified animation + * + * Param1: ? + * Param2: frames of animation to play or -1 to loop + * Param3: animation id + * +\*--------------------------------------------------------------------------*/ +{ + SDataWord_T unk_parm; + SDataWord_T frame_parm; + SDataWord_T anim_id_parm; + + int frame_count; + int anim_id; + + SSTACK_Pop(thread->stack, &anim_id_parm); + SSTACK_Pop(thread->stack, &frame_parm); + SSTACK_Pop(thread->stack, &unk_parm); + + frame_count = SDATA_ReadWordS(frame_parm); + anim_id = SDATA_ReadWordS(anim_id_parm); + + if (ANIM_Play(anim_id, 0) != R_SUCCESS) { + + CON_Print(S_WARN_PREFIX + "SF.26: ANIM_Play() failed. Anim id: %u\n", anim_id); + + return R_FAILURE; + } + + return R_SUCCESS; +} + +int SF_ActorWalkToAsync(R_SCRIPTFUNC_PARAMS) +/*--------------------------------------------------------------------------*\ + * + * Script function #27 (0x1B) nonblocking + * + * Commands the specified actor to walk to the given position + * + * Param1: actor id + * Param2: actor destination x + * Param3: actor destination y + * +\*--------------------------------------------------------------------------*/ +{ + SDataWord_T actor_parm; + + SDataWord_T x_parm; + SDataWord_T y_parm; + + int actor_id; + int actor_idx; + + R_POINT pt; + + SSTACK_Pop(thread->stack, &actor_parm); + + SSTACK_Pop(thread->stack, &x_parm); + SSTACK_Pop(thread->stack, &y_parm); + + actor_id = SDATA_ReadWordS(actor_parm); + + actor_idx = ACTOR_GetActorIndex(actor_id); + if (actor_idx < 0) { + CON_Print(S_WARN_PREFIX "SF.08: Actor id 0x%X not found.", + actor_id); + return R_FAILURE; + } + + pt.x = SDATA_ReadWordS(x_parm); + pt.y = SDATA_ReadWordS(y_parm); + + ACTOR_WalkTo(actor_idx, &pt, 0, NULL); + + return R_SUCCESS; +} + +int SF_PlaceActor(R_SCRIPTFUNC_PARAMS) +/*--------------------------------------------------------------------------*\ + * + * Script function #30 (0x1E) nonblocking + * + * Positions an actor at the specified location; actor is created if the + * actor does not already exist. + * + * Param1: actor id + * Param2: actor pos x + * Param3: actor pos y + * +\*--------------------------------------------------------------------------*/ +{ + SDataWord_T actor_parm; + + SDataWord_T x_parm; + SDataWord_T y_parm; + + int actor_id; + int actor_idx; + int result; + + R_POINT pt; + + SSTACK_Pop(thread->stack, &actor_parm); + + SSTACK_Pop(thread->stack, &x_parm); + SSTACK_Pop(thread->stack, &y_parm); + + actor_id = SDATA_ReadWordS(actor_parm); + + pt.x = SDATA_ReadWordS(x_parm); + pt.y = SDATA_ReadWordS(y_parm); + + if (!ACTOR_ActorExists(actor_id)) { + + result = ACTOR_Create(actor_id, pt.x, pt.y); + + if (result != R_SUCCESS) { + + CON_Print(S_WARN_PREFIX + "SF.30: Couldn't create actor 0x%X.", actor_id); + return R_FAILURE; + } + } else { + + actor_idx = ACTOR_GetActorIndex(actor_id); + + ACTOR_Move(actor_idx, &pt); + } + + return R_SUCCESS; +} + +int SF_ActorWalkTo2(R_SCRIPTFUNC_PARAMS) +/*--------------------------------------------------------------------------*\ + * + * Script function #36 (0x24) ? + * + * Commands the specified actor to walk to the given position + * + * Param1: actor id + * Param2: actor destination x + * Param3: actor destination y + * Param4: unknown + * +\*--------------------------------------------------------------------------*/ +{ + /* INCOMPLETE */ + + SDataWord_T actor_parm; + + SDataWord_T x_parm; + SDataWord_T y_parm; + SDataWord_T unk_parm; + + int actor_idx; + + R_POINT pt; + + SSTACK_Pop(thread->stack, &actor_parm); + + SSTACK_Pop(thread->stack, &x_parm); + SSTACK_Pop(thread->stack, &y_parm); + SSTACK_Pop(thread->stack, &unk_parm); + + actor_idx = ACTOR_GetActorIndex(SDATA_ReadWordS(actor_parm)); + if (actor_idx < 0) { + CON_Print(S_WARN_PREFIX "SF.36: Actor id 0x%X not found.", + (int)actor_parm); + return R_FAILURE; + } + + pt.x = SDATA_ReadWordS(x_parm); + pt.y = SDATA_ReadWordS(y_parm); + +#if 1 + ACTOR_WalkTo(actor_idx, &pt, 0, NULL); +#else + ACTOR_WalkTo(actor_idx, &pt, 0, &thread->sem); +#endif + + return R_SUCCESS; +} + +int SF_SetActorAct(R_SCRIPTFUNC_PARAMS) +/*--------------------------------------------------------------------------*\ + * + * Script function #37 (0x25) nonblocking + * + * Sets an actor to the specified action state + * + * Param1: actor id + * Param2: unknown + * Param3: actor action state + * Param4: unknown + * +\*--------------------------------------------------------------------------*/ +{ + /* INCOMPLETE */ + + SDataWord_T actor_parm; + + SDataWord_T unk1_parm; + SDataWord_T unk2_parm; + SDataWord_T action_parm; + + int actor_id; + int actor_idx; + + int action; + /*uint flags; */ + + SSTACK_Pop(thread->stack, &actor_parm); + + SSTACK_Pop(thread->stack, &unk1_parm); + SSTACK_Pop(thread->stack, &action_parm); + SSTACK_Pop(thread->stack, &unk2_parm); + + actor_id = SDATA_ReadWordS(actor_parm); + action = SDATA_ReadWordS(action_parm); + + actor_idx = ACTOR_GetActorIndex(actor_id); + + if (ACTOR_SetAction(actor_idx, action, ACTION_NONE) != R_SUCCESS) { + CON_Print(S_WARN_PREFIX "SF.37: ACTOR_SetAction() failed."); + + return R_FAILURE; + } + + return R_SUCCESS; +} + +int SF_SetActorAct2(R_SCRIPTFUNC_PARAMS) +/*--------------------------------------------------------------------------*\ + * + * Script function #38 (0x26) nonblocking + * + * Sets an actor to the specified action state + * + * Param1: actor id + * Param2: actor action state + * Param3: unknown + * +\*--------------------------------------------------------------------------*/ +{ + /* INCOMPLETE */ + + SDataWord_T actor_parm; + + SDataWord_T unk1_parm; + SDataWord_T action_parm; + + int actor_id; + int actor_idx; + + int action; + /*uint flags; */ + + SSTACK_Pop(thread->stack, &actor_parm); + + SSTACK_Pop(thread->stack, &action_parm); + SSTACK_Pop(thread->stack, &unk1_parm); + + actor_id = SDATA_ReadWordS(actor_parm); + action = SDATA_ReadWordS(action_parm); + + actor_idx = ACTOR_GetActorIndex(actor_id); + + if (ACTOR_SetAction(actor_idx, action, ACTION_NONE) != R_SUCCESS) { + CON_Print(S_WARN_PREFIX "SF.38: ACTOR_SetAction() failed."); + + return R_FAILURE; + } + + return R_SUCCESS; +} + +int SF_LinkAnim(R_SCRIPTFUNC_PARAMS) +/*--------------------------------------------------------------------------*\ + * + * Script function #41 (0x29) nonblocking + * + * Links the specified animations for playback + * + * Param1: ? + * Param2: total linked frame count + * Param3: animation id link target + * Param4: animation id link source + * +\*--------------------------------------------------------------------------*/ +{ + SDataWord_T unk_parm; + + SDataWord_T tframes_parm; + SDataWord_T anim1_parm; + SDataWord_T anim2_parm; + + int tframes; + + uint anim_id1; + uint anim_id2; + + SSTACK_Pop(thread->stack, &anim1_parm); + SSTACK_Pop(thread->stack, &anim2_parm); + + SSTACK_Pop(thread->stack, &tframes_parm); + SSTACK_Pop(thread->stack, &unk_parm); + + tframes = SDATA_ReadWordS(tframes_parm); + + anim_id1 = SDATA_ReadWordU(anim1_parm); + anim_id2 = SDATA_ReadWordU(anim2_parm); + + if (ANIM_Link(anim_id1, anim_id2) != R_SUCCESS) { + + CON_Print(S_WARN_PREFIX + "SF.41: ANIM_Link() failed. (%u->%u)\n", anim_id1, + anim_id2); + + return R_FAILURE; + } + + return R_SUCCESS; +} + +int SF_PlaceActorEx(R_SCRIPTFUNC_PARAMS) +/*--------------------------------------------------------------------------*\ + * + * Script function #43 (0x2B) nonblocking + * + * Positions an actor at the specified location; actor is created if the + * actor does not already exist. + * + * Param1: actor id + * Param2: actor pos x + * Param3: actor pos y + * Param4: ? + * Param5: actor action + * Param6: ? + * +\*--------------------------------------------------------------------------*/ +{ + /* INCOMPLETE */ + + SDataWord_T actor_parm; + + SDataWord_T x_parm; + SDataWord_T y_parm; + + SDataWord_T action_parm; + + SDataWord_T unknown_parm; + + int actor_id; + int actor_idx; + int action_state; + int result; + + R_POINT pt; + + SSTACK_Pop(thread->stack, &actor_parm); + + SSTACK_Pop(thread->stack, &x_parm); + SSTACK_Pop(thread->stack, &y_parm); + + SSTACK_Pop(thread->stack, &unknown_parm); + SSTACK_Pop(thread->stack, &action_parm); + SSTACK_Pop(thread->stack, &unknown_parm); + + actor_id = SDATA_ReadWordS(actor_parm); + + pt.x = SDATA_ReadWordS(x_parm); + pt.y = SDATA_ReadWordS(y_parm); + + action_state = SDATA_ReadWordU(action_parm); + + if (!ACTOR_ActorExists(actor_id)) { + + result = ACTOR_Create(actor_id, pt.x, pt.y); + + if (result != R_SUCCESS) { + + CON_Print(S_WARN_PREFIX + "SF.43: Couldn't create actor 0x%X.", actor_id); + + return R_FAILURE; + } + } else { + + actor_idx = ACTOR_GetActorIndex(actor_id); + + ACTOR_Move(actor_idx, &pt); + } + + actor_idx = ACTOR_GetActorIndex(actor_id); + + ACTOR_SetDefaultAction(actor_idx, action_state, ACTION_NONE); + ACTOR_SetAction(actor_idx, action_state, ACTION_NONE); + + return R_SUCCESS; +} + +int SF_CheckUserInterrupt(R_SCRIPTFUNC_PARAMS) +/*--------------------------------------------------------------------------*\ + * + * Script function #44 (0x2C) nonblocking + * + * Checks to see if the user has interrupted a currently playing + * game cinematic. Pushes a zero or positive value if the game + * has not been interrupted. + * +\*--------------------------------------------------------------------------*/ +{ + SSTACK_Push(thread->stack, 0); + + /* INCOMPLETE */ + + return R_SUCCESS; +} + +} // End of namespace Saga diff --git a/saga/sfuncs.h b/saga/sfuncs.h new file mode 100644 index 0000000000..75d7339420 --- /dev/null +++ b/saga/sfuncs.h @@ -0,0 +1,103 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Scripting module script function component header file + + Notes: +*/ + +#ifndef SAGA_SFUNCS_H +#define SAGA_SFUNCS_H + +#include "sthread.h" + +namespace Saga { + +#define R_SFUNC_NUM 78 + + +#define R_SCRIPTFUNC_PARAMS R_SCRIPT_THREAD * thread + +typedef int (*SFunc_T) (R_SCRIPTFUNC_PARAMS); + +typedef struct R_SFUNC_ENTRY_tag { + + int sfunc_num; + int sfunc_argc; + SFunc_T sfunc_fp; + +} R_SFUNC_ENTRY; + +extern R_SFUNC_ENTRY SFuncList[]; + +/* SF 1 */ +int SF_Sleep(R_SCRIPTFUNC_PARAMS); + +/* SF 3 */ +int SF_3(R_SCRIPTFUNC_PARAMS); + +/* SF 4 */ +int SF_SetCommandText(R_SCRIPTFUNC_PARAMS); + +/* SF 6 */ +int SF_ActorWalkTo(R_SCRIPTFUNC_PARAMS); + +/* SF 8 */ +int SF_SetActorOrient(R_SCRIPTFUNC_PARAMS); + +/* SF 11 */ +int SF_FreezeInterface(R_SCRIPTFUNC_PARAMS); + +/* SF 26 */ +int SF_StartAnim(R_SCRIPTFUNC_PARAMS); + +/* SF 27 */ +int SF_ActorWalkToAsync(R_SCRIPTFUNC_PARAMS); + +/* SF 30 */ +int SF_PlaceActor(R_SCRIPTFUNC_PARAMS); + +/* SF 36 */ +int SF_ActorWalkTo2(R_SCRIPTFUNC_PARAMS); + +/* SF 37 */ +int SF_SetActorAct(R_SCRIPTFUNC_PARAMS); + +/* SF 38 */ +int SF_SetActorAct2(R_SCRIPTFUNC_PARAMS); + +/* SF 41 */ +int SF_LinkAnim(R_SCRIPTFUNC_PARAMS); + +/* SF 43 */ +int SF_PlaceActorEx(R_SCRIPTFUNC_PARAMS); + +/* SF 44 */ +int SF_CheckUserInterrupt(R_SCRIPTFUNC_PARAMS); + +} // End of namespace Saga + +#endif /* SAGA_SFUNCS_H */ diff --git a/saga/sndres.cpp b/saga/sndres.cpp new file mode 100644 index 0000000000..3592095578 --- /dev/null +++ b/saga/sndres.cpp @@ -0,0 +1,353 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Sound resource management module + + Notes: +*/ + +#include "reinherit.h" + +#include "yslib.h" + +#include <limits.h> + +/* + * Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "game_mod.h" +#include "rscfile_mod.h" + +/* + * Begin module component +\*--------------------------------------------------------------------------*/ +#include "sndres_mod.h" +#include "sndres.h" + +namespace Saga { + +R_SNDRES_MODULE SndModule; + +int SND_Init(void) +{ + int result; + + /* Load sound module resource file contexts + * \*------------------------------------------------------------- */ + result = GAME_GetFileContext(&SndModule.sfx_ctxt, R_GAME_SOUNDFILE, 0); + if (result != R_SUCCESS) { + return R_FAILURE; + } + + result = GAME_GetFileContext(&SndModule.voice_ctxt, + R_GAME_VOICEFILE, 0); + if (result != R_SUCCESS) { + return R_FAILURE; + } + + /* Grab sound resource information for the current game + * \*------------------------------------------------------------- */ + GAME_GetSoundInfo(&SndModule.snd_info); + + SndModule.init = 1; + + return R_SUCCESS; +} + +int SND_PlayVoice(ulong voice_rn) +{ + R_SOUNDBUFFER snd_buffer; + int result; + + result = SND_Load(SndModule.voice_ctxt, voice_rn, &snd_buffer); + if (result != R_SUCCESS) { + return R_FAILURE; + } + + SYSSOUND_PlayVoice(&snd_buffer); + + return R_SUCCESS; +} + +int +SND_Load(R_RSCFILE_CONTEXT * snd_ctxt, ulong snd_rn, R_SOUNDBUFFER * snd_buf_i) +{ + + uchar *snd_res; + size_t snd_res_len; + + int result; + + assert((snd_ctxt != NULL) && (snd_buf_i != NULL)); + + result = RSC_LoadResource(snd_ctxt, snd_rn, &snd_res, &snd_res_len); + if (result != R_SUCCESS) { + return R_FAILURE; + } + + switch (SndModule.snd_info.res_type) { + + case R_GAME_SOUND_PCM: + + snd_buf_i->s_freq = SndModule.snd_info.freq; + snd_buf_i->s_samplebits = SndModule.snd_info.sample_size; + snd_buf_i->s_stereo = SndModule.snd_info.stereo; + + snd_buf_i->res_data = snd_res; + snd_buf_i->res_len = snd_res_len; + + snd_buf_i->s_buf = snd_res; + snd_buf_i->s_buf_len = snd_res_len; + + snd_buf_i->s_signed = 1; + + break; + + case R_GAME_SOUND_VOC: + + if (LoadVocSound(snd_res, snd_res_len, snd_buf_i) != R_SUCCESS) { + + RSC_FreeResource(snd_res); + + return R_FAILURE; + } + + break; + + default: + /* Unknown sound type */ + + RSC_FreeResource(snd_res); + + return R_FAILURE; + break; + } + + return R_SUCCESS; +} + +int +LoadVocSound(const uchar * snd_res, + size_t snd_res_len, R_SOUNDBUFFER * snd_buf_i) +{ + + R_VOC_HEADER_BLOCK voc_hb; + R_VOC_GENBLOCK voc_gb; + R_VOC_BLOCK1 voc_b1; + + long byte_rate; + + const uchar *read_p; + size_t read_len; + + read_p = snd_res; + read_len = snd_res_len; + + if (read_len < R_VOC_HEADER_BLOCK_LEN) { + return R_FAILURE; + } + + memcpy(voc_hb.ft_desc, read_p, R_VOC_FILE_DESC_LEN); + read_p += R_VOC_FILE_DESC_LEN; + read_len -= R_VOC_FILE_DESC_LEN; + + if (memcmp(voc_hb.ft_desc, R_VOC_FILE_DESC, R_VOC_FILE_DESC_LEN) != 0) { + + /* Voc file desc string not found */ + return R_FAILURE; + } + + voc_hb.db_offset = ys_read_u16_le(read_p, &read_p); + voc_hb.voc_version = ys_read_u16_le(read_p, &read_p); + voc_hb.voc_fileid = ys_read_u16_le(read_p, &read_p); + + if (read_len < voc_hb.db_offset + R_VOC_GENBLOCK_LEN) { + + return R_FAILURE; + } + + read_p = snd_res + voc_hb.db_offset; + read_len = snd_res_len - voc_hb.db_offset; + + for (;;) { + + /* Read generic block header + * \*--------------------------------------------------------- */ + if (read_len < R_VOC_GENBLOCK_LEN) { + return R_FAILURE; + } + + voc_gb.block_id = ys_read_u8(read_p, &read_p); + if (voc_gb.block_id == 0) { + return R_FAILURE; + } + + voc_gb.block_len = ys_read_u24_le(read_p, &read_p); + + read_len -= R_VOC_GENBLOCK_LEN; + + /* Process block + * \*--------------------------------------------------------- */ + switch (voc_gb.block_id) { + + case 1: /* Sound data block */ + + voc_b1.time_constant = ys_read_u8(read_p, &read_p); + voc_b1.pack_method = ys_read_u8(read_p, &read_p); + read_len -= 2; + + if (voc_b1.pack_method != 0) { + /* Packed VOC files not supported */ + return R_FAILURE; + } + + byte_rate = R_VOC_TIME_BASE / (R_VOC_TIME_CBASE - + (voc_b1.time_constant << 8)); + + snd_buf_i->s_stereo = 0; + snd_buf_i->s_samplebits = 8; + snd_buf_i->s_freq = byte_rate; + + snd_buf_i->res_data = (uchar *) snd_res; + snd_buf_i->res_len = snd_res_len; + + snd_buf_i->s_buf = (uchar *) read_p; + snd_buf_i->s_buf_len = read_len - 1; /* -1 for end block */ + + snd_buf_i->s_signed = 0; + + return R_SUCCESS; + + break; + + default: + + read_p += voc_gb.block_len; + read_len -= voc_gb.block_len; + break; + } + } + + return R_SUCCESS; +} + +int SND_GetVoiceLength(ulong voice_rn) +{ + + ulong length; + + double ms_f; + int ms_i = -1; + + int result; + + assert(SndModule.init); + + result = RSC_GetResourceSize(SndModule.voice_ctxt, voice_rn, &length); + if (result != R_SUCCESS) { + return -1; + } + + if (SndModule.snd_info.res_type == R_GAME_SOUND_PCM) { + + ms_f = (double)length / + (SndModule.snd_info.sample_size / CHAR_BIT) / + (SndModule.snd_info.freq) * 1000.0; + + ms_i = (int)ms_f; + } else if (SndModule.snd_info.res_type == R_GAME_SOUND_VOC) { + + /* Rough hack, fix this to be accurate */ + + ms_f = (double)length / 14705 * 1000.0; + ms_i = (int)ms_f; + } else { + return -1; + } + + return ms_i; +} + +int +SND_ITEVOC_Resample(long src_freq, + long dst_freq, + uchar * src_buf, + size_t src_buf_len, uchar ** dst_buf, size_t * dst_buf_len) +{ + uchar *resamp_buf; + size_t resamp_len; + + uchar src_samp_a; + uchar src_samp_b; + + const uchar *read_pa; + const uchar *read_pb; + + uchar *write_pa; + uchar *write_pb; + uchar *write_pc; + + size_t src_i; + + assert(src_freq == 14705); + assert(dst_freq == 22050); + + resamp_len = (size_t) (src_buf_len * 1.5); + resamp_buf = (uchar *)malloc(resamp_len); + if (resamp_buf == NULL) { + return R_FAILURE; + } + + read_pa = src_buf; + read_pb = src_buf + 1; + + write_pa = resamp_buf; + write_pb = resamp_buf + 1; + write_pc = resamp_buf + 2; + + for (src_i = 0; src_i < src_buf_len / 2; src_i++) { + + src_samp_a = *read_pa; + src_samp_b = *read_pb; + + read_pa += 2; + read_pb += 2; + + *write_pa = src_samp_a; + *write_pb = (uchar) ((src_samp_a / 2) + (src_samp_b / 2)); + *write_pc = src_samp_b; + + write_pa += 3; + write_pb += 3; + write_pc += 3; + } + + *dst_buf = resamp_buf; + *dst_buf_len = resamp_len; + + return R_SUCCESS; +} + +} // End of namespace Saga diff --git a/saga/sndres.h b/saga/sndres.h new file mode 100644 index 0000000000..1bdfc577a8 --- /dev/null +++ b/saga/sndres.h @@ -0,0 +1,92 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Sound resource management module - private header + + Notes: +*/ + +#ifndef SAGA_SNDRES_H_ +#define SAGA_SNDRES_H_ + +namespace Saga { + +#define R_VOC_TIME_BASE 256000000L +#define R_VOC_TIME_CBASE 65536L + +#define R_VOC_FILE_DESC_LEN 20 +#define R_VOC_FILE_DESC "Creative Voice File\x1A" + +typedef struct R_VOC_HEADER_BLOCK_tag { + + char ft_desc[20]; /* BYTE [20] */ + uint db_offset; /* WORD */ + uint voc_version; /* WORD */ + uint voc_fileid; /* WORD */ + +} R_VOC_HEADER_BLOCK; + +#define R_VOC_HEADER_BLOCK_LEN 26 + +typedef struct R_VOC_GENBLOCK_tag { + + int block_id; /* BYTE */ + ulong block_len; /* BYTE[3] */ + +} R_VOC_GENBLOCK; + +#define R_VOC_GENBLOCK_LEN 4 + +typedef struct R_VOC_BLOCK1_tag { + + int block_id; /* BYTE */ + ulong block_len; /* BYTE[3] */ + uint time_constant; /* BYTE */ + int pack_method; /* BYTE */ + +} R_VOC_BLOCK1; + +typedef struct R_SNDRES_MODULE_tag { + + int init; + + R_RSCFILE_CONTEXT *sfx_ctxt; + R_RSCFILE_CONTEXT *voice_ctxt; + + R_GAME_SOUNDINFO snd_info; + +} R_SNDRES_MODULE; + +int +SND_Load(R_RSCFILE_CONTEXT * snd_ctxt, + ulong snd_rn, R_SOUNDBUFFER * snd_buf_i); + +int +LoadVocSound(const uchar * snd_res, + size_t snd_res_len, R_SOUNDBUFFER * snd_buf_i); + +} // End of namespace Saga + +#endif /* SAGA_SNDRES_H_ */ diff --git a/saga/sndres_mod.h b/saga/sndres_mod.h new file mode 100644 index 0000000000..245727dd34 --- /dev/null +++ b/saga/sndres_mod.h @@ -0,0 +1,52 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Sound resource management module - public header + + Notes: +*/ + +#ifndef SAGA_SNDRES_MOD_H_ +#define SAGA_SNDRES_MOD_H_ + +namespace Saga { + +int SND_Init(void); + +int SND_LoadSound(ulong sound_rn); + +int SND_PlayVoice(ulong voice_rn); + +int SND_GetVoiceLength(ulong voice_rn); + +int +SND_ITEVOC_Resample(long src_freq, + long dst_freq, + uchar * src_buf, + size_t src_buf_len, uchar ** dst_buf, size_t * dst_buf_len); + +} // End of namespace Saga + +#endif /* SAGA_SNDRES_MOD_H_ */ diff --git a/saga/sprite.cpp b/saga/sprite.cpp new file mode 100644 index 0000000000..975d79ec00 --- /dev/null +++ b/saga/sprite.cpp @@ -0,0 +1,567 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Sprite management module + + Notes: +*/ + +#include "reinherit.h" + +#include "yslib.h" + +/* + * Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "game_mod.h" +#include "gfx_mod.h" +#include "scene_mod.h" +#include "rscfile_mod.h" + +#include "text_mod.h" +#include "font_mod.h" + +/* + * Begin module component +\*--------------------------------------------------------------------------*/ +#include "sprite_mod.h" +#include "sprite.h" + +namespace Saga { + +R_SPRITE_MODULE SpriteModule = { 0 }; + +int SPRITE_Init(void) +{ + int result; + + if (SpriteModule.init) { + return R_FAILURE; + } + + R_printf(R_STDOUT, "Initializing sprite subsystem...\n"); + + /* Load sprite module resource context + * \*------------------------------------------------------------- */ + result = GAME_GetFileContext(&SpriteModule.sprite_ctxt, + R_GAME_RESOURCEFILE, 0); + if (result != R_SUCCESS) { + + return R_FAILURE; + } + + SpriteModule.decode_buf_len = R_DECODE_BUF_LEN; + + SpriteModule.decode_buf = (uchar *)malloc(R_DECODE_BUF_LEN); + if (SpriteModule.decode_buf == NULL) { + return R_MEM; + } + + SpriteModule.init = 1; + + return R_SUCCESS; +} + +int SPRITE_Shutdown(void) +{ + if (!SpriteModule.init) { + return R_FAILURE; + } + + R_printf(R_STDOUT, "Shutting down sprite subsystem...\n"); + + free(SpriteModule.decode_buf); + + return R_SUCCESS; +} + +int SPRITE_LoadList(int resource_num, R_SPRITELIST ** sprite_list_p) +{ + R_SPRITELIST *new_slist; + + uchar *spritelist_data; + size_t spritelist_len; + + const uchar *read_p; + + uint sprite_count; + uint i; + + new_slist = (R_SPRITELIST *)malloc(sizeof *new_slist); + if (new_slist == NULL) { + + return R_MEM; + } + + if (RSC_LoadResource(SpriteModule.sprite_ctxt, + resource_num, + &spritelist_data, &spritelist_len) != R_SUCCESS) { + + return R_FAILURE; + } + + read_p = spritelist_data; + + sprite_count = ys_read_u16_le(read_p, &read_p); + + new_slist->sprite_count = sprite_count; + + new_slist->offset_list = (R_SPRITELIST_OFFSET *)malloc(sprite_count * + sizeof *new_slist->offset_list); + if (new_slist->offset_list == NULL) { + free(new_slist); + + return R_MEM; + } + + for (i = 0; i < sprite_count; i++) { + new_slist->offset_list[i].data_idx = 0; + new_slist->offset_list[i].offset = + ys_read_u16_le(read_p, &read_p); + } + + new_slist->slist_rn = resource_num; + new_slist->sprite_data[0] = spritelist_data; + new_slist->append_count = 0; + + *sprite_list_p = new_slist; + + return R_SUCCESS; +} + +int SPRITE_AppendList(int resource_num, R_SPRITELIST * spritelist) +{ + uchar *spritelist_data; + size_t spritelist_len; + + const uchar *read_p; + + void *test_p; + + uint old_sprite_count; + uint new_sprite_count; + uint sprite_count; + + int i; + + if (spritelist->append_count >= (R_APPENDMAX - 1)) { + + return R_FAILURE; + } + + if (RSC_LoadResource(SpriteModule.sprite_ctxt, + resource_num, + &spritelist_data, &spritelist_len) != R_SUCCESS) { + + return R_FAILURE; + } + + read_p = spritelist_data; + + sprite_count = ys_read_u16_le(read_p, &read_p); + + old_sprite_count = spritelist->sprite_count; + new_sprite_count = spritelist->sprite_count + sprite_count; + + test_p = realloc(spritelist->offset_list, + new_sprite_count * sizeof *spritelist->offset_list); + if (test_p == NULL) { + return R_MEM; + } + + spritelist->offset_list = (R_SPRITELIST_OFFSET *)test_p; + + spritelist->sprite_count = new_sprite_count; + spritelist->append_count++; + + for (i = old_sprite_count; i < spritelist->sprite_count; i++) { + spritelist->offset_list[i].data_idx = spritelist->append_count; + spritelist->offset_list[i].offset = + ys_read_u16_le(read_p, &read_p); + } + + spritelist->sprite_data[spritelist->append_count] = spritelist_data; + + return R_SUCCESS; +} + +int SPRITE_GetListLen(R_SPRITELIST * spritelist) +{ + + return spritelist->sprite_count; +} + +int SPRITE_Free(R_SPRITELIST * spritelist) +{ + int i; + + for (i = 0; i <= spritelist->append_count; i++) { + + RSC_FreeResource(spritelist->sprite_data[i]); + } + + free(spritelist->offset_list); + free(spritelist); + + return R_SUCCESS; +} + +int +SPRITE_Draw(R_SURFACE * ds, + R_SPRITELIST * sprite_list, int sprite_num, int spr_x, int spr_y) +{ + + int offset; + int offset_idx; + + uchar *sprite_p; + + const uchar *sprite_data_p; + const uchar *read_p; + + int i, j; + + uchar *buf_row_p; + uchar *src_row_p; + + int s_width; + int s_height; + + int clip_width; + int clip_height; + + int x_align; + int y_align; + + if (!SpriteModule.init) { + return R_FAILURE; + } + + offset = sprite_list->offset_list[sprite_num].offset; + offset_idx = sprite_list->offset_list[sprite_num].data_idx; + + sprite_p = sprite_list->sprite_data[offset_idx]; + sprite_p += offset; + + read_p = (uchar *) sprite_p; + + x_align = ys_read_s8(read_p, &read_p); + y_align = ys_read_s8(read_p, &read_p); + + s_width = ys_read_u8(read_p, &read_p); + s_height = ys_read_u8(read_p, &read_p); + + sprite_data_p = read_p; + + spr_x += x_align; + spr_y += y_align; + + if (spr_x < 0) { + return 0; + } + + if (spr_y < 0) { + return 0; + } + + DecodeRLESprite(sprite_data_p, + 64000, SpriteModule.decode_buf, s_width * s_height); + + buf_row_p = ds->buf + ds->buf_pitch * spr_y; + src_row_p = SpriteModule.decode_buf; + + /* Clip to right side of surface */ + clip_width = s_width; + if (s_width > (ds->buf_w - spr_x)) { + clip_width = (ds->buf_w - spr_x); + } + + /* Clip to bottom side of surface */ + clip_height = s_height; + if (s_height > (ds->buf_h - spr_y)) { + clip_height = (ds->buf_h - spr_y); + } + + for (i = 0; i < clip_height; i++) { + + for (j = 0; j < clip_width; j++) { + if (*(src_row_p + j) != 0) { + *(buf_row_p + j + spr_x) = *(src_row_p + j); + } + } + + buf_row_p += ds->buf_pitch; + src_row_p += s_width; + } + + return R_SUCCESS; +} + +int +SPRITE_DrawOccluded(R_SURFACE * ds, + R_SPRITELIST * sprite_list, int sprite_num, int spr_x, int spr_y) +{ + int offset; + int offset_idx; + + uchar *sprite_p; + const uchar *sprite_data_p; + const uchar *read_p; + + int i; + + int x, y; + uchar *dst_row_p; + uchar *src_row_p; + uchar *src_p; + uchar *dst_p; + uchar *mask_p; + + int s_width; + int s_height; + int x_align; + int y_align; + + int z_lut[R_SPRITE_ZMAX]; + int e_slope; + + /* Clipinfo variables */ + R_POINT spr_pt; + R_RECT spr_src_rect; + R_RECT spr_dst_rect; + + R_CLIPINFO ci; + + /* BG mask variables */ + int mask_w; + int mask_h; + uchar *mask_buf; + size_t mask_buf_len; + + uchar *mask_row_p; + int mask_z; + + /* Z info variables */ + SCENE_ZINFO zinfo; + int actor_z; + + if (!SpriteModule.init) { + return R_FAILURE; + } + + if (!SCENE_IsBGMaskPresent()) { + return SPRITE_Draw(ds, sprite_list, sprite_num, spr_x, spr_y); + } + + if (sprite_num >= sprite_list->sprite_count) { + + R_printf(R_STDOUT, + "Invalid sprite number (%d) for sprite list %d.\n", + sprite_num, sprite_list->slist_rn); + + return R_FAILURE; + } + + /* Get sprite data from list + * \*------------------------------------------------------------- */ + offset = sprite_list->offset_list[sprite_num].offset; + offset_idx = sprite_list->offset_list[sprite_num].data_idx; + + sprite_p = sprite_list->sprite_data[offset_idx]; + sprite_p += offset; + + read_p = sprite_p; + + /* Read sprite dimensions -- should probably cache this stuff in + * sprite list */ + x_align = ys_read_s8(read_p, &read_p); + y_align = ys_read_s8(read_p, &read_p); + + s_width = ys_read_u8(read_p, &read_p); + s_height = ys_read_u8(read_p, &read_p); + + sprite_data_p = read_p; + + /* Create actor Z occlusion LUT + * \*---------------------------------------------------------------------- */ + SCENE_GetZInfo(&zinfo); + + e_slope = zinfo.end_slope; + + for (i = 0; i < R_SPRITE_ZMAX; i++) { + + z_lut[i] = + (int)(e_slope + ((137.0 - e_slope) / 14.0) * (15.0 - i)); + } + + actor_z = spr_y; + + SCENE_GetBGMaskInfo(&mask_w, &mask_h, &mask_buf, &mask_buf_len); + + spr_src_rect.x1 = 0; + spr_src_rect.y1 = 0; + spr_src_rect.x2 = s_width - 1; + spr_src_rect.y2 = s_height - 1; + + spr_dst_rect.x1 = 0; + spr_dst_rect.y1 = 0; + spr_dst_rect.x2 = ds->clip_rect.x2; + spr_dst_rect.y2 = YS_MIN(ds->clip_rect.y2, mask_h - 1); + + spr_pt.x = spr_x + x_align; + spr_pt.y = spr_y + y_align; + + spr_x += x_align; + spr_y += y_align; + + ci.dst_rect = &spr_dst_rect; + ci.src_rect = &spr_src_rect; + ci.dst_pt = &spr_pt; + + GFX_GetClipInfo(&ci); + + if (ci.nodraw) { + return R_SUCCESS; + } + + DecodeRLESprite(sprite_data_p, + 64000, SpriteModule.decode_buf, s_width * s_height); + + /* Finally, draw the occluded sprite + * \*---------------------------------------------------------------------- */ + src_row_p = SpriteModule.decode_buf + ci.src_draw_x + + (ci.src_draw_y * s_width); + + dst_row_p = ds->buf + ci.dst_draw_x + (ci.dst_draw_y * ds->buf_pitch); + mask_row_p = mask_buf + ci.dst_draw_x + (ci.dst_draw_y * mask_w); + + for (y = 0; y < ci.draw_h; y++) { + + src_p = src_row_p; + dst_p = dst_row_p; + mask_p = mask_row_p; + + for (x = 0; x < ci.draw_w; x++) { + + if (*src_p != 0) { + + mask_z = *mask_p & R_SPRITE_ZMASK; + + if (actor_z > z_lut[mask_z]) { + *dst_p = *src_p; + } + } + src_p++; + dst_p++; + mask_p++; + } + dst_row_p += ds->buf_pitch; + mask_row_p += mask_w; + src_row_p += s_width; + } +/* + { + char buf[1024] = { 0 }; + + sprintf( buf, "dw: %d, dh: %d.", ci.draw_w, ci.draw_h ); + + TEXT_Draw( 2, + ds, + buf, + spr_x - x_align, spr_y - y_align, + 255, 0, + FONT_OUTLINE ); + } +*/ + return R_SUCCESS; +} + +int +DecodeRLESprite(const uchar * inbuf, + size_t inbuf_len, uchar * outbuf, size_t outbuf_len) +{ + + int bg_runcount; + int fg_runcount; + + const uchar *inbuf_ptr; + uchar *outbuf_ptr; + + const uchar *inbuf_end; + uchar *outbuf_end; + + int c; + + inbuf_ptr = inbuf; + outbuf_ptr = outbuf; + + inbuf_end = inbuf + (inbuf_len); + inbuf_end--; + + outbuf_end = outbuf + outbuf_len; + outbuf_end--; + + memset(outbuf, 0, outbuf_len); + + while ((inbuf_ptr < inbuf_end) && (outbuf_ptr < outbuf_end)) { + + bg_runcount = *inbuf_ptr; + if (inbuf_ptr < inbuf_end) + inbuf_ptr++; + else + return 0; + fg_runcount = *inbuf_ptr; + if (inbuf_ptr < inbuf_end) + inbuf_ptr++; + else + return 0; + + for (c = 0; c < bg_runcount; c++) { + + *outbuf_ptr = (uchar) 0; + if (outbuf_ptr < outbuf_end) + outbuf_ptr++; + else + return 0; + } + + for (c = 0; c < fg_runcount; c++) { + + *outbuf_ptr = *inbuf_ptr; + if (inbuf_ptr < inbuf_end) + inbuf_ptr++; + else + return 0; + if (outbuf_ptr < outbuf_end) + outbuf_ptr++; + else + return 0; + } + } + + return R_SUCCESS; +} + +} // End of namespace Saga diff --git a/saga/sprite.h b/saga/sprite.h new file mode 100644 index 0000000000..d90d5e0800 --- /dev/null +++ b/saga/sprite.h @@ -0,0 +1,88 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Sprite management module private header file + + Notes: +*/ + +#ifndef SAGA_SPRITE_H__ +#define SAGA_SPRITE_H__ + +namespace Saga { + +#define R_APPENDMAX 4 + +#define R_SPRITE_ZMAX 16 +#define R_SPRITE_ZMASK 0x0F + +#define R_DECODE_BUF_LEN 64000 + +typedef struct R_SPRITELIST_ENTRY_tag { + + int x_align; + int y_align; + int width; + int height; + +} R_SPRITELIST_ENTRY; + +typedef struct R_SPRITELIST_OFFSET_tag { + + uint data_idx; + size_t offset; + +} R_SPRITELIST_OFFSET; + +struct R_SPRITELIST_tag { + + int append_count; + int sprite_count; + + R_SPRITELIST_OFFSET *offset_list; + + int slist_rn; + uchar *sprite_data[R_APPENDMAX]; + +}; + +typedef struct R_SPRITE_MODULE_tag { + + int init; + + R_RSCFILE_CONTEXT *sprite_ctxt; + + uchar *decode_buf; + size_t decode_buf_len; + +} R_SPRITE_MODULE; + +int +DecodeRLESprite(const uchar * inbuf, + size_t inbuf_len, uchar * outbuf, size_t outbuf_len); + +} // End of namespace Saga + +#endif /* SAGA_SPRITE_H__ */ diff --git a/saga/sprite_mod.h b/saga/sprite_mod.h new file mode 100644 index 0000000000..e93eec0513 --- /dev/null +++ b/saga/sprite_mod.h @@ -0,0 +1,61 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Sprite management module public header file + + Notes: +*/ + +#ifndef SAGA_SPRITE_MOD_H__ +#define SAGA_SPRITE_MOD_H__ + +namespace Saga { + +typedef struct R_SPRITELIST_tag R_SPRITELIST; + +int SPRITE_Init(void); + +int SPRITE_Shutdown(void); + +int SPRITE_LoadList(int resource_num, R_SPRITELIST ** sprite_list_p); + +int SPRITE_AppendList(int resource_num, R_SPRITELIST * spritelist); + +int SPRITE_GetListLen(R_SPRITELIST * spritelist); + +int SPRITE_Free(R_SPRITELIST * spritelist); + +int +SPRITE_Draw(R_SURFACE * ds, + R_SPRITELIST * sprite_list, int sprite_num, int spr_x, int spr_y); + +int +SPRITE_DrawOccluded(R_SURFACE * ds, + R_SPRITELIST * sprite_list, int sprite_num, int spr_x, int spr_y); + +} // End of namespace Saga + +#endif /* SAGA_SPRITE_MOD_H__ */ diff --git a/saga/sstack.cpp b/saga/sstack.cpp new file mode 100644 index 0000000000..99741ac632 --- /dev/null +++ b/saga/sstack.cpp @@ -0,0 +1,199 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Scripting engine stack component + + Notes: +*/ + +#include "reinherit.h" + +#include "yslib.h" + +/* + * Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "console_mod.h" +#include "text_mod.h" + +/* + * Begin module component +\*--------------------------------------------------------------------------*/ +#include "script.h" +#include "sstack.h" + +namespace Saga { + +int SSTACK_Create(SSTACK * stack, int stack_len, int flags) +{ + + SSTACK new_stack; + SDataWord_T *new_stack_data; + + *stack = NULL; + + new_stack = (SSTACK_tag *)malloc(sizeof(struct SSTACK_tag)); + if (new_stack == NULL) { + + return STACK_MEM; + } + + new_stack_data = (SDataWord_T *)calloc(stack_len, sizeof *new_stack_data); + if (new_stack_data == NULL) { + free(new_stack); + + return STACK_MEM; + } + + new_stack->data = new_stack_data; + + new_stack->flags = flags; + new_stack->len = stack_len; + new_stack->top = -1; + + *stack = new_stack; + + return STACK_SUCCESS; +} + +int SSTACK_Destroy(SSTACK stack) +{ + if (stack != NULL) { + free(stack->data); + } + + free(stack); + + return STACK_SUCCESS; +} + +int SSTACK_Clear(SSTACK stack) +{ + + stack->top = -1; + + return STACK_SUCCESS; +} + +int SSTACK_PushNull(SSTACK stack) +{ + + if (stack->top >= (stack->len - 1)) { + + if (stack->flags & STACK_FIXED) { + + return STACK_OVERFLOW; + } else if (SSTACK_Grow(stack) != STACK_SUCCESS) { + + return STACK_MEM; + } + } + + stack->top++; + + return STACK_SUCCESS; +} + +int SSTACK_Push(SSTACK stack, SDataWord_T value) +{ + + if (stack->top >= (stack->len - 1)) { + + if (stack->flags & STACK_FIXED) { + + return STACK_OVERFLOW; + } else if (SSTACK_Grow(stack) != STACK_SUCCESS) { + + return STACK_MEM; + } + } + + stack->top++; + stack->data[stack->top] = value; + + return STACK_SUCCESS; +} + +int SSTACK_Pop(SSTACK stack, SDataWord_T * value) +{ + + if (stack->top <= -1) { + + return STACK_UNDERFLOW; + } + + if (value == NULL) { + + stack->top--; + return STACK_SUCCESS; + } + + *value = stack->data[stack->top]; + stack->top--; + + return STACK_SUCCESS; +} + +int SSTACK_Top(SSTACK stack, SDataWord_T * value) +{ + + *value = 0; + + if (stack->top <= -1) { + + return STACK_UNDERFLOW; + } + + *value = stack->data[stack->top]; + + return STACK_SUCCESS; +} + +int SSTACK_Grow(SSTACK stack) +{ + + SDataWord_T *new_data; + + if ((stack->len * 2) > R_STACK_SIZE_LIMIT) { + + CON_Print(S_ERROR_PREFIX "Stack fault: growing beyond limit."); + return STACK_OVERFLOW; + } + + new_data = (SDataWord_T *)realloc(stack->data, (stack->len * 2) * sizeof *new_data); + if (new_data == NULL) { + + return STACK_MEM; + } + + stack->data = new_data; + stack->len *= 2; + + return STACK_SUCCESS; +} + +} // End of namespace Saga + diff --git a/saga/sstack.h b/saga/sstack.h new file mode 100644 index 0000000000..669d0b0423 --- /dev/null +++ b/saga/sstack.h @@ -0,0 +1,81 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Scripting engine stack component header file + + Notes: +*/ + +#ifndef SAGA_SSTACK_H +#define SAGA_SSTACK_H + +#include "script_mod.h" + +namespace Saga { + +#define R_STACK_SIZE_LIMIT 16384 + +struct SSTACK_tag { + int flags; + int len; + int top; + SDataWord_T *data; +}; + +typedef struct SSTACK_tag *SSTACK; + +typedef enum SSTACK_ERR_enum { + STACK_SUCCESS = 0, + STACK_ERROR, + STACK_MEM, + STACK_UNDERFLOW, + STACK_OVERFLOW +} SSTACK_ERR_CODE; + +typedef enum SSTACK_FLAGS_enum { + STACK_FIXED = 0x00, + STACK_GROW = 0x01 +} SSTACK_FLAGS; + +int SSTACK_Create(SSTACK * stack, int stack_len, int flags); + +int SSTACK_Destroy(SSTACK stack); + +int SSTACK_Clear(SSTACK stack); + +int SSTACK_Push(SSTACK stack, SDataWord_T value); + +int SSTACK_PushNull(SSTACK stack); + +int SSTACK_Pop(SSTACK stack, SDataWord_T * value); + +int SSTACK_Top(SSTACK stack, SDataWord_T * value); + +int SSTACK_Grow(SSTACK stack); + +} // End of namespace Saga + +#endif /* SAGA_SSTACK_H */ diff --git a/saga/stack.cpp b/saga/stack.cpp new file mode 100644 index 0000000000..ef5552d4a1 --- /dev/null +++ b/saga/stack.cpp @@ -0,0 +1,180 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Simple integer stack module + + Notes: +*/ + +#include "reinherit.h" + +#include "stack.h" +#include "stack_mod.h" + +namespace Saga { + +int ISTACK_Create(R_ISTACK * stack, int stack_len, int flags) +{ + + R_ISTACK new_stack; + int *new_stack_data; + + *stack = NULL; + + new_stack = (R_ISTACK_tag *)malloc(sizeof(struct R_ISTACK_tag)); + + if (new_stack == NULL) { + return STACK_MEM; + } + + new_stack_data = (int *)calloc(stack_len, sizeof(int)); + + if (new_stack_data == NULL) { + + free(new_stack); + return STACK_MEM; + } + + new_stack->flags = flags; + new_stack->len = stack_len; + new_stack->top = -1; + + return STACK_SUCCESS; +} + +int ISTACK_Destroy(R_ISTACK * stack) +{ + + if (stack != NULL) { + free((*stack)->data); + } + + free(stack); + + *stack = NULL; + + return STACK_SUCCESS; +} + +int ISTACK_Clear(R_ISTACK stack) +{ + + stack->top = -1; + return STACK_SUCCESS; +} + +int ISTACK_PushNull(R_ISTACK stack) +{ + + if (stack->top >= (stack->len - 1)) { + + if (stack->flags & STACK_FIXED) { + + return STACK_OVERFLOW; + } else if (ISTACK_Grow(stack) != STACK_SUCCESS) { + + return STACK_MEM; + } + } + + stack->top++; + +} + +int ISTACK_Push(R_ISTACK stack, int value) +{ + + if (stack->top >= (stack->len - 1)) { + + if (stack->flags & STACK_FIXED) { + + return STACK_OVERFLOW; + } else if (ISTACK_Grow(stack) != STACK_SUCCESS) { + + return STACK_MEM; + } + } + + stack->top++; + stack->data[stack->top] = value; + + return STACK_SUCCESS; +} + +int ISTACK_Pop(R_ISTACK stack, int *value) +{ + + if (stack->top <= -1) { + + return STACK_UNDERFLOW; + } + + if (value == NULL) { + + stack->top--; + return STACK_SUCCESS; + } + + *value = stack->data[stack->top]; + stack->top--; + + return STACK_SUCCESS; +} + +int ISTACK_Top(R_ISTACK stack, int *value) +{ + *value = 0; + + if (stack->top <= -1) { + + return STACK_UNDERFLOW; + } + + *value = stack->data[stack->top]; + + return STACK_SUCCESS; + +} + +int ISTACK_Grow(R_ISTACK stack) +{ + + int *new_data; + + new_data = (int *)realloc(stack->data, (stack->len * 2) * sizeof(int)); + + if (new_data == NULL) { + + return STACK_MEM; + }; + + stack->data = new_data; + stack->len *= 2; + + return STACK_SUCCESS; +} + +} // End of namespace Saga + diff --git a/saga/stack.h b/saga/stack.h new file mode 100644 index 0000000000..474d2d865c --- /dev/null +++ b/saga/stack.h @@ -0,0 +1,49 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Simple integer stack module private header + + Notes: +*/ + +#ifndef SAGA_STACK_H +#define SAGA_STACK_H + +namespace Saga { + +#define ISTACK_MAX + +struct R_ISTACK_tag { + + int flags; + int len; + int top; + int *data; + +}; + +} // End of namespace Saga + +#endif /* SAGA_STACK_H */ diff --git a/saga/stack_mod.h b/saga/stack_mod.h new file mode 100644 index 0000000000..09e2711c89 --- /dev/null +++ b/saga/stack_mod.h @@ -0,0 +1,69 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Simple integer stack module public header + + Notes: +*/ + +#ifndef SAGA_STACK_MOD_H +#define SAGA_STACK_MOD_H + +#include "stack.h" + +namespace Saga { + +typedef enum STACK_ERR_enum { + STACK_SUCCESS = 0, + STACK_ERROR, + STACK_MEM, + STACK_UNDERFLOW, + STACK_OVERFLOW +} STACK_ERR_CODE; + +typedef enum STACK_FLAGS_enum { + STACK_FIXED = 0x00, + STACK_GROW = 0x01 +} STACK_FLAGS; + +typedef struct R_ISTACK_tag *R_ISTACK; + +int ISTACK_Create(R_ISTACK * stack, int stack_len, int flags); + +int ISTACK_Destroy(R_ISTACK * stack); + +int ISTACK_Clear(R_ISTACK stack); + +int ISTACK_Push(R_ISTACK stack, int value); + +int ISTACK_PushNull(R_ISTACK stack); + +int ISTACK_Pop(R_ISTACK stack, int *value); + +int ISTACK_Grow(R_ISTACK stack); + +} // End of namespace Saga + +#endif /* SAGA_STACK_MOD_H */ diff --git a/saga/sthread.cpp b/saga/sthread.cpp new file mode 100644 index 0000000000..04407a1eec --- /dev/null +++ b/saga/sthread.cpp @@ -0,0 +1,1120 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Scripting module thread management component + + Notes: +*/ + +#include "reinherit.h" + +#include "yslib.h" + +#include <limits.h> + +/* + * Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "actor_mod.h" +#include "console_mod.h" +#include "text_mod.h" + +/* + * Begin module component +\*--------------------------------------------------------------------------*/ +#include "script.h" +#include "script_mod.h" + +#include "sdata.h" +#include "sstack.h" +#include "sthread.h" +#include "sfuncs.h" + +namespace Saga { + +R_SCRIPT_THREAD *STHREAD_Create(void) +{ + YS_DL_NODE *new_node; + R_SCRIPT_THREAD *new_thread; + + int result; + + if (!ScriptModule.initialized) { + + return NULL; + } + + new_thread = (R_SCRIPT_THREAD *)calloc(1, sizeof *new_thread); + if (new_thread == NULL) { + return NULL; + } + + result = SSTACK_Create(&(new_thread->stack), + R_DEF_THREAD_STACKSIZE, STACK_GROW); + + if (result != STACK_SUCCESS) { + return NULL; + } + + new_node = ys_dll_add_head(ScriptModule.thread_list, + new_thread, sizeof *new_thread); + + free(new_thread); + + return (R_SCRIPT_THREAD *)ys_dll_get_data(new_node); + +} + +int STHREAD_Destroy(R_SCRIPT_THREAD * thread) +{ + if (thread == NULL) { + return R_FAILURE; + } + + SSTACK_Destroy(thread->stack); + + return R_SUCCESS; +} + +int STHREAD_ExecThreads(int msec) +{ + YS_DL_NODE *walk_p; + R_SCRIPT_THREAD *thread; + + if (!ScriptModule.initialized) { + + return R_FAILURE; + } + + for (walk_p = ys_dll_head(ScriptModule.thread_list); + walk_p != NULL; walk_p = ys_dll_next(walk_p)) { + + thread = (R_SCRIPT_THREAD *)ys_dll_get_data(walk_p); + + if (thread->executing) { + + STHREAD_Run(thread, STHREAD_DEF_INSTR_COUNT, msec); + } + } + + return R_SUCCESS; +} + +int STHREAD_SetEntrypoint(R_SCRIPT_THREAD * thread, int ep_num) +{ + + R_SCRIPT_BYTECODE *bytecode; + int max_entrypoint; + + assert(ScriptModule.initialized); + + bytecode = ScriptModule.current_script->bytecode; + max_entrypoint = bytecode->n_entrypoints; + + if ((ep_num < 0) || (ep_num >= max_entrypoint)) { + return R_FAILURE; + } + + thread->ep_num = ep_num; + thread->ep_offset = bytecode->entrypoints[ep_num].offset; + + return R_SUCCESS; +} + +int STHREAD_Execute(R_SCRIPT_THREAD * thread, int ep_num) +{ + + assert(ScriptModule.initialized); + + if ((ScriptModule.current_script == NULL) || + (!ScriptModule.current_script->loaded)) { + + return R_FAILURE; + } + + STHREAD_SetEntrypoint(thread, ep_num); + + thread->i_offset = thread->ep_offset; + thread->executing = 1; + + return R_SUCCESS; +} + +unsigned char *GetReadPtr(R_SCRIPT_THREAD * thread) +{ + + return ScriptModule.current_script->bytecode->bytecode_p + + thread->i_offset; +} + +unsigned long GetReadOffset(const uchar * read_p) +{ + + return (unsigned long)(read_p - (unsigned char *) + ScriptModule.current_script->bytecode->bytecode_p); +} + +int STHREAD_HoldSem(R_SEMAPHORE * sem) +{ + if (sem == NULL) { + return R_FAILURE; + } + + sem->hold_count++; + + return R_SUCCESS; +} + +int STHREAD_ReleaseSem(R_SEMAPHORE * sem) +{ + if (sem == NULL) { + return R_FAILURE; + } + + sem->hold_count--; + if (sem->hold_count < 0) { + sem->hold_count = 0; + } + + return R_SUCCESS; +} + +int STHREAD_DebugStep(void) +{ + + if (ScriptModule.dbg_singlestep) { + ScriptModule.dbg_dostep = 1; + } + + return R_SUCCESS; +} + +int STHREAD_Run(R_SCRIPT_THREAD * thread, int instr_limit, int msec) +{ + + int instr_count; + + const uchar *read_p; + ulong saved_offset; + + SDataWord_T param1; + SDataWord_T param2; + + long iparam1; + long iparam2; + long iresult; + + SDataWord_T data; + + int debug_print = 0; + int n_buf; + int bitstate; + + int result; + int in_char; + int i; + + int unhandled = 0; + + /* Handle debug single-stepping */ + if ((thread == ScriptModule.dbg_thread) && ScriptModule.dbg_singlestep) { + + if (ScriptModule.dbg_dostep) { + + debug_print = 1; + + thread->sleep_time = 0; + instr_limit = 1; + ScriptModule.dbg_dostep = 0; + } else { + + return R_SUCCESS; + } + } + + for (instr_count = 0; instr_count < instr_limit; instr_count++) { + + if ((!thread->executing) || (thread->sem.hold_count)) { + break; + } + + thread->sleep_time -= msec; + if (thread->sleep_time < 0) { + thread->sleep_time = 0; + } + + if (thread->sleep_time) { + break; + } + + saved_offset = thread->i_offset; +#if 0 + R_printf(R_STDOUT, "Executing thread offset: %lu", + thread->i_offset); +#endif + read_p = GetReadPtr(thread); + + in_char = ys_read_u8(read_p, &read_p); + + switch (in_char) { + + /* Align (ALGN) */ + case 0x01: + break; + + /*-------------------------------------------------------------*\ + * STACK INSTRUCTIONS + \*-------------------------------------------------------------*/ + + /* Push nothing (PSHN) */ + case 0x02: + + SSTACK_PushNull(thread->stack); + + break; + + /* Pop nothing (POPN) */ + case 0x03: + + SSTACK_Pop(thread->stack, NULL); + + break; + + /* Push false (PSHF) */ + case 0x04: + + SSTACK_Push(thread->stack, 0); + + break; + + /* Push true (PSHT) */ + case 0x05: + + SSTACK_Push(thread->stack, 1); + + break; + + /* Push word (PUSH) */ + case 0x06: + + param1 = (SDataWord_T) ys_read_u16_le(read_p, &read_p); + SSTACK_Push(thread->stack, param1); + + break; + + /* Push word (PSHD) (dialogue string index) */ + case 0x08: + + param1 = (SDataWord_T) ys_read_u16_le(read_p, &read_p); + SSTACK_Push(thread->stack, param1); + + break; + + /*-------------------------------------------------------------*\ + * DATA INSTRUCTIONS + \*-------------------------------------------------------------*/ + + /* Test flag (TSTF) */ + case 0x0B: + + n_buf = *read_p++; + param1 = (SDataWord_T) ys_read_u16_le(read_p, &read_p); + + SDATA_GetBit(n_buf, param1, &bitstate); + SSTACK_Push(thread->stack, bitstate); + + break; + + /* Get word (GETW) */ + case 0x0C: + + n_buf = *read_p++; + param1 = ys_read_u16_le(read_p, &read_p); + + SDATA_GetWord(n_buf, param1, &data); + SSTACK_Push(thread->stack, data); + + break; + + /* Modify flag (MODF) */ + case 0x0F: + + n_buf = *read_p++; + param1 = (SDataWord_T) ys_read_u16_le(read_p, &read_p); + + bitstate = SDATA_ReadWordU(param1); + + SSTACK_Top(thread->stack, &data); + + if (bitstate) { + SDATA_SetBit(n_buf, data, 1); + } else { + SDATA_SetBit(n_buf, data, 0); + } + + break; + + /* Put word (PUTW) */ + case 0x10: + + n_buf = *read_p++; + param1 = (SDataWord_T) ys_read_u16_le(read_p, &read_p); + + SSTACK_Top(thread->stack, &data); + SDATA_PutWord(n_buf, param1, data); + + break; + + /* Modify flag and pop (MDFP) */ + case 0x13: + + n_buf = *read_p++; + param1 = (SDataWord_T) ys_read_u16_le(read_p, &read_p); + + SSTACK_Pop(thread->stack, ¶m1); + + bitstate = SDATA_ReadWordU(param1); + + if (bitstate) { + SDATA_SetBit(n_buf, param1, 1); + } else { + SDATA_SetBit(n_buf, param1, 0); + } + + break; + + /* Put word and pop (PTWP) */ + case 0x14: + + n_buf = *read_p++; + param1 = (SDataWord_T) ys_read_u16_le(read_p, &read_p); + + SSTACK_Top(thread->stack, &data); + SDATA_PutWord(n_buf, param1, data); + + break; + + /*-------------------------------------------------------------*\ + * CONTROL INSTRUCTIONS + \*-------------------------------------------------------------*/ + + /* (GOSB): Call subscript ? */ + case 0x17: + { + + int temp; + int temp2; + + temp = *read_p++; + temp2 = *read_p++; + + param1 = + (SDataWord_T) ys_read_u16_le(read_p, + &read_p); + data = GetReadOffset(read_p); + + /*SSTACK_Push( thread->stack, (SDataWord_T)temp ); */ + SSTACK_Push(thread->stack, data); + + thread->i_offset = (unsigned long)param1; + } + break; + + /* (CALL): Call function */ + case 0x19: + case 0x18: + { + int n_args; + uint func_num; + int result; + + SFunc_T sfunc; + + n_args = ys_read_u8(read_p, &read_p); + func_num = ys_read_u16_le(read_p, &read_p); + + if (func_num >= R_SFUNC_NUM) { + + CON_Print(S_ERROR_PREFIX + "Invalid script function number: (%X)\n", + func_num); + + thread->executing = 0; + break; + } + + sfunc = SFuncList[func_num].sfunc_fp; + + if (sfunc == NULL) { + + CON_Print(S_WARN_PREFIX + "%X: Undefined script function number: (%X)\n", + thread->i_offset, func_num); + + CON_Print(S_WARN_PREFIX + "Removing %d operand(s) from stack.\n", + n_args); + + for (i = 0; i < n_args; i++) { + + SSTACK_Pop(thread->stack, + NULL); + } + } else { + + result = sfunc(thread); + + if (result != R_SUCCESS) { + CON_Print(S_WARN_PREFIX + "%X: Script function %d failed.\n", + thread->i_offset, + func_num); + } + } + + } + break; + + /* (ENTR) Enter the dragon */ + case 0x1A: + + param1 = ys_read_u16_le(read_p, &read_p); + + break; + + /* (?) Unknown */ + case 0x1B: + + unhandled = 1; + break; + + /* (EXIT) End subscript */ + case 0x1C: + + result = SSTACK_Pop(thread->stack, &data); + + if (result != STACK_SUCCESS) { + + CON_Print("Script execution complete."); + thread->executing = 0; + } else { + + thread->i_offset = data; + } + break; + + /*-------------------------------------------------------------*\ + * BRANCH INSTRUCTIONS + \*-------------------------------------------------------------*/ + + /* (JMP): Unconditional jump */ + case 0x1D: + + param1 = ys_read_u16_le(read_p, &read_p); + thread->i_offset = (unsigned long)param1; + + break; + + /* (JNZP): Jump if nonzero + POP */ + case 0x1E: + + param1 = ys_read_u16_le(read_p, &read_p); + + SSTACK_Pop(thread->stack, &data); + if (data) { + thread->i_offset = (unsigned long)param1; + } + + break; + + /* (JZP): Jump if zero + POP */ + case 0x1F: + + param1 = ys_read_u16_le(read_p, &read_p); + + SSTACK_Pop(thread->stack, &data); + if (!data) { + thread->i_offset = (unsigned long)param1; + } + + break; + + /* (JNZ): Jump if nonzero */ + case 0x20: + + param1 = ys_read_u16_le(read_p, &read_p); + + SSTACK_Top(thread->stack, &data); + if (data) { + thread->i_offset = (unsigned long)param1; + } + + break; + + /* (JZ): Jump if zero */ + case 0x21: + + param1 = ys_read_u16_le(read_p, &read_p); + + SSTACK_Top(thread->stack, &data); + if (!data) { + thread->i_offset = (unsigned long)param1; + } + + break; + + /* (JMPR): Relative jump */ + case 0x57: + + /* ignored? */ + ys_read_u16_le(read_p, &read_p); + ys_read_u16_le(read_p, &read_p); + + iparam1 = (long)*read_p++; + + thread->i_offset += iparam1; + break; + + /* (SWCH): Switch */ + case 0x22: + { + + int n_switch; + unsigned int switch_num; + unsigned int switch_jmp; + unsigned int default_jmp; + int case_found = 0; + + SSTACK_Pop(thread->stack, &data); + + n_switch = ys_read_u16_le(read_p, &read_p); + + for (i = 0; i < n_switch; i++) { + + switch_num = + ys_read_u16_le(read_p, &read_p); + switch_jmp = + ys_read_u16_le(read_p, &read_p); + + /* Found the specified case */ + if (data == (SDataWord_T) switch_num) { + + thread->i_offset = switch_jmp; + case_found = 1; + break; + } + } + + /* Jump to default case */ + if (!case_found) { + + default_jmp = + ys_read_u16_le(read_p, &read_p); + thread->i_offset = default_jmp; + } + + } + break; + + /* (RJMP): Random branch */ + case 0x24: + { + int n_branch; + unsigned int branch_wt; + unsigned int branch_jmp; + + int rand_sel = 0; + int branch_found = 0; + + /* Ignored? */ + ys_read_u16_le(read_p, &read_p); + + n_branch = ys_read_u16_le(read_p, &read_p); + + for (i = 0; i < n_branch; i++) { + + branch_wt = + ys_read_u16_le(read_p, &read_p); + branch_jmp = + ys_read_u16_le(read_p, &read_p); + + if (rand_sel == i) { + + thread->i_offset = branch_jmp; + branch_found = 1; + break; + } + } + + if (!branch_found) { + CON_Print(S_ERROR_PREFIX + "%X: Random jump target out of " + "bounds.", thread->i_offset); + } + + } + break; + + /*-------------------------------------------------------------*\ + * MISC. INSTRUCTIONS + \*-------------------------------------------------------------*/ + + /* (NEG) Negate stack by 2's complement */ + case 0x25: + + SSTACK_Pop(thread->stack, &data); + data = ~data; + data++; + SSTACK_Push(thread->stack, data); + + break; + + /* (TSTZ) Test for zero */ + case 0x26: + + SSTACK_Pop(thread->stack, &data); + data = data ? 0 : 1; + SSTACK_Push(thread->stack, data); + + break; + + /* (NOT) Binary not */ + case 0x27: + + SSTACK_Pop(thread->stack, &data); + data = ~data; + SSTACK_Push(thread->stack, data); + + break; + + /* (?) */ + case 0x28: + unhandled = 1; + printf("??? "); + read_p++; + ys_read_u16_le(read_p, &read_p); + break; + + /* (?) */ + case 0x29: + unhandled = 1; + printf("??? "); + read_p++; + ys_read_u16_le(read_p, &read_p); + break; + + /* (?) */ + case 0x2A: + unhandled = 1; + printf("??? "); + read_p++; + ys_read_u16_le(read_p, &read_p); + break; + + /* (?) */ + case 0x2B: + unhandled = 1; + printf("??? "); + read_p++; + ys_read_u16_le(read_p, &read_p); + break; + + /*-------------------------------------------------------------*\ + * ARITHMETIC INSTRUCTIONS + \*-------------------------------------------------------------*/ + + /* (ADD): Addition */ + case 0x2C: + + SSTACK_Pop(thread->stack, ¶m2); + SSTACK_Pop(thread->stack, ¶m1); + iparam2 = (long)param2; + iparam1 = (long)param1; + + iresult = iparam1 + iparam2; + + SSTACK_Push(thread->stack, (SDataWord_T) iresult); + break; + + /* (SUB): Subtraction */ + case 0x2D: + + SSTACK_Pop(thread->stack, ¶m2); + SSTACK_Pop(thread->stack, ¶m1); + iparam2 = (long)param2; + iparam1 = (long)param1; + + iresult = iparam1 - iparam2; + + SSTACK_Push(thread->stack, (SDataWord_T) iresult); + break; + + /* (MULT): Integer multiplication */ + case 0x2E: + + SSTACK_Pop(thread->stack, ¶m2); + SSTACK_Pop(thread->stack, ¶m1); + iparam2 = (long)param2; + iparam1 = (long)param1; + + iresult = iparam1 * iparam2; + + SSTACK_Push(thread->stack, (SDataWord_T) iresult); + break; + + /* (DIB): Integer division */ + case 0x2F: + + SSTACK_Pop(thread->stack, ¶m2); + SSTACK_Pop(thread->stack, ¶m1); + iparam2 = (long)param2; + iparam1 = (long)param1; + + iresult = iparam1 / iparam2; + + SSTACK_Push(thread->stack, (SDataWord_T) iresult); + break; + + /* (MOD) Modulus */ + case 0x30: + + SSTACK_Pop(thread->stack, ¶m2); + SSTACK_Pop(thread->stack, ¶m1); + iparam2 = (long)param2; + iparam1 = (long)param1; + + iresult = iparam1 % iparam2; + + SSTACK_Push(thread->stack, (SDataWord_T) iresult); + break; + + /* (EQU) Test equality */ + case 0x33: + + SSTACK_Pop(thread->stack, ¶m2); + SSTACK_Pop(thread->stack, ¶m1); + iparam2 = (long)param2; + iparam1 = (long)param1; + + data = (iparam1 == iparam2) ? 1 : 0; + + SSTACK_Push(thread->stack, data); + break; + + /* (NEQU) Test inequality */ + case 0x34: + + SSTACK_Pop(thread->stack, ¶m2); + SSTACK_Pop(thread->stack, ¶m1); + iparam2 = (long)param2; + iparam1 = (long)param1; + + data = (iparam1 != iparam2) ? 1 : 0; + + SSTACK_Push(thread->stack, data); + break; + + /* (GRT) Test Greater-than */ + case 0x35: + + SSTACK_Pop(thread->stack, ¶m2); + SSTACK_Pop(thread->stack, ¶m1); + iparam2 = (long)param2; + iparam1 = (long)param1; + + data = (iparam1 > iparam2) ? 1 : 0; + + SSTACK_Push(thread->stack, data); + break; + + /* (LST) Test Less-than */ + case 0x36: + + SSTACK_Pop(thread->stack, ¶m2); + SSTACK_Pop(thread->stack, ¶m1); + iparam2 = (long)param2; + iparam1 = (long)param1; + + data = (iparam1 < iparam2) ? 1 : 0; + + SSTACK_Push(thread->stack, data); + break; + + /* (GRTE) Test Greater-than or Equal to */ + case 0x37: + + SSTACK_Pop(thread->stack, ¶m2); + SSTACK_Pop(thread->stack, ¶m1); + iparam2 = (long)param2; + iparam1 = (long)param1; + + data = (iparam1 >= iparam2) ? 1 : 0; + + SSTACK_Push(thread->stack, data); + break; + + /* (LSTE) Test Less-than or Equal to */ + case 0x38: + + SSTACK_Pop(thread->stack, ¶m2); + SSTACK_Pop(thread->stack, ¶m1); + iparam2 = (long)param2; + iparam1 = (long)param1; + + data = (iparam1 <= iparam2) ? 1 : 0; + + SSTACK_Push(thread->stack, data); + break; + + /* (SHR): Arithmetic binary shift right */ + case 0x3F: + + SSTACK_Pop(thread->stack, ¶m2); + SSTACK_Pop(thread->stack, ¶m1); + + iparam2 = (long)param2; + + /* Preserve most significant bit */ + data = + (0x01 << ((sizeof param1 * CHAR_BIT) - + 1)) & param1; + + for (i = 0; i < (int)iparam2; i++) { + param1 >>= 1; + param1 |= data; + } + + SSTACK_Push(thread->stack, param1); + break; + + /*-------------------------------------------------------------*\ + * BITWISE INSTRUCTIONS + \*-------------------------------------------------------------*/ + + /* (SHL) Binary shift left */ + case 0x40: + + SSTACK_Pop(thread->stack, ¶m2); + SSTACK_Pop(thread->stack, ¶m1); + + param1 <<= param2; + + SSTACK_Push(thread->stack, param1); + break; + + /* (AND) Binary AND */ + case 0x41: + + SSTACK_Pop(thread->stack, ¶m2); + SSTACK_Pop(thread->stack, ¶m1); + + param1 &= param2; + + SSTACK_Push(thread->stack, param1); + break; + + /* (OR) Binary OR */ + case 0x42: + + SSTACK_Pop(thread->stack, ¶m2); + SSTACK_Pop(thread->stack, ¶m1); + + param1 |= param2; + + SSTACK_Push(thread->stack, param1); + break; + + /* (XOR) Binary XOR */ + case 0x43: + + SSTACK_Pop(thread->stack, ¶m2); + SSTACK_Pop(thread->stack, ¶m1); + + param1 ^= param2; + + SSTACK_Push(thread->stack, param1); + break; + + /*-------------------------------------------------------------*\ + * BOOLEAN LOGIC INSTRUCTIONS + \*-------------------------------------------------------------*/ + + /* (LAND): Logical AND */ + case 0x44: + + SSTACK_Pop(thread->stack, ¶m2); + SSTACK_Pop(thread->stack, ¶m1); + + data = (param1 && param2) ? 1 : 0; + + SSTACK_Push(thread->stack, data); + break; + + /* (LOR): Logical OR */ + case 0x45: + + SSTACK_Pop(thread->stack, ¶m2); + SSTACK_Pop(thread->stack, ¶m1); + + data = (param1 || param2) ? 1 : 0; + + SSTACK_Push(thread->stack, data); + break; + + /* (LXOR): Logical XOR */ + case 0x46: + + SSTACK_Pop(thread->stack, ¶m2); + SSTACK_Pop(thread->stack, ¶m1); + + data = ((param1) ? !(param2) : !!(param2)); + + SSTACK_Push(thread->stack, data); + break; + + /*-------------------------------------------------------------*\ + * GAME INSTRUCTIONS + \*-------------------------------------------------------------*/ + + /* (DLGP): Play Character Dialogue */ + case 0x53: + { + int n_voices; + int a_index; + int voice_rn; + + n_voices = *read_p++; + param1 = + (SDataWord_T) ys_read_u16_le(read_p, + &read_p); + + /* ignored ? */ + *read_p++; + ys_read_u16_le(read_p, &read_p); + + a_index = ACTOR_GetActorIndex(param1); + + if (a_index < 0) { + CON_Print(S_WARN_PREFIX + "%X: DLGP Actor id not found.", + thread->i_offset); + } + + for (i = 0; i < n_voices; i++) { + + SSTACK_Pop(thread->stack, &data); + + if (a_index < 0) + continue; + + if (!ScriptModule.voice_lut_present) { + voice_rn = -1; + } else { + voice_rn = + ScriptModule. + current_script->voice-> + voices[data]; + } + + ACTOR_Speak(a_index, + ScriptModule.current_script->diag-> + str[data], voice_rn, &thread->sem); + + } + + } + break; + + /* (DLGS): Initialize dialogue interface */ + case 0x54: + break; + + /* (DLGX): Run dialogue interface */ + case 0x55: + break; + + /* (DLGO): Add a dialogue option to interface */ + case 0x56: + { + int param1; + int param2; + int param3; + + printf("DLGO | "); + param1 = *read_p++; + param2 = *read_p++; + + printf("%02X %02X ", param1, param2); + + if (param2 > 0) { + param3 = + ys_read_u16_le(read_p, &read_p); + + printf("%04X", param3); + } + } + break; + + /*-------------------------------------------------------------*\ + * End instruction list + \*-------------------------------------------------------------*/ + + default: + + CON_Print(S_ERROR_PREFIX + "%X: Invalid opcode encountered: " "(%X).\n", + thread->i_offset, in_char); + thread->executing = 0; + + break; + + } /* end switch( in_char ) */ + + /* Set instruction offset only if a previous instruction didn't + * branch */ + if (saved_offset == thread->i_offset) { + + thread->i_offset = GetReadOffset(read_p); + } + + if (unhandled) { + + CON_Print(S_ERROR_PREFIX "%X: Unhandled opcode.\n", + thread->i_offset); + thread->executing = 0; + } + + if (thread->executing && debug_print) { + SDEBUG_PrintInstr(thread); + } + + } + + return R_SUCCESS; +} + +} // End of namespace Saga + diff --git a/saga/sthread.h b/saga/sthread.h new file mode 100644 index 0000000000..0ab86dfff1 --- /dev/null +++ b/saga/sthread.h @@ -0,0 +1,69 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Scripting module thread management component header file + + Notes: +*/ + +#ifndef SAGA_STHREAD_H__ +#define SAGA_STHREAD_H__ + +#include "sstack.h" + +namespace Saga { + +#define STHREAD_DEF_INSTR_COUNT 7 + +struct R_SEMAPHORE_tag { + int hold_count; +}; + +struct R_SCRIPT_THREAD_tag { + int executing; + + int sleep_time; + int ep_num; /* Entrypoint number */ + unsigned long ep_offset; /* Entrypoint offset */ + unsigned long i_offset; /* Instruction offset */ + + R_SEMAPHORE sem; + + SSTACK stack; +}; + +R_SCRIPT_THREAD *STHREAD_Create(void); +int STHREAD_Destroy(R_SCRIPT_THREAD *thread); +int STHREAD_SetEntrypoint(R_SCRIPT_THREAD *thread, int ep_num); +int STHREAD_Execute(R_SCRIPT_THREAD *thread, int ep_num); +int STHREAD_Run(R_SCRIPT_THREAD *thread, int instr_limit, int msec); +unsigned long GetReadOffset(const uchar *read_p); +unsigned char *GetReadPtr(R_SCRIPT_THREAD *thread); +int SDEBUG_PrintInstr(R_SCRIPT_THREAD *thread); + +} // End of namespace Saga + +#endif /* SAGA_STHREAD_H__ */ diff --git a/saga/sys_fs.cpp b/saga/sys_fs.cpp new file mode 100644 index 0000000000..4fd26c5356 --- /dev/null +++ b/saga/sys_fs.cpp @@ -0,0 +1,82 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +#include "reinherit.h" + +namespace Saga { + +int +SYSFS_GetFQFN(const char *f_dir, const char *f_name, char *buf, size_t buf_len) +{ + size_t f_dir_len; + size_t f_name_len; + char sep_buf[2] = { R_DIRECTORY_SEP }; + + size_t i; + + if ((f_dir == NULL) || (f_name == NULL) || (buf == NULL)) { + + return R_FAILURE; + } + + f_dir_len = strlen(f_dir); + f_name_len = strlen(f_name); + + buf[0] = 0; + + strncat(buf, f_dir, buf_len); + +#if R_DIRECTORY_SEP != '/' + /* Convert frontslashes to backslashes */ + for (i = 0; i < f_dir_len; i++) { + if (buf[i] == '/') { + buf[i] = R_DIRECTORY_SEP; + } + } +#endif + + for (i = f_dir_len - 1; i > 0; i--) { + + /* Remove any trailing whitespace */ + if (isspace(buf[i])) { + buf[i] = 0; + } else { + break; + } + } + + f_dir_len = strlen(buf); + + if (buf[f_dir_len - 1] != R_DIRECTORY_SEP) { + + /* Append a proper directory separator if req. */ + strncat(buf, sep_buf, buf_len); + } + + strncat(buf, f_name, buf_len); + + return R_SUCCESS; +} + +} // End of namespace Saga + + diff --git a/saga/sys_interface.h b/saga/sys_interface.h new file mode 100644 index 0000000000..51391ccbdd --- /dev/null +++ b/saga/sys_interface.h @@ -0,0 +1,49 @@ +/****************************************************************************\ + ____ ___ _ _ _ +| _ \ ___|_ _|_ __ | |__ ___ _ __(_) |_ +| |_) / _ \| || '_ \| '_ \ / _ \ '__| | __| +| _ < __/| || | | | | | | __/ | | | |_ +|_| \_\___|___|_| |_|_| |_|\___|_| |_|\__| + + ---------------------------------------------------------------------------- + Project: ReInherit Engine + Version: .1a + + The ReInherit Engine is (C)2000-2001 by Daniel Balsom + This code is subject to the terms and conditions of the General Public + License (GPL). + + ---------------------------------------------------------------------------- + + File: sys_interface.h + Revision: $Revision$ + + Description: + + (Linux) System-specific interface data + + Notes: + +\****************************************************************************/ +#ifndef REINHERIT_SYSINTERFACE_H +#define REINHERIT_SYSINTERFACE_H + +namespace Saga { + +#define BYTE unsigned char +#define WORD unsigned short +#define DWORD unsigned int + +#define R_CFGFILE_NAME ".reinheritrc" + +#define R_DIRECTORY_SEP '/' + +#define R_STDOUT stdout +#define R_STDERR stderr + +#define R_printf fprintf +#define R_vprintf vfprintf + +} // End of namespace Saga + +#endif /* REINHERIT_SYSTYPES_H */ diff --git a/saga/sysgfx.cpp b/saga/sysgfx.cpp new file mode 100644 index 0000000000..bcdcd6dc6d --- /dev/null +++ b/saga/sysgfx.cpp @@ -0,0 +1,548 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +#include "reinherit.h" + +#include <SDL.h> +#include <limits.h> + +/* + * Begin module component +\*--------------------------------------------------------------------------*/ +#include "sysgfx.h" + +namespace Saga { + +R_SYSGFX_MODULE SGfxModule; + +static SDL_Color cur_pal[R_PAL_ENTRIES]; + +int SYSGFX_Init(R_SYSGFX_INIT * gfx_init) +{ + SDL_Surface *sdl_screen; + R_SURFACE r_screen; + + SDL_Surface *sdl_back_buf; + R_SURFACE r_back_buf; + + int result; + Uint32 flags; + + assert(gfx_init != NULL); + + if (gfx_init->fullscreen) { + flags = SDL_FULLSCREEN | SDL_HWPALETTE; + } else { + flags = SDL_HWPALETTE; + } + + /* Test video mode availability + * \*------------------------------------------------------------- */ + result = SDL_VideoModeOK(gfx_init->screen_w, + gfx_init->screen_h, gfx_init->screen_bpp, flags); + if (result == 0) { + R_printf(R_STDERR, + "Requested video mode (%d x %d @ %d bpp) " + "is unavailable.\n", + gfx_init->screen_w, + gfx_init->screen_h, gfx_init->screen_bpp); + + return R_FAILURE; + } + + /* Set the video mode + * \*------------------------------------------------------------- */ + sdl_screen = SDL_SetVideoMode(gfx_init->screen_w, + gfx_init->screen_h, gfx_init->screen_bpp, flags); + if (sdl_screen == NULL) { + + R_printf(R_STDERR, + "Unable to set video mode (%d x %d @ %d bpp).\n", + gfx_init->screen_w, + gfx_init->screen_h, gfx_init->screen_bpp); + + R_printf(R_STDERR, "SDL reports: %s\n", SDL_GetError()); + + return R_FAILURE; + } + + R_printf(R_STDOUT, + "Set video mode: (%d x %d @ %d bpp)\n", + sdl_screen->w, sdl_screen->h, sdl_screen->format->BitsPerPixel); + + /* Convert sdl surface data to R surface data */ + r_screen.buf = (uchar *)sdl_screen->pixels; + r_screen.buf_w = sdl_screen->w; + r_screen.buf_h = sdl_screen->h; + r_screen.buf_pitch = sdl_screen->pitch; + r_screen.bpp = gfx_init->screen_bpp; + + r_screen.clip_rect.x1 = 0; + r_screen.clip_rect.y1 = 0; + r_screen.clip_rect.x2 = sdl_screen->w - 1; + r_screen.clip_rect.y2 = sdl_screen->h - 1; + + r_screen.impl_src = sdl_screen; + + /* Create the back buffer + * \*------------------------------------------------------------- */ + sdl_back_buf = SDL_CreateRGBSurface(SDL_SWSURFACE, + gfx_init->backbuf_w, + gfx_init->backbuf_h, gfx_init->backbuf_bpp, 0, 0, 0, 0); + if (sdl_back_buf == NULL) { + + R_printf(R_STDERR, + "Unable to create back buffer (%d x %d @ %d bpp).\n", + gfx_init->backbuf_w, + gfx_init->backbuf_h, gfx_init->backbuf_bpp); + + R_printf(R_STDERR, "SDL reports: %s.\n", SDL_GetError()); + + return R_FAILURE; + } + + /* Convert sdl surface data to R surface data + * \*------------------------------------------------------------- */ + r_back_buf.buf = (uchar *)sdl_back_buf->pixels; + r_back_buf.buf_w = sdl_back_buf->w; + r_back_buf.buf_h = sdl_back_buf->h; + r_back_buf.buf_pitch = sdl_back_buf->pitch; + r_back_buf.bpp = gfx_init->backbuf_bpp; + + r_back_buf.clip_rect.x1 = 0; + r_back_buf.clip_rect.y1 = 0; + r_back_buf.clip_rect.x2 = sdl_back_buf->w - 1; + r_back_buf.clip_rect.y2 = sdl_back_buf->h - 1; + + r_back_buf.impl_src = sdl_back_buf; + + /* Set module data + * \*------------------------------------------------------------- */ + SGfxModule.sdl_screen = sdl_screen; + SGfxModule.r_screen = r_screen; + SGfxModule.sdl_back_buf = sdl_back_buf; + SGfxModule.r_back_buf = r_back_buf; + + SGfxModule.init = 1; + + return R_SUCCESS; +} + +R_SURFACE *SYSGFX_GetScreenSurface(void) +{ + return &SGfxModule.r_screen; +} + +R_SURFACE *SYSGFX_GetBackBuffer(void) +{ + return &SGfxModule.r_back_buf; +} + +int SYSGFX_LockSurface(R_SURFACE * surface) +{ + int result; + + assert(surface != NULL); + + result = SDL_LockSurface((SDL_Surface *) surface->impl_src); + + return (result == 0) ? R_SUCCESS : R_FAILURE; +} + +int SYSGFX_UnlockSurface(R_SURFACE * surface) +{ + assert(surface != NULL); + + SDL_UnlockSurface((SDL_Surface *) surface->impl_src); + + return R_SUCCESS; +} + +R_SURFACE *SYSGFX_FormatToDisplay(R_SURFACE * surface) +{ + R_SURFACE *new_r_surface; + SDL_Surface *new_sdl_surface; + + new_r_surface = (R_SURFACE *)malloc(sizeof *new_r_surface); + if (new_r_surface == NULL) { + return NULL; + } + + new_sdl_surface = SDL_DisplayFormat((SDL_Surface *)surface->impl_src); + if (new_sdl_surface == NULL) { + free(new_r_surface); + return NULL; + } + + new_r_surface->buf = (uchar *)new_sdl_surface->pixels; + new_r_surface->buf_w = new_sdl_surface->w; + new_r_surface->buf_h = new_sdl_surface->h; + new_r_surface->buf_pitch = new_sdl_surface->pitch; + new_r_surface->bpp = new_sdl_surface->format->BitsPerPixel; + + new_r_surface->clip_rect.x1 = 0; + new_r_surface->clip_rect.y1 = 0; + new_r_surface->clip_rect.x2 = new_sdl_surface->w - 1; + new_r_surface->clip_rect.y2 = new_sdl_surface->h - 1; + + new_r_surface->impl_src = new_sdl_surface; + + return new_r_surface; +} + +R_SURFACE *SYSGFX_CreateSurface(int w, int h, int bpp) +{ + R_SURFACE *new_surface; + SDL_Surface *new_sdl_surface; + + assert(bpp == 8); /* 16bpp not supported, maybe not necessary? */ + assert((w > 0) && (h > 0)); + + new_surface = (R_SURFACE *)malloc(sizeof *new_surface); + if (new_surface == NULL) { + return NULL; + } + + new_sdl_surface = + SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, bpp, 0, 0, 0, 0); + if (new_sdl_surface == NULL) { + + free(new_surface); + return NULL; + } + + new_surface->buf_w = new_sdl_surface->w; + new_surface->buf_h = new_sdl_surface->h; + new_surface->buf_pitch = new_sdl_surface->pitch; + new_surface->bpp = new_sdl_surface->format->BitsPerPixel; + + new_surface->clip_rect.x1 = 0; + new_surface->clip_rect.y1 = 0; + new_surface->clip_rect.x2 = w - 1; + new_surface->clip_rect.y2 = h - 1; + + new_surface->impl_src = new_sdl_surface; + + return new_surface; +} + +int SYSGFX_DestroySurface(R_SURFACE * surface) +{ + SDL_FreeSurface((SDL_Surface *) surface->impl_src); + + free(surface); + + return R_SUCCESS; +} + +int SYSGFX_GetWhite(void) +{ + return SGfxModule.white_index; +} + +int SYSGFX_GetBlack(void) +{ + return SGfxModule.black_index; +} + +int SYSGFX_MatchColor(unsigned long colormask) +{ + + int i; + + int red = (colormask & 0x0FF0000UL) >> 16; + int green = (colormask & 0x000FF00UL) >> 8; + int blue = colormask & 0x00000FFUL; + + int dr; + int dg; + int db; + + long color_delta; + long best_delta = LONG_MAX; + int best_index = 0; + + for (i = 0; i < R_PAL_ENTRIES; i++) { + + dr = cur_pal[i].r - red; + dr = ABS(dr); + + dg = cur_pal[i].g - green; + dg = ABS(dg); + + db = cur_pal[i].b - blue; + db = ABS(db); + +#if R_COLORSEARCH_SQUARE + color_delta = (long)((dr * dr) * R_RED_WEIGHT + + (dg * dg) * R_GREEN_WEIGHT + (db * db) * R_BLUE_WEIGHT); +#else + color_delta = (long)(dr * R_RED_WEIGHT + + dg * R_GREEN_WEIGHT + db * R_BLUE_WEIGHT); +#endif + if (color_delta == 0) { + return i; + } + + if (color_delta < best_delta) { + best_delta = color_delta; + best_index = i; + } + } + + return best_index; +} + +int SYSGFX_SetPalette(R_SURFACE *surface, PALENTRY *pal) +{ + + uchar red; + uchar green; + uchar blue; + + int color_delta; + int best_wdelta = 0; + int best_windex = 0; + int best_bindex = 0; + int best_bdelta = 1000; + + int i; + + for (i = 0; i < R_PAL_ENTRIES; i++) { + + red = pal[i].red; + cur_pal[i].r = red; + + color_delta = red; + + green = pal[i].green; + cur_pal[i].g = green; + + color_delta += green; + + blue = pal[i].blue; + cur_pal[i].b = blue; + + color_delta += blue; + + if (color_delta < best_bdelta) { + best_bindex = i; + best_bdelta = color_delta; + } + + if (color_delta > best_wdelta) { + best_windex = i; + best_wdelta = color_delta; + } + } + + /* Set whitest and blackest color indices */ + SGfxModule.white_index = best_windex; + SGfxModule.black_index = best_bindex; + + /* If the screen surface is palettized, set the screen palette. + * If the screen surface is not palettized, set the palette of + * the surface parameter */ + if (SGfxModule.r_screen.bpp < 16) { + + SDL_SetColors(SGfxModule.sdl_screen, cur_pal, 0, + R_PAL_ENTRIES); + } else { + + SDL_SetColors((SDL_Surface *) surface->impl_src, + cur_pal, 0, R_PAL_ENTRIES); + } + + return R_SUCCESS; +} + +int SYSGFX_GetCurrentPal(PALENTRY * src_pal) +{ + + int i; + + for (i = 0; i < R_PAL_ENTRIES; i++) { + + src_pal[i].red = cur_pal[i].r; + src_pal[i].green = cur_pal[i].g; + src_pal[i].blue = cur_pal[i].b; + } + + return R_SUCCESS; +} + +int SYSGFX_PalToBlack(R_SURFACE * surface, PALENTRY * src_pal, double percent) +{ + + int i; + + /*int fade_max = 255; */ + int new_entry; + + double fpercent; + + if (percent > 1.0) { + percent = 1.0; + } + + /* Exponential fade */ + fpercent = percent * percent; + + fpercent = 1.0 - fpercent; + + /* Use the correct percentage change per frame for each palette entry */ + for (i = 0; i < R_PAL_ENTRIES; i++) { + + new_entry = (int)(src_pal[i].red * fpercent); + + if (new_entry < 0) { + cur_pal[i].r = 0; + } else { + cur_pal[i].r = (uchar) new_entry; + } + + new_entry = (int)(src_pal[i].green * fpercent); + + if (new_entry < 0) { + cur_pal[i].g = 0; + } else { + cur_pal[i].g = (uchar) new_entry; + } + + new_entry = (int)(src_pal[i].blue * fpercent); + + if (new_entry < 0) { + cur_pal[i].b = 0; + } else { + cur_pal[i].b = (uchar) new_entry; + } + } + + /* If the screen surface is palettized, set the screen palette. + * If the screen surface is not palettized, set the palette of + * the surface parameter */ + if (SGfxModule.r_screen.bpp < 16) { + + SDL_SetColors(SGfxModule.sdl_screen, cur_pal, 0, + R_PAL_ENTRIES); + } else { + + SDL_SetColors((SDL_Surface *) surface->impl_src, + cur_pal, 0, R_PAL_ENTRIES); + } + + return R_SUCCESS; + +} + +int SYSGFX_BlackToPal(R_SURFACE * surface, PALENTRY * src_pal, double percent) +{ + + int new_entry; + double fpercent; + + int color_delta; + int best_wdelta = 0; + int best_windex = 0; + int best_bindex = 0; + int best_bdelta = 1000; + + int i; + + if (percent > 1.0) { + percent = 1.0; + } + + /* Exponential fade */ + fpercent = percent * percent; + + fpercent = 1.0 - fpercent; + + /* Use the correct percentage change per frame for each palette entry */ + for (i = 0; i < R_PAL_ENTRIES; i++) { + + new_entry = (int)(src_pal[i].red - src_pal[i].red * fpercent); + + if (new_entry < 0) { + cur_pal[i].r = 0; + } else { + cur_pal[i].r = (uchar) new_entry; + } + + new_entry = + (int)(src_pal[i].green - src_pal[i].green * fpercent); + + if (new_entry < 0) { + cur_pal[i].g = 0; + } else { + cur_pal[i].g = (uchar) new_entry; + } + + new_entry = + (int)(src_pal[i].blue - src_pal[i].blue * fpercent); + + if (new_entry < 0) { + cur_pal[i].b = 0; + } else { + cur_pal[i].b = (uchar) new_entry; + } + } + + /* Find the best white and black color indices again */ + if (percent >= 1.0) { + + for (i = 0; i < R_PAL_ENTRIES; i++) { + + color_delta = cur_pal[i].r; + color_delta += cur_pal[i].g; + color_delta += cur_pal[i].b; + + if (color_delta < best_bdelta) { + best_bindex = i; + best_bdelta = color_delta; + } + + if (color_delta > best_wdelta) { + best_windex = i; + best_wdelta = color_delta; + } + } + } + + /* If the screen surface is palettized, set the screen palette. + * If the screen surface is not palettized, set the palette of + * the surface parameter */ + if (SGfxModule.r_screen.bpp < 16) { + + SDL_SetColors(SGfxModule.sdl_screen, cur_pal, 0, + R_PAL_ENTRIES); + } else { + + SDL_SetColors((SDL_Surface *) surface->impl_src, + cur_pal, 0, R_PAL_ENTRIES); + } + + return R_SUCCESS; +} + +} // End of namespace Saga + diff --git a/saga/sysgfx.h b/saga/sysgfx.h new file mode 100644 index 0000000000..3d37e29fdb --- /dev/null +++ b/saga/sysgfx.h @@ -0,0 +1,51 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +#ifndef SYSGFX_H_ +#define SYSGFX_H_ + +namespace Saga { + +#define R_COLORSEARCH_SQUARE 0 + +#define R_RED_WEIGHT 0.299 +#define R_GREEN_WEIGHT 0.587 +#define R_BLUE_WEIGHT 0.114 + +typedef struct R_SYSGFX_MODULE_tag { + + int init; + + SDL_Surface *sdl_screen; /* Screen surface */ + R_SURFACE r_screen; + + SDL_Surface *sdl_back_buf; /* Double buffer surface */ + R_SURFACE r_back_buf; + + int white_index; + int black_index; + +} R_SYSGFX_MODULE; + +} // End of namespace Saga + +#endif /* SYSGFX_H_ */ diff --git a/saga/sysinput.cpp b/saga/sysinput.cpp new file mode 100644 index 0000000000..4edab7ce22 --- /dev/null +++ b/saga/sysinput.cpp @@ -0,0 +1,238 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +#include "reinherit.h" + +#include <SDL.h> + +/* + * Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "actor_mod.h" +#include "console_mod.h" +#include "interface_mod.h" +#include "render_mod.h" +#include "scene_mod.h" +#include "script_mod.h" + +namespace Saga { + +/* + * Begin module component +\*--------------------------------------------------------------------------*/ + +int SYSINPUT_Init(void) +{ + + SDL_EnableUNICODE(1); + SDL_EnableKeyRepeat(200, 30); + + return R_SUCCESS; +} + +int SYSINPUT_ProcessInput(void) +{ + SDL_Event sdl_event; + + int mouse_x, mouse_y; + R_POINT imouse_pt; + + SYSINPUT_GetMousePos(&mouse_x, &mouse_y); + + imouse_pt.x = mouse_x; + imouse_pt.y = mouse_y; + + RENDER_ConvertMousePt(&imouse_pt); + + while (SDL_PollEvent(&sdl_event)) { + + int in_char; + + switch (sdl_event.type) { + + case SDL_KEYDOWN: + + if (CON_IsActive()) { + + in_char = sdl_event.key.keysym.sym; + + switch (sdl_event.key.keysym.sym) { + + case SDLK_BACKQUOTE: + CON_Deactivate(); + break; + + case SDLK_PAGEUP: + CON_PageUp(); + break; + + case SDLK_PAGEDOWN: + CON_PageDown(); + break; + + case SDLK_UP: + case SDLK_KP8: + CON_CmdUp(); + break; + + case SDLK_DOWN: + case SDLK_KP2: + CON_CmdDown(); + break; + + default: + + if ((sdl_event.key.keysym. + unicode & 0xFF80) == 0) { + + in_char = + sdl_event.key.keysym. + unicode & 0x7F; + if (in_char) { + CON_Type(in_char); + } + } else { + R_printf(R_STDOUT, + "Ignored UNICODE character.\n"); + } + + break; + } + + break; + } + + switch (sdl_event.key.keysym.sym) { + + case SDLK_BACKQUOTE: + CON_Activate(); + break; + + case SDLK_q: + R_printf(R_STDOUT, "Quit key pressed.\n"); + /*goto done; */ + break; + + case SDLK_r: + INTERFACE_Draw(); + break; + + case SDLK_F1: + RENDER_ToggleFlag(RF_SHOW_FPS); + break; + + case SDLK_F2: + RENDER_ToggleFlag(RF_PALETTE_TEST); + break; + + case SDLK_F3: + RENDER_ToggleFlag(RF_TEXT_TEST); + break; + + case SDLK_F4: + RENDER_ToggleFlag(RF_OBJECTMAP_TEST); + break; + + case SDLK_1: + RENDER_SetMode(RM_NORMAL); + break; + + case SDLK_4: + RENDER_SetMode(RM_2XSAI); + break; + + case SDLK_5: + RENDER_SetMode(RM_SUPER2XSAI); + break; + + case SDLK_6: + RENDER_SetMode(RM_SUPEREAGLE); + break; + + case SDLK_TAB: + STHREAD_DebugStep(); + break; + + /* Actual game keys */ + + case SDLK_SPACE: + + ACTOR_SkipDialogue(); + break; + + case SDLK_PAUSE: + case SDLK_p: + RENDER_ToggleFlag(RF_RENDERPAUSE); + break; + + case SDLK_ESCAPE: + /* Skip to next scene skip target */ + SCENE_Skip(); + break; + + default: + break; + } + + break; + + case SDL_KEYUP: + break; + + case SDL_MOUSEBUTTONDOWN: + INTERFACE_Update(&imouse_pt, UPDATE_MOUSECLICK); + break; + + default: + break; + } + } + + return R_SUCCESS; +} + +int SYSINPUT_GetMousePos(int *mouse_x, int *mouse_y) +{ + + SDL_GetMouseState(mouse_x, mouse_y); + + return R_SUCCESS; +} + +int SYSINPUT_HideMouse(void) +{ + + SDL_ShowCursor(SDL_DISABLE); + + return R_SUCCESS; +} + +int SYSINPUT_ShowMouse(void) +{ + + SDL_ShowCursor(SDL_ENABLE); + + return R_SUCCESS; +} + +} // End of namespace Saga + diff --git a/saga/sysio.cpp b/saga/sysio.cpp new file mode 100644 index 0000000000..4f688ba607 --- /dev/null +++ b/saga/sysio.cpp @@ -0,0 +1,65 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#include "reinherit.h" + +#include "SDL.h" + +namespace Saga { + +/* + * Uses the following modules: +\*--------------------------------------------------------------------------*/ + +/* + * Begin module component +\*--------------------------------------------------------------------------*/ + +int SYSIO_Init(void) +{ + + int result; + + /* Initialize SDL library */ + result = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_AUDIO); + + if (result != 0) { + + R_printf(R_STDERR, "SDL library initialization failed.\n"); + + return R_FAILURE; + } + + R_printf(R_STDOUT, "SDL library initialized.\n"); + + return R_SUCCESS; +} + +int SYSIO_Shutdown(void) +{ + + return R_SUCCESS; +} + +} // End of namespace Saga + diff --git a/saga/sysmusic.cpp b/saga/sysmusic.cpp new file mode 100644 index 0000000000..2c230679bf --- /dev/null +++ b/saga/sysmusic.cpp @@ -0,0 +1,98 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +#include "reinherit.h" + +#include "yslib.h" + +namespace Saga { + +static int MusicInitialized = 0; + +int SYSMUSIC_Init(int enabled) +{ + YS_IGNORE_PARAM(enabled); + + if (MusicInitialized) { + return R_FAILURE; + } + + MusicInitialized = 1; + return R_SUCCESS; +} + +int SYSMUSIC_Shutdown(void) +{ + if (!MusicInitialized) { + return R_FAILURE; + } + + MusicInitialized = 0; + return R_SUCCESS; +} + +int SYSMUSIC_Play(ulong music_rn, uint flags) +{ + if (!MusicInitialized) { + return R_FAILURE; + } + + YS_IGNORE_PARAM(music_rn); + YS_IGNORE_PARAM(flags); + + return R_SUCCESS; + +} + +int SYSMUSIC_Pause(void) +{ + if (!MusicInitialized) { + return R_FAILURE; + } + + return R_SUCCESS; + +} + +int SYSMUSIC_Resume(void) +{ + if (!MusicInitialized) { + return R_FAILURE; + } + + return R_SUCCESS; + +} + +int SYSMUSIC_Stop(void) +{ + + if (!MusicInitialized) { + return R_FAILURE; + } + + return R_SUCCESS; + +} + +} // End of namespace Saga + diff --git a/saga/syssound.cpp b/saga/syssound.cpp new file mode 100644 index 0000000000..ca50536ffa --- /dev/null +++ b/saga/syssound.cpp @@ -0,0 +1,173 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +#include "reinherit.h" + +#include "yslib.h" + +/* + * Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "game_mod.h" +#include "rscfile_mod.h" + +namespace Saga { + +/* + * Begin module component +\*--------------------------------------------------------------------------*/ + +static int SoundInitialized = 0; + +static R_RSCFILE_CONTEXT *SoundContext; +static R_RSCFILE_CONTEXT *VoiceContext; + +int SYSSOUND_Init(int enabled) +{ + + int result; + + YS_IGNORE_PARAM(enabled); + + if (SoundInitialized) { + return R_FAILURE; + } + + /* Load sound module resource file contexts + * \*------------------------------------------------------------- */ + result = GAME_GetFileContext(&SoundContext, R_GAME_SOUNDFILE, 0); + if (result != R_SUCCESS) { + return R_FAILURE; + } + + result = GAME_GetFileContext(&VoiceContext, R_GAME_VOICEFILE, 0); + if (result != R_SUCCESS) { + return R_FAILURE; + } + + SoundInitialized = 1; + return R_SUCCESS; +} + +int SYSSOUND_Shutdown() +{ + if (!SoundInitialized) { + return R_FAILURE; + } + + SoundInitialized = 0; + + return R_SUCCESS; +} + +int SYSSOUND_Play(int sound_rn, int channel) +{ + + (void)sound_rn; + (void)channel; + + if (!SoundInitialized) { + return R_FAILURE; + } + + return R_SUCCESS; +} + +int SYSSOUND_Pause(int channel) +{ + + (void)channel; + + if (!SoundInitialized) { + return R_FAILURE; + } + + return R_SUCCESS; +} + +int SYSSOUND_Resume(int channel) +{ + + (void)channel; + + if (!SoundInitialized) { + return R_FAILURE; + } + + return R_SUCCESS; +} + +int SYSSOUND_Stop(int channel) +{ + + (void)channel; + + if (!SoundInitialized) { + return R_FAILURE; + } + + return R_SUCCESS; +} + +int SYSSOUND_PlayVoice(R_SOUNDBUFFER * buf) +{ + + (void)buf; + + if (!SoundInitialized) { + return R_FAILURE; + } + + return R_SUCCESS; +} + +int SYSSOUND_PauseVoice(void) +{ + + if (!SoundInitialized) { + return R_FAILURE; + } + + return R_SUCCESS; +} + +int SYSSOUND_ResumeVoice(void) +{ + + if (!SoundInitialized) { + return R_FAILURE; + } + + return R_SUCCESS; +} + +int SYSSOUND_StopVoice(void) +{ + + if (!SoundInitialized) { + return R_FAILURE; + } + + return R_SUCCESS; +} + +} // End of namespace Saga diff --git a/saga/systimer.cpp b/saga/systimer.cpp new file mode 100644 index 0000000000..dd76f43849 --- /dev/null +++ b/saga/systimer.cpp @@ -0,0 +1,144 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +#include "reinherit.h" + +#include <SDL.h> + +/* + * Begin module +\*--------------------------------------------------------------------------*/ +#include "systimer.h" + +namespace Saga { + +R_SYSTIMER_DATA R_TimerData; + +int SYSTIMER_InitMSCounter(void) +{ + + if (R_TimerData.initialized) { + return R_FAILURE; + } + + R_TimerData.t_previous_ticks = SDL_GetTicks(); + + R_TimerData.initialized = 1; + + return R_SUCCESS; +} + +unsigned long SYSTIMER_ReadMSCounter(void) +{ + + Uint32 ms_elapsed = 0; + + if (!R_TimerData.initialized) { + return 0; + } + + R_TimerData.t_current_ticks = SDL_GetTicks(); + + if (R_TimerData.t_current_ticks < R_TimerData.t_previous_ticks) { + /* Timer has rolled over after 49 days... */ + } else { + ms_elapsed = R_TimerData.t_current_ticks - + R_TimerData.t_previous_ticks; + + R_TimerData.t_previous_ticks = R_TimerData.t_current_ticks; + } + + return ms_elapsed; +} + +int SYSTIMER_ResetMSCounter(void) +{ + + if (!R_TimerData.initialized) { + return R_FAILURE; + } + + R_TimerData.t_previous_ticks = SDL_GetTicks(); + + return R_SUCCESS; +} + +int SYSTIMER_Sleep(uint msec) +{ + SDL_Delay(msec); + + return R_SUCCESS; +} + +int +SYSTIMER_CreateTimer(R_SYSTIMER ** timer, + unsigned long interval, void *param, R_SYSTIMER_CALLBACK callback) +{ + R_SYSTIMER *new_timer = (R_SYSTIMER *)malloc(sizeof *new_timer); + if (new_timer == NULL) { + return R_MEM; + } + + new_timer->t_interval = interval; + new_timer->t_param = param; + new_timer->t_callback_f = callback; + + *timer = new_timer; + + new_timer->t_sdl_timerid = SDL_AddTimer(interval, + SYSTIMER_Callback, new_timer); + + if (new_timer->t_sdl_timerid == NULL) { + free(new_timer); + *timer = NULL; + + return R_FAILURE; + } + + return R_SUCCESS; +} + +int SYSTIMER_DestroyTimer(R_SYSTIMER * timer) +{ + if (timer == NULL) { + return R_FAILURE; + } + + timer->t_running = 0; + + SDL_RemoveTimer(timer->t_sdl_timerid); + + free(timer); + + return R_SUCCESS; +} + +Uint32 SYSTIMER_Callback(Uint32 interval, void *param) +{ + R_SYSTIMER *timer_p = (R_SYSTIMER *)param; + + timer_p->t_callback_f(timer_p->t_interval, timer_p->t_param); + + return timer_p->t_interval; +} + +} // End of namespace Saga diff --git a/saga/systimer.h b/saga/systimer.h new file mode 100644 index 0000000000..19398ba567 --- /dev/null +++ b/saga/systimer.h @@ -0,0 +1,54 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +#ifndef SAGA_SYSTIMER_H__ +#define SAGA_SYSTIMER_H__ + +namespace Saga { + +typedef struct R_SYSTIMER_DATA_tag { + + int initialized; + + Uint32 t_start_ticks; + + Uint32 t_current_ticks; + Uint32 t_previous_ticks; + +} R_SYSTIMER_DATA; + +struct R_SYSTIMER_tag { + + int t_running; + + unsigned long t_interval; + void *t_param; + + R_SYSTIMER_CALLBACK t_callback_f; + SDL_TimerID t_sdl_timerid; +}; + +Uint32 SYSTIMER_Callback(Uint32 interval, void *param); + +} // End of namespace Saga + +#endif /* SAGA_SYSTIMER_H__ */ diff --git a/saga/text.cpp b/saga/text.cpp new file mode 100644 index 0000000000..80367169c9 --- /dev/null +++ b/saga/text.cpp @@ -0,0 +1,342 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Text / dialogue display management module + + Notes: +*/ + +#include "reinherit.h" + +#include "yslib.h" + +/* + * Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "font_mod.h" + +/* + * Begin module +\*--------------------------------------------------------------------------*/ +#include "text_mod.h" +#include "text.h" + +namespace Saga { + +int +TEXT_Draw(int font_id, + R_SURFACE * ds, + const char *string, + int text_x, int text_y, int color, int effect_color, int flags) +{ + + int string_w; + int string_len; + + int fit_w; + + const char *start_p; + const char *search_p; + const char *measure_p; + const char *found_p; + int len; + int w; + const char *end_p; + int h; + int wc; + + int w_total; + int len_total; + + string_len = strlen(string); + + if (flags & FONT_CENTERED) { + + /* Text is centered... format output */ + + /* Enforce minimum and maximum center points for centered text */ + if (text_x < R_TEXT_CENTERLIMIT) { + text_x = R_TEXT_CENTERLIMIT; + } + + if (text_x > ds->buf_w - R_TEXT_CENTERLIMIT) { + text_x = ds->buf_w - R_TEXT_CENTERLIMIT; + } + + if (text_x < (R_TEXT_MARGIN * 2)) { + /* Text can't be centered if it's too close to the margin */ + return R_FAILURE; + } + + string_w = + FONT_GetStringWidth(font_id, string, string_len, flags); + + if (text_x < (ds->buf_w / 2)) { + /* Fit to right side */ + fit_w = (text_x - R_TEXT_MARGIN) * 2; + } else { + /* Fit to left side */ + fit_w = ((ds->buf_w - R_TEXT_MARGIN) - text_x) * 2; + } + + if (fit_w >= string_w) { + + /* Entire string fits, draw it */ + text_x = text_x - (string_w / 2); + + FONT_Draw(font_id, + ds, + string, + string_len, + text_x, text_y, color, effect_color, flags); + + return R_SUCCESS; + } + + /* String won't fit on one line ... */ + + h = FONT_GetHeight(font_id); + w_total = 0; + len_total = 0; + wc = 0; + + start_p = string; + measure_p = string; + search_p = string; + end_p = string + string_len; + + for (;;) { + + found_p = strchr(search_p, ' '); + + if (found_p == NULL) { + /* Ran to the end of the buffer */ + len = end_p - measure_p; + } else { + len = found_p - measure_p; + } + + w = FONT_GetStringWidth(font_id, measure_p, len, + flags); + measure_p = found_p; + + if ((w_total + w) > fit_w) { + /* This word won't fit */ + if (wc == 0) { + /* The first word in the line didn't fit. abort */ + return R_SUCCESS; + } + + /* Wrap what we've got and restart */ + FONT_Draw(font_id, + ds, + start_p, + len_total, + text_x - (w_total / 2), + text_y, color, effect_color, flags); + + text_y += h + R_TEXT_LINESPACING; + w_total = 0; + len_total = 0; + wc = 0; + measure_p = search_p; + start_p = search_p; + + } else { + /* Word will fit ok */ + w_total += w; + len_total += len; + wc++; + + if (found_p == NULL) { + /* Since word hit NULL but fit, we are done */ + FONT_Draw(font_id, + ds, + start_p, + len_total, + text_x - (w_total / 2), + text_y, + color, effect_color, flags); + + return R_SUCCESS; + } + + search_p = measure_p + 1; + } + } /* End for (;;) */ + + } else { + + /* Text is not centered; No formatting required */ + + FONT_Draw(font_id, + ds, + string, + string_len, text_x, text_y, color, effect_color, flags); + + } + + return R_SUCCESS; +} + +R_TEXTLIST *TEXT_CreateList(void) +{ + R_TEXTLIST *new_textlist; + + new_textlist = (R_TEXTLIST *)malloc(sizeof *new_textlist); + + if (new_textlist == NULL) { + return NULL; + } + + new_textlist->list = ys_dll_create(); + + if (new_textlist->list == NULL) { + free(new_textlist); + return NULL; + } + + return new_textlist; +} + +void TEXT_ClearList(R_TEXTLIST * tlist) +{ + if (tlist != NULL) { + ys_dll_delete_all(tlist->list); + } + + return; +} + +void TEXT_DestroyList(R_TEXTLIST * tlist) +{ + if (tlist != NULL) { + ys_dll_destroy(tlist->list); + } + free(tlist); + + return; +} + +int TEXT_DrawList(R_TEXTLIST * textlist, R_SURFACE * ds) +{ + + R_TEXTLIST_ENTRY *entry_p; + YS_DL_NODE *walk_p; + + assert((textlist != NULL) && (ds != NULL)); + + for (walk_p = ys_dll_head(textlist->list); + walk_p != NULL; walk_p = ys_dll_next(walk_p)) { + + entry_p = (R_TEXTLIST_ENTRY *)ys_dll_get_data(walk_p); + + if (entry_p->display != 0) { + + TEXT_Draw(entry_p->font_id, + ds, + entry_p->string, + entry_p->text_x, + entry_p->text_y, + entry_p->color, + entry_p->effect_color, entry_p->flags); + } + } + + return R_SUCCESS; +} + +int TEXT_ProcessList(R_TEXTLIST * textlist, long ms) +{ + R_TEXTLIST_ENTRY *entry_p; + YS_DL_NODE *walk_p; + YS_DL_NODE *temp_p; + + for (walk_p = ys_dll_head(textlist->list); + walk_p != NULL; walk_p = temp_p) { + + temp_p = ys_dll_next(walk_p); + + entry_p = (R_TEXTLIST_ENTRY *)ys_dll_get_data(walk_p); + + if (entry_p->flags & TEXT_TIMEOUT) { + + entry_p->time -= ms; + if (entry_p->time <= 0) { + + ys_dll_delete(walk_p); + } + } + } + + return R_SUCCESS; + +} + +R_TEXTLIST_ENTRY *TEXT_AddEntry(R_TEXTLIST * textlist, + R_TEXTLIST_ENTRY * entry) +{ + YS_DL_NODE *new_node = NULL; + + if (entry != NULL) { + new_node = + ys_dll_add_tail(textlist->list, entry, sizeof *entry); + } + + return (new_node != NULL) ? (R_TEXTLIST_ENTRY *)new_node->data : NULL; +} + +int TEXT_SetDisplay(R_TEXTLIST_ENTRY * entry, int val) +{ + if (entry != NULL) { + entry->display = !!val; + return R_SUCCESS; + } + + return R_FAILURE; +} + +int TEXT_DeleteEntry(R_TEXTLIST * textlist, R_TEXTLIST_ENTRY * entry) +{ + YS_DL_NODE *walk_p; + + if (entry == NULL) { + return R_FAILURE; + } + + for (walk_p = ys_dll_head(textlist->list); + walk_p != NULL; walk_p = ys_dll_next(walk_p)) { + + if (entry == ys_dll_get_data(walk_p)) { + ys_dll_delete(walk_p); + break; + } + } + + return R_SUCCESS; +} + +} // End of namespace Saga + diff --git a/saga/text.h b/saga/text.h new file mode 100644 index 0000000000..49adac7053 --- /dev/null +++ b/saga/text.h @@ -0,0 +1,46 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Text / dialogue display management module private header + + Notes: +*/ + +#ifndef SAGA_TEXT_H__ +#define SAGA_TEXT_H__ + +namespace Saga { + +#define R_TEXT_CENTERLIMIT 50 +#define R_TEXT_MARGIN 10 +#define R_TEXT_LINESPACING 2 + +struct R_TEXTLIST_tag { + YS_DL_LIST *list; +}; + +} // End of namespace Saga +#endif /* SAGA_TEXT_H__ */ diff --git a/saga/text_mod.h b/saga/text_mod.h new file mode 100644 index 0000000000..b136a3b34a --- /dev/null +++ b/saga/text_mod.h @@ -0,0 +1,70 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Text / dialogue display management module public header + + Notes: +*/ + +#ifndef SAGA_TEXT_MOD_H_ +#define SAGA_TEXT_MOD_H_ + +namespace Saga { + +enum R_TEXT_FLAGS { + TEXT_TIMEOUT = 0x01 +}; + +typedef struct R_TEXTLIST_ENTRY_tag { + struct R_TEXTLIST_ENTRY_tag *next; + struct R_TEXTLIST_ENTRY_tag *prev; + int display; + int id; + int text_x; + int text_y; + int color; + int effect_color; + int flags; + int font_id; + long time; + char *string; +} R_TEXTLIST_ENTRY; + +typedef struct R_TEXTLIST_tag R_TEXTLIST; + +R_TEXTLIST *TEXT_CreateList(void); +void TEXT_DestroyList(R_TEXTLIST *textlist); +void TEXT_ClearList(R_TEXTLIST *textlist); +int TEXT_DrawList(R_TEXTLIST *textlist, R_SURFACE *ds); +R_TEXTLIST_ENTRY *TEXT_AddEntry(R_TEXTLIST *textlist, R_TEXTLIST_ENTRY *entry); +int TEXT_DeleteEntry(R_TEXTLIST *textlist, R_TEXTLIST_ENTRY *entry); +int TEXT_SetDisplay(R_TEXTLIST_ENTRY *entry, int val); +int TEXT_Draw(int font_id, R_SURFACE *ds, const char *string, int text_x, + int text_y, int color, int effect_color, int flags); +int TEXT_ProcessList(R_TEXTLIST *textlist, long ms); + +} // End of namespace Saga + +#endif /* SAGA_TEXT_MOD_H_ */ diff --git a/saga/transitions.cpp b/saga/transitions.cpp new file mode 100644 index 0000000000..759652593d --- /dev/null +++ b/saga/transitions.cpp @@ -0,0 +1,83 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + Background transition routines + + Notes: +*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "yslib.h" + +#include "reinherit.h" + +namespace Saga { + +int +TRANSITION_Dissolve(uchar * dst_img, + int dst_w, + int dst_h, + int dst_p, const uchar * src_img, int src_p, int flags, double percent) +{ +#define XOR_MASK 0xB400; + + int pixelcount = dst_w * dst_h; + int seqlimit = (int)(65535 * percent); + + int seq = 1; + int i; + + YS_IGNORE_PARAM(flags); + YS_IGNORE_PARAM(src_p); + YS_IGNORE_PARAM(dst_p); + + for (i = 0; i < seqlimit; i++) { + + if (seq & 1) { + seq = (seq >> 1) ^ XOR_MASK; + } else { + seq = seq >> 1; + } + + if (seq == 1) { + return 0; + } + + if (seq >= pixelcount) { + continue; + } else { + + dst_img[seq] = src_img[seq]; + + } + } + + return 1; +} + +} // End of namespace Saga + diff --git a/saga/x86_32.h b/saga/x86_32.h new file mode 100644 index 0000000000..503d0cd777 --- /dev/null +++ b/saga/x86_32.h @@ -0,0 +1,46 @@ +/****************************************************************************\ + ____ ___ _ _ _ +| _ \ ___|_ _|_ __ | |__ ___ _ __(_) |_ +| |_) / _ \| || '_ \| '_ \ / _ \ '__| | __| +| _ < __/| || | | | | | | __/ | | | |_ +|_| \_\___|___|_| |_|_| |_|\___|_| |_|\__| + + ---------------------------------------------------------------------------- + Project: ReInherit Engine + Version: .1a + + The ReInherit Engine is (C)2000-2001 by Daniel Balsom + This code is subject to the terms and conditions of the General Public + License (GPL). + + ---------------------------------------------------------------------------- + + File: x86-32.h + Revision: $Revision$ + + Description: + + Architecture-specific typedefs for Intel(tm) compatible 32 bit processors + + Notes: + +\****************************************************************************/ +#ifndef R_ARCH_H +#define R_ARCH_H + +namespace Saga { + +#define R_LITTLE_ENDIAN + +typedef unsigned int R_UINT32; +typedef signed int R_SINT32; + +typedef unsigned short R_UINT16; +typedef signed short R_SINT16; + +typedef unsigned char R_UINT8; +typedef signed char R_SINT8; + +} // End of namespace Saga + +#endif /* R_ARCH_H */ diff --git a/saga/xmidi.cpp b/saga/xmidi.cpp new file mode 100644 index 0000000000..4767a6b849 --- /dev/null +++ b/saga/xmidi.cpp @@ -0,0 +1,832 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + XMIDI conversion routines + + Notes: + + Code adapted from XMILoader by Keet ( fox@foxpaws.net ), (C)2000 +*/ + +#include "reinherit.h" + +#include "yslib.h" + +/* Begin module component +\*--------------------------------------------------------------------------*/ +#include "xmidi_mod.h" +#include "xmidi.h" + +namespace Saga { + +int +ConvertEventListToSMF(XMIDIEVENT_LIST * event_list, + uchar ** smf_ptr, size_t * smf_len) +/*--------------------------------------------------------------------------*\ + * Given a pointer to an event list structure, this function creates and + * returns a pointer to a Standard Midi File (SMF) image and the image's + * length in bytes. +\*--------------------------------------------------------------------------*/ +{ + YS_IGNORE_PARAM(event_list); + YS_IGNORE_PARAM(smf_ptr); + YS_IGNORE_PARAM(smf_len); + +#if 0 + SMF_HEADER_CHUNK smfh; + SMF_TRACK_CHUNK smft; + + XMIDIEVENT *event_p; + + uchar *write_p = NULL; + uchar *smf_buf = NULL; + + size_t alloc_size; + + int vlq_len; + + if ((smf_ptr == NULL) || (smf_len == NULL)) { + + return R_FAILURE; + } + + /* Allocate memory for SMF image + * \*---------------------------------------------------------------------- */ + alloc_size = event_list->smf_size + MIDI_HEADER_LEN + + MIDI_TRACK_CHUNK_LEN; + + /* SMF requires an even size */ + if (alloc_size % 2) { + alloc_size++; + } + + smf_buf = malloc(alloc_size); + if (smf_buf == NULL) { + R_printf(R_STDERR, "Memory allocation error.\n"); + + return R_FAILURE; + } + + memset(smf_ptr, 0, alloc_size); + + /* Write header chunk + * \*---------------------------------------------------------------------- */ + write_p = smf_buf; + + smfh.smf_header_len = MIDI_HEADER_CHUNK_LEN; + smfh.smf_format = 0; + smfh.smf_ntracks = 1; + smfh.time_division.ppqn = XMIDI_TIMEDIV; + + memcpy(write_p, MIDI_HEADER_TAG, 4); + write_p += 4; + + ys_write_u32_be(smfh.smf_header_len, write_p, &write_p); + ys_write_u16_be(smfh.smf_format, write_p, &write_p); + ys_write_u16_be(smfh.smf_ntracks, write_p, &write_p); + ys_write_u16_be(smfh.time_division.ppqn, write_p, &write_p); + + /* Write track chunk + * \*---------------------------------------------------------------------- */ + memcpy(write_p, MIDI_TRACK_TAG, 4); + write_p += 4; + + smft.smf_track_len = event_list->smf_size; + + ys_write_u32_be(smft.smf_track_len, write_p, &write_p); + + /* Write MIDI events + * \*---------------------------------------------------------------------- */ + event_p = event_list->head; + + while (event_p != NULL) { + + vlq_len = WriteVLQ_DW(write_p, event_p->delta_time); + write_p += vlq_len; + + /* + * R_printf( R_STDOUT, + * "Wrote %d len VLQ. (%d)\n", + * vlq_len, + * event_p->delta_time ); + */ + + switch (event_p->event) { + + case MIDI_NOTE_ON: + case MIDI_NOTE_OFF: + case MIDI_AFTERTOUCH: + case MIDI_CONTROLCHANGE: + case MIDI_PITCHWHEEL: + + *write_p++ = + (uchar) (event_p->event | (uchar) event_p-> + channel); + *write_p++ = event_p->op1; + *write_p++ = event_p->op2; + break; + + case MIDI_PROGRAMCHANGE: + case MIDI_CHANNELPRESSURE: + + *write_p = + (uchar) (event_p->event | (uchar) event_p-> + channel); + *write_p = event_p->op1; + break; + + case MIDI_SYSTEMEXCLUSIVE: + + *write_p = (uchar) MIDI_NONMIDI; + + switch (event_p->sysex_op) { + + case MIDI_SYSEX_TRACKEND: + + *write_p++ = event_p->sysex_op; + *write_p++ = (uchar) 0; + break; + + case MIDI_SYSEX_TEMPO: + + *write_p++ = event_p->sysex_op; + *write_p++ = (uchar) 3; + /* + *write_p++ = event_p->op1; + *write_p++ = event_p->op2; + *write_p++ = event_p->op3; + */ + + /* Override tempo change */ + *write_p++ = (uchar) 0x07; + *write_p++ = (uchar) 0xA1; + *write_p++ = (uchar) 0x20; + break; + + case MIDI_SYSEX_TIMESIG: + + *write_p++ = event_p->sysex_op; + *write_p++ = (uchar) 4; + *write_p++ = event_p->op1; + *write_p++ = event_p->op2; + *write_p++ = event_p->op3; + *write_p++ = event_p->op4; + break; + + default: + + R_printf(R_STDERR, + "Error, invalid sysex event type (%d): " + "Aborting.\n", event_p->sysex_op); + + return R_FAILURE; + break; + + } + break; + + default: + R_printf(R_STDERR, + "Invalid event code encountered; " "aborting.\n"); + + return R_FAILURE; + break; + } + + event_p = event_p->next_event; + } + + *smf_ptr = smf_buf; + *smf_len = alloc_size; +#endif + return R_SUCCESS; +} + +int WriteVLQ_DW(char *write_ptr, DWORD value) +{ + + int vlq_len = 1; + DWORD pack = value & 0x7F; + int x; + + while (value >>= 7) { + pack <<= 8; + pack |= ((value & 0x7F) | 0x80); + vlq_len++; + } + for (x = 0; x < sizeof(DWORD); x++) { + *write_ptr++ = ((char *)(&pack))[x]; + } + + return vlq_len; +} + +int XMIDI_Read(const uchar * XMI_img, XMIDIEVENT_LIST * event_list) +{ + /* XMI header data */ + const uchar *XMIDI_data; + uint n_tracks; + + /* XMIDI data */ + IFF_ID_CHUNK cat_chunk; + IFF_ID_CHUNK id_chunk; /* Present after categeory chunk */ + XMI_TIMB_CHUNK timbre_chunk; /* Present after id chunk */ + XMI_EVENT_CHUNK event_chunk; + + const uchar *read_p; + + const uchar *event_data; + size_t event_data_len; + + if (XMIDI_ReadXMIHeader(XMI_img, &XMIDI_data, &n_tracks) != R_SUCCESS) { + + return R_FAILURE; + } + + read_p = XMIDI_data; + + /* Read category chunk + * \*------------------------------------------------------------- */ + ReadIFF_IDChunk(&cat_chunk, read_p, &read_p); + + if (memcmp(cat_chunk.id_4cc, IFF_CATEGORY_4CC, 4) != 0) { + + R_printf(R_STDERR, "Error: Category chunk not present.\n"); + Print4CC(cat_chunk.id_4cc); + + return R_FAILURE; + } + + if (memcmp(cat_chunk.desc_4cc, XMIDI_DESC_4CC, 4) != 0) { + + R_printf(R_STDERR, + "Error: Incorrect category description field.\n"); + Print4CC(cat_chunk.desc_4cc); + + return R_FAILURE; + } + + /* Read XMIDI ID Chunk + * \*------------------------------------------------------------- */ + ReadIFF_IDChunk(&id_chunk, read_p, &read_p); + + if (memcmp(id_chunk.id_4cc, IFF_FORMAT_4CC, 4) != 0) { + + R_printf(R_STDERR, "Error: ID chunk not present.\n"); + Print4CC(id_chunk.id_4cc); + + return R_FAILURE; + } + + if (memcmp(id_chunk.desc_4cc, XMIDI_DESC_4CC, 4) != 0) { + + R_printf(R_STDERR, + "Error: XMID tag not present in ID chunk: " + "Not XMIDI data.\n"); + Print4CC(id_chunk.desc_4cc); + + return R_FAILURE; + } + + /* Read XMIDI Timbre Chunk + * \*------------------------------------------------------------- */ + ys_read_4cc(timbre_chunk.id_4cc, read_p, &read_p); + timbre_chunk.chunk_len = ys_read_u32_be(read_p, &read_p); + + if (memcmp(timbre_chunk.id_4cc, XMIDI_TIMBRE_4CC, 4) != 0) { + + R_printf(R_STDERR, "Error: Timbre chunk not present.\n"); + Print4CC(timbre_chunk.id_4cc); + + return R_FAILURE; + } + + /* Read XMIDI Event Chunk + * \*------------------------------------------------------------- */ + read_p += timbre_chunk.chunk_len; + + ys_read_4cc(event_chunk.id_4cc, read_p, &read_p); + event_chunk.chunk_len = ys_read_u32_be(read_p, &read_p); + + if (memcmp(event_chunk.id_4cc, XMIDI_EVENT_4CC, 4) != 0) { + + R_printf(R_STDERR, "Error: Event chunk not present.\n"); + Print4CC(event_chunk.id_4cc); + + return R_FAILURE; + } + + /* Read XMIDI Event data + * \*------------------------------------------------------------- */ + event_data = read_p; + event_data_len = event_chunk.chunk_len; + + R_printf(R_STDOUT, + "Converting %d bytes of event data:\n", event_data_len); + + XMIDI_ReadEvents(event_list, event_data, event_data_len, n_tracks); + + /* Process XMIDI Event data + * \*------------------------------------------------------------- */ + ProcessEventList(event_list); + + return R_SUCCESS; +} + +int +ReadIFF_IDChunk(IFF_ID_CHUNK * chunk, + const uchar * read_p, const uchar ** read_pp) +{ + const uchar *chunk_p = read_p; + + ys_read_4cc(chunk->id_4cc, chunk_p, &chunk_p); + + chunk->chunk_len = ys_read_u32_be(chunk_p, &chunk_p); + + ys_read_4cc(chunk->desc_4cc, chunk_p, &chunk_p); + + if (read_pp != NULL) { + *read_pp = chunk_p; + } + + return R_SUCCESS; +} + +int Print4CC(char *fourcc) +{ + R_printf(R_STDERR, + "FourCC: %c%c%c%c (%X %X %X %X)\n", + fourcc[0], fourcc[1], fourcc[2], fourcc[3], + fourcc[0], fourcc[1], fourcc[2], fourcc[3]); + + return R_SUCCESS; +} + +int +XMIDI_ReadXMIHeader(const uchar * XMI_img, + const uchar ** XMIDI_data, uint * n_tracks) +{ + const uchar *read_p; + + IFF_ID_CHUNK id_chunk; + XMI_INFO_CHUNK info_chunk; + + *n_tracks = 0; + *XMIDI_data = NULL; + + /* Read ID chunk + * \*------------------------------------------------------------ */ + read_p = XMI_img; + + ys_read_4cc(id_chunk.id_4cc, read_p, &read_p); + id_chunk.chunk_len = ys_read_u32_be(read_p, &read_p); + ys_read_4cc(id_chunk.desc_4cc, read_p, &read_p); + + if (memcmp(id_chunk.id_4cc, IFF_FORMAT_4CC, 4) != 0) { + R_printf(R_STDERR, "Error: ID chunk not present.\n"); + + return R_FAILURE; + } + + if (memcmp(id_chunk.desc_4cc, XMI_DESC_4CC, 4) != 0) { + R_printf(R_STDERR, + "Error: XDIR tag not present in ID chunk.\n"); + + return R_FAILURE; + } + + /* Read INFO chunk + * \*------------------------------------------------------------ */ + ys_read_4cc(info_chunk.id_4cc, read_p, &read_p); + info_chunk.chunk_len = ys_read_u32_be(read_p, &read_p); + info_chunk.n_tracks = ys_read_u16_le(read_p, &read_p); + + if (memcmp(info_chunk.id_4cc, XMI_INFO_4CC, 4) != 0) { + + R_printf(R_STDERR, "Error: INFO chunk not present.\n"); + + return R_FAILURE; + } + + *n_tracks = info_chunk.n_tracks; + + *XMIDI_data = XMI_img + + (id_chunk.chunk_len + IFF_ID_CHUNK_HEADERLEN - 4); + + return R_SUCCESS; +} + +int +XMIDI_ReadEvents(XMIDIEVENT_LIST * event_list, + const uchar * event_data, size_t event_data_len, uint n_tracks) +{ + + const uchar *event_data_ptr = event_data; + size_t event_bytes_left = event_data_len; + + ulong new_event_time = 0; + ulong event_time = 0; + ulong event_len; + + ulong vlq_len; + uint data_byte; + + int channel; + int event; + + /*int tempo = MIDI_STD_TEMPO; */ + + unsigned int sysex_op; + unsigned int op1; + unsigned int op2; + unsigned int op3; + unsigned int op4; + + /* Set initial tempo */ + /* + * AddEventToList( event_list, MIDI_SYSEX_TEMPO_LEN + GetLengthAsVLQ( 0 ), 0, MIDI_SYSTEMEXCLUSIVE, 0, MIDI_SYSEX_TEMPO, 0, ); + */ + + while (event_bytes_left > 0) { + + vlq_len = ReadVLQ2_DW((char *)event_data_ptr, + (DWORD)event_bytes_left, (DWORD *)&new_event_time); + + event_time += new_event_time; + event_data_ptr += vlq_len; + event_bytes_left -= vlq_len; + + /* + * vlq_len = GetLengthAsVLQ( new_event_time ); + * R_printf( R_STDOUT, "Count: %d len VLQ (%d)\n", vlq_len, new_event_time ); + */ + + data_byte = *event_data_ptr++; + + channel = data_byte & 0x0FU; + event = data_byte & 0xF0U; + + switch (event) { + + case MIDI_NOTE_ON: + +#ifdef XMIPLAY_VERBOSE + R_printf(R_STDOUT, "MIDI_NOTE_ON event:\n"); +#endif + + op1 = *(event_data_ptr++); + op2 = *(event_data_ptr++); + + AddEventToList(event_list, + MIDI_NOTE_ON_LEN, + event_time, event, channel, 0, op1, op2, 0, 0); + + vlq_len = + ReadVLQ_DW((char *)event_data_ptr, (DWORD)event_bytes_left, + (DWORD *)&event_len); + AddEventToList(event_list, MIDI_NOTE_OFF_LEN, + event_time + event_len, MIDI_NOTE_OFF, channel, 0, + op1, MIDI_STD_VELOCITY, 0, 0); + + event_data_ptr += (vlq_len); + event_bytes_left -= (2 + vlq_len); + break; + + case MIDI_AFTERTOUCH: +#ifdef XMIPLAY_VERBOSE + R_printf(R_STDOUT, "MIDI_AFTERTOUCH event:\n"); +#endif + op1 = *(event_data_ptr++); + op2 = *(event_data_ptr++); + + AddEventToList(event_list, + MIDI_AFTERTOUCH_LEN, + event_time, event, channel, 0, op1, op2, 0, 0); + + event_bytes_left -= 2; + break; + + case MIDI_CONTROLCHANGE: +#ifdef XMIPLAY_VERBOSE + R_printf(R_STDOUT, "MIDI_CONTROLCHANGE event:\n"); +#endif + op1 = *(event_data_ptr++); + op2 = *(event_data_ptr++); + + AddEventToList(event_list, + MIDI_CONTROLCHANGE_LEN, + event_time, event, channel, 0, op1, op2, 0, 0); + + event_bytes_left -= 2; + break; + + case MIDI_PITCHWHEEL: +#ifdef XMIPLAY_VERBOSE + R_printf(R_STDOUT, "MIDI_PITCHWHEEL event:\n"); +#endif + op1 = *(event_data_ptr++); + op2 = *(event_data_ptr++); + + AddEventToList(event_list, + MIDI_PITCHWHEEL_LEN, + event_time, event, channel, 0, op1, op2, 0, 0); + + event_bytes_left -= 2; + break; + + case MIDI_PROGRAMCHANGE: +#ifdef XMIPLAY_VERBOSE + R_printf(R_STDOUT, "MIDI_PROGRAMCHANGE event:\n"); +#endif + op1 = *(event_data_ptr++); + AddEventToList(event_list, MIDI_PROGRAMCHANGE_LEN, + event_time, event, channel, 0, op1, 0, 0, 0); + + event_bytes_left--; + break; + + case MIDI_CHANNELPRESSURE: +#ifdef XMIPLAY_VERBOSE + R_printf(R_STDOUT, "MIDI_CHANNELPRESSURE event:\n"); +#endif + op1 = *(event_data_ptr++); + AddEventToList(event_list, MIDI_CHANNELPRESSURE_LEN, + event_time, event, channel, 0, op1, 0, 0, 0); + + event_bytes_left--; + break; + + case MIDI_SYSTEMEXCLUSIVE: + + sysex_op = (BYTE) * event_data_ptr++; + event_bytes_left--; + + if (data_byte == MIDI_NONMIDI) { + + switch (sysex_op) { + + case MIDI_SYSEX_TRACKEND: + R_printf(R_STDOUT, + "Track end encountered.\n"); + AddEventToList(event_list, + MIDI_SYSEX_TRACKEND_LEN, + event_time, event, channel, + sysex_op, op1, op2, 0, 0); + event_bytes_left = 0; + break; + + case MIDI_SYSEX_TEMPO: + event_data_ptr++; /*(skip length VLQ) (always 3) */ + + op1 = (BYTE) * event_data_ptr++; + op2 = (BYTE) * event_data_ptr++; + op3 = (BYTE) * event_data_ptr++; + AddEventToList(event_list, + MIDI_SYSEX_TEMPO_LEN, event_time, + event, channel, sysex_op, op1, op2, + op3, 0); + /* + * R_printf( R_STDOUT, "Adding tempo change event. :%X %X %X\n", op1, op2, op3 ); + */ + event_bytes_left -= 4; + break; + + case MIDI_SYSEX_TIMESIG: + event_data_ptr++; /*(skip length VLQ) (always 4) */ + + op1 = (BYTE) * event_data_ptr++; + op2 = (BYTE) * event_data_ptr++; + op3 = (BYTE) * event_data_ptr++; + op4 = (BYTE) * event_data_ptr++; + AddEventToList(event_list, + MIDI_SYSEX_TIMESIG_LEN, event_time, + event, channel, sysex_op, op1, op2, + op3, op4); + + /* + * R_printf( R_STDOUT, "Adding time signature event. :%X %X %X %X\n", op1, op2, op3, op4 ); + */ + event_bytes_left -= 5; + break; + + default: + R_printf(R_STDERR, + "Unhandled sysex nonmidi event, aborting.\n"); + R_printf(R_STDERR, "%X %X %X %X", + *event_data_ptr, + *(event_data_ptr + 1), + *(event_data_ptr + 2), + *(event_data_ptr + 3)); + + event_bytes_left = 0; + break; + + } + } else { + R_printf(R_STDERR, + "Unhandled sysex event, aborting.\n"); + event_bytes_left = 0; + } + + break; + + default: + R_printf(R_STDERR, + "Invalid event code encountered; aborting.\n"); + event_bytes_left = 0; + break; + } + + } /* end while ( event_bytes_left > 0 ) */ + + return R_SUCCESS; +} + +int GetLengthAsVLQ(DWORD data) +{ + + int len = 1; + + while (data >>= 7) + len++; + return len; + +} + +DWORD ReadVLQ_DW(char *data, DWORD bytes_left, DWORD * value) +{ + BYTE byte; + DWORD vlq_len = 0; + *value = 0; + + do { + if (bytes_left <= 0) + return 0; + byte = *data++; + bytes_left--; + vlq_len++; + *value = (*value << 7) | (byte & 0x7F); + } while (byte & 0x80); + + return vlq_len; +} + +DWORD ReadVLQ2_DW(char *data, DWORD bytes_left, DWORD * value) +{ + + BYTE byte; + DWORD vlq_len = 0; + *value = 0; + + while (!((byte = *data++) & 0x80)) { + if (bytes_left <= 0) + return 0; + bytes_left--; + vlq_len++; + (*value) += byte; + } + + return vlq_len; +} + +int +AddEventToList(XMIDIEVENT_LIST * event_list, int smf_size, int time, int event, + int channel, int sysex_op, int op1, int op2, int op3, int op4) +{ + + XMIDIEVENT *new_event; + XMIDIEVENT *search_ptr = event_list->tail; + + new_event = (XMIDIEVENT *)malloc(sizeof(XMIDIEVENT)); + + if (new_event == NULL) { + R_printf(R_STDERR, + "Error: Out of memory allocating XMIDI event list entry."); + return -1; + } + + new_event->next_event = NULL; + new_event->prev_event = NULL; + + if (event_list->head == NULL) { + /* Set up new list */ + event_list->head = new_event; + event_list->tail = new_event; + } else { + /* List isn't empty */ + if ((unsigned int)time >= event_list->tail->delta_time) { + + /* If this is the most recent event, append */ + event_list->tail->next_event = new_event; + new_event->prev_event = event_list->tail; + event_list->tail = new_event; + + } else { + /* Otherwise scan list backwards and insert in proper position */ + while (search_ptr != NULL) { + + if ((unsigned int)time >= + search_ptr->delta_time) { + /* Insert entry */ + new_event->next_event = + search_ptr->next_event; + new_event->prev_event = search_ptr; + + search_ptr->next_event->prev_event = + new_event; + search_ptr->next_event = new_event; + break; + } + search_ptr = search_ptr->prev_event; + } + } + } + + new_event->smf_size = smf_size; + new_event->delta_time = time; + + new_event->sysex_op = sysex_op; + new_event->event = (BYTE) event; + new_event->channel = (BYTE) channel; + new_event->op1 = (BYTE) op1; + new_event->op2 = (BYTE) op2; + new_event->op3 = (BYTE) op3; + new_event->op4 = (BYTE) op4; + +#ifdef XMIPLAY_VERBOSE + R_printf(R_STDOUT, + "Added event: Time: %d Tempo: %d Event: %d Chan: %d Op1: %d Op2: %d\n", + new_event->delta_time, new_event->tempo, new_event->event, + new_event->channel, new_event->op1, new_event->op2); +#endif + return 0; +} + +int ProcessEventList(XMIDIEVENT_LIST * event_list) +{ + XMIDIEVENT *convert_ptr = event_list->head; + int last_time = 0; + int delta = 0; + + while (convert_ptr != NULL) { + + delta = convert_ptr->delta_time - last_time; + if (delta < 0) + R_printf(R_STDERR, + "Error: Negative delta time found."); + last_time = convert_ptr->delta_time; + convert_ptr->delta_time = delta; + + /* Update smf size count */ + event_list->smf_size += + (convert_ptr->smf_size + GetLengthAsVLQ(delta)); + convert_ptr = convert_ptr->next_event; + } + + R_printf(R_STDOUT, + "ProcessEventList(): %d bytes of SMF data processed.\n", + event_list->smf_size); + + return 0; +} + +int XMIDI_Free(XMIDIEVENT_LIST * event_list) +{ + + XMIDIEVENT *free_ptr = event_list->head; + XMIDIEVENT *temp_ptr; + + while (free_ptr != NULL) { + temp_ptr = free_ptr->next_event; + free(free_ptr); + free_ptr = temp_ptr; + } + + return 0; + +} + +} // End of namespace Saga + diff --git a/saga/xmidi.h b/saga/xmidi.h new file mode 100644 index 0000000000..a408cfc74e --- /dev/null +++ b/saga/xmidi.h @@ -0,0 +1,117 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + XMIDI conversion routines + + Notes: + + Code adapted from XMILoader by Keet ( fox@foxpaws.net ), (C)2000 +*/ + +#ifndef SAGA_XMIDI_H_ +#define SAGA_XMIDI_H_ + +namespace Saga { + +#define XMIDI_TIMEDIV 0x3C + +/* XMIDI/IFF 4CC codes +\*--------------------------------------------------------------------------*/ +#define IFF_FORMAT_4CC "FORM" +#define IFF_CATEGORY_4CC "CAT " + +#define XMI_DESC_4CC "XDIR" +#define XMI_INFO_4CC "INFO" + +#define XMIDI_DESC_4CC "XMID" +#define XMIDI_TIMBRE_4CC "TIMB" +#define XMIDI_EVENT_4CC "EVNT" + +/* IFF/XMI Data structures +\*--------------------------------------------------------------------------*/ + +typedef struct IFF_ID_CHUNK_tag { + char id_4cc[4]; /* 4cc */ + ulong chunk_len; /* u32_be */ + char desc_4cc[4]; /* 4cc */ +} IFF_ID_CHUNK; + +#define IFF_ID_CHUNK_HEADERLEN 12 + +typedef struct XMI_INFO_CHUNK_tag { + char id_4cc[4]; /* 4cc */ + ulong chunk_len; /* u32_be */ + uint n_tracks; /* u16_le */ +} XMI_INFO_CHUNK; + +typedef struct XMI_TIMB_CHUNK_tag { + char id_4cc[4]; /* 4cc */ + ulong chunk_len; /* u32_be */ +} XMI_TIMB_CHUNK; + +typedef struct XMI_EVENT_CHUNK_tag { + char id_4cc[4]; /* 4cc */ + ulong chunk_len; /* u32_be */ +} XMI_EVENT_CHUNK; + +typedef struct SMF_HEADER_CHUNK_tag { + char smf_id[4]; /* u8 */ + unsigned int smf_header_len; /* u32_be */ + unsigned short smf_format; /* u16_be */ + unsigned short smf_ntracks; /* u16_be */ + union { + unsigned short ppqn; /* u16_be */ + signed char smpte[2]; + } time_division; +} SMF_HEADER_CHUNK; + +typedef struct SMF_TRACK_CHUNK_tag { + char smf_track_id[4]; + unsigned int smf_track_len; +} SMF_TRACK_CHUNK; + +#define MIDI_HEADER_LEN 14 +#define MIDI_HEADER_CHUNK_LEN 6 +#define MIDI_TRACK_CHUNK_LEN 8 + +#define MIDI_HEADER_TAG "MThd" +#define MIDI_TRACK_TAG "MTrk" + +int XMIDI_ReadXMIHeader(const uchar *XMI_img, const uchar **XMIDI_data, uint *n_tracks); +int ReadIFF_IDChunk(IFF_ID_CHUNK *chunk, const uchar *read_p, const uchar **read_pp); +int Print4CC(char *fourcc); +int XMIDI_ReadEvents(XMIDIEVENT_LIST *event_list, const uchar *event_data, + size_t event_data_len, uint n_tracks); +int WriteVLQ_DW(char *write_ptr, DWORD value); +DWORD ReadVLQ_DW(char *data, DWORD bytes_left, DWORD *value); +DWORD ReadVLQ2_DW(char *data, DWORD bytes_left, DWORD *value); +int GetLengthAsVLQ(DWORD data); +int AddEventToList(XMIDIEVENT_LIST *event_list, int smf_size, int time, + int event, int channel, int sysex_op, int op1, int op2, int op3, int op4); +int ProcessEventList(XMIDIEVENT_LIST *event_list); +void PrintMidiOutError(unsigned long err); +} // End of namespace Saga + +#endif /* SAGA_XMIDI_H_ */ diff --git a/saga/xmidi_mod.h b/saga/xmidi_mod.h new file mode 100644 index 0000000000..4d093072a7 --- /dev/null +++ b/saga/xmidi_mod.h @@ -0,0 +1,115 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + Description: + + XMIDI conversion routines - module header + + Notes: +*/ + +#ifndef SAGA_XMIDI_MOD_H_ +#define SAGA_XMIDI_MOD_H_ + +namespace Saga { + +#define MIDI_STD_VELOCITY 0x7F +#define MIDI_STD_TEMPO 0x0007A120L /* 500000 */ + +/* MIDI Events +\*--------------------------------------------------------------------------*/ +enum R_MIDI_EVENTS { + MIDI_NOTE_ON = 0x90, + MIDI_NOTE_OFF = 0x80, + MIDI_AFTERTOUCH = 0xA0, + MIDI_CONTROLCHANGE = 0xB0, + MIDI_PROGRAMCHANGE = 0xC0, + MIDI_CHANNELPRESSURE = 0xD0, + MIDI_PITCHWHEEL = 0xE0, + MIDI_SYSTEMEXCLUSIVE = 0xF0, + + MIDI_NONMIDI = 0xFF, + + MIDI_SYSEX_SEQNUM = 0x00, + MIDI_SYSEX_TEXT = 0x01, + MIDI_SYSEX_COPYRIGHT = 0x02, + MIDI_SYSEX_SEQNAME = 0x03, + MIDI_SYSEX_INSTRUMENT = 0x04, + MIDI_SYSEX_LYRIC = 0x05, + MIDI_SYSEX_MARKER = 0x06, + MIDI_SYSEX_CUEPOINT = 0x07, + + MIDI_SYSEX_CHANNEL = 0x20, + MIDI_SYSEX_PORTNUM = 0x21, + MIDI_SYSEX_TRACKEND = 0x2F, + MIDI_SYSEX_TEMPO = 0x51, + MIDI_SYSEX_TIMESIG = 0x58, + + MIDI_SYSEX_PROPRIETARY = 0x7F +}; + +enum MIDI_EVENT_LENGTHS { + MIDI_NOTE_ON_LEN = 3, + MIDI_NOTE_OFF_LEN = 3, + MIDI_AFTERTOUCH_LEN = 3, + MIDI_CONTROLCHANGE_LEN = 3, + MIDI_PITCHWHEEL_LEN = 3, + + MIDI_PROGRAMCHANGE_LEN = 2, + MIDI_CHANNELPRESSURE_LEN = 2, + + MIDI_SYSEX_TRACKEND_LEN = 3, + MIDI_SYSEX_TEMPO_LEN = 6, + MIDI_SYSEX_TIMESIG_LEN = 7 +}; + +typedef struct XMIDIEVENT_tag { + struct XMIDIEVENT_tag *prev_event; + struct XMIDIEVENT_tag *next_event; + + size_t smf_size; /* Size of event in SMF format */ + + ulong delta_time; + + uchar event; + uchar channel; + uchar sysex_op; + uchar op1; + uchar op2; + uchar op3; + uchar op4; + uchar pad; +} XMIDIEVENT; + +typedef struct XMIDIEVENT_LIST_tag { + XMIDIEVENT *head; + XMIDIEVENT *tail; + int smf_size; +} XMIDIEVENT_LIST; + +int XMIDI_Read(const uchar *XMI_img, XMIDIEVENT_LIST *event_list); +int XMIDI_Free(XMIDIEVENT_LIST *event_list); + +} // End of namespace Saga + +#endif /* SAGA_XMIDI_MOD_H_ */ diff --git a/saga/ys_binread.cpp b/saga/ys_binread.cpp new file mode 100644 index 0000000000..4f363bbc8f --- /dev/null +++ b/saga/ys_binread.cpp @@ -0,0 +1,350 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +#include <stdio.h> +#include "yslib.h" + +namespace Saga { + +void +ys_read_4cc(char *fourcc, + const unsigned char *data_p, const unsigned char **data_pp) +{ + fourcc[0] = (char)data_p[0]; + fourcc[1] = (char)data_p[1]; + fourcc[2] = (char)data_p[2]; + fourcc[3] = (char)data_p[3]; + + if (data_pp) { + + *data_pp = data_p + 4; + } + + return; +} + +unsigned int +ys_read_u8(const unsigned char *data_p, const unsigned char **data_pp) +/*---------------------------------------------------------------------------*\ + * Reads an unsigned 8 bit integer in from the array of bytes pointed to by + * 'data_p'. If 'data_pp' is not null, it will set '*data_pp' to point past + * the integer read. +\*---------------------------------------------------------------------------*/ +{ + unsigned int u8 = *data_p; + + if (data_pp != NULL) { + *data_pp = data_p + 1; + } + + return u8; +} + +int ys_read_s8(const unsigned char *data_p, const unsigned char **data_pp) +/*---------------------------------------------------------------------------*\ + * Reads a signed 8 bit integer in two's complement notation from the array + * of bytes pointed to by 'data_p'. If 'data_pp' is not null, it will set + * '*data_pp' to point past the integer read. +\*---------------------------------------------------------------------------*/ +{ + unsigned int u8 = *data_p; + int s8; + +#ifndef YS_ASSUME_2S_COMP + if (u8 & 0x80U) { + s8 = (int)(u8 - 0x80U) - 0x7F - 1; + } else +#endif + s8 = u8; + + if (data_pp != NULL) { + *data_pp = data_p + 1; + } + + return s8; +} + +unsigned int +ys_read_u16_be(const unsigned char *data_p, const unsigned char **data_pp) +/*---------------------------------------------------------------------------*\ + * Reads an unsigned 16 bit integer in big-endian format from the array of + * bytes pointed to by 'data_p'. If 'data_pp' is not null, it will set + * '*data_pp' to point past the integer read. +\*---------------------------------------------------------------------------*/ +{ + unsigned int u16_be = ((unsigned int)data_p[0] << 8) | data_p[1]; + + if (data_pp != NULL) { + *data_pp = (unsigned char *)(data_p + 2); + } + + return u16_be; +} + +unsigned int +ys_read_u16_le(const unsigned char *data_p, const unsigned char **data_pp) +/*---------------------------------------------------------------------------*\ + * Reads an unsigned 16 bit integer in little-endian format from the array of + * bytes pointed to by 'data_p'. If 'data_pp' is not null, it will set + * '*data_pp' to point past the integer read. +\*---------------------------------------------------------------------------*/ +{ + unsigned int u16_le = ((unsigned int)data_p[1] << 8) | data_p[0]; + + if (data_pp != NULL) { + *data_pp = (unsigned char *)(data_p + 2); + } + + return u16_le; +} + +int ys_read_s16_be(const unsigned char *data_p, const unsigned char **data_pp) +/*---------------------------------------------------------------------------*\ + * Reads a signed 16 bit integer in big-endian, 2's complement format from + * the array of bytes pointed to by 'data_p'. + * If 'data_pp' is not null, it will set '*data_pp' to point past the integer + * read. +\*---------------------------------------------------------------------------*/ +{ + unsigned int u16_be = ((unsigned int)data_p[0] << 8) | data_p[1]; + int s16_be; + +#ifndef YS_ASSUME_2S_COMP + if (u16_be & 0x8000U) { + s16_be = (int)(u16_be - 0x8000U) - 0x7FFF - 1; + } else +#endif + s16_be = u16_be; + + if (data_pp != NULL) { + *data_pp = (unsigned char *)(data_p + 2); + } + + return s16_be; +} + +int ys_read_s16_le(const unsigned char *data_p, const unsigned char **data_pp) +/*---------------------------------------------------------------------------*\ + * Reads a signed 16 bit integer in little-endian, 2's complement format from + * the array of bytes pointed to by 'data_p'. + * If 'data_pp' is not null, it will set '*data_pp' to point past the integer + * read. +\*---------------------------------------------------------------------------*/ +{ + unsigned int u16_le = ((unsigned int)data_p[1] << 8) | data_p[0]; + int s16_le; + +#ifndef YS_ASSUME_2S_COMP + if (u16_le & 0x8000U) { + s16_le = (int)(u16_le - 0x8000U) - 0x7FFF - 1; + } else +#endif + s16_le = u16_le; + + if (data_pp != NULL) { + *data_pp = (unsigned char *)(data_p + 2); + } + + return s16_le; +} + +unsigned long +ys_read_u24_be(const unsigned char *data_p, const unsigned char **data_pp) +/*---------------------------------------------------------------------------*\ + * Reads an unsigned 24 bit integer in big-endian format from the array of + * bytes pointed to by 'data_p'. If 'data_pp' is not null, it will set + * '*data_pp' to point past the integer read. +\*---------------------------------------------------------------------------*/ +{ + unsigned long u24_be = ((unsigned long)data_p[0] << 16) | + ((unsigned long)data_p[1] << 8) | data_p[2]; + + if (data_pp != NULL) { + *data_pp = (unsigned char *)(data_p + 3); + } + + return u24_be; +} + +unsigned long +ys_read_u24_le(const unsigned char *data_p, const unsigned char **data_pp) +/*---------------------------------------------------------------------------*\ + * Reads an unsigned 24 bit integer in big-endian format from the array of + * bytes pointed to by 'data_p'. If 'data_pp' is not null, it will set + * '*data_pp' to point past the integer read. +\*---------------------------------------------------------------------------*/ +{ + unsigned long u24_le = ((unsigned long)data_p[3] << 16) | + ((unsigned long)data_p[2] << 8) | data_p[0]; + + if (data_pp != NULL) { + *data_pp = (unsigned char *)(data_p + 3); + } + + return u24_le; +} + +long ys_read_s24_be(const unsigned char *data_p, const unsigned char **data_pp) +/*---------------------------------------------------------------------------*\ + * Reads a signed 24 bit integer in big-endian, 2's complement format from + * the array of bytes pointed to by 'data_p'. + * If 'data_pp' is not null, it will set '*data_pp' to point past the integer + * read. +\*---------------------------------------------------------------------------*/ +{ + unsigned long u24_be = ((unsigned long)data_p[0] << 16) | + ((unsigned long)data_p[1] << 8) | data_p[2]; + long s24_be; + +#ifndef YS_ASSUME_2S_COMP + if (u24_be & 0x800000UL) { + s24_be = (long)(u24_be - 0x800000UL) - 0x800000; + } else +#endif + s24_be = u24_be; + + if (data_pp != NULL) { + *data_pp = (unsigned char *)(data_p + 3); + } + + return s24_be; +} + +long ys_read_s24_le(const unsigned char *data_p, const unsigned char **data_pp) +/*---------------------------------------------------------------------------*\ + * Reads a signed 24 bit integer in little-endian, 2's complement format from + * the array of bytes pointed to by 'data_p'. + * If 'data_pp' is not null, it will set '*data_pp' to point past the integer + * read. +\*---------------------------------------------------------------------------*/ +{ + unsigned long u24_be = ((unsigned long)data_p[2] << 16) | + ((unsigned long)data_p[1] << 8) | data_p[0]; + long s24_be; + +#ifndef YS_ASSUME_2S_COMP + if (u24_be & 0x800000UL) { + s24_be = (long)(u24_be - 0x800000UL) - 0x800000; + } else +#endif + s24_be = u24_be; + + if (data_pp != NULL) { + *data_pp = (unsigned char *)(data_p + 3); + } + + return s24_be; +} + +unsigned long +ys_read_u32_be(const unsigned char *data_p, const unsigned char **data_pp) +/*---------------------------------------------------------------------------*\ + * Reads an unsigned 32 bit integer in big-endian format from the array of + * bytes pointed to by 'data_p'. If 'data_pp' is not null, it will set + * '*data_pp' to point past the integer read. +\*---------------------------------------------------------------------------*/ +{ + unsigned long u32_be = ((unsigned long)data_p[0] << 24) | + ((unsigned long)data_p[1] << 16) | + ((unsigned long)data_p[2] << 8) | data_p[3]; + + if (data_pp != NULL) { + *data_pp = (unsigned char *)(data_p + 4); + } + + return u32_be; +} + +unsigned long +ys_read_u32_le(const unsigned char *data_p, const unsigned char **data_pp) +/*---------------------------------------------------------------------------*\ + * Reads an unsigned 32 bit integer in little-endian format from the array of + * bytes pointed to by 'data_p'. If 'data_pp' is not null, it will set + * '*data_pp' to point past the integer read. +\*---------------------------------------------------------------------------*/ +{ + unsigned long u32_le = ((unsigned long)data_p[3] << 24) | + ((unsigned long)data_p[2] << 16) | + ((unsigned long)data_p[1] << 8) | data_p[0]; + + if (data_pp != NULL) { + *data_pp = (unsigned char *)(data_p + 4); + } + + return u32_le; +} + +long ys_read_s32_be(const unsigned char *data_p, const unsigned char **data_pp) +/*---------------------------------------------------------------------------*\ + * Reads a signed 32 bit integer in big-endian, 2's complement format from + * the array of bytes pointed to by 'data_p'. + * If 'data_pp' is not null, it will set '*data_pp' to point past the integer + * read. +\*---------------------------------------------------------------------------*/ +{ + unsigned long u32_be = ((unsigned long)data_p[0] << 24) | + ((unsigned long)data_p[1] << 16) | + ((unsigned long)data_p[2] << 8) | data_p[3]; + long s32_be; + +#ifndef YS_ASSUME_2S_COMP + if (u32_be & 0x80000000UL) { + s32_be = (long)(u32_be - 0x80000000UL) - 0x7FFFFFFF - 1; + } else +#endif + s32_be = u32_be; + + if (data_pp != NULL) { + *data_pp = (unsigned char *)(data_p + 4); + } + + return s32_be; +} + +long ys_read_s32_le(const unsigned char *data_p, const unsigned char **data_pp) +/*---------------------------------------------------------------------------*\ + * Reads a signed 32 bit integer in little-endian, 2's complement format from + * the array of bytes pointed to by 'data_p'. + * If 'data_pp' is not null, it will set '*data_pp' to point past the integer + * read. +\*---------------------------------------------------------------------------*/ +{ + unsigned long u32_le = ((unsigned long)data_p[3] << 24) | + ((unsigned long)data_p[2] << 16) | + ((unsigned long)data_p[1] << 8) | data_p[0]; + long s32_le; + +#ifndef YS_ASSUME_2S_COMP + if (u32_le & 0x80000000UL) { + s32_le = (long)(u32_le - 0x80000000UL) - 0x7FFFFFFF - 1; + } else +#endif + s32_le = u32_le; + + if (data_pp != NULL) { + *data_pp = (unsigned char *)(data_p + 4); + } + + return s32_le; +} + +} // End of namespace Saga diff --git a/saga/ys_binwrite.cpp b/saga/ys_binwrite.cpp new file mode 100644 index 0000000000..ae10e364a2 --- /dev/null +++ b/saga/ys_binwrite.cpp @@ -0,0 +1,296 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +#include <stddef.h> + +namespace Saga { +void +ys_write_u8(unsigned int u8, unsigned char *data_p, unsigned char **data_pp) +{ + *data_p = (unsigned char)(u8 & 0xFFU); + + if (data_pp != NULL) { + *data_pp = data_p + 1; + } + + return; +} + +void +ys_write_u16_be(unsigned int u16_be, + unsigned char *data_p, unsigned char **data_pp) +/*---------------------------------------------------------------------------*\ + * Writes an unsigned 16 bit integer in big-endian format to the buffer + * pointed to by 'data_p'. + * If 'data_pp' is not null, the function will set it to point just beyond + * the integer written. +\*---------------------------------------------------------------------------*/ +{ + data_p[0] = (unsigned char)((u16_be >> 8) & 0xFFU); + data_p[1] = (unsigned char)(u16_be & 0xFFU); + + if (data_pp != NULL) { + *data_pp = data_p + 2; + } + + return; +} + +void +ys_write_u16_le(unsigned int u16_le, + unsigned char *data_p, unsigned char **data_pp) +/*---------------------------------------------------------------------------*\ + * Writes an unsigned 16 bit integer in little-endian format to the buffer + * pointed to by 'data_p'. + * If 'data_pp' is not null, the function will set it to point just beyond + * the integer written. +\*---------------------------------------------------------------------------*/ +{ + data_p[0] = (unsigned char)(u16_le & 0xFFU); + data_p[1] = (unsigned char)((u16_le >> 8) & 0xFFU); + + if (data_pp != NULL) { + *data_pp = data_p + 2; + } + + return; +} + +void +ys_write_s16_be(int s16_be, unsigned char *data_p, unsigned char **data_pp) +/*---------------------------------------------------------------------------*\ + * Writes an signed 16 bit integer in big-endian format and two's + * complement representation to the buffer pointed to by 'data_p'. + * If 'data_pp' is not null, the function will set it to point just beyond + * the integer written. +\*---------------------------------------------------------------------------*/ +{ + unsigned int u16_be = s16_be; + + data_p[0] = (unsigned char)((u16_be >> 8) & 0xFFU); + data_p[1] = (unsigned char)(u16_be & 0xFFU); + + if (data_pp != NULL) { + *data_pp = data_p + 2; + } + + return; +} + +void +ys_write_s16_le(int s16_le, unsigned char *data_p, unsigned char **data_pp) +/*---------------------------------------------------------------------------*\ + * Writes an signed 16 bit integer in little-endian format and two's + * complement representation to the buffer pointed to by 'data_p'. + * If 'data_pp' is not null, the function will set it to point just beyond + * the integer written. +\*---------------------------------------------------------------------------*/ +{ + unsigned int u16_le = s16_le; + + data_p[0] = (unsigned char)(u16_le & 0xFFU); + data_p[1] = (unsigned char)((u16_le >> 8) & 0xFFU); + + if (data_pp != NULL) { + *data_pp = data_p + 2; + } + + return; +} + +void +ys_write_u24_be(unsigned long u24_be, + unsigned char *data_p, unsigned char **data_pp) +/*---------------------------------------------------------------------------*\ + * Writes an unsigned 24 bit integer in big-endian format to the buffer + * pointed to by 'data_p'. + * If 'data_pp' is not null, the function will set it to point just beyond + * the integer written. +\*---------------------------------------------------------------------------*/ +{ + data_p[0] = (unsigned char)((u24_be >> 16) & 0xFFU); + data_p[1] = (unsigned char)((u24_be >> 8) & 0xFFU); + data_p[2] = (unsigned char)(u24_be & 0xFFU); + + if (data_pp != NULL) { + *data_pp = data_p + 3; + } + + return; +} + +void +ys_write_u24_le(unsigned long u24_le, + unsigned char *data_p, unsigned char **data_pp) +/*---------------------------------------------------------------------------*\ + * Writes an unsigned 24 bit integer in little-endian format to the buffer + * pointed to by 'data_p'. + * If 'data_pp' is not null, the function will set it to point just beyond + * the integer written. +\*---------------------------------------------------------------------------*/ +{ + data_p[0] = (unsigned char)(u24_le & 0xFFU); + data_p[1] = (unsigned char)((u24_le >> 8) & 0xFFU); + data_p[2] = (unsigned char)((u24_le >> 16) & 0xFFU); + + if (data_pp != NULL) { + *data_pp = data_p + 3; + } + + return; +} + +void +ys_write_s24_be(long s24_be, unsigned char *data_p, unsigned char **data_pp) +/*---------------------------------------------------------------------------*\ + * Writes an signed 24 bit integer in big-endian format and two's + * complement representation to the buffer pointed to by 'data_p'. + * If 'data_pp' is not null, the function will set it to point just beyond + * the integer written. +\*---------------------------------------------------------------------------*/ +{ + unsigned long u24_be = s24_be; + + data_p[0] = (unsigned char)((u24_be >> 16) & 0xFFU); + data_p[1] = (unsigned char)((u24_be >> 8) & 0xFFU); + data_p[2] = (unsigned char)(u24_be & 0xFFU); + + if (data_pp != NULL) { + *data_pp = data_p + 3; + } + + return; +} + +void +ys_write_s24_le(long s24_le, unsigned char *data_p, unsigned char **data_pp) +/*---------------------------------------------------------------------------*\ + * Writes an signed 24 bit integer in little-endian format and two's + * complement representation to the buffer pointed to by 'data_p'. + * If 'data_pp' is not null, the function will set it to point just beyond + * the integer written. +\*---------------------------------------------------------------------------*/ +{ + unsigned long u24_le = s24_le; + + data_p[0] = (unsigned char)(u24_le & 0xFFU); + data_p[1] = (unsigned char)((u24_le >> 8) & 0xFFU); + data_p[2] = (unsigned char)((u24_le >> 16) & 0xFFU); + + if (data_pp != NULL) { + *data_pp = (unsigned char *)(data_p + 3); + } + + return; +} + +void +ys_write_u32_be(unsigned long u32_be, + unsigned char *data_p, unsigned char **data_pp) +/*---------------------------------------------------------------------------*\ + * Writes an unsigned 32 bit integer in big-endian format to the buffer + * pointed to by 'data_p'. + * If 'data_pp' is not null, the function will set it to point just beyond + * the integer written. +\*---------------------------------------------------------------------------*/ +{ + data_p[0] = (unsigned char)((u32_be >> 24) & 0xFFU); + data_p[1] = (unsigned char)((u32_be >> 16) & 0xFFU); + data_p[2] = (unsigned char)((u32_be >> 8) & 0xFFU); + data_p[3] = (unsigned char)(u32_be & 0xFFU); + + if (data_pp != NULL) { + *data_pp = data_p + 4; + } + + return; +} + +void +ys_write_u32_le(unsigned long u32_le, + unsigned char *data_p, unsigned char **data_pp) +/*---------------------------------------------------------------------------*\ + * Writes an unsigned 32 bit integer in little-endian format to the buffer + * pointed to by 'data_p'. + * If 'data_pp' is not null, the function will set it to point just beyond + * the integer written. +\*---------------------------------------------------------------------------*/ +{ + data_p[0] = (unsigned char)(u32_le & 0xFFU); + data_p[1] = (unsigned char)((u32_le >> 8) & 0xFFU); + data_p[2] = (unsigned char)((u32_le >> 16) & 0xFFU); + data_p[3] = (unsigned char)((u32_le >> 24) & 0xFFU); + + if (data_pp != NULL) { + *data_pp = data_p + 4; + } + + return; +} + +void +ys_write_s32_be(long s32_be, unsigned char *data_p, unsigned char **data_pp) +/*---------------------------------------------------------------------------*\ + * Writes an signed 32 bit integer in big-endian format and two's + * complement representation to the buffer pointed to by 'data_p'. + * If 'data_pp' is not null, the function will set it to point just beyond + * the integer written. +\*---------------------------------------------------------------------------*/ +{ + unsigned long u32_be = s32_be; + + data_p[0] = (unsigned char)((u32_be >> 24) & 0xFFU); + data_p[1] = (unsigned char)((u32_be >> 16) & 0xFFU); + data_p[2] = (unsigned char)((u32_be >> 8) & 0xFFU); + data_p[3] = (unsigned char)(u32_be & 0xFFU); + + if (data_pp != NULL) { + *data_pp = data_p + 4; + } + + return; +} + +void +ys_write_s32_le(long s32_le, unsigned char *data_p, unsigned char **data_pp) +/*---------------------------------------------------------------------------*\ + * Writes an signed 32 bit integer in little-endian format and two's + * complement representation to the buffer pointed to by 'data_p'. + * If 'data_pp' is not null, the function will set it to point just beyond + * the integer written. +\*---------------------------------------------------------------------------*/ +{ + unsigned long u32_le = s32_le; + + data_p[0] = (unsigned char)(u32_le & 0xFFU); + data_p[1] = (unsigned char)((u32_le >> 8) & 0xFFU); + data_p[2] = (unsigned char)((u32_le >> 16) & 0xFFU); + data_p[3] = (unsigned char)((u32_le >> 24) & 0xFFU); + + if (data_pp != NULL) { + *data_pp = data_p + 4; + } + + return; +} + +} // End of namespace Saga diff --git a/saga/ys_dl_list.cpp b/saga/ys_dl_list.cpp new file mode 100644 index 0000000000..116f52e8ea --- /dev/null +++ b/saga/ys_dl_list.cpp @@ -0,0 +1,310 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +#include "reinherit.h" + +#include "yslib.h" + +namespace Saga { + +YS_DL_LIST *ys_dll_create(void) +{ + + YS_DL_LIST *new_list; + + new_list = (YS_DL_LIST *)malloc(sizeof *new_list); + + if (new_list != NULL) { + new_list->next = new_list; + new_list->prev = new_list; + + /* Sentinel is marked by self-referential node data. + * No other link is permitted to do this */ + new_list->data = new_list; + } + + return new_list; +} + +void ys_dll_destroy(YS_DL_LIST * list) +{ + YS_DL_NODE *walk_p; + YS_DL_NODE *temp_p; + + for (walk_p = list->next; walk_p != list; walk_p = temp_p) { + temp_p = walk_p->next; + + free(walk_p->data); + free(walk_p); + } + + free(list); + + return; +} + +void *ys_dll_get_data(YS_DL_NODE * node) +{ + return node->data; +} + +YS_DL_NODE *ys_dll_head(YS_DL_LIST * list) +{ + return (list->next != list) ? list->next : NULL; +} + +YS_DL_NODE *ys_dll_tail(YS_DL_LIST * list) +{ + return (list->prev != list) ? list->prev : NULL; +} + +YS_DL_NODE *ys_dll_next(YS_DL_NODE *node) +{ + return (node->next != + (YS_DL_LIST *) node->next->data) ? node->next : NULL; +} + +YS_DL_NODE *ys_dll_prev(YS_DL_NODE * node) +{ + return (node->prev != + (YS_DL_LIST *) node->prev->data) ? node->prev : NULL; +} + +YS_DL_NODE *ys_dll_add_head(YS_DL_LIST * list, void *data, size_t size) +{ + YS_DL_NODE *new_node; + void *new_data; + + new_node = (YS_DL_NODE *)malloc(sizeof *new_node); + + if (new_node) { + new_data = malloc(size); + + if (new_data) { + memcpy(new_data, data, size); + new_node->data = new_data; + + new_node->prev = list; + new_node->next = list->next; + new_node->next->prev = new_node; + list->next = new_node; + } + } + return new_node; +} + +YS_DL_NODE *ys_dll_add_tail(YS_DL_LIST * list, void *data, size_t size) +{ + YS_DL_NODE *new_node; + void *new_data; + + new_node = (YS_DL_NODE *)malloc(sizeof *new_node); + + if (new_node != NULL) { + new_data = malloc(size); + + if (new_data != NULL) { + + memcpy(new_data, data, size); + new_node->data = new_data; + + new_node->next = list; + new_node->prev = list->prev; + new_node->prev->next = new_node; + list->prev = new_node; + } + } + return new_node; +} + +YS_DL_NODE *ys_dll_insert(YS_DL_NODE * list, + void *data, size_t size, YS_COMPARE_FUNC * compare) +{ + YS_DL_NODE *walk_p; + YS_DL_NODE *new_node; + int result; + + for (walk_p = list->next; walk_p != list; walk_p = walk_p->next) { + + result = compare(data, walk_p->data); + if (result < 0) { + new_node = ys_dll_preinsert(walk_p, data, size); + return new_node; + } + } + + new_node = ys_dll_add_tail(list, data, size); + return new_node; +} + +int ys_dll_delete(YS_DL_NODE * node) +{ + + if (node == NULL) { + return YS_E_FAILURE; + } + + node->next->prev = node->prev; + node->prev->next = node->next; + + free(node->data); + free(node); + + return YS_E_SUCCESS; +} + +void ys_dll_delete_all(YS_DL_LIST * list) +{ + YS_DL_NODE *walk_p; + YS_DL_NODE *temp_p; + + for (walk_p = list->next; walk_p != list; walk_p = temp_p) { + temp_p = walk_p->next; + + free(walk_p->data); + free(walk_p); + } + + list->next = list; + list->prev = list; + + return; +} + +YS_DL_NODE *ys_dll_replace(YS_DL_NODE * node, void *data, size_t size) +{ + void *new_data; + + if ((node == NULL) || (data == NULL) || (!size)) { + return NULL; + } + + new_data = malloc(size); + + if (new_data == NULL) { + return NULL; + } + + free(node->data); + node->data = new_data; + memcpy(new_data, data, size); + + return node; +} + +int +ys_dll_reorder_up(YS_DL_NODE * list, + YS_DL_NODE * olink, YS_COMPARE_FUNC * compare) +{ + YS_DL_NODE *walk_p; + int result; + int reorder = 0; + + for (walk_p = olink->prev; walk_p != list; walk_p = walk_p->prev) { + result = compare(walk_p->data, olink->data); + if (result <= 0) { + reorder = 1; + break; + } + } + + if (reorder) { + /* Unlink original link */ + olink->next->prev = olink->prev; + olink->prev->next = olink->next; + + /* Reinsert after walk link */ + olink->prev = walk_p; + olink->next = walk_p->next; + olink->next->prev = olink; + walk_p->next = olink; + } + return YS_E_SUCCESS; +} + +int +ys_dll_reorder_down(YS_DL_NODE * list, + YS_DL_NODE * olink, YS_COMPARE_FUNC * compare) +{ + YS_DL_NODE *walk_p; + int result; + int reorder = 0; + + for (walk_p = olink->next; walk_p != list; walk_p = walk_p->next) { + result = compare(walk_p->data, olink->data); + if (result >= 0) { + reorder = 1; + break; + } + } + + if (reorder) { + /* Unlink original link */ + olink->next->prev = olink->prev; + olink->prev->next = olink->next; + + /* Reinsert before walk link */ + olink->next = walk_p; + olink->prev = walk_p->prev; + olink->prev->next = olink; + walk_p->prev = olink; + } + return YS_E_SUCCESS; +} + +int +ys_dll_foreach(YS_DL_NODE * list, + int direction, + void *param, + int (*ys_dll_proc) (void *data, void *param), YS_DL_NODE ** t_node) +{ + YS_DL_NODE *walk_p; + + /* Only walk bakcward if explicitly requested to */ + if (direction == YS_WALK_BACKWARD) { + for (walk_p = list->prev; walk_p != list; + walk_p = walk_p->prev) { + + if (ys_dll_proc(walk_p->data, param) == 0) { + break; + } + + } + } else { + /* Default behavior is to walk forwards */ + for (walk_p = list->next; walk_p != list; + walk_p = walk_p->next) { + + if (ys_dll_proc(walk_p->data, param) == 0) { + break; + } + } + } + + if (t_node) { + *t_node = (walk_p != list) ? walk_p : NULL; + } + + return YS_E_SUCCESS; +} + +} // End of namespace Saga diff --git a/saga/ys_file.cpp b/saga/ys_file.cpp new file mode 100644 index 0000000000..39cb84cff0 --- /dev/null +++ b/saga/ys_file.cpp @@ -0,0 +1,63 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + +#include "yslib.h" + +namespace Saga { + +int ys_get_filesize(FILE * file_p, unsigned long *len_p, int *p_errno) +/*--------------------------------------------------------------------------*\ + * Returns the 'size' of the specified file. The file must be opened in + * binary mode. Note that not all operating systems support determing the + * exact end of a binary file stream, so this function is limited in + * portability. +\*--------------------------------------------------------------------------*/ +{ + long f_pos; + long f_len; + + f_pos = ftell(file_p); + if (f_pos == -1) { + *p_errno = errno; + return YS_E_FAILURE; + } + + fseek(file_p, 0, SEEK_END); + + f_len = ftell(file_p); + if (f_pos == -1) { + *p_errno = errno; + return YS_E_FAILURE; + } + + fseek(file_p, f_pos, SEEK_SET); + + *len_p = (unsigned long)f_len; + + return YS_E_SUCCESS;; +} + +} // End of namespace Saga diff --git a/saga/yslib.h b/saga/yslib.h new file mode 100644 index 0000000000..b5bc464d2c --- /dev/null +++ b/saga/yslib.h @@ -0,0 +1,219 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +#ifndef YSLIB_MAIN_H__ +#define YSLIB_MAIN_H__ + +namespace Saga { + +enum YS_ERROR_STATES { + + YS_E_SUCCESS = 0, + YS_E_FAILURE, + YS_E_MEM +}; + +enum YS_CONFIRM_STATES { + + YS_CONFIRM_NO = 0, + YS_CONFIRM_YES, + YS_CONFIRM_CANCEL +}; + +/* General purpose quantity-comparison function */ +typedef int (YS_COMPARE_FUNC) (const void *, const void *); + +/* General-purpose utility macros +\*------------------------------------------------------------------*/ + +/* Ignore a parameter (Supress warnings) */ +#define YS_IGNORE_PARAM( param ) ( void )( param ) + +/* Calculate the number of elements in an array */ +#define YS_NELEMS( arr ) (( sizeof arr ) / ( sizeof *arr )) + +#define YS_DUMMY_DECL /* C99 permits statements before declarations */ + +#define YS_REG_FUNC( arr ) YS_DUMMY_DECL +#define YS_FUNC __func__ + +#define YS_FLEX_ARRAY +#define YS_FLEX_ARRAY_MOD 0 + +/* Minimum and maximum of two values */ +#define YS_MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define YS_MAX(a,b) (((a) > (b)) ? (a) : (b)) + +/* Minimum and maximum of two objects, convert to lvalue */ +#define YS_LV_MIN(a,b) (*((a) < (b)) ? &(a) : &(b)) +#define YS_LV_MAX(a,b) (*((a) < (b)) ? &(a) : &(b)) + +#define YS_ABS(n) ((n < 0) ? -n : n) + +/* ys_binread.c : Binary input functions (buffer oriented) +\*------------------------------------------------------------------*/ + +/* #define YS_ASSUME_2S_COMP */ + +/* Read a 4CC ( Four characater code ) */ +void +ys_read_4cc(char *fourcc, + const unsigned char *data_p, const unsigned char **data_pp); + +/* Read 8 bit unsigned integer */ +unsigned int ys_read_u8(const unsigned char *, const unsigned char **); + +/* Read 8 bit signed integer */ +int ys_read_s8(const unsigned char *, const unsigned char **); + +/* Read 16 bit unsigned integer, big-endian */ +unsigned int ys_read_u16_be(const unsigned char *, const unsigned char **); + +/* Read 16 bit unsigned integer, little-endian */ +unsigned int ys_read_u16_le(const unsigned char *, const unsigned char **); + +/* Read 16 bit signed integer, 2's complement, big-endian */ +int ys_read_s16_be(const unsigned char *, const unsigned char **); + +/* Read 16 bit signed integer, 2's complement, little-endian */ +int ys_read_s16_le(const unsigned char *, const unsigned char **); + +/* Read 24 bit unsigned integer, big-endian */ +unsigned long ys_read_u24_be(const unsigned char *, const unsigned char **); + +/* Read 24 bit unsigned integer, little-endian */ +unsigned long ys_read_u24_le(const unsigned char *, const unsigned char **); + +/* Read 24 bit signed integer, 2's complement, big-endian */ +long ys_read_s24_be(const unsigned char *, const unsigned char **); + +/* Read 24 bit signed integer, 2's complement, little-endian */ +long ys_read_s24_le(const unsigned char *, const unsigned char **); + +/* Read 32 bit unsigned integer, big-endian */ +unsigned long ys_read_u32_be(const unsigned char *, const unsigned char **); + +/* Read 32 bit unsigned integer, little-endian */ +unsigned long ys_read_u32_le(const unsigned char *, const unsigned char **); + +/* Read 32 bit signed integer, 2's complement, big-endian */ +long ys_read_s32_be(const unsigned char *, const unsigned char **); + +/* Read 32 bit signed integer, 2's complement, little-endian */ +long ys_read_s32_le(const unsigned char *, const unsigned char **); + +/* ys_binwrite.c : Binary output functions ( buffer oriented ) +\*------------------------------------------------------------------*/ + +void ys_write_u8(unsigned int, unsigned char *, unsigned char **); + +/* Write 16 bit unsigned integer, big-endian */ +void ys_write_u16_be(unsigned int, unsigned char *, unsigned char **); + +/* Write 16 bit unsigned integer, little-endian */ +void ys_write_u16_le(unsigned int, unsigned char *, unsigned char **); + +/* Write 16 bit signed integer, 2's complement, big-endian */ +void ys_write_s16_be(int, unsigned char *, unsigned char **); + +/* Write 16 bit signed integer, 2's complement, little-endian */ +void ys_write_s16_le(int, unsigned char *, unsigned char **); + +/* Write 24 bit unsigned integer, big-endian */ +void ys_write_u24_be(unsigned long, unsigned char *, unsigned char **); + +/* Write 24 bit unsigned integer, little-endian */ +void ys_write_u24_le(unsigned long, unsigned char *, unsigned char **); + +/* Write 24 bit signed integer, 2's complement, big-endian */ +void ys_write_s24_be(long, unsigned char *, unsigned char **); + +/* Write 24 bit signed integer, 2's complement, little-endian */ +void ys_write_s24_le(long, unsigned char *, unsigned char **); + +/* Write 32 bit unsigned integer, big-endian */ +void ys_write_u32_be(unsigned long, unsigned char *, unsigned char **); + +/* Write 32 bit unsigned integer, little-endian */ +void ys_write_u32_le(unsigned long, unsigned char *, unsigned char **); + +/* Write 32 bit signed integer, 2's complement, big-endian */ +void ys_write_s32_be(long, unsigned char *, unsigned char **); + +/* Write 32 bit signed integer, 2's complement, little-endian */ +void ys_write_s32_le(long, unsigned char *, unsigned char **); + + +/* ys_file.c : File management functions +\*------------------------------------------------------------------*/ +int ys_get_filesize(FILE *, unsigned long *, int *); + +/* Shared declarations for list modules +\*------------------------------------------------------------------*/ +enum YS_WALK_DIRECTIONS { + YS_WALK_BACKWARD = 0, + YS_WALK_FORWARD +}; + +/* ys_dl_list.c : Doubly-linked list functions +\*------------------------------------------------------------------*/ +typedef struct ys_dl_node_tag YS_DL_NODE; +typedef struct ys_dl_node_tag YS_DL_LIST; + +struct ys_dl_node_tag { + void *data; + struct ys_dl_node_tag *next; + struct ys_dl_node_tag *prev; +}; + +YS_DL_LIST *ys_dll_create(void); +void ys_dll_destroy(YS_DL_LIST *); + +void *ys_dll_get_data(YS_DL_NODE *); + +YS_DL_NODE *ys_dll_head(YS_DL_LIST *); +YS_DL_NODE *ys_dll_tail(YS_DL_LIST *); +YS_DL_NODE *ys_dll_next(YS_DL_NODE *); +YS_DL_NODE *ys_dll_prev(YS_DL_NODE *); + +YS_DL_NODE *ys_dll_add_head(YS_DL_LIST *, void *, size_t); +YS_DL_NODE *ys_dll_add_tail(YS_DL_LIST *, void *, size_t); + +#define ys_dll_preinsert ys_dll_add_tail +#define ys_dll_postinsert ys_dll_add_head + +YS_DL_NODE *ys_dll_insert(YS_DL_LIST *, void *, size_t, YS_COMPARE_FUNC *); +int ys_dll_delete(YS_DL_NODE *); +void ys_dll_delete_all(YS_DL_LIST *); + +YS_DL_NODE *ys_dll_replace(YS_DL_NODE *, void *, size_t); + +int ys_dll_reorder_up(YS_DL_LIST *, YS_DL_NODE *, YS_COMPARE_FUNC *); +int ys_dll_reorder_down(YS_DL_LIST *, YS_DL_NODE *, YS_COMPARE_FUNC *); + +int ys_dll_foreach(YS_DL_LIST *, + int, void *, int (*)(void *, void *), YS_DL_NODE **); + + +} // End of namespace Saga + +#endif /* YSLIB_MAIN_H__ */ |