diff options
author | Alyssa Milburn | 2011-08-17 09:28:51 +0200 |
---|---|---|
committer | Alyssa Milburn | 2011-08-17 09:28:51 +0200 |
commit | ae287ccee58ebf68ab6125e5bbb4d8a44874330e (patch) | |
tree | 2f4cee4b2940466b8a578962e0174c6f89077a40 /engines/agi | |
parent | f5255288eabc0527c4c6b727a9db6b8d09a31206 (diff) | |
parent | e36832bbf84cba88fe6b17e1634fab0d550f13df (diff) | |
download | scummvm-rg350-ae287ccee58ebf68ab6125e5bbb4d8a44874330e.tar.gz scummvm-rg350-ae287ccee58ebf68ab6125e5bbb4d8a44874330e.tar.bz2 scummvm-rg350-ae287ccee58ebf68ab6125e5bbb4d8a44874330e.zip |
Merge remote-tracking branch 'origin/master' into soccer
Conflicts:
engines/scumm/he/logic_he.cpp
engines/scumm/he/logic_he.h
Diffstat (limited to 'engines/agi')
46 files changed, 3746 insertions, 2936 deletions
diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp index 0eefbab04d..4bebf97e95 100644 --- a/engines/agi/agi.cpp +++ b/engines/agi/agi.cpp @@ -504,6 +504,7 @@ AgiBase::AgiBase(OSystem *syst, const AGIGameDescription *gameDesc) : Engine(sys _noSaveLoadAllowed = false; _rnd = new Common::RandomSource("agi"); + _sound = 0; initFeatures(); initVersion(); @@ -511,6 +512,11 @@ AgiBase::AgiBase(OSystem *syst, const AGIGameDescription *gameDesc) : Engine(sys AgiBase::~AgiBase() { delete _rnd; + + if (_sound) { + _sound->deinitSound(); + delete _sound; + } } AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBase(syst, gameDesc) { @@ -536,6 +542,8 @@ AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBas memset(&_debug, 0, sizeof(struct AgiDebug)); memset(&_mouse, 0, sizeof(struct Mouse)); + _game._vm = this; + _game.clockEnabled = false; _game.state = STATE_INIT; @@ -571,7 +579,7 @@ AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBas _game.controllerOccured[i] = false; setupOpcodes(); - _curLogic = NULL; + _game._curLogic = NULL; _timerHack = 0; } @@ -680,8 +688,6 @@ AgiEngine::~AgiEngine() { agiDeinit(); delete _loader; - _sound->deinitSound(); - delete _sound; _gfx->deinitVideo(); delete _sprites; delete _picture; diff --git a/engines/agi/agi.h b/engines/agi/agi.h index 0155caf11d..080373d27b 100644 --- a/engines/agi/agi.h +++ b/engines/agi/agi.h @@ -88,6 +88,7 @@ typedef signed int Err; #define _EMPTY 0xfffff #define EGO_OWNED 0xff +#define EGO_OWNED_V1 0xf9 #define CRYPT_KEY_SIERRA "Avis Durgan" #define CRYPT_KEY_AGDS "Alex Simkin" @@ -131,10 +132,16 @@ enum AgiGameID { enum AgiGameType { GType_PreAGI = 0, - GType_V2 = 1, - GType_V3 = 2 + GType_V1 = 1, + GType_V2 = 2, + GType_V3 = 3 }; + enum BooterDisks { + BooterDisk1 = 0, + BooterDisk2 = 1 + }; + // // GF_OLDAMIGAV20 means that the interpreter is an old Amiga AGI interpreter that // uses value 20 for the computer type (v20 i.e. vComputer) rather than the usual value 5. @@ -537,6 +544,8 @@ enum { * by the interpreter. */ struct AgiGame { + AgiEngine *_vm; + State state; /**< state of the interpreter */ // TODO: Check whether adjMouseX and adjMouseY must be saved and loaded when using savegames. @@ -621,6 +630,11 @@ struct AgiGame { AgiView views[MAX_DIRS]; /**< AGI view resources */ AgiSound *sounds[MAX_DIRS]; /**< Pointers to AGI sound resources */ + AgiLogic *_curLogic; + + // words + Common::Array<AgiWord*> words[26]; + // view table VtEntry viewTable[MAX_VIEWTABLE]; @@ -629,6 +643,13 @@ struct AgiGame { int simpleSave; /**< select simple savegames */ Common::Rect mouseFence; /**< rectangle set by fence.mouse command */ + + // IF condition handling + int testResult; + + + int max_logics; + int logic_list[256]; }; class AgiLoader { @@ -646,6 +667,28 @@ public: virtual int loadWords(const char *) = 0; }; +class AgiLoader_v1 : public AgiLoader { +private: + AgiEngine *_vm; + Common::String _filenameDisk0; + Common::String _filenameDisk1; + + int loadDir_DDP(AgiDir *agid, int offset, int max); + int loadDir_BC(AgiDir *agid, int offset, int max); + uint8 *loadVolRes(AgiDir *agid); + +public: + AgiLoader_v1(AgiEngine *vm); + + virtual int init(); + virtual int deinit(); + virtual int detectGame(); + virtual int loadResource(int, int); + virtual int unloadResource(int, int); + virtual int loadObjects(const char *); + virtual int loadWords(const char *); +}; + class AgiLoader_v2 : public AgiLoader { private: AgiEngine *_vm; @@ -690,6 +733,7 @@ public: virtual int loadWords(const char *); }; + class GfxMgr; class SpritesMgr; class Menu; @@ -745,6 +789,8 @@ public: AgiGame _game; Common::RandomSource *_rnd; + SoundMgr *_sound; + Mouse _mouse; bool _noSaveLoadAllowed; @@ -789,10 +835,14 @@ public: void initVersion(); void setVersion(uint16 version); + const char *getDiskName(uint16 id); + bool canLoadGameStateCurrently(); bool canSaveGameStateCurrently(); }; +typedef void (*AgiCommand)(AgiGame *state, uint8 *p); + class AgiEngine : public AgiBase { protected: // Engine APIs @@ -851,7 +901,6 @@ public: char _lastSentence[40]; SpritesMgr *_sprites; - SoundMgr *_sound; PictureMgr *_picture; AgiLoader *_loader; // loader @@ -915,16 +964,21 @@ public: void checkQuickLoad(); // Objects +public: int showObjects(); - int decodeObjects(uint8 *mem, uint32 flen); int loadObjects(const char *fname); - int allocObjects(int); + int loadObjects(Common::File &fp); void unloadObjects(); const char *objectName(unsigned int); int objectGetLocation(unsigned int); void objectSetLocation(unsigned int, int); +private: + int decodeObjects(uint8 *mem, uint32 flen); + int readObjects(Common::File &fp, int flen); + int allocObjects(int); // Logic +public: int decodeLogic(int); void unloadLogic(int); int runLogic(int); @@ -932,8 +986,10 @@ public: int testIfCode(int); void executeAgiCommand(uint8, uint8 *); -private: +public: // Some submethods of testIfCode + void skipInstruction(byte op); + void skipInstructionsUntil(byte v); uint8 testObjRight(uint8, uint8, uint8, uint8, uint8); uint8 testObjCenter(uint8, uint8, uint8, uint8, uint8); uint8 testObjInBox(uint8, uint8, uint8, uint8, uint8); @@ -966,8 +1022,10 @@ public: bool isEgoView(const VtEntry *v); // Words +public: int showWords(); int loadWords(const char *); + int loadWords_v1(Common::File &f); void unloadWords(); int findWord(const char *word, int *flen); void dictionaryWords(char *); @@ -1045,196 +1103,13 @@ public: char _predictiveResult[40]; private: - typedef void (AgiEngine::*AgiCommand)(uint8 *); - AgiCommand _agiCommands[183]; - AgiLogic *_curLogic; - int _timerHack; // Workaround for timer loop in MH1 logic 153 + AgiCommand _agiCondCommands[256]; void setupOpcodes(); - void cmd_increment(uint8 *p); - void cmd_decrement(uint8 *p); - void cmd_assignn(uint8 *p); - void cmd_assignv(uint8 *p); - void cmd_addn(uint8 *p); - void cmd_addv(uint8 *p); - void cmd_subn(uint8 *p); - void cmd_subv(uint8 *p); // 0x08 - void cmd_lindirectv(uint8 *p); - void cmd_rindirect(uint8 *p); - void cmd_lindirectn(uint8 *p); - void cmd_set(uint8 *p); - void cmd_reset(uint8 *p); - void cmd_toggle(uint8 *p); - void cmd_set_v(uint8 *p); - void cmd_reset_v(uint8 *p); // 0x10 - void cmd_toggle_v(uint8 *p); - void cmd_new_room(uint8 *p); - void cmd_new_room_f(uint8 *p); - void cmd_load_logic(uint8 *p); - void cmd_load_logic_f(uint8 *p); - void cmd_call(uint8 *p); - void cmd_call_f(uint8 *p); - void cmd_load_pic(uint8 *p); // 0x18 - void cmd_draw_pic(uint8 *p); - void cmd_show_pic(uint8 *p); - void cmd_discard_pic(uint8 *p); - void cmd_overlay_pic(uint8 *p); - void cmd_show_pri_screen(uint8 *p); - void cmd_load_view(uint8 *p); - void cmd_load_view_f(uint8 *p); - void cmd_discard_view(uint8 *p); // 0x20 - void cmd_animate_obj(uint8 *p); - void cmd_unanimate_all(uint8 *p); - void cmd_draw(uint8 *p); - void cmd_erase(uint8 *p); - void cmd_position(uint8 *p); - void cmd_position_f(uint8 *p); - void cmd_get_posn(uint8 *p); - void cmd_reposition(uint8 *p); // 0x28 - void cmd_set_view(uint8 *p); - void cmd_set_view_f(uint8 *p); - void cmd_set_loop(uint8 *p); - void cmd_set_loop_f(uint8 *p); - void cmd_fix_loop(uint8 *p); - void cmd_release_loop(uint8 *p); - void cmd_set_cel(uint8 *p); - void cmd_set_cel_f(uint8 *p); // 0x30 - void cmd_last_cel(uint8 *p); - void cmd_current_cel(uint8 *p); - void cmd_current_loop(uint8 *p); - void cmd_current_view(uint8 *p); - void cmd_number_of_loops(uint8 *p); - void cmd_set_priority(uint8 *p); - void cmd_set_priority_f(uint8 *p); - void cmd_release_priority(uint8 *p); // 0x38 - void cmd_get_priority(uint8 *p); - void cmd_stop_update(uint8 *p); - void cmd_start_update(uint8 *p); - void cmd_force_update(uint8 *p); - void cmd_ignore_horizon(uint8 *p); - void cmd_observe_horizon(uint8 *p); - void cmd_set_horizon(uint8 *p); - void cmd_object_on_water(uint8 *p); // 0x40 - void cmd_object_on_land(uint8 *p); - void cmd_object_on_anything(uint8 *p); - void cmd_ignore_objs(uint8 *p); - void cmd_observe_objs(uint8 *p); - void cmd_distance(uint8 *p); - void cmd_stop_cycling(uint8 *p); - void cmd_start_cycling(uint8 *p); - void cmd_normal_cycle(uint8 *p); // 0x48 - void cmd_end_of_loop(uint8 *p); - void cmd_reverse_cycle(uint8 *p); - void cmd_reverse_loop(uint8 *p); - void cmd_cycle_time(uint8 *p); - void cmd_stop_motion(uint8 *p); - void cmd_start_motion(uint8 *p); - void cmd_step_size(uint8 *p); - void cmd_step_time(uint8 *p); // 0x50 - void cmd_move_obj(uint8 *p); - void cmd_move_obj_f(uint8 *p); - void cmd_follow_ego(uint8 *p); - void cmd_wander(uint8 *p); - void cmd_normal_motion(uint8 *p); - void cmd_set_dir(uint8 *p); - void cmd_get_dir(uint8 *p); - void cmd_ignore_blocks(uint8 *p); // 0x58 - void cmd_observe_blocks(uint8 *p); - void cmd_block(uint8 *p); - void cmd_unblock(uint8 *p); - void cmd_get(uint8 *p); - void cmd_get_f(uint8 *p); - void cmd_drop(uint8 *p); - void cmd_put(uint8 *p); - void cmd_put_f(uint8 *p); // 0x60 - void cmd_get_room_f(uint8 *p); - void cmd_load_sound(uint8 *p); - void cmd_sound(uint8 *p); - void cmd_stop_sound(uint8 *p); - void cmd_print(uint8 *p); - void cmd_print_f(uint8 *p); - void cmd_display(uint8 *p); - void cmd_display_f(uint8 *p); // 0x68 - void cmd_clear_lines(uint8 *p); - void cmd_text_screen(uint8 *p); - void cmd_graphics(uint8 *p); - void cmd_set_cursor_char(uint8 *p); - void cmd_set_text_attribute(uint8 *p); - void cmd_shake_screen(uint8 *p); - void cmd_configure_screen(uint8 *p); - void cmd_status_line_on(uint8 *p); // 0x70 - void cmd_status_line_off(uint8 *p); - void cmd_set_string(uint8 *p); - void cmd_get_string(uint8 *p); - void cmd_word_to_string(uint8 *p); - void cmd_parse(uint8 *p); - void cmd_get_num(uint8 *p); - void cmd_prevent_input(uint8 *p); - void cmd_accept_input(uint8 *p); // 0x78 - void cmd_set_key(uint8 *p); - void cmd_add_to_pic(uint8 *p); - void cmd_add_to_pic_f(uint8 *p); - void cmd_status(uint8 *p); - void cmd_save_game(uint8 *p); - void cmd_load_game(uint8 *p); - void cmd_init_disk(uint8 *p); - void cmd_restart_game(uint8 *p); // 0x80 - void cmd_show_obj(uint8 *p); - void cmd_random(uint8 *p); - void cmd_program_control(uint8 *p); - void cmd_player_control(uint8 *p); - void cmd_obj_status_f(uint8 *p); - void cmd_quit(uint8 *p); - void cmd_show_mem(uint8 *p); - void cmd_pause(uint8 *p); // 0x88 - void cmd_echo_line(uint8 *p); - void cmd_cancel_line(uint8 *p); - void cmd_init_joy(uint8 *p); - void cmd_toggle_monitor(uint8 *p); - void cmd_version(uint8 *p); - void cmd_script_size(uint8 *p); - void cmd_set_game_id(uint8 *p); - void cmd_log(uint8 *p); // 0x90 - void cmd_set_scan_start(uint8 *p); - void cmd_reset_scan_start(uint8 *p); - void cmd_reposition_to(uint8 *p); - void cmd_reposition_to_f(uint8 *p); - void cmd_trace_on(uint8 *p); - void cmd_trace_info(uint8 *p); - void cmd_print_at(uint8 *p); - void cmd_print_at_v(uint8 *p); // 0x98 - //void cmd_discard_view(uint8 *p); // Opcode repeated from 0x20 ? - void cmd_clear_text_rect(uint8 *p); - void cmd_set_upper_left(uint8 *p); - void cmd_set_menu(uint8 *p); - void cmd_set_menu_item(uint8 *p); - void cmd_submit_menu(uint8 *p); - void cmd_enable_item(uint8 *p); - void cmd_disable_item(uint8 *p); // 0xa0 - void cmd_menu_input(uint8 *p); - void cmd_show_obj_v(uint8 *p); - void cmd_open_dialogue(uint8 *p); - void cmd_close_dialogue(uint8 *p); - void cmd_mul_n(uint8 *p); - void cmd_mul_v(uint8 *p); - void cmd_div_n(uint8 *p); - void cmd_div_v(uint8 *p); // 0xa8 - void cmd_close_window(uint8 *p); - void cmd_set_simple(uint8 *p); - void cmd_push_script(uint8 *p); - void cmd_pop_script(uint8 *p); - void cmd_hold_key(uint8 *p); - void cmd_set_pri_base(uint8 *p); - void cmd_discard_sound(uint8 *p); - void cmd_hide_mouse(uint8 *p); // 0xb0 - void cmd_allow_menu(uint8 *p); - void cmd_show_mouse(uint8 *p); - void cmd_fence_mouse(uint8 *p); - void cmd_mouse_posn(uint8 *p); - void cmd_release_key(uint8 *p); - void cmd_adj_ego_move_to_x_y(uint8 *p); +public: + int _timerHack; // Workaround for timer loop in MH1 logic 153 }; } // End of namespace Agi diff --git a/engines/agi/checks.cpp b/engines/agi/checks.cpp index 20276657ff..c3b31f6ba9 100644 --- a/engines/agi/checks.cpp +++ b/engines/agi/checks.cpp @@ -31,7 +31,7 @@ int AgiEngine::checkPosition(VtEntry *v) { v->xPos + v->xSize > _WIDTH || v->yPos - v->ySize + 1 < 0 || v->yPos >= _HEIGHT || - ((~v->flags & IGNORE_HORIZON) && v->yPos <= _game.horizon)) { + ((~v->flags & fIgnoreHorizon) && v->yPos <= _game.horizon)) { debugC(4, kDebugLevelSprites, "check position failed: x=%d, y=%d, h=%d, w=%d", v->xPos, v->yPos, v->xSize, v->ySize); return 0; @@ -52,14 +52,14 @@ int AgiEngine::checkPosition(VtEntry *v) { int AgiEngine::checkCollision(VtEntry *v) { VtEntry *u; - if (v->flags & IGNORE_OBJECTS) + if (v->flags & fIgnoreObjects) return 0; for (u = _game.viewTable; u < &_game.viewTable[MAX_VIEWTABLE]; u++) { - if ((u->flags & (ANIMATED | DRAWN)) != (ANIMATED | DRAWN)) + if ((u->flags & (fAnimated | fDrawn)) != (fAnimated | fDrawn)) continue; - if (u->flags & IGNORE_OBJECTS) + if (u->flags & fIgnoreObjects) continue; // Same object, check next @@ -92,7 +92,7 @@ int AgiEngine::checkPriority(VtEntry *v) { int i, trigger, water, pass, pri; uint8 *p0; - if (~v->flags & FIXED_PRIORITY) { + if (~v->flags & fFixedPriority) { // Priority bands v->priority = _game.priTable[v->yPos]; } @@ -129,7 +129,7 @@ int AgiEngine::checkPriority(VtEntry *v) { water = 0; if (pri == 1) { // conditional blue - if (v->flags & IGNORE_BLOCKS) + if (v->flags & fIgnoreBlocks) continue; debugC(4, kDebugLevelSprites, "Blocks observed!"); @@ -145,9 +145,9 @@ int AgiEngine::checkPriority(VtEntry *v) { } if (pass) { - if (!water && v->flags & ON_WATER) + if (!water && v->flags & fOnWater) pass = 0; - if (water && v->flags & ON_LAND) + if (water && v->flags & fOnLand) pass = 0; } @@ -180,7 +180,7 @@ void AgiEngine::updatePosition() { _game.vars[vBorderTouchObj] = 0; for (v = _game.viewTable; v < &_game.viewTable[MAX_VIEWTABLE]; v++) { - if ((v->flags & (ANIMATED | UPDATE | DRAWN)) != (ANIMATED | UPDATE | DRAWN)) { + if ((v->flags & (fAnimated | fUpdate | fDrawn)) != (fAnimated | fUpdate | fDrawn)) { continue; } @@ -195,7 +195,7 @@ void AgiEngine::updatePosition() { y = oldY = v->yPos; // If object has moved, update its position - if (~v->flags & UPDATE_POS) { + if (~v->flags & fUpdatePos) { int dx[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 }; int dy[9] = { 0, -1, -1, 0, 1, 1, 1, 0, -1 }; x += v->stepSize * dx[v->direction]; @@ -212,7 +212,7 @@ void AgiEngine::updatePosition() { } else if (x <= 0 && getVersion() == 0x3086) { // KQ4 x = 0; // See Sarien bug #590462 border = 4; - } else if (v->entry == 0 && x == 0 && v->flags & ADJ_EGO_XY) { + } else if (v->entry == 0 && x == 0 && v->flags & fAdjEgoXY) { // Extra test to walk west clicking the mouse x = 0; border = 4; @@ -228,7 +228,7 @@ void AgiEngine::updatePosition() { } else if (y > _HEIGHT - 1) { y = _HEIGHT - 1; border = 3; - } else if ((~v->flags & IGNORE_HORIZON) && y <= _game.horizon) { + } else if ((~v->flags & fIgnoreHorizon) && y <= _game.horizon) { debugC(4, kDebugLevelSprites, "y = %d, horizon = %d", y, _game.horizon); y = _game.horizon + 1; border = 1; @@ -251,12 +251,12 @@ void AgiEngine::updatePosition() { _game.vars[vBorderCode] = v->entry; _game.vars[vBorderTouchObj] = border; } - if (v->motion == MOTION_MOVE_OBJ) { + if (v->motion == kMotionMoveObj) { inDestination(v); } } - v->flags &= ~UPDATE_POS; + v->flags &= ~fUpdatePos; } } @@ -276,7 +276,7 @@ void AgiEngine::fixPosition(int n) { debugC(4, kDebugLevelSprites, "adjusting view table entry #%d (%d,%d)", n, v->xPos, v->yPos); // test horizon - if ((~v->flags & IGNORE_HORIZON) && v->yPos <= _game.horizon) + if ((~v->flags & fIgnoreHorizon) && v->yPos <= _game.horizon) v->yPos = _game.horizon + 1; dir = 0; diff --git a/engines/agi/console.cpp b/engines/agi/console.cpp index d49bd57ea2..dd06736290 100644 --- a/engines/agi/console.cpp +++ b/engines/agi/console.cpp @@ -96,8 +96,8 @@ bool Console::Cmd_RunOpcode(int argc, const char **argv) { for (int i = 0; logicNamesCmd[i].name; i++) { if (!strcmp(argv[1], logicNamesCmd[i].name)) { uint8 p[16]; - if ((argc - 2) != logicNamesCmd[i].numArgs) { - DebugPrintf("AGI command wants %d arguments\n", logicNamesCmd[i].numArgs); + if ((argc - 2) != logicNamesCmd[i].argumentsLength()) { + DebugPrintf("AGI command wants %d arguments\n", logicNamesCmd[i].argumentsLength()); return 0; } p[0] = argv[2] ? (char)strtoul(argv[2], NULL, 0) : 0; @@ -260,7 +260,7 @@ bool Console::Cmd_BT(int argc, const char **argv) { for (it = _vm->_game.execStack.begin(); it != _vm->_game.execStack.end(); ++it) { code = _vm->_game.logics[it->script].data; op = code[it->curIP]; - num = logicNamesCmd[op].numArgs; + num = logicNamesCmd[op].argumentsLength(); memmove(p, &code[it->curIP], num); memset(p + num, 0, CMD_BSIZE - num); @@ -275,25 +275,21 @@ bool Console::Cmd_BT(int argc, const char **argv) { return true; } -PreAGI_Console::PreAGI_Console(PreAgiEngine *vm) { - _vm = vm; -} - -Mickey_Console::Mickey_Console(PreAgiEngine *vm, Mickey *mickey) : PreAGI_Console(vm) { +MickeyConsole::MickeyConsole(MickeyEngine *mickey) : GUI::Debugger() { _mickey = mickey; - DCmd_Register("curRoom", WRAP_METHOD(Mickey_Console, Cmd_CurRoom)); - DCmd_Register("gotoRoom", WRAP_METHOD(Mickey_Console, Cmd_GotoRoom)); - DCmd_Register("drawPic", WRAP_METHOD(Mickey_Console, Cmd_DrawPic)); - DCmd_Register("drawObj", WRAP_METHOD(Mickey_Console, Cmd_DrawObj)); + DCmd_Register("curRoom", WRAP_METHOD(MickeyConsole, Cmd_CurRoom)); + DCmd_Register("gotoRoom", WRAP_METHOD(MickeyConsole, Cmd_GotoRoom)); + DCmd_Register("drawPic", WRAP_METHOD(MickeyConsole, Cmd_DrawPic)); + DCmd_Register("drawObj", WRAP_METHOD(MickeyConsole, Cmd_DrawObj)); } -bool Mickey_Console::Cmd_CurRoom(int argc, const char **argv) { +bool MickeyConsole::Cmd_CurRoom(int argc, const char **argv) { _mickey->debugCurRoom(); return true; } -bool Mickey_Console::Cmd_GotoRoom(int argc, const char **argv) { +bool MickeyConsole::Cmd_GotoRoom(int argc, const char **argv) { if (argc != 2) DebugPrintf("Usage: %s <Room number>\n", argv[0]); else @@ -301,7 +297,7 @@ bool Mickey_Console::Cmd_GotoRoom(int argc, const char **argv) { return true; } -bool Mickey_Console::Cmd_DrawPic(int argc, const char **argv) { +bool MickeyConsole::Cmd_DrawPic(int argc, const char **argv) { if (argc != 2) DebugPrintf("Usage: %s <Picture number>\n", argv[0]); else @@ -309,7 +305,7 @@ bool Mickey_Console::Cmd_DrawPic(int argc, const char **argv) { return true; } -bool Mickey_Console::Cmd_DrawObj(int argc, const char **argv) { +bool MickeyConsole::Cmd_DrawObj(int argc, const char **argv) { if (argc != 2) DebugPrintf("Usage: %s <Object number>\n", argv[0]); else @@ -317,13 +313,13 @@ bool Mickey_Console::Cmd_DrawObj(int argc, const char **argv) { return true; } -Winnie_Console::Winnie_Console(PreAgiEngine *vm, Winnie *winnie) : PreAGI_Console(vm) { +WinnieConsole::WinnieConsole(WinnieEngine *winnie) : GUI::Debugger() { _winnie = winnie; - DCmd_Register("curRoom", WRAP_METHOD(Winnie_Console, Cmd_CurRoom)); + DCmd_Register("curRoom", WRAP_METHOD(WinnieConsole, Cmd_CurRoom)); } -bool Winnie_Console::Cmd_CurRoom(int argc, const char **argv) { +bool WinnieConsole::Cmd_CurRoom(int argc, const char **argv) { _winnie->debugCurRoom(); return true; diff --git a/engines/agi/console.h b/engines/agi/console.h index 308b0f1d1f..5f69460907 100644 --- a/engines/agi/console.h +++ b/engines/agi/console.h @@ -27,8 +27,8 @@ namespace Agi { class AgiEngine; class PreAgiEngine; -class Winnie; -class Mickey; +class MickeyEngine; +class WinnieEngine; struct AgiDebug { int enabled; @@ -67,23 +67,13 @@ private: AgiEngine *_vm; }; -class PreAGI_Console : public GUI::Debugger { +class MickeyConsole : public GUI::Debugger { public: - PreAGI_Console(PreAgiEngine *vm); - virtual ~PreAGI_Console() {} + MickeyConsole(MickeyEngine *mickey); + virtual ~MickeyConsole() {} private: - PreAgiEngine *_vm; -}; - - -class Mickey_Console : public PreAGI_Console { -public: - Mickey_Console(PreAgiEngine *vm, Mickey *mickey); - virtual ~Mickey_Console() {} - -private: - Mickey *_mickey; + MickeyEngine *_mickey; bool Cmd_CurRoom(int argc, const char **argv); bool Cmd_GotoRoom(int argc, const char **argv); @@ -91,17 +81,17 @@ private: bool Cmd_DrawObj(int argc, const char **argv); }; -class Winnie_Console : public PreAGI_Console { +class WinnieConsole : public GUI::Debugger { public: - Winnie_Console(PreAgiEngine *vm, Winnie *winnie); - virtual ~Winnie_Console() {} + WinnieConsole(WinnieEngine *winnie); + virtual ~WinnieConsole() {} private: - Winnie *_winnie; + WinnieEngine *_winnie; bool Cmd_CurRoom(int argc, const char **argv); }; -} // End of namespace Agi +} // End of namespace Agi #endif /* AGI_CONSOLE_H */ diff --git a/engines/agi/cycle.cpp b/engines/agi/cycle.cpp index d86fb36709..e6f122f9f6 100644 --- a/engines/agi/cycle.cpp +++ b/engines/agi/cycle.cpp @@ -47,8 +47,8 @@ void AgiEngine::newRoom(int n) { i = 0; for (v = _game.viewTable; v < &_game.viewTable[MAX_VIEWTABLE]; v++) { v->entry = i++; - v->flags &= ~(ANIMATED | DRAWN); - v->flags |= UPDATE; + v->flags &= ~(fAnimated | fDrawn); + v->flags |= fUpdate; v->stepTime = 1; v->stepTimeCount = 1; v->cycleTime = 1; @@ -220,7 +220,7 @@ int AgiEngine::mainCycle() { } // Click-to-walk mouse interface - if (_game.playerControl && v->flags & ADJ_EGO_XY) { + if (_game.playerControl && v->flags & fAdjEgoXY) { int toX = v->parm1; int toY = v->parm2; diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp index 93fcd2d283..5141ab761f 100644 --- a/engines/agi/detection.cpp +++ b/engines/agi/detection.cpp @@ -28,6 +28,7 @@ #include "engines/advancedDetector.h" #include "common/config-manager.h" #include "common/file.h" +#include "common/md5.h" #include "common/savefile.h" #include "common/textconsole.h" #include "graphics/thumbnail.h" @@ -35,6 +36,9 @@ #include "agi/agi.h" #include "agi/preagi.h" +#include "agi/preagi_mickey.h" +#include "agi/preagi_troll.h" +#include "agi/preagi_winnie.h" #include "agi/wagparser.h" @@ -93,6 +97,14 @@ void AgiBase::initVersion() { _gameVersion = _gameDescription->version; } +const char *AgiBase::getDiskName(uint16 id) { + for (int i = 0; _gameDescription->desc.filesDescriptions[i].fileName != NULL; i++) + if (_gameDescription->desc.filesDescriptions[i].fileType == id) + return _gameDescription->desc.filesDescriptions[i].fileName; + + return ""; +} + } static const PlainGameDescriptor agiGames[] = { @@ -182,8 +194,19 @@ bool AgiMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameD switch (gd->gameType) { case Agi::GType_PreAGI: - *engine = new Agi::PreAgiEngine(syst, gd); + switch (gd->gameID) { + case GID_MICKEY: + *engine = new Agi::MickeyEngine(syst, gd); + break; + case GID_TROLL: + *engine = new Agi::TrollEngine(syst, gd); + break; + case GID_WINNIE: + *engine = new Agi::WinnieEngine(syst, gd); + break; + } break; + case Agi::GType_V1: case Agi::GType_V2: case Agi::GType_V3: *engine = new Agi::AgiEngine(syst, gd); @@ -477,7 +500,9 @@ int AgiEngine::agiDetectGame() { assert(_gameDescription != NULL); - if (getVersion() <= 0x2999) { + if (getVersion() <= 0x2001) { + _loader = new AgiLoader_v1(this); + } else if (getVersion() <= 0x2999) { _loader = new AgiLoader_v2(this); } else { _loader = new AgiLoader_v3(this); diff --git a/engines/agi/detection_tables.h b/engines/agi/detection_tables.h index cd3edf50c6..28e94075a6 100644 --- a/engines/agi/detection_tables.h +++ b/engines/agi/detection_tables.h @@ -37,7 +37,7 @@ using Common::GUIO_NONE; gid, \ interp, \ features, \ - ver, \ + ver \ } #define GAME_LVFPNF(id,name,fname,md5,size,lang,ver,features,gid,platform,interp) { \ @@ -53,9 +53,10 @@ using Common::GUIO_NONE; gid, \ interp, \ features, \ - ver, \ + ver \ } +#define BOOTER2(id,extra,fname,md5,size,ver,gid) GAME_LVFPN(id,extra,fname,md5,size,Common::EN_ANY,ver,0,gid,Common::kPlatformPC,GType_V2) #define GAME(id,extra,md5,ver,gid) GAME_LVFPN(id,extra,"logdir",md5,-1,Common::EN_ANY,ver,0,gid,Common::kPlatformPC,GType_V2) #define GAME3(id,extra,fname,md5,ver,gid) GAME_LVFPN(id,extra,fname,md5,-1,Common::EN_ANY,ver,0,gid,Common::kPlatformPC,GType_V3) @@ -118,6 +119,69 @@ static const AGIGameDescription gameDescriptions[] = { // AGI Demo for Kings Quest III and Space Quest I GAME("agidemo", "Demo Kings Quest III and Space Quest I", "502e6bf96827b6c4d3e67c9cdccd1033", 0x2272, GID_AGIDEMO), + { + // Black Cauldron (PC 3.5" booter) 1.1J [AGI 1.12] + { + "bc", + "Booter 1.1J", + { + { "bc-d1.img", BooterDisk1, "1d29a82b41c9c7491e2b68d16864bd11", 368640}, + { "bc-d2.img", BooterDisk2, "5568f7a52e787305656246f95e2aa375", 368640}, + { NULL, 0, NULL, 0} + }, + Common::EN_ANY, + Common::kPlatformPC, + ADGF_NO_FLAGS, + GUIO_NONE + }, + GID_BC, + GType_V1, + 0, + 0x1120 + }, + + { + // Black Cauldron (PC 3.5" booter) 1.1K [AGI 1.12] + { + "bc", + "Booter 1.1K", + { + { "bc-d1.img", BooterDisk1, "98a51d3a372baa9df288b6c0f0232567", 368640}, + { "bc-d2.img", BooterDisk2, "5568f7a52e787305656246f95e2aa375", 368640}, + { NULL, 0, NULL, 0} + }, + Common::EN_ANY, + Common::kPlatformPC, + ADGF_NO_FLAGS, + GUIO_NONE + }, + GID_BC, + GType_V1, + 0, + 0x1120 + }, + + { + // Black Cauldron (PC 3.5" booter) 1.1M [AGI 1.12] + { + "bc", + "Booter 1.1M", + { + { "bc-d1.img", BooterDisk1, "edc0e5befbe5e44bb109cdf9137ee12d", 368640}, + { "bc-d2.img", BooterDisk2, "5568f7a52e787305656246f95e2aa375", 368640}, + { NULL, 0, NULL, 0} + }, + Common::EN_ANY, + Common::kPlatformPC, + ADGF_NO_FLAGS, + GUIO_NONE + }, + GID_BC, + GType_V1, + 0, + 0x1120 + }, + // Black Cauldron (Amiga) 2.00 6/14/87 GAME_P("bc", "2.00 1987-06-14", "7b01694af21213b4727bb94476f64eb5", 0x2440, GID_BC, Common::kPlatformAmiga), @@ -143,9 +207,9 @@ static const AGIGameDescription gameDescriptions[] = { // Black Cauldron (CoCo3 360k) [AGI 2.072] GAME_PS("bc", "updated", "c4e1937f74e8100cd0152b904434d8b4", 357, 0x2440, GID_BC, Common::kPlatformCoCo3), -// TODO -// These aren't supposed to work now as they require unsupported agi engine 2.01 -#if 0 + // Donald Duck's Playground (PC Booter) 1.0Q + BOOTER2("ddp", "Booter 1.0Q", "ddp.img", "f323f10abf8140ffb2668b09af2e7b87", 368640, 0x2001, GID_DDP), + // Donald Duck's Playground (Amiga) 1.0C // Menus not tested GAME_P("ddp", "1.0C 1987-04-27", "550971d196f65190a5c760d2479406ef", 0x2272, GID_DDP, Common::kPlatformAmiga), @@ -157,7 +221,6 @@ static const AGIGameDescription gameDescriptions[] = { // reported by Filippos (thebluegr) in bugreport #1654500 // Menus not tested GAME_PS("ddp", "1.0C 1986-06-09", "550971d196f65190a5c760d2479406ef", 132, 0x2272, GID_DDP, Common::kPlatformPC), -#endif // Gold Rush! (Amiga) 1.01 1/13/89 aka 2.05 3/9/89 # 2.316 GAME3_PS("goldrush", "1.01 1989-01-13 aka 2.05 1989-03-09", "dirs", "a1d4de3e75c2688c1e2ca2634ffc3bd8", 2399, 0x3149, 0, GID_GOLDRUSH, Common::kPlatformAmiga), @@ -196,7 +259,7 @@ static const AGIGameDescription gameDescriptions[] = { GID_GOLDRUSH, GType_V3, GF_MACGOLDRUSH, - 0x3149, + 0x3149 }, @@ -514,7 +577,7 @@ static const AGIGameDescription gameDescriptions[] = { GID_SQ2, GType_V2, 0, - 0x2936, + 0x2936 }, @@ -659,7 +722,7 @@ static const AGIGameDescription gameDescriptions[] = { GID_FANMADE, GType_V2, GF_AGDS, - 0x2440, + 0x2440 }, { @@ -676,7 +739,7 @@ static const AGIGameDescription gameDescriptions[] = { GID_GETOUTTASQ, GType_V2, 0, - 0x2440, + 0x2440 }, FANMADE_F("Half-Death - Terror At White-Mesa", "b62c05d0ace878261392073f57ae788c", GF_AGIMOUSE), @@ -831,7 +894,7 @@ static const AGIGameDescription gameDescriptions[] = { GID_FANMADE, GType_V3, GF_FANMADE, - 0x3149, + 0x3149 }, FANMADE_SVP("V - The Graphical Adventure", "1646eaade74f137a9041eb427a389969", 768, 0x2440, Common::kPlatformCoCo3), @@ -859,7 +922,7 @@ static AGIGameDescription g_fallbackDesc = { GID_FANMADE, GType_V2, GF_FANMADE, - 0x2917, + 0x2917 }; } // End of namespace Agi diff --git a/engines/agi/id.cpp b/engines/agi/id.cpp index 00f8407529..dd370d4189 100644 --- a/engines/agi/id.cpp +++ b/engines/agi/id.cpp @@ -48,14 +48,17 @@ int AgiEngine::setupV2Game(int ver) { // 'quit' takes 0 args for 2.089 if (ver == 0x2089) - logicNamesCmd[0x86].numArgs = 0; +// logicNamesCmd[0x86].numArgs = 0; + logicNamesCmd[0x86].args = ""; // 'print.at' and 'print.at.v' take 3 args before 2.272 // This is documented in the specs as only < 2.440, but it seems // that KQ3 (2.272) needs a 'print.at' taking 4 args. if (ver < 0x2272) { - logicNamesCmd[0x97].numArgs = 3; - logicNamesCmd[0x98].numArgs = 3; +// logicNamesCmd[0x97].numArgs = 3; +// logicNamesCmd[0x98].numArgs = 3; + logicNamesCmd[0x97].args = "vvv"; + logicNamesCmd[0x98].args = "vvv"; } return ec; @@ -73,8 +76,10 @@ int AgiEngine::setupV3Game(int ver) { // 'unknown173' also takes 1 arg for 3.002.068, not 0 args. // Is this actually used anywhere? -- dsymonds if (ver == 0x3086) { - logicNamesCmd[0xb0].numArgs = 1; - logicNamesCmd[0xad].numArgs = 1; +// logicNamesCmd[0xb0].numArgs = 1; +// logicNamesCmd[0xad].numArgs = 1; + logicNamesCmd[0xb0].args = "n"; + logicNamesCmd[0xad].args = "n"; } // FIXME: Apply this fix to other games also that use 2 arguments for command 182. @@ -83,7 +88,8 @@ int AgiEngine::setupV3Game(int ver) { // has been set to use AGI 3.149 in ScummVM so that's why this initialization is // here and not in setupV2Game. if (getGameID() == GID_GOLDRUSH && getPlatform() == Common::kPlatformAmiga) - logicNamesCmd[182].numArgs = 2; +// logicNamesCmd[182].numArgs = 2; + logicNamesCmd[182].args = "vv"; return ec; } diff --git a/engines/agi/keyboard.cpp b/engines/agi/keyboard.cpp index f5810a6e8c..d899a6e202 100644 --- a/engines/agi/keyboard.cpp +++ b/engines/agi/keyboard.cpp @@ -180,7 +180,7 @@ int AgiEngine::handleController(int key) { if (!(getFeatures() & GF_AGIMOUSE)) { // Handle mouse button events if (key == BUTTON_LEFT) { - v->flags |= ADJ_EGO_XY; + v->flags |= fAdjEgoXY; v->parm1 = WIN_TO_PIC_X(_mouse.x); v->parm2 = WIN_TO_PIC_Y(_mouse.y); return true; @@ -188,7 +188,7 @@ int AgiEngine::handleController(int key) { } if (d || key == KEY_STATIONARY) { - v->flags &= ~ADJ_EGO_XY; + v->flags &= ~fAdjEgoXY; v->direction = v->direction == d ? 0 : d; return true; } diff --git a/engines/agi/loader_v1.cpp b/engines/agi/loader_v1.cpp new file mode 100644 index 0000000000..c6a3e66705 --- /dev/null +++ b/engines/agi/loader_v1.cpp @@ -0,0 +1,329 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +#include "agi/agi.h" +#include "common/md5.h" + +#define IMAGE_SIZE 368640 // = 40 * 2 * 9 * 512 = tracks * sides * sectors * sector size +#define SECTOR_OFFSET(s) ((s) * 512) + +#define DDP_BASE_SECTOR 0x1C2 +#define DDP_LOGDIR_SEC SECTOR_OFFSET(171) + 5 +#define DDP_LOGDIR_MAX 43 +#define DDP_PICDIR_SEC SECTOR_OFFSET(180) + 5 +#define DDP_PICDIR_MAX 30 +#define DDP_VIEWDIR_SEC SECTOR_OFFSET(189) + 5 +#define DDP_VIEWDIR_MAX 171 +#define DDP_SNDDIR_SEC SECTOR_OFFSET(198) + 5 +#define DDP_SNDDIR_MAX 64 + +#define BC_LOGDIR_SEC SECTOR_OFFSET(90) + 5 +#define BC_LOGDIR_MAX 118 +#define BC_VIEWDIR_SEC SECTOR_OFFSET(96) + 5 +#define BC_VIEWDIR_MAX 180 +#define BC_PICDIR_SEC SECTOR_OFFSET(93) + 8 +#define BC_PICDIR_MAX 117 +#define BC_SNDDIR_SEC SECTOR_OFFSET(99) + 5 +#define BC_SNDDIR_MAX 29 +#define BC_WORDS SECTOR_OFFSET(0x26D) + 5 +#define BC_OBJECTS SECTOR_OFFSET(0x1E6) + 3 + +namespace Agi { + + +AgiLoader_v1::AgiLoader_v1(AgiEngine *vm) { + _vm = vm; +} + +int AgiLoader_v1::detectGame() { + // Find filenames for the disk images + _filenameDisk0 = _vm->getDiskName(BooterDisk1); + _filenameDisk1 = _vm->getDiskName(BooterDisk2); + + return _vm->setupV2Game(_vm->getVersion()); +} + +int AgiLoader_v1::loadDir_DDP(AgiDir *agid, int offset, int max) { + Common::File fp; + + if (!fp.open(_filenameDisk0)) + return errBadFileOpen; + + // Cleanup + for (int i = 0; i < MAX_DIRS; i++) { + agid[i].volume = 0xFF; + agid[i].offset = _EMPTY; + } + + fp.seek(offset, SEEK_SET); + for (int i = 0; i <= max; i++) { + int b0 = fp.readByte(); + int b1 = fp.readByte(); + int b2 = fp.readByte(); + + if (b0 == 0xFF && b1 == 0xFF && b2 == 0xFF) { + agid[i].volume = 0xFF; + agid[i].offset = _EMPTY; + } else { + int sec = (DDP_BASE_SECTOR + (((b0 & 0xF) << 8) | b1)) >> 1; + int off = ((b1 & 0x1) << 8) | b2; + agid[i].volume = 0; + agid[i].offset = SECTOR_OFFSET(sec) + off; + } + } + + fp.close(); + + return errOK; +} + +int AgiLoader_v1::loadDir_BC(AgiDir *agid, int offset, int max) { + Common::File fp; + + if (!fp.open(_filenameDisk0)) + return errBadFileOpen; + + // Cleanup + for (int i = 0; i < MAX_DIRS; i++) { + agid[i].volume = 0xFF; + agid[i].offset = _EMPTY; + } + + fp.seek(offset, SEEK_SET); + for (int i = 0; i <= max; i++) { + int b0 = fp.readByte(); + int b1 = fp.readByte(); + int b2 = fp.readByte(); + + if (b0 == 0xFF && b1 == 0xFF && b2 == 0xFF) { + agid[i].volume = 0xFF; + agid[i].offset = _EMPTY; + } else { + int sec = (b0 & 0x3F) * 18 + ((b1 >> 1) & 0x1) * 9 + ((b1 >> 2) & 0x1F) - 1; + int off = ((b1 & 0x1) << 8) | b2; + int vol = (b0 & 0xC0) >> 6; + agid[i].volume = 0; + agid[i].offset = (vol == 2) * IMAGE_SIZE + SECTOR_OFFSET(sec) + off; + } + } + + fp.close(); + + return errOK; +} + +int AgiLoader_v1::init() { + int ec = errOK; + + switch (_vm->getGameID()) { + case GID_DDP: + ec = loadDir_DDP(_vm->_game.dirLogic, DDP_LOGDIR_SEC, DDP_LOGDIR_MAX); + if (ec == errOK) + ec = loadDir_DDP(_vm->_game.dirPic, DDP_PICDIR_SEC, DDP_PICDIR_MAX); + if (ec == errOK) + ec = loadDir_DDP(_vm->_game.dirView, DDP_VIEWDIR_SEC, DDP_VIEWDIR_MAX); + if (ec == errOK) + ec = loadDir_DDP(_vm->_game.dirSound, DDP_SNDDIR_SEC, DDP_SNDDIR_MAX); + break; + + case GID_BC: + ec = loadDir_BC(_vm->_game.dirLogic, BC_LOGDIR_SEC, BC_LOGDIR_MAX); + if (ec == errOK) + ec = loadDir_BC(_vm->_game.dirPic, BC_PICDIR_SEC, BC_PICDIR_MAX); + if (ec == errOK) + ec = loadDir_BC(_vm->_game.dirView, BC_VIEWDIR_SEC, BC_VIEWDIR_MAX); + if (ec == errOK) + ec = loadDir_BC(_vm->_game.dirSound, BC_SNDDIR_SEC, BC_SNDDIR_MAX); + break; + } + + return ec; +} + +int AgiLoader_v1::deinit() { + int ec = errOK; + return ec; +} + +uint8 *AgiLoader_v1::loadVolRes(struct AgiDir *agid) { + uint8 *data = NULL; + Common::File fp; + int offset = agid->offset; + + if (offset == _EMPTY) + return NULL; + + if (offset > IMAGE_SIZE) { + fp.open(_filenameDisk1); + offset -= IMAGE_SIZE; + } else { + fp.open(_filenameDisk0); + } + + fp.seek(offset, SEEK_SET); + + int signature = fp.readUint16BE(); + if (signature != 0x1234) { + warning("AgiLoader_v1::loadVolRes: bad signature %04x", signature); + return NULL; + } + + fp.readByte(); + agid->len = fp.readUint16LE(); + data = (uint8 *)calloc(1, agid->len + 32); + fp.read(data, agid->len); + + fp.close(); + + return data; +} + +int AgiLoader_v1::loadResource(int t, int n) { + int ec = errOK; + uint8 *data = NULL; + + debugC(3, kDebugLevelResources, "(t = %d, n = %d)", t, n); + if (n > MAX_DIRS) + return errBadResource; + + switch (t) { + case rLOGIC: + if (~_vm->_game.dirLogic[n].flags & RES_LOADED) { + debugC(3, kDebugLevelResources, "loading logic resource %d", n); + unloadResource(rLOGIC, n); + + // load raw resource into data + data = loadVolRes(&_vm->_game.dirLogic[n]); + + _vm->_game.logics[n].data = data; + ec = data ? _vm->decodeLogic(n) : errBadResource; + + _vm->_game.logics[n].sIP = 2; + } + + // if logic was cached, we get here + // reset code pointers incase it was cached + + _vm->_game.logics[n].cIP = _vm->_game.logics[n].sIP; + break; + case rPICTURE: + // if picture is currently NOT loaded *OR* cacheing is off, + // unload the resource (caching == off) and reload it + + debugC(3, kDebugLevelResources, "loading picture resource %d", n); + if (_vm->_game.dirPic[n].flags & RES_LOADED) + break; + + // if loaded but not cached, unload it + // if cached but not loaded, etc + unloadResource(rPICTURE, n); + data = loadVolRes(&_vm->_game.dirPic[n]); + + if (data != NULL) { + _vm->_game.pictures[n].rdata = data; + _vm->_game.dirPic[n].flags |= RES_LOADED; + } else { + ec = errBadResource; + } + break; + case rSOUND: + debugC(3, kDebugLevelResources, "loading sound resource %d", n); + if (_vm->_game.dirSound[n].flags & RES_LOADED) + break; + + data = loadVolRes(&_vm->_game.dirSound[n]); + + if (data != NULL) { + // Freeing of the raw resource from memory is delegated to the createFromRawResource-function + _vm->_game.sounds[n] = AgiSound::createFromRawResource(data, _vm->_game.dirSound[n].len, n, *_vm->_sound, _vm->_soundemu); + _vm->_game.dirSound[n].flags |= RES_LOADED; + } else { + ec = errBadResource; + } + break; + case rVIEW: + // Load a VIEW resource into memory... + // Since VIEWS alter the view table ALL the time + // can we cache the view? or must we reload it all + // the time? + if (_vm->_game.dirView[n].flags & RES_LOADED) + break; + + debugC(3, kDebugLevelResources, "loading view resource %d", n); + unloadResource(rVIEW, n); + data = loadVolRes(&_vm->_game.dirView[n]); + if (data) { + _vm->_game.views[n].rdata = data; + _vm->_game.dirView[n].flags |= RES_LOADED; + ec = _vm->decodeView(n); + } else { + ec = errBadResource; + } + break; + default: + ec = errBadResource; + break; + } + + return ec; +} + +int AgiLoader_v1::unloadResource(int t, int n) { + switch (t) { + case rLOGIC: + _vm->unloadLogic(n); + break; + case rPICTURE: + _vm->_picture->unloadPicture(n); + break; + case rVIEW: + _vm->unloadView(n); + break; + case rSOUND: + _vm->_sound->unloadSound(n); + break; + } + + return errOK; +} + +int AgiLoader_v1::loadObjects(const char *fname) { + if (_vm->getGameID() == GID_BC) { + Common::File f; + f.open(_filenameDisk0); + f.seek(BC_OBJECTS, SEEK_SET); + return _vm->loadObjects(f); + } + return errOK; +} + +int AgiLoader_v1::loadWords(const char *fname) { + if (_vm->getGameID() == GID_BC) { + Common::File f; + f.open(_filenameDisk0); + f.seek(BC_WORDS, SEEK_SET); + return _vm->loadWords_v1(f); + } + return errOK; +} + +} diff --git a/engines/agi/module.mk b/engines/agi/module.mk index 2339d1019f..68d86f7b2e 100644 --- a/engines/agi/module.mk +++ b/engines/agi/module.mk @@ -11,6 +11,7 @@ MODULE_OBJS := \ id.o \ inv.o \ keyboard.o \ + loader_v1.o \ loader_v2.o \ loader_v3.o \ logic.o \ @@ -18,12 +19,12 @@ MODULE_OBJS := \ menu.o \ motion.o \ objects.o \ + opcodes.o \ op_cmd.o \ op_dbg.o \ op_test.o \ picture.o \ preagi.o \ - preagi_common.o \ preagi_mickey.o \ preagi_troll.o \ preagi_winnie.o \ diff --git a/engines/agi/motion.cpp b/engines/agi/motion.cpp index 261a7f3e61..e4de232267 100644 --- a/engines/agi/motion.cpp +++ b/engines/agi/motion.cpp @@ -52,9 +52,9 @@ void AgiEngine::changePos(VtEntry *v) { y += v->stepSize * dy[v->direction]; if (checkBlock(x, y) == b) { - v->flags &= ~MOTION; + v->flags &= ~fMotion; } else { - v->flags |= MOTION; + v->flags |= fMotion; v->direction = 0; if (isEgoView(v)) _game.vars[vEgoDir] = 0; @@ -63,7 +63,7 @@ void AgiEngine::changePos(VtEntry *v) { void AgiEngine::motionWander(VtEntry *v) { if (v->parm1--) { - if (~v->flags & DIDNT_MOVE) + if (~v->flags & fDidntMove) return; } @@ -94,14 +94,14 @@ void AgiEngine::motionFollowEgo(VtEntry *v) { // Already at ego coordinates if (dir == 0) { v->direction = 0; - v->motion = MOTION_NORMAL; + v->motion = kMotionNormal; setflag(v->parm2, true); return; } if (v->parm3 == 0xff) { v->parm3 = 0; - } else if (v->flags & DIDNT_MOVE) { + } else if (v->flags & fDidntMove) { int d; while ((v->direction = _rnd->getRandomNumber(8)) == 0) { @@ -152,18 +152,20 @@ void AgiEngine::motionMoveObj(VtEntry *v) { void AgiEngine::checkMotion(VtEntry *v) { switch (v->motion) { - case MOTION_WANDER: + case kMotionNormal: + break; + case kMotionWander: motionWander(v); break; - case MOTION_FOLLOW_EGO: + case kMotionFollowEgo: motionFollowEgo(v); break; - case MOTION_MOVE_OBJ: + case kMotionMoveObj: motionMoveObj(v); break; } - if ((_game.block.active && (~v->flags & IGNORE_BLOCKS)) && v->direction) + if ((_game.block.active && (~v->flags & fIgnoreBlocks)) && v->direction) changePos(v); } @@ -178,7 +180,7 @@ void AgiEngine::checkAllMotions() { VtEntry *v; for (v = _game.viewTable; v < &_game.viewTable[MAX_VIEWTABLE]; v++) { - if ((v->flags & (ANIMATED | UPDATE | DRAWN)) == (ANIMATED | UPDATE | DRAWN) + if ((v->flags & (fAnimated | fUpdate | fDrawn)) == (fAnimated | fUpdate | fDrawn) && v->stepTimeCount == 1) { checkMotion(v); } @@ -192,11 +194,11 @@ void AgiEngine::checkAllMotions() { * @param v Pointer to view table entry */ void AgiEngine::inDestination(VtEntry *v) { - if (v->motion == MOTION_MOVE_OBJ) { + if (v->motion == kMotionMoveObj) { v->stepSize = v->parm3; setflag(v->parm4, true); } - v->motion = MOTION_NORMAL; + v->motion = kMotionNormal; if (isEgoView(v)) _game.playerControl = true; } @@ -204,7 +206,7 @@ void AgiEngine::inDestination(VtEntry *v) { /** * Wrapper for static function motion_moveobj(). * This function is used by cmd_move_object() in the first motion cycle - * after setting the motion mode to MOTION_MOVE_OBJ. + * after setting the motion mode to kMotionMoveObj. * @param v Pointer to view table entry */ void AgiEngine::moveObj(VtEntry *v) { diff --git a/engines/agi/objects.cpp b/engines/agi/objects.cpp index e04c9742f3..efc8645287 100644 --- a/engines/agi/objects.cpp +++ b/engines/agi/objects.cpp @@ -34,7 +34,7 @@ int AgiEngine::allocObjects(int n) { } int AgiEngine::decodeObjects(uint8 *mem, uint32 flen) { - unsigned int i, so, padsize; + unsigned int i, so, padsize, spos; padsize = _game.gameFlags & ID_AMIGA ? 4 : 3; @@ -64,11 +64,12 @@ int AgiEngine::decodeObjects(uint8 *mem, uint32 flen) { return errNotEnoughMemory; // build the object list - for (i = 0, so = padsize; i < _game.numObjects; i++, so += padsize) { + spos = getVersion() >= 0x2000 ? padsize : 0; + for (i = 0, so = spos; i < _game.numObjects; i++, so += padsize) { int offset; (_objects + i)->location = *(mem + so + 2); - offset = READ_LE_UINT16(mem + so) + padsize; + offset = READ_LE_UINT16(mem + so) + spos; if ((uint) offset < flen) { (_objects + i)->name = (char *)strdup((const char *)mem + offset); @@ -84,20 +85,33 @@ int AgiEngine::decodeObjects(uint8 *mem, uint32 flen) { int AgiEngine::loadObjects(const char *fname) { Common::File fp; - uint32 flen; - uint8 *mem; - - _objects = NULL; - _game.numObjects = 0; debugC(5, kDebugLevelResources, "(Loading objects '%s')", fname); if (!fp.open(fname)) return errBadFileOpen; - fp.seek(0, SEEK_END); - flen = fp.pos(); - fp.seek(0, SEEK_SET); + return readObjects(fp, fp.size()); +} + +/** + * Loads an object file that is in the common VOL resource format. Expects + * the file pointer to point to the last field in header, ie. file length. + * This is used at least by the V1 booter games. + */ +int AgiEngine::loadObjects(Common::File &fp) { + int flen = fp.readUint16LE(); + return readObjects(fp, flen); +} + +/** + * Read and decode objects, and store them in the internal structure. + * + * @param fp File pointer + * @param flen File length + */ +int AgiEngine::readObjects(Common::File &fp, int flen) { + uint8 *mem; if ((mem = (uint8 *)calloc(1, flen + 32)) == NULL) { fp.close(); diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp index bde62fe2d9..17addc0c05 100644 --- a/engines/agi/op_cmd.cpp +++ b/engines/agi/op_cmd.cpp @@ -41,23 +41,36 @@ namespace Agi { #define p5 (p[5]) #define p6 (p[6]) -#define ip _curLogic->cIP -#define vt _game.viewTable[p0] -#define vt_v _game.viewTable[_game.vars[p0]] - -#define _v _game.vars - -void AgiEngine::cmd_increment(uint8 *p) { - if (_v[p0] != 0xff) - ++_v[p0]; +#define code state->_curLogic->data +#define ip state->_curLogic->cIP +#define vt state->viewTable[p0] +#define vt_v state->viewTable[state->vars[p0]] + +#define _v state->vars + +#define getGameID() state->_vm->getGameID() +#define getFeatures() state->_vm->getFeatures() +#define getVersion() state->_vm->getVersion() +#define getLanguage() state->_vm->getLanguage() +#define setflag(a,b) state->_vm->setflag(a,b) +#define getflag(a) state->_vm->getflag(a) + +void cmdIncrement(AgiGame *state, uint8 *p) { + if (getVersion() < 0x2000) { + if (_v[p0] < 0xf0) + ++_v[p0]; + } else { + if (_v[p0] != 0xff) + ++_v[p0]; + } } -void AgiEngine::cmd_decrement(uint8 *p) { +void cmdDecrement(AgiGame *state, uint8 *p) { if (_v[p0] != 0) --_v[p0]; } -void AgiEngine::cmd_assignn(uint8 *p) { +void cmdAssignN(AgiGame *state, uint8 *p) { _v[p0] = p1; // WORKAROUND for a bug in fan _game "Get outta SQ" @@ -71,84 +84,100 @@ void AgiEngine::cmd_assignn(uint8 *p) { _v[p0] = 8; } -void AgiEngine::cmd_addn(uint8 *p) { +void cmdAddN(AgiGame *state, uint8 *p) { _v[p0] += p1; } -void AgiEngine::cmd_subn(uint8 *p) { +void cmdSubN(AgiGame *state, uint8 *p) { _v[p0] -= p1; } -void AgiEngine::cmd_assignv(uint8 *p) { +void cmdAssignV(AgiGame *state, uint8 *p) { _v[p0] = _v[p1]; } -void AgiEngine::cmd_addv(uint8 *p) { +void cmdAddV(AgiGame *state, uint8 *p) { _v[p0] += _v[p1]; } -void AgiEngine::cmd_subv(uint8 *p) { +void cmdSubV(AgiGame *state, uint8 *p) { _v[p0] -= _v[p1]; } -void AgiEngine::cmd_mul_n(uint8 *p) { +void cmdMulN(AgiGame *state, uint8 *p) { _v[p0] *= p1; } -void AgiEngine::cmd_mul_v(uint8 *p) { +void cmdMulV(AgiGame *state, uint8 *p) { _v[p0] *= _v[p1]; } -void AgiEngine::cmd_div_n(uint8 *p) { +void cmdDivN(AgiGame *state, uint8 *p) { _v[p0] /= p1; } -void AgiEngine::cmd_div_v(uint8 *p) { +void cmdDivV(AgiGame *state, uint8 *p) { _v[p0] /= _v[p1]; } -void AgiEngine::cmd_random(uint8 *p) { - _v[p2] = _rnd->getRandomNumber(p1 - p0) + p0; +void cmdRandomV1(AgiGame *state, uint8 *p) { + _v[p0] = state->_vm->_rnd->getRandomNumber(250); +} + +void cmdRandom(AgiGame *state, uint8 *p) { + _v[p2] = state->_vm->_rnd->getRandomNumber(p1 - p0) + p0; } -void AgiEngine::cmd_lindirectn(uint8 *p) { +void cmdLindirectN(AgiGame *state, uint8 *p) { _v[_v[p0]] = p1; } -void AgiEngine::cmd_lindirectv(uint8 *p) { +void cmdLindirectV(AgiGame *state, uint8 *p) { _v[_v[p0]] = _v[p1]; } -void AgiEngine::cmd_rindirect(uint8 *p) { +void cmdRindirect(AgiGame *state, uint8 *p) { _v[p0] = _v[_v[p1]]; } -void AgiEngine::cmd_set(uint8 *p) { +void cmdSet(AgiGame *state, uint8 *p) { setflag(*p, true); } -void AgiEngine::cmd_reset(uint8 *p) { +void cmdReset(AgiGame *state, uint8 *p) { setflag(*p, false); } -void AgiEngine::cmd_toggle(uint8 *p) { +void cmdToggle(AgiGame *state, uint8 *p) { setflag(*p, !getflag(*p)); } -void AgiEngine::cmd_set_v(uint8 *p) { - setflag(_v[p0], true); +void cmdSetV(AgiGame *state, uint8 *p) { + if (getVersion() < 0x2000) { + _v[p0] = 1; + } else { + setflag(_v[p0], true); + } } -void AgiEngine::cmd_reset_v(uint8 *p) { - setflag(_v[p0], false); +void cmdResetV(AgiGame *state, uint8 *p) { + if (getVersion() < 0x2000) { + _v[p0] = 0; + } else { + setflag(_v[p0], false); + } } -void AgiEngine::cmd_toggle_v(uint8 *p) { - setflag(_v[p0], !getflag(_v[p0])); +void cmdToggleV(AgiGame *state, uint8 *p) { + if (getVersion() < 0x2000) { + _v[p0] ^= 1; + } else { + setflag(_v[p0], !getflag(_v[p0])); + } } -void AgiEngine::cmd_new_room(uint8 *p) { - newRoom(p0); +void cmdNewRoom(AgiGame *state, uint8 *p) { + state->_vm->newRoom(p0); // WORKAROUND: Works around intro skipping bug (#1737343) in Gold Rush. // Intro was skipped because the enter-keypress finalizing the entering @@ -160,83 +189,83 @@ void AgiEngine::cmd_new_room(uint8 *p) { // loaded so that no keys from the copy protection scene can be left // over to cause the intro to skip to the _game's start. if (getGameID() == GID_GOLDRUSH && p0 == 73) - _game.keypress = 0; + state->keypress = 0; } -void AgiEngine::cmd_new_room_f(uint8 *p) { - newRoom(_v[p0]); +void cmdNewRoomF(AgiGame *state, uint8 *p) { + state->_vm->newRoom(_v[p0]); } -void AgiEngine::cmd_load_view(uint8 *p) { - agiLoadResource(rVIEW, p0); +void cmdLoadView(AgiGame *state, uint8 *p) { + state->_vm->agiLoadResource(rVIEW, p0); } -void AgiEngine::cmd_load_logic(uint8 *p) { - agiLoadResource(rLOGIC, p0); +void cmdLoadLogic(AgiGame *state, uint8 *p) { + state->_vm->agiLoadResource(rLOGIC, p0); } -void AgiEngine::cmd_load_sound(uint8 *p) { - agiLoadResource(rSOUND, p0); +void cmdLoadSound(AgiGame *state, uint8 *p) { + state->_vm->agiLoadResource(rSOUND, p0); } -void AgiEngine::cmd_load_view_f(uint8 *p) { - agiLoadResource(rVIEW, _v[p0]); +void cmdLoadViewF(AgiGame *state, uint8 *p) { + state->_vm->agiLoadResource(rVIEW, _v[p0]); } -void AgiEngine::cmd_load_logic_f(uint8 *p) { - agiLoadResource(rLOGIC, _v[p0]); +void cmdLoadLogicF(AgiGame *state, uint8 *p) { + state->_vm->agiLoadResource(rLOGIC, _v[p0]); } -void AgiEngine::cmd_discard_view(uint8 *p) { - agiUnloadResource(rVIEW, p0); +void cmdDiscardView(AgiGame *state, uint8 *p) { + state->_vm->agiUnloadResource(rVIEW, p0); } -void AgiEngine::cmd_object_on_anything(uint8 *p) { - vt.flags &= ~(ON_WATER | ON_LAND); +void cmdObjectOnAnything(AgiGame *state, uint8 *p) { + vt.flags &= ~(fOnWater | fOnLand); } -void AgiEngine::cmd_object_on_land(uint8 *p) { - vt.flags |= ON_LAND; +void cmdObjectOnLand(AgiGame *state, uint8 *p) { + vt.flags |= fOnLand; } -void AgiEngine::cmd_object_on_water(uint8 *p) { - vt.flags |= ON_WATER; +void cmdObjectOnWater(AgiGame *state, uint8 *p) { + vt.flags |= fOnWater; } -void AgiEngine::cmd_observe_horizon(uint8 *p) { - vt.flags &= ~IGNORE_HORIZON; +void cmdObserveHorizon(AgiGame *state, uint8 *p) { + vt.flags &= ~fIgnoreHorizon; } -void AgiEngine::cmd_ignore_horizon(uint8 *p) { - vt.flags |= IGNORE_HORIZON; +void cmdIgnoreHorizon(AgiGame *state, uint8 *p) { + vt.flags |= fIgnoreHorizon; } -void AgiEngine::cmd_observe_objs(uint8 *p) { - vt.flags &= ~IGNORE_OBJECTS; +void cmdObserveObjs(AgiGame *state, uint8 *p) { + vt.flags &= ~fIgnoreObjects; } -void AgiEngine::cmd_ignore_objs(uint8 *p) { - vt.flags |= IGNORE_OBJECTS; +void cmdIgnoreObjs(AgiGame *state, uint8 *p) { + vt.flags |= fIgnoreObjects; } -void AgiEngine::cmd_observe_blocks(uint8 *p) { - vt.flags &= ~IGNORE_BLOCKS; +void cmdObserveBlocks(AgiGame *state, uint8 *p) { + vt.flags &= ~fIgnoreBlocks; } -void AgiEngine::cmd_ignore_blocks(uint8 *p) { - vt.flags |= IGNORE_BLOCKS; +void cmdIgnoreBlocks(AgiGame *state, uint8 *p) { + vt.flags |= fIgnoreBlocks; } -void AgiEngine::cmd_set_horizon(uint8 *p) { - _game.horizon = p0; +void cmdSetHorizon(AgiGame *state, uint8 *p) { + state->horizon = p0; } -void AgiEngine::cmd_get_priority(uint8 *p) { +void cmdGetPriority(AgiGame *state, uint8 *p) { _v[p1] = vt.priority; } -void AgiEngine::cmd_set_priority(uint8 *p) { - vt.flags |= FIXED_PRIORITY; +void cmdSetPriority(AgiGame *state, uint8 *p) { + vt.flags |= fFixedPriority; vt.priority = p1; // WORKAROUND: this fixes bug #1712585 in KQ4 (dwarf sprite priority) @@ -253,250 +282,257 @@ void AgiEngine::cmd_set_priority(uint8 *p) { // Therefore, this workaround only affects that specific part of this scene // Ego is set to object 19 by script 54 if (getGameID() == GID_KQ4 && vt.currentView == 152) { - _game.viewTable[19].flags |= FIXED_PRIORITY; - _game.viewTable[19].priority = 7; + state->viewTable[19].flags |= fFixedPriority; + state->viewTable[19].priority = 7; } } -void AgiEngine::cmd_set_priority_f(uint8 *p) { - vt.flags |= FIXED_PRIORITY; +void cmdSetPriorityF(AgiGame *state, uint8 *p) { + vt.flags |= fFixedPriority; vt.priority = _v[p1]; } -void AgiEngine::cmd_release_priority(uint8 *p) { - vt.flags &= ~FIXED_PRIORITY; +void cmdReleasePriority(AgiGame *state, uint8 *p) { + vt.flags &= ~fFixedPriority; } -void AgiEngine::cmd_set_upper_left(uint8 *p) { // do nothing (AGI 2.917) +void cmdSetUpperLeft(AgiGame *state, uint8 *p) { // do nothing (AGI 2.917) } -void AgiEngine::cmd_start_update(uint8 *p) { - startUpdate(&vt); +void cmdStartUpdate(AgiGame *state, uint8 *p) { + state->_vm->startUpdate(&vt); } -void AgiEngine::cmd_stop_update(uint8 *p) { - stopUpdate(&vt); +void cmdStopUpdate(AgiGame *state, uint8 *p) { + state->_vm->stopUpdate(&vt); } -void AgiEngine::cmd_current_view(uint8 *p) { +void cmdCurrentView(AgiGame *state, uint8 *p) { _v[p1] = vt.currentView; } -void AgiEngine::cmd_current_cel(uint8 *p) { +void cmdCurrentCel(AgiGame *state, uint8 *p) { _v[p1] = vt.currentCel; debugC(4, kDebugLevelScripts, "v%d=%d", p1, _v[p1]); } -void AgiEngine::cmd_current_loop(uint8 *p) { +void cmdCurrentLoop(AgiGame *state, uint8 *p) { _v[p1] = vt.currentLoop; } -void AgiEngine::cmd_last_cel(uint8 *p) { +void cmdLastCel(AgiGame *state, uint8 *p) { _v[p1] = vt.loopData->numCels - 1; } -void AgiEngine::cmd_set_cel(uint8 *p) { - setCel(&vt, p1); - vt.flags &= ~DONTUPDATE; +void cmdSetCel(AgiGame *state, uint8 *p) { + state->_vm->setCel(&vt, p1); + + if (getVersion() >= 0x2000) { + vt.flags &= ~fDontupdate; + } } -void AgiEngine::cmd_set_cel_f(uint8 *p) { - setCel(&vt, _v[p1]); - vt.flags &= ~DONTUPDATE; +void cmdSetCelF(AgiGame *state, uint8 *p) { + state->_vm->setCel(&vt, _v[p1]); + vt.flags &= ~fDontupdate; } -void AgiEngine::cmd_set_view(uint8 *p) { - setView(&vt, p1); +void cmdSetView(AgiGame *state, uint8 *p) { + state->_vm->setView(&vt, p1); } -void AgiEngine::cmd_set_view_f(uint8 *p) { - setView(&vt, _v[p1]); +void cmdSetViewF(AgiGame *state, uint8 *p) { + state->_vm->setView(&vt, _v[p1]); } -void AgiEngine::cmd_set_loop(uint8 *p) { - setLoop(&vt, p1); +void cmdSetLoop(AgiGame *state, uint8 *p) { + state->_vm->setLoop(&vt, p1); } -void AgiEngine::cmd_set_loop_f(uint8 *p) { - setLoop(&vt, _v[p1]); +void cmdSetLoopF(AgiGame *state, uint8 *p) { + state->_vm->setLoop(&vt, _v[p1]); } -void AgiEngine::cmd_number_of_loops(uint8 *p) { +void cmdNumberOfLoops(AgiGame *state, uint8 *p) { _v[p1] = vt.numLoops; } -void AgiEngine::cmd_fix_loop(uint8 *p) { - vt.flags |= FIX_LOOP; +void cmdFixLoop(AgiGame *state, uint8 *p) { + vt.flags |= fFixLoop; } -void AgiEngine::cmd_release_loop(uint8 *p) { - vt.flags &= ~FIX_LOOP; +void cmdReleaseLoop(AgiGame *state, uint8 *p) { + vt.flags &= ~fFixLoop; } -void AgiEngine::cmd_step_size(uint8 *p) { +void cmdStepSize(AgiGame *state, uint8 *p) { vt.stepSize = _v[p1]; } -void AgiEngine::cmd_step_time(uint8 *p) { +void cmdStepTime(AgiGame *state, uint8 *p) { vt.stepTime = vt.stepTimeCount = _v[p1]; } -void AgiEngine::cmd_cycle_time(uint8 *p) { +void cmdCycleTime(AgiGame *state, uint8 *p) { vt.cycleTime = vt.cycleTimeCount = _v[p1]; } -void AgiEngine::cmd_stop_cycling(uint8 *p) { - vt.flags &= ~CYCLING; +void cmdStopCycling(AgiGame *state, uint8 *p) { + vt.flags &= ~fCycling; } -void AgiEngine::cmd_start_cycling(uint8 *p) { - vt.flags |= CYCLING; +void cmdStartCycling(AgiGame *state, uint8 *p) { + vt.flags |= fCycling; } -void AgiEngine::cmd_normal_cycle(uint8 *p) { - vt.cycle = CYCLE_NORMAL; - vt.flags |= CYCLING; +void cmdNormalCycle(AgiGame *state, uint8 *p) { + vt.cycle = kCycleNormal; + vt.flags |= fCycling; } -void AgiEngine::cmd_reverse_cycle(uint8 *p) { - vt.cycle = CYCLE_REVERSE; - vt.flags |= CYCLING; +void cmdReverseCycle(AgiGame *state, uint8 *p) { + vt.cycle = kCycleReverse; + vt.flags |= fCycling; } -void AgiEngine::cmd_set_dir(uint8 *p) { +void cmdSetDir(AgiGame *state, uint8 *p) { vt.direction = _v[p1]; } -void AgiEngine::cmd_get_dir(uint8 *p) { +void cmdGetDir(AgiGame *state, uint8 *p) { _v[p1] = vt.direction; } -void AgiEngine::cmd_get_room_f(uint8 *p) { - _v[p1] = objectGetLocation(_v[p0]); +void cmdGetRoomF(AgiGame *state, uint8 *p) { + _v[p1] = state->_vm->objectGetLocation(_v[p0]); +} + +void cmdPut(AgiGame *state, uint8 *p) { + state->_vm->objectSetLocation(p0, _v[p1]); } -void AgiEngine::cmd_put(uint8 *p) { - objectSetLocation(p0, _v[p1]); +void cmdPutF(AgiGame *state, uint8 *p) { + state->_vm->objectSetLocation(_v[p0], _v[p1]); } -void AgiEngine::cmd_put_f(uint8 *p) { - objectSetLocation(_v[p0], _v[p1]); +void cmdDrop(AgiGame *state, uint8 *p) { + state->_vm->objectSetLocation(p0, 0); } -void AgiEngine::cmd_drop(uint8 *p) { - objectSetLocation(p0, 0); +void cmdGet(AgiGame *state, uint8 *p) { + state->_vm->objectSetLocation(p0, EGO_OWNED); } -void AgiEngine::cmd_get(uint8 *p) { - objectSetLocation(p0, EGO_OWNED); +void cmdGetV1(AgiGame *state, uint8 *p) { + state->_vm->objectSetLocation(p0, EGO_OWNED_V1); } -void AgiEngine::cmd_get_f(uint8 *p) { - objectSetLocation(_v[p0], EGO_OWNED); +void cmdGetF(AgiGame *state, uint8 *p) { + state->_vm->objectSetLocation(_v[p0], EGO_OWNED); } -void AgiEngine::cmd_word_to_string(uint8 *p) { - strcpy(_game.strings[p0], _game.egoWords[p1].word); +void cmdWordToString(AgiGame *state, uint8 *p) { + strcpy(state->strings[p0], state->egoWords[p1].word); } -void AgiEngine::cmd_open_dialogue(uint8 *p) { - _game.hasWindow = true; +void cmdOpenDialogue(AgiGame *state, uint8 *p) { + state->hasWindow = true; } -void AgiEngine::cmd_close_dialogue(uint8 *p) { - _game.hasWindow = false; +void cmdCloseDialogue(AgiGame *state, uint8 *p) { + state->hasWindow = false; } -void AgiEngine::cmd_close_window(uint8 *p) { - closeWindow(); +void cmdCloseWindow(AgiGame *state, uint8 *p) { + state->_vm->closeWindow(); } -void AgiEngine::cmd_status_line_on(uint8 *p) { - _game.statusLine = true; - writeStatus(); +void cmdStatusLineOn(AgiGame *state, uint8 *p) { + state->statusLine = true; + state->_vm->writeStatus(); } -void AgiEngine::cmd_status_line_off(uint8 *p) { - _game.statusLine = false; - writeStatus(); +void cmdStatusLineOff(AgiGame *state, uint8 *p) { + state->statusLine = false; + state->_vm->writeStatus(); } -void AgiEngine::cmd_show_obj(uint8 *p) { - _sprites->showObj(p0); +void cmdShowObj(AgiGame *state, uint8 *p) { + state->_vm->_sprites->showObj(p0); } -void AgiEngine::cmd_show_obj_v(uint8 *p) { - _sprites->showObj(_v[p0]); +void cmdShowObjV(AgiGame *state, uint8 *p) { + state->_vm->_sprites->showObj(_v[p0]); } -void AgiEngine::cmd_sound(uint8 *p) { - _sound->startSound(p0, p1); +void cmdSound(AgiGame *state, uint8 *p) { + state->_vm->_sound->startSound(p0, p1); } -void AgiEngine::cmd_stop_sound(uint8 *p) { - _sound->stopSound(); +void cmdStopSound(AgiGame *state, uint8 *p) { + state->_vm->_sound->stopSound(); } -void AgiEngine::cmd_menu_input(uint8 *p) { - newInputMode(INPUT_MENU); +void cmdMenuInput(AgiGame *state, uint8 *p) { + state->_vm->newInputMode(INPUT_MENU); } -void AgiEngine::cmd_enable_item(uint8 *p) { - _menu->setItem(p0, true); +void cmdEnableItem(AgiGame *state, uint8 *p) { + state->_vm->_menu->setItem(p0, true); } -void AgiEngine::cmd_disable_item(uint8 *p) { - _menu->setItem(p0, false); +void cmdDisableItem(AgiGame *state, uint8 *p) { + state->_vm->_menu->setItem(p0, false); } -void AgiEngine::cmd_submit_menu(uint8 *p) { - _menu->submit(); +void cmdSubmitMenu(AgiGame *state, uint8 *p) { + state->_vm->_menu->submit(); } -void AgiEngine::cmd_set_scan_start(uint8 *p) { - _curLogic->sIP = _curLogic->cIP; +void cmdSetScanStart(AgiGame *state, uint8 *p) { + state->_curLogic->sIP = state->_curLogic->cIP; } -void AgiEngine::cmd_reset_scan_start(uint8 *p) { - _curLogic->sIP = 2; +void cmdResetScanStart(AgiGame *state, uint8 *p) { + state->_curLogic->sIP = 2; } -void AgiEngine::cmd_save_game(uint8 *p) { - _game.simpleSave ? saveGameSimple() : saveGameDialog(); +void cmdSaveGame(AgiGame *state, uint8 *p) { + state->simpleSave ? state->_vm->saveGameSimple() : state->_vm->saveGameDialog(); } -void AgiEngine::cmd_load_game(uint8 *p) { +void cmdLoadGame(AgiGame *state, uint8 *p) { assert(1); - _game.simpleSave ? loadGameSimple() : loadGameDialog(); + state->simpleSave ? state->_vm->loadGameSimple() : state->_vm->loadGameDialog(); } -void AgiEngine::cmd_init_disk(uint8 *p) { // do nothing +void cmdInitDisk(AgiGame *state, uint8 *p) { // do nothing } -void AgiEngine::cmd_log(uint8 *p) { // do nothing +void cmdLog(AgiGame *state, uint8 *p) { // do nothing } -void AgiEngine::cmd_trace_on(uint8 *p) { // do nothing +void cmdTraceOn(AgiGame *state, uint8 *p) { // do nothing } -void AgiEngine::cmd_trace_info(uint8 *p) { // do nothing +void cmdTraceInfo(AgiGame *state, uint8 *p) { // do nothing } -void AgiEngine::cmd_show_mem(uint8 *p) { - messageBox("Enough memory"); +void cmdShowMem(AgiGame *state, uint8 *p) { + state->_vm->messageBox("Enough memory"); } -void AgiEngine::cmd_init_joy(uint8 *p) { // do nothing +void cmdInitJoy(AgiGame *state, uint8 *p) { // do nothing } -void AgiEngine::cmd_script_size(uint8 *p) { +void cmdScriptSize(AgiGame *state, uint8 *p) { debug(0, "script.size(%d)", p0); } -void AgiEngine::cmd_cancel_line(uint8 *p) { - _game.inputBuffer[0] = 0; - _game.cursorPos = 0; - writePrompt(); +void cmdCancelLine(AgiGame *state, uint8 *p) { + state->inputBuffer[0] = 0; + state->cursorPos = 0; + state->_vm->writePrompt(); } // This implementation is based on observations of Amiga's Gold Rush. @@ -509,23 +545,23 @@ void AgiEngine::cmd_cancel_line(uint8 *p) { // 4051 (When ego is stationary), // 471 (When walking on the first screen's bridge), // 71 (When walking around, using the mouse or the keyboard). -void AgiEngine::cmd_obj_status_f(uint8 *p) { +void cmdObjStatusF(AgiGame *state, uint8 *p) { const char *cycleDesc; // Object's cycle description line const char *motionDesc; // Object's motion description line char msg[256]; // The whole object status message // Generate cycle description line switch (vt_v.cycle) { - case CYCLE_NORMAL: + case kCycleNormal: cycleDesc = "normal cycle"; break; - case CYCLE_END_OF_LOOP: + case kCycleEndOfLoop: cycleDesc = "end of loop"; break; - case CYCLE_REV_LOOP: + case kCycleRevLoop: cycleDesc = "reverse loop"; break; - case CYCLE_REVERSE: + case kCycleReverse: cycleDesc = "reverse cycle"; break; default: @@ -535,16 +571,16 @@ void AgiEngine::cmd_obj_status_f(uint8 *p) { // Generate motion description line switch (vt_v.motion) { - case MOTION_NORMAL: + case kMotionNormal: motionDesc = "normal motion"; break; - case MOTION_WANDER: + case kMotionWander: motionDesc = "wandering"; break; - case MOTION_FOLLOW_EGO: + case kMotionFollowEgo: motionDesc = "following ego"; break; - case MOTION_MOVE_OBJ: + case kMotionMoveObj: // Amiga's Gold Rush! most probably uses "move to (x, y)" // here with real values for x and y. The same output // is used when moving the ego around using the mouse. @@ -570,7 +606,7 @@ void AgiEngine::cmd_obj_status_f(uint8 *p) { vt_v.stepSize, cycleDesc, motionDesc); - messageBox(msg); + state->_vm->messageBox(msg); } // unknown commands: @@ -581,49 +617,49 @@ void AgiEngine::cmd_obj_status_f(uint8 *p) { // unk_174: Change priority table (used in KQ4) -- j5 // unk_177: Disable menus completely -- j5 // unk_181: Deactivate keypressed control (default control of ego) -void AgiEngine::cmd_set_simple(uint8 *p) { +void cmdSetSimple(AgiGame *state, uint8 *p) { if (!(getFeatures() & (GF_AGI256 | GF_AGI256_2))) { - _game.simpleSave = true; + state->simpleSave = true; } else { // AGI256 and AGI256-2 use this unknown170 command to load 256 color pictures. - // Load the picture. Similar to void AgiEngine::cmd_load_pic(uint8 *p). - _sprites->eraseBoth(); - agiLoadResource(rPICTURE, _v[p0]); + // Load the picture. Similar to void cmdLoad_pic(AgiGame *state, uint8 *p). + state->_vm->_sprites->eraseBoth(); + state->_vm->agiLoadResource(rPICTURE, _v[p0]); - // Draw the picture. Similar to void AgiEngine::cmd_draw_pic(uint8 *p). - _picture->decodePicture(_v[p0], false, true); - _sprites->blitBoth(); - _game.pictureShown = 0; + // Draw the picture. Similar to void cmdDraw_pic(AgiGame *state, uint8 *p). + state->_vm->_picture->decodePicture(_v[p0], false, true); + state->_vm->_sprites->blitBoth(); + state->pictureShown = 0; - // Show the picture. Similar to void AgiEngine::cmd_show_pic(uint8 *p). + // Show the picture. Similar to void cmdShow_pic(AgiGame *state, uint8 *p). setflag(fOutputMode, false); - closeWindow(); - _picture->showPic(); - _game.pictureShown = 1; + state->_vm->closeWindow(); + state->_vm->_picture->showPic(); + state->pictureShown = 1; // Simulate slowww computer. Many effects rely on this - pause(kPausePicture); + state->_vm->pause(kPausePicture); } } -void AgiEngine::cmd_pop_script(uint8 *p) { +void cmdPopScript(AgiGame *state, uint8 *p) { if (getVersion() >= 0x2915) { debug(0, "pop.script"); } } -void AgiEngine::cmd_hold_key(uint8 *p) { +void cmdHoldKey(AgiGame *state, uint8 *p) { if (getVersion() >= 0x3098) { - _egoHoldKey = true; + state->_vm->_egoHoldKey = true; } } -void AgiEngine::cmd_discard_sound(uint8 *p) { +void cmdDiscardSound(AgiGame *state, uint8 *p) { if (getVersion() >= 0x2936) { debug(0, "discard.sound"); } } -void AgiEngine::cmd_hide_mouse(uint8 *p) { +void cmdHideMouse(AgiGame *state, uint8 *p) { // WORKAROUND: Turns off current movement that's being caused with the mouse. // This fixes problems with too many popup boxes appearing in the Amiga // Gold Rush's copy protection failure scene (i.e. the hanging scene, logic.192). @@ -631,37 +667,37 @@ void AgiEngine::cmd_hide_mouse(uint8 *p) { // to walk somewhere else than to the right using the mouse. // FIXME: Write a proper implementation using disassembly and // apply it to other games as well if applicable. - _game.viewTable[0].flags &= ~ADJ_EGO_XY; + state->viewTable[0].flags &= ~fAdjEgoXY; g_system->showMouse(false); } -void AgiEngine::cmd_allow_menu(uint8 *p) { +void cmdAllowMenu(AgiGame *state, uint8 *p) { if (getVersion() >= 0x3098) { setflag(fMenusWork, ((p0 != 0) ? true : false)); } } -void AgiEngine::cmd_show_mouse(uint8 *p) { +void cmdShowMouse(AgiGame *state, uint8 *p) { g_system->showMouse(true); } -void AgiEngine::cmd_fence_mouse(uint8 *p) { - _game.mouseFence.moveTo(p0, p1); - _game.mouseFence.setWidth(p2 - p0); - _game.mouseFence.setHeight(p3 - p1); +void cmdFenceMouse(AgiGame *state, uint8 *p) { + state->mouseFence.moveTo(p0, p1); + state->mouseFence.setWidth(p2 - p0); + state->mouseFence.setHeight(p3 - p1); } -void AgiEngine::cmd_release_key(uint8 *p) { +void cmdReleaseKey(AgiGame *state, uint8 *p) { if (getVersion() >= 0x3098) { - _egoHoldKey = false; + state->_vm->_egoHoldKey = false; } } -void AgiEngine::cmd_adj_ego_move_to_x_y(uint8 *p) { +void cmdAdjEgoMoveToXY(AgiGame *state, uint8 *p) { int8 x, y; - switch (logicNamesCmd[182].numArgs) { + switch (logicNamesCmd[182].argumentsLength()) { // The 2 arguments version is used at least in Amiga Gold Rush! // (v2.05 1989-03-09, Amiga AGI 2.316) in logics 130 and 150 // (Using arguments (0, 0), (0, 7), (0, 8), (9, 9) and (-9, 9)). @@ -680,57 +716,67 @@ void AgiEngine::cmd_adj_ego_move_to_x_y(uint8 *p) { // onto the ladder so this is more like it (Although that may be caused // by something else because this command doesn't do any flag manipulations // in the Amiga version - checked it with disassembly). - if (x != _game.adjMouseX || y != _game.adjMouseY) - _game.viewTable[EGO_VIEW_TABLE].flags &= ~ADJ_EGO_XY; + if (x != state->adjMouseX || y != state->adjMouseY) + state->viewTable[EGO_VIEW_TABLE].flags &= ~fAdjEgoXY; - _game.adjMouseX = x; - _game.adjMouseY = y; + state->adjMouseX = x; + state->adjMouseY = y; debugC(4, kDebugLevelScripts, "adj.ego.move.to.x.y(%d, %d)", x, y); break; // TODO: Check where (if anywhere) the 0 arguments version is used case 0: default: - _game.viewTable[0].flags |= ADJ_EGO_XY; + state->viewTable[0].flags |= fAdjEgoXY; break; } } -void AgiEngine::cmd_parse(uint8 *p) { +void cmdParse(AgiGame *state, uint8 *p) { _v[vWordNotFound] = 0; setflag(fEnteredCli, false); setflag(fSaidAcceptedInput, false); - dictionaryWords(agiSprintf(_game.strings[p0])); + state->_vm->dictionaryWords(state->_vm->agiSprintf(state->strings[p0])); } -void AgiEngine::cmd_call(uint8 *p) { +void cmdCall(AgiGame *state, uint8 *p) { int oldCIP; int oldLognum; // CM: we don't save sIP because set.scan.start can be // used in a called script (fixes xmas demo) - oldCIP = _curLogic->cIP; - oldLognum = _game.lognum; + oldCIP = state->_curLogic->cIP; + oldLognum = state->lognum; - runLogic(p0); + state->_vm->runLogic(p0); - _game.lognum = oldLognum; - _curLogic = &_game.logics[_game.lognum]; - _curLogic->cIP = oldCIP; + state->lognum = oldLognum; + state->_curLogic = &state->logics[state->lognum]; + state->_curLogic->cIP = oldCIP; } -void AgiEngine::cmd_call_f(uint8 *p) { - cmd_call(&_v[p0]); +void cmdCallF(AgiGame *state, uint8 *p) { + cmdCall(state, &_v[p0]); +} + +void cmdDrawPicV1(AgiGame *state, uint8 *p) { + debugC(6, kDebugLevelScripts, "=== draw pic V1 %d ===", _v[p0]); + state->_vm->_picture->decodePicture(_v[p0], true); + + state->_vm->clearPrompt(); + + // Simulate slowww computer. Many effects rely on this + state->_vm->pause(kPausePicture); } -void AgiEngine::cmd_draw_pic(uint8 *p) { +void cmdDrawPic(AgiGame *state, uint8 *p) { debugC(6, kDebugLevelScripts, "=== draw pic %d ===", _v[p0]); - _sprites->eraseBoth(); - _picture->decodePicture(_v[p0], true); - _sprites->blitBoth(); - _sprites->commitBoth(); - _game.pictureShown = 0; + state->_vm->_sprites->eraseBoth(); + state->_vm->_picture->decodePicture(_v[p0], true); + state->_vm->_sprites->blitBoth(); + state->_vm->_sprites->commitBoth(); + state->pictureShown = 0; debugC(6, kDebugLevelScripts, "--- end of draw pic %d ---", _v[p0]); // WORKAROUND for a script bug which exists in SQ1, logic scripts @@ -749,79 +795,93 @@ void AgiEngine::cmd_draw_pic(uint8 *p) { setflag(103, false); // Simulate slowww computer. Many effects rely on this - pause(kPausePicture); + state->_vm->pause(kPausePicture); } -void AgiEngine::cmd_show_pic(uint8 *p) { +void cmdShowPic(AgiGame *state, uint8 *p) { debugC(6, kDebugLevelScripts, "=== show pic ==="); setflag(fOutputMode, false); - closeWindow(); - _picture->showPic(); - _game.pictureShown = 1; + state->_vm->closeWindow(); + state->_vm->_picture->showPic(); + state->pictureShown = 1; debugC(6, kDebugLevelScripts, "--- end of show pic ---"); } -void AgiEngine::cmd_load_pic(uint8 *p) { - _sprites->eraseBoth(); - agiLoadResource(rPICTURE, _v[p0]); - _sprites->blitBoth(); - _sprites->commitBoth(); +void cmdLoadPic(AgiGame *state, uint8 *p) { + state->_vm->_sprites->eraseBoth(); + state->_vm->agiLoadResource(rPICTURE, _v[p0]); + state->_vm->_sprites->blitBoth(); + state->_vm->_sprites->commitBoth(); } -void AgiEngine::cmd_discard_pic(uint8 *p) { +void cmdLoadPicV1(AgiGame *state, uint8 *p) { + state->_vm->agiLoadResource(rPICTURE, _v[p0]); +} + +void cmdDiscardPic(AgiGame *state, uint8 *p) { debugC(6, kDebugLevelScripts, "--- discard pic ---"); // do nothing } -void AgiEngine::cmd_overlay_pic(uint8 *p) { +void cmdOverlayPic(AgiGame *state, uint8 *p) { debugC(6, kDebugLevelScripts, "--- overlay pic ---"); - _sprites->eraseBoth(); - _picture->decodePicture(_v[p0], false); - _sprites->blitBoth(); - _game.pictureShown = 0; - _sprites->commitBoth(); + state->_vm->_sprites->eraseBoth(); + state->_vm->_picture->decodePicture(_v[p0], false); + state->_vm->_sprites->blitBoth(); + state->pictureShown = 0; + state->_vm->_sprites->commitBoth(); // Simulate slowww computer. Many effects rely on this - pause(kPausePicture); + state->_vm->pause(kPausePicture); } -void AgiEngine::cmd_show_pri_screen(uint8 *p) { - _debug.priority = 1; - _sprites->eraseBoth(); - _picture->showPic(); - _sprites->blitBoth(); +void cmdShowPriScreen(AgiGame *state, uint8 *p) { + state->_vm->_debug.priority = 1; + state->_vm->_sprites->eraseBoth(); + state->_vm->_picture->showPic(); + state->_vm->_sprites->blitBoth(); - waitKey(); + state->_vm->waitKey(); - _debug.priority = 0; - _sprites->eraseBoth(); - _picture->showPic(); - _sprites->blitBoth(); + state->_vm->_debug.priority = 0; + state->_vm->_sprites->eraseBoth(); + state->_vm->_picture->showPic(); + state->_vm->_sprites->blitBoth(); } -void AgiEngine::cmd_animate_obj(uint8 *p) { - if (vt.flags & ANIMATED) - return; +void cmdAnimateObj(AgiGame *state, uint8 *p) { + if (getVersion() < 0x2000) { + if (vt.flags & fDidntMove) + return; + } else { + if (vt.flags & fAnimated) + return; + } debugC(4, kDebugLevelScripts, "animate vt entry #%d", p0); - vt.flags = ANIMATED | UPDATE | CYCLING; - vt.motion = MOTION_NORMAL; - vt.cycle = CYCLE_NORMAL; + vt.flags = fAnimated | fUpdate | fCycling; + + if (getVersion() < 0x2000) { + vt.flags |= fDidntMove; + } + + vt.motion = kMotionNormal; + vt.cycle = kCycleNormal; vt.direction = 0; } -void AgiEngine::cmd_unanimate_all(uint8 *p) { +void cmdUnanimateAll(AgiGame *state, uint8 *p) { int i; for (i = 0; i < MAX_VIEWTABLE; i++) - _game.viewTable[i].flags &= ~(ANIMATED | DRAWN); + state->viewTable[i].flags &= ~(fAnimated | fDrawn); } -void AgiEngine::cmd_draw(uint8 *p) { - if (vt.flags & DRAWN) +void cmdDraw(AgiGame *state, uint8 *p) { + if (vt.flags & fDrawn) return; if (vt.ySize <= 0 || vt.xSize <= 0) @@ -829,18 +889,18 @@ void AgiEngine::cmd_draw(uint8 *p) { debugC(4, kDebugLevelScripts, "draw entry %d", vt.entry); - vt.flags |= UPDATE; + vt.flags |= fUpdate; if (getVersion() >= 0x3000) { - setLoop(&vt, vt.currentLoop); - setCel(&vt, vt.currentCel); + state->_vm->setLoop(&vt, vt.currentLoop); + state->_vm->setCel(&vt, vt.currentCel); } - fixPosition(p0); + state->_vm->fixPosition(p0); vt.xPos2 = vt.xPos; vt.yPos2 = vt.yPos; vt.celData2 = vt.celData; - _sprites->eraseUpdSprites(); - vt.flags |= DRAWN; + state->_vm->_sprites->eraseUpdSprites(); + vt.flags |= fDrawn; // WORKAROUND: This fixes a bug with AGI Fanmade _game Space Trek. // The original workaround checked if AGI version was <= 2.440, which could @@ -854,30 +914,30 @@ void AgiEngine::cmd_draw(uint8 *p) { // games are affected. If yes, then it'd be best to set this for Space // Trek only if (getFeatures() & GF_FANMADE) // See Sarien bug #546562 - vt.flags |= ANIMATED; + vt.flags |= fAnimated; - _sprites->blitUpdSprites(); - vt.flags &= ~DONTUPDATE; + state->_vm->_sprites->blitUpdSprites(); + vt.flags &= ~fDontupdate; - _sprites->commitBlock(vt.xPos, vt.yPos - vt.ySize + 1, vt.xPos + vt.xSize - 1, vt.yPos, true); + state->_vm->_sprites->commitBlock(vt.xPos, vt.yPos - vt.ySize + 1, vt.xPos + vt.xSize - 1, vt.yPos, true); debugC(4, kDebugLevelScripts, "vt entry #%d flags = %02x", p0, vt.flags); } -void AgiEngine::cmd_erase(uint8 *p) { - if (~vt.flags & DRAWN) +void cmdErase(AgiGame *state, uint8 *p) { + if (~vt.flags & fDrawn) return; - _sprites->eraseUpdSprites(); + state->_vm->_sprites->eraseUpdSprites(); - if (vt.flags & UPDATE) { - vt.flags &= ~DRAWN; + if (vt.flags & fUpdate) { + vt.flags &= ~fDrawn; } else { - _sprites->eraseNonupdSprites(); - vt.flags &= ~DRAWN; - _sprites->blitNonupdSprites(); + state->_vm->_sprites->eraseNonupdSprites(); + vt.flags &= ~fDrawn; + state->_vm->_sprites->blitNonupdSprites(); } - _sprites->blitUpdSprites(); + state->_vm->_sprites->blitUpdSprites(); int x1, y1, x2, y2; @@ -886,10 +946,10 @@ void AgiEngine::cmd_erase(uint8 *p) { y1 = MIN((int)MIN(vt.yPos, vt.yPos2), MIN(vt.yPos - vt.celData->height, vt.yPos2 - vt.celData2->height)); y2 = MAX((int)MAX(vt.yPos, vt.yPos2), MAX(vt.yPos - vt.celData->height, vt.yPos2 - vt.celData2->height)); - _sprites->commitBlock(x1, y1, x2, y2, true); + state->_vm->_sprites->commitBlock(x1, y1, x2, y2, true); } -void AgiEngine::cmd_position(uint8 *p) { +void cmdPosition(AgiGame *state, uint8 *p) { vt.xPos = vt.xPos2 = p1; vt.yPos = vt.yPos2 = p2; @@ -907,10 +967,15 @@ void AgiEngine::cmd_position(uint8 *p) { // strictly need the identical workaround in the position.v-command but it does make // for a nice symmetry. if (getFeatures() & GF_CLIPCOORDS) - clipViewCoordinates(&vt); + state->_vm->clipViewCoordinates(&vt); } -void AgiEngine::cmd_position_f(uint8 *p) { +void cmdPositionV1(AgiGame *state, uint8 *p) { + vt.xPos = p1; + vt.yPos = p2; +} + +void cmdPositionF(AgiGame *state, uint8 *p) { vt.xPos = vt.xPos2 = _v[p1]; vt.yPos = vt.yPos2 = _v[p2]; @@ -918,19 +983,24 @@ void AgiEngine::cmd_position_f(uint8 *p) { // with an accompanying identical workaround in position-command (i.e. command 0x25). // See that workaround's comment for more in-depth information. if (getFeatures() & GF_CLIPCOORDS) - clipViewCoordinates(&vt); + state->_vm->clipViewCoordinates(&vt); +} + +void cmdPositionFV1(AgiGame *state, uint8 *p) { + vt.xPos = _v[p1]; + vt.yPos = _v[p2]; } -void AgiEngine::cmd_get_posn(uint8 *p) { - _game.vars[p1] = (unsigned char)vt.xPos; - _game.vars[p2] = (unsigned char)vt.yPos; +void cmdGetPosn(AgiGame *state, uint8 *p) { + state->vars[p1] = (unsigned char)vt.xPos; + state->vars[p2] = (unsigned char)vt.yPos; } -void AgiEngine::cmd_reposition(uint8 *p) { +void cmdReposition(AgiGame *state, uint8 *p) { int dx = (int8) _v[p1], dy = (int8) _v[p2]; debugC(4, kDebugLevelScripts, "dx=%d, dy=%d", dx, dy); - vt.flags |= UPDATE_POS; + vt.flags |= fUpdatePos; if (dx < 0 && vt.xPos < -dx) vt.xPos = 0; @@ -942,109 +1012,154 @@ void AgiEngine::cmd_reposition(uint8 *p) { else vt.yPos += dy; - fixPosition(p0); + state->_vm->fixPosition(p0); } -void AgiEngine::cmd_reposition_to(uint8 *p) { +void cmdRepositionV1(AgiGame *state, uint8 *p) { + vt.xPos2 = vt.xPos; + vt.yPos2 = vt.yPos; + vt.flags |= fUpdatePos; + + vt.xPos = (vt.xPos + p1) & 0xff; + vt.yPos = (vt.yPos + p2) & 0xff; +} + +void cmdRepositionTo(AgiGame *state, uint8 *p) { vt.xPos = p1; vt.yPos = p2; - vt.flags |= UPDATE_POS; - fixPosition(p0); + vt.flags |= fUpdatePos; + state->_vm->fixPosition(p0); } -void AgiEngine::cmd_reposition_to_f(uint8 *p) { +void cmdRepositionToF(AgiGame *state, uint8 *p) { vt.xPos = _v[p1]; vt.yPos = _v[p2]; - vt.flags |= UPDATE_POS; - fixPosition(p0); + vt.flags |= fUpdatePos; + state->_vm->fixPosition(p0); +} + +void cmdAddToPic(AgiGame *state, uint8 *p) { + state->_vm->_sprites->addToPic(p0, p1, p2, p3, p4, p5, p6); } -void AgiEngine::cmd_add_to_pic(uint8 *p) { - _sprites->addToPic(p0, p1, p2, p3, p4, p5, p6); +void cmdAddToPicV1(AgiGame *state, uint8 *p) { + state->_vm->_sprites->addToPic(p0, p1, p2, p3, p4, p5, -1); } -void AgiEngine::cmd_add_to_pic_f(uint8 *p) { - _sprites->addToPic(_v[p0], _v[p1], _v[p2], _v[p3], _v[p4], _v[p5], _v[p6]); +void cmdAddToPicF(AgiGame *state, uint8 *p) { + state->_vm->_sprites->addToPic(_v[p0], _v[p1], _v[p2], _v[p3], _v[p4], _v[p5], _v[p6]); } -void AgiEngine::cmd_force_update(uint8 *p) { - _sprites->eraseBoth(); - _sprites->blitBoth(); - _sprites->commitBoth(); +void cmdForceUpdate(AgiGame *state, uint8 *p) { + state->_vm->_sprites->eraseBoth(); + state->_vm->_sprites->blitBoth(); + state->_vm->_sprites->commitBoth(); } -void AgiEngine::cmd_reverse_loop(uint8 *p) { +void cmdReverseLoop(AgiGame *state, uint8 *p) { debugC(4, kDebugLevelScripts, "o%d, f%d", p0, p1); - vt.cycle = CYCLE_REV_LOOP; - vt.flags |= (DONTUPDATE | UPDATE | CYCLING); + vt.cycle = kCycleRevLoop; + vt.flags |= (fDontupdate | fUpdate | fCycling); vt.parm1 = p1; setflag(p1, false); } -void AgiEngine::cmd_end_of_loop(uint8 *p) { +void cmdReverseLoopV1(AgiGame *state, uint8 *p) { debugC(4, kDebugLevelScripts, "o%d, f%d", p0, p1); - vt.cycle = CYCLE_END_OF_LOOP; - vt.flags |= (DONTUPDATE | UPDATE | CYCLING); + vt.cycle = kCycleRevLoop; + state->_vm->setCel(&vt, 0); + vt.flags |= (fDontupdate | fUpdate | fCycling); + vt.parm1 = p1; + vt.parm3 = 0; +} + +void cmdEndOfLoop(AgiGame *state, uint8 *p) { + debugC(4, kDebugLevelScripts, "o%d, f%d", p0, p1); + vt.cycle = kCycleEndOfLoop; + vt.flags |= (fDontupdate | fUpdate | fCycling); vt.parm1 = p1; setflag(p1, false); } -void AgiEngine::cmd_block(uint8 *p) { +void cmdEndOfLoopV1(AgiGame *state, uint8 *p) { + debugC(4, kDebugLevelScripts, "o%d, f%d", p0, p1); + vt.cycle = kCycleEndOfLoop; + state->_vm->setCel(&vt, 0); + vt.flags |= (fDontupdate | fUpdate | fCycling); + vt.parm1 = p1; + vt.parm3 = 0; +} + +void cmdBlock(AgiGame *state, uint8 *p) { debugC(4, kDebugLevelScripts, "x1=%d, y1=%d, x2=%d, y2=%d", p0, p1, p2, p3); - _game.block.active = true; - _game.block.x1 = p0; - _game.block.y1 = p1; - _game.block.x2 = p2; - _game.block.y2 = p3; + state->block.active = true; + state->block.x1 = p0; + state->block.y1 = p1; + state->block.x2 = p2; + state->block.y2 = p3; } -void AgiEngine::cmd_unblock(uint8 *p) { - _game.block.active = false; +void cmdUnblock(AgiGame *state, uint8 *p) { + state->block.active = false; } -void AgiEngine::cmd_normal_motion(uint8 *p) { - vt.motion = MOTION_NORMAL; +void cmdNormalMotion(AgiGame *state, uint8 *p) { + vt.motion = kMotionNormal; } -void AgiEngine::cmd_stop_motion(uint8 *p) { +void cmdStopMotion(AgiGame *state, uint8 *p) { vt.direction = 0; - vt.motion = MOTION_NORMAL; + vt.motion = kMotionNormal; if (p0 == 0) { // ego only _v[vEgoDir] = 0; - _game.playerControl = false; + state->playerControl = false; } } -void AgiEngine::cmd_start_motion(uint8 *p) { - vt.motion = MOTION_NORMAL; +void cmdStopMotionV1(AgiGame *state, uint8 *p) { + vt.flags &= ~fAnimated; +} + +void cmdStartMotion(AgiGame *state, uint8 *p) { + vt.motion = kMotionNormal; if (p0 == 0) { // ego only _v[vEgoDir] = 0; - _game.playerControl = true; + state->playerControl = true; } } -void AgiEngine::cmd_player_control(uint8 *p) { - _game.playerControl = true; - _game.viewTable[0].motion = MOTION_NORMAL; +void cmdStartMotionV1(AgiGame *state, uint8 *p) { + vt.flags |= fAnimated; } -void AgiEngine::cmd_program_control(uint8 *p) { - _game.playerControl = false; +void cmdPlayerControl(AgiGame *state, uint8 *p) { + state->playerControl = true; + state->viewTable[0].motion = kMotionNormal; } -void AgiEngine::cmd_follow_ego(uint8 *p) { - vt.motion = MOTION_FOLLOW_EGO; +void cmdProgramControl(AgiGame *state, uint8 *p) { + state->playerControl = false; +} + +void cmdFollowEgo(AgiGame *state, uint8 *p) { + vt.motion = kMotionFollowEgo; vt.parm1 = p1 > vt.stepSize ? p1 : vt.stepSize; vt.parm2 = p2; vt.parm3 = 0xff; - setflag(p2, false); - vt.flags |= UPDATE; + + if (getVersion() < 0x2000) { + _v[p2] = 0; + vt.flags |= fUpdate | fAnimated; + } else { + setflag(p2, false); + vt.flags |= fUpdate; + } } -void AgiEngine::cmd_move_obj(uint8 *p) { +void cmdMoveObj(AgiGame *state, uint8 *p) { // _D (_D_WARN "o=%d, x=%d, y=%d, s=%d, f=%d", p0, p1, p2, p3, p4); - vt.motion = MOTION_MOVE_OBJ; + vt.motion = kMotionMoveObj; vt.parm1 = p1; vt.parm2 = p2; vt.parm3 = vt.stepSize; @@ -1053,19 +1168,24 @@ void AgiEngine::cmd_move_obj(uint8 *p) { if (p3 != 0) vt.stepSize = p3; - setflag(p4, false); - vt.flags |= UPDATE; + if (getVersion() < 0x2000) { + _v[p4] = 0; + vt.flags |= fUpdate | fAnimated; + } else { + setflag(p4, false); + vt.flags |= fUpdate; + } if (p0 == 0) - _game.playerControl = false; + state->playerControl = false; // AGI 2.272 (ddp, xmas) doesn't call move_obj! if (getVersion() > 0x2272) - moveObj(&vt); + state->_vm->moveObj(&vt); } -void AgiEngine::cmd_move_obj_f(uint8 *p) { - vt.motion = MOTION_MOVE_OBJ; +void cmdMoveObjF(AgiGame *state, uint8 *p) { + vt.motion = kMotionMoveObj; vt.parm1 = _v[p1]; vt.parm2 = _v[p2]; vt.parm3 = vt.stepSize; @@ -1075,66 +1195,70 @@ void AgiEngine::cmd_move_obj_f(uint8 *p) { vt.stepSize = _v[p3]; setflag(p4, false); - vt.flags |= UPDATE; + vt.flags |= fUpdate; if (p0 == 0) - _game.playerControl = false; + state->playerControl = false; // AGI 2.272 (ddp, xmas) doesn't call move_obj! if (getVersion() > 0x2272) - moveObj(&vt); + state->_vm->moveObj(&vt); } -void AgiEngine::cmd_wander(uint8 *p) { +void cmdWander(AgiGame *state, uint8 *p) { if (p0 == 0) - _game.playerControl = false; + state->playerControl = false; - vt.motion = MOTION_WANDER; - vt.flags |= UPDATE; + vt.motion = kMotionWander; + if (getVersion() < 0x2000) { + vt.flags |= fUpdate | fAnimated; + } else { + vt.flags |= fUpdate; + } } -void AgiEngine::cmd_set_game_id(uint8 *p) { - if (_curLogic->texts && (p0 - 1) <= _curLogic->numTexts) - strncpy(_game.id, _curLogic->texts[p0 - 1], 8); +void cmdSetGameID(AgiGame *state, uint8 *p) { + if (state->_curLogic->texts && (p0 - 1) <= state->_curLogic->numTexts) + strncpy(state->id, state->_curLogic->texts[p0 - 1], 8); else - _game.id[0] = 0; + state->id[0] = 0; - debug(0, "Game ID: \"%s\"", _game.id); + debug(0, "Game ID: \"%s\"", state->id); } -void AgiEngine::cmd_pause(uint8 *p) { - int tmp = _game.clockEnabled; +void cmdPause(AgiGame *state, uint8 *p) { + int tmp = state->clockEnabled; const char *b[] = { "Continue", NULL }; const char *b_ru[] = { "\x8f\xe0\xae\xa4\xae\xab\xa6\xa8\xe2\xec", NULL }; - _game.clockEnabled = false; + state->clockEnabled = false; switch (getLanguage()) { case Common::RU_RUS: - selectionBox(" \x88\xa3\xe0\xa0 \xae\xe1\xe2\xa0\xad\xae\xa2\xab\xa5\xad\xa0. \n\n\n", b_ru); + state->_vm->selectionBox(" \x88\xa3\xe0\xa0 \xae\xe1\xe2\xa0\xad\xae\xa2\xab\xa5\xad\xa0. \n\n\n", b_ru); break; default: - selectionBox(" Game is paused. \n\n\n", b); + state->_vm->selectionBox(" Game is paused. \n\n\n", b); break; } - _game.clockEnabled = tmp; + state->clockEnabled = tmp; } -void AgiEngine::cmd_set_menu(uint8 *p) { - debugC(4, kDebugLevelScripts, "text %02x of %02x", p0, _curLogic->numTexts); +void cmdSetMenu(AgiGame *state, uint8 *p) { + debugC(4, kDebugLevelScripts, "text %02x of %02x", p0, state->_curLogic->numTexts); - if (_curLogic->texts != NULL && p0 <= _curLogic->numTexts) - _menu->add(_curLogic->texts[p0 - 1]); + if (state->_curLogic->texts != NULL && p0 <= state->_curLogic->numTexts) + state->_vm->_menu->add(state->_curLogic->texts[p0 - 1]); } -void AgiEngine::cmd_set_menu_item(uint8 *p) { - debugC(4, kDebugLevelScripts, "text %02x of %02x", p0, _curLogic->numTexts); +void cmdSetMenuItem(AgiGame *state, uint8 *p) { + debugC(4, kDebugLevelScripts, "text %02x of %02x", p0, state->_curLogic->numTexts); - if (_curLogic->texts != NULL && p0 <= _curLogic->numTexts) - _menu->addItem(_curLogic->texts[p0 - 1], p1); + if (state->_curLogic->texts != NULL && p0 <= state->_curLogic->numTexts) + state->_vm->_menu->addItem(state->_curLogic->texts[p0 - 1], p1); } -void AgiEngine::cmd_version(uint8 *p) { +void cmdVersion(AgiGame *state, uint8 *p) { char verMsg[64]; char ver2Msg[] = "\n" @@ -1171,89 +1295,94 @@ void AgiEngine::cmd_version(uint8 *p) { strncpy(q + 1 + gap, verMsg, strlen(verMsg)); sprintf(msg, q, maj, min); - messageBox(msg); + state->_vm->messageBox(msg); } -void AgiEngine::cmd_configure_screen(uint8 *p) { - _game.lineMinPrint = p0; - _game.lineUserInput = p1; - _game.lineStatus = p2; +void cmdConfigureScreen(AgiGame *state, uint8 *p) { + state->lineMinPrint = p0; + state->lineUserInput = p1; + state->lineStatus = p2; } -void AgiEngine::cmd_text_screen(uint8 *p) { +void cmdTextScreen(AgiGame *state, uint8 *p) { debugC(4, kDebugLevelScripts, "switching to text mode"); - _game.gfxMode = false; + state->gfxMode = false; // Simulates the "bright background bit" of the PC video // controller. - if (_game.colorBg) - _game.colorBg |= 0x08; + if (state->colorBg) + state->colorBg |= 0x08; - _gfx->clearScreen(_game.colorBg); + state->_vm->_gfx->clearScreen(state->colorBg); } -void AgiEngine::cmd_graphics(uint8 *p) { +void cmdGraphics(AgiGame *state, uint8 *p) { debugC(4, kDebugLevelScripts, "switching to graphics mode"); - if (!_game.gfxMode) { - _game.gfxMode = true; - _gfx->clearScreen(0); - _picture->showPic(); - writeStatus(); - writePrompt(); + if (!state->gfxMode) { + state->gfxMode = true; + state->_vm->_gfx->clearScreen(0); + state->_vm->_picture->showPic(); + state->_vm->writeStatus(); + state->_vm->writePrompt(); } } -void AgiEngine::cmd_set_text_attribute(uint8 *p) { - _game.colorFg = p0; - _game.colorBg = p1; +void cmdSetTextAttribute(AgiGame *state, uint8 *p) { + state->colorFg = p0; + state->colorBg = p1; - if (_game.gfxMode) { - if (_game.colorBg != 0) { - _game.colorFg = 0; - _game.colorBg = 15; + if (state->gfxMode) { + if (state->colorBg != 0) { + state->colorFg = 0; + state->colorBg = 15; } } } -void AgiEngine::cmd_status(uint8 *p) { - inventory(); +void cmdStatus(AgiGame *state, uint8 *p) { + state->_vm->inventory(); } -void AgiEngine::cmd_quit(uint8 *p) { +void cmdQuit(AgiGame *state, uint8 *p) { const char *buttons[] = { "Quit", "Continue", NULL }; - _sound->stopSound(); + state->_vm->_sound->stopSound(); if (p0) { - quitGame(); + state->_vm->quitGame(); } else { - if (selectionBox(" Quit the game, or continue? \n\n\n", buttons) == 0) { - quitGame(); + if (state->_vm->selectionBox(" Quit the game, or continue? \n\n\n", buttons) == 0) { + state->_vm->quitGame(); } } } -void AgiEngine::cmd_restart_game(uint8 *p) { +void cmdQuitV1(AgiGame *state, uint8 *p) { + state->_vm->_sound->stopSound(); + state->_vm->quitGame(); +} + +void cmdRestartGame(AgiGame *state, uint8 *p) { const char *buttons[] = { "Restart", "Continue", NULL }; int sel; - _sound->stopSound(); + state->_vm->_sound->stopSound(); sel = getflag(fAutoRestart) ? 0 : - selectionBox(" Restart _game, or continue? \n\n\n", buttons); + state->_vm->selectionBox(" Restart _game, or continue? \n\n\n", buttons); if (sel == 0) { - _restartGame = true; + state->_vm->_restartGame = true; setflag(fRestartGame, true); - _menu->enableAll(); + state->_vm->_menu->enableAll(); } } -void AgiEngine::cmd_distance(uint8 *p) { +void cmdDistance(AgiGame *state, uint8 *p) { int16 x1, y1, x2, y2, d; - VtEntry *v0 = &_game.viewTable[p0]; - VtEntry *v1 = &_game.viewTable[p1]; + VtEntry *v0 = &state->viewTable[p0]; + VtEntry *v1 = &state->viewTable[p1]; - if (v0->flags & DRAWN && v1->flags & DRAWN) { + if (v0->flags & fDrawn && v1->flags & fDrawn) { x1 = v0->xPos + v0->xSize / 2; y1 = v0->yPos; x2 = v1->xPos + v1->xSize / 2; @@ -1299,24 +1428,24 @@ void AgiEngine::cmd_distance(uint8 *p) { _v[p2] = (unsigned char)d; } -void AgiEngine::cmd_accept_input(uint8 *p) { +void cmdAcceptInput(AgiGame *state, uint8 *p) { debugC(4, kDebugLevelScripts | kDebugLevelInput, "input normal"); - newInputMode(INPUT_NORMAL); - _game.inputEnabled = true; - writePrompt(); + state->_vm->newInputMode(INPUT_NORMAL); + state->inputEnabled = true; + state->_vm->writePrompt(); } -void AgiEngine::cmd_prevent_input(uint8 *p) { +void cmdPreventInput(AgiGame *state, uint8 *p) { debugC(4, kDebugLevelScripts | kDebugLevelInput, "no input"); - newInputMode(INPUT_NONE); - _game.inputEnabled = false; + state->_vm->newInputMode(INPUT_NONE); + state->inputEnabled = false; - clearPrompt(); + state->_vm->clearPrompt(); } -void AgiEngine::cmd_get_string(uint8 *p) { +void cmdGetString(AgiGame *state, uint8 *p) { int tex, row, col; debugC(4, kDebugLevelScripts, "%d %d %d %d %d", p0, p1, p2, p3, p4); @@ -1332,63 +1461,63 @@ void AgiEngine::cmd_get_string(uint8 *p) { if (col > 39) col = 39; - newInputMode(INPUT_GETSTRING); + state->_vm->newInputMode(INPUT_GETSTRING); - if (_curLogic->texts != NULL && _curLogic->numTexts >= tex) { - int len = strlen(_curLogic->texts[tex]); + if (state->_curLogic->texts != NULL && state->_curLogic->numTexts >= tex) { + int len = strlen(state->_curLogic->texts[tex]); - printText(_curLogic->texts[tex], 0, col, row, len, _game.colorFg, _game.colorBg); - getString(col + len - 1, row, p4, p0); + state->_vm->printText(state->_curLogic->texts[tex], 0, col, row, len, state->colorFg, state->colorBg); + state->_vm->getString(col + len - 1, row, p4, p0); // SGEO: display input char - _gfx->printCharacter((col + len), row, _game.cursorChar, _game.colorFg, _game.colorBg); + state->_vm->_gfx->printCharacter((col + len), row, state->cursorChar, state->colorFg, state->colorBg); } do { - mainCycle(); - } while (_game.inputMode == INPUT_GETSTRING && !(shouldQuit() || _restartGame)); + state->_vm->mainCycle(); + } while (state->inputMode == INPUT_GETSTRING && !(state->_vm->shouldQuit() || state->_vm->_restartGame)); } -void AgiEngine::cmd_get_num(uint8 *p) { +void cmdGetNum(AgiGame *state, uint8 *p) { debugC(4, kDebugLevelScripts, "%d %d", p0, p1); - newInputMode(INPUT_GETSTRING); + state->_vm->newInputMode(INPUT_GETSTRING); - if (_curLogic->texts != NULL && _curLogic->numTexts >= (p0 - 1)) { - int len = strlen(_curLogic->texts[p0 - 1]); + if (state->_curLogic->texts != NULL && state->_curLogic->numTexts >= (p0 - 1)) { + int len = strlen(state->_curLogic->texts[p0 - 1]); - printText(_curLogic->texts[p0 - 1], 0, 0, 22, len, _game.colorFg, _game.colorBg); - getString(len - 1, 22, 3, MAX_STRINGS); + state->_vm->printText(state->_curLogic->texts[p0 - 1], 0, 0, 22, len, state->colorFg, state->colorBg); + state->_vm->getString(len - 1, 22, 3, MAX_STRINGS); // CM: display input char - _gfx->printCharacter((p3 + len), 22, _game.cursorChar, _game.colorFg, _game.colorBg); + state->_vm->_gfx->printCharacter((p3 + len), 22, state->cursorChar, state->colorFg, state->colorBg); } do { - mainCycle(); - } while (_game.inputMode == INPUT_GETSTRING && !(shouldQuit() || _restartGame)); + state->_vm->mainCycle(); + } while (state->inputMode == INPUT_GETSTRING && !(state->_vm->shouldQuit() || state->_vm->_restartGame)); - _v[p1] = atoi(_game.strings[MAX_STRINGS]); + _v[p1] = atoi(state->strings[MAX_STRINGS]); - debugC(4, kDebugLevelScripts, "[%s] -> %d", _game.strings[MAX_STRINGS], _v[p1]); + debugC(4, kDebugLevelScripts, "[%s] -> %d", state->strings[MAX_STRINGS], _v[p1]); - clearLines(22, 22, _game.colorBg); - flushLines(22, 22); + state->_vm->clearLines(22, 22, state->colorBg); + state->_vm->flushLines(22, 22); } -void AgiEngine::cmd_set_cursor_char(uint8 *p) { - if (_curLogic->texts != NULL && (p0 - 1) <= _curLogic->numTexts) { - _game.cursorChar = *_curLogic->texts[p0 - 1]; +void cmdSetCursorChar(AgiGame *state, uint8 *p) { + if (state->_curLogic->texts != NULL && (p0 - 1) <= state->_curLogic->numTexts) { + state->cursorChar = *state->_curLogic->texts[p0 - 1]; } else { // default - _game.cursorChar = '_'; + state->cursorChar = '_'; } } -void AgiEngine::cmd_set_key(uint8 *p) { +void cmdSetKey(AgiGame *state, uint8 *p) { int key; - if (_game.lastController >= MAX_CONTROLLERS) { + if (state->lastController >= MAX_CONTROLLERS) { warning("Number of set.keys exceeded %d", MAX_CONTROLLERS); return; } @@ -1397,35 +1526,37 @@ void AgiEngine::cmd_set_key(uint8 *p) { key = 256 * p1 + p0; - _game.controllers[_game.lastController].keycode = key; - _game.controllers[_game.lastController].controller = p2; - _game.lastController++; + state->controllers[state->lastController].keycode = key; + state->controllers[state->lastController].controller = p2; + state->lastController++; - _game.controllerOccured[p2] = false; + state->controllerOccured[p2] = false; } -void AgiEngine::cmd_set_string(uint8 *p) { +void cmdSetString(AgiGame *state, uint8 *p) { // CM: to avoid crash in Groza (str = 150) if (p0 > MAX_STRINGS) return; - strcpy(_game.strings[p0], _curLogic->texts[p1 - 1]); + strcpy(state->strings[p0], state->_curLogic->texts[p1 - 1]); } -void AgiEngine::cmd_display(uint8 *p) { +void cmdDisplay(AgiGame *state, uint8 *p) { + // V1 has 4 args + int t = (getVersion() >= 0x2000 ? p2 : p3); int len = 40; - char *s = wordWrapString(_curLogic->texts[p2 - 1], &len); + char *s = state->_vm->wordWrapString(state->_curLogic->texts[t - 1], &len); - printText(s, p1, 0, p0, 40, _game.colorFg, _game.colorBg); + state->_vm->printText(s, p1, 0, p0, 40, state->colorFg, state->colorBg); free(s); } -void AgiEngine::cmd_display_f(uint8 *p) { - printText(_curLogic->texts[_v[p2] - 1], _v[p1], 0, _v[p0], 40, _game.colorFg, _game.colorBg); +void cmdDisplayF(AgiGame *state, uint8 *p) { + state->_vm->printText(state->_curLogic->texts[_v[p2] - 1], _v[p1], 0, _v[p0], 40, state->colorFg, state->colorBg); } -void AgiEngine::cmd_clear_text_rect(uint8 *p) { +void cmdClearTextRect(AgiGame *state, uint8 *p) { int c, x1, y1, x2, y2; if ((c = p4) != 0) @@ -1446,21 +1577,21 @@ void AgiEngine::cmd_clear_text_rect(uint8 *p) { if (y2 > GFX_HEIGHT) y2 = GFX_HEIGHT - 1; - _gfx->drawRectangle(x1, y1, x2, y2, c); - _gfx->flushBlock(x1, y1, x2, y2); + state->_vm->_gfx->drawRectangle(x1, y1, x2, y2, c); + state->_vm->_gfx->flushBlock(x1, y1, x2, y2); } -void AgiEngine::cmd_toggle_monitor(uint8 *p) { +void cmdToggleMonitor(AgiGame *state, uint8 *p) { debug(0, "toggle.monitor"); } -void AgiEngine::cmd_echo_line(uint8 *p) { - strcpy((char *)_game.inputBuffer, (const char *)_game.echoBuffer); - _game.cursorPos = strlen((char *)_game.inputBuffer); - _game.hasPrompt = 0; +void cmdEchoLine(AgiGame *state, uint8 *p) { + strcpy((char *)state->inputBuffer, (const char *)state->echoBuffer); + state->cursorPos = strlen((char *)state->inputBuffer); + state->hasPrompt = 0; } -void AgiEngine::cmd_clear_lines(uint8 *p) { +void cmdClearLines(AgiGame *state, uint8 *p) { uint8 l; // Residence 44 calls clear.lines(24,0,0), see Sarien bug #558423 @@ -1470,42 +1601,42 @@ void AgiEngine::cmd_clear_lines(uint8 *p) { // #1935838 and #1935842 l = (l <= 24) ? l : 24; - clearLines(p0, l, p2); - flushLines(p0, l); + state->_vm->clearLines(p0, l, p2); + state->_vm->flushLines(p0, l); } -void AgiEngine::cmd_print(uint8 *p) { +void cmdPrint(AgiGame *state, uint8 *p) { int n = p0 < 1 ? 1 : p0; - print(_curLogic->texts[n - 1], 0, 0, 0); + state->_vm->print(state->_curLogic->texts[n - 1], 0, 0, 0); } -void AgiEngine::cmd_print_f(uint8 *p) { +void cmdPrintF(AgiGame *state, uint8 *p) { int n = _v[p0] < 1 ? 1 : _v[p0]; - print(_curLogic->texts[n - 1], 0, 0, 0); + state->_vm->print(state->_curLogic->texts[n - 1], 0, 0, 0); } -void AgiEngine::cmd_print_at(uint8 *p) { +void cmdPrintAt(AgiGame *state, uint8 *p) { int n = p0 < 1 ? 1 : p0; debugC(4, kDebugLevelScripts, "%d %d %d %d", p0, p1, p2, p3); - print(_curLogic->texts[n - 1], p1, p2, p3); + state->_vm->print(state->_curLogic->texts[n - 1], p1, p2, p3); } -void AgiEngine::cmd_print_at_v(uint8 *p) { +void cmdPrintAtV(AgiGame *state, uint8 *p) { int n = _v[p0] < 1 ? 1 : _v[p0]; - print(_curLogic->texts[n - 1], p1, p2, p3); + state->_vm->print(state->_curLogic->texts[n - 1], p1, p2, p3); } -void AgiEngine::cmd_push_script(uint8 *p) { +void cmdPushScript(AgiGame *state, uint8 *p) { // We run AGIMOUSE always as a side effect if (getFeatures() & GF_AGIMOUSE || true) { - _game.vars[27] = _mouse.button; - _game.vars[28] = _mouse.x / 2; - _game.vars[29] = _mouse.y; + state->vars[27] = state->_vm->_mouse.button; + state->vars[28] = state->_vm->_mouse.x / 2; + state->vars[29] = state->_vm->_mouse.y; } else { if (getVersion() >= 0x2915) { debug(0, "push.script"); @@ -1513,35 +1644,35 @@ void AgiEngine::cmd_push_script(uint8 *p) { } } -void AgiEngine::cmd_set_pri_base(uint8 *p) { +void cmdSetPriBase(AgiGame *state, uint8 *p) { int i, x, pri; debug(0, "Priority base set to %d", p0); - // _game.alt_pri = true; + // state->alt_pri = true; x = (_HEIGHT - p0) * _HEIGHT / 10; for (i = 0; i < _HEIGHT; i++) { pri = (i - p0) < 0 ? 4 : (i - p0) * _HEIGHT / x + 5; if (pri > 15) pri = 15; - _game.priTable[i] = pri; + state->priTable[i] = pri; } } -void AgiEngine::cmd_mouse_posn(uint8 *p) { - _v[p0] = WIN_TO_PIC_X(_mouse.x); - _v[p1] = WIN_TO_PIC_Y(_mouse.y); +void cmdMousePosn(AgiGame *state, uint8 *p) { + _v[p0] = WIN_TO_PIC_X(state->_vm->_mouse.x); + _v[p1] = WIN_TO_PIC_Y(state->_vm->_mouse.y); } -void AgiEngine::cmd_shake_screen(uint8 *p) { +void cmdShakeScreen(AgiGame *state, uint8 *p) { int i; // AGIPAL uses shake.screen values between 100 and 109 to set the palette // (Checked the original AGIPAL-hack's shake.screen-routine's disassembly). if (p0 >= 100 && p0 < 110) { if (getFeatures() & GF_AGIPAL) { - _gfx->setAGIPal(p0); + state->_vm->_gfx->setAGIPal(p0); return; } else { warning("It looks like GF_AGIPAL flag is missing"); @@ -1550,212 +1681,60 @@ void AgiEngine::cmd_shake_screen(uint8 *p) { // Disables input while shaking to prevent bug // #1678230: AGI: Entering text while screen is shaking - bool originalValue = _game.inputEnabled; - _game.inputEnabled = false; + bool originalValue = state->inputEnabled; + state->inputEnabled = false; - _gfx->shakeStart(); + state->_vm->_gfx->shakeStart(); - _sprites->commitBoth(); // Fixes SQ1 demo + state->_vm->_sprites->commitBoth(); // Fixes SQ1 demo for (i = 4 * p0; i; i--) { - _gfx->shakeScreen(i & 1); - _gfx->flushBlock(0, 0, GFX_WIDTH - 1, GFX_HEIGHT - 1); - mainCycle(); + state->_vm->_gfx->shakeScreen(i & 1); + state->_vm->_gfx->flushBlock(0, 0, GFX_WIDTH - 1, GFX_HEIGHT - 1); + state->_vm->mainCycle(); } - _gfx->shakeEnd(); + state->_vm->_gfx->shakeEnd(); // Sets input back to what it was - _game.inputEnabled = originalValue; -} - -void AgiEngine::setupOpcodes() { - AgiCommand tmp[] = { - NULL, // 0x00 - &AgiEngine::cmd_increment, - &AgiEngine::cmd_decrement, - &AgiEngine::cmd_assignn, - &AgiEngine::cmd_assignv, - &AgiEngine::cmd_addn, - &AgiEngine::cmd_addv, - &AgiEngine::cmd_subn, - &AgiEngine::cmd_subv, // 0x08 - &AgiEngine::cmd_lindirectv, - &AgiEngine::cmd_rindirect, - &AgiEngine::cmd_lindirectn, - &AgiEngine::cmd_set, - &AgiEngine::cmd_reset, - &AgiEngine::cmd_toggle, - &AgiEngine::cmd_set_v, - &AgiEngine::cmd_reset_v, // 0x10 - &AgiEngine::cmd_toggle_v, - &AgiEngine::cmd_new_room, - &AgiEngine::cmd_new_room_f, - &AgiEngine::cmd_load_logic, - &AgiEngine::cmd_load_logic_f, - &AgiEngine::cmd_call, - &AgiEngine::cmd_call_f, - &AgiEngine::cmd_load_pic, // 0x18 - &AgiEngine::cmd_draw_pic, - &AgiEngine::cmd_show_pic, - &AgiEngine::cmd_discard_pic, - &AgiEngine::cmd_overlay_pic, - &AgiEngine::cmd_show_pri_screen, - &AgiEngine::cmd_load_view, - &AgiEngine::cmd_load_view_f, - &AgiEngine::cmd_discard_view, // 0x20 - &AgiEngine::cmd_animate_obj, - &AgiEngine::cmd_unanimate_all, - &AgiEngine::cmd_draw, - &AgiEngine::cmd_erase, - &AgiEngine::cmd_position, - &AgiEngine::cmd_position_f, - &AgiEngine::cmd_get_posn, - &AgiEngine::cmd_reposition, // 0x28 - &AgiEngine::cmd_set_view, - &AgiEngine::cmd_set_view_f, - &AgiEngine::cmd_set_loop, - &AgiEngine::cmd_set_loop_f, - &AgiEngine::cmd_fix_loop, - &AgiEngine::cmd_release_loop, - &AgiEngine::cmd_set_cel, - &AgiEngine::cmd_set_cel_f, // 0x30 - &AgiEngine::cmd_last_cel, - &AgiEngine::cmd_current_cel, - &AgiEngine::cmd_current_loop, - &AgiEngine::cmd_current_view, - &AgiEngine::cmd_number_of_loops, - &AgiEngine::cmd_set_priority, - &AgiEngine::cmd_set_priority_f, - &AgiEngine::cmd_release_priority, // 0x38 - &AgiEngine::cmd_get_priority, - &AgiEngine::cmd_stop_update, - &AgiEngine::cmd_start_update, - &AgiEngine::cmd_force_update, - &AgiEngine::cmd_ignore_horizon, - &AgiEngine::cmd_observe_horizon, - &AgiEngine::cmd_set_horizon, - &AgiEngine::cmd_object_on_water, // 0x40 - &AgiEngine::cmd_object_on_land, - &AgiEngine::cmd_object_on_anything, - &AgiEngine::cmd_ignore_objs, - &AgiEngine::cmd_observe_objs, - &AgiEngine::cmd_distance, - &AgiEngine::cmd_stop_cycling, - &AgiEngine::cmd_start_cycling, - &AgiEngine::cmd_normal_cycle, // 0x48 - &AgiEngine::cmd_end_of_loop, - &AgiEngine::cmd_reverse_cycle, - &AgiEngine::cmd_reverse_loop, - &AgiEngine::cmd_cycle_time, - &AgiEngine::cmd_stop_motion, - &AgiEngine::cmd_start_motion, - &AgiEngine::cmd_step_size, - &AgiEngine::cmd_step_time, // 0x50 - &AgiEngine::cmd_move_obj, - &AgiEngine::cmd_move_obj_f, - &AgiEngine::cmd_follow_ego, - &AgiEngine::cmd_wander, - &AgiEngine::cmd_normal_motion, - &AgiEngine::cmd_set_dir, - &AgiEngine::cmd_get_dir, - &AgiEngine::cmd_ignore_blocks, // 0x58 - &AgiEngine::cmd_observe_blocks, - &AgiEngine::cmd_block, - &AgiEngine::cmd_unblock, - &AgiEngine::cmd_get, - &AgiEngine::cmd_get_f, - &AgiEngine::cmd_drop, - &AgiEngine::cmd_put, - &AgiEngine::cmd_put_f, // 0x60 - &AgiEngine::cmd_get_room_f, - &AgiEngine::cmd_load_sound, - &AgiEngine::cmd_sound, - &AgiEngine::cmd_stop_sound, - &AgiEngine::cmd_print, - &AgiEngine::cmd_print_f, - &AgiEngine::cmd_display, - &AgiEngine::cmd_display_f, // 0x68 - &AgiEngine::cmd_clear_lines, - &AgiEngine::cmd_text_screen, - &AgiEngine::cmd_graphics, - &AgiEngine::cmd_set_cursor_char, - &AgiEngine::cmd_set_text_attribute, - &AgiEngine::cmd_shake_screen, - &AgiEngine::cmd_configure_screen, - &AgiEngine::cmd_status_line_on, // 0x70 - &AgiEngine::cmd_status_line_off, - &AgiEngine::cmd_set_string, - &AgiEngine::cmd_get_string, - &AgiEngine::cmd_word_to_string, - &AgiEngine::cmd_parse, - &AgiEngine::cmd_get_num, - &AgiEngine::cmd_prevent_input, - &AgiEngine::cmd_accept_input, // 0x78 - &AgiEngine::cmd_set_key, - &AgiEngine::cmd_add_to_pic, - &AgiEngine::cmd_add_to_pic_f, - &AgiEngine::cmd_status, - &AgiEngine::cmd_save_game, - &AgiEngine::cmd_load_game, - &AgiEngine::cmd_init_disk, - &AgiEngine::cmd_restart_game, // 0x80 - &AgiEngine::cmd_show_obj, - &AgiEngine::cmd_random, - &AgiEngine::cmd_program_control, - &AgiEngine::cmd_player_control, - &AgiEngine::cmd_obj_status_f, - &AgiEngine::cmd_quit, - &AgiEngine::cmd_show_mem, - &AgiEngine::cmd_pause, // 0x88 - &AgiEngine::cmd_echo_line, - &AgiEngine::cmd_cancel_line, - &AgiEngine::cmd_init_joy, - &AgiEngine::cmd_toggle_monitor, - &AgiEngine::cmd_version, - &AgiEngine::cmd_script_size, - &AgiEngine::cmd_set_game_id, - &AgiEngine::cmd_log, // 0x90 - &AgiEngine::cmd_set_scan_start, - &AgiEngine::cmd_reset_scan_start, - &AgiEngine::cmd_reposition_to, - &AgiEngine::cmd_reposition_to_f, - &AgiEngine::cmd_trace_on, - &AgiEngine::cmd_trace_info, - &AgiEngine::cmd_print_at, - &AgiEngine::cmd_print_at_v, // 0x98 - &AgiEngine::cmd_discard_view, // Opcode repeated from 0x20 ? - &AgiEngine::cmd_clear_text_rect, - &AgiEngine::cmd_set_upper_left, - &AgiEngine::cmd_set_menu, - &AgiEngine::cmd_set_menu_item, - &AgiEngine::cmd_submit_menu, - &AgiEngine::cmd_enable_item, - &AgiEngine::cmd_disable_item, // 0xa0 - &AgiEngine::cmd_menu_input, - &AgiEngine::cmd_show_obj_v, - &AgiEngine::cmd_open_dialogue, - &AgiEngine::cmd_close_dialogue, - &AgiEngine::cmd_mul_n, - &AgiEngine::cmd_mul_v, - &AgiEngine::cmd_div_n, - &AgiEngine::cmd_div_v, // 0xa8 - &AgiEngine::cmd_close_window, - &AgiEngine::cmd_set_simple, - &AgiEngine::cmd_push_script, - &AgiEngine::cmd_pop_script, - &AgiEngine::cmd_hold_key, - &AgiEngine::cmd_set_pri_base, - &AgiEngine::cmd_discard_sound, - &AgiEngine::cmd_hide_mouse, // 0xb0 - &AgiEngine::cmd_allow_menu, - &AgiEngine::cmd_show_mouse, - &AgiEngine::cmd_fence_mouse, - &AgiEngine::cmd_mouse_posn, - &AgiEngine::cmd_release_key, - &AgiEngine::cmd_adj_ego_move_to_x_y - }; - assert(ARRAYSIZE(_agiCommands) == ARRAYSIZE(tmp)); - for (int i = 0; i < ARRAYSIZE(tmp); ++i) - _agiCommands[i] = tmp[i]; + state->inputEnabled = originalValue; +} + +void cmdSetSpeed(AgiGame *state, uint8 *p) { + // V1 command + (void)state; + (void)p; + // speed = _v[p0]; +} + +void cmdSetItemView(AgiGame *state, uint8 *p) { + // V1 command + (void)state; + (void)p; +} + +void cmdCallV1(AgiGame *state, uint8 *p) { + state->_vm->agiLoadResource(rLOGIC, p0); + state->logic_list[++state->max_logics]; + _v[13] = 1; +} + +void cmdNewRoomV1(AgiGame *state, uint8 *p) { + warning("cmdNewRoomV1()"); + state->_vm->agiLoadResource(rLOGIC, p0); + state->max_logics = 1; + state->logic_list[1] = p0; + _v[13] = 1; +} + +void cmdNewRoomVV1(AgiGame *state, uint8 *p) { + warning("cmdNewRoomVV1()"); + state->_vm->agiLoadResource(rLOGIC, _v[p0]); + state->max_logics = 1; + state->logic_list[1] = _v[p0]; + _v[13] = 1; +} + +void cmdUnknown(AgiGame *state, uint8 *p) { + warning("Skipping unknown opcode %2X", *(code + ip - 1)); } /** @@ -1763,11 +1742,15 @@ void AgiEngine::setupOpcodes() { * @param n Number of the logic resource to execute */ int AgiEngine::runLogic(int n) { + AgiGame *state = &_game; uint8 op = 0; uint8 p[CMD_BSIZE] = { 0 }; - uint8 *code = NULL; int num = 0; ScriptPos sp; + //int logic_index = 0; + + state->logic_list[0] = 0; + state->max_logics = 0; debugC(2, kDebugLevelScripts, "================="); debugC(2, kDebugLevelScripts, "runLogic(%d)", n); @@ -1783,10 +1766,9 @@ int AgiEngine::runLogic(int n) { } _game.lognum = n; - _curLogic = &_game.logics[_game.lognum]; + _game._curLogic = &_game.logics[_game.lognum]; - code = _curLogic->data; - _curLogic->cIP = _curLogic->sIP; + _game._curLogic->cIP = _game._curLogic->sIP; _timerHack = 0; while (ip < _game.logics[n].size && !(shouldQuit() || _restartGame)) { @@ -1833,19 +1815,39 @@ int AgiEngine::runLogic(int n) { debugC(2, kDebugLevelScripts, "%sreturn() // Logic %d", st, n); debugC(2, kDebugLevelScripts, "================="); +// if (getVersion() < 0x2000) { +// if (logic_index < state->max_logics) { +// n = state->logic_list[++logic_index]; +// state->_curLogic = &state->logics[n]; +// state->lognum = n; +// ip = 2; +// warning("running logic %d\n", n); +// break; +// } +// _v[13]=0; +// } + _game.execStack.pop_back(); return 1; default: - num = logicNamesCmd[op].numArgs; + num = logicNamesCmd[op].argumentsLength(); memmove(p, code + ip, num); memset(p + num, 0, CMD_BSIZE - num); debugC(2, kDebugLevelScripts, "%s%s(%d %d %d)", st, logicNamesCmd[op].name, p[0], p[1], p[2]); - (this->*_agiCommands[op])(p); + _agiCommands[op](&_game, p); ip += num; } +// if ((op == 0x0B || op == 0x3F || op == 0x40) && logic_index < state->max_logics) { +// n = state->logic_list[++logic_index]; +// state->_curLogic = &state->logics[n]; +// state->lognum = n; +// ip = 2; +// warning("running logic %d\n", n); +// } + if (_game.exitAllLogics) break; } @@ -1858,7 +1860,7 @@ int AgiEngine::runLogic(int n) { void AgiEngine::executeAgiCommand(uint8 op, uint8 *p) { debugC(2, kDebugLevelScripts, "%s(%d %d %d)", logicNamesCmd[op].name, p[0], p[1], p[2]); - (this->*_agiCommands[op])(p); + _agiCommands[op](&_game, p); } } // End of namespace Agi diff --git a/engines/agi/op_dbg.cpp b/engines/agi/op_dbg.cpp index be73dbefae..87e235cf17 100644 --- a/engines/agi/op_dbg.cpp +++ b/engines/agi/op_dbg.cpp @@ -28,248 +28,17 @@ namespace Agi { #define ip (_game.logics[lognum].cIP) #define code (_game.logics[lognum].data) -#ifdef _L -#undef _L -#endif - -#define _L(a,b,c) { a, b, c } - -struct AgiLogicnames logicNamesTest[] = { - _L("", 0, 0x00), - _L("equaln", 2, 0x80), - _L("equalv", 2, 0xC0), - _L("lessn", 2, 0x80), - _L("lessv", 2, 0xC0), - _L("greatern", 2, 0x80), - _L("greaterv", 2, 0xC0), - _L("isset", 1, 0x00), - _L("issetv", 1, 0x80), - _L("has", 1, 0x00), - _L("obj.in.room", 2, 0x40), - _L("posn", 5, 0x00), - _L("controller", 1, 0x00), - _L("have.key", 0, 0x00), - - // Not 0 args. Has variable number. - _L("said", 0, 0x00), - - _L("compare.strings", 2, 0x00), - _L("obj.in.box", 5, 0x00), - _L("center.posn", 5, 0x00), - _L("right.posn", 5, 0x00), - - // Haven't seen an official name for this command so tried to name it descriptively. - _L("in.motion.using.mouse", 0, 0x00) -}; - -struct AgiLogicnames logicNamesIf[] = { - _L("OR", 0, 0x00), - _L("NOT", 0, 0x00), - _L("ELSE", 0, 0x00), - _L("IF", 0, 0x00) -}; - -struct AgiLogicnames logicNamesCmd[] = { - _L("return", 0, 0x00), // 00 - _L("increment", 1, 0x80), // 01 - _L("decrement", 1, 0x80), // 02 - _L("assignn", 2, 0x80), // 03 - _L("assignv", 2, 0xC0), // 04 - _L("addn", 2, 0x80), // 05 - _L("addv", 2, 0xC0), // 06 - _L("subn", 2, 0x80), // 07 - _L("subv", 2, 0xC0), // 08 - _L("lindirectv", 2, 0xC0), // 09 - _L("rindirect", 2, 0xC0), // 0A - _L("lindirectn", 2, 0x80), // 0B - _L("set", 1, 0x00), // 0C - _L("reset", 1, 0x00), // 0D - _L("toggle", 1, 0x00), // 0E - _L("set.v", 1, 0x80), // 0F - _L("reset.v", 1, 0x80), // 10 - _L("toggle.v", 1, 0x80), // 11 - _L("new.room", 1, 0x00), // 12 - _L("new.room.v", 1, 0x80), // 13 - _L("load.logics", 1, 0x00), // 14 - _L("load.logics.v", 1, 0x80), // 15 - _L("call", 1, 0x00), // 16 - _L("call.v", 1, 0x80), // 17 - _L("load.pic", 1, 0x80), // 18 - _L("draw.pic", 1, 0x80), // 19 - _L("show.pic", 0, 0x00), // 1A - _L("discard.pic", 1, 0x80), // 1B - _L("overlay.pic", 1, 0x80), // 1C - _L("show.pri.screen", 0, 0x00), // 1D - _L("load.view", 1, 0x00), // 1E - _L("load.view.v", 1, 0x80), // 1F - _L("discard.view", 1, 0x00), // 20 - _L("animate.obj", 1, 0x00), // 21 - _L("unanimate.all", 0, 0x00), // 22 - _L("draw", 1, 0x00), // 23 - _L("erase", 1, 0x00), // 24 - _L("position", 3, 0x00), // 25 - _L("position.v", 3, 0x60), // 26 - _L("get.posn", 3, 0x60), // 27 - _L("reposition", 3, 0x60), // 28 - _L("set.view", 2, 0x00), // 29 - _L("set.view.v", 2, 0x40), // 2A - _L("set.loop", 2, 0x00), // 2B - _L("set.loop.v", 2, 0x40), // 2C - _L("fix.loop", 1, 0x00), // 2D - _L("release.loop", 1, 0x00), // 2E - _L("set.cel", 2, 0x00), // 2F - _L("set.cel.v", 2, 0x40), // 30 - _L("last.cel", 2, 0x40), // 31 - _L("current.cel", 2, 0x40), // 32 - _L("current.loop", 2, 0x40), // 33 - _L("current.view", 2, 0x40), // 34 - _L("number.of.loops", 2, 0x40), // 35 - _L("set.priority", 2, 0x00), // 36 - _L("set.priority.v", 2, 0x40), // 37 - _L("release.priority", 1, 0x00), // 38 - _L("get.priority", 2, 0x40), // 39 - _L("stop.update", 1, 0x00), // 3A - _L("start.update", 1, 0x00), // 3B - _L("force.update", 1, 0x00), // 3C - _L("ignore.horizon", 1, 0x00), // 3D - _L("observe.horizon", 1, 0x00), // 3E - _L("set.horizon", 1, 0x00), // 3F - _L("object.on.water", 1, 0x00), // 40 - _L("object.on.land", 1, 0x00), // 41 - _L("object.on.anything", 1, 0x00), // 42 - _L("ignore.objs", 1, 0x00), // 43 - _L("observe.objs", 1, 0x00), // 44 - _L("distance", 3, 0x20), // 45 - _L("stop.cycling", 1, 0x00), // 46 - _L("start.cycling", 1, 0x00), // 47 - _L("normal.cycle", 1, 0x00), // 48 - _L("end.of.loop", 2, 0x00), // 49 - _L("reverse.cycle", 1, 0x00), // 4A - _L("reverse.loop", 2, 0x00), // 4B - _L("cycle.time", 2, 0x40), // 4C - _L("stop.motion", 1, 0x00), // 4D - _L("start.motion", 1, 0x00), // 4E - _L("step.size", 2, 0x40), // 4F - _L("step.time", 2, 0x40), // 50 - _L("move.obj", 5, 0x00), // 51 - _L("move.obj.v", 5, 0x70), // 52 - _L("follow.ego", 3, 0x00), // 53 - _L("wander", 1, 0x00), // 54 - _L("normal.motion", 1, 0x00), // 55 - _L("set.dir", 2, 0x40), // 56 - _L("get.dir", 2, 0x40), // 57 - _L("ignore.blocks", 1, 0x00), // 58 - _L("observe.blocks", 1, 0x00), // 59 - _L("block", 4, 0x00), // 5A - _L("unblock", 0, 0x00), // 5B - _L("get", 1, 0x00), // 5C - _L("get.v", 1, 0x80), // 5D - _L("drop", 1, 0x00), // 5E - _L("put", 2, 0x00), // 5F - _L("put.v", 2, 0x40), // 60 - _L("get.room.v", 2, 0xC0), // 61 - _L("load.sound", 1, 0x00), // 62 - _L("sound", 2, 0x00), // 63 - _L("stop.sound", 0, 0x00), // 64 - _L("print", 1, 0x00), // 65 - _L("print.v", 1, 0x80), // 66 - _L("display", 3, 0x00), // 67 - _L("display.v", 3, 0xE0), // 68 - _L("clear.lines", 3, 0x00), // 69 - _L("text.screen", 0, 0x00), // 6A - _L("graphics", 0, 0x00), // 6B - _L("set.cursor.char", 1, 0x00), // 6C - _L("set.text.attribute", 2, 0x00), // 6D - _L("shake.screen", 1, 0x00), // 6E - _L("configure.screen", 3, 0x00), // 6F - _L("status.line.on", 0, 0x00), // 70 - _L("status.line.off", 0, 0x00), // 71 - _L("set.string", 2, 0x00), // 72 - _L("get.string", 5, 0x00), // 73 - _L("word.to.string", 2, 0x00), // 74 - _L("parse", 1, 0x00), // 75 - _L("get.num", 2, 0x40), // 76 - _L("prevent.input", 0, 0x00), // 77 - _L("accept.input", 0, 0x00), // 78 - _L("set.key", 3, 0x00), // 79 - _L("add.to.pic", 7, 0x00), // 7A - _L("add.to.pic.v", 7, 0xFE), // 7B - _L("status", 0, 0x00), // 7C - _L("save.game", 0, 0x00), // 7D - _L("restore.game", 0, 0x00), // 7E - _L("init.disk", 0, 0x00), // 7F - _L("restart.game", 0, 0x00), // 80 - _L("show.obj", 1, 0x00), // 81 - _L("random", 3, 0x20), // 82 - _L("program.control", 0, 0x00), // 83 - _L("player.control", 0, 0x00), // 84 - _L("obj.status.v", 1, 0x80), // 85 - // 0 args for AGI version 2.089 - _L("quit", 1, 0x00), // 86 - - _L("show.mem", 0, 0x00), // 87 - _L("pause", 0, 0x00), // 88 - _L("echo.line", 0, 0x00), // 89 - _L("cancel.line", 0, 0x00), // 8A - _L("init.joy", 0, 0x00), // 8B - _L("toggle.monitor", 0, 0x00), // 8C - _L("version", 0, 0x00), // 8D - _L("script.size", 1, 0x00), // 8E - _L("set.game.id", 1, 0x00), // 8F - _L("log", 1, 0x00), // 90 - _L("set.scan.start", 0, 0x00), // 91 - _L("reset.scan.start", 0, 0x00), // 92 - _L("reposition.to", 3, 0x00), // 93 - _L("reposition.to.v", 3, 0x60), // 94 - _L("trace.on", 0, 0x00), // 95 - _L("trace.info", 3, 0x00), // 96 - - // 3 args for AGI versions before 2.440 - _L("print.at", 4, 0x00), // 97 - _L("print.at.v", 4, 0x80), // 98 - - _L("discard.view.v", 1, 0x80), // 99 - _L("clear.text.rect", 5, 0x00), // 9A - _L("set.upper.left", 2, 0x00), // 9B - _L("set.menu", 1, 0x00), // 9C - _L("set.menu.item", 2, 0x00), // 9D - _L("submit.menu", 0, 0x00), // 9E - _L("enable.item", 1, 0x00), // 9F - _L("disable.item", 1, 0x00), // A0 - _L("menu.input", 0, 0x00), // A1 - _L("show.obj.v", 1, 0x01), // A2 - _L("open.dialogue", 0, 0x00), // A3 - _L("close.dialogue", 0, 0x00), // A4 - _L("mul.n", 2, 0x80), // A5 - _L("mul.v", 2, 0xC0), // A6 - _L("div.n", 2, 0x80), // A7 - _L("div.v", 2, 0xC0), // A8 - _L("close.window", 0, 0x00), // A9 - - _L("set.simple", 1, 0x00), // AA - _L("push.script", 0, 0x00), // AB - _L("pop.script", 0, 0x00), // AC - _L("hold.key", 0, 0x00), // AD - _L("set.pri.base", 1, 0x00), // AE - _L("discard.sound", 1, 0x00), // AF - - // 1 arg for AGI version 3.002.086 - _L("hide.mouse", 0, 0x00), // B0 - - _L("allow.menu", 1, 0x00), // B1 - _L("show.mouse", 0, 0x00), // B2 - _L("fence.mouse", 4, 0x00), // B3 - _L("mouse.posn", 2, 0x00), // B4 - _L("release.key", 0, 0x00), // B5 - - // 2 args for at least the Amiga Gold Rush! (v2.05 1989-03-09) using Amiga AGI 2.316. - _L("adj.ego.move.to.xy", 0, 0x00), // B6 - _L(NULL, 0, 0x00) +AgiInstruction logicNamesIf[] = { + { "OR", "", NULL }, + { "NOT", "", NULL }, + { "ELSE", "", NULL }, + { "IF", "", NULL } }; void AgiEngine::debugConsole(int lognum, int mode, const char *str) { - AgiLogicnames *x; - uint8 a, c, z; + AgiInstruction *x; + uint8 a, z; + const char *c; if (str) { debug(0, " %s", str); @@ -302,8 +71,8 @@ void AgiEngine::debugConsole(int lognum, int mode, const char *str) { break; default: x = mode == lCOMMAND_MODE ? logicNamesCmd : logicNamesTest; - a = (unsigned char)(x + *(code + ip))->numArgs; - c = (unsigned char)(x + *(code + ip))->argMask; + a = x[*(code + ip)].argumentsLength(); + c = x[*(code + ip)].args; if (_debug.opcodes) { debugN(0, "%02X %02X %02X %02X %02X %02X %02X %02X %02X\n" @@ -321,12 +90,12 @@ void AgiEngine::debugConsole(int lognum, int mode, const char *str) { debugN(0, "%s ", (x + *(code + ip))->name); for (z = 1; a > 0;) { - if (~c & 0x80) { + if (*c == 'n') { debugN(0, "%d", *(code + (ip + z))); } else { debugN(0, "v%d[%d]", *(code + (ip + z)), getvar(*(code + (ip + z)))); } - c <<= 1; + c++; z++; if (--a > 0) debugN(0, ","); diff --git a/engines/agi/op_test.cpp b/engines/agi/op_test.cpp index 0660a614b6..a44c68e0fc 100644 --- a/engines/agi/op_test.cpp +++ b/engines/agi/op_test.cpp @@ -23,18 +23,180 @@ #include "agi/agi.h" #include "agi/opcodes.h" +#include "common/endian.h" namespace Agi { -#define ip (_game.logics[lognum].cIP) -#define code (_game.logics[lognum].data) +#define ip (state->_curLogic->cIP) +#define code (state->_curLogic->data) + +#define getvar(a) state->_vm->getvar(a) +#define getflag(a) state->_vm->getflag(a) #define testEqual(v1, v2) (getvar(v1) == (v2)) #define testLess(v1, v2) (getvar(v1) < (v2)) #define testGreater(v1, v2) (getvar(v1) > (v2)) #define testIsSet(flag) (getflag(flag)) -#define testHas(obj) (objectGetLocation(obj) == EGO_OWNED) -#define testObjInRoom(obj, v) (objectGetLocation(obj) == getvar(v)) +#define testHas(obj) (state->_vm->objectGetLocation(obj) == EGO_OWNED) +#define testHasV1(obj) (state->_vm->objectGetLocation(obj) == EGO_OWNED_V1) +#define testObjInRoom(obj, v) (state->_vm->objectGetLocation(obj) == getvar(v)) + +void condEqual(AgiGame *state, uint8 *p) { + if (p[0] == 11) + state->_vm->_timerHack++; + state->testResult = testEqual(p[0], p[1]); +} + +void condEqualV(AgiGame *state, uint8 *p) { + if (p[0] == 11 || p[1] == 11) + state->_vm->_timerHack++; + state->testResult = testEqual(p[0], getvar(p[1])); +} + +void condLess(AgiGame *state, uint8 *p) { + if (p[0] == 11) + state->_vm->_timerHack++; + state->testResult = testLess(p[0], p[1]); +} + +void condLessV(AgiGame *state, uint8 *p) { + if (p[0] == 11 || p[1] == 11) + state->_vm->_timerHack++; + state->testResult = testLess(p[0], getvar(p[1])); +} + +void condGreater(AgiGame *state, uint8 *p) { + if (p[0] == 11) + state->_vm->_timerHack++; + state->testResult = testGreater(p[0], p[1]); +} + +void condGreaterV(AgiGame *state, uint8 *p) { + if (p[0] == 11 || p[1] == 11) + state->_vm->_timerHack++; + state->testResult = testGreater(p[0], getvar(p[1])); +} + +void condIsSet(AgiGame *state, uint8 *p) { + state->testResult = testIsSet(p[0]); +} + +void condIsSetV(AgiGame *state, uint8 *p) { + state->testResult = testIsSet(getvar(p[1])); +} + +void condIsSetV1(AgiGame *state, uint8 *p) { + state->testResult = getvar(p[0]) > 0; +} + +void condHas(AgiGame *state, uint8 *p) { + state->testResult = testHas(p[0]); +} + +void condHasV1(AgiGame *state, uint8 *p) { + state->testResult = testHasV1(p[0]); +} + +void condObjInRoom(AgiGame *state, uint8 *p) { + state->testResult = testObjInRoom(p[0], p[1]); +} + +void condPosn(AgiGame *state, uint8 *p) { + state->testResult = state->_vm->testPosn(p[0], p[1], p[2], p[3], p[4]); +} + +void condController(AgiGame *state, uint8 *p) { + state->testResult = state->_vm->testController(p[0]); +} + +void condHaveKey(AgiGame *state, uint8 *p) { + state->testResult = state->_vm->testKeypressed(); +} + +void condSaid(AgiGame *state, uint8 *p) { + int ec = state->_vm->testSaid(p[0], p + 1); + state->testResult = ec; +} + +void condSaid1(AgiGame *state, uint8 *p) { + state->testResult = false; + + if (!getflag(fEnteredCli)) + return; + + int id0 = READ_LE_UINT16(p); + + if ((id0 == 1 || id0 == state->egoWords[0].id)) + state->testResult = true; +} + +void condSaid2(AgiGame *state, uint8 *p) { + state->testResult = false; + + if (!getflag(fEnteredCli)) + return; + + int id0 = READ_LE_UINT16(p); + int id1 = READ_LE_UINT16(p + 2); + + if ((id0 == 1 || id0 == state->egoWords[0].id) && + (id1 == 1 || id1 == state->egoWords[1].id)) + state->testResult = true; +} + +void condSaid3(AgiGame *state, uint8 *p) { + state->testResult = false; + + if (!getflag(fEnteredCli)) + return; + + int id0 = READ_LE_UINT16(p); + int id1 = READ_LE_UINT16(p + 2); + int id2 = READ_LE_UINT16(p + 4); + + if ((id0 == 1 || id0 == state->egoWords[0].id) && + (id1 == 1 || id1 == state->egoWords[1].id) && + (id2 == 1 || id2 == state->egoWords[2].id)) + state->testResult = true; +} + +void condBit(AgiGame *state, uint8 *p) { + state->testResult = (getvar(p[1]) >> p[0]) & 1; +} + +void condCompareStrings(AgiGame *state, uint8 *p) { + debugC(7, kDebugLevelScripts, "comparing [%s], [%s]", state->strings[p[0]], state->strings[p[1]]); + state->testResult = state->_vm->testCompareStrings(p[0], p[1]); +} + +void condObjInBox(AgiGame *state, uint8 *p) { + state->testResult = state->_vm->testObjInBox(p[0], p[1], p[2], p[3], p[4]); +} + +void condCenterPosn(AgiGame *state, uint8 *p) { + state->testResult = state->_vm->testObjCenter(p[0], p[1], p[2], p[3], p[4]); +} + +void condRightPosn(AgiGame *state, uint8 *p) { + state->testResult = state->_vm->testObjRight(p[0], p[1], p[2], p[3], p[4]); +} + +void condUnknown13(AgiGame *state, uint8 *p) { + // My current theory is that this command checks whether the ego is currently moving + // and that that movement has been caused using the mouse and not using the keyboard. + // I base this theory on the game's behavior on an Amiga emulator, not on disassembly. + // This command is used at least in the Amiga version of Gold Rush! v2.05 1989-03-09 + // (AGI 2.316) in logics 1, 3, 5, 6, 137 and 192 (Logic.192 revealed this command's nature). + // TODO: Check this command's implementation using disassembly just to be sure. + int ec = state->viewTable[0].flags & fAdjEgoXY; + debugC(7, kDebugLevelScripts, "op_test: in.motion.using.mouse = %s (Amiga-specific testcase 19)", ec ? "true" : "false"); + state->testResult = ec; +} + +void condUnknown(AgiGame *state, uint8 *p) { + warning("Skipping unknown test command %2X", *(code + ip - 1)); + state->testResult = false; +} uint8 AgiEngine::testCompareStrings(uint8 s1, uint8 s2) { char ms1[MAX_STRINGLEN]; @@ -147,6 +309,7 @@ uint8 AgiEngine::testObjRight(uint8 n, uint8 x1, uint8 y1, uint8 x2, uint8 y2) { // When player has entered something, it is parsed elsewhere uint8 AgiEngine::testSaid(uint8 nwords, uint8 *cc) { + AgiGame *state = &_game; int c, n = _game.numEgoWords; int z = 0; @@ -202,210 +365,110 @@ uint8 AgiEngine::testSaid(uint8 nwords, uint8 *cc) { } int AgiEngine::testIfCode(int lognum) { - int ec = true; - int retval = true; - uint8 op = 0; - uint8 notTest = false; - uint8 orTest = false; - uint16 lastIp = ip; - uint8 p[16] = { 0 }; - bool end_test = false; - - while (retval && !(shouldQuit() || _restartGame) && !end_test) { + AgiGame *state = &_game; + uint8 op; + uint8 p[16]; + + int notMode = false; + int orMode = false; + int endTest = false; + int result = true; + + while (!(shouldQuit() || _restartGame) && !endTest) { if (_debug.enabled && (_debug.logic0 || lognum)) debugConsole(lognum, lTEST_MODE, NULL); - lastIp = ip; op = *(code + ip++); memmove(p, (code + ip), 16); switch (op) { - case 0xFF: // END IF, TEST true - end_test = true; - break; - case 0xFD: - notTest = !notTest; - continue; - case 0xFC: // OR - // if or_test is ON and we hit 0xFC, end of OR, then - // or is STILL false so break. - if (orTest) { - ec = false; - retval = false; - end_test = true; + case 0xFC: + if (orMode) { + // We have reached the end of an OR expression without + // a single test command evaluating as true. Thus the OR + // expression evalutes as false which means the whole + // expression evaluates as false. So skip until the + // ending 0xFF and return. + skipInstructionsUntil(0xFF); + result = false; + endTest = true; + } else { + orMode = true; } - - orTest = true; continue; - + case 0xFD: + notMode = true; + continue; case 0x00: - // return true? - end_test = true; - break; - case 0x01: - ec = testEqual(p[0], p[1]); - if (p[0] == 11) - _timerHack++; - break; - case 0x02: - ec = testEqual(p[0], getvar(p[1])); - if (p[0] == 11 || p[1] == 11) - _timerHack++; - break; - case 0x03: - ec = testLess(p[0], p[1]); - if (p[0] == 11) - _timerHack++; - break; - case 0x04: - ec = testLess(p[0], getvar(p[1])); - if (p[0] == 11 || p[1] == 11) - _timerHack++; - break; - case 0x05: - ec = testGreater(p[0], p[1]); - if (p[0] == 11) - _timerHack++; - break; - case 0x06: - ec = testGreater(p[0], getvar(p[1])); - if (p[0] == 11 || p[1] == 11) - _timerHack++; - break; - case 0x07: - ec = testIsSet(p[0]); - break; - case 0x08: - ec = testIsSet(getvar(p[0])); - break; - case 0x09: - ec = testHas(p[0]); - break; - case 0x0A: - ec = testObjInRoom(p[0], p[1]); - break; - case 0x0B: - ec = testPosn(p[0], p[1], p[2], p[3], p[4]); - break; - case 0x0C: - ec = testController(p[0]); - break; - case 0x0D: - ec = testKeypressed(); - break; - case 0x0E: - ec = testSaid(p[0], (uint8 *) code + (ip + 1)); - ip = lastIp; - ip++; // skip opcode - ip += p[0] * 2; // skip num_words * 2 - ip++; // skip num_words opcode - break; - case 0x0F: - debugC(7, kDebugLevelScripts, "comparing [%s], [%s]", _game.strings[p[0]], _game.strings[p[1]]); - ec = testCompareStrings(p[0], p[1]); - break; - case 0x10: - ec = testObjInBox(p[0], p[1], p[2], p[3], p[4]); - break; - case 0x11: - ec = testObjCenter(p[0], p[1], p[2], p[3], p[4]); - break; - case 0x12: - ec = testObjRight(p[0], p[1], p[2], p[3], p[4]); - break; - case 0x13: // Unknown test command 19 - // My current theory is that this command checks whether the ego is currently moving - // and that that movement has been caused using the mouse and not using the keyboard. - // I base this theory on the game's behavior on an Amiga emulator, not on disassembly. - // This command is used at least in the Amiga version of Gold Rush! v2.05 1989-03-09 - // (AGI 2.316) in logics 1, 3, 5, 6, 137 and 192 (Logic.192 revealed this command's nature). - // TODO: Check this command's implementation using disassembly just to be sure. - ec = _game.viewTable[0].flags & ADJ_EGO_XY; - debugC(7, kDebugLevelScripts, "op_test: in.motion.using.mouse = %s (Amiga-specific testcase 19)", ec ? "true" : "false"); - break; + case 0xFF: + endTest = true; + continue; + default: - ec = false; - end_test = true; - } - - if (!end_test) { - if (op <= 0x12) - ip += logicNamesTest[op].numArgs; - - // exchange ec value - if (notTest) - ec = !ec; - - // not is only enabled for 1 test command - notTest = false; - - if (orTest && ec) { - // a true inside an OR statement passes - // ENTIRE statement scan for end of OR - - // CM: test for opcode < 0xfc changed from 'op' to - // '*(code+ip)', to avoid problem with the 0xfd (NOT) - // opcode byte. Changed a bad ip += ... ip++ construct. - // This should fix the crash with Larry's logic.0 code: - // - // if ((isset(4) || - // !isset(2) || - // v30 == 2 || - // v30 == 1)) { - // goto Label1; - // } - // - // The bytecode is: - // ff fc 07 04 fd 07 02 01 1e 02 01 1e 01 fc ff - - // find end of OR - while (*(code + ip) != 0xFC) { - if (*(code + ip) == 0x0E) { // said - ip++; - - // cover count + ^words - ip += 1 + ((*(code + ip)) * 2); - continue; - } - - if (*(code + ip) < 0xFC) - ip += logicNamesTest[*(code + ip)].numArgs; - ip++; + // Evaluate the command and skip the rest of the instruction + _agiCondCommands[op](state, p); + skipInstruction(op); + + // NOT mode is enabled only for one instruction + if (notMode) + state->testResult = !state->testResult; + notMode = false; + + if (orMode) { + if (state->testResult) { + // We are in OR mode and the last test command evaluated + // as true, thus the whole OR expression evaluates as + // true. So skip the rest of the OR expression and + // continue normally. + skipInstructionsUntil(0xFC); + orMode = false; + continue; } - ip++; - - orTest = false; - retval = true; } else { - retval = orTest ? retval || ec : retval && ec; + result &= state->testResult; + if (!result) { + // Since we are in AND mode and the last test command + // evaluated as false, the whole expression also evaluates + // as false. So skip until the ending 0xFF and return. + skipInstructionsUntil(0xFF); + endTest = true; + continue; + } } + break; } } - // if false, scan for end of IP? - if (retval) + // Skip the following IF block if the condition evaluates as false + if (result) ip += 2; - else { - ip = lastIp; - while (*(code + ip) != 0xff) { - if (*(code + ip) == 0x0e) { - ip++; - ip += (*(code + ip)) * 2 + 1; - } else if (*(code + ip) < 0xfc) { - ip += logicNamesTest[*(code + ip)].numArgs; - ip++; - } else { - ip++; - } - } - ip++; // skip over 0xFF + else ip += READ_LE_UINT16(code + ip) + 2; - } if (_debug.enabled && (_debug.logic0 || lognum)) - debugConsole(lognum, 0xFF, retval ? "=true" : "=false"); + debugConsole(lognum, 0xFF, result ? "=true" : "=false"); + + return result; +} - return retval; +void AgiEngine::skipInstruction(byte op) { + AgiGame *state = &_game; + if (op >= 0xFC) + return; + if (op == 0x0E && state->_vm->getVersion() >= 0x2000) // said + ip += *(code + ip) * 2 + 1; + else + ip += logicNamesTest[op].argumentsLength(); +} + +void AgiEngine::skipInstructionsUntil(byte v) { + AgiGame *state = &_game; + while (1) { + byte op = *(code + ip++); + if (op == v) + return; + skipInstruction(op); + } } } // End of namespace Agi diff --git a/engines/agi/opcodes.cpp b/engines/agi/opcodes.cpp new file mode 100644 index 0000000000..c2cecefc52 --- /dev/null +++ b/engines/agi/opcodes.cpp @@ -0,0 +1,381 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +#include "agi/agi.h" +#include "agi/opcodes.h" + +namespace Agi { + +AgiInstruction *logicNamesTest; +AgiInstruction *logicNamesCmd; + +AgiInstruction insV1Test[] = { + { "", "", &condUnknown }, // 00 + { "equaln", "vn", &condEqual }, // 01 + { "equalv", "vv", &condEqualV }, // 02 + { "lessn", "vn", &condLess }, // 03 + { "lessv", "vv", &condLessV }, // 04 + { "greatern", "vn", &condGreater }, // 05 + { "greaterv", "vv", &condGreaterV }, // 06 + { "isset", "v", &condIsSetV1 }, // 07 + { "has", "n", &condHasV1 }, // 08 + { "said", "nnnn", &condSaid2 }, // 09 + { "posn", "nnnnn", &condPosn }, // 0A + { "controller", "n", &condController }, // 0B + { "obj.in.room", "nv", &condObjInRoom }, // 0C + { "said", "nnnnnn", &condSaid3 }, // 0D + { "have.key", "", &condHaveKey }, // 0E + { "said", "nn", &condSaid1 }, // 0F + { "bit", "nv", &condBit }, // 10 +}; + +AgiInstruction insV1[] = { + { "return", "", NULL }, // 00 + { "increment", "v", &cmdIncrement }, // 01 + { "decrement", "v", &cmdDecrement }, // 02 + { "assignn", "vn", &cmdAssignN }, // 03 + { "assignv", "vv", &cmdAssignV }, // 04 + { "addn", "vn", &cmdAddN }, // 05 + { "addv", "vv", &cmdAddV }, // 06 + { "subn", "vn", &cmdSubN }, // 07 + { "subv", "vv", &cmdSubV }, // 08 + { "load.view", "n", &cmdLoadView }, // 09 + { "animate.obj", "n", &cmdAnimateObj }, // 0A + { "new.room", "n", &cmdNewRoomV1 }, // 0B + { "draw.pic", "v", &cmdDrawPicV1 }, // 0C + { "print", "s", &cmdPrint }, // 0D TODO + { "status", "", &cmdStatus }, // 0E TODO + { "save.game", "", &cmdSaveGame }, // 0F TODO + { "restore.game", "", &cmdLoadGame }, // 10 TODO + { "init.disk", "", &cmdInitDisk }, // 11 TODO + { "restart.game", "", &cmdRestartGame }, // 12 TODO + { "random", "v", &cmdRandomV1 }, // 13 + { "get", "n", &cmdGetV1 }, // 14 + { "drop", "n", &cmdDrop }, // 15 + { "draw", "n", &cmdDraw }, // 16 TODO + { "erase", "n", &cmdErase }, // 17 TODO + { "position", "nnn", &cmdPositionV1 }, // 18 + { "position.v", "nvv", &cmdPositionFV1 }, // 19 + { "get.posn", "nvv", &cmdGetPosn }, // 1A + { "set.cel", "nn", &cmdSetCel }, // 1B + { "set.loop", "nn", &cmdSetLoop }, // 1C + { "end.of.loop", "nn", &cmdEndOfLoopV1 }, // 1D + { "reverse.loop", "nn", &cmdReverseLoopV1 }, // 1E + { "move.obj", "nnnnn", &cmdMoveObj }, // 1F + { "set.view", "nn", &cmdSetView }, // 20 + { "follow.ego", "nnn", &cmdFollowEgo }, // 21 + { "block", "", &cmdBlock }, // 22 + { "unblock", "", &cmdUnblock }, // 23 + { "ignore.blocks", "n", &cmdIgnoreBlocks }, // 24 + { "observe.blocks", "n", &cmdObserveBlocks }, // 25 + { "wander", "n", &cmdWander }, // 26 + { "reposition", "nvv", &cmdRepositionV1 }, // 27 + { "stop.motion", "n", &cmdStopMotionV1 }, // 28 + { "start.motion", "n", &cmdStartMotionV1 }, // 29 + { "stop.cycling", "n", &cmdStopCycling }, // 2A + { "start.cycling", "n", &cmdStartCycling }, // 2B + { "stop.update", "n", &cmdStopUpdate }, // 2C + { "start.update", "n", &cmdStartUpdate }, // 2D + { "program.control", "", &cmdProgramControl }, // 2E + { "player.control", "", &cmdPlayerControl }, // 2F + { "set.priority", "nn", &cmdSetPriority }, // 30 + { "release.priority", "n", &cmdReleasePriority }, // 31 + { "add.to.pic", "nnnnnn", &cmdAddToPicV1 }, // 32 + { "set.horizon", "n", &cmdSetHorizon }, // 33 + { "ignore.horizon", "n", &cmdIgnoreHorizon }, // 34 + { "observe.horizon", "n", &cmdObserveHorizon }, // 35 + { "load.logics", "n", &cmdLoadLogic }, // 36 TODO + { "object.on.water", "n", &cmdObjectOnWater }, // 37 + { "load.pic", "v", &cmdLoadPicV1 }, // 38 + { "load.sound", "n", &cmdLoadSound }, // 39 + { "sound", "nn", &cmdSound }, // 3A + { "stop.sound", "", &cmdStopSound }, // 3B + { "set.v", "v", &cmdSetV }, // 3C + { "reset.v", "v", &cmdResetV }, // 3D + { "toggle.v", "v", &cmdToggleV }, // 3E + { "new.room.v", "v", &cmdNewRoomVV1 }, // 3F TODO + { "call", "n", &cmdCallV1 }, // 40 TODO + { "quit", "", &cmdQuitV1 }, // 41 + { "set.speed", "v", &cmdSetSpeed }, // 42 + { "move.obj.v", "nvvvv", &cmdMoveObjF }, // 43 + { "...", "nn", &cmdUnknown }, // 44 + { "get.v", "v", &cmdUnknown }, // 45 + { "assign.v", "vv", &cmdUnknown }, // 46 + { "...", "n", &cmdUnknown }, // 47 # printvar.v + { "get.priority", "nv", &cmdGetPriority }, // 48 + { "ignore.objs", "n", &cmdIgnoreObjs }, // 49 + { "observe.objs", "n", &cmdObserveObjs }, // 4A + { "distance", "nnv", &cmdDistance }, // 4B + { "object.on.land", "n", &cmdObjectOnLand }, // 4C + { "...", "nv", &cmdUnknown }, // 4D # set.priority.f + { "...", "", &cmdUnknown }, // 4E # show.obj + { "load.logics", "n", &cmdLoadLogic }, // 4F # load.global.logics + { "display", "nnns", &cmdDisplay }, // 50 TODO: 4 vs 3 args + { "prevent.input???", "", &cmdUnknown }, // 51 + { "...", "", &cmdUnknown }, // 52 # nop + { "...", "n", &cmdUnknown }, // 53 # text.screen + { "...", "", &cmdUnknown }, // 54 ??? + { "stop.motion", "", &cmdStopMotion }, // 55 or force.update?? + { "discard.view", "n", &cmdDiscardView }, // 56 + { "discard.pic", "v", &cmdDiscardPic }, // 57 + { "set.item.view", "nn", &cmdSetItemView }, // 58 + { "...", "", &cmdUnknown }, // 59 # reverse.cycle + { "last.cel", "nv", &cmdLastCel }, // 5A + { "set.cel.v", "nv", &cmdSetCelF }, // 5B + { "...", "", &cmdUnknown }, // 5C # normal.cycle + { "load.view", "n", &cmdLoadView }, // 5D + { "...", "", &cmdUnknown }, // 5E + { "...", "", &cmdUnknown }, // 5F + { "setbit", "nv", &cmdUnknown }, // 60 + { "...", "nv", &cmdUnknown }, // 61 # clearbit +}; + +AgiInstruction insV2Test[] = { + { "", "", &condUnknown }, // 00 + { "equaln", "vn", &condEqual }, // 01 + { "equalv", "vv", &condEqualV }, // 02 + { "lessn", "vn", &condLess }, // 03 + { "lessv", "vv", &condLessV }, // 04 + { "greatern", "vn", &condGreater }, // 05 + { "greaterv", "vv", &condGreaterV }, // 06 + { "isset", "n", &condIsSet }, // 07 + { "issetv", "v", &condIsSetV }, // 08 + { "has", "n", &condHas }, // 09 + { "obj.in.room", "nv", &condObjInRoom}, // 0A + { "posn", "nnnnn", &condPosn }, // 0B + { "controller", "n", &condController }, // 0C + { "have.key", "", &condHaveKey}, // 0D + { "said", "", &condSaid }, // 0E + { "compare.strings", "ss", &condCompareStrings }, // 0F + { "obj.in.box", "nnnnn", &condObjInBox }, // 10 + { "center.posn", "nnnnn", &condCenterPosn }, // 11 + { "right.posn", "nnnnn", &condRightPosn }, // 12 + { "in.motion.using.mouse", "", &condUnknown13 } // 13 +}; + +AgiInstruction insV2[] = { + { "return", "", NULL }, + { "increment", "v", &cmdIncrement }, + { "decrement", "v", &cmdDecrement }, + { "assignn", "vn", &cmdAssignN }, + { "assignv", "vv", &cmdAssignV }, + { "addn", "vn", &cmdAddN }, + { "addv", "vv", &cmdAddV }, + { "subn", "vn", &cmdSubN }, + { "subv", "vv", &cmdSubV }, + { "lindirectv", "vv", &cmdLindirectV }, + { "lindirect", "vv", &cmdRindirect }, + { "lindirectn", "vn", &cmdLindirectN }, + { "set", "n", &cmdSet }, + { "reset", "n", &cmdReset }, + { "toggle", "n", &cmdToggle }, + { "set.v", "v", &cmdSetV }, + { "reset.v", "v", &cmdResetV }, + { "toggle.v", "v", &cmdToggleV }, + { "new.room", "n", &cmdNewRoom }, + { "new.room.v", "v", &cmdNewRoomF }, + { "load.logics", "n", &cmdLoadLogic }, + { "load.logics.v", "v", &cmdLoadLogicF }, + { "call", "n", &cmdCall }, + { "call.v", "v", &cmdCallF }, + { "load.pic", "v", &cmdLoadPic }, + { "draw.pic", "v", &cmdDrawPic }, + { "show.pic", "", &cmdShowPic }, + { "discard.pic", "v", &cmdDiscardPic }, + { "overlay.pic", "v", &cmdOverlayPic }, + { "show.pri.screen", "", &cmdShowPriScreen }, + { "load.view", "n", &cmdLoadView }, + { "load.view.v", "v", &cmdLoadViewF }, + { "discard.view", "n", &cmdDiscardView }, + { "animate.obj", "n", &cmdAnimateObj }, + { "unanimate.all", "", &cmdUnanimateAll }, + { "draw", "n", &cmdDraw }, + { "erase", "n", &cmdErase }, + { "position", "nnn", &cmdPosition }, + { "position.v", "nvv", &cmdPositionF }, + { "get.posn", "nvv", &cmdGetPosn }, + { "reposition", "nvv", &cmdReposition }, + { "set.view", "nn", &cmdSetView }, + { "set.view.v", "nv", &cmdSetViewF }, + { "set.loop", "nn", &cmdSetLoop }, + { "set.loop.v", "nv", &cmdSetLoopF }, + { "fix.loop", "n", &cmdFixLoop }, + { "release.loop", "n", &cmdReleaseLoop }, + { "set.cel", "nn", &cmdSetCel }, + { "set.cel.v", "nv", &cmdSetCelF }, + { "last.cel", "nv", &cmdLastCel }, + { "current.cel", "nv", &cmdCurrentCel }, + { "current.loop", "nv", &cmdCurrentLoop }, + { "current.view", "nv", &cmdCurrentView }, + { "number.of.loops", "nv", &cmdNumberOfLoops }, + { "set.priority", "nn", &cmdSetPriority }, + { "set.priority.v", "nv", &cmdSetPriorityF }, + { "release.priority", "n", &cmdReleasePriority }, + { "get.priority", "nn", &cmdGetPriority }, + { "stop.update", "n", &cmdStopUpdate }, + { "start.update", "n", &cmdStartUpdate }, + { "force.update", "n", &cmdForceUpdate }, + { "ignore.horizon", "n", &cmdIgnoreHorizon }, + { "observe.horizon", "n", &cmdObserveHorizon }, + { "set.horizon", "n", &cmdSetHorizon }, + { "object.on.water", "n", &cmdObjectOnWater }, + { "object.on.land", "n", &cmdObjectOnLand }, + { "object.on.anything", "n", &cmdObjectOnAnything }, + { "ignore.objs", "n", &cmdIgnoreObjs }, + { "observe.objs", "n", &cmdObserveObjs }, + { "distance", "nnv", &cmdDistance }, + { "stop.cycling", "n", &cmdStopCycling }, + { "start.cycling", "n", &cmdStartCycling }, + { "normal.cycle", "n", &cmdNormalCycle }, + { "end.of.loop", "nn", &cmdEndOfLoop }, + { "reverse.cycle", "n", &cmdReverseCycle }, + { "reverse.loop", "nn", &cmdReverseLoop }, + { "cycle.time", "nv", &cmdCycleTime }, + { "stop.motion", "n", &cmdStopMotion }, + { "start.motion", "n", &cmdStartMotion }, + { "step.size", "nv", &cmdStepSize }, + { "step.time", "nv", &cmdStepTime }, + { "move.obj", "nnnnn", &cmdMoveObj }, + { "move.obj.v", "nvvvv", &cmdMoveObjF }, + { "follow.ego", "nnn", &cmdFollowEgo }, + { "wander", "n", &cmdWander }, + { "normal.motion", "n", &cmdNormalMotion }, + { "set.dir", "nv", &cmdSetDir }, + { "get.dir", "nv", &cmdGetDir }, + { "ignore.blocks", "n", &cmdIgnoreBlocks }, + { "observe.blocks", "n", &cmdObserveBlocks }, + { "block", "nnnn", &cmdBlock }, + { "unblock", "", &cmdUnblock }, + { "get", "n", &cmdGet }, + { "get.v", "v", &cmdGetF }, + { "drop", "n", &cmdDrop }, + { "put", "nn", &cmdPut }, + { "put.v", "vv", &cmdPutF }, + { "get.room.v", "vv", &cmdGetRoomF }, + { "load.sound", "n", &cmdLoadSound }, + { "sound", "nn", &cmdSound }, + { "stop.sound", "", &cmdStopSound }, + { "print", "s", &cmdPrint }, + { "print.v", "v", &cmdPrintF }, + { "display", "nns", &cmdDisplay }, + { "display.v", "vvv", &cmdDisplayF }, + { "clear.lines", "nns", &cmdClearLines }, + { "text.screen", "", &cmdTextScreen }, + { "graphics", "", &cmdGraphics }, + { "set.cursor.char", "s", &cmdSetCursorChar }, + { "set.text.attribute", "nn", &cmdSetTextAttribute }, + { "shake.screen", "n", &cmdShakeScreen }, + { "configure.screen", "nnn", &cmdConfigureScreen }, + { "status.line.on", "", &cmdStatusLineOn }, + { "status.line.off", "", &cmdStatusLineOff }, + { "set.string", "ns", &cmdSetString }, + { "get.string", "ns", &cmdGetString }, + { "word.to.string", "nn", &cmdWordToString }, + { "parse", "n", &cmdParse }, + { "get.num", "nv", &cmdGetNum }, + { "prevent.input", "", &cmdPreventInput }, + { "accept.input", "", &cmdAcceptInput }, + { "set.key", "nnn", &cmdSetKey }, + { "add.to.pic", "nnnnnnn", &cmdAddToPic }, + { "add.to.pic.v", "vvvvvvv", &cmdAddToPicF }, + { "status", "", &cmdStatus }, + { "save.game", "", &cmdSaveGame }, + { "restore.game", "", &cmdLoadGame }, + { "init.disk", "", &cmdInitDisk }, + { "restart.game", "", &cmdRestartGame }, + { "show.obj", "n", &cmdShowObj }, + { "random", "nnv", &cmdRandom }, + { "program.control", "", &cmdProgramControl }, + { "player.control", "", &cmdPlayerControl }, + { "obj.status.v", "v", &cmdObjStatusF }, + { "quit", "n", &cmdQuit }, + { "show.mem", "", &cmdShowMem }, + { "pause", "", &cmdPause }, + { "echo.line", "", &cmdEchoLine }, + { "cancel.line", "", &cmdCancelLine }, + { "init.joy", "", &cmdInitJoy }, + { "toggle.monitor", "", &cmdToggleMonitor }, + { "version", "", &cmdVersion }, + { "script.size", "n", &cmdScriptSize }, + { "set.game.id", "s", &cmdSetGameID }, + { "log", "s", &cmdLog }, + { "set.scan.start", "", &cmdSetScanStart }, + { "reset.scan.start", "", &cmdResetScanStart }, + { "reposition.to", "nnn", &cmdRepositionTo }, + { "reposition.to.v", "nvv", &cmdRepositionToF }, + { "trace.on", "", &cmdTraceOn }, + { "trace.info", "nnn", &cmdTraceInfo }, + { "print.at", "snnn", &cmdPrintAt }, + { "print.at.v", "vnnn", &cmdPrintAtV }, + { "discard.view.v", "v", &cmdDiscardView}, + { "clear.text.rect", "nnnnn", &cmdClearTextRect }, + { "set.upper.left", "nn", &cmdSetUpperLeft }, + { "set.menu", "s", &cmdSetMenu }, + { "set.menu.member", "sn", &cmdSetMenuItem }, + { "submit.menu", "", &cmdSubmitMenu }, + { "enable.member", "n", &cmdEnableItem }, + { "disable.member", "n", &cmdDisableItem }, + { "menu.input", "", &cmdMenuInput }, + { "show.obj.v", "v", &cmdShowObjV }, + { "open.dialogue", "", &cmdOpenDialogue }, + { "close.dialogue", "", &cmdCloseDialogue }, + { "mul.n", "vn", &cmdMulN }, + { "mul.v", "vv", &cmdMulV }, + { "div.n", "vn", &cmdDivN }, + { "div.v", "vv", &cmdDivV }, + { "close.window", "", &cmdCloseWindow }, + { "set.simple", "n", &cmdSetSimple }, + { "push.script", "", &cmdPushScript }, + { "pop.script", "", &cmdPopScript }, + { "hold.key", "", &cmdHoldKey }, + { "set.pri.base", "n", &cmdSetPriBase }, + { "discard.sound", "n", &cmdDiscardSound }, + { "hide.mouse", "", &cmdHideMouse }, + { "allow.menu", "n", &cmdAllowMenu }, + { "show.mouse", "", &cmdShowMouse }, + { "fence.mouse", "nnnn", &cmdFenceMouse }, + { "mouse.posn", "vv", &cmdMousePosn }, + { "release.key", "", &cmdReleaseKey }, + { "adj.ego.move.to.xy", "", &cmdAdjEgoMoveToXY } +}; + +void AgiEngine::setupOpcodes() { + if (getVersion() >= 0x2000) { + for (int i = 0; i <= ARRAYSIZE(insV2Test); ++i) + _agiCondCommands[i] = insV2Test[i].func; + for (int i = 0; i < ARRAYSIZE(insV2); ++i) + _agiCommands[i] = insV2[i].func; + + logicNamesTest = insV2Test; + logicNamesCmd = insV2; + } else { + for (int i = 0; i <= ARRAYSIZE(insV1Test); ++i) + _agiCondCommands[i] = insV1Test[i].func; + for (int i = 0; i < ARRAYSIZE(insV1); ++i) + _agiCommands[i] = insV1[i].func; + + logicNamesTest = insV1Test; + logicNamesCmd = insV1; + } +} + +} diff --git a/engines/agi/opcodes.h b/engines/agi/opcodes.h index b0d2051f0b..7f0f287550 100644 --- a/engines/agi/opcodes.h +++ b/engines/agi/opcodes.h @@ -23,17 +23,251 @@ #ifndef AGI_OPCODES_H #define AGI_OPCODES_H +#include <string.h> + namespace Agi { -struct AgiLogicnames { +struct AgiInstruction { const char *name; - uint16 numArgs; - uint16 argMask; + const char *args; + AgiCommand func; + + int argumentsLength() { return strlen(args); } }; -extern AgiLogicnames logicNamesTest[]; -extern AgiLogicnames logicNamesCmd[]; -extern AgiLogicnames logicNamesIf[]; +extern AgiInstruction *logicNamesTest; +extern AgiInstruction *logicNamesCmd; + +void cmdIncrement(AgiGame *state, uint8 *p); +void cmdDecrement(AgiGame *state, uint8 *p); +void cmdAssignN(AgiGame *state, uint8 *p); +void cmdAssignV(AgiGame *state, uint8 *p); +void cmdAddN(AgiGame *state, uint8 *p); +void cmdAddV(AgiGame *state, uint8 *p); +void cmdSubN(AgiGame *state, uint8 *p); +void cmdSubV(AgiGame *state, uint8 *p); // 0x08 +void cmdLindirectV(AgiGame *state, uint8 *p); +void cmdRindirect(AgiGame *state, uint8 *p); +void cmdLindirectN(AgiGame *state, uint8 *p); +void cmdSet(AgiGame *state, uint8 *p); +void cmdReset(AgiGame *state, uint8 *p); +void cmdToggle(AgiGame *state, uint8 *p); +void cmdSetV(AgiGame *state, uint8 *p); +void cmdResetV(AgiGame *state, uint8 *p); // 0x10 +void cmdToggleV(AgiGame *state, uint8 *p); +void cmdNewRoom(AgiGame *state, uint8 *p); +void cmdNewRoomF(AgiGame *state, uint8 *p); +void cmdLoadLogic(AgiGame *state, uint8 *p); +void cmdLoadLogicF(AgiGame *state, uint8 *p); +void cmdCall(AgiGame *state, uint8 *p); +void cmdCallF(AgiGame *state, uint8 *p); +void cmdLoadPic(AgiGame *state, uint8 *p); // 0x18 +void cmdLoadPicV1(AgiGame *state, uint8 *p); +void cmdDrawPic(AgiGame *state, uint8 *p); +void cmdDrawPicV1(AgiGame *state, uint8 *p); +void cmdShowPic(AgiGame *state, uint8 *p); +void cmdDiscardPic(AgiGame *state, uint8 *p); +void cmdOverlayPic(AgiGame *state, uint8 *p); +void cmdShowPriScreen(AgiGame *state, uint8 *p); +void cmdLoadView(AgiGame *state, uint8 *p); +void cmdLoadViewF(AgiGame *state, uint8 *p); +void cmdDiscardView(AgiGame *state, uint8 *p); // 0x20 +void cmdAnimateObj(AgiGame *state, uint8 *p); +void cmdUnanimateAll(AgiGame *state, uint8 *p); +void cmdDraw(AgiGame *state, uint8 *p); +void cmdErase(AgiGame *state, uint8 *p); +void cmdPosition(AgiGame *state, uint8 *p); +void cmdPositionV1(AgiGame *state, uint8 *p); +void cmdPositionF(AgiGame *state, uint8 *p); +void cmdPositionFV1(AgiGame *state, uint8 *p); +void cmdGetPosn(AgiGame *state, uint8 *p); +void cmdReposition(AgiGame *state, uint8 *p); // 0x28 +void cmdRepositionV1(AgiGame *state, uint8 *p); // 0x28 +void cmdSetView(AgiGame *state, uint8 *p); +void cmdSetViewF(AgiGame *state, uint8 *p); +void cmdSetLoop(AgiGame *state, uint8 *p); +void cmdSetLoopF(AgiGame *state, uint8 *p); +void cmdFixLoop(AgiGame *state, uint8 *p); +void cmdReleaseLoop(AgiGame *state, uint8 *p); +void cmdSetCel(AgiGame *state, uint8 *p); +void cmdSetCelF(AgiGame *state, uint8 *p); // 0x30 +void cmdLastCel(AgiGame *state, uint8 *p); +void cmdCurrentCel(AgiGame *state, uint8 *p); +void cmdCurrentLoop(AgiGame *state, uint8 *p); +void cmdCurrentView(AgiGame *state, uint8 *p); +void cmdNumberOfLoops(AgiGame *state, uint8 *p); +void cmdSetPriority(AgiGame *state, uint8 *p); +void cmdSetPriorityF(AgiGame *state, uint8 *p); +void cmdReleasePriority(AgiGame *state, uint8 *p); // 0x38 +void cmdGetPriority(AgiGame *state, uint8 *p); +void cmdStopUpdate(AgiGame *state, uint8 *p); +void cmdStartUpdate(AgiGame *state, uint8 *p); +void cmdForceUpdate(AgiGame *state, uint8 *p); +void cmdIgnoreHorizon(AgiGame *state, uint8 *p); +void cmdObserveHorizon(AgiGame *state, uint8 *p); +void cmdSetHorizon(AgiGame *state, uint8 *p); +void cmdObjectOnWater(AgiGame *state, uint8 *p); // 0x40 +void cmdObjectOnLand(AgiGame *state, uint8 *p); +void cmdObjectOnAnything(AgiGame *state, uint8 *p); +void cmdIgnoreObjs(AgiGame *state, uint8 *p); +void cmdObserveObjs(AgiGame *state, uint8 *p); +void cmdDistance(AgiGame *state, uint8 *p); +void cmdStopCycling(AgiGame *state, uint8 *p); +void cmdStartCycling(AgiGame *state, uint8 *p); +void cmdNormalCycle(AgiGame *state, uint8 *p); // 0x48 +void cmdEndOfLoop(AgiGame *state, uint8 *p); +void cmdEndOfLoopV1(AgiGame *state, uint8 *p); +void cmdReverseCycle(AgiGame *state, uint8 *p); +void cmdReverseLoop(AgiGame *state, uint8 *p); +void cmdReverseLoopV1(AgiGame *state, uint8 *p); +void cmdCycleTime(AgiGame *state, uint8 *p); +void cmdStopMotion(AgiGame *state, uint8 *p); +void cmdStopMotionV1(AgiGame *state, uint8 *p); +void cmdStartMotion(AgiGame *state, uint8 *p); +void cmdStartMotionV1(AgiGame *state, uint8 *p); +void cmdStepSize(AgiGame *state, uint8 *p); +void cmdStepTime(AgiGame *state, uint8 *p); // 0x50 +void cmdMoveObj(AgiGame *state, uint8 *p); +void cmdMoveObjF(AgiGame *state, uint8 *p); +void cmdFollowEgo(AgiGame *state, uint8 *p); +void cmdWander(AgiGame *state, uint8 *p); +void cmdNormalMotion(AgiGame *state, uint8 *p); +void cmdSetDir(AgiGame *state, uint8 *p); +void cmdGetDir(AgiGame *state, uint8 *p); +void cmdIgnoreBlocks(AgiGame *state, uint8 *p); // 0x58 +void cmdObserveBlocks(AgiGame *state, uint8 *p); +void cmdBlock(AgiGame *state, uint8 *p); +void cmdUnblock(AgiGame *state, uint8 *p); +void cmdGet(AgiGame *state, uint8 *p); +void cmdGetV1(AgiGame *state, uint8 *p); +void cmdGetF(AgiGame *state, uint8 *p); +void cmdDrop(AgiGame *state, uint8 *p); +void cmdPut(AgiGame *state, uint8 *p); +void cmdPutF(AgiGame *state, uint8 *p); // 0x60 +void cmdGetRoomF(AgiGame *state, uint8 *p); +void cmdLoadSound(AgiGame *state, uint8 *p); +void cmdSound(AgiGame *state, uint8 *p); +void cmdStopSound(AgiGame *state, uint8 *p); +void cmdPrint(AgiGame *state, uint8 *p); +void cmdPrintF(AgiGame *state, uint8 *p); +void cmdDisplay(AgiGame *state, uint8 *p); +void cmdDisplayF(AgiGame *state, uint8 *p); // 0x68 +void cmdClearLines(AgiGame *state, uint8 *p); +void cmdTextScreen(AgiGame *state, uint8 *p); +void cmdGraphics(AgiGame *state, uint8 *p); +void cmdSetCursorChar(AgiGame *state, uint8 *p); +void cmdSetTextAttribute(AgiGame *state, uint8 *p); +void cmdShakeScreen(AgiGame *state, uint8 *p); +void cmdConfigureScreen(AgiGame *state, uint8 *p); +void cmdStatusLineOn(AgiGame *state, uint8 *p); // 0x70 +void cmdStatusLineOff(AgiGame *state, uint8 *p); +void cmdSetString(AgiGame *state, uint8 *p); +void cmdGetString(AgiGame *state, uint8 *p); +void cmdWordToString(AgiGame *state, uint8 *p); +void cmdParse(AgiGame *state, uint8 *p); +void cmdGetNum(AgiGame *state, uint8 *p); +void cmdPreventInput(AgiGame *state, uint8 *p); +void cmdAcceptInput(AgiGame *state, uint8 *p); // 0x78 +void cmdSetKey(AgiGame *state, uint8 *p); +void cmdAddToPic(AgiGame *state, uint8 *p); +void cmdAddToPicV1(AgiGame *state, uint8 *p); +void cmdAddToPicF(AgiGame *state, uint8 *p); +void cmdStatus(AgiGame *state, uint8 *p); +void cmdSaveGame(AgiGame *state, uint8 *p); +void cmdLoadGame(AgiGame *state, uint8 *p); +void cmdInitDisk(AgiGame *state, uint8 *p); +void cmdRestartGame(AgiGame *state, uint8 *p); // 0x80 +void cmdShowObj(AgiGame *state, uint8 *p); +void cmdRandom(AgiGame *state, uint8 *p); +void cmdRandomV1(AgiGame *state, uint8 *p); +void cmdProgramControl(AgiGame *state, uint8 *p); +void cmdPlayerControl(AgiGame *state, uint8 *p); +void cmdObjStatusF(AgiGame *state, uint8 *p); +void cmdQuit(AgiGame *state, uint8 *p); +void cmdQuitV1(AgiGame *state, uint8 *p); +void cmdShowMem(AgiGame *state, uint8 *p); +void cmdPause(AgiGame *state, uint8 *p); // 0x88 +void cmdEchoLine(AgiGame *state, uint8 *p); +void cmdCancelLine(AgiGame *state, uint8 *p); +void cmdInitJoy(AgiGame *state, uint8 *p); +void cmdToggleMonitor(AgiGame *state, uint8 *p); +void cmdVersion(AgiGame *state, uint8 *p); +void cmdScriptSize(AgiGame *state, uint8 *p); +void cmdSetGameID(AgiGame *state, uint8 *p); +void cmdLog(AgiGame *state, uint8 *p); // 0x90 +void cmdSetScanStart(AgiGame *state, uint8 *p); +void cmdResetScanStart(AgiGame *state, uint8 *p); +void cmdRepositionTo(AgiGame *state, uint8 *p); +void cmdRepositionToF(AgiGame *state, uint8 *p); +void cmdTraceOn(AgiGame *state, uint8 *p); +void cmdTraceInfo(AgiGame *state, uint8 *p); +void cmdPrintAt(AgiGame *state, uint8 *p); +void cmdPrintAtV(AgiGame *state, uint8 *p); // 0x98 +//void cmdDiscardView(AgiGame *state, uint8 *p); // Opcode repeated from 0x20 ? +void cmdClearTextRect(AgiGame *state, uint8 *p); +void cmdSetUpperLeft(AgiGame *state, uint8 *p); +void cmdSetMenu(AgiGame *state, uint8 *p); +void cmdSetMenuItem(AgiGame *state, uint8 *p); +void cmdSubmitMenu(AgiGame *state, uint8 *p); +void cmdEnableItem(AgiGame *state, uint8 *p); +void cmdDisableItem(AgiGame *state, uint8 *p); // 0xa0 +void cmdMenuInput(AgiGame *state, uint8 *p); +void cmdShowObjV(AgiGame *state, uint8 *p); +void cmdOpenDialogue(AgiGame *state, uint8 *p); +void cmdCloseDialogue(AgiGame *state, uint8 *p); +void cmdMulN(AgiGame *state, uint8 *p); +void cmdMulV(AgiGame *state, uint8 *p); +void cmdDivN(AgiGame *state, uint8 *p); +void cmdDivV(AgiGame *state, uint8 *p); // 0xa8 +void cmdCloseWindow(AgiGame *state, uint8 *p); +void cmdSetSimple(AgiGame *state, uint8 *p); +void cmdPushScript(AgiGame *state, uint8 *p); +void cmdPopScript(AgiGame *state, uint8 *p); +void cmdHoldKey(AgiGame *state, uint8 *p); +void cmdSetPriBase(AgiGame *state, uint8 *p); +void cmdDiscardSound(AgiGame *state, uint8 *p); +void cmdHideMouse(AgiGame *state, uint8 *p); // 0xb0 +void cmdAllowMenu(AgiGame *state, uint8 *p); +void cmdShowMouse(AgiGame *state, uint8 *p); +void cmdFenceMouse(AgiGame *state, uint8 *p); +void cmdMousePosn(AgiGame *state, uint8 *p); +void cmdReleaseKey(AgiGame *state, uint8 *p); +void cmdAdjEgoMoveToXY(AgiGame *state, uint8 *p); + +void cmdSetSpeed(AgiGame *state, uint8 *p); +void cmdSetItemView(AgiGame *state, uint8 *p); +void cmdCallV1(AgiGame *state, uint8 *p); +void cmdNewRoomV1(AgiGame *state, uint8 *p); +void cmdNewRoomVV1(AgiGame *state, uint8 *p); +void cmdUnknown(AgiGame *state, uint8 *p); + +void condEqual(AgiGame *state, uint8 *p); +void condEqualV(AgiGame *state, uint8 *p); +void condLess(AgiGame *state, uint8 *p); +void condLessV(AgiGame *state, uint8 *p); +void condGreater(AgiGame *state, uint8 *p); +void condGreaterV(AgiGame *state, uint8 *p); +void condIsSet(AgiGame *state, uint8 *p); +void condIsSetV(AgiGame *state, uint8 *p); +void condHas(AgiGame *state, uint8 *p); +void condHasV1(AgiGame *state, uint8 *p); +void condObjInRoom(AgiGame *state, uint8 *p); +void condPosn(AgiGame *state, uint8 *p); +void condController(AgiGame *state, uint8 *p); +void condHaveKey(AgiGame *state, uint8 *p); +void condSaid(AgiGame *state, uint8 *p); +void condCompareStrings(AgiGame *state, uint8 *p); +void condObjInBox(AgiGame *state, uint8 *p); +void condCenterPosn(AgiGame *state, uint8 *p); +void condRightPosn(AgiGame *state, uint8 *p); +void condUnknown13(AgiGame *state, uint8 *p); +void condUnknown(AgiGame *state, uint8 *p); + +void condIsSetV1(AgiGame *state, uint8 *p); +void condSaid1(AgiGame *state, uint8 *p); +void condSaid2(AgiGame *state, uint8 *p); +void condSaid3(AgiGame *state, uint8 *p); +void condBit(AgiGame *state, uint8 *p); } // End of namespace Agi diff --git a/engines/agi/preagi.cpp b/engines/agi/preagi.cpp index c1a6cd33fe..34180b543f 100644 --- a/engines/agi/preagi.cpp +++ b/engines/agi/preagi.cpp @@ -22,18 +22,13 @@ #include "common/config-manager.h" #include "common/debug-channels.h" +#include "common/events.h" #include "common/random.h" #include "common/textconsole.h" -#include "audio/mididrv.h" - #include "agi/preagi.h" #include "agi/graphics.h" - -// preagi engines -#include "agi/preagi_mickey.h" -#include "agi/preagi_troll.h" -#include "agi/preagi_winnie.h" +#include "agi/keyboard.h" namespace Agi { @@ -59,19 +54,6 @@ PreAgiEngine::PreAgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : } void PreAgiEngine::initialize() { - // TODO: Some sound emulation modes do not fit our current music - // drivers, and I'm not sure what they are. For now, they might - // as well be called "PC Speaker" and "Not PC Speaker". - - switch (MidiDriver::getMusicType(MidiDriver::detectDevice(MDT_PCSPK))) { - case MT_PCSPK: - _soundemu = SOUND_EMU_PC; - break; - default: - _soundemu = SOUND_EMU_NONE; - break; - } - if (ConfMan.hasKey("render_mode")) { _renderMode = Common::parseRenderMode(ConfMan.get("render_mode").c_str()); } else if (ConfMan.hasKey("platform")) { @@ -89,9 +71,7 @@ void PreAgiEngine::initialize() { } _gfx = new GfxMgr(this); - //_sound = new SoundMgr(this, _mixer); _picture = new PictureMgr(this, _gfx); - //_sprites = new SpritesMgr(this, _gfx); _gfx->initMachine(); @@ -111,7 +91,6 @@ void PreAgiEngine::initialize() { _game.lineMinPrint = 0; // hardcoded _gfx->initVideo(); - //_sound->initSound(); _speakerStream = new Audio::PCSpeaker(_mixer->getOutputRate()); _mixer->playStream(Audio::Mixer::kSFXSoundType, &_speakerHandle, @@ -126,8 +105,6 @@ void PreAgiEngine::initialize() { memset(&_game.dirPic[i], 0, sizeof(struct AgiDir)); memset(&_game.dirSound[i], 0, sizeof(struct AgiDir)); } - - debugC(2, kDebugLevelMain, "Init sound"); } PreAgiEngine::~PreAgiEngine() { @@ -135,50 +112,181 @@ PreAgiEngine::~PreAgiEngine() { delete _speakerStream; } +int PreAgiEngine::rnd(int hi) { + return (_rnd->getRandomNumber(hi - 1) + 1); +} + +// Screen functions +void PreAgiEngine::clearScreen(int attr, bool overrideDefault) { + if (overrideDefault) + _defaultColor = attr; -Common::Error PreAgiEngine::go() { - setflag(fSoundOn, true); // enable sound + _gfx->clearScreen((attr & 0xF0) / 0x10); +} -// -// FIXME (Fingolfin asks): Why are Mickey, Winnie and Troll standalone classes -// instead of being subclasses of PreAgiEngine ? -// +void PreAgiEngine::clearGfxScreen(int attr) { + _gfx->drawRectangle(0, 0, GFX_WIDTH - 1, IDI_MAX_ROW_PIC * 8 -1, (attr & 0xF0) / 0x10); +} - // run preagi engine main loop - switch (getGameID()) { - case GID_MICKEY: - { - Mickey *mickey = new Mickey(this); - mickey->init(); - mickey->run(); - delete mickey; - } - break; - case GID_WINNIE: - { - Winnie *winnie = new Winnie(this); - winnie->init(); - winnie->run(); - delete winnie; +// String functions + +void PreAgiEngine::drawStr(int row, int col, int attr, const char *buffer) { + int code; + + if (attr == kColorDefault) + attr = _defaultColor; + + for (int iChar = 0; iChar < (int)strlen(buffer); iChar++) { + code = buffer[iChar]; + + switch (code) { + case '\n': + case 0x8D: + if (++row == 200 / 8) return; + col = 0; + break; + + case '|': + // swap attribute nibbles + break; + + default: + _gfx->putTextCharacter(1, col * 8 , row * 8, static_cast<char>(code), attr & 0x0f, (attr & 0xf0) / 0x10, false, getGameID() == GID_MICKEY ? mickey_fontdata : ibm_fontdata); + + if (++col == 320 / 8) { + col = 0; + if (++row == 200 / 8) return; + } } - break; - case GID_TROLL: - { - Troll *troll = new Troll(this); - troll->init(); - troll->run(); - delete troll; + } +} + +void PreAgiEngine::drawStrMiddle(int row, int attr, const char *buffer) { + int col = (25 / 2) - (strlen(buffer) / 2); // 25 = 320 / 8 (maximum column) + drawStr(row, col, attr, buffer); +} + +void PreAgiEngine::clearTextArea() { + int start = IDI_MAX_ROW_PIC; + + if (getGameID() == GID_TROLL) + start = 21; + + for (int row = start; row < 200 / 8; row++) { + clearRow(row); + } +} + +void PreAgiEngine::clearRow(int row) { + drawStr(row, 0, IDA_DEFAULT, " "); // 40 spaces +} + +void PreAgiEngine::printStr(const char* szMsg) { + clearTextArea(); + drawStr(21, 0, IDA_DEFAULT, szMsg); + _gfx->doUpdate(); + _system->updateScreen(); +} + +void PreAgiEngine::XOR80(char *buffer) { + for (size_t i = 0; i < strlen(buffer); i++) + if (buffer[i] & 0x80) + buffer[i] ^= 0x80; +} + +void PreAgiEngine::printStrXOR(char *szMsg) { + XOR80(szMsg); + printStr(szMsg); +} + +// Input functions + +int PreAgiEngine::getSelection(SelectionTypes type) { + Common::Event event; + GUI::Debugger *console = getDebugger(); + + while (!shouldQuit()) { + while (_eventMan->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_RTL: + case Common::EVENT_QUIT: + return 0; + case Common::EVENT_RBUTTONUP: + return 0; + case Common::EVENT_LBUTTONUP: + if (type == kSelYesNo || type == kSelAnyKey) + return 1; + case Common::EVENT_KEYDOWN: + if (event.kbd.keycode == Common::KEYCODE_d && (event.kbd.flags & Common::KBD_CTRL) && console) { + console->attach(); + console->onFrame(); + //FIXME: If not cleared, clicking again will start the console + event.kbd.keycode = Common::KEYCODE_INVALID; + event.kbd.flags = 0; + continue; + } + switch (event.kbd.keycode) { + case Common::KEYCODE_y: + if (type == kSelYesNo) + return 1; + case Common::KEYCODE_n: + if (type == kSelYesNo) + return 0; + case Common::KEYCODE_ESCAPE: + if (type == kSelNumber || type == kSelAnyKey) + return 0; + case Common::KEYCODE_1: + case Common::KEYCODE_2: + case Common::KEYCODE_3: + case Common::KEYCODE_4: + case Common::KEYCODE_5: + case Common::KEYCODE_6: + case Common::KEYCODE_7: + case Common::KEYCODE_8: + case Common::KEYCODE_9: + if (type == kSelNumber) + return event.kbd.keycode - Common::KEYCODE_1 + 1; + case Common::KEYCODE_SPACE: + if (type == kSelSpace) + return 1; + case Common::KEYCODE_BACKSPACE: + if (type == kSelBackspace) + return 0; + default: + if (event.kbd.flags & Common::KBD_CTRL) + break; + if (type == kSelYesNo) { + return 2; + } else if (type == kSelNumber) { + return 10; + } else if (type == kSelAnyKey || type == kSelBackspace) { + return 1; + } + } + break; + default: + break; + } } - break; - default: - error("Unknown preagi engine"); - break; + _system->updateScreen(); + _system->delayMillis(10); } - return Common::kNoError; + return 0; } -int PreAgiEngine::rnd(int hi) { - return (_rnd->getRandomNumber(hi - 1) + 1); +void PreAgiEngine::playNote(int16 frequency, int32 length) { + _speakerStream->play(Audio::PCSpeaker::kWaveFormSquare, frequency, length); + waitForTimer(length); +} + +void PreAgiEngine::waitForTimer(int msec_delay) { + uint32 start_time = _system->getMillis(); + + while (_system->getMillis() < start_time + msec_delay) { + _gfx->doUpdate(); + _system->updateScreen(); + _system->delayMillis(10); + } } } // End of namespace Agi diff --git a/engines/agi/preagi.h b/engines/agi/preagi.h index 1a178497ad..14ff483d9f 100644 --- a/engines/agi/preagi.h +++ b/engines/agi/preagi.h @@ -24,20 +24,36 @@ #define AGI_PREAGI_H #include "agi/agi.h" -#include "agi/preagi_common.h" #include "audio/softsynth/pcspk.h" namespace Agi { +// default attributes +#define IDA_DEFAULT 0x0F +#define IDA_DEFAULT_REV 0xF0 + +#define IDI_SND_OSCILLATOR_FREQUENCY 1193180 +#define IDI_SND_TIMER_RESOLUTION 0.0182 + +#define kColorDefault 0x1337 + +#define IDI_MAX_ROW_PIC 20 + +enum SelectionTypes { + kSelYesNo, + kSelNumber, + kSelSpace, + kSelAnyKey, + kSelBackspace +}; + class PreAgiEngine : public AgiBase { int _gameId; protected: - Common::Error go(); void initialize(); -public: void pollTimer() {} int getKeypress() { return 0; } bool isKeypress() { return false; } @@ -49,10 +65,7 @@ public: return _gameId; } - //SoundMgr *_sound; PictureMgr *_picture; - PreAGI_Console *_console; - GUI::Debugger *getDebugger() { return _console; } void clearImageStack() {} void recordImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3, diff --git a/engines/agi/preagi_common.cpp b/engines/agi/preagi_common.cpp deleted file mode 100644 index d437dc08f2..0000000000 --- a/engines/agi/preagi_common.cpp +++ /dev/null @@ -1,205 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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. - * - */ - -#include "agi/preagi.h" -#include "agi/graphics.h" -#include "agi/keyboard.h" - -#include "agi/preagi_common.h" - -#include "common/events.h" - -namespace Agi { - -// Screen functions -void PreAgiEngine::clearScreen(int attr, bool overrideDefault) { - if (overrideDefault) - _defaultColor = attr; - - _gfx->clearScreen((attr & 0xF0) / 0x10); -} - -void PreAgiEngine::clearGfxScreen(int attr) { - _gfx->drawRectangle(0, 0, GFX_WIDTH - 1, IDI_MAX_ROW_PIC * 8 -1, (attr & 0xF0) / 0x10); -} - -// String functions - -void PreAgiEngine::drawStr(int row, int col, int attr, const char *buffer) { - int code; - - if (attr == kColorDefault) - attr = _defaultColor; - - for (int iChar = 0; iChar < (int)strlen(buffer); iChar++) { - code = buffer[iChar]; - - switch (code) { - case '\n': - case 0x8D: - if (++row == 200 / 8) return; - col = 0; - break; - - case '|': - // swap attribute nibbles - break; - - default: - _gfx->putTextCharacter(1, col * 8 , row * 8, static_cast<char>(code), attr & 0x0f, (attr & 0xf0) / 0x10, false, getGameID() == GID_MICKEY ? mickey_fontdata : ibm_fontdata); - - if (++col == 320 / 8) { - col = 0; - if (++row == 200 / 8) return; - } - } - } -} - -void PreAgiEngine::drawStrMiddle(int row, int attr, const char *buffer) { - int col = (25 / 2) - (strlen(buffer) / 2); // 25 = 320 / 8 (maximum column) - drawStr(row, col, attr, buffer); -} - -void PreAgiEngine::clearTextArea() { - int start = IDI_MAX_ROW_PIC; - - if (getGameID() == GID_TROLL) - start = 21; - - for (int row = start; row < 200 / 8; row++) { - clearRow(row); - } -} - -void PreAgiEngine::clearRow(int row) { - drawStr(row, 0, IDA_DEFAULT, " "); // 40 spaces -} - -void PreAgiEngine::printStr(const char* szMsg) { - clearTextArea(); - drawStr(21, 0, IDA_DEFAULT, szMsg); - _gfx->doUpdate(); - _system->updateScreen(); -} - -void PreAgiEngine::XOR80(char *buffer) { - for (size_t i = 0; i < strlen(buffer); i++) - if (buffer[i] & 0x80) - buffer[i] ^= 0x80; -} - -void PreAgiEngine::printStrXOR(char *szMsg) { - XOR80(szMsg); - printStr(szMsg); -} - -// Input functions - -int PreAgiEngine::getSelection(SelectionTypes type) { - Common::Event event; - - while (!shouldQuit()) { - while (_eventMan->pollEvent(event)) { - switch (event.type) { - case Common::EVENT_RTL: - case Common::EVENT_QUIT: - return 0; - case Common::EVENT_RBUTTONUP: - return 0; - case Common::EVENT_LBUTTONUP: - if (type == kSelYesNo || type == kSelAnyKey) - return 1; - case Common::EVENT_KEYDOWN: - if (event.kbd.keycode == Common::KEYCODE_d && (event.kbd.flags & Common::KBD_CTRL) && _console) { - _console->attach(); - _console->onFrame(); - //FIXME: If not cleared, clicking again will start the console - event.kbd.keycode = Common::KEYCODE_INVALID; - event.kbd.flags = 0; - continue; - } - switch (event.kbd.keycode) { - case Common::KEYCODE_y: - if (type == kSelYesNo) - return 1; - case Common::KEYCODE_n: - if (type == kSelYesNo) - return 0; - case Common::KEYCODE_ESCAPE: - if (type == kSelNumber || type == kSelAnyKey) - return 0; - case Common::KEYCODE_1: - case Common::KEYCODE_2: - case Common::KEYCODE_3: - case Common::KEYCODE_4: - case Common::KEYCODE_5: - case Common::KEYCODE_6: - case Common::KEYCODE_7: - case Common::KEYCODE_8: - case Common::KEYCODE_9: - if (type == kSelNumber) - return event.kbd.keycode - Common::KEYCODE_1 + 1; - case Common::KEYCODE_SPACE: - if (type == kSelSpace) - return 1; - case Common::KEYCODE_BACKSPACE: - if (type == kSelBackspace) - return 0; - default: - if (event.kbd.flags & Common::KBD_CTRL) - break; - if (type == kSelYesNo) { - return 2; - } else if (type == kSelNumber) { - return 10; - } else if (type == kSelAnyKey || type == kSelBackspace) { - return 1; - } - } - break; - default: - break; - } - } - _system->updateScreen(); - _system->delayMillis(10); - } - return 0; -} - -void PreAgiEngine::playNote(int16 frequency, int32 length) { - _speakerStream->play(Audio::PCSpeaker::kWaveFormSquare, frequency, length); - waitForTimer(length); -} - -void PreAgiEngine::waitForTimer(int msec_delay) { - uint32 start_time = _system->getMillis(); - - while (_system->getMillis() < start_time + msec_delay) { - _gfx->doUpdate(); - _system->updateScreen(); - _system->delayMillis(10); - } -} - -} diff --git a/engines/agi/preagi_common.h b/engines/agi/preagi_common.h deleted file mode 100644 index a557f69977..0000000000 --- a/engines/agi/preagi_common.h +++ /dev/null @@ -1,51 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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. - * - */ - - - -#ifndef AGI_PREAGI_COMMON_H -#define AGI_PREAGI_COMMON_H - -namespace Agi { - -// default attributes -#define IDA_DEFAULT 0x0F -#define IDA_DEFAULT_REV 0xF0 - -#define IDI_SND_OSCILLATOR_FREQUENCY 1193180 -#define IDI_SND_TIMER_RESOLUTION 0.0182 - -#define kColorDefault 0x1337 - -#define IDI_MAX_ROW_PIC 20 - -enum SelectionTypes { - kSelYesNo, - kSelNumber, - kSelSpace, - kSelAnyKey, - kSelBackspace -}; - -} // End of namespace Agi - -#endif diff --git a/engines/agi/preagi_mickey.cpp b/engines/agi/preagi_mickey.cpp index 21eb780916..6d1eb445a2 100644 --- a/engines/agi/preagi_mickey.cpp +++ b/engines/agi/preagi_mickey.cpp @@ -32,7 +32,7 @@ namespace Agi { -int Mickey::getDat(int iRoom) { +int MickeyEngine::getDat(int iRoom) { if (((iRoom > 0) && (iRoom < 24)) || iRoom == 154 || iRoom == 155) return IDI_MSA_PLANET_EARTH; if ((iRoom >= 30) && (iRoom <= 39)) return IDI_MSA_PLANET_VENUS; if ((iRoom >= 40) && (iRoom <= 69)) return IDI_MSA_PLANET_NEPTUNE; @@ -45,7 +45,7 @@ int Mickey::getDat(int iRoom) { return IDI_MSA_PLANET_SPACESHIP; } -void Mickey::readExe(int ofs, uint8 *buffer, long buflen) { +void MickeyEngine::readExe(int ofs, uint8 *buffer, long buflen) { Common::File infile; if (!infile.open("mickey.exe")) return; @@ -54,11 +54,11 @@ void Mickey::readExe(int ofs, uint8 *buffer, long buflen) { infile.close(); } -void Mickey::getDatFileName(int iRoom, char *szFile) { +void MickeyEngine::getDatFileName(int iRoom, char *szFile) { sprintf(szFile, IDS_MSA_PATH_DAT, IDS_MSA_NAME_DAT[getDat(iRoom)]); } -void Mickey::readDatHdr(char *szFile, MSA_DAT_HEADER *hdr) { +void MickeyEngine::readDatHdr(char *szFile, MSA_DAT_HEADER *hdr) { Common::File infile; if (!infile.open(szFile)) @@ -83,7 +83,7 @@ void Mickey::readDatHdr(char *szFile, MSA_DAT_HEADER *hdr) { infile.close(); } -void Mickey::readOfsData(int offset, int iItem, uint8 *buffer, long buflen) { +void MickeyEngine::readOfsData(int offset, int iItem, uint8 *buffer, long buflen) { uint16 ofs[256]; readExe(offset, buffer, buflen); @@ -97,11 +97,11 @@ void Mickey::readOfsData(int offset, int iItem, uint8 *buffer, long buflen) { // User Interface -bool Mickey::chooseY_N(int ofsPrompt, bool fErrorMsg) { +bool MickeyEngine::chooseY_N(int ofsPrompt, bool fErrorMsg) { printExeStr(ofsPrompt); - while (!_vm->shouldQuit()) { - switch (_vm->getSelection(kSelYesNo)) { + while (!shouldQuit()) { + switch (getSelection(kSelYesNo)) { case 0: return false; case 1: return true; default: @@ -117,15 +117,15 @@ bool Mickey::chooseY_N(int ofsPrompt, bool fErrorMsg) { return false; } -int Mickey::choose1to9(int ofsPrompt) { +int MickeyEngine::choose1to9(int ofsPrompt) { int answer = 0; printExeStr(ofsPrompt); - while (!_vm->shouldQuit()) { - answer = _vm->getSelection(kSelNumber); + while (!shouldQuit()) { + answer = getSelection(kSelNumber); if (answer == 10) { printExeStr(IDO_MSA_PRESS_1_TO_9); - if (_vm->getSelection(kSelAnyKey) == 0) + if (getSelection(kSelAnyKey) == 0) return 0; printExeStr(ofsPrompt); } else return answer; @@ -134,38 +134,38 @@ int Mickey::choose1to9(int ofsPrompt) { return 0; } -void Mickey::printStr(char *buffer) { +void MickeyEngine::printStr(char *buffer) { int pc = 1; int nRows, iCol, iRow; nRows = *buffer + IDI_MSA_ROW_MENU_0; - _vm->clearTextArea(); + clearTextArea(); for (iRow = IDI_MSA_ROW_MENU_0; iRow < nRows; iRow++) { iCol = *(buffer + pc++); - _vm->drawStr(iRow, iCol, IDA_DEFAULT, buffer + pc); + drawStr(iRow, iCol, IDA_DEFAULT, buffer + pc); pc += strlen(buffer + pc) + 1; } // Show the string on screen - _vm->_gfx->doUpdate(); - _vm->_system->updateScreen(); + _gfx->doUpdate(); + _system->updateScreen(); } -void Mickey::printLine(const char *buffer) { - _vm->clearTextArea(); +void MickeyEngine::printLine(const char *buffer) { + clearTextArea(); - _vm->drawStr(22, 18 - strlen(buffer) / 2, IDA_DEFAULT, buffer); + drawStr(22, 18 - strlen(buffer) / 2, IDA_DEFAULT, buffer); // Show the string on screen - _vm->_gfx->doUpdate(); - _vm->_system->updateScreen(); + _gfx->doUpdate(); + _system->updateScreen(); waitAnyKey(true); } -void Mickey::printExeStr(int ofs) { +void MickeyEngine::printExeStr(int ofs) { uint8 buffer[256] = {0}; if (!ofs) @@ -175,7 +175,7 @@ void Mickey::printExeStr(int ofs) { printStr((char *)buffer); } -void Mickey::printExeMsg(int ofs) { +void MickeyEngine::printExeMsg(int ofs) { if (!ofs) return; @@ -183,9 +183,9 @@ void Mickey::printExeMsg(int ofs) { waitAnyKey(true); } -void Mickey::printDatString(int iStr) { +void MickeyEngine::printDatString(int iStr) { char buffer[256]; - int iDat = getDat(_game.iRoom); + int iDat = getDat(_gameStateMickey.iRoom); MSA_DAT_HEADER hdr; char szFile[256] = {0}; @@ -205,7 +205,7 @@ void Mickey::printDatString(int iStr) { printStr(buffer); } -void Mickey::printDesc(int iRoom) { +void MickeyEngine::printDesc(int iRoom) { MSA_DAT_HEADER hdr; char szFile[256] = {0}; @@ -228,20 +228,20 @@ void Mickey::printDesc(int iRoom) { free(buffer); } -bool Mickey::checkMenu() { +bool MickeyEngine::checkMenu() { MSA_MENU menu; int iSel0, iSel1; MSA_DAT_HEADER hdr; char szFile[256] = {0}; Common::File infile; - getDatFileName(_game.iRoom, szFile); + getDatFileName(_gameStateMickey.iRoom, szFile); readDatHdr(szFile, &hdr); if (!infile.open(szFile)) return false; char *buffer = new char[sizeof(MSA_MENU)]; - infile.seek(hdr.ofsRoom[_game.iRoom - 1] + IDI_MSA_OFS_DAT, SEEK_SET); + infile.seek(hdr.ofsRoom[_gameStateMickey.iRoom - 1] + IDI_MSA_OFS_DAT, SEEK_SET); infile.read((uint8 *)buffer, sizeof(MSA_MENU)); infile.close(); @@ -255,7 +255,7 @@ bool Mickey::checkMenu() { return parse(menu.cmd[iSel0].data[iSel1], menu.arg[iSel0].data[iSel1]); } -void Mickey::drawMenu(MSA_MENU menu, int sel0, int sel1) { +void MickeyEngine::drawMenu(MSA_MENU menu, int sel0, int sel1) { int iWord; int iRow; int sel; @@ -263,7 +263,7 @@ void Mickey::drawMenu(MSA_MENU menu, int sel0, int sel1) { // draw menu - _vm->clearTextArea(); + clearTextArea(); for (iRow = 0; iRow < 2; iRow++) { for (iWord = 0; iWord < menu.row[iRow].count; iWord++) { @@ -277,17 +277,17 @@ void Mickey::drawMenu(MSA_MENU menu, int sel0, int sel1) { else attr = IDA_DEFAULT; - _vm->drawStr(IDI_MSA_ROW_MENU_0 + iRow, menu.row[iRow].entry[iWord].x0, + drawStr(IDI_MSA_ROW_MENU_0 + iRow, menu.row[iRow].entry[iWord].x0, attr, (char *)menu.row[iRow].entry[iWord].szText); } } // Menu created, show it on screen - _vm->_gfx->doUpdate(); - _vm->_system->updateScreen(); + _gfx->doUpdate(); + _system->updateScreen(); } -void Mickey::getMouseMenuSelRow(MSA_MENU menu, int *sel0, int *sel1, int iRow, int x, int y) { +void MickeyEngine::getMouseMenuSelRow(MSA_MENU menu, int *sel0, int *sel1, int iRow, int x, int y) { int iWord; int *sel = 0; @@ -314,7 +314,7 @@ void Mickey::getMouseMenuSelRow(MSA_MENU menu, int *sel0, int *sel1, int iRow, i } } -bool Mickey::getMenuSelRow(MSA_MENU menu, int *sel0, int *sel1, int iRow) { +bool MickeyEngine::getMenuSelRow(MSA_MENU menu, int *sel0, int *sel1, int iRow) { Common::Event event; int *sel = 0; int nWords; @@ -357,8 +357,8 @@ bool Mickey::getMenuSelRow(MSA_MENU menu, int *sel0, int *sel1, int iRow) { drawMenu(menu, *sel0, *sel1); - while (!_vm->shouldQuit()) { - while (_vm->_system->getEventManager()->pollEvent(event)) { + while (!shouldQuit()) { + while (_system->getEventManager()->pollEvent(event)) { switch (event.type) { case Common::EVENT_RTL: case Common::EVENT_QUIT: @@ -376,18 +376,18 @@ bool Mickey::getMenuSelRow(MSA_MENU menu, int *sel0, int *sel1, int iRow) { // Change cursor if (northIndex >= 0 && (event.mouse.x >= 20 && event.mouse.x <= (IDI_MSA_PIC_WIDTH + 10) * 2) && (event.mouse.y >= 0 && event.mouse.y <= 10)) { - _vm->_gfx->setCursorPalette(true); + _gfx->setCursorPalette(true); } else if (southIndex >= 0 && (event.mouse.x >= 20 && event.mouse.x <= (IDI_MSA_PIC_WIDTH + 10) * 2) && (event.mouse.y >= IDI_MSA_PIC_HEIGHT - 10 && event.mouse.y <= IDI_MSA_PIC_HEIGHT)) { - _vm->_gfx->setCursorPalette(true); + _gfx->setCursorPalette(true); } else if (westIndex >= 0 && (event.mouse.y >= 0 && event.mouse.y <= IDI_MSA_PIC_HEIGHT) && (event.mouse.x >= 20 && event.mouse.x <= 30)) { - _vm->_gfx->setCursorPalette(true); + _gfx->setCursorPalette(true); } else if (eastIndex >= 0 && (event.mouse.y >= 0 && event.mouse.y <= IDI_MSA_PIC_HEIGHT) && (event.mouse.x >= IDI_MSA_PIC_WIDTH * 2 && event.mouse.x <= (IDI_MSA_PIC_WIDTH + 10) * 2)) { - _vm->_gfx->setCursorPalette(true); + _gfx->setCursorPalette(true); } else { - _vm->_gfx->setCursorPalette(false); + _gfx->setCursorPalette(false); } } break; @@ -400,7 +400,7 @@ bool Mickey::getMenuSelRow(MSA_MENU menu, int *sel0, int *sel1, int iRow) { drawMenu(menu, *sel0, *sel1); - _vm->_gfx->setCursorPalette(false); + _gfx->setCursorPalette(false); _clickToMove = true; } else if (southIndex >= 0 && (event.mouse.x >= 20 && event.mouse.x <= (IDI_MSA_PIC_WIDTH + 10) * 2) && (event.mouse.y >= IDI_MSA_PIC_HEIGHT - 10 && event.mouse.y <= IDI_MSA_PIC_HEIGHT)) { @@ -409,7 +409,7 @@ bool Mickey::getMenuSelRow(MSA_MENU menu, int *sel0, int *sel1, int iRow) { drawMenu(menu, *sel0, *sel1); - _vm->_gfx->setCursorPalette(false); + _gfx->setCursorPalette(false); _clickToMove = true; } else if (westIndex >= 0 && (event.mouse.y >= 0 && event.mouse.y <= IDI_MSA_PIC_HEIGHT) && (event.mouse.x >= 20 && event.mouse.x <= 30)) { @@ -418,7 +418,7 @@ bool Mickey::getMenuSelRow(MSA_MENU menu, int *sel0, int *sel1, int iRow) { drawMenu(menu, *sel0, *sel1); - _vm->_gfx->setCursorPalette(false); + _gfx->setCursorPalette(false); _clickToMove = true; } else if (eastIndex >= 0 && (event.mouse.y >= 0 && event.mouse.y <= IDI_MSA_PIC_HEIGHT) && (event.mouse.x >= IDI_MSA_PIC_WIDTH * 2 && event.mouse.x <= (IDI_MSA_PIC_WIDTH + 10) * 2)) { @@ -427,10 +427,10 @@ bool Mickey::getMenuSelRow(MSA_MENU menu, int *sel0, int *sel1, int iRow) { drawMenu(menu, *sel0, *sel1); - _vm->_gfx->setCursorPalette(false); + _gfx->setCursorPalette(false); _clickToMove = true; } else { - _vm->_gfx->setCursorPalette(false); + _gfx->setCursorPalette(false); } return true; case Common::EVENT_RBUTTONUP: @@ -458,20 +458,20 @@ bool Mickey::getMenuSelRow(MSA_MENU menu, int *sel0, int *sel1, int iRow) { } break; case Common::EVENT_KEYDOWN: - if (event.kbd.keycode == Common::KEYCODE_d && (event.kbd.flags & Common::KBD_CTRL) && _vm->_console) { - _vm->_console->attach(); - _vm->_console->onFrame(); + if (event.kbd.keycode == Common::KEYCODE_d && (event.kbd.flags & Common::KBD_CTRL) && _console) { + _console->attach(); + _console->onFrame(); continue; } switch (event.kbd.keycode) { case Common::KEYCODE_2: // Hidden message - if (_game.iRoom == IDI_MSA_PIC_MERCURY_CAVE_0) { + if (_gameStateMickey.iRoom == IDI_MSA_PIC_MERCURY_CAVE_0) { for (int i = 0; i < 5; i++) { printExeMsg(IDO_MSA_HIDDEN_MSG[i]); } - _vm->clearTextArea(); + clearTextArea(); waitAnyKey(); } break; @@ -489,7 +489,7 @@ bool Mickey::getMenuSelRow(MSA_MENU menu, int *sel0, int *sel1, int iRow) { return false; case Common::KEYCODE_s: - _vm->flipflag(fSoundOn); + flipflag(fSoundOn); break; case Common::KEYCODE_c: inventory(); @@ -552,7 +552,7 @@ bool Mickey::getMenuSelRow(MSA_MENU menu, int *sel0, int *sel1, int iRow) { return false; } -void Mickey::getMenuSel(char *buffer, int *sel0, int *sel1) { +void MickeyEngine::getMenuSel(char *buffer, int *sel0, int *sel1) { MSA_MENU menu; memcpy(&menu, buffer, sizeof(MSA_MENU)); @@ -563,8 +563,8 @@ void Mickey::getMenuSel(char *buffer, int *sel0, int *sel1) { // Show the mouse cursor for the menu CursorMan.showMouse(true); - while (!_vm->shouldQuit()) { - while (!_vm->shouldQuit()) { + while (!shouldQuit()) { + while (!shouldQuit()) { if (getMenuSelRow(menu, sel0, sel1, 0)) { if (_clickToMove) break; @@ -586,7 +586,7 @@ void Mickey::getMenuSel(char *buffer, int *sel0, int *sel1) { CursorMan.showMouse(false); } -void Mickey::centerMenu(MSA_MENU *menu) { +void MickeyEngine::centerMenu(MSA_MENU *menu) { int iWord; int iRow; int w, x; @@ -606,19 +606,19 @@ void Mickey::centerMenu(MSA_MENU *menu) { } } -void Mickey::patchMenu(MSA_MENU *menu) { +void MickeyEngine::patchMenu(MSA_MENU *menu) { uint8 buffer[512]; uint8 menubuf[sizeof(MSA_MENU)]; int nPatches; int pBuf = 0; // change planet name in ship airlock menu - if (_game.iRoom == IDI_MSA_PIC_SHIP_AIRLOCK) { - strcpy((char *)menu->row[1].entry[2].szText, IDS_MSA_NAME_PLANET[_game.iPlanet]); + if (_gameStateMickey.iRoom == IDI_MSA_PIC_SHIP_AIRLOCK) { + strcpy((char *)menu->row[1].entry[2].szText, IDS_MSA_NAME_PLANET[_gameStateMickey.iPlanet]); } // exit if fix unnecessary - if (!_game.iRmMenu[_game.iRoom]) { + if (!_gameStateMickey.iRmMenu[_gameStateMickey.iRoom]) { centerMenu(menu); return; } @@ -629,7 +629,7 @@ void Mickey::patchMenu(MSA_MENU *menu) { // read patches readOfsData( IDOFS_MSA_MENU_PATCHES, - _game.nRmMenu[_game.iRoom] + _game.iRmMenu[_game.iRoom] - 1, + _gameStateMickey.nRmMenu[_gameStateMickey.iRoom] + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] - 1, buffer, sizeof(buffer) ); @@ -652,24 +652,24 @@ void Mickey::patchMenu(MSA_MENU *menu) { centerMenu(menu); } -void Mickey::printDatMessage(int iStr) { +void MickeyEngine::printDatMessage(int iStr) { printDatString(iStr); waitAnyKey(true); } // Sound -void Mickey::playNote(MSA_SND_NOTE note) { +void MickeyEngine::playNote(MSA_SND_NOTE note) { if (!note.counter) { // Pause - _vm->_system->delayMillis((uint) (note.length / IDI_SND_TIMER_RESOLUTION)); + _system->delayMillis((uint) (note.length / IDI_SND_TIMER_RESOLUTION)); } else { - _vm->playNote(IDI_SND_OSCILLATOR_FREQUENCY / note.counter, (int32) (note.length / IDI_SND_TIMER_RESOLUTION)); + PreAgiEngine::playNote(IDI_SND_OSCILLATOR_FREQUENCY / note.counter, (int32) (note.length / IDI_SND_TIMER_RESOLUTION)); } } -void Mickey::playSound(ENUM_MSA_SOUND iSound) { - if (!_vm->getflag(fSoundOn)) +void MickeyEngine::playSound(ENUM_MSA_SOUND iSound) { + if (!getflag(fSoundOn)) return; Common::Event event; @@ -680,7 +680,7 @@ void Mickey::playSound(ENUM_MSA_SOUND iSound) { switch (iSound) { case IDI_MSA_SND_XL30: for (int iNote = 0; iNote < 6; iNote++) { - note.counter = _vm->rnd(59600) + 59; + note.counter = rnd(59600) + 59; note.length = 4; playNote(note); } @@ -698,7 +698,7 @@ void Mickey::playSound(ENUM_MSA_SOUND iSound) { pBuf += 3; if (iSound == IDI_MSA_SND_THEME) { - while (_vm->_system->getEventManager()->pollEvent(event)) { + while (_system->getEventManager()->pollEvent(event)) { switch (event.type) { case Common::EVENT_RTL: case Common::EVENT_QUIT: @@ -722,7 +722,7 @@ void Mickey::playSound(ENUM_MSA_SOUND iSound) { // Graphics -void Mickey::drawObj(ENUM_MSA_OBJECT iObj, int x0, int y0) { +void MickeyEngine::drawObj(ENUM_MSA_OBJECT iObj, int x0, int y0) { char szFile[255] = {0}; sprintf(szFile, IDS_MSA_PATH_OBJ, IDS_MSA_NAME_OBJ[iObj]); @@ -736,15 +736,15 @@ void Mickey::drawObj(ENUM_MSA_OBJECT iObj, int x0, int y0) { file.close(); if (iObj == IDI_MSA_OBJECT_CRYSTAL) - _vm->_picture->setPictureFlags(kPicFStep); + _picture->setPictureFlags(kPicFStep); - _vm->_picture->setOffset(x0, y0); - _vm->_picture->decodePicture(buffer, size, false, IDI_MSA_PIC_WIDTH, IDI_MSA_PIC_HEIGHT); - _vm->_picture->setOffset(0, 0); - _vm->_picture->showPic(10, 0, IDI_MSA_PIC_WIDTH, IDI_MSA_PIC_HEIGHT); + _picture->setOffset(x0, y0); + _picture->decodePicture(buffer, size, false, IDI_MSA_PIC_WIDTH, IDI_MSA_PIC_HEIGHT); + _picture->setOffset(0, 0); + _picture->showPic(10, 0, IDI_MSA_PIC_WIDTH, IDI_MSA_PIC_HEIGHT); } -void Mickey::drawPic(int iPic) { +void MickeyEngine::drawPic(int iPic) { char szFile[255] = {0}; sprintf(szFile, IDS_MSA_PATH_PIC, iPic); @@ -758,16 +758,16 @@ void Mickey::drawPic(int iPic) { file.close(); // Note that decodePicture clears the screen - _vm->_picture->decodePicture(buffer, size, true, IDI_MSA_PIC_WIDTH, IDI_MSA_PIC_HEIGHT); - _vm->_picture->showPic(10, 0, IDI_MSA_PIC_WIDTH, IDI_MSA_PIC_HEIGHT); + _picture->decodePicture(buffer, size, true, IDI_MSA_PIC_WIDTH, IDI_MSA_PIC_HEIGHT); + _picture->showPic(10, 0, IDI_MSA_PIC_WIDTH, IDI_MSA_PIC_HEIGHT); } -void Mickey::drawRoomAnimation() { +void MickeyEngine::drawRoomAnimation() { uint8 objLight[] = { 0xF0, 1, 0xF9, 2, 43, 45, 0xFF }; - switch (_game.iRoom) { + switch (_gameStateMickey.iRoom) { case IDI_MSA_PIC_EARTH_SHIP: case IDI_MSA_PIC_VENUS_SHIP: case IDI_MSA_PIC_NEPTUNE_SHIP: @@ -790,26 +790,26 @@ void Mickey::drawRoomAnimation() { uint8 iColor = 0; - _vm->_picture->setPattern(2, 0); + _picture->setPattern(2, 0); for (int i = 0; i < 12; i++) { - iColor = _game.nFrame + i; + iColor = _gameStateMickey.nFrame + i; if (iColor > 15) iColor -= 15; objLight[1] = iColor; objLight[4] += 7; - _vm->_picture->setPictureData(objLight); - _vm->_picture->setPictureFlags(kPicFCircle); - _vm->_picture->drawPicture(); + _picture->setPictureData(objLight); + _picture->setPictureFlags(kPicFCircle); + _picture->drawPicture(); } - _vm->_picture->showPic(10, 0, IDI_MSA_PIC_WIDTH, IDI_MSA_PIC_HEIGHT); + _picture->showPic(10, 0, IDI_MSA_PIC_WIDTH, IDI_MSA_PIC_HEIGHT); - _game.nFrame--; - if (_game.nFrame < 0) - _game.nFrame = 15; + _gameStateMickey.nFrame--; + if (_gameStateMickey.nFrame < 0) + _gameStateMickey.nFrame = 15; playSound(IDI_MSA_SND_PRESS_BLUE); } @@ -818,12 +818,12 @@ void Mickey::drawRoomAnimation() { case IDI_MSA_PIC_SHIP_CONTROLS: // draw XL30 screen - if (_game.fAnimXL30) { - if (_game.nFrame > 5) - _game.nFrame = 0; + if (_gameStateMickey.fAnimXL30) { + if (_gameStateMickey.nFrame > 5) + _gameStateMickey.nFrame = 0; - drawObj((ENUM_MSA_OBJECT)(IDI_MSA_OBJECT_XL31 + _game.nFrame), 0, 4); - _game.nFrame++; + drawObj((ENUM_MSA_OBJECT)(IDI_MSA_OBJECT_XL31 + _gameStateMickey.nFrame), 0, 4); + _gameStateMickey.nFrame++; }; break; @@ -831,17 +831,17 @@ void Mickey::drawRoomAnimation() { default: // draw crystal - if (_game.iRoom == IDI_MSA_XTAL_ROOM_XY[_game.iPlanet][0]) { - if (!_game.fHasXtal) { - switch (_game.iPlanet) { + if (_gameStateMickey.iRoom == IDI_MSA_XTAL_ROOM_XY[_gameStateMickey.iPlanet][0]) { + if (!_gameStateMickey.fHasXtal) { + switch (_gameStateMickey.iPlanet) { case IDI_MSA_PLANET_VENUS: - if (_game.iRmMenu[_game.iRoom] != 2) + if (_gameStateMickey.iRmMenu[_gameStateMickey.iRoom] != 2) break; default: drawObj( IDI_MSA_OBJECT_CRYSTAL, - IDI_MSA_XTAL_ROOM_XY[_game.iPlanet][1], - IDI_MSA_XTAL_ROOM_XY[_game.iPlanet][2] + IDI_MSA_XTAL_ROOM_XY[_gameStateMickey.iPlanet][1], + IDI_MSA_XTAL_ROOM_XY[_gameStateMickey.iPlanet][2] ); break; } @@ -852,36 +852,36 @@ void Mickey::drawRoomAnimation() { } } -void Mickey::drawRoom() { +void MickeyEngine::drawRoom() { uint8 buffer[256]; int pBuf = 0; int nObjs; // Draw room picture - if (_game.iRoom == IDI_MSA_PIC_TITLE) { + if (_gameStateMickey.iRoom == IDI_MSA_PIC_TITLE) { drawPic(IDI_MSA_PIC_TITLE); } else { - drawPic(_game.iRmPic[_game.iRoom]); + drawPic(_gameStateMickey.iRmPic[_gameStateMickey.iRoom]); - if (_game.iRoom == IDI_MSA_PIC_SHIP_CONTROLS) { + if (_gameStateMickey.iRoom == IDI_MSA_PIC_SHIP_CONTROLS) { // Draw ship control room window - if (_game.fFlying) { + if (_gameStateMickey.fFlying) { drawObj(IDI_MSA_OBJECT_W_SPACE, 0, 0); } else { - drawObj((ENUM_MSA_OBJECT)(IDI_MSA_OBJECT_W_EARTH + _game.iPlanet), 0, 1); + drawObj((ENUM_MSA_OBJECT)(IDI_MSA_OBJECT_W_EARTH + _gameStateMickey.iPlanet), 0, 1); } } } // Draw room objects - if (_game.iRoom >= IDI_MSA_MAX_PIC_ROOM) { + if (_gameStateMickey.iRoom >= IDI_MSA_MAX_PIC_ROOM) { drawRoomAnimation(); return; } - if (_game.iRmObj[_game.iRoom] != IDI_MSA_OBJECT_NONE) { + if (_gameStateMickey.iRmObj[_gameStateMickey.iRoom] != IDI_MSA_OBJECT_NONE) { readOfsData(IDO_MSA_ROOM_OBJECT_XY_OFFSETS, - _game.iRmObj[_game.iRoom], buffer, sizeof(buffer)); + _gameStateMickey.iRmObj[_gameStateMickey.iRoom], buffer, sizeof(buffer)); nObjs = buffer[pBuf++]; @@ -914,7 +914,7 @@ const uint8 colorBCG[16][2] = { { 0xFF, 0xFF } // F (white, white) }; -void Mickey::drawLogo() { +void MickeyEngine::drawLogo() { // TODO: clean this up and make it work properly, the logo is drawn way off to the right #if 0 char szFile[256] = {0}; @@ -937,7 +937,7 @@ void Mickey::drawLogo() { // draw logo bitmap memcpy(bitmap, buffer, sizeof(bitmap)); - _vm->_picture->setDimensions(w, h); + _picture->setDimensions(w, h); // Show BCG picture for (int y = 0; y < h; y++) { @@ -947,40 +947,40 @@ void Mickey::drawLogo() { color3 = colorBCG[ bitmap[y][x] & 0x0f][0]; // foreground color4 = colorBCG[ bitmap[y][x] & 0x0f][1]; // foreground - _vm->_picture->putPixel(x * 4 - xoffset, y, color); - _vm->_picture->putPixel(x * 4 + 1 - xoffset, y, color2); - _vm->_picture->putPixel(x * 4 + 2 - xoffset, y, color3); - _vm->_picture->putPixel(x * 4 + 3 - xoffset, y, color4); - _vm->_picture->putPixel(x * 4 - xoffset, y + 1, color); - _vm->_picture->putPixel(x * 4 + 1 - xoffset, y + 1, color2); - _vm->_picture->putPixel(x * 4 + 2 - xoffset, y + 1, color3); - _vm->_picture->putPixel(x * 4 + 3 - xoffset, y + 1, color4); + _picture->putPixel(x * 4 - xoffset, y, color); + _picture->putPixel(x * 4 + 1 - xoffset, y, color2); + _picture->putPixel(x * 4 + 2 - xoffset, y, color3); + _picture->putPixel(x * 4 + 3 - xoffset, y, color4); + _picture->putPixel(x * 4 - xoffset, y + 1, color); + _picture->putPixel(x * 4 + 1 - xoffset, y + 1, color2); + _picture->putPixel(x * 4 + 2 - xoffset, y + 1, color3); + _picture->putPixel(x * 4 + 3 - xoffset, y + 1, color4); } } - _vm->_picture->showPic(10, 10, w, h); + _picture->showPic(10, 10, w, h); delete[] buffer; #endif } -void Mickey::animate() { - _vm->_system->delayMillis(IDI_MSA_ANIM_DELAY); +void MickeyEngine::animate() { + _system->delayMillis(IDI_MSA_ANIM_DELAY); drawRoomAnimation(); } -void Mickey::printRoomDesc() { +void MickeyEngine::printRoomDesc() { // print room description - printDesc(_game.iRoom); + printDesc(_gameStateMickey.iRoom); waitAnyKey(true); // print extended room description - if (_game.oRmTxt[_game.iRoom]) { - printExeMsg(_game.oRmTxt[_game.iRoom] + IDI_MSA_OFS_EXE); + if (_gameStateMickey.oRmTxt[_gameStateMickey.iRoom]) { + printExeMsg(_gameStateMickey.oRmTxt[_gameStateMickey.iRoom] + IDI_MSA_OFS_EXE); } } -bool Mickey::loadGame() { +bool MickeyEngine::loadGame() { Common::InSaveFile *infile; char szFile[256] = {0}; bool diskerror = true; @@ -994,15 +994,15 @@ bool Mickey::loadGame() { return false; // load game - sprintf(szFile, "%s.s%02d", _vm->getTargetName().c_str(), sel); - if (!(infile = _vm->getSaveFileMan()->openForLoading(szFile))) { + sprintf(szFile, "%s.s%02d", getTargetName().c_str(), sel); + if (!(infile = getSaveFileMan()->openForLoading(szFile))) { printLine("PLEASE CHECK THE DISK DRIVE"); - if (_vm->getSelection(kSelAnyKey) == 0) + if (getSelection(kSelAnyKey) == 0) return false; } else { if (infile->readUint32BE() != MKTAG('M','I','C','K')) { - warning("Mickey::loadGame wrong save game format"); + warning("MickeyEngine::loadGame wrong save game format"); return false; } @@ -1015,61 +1015,61 @@ bool Mickey::loadGame() { if (saveVersion != MSA_SAVEGAME_VERSION) warning("Old save game version (%d, current version is %d). Will try and read anyway, but don't be surprised if bad things happen", saveVersion, MSA_SAVEGAME_VERSION); - _game.iRoom = infile->readByte(); - _game.iPlanet = infile->readByte(); - _game.iDisk = infile->readByte(); + _gameStateMickey.iRoom = infile->readByte(); + _gameStateMickey.iPlanet = infile->readByte(); + _gameStateMickey.iDisk = infile->readByte(); - _game.nAir = infile->readByte(); - _game.nButtons = infile->readByte(); - _game.nRocks = infile->readByte(); + _gameStateMickey.nAir = infile->readByte(); + _gameStateMickey.nButtons = infile->readByte(); + _gameStateMickey.nRocks = infile->readByte(); - _game.nXtals = infile->readByte(); + _gameStateMickey.nXtals = infile->readByte(); for (i = 0; i < IDI_MSA_MAX_DAT; i++) - _game.iPlanetXtal[i] = infile->readByte(); + _gameStateMickey.iPlanetXtal[i] = infile->readByte(); for (i = 0; i < IDI_MSA_MAX_PLANET; i++) - _game.iClue[i] = infile->readUint16LE(); + _gameStateMickey.iClue[i] = infile->readUint16LE(); - infile->read(_game.szAddr, IDI_MSA_MAX_BUTTON + 1); + infile->read(_gameStateMickey.szAddr, IDI_MSA_MAX_BUTTON + 1); - _game.fHasXtal = infile->readByte() == 1; - _game.fIntro = infile->readByte() == 1; - _game.fSuit = infile->readByte() == 1; - _game.fShipDoorOpen = infile->readByte() == 1; - _game.fFlying = infile->readByte() == 1; - _game.fStoryShown = infile->readByte() == 1; - _game.fPlanetsInitialized = infile->readByte() == 1; - _game.fTempleDoorOpen = infile->readByte() == 1; - _game.fAnimXL30 = infile->readByte() == 1; + _gameStateMickey.fHasXtal = infile->readByte() == 1; + _gameStateMickey.fIntro = infile->readByte() == 1; + _gameStateMickey.fSuit = infile->readByte() == 1; + _gameStateMickey.fShipDoorOpen = infile->readByte() == 1; + _gameStateMickey.fFlying = infile->readByte() == 1; + _gameStateMickey.fStoryShown = infile->readByte() == 1; + _gameStateMickey.fPlanetsInitialized = infile->readByte() == 1; + _gameStateMickey.fTempleDoorOpen = infile->readByte() == 1; + _gameStateMickey.fAnimXL30 = infile->readByte() == 1; for (i = 0; i < IDI_MSA_MAX_ITEM; i++) - _game.fItem[i] = infile->readByte() == 1; + _gameStateMickey.fItem[i] = infile->readByte() == 1; for (i = 0; i < IDI_MSA_MAX_ITEM; i++) - _game.fItemUsed[i] = infile->readByte() == 1; + _gameStateMickey.fItemUsed[i] = infile->readByte() == 1; for (i = 0; i < IDI_MSA_MAX_ITEM; i++) - _game.iItem[i] = infile->readSByte(); + _gameStateMickey.iItem[i] = infile->readSByte(); - _game.nItems = infile->readByte(); + _gameStateMickey.nItems = infile->readByte(); for (i = 0; i < IDI_MSA_MAX_ROOM; i++) - _game.iRmObj[i] = infile->readSByte(); + _gameStateMickey.iRmObj[i] = infile->readSByte(); for (i = 0; i < IDI_MSA_MAX_ROOM; i++) - _game.iRmPic[i] = infile->readByte(); + _gameStateMickey.iRmPic[i] = infile->readByte(); for (i = 0; i < IDI_MSA_MAX_ROOM; i++) - _game.oRmTxt[i] = infile->readUint16LE(); + _gameStateMickey.oRmTxt[i] = infile->readUint16LE(); for (i = 0; i < IDI_MSA_MAX_ROOM; i++) - _game.iRmMenu[i] = infile->readByte(); + _gameStateMickey.iRmMenu[i] = infile->readByte(); for (i = 0; i < IDI_MSA_MAX_ROOM; i++) - _game.nRmMenu[i] = infile->readByte(); + _gameStateMickey.nRmMenu[i] = infile->readByte(); - _game.nFrame = infile->readSByte(); + _gameStateMickey.nFrame = infile->readSByte(); diskerror = false; delete infile; @@ -1080,7 +1080,7 @@ bool Mickey::loadGame() { return true; } -void Mickey::saveGame() { +void MickeyEngine::saveGame() { Common::OutSaveFile* outfile; char szFile[256] = {0}; bool diskerror = true; @@ -1094,7 +1094,7 @@ void Mickey::saveGame() { else printExeStr(IDO_MSA_SAVE_GAME[2]); - if (_vm->getSelection(kSelAnyKey) == 0) + if (getSelection(kSelAnyKey) == 0) return; while (diskerror) { @@ -1107,75 +1107,75 @@ void Mickey::saveGame() { else printExeStr(IDO_MSA_SAVE_GAME[4]); - if (_vm->getSelection(kSelAnyKey) == 0) + if (getSelection(kSelAnyKey) == 0) return; // save game - sprintf(szFile, "%s.s%02d", _vm->getTargetName().c_str(), sel); - if (!(outfile = _vm->getSaveFileMan()->openForSaving(szFile))) { + sprintf(szFile, "%s.s%02d", getTargetName().c_str(), sel); + if (!(outfile = getSaveFileMan()->openForSaving(szFile))) { printLine("PLEASE CHECK THE DISK DRIVE"); - if (_vm->getSelection(kSelAnyKey) == 0) + if (getSelection(kSelAnyKey) == 0) return; } else { outfile->writeUint32BE(MKTAG('M','I','C','K')); // header outfile->writeByte(MSA_SAVEGAME_VERSION); - outfile->writeByte(_game.iRoom); - outfile->writeByte(_game.iPlanet); - outfile->writeByte(_game.iDisk); + outfile->writeByte(_gameStateMickey.iRoom); + outfile->writeByte(_gameStateMickey.iPlanet); + outfile->writeByte(_gameStateMickey.iDisk); - outfile->writeByte(_game.nAir); - outfile->writeByte(_game.nButtons); - outfile->writeByte(_game.nRocks); + outfile->writeByte(_gameStateMickey.nAir); + outfile->writeByte(_gameStateMickey.nButtons); + outfile->writeByte(_gameStateMickey.nRocks); - outfile->writeByte(_game.nXtals); + outfile->writeByte(_gameStateMickey.nXtals); for (i = 0; i < IDI_MSA_MAX_DAT; i++) - outfile->writeByte(_game.iPlanetXtal[i]); + outfile->writeByte(_gameStateMickey.iPlanetXtal[i]); for (i = 0; i < IDI_MSA_MAX_PLANET; i++) - outfile->writeUint16LE(_game.iClue[i]); + outfile->writeUint16LE(_gameStateMickey.iClue[i]); - outfile->write(_game.szAddr, IDI_MSA_MAX_BUTTON + 1); + outfile->write(_gameStateMickey.szAddr, IDI_MSA_MAX_BUTTON + 1); - outfile->writeByte(_game.fHasXtal ? 1 : 0); - outfile->writeByte(_game.fIntro ? 1 : 0); - outfile->writeByte(_game.fSuit ? 1 : 0); - outfile->writeByte(_game.fShipDoorOpen ? 1 : 0); - outfile->writeByte(_game.fFlying ? 1 : 0); - outfile->writeByte(_game.fStoryShown ? 1 : 0); - outfile->writeByte(_game.fPlanetsInitialized ? 1 : 0); - outfile->writeByte(_game.fTempleDoorOpen ? 1 : 0); - outfile->writeByte(_game.fAnimXL30 ? 1 : 0); + outfile->writeByte(_gameStateMickey.fHasXtal ? 1 : 0); + outfile->writeByte(_gameStateMickey.fIntro ? 1 : 0); + outfile->writeByte(_gameStateMickey.fSuit ? 1 : 0); + outfile->writeByte(_gameStateMickey.fShipDoorOpen ? 1 : 0); + outfile->writeByte(_gameStateMickey.fFlying ? 1 : 0); + outfile->writeByte(_gameStateMickey.fStoryShown ? 1 : 0); + outfile->writeByte(_gameStateMickey.fPlanetsInitialized ? 1 : 0); + outfile->writeByte(_gameStateMickey.fTempleDoorOpen ? 1 : 0); + outfile->writeByte(_gameStateMickey.fAnimXL30 ? 1 : 0); for (i = 0; i < IDI_MSA_MAX_ITEM; i++) - outfile->writeByte(_game.fItem[i] ? 1 : 0); + outfile->writeByte(_gameStateMickey.fItem[i] ? 1 : 0); for (i = 0; i < IDI_MSA_MAX_ITEM; i++) - outfile->writeByte(_game.fItemUsed[i] ? 1 : 0); + outfile->writeByte(_gameStateMickey.fItemUsed[i] ? 1 : 0); for (i = 0; i < IDI_MSA_MAX_ITEM; i++) - outfile->writeSByte(_game.iItem[i]); + outfile->writeSByte(_gameStateMickey.iItem[i]); - outfile->writeByte(_game.nItems); + outfile->writeByte(_gameStateMickey.nItems); for (i = 0; i < IDI_MSA_MAX_ROOM; i++) - outfile->writeSByte(_game.iRmObj[i]); + outfile->writeSByte(_gameStateMickey.iRmObj[i]); for (i = 0; i < IDI_MSA_MAX_ROOM; i++) - outfile->writeByte(_game.iRmPic[i]); + outfile->writeByte(_gameStateMickey.iRmPic[i]); for (i = 0; i < IDI_MSA_MAX_ROOM; i++) - outfile->writeUint16LE(_game.oRmTxt[i]); + outfile->writeUint16LE(_gameStateMickey.oRmTxt[i]); for (i = 0; i < IDI_MSA_MAX_ROOM; i++) - outfile->writeByte(_game.iRmMenu[i]); + outfile->writeByte(_gameStateMickey.iRmMenu[i]); for (i = 0; i < IDI_MSA_MAX_ROOM; i++) - outfile->writeByte(_game.nRmMenu[i]); + outfile->writeByte(_gameStateMickey.nRmMenu[i]); - outfile->writeSByte(_game.nFrame); + outfile->writeSByte(_gameStateMickey.nFrame); outfile->finalize(); @@ -1190,14 +1190,14 @@ void Mickey::saveGame() { printExeMsg(IDO_MSA_SAVE_GAME[6]); } -void Mickey::showPlanetInfo() { +void MickeyEngine::showPlanetInfo() { for (int i = 0; i < 4; i++) { - printExeStr(IDO_MSA_PLANET_INFO[_game.iPlanet][i]); + printExeStr(IDO_MSA_PLANET_INFO[_gameStateMickey.iPlanet][i]); waitAnyKey(); } } -void Mickey::printStory() { +void MickeyEngine::printStory() { char buffer[IDI_MSA_LEN_STORY] = {0}; char szLine[41] = {0}; int iRow; @@ -1205,37 +1205,37 @@ void Mickey::printStory() { readExe(IDO_MSA_GAME_STORY, (uint8 *)buffer, sizeof(buffer)); - _vm->clearScreen(IDA_DEFAULT); + clearScreen(IDA_DEFAULT); for (iRow = 0; iRow < 25; iRow++) { strcpy(szLine, buffer + pBuf); - _vm->drawStr(iRow, 0, IDA_DEFAULT, szLine); + drawStr(iRow, 0, IDA_DEFAULT, szLine); pBuf += strlen(szLine) + 1; } waitAnyKey(); - _vm->clearScreen(IDA_DEFAULT); + clearScreen(IDA_DEFAULT); for (iRow = 0; iRow < 21; iRow++) { strcpy(szLine, buffer + pBuf); - _vm->drawStr(iRow, 0, IDA_DEFAULT, szLine); + drawStr(iRow, 0, IDA_DEFAULT, szLine); pBuf += strlen(szLine) + 1; } waitAnyKey(); //Set back to black - _vm->_gfx->clearScreen(0); - _vm->_gfx->doUpdate(); + _gfx->clearScreen(0); + _gfx->doUpdate(); drawRoom(); - _game.fStoryShown = true; + _gameStateMickey.fStoryShown = true; } -int Mickey::getPlanet() { - if (!_game.nButtons) +int MickeyEngine::getPlanet() { + if (!_gameStateMickey.nButtons) return -1; for (int iPlanet = 0; iPlanet < IDI_MSA_MAX_DAT - 1; iPlanet++) { - if (!strcmp(IDS_MSA_ADDR_PLANET[iPlanet], _game.szAddr)) { + if (!strcmp(IDS_MSA_ADDR_PLANET[iPlanet], _gameStateMickey.szAddr)) { return iPlanet; } } @@ -1243,49 +1243,49 @@ int Mickey::getPlanet() { return -1; } -void Mickey::pressOB(int iButton) { +void MickeyEngine::pressOB(int iButton) { char szButtons[12] = {0}; // check if too many buttons pressed - if (_game.nButtons == IDI_MSA_MAX_BUTTON) { - _game.nButtons = 0; - memset(_game.szAddr, 0, sizeof(_game.szAddr)); + if (_gameStateMickey.nButtons == IDI_MSA_MAX_BUTTON) { + _gameStateMickey.nButtons = 0; + memset(_gameStateMickey.szAddr, 0, sizeof(_gameStateMickey.szAddr)); printExeMsg(IDO_MSA_TOO_MANY_BUTTONS_PRESSED); return; } // add button press to address - _game.nButtons++; - _game.szAddr[_game.nButtons - 1] = (char)iButton; + _gameStateMickey.nButtons++; + _gameStateMickey.szAddr[_gameStateMickey.nButtons - 1] = (char)iButton; // format buttons string for (int i = 0; i < IDI_MSA_MAX_BUTTON; i++) { - szButtons[i * 2] = _game.szAddr[i]; - if (_game.szAddr[i + 1]) szButtons[(i * 2) + 1] = ','; + szButtons[i * 2] = _gameStateMickey.szAddr[i]; + if (_gameStateMickey.szAddr[i + 1]) szButtons[(i * 2) + 1] = ','; } // print pressed buttons printLine("MICKEY HAS PRESSED: "); - _vm->drawStr(20, 22, IDA_DEFAULT, szButtons); + drawStr(20, 22, IDA_DEFAULT, szButtons); waitAnyKey(); } -void Mickey::insertDisk(int iDisk) { - _vm->clearTextArea(); - _vm->drawStr(IDI_MSA_ROW_INSERT_DISK, IDI_MSA_COL_INSERT_DISK, IDA_DEFAULT, (const char *)IDS_MSA_INSERT_DISK[iDisk]); +void MickeyEngine::insertDisk(int iDisk) { + clearTextArea(); + drawStr(IDI_MSA_ROW_INSERT_DISK, IDI_MSA_COL_INSERT_DISK, IDA_DEFAULT, (const char *)IDS_MSA_INSERT_DISK[iDisk]); waitAnyKey(); } -void Mickey::gameOver() { +void MickeyEngine::gameOver() { // We shouldn't run the game over segment if we're quitting. - if (_vm->shouldQuit()) + if (shouldQuit()) return; drawPic(IDI_MSA_PIC_EARTH_SHIP_LEAVING); printExeMsg(IDO_MSA_GAME_OVER[3]); playSound(IDI_MSA_SND_GAME_OVER); - if (_game.fItemUsed[IDI_MSA_ITEM_LETTER]) { + if (_gameStateMickey.fItemUsed[IDI_MSA_ITEM_LETTER]) { drawPic(IDI_MSA_PIC_EARTH_MINNIE); printExeMsg(IDO_MSA_GAME_OVER[4]); printExeMsg(IDO_MSA_GAME_OVER[5]); @@ -1297,74 +1297,74 @@ void Mickey::gameOver() { waitAnyKey(); } -void Mickey::flipSwitch() { - if (_game.fHasXtal || _game.nXtals) { - if (!_game.fStoryShown) +void MickeyEngine::flipSwitch() { + if (_gameStateMickey.fHasXtal || _gameStateMickey.nXtals) { + if (!_gameStateMickey.fStoryShown) printStory(); // Initialize planet data - if (!_game.fPlanetsInitialized) { + if (!_gameStateMickey.fPlanetsInitialized) { int iHint = 0; int iPlanet = 0; - memset(_game.iPlanetXtal, 0, sizeof(_game.iPlanetXtal)); - memset(_game.iClue, 0, sizeof(_game.iClue)); + memset(_gameStateMickey.iPlanetXtal, 0, sizeof(_gameStateMickey.iPlanetXtal)); + memset(_gameStateMickey.iClue, 0, sizeof(_gameStateMickey.iClue)); - _game.iPlanetXtal[0] = IDI_MSA_PLANET_EARTH; - _game.iPlanetXtal[8] = IDI_MSA_PLANET_URANUS; + _gameStateMickey.iPlanetXtal[0] = IDI_MSA_PLANET_EARTH; + _gameStateMickey.iPlanetXtal[8] = IDI_MSA_PLANET_URANUS; for (int i = 1; i < IDI_MSA_MAX_PLANET; i++) { if (i < 8) { do { // Earth (planet 0) and Uranus (planet 8) are excluded - iPlanet = _vm->rnd(IDI_MSA_MAX_PLANET - 2); + iPlanet = rnd(IDI_MSA_MAX_PLANET - 2); } while (planetIsAlreadyAssigned(iPlanet)); } else { iPlanet = IDI_MSA_PLANET_URANUS; // Uranus is always last } - _game.iPlanetXtal[i] = iPlanet; - iHint = _vm->rnd(5) - 1; // clues are 0-4 - _game.iClue[i] = IDO_MSA_NEXT_PIECE[iPlanet][iHint]; + _gameStateMickey.iPlanetXtal[i] = iPlanet; + iHint = rnd(5) - 1; // clues are 0-4 + _gameStateMickey.iClue[i] = IDO_MSA_NEXT_PIECE[iPlanet][iHint]; } - _game.fPlanetsInitialized = true; + _gameStateMickey.fPlanetsInitialized = true; } // activate screen animation - _game.fAnimXL30 = true; + _gameStateMickey.fAnimXL30 = true; - _vm->clearTextArea(); + clearTextArea(); playSound(IDI_MSA_SND_XL30); printExeMsg(IDO_MSA_XL30_SPEAKING); - if (_game.fHasXtal) { - _game.fHasXtal = false; + if (_gameStateMickey.fHasXtal) { + _gameStateMickey.fHasXtal = false; printExeMsg(IDO_MSA_CRYSTAL_PIECE_FOUND); } - if (_game.nXtals == IDI_MSA_MAX_PLANET) { + if (_gameStateMickey.nXtals == IDI_MSA_MAX_PLANET) { printExeMsg(IDO_MSA_GAME_OVER[0]); printExeMsg(IDO_MSA_GAME_OVER[1]); printExeMsg(IDO_MSA_GAME_OVER[2]); #if 0 // DEBUG - strcpy(_game.szAddr, (char *)IDS_MSA_ADDR_PLANET[IDI_MSA_PLANET_EARTH]); - _game.nButtons = strlen(_game.szAddr); + strcpy(_gameStateMickey.szAddr, (char *)IDS_MSA_ADDR_PLANET[IDI_MSA_PLANET_EARTH]); + _gameStateMickey.nButtons = strlen(_gameStateMickey.szAddr); #endif } else { - printExeStr(_game.iClue[_game.nXtals]); + printExeStr(_gameStateMickey.iClue[_gameStateMickey.nXtals]); #if 0 // DEBUG - _vm->drawStr(24, 12, IDA_DEFAULT, (char *)IDS_MSA_NAME_PLANET_2[_game.iPlanetXtal[_game.nXtals]]); - _vm->drawStr(24, 22, IDA_DEFAULT, (char *)IDS_MSA_ADDR_PLANET[_game.iPlanetXtal[_game.nXtals]]); - strcpy(_game.szAddr, (char *)IDS_MSA_ADDR_PLANET[_game.iPlanetXtal[_game.nXtals]]); - _game.nButtons = strlen(_game.szAddr); - _vm->_gfx->doUpdate(); - _vm->_system->updateScreen(); // TODO: this should go in the game's main loop + drawStr(24, 12, IDA_DEFAULT, (char *)IDS_MSA_NAME_PLANET_2[_gameStateMickey.iPlanetXtal[_gameStateMickey.nXtals]]); + drawStr(24, 22, IDA_DEFAULT, (char *)IDS_MSA_ADDR_PLANET[_gameStateMickey.iPlanetXtal[_gameStateMickey.nXtals]]); + strcpy(_gameStateMickey.szAddr, (char *)IDS_MSA_ADDR_PLANET[_gameStateMickey.iPlanetXtal[_gameStateMickey.nXtals]]); + _gameStateMickey.nButtons = strlen(_gameStateMickey.szAddr); + _gfx->doUpdate(); + _system->updateScreen(); // TODO: this should go in the game's main loop #endif waitAnyKey(true); @@ -1374,73 +1374,73 @@ void Mickey::flipSwitch() { } } -void Mickey::inventory() { +void MickeyEngine::inventory() { int iRow = IDI_MSA_ROW_INV_ITEMS; char szCrystals[12] = {0}; - sprintf(szCrystals, IDS_MSA_CRYSTALS, IDS_MSA_CRYSTAL_NO[_game.nXtals]); + sprintf(szCrystals, IDS_MSA_CRYSTALS, IDS_MSA_CRYSTAL_NO[_gameStateMickey.nXtals]); CursorMan.showMouse(false); - _vm->clearScreen(IDA_DEFAULT); - _vm->drawStr(IDI_MSA_ROW_INV_TITLE, IDI_MSA_COL_INV_TITLE, IDA_DEFAULT, IDS_MSA_INVENTORY); - _vm->drawStr(IDI_MSA_ROW_INV_CRYSTALS, IDI_MSA_COL_INV_ITEMS, IDA_DEFAULT, szCrystals); + clearScreen(IDA_DEFAULT); + drawStr(IDI_MSA_ROW_INV_TITLE, IDI_MSA_COL_INV_TITLE, IDA_DEFAULT, IDS_MSA_INVENTORY); + drawStr(IDI_MSA_ROW_INV_CRYSTALS, IDI_MSA_COL_INV_ITEMS, IDA_DEFAULT, szCrystals); for (int iItem = 0; iItem < IDI_MSA_MAX_ITEM; iItem++) { - if (_game.fItem[_game.iItem[iItem]] && (_game.iItem[iItem] != IDI_MSA_OBJECT_NONE)) { - _vm->drawStr(iRow++, IDI_MSA_COL_INV_ITEMS, IDA_DEFAULT, (const char *)IDS_MSA_NAME_ITEM[_game.iItem[iItem]]); + if (_gameStateMickey.fItem[_gameStateMickey.iItem[iItem]] && (_gameStateMickey.iItem[iItem] != IDI_MSA_OBJECT_NONE)) { + drawStr(iRow++, IDI_MSA_COL_INV_ITEMS, IDA_DEFAULT, (const char *)IDS_MSA_NAME_ITEM[_gameStateMickey.iItem[iItem]]); } } waitAnyKey(); - _vm->clearScreen(IDA_DEFAULT); + clearScreen(IDA_DEFAULT); CursorMan.showMouse(true); } -void Mickey::intro() { +void MickeyEngine::intro() { // Draw Sierra logo //drawLogo(); // Original does not even show this, so we skip it too //waitAnyKey(); // Not in the original, but needed so that the logo is visible // draw title picture - _game.iRoom = IDI_MSA_PIC_TITLE; + _gameStateMickey.iRoom = IDI_MSA_PIC_TITLE; drawRoom(); // show copyright and play theme printExeMsg(IDO_MSA_COPYRIGHT); // Quit if necessary - if (_vm->shouldQuit()) + if (shouldQuit()) return; playSound(IDI_MSA_SND_THEME); // load game - _game.fIntro = true; + _gameStateMickey.fIntro = true; if (chooseY_N(IDO_MSA_LOAD_GAME[0], true)) { if (loadGame()) { - _game.iPlanet = IDI_MSA_PLANET_EARTH; - _game.fIntro = false; - _game.iRoom = IDI_MSA_PIC_SHIP_CORRIDOR; + _gameStateMickey.iPlanet = IDI_MSA_PLANET_EARTH; + _gameStateMickey.fIntro = false; + _gameStateMickey.iRoom = IDI_MSA_PIC_SHIP_CORRIDOR; return; } } // Quit if necessary - if (_vm->shouldQuit()) + if (shouldQuit()) return; // play spaceship landing scene - _game.iPlanet = IDI_MSA_PLANET_EARTH; - _game.iRoom = IDI_MSA_PIC_EARTH_ROAD_4; + _gameStateMickey.iPlanet = IDI_MSA_PLANET_EARTH; + _gameStateMickey.iRoom = IDI_MSA_PIC_EARTH_ROAD_4; drawRoom(); printRoomDesc(); // Quit if necessary - if (_vm->shouldQuit()) + if (shouldQuit()) return; playSound(IDI_MSA_SND_SHIP_LAND); @@ -1450,48 +1450,48 @@ void Mickey::intro() { playSound(IDI_MSA_SND_PRESS_BLUE); //Set screen to white - _vm->_gfx->clearScreen(15); - _vm->_gfx->doUpdate(); - _vm->_system->updateScreen(); + _gfx->clearScreen(15); + _gfx->doUpdate(); + _system->updateScreen(); - _vm->_system->delayMillis(IDI_MSA_ANIM_DELAY); + _system->delayMillis(IDI_MSA_ANIM_DELAY); //Set back to black - _vm->_gfx->clearScreen(0); - _vm->_gfx->doUpdate(); - _vm->_system->updateScreen(); + _gfx->clearScreen(0); + _gfx->doUpdate(); + _system->updateScreen(); drawRoom(); - printDesc(_game.iRoom); + printDesc(_gameStateMickey.iRoom); } printExeMsg(IDO_MSA_INTRO); } -void Mickey::getItem(ENUM_MSA_ITEM iItem) { - _game.fItem[iItem] = true; - _game.iItem[_game.nItems++] = iItem; - _game.oRmTxt[_game.iRoom] = 0; +void MickeyEngine::getItem(ENUM_MSA_ITEM iItem) { + _gameStateMickey.fItem[iItem] = true; + _gameStateMickey.iItem[_gameStateMickey.nItems++] = iItem; + _gameStateMickey.oRmTxt[_gameStateMickey.iRoom] = 0; playSound(IDI_MSA_SND_TAKE); drawRoom(); } -void Mickey::getXtal(int iStr) { - _game.oRmTxt[_game.iRoom] = 0; - _game.fHasXtal = true; - _game.nXtals++; +void MickeyEngine::getXtal(int iStr) { + _gameStateMickey.oRmTxt[_gameStateMickey.iRoom] = 0; + _gameStateMickey.fHasXtal = true; + _gameStateMickey.nXtals++; playSound(IDI_MSA_SND_CRYSTAL); drawRoom(); printDatMessage(iStr); } -bool Mickey::parse(int cmd, int arg) { +bool MickeyEngine::parse(int cmd, int arg) { switch (cmd) { // BASIC case IDI_MSA_ACTION_GOTO_ROOM: - _game.iRoom = arg; + _gameStateMickey.iRoom = arg; return true; case IDI_MSA_ACTION_SHOW_INT_STR: printLine(IDS_MSA_ERRORS[arg]); @@ -1515,291 +1515,291 @@ bool Mickey::parse(int cmd, int arg) { // EARTH case IDI_MSA_ACTION_GET_ROPE: - if (_game.iRmMenu[_game.iRoom] == 2) { - _game.iRmObj[_game.iRoom] = IDI_MSA_OBJECT_NONE; - _game.iRmMenu[_game.iRoom] = 3; + if (_gameStateMickey.iRmMenu[_gameStateMickey.iRoom] == 2) { + _gameStateMickey.iRmObj[_gameStateMickey.iRoom] = IDI_MSA_OBJECT_NONE; + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 3; getItem(IDI_MSA_ITEM_ROPE); printLine("MICKEY TAKES THE ROPE"); } else { - _game.iRmMenu[_game.iRoom] = 1; + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 1; printDatMessage(11); } break; case IDI_MSA_ACTION_UNTIE_ROPE: - _game.iRmPic[_game.iRoom] = IDI_MSA_PIC_EARTH_TIRE_SWING_1; - _game.iRmObj[_game.iRoom] = 0; - _game.iRmMenu[_game.iRoom] = 2; + _gameStateMickey.iRmPic[_gameStateMickey.iRoom] = IDI_MSA_PIC_EARTH_TIRE_SWING_1; + _gameStateMickey.iRmObj[_gameStateMickey.iRoom] = 0; + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 2; drawRoom(); printDatMessage(12); break; case IDI_MSA_ACTION_GET_BONE: - _game.iRmObj[_game.iRoom] = IDI_MSA_OBJECT_NONE; - _game.iRmMenu[_game.iRoom] = 1; + _gameStateMickey.iRmObj[_gameStateMickey.iRoom] = IDI_MSA_OBJECT_NONE; + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 1; getItem(IDI_MSA_ITEM_BONE); printDatMessage(arg); break; case IDI_MSA_ACTION_GET_XTAL_EARTH: - _game.iRmMenu[_game.iRoom] = 1; + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 1; getXtal(arg); break; case IDI_MSA_ACTION_LOOK_DESK: - _game.iRmMenu[_game.iRoom] = 1; - _game.iRmObj[_game.iRoom] = 2; + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 1; + _gameStateMickey.iRmObj[_gameStateMickey.iRoom] = 2; drawRoom(); printDatMessage(arg); break; case IDI_MSA_ACTION_WRITE_LETTER: - _game.iRmMenu[_game.iRoom] = 3; - _game.iRmMenu[IDI_MSA_PIC_EARTH_MAILBOX] = 1; - _game.iRmObj[_game.iRoom] = IDI_MSA_OBJECT_NONE; + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 3; + _gameStateMickey.iRmMenu[IDI_MSA_PIC_EARTH_MAILBOX] = 1; + _gameStateMickey.iRmObj[_gameStateMickey.iRoom] = IDI_MSA_OBJECT_NONE; getItem(IDI_MSA_ITEM_LETTER); printDatMessage(arg); break; case IDI_MSA_ACTION_MAIL_LETTER: - _game.fItemUsed[IDI_MSA_ITEM_LETTER] = true; - _game.fItem[IDI_MSA_ITEM_LETTER] = false; - _game.iRmMenu[_game.iRoom] = 0; + _gameStateMickey.fItemUsed[IDI_MSA_ITEM_LETTER] = true; + _gameStateMickey.fItem[IDI_MSA_ITEM_LETTER] = false; + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 0; printDatMessage(arg); break; case IDI_MSA_ACTION_OPEN_MAILBOX: - if (_game.fItemUsed[IDI_MSA_ITEM_LETTER]) { + if (_gameStateMickey.fItemUsed[IDI_MSA_ITEM_LETTER]) { printDatMessage(110); } else { printDatMessage(arg); } break; case IDI_MSA_ACTION_OPEN_CUPBOARD: - if (_game.iRmMenu[_game.iRoom]) { - if (_game.iRmObj[_game.iRoom] == IDI_MSA_OBJECT_NONE) { + if (_gameStateMickey.iRmMenu[_gameStateMickey.iRoom]) { + if (_gameStateMickey.iRmObj[_gameStateMickey.iRoom] == IDI_MSA_OBJECT_NONE) { printDatMessage(78); } else { printDatMessage(arg); } } else { - _game.iRmMenu[_game.iRoom] = 1; - _game.iRmPic[_game.iRoom] = IDI_MSA_PIC_EARTH_KITCHEN_1; - _game.iRmObj[_game.iRoom] = 3; + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 1; + _gameStateMickey.iRmPic[_gameStateMickey.iRoom] = IDI_MSA_PIC_EARTH_KITCHEN_1; + _gameStateMickey.iRmObj[_gameStateMickey.iRoom] = 3; drawRoom(); printDatMessage(arg); } break; case IDI_MSA_ACTION_GET_FLASHLIGHT: if (!mickeyHasItem(IDI_MSA_ITEM_FLASHLIGHT)) { - _game.iRmObj[_game.iRoom] = IDI_MSA_OBJECT_NONE; + _gameStateMickey.iRmObj[_gameStateMickey.iRoom] = IDI_MSA_OBJECT_NONE; getItem(IDI_MSA_ITEM_FLASHLIGHT); drawRoom(); printDatMessage(arg); } break; case IDI_MSA_ACTION_OPEN_CABINET: - if (_game.iRmMenu[_game.iRoom]) { + if (_gameStateMickey.iRmMenu[_gameStateMickey.iRoom]) { printDatMessage(109); } else { - _game.iRmMenu[_game.iRoom] = 1; - _game.iRmPic[_game.iRoom] = IDI_MSA_PIC_EARTH_GARAGE_1; - _game.iRmObj[_game.iRoom] = 15; + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 1; + _gameStateMickey.iRmPic[_gameStateMickey.iRoom] = IDI_MSA_PIC_EARTH_GARAGE_1; + _gameStateMickey.iRmObj[_gameStateMickey.iRoom] = 15; drawRoom(); printDatMessage(arg); } break; case IDI_MSA_ACTION_GET_CROWBAR: if (!mickeyHasItem(IDI_MSA_ITEM_CROWBAR)) { - _game.iRmObj[_game.iRoom]--; + _gameStateMickey.iRmObj[_gameStateMickey.iRoom]--; getItem(IDI_MSA_ITEM_CROWBAR); printDatMessage(arg); } break; case IDI_MSA_ACTION_GET_WRENCH: if (!mickeyHasItem(IDI_MSA_ITEM_WRENCH)) { - _game.iRmObj[_game.iRoom] -= 2; + _gameStateMickey.iRmObj[_gameStateMickey.iRoom] -= 2; getItem(IDI_MSA_ITEM_WRENCH); printDatMessage(arg); } break; case IDI_MSA_ACTION_OPEN_CLOSET: - if (_game.iRmMenu[_game.iRoom]) { + if (_gameStateMickey.iRmMenu[_gameStateMickey.iRoom]) { printDatMessage(99); } else { - _game.iRmMenu[_game.iRoom] = 1; - _game.iRmPic[_game.iRoom] = IDI_MSA_PIC_EARTH_BEDROOM_1; - _game.iRmObj[_game.iRoom] = 7; + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 1; + _gameStateMickey.iRmPic[_gameStateMickey.iRoom] = IDI_MSA_PIC_EARTH_BEDROOM_1; + _gameStateMickey.iRmObj[_gameStateMickey.iRoom] = 7; drawRoom(); printDatMessage(arg); } break; case IDI_MSA_ACTION_GET_MATTRESS: if (!mickeyHasItem(IDI_MSA_ITEM_MATTRESS)) { - _game.iRmObj[_game.iRoom]--; + _gameStateMickey.iRmObj[_gameStateMickey.iRoom]--; getItem(IDI_MSA_ITEM_MATTRESS); printDatMessage(arg); } break; case IDI_MSA_ACTION_GET_SCARF: if (!mickeyHasItem(IDI_MSA_ITEM_SCARF)) { - _game.iRmObj[_game.iRoom] -= 2; + _gameStateMickey.iRmObj[_gameStateMickey.iRoom] -= 2; getItem(IDI_MSA_ITEM_SCARF); printDatMessage(arg); } break; case IDI_MSA_ACTION_GET_SUNGLASSES: if (!mickeyHasItem(IDI_MSA_ITEM_SUNGLASSES)) { - _game.iRmObj[_game.iRoom]--; + _gameStateMickey.iRmObj[_gameStateMickey.iRoom]--; getItem(IDI_MSA_ITEM_SUNGLASSES); printDatMessage(arg); } break; case IDI_MSA_ACTION_GET_SCALE: if (!mickeyHasItem(IDI_MSA_ITEM_SCALE)) { - _game.iRmMenu[IDI_MSA_PIC_VENUS_WEIGH] = 1; - _game.iRmMenu[IDI_MSA_PIC_NEPTUNE_WEIGH] = 1; - _game.iRmMenu[IDI_MSA_PIC_MERCURY_WEIGH] = 1; - _game.iRmMenu[IDI_MSA_PIC_SATURN_WEIGH] = 1; - _game.iRmMenu[IDI_MSA_PIC_PLUTO_WEIGH] = 1; - _game.iRmMenu[IDI_MSA_PIC_JUPITER_WEIGH] = 1; - _game.iRmMenu[IDI_MSA_PIC_MARS_WEIGH] = 1; - _game.iRmMenu[IDI_MSA_PIC_URANUS_WEIGH] = 1; - _game.iRmObj[_game.iRoom] -= 2; + _gameStateMickey.iRmMenu[IDI_MSA_PIC_VENUS_WEIGH] = 1; + _gameStateMickey.iRmMenu[IDI_MSA_PIC_NEPTUNE_WEIGH] = 1; + _gameStateMickey.iRmMenu[IDI_MSA_PIC_MERCURY_WEIGH] = 1; + _gameStateMickey.iRmMenu[IDI_MSA_PIC_SATURN_WEIGH] = 1; + _gameStateMickey.iRmMenu[IDI_MSA_PIC_PLUTO_WEIGH] = 1; + _gameStateMickey.iRmMenu[IDI_MSA_PIC_JUPITER_WEIGH] = 1; + _gameStateMickey.iRmMenu[IDI_MSA_PIC_MARS_WEIGH] = 1; + _gameStateMickey.iRmMenu[IDI_MSA_PIC_URANUS_WEIGH] = 1; + _gameStateMickey.iRmObj[_gameStateMickey.iRoom] -= 2; getItem(IDI_MSA_ITEM_SCALE); printDatMessage(arg); } break; case IDI_MSA_ACTION_GOTO_SPACESHIP: - _game.iRoom = IDI_MSA_PIC_SHIP_AIRLOCK; - if (_game.iPlanet != IDI_MSA_PLANET_EARTH) + _gameStateMickey.iRoom = IDI_MSA_PIC_SHIP_AIRLOCK; + if (_gameStateMickey.iPlanet != IDI_MSA_PLANET_EARTH) insertDisk(0); return true; // VENUS case IDI_MSA_ACTION_DOWN_CHASM: - if (_game.fItem[IDI_MSA_ITEM_ROPE]) { - _game.iRmMenu[_game.iRoom] = 1; + if (_gameStateMickey.fItem[IDI_MSA_ITEM_ROPE]) { + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 1; } printDatMessage(arg); break; case IDI_MSA_ACTION_DOWN_ROPE: - if (_game.fItemUsed[IDI_MSA_ITEM_ROPE]) { - _game.iRoom = IDI_MSA_PIC_VENUS_PROBE; + if (_gameStateMickey.fItemUsed[IDI_MSA_ITEM_ROPE]) { + _gameStateMickey.iRoom = IDI_MSA_PIC_VENUS_PROBE; return true; } else { printDatMessage(arg); } break; case IDI_MSA_ACTION_USE_ROPE: - if (_game.fItemUsed[IDI_MSA_ITEM_ROPE]) { + if (_gameStateMickey.fItemUsed[IDI_MSA_ITEM_ROPE]) { printDatMessage(22); } else { - _game.fItemUsed[IDI_MSA_ITEM_ROPE] = true; - _game.fItem[IDI_MSA_ITEM_ROPE] = false; - _game.iRmPic[_game.iRoom] = IDI_MSA_PIC_VENUS_CHASM_1; + _gameStateMickey.fItemUsed[IDI_MSA_ITEM_ROPE] = true; + _gameStateMickey.fItem[IDI_MSA_ITEM_ROPE] = false; + _gameStateMickey.iRmPic[_gameStateMickey.iRoom] = IDI_MSA_PIC_VENUS_CHASM_1; drawRoom(); printDatMessage(arg); } break; case IDI_MSA_ACTION_OPEN_HATCH: - if (_game.fItemUsed[IDI_MSA_ITEM_WRENCH]) { - if ((_game.iRmMenu[_game.iRoom] == 3) || (_game.iRmPic[_game.iRoom] == IDI_MSA_PIC_VENUS_PROBE_1)) + if (_gameStateMickey.fItemUsed[IDI_MSA_ITEM_WRENCH]) { + if ((_gameStateMickey.iRmMenu[_gameStateMickey.iRoom] == 3) || (_gameStateMickey.iRmPic[_gameStateMickey.iRoom] == IDI_MSA_PIC_VENUS_PROBE_1)) printDatMessage(39); else { - _game.iRmMenu[_game.iRoom] = 2; - _game.iRmPic[_game.iRoom] = IDI_MSA_PIC_VENUS_PROBE_1; + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 2; + _gameStateMickey.iRmPic[_gameStateMickey.iRoom] = IDI_MSA_PIC_VENUS_PROBE_1; drawRoom(); printDatMessage(24); } } else { - if (_game.fItem[IDI_MSA_ITEM_WRENCH]) { - _game.iRmMenu[_game.iRoom] = 1; + if (_gameStateMickey.fItem[IDI_MSA_ITEM_WRENCH]) { + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 1; } printDatMessage(arg); } break; case IDI_MSA_ACTION_USE_WRENCH: - _game.fItemUsed[IDI_MSA_ITEM_WRENCH] = true; + _gameStateMickey.fItemUsed[IDI_MSA_ITEM_WRENCH] = true; printDatString(arg); - if (_game.iRmPic[_game.iRoom] == IDI_MSA_PIC_VENUS_PROBE_1) { - _vm->clearRow(22); + if (_gameStateMickey.iRmPic[_gameStateMickey.iRoom] == IDI_MSA_PIC_VENUS_PROBE_1) { + clearRow(22); } waitAnyKey(); break; case IDI_MSA_ACTION_GET_XTAL_VENUS: - _game.iRmMenu[_game.iRoom] = 3; + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 3; getXtal(arg); break; // TRITON (NEPTUNE) case IDI_MSA_ACTION_LOOK_CASTLE: - if (!_game.iRmMenu[_game.iRoom]) { - _game.iRmMenu[_game.iRoom] = 1; + if (!_gameStateMickey.iRmMenu[_gameStateMickey.iRoom]) { + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 1; } printDatMessage(arg); break; case IDI_MSA_ACTION_ENTER_OPENING: - if (_game.fItemUsed[IDI_MSA_ITEM_CROWBAR]) { - _game.iRoom = IDI_MSA_PIC_NEPTUNE_CASTLE_4; + if (_gameStateMickey.fItemUsed[IDI_MSA_ITEM_CROWBAR]) { + _gameStateMickey.iRoom = IDI_MSA_PIC_NEPTUNE_CASTLE_4; return true; } else { - if (_game.fItem[IDI_MSA_ITEM_CROWBAR]) { - _game.iRmMenu[_game.iRoom] = 2; + if (_gameStateMickey.fItem[IDI_MSA_ITEM_CROWBAR]) { + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 2; } printDatMessage(arg); } break; case IDI_MSA_ACTION_USE_CROWBAR: - _game.fItemUsed[IDI_MSA_ITEM_CROWBAR] = true; - _game.iRmMenu[_game.iRoom] = 1; - _game.iRmPic[_game.iRoom] = IDI_MSA_PIC_NEPTUNE_ENTRANCE_1; + _gameStateMickey.fItemUsed[IDI_MSA_ITEM_CROWBAR] = true; + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 1; + _gameStateMickey.iRmPic[_gameStateMickey.iRoom] = IDI_MSA_PIC_NEPTUNE_ENTRANCE_1; drawRoom(); printDatMessage(arg); break; case IDI_MSA_ACTION_GET_XTAL_NEPTUNE: - if (_game.fHasXtal) { + if (_gameStateMickey.fHasXtal) { printDatMessage(71); } else { - if (_game.fItem[IDI_MSA_ITEM_SCARF]) { - _game.iRmMenu[_game.iRoom] = 1; + if (_gameStateMickey.fItem[IDI_MSA_ITEM_SCARF]) { + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 1; } printDatMessage(arg); } break; case IDI_MSA_ACTION_TALK_LEADER: - _game.iRoom = IDI_MSA_PIC_NEPTUNE_ENTRYWAY; + _gameStateMickey.iRoom = IDI_MSA_PIC_NEPTUNE_ENTRYWAY; printDatMessage(arg); return true; case IDI_MSA_ACTION_GIVE_SCARF: - _game.iRmObj[_game.iRoom] = 18; + _gameStateMickey.iRmObj[_gameStateMickey.iRoom] = 18; getXtal(arg); - _game.fItem[IDI_MSA_ITEM_SCARF] = false; - _game.iRmMenu[_game.iRoom] = 0; - _game.iRmMenu[IDI_MSA_PIC_EARTH_BEDROOM] = 2; - _game.iRoom = IDI_MSA_PIC_NEPTUNE_ENTRYWAY; + _gameStateMickey.fItem[IDI_MSA_ITEM_SCARF] = false; + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 0; + _gameStateMickey.iRmMenu[IDI_MSA_PIC_EARTH_BEDROOM] = 2; + _gameStateMickey.iRoom = IDI_MSA_PIC_NEPTUNE_ENTRYWAY; return true; // MERCURY case IDI_MSA_ACTION_GET_XTAL_MERCURY: - if (_game.fHasXtal) { - _game.iRmMenu[_game.iRoom] = 2; + if (_gameStateMickey.fHasXtal) { + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 2; printDatMessage(32); } else { - if (_game.fItem[IDI_MSA_ITEM_SUNGLASSES]) { - _game.iRmMenu[_game.iRoom] = 1; + if (_gameStateMickey.fItem[IDI_MSA_ITEM_SUNGLASSES]) { + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 1; } printDatMessage(arg); } break; case IDI_MSA_ACTION_GIVE_SUNGLASSES: - _game.iRmObj[_game.iRoom] = 17; - _game.iRmMenu[_game.iRoom] = 2; - _game.fItem[IDI_MSA_ITEM_SUNGLASSES] = false; + _gameStateMickey.iRmObj[_gameStateMickey.iRoom] = 17; + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 2; + _gameStateMickey.fItem[IDI_MSA_ITEM_SUNGLASSES] = false; getXtal(arg); @@ -1808,30 +1808,30 @@ bool Mickey::parse(int cmd, int arg) { // TITAN (SATURN) case IDI_MSA_ACTION_CROSS_LAKE: - if (_game.fItem[IDI_MSA_ITEM_MATTRESS]) { - _game.iRmMenu[IDI_MSA_PIC_SATURN_LAKE_0] = 1; - _game.iRmMenu[IDI_MSA_PIC_SATURN_LAKE_1] = 1; - _game.iRmMenu[IDI_MSA_PIC_SATURN_LAKE_2] = 1; + if (_gameStateMickey.fItem[IDI_MSA_ITEM_MATTRESS]) { + _gameStateMickey.iRmMenu[IDI_MSA_PIC_SATURN_LAKE_0] = 1; + _gameStateMickey.iRmMenu[IDI_MSA_PIC_SATURN_LAKE_1] = 1; + _gameStateMickey.iRmMenu[IDI_MSA_PIC_SATURN_LAKE_2] = 1; } printDatMessage(arg); break; case IDI_MSA_ACTION_USE_MATTRESS: - _game.iRoom = IDI_MSA_PIC_SATURN_ISLAND; + _gameStateMickey.iRoom = IDI_MSA_PIC_SATURN_ISLAND; printDatMessage(arg); return true; case IDI_MSA_ACTION_GET_XTAL_SATURN: - if (_game.fHasXtal) { + if (_gameStateMickey.fHasXtal) { printDatMessage(29); } else { getXtal(arg); } break; case IDI_MSA_ACTION_LEAVE_ISLAND: - _game.iRoom = IDI_MSA_PIC_SATURN_LAKE_1; + _gameStateMickey.iRoom = IDI_MSA_PIC_SATURN_LAKE_1; printDatMessage(arg); @@ -1840,19 +1840,19 @@ bool Mickey::parse(int cmd, int arg) { // PLUTO case IDI_MSA_ACTION_GET_XTAL_PLUTO: - if (_game.fHasXtal) { + if (_gameStateMickey.fHasXtal) { printDatMessage(19); } else { - if (_game.fItem[IDI_MSA_ITEM_BONE]) { - _game.iRmMenu[_game.iRoom] = 1; + if (_gameStateMickey.fItem[IDI_MSA_ITEM_BONE]) { + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 1; } printDatMessage(arg); } break; case IDI_MSA_ACTION_GIVE_BONE: - _game.fItem[IDI_MSA_ITEM_BONE] = false; - _game.iRmMenu[_game.iRoom] = 0; - _game.iRmObj[_game.iRoom] = 16; + _gameStateMickey.fItem[IDI_MSA_ITEM_BONE] = false; + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 0; + _gameStateMickey.iRmObj[_gameStateMickey.iRoom] = 16; getXtal(arg); @@ -1862,29 +1862,29 @@ bool Mickey::parse(int cmd, int arg) { case IDI_MSA_ACTION_GET_ROCK_0: case IDI_MSA_ACTION_GET_ROCK_1: - if (_game.fItem[IDI_MSA_ITEM_ROCK]) { + if (_gameStateMickey.fItem[IDI_MSA_ITEM_ROCK]) { printDatMessage(38); } else { - _game.iRmMenu[_game.iRoom] = 1; - _game.iRmObj[_game.iRoom] = IDI_MSA_OBJECT_NONE; + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 1; + _gameStateMickey.iRmObj[_gameStateMickey.iRoom] = IDI_MSA_OBJECT_NONE; getItem(IDI_MSA_ITEM_ROCK); printDatMessage(arg); } break; case IDI_MSA_ACTION_GET_XTAL_JUPITER: - if (_game.fHasXtal) { + if (_gameStateMickey.fHasXtal) { printDatMessage(15); } else { - switch (_game.nRocks) { + switch (_gameStateMickey.nRocks) { case 0: - if (_game.fItem[IDI_MSA_ITEM_ROCK]) { - _game.iRmMenu[_game.iRoom] = 1; + if (_gameStateMickey.fItem[IDI_MSA_ITEM_ROCK]) { + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 1; } printDatMessage(arg); break; case 1: - if (_game.fItem[IDI_MSA_ITEM_ROCK]) { - _game.iRmMenu[_game.iRoom] = 1; + if (_gameStateMickey.fItem[IDI_MSA_ITEM_ROCK]) { + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 1; } printDatMessage(34); break; @@ -1895,47 +1895,47 @@ bool Mickey::parse(int cmd, int arg) { } break; case IDI_MSA_ACTION_THROW_ROCK: - _game.fItem[IDI_MSA_ITEM_ROCK] = false; - _game.nItems--; - _game.iRmObj[_game.iRoom]++; - _game.iRmMenu[_game.iRoom] = 0; + _gameStateMickey.fItem[IDI_MSA_ITEM_ROCK] = false; + _gameStateMickey.nItems--; + _gameStateMickey.iRmObj[_gameStateMickey.iRoom]++; + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 0; drawRoom(); - if (_game.nRocks) { + if (_gameStateMickey.nRocks) { printDatMessage(37); } else { printDatMessage(arg); } - _game.nRocks++; + _gameStateMickey.nRocks++; break; // MARS case IDI_MSA_ACTION_GO_TUBE: - if (_game.fItem[IDI_MSA_ITEM_FLASHLIGHT]) { - _game.iRmMenu[_game.iRoom] = 1; + if (_gameStateMickey.fItem[IDI_MSA_ITEM_FLASHLIGHT]) { + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 1; } printDatMessage(arg); break; case IDI_MSA_ACTION_USE_FLASHLIGHT: - _game.iRoom = IDI_MSA_PIC_MARS_TUBE_1; + _gameStateMickey.iRoom = IDI_MSA_PIC_MARS_TUBE_1; printDatMessage(15); return true; case IDI_MSA_ACTION_PLUTO_DIG: - if (_game.fHasXtal) { + if (_gameStateMickey.fHasXtal) { printDatMessage(21); } else { getXtal(arg); } break; case IDI_MSA_ACTION_GET_XTAL_MARS: - if (_game.fHasXtal) { + if (_gameStateMickey.fHasXtal) { printDatMessage(23); } else { printDatMessage(arg); @@ -1945,29 +1945,29 @@ bool Mickey::parse(int cmd, int arg) { // OBERON (URANUS) case IDI_MSA_ACTION_ENTER_TEMPLE: - _game.iRoom = IDI_MSA_PIC_URANUS_TEMPLE; + _gameStateMickey.iRoom = IDI_MSA_PIC_URANUS_TEMPLE; return true; case IDI_MSA_ACTION_USE_CRYSTAL: - if (_game.iRmMenu[_game.iRoom]) { + if (_gameStateMickey.iRmMenu[_gameStateMickey.iRoom]) { printDatMessage(25); } else { - _game.iRmMenu[_game.iRoom] = 1; - _game.iRmPic[_game.iRoom] = IDI_MSA_PIC_URANUS_TEMPLE_1; + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 1; + _gameStateMickey.iRmPic[_gameStateMickey.iRoom] = IDI_MSA_PIC_URANUS_TEMPLE_1; drawRoom(); - _game.iRmPic[_game.iRoom] = IDI_MSA_PIC_URANUS_TEMPLE; + _gameStateMickey.iRmPic[_gameStateMickey.iRoom] = IDI_MSA_PIC_URANUS_TEMPLE; printDatMessage(arg); } break; case IDI_MSA_ACTION_OPEN_DOOR: - if (_game.fTempleDoorOpen) { + if (_gameStateMickey.fTempleDoorOpen) { printDatMessage(36); } else { - _game.fTempleDoorOpen = 1; - _game.iRmPic[_game.iRoom] = IDI_MSA_PIC_URANUS_TEMPLE_2; + _gameStateMickey.fTempleDoorOpen = 1; + _gameStateMickey.iRmPic[_gameStateMickey.iRoom] = IDI_MSA_PIC_URANUS_TEMPLE_2; drawRoom(); @@ -1975,8 +1975,8 @@ bool Mickey::parse(int cmd, int arg) { } break; case IDI_MSA_ACTION_ENTER_DOOR: - if (_game.fTempleDoorOpen) { - _game.iRoom = IDI_MSA_PIC_URANUS_STEPS; + if (_gameStateMickey.fTempleDoorOpen) { + _gameStateMickey.iRoom = IDI_MSA_PIC_URANUS_STEPS; return true; } else { @@ -1984,17 +1984,17 @@ bool Mickey::parse(int cmd, int arg) { } break; case IDI_MSA_ACTION_GET_XTAL_URANUS: - if (_game.fHasXtal) { + if (_gameStateMickey.fHasXtal) { printDatMessage(34); } else { - if (_game.fItem[IDI_MSA_ITEM_CROWBAR]) { - _game.iRmMenu[_game.iRoom] = 1; + if (_gameStateMickey.fItem[IDI_MSA_ITEM_CROWBAR]) { + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 1; } printDatMessage(arg); } break; case IDI_MSA_ACTION_USE_CROWBAR_1: - _game.iRmMenu[_game.iRoom] = 0; + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 0; getXtal(arg); @@ -2003,11 +2003,11 @@ bool Mickey::parse(int cmd, int arg) { // SPACESHIP case IDI_MSA_ACTION_GO_NORTH: - if (_game.fShipDoorOpen) { - if (_game.fSuit) { + if (_gameStateMickey.fShipDoorOpen) { + if (_gameStateMickey.fSuit) { printDatMessage(45); } else { - _game.iRoom = IDI_MSA_PIC_SHIP_CORRIDOR; + _gameStateMickey.iRoom = IDI_MSA_PIC_SHIP_CORRIDOR; return true; } } else { @@ -2015,19 +2015,19 @@ bool Mickey::parse(int cmd, int arg) { } break; case IDI_MSA_ACTION_GO_PLANET: - if (!_game.fShipDoorOpen) { - if ((_game.nXtals == IDI_MSA_MAX_PLANET) && (_game.iPlanet == IDI_MSA_PLANET_EARTH)) + if (!_gameStateMickey.fShipDoorOpen) { + if ((_gameStateMickey.nXtals == IDI_MSA_MAX_PLANET) && (_gameStateMickey.iPlanet == IDI_MSA_PLANET_EARTH)) gameOver(); - if ((_game.iPlanet == _game.iPlanetXtal[_game.nXtals]) || (_game.iPlanet == IDI_MSA_PLANET_EARTH)) { - _game.fHasXtal = false; - _game.iRoom = IDI_MSA_HOME_PLANET[_game.iPlanet]; + if ((_gameStateMickey.iPlanet == _gameStateMickey.iPlanetXtal[_gameStateMickey.nXtals]) || (_gameStateMickey.iPlanet == IDI_MSA_PLANET_EARTH)) { + _gameStateMickey.fHasXtal = false; + _gameStateMickey.iRoom = IDI_MSA_HOME_PLANET[_gameStateMickey.iPlanet]; - if (_game.iPlanet != IDI_MSA_PLANET_EARTH) + if (_gameStateMickey.iPlanet != IDI_MSA_PLANET_EARTH) insertDisk(1); return true; } else { - _game.iRoom = IDI_MSA_SHIP_PLANET[_game.iPlanet]; + _gameStateMickey.iRoom = IDI_MSA_SHIP_PLANET[_gameStateMickey.iPlanet]; return true; } @@ -2036,20 +2036,20 @@ bool Mickey::parse(int cmd, int arg) { } break; case IDI_MSA_ACTION_PRESS_BUTTON: - if (_game.fShipDoorOpen) { // inner door open - if (_game.iPlanet && !_game.fSuit) { + if (_gameStateMickey.fShipDoorOpen) { // inner door open + if (_gameStateMickey.iPlanet && !_gameStateMickey.fSuit) { printDatMessage(arg); } else { - _game.fShipDoorOpen = false; - _game.iRmPic[_game.iRoom]--; + _gameStateMickey.fShipDoorOpen = false; + _gameStateMickey.iRmPic[_gameStateMickey.iRoom]--; drawRoom(); printDatMessage(2); } } else { - _game.fShipDoorOpen = true; - _game.iRmPic[_game.iRoom]++; + _gameStateMickey.fShipDoorOpen = true; + _gameStateMickey.iRmPic[_gameStateMickey.iRoom]++; drawRoom(); @@ -2057,11 +2057,11 @@ bool Mickey::parse(int cmd, int arg) { } break; case IDI_MSA_ACTION_WEAR_SPACESUIT: - if (_game.fSuit) { - if (_game.fShipDoorOpen) { - _game.fSuit = false; - _game.iRmMenu[_game.iRoom] = 0; - _game.iRmPic[_game.iRoom] -= 2; + if (_gameStateMickey.fSuit) { + if (_gameStateMickey.fShipDoorOpen) { + _gameStateMickey.fSuit = false; + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 0; + _gameStateMickey.iRmPic[_gameStateMickey.iRoom] -= 2; drawRoom(); @@ -2070,10 +2070,10 @@ bool Mickey::parse(int cmd, int arg) { printDatMessage(3); } } else { - if (_game.iPlanet) { - _game.fSuit = true; - _game.iRmMenu[_game.iRoom] = 1; - _game.iRmPic[_game.iRoom] += 2; + if (_gameStateMickey.iPlanet) { + _gameStateMickey.fSuit = true; + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 1; + _gameStateMickey.iRmPic[_gameStateMickey.iRoom] += 2; drawRoom(); @@ -2085,14 +2085,14 @@ bool Mickey::parse(int cmd, int arg) { break; case IDI_MSA_ACTION_READ_GAUGE: printDatString(arg); - _vm->drawStr(21, 15, IDA_DEFAULT, (const char *)IDS_MSA_TEMP_C[_game.iPlanet]); - _vm->drawStr(21, 23, IDA_DEFAULT, (const char *)IDS_MSA_TEMP_F[_game.iPlanet]); + drawStr(21, 15, IDA_DEFAULT, (const char *)IDS_MSA_TEMP_C[_gameStateMickey.iPlanet]); + drawStr(21, 23, IDA_DEFAULT, (const char *)IDS_MSA_TEMP_F[_gameStateMickey.iPlanet]); waitAnyKey(); break; case IDI_MSA_ACTION_PRESS_ORANGE: - if (_game.fFlying) { + if (_gameStateMickey.fFlying) { printDatMessage(4); } else { playSound(IDI_MSA_SND_PRESS_ORANGE); @@ -2101,7 +2101,7 @@ bool Mickey::parse(int cmd, int arg) { } break; case IDI_MSA_ACTION_PRESS_BLUE: - if (_game.fFlying) { + if (_gameStateMickey.fFlying) { printDatMessage(4); } else { playSound(IDI_MSA_SND_PRESS_BLUE); @@ -2113,18 +2113,18 @@ bool Mickey::parse(int cmd, int arg) { flipSwitch(); break; case IDI_MSA_ACTION_PUSH_THROTTLE: - if (_game.fFlying) { - _game.fFlying = false; - _game.nButtons = 0; + if (_gameStateMickey.fFlying) { + _gameStateMickey.fFlying = false; + _gameStateMickey.nButtons = 0; - memset(_game.szAddr, 0, sizeof(_game.szAddr)); + memset(_gameStateMickey.szAddr, 0, sizeof(_gameStateMickey.szAddr)); drawRoom(); printDatString(22); - _vm->drawStr(IDI_MSA_ROW_PLANET, IDI_MSA_COL_PLANET, IDA_DEFAULT, - (const char *)IDS_MSA_PLANETS[_game.iPlanet]); + drawStr(IDI_MSA_ROW_PLANET, IDI_MSA_COL_PLANET, IDA_DEFAULT, + (const char *)IDS_MSA_PLANETS[_gameStateMickey.iPlanet]); waitAnyKey(true); @@ -2134,39 +2134,39 @@ bool Mickey::parse(int cmd, int arg) { } break; case IDI_MSA_ACTION_PULL_THROTTLE: - if (_game.fFlying) { + if (_gameStateMickey.fFlying) { printDatMessage(18); } else { if (getPlanet() != -1) { - _game.fFlying = true; - _game.iPlanet = getPlanet(); + _gameStateMickey.fFlying = true; + _gameStateMickey.iPlanet = getPlanet(); drawRoom(); printDatMessage(16); } else { - _game.nButtons = 0; + _gameStateMickey.nButtons = 0; - memset(_game.szAddr, 0, sizeof(_game.szAddr)); + memset(_gameStateMickey.szAddr, 0, sizeof(_gameStateMickey.szAddr)); printDatMessage(17); } } break; case IDI_MSA_ACTION_LEAVE_ROOM: - if (_game.fFlying) { + if (_gameStateMickey.fFlying) { printDatMessage(24); } else { - _game.iRoom = arg; + _gameStateMickey.iRoom = arg; return true; } break; case IDI_MSA_ACTION_OPEN_CABINET_1: - if (_game.iRmMenu[_game.iRoom]) { + if (_gameStateMickey.iRmMenu[_gameStateMickey.iRoom]) { printLine("THE CABINET IS ALREADY OPEN"); } else { - _game.iRmMenu[_game.iRoom] = 1; - _game.iRmPic[_game.iRoom] = IDI_MSA_PIC_SHIP_KITCHEN_1; + _gameStateMickey.iRmMenu[_gameStateMickey.iRoom] = 1; + _gameStateMickey.iRmPic[_gameStateMickey.iRoom] = IDI_MSA_PIC_SHIP_KITCHEN_1; drawRoom(); @@ -2174,7 +2174,7 @@ bool Mickey::parse(int cmd, int arg) { } break; case IDI_MSA_ACTION_READ_MAP: - _game.iRmPic[_game.iRoom] = IDI_MSA_PIC_STAR_MAP; + _gameStateMickey.iRmPic[_gameStateMickey.iRoom] = IDI_MSA_PIC_STAR_MAP; drawRoom(); @@ -2182,16 +2182,16 @@ bool Mickey::parse(int cmd, int arg) { printDatMessage(47); printDatMessage(48); - _game.iRmPic[_game.iRoom] = IDI_MSA_PIC_SHIP_BEDROOM; + _gameStateMickey.iRmPic[_gameStateMickey.iRoom] = IDI_MSA_PIC_SHIP_BEDROOM; drawRoom(); break; case IDI_MSA_ACTION_GO_WEST: - _game.nButtons = 0; + _gameStateMickey.nButtons = 0; - memset(_game.szAddr, 0, sizeof(_game.szAddr)); + memset(_gameStateMickey.szAddr, 0, sizeof(_gameStateMickey.szAddr)); - _game.iRoom = arg; + _gameStateMickey.iRoom = arg; return true; } @@ -2201,14 +2201,14 @@ bool Mickey::parse(int cmd, int arg) { // Keyboard -void Mickey::waitAnyKey(bool anim) { +void MickeyEngine::waitAnyKey(bool anim) { Common::Event event; if (!anim) - _vm->_gfx->doUpdate(); + _gfx->doUpdate(); - while (!_vm->shouldQuit()) { - while (_vm->_system->getEventManager()->pollEvent(event)) { + while (!shouldQuit()) { + while (_system->getEventManager()->pollEvent(event)) { switch (event.type) { case Common::EVENT_RTL: case Common::EVENT_QUIT: @@ -2223,134 +2223,138 @@ void Mickey::waitAnyKey(bool anim) { if (anim) { animate(); - _vm->_gfx->doUpdate(); + _gfx->doUpdate(); } - _vm->_system->updateScreen(); - _vm->_system->delayMillis(10); + _system->updateScreen(); + _system->delayMillis(10); } } // Console-related functions -void Mickey::debugCurRoom() { - _vm->_console->DebugPrintf("Current Room = %d\n", _game.iRoom); +void MickeyEngine::debugCurRoom() { + _console->DebugPrintf("Current Room = %d\n", _gameStateMickey.iRoom); - if (_game.iRmObj[_game.iRoom] != IDI_MSA_OBJECT_NONE) { - _vm->_console->DebugPrintf("Object %d is in the room\n", _game.iRmObj[_game.iRoom]); + if (_gameStateMickey.iRmObj[_gameStateMickey.iRoom] != IDI_MSA_OBJECT_NONE) { + _console->DebugPrintf("Object %d is in the room\n", _gameStateMickey.iRmObj[_gameStateMickey.iRoom]); } } -void Mickey::debugGotoRoom(int room) { - _game.iRoom = room; +void MickeyEngine::debugGotoRoom(int room) { + _gameStateMickey.iRoom = room; drawRoom(); } -Mickey::Mickey(PreAgiEngine *vm) : _vm(vm) { - _vm->_console = new Mickey_Console(_vm, this); +MickeyEngine::MickeyEngine(OSystem *syst, const AGIGameDescription *gameDesc) : PreAgiEngine(syst, gameDesc) { + _console = new MickeyConsole(this); } -Mickey::~Mickey() { +MickeyEngine::~MickeyEngine() { + delete _console; } -void Mickey::init() { +void MickeyEngine::init() { uint8 buffer[512]; // clear game struct - memset(&_game, 0, sizeof(_game)); - memset(&_game.iItem, IDI_MSA_OBJECT_NONE, sizeof(_game.iItem)); + memset(&_gameStateMickey, 0, sizeof(_gameStateMickey)); + memset(&_gameStateMickey.iItem, IDI_MSA_OBJECT_NONE, sizeof(_gameStateMickey.iItem)); // read room extended desc flags //readExe(IDO_MSA_ROOM_TEXT, buffer, sizeof(buffer)); - //memcpy(_game.fRmTxt, buffer, sizeof(_game.fRmTxt)); + //memcpy(_gameStateMickey.fRmTxt, buffer, sizeof(_gameStateMickey.fRmTxt)); // read room extended desc offsets readExe(IDO_MSA_ROOM_TEXT_OFFSETS, buffer, sizeof(buffer)); - memcpy(_game.oRmTxt, buffer, sizeof(_game.oRmTxt)); + memcpy(_gameStateMickey.oRmTxt, buffer, sizeof(_gameStateMickey.oRmTxt)); for (int i = 0; i < IDI_MSA_MAX_ROOM; i++) - _game.oRmTxt[i] = buffer[i*2] + 256 * buffer[i*2+1]; + _gameStateMickey.oRmTxt[i] = buffer[i*2] + 256 * buffer[i*2+1]; // read room object indices //readExe(IDO_MSA_ROOM_OBJECT, buffer, sizeof(buffer)); - //memcpy(_game.iRmObj, buffer, sizeof(_game.iRmObj)); + //memcpy(_gameStateMickey.iRmObj, buffer, sizeof(_gameStateMickey.iRmObj)); // read room picture indices //readExe(IDO_MSA_ROOM_PICTURE, buffer, sizeof(buffer)); - //memcpy(_game.iRmPic, buffer, sizeof(_game.iRmPic)); + //memcpy(_gameStateMickey.iRmPic, buffer, sizeof(_gameStateMickey.iRmPic)); // read room menu patch indices readExe(IDO_MSA_ROOM_MENU_FIX, buffer, sizeof(buffer)); - memcpy(_game.nRmMenu, buffer, sizeof(_game.nRmMenu)); + memcpy(_gameStateMickey.nRmMenu, buffer, sizeof(_gameStateMickey.nRmMenu)); // set room picture and room object indices for (int i = 0; i < IDI_MSA_MAX_ROOM; i++) { - _game.iRmPic[i] = i; - _game.iRmObj[i] = -1; + _gameStateMickey.iRmPic[i] = i; + _gameStateMickey.iRmObj[i] = -1; } - _game.iRmPic[IDI_MSA_PIC_SHIP_AIRLOCK] = IDI_MSA_PIC_SHIP_AIRLOCK_0; - _game.iRmObj[IDI_MSA_PIC_EARTH_BATHROOM] = 11; - _game.iRmObj[IDI_MSA_PIC_JUPITER_LAVA] = 21; - _game.iRmObj[IDI_MSA_PIC_JUPITER_ROCK_0] = 20; - _game.iRmObj[IDI_MSA_PIC_JUPITER_ROCK_1] = 19; - _game.iRmObj[IDI_MSA_PIC_EARTH_IN_DOGHOUSE] = 1; + _gameStateMickey.iRmPic[IDI_MSA_PIC_SHIP_AIRLOCK] = IDI_MSA_PIC_SHIP_AIRLOCK_0; + _gameStateMickey.iRmObj[IDI_MSA_PIC_EARTH_BATHROOM] = 11; + _gameStateMickey.iRmObj[IDI_MSA_PIC_JUPITER_LAVA] = 21; + _gameStateMickey.iRmObj[IDI_MSA_PIC_JUPITER_ROCK_0] = 20; + _gameStateMickey.iRmObj[IDI_MSA_PIC_JUPITER_ROCK_1] = 19; + _gameStateMickey.iRmObj[IDI_MSA_PIC_EARTH_IN_DOGHOUSE] = 1; #if 0 // DEBUG - _game.iPlanet = IDI_MSA_PLANET_EARTH; - _game.iRoom = IDI_MSA_PIC_SHIP_CONTROLS; - _game.fHasXtal = true; - _game.nXtals = 9; - _game.fItemUsed[IDI_MSA_ITEM_LETTER] = true; + _gameStateMickey.iPlanet = IDI_MSA_PLANET_EARTH; + _gameStateMickey.iRoom = IDI_MSA_PIC_SHIP_CONTROLS; + _gameStateMickey.fHasXtal = true; + _gameStateMickey.nXtals = 9; + _gameStateMickey.fItemUsed[IDI_MSA_ITEM_LETTER] = true; #endif } -void Mickey::run() { - bool done; +Common::Error MickeyEngine::go() { + init(); // Game intro intro(); // Game loop - while (!_vm->shouldQuit()) { + while (!shouldQuit()) { drawRoom(); - if (_game.fIntro) { - _game.fIntro = false; + if (_gameStateMickey.fIntro) { + _gameStateMickey.fIntro = false; } else { printRoomDesc(); } - if (_game.iRoom == IDI_MSA_PIC_NEPTUNE_GUARD) { - _game.iRoom = IDI_MSA_PIC_NEPTUNE_LEADER; + bool done; + if (_gameStateMickey.iRoom == IDI_MSA_PIC_NEPTUNE_GUARD) { + _gameStateMickey.iRoom = IDI_MSA_PIC_NEPTUNE_LEADER; done = true; } else { done = false; } - while (!done && !_vm->shouldQuit()) { + while (!done && !shouldQuit()) { // Check air supply - if (_game.fSuit) { - _game.nAir -= 1; + if (_gameStateMickey.fSuit) { + _gameStateMickey.nAir -= 1; for (int i = 0; i < 4; i++) { - if (_game.nAir == IDI_MSA_AIR_SUPPLY[i]) { + if (_gameStateMickey.nAir == IDI_MSA_AIR_SUPPLY[i]) { playSound(IDI_MSA_SND_XL30); printExeMsg(IDO_MSA_XL30_SPEAKING); printExeMsg(IDO_MSA_AIR_SUPPLY[i]); if (i == 3) - return; + return Common::kNoError; } } } else { - _game.nAir = 50; // max air supply + _gameStateMickey.nAir = 50; // max air supply } done = checkMenu(); } - _game.nFrame = 0; + _gameStateMickey.nFrame = 0; } gameOver(); -} + return Common::kNoError; } + +} // End of namespace Agi diff --git a/engines/agi/preagi_mickey.h b/engines/agi/preagi_mickey.h index 62981375c6..673839a592 100644 --- a/engines/agi/preagi_mickey.h +++ b/engines/agi/preagi_mickey.h @@ -676,23 +676,25 @@ struct MSA_GAME { class PreAgiEngine; -class Mickey { +class MickeyEngine : public PreAgiEngine { public: - Mickey(PreAgiEngine *vm); - ~Mickey(); + MickeyEngine(OSystem *syst, const AGIGameDescription *gameDesc); + ~MickeyEngine(); void init(); - void run(); + Common::Error go(); void debugCurRoom(); void debugGotoRoom(int); void drawPic(int); void drawObj(ENUM_MSA_OBJECT, int, int); + GUI::Debugger *getDebugger() { return _console; } + protected: - PreAgiEngine *_vm; + MickeyConsole *_console; - MSA_GAME _game; + MSA_GAME _gameStateMickey; bool _clickToMove; int getDat(int); @@ -741,14 +743,14 @@ protected: bool planetIsAlreadyAssigned(int planet) { for (int j = 0; j < IDI_MSA_MAX_PLANET; j++) { - if (_game.iPlanetXtal[j] == planet) + if (_gameStateMickey.iPlanetXtal[j] == planet) return true; } return false; } bool mickeyHasItem(int item) { - if (_game.fItem[item]) { + if (_gameStateMickey.fItem[item]) { printDatMessage(90); // Mickey already has item return true; } else { diff --git a/engines/agi/preagi_troll.cpp b/engines/agi/preagi_troll.cpp index 445a9e34ff..c2e2bef66e 100644 --- a/engines/agi/preagi_troll.cpp +++ b/engines/agi/preagi_troll.cpp @@ -31,32 +31,35 @@ namespace Agi { -Troll::Troll(PreAgiEngine* vm) : _vm(vm) { +TrollEngine::TrollEngine(OSystem *syst, const AGIGameDescription *gameDesc) : PreAgiEngine(syst, gameDesc) { +} + +TrollEngine::~TrollEngine() { } // User Interface -void Troll::pressAnyKey(int col) { - _vm->drawStr(24, col, kColorDefault, IDS_TRO_PRESSANYKEY); - _vm->_gfx->doUpdate(); - _vm->getSelection(kSelAnyKey); +void TrollEngine::pressAnyKey(int col) { + drawStr(24, col, kColorDefault, IDS_TRO_PRESSANYKEY); + _gfx->doUpdate(); + getSelection(kSelAnyKey); } -void Troll::drawMenu(const char *szMenu, int iSel) { - _vm->clearTextArea(); - _vm->drawStr(21, 0, kColorDefault, szMenu); - _vm->drawStr(22 + iSel, 0, kColorDefault, " *"); - _vm->_gfx->doUpdate(); +void TrollEngine::drawMenu(const char *szMenu, int iSel) { + clearTextArea(); + drawStr(21, 0, kColorDefault, szMenu); + drawStr(22 + iSel, 0, kColorDefault, " *"); + _gfx->doUpdate(); } -bool Troll::getMenuSel(const char *szMenu, int *iSel, int nSel) { +bool TrollEngine::getMenuSel(const char *szMenu, int *iSel, int nSel) { Common::Event event; int y; drawMenu(szMenu, *iSel); - while (!_vm->shouldQuit()) { - while (_vm->_system->getEventManager()->pollEvent(event)) { + while (!shouldQuit()) { + while (_system->getEventManager()->pollEvent(event)) { switch (event.type) { case Common::EVENT_RTL: case Common::EVENT_QUIT: @@ -117,8 +120,8 @@ bool Troll::getMenuSel(const char *szMenu, int *iSel, int nSel) { break; } } - _vm->_system->updateScreen(); - _vm->_system->delayMillis(10); + _system->updateScreen(); + _system->delayMillis(10); } return true; @@ -126,18 +129,18 @@ bool Troll::getMenuSel(const char *szMenu, int *iSel, int nSel) { // Graphics -void Troll::drawPic(int iPic, bool f3IsCont, bool clr, bool troll) { - _vm->_picture->setDimensions(IDI_TRO_PIC_WIDTH, IDI_TRO_PIC_HEIGHT); +void TrollEngine::drawPic(int iPic, bool f3IsCont, bool clr, bool troll) { + _picture->setDimensions(IDI_TRO_PIC_WIDTH, IDI_TRO_PIC_HEIGHT); if (clr) { - _vm->clearScreen(0x0f, false); - _vm->_picture->clear(); + clearScreen(0x0f, false); + _picture->clear(); } - _vm->_picture->setPictureData(_gameData + IDO_TRO_FRAMEPIC); - _vm->_picture->drawPicture(); + _picture->setPictureData(_gameData + IDO_TRO_FRAMEPIC); + _picture->drawPicture(); - _vm->_picture->setPictureData(_gameData + _pictureOffsets[iPic]); + _picture->setPictureData(_gameData + _pictureOffsets[iPic]); int addFlag = 0; @@ -145,26 +148,26 @@ void Troll::drawPic(int iPic, bool f3IsCont, bool clr, bool troll) { addFlag = kPicFTrollMode; if (f3IsCont) { - _vm->_picture->setPictureFlags(kPicFf3Cont | addFlag); + _picture->setPictureFlags(kPicFf3Cont | addFlag); } else { - _vm->_picture->setPictureFlags(kPicFf3Stop | addFlag); + _picture->setPictureFlags(kPicFf3Stop | addFlag); } - _vm->_picture->drawPicture(); + _picture->drawPicture(); - _vm->_picture->showPic(); - _vm->_gfx->doUpdate(); + _picture->showPic(); + _gfx->doUpdate(); } // Game Logic -void Troll::inventory() { +void TrollEngine::inventory() { char tmp[40]; int n; - _vm->clearScreen(0x07); - _vm->drawStr(1, 12, kColorDefault, IDS_TRO_TREASURE_0); - _vm->drawStr(2, 12, kColorDefault, IDS_TRO_TREASURE_1); + clearScreen(0x07); + drawStr(1, 12, kColorDefault, IDS_TRO_TREASURE_0); + drawStr(2, 12, kColorDefault, IDS_TRO_TREASURE_1); for (int i = 0; i < IDI_TRO_MAX_TREASURE - _treasuresLeft; i++) { @@ -172,36 +175,36 @@ void Troll::inventory() { sprintf(tmp, " %2d ", i + 1); - _vm->drawStr(2 + i, 10, _items[n].bg << 4 | 0x0f, tmp); - _vm->drawStr(2 + i, 14, _items[n].bg << 4 | _items[n].fg, _items[n].name); + drawStr(2 + i, 10, _items[n].bg << 4 | 0x0f, tmp); + drawStr(2 + i, 14, _items[n].bg << 4 | _items[n].fg, _items[n].name); } switch (_treasuresLeft) { case 1: sprintf(tmp, IDS_TRO_TREASURE_5, _treasuresLeft); - _vm->drawStr(20, 10, kColorDefault, tmp); + drawStr(20, 10, kColorDefault, tmp); break; case 0: - _vm->drawStr(20, 1, kColorDefault, IDS_TRO_TREASURE_6); + drawStr(20, 1, kColorDefault, IDS_TRO_TREASURE_6); break; case IDI_TRO_MAX_TREASURE: - _vm->drawStr(3, 17, kColorDefault, IDS_TRO_TREASURE_2); + drawStr(3, 17, kColorDefault, IDS_TRO_TREASURE_2); default: sprintf(tmp, IDS_TRO_TREASURE_4, _treasuresLeft); - _vm->drawStr(20, 10, kColorDefault, tmp); + drawStr(20, 10, kColorDefault, tmp); break; } pressAnyKey(6); } -void Troll::waitAnyKeyIntro() { +void TrollEngine::waitAnyKeyIntro() { Common::Event event; int iMsg = 0; - while (!_vm->shouldQuit()) { - while (_vm->_system->getEventManager()->pollEvent(event)) { + while (!shouldQuit()) { + while (_system->getEventManager()->pollEvent(event)) { switch (event.type) { case Common::EVENT_RTL: case Common::EVENT_QUIT: @@ -217,26 +220,26 @@ void Troll::waitAnyKeyIntro() { case 200: iMsg = 0; case 0: - _vm->drawStr(22, 3, kColorDefault, IDS_TRO_INTRO_2); - _vm->_gfx->doUpdate(); + drawStr(22, 3, kColorDefault, IDS_TRO_INTRO_2); + _gfx->doUpdate(); break; case 100: - _vm->drawStr(22, 3, kColorDefault, IDS_TRO_INTRO_3); - _vm->_gfx->doUpdate(); + drawStr(22, 3, kColorDefault, IDS_TRO_INTRO_3); + _gfx->doUpdate(); break; } iMsg++; - _vm->_system->updateScreen(); - _vm->_system->delayMillis(10); + _system->updateScreen(); + _system->delayMillis(10); } } -void Troll::credits() { - _vm->clearScreen(0x07); +void TrollEngine::credits() { + clearScreen(0x07); - _vm->drawStr(1, 2, kColorDefault, IDS_TRO_CREDITS_0); + drawStr(1, 2, kColorDefault, IDS_TRO_CREDITS_0); int color = 10; char str[2]; @@ -245,49 +248,49 @@ void Troll::credits() { for (uint i = 0; i < strlen(IDS_TRO_CREDITS_1); i++) { str[0] = IDS_TRO_CREDITS_1[i]; - _vm->drawStr(7, 19 + i, color++, str); + drawStr(7, 19 + i, color++, str); if (color > 15) color = 9; } - _vm->drawStr(8, 19, kColorDefault, IDS_TRO_CREDITS_2); + drawStr(8, 19, kColorDefault, IDS_TRO_CREDITS_2); - _vm->drawStr(13, 11, 9, IDS_TRO_CREDITS_3); - _vm->drawStr(15, 8, 10, IDS_TRO_CREDITS_4); - _vm->drawStr(17, 7, 12, IDS_TRO_CREDITS_5); - _vm->drawStr(19, 2, 14, IDS_TRO_CREDITS_6); + drawStr(13, 11, 9, IDS_TRO_CREDITS_3); + drawStr(15, 8, 10, IDS_TRO_CREDITS_4); + drawStr(17, 7, 12, IDS_TRO_CREDITS_5); + drawStr(19, 2, 14, IDS_TRO_CREDITS_6); - _vm->_gfx->doUpdate(); + _gfx->doUpdate(); pressAnyKey(); } -void Troll::tutorial() { +void TrollEngine::tutorial() { bool done = false; int iSel = 0; //char szTreasure[16] = {0}; - while (!_vm->shouldQuit()) { - _vm->clearScreen(0xFF); + while (!shouldQuit()) { + clearScreen(0xFF); - _vm->printStr(IDS_TRO_TUTORIAL_0); - _vm->getSelection(kSelSpace); + printStr(IDS_TRO_TUTORIAL_0); + getSelection(kSelSpace); - _vm->clearScreen(0x55); - _vm->setDefaultTextColor(0x0F); + clearScreen(0x55); + setDefaultTextColor(0x0F); done = false; - while (!done && !_vm->shouldQuit()) { + while (!done && !shouldQuit()) { getMenuSel(IDS_TRO_TUTORIAL_1, &iSel, IDI_TRO_MAX_OPTION); switch (iSel) { case IDI_TRO_SEL_OPTION_1: - _vm->clearScreen(0x22, false); - _vm->_gfx->doUpdate(); + clearScreen(0x22, false); + _gfx->doUpdate(); break; case IDI_TRO_SEL_OPTION_2: - _vm->clearScreen(0x00, false); - _vm->_gfx->doUpdate(); + clearScreen(0x00, false); + _gfx->doUpdate(); break; case IDI_TRO_SEL_OPTION_3: done = true; @@ -296,102 +299,102 @@ void Troll::tutorial() { } // do you need more practice ? - _vm->clearScreen(0x4F); - _vm->drawStr(7, 4, kColorDefault, IDS_TRO_TUTORIAL_5); - _vm->drawStr(9, 4, kColorDefault, IDS_TRO_TUTORIAL_6); - _vm->_gfx->doUpdate(); + clearScreen(0x4F); + drawStr(7, 4, kColorDefault, IDS_TRO_TUTORIAL_5); + drawStr(9, 4, kColorDefault, IDS_TRO_TUTORIAL_6); + _gfx->doUpdate(); - if (!_vm->getSelection(kSelYesNo)) + if (!getSelection(kSelYesNo)) break; } // show info texts - _vm->clearScreen(0x5F); - _vm->drawStr(4, 1, kColorDefault, IDS_TRO_TUTORIAL_7); - _vm->drawStr(5, 1, kColorDefault, IDS_TRO_TUTORIAL_8); - _vm->_gfx->doUpdate(); + clearScreen(0x5F); + drawStr(4, 1, kColorDefault, IDS_TRO_TUTORIAL_7); + drawStr(5, 1, kColorDefault, IDS_TRO_TUTORIAL_8); + _gfx->doUpdate(); pressAnyKey(); - _vm->clearScreen(0x2F); - _vm->drawStr(6, 1, kColorDefault, IDS_TRO_TUTORIAL_9); - _vm->_gfx->doUpdate(); + clearScreen(0x2F); + drawStr(6, 1, kColorDefault, IDS_TRO_TUTORIAL_9); + _gfx->doUpdate(); pressAnyKey(); - _vm->clearScreen(0x19); - _vm->drawStr(7, 1, kColorDefault, IDS_TRO_TUTORIAL_10); - _vm->drawStr(8, 1, kColorDefault, IDS_TRO_TUTORIAL_11); - _vm->_gfx->doUpdate(); + clearScreen(0x19); + drawStr(7, 1, kColorDefault, IDS_TRO_TUTORIAL_10); + drawStr(8, 1, kColorDefault, IDS_TRO_TUTORIAL_11); + _gfx->doUpdate(); pressAnyKey(); - _vm->clearScreen(0x6E); - _vm->drawStr(9, 1, kColorDefault, IDS_TRO_TUTORIAL_12); - _vm->drawStr(10, 1, kColorDefault, IDS_TRO_TUTORIAL_13); - _vm->_gfx->doUpdate(); + clearScreen(0x6E); + drawStr(9, 1, kColorDefault, IDS_TRO_TUTORIAL_12); + drawStr(10, 1, kColorDefault, IDS_TRO_TUTORIAL_13); + _gfx->doUpdate(); pressAnyKey(); - _vm->clearScreen(0x4C); - _vm->drawStr(11, 1, kColorDefault, IDS_TRO_TUTORIAL_14); - _vm->drawStr(12, 1, kColorDefault, IDS_TRO_TUTORIAL_15); - _vm->_gfx->doUpdate(); + clearScreen(0x4C); + drawStr(11, 1, kColorDefault, IDS_TRO_TUTORIAL_14); + drawStr(12, 1, kColorDefault, IDS_TRO_TUTORIAL_15); + _gfx->doUpdate(); pressAnyKey(); - _vm->clearScreen(0x5D); - _vm->drawStr(13, 1, kColorDefault, IDS_TRO_TUTORIAL_16); - _vm->drawStr(14, 1, kColorDefault, IDS_TRO_TUTORIAL_17); - _vm->drawStr(15, 1, kColorDefault, IDS_TRO_TUTORIAL_18); - _vm->_gfx->doUpdate(); + clearScreen(0x5D); + drawStr(13, 1, kColorDefault, IDS_TRO_TUTORIAL_16); + drawStr(14, 1, kColorDefault, IDS_TRO_TUTORIAL_17); + drawStr(15, 1, kColorDefault, IDS_TRO_TUTORIAL_18); + _gfx->doUpdate(); pressAnyKey(); // show treasures - _vm->clearScreen(0x2A); - _vm->drawStr(2, 1, kColorDefault, IDS_TRO_TUTORIAL_19); + clearScreen(0x2A); + drawStr(2, 1, kColorDefault, IDS_TRO_TUTORIAL_19); for (int i = 0; i < IDI_TRO_MAX_TREASURE; i++) - _vm->drawStr(19 - i, 11, kColorDefault, _items[i].name); + drawStr(19 - i, 11, kColorDefault, _items[i].name); - _vm->_gfx->doUpdate(); + _gfx->doUpdate(); pressAnyKey(); } -void Troll::intro() { +void TrollEngine::intro() { // sierra on-line presents - _vm->clearScreen(0x2F); - _vm->drawStr(9, 10, kColorDefault, IDS_TRO_INTRO_0); - _vm->drawStr(14, 15, kColorDefault, IDS_TRO_INTRO_1); - _vm->_gfx->doUpdate(); - _vm->_system->updateScreen(); - _vm->_system->delayMillis(3200); + clearScreen(0x2F); + drawStr(9, 10, kColorDefault, IDS_TRO_INTRO_0); + drawStr(14, 15, kColorDefault, IDS_TRO_INTRO_1); + _gfx->doUpdate(); + _system->updateScreen(); + _system->delayMillis(3200); CursorMan.showMouse(true); // Draw logo - _vm->setDefaultTextColor(0x0f); + setDefaultTextColor(0x0f); drawPic(45, false, true); - _vm->_gfx->doUpdate(); + _gfx->doUpdate(); // wait for keypress and alternate message waitAnyKeyIntro(); // have you played this game before? - _vm->drawStr(22, 3, kColorDefault, IDS_TRO_INTRO_4); - _vm->drawStr(23, 6, kColorDefault, IDS_TRO_INTRO_5); - _vm->_gfx->doUpdate(); + drawStr(22, 3, kColorDefault, IDS_TRO_INTRO_4); + drawStr(23, 6, kColorDefault, IDS_TRO_INTRO_5); + _gfx->doUpdate(); - if (!_vm->getSelection(kSelYesNo)) + if (!getSelection(kSelYesNo)) tutorial(); credits(); } -void Troll::gameOver() { +void TrollEngine::gameOver() { // We do a check to see if the game should quit. Without this, the game show the picture, plays the // music, and then quits. So if the game is quitting, we shouldn't run the "game over" part. - if (_vm->shouldQuit()) + if (shouldQuit()) return; char szMoves[40]; - _vm->clearTextArea(); + clearTextArea(); drawPic(42, true, true); playTune(4, 25); @@ -400,19 +403,19 @@ void Troll::gameOver() { printUserMessage(33); - _vm->clearTextArea(); + clearTextArea(); drawPic(46, true, true); sprintf(szMoves, IDS_TRO_GAMEOVER_0, _moves); - _vm->drawStr(21, 1, kColorDefault, szMoves); - _vm->drawStr(22, 1, kColorDefault, IDS_TRO_GAMEOVER_1); - _vm->_gfx->doUpdate(); + drawStr(21, 1, kColorDefault, szMoves); + drawStr(22, 1, kColorDefault, IDS_TRO_GAMEOVER_1); + _gfx->doUpdate(); pressAnyKey(); } -void Troll::drawTroll() { +void TrollEngine::drawTroll() { for (int i = 0; i < IDI_TRO_NUM_NONTROLL; i++) if (_currentRoom == _nonTrollRooms[i]) { _isTrollAway = true; @@ -422,14 +425,14 @@ void Troll::drawTroll() { drawPic(43, false, false, true); } -int Troll::drawRoom(char *menu) { +int TrollEngine::drawRoom(char *menu) { int n = 0; bool contFlag = false; if (_currentRoom == 1) { - _vm->_picture->setDimensions(IDI_TRO_PIC_WIDTH, IDI_TRO_PIC_HEIGHT); - _vm->clearScreen(0x00, false); - _vm->_picture->clear(); + _picture->setDimensions(IDI_TRO_PIC_WIDTH, IDI_TRO_PIC_HEIGHT); + clearScreen(0x00, false); + _picture->clear(); } else { if (_currentRoom != 42) { @@ -439,7 +442,7 @@ int Troll::drawRoom(char *menu) { } drawPic(_currentRoom, contFlag, true); - _vm->_gfx->doUpdate(); + _gfx->doUpdate(); if (_currentRoom == 42) { drawPic(44, false, false); // don't clear @@ -450,7 +453,7 @@ int Troll::drawRoom(char *menu) { } } - _vm->_gfx->doUpdate(); + _gfx->doUpdate(); char tmp[10]; strncat(menu, (char*)_gameData + _locMessagesIdx[_currentRoom], 39); @@ -469,7 +472,7 @@ int Troll::drawRoom(char *menu) { return n; } -void Troll::playTune(int tune, int len) { +void TrollEngine::playTune(int tune, int len) { if (!_soundOn) return; @@ -482,34 +485,34 @@ void Troll::playTune(int tune, int len) { duration = READ_LE_UINT16(_gameData + ptr); ptr += 2; - _vm->playNote(freq, duration); + playNote(freq, duration); } } -void Troll::pickupTreasure(int treasureId) { +void TrollEngine::pickupTreasure(int treasureId) { char tmp[40]; _inventory[IDI_TRO_MAX_TREASURE - _treasuresLeft] = treasureId; if (_currentRoom != 24) { - _vm->clearTextArea(); + clearTextArea(); drawPic(_currentRoom, false, true); - _vm->_gfx->doUpdate(); + _gfx->doUpdate(); } printUserMessage(treasureId + 16); - _vm->clearTextArea(); + clearTextArea(); _treasuresLeft--; switch (_treasuresLeft) { case 1: - _vm->drawStr(22, 1, kColorDefault, IDS_TRO_TREASURE_7); + drawStr(22, 1, kColorDefault, IDS_TRO_TREASURE_7); break; case 0: - _vm->drawStr(22, 1, kColorDefault, IDS_TRO_TREASURE_8); - _vm->drawStr(23, 4, kColorDefault, IDS_TRO_TREASURE_9); + drawStr(22, 1, kColorDefault, IDS_TRO_TREASURE_8); + drawStr(23, 4, kColorDefault, IDS_TRO_TREASURE_9); _roomStates[6] = 1; @@ -517,20 +520,20 @@ void Troll::pickupTreasure(int treasureId) { break; default: sprintf(tmp, IDS_TRO_TREASURE_3, _treasuresLeft); - _vm->drawStr(22, 1, kColorDefault, tmp); + drawStr(22, 1, kColorDefault, tmp); break; } pressAnyKey(); } -void Troll::printUserMessage(int msgId) { +void TrollEngine::printUserMessage(int msgId) { int i; - _vm->clearTextArea(); + clearTextArea(); for (i = 0; i < _userMessages[msgId - 1].num; i++) { - _vm->drawStr(21 + i, 1, kColorDefault, _userMessages[msgId - 1].msg[i]); + drawStr(21 + i, 1, kColorDefault, _userMessages[msgId - 1].msg[i]); } if (msgId == 34) { @@ -540,7 +543,7 @@ void Troll::printUserMessage(int msgId) { pressAnyKey(); } -void Troll::gameLoop() { +void TrollEngine::gameLoop() { bool done = false; char menu[160+5]; int currentOption, numberOfOptions; @@ -559,7 +562,7 @@ void Troll::gameLoop() { memset(_inventory, 0, sizeof(_inventory)); - while (!done && !_vm->shouldQuit()) { + while (!done && !shouldQuit()) { *menu = 0; currentOption = 0; @@ -589,7 +592,7 @@ void Troll::gameLoop() { if (_currentRoom < 6 || _treasuresLeft == 0) { _isTrollAway = true; } else { // make odd 1:3 - _isTrollAway = (_vm->rnd(3) != 2); + _isTrollAway = (rnd(3) != 2); } break; case OT_GET: @@ -634,7 +637,7 @@ void Troll::gameLoop() { } -void Troll::fillOffsets() { +void TrollEngine::fillOffsets() { int i; for (i = 0; i < IDI_TRO_PICNUM; i++) @@ -721,8 +724,8 @@ void Troll::fillOffsets() { // Init -void Troll::init() { - _vm->_picture->setPictureVersion(AGIPIC_V15); +void TrollEngine::init() { + _picture->setPictureVersion(AGIPIC_V15); //SetScreenPar(320, 200, (char*)ibm_fontdata); const int gaps[] = { 0x3A40, 0x4600, 0x4800, 0x5800, 0x5a00, 0x6a00, @@ -762,12 +765,16 @@ void Troll::init() { fillOffsets(); } -void Troll::run() { - while (!_vm->shouldQuit()) { +Common::Error TrollEngine::go() { + init(); + + while (!shouldQuit()) { intro(); gameLoop(); gameOver(); } + + return Common::kNoError; } } // End of namespace Agi diff --git a/engines/agi/preagi_troll.h b/engines/agi/preagi_troll.h index d9a995072b..c14a7872c2 100644 --- a/engines/agi/preagi_troll.h +++ b/engines/agi/preagi_troll.h @@ -157,16 +157,14 @@ struct Item { char name[16]; }; -class Troll { +class TrollEngine : public PreAgiEngine { public: - Troll(PreAgiEngine *vm); + TrollEngine(OSystem *syst, const AGIGameDescription *gameDesc); + ~TrollEngine(); - void init(); - void run(); + Common::Error go(); private: - PreAgiEngine *_vm; - int _roomPicture; int _treasuresLeft; int _currentRoom; @@ -180,6 +178,7 @@ private: byte *_gameData; + void init(); void intro(); void drawPic(int iPic, bool f3IsCont, bool clear, bool troll = false); void drawTroll(); @@ -205,9 +204,7 @@ private: void fillOffsets(); -private: // These are come from game data - int _pictureOffsets[IDI_TRO_PICNUM]; int _roomPicStartIdx[IDI_TRO_NUM_NUMROOMS]; int _roomPicDeltas[IDI_TRO_NUM_NUMROOMS]; diff --git a/engines/agi/preagi_winnie.cpp b/engines/agi/preagi_winnie.cpp index af26fe62d0..fee8fde2b3 100644 --- a/engines/agi/preagi_winnie.cpp +++ b/engines/agi/preagi_winnie.cpp @@ -31,9 +31,11 @@ #include "common/savefile.h" #include "common/textconsole.h" +#include "audio/mididrv.h" + namespace Agi { -void Winnie::parseRoomHeader(WTP_ROOM_HDR *roomHdr, byte *buffer, int len) { +void WinnieEngine::parseRoomHeader(WTP_ROOM_HDR *roomHdr, byte *buffer, int len) { int i; Common::MemoryReadStreamEndian readS(buffer, len, _isBigEndian); @@ -68,7 +70,7 @@ void Winnie::parseRoomHeader(WTP_ROOM_HDR *roomHdr, byte *buffer, int len) { roomHdr->opt[i].ofsOpt[j] = readS.readUint16(); } -void Winnie::parseObjHeader(WTP_OBJ_HDR *objHdr, byte *buffer, int len) { +void WinnieEngine::parseObjHeader(WTP_OBJ_HDR *objHdr, byte *buffer, int len) { int i; Common::MemoryReadStreamEndian readS(buffer, len, _isBigEndian); @@ -85,16 +87,16 @@ void Winnie::parseObjHeader(WTP_OBJ_HDR *objHdr, byte *buffer, int len) { objHdr->ofsPic = readS.readUint16(); } -uint32 Winnie::readRoom(int iRoom, uint8 *buffer, WTP_ROOM_HDR &roomHdr) { +uint32 WinnieEngine::readRoom(int iRoom, uint8 *buffer, WTP_ROOM_HDR &roomHdr) { Common::String fileName; - if (_vm->getPlatform() == Common::kPlatformPC) + if (getPlatform() == Common::kPlatformPC) fileName = Common::String::format(IDS_WTP_ROOM_DOS, iRoom); - else if (_vm->getPlatform() == Common::kPlatformAmiga) + else if (getPlatform() == Common::kPlatformAmiga) fileName = Common::String::format(IDS_WTP_ROOM_AMIGA, iRoom); - else if (_vm->getPlatform() == Common::kPlatformC64) + else if (getPlatform() == Common::kPlatformC64) fileName = Common::String::format(IDS_WTP_ROOM_C64, iRoom); - else if (_vm->getPlatform() == Common::kPlatformApple2GS) + else if (getPlatform() == Common::kPlatformApple2GS) fileName = Common::String::format(IDS_WTP_ROOM_APPLE, iRoom); Common::File file; @@ -104,7 +106,7 @@ uint32 Winnie::readRoom(int iRoom, uint8 *buffer, WTP_ROOM_HDR &roomHdr) { } uint32 filelen = file.size(); - if (_vm->getPlatform() == Common::kPlatformC64) { // Skip the loading address + if (getPlatform() == Common::kPlatformC64) { // Skip the loading address filelen -= 2; file.seek(2, SEEK_CUR); } @@ -118,16 +120,16 @@ uint32 Winnie::readRoom(int iRoom, uint8 *buffer, WTP_ROOM_HDR &roomHdr) { return filelen; } -uint32 Winnie::readObj(int iObj, uint8 *buffer) { +uint32 WinnieEngine::readObj(int iObj, uint8 *buffer) { Common::String fileName; - if (_vm->getPlatform() == Common::kPlatformPC) + if (getPlatform() == Common::kPlatformPC) fileName = Common::String::format(IDS_WTP_OBJ_DOS, iObj); - else if (_vm->getPlatform() == Common::kPlatformAmiga) + else if (getPlatform() == Common::kPlatformAmiga) fileName = Common::String::format(IDS_WTP_OBJ_AMIGA, iObj); - else if (_vm->getPlatform() == Common::kPlatformC64) + else if (getPlatform() == Common::kPlatformC64) fileName = Common::String::format(IDS_WTP_OBJ_C64, iObj); - else if (_vm->getPlatform() == Common::kPlatformApple2GS) + else if (getPlatform() == Common::kPlatformApple2GS) fileName = Common::String::format(IDS_WTP_OBJ_APPLE, iObj); Common::File file; @@ -137,7 +139,7 @@ uint32 Winnie::readObj(int iObj, uint8 *buffer) { } uint32 filelen = file.size(); - if (_vm->getPlatform() == Common::kPlatformC64) { // Skip the loading address + if (getPlatform() == Common::kPlatformC64) { // Skip the loading address filelen -= 2; file.seek(2, SEEK_CUR); } @@ -148,7 +150,7 @@ uint32 Winnie::readObj(int iObj, uint8 *buffer) { return filelen; } -void Winnie::randomize() { +void WinnieEngine::randomize() { int iObj = 0; int iRoom = 0; bool done; @@ -157,52 +159,52 @@ void Winnie::randomize() { done = false; while (!done) { - iObj = _vm->rnd(IDI_WTP_MAX_OBJ - 1); + iObj = rnd(IDI_WTP_MAX_OBJ - 1); done = true; for (int j = 0; j < IDI_WTP_MAX_OBJ_MISSING; j++) { - if (_game.iUsedObj[j] == iObj) { + if (_gameStateWinnie.iUsedObj[j] == iObj) { done = false; break; } } } - _game.iUsedObj[i] = iObj; + _gameStateWinnie.iUsedObj[i] = iObj; done = false; while (!done) { - iRoom = _vm->rnd(IDI_WTP_MAX_ROOM_NORMAL); + iRoom = rnd(IDI_WTP_MAX_ROOM_NORMAL); done = true; for (int j = 0; j < IDI_WTP_MAX_ROOM_OBJ; j++) { - if (_game.iObjRoom[j] == iRoom) { + if (_gameStateWinnie.iObjRoom[j] == iRoom) { done = false; break; } } } - _game.iObjRoom[iObj] = iRoom; + _gameStateWinnie.iObjRoom[iObj] = iRoom; } } -void Winnie::intro() { +void WinnieEngine::intro() { drawPic(IDS_WTP_FILE_LOGO); - _vm->printStr(IDS_WTP_INTRO_0); - _vm->_gfx->doUpdate(); - _vm->_system->updateScreen(); - _vm->_system->delayMillis(0x640); + printStr(IDS_WTP_INTRO_0); + _gfx->doUpdate(); + _system->updateScreen(); + _system->delayMillis(0x640); - if (_vm->getPlatform() == Common::kPlatformAmiga) - _vm->_gfx->clearScreen(0); + if (getPlatform() == Common::kPlatformAmiga) + _gfx->clearScreen(0); drawPic(IDS_WTP_FILE_TITLE); - _vm->printStr(IDS_WTP_INTRO_1); - _vm->_gfx->doUpdate(); - _vm->_system->updateScreen(); - _vm->_system->delayMillis(0x640); + printStr(IDS_WTP_INTRO_1); + _gfx->doUpdate(); + _system->updateScreen(); + _system->delayMillis(0x640); if (!playSound(IDI_WTP_SND_POOH_0)) return; @@ -214,27 +216,27 @@ void Winnie::intro() { return; } -int Winnie::getObjInRoom(int iRoom) { +int WinnieEngine::getObjInRoom(int iRoom) { for (int iObj = 1; iObj < IDI_WTP_MAX_ROOM_OBJ; iObj++) - if (_game.iObjRoom[iObj] == iRoom) + if (_gameStateWinnie.iObjRoom[iObj] == iRoom) return iObj; return 0; } -void Winnie::setTakeDrop(int fCanSel[]) { +void WinnieEngine::setTakeDrop(int fCanSel[]) { fCanSel[IDI_WTP_SEL_TAKE] = getObjInRoom(_room); - fCanSel[IDI_WTP_SEL_DROP] = _game.iObjHave; + fCanSel[IDI_WTP_SEL_DROP] = _gameStateWinnie.iObjHave; } -void Winnie::setFlag(int iFlag) { - _game.fGame[iFlag] = 1; +void WinnieEngine::setFlag(int iFlag) { + _gameStateWinnie.fGame[iFlag] = 1; } -void Winnie::clearFlag(int iFlag) { - _game.fGame[iFlag] = 0; +void WinnieEngine::clearFlag(int iFlag) { + _gameStateWinnie.fGame[iFlag] = 0; } -int Winnie::parser(int pc, int index, uint8 *buffer) { +int WinnieEngine::parser(int pc, int index, uint8 *buffer) { WTP_ROOM_HDR hdr; int startpc = pc; int8 opcode; @@ -249,7 +251,7 @@ int Winnie::parser(int pc, int index, uint8 *buffer) { // extract header from buffer parseRoomHeader(&hdr, buffer, sizeof(WTP_ROOM_HDR)); - while (!_vm->shouldQuit()) { + while (!shouldQuit()) { pc = startpc; // check if block is to be run @@ -259,7 +261,7 @@ int Winnie::parser(int pc, int index, uint8 *buffer) { return IDI_WTP_PAR_OK; fBlock = *(buffer + pc++); - if (_game.fGame[iBlock] != fBlock) + if (_gameStateWinnie.fGame[iBlock] != fBlock) return IDI_WTP_PAR_OK; // extract text from block @@ -292,12 +294,12 @@ int Winnie::parser(int pc, int index, uint8 *buffer) { // extract menu string strcpy(szMenu, (char *)(buffer + pc)); - _vm->XOR80(szMenu); + XOR80(szMenu); break; default: // print description printStrWinnie((char *)(buffer + pc)); - if (_vm->getSelection(kSelBackspace) == 1) + if (getSelection(kSelBackspace) == 1) return IDI_WTP_PAR_OK; else return IDI_WTP_PAR_BACK; @@ -314,7 +316,7 @@ int Winnie::parser(int pc, int index, uint8 *buffer) { // get menu selection getMenuSel(szMenu, &iSel, fCanSel); - if (++_game.nMoves == IDI_WTP_MAX_MOVES_UNTIL_WIND) + if (++_gameStateWinnie.nMoves == IDI_WTP_MAX_MOVES_UNTIL_WIND) _doWind = true; if (_winnieEvent && (_room <= IDI_WTP_MAX_ROOM_TELEPORT)) { @@ -356,8 +358,8 @@ int Winnie::parser(int pc, int index, uint8 *buffer) { iDir = iSel - IDI_WTP_SEL_NORTH; if (hdr.roomNew[iDir] == IDI_WTP_ROOM_NONE) { - _vm->printStr(IDS_WTP_CANT_GO); - _vm->getSelection(kSelAnyKey); + printStr(IDS_WTP_CANT_GO); + getSelection(kSelAnyKey); } else { _room = hdr.roomNew[iDir]; return IDI_WTP_PAR_GOTO; @@ -391,7 +393,7 @@ int Winnie::parser(int pc, int index, uint8 *buffer) { case IDO_WTP_PRINT_MSG: opcode = *(buffer + pc++); printRoomStr(_room, opcode); - _vm->getSelection(kSelAnyKey); + getSelection(kSelAnyKey); break; case IDO_WTP_PRINT_STR: opcode = *(buffer + pc++); @@ -416,7 +418,7 @@ int Winnie::parser(int pc, int index, uint8 *buffer) { case IDO_WTP_WALK_MIST: _mist--; if (!_mist) { - _room = _vm->rnd(IDI_WTP_MAX_ROOM_TELEPORT) + 1; + _room = rnd(IDI_WTP_MAX_ROOM_TELEPORT) + 1; return IDI_WTP_PAR_GOTO; } break; @@ -437,13 +439,13 @@ int Winnie::parser(int pc, int index, uint8 *buffer) { showOwlHelp(); break; case IDO_WTP_GOTO_RND: - _room = _vm->rnd(IDI_WTP_MAX_ROOM_TELEPORT) + 1; + _room = rnd(IDI_WTP_MAX_ROOM_TELEPORT) + 1; return IDI_WTP_PAR_GOTO; default: opcode = 0; break; } - } while (opcode && !_vm->shouldQuit()); + } while (opcode && !shouldQuit()); if (iNewRoom) { _room = iNewRoom; @@ -452,38 +454,38 @@ int Winnie::parser(int pc, int index, uint8 *buffer) { if (iBlock == 1) return IDI_WTP_PAR_OK; - _vm->_gfx->doUpdate(); - _vm->_system->updateScreen(); + _gfx->doUpdate(); + _system->updateScreen(); } return IDI_WTP_PAR_OK; } -void Winnie::keyHelp() { +void WinnieEngine::keyHelp() { playSound(IDI_WTP_SND_KEYHELP); - _vm->printStr(IDS_WTP_HELP_0); - _vm->getSelection(kSelAnyKey); - _vm->printStr(IDS_WTP_HELP_1); - _vm->getSelection(kSelAnyKey); + printStr(IDS_WTP_HELP_0); + getSelection(kSelAnyKey); + printStr(IDS_WTP_HELP_1); + getSelection(kSelAnyKey); } -void Winnie::inventory() { - if (_game.iObjHave) - printObjStr(_game.iObjHave, IDI_WTP_OBJ_TAKE); +void WinnieEngine::inventory() { + if (_gameStateWinnie.iObjHave) + printObjStr(_gameStateWinnie.iObjHave, IDI_WTP_OBJ_TAKE); else { - _vm->clearTextArea(); - _vm->drawStr(IDI_WTP_ROW_MENU, IDI_WTP_COL_MENU, IDA_DEFAULT, IDS_WTP_INVENTORY_0); + clearTextArea(); + drawStr(IDI_WTP_ROW_MENU, IDI_WTP_COL_MENU, IDA_DEFAULT, IDS_WTP_INVENTORY_0); } - Common::String missing = Common::String::format(IDS_WTP_INVENTORY_1, _game.nObjMiss); + Common::String missing = Common::String::format(IDS_WTP_INVENTORY_1, _gameStateWinnie.nObjMiss); - _vm->drawStr(IDI_WTP_ROW_OPTION_4, IDI_WTP_COL_MENU, IDA_DEFAULT, missing.c_str()); - _vm->_gfx->doUpdate(); - _vm->_system->updateScreen(); //TODO: Move to game's main loop - _vm->getSelection(kSelAnyKey); + drawStr(IDI_WTP_ROW_OPTION_4, IDI_WTP_COL_MENU, IDA_DEFAULT, missing.c_str()); + _gfx->doUpdate(); + _system->updateScreen(); //TODO: Move to game's main loop + getSelection(kSelAnyKey); } -void Winnie::printObjStr(int iObj, int iStr) { +void WinnieEngine::printObjStr(int iObj, int iStr) { WTP_OBJ_HDR hdr; uint8 *buffer = (uint8 *)malloc(2048); @@ -494,7 +496,7 @@ void Winnie::printObjStr(int iObj, int iStr) { free(buffer); } -bool Winnie::isRightObj(int iRoom, int iObj, int *iCode) { +bool WinnieEngine::isRightObj(int iRoom, int iObj, int *iCode) { WTP_ROOM_HDR roomhdr; WTP_OBJ_HDR objhdr; uint8 *roomdata = (uint8 *)malloc(4096); @@ -517,212 +519,212 @@ bool Winnie::isRightObj(int iRoom, int iObj, int *iCode) { return false; } -void Winnie::takeObj(int iRoom) { - if (_game.iObjHave) { +void WinnieEngine::takeObj(int iRoom) { + if (_gameStateWinnie.iObjHave) { // player is already carrying an object, can't take - _vm->printStr(IDS_WTP_CANT_TAKE); - _vm->getSelection(kSelAnyKey); + printStr(IDS_WTP_CANT_TAKE); + getSelection(kSelAnyKey); } else { // take object int iObj = getObjInRoom(iRoom); - _game.iObjHave = iObj; - _game.iObjRoom[iObj] = 0; + _gameStateWinnie.iObjHave = iObj; + _gameStateWinnie.iObjRoom[iObj] = 0; - _vm->printStr(IDS_WTP_OK); + printStr(IDS_WTP_OK); playSound(IDI_WTP_SND_TAKE); drawRoomPic(); // print object "take" string - printObjStr(_game.iObjHave, IDI_WTP_OBJ_TAKE); - _vm->getSelection(kSelAnyKey); + printObjStr(_gameStateWinnie.iObjHave, IDI_WTP_OBJ_TAKE); + getSelection(kSelAnyKey); // HACK WARNING if (iObj == 18) { - _game.fGame[0x0d] = 1; + _gameStateWinnie.fGame[0x0d] = 1; } } } -void Winnie::dropObj(int iRoom) { +void WinnieEngine::dropObj(int iRoom) { int iCode; if (getObjInRoom(iRoom)) { // there already is an object in the room, can't drop - _vm->printStr(IDS_WTP_CANT_DROP); - _vm->getSelection(kSelAnyKey); + printStr(IDS_WTP_CANT_DROP); + getSelection(kSelAnyKey); } else { // HACK WARNING - if (_game.iObjHave == 18) { - _game.fGame[0x0d] = 0; + if (_gameStateWinnie.iObjHave == 18) { + _gameStateWinnie.fGame[0x0d] = 0; } - if (isRightObj(iRoom, _game.iObjHave, &iCode)) { + if (isRightObj(iRoom, _gameStateWinnie.iObjHave, &iCode)) { // object has been dropped in the right place - _vm->printStr(IDS_WTP_OK); - _vm->getSelection(kSelAnyKey); + printStr(IDS_WTP_OK); + getSelection(kSelAnyKey); playSound(IDI_WTP_SND_DROP_OK); - printObjStr(_game.iObjHave, IDI_WTP_OBJ_DROP); - _vm->getSelection(kSelAnyKey); + printObjStr(_gameStateWinnie.iObjHave, IDI_WTP_OBJ_DROP); + getSelection(kSelAnyKey); // increase amount of objects returned, decrease amount of objects missing - _game.nObjMiss--; - _game.nObjRet++; + _gameStateWinnie.nObjMiss--; + _gameStateWinnie.nObjRet++; // xor the dropped object with 0x80 to signify it has been dropped in the right place for (int i = 0; i < IDI_WTP_MAX_OBJ_MISSING; i++) { - if (_game.iUsedObj[i] == _game.iObjHave) { - _game.iUsedObj[i] ^= 0x80; + if (_gameStateWinnie.iUsedObj[i] == _gameStateWinnie.iObjHave) { + _gameStateWinnie.iUsedObj[i] ^= 0x80; break; } } // set flag according to dropped object's id - _game.fGame[iCode] = 1; + _gameStateWinnie.fGame[iCode] = 1; // player is carrying nothing - _game.iObjHave = 0; + _gameStateWinnie.iObjHave = 0; - if (!_game.nObjMiss) { + if (!_gameStateWinnie.nObjMiss) { // all objects returned, tell player to find party playSound(IDI_WTP_SND_FANFARE); - _vm->printStr(IDS_WTP_GAME_OVER_0); - _vm->getSelection(kSelAnyKey); - _vm->printStr(IDS_WTP_GAME_OVER_1); - _vm->getSelection(kSelAnyKey); + printStr(IDS_WTP_GAME_OVER_0); + getSelection(kSelAnyKey); + printStr(IDS_WTP_GAME_OVER_1); + getSelection(kSelAnyKey); } } else { // drop object in the given room - _game.iObjRoom[_game.iObjHave] = iRoom; + _gameStateWinnie.iObjRoom[_gameStateWinnie.iObjHave] = iRoom; // object has been dropped in the wrong place - _vm->printStr(IDS_WTP_WRONG_PLACE); - _vm->getSelection(kSelAnyKey); + printStr(IDS_WTP_WRONG_PLACE); + getSelection(kSelAnyKey); playSound(IDI_WTP_SND_DROP); drawRoomPic(); - _vm->printStr(IDS_WTP_WRONG_PLACE); - _vm->getSelection(kSelAnyKey); + printStr(IDS_WTP_WRONG_PLACE); + getSelection(kSelAnyKey); // print object description - printObjStr(_game.iObjHave, IDI_WTP_OBJ_DESC); - _vm->getSelection(kSelAnyKey); + printObjStr(_gameStateWinnie.iObjHave, IDI_WTP_OBJ_DESC); + getSelection(kSelAnyKey); - _game.iObjHave = 0; + _gameStateWinnie.iObjHave = 0; } } } -void Winnie::dropObjRnd() { - if (!_game.iObjHave) +void WinnieEngine::dropObjRnd() { + if (!_gameStateWinnie.iObjHave) return; int iRoom = 0; bool done = false; while (!done) { - iRoom = _vm->rnd(IDI_WTP_MAX_ROOM_NORMAL); + iRoom = rnd(IDI_WTP_MAX_ROOM_NORMAL); done = true; if (iRoom == _room) done = false; for (int j = 0; j < IDI_WTP_MAX_ROOM_OBJ; j++) { - if (_game.iObjRoom[j] == iRoom) { + if (_gameStateWinnie.iObjRoom[j] == iRoom) { done = false; } } } - _game.iObjRoom[_game.iObjHave] = iRoom; - _game.iObjHave = 0; + _gameStateWinnie.iObjRoom[_gameStateWinnie.iObjHave] = iRoom; + _gameStateWinnie.iObjHave = 0; } -void Winnie::wind() { +void WinnieEngine::wind() { int iRoom = 0; bool done; _doWind = 0; - _game.nMoves = 0; - if (!_game.nObjMiss) + _gameStateWinnie.nMoves = 0; + if (!_gameStateWinnie.nObjMiss) return; - _vm->printStr(IDS_WTP_WIND_0); + printStr(IDS_WTP_WIND_0); playSound(IDI_WTP_SND_WIND_0); - _vm->getSelection(kSelAnyKey); + getSelection(kSelAnyKey); - _vm->printStr(IDS_WTP_WIND_1); + printStr(IDS_WTP_WIND_1); playSound(IDI_WTP_SND_WIND_0); - _vm->getSelection(kSelAnyKey); + getSelection(kSelAnyKey); dropObjRnd(); // randomize positions of objects at large for (int i = 0; i < IDI_WTP_MAX_OBJ_MISSING; i++) { - if (!(_game.iUsedObj[i] & IDI_XOR_KEY)) { + if (!(_gameStateWinnie.iUsedObj[i] & IDI_XOR_KEY)) { done = false; while (!done) { - iRoom = _vm->rnd(IDI_WTP_MAX_ROOM_NORMAL); + iRoom = rnd(IDI_WTP_MAX_ROOM_NORMAL); done = true; for (int j = 0; j < IDI_WTP_MAX_ROOM_OBJ; j++) { - if (_game.iObjRoom[j] == iRoom) { + if (_gameStateWinnie.iObjRoom[j] == iRoom) { done = false; } } } - _game.iObjRoom[_game.iUsedObj[i]] = iRoom; + _gameStateWinnie.iObjRoom[_gameStateWinnie.iUsedObj[i]] = iRoom; } } } -void Winnie::mist() { +void WinnieEngine::mist() { // mist length in turns is (2-5) - _mist = _vm->rnd(4) + 2; + _mist = rnd(4) + 2; _room = IDI_WTP_ROOM_MIST; drawRoomPic(); - _vm->printStr(IDS_WTP_MIST); + printStr(IDS_WTP_MIST); } -void Winnie::tigger() { +void WinnieEngine::tigger() { _room = IDI_WTP_ROOM_TIGGER; drawRoomPic(); - _vm->printStr(IDS_WTP_TIGGER); + printStr(IDS_WTP_TIGGER); dropObjRnd(); } -void Winnie::showOwlHelp() { - if (_game.iObjHave) { - _vm->printStr(IDS_WTP_OWL_0); - _vm->getSelection(kSelAnyKey); - printObjStr(_game.iObjHave, IDI_WTP_OBJ_HELP); - _vm->getSelection(kSelAnyKey); +void WinnieEngine::showOwlHelp() { + if (_gameStateWinnie.iObjHave) { + printStr(IDS_WTP_OWL_0); + getSelection(kSelAnyKey); + printObjStr(_gameStateWinnie.iObjHave, IDI_WTP_OBJ_HELP); + getSelection(kSelAnyKey); } if (getObjInRoom(_room)) { - _vm->printStr(IDS_WTP_OWL_0); - _vm->getSelection(kSelAnyKey); + printStr(IDS_WTP_OWL_0); + getSelection(kSelAnyKey); printObjStr(getObjInRoom(_room), IDI_WTP_OBJ_HELP); - _vm->getSelection(kSelAnyKey); + getSelection(kSelAnyKey); } } -void Winnie::drawMenu(char *szMenu, int iSel, int fCanSel[]) { +void WinnieEngine::drawMenu(char *szMenu, int iSel, int fCanSel[]) { int iRow = 0, iCol = 0; - _vm->clearTextArea(); - _vm->drawStr(IDI_WTP_ROW_MENU, IDI_WTP_COL_MENU, IDA_DEFAULT, szMenu); + clearTextArea(); + drawStr(IDI_WTP_ROW_MENU, IDI_WTP_COL_MENU, IDA_DEFAULT, szMenu); if (fCanSel[IDI_WTP_SEL_NORTH]) - _vm->drawStr(IDI_WTP_ROW_OPTION_4, IDI_WTP_COL_NSEW, IDA_DEFAULT, IDS_WTP_NSEW); + drawStr(IDI_WTP_ROW_OPTION_4, IDI_WTP_COL_NSEW, IDA_DEFAULT, IDS_WTP_NSEW); if (fCanSel[IDI_WTP_SEL_TAKE]) - _vm->drawStr(IDI_WTP_ROW_OPTION_4, IDI_WTP_COL_TAKE, IDA_DEFAULT, IDS_WTP_TAKE); + drawStr(IDI_WTP_ROW_OPTION_4, IDI_WTP_COL_TAKE, IDA_DEFAULT, IDS_WTP_TAKE); if (fCanSel[IDI_WTP_SEL_DROP]) - _vm->drawStr(IDI_WTP_ROW_OPTION_4, IDI_WTP_COL_DROP, IDA_DEFAULT, IDS_WTP_DROP); + drawStr(IDI_WTP_ROW_OPTION_4, IDI_WTP_COL_DROP, IDA_DEFAULT, IDS_WTP_DROP); switch (iSel) { case IDI_WTP_SEL_OPT_1: @@ -756,26 +758,26 @@ void Winnie::drawMenu(char *szMenu, int iSel, int fCanSel[]) { iCol = IDI_WTP_COL_DROP; break; } - _vm->drawStr(iRow, iCol - 1, IDA_DEFAULT, ">"); - _vm->_gfx->doUpdate(); - _vm->_system->updateScreen(); //TODO: Move to game's main loop + drawStr(iRow, iCol - 1, IDA_DEFAULT, ">"); + _gfx->doUpdate(); + _system->updateScreen(); //TODO: Move to game's main loop } -void Winnie::incMenuSel(int *iSel, int fCanSel[]) { +void WinnieEngine::incMenuSel(int *iSel, int fCanSel[]) { do { *iSel += 1; if (*iSel > IDI_WTP_SEL_DROP) *iSel = IDI_WTP_SEL_OPT_1; } while (!fCanSel[*iSel]); } -void Winnie::decMenuSel(int *iSel, int fCanSel[]) { +void WinnieEngine::decMenuSel(int *iSel, int fCanSel[]) { do { *iSel -= 1; if (*iSel < IDI_WTP_SEL_OPT_1) *iSel = IDI_WTP_SEL_DROP; } while (!fCanSel[*iSel]); } -void Winnie::getMenuMouseSel(int *iSel, int fCanSel[], int x, int y) { +void WinnieEngine::getMenuMouseSel(int *iSel, int fCanSel[], int x, int y) { switch (y) { case IDI_WTP_ROW_OPTION_1: case IDI_WTP_ROW_OPTION_2: @@ -793,7 +795,7 @@ void Winnie::getMenuMouseSel(int *iSel, int fCanSel[], int x, int y) { } } -void Winnie::makeSel(int *iSel, int fCanSel[]) { +void WinnieEngine::makeSel(int *iSel, int fCanSel[]) { if (fCanSel[*iSel]) return; @@ -801,7 +803,7 @@ void Winnie::makeSel(int *iSel, int fCanSel[]) { clrMenuSel(iSel, fCanSel); } -void Winnie::getMenuSel(char *szMenu, int *iSel, int fCanSel[]) { +void WinnieEngine::getMenuSel(char *szMenu, int *iSel, int fCanSel[]) { Common::Event event; int x, y; @@ -811,8 +813,8 @@ void Winnie::getMenuSel(char *szMenu, int *iSel, int fCanSel[]) { // Show the mouse cursor for the menu CursorMan.showMouse(true); - while (!_vm->shouldQuit()) { - while (_vm->_system->getEventManager()->pollEvent(event)) { + while (!shouldQuit()) { + while (_system->getEventManager()->pollEvent(event)) { switch (event.type) { case Common::EVENT_RTL: case Common::EVENT_QUIT: @@ -824,15 +826,15 @@ void Winnie::getMenuSel(char *szMenu, int *iSel, int fCanSel[]) { // Change cursor if (fCanSel[IDI_WTP_SEL_NORTH] && hotspotNorth.contains(event.mouse.x, event.mouse.y)) { - _vm->_gfx->setCursorPalette(true); + _gfx->setCursorPalette(true); } else if (fCanSel[IDI_WTP_SEL_SOUTH] && hotspotSouth.contains(event.mouse.x, event.mouse.y)) { - _vm->_gfx->setCursorPalette(true); + _gfx->setCursorPalette(true); } else if (fCanSel[IDI_WTP_SEL_WEST] && hotspotWest.contains(event.mouse.x, event.mouse.y)) { - _vm->_gfx->setCursorPalette(true); + _gfx->setCursorPalette(true); } else if (fCanSel[IDI_WTP_SEL_EAST] && hotspotEast.contains(event.mouse.x, event.mouse.y)) { - _vm->_gfx->setCursorPalette(true); + _gfx->setCursorPalette(true); } else { - _vm->_gfx->setCursorPalette(false); + _gfx->setCursorPalette(false); } break; @@ -841,25 +843,25 @@ void Winnie::getMenuSel(char *szMenu, int *iSel, int fCanSel[]) { if (fCanSel[IDI_WTP_SEL_NORTH] && hotspotNorth.contains(event.mouse.x, event.mouse.y)) { *iSel = IDI_WTP_SEL_NORTH; makeSel(iSel, fCanSel); - _vm->_gfx->setCursorPalette(false); + _gfx->setCursorPalette(false); return; } else if (fCanSel[IDI_WTP_SEL_SOUTH] && hotspotSouth.contains(event.mouse.x, event.mouse.y)) { *iSel = IDI_WTP_SEL_SOUTH; makeSel(iSel, fCanSel); - _vm->_gfx->setCursorPalette(false); + _gfx->setCursorPalette(false); return; } else if (fCanSel[IDI_WTP_SEL_WEST] && hotspotWest.contains(event.mouse.x, event.mouse.y)) { *iSel = IDI_WTP_SEL_WEST; makeSel(iSel, fCanSel); - _vm->_gfx->setCursorPalette(false); + _gfx->setCursorPalette(false); return; } else if (fCanSel[IDI_WTP_SEL_EAST] && hotspotEast.contains(event.mouse.x, event.mouse.y)) { *iSel = IDI_WTP_SEL_EAST; makeSel(iSel, fCanSel); - _vm->_gfx->setCursorPalette(false); + _gfx->setCursorPalette(false); return; } else { - _vm->_gfx->setCursorPalette(false); + _gfx->setCursorPalette(false); } switch (*iSel) { @@ -896,9 +898,9 @@ void Winnie::getMenuSel(char *szMenu, int *iSel, int fCanSel[]) { incMenuSel(iSel, fCanSel); break; case Common::EVENT_KEYDOWN: - if (event.kbd.keycode == Common::KEYCODE_d && (event.kbd.flags & Common::KBD_CTRL) && _vm->_console) { - _vm->_console->attach(); - _vm->_console->onFrame(); + if (event.kbd.keycode == Common::KEYCODE_d && (event.kbd.flags & Common::KBD_CTRL) && _console) { + _console->attach(); + _console->onFrame(); continue; } @@ -944,7 +946,7 @@ void Winnie::getMenuSel(char *szMenu, int *iSel, int fCanSel[]) { break; case Common::KEYCODE_s: if (event.kbd.flags & Common::KBD_CTRL) { - _vm->flipflag(fSoundOn); + flipflag(fSoundOn); } else { *iSel = IDI_WTP_SEL_SOUTH; makeSel(iSel, fCanSel); @@ -1005,24 +1007,24 @@ void Winnie::getMenuSel(char *szMenu, int *iSel, int fCanSel[]) { } } -void Winnie::gameLoop() { +void WinnieEngine::gameLoop() { WTP_ROOM_HDR hdr; uint8 *roomdata = (uint8 *)malloc(4096); int iBlock; phase0: - if (!_game.nObjMiss && (_room == IDI_WTP_ROOM_PICNIC)) + if (!_gameStateWinnie.nObjMiss && (_room == IDI_WTP_ROOM_PICNIC)) _room = IDI_WTP_ROOM_PARTY; readRoom(_room, roomdata, hdr); drawRoomPic(); - _vm->_gfx->doUpdate(); - _vm->_system->updateScreen(); + _gfx->doUpdate(); + _system->updateScreen(); phase1: if (getObjInRoom(_room)) { printObjStr(getObjInRoom(_room), IDI_WTP_OBJ_DESC); - _vm->getSelection(kSelAnyKey); + getSelection(kSelAnyKey); } phase2: @@ -1031,7 +1033,7 @@ phase2: goto phase1; } - while (!_vm->shouldQuit()) { + while (!shouldQuit()) { for (iBlock = 0; iBlock < IDI_WTP_MAX_BLOCK; iBlock++) { switch (parser(hdr.ofsBlock[iBlock] - _roomOffset, iBlock, roomdata)) { case IDI_WTP_PAR_GOTO: @@ -1047,10 +1049,10 @@ phase2: free(roomdata); } -void Winnie::drawPic(const char *szName) { +void WinnieEngine::drawPic(const char *szName) { Common::String fileName = szName; - if (_vm->getPlatform() != Common::kPlatformAmiga) + if (getPlatform() != Common::kPlatformAmiga) fileName += ".pic"; Common::File file; @@ -1065,13 +1067,13 @@ void Winnie::drawPic(const char *szName) { file.read(buffer, size); file.close(); - _vm->_picture->decodePicture(buffer, size, 1, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT); - _vm->_picture->showPic(IDI_WTP_PIC_X0, IDI_WTP_PIC_Y0, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT); + _picture->decodePicture(buffer, size, 1, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT); + _picture->showPic(IDI_WTP_PIC_X0, IDI_WTP_PIC_Y0, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT); free(buffer); } -void Winnie::drawObjPic(int iObj, int x0, int y0) { +void WinnieEngine::drawObjPic(int iObj, int x0, int y0) { if (!iObj) return; @@ -1080,28 +1082,28 @@ void Winnie::drawObjPic(int iObj, int x0, int y0) { uint32 objSize = readObj(iObj, buffer); parseObjHeader(&objhdr, buffer, sizeof(WTP_OBJ_HDR)); - _vm->_picture->setOffset(x0, y0); - _vm->_picture->decodePicture(buffer + objhdr.ofsPic - _objOffset, objSize, 0, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT); - _vm->_picture->setOffset(0, 0); - _vm->_picture->showPic(10, 0, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT); + _picture->setOffset(x0, y0); + _picture->decodePicture(buffer + objhdr.ofsPic - _objOffset, objSize, 0, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT); + _picture->setOffset(0, 0); + _picture->showPic(10, 0, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT); free(buffer); } -void Winnie::drawRoomPic() { +void WinnieEngine::drawRoomPic() { WTP_ROOM_HDR roomhdr; uint8 *buffer = (uint8 *)malloc(4096); int iObj = getObjInRoom(_room); // clear gfx screen - _vm->_gfx->clearScreen(0); + _gfx->clearScreen(0); // read room picture readRoom(_room, buffer, roomhdr); // draw room picture - _vm->_picture->decodePicture(buffer + roomhdr.ofsPic - _roomOffset, 4096, 1, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT); - _vm->_picture->showPic(IDI_WTP_PIC_X0, IDI_WTP_PIC_Y0, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT); + _picture->decodePicture(buffer + roomhdr.ofsPic - _roomOffset, 4096, 1, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT); + _picture->showPic(IDI_WTP_PIC_X0, IDI_WTP_PIC_Y0, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT); // draw object picture drawObjPic(iObj, IDI_WTP_PIC_X0 + roomhdr.objX, IDI_WTP_PIC_Y0 + roomhdr.objY); @@ -1109,21 +1111,68 @@ void Winnie::drawRoomPic() { free(buffer); } -bool Winnie::playSound(ENUM_WTP_SOUND iSound) { - //TODO - warning ("STUB: playSound(%d)", iSound); - return 1; +bool WinnieEngine::playSound(ENUM_WTP_SOUND iSound) { + // TODO: Only DOS sound is supported, currently + if (getPlatform() != Common::kPlatformPC) { + warning("STUB: playSound(%d)", iSound); + return false; + } + + Common::String fileName = Common::String::format(IDS_WTP_SND_DOS, iSound); + + Common::File file; + if (!file.open(fileName)) + return false; + + uint32 size = file.size(); + byte *data = new byte[size]; + file.read(data, size); + file.close(); + + _game.sounds[0] = AgiSound::createFromRawResource(data, size, 0, *_sound, _soundemu); + _sound->startSound(0, 0); + + bool cursorShowing = CursorMan.showMouse(false); + _system->updateScreen(); + + // Loop until the sound is done + bool skippedSound = false; + while (!shouldQuit() && _game.sounds[0]->isPlaying()) { + Common::Event event; + while (_system->getEventManager()->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_KEYDOWN: + _sound->stopSound(); + skippedSound = true; + break; + default: + break; + } + } + + _system->delayMillis(10); + } + + if (cursorShowing) { + CursorMan.showMouse(true); + _system->updateScreen(); + } + + delete _game.sounds[0]; + _game.sounds[0] = 0; + + return !shouldQuit() && !skippedSound; } -void Winnie::clrMenuSel(int *iSel, int fCanSel[]) { +void WinnieEngine::clrMenuSel(int *iSel, int fCanSel[]) { *iSel = IDI_WTP_SEL_OPT_1; while (!fCanSel[*iSel]) { *iSel += 1; } - _vm->_gfx->setCursorPalette(false); + _gfx->setCursorPalette(false); } -void Winnie::printRoomStr(int iRoom, int iStr) { +void WinnieEngine::printRoomStr(int iRoom, int iStr) { WTP_ROOM_HDR hdr; uint8 *buffer = (uint8 *)malloc(4096); @@ -1133,23 +1182,23 @@ void Winnie::printRoomStr(int iRoom, int iStr) { free(buffer); } -void Winnie::gameOver() { +void WinnieEngine::gameOver() { // sing the Pooh song forever - while (!_vm->shouldQuit()) { - _vm->printStr(IDS_WTP_SONG_0); + while (!shouldQuit()) { + printStr(IDS_WTP_SONG_0); playSound(IDI_WTP_SND_POOH_0); - _vm->printStr(IDS_WTP_SONG_1); + printStr(IDS_WTP_SONG_1); playSound(IDI_WTP_SND_POOH_1); - _vm->printStr(IDS_WTP_SONG_2); + printStr(IDS_WTP_SONG_2); playSound(IDI_WTP_SND_POOH_2); - _vm->getSelection(kSelAnyKey); + getSelection(kSelAnyKey); } } -void Winnie::saveGame() { +void WinnieEngine::saveGame() { int i = 0; - Common::OutSaveFile *outfile = _vm->getSaveFileMan()->openForSaving(IDS_WTP_FILE_SAVEGAME); + Common::OutSaveFile *outfile = getSaveFileMan()->openForSaving(IDS_WTP_FILE_SAVEGAME); if (!outfile) return; @@ -1157,20 +1206,20 @@ void Winnie::saveGame() { outfile->writeUint32BE(MKTAG('W','I','N','N')); // header outfile->writeByte(WTP_SAVEGAME_VERSION); - outfile->writeByte(_game.fSound); - outfile->writeByte(_game.nMoves); - outfile->writeByte(_game.nObjMiss); - outfile->writeByte(_game.nObjRet); - outfile->writeByte(_game.iObjHave); + outfile->writeByte(_gameStateWinnie.fSound); + outfile->writeByte(_gameStateWinnie.nMoves); + outfile->writeByte(_gameStateWinnie.nObjMiss); + outfile->writeByte(_gameStateWinnie.nObjRet); + outfile->writeByte(_gameStateWinnie.iObjHave); for (i = 0; i < IDI_WTP_MAX_FLAG; i++) - outfile->writeByte(_game.fGame[i]); + outfile->writeByte(_gameStateWinnie.fGame[i]); for (i = 0; i < IDI_WTP_MAX_OBJ_MISSING; i++) - outfile->writeByte(_game.iUsedObj[i]); + outfile->writeByte(_gameStateWinnie.iUsedObj[i]); for (i = 0; i < IDI_WTP_MAX_ROOM_OBJ; i++) - outfile->writeByte(_game.iObjRoom[i]); + outfile->writeByte(_gameStateWinnie.iObjRoom[i]); outfile->finalize(); @@ -1180,11 +1229,11 @@ void Winnie::saveGame() { delete outfile; } -void Winnie::loadGame() { +void WinnieEngine::loadGame() { int saveVersion = 0; int i = 0; - Common::InSaveFile *infile = _vm->getSaveFileMan()->openForLoading(IDS_WTP_FILE_SAVEGAME); + Common::InSaveFile *infile = getSaveFileMan()->openForLoading(IDS_WTP_FILE_SAVEGAME); if (!infile) return; @@ -1194,11 +1243,11 @@ void Winnie::loadGame() { if (saveVersion != WTP_SAVEGAME_VERSION) warning("Old save game version (%d, current version is %d). Will try and read anyway, but don't be surprised if bad things happen", saveVersion, WTP_SAVEGAME_VERSION); - _game.fSound = infile->readByte(); - _game.nMoves = infile->readByte(); - _game.nObjMiss = infile->readByte(); - _game.nObjRet = infile->readByte(); - _game.iObjHave = infile->readByte(); + _gameStateWinnie.fSound = infile->readByte(); + _gameStateWinnie.nMoves = infile->readByte(); + _gameStateWinnie.nObjMiss = infile->readByte(); + _gameStateWinnie.nObjRet = infile->readByte(); + _gameStateWinnie.iObjHave = infile->readByte(); } else { // This is probably a save from the original interpreter, throw a warning and attempt // to read it as LE @@ -1211,31 +1260,31 @@ void Winnie::loadGame() { infile->readUint16LE(); // skip unused field infile->readByte(); // first 8 bits of fSound - _game.fSound = infile->readByte(); + _gameStateWinnie.fSound = infile->readByte(); infile->readByte(); // first 8 bits of nMoves - _game.nMoves = infile->readByte(); + _gameStateWinnie.nMoves = infile->readByte(); infile->readByte(); // first 8 bits of nObjMiss - _game.nObjMiss = infile->readByte(); + _gameStateWinnie.nObjMiss = infile->readByte(); infile->readByte(); // first 8 bits of nObjRet - _game.nObjRet = infile->readByte(); + _gameStateWinnie.nObjRet = infile->readByte(); infile->readUint16LE(); // skip unused field infile->readUint16LE(); // skip unused field infile->readUint16LE(); // skip unused field infile->readByte(); // first 8 bits of iObjHave - _game.iObjHave = infile->readByte(); + _gameStateWinnie.iObjHave = infile->readByte(); infile->readUint16LE(); // skip unused field infile->readUint16LE(); // skip unused field infile->readUint16LE(); // skip unused field } for (i = 0; i < IDI_WTP_MAX_FLAG; i++) - _game.fGame[i] = infile->readByte(); + _gameStateWinnie.fGame[i] = infile->readByte(); for (i = 0; i < IDI_WTP_MAX_OBJ_MISSING; i++) - _game.iUsedObj[i] = infile->readByte(); + _gameStateWinnie.iUsedObj[i] = infile->readByte(); for (i = 0; i < IDI_WTP_MAX_ROOM_OBJ; i++) - _game.iObjRoom[i] = infile->readByte(); + _gameStateWinnie.iObjRoom[i] = infile->readByte(); // Note that saved games from the original interpreter have 2 more 16-bit fields here // which are ignored @@ -1243,37 +1292,59 @@ void Winnie::loadGame() { delete infile; } -void Winnie::printStrWinnie(char *szMsg) { - if (_vm->getPlatform() != Common::kPlatformAmiga) - _vm->printStrXOR(szMsg); +void WinnieEngine::printStrWinnie(char *szMsg) { + if (getPlatform() != Common::kPlatformAmiga) + printStrXOR(szMsg); else - _vm->printStr(szMsg); + printStr(szMsg); } // Console-related functions -void Winnie::debugCurRoom() { - _vm->_console->DebugPrintf("Current Room = %d\n", _room); +void WinnieEngine::debugCurRoom() { + _console->DebugPrintf("Current Room = %d\n", _room); +} + +WinnieEngine::WinnieEngine(OSystem *syst, const AGIGameDescription *gameDesc) : PreAgiEngine(syst, gameDesc) { + _console = new WinnieConsole(this); } -Winnie::Winnie(PreAgiEngine* vm) : _vm(vm) { - _vm->_console = new Winnie_Console(_vm, this); +WinnieEngine::~WinnieEngine() { + delete _console; } -void Winnie::init() { - memset(&_game, 0, sizeof(_game)); - _game.fSound = 1; - _game.nObjMiss = IDI_WTP_MAX_OBJ_MISSING; - _game.nObjRet = 0; - _game.fGame[0] = 1; - _game.fGame[1] = 1; +void WinnieEngine::init() { + // Initialize sound + + switch (MidiDriver::getMusicType(MidiDriver::detectDevice(MDT_PCSPK|MDT_PCJR))) { + case MT_PCSPK: + _soundemu = SOUND_EMU_PC; + break; + case MT_PCJR: + _soundemu = SOUND_EMU_PCJR; + break; + default: + _soundemu = SOUND_EMU_NONE; + break; + } + + _sound = new SoundMgr(this, _mixer); + _sound->initSound(); + setflag(fSoundOn, true); // enable sound + + memset(&_gameStateWinnie, 0, sizeof(_gameStateWinnie)); + _gameStateWinnie.fSound = 1; + _gameStateWinnie.nObjMiss = IDI_WTP_MAX_OBJ_MISSING; + _gameStateWinnie.nObjRet = 0; + _gameStateWinnie.fGame[0] = 1; + _gameStateWinnie.fGame[1] = 1; _room = IDI_WTP_ROOM_HOME; _mist = -1; _doWind = false; _winnieEvent = false; - if (_vm->getPlatform() != Common::kPlatformAmiga) { + if (getPlatform() != Common::kPlatformAmiga) { _isBigEndian = false; _roomOffset = IDI_WTP_OFS_ROOM; _objOffset = IDI_WTP_OFS_OBJ; @@ -1283,8 +1354,8 @@ void Winnie::init() { _objOffset = 0; } - if (_vm->getPlatform() == Common::kPlatformC64 || _vm->getPlatform() == Common::kPlatformApple2GS) - _vm->_picture->setPictureVersion(AGIPIC_C64); + if (getPlatform() == Common::kPlatformC64 || getPlatform() == Common::kPlatformApple2GS) + _picture->setPictureVersion(AGIPIC_C64); hotspotNorth = Common::Rect(20, 0, (IDI_WTP_PIC_WIDTH + 10) * 2, 10); hotspotSouth = Common::Rect(20, IDI_WTP_PIC_HEIGHT - 10, (IDI_WTP_PIC_WIDTH + 10) * 2, IDI_WTP_PIC_HEIGHT); @@ -1292,11 +1363,17 @@ void Winnie::init() { hotspotWest = Common::Rect(20, 0, 30, IDI_WTP_PIC_HEIGHT); } -void Winnie::run() { +Common::Error WinnieEngine::go() { + init(); randomize(); - if (_vm->getPlatform() != Common::kPlatformC64 && _vm->getPlatform() != Common::kPlatformApple2GS) + + // The intro is not supported on these platforms yet + if (getPlatform() != Common::kPlatformC64 && getPlatform() != Common::kPlatformApple2GS) intro(); + gameLoop(); -} + return Common::kNoError; } + +} // End of namespace AGI diff --git a/engines/agi/preagi_winnie.h b/engines/agi/preagi_winnie.h index 07a1a13e2e..96ae65997e 100644 --- a/engines/agi/preagi_winnie.h +++ b/engines/agi/preagi_winnie.h @@ -281,19 +281,22 @@ struct WTP_SAVE_GAME { class PreAgiEngine; -class Winnie { +class WinnieEngine : public PreAgiEngine { public: - Winnie(PreAgiEngine *vm); + WinnieEngine(OSystem *syst, const AGIGameDescription *gameDesc); + ~WinnieEngine(); void init(); - void run(); + Common::Error go(); void debugCurRoom(); + GUI::Debugger *getDebugger() { return _console; } + private: - PreAgiEngine *_vm; + WinnieConsole *_console; - WTP_SAVE_GAME _game; + WTP_SAVE_GAME _gameStateWinnie; int _room; int _mist; bool _doWind; diff --git a/engines/agi/saveload.cpp b/engines/agi/saveload.cpp index f0d976bbbb..28dd0a53dd 100644 --- a/engines/agi/saveload.cpp +++ b/engines/agi/saveload.cpp @@ -474,8 +474,8 @@ int AgiEngine::loadGame(const char *fileName, bool checkId) { v->cycleTimeCount = in->readByte(); v->direction = in->readByte(); - v->motion = in->readByte(); - v->cycle = in->readByte(); + v->motion = (MotionType)in->readByte(); + v->cycle = (CycleType)in->readByte(); v->priority = in->readByte(); v->flags = in->readUint16BE(); diff --git a/engines/agi/sound.cpp b/engines/agi/sound.cpp index f2d7af32da..ca3d799ecc 100644 --- a/engines/agi/sound.cpp +++ b/engines/agi/sound.cpp @@ -41,6 +41,10 @@ AgiSound *AgiSound::createFromRawResource(uint8 *data, uint32 len, int resnum, S return NULL; uint16 type = READ_LE_UINT16(data); + // For V1 sound resources + if (type != AGI_SOUND_SAMPLE && (type & 0xFF) == 0x01) + return new PCjrSound(data, len, resnum, manager); + switch (type) { // Create a sound object based on the type case AGI_SOUND_SAMPLE: return new IIgsSample(data, len, resnum, manager); @@ -62,6 +66,11 @@ PCjrSound::PCjrSound(uint8 *data, uint32 len, int resnum, SoundMgr &manager) : A _data = data; // Save the resource pointer _len = len; // Save the resource's length _type = READ_LE_UINT16(data); // Read sound resource's type + + // Detect V1 sound resources + if ((_type & 0xFF) == 0x01) + _type = AGI_SOUND_4CHN; + _isValid = (_type == AGI_SOUND_4CHN) && (_data != NULL) && (_len >= 2); if (!_isValid) // Check for errors @@ -127,7 +136,12 @@ void SoundMgr::startSound(int resnum, int flag) { // Reset the flag _endflag = flag; - _vm->setflag(_endflag, false); + + if (_vm->getVersion() < 0x2000) { + _vm->_game.vars[_endflag] = 0; + } else { + _vm->setflag(_endflag, false); + } } void SoundMgr::stopSound() { @@ -142,8 +156,13 @@ void SoundMgr::stopSound() { // This is probably not needed most of the time, but there also should // not be any harm doing it, so do it anyway. - if (_endflag != -1) - _vm->setflag(_endflag, true); + if (_endflag != -1) { + if (_vm->getVersion() < 0x2000) { + _vm->_game.vars[_endflag] = 1; + } else { + _vm->setflag(_endflag, true); + } + } _endflag = -1; } @@ -168,7 +187,7 @@ void SoundMgr::soundIsFinished() { _endflag = -1; } -SoundMgr::SoundMgr(AgiEngine *agi, Audio::Mixer *pMixer) { +SoundMgr::SoundMgr(AgiBase *agi, Audio::Mixer *pMixer) { _vm = agi; _endflag = -1; _playingSound = -1; diff --git a/engines/agi/sound.h b/engines/agi/sound.h index 0ee19878c4..6fd8dd516e 100644 --- a/engines/agi/sound.h +++ b/engines/agi/sound.h @@ -71,7 +71,7 @@ class SoundMgr; class SoundGen { public: - SoundGen(AgiEngine *vm, Audio::Mixer *pMixer) : _vm(vm), _mixer(pMixer) { + SoundGen(AgiBase *vm, Audio::Mixer *pMixer) : _vm(vm), _mixer(pMixer) { _sampleRate = pMixer->getOutputRate(); } @@ -80,7 +80,7 @@ public: virtual void play(int resnum) = 0; virtual void stop(void) = 0; - AgiEngine *_vm; + AgiBase *_vm; Audio::Mixer *_mixer; Audio::SoundHandle _soundHandle; @@ -122,6 +122,8 @@ public: ~PCjrSound() { free(_data); } virtual uint16 type() { return _type; } const uint8 *getVoicePointer(uint voiceNum); + uint8 *getData() { return _data; } + uint32 getLength() { return _len; } protected: uint8 *_data; ///< Raw sound resource data uint32 _len; ///< Length of the raw sound resource @@ -131,7 +133,7 @@ protected: class SoundMgr { public: - SoundMgr(AgiEngine *agi, Audio::Mixer *pMixer); + SoundMgr(AgiBase *agi, Audio::Mixer *pMixer); ~SoundMgr(); void setVolume(uint8 volume); @@ -147,7 +149,7 @@ public: private: int _endflag; - AgiEngine *_vm; + AgiBase *_vm; SoundGen *_soundGen; diff --git a/engines/agi/sound_2gs.cpp b/engines/agi/sound_2gs.cpp index 38e256aa4b..c5cfa125d6 100644 --- a/engines/agi/sound_2gs.cpp +++ b/engines/agi/sound_2gs.cpp @@ -33,7 +33,7 @@ namespace Agi { -SoundGen2GS::SoundGen2GS(AgiEngine *vm, Audio::Mixer *pMixer) : SoundGen(vm, pMixer) { +SoundGen2GS::SoundGen2GS(AgiBase *vm, Audio::Mixer *pMixer) : SoundGen(vm, pMixer) { // Allocate memory for the wavetable _wavetable = new int8[SIERRASTANDARD_SIZE]; diff --git a/engines/agi/sound_2gs.h b/engines/agi/sound_2gs.h index 9123e18415..89ffc3fe11 100644 --- a/engines/agi/sound_2gs.h +++ b/engines/agi/sound_2gs.h @@ -215,7 +215,7 @@ private: class SoundGen2GS : public SoundGen, public Audio::AudioStream { public: - SoundGen2GS(AgiEngine *vm, Audio::Mixer *pMixer); + SoundGen2GS(AgiBase *vm, Audio::Mixer *pMixer); ~SoundGen2GS(); void play(int resnum); diff --git a/engines/agi/sound_coco3.cpp b/engines/agi/sound_coco3.cpp index 281f2cb2d4..64818e4e34 100644 --- a/engines/agi/sound_coco3.cpp +++ b/engines/agi/sound_coco3.cpp @@ -34,7 +34,7 @@ static int cocoFrequencies[] = { 2093, 2217, 2349, 2489, 2637, 2793, 2959, 3135, 3322, 3520, 3729, 3951 }; -SoundGenCoCo3::SoundGenCoCo3(AgiEngine *vm, Audio::Mixer *pMixer) : SoundGen(vm, pMixer) { +SoundGenCoCo3::SoundGenCoCo3(AgiBase *vm, Audio::Mixer *pMixer) : SoundGen(vm, pMixer) { } SoundGenCoCo3::~SoundGenCoCo3() { diff --git a/engines/agi/sound_coco3.h b/engines/agi/sound_coco3.h index 7058b770f5..d24acf5cc5 100644 --- a/engines/agi/sound_coco3.h +++ b/engines/agi/sound_coco3.h @@ -42,7 +42,7 @@ struct CoCoNote { class SoundGenCoCo3 : public SoundGen, public Audio::AudioStream { public: - SoundGenCoCo3(AgiEngine *vm, Audio::Mixer *pMixer); + SoundGenCoCo3(AgiBase *vm, Audio::Mixer *pMixer); ~SoundGenCoCo3(); void play(int resnum); diff --git a/engines/agi/sound_midi.cpp b/engines/agi/sound_midi.cpp index 0cbaa4af86..47d354093b 100644 --- a/engines/agi/sound_midi.cpp +++ b/engines/agi/sound_midi.cpp @@ -69,7 +69,7 @@ MIDISound::MIDISound(uint8 *data, uint32 len, int resnum, SoundMgr &manager) : A warning("Error creating MIDI sound from resource %d (Type %d, length %d)", resnum, _type, len); } -SoundGenMIDI::SoundGenMIDI(AgiEngine *vm, Audio::Mixer *pMixer) : SoundGen(vm, pMixer), _isGM(false) { +SoundGenMIDI::SoundGenMIDI(AgiBase *vm, Audio::Mixer *pMixer) : SoundGen(vm, pMixer), _isGM(false) { MidiPlayer::createDriver(MDT_MIDI | MDT_ADLIB); int ret = _driver->open(); diff --git a/engines/agi/sound_midi.h b/engines/agi/sound_midi.h index 92a4002498..36bd66ee76 100644 --- a/engines/agi/sound_midi.h +++ b/engines/agi/sound_midi.h @@ -45,7 +45,7 @@ protected: class SoundGenMIDI : public SoundGen, public Audio::MidiPlayer { public: - SoundGenMIDI(AgiEngine *vm, Audio::Mixer *pMixer); + SoundGenMIDI(AgiBase *vm, Audio::Mixer *pMixer); void play(int resnum); // We must overload stop() here to implement the pure virtual diff --git a/engines/agi/sound_pcjr.cpp b/engines/agi/sound_pcjr.cpp index fdebf16b1a..d21baa450f 100644 --- a/engines/agi/sound_pcjr.cpp +++ b/engines/agi/sound_pcjr.cpp @@ -102,7 +102,7 @@ const int8 dissolveDataV3[] = { }; -SoundGenPCJr::SoundGenPCJr(AgiEngine *vm, Audio::Mixer *pMixer) : SoundGen(vm, pMixer) { +SoundGenPCJr::SoundGenPCJr(AgiBase *vm, Audio::Mixer *pMixer) : SoundGen(vm, pMixer) { _chanAllocated = 10240; // preallocate something which will most likely fit _chanData = (int16 *)malloc(_chanAllocated << 1); @@ -126,6 +126,9 @@ SoundGenPCJr::SoundGenPCJr(AgiEngine *vm, Audio::Mixer *pMixer) : SoundGen(vm, p memset(_tchannel, 0, sizeof(_tchannel)); _mixer->playStream(Audio::Mixer::kMusicSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); + + _v1data = NULL; + _v1size = 0; } SoundGenPCJr::~SoundGenPCJr() { @@ -153,6 +156,9 @@ void SoundGenPCJr::play(int resnum) { _tchannel[i].genType = kGenTone; _tchannel[i].genTypePrev = -1; } + + _v1data = pcjrSound->getData() + 1; + _v1size = pcjrSound->getLength() - 1; } void SoundGenPCJr::stop(void) { @@ -201,7 +207,7 @@ int SoundGenPCJr::volumeCalc(SndGenChan *chan) { chan->attenuationCopy = attenuation; attenuation &= 0x0F; - attenuation += _vm->getvar(vVolume); + attenuation += _mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType) / 17; if (attenuation > 0x0F) attenuation = 0x0F; } @@ -214,16 +220,25 @@ int SoundGenPCJr::volumeCalc(SndGenChan *chan) { return attenuation; } +int SoundGenPCJr::getNextNote(int ch) +{ + if (_vm->getVersion() > 0x2001) + return getNextNote_v2(ch); + else + return getNextNote_v1(ch); + + return -1; +} + // read the next channel data.. fill it in *tone // if tone isn't touched.. it should be inited so it just plays silence // return 0 if it's passing more data // return -1 if it's passing nothing (end of data) -int SoundGenPCJr::getNextNote(int ch, Tone *tone) { +int SoundGenPCJr::getNextNote_v2(int ch) { ToneChan *tpcm; SndGenChan *chan; const byte *data; - assert(tone); assert(ch < CHAN_MAX); if (!_vm->getflag(fSoundOn)) @@ -234,7 +249,7 @@ int SoundGenPCJr::getNextNote(int ch, Tone *tone) { if (!chan->avail) return -1; - while ((chan->duration == 0) && (chan->duration != 0xFFFF)) { + while (chan->duration <= 0) { data = chan->data; // read the duration of the note @@ -242,58 +257,32 @@ int SoundGenPCJr::getNextNote(int ch, Tone *tone) { // if it's 0 then it's not going to be played // if it's 0xFFFF then the channel data has finished. - if ((chan->duration != 0) && (chan->duration != 0xFFFF)) { + if ((chan->duration == 0) || (chan->duration == 0xFFFF)) { tpcm->genTypePrev = -1; tpcm->freqCountPrev = -1; - // only tone channels dissolve - if ((ch != 3) && (_dissolveMethod != 0)) // != noise?? - chan->dissolveCount = 0; + break; + } - // attenuation (volume) - chan->attenuation = data[4] & 0xF; + _tchannel[ch].genTypePrev = -1; + _tchannel[ch].freqCountPrev = -1; - // frequency - if (ch < (CHAN_MAX - 1)) { - chan->freqCount = (uint16)data[2] & 0x3F; - chan->freqCount <<= 4; - chan->freqCount |= data[3] & 0x0F; + // only tone channels dissolve + if ((ch != 3) && (_dissolveMethod != 0)) // != noise?? + chan->dissolveCount = 0; + + // attenuation (volume) + writeData(data[4]); + + // frequency + writeData(data[3]); + writeData(data[2]); - chan->genType = kGenTone; - } else { - int noiseFreq; - - // check for white noise (1) or periodic (0) - chan->genType = (data[3] & 0x04) ? kGenWhite : kGenPeriod; - - noiseFreq = data[3] & 0x03; - - switch (noiseFreq) { - case 0: - chan->freqCount = 32; - break; - case 1: - chan->freqCount = 64; - break; - case 2: - chan->freqCount = 128; - break; - case 3: - chan->freqCount = _channel[2].freqCount * 2; - break; - } - } - } // data now points to the next data seg-a-ment chan->data += 5; } - if (chan->duration != 0xFFFF) { - tone->freqCount = chan->freqCount; - tone->atten = volumeCalc(chan); // calc volume, sent vol is different from saved vol - tone->type = chan->genType; - chan->duration--; - } else { + if (chan->duration == 0xFFFF) { // kill channel chan->avail = 0; chan->attenuation = 0x0F; // silent @@ -302,9 +291,80 @@ int SoundGenPCJr::getNextNote(int ch, Tone *tone) { return -1; } + chan->duration--; + return 0; } +int SoundGenPCJr::getNextNote_v1(int ch) { + static int duration = 0; + + byte *data = _v1data; + uint32 len = _v1size; + + if (len <= 0 || data == NULL) { + _channel[ch].avail = 0; + _channel[ch].attenuation = 0x0F; + _channel[ch].attenuationCopy = 0x0F; + return -1; + } + + // In the V1 player the default duration for a row is 3 ticks + if (duration > 0) { + duration--; + return 0; + } + duration = 3 * CHAN_MAX; + + // Otherwise fetch a row of data for all channels + while (*data) { + writeData(*data); + data++; + len--; + } + data++; + len--; + + _v1data = data; + _v1size = len; + + return 0; +} + +void SoundGenPCJr::writeData(uint8 val) { + static int reg = 0; + + debugC(5, kDebugLevelSound, "writeData(%.2X)", val); + + if ((val & 0x90) == 0x90) { + reg = (val >> 5) & 0x3; + _channel[reg].attenuation = val & 0xF; + } else if ((val & 0xF0) == 0xE0) { + _channel[3].genType = (val & 0x4) ? kGenWhite : kGenPeriod; + int noiseFreq = val & 0x03; + switch (noiseFreq) { + case 0: + _channel[3].freqCount = 32; + break; + case 1: + _channel[3].freqCount = 64; + break; + case 2: + _channel[3].freqCount = 128; + break; + case 3: + _channel[3].freqCount = _channel[2].freqCount * 2; + break; + } + } else if (val & 0x80) { + reg = (val >> 5) & 0x3; + _channel[reg].freqCount = val & 0xF; + _channel[reg].genType = kGenTone; + } else { + _channel[reg].freqCount |= (val & 0x3F) << 4; + } +} + // Formulas for noise generator // bit0 = output @@ -340,7 +400,6 @@ const int16 volTable[16] = { // fill buff int SoundGenPCJr::chanGen(int chan, int16 *stream, int len) { ToneChan *tpcm; - Tone toneNew; int fillSize; int retVal; @@ -351,13 +410,10 @@ int SoundGenPCJr::chanGen(int chan, int16 *stream, int len) { while (len > 0) { if (tpcm->noteCount <= 0) { // get new tone data - toneNew.freqCount = 0; - toneNew.atten = 0xF; - toneNew.type = kGenTone; - if ((tpcm->avail) && (getNextNote(chan, &toneNew) == 0)) { - tpcm->atten = toneNew.atten; - tpcm->freqCount = toneNew.freqCount; - tpcm->genType = toneNew.type; + if ((tpcm->avail) && (getNextNote(chan) == 0)) { + tpcm->atten = _channel[chan].attenuation; + tpcm->freqCount = _channel[chan].freqCount; + tpcm->genType = _channel[chan].genType; // setup counters 'n stuff // SAMPLE_RATE samples per sec.. tone changes 60 times per sec diff --git a/engines/agi/sound_pcjr.h b/engines/agi/sound_pcjr.h index 4317e86516..1b4d1e9efb 100644 --- a/engines/agi/sound_pcjr.h +++ b/engines/agi/sound_pcjr.h @@ -71,15 +71,9 @@ struct ToneChan { int feedback; /* noise feedback mask */ }; -struct Tone { - int freqCount; - int atten; - GenType type; -}; - class SoundGenPCJr : public SoundGen, public Audio::AudioStream { public: - SoundGenPCJr(AgiEngine *vm, Audio::Mixer *pMixer); + SoundGenPCJr(AgiBase *vm, Audio::Mixer *pMixer); ~SoundGenPCJr(); void play(int resnum); @@ -102,9 +96,13 @@ public: } private: - int getNextNote(int ch, Tone *tone); + int getNextNote(int ch); + int getNextNote_v2(int ch); + int getNextNote_v1(int ch); int volumeCalc(SndGenChan *chan); + void writeData(uint8 val); + int chanGen(int chan, int16 *stream, int len); int fillNoise(ToneChan *t, int16 *buf, int len); @@ -117,6 +115,9 @@ private: int _chanAllocated; int _dissolveMethod; + + uint8 *_v1data; + uint32 _v1size; }; } // End of namespace Agi diff --git a/engines/agi/sound_sarien.cpp b/engines/agi/sound_sarien.cpp index 9ea8569b81..a2baf89d12 100644 --- a/engines/agi/sound_sarien.cpp +++ b/engines/agi/sound_sarien.cpp @@ -65,7 +65,7 @@ static const int16 waveformMac[WAVEFORM_SIZE] = { -175, -172, -165, -159, -137, -114, -67, -19 }; -SoundGenSarien::SoundGenSarien(AgiEngine *vm, Audio::Mixer *pMixer) : SoundGen(vm, pMixer), _chn() { +SoundGenSarien::SoundGenSarien(AgiBase *vm, Audio::Mixer *pMixer) : SoundGen(vm, pMixer), _chn() { _sndBuffer = (int16 *)calloc(2, BUFFER_SIZE); memset(_sndBuffer, 0, BUFFER_SIZE << 1); diff --git a/engines/agi/sound_sarien.h b/engines/agi/sound_sarien.h index 22bfff3395..04f274ca7d 100644 --- a/engines/agi/sound_sarien.h +++ b/engines/agi/sound_sarien.h @@ -68,7 +68,7 @@ struct ChannelInfo { class SoundGenSarien : public SoundGen, public Audio::AudioStream { public: - SoundGenSarien(AgiEngine *vm, Audio::Mixer *pMixer); + SoundGenSarien(AgiBase *vm, Audio::Mixer *pMixer); ~SoundGenSarien(); void play(int resnum); diff --git a/engines/agi/sprite.cpp b/engines/agi/sprite.cpp index ea0b07f4da..cec0895073 100644 --- a/engines/agi/sprite.cpp +++ b/engines/agi/sprite.cpp @@ -257,7 +257,7 @@ bool SpritesMgr::testUpdating(VtEntry *v, AgiEngine *agi) { if (~agi->_game.dirView[v->currentView].flags & RES_LOADED) return false; - return (v->flags & (ANIMATED | UPDATE | DRAWN)) == (ANIMATED | UPDATE | DRAWN); + return (v->flags & (fAnimated | fUpdate | fDrawn)) == (fAnimated | fUpdate | fDrawn); } /** @@ -268,7 +268,7 @@ bool SpritesMgr::testNotUpdating(VtEntry *v, AgiEngine *vm) { if (~vm->_game.dirView[v->currentView].flags & RES_LOADED) return false; - return (v->flags & (ANIMATED | UPDATE | DRAWN)) == (ANIMATED | DRAWN); + return (v->flags & (fAnimated | fUpdate | fDrawn)) == (fAnimated | fDrawn); } /** @@ -332,7 +332,7 @@ void SpritesMgr::buildList(SpriteList &l, bool (*test)(VtEntry *, AgiEngine *)) for (v = _vm->_game.viewTable; v < &_vm->_game.viewTable[MAX_VIEWTABLE]; v++) { if ((*test)(v, _vm)) { entry[i] = v; - yVal[i] = v->flags & FIXED_PRIORITY ? prioToY(v->priority) : v->yPos; + yVal[i] = v->flags & fFixedPriority ? prioToY(v->priority) : v->yPos; i++; } } @@ -407,13 +407,13 @@ void SpritesMgr::commitSprites(SpriteList &l, bool immediate) { continue; if (s->v->xPos == s->v->xPos2 && s->v->yPos == s->v->yPos2) { - s->v->flags |= DIDNT_MOVE; + s->v->flags |= fDidntMove; continue; } s->v->xPos2 = s->v->xPos; s->v->yPos2 = s->v->yPos; - s->v->flags &= ~DIDNT_MOVE; + s->v->flags &= ~fDidntMove; } } @@ -604,7 +604,9 @@ void SpritesMgr::addToPic(int view, int loop, int cel, int x, int y, int pri, in // If margin is 0, 1, 2, or 3, the base of the cel is // surrounded with a rectangle of the corresponding priority. // If margin >= 4, this extra margin is not shown. - if (mar < 4) { + // + // -1 indicates ignore and is set for V1 + if (mar < 4 && mar != -1) { // add rectangle around object, don't clobber control // info in priority data. The box extends to the end of // its priority band! diff --git a/engines/agi/view.cpp b/engines/agi/view.cpp index 0d420caa81..3f3686561e 100644 --- a/engines/agi/view.cpp +++ b/engines/agi/view.cpp @@ -47,7 +47,7 @@ void AgiEngine::lSetCel(VtEntry *v, int n) { // in the KQ4 introduction // It seems there's either a bug with KQ4's logic script 120 (the intro script) // or flag 64 is not set correctly, which causes the erroneous behavior from the actors - if (getGameID() == GID_KQ4 && !(v->flags & UPDATE) && (v->currentView == 172)) + if (getGameID() == GID_KQ4 && !(v->flags & fUpdate) && (v->currentView == 172)) return; currentVc = ¤tVl->cel[n]; @@ -78,8 +78,8 @@ void AgiEngine::lSetLoop(VtEntry *v, int n) { void AgiEngine::updateView(VtEntry *v) { int cel, lastCel; - if (v->flags & DONTUPDATE) { - v->flags &= ~DONTUPDATE; + if (v->flags & fDontupdate) { + v->flags &= ~fDontupdate; return; } @@ -87,32 +87,32 @@ void AgiEngine::updateView(VtEntry *v) { lastCel = v->numCels - 1; switch (v->cycle) { - case CYCLE_NORMAL: + case kCycleNormal: if (++cel > lastCel) cel = 0; break; - case CYCLE_END_OF_LOOP: + case kCycleEndOfLoop: if (cel < lastCel) { debugC(5, kDebugLevelResources, "cel %d (last = %d)", cel + 1, lastCel); if (++cel != lastCel) break; } setflag(v->parm1, true); - v->flags &= ~CYCLING; + v->flags &= ~fCycling; v->direction = 0; - v->cycle = CYCLE_NORMAL; + v->cycle = kCycleNormal; break; - case CYCLE_REV_LOOP: + case kCycleRevLoop: if (cel) { if (--cel) break; } setflag(v->parm1, true); - v->flags &= ~CYCLING; + v->flags &= ~fCycling; v->direction = 0; - v->cycle = CYCLE_NORMAL; + v->cycle = kCycleNormal; break; - case CYCLE_REVERSE: + case kCycleReverse: if (cel == 0) { cel = lastCel; } else { @@ -259,17 +259,22 @@ void AgiEngine::setCel(VtEntry *v, int n) { */ void AgiEngine::clipViewCoordinates(VtEntry *v) { if (v->xPos + v->xSize > _WIDTH) { - v->flags |= UPDATE_POS; + v->flags |= fUpdatePos; v->xPos = _WIDTH - v->xSize; } if (v->yPos - v->ySize + 1 < 0) { - v->flags |= UPDATE_POS; + v->flags |= fUpdatePos; v->yPos = v->ySize - 1; } - if (v->yPos <= _game.horizon && (~v->flags & IGNORE_HORIZON)) { - v->flags |= UPDATE_POS; + if (v->yPos <= _game.horizon && (~v->flags & fIgnoreHorizon)) { + v->flags |= fUpdatePos; v->yPos = _game.horizon + 1; } + + if (getVersion() < 0x2000) { + v->flags |= fDontupdate; + } + } /** @@ -294,6 +299,12 @@ void AgiEngine::setView(VtEntry *v, int n) { v->currentView = n; v->numLoops = v->viewData->numLoops; v->viewReplaced = true; + + if (getVersion() < 0x2000) { + v->stepSize = v->viewData->rdata[0]; + v->cycleTime = v->viewData->rdata[1]; + v->cycleTimeCount = 0; + } setLoop(v, v->currentLoop >= v->numLoops ? 0 : v->currentLoop); } @@ -302,10 +313,10 @@ void AgiEngine::setView(VtEntry *v, int n) { * @param v pointer to view table entry */ void AgiEngine::startUpdate(VtEntry *v) { - if (~v->flags & UPDATE) { + if (~v->flags & fUpdate) { _sprites->eraseBoth(); - v->flags |= UPDATE; + v->flags |= fUpdate; _sprites->blitBoth(); _sprites->commitBoth(); } @@ -316,10 +327,10 @@ void AgiEngine::startUpdate(VtEntry *v) { * @param v pointer to view table entry */ void AgiEngine::stopUpdate(VtEntry *v) { - if (v->flags & UPDATE) { + if (v->flags & fUpdate) { _sprites->eraseBoth(); - v->flags &= ~UPDATE; + v->flags &= ~fUpdate; _sprites->blitBoth(); _sprites->commitBoth(); } @@ -346,14 +357,14 @@ void AgiEngine::updateViewtable() { i = 0; for (v = _game.viewTable; v < &_game.viewTable[MAX_VIEWTABLE]; v++) { - if ((v->flags & (ANIMATED | UPDATE | DRAWN)) != (ANIMATED | UPDATE | DRAWN)) { + if ((v->flags & (fAnimated | fUpdate | fDrawn)) != (fAnimated | fUpdate | fDrawn)) { continue; } i++; loop = 4; - if (~v->flags & FIX_LOOP) { + if (~v->flags & fFixLoop) { switch (v->numLoops) { case 2: case 3: @@ -378,7 +389,7 @@ void AgiEngine::updateViewtable() { } } - if (~v->flags & CYCLING) + if (~v->flags & fCycling) continue; if (v->cycleTimeCount == 0) @@ -395,7 +406,7 @@ void AgiEngine::updateViewtable() { updatePosition(); _sprites->blitUpdSprites(); _sprites->commitUpdSprites(); - _game.viewTable[0].flags &= ~(ON_WATER | ON_LAND); + _game.viewTable[0].flags &= ~(fOnWater | fOnLand); } } diff --git a/engines/agi/view.h b/engines/agi/view.h index 0ef443f8e5..5cf59d7df5 100644 --- a/engines/agi/view.h +++ b/engines/agi/view.h @@ -50,6 +50,39 @@ struct AgiView { uint8 *rdata; }; +enum MotionType { + kMotionNormal = 0, + kMotionWander = 1, + kMotionFollowEgo = 2, + kMotionMoveObj = 3 +}; + +enum CycleType { + kCycleNormal = 0, + kCycleEndOfLoop = 1, + kCycleRevLoop = 2, + kCycleReverse = 3 + }; + +enum ViewFlags { + fDrawn = (1 << 0), + fIgnoreBlocks = (1 << 1), + fFixedPriority = (1 << 2), + fIgnoreHorizon = (1 << 3), + fUpdate = (1 << 4), + fCycling = (1 << 5), + fAnimated = (1 << 6), + fMotion = (1 << 7), + fOnWater = (1 << 8), + fIgnoreObjects = (1 << 9), + fUpdatePos = (1 << 10), + fOnLand = (1 << 11), + fDontupdate = (1 << 12), + fFixLoop = (1 << 13), + fDidntMove = (1 << 14), + fAdjEgoXY = (1 << 15) +}; + /** * AGI view table entry */ @@ -78,39 +111,10 @@ struct VtEntry { uint8 cycleTime; uint8 cycleTimeCount; uint8 direction; - -#define MOTION_NORMAL 0 -#define MOTION_WANDER 1 -#define MOTION_FOLLOW_EGO 2 -#define MOTION_MOVE_OBJ 3 - uint8 motion; - -#define CYCLE_NORMAL 0 -#define CYCLE_END_OF_LOOP 1 -#define CYCLE_REV_LOOP 2 -#define CYCLE_REVERSE 3 - uint8 cycle; - + MotionType motion; + CycleType cycle; uint8 priority; - -#define DRAWN 0x0001 -#define IGNORE_BLOCKS 0x0002 -#define FIXED_PRIORITY 0x0004 -#define IGNORE_HORIZON 0x0008 -#define UPDATE 0x0010 -#define CYCLING 0x0020 -#define ANIMATED 0x0040 -#define MOTION 0x0080 -#define ON_WATER 0x0100 -#define IGNORE_OBJECTS 0x0200 -#define UPDATE_POS 0x0400 -#define ON_LAND 0x0800 -#define DONTUPDATE 0x1000 -#define FIX_LOOP 0x2000 -#define DIDNT_MOVE 0x4000 -#define ADJ_EGO_XY 0x8000 uint16 flags; - uint8 parm1; uint8 parm2; uint8 parm3; diff --git a/engines/agi/words.cpp b/engines/agi/words.cpp index 4b96fdf711..ec6928f8ed 100644 --- a/engines/agi/words.cpp +++ b/engines/agi/words.cpp @@ -20,19 +20,12 @@ * */ -// -// New find_word algorithm by Thomas Akesson <tapilot@home.se> -// - #include "agi/agi.h" #include "common/textconsole.h" namespace Agi { -static uint8 *words; // words in the game -static uint32 wordsFlen; // length of word memory - // // Local implementation to avoid problems with strndup() used by // gcc 3.2 Cygwin (see #635984) @@ -43,12 +36,38 @@ static char *myStrndup(const char *src, int n) { return tmp; } +int AgiEngine::loadWords_v1(Common::File &f) { + char str[64]; + int k; + + debug(0, "Loading dictionary"); + + // Loop through alphabet, as words in the dictionary file are sorted by + // first character + f.seek(f.pos() + 26 * 2, SEEK_SET); + do { + // Read next word + for (k = 0; k < (int)sizeof(str) - 1; k++) { + str[k] = f.readByte(); + if (str[k] == 0 || (uint8)str[k] == 0xFF) + break; + } + + // And store it in our internal dictionary + if (k > 0) { + AgiWord *w = new AgiWord; + w->word = myStrndup(str, k + 1); + w->id = f.readUint16LE(); + _game.words[str[0] - 'a'].push_back(w); + debug(3, "'%s' (%d)", w->word, w->id); + } + } while((uint8)str[0] != 0xFF); + + return errOK; +} + int AgiEngine::loadWords(const char *fname) { Common::File fp; - uint32 flen; - uint8 *mem = NULL; - - words = NULL; if (!fp.open(fname)) { warning("loadWords: can't open %s", fname); @@ -56,85 +75,70 @@ int AgiEngine::loadWords(const char *fname) { } debug(0, "Loading dictionary: %s", fname); - fp.seek(0, SEEK_END); - flen = fp.pos(); - wordsFlen = flen; - fp.seek(0, SEEK_SET); - - if ((mem = (uint8 *)calloc(1, flen + 32)) == NULL) { - fp.close(); - return errNotEnoughMemory; + // Loop through alphabet, as words in the dictionary file are sorted by + // first character + for (int i = 0; i < 26; i++) { + fp.seek(i * 2, SEEK_SET); + int offset = fp.readUint16BE(); + if (offset == 0) + continue; + fp.seek(offset, SEEK_SET); + int k = fp.readByte(); + while (!fp.eos() && !fp.err()) { + // Read next word + char c, str[64]; + do { + c = fp.readByte(); + str[k++] = (c ^ 0x7F) & 0x7F; + } while (!(c & 0x80) && k < (int)sizeof(str) - 1); + str[k] = 0; + + // And store it in our internal dictionary + AgiWord *w = new AgiWord; + w->word = myStrndup(str, k); + w->id = fp.readUint16BE(); + _game.words[i].push_back(w); + + // Are there more words with an already known prefix? + if (!(k = fp.readByte())) + break; + } } - fp.read(mem, flen); - fp.close(); - - words = mem; - return errOK; } void AgiEngine::unloadWords() { - free(words); - words = NULL; + for (int i = 0; i < 26; i++) + _game.words[i].clear(); } /** * Find a word in the dictionary * Uses an algorithm hopefully like the one Sierra used. Returns the ID * of the word and the length in flen. Returns -1 if not found. - * - * Thomas Akesson, November 2001 */ int AgiEngine::findWord(const char *word, int *flen) { - int mchr = 0; // matched chars - int len, fchr, id = -1; - const uint8 *p = words; - const uint8 *q = words + wordsFlen; - *flen = 0; + int c; debugC(2, kDebugLevelScripts, "find_word(%s)", word); if (word[0] >= 'a' && word[0] <= 'z') - fchr = word[0] - 'a'; + c = word[0] - 'a'; else return -1; - len = strlen(word); - - // Get the offset to the first word beginning with the - // right character - p += READ_BE_UINT16(p + 2 * fchr); - - while (p[0] >= mchr) { - if (p[0] == mchr) { - p++; - // Loop through all matching characters - while ((p[0] ^ word[mchr]) == 0x7F && mchr < len) { - mchr++; - p++; - } - // Check if this is the last character of the word - // and if it matches - if ((p[0] ^ word[mchr]) == 0xFF && mchr < len) { - mchr++; - if (word[mchr] == 0 || word[mchr] == 0x20) { - id = READ_BE_UINT16(p + 1); - *flen = mchr; - } - } + *flen = 0; + Common::Array<AgiWord*> &a = _game.words[c]; + for (int i = 0; i < (int)a.size(); i++) { + int wlen = strlen(a[i]->word); + if (!strncmp(a[i]->word, word, wlen) && (word[wlen] == 0 || word[wlen] == 0x20)) { + *flen = wlen; + return a[i]->id; } - if (p >= q) - return -1; - - // Step to the next word - while (p[0] < 0x80) - p++; - - p += 3; } - return id; + return -1; } void AgiEngine::dictionaryWords(char *msg) { |