diff options
Diffstat (limited to 'engines')
146 files changed, 8425 insertions, 6705 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) { diff --git a/engines/agos/detection_tables.h b/engines/agos/detection_tables.h index a43d581173..d9f321d98e 100644 --- a/engines/agos/detection_tables.h +++ b/engines/agos/detection_tables.h @@ -1040,7 +1040,7 @@ static const AGOSGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformAcorn, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NOSUBTITLES }, @@ -1208,7 +1208,7 @@ static const AGOSGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformAmiga, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NOSUBTITLES | GUIO_NOMIDI }, @@ -1232,7 +1232,7 @@ static const AGOSGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformAmiga, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NOSUBTITLES | GUIO_NOMIDI }, @@ -1546,7 +1546,7 @@ static const AGOSGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NOSUBTITLES }, @@ -1571,7 +1571,7 @@ static const AGOSGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NOSUBTITLES }, @@ -1596,7 +1596,7 @@ static const AGOSGameDescription gameDescriptions[] = { }, Common::RU_RUS, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, @@ -1621,7 +1621,7 @@ static const AGOSGameDescription gameDescriptions[] = { }, Common::FR_FRA, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, @@ -1671,7 +1671,7 @@ static const AGOSGameDescription gameDescriptions[] = { }, Common::HE_ISR, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, @@ -1696,7 +1696,7 @@ static const AGOSGameDescription gameDescriptions[] = { }, Common::IT_ITA, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, @@ -1722,7 +1722,7 @@ static const AGOSGameDescription gameDescriptions[] = { // FIXME: DOS version which uses WAV format Common::IT_ITA, Common::kPlatformWindows, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, @@ -1747,7 +1747,7 @@ static const AGOSGameDescription gameDescriptions[] = { }, Common::ES_ESP, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, @@ -1772,7 +1772,7 @@ static const AGOSGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformWindows, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NOSUBTITLES }, @@ -1797,7 +1797,7 @@ static const AGOSGameDescription gameDescriptions[] = { }, Common::DE_DEU, Common::kPlatformWindows, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NOSUBTITLES }, @@ -2022,7 +2022,7 @@ static const AGOSGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, @@ -2047,7 +2047,7 @@ static const AGOSGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, @@ -2072,7 +2072,7 @@ static const AGOSGameDescription gameDescriptions[] = { }, Common::FR_FRA, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, @@ -2097,7 +2097,7 @@ static const AGOSGameDescription gameDescriptions[] = { }, Common::DE_DEU, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, @@ -2122,7 +2122,7 @@ static const AGOSGameDescription gameDescriptions[] = { }, Common::DE_DEU, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, @@ -2147,7 +2147,7 @@ static const AGOSGameDescription gameDescriptions[] = { }, Common::HE_ISR, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, @@ -2173,7 +2173,7 @@ static const AGOSGameDescription gameDescriptions[] = { // FIXME: DOS version which uses WAV format Common::IT_ITA, Common::kPlatformWindows, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, @@ -2198,7 +2198,7 @@ static const AGOSGameDescription gameDescriptions[] = { }, Common::ES_ESP, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, @@ -2223,7 +2223,7 @@ static const AGOSGameDescription gameDescriptions[] = { }, Common::CZ_CZE, Common::kPlatformWindows, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, @@ -2248,7 +2248,7 @@ static const AGOSGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformWindows, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, @@ -2273,7 +2273,7 @@ static const AGOSGameDescription gameDescriptions[] = { }, Common::FR_FRA, Common::kPlatformWindows, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, @@ -2298,7 +2298,7 @@ static const AGOSGameDescription gameDescriptions[] = { }, Common::DE_DEU, Common::kPlatformWindows, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, @@ -2323,7 +2323,7 @@ static const AGOSGameDescription gameDescriptions[] = { }, Common::PL_POL, Common::kPlatformWindows, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, diff --git a/engines/composer/composer.cpp b/engines/composer/composer.cpp index cf773dc2dc..d9bb0cdc54 100644 --- a/engines/composer/composer.cpp +++ b/engines/composer/composer.cpp @@ -125,9 +125,9 @@ Common::Error ComposerEngine::run() { } if (lastDrawTime + frameTime <= thisTime) { - // catch up if we're more than 5 frames behind - if (lastDrawTime + (frameTime * 5) <= thisTime) - lastDrawTime = thisTime - (frameTime * 5); + // catch up if we're more than 2 frames behind + if (lastDrawTime + (frameTime * 2) <= thisTime) + lastDrawTime = thisTime; else lastDrawTime += frameTime; @@ -253,16 +253,15 @@ void ComposerEngine::setCursor(uint16 id, const Common::Point &offset) { } void ComposerEngine::setCursorVisible(bool visible) { - if (!_mouseSpriteId) - return; - if (visible && !_mouseVisible) { _mouseVisible = true; - addSprite(_mouseSpriteId, 0, 0, _lastMousePos - _mouseOffset); + if (_mouseSpriteId) + addSprite(_mouseSpriteId, 0, 0, _lastMousePos - _mouseOffset); onMouseMove(_lastMousePos); } else if (!visible && _mouseVisible) { _mouseVisible = false; - removeSprite(_mouseSpriteId, 0); + if (_mouseSpriteId) + removeSprite(_mouseSpriteId, 0); } } @@ -276,6 +275,11 @@ Common::String ComposerEngine::getStringFromConfig(const Common::String §ion Common::String ComposerEngine::getFilename(const Common::String §ion, uint id) { Common::String key = Common::String::format("%d", id); Common::String filename = getStringFromConfig(section, key); + + return mangleFilename(filename); +} + +Common::String ComposerEngine::mangleFilename(Common::String filename) { while (filename.size() && (filename[0] == '~' || filename[0] == ':' || filename[0] == '\\')) filename = filename.c_str() + 1; @@ -318,11 +322,11 @@ void ComposerEngine::loadLibrary(uint id) { for (uint i = 0; i < buttonResources.size(); i++) { uint16 buttonId = buttonResources[i]; Common::SeekableReadStream *stream = library._archive->getResource(ID_BUTN, buttonId); - Button button(stream, buttonId); + Button button(stream, buttonId, getGameType()); bool inserted = false; for (Common::List<Button>::iterator b = newLib._buttons.begin(); b != newLib._buttons.end(); b++) { - if (button._zorder <= b->_zorder) + if (button._zorder < b->_zorder) continue; newLib._buttons.insert(b, button); inserted = true; @@ -405,22 +409,32 @@ Common::SeekableReadStream *ComposerEngine::getResource(uint32 tag, uint16 id) { error("No loaded library contains '%s' %04x", tag2str(tag), id); } -Button::Button(Common::SeekableReadStream *stream, uint16 id) { +Button::Button(Common::SeekableReadStream *stream, uint16 id, uint gameType) { _id = id; _type = stream->readUint16LE(); _active = (_type & 0x8000) ? true : false; _type &= 0xfff; - debug(9, "button: type %d, active %d", _type, _active); - - _zorder = stream->readUint16LE(); - _scriptId = stream->readUint16LE(); - _scriptIdRollOn = stream->readUint16LE(); - _scriptIdRollOff = stream->readUint16LE(); - - stream->skip(4); - - uint16 size = stream->readUint16LE(); + debug(9, "button %d: type %d, active %d", id, _type, _active); + + uint16 flags = 0; + uint16 size = 4; + if (gameType == GType_ComposerV1) { + flags = stream->readUint16LE(); + _zorder = 0; + _scriptId = stream->readUint16LE(); + _scriptIdRollOn = 0; + _scriptIdRollOff = 0; + } else { + _zorder = stream->readUint16LE(); + _scriptId = stream->readUint16LE(); + _scriptIdRollOn = stream->readUint16LE(); + _scriptIdRollOff = stream->readUint16LE(); + + stream->skip(4); + + size = stream->readUint16LE(); + } switch (_type) { case kButtonRect: @@ -431,17 +445,23 @@ Button::Button(Common::SeekableReadStream *stream, uint16 id) { _rect.top = stream->readSint16LE(); _rect.right = stream->readSint16LE(); _rect.bottom = stream->readSint16LE(); - debug(9, "button: (%d, %d, %d, %d)", _rect.left, _rect.top, _rect.right, _rect.bottom); break; case kButtonSprites: + if (gameType == GType_ComposerV1) + error("encountered kButtonSprites in V1 data"); for (uint i = 0; i < size; i++) { - _spriteIds.push_back(stream->readSint16LE()); + _spriteIds.push_back(stream->readUint16LE()); } break; default: error("unknown button type %d", _type); } + if (flags & 0x40) { + _scriptIdRollOn = stream->readUint16LE(); + _scriptIdRollOff = stream->readUint16LE(); + } + delete stream; } diff --git a/engines/composer/composer.h b/engines/composer/composer.h index 99ed56ead7..c0d456daaa 100644 --- a/engines/composer/composer.h +++ b/engines/composer/composer.h @@ -68,7 +68,7 @@ enum { class Button { public: Button() { } - Button(Common::SeekableReadStream *stream, uint16 id); + Button(Common::SeekableReadStream *stream, uint16 id, uint gameType); bool contains(const Common::Point &pos) const; @@ -172,6 +172,7 @@ private: Common::String getStringFromConfig(const Common::String §ion, const Common::String &key); Common::String getFilename(const Common::String §ion, uint id); + Common::String mangleFilename(Common::String filename); void loadLibrary(uint id); void unloadLibrary(uint id); diff --git a/engines/composer/detection.cpp b/engines/composer/detection.cpp index c4e98fadd7..8c97b6c4db 100644 --- a/engines/composer/detection.cpp +++ b/engines/composer/detection.cpp @@ -120,6 +120,19 @@ static const ComposerGameDescription gameDescriptions[] = { GType_ComposerV2 }, + { // Provided by Strangerke, "CD-Rom 100% Malin" Pack + { + "darby", + 0, + AD_ENTRY1("book.ini", "285308372f7dddff2ca5a25c9192cf5c"), + Common::FR_FRA, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_ComposerV2 + }, + { { "gregory", @@ -133,6 +146,19 @@ static const ComposerGameDescription gameDescriptions[] = { GType_ComposerV2 }, + { // Provided by Strangerke, "CD-Rom 100% Malin" Pack + { + "gregory", + 0, + AD_ENTRY1("book.ini", "e54fc5c00de5f94e908a969e445af5d0"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_ComposerV2 + }, + { { "princess", diff --git a/engines/composer/graphics.cpp b/engines/composer/graphics.cpp index 5c9fc6e1f7..0768a86e7a 100644 --- a/engines/composer/graphics.cpp +++ b/engines/composer/graphics.cpp @@ -598,10 +598,16 @@ enum { }; void ComposerEngine::decompressBitmap(uint16 type, Common::SeekableReadStream *stream, byte *buffer, uint32 size, uint width, uint height) { + uint outSize = width * height; + switch (type) { case kBitmapUncompressed: - assert(stream->size() - (uint)stream->pos() == size); - assert(size == width * height); + if (stream->size() - (uint)stream->pos() != size) + error("kBitmapUncompressed stream had %d bytes left, supposed to be %d", + stream->size() - (uint)stream->pos(), size); + if (size != outSize) + error("kBitmapUncompressed size %d doesn't match required size %d", + size, outSize); stream->read(buffer, size); break; case kBitmapSpp32: @@ -615,12 +621,22 @@ void ComposerEngine::decompressBitmap(uint16 type, Common::SeekableReadStream *s // run of a single color uint count = (uint)stream->readByte() + 3; size--; + if (outSize < count) + error("kBitmapSpp32 only needed %d bytes, but got run of %d", + outSize, count); + outSize -= count; memset(buffer, lookup[lowBits], count); buffer += count; } else { // two pixels + if (!outSize) + error("kBitmapSpp32 had too many pixels"); *buffer++ = lookup[highBits]; - *buffer++ = lookup[lowBits]; + outSize--; + if (outSize) { + *buffer++ = lookup[lowBits]; + outSize--; + } } } break; diff --git a/engines/dreamweb/dreamgen.cpp b/engines/dreamweb/dreamgen.cpp index 59d69758b6..9a5a27dff0 100644 --- a/engines/dreamweb/dreamgen.cpp +++ b/engines/dreamweb/dreamgen.cpp @@ -1694,116 +1694,6 @@ notendtelly: showgamereel(); } -void DreamGenContext::madman() { - STACK_CHECK; - data.word(kWatchingtime) = 2; - checkspeed(); - if (!flags.z()) - goto nomadspeed; - ax = es.word(bx+3); - _cmp(ax, 364); - if (!flags.c()) - goto ryansded; - _cmp(ax, 10); - if (!flags.z()) - goto notfirstmad; - push(es); - push(bx); - push(ax); - dx = 2247; - loadtemptext(); - ax = pop(); - bx = pop(); - es = pop(); - data.byte(kCombatcount) = -1; - data.byte(kSpeechcount) = 0; -notfirstmad: - _inc(ax); - _cmp(ax, 294); - if (flags.z()) - goto madmanspoken; - _cmp(ax, 66); - if (!flags.z()) - goto nomadspeak; - _inc(data.byte(kCombatcount)); - push(es); - push(bx); - madmantext(); - bx = pop(); - es = pop(); - ax = 53; - _cmp(data.byte(kCombatcount), 64); - if (flags.c()) - goto nomadspeak; - _cmp(data.byte(kCombatcount), 70); - if (flags.z()) - goto killryan; - _cmp(data.byte(kLastweapon), 8); - if (!flags.z()) - goto nomadspeak; - data.byte(kCombatcount) = 72; - data.byte(kLastweapon) = -1; - data.byte(kMadmanflag) = 1; - ax = 67; - goto nomadspeak; -killryan: - ax = 310; -nomadspeak: - es.word(bx+3) = ax; -nomadspeed: - showgamereel(); - al = data.byte(kMapx); - es.byte(bx+1) = al; - madmode(); - return; -madmanspoken: - _cmp(data.byte(kWongame), 1); - if (flags.z()) - return /* (alreadywon) */; - data.byte(kWongame) = 1; - push(es); - push(bx); - getridoftemptext(); - bx = pop(); - es = pop(); - return; -ryansded: - data.byte(kMandead) = 2; - showgamereel(); -} - -void DreamGenContext::madmantext() { - STACK_CHECK; - _cmp(data.byte(kSpeechcount), 63); - if (!flags.c()) - return /* (nomadtext) */; - _cmp(data.byte(kCh1playing), 255); - if (!flags.z()) - return /* (nomadtext) */; - al = data.byte(kSpeechcount); - _inc(data.byte(kSpeechcount)); - _add(al, 47); - bl = 72; - bh = 80; - cx = 90; - dx = 1; - ah = 82; - setuptimedtemp(); -} - -void DreamGenContext::madmode() { - STACK_CHECK; - data.word(kWatchingtime) = 2; - data.byte(kPointermode) = 0; - _cmp(data.byte(kCombatcount), 65); - if (flags.c()) - return /* (iswatchmad) */; - _cmp(data.byte(kCombatcount), 70); - if (!flags.c()) - return /* (iswatchmad) */; - data.byte(kPointermode) = 2; -} - void DreamGenContext::priesttext() { STACK_CHECK; _cmp(es.word(bx+3), 2); @@ -2160,22 +2050,6 @@ void DreamGenContext::addtopeoplelist() { _add(data.word(kListpos), 5); } -void DreamGenContext::showgamereel() { - STACK_CHECK; - ax = es.word(bx+3); - _cmp(ax, 512); - if (!flags.c()) - return /* (noshow) */; - data.word(kReelpointer) = ax; - push(es); - push(bx); - plotreel(); - bx = pop(); - es = pop(); - ax = data.word(kReelpointer); - es.word(bx+3) = ax; -} - void DreamGenContext::checkspeed() { STACK_CHECK; _cmp(data.byte(kLastweapon), -1); @@ -2237,182 +2111,6 @@ void DreamGenContext::checkone() { dx = pop(); } -void DreamGenContext::findsource() { - STACK_CHECK; - ax = data.word(kCurrentframe); - _cmp(ax, 160); - if (!flags.c()) - goto over1000; - ds = data.word(kReel1); - data.word(kTakeoff) = 0; - return; -over1000: - _cmp(ax, 320); - if (!flags.c()) - goto over1001; - ds = data.word(kReel2); - data.word(kTakeoff) = 160; - return; -over1001: - ds = data.word(kReel3); - data.word(kTakeoff) = 320; -} - -void DreamGenContext::mainman() { - STACK_CHECK; - _cmp(data.byte(kResetmanxy), 1); - if (!flags.z()) - goto notinnewroom; - data.byte(kResetmanxy) = 0; - al = data.byte(kRyanx); - ah = data.byte(kRyany); - es.word(bx+10) = ax; - es.byte(bx+29) = 0; - goto executewalk; -notinnewroom: - _dec(es.byte(bx+22)); - _cmp(es.byte(bx+22), -1); - if (flags.z()) - goto executewalk; - return; -executewalk: - es.byte(bx+22) = 0; - al = data.byte(kTurntoface); - _cmp(al, data.byte(kFacing)); - if (flags.z()) - goto facingok; - aboutturn(); - goto notwalk; -facingok: - _cmp(data.byte(kTurndirection), 0); - if (flags.z()) - goto alreadyturned; - _cmp(data.byte(kLinepointer), 254); - if (!flags.z()) - goto alreadyturned; - data.byte(kReasseschanges) = 1; - al = data.byte(kFacing); - _cmp(al, data.byte(kLeavedirection)); - if (!flags.z()) - goto alreadyturned; - checkforexit(); -alreadyturned: - data.byte(kTurndirection) = 0; - _cmp(data.byte(kLinepointer), 254); - if (!flags.z()) - goto walkman; - es.byte(bx+29) = 0; - goto notwalk; -walkman: - al = es.byte(bx+29); - _inc(al); - _cmp(al, 11); - if (!flags.z()) - goto notanimend1; - al = 1; -notanimend1: - es.byte(bx+29) = al; - walking(); - _cmp(data.byte(kLinepointer), 254); - if (flags.z()) - goto afterwalk; - al = data.byte(kFacing); - _and(al, 1); - if (flags.z()) - goto isdouble; - al = es.byte(bx+29); - _cmp(al, 2); - if (flags.z()) - goto afterwalk; - _cmp(al, 7); - if (flags.z()) - goto afterwalk; -isdouble: - walking(); -afterwalk: - _cmp(data.byte(kLinepointer), 254); - if (!flags.z()) - goto notwalk; - al = data.byte(kTurntoface); - _cmp(al, data.byte(kFacing)); - if (!flags.z()) - goto notwalk; - data.byte(kReasseschanges) = 1; - al = data.byte(kFacing); - _cmp(al, data.byte(kLeavedirection)); - if (!flags.z()) - goto notwalk; - checkforexit(); -notwalk: - al = data.byte(kFacing); - ah = 0; - di = 1105; - _add(di, ax); - al = cs.byte(di); - _add(al, es.byte(bx+29)); - es.byte(bx+15) = al; - ax = es.word(bx+10); - data.byte(kRyanx) = al; - data.byte(kRyany) = ah; -} - -void DreamGenContext::aboutturn() { - STACK_CHECK; - _cmp(data.byte(kTurndirection), 1); - if (flags.z()) - goto incdir; - _cmp(data.byte(kTurndirection), -1); - if (flags.z()) - goto decdir; - al = data.byte(kFacing); - _sub(al, data.byte(kTurntoface)); - if (!flags.c()) - goto higher; - _neg(al); - _cmp(al, 4); - if (!flags.c()) - goto decdir; - goto incdir; -higher: - _cmp(al, 4); - if (!flags.c()) - goto incdir; - goto decdir; -incdir: - data.byte(kTurndirection) = 1; - al = data.byte(kFacing); - _inc(al); - _and(al, 7); - data.byte(kFacing) = al; - es.byte(bx+29) = 0; - return; -decdir: - data.byte(kTurndirection) = -1; - al = data.byte(kFacing); - _dec(al); - _and(al, 7); - data.byte(kFacing) = al; - es.byte(bx+29) = 0; -} - -void DreamGenContext::facerightway() { - STACK_CHECK; - push(es); - push(bx); - getroomspaths(); - al = data.byte(kManspath); - ah = 0; - _add(ax, ax); - _add(ax, ax); - _add(ax, ax); - _add(bx, ax); - al = es.byte(bx+7); - data.byte(kTurntoface) = al; - data.byte(kLeavedirection) = al; - bx = pop(); - es = pop(); -} - void DreamGenContext::checkforexit() { STACK_CHECK; cl = data.byte(kRyanx); @@ -2772,147 +2470,6 @@ failrain: al = 0; } -void DreamGenContext::showrain() { - STACK_CHECK; - ds = data.word(kMainsprites); - si = 6*58; - ax = ds.word(si+2); - si = ax; - _add(si, 2080); - bx = (0+(228*13)+32+60+(32*32)+(11*10*3)+768+768+768+(32*32)+(128*5)+(80*5)+(100*5)+(12*5)+(46*40)+(5*80)+(250*4)+(256*30)); - es = data.word(kBuffers); - _cmp(es.byte(bx), 255); - if (flags.z()) - return /* (nothunder) */; -morerain: - es = data.word(kBuffers); - _cmp(es.byte(bx), 255); - if (flags.z()) - goto finishrain; - al = es.byte(bx+1); - ah = 0; - _add(ax, data.word(kMapady)); - _add(ax, data.word(kMapystart)); - cx = 320; - _mul(cx); - cl = es.byte(bx); - ch = 0; - _add(ax, cx); - _add(ax, data.word(kMapadx)); - _add(ax, data.word(kMapxstart)); - di = ax; - cl = es.byte(bx+2); - ch = 0; - ax = es.word(bx+3); - dl = es.byte(bx+5); - dh = 0; - _sub(ax, dx); - _and(ax, 511); - es.word(bx+3) = ax; - _add(bx, 6); - push(si); - _add(si, ax); - es = data.word(kWorkspace); - ah = 0; - dx = 320-2; -rainloop: - _lodsb(); - _cmp(al, ah); - if (flags.z()) - goto noplot; - _stosb(); - _add(di, dx); - if (--cx) - goto rainloop; - si = pop(); - goto morerain; -noplot: - _add(di, 320-1); - if (--cx) - goto rainloop; - si = pop(); - goto morerain; -finishrain: - _cmp(data.word(kCh1blockstocopy), 0); - if (!flags.z()) - return /* (nothunder) */; - _cmp(data.byte(kReallocation), 2); - if (!flags.z()) - goto notlouisthund; - _cmp(data.byte(kBeenmugged), 1); - if (!flags.z()) - return /* (nothunder) */; -notlouisthund: - _cmp(data.byte(kReallocation), 55); - if (flags.z()) - return /* (nothunder) */; - randomnum1(); - _cmp(al, 1); - if (!flags.c()) - return /* (nothunder) */; - al = 7; - _cmp(data.byte(kCh0playing), 6); - if (flags.z()) - goto isthunder1; - al = 4; -isthunder1: - playchannel1(); -} - -void DreamGenContext::backobject() { - STACK_CHECK; - ds = data.word(kSetdat); - di = es.word(bx+20); - al = es.byte(bx+18); - _cmp(al, 0); - if (flags.z()) - goto _tmp48z; - _dec(al); - es.byte(bx+18) = al; - return /* (finishback) */; -_tmp48z: - al = ds.byte(di+7); - es.byte(bx+18) = al; - al = ds.byte(di+8); - _cmp(al, 6); - if (!flags.z()) - goto notwidedoor; - widedoor(); - return /* (finishback) */; -notwidedoor: - _cmp(al, 5); - if (!flags.z()) - goto notrandom; - random(); - return /* (finishback) */; -notrandom: - _cmp(al, 4); - if (!flags.z()) - goto notlockdoor; - lockeddoorway(); - return /* (finishback) */; -notlockdoor: - _cmp(al, 3); - if (!flags.z()) - goto notlift; - liftsprite(); - return /* (finishback) */; -notlift: - _cmp(al, 2); - if (!flags.z()) - goto notdoor; - doorway(); - return /* (finishback) */; -notdoor: - _cmp(al, 1); - if (!flags.z()) - goto steadyob; - constant(); - return /* (finishback) */; -steadyob: - steady(); -} - void DreamGenContext::liftnoise() { STACK_CHECK; _cmp(data.byte(kReallocation), 5); @@ -2966,231 +2523,6 @@ gotconst: ds.byte(di+17) = al; } -void DreamGenContext::doorway() { - STACK_CHECK; - data.byte(kDoorcheck1) = -24; - data.byte(kDoorcheck2) = 10; - data.byte(kDoorcheck3) = -30; - data.byte(kDoorcheck4) = 10; - dodoor(); -} - -void DreamGenContext::widedoor() { - STACK_CHECK; - data.byte(kDoorcheck1) = -24; - data.byte(kDoorcheck2) = 24; - data.byte(kDoorcheck3) = -30; - data.byte(kDoorcheck4) = 24; - dodoor(); -} - -void DreamGenContext::lockeddoorway() { - STACK_CHECK; - al = data.byte(kRyanx); - ah = data.byte(kRyany); - cl = es.byte(bx+10); - ch = es.byte(bx+11); - _cmp(al, cl); - if (!flags.c()) - goto rtofdoor2; - _sub(al, cl); - _cmp(al, -24); - if (!flags.c()) - goto upordown2; - goto shutdoor2; -rtofdoor2: - _sub(al, cl); - _cmp(al, 10); - if (!flags.c()) - goto shutdoor2; -upordown2: - _cmp(ah, ch); - if (!flags.c()) - goto botofdoor2; - _sub(ah, ch); - _cmp(ah, -30); - if (flags.c()) - goto shutdoor2; - goto opendoor2; -botofdoor2: - _sub(ah, ch); - _cmp(ah, 12); - if (!flags.c()) - goto shutdoor2; -opendoor2: - _cmp(data.byte(kThroughdoor), 1); - if (flags.z()) - goto mustbeopen; - _cmp(data.byte(kLockstatus), 1); - if (flags.z()) - goto shutdoor; -mustbeopen: - cl = es.byte(bx+19); - _cmp(cl, 1); - if (!flags.z()) - goto notdoorsound4; - al = 0; - playchannel1(); -notdoorsound4: - _cmp(cl, 6); - if (!flags.z()) - goto noturnonyet; - al = data.byte(kDoorpath); - push(es); - push(bx); - turnpathon(); - bx = pop(); - es = pop(); -noturnonyet: - cl = es.byte(bx+19); - _cmp(data.byte(kThroughdoor), 1); - if (!flags.z()) - goto notthrough2; - _cmp(cl, 0); - if (!flags.z()) - goto notthrough2; - cl = 6; -notthrough2: - _inc(cl); - ch = 0; - push(di); - _add(di, cx); - al = ds.byte(di+18); - _cmp(al, 255); - if (!flags.z()) - goto atlast3; - _dec(di); - _dec(cl); -atlast3: - es.byte(bx+19) = cl; - al = ds.byte(di+18); - di = pop(); - es.byte(bx+15) = al; - ds.byte(di+17) = al; - _cmp(cl, 5); - if (!flags.z()) - return /* (justshutting) */; - data.byte(kThroughdoor) = 1; - return; -shutdoor2: - cl = es.byte(bx+19); - _cmp(cl, 5); - if (!flags.z()) - goto notdoorsound3; - al = 1; - playchannel1(); -notdoorsound3: - _cmp(cl, 0); - if (flags.z()) - goto atlast4; - _dec(cl); - es.byte(bx+19) = cl; -atlast4: - ch = 0; - data.byte(kThroughdoor) = 0; - push(di); - _add(di, cx); - al = ds.byte(di+18); - di = pop(); - es.byte(bx+15) = al; - ds.byte(di+17) = al; - _cmp(cl, 0); - if (!flags.z()) - return /* (notlocky) */; - al = data.byte(kDoorpath); - push(es); - push(bx); - turnpathoff(); - bx = pop(); - es = pop(); - data.byte(kLockstatus) = 1; - return; -/*continuing to unbounded code: shutdoor from dodoor:60-87*/ -shutdoor: - cl = es.byte(bx+19); - _cmp(cl, 5); - if (!flags.z()) - goto notdoorsound1; - al = 1; - _cmp(data.byte(kReallocation), 5); - if (!flags.z()) - goto nothoteldoor1; - al = 13; -nothoteldoor1: - playchannel1(); -notdoorsound1: - _cmp(cl, 0); - if (flags.z()) - goto atlast2; - _dec(cl); - es.byte(bx+19) = cl; -atlast2: - ch = 0; - push(di); - _add(di, cx); - al = ds.byte(di+18); - di = pop(); - es.byte(bx+15) = al; - ds.byte(di+17) = al; - _cmp(cl, 5); - if (!flags.z()) - return /* (notnearly) */; - data.byte(kThroughdoor) = 0; -} - -void DreamGenContext::updatepeople() { - STACK_CHECK; - es = data.word(kBuffers); - di = (0+(228*13)+32+60+(32*32)+(11*10*3)+768+768+768+(32*32)+(128*5)+(80*5)+(100*5)); - data.word(kListpos) = di; - cx = 12*5; - al = 255; - _stosb(cx, true); - _inc(data.word(kMaintimer)); - es = cs; - bx = 534; - di = 991; -updateloop: - al = es.byte(bx); - _cmp(al, 255); - if (flags.z()) - return /* (endupdate) */; - _cmp(al, data.byte(kReallocation)); - if (!flags.z()) - goto notinthisroom; - cx = es.word(bx+1); - _cmp(cl, data.byte(kMapx)); - if (!flags.z()) - goto notinthisroom; - _cmp(ch, data.byte(kMapy)); - if (!flags.z()) - goto notinthisroom; - push(di); - ax = cs.word(di); - __dispatch_call(ax); - di = pop(); -notinthisroom: - _add(bx, 8); - _add(di, 2); - goto updateloop; -} - -void DreamGenContext::getreelframeax() { - STACK_CHECK; - push(ds); - data.word(kCurrentframe) = ax; - findsource(); - es = ds; - ds = pop(); - ax = data.word(kCurrentframe); - _sub(ax, data.word(kTakeoff)); - _add(ax, ax); - cx = ax; - _add(ax, ax); - _add(ax, cx); - bx = ax; -} - void DreamGenContext::reelsonscreen() { STACK_CHECK; reconstruct(); @@ -3200,48 +2532,6 @@ void DreamGenContext::reelsonscreen() { usetimedtext(); } -void DreamGenContext::plotreel() { - STACK_CHECK; - getreelstart(); -retryreel: - push(es); - push(si); - ax = es.word(si+2); - _cmp(al, 220); - if (flags.c()) - goto normalreel; - _cmp(al, 255); - if (flags.z()) - goto normalreel; - dealwithspecial(); - _inc(data.word(kReelpointer)); - si = pop(); - es = pop(); - _add(si, 40); - goto retryreel; -normalreel: - cx = 8; -plotloop: - push(cx); - push(es); - push(si); - ax = es.word(si); - _cmp(ax, 0x0ffff); - if (flags.z()) - goto notplot; - showreelframe(); -notplot: - si = pop(); - es = pop(); - cx = pop(); - _add(si, 5); - if (--cx) - goto plotloop; - soundonreels(); - bx = pop(); - es = pop(); -} - void DreamGenContext::soundonreels() { STACK_CHECK; bl = data.byte(kReallocation); @@ -3307,126 +2597,6 @@ notfudge: data.byte(kHavedoneobs) = 0; } -void DreamGenContext::dealwithspecial() { - STACK_CHECK; - _sub(al, 220); - _cmp(al, 0); - if (!flags.z()) - goto notplset; - al = ah; - placesetobject(); - data.byte(kHavedoneobs) = 1; - return; -notplset: - _cmp(al, 1); - if (!flags.z()) - goto notremset; - al = ah; - removesetobject(); - data.byte(kHavedoneobs) = 1; - return; -notremset: - _cmp(al, 2); - if (!flags.z()) - goto notplfree; - al = ah; - placefreeobject(); - data.byte(kHavedoneobs) = 1; - return; -notplfree: - _cmp(al, 3); - if (!flags.z()) - goto notremfree; - al = ah; - removefreeobject(); - data.byte(kHavedoneobs) = 1; - return; -notremfree: - _cmp(al, 4); - if (!flags.z()) - goto notryanoff; - switchryanoff(); - return; -notryanoff: - _cmp(al, 5); - if (!flags.z()) - goto notryanon; - data.byte(kTurntoface) = ah; - data.byte(kFacing) = ah; - switchryanon(); - return; -notryanon: - _cmp(al, 6); - if (!flags.z()) - goto notchangeloc; - data.byte(kNewlocation) = ah; - return; -notchangeloc: - movemap(); -} - -void DreamGenContext::movemap() { - STACK_CHECK; - _cmp(ah, 32); - if (!flags.z()) - goto notmapup2; - _sub(data.byte(kMapy), 20); - data.byte(kNowinnewroom) = 1; - return; -notmapup2: - _cmp(ah, 16); - if (!flags.z()) - goto notmapupspec; - _sub(data.byte(kMapy), 10); - data.byte(kNowinnewroom) = 1; - return; -notmapupspec: - _cmp(ah, 8); - if (!flags.z()) - goto notmapdownspec; - _add(data.byte(kMapy), 10); - data.byte(kNowinnewroom) = 1; - return; -notmapdownspec: - _cmp(ah, 2); - if (!flags.z()) - goto notmaprightspec; - _add(data.byte(kMapx), 11); - data.byte(kNowinnewroom) = 1; - return; -notmaprightspec: - _sub(data.byte(kMapx), 11); - data.byte(kNowinnewroom) = 1; -} - -void DreamGenContext::getreelstart() { - STACK_CHECK; - ax = data.word(kReelpointer); - cx = 40; - _mul(cx); - es = data.word(kReels); - si = ax; - _add(si, (0+(36*144))); -} - -void DreamGenContext::showreelframe() { - STACK_CHECK; - al = es.byte(si+2); - ah = 0; - di = ax; - _add(di, data.word(kMapadx)); - al = es.byte(si+3); - bx = ax; - _add(bx, data.word(kMapady)); - ax = es.word(si); - data.word(kCurrentframe) = ax; - findsource(); - ax = data.word(kCurrentframe); - _sub(ax, data.word(kTakeoff)); - ah = 8; - showframe(); -} - void DreamGenContext::deleverything() { STACK_CHECK; al = data.byte(kMapysize); @@ -3501,13 +2671,6 @@ dumpevery2: goto dumpevery2; } -void DreamGenContext::allocatework() { - STACK_CHECK; - bx = 0x1000; - allocatemem(); - data.word(kWorkspace) = ax; -} - void DreamGenContext::loadpalfromiff() { STACK_CHECK; dx = 2481; @@ -3669,68 +2832,6 @@ void DreamGenContext::createpanel2() { showframe(); } -void DreamGenContext::clearwork() { - STACK_CHECK; - ax = 0x0; - es = data.word(kWorkspace); - di = 0; - cx = (200*320)/64; -clearloop: - _stosw(32); - if (--cx) - goto clearloop; -} - -void DreamGenContext::zoom() { - STACK_CHECK; - _cmp(data.word(kWatchingtime), 0); - if (!flags.z()) - return /* (inwatching) */; - _cmp(data.byte(kZoomon), 1); - if (flags.z()) - goto zoomswitch; - return; -zoomswitch: - _cmp(data.byte(kCommandtype), 199); - if (flags.c()) - goto zoomit; - putunderzoom(); - return; -zoomit: - ax = data.word(kOldpointery); - _sub(ax, 9); - cx = (320); - _mul(cx); - _add(ax, data.word(kOldpointerx)); - _sub(ax, 11); - si = ax; - ax = (132)+4; - cx = (320); - _mul(cx); - _add(ax, (8)+5); - di = ax; - es = data.word(kWorkspace); - ds = data.word(kWorkspace); - cx = 20; -zoomloop: - push(cx); - cx = 23; -zoomloop2: - _lodsb(); - ah = al; - _stosw(); - es.word(di+(320)-2) = ax; - if (--cx) - goto zoomloop2; - _add(si, (320)-23); - _add(di, (320)-46+(320)); - cx = pop(); - if (--cx) - goto zoomloop; - crosshair(); - data.byte(kDidzoom) = 1; -} - void DreamGenContext::delthisone() { STACK_CHECK; push(ax); @@ -3775,83 +2876,6 @@ deloneloop: goto deloneloop; } -void DreamGenContext::doblocks() { - STACK_CHECK; - es = data.word(kWorkspace); - ax = data.word(kMapady); - cx = (320); - _mul(cx); - di = data.word(kMapadx); - _add(di, ax); - al = data.byte(kMapy); - ah = 0; - bx = (66); - _mul(bx); - bl = data.byte(kMapx); - bh = 0; - _add(ax, bx); - si = (0); - _add(si, ax); - cx = 10; -loop120: - push(di); - push(cx); - cx = 11; -loop124: - push(cx); - push(di); - ds = data.word(kMapdata); - _lodsb(); - ds = data.word(kBackdrop); - push(si); - _cmp(al, 0); - if (flags.z()) - goto zeroblock; - ah = al; - al = 0; - si = (0+192); - _add(si, ax); - bh = 14; - bh = 4; -firstbitofblock: - _movsw(8); - _add(di, (320)-16); - _dec(bh); - if (!flags.z()) - goto firstbitofblock; - bh = 12; -loop125: - _movsw(8); - ax = 0x0dfdf; - _stosw(2); - _add(di, (320)-20); - _dec(bh); - if (!flags.z()) - goto loop125; - _add(di, 4); - ax = 0x0dfdf; - _stosw(8); - _add(di, (320)-16); - _stosw(8); - _add(di, (320)-16); - _stosw(8); - _add(di, (320)-16); - _stosw(8); -zeroblock: - si = pop(); - di = pop(); - cx = pop(); - _add(di, 16); - if (--cx) - goto loop124; - _add(si, (66)-11); - cx = pop(); - di = pop(); - _add(di, (320)*16); - if (--cx) - goto loop120; -} - void DreamGenContext::transferinv() { STACK_CHECK; di = data.word(kExframepos); @@ -7648,40 +6672,6 @@ blankframe: goto showobsloop; } -void DreamGenContext::makebackob() { - STACK_CHECK; - _cmp(data.byte(kNewobs), 0); - if (flags.z()) - return /* (nomake) */; - al = es.byte(si+5); - ah = es.byte(si+8); - push(si); - push(ax); - push(si); - ax = data.word(kObjectx); - bx = data.word(kObjecty); - ah = bl; - si = ax; - cx = 49520; - dx = data.word(kSetframes); - di = (0); - makesprite(); - ax = pop(); - es.word(bx+20) = ax; - ax = pop(); - _cmp(al, 255); - if (!flags.z()) - goto usedpriority; - al = 0; -usedpriority: - es.byte(bx+23) = al; - es.byte(bx+30) = ah; - es.byte(bx+16) = 0; - es.byte(bx+18) = 0; - es.byte(bx+19) = 0; - si = pop(); -} - void DreamGenContext::showallfree() { STACK_CHECK; es = data.word(kBuffers); @@ -12853,28 +11843,6 @@ notonsartroof: placesetobject(); } -void DreamGenContext::dumptimedtext() { - STACK_CHECK; - _cmp(data.byte(kNeedtodumptimed), 1); - if (!flags.z()) - return /* (nodumptimed) */; - al = data.byte(kTimedy); - _cmp(data.byte(kForeignrelease), 0); - if (flags.z()) - goto _tmp1; - _sub(al, 3); -_tmp1: - ah = 0; - bx = ax; - al = data.byte(kTimedx); - ah = 0; - di = ax; - cl = 240; - ch = (30); - multidump(); - data.byte(kNeedtodumptimed) = 0; -} - void DreamGenContext::setuptimeduse() { STACK_CHECK; _cmp(data.word(kTimecount), 0); @@ -12897,58 +11865,6 @@ void DreamGenContext::setuptimeduse() { data.word(kTimedoffset) = bx; } -void DreamGenContext::setuptimedtemp() { - STACK_CHECK; - _cmp(ah, 0); - if (flags.z()) - goto notloadspeech3; - push(ax); - push(bx); - push(cx); - push(dx); - dl = 'T'; - dh = ah; - cl = 'T'; - ah = 0; - loadspeech(); - _cmp(data.byte(kSpeechloaded), 1); - if (!flags.z()) - goto _tmp1; - al = 50+12; - playchannel1(); -_tmp1: - dx = pop(); - cx = pop(); - bx = pop(); - ax = pop(); - _cmp(data.byte(kSpeechloaded), 1); - if (!flags.z()) - goto notloadspeech3; - _cmp(data.byte(kSubtitles), 1); - if (flags.z()) - goto notloadspeech3; - return; -notloadspeech3: - _cmp(data.word(kTimecount), 0); - if (!flags.z()) - return /* (cantsetup2) */; - data.byte(kTimedy) = bh; - data.byte(kTimedx) = bl; - data.word(kCounttotimed) = cx; - _add(dx, cx); - data.word(kTimecount) = dx; - bl = al; - bh = 0; - _add(bx, bx); - es = data.word(kTextfile1); - cx = (66*2); - ax = es.word(bx); - _add(ax, cx); - bx = ax; - data.word(kTimedseg) = es; - data.word(kTimedoffset) = bx; -} - void DreamGenContext::edenscdplayer() { STACK_CHECK; showfirstuse(); @@ -16137,46 +15053,6 @@ notsecondbank1: es = pop(); } -void DreamGenContext::makenextblock() { - STACK_CHECK; - volumeadjust(); - loopchannel0(); - _cmp(data.word(kCh1blockstocopy), 0); - if (flags.z()) - goto mightbeonlych0; - _cmp(data.word(kCh0blockstocopy), 0); - if (flags.z()) - goto mightbeonlych1; - _dec(data.word(kCh0blockstocopy)); - _dec(data.word(kCh1blockstocopy)); - bothchannels(); - return; -mightbeonlych1: - data.byte(kCh0playing) = 255; - _cmp(data.word(kCh1blockstocopy), 0); - if (flags.z()) - return /* (notch1only) */; - _dec(data.word(kCh1blockstocopy)); - channel1only(); - return; -mightbeonlych0: - data.byte(kCh1playing) = 255; - _cmp(data.word(kCh0blockstocopy), 0); - if (flags.z()) - goto notch0only; - _dec(data.word(kCh0blockstocopy)); - channel0only(); - return; -notch0only: - es = data.word(kSoundbuffer); - di = data.word(kSoundbufferwrite); - cx = 1024; - ax = 0x7f7f; - _stosw(cx, true); - _and(di, 16384-1); - data.word(kSoundbufferwrite) = di; -} - void DreamGenContext::volumeadjust() { STACK_CHECK; al = data.byte(kVolumedirection); @@ -16198,162 +15074,6 @@ volfinish: data.byte(kVolumedirection) = 0; } -void DreamGenContext::loopchannel0() { - STACK_CHECK; - _cmp(data.word(kCh0blockstocopy), 0); - if (!flags.z()) - return /* (notloop) */; - _cmp(data.byte(kCh0repeat), 0); - if (flags.z()) - return /* (notloop) */; - _cmp(data.byte(kCh0repeat), 255); - if (flags.z()) - goto endlessloop; - _dec(data.byte(kCh0repeat)); -endlessloop: - ax = data.word(kCh0oldemmpage); - data.word(kCh0emmpage) = ax; - ax = data.word(kCh0oldoffset); - data.word(kCh0offset) = ax; - ax = data.word(kCh0blockstocopy); - _add(ax, data.word(kCh0oldblockstocopy)); - data.word(kCh0blockstocopy) = ax; -} - -void DreamGenContext::channel0tran() { - STACK_CHECK; - _cmp(data.byte(kVolume), 0); - if (!flags.z()) - goto lowvolumetran; - cx = 1024; - _movsw(cx, true); - return; -lowvolumetran: - cx = 1024; - bh = data.byte(kVolume); - bl = 0; - _add(bx, 16384-256); -volloop: - _lodsw(); - bl = al; - al = es.byte(bx); - bl = ah; - ah = es.byte(bx); - _stosw(); - if (--cx) - goto volloop; -} - -void DreamGenContext::domix() { - STACK_CHECK; - _cmp(data.byte(kVolume), 0); - if (!flags.z()) - goto lowvolumemix; -slow: - _lodsb(); - ah = ds.byte(bx); - _inc(bx); - _cmp(al, dh); - if (!flags.c()) - goto toplot; - _cmp(ah, dh); - if (!flags.c()) - goto nodistort; - _add(al, ah); - if (flags.s()) - goto botok; - _xor(al, al); - _stosb(); - if (--cx) - goto slow; - return /* (doneit) */; -botok: - _xor(al, dh); - _stosb(); - if (--cx) - goto slow; - return /* (doneit) */; -toplot: - _cmp(ah, dh); - if (flags.c()) - goto nodistort; - _add(al, ah); - if (!flags.s()) - goto topok; - al = dl; - _stosb(); - if (--cx) - goto slow; - return /* (doneit) */; -topok: - _xor(al, dh); - _stosb(); - if (--cx) - goto slow; - return /* (doneit) */; -nodistort: - _add(al, ah); - _xor(al, dh); - _stosb(); - if (--cx) - goto slow; - return /* (doneit) */; -lowvolumemix: - _lodsb(); - push(bx); - bh = data.byte(kVolume); - _add(bh, 63); - bl = al; - al = es.byte(bx); - bx = pop(); - ah = ds.byte(bx); - _inc(bx); - _cmp(al, dh); - if (!flags.c()) - goto toplotv; - _cmp(ah, dh); - if (!flags.c()) - goto nodistortv; - _add(al, ah); - if (flags.s()) - goto botokv; - _xor(al, al); - _stosb(); - if (--cx) - goto lowvolumemix; - return /* (doneit) */; -botokv: - _xor(al, dh); - _stosb(); - if (--cx) - goto lowvolumemix; - return /* (doneit) */; -toplotv: - _cmp(ah, dh); - if (flags.c()) - goto nodistortv; - _add(al, ah); - if (!flags.s()) - goto topokv; - al = dl; - _stosb(); - if (--cx) - goto lowvolumemix; - return /* (doneit) */; -topokv: - _xor(al, dh); - _stosb(); - if (--cx) - goto lowvolumemix; - return /* (doneit) */; -nodistortv: - _add(al, ah); - _xor(al, dh); - _stosb(); - if (--cx) - goto lowvolumemix; -} - void DreamGenContext::entrytexts() { STACK_CHECK; _cmp(data.byte(kLocation), 21); @@ -16776,84 +15496,6 @@ void DreamGenContext::clearrest() { deallocatemem(); } -void DreamGenContext::parseblaster() { - STACK_CHECK; -lookattail: - al = es.byte(bx); - _cmp(al, 0); - if (flags.z()) - return /* (endtail) */; - _cmp(al, 13); - if (flags.z()) - return /* (endtail) */; - _cmp(al, 'i'); - if (flags.z()) - goto issoundint; - _cmp(al, 'I'); - if (flags.z()) - goto issoundint; - _cmp(al, 'b'); - if (flags.z()) - goto isbright; - _cmp(al, 'B'); - if (flags.z()) - goto isbright; - _cmp(al, 'a'); - if (flags.z()) - goto isbaseadd; - _cmp(al, 'A'); - if (flags.z()) - goto isbaseadd; - _cmp(al, 'n'); - if (flags.z()) - goto isnosound; - _cmp(al, 'N'); - if (flags.z()) - goto isnosound; - _cmp(al, 'd'); - if (flags.z()) - goto isdma; - _cmp(al, 'D'); - if (flags.z()) - goto isdma; - _inc(bx); - if (--cx) - goto lookattail; - return; -issoundint: - al = es.byte(bx+1); - _sub(al, '0'); - data.byte(kSoundint) = al; - _inc(bx); - goto lookattail; -isdma: - al = es.byte(bx+1); - _sub(al, '0'); - data.byte(kSounddmachannel) = al; - _inc(bx); - goto lookattail; -isbaseadd: - push(cx); - al = es.byte(bx+2); - _sub(al, '0'); - ah = 0; - cl = 4; - _shl(ax, cl); - _add(ax, 0x200); - data.word(kSoundbaseadd) = ax; - cx = pop(); - _inc(bx); - goto lookattail; -isbright: - data.byte(kBrightness) = 1; - _inc(bx); - goto lookattail; -isnosound: - data.byte(kSoundint) = 255; - _inc(bx); - goto lookattail; -} - void DreamGenContext::startup() { STACK_CHECK; data.byte(kCurrentkey) = 0; @@ -17488,69 +16130,6 @@ nothingund: blank(); } -void DreamGenContext::checkifperson() { - STACK_CHECK; - es = data.word(kBuffers); - bx = (0+(228*13)+32+60+(32*32)+(11*10*3)+768+768+768+(32*32)+(128*5)+(80*5)+(100*5)); - cx = 12; -identifyreel: - push(cx); - _cmp(es.byte(bx+4), 255); - if (flags.z()) - goto notareelid; - push(es); - push(bx); - push(ax); - ax = es.word(bx+0); - data.word(kReelpointer) = ax; - getreelstart(); - _cmp(es.word(si+2), 0x0ffff); - if (!flags.z()) - goto notblankpers; - _add(si, 5); -notblankpers: - cx = es.word(si+2); - ax = es.word(si+0); - push(cx); - getreelframeax(); - cx = pop(); - _add(cl, es.byte(bx+4)); - _add(ch, es.byte(bx+5)); - dx = cx; - _add(dl, es.byte(bx+0)); - _add(dh, es.byte(bx+1)); - ax = pop(); - bx = pop(); - es = pop(); - _cmp(al, cl); - if (flags.c()) - goto notareelid; - _cmp(ah, ch); - if (flags.c()) - goto notareelid; - _cmp(al, dl); - if (!flags.c()) - goto notareelid; - _cmp(ah, dh); - if (!flags.c()) - goto notareelid; - cx = pop(); - ax = es.word(bx+2); - data.word(kPersondata) = ax; - al = es.byte(bx+4); - ah = 5; - obname(); - al = 0; - _cmp(al, 1); - return; -notareelid: - cx = pop(); - _add(bx, 5); - _dec(cx); - if (!flags.z()) - goto identifyreel; -} - void DreamGenContext::checkifset() { STACK_CHECK; es = data.word(kBuffers); @@ -18184,60 +16763,6 @@ void DreamGenContext::examineobtext() { commandwithob(); } -void DreamGenContext::commandwithob() { - STACK_CHECK; - push(ax); - push(ax); - push(bx); - push(cx); - push(dx); - push(es); - push(ds); - push(si); - push(di); - deltextline(); - di = pop(); - si = pop(); - ds = pop(); - es = pop(); - dx = pop(); - cx = pop(); - bx = pop(); - ax = pop(); - push(bx); - ah = 0; - _add(ax, ax); - bx = ax; - es = data.word(kCommandtext); - ax = es.word(bx); - _add(ax, (66*2)); - si = ax; - di = data.word(kTextaddressx); - bx = data.word(kTextaddressy); - dl = data.byte(kTextlen); - al = 0; - ah = 0; - printdirect(); - ax = pop(); - di = 5847; - copyname(); - ax = pop(); - di = data.word(kLastxpos); - _cmp(al, 0); - if (flags.z()) - goto noadd; - _add(di, 5); -noadd: - bx = data.word(kTextaddressy); - es = cs; - si = 5847; - dl = data.byte(kTextlen); - al = 0; - ah = 0; - printdirect(); - data.byte(kNewtextline) = 1; -} - void DreamGenContext::commandonly() { STACK_CHECK; push(ax); @@ -18402,109 +16927,6 @@ holdingreel: data.byte(kWatchmode) = 2; } -void DreamGenContext::autosetwalk() { - STACK_CHECK; - al = data.byte(kManspath); - _cmp(data.byte(kFinaldest), al); - if (!flags.z()) - goto notsamealready; - return; -notsamealready: - getroomspaths(); - checkdest(); - push(bx); - al = data.byte(kManspath); - ah = 0; - _add(ax, ax); - _add(ax, ax); - _add(ax, ax); - _add(bx, ax); - al = es.byte(bx); - ah = 0; - _sub(ax, 12); - data.word(kLinestartx) = ax; - al = es.byte(bx+1); - ah = 0; - _sub(ax, 12); - data.word(kLinestarty) = ax; - bx = pop(); - al = data.byte(kDestination); - ah = 0; - _add(ax, ax); - _add(ax, ax); - _add(ax, ax); - _add(bx, ax); - al = es.byte(bx); - ah = 0; - _sub(ax, 12); - data.word(kLineendx) = ax; - al = es.byte(bx+1); - ah = 0; - _sub(ax, 12); - data.word(kLineendy) = ax; - bresenhams(); - _cmp(data.byte(kLinedirection), 0); - if (flags.z()) - goto normalline; - al = data.byte(kLinelength); - _dec(al); - data.byte(kLinepointer) = al; - data.byte(kLinedirection) = 1; - return; -normalline: - data.byte(kLinepointer) = 0; -} - -void DreamGenContext::checkdest() { - STACK_CHECK; - push(bx); - _add(bx, 12*8); - ah = data.byte(kManspath); - cl = 4; - _shl(ah, cl); - al = data.byte(kDestination); - cl = 24; - ch = data.byte(kDestination); -checkdestloop: - dh = es.byte(bx); - _and(dh, 0xf0); - dl = es.byte(bx); - _and(dl, 0xf); - _cmp(ax, dx); - if (!flags.z()) - goto nextcheck; - al = es.byte(bx+1); - _and(al, 15); - data.byte(kDestination) = al; - bx = pop(); - return; -nextcheck: - dl = es.byte(bx); - _and(dl, 0xf0); - _shr(dl, 1); - _shr(dl, 1); - _shr(dl, 1); - _shr(dl, 1); - dh = es.byte(bx); - _and(dh, 0xf); - _shl(dh, 1); - _shl(dh, 1); - _shl(dh, 1); - _shl(dh, 1); - _cmp(ax, dx); - if (!flags.z()) - goto nextcheck2; - ch = es.byte(bx+1); - _and(ch, 15); -nextcheck2: - _add(bx, 2); - _dec(cl); - if (!flags.z()) - goto checkdestloop; - data.byte(kDestination) = ch; - bx = pop(); -} - void DreamGenContext::bresenhams() { STACK_CHECK; workoutframes(); @@ -18720,106 +17142,6 @@ success: data.byte(kTurndirection) = 0; } -void DreamGenContext::getroomspaths() { - STACK_CHECK; - al = data.byte(kRoomnum); - ah = 0; - cx = 144; - _mul(cx); - es = data.word(kReels); - bx = (0); - _add(bx, ax); -} - -void DreamGenContext::copyname() { - STACK_CHECK; - push(di); - findobname(); - di = pop(); - es = cs; - cx = 28; -make: - _lodsb(); - _cmp(al, ':'); - if (flags.z()) - goto finishmakename; - _cmp(al, 0); - if (flags.z()) - goto finishmakename; - _stosb(); - if (--cx) - goto make; -finishmakename: - _inc(cx); - al = 0; - _stosb(); - return; - al = 255; - _stosb(cx, true); -} - -void DreamGenContext::findobname() { - STACK_CHECK; - push(ax); - ah = 0; - _add(ax, ax); - bx = ax; - ax = pop(); - _cmp(ah, 5); - if (!flags.z()) - goto notpersonname; - push(ax); - _and(al, 127); - ah = 0; - bx = 64*2; - _mul(bx); - si = ax; - ds = data.word(kPeople); - _add(si, (0+24)); - cx = (0+24+(1026*2)); - ax = ds.word(si); - _add(ax, cx); - si = ax; - ax = pop(); - return; -notpersonname: - _cmp(ah, 4); - if (!flags.z()) - goto notextraname; - ds = data.word(kExtras); - _add(bx, (0+2080+30000+(16*114))); - ax = ds.word(bx); - _add(ax, (0+2080+30000+(16*114)+((114+2)*2))); - si = ax; - return; -notextraname: - _cmp(ah, 2); - if (!flags.z()) - goto notfreename; - ds = data.word(kFreedesc); - _add(bx, (0)); - ax = ds.word(bx); - _add(ax, (0+(82*2))); - si = ax; - return; -notfreename: - _cmp(ah, 1); - if (!flags.z()) - goto notsetname; - ds = data.word(kSetdesc); - _add(bx, (0)); - ax = ds.word(bx); - _add(ax, (0+(130*2))); - si = ax; - return; -notsetname: - ds = data.word(kBlockdesc); - _add(bx, (0)); - ax = ds.word(bx); - _add(ax, (0+(98*2))); - si = ax; -} - void DreamGenContext::showicon() { STACK_CHECK; _cmp(data.byte(kReallocation), 50); @@ -18924,22 +17246,6 @@ void DreamGenContext::showman() { showframe(); } -void DreamGenContext::showpanel() { - STACK_CHECK; - ds = data.word(kIcons1); - di = 72; - bx = 0; - al = 19; - ah = 0; - showframe(); - ds = data.word(kIcons1); - di = 192; - bx = 0; - al = 19; - ah = 0; - showframe(); -} - void DreamGenContext::roomname() { STACK_CHECK; di = 88; @@ -19248,32 +17554,6 @@ void DreamGenContext::putunderzoom() { multiput(); } -void DreamGenContext::crosshair() { - STACK_CHECK; - _cmp(data.byte(kCommandtype), 3); - if (flags.z()) - goto nocross; - _cmp(data.byte(kCommandtype), 10); - if (!flags.c()) - goto nocross; - es = data.word(kWorkspace); - ds = data.word(kIcons1); - di = (8)+24; - bx = (132)+19; - al = 9; - ah = 0; - showframe(); - return; -nocross: - es = data.word(kWorkspace); - ds = data.word(kIcons1); - di = (8)+24; - bx = (132)+19; - al = 29; - ah = 0; - showframe(); -} - void DreamGenContext::showpointer() { STACK_CHECK; showblink(); @@ -19446,22 +17726,6 @@ _tmp1: multiget(); } -void DreamGenContext::deltextline() { - STACK_CHECK; - di = data.word(kTextaddressx); - bx = data.word(kTextaddressy); - _cmp(data.byte(kForeignrelease), 0); - if (flags.z()) - goto _tmp1; - _sub(bx, 3); -_tmp1: - ds = data.word(kBuffers); - si = (0); - cl = (228); - ch = (13); - multiput(); -} - void DreamGenContext::animpointer() { STACK_CHECK; _cmp(data.byte(kPointermode), 2); @@ -19941,142 +18205,6 @@ blimey: es = pop(); } -void DreamGenContext::startloading() { - STACK_CHECK; - data.byte(kCombatcount) = 0; - al = cs.byte(bx+13); - data.byte(kRoomssample) = al; - al = cs.byte(bx+15); - data.byte(kMapx) = al; - al = cs.byte(bx+16); - data.byte(kMapy) = al; - al = cs.byte(bx+20); - data.byte(kLiftflag) = al; - al = cs.byte(bx+21); - data.byte(kManspath) = al; - data.byte(kDestination) = al; - data.byte(kFinaldest) = al; - al = cs.byte(bx+22); - data.byte(kFacing) = al; - data.byte(kTurntoface) = al; - al = cs.byte(bx+23); - data.byte(kCounttoopen) = al; - al = cs.byte(bx+24); - data.byte(kLiftpath) = al; - al = cs.byte(bx+25); - data.byte(kDoorpath) = al; - data.byte(kLastweapon) = -1; - al = cs.byte(bx+27); - push(ax); - al = cs.byte(bx+31); - ah = data.byte(kReallocation); - data.byte(kReallocation) = al; - dx = bx; - openfile(); - readheader(); - allocateload(); - ds = ax; - data.word(kBackdrop) = ax; - dx = (0); - loadseg(); - ds = data.word(kWorkspace); - dx = (0); - cx = 132*66; - al = 0; - fillspace(); - loadseg(); - sortoutmap(); - allocateload(); - data.word(kSetframes) = ax; - ds = ax; - dx = (0); - loadseg(); - ds = data.word(kSetdat); - dx = 0; - cx = (64*128); - al = 255; - fillspace(); - loadseg(); - allocateload(); - data.word(kReel1) = ax; - ds = ax; - dx = 0; - loadseg(); - allocateload(); - data.word(kReel2) = ax; - ds = ax; - dx = 0; - loadseg(); - allocateload(); - data.word(kReel3) = ax; - ds = ax; - dx = 0; - loadseg(); - allocateload(); - data.word(kReels) = ax; - ds = ax; - dx = 0; - loadseg(); - allocateload(); - data.word(kPeople) = ax; - ds = ax; - dx = 0; - loadseg(); - allocateload(); - data.word(kSetdesc) = ax; - ds = ax; - dx = 0; - loadseg(); - allocateload(); - data.word(kBlockdesc) = ax; - ds = ax; - dx = 0; - loadseg(); - allocateload(); - data.word(kRoomdesc) = ax; - ds = ax; - dx = 0; - loadseg(); - allocateload(); - data.word(kFreeframes) = ax; - ds = ax; - dx = 0; - loadseg(); - ds = data.word(kFreedat); - dx = 0; - cx = (16*80); - al = 255; - fillspace(); - loadseg(); - allocateload(); - data.word(kFreedesc) = ax; - ds = ax; - dx = (0); - loadseg(); - closefile(); - findroominloc(); - deletetaken(); - setallchanges(); - autoappear(); - al = data.byte(kNewlocation); - getroomdata(); - data.byte(kLastweapon) = -1; - data.byte(kMandead) = 0; - data.word(kLookcounter) = 160; - data.byte(kNewlocation) = 255; - data.byte(kLinepointer) = 254; - ax = pop(); - _cmp(al, 255); - if (flags.z()) - goto dontwalkin; - data.byte(kManspath) = al; - push(bx); - autosetwalk(); - bx = pop(); -dontwalkin: - findxyfrompath(); -} - void DreamGenContext::disablepath() { STACK_CHECK; push(cx); @@ -20146,25 +18274,6 @@ lookx: data.byte(kRoomnum) = cl; } -void DreamGenContext::getroomdata() { - STACK_CHECK; - ah = 0; - cx = 32; - _mul(cx); - bx = 6187; - _add(bx, ax); -} - -void DreamGenContext::readheader() { - STACK_CHECK; - ds = cs; - dx = 6091; - cx = (6187-6091); - readfromfile(); - es = cs; - di = 6141; -} - void DreamGenContext::allocateload() { STACK_CHECK; push(es); @@ -20177,23 +18286,6 @@ void DreamGenContext::allocateload() { es = pop(); } -void DreamGenContext::fillspace() { - STACK_CHECK; - push(es); - push(ds); - push(dx); - push(di); - push(bx); - di = dx; - es = ds; - _stosb(cx, true); - bx = pop(); - di = pop(); - dx = pop(); - ds = pop(); - es = pop(); -} - void DreamGenContext::getridoftemp() { STACK_CHECK; es = data.word(kTempgraphics); @@ -20912,8 +19004,6 @@ void DreamGenContext::__dispatch_call(uint16 addr) { case addr_priest: priest(); break; case addr_madmanstelly: madmanstelly(); break; case addr_madman: madman(); break; - case addr_madmantext: madmantext(); break; - case addr_madmode: madmode(); break; case addr_priesttext: priesttext(); break; case addr_textforend: textforend(); break; case addr_textformonk: textformonk(); break; @@ -20923,14 +19013,10 @@ void DreamGenContext::__dispatch_call(uint16 addr) { case addr_sparky: sparky(); break; case addr_train: train(); break; case addr_addtopeoplelist: addtopeoplelist(); break; - case addr_showgamereel: showgamereel(); break; case addr_checkspeed: checkspeed(); break; case addr_delsprite: delsprite(); break; case addr_checkone: checkone(); break; - case addr_findsource: findsource(); break; case addr_mainman: mainman(); break; - case addr_aboutturn: aboutturn(); break; - case addr_facerightway: facerightway(); break; case addr_checkforexit: checkforexit(); break; case addr_adjustdown: adjustdown(); break; case addr_adjustup: adjustup(); break; @@ -20940,28 +19026,16 @@ void DreamGenContext::__dispatch_call(uint16 addr) { case addr_initrain: initrain(); break; case addr_splitintolines: splitintolines(); break; case addr_getblockofpixel: getblockofpixel(); break; - case addr_showrain: showrain(); break; case addr_backobject: backobject(); break; case addr_liftnoise: liftnoise(); break; case addr_random: random(); break; case addr_steady: steady(); break; case addr_constant: constant(); break; - case addr_doorway: doorway(); break; - case addr_widedoor: widedoor(); break; - case addr_lockeddoorway: lockeddoorway(); break; - case addr_updatepeople: updatepeople(); break; - case addr_getreelframeax: getreelframeax(); break; case addr_reelsonscreen: reelsonscreen(); break; - case addr_plotreel: plotreel(); break; case addr_soundonreels: soundonreels(); break; case addr_reconstruct: reconstruct(); break; - case addr_dealwithspecial: dealwithspecial(); break; - case addr_movemap: movemap(); break; - case addr_getreelstart: getreelstart(); break; - case addr_showreelframe: showreelframe(); break; case addr_deleverything: deleverything(); break; case addr_dumpeverything: dumpeverything(); break; - case addr_allocatework: allocatework(); break; case addr_showpcx: showpcx(); break; case addr_loadpalfromiff: loadpalfromiff(); break; case addr_setmode: setmode(); break; @@ -20971,12 +19045,9 @@ void DreamGenContext::__dispatch_call(uint16 addr) { case addr_pixelcheckset: pixelcheckset(); break; case addr_createpanel: createpanel(); break; case addr_createpanel2: createpanel2(); break; - case addr_clearwork: clearwork(); break; case addr_vsync: vsync(); break; case addr_doshake: doshake(); break; - case addr_zoom: zoom(); break; case addr_delthisone: delthisone(); break; - case addr_doblocks: doblocks(); break; case addr_transferinv: transferinv(); break; case addr_transfermap: transfermap(); break; case addr_fadedos: fadedos(); break; @@ -21099,7 +19170,6 @@ void DreamGenContext::__dispatch_call(uint16 addr) { case addr_addlength: addlength(); break; case addr_drawflags: drawflags(); break; case addr_showallobs: showallobs(); break; - case addr_makebackob: makebackob(); break; case addr_showallfree: showallfree(); break; case addr_showallex: showallex(); break; case addr_calcfrframe: calcfrframe(); break; @@ -21276,9 +19346,7 @@ void DreamGenContext::__dispatch_call(uint16 addr) { case addr_setallchanges: setallchanges(); break; case addr_dochange: dochange(); break; case addr_autoappear: autoappear(); break; - case addr_dumptimedtext: dumptimedtext(); break; case addr_setuptimeduse: setuptimeduse(); break; - case addr_setuptimedtemp: setuptimedtemp(); break; case addr_edenscdplayer: edenscdplayer(); break; case addr_usewall: usewall(); break; case addr_usechurchgate: usechurchgate(); break; @@ -21398,16 +19466,12 @@ void DreamGenContext::__dispatch_call(uint16 addr) { case addr_out22c: out22c(); break; case addr_playchannel0: playchannel0(); break; case addr_playchannel1: playchannel1(); break; - case addr_makenextblock: makenextblock(); break; case addr_volumeadjust: volumeadjust(); break; - case addr_loopchannel0: loopchannel0(); break; case addr_channel0only: channel0only(); break; case addr_channel1only: channel1only(); break; - case addr_channel0tran: channel0tran(); break; case addr_bothchannels: bothchannels(); break; case addr_saveems: saveems(); break; case addr_restoreems: restoreems(); break; - case addr_domix: domix(); break; case addr_dmaend: dmaend(); break; case addr_startdmablock: startdmablock(); break; case addr_setuppit: setuppit(); break; @@ -21430,7 +19494,6 @@ void DreamGenContext::__dispatch_call(uint16 addr) { case addr_clearrest: clearrest(); break; case addr_deallocatemem: deallocatemem(); break; case addr_allocatemem: allocatemem(); break; - case addr_parseblaster: parseblaster(); break; case addr_startup: startup(); break; case addr_startup1: startup1(); break; case addr_screenupdate: screenupdate(); break; @@ -21448,7 +19511,6 @@ void DreamGenContext::__dispatch_call(uint16 addr) { case addr_madmanrun: madmanrun(); break; case addr_checkcoords: checkcoords(); break; case addr_identifyob: identifyob(); break; - case addr_checkifperson: checkifperson(); break; case addr_checkifset: checkifset(); break; case addr_checkifex: checkifex(); break; case addr_checkiffree: checkiffree(); break; @@ -21467,7 +19529,6 @@ void DreamGenContext::__dispatch_call(uint16 addr) { case addr_obname: obname(); break; case addr_finishedwalking: finishedwalking(); break; case addr_examineobtext: examineobtext(); break; - case addr_commandwithob: commandwithob(); break; case addr_commandonly: commandonly(); break; case addr_printmessage: printmessage(); break; case addr_printmessage2: printmessage2(); break; @@ -21476,17 +19537,11 @@ void DreamGenContext::__dispatch_call(uint16 addr) { case addr_walktotext: walktotext(); break; case addr_getflagunderp: getflagunderp(); break; case addr_setwalk: setwalk(); break; - case addr_autosetwalk: autosetwalk(); break; - case addr_checkdest: checkdest(); break; case addr_bresenhams: bresenhams(); break; case addr_workoutframes: workoutframes(); break; - case addr_getroomspaths: getroomspaths(); break; - case addr_copyname: copyname(); break; - case addr_findobname: findobname(); break; case addr_showicon: showicon(); break; case addr_middlepanel: middlepanel(); break; case addr_showman: showman(); break; - case addr_showpanel: showpanel(); break; case addr_roomname: roomname(); break; case addr_usecharset1: usecharset1(); break; case addr_usetempcharset: usetempcharset(); break; @@ -21506,12 +19561,10 @@ void DreamGenContext::__dispatch_call(uint16 addr) { case addr_getunderzoom: getunderzoom(); break; case addr_dumpzoom: dumpzoom(); break; case addr_putunderzoom: putunderzoom(); break; - case addr_crosshair: crosshair(); break; case addr_showpointer: showpointer(); break; case addr_delpointer: delpointer(); break; case addr_dumppointer: dumppointer(); break; case addr_undertextline: undertextline(); break; - case addr_deltextline: deltextline(); break; case addr_animpointer: animpointer(); break; case addr_setmouse: setmouse(); break; case addr_readmouse: readmouse(); break; @@ -21538,15 +19591,11 @@ void DreamGenContext::__dispatch_call(uint16 addr) { case addr_restorereels: restorereels(); break; case addr_restoreall: restoreall(); break; case addr_sortoutmap: sortoutmap(); break; - case addr_startloading: startloading(); break; case addr_disablepath: disablepath(); break; case addr_findxyfrompath: findxyfrompath(); break; case addr_findroominloc: findroominloc(); break; - case addr_getroomdata: getroomdata(); break; - case addr_readheader: readheader(); break; case addr_dontloadseg: dontloadseg(); break; case addr_allocateload: allocateload(); break; - case addr_fillspace: fillspace(); break; case addr_getridoftemp: getridoftemp(); break; case addr_getridoftemptext: getridoftemptext(); break; case addr_getridoftemp2: getridoftemp2(); break; diff --git a/engines/dreamweb/dreamgen.h b/engines/dreamweb/dreamgen.h index c2aa204942..e1071dfebc 100644 --- a/engines/dreamweb/dreamgen.h +++ b/engines/dreamweb/dreamgen.h @@ -57,15 +57,11 @@ public: static const uint16 addr_getridoftemp2 = 0xcb78; static const uint16 addr_getridoftemptext = 0xcb74; static const uint16 addr_getridoftemp = 0xcb70; - static const uint16 addr_fillspace = 0xcb6c; static const uint16 addr_allocateload = 0xcb68; static const uint16 addr_dontloadseg = 0xcb64; - static const uint16 addr_readheader = 0xcb60; - static const uint16 addr_getroomdata = 0xcb5c; static const uint16 addr_findroominloc = 0xcb58; static const uint16 addr_findxyfrompath = 0xcb54; static const uint16 addr_disablepath = 0xcb50; - static const uint16 addr_startloading = 0xcb4c; static const uint16 addr_sortoutmap = 0xcb48; static const uint16 addr_restoreall = 0xcb44; static const uint16 addr_restorereels = 0xcb40; @@ -92,12 +88,10 @@ public: static const uint16 addr_readmouse = 0xcae4; static const uint16 addr_setmouse = 0xcae0; static const uint16 addr_animpointer = 0xcadc; - static const uint16 addr_deltextline = 0xcad4; static const uint16 addr_undertextline = 0xcad0; static const uint16 addr_dumppointer = 0xcacc; static const uint16 addr_delpointer = 0xcac8; static const uint16 addr_showpointer = 0xcac4; - static const uint16 addr_crosshair = 0xcac0; static const uint16 addr_putunderzoom = 0xcabc; static const uint16 addr_dumpzoom = 0xcab8; static const uint16 addr_getunderzoom = 0xcab4; @@ -117,17 +111,11 @@ public: static const uint16 addr_usetempcharset = 0xca7c; static const uint16 addr_usecharset1 = 0xca78; static const uint16 addr_roomname = 0xca74; - static const uint16 addr_showpanel = 0xca70; static const uint16 addr_showman = 0xca6c; static const uint16 addr_middlepanel = 0xca68; static const uint16 addr_showicon = 0xca64; - static const uint16 addr_findobname = 0xca60; - static const uint16 addr_copyname = 0xca5c; - static const uint16 addr_getroomspaths = 0xca58; static const uint16 addr_workoutframes = 0xca54; static const uint16 addr_bresenhams = 0xca50; - static const uint16 addr_checkdest = 0xca4c; - static const uint16 addr_autosetwalk = 0xca48; static const uint16 addr_setwalk = 0xca44; static const uint16 addr_getflagunderp = 0xca40; static const uint16 addr_walktotext = 0xca3c; @@ -136,7 +124,6 @@ public: static const uint16 addr_printmessage2 = 0xca30; static const uint16 addr_printmessage = 0xca2c; static const uint16 addr_commandonly = 0xca28; - static const uint16 addr_commandwithob = 0xca24; static const uint16 addr_examineobtext = 0xca20; static const uint16 addr_finishedwalking = 0xca1c; static const uint16 addr_obname = 0xca18; @@ -155,7 +142,6 @@ public: static const uint16 addr_checkiffree = 0xc9e4; static const uint16 addr_checkifex = 0xc9e0; static const uint16 addr_checkifset = 0xc9dc; - static const uint16 addr_checkifperson = 0xc9d8; static const uint16 addr_identifyob = 0xc9d4; static const uint16 addr_checkcoords = 0xc9d0; static const uint16 addr_madmanrun = 0xc9cc; @@ -174,7 +160,6 @@ public: static const uint16 addr_screenupdate = 0xc99c; static const uint16 addr_startup1 = 0xc998; static const uint16 addr_startup = 0xc994; - static const uint16 addr_parseblaster = 0xc990; static const uint16 addr_allocatemem = 0xc988; static const uint16 addr_deallocatemem = 0xc984; static const uint16 addr_clearrest = 0xc980; @@ -196,16 +181,12 @@ public: static const uint16 addr_setuppit = 0xc93c; static const uint16 addr_startdmablock = 0xc938; static const uint16 addr_dmaend = 0xc934; - static const uint16 addr_domix = 0xc930; static const uint16 addr_restoreems = 0xc92c; static const uint16 addr_saveems = 0xc928; static const uint16 addr_bothchannels = 0xc924; - static const uint16 addr_channel0tran = 0xc920; static const uint16 addr_channel1only = 0xc91c; static const uint16 addr_channel0only = 0xc918; - static const uint16 addr_loopchannel0 = 0xc90c; static const uint16 addr_volumeadjust = 0xc908; - static const uint16 addr_makenextblock = 0xc904; static const uint16 addr_playchannel1 = 0xc900; static const uint16 addr_playchannel0 = 0xc8fc; static const uint16 addr_out22c = 0xc8f8; @@ -327,9 +308,7 @@ public: static const uint16 addr_usechurchgate = 0xc730; static const uint16 addr_usewall = 0xc72c; static const uint16 addr_edenscdplayer = 0xc728; - static const uint16 addr_setuptimedtemp = 0xc720; static const uint16 addr_setuptimeduse = 0xc71c; - static const uint16 addr_dumptimedtext = 0xc718; static const uint16 addr_autoappear = 0xc70c; static const uint16 addr_dochange = 0xc708; static const uint16 addr_setallchanges = 0xc704; @@ -506,7 +485,6 @@ public: static const uint16 addr_calcfrframe = 0xc454; static const uint16 addr_showallex = 0xc450; static const uint16 addr_showallfree = 0xc44c; - static const uint16 addr_makebackob = 0xc448; static const uint16 addr_showallobs = 0xc444; static const uint16 addr_drawflags = 0xc43c; static const uint16 addr_addlength = 0xc438; @@ -629,12 +607,9 @@ public: static const uint16 addr_fadedos = 0xc248; static const uint16 addr_transfermap = 0xc244; static const uint16 addr_transferinv = 0xc240; - static const uint16 addr_doblocks = 0xc228; static const uint16 addr_delthisone = 0xc214; - static const uint16 addr_zoom = 0xc210; static const uint16 addr_doshake = 0xc20c; static const uint16 addr_vsync = 0xc208; - static const uint16 addr_clearwork = 0xc204; static const uint16 addr_createpanel2 = 0xc200; static const uint16 addr_createpanel = 0xc1fc; static const uint16 addr_pixelcheckset = 0xc1f8; @@ -644,28 +619,16 @@ public: static const uint16 addr_setmode = 0xc1dc; static const uint16 addr_loadpalfromiff = 0xc1d8; static const uint16 addr_showpcx = 0xc1cc; - static const uint16 addr_allocatework = 0xc1c8; static const uint16 addr_dumpeverything = 0xc1c4; static const uint16 addr_deleverything = 0xc1c0; - static const uint16 addr_showreelframe = 0xc1bc; - static const uint16 addr_getreelstart = 0xc1b8; - static const uint16 addr_movemap = 0xc1b4; - static const uint16 addr_dealwithspecial = 0xc1b0; static const uint16 addr_reconstruct = 0xc1ac; static const uint16 addr_soundonreels = 0xc1a8; - static const uint16 addr_plotreel = 0xc1a4; static const uint16 addr_reelsonscreen = 0xc1a0; - static const uint16 addr_getreelframeax = 0xc19c; - static const uint16 addr_updatepeople = 0xc198; - static const uint16 addr_lockeddoorway = 0xc194; - static const uint16 addr_widedoor = 0xc18c; - static const uint16 addr_doorway = 0xc188; static const uint16 addr_constant = 0xc184; static const uint16 addr_steady = 0xc180; static const uint16 addr_random = 0xc17c; static const uint16 addr_liftnoise = 0xc178; static const uint16 addr_backobject = 0xc170; - static const uint16 addr_showrain = 0xc16c; static const uint16 addr_getblockofpixel = 0xc168; static const uint16 addr_splitintolines = 0xc164; static const uint16 addr_initrain = 0xc160; @@ -675,14 +638,10 @@ public: static const uint16 addr_adjustup = 0xc150; static const uint16 addr_adjustdown = 0xc14c; static const uint16 addr_checkforexit = 0xc148; - static const uint16 addr_facerightway = 0xc144; - static const uint16 addr_aboutturn = 0xc13c; static const uint16 addr_mainman = 0xc138; - static const uint16 addr_findsource = 0xc130; static const uint16 addr_checkone = 0xc12c; static const uint16 addr_delsprite = 0xc11c; static const uint16 addr_checkspeed = 0xc110; - static const uint16 addr_showgamereel = 0xc10c; static const uint16 addr_addtopeoplelist = 0xc108; static const uint16 addr_train = 0xc104; static const uint16 addr_sparky = 0xc100; @@ -692,8 +651,6 @@ public: static const uint16 addr_textformonk = 0xc0f0; static const uint16 addr_textforend = 0xc0ec; static const uint16 addr_priesttext = 0xc0e8; - static const uint16 addr_madmode = 0xc0e4; - static const uint16 addr_madmantext = 0xc0e0; static const uint16 addr_madman = 0xc0dc; static const uint16 addr_madmanstelly = 0xc0d8; static const uint16 addr_priest = 0xc0d4; @@ -1323,10 +1280,10 @@ public: void bothchannels(); void usewire(); void getnamepos(); - void drawitall(); + void loadtemptext(); void clearstartpal(); void femalefan(); - void showgamereel(); + //void showgamereel(); void identifyob(); void trysoundalloc(); void uselighter(); @@ -1338,7 +1295,7 @@ public: void clearbuffers(); void neterror(); void storeit(); - void lockeddoorway(); + //void lockeddoorway(); void isitworn(); //void putundertimed(); void dumpmap(); @@ -1356,14 +1313,14 @@ public: void readkey(); void louis(); void entrytexts(); - void getreelstart(); + //void getreelstart(); void buttonenter(); void checkinput(); - void crosshair(); + //void crosshair(); void bresenhams(); void getbackfromops(); //void frameoutv(); - void restoreall(); + void opensarters(); void screenupdate(); void addlength(); void wornerror(); @@ -1372,29 +1329,32 @@ public: void commandonly(); void adjustlen(); void deallocatemem(); - void mainscreen(); + void checkforemm(); void watchreel(); void showfolder(); void turnanypathoff(); void openfilefromc(); void gettime(); - void clearwork(); + //void clearwork(); void loadtraveltext(); //void worktoscreen(); void getexpos(); void fadedos(); + //void fillspace(); //void multiget(); + //void autosetwalk(); void fadeupmonfirst(); void drawfloor(); void loadkeypad(); - void findsource(); + //void findsource(); void clearendpal(); void findtext1(); void isryanholding(); - void interupttest(); + void showslots(); void usecashcard(); void usewall(); void opentomb(); + //void findobname(); void buttonfour(); void animpointer(); //void lockmon(); @@ -1409,8 +1369,8 @@ public: void additionaltext(); //void kernchars(); void othersmoker(); - void autosetwalk(); - void setuptimedtemp(); + void dofade(); + //void setuptimedtemp(); void blocknametext(); void useelevator5(); void useelevator4(); @@ -1420,13 +1380,13 @@ public: void useelevator2(); void buttonone(); void keyboardread(); - void deltextline(); + //void deltextline(); void entercode(); void getopenedsize(); void getpersframe(); void doshake(); void resetkeyboard(); - void showpanel(); + //void showpanel(); void soundstartup(); void slabdoora(); void fadeupyellows(); @@ -1450,17 +1410,16 @@ public: void eden(); void showdiary(); void purgealocation(); - void updatepeople(); + //void updatepeople(); void slabdoorf(); void addtopeoplelist(); void hangoncurs(); void sparkydrip(); - //void modifychar(); void compare(); void printcurs(); //void convertkey(); void outofopen(); - void dealwithspecial(); + //void dealwithspecial(); //void eraseoldobs(); void dircom(); //void liftsprite(); @@ -1473,8 +1432,8 @@ public: void fadescreenup(); void loadold(); void loadtempcharset(); + void showbyte(); void useslab(); - void aboutturn(); void usealtar(); void createpanel2(); void turnonpower(); @@ -1488,7 +1447,7 @@ public: void endgame(); void monprint(); void usepipe(); - void startloading(); + //void startloading(); void getunderzoom(); void candles(); void backobject(); @@ -1496,7 +1455,7 @@ public: void reminders(); void selectslot2(); void runtap(); - void domix(); + //void domix(); void priesttext(); void paneltomap(); void obname(); @@ -1508,13 +1467,11 @@ public: void disablesoundint(); void checkifset(); void showallex(); - void showrain(); void openpoolboss(); void buttontwo(); - void fillopen(); //void usetimedtext(); void delsprite(); - void getroomspaths(); + //void getroomspaths(); //void dumptextline(); void fadescreendownhalf(); void useplate(); @@ -1524,9 +1481,10 @@ public: void isitdescribed(); void hotelbell(); void loadspeech(); + void interupttest(); //void cls(); //void printsprites(); - void checkifperson(); + //void checkifperson(); void showallobs(); //void getnumber(); void adjustleft(); @@ -1546,6 +1504,7 @@ public: //void printchar(); void showkeypad(); void obtoinv(); + //void getroomdata(); void removeobfrominv(); void usecoveredbox(); void openyourneighbour(); @@ -1562,7 +1521,7 @@ public: void discops(); //void printdirect(); void delthisone(); - void makebackob(); + //void makebackob(); void middlepanel(); void dumpwatch(); void saveload(); @@ -1577,8 +1536,8 @@ public: void locklightoff(); void wearwatch(); void runintroseq(); - void doblocks(); - void showbyte(); + //void doblocks(); + void restoreall(); void allpalette(); void findormake(); void nextsymbol(); @@ -1593,14 +1552,14 @@ public: void folderhints(); void openhoteldoor(); void removesetobject(); - void dumptimedtext(); + //void dumptimedtext(); //void frameoutfx(); void blank(); void drinker(); void nextcolon(); void placefreeobject(); void delpointer(); - void loopchannel0(); + //void loopchannel0(); void initrain(); void showleftpage(); void rockstar(); @@ -1635,7 +1594,7 @@ public: void showpointer(); void usecooker(); void loadmenu(); - void checkforemm(); + //void aboutturn(); void checkifpathison(); void smallcandle(); void receptionist(); @@ -1656,7 +1615,7 @@ public: void putundermenu(); void checkifex(); void intromagic2(); - void findobname(); + void mainscreen(); void edeninbath(); void intromagic1(); void showdiarypage(); @@ -1671,12 +1630,12 @@ public: void steady(); void pixelcheckset(); void reexfrominv(); - void fillspace(); + void examinventory(); void talk(); void usedryer(); void dumpeverything(); void usehatch(); - void zoom(); + //void zoom(); void outofinv(); void viewfolder(); //void walking(); @@ -1690,7 +1649,7 @@ public: void playguitar(); void lastfolder(); void transfermap(); - void showreelframe(); + //void showreelframe(); void showmonk(); void diarykeyn(); void set16colpalette(); @@ -1711,7 +1670,7 @@ public: void getridofpit(); void convnum(); void nothelderror(); - void readheader(); + //void readheader(); void getsetad(); void getyad(); void reconstruct(); @@ -1778,11 +1737,10 @@ public: void loadintotemp2(); void gamer(); void personnametext(); - void quitsymbol(); void readfromfile(); void initialinv(); - void showslots(); - void dofade(); + void quitsymbol(); + //void modifychar(); void hangon(); void settopright(); void findsetobject(); @@ -1809,14 +1767,15 @@ public: void scrollmonitor(); void setsoundoff(); void setpickup(); + //void doorway(); void dropobject(); void printmessage(); void reexfromopen(); void fillryan(); - void loadtemptext(); + void drawitall(); void usestereo(); void showcurrentfile(); - void copyname(); + //void copyname(); void look(); void setmouse(); void checkone(); @@ -1832,32 +1791,32 @@ public: void afterintroroom(); void blockget(); void usetrainer(); - void allocatework(); + //void allocatework(); void addtopresslist(); void walkandexamine(); void dmaend(); //void quickquit2(); void twodigitnum(); - void madmantext(); + //void madmantext(); void dumpcurrent(); void textforend(); void showdiarykeys(); void dontloadseg(); - void madmode(); + //void madmode(); void intro3text(); void allocatemem(); void sortoutmap(); - void doorway(); + //void showrain(); void useopened(); void inventory(); void powerlightoff(); - void getroomdata(); + void fillopen(); void showoutermenu(); void signon(); void deleteextext(); void foghornsound(); void showrightpage(); - void openhoteldoor2(); + void showloadops(); void examicon(); void showgun(); void switchryanon(); @@ -1869,7 +1828,7 @@ public: void opentvdoor(); void triggermessage(); void finalframe(); - void plotreel(); + //void plotreel(); void swapwithopen(); //void makesprite(); void dreamweb(); @@ -1883,7 +1842,6 @@ public: void turnanypathon(); void restorereels(); void setwalk(); - //void printboth(); void useroutine(); void zoomicon(); void hotelcontrol(); @@ -1900,10 +1858,10 @@ public: void makecaps(); void read(); void fadescreenups(); - void checkdest(); + //void checkdest(); //void initman(); void loadpalfromiff(); - void facerightway(); + //void facerightway(); void startup1(); void findlen(); void showsymbol(); @@ -1917,7 +1875,7 @@ public: //void clearsprites(); void obpicture(); void selectopenob(); - void widedoor(); + //void widedoor(); void security(); //void printasprite(); void buttonfive(); @@ -1931,7 +1889,7 @@ public: void showman(); void readmouse2(); void newplace(); - void movemap(); + //void movemap(); void loadsample(); void usecardreader1(); void usecardreader2(); @@ -1941,7 +1899,7 @@ public: void quitkey(); void openfile(); void usecharset1(); - void makenextblock(); + //void makenextblock(); void showpuztext(); void addalong(); //void width160(); @@ -1949,7 +1907,6 @@ public: //void dodoor(); void greyscalesum(); void buttoneight(); - void opensarters(); void findexobject(); void errormessage2(); void usechurchhole(); @@ -1958,7 +1915,7 @@ public: void fadecalculation(); void waitframes(); void clearrest(); - void getreelframeax(); + //void getreelframeax(); void barwoman(); void roomname(); void credits(); @@ -1998,9 +1955,9 @@ public: void redrawmainscrn(); void finishedwalking(); void findallryan(); - void channel0tran(); + //void channel0tran(); void buttonpress(); - void parseblaster(); + //void parseblaster(); void callhotellift(); void makemainscreen(); void intromonks2(); @@ -2034,12 +1991,12 @@ public: void intro(); void hangonp(); void fadescreendowns(); - void showloadops(); + void openhoteldoor2(); void getridoftempsp(); void scanfornames(); void setallchanges(); void newgame(); - void examinventory(); + //void printboth(); void standardload(); void undertextline(); void findroominloc(); @@ -2063,7 +2020,7 @@ public: void isitright(); void businessman(); void switchryanoff(); - void commandwithob(); + //void commandwithob(); void panelicons1(); void adjustdown(); void withwhat(); diff --git a/engines/dreamweb/module.mk b/engines/dreamweb/module.mk index 3b0c7f3325..6c4c506695 100644 --- a/engines/dreamweb/module.mk +++ b/engines/dreamweb/module.mk @@ -5,7 +5,10 @@ MODULE_OBJS := \ detection.o \ dreamweb.o \ dreamgen.o \ - stubs.o + print.o \ + sprite.o \ + stubs.o \ + vgagrafx.o # This module can be built as a plugin ifeq ($(ENABLE_DREAMWEB), DYNAMIC_PLUGIN) diff --git a/engines/dreamweb/print.cpp b/engines/dreamweb/print.cpp new file mode 100644 index 0000000000..26084c35d1 --- /dev/null +++ b/engines/dreamweb/print.cpp @@ -0,0 +1,224 @@ +/* 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 "dreamweb/dreamweb.h" +#include "engines/util.h" +#include "graphics/surface.h" + +namespace DreamGen { + +void DreamGenContext::printboth(const Frame *charSet, uint16 *x, uint16 y, uint8 c, uint8 nextChar) { + uint16 newX = *x; + uint8 width, height; + printchar(charSet, &newX, y, c, nextChar, &width, &height); + multidump(*x, y, width, height); + *x = newX; +} + +uint8 DreamGenContext::getnextword(const Frame *charSet, const uint8 *string, uint8 *totalWidth, uint8 *charCount) { + *totalWidth = 0; + *charCount = 0; + while(true) { + uint8 firstChar = *string; + ++string; + ++*charCount; + if ((firstChar == ':') || (firstChar == 0)) { //endall + *totalWidth += 6; + return 1; + } + if (firstChar == 32) { //endword + *totalWidth += 6; + return 0; + } + firstChar = engine->modifyChar(firstChar); + if (firstChar != 255) { + uint8 secondChar = *string; + uint8 width = charSet[firstChar - 32 + data.word(kCharshift)].width; + width = kernchars(firstChar, secondChar, width); + *totalWidth += width; + } + } +} + +void DreamGenContext::printchar() { + uint16 x = di; + uint8 width, height; + printchar((const Frame *)ds.ptr(0, 0), &x, bx, al, ah, &width, &height); + di = x; + cl = width; + ch = height; +} + +void DreamGenContext::printchar(const Frame *charSet, uint16* x, uint16 y, uint8 c, uint8 nextChar, uint8 *width, uint8 *height) { + if (c == 255) + return; + push(si); + push(di); + if (data.byte(kForeignrelease) != 0) + y -= 3; + uint16 tmp = c - 32 + data.word(kCharshift); + showframe(charSet, *x, y, tmp & 0x1ff, (tmp >> 8) & 0xfe, width, height); + di = pop(); + si = pop(); + _cmp(data.byte(kKerning), 0); + if (flags.z()) + *width = kernchars(c, nextChar, *width); + (*x) += *width; +} + +void DreamGenContext::printslow() { + al = printslow(es.ptr(si, 0), di, bx, dl, (bool)(dl & 1)); +} + +uint8 DreamGenContext::printslow(const uint8 *string, uint16 x, uint16 y, uint8 maxWidth, bool centered) { + data.byte(kPointerframe) = 1; + data.byte(kPointermode) = 3; + const Frame* charSet = (const Frame *)segRef(data.word(kCharset1)).ptr(0, 0); + do { + uint16 offset = x; + uint16 charCount = getnumber(charSet, string, maxWidth, centered, &offset); + do { + uint8 c0 = string[0]; + uint8 c1 = string[1]; + uint8 c2 = string[2]; + c0 = engine->modifyChar(c0); + printboth(charSet, &offset, y, c0, c1); + if ((c1 == 0) || (c1 == ':')) { + return 0; + } + if (charCount != 1) { + c1 = engine->modifyChar(c1); + data.word(kCharshift) = 91; + uint16 offset2 = offset; + printboth(charSet, &offset2, y, c1, c2); + data.word(kCharshift) = 0; + for (int i=0; i<2; ++i) { + waitframes(); + if (ax == 0) + continue; + if (ax != data.word(kOldbutton)) { + return 1; + } + } + } + + ++string; + --charCount; + } while (charCount); + y += 10; + } while (true); +} + +void DreamGenContext::printdirect() { + uint16 y = bx; + uint16 initialSi = si; + const uint8 *initialString = es.ptr(si, 0); + const uint8 *string = initialString; + printdirect(&string, di, &y, dl, (bool)(dl & 1)); + si = initialSi + (string - initialString); + bx = y; +} + +void DreamGenContext::printdirect(const uint8** string, uint16 x, uint16 *y, uint8 maxWidth, bool centered) { + data.word(kLastxpos) = x; + const Frame *charSet = (const Frame *)segRef(data.word(kCurrentset)).ptr(0, 0); + while (true) { + uint16 offset = x; + uint8 charCount = getnumber(charSet, *string, maxWidth, centered, &offset); + uint16 i = offset; + do { + uint8 c = (*string)[0]; + uint8 nextChar = (*string)[1]; + ++(*string); + if ((c == 0) || (c == ':')) { + return; + } + c = engine->modifyChar(c); + uint8 width, height; + printchar(charSet, &i, *y, c, nextChar, &width, &height); + data.word(kLastxpos) = i; + --charCount; + } while(charCount); + *y += data.word(kLinespacing); + } +} + +void DreamGenContext::getnumber() { + uint16 offset = di; + cl = getnumber((Frame *)ds.ptr(0, 0), es.ptr(si, 0), dl, (bool)(dl & 1), &offset); + di = offset; +} + +uint8 DreamGenContext::getnumber(const Frame *charSet, const uint8 *string, uint16 maxWidth, bool centered, uint16* offset) { + uint8 totalWidth = 0; + uint8 charCount = 0; + while (true) { + uint8 wordTotalWidth, wordCharCount; + uint8 done = getnextword(charSet, string, &wordTotalWidth, &wordCharCount); + string += wordCharCount; + + if (done == 1) { //endoftext + ax = totalWidth + wordTotalWidth - 10; + if (ax < maxWidth) { + totalWidth += wordTotalWidth; + charCount += wordCharCount; + } + + if (centered) { + ax = (maxWidth & 0xfe) + 2 + 20 - totalWidth; + ax /= 2; + } else { + ax = 0; + } + *offset += ax; + return charCount; + } + ax = totalWidth + wordTotalWidth - 10; + if (ax >= maxWidth) { //gotoverend + if (centered) { + ax = (maxWidth & 0xfe) - totalWidth + 20; + ax /= 2; + } else { + ax = 0; + } + *offset += ax; + return charCount; + } + totalWidth += wordTotalWidth; + charCount += wordCharCount; + } +} + +uint8 DreamGenContext::kernchars(uint8 firstChar, uint8 secondChar, uint8 width) { + if ((firstChar == 'a') || (al == 'u')) { + if ((secondChar == 'n') || (secondChar == 't') || (secondChar == 'r') || (secondChar == 'i') || (secondChar == 'l')) + return width-1; + } + return width; +} + +void DreamGenContext::kernchars() { + cl = kernchars(al, ah, cl); +} + +} /*namespace dreamgen */ + diff --git a/engines/dreamweb/runtime.h b/engines/dreamweb/runtime.h index 0c27c12e3c..8aa71b285c 100644 --- a/engines/dreamweb/runtime.h +++ b/engines/dreamweb/runtime.h @@ -287,6 +287,12 @@ public: _freeSegments.push_back(id); } + SegmentRef segRef(uint16 seg) { + SegmentRef result(this); + result = seg; + return result; + } + inline void _cmp(uint8 a, uint8 b) { _sub(a, b); } diff --git a/engines/dreamweb/sprite.cpp b/engines/dreamweb/sprite.cpp new file mode 100644 index 0000000000..2129d1ca6d --- /dev/null +++ b/engines/dreamweb/sprite.cpp @@ -0,0 +1,874 @@ +/* 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 "dreamweb/dreamweb.h" +#include "engines/util.h" +#include "graphics/surface.h" + +namespace DreamGen { + +Sprite *DreamGenContext::spritetable() { + Sprite *sprite = (Sprite *)segRef(data.word(kBuffers)).ptr(kSpritetable, 16 * sizeof(Sprite)); + return sprite; +} + +void DreamGenContext::printsprites() { + for (size_t priority = 0; priority < 7; ++priority) { + Sprite *sprites = spritetable(); + for (size_t j = 0; j < 16; ++j) { + const Sprite &sprite = sprites[j]; + if (sprite.updateCallback() == 0x0ffff) + continue; + if (priority != sprite.priority) + continue; + if (sprite.hidden == 1) + continue; + printasprite(&sprite); + } + } +} + +void DreamGenContext::printasprite(const Sprite *sprite) { + uint16 x, y; + if (sprite->y >= 220) { + y = data.word(kMapady) - (256 - sprite->y); + } else { + y = sprite->y + data.word(kMapady); + } + + if (sprite->x >= 220) { + x = data.word(kMapadx) - (256 - sprite->x); + } else { + x = sprite->x + data.word(kMapadx); + } + + uint8 c; + if (sprite->b29 != 0) + c = 8; + else + c = 0; + uint8 width, height; + showframe((const Frame *)segRef(sprite->frameData()).ptr(0, 0), x, y, sprite->b15, c, &width, &height); +} + +void DreamGenContext::clearsprites() { + memset(spritetable(), 0xff, sizeof(Sprite) * 16); +} + +Sprite *DreamGenContext::makesprite(uint8 x, uint8 y, uint16 updateCallback, uint16 frameData, uint16 somethingInDi) { + Sprite *sprite = spritetable(); + while (sprite->b15 != 0xff) { // NB: No boundchecking in the original code either + ++sprite; + } + + sprite->setUpdateCallback(updateCallback); + sprite->x = x; + sprite->y = y; + sprite->setFrameData(frameData); + WRITE_LE_UINT16(&sprite->w8, somethingInDi); + sprite->w2 = 0xffff; + sprite->b15 = 0; + sprite->delay = 0; + return sprite; +} + +void DreamGenContext::makesprite() { // NB: returns new sprite in es:bx + Sprite *sprite = makesprite(si & 0xff, si >> 8, cx, dx, di); + + // Recover es:bx from sprite + es = data.word(kBuffers); + bx = kSpritetable; + Sprite *sprites = (Sprite *)es.ptr(bx, sizeof(Sprite) * 16); + bx += sizeof(Sprite) * (sprite - sprites); + // +} + +void DreamGenContext::spriteupdate() { + Sprite *sprites = spritetable(); + sprites[0].hidden = data.byte(kRyanon); + + Sprite *sprite = sprites; + for (size_t i=0; i < 16; ++i) { + uint16 updateCallback = sprite->updateCallback(); + if (updateCallback != 0xffff) { + sprite->w24 = sprite->w2; + if (updateCallback == addr_mainman) // NB : Let's consider the callback as an enum while more code is not ported to C++ + mainman(sprite); + else { + assert(updateCallback == addr_backobject); + backobject(sprite); + } + } + + if (data.byte(kNowinnewroom) == 1) + break; + ++sprite; + } +} + +void DreamGenContext::initman() { + Sprite *sprite = makesprite(data.byte(kRyanx), data.byte(kRyany), addr_mainman, data.word(kMainsprites), 0); + sprite->priority = 4; + sprite->b22 = 0; + sprite->b29 = 0; +} + +void DreamGenContext::mainman() { + assert(false); +} + +void DreamGenContext::mainman(Sprite *sprite) { + push(es); + push(ds); + + // Recover es:bx from sprite + es = data.word(kBuffers); + bx = kSpritetable; + Sprite *sprites = (Sprite *)es.ptr(bx, sizeof(Sprite) * 16); + bx += 32 * (sprite - sprites); + // + + if (data.byte(kResetmanxy) == 1) { + data.byte(kResetmanxy) = 0; + sprite->x = data.byte(kRyanx); + sprite->y = data.byte(kRyany); + sprite->b29 = 0; + } + --sprite->b22; + if (sprite->b22 != 0xff) { + ds = pop(); + es = pop(); + return; + } + sprite->b22 = 0; + if (data.byte(kTurntoface) != data.byte(kFacing)) { + aboutturn(sprite); + } else { + if ((data.byte(kTurndirection) != 0) && (data.byte(kLinepointer) == 254)) { + data.byte(kReasseschanges) = 1; + if (data.byte(kFacing) == data.byte(kLeavedirection)) + checkforexit(); + } + data.byte(kTurndirection) = 0; + if (data.byte(kLinepointer) == 254) { + sprite->b29 = 0; + } else { + ++sprite->b29; + if (sprite->b29 == 11) + sprite->b29 = 1; + walking(sprite); + if (data.byte(kLinepointer) != 254) { + if ((data.byte(kFacing) & 1) == 0) + walking(sprite); + else if ((sprite->b29 != 2) && (sprite->b29 != 7)) + walking(sprite); + } + if (data.byte(kLinepointer) == 254) { + if (data.byte(kTurntoface) == data.byte(kFacing)) { + data.byte(kReasseschanges) = 1; + if (data.byte(kFacing) == data.byte(kLeavedirection)) + checkforexit(); + } + } + } + } + static const uint8 facelist[] = { 0,60,33,71,11,82,22,93 }; + sprite->b15 = sprite->b29 + facelist[data.byte(kFacing)]; + data.byte(kRyanx) = sprite->x; + data.byte(kRyany) = sprite->y; + + ds = pop(); + es = pop(); +} + +void DreamGenContext::walking(Sprite *sprite) { + uint8 comp; + if (data.byte(kLinedirection) != 0) { + --data.byte(kLinepointer); + comp = 200; + } else { + ++data.byte(kLinepointer); + comp = data.byte(kLinelength); + } + if (data.byte(kLinepointer) < comp) { + sprite->x = data.byte(kLinedata + data.byte(kLinepointer) * 2 + 0); + sprite->y = data.byte(kLinedata + data.byte(kLinepointer) * 2 + 1); + return; + } + + data.byte(kLinepointer) = 254; + data.byte(kManspath) = data.byte(kDestination); + if (data.byte(kDestination) == data.byte(kFinaldest)) { + facerightway(); + return; + } + data.byte(kDestination) = data.byte(kFinaldest); + push(es); + push(bx); + autosetwalk(); + bx = pop(); + es = pop(); +} + +void DreamGenContext::aboutturn(Sprite *sprite) { + bool incdir = true; + + if (data.byte(kTurndirection) == 1) + incdir = true; + else if ((int8)data.byte(kTurndirection) == -1) + incdir = false; + else { + if (data.byte(kFacing) < data.byte(kTurntoface)) { + uint8 delta = data.byte(kTurntoface) - data.byte(kFacing); + if (delta >= 4) + incdir = false; + else + incdir = true; + } else { + uint8 delta = data.byte(kFacing) - data.byte(kTurntoface); + if (delta >= 4) + incdir = true; + else + incdir = false; + } + } + + if (incdir) { + data.byte(kTurndirection) = 1; + data.byte(kFacing) = (data.byte(kFacing) + 1) & 7; + sprite->b29 = 0; + } else { + data.byte(kTurndirection) = -1; + data.byte(kFacing) = (data.byte(kFacing) - 1) & 7; + sprite->b29 = 0; + } +} + +void DreamGenContext::backobject() { + assert(false); +} + +void DreamGenContext::backobject(Sprite *sprite) { + ObjData *objData = (ObjData *)segRef(data.word(kSetdat)).ptr(sprite->objData(), 0); + + if (sprite->delay != 0) { + --sprite->delay; + return; + } + + sprite->delay = objData->delay; + if (objData->type == 6) + widedoor(sprite, objData); + else if (objData->type == 5) + random(sprite, objData); + else if (objData->type == 4) + lockeddoorway(sprite, objData); + else if (objData->type == 3) + liftsprite(sprite, objData); + else if (objData->type == 2) + doorway(sprite, objData); + else if (objData->type == 1) + constant(sprite, objData); + else + steady(sprite, objData); +} + +void DreamGenContext::constant(Sprite *sprite, ObjData *objData) { + ++sprite->frame; + if (objData->b18[sprite->frame] == 255) { + sprite->frame = 0; + } + uint8 b18 = objData->b18[sprite->frame]; + objData->b17 = b18; + sprite->b15 = b18; +} + +void DreamGenContext::random(Sprite *sprite, ObjData *objData) { + randomnum1(); + uint16 r = ax; + sprite->b15 = objData->b18[r&7]; +} + +void DreamGenContext::doorway(Sprite *sprite, ObjData *objData) { + data.byte(kDoorcheck1) = -24; + data.byte(kDoorcheck2) = 10; + data.byte(kDoorcheck3) = -30; + data.byte(kDoorcheck4) = 10; + dodoor(sprite, objData); +} + +void DreamGenContext::widedoor(Sprite *sprite, ObjData *objData) { + data.byte(kDoorcheck1) = -24; + data.byte(kDoorcheck2) = 24; + data.byte(kDoorcheck3) = -30; + data.byte(kDoorcheck4) = 24; + dodoor(sprite, objData); +} + +void DreamGenContext::dodoor() { + Sprite *sprite = (Sprite *)es.ptr(bx, sizeof(Sprite)); + ObjData *objData = (ObjData *)ds.ptr(di, 0); + dodoor(sprite, objData); +} + +void DreamGenContext::dodoor(Sprite *sprite, ObjData *objData) { + uint8 ryanx = data.byte(kRyanx); + uint8 ryany = data.byte(kRyany); + if (ryanx < sprite->x) { + if (ryanx < sprite->x + (int8)data.byte(kDoorcheck1)) + goto shutdoor; + } else { + if (ryanx >= sprite->x + data.byte(kDoorcheck2)) + goto shutdoor; + } + if (ryany < sprite->y) { + if (ryany < sprite->y + (int8)data.byte(kDoorcheck3)) + goto shutdoor; + } else { + if (ryany >= sprite->y + data.byte(kDoorcheck4)) + goto shutdoor; + } +//opendoor: + if ((data.byte(kThroughdoor) == 1) && (sprite->frame == 0)) + sprite->frame = 6; + + ++sprite->frame; + if (sprite->frame == 1) { //doorsound2 + if (data.byte(kReallocation) == 5) //hoteldoor2 + al = 13; + else + al = 0; + playchannel1(); + } + if (objData->b18[sprite->frame] == 255) { + --sprite->frame; + } + sprite->b15 = objData->b17 = objData->b18[sprite->frame]; + data.byte(kThroughdoor) = 1; + return; +shutdoor: + if (sprite->frame == 5) { //doorsound1; + if (data.byte(kReallocation) == 5) //hoteldoor1 + al = 13; + else + al = 1; + playchannel1(); + } + if (sprite->frame != 0) { + --sprite->frame; + } + sprite->b15 = objData->b17 = objData->b18[sprite->frame]; + if (sprite->frame == 5) //nearly + data.byte(kThroughdoor) = 0; +} + +void DreamGenContext::steady(Sprite *sprite, ObjData *objData) { + uint8 b18 = objData->b18[0]; + objData->b17 = b18; + sprite->b15 = b18; +} + +void DreamGenContext::lockeddoorway(Sprite *sprite, ObjData *objData) { + if (data.byte(kRyanx) < sprite->x) { + if (sprite->x - data.byte(kRyanx) > 24) + goto shutdoor2; + } else { + if (data.byte(kRyanx) - sprite->x >= 10) + goto shutdoor2; + } + + if (data.byte(kRyany) < sprite->y) { + if (sprite->y - data.byte(kRyany) > 30) + goto shutdoor2; + } else { + if (data.byte(kRyany) - sprite->y >= 12) + goto shutdoor2; + } + + if (data.byte(kThroughdoor) != 1) { + if (data.byte(kLockstatus) == 1) + goto shutdoor2; + } + + if (sprite->frame == 1) { + al = 0; + playchannel1(); + } + + if (sprite->frame == 6) { + turnpathonCPP(data.byte(kDoorpath)); + } + + if ((data.byte(kThroughdoor) == 1) && (sprite->frame == 0)) { + sprite->frame = 6; + } + + ++sprite->frame; + if (objData->b18[sprite->frame] == 255) { + --sprite->frame; + } + + sprite->b15 = objData->b17 = objData->b18[sprite->frame]; + if (sprite->frame == 5) + data.byte(kThroughdoor) = 1; + return; + +shutdoor2: + if (sprite->frame == 5) { + al = 1; + playchannel1(); + } + + if (sprite->frame != 0) { + --sprite->frame; + } + + data.byte(kThroughdoor) = 0; + sprite->b15 = objData->b17 = objData->b18[sprite->frame]; + + if (sprite->frame == 0) { + turnpathoffCPP(data.byte(kDoorpath)); + data.byte(kLockstatus) = 1; + } +} + +void DreamGenContext::liftsprite(Sprite *sprite, ObjData *objData) { + uint8 liftFlag = data.byte(kLiftflag); + if (liftFlag == 0) { //liftclosed + turnpathoffCPP(data.byte(kLiftpath)); + + if (data.byte(kCounttoopen) != 0) { + _dec(data.byte(kCounttoopen)); + if (data.byte(kCounttoopen) == 0) + data.byte(kLiftflag) = 3; + } + sprite->frame = 0; + sprite->b15 = objData->b17 = objData->b18[sprite->frame]; + } + else if (liftFlag == 1) { //liftopen + turnpathonCPP(data.byte(kLiftpath)); + + if (data.byte(kCounttoclose) != 0) { + _dec(data.byte(kCounttoclose)); + if (data.byte(kCounttoclose) == 0) + data.byte(kLiftflag) = 2; + } + sprite->frame = 12; + sprite->b15 = objData->b17 = objData->b18[sprite->frame]; + } + else if (liftFlag == 3) { //openlift + if (sprite->frame == 12) { + data.byte(kLiftflag) = 1; + return; + } + ++sprite->frame; + if (sprite->frame == 1) { + al = 2; + liftnoise(); + } + sprite->b15 = objData->b17 = objData->b18[sprite->frame]; + } else { //closeLift + assert(liftFlag == 2); + if (sprite->frame == 0) { + data.byte(kLiftflag) = 0; + return; + } + --sprite->frame; + if (sprite->frame == 11) { + al = 3; + liftnoise(); + } + sprite->b15 = objData->b17 = objData->b18[sprite->frame]; + } +} + +void DreamGenContext::facerightway() { + uint8 *paths = getroomspathsCPP(); + uint8 dir = paths[8 * data.byte(kManspath) + 7]; + data.byte(kTurntoface) = dir; + data.byte(kLeavedirection) = dir; +} + +void DreamGenContext::findsource() { + uint16 currentFrame = data.word(kCurrentframe); + if (currentFrame < 160) { + ds = data.word(kReel1); + data.word(kTakeoff) = 0; + } else if (currentFrame < 320) { + ds = data.word(kReel2); + data.word(kTakeoff) = 160; + } else { + ds = data.word(kReel3); + data.word(kTakeoff) = 320; + } +} + +Frame *DreamGenContext::findsourceCPP() { + push(ds); + findsource(); + Frame *result = (Frame *)ds.ptr(0, 0); + ds = pop(); + return result; +} + +Reel *DreamGenContext::getreelstart() { + Reel *reel = (Reel *)segRef(data.word(kReels)).ptr(kReellist + data.word(kReelpointer) * sizeof(Reel) * 8, sizeof(Reel)); + return reel; +} + +void DreamGenContext::showreelframe() { + Reel *reel = (Reel *)es.ptr(si, sizeof(Reel)); + showreelframe(reel); +} + +void DreamGenContext::showreelframe(Reel *reel) { + uint16 x = reel->x + data.word(kMapadx); + uint16 y = reel->y + data.word(kMapady); + data.word(kCurrentframe) = reel->frame(); + Frame *source = findsourceCPP(); + uint16 frame = data.word(kCurrentframe) - data.word(kTakeoff); + uint8 width, height; + showframe(source, x, y, frame, 8, &width, &height); +} + +void DreamGenContext::showgamereel() { + uint16 reelpointer = es.word(bx+3); + if (reelpointer >= 512) + return; + data.word(kReelpointer) = reelpointer; + push(es); + push(bx); + plotreel(); + bx = pop(); + es = pop(); + es.word(bx+3) = data.word(kReelpointer); +} + +const Frame *DreamGenContext::getreelframeax(uint16 frame) { + data.word(kCurrentframe) = frame; + uint16 offset = data.word(kCurrentframe) - data.word(kTakeoff); + return findsourceCPP() + offset; +} + +void DreamGenContext::showrain() { + ds = data.word(kMainsprites); + si = 6*58; + ax = ds.word(si+2); + si = ax + 2080; + Rain *rain = (Rain *)segRef(data.word(kBuffers)).ptr(kRainlist, 0); + if (rain->x == 255) + return; + while (true) { + if (rain->x == 255) { + if (data.word(kCh1blockstocopy) != 0) + return; + if ((data.byte(kReallocation) == 2) && (data.byte(kBeenmugged) != 1)) + return; + if (data.byte(kReallocation) == 55) + return; + randomnum1(); + if (al >= 1) + return; + if (data.byte(kCh0playing) != 6) + al = 4; + else + al = 7; + playchannel1(); + return; + } + uint16 y = rain->y + data.word(kMapady) + data.word(kMapystart); + uint16 x = rain->x + data.word(kMapadx) + data.word(kMapxstart); + uint16 size = rain->size; + ax = ((uint16)(rain->w3() - rain->b5)) & 511; + rain->setW3(ax); + ++rain; + const uint8 *src = ds.ptr(si, 0) + ax; + uint8 *dst = workspace() + y * 320 + x; + for(uint16 i = 0; i < size; ++i) { + uint8 v = src[i]; + if (v != 0) + *dst = v; + dst += 320-1; + } + } +} + +void DreamGenContext::updatepeople() { + data.word(kListpos) = kPeoplelist; + memset(segRef(data.word(kBuffers)).ptr(kPeoplelist, 12 * sizeof(People)), 0xff, 12 * sizeof(People)); + ++data.word(kMaintimer); + es = cs; + bx = kReelroutines; + const ReelRoutine *reelRoutine = (const ReelRoutine *)cs.ptr(bx, 0); + const uint16 *callbacks = (const uint16 *)cs.ptr(kReelcalls, 0); + while (true) { + uint8 realLocation = reelRoutine->reallocation; + if (realLocation == 255) + return; + if ((realLocation == data.byte(kReallocation)) && + (reelRoutine->mapX == data.byte(kMapx)) && + (reelRoutine->mapY == data.byte(kMapy))) { + uint16 callback = READ_LE_UINT16(callbacks); + //dw gamer,sparkydrip,eden,edeninbath,sparky,smokebloke + if (callback == addr_gamer) + gamer(); + else if (callback == addr_sparkydrip) + sparkydrip(); + else if (callback == addr_eden) + eden(); + else if (callback == addr_edeninbath) + edeninbath(); + else if (callback == addr_sparky) + sparky(); + else if (callback == addr_smokebloke) + smokebloke(); + //dw manasleep,drunk,receptionist,malefan,femalefan + else if (callback == addr_manasleep) + manasleep(); + else if (callback == addr_drunk) + drunk(); + else if (callback == addr_receptionist) + receptionist(); + else if (callback == addr_malefan) + malefan(); + else if (callback == addr_femalefan) + femalefan(); + //dw louis,louischair,soldier1,bossman,interviewer + else if (callback == addr_louis) + louis(); + else if (callback == addr_louischair) + louischair(); + else if (callback == addr_soldier1) + soldier1(); + else if (callback == addr_bossman) + bossman(); + else if (callback == addr_interviewer) + interviewer(); + //dw heavy,manasleep2,mansatstill,drinker,bartender + else if (callback == addr_heavy) + heavy(); + else if (callback == addr_manasleep2) + manasleep2(); + else if (callback == addr_mansatstill) + mansatstill(); + else if (callback == addr_drinker) + drinker(); + else if (callback == addr_bartender) + bartender(); + //dw othersmoker,tattooman,attendant,keeper,candles1 + else if (callback == addr_othersmoker) + othersmoker(); + else if (callback == addr_tattooman) + tattooman(); + else if (callback == addr_attendant) + attendant(); + else if (callback == addr_keeper) + keeper(); + else if (callback == addr_candles1) + candles1(); + //dw smallcandle,security,copper,poolguard,rockstar + else if (callback == addr_smallcandle) + smallcandle(); + else if (callback == addr_security) + security(); + else if (callback == addr_copper) + copper(); + else if (callback == addr_poolguard) + poolguard(); + else if (callback == addr_rockstar) + rockstar(); + //dw businessman,train,aide,mugger,helicopter + else if (callback == addr_businessman) + businessman(); + else if (callback == addr_train) + train(); + else if (callback == addr_aide) + aide(); + else if (callback == addr_mugger) + mugger(); + else if (callback == addr_helicopter) + helicopter(); + //dw intromagic1,intromusic,intromagic2,candles2,gates + else if (callback == addr_intromagic1) + intromagic1(); + else if (callback == addr_intromusic) + intromusic(); + else if (callback == addr_intromagic2) + intromagic2(); + else if (callback == addr_candles2) + candles2(); + else if (callback == addr_gates) + gates(); + //dw intromagic3,intromonks1,candles,intromonks2 + else if (callback == addr_intromagic3) + intromagic3(); + else if (callback == addr_intromonks1) + intromonks1(); + else if (callback == addr_candles) + candles(); + else if (callback == addr_intromonks2) + intromonks2(); + //dw handclap,monkandryan,endgameseq,priest,madman + else if (callback == addr_handclap) + handclap(); + else if (callback == addr_monkandryan) + monkandryan(); + else if (callback == addr_endgameseq) + endgameseq(); + else if (callback == addr_priest) + priest(); + else if (callback == addr_madman) + madman(); + //dw madmanstelly,alleybarksound,foghornsound + else if (callback == addr_madmanstelly) + madmanstelly(); + else if (callback == addr_alleybarksound) + alleybarksound(); + else if (callback == addr_foghornsound) + foghornsound(); + //dw carparkdrip,carparkdrip,carparkdrip,carparkdrip + else if (callback == addr_carparkdrip) + carparkdrip(); + else + assert(false); // Oops I forgot something in the dispatch table + } + bx += 8; + ++reelRoutine; + ++callbacks; + } +} + +void DreamGenContext::madmantext() { + if (isCD()) { + if (data.byte(kSpeechcount) >= 63) + return; + if (data.byte(kCh1playing) != 255) + return; + al = data.byte(kSpeechcount); + ++data.byte(kSpeechcount); + } else { + if (data.byte(kCombatcount) >= 61) + return; + al = data.byte(kCombatcount); + _and(al, 3); + if (!flags.z()) + return; + al = data.byte(kCombatcount) / 4; + } + setuptimedtemp(47 + al, 82, 72, 80, 90, 1); +} + +void DreamGenContext::madman() { + data.word(kWatchingtime) = 2; + checkspeed(); + if (flags.z()) { + ax = es.word(bx+3); + if (ax >= 364) { + data.byte(kMandead) = 2; + showgamereel(); + return; + } + if (ax == 10) { + push(es); + push(bx); + push(ax); + dx = kIntrotextname; + loadtemptext(); + ax = pop(); + bx = pop(); + es = pop(); + data.byte(kCombatcount) = -1; + data.byte(kSpeechcount) = 0; + } + ++ax; + if (ax == 294) { + if (data.byte(kWongame) == 1) + return; + data.byte(kWongame) = 1; + push(es); + push(bx); + getridoftemptext(); + bx = pop(); + es = pop(); + return; + } + if (ax == 66) { + ++data.byte(kCombatcount); + push(es); + push(bx); + madmantext(); + bx = pop(); + es = pop(); + ax = 53; + if (data.byte(kCombatcount) >= (isCD() ? 64 : 62)) { + if (data.byte(kCombatcount) == (isCD() ? 70 : 68)) + ax = 310; + else { + if (data.byte(kLastweapon) == 8) { + data.byte(kCombatcount) = isCD() ? 72 : 70; + data.byte(kLastweapon) = -1; + data.byte(kMadmanflag) = 1; + ax = 67; + } + } + } + } + es.word(bx+3) = ax; + } + showgamereel(); + es.byte(bx+1) = data.byte(kMapx); + madmode(); +} + +void DreamGenContext::madmode() { + data.word(kWatchingtime) = 2; + data.byte(kPointermode) = 0; + if (data.byte(kCombatcount) < (isCD() ? 65 : 63)) + return; + if (data.byte(kCombatcount) >= (isCD() ? 70 : 68)) + return; + data.byte(kPointermode) = 2; +} + +void DreamGenContext::movemap(uint8 param) { + switch (param) { + case 32: + data.byte(kMapy) -= 20; + break; + case 16: + data.byte(kMapy) -= 10; + break; + case 8: + data.byte(kMapy) += 10; + break; + case 2: + data.byte(kMapx) += 11; + break; + default: + data.byte(kMapx) -= 11; + break; + } + data.byte(kNowinnewroom) = 1; +} + +} /*namespace dreamgen */ + diff --git a/engines/dreamweb/structs.h b/engines/dreamweb/structs.h index e274375cf4..685e4cffe1 100644 --- a/engines/dreamweb/structs.h +++ b/engines/dreamweb/structs.h @@ -20,21 +20,30 @@ * */ +#include "common/endian.h" + struct Sprite { - uint16 updateCallback; + uint16 _updateCallback; + uint16 updateCallback() const { return READ_LE_UINT16(&_updateCallback); } + void setUpdateCallback(uint16 v) { WRITE_LE_UINT16(&_updateCallback, v); } uint16 w2; uint16 w4; - uint16 w6; + uint16 _frameData; + uint16 frameData() const { return READ_LE_UINT16(&_frameData); } + void setFrameData(uint16 v) { WRITE_LE_UINT16(&_frameData, v); } uint16 w8; uint8 x; uint8 y; uint16 w12; uint8 b14; uint8 b15; - uint16 w16; + uint8 b16; + uint8 b17; uint8 delay; uint8 frame; - uint16 obj_data; + uint16 _objData; + uint16 objData() const { return READ_LE_UINT16(&_objData); } + void setObjData(uint16 v) { WRITE_LE_UINT16(&_objData, v); } uint8 b22; uint8 priority; uint16 w24; @@ -66,3 +75,85 @@ struct ObjData { uint8 b17; uint8 b18[256]; // NB: Don't know the size yet }; + +struct Frame { + uint8 width; + uint8 height; + uint16 _ptr; + uint16 ptr() const { return READ_LE_UINT16(&_ptr); } + void setPtr(uint16 v) { WRITE_LE_UINT16(&_ptr, v); } + uint8 x; + uint8 y; +}; + +struct Reel { + uint8 frame_lo; + uint8 frame_hi; + uint16 frame() const { return READ_LE_UINT16(&frame_lo); } + void setFrame(uint16 v) { WRITE_LE_UINT16(&frame_lo, v); } + uint8 x; + uint8 y; + uint8 b4; +}; + +struct ReelRoutine { + uint8 reallocation; + uint8 mapX; + uint8 mapY; + uint8 b3; + uint8 b4; + uint8 b5; + uint8 b6; + uint8 b7; +}; + +struct People { + uint8 b0; + uint8 b1; + uint16 w0() const { return READ_LE_UINT16(&b0); } + void setW0(uint16 v) { WRITE_LE_UINT16(&b0, v); } + uint8 b2; + uint8 b3; + uint16 w2() const { return READ_LE_UINT16(&b2); } + void setW2(uint16 v) { WRITE_LE_UINT16(&b2, v); } + uint8 b4; + +}; + +struct Room { + uint8 name[10]; + uint8 b10; + uint8 b11; + uint8 b12; + uint8 roomsSample; + uint8 b14; + uint8 mapX; + uint8 mapY; + uint8 b17; + uint8 b18; + uint8 b19; + uint8 liftFlag; + uint8 b21; + uint8 b22; + uint8 countToOpen; + uint8 liftPath; + uint8 doorPath; + uint8 b26; + uint8 b27; + uint8 b28; + uint8 b29; + uint8 b30; + uint8 b31; +}; + +struct Rain { + uint8 x; + uint8 y; + uint8 size; + uint8 w3_lo; + uint8 w3_hi; + uint16 w3() const { return READ_LE_UINT16(&w3_lo); } + void setW3(uint16 v) { WRITE_LE_UINT16(&w3_lo, v); } + uint8 b5; +}; + diff --git a/engines/dreamweb/stubs.cpp b/engines/dreamweb/stubs.cpp index 5ba3796e30..c978d8d475 100644 --- a/engines/dreamweb/stubs.cpp +++ b/engines/dreamweb/stubs.cpp @@ -174,7 +174,7 @@ void DreamGenContext::dreamweb() { } } -Common::String getFilename(Context &context) { +static Common::String getFilename(Context &context) { uint16 name_ptr = context.dx; Common::String name; uint8 c; @@ -183,126 +183,6 @@ Common::String getFilename(Context &context) { return name; } -void DreamGenContext::multiget() { - multiget(di, bx, cl, ch); -} - -void DreamGenContext::multiget(uint16 x, uint16 y, uint8 w, uint8 h) { - unsigned src = x + y * kScreenwidth; - unsigned dst = (uint16)si; - es = ds; - ds = data.word(kWorkspace); - if (y + h > 200) - h = 200 - y; - if (x + w > 320) - w = 320 - x; - //debug(1, "multiget %u,%u %ux%u -> segment: %04x->%04x", x, y, w, h, (uint16)ds, (uint16)es); - for(unsigned l = 0; l < h; ++l) { - uint8 *src_p = ds.ptr(src + kScreenwidth * l, w); - uint8 *dst_p = es.ptr(dst + w * l, w); - memcpy(dst_p, src_p, w); - } - si += w * h; - di = src + kScreenwidth * h; - cx = 0; -} - -void DreamGenContext::multiput() { - multiput(di, bx, cl, ch); -} - -void DreamGenContext::multiput(uint16 x, uint16 y, uint8 w, uint8 h) { - unsigned src = (uint16)si; - unsigned dst = x + y * kScreenwidth; - es = data.word(kWorkspace); - if (y + h > 200) - h = 200 - y; - if (x + w > 320) - w = 320 - x; - //debug(1, "multiput %ux%u -> segment: %04x->%04x", w, h, (uint16)ds, (uint16)es); - for(unsigned l = 0; l < h; ++l) { - uint8 *src_p = ds.ptr(src + w * l, w); - uint8 *dst_p = es.ptr(dst + kScreenwidth * l, w); - memcpy(dst_p, src_p, w); - } - si += w * h; - di = dst + kScreenwidth * h; - cx = 0; -} - -void DreamGenContext::multidump(uint16 x, uint16 y, uint8 width, uint8 height) { - ds = data.word(kWorkspace); - unsigned offset = x + y * kScreenwidth; - //debug(1, "multidump %ux%u(segment: %04x) -> %d,%d(address: %d)", w, h, (uint16)ds, x, y, offset); - engine->blit(ds.ptr(offset, width * height), kScreenwidth, x, y, width, height); -} - -void DreamGenContext::multidump() { - multidump(di, bx, cl, ch); - unsigned offset = di + bx * kScreenwidth; - si = di = offset + ch * kScreenwidth; - cx = 0; -} - -void DreamGenContext::worktoscreen() { - ds = data.word(kWorkspace); - uint size = 320 * 200; - engine->blit(ds.ptr(0, size), 320, 0, 0, 320, 200); - di = si = size; - cx = 0; -} - -void DreamGenContext::printundermon() { - engine->printUnderMonitor(); -} - -void DreamGenContext::cls() { - engine->cls(); -} - -void DreamGenContext::frameoutnm(uint8 *dst, const uint8 *src, uint16 pitch, uint16 width, uint16 height, uint16 x, uint16 y) { - dst += pitch * y + x; - - for (uint16 j = 0; j < height; ++j) { - memcpy(dst, src, width); - dst += pitch; - src += width; - } -} - -void DreamGenContext::frameoutbh(uint8 *dst, const uint8 *src, uint16 pitch, uint16 width, uint16 height, uint16 x, uint16 y) { - uint16 stride = pitch - width; - dst += y * pitch + x; - - for (uint16 i = 0; i < height; ++i) { - for (uint16 j = 0; j < width; ++j) { - if (*dst == 0xff) { - *dst = *src; - } - ++src; - ++dst; - } - dst += stride; - } -} - -void DreamGenContext::frameoutfx(uint8 *dst, const uint8 *src, uint16 pitch, uint16 width, uint16 height, uint16 x, uint16 y) { - uint16 stride = pitch - width; - dst += y * pitch + x; - dst -= width; - - for (uint16 j = 0; j < height; ++j) { - for (uint16 i = 0; i < width; ++i) { - uint8 pixel = src[width - i - 1]; - if (pixel) - *dst = pixel; - ++dst; - } - src += width; - dst += stride; - } -} - void DreamGenContext::seecommandtail() { data.word(kSoundbaseadd) = 0x220; data.byte(kSoundint) = 5; @@ -394,84 +274,6 @@ void DreamGenContext::setmouse() { data.word(kOldpointerx) = 0xffff; } -void DreamGenContext::printboth() { - uint16 x = di; - printboth(es, ds, &x, bx, al); - di = x; -} - -void DreamGenContext::printboth(uint16 dst, uint16 src, uint16 *x, uint16 y, uint8 c) { - uint16 newX = *x; - uint8 width, height; - printchar(dst, src, &newX, y, c, &width, &height); - multidump(*x, y, width, height); - *x = newX; -} - -uint8 DreamGenContext::getnextword(const uint8 *string, uint8 *totalWidth, uint8 *charCount) { - *totalWidth = 0; - *charCount = 0; - while(true) { - uint8 firstChar = *string; - ++string; - ++*charCount; - if ((firstChar == ':') || (firstChar == 0)) { //endall - *totalWidth += 6; - return 1; - } - if (firstChar == 32) { //endword - *totalWidth += 6; - return 0; - } - firstChar = engine->modifyChar(firstChar); - if (firstChar != 255) { - uint8 secondChar = *string; - uint8 width = ds.byte(6*(firstChar - 32 + data.word(kCharshift))); - width = kernchars(firstChar, secondChar, width); - *totalWidth += width; - } - } -} - -void DreamGenContext::getnextword() { - uint8 totalWidth, charCount; - al = getnextword(es.ptr(di, 0), &totalWidth, &charCount); - bl = totalWidth; - bh = charCount; - di += charCount; -} - -void DreamGenContext::printchar() { - uint16 x = di; - uint8 width, height; - printchar(es, ds, &x, bx, al, &width, &height); - di = x; - cl = width; - ch = height; -} - -void DreamGenContext::printchar(uint16 dst, uint16 src, uint16* x, uint16 y, uint8 c, uint8 *width, uint8 *height) { - if (c == 255) - return; - push(si); - push(di); - push(ax); - if (data.byte(kForeignrelease) != 0) - y -= 3; - showframe(dst, src, *x, y, c - 32 + data.word(kCharshift), 0, width, height); - ax = pop(); - di = pop(); - si = pop(); - _cmp(data.byte(kKerning), 0); - if (flags.z()) - *width = kernchars(c, ah, *width); - (*x) += *width; -} - -void DreamGenContext::printslow() { - al = printslow(di, bx, dl, (bool)(dl & 1)); -} - void DreamGenContext::dumptextline() { if (data.byte(kNewtextline) != 1) return; @@ -483,100 +285,13 @@ void DreamGenContext::dumptextline() { multidump(x, y, 228, 13); } -uint8 DreamGenContext::printslow(uint16 x, uint16 y, uint8 maxWidth, bool centered) { - data.byte(kPointerframe) = 1; - data.byte(kPointermode) = 3; - ds = data.word(kCharset1); - do { - uint16 offset = x; - uint16 charCount = getnumber(si, maxWidth, centered, &offset); - do { - push(si); - push(es); - uint8 c0 = es.byte(si); - push(es); - push(ds); - c0 = engine->modifyChar(c0); - printboth(es, ds, &offset, y, c0); - ds = pop(); - es = pop(); - uint8 c1 = es.byte(si+1); - ++si; - if ((c1 == 0) || (c1 == ':')) { - es = pop(); - si = pop(); - return 0; - } - if (charCount != 1) { - push(ds); - push(es); - c1 = engine->modifyChar(c1); - data.word(kCharshift) = 91; - uint16 offset2 = offset; - printboth(es, ds, &offset2, y, c1); - data.word(kCharshift) = 0; - es = pop(); - ds = pop(); - for (int i=0; i<2; ++i) { - waitframes(); - if (ax == 0) - continue; - if (ax != data.word(kOldbutton)) { - es = pop(); - si = pop(); - return 1; - } - } - } - - es = pop(); - si = pop(); - ++si; - --charCount; - } while (charCount); - y += 10; - } while (true); -} - -void DreamGenContext::printdirect() { - uint16 y = bx; - printdirect(di, &y, dl, (bool)(dl & 1)); - bx = y; -} - -void DreamGenContext::printdirect(uint16 x, uint16 *y, uint8 maxWidth, bool centered) { - data.word(kLastxpos) = x; - ds = data.word(kCurrentset); - while (true) { - uint16 offset = x; - uint8 charCount = getnumber(si, maxWidth, centered, &offset); - uint16 i = offset; - do { - uint8 c = es.byte(si); - ++si; - if ((c == 0) || (c == ':')) { - return; - } - c = engine->modifyChar(c); - ah = es.byte(si); // get next char for kerning - uint8 width, height; - push(es); - printchar(es, ds, &i, *y, c, &width, &height); - es = pop(); - data.word(kLastxpos) = i; - --charCount; - } while(charCount); - *y += data.word(kLinespacing); - } -} - void DreamGenContext::getundertimed() { uint16 y = data.byte(kTimedy); if (data.byte(kForeignrelease)) y -= 3; ds = data.word(kBuffers); si = kUndertimedtext; - multiget(data.byte(kTimedx), y, 240, kUndertimedysize); + multiget(ds.ptr(si, 0), data.byte(kTimedx), y, 240, kUndertimedysize); } void DreamGenContext::putundertimed() { @@ -585,7 +300,7 @@ void DreamGenContext::putundertimed() { y -= 3; ds = data.word(kBuffers); si = kUndertimedtext; - multiput(data.byte(kTimedx), y, 240, kUndertimedysize); + multiput(ds.ptr(si, 0), data.byte(kTimedx), y, 240, kUndertimedysize); } void DreamGenContext::usetimedtext() { @@ -605,67 +320,62 @@ void DreamGenContext::usetimedtext() { es = data.word(kTimedseg); si = data.word(kTimedoffset); + const uint8 *string = es.ptr(si, 0); uint16 y = data.byte(kTimedy); - printdirect(data.byte(kTimedx), &y, 237, true); + printdirect(&string, data.byte(kTimedx), &y, 237, true); data.byte(kNeedtodumptimed) = 1; } -void DreamGenContext::getnumber() { - uint16 offset = di; - cl = getnumber(si, dl, (bool)(dl & 1), &offset); - di = offset; -} - -uint8 DreamGenContext::getnumber(uint16 index, uint16 maxWidth, bool centered, uint16* offset) { - uint8 totalWidth = 0; - uint8 charCount = 0; - while (true) { - uint8 wordTotalWidth, wordCharCount; - uint8 done = getnextword(es.ptr(index, 0), &wordTotalWidth, &wordCharCount); - index += wordCharCount; - - if (done == 1) { //endoftext - ax = totalWidth + wordTotalWidth - 10; - if (ax < maxWidth) { - totalWidth += wordTotalWidth; - charCount += wordCharCount; - } - - if (centered) { - ax = (maxWidth & 0xfe) + 2 + 20 - totalWidth; - ax /= 2; - } else { - ax = 0; - } - *offset += ax; - return charCount; - } - ax = totalWidth + wordTotalWidth - 10; - if (ax >= maxWidth) { //gotoverend - if (centered) { - ax = (maxWidth & 0xfe) - totalWidth + 20; - ax /= 2; - } else { - ax = 0; - } - *offset += ax; - return charCount; +void DreamGenContext::setuptimedtemp() { + setuptimedtemp(al, ah, bl, bh, cx, dx); +} + +void DreamGenContext::setuptimedtemp(uint8 textIndex, uint8 voiceIndex, uint8 x, uint8 y, uint16 countToTimed, uint16 timeCount) { +#if 1 // if cd + if (voiceIndex != 0) { + push(ax); + push(bx); + push(cx); + push(dx); + dl = 'T'; + dh = voiceIndex; + cl = 'T'; + ah = 0; + loadspeech(); + if (data.byte(kSpeechloaded) == 1) { + al = 50+12; + playchannel1(); } - totalWidth += wordTotalWidth; - charCount += wordCharCount; + dx = pop(); + cx = pop(); + bx = pop(); + ax = pop(); + if ((data.byte(kSpeechloaded) == 1) && (data.byte(kSubtitles) != 1)) + return; } -} +#endif -uint8 DreamGenContext::kernchars(uint8 firstChar, uint8 secondChar, uint8 width) { - if ((firstChar == 'a') || (al == 'u')) { - if ((secondChar == 'n') || (secondChar == 't') || (secondChar == 'r') || (secondChar == 'i') || (secondChar == 'l')) - return width-1; - } - return width; -} + if (data.word(kTimecount) != 0) + return; + data.byte(kTimedy) = y; + data.byte(kTimedx) = x; + data.word(kCounttotimed) = countToTimed; + data.word(kTimecount) = timeCount + countToTimed; + data.word(kTimedseg) = data.word(kTextfile1); + data.word(kTimedoffset) = kTextstart + segRef(data.word(kTextfile1)).word(textIndex * 2); + const uint8 *string = segRef(data.word(kTextfile1)).ptr(data.word(kTimedoffset), 0); + debug(1, "setuptimedtemp: (%d, %d) => '%s'", textIndex, voiceIndex, string); +} + +void DreamGenContext::dumptimedtext() { + if (data.byte(kNeedtodumptimed) != 1) + return; + uint8 y = data.byte(kTimedy); + if (data.byte(kForeignrelease) != 0) + y -= 3; -void DreamGenContext::kernchars() { - cl = kernchars(al, ah, cl); + multidump(data.byte(kTimedx), y, 240, kUndertimedysize); + data.byte(kNeedtodumptimed) = 0; } void DreamGenContext::gettime() { @@ -681,12 +391,17 @@ void DreamGenContext::gettime() { } void DreamGenContext::allocatemem() { - uint size = (bx + 2) * 16; + ax = allocatemem(bx); +} + +uint16 DreamGenContext::allocatemem(uint16 paragraphs) { + uint size = (paragraphs + 2) * 16; debug(1, "allocate mem, %u bytes", size); flags._c = false; SegmentRef seg = allocateSegment(size); - ax = (uint16)seg; - debug(1, "\tsegment address -> %04x", (uint16)ax); + uint16 result = (uint16)seg; + debug(1, "\tsegment address -> %04x", result); + return result; } void DreamGenContext::deallocatemem() { @@ -880,349 +595,96 @@ void DreamGenContext::fadedos() { engine->fadeDos(); } -void DreamGenContext::doshake() { - uint8 &counter = data.byte(kShakecounter); - _cmp(counter, 48); - if (flags.z()) - return; - - _add(counter, 1); - static const int shakeTable[] = { - 0, -2, 3, -2, 0, 2, 4, -1, - 1, -3, 3, 2, 0, -2, 3, -2, - 0, 2, 4, -1, 1, -3, 3, 2, - 0, -2, 3, -2, 0, 2, 4, -1, - - 1, -3, 3, 2, 0, -2, 3, -2, - 0, 2, 4, -1, 1, -3, 3, 2, - 0, -2, 3, -2, 0, 2, 4, -1, - 1, -3, 3, 2, 0, -2, 3, -2, - - 0, 2, 4, -1, 1, -3, 3, 2, - 0, -2, 3, -2, 0, 2, 4, -1, - 1, -3, 3, 2, 0, -2, 3, -2, - 0, 2, 4, -1, 1, -3, 3, 2, - - 0, -2, 3, -2, 0, 2, 4, -1, - 1, -3, 3, 0, - }; - int offset = shakeTable[counter]; - engine->setShakePos(offset >= 0 ? offset : -offset); -} - -void DreamGenContext::vsync() { - push(ax); - push(bx); - push(cx); - push(dx); - push(si); - push(di); - push(es); - push(ds); - engine->waitForVSync(); - ds = pop(); - es = pop(); - di = pop(); - si = pop(); - dx = pop(); - cx = pop(); - bx = pop(); - ax = pop(); -} - -void DreamGenContext::setmode() { - vsync(); - initGraphics(320, 200, false); -} - -void DreamGenContext::showpcx() { - Common::String name = getFilename(*this); - Common::File pcxFile; - - if (!pcxFile.open(name)) { - warning("showpcx: Could not open '%s'", name.c_str()); - return; - } - - uint8 *maingamepal; - int i, j; - - // Read the 16-color palette into the 'maingamepal' buffer. Note that - // the color components have to be adjusted from 8 to 6 bits. - - pcxFile.seek(16, SEEK_SET); - es = data.word(kBuffers); - maingamepal = es.ptr(kMaingamepal, 768); - pcxFile.read(maingamepal, 48); - - memset(maingamepal + 48, 0xff, 720); - for (i = 0; i < 48; i++) { - maingamepal[i] >>= 2; - } - - // Decode the image data. - - Graphics::Surface *s = g_system->lockScreen(); - Common::Rect rect(640, 480); - - s->fillRect(rect, 0); - pcxFile.seek(128, SEEK_SET); - - for (int y = 0; y < 480; y++) { - byte *dst = (byte *)s->getBasePtr(0, y); - int decoded = 0; - - while (decoded < 320) { - byte col = pcxFile.readByte(); - byte len; - - if ((col & 0xc0) == 0xc0) { - len = col & 0x3f; - col = pcxFile.readByte(); - } else { - len = 1; - } - - // The image uses 16 colors and is stored as four bit - // planes, one for each bit of the color, least - // significant bit plane first. - - for (i = 0; i < len; i++) { - int plane = decoded / 80; - int pos = decoded % 80; - - for (j = 0; j < 8; j++) { - byte bit = (col >> (7 - j)) & 1; - dst[8 * pos + j] |= (bit << plane); - } - - decoded++; - } - } - } - - g_system->unlockScreen(); - pcxFile.close(); -} - -/* -void DreamGenContext::frameoutv() { - uint16 pitch = dx; - uint16 width = cx & 0xff; - uint16 height = cx >> 8; - - const uint8 *src = ds.ptr(si, width * height); - uint8 *dst = es.ptr(0, pitch * height); - - frameoutv(dst, src, pitch, width, height, di, bx); -} -*/ - -void DreamGenContext::frameoutv(uint8 *dst, const uint8 *src, uint16 pitch, uint16 width, uint16 height, uint16 x, uint16 y) { - // NB : These resilience checks were not in the original engine, but did they result in undefined behaviour - // or was something broken during porting to C++? - assert(pitch == 320); - - if(x >= 320) - return; - if(y >= 200) +void DreamGenContext::eraseoldobs() { + if (data.byte(kNewobs) == 0) return; - if(x + width > 320) { - width = 320 - x; - } - if(y + height > 200) { - height = 200 - y; - } - uint16 stride = pitch - width; - dst += pitch * y + x; - - for (uint16 j = 0; j < height; ++j) { - for (uint16 i = 0; i < width; ++i) { - uint8 pixel = *src++; - if (pixel) - *dst = pixel; - ++dst; + Sprite *sprites = spritetable(); + for (size_t i=0; i < 16; ++i) { + Sprite &sprite = sprites[i]; + if (sprite.objData() != 0xffff) { + memset(&sprite, 0xff, sizeof(Sprite)); } - dst += stride; } } -Sprite *DreamGenContext::spritetable() { +void DreamGenContext::turnpathonCPP(uint8 param) { + al = param; push(es); push(bx); - - es = data.word(kBuffers); - bx = kSpritetable; - Sprite *sprite = (Sprite *)es.ptr(bx, 16 * sizeof(Sprite)); - + turnpathon(); bx = pop(); es = pop(); - - return sprite; -} - -void DreamGenContext::showframe(uint16 dst, uint16 src, uint16 x, uint16 y, uint16 frameNumber, uint8 effectsFlag, uint8 *width, uint8 *height) { - // frameNumber takes up 9 bits of ax, and effectsFlag 7. - assert(!(effectsFlag & 1)); - - es = dst; - ds = src; - di = x; - bx = y; - ax = frameNumber | (effectsFlag << 8); - - - si = (ax & 0x1ff) * 6; - if (ds.word(si) == 0) { - *width = 0; - *height = 0; - return; - } - -//notblankshow: - if ((effectsFlag & 128) == 0) { - di += ds.byte(si + 4); - bx += ds.byte(si + 5); - } -//skipoffsets: - cx = ds.word(si + 0); - *width = cl; - *height = ch; - si = ds.word(si+2) + 2080; - - if (effectsFlag) { - if (effectsFlag & 128) { //centred - di -= *width / 2; - bx -= *height / 2; - } - if (effectsFlag & 64) { //diffdest - frameoutfx(es.ptr(0, dx * *height), ds.ptr(si, *width * *height), dx, *width, *height, di, bx); - return; - } - if (effectsFlag & 8) { //printlist - push(ax); - ax = di - data.word(kMapadx); - push(bx); - bx -= data.word(kMapady); - ah = bl; - bx = pop(); - //addtoprintlist(); // NB: Commented in the original asm - ax = pop(); - } - if (effectsFlag & 4) { //flippedx - es = data.word(kWorkspace); - frameoutfx(es.ptr(0, 320 * *height), ds.ptr(si, *width * *height), 320, *width, *height, di, bx); - return; - } - if (effectsFlag & 2) { //nomask - es = data.word(kWorkspace); - frameoutnm(es.ptr(0, 320 * *height), ds.ptr(si, *width * *height), 320, *width, *height, di, bx); - return; - } - if (effectsFlag & 32) { - es = data.word(kWorkspace); - frameoutbh(es.ptr(0, 320 * *height), ds.ptr(si, *width * *height), 320, *width, *height, di, bx); - return; - } - } -//noeffects: - es = data.word(kWorkspace); - frameoutv(es.ptr(0, 65536), ds.ptr(si, *width * *height), 320, *width, *height, di, bx); - return; } -void DreamGenContext::showframe() { - uint8 width, height; - showframe(es, ds, di, bx, ax & 0x1ff, ah & 0xfe, &width, &height); - cl = width; - ch = height; -} - -void DreamGenContext::printsprites() { - for (size_t priority = 0; priority < 7; ++priority) { - Sprite *sprites = spritetable(); - for (size_t j = 0; j < 16; ++j) { - const Sprite &sprite = sprites[j]; - if (READ_LE_UINT16(&sprite.updateCallback) == 0x0ffff) - continue; - if (priority != sprite.priority) - continue; - if (sprite.hidden == 1) - continue; - printasprite(&sprite); - } - } -} - -void DreamGenContext::printasprite(const Sprite *sprite) { +void DreamGenContext::turnpathoffCPP(uint8 param) { + al = param; push(es); push(bx); - ds = READ_LE_UINT16(&sprite->w6); - ax = sprite->y; - if (al >= 220) { - bx = data.word(kMapady) - (256 - al); - } else { - bx = ax + data.word(kMapady); - } - - ax = sprite->x; - if (al >= 220) { - di = data.word(kMapadx) - (256 - al); - } else { - di = ax + data.word(kMapadx); - } - - uint8 c; - if (sprite->b29 != 0) - c = 8; - else - c = 0; - uint8 width, height; - showframe(es, ds, di, bx, sprite->b15, c, &width, &height); - cl = width; - ch = height; - + turnpathoff(); bx = pop(); es = pop(); } -void DreamGenContext::eraseoldobs() { - if (data.byte(kNewobs) == 0) - return; +void DreamGenContext::modifychar() { + al = engine->modifyChar(al); +} - Sprite *sprites = spritetable(); - for (size_t i=0; i < 16; ++i) { - Sprite &sprite = sprites[i]; - if (READ_LE_UINT16(&sprite.obj_data) != 0xffff) { - memset(&sprite, 0xff, sizeof(Sprite)); +void DreamGenContext::lockmon() { + // Pressing space pauses text output in the monitor. We use the "hard" + // key because calling readkey() drains characters from the input + // buffer, we we want the user to be able to type ahead while the text + // is being printed. + if (data.byte(kLasthardkey) == 57) { + // Clear the keyboard buffer. Otherwise the space that caused + // the pause will be read immediately unpause the game. + do { + readkey(); + } while (data.byte(kCurrentkey) != 0); + + locklighton(); + while (!engine->shouldQuit()) { + engine->waitForVSync(); + readkey(); + if (data.byte(kCurrentkey) == ' ') + break; } + // Forget the last "hard" key, otherwise the space that caused + // the unpausing will immediately re-pause the game. + data.byte(kLasthardkey) = 0; + locklightoff(); } } -void DreamGenContext::clearsprites() { - memset(spritetable(), 0xff, sizeof(Sprite) * 16); +void DreamGenContext::cancelch0() { + data.byte(kCh0repeat) = 0; + data.word(kCh0blockstocopy) = 0; + data.byte(kCh0playing) = 255; + engine->stopSound(0); } -Sprite *DreamGenContext::makesprite(uint8 x, uint8 y, uint16 updateCallback, uint16 somethingInDx, uint16 somethingInDi) { - Sprite *sprite = spritetable(); - while (sprite->b15 != 0xff) { // NB: No boundchecking in the original code either - ++sprite; - } +void DreamGenContext::cancelch1() { + data.word(kCh1blockstocopy) = 0; + data.byte(kCh1playing) = 255; + engine->stopSound(1); +} - WRITE_LE_UINT16(&sprite->updateCallback, updateCallback); - sprite->x = x; - sprite->y = y; - WRITE_LE_UINT16(&sprite->w6, somethingInDx); - WRITE_LE_UINT16(&sprite->w8, somethingInDi); - sprite->w2 = 0xffff; - sprite->b15 = 0; - sprite->delay = 0; - return sprite; +void DreamGenContext::getroomspaths() { + es = data.word(kReels); + bx = data.byte(kRoomnum) * 144; +} + +uint8 *DreamGenContext::getroomspathsCPP() { + void *result = segRef(data.word(kReels)).ptr(data.byte(kRoomnum) * 144, 144); + return (uint8 *)result; } -void DreamGenContext::makesprite() { // NB: returns new sprite in es:bx - Sprite *sprite = makesprite(si & 0xff, si >> 8, cx, dx, di); +void DreamGenContext::makebackob() { + if (data.byte(kNewobs) == 0) + return; + uint8 priority = es.byte(si+5); + uint8 type = es.byte(si+8); + Sprite *sprite = makesprite(data.word(kObjectx), data.word(kObjecty), addr_backobject, data.word(kSetframes), 0); // Recover es:bx from sprite es = data.word(kBuffers); @@ -1230,428 +692,391 @@ void DreamGenContext::makesprite() { // NB: returns new sprite in es:bx Sprite *sprites = (Sprite *)es.ptr(bx, sizeof(Sprite) * 16); bx += sizeof(Sprite) * (sprite - sprites); // + sprite->setObjData(si); + if (priority == 255) + priority = 0; + sprite->priority = priority; + sprite->type = type; + sprite->b16 = 0; + sprite->delay = 0; + sprite->frame = 0; } -void DreamGenContext::spriteupdate() { - Sprite *sprites = spritetable(); - sprites[0].hidden = data.byte(kRyanon); - - Sprite *sprite = sprites; - for (size_t i=0; i < 16; ++i) { - uint16 updateCallback = READ_LE_UINT16(&sprite->updateCallback); - if (updateCallback != 0xffff) { - sprite->w24 = sprite->w2; - if (updateCallback == addr_mainman) // NB : Let's consider the callback as an enum while more code is not ported to C++ - mainmanCPP(sprite); - else { - assert(updateCallback == addr_backobject); - backobject(sprite); - } - } - - if (data.byte(kNowinnewroom) == 1) - break; - ++sprite; - } +void DreamGenContext::getroomdata() { + bx = kRoomdata + sizeof(Room) * al; } -void DreamGenContext::initman() { - Sprite *sprite = makesprite(data.byte(kRyanx), data.byte(kRyany), addr_mainman, data.word(kMainsprites), 0); - sprite->priority = 4; - sprite->b22 = 0; - sprite->b29 = 0; - - // Recover es:bx from sprite - es = data.word(kBuffers); - bx = kSpritetable; - Sprite *sprites = (Sprite *)es.ptr(bx, sizeof(Sprite) * 16); - bx += 32 * (sprite - sprites); - // +void DreamGenContext::getroomdata(uint8 roomIndex) { + getroomdata(roomIndex); } -void DreamGenContext::mainmanCPP(Sprite *sprite) { - push(es); - push(ds); +void DreamGenContext::startloading() { + const Room *room = (Room *)cs.ptr(bx, sizeof(Room)); + startloading(room); +} - // Recover es:bx from sprite - es = data.word(kBuffers); - bx = kSpritetable; - Sprite *sprites = (Sprite *)es.ptr(bx, sizeof(Sprite) * 16); - bx += 32 * (sprite - sprites); - // +void DreamGenContext::readheader() { + ax = engine->readFromFile(cs.ptr(kFileheader, kHeaderlen), kHeaderlen); + es = cs; + di = kFiledata; +} - if (data.byte(kResetmanxy) == 1) { - data.byte(kResetmanxy) = 0; - sprite->x = data.byte(kRyanx); - sprite->y = data.byte(kRyany); - sprite->b29 = 0; - } - --sprite->b22; - if (sprite->b22 != 0xff) { - ds = pop(); - es = pop(); - return; +void DreamGenContext::startloading(const Room *room) { + data.byte(kCombatcount) = 0; + data.byte(kRoomssample) = room->roomsSample; + data.byte(kMapx) = room->mapX; + data.byte(kMapy) = room->mapY; + data.byte(kLiftflag) = room->liftFlag; + data.byte(kManspath) = room->b21; + data.byte(kDestination) = room->b21; + data.byte(kFinaldest) = room->b21; + data.byte(kFacing) = room->b22; + data.byte(kTurntoface) = room->b22; + data.byte(kCounttoopen) = room->countToOpen; + data.byte(kLiftpath) = room->liftPath; + data.byte(kDoorpath) = room->doorPath; + data.byte(kLastweapon) = -1; + al = room->b27; + push(ax); + al = room->b31; + ah = data.byte(kReallocation); + data.byte(kReallocation) = al; + dx = bx; + Common::String name = getFilename(*this); + engine->openFile(name); + cs.word(kHandle) = 1; //only one handle + flags._c = false; + readheader(); + allocateload(); + ds = ax; + data.word(kBackdrop) = ax; + dx = (0); + loadseg(); + ds = data.word(kWorkspace); + dx = (0); + cx = 132*66; + al = 0; + fillspace(); + loadseg(); + sortoutmap(); + allocateload(); + data.word(kSetframes) = ax; + ds = ax; + dx = (0); + loadseg(); + ds = data.word(kSetdat); + dx = 0; + cx = (64*128); + al = 255; + fillspace(); + loadseg(); + allocateload(); + data.word(kReel1) = ax; + ds = ax; + dx = 0; + loadseg(); + allocateload(); + data.word(kReel2) = ax; + ds = ax; + dx = 0; + loadseg(); + allocateload(); + data.word(kReel3) = ax; + ds = ax; + dx = 0; + loadseg(); + allocateload(); + data.word(kReels) = ax; + ds = ax; + dx = 0; + loadseg(); + allocateload(); + data.word(kPeople) = ax; + ds = ax; + dx = 0; + loadseg(); + allocateload(); + data.word(kSetdesc) = ax; + ds = ax; + dx = 0; + loadseg(); + allocateload(); + data.word(kBlockdesc) = ax; + ds = ax; + dx = 0; + loadseg(); + allocateload(); + data.word(kRoomdesc) = ax; + ds = ax; + dx = 0; + loadseg(); + allocateload(); + data.word(kFreeframes) = ax; + ds = ax; + dx = 0; + loadseg(); + ds = data.word(kFreedat); + dx = 0; + cx = (16*80); + al = 255; + fillspace(); + loadseg(); + allocateload(); + data.word(kFreedesc) = ax; + ds = ax; + dx = (0); + loadseg(); + closefile(); + findroominloc(); + deletetaken(); + setallchanges(); + autoappear(); + al = data.byte(kNewlocation); + getroomdata(); + data.byte(kLastweapon) = -1; + data.byte(kMandead) = 0; + data.word(kLookcounter) = 160; + data.byte(kNewlocation) = 255; + data.byte(kLinepointer) = 254; + ax = pop(); + if (al != 255) { + data.byte(kManspath) = al; + push(bx); + autosetwalk(); + bx = pop(); } - sprite->b22 = 0; - if (data.byte(kTurntoface) != data.byte(kFacing)) { - aboutturn(sprite); + findxyfrompath(); +} + +void DreamGenContext::fillspace() { + memset(ds.ptr(dx, cx), al, cx); +} + +void DreamGenContext::dealwithspecial(uint8 firstParam, uint8 secondParam) { + uint8 type = firstParam - 220; + if (type == 0) { + al = secondParam; + placesetobject(); + data.byte(kHavedoneobs) = 1; + } else if (type == 1) { + al = secondParam; + removesetobject(); + data.byte(kHavedoneobs) = 1; + } else if (type == 2) { + al = secondParam; + placefreeobject(); + data.byte(kHavedoneobs) = 1; + } else if (type == 3) { + al = secondParam; + removefreeobject(); + data.byte(kHavedoneobs) = 1; + } else if (type == 4) { + switchryanoff(); + } else if (type == 5) { + data.byte(kTurntoface) = secondParam; + data.byte(kFacing) = secondParam; + switchryanon(); + } else if (type == 6) { + data.byte(kNewlocation) = secondParam; } else { - if ((data.byte(kTurndirection) != 0) && (data.byte(kLinepointer) == 254)) { - data.byte(kReasseschanges) = 1; - if (data.byte(kFacing) == data.byte(kLeavedirection)) - checkforexit(); - } - data.byte(kTurndirection) = 0; - if (data.byte(kLinepointer) == 254) { - sprite->b29 = 0; - } else { - ++sprite->b29; - if (sprite->b29 == 11) - sprite->b29 = 1; - walking(); - if (data.byte(kLinepointer) != 254) { - if ((data.byte(kFacing) & 1) == 0) - walking(); - else if ((sprite->b29 != 2) && (sprite->b29 != 7)) - walking(); - } - if (data.byte(kLinepointer) == 254) { - if (data.byte(kTurntoface) == data.byte(kFacing)) { - data.byte(kReasseschanges) = 1; - if (data.byte(kFacing) == data.byte(kLeavedirection)) - checkforexit(); - } - } - } + movemap(secondParam); } - static const uint8 facelist[] = { 0,60,33,71,11,82,22,93 }; - sprite->b15 = sprite->b29 + facelist[data.byte(kFacing)]; - data.byte(kRyanx) = sprite->x; - data.byte(kRyany) = sprite->y; - - ds = pop(); - es = pop(); } -void DreamGenContext::walking() { - Sprite *sprite = (Sprite *)es.ptr(bx, sizeof(Sprite)); - - uint8 comp; - if (data.byte(kLinedirection) != 0) { - --data.byte(kLinepointer); - comp = 200; - } else { - ++data.byte(kLinepointer); - comp = data.byte(kLinelength); - } - if (data.byte(kLinepointer) < comp) { - sprite->x = data.byte(kLinedata + data.byte(kLinepointer) * 2 + 0); - sprite->y = data.byte(kLinedata + data.byte(kLinepointer) * 2 + 1); - return; +void DreamGenContext::plotreel() { + Reel *reel = getreelstart(); + while (true) { + if (reel->x < 220) + break; + if (reel->x == 255) + break; + dealwithspecial(reel->x, reel->y); + ++data.word(kReelpointer); + reel += 8; } - data.byte(kLinepointer) = 254; - data.byte(kManspath) = data.byte(kDestination); - if (data.byte(kDestination) == data.byte(kFinaldest)) { - facerightway(); - return; + for (size_t i = 0; i < 8; ++i) { + if (reel->frame() != 0xffff) + showreelframe(reel); + ++reel; } - data.byte(kDestination) = data.byte(kFinaldest); - push(es); - push(bx); - autosetwalk(); - bx = pop(); - es = pop(); + soundonreels(); } -void DreamGenContext::aboutturn(Sprite *sprite) { - bool incdir = true; - - if (data.byte(kTurndirection) == 1) - incdir = true; - else if ((int8)data.byte(kTurndirection) == -1) - incdir = false; - else { - if (data.byte(kFacing) < data.byte(kTurntoface)) { - uint8 delta = data.byte(kTurntoface) - data.byte(kFacing); - if (delta >= 4) - incdir = false; - else - incdir = true; - } else { - uint8 delta = data.byte(kFacing) - data.byte(kTurntoface); - if (delta >= 4) - incdir = true; - else - incdir = false; - } - } - - if (incdir) { - data.byte(kTurndirection) = 1; - data.byte(kFacing) = (data.byte(kFacing) + 1) & 7; - sprite->b29 = 0; +void DreamGenContext::crosshair() { + uint8 frame; + if ((data.byte(kCommandtype) != 3) && (data.byte(kCommandtype) < 10)) { + frame = 9; } else { - data.byte(kTurndirection) = -1; - data.byte(kFacing) = (data.byte(kFacing) - 1) & 7; - sprite->b29 = 0; + frame = 29; } + const Frame *src = (const Frame *)segRef(data.word(kIcons1)).ptr(0, 0); + uint8 width, height; + showframe(src, kZoomx + 24, kZoomy + 19, frame, 0, &width, &height); } -void DreamGenContext::backobject(Sprite *sprite) { - push(es); - push(ds); - - // Recover es:bx from sprite - es = data.word(kBuffers); - bx = kSpritetable; - Sprite *sprites = (Sprite *)es.ptr(bx, sizeof(Sprite) * 16); - bx += 32 * (sprite - sprites); - // - - ds = data.word(kSetdat); - di = READ_LE_UINT16(&sprite->obj_data); - ObjData *objData = (ObjData *)ds.ptr(di, 0); +void DreamGenContext::deltextline() { + uint16 x = data.word(kTextaddressx); + uint16 y = data.word(kTextaddressy); + if (data.byte(kForeignrelease) != 0) + y -= 3; + multiput(segRef(data.word(kBuffers)).ptr(kTextunder, 0), x, y, kUndertextsizex, kUndertextsizey); +} - if (sprite->delay != 0) { - --sprite->delay; - ds = pop(); - es = pop(); +void DreamGenContext::autosetwalk() { + al = data.byte(kManspath); + if (data.byte(kFinaldest) == al) + return; + const uint8 *roomsPaths = getroomspathsCPP(); + checkdest(roomsPaths); + data.word(kLinestartx) = roomsPaths[data.byte(kManspath) * 8 + 0] - 12; + data.word(kLinestarty) = roomsPaths[data.byte(kManspath) * 8 + 1] - 12; + data.word(kLineendx) = roomsPaths[data.byte(kDestination) * 8 + 0] - 12; + data.word(kLineendy) = roomsPaths[data.byte(kDestination) * 8 + 1] - 12; + bresenhams(); + if (data.byte(kLinedirection) != 0) { + data.byte(kLinepointer) = data.byte(kLinelength) - 1; + data.byte(kLinedirection) = 1; return; } - - sprite->delay = objData->delay; - if (objData->type == 6) - widedoor(sprite, objData); - else if (objData->type == 5) - random(sprite, objData); - else if (objData->type == 4) - lockeddoorway(); - else if (objData->type == 3) - liftsprite(sprite, objData); - else if (objData->type == 2) - doorway(sprite, objData); - else if (objData->type == 1) - constant(sprite, objData); - else - steady(sprite, objData); - - ds = pop(); - es = pop(); -} - -void DreamGenContext::constant(Sprite *sprite, ObjData *objData) { - ++sprite->frame; - if (objData->b18[sprite->frame] == 255) { - sprite->frame = 0; + data.byte(kLinepointer) = 0; +} + +void DreamGenContext::checkdest(const uint8 *roomsPaths) { + const uint8 *p = roomsPaths + 12 * 8; + ah = data.byte(kManspath) << 4; + al = data.byte(kDestination); + uint8 destination = data.byte(kDestination); + for (size_t i = 0; i < 24; ++i) { + dh = p[0] & 0xf0; + dl = p[0] & 0x0f; + if (ax == dx) { + data.byte(kDestination) = p[1] & 0x0f; + return; + } + dl = (p[0] & 0xf0) >> 4; + dh = (p[0] & 0x0f) << 4; + if (ax == dx) { + destination = p[1] & 0x0f; + } + p += 2; } - uint8 b18 = objData->b18[sprite->frame]; - objData->b17 = b18; - sprite->b15 = b18; -} - -void DreamGenContext::random(Sprite *sprite, ObjData *objData) { - randomnum1(); - uint16 r = ax; - sprite->b15 = objData->b18[r&7]; -} - -void DreamGenContext::doorway(Sprite *sprite, ObjData *objData) { - data.byte(kDoorcheck1) = -24; - data.byte(kDoorcheck2) = 10; - data.byte(kDoorcheck3) = -30; - data.byte(kDoorcheck4) = 10; - dodoor(sprite, objData); -} - -void DreamGenContext::widedoor(Sprite *sprite, ObjData *objData) { - data.byte(kDoorcheck1) = -24; - data.byte(kDoorcheck2) = 24; - data.byte(kDoorcheck3) = -30; - data.byte(kDoorcheck4) = 24; - dodoor(sprite, objData); -} - -void DreamGenContext::dodoor() { - Sprite *sprite = (Sprite *)es.ptr(bx, sizeof(Sprite)); - ObjData *objData = (ObjData *)ds.ptr(di, 0); - dodoor(sprite, objData); -} - -void DreamGenContext::dodoor(Sprite *sprite, ObjData *objData) { - uint8 ryanx = data.byte(kRyanx); - uint8 ryany = data.byte(kRyany); - int8 deltax = ryanx - sprite->x; - int8 deltay = ryany - sprite->y; - if (ryanx < sprite->x) { - if (deltax < (int8)data.byte(kDoorcheck1)) - goto shutdoor; - } else { - if (deltax >= data.byte(kDoorcheck2)) - goto shutdoor; + data.byte(kDestination) = destination; +} + +void DreamGenContext::checkifperson() { + flags._z = not checkifperson(al, ah); +} + +bool DreamGenContext::checkifperson(uint8 x, uint8 y) { + People *people = (People *)segRef(data.word(kBuffers)).ptr(kPeoplelist, 0); + + for (size_t i = 0; i < 12; ++i, ++people) { + if (people->b4 == 255) + continue; + data.word(kReelpointer) = people->w0(); + Reel *reel = getreelstart(); + if (reel->frame() == 0xffff) + ++reel; + const Frame *frame = getreelframeax(reel->frame()); + uint8 xmin = reel->x + frame->x; + uint8 ymin = reel->y + frame->y; + uint8 xmax = xmin + frame->width; + uint8 ymax = ymin + frame->height; + if (x < xmin) + continue; + if (y < ymin) + continue; + if (x >= xmax) + continue; + if (y >= ymax) + continue; + data.word(kPersondata) = people->w2(); + al = people->b4; + ah = 5; + obname(); + return true; } - if (ryany < sprite->y) { - if (deltay < (int8)data.byte(kDoorcheck3)) - goto shutdoor; + return false; +} + +const uint8 *DreamGenContext::findobname(uint8 type, uint8 index) { + if (type == 5) { + uint16 i = 64 * 2 * (index & 127); + uint16 offset = segRef(data.word(kPeople)).word(kPersontxtdat + i) + kPersontext; + return segRef(data.word(kPeople)).ptr(offset, 0); + } else if (type == 4) { + uint16 offset = segRef(data.word(kExtras)).word(kExtextdat + index * 2) + kExtext; + return segRef(data.word(kExtras)).ptr(offset, 0); + } else if (type == 2) { + uint16 offset = segRef(data.word(kFreedesc)).word(kFreetextdat + index * 2) + kFreetext; + return segRef(data.word(kFreedesc)).ptr(offset, 0); + } else if (type == 1) { + uint16 offset = segRef(data.word(kSetdesc)).word(kSettextdat + index * 2) + kSettext; + return segRef(data.word(kSetdesc)).ptr(offset, 0); } else { - if (deltay >= data.byte(kDoorcheck4)) - goto shutdoor; - } -//opendoor: - if ((data.byte(kThroughdoor) == 1) && (sprite->frame == 0)) - sprite->frame = 6; - - ++sprite->frame; - if (sprite->frame == 1) { //doorsound2 - if (data.byte(kReallocation) == 5) //hoteldoor2 - al = 13; - else - al = 0; - playchannel1(); - } - if (objData->b18[sprite->frame] == 255) { - --sprite->frame; - } - sprite->b15 = objData->b17 = objData->b18[sprite->frame]; - data.byte(kThroughdoor) = 1; - return; -shutdoor: - if (sprite->frame == 5) { //doorsound1; - if (data.byte(kReallocation) == 5) //hoteldoor1 - al = 13; - else - al = 1; - playchannel1(); - } - if (sprite->frame != 0) { - --sprite->frame; + uint16 offset = segRef(data.word(kBlockdesc)).word(kBlocktextdat + index * 2) + kBlocktext; + return segRef(data.word(kBlockdesc)).ptr(offset, 0); } - sprite->b15 = objData->b17 = objData->b18[sprite->frame]; - if (sprite->frame == 5) //nearly - data.byte(kThroughdoor) = 0; -} - -void DreamGenContext::steady(Sprite *sprite, ObjData *objData) { - uint8 b18 = objData->b18[0]; - objData->b17 = b18; - sprite->b15 = b18; -} - -void DreamGenContext::turnpathonCPP(uint8 param) { - al = param; - push(es); - push(bx); - turnpathon(); - bx = pop(); - es = pop(); } -void DreamGenContext::turnpathoffCPP(uint8 param) { - al = param; - push(es); - push(bx); - turnpathoff(); - bx = pop(); - es = pop(); +void DreamGenContext::copyname() { + copyname(ah, al, cs.ptr(di, 0)); } -void DreamGenContext::liftsprite() { - Sprite *sprite = (Sprite *)es.ptr(bx, sizeof(Sprite)); - ObjData *objData = (ObjData *)ds.ptr(di, 0); - liftsprite(sprite, objData); -} - -void DreamGenContext::liftsprite(Sprite *sprite, ObjData *objData) { - uint8 liftFlag = data.byte(kLiftflag); - if (liftFlag == 0) { //liftclosed - turnpathoffCPP(data.byte(kLiftpath)); - - if (data.byte(kCounttoopen) != 0) { - _dec(data.byte(kCounttoopen)); - if (data.byte(kCounttoopen) == 0) - data.byte(kLiftflag) = 3; - } - sprite->frame = 0; - sprite->b15 = objData->b17 = objData->b18[sprite->frame]; - } - else if (liftFlag == 1) { //liftopen - turnpathonCPP(data.byte(kLiftpath)); - - if (data.byte(kCounttoclose) != 0) { - _dec(data.byte(kCounttoclose)); - if (data.byte(kCounttoclose) == 0) - data.byte(kLiftflag) = 2; - } - sprite->frame = 12; - sprite->b15 = objData->b17 = objData->b18[sprite->frame]; - } - else if (liftFlag == 3) { //openlift - if (sprite->frame == 12) { - data.byte(kLiftflag) = 1; - return; - } - ++sprite->frame; - if (sprite->frame == 1) { - al = 2; - liftnoise(); - } - sprite->b15 = objData->b17 = objData->b18[sprite->frame]; - } else { //closeLift - assert(liftFlag == 2); - if (sprite->frame == 0) { - data.byte(kLiftflag) = 0; - return; - } - --sprite->frame; - if (sprite->frame == 11) { - al = 3; - liftnoise(); - } - sprite->b15 = objData->b17 = objData->b18[sprite->frame]; +void DreamGenContext::copyname(uint8 type, uint8 index, uint8 *dst) { + const uint8 *src = findobname(type, index); + size_t i; + for (i = 0; i < 28; ++i) { + char c = src[i]; + if (c == ':') + break; + if (c == 0) + break; + dst[i] = c; } + dst[i] = 0; } -void DreamGenContext::modifychar() { - al = engine->modifyChar(al); +void DreamGenContext::commandwithob() { + commandwithob(al, bh, bl); } -void DreamGenContext::lockmon() { - // Pressing space pauses text output in the monitor. We use the "hard" - // key because calling readkey() drains characters from the input - // buffer, we we want the user to be able to type ahead while the text - // is being printed. - if (data.byte(kLasthardkey) == 57) { - // Clear the keyboard buffer. Otherwise the space that caused - // the pause will be read immediately unpause the game. - do { - readkey(); - } while (data.byte(kCurrentkey) != 0); - - locklighton(); - while (!engine->shouldQuit()) { - engine->waitForVSync(); - readkey(); - if (data.byte(kCurrentkey) == ' ') - break; - } - // Forget the last "hard" key, otherwise the space that caused - // the unpausing will immediately re-pause the game. - data.byte(kLasthardkey) = 0; - locklightoff(); +void DreamGenContext::commandwithob(uint8 command, uint8 type, uint8 index) { + uint8 commandLine[64] = "OBJECT NAME ONE "; + deltextline(); + uint16 commandText = kTextstart + segRef(data.word(kCommandtext)).word(command * 2); + uint8 textLen = data.byte(kTextlen); + { + uint16 y = data.word(kTextaddressy); + const uint8 *string = segRef(data.word(kCommandtext)).ptr(commandText, 0); + printdirect(&string, data.word(kTextaddressx), &y, textLen, (bool)(textLen & 1)); } + copyname(type, index, commandLine); + uint16 x = data.word(kLastxpos); + if (command != 0) + x += 5; + { + uint16 y = data.word(kTextaddressy); + const uint8 *string = commandLine; + printdirect(&string, x, &y, textLen, (bool)(textLen & 1)); + } + data.byte(kNewtextline) = 1; } -void DreamGenContext::cancelch0() { - data.byte(kCh0repeat) = 0; - data.word(kCh0blockstocopy) = 0; - data.byte(kCh0playing) = 255; - engine->stopSound(0); +void DreamGenContext::showpanel() { + Frame *frame = (Frame *)segRef(data.word(kIcons1)).ptr(0, sizeof(Frame)); + uint8 width, height; + showframe(frame, 72, 0, 19, 0, &width, &height); + showframe(frame, 192, 0, 19, 0, &width, &height); } -void DreamGenContext::cancelch1() { - data.word(kCh1blockstocopy) = 0; - data.byte(kCh1playing) = 255; - engine->stopSound(1); +bool DreamGenContext::isCD() { + // The original sources has two codepaths depending if the game is 'if cd' or not + // This is a hack to guess which version to use with the assumption that if we have a cd version + // we managed to load the speech. At least it is isolated in this function and can be changed. + // Maybe detect the version during game id? + return (data.byte(kSpeechloaded) == 1); } - } /*namespace dreamgen */ + diff --git a/engines/dreamweb/stubs.h b/engines/dreamweb/stubs.h index b633684f4d..c4385613f6 100644 --- a/engines/dreamweb/stubs.h +++ b/engines/dreamweb/stubs.h @@ -19,7 +19,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ - + uint16 allocatemem(uint16 paragraphs); + uint8 *workspace(); + void allocatework(); + void clearwork(); void multidump(); void multidump(uint16 x, uint16 y, uint8 width, uint8 height); void frameoutv(uint8 *dst, const uint8 *src, uint16 pitch, uint16 width, uint16 height, uint16 x, uint16 y); @@ -28,7 +31,7 @@ void frameoutfx(uint8 *dst, const uint8 *src, uint16 pitch, uint16 width, uint16 height, uint16 x, uint16 y); void worktoscreen(); void multiget(); - void multiget(uint16 x, uint16 y, uint8 width, uint8 height); + void multiget(uint8 *dst, uint16 x, uint16 y, uint8 width, uint8 height); void convertkey(); void cls(); void printsprites(); @@ -38,39 +41,49 @@ void seecommandtail(); void randomnumber(); void quickquit2(); - void getnextword(); - uint8 getnextword(const uint8 *string, uint8 *totalWidth, uint8 *charCount); - void printboth(); - void printboth(uint16 dst, uint16 src, uint16 *x, uint16 y, uint8 c); + uint8 getnextword(const Frame *charSet, const uint8 *string, uint8 *totalWidth, uint8 *charCount); + void printboth(const Frame* charSet, uint16 *x, uint16 y, uint8 c, uint8 nextChar); void printchar(); - void printchar(uint16 dst, uint16 src, uint16 *x, uint16 y, uint8 c, uint8 *width, uint8 *height); + void printchar(const Frame* charSet, uint16 *x, uint16 y, uint8 c, uint8 nextChar, uint8 *width, uint8 *height); void printdirect(); - void printdirect(uint16 x, uint16 *y, uint8 maxWidth, bool centered); + void printdirect(const uint8** string, uint16 x, uint16 *y, uint8 maxWidth, bool centered); void usetimedtext(); + void dumptimedtext(); + void setuptimedtemp(); + void setuptimedtemp(uint8 textIndex, uint8 voiceIndex, uint8 x, uint8 y, uint16 countToTimed, uint16 timeCount); void getundertimed(); void putundertimed(); - uint8 printslow(uint16 x, uint16 y, uint8 maxWidth, bool centered); + uint8 printslow(const uint8 *string, uint16 x, uint16 y, uint8 maxWidth, bool centered); void printslow(); void dumptextline(); void getnumber(); - uint8 getnumber(uint16 index, uint16 maxWidth, bool centered, uint16* offset); + uint8 getnumber(const Frame *charSet, const uint8 *string, uint16 maxWidth, bool centered, uint16 *offset); void kernchars(); uint8 kernchars(uint8 firstChar, uint8 secondChar, uint8 width); + void getroomdata(); + void getroomdata(uint8 roomIndex); + void readheader(); + void fillspace(); + void startloading(); + void startloading(const Room *room); Sprite *spritetable(); void showframe(); - void showframe(uint16 dst, uint16 src, uint16 x, uint16 y, uint16 frameNumber, uint8 effectsFlag, uint8 *width, uint8 *height); + void showframe(const Frame *frameData, uint16 x, uint16 y, uint16 frameNumber, uint8 effectsFlag, uint8 *width, uint8 *height); void printasprite(const Sprite *sprite); void width160(); - void multiput(uint16 x, uint16 y, uint8 width, uint8 height); + void multiput(const uint8 *src, uint16 x, uint16 y, uint8 width, uint8 height); void multiput(); void eraseoldobs(); void clearsprites(); void makesprite(); - Sprite *makesprite(uint8 x, uint8 y, uint16 updateCallback, uint16 somethingInDx, uint16 somethingInDi); + Sprite *makesprite(uint8 x, uint8 y, uint16 updateCallback, uint16 frameData, uint16 somethingInDi); void spriteupdate(); void initman(); - void mainmanCPP(Sprite *sprite); - void walking(); + void mainman(Sprite *sprite); + void facerightway(); + void walking(Sprite *sprite); + void autosetwalk(); + void checkdest(const uint8 *roomsPaths); void aboutturn(Sprite *sprite); void backobject(Sprite *sprite); void constant(Sprite *sprite, ObjData *objData); @@ -80,11 +93,42 @@ void dodoor(Sprite *sprite, ObjData *objData); void doorway(Sprite *sprite, ObjData *objData); void widedoor(Sprite *sprite, ObjData *objData); - void liftsprite(); + void lockeddoorway(Sprite *sprite, ObjData *objData); void liftsprite(Sprite *sprite, ObjData *objData); + void findsource(); + Frame *findsourceCPP(); + void showgamereel(); + void showreelframe(); + void showreelframe(Reel *reel); + const Frame *getreelframeax(uint16 frame); void turnpathonCPP(uint8 param); void turnpathoffCPP(uint8 param); + void getroomspaths(); + uint8 *getroomspathsCPP(); + void makebackob(); void modifychar(); void lockmon(); void cancelch0(); void cancelch1(); + void plotreel(); + Reel *getreelstart(); + void dealwithspecial(uint8 firstParam, uint8 secondParam); + void zoom(); + void crosshair(); + void showrain(); + void deltextline(); + void doblocks(); + void checkifperson(); + bool checkifperson(uint8 x, uint8 y); + const uint8 *findobname(uint8 type, uint8 index); + void copyname(); + void copyname(uint8 type, uint8 index, uint8 *dst); + void commandwithob(); + void commandwithob(uint8 command, uint8 type, uint8 index); + void showpanel(); + void updatepeople(); + void madmantext(); + void madmode(); + void movemap(uint8 param); + bool isCD(); + diff --git a/engines/dreamweb/vgagrafx.cpp b/engines/dreamweb/vgagrafx.cpp new file mode 100644 index 0000000000..c87e27a8c4 --- /dev/null +++ b/engines/dreamweb/vgagrafx.cpp @@ -0,0 +1,452 @@ +/* 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 "dreamweb/dreamweb.h" +#include "engines/util.h" +#include "graphics/surface.h" + +namespace DreamGen { + +uint8 *DreamGenContext::workspace() { + uint8 *result = segRef(data.word(kWorkspace)).ptr(0, 0); + return result; +} + +void DreamGenContext::allocatework() { + data.word(kWorkspace) = allocatemem(0x1000); +} + +void DreamGenContext::multiget() { + multiget(ds.ptr(si, 0), di, bx, cl, ch); + si += cl * ch; + di += bx * kScreenwidth + kScreenwidth * ch; + cx = 0; +} + +void DreamGenContext::multiget(uint8 *dst, uint16 x, uint16 y, uint8 w, uint8 h) { + const uint8 *src = workspace() + x + y * kScreenwidth; + if (y + h > 200) + h = 200 - y; + if (x + w > 320) + w = 320 - x; + //debug(1, "multiget %u,%u %ux%u -> segment: %04x->%04x", x, y, w, h, (uint16)ds, (uint16)es); + for(unsigned l = 0; l < h; ++l) { + const uint8 *src_p = src + kScreenwidth * l; + uint8 *dst_p = dst + w * l; + memcpy(dst_p, src_p, w); + } +} + +void DreamGenContext::multiput() { + multiput(ds.ptr(si, 0), di, bx, cl, ch); + si += cl * ch; + di += bx * kScreenwidth + kScreenwidth * ch; + cx = 0; +} + +void DreamGenContext::multiput(const uint8 *src, uint16 x, uint16 y, uint8 w, uint8 h) { + uint8 *dst = workspace() + x + y * kScreenwidth; + if (y + h > 200) + h = 200 - y; + if (x + w > 320) + w = 320 - x; + //debug(1, "multiput %ux%u -> segment: %04x->%04x", w, h, (uint16)ds, (uint16)es); + for(unsigned l = 0; l < h; ++l) { + const uint8 *src_p = src + w * l; + uint8 *dst_p = dst + kScreenwidth * l; + memcpy(dst_p, src_p, w); + } +} + +void DreamGenContext::multidump(uint16 x, uint16 y, uint8 width, uint8 height) { + unsigned offset = x + y * kScreenwidth; + //debug(1, "multidump %ux%u(segment: %04x) -> %d,%d(address: %d)", w, h, (uint16)ds, x, y, offset); + engine->blit(workspace() + offset, kScreenwidth, x, y, width, height); +} + +void DreamGenContext::multidump() { + multidump(di, bx, cl, ch); + unsigned offset = di + bx * kScreenwidth; + si = di = offset + ch * kScreenwidth; + cx = 0; +} + +void DreamGenContext::worktoscreen() { + uint size = 320 * 200; + engine->blit(workspace(), 320, 0, 0, 320, 200); + di = si = size; + cx = 0; +} + +void DreamGenContext::printundermon() { + engine->printUnderMonitor(); +} + +void DreamGenContext::cls() { + engine->cls(); +} + +void DreamGenContext::frameoutnm(uint8 *dst, const uint8 *src, uint16 pitch, uint16 width, uint16 height, uint16 x, uint16 y) { + dst += pitch * y + x; + + for (uint16 j = 0; j < height; ++j) { + memcpy(dst, src, width); + dst += pitch; + src += width; + } +} + +void DreamGenContext::frameoutbh(uint8 *dst, const uint8 *src, uint16 pitch, uint16 width, uint16 height, uint16 x, uint16 y) { + uint16 stride = pitch - width; + dst += y * pitch + x; + + for (uint16 i = 0; i < height; ++i) { + for (uint16 j = 0; j < width; ++j) { + if (*dst == 0xff) { + *dst = *src; + } + ++src; + ++dst; + } + dst += stride; + } +} + +void DreamGenContext::frameoutfx(uint8 *dst, const uint8 *src, uint16 pitch, uint16 width, uint16 height, uint16 x, uint16 y) { + uint16 stride = pitch - width; + dst += y * pitch + x; + dst -= width; + + for (uint16 j = 0; j < height; ++j) { + for (uint16 i = 0; i < width; ++i) { + uint8 pixel = src[width - i - 1]; + if (pixel) + *dst = pixel; + ++dst; + } + src += width; + dst += stride; + } +} + +void DreamGenContext::doshake() { + uint8 &counter = data.byte(kShakecounter); + _cmp(counter, 48); + if (flags.z()) + return; + + _add(counter, 1); + static const int shakeTable[] = { + 0, -2, 3, -2, 0, 2, 4, -1, + 1, -3, 3, 2, 0, -2, 3, -2, + 0, 2, 4, -1, 1, -3, 3, 2, + 0, -2, 3, -2, 0, 2, 4, -1, + + 1, -3, 3, 2, 0, -2, 3, -2, + 0, 2, 4, -1, 1, -3, 3, 2, + 0, -2, 3, -2, 0, 2, 4, -1, + 1, -3, 3, 2, 0, -2, 3, -2, + + 0, 2, 4, -1, 1, -3, 3, 2, + 0, -2, 3, -2, 0, 2, 4, -1, + 1, -3, 3, 2, 0, -2, 3, -2, + 0, 2, 4, -1, 1, -3, 3, 2, + + 0, -2, 3, -2, 0, 2, 4, -1, + 1, -3, 3, 0, + }; + int offset = shakeTable[counter]; + engine->setShakePos(offset >= 0 ? offset : -offset); +} + +void DreamGenContext::vsync() { + push(ax); + push(bx); + push(cx); + push(dx); + push(si); + push(di); + push(es); + push(ds); + engine->waitForVSync(); + ds = pop(); + es = pop(); + di = pop(); + si = pop(); + dx = pop(); + cx = pop(); + bx = pop(); + ax = pop(); +} + +void DreamGenContext::setmode() { + vsync(); + initGraphics(320, 200, false); +} + +static Common::String getFilename(Context &context) { + uint16 name_ptr = context.dx; + Common::String name; + uint8 c; + while((c = context.cs.byte(name_ptr++)) != 0) + name += (char)c; + return name; +} + +void DreamGenContext::showpcx() { + Common::String name = getFilename(*this); + Common::File pcxFile; + + if (!pcxFile.open(name)) { + warning("showpcx: Could not open '%s'", name.c_str()); + return; + } + + uint8 *maingamepal; + int i, j; + + // Read the 16-color palette into the 'maingamepal' buffer. Note that + // the color components have to be adjusted from 8 to 6 bits. + + pcxFile.seek(16, SEEK_SET); + es = data.word(kBuffers); + maingamepal = es.ptr(kMaingamepal, 768); + pcxFile.read(maingamepal, 48); + + memset(maingamepal + 48, 0xff, 720); + for (i = 0; i < 48; i++) { + maingamepal[i] >>= 2; + } + + // Decode the image data. + + Graphics::Surface *s = g_system->lockScreen(); + Common::Rect rect(640, 480); + + s->fillRect(rect, 0); + pcxFile.seek(128, SEEK_SET); + + for (int y = 0; y < 480; y++) { + byte *dst = (byte *)s->getBasePtr(0, y); + int decoded = 0; + + while (decoded < 320) { + byte col = pcxFile.readByte(); + byte len; + + if ((col & 0xc0) == 0xc0) { + len = col & 0x3f; + col = pcxFile.readByte(); + } else { + len = 1; + } + + // The image uses 16 colors and is stored as four bit + // planes, one for each bit of the color, least + // significant bit plane first. + + for (i = 0; i < len; i++) { + int plane = decoded / 80; + int pos = decoded % 80; + + for (j = 0; j < 8; j++) { + byte bit = (col >> (7 - j)) & 1; + dst[8 * pos + j] |= (bit << plane); + } + + decoded++; + } + } + } + + g_system->unlockScreen(); + pcxFile.close(); +} + +void DreamGenContext::frameoutv(uint8 *dst, const uint8 *src, uint16 pitch, uint16 width, uint16 height, uint16 x, uint16 y) { + // NB : These resilience checks were not in the original engine, but did they result in undefined behaviour + // or was something broken during porting to C++? + assert(pitch == 320); + + if(x >= 320) + return; + if(y >= 200) + return; + if(x + width > 320) { + width = 320 - x; + } + if(y + height > 200) { + height = 200 - y; + } + + uint16 stride = pitch - width; + dst += pitch * y + x; + + for (uint16 j = 0; j < height; ++j) { + for (uint16 i = 0; i < width; ++i) { + uint8 pixel = *src++; + if (pixel) + *dst = pixel; + ++dst; + } + dst += stride; + } +} + +void DreamGenContext::showframe(const Frame *frameData, uint16 x, uint16 y, uint16 frameNumber, uint8 effectsFlag, uint8 *width, uint8 *height) { + const Frame *frame = frameData + frameNumber; + if ((frame->width == 0) && (frame->height == 0)) { + *width = 0; + *height = 0; + return; + } + +//notblankshow: + if ((effectsFlag & 128) == 0) { + x += frame->x; + y += frame->y; + } +//skipoffsets: + + *width = frame->width; + *height = frame->height; + const uint8 *pSrc = ((const uint8 *)frameData) + frame->ptr() + 2080; + + if (effectsFlag) { + if (effectsFlag & 128) { //centred + x -= *width / 2; + y -= *height / 2; + } + if (effectsFlag & 64) { //diffdest + frameoutfx(es.ptr(0, dx * *height), pSrc, dx, *width, *height, x, y); + return; + } + if (effectsFlag & 8) { //printlist + /* + push(ax); + al = x - data.word(kMapadx); + ah = y - data.word(kMapady); + //addtoprintlist(); // NB: Commented in the original asm + ax = pop(); + */ + } + if (effectsFlag & 4) { //flippedx + frameoutfx(workspace(), pSrc, 320, *width, *height, x, y); + return; + } + if (effectsFlag & 2) { //nomask + frameoutnm(workspace(), pSrc, 320, *width, *height, x, y); + return; + } + if (effectsFlag & 32) { + frameoutbh(workspace(), pSrc, 320, *width, *height, x, y); + return; + } + } +//noeffects: + frameoutv(workspace(), pSrc, 320, *width, *height, x, y); + return; +} + +void DreamGenContext::showframe() { + uint8 width, height; + showframe((Frame *)ds.ptr(0, 0), di, bx, ax & 0x1ff, ah & 0xfe, &width, &height); + cl = width; + ch = height; +} + +void DreamGenContext::clearwork() { + memset(workspace(), 0, 320*200); +} + +void DreamGenContext::doblocks() { + uint16 dstOffset = data.word(kMapady) * 320 + data.word(kMapadx); + uint16 mapOffset = kMap + data.byte(kMapy) * kMapwidth + data.byte(kMapx); + ds = data.word(kMapdata); + const uint8 *mapData = ds.ptr(mapOffset, 0); + ds = data.word(kBackdrop); + const uint8 *blocks = ds.ptr(kBlocks, 0); + es = data.word(kWorkspace); + uint8 *dstBuffer = es.ptr(dstOffset, 0); + + for (size_t i = 0; i < 10; ++i) { + for (size_t j = 0; j < 11; ++j) { + uint16 blockType = mapData[j]; + if (blockType != 0) { + uint8 *dst = dstBuffer + i * 320 * 16 + j * 16; + const uint8 *block = blocks + blockType * 256; + for (size_t k = 0; k < 4; ++k) { + memcpy(dst, block, 16); + block += 16; + dst += 320; + } + for (size_t k = 0; k < 12; ++k) { + memcpy(dst, block, 16); + memset(dst + 16, 0xdf, 4); + block += 16; + dst += 320; + } + dst += 4; + ax = 0x0dfdf; + memset(dst, 0xdf, 16); + dst += 320; + memset(dst, 0xdf, 16); + dst += 320; + memset(dst, 0xdf, 16); + dst += 320; + memset(dst, 0xdf, 16); + } + } + mapData += kMapwidth; + } +} + +void DreamGenContext::zoom() { + if (data.word(kWatchingtime) != 0) + return; + if (data.byte(kZoomon) != 1) + return; + if (data.byte(kCommandtype) >= 199) { + putunderzoom(); + return; + } + uint16 srcOffset = (data.word(kOldpointery) - 9) * 320 + (data.word(kOldpointerx) - 11); + uint16 dstOffset = (kZoomy + 4) * 320 + (kZoomx + 5); + const uint8 *src = workspace() + srcOffset; + uint8 *dst = workspace() + dstOffset; + for(size_t i=0; i<20; ++i) { + for(size_t j=0; j<23; ++j) { + uint8 v = src[j]; + dst[2*j+0] = v; + dst[2*j+1] = v; + dst[2*j+320] = v; + dst[2*j+321] = v; + } + src += 320; + dst += 320*2; + } + crosshair(); + data.byte(kDidzoom) = 1; +} + +} /*namespace dreamgen */ + diff --git a/engines/made/detection.cpp b/engines/made/detection.cpp index 1320daaf9d..fa08923e44 100644 --- a/engines/made/detection.cpp +++ b/engines/made/detection.cpp @@ -104,7 +104,7 @@ static const MadeGameDescription gameDescriptions[] = { AD_ENTRY1("rtzcd.red", "cd8b62ece4677c438688c1de3f5379b9"), Common::EN_ANY, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_RTZ, @@ -121,7 +121,7 @@ static const MadeGameDescription gameDescriptions[] = { AD_ENTRY1s("rtzcd.dat", "a1db8c97a78dae10f91d356f16ad07b8", 536064), Common::EN_ANY, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_RTZ, @@ -138,7 +138,7 @@ static const MadeGameDescription gameDescriptions[] = { AD_ENTRY1s("rtzcd.red", "c4e2430e6b6c6ff1562a80fb4a9df24c", 276177), Common::EN_ANY, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_RTZ, @@ -156,7 +156,7 @@ static const MadeGameDescription gameDescriptions[] = { AD_ENTRY1("rtzcd.dat", "9d740378da2d16e83d0d0efff01bf83a"), Common::EN_ANY, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_RTZ, @@ -173,7 +173,7 @@ static const MadeGameDescription gameDescriptions[] = { AD_ENTRY1s("rtzcd.red", "946997d8b0aa6cb4e848bad02a1fc3d2", 276584), Common::EN_ANY, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_RTZ, @@ -191,7 +191,7 @@ static const MadeGameDescription gameDescriptions[] = { AD_ENTRY1s("rtzcd.dat", "9d740378da2d16e83d0d0efff01bf83a", 525824), Common::DE_DEU, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_RTZ, @@ -209,7 +209,7 @@ static const MadeGameDescription gameDescriptions[] = { AD_ENTRY1s("rtzcd.red", "946997d8b0aa6cb4e848bad02a1fc3d2", 355442), Common::DE_DEU, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_RTZ, @@ -227,7 +227,7 @@ static const MadeGameDescription gameDescriptions[] = { AD_ENTRY1s("rtzcd.dat", "5b86035aed0277f96e3d173542b5364a", 523776), Common::IT_ITA, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_RTZ, @@ -245,7 +245,7 @@ static const MadeGameDescription gameDescriptions[] = { AD_ENTRY1s("rtzcd.red", "946997d8b0aa6cb4e848bad02a1fc3d2", 354971), Common::IT_ITA, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_RTZ, @@ -263,7 +263,7 @@ static const MadeGameDescription gameDescriptions[] = { AD_ENTRY1s("rtzcd.dat", "bde8251a8e34e87c54e3f93147d56c9e", 523776), Common::FR_FRA, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_RTZ, @@ -281,7 +281,7 @@ static const MadeGameDescription gameDescriptions[] = { AD_ENTRY1s("rtzcd.red", "946997d8b0aa6cb4e848bad02a1fc3d2", 354614), Common::FR_FRA, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_RTZ, @@ -333,7 +333,7 @@ static const MadeGameDescription gameDescriptions[] = { AD_ENTRY1("rtzcd.dat", "c4fccf67ad247f09b94c3c808b138576"), Common::JA_JPN, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_RTZ, @@ -351,7 +351,7 @@ static const MadeGameDescription gameDescriptions[] = { AD_ENTRY1("rtzcd.dat", "e949a6a42d82daabfa7d4dc0a87a9843"), Common::JA_JPN, Common::kPlatformFMTowns, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_RTZ, @@ -369,7 +369,7 @@ static const MadeGameDescription gameDescriptions[] = { AD_ENTRY1("rtzcd.dat", "0c0117e98530c736a141c2aad6834dc5"), Common::JA_JPN, Common::kPlatformPC98, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_RTZ, @@ -386,7 +386,7 @@ static const MadeGameDescription gameDescriptions[] = { AD_ENTRY1("manhole.dat", "cb21e31ed35c963208343bc995225b73"), Common::EN_ANY, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NOSPEECH }, GID_MANHOLE, diff --git a/engines/mohawk/cursors.cpp b/engines/mohawk/cursors.cpp index 78e099ccfe..cbd17e0b86 100644 --- a/engines/mohawk/cursors.cpp +++ b/engines/mohawk/cursors.cpp @@ -49,36 +49,13 @@ void CursorManager::hideCursor() { } void CursorManager::setDefaultCursor() { - static const byte defaultCursor[] = { - 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, - 1, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, - 1, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, - 1, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, - 1, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, - 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, - 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, - 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, - 1, 2, 2, 2, 1, 2, 2, 1, 0, 0, 0, 0, - 1, 2, 2, 1, 1, 2, 2, 1, 0, 0, 0, 0, - 1, 2, 1, 0, 1, 1, 2, 2, 1, 0, 0, 0, - 1, 1, 0, 0, 0, 1, 2, 2, 1, 0, 0, 0, - 1, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0 - }; - - static const byte bwPalette[] = { - 0x00, 0x00, 0x00, // Black - 0xFF, 0xFF, 0xFF // White - }; - - CursorMan.replaceCursor(defaultCursor, 12, 20, 0, 0, 0); - CursorMan.replaceCursorPalette(bwPalette, 1, 2); + Graphics::Cursor *cursor = Graphics::makeDefaultWinCursor(); + + CursorMan.replaceCursor(cursor->getSurface(), cursor->getWidth(), cursor->getHeight(), cursor->getHotspotX(), + cursor->getHotspotY(), cursor->getKeyColor()); + CursorMan.replaceCursorPalette(cursor->getPalette(), cursor->getPaletteStartIndex(), cursor->getPaletteCount()); + + delete cursor; } void CursorManager::setCursor(uint16 id) { diff --git a/engines/mohawk/detection_tables.h b/engines/mohawk/detection_tables.h index 01eac0aaba..a587d06760 100644 --- a/engines/mohawk/detection_tables.h +++ b/engines/mohawk/detection_tables.h @@ -653,6 +653,23 @@ static const MohawkGameDescription gameDescriptions[] = { "HARRY.EXE" }, + // part of "Super Living Books" compilation + // from rgemini, bug #3309343 + { + { + "harryhh", + "", + AD_ENTRY1("HARRY.512", "39d11399796dfa36d3f631d2d87e8b85"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV1, + 0, + "HARRY.EXE" + }, + { { "carmentq", @@ -929,6 +946,23 @@ static const MohawkGameDescription gameDescriptions[] = { "TORTOISE.EXE" }, + // part of "Super Living Books" compilation + // from rgemini, bug #3309343 + { + { + "tortoise", + "", + AD_ENTRY1("TORTOISE.512", "e9ec7a6bc6b451c9e85e5b4f072d5143"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV1, + 0, + "TORTOISE.EXE" + }, + // From afholman in bug#3309308 { { @@ -1053,6 +1087,23 @@ static const MohawkGameDescription gameDescriptions[] = { "ARTHUR.EXE" }, + // part of "Super Living Books" compilation + // from rgemini, bug #3309343 + { + { + "arthur", + "", + AD_ENTRY1("PAGES.512", "cd995d20d0d7b4642476fd76044b4e5b"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV1, + GF_LB_10, + "ARTHUR.EXE" + }, + // From afholman in bug#3309308 { { @@ -1195,6 +1246,22 @@ static const MohawkGameDescription gameDescriptions[] = { "GRANDMA.EXE" }, + // from jjnryan in bug #3389857 + { + { + "grandma", + "v1.0", + AD_ENTRY1("PAGES.512", "613ca946bc8d91087fb7c10e9b84e88b"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV1, + GF_LB_10, + "GRANDMA.EXE" + }, + { { "grandma", @@ -1366,6 +1433,23 @@ static const MohawkGameDescription gameDescriptions[] = { "NEWKID.EXE" }, + // part of "Super Living Books" compilation + // from rgemini, bug #3309343 + { + { + "newkid", + "", + AD_ENTRY1("NEWKID.512", "28a5aef3e6ef7e2ed7742485c25bdff6"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV1, + 0, + "NEWKID.EXE" + }, + // From aluff in bug#3309981 { { diff --git a/engines/mohawk/dialogs.cpp b/engines/mohawk/dialogs.cpp index 11e050aa72..2d1cc3bfa3 100644 --- a/engines/mohawk/dialogs.cpp +++ b/engines/mohawk/dialogs.cpp @@ -81,7 +81,8 @@ enum { kTransCmd = 'TRAN', kWaterCmd = 'WATR', kDropCmd = 'DROP', - kMapCmd = 'SMAP' + kMapCmd = 'SMAP', + kMenuCmd = 'MENU' }; #ifdef ENABLE_MYST @@ -97,6 +98,12 @@ MystOptionsDialog::MystOptionsDialog(MohawkEngine_Myst* vm) : GUI::OptionsDialog else _showMapButton = 0; + // Myst demo only has a menu + if (_vm->getFeatures() & GF_DEMO) + _returnToMenuButton = new GUI::ButtonWidget(this, 15, 95, 100, 25, _("~M~ain Menu"), 0, kMenuCmd); + else + _returnToMenuButton = 0; + new GUI::ButtonWidget(this, 95, 160, 120, 25, _("~O~K"), 0, GUI::kOKCmd); new GUI::ButtonWidget(this, 225, 160, 120, 25, _("~C~ancel"), 0, GUI::kCloseCmd); } @@ -113,6 +120,11 @@ void MystOptionsDialog::open() { _showMapButton->setEnabled(_vm->_scriptParser && _vm->_scriptParser->getMap()); + // Return to menu button is not enabled on the menu + if (_returnToMenuButton) + _returnToMenuButton->setEnabled(_vm->_scriptParser && + _vm->getCurStack() != kDemoStack); + // Zip mode is disabled in the demo if (_vm->getFeatures() & GF_DEMO) _zipModeCheckbox->setEnabled(false); @@ -137,6 +149,10 @@ void MystOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, ui _vm->_needsShowMap = true; close(); break; + case kMenuCmd: + _vm->_needsShowDemoMenu = true; + close(); + break; case GUI::kCloseCmd: close(); break; diff --git a/engines/mohawk/dialogs.h b/engines/mohawk/dialogs.h index 853ff30813..844c01ad26 100644 --- a/engines/mohawk/dialogs.h +++ b/engines/mohawk/dialogs.h @@ -83,6 +83,7 @@ private: GUI::CheckboxWidget *_transitionsCheckbox; GUI::ButtonWidget *_dropPageButton; GUI::ButtonWidget *_showMapButton; + GUI::ButtonWidget *_returnToMenuButton; }; #endif diff --git a/engines/mohawk/graphics.cpp b/engines/mohawk/graphics.cpp index b3653b1fdf..35c9d478d8 100644 --- a/engines/mohawk/graphics.cpp +++ b/engines/mohawk/graphics.cpp @@ -672,6 +672,14 @@ void MystGraphics::simulatePreviousDrawDelay(const Common::Rect &dest) { _nextAllowedDrawTime = time + _constantDrawDelay + dest.height() * dest.width() / _proportionalDrawDelay; } +void MystGraphics::fadeToBlack() { + // TODO: Implement +} + +void MystGraphics::fadeFromBlack() { + // TODO: Implement +} + #endif // ENABLE_MYST #ifdef ENABLE_RIVEN @@ -913,7 +921,8 @@ void RivenGraphics::clearMainScreen() { } void RivenGraphics::fadeToBlack() { - // Self-explanatory + // The transition speed is forced to best here + setTransitionSpeed(kRivenTransitionSpeedBest); scheduleTransition(16); clearMainScreen(); runScheduledTransition(); diff --git a/engines/mohawk/graphics.h b/engines/mohawk/graphics.h index d7057f48cf..96357bbff1 100644 --- a/engines/mohawk/graphics.h +++ b/engines/mohawk/graphics.h @@ -129,6 +129,8 @@ public: void drawRect(Common::Rect rect, RectState state); void drawLine(const Common::Point &p1, const Common::Point &p2, uint32 color); void enableDrawingTimeSimulation(bool enable); + void fadeToBlack(); + void fadeFromBlack(); protected: MohawkSurface *decodeImage(uint16 id); @@ -194,6 +196,7 @@ public: void scheduleTransition(uint16 id, Common::Rect rect = Common::Rect(0, 0, 608, 392)); void runScheduledTransition(); void fadeToBlack(); + void setTransitionSpeed(uint32 speed) { _transitionSpeed = speed; } // Inventory void showInventory(); @@ -229,6 +232,7 @@ private: // Transitions int16 _scheduledTransition; Common::Rect _transitionRect; + uint32 _transitionSpeed; // Inventory void clearInventoryArea(); diff --git a/engines/mohawk/myst.cpp b/engines/mohawk/myst.cpp index 342fa4e78c..eeb4594f3c 100644 --- a/engines/mohawk/myst.cpp +++ b/engines/mohawk/myst.cpp @@ -343,6 +343,7 @@ Common::Error MohawkEngine_Myst::run() { case Common::KEYCODE_F5: _needsPageDrop = false; _needsShowMap = false; + _needsShowDemoMenu = false; runDialog(*_optionsDialog); @@ -355,6 +356,11 @@ Common::Error MohawkEngine_Myst::run() { _scriptParser->showMap(); _needsShowMap = false; } + + if (_needsShowDemoMenu) { + changeToStack(kDemoStack, 2002, 0, 0); + _needsShowDemoMenu = false; + } break; default: break; diff --git a/engines/mohawk/myst.h b/engines/mohawk/myst.h index ebcc3b445c..02f0a46e3f 100644 --- a/engines/mohawk/myst.h +++ b/engines/mohawk/myst.h @@ -167,6 +167,7 @@ public: bool _needsUpdate; bool _needsPageDrop; bool _needsShowMap; + bool _needsShowDemoMenu; MystView _view; MystGraphics *_gfx; diff --git a/engines/mohawk/myst_stacks/demo.cpp b/engines/mohawk/myst_stacks/demo.cpp index 5788f4b3a3..c9e806655e 100644 --- a/engines/mohawk/myst_stacks/demo.cpp +++ b/engines/mohawk/myst_stacks/demo.cpp @@ -20,16 +20,20 @@ * */ +#include "mohawk/cursors.h" +#include "mohawk/graphics.h" #include "mohawk/myst.h" #include "mohawk/myst_stacks/demo.h" -#include "gui/message.h" +#include "common/system.h" namespace Mohawk { namespace MystStacks { Demo::Demo(MohawkEngine_Myst *vm) : Intro(vm) { setupOpcodes(); + + _returnToMenuStep = 0; } Demo::~Demo() { @@ -47,15 +51,12 @@ Demo::~Demo() { void Demo::setupOpcodes() { // "Stack-Specific" Opcodes - OVERRIDE_OPCODE(100, opcode_100); - OPCODE(101, opcode_101); - OPCODE(102, opcode_102); + OVERRIDE_OPCODE(100, o_stopIntro); + OPCODE(101, o_fadeFromBlack); + OPCODE(102, o_fadeToBlack); // "Init" Opcodes - OVERRIDE_OPCODE(201, opcode_201); - - // "Exit" Opcodes - OVERRIDE_OPCODE(300, opcode_300); + OVERRIDE_OPCODE(201, o_returnToMenu_init); } #undef OPCODE @@ -64,61 +65,66 @@ void Demo::setupOpcodes() { void Demo::disablePersistentScripts() { Intro::disablePersistentScripts(); - _enabled201 = false; + _returnToMenuRunning = false; } void Demo::runPersistentScripts() { Intro::runPersistentScripts(); - if (_enabled201) { - // Used on Card 2001, 2002 and 2003 - - // TODO: Fill in Function... + if (_returnToMenuRunning) { + returnToMenu_run(); } } -void Demo::opcode_100(uint16 op, uint16 var, uint16 argc, uint16 *argv) { - // TODO: Fill in Function... +void Demo::o_stopIntro(uint16 op, uint16 var, uint16 argc, uint16 *argv) { + debugC(kDebugScript, "Opcode %d: Unk", op); + // The original also seems to stop the movies. Not needed with this engine. + _vm->_gfx->fadeToBlack(); } -void Demo::opcode_101(uint16 op, uint16 var, uint16 argc, uint16 *argv) { - varUnusedCheck(op, var); - - // Used on Card 2000, 2002 and 2003 - // Triggered by Click - if (argc == 0) { - // TODO: Fill in Logic.. Fade in? - } else - unknown(op, var, argc, argv); +void Demo::o_fadeFromBlack(uint16 op, uint16 var, uint16 argc, uint16 *argv) { + debugC(kDebugScript, "Opcode %d: Fade from black", op); + _vm->_gfx->fadeFromBlack(); } -void Demo::opcode_102(uint16 op, uint16 var, uint16 argc, uint16 *argv) { - varUnusedCheck(op, var); - - // Used on Card 2002 and 2003 - // Triggered by Click - if (argc == 0) { - // TODO: Fill in Logic.. Fade out? - } else - unknown(op, var, argc, argv); +void Demo::o_fadeToBlack(uint16 op, uint16 var, uint16 argc, uint16 *argv) { + debugC(kDebugScript, "Opcode %d: Fade to black", op); + _vm->_gfx->fadeToBlack(); } -void Demo::opcode_201(uint16 op, uint16 var, uint16 argc, uint16 *argv) { - varUnusedCheck(op, var); - - // Used on Card 2001, 2002 and 2003 - if (argc == 0) - _enabled201 = true; - else - unknown(op, var, argc, argv); +void Demo::returnToMenu_run() { + uint32 time = _vm->_system->getMillis(); + + if (time < _returnToMenuNextTime) + return; + + switch (_returnToMenuStep){ + case 0: + _vm->_gfx->fadeToBlack(); + _vm->changeToCard(2003, true); + _vm->_gfx->fadeFromBlack(); + + _returnToMenuStep++; + break; + case 1: + _vm->_gfx->fadeToBlack(); + _vm->changeToCard(2001, true); + _vm->_gfx->fadeFromBlack(); + _vm->_cursor->showCursor(); + + _returnToMenuStep++; + break; + default: + break; + } } +void Demo::o_returnToMenu_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { + debugC(kDebugScript, "Opcode %d: Return to menu init", op); -void Demo::opcode_300(uint16 op, uint16 var, uint16 argc, uint16 *argv) { - // Used on Card 2000 - varUnusedCheck(op, var); - - // TODO: Fill in Function... + // Used on Card 2001, 2002 and 2003 + _returnToMenuNextTime = _vm->_system->getMillis() + 5000; + _returnToMenuRunning = true; } } // End of namespace MystStacks diff --git a/engines/mohawk/myst_stacks/demo.h b/engines/mohawk/myst_stacks/demo.h index 4f8d68759b..c3e57cf7ae 100644 --- a/engines/mohawk/myst_stacks/demo.h +++ b/engines/mohawk/myst_stacks/demo.h @@ -46,15 +46,19 @@ public: private: void setupOpcodes(); - DECLARE_OPCODE(opcode_100); - DECLARE_OPCODE(opcode_101); - DECLARE_OPCODE(opcode_102); + DECLARE_OPCODE(o_stopIntro); + DECLARE_OPCODE(o_fadeFromBlack); + DECLARE_OPCODE(o_fadeToBlack); - DECLARE_OPCODE(opcode_201); + DECLARE_OPCODE(o_returnToMenu_init); DECLARE_OPCODE(opcode_300); - bool _enabled201; + bool _returnToMenuRunning; + uint16 _returnToMenuStep; // 42 + uint32 _returnToMenuNextTime; // 6 + + void returnToMenu_run(); }; } // End of namespace MystStacks diff --git a/engines/mohawk/myst_stacks/myst.h b/engines/mohawk/myst_stacks/myst.h index 9510d371d7..e9bff08cb4 100644 --- a/engines/mohawk/myst_stacks/myst.h +++ b/engines/mohawk/myst_stacks/myst.h @@ -40,8 +40,8 @@ public: Myst(MohawkEngine_Myst *vm); ~Myst(); - void disablePersistentScripts(); - void runPersistentScripts(); + virtual void disablePersistentScripts(); + virtual void runPersistentScripts(); private: void setupOpcodes(); diff --git a/engines/mohawk/myst_stacks/preview.cpp b/engines/mohawk/myst_stacks/preview.cpp index 07e4fa6e57..1b72c85d96 100644 --- a/engines/mohawk/myst_stacks/preview.cpp +++ b/engines/mohawk/myst_stacks/preview.cpp @@ -54,86 +54,187 @@ Preview::~Preview() { void Preview::setupOpcodes() { // "Stack-Specific" Opcodes - OVERRIDE_OPCODE(196, opcode_196); - OVERRIDE_OPCODE(197, opcode_197); - OVERRIDE_OPCODE(198, opcode_198); - OVERRIDE_OPCODE(199, opcode_199); + OVERRIDE_OPCODE(196, o_fadeToBlack); + OVERRIDE_OPCODE(197, o_fadeFromBlack); + OVERRIDE_OPCODE(198, o_stayHere); + OVERRIDE_OPCODE(199, o_speechStop); // "Init" Opcodes - OPCODE(298, opcode_298); - OPCODE(299, opcode_299); + OPCODE(298, o_speech_init); + OPCODE(299, o_library_init); } #undef OPCODE #undef OVERRIDE_OPCODE -void Preview::opcode_196(uint16 op, uint16 var, uint16 argc, uint16 *argv) { - varUnusedCheck(op, var); +void Preview::disablePersistentScripts() { + Myst::disablePersistentScripts(); +} + +void Preview::runPersistentScripts() { + Myst::runPersistentScripts(); - // Used on Card ... - // TODO: Finish Implementation... - // Voice Over and Card Advance? + if (_speechRunning) + speech_run(); } -void Preview::opcode_197(uint16 op, uint16 var, uint16 argc, uint16 *argv) { - varUnusedCheck(op, var); +void Preview::o_fadeToBlack(uint16 op, uint16 var, uint16 argc, uint16 *argv) { + debugC(kDebugScript, "Opcode %d: Fade to black", op); + _vm->_gfx->fadeToBlack(); +} - // Used on Card ... - // TODO: Finish Implementation... - // Voice Over and Card Advance? +void Preview::o_fadeFromBlack(uint16 op, uint16 var, uint16 argc, uint16 *argv) { + debugC(kDebugScript, "Opcode %d: Fade from black", op); + _vm->_gfx->fadeFromBlack(); } -// TODO: Merge with Opcode 42? -void Preview::opcode_198(uint16 op, uint16 var, uint16 argc, uint16 *argv) { - varUnusedCheck(op, var); +void Preview::o_stayHere(uint16 op, uint16 var, uint16 argc, uint16 *argv) { + debugC(kDebugScript, "Opcode %d: Stay here dialog", op); - if (argc == 0) { - // Nuh-uh! No leaving the library in the demo! - GUI::MessageDialog dialog("You can't leave the library in the demo."); - dialog.runModal(); - } else - unknown(op, var, argc, argv); + // Nuh-uh! No leaving the library in the demo! + GUI::MessageDialog dialog("You can't leave the library in the demo."); + dialog.runModal(); } -void Preview::opcode_199(uint16 op, uint16 var, uint16 argc, uint16 *argv) { - varUnusedCheck(op, var); +void Preview::o_speechStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) { + debugC(kDebugScript, "Opcode %d: Speech stop", op); - // Used on Card ... - // TODO: Finish Implementation... - // Voice Over and Card Advance? + _speechRunning = false; + _globals.currentAge = 2; } -void Preview::opcode_298(uint16 op, uint16 var, uint16 argc, uint16 *argv) { - varUnusedCheck(op, var); +void Preview::speechUpdateCue() { + // This is a callback in the original, handling audio events. + if (!_vm->_sound->isPlaying(3001)) { + return; + } - // Used for Card 3000 (Closed Myst Book) - // TODO: Fill in logic. - // Start Voice Over... which controls book opening - _vm->_sound->replaceSoundMyst(3001); - - // then link to Myst - Trigger of Hotspot? then opcode 199/196/197 for voice over continue? - // TODO: Sync Voice and Actions to Original - // TODO: Flash Library Red - // TODO: Move to run process based delay to prevent - // blocking... - _vm->_system->updateScreen(); - _vm->_system->delayMillis(20 * 1000); - - for (uint16 imageId = 3001; imageId <= 3012; imageId++) { - _vm->_gfx->copyImageToScreen(imageId, Common::Rect(0, 0, 544, 333)); - _vm->_system->updateScreen(); - _vm->_system->delayMillis(5 * 1000); + uint samples = _vm->_sound->getNumSamplesPlayed(3001); + for (int16 i = 0; i < _cueList.pointCount; i++) { + if (_cueList.points[i].sampleFrame > samples) + return; + if (i > _currentCue - 1) { + _currentCue++; + debugC(kDebugScript, "Sneak speech advanced to cue %d", _currentCue); + } } } -void Preview::opcode_299(uint16 op, uint16 var, uint16 argc, uint16 *argv) { - varUnusedCheck(op, var); +void Preview::speech_run() { + uint32 time = _vm->_system->getMillis(); + + // Update current speech sound cue + speechUpdateCue(); + + switch (_speechStep) { + case 0: // Start Voice Over... which controls book opening + _currentCue = 0; + _vm->_sound->playSound(3001, Audio::Mixer::kMaxChannelVolume, false, &_cueList); + + _speechStep++; + break; + case 1: // Open book + if (_currentCue >= 1) { + _vm->changeToCard(3001, true); + + _speechStep++; + } + break; + case 2: // Go to Myst + if (_currentCue >= 2) { + _vm->_gfx->fadeToBlack(); + _vm->changeToCard(3002, true); + _vm->_gfx->fadeFromBlack(); + + _speechStep++; + } + break; + case 3: // Start blinking the library + if (_currentCue >= 3) { + _libraryState = 1; + _speechNextTime = 0; + _speechStep++; + } + break; + case 4: // Library blinking, zoom in library + if (_currentCue >= 4) { + _library->drawConditionalDataToScreen(0); + + _vm->changeToCard(3003, true); + + _speechNextTime = time + 2000; + _speechStep++; + } else { + if (time < _speechNextTime) + break; + + _library->drawConditionalDataToScreen(_libraryState); + _libraryState = (_libraryState + 1) % 2; + _speechNextTime = time + 500; + } + break; + case 5: // Go to library near view + if (time < _speechNextTime) + break; + + _vm->changeToCard(3004, true); + _speechNextTime = time + 2000; + _speechStep++; + break; + case 6: // Fade to courtyard + if (time < _speechNextTime) + break; + + _vm->_gfx->fadeToBlack(); + _vm->changeToCard(3005, true); + _vm->_gfx->fadeFromBlack(); + _speechNextTime = time + 1000; + _speechStep++; + break; + case 7: // Walk to library + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + if (time < _speechNextTime) + break; + + _vm->changeToCard(3006 + _speechStep - 7, true); + _speechNextTime = time + 2000; + _speechStep++; + break; + case 14: // Go to playable library card + if (time < _speechNextTime) + break; + + _vm->changeToCard(4329, true); + + _speechRunning = false; + _globals.currentAge = 2; + + _vm->_cursor->showCursor(); + break; + default: + warning("Unknown speech step"); + break; + } +} + +void Preview::o_speech_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { + debugC(kDebugScript, "Opcode %d: Speech init", op); + + // Used for Card 3000 (Closed Myst Book) + _speechStep = 0; + _speechRunning = true; +} + +void Preview::o_library_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { + debugC(kDebugScript, "Opcode %d: Library init", op); // Used for Card 3002 (Myst Island Overview) - // TODO: Fill in logic. - // Zoom into Island? - // On this card is a Type 8 controlled by Var 0, which - // can change the Myst Library to Red.. + _library = static_cast<MystResourceType8 *>(_invokingResource); } } // End of namespace MystStacks diff --git a/engines/mohawk/myst_stacks/preview.h b/engines/mohawk/myst_stacks/preview.h index 7e4e418eef..1e4ff3efb4 100644 --- a/engines/mohawk/myst_stacks/preview.h +++ b/engines/mohawk/myst_stacks/preview.h @@ -40,16 +40,31 @@ public: Preview(MohawkEngine_Myst *vm); ~Preview(); + void disablePersistentScripts(); + void runPersistentScripts(); + private: void setupOpcodes(); - DECLARE_OPCODE(opcode_196); - DECLARE_OPCODE(opcode_197); - DECLARE_OPCODE(opcode_198); - DECLARE_OPCODE(opcode_199); + DECLARE_OPCODE(o_fadeToBlack); + DECLARE_OPCODE(o_fadeFromBlack); + DECLARE_OPCODE(o_stayHere); + DECLARE_OPCODE(o_speechStop); + + DECLARE_OPCODE(o_speech_init); + DECLARE_OPCODE(o_library_init); + + uint16 _libraryState; // 4 + MystResourceType8 *_library; // 32 + + bool _speechRunning; + uint _speechStep; + CueList _cueList; + int16 _currentCue; + uint32 _speechNextTime; // 6 - DECLARE_OPCODE(opcode_298); - DECLARE_OPCODE(opcode_299); + void speech_run(); + void speechUpdateCue(); }; } // End of namespace MystStacks diff --git a/engines/mohawk/myst_stacks/slides.cpp b/engines/mohawk/myst_stacks/slides.cpp index e9bb91c84d..943cb90071 100644 --- a/engines/mohawk/myst_stacks/slides.cpp +++ b/engines/mohawk/myst_stacks/slides.cpp @@ -61,18 +61,26 @@ void Slides::disablePersistentScripts() { void Slides::runPersistentScripts() { if (_cardSwapEnabled) { // Used on Cards... - if (_vm->_system->getMillis() > _nextCardTime) + if (_vm->_system->getMillis() > _nextCardTime) { + _vm->_gfx->fadeToBlack(); _vm->changeToCard(_nextCardID, true); + _vm->_gfx->fadeFromBlack(); + } } } void Slides::o_returnToMenu(uint16 op, uint16 var, uint16 argc, uint16 *argv) { + debugC(kDebugScript, "Opcode %d: Return to menu", op); + // Go to the information screens of the menu _vm->changeToStack(kDemoStack, 2002, 0, 0); } void Slides::o_setCardSwap(uint16 op, uint16 var, uint16 argc, uint16 *argv) { _nextCardID = argv[0]; + + debugC(kDebugScript, "Opcode %d: Set next card %d", op, _nextCardID); + _nextCardTime = _vm->_system->getMillis() + 5000; _cardSwapEnabled = true; } diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp index 612b8b3685..3e2fa4f979 100644 --- a/engines/mohawk/riven.cpp +++ b/engines/mohawk/riven.cpp @@ -150,6 +150,9 @@ Common::Error MohawkEngine_Riven::run() { return Common::kNoGameDataFoundError; } + // Set the transition speed + _gfx->setTransitionSpeed(_vars["transitionmode"]); + // Start at main cursor _cursor->setCursor(kRivenMainCursor); _cursor->showCursor(); @@ -209,8 +212,10 @@ void MohawkEngine_Riven::handleEvents() { needsUpdate = true; break; case Common::EVENT_LBUTTONDOWN: - if (_curHotspot >= 0) + if (_curHotspot >= 0) { + checkSunnerAlertClick(); runHotspotScript(_curHotspot, kMouseDownScript); + } break; case Common::EVENT_LBUTTONUP: // See RivenScript::switchCard() for more information on why we sometimes @@ -812,6 +817,138 @@ static void catherineIdleTimer(MohawkEngine_Riven *vm) { vm->installTimer(&catherineIdleTimer, timeUntilNextMovie); } +static void sunnersTopStairsTimer(MohawkEngine_Riven *vm) { + // If the sunners are gone, we have no video to play + if (vm->_vars["jsunners"] != 0) { + vm->removeTimer(); + return; + } + + // Play a random sunners video if the script one is not playing already + // and then set a new timer for when the new video should be played + + VideoHandle oldHandle = vm->_video->findVideoHandleRiven(1); + uint32 timerTime = 500; + + if (oldHandle == NULL_VID_HANDLE || vm->_video->endOfVideo(oldHandle)) { + uint32 &sunnerTime = vm->_vars["jsunnertime"]; + + if (sunnerTime == 0) { + timerTime = vm->_rnd->getRandomNumberRng(2, 15) * 1000; + } else if (sunnerTime < vm->getTotalPlayTime()) { + VideoHandle handle = vm->_video->playMovieRiven(vm->_rnd->getRandomNumberRng(1, 3)); + + timerTime = vm->_video->getDuration(handle) + vm->_rnd->getRandomNumberRng(2, 15) * 1000; + } + + sunnerTime = timerTime + vm->getTotalPlayTime(); + } + + vm->installTimer(&sunnersTopStairsTimer, timerTime); +} + +static void sunnersMidStairsTimer(MohawkEngine_Riven *vm) { + // If the sunners are gone, we have no video to play + if (vm->_vars["jsunners"] != 0) { + vm->removeTimer(); + return; + } + + // Play a random sunners video if the script one is not playing already + // and then set a new timer for when the new video should be played + + VideoHandle oldHandle = vm->_video->findVideoHandleRiven(1); + uint32 timerTime = 500; + + if (oldHandle == NULL_VID_HANDLE || vm->_video->endOfVideo(oldHandle)) { + uint32 &sunnerTime = vm->_vars["jsunnertime"]; + + if (sunnerTime == 0) { + timerTime = vm->_rnd->getRandomNumberRng(1, 10) * 1000; + } else if (sunnerTime < vm->getTotalPlayTime()) { + // Randomize the video + int randValue = vm->_rnd->getRandomNumber(5); + uint16 movie = 4; + if (randValue == 4) + movie = 2; + else if (randValue == 5) + movie = 3; + + VideoHandle handle = vm->_video->playMovieRiven(movie); + + timerTime = vm->_video->getDuration(handle) + vm->_rnd->getRandomNumberRng(1, 10) * 1000; + } + + sunnerTime = timerTime + vm->getTotalPlayTime(); + } + + vm->installTimer(&sunnersMidStairsTimer, timerTime); +} + +static void sunnersLowerStairsTimer(MohawkEngine_Riven *vm) { + // If the sunners are gone, we have no video to play + if (vm->_vars["jsunners"] != 0) { + vm->removeTimer(); + return; + } + + // Play a random sunners video if the script one is not playing already + // and then set a new timer for when the new video should be played + + VideoHandle oldHandle = vm->_video->findVideoHandleRiven(1); + uint32 timerTime = 500; + + if (oldHandle == NULL_VID_HANDLE || vm->_video->endOfVideo(oldHandle)) { + uint32 &sunnerTime = vm->_vars["jsunnertime"]; + + if (sunnerTime == 0) { + timerTime = vm->_rnd->getRandomNumberRng(1, 30) * 1000; + } else if (sunnerTime < vm->getTotalPlayTime()) { + VideoHandle handle = vm->_video->playMovieRiven(vm->_rnd->getRandomNumberRng(3, 5)); + + timerTime = vm->_video->getDuration(handle) + vm->_rnd->getRandomNumberRng(1, 30) * 1000; + } + + sunnerTime = timerTime + vm->getTotalPlayTime(); + } + + vm->installTimer(&sunnersLowerStairsTimer, timerTime); +} + +static void sunnersBeachTimer(MohawkEngine_Riven *vm) { + // If the sunners are gone, we have no video to play + if (vm->_vars["jsunners"] != 0) { + vm->removeTimer(); + return; + } + + // Play a random sunners video if the script one is not playing already + // and then set a new timer for when the new video should be played + + VideoHandle oldHandle = vm->_video->findVideoHandleRiven(3); + uint32 timerTime = 500; + + if (oldHandle == NULL_VID_HANDLE || vm->_video->endOfVideo(oldHandle)) { + uint32 &sunnerTime = vm->_vars["jsunnertime"]; + + if (sunnerTime == 0) { + timerTime = vm->_rnd->getRandomNumberRng(1, 30) * 1000; + } else if (sunnerTime < vm->getTotalPlayTime()) { + // Unlike the other cards' scripts which automatically + // activate the MLST, we have to set it manually here. + uint16 mlstID = vm->_rnd->getRandomNumberRng(3, 8); + vm->_video->activateMLST(mlstID, vm->getCurCard()); + VideoHandle handle = vm->_video->playMovieRiven(mlstID); + + timerTime = vm->_video->getDuration(handle) + vm->_rnd->getRandomNumberRng(1, 30) * 1000; + } + + sunnerTime = timerTime + vm->getTotalPlayTime(); + } + + vm->installTimer(&sunnersBeachTimer, timerTime); +} + void MohawkEngine_Riven::installCardTimer() { switch (getCurCardRMAP()) { case 0x3a85: // Top of elevator on prison island @@ -819,16 +956,16 @@ void MohawkEngine_Riven::installCardTimer() { installTimer(&catherineIdleTimer, _rnd->getRandomNumberRng(1, 33) * 1000); break; case 0x77d6: // Sunners, top of stairs - // TODO: Background Sunner videos + installTimer(&sunnersTopStairsTimer, 500); break; case 0x79bd: // Sunners, middle of stairs - // TODO: Background Sunner videos + installTimer(&sunnersMidStairsTimer, 500); break; case 0x7beb: // Sunners, bottom of stairs - // TODO: Background Sunner videos + installTimer(&sunnersLowerStairsTimer, 500); break; case 0xb6ca: // Sunners, shoreline - // TODO: Background Sunner videos + installTimer(&sunnersBeachTimer, 500); break; } } @@ -846,6 +983,34 @@ void MohawkEngine_Riven::doVideoTimer(VideoHandle handle, bool force) { _scriptMan->runStoredMovieOpcode(); } +void MohawkEngine_Riven::checkSunnerAlertClick() { + // We need to do a manual hardcoded check for the sunners' + // alert movies. + + uint32 &sunners = _vars["jsunners"]; + + // If the sunners are gone, there's nothing for us to do + if (sunners != 0) + return; + + uint32 rmapCode = getCurCardRMAP(); + + // This is only for the mid/lower staircase sections + if (rmapCode != 0x79bd && rmapCode != 0x7beb) + return; + + // Only set the sunners variable on the forward hotspot + if ((rmapCode == 0x79bd && _curHotspot != 1) || (rmapCode == 0x7beb && _curHotspot != 2)) + return; + + // If the alert video is no longer playing, we have nothing left to do + VideoHandle handle = _video->findVideoHandleRiven(1); + if (handle == NULL_VID_HANDLE || _video->endOfVideo(handle)) + return; + + sunners = 1; +} + bool ZipMode::operator== (const ZipMode &z) const { return z.name == name && z.id == id; } diff --git a/engines/mohawk/riven.h b/engines/mohawk/riven.h index c7d36e585d..e99a9f78fc 100644 --- a/engines/mohawk/riven.h +++ b/engines/mohawk/riven.h @@ -67,6 +67,13 @@ enum { StackNames = 5 }; +enum RivenTransitionSpeed { + kRivenTransitionSpeedNone = 5000, + kRivenTransitionSpeedFastest = 5001, + kRivenTransitionSpeedNormal = 5002, + kRivenTransitionSpeedBest = 5003 +}; + // Rects for the inventory object positions (initialized in // MohawkEngine_Riven's constructor). extern Common::Rect *g_atrusJournalRect1; @@ -164,6 +171,7 @@ private: // Miscellaneous bool _gameOver; bool _ignoreNextMouseUp; + void checkSunnerAlertClick(); public: // Stack/card/script funtions diff --git a/engines/mohawk/riven_external.cpp b/engines/mohawk/riven_external.cpp index 60e94ea795..9e1365f8da 100644 --- a/engines/mohawk/riven_external.cpp +++ b/engines/mohawk/riven_external.cpp @@ -234,10 +234,10 @@ void RivenExternal::runCredits(uint16 video, uint32 delay) { // Set us up to start after delay ms nextCreditsFrameStart = _vm->_system->getMillis() + delay; } else if (_vm->_system->getMillis() >= nextCreditsFrameStart) { - // the first two frames stay on for 5 seconds + // the first two frames stay on for 4 seconds // the rest of the scroll updates happen at 30Hz if (_vm->_gfx->getCurCreditsImage() < 304) - nextCreditsFrameStart = _vm->_system->getMillis() + 5000; + nextCreditsFrameStart = _vm->_system->getMillis() + 4000; else nextCreditsFrameStart = _vm->_system->getMillis() + 1000 / 30; @@ -1889,21 +1889,42 @@ void RivenExternal::xjplaybeetle_1450(uint16 argc, uint16 *argv) { } void RivenExternal::xjlagoon700_alert(uint16 argc, uint16 *argv) { - // TODO: Sunner related + // Handle sunner reactions (mid-staircase) + + if (_vm->_vars["jsunners"] == 0) + _vm->_video->playMovieRiven(1); } void RivenExternal::xjlagoon800_alert(uint16 argc, uint16 *argv) { - // TODO: Sunner related + // Handle sunner reactions (lower-staircase) + + uint32 &sunners = _vm->_vars["jsunners"]; + + if (sunners == 0) { + // Show the sunners alert video + _vm->_video->playMovieRiven(1); + } else if (sunners == 1) { + // Show the sunners leaving if you moved forward in their "alert" status + _vm->_video->playMovieBlockingRiven(2); + _vm->_video->playMovieBlockingRiven(6); + sunners = 2; + _vm->refreshCard(); + } } void RivenExternal::xjlagoon1500_alert(uint16 argc, uint16 *argv) { - // Have the sunners move a bit as you get closer ;) + // Handle sunner reactions (beach) + uint32 &sunners = _vm->_vars["jsunners"]; + if (sunners == 0) { + // Show the sunners alert video _vm->_video->playMovieBlockingRiven(3); } else if (sunners == 1) { + // Show the sunners leaving if you moved forward in their "alert" status _vm->_video->playMovieBlockingRiven(2); sunners = 2; + _vm->refreshCard(); } } @@ -2726,6 +2747,7 @@ void RivenExternal::xtatboundary(uint16 argc, uint16 *argv) { void RivenExternal::xflies(uint16 argc, uint16 *argv) { // TODO: Activate the "flies" effect + debug(1, "STUB: xflies(): create %d %s fl%s", argv[1], (argv[0] == 0) ? "black" : "glowing", (argv[1] == 1) ? "y" : "ies"); } } // End of namespace Mohawk diff --git a/engines/mohawk/riven_vars.cpp b/engines/mohawk/riven_vars.cpp index 946e2e0496..ba5c343e07 100644 --- a/engines/mohawk/riven_vars.cpp +++ b/engines/mohawk/riven_vars.cpp @@ -268,7 +268,12 @@ static const char *variableNames[] = { }; uint32 &MohawkEngine_Riven::getStackVar(uint32 index) { - return _vars[getName(VariableNames, index)]; + Common::String name = getName(VariableNames, index); + + if (!_vars.contains(name)) + error("Could not find variable '%s' (stack variable %d)", name.c_str(), index); + + return _vars[name]; } void MohawkEngine_Riven::initVars() { @@ -299,6 +304,7 @@ void MohawkEngine_Riven::initVars() { _vars["bmagcar"] = 1; _vars["gnmagcar"] = 1; _vars["omusicplayer"] = 1; + _vars["transitionmode"] = kRivenTransitionSpeedFastest; // Randomize the telescope combination uint32 &teleCombo = _vars["tcorrectorder"]; diff --git a/engines/mohawk/sound.cpp b/engines/mohawk/sound.cpp index 68b60515be..f92bebf10e 100644 --- a/engines/mohawk/sound.cpp +++ b/engines/mohawk/sound.cpp @@ -85,7 +85,7 @@ Audio::AudioStream *Sound::makeAudioStream(uint16 id, CueList *cueList) { if (_vm->getFeatures() & GF_ME) audStream = Audio::makeWAVStream(_vm->getResource(ID_MSND, convertMystID(id)), DisposeAfterUse::YES); else - audStream = makeMohawkWaveStream(_vm->getResource(ID_MSND, id)); + audStream = makeMohawkWaveStream(_vm->getResource(ID_MSND, id), cueList); break; case GType_ZOOMBINI: audStream = makeMohawkWaveStream(_vm->getResource(ID_SND, id)); diff --git a/engines/saga/detection_tables.h b/engines/saga/detection_tables.h index a29d835a54..3e83c30eef 100644 --- a/engines/saga/detection_tables.h +++ b/engines/saga/detection_tables.h @@ -328,7 +328,7 @@ static const SAGAGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformMacintosh, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_ITE, @@ -352,7 +352,7 @@ static const SAGAGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformMacintosh, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_ITE, @@ -384,7 +384,7 @@ static const SAGAGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformUnknown, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_ITE, @@ -414,7 +414,7 @@ static const SAGAGameDescription gameDescriptions[] = { }, Common::IT_ITA, Common::kPlatformUnknown, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_ITE, @@ -438,7 +438,7 @@ static const SAGAGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_ITE, @@ -462,7 +462,7 @@ static const SAGAGameDescription gameDescriptions[] = { }, Common::IT_ITA, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_ITE, @@ -486,7 +486,7 @@ static const SAGAGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_ITE, @@ -511,7 +511,7 @@ static const SAGAGameDescription gameDescriptions[] = { }, Common::DE_DEU, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_ITE, diff --git a/engines/scumm/cursor.cpp b/engines/scumm/cursor.cpp index a8adb4d5c5..29b5eaedcb 100644 --- a/engines/scumm/cursor.cpp +++ b/engines/scumm/cursor.cpp @@ -22,6 +22,9 @@ #include "common/system.h" #include "common/util.h" #include "graphics/cursorman.h" +#ifdef ENABLE_HE +#include "graphics/wincursor.h" +#endif #include "scumm/bomp.h" #include "scumm/charset.h" #include "scumm/he/intern_he.h" @@ -177,12 +180,8 @@ void ScummEngine_v70he::setDefaultCursor() { 0xff, 0xff, 0xff, 0, 0, 0, }; - if (_bytesPerPixel == 2) { - for (i = 0; i < 1024; i++) - WRITE_UINT16(_grabbedCursor + i * 2, 5); - } else { - memset(_grabbedCursor, 5, sizeof(_grabbedCursor)); - } + + memset(_grabbedCursor, 5, sizeof(_grabbedCursor)); _cursor.hotspotX = _cursor.hotspotY = 2; src = default_he_cursor; @@ -195,16 +194,10 @@ void ScummEngine_v70he::setDefaultCursor() { for (j = 0; j < 32; j++) { switch ((p & (0x3 << 14)) >> 14) { case 1: - if (_bytesPerPixel == 2) - WRITE_UINT16(_grabbedCursor + 64 * i + j * 2, get16BitColor(palette[4], palette[5], palette[6])); - else - _grabbedCursor[32 * i + j] = 0xfe; + _grabbedCursor[32 * i + j] = 0xfe; break; case 2: - if (_bytesPerPixel == 2) - WRITE_UINT16(_grabbedCursor + 64 * i + j * 2, get16BitColor(palette[0], palette[1], palette[2])); - else - _grabbedCursor[32 * i + j] = 0xfd; + _grabbedCursor[32 * i + j] = 0xfd; break; default: break; @@ -216,15 +209,61 @@ void ScummEngine_v70he::setDefaultCursor() { } } - if (_bytesPerPixel == 1) { - // Since white color position is not guaranteed - // we setup our own palette if supported by backend - CursorMan.disableCursorPalette(false); - CursorMan.replaceCursorPalette(palette, 0xfd, 3); + // Since white color position is not guaranteed + // we setup our own palette if supported by backend + CursorMan.disableCursorPalette(false); + CursorMan.replaceCursorPalette(palette, 0xfd, 3); + + updateCursor(); +} + +#ifdef ENABLE_HE +void ScummEngine_v80he::setDefaultCursor() { + // v80+ games use the default Windows cursor instead of the usual + // default HE cursor. + Graphics::Cursor *cursor = Graphics::makeDefaultWinCursor(); + + // Clear the cursor + if (_bytesPerPixel == 2) { + for (int i = 0; i < 1024; i++) + WRITE_UINT16(_grabbedCursor + i * 2, 5); + } else { + memset(_grabbedCursor, 5, sizeof(_grabbedCursor)); } + _cursor.width = cursor->getWidth(); + _cursor.height = cursor->getHeight(); + _cursor.hotspotX = cursor->getHotspotX(); + _cursor.hotspotY = cursor->getHotspotY(); + + const byte *surface = cursor->getSurface(); + const byte *palette = cursor->getPalette(); + + for (uint16 y = 0; y < _cursor.height; y++) { + for (uint16 x = 0; x < _cursor.width; x++) { + byte pixel = *surface++; + + if (pixel != cursor->getKeyColor()) { + pixel -= cursor->getPaletteStartIndex(); + + if (_bytesPerPixel == 2) + WRITE_UINT16(_grabbedCursor + (y * _cursor.width + x) * 2, get16BitColor(palette[pixel * 3], palette[pixel * 3 + 1], palette[pixel * 3 + 2])); + else + _grabbedCursor[y * _cursor.width + x] = (pixel == 0) ? 0xfd : 0xfe; + } + } + } + + delete cursor; + + // Since white color position is not guaranteed + // we setup our own palette if supported by backend + CursorMan.disableCursorPalette(false); + CursorMan.replaceCursorPalette(palette, 0xfd, cursor->getPaletteCount() * 3); + updateCursor(); } +#endif void ScummEngine_v6::setCursorFromImg(uint img, uint room, uint imgindex) { int w, h; diff --git a/engines/scumm/he/intern_he.h b/engines/scumm/he/intern_he.h index c49217b650..f4df6571fa 100644 --- a/engines/scumm/he/intern_he.h +++ b/engines/scumm/he/intern_he.h @@ -383,6 +383,8 @@ protected: void drawLine(int x1, int y1, int x, int unk1, int unk2, int type, int id); void drawPixel(int x, int y, int flags); + virtual void setDefaultCursor(); + /* HE version 80 script opcodes */ void o80_createSound(); void o80_getFileSize(); diff --git a/engines/scumm/he/logic/basketball.cpp b/engines/scumm/he/logic/basketball.cpp index 0a2f99aa90..8352aa4357 100644 --- a/engines/scumm/he/logic/basketball.cpp +++ b/engines/scumm/he/logic/basketball.cpp @@ -35,6 +35,28 @@ public: int versionID(); int32 dispatch(int op, int numArgs, int32 *args); + +private: + int op_1012(); + int op_1050(int32 *args); + int op_1053(); + + // op_1050 loads court object data + enum CourtObjectType { + kObjectTypeBackboard = 1, + kObjectTypeRim = 2, + kObjectTypeOther = 3, + kObjectTypeFloor = 4 + }; + + struct CourtObject { + Common::String name; + CourtObjectType type; + uint32 data[10]; + }; + + Common::Array<CourtObject> _courtObjects; + uint32 _backboardObjectLeft, _backboardObjectRight; }; int LogicHEbasketball::versionID() { @@ -55,12 +77,14 @@ int32 LogicHEbasketball::dispatch(int op, int numArgs, int32 *args) { break; case 1012: + res = op_1012(); break; case 1035: break; case 1050: + res = op_1050(args); break; case 1051: @@ -69,6 +93,10 @@ int32 LogicHEbasketball::dispatch(int op, int numArgs, int32 *args) { case 1052: break; + case 1053: + res = op_1053(); + break; + case 1056: break; @@ -118,6 +146,83 @@ int32 LogicHEbasketball::dispatch(int op, int numArgs, int32 *args) { return res; } +int LogicHEbasketball::op_1012() { + writeScummVar(108, 12000); + writeScummVar(109, 8000); + writeScummVar(110, 760); + writeScummVar(111, 4000); + writeScummVar(112, 1600); + return 1; +} + +int LogicHEbasketball::op_1050(int32 *args) { + // This function loads the court data + static const char *courtNames[] = { + "Dobbaguchi", "Jocindas", "SandyFlats", "Queens", + "Park", "Scheffler", "Polk", "McMillan", + "CrownHill", "Memorial", "TechState", "Garden", + "Moon", "Barn" + }; + + Common::String courtFileName = Common::String::format("data/courts/%s.cof", courtNames[args[0] - 1]); + + Common::File file; + if (!file.open(courtFileName)) + error("Could not open file '%s'", courtFileName.c_str()); + + debug(0, "Loading court data from '%s'", courtFileName.c_str()); + + // First, read in the header + file.readUint32LE(); // Header size (?) + + char version[6]; + file.read(version, 5); + version[5] = 0; + + if (strcmp(version, "01.05")) + error("Invalid court version field: %s", version); + + uint32 objectCount = file.readUint32LE(); + + for (uint32 i = 0; i < objectCount; i++) { + char nameBuf[100]; + memset(nameBuf, 0, sizeof(nameBuf)); + + uint32 nameLength = file.readUint32LE(); + assert(nameLength < sizeof(nameBuf) - 1); + file.read(nameBuf, nameLength); + + CourtObject object; + object.name = nameBuf; + object.type = (CourtObjectType)file.readUint32LE(); + for (uint32 j = 0; j < 10; j++) + object.data[j] = file.readUint32LE(); + + debug(1, "Found court object '%s' - Type %d", nameBuf, object.type); + + // Store backboard object indices for later + if (object.type == kObjectTypeBackboard) { + if (object.data[7] + object.data[4] / 2 >= 6000) + _backboardObjectRight = i; + else + _backboardObjectLeft = i; + } + + _courtObjects.push_back(object); + } + + // TODO: Some other variables are initialized with constants here + + return 1; +} + +int LogicHEbasketball::op_1053() { + _courtObjects.clear(); + // TODO: This also calls op_1065 with one argument (5) + + return 1; +} + LogicHE *makeLogicHEbasketball(ScummEngine_v90he *vm) { return new LogicHEbasketball(vm); } diff --git a/engines/scumm/player_v2cms.cpp b/engines/scumm/player_v2cms.cpp index d16f9d2be7..d4b21774ed 100644 --- a/engines/scumm/player_v2cms.cpp +++ b/engines/scumm/player_v2cms.cpp @@ -36,6 +36,10 @@ Player_V2CMS::Player_V2CMS(ScummEngine *scumm, Audio::Mixer *mixer) _outputTableReady(0), _midiChannel(), _midiChannelUse() { setMusicVolume(255); + memset(_sfxFreq, 0xFF, sizeof(_sfxFreq)); + memset(_sfxAmpl, 0x00, sizeof(_sfxAmpl)); + memset(_sfxOctave, 0x66, sizeof(_sfxOctave)); + _cmsVoices[0].amplitudeOutput = &_cmsChips[0].ampl[0]; _cmsVoices[0].freqOutput = &_cmsChips[0].freq[0]; _cmsVoices[0].octaveOutput = &_cmsChips[0].octave[0]; @@ -596,7 +600,6 @@ void Player_V2CMS::play() { _octaveMask = 0xF0; channel_data *chan = &_channels[0].d; - MusicChip &cms = _cmsChips[0]; byte noiseGen = 3; for (int i = 1; i <= 4; ++i) { @@ -608,8 +611,8 @@ void Player_V2CMS::play() { noiseGen = freq & 0xFF; } else { noiseGen = 3; - cms.freq[0] = cms.freq[3]; - cms.octave[0] = (cms.octave[0] & 0xF0) | ((cms.octave[1] & 0xF0) >> 4); + _sfxFreq[0] = _sfxFreq[3]; + _sfxOctave[0] = (_sfxOctave[0] & 0xF0) | ((_sfxOctave[1] & 0xF0) >> 4); } } else { if (freq == 0) { @@ -635,15 +638,15 @@ void Player_V2CMS::play() { oct |= cmsOct; oct &= _octaveMask; - oct |= (~_octaveMask) & cms.octave[(i & 3) >> 1]; - cms.octave[(i & 3) >> 1] = oct; + oct |= (~_octaveMask) & _sfxOctave[(i & 3) >> 1]; + _sfxOctave[(i & 3) >> 1] = oct; freq >>= -(cmsOct - 9); - cms.freq[i & 3] = (-(freq - 511)) & 0xFF; + _sfxFreq[i & 3] = (-(freq - 511)) & 0xFF; } - cms.ampl[i & 3] = _volumeTable[chan->volume >> 12]; + _sfxAmpl[i & 3] = _volumeTable[chan->volume >> 12]; } else { - cms.ampl[i & 3] = 0; + _sfxAmpl[i & 3] = 0; } chan = &_channels[i].d; @@ -654,25 +657,25 @@ void Player_V2CMS::play() { // the right channels amplitude is set // with the low value the left channels amplitude _cmsEmu->portWrite(0x221, 0); - _cmsEmu->portWrite(0x220, cms.ampl[0]); + _cmsEmu->portWrite(0x220, _sfxAmpl[0]); _cmsEmu->portWrite(0x221, 1); - _cmsEmu->portWrite(0x220, cms.ampl[1]); + _cmsEmu->portWrite(0x220, _sfxAmpl[1]); _cmsEmu->portWrite(0x221, 2); - _cmsEmu->portWrite(0x220, cms.ampl[2]); + _cmsEmu->portWrite(0x220, _sfxAmpl[2]); _cmsEmu->portWrite(0x221, 3); - _cmsEmu->portWrite(0x220, cms.ampl[3]); + _cmsEmu->portWrite(0x220, _sfxAmpl[3]); _cmsEmu->portWrite(0x221, 8); - _cmsEmu->portWrite(0x220, cms.freq[0]); + _cmsEmu->portWrite(0x220, _sfxFreq[0]); _cmsEmu->portWrite(0x221, 9); - _cmsEmu->portWrite(0x220, cms.freq[1]); + _cmsEmu->portWrite(0x220, _sfxFreq[1]); _cmsEmu->portWrite(0x221, 10); - _cmsEmu->portWrite(0x220, cms.freq[2]); + _cmsEmu->portWrite(0x220, _sfxFreq[2]); _cmsEmu->portWrite(0x221, 11); - _cmsEmu->portWrite(0x220, cms.freq[3]); + _cmsEmu->portWrite(0x220, _sfxFreq[3]); _cmsEmu->portWrite(0x221, 0x10); - _cmsEmu->portWrite(0x220, cms.octave[0]); + _cmsEmu->portWrite(0x220, _sfxOctave[0]); _cmsEmu->portWrite(0x221, 0x11); - _cmsEmu->portWrite(0x220, cms.octave[1]); + _cmsEmu->portWrite(0x220, _sfxOctave[1]); _cmsEmu->portWrite(0x221, 0x14); _cmsEmu->portWrite(0x220, 0x3E); _cmsEmu->portWrite(0x221, 0x15); diff --git a/engines/scumm/player_v2cms.h b/engines/scumm/player_v2cms.h index cbad46fe5d..905c7c141e 100644 --- a/engines/scumm/player_v2cms.h +++ b/engines/scumm/player_v2cms.h @@ -50,7 +50,6 @@ public: virtual bool isStereo() const { return true; } private: -#include "common/pack-start.h" // START STRUCT PACKING struct Voice { byte attack; byte decay; @@ -60,7 +59,7 @@ private: int16 vibrato; int16 vibrato2; int16 noise; - } PACKED_STRUCT; + }; struct Voice2 { byte *amplitudeOutput; @@ -105,14 +104,13 @@ private: Voice2 *nextVoice; byte chanNumber; - } PACKED_STRUCT; + }; struct MusicChip { byte ampl[4]; byte freq[4]; byte octave[2]; - } PACKED_STRUCT; -#include "common/pack-end.h" // END STRUCT PACKING + }; Voice _cmsVoicesBase[16]; Voice2 _cmsVoices[8]; @@ -130,6 +128,8 @@ private: int _loadedMidiSong; + byte _sfxFreq[4], _sfxAmpl[4], _sfxOctave[2]; + byte _lastMidiCommand; uint _outputTableReady; byte _voiceTimer; diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp index 50ae045052..5aded50600 100644 --- a/engines/scumm/sound.cpp +++ b/engines/scumm/sound.cpp @@ -1157,7 +1157,9 @@ int ScummEngine::readSoundResource(ResId idx) { // only contains a ROL resource for sound id 60. Formerly we tried // to play that via the AdLib or FM-Towns audio driver resulting // in strange noises. Now we behave like the original did. - if ((_sound->_musicType == MDT_ADLIB || _sound->_musicType == MDT_TOWNS) && pri != 10) + // We make an exception for priority 2 for the Mac output since + // we're doing GM -> AdLib conversion. + if ((_sound->_musicType == MDT_ADLIB || _sound->_musicType == MDT_TOWNS) && pri != 10 && pri != 2) pri = -1; debugC(DEBUG_RESOURCE, " tag: %s, total_size=%d, pri=%d", tag2str(tag), size, pri); diff --git a/engines/tinsel/detection_tables.h b/engines/tinsel/detection_tables.h index 116322aa89..bea0938fad 100644 --- a/engines/tinsel/detection_tables.h +++ b/engines/tinsel/detection_tables.h @@ -214,7 +214,7 @@ static const TinselGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_DW1, @@ -236,7 +236,7 @@ static const TinselGameDescription gameDescriptions[] = { }, Common::IT_ITA, Common::kPlatformPC, - ADGF_DROPLANGUAGE, + ADGF_DROPLANGUAGE | ADGF_CD, GUIO_NONE }, GID_DW1, @@ -261,7 +261,7 @@ static const TinselGameDescription gameDescriptions[] = { }, Common::FR_FRA, Common::kPlatformPC, - ADGF_DROPLANGUAGE, + ADGF_DROPLANGUAGE | ADGF_CD, GUIO_NONE }, GID_DW1, @@ -285,7 +285,7 @@ static const TinselGameDescription gameDescriptions[] = { }, Common::DE_DEU, Common::kPlatformPC, - ADGF_DROPLANGUAGE, + ADGF_DROPLANGUAGE | ADGF_CD, GUIO_NONE }, GID_DW1, @@ -308,7 +308,7 @@ static const TinselGameDescription gameDescriptions[] = { }, Common::IT_ITA, Common::kPlatformPC, - ADGF_DROPLANGUAGE, + ADGF_DROPLANGUAGE | ADGF_CD, GUIO_NONE }, GID_DW1, @@ -331,7 +331,7 @@ static const TinselGameDescription gameDescriptions[] = { }, Common::ES_ESP, Common::kPlatformPC, - ADGF_DROPLANGUAGE, + ADGF_DROPLANGUAGE | ADGF_CD, GUIO_NONE }, GID_DW1, @@ -351,7 +351,7 @@ static const TinselGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_DW1, @@ -371,7 +371,7 @@ static const TinselGameDescription gameDescriptions[] = { }, Common::HE_ISR, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_DW1, @@ -390,7 +390,7 @@ static const TinselGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformPSX, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_DW1, @@ -434,7 +434,7 @@ static const TinselGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_DW1, @@ -456,7 +456,7 @@ static const TinselGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformMacintosh, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_DW1, @@ -475,7 +475,7 @@ static const TinselGameDescription gameDescriptions[] = { AD_ENTRY1s("dw.scn", "6182c7986eaec893c62fb6ea13a9f225", 774556), Common::DE_DEU, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_DW1, @@ -496,7 +496,7 @@ static const TinselGameDescription gameDescriptions[] = { }, Common::RU_RUS, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_DW1, diff --git a/engines/toon/path.cpp b/engines/toon/path.cpp index 785b84a78e..60ca007930 100644 --- a/engines/toon/path.cpp +++ b/engines/toon/path.cpp @@ -33,15 +33,15 @@ PathFindingHeap::PathFindingHeap() { } PathFindingHeap::~PathFindingHeap() { - delete[] _data; + free(_data); } void PathFindingHeap::init(int32 size) { debugC(1, kDebugPath, "init(%d)", size); _size = size; - delete[] _data; - _data = new HeapDataGrid[_size]; + free(_data); + _data = (HeapDataGrid *)malloc(sizeof(HeapDataGrid) * _size); memset(_data, 0, sizeof(HeapDataGrid) * _size); _count = 0; } @@ -49,7 +49,7 @@ void PathFindingHeap::init(int32 size) { void PathFindingHeap::unload() { _count = 0; _size = 0; - delete[] _data; + free(_data); _data = NULL; } @@ -64,8 +64,19 @@ void PathFindingHeap::push(int32 x, int32 y, int32 weight) { debugC(2, kDebugPath, "push(%d, %d, %d)", x, y, weight); if (_count == _size) { - warning("Aborting attempt to push onto PathFindingHeap at maximum size: %d", _count); - return; + // Increase size by 50% + int newSize = _size + (_size >> 1) + 1; + HeapDataGrid *newData; + + newData = (HeapDataGrid *)realloc(_data, sizeof(HeapDataGrid) * newSize); + if (newData == NULL) { + warning("Aborting attempt to push onto PathFindingHeap at maximum size: %d", _count); + return; + } + + memset(newData + _size, 0, sizeof(HeapDataGrid) * (newSize - _size)); + _data = newData; + _size = newSize; } _data[_count]._x = x; @@ -427,11 +438,7 @@ void PathFinding::init(Picture *mask) { _height = mask->getHeight(); _currentMask = mask; _heap->unload(); - // In order to reduce memory fragmentation on small devices, we use the maximum - // possible size here which is TOON_BACKBUFFER_WIDTH. Even though this is - // 1280 as opposed to the possible 640, it actually helps memory allocation on - // those devices. - _heap->init(TOON_BACKBUFFER_WIDTH * _height); // should really be _width + _heap->init(500); delete[] _gridTemp; _gridTemp = new int32[_width*_height]; } diff --git a/engines/tsage/blue_force/blueforce_logic.cpp b/engines/tsage/blue_force/blueforce_logic.cpp new file mode 100644 index 0000000000..ec85e48fbf --- /dev/null +++ b/engines/tsage/blue_force/blueforce_logic.cpp @@ -0,0 +1,255 @@ +/* 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 "tsage/blue_force/blueforce_logic.h" +#include "tsage/blue_force/blueforce_scenes0.h" +#include "tsage/blue_force/blueforce_scenes1.h" +#include "tsage/scenes.h" +#include "tsage/tsage.h" +#include "tsage/staticres.h" + +namespace TsAGE { + +namespace BlueForce { + +void BlueForceGame::start() { + // Start the game + _globals->_sceneManager.changeScene(100); + + _globals->_events.setCursor(CURSOR_WALK); +} + +Scene *BlueForceGame::createScene(int sceneNumber) { + switch (sceneNumber) { + /* Scene Group #0 */ + case 20: + // Tsunami Title Screen + return new Scene20(); + case 50: + case 60: + error("Scene group 0 not implemented"); + /* Scene Group #1 */ + case 100: + // Tsnunami Title Screen #2 + return new Scene100(); + case 109: + // Introduction Bar Room + return new Scene109(); + case 110: + case 114: + case 115: + case 125: + case 140: + case 150: + case 160: + case 180: + case 190: + error("Scene group 1 not implemented"); + case 200: + case 210: + case 220: + case 225: + case 265: + case 270: + case 271: + case 280: + error("Scene group 2 not implemented"); + case 300: + case 315: + case 325: + case 330: + case 340: + case 342: + case 350: + case 355: + case 360: + case 370: + case 380: + case 385: + case 390: + error("Scene group 3 not implemented"); + case 410: + case 415: + case 440: + case 450: + error("Scene group 4 not implemented"); + case 550: + case 551: + case 560: + case 570: + case 580: + case 590: + error("Scene group 5 not implemented"); + case 600: + case 620: + case 666: + case 690: + error("Scene group 6 not implemented"); + case 710: + error("Scene group 7 not implemented"); + case 800: + case 810: + case 820: + case 830: + case 840: + case 850: + case 860: + case 870: + case 880: + error("Scene group 8 not implemented"); + case 900: + case 910: + case 920: + case 930: + case 935: + case 940: + error("Scene group 9 not implemented"); + default: + error("Unknown scene number - %d", sceneNumber); + break; + } +} + +/*--------------------------------------------------------------------------*/ + +ObjArray::ObjArray(): EventHandler() { + _inUse = false; + clear(); +} + +void ObjArray::clear() { + for (int i = 0; i < OBJ_ARRAY_SIZE; ++i) + _objList[i] = NULL; +} + +void ObjArray::synchronize(Serializer &s) { + EventHandler::synchronize(s); + for (int i = 0; i < OBJ_ARRAY_SIZE; ++i) + SYNC_POINTER(_objList[i]); +} + +void ObjArray::process(Event &event) { + if (_inUse) + error("Array error"); + _inUse = true; + + for (int i = 0; i < OBJ_ARRAY_SIZE; ++i) { + if (_objList[i]) + _objList[i]->process(event); + } + + _inUse = false; +} + +void ObjArray::dispatch() { + if (_inUse) + error("Array error"); + _inUse = true; + + for (int i = 0; i < OBJ_ARRAY_SIZE; ++i) { + if (_objList[i]) + _objList[i]->dispatch(); + } + + _inUse = false; +} + +/*--------------------------------------------------------------------------*/ + +SceneExt::SceneExt(): Scene() { + warning("TODO: dword_503AA/dword_503AE/dword_53030"); + + _field372 = 0; + _field37C = NULL; +} + +void SceneExt::postInit(SceneObjectList *OwnerList) { + Scene::postInit(OwnerList); + if (BF_GLOBALS._v4CEA2) { + // Blank out the bottom portion of the screen + BF_GLOBALS._interfaceY = BF_INTERFACE_Y; + + Rect r(0, BF_INTERFACE_Y, SCREEN_WIDTH, SCREEN_HEIGHT); + BF_GLOBALS.gfxManager().getSurface().fillRect(r, 0); + } +} + +void SceneExt::process(Event &event) { + _objArray2.process(event); + if (!event.handled) + Scene::process(event); +} + +void SceneExt::dispatch() { + _objArray1.dispatch(); + + if (_field37A) { + if ((--_field37A == 0) && BF_GLOBALS._v4CEA2) { + if (BF_GLOBALS._v4E238 && (BF_GLOBALS._v4CF9E == 1)) { + warning("sub_1B052"); + } + + _field37A = 0; + } + } + + Scene::dispatch(); +} + +void SceneExt::loadScene(int sceneNum) { + Scene::loadScene(sceneNum); + + _v51C34.top = 0; + _v51C34.bottom = 300; +} + +/*--------------------------------------------------------------------------*/ + +GameScene::GameScene() { + +} + +void GameScene::postInit(SceneObjectList *OwnerList) { + _field794 = 0; + _field412 = 1; + SceneExt::postInit(OwnerList); +} + +void GameScene::remove() { + SceneExt::remove(); + if (_field794 == 1) { + for (SynchronizedList<SceneObject *>::iterator i = BF_GLOBALS._sceneObjects->begin(); + i != BF_GLOBALS._sceneObjects->end(); ++i) + (*i)->remove(); + + BF_GLOBALS._sceneObjects->draw(); + BF_GLOBALS._scenePalette.loadPalette(2); + BF_GLOBALS._v51C44 = 1; + BF_GLOBALS._v51C42 = 1; + } + + BF_GLOBALS._scenePalette._field412 = 1; +} + +} // End of namespace BlueForce + +} // End of namespace TsAGE diff --git a/engines/tsage/blueforce_logic.h b/engines/tsage/blue_force/blueforce_logic.h index 9237e50a13..1ff6ecf507 100644 --- a/engines/tsage/blueforce_logic.h +++ b/engines/tsage/blue_force/blueforce_logic.h @@ -29,7 +29,13 @@ #include "tsage/scenes.h" #include "tsage/globals.h" -namespace tSage { +#define BF_INTERFACE_Y 168 + +namespace TsAGE { + +namespace BlueForce { + +using namespace TsAGE; class BlueForceGame: public Game { public: @@ -37,6 +43,57 @@ public: virtual Scene *createScene(int sceneNumber); }; -} // End of namespace tSage +#define OBJ_ARRAY_SIZE 10 +class ObjArray: public EventHandler { +public: + EventHandler *_objList[OBJ_ARRAY_SIZE]; + bool _inUse; +public: + ObjArray(); + void clear(); + + virtual Common::String getClassName() { return "ObjArray"; } + virtual void synchronize(Serializer &s); + virtual void process(Event &event); + virtual void dispatch(); +}; + +class SceneExt: public Scene { +public: + ObjArray _objArray1, _objArray2; + int _field372; + int _field37A; + EventHandler *_field37C; + + Rect _v51C34; +public: + SceneExt(); + + virtual Common::String getClassName() { return "SceneExt"; } + virtual void postInit(SceneObjectList *OwnerList = NULL); + virtual void process(Event &event); + virtual void dispatch(); + virtual void loadScene(int sceneNum); + virtual void proc13() { warning("TODO: SceneExt::proc13"); } +}; + +class GameScene: public SceneExt { +public: + int _field412; + int _field794; +public: + GameScene(); + + virtual void postInit(SceneObjectList *OwnerList = NULL); + virtual void remove(); +}; + +class BlueAnimatedSpeaker: public Speaker { +public: +}; + +} // End of namespace BlueForce + +} // End of namespace TsAGE #endif diff --git a/engines/tsage/blueforce_scenes0.cpp b/engines/tsage/blue_force/blueforce_scenes0.cpp index 4a0259cb98..cc0f9bb1fd 100644 --- a/engines/tsage/blueforce_scenes0.cpp +++ b/engines/tsage/blue_force/blueforce_scenes0.cpp @@ -20,20 +20,22 @@ * */ -#include "tsage/blueforce_scenes0.h" +#include "tsage/blue_force/blueforce_scenes0.h" #include "tsage/scenes.h" #include "tsage/tsage.h" #include "tsage/staticres.h" -namespace tSage { +namespace TsAGE { + +namespace BlueForce { /*-------------------------------------------------------------------------- * Scene 20 - Tsunami Title Screen * *--------------------------------------------------------------------------*/ -void BF_Scene20::Action1::signal() { - BF_Scene20 *scene = (BF_Scene20 *)_globals->_sceneManager._scene; +void Scene20::Action1::signal() { + Scene20 *scene = (Scene20 *)BF_GLOBALS._sceneManager._scene; static byte black[3] = { 0, 0, 0 }; switch (_actionIndex++) { @@ -42,7 +44,7 @@ void BF_Scene20::Action1::signal() { break; case 1: _sound.play(1); - _globals->_scenePalette.addRotation(64, 127, -1, 1, this); + BF_GLOBALS._scenePalette.addRotation(64, 127, -1, 1, this); break; case 2: scene->_object1.setVisage(22); @@ -88,7 +90,7 @@ void BF_Scene20::Action1::signal() { setDelay(1); break; case 3: - _globals->_scenePalette.addFader(scene->_scenePalette._palette, 256, 8, this); + BF_GLOBALS._scenePalette.addFader(scene->_scenePalette._palette, 256, 8, this); break; case 4: setDelay(60); @@ -105,10 +107,10 @@ void BF_Scene20::Action1::signal() { setDelay(120); break; case 7: - _globals->_scenePalette.addFader(black, 1, 5, this); + BF_GLOBALS._scenePalette.addFader(black, 1, 5, this); break; case 8: - _globals->_sceneManager.changeScene(100); + BF_GLOBALS._sceneManager.changeScene(100); remove(); break; } @@ -116,13 +118,11 @@ void BF_Scene20::Action1::signal() { /*--------------------------------------------------------------------------*/ -void BF_Scene20::postInit(SceneObjectList *OwnerList) { +void Scene20::postInit(SceneObjectList *OwnerList) { loadScene(20); Scene::postInit(); setZoomPercents(60, 85, 200, 100); - preloadVisage(21); - preloadVisage(22); _scenePalette.loadPalette(1); _scenePalette.loadPalette(22); @@ -193,4 +193,52 @@ void BF_Scene20::postInit(SceneObjectList *OwnerList) { setAction(&_action1); } -} // End of namespace tSage +/*-------------------------------------------------------------------------- + * Scene 50 - Map Screen + * + *--------------------------------------------------------------------------*/ + +Scene50::Tooltip::Tooltip(): SavedObject() { + strcpy(_msg, ""); + _field60 = _field62 = 0; +} + +void Scene50::Tooltip::synchronize(Serializer &s) { + SavedObject::synchronize(s); + _bounds.synchronize(s); + s.syncBytes((byte *)&_msg[0], 84); +} + +void Scene50::Tooltip2::signal() { + switch (_actionIndex++) { + case 0: + setDelay(60); + break; + case 1: { + Common::Point pt(410, 181); + NpcMover *mover = new NpcMover(); + ((SceneObject *)_owner)->addMover(mover, &pt, this); + break; + } + case 2: + _owner->remove(); + break; + default: + break; + } +} + +void Scene50::Tooltip2::dispatch() { + Action::dispatch(); + SceneObject *owner = (SceneObject *)_owner; + + if ((_actionIndex == 2) && (owner->_percent < 100)) { + owner->changeZoom(owner->_percent + 1); + } +} + +/*--------------------------------------------------------------------------*/ + +} // End of namespace BlueForce + +} // End of namespace TsAGE diff --git a/engines/tsage/blueforce_scenes0.h b/engines/tsage/blue_force/blueforce_scenes0.h index 06f7912959..587941e59e 100644 --- a/engines/tsage/blueforce_scenes0.h +++ b/engines/tsage/blue_force/blueforce_scenes0.h @@ -24,7 +24,7 @@ #define TSAGE_BLUEFORCE_SCENES0_H #include "common/scummsys.h" -#include "tsage/blueforce_logic.h" +#include "tsage/blue_force/blueforce_logic.h" #include "tsage/converse.h" #include "tsage/events.h" #include "tsage/core.h" @@ -32,9 +32,13 @@ #include "tsage/globals.h" #include "tsage/sound.h" -namespace tSage { +namespace TsAGE { -class BF_Scene20 : public Scene { +namespace BlueForce { + +using namespace TsAGE; + +class Scene20 : public SceneExt { /* Actions */ class Action1 : public Action { private: @@ -51,6 +55,33 @@ public: virtual void postInit(SceneObjectList *OwnerList = NULL); }; -} // End of namespace tSage +class Scene50: public SceneExt { + class Tooltip: public SavedObject { + public: + Rect _bounds; + char _msg[80]; + int _field60; + int _field62; + public: + Tooltip(); + + virtual Common::String getClassName() { return "Scene50_Tooltip"; } + virtual void synchronize(Serializer &s); + }; + class Tooltip2: public Action { + public: + Tooltip2(): Action() {} + + virtual Common::String getClassName() { return "Scene50_Tooltip2"; } + virtual void signal(); + virtual void dispatch(); + }; +public: + +}; + +} // End of namespace BlueForce + +} // End of namespace TsAGE #endif diff --git a/engines/tsage/blue_force/blueforce_scenes1.cpp b/engines/tsage/blue_force/blueforce_scenes1.cpp new file mode 100644 index 0000000000..650b63c24b --- /dev/null +++ b/engines/tsage/blue_force/blueforce_scenes1.cpp @@ -0,0 +1,432 @@ +/* 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 "common/config-manager.h" +#include "tsage/blue_force/blueforce_scenes1.h" +#include "tsage/scenes.h" +#include "tsage/tsage.h" +#include "tsage/staticres.h" +#include "tsage/globals.h" + +namespace TsAGE { + +namespace BlueForce { + +/*-------------------------------------------------------------------------- + * Scene 100 - Tsunami Title Screen #2 + * + *--------------------------------------------------------------------------*/ + +void Scene100::Text::dispatch() { + SceneText::dispatch(); + + // Keep the second text string below the first one + Scene100 *scene = (Scene100 *)BF_GLOBALS._sceneManager._scene; + Common::Point &pt = scene->_action1._sceneText1._position; + scene->_action1._sceneText2.setPosition(Common::Point(pt.x, + pt.y + scene->_action1._textHeight)); +} + + +void Scene100::Action1::signal() { + static byte black[3] = { 0, 0, 0 }; + + switch (_actionIndex++) { + case 0: + _state = 0; + setDelay(6); + break; + case 1: { + Common::String msg1 = _resourceManager->getMessage(100, _state++); + if (msg1.compareTo("LASTCREDIT")) { + Common::String msg2 = _resourceManager->getMessage(100, _state++); + setTextStrings(msg1, msg2, this); + --_actionIndex; + } else { + setTextStrings(BF_NAME, BF_ALL_RIGHTS_RESERVED, this); + + Common::Point pt(_sceneText1._position.x, 80); + NpcMover *mover = new NpcMover(); + _sceneText1.addMover(mover, &pt, this); + } + break; + } + case 2: + setDelay(600); + break; + case 3: + BF_GLOBALS._sound1.fade(0, 10, 10, 1, this); + GLOBALS._scenePalette.addFader(black, 1, 2, NULL); + break; + case 4: + error("??exit"); + break; + } +} + +void Scene100::Action1::setTextStrings(const Common::String &msg1, const Common::String &msg2, Action *action) { + // Set data for first text control + _sceneText1._fontNumber = 10; + _sceneText1._width = 160; + _sceneText1._textMode = ALIGN_RIGHT; + _sceneText1._color1 = BF_GLOBALS._scenePalette._colors.foreground; + _sceneText1._color2 = BF_GLOBALS._scenePalette._colors.background; + _sceneText1._color3 = BF_GLOBALS._scenePalette._colors.foreground; + _sceneText1.setup(msg1); + _sceneText1.fixPriority(255); + _sceneText1.setPosition(Common::Point( + (SCREEN_WIDTH - _sceneText1.getFrame().getBounds().width()) / 2, 202)); + _sceneText1._moveRate = 30; + _sceneText1._moveDiff.y = 1; + + // Set data for second text control + _sceneText2._fontNumber = 10; + _sceneText2._width = _sceneText1._width; + _sceneText2._textMode = _sceneText1._textMode; + _sceneText2._color1 = _sceneText1._color1; + _sceneText2._color2 = 31; + _sceneText2._color3 = _sceneText1._color3; + _sceneText2.setup(msg2); + _sceneText2.fixPriority(255); + GfxSurface textSurface = _sceneText2.getFrame(); + _sceneText2.setPosition(Common::Point((SCREEN_WIDTH - textSurface.getBounds().width()) / 2, 202)); + _sceneText2._moveRate = 30; + _sceneText2._moveDiff.y = 1; + + _textHeight = textSurface.getBounds().height(); + int yp = -(_textHeight * 2); + + Common::Point pt(_sceneText1._position.x, yp); + NpcMover *mover = new NpcMover(); + _sceneText1.addMover(mover, &pt, action); +} + +void Scene100::Action2::signal() { + Scene100 *scene = (Scene100 *)_globals->_sceneManager._scene; + static byte black[3] = {0, 0, 0}; + + switch (_actionIndex++) { + case 0: + BF_GLOBALS._scenePalette.addFader(black, 1, -2, this); + break; + case 1: + setDelay(180); + break; + case 2: { + const char *SEEN_INTRO = "seen_intro"; + if (!ConfMan.hasKey(SEEN_INTRO) || !ConfMan.getBool(SEEN_INTRO)) { + // First time being played, so will need to show the intro + ConfMan.setBool(SEEN_INTRO, true); + ConfMan.flushToDisk(); + } else { + // Prompt user for whether to start play or watch introduction + _globals->_player.enableControl(); + + if (MessageDialog::show2(WATCH_INTRO_MSG, START_PLAY_BTN_STRING, INTRODUCTION_BTN_STRING) == 0) { + // Signal to start the game + scene->_index = 190; + remove(); + return; + } + } + + // At this point the introduction needs to start + _globals->_scenePalette.addFader(black, 1, 2, this); + break; + } + case 3: + remove(); + break; + } +} + +/*--------------------------------------------------------------------------*/ + +Scene100::Scene100(): SceneExt() { + _index = 0; +} + +void Scene100::postInit(SceneObjectList *OwnerList) { + BF_GLOBALS._scenePalette.loadPalette(2); + BF_GLOBALS._v51C44 = 1; + Scene::postInit(); + BF_GLOBALS._interfaceY = SCREEN_HEIGHT; + + _globals->_player.enableControl(); + _globals->_player.hide(); + _globals->_player.disableControl(); + _index = 109; + + if (BF_GLOBALS._v4CEA2 < 6) { + // Title + loadScene(100); + BF_GLOBALS._sound1.play(2); + setAction(&_action2, this); + } else { + // Credits + loadScene(101); + BF_GLOBALS._sound1.play(118); + setAction(&_action1, this); + } +} + +void Scene100::signal() { + ++_sceneMode; + if (BF_GLOBALS._v4CEA2 < 6) { + BF_GLOBALS._scenePalette.clearListeners(); + BF_GLOBALS._scenePalette.loadPalette(100); + BF_GLOBALS._sceneManager.changeScene(_index); + } else { + if (_sceneMode > 1) + BF_GLOBALS._events.setCursor(CURSOR_ARROW); + + setAction(this, &_action1, this); + } +} + +/*-------------------------------------------------------------------------- + * Scene 109 - Introduction Bar Room + * + *--------------------------------------------------------------------------*/ + +void Scene109::Action1::signal() { + Scene109 *scene = (Scene109 *)BF_GLOBALS._sceneManager._scene; + + switch (_actionIndex++) { + case 0: + setDelay(30); + break; + case 1: + BF_GLOBALS._sound1.play(12); + BF_GLOBALS._sceneObjects->draw(); + BF_GLOBALS._scenePalette.loadPalette(2); + BF_GLOBALS._scenePalette.refresh(); + setDelay(10); + break; + case 2: + scene->_text.setup(BF_19840515, this); + break; + case 3: + BF_GLOBALS._v51C44 = 1; + scene->loadScene(115); + + scene->_protaginist2.show(); + scene->_protaginist2.setPriority(133); + scene->_protaginist1.show(); + scene->_bartender.show(); + scene->_object1.show(); + scene->_drunk.show(); + scene->_drunk.setAction(&scene->_action3); + scene->_object2.show(); + scene->_object9.show(); + scene->_object9.setAction(&scene->_action2); + + BF_GLOBALS._v501FC = 170; + setDelay(60); + break; + case 4: + // Start drinking + scene->_bartender.setAction(&scene->_sequenceManager4, NULL, 109, &scene->_bartender, &scene->_object2, NULL); + scene->_protaginist1.setAction(&scene->_sequenceManager5, NULL, 107, &scene->_protaginist1, NULL); + scene->_protaginist2.setAction(&scene->_sequenceManager6, this, 106, &scene->_protaginist2, NULL); + break; + case 5: + // Open briefcase and pass over disk + setAction(&scene->_sequenceManager6, this, 105, &scene->_object10, NULL); + break; + case 6: + // Protaginist 2 walk to the bar + scene->_object10.remove(); + setAction(&scene->_sequenceManager6, this, 100, &scene->_protaginist2, NULL); + break; + case 7: + // Two thugs enter and walk to table + scene->_object7.setAction(&scene->_sequenceManager7, NULL, 103, &scene->_object7, NULL); + scene->_object5.setAction(&scene->_sequenceManager8, this, 102, &scene->_object5, NULL); + scene->_protaginist2.setAction(&scene->_sequenceManager6, NULL, 104, &scene->_protaginist2, &scene->_bartender, NULL); + break; + case 8: + // Protaginist 1 leaves, protaginist 2 stands up + setAction(&scene->_sequenceManager8, this, 101, &scene->_object5, &scene->_protaginist1, NULL); + break; + case 9: + // Shots fired! + scene->_protaginist1.setAction(&scene->_sequenceManager5, this, 98, &scene->_protaginist1, NULL); + scene->_object7.setAction(&scene->_sequenceManager7, NULL, 99, &scene->_object7, NULL); + break; + case 10: + // End scene + scene->_sceneMode = 1; + remove(); + break; + } +} + +void Scene109::Action2::signal() { + Scene109 *scene = (Scene109 *)BF_GLOBALS._sceneManager._scene; + scene->setAction(&scene->_sequenceManager2, this, 3117, &scene->_object9, NULL); +} + +void Scene109::Action3::signal() { + Scene109 *scene = (Scene109 *)BF_GLOBALS._sceneManager._scene; + scene->setAction(&scene->_sequenceManager3, this, 108, &scene->_drunk, NULL); +} + +/*--------------------------------------------------------------------------*/ + +Scene109::Text::Text(): SceneText() { + _action = NULL; + _frameNumber = 0; + _diff = 0; +} + +void Scene109::Text::setup(const Common::String &msg, Action *action) { + _frameNumber = BF_GLOBALS._events.getFrameNumber(); + _diff = 180; + _action = action; + _fontNumber = 4; + _width = 300; + _textMode = ALIGN_CENTER; + _color1 = BF_GLOBALS._scenePalette._colors.background; + _color2 = _color3 = 0; + + SceneText::setup(msg); + + // Center the text on-screen + reposition(); + _bounds.center(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2); + + // Set the new position + _position.x = _bounds.left; + _position.y = _bounds.top; +} + +void Scene109::Text::synchronize(Serializer &s) { + SceneText::synchronize(s); + SYNC_POINTER(_action); + s.syncAsUint32LE(_frameNumber); + s.syncAsSint16LE(_diff); +} + +void Scene109::Text::dispatch() { + if (_diff) { + uint32 frameNumber = BF_GLOBALS._events.getFrameNumber(); + if (_frameNumber < frameNumber) { + _diff -= frameNumber - _frameNumber; + _frameNumber = frameNumber; + + if (_diff <= 0) { + // Time has expired, so remove the text and signal the designated action + remove(); + if (_action) + _action->signal(); + } + } + } +} + +/*--------------------------------------------------------------------------*/ + +Scene109::Scene109(): GameScene() { +} + +void Scene109::postInit(SceneObjectList *OwnerList) { + GameScene::postInit(OwnerList); + loadScene(999); + + _protaginist2.postInit(); + _protaginist2.setVisage(119); + _protaginist2.setFrame(11); + _protaginist2.fixPriority(133); + _protaginist2.setPosition(Common::Point(165, 124)); + _protaginist2.hide(); + + _protaginist1.postInit(); + _protaginist1.setVisage(118); + _protaginist1.setStrip(1); + _protaginist1.setFrame(8); + _protaginist1.fixPriority(132); + _protaginist1.setPosition(Common::Point(143, 125)); + _protaginist1.hide(); + + _bartender.postInit(); + _bartender.setVisage(121); + _bartender.setStrip(2); + _bartender.setFrame(1); + _bartender.setPriority(-1); + _bartender.setPosition(Common::Point(92, 64)); + _bartender.hide(); + + _object1.postInit(); + _object1.setVisage(121); + _object1.setStrip(6); + _object1.setFrame(1); + _object1.setPriority(-1); + _object1.setPosition(Common::Point(110, 64)); + _object1.hide(); + + _drunk.postInit(); + _drunk.setVisage(120); + _drunk.setStrip(2); + _drunk.setFrame(5); + _drunk.setPriority(-1); + _drunk.setPosition(Common::Point(127, 97)); + _drunk.hide(); + + _object2.postInit(); + _object2.setVisage(121); + _object2.setStrip(5); + _object2.setFrame(1); + _object2.setPriority(-1); + _object2.setPosition(Common::Point(104, 64)); + _object2.hide(); + + _object9.postInit(); + _object9.setVisage(115); + _object9.setStrip(4); + _object9.setFrame(1); + _object9.setPosition(Common::Point(262, 29)); + _object9.hide(); + + _object5.postInit(); + _object5.hide(); + + _object7.postInit(); + _object7.hide(); + + _object10.postInit(); + _object10.hide(); + + BF_GLOBALS._player.disableControl(); + setAction(&_action1, this); +} + +void Scene109::signal() { + if (_sceneMode == 1) { + BF_GLOBALS._scenePalette.clearListeners(); + BF_GLOBALS._sceneManager.changeScene(110); + } +} + +} // End of namespace BlueForce + +} // End of namespace TsAGE diff --git a/engines/tsage/blue_force/blueforce_scenes1.h b/engines/tsage/blue_force/blueforce_scenes1.h new file mode 100644 index 0000000000..0769c6e3c6 --- /dev/null +++ b/engines/tsage/blue_force/blueforce_scenes1.h @@ -0,0 +1,132 @@ +/* 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 TSAGE_BLUEFORCE_SCENES1_H +#define TSAGE_BLUEFORCE_SCENES1_H + +#include "common/scummsys.h" +#include "tsage/blue_force/blueforce_logic.h" +#include "tsage/converse.h" +#include "tsage/events.h" +#include "tsage/core.h" +#include "tsage/scenes.h" +#include "tsage/globals.h" +#include "tsage/sound.h" + +namespace TsAGE { + +namespace BlueForce { + +using namespace TsAGE; + +class Scene100: public SceneExt { + /* Support classes */ + class Text: public SceneText { + public: + virtual Common::String getClassName() { return "BF100Text"; } + virtual void dispatch(); + }; + + /* Actions */ + class Action1: public ActionExt { + private: + void setTextStrings(const Common::String &msg1, const Common::String &msg2, Action *action); + public: + Text _sceneText1; + SceneText _sceneText2; + int _textHeight; + + virtual Common::String getClassName() { return "BF100Action1"; } + virtual void synchronize(Serializer &s) { + ActionExt::synchronize(s); + s.syncAsSint16LE(_textHeight); + } + virtual void signal(); + }; + class Action2: public ActionExt { + public: + virtual void signal(); + }; +public: + SequenceManager _sequenceManager; + Action1 _action1; + Action2 _action2; + ScenePalette _scenePalette; + SceneObjectExt2 _object1, _object2, _object3, _object4, _object5; + int _index; + + Scene100(); + virtual void postInit(SceneObjectList *OwnerList = NULL); + virtual void signal(); +}; + +class Scene109: public GameScene { + /* Actions */ + class Action1: public Action { + public: + virtual void signal(); + }; + class Action2: public Action { + public: + virtual void signal(); + }; + class Action3: public Action { + public: + virtual void signal(); + }; + + /* Texts */ + class Text: public SceneText { + public: + Action *_action; + uint32 _frameNumber; + int _diff; + public: + Text(); + void setup(const Common::String &msg, Action *action); + + virtual Common::String getClassName() { return "BF109Text"; } + virtual void synchronize(Serializer &s); + virtual void dispatch(); + }; +public: + SequenceManager _sequenceManager1, _sequenceManager2, _sequenceManager3; + SequenceManager _sequenceManager4, _sequenceManager5, _sequenceManager6; + SequenceManager _sequenceManager7, _sequenceManager8; + SceneObject _object1, _object2, _protaginist2, _protaginist1, _object5; + SceneObject _drunk, _object7, _bartender, _object9, _object10; + Text _text; + BlueAnimatedSpeaker _speaker; + Action1 _action1; + Action _action2, _action3; +public: + Scene109(); + + virtual void postInit(SceneObjectList *OwnerList = NULL); + virtual void signal(); +}; + +} // End of namespace BlueForce + +} // End of namespace TsAGE + +#endif diff --git a/engines/tsage/blueforce_logic.cpp b/engines/tsage/blueforce_logic.cpp deleted file mode 100644 index 3cf31b0b0a..0000000000 --- a/engines/tsage/blueforce_logic.cpp +++ /dev/null @@ -1,123 +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 "tsage/blueforce_logic.h" -#include "tsage/blueforce_scenes0.h" -#include "tsage/scenes.h" -#include "tsage/tsage.h" -#include "tsage/staticres.h" - -namespace tSage { - -void BlueForceGame::start() { - // Start the game - _globals->_sceneManager.changeScene(20); - - _globals->_events.setCursor(CURSOR_WALK); -} - -Scene *BlueForceGame::createScene(int sceneNumber) { - switch (sceneNumber) { - case 20: - // Tsunami Title Screen - return new BF_Scene20(); - case 50: - case 60: - error("Scene group 0 not implemented"); - case 100: - case 109: - case 110: - case 114: - case 115: - case 125: - case 140: - case 150: - case 160: - case 180: - case 190: - error("Scene group 1 not implemented"); - case 200: - case 210: - case 220: - case 225: - case 265: - case 270: - case 271: - case 280: - error("Scene group 2 not implemented"); - case 300: - case 315: - case 325: - case 330: - case 340: - case 342: - case 350: - case 355: - case 360: - case 370: - case 380: - case 385: - case 390: - error("Scene group 3 not implemented"); - case 410: - case 415: - case 440: - case 450: - error("Scene group 4 not implemented"); - case 550: - case 551: - case 560: - case 570: - case 580: - case 590: - error("Scene group 5 not implemented"); - case 600: - case 620: - case 666: - case 690: - error("Scene group 6 not implemented"); - case 710: - error("Scene group 7 not implemented"); - case 800: - case 810: - case 820: - case 830: - case 840: - case 850: - case 860: - case 870: - case 880: - error("Scene group 8 not implemented"); - case 900: - case 910: - case 920: - case 930: - case 935: - case 940: - error("Scene group 9 not implemented"); - default: - error("Unknown scene number - %d", sceneNumber); - break; - } -} - -} // End of namespace tSage diff --git a/engines/tsage/converse.cpp b/engines/tsage/converse.cpp index 0ae575c557..615b1c36fd 100644 --- a/engines/tsage/converse.cpp +++ b/engines/tsage/converse.cpp @@ -26,7 +26,7 @@ #include "tsage/globals.h" #include "tsage/staticres.h" -namespace tSage { +namespace TsAGE { #define STRIP_WORD_DELAY 30 @@ -34,7 +34,7 @@ namespace tSage { SequenceManager::SequenceManager() : Action() { Common::set_to(&_objectList[0], &_objectList[6], (SceneObject *)NULL); _sequenceData.clear(); - _field24 = 0; + _fontNum = 0; _sequenceOffset = 0; _resNum = 0; _field26 = 0; @@ -56,7 +56,7 @@ void SequenceManager::synchronize(Serializer &s) { s.syncAsSint32LE(_resNum); s.syncAsSint32LE(_sequenceOffset); s.syncAsByte(_keepActive); - s.syncAsSint32LE(_field24); + s.syncAsSint32LE(_fontNum); s.syncAsSint32LE(_field26); s.syncAsSint32LE(_objectIndex); @@ -284,6 +284,32 @@ void SequenceManager::signal() { _objectList[objIndex3], _objectList[objIndex4], _objectList[objIndex5], _objectList[objIndex6], NULL); break; } + /* Following indexes were introduced for Blue Force */ + case 35: + v1 = getNextValue(); + _sceneObject->updateAngle(_objectList[v1]); + break; + case 36: + _sceneObject->animate(ANIM_MODE_9, NULL); + break; + case 37: + v1 = getNextValue(); + v2 = getNextValue(); + warning("TODO: dword_53030(%d,%d)", v1, v2); + break; + case 38: { + int resNum = getNextValue(); + int lineNum = getNextValue(); + int fontNum = getNextValue(); + int color1 = getNextValue(); + int color2 = getNextValue(); + int color3 = getNextValue(); + int xp = getNextValue(); + int yp = getNextValue(); + int width = getNextValue(); + setMessage(resNum, lineNum, fontNum, color1, color2, color3, Common::Point(xp, yp), width); + break; + } default: error("SequenceManager::signal - Unknown action %d at offset %xh", idx, _sequenceOffset - 2); break; @@ -337,10 +363,15 @@ uint16 SequenceManager::getNextValue() { } void SequenceManager::setMessage(int resNum, int lineNum, int color, const Common::Point &pt, int width) { - _sceneText._color1 = color; - _sceneText._color2 = 0; - _sceneText._color3 = 0; - _sceneText._fontNumber = 2; + setMessage(resNum, lineNum, 2, color, 0, 0, pt, width); +} + +void SequenceManager::setMessage(int resNum, int lineNum, int fontNum, int color1, int color2, int color3, + const Common::Point &pt, int width) { + _sceneText._color1 = color1; + _sceneText._color2 = color2; + _sceneText._color3 = color3; + _sceneText._fontNumber = fontNum; _sceneText._width = width; // Get the display message @@ -954,4 +985,4 @@ void AnimatedSpeaker::removeText() { _objectList.draw(); } -} // end of namespace tSage +} // end of namespace TsAGE diff --git a/engines/tsage/converse.h b/engines/tsage/converse.h index 13c490e995..e263a12d12 100644 --- a/engines/tsage/converse.h +++ b/engines/tsage/converse.h @@ -27,7 +27,7 @@ #include "tsage/dialogs.h" #include "tsage/sound.h" -namespace tSage { +namespace TsAGE { class StripCallback : public Action { public: @@ -39,13 +39,15 @@ private: void setup(); uint16 getNextValue(); void setMessage(int resNum, int lineNum, int color, const Common::Point &pt, int width); + void setMessage(int resNum, int lineNum, int fontNum, int color1, int color2, int color3, + const Common::Point &pt, int width); SequenceManager *globalManager(); public: SceneText _sceneText; int _resNum; uint _sequenceOffset; bool _keepActive; - int _field24; + int _fontNum; int _field26; Common::Array<byte> _sequenceData; int _objectIndex; @@ -222,6 +224,6 @@ public: void addSpeaker(Speaker *speaker); }; -} // End of namespace tSage +} // End of namespace TsAGE #endif diff --git a/engines/tsage/core.cpp b/engines/tsage/core.cpp index d0075d5acf..864c3af103 100644 --- a/engines/tsage/core.cpp +++ b/engines/tsage/core.cpp @@ -33,7 +33,7 @@ #include "tsage/globals.h" #include "tsage/sound.h" -namespace tSage { +namespace TsAGE { // The engine uses ScumMVM screen buffering, so all logic is hardcoded to use pane buffer 0 #define CURRENT_PANENUM 0 @@ -1161,6 +1161,20 @@ void PaletteFader::remove() { action->signal(); } +void PaletteFader::setPalette(ScenePalette *palette, int step) { + if (step < 0) { + // Reverse step means moving from dest palette to source, so swap the two palettes + byte tempPal[256 * 3]; + Common::copy(&palette->_palette[0], &palette->_palette[256 * 3], &tempPal[0]); + Common::copy(&this->_palette[0], &this->_palette[256 * 3], &palette->_palette[0]); + Common::copy(&tempPal[0], &tempPal[256 * 3], &this->_palette[0]); + + step = -step; + } + + PaletteModifierCached::setPalette(palette, step); +} + /*--------------------------------------------------------------------------*/ ScenePalette::ScenePalette() { @@ -1314,7 +1328,7 @@ PaletteRotation *ScenePalette::addRotation(int start, int end, int rotationMode, return obj; } -PaletteFader *ScenePalette::addFader(const byte *arrBufferRGB, int palSize, int percent, Action *action) { +PaletteFader *ScenePalette::addFader(const byte *arrBufferRGB, int palSize, int step, Action *action) { PaletteFader *fader = new PaletteFader(); fader->_action = action; for (int i = 0; i < 256 * 3; i += 3) { @@ -1326,7 +1340,7 @@ PaletteFader *ScenePalette::addFader(const byte *arrBufferRGB, int palSize, int arrBufferRGB += 3; } - fader->setPalette(this, percent); + fader->setPalette(this, step); _globals->_scenePalette._listeners.push_back(fader); return fader; } @@ -1641,6 +1655,11 @@ void SceneObjectWrapper::remove() { } void SceneObjectWrapper::dispatch() { + if (_vm->getGameID() == GType_Ringworld) + check(); +} + +void SceneObjectWrapper::check() { _visageImages.setVisage(_sceneObject->_visage); int frameCount = _visageImages.getFrameCount(); int angle = _sceneObject->_angle; @@ -2263,6 +2282,18 @@ void SceneObject::updateScreen() { } } +void SceneObject::updateAngle(SceneObject *sceneObj) { + checkAngle(sceneObj); + if (_objectWrapper) + _objectWrapper->check(); +} + +void SceneObject::changeAngle(int angle) { + _angle = angle; + if (_objectWrapper) + _objectWrapper->check(); +} + void SceneObject::setup(int visage, int stripFrameNum, int frameNum, int posX, int posY, int priority) { postInit(); setVisage(visage); @@ -2274,6 +2305,22 @@ void SceneObject::setup(int visage, int stripFrameNum, int frameNum, int posX, i /*--------------------------------------------------------------------------*/ +void SceneObjectExt2::postInit(SceneObjectList *OwnerList) { + _v8A = -1; + _v8C = -1; + _v8E = -1; + SceneObject::postInit(); +} + +void SceneObjectExt2::synchronize(Serializer &s) { + SceneObject::synchronize(s); + s.syncAsSint16LE(_v8A); + s.syncAsSint16LE(_v8C); + s.syncAsSint16LE(_v8E); +} + +/*--------------------------------------------------------------------------*/ + void SceneObjectList::draw() { Common::Array<SceneObject *> objList; int paneNum = 0; @@ -3573,4 +3620,4 @@ void SceneHandler::dispatchObject(EventHandler *obj) { void SceneHandler::saveListener(Serializer &ser) { } -} // End of namespace tSage +} // End of namespace TsAGE diff --git a/engines/tsage/core.h b/engines/tsage/core.h index b86e2f63fe..96e7e82fe5 100644 --- a/engines/tsage/core.h +++ b/engines/tsage/core.h @@ -34,7 +34,7 @@ #include "tsage/resources.h" #include "tsage/saveload.h" -namespace tSage { +namespace TsAGE { #define MAX_FLAGS 256 @@ -287,7 +287,7 @@ public: PaletteModifierCached(); - void setPalette(ScenePalette *palette, int step); + virtual void setPalette(ScenePalette *palette, int step); virtual Common::String getClassName() { return "PaletteModifierCached"; } virtual void synchronize(Serializer &s); }; @@ -323,6 +323,7 @@ public: virtual void synchronize(Serializer &s); virtual void signal(); virtual void remove(); + virtual void setPalette(ScenePalette *palette, int step); }; /*--------------------------------------------------------------------------*/ @@ -356,7 +357,7 @@ public: void clearListeners(); void fade(const byte *adjustData, bool fullAdjust, int percent); PaletteRotation *addRotation(int start, int end, int rotationMode, int duration = 0, Action *action = NULL); - PaletteFader *addFader(const byte *arrBufferRGB, int palSize, int percent, Action *action); + PaletteFader *addFader(const byte *arrBufferRGB, int palSize, int step, Action *action); static void changeBackground(const Rect &bounds, FadeMode fadeMode); @@ -436,7 +437,10 @@ public: }; enum AnimateMode {ANIM_MODE_NONE = 0, ANIM_MODE_1 = 1, ANIM_MODE_2 = 2, ANIM_MODE_3 = 3, - ANIM_MODE_4 = 4, ANIM_MODE_5 = 5, ANIM_MODE_6 = 6, ANIM_MODE_7 = 7, ANIM_MODE_8 = 8}; + ANIM_MODE_4 = 4, ANIM_MODE_5 = 5, ANIM_MODE_6 = 6, ANIM_MODE_7 = 7, ANIM_MODE_8 = 8, + // Introduced in Blue Force + ANIM_MODE_9 = 9 +}; class SceneObject; @@ -467,6 +471,7 @@ public: virtual ~SceneObjectWrapper() {} void setSceneObject(SceneObject *so); + void check(); virtual void synchronize(Serializer &s); virtual Common::String getClassName() { return "SceneObjectWrapper"; } @@ -555,6 +560,10 @@ public: virtual void draw(); virtual void proc19() {} virtual void updateScreen(); + // New methods introduced by Blue FOrce + virtual void updateAngle(SceneObject *sceneObj); + virtual void changeAngle(int angle); + void setup(int visage, int stripFrameNum, int frameNum, int posX, int posY, int priority); }; @@ -569,6 +578,16 @@ public: virtual Common::String getClassName() { return "SceneObjectExt"; } }; +class SceneObjectExt2: public SceneObject { +public: + int _v88, _v8A, _v8C, _v8E; + + virtual Common::String getClassName() { return "BF100Object"; } + virtual void synchronize(Serializer &s); + virtual void postInit(SceneObjectList *OwnerList = NULL); +}; + + class SceneText : public SceneObject { public: int _fontNumber; @@ -695,7 +714,7 @@ public: SynchronizedList<SceneObject *>::iterator begin() { return _objList.begin(); } SynchronizedList<SceneObject *>::iterator end() { return _objList.end(); } int size() const { return _objList.size(); } - bool contains(SceneObject *sceneObj) { return tSage::contains(_objList, sceneObj); } + bool contains(SceneObject *sceneObj) { return TsAGE::contains(_objList, sceneObj); } void push_back(SceneObject *sceneObj) { _objList.push_back(sceneObj); } void push_front(SceneObject *sceneObj) { _objList.push_front(sceneObj); } void remove(SceneObject *sceneObj) { @@ -840,6 +859,6 @@ public: static void saveListener(Serializer &ser); }; -} // End of namespace tSage +} // End of namespace TsAGE #endif diff --git a/engines/tsage/debugger.cpp b/engines/tsage/debugger.cpp index 00cd61ae07..e3c4569dd2 100644 --- a/engines/tsage/debugger.cpp +++ b/engines/tsage/debugger.cpp @@ -23,9 +23,9 @@ #include "tsage/debugger.h" #include "tsage/globals.h" #include "tsage/graphics.h" -#include "tsage/ringworld_logic.h" +#include "tsage/ringworld/ringworld_logic.h" -namespace tSage { +namespace TsAGE { Debugger::Debugger() : GUI::Debugger() { DCmd_Register("continue", WRAP_METHOD(Debugger, Cmd_Exit)); @@ -449,4 +449,4 @@ bool Debugger::Cmd_Sound(int argc, const char **argv) { return false; } -} // End of namespace tSage +} // End of namespace TsAGE diff --git a/engines/tsage/debugger.h b/engines/tsage/debugger.h index 44fd61ec5e..8bc1b06336 100644 --- a/engines/tsage/debugger.h +++ b/engines/tsage/debugger.h @@ -26,7 +26,7 @@ #include "common/scummsys.h" #include "gui/debugger.h" -namespace tSage { +namespace TsAGE { class Debugger : public GUI::Debugger { public: @@ -46,6 +46,6 @@ protected: bool Cmd_Sound(int argc, const char **argv); }; -} // End of namespace tSage +} // End of namespace TsAGE #endif diff --git a/engines/tsage/detection.cpp b/engines/tsage/detection.cpp index c8aa415914..f12efc02e8 100644 --- a/engines/tsage/detection.cpp +++ b/engines/tsage/detection.cpp @@ -30,7 +30,7 @@ #include "tsage/tsage.h" -namespace tSage { +namespace TsAGE { struct tSageGameDescription { ADGameDescription desc; @@ -55,7 +55,7 @@ Common::String TSageEngine::getPrimaryFilename() const { return Common::String(_gameDescription->desc.filesDescriptions[0].fileName); } -} // End of namespace tSage +} // End of namespace TsAGE static const PlainGameDescriptor tSageGameTitles[] = { { "tsage", "Unknown Tsunami TSAGE-based Game" }, @@ -72,7 +72,7 @@ enum { class TSageMetaEngine : public AdvancedMetaEngine { public: - TSageMetaEngine() : AdvancedMetaEngine(tSage::gameDescriptions, sizeof(tSage::tSageGameDescription), tSageGameTitles) { + TSageMetaEngine() : AdvancedMetaEngine(TsAGE::gameDescriptions, sizeof(TsAGE::tSageGameDescription), tSageGameTitles) { _md5Bytes = 5000; _singleid = "tsage"; _guioptions = Common::GUIO_NOSPEECH; @@ -103,7 +103,7 @@ public: virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { if (desc) { - *engine = new tSage::TSageEngine(syst, (const tSage::tSageGameDescription *)desc); + *engine = new TsAGE::TSageEngine(syst, (const TsAGE::tSageGameDescription *)desc); } return desc != 0; } @@ -118,7 +118,7 @@ public: Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles(pattern); sort(filenames.begin(), filenames.end()); - tSage::tSageSavegameHeader header; + TsAGE::tSageSavegameHeader header; SaveStateList saveList; for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { @@ -129,7 +129,7 @@ public: Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(*file); if (in) { - if (tSage::Saver::readSavegameHeader(in, header)) { + if (TsAGE::Saver::readSavegameHeader(in, header)) { saveList.push_back(SaveStateDescriptor(slot, header.saveName)); delete header.thumbnail; } @@ -156,8 +156,8 @@ public: generateGameStateFileName(target, slot)); assert(f); - tSage::tSageSavegameHeader header; - tSage::Saver::readSavegameHeader(f, header); + TsAGE::tSageSavegameHeader header; + TsAGE::Saver::readSavegameHeader(f, header); delete f; // Create the return descriptor diff --git a/engines/tsage/detection_tables.h b/engines/tsage/detection_tables.h index 7fbfa55c95..4b69549673 100644 --- a/engines/tsage/detection_tables.h +++ b/engines/tsage/detection_tables.h @@ -20,7 +20,7 @@ * */ -namespace tSage { +namespace TsAGE { static const tSageGameDescription gameDescriptions[] = { @@ -32,7 +32,7 @@ static const tSageGameDescription gameDescriptions[] = { AD_ENTRY1s("ring.rlb", "466f0e6492d9d0f34d35c5cd088de90f", 37847618), Common::EN_ANY, Common::kPlatformPC, - ADGF_TESTING, + ADGF_TESTING | ADGF_CD, Common::GUIO_NOSPEECH | Common::GUIO_NOSFX }, GType_Ringworld, @@ -46,7 +46,7 @@ static const tSageGameDescription gameDescriptions[] = { AD_ENTRY1s("ring.rlb", "cb8bba91b30cd172712371d7123bd763", 7427980), Common::ES_ESP, Common::kPlatformPC, - ADGF_TESTING, + ADGF_TESTING | ADGF_CD, Common::GUIO_NOSPEECH | Common::GUIO_NOSFX }, GType_Ringworld, @@ -120,11 +120,11 @@ static const tSageGameDescription gameDescriptions[] = { AD_ENTRY1s("blue.rlb", "17eabb456cb1546c66baf1aff387ba6a", 10032614), Common::EN_ANY, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_UNSTABLE, Common::GUIO_NOSPEECH | Common::GUIO_NOSFX }, GType_BlueForce, - GF_FLOPPY + GF_FLOPPY | GF_ALT_REGIONS }, // Blue Force CD and First Wave use the same files { @@ -134,13 +134,13 @@ static const tSageGameDescription gameDescriptions[] = { AD_ENTRY1s("blue.rlb", "99983f48cb218f1f3760cf2f9a7ef11d", 63863322), Common::EN_ANY, Common::kPlatformPC, - ADGF_NO_FLAGS, + ADGF_CD | ADGF_UNSTABLE, Common::GUIO_NOSPEECH | Common::GUIO_NOSFX }, GType_BlueForce, - GF_CD + GF_CD | GF_ALT_REGIONS }, { AD_TABLE_END_MARKER, 0, 0 } }; -} // End of namespace tSage +} // End of namespace TsAGE diff --git a/engines/tsage/dialogs.cpp b/engines/tsage/dialogs.cpp index d315ce092b..ae385b8c15 100644 --- a/engines/tsage/dialogs.cpp +++ b/engines/tsage/dialogs.cpp @@ -30,9 +30,9 @@ #include "tsage/dialogs.h" #include "tsage/staticres.h" #include "tsage/globals.h" -#include "tsage/ringworld_logic.h" +#include "tsage/ringworld/ringworld_logic.h" -namespace tSage { +namespace TsAGE { /*--------------------------------------------------------------------------*/ @@ -595,4 +595,4 @@ OptionsDialog::OptionsDialog() { } -} // End of namespace tSage +} // End of namespace TsAGE diff --git a/engines/tsage/dialogs.h b/engines/tsage/dialogs.h index a50307f775..55adb6c813 100644 --- a/engines/tsage/dialogs.h +++ b/engines/tsage/dialogs.h @@ -30,7 +30,7 @@ #include "common/rect.h" #include "common/system.h" -namespace tSage { +namespace TsAGE { class MessageDialog : public GfxDialog { public: @@ -128,6 +128,6 @@ public: static void show(); }; -} // End of namespace tSage +} // End of namespace TsAGE #endif diff --git a/engines/tsage/events.cpp b/engines/tsage/events.cpp index 7aadf62b8d..44c79bd2fe 100644 --- a/engines/tsage/events.cpp +++ b/engines/tsage/events.cpp @@ -31,7 +31,7 @@ #include "tsage/tsage.h" #include "tsage/globals.h" -namespace tSage { +namespace TsAGE { EventsClass::EventsClass() { _currentCursor = CURSOR_NONE; @@ -155,7 +155,7 @@ void EventsClass::setCursor(CursorType cursorType) { // No cursor _globals->setFlag(122); - if (_vm->getFeatures() & GF_DEMO) { + if ((_vm->getFeatures() & GF_DEMO) || (_vm->getGameID() == GType_BlueForce)) { CursorMan.showMouse(false); return; } @@ -325,4 +325,4 @@ void EventsClass::loadNotifierProc(bool postFlag) { } } -} // end of namespace tSage +} // end of namespace TsAGE diff --git a/engines/tsage/events.h b/engines/tsage/events.h index 772de24b5a..c36db59270 100644 --- a/engines/tsage/events.h +++ b/engines/tsage/events.h @@ -29,7 +29,7 @@ #include "graphics/surface.h" #include "tsage/saveload.h" -namespace tSage { +namespace TsAGE { enum EventType {EVENT_NONE = 0, EVENT_BUTTON_DOWN = 1, EVENT_BUTTON_UP = 2, EVENT_KEYPRESS = 4, EVENT_MOUSE_MOVE = 8}; @@ -103,6 +103,6 @@ public: static void loadNotifierProc(bool postFlag); }; -} // End of namespace tSage +} // End of namespace TsAGE #endif diff --git a/engines/tsage/globals.cpp b/engines/tsage/globals.cpp index 34b26ec311..47c83fcc94 100644 --- a/engines/tsage/globals.cpp +++ b/engines/tsage/globals.cpp @@ -22,11 +22,11 @@ #include "tsage/globals.h" #include "tsage/tsage.h" -#include "tsage/blueforce_logic.h" -#include "tsage/ringworld_demo.h" -#include "tsage/ringworld_logic.h" +#include "tsage/blue_force/blueforce_logic.h" +#include "tsage/ringworld/ringworld_demo.h" +#include "tsage/ringworld/ringworld_logic.h" -namespace tSage { +namespace TsAGE { Globals *_globals = NULL; ResourceManager *_resourceManager = NULL; @@ -51,7 +51,7 @@ static SavedObject *classFactoryProc(const Common::String &className) { /*--------------------------------------------------------------------------*/ Globals::Globals() : _dialogCenter(160, 140), _gfxManagerInstance(_screenSurface), - _randomSource("tsage"), _unkColor1(0), _unkColor2(255), _unkColor3(255) { + _randomSource("tsage"), _color1(0), _color2(255), _color3(255) { reset(); _stripNum = 0; _gfxEdgeAdjust = 3; @@ -64,18 +64,26 @@ Globals::Globals() : _dialogCenter(160, 140), _gfxManagerInstance(_screenSurface _fontColors.foreground = 6; _dialogCenter.y = 80; // Workaround in order to use later version of the engine - _unkColor1 = _gfxColors.foreground; - _unkColor2 = _gfxColors.foreground; - _unkColor3 = _gfxColors.foreground; + _color1 = _gfxColors.foreground; + _color2 = _gfxColors.foreground; + _color3 = _gfxColors.foreground; + } else if (_vm->getGameID() == GType_BlueForce) { + // Blue Force + _gfxFontNumber = 0; + _gfxColors.background = 89; + _gfxColors.foreground = 83; + _fontColors.background = 88; + _fontColors.foreground = 92; + _dialogCenter.y = 165; } else if ((_vm->getGameID() == GType_Ringworld) && (_vm->getFeatures() & GF_CD)) { _gfxFontNumber = 50; _gfxColors.background = 53; _gfxColors.foreground = 0; _fontColors.background = 51; _fontColors.foreground = 54; - _unkColor1 = 18; - _unkColor2 = 18; - _unkColor3 = 18; + _color1 = 18; + _color2 = 18; + _color3 = 18; } else { _gfxFontNumber = 50; _gfxColors.background = 53; @@ -83,9 +91,9 @@ Globals::Globals() : _dialogCenter(160, 140), _gfxManagerInstance(_screenSurface _fontColors.background = 51; _fontColors.foreground = 54; // Workaround in order to use later version of the engine - _unkColor1 = _gfxColors.foreground; - _unkColor2 = _gfxColors.foreground; - _unkColor3 = _gfxColors.foreground; + _color1 = _gfxColors.foreground; + _color2 = _gfxColors.foreground; + _color3 = _gfxColors.foreground; } _screenSurface.setScreenSurface(); _gfxManagers.push_back(&_gfxManagerInstance); @@ -103,20 +111,21 @@ Globals::Globals() : _dialogCenter(160, 140), _gfxManagerInstance(_screenSurface switch (_vm->getGameID()) { case GType_Ringworld: if (!(_vm->getFeatures() & GF_DEMO)) { - _inventory = new RingworldInvObjectList(); - _game = new RingworldGame(); + _inventory = new Ringworld::RingworldInvObjectList(); + _game = new Ringworld::RingworldGame(); } else { - _game = new RingworldDemoGame(); + _game = new Ringworld::RingworldDemoGame(); } break; case GType_BlueForce: - _game = new BlueForceGame(); + _game = new BlueForce::BlueForceGame(); break; } } Globals::~Globals() { + _scenePalette.clearListeners(); delete _inventory; delete _game; _globals = NULL; @@ -142,9 +151,9 @@ void Globals::synchronize(Serializer &s) { s.syncAsSint32LE(_fontColors.foreground); if (s.getVersion() >= 4) { - s.syncAsByte(_unkColor1); - s.syncAsByte(_unkColor2); - s.syncAsByte(_unkColor3); + s.syncAsByte(_color1); + s.syncAsByte(_color2); + s.syncAsByte(_color3); } s.syncAsSint16LE(_dialogCenter.x); s.syncAsSint16LE(_dialogCenter.y); @@ -166,5 +175,21 @@ void Globals::dispatchSounds() { Common::for_each(_sounds.begin(), _sounds.end(), Globals::dispatchSound); } +/*--------------------------------------------------------------------------*/ + +namespace BlueForce { + +BlueForceGlobals::BlueForceGlobals(): Globals() { + _interfaceY = 0; + _v51C44 = 1; + _v4CEA2 = 0; +} + +void BlueForceGlobals::synchronize(Serializer &s) { + Globals::synchronize(s); + error("Sync variables"); +} + +} // end of namespace BlueForce -} // end of namespace tSage +} // end of namespace TsAGE diff --git a/engines/tsage/globals.h b/engines/tsage/globals.h index 7cfec718e2..c8cfc1c323 100644 --- a/engines/tsage/globals.h +++ b/engines/tsage/globals.h @@ -31,7 +31,7 @@ #include "tsage/sound.h" #include "tsage/saveload.h" -namespace tSage { +namespace TsAGE { class Globals : public SavedObject { private: @@ -54,7 +54,7 @@ public: int _gfxFontNumber; GfxColors _gfxColors; GfxColors _fontColors; - byte _unkColor1, _unkColor2, _unkColor3; + byte _color1, _color2, _color3; SoundManager _soundManager; Common::Point _dialogCenter; WalkRegions _walkRegions; @@ -98,10 +98,36 @@ public: extern Globals *_globals; +#define GLOBALS (*_globals) +#define BF_GLOBALS (*((::TsAGE::BlueForce::BlueForceGlobals *)_globals)) + // Note: Currently this can't be part of the _globals structure, since it needs to be constructed // prior to many of the fields in Globals execute their constructors extern ResourceManager *_resourceManager; -} // End of namespace tSage + +namespace BlueForce { + +using namespace TsAGE; + +class BlueForceGlobals: public Globals { +public: + ASound _sound1, _sound2, _sound3; + int _v4CEA2; + int _v4CF9E; + int _v4E238; + int _v501FC; + int _v51C42; + int _v51C44; + int _interfaceY; + + BlueForceGlobals(); + virtual Common::String getClassName() { return "BFGlobals"; } + virtual void synchronize(Serializer &s); +}; + +} // End of namespace BlueForce + +} // End of namespace TsAGE #endif diff --git a/engines/tsage/graphics.cpp b/engines/tsage/graphics.cpp index 87ffdf4494..1884bfb4f5 100644 --- a/engines/tsage/graphics.cpp +++ b/engines/tsage/graphics.cpp @@ -30,7 +30,7 @@ #include "graphics/surface.h" #include "tsage/globals.h" -namespace tSage { +namespace TsAGE { /** * Creates a new graphics surface with the specified area of another surface @@ -626,9 +626,9 @@ void GfxElement::setDefaults() { _fontNumber = _globals->_gfxFontNumber; _colors = _globals->_gfxColors; _fontColors = _globals->_fontColors; - _unkColor1 = _globals->_unkColor1; - _unkColor2 = _globals->_unkColor2; - _unkColor3 = _globals->_unkColor3; + _color1 = _globals->_color1; + _color2 = _globals->_color2; + _color3 = _globals->_color3; } /** @@ -824,9 +824,9 @@ void GfxMessage::draw() { gfxManager.setFillFlag(false); gfxManager._font.setFontNumber(_fontNumber); - gfxManager._font._colors.foreground = this->_unkColor1; - gfxManager._font._colors2.background = this->_unkColor2; - gfxManager._font._colors2.foreground = this->_unkColor3; + gfxManager._font._colors.foreground = this->_color1; + gfxManager._font._colors2.background = this->_color2; + gfxManager._font._colors2.foreground = this->_color3; // Display the text gfxManager._font.writeLines(_message.c_str(), _bounds, _textAlign); @@ -867,9 +867,9 @@ void GfxButton::draw() { gfxManager._font.setFontNumber(_fontNumber); // - gfxManager._font._colors.foreground = this->_unkColor1; - gfxManager._font._colors2.background = this->_unkColor2; - gfxManager._font._colors2.foreground = this->_unkColor3; + gfxManager._font._colors.foreground = this->_color1; + gfxManager._font._colors2.background = this->_color2; + gfxManager._font._colors2.foreground = this->_color3; // Display the button's text Rect tempRect(_bounds); @@ -1512,4 +1512,4 @@ GfxFontBackup::~GfxFontBackup() { } -} // End of namespace tSage +} // End of namespace TsAGE diff --git a/engines/tsage/graphics.h b/engines/tsage/graphics.h index e09e1093a3..06b482d7b5 100644 --- a/engines/tsage/graphics.h +++ b/engines/tsage/graphics.h @@ -30,7 +30,7 @@ #include "common/system.h" #include "graphics/surface.h" -namespace tSage { +namespace TsAGE { class GfxSurface; class Region; @@ -177,7 +177,7 @@ public: uint16 _fontNumber; GfxColors _colors; GfxColors _fontColors; - byte _unkColor1, _unkColor2, _unkColor3; + byte _color1, _color2, _color3; uint16 _keycode; public: GfxElement(); @@ -343,6 +343,6 @@ GfxSurface *Surface_getArea(GfxSurface &src, const Rect &bounds); GfxSurface surfaceFromRes(const byte *imgData); GfxSurface surfaceFromRes(int resNum, int rlbNum, int subNum); -} // End of namespace tSage +} // End of namespace TsAGE #endif diff --git a/engines/tsage/module.mk b/engines/tsage/module.mk index 586699593d..5c7104936e 100644 --- a/engines/tsage/module.mk +++ b/engines/tsage/module.mk @@ -1,8 +1,9 @@ MODULE := engines/tsage MODULE_OBJS := \ - blueforce_logic.o \ - blueforce_scenes0.o \ + blue_force/blueforce_logic.o \ + blue_force/blueforce_scenes0.o \ + blue_force/blueforce_scenes1.o \ converse.o \ core.o \ debugger.o \ @@ -12,16 +13,16 @@ MODULE_OBJS := \ globals.o \ graphics.o \ resources.o \ - ringworld_demo.o \ - ringworld_logic.o \ - ringworld_scenes1.o \ - ringworld_scenes2.o \ - ringworld_scenes3.o \ - ringworld_scenes4.o \ - ringworld_scenes5.o \ - ringworld_scenes6.o \ - ringworld_scenes8.o \ - ringworld_scenes10.o \ + ringworld/ringworld_demo.o \ + ringworld/ringworld_logic.o \ + ringworld/ringworld_scenes1.o \ + ringworld/ringworld_scenes2.o \ + ringworld/ringworld_scenes3.o \ + ringworld/ringworld_scenes4.o \ + ringworld/ringworld_scenes5.o \ + ringworld/ringworld_scenes6.o \ + ringworld/ringworld_scenes8.o \ + ringworld/ringworld_scenes10.o \ saveload.o \ scenes.o \ sound.o \ diff --git a/engines/tsage/resources.cpp b/engines/tsage/resources.cpp index 6d2c6b5837..99b431b5dc 100644 --- a/engines/tsage/resources.cpp +++ b/engines/tsage/resources.cpp @@ -28,7 +28,7 @@ #include "tsage/resources.h" #include "tsage/tsage.h" -namespace tSage { +namespace TsAGE { MemoryManager::MemoryManager() { @@ -504,4 +504,4 @@ Common::String ResourceManager::getMessage(int resNum, int lineNum, bool suppres return result; } -} // end of namespace tSage +} // end of namespace TsAGE diff --git a/engines/tsage/resources.h b/engines/tsage/resources.h index efbb86b24e..176d60fcc4 100644 --- a/engines/tsage/resources.h +++ b/engines/tsage/resources.h @@ -33,7 +33,7 @@ #include "common/util.h" #include "graphics/surface.h" -namespace tSage { +namespace TsAGE { // Magic number used by original game to identify valid memory blocks const uint32 MEMORY_ENTRY_ID = 0xE11DA722; @@ -175,6 +175,6 @@ public: }; -} // end of namespace tSage +} // end of namespace TsAGE #endif diff --git a/engines/tsage/ringworld_demo.cpp b/engines/tsage/ringworld/ringworld_demo.cpp index b24fec98f9..5612325aff 100644 --- a/engines/tsage/ringworld_demo.cpp +++ b/engines/tsage/ringworld/ringworld_demo.cpp @@ -20,12 +20,14 @@ * */ -#include "tsage/ringworld_demo.h" +#include "tsage/ringworld/ringworld_demo.h" #include "tsage/scenes.h" #include "tsage/tsage.h" #include "tsage/staticres.h" -namespace tSage { +namespace TsAGE { + +namespace Ringworld { void RingworldDemoGame::start() { // Start the demo's single scene @@ -117,4 +119,6 @@ void RingworldDemoScene::process(Event &event) { } -} // End of namespace tSage +} // End of namespace Ringworld + +} // End of namespace TsAGE diff --git a/engines/tsage/ringworld_demo.h b/engines/tsage/ringworld/ringworld_demo.h index 3e7431e107..30527b0aea 100644 --- a/engines/tsage/ringworld_demo.h +++ b/engines/tsage/ringworld/ringworld_demo.h @@ -30,7 +30,11 @@ #include "tsage/globals.h" #include "tsage/sound.h" -namespace tSage { +namespace TsAGE { + +namespace Ringworld { + +using namespace TsAGE; class RingworldDemoGame: public Game { private: @@ -54,6 +58,8 @@ public: virtual void signal(); }; -} // End of namespace tSage +} // End of namespace Ringworld + +} // End of namespace TsAGE #endif diff --git a/engines/tsage/ringworld_logic.cpp b/engines/tsage/ringworld/ringworld_logic.cpp index 070d8afd25..d6e72fe95c 100644 --- a/engines/tsage/ringworld_logic.cpp +++ b/engines/tsage/ringworld/ringworld_logic.cpp @@ -23,21 +23,23 @@ #include "common/config-manager.h" #include "common/translation.h" #include "gui/saveload.h" -#include "tsage/ringworld_logic.h" +#include "tsage/ringworld/ringworld_logic.h" #include "tsage/scenes.h" #include "tsage/tsage.h" #include "tsage/staticres.h" -#include "tsage/ringworld_demo.h" -#include "tsage/ringworld_scenes1.h" -#include "tsage/ringworld_scenes2.h" -#include "tsage/ringworld_scenes3.h" -#include "tsage/ringworld_scenes4.h" -#include "tsage/ringworld_scenes5.h" -#include "tsage/ringworld_scenes6.h" -#include "tsage/ringworld_scenes8.h" -#include "tsage/ringworld_scenes10.h" - -namespace tSage { +#include "tsage/ringworld/ringworld_demo.h" +#include "tsage/ringworld/ringworld_scenes1.h" +#include "tsage/ringworld/ringworld_scenes2.h" +#include "tsage/ringworld/ringworld_scenes3.h" +#include "tsage/ringworld/ringworld_scenes4.h" +#include "tsage/ringworld/ringworld_scenes5.h" +#include "tsage/ringworld/ringworld_scenes6.h" +#include "tsage/ringworld/ringworld_scenes8.h" +#include "tsage/ringworld/ringworld_scenes10.h" + +namespace TsAGE { + +namespace Ringworld { Scene *RingworldGame::createScene(int sceneNumber) { switch (sceneNumber) { @@ -1487,4 +1489,6 @@ void RingworldGame::processEvent(Event &event) { } } -} // End of namespace tSage +} // End of namespace Ringworld + +} // End of namespace TsAGE diff --git a/engines/tsage/ringworld_logic.h b/engines/tsage/ringworld/ringworld_logic.h index 19b0f10b42..73ecc9722b 100644 --- a/engines/tsage/ringworld_logic.h +++ b/engines/tsage/ringworld/ringworld_logic.h @@ -29,7 +29,11 @@ #include "tsage/scenes.h" #include "tsage/globals.h" -namespace tSage { +namespace TsAGE { + +namespace Ringworld { + +using namespace TsAGE; #define ADD_PLAYER_MOVER(X, Y) { Common::Point pt(X, Y); PlayerMover *mover = new PlayerMover(); \ _globals->_player.addMover(mover, &pt, this); } @@ -438,7 +442,7 @@ public: virtual Common::String getClassName() { return "RingworldInvObjectList"; } }; -#define RING_INVENTORY (*((RingworldInvObjectList *)_globals->_inventory)) +#define RING_INVENTORY (*((::TsAGE::Ringworld::RingworldInvObjectList *)_globals->_inventory)) class RingworldGame: public Game { protected: @@ -456,6 +460,8 @@ public: virtual void processEvent(Event &event); }; -} // End of namespace tSage +} // End of namespace Ringworld + +} // End of namespace TsAGE #endif diff --git a/engines/tsage/ringworld_scenes1.cpp b/engines/tsage/ringworld/ringworld_scenes1.cpp index f97cfa4ae6..332aef6d8d 100644 --- a/engines/tsage/ringworld_scenes1.cpp +++ b/engines/tsage/ringworld/ringworld_scenes1.cpp @@ -20,12 +20,14 @@ * */ -#include "tsage/ringworld_scenes1.h" +#include "tsage/ringworld/ringworld_scenes1.h" #include "tsage/scenes.h" #include "tsage/tsage.h" #include "tsage/staticres.h" -namespace tSage { +namespace TsAGE { + +namespace Ringworld { /*-------------------------------------------------------------------------- * Scene 10 - Kziniti Palace (Introduction) @@ -3342,4 +3344,6 @@ void Scene6100::showMessage(const Common::String &msg, int color, Action *action } } -} // End of namespace tSage +} // End of namespace Ringworld + +} // End of namespace TsAGE diff --git a/engines/tsage/ringworld_scenes1.h b/engines/tsage/ringworld/ringworld_scenes1.h index 0f9bf61117..49ea65eb3a 100644 --- a/engines/tsage/ringworld_scenes1.h +++ b/engines/tsage/ringworld/ringworld_scenes1.h @@ -24,7 +24,7 @@ #define TSAGE_RINGWORLD_SCENES1_H #include "common/scummsys.h" -#include "tsage/ringworld_logic.h" +#include "tsage/ringworld/ringworld_logic.h" #include "tsage/converse.h" #include "tsage/events.h" #include "tsage/core.h" @@ -32,7 +32,11 @@ #include "tsage/globals.h" #include "tsage/sound.h" -namespace tSage { +namespace TsAGE { + +namespace Ringworld { + +using namespace TsAGE; class Scene10 : public Scene { /* Actions */ @@ -533,6 +537,8 @@ public: }; -} // End of namespace tSage +} // End of namespace Ringworld + +} // End of namespace TsAGE #endif diff --git a/engines/tsage/ringworld_scenes10.cpp b/engines/tsage/ringworld/ringworld_scenes10.cpp index 839fa0f008..df25c324ab 100644 --- a/engines/tsage/ringworld_scenes10.cpp +++ b/engines/tsage/ringworld/ringworld_scenes10.cpp @@ -21,12 +21,14 @@ */ #include "graphics/cursorman.h" -#include "tsage/ringworld_scenes10.h" +#include "tsage/ringworld/ringworld_scenes10.h" #include "tsage/scenes.h" #include "tsage/tsage.h" #include "tsage/staticres.h" -namespace tSage { +namespace TsAGE { + +namespace Ringworld { Scene2::Scene2() : Scene() { _sceneState = 0; @@ -2086,4 +2088,6 @@ void Scene9999::postInit(SceneObjectList *OwnerList) { } -} // End of namespace tSage +} // End of namespace Ringworld + +} // End of namespace TsAGE diff --git a/engines/tsage/ringworld_scenes10.h b/engines/tsage/ringworld/ringworld_scenes10.h index 33b16d0014..02c42f3d01 100644 --- a/engines/tsage/ringworld_scenes10.h +++ b/engines/tsage/ringworld/ringworld_scenes10.h @@ -24,13 +24,17 @@ #define TSAGE_RINGWORLD_SCENES10_H #include "common/scummsys.h" -#include "tsage/ringworld_logic.h" +#include "tsage/ringworld/ringworld_logic.h" #include "tsage/events.h" #include "tsage/core.h" #include "tsage/scenes.h" #include "tsage/globals.h" -namespace tSage { +namespace TsAGE { + +namespace Ringworld { + +using namespace TsAGE; class SceneObject9150 : public SceneObject { public: @@ -526,7 +530,8 @@ public: virtual void postInit(SceneObjectList *OwnerList = NULL); }; +} // End of namespace Ringworld -} // End of namespace tSage +} // End of namespace TsAGE #endif diff --git a/engines/tsage/ringworld_scenes2.cpp b/engines/tsage/ringworld/ringworld_scenes2.cpp index 0154123c3d..cfd3e3d8f7 100644 --- a/engines/tsage/ringworld_scenes2.cpp +++ b/engines/tsage/ringworld/ringworld_scenes2.cpp @@ -21,12 +21,14 @@ */ #include "common/config-manager.h" -#include "tsage/ringworld_scenes2.h" +#include "tsage/ringworld/ringworld_scenes2.h" #include "tsage/scenes.h" #include "tsage/tsage.h" #include "tsage/staticres.h" -namespace tSage { +namespace TsAGE { + +namespace Ringworld { /*-------------------------------------------------------------------------- * Scene 1000 - Title Screen @@ -925,4 +927,6 @@ void Scene1500::postInit(SceneObjectList *OwnerList) { } } -} // End of namespace tSage +} // End of namespace Ringworld + +} // End of namespace TsAGE diff --git a/engines/tsage/ringworld_scenes2.h b/engines/tsage/ringworld/ringworld_scenes2.h index 93a8f04fd4..3502aea15b 100644 --- a/engines/tsage/ringworld_scenes2.h +++ b/engines/tsage/ringworld/ringworld_scenes2.h @@ -24,13 +24,17 @@ #define TSAGE_RINGWORLD_SCENES2_H #include "common/scummsys.h" -#include "tsage/ringworld_logic.h" +#include "tsage/ringworld/ringworld_logic.h" #include "tsage/events.h" #include "tsage/core.h" #include "tsage/scenes.h" #include "tsage/globals.h" -namespace tSage { +namespace TsAGE { + +namespace Ringworld { + +using namespace TsAGE; class Scene1000 : public Scene { /* Actions */ @@ -142,8 +146,8 @@ public: virtual void postInit(SceneObjectList *OwnerList = NULL); }; +} // End of namespace Ringworld - -} // End of namespace tSage +} // End of namespace TsAGE #endif diff --git a/engines/tsage/ringworld_scenes3.cpp b/engines/tsage/ringworld/ringworld_scenes3.cpp index 209144766a..f744a98c33 100644 --- a/engines/tsage/ringworld_scenes3.cpp +++ b/engines/tsage/ringworld/ringworld_scenes3.cpp @@ -21,12 +21,14 @@ */ #include "common/config-manager.h" -#include "tsage/ringworld_scenes3.h" +#include "tsage/ringworld/ringworld_scenes3.h" #include "tsage/scenes.h" #include "tsage/tsage.h" #include "tsage/staticres.h" -namespace tSage { +namespace TsAGE { + +namespace Ringworld { /*-------------------------------------------------------------------------- * Scene 2000 - Cockpit cutscenes @@ -6130,4 +6132,6 @@ void Scene2400::postInit(SceneObjectList *OwnerList) { _globals->_soundHandler.play(153); } -} // End of namespace tSage +} // End of namespace Ringworld + +} // End of namespace TsAGE diff --git a/engines/tsage/ringworld_scenes3.h b/engines/tsage/ringworld/ringworld_scenes3.h index 711360c190..2dbdc27211 100644 --- a/engines/tsage/ringworld_scenes3.h +++ b/engines/tsage/ringworld/ringworld_scenes3.h @@ -26,9 +26,13 @@ #include "common/scummsys.h" #include "tsage/core.h" #include "tsage/converse.h" -#include "tsage/ringworld_logic.h" +#include "tsage/ringworld/ringworld_logic.h" -namespace tSage { +namespace TsAGE { + +namespace Ringworld { + +using namespace TsAGE; class Scene2000 : public Scene { /* Actions */ @@ -890,6 +894,8 @@ public: virtual void postInit(SceneObjectList *OwnerList = NULL); }; -} // End of namespace tSage +} // End of namespace Ringworld + +} // End of namespace TsAGE #endif diff --git a/engines/tsage/ringworld_scenes4.cpp b/engines/tsage/ringworld/ringworld_scenes4.cpp index 838769e4af..0f4c3e49a0 100644 --- a/engines/tsage/ringworld_scenes4.cpp +++ b/engines/tsage/ringworld/ringworld_scenes4.cpp @@ -21,12 +21,14 @@ */ #include "common/config-manager.h" -#include "tsage/ringworld_scenes4.h" +#include "tsage/ringworld/ringworld_scenes4.h" #include "tsage/scenes.h" #include "tsage/tsage.h" #include "tsage/staticres.h" -namespace tSage { +namespace TsAGE { + +namespace Ringworld { /*-------------------------------------------------------------------------- * Scene 3500 - Ringworld Scan @@ -227,7 +229,7 @@ void Scene3700::Action1::signal() { /*--------------------------------------------------------------------------*/ -void Scene3700::postInit(tSage::SceneObjectList *OwnerList) { +void Scene3700::postInit(TsAGE::SceneObjectList *OwnerList) { Scene::postInit(); loadScene(3700); @@ -247,4 +249,6 @@ void Scene3700::postInit(tSage::SceneObjectList *OwnerList) { _globals->_soundHandler.play(195); } -} // End of namespace tSage +} // End of namespace Ringworld + +} // End of namespace TsAGE diff --git a/engines/tsage/ringworld_scenes4.h b/engines/tsage/ringworld/ringworld_scenes4.h index 0b575d02d3..af31de84b9 100644 --- a/engines/tsage/ringworld_scenes4.h +++ b/engines/tsage/ringworld/ringworld_scenes4.h @@ -26,9 +26,13 @@ #include "common/scummsys.h" #include "tsage/core.h" #include "tsage/converse.h" -#include "tsage/ringworld_logic.h" +#include "tsage/ringworld/ringworld_logic.h" -namespace tSage { +namespace TsAGE { + +namespace Ringworld { + +using namespace TsAGE; class Scene3500 : public Scene { /* Actions */ @@ -87,6 +91,8 @@ public: virtual void postInit(SceneObjectList *OwnerList = NULL); }; -} // End of namespace tSage +} // End of namespace Ringworld + +} // End of namespace TsAGE #endif diff --git a/engines/tsage/ringworld_scenes5.cpp b/engines/tsage/ringworld/ringworld_scenes5.cpp index fccc7e1b50..58f47d7f82 100644 --- a/engines/tsage/ringworld_scenes5.cpp +++ b/engines/tsage/ringworld/ringworld_scenes5.cpp @@ -21,12 +21,14 @@ */ #include "common/config-manager.h" -#include "tsage/ringworld_scenes5.h" +#include "tsage/ringworld/ringworld_scenes5.h" #include "tsage/scenes.h" #include "tsage/tsage.h" #include "tsage/staticres.h" -namespace tSage { +namespace TsAGE { + +namespace Ringworld { /*-------------------------------------------------------------------------- * Scene 4000 - Village @@ -3520,7 +3522,7 @@ Scene4250::Scene4250() : _hotspot7(0, CURSOR_LOOK, 4250, 0, LIST_END) { } -void Scene4250::postInit(tSage::SceneObjectList *OwnerList) { +void Scene4250::postInit(TsAGE::SceneObjectList *OwnerList) { loadScene(4250); Scene::postInit(); setZoomPercents(160, 90, 185, 100); @@ -4438,4 +4440,6 @@ void Scene4301::dispatch() { } } -} // End of namespace tSage +} // End of namespace Ringworld + +} // End of namespace TsAGE diff --git a/engines/tsage/ringworld_scenes5.h b/engines/tsage/ringworld/ringworld_scenes5.h index c3ae9f4aa9..6c6b6b6f32 100644 --- a/engines/tsage/ringworld_scenes5.h +++ b/engines/tsage/ringworld/ringworld_scenes5.h @@ -26,9 +26,13 @@ #include "common/scummsys.h" #include "tsage/core.h" #include "tsage/converse.h" -#include "tsage/ringworld_logic.h" +#include "tsage/ringworld/ringworld_logic.h" -namespace tSage { +namespace TsAGE { + +namespace Ringworld { + +using namespace TsAGE; class Scene4000 : public Scene { /* Actions */ @@ -687,7 +691,8 @@ public: } }; +} // End of namespace Ringworld -} // End of namespace tSage +} // End of namespace TsAGE #endif diff --git a/engines/tsage/ringworld_scenes6.cpp b/engines/tsage/ringworld/ringworld_scenes6.cpp index 68c184196c..f21ae59478 100644 --- a/engines/tsage/ringworld_scenes6.cpp +++ b/engines/tsage/ringworld/ringworld_scenes6.cpp @@ -20,12 +20,14 @@ * */ -#include "tsage/ringworld_scenes6.h" +#include "tsage/ringworld/ringworld_scenes6.h" #include "tsage/scenes.h" #include "tsage/tsage.h" #include "tsage/staticres.h" -namespace tSage { +namespace TsAGE { + +namespace Ringworld { /*-------------------------------------------------------------------------- * Scene 5000 - Caverns - Entrance @@ -2196,5 +2198,6 @@ void Scene5300::signal() { } } +} // End of namespace Ringworld -} // End of namespace tSage +} // End of namespace TsAGE diff --git a/engines/tsage/ringworld_scenes6.h b/engines/tsage/ringworld/ringworld_scenes6.h index 2e99f5ab87..79e604a177 100644 --- a/engines/tsage/ringworld_scenes6.h +++ b/engines/tsage/ringworld/ringworld_scenes6.h @@ -24,13 +24,17 @@ #define TSAGE_RINGWORLD_SCENES6_H #include "common/scummsys.h" -#include "tsage/ringworld_logic.h" +#include "tsage/ringworld/ringworld_logic.h" #include "tsage/events.h" #include "tsage/core.h" #include "tsage/scenes.h" #include "tsage/globals.h" -namespace tSage { +namespace TsAGE { + +namespace Ringworld { + +using namespace TsAGE; class Scene5000 : public Scene { /* Actions */ @@ -324,7 +328,8 @@ public: } }; +} // End of namespace Ringworld -} // End of namespace tSage +} // End of namespace TsAGE #endif diff --git a/engines/tsage/ringworld_scenes8.cpp b/engines/tsage/ringworld/ringworld_scenes8.cpp index d0e7491d4a..5f1ff5cdca 100644 --- a/engines/tsage/ringworld_scenes8.cpp +++ b/engines/tsage/ringworld/ringworld_scenes8.cpp @@ -21,12 +21,14 @@ */ #include "graphics/cursorman.h" -#include "tsage/ringworld_scenes8.h" +#include "tsage/ringworld/ringworld_scenes8.h" #include "tsage/scenes.h" #include "tsage/tsage.h" #include "tsage/staticres.h" -namespace tSage { +namespace TsAGE { + +namespace Ringworld { void NamedHotspotMult::synchronize(Serializer &s) { SceneHotspot::synchronize(s); @@ -2542,4 +2544,6 @@ void Scene7700::synchronize(Serializer &s) { } } -} // End of namespace tSage +} // End of namespace Ringworld + +} // End of namespace TsAGE diff --git a/engines/tsage/ringworld_scenes8.h b/engines/tsage/ringworld/ringworld_scenes8.h index fe9560d9d8..4878db5cc8 100644 --- a/engines/tsage/ringworld_scenes8.h +++ b/engines/tsage/ringworld/ringworld_scenes8.h @@ -24,13 +24,17 @@ #define TSAGE_RINGWORLD_SCENES8_H #include "common/scummsys.h" -#include "tsage/ringworld_logic.h" +#include "tsage/ringworld/ringworld_logic.h" #include "tsage/events.h" #include "tsage/core.h" #include "tsage/scenes.h" #include "tsage/globals.h" -namespace tSage { +namespace TsAGE { + +namespace Ringworld { + +using namespace TsAGE; class NamedHotspotMult : public SceneHotspot { public: @@ -485,6 +489,8 @@ public: virtual void synchronize(Serializer &s); }; -} // End of namespace tSage +} // End of namespace Ringworld + +} // End of namespace TsAGE #endif diff --git a/engines/tsage/saveload.cpp b/engines/tsage/saveload.cpp index e07964d443..45e655037d 100644 --- a/engines/tsage/saveload.cpp +++ b/engines/tsage/saveload.cpp @@ -30,7 +30,7 @@ #include "tsage/sound.h" #include "tsage/tsage.h" -namespace tSage { +namespace TsAGE { Saver *_saver; @@ -410,4 +410,4 @@ void Saver::resolveLoadPointers() { error("Could not resolve savegame block pointers"); } -} // End of namespace tSage +} // End of namespace TsAGE diff --git a/engines/tsage/saveload.h b/engines/tsage/saveload.h index ce181cbc8f..03beafed7c 100644 --- a/engines/tsage/saveload.h +++ b/engines/tsage/saveload.h @@ -29,7 +29,7 @@ #include "common/savefile.h" #include "common/serializer.h" -namespace tSage { +namespace TsAGE { typedef void (*SaveNotifierFn)(bool postFlag); @@ -222,6 +222,6 @@ public: extern Saver *_saver; -} // End of namespace tSage +} // End of namespace TsAGE #endif diff --git a/engines/tsage/scenes.cpp b/engines/tsage/scenes.cpp index 9a175ea08f..53e48a1d21 100644 --- a/engines/tsage/scenes.cpp +++ b/engines/tsage/scenes.cpp @@ -22,14 +22,11 @@ #include "tsage/scenes.h" #include "tsage/globals.h" -#include "tsage/ringworld_logic.h" +#include "tsage/ringworld/ringworld_logic.h" #include "tsage/tsage.h" #include "tsage/saveload.h" -namespace tSage { - -// TODO: Doesn't seem to be ever set -const bool _v52C9F = false; +namespace TsAGE { SceneManager::SceneManager() { _scene = NULL; @@ -427,6 +424,11 @@ void Scene::refreshBackground(int xAmount, int yAmount) { (xSectionSrc + 1) * 160, (ySectionSrc + 1) * 100); Rect destBounds(xSectionDest * 160, ySectionDest * 100, (xSectionDest + 1) * 160, (ySectionDest + 1) * 100); + if (_vm->getGameID() == GType_BlueForce) { + // For Blue Force, if the scene has an interface area, exclude it from the copy + srcBounds.bottom = MIN<int16>(srcBounds.bottom, BF_GLOBALS._interfaceY); + destBounds.bottom = MIN<int16>(destBounds.bottom, BF_GLOBALS._interfaceY); + } _backSurface.copyFrom(_backSurface, srcBounds, destBounds); } @@ -504,11 +506,6 @@ void Scene::setZoomPercents(int yStart, int minPercent, int yEnd, int maxPercent _zoomPercents[yEnd++] = minPercent; } -byte *Scene::preloadVisage(int resNum) { - assert(!_v52C9F); - return _resourceManager->getResource(RES_VISAGE, resNum, 9999, false); -} - /*--------------------------------------------------------------------------*/ void Game::execute() { @@ -527,4 +524,4 @@ void Game::execute() { } while (activeFlag && !_vm->shouldQuit()); } -} // End of namespace tSage +} // End of namespace TsAGE diff --git a/engines/tsage/scenes.h b/engines/tsage/scenes.h index 665da585f8..7e8c26f912 100644 --- a/engines/tsage/scenes.h +++ b/engines/tsage/scenes.h @@ -29,7 +29,7 @@ #include "tsage/core.h" #include "tsage/saveload.h" -namespace tSage { +namespace TsAGE { class Scene : public StripCallback { private: @@ -67,7 +67,6 @@ public: void loadBackground(int xAmount, int yAmount); void refreshBackground(int xAmount, int yAmount); void loadSceneData(int sceneNum); - byte *preloadVisage(int resNum); }; class SceneManager : public GameHandler, public SaveListener { @@ -135,6 +134,6 @@ public: virtual void processEvent(Event &event) {} }; -} // End of namespace tSage +} // End of namespace TsAGE #endif diff --git a/engines/tsage/sound.cpp b/engines/tsage/sound.cpp index efffa70574..22aff6cb04 100644 --- a/engines/tsage/sound.cpp +++ b/engines/tsage/sound.cpp @@ -28,7 +28,7 @@ #include "tsage/graphics.h" #include "tsage/tsage.h" -namespace tSage { +namespace TsAGE { static SoundManager *_soundManager = NULL; @@ -2929,4 +2929,4 @@ void SoundBlasterDriver::proc42(int channel, int cmd, int value, int *v1, int *v *v1 = 1; } -} // End of namespace tSage +} // End of namespace TsAGE diff --git a/engines/tsage/sound.h b/engines/tsage/sound.h index 2c9221c27a..9507d22cfb 100644 --- a/engines/tsage/sound.h +++ b/engines/tsage/sound.h @@ -33,7 +33,7 @@ #include "tsage/saveload.h" #include "tsage/core.h" -namespace tSage { +namespace TsAGE { class Sound; @@ -499,6 +499,6 @@ public: }; -} // End of namespace tSage +} // End of namespace TsAGE #endif diff --git a/engines/tsage/staticres.cpp b/engines/tsage/staticres.cpp index 9f36268ce3..deb6fd61a6 100644 --- a/engines/tsage/staticres.cpp +++ b/engines/tsage/staticres.cpp @@ -22,7 +22,7 @@ #include "tsage/staticres.h" -namespace tSage { +namespace TsAGE { const byte CURSOR_ARROW_DATA[] = { 15, 0, 15, 0, 0, 0, 0, 0, 9, 0, @@ -73,7 +73,6 @@ const char *SAVE_ERROR_MSG = "Error occurred saving game. Please do not try to r const char *SAVING_NOT_ALLOWED_MSG = "Saving is not allowed at this time."; const char *RESTORING_NOT_ALLOWED_MSG = "Restoring is not allowed at this time."; const char *RESTART_CONFIRM_MSG = "Do you want to restart your game?"; -const char *WATCH_INTRO_MSG = "Do you wish to watch the introduction?"; const char *INV_EMPTY_MSG = "You have nothing in your possesion."; const char *HELP_MSG = "Ringworld\rRevenge of the Patriarch\x14\rScummVM Version\r\r\ @@ -93,9 +92,16 @@ const char *SOUND_BTN_STRING = "Sound"; const char *RESUME_BTN_STRING = " Resume \rplay"; const char *LOOK_BTN_STRING = "Look"; const char *PICK_BTN_STRING = "Pick"; + + +namespace Ringworld { + +// Dialog resources +const char *WATCH_INTRO_MSG = "Do you wish to watch the introduction?"; const char *START_PLAY_BTN_STRING = " Start Play "; const char *INTRODUCTION_BTN_STRING = "Introduction"; +// Scene specific resources const char *EXIT_MSG = " EXIT "; const char *SCENE6100_CAREFUL = "Be careful! The probe cannot handle too much of that."; const char *SCENE6100_TOUGHER = "Hey! This is tougher than it looks!"; @@ -118,4 +124,26 @@ const char *EXIT_BTN_STRING = "Exit"; const char *DEMO_BTN_STRING = "Demo"; const char *DEMO_RESUME_BTN_STRING = "Resume"; -} // End of namespace tSage +} // End of namespace Ringworld + +namespace BlueForce { + +// Dialog resources +const char *WATCH_INTRO_MSG = "Do you wish to watch the introduction?"; +const char *START_PLAY_BTN_STRING = " Play "; +const char *INTRODUCTION_BTN_STRING = " Watch "; + +// Blue Force general messages +const char *BF_NAME = "Blue Force"; +const char *BF_COPYRIGHT = " Copyright, 1993 Tsunami Media, Inc."; +const char *BF_ALL_RIGHTS_RESERVED = "All Rights Reserved"; +const char *BF_19840518 = "May 18, 1984"; +const char *BF_19840515 = "May 15, 1984"; +const char *BF_3_DAYS = "Three days later"; +const char *BF_11_YEARS = "Eleven years later."; +const char *BF_NEXT_DAY = "The Next Day"; +const char *BF_ACADEMY = "Here we are at the Academy"; + +} // End of namespace BlueForce + +} // End of namespace TsAGE diff --git a/engines/tsage/staticres.h b/engines/tsage/staticres.h index fa93511779..290d627090 100644 --- a/engines/tsage/staticres.h +++ b/engines/tsage/staticres.h @@ -25,7 +25,7 @@ #include "common/scummsys.h" -namespace tSage { +namespace TsAGE { extern const byte CURSOR_ARROW_DATA[]; @@ -40,7 +40,6 @@ extern const char *SAVE_ERROR_MSG; extern const char *SAVING_NOT_ALLOWED_MSG; extern const char *RESTORING_NOT_ALLOWED_MSG; extern const char *RESTART_CONFIRM_MSG; -extern const char *WATCH_INTRO_MSG; // Dialogs extern const char *HELP_MSG; @@ -59,6 +58,11 @@ extern const char *RESUME_BTN_STRING; extern const char *LOOK_BTN_STRING; extern const char *PICK_BTN_STRING; extern const char *INV_EMPTY_MSG; + +namespace Ringworld { + +// Dialog resources +extern const char *WATCH_INTRO_MSG; extern const char *START_PLAY_BTN_STRING; extern const char *INTRODUCTION_BTN_STRING; @@ -86,6 +90,28 @@ extern const char *EXIT_BTN_STRING; extern const char *DEMO_BTN_STRING; extern const char *DEMO_RESUME_BTN_STRING; -} // End of namespace tSage +} // End of namespace Ringworld + +namespace BlueForce { + +// Dialog resources +extern const char *WATCH_INTRO_MSG; +extern const char *START_PLAY_BTN_STRING; +extern const char *INTRODUCTION_BTN_STRING; + +// Blue Force messages +extern const char *BF_NAME; +extern const char *BF_COPYRIGHT; +extern const char *BF_ALL_RIGHTS_RESERVED; +extern const char *BF_19840518; +extern const char *BF_19840515; +extern const char *BF_3_DAYS; +extern const char *BF_11_YEARS; +extern const char *BF_NEXT_DAY; +extern const char *BF_ACADEMY; + +} // End of namespace BlueForce + +} // End of namespace TsAGE #endif diff --git a/engines/tsage/tsage.cpp b/engines/tsage/tsage.cpp index 23a0193b7c..b958933c0c 100644 --- a/engines/tsage/tsage.cpp +++ b/engines/tsage/tsage.cpp @@ -30,7 +30,7 @@ #include "tsage/resources.h" #include "tsage/globals.h" -namespace tSage { +namespace TsAGE { TSageEngine *_vm = NULL; @@ -68,18 +68,22 @@ void TSageEngine::initialize() { if (_vm->getFeatures() & GF_DEMO) { // Add the single library file associated with the demo _resourceManager->addLib(getPrimaryFilename()); + _globals = new Globals(); + } else if (_vm->getGameID() == GType_Ringworld) { _resourceManager->addLib("RING.RLB"); _resourceManager->addLib("TSAGE.RLB"); + _globals = new Globals(); + } else if (_vm->getGameID() == GType_BlueForce) { _resourceManager->addLib("BLUE.RLB"); if (_vm->getFeatures() & GF_FLOPPY) { _resourceManager->addLib("FILES.RLB"); _resourceManager->addLib("TSAGE.RLB"); } + _globals = new BlueForce::BlueForceGlobals(); } - _globals = new Globals(); _globals->gfxManager().setDefaults(); // Setup sound settings @@ -151,4 +155,4 @@ bool TSageEngine::shouldQuit() { return getEventManager()->shouldQuit() || getEventManager()->shouldRTL(); } -} // End of namespace tSage +} // End of namespace TsAGE diff --git a/engines/tsage/tsage.h b/engines/tsage/tsage.h index 805461886a..88175f92ce 100644 --- a/engines/tsage/tsage.h +++ b/engines/tsage/tsage.h @@ -36,7 +36,7 @@ #include "tsage/resources.h" -namespace tSage { +namespace TsAGE { enum { GType_Ringworld = 0, @@ -99,6 +99,6 @@ extern TSageEngine *_vm; #define ALLOCATE(x) _vm->_memoryManager.allocate2(x) #define DEALLOCATE(x) _vm->_memoryManager.deallocate(x) -} // End of namespace tSage +} // End of namespace TsAGE #endif |