diff options
Diffstat (limited to 'engines/agi/cycle.cpp')
-rw-r--r-- | engines/agi/cycle.cpp | 423 |
1 files changed, 423 insertions, 0 deletions
diff --git a/engines/agi/cycle.cpp b/engines/agi/cycle.cpp new file mode 100644 index 0000000000..1c5365e4d1 --- /dev/null +++ b/engines/agi/cycle.cpp @@ -0,0 +1,423 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2006 The ScummVM project + * + * Copyright (C) 1999-2003 Sarien Team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/stdafx.h" + +#include "agi/agi.h" +#include "agi/text.h" +#include "agi/sprite.h" +#include "agi/graphics.h" +#include "agi/keyboard.h" +#include "agi/menu.h" +#include "agi/savegame.h" + +namespace Agi { + +#define TICK_SECONDS 20 + +#ifdef USE_MOUSE +struct mouse mouse; +#endif + +volatile uint32 clock_ticks; +volatile uint32 clock_count; + +/** + * Set up new room. + * This function is called when ego enters a new room. + * @param n room number + */ +void new_room(int n) { + struct vt_entry *v; + int i; + + debugC(4, kDebugLevelMain, "*** room %d ***", n); + stop_sound(); + + i = 0; + for (v = game.view_table; v < &game.view_table[MAX_VIEWTABLE]; v++) { + v->entry = i++; + v->flags &= ~(ANIMATED | DRAWN); + v->flags |= UPDATE; + v->step_time = 1; + v->step_time_count = 1; + v->cycle_time = 1; + v->cycle_time_count = 1; + v->step_size = 1; + } + agi_unload_resources(); + + game.player_control = true; + game.block.active = false; + game.horizon = 36; + game.vars[V_prev_room] = game.vars[V_cur_room]; + game.vars[V_cur_room] = n; + game.vars[V_border_touch_obj] = 0; + game.vars[V_border_code] = 0; + game.vars[V_ego_view_resource] = game.view_table[0].current_view; + + agi_load_resource(rLOGIC, n); + + /* Reposition ego in the new room */ + switch (game.vars[V_border_touch_ego]) { + case 1: + game.view_table[0].y_pos = _HEIGHT - 1; + break; + case 2: + game.view_table[0].x_pos = 0; + break; + case 3: + game.view_table[0].y_pos = HORIZON + 1; + break; + case 4: + game.view_table[0].x_pos = _WIDTH - game.view_table[0].x_size; + break; + } + + game.vars[V_border_touch_ego] = 0; + setflag(F_new_room_exec, true); + + game.exit_all_logics = true; + + write_status(); + write_prompt(); +} + +static void reset_controllers() { + int i; + + for (i = 0; i < MAX_DIRS; i++) { + game.ev_keyp[i].occured = false; + } +} + +static void interpret_cycle() { + int old_sound, old_score; + + if (game.player_control) + game.vars[V_ego_dir] = game.view_table[0].direction; + else + game.view_table[0].direction = game.vars[V_ego_dir]; + + check_all_motions(); + + old_score = game.vars[V_score]; + old_sound = getflag(F_sound_on); + + game.exit_all_logics = false; + while (run_logic(0) == 0 && !game.quit_prog_now) { + game.vars[V_word_not_found] = 0; + game.vars[V_border_touch_obj] = 0; + game.vars[V_border_code] = 0; + old_score = game.vars[V_score]; + setflag(F_entered_cli, false); + game.exit_all_logics = false; + reset_controllers(); + } + reset_controllers(); + + game.view_table[0].direction = game.vars[V_ego_dir]; + + if (game.vars[V_score] != old_score || getflag(F_sound_on) != old_sound) + write_status(); + + game.vars[V_border_touch_obj] = 0; + game.vars[V_border_code] = 0; + setflag(F_new_room_exec, false); + setflag(F_restart_game, false); + setflag(F_restore_just_ran, false); + + if (game.gfx_mode) { + update_viewtable(); + do_update(); + } +} + +/** + * Update AGI interpreter timer. + */ +void update_timer() { + clock_count++; + if (clock_count <= TICK_SECONDS) + return; + + clock_count -= TICK_SECONDS; + + if (!game.clock_enabled) + return; + + setvar(V_seconds, getvar(V_seconds) + 1); + if (getvar(V_seconds) < 60) + return; + + setvar(V_seconds, 0); + setvar(V_minutes, getvar(V_minutes) + 1); + if (getvar(V_minutes) < 60) + return; + + setvar(V_minutes, 0); + setvar(V_hours, getvar(V_hours) + 1); + if (getvar(V_hours) < 24) + return; + + setvar(V_hours, 0); + setvar(V_days, getvar(V_days) + 1); +} + +static int old_mode = -1; + +void new_input_mode(int i) { + old_mode = game.input_mode; + game.input_mode = i; +} + +void old_input_mode() { + game.input_mode = old_mode; +} + +/* If main_cycle returns false, don't process more events! */ +int main_cycle() { + unsigned int key, kascii; + struct vt_entry *v = &game.view_table[0]; + + poll_timer(); /* msdos driver -> does nothing */ + update_timer(); + + if (game.ver == 0) { + message_box("Warning: game CRC not listed, assuming AGI version 2.917."); + game.ver = -1; + } + + key = do_poll_keyboard(); + +#ifdef USE_MOUSE + /* In AGI Mouse emulation mode we must update the mouse-related + * vars in every interpreter cycle. + */ + if (opt.agimouse) { + game.vars[28] = mouse.x / 2; + game.vars[29] = mouse.y; + } +#endif + +#ifdef USE_CONSOLE + if (key == KEY_PRIORITY) { + erase_both(); + debug_.priority = !debug_.priority; + show_pic(); + blit_both(); + commit_both(); + key = 0; + } + + if (key == KEY_STATUSLN) { + debug_.statusline = !debug_.statusline; + write_status(); + key = 0; + } +#endif + + /* Click-to-walk mouse interface */ + if (game.player_control && v->flags & ADJ_EGO_XY) { + v->direction = get_direction(v->x_pos, v->y_pos, v->parm1, v->parm2, v->step_size); + + if (v->direction == 0) + in_destination(v); + } + + kascii = KEY_ASCII(key); + + if (!console_keyhandler(key)) { + if (kascii) + setvar(V_key, kascii); + process_key: + switch (game.input_mode) { + case INPUT_NORMAL: + if (!handle_controller(key)) { + if (key == 0 || !game.input_enabled) + break; + handle_keys(key); + + /* if ESC pressed, activate menu before + * accept.input from the interpreter cycle + * sets the input mode to normal again + * (closes: #540856) + */ + if (key == KEY_ESCAPE) { + key = 0; + goto process_key; + } + + /* commented out to close bug #438872 + * if (key) game.keypress = key; + */ + } + break; + case INPUT_GETSTRING: + handle_controller(key); + handle_getstring(key); + setvar(V_key, 0); /* clear ENTER key */ + break; + case INPUT_MENU: + menu_keyhandler(key); + console_cycle(); + return false; + case INPUT_NONE: + handle_controller(key); + if (key) + game.keypress = key; + break; + } + } else { + if (game.input_mode == INPUT_MENU) { + console_cycle(); + return false; + } + } + + console_cycle(); + + if (game.msg_box_ticks > 0) + game.msg_box_ticks--; + + return true; +} + +static int play_game() { + int ec = err_OK; + + debugC(2, kDebugLevelMain, "initializing..."); + debugC(2, kDebugLevelMain, "game.ver = 0x%x", game.ver); + + stop_sound(); + clear_screen(0); + + game.horizon = HORIZON; + game.player_control = false; + + setflag(F_logic_zero_firsttime, true); /* not in 2.917 */ + setflag(F_new_room_exec, true); /* needed for MUMG and SQ2! */ + setflag(F_sound_on, true); /* enable sound */ + setvar(V_time_delay, 2); /* "normal" speed */ + + game.gfx_mode = true; + game.quit_prog_now = false; + game.clock_enabled = true; + game.line_user_input = 22; + +#ifdef USE_MOUSE + if (opt.agimouse) + report("Using AGI Mouse 1.0 protocol\n"); +#endif + + report("Running AGI script.\n"); + +#ifdef USE_CONSOLE + console.count = 5; + console_prompt(); +#endif + + setflag(F_entered_cli, false); + setflag(F_said_accepted_input, false); + game.vars[V_word_not_found] = 0; + game.vars[V_key] = 0; + + debugC(2, kDebugLevelMain, "Entering main loop"); + do { + + if (!main_cycle()) + continue; + + if (getvar(V_time_delay) == 0 || + (1 + clock_count) % getvar(V_time_delay) == 0) { + if (!game.has_prompt && game.input_mode == INPUT_NORMAL) { + write_prompt(); + game.has_prompt = 1; + } else + if (game.has_prompt && game.input_mode == INPUT_NONE) { + write_prompt(); + game.has_prompt = 0; + } + + interpret_cycle(); + + setflag(F_entered_cli, false); + setflag(F_said_accepted_input, false); + game.vars[V_word_not_found] = 0; + game.vars[V_key] = 0; + } + + if (game.quit_prog_now == 0xff) + ec = err_RestartGame; + + } while (game.quit_prog_now == 0); + + stop_sound(); + + return ec; +} + +int run_game() { + int i, ec = err_OK; + +#ifdef USE_HIRES + if (opt.cgaemu) + opt.hires = 0; +#endif + + for (i = 0; i < MAX_DIRS; i++) + memset(&game.ev_keyp[i], 0, sizeof(struct agi_event)); + + /* Execute the game */ + do { + debugC(2, kDebugLevelMain, "game loop"); + debugC(2, kDebugLevelMain, "game.ver = 0x%x", game.ver); + + if (agi_init() != err_OK) + break; + if (ec == err_RestartGame) + setflag(F_restart_game, true); + + setvar(V_computer, 0); /* IBM PC (4 = Atari ST) */ + setvar(V_soundgen, 1); /* IBM PC SOUND */ + setvar(V_monitor, 0x3); /* EGA monitor */ + setvar(V_max_input_chars, 38); + game.input_mode = INPUT_NONE; + game.input_enabled = 0; + game.has_prompt = 0; + + game.state = STATE_RUNNING; + ec = play_game(); + game.state = STATE_LOADED; + agi_deinit(); + } while (ec == err_RestartGame); + + menu_deinit(); + + release_image_stack(); + + return ec; +} + +} // End of namespace Agi |