/* Sarien - A Sierra AGI resource interpreter engine * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka * * $Id: cycle.c,v 1.75 2001/11/06 01:07:38 cmatsuoka Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; see docs/COPYING for further details. */ #include "sarien.h" #include "agi.h" #include "text.h" #include "sprite.h" #include "graphics.h" #include "keyboard.h" #include "menu.h" #define TICK_SECONDS 20 #ifdef USE_MOUSE struct mouse mouse; #endif /** * 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; _D (_D_WARN "room %d", n); stop_sound (); i = 0; for_each_vt_entry (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; } /* function 0x10d0 */ 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 - v->x_size; break; } game.vars[V_border_touch_ego] = 0; setflag (F_new_room_exec, TRUE); game.exit_all_logics = TRUE; /* clear kb buffer */ /* write status */ /* function 0x38d5 */ } static void reset_controllers () { int i; for (i = 0; i < MAX_DIRS; i++) { game.ev_scan[i].occured = FALSE; 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 (); } } /** * Print user input prompt. */ static void print_line_prompt () { _D (_D_WARN "input mode = %d", game.input_mode); if (game.input_mode == INPUT_NORMAL) { _D (_D_WARN "prompt = '%s'", agi_sprintf (game.strings[0])); print_text (game.strings[0], 0, 0, game.line_user_input, 1, game.color_fg, game.color_bg); print_text ((char *)game.input_buffer, 0, 1, game.line_user_input, game.cursor_pos + 1, game.color_fg, game.color_bg); print_character (game.cursor_pos + 1, game.line_user_input, game.cursor_char, game.color_fg, game.color_bg); do_update (); /* synchronous */ } } void update_timer () { if (!game.clock_enabled) return; clock_count++; if (clock_count <= TICK_SECONDS) return; clock_count -= TICK_SECONDS; 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 ("Sarien didn't recognize this game and may " "execute it with an incorrect interpreter version. " "Please check the configuration file; if this game " "is not listed, please contact the authors."); 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); switch (game.input_mode) { case INPUT_NORMAL: if (!handle_controller (key)) { if (key == 0) break; handle_keys (key); /* commented out to close bug #438872 * if (key) game.keypress = key; */ } break; case INPUT_GETSTRING: handle_controller (key); handle_getstring (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; } int run_game () { int ec = err_OK; _D (_D_WARN "initializing..."); stop_sound (); setflag (F_logic_zero_firsttime, TRUE); /* not in 2.917 */ setflag (F_new_room_exec, TRUE); /* needed for MUMG and SQ2! */ setflag (F_restart_game, FALSE); 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.input_mode = INPUT_NONE; 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); _D (_D_WARN "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) { print_line_prompt (); game.has_prompt = 1; } interpret_cycle (); setflag (F_entered_cli, FALSE); setflag (F_said_accepted_input, FALSE); } if (game.quit_prog_now == 0xff) ec = err_RestartGame; } while (game.quit_prog_now == 0); stop_sound (); return ec; }