diff options
Diffstat (limited to 'saga/interface.cpp')
-rw-r--r-- | saga/interface.cpp | 756 |
1 files changed, 756 insertions, 0 deletions
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 |