diff options
author | Alyssa Milburn | 2011-08-22 20:03:05 +0200 |
---|---|---|
committer | Alyssa Milburn | 2011-08-22 20:03:05 +0200 |
commit | 84063dc9727a9f55e09d39574027beab695680e6 (patch) | |
tree | d71a9599cb550d9f7949a2d3209574064e054d85 /engines | |
parent | c6e89df3d940747a85d447f172e2323c800f5eaf (diff) | |
parent | a39a3eda46aea108a51556f001617ad28d29e520 (diff) | |
download | scummvm-rg350-84063dc9727a9f55e09d39574027beab695680e6.tar.gz scummvm-rg350-84063dc9727a9f55e09d39574027beab695680e6.tar.bz2 scummvm-rg350-84063dc9727a9f55e09d39574027beab695680e6.zip |
Merge remote-tracking branch 'origin/master' into soltys_wip2
Diffstat (limited to 'engines')
527 files changed, 21732 insertions, 13383 deletions
diff --git a/engines/advancedDetector.h b/engines/advancedDetector.h index cbdfdf39d8..c5bfdbd26b 100644 --- a/engines/advancedDetector.h +++ b/engines/advancedDetector.h @@ -161,7 +161,7 @@ protected: * is primarily based on computing and matching MD5 checksums of files. * Since doing that for large files can be slow, it can be restricted * to a subset of all files. - * Typically this will be set to something between 5 and 50 kilobyte, + * Typically this will be set to something between 5 and 50 kilobytes, * but arbitrary non-zero values are possible. The default is 5000. */ uint _md5Bytes; 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 a0736d0cc3..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); @@ -258,12 +281,7 @@ SaveStateDescriptor AgiMetaEngine::querySaveMetaInfos(const char *target, int sl char saveVersion = in->readByte(); if (saveVersion >= 4) { - Graphics::Surface *thumbnail = new Graphics::Surface(); - assert(thumbnail); - if (!Graphics::loadThumbnail(*in, *thumbnail)) { - delete thumbnail; - thumbnail = 0; - } + Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*in); desc.setThumbnail(thumbnail); @@ -482,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_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 002eada65c..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; @@ -355,5 +358,3 @@ private: } // End of namespace Agi #endif - - diff --git a/engines/agi/saveload.cpp b/engines/agi/saveload.cpp index dae3dd42c1..28dd0a53dd 100644 --- a/engines/agi/saveload.cpp +++ b/engines/agi/saveload.cpp @@ -290,11 +290,7 @@ int AgiEngine::loadGame(const char *fileName, bool checkId) { if (saveVersion >= 4) { // We don't need the thumbnail here, so just read it and discard it - Graphics::Surface *thumbnail = new Graphics::Surface(); - assert(thumbnail); - Graphics::loadThumbnail(*in, *thumbnail); - delete thumbnail; - thumbnail = 0; + Graphics::skipThumbnail(*in); in->readUint32BE(); // save date in->readUint16BE(); // save time @@ -478,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/agos.cpp b/engines/agos/agos.cpp index 4d879909c4..97c594684c 100644 --- a/engines/agos/agos.cpp +++ b/engines/agos/agos.cpp @@ -24,13 +24,13 @@ #include "common/file.h" #include "common/fs.h" #include "common/textconsole.h" -#include "common/system.h" #include "engines/util.h" #include "agos/debugger.h" #include "agos/intern.h" #include "agos/agos.h" +#include "agos/midi.h" #include "backends/audiocd/audiocd.h" @@ -541,16 +541,18 @@ Common::Error AGOSEngine::init() { initGraphics(_screenWidth, _screenHeight, getGameType() == GType_FF || getGameType() == GType_PP); + _midi = new MidiPlayer(); + if ((getGameType() == GType_SIMON2 && getPlatform() == Common::kPlatformWindows) || (getGameType() == GType_SIMON1 && getPlatform() == Common::kPlatformWindows) || ((getFeatures() & GF_TALKIE) && getPlatform() == Common::kPlatformAcorn) || (getPlatform() == Common::kPlatformPC)) { - int ret = _midi.open(getGameType()); + int ret = _midi->open(getGameType()); if (ret) warning("MIDI Player init failed: \"%s\"", MidiDriver::getErrorName(ret)); - _midi.setVolume(ConfMan.getInt("music_volume"), ConfMan.getInt("sfx_volume")); + _midi->setVolume(ConfMan.getInt("music_volume"), ConfMan.getInt("sfx_volume")); _midiEnabled = true; } @@ -597,14 +599,14 @@ Common::Error AGOSEngine::init() { if (ConfMan.hasKey("music_mute") && ConfMan.getBool("music_mute") == 1) { _musicPaused = true; if (_midiEnabled) { - _midi.pause(_musicPaused); + _midi->pause(_musicPaused); } _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, 0); } if (ConfMan.hasKey("sfx_mute") && ConfMan.getBool("sfx_mute") == 1) { if (getGameId() == GID_SIMON1DOS) - _midi._enable_sfx = !_midi._enable_sfx; + _midi->_enable_sfx = !_midi->_enable_sfx; else { _effectsPaused = !_effectsPaused; _sound->effectsPause(_effectsPaused); @@ -640,14 +642,12 @@ Common::Error AGOSEngine::init() { // TODO: Use special debug levels instead of the following hack. _debugMode = (gDebugLevel >= 0); - if (gDebugLevel == 2) - _dumpOpcodes = true; - if (gDebugLevel == 3) - _dumpVgaOpcodes = true; - if (gDebugLevel == 4) - _dumpScripts = true; - if (gDebugLevel == 5) - _dumpVgaScripts = true; + switch (gDebugLevel) { + case 2: _dumpOpcodes = true; break; + case 3: _dumpVgaOpcodes = true; break; + case 4: _dumpScripts = true; break; + case 5: _dumpVgaScripts = true; break; + } return Common::kNoError; } @@ -708,7 +708,7 @@ void AGOSEngine_Simon2::setupGame() { _itemMemSize = 20000; _tableMemSize = 100000; // Check whether to use MT-32 MIDI tracks in Simon the Sorcerer 2 - if (getGameType() == GType_SIMON2 && _midi.hasNativeMT32()) + if (getGameType() == GType_SIMON2 && _midi->hasNativeMT32()) _musicIndexBase = (1128 + 612) / 4; else _musicIndexBase = 1128 / 4; @@ -911,6 +911,8 @@ AGOSEngine::~AGOSEngine() { _window6BackScn->free(); delete _window6BackScn; + delete _midi; + free(_firstTimeStruct); free(_pendingDeleteTimeEvent); @@ -938,12 +940,12 @@ void AGOSEngine::pauseEngineIntern(bool pauseIt) { _keyPressed.reset(); _pause = true; - _midi.pause(true); + _midi->pause(true); _mixer->pauseAll(true); } else { _pause = false; - _midi.pause(_musicPaused); + _midi->pause(_musicPaused); _mixer->pauseAll(false); } } @@ -1027,7 +1029,7 @@ void AGOSEngine::syncSoundSettings() { int soundVolumeSFX = ConfMan.getInt("sfx_volume"); if (_midiEnabled) - _midi.setVolume((mute ? 0 : soundVolumeMusic), (mute ? 0 : soundVolumeSFX)); + _midi->setVolume((mute ? 0 : soundVolumeMusic), (mute ? 0 : soundVolumeSFX)); } } // End of namespace AGOS diff --git a/engines/agos/agos.h b/engines/agos/agos.h index aa68a05eee..820bc0260b 100644 --- a/engines/agos/agos.h +++ b/engines/agos/agos.h @@ -33,7 +33,6 @@ #include "common/stack.h" #include "common/util.h" -#include "agos/midi.h" #include "agos/sound.h" #include "agos/vga.h" @@ -50,6 +49,16 @@ * - Simon the Sorcerer 2 * - Simon the Sorcerer Puzzle Pack */ + +namespace Common { +class File; +class SeekableReadStream; +} + +namespace Graphics { +struct Surface; +} + namespace AGOS { uint fileReadItemID(Common::SeekableReadStream *in); @@ -60,6 +69,8 @@ uint fileReadItemID(Common::SeekableReadStream *in); class MoviePlayer; #endif +class MidiPlayer; + struct Child; struct SubObject; @@ -313,7 +324,7 @@ protected: bool _backFlag; uint16 _debugMode; - uint16 _language; + Common::Language _language; bool _copyProtection; bool _pause; bool _dumpScripts; @@ -548,7 +559,7 @@ protected: byte _lettersToPrintBuf[80]; - MidiPlayer _midi; + MidiPlayer *_midi; bool _midiEnabled; int _vgaTickCounter; diff --git a/engines/agos/charset-fontdata.cpp b/engines/agos/charset-fontdata.cpp index b708b4890b..e6b81f54ee 100644 --- a/engines/agos/charset-fontdata.cpp +++ b/engines/agos/charset-fontdata.cpp @@ -20,8 +20,6 @@ * */ - - #include "common/system.h" #include "common/textconsole.h" @@ -2454,4 +2452,3 @@ void AGOSEngine::windowDrawChar(WindowBlock *window, uint x, uint y, byte chr) { } } // End of namespace AGOS - diff --git a/engines/agos/charset.cpp b/engines/agos/charset.cpp index 9d27afaa27..54aef99a47 100644 --- a/engines/agos/charset.cpp +++ b/engines/agos/charset.cpp @@ -20,8 +20,7 @@ * */ - - +#include "common/endian.h" #include "common/system.h" #include "agos/agos.h" @@ -655,4 +654,3 @@ void AGOSEngine::windowScroll(WindowBlock *window) { _videoLockOut &= ~0x8000; } } // End of namespace AGOS - diff --git a/engines/agos/contain.cpp b/engines/agos/contain.cpp index ba60c65ff3..173194d45e 100644 --- a/engines/agos/contain.cpp +++ b/engines/agos/contain.cpp @@ -20,8 +20,6 @@ * */ - - #include "agos/agos.h" #include "agos/intern.h" diff --git a/engines/agos/cursor.cpp b/engines/agos/cursor.cpp index ef4a1406c9..7c64d68048 100644 --- a/engines/agos/cursor.cpp +++ b/engines/agos/cursor.cpp @@ -20,10 +20,8 @@ * */ - - +#include "common/endian.h" #include "common/events.h" -#include "common/system.h" #include "graphics/cursorman.h" diff --git a/engines/agos/debug.cpp b/engines/agos/debug.cpp index 9c44342975..18c4736031 100644 --- a/engines/agos/debug.cpp +++ b/engines/agos/debug.cpp @@ -22,7 +22,6 @@ // AGOS debug functions - #include "common/file.h" #include "common/textconsole.h" diff --git a/engines/agos/debug.h b/engines/agos/debug.h index fd5908997f..fe14ae4860 100644 --- a/engines/agos/debug.h +++ b/engines/agos/debug.h @@ -2843,4 +2843,3 @@ const char *const feeblefiles_videoOpcodeNameTable[] = { } // End of namespace AGOS #endif - diff --git a/engines/agos/debugger.cpp b/engines/agos/debugger.cpp index a313dbbd1e..fc24c6d363 100644 --- a/engines/agos/debugger.cpp +++ b/engines/agos/debugger.cpp @@ -20,12 +20,11 @@ * */ - - #include "common/config-manager.h" #include "agos/debugger.h" #include "agos/agos.h" +#include "agos/midi.h" namespace AGOS { @@ -58,7 +57,7 @@ bool Debugger::Cmd_DebugLevel(int argc, const char **argv) { DebugPrintf("Debugging is currently set at level %d\n", gDebugLevel); } else { // set level gDebugLevel = atoi(argv[1]); - if (gDebugLevel >= 0 && gDebugLevel < 10) { + if (0 <= gDebugLevel && gDebugLevel < 11) { _vm->_debugMode = true; DebugPrintf("Debug level set to level %d\n", gDebugLevel); } else if (gDebugLevel < 0) { @@ -79,7 +78,7 @@ bool Debugger::Cmd_PlayMusic(int argc, const char **argv) { // TODO } else if (_vm->getGameType() == GType_SIMON2) { _vm->loadMusic(music); - _vm->_midi.startTrack(0); + _vm->_midi->startTrack(0); } else { _vm->playMusic(music, 0); } @@ -287,4 +286,3 @@ bool Debugger::Cmd_dumpScript(int argc, const char **argv) { } } // End of namespace AGOS - 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/agos/draw.cpp b/engines/agos/draw.cpp index 4d66b56a96..9fc5cedbf9 100644 --- a/engines/agos/draw.cpp +++ b/engines/agos/draw.cpp @@ -20,8 +20,7 @@ * */ - - +#include "common/endian.h" #include "common/system.h" #include "graphics/surface.h" diff --git a/engines/agos/event.cpp b/engines/agos/event.cpp index 3411e6d632..ed26b96381 100644 --- a/engines/agos/event.cpp +++ b/engines/agos/event.cpp @@ -20,8 +20,6 @@ * */ - - #include "agos/agos.h" #include "agos/animation.h" #include "agos/debugger.h" diff --git a/engines/agos/gfx.cpp b/engines/agos/gfx.cpp index 0b045bae01..fbf7f416ed 100644 --- a/engines/agos/gfx.cpp +++ b/engines/agos/gfx.cpp @@ -20,8 +20,7 @@ * */ - - +#include "common/endian.h" #include "common/system.h" #include "common/textconsole.h" diff --git a/engines/agos/icons.cpp b/engines/agos/icons.cpp index ead4e49ebb..7db2d85f21 100644 --- a/engines/agos/icons.cpp +++ b/engines/agos/icons.cpp @@ -20,8 +20,6 @@ * */ - - #include "common/file.h" #include "common/system.h" #include "common/textconsole.h" diff --git a/engines/agos/input.cpp b/engines/agos/input.cpp index 2ab543a943..24e5339420 100644 --- a/engines/agos/input.cpp +++ b/engines/agos/input.cpp @@ -20,13 +20,12 @@ * */ - - #include "common/config-manager.h" #include "common/file.h" #include "agos/intern.h" #include "agos/agos.h" +#include "agos/midi.h" #include "agos/vga.h" namespace AGOS { @@ -582,14 +581,14 @@ bool AGOSEngine::processSpecialKeys() { break; case '+': if (_midiEnabled) { - _midi.setVolume(_midi.getMusicVolume() + 16, _midi.getSFXVolume() + 16); + _midi->setVolume(_midi->getMusicVolume() + 16, _midi->getSFXVolume() + 16); } ConfMan.setInt("music_volume", _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) + 16); syncSoundSettings(); break; case '-': if (_midiEnabled) { - _midi.setVolume(_midi.getMusicVolume() - 16, _midi.getSFXVolume() - 16); + _midi->setVolume(_midi->getMusicVolume() - 16, _midi->getSFXVolume() - 16); } ConfMan.setInt("music_volume", _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) - 16); syncSoundSettings(); @@ -597,13 +596,13 @@ bool AGOSEngine::processSpecialKeys() { case 'm': _musicPaused = !_musicPaused; if (_midiEnabled) { - _midi.pause(_musicPaused); + _midi->pause(_musicPaused); } syncSoundSettings(); break; case 's': if (getGameId() == GID_SIMON1DOS) { - _midi._enable_sfx = !_midi._enable_sfx; + _midi->_enable_sfx = !_midi->_enable_sfx; } else { _effectsPaused = !_effectsPaused; _sound->effectsPause(_effectsPaused); diff --git a/engines/agos/input_pn.cpp b/engines/agos/input_pn.cpp index 9cc97ff10f..b3a44f2b2f 100644 --- a/engines/agos/input_pn.cpp +++ b/engines/agos/input_pn.cpp @@ -20,8 +20,6 @@ * */ - - #include "agos/agos.h" #include "agos/intern.h" diff --git a/engines/agos/items.cpp b/engines/agos/items.cpp index 0fb873a733..3bb5a132ef 100644 --- a/engines/agos/items.cpp +++ b/engines/agos/items.cpp @@ -20,8 +20,6 @@ * */ - - #include "common/file.h" #include "common/textconsole.h" diff --git a/engines/agos/menus.cpp b/engines/agos/menus.cpp index 4d62e34820..a0d2bdcaa0 100644 --- a/engines/agos/menus.cpp +++ b/engines/agos/menus.cpp @@ -20,8 +20,6 @@ * */ - - #include "common/file.h" #include "common/system.h" #include "common/textconsole.h" diff --git a/engines/agos/midi.cpp b/engines/agos/midi.cpp index 88f6dd80d1..9a93e0a273 100644 --- a/engines/agos/midi.cpp +++ b/engines/agos/midi.cpp @@ -20,14 +20,12 @@ * */ - - #include "common/config-manager.h" #include "common/file.h" -#include "common/system.h" #include "common/textconsole.h" #include "agos/agos.h" +#include "agos/midi.h" namespace AGOS { diff --git a/engines/agos/midiparser_s1d.cpp b/engines/agos/midiparser_s1d.cpp index 01690247f0..9ca87436fc 100644 --- a/engines/agos/midiparser_s1d.cpp +++ b/engines/agos/midiparser_s1d.cpp @@ -31,20 +31,22 @@ namespace AGOS { /** * Simon 1 Demo version of MidiParser. - * - * This parser is the result of eyeballing the one MUS file that's included - * with simon1demo. So there might be some things missing. I've tried to notate - * question-mark areas where they occur. */ class MidiParser_S1D : public MidiParser { -protected: +private: byte *_data; bool _no_delta; + struct Loop { + uint16 timer; + byte *start, *end; + } _loops[16]; + + uint32 readVLQ2(byte *&data); + void chainEvent(EventInfo &info); protected: void parseNextEvent(EventInfo &info); void resetTracking(); - uint32 readVLQ2(byte * &data); public: MidiParser_S1D() : _data(0), _no_delta(false) {} @@ -52,145 +54,128 @@ public: bool loadMusic(byte *data, uint32 size); }; +uint32 MidiParser_S1D::readVLQ2(byte *&data) { + uint32 delta = 0; -// The VLQs for simon1demo seem to be -// in Little Endian format. -uint32 MidiParser_S1D::readVLQ2(byte * &data) { - byte str; - uint32 value = 0; - int i; - - for (i = 0; i < 4; ++i) { - str = data[0]; - ++data; - value |= (str & 0x7F) << (i * 7); - if (!(str & 0x80)) - break; + // LE format VLQ, which is 2 bytes long at max. + delta = *data++; + if (delta & 0x80) { + delta &= 0x7F; + delta |= *data++ << 7; } - return value; + + return delta; +} + +void MidiParser_S1D::chainEvent(EventInfo &info) { + // When we chain an event, we add up the old delta. + uint32 delta = info.delta; + parseNextEvent(info); + info.delta += delta; } void MidiParser_S1D::parseNextEvent(EventInfo &info) { info.start = _position._play_pos; + info.length = 0; info.delta = _no_delta ? 0 : readVLQ2(_position._play_pos); - _no_delta = false; - info.event = *(_position._play_pos++); - if (info.command() < 0x8) { + + info.event = *_position._play_pos++; + if (!(info.event & 0x80)) { _no_delta = true; - info.event += 0x80; + info.event |= 0x80; } - switch (info.command()) { - case 0x8: - info.basic.param1 = *(_position._play_pos++); - info.basic.param2 = 0; - info.length = 0; - break; - - case 0x9: - info.basic.param1 = *(_position._play_pos++); - info.basic.param2 = *(_position._play_pos++); // I'm ASSUMING this byte is velocity! - info.length = 0; - break; - - case 0xA: - case 0xB: - // I'm not sure what these are meant to do, or what the - // parameter is. Elvira 1 needs them, though, and who am I to - // argue with her? - info.basic.param1 = *(_position._play_pos++); - info.basic.param2 = 0; - break; - - case 0xC: - info.basic.param1 = *(_position._play_pos++); - info.basic.param2 = 0; - ++_position._play_pos; // I have NO IDEA what the second byte is for. - break; - - case 0xD: - // Triggered by MOD0/MOD1/MOD2/MOD3/MOD4/MOD6/MOD7/MOD8/MOD9 in Elvira 2 - // Triggered by MOD0/MOD2/MOD3/MOD5/MOD6/MOD7/MOD8/MOD9/MOD10/MOD12/MOD14/MOD15/MOD20 in Waxworks - break; - - case 0xE: - // Triggered by MOD9 in Elvira 1 - // Triggered by MOD3/MOD5 in Elvira 2 - // Triggered by MOD3/MOD7/MOD8/MOD13 in Waxworks - break; - - case 0xF: - switch (info.event & 0x0F) { - case 0x0: - // Trigged by MOD2/MOD6/MOD15 in Waxworks - // Pure guesswork - info.ext.type = *(_position._play_pos++); - info.length = readVLQ(_position._play_pos); - info.ext.data = _position._play_pos; - break; - - case 0x3: // Not sure, Song Select? - // Trigged by MOD1/MOD7/MOD10 in Elvira 1 - info.basic.param1 = *(_position._play_pos++); + if (info.event == 0xFC) { + // This means End of Track. + // Rewrite in SMF (MIDI transmission) form. + info.event = 0xFF; + info.ext.type = 0x2F; + } else { + switch (info.command()) { + case 0x8: // note off + info.basic.param1 = *_position._play_pos++; info.basic.param2 = 0; break; - case 0x4: - // Trigged by MOD8 in Elvira 1 - break; - - case 0x7: - // Trigged by MOD6 in Elvira 2 - // Trigged by MOD5 in Waxworks + case 0x9: // note on + info.basic.param1 = *_position._play_pos++; + info.basic.param2 = *_position._play_pos++; break; - case 0x8: // Not sure, ? - // Trigged by MOD19 in Waxworks - info.basic.param1 = info.basic.param2 = 0; + case 0xA: { // loop control + // In case the stop mode(?) is set to 0x80 this will stop the + // track over here. + + const int16 loopIterations = int8(*_position._play_pos++); + if (!loopIterations) { + _loops[info.channel()].start = _position._play_pos; + } else { + if (!_loops[info.channel()].timer) { + if (_loops[info.channel()].start) { + _loops[info.channel()].timer = uint16(loopIterations); + _loops[info.channel()].end = _position._play_pos; + + // Go to the start of the loop + _position._play_pos = _loops[info.channel()].start; + } + } else { + if (_loops[info.channel()].timer) + _position._play_pos = _loops[info.channel()].start; + --_loops[info.channel()].timer; + } + } + + // We need to read the next midi event here. Since we can not + // safely pass this event to the MIDI event processing. + chainEvent(info); + } break; + + case 0xB: // auto stop marker(?) + // In case the stop mode(?) is set to 0x80 this will stop the + // track. + + // We need to read the next midi event here. Since we can not + // safely pass this event to the MIDI event processing. + chainEvent(info); break; - case 0xA: - // Trigged by MOD5 in Elvira 2 + case 0xC: // program change + info.basic.param1 = *_position._play_pos++; + info.basic.param2 = 0; break; - case 0xC: - // This means End of Track. - // Rewrite in SMF (MIDI transmission) form. - info.event = 0xFF; - info.ext.type = 0x2F; - info.length = 0; - break; + case 0xD: // jump to loop end + if (_loops[info.channel()].end) + _position._play_pos = _loops[info.channel()].end; - case 0xF: // Not sure, META event? - // Trigged by MOD8/MOD9/MOD11/MOD12/MOD13 in Waxworks - info.ext.type = *(_position._play_pos++); - info.length = readVLQ(_position._play_pos); - info.ext.data = _position._play_pos; - _position._play_pos += info.length; + // We need to read the next midi event here. Since we can not + // safely pass this event to the MIDI event processing. + chainEvent(info); break; default: - error("MidiParser_S1D: Unexpected type 0x%02X found", (int) info.event); + // The original called some other function from here, which seems + // not to be MIDI related. + warning("MidiParser_S1D: default case %d", info.channel()); + + // We need to read the next midi event here. Since we can not + // safely pass this event to the MIDI event processing. + chainEvent(info); break; } - break; - default: - error("MidiParser_S1D: Unexpected event 0x%02X found", (int) info.command()); - break; } } bool MidiParser_S1D::loadMusic(byte *data, uint32 size) { unloadMusic(); + // The original actually just ignores the first two bytes. byte *pos = data; if (*(pos++) != 0xFC) debug(1, "Expected 0xFC header but found 0x%02X instead", (int) *pos); - // The next 3 bytes MIGHT be tempo, but we skip them and use the default. -// setTempo (*(pos++) | (*(pos++) << 8) | (*(pos++) << 16)); - pos += 3; + pos += 1; // And now we're at the actual data. Only one track. _num_tracks = 1; @@ -208,7 +193,9 @@ bool MidiParser_S1D::loadMusic(byte *data, uint32 size) { void MidiParser_S1D::resetTracking() { MidiParser::resetTracking(); - _no_delta = false; + // The first event never contains any delta. + _no_delta = true; + memset(_loops, 0, sizeof(_loops)); } MidiParser *MidiParser_createS1D() { return new MidiParser_S1D; } diff --git a/engines/agos/oracle.cpp b/engines/agos/oracle.cpp index 2a3c668c08..025a833b77 100644 --- a/engines/agos/oracle.cpp +++ b/engines/agos/oracle.cpp @@ -25,7 +25,6 @@ #ifdef ENABLE_AGOS2 #include "common/savefile.h" -#include "common/system.h" #include "graphics/surface.h" diff --git a/engines/agos/res_ami.cpp b/engines/agos/res_ami.cpp index b83d10364a..32adfa29e6 100644 --- a/engines/agos/res_ami.cpp +++ b/engines/agos/res_ami.cpp @@ -26,6 +26,8 @@ #include "agos/agos.h" #include "agos/intern.h" +#include "common/endian.h" + namespace AGOS { enum { diff --git a/engines/agos/res_snd.cpp b/engines/agos/res_snd.cpp index 819af4fa40..9a04ce2d26 100644 --- a/engines/agos/res_snd.cpp +++ b/engines/agos/res_snd.cpp @@ -27,12 +27,12 @@ #include "agos/intern.h" #include "agos/agos.h" +#include "agos/midi.h" #include "agos/vga.h" #include "backends/audiocd/audiocd.h" #include "audio/audiostream.h" -#include "audio/mididrv.h" #include "audio/mods/protracker.h" namespace AGOS { @@ -125,10 +125,10 @@ void AGOSEngine::loadMusic(uint16 music) { _gameFile->read(buf, 4); if (!memcmp(buf, "FORM", 4)) { _gameFile->seek(_gameOffsetsPtr[_musicIndexBase + music - 1], SEEK_SET); - _midi.loadXMIDI(_gameFile); + _midi->loadXMIDI(_gameFile); } else { _gameFile->seek(_gameOffsetsPtr[_musicIndexBase + music - 1], SEEK_SET); - _midi.loadMultipleSMF(_gameFile); + _midi->loadMultipleSMF(_gameFile); } _lastMusicPlayed = music; @@ -242,20 +242,20 @@ void AGOSEngine_Simon1::playMusic(uint16 music, uint16 track) { if (music == 35) return; - _midi.setLoop(true); // Must do this BEFORE loading music. (GMF may have its own override.) + _midi->setLoop(true); // Must do this BEFORE loading music. (GMF may have its own override.) _gameFile->seek(_gameOffsetsPtr[_musicIndexBase + music], SEEK_SET); _gameFile->read(buf, 4); if (!memcmp(buf, "GMF\x1", 4)) { _gameFile->seek(_gameOffsetsPtr[_musicIndexBase + music], SEEK_SET); - _midi.loadSMF(_gameFile, music); + _midi->loadSMF(_gameFile, music); } else { _gameFile->seek(_gameOffsetsPtr[_musicIndexBase + music], SEEK_SET); - _midi.loadMultipleSMF(_gameFile); + _midi->loadMultipleSMF(_gameFile); } - _midi.startTrack(0); - _midi.startTrack(track); + _midi->startTrack(0); + _midi->startTrack(track); } else if (getPlatform() == Common::kPlatformAcorn) { // TODO: Add support for Desktop Tracker format in Acorn disk version } else { @@ -266,15 +266,15 @@ void AGOSEngine_Simon1::playMusic(uint16 music, uint16 track) { if (f.isOpen() == false) error("playMusic: Can't load music from '%s'", filename); - _midi.setLoop(true); // Must do this BEFORE loading music. (GMF may have its own override.) + _midi->setLoop(true); // Must do this BEFORE loading music. (GMF may have its own override.) if (getFeatures() & GF_DEMO) - _midi.loadS1D(&f); + _midi->loadS1D(&f); else - _midi.loadSMF(&f, music); + _midi->loadSMF(&f, music); - _midi.startTrack(0); - _midi.startTrack(track); + _midi->startTrack(0); + _midi->startTrack(track); } } @@ -286,7 +286,7 @@ void AGOSEngine::playMusic(uint16 music, uint16 track) { } else if (getPlatform() == Common::kPlatformAtariST) { // TODO: Add support for music formats used } else { - _midi.setLoop(true); // Must do this BEFORE loading music. + _midi->setLoop(true); // Must do this BEFORE loading music. char filename[15]; Common::File f; @@ -295,21 +295,21 @@ void AGOSEngine::playMusic(uint16 music, uint16 track) { if (f.isOpen() == false) error("playMusic: Can't load music from '%s'", filename); - _midi.loadS1D(&f); - _midi.startTrack(0); - _midi.startTrack(track); + _midi->loadS1D(&f); + _midi->startTrack(0); + _midi->startTrack(track); } } void AGOSEngine::stopMusic() { if (_midiEnabled) { - _midi.stop(); + _midi->stop(); } _mixer->stopHandle(_modHandle); } void AGOSEngine::playSting(uint16 soundId) { - if (!_midi._enable_sfx) + if (!_midi->_enable_sfx) return; char filename[15]; @@ -328,8 +328,8 @@ void AGOSEngine::playSting(uint16 soundId) { error("playSting: Can't read sting %d offset", soundId); mus_file.seek(mus_offset, SEEK_SET); - _midi.loadSMF(&mus_file, soundId, true); - _midi.startTrack(0); + _midi->loadSMF(&mus_file, soundId, true); + _midi->startTrack(0); } static const byte elvira1_soundTable[100] = { diff --git a/engines/agos/saveload.cpp b/engines/agos/saveload.cpp index e6cce36b22..10830db002 100644 --- a/engines/agos/saveload.cpp +++ b/engines/agos/saveload.cpp @@ -22,7 +22,6 @@ #include "common/file.h" #include "common/savefile.h" -#include "common/system.h" #include "common/textconsole.h" #include "common/translation.h" diff --git a/engines/agos/script.cpp b/engines/agos/script.cpp index 68a90e405b..1c36454278 100644 --- a/engines/agos/script.cpp +++ b/engines/agos/script.cpp @@ -22,8 +22,7 @@ // Item script opcodes for Simon1/Simon2 - - +#include "common/endian.h" #include "common/system.h" #include "common/textconsole.h" diff --git a/engines/agos/script_dp.cpp b/engines/agos/script_dp.cpp index a4ee249f47..f51e15dc67 100644 --- a/engines/agos/script_dp.cpp +++ b/engines/agos/script_dp.cpp @@ -24,8 +24,6 @@ #ifdef ENABLE_AGOS2 -#include "common/system.h" - #include "agos/agos.h" namespace AGOS { diff --git a/engines/agos/script_pn.cpp b/engines/agos/script_pn.cpp index 3bd8ce19a3..196350b9bf 100644 --- a/engines/agos/script_pn.cpp +++ b/engines/agos/script_pn.cpp @@ -23,6 +23,7 @@ #include "agos/agos.h" #include "agos/vga.h" +#include "common/endian.h" #include "common/textconsole.h" namespace AGOS { diff --git a/engines/agos/script_s1.cpp b/engines/agos/script_s1.cpp index 0e7e66778e..a07c05b4fc 100644 --- a/engines/agos/script_s1.cpp +++ b/engines/agos/script_s1.cpp @@ -20,8 +20,8 @@ * */ - #include "common/system.h" +#include "common/localization.h" #include "graphics/palette.h" @@ -308,34 +308,9 @@ void AGOSEngine_Simon1::os1_pauseGame() { // 135: pause game _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true); - // If all else fails, use English as fallback. - Common::KeyCode keyYes = Common::KEYCODE_y; - Common::KeyCode keyNo = Common::KEYCODE_n; - - switch (_language) { - case Common::RU_RUS: - break; - case Common::PL_POL: - keyYes = Common::KEYCODE_t; - break; - case Common::HE_ISR: - keyYes = Common::KEYCODE_f; - break; - case Common::ES_ESP: - keyYes = Common::KEYCODE_s; - break; - case Common::IT_ITA: - keyYes = Common::KEYCODE_s; - break; - case Common::FR_FRA: - keyYes = Common::KEYCODE_o; - break; - case Common::DE_DEU: - keyYes = Common::KEYCODE_j; - break; - default: - break; - } + Common::KeyCode keyYes, keyNo; + + Common::getLanguageYesNo(_language, keyYes, keyNo); while (!shouldQuit()) { delay(1); diff --git a/engines/agos/script_s2.cpp b/engines/agos/script_s2.cpp index c646397ac3..c35771f8ec 100644 --- a/engines/agos/script_s2.cpp +++ b/engines/agos/script_s2.cpp @@ -23,6 +23,7 @@ #include "agos/agos.h" +#include "agos/midi.h" #include "common/textconsole.h" @@ -342,11 +343,11 @@ void AGOSEngine_Simon2::os2_playTune() { // effectively preloaded so there's no latency when // starting playback). - _midi.setLoop(loop != 0); + _midi->setLoop(loop != 0); if (_lastMusicPlayed != music) _nextMusicToPlay = music; else - _midi.startTrack(track); + _midi->startTrack(track); } void AGOSEngine_Simon2::os2_screenTextPObj() { diff --git a/engines/agos/script_ww.cpp b/engines/agos/script_ww.cpp index 29a91a15aa..873f258743 100644 --- a/engines/agos/script_ww.cpp +++ b/engines/agos/script_ww.cpp @@ -22,8 +22,6 @@ -#include "common/system.h" - #include "agos/agos.h" namespace AGOS { diff --git a/engines/agos/sound.cpp b/engines/agos/sound.cpp index 03932aa4de..11a1cd792e 100644 --- a/engines/agos/sound.cpp +++ b/engines/agos/sound.cpp @@ -22,6 +22,7 @@ #include "common/file.h" #include "common/memstream.h" +#include "common/ptr.h" #include "common/textconsole.h" #include "common/util.h" @@ -43,11 +44,10 @@ namespace AGOS { class BaseSound : Common::NonCopyable { protected: - Common::File *_file; + Common::DisposablePtr<Common::File> _file; uint32 *_offsets; Audio::Mixer *_mixer; bool _freeOffsets; - DisposeAfterUse::Flag _disposeFile; public: BaseSound(Audio::Mixer *mixer, Common::File *file, uint32 base, bool bigEndian, DisposeAfterUse::Flag disposeFileAfterUse = DisposeAfterUse::YES); @@ -62,7 +62,7 @@ public: }; BaseSound::BaseSound(Audio::Mixer *mixer, Common::File *file, uint32 base, bool bigEndian, DisposeAfterUse::Flag disposeFileAfterUse) - : _mixer(mixer), _file(file), _disposeFile(disposeFileAfterUse) { + : _mixer(mixer), _file(file, disposeFileAfterUse) { uint res = 0; uint32 size; @@ -96,7 +96,7 @@ BaseSound::BaseSound(Audio::Mixer *mixer, Common::File *file, uint32 base, bool } BaseSound::BaseSound(Audio::Mixer *mixer, Common::File *file, uint32 *offsets, DisposeAfterUse::Flag disposeFileAfterUse) - : _mixer(mixer), _file(file), _disposeFile(disposeFileAfterUse) { + : _mixer(mixer), _file(file, disposeFileAfterUse) { _offsets = offsets; _freeOffsets = false; @@ -105,8 +105,6 @@ BaseSound::BaseSound(Audio::Mixer *mixer, Common::File *file, uint32 *offsets, D BaseSound::~BaseSound() { if (_freeOffsets) free(_offsets); - if (_disposeFile == DisposeAfterUse::YES) - delete _file; } /////////////////////////////////////////////////////////////////////////////// @@ -234,7 +232,7 @@ Audio::AudioStream *WavSound::makeAudioStream(uint sound) { return NULL; _file->seek(_offsets[sound], SEEK_SET); - return Audio::makeWAVStream(_file, DisposeAfterUse::NO); + return Audio::makeWAVStream(_file.get(), DisposeAfterUse::NO); } void WavSound::playSound(uint sound, uint loopSound, Audio::Mixer::SoundType type, Audio::SoundHandle *handle, bool loop, int vol) { @@ -257,7 +255,7 @@ public: Audio::AudioStream *VocSound::makeAudioStream(uint sound) { assert(_offsets); _file->seek(_offsets[sound], SEEK_SET); - return Audio::makeVOCStream(_file, _flags); + return Audio::makeVOCStream(_file.get(), _flags); } void VocSound::playSound(uint sound, uint loopSound, Audio::Mixer::SoundType type, Audio::SoundHandle *handle, bool loop, int vol) { diff --git a/engines/agos/sound.h b/engines/agos/sound.h index a7c4cd73db..ab4a3a963d 100644 --- a/engines/agos/sound.h +++ b/engines/agos/sound.h @@ -28,6 +28,10 @@ #include "agos/intern.h" #include "common/str.h" +namespace Common { +class File; +} + namespace AGOS { class BaseSound; diff --git a/engines/agos/verb.cpp b/engines/agos/verb.cpp index abc45c1ace..dec05f6703 100644 --- a/engines/agos/verb.cpp +++ b/engines/agos/verb.cpp @@ -22,7 +22,6 @@ // Verb and hitarea handling - #include "common/system.h" #include "graphics/surface.h" diff --git a/engines/agos/vga.cpp b/engines/agos/vga.cpp index de6a6976e5..8541f579d6 100644 --- a/engines/agos/vga.cpp +++ b/engines/agos/vga.cpp @@ -27,6 +27,7 @@ #include "agos/intern.h" #include "agos/vga.h" +#include "common/endian.h" #include "common/system.h" #include "common/textconsole.h" diff --git a/engines/agos/vga_e2.cpp b/engines/agos/vga_e2.cpp index 1bde6945f0..d4aafd3d7b 100644 --- a/engines/agos/vga_e2.cpp +++ b/engines/agos/vga_e2.cpp @@ -26,6 +26,7 @@ #include "agos/agos.h" #include "agos/intern.h" +#include "common/endian.h" #include "common/system.h" #include "graphics/surface.h" diff --git a/engines/agos/vga_s2.cpp b/engines/agos/vga_s2.cpp index 1021ea8f94..9b9ed4e297 100644 --- a/engines/agos/vga_s2.cpp +++ b/engines/agos/vga_s2.cpp @@ -20,10 +20,9 @@ * */ - - #include "agos/agos.h" #include "agos/intern.h" +#include "agos/midi.h" #include "graphics/surface.h" @@ -146,8 +145,8 @@ void AGOSEngine::vc69_playSeq() { // specifying a non-valid track number (999 or -1) // as a means of stopping what music is currently // playing. - _midi.setLoop(loop != 0); - _midi.startTrack(track); + _midi->setLoop(loop != 0); + _midi->startTrack(track); } void AGOSEngine::vc70_joinSeq() { @@ -161,9 +160,9 @@ void AGOSEngine::vc70_joinSeq() { // track and, if not, whether to switch to // a different track upon completion. if (track != 0xFFFF && track != 999) - _midi.queueTrack(track, loop != 0); + _midi->queueTrack(track, loop != 0); else - _midi.setLoop(loop != 0); + _midi->setLoop(loop != 0); } void AGOSEngine::vc71_ifSeqWaiting() { @@ -171,7 +170,7 @@ void AGOSEngine::vc71_ifSeqWaiting() { // This command skips the next instruction // unless (1) there is a track playing, AND // (2) there is a track queued to play after it. - if (!_midi.isPlaying(true)) + if (!_midi->isPlaying(true)) vcSkipNextInstruction(); } @@ -195,8 +194,8 @@ void AGOSEngine::vc72_segue() { if (track == -1 || track == 999) { stopMusic(); } else { - _midi.setLoop(loop != 0); - _midi.startTrack(track); + _midi->setLoop(loop != 0); + _midi->startTrack(track); } } diff --git a/engines/agos/window.cpp b/engines/agos/window.cpp index c55e3dcdda..0365c736d8 100644 --- a/engines/agos/window.cpp +++ b/engines/agos/window.cpp @@ -21,7 +21,6 @@ */ - #include "common/system.h" #include "common/textconsole.h" diff --git a/engines/agos/zones.cpp b/engines/agos/zones.cpp index 61efbcb89a..483b9949eb 100644 --- a/engines/agos/zones.cpp +++ b/engines/agos/zones.cpp @@ -214,5 +214,3 @@ void AGOSEngine::checkZonePtrs() { } } // End of namespace AGOS - - diff --git a/engines/composer/composer.cpp b/engines/composer/composer.cpp new file mode 100644 index 0000000000..d9bb0cdc54 --- /dev/null +++ b/engines/composer/composer.cpp @@ -0,0 +1,515 @@ +/* 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/scummsys.h" + +#include "common/config-manager.h" +#include "common/events.h" +#include "common/file.h" +#include "common/random.h" +#include "common/fs.h" +#include "common/keyboard.h" +#include "common/substream.h" + +#include "graphics/cursorman.h" +#include "graphics/surface.h" +#include "graphics/pixelformat.h" + +#include "engines/util.h" +#include "engines/advancedDetector.h" + +#include "audio/audiostream.h" + +#include "composer/composer.h" +#include "composer/graphics.h" +#include "composer/resource.h" + +namespace Composer { + +ComposerEngine::ComposerEngine(OSystem *syst, const ComposerGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc) { + _rnd = new Common::RandomSource("composer"); + _audioStream = NULL; +} + +ComposerEngine::~ComposerEngine() { + DebugMan.clearAllDebugChannels(); + + for (Common::List<Library>::iterator i = _libraries.begin(); i != _libraries.end(); i++) + delete i->_archive; + for (Common::List<Sprite>::iterator i = _sprites.begin(); i != _sprites.end(); i++) + i->_surface.free(); + + delete _rnd; +} + +Common::Error ComposerEngine::run() { + Common::Event event; + + _vars.resize(1000); + for (uint i = 0; i < _vars.size(); i++) + _vars[i] = 0; + + _queuedScripts.resize(10); + for (uint i = 0; i < _queuedScripts.size(); i++) { + _queuedScripts[i]._count = 0; + _queuedScripts[i]._scriptId = 0; + } + + _mouseVisible = true; + _mouseEnabled = false; + _mouseSpriteId = 0; + _lastButton = NULL; + + _directoriesToStrip = 1; + if (!_bookIni.loadFromFile("book.ini")) { + _directoriesToStrip = 0; + if (!_bookIni.loadFromFile("programs/book.ini")) + error("failed to find book.ini"); + } + + uint width = 640; + if (_bookIni.hasKey("Width", "Common")) + width = atoi(getStringFromConfig("Common", "Width").c_str()); + uint height = 480; + if (_bookIni.hasKey("Height", "Common")) + height = atoi(getStringFromConfig("Common", "Height").c_str()); + initGraphics(width, height, true); + _surface.create(width, height, Graphics::PixelFormat::createFormatCLUT8()); + _needsUpdate = true; + + loadLibrary(0); + + uint fps = atoi(getStringFromConfig("Common", "FPS").c_str()); + uint frameTime = 1000 / fps; + uint32 lastDrawTime = 0; + while (!shouldQuit()) { + for (uint i = 0; i < _pendingPageChanges.size(); i++) { + if (_pendingPageChanges[i]._remove) + unloadLibrary(_pendingPageChanges[i]._pageId); + else + loadLibrary(_pendingPageChanges[i]._pageId); + + lastDrawTime = _system->getMillis(); + } + _pendingPageChanges.clear(); + + uint32 thisTime = _system->getMillis(); + for (uint i = 0; i < _queuedScripts.size(); i++) { + QueuedScript &script = _queuedScripts[i]; + if (!script._count) + continue; + if (script._baseTime + script._duration > thisTime) + continue; + if (script._count != 0xffffffff) + script._count--; + script._baseTime = thisTime; + runScript(script._scriptId, i, 0, 0); + } + + if (lastDrawTime + frameTime <= thisTime) { + // catch up if we're more than 2 frames behind + if (lastDrawTime + (frameTime * 2) <= thisTime) + lastDrawTime = thisTime; + else + lastDrawTime += frameTime; + + redraw(); + + processAnimFrame(); + } else if (_needsUpdate) { + redraw(); + } + + while (_eventMan->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_LBUTTONDOWN: + onMouseDown(event.mouse); + break; + + case Common::EVENT_LBUTTONUP: + break; + + case Common::EVENT_RBUTTONDOWN: + break; + + case Common::EVENT_MOUSEMOVE: + onMouseMove(event.mouse); + break; + + case Common::EVENT_KEYDOWN: + switch (event.kbd.keycode) { + case Common::KEYCODE_d: + /*if (event.kbd.hasFlags(Common::KBD_CTRL)) { + // Start the debugger + getDebugger()->attach(); + getDebugger()->onFrame(); + }*/ + break; + + case Common::KEYCODE_q: + if (event.kbd.hasFlags(Common::KBD_CTRL)) + quitGame(); + break; + + default: + break; + } + + onKeyDown(event.kbd.keycode); + break; + + case Common::EVENT_QUIT: + case Common::EVENT_RTL: + quitGame(); + break; + + default: + break; + } + } + + _system->delayMillis(20); + } + + return Common::kNoError; +} + +void ComposerEngine::onMouseDown(const Common::Point &pos) { + if (!_mouseEnabled || !_mouseVisible) + return; + + const Sprite *sprite = getSpriteAtPos(pos); + const Button *button = getButtonFor(sprite, pos); + if (!button) + return; + + // TODO: other buttons? + uint16 buttonsDown = 1; // MK_LBUTTON + + uint16 spriteId = sprite ? sprite->_id : 0; + runScript(button->_scriptId, button->_id, buttonsDown, spriteId); +} + +void ComposerEngine::onMouseMove(const Common::Point &pos) { + _lastMousePos = pos; + + if (!_mouseEnabled || !_mouseVisible) + return; + + // TODO: do we need to keep track of this? + uint buttonsDown = 0; + + const Sprite *sprite = getSpriteAtPos(pos); + const Button *button = getButtonFor(sprite, pos); + if (_lastButton != button) { + if (_lastButton && _lastButton->_scriptIdRollOff) + runScript(_lastButton->_scriptIdRollOff, _lastButton->_id, buttonsDown, 0); + _lastButton = button; + if (_lastButton && _lastButton->_scriptIdRollOn) + runScript(_lastButton->_scriptIdRollOn, _lastButton->_id, buttonsDown, 0); + } + + if (_mouseSpriteId) { + addSprite(_mouseSpriteId, 0, 0, _lastMousePos - _mouseOffset); + _needsUpdate = true; + } +} + +void ComposerEngine::onKeyDown(uint16 keyCode) { + runEvent(kEventKeyDown, keyCode, 0, 0); + runEvent(kEventChar, keyCode, 0, 0); +} + +void ComposerEngine::setCursor(uint16 id, const Common::Point &offset) { + _mouseOffset = offset; + if (_mouseSpriteId == id) + return; + + if (_mouseSpriteId && _mouseVisible) { + removeSprite(_mouseSpriteId, 0); + } + _mouseSpriteId = id; + if (_mouseSpriteId && _mouseVisible) { + addSprite(_mouseSpriteId, 0, 0, _lastMousePos - _mouseOffset); + } +} + +void ComposerEngine::setCursorVisible(bool visible) { + if (visible && !_mouseVisible) { + _mouseVisible = true; + if (_mouseSpriteId) + addSprite(_mouseSpriteId, 0, 0, _lastMousePos - _mouseOffset); + onMouseMove(_lastMousePos); + } else if (!visible && _mouseVisible) { + _mouseVisible = false; + if (_mouseSpriteId) + removeSprite(_mouseSpriteId, 0); + } +} + +Common::String ComposerEngine::getStringFromConfig(const Common::String §ion, const Common::String &key) { + Common::String value; + if (!_bookIni.getKey(key, section, value)) + error("failed to find key '%s' in section '%s' of book config", key.c_str(), section.c_str()); + return value; +} + +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; + + uint slashesToStrip = _directoriesToStrip; + while (slashesToStrip--) { + for (uint i = 0; i < filename.size(); i++) { + if (filename[i] != '\\') + continue; + filename = filename.c_str() + i + 1; + break; + } + } + + Common::String outFilename; + for (uint i = 0; i < filename.size(); i++) { + if (filename[i] == '\\') + outFilename += '/'; + else + outFilename += filename[i]; + } + return outFilename; +} + +void ComposerEngine::loadLibrary(uint id) { + if (!id) + id = atoi(getStringFromConfig("Common", "StartUp").c_str()); + Common::String filename = getFilename("Libs", id); + + Library library; + + library._id = id; + library._archive = new ComposerArchive(); + if (!library._archive->openFile(filename)) + error("failed to open '%s'", filename.c_str()); + _libraries.push_front(library); + + Library &newLib = _libraries.front(); + + Common::Array<uint16> buttonResources = library._archive->getResourceIDList(ID_BUTN); + 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, getGameType()); + + bool inserted = false; + for (Common::List<Button>::iterator b = newLib._buttons.begin(); b != newLib._buttons.end(); b++) { + if (button._zorder < b->_zorder) + continue; + newLib._buttons.insert(b, button); + inserted = true; + break; + } + if (!inserted) + newLib._buttons.push_back(button); + } + + // add background sprite, if it exists + if (hasResource(ID_BMAP, 1000)) + setBackground(1000); + + // TODO: better CTBL logic + loadCTBL(1000, 100); + + // Run the startup script. + runScript(1000, 0, 0, 0); + + _mouseEnabled = true; + onMouseMove(_lastMousePos); + + runEvent(kEventLoad, id, 0, 0); +} + +void ComposerEngine::unloadLibrary(uint id) { + for (Common::List<Library>::iterator i = _libraries.begin(); i != _libraries.end(); i++) { + if (i->_id != id) + continue; + + for (Common::List<Animation *>::iterator j = _anims.begin(); j != _anims.end(); j++) { + delete *j; + } + _anims.clear(); + for (Common::List<Pipe *>::iterator j = _pipes.begin(); j != _pipes.end(); j++) { + delete *j; + } + _pipes.clear(); + + for (Common::List<Sprite>::iterator j = _sprites.begin(); j != _sprites.end(); j++) { + j->_surface.free(); + } + _sprites.clear(); + i->_buttons.clear(); + + _lastButton = NULL; + + _mixer->stopAll(); + _audioStream = NULL; + + for (uint j = 0; j < _queuedScripts.size(); j++) { + _queuedScripts[j]._count = 0; + _queuedScripts[j]._scriptId = 0; + } + + delete i->_archive; + _libraries.erase(i); + + runEvent(kEventUnload, id, 0, 0); + + return; + } + + error("tried to unload library %d, which isn't loaded", id); +} + +bool ComposerEngine::hasResource(uint32 tag, uint16 id) { + for (Common::List<Library>::iterator i = _libraries.begin(); i != _libraries.end(); i++) + if (i->_archive->hasResource(tag, id)) + return true; + + return false; +} + +Common::SeekableReadStream *ComposerEngine::getResource(uint32 tag, uint16 id) { + for (Common::List<Library>::iterator i = _libraries.begin(); i != _libraries.end(); i++) + if (i->_archive->hasResource(tag, id)) + return i->_archive->getResource(tag, id); + + error("No loaded library contains '%s' %04x", tag2str(tag), 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 %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: + case kButtonEllipse: + if (size != 4) + error("button %d of type %d had %d points, not 4", id, _type, size); + _rect.left = stream->readSint16LE(); + _rect.top = stream->readSint16LE(); + _rect.right = stream->readSint16LE(); + _rect.bottom = stream->readSint16LE(); + break; + case kButtonSprites: + if (gameType == GType_ComposerV1) + error("encountered kButtonSprites in V1 data"); + for (uint i = 0; i < size; i++) { + _spriteIds.push_back(stream->readUint16LE()); + } + break; + default: + error("unknown button type %d", _type); + } + + if (flags & 0x40) { + _scriptIdRollOn = stream->readUint16LE(); + _scriptIdRollOff = stream->readUint16LE(); + } + + delete stream; +} + +bool Button::contains(const Common::Point &pos) const { + switch (_type) { + case kButtonRect: + return _rect.contains(pos); + case kButtonEllipse: + if (!_rect.contains(pos)) + return false; + { + int16 a = _rect.width() / 2; + int16 b = _rect.height() / 2; + if (!a || !b) + return false; + Common::Point adjustedPos = pos - Common::Point(_rect.left + a, _rect.top + b); + return ((adjustedPos.x*adjustedPos.x)/(a*a) + (adjustedPos.y*adjustedPos.y)/(b*b) < 1); + } + case kButtonSprites: + return false; + default: + error("internal error (button type %d)", _type); + } +} + +const Button *ComposerEngine::getButtonFor(const Sprite *sprite, const Common::Point &pos) { + for (Common::List<Library>::iterator l = _libraries.begin(); l != _libraries.end(); l++) { + for (Common::List<Button>::iterator i = l->_buttons.reverse_begin(); i != l->_buttons.end(); --i) { + if (!i->_active) + continue; + + if (i->_spriteIds.empty()) { + if (i->contains(pos)) + return &(*i); + continue; + } + + if (!sprite) + continue; + + for (uint j = 0; j < i->_spriteIds.size(); j++) { + if (i->_spriteIds[j] == sprite->_id) + return &(*i); + } + } + } + + return NULL; +} + +} // End of namespace Composer diff --git a/engines/composer/composer.h b/engines/composer/composer.h new file mode 100644 index 0000000000..c0d456daaa --- /dev/null +++ b/engines/composer/composer.h @@ -0,0 +1,213 @@ +/* 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 COMPOSER_H +#define COMPOSER_H + +#include "common/config-file.h" +#include "common/random.h" +#include "common/system.h" +#include "common/debug.h" +#include "common/debug-channels.h" +#include "common/textconsole.h" +#include "common/rect.h" + +#include "engines/engine.h" +#include "engines/util.h" + +#include "graphics/surface.h" + +#include "audio/mixer.h" + +#include "composer/resource.h" + +namespace Audio { + class QueuingAudioStream; +} + +namespace Composer { + +struct ComposerGameDescription; + +enum GameType { + GType_ComposerV1, + GType_ComposerV2 +}; + +class Archive; +struct Animation; +class ComposerEngine; +class Pipe; +struct Sprite; + +enum { + kButtonRect = 0, + kButtonEllipse = 1, + kButtonSprites = 4 +}; + +class Button { +public: + Button() { } + Button(Common::SeekableReadStream *stream, uint16 id, uint gameType); + + bool contains(const Common::Point &pos) const; + + uint16 _id; + uint16 _type; + uint16 _zorder; + uint16 _scriptId; + uint16 _scriptIdRollOn; + uint16 _scriptIdRollOff; + bool _active; + + Common::Rect _rect; + Common::Array<uint16> _spriteIds; +}; + +enum { + kEventAnimStarted = 1, + kEventAnimDone = 2, + kEventLoad = 3, + kEventUnload = 4, + kEventKeyDown = 5, + kEventChar = 6, + kEventKeyUp = 7 +}; + +struct Library { + uint _id; + Archive *_archive; + + Common::List<Button> _buttons; +}; + +struct QueuedScript { + uint32 _baseTime; + uint32 _duration; + uint32 _count; + uint16 _scriptId; +}; + +struct PendingPageChange { + PendingPageChange() { } + PendingPageChange(uint16 id, bool remove) : _pageId(id), _remove(remove) { } + + uint16 _pageId; + bool _remove; +}; + +class ComposerEngine : public Engine { +protected: + Common::Error run(); + +public: + ComposerEngine(OSystem *syst, const ComposerGameDescription *gameDesc); + virtual ~ComposerEngine(); + + virtual bool hasFeature(EngineFeature f) const; + + int getGameType() const; + const char *getGameId() const; + uint32 getFeatures() const; + Common::Language getLanguage() const; + + const ComposerGameDescription *_gameDescription; + +private: + Common::RandomSource *_rnd; + + Audio::SoundHandle _soundHandle; + Audio::QueuingAudioStream *_audioStream; + uint16 _currSoundPriority; + + bool _needsUpdate; + Common::Array<Common::Rect> _dirtyRects; + Graphics::Surface _surface; + Common::List<Sprite> _sprites; + + uint _directoriesToStrip; + Common::ConfigFile _bookIni; + Common::List<Library> _libraries; + Common::Array<PendingPageChange> _pendingPageChanges; + + Common::Array<uint16> _stack; + Common::Array<uint16> _vars; + + Common::Array<QueuedScript> _queuedScripts; + Common::List<Animation *> _anims; + Common::List<Pipe *> _pipes; + + void onMouseDown(const Common::Point &pos); + void onMouseMove(const Common::Point &pos); + void onKeyDown(uint16 keyCode); + void setCursor(uint16 id, const Common::Point &offset); + void setCursorVisible(bool visible); + + bool _mouseEnabled; + bool _mouseVisible; + Common::Point _lastMousePos; + const Button *_lastButton; + uint16 _mouseSpriteId; + Common::Point _mouseOffset; + + 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); + + bool hasResource(uint32 tag, uint16 id); + Common::SeekableReadStream *getResource(uint32 tag, uint16 id); + + void runEvent(uint16 id, int16 param1, int16 param2, int16 param3); + int16 runScript(uint16 id, int16 param1, int16 param2, int16 param3); + + int16 getArg(uint16 arg, uint16 type); + void setArg(uint16 arg, uint16 type, uint16 val); + void runScript(uint16 id); + int16 scriptFuncCall(uint16 id, int16 param1, int16 param2, int16 param3); + + void playAnimation(uint16 animId, int16 param1, int16 param2, int16 param3); + void stopAnimation(Animation *anim, bool localOnly = false, bool pipesOnly = false); + void playWaveForAnim(uint16 id, uint16 priority, bool bufferingOnly); + void processAnimFrame(); + + bool spriteVisible(uint16 id, uint16 animId); + Sprite *addSprite(uint16 id, uint16 animId, uint16 zorder, const Common::Point &pos); + void removeSprite(uint16 id, uint16 animId); + const Sprite *getSpriteAtPos(const Common::Point &pos); + const Button *getButtonFor(const Sprite *sprite, const Common::Point &pos); + + void dirtySprite(const Sprite &sprite); + void redraw(); + void loadCTBL(uint16 id, uint fadePercent); + void setBackground(uint16 id); + void decompressBitmap(uint16 type, Common::SeekableReadStream *stream, byte *buffer, uint32 size, uint width, uint height); + bool initSprite(Sprite &sprite); + Common::SeekableReadStream *getStreamForSprite(uint16 id); + void drawSprite(const Sprite &sprite); +}; + +} // End of namespace Composer + +#endif diff --git a/engines/composer/detection.cpp b/engines/composer/detection.cpp new file mode 100644 index 0000000000..8c97b6c4db --- /dev/null +++ b/engines/composer/detection.cpp @@ -0,0 +1,233 @@ +/* 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 "base/plugins.h" +#include "engines/advancedDetector.h" + +#include "composer/composer.h" + +namespace Composer { + +struct ComposerGameDescription { + ADGameDescription desc; + + int gameType; +}; + +int ComposerEngine::getGameType() const { + return _gameDescription->gameType; +} + +const char *ComposerEngine::getGameId() const { + return _gameDescription->desc.gameid; +} + +uint32 ComposerEngine::getFeatures() const { + return _gameDescription->desc.flags; +} + +Common::Language ComposerEngine::getLanguage() const { + return _gameDescription->desc.language; +} + +} + +static const PlainGameDescriptor composerGames[] = { + {"composer", "Composer Game"}, + {"darby", "Darby the Dragon"}, + {"gregory", "Gregory and the Hot Air Balloon"}, + {"liam", "Magic Tales: Liam Finds a Story"}, + {"princess", "The Princess and the Crab"}, + {"sleepingcub", "Sleeping Cub's Test of Courage"}, + {0, 0} +}; + +namespace Composer { + +using Common::GUIO_NONE; + +static const ComposerGameDescription gameDescriptions[] = { + // from Liam Finds a Story CD + { + { + "magictales", + "Magic Tales Demo: Baby Yaga, Samurai, Imo", + AD_ENTRY1("book.ini", "dbc98c566f4ac61b544443524585dccb"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_USEEXTRAASTITLE, + Common::GUIO_NONE + }, + GType_ComposerV1 + }, + + { + { + "liam", + 0, + AD_ENTRY1("install.inf", "320d2f1d4f8dd96947676ae25d6688c6"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_ComposerV2 + }, + + // from Liam Finds a Story CD + { + { + "magictales", + "Magic Tales Demo: Sleeping Cub, Princess & Crab", + AD_ENTRY1("book.ini", "3dede2522bb0886c95667b082987a87f"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_USEEXTRAASTITLE, + Common::GUIO_NONE + }, + GType_ComposerV2 + }, + + { + { + "darby", + 0, + AD_ENTRY1("install.inf", "e83cc20ee18a2e138da1aadfc640dff2"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + 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", + 0, + AD_ENTRY1("install.inf", "b7e9d6f7949d412dad0a183375069844"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + 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", + 0, + AD_ENTRY1s("install.inf", "f1cf45db3c4c54a0d2d89d359af8f334", 244), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_ComposerV2 + }, + + { + { + "sleepingcub", + 0, + AD_ENTRY1s("install.inf", "1092e753b8692463f41b8c0b1931398e", 251), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_ComposerV2 + }, + + { AD_TABLE_END_MARKER, 0 } +}; + +} // End of namespace Composer + +using namespace Composer; + +class ComposerMetaEngine : public AdvancedMetaEngine { +public: + ComposerMetaEngine() : AdvancedMetaEngine(Composer::gameDescriptions, sizeof(Composer::ComposerGameDescription), composerGames) { + _singleid = "composer"; + } + + virtual const char *getName() const { + return "Magic Composer Engine"; + } + + virtual const char *getOriginalCopyright() const { + return "Copyright (C) 1995-1999 Animation Magic"; + } + + virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const; + virtual bool hasFeature(MetaEngineFeature f) const; +}; + +bool ComposerMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { + const Composer::ComposerGameDescription *gd = (const Composer::ComposerGameDescription *)desc; + if (gd) { + *engine = new Composer::ComposerEngine(syst, gd); + } + return gd != 0; +} + +bool ComposerMetaEngine::hasFeature(MetaEngineFeature f) const { + return false; +} + +bool Composer::ComposerEngine::hasFeature(EngineFeature f) const { + return (f == kSupportsRTL); +} + +#if PLUGIN_ENABLED_DYNAMIC(COMPOSER) +REGISTER_PLUGIN_DYNAMIC(COMPOSER, PLUGIN_TYPE_ENGINE, ComposerMetaEngine); +#else +REGISTER_PLUGIN_STATIC(COMPOSER, PLUGIN_TYPE_ENGINE, ComposerMetaEngine); +#endif diff --git a/engines/composer/graphics.cpp b/engines/composer/graphics.cpp new file mode 100644 index 0000000000..0768a86e7a --- /dev/null +++ b/engines/composer/graphics.cpp @@ -0,0 +1,774 @@ +/* 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/scummsys.h" + +#include "graphics/palette.h" + +#include "audio/audiostream.h" +#include "audio/decoders/raw.h" + +#include "composer/composer.h" +#include "composer/graphics.h" +#include "composer/resource.h" + +namespace Composer { + +bool Sprite::contains(const Common::Point &pos) const { + Common::Point adjustedPos = pos - _pos; + + if (adjustedPos.x < 0 || adjustedPos.x >= _surface.w) + return false; + if (adjustedPos.y < 0 || adjustedPos.y >= _surface.h) + return false; + byte *pixels = (byte *)_surface.pixels; + return (pixels[(_surface.h - adjustedPos.y - 1) * _surface.w + adjustedPos.x] != 0); +} + +enum { + kAnimOpEvent = 1, + kAnimOpPlayWave = 2, + kAnimOpPlayAnim = 3, + kAnimOpDrawSprite = 4 +}; + +Animation::Animation(Common::SeekableReadStream *stream, uint16 id, Common::Point basePos, uint32 eventParam) + : _stream(stream), _id(id), _basePos(basePos), _eventParam(eventParam) { + uint32 size = _stream->readUint32LE(); + _state = _stream->readUint32LE() + 1; + + // probably total size? + uint32 unknown = _stream->readUint32LE(); + + debug(8, "anim: size %d, state %08x, unknown %08x", size, _state, unknown); + + for (uint i = 0; i < size; i++) { + AnimationEntry entry; + entry.op = _stream->readUint16LE(); + entry.priority = _stream->readUint16LE(); + entry.state = _stream->readUint16LE(); + entry.counter = 0; + entry.prevValue = 0; + debug(8, "anim entry: %04x, %04x, %04x", entry.op, entry.priority, entry.state); + _entries.push_back(entry); + } + + _offset = _stream->pos(); +} + +Animation::~Animation() { + delete _stream; +} + +void Animation::seekToCurrPos() { + _stream->seek(_offset, SEEK_SET); +} + +void ComposerEngine::playAnimation(uint16 animId, int16 x, int16 y, int16 eventParam) { + // First, we check if this animation is already playing, + // and if it is, we sabotage that running one first. + for (Common::List<Animation *>::iterator i = _anims.begin(); i != _anims.end(); i++) { + Animation *anim = *i; + if (anim->_id != animId) + continue; + + stopAnimation(*i); + } + + Common::SeekableReadStream *stream = NULL; + Pipe *newPipe = NULL; + + // First, check the existing pipes. + for (Common::List<Pipe *>::iterator j = _pipes.begin(); j != _pipes.end(); j++) { + Pipe *pipe = *j; + if (!pipe->hasResource(ID_ANIM, animId)) + continue; + stream = pipe->getResource(ID_ANIM, animId, false); + break; + } + + // If we didn't find it, try the libraries. + if (!stream) { + if (!hasResource(ID_ANIM, animId)) { + warning("ignoring attempt to play invalid anim %d", animId); + return; + } + stream = getResource(ID_ANIM, animId); + + uint32 type = 0; + for (Common::List<Library>::iterator i = _libraries.begin(); i != _libraries.end(); i++) + if (i->_archive->hasResource(ID_ANIM, animId)) { + type = i->_archive->getResourceFlags(ID_ANIM, animId); + break; + } + + // If the resource is a pipe itself, then load the pipe + // and then fish the requested animation out of it. + if (type != 1) { + newPipe = new Pipe(stream); + _pipes.push_front(newPipe); + stream = newPipe->getResource(ID_ANIM, animId, false); + } + } + + Animation *anim = new Animation(stream, animId, Common::Point(x, y), eventParam); + _anims.push_back(anim); + runEvent(kEventAnimStarted, animId, eventParam, 0); + if (newPipe) + newPipe->_anim = anim; +} + +void ComposerEngine::stopAnimation(Animation *anim, bool localOnly, bool pipesOnly) { + // disable the animation + anim->_state = 0; + + // stop any animations it may have spawned + for (uint j = 0; j < anim->_entries.size(); j++) { + AnimationEntry &entry = anim->_entries[j]; + if (!entry.prevValue) + continue; + if (localOnly) { + if (pipesOnly) + continue; + if (entry.op == kAnimOpDrawSprite) { + removeSprite(entry.prevValue, anim->_id); + } else if (entry.op == kAnimOpPlayWave) { + if (_currSoundPriority >= entry.priority) { + _mixer->stopAll(); + _audioStream = NULL; + } + } + } else { + if (entry.op != kAnimOpPlayAnim) + continue; + for (Common::List<Animation *>::iterator i = _anims.begin(); i != _anims.end(); i++) { + if ((*i)->_id == entry.prevValue) + stopAnimation(*i); + } + } + } + + // kill any pipe owned by the animation + for (Common::List<Pipe *>::iterator j = _pipes.begin(); j != _pipes.end(); j++) { + Pipe *pipe = *j; + if (pipe->_anim != anim) + continue; + j = _pipes.reverse_erase(j); + delete pipe; + break; + } +} + +void ComposerEngine::playWaveForAnim(uint16 id, uint16 priority, bool bufferingOnly) { + if (_audioStream && _audioStream->numQueuedStreams() != 0) { + if (_currSoundPriority < priority) + return; + if (_currSoundPriority > priority) { + _mixer->stopAll(); + _audioStream = NULL; + } + } + Common::SeekableReadStream *stream = NULL; + if (!bufferingOnly && hasResource(ID_WAVE, id)) { + stream = getResource(ID_WAVE, id); + } else { + for (Common::List<Pipe *>::iterator k = _pipes.begin(); k != _pipes.end(); k++) { + Pipe *pipe = *k; + if (!pipe->hasResource(ID_WAVE, id)) + continue; + stream = pipe->getResource(ID_WAVE, id, true); + break; + } + } + if (!stream) + return; + // FIXME: non-pipe buffers have fixed wav header (data at +44, size at +40) + byte *buffer = (byte *)malloc(stream->size()); + stream->read(buffer, stream->size()); + if (!_audioStream) + _audioStream = Audio::makeQueuingAudioStream(22050, false); + _audioStream->queueBuffer(buffer, stream->size(), DisposeAfterUse::YES, Audio::FLAG_UNSIGNED); + _currSoundPriority = priority; + delete stream; + if (!_mixer->isSoundHandleActive(_soundHandle)) + _mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle, _audioStream); +} + +void ComposerEngine::processAnimFrame() { + for (Common::List<Animation *>::iterator i = _anims.begin(); i != _anims.end(); i++) { + Animation *anim = *i; + + anim->seekToCurrPos(); + + if (anim->_state <= 1) { + bool normalEnd = (anim->_state == 1); + if (normalEnd) { + runEvent(kEventAnimDone, anim->_id, anim->_eventParam, 0); + } + stopAnimation(anim, true, normalEnd); + delete anim; + i = _anims.reverse_erase(i); + + continue; + } + + for (uint j = 0; j < anim->_entries.size(); j++) { + AnimationEntry &entry = anim->_entries[j]; + if (entry.op != kAnimOpEvent) + break; + if (entry.counter) { + entry.counter--; + } else { + if ((anim->_state > 1) && (anim->_stream->pos() + 2 > anim->_stream->size())) { + warning("anim with id %d ended too soon", anim->_id); + anim->_state = 0; + break; + } + + uint16 event = anim->_stream->readUint16LE(); + anim->_offset += 2; + if (event == 0xffff) { + entry.counter = anim->_stream->readUint16LE() - 1; + anim->_offset += 2; + } else { + debug(4, "anim: event %d", event); + runEvent(event, anim->_id, 0, 0); + } + } + } + } + + for (Common::List<Animation *>::iterator i = _anims.begin(); i != _anims.end(); i++) { + Animation *anim = *i; + + // did the anim get disabled? + if (anim->_state == 0) { + stopAnimation(anim, true, false); + delete anim; + i = _anims.reverse_erase(i); + continue; + } + + anim->_state--; + + bool foundWait = false; + for (uint j = 0; j < anim->_entries.size(); j++) { + AnimationEntry &entry = anim->_entries[j]; + + // only skip these at the start + if (!foundWait && (entry.op == kAnimOpEvent)) + continue; + foundWait = true; + + if (entry.counter) { + entry.counter--; + if ((entry.op == kAnimOpPlayWave) && entry.prevValue) { + debug(4, "anim: continue play wave %d", entry.prevValue); + playWaveForAnim(entry.prevValue, entry.priority, true); + } + } else { + anim->seekToCurrPos(); + if ((anim->_state > 1) && (anim->_stream->pos() + 2 > anim->_stream->size())) { + warning("anim with id %d ended too soon", anim->_id); + anim->_state = 0; + break; + } + + uint16 data = anim->_stream->readUint16LE(); + anim->_offset += 2; + if (data == 0xffff) { + entry.counter = anim->_stream->readUint16LE() - 1; + anim->_offset += 2; + } else { + switch (entry.op) { + case kAnimOpEvent: + debug(4, "anim: event %d", data); + runEvent(data, anim->_id, 0, 0); + break; + case kAnimOpPlayWave: + debug(4, "anim: play wave %d", data); + playWaveForAnim(data, entry.priority, false); + break; + case kAnimOpPlayAnim: + debug(4, "anim: play anim %d", data); + playAnimation(data, anim->_basePos.x, anim->_basePos.y, 1); + break; + case kAnimOpDrawSprite: + if (!data || (entry.prevValue && (data != entry.prevValue))) { + debug(4, "anim: erase sprite %d", entry.prevValue); + removeSprite(entry.prevValue, anim->_id); + } + if (data) { + int16 x = anim->_stream->readSint16LE(); + int16 y = anim->_stream->readSint16LE(); + Common::Point pos(x, y); + anim->_offset += 4; + uint16 animId = anim->_id; + if (anim->_state == entry.state) + animId = 0; + debug(4, "anim: draw sprite %d at (relative) %d,%d", data, x, y); + bool wasVisible = spriteVisible(data, animId); + addSprite(data, animId, entry.priority, anim->_basePos + pos); + if (wasVisible) { + // make sure modified sprite isn't removed by another entry + for (uint k = 0; k < anim->_entries.size(); k++) { + if (anim->_entries[k].op != kAnimOpDrawSprite) + continue; + if (anim->_entries[k].prevValue == data) + anim->_entries[k].prevValue = 1; + } + } + } + break; + default: + warning("unknown anim op %d", entry.op); + } + + entry.prevValue = data; + } + } + } + } + + for (Common::List<Pipe *>::iterator j = _pipes.begin(); j != _pipes.end(); j++) { + Pipe *pipe = *j; + pipe->nextFrame(); + } +} + +bool ComposerEngine::spriteVisible(uint16 id, uint16 animId) { + for (Common::List<Sprite>::iterator i = _sprites.begin(); i != _sprites.end(); i++) { + if (i->_id != id) + continue; + if (i->_animId && animId && (i->_animId != animId)) + continue; + return true; + } + + return false; +} + +Sprite *ComposerEngine::addSprite(uint16 id, uint16 animId, uint16 zorder, const Common::Point &pos) { + Sprite sprite; + bool foundSprite = false; + + // re-use old sprite, if any (the BMAP for this id might well have + // changed in the meantime, but the scripts depend on that!) + for (Common::List<Sprite>::iterator i = _sprites.begin(); i != _sprites.end(); i++) { + if (i->_id != id) + continue; + if (i->_animId && animId && (i->_animId != animId)) + continue; + + dirtySprite(*i); + + // if the zordering is identical, modify it in-place + if (i->_zorder == zorder) { + i->_animId = animId; + i->_pos = pos; + dirtySprite(*i); + return &(*i); + } + + // otherwise, take a copy and remove it from the list + sprite = *i; + foundSprite = true; + _sprites.erase(i); + break; + } + + sprite._animId = animId; + sprite._zorder = zorder; + sprite._pos = pos; + + if (!foundSprite) { + sprite._id = id; + if (!initSprite(sprite)) { + debug(1, "ignoring addSprite on invalid sprite %d", id); + return NULL; + } + } + + dirtySprite(sprite); + + for (Common::List<Sprite>::iterator i = _sprites.begin(); i != _sprites.end(); i++) { + if (sprite._zorder <= i->_zorder) + continue; + // insert *before* this sprite + _sprites.insert(i, sprite); + --i; + return &(*i); + } + _sprites.push_back(sprite); + return &_sprites.back(); +} + +void ComposerEngine::removeSprite(uint16 id, uint16 animId) { + for (Common::List<Sprite>::iterator i = _sprites.begin(); i != _sprites.end(); i++) { + if (!i->_id || (id && i->_id != id)) + continue; + if (i->_animId && animId && (i->_animId != animId)) + continue; + dirtySprite(*i); + i->_surface.free(); + i = _sprites.reverse_erase(i); + if (id) + break; + } +} + +const Sprite *ComposerEngine::getSpriteAtPos(const Common::Point &pos) { + for (Common::List<Sprite>::iterator i = _sprites.reverse_begin(); i != _sprites.end(); --i) { + // avoid highest-level objects (e.g. the cursor) + if (!i->_zorder) + continue; + + if (i->contains(pos)) + return &(*i); + } + + return NULL; +} + +void ComposerEngine::dirtySprite(const Sprite &sprite) { + Common::Rect rect(sprite._pos.x, sprite._pos.y, sprite._pos.x + sprite._surface.w, sprite._pos.y + sprite._surface.h); + rect.clip(_surface.w, _surface.h); + if (rect.isEmpty()) + return; + + for (uint i = 0; i < _dirtyRects.size(); i++) { + if (!_dirtyRects[i].intersects(rect)) + continue; + _dirtyRects[i].extend(rect); + return; + } + + _dirtyRects.push_back(rect); +} + +void ComposerEngine::redraw() { + if (!_needsUpdate && _dirtyRects.empty()) + return; + + for (Common::List<Sprite>::iterator i = _sprites.begin(); i != _sprites.end(); i++) { + Common::Rect rect(i->_pos.x, i->_pos.y, i->_pos.x + i->_surface.w, i->_pos.y + i->_surface.h); + bool intersects = false; + for (uint j = 0; j < _dirtyRects.size(); j++) { + if (!_dirtyRects[j].intersects(rect)) + continue; + intersects = true; + break; + } + if (!intersects) + continue; + drawSprite(*i); + } + + for (uint i = 0; i < _dirtyRects.size(); i++) { + const Common::Rect &rect = _dirtyRects[i]; + byte *pixels = (byte *)_surface.pixels + (rect.top * _surface.pitch) + rect.left; + _system->copyRectToScreen(pixels, _surface.pitch, rect.left, rect.top, rect.width(), rect.height()); + } + _system->updateScreen(); + + _needsUpdate = false; + _dirtyRects.clear(); +} + +void ComposerEngine::loadCTBL(uint16 id, uint fadePercent) { + Common::SeekableReadStream *stream = getResource(ID_CTBL, id); + + uint16 numEntries = stream->readUint16LE(); + debug(1, "CTBL: %d entries", numEntries); + + assert(numEntries <= 256); + assert(stream->size() == 2 + (numEntries * 3)); + + byte buffer[256 * 3]; + stream->read(buffer, numEntries * 3); + delete stream; + + for (uint16 i = 0; i < numEntries * 3; i++) + buffer[i] = ((unsigned int)buffer[i] * fadePercent) / 100; + + _system->getPaletteManager()->setPalette(buffer, 0, numEntries); + _needsUpdate = true; +} + +void ComposerEngine::setBackground(uint16 id) { + for (Common::List<Sprite>::iterator i = _sprites.begin(); i != _sprites.end(); i++) { + if (i->_id) + continue; + dirtySprite(*i); + i->_surface.free(); + i->_id = id; + if (!initSprite(*i)) + error("failed to set background %d", id); + dirtySprite(*i); + i->_id = 0; + return; + } + + Sprite *background = addSprite(id, 0, 0xffff, Common::Point()); + if (background) + background->_id = 0; +} + +static void decompressSLWM(byte *buffer, Common::SeekableReadStream *stream) { + uint bitsLeft = 0; + uint16 lastBits; + byte currBit; + while (true) { + if (bitsLeft == 0) { bitsLeft = 16; lastBits = stream->readUint16LE(); } + currBit = (lastBits & 1); lastBits >>= 1; bitsLeft--; + + if (currBit) { + // single byte + *buffer++ = stream->readByte(); + continue; + } + + if (bitsLeft == 0) { bitsLeft = 16; lastBits = stream->readUint16LE(); } + currBit = (lastBits & 1); lastBits >>= 1; bitsLeft--; + + uint start; + uint count; + if (currBit) { + uint orMask = stream->readByte(); + uint in = stream->readByte(); + count = in & 7; + start = ((in & ~7) << 5) | orMask; + if (!count) { + count = stream->readByte(); + if (!count) + break; + count -= 2; + } + } else { + // count encoded in the next two bits + count = 0; + + if (bitsLeft == 0) { bitsLeft = 16; lastBits = stream->readUint16LE(); } + currBit = (lastBits & 1); lastBits >>= 1; bitsLeft--; + + count = (count << 1) | currBit; + + if (bitsLeft == 0) { bitsLeft = 16; lastBits = stream->readUint16LE(); } + currBit = (lastBits & 1); lastBits >>= 1; bitsLeft--; + + count = (count << 1) | currBit; + + start = stream->readByte(); + } + + count += 2; + start++; + for (uint i = 0; i < count; i++) { + *buffer = *(buffer - start); + buffer++; + } + } +} + +// bitmap compression types +enum { + kBitmapUncompressed = 0, + kBitmapSpp32 = 1, + kBitmapSLW8 = 3, + kBitmapRLESLWM = 4, + kBitmapSLWM = 5 +}; + +void ComposerEngine::decompressBitmap(uint16 type, Common::SeekableReadStream *stream, byte *buffer, uint32 size, uint width, uint height) { + uint outSize = width * height; + + switch (type) { + case kBitmapUncompressed: + 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: + byte lookup[16]; + stream->read(lookup, 16); + while (size--) { + uint in = stream->readByte(); + byte lowBits = in & 0xF; + byte highBits = (in & 0xF0) >> 4; + if (highBits == 0xf) { + // 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]; + outSize--; + if (outSize) { + *buffer++ = lookup[lowBits]; + outSize--; + } + } + } + break; + case kBitmapSLW8: + while (size--) { + byte val = stream->readByte(); + if (val != 0xff) { + *buffer++ = val; + continue; + } + uint count = stream->readByte(); + size--; + + uint16 step; + if (!(count & 0x80)) { + step = stream->readByte(); + size--; + } else { + count = (count ^ 0x80); + step = stream->readUint16LE(); + size -= 2; + } + count += 4; + // this is often overlapping (for repeating patterns) + for (uint i = 0; i < count; i++) { + *buffer = *(buffer - step - 1); + buffer++; + } + } + break; + case kBitmapRLESLWM: + { + uint32 bufSize = stream->readUint32LE(); + byte *tempBuf = new byte[bufSize]; + decompressSLWM(tempBuf, stream); + + uint instrPos = tempBuf[0] + 1; + instrPos += READ_LE_UINT16(tempBuf + instrPos) + 2; + byte *instr = tempBuf + instrPos; + + uint line = 0; + while (line++ < height) { + uint pixels = 0; + + while (pixels < width) { + byte data = *instr++; + byte color = tempBuf[(data & 0x7F) + 1]; + if (!(data & 0x80)) { + *buffer++ = color; + pixels++; + } else { + byte count = *instr++; + if (!count) { + while (pixels++ < width) + *buffer++ = color; + break; + } + for (uint i = 0; i < count; i++) { + *buffer++ = color; + pixels++; + } + } + } + } + delete[] tempBuf; + } + break; + case kBitmapSLWM: + decompressSLWM(buffer, stream); + break; + default: + error("decompressBitmap can't handle type %d", type); + } +} + +Common::SeekableReadStream *ComposerEngine::getStreamForSprite(uint16 id) { + for (Common::List<Pipe *>::iterator k = _pipes.begin(); k != _pipes.end(); k++) { + Pipe *pipe = *k; + if (!pipe->hasResource(ID_BMAP, id)) + continue; + return pipe->getResource(ID_BMAP, id, true); + } + if (hasResource(ID_BMAP, id)) + return getResource(ID_BMAP, id); + return NULL; +} + +bool ComposerEngine::initSprite(Sprite &sprite) { + Common::SeekableReadStream *stream = getStreamForSprite(sprite._id); + if (!stream) + return false; + + uint16 type = stream->readUint16LE(); + int16 height = stream->readSint16LE(); + int16 width = stream->readSint16LE(); + uint32 size = stream->readUint32LE(); + debug(1, "loading BMAP: type %d, width %d, height %d, size %d", type, width, height, size); + + if (width > 0 && height > 0) { + sprite._surface.create(width, height, Graphics::PixelFormat::createFormatCLUT8()); + decompressBitmap(type, stream, (byte *)sprite._surface.pixels, size, width, height); + } else { + // there are some sprites (e.g. a -998x-998 one in Gregory's title screen) + // which have an invalid size, but the original engine doesn't notice for + // RLE sprites since the width/height is ignored until the actual draw + if (type != kBitmapRLESLWM) + error("sprite (type %d) had invalid size %dx%d", type, width, height); + delete stream; + return false; + } + delete stream; + + return true; +} + +void ComposerEngine::drawSprite(const Sprite &sprite) { + int x = sprite._pos.x; + int y = sprite._pos.y; + + // incoming data is BMP-style (bottom-up), so flip it + byte *pixels = (byte *)_surface.pixels; + for (int j = 0; j < sprite._surface.h; j++) { + if (j + y < 0) + continue; + if (j + y >= _surface.h) + break; + byte *in = (byte *)sprite._surface.pixels + (sprite._surface.h - j - 1) * sprite._surface.w; + byte *out = pixels + ((j + y) * _surface.w) + x; + for (int i = 0; i < sprite._surface.w; i++) + if ((x + i >= 0) && (x + i < _surface.w) && in[i]) + out[i] = in[i]; + } +} + +} // End of namespace Composer diff --git a/engines/composer/graphics.h b/engines/composer/graphics.h new file mode 100644 index 0000000000..e9d82920ba --- /dev/null +++ b/engines/composer/graphics.h @@ -0,0 +1,71 @@ +/* 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 COMPOSER_GRAPHICS_H +#define COMPOSER_GRAPHICS_H + +#include "common/rect.h" +#include "graphics/surface.h" + +namespace Composer { + +class ComposerEngine; + +struct Sprite { + uint16 _id; + uint16 _animId; + uint16 _zorder; + Common::Point _pos; + Graphics::Surface _surface; + + bool contains(const Common::Point &pos) const; +}; + +struct AnimationEntry { + uint32 state; + uint16 op; + uint16 priority; + uint16 counter; + uint16 prevValue; +}; + +struct Animation { + Animation(Common::SeekableReadStream *stream, uint16 id, Common::Point basePos, uint32 eventParam); + ~Animation(); + + void seekToCurrPos(); + + uint16 _id; + Common::Point _basePos; + uint32 _eventParam; + + uint32 _state; + + Common::Array<AnimationEntry> _entries; + + uint32 _offset; + Common::SeekableReadStream *_stream; +}; + +} // End of namespace Composer + +#endif diff --git a/engines/composer/module.mk b/engines/composer/module.mk new file mode 100644 index 0000000000..8bfaf932e8 --- /dev/null +++ b/engines/composer/module.mk @@ -0,0 +1,16 @@ +MODULE := engines/composer + +MODULE_OBJS = \ + composer.o \ + detection.o \ + graphics.o \ + resource.o \ + scripting.o + +# This module can be built as a plugin +ifeq ($(ENABLE_COMPOSER), DYNAMIC_PLUGIN) +PLUGIN := 1 +endif + +# Include common rules +include $(srcdir)/rules.mk diff --git a/engines/composer/resource.cpp b/engines/composer/resource.cpp new file mode 100644 index 0000000000..b40bdb379b --- /dev/null +++ b/engines/composer/resource.cpp @@ -0,0 +1,337 @@ +/* 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 "composer/resource.h" + +#include "common/debug.h" +#include "common/memstream.h" +#include "common/substream.h" +#include "common/util.h" +#include "common/textconsole.h" + +namespace Composer { + +// Base Archive code +// (copied from clone2727's mohawk code) + +Archive::Archive() { + _stream = 0; +} + +Archive::~Archive() { + close(); +} + +bool Archive::openFile(const Common::String &fileName) { + Common::File *file = new Common::File(); + + if (!file->open(fileName)) { + delete file; + return false; + } + + if (!openStream(file)) { + close(); + return false; + } + + return true; +} + +void Archive::close() { + _types.clear(); + delete _stream; _stream = 0; +} + +bool Archive::hasResource(uint32 tag, uint16 id) const { + if (!_types.contains(tag)) + return false; + + return _types[tag].contains(id); +} + +bool Archive::hasResource(uint32 tag, const Common::String &resName) const { + if (!_types.contains(tag) || resName.empty()) + return false; + + const ResourceMap &resMap = _types[tag]; + + for (ResourceMap::const_iterator it = resMap.begin(); it != resMap.end(); it++) + if (it->_value.name.matchString(resName)) + return true; + + return false; +} + +Common::SeekableReadStream *Archive::getResource(uint32 tag, uint16 id) { + if (!_types.contains(tag)) + error("Archive does not contain '%s' %04x", tag2str(tag), id); + + const ResourceMap &resMap = _types[tag]; + + if (!resMap.contains(id)) + error("Archive does not contain '%s' %04x", tag2str(tag), id); + + const Resource &res = resMap[id]; + + return new Common::SeekableSubReadStream(_stream, res.offset, res.offset + res.size); +} + +uint32 Archive::getResourceFlags(uint32 tag, uint16 id) const { + if (!_types.contains(tag)) + error("Archive does not contain '%s' %04x", tag2str(tag), id); + + const ResourceMap &resMap = _types[tag]; + + if (!resMap.contains(id)) + error("Archive does not contain '%s' %04x", tag2str(tag), id); + + const Resource &res = resMap[id]; + + return res.flags; +} + +uint32 Archive::getOffset(uint32 tag, uint16 id) const { + if (!_types.contains(tag)) + error("Archive does not contain '%s' %04x", tag2str(tag), id); + + const ResourceMap &resMap = _types[tag]; + + if (!resMap.contains(id)) + error("Archive does not contain '%s' %04x", tag2str(tag), id); + + return resMap[id].offset; +} + +uint16 Archive::findResourceID(uint32 tag, const Common::String &resName) const { + if (!_types.contains(tag) || resName.empty()) + return 0xFFFF; + + const ResourceMap &resMap = _types[tag]; + + for (ResourceMap::const_iterator it = resMap.begin(); it != resMap.end(); it++) + if (it->_value.name.matchString(resName)) + return it->_key; + + return 0xFFFF; +} + +Common::String Archive::getName(uint32 tag, uint16 id) const { + if (!_types.contains(tag)) + error("Archive does not contain '%s' %04x", tag2str(tag), id); + + const ResourceMap &resMap = _types[tag]; + + if (!resMap.contains(id)) + error("Archive does not contain '%s' %04x", tag2str(tag), id); + + return resMap[id].name; +} + +Common::Array<uint32> Archive::getResourceTypeList() const { + Common::Array<uint32> typeList; + + for (TypeMap::const_iterator it = _types.begin(); it != _types.end(); it++) + typeList.push_back(it->_key); + + return typeList; +} + +Common::Array<uint16> Archive::getResourceIDList(uint32 type) const { + Common::Array<uint16> idList; + + if (!_types.contains(type)) + return idList; + + const ResourceMap &resMap = _types[type]; + + for (ResourceMap::const_iterator it = resMap.begin(); it != resMap.end(); it++) + idList.push_back(it->_key); + + return idList; +} + +// Composer Archive code + +bool ComposerArchive::openStream(Common::SeekableReadStream *stream) { + // Make sure no other file is open... + close(); + + bool newStyle = false; + uint32 headerSize = stream->readUint32LE(); + if (headerSize == SWAP_CONSTANT_32(ID_LBRC)) { + // new-style file + newStyle = true; + headerSize = stream->readUint32LE(); + uint32 zeros = stream->readUint32LE(); + if (zeros != 0) + error("invalid LBRC header (%d instead of zeros)", zeros); + } + + uint16 numResourceTypes = stream->readUint16LE(); + if (newStyle) { + uint16 unknown = stream->readUint16LE(); + debug(4, "skipping unknown %04x", unknown); + } + + debug(4, "Reading LBRC resource table with %d entries", numResourceTypes); + for (uint i = 0; i < numResourceTypes; i++) { + uint32 tag = stream->readUint32BE(); + uint32 tableOffset = stream->readUint32LE(); + debug(4, "Type '%s' at offset %d", tag2str(tag), tableOffset); + // starting from the start of the resource table, which differs + // according to whether we have the 10 extra bytes for newStyle + if (newStyle) + tableOffset += 16; + else + tableOffset += 6; + + ResourceMap &resMap = _types[tag]; + + uint32 oldPos = stream->pos(); + stream->seek(tableOffset); + + while (true) { + if (stream->eos()) + error("LBRC file ran out of stream"); + + uint32 offset, size, id, flags; + if (newStyle) { + offset = stream->readUint32LE(); + if (!offset) + break; + size = stream->readUint32LE(); + id = stream->readUint16LE(); + flags = stream->readUint16LE(); // set to 1 for preload, otherwise no preload + /*uint32 junk = */ stream->readUint32LE(); + } else { + id = stream->readUint16LE(); + if (!id) + break; + offset = stream->readUint32LE(); + offset += headerSize; + size = stream->readUint32LE(); + flags = stream->readUint16LE(); // FIXME + + } + + Resource &res = resMap[id]; + res.offset = offset; + res.size = size; + res.flags = flags; + debug(4, "Id %d, offset %d, size %d, flags %08x", id, offset, size, flags); + } + + stream->seek(oldPos); + } + + _stream = stream; + return true; +} + +Pipe::Pipe(Common::SeekableReadStream *stream) { + _offset = 0; + _stream = stream; + _anim = NULL; + + nextFrame(); +} + +void Pipe::nextFrame() { + if (_offset == (uint)_stream->size()) + return; + + _stream->seek(_offset, SEEK_SET); + + uint32 tagCount = _stream->readUint32LE(); + _offset += 4; + for (uint i = 0; i < tagCount; i++) { + uint32 tag = _stream->readUint32BE(); + uint32 count = _stream->readUint32LE(); + _offset += 8; + + ResourceMap &resMap = _types[tag]; + + _offset += (12 * count); + for (uint j = 0; j < count; j++) { + uint32 offset = _stream->readUint32LE(); + uint32 size = _stream->readUint32LE(); + uint16 id = _stream->readUint16LE(); + uint32 unknown = _stream->readUint16LE(); // frame id? + debug(9, "pipe: %s/%d: offset %d, size %d, unknown %d", tag2str(tag), id, offset, size, unknown); + + PipeResourceEntry entry; + entry.size = size; + entry.offset = _offset; + resMap[id].entries.push_back(entry); + + _offset += size; + } + _stream->seek(_offset, SEEK_SET); + } +} + +bool Pipe::hasResource(uint32 tag, uint16 id) const { + if (!_types.contains(tag)) + return false; + + return _types[tag].contains(id); +} + +Common::SeekableReadStream *Pipe::getResource(uint32 tag, uint16 id, bool buffering) { + if (!_types.contains(tag)) + error("Pipe does not contain '%s' %04x", tag2str(tag), id); + + const ResourceMap &resMap = _types[tag]; + + if (!resMap.contains(id)) + error("Archive does not contain '%s' %04x", tag2str(tag), id); + + const PipeResource &res = resMap[id]; + + if (res.entries.size() == 1) { + Common::SeekableReadStream *stream = new Common::SeekableSubReadStream(_stream, + res.entries[0].offset, res.entries[0].offset + res.entries[0].size); + if (buffering) + _types[tag].erase(id); + return stream; + } + + // If there are multiple entries in the pipe, we have to concaternate them together. + + uint32 size = 0; + for (uint i = 0; i < res.entries.size(); i++) + size += res.entries[i].size; + + byte *buffer = (byte *)malloc(size); + uint32 offset = 0; + for (uint i = 0; i < res.entries.size(); i++) { + _stream->seek(res.entries[i].offset, SEEK_SET); + _stream->read(buffer + offset, res.entries[i].size); + offset += res.entries[i].size; + } + if (buffering) + _types[tag].erase(id); + return new Common::MemoryReadStream(buffer, size, DisposeAfterUse::YES); +} + +} // End of namespace Composer diff --git a/engines/composer/resource.h b/engines/composer/resource.h new file mode 100644 index 0000000000..9408cdffb8 --- /dev/null +++ b/engines/composer/resource.h @@ -0,0 +1,124 @@ +/* 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/scummsys.h" +#include "common/endian.h" +#include "common/hashmap.h" +#include "common/file.h" +#include "common/str.h" + +#ifndef COMPOSER_RESOURCE_H +#define COMPOSER_RESOURCE_H + +namespace Composer { + +struct Animation; + +#define ID_LBRC MKTAG('L','B','R','C') // Main FourCC + +#define ID_ANIM MKTAG('A','N','I','M') // Animation +#define ID_BMAP MKTAG('B','M','A','P') // Bitmap +#define ID_BUTN MKTAG('B','U','T','N') // Button +#define ID_CTBL MKTAG('C','T','B','L') // Color Table +#define ID_EVNT MKTAG('E','V','N','T') // Event +#define ID_PIPE MKTAG('P','I','P','E') // Pipe +#define ID_SCRP MKTAG('S','C','R','P') // Script +#define ID_VARI MKTAG('V','A','R','I') // Variables +#define ID_WAVE MKTAG('W','A','V','E') // Wave + +class Archive { +public: + Archive(); + virtual ~Archive(); + + bool openFile(const Common::String &fileName); + virtual bool openStream(Common::SeekableReadStream *stream) = 0; + void close(); + + bool isOpen() const { return _stream != 0; } + + bool hasResource(uint32 tag, uint16 id) const; + bool hasResource(uint32 tag, const Common::String &resName) const; + Common::SeekableReadStream *getResource(uint32 tag, uint16 id); + uint32 getResourceFlags(uint32 tag, uint16 id) const; + uint32 getOffset(uint32 tag, uint16 id) const; + uint16 findResourceID(uint32 tag, const Common::String &resName) const; + Common::String getName(uint32 tag, uint16 id) const; + + Common::Array<uint32> getResourceTypeList() const; + Common::Array<uint16> getResourceIDList(uint32 type) const; + +protected: + Common::SeekableReadStream *_stream; + + struct Resource { + uint32 offset; + uint32 size; + Common::String name; + uint32 flags; + }; + + typedef Common::HashMap<uint16, Resource> ResourceMap; + typedef Common::HashMap<uint32, ResourceMap> TypeMap; + TypeMap _types; +}; + +class ComposerArchive : public Archive { +public: + ComposerArchive() : Archive() {} + ~ComposerArchive() {} + + bool openStream(Common::SeekableReadStream *stream); +}; + +struct PipeResourceEntry { + uint32 size; + uint32 offset; +}; + +struct PipeResource { + Common::Array<PipeResourceEntry> entries; +}; + +class Pipe { +public: + Pipe(Common::SeekableReadStream *stream); + void nextFrame(); + + Animation *_anim; + + bool hasResource(uint32 tag, uint16 id) const; + Common::SeekableReadStream *getResource(uint32 tag, uint16 id, bool buffering); + +protected: + Common::SeekableReadStream *_stream; + + typedef Common::HashMap<uint16, PipeResource> ResourceMap; + typedef Common::HashMap<uint32, ResourceMap> TypeMap; + TypeMap _types; + + uint32 _offset; +}; + +} // End of namespace Composer + +#endif diff --git a/engines/composer/scripting.cpp b/engines/composer/scripting.cpp new file mode 100644 index 0000000000..d85bd524e0 --- /dev/null +++ b/engines/composer/scripting.cpp @@ -0,0 +1,729 @@ +/* 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/scummsys.h" +#include "common/savefile.h" + +#include "composer/composer.h" +#include "composer/graphics.h" +#include "composer/resource.h" + +namespace Composer { + +// new script ops +enum { + kOpPlusPlus = 0x1, + kOpMinusMinus = 0x2, + kOpAssign = 0x3, + kOpAdd = 0x4, + kOpSubtract = 0x5, + kOpMultiply = 0x6, + kOpDivide = 0x7, + kOpModulo = 0x8, + kOpMaybeAlsoAssign = 0x9, + kOpBooleanAssign = 0xA, + kOpNegate = 0xB, + kOpAnd = 0xC, + kOpOr = 0xD, + kOpXor = 0xE, + kOpNot = 0xF, + kOpSqrt = 0x10, + kOpRandom = 0x11, + kOpExecuteScript = 0x12, + kOpCallFunc = 0x13, + kOpBoolLessThanEq = 0x17, + kOpBoolLessThan = 0x16, + kOpBoolGreaterThanEq = 0x15, + kOpBoolGreaterThan = 0x14, + kOpBoolEqual = 0x18, + kOpBoolNotEqual = 0x19, + kOpSaveArgs = 0x1A, + kOpRestoreArgs = 0x1B, + kOpReturn = 0x20, + kOpLessThanEq = 0x22, + kOpLessThan = 0x21, + kOpGreaterThanEq = 0x24, + kOpGreaterThan = 0x23, + kOpEqual = 0x25, + kOpNotEqual = 0x26, + kOpJump = 0x80, + kOpJumpIfNot = 0x81, + kOpJumpIf = 0x82, + kOpJumpIfNotValue = 0x83, + kOpJumpIfValue = 0x84 +}; + +enum { + kFuncPlayAnim = 35001, + kFuncStopAnim = 35002, + // (no 35003) + kFuncQueueScript = 35004, + kFuncDequeueScript = 35005, + kFuncSetCursor = 35006, + kFuncGetCursor = 35007, + kFuncShowCursor = 35008, + kFuncHideCursor = 35009, + // (no 35010) + kFuncActivateButton = 35011, + kFuncDeactivateButton = 35012, + kFuncNewPage = 35013, + kFuncLoadPage = 35014, + kFuncUnloadPage = 35015, + kFuncSetPalette = 35016, + kFuncSaveVars = 35017, + kFuncLoadVars = 35018, + kFuncQueueScriptOnce = 35019, + kFuncGetMousePos = 35020, + kFuncChangeBackground = 35021, + kFuncSetBackgroundColor = 35022, + kFuncClearSprites = 35023, + kFuncAddSprite = 35024, + kFuncRemoveSprite = 35025, + kFuncQuit = 35026, + kFuncSaveData = 35027, + kFuncLoadData = 35028, + kFuncGetSpriteSize = 35029 +}; + +void ComposerEngine::runEvent(uint16 id, int16 param1, int16 param2, int16 param3) { + if (!hasResource(ID_EVNT, id)) + return; + + Common::SeekableReadStream *stream = getResource(ID_EVNT, id); + if (stream->size() != 2) + error("bad EVNT size %d", stream->size()); + uint16 scriptId = stream->readUint16LE(); + delete stream; + + if (!scriptId) + return; + + debug(2, "running event %d via script %d(%d, %d, %d)", id, scriptId, param1, param2, param3); + + runScript(scriptId, param1, param2, param3); +} + +int16 ComposerEngine::runScript(uint16 id, int16 param1, int16 param2, int16 param3) { + _vars[1] = param1; + _vars[2] = param2; + _vars[3] = param3; + + runScript(id); + + return _vars[0]; +} + +int16 ComposerEngine::getArg(uint16 arg, uint16 type) { + switch (type) { + case 0: + return (int16)arg; + case 1: + return (int16)_vars[arg]; + case 2: + return (int16)_vars[_vars[arg]]; + default: + error("invalid argument type %d (getting arg %d)", type, arg); + } +} + +void ComposerEngine::setArg(uint16 arg, uint16 type, uint16 val) { + switch (type) { + case 1: + _vars[arg] = val; + break; + case 2: + _vars[_vars[arg]] = val; + break; + default: + error("invalid argument type %d (setting arg %d)", type, arg); + } + +} + +void ComposerEngine::runScript(uint16 id) { + if (!hasResource(ID_SCRP, id)) { + warning("ignoring attempt to run script %d, because it doesn't exist", id); + return; + } + + uint stackBase = _stack.size(); + _stack.resize(_stack.size() + 19); + + Common::SeekableReadStream *stream = getResource(ID_SCRP, id); + if (stream->size() < 2) + error("SCRP was too small (%d)", stream->size()); + uint16 size = stream->readUint16LE(); + if (stream->size() < 2 + 2*size) + error("SCRP was too small (%d, but claimed %d entries)", stream->size(), size); + uint16 *script = new uint16[size]; + for (uint i = 0; i < size; i++) + script[i] = stream->readUint16LE(); + delete stream; + + uint16 pos = 0; + bool lastResult = false; + while (pos < size) { + int16 val1, val2, val3; + + byte op = (byte)script[pos]; + uint numParams = (script[pos] & 0x300) >> 8; // 2 bits + if (pos + numParams >= size) + error("script ran out of content"); + uint arg1 = (script[pos] & 0xc00) >> 10; // 2 bits + uint arg2 = (script[pos] & 0x3000) >> 12; // 2 bits + uint arg3 = (script[pos] & 0xC000) >> 14; // 2 bits + switch (op) { + case kOpPlusPlus: + if (numParams != 1) + error("kOpPlusPlus had wrong number of params (%d)", numParams); + val1 = getArg(script[pos + 1], arg1); + debug(9, "[%d/%d]++ (now %d)", script[pos + 1], arg1, val1 + 1); + setArg(script[pos + 1], arg1, val1 + 1); + break; + case kOpMinusMinus: + if (numParams != 1) + error("kOpMinusMinus had wrong number of params (%d)", numParams); + val1 = getArg(script[pos + 1], arg1); + debug(9, "[%d/%d]-- (now %d)", script[pos + 1], arg1, val1 - 1); + setArg(script[pos + 1], arg1, val1 - 1); + break; + case kOpAssign: + if (numParams != 2) + error("kOpAssign had wrong number of params (%d)", numParams); + val2 = getArg(script[pos + 2], arg2); + debug(9, "[%d/%d] = [%d/%d] (%d)", script[pos + 1], arg1, script[pos + 2], arg2, val2); + setArg(script[pos + 1], arg1, val2); + break; + case kOpAdd: + if (numParams != 3) + error("kOpAdd had wrong number of params (%d)", numParams); + val2 = getArg(script[pos + 2], arg2); + val3 = getArg(script[pos + 3], arg3); + debug(9, "[%d/%d] = [%d/%d]=%d + [%d/%d]=%d (%d)", script[pos + 1], arg1, script[pos + 2], arg2, val2, script[pos+3], arg3, val3, val2 + val3); + setArg(script[pos + 1], arg1, val2 + val3); + break; + case kOpSubtract: + if (numParams != 3) + error("kOpSubtract had wrong number of params (%d)", numParams); + val2 = getArg(script[pos + 2], arg2); + val3 = getArg(script[pos + 3], arg3); + debug(9, "[%d/%d] = [%d/%d]=%d - [%d/%d]=%d (%d)", script[pos + 1], arg1, script[pos + 2], arg2, val2, script[pos+3], arg3, val3, val2 - val3); + setArg(script[pos + 1], arg1, val2 - val3); + break; + case kOpMultiply: + if (numParams != 3) + error("kOpMultiply had wrong number of params (%d)", numParams); + val2 = getArg(script[pos + 2], arg2); + val3 = getArg(script[pos + 3], arg3); + debug(9, "[%d/%d] = [%d/%d]=%d * [%d/%d]=%d (%d)", script[pos + 1], arg1, script[pos + 2], arg2, val2, script[pos+3], arg3, val3, val2 * val3); + setArg(script[pos + 1], arg1, val2 * val3); + break; + case kOpDivide: + if (numParams != 3) + error("kOpDivide had wrong number of params (%d)", numParams); + val2 = getArg(script[pos + 2], arg2); + val3 = getArg(script[pos + 3], arg3); + if (val3 == 0) + error("script tried to divide by zero"); + debug(9, "[%d/%d] = [%d/%d]=%d / [%d/%d]=%d (%d)", script[pos + 1], arg1, script[pos + 2], arg2, val2, script[pos+3], arg3, val3, val2 / val3); + setArg(script[pos + 1], arg1, val2 / val3); + break; + case kOpModulo: + if (numParams != 3) + error("kOpModulo had wrong number of params (%d)", numParams); + val2 = getArg(script[pos + 2], arg2); + val3 = getArg(script[pos + 3], arg3); + if (val3 == 0) + error("script tried to divide by zero (modulo)"); + debug(9, "[%d/%d] = [%d/%d]=%d %% [%d/%d]=%d (%d)", script[pos + 1], arg1, script[pos + 2], arg2, val2, script[pos+3], arg3, val3, val2 % val3); + setArg(script[pos + 1], arg1, val2 % val3); + break; + case kOpMaybeAlsoAssign: + if (numParams != 2) + error("kOpMaybeAlsoAssign had wrong number of params (%d)", numParams); + val2 = getArg(script[pos + 2], arg2); + debug(9, "[%d/%d] =(?) [%d/%d] (%d)", script[pos + 1], arg1, script[pos + 2], arg2, val2); + setArg(script[pos + 1], arg1, val2); + break; + case kOpBooleanAssign: + if (numParams != 2) + error("kOpBooleanAssign had wrong number of params (%d)", numParams); + val2 = getArg(script[pos + 2], arg2); + debug(9, "[%d/%d] = [%d/%d] (%d) ? 1 : 0", script[pos + 1], arg1, script[pos + 2], arg2, val2); + setArg(script[pos + 1], arg1, val2 ? 1 : 0); + break; + case kOpNegate: + if (numParams != 2) + error("kOpNegate had wrong number of params (%d)", numParams); + val2 = getArg(script[pos + 2], arg2); + debug(9, "[%d/%d] = -[%d/%d] (%d)", script[pos + 1], arg1, script[pos + 2], arg2, val2); + setArg(script[pos + 1], arg1, -val2); + break; + case kOpAnd: + if (numParams != 3) + error("kOpAnd had wrong number of params (%d)", numParams); + val2 = getArg(script[pos + 2], arg2); + val3 = getArg(script[pos + 3], arg3); + debug(9, "[%d/%d] = [%d/%d]=%d & [%d/%d]=%d (%d)", script[pos + 1], arg1, script[pos + 2], arg2, val2, script[pos+3], arg3, val3, val2 & val3); + setArg(script[pos + 1], arg1, val2 & val3); + break; + case kOpOr: + if (numParams != 3) + error("kOpOr had wrong number of params (%d)", numParams); + val2 = getArg(script[pos + 2], arg2); + val3 = getArg(script[pos + 3], arg3); + debug(9, "[%d/%d] = [%d/%d]=%d | [%d/%d]=%d (%d)", script[pos + 1], arg1, script[pos + 2], arg2, val2, script[pos+3], arg3, val3, val2 | val3); + setArg(script[pos + 1], arg1, val2 | val3); + break; + case kOpXor: + if (numParams != 3) + error("kOpXor had wrong number of params (%d)", numParams); + val2 = getArg(script[pos + 2], arg2); + val3 = getArg(script[pos + 3], arg3); + debug(9, "[%d/%d] = [%d/%d]=%d ^ [%d/%d]=%d (%d)", script[pos + 1], arg1, script[pos + 2], arg2, val2, script[pos+3], arg3, val3, val2 ^ val3); + setArg(script[pos + 1], arg1, val2 ^ val3); + break; + case kOpNot: + if (numParams != 2) + error("kOpNot had wrong number of params (%d)", numParams); + val2 = getArg(script[pos + 2], arg2); + debug(9, "[%d/%d] = ![%d/%d] (!%d)", script[pos + 1], arg1, script[pos + 2], arg2, val2); + setArg(script[pos + 1], arg1, val2 ? 0 : 1); + break; + case kOpSqrt: + if (numParams != 2) + error("kOpSqrt had wrong number of params (%d)", numParams); + val2 = getArg(script[pos + 2], arg2); + debug(9, "[%d/%d] = sqrt([%d/%d] (%d))", script[pos + 1], arg1, script[pos + 2], arg2, val2); + setArg(script[pos + 1], arg1, (int16)sqrt((double)val2)); + break; + case kOpRandom: + if (numParams != 3) + error("kOpRandom had wrong number of params (%d)", numParams); + val2 = getArg(script[pos + 2], arg2); + val3 = getArg(script[pos + 3], arg3); + val1 = _rnd->getRandomNumberRng(val2, val3); + debug(9, "[%d/%d] = rnd([%d/%d]=%d, [%d/%d]=%d) (%d)", script[pos + 1], arg1, script[pos + 2], arg2, val2, script[pos+3], arg3, val3, val1); + setArg(script[pos + 1], arg1, val1); + break; + case kOpExecuteScript: + if (numParams != 1) + error("kOpExecuteScript had wrong number of params (%d)", numParams); + val1 = getArg(script[pos + 1], arg1); + debug(8, "run script [%d/%d]=%d", script[pos + 1], arg1, val1); + runScript(val1); + debug(8, "done run script"); + break; + case kOpCallFunc: + if (numParams != 1) + error("kOpCallFunc had wrong number of params (%d)", numParams); + val1 = getArg(script[pos + 1], arg1); + debug(8, "%d(%d, %d, %d)", (uint16)val1, _vars[1], _vars[2], _vars[3]); + _vars[0] = scriptFuncCall(val1, _vars[1], _vars[2], _vars[3]); + break; + case kOpBoolLessThanEq: + if (numParams != 2) + error("kOpBoolLessThanEq had wrong number of params (%d)", numParams); + val1 = getArg(script[pos + 1], arg1); + val2 = getArg(script[pos + 2], arg2); + debug(9, "[%d/%d] <= [%d/%d]? (%d <= %d)", script[pos + 1], arg1, script[pos + 2], arg2, val1, val2); + lastResult = (val1 <= val2); + break; + case kOpBoolLessThan: + if (numParams != 2) + error("kOpBoolLessThan had wrong number of params (%d)", numParams); + val1 = getArg(script[pos + 1], arg1); + val2 = getArg(script[pos + 2], arg2); + debug(9, "[%d/%d] < [%d/%d]? (%d < %d)", script[pos + 1], arg1, script[pos + 2], arg2, val1, val2); + lastResult = (val1 < val2); + break; + case kOpBoolGreaterThanEq: + if (numParams != 2) + error("kOpBoolGreaterThanEq had wrong number of params (%d)", numParams); + val1 = getArg(script[pos + 1], arg1); + val2 = getArg(script[pos + 2], arg2); + debug(9, "[%d/%d] >= [%d/%d]? (%d >= %d)", script[pos + 1], arg1, script[pos + 2], arg2, val1, val2); + lastResult = (val1 >= val2); + break; + case kOpBoolGreaterThan: + if (numParams != 2) + error("kOpBoolGreaterThan had wrong number of params (%d)", numParams); + val1 = getArg(script[pos + 1], arg1); + val2 = getArg(script[pos + 2], arg2); + debug(9, "[%d/%d] > [%d/%d]? (%d > %d)", script[pos + 1], arg1, script[pos + 2], arg2, val1, val2); + lastResult = (val1 > val2); + break; + case kOpBoolEqual: + if (numParams != 2) + error("kOpBoolEqual had wrong number of params (%d)", numParams); + val1 = getArg(script[pos + 1], arg1); + val2 = getArg(script[pos + 2], arg2); + debug(9, "[%d/%d] == [%d/%d]? (%d == %d)", script[pos + 1], arg1, script[pos + 2], arg2, val1, val2); + lastResult = (val1 == val2); + break; + case kOpBoolNotEqual: + if (numParams != 2) + error("kOpBoolNotEqual had wrong number of params (%d)", numParams); + val1 = getArg(script[pos + 1], arg1); + val2 = getArg(script[pos + 2], arg2); + debug(9, "[%d/%d] != [%d/%d]? (%d != %d)", script[pos + 1], arg1, script[pos + 2], arg2, val1, val2); + lastResult = (val1 != val2); + break; + case kOpSaveArgs: + if (numParams != 0) + error("kOpSaveArgs had wrong number of params (%d)", numParams); + debug(9, "save args"); + for (uint i = 1; i < 19; i++) + _stack[stackBase + i] = _vars[i]; + break; + case kOpRestoreArgs: + if (numParams != 0) + error("kOpRestoreArgs had wrong number of params (%d)", numParams); + debug(9, "restore args"); + for (uint i = 1; i < 19; i++) + _vars[i] = _stack[stackBase + i]; + break; + case kOpReturn: + if (numParams != 1) + error("kOpReturn had wrong number of params (%d)", numParams); + val1 = getArg(script[pos + 1], arg1); + debug(9, "return [%d/%d]=%d", script[pos + 1], arg1, val1); + _vars[0] = val1; + break; + case kOpLessThanEq: + if (numParams != 3) + error("kOpLessThanEq had wrong number of params (%d)", numParams); + val2 = getArg(script[pos + 2], arg2); + val3 = getArg(script[pos + 3], arg3); + debug(9, "[%d/%d] = [%d/%d] <= [%d/%d]? (%d <= %d)", script[pos + 1], arg1, script[pos + 2], arg2, script[pos + 3], arg3, val3, val2); + setArg(script[pos + 1], arg1, (val3 <= val2) ? 1 : 0); + break; + case kOpLessThan: + if (numParams != 3) + error("kOpLessThan had wrong number of params (%d)", numParams); + val2 = getArg(script[pos + 2], arg2); + val3 = getArg(script[pos + 3], arg3); + debug(9, "[%d/%d] = [%d/%d] < [%d/%d]? (%d < %d)", script[pos + 1], arg1, script[pos + 2], arg2, script[pos + 3], arg3, val3, val2); + setArg(script[pos + 1], arg1, (val3 < val2) ? 1 : 0); + break; + case kOpGreaterThanEq: + if (numParams != 3) + error("kOpGreaterThanEq had wrong number of params (%d)", numParams); + val2 = getArg(script[pos + 2], arg2); + val3 = getArg(script[pos + 3], arg3); + debug(9, "[%d/%d] = [%d/%d] >= [%d/%d]? (%d >= %d)", script[pos + 1], arg1, script[pos + 2], arg2, script[pos + 3], arg3, val3, val2); + setArg(script[pos + 1], arg1, (val3 >= val2) ? 1 : 0); + break; + case kOpGreaterThan: + if (numParams != 3) + error("kOpGreaterThan had wrong number of params (%d)", numParams); + val2 = getArg(script[pos + 2], arg2); + val3 = getArg(script[pos + 3], arg3); + debug(9, "[%d/%d] = [%d/%d] > [%d/%d]? (%d > %d)", script[pos + 1], arg1, script[pos + 2], arg2, script[pos + 3], arg3, val3, val2); + setArg(script[pos + 1], arg1, (val3 > val2) ? 1 : 0); + break; + case kOpEqual: + if (numParams != 3) + error("kOpEqual had wrong number of params (%d)", numParams); + val2 = getArg(script[pos + 2], arg2); + val3 = getArg(script[pos + 3], arg3); + debug(9, "[%d/%d] = [%d/%d] == [%d/%d]? (%d == %d)", script[pos + 1], arg1, script[pos + 2], arg2, script[pos + 3], arg3, val2, val3); + setArg(script[pos + 1], arg1, (val3 == val2) ? 1 : 0); + break; + case kOpNotEqual: + if (numParams != 3) + error("kOpNotEqual had wrong number of params (%d)", numParams); + val2 = getArg(script[pos + 2], arg2); + val3 = getArg(script[pos + 3], arg3); + debug(9, "[%d/%d] = [%d/%d] != [%d/%d]? (%d != %d)", script[pos + 1], arg1, script[pos + 2], arg2, script[pos + 3], arg3, val2, val3); + setArg(script[pos + 1], arg1, (val3 != val2) ? 1 : 0); + break; + case kOpJump: + if (numParams != 1) + error("kOpJump had wrong number of params (%d)", numParams); + val1 = getArg(script[pos + 1], arg1); + debug(9, "jump by [%d/%d]=%d", script[pos + 1], arg1, val1); + pos += val1; + break; + case kOpJumpIfNot: + if (numParams != 1) + error("kOpJumpIfNot had wrong number of params (%d)", numParams); + if (lastResult) + break; + val1 = getArg(script[pos + 1], arg1); + debug(9, "jump if not, by [%d/%d]=%d", script[pos + 1], arg1, val1); + pos += val1; + break; + case kOpJumpIf: + if (numParams != 1) + error("kOpJumpIf had wrong number of params (%d)", numParams); + if (!lastResult) + break; + val1 = getArg(script[pos + 1], arg1); + debug(9, "jump if, by [%d/%d]=%d", script[pos + 1], arg1, val1); + pos += val1; + break; + case kOpJumpIfNotValue: + if (numParams != 2) + error("kOpJumpIfNotValue had wrong number of params (%d)", numParams); + val1 = getArg(script[pos + 1], arg1); + val2 = getArg(script[pos + 2], arg2); + debug(9, "jump if not [%d/%d]=%d", script[pos + 1], arg1, val1); + if (val1) + break; + debug(9, "--> jump by [%d/%d]=%d", script[pos + 2], arg2, val2); + pos += val2; + break; + case kOpJumpIfValue: + if (numParams != 2) + error("kOpJumpIfValue had wrong number of params (%d)", numParams); + val1 = getArg(script[pos + 1], arg1); + val2 = getArg(script[pos + 2], arg2); + debug(9, "jump if [%d/%d]=%d", script[pos + 1], arg1, val1); + if (!val1) + break; + debug(9, "--> jump by [%d/%d]=%d", script[pos + 2], arg2, val2); + pos += val2; + break; + default: + error("unknown script op 0x%02x", op); + } + pos += (1 + numParams); + + if (op == kOpReturn) + break; + } + + delete[] script; + _stack.resize(_stack.size() - 19); +} + +int16 ComposerEngine::scriptFuncCall(uint16 id, int16 param1, int16 param2, int16 param3) { + switch (id) { + case kFuncPlayAnim: + debug(3, "kFuncPlayAnim(%d, %d, %d)", param1, param2, param3); + playAnimation(param1, param2, param3, 0); + return 1; // TODO: return 0 on failure + case kFuncStopAnim: + debug(3, "kFuncStopAnim(%d)", param1); + for (Common::List<Animation *>::iterator i = _anims.begin(); i != _anims.end(); i++) { + if ((*i)->_id == param1) + stopAnimation(*i); + } + return 0; + case kFuncQueueScript: + debug(3, "kFuncQueueScript(%d, %d, %d)", param1, param2, param3); + _queuedScripts[param1]._baseTime = _system->getMillis(); + _queuedScripts[param1]._duration = 10 * param2; + _queuedScripts[param1]._count = 0xffffffff; + _queuedScripts[param1]._scriptId = param3; + return 0; + case kFuncDequeueScript: + debug(3, "kFuncDequeueScript(%d)", param1); + _queuedScripts[param1]._count = 0; + _queuedScripts[param1]._scriptId = 0; + return 0; + case kFuncSetCursor: + debug(3, "kSetCursor(%d, (%d, %d))", param1, param2, param3); + { + uint16 oldCursor = _mouseSpriteId; + setCursor(param1, Common::Point(param2, param3)); + return oldCursor; + } + case kFuncGetCursor: + debug(3, "kFuncGetCursor()"); + return _mouseSpriteId; + case kFuncShowCursor: + debug(3, "kFuncShowCursor()"); + setCursorVisible(true); + return 0; + case kFuncHideCursor: + debug(3, "kFuncHideCursor()"); + setCursorVisible(false); + return 0; + case kFuncActivateButton: + debug(3, "kFuncActivateButton(%d)", param1); + for (Common::List<Library>::iterator l = _libraries.begin(); l != _libraries.end(); l++) { + for (Common::List<Button>::iterator i = l->_buttons.begin(); i != l->_buttons.end(); i++) { + if (i->_id != param1) + continue; + i->_active = true; + } + } + onMouseMove(_lastMousePos); + return 1; + case kFuncDeactivateButton: + debug(3, "kFuncDeactivateButton(%d)", param1); + for (Common::List<Library>::iterator l = _libraries.begin(); l != _libraries.end(); l++) { + for (Common::List<Button>::iterator i = l->_buttons.begin(); i != l->_buttons.end(); i++) { + if (i->_id != param1) + continue; + i->_active = false; + } + } + onMouseMove(_lastMousePos); + return 1; + case kFuncNewPage: + debug(3, "kFuncNewPage(%d, %d)", param1, param2); + _pendingPageChanges.push_back(PendingPageChange(param1, true)); + _pendingPageChanges.push_back(PendingPageChange(param2, false)); + return 1; + case kFuncLoadPage: + debug(3, "kFuncLoadPage(%d)", param1); + _pendingPageChanges.push_back(PendingPageChange(param1, false)); + return 1; + case kFuncUnloadPage: + debug(3, "kFuncUnloadPage(%d)", param1); + _pendingPageChanges.push_back(PendingPageChange(param1, true)); + return 1; + case kFuncSetPalette: + // TODO: return 0 if not disabling (0) and doesn't exist + debug(4, "kFuncSetPalette(%d, %d)", param1, param2); + // this seems only needed for a script bug in the Gregory credits, sigh + if ((uint16)param2 > 100) + param2 = 100; + loadCTBL(param1, param2); + return 1; + case kFuncSaveVars: + debug(3, "kFuncSaveVars(%d)", param1); + { + Common::String filename = _targetName + Common::String::format(".%03d", param1); + Common::WriteStream *stream = _saveFileMan->openForSaving(filename); + for (uint i = 0; i < 1000; i++) { + stream->writeUint16LE(_vars[i]); + } + delete stream; + } + return 1; + case kFuncLoadVars: + debug(3, "kFuncLoadVars(%d, %d, %d)", param1, param2, param3); + { + Common::String filename = _targetName + Common::String::format(".%03d", param1); + Common::SeekableReadStream *stream = _saveFileMan->openForLoading(filename); + if (!stream) { + if (!_bookIni.hasKey(Common::String::format("%d", param1), "Data")) + return 0; + filename = getFilename("Data", param1); + Common::File *file = new Common::File(); + if (!file->open(filename)) + error("couldn't open '%s' to get vars id '%d'", filename.c_str(), param1); + stream = file; + } + if (param3 == 0) + param3 = 1000; + if (param2 < 0 || param3 < 0 || param2 + param3 > 1000) + error("can't read %d entries into %d from file '%s' for vars id '%d'", param3, param2, filename.c_str(), param1); + stream->skip(param2 * 2); + for (uint i = 0; i < (uint)param3; i++) { + if (stream->pos() + 1 > stream->size()) + break; + _vars[param2 + i] = stream->readUint16LE(); + } + delete stream; + } + return 1; + case kFuncQueueScriptOnce: + debug(3, "kFuncQueueScriptOnce(%d, %d, %d)", param1, param2, param3); + _queuedScripts[param1]._baseTime = _system->getMillis(); + _queuedScripts[param1]._duration = 10 * param2; + _queuedScripts[param1]._count = 1; + _queuedScripts[param1]._scriptId = param3; + return 0; + case kFuncGetMousePos: + debug(3, "kFuncGetMousePos(%d, %d)", param1, param2); + _vars[param1] = _lastMousePos.x; + _vars[param2] = _lastMousePos.y; + return 0; + case kFuncChangeBackground: + debug(3, "kFuncChangeBackground(%d)", param1); + // TODO: return 1 if background existed, else 0 + setBackground(param1); + return 1; + case kFuncSetBackgroundColor: + // TODO + warning("ignoring kFuncSetBackgroundColor(%d)", param1); + return 0; + case kFuncClearSprites: + debug(3, "kFuncClearSprites()"); + removeSprite(0, 0); + return 0; + case kFuncAddSprite: + { + Common::Point pos(_vars[param3], _vars[param3 + 1]); + int16 zorder = _vars[param3 + 2]; + debug(3, "kFuncAddSprite(%d, %d, [%d = (%d, %d), %d])", param1, param2, param3, pos.x, pos.y, zorder); + addSprite(param1, param2, zorder, pos); + } + return 0; + case kFuncRemoveSprite: + debug(3, "kFuncRemoveSprite(%d, %d)", param1, param2); + removeSprite(param1, param2); + return 0; + case kFuncQuit: + debug(3, "kFuncQuit()"); + quitGame(); + return 0; + case kFuncSaveData: + // TODO + warning("ignoring kFuncSaveData(%d, %d, %d)", param1, param2, param3); + return 1; + case kFuncLoadData: + debug(3, "kFuncLoadData(%d, %d, %d)", param1, param2, param3); + { + Common::String filename = getFilename("Data", param1); + Common::File *file = new Common::File(); + if (!file->open(filename)) + error("couldn't open '%s' to get data id '%d'", filename.c_str(), param1); + if (param3 == 0) + param3 = 1000; + if (param2 < 0 || param3 < 0 || param2 + param3 > 1000) + error("can't read %d entries into %d from file '%s' for data id '%d'", param3, param2, filename.c_str(), param1); + for (uint i = 0; i < (uint)param3; i++) { + if (file->pos() + 1 > file->size()) + break; + _vars[param2 + i] = file->readUint16LE(); + } + delete file; + } + return 1; + case kFuncGetSpriteSize: + debug(3, "kFuncGetSpriteSize(%d, %d, %d)", param1, param2, param3); + int16 width, height; + width = 0; + height = 0; + { + Common::SeekableReadStream *stream = getStreamForSprite(param1); + if (stream) { + stream->readUint16LE(); + height = stream->readSint16LE(); + width = stream->readSint16LE(); + delete stream; + } + } + _vars[param2] = width; + _vars[param3] = height; + return 0; + default: + error("unknown scriptFuncCall %d(%d, %d, %d)", (uint32)id, param1, param2, param3); + } +} + +} // End of namespace Composer diff --git a/engines/cruise/cruise.h b/engines/cruise/cruise.h index 900f677975..94f8759d01 100644 --- a/engines/cruise/cruise.h +++ b/engines/cruise/cruise.h @@ -108,7 +108,15 @@ public: Common::RandomSource _rnd; - Common::List<byte *> _memList; + struct MemInfo { + int32 lineNum; + char fname[64]; + uint32 magic; + + static uint32 const cookie = 0x41424344; + }; + + Common::List<MemInfo*> _memList; typedef Common::List<Common::Rect> RectList; diff --git a/engines/cruise/cruise_main.cpp b/engines/cruise/cruise_main.cpp index 031c53b96a..ff4669607d 100644 --- a/engines/cruise/cruise_main.cpp +++ b/engines/cruise/cruise_main.cpp @@ -40,19 +40,21 @@ unsigned int timer = 0; gfxEntryStruct* linkedMsgList = NULL; +typedef CruiseEngine::MemInfo MemInfo; + void MemoryList() { if (!_vm->_memList.empty()) { debug("Current list of un-freed memory blocks:"); - Common::List<byte *>::iterator i; + Common::List<MemInfo*>::iterator i; for (i = _vm->_memList.begin(); i != _vm->_memList.end(); ++i) { - byte *v = *i; - debug("%s - %d", (const char *)(v - 68), *((int32 *)(v - 72))); + MemInfo const *const v = *i; + debug("%s - %d", v->fname, v->lineNum); } } } void *MemoryAlloc(uint32 size, bool clearFlag, int32 lineNum, const char *fname) { - byte *result; + void *result; if (gDebugLevel > 0) { // Find the point after the final slash @@ -61,17 +63,17 @@ void *MemoryAlloc(uint32 size, bool clearFlag, int32 lineNum, const char *fname) --fnameP; // Create the new memory block and add it to the memory list - byte *v = (byte *)malloc(size + 64 + 8); - *((int32 *) v) = lineNum; - strncpy((char *)v + 4, fnameP, 63); - *((char *)v + 4 + 63) = '\0'; - *((uint32 *) (v + 68)) = 0x41424344; + MemInfo *const v = (MemInfo *)malloc(sizeof(MemInfo) + size); + v->lineNum = lineNum; + strncpy(v->fname, fnameP, sizeof(v->fname)); + v->fname[ARRAYSIZE(v->fname) - 1] = '\0'; + v->magic = MemInfo::cookie; // Add the block to the memory list - result = v + 64 + 8; - _vm->_memList.push_back(result); + _vm->_memList.push_back(v); + result = v + 1; } else - result = (byte *)malloc(size); + result = malloc(size); if (clearFlag) memset(result, 0, size); @@ -84,11 +86,11 @@ void MemoryFree(void *v) { return; if (gDebugLevel > 0) { - byte *p = (byte *)v; - assert(*((uint32 *) (p - 4)) == 0x41424344); + MemInfo *const p = (MemInfo *)v - 1; + assert(p->magic == MemInfo::cookie); _vm->_memList.remove(p); - free(p - 8 - 64); + free(p); } else free(v); } diff --git a/engines/cruise/module.mk b/engines/cruise/module.mk index 5c36b2a7c1..ae07d20956 100644 --- a/engines/cruise/module.mk +++ b/engines/cruise/module.mk @@ -40,4 +40,3 @@ endif # Include common rules include $(srcdir)/rules.mk - diff --git a/engines/cruise/saveload.cpp b/engines/cruise/saveload.cpp index 6392009373..c3d1ea6643 100644 --- a/engines/cruise/saveload.cpp +++ b/engines/cruise/saveload.cpp @@ -62,12 +62,9 @@ bool readSavegameHeader(Common::InSaveFile *in, CruiseSavegameHeader &header) { while ((ch = (char)in->readByte()) != '\0') header.saveName += ch; // Get the thumbnail - header.thumbnail = new Graphics::Surface(); - if (!Graphics::loadThumbnail(*in, *header.thumbnail)) { - delete header.thumbnail; - header.thumbnail = NULL; + header.thumbnail = Graphics::loadThumbnail(*in); + if (!header.thumbnail) return false; - } return true; } diff --git a/engines/cruise/sound.cpp b/engines/cruise/sound.cpp index 290cc220d4..21d9a75297 100644 --- a/engines/cruise/sound.cpp +++ b/engines/cruise/sound.cpp @@ -31,6 +31,7 @@ #include "audio/audiostream.h" #include "audio/fmopl.h" +#include "audio/mixer.h" #include "audio/mods/soundfx.h" namespace Cruise { diff --git a/engines/cruise/sound.h b/engines/cruise/sound.h index 11aec0b04e..c1975dc579 100644 --- a/engines/cruise/sound.h +++ b/engines/cruise/sound.h @@ -23,10 +23,6 @@ #ifndef CRUISE_SOUND_H #define CRUISE_SOUND_H -#include "audio/mididrv.h" -#include "audio/midiparser.h" -#include "audio/mixer.h" - #include "common/config-manager.h" #include "common/serializer.h" diff --git a/engines/dialogs.cpp b/engines/dialogs.cpp index 1a077e5bf7..58bf629dc4 100644 --- a/engines/dialogs.cpp +++ b/engines/dialogs.cpp @@ -338,4 +338,3 @@ void ConfigDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 GUI::OptionsDialog::handleCommand (sender, cmd, data); } } - diff --git a/engines/draci/saveload.cpp b/engines/draci/saveload.cpp index 1479dd3c77..78315d1a97 100644 --- a/engines/draci/saveload.cpp +++ b/engines/draci/saveload.cpp @@ -58,13 +58,9 @@ bool readSavegameHeader(Common::InSaveFile *in, DraciSavegameHeader &header) { header.playtime = in->readUint32LE(); // Get the thumbnail - header.thumbnail = new Graphics::Surface(); - if (!Graphics::loadThumbnail(*in, *header.thumbnail)) { - header.thumbnail->free(); - delete header.thumbnail; - header.thumbnail = NULL; + header.thumbnail = Graphics::loadThumbnail(*in); + if (!header.thumbnail) return false; - } return true; } diff --git a/engines/drascula/drascula.h b/engines/drascula/drascula.h index 2b6aa0f291..5ec4684723 100644 --- a/engines/drascula/drascula.h +++ b/engines/drascula/drascula.h @@ -30,6 +30,7 @@ #include "common/file.h" #include "common/hash-str.h" #include "common/keyboard.h" +#include "common/ptr.h" #include "common/random.h" #include "common/savefile.h" #include "common/system.h" @@ -264,15 +265,13 @@ private: }; class TextResourceParser { - Common::SeekableReadStream *_stream; - DisposeAfterUse::Flag _dispose; + Common::DisposablePtr<Common::SeekableReadStream> _stream; int _maxLen; void getLine(char *buf); public: TextResourceParser(Common::SeekableReadStream *stream, DisposeAfterUse::Flag dispose); - ~TextResourceParser(); void parseInt(int &result); void parseString(char *result); diff --git a/engines/drascula/resource.cpp b/engines/drascula/resource.cpp index 6da43e7cba..95a95e3487 100644 --- a/engines/drascula/resource.cpp +++ b/engines/drascula/resource.cpp @@ -42,7 +42,7 @@ Common::SeekableReadStream *ArchiveMan::open(const Common::String &filename) { } TextResourceParser::TextResourceParser(Common::SeekableReadStream *stream, DisposeAfterUse::Flag dispose) : - _stream(stream), _dispose(dispose) { + _stream(stream, dispose) { // NOTE: strangely enough, the code before this refactoring used the size of // the stream as a fixed maximum length for the parser. Using an updated @@ -50,12 +50,6 @@ TextResourceParser::TextResourceParser(Common::SeekableReadStream *stream, Dispo _maxLen = _stream->size(); } -TextResourceParser::~TextResourceParser() { - if (_dispose == DisposeAfterUse::YES) { - delete _stream; - } -} - void TextResourceParser::getLine(char *buf) { byte c; char *b; @@ -101,4 +95,3 @@ void TextResourceParser::parseString(char* result) { } // End of namespace Drascula - diff --git a/engines/dreamweb/backdrop.cpp b/engines/dreamweb/backdrop.cpp new file mode 100644 index 0000000000..cba1f14c5e --- /dev/null +++ b/engines/dreamweb/backdrop.cpp @@ -0,0 +1,285 @@ +/* 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::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; + } +} + +uint8 DreamGenContext::getxad(const uint8 *setData, uint8 *result) { + uint8 v0 = setData[0]; + uint8 v1 = setData[1]; + uint8 v2 = setData[2]; + if (v0 != 0) + return 0; + if (v1 < data.byte(kMapx)) + return 0; + v1 -= data.byte(kMapx); + if (v1 >= 11) + return 0; + *result = (v1 << 4) | v2; + return 1; +} + +uint8 DreamGenContext::getyad(const uint8 *setData, uint8 *result) { + uint8 v0 = setData[3]; + uint8 v1 = setData[4]; + if (v0 < data.byte(kMapy)) + return 0; + v0 -= data.byte(kMapy); + if (v0 >= 10) + return 0; + *result = (v0 << 4) | v1; + return 1; +} + +void DreamGenContext::getmapad() { + ch = getmapad((const uint8 *)es.ptr(si, 5)); +} + +uint8 DreamGenContext::getmapad(const uint8 *setData) { + uint8 xad, yad; + if (getxad(setData, &xad) == 0) + return 0; + data.word(kObjectx) = xad; + if (getyad(setData, &yad) == 0) + return 0; + data.word(kObjecty) = yad; + return 1; +} + +void DreamGenContext::calcfrframe() { + uint8 width, height; + calcfrframe(&width, &height); + cl = width; + ch = height; +} + +void DreamGenContext::calcfrframe(uint8* width, uint8* height) { + const Frame *frame = (const Frame *)segRef(data.word(kFrsegment)).ptr(data.word(kCurrentframe) * sizeof(Frame), sizeof(Frame)); + data.word(kSavesource) = data.word(kFramesad) + frame->ptr(); + data.byte(kSavesize+0) = frame->width; + data.byte(kSavesize+1) = frame->height; + data.word(kOffsetx) = frame->x; + data.word(kOffsety) = frame->y; + *width = frame->width; + *height = frame->height; +} + +void DreamGenContext::finalframe() { + uint16 x, y; + finalframe(&x, &y); + di = x; + bx = y; +} + +void DreamGenContext::finalframe(uint16 *x, uint16 *y) { + data.byte(kSavex) = (data.word(kObjectx) + data.word(kOffsetx)) & 0xff; + data.byte(kSavey) = (data.word(kObjecty) + data.word(kOffsety)) & 0xff; + *x = data.word(kObjectx); + *y = data.word(kObjecty); +} + +void DreamGenContext::showallobs() { + data.word(kListpos) = kSetlist; + memset(segRef(data.word(kBuffers)).ptr(kSetlist, 0), 0xff, 128 * 5); + data.word(kFrsegment) = data.word(kSetframes); + data.word(kDataad) = kFramedata; + data.word(kFramesad) = kFrames; + + const Frame *frames = (const Frame *)segRef(data.word(kFrsegment)).ptr(0, 0); + ObjData *setEntries = (ObjData *)segRef(data.word(kSetdat)).ptr(0, 128 * sizeof(ObjData)); + for (size_t i = 0; i < 128; ++i) { + ObjData *setEntry = setEntries + i; + if (getmapad(setEntry->b58) == 0) + continue; + uint8 currentFrame = setEntry->b18[0]; + data.word(kCurrentframe) = currentFrame; + if (currentFrame == 0xff) + continue; + calcfrframe(); + uint16 x, y; + finalframe(&x, &y); + setEntry->b17 = setEntry->b18[0]; + if ((setEntry->type == 0) && (setEntry->priority != 5) && (setEntry->priority != 6)) { + x += data.word(kMapadx); + y += data.word(kMapady); + showframe(frames, x, y, data.word(kCurrentframe), 0); + } else + makebackob(setEntry); + + ObjPos *objPos = (ObjPos *)segRef(data.word(kBuffers)).ptr(data.word(kListpos), sizeof(ObjPos)); + objPos->xMin = data.byte(kSavex); + objPos->yMin = data.byte(kSavey); + objPos->xMax = data.byte(kSavex) + data.byte(kSavesize+0); + objPos->yMax = data.byte(kSavey) + data.byte(kSavesize+1); + objPos->index = i; + data.word(kListpos) += sizeof(ObjPos); + } +} + +void DreamGenContext::getdimension() +{ + uint8 mapXstart, mapYstart; + uint8 mapXsize, mapYsize; + getdimension(&mapXstart, &mapYstart, &mapXsize, &mapYsize); + cl = mapXstart; + ch = mapYstart; + dl = mapXsize; + dh = mapYsize; +} + +bool DreamGenContext::addalong(const uint8 *mapFlags) { + for (size_t i = 0; i < 11; ++i) { + if (mapFlags[3 * i] != 0) + return true; + } + return false; +} + +bool DreamGenContext::addlength(const uint8 *mapFlags) { + for (size_t i = 0; i < 10; ++i) { + if (mapFlags[3 * 11 * i] != 0) + return true; + } + return false; +} + +void DreamGenContext::getdimension(uint8 *mapXstart, uint8 *mapYstart, uint8 *mapXsize, uint8 *mapYsize) { + const uint8 *mapFlags = segRef(data.word(kBuffers)).ptr(kMapflags, 0); + + uint8 yStart = 0; + while (! addalong(mapFlags + 3 * 11 * yStart)) + ++yStart; + + uint8 xStart = 0; + while (! addlength(mapFlags + 3 * xStart)) + ++xStart; + + uint8 yEnd = 10; + while (! addalong(mapFlags + 3 * 11 * (yEnd - 1))) + --yEnd; + + uint8 xEnd = 11; + while (! addlength(mapFlags + 3 * (xEnd - 1))) + --xEnd; + + *mapXstart = xStart; + *mapYstart = yStart; + *mapXsize = xEnd - xStart; + *mapYsize = yEnd - yStart; + data.word(kMapxstart) = xStart << 4; + data.word(kMapystart) = yStart << 4; + data.byte(kMapxsize) = *mapXsize << 4; + data.byte(kMapysize) = *mapYsize << 4; +} + +void DreamGenContext::calcmapad() { + uint8 mapXstart, mapYstart; + uint8 mapXsize, mapYsize; + getdimension(&mapXstart, &mapYstart, &mapXsize, &mapYsize); + data.word(kMapadx) = data.word(kMapoffsetx) - 8 * (mapXsize + 2 * mapXstart - 11); + data.word(kMapady) = data.word(kMapoffsety) - 8 * (mapYsize + 2 * mapYstart - 10); +} + +void DreamGenContext::showallfree() { + data.word(kListpos) = kFreelist; + ObjPos *listPos = (ObjPos *)segRef(data.word(kBuffers)).ptr(kFreelist, 80 * sizeof(ObjPos)); + memset(listPos, 0xff, 80 * sizeof(ObjPos)); + + data.word(kFrsegment) = data.word(kFreeframes); + data.word(kDataad) = kFrframedata; + data.word(kFramesad) = kFrframes; + data.byte(kCurrentfree) = 0; + const uint8 *mapData = segRef(data.word(kFreedat)).ptr(2, 0); + for(size_t i = 0; i < 80; ++i) { + uint8 mapad = getmapad(mapData); + if (mapad != 0) { + data.word(kCurrentframe) = 3 * data.byte(kCurrentfree); + uint8 width, height; + calcfrframe(&width, &height); + uint16 x, y; + finalframe(&x, &y); + if ((width != 0) || (height != 0)) { + x += data.word(kMapadx); + y += data.word(kMapady); + showframe((Frame *)segRef(data.word(kFrsegment)).ptr(0, 0), x, y, data.word(kCurrentframe) & 0xff, 0); + ObjPos *objPos = (ObjPos *)segRef(data.word(kBuffers)).ptr(data.word(kListpos), sizeof(ObjPos)); + objPos->xMin = data.byte(kSavex); + objPos->yMin = data.byte(kSavey); + objPos->xMax = data.byte(kSavex) + data.byte(kSavesize+0); + objPos->yMax = data.byte(kSavey) + data.byte(kSavesize+1); + objPos->index = i; + data.word(kListpos) += sizeof(ObjPos); + } + } + + ++data.byte(kCurrentfree); + mapData += 16; + } +} + +} /*namespace dreamgen */ + diff --git a/engines/dreamweb/console.cpp b/engines/dreamweb/console.cpp index e004746d8a..d415089a48 100644 --- a/engines/dreamweb/console.cpp +++ b/engines/dreamweb/console.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL: https://svn.scummvm.org:4444/svn/dreamweb/console.cpp $ - * $Id: console.cpp 70 2011-01-26 05:36:55Z digitall $ - * */ #include "dreamweb/console.h" diff --git a/engines/dreamweb/console.h b/engines/dreamweb/console.h index 58c8467b34..a90794e94e 100644 --- a/engines/dreamweb/console.h +++ b/engines/dreamweb/console.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL: https://svn.scummvm.org:4444/svn/dreamweb/console.h $ - * $Id: console.h 70 2011-01-26 05:36:55Z digitall $ - * */ #ifndef DREAMWEB_CONSOLE_H diff --git a/engines/dreamweb/detection.cpp b/engines/dreamweb/detection.cpp index ef4a746b62..0ac61a3ac2 100644 --- a/engines/dreamweb/detection.cpp +++ b/engines/dreamweb/detection.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL: https://svn.scummvm.org:4444/svn/dreamweb/detection.cpp $ - * $Id: detection.cpp 3 2010-09-16 19:32:18Z megath $ - * */ #include "base/plugins.h" @@ -43,7 +40,7 @@ public: AdvancedMetaEngine(DreamWeb::gameDescriptions, sizeof(DreamWeb::DreamWebGameDescription), dreamWebGames) { _singleid = "dreamweb"; - _guioptions = Common::GUIO_NOMIDI | Common::GUIO_NOLAUNCHLOAD; + _guioptions = Common::GUIO_NOMIDI; } virtual const char *getName() const { @@ -64,8 +61,8 @@ public: bool DreamWebMetaEngine::hasFeature(MetaEngineFeature f) const { switch(f) { case kSupportsListSaves: - //case kSupportsLoadingDuringStartup: - //case kSupportsDeleteSave: + case kSupportsLoadingDuringStartup: + case kSupportsDeleteSave: return true; default: return false; @@ -108,14 +105,15 @@ SaveStateList DreamWebMetaEngine::listSaves(const char *target) const { stream->read(name, sizeof(name) - 1); delete stream; - SaveStateDescriptor sd(i, name); + int slotNum = atoi(file.c_str() + file.size() - 2); + SaveStateDescriptor sd(slotNum, name); saveList.push_back(sd); } return saveList; } -int DreamWebMetaEngine::getMaximumSaveSlot() const { return 6; } +int DreamWebMetaEngine::getMaximumSaveSlot() const { return 99; } void DreamWebMetaEngine::removeSaveState(const char *target, int slot) const { } diff --git a/engines/dreamweb/detection_tables.h b/engines/dreamweb/detection_tables.h index 6c7d8e4809..82fb6102e4 100644 --- a/engines/dreamweb/detection_tables.h +++ b/engines/dreamweb/detection_tables.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL: https://svn.scummvm.org:4444/svn/dreamweb/detection_tables.h $ - * $Id: detection_tables.h 66 2010-11-07 08:31:21Z eriktorbjorn $ - * */ #ifndef DREAMWEB_DETECTION_TABLES_H diff --git a/engines/dreamweb/dreamgen.cpp b/engines/dreamweb/dreamgen.cpp index a183c7c798..0ee8c50cd3 100644 --- a/engines/dreamweb/dreamgen.cpp +++ b/engines/dreamweb/dreamgen.cpp @@ -1,5 +1,29 @@ /* PLEASE DO NOT MODIFY THIS FILE. ALL CHANGES WILL BE LOST! LOOK FOR README FOR DETAILS */ +/* 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 "dreamgen.h" namespace DreamGen { @@ -1670,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); @@ -2136,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); @@ -2170,35 +2068,6 @@ forcenext: _cmp(al, al); } -void DreamGenContext::clearsprites() { - STACK_CHECK; - es = data.word(kBuffers); - di = (0+(228*13)+32+60+(32*32)+(11*10*3)+768+768+768); - al = 255; - cx = (32)*16; - _stosb(cx, true); -} - -void DreamGenContext::makesprite() { - STACK_CHECK; - es = data.word(kBuffers); - bx = (0+(228*13)+32+60+(32*32)+(11*10*3)+768+768+768); -_tmp17: - _cmp(es.byte(bx+15), 255); - if (flags.z()) - goto _tmp17a; - _add(bx, (32)); - goto _tmp17; -_tmp17a: - es.word(bx) = cx; - es.word(bx+10) = si; - es.word(bx+6) = dx; - es.word(bx+8) = di; - es.word(bx+2) = 0x0ffff; - es.byte(bx+15) = 0; - es.byte(bx+18) = 0; -} - void DreamGenContext::delsprite() { STACK_CHECK; di = bx; @@ -2207,394 +2076,6 @@ void DreamGenContext::delsprite() { _stosb(cx, true); } -void DreamGenContext::spriteupdate() { - STACK_CHECK; - es = data.word(kBuffers); - bx = (0+(228*13)+32+60+(32*32)+(11*10*3)+768+768+768); - al = data.byte(kRyanon); - es.byte(bx+31) = al; - es = data.word(kBuffers); - bx = (0+(228*13)+32+60+(32*32)+(11*10*3)+768+768+768); - cx = 16; -_tmp18: - push(cx); - push(bx); - ax = es.word(bx); - _cmp(ax, 0x0ffff); - if (flags.z()) - goto _tmp18a; - push(es); - push(ds); - cx = es.word(bx+2); - es.word(bx+24) = cx; - __dispatch_call(ax); - ds = pop(); - es = pop(); -_tmp18a: - bx = pop(); - cx = pop(); - _cmp(data.byte(kNowinnewroom), 1); - if (flags.z()) - return /* ($18b) */; - _add(bx, (32)); - if (--cx) - goto _tmp18; -} - -void DreamGenContext::printsprites() { - STACK_CHECK; - es = data.word(kBuffers); - cx = 0; -priorityloop: - push(cx); - data.byte(kPriority) = cl; - bx = (0+(228*13)+32+60+(32*32)+(11*10*3)+768+768+768); - cx = 16; -prtspriteloop: - push(cx); - push(bx); - ax = es.word(bx); - _cmp(ax, 0x0ffff); - if (flags.z()) - goto skipsprite; - al = data.byte(kPriority); - _cmp(al, es.byte(bx+23)); - if (!flags.z()) - goto skipsprite; - _cmp(es.byte(bx+31), 1); - if (flags.z()) - goto skipsprite; - printasprite(); -skipsprite: - bx = pop(); - cx = pop(); - _add(bx, (32)); - if (--cx) - goto prtspriteloop; - cx = pop(); - _inc(cx); - _cmp(cx, 7); - if (!flags.z()) - goto priorityloop; -} - -void DreamGenContext::printasprite() { - STACK_CHECK; - push(es); - push(bx); - si = bx; - ds = es.word(si+6); - al = es.byte(si+11); - ah = 0; - _cmp(al, 220); - if (flags.c()) - goto notnegative1; - ah = 255; -notnegative1: - bx = ax; - _add(bx, data.word(kMapady)); - al = es.byte(si+10); - ah = 0; - _cmp(al, 220); - if (flags.c()) - goto notnegative2; - ah = 255; -notnegative2: - di = ax; - _add(di, data.word(kMapadx)); - al = es.byte(si+15); - ah = 0; - _cmp(es.byte(si+30), 0); - if (flags.z()) - goto steadyframe; - ah = 8; -steadyframe: - _cmp(data.byte(kPriority), 6); - if (!flags.z()) - goto notquickp; -notquickp: - showframe(); - bx = pop(); - es = pop(); -} - -void DreamGenContext::checkone() { - STACK_CHECK; - push(cx); - al = ch; - ah = 0; - cl = 4; - _shr(ax, cl); - dl = al; - cx = pop(); - al = cl; - ah = 0; - cl = 4; - _shr(ax, cl); - ah = dl; - push(ax); - ch = 0; - cl = al; - push(cx); - al = ah; - ah = 0; - cx = 11; - _mul(cx); - cx = pop(); - _add(ax, cx); - cx = 3; - _mul(cx); - si = ax; - ds = data.word(kBuffers); - _add(si, (0+(228*13)+32+60+(32*32))); - _lodsw(); - cx = ax; - _lodsb(); - 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::initman() { - STACK_CHECK; - al = data.byte(kRyanx); - ah = data.byte(kRyany); - si = ax; - cx = 49464; - dx = data.word(kMainsprites); - di = 0; - makesprite(); - es.byte(bx+23) = 4; - es.byte(bx+22) = 0; - es.byte(bx+29) = 0; -} - -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::walking() { - STACK_CHECK; - _cmp(data.byte(kLinedirection), 0); - if (flags.z()) - goto normalwalk; - al = data.byte(kLinepointer); - _dec(al); - data.byte(kLinepointer) = al; - _cmp(al, 200); - if (!flags.c()) - goto endofline; - goto continuewalk; -normalwalk: - al = data.byte(kLinepointer); - _inc(al); - data.byte(kLinepointer) = al; - _cmp(al, data.byte(kLinelength)); - if (!flags.c()) - goto endofline; -continuewalk: - ah = 0; - _add(ax, ax); - push(es); - push(bx); - dx = data; - es = dx; - bx = 8173; - _add(bx, ax); - ax = es.word(bx); - bx = pop(); - es = pop(); - es.word(bx+10) = ax; - return; -endofline: - data.byte(kLinepointer) = 254; - al = data.byte(kDestination); - data.byte(kManspath) = al; - _cmp(al, data.byte(kFinaldest)); - if (flags.z()) - goto finishedwalk; - al = data.byte(kFinaldest); - data.byte(kDestination) = al; - push(es); - push(bx); - autosetwalk(); - bx = pop(); - es = pop(); - return; -finishedwalk: - facerightway(); -} - -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); @@ -2811,7 +2292,7 @@ void DreamGenContext::initrain() { 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)+(12*5)+(46*40)+(5*80)+(250*4)+(256*30)); - bx = 1113; + bx = offset_rainlocations; checkmorerain: al = cs.byte(bx); _cmp(al, 255); @@ -2954,239 +2435,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::liftsprite() { - STACK_CHECK; - al = data.byte(kLiftflag); - _cmp(al, 0); - if (flags.z()) - goto liftclosed; - _cmp(al, 1); - if (flags.z()) - goto liftopen; - _cmp(al, 3); - if (flags.z()) - goto openlift; - al = es.byte(bx+19); - _cmp(al, 0); - if (flags.z()) - goto finishclose; - _dec(al); - _cmp(al, 11); - if (!flags.z()) - goto pokelift; - push(ax); - al = 3; - liftnoise(); - ax = pop(); - goto pokelift; -finishclose: - data.byte(kLiftflag) = 0; - return; -openlift: - al = es.byte(bx+19); - _cmp(al, 12); - if (flags.z()) - goto endoflist; - _inc(al); - _cmp(al, 1); - if (!flags.z()) - goto pokelift; - push(ax); - al = 2; - liftnoise(); - ax = pop(); -pokelift: - es.byte(bx+19) = al; - ah = 0; - push(di); - _add(di, ax); - al = ds.byte(di+18); - di = pop(); - es.byte(bx+15) = al; - ds.byte(di+17) = al; - return; -endoflist: - data.byte(kLiftflag) = 1; - return; -liftopen: - al = data.byte(kLiftpath); - push(es); - push(bx); - turnpathon(); - bx = pop(); - es = pop(); - _cmp(data.byte(kCounttoclose), 0); - if (flags.z()) - goto nocountclose; - _dec(data.byte(kCounttoclose)); - _cmp(data.byte(kCounttoclose), 0); - if (!flags.z()) - goto nocountclose; - data.byte(kLiftflag) = 2; -nocountclose: - al = 12; - goto pokelift; -liftclosed: - al = data.byte(kLiftpath); - push(es); - push(bx); - turnpathoff(); - bx = pop(); - es = pop(); - _cmp(data.byte(kCounttoopen), 0); - if (flags.z()) - goto nocountopen; - _dec(data.byte(kCounttoopen)); - _cmp(data.byte(kCounttoopen), 0); - if (!flags.z()) - goto nocountopen; - data.byte(kLiftflag) = 3; -nocountopen: - al = 0; - goto pokelift; -} - void DreamGenContext::liftnoise() { STACK_CHECK; _cmp(data.byte(kReallocation), 5); @@ -3240,335 +2488,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::dodoor() { - 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 rtofdoor; - _sub(al, cl); - _cmp(al, data.byte(kDoorcheck1)); - if (!flags.c()) - goto upordown; - goto shutdoor; -rtofdoor: - _sub(al, cl); - _cmp(al, data.byte(kDoorcheck2)); - if (!flags.c()) - goto shutdoor; -upordown: - _cmp(ah, ch); - if (!flags.c()) - goto botofdoor; - _sub(ah, ch); - _cmp(ah, data.byte(kDoorcheck3)); - if (flags.c()) - goto shutdoor; - goto opendoor; -botofdoor: - _sub(ah, ch); - _cmp(ah, data.byte(kDoorcheck4)); - if (!flags.c()) - goto shutdoor; -opendoor: - cl = es.byte(bx+19); - _cmp(data.byte(kThroughdoor), 1); - if (!flags.z()) - goto notthrough; - _cmp(cl, 0); - if (!flags.z()) - goto notthrough; - cl = 6; -notthrough: - _inc(cl); - _cmp(cl, 1); - if (!flags.z()) - goto notdoorsound2; - al = 0; - _cmp(data.byte(kReallocation), 5); - if (!flags.z()) - goto nothoteldoor2; - al = 13; -nothoteldoor2: - playchannel1(); -notdoorsound2: - ch = 0; - push(di); - _add(di, cx); - al = ds.byte(di+18); - _cmp(al, 255); - if (!flags.z()) - goto atlast1; - _dec(di); - _dec(cl); -atlast1: - es.byte(bx+19) = cl; - al = ds.byte(di+18); - di = pop(); - es.byte(bx+15) = al; - ds.byte(di+17) = al; - data.byte(kThroughdoor) = 1; - return; -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::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(); @@ -3578,48 +2497,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); @@ -3685,126 +2562,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); @@ -3879,13 +2636,6 @@ dumpevery2: goto dumpevery2; } -void DreamGenContext::allocatework() { - STACK_CHECK; - bx = 0x1000; - allocatemem(); - data.word(kWorkspace) = ax; -} - void DreamGenContext::loadpalfromiff() { STACK_CHECK; dx = 2481; @@ -4047,68 +2797,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); @@ -4153,275 +2841,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::showframe() { - STACK_CHECK; - push(dx); - push(ax); - cx = ax; - _and(cx, 511); - _add(cx, cx); - si = cx; - _add(cx, cx); - _add(si, cx); - _cmp(ds.word(si), 0); - if (!flags.z()) - goto notblankshow; - ax = pop(); - dx = pop(); - cx = 0; - return; -notblankshow: - _test(ah, 128); - if (!flags.z()) - goto skipoffsets; - al = ds.byte(si+4); - ah = 0; - _add(di, ax); - al = ds.byte(si+5); - ah = 0; - _add(bx, ax); -skipoffsets: - cx = ds.word(si+0); - ax = ds.word(si+2); - _add(ax, 2080); - si = ax; - ax = pop(); - dx = pop(); - _cmp(ah, 0); - if (flags.z()) - goto noeffects; - _test(ah, 128); - if (flags.z()) - goto notcentred; - push(ax); - al = cl; - ah = 0; - _shr(ax, 1); - _sub(di, ax); - al = ch; - ah = 0; - _shr(ax, 1); - _sub(bx, ax); - ax = pop(); -notcentred: - _test(ah, 64); - if (flags.z()) - goto notdiffdest; - push(cx); - frameoutfx(); - cx = pop(); - return; -notdiffdest: - _test(ah, 8); - if (flags.z()) - goto notprintlist; - push(ax); - ax = di; - _sub(ax, data.word(kMapadx)); - push(bx); - _sub(bx, data.word(kMapady)); - ah = bl; - bx = pop(); - ax = pop(); -notprintlist: - _test(ah, 4); - if (flags.z()) - goto notflippedx; - dx = (320); - es = data.word(kWorkspace); - push(cx); - frameoutfx(); - cx = pop(); - return; -notflippedx: - _test(ah, 2); - if (flags.z()) - goto notnomask; - dx = (320); - es = data.word(kWorkspace); - push(cx); - frameoutnm(); - cx = pop(); - return; -notnomask: - _test(ah, 32); - if (flags.z()) - goto noeffects; - dx = (320); - es = data.word(kWorkspace); - push(cx); - frameoutbh(); - cx = pop(); - return; -noeffects: - dx = (320); - es = data.word(kWorkspace); - push(cx); - frameoutv(); - cx = pop(); -} - -void DreamGenContext::frameoutbh() { - STACK_CHECK; - push(dx); - ax = bx; - bx = dx; - _mul(bx); - _add(di, ax); - dx = pop(); - push(cx); - ch = 0; - _sub(dx, cx); - cx = pop(); -bhloop2: - push(cx); - ch = 0; - ah = 255; -bhloop1: - _cmp(es.byte(di), ah); - if (!flags.z()) - goto nofill; - _movsb(); - if (--cx) - goto bhloop1; - goto nextline; -nofill: - _inc(di); - _inc(si); - if (--cx) - goto bhloop1; -nextline: - _add(di, dx); - cx = pop(); - _dec(ch); - if (!flags.z()) - goto bhloop2; -} - -void DreamGenContext::frameoutfx() { - STACK_CHECK; - push(dx); - ax = bx; - bx = dx; - _mul(bx); - _add(di, ax); - dx = pop(); - push(cx); - ch = 0; - _add(dx, cx); - cx = pop(); -frameloopfx1: - push(cx); - ch = 0; -frameloopfx2: - _lodsb(); - _cmp(al, 0); - if (!flags.z()) - goto backtosolidfx; -backtootherfx: - _dec(di); - if (--cx) - goto frameloopfx2; - cx = pop(); - _add(di, dx); - _dec(ch); - if (!flags.z()) - goto frameloopfx1; - return; -frameloopfx3: - _lodsb(); - _cmp(al, 0); - if (flags.z()) - goto backtootherfx; -backtosolidfx: - es.byte(di) = al; - _dec(di); - if (--cx) - goto frameloopfx3; - cx = pop(); - _add(di, dx); - _dec(ch); - if (!flags.z()) - goto frameloopfx1; -} - void DreamGenContext::transferinv() { STACK_CHECK; di = data.word(kExframepos); @@ -5507,170 +3926,6 @@ realcreditsearly: data.byte(kLasthardkey) = 0; } -void DreamGenContext::printchar() { - STACK_CHECK; - _cmp(al, 255); - if (flags.z()) - return /* (ignoreit) */; - push(si); - push(bx); - push(di); - _cmp(data.byte(kForeignrelease), 0); - if (flags.z()) - goto _tmp1; - _sub(bx, 3); -_tmp1: - push(ax); - _sub(al, 32); - ah = 0; - _add(ax, data.word(kCharshift)); - showframe(); - ax = pop(); - di = pop(); - bx = pop(); - si = pop(); - _cmp(data.byte(kKerning), 0); - if (!flags.z()) - goto nokern; - kernchars(); -nokern: - push(cx); - ch = 0; - _add(di, cx); - cx = pop(); -} - -void DreamGenContext::kernchars() { - STACK_CHECK; - _cmp(al, 'a'); - if (flags.z()) - goto iskern; - _cmp(al, 'u'); - if (flags.z()) - goto iskern; - return; -iskern: - _cmp(ah, 'n'); - if (flags.z()) - goto kernit; - _cmp(ah, 't'); - if (flags.z()) - goto kernit; - _cmp(ah, 'r'); - if (flags.z()) - goto kernit; - _cmp(ah, 'i'); - if (flags.z()) - goto kernit; - _cmp(ah, 'l'); - if (flags.z()) - goto kernit; - return; -kernit: - _dec(cl); -} - -void DreamGenContext::printslow() { - STACK_CHECK; - data.byte(kPointerframe) = 1; - data.byte(kPointermode) = 3; - ds = data.word(kCharset1); -printloopslow6: - push(bx); - push(di); - push(dx); - getnumber(); - ch = 0; -printloopslow5: - push(cx); - push(si); - push(es); - ax = es.word(si); - push(bx); - push(cx); - push(es); - push(si); - push(ds); - modifychar(); - printboth(); - ds = pop(); - si = pop(); - es = pop(); - cx = pop(); - bx = pop(); - ax = es.word(si+1); - _inc(si); - _cmp(al, 0); - if (flags.z()) - goto finishslow; - _cmp(al, ':'); - if (flags.z()) - goto finishslow; - _cmp(cl, 1); - if (flags.z()) - goto afterslow; - push(di); - push(ds); - push(bx); - push(cx); - push(es); - push(si); - modifychar(); - data.word(kCharshift) = 91; - printboth(); - data.word(kCharshift) = 0; - si = pop(); - es = pop(); - cx = pop(); - bx = pop(); - ds = pop(); - di = pop(); - waitframes(); - _cmp(ax, 0); - if (flags.z()) - goto keepgoing; - _cmp(ax, data.word(kOldbutton)); - if (!flags.z()) - goto finishslow2; -keepgoing: - waitframes(); - _cmp(ax, 0); - if (flags.z()) - goto afterslow; - _cmp(ax, data.word(kOldbutton)); - if (!flags.z()) - goto finishslow2; -afterslow: - es = pop(); - si = pop(); - cx = pop(); - _inc(si); - if (--cx) - goto printloopslow5; - dx = pop(); - di = pop(); - bx = pop(); - _add(bx, 10); - goto printloopslow6; -finishslow: - es = pop(); - si = pop(); - cx = pop(); - dx = pop(); - di = pop(); - bx = pop(); - al = 0; - return; -finishslow2: - es = pop(); - si = pop(); - cx = pop(); - dx = pop(); - di = pop(); - bx = pop(); - al = 1; -} - void DreamGenContext::waitframes() { STACK_CHECK; push(di); @@ -5691,62 +3946,6 @@ void DreamGenContext::waitframes() { di = pop(); } -void DreamGenContext::printboth() { - STACK_CHECK; - push(ax); - push(cx); - push(bx); - push(di); - printchar(); - ax = pop(); - push(di); - di = ax; - multidump(); - di = pop(); - bx = pop(); - cx = pop(); - ax = pop(); -} - -void DreamGenContext::printdirect() { - STACK_CHECK; - data.word(kLastxpos) = di; - ds = data.word(kCurrentset); -printloop6: - push(bx); - push(di); - push(dx); - getnumber(); - ch = 0; -printloop5: - ax = es.word(si); - _inc(si); - _cmp(al, 0); - if (flags.z()) - goto finishdirct; - _cmp(al, ':'); - if (flags.z()) - goto finishdirct; - push(cx); - push(es); - modifychar(); - printchar(); - data.word(kLastxpos) = di; - es = pop(); - cx = pop(); - if (--cx) - goto printloop5; - dx = pop(); - di = pop(); - bx = pop(); - _add(bx, data.word(kLinespacing)); - goto printloop6; -finishdirct: - dx = pop(); - di = pop(); - bx = pop(); -} - void DreamGenContext::monprint() { STACK_CHECK; data.byte(kKerning) = 1; @@ -5833,156 +4032,6 @@ nottrigger2: data.byte(kKerning) = 0; } -void DreamGenContext::getnumber() { - STACK_CHECK; - cx = 0; - push(si); - push(bx); - push(di); - push(ds); - push(es); - di = si; -wordloop: - push(cx); - push(dx); - getnextword(); - dx = pop(); - cx = pop(); - _cmp(al, 1); - if (flags.z()) - goto endoftext; - al = cl; - ah = 0; - push(bx); - bh = 0; - _add(ax, bx); - bx = pop(); - _sub(ax, 10); - dh = 0; - _cmp(ax, dx); - if (!flags.c()) - goto gotoverend; - _add(cl, bl); - _add(ch, bh); - goto wordloop; -gotoverend: - al = dl; - _and(al, 1); - if (flags.z()) - goto notcentre; - push(cx); - al = dl; - _and(al, 0xfe); - ah = 0; - ch = 0; - _sub(ax, cx); - _add(ax, 20); - _shr(ax, 1); - cx = pop(); - es = pop(); - ds = pop(); - di = pop(); - bx = pop(); - si = pop(); - _add(di, ax); - cl = ch; - return; -notcentre: - es = pop(); - ds = pop(); - di = pop(); - bx = pop(); - si = pop(); - cl = ch; - return; -endoftext: - al = cl; - ah = 0; - push(bx); - bh = 0; - _add(ax, bx); - bx = pop(); - _sub(ax, 10); - dh = 0; - _cmp(ax, dx); - if (!flags.c()) - goto gotoverend2; - _add(cl, bl); - _add(ch, bh); -gotoverend2: - al = dl; - _and(al, 1); - if (flags.z()) - goto notcent2; - push(cx); - al = dl; - _and(al, 0xfe); - _add(al, 2); - ah = 0; - ch = 0; - _add(ax, 20); - _sub(ax, cx); - _shr(ax, 1); - cx = pop(); - es = pop(); - ds = pop(); - di = pop(); - bx = pop(); - si = pop(); - _add(di, ax); - cl = ch; - return; -notcent2: - es = pop(); - ds = pop(); - di = pop(); - bx = pop(); - si = pop(); - cl = ch; -} - -void DreamGenContext::getnextword() { - STACK_CHECK; - bx = 0; -getloop: - ax = es.word(di); - _inc(di); - _inc(bh); - _cmp(al, ':'); - if (flags.z()) - goto endall; - _cmp(al, 0); - if (flags.z()) - goto endall; - _cmp(al, 32); - if (flags.z()) - goto endword; - modifychar(); - _cmp(al, 255); - if (flags.z()) - goto getloop; - push(ax); - _sub(al, 32); - ah = 0; - _add(ax, data.word(kCharshift)); - _add(ax, ax); - si = ax; - _add(ax, ax); - _add(si, ax); - cl = ds.byte(si+0); - ax = pop(); - kernchars(); - _add(bl, cl); - goto getloop; -endword: - _add(bl, 6); - al = 0; - return; -endall: - _add(bl, 6); - al = 1; -} - void DreamGenContext::fillryan() { STACK_CHECK; es = data.word(kBuffers); @@ -6291,15 +4340,15 @@ waitexam: dumptextline(); delpointer(); data.byte(kGetback) = 0; - bx = 2494; + bx = offset_examlist; _cmp(data.byte(kInvopen), 0); if (flags.z()) goto notuseinv; - bx = 2556; + bx = offset_invlist1; _cmp(data.byte(kInvopen), 1); if (flags.z()) goto notuseinv; - bx = 2618; + bx = offset_withlist1; notuseinv: checkcoords(); _cmp(data.byte(kExamagain), 0); @@ -6430,7 +4479,7 @@ void DreamGenContext::openob() { STACK_CHECK; al = data.byte(kOpenedob); ah = data.byte(kOpenedtype); - di = 5847; + di = offset_commandline; copyname(); di = (80); bx = (58)+86; @@ -6441,7 +4490,7 @@ void DreamGenContext::openob() { _add(di, 5); bx = (58)+86; es = cs; - si = 5847; + si = offset_commandline; dl = 220; al = 0; ah = 0; @@ -6453,7 +4502,7 @@ void DreamGenContext::openob() { cx = (44); _mul(cx); _add(ax, (80)); - bx = 2588; + bx = offset_openchangesize; cs.word(bx) = ax; } @@ -6805,15 +4854,15 @@ waitexam: dumptextline(); delpointer(); data.byte(kGetback) = 0; - bx = 2494; + bx = offset_examlist; _cmp(data.byte(kInvopen), 0); if (flags.z()) goto notuseinv; - bx = 2556; + bx = offset_invlist1; _cmp(data.byte(kInvopen), 1); if (flags.z()) goto notuseinv; - bx = 2618; + bx = offset_withlist1; notuseinv: checkcoords(); _cmp(data.byte(kExamagain), 0); @@ -7171,31 +5220,6 @@ doplace: delpointer(); } -void DreamGenContext::deletetaken() { - STACK_CHECK; - es = data.word(kFreedat); - ah = data.byte(kReallocation); - ds = data.word(kExtras); - si = (0+2080+30000); - cx = (114); -takenloop: - al = ds.byte(si+11); - _cmp(al, ah); - if (!flags.z()) - goto notinhere; - bl = ds.byte(si+1); - bh = 0; - _add(bx, bx); - _add(bx, bx); - _add(bx, bx); - _add(bx, bx); - es.byte(bx+2) = 254; -notinhere: - _add(si, 16); - if (--cx) - goto takenloop; -} - void DreamGenContext::outofinv() { STACK_CHECK; findinvpos(); @@ -8317,151 +6341,6 @@ void DreamGenContext::drawfloor() { es = pop(); } -void DreamGenContext::calcmapad() { - STACK_CHECK; - getdimension(); - push(cx); - push(dx); - al = 11; - _sub(al, dl); - _sub(al, cl); - _sub(al, cl); - ax.cbw(); - bx = 8; - _mul(bx); - _add(ax, data.word(kMapoffsetx)); - data.word(kMapadx) = ax; - dx = pop(); - cx = pop(); - al = 10; - _sub(al, dh); - _sub(al, ch); - _sub(al, ch); - ax.cbw(); - bx = 8; - _mul(bx); - _add(ax, data.word(kMapoffsety)); - data.word(kMapady) = ax; -} - -void DreamGenContext::getdimension() { - STACK_CHECK; - es = data.word(kBuffers); - bx = (0+(228*13)+32+60+(32*32)); - ch = 0; -dimloop1: - addalong(); - _cmp(al, 0); - if (!flags.z()) - goto finishdim1; - _inc(ch); - goto dimloop1; -finishdim1: - bx = (0+(228*13)+32+60+(32*32)); - cl = 0; -dimloop2: - push(bx); - addlength(); - bx = pop(); - _cmp(al, 0); - if (!flags.z()) - goto finishdim2; - _inc(cl); - _add(bx, 3); - goto dimloop2; -finishdim2: - bx = (0+(228*13)+32+60+(32*32))+(11*3*9); - dh = 10; -dimloop3: - push(bx); - addalong(); - bx = pop(); - _cmp(al, 0); - if (!flags.z()) - goto finishdim3; - _dec(dh); - _sub(bx, 11*3); - goto dimloop3; -finishdim3: - bx = (0+(228*13)+32+60+(32*32))+(3*10); - dl = 11; -dimloop4: - push(bx); - addlength(); - bx = pop(); - _cmp(al, 0); - if (!flags.z()) - goto finishdim4; - _dec(dl); - _sub(bx, 3); - goto dimloop4; -finishdim4: - al = cl; - ah = 0; - _shl(ax, 1); - _shl(ax, 1); - _shl(ax, 1); - _shl(ax, 1); - data.word(kMapxstart) = ax; - al = ch; - ah = 0; - _shl(ax, 1); - _shl(ax, 1); - _shl(ax, 1); - _shl(ax, 1); - data.word(kMapystart) = ax; - _sub(dl, cl); - _sub(dh, ch); - al = dl; - ah = 0; - _shl(ax, 1); - _shl(ax, 1); - _shl(ax, 1); - _shl(ax, 1); - data.byte(kMapxsize) = al; - al = dh; - ah = 0; - _shl(ax, 1); - _shl(ax, 1); - _shl(ax, 1); - _shl(ax, 1); - data.byte(kMapysize) = al; -} - -void DreamGenContext::addalong() { - STACK_CHECK; - ah = 11; -addloop: - _cmp(es.byte(bx), 0); - if (!flags.z()) - goto gotalong; - _add(bx, 3); - _dec(ah); - if (!flags.z()) - goto addloop; - al = 0; - return; -gotalong: - al = 1; -} - -void DreamGenContext::addlength() { - STACK_CHECK; - ah = 10; -addloop2: - _cmp(es.byte(bx), 0); - if (!flags.z()) - goto gotlength; - _add(bx, 3*11); - _dec(ah); - if (!flags.z()) - goto addloop2; - al = 0; - return; -gotlength: - al = 1; -} - void DreamGenContext::drawflags() { STACK_CHECK; es = data.word(kBuffers); @@ -8501,235 +6380,6 @@ _tmp28a: goto _tmp28; } -void DreamGenContext::eraseoldobs() { - STACK_CHECK; - _cmp(data.byte(kNewobs), 0); - if (flags.z()) - return /* (donterase) */; - es = data.word(kBuffers); - bx = (0+(228*13)+32+60+(32*32)+(11*10*3)+768+768+768); - cx = 16; -oberase: - push(cx); - push(bx); - ax = es.word(bx+20); - _cmp(ax, 0x0ffff); - if (flags.z()) - goto notthisob; - di = bx; - al = 255; - cx = (32); - _stosb(cx, true); -notthisob: - bx = pop(); - cx = pop(); - _add(bx, (32)); - if (--cx) - goto oberase; -} - -void DreamGenContext::showallobs() { - STACK_CHECK; - es = data.word(kBuffers); - bx = (0+(228*13)+32+60+(32*32)+(11*10*3)+768+768+768+(32*32)); - data.word(kListpos) = bx; - di = bx; - cx = 128*5; - al = 255; - _stosb(cx, true); - es = data.word(kSetframes); - data.word(kFrsegment) = es; - ax = (0); - data.word(kDataad) = ax; - ax = (0+2080); - data.word(kFramesad) = ax; - data.byte(kCurrentob) = 0; - ds = data.word(kSetdat); - si = 0; - cx = 128; -showobsloop: - push(cx); - push(si); - push(si); - _add(si, 58); - es = data.word(kSetdat); - getmapad(); - si = pop(); - _cmp(ch, 0); - if (flags.z()) - goto blankframe; - al = es.byte(si+18); - ah = 0; - data.word(kCurrentframe) = ax; - _cmp(al, 255); - if (flags.z()) - goto blankframe; - push(es); - push(si); - calcfrframe(); - finalframe(); - si = pop(); - es = pop(); - al = es.byte(si+18); - es.byte(si+17) = al; - _cmp(es.byte(si+8), 0); - if (!flags.z()) - goto animating; - _cmp(es.byte(si+5), 5); - if (flags.z()) - goto animating; - _cmp(es.byte(si+5), 6); - if (flags.z()) - goto animating; - ax = data.word(kCurrentframe); - ah = 0; - _add(di, data.word(kMapadx)); - _add(bx, data.word(kMapady)); - showframe(); - goto drawnsetob; -animating: - makebackob(); -drawnsetob: - si = data.word(kListpos); - es = data.word(kBuffers); - al = data.byte(kSavex); - ah = data.byte(kSavey); - es.word(si) = ax; - cx = ax; - ax = data.word(kSavesize); - _add(al, cl); - _add(ah, ch); - es.word(si+2) = ax; - al = data.byte(kCurrentob); - es.byte(si+4) = al; - _add(si, 5); - data.word(kListpos) = si; -blankframe: - _inc(data.byte(kCurrentob)); - si = pop(); - cx = pop(); - _add(si, 64); - _dec(cx); - if (flags.z()) - return /* (finishedsetobs) */; - 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); - bx = (0+(228*13)+32+60+(32*32)+(11*10*3)+768+768+768+(32*32)+(128*5)); - data.word(kListpos) = bx; - di = (0+(228*13)+32+60+(32*32)+(11*10*3)+768+768+768+(32*32)+(128*5)); - cx = 80*5; - al = 255; - _stosb(cx, true); - es = data.word(kFreeframes); - data.word(kFrsegment) = es; - ax = (0); - data.word(kDataad) = ax; - ax = (0+2080); - data.word(kFramesad) = ax; - al = 0; - data.byte(kCurrentfree) = al; - ds = data.word(kFreedat); - si = 2; - cx = 0; -loop127: - push(cx); - push(si); - push(si); - es = data.word(kFreedat); - getmapad(); - si = pop(); - _cmp(ch, 0); - if (flags.z()) - goto over138; - al = data.byte(kCurrentfree); - ah = 0; - dx = ax; - _add(ax, ax); - _add(ax, dx); - data.word(kCurrentframe) = ax; - push(es); - push(si); - calcfrframe(); - es = data.word(kMapstore); - ds = data.word(kFrsegment); - finalframe(); - si = pop(); - es = pop(); - _cmp(cx, 0); - if (flags.z()) - goto over138; - ax = data.word(kCurrentframe); - ah = 0; - _add(di, data.word(kMapadx)); - _add(bx, data.word(kMapady)); - showframe(); - si = data.word(kListpos); - es = data.word(kBuffers); - al = data.byte(kSavex); - ah = data.byte(kSavey); - es.word(si) = ax; - cx = ax; - ax = data.word(kSavesize); - _add(al, cl); - _add(ah, ch); - es.word(si+2) = ax; - ax = pop(); - cx = pop(); - push(cx); - push(ax); - es.byte(si+4) = cl; - _add(si, 5); - data.word(kListpos) = si; -over138: - _inc(data.byte(kCurrentfree)); - si = pop(); - cx = pop(); - _add(si, 16); - _inc(cx); - _cmp(cx, 80); - if (flags.z()) - return /* (finfree) */; - goto loop127; -} - void DreamGenContext::showallex() { STACK_CHECK; es = data.word(kBuffers); @@ -8818,128 +6468,6 @@ blankex: goto exloop; } -void DreamGenContext::calcfrframe() { - STACK_CHECK; - dx = data.word(kFrsegment); - ax = data.word(kFramesad); - push(ax); - cx = data.word(kDataad); - ax = data.word(kCurrentframe); - ds = dx; - bx = 6; - _mul(bx); - _add(ax, cx); - bx = ax; - cx = ds.word(bx); - ax = ds.word(bx+2); - dx = ds.word(bx+4); - bx = pop(); - push(dx); - _add(ax, bx); - data.word(kSavesource) = ax; - data.word(kSavesize) = cx; - ax = pop(); - push(ax); - ah = 0; - data.word(kOffsetx) = ax; - ax = pop(); - al = ah; - ah = 0; - data.word(kOffsety) = ax; - return; - ax = pop(); - cx = 0; - data.word(kSavesize) = cx; -} - -void DreamGenContext::finalframe() { - STACK_CHECK; - ax = data.word(kObjecty); - _add(ax, data.word(kOffsety)); - bx = data.word(kObjectx); - _add(bx, data.word(kOffsetx)); - data.byte(kSavex) = bl; - data.byte(kSavey) = al; - di = data.word(kObjectx); - bx = data.word(kObjecty); -} - -void DreamGenContext::adjustlen() { - STACK_CHECK; - ah = al; - _add(al, ch); - _cmp(al, 100); - if (flags.c()) - return /* (over242) */; - al = 224; - _sub(al, ch); - ch = al; -} - -void DreamGenContext::getmapad() { - STACK_CHECK; - getxad(); - _cmp(ch, 0); - if (flags.z()) - return /* (over146) */; - data.word(kObjectx) = ax; - getyad(); - _cmp(ch, 0); - if (flags.z()) - return /* (over146) */; - data.word(kObjecty) = ax; - ch = 1; -} - -void DreamGenContext::getxad() { - STACK_CHECK; - cl = es.byte(si); - _inc(si); - al = es.byte(si); - _inc(si); - ah = es.byte(si); - _inc(si); - _cmp(cl, 0); - if (!flags.z()) - goto over148; - _sub(al, data.byte(kMapx)); - if (flags.c()) - goto over148; - _cmp(al, 11); - if (!flags.c()) - goto over148; - cl = 4; - _shl(al, cl); - _or(al, ah); - ah = 0; - ch = 1; - return; -over148: - ch = 0; -} - -void DreamGenContext::getyad() { - STACK_CHECK; - al = es.byte(si); - _inc(si); - ah = es.byte(si); - _inc(si); - _sub(al, data.byte(kMapy)); - if (flags.c()) - goto over147; - _cmp(al, 10); - if (!flags.c()) - goto over147; - cl = 4; - _shl(al, cl); - _or(al, ah); - ah = 0; - ch = 1; - return; -over147: - ch = 0; -} - void DreamGenContext::autolook() { STACK_CHECK; ax = data.word(kMousex); @@ -9095,7 +6623,7 @@ waittalk: dumppointer(); dumptextline(); data.byte(kGetback) = 0; - bx = 2660; + bx = offset_talklist; checkcoords(); _cmp(data.byte(kQuitrequested), 0); if (!flags.z()) @@ -9389,7 +6917,7 @@ hangloopq: vsync(); dumppointer(); dumptextline(); - bx = 2692; + bx = offset_quitlist; checkcoords(); bx = pop(); cx = pop(); @@ -9524,7 +7052,7 @@ select: _cmp(data.byte(kGetback), 1); if (flags.z()) goto quittravel; - bx = 2714; + bx = offset_destlist; checkcoords(); _cmp(data.byte(kNewlocation), 255); if (flags.z()) @@ -9948,12 +7476,12 @@ void DreamGenContext::usemon() { al = 32; _stosb(cx, true); es = cs; - di = 2942+1; + di = offset_operand1+1; cx = 12; al = 32; _stosb(cx, true); es = cs; - di = 2836; + di = offset_keys; es.byte(di) = 1; _add(di, 26); cx = 3; @@ -10451,7 +7979,7 @@ void DreamGenContext::delchar() { void DreamGenContext::execcommand() { STACK_CHECK; es = cs; - bx = 2776; + bx = offset_comlist; ds = cs; si = 8045; al = ds.byte(si); @@ -10550,7 +8078,7 @@ void DreamGenContext::dircom() { dirroot: data.byte(kLogonum) = 0; ds = cs; - si = 2956; + si = offset_rootdir; _inc(si); es = cs; di = 2970; @@ -10591,7 +8119,7 @@ void DreamGenContext::signon() { parser(); _inc(di); ds = cs; - si = 2836; + si = offset_keys; cx = 4; signonloop: push(cx); @@ -10695,7 +8223,7 @@ void DreamGenContext::showkeys() { al = 18; monmessage(); es = cs; - bx = 2836; + bx = offset_keys; cx = 4; keysloop: push(cx); @@ -10762,7 +8290,7 @@ foundfile2: return; keyok1: es = cs; - di = 2942; + di = offset_operand1; ds = data.word(kMonsource); searchforstring(); _cmp(al, 0); @@ -10854,7 +8382,7 @@ keyok2: push(es); push(bx); ds = cs; - si = 2942+1; + si = offset_operand1+1; es = cs; di = 2970+1; cx = 12; @@ -10901,7 +8429,7 @@ void DreamGenContext::getkeyandlogo() { cx = 26; _mul(cx); es = cs; - bx = 2836; + bx = offset_keys; _add(bx, ax); al = es.byte(bx); _cmp(al, 1); @@ -10975,11 +8503,11 @@ notfound: void DreamGenContext::parser() { STACK_CHECK; es = cs; - di = 2942; + di = offset_operand1; cx = 13; al = 0; _stosb(cx, true); - di = 2942; + di = offset_operand1; al = '='; _stosb(); ds = cs; @@ -11008,7 +8536,7 @@ copyin1: if (!flags.z()) goto copyin1; finishpars: - di = 2942; + di = offset_operand1; } void DreamGenContext::scrollmonitor() { @@ -11039,19 +8567,6 @@ void DreamGenContext::scrollmonitor() { ax = pop(); } -void DreamGenContext::lockmon() { - STACK_CHECK; - _cmp(data.byte(kLasthardkey), 57); - if (!flags.z()) - return /* (notlock) */; - locklighton(); -lockloop: - _cmp(data.byte(kLasthardkey), 57); - if (flags.z()) - goto lockloop; - locklightoff(); -} - void DreamGenContext::monitorlogo() { STACK_CHECK; al = data.byte(kLogonum); @@ -11315,7 +8830,7 @@ nodream7: getanyad(); dx = data; ds = dx; - si = 2984; + si = offset_uselist; checkuselist: push(si); _lodsb(); @@ -12739,7 +10254,7 @@ _tmp1: di = 160; bx = 155; es = cs; - si = 3474; + si = offset_money1poke; data.word(kCharshift) = 91*2+75; al = 0; ah = 0; @@ -12748,7 +10263,7 @@ _tmp1: di = 187; bx = 155; es = cs; - si = 3479; + si = offset_money2poke; data.word(kCharshift) = 91*2+85; al = 0; ah = 0; @@ -12816,7 +10331,7 @@ void DreamGenContext::lookatcard() { void DreamGenContext::moneypoke() { STACK_CHECK; - bx = 3474; + bx = offset_money1poke; cl = 48-1; numberpoke0: _inc(cl); @@ -12852,7 +10367,7 @@ numberpoke3: goto numberpoke3; _add(ax, 10); cs.byte(bx) = cl; - bx = 3479; + bx = offset_money2poke; _add(al, 48); cs.byte(bx) = al; } @@ -13315,7 +10830,7 @@ void DreamGenContext::withwhat() { al = data.byte(kCommand); ah = data.byte(kObjecttype); es = cs; - di = 5847; + di = offset_commandline; copyname(); di = 100; bx = 21; @@ -13327,7 +10842,7 @@ void DreamGenContext::withwhat() { _add(di, 5); bx = 21; es = cs; - si = 5847; + si = offset_commandline; dl = 220; al = 0; ah = 0; @@ -13600,32 +11115,6 @@ void DreamGenContext::findpuztext() { si = ax; } -void DreamGenContext::placesetobject() { - STACK_CHECK; - push(es); - push(bx); - cl = 0; - ch = 0; - findormake(); - getsetad(); - es.byte(bx+58) = 0; - bx = pop(); - es = pop(); -} - -void DreamGenContext::removesetobject() { - STACK_CHECK; - push(es); - push(bx); - cl = 255; - ch = 0; - findormake(); - getsetad(); - es.byte(bx+58) = 255; - bx = pop(); - es = pop(); -} - void DreamGenContext::issetobonmap() { STACK_CHECK; push(es); @@ -13660,35 +11149,6 @@ void DreamGenContext::removefreeobject() { es = pop(); } -void DreamGenContext::findormake() { - STACK_CHECK; - 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)); - push(ax); - es = data.word(kBuffers); - ah = data.byte(kReallocation); -changeloop: - _cmp(es.byte(bx), 255); - if (flags.z()) - goto haventfound; - _cmp(ax, es.word(bx)); - if (!flags.z()) - goto nofoundchange; - _cmp(ch, es.byte(bx+3)); - if (flags.z()) - goto foundchange; -nofoundchange: - _add(bx, 4); - goto changeloop; -foundchange: - ax = pop(); - es.byte(bx+2) = cl; - return; -haventfound: - es.word(bx) = ax; - es.word(bx+2) = cx; - ax = pop(); -} - void DreamGenContext::switchryanon() { STACK_CHECK; data.byte(kRyanon) = 255; @@ -13699,70 +11159,6 @@ void DreamGenContext::switchryanoff() { data.byte(kRyanon) = 1; } -void DreamGenContext::setallchanges() { - 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)+(12*5)+(46*40)+(5*80)); -setallloop: - ax = es.word(bx); - _cmp(al, 255); - if (flags.z()) - return /* (endsetloop) */; - cx = es.word(bx+2); - _add(bx, 4); - _cmp(ah, data.byte(kReallocation)); - if (!flags.z()) - goto setallloop; - push(es); - push(bx); - dochange(); - bx = pop(); - es = pop(); - goto setallloop; -} - -void DreamGenContext::dochange() { - STACK_CHECK; - _cmp(ch, 0); - if (flags.z()) - goto object; - _cmp(ch, 1); - if (flags.z()) - goto freeobject; - push(cx); - ah = 0; - _add(ax, ax); - _add(ax, ax); - _add(ax, ax); - push(ax); - al = ch; - _sub(al, 100); - ah = 0; - cx = 144; - _mul(cx); - bx = pop(); - _add(bx, ax); - _add(bx, (0)); - es = data.word(kReels); - cx = pop(); - es.byte(bx+6) = cl; - return; -object: - push(cx); - getsetad(); - cx = pop(); - es.byte(bx+58) = cl; - return; -freeobject: - push(cx); - getfreead(); - cx = pop(); - _cmp(es.byte(bx+2), 255); - if (!flags.z()) - return /* (beenpickedup) */; - es.byte(bx+2) = cl; -} - void DreamGenContext::autoappear() { STACK_CHECK; _cmp(data.byte(kLocation), 32); @@ -13833,68 +11229,6 @@ notonsartroof: placesetobject(); } -void DreamGenContext::getundertimed() { - STACK_CHECK; - 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; - ch = (30); - cl = 240; - ds = data.word(kBuffers); - si = (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)); - multiget(); -} - -void DreamGenContext::putundertimed() { - STACK_CHECK; - 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; - ch = (30); - cl = 240; - ds = data.word(kBuffers); - si = (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)); - multiput(); -} - -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); @@ -13917,94 +11251,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::usetimedtext() { - STACK_CHECK; - _cmp(data.word(kTimecount), 0); - if (flags.z()) - return /* (notext) */; - _dec(data.word(kTimecount)); - _cmp(data.word(kTimecount), 0); - if (flags.z()) - goto deltimedtext; - ax = data.word(kTimecount); - _cmp(ax, data.word(kCounttotimed)); - if (flags.z()) - goto firsttimed; - if (!flags.c()) - return /* (notext) */; - goto notfirsttimed; -firsttimed: - getundertimed(); -notfirsttimed: - bl = data.byte(kTimedy); - bh = 0; - al = data.byte(kTimedx); - ah = 0; - di = ax; - es = data.word(kTimedseg); - si = data.word(kTimedoffset); - dl = 237; - ah = 0; - printdirect(); - data.byte(kNeedtodumptimed) = 1; - return; -deltimedtext: - putundertimed(); - data.byte(kNeedtodumptimed) = 1; -} - void DreamGenContext::edenscdplayer() { STACK_CHECK; showfirstuse(); @@ -14463,7 +11709,7 @@ afterpress: dumppointer(); dumpkeypad(); dumptextline(); - bx = 3482; + bx = offset_keypadlist; checkcoords(); _cmp(data.byte(kGetback), 1); if (flags.z()) @@ -14803,7 +12049,7 @@ menuloop: dumppointer(); dumpmenu(); dumptextline(); - bx = 3614; + bx = offset_menulist; checkcoords(); _cmp(data.byte(kGetback), 1); if (!flags.z()) @@ -14916,7 +12162,7 @@ folderloop: vsync(); dumppointer(); dumptextline(); - bx = 3636; + bx = offset_folderlist; checkcoords(); _cmp(data.byte(kGetback), 0); if (flags.z()) @@ -14960,7 +12206,7 @@ donextf: delpointer(); showfolder(); data.word(kMousebutton) = 0; - bx = 3636; + bx = offset_folderlist; checkcoords(); worktoscreenm(); } @@ -15047,7 +12293,7 @@ dolastf: delpointer(); showfolder(); data.word(kMousebutton) = 0; - bx = 3636; + bx = offset_folderlist; checkcoords(); worktoscreenm(); } @@ -15309,7 +12555,7 @@ symbolloop: dumppointer(); dumptextline(); dumpsymbol(); - bx = 3678; + bx = offset_symbollist; checkcoords(); _cmp(data.byte(kGetback), 0); if (flags.z()) @@ -15680,7 +12926,7 @@ diaryloop: dumppointer(); dumpdiarykeys(); dumptextline(); - bx = 3740; + bx = offset_diarylist; checkcoords(); _cmp(data.byte(kGetback), 0); if (flags.z()) @@ -16016,7 +13262,7 @@ waitops: dumppointer(); dumptextline(); delpointer(); - bx = 3782; + bx = offset_opslist; checkcoords(); _cmp(data.byte(kGetback), 0); if (flags.z()) @@ -16106,71 +13352,6 @@ void DreamGenContext::loadsavebox() { loadintotemp(); } -void DreamGenContext::loadgame() { - STACK_CHECK; - _cmp(data.byte(kCommandtype), 246); - if (flags.z()) - goto alreadyload; - data.byte(kCommandtype) = 246; - al = 41; - commandonly(); -alreadyload: - ax = data.word(kMousebutton); - _cmp(ax, data.word(kOldbutton)); - if (flags.z()) - return /* (noload) */; - _cmp(ax, 1); - if (flags.z()) - goto doload; - return; -doload: - data.byte(kLoadingorsave) = 1; - showopbox(); - showloadops(); - data.byte(kCurrentslot) = 0; - showslots(); - shownames(); - data.byte(kPointerframe) = 0; - worktoscreenm(); - namestoold(); - data.byte(kGetback) = 0; -loadops: - _cmp(data.byte(kQuitrequested), 0); - if (!flags.z()) - return /* (quitloaded) */; - delpointer(); - readmouse(); - showpointer(); - vsync(); - dumppointer(); - dumptextline(); - bx = 3824; - checkcoords(); - _cmp(data.byte(kGetback), 0); - if (flags.z()) - goto loadops; - _cmp(data.byte(kGetback), 2); - if (flags.z()) - return /* (quitloaded) */; - getridoftemp(); - dx = data; - es = dx; - bx = 7979; - startloading(); - loadroomssample(); - data.byte(kRoomloaded) = 1; - data.byte(kNewlocation) = 255; - clearsprites(); - initman(); - initrain(); - data.word(kTextaddressx) = 13; - data.word(kTextaddressy) = 182; - data.byte(kTextlen) = 240; - startup(); - worktoscreen(); - data.byte(kGetback) = 4; -} - void DreamGenContext::getbacktoops() { STACK_CHECK; _cmp(data.byte(kCommandtype), 201); @@ -16228,63 +13409,13 @@ discopsloop: vsync(); dumppointer(); dumptextline(); - bx = 3866; + bx = offset_discopslist; checkcoords(); _cmp(data.byte(kGetback), 0); if (flags.z()) goto discopsloop; } -void DreamGenContext::savegame() { - STACK_CHECK; - _cmp(data.byte(kMandead), 2); - if (!flags.z()) - goto cansaveok; - blank(); - return; -cansaveok: - _cmp(data.byte(kCommandtype), 247); - if (flags.z()) - goto alreadysave; - data.byte(kCommandtype) = 247; - al = 44; - commandonly(); -alreadysave: - ax = data.word(kMousebutton); - _and(ax, 1); - if (!flags.z()) - goto dosave; - return; -dosave: - data.byte(kLoadingorsave) = 2; - showopbox(); - showsaveops(); - data.byte(kCurrentslot) = 0; - showslots(); - shownames(); - worktoscreenm(); - namestoold(); - data.word(kBufferin) = 0; - data.word(kBufferout) = 0; - data.byte(kGetback) = 0; -saveops: - _cmp(data.byte(kQuitrequested), 0); - if (!flags.z()) - return /* (quitsavegame) */; - delpointer(); - checkinput(); - readmouse(); - showpointer(); - vsync(); - dumppointer(); - dumptextline(); - bx = 3908; - checkcoords(); - _cmp(data.byte(kGetback), 0); - if (flags.z()) - goto saveops; -} - void DreamGenContext::actualsave() { STACK_CHECK; _cmp(data.byte(kCommandtype), 222); @@ -16811,21 +13942,6 @@ isntblank: _stosw(); } -void DreamGenContext::findlen() { - STACK_CHECK; - _dec(bx); - _add(bx, ax); -nextone: - _cmp(cl, ds.byte(bx)); - if (!flags.z()) - return /* (foundlen) */; - _dec(bx); - _dec(ax); - _cmp(ax, 0); - if (!flags.z()) - goto nextone; -} - void DreamGenContext::scanfornames() { STACK_CHECK; dx = data; @@ -16905,7 +14021,7 @@ _tmp1: dumppointer(); dumptextline(); delpointer(); - bx = 5057; + bx = offset_decidelist; checkcoords(); _cmp(data.byte(kGetback), 0); if (flags.z()) @@ -16949,55 +14065,6 @@ alreadynewgame: data.byte(kGetback) = 3; } -void DreamGenContext::doload() { - STACK_CHECK; - data.byte(kLoadingorsave) = 1; - showopbox(); - showloadops(); - data.byte(kCurrentslot) = 0; - showslots(); - shownames(); - data.byte(kPointerframe) = 0; - worktoscreenm(); - namestoold(); - data.byte(kGetback) = 0; -loadops: - _cmp(data.byte(kQuitrequested), 0); - if (!flags.z()) - return /* (quitloaded) */; - delpointer(); - readmouse(); - showpointer(); - vsync(); - dumppointer(); - dumptextline(); - bx = 3824; - checkcoords(); - _cmp(data.byte(kGetback), 0); - if (flags.z()) - goto loadops; - _cmp(data.byte(kGetback), 2); - if (flags.z()) - return /* (quitloaded) */; - getridoftemp(); - dx = data; - es = dx; - bx = 7979; - startloading(); - loadroomssample(); - data.byte(kRoomloaded) = 1; - data.byte(kNewlocation) = 255; - clearsprites(); - initman(); - initrain(); - data.word(kTextaddressx) = 13; - data.word(kTextaddressy) = 182; - data.byte(kTextlen) = 240; - startup(); - worktoscreen(); - data.byte(kGetback) = 4; -} - void DreamGenContext::loadold() { STACK_CHECK; _cmp(data.byte(kCommandtype), 252); @@ -17011,6 +14078,7 @@ alreadyloadold: _and(ax, 1); if (flags.z()) return /* (noloadold) */; + ax = 0x0ffff; doload(); _cmp(data.byte(kGetback), 4); if (flags.z()) @@ -17026,7 +14094,7 @@ alreadyloadold: void DreamGenContext::createname() { STACK_CHECK; push(ax); - di = 5105; + di = offset_speechfile; cs.byte(di+0) = dl; cs.byte(di+3) = cl; al = dh; @@ -17193,46 +14261,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); @@ -17254,175 +14282,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::cancelch0() { - STACK_CHECK; - data.byte(kCh0repeat) = 0; - data.word(kCh0blockstocopy) = 0; - data.byte(kCh0playing) = 255; -} - -void DreamGenContext::cancelch1() { - STACK_CHECK; - data.word(kCh1blockstocopy) = 0; - data.byte(kCh1playing) = 255; -} - -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); @@ -17845,84 +14704,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; @@ -18413,11 +15194,11 @@ toofaraway: void DreamGenContext::mainscreen() { STACK_CHECK; data.byte(kInmaparea) = 0; - bx = 5122; + bx = offset_mainlist; _cmp(data.byte(kWatchon), 1); if (flags.z()) goto checkmain; - bx = 5184; + bx = offset_mainlist2; checkmain: checkcoords(); _cmp(data.byte(kWalkandexam), 0); @@ -18557,69 +15338,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); @@ -18696,41 +15414,6 @@ notanexid: goto identifyex; } -void DreamGenContext::checkiffree() { - STACK_CHECK; - es = data.word(kBuffers); - bx = (0+(228*13)+32+60+(32*32)+(11*10*3)+768+768+768+(32*32)+(128*5))+(79*5); - cx = 79; -identifyfree: - _cmp(es.byte(bx+4), 255); - if (flags.z()) - goto notafreeid; - _cmp(al, es.byte(bx)); - if (flags.c()) - goto notafreeid; - _cmp(al, es.byte(bx+2)); - if (!flags.c()) - goto notafreeid; - _cmp(ah, es.byte(bx+1)); - if (flags.c()) - goto notafreeid; - _cmp(ah, es.byte(bx+3)); - if (!flags.c()) - goto notafreeid; - al = es.byte(bx+4); - ah = 2; - obname(); - al = 0; - _cmp(al, 1); - return; -notafreeid: - _sub(bx, 5); - _dec(cx); - _cmp(cx, -1); - if (!flags.z()) - goto identifyfree; -} - void DreamGenContext::isitdescribed() { STACK_CHECK; push(ax); @@ -18996,7 +15679,7 @@ void DreamGenContext::atmospheres() { STACK_CHECK; cl = data.byte(kMapx); ch = data.byte(kMapy); - bx = 5246; + bx = offset_atmospherelist; nextatmos: al = cs.byte(bx); _cmp(al, 255); @@ -19236,15 +15919,6 @@ toofaraway: walktotext(); } -void DreamGenContext::finishedwalking() { - STACK_CHECK; - _cmp(data.byte(kLinepointer), 254); - if (!flags.z()) - return /* (iswalking) */; - al = data.byte(kFacing); - _cmp(al, data.byte(kTurntoface)); -} - void DreamGenContext::examineobtext() { STACK_CHECK; bl = data.byte(kCommand); @@ -19253,95 +15927,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); - 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(); - 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(); - data.byte(kNewtextline) = 1; -} - void DreamGenContext::printmessage() { STACK_CHECK; push(dx); @@ -19391,31 +15976,6 @@ searchmess: printdirect(); } -void DreamGenContext::blocknametext() { - STACK_CHECK; - bl = data.byte(kCommand); - bh = data.byte(kCommandtype); - al = 0; - commandwithob(); -} - -void DreamGenContext::personnametext() { - STACK_CHECK; - bl = data.byte(kCommand); - _and(bl, 127); - bh = data.byte(kCommandtype); - al = 2; - commandwithob(); -} - -void DreamGenContext::walktotext() { - STACK_CHECK; - bl = data.byte(kCommand); - bh = data.byte(kCommandtype); - al = 3; - commandwithob(); -} - void DreamGenContext::getflagunderp() { STACK_CHECK; cx = data.word(kMousex); @@ -19471,109 +16031,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(); @@ -19789,106 +16246,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); @@ -19993,22 +16350,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; @@ -20151,7 +16492,7 @@ void DreamGenContext::showblink() { al = 6; nomorethan6: ah = 0; - bx = 5888; + bx = offset_blinktab; _add(bx, ax); al = cs.byte(bx); ds = data.word(kIcons1); @@ -20317,32 +16658,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(); @@ -20515,40 +16830,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::dumptextline() { - STACK_CHECK; - _cmp(data.byte(kNewtextline), 1); - if (!flags.z()) - return /* (nodumptextline) */; - data.byte(kNewtextline) = 0; - di = data.word(kTextaddressx); - bx = data.word(kTextaddressy); - _cmp(data.byte(kForeignrelease), 0); - if (flags.z()) - goto _tmp1; - _sub(bx, 3); -_tmp1: - cl = (228); - ch = (13); - multidump(); -} - void DreamGenContext::animpointer() { STACK_CHECK; _cmp(data.byte(kPointermode), 2); @@ -20611,7 +16892,7 @@ rightspeed3: finflashmouse: al = data.byte(kPointercount); ah = 0; - bx = 5895; + bx = offset_flashmousetab; _add(bx, ax); al = cs.byte(bx); data.byte(kPointerframe) = al; @@ -20704,7 +16985,7 @@ void DreamGenContext::readkey() { _inc(bx); _and(bx, 15); data.word(kBufferout) = bx; - di = 5912; + di = offset_keybuffer; _add(di, bx); al = cs.byte(di); data.byte(kCurrentkey) = al; @@ -21028,142 +17309,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); @@ -21198,22 +17343,6 @@ lookx2: es.byte(bx+6) = al; } -void DreamGenContext::findxyfrompath() { - STACK_CHECK; - getroomspaths(); - al = data.byte(kManspath); - ah = 0; - _add(ax, ax); - _add(ax, ax); - _add(ax, ax); - _add(bx, ax); - ax = es.word(bx); - _sub(al, 12); - _sub(ah, 12); - data.byte(kRyanx) = al; - data.byte(kRyany) = ah; -} - void DreamGenContext::findroominloc() { STACK_CHECK; al = data.byte(kMapy); @@ -21233,25 +17362,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); @@ -21264,23 +17374,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); @@ -21351,153 +17444,6 @@ void DreamGenContext::readsetdata() { closefile(); } -void DreamGenContext::makename() { - STACK_CHECK; - si = dx; - di = 6061; -transfer: - al = cs.byte(si); - cs.byte(di) = al; - _inc(si); - _inc(di); - _cmp(al, 0); - if (!flags.z()) - goto transfer; - dx = 6059; -} - -void DreamGenContext::dreamweb() { - STACK_CHECK; - seecommandtail(); - checkbasemem(); - soundstartup(); - setkeyboardint(); - setupemm(); - allocatebuffers(); - setmouse(); - fadedos(); - gettime(); - clearbuffers(); - clearpalette(); - set16colpalette(); - readsetdata(); - data.byte(kWongame) = 0; - dx = 1909; - loadsample(); - setsoundoff(); - scanfornames(); - _cmp(al, 0); - if (!flags.z()) - goto dodecisions; - setmode(); - loadpalfromiff(); - titles(); - credits(); - goto playgame; -dodecisions: - cls(); - setmode(); - decide(); - _cmp(data.byte(kQuitrequested), 0); - if (!flags.z()) - return /* (exitgame) */; - _cmp(data.byte(kGetback), 4); - if (flags.z()) - goto mainloop; - titles(); - _cmp(data.byte(kQuitrequested), 0); - if (!flags.z()) - return /* (exitgame) */; - credits(); -playgame: - _cmp(data.byte(kQuitrequested), 0); - if (!flags.z()) - return /* (exitgame) */; - clearchanges(); - setmode(); - loadpalfromiff(); - data.byte(kLocation) = 255; - data.byte(kRoomafterdream) = 1; - data.byte(kNewlocation) = 35; - data.byte(kVolume) = 7; - loadroom(); - clearsprites(); - initman(); - entrytexts(); - entryanims(); - data.byte(kDestpos) = 3; - initialinv(); - data.byte(kLastflag) = 32; - startup1(); - data.byte(kVolumeto) = 0; - data.byte(kVolumedirection) = -1; - data.byte(kCommandtype) = 255; - goto mainloop; -loadnew: - clearbeforeload(); - loadroom(); - clearsprites(); - initman(); - entrytexts(); - entryanims(); - data.byte(kNewlocation) = 255; - startup(); - data.byte(kCommandtype) = 255; - worktoscreenm(); - goto mainloop; - data.byte(kNewlocation) = 255; - clearsprites(); - initman(); - startup(); - data.byte(kCommandtype) = 255; -mainloop: - _cmp(data.byte(kQuitrequested), 0); - if (!flags.z()) - return /* (exitgame) */; - screenupdate(); - _cmp(data.byte(kWongame), 0); - if (!flags.z()) - goto endofgame; - _cmp(data.byte(kMandead), 1); - if (flags.z()) - goto gameover; - _cmp(data.byte(kMandead), 2); - if (flags.z()) - goto gameover; - _cmp(data.word(kWatchingtime), 0); - if (flags.z()) - goto notwatching; - al = data.byte(kFinaldest); - _cmp(al, data.byte(kManspath)); - if (!flags.z()) - goto mainloop; - _dec(data.word(kWatchingtime)); - if (!flags.z()) - goto mainloop; -notwatching: - _cmp(data.byte(kMandead), 4); - if (flags.z()) - goto gameover; - _cmp(data.byte(kNewlocation), 255); - if (!flags.z()) - goto loadnew; - goto mainloop; -gameover: - clearbeforeload(); - showgun(); - fadescreendown(); - cx = 100; - hangon(); - goto dodecisions; -endofgame: - clearbeforeload(); - fadescreendowns(); - cx = 200; - hangon(); - endgame(); - { quickquit2(); return; }; -} - void DreamGenContext::__start() { @@ -22075,745 +18021,647 @@ dreamweb(); void DreamGenContext::__dispatch_call(uint16 addr) { switch(addr) { - case 0xc000: alleybarksound(); break; - case 0xc004: intromusic(); break; - case 0xc008: foghornsound(); break; - case 0xc00c: receptionist(); break; - case 0xc010: smokebloke(); break; - case 0xc014: attendant(); break; - case 0xc018: manasleep(); break; - case 0xc01c: eden(); break; - case 0xc020: edeninbath(); break; - case 0xc024: malefan(); break; - case 0xc028: femalefan(); break; - case 0xc02c: louis(); break; - case 0xc030: louischair(); break; - case 0xc034: manasleep2(); break; - case 0xc038: mansatstill(); break; - case 0xc03c: tattooman(); break; - case 0xc040: drinker(); break; - case 0xc044: bartender(); break; - case 0xc048: othersmoker(); break; - case 0xc04c: barwoman(); break; - case 0xc050: interviewer(); break; - case 0xc054: soldier1(); break; - case 0xc058: rockstar(); break; - case 0xc05c: helicopter(); break; - case 0xc060: mugger(); break; - case 0xc064: aide(); break; - case 0xc068: businessman(); break; - case 0xc06c: poolguard(); break; - case 0xc070: security(); break; - case 0xc074: heavy(); break; - case 0xc078: bossman(); break; - case 0xc07c: gamer(); break; - case 0xc080: sparkydrip(); break; - case 0xc084: carparkdrip(); break; - case 0xc088: keeper(); break; - case 0xc08c: candles1(); break; - case 0xc090: smallcandle(); break; - case 0xc094: intromagic1(); break; - case 0xc098: candles(); break; - case 0xc09c: candles2(); break; - case 0xc0a0: gates(); break; - case 0xc0a4: intromagic2(); break; - case 0xc0a8: intromagic3(); break; - case 0xc0ac: intromonks1(); break; - case 0xc0b0: intromonks2(); break; - case 0xc0b4: handclap(); break; - case 0xc0b8: monks2text(); break; - case 0xc0bc: intro1text(); break; - case 0xc0c0: intro2text(); break; - case 0xc0c4: intro3text(); break; - case 0xc0c8: monkandryan(); break; - case 0xc0cc: endgameseq(); break; - case 0xc0d0: rollendcredits(); break; - case 0xc0d4: priest(); break; - case 0xc0d8: madmanstelly(); break; - case 0xc0dc: madman(); break; - case 0xc0e0: madmantext(); break; - case 0xc0e4: madmode(); break; - case 0xc0e8: priesttext(); break; - case 0xc0ec: textforend(); break; - case 0xc0f0: textformonk(); break; - case 0xc0f4: drunk(); break; - case 0xc0f8: advisor(); break; - case 0xc0fc: copper(); break; - case 0xc100: sparky(); break; - case 0xc104: train(); break; - case 0xc108: addtopeoplelist(); break; - case 0xc10c: showgamereel(); break; - case 0xc110: checkspeed(); break; - case 0xc114: clearsprites(); break; - case 0xc118: makesprite(); break; - case 0xc11c: delsprite(); break; - case 0xc120: spriteupdate(); break; - case 0xc124: printsprites(); break; - case 0xc128: printasprite(); break; - case 0xc12c: checkone(); break; - case 0xc130: findsource(); break; - case 0xc134: initman(); break; - case 0xc138: mainman(); break; - case 0xc13c: aboutturn(); break; - case 0xc140: walking(); break; - case 0xc144: facerightway(); break; - case 0xc148: checkforexit(); break; - case 0xc14c: adjustdown(); break; - case 0xc150: adjustup(); break; - case 0xc154: adjustleft(); break; - case 0xc158: adjustright(); break; - case 0xc15c: reminders(); break; - case 0xc160: initrain(); break; - case 0xc164: splitintolines(); break; - case 0xc168: getblockofpixel(); break; - case 0xc16c: showrain(); break; - case 0xc170: backobject(); break; - case 0xc174: liftsprite(); break; - case 0xc178: liftnoise(); break; - case 0xc17c: random(); break; - case 0xc180: steady(); break; - case 0xc184: constant(); break; - case 0xc188: doorway(); break; - case 0xc18c: widedoor(); break; - case 0xc190: dodoor(); break; - case 0xc194: lockeddoorway(); break; - case 0xc198: updatepeople(); break; - case 0xc19c: getreelframeax(); break; - case 0xc1a0: reelsonscreen(); break; - case 0xc1a4: plotreel(); break; - case 0xc1a8: soundonreels(); break; - case 0xc1ac: reconstruct(); break; - case 0xc1b0: dealwithspecial(); break; - case 0xc1b4: movemap(); break; - case 0xc1b8: getreelstart(); break; - case 0xc1bc: showreelframe(); break; - case 0xc1c0: deleverything(); break; - case 0xc1c4: dumpeverything(); break; - case 0xc1c8: allocatework(); break; - case 0xc1cc: showpcx(); break; - case 0xc1d8: loadpalfromiff(); break; - case 0xc1dc: setmode(); break; - case 0xc1ec: paneltomap(); break; - case 0xc1f0: maptopanel(); break; - case 0xc1f4: dumpmap(); break; - case 0xc1f8: pixelcheckset(); break; - case 0xc1fc: createpanel(); break; - case 0xc200: createpanel2(); break; - case 0xc204: clearwork(); break; - case 0xc208: vsync(); break; - case 0xc20c: doshake(); break; - case 0xc210: zoom(); break; - case 0xc214: delthisone(); break; - case 0xc228: doblocks(); break; - case 0xc22c: showframe(); break; - case 0xc238: frameoutbh(); break; - case 0xc23c: frameoutfx(); break; - case 0xc240: transferinv(); break; - case 0xc244: transfermap(); break; - case 0xc248: fadedos(); break; - case 0xc24c: dofade(); break; - case 0xc250: clearendpal(); break; - case 0xc254: clearpalette(); break; - case 0xc258: fadescreenup(); break; - case 0xc25c: fadetowhite(); break; - case 0xc260: fadefromwhite(); break; - case 0xc264: fadescreenups(); break; - case 0xc268: fadescreendownhalf(); break; - case 0xc26c: fadescreenuphalf(); break; - case 0xc270: fadescreendown(); break; - case 0xc274: fadescreendowns(); break; - case 0xc278: clearstartpal(); break; - case 0xc27c: showgun(); break; - case 0xc280: rollendcredits2(); break; - case 0xc284: rollem(); break; - case 0xc288: fadecalculation(); break; - case 0xc28c: greyscalesum(); break; - case 0xc290: showgroup(); break; - case 0xc294: paltostartpal(); break; - case 0xc298: endpaltostart(); break; - case 0xc29c: startpaltoend(); break; - case 0xc2a0: paltoendpal(); break; - case 0xc2a4: allpalette(); break; - case 0xc2a8: dumpcurrent(); break; - case 0xc2ac: fadedownmon(); break; - case 0xc2b0: fadeupmon(); break; - case 0xc2b4: fadeupmonfirst(); break; - case 0xc2b8: fadeupyellows(); break; - case 0xc2bc: initialmoncols(); break; - case 0xc2c0: titles(); break; - case 0xc2c4: endgame(); break; - case 0xc2c8: monkspeaking(); break; - case 0xc2cc: showmonk(); break; - case 0xc2d0: gettingshot(); break; - case 0xc2d4: credits(); break; - case 0xc2d8: biblequote(); break; - case 0xc2dc: hangone(); break; - case 0xc2e0: intro(); break; - case 0xc2e4: runintroseq(); break; - case 0xc2e8: runendseq(); break; - case 0xc2ec: loadintroroom(); break; - case 0xc2f0: mode640x480(); break; - case 0xc2f4: set16colpalette(); break; - case 0xc2f8: realcredits(); break; - case 0xc2fc: printchar(); break; - case 0xc300: kernchars(); break; - case 0xc304: printslow(); break; - case 0xc308: waitframes(); break; - case 0xc30c: printboth(); break; - case 0xc310: printdirect(); break; - case 0xc314: monprint(); break; - case 0xc318: getnumber(); break; - case 0xc31c: getnextword(); break; - case 0xc320: fillryan(); break; - case 0xc324: fillopen(); break; - case 0xc328: findallryan(); break; - case 0xc32c: findallopen(); break; - case 0xc330: obtoinv(); break; - case 0xc334: isitworn(); break; - case 0xc338: makeworn(); break; - case 0xc33c: examineob(); break; - case 0xc340: makemainscreen(); break; - case 0xc344: getbackfromob(); break; - case 0xc348: incryanpage(); break; - case 0xc34c: openinv(); break; - case 0xc350: showryanpage(); break; - case 0xc354: openob(); break; - case 0xc358: obicons(); break; - case 0xc35c: examicon(); break; - case 0xc360: obpicture(); break; - case 0xc364: describeob(); break; - case 0xc368: additionaltext(); break; - case 0xc36c: obsthatdothings(); break; - case 0xc370: getobtextstart(); break; - case 0xc374: searchforsame(); break; - case 0xc378: findnextcolon(); break; - case 0xc37c: inventory(); break; - case 0xc380: setpickup(); break; - case 0xc384: examinventory(); break; - case 0xc388: reexfrominv(); break; - case 0xc38c: reexfromopen(); break; - case 0xc390: swapwithinv(); break; - case 0xc394: swapwithopen(); break; - case 0xc398: intoinv(); break; - case 0xc39c: deletetaken(); break; - case 0xc3a0: outofinv(); break; - case 0xc3a4: getfreead(); break; - case 0xc3a8: getexad(); break; - case 0xc3ac: geteitherad(); break; - case 0xc3b0: getanyad(); break; - case 0xc3b4: getanyaddir(); break; - case 0xc3b8: getopenedsize(); break; - case 0xc3bc: getsetad(); break; - case 0xc3c0: findinvpos(); break; - case 0xc3c4: findopenpos(); break; - case 0xc3c8: dropobject(); break; - case 0xc3cc: droperror(); break; - case 0xc3d0: cantdrop(); break; - case 0xc3d4: wornerror(); break; - case 0xc3d8: removeobfrominv(); break; - case 0xc3dc: selectopenob(); break; - case 0xc3e0: useopened(); break; - case 0xc3e4: errormessage1(); break; - case 0xc3e8: errormessage2(); break; - case 0xc3ec: errormessage3(); break; - case 0xc3f0: checkobjectsize(); break; - case 0xc3f4: outofopen(); break; - case 0xc3f8: transfertoex(); break; - case 0xc3fc: pickupconts(); break; - case 0xc400: transfercontoex(); break; - case 0xc404: transfertext(); break; - case 0xc408: getexpos(); break; - case 0xc40c: purgealocation(); break; - case 0xc410: emergencypurge(); break; - case 0xc414: purgeanitem(); break; - case 0xc418: deleteexobject(); break; - case 0xc41c: deleteexframe(); break; - case 0xc420: deleteextext(); break; - case 0xc424: blockget(); break; - case 0xc428: drawfloor(); break; - case 0xc42c: calcmapad(); break; - case 0xc430: getdimension(); break; - case 0xc434: addalong(); break; - case 0xc438: addlength(); break; - case 0xc43c: drawflags(); break; - case 0xc440: eraseoldobs(); break; - case 0xc444: showallobs(); break; - case 0xc448: makebackob(); break; - case 0xc44c: showallfree(); break; - case 0xc450: showallex(); break; - case 0xc454: calcfrframe(); break; - case 0xc458: finalframe(); break; - case 0xc45c: adjustlen(); break; - case 0xc460: getmapad(); break; - case 0xc464: getxad(); break; - case 0xc468: getyad(); break; - case 0xc46c: autolook(); break; - case 0xc470: look(); break; - case 0xc474: dolook(); break; - case 0xc478: redrawmainscrn(); break; - case 0xc47c: getback1(); break; - case 0xc480: talk(); break; - case 0xc484: convicons(); break; - case 0xc488: getpersframe(); break; - case 0xc48c: starttalk(); break; - case 0xc490: getpersontext(); break; - case 0xc494: moretalk(); break; - case 0xc498: dosometalk(); break; - case 0xc49c: hangonpq(); break; - case 0xc4a0: redes(); break; - case 0xc4a4: newplace(); break; - case 0xc4a8: selectlocation(); break; - case 0xc4ac: showcity(); break; - case 0xc4b0: lookatplace(); break; - case 0xc4b4: getundercentre(); break; - case 0xc4b8: putundercentre(); break; - case 0xc4bc: locationpic(); break; - case 0xc4c0: getdestinfo(); break; - case 0xc4c4: showarrows(); break; - case 0xc4c8: nextdest(); break; - case 0xc4cc: lastdest(); break; - case 0xc4d0: destselect(); break; - case 0xc4d4: getlocation(); break; - case 0xc4d8: setlocation(); break; - case 0xc4dc: resetlocation(); break; - case 0xc4e0: readdesticon(); break; - case 0xc4e4: readcitypic(); break; - case 0xc4e8: usemon(); break; - case 0xc4ec: printoutermon(); break; - case 0xc4f0: loadpersonal(); break; - case 0xc4f4: loadnews(); break; - case 0xc4f8: loadcart(); break; - case 0xc4fc: lookininterface(); break; - case 0xc500: turnonpower(); break; - case 0xc504: randomaccess(); break; - case 0xc508: powerlighton(); break; - case 0xc50c: powerlightoff(); break; - case 0xc510: accesslighton(); break; - case 0xc514: accesslightoff(); break; - case 0xc518: locklighton(); break; - case 0xc51c: locklightoff(); break; - case 0xc520: input(); break; - case 0xc524: makecaps(); break; - case 0xc528: delchar(); break; - case 0xc52c: execcommand(); break; - case 0xc530: neterror(); break; - case 0xc534: dircom(); break; - case 0xc538: searchforfiles(); break; - case 0xc53c: signon(); break; - case 0xc540: showkeys(); break; - case 0xc544: read(); break; - case 0xc548: dirfile(); break; - case 0xc54c: getkeyandlogo(); break; - case 0xc550: searchforstring(); break; - case 0xc554: parser(); break; - case 0xc558: scrollmonitor(); break; - case 0xc55c: lockmon(); break; - case 0xc560: monitorlogo(); break; - case 0xc564: printlogo(); break; - case 0xc568: showcurrentfile(); break; - case 0xc56c: monmessage(); break; - case 0xc570: processtrigger(); break; - case 0xc574: triggermessage(); break; - case 0xc578: printcurs(); break; - case 0xc57c: delcurs(); break; - case 0xc580: useobject(); break; - case 0xc584: useroutine(); break; - case 0xc588: wheelsound(); break; - case 0xc58c: runtap(); break; - case 0xc590: playguitar(); break; - case 0xc594: hotelcontrol(); break; - case 0xc598: hotelbell(); break; - case 0xc59c: opentomb(); break; - case 0xc5a0: usetrainer(); break; - case 0xc5a4: nothelderror(); break; - case 0xc5a8: usepipe(); break; - case 0xc5ac: usefullcart(); break; - case 0xc5b0: useplinth(); break; - case 0xc5b4: chewy(); break; - case 0xc5b8: useladder(); break; - case 0xc5bc: useladderb(); break; - case 0xc5c0: slabdoora(); break; - case 0xc5c4: slabdoorb(); break; - case 0xc5c8: slabdoord(); break; - case 0xc5cc: slabdoorc(); break; - case 0xc5d0: slabdoore(); break; - case 0xc5d4: slabdoorf(); break; - case 0xc5d8: useslab(); break; - case 0xc5dc: usecart(); break; - case 0xc5e0: useclearbox(); break; - case 0xc5e4: usecoveredbox(); break; - case 0xc5e8: userailing(); break; - case 0xc5ec: useopenbox(); break; - case 0xc5f0: wearwatch(); break; - case 0xc5f4: wearshades(); break; - case 0xc5f8: sitdowninbar(); break; - case 0xc5fc: usechurchhole(); break; - case 0xc600: usehole(); break; - case 0xc604: usealtar(); break; - case 0xc608: opentvdoor(); break; - case 0xc60c: usedryer(); break; - case 0xc610: openlouis(); break; - case 0xc614: nextcolon(); break; - case 0xc618: openyourneighbour(); break; - case 0xc61c: usewindow(); break; - case 0xc620: usebalcony(); break; - case 0xc624: openryan(); break; - case 0xc628: openpoolboss(); break; - case 0xc62c: openeden(); break; - case 0xc630: opensarters(); break; - case 0xc634: isitright(); break; - case 0xc638: drawitall(); break; - case 0xc63c: openhoteldoor(); break; - case 0xc640: openhoteldoor2(); break; - case 0xc644: grafittidoor(); break; - case 0xc648: trapdoor(); break; - case 0xc64c: callhotellift(); break; - case 0xc650: calledenslift(); break; - case 0xc654: calledensdlift(); break; - case 0xc658: usepoolreader(); break; - case 0xc65c: uselighter(); break; - case 0xc660: showseconduse(); break; - case 0xc664: usecardreader1(); break; - case 0xc668: usecardreader2(); break; - case 0xc66c: usecardreader3(); break; - case 0xc670: usecashcard(); break; - case 0xc674: lookatcard(); break; - case 0xc678: moneypoke(); break; - case 0xc67c: usecontrol(); break; - case 0xc680: usehatch(); break; - case 0xc684: usewire(); break; - case 0xc688: usehandle(); break; - case 0xc68c: useelevator1(); break; - case 0xc690: showfirstuse(); break; - case 0xc694: useelevator3(); break; - case 0xc698: useelevator4(); break; - case 0xc69c: useelevator2(); break; - case 0xc6a0: useelevator5(); break; - case 0xc6a4: usekey(); break; - case 0xc6a8: usestereo(); break; - case 0xc6ac: usecooker(); break; - case 0xc6b0: useaxe(); break; - case 0xc6b4: useelvdoor(); break; - case 0xc6b8: withwhat(); break; - case 0xc6bc: selectob(); break; - case 0xc6c0: compare(); break; - case 0xc6c4: findsetobject(); break; - case 0xc6c8: findexobject(); break; - case 0xc6cc: isryanholding(); break; - case 0xc6d0: checkinside(); break; - case 0xc6d4: usetext(); break; - case 0xc6d8: putbackobstuff(); break; - case 0xc6dc: showpuztext(); break; - case 0xc6e0: findpuztext(); break; - case 0xc6e4: placesetobject(); break; - case 0xc6e8: removesetobject(); break; - case 0xc6ec: issetobonmap(); break; - case 0xc6f0: placefreeobject(); break; - case 0xc6f4: removefreeobject(); break; - case 0xc6f8: findormake(); break; - case 0xc6fc: switchryanon(); break; - case 0xc700: switchryanoff(); break; - case 0xc704: setallchanges(); break; - case 0xc708: dochange(); break; - case 0xc70c: autoappear(); break; - case 0xc710: getundertimed(); break; - case 0xc714: putundertimed(); break; - case 0xc718: dumptimedtext(); break; - case 0xc71c: setuptimeduse(); break; - case 0xc720: setuptimedtemp(); break; - case 0xc724: usetimedtext(); break; - case 0xc728: edenscdplayer(); break; - case 0xc72c: usewall(); break; - case 0xc730: usechurchgate(); break; - case 0xc734: usegun(); break; - case 0xc738: useshield(); break; - case 0xc73c: usebuttona(); break; - case 0xc740: useplate(); break; - case 0xc744: usewinch(); break; - case 0xc748: entercode(); break; - case 0xc74c: loadkeypad(); break; - case 0xc750: quitkey(); break; - case 0xc754: addtopresslist(); break; - case 0xc758: buttonone(); break; - case 0xc75c: buttontwo(); break; - case 0xc760: buttonthree(); break; - case 0xc764: buttonfour(); break; - case 0xc768: buttonfive(); break; - case 0xc76c: buttonsix(); break; - case 0xc770: buttonseven(); break; - case 0xc774: buttoneight(); break; - case 0xc778: buttonnine(); break; - case 0xc77c: buttonnought(); break; - case 0xc780: buttonenter(); break; - case 0xc784: buttonpress(); break; - case 0xc788: showouterpad(); break; - case 0xc78c: showkeypad(); break; - case 0xc790: singlekey(); break; - case 0xc794: dumpkeypad(); break; - case 0xc798: usemenu(); break; - case 0xc79c: dumpmenu(); break; - case 0xc7a0: getundermenu(); break; - case 0xc7a4: putundermenu(); break; - case 0xc7a8: showoutermenu(); break; - case 0xc7ac: showmenu(); break; - case 0xc7b0: loadmenu(); break; - case 0xc7b4: viewfolder(); break; - case 0xc7b8: nextfolder(); break; - case 0xc7bc: folderhints(); break; - case 0xc7c0: lastfolder(); break; - case 0xc7c4: loadfolder(); break; - case 0xc7c8: showfolder(); break; - case 0xc7cc: folderexit(); break; - case 0xc7d0: showleftpage(); break; - case 0xc7d4: showrightpage(); break; - case 0xc7d8: entersymbol(); break; - case 0xc7dc: quitsymbol(); break; - case 0xc7e0: settopleft(); break; - case 0xc7e4: settopright(); break; - case 0xc7e8: setbotleft(); break; - case 0xc7ec: setbotright(); break; - case 0xc7f0: dumpsymbol(); break; - case 0xc7f4: showsymbol(); break; - case 0xc7f8: nextsymbol(); break; - case 0xc7fc: updatesymboltop(); break; - case 0xc800: updatesymbolbot(); break; - case 0xc804: dumpsymbox(); break; - case 0xc808: usediary(); break; - case 0xc80c: showdiary(); break; - case 0xc810: showdiarykeys(); break; - case 0xc814: dumpdiarykeys(); break; - case 0xc818: diarykeyp(); break; - case 0xc81c: diarykeyn(); break; - case 0xc820: showdiarypage(); break; - case 0xc824: findtext1(); break; - case 0xc828: zoomonoff(); break; - case 0xc82c: saveload(); break; - case 0xc830: dosaveload(); break; - case 0xc834: getbackfromops(); break; - case 0xc838: showmainops(); break; - case 0xc83c: showdiscops(); break; - case 0xc840: loadsavebox(); break; - case 0xc844: loadgame(); break; - case 0xc848: getbacktoops(); break; - case 0xc84c: discops(); break; - case 0xc850: savegame(); break; - case 0xc854: actualsave(); break; - case 0xc858: actualload(); break; - case 0xc85c: selectslot2(); break; - case 0xc860: checkinput(); break; - case 0xc864: getnamepos(); break; - case 0xc868: showopbox(); break; - case 0xc86c: showloadops(); break; - case 0xc870: showsaveops(); break; - case 0xc874: selectslot(); break; - case 0xc878: showslots(); break; - case 0xc87c: shownames(); break; - case 0xc880: dosreturn(); break; - case 0xc884: error(); break; - case 0xc888: namestoold(); break; - case 0xc88c: oldtonames(); break; - case 0xc890: savefilewrite(); break; - case 0xc894: savefileread(); break; - case 0xc898: saveposition(); break; - case 0xc89c: loadposition(); break; - case 0xc8a0: loadseg(); break; - case 0xc8a4: makeheader(); break; - case 0xc8a8: storeit(); break; - case 0xc8ac: saveseg(); break; - case 0xc8b0: findlen(); break; - case 0xc8b4: scanfornames(); break; - case 0xc8b8: decide(); break; - case 0xc8bc: showdecisions(); break; - case 0xc8c0: newgame(); break; - case 0xc8c4: loadold(); break; - case 0xc8c8: loadspeech(); break; - case 0xc8cc: createname(); break; - case 0xc8d0: loadsample(); break; - case 0xc8d4: loadsecondsample(); break; - case 0xc8d8: soundstartup(); break; - case 0xc8dc: trysoundalloc(); break; - case 0xc8e0: setsoundoff(); break; - case 0xc8e4: checksoundint(); break; - case 0xc8e8: enablesoundint(); break; - case 0xc8ec: disablesoundint(); break; - case 0xc8f0: interupttest(); break; - case 0xc8f4: soundend(); break; - case 0xc8f8: out22c(); break; - case 0xc8fc: playchannel0(); break; - case 0xc900: playchannel1(); break; - case 0xc904: makenextblock(); break; - case 0xc908: volumeadjust(); break; - case 0xc90c: loopchannel0(); break; - case 0xc910: cancelch0(); break; - case 0xc914: cancelch1(); break; - case 0xc918: channel0only(); break; - case 0xc91c: channel1only(); break; - case 0xc920: channel0tran(); break; - case 0xc924: bothchannels(); break; - case 0xc928: saveems(); break; - case 0xc92c: restoreems(); break; - case 0xc930: domix(); break; - case 0xc934: dmaend(); break; - case 0xc938: startdmablock(); break; - case 0xc93c: setuppit(); break; - case 0xc940: getridofpit(); break; - case 0xc944: pitinterupt(); break; - case 0xc948: dreamweb(); break; - case 0xc94c: entrytexts(); break; - case 0xc950: entryanims(); break; - case 0xc954: initialinv(); break; - case 0xc958: pickupob(); break; - case 0xc95c: setupemm(); break; - case 0xc960: removeemm(); break; - case 0xc964: checkforemm(); break; - case 0xc968: checkbasemem(); break; - case 0xc96c: allocatebuffers(); break; - case 0xc970: clearbuffers(); break; - case 0xc974: clearchanges(); break; - case 0xc978: clearbeforeload(); break; - case 0xc97c: clearreels(); break; - case 0xc980: clearrest(); break; - case 0xc984: deallocatemem(); break; - case 0xc988: allocatemem(); break; - case 0xc990: parseblaster(); break; - case 0xc994: startup(); break; - case 0xc998: startup1(); break; - case 0xc99c: screenupdate(); break; - case 0xc9a0: watchreel(); break; - case 0xc9a4: checkforshake(); break; - case 0xc9a8: watchcount(); break; - case 0xc9ac: showtime(); break; - case 0xc9b0: dumpwatch(); break; - case 0xc9b4: showbyte(); break; - case 0xc9b8: onedigit(); break; - case 0xc9bc: twodigitnum(); break; - case 0xc9c0: showword(); break; - case 0xc9c4: convnum(); break; - case 0xc9c8: mainscreen(); break; - case 0xc9cc: madmanrun(); break; - case 0xc9d0: checkcoords(); break; - case 0xc9d4: identifyob(); break; - case 0xc9d8: checkifperson(); break; - case 0xc9dc: checkifset(); break; - case 0xc9e0: checkifex(); break; - case 0xc9e4: checkiffree(); break; - case 0xc9e8: isitdescribed(); break; - case 0xc9ec: findpathofpoint(); break; - case 0xc9f0: findfirstpath(); break; - case 0xc9f4: turnpathon(); break; - case 0xc9f8: turnpathoff(); break; - case 0xc9fc: turnanypathon(); break; - case 0xca00: turnanypathoff(); break; - case 0xca04: checkifpathison(); break; - case 0xca08: afternewroom(); break; - case 0xca0c: atmospheres(); break; - case 0xca10: walkintoroom(); break; - case 0xca14: afterintroroom(); break; - case 0xca18: obname(); break; - case 0xca1c: finishedwalking(); break; - case 0xca20: examineobtext(); break; - case 0xca24: commandwithob(); break; - case 0xca28: commandonly(); break; - case 0xca2c: printmessage(); break; - case 0xca30: printmessage2(); break; - case 0xca34: blocknametext(); break; - case 0xca38: personnametext(); break; - case 0xca3c: walktotext(); break; - case 0xca40: getflagunderp(); break; - case 0xca44: setwalk(); break; - case 0xca48: autosetwalk(); break; - case 0xca4c: checkdest(); break; - case 0xca50: bresenhams(); break; - case 0xca54: workoutframes(); break; - case 0xca58: getroomspaths(); break; - case 0xca5c: copyname(); break; - case 0xca60: findobname(); break; - case 0xca64: showicon(); break; - case 0xca68: middlepanel(); break; - case 0xca6c: showman(); break; - case 0xca70: showpanel(); break; - case 0xca74: roomname(); break; - case 0xca78: usecharset1(); break; - case 0xca7c: usetempcharset(); break; - case 0xca80: showexit(); break; - case 0xca84: panelicons1(); break; - case 0xca88: showwatch(); break; - case 0xca8c: gettime(); break; - case 0xca90: zoomicon(); break; - case 0xca94: showblink(); break; - case 0xca98: dumpblink(); break; - case 0xca9c: worktoscreenm(); break; - case 0xcaa0: blank(); break; - case 0xcaa4: allpointer(); break; - case 0xcaa8: hangonp(); break; - case 0xcaac: hangonw(); break; - case 0xcab0: hangoncurs(); break; - case 0xcab4: getunderzoom(); break; - case 0xcab8: dumpzoom(); break; - case 0xcabc: putunderzoom(); break; - case 0xcac0: crosshair(); break; - case 0xcac4: showpointer(); break; - case 0xcac8: delpointer(); break; - case 0xcacc: dumppointer(); break; - case 0xcad0: undertextline(); break; - case 0xcad4: deltextline(); break; - case 0xcad8: dumptextline(); break; - case 0xcadc: animpointer(); break; - case 0xcae0: setmouse(); break; - case 0xcae4: readmouse(); break; - case 0xcae8: mousecall(); break; - case 0xcaec: readmouse1(); break; - case 0xcaf0: readmouse2(); break; - case 0xcaf4: readmouse3(); break; - case 0xcaf8: readmouse4(); break; - case 0xcafc: readkey(); break; - case 0xcb04: randomnum1(); break; - case 0xcb08: randomnum2(); break; - case 0xcb10: hangon(); break; - case 0xcb14: loadtraveltext(); break; - case 0xcb18: loadintotemp(); break; - case 0xcb1c: loadintotemp2(); break; - case 0xcb20: loadintotemp3(); break; - case 0xcb24: loadtempcharset(); break; - case 0xcb28: standardload(); break; - case 0xcb2c: loadtemptext(); break; - case 0xcb30: loadroom(); break; - case 0xcb34: loadroomssample(); break; - case 0xcb38: getridofreels(); break; - case 0xcb3c: getridofall(); break; - case 0xcb40: restorereels(); break; - case 0xcb44: restoreall(); break; - case 0xcb48: sortoutmap(); break; - case 0xcb4c: startloading(); break; - case 0xcb50: disablepath(); break; - case 0xcb54: findxyfrompath(); break; - case 0xcb58: findroominloc(); break; - case 0xcb5c: getroomdata(); break; - case 0xcb60: readheader(); break; - case 0xcb64: dontloadseg(); break; - case 0xcb68: allocateload(); break; - case 0xcb6c: fillspace(); break; - case 0xcb70: getridoftemp(); break; - case 0xcb74: getridoftemptext(); break; - case 0xcb78: getridoftemp2(); break; - case 0xcb7c: getridoftemp3(); break; - case 0xcb80: getridoftempcharset(); break; - case 0xcb84: getridoftempsp(); break; - case 0xcb88: readsetdata(); break; - case 0xcb8c: createfile(); break; - case 0xcb90: openfile(); break; - case 0xcb94: openfilefromc(); break; - case 0xcb98: makename(); break; - case 0xcb9c: openfilenocheck(); break; - case 0xcba0: openforsave(); break; - case 0xcba4: closefile(); break; - case 0xcba8: readfromfile(); break; - case 0xcbac: setkeyboardint(); break; - case 0xcbb0: resetkeyboard(); break; - case 0xcbb4: keyboardread(); break; - case 0xcbb8: walkandexamine(); break; - case 0xcbbc: doload(); break; - case 0xcbc0: generalerror(); break; + case addr_alleybarksound: alleybarksound(); break; + case addr_intromusic: intromusic(); break; + case addr_foghornsound: foghornsound(); break; + case addr_receptionist: receptionist(); break; + case addr_smokebloke: smokebloke(); break; + case addr_attendant: attendant(); break; + case addr_manasleep: manasleep(); break; + case addr_eden: eden(); break; + case addr_edeninbath: edeninbath(); break; + case addr_malefan: malefan(); break; + case addr_femalefan: femalefan(); break; + case addr_louis: louis(); break; + case addr_louischair: louischair(); break; + case addr_manasleep2: manasleep2(); break; + case addr_mansatstill: mansatstill(); break; + case addr_tattooman: tattooman(); break; + case addr_drinker: drinker(); break; + case addr_bartender: bartender(); break; + case addr_othersmoker: othersmoker(); break; + case addr_barwoman: barwoman(); break; + case addr_interviewer: interviewer(); break; + case addr_soldier1: soldier1(); break; + case addr_rockstar: rockstar(); break; + case addr_helicopter: helicopter(); break; + case addr_mugger: mugger(); break; + case addr_aide: aide(); break; + case addr_businessman: businessman(); break; + case addr_poolguard: poolguard(); break; + case addr_security: security(); break; + case addr_heavy: heavy(); break; + case addr_bossman: bossman(); break; + case addr_gamer: gamer(); break; + case addr_sparkydrip: sparkydrip(); break; + case addr_carparkdrip: carparkdrip(); break; + case addr_keeper: keeper(); break; + case addr_candles1: candles1(); break; + case addr_smallcandle: smallcandle(); break; + case addr_intromagic1: intromagic1(); break; + case addr_candles: candles(); break; + case addr_candles2: candles2(); break; + case addr_gates: gates(); break; + case addr_intromagic2: intromagic2(); break; + case addr_intromagic3: intromagic3(); break; + case addr_intromonks1: intromonks1(); break; + case addr_intromonks2: intromonks2(); break; + case addr_handclap: handclap(); break; + case addr_monks2text: monks2text(); break; + case addr_intro1text: intro1text(); break; + case addr_intro2text: intro2text(); break; + case addr_intro3text: intro3text(); break; + case addr_monkandryan: monkandryan(); break; + case addr_endgameseq: endgameseq(); break; + case addr_rollendcredits: rollendcredits(); break; + case addr_priest: priest(); break; + case addr_madmanstelly: madmanstelly(); break; + case addr_madman: madman(); break; + case addr_priesttext: priesttext(); break; + case addr_textforend: textforend(); break; + case addr_textformonk: textformonk(); break; + case addr_drunk: drunk(); break; + case addr_advisor: advisor(); break; + case addr_copper: copper(); break; + case addr_sparky: sparky(); break; + case addr_train: train(); break; + case addr_addtopeoplelist: addtopeoplelist(); break; + case addr_checkspeed: checkspeed(); break; + case addr_delsprite: delsprite(); break; + case addr_mainman: mainman(); break; + case addr_checkforexit: checkforexit(); break; + case addr_adjustdown: adjustdown(); break; + case addr_adjustup: adjustup(); break; + case addr_adjustleft: adjustleft(); break; + case addr_adjustright: adjustright(); break; + case addr_reminders: reminders(); break; + case addr_initrain: initrain(); break; + case addr_splitintolines: splitintolines(); break; + case addr_getblockofpixel: getblockofpixel(); 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_reelsonscreen: reelsonscreen(); break; + case addr_soundonreels: soundonreels(); break; + case addr_reconstruct: reconstruct(); break; + case addr_deleverything: deleverything(); break; + case addr_dumpeverything: dumpeverything(); break; + case addr_showpcx: showpcx(); break; + case addr_loadpalfromiff: loadpalfromiff(); break; + case addr_setmode: setmode(); break; + case addr_paneltomap: paneltomap(); break; + case addr_maptopanel: maptopanel(); break; + case addr_dumpmap: dumpmap(); break; + case addr_pixelcheckset: pixelcheckset(); break; + case addr_createpanel: createpanel(); break; + case addr_createpanel2: createpanel2(); break; + case addr_vsync: vsync(); break; + case addr_doshake: doshake(); break; + case addr_delthisone: delthisone(); break; + case addr_transferinv: transferinv(); break; + case addr_transfermap: transfermap(); break; + case addr_fadedos: fadedos(); break; + case addr_dofade: dofade(); break; + case addr_clearendpal: clearendpal(); break; + case addr_clearpalette: clearpalette(); break; + case addr_fadescreenup: fadescreenup(); break; + case addr_fadetowhite: fadetowhite(); break; + case addr_fadefromwhite: fadefromwhite(); break; + case addr_fadescreenups: fadescreenups(); break; + case addr_fadescreendownhalf: fadescreendownhalf(); break; + case addr_fadescreenuphalf: fadescreenuphalf(); break; + case addr_fadescreendown: fadescreendown(); break; + case addr_fadescreendowns: fadescreendowns(); break; + case addr_clearstartpal: clearstartpal(); break; + case addr_showgun: showgun(); break; + case addr_rollendcredits2: rollendcredits2(); break; + case addr_rollem: rollem(); break; + case addr_fadecalculation: fadecalculation(); break; + case addr_greyscalesum: greyscalesum(); break; + case addr_showgroup: showgroup(); break; + case addr_paltostartpal: paltostartpal(); break; + case addr_endpaltostart: endpaltostart(); break; + case addr_startpaltoend: startpaltoend(); break; + case addr_paltoendpal: paltoendpal(); break; + case addr_allpalette: allpalette(); break; + case addr_dumpcurrent: dumpcurrent(); break; + case addr_fadedownmon: fadedownmon(); break; + case addr_fadeupmon: fadeupmon(); break; + case addr_fadeupmonfirst: fadeupmonfirst(); break; + case addr_fadeupyellows: fadeupyellows(); break; + case addr_initialmoncols: initialmoncols(); break; + case addr_titles: titles(); break; + case addr_endgame: endgame(); break; + case addr_monkspeaking: monkspeaking(); break; + case addr_showmonk: showmonk(); break; + case addr_gettingshot: gettingshot(); break; + case addr_credits: credits(); break; + case addr_biblequote: biblequote(); break; + case addr_hangone: hangone(); break; + case addr_intro: intro(); break; + case addr_runintroseq: runintroseq(); break; + case addr_runendseq: runendseq(); break; + case addr_loadintroroom: loadintroroom(); break; + case addr_mode640x480: mode640x480(); break; + case addr_set16colpalette: set16colpalette(); break; + case addr_realcredits: realcredits(); break; + case addr_waitframes: waitframes(); break; + case addr_monprint: monprint(); break; + case addr_fillryan: fillryan(); break; + case addr_fillopen: fillopen(); break; + case addr_findallryan: findallryan(); break; + case addr_findallopen: findallopen(); break; + case addr_obtoinv: obtoinv(); break; + case addr_isitworn: isitworn(); break; + case addr_makeworn: makeworn(); break; + case addr_examineob: examineob(); break; + case addr_makemainscreen: makemainscreen(); break; + case addr_getbackfromob: getbackfromob(); break; + case addr_incryanpage: incryanpage(); break; + case addr_openinv: openinv(); break; + case addr_showryanpage: showryanpage(); break; + case addr_openob: openob(); break; + case addr_obicons: obicons(); break; + case addr_examicon: examicon(); break; + case addr_obpicture: obpicture(); break; + case addr_describeob: describeob(); break; + case addr_additionaltext: additionaltext(); break; + case addr_obsthatdothings: obsthatdothings(); break; + case addr_getobtextstart: getobtextstart(); break; + case addr_searchforsame: searchforsame(); break; + case addr_findnextcolon: findnextcolon(); break; + case addr_inventory: inventory(); break; + case addr_setpickup: setpickup(); break; + case addr_examinventory: examinventory(); break; + case addr_reexfrominv: reexfrominv(); break; + case addr_reexfromopen: reexfromopen(); break; + case addr_swapwithinv: swapwithinv(); break; + case addr_swapwithopen: swapwithopen(); break; + case addr_intoinv: intoinv(); break; + case addr_outofinv: outofinv(); break; + case addr_getfreead: getfreead(); break; + case addr_getexad: getexad(); break; + case addr_geteitherad: geteitherad(); break; + case addr_getanyad: getanyad(); break; + case addr_getanyaddir: getanyaddir(); break; + case addr_getopenedsize: getopenedsize(); break; + case addr_getsetad: getsetad(); break; + case addr_findinvpos: findinvpos(); break; + case addr_findopenpos: findopenpos(); break; + case addr_dropobject: dropobject(); break; + case addr_droperror: droperror(); break; + case addr_cantdrop: cantdrop(); break; + case addr_wornerror: wornerror(); break; + case addr_removeobfrominv: removeobfrominv(); break; + case addr_selectopenob: selectopenob(); break; + case addr_useopened: useopened(); break; + case addr_errormessage1: errormessage1(); break; + case addr_errormessage2: errormessage2(); break; + case addr_errormessage3: errormessage3(); break; + case addr_checkobjectsize: checkobjectsize(); break; + case addr_outofopen: outofopen(); break; + case addr_transfertoex: transfertoex(); break; + case addr_pickupconts: pickupconts(); break; + case addr_transfercontoex: transfercontoex(); break; + case addr_transfertext: transfertext(); break; + case addr_getexpos: getexpos(); break; + case addr_purgealocation: purgealocation(); break; + case addr_emergencypurge: emergencypurge(); break; + case addr_purgeanitem: purgeanitem(); break; + case addr_deleteexobject: deleteexobject(); break; + case addr_deleteexframe: deleteexframe(); break; + case addr_deleteextext: deleteextext(); break; + case addr_blockget: blockget(); break; + case addr_drawfloor: drawfloor(); break; + case addr_drawflags: drawflags(); break; + case addr_showallex: showallex(); break; + case addr_autolook: autolook(); break; + case addr_look: look(); break; + case addr_dolook: dolook(); break; + case addr_redrawmainscrn: redrawmainscrn(); break; + case addr_getback1: getback1(); break; + case addr_talk: talk(); break; + case addr_convicons: convicons(); break; + case addr_getpersframe: getpersframe(); break; + case addr_starttalk: starttalk(); break; + case addr_getpersontext: getpersontext(); break; + case addr_moretalk: moretalk(); break; + case addr_dosometalk: dosometalk(); break; + case addr_hangonpq: hangonpq(); break; + case addr_redes: redes(); break; + case addr_newplace: newplace(); break; + case addr_selectlocation: selectlocation(); break; + case addr_showcity: showcity(); break; + case addr_lookatplace: lookatplace(); break; + case addr_getundercentre: getundercentre(); break; + case addr_putundercentre: putundercentre(); break; + case addr_locationpic: locationpic(); break; + case addr_getdestinfo: getdestinfo(); break; + case addr_showarrows: showarrows(); break; + case addr_nextdest: nextdest(); break; + case addr_lastdest: lastdest(); break; + case addr_destselect: destselect(); break; + case addr_getlocation: getlocation(); break; + case addr_setlocation: setlocation(); break; + case addr_resetlocation: resetlocation(); break; + case addr_readdesticon: readdesticon(); break; + case addr_readcitypic: readcitypic(); break; + case addr_usemon: usemon(); break; + case addr_printoutermon: printoutermon(); break; + case addr_loadpersonal: loadpersonal(); break; + case addr_loadnews: loadnews(); break; + case addr_loadcart: loadcart(); break; + case addr_lookininterface: lookininterface(); break; + case addr_turnonpower: turnonpower(); break; + case addr_randomaccess: randomaccess(); break; + case addr_powerlighton: powerlighton(); break; + case addr_powerlightoff: powerlightoff(); break; + case addr_accesslighton: accesslighton(); break; + case addr_accesslightoff: accesslightoff(); break; + case addr_locklighton: locklighton(); break; + case addr_locklightoff: locklightoff(); break; + case addr_input: input(); break; + case addr_makecaps: makecaps(); break; + case addr_delchar: delchar(); break; + case addr_execcommand: execcommand(); break; + case addr_neterror: neterror(); break; + case addr_dircom: dircom(); break; + case addr_searchforfiles: searchforfiles(); break; + case addr_signon: signon(); break; + case addr_showkeys: showkeys(); break; + case addr_read: read(); break; + case addr_dirfile: dirfile(); break; + case addr_getkeyandlogo: getkeyandlogo(); break; + case addr_searchforstring: searchforstring(); break; + case addr_parser: parser(); break; + case addr_scrollmonitor: scrollmonitor(); break; + case addr_monitorlogo: monitorlogo(); break; + case addr_printlogo: printlogo(); break; + case addr_showcurrentfile: showcurrentfile(); break; + case addr_monmessage: monmessage(); break; + case addr_processtrigger: processtrigger(); break; + case addr_triggermessage: triggermessage(); break; + case addr_printcurs: printcurs(); break; + case addr_delcurs: delcurs(); break; + case addr_useobject: useobject(); break; + case addr_useroutine: useroutine(); break; + case addr_wheelsound: wheelsound(); break; + case addr_runtap: runtap(); break; + case addr_playguitar: playguitar(); break; + case addr_hotelcontrol: hotelcontrol(); break; + case addr_hotelbell: hotelbell(); break; + case addr_opentomb: opentomb(); break; + case addr_usetrainer: usetrainer(); break; + case addr_nothelderror: nothelderror(); break; + case addr_usepipe: usepipe(); break; + case addr_usefullcart: usefullcart(); break; + case addr_useplinth: useplinth(); break; + case addr_chewy: chewy(); break; + case addr_useladder: useladder(); break; + case addr_useladderb: useladderb(); break; + case addr_slabdoora: slabdoora(); break; + case addr_slabdoorb: slabdoorb(); break; + case addr_slabdoord: slabdoord(); break; + case addr_slabdoorc: slabdoorc(); break; + case addr_slabdoore: slabdoore(); break; + case addr_slabdoorf: slabdoorf(); break; + case addr_useslab: useslab(); break; + case addr_usecart: usecart(); break; + case addr_useclearbox: useclearbox(); break; + case addr_usecoveredbox: usecoveredbox(); break; + case addr_userailing: userailing(); break; + case addr_useopenbox: useopenbox(); break; + case addr_wearwatch: wearwatch(); break; + case addr_wearshades: wearshades(); break; + case addr_sitdowninbar: sitdowninbar(); break; + case addr_usechurchhole: usechurchhole(); break; + case addr_usehole: usehole(); break; + case addr_usealtar: usealtar(); break; + case addr_opentvdoor: opentvdoor(); break; + case addr_usedryer: usedryer(); break; + case addr_openlouis: openlouis(); break; + case addr_nextcolon: nextcolon(); break; + case addr_openyourneighbour: openyourneighbour(); break; + case addr_usewindow: usewindow(); break; + case addr_usebalcony: usebalcony(); break; + case addr_openryan: openryan(); break; + case addr_openpoolboss: openpoolboss(); break; + case addr_openeden: openeden(); break; + case addr_opensarters: opensarters(); break; + case addr_isitright: isitright(); break; + case addr_drawitall: drawitall(); break; + case addr_openhoteldoor: openhoteldoor(); break; + case addr_openhoteldoor2: openhoteldoor2(); break; + case addr_grafittidoor: grafittidoor(); break; + case addr_trapdoor: trapdoor(); break; + case addr_callhotellift: callhotellift(); break; + case addr_calledenslift: calledenslift(); break; + case addr_calledensdlift: calledensdlift(); break; + case addr_usepoolreader: usepoolreader(); break; + case addr_uselighter: uselighter(); break; + case addr_showseconduse: showseconduse(); break; + case addr_usecardreader1: usecardreader1(); break; + case addr_usecardreader2: usecardreader2(); break; + case addr_usecardreader3: usecardreader3(); break; + case addr_usecashcard: usecashcard(); break; + case addr_lookatcard: lookatcard(); break; + case addr_moneypoke: moneypoke(); break; + case addr_usecontrol: usecontrol(); break; + case addr_usehatch: usehatch(); break; + case addr_usewire: usewire(); break; + case addr_usehandle: usehandle(); break; + case addr_useelevator1: useelevator1(); break; + case addr_showfirstuse: showfirstuse(); break; + case addr_useelevator3: useelevator3(); break; + case addr_useelevator4: useelevator4(); break; + case addr_useelevator2: useelevator2(); break; + case addr_useelevator5: useelevator5(); break; + case addr_usekey: usekey(); break; + case addr_usestereo: usestereo(); break; + case addr_usecooker: usecooker(); break; + case addr_useaxe: useaxe(); break; + case addr_useelvdoor: useelvdoor(); break; + case addr_withwhat: withwhat(); break; + case addr_selectob: selectob(); break; + case addr_compare: compare(); break; + case addr_findsetobject: findsetobject(); break; + case addr_findexobject: findexobject(); break; + case addr_isryanholding: isryanholding(); break; + case addr_checkinside: checkinside(); break; + case addr_usetext: usetext(); break; + case addr_putbackobstuff: putbackobstuff(); break; + case addr_showpuztext: showpuztext(); break; + case addr_findpuztext: findpuztext(); break; + case addr_issetobonmap: issetobonmap(); break; + case addr_placefreeobject: placefreeobject(); break; + case addr_removefreeobject: removefreeobject(); break; + case addr_switchryanon: switchryanon(); break; + case addr_switchryanoff: switchryanoff(); break; + case addr_autoappear: autoappear(); break; + case addr_setuptimeduse: setuptimeduse(); break; + case addr_edenscdplayer: edenscdplayer(); break; + case addr_usewall: usewall(); break; + case addr_usechurchgate: usechurchgate(); break; + case addr_usegun: usegun(); break; + case addr_useshield: useshield(); break; + case addr_usebuttona: usebuttona(); break; + case addr_useplate: useplate(); break; + case addr_usewinch: usewinch(); break; + case addr_entercode: entercode(); break; + case addr_loadkeypad: loadkeypad(); break; + case addr_quitkey: quitkey(); break; + case addr_addtopresslist: addtopresslist(); break; + case addr_buttonone: buttonone(); break; + case addr_buttontwo: buttontwo(); break; + case addr_buttonthree: buttonthree(); break; + case addr_buttonfour: buttonfour(); break; + case addr_buttonfive: buttonfive(); break; + case addr_buttonsix: buttonsix(); break; + case addr_buttonseven: buttonseven(); break; + case addr_buttoneight: buttoneight(); break; + case addr_buttonnine: buttonnine(); break; + case addr_buttonnought: buttonnought(); break; + case addr_buttonenter: buttonenter(); break; + case addr_buttonpress: buttonpress(); break; + case addr_showouterpad: showouterpad(); break; + case addr_showkeypad: showkeypad(); break; + case addr_singlekey: singlekey(); break; + case addr_dumpkeypad: dumpkeypad(); break; + case addr_usemenu: usemenu(); break; + case addr_dumpmenu: dumpmenu(); break; + case addr_getundermenu: getundermenu(); break; + case addr_putundermenu: putundermenu(); break; + case addr_showoutermenu: showoutermenu(); break; + case addr_showmenu: showmenu(); break; + case addr_loadmenu: loadmenu(); break; + case addr_viewfolder: viewfolder(); break; + case addr_nextfolder: nextfolder(); break; + case addr_folderhints: folderhints(); break; + case addr_lastfolder: lastfolder(); break; + case addr_loadfolder: loadfolder(); break; + case addr_showfolder: showfolder(); break; + case addr_folderexit: folderexit(); break; + case addr_showleftpage: showleftpage(); break; + case addr_showrightpage: showrightpage(); break; + case addr_entersymbol: entersymbol(); break; + case addr_quitsymbol: quitsymbol(); break; + case addr_settopleft: settopleft(); break; + case addr_settopright: settopright(); break; + case addr_setbotleft: setbotleft(); break; + case addr_setbotright: setbotright(); break; + case addr_dumpsymbol: dumpsymbol(); break; + case addr_showsymbol: showsymbol(); break; + case addr_nextsymbol: nextsymbol(); break; + case addr_updatesymboltop: updatesymboltop(); break; + case addr_updatesymbolbot: updatesymbolbot(); break; + case addr_dumpsymbox: dumpsymbox(); break; + case addr_usediary: usediary(); break; + case addr_showdiary: showdiary(); break; + case addr_showdiarykeys: showdiarykeys(); break; + case addr_dumpdiarykeys: dumpdiarykeys(); break; + case addr_diarykeyp: diarykeyp(); break; + case addr_diarykeyn: diarykeyn(); break; + case addr_showdiarypage: showdiarypage(); break; + case addr_findtext1: findtext1(); break; + case addr_zoomonoff: zoomonoff(); break; + case addr_saveload: saveload(); break; + case addr_dosaveload: dosaveload(); break; + case addr_getbackfromops: getbackfromops(); break; + case addr_showmainops: showmainops(); break; + case addr_showdiscops: showdiscops(); break; + case addr_loadsavebox: loadsavebox(); break; + case addr_loadgame: loadgame(); break; + case addr_getbacktoops: getbacktoops(); break; + case addr_discops: discops(); break; + case addr_savegame: savegame(); break; + case addr_actualsave: actualsave(); break; + case addr_actualload: actualload(); break; + case addr_selectslot2: selectslot2(); break; + case addr_checkinput: checkinput(); break; + case addr_getnamepos: getnamepos(); break; + case addr_showopbox: showopbox(); break; + case addr_showloadops: showloadops(); break; + case addr_showsaveops: showsaveops(); break; + case addr_selectslot: selectslot(); break; + case addr_showslots: showslots(); break; + case addr_shownames: shownames(); break; + case addr_dosreturn: dosreturn(); break; + case addr_error: error(); break; + case addr_namestoold: namestoold(); break; + case addr_oldtonames: oldtonames(); break; + case addr_savefilewrite: savefilewrite(); break; + case addr_savefileread: savefileread(); break; + case addr_saveposition: saveposition(); break; + case addr_loadposition: loadposition(); break; + case addr_loadseg: loadseg(); break; + case addr_makeheader: makeheader(); break; + case addr_storeit: storeit(); break; + case addr_saveseg: saveseg(); break; + case addr_scanfornames: scanfornames(); break; + case addr_decide: decide(); break; + case addr_showdecisions: showdecisions(); break; + case addr_newgame: newgame(); break; + case addr_loadold: loadold(); break; + case addr_loadspeech: loadspeech(); break; + case addr_createname: createname(); break; + case addr_loadsample: loadsample(); break; + case addr_loadsecondsample: loadsecondsample(); break; + case addr_soundstartup: soundstartup(); break; + case addr_trysoundalloc: trysoundalloc(); break; + case addr_setsoundoff: setsoundoff(); break; + case addr_checksoundint: checksoundint(); break; + case addr_enablesoundint: enablesoundint(); break; + case addr_disablesoundint: disablesoundint(); break; + case addr_interupttest: interupttest(); break; + case addr_soundend: soundend(); break; + case addr_out22c: out22c(); break; + case addr_playchannel0: playchannel0(); break; + case addr_playchannel1: playchannel1(); break; + case addr_volumeadjust: volumeadjust(); break; + case addr_channel0only: channel0only(); break; + case addr_channel1only: channel1only(); break; + case addr_bothchannels: bothchannels(); break; + case addr_saveems: saveems(); break; + case addr_restoreems: restoreems(); break; + case addr_dmaend: dmaend(); break; + case addr_startdmablock: startdmablock(); break; + case addr_setuppit: setuppit(); break; + case addr_getridofpit: getridofpit(); break; + case addr_pitinterupt: pitinterupt(); break; + case addr_dreamweb: dreamweb(); break; + case addr_entrytexts: entrytexts(); break; + case addr_entryanims: entryanims(); break; + case addr_initialinv: initialinv(); break; + case addr_pickupob: pickupob(); break; + case addr_setupemm: setupemm(); break; + case addr_removeemm: removeemm(); break; + case addr_checkforemm: checkforemm(); break; + case addr_checkbasemem: checkbasemem(); break; + case addr_allocatebuffers: allocatebuffers(); break; + case addr_clearbuffers: clearbuffers(); break; + case addr_clearchanges: clearchanges(); break; + case addr_clearbeforeload: clearbeforeload(); break; + case addr_clearreels: clearreels(); break; + case addr_clearrest: clearrest(); break; + case addr_deallocatemem: deallocatemem(); break; + case addr_allocatemem: allocatemem(); break; + case addr_startup: startup(); break; + case addr_startup1: startup1(); break; + case addr_screenupdate: screenupdate(); break; + case addr_watchreel: watchreel(); break; + case addr_checkforshake: checkforshake(); break; + case addr_watchcount: watchcount(); break; + case addr_showtime: showtime(); break; + case addr_dumpwatch: dumpwatch(); break; + case addr_showbyte: showbyte(); break; + case addr_onedigit: onedigit(); break; + case addr_twodigitnum: twodigitnum(); break; + case addr_showword: showword(); break; + case addr_convnum: convnum(); break; + case addr_mainscreen: mainscreen(); break; + case addr_madmanrun: madmanrun(); break; + case addr_checkcoords: checkcoords(); break; + case addr_identifyob: identifyob(); break; + case addr_checkifset: checkifset(); break; + case addr_checkifex: checkifex(); break; + case addr_isitdescribed: isitdescribed(); break; + case addr_findpathofpoint: findpathofpoint(); break; + case addr_findfirstpath: findfirstpath(); break; + case addr_turnpathon: turnpathon(); break; + case addr_turnpathoff: turnpathoff(); break; + case addr_turnanypathon: turnanypathon(); break; + case addr_turnanypathoff: turnanypathoff(); break; + case addr_checkifpathison: checkifpathison(); break; + case addr_afternewroom: afternewroom(); break; + case addr_atmospheres: atmospheres(); break; + case addr_walkintoroom: walkintoroom(); break; + case addr_afterintroroom: afterintroroom(); break; + case addr_obname: obname(); break; + case addr_examineobtext: examineobtext(); break; + case addr_printmessage: printmessage(); break; + case addr_printmessage2: printmessage2(); break; + case addr_getflagunderp: getflagunderp(); break; + case addr_setwalk: setwalk(); break; + case addr_bresenhams: bresenhams(); break; + case addr_workoutframes: workoutframes(); break; + case addr_showicon: showicon(); break; + case addr_middlepanel: middlepanel(); break; + case addr_showman: showman(); break; + case addr_roomname: roomname(); break; + case addr_usecharset1: usecharset1(); break; + case addr_usetempcharset: usetempcharset(); break; + case addr_showexit: showexit(); break; + case addr_panelicons1: panelicons1(); break; + case addr_showwatch: showwatch(); break; + case addr_gettime: gettime(); break; + case addr_zoomicon: zoomicon(); break; + case addr_showblink: showblink(); break; + case addr_dumpblink: dumpblink(); break; + case addr_worktoscreenm: worktoscreenm(); break; + case addr_blank: blank(); break; + case addr_allpointer: allpointer(); break; + case addr_hangonp: hangonp(); break; + case addr_hangonw: hangonw(); break; + case addr_hangoncurs: hangoncurs(); break; + case addr_getunderzoom: getunderzoom(); break; + case addr_dumpzoom: dumpzoom(); break; + case addr_putunderzoom: putunderzoom(); break; + case addr_showpointer: showpointer(); break; + case addr_delpointer: delpointer(); break; + case addr_dumppointer: dumppointer(); break; + case addr_undertextline: undertextline(); break; + case addr_animpointer: animpointer(); break; + case addr_setmouse: setmouse(); break; + case addr_readmouse: readmouse(); break; + case addr_mousecall: mousecall(); break; + case addr_readmouse1: readmouse1(); break; + case addr_readmouse2: readmouse2(); break; + case addr_readmouse3: readmouse3(); break; + case addr_readmouse4: readmouse4(); break; + case addr_readkey: readkey(); break; + case addr_randomnum1: randomnum1(); break; + case addr_randomnum2: randomnum2(); break; + case addr_hangon: hangon(); break; + case addr_loadtraveltext: loadtraveltext(); break; + case addr_loadintotemp: loadintotemp(); break; + case addr_loadintotemp2: loadintotemp2(); break; + case addr_loadintotemp3: loadintotemp3(); break; + case addr_loadtempcharset: loadtempcharset(); break; + case addr_standardload: standardload(); break; + case addr_loadtemptext: loadtemptext(); break; + case addr_loadroom: loadroom(); break; + case addr_loadroomssample: loadroomssample(); break; + case addr_getridofreels: getridofreels(); break; + case addr_getridofall: getridofall(); break; + case addr_restorereels: restorereels(); break; + case addr_restoreall: restoreall(); break; + case addr_sortoutmap: sortoutmap(); break; + case addr_disablepath: disablepath(); break; + case addr_findroominloc: findroominloc(); break; + case addr_dontloadseg: dontloadseg(); break; + case addr_allocateload: allocateload(); break; + case addr_getridoftemp: getridoftemp(); break; + case addr_getridoftemptext: getridoftemptext(); break; + case addr_getridoftemp2: getridoftemp2(); break; + case addr_getridoftemp3: getridoftemp3(); break; + case addr_getridoftempcharset: getridoftempcharset(); break; + case addr_getridoftempsp: getridoftempsp(); break; + case addr_readsetdata: readsetdata(); break; + case addr_createfile: createfile(); break; + case addr_openfile: openfile(); break; + case addr_openfilefromc: openfilefromc(); break; + case addr_openfilenocheck: openfilenocheck(); break; + case addr_openforsave: openforsave(); break; + case addr_closefile: closefile(); break; + case addr_readfromfile: readfromfile(); break; + case addr_setkeyboardint: setkeyboardint(); break; + case addr_resetkeyboard: resetkeyboard(); break; + case addr_keyboardread: keyboardread(); break; + case addr_walkandexamine: walkandexamine(); break; + case addr_doload: doload(); break; + case addr_generalerror: generalerror(); break; default: ::error("invalid call to %04x dispatched", (uint16)ax); } } diff --git a/engines/dreamweb/dreamgen.h b/engines/dreamweb/dreamgen.h index 71c466da24..7ed079c00e 100644 --- a/engines/dreamweb/dreamgen.h +++ b/engines/dreamweb/dreamgen.h @@ -3,594 +3,1306 @@ /* PLEASE DO NOT MODIFY THIS FILE. ALL CHANGES WILL BE LOST! LOOK FOR README FOR DETAILS */ +/* 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/runtime.h" namespace DreamGen { - +#include "structs.h" class DreamGenContext : public Context { public: void __start(); void __dispatch_call(uint16 addr); +#include "stubs.h" // Allow hand-reversed functions to have a signature different than void f() - const static uint16 kStartvars = 0; - const static uint16 kProgresspoints = 1; - const static uint16 kWatchon = 2; - const static uint16 kShadeson = 3; - const static uint16 kSecondcount = 4; - const static uint16 kMinutecount = 5; - const static uint16 kHourcount = 6; - const static uint16 kZoomon = 7; - const static uint16 kLocation = 8; - const static uint16 kExpos = 9; - const static uint16 kExframepos = 10; - const static uint16 kExtextpos = 12; - const static uint16 kCard1money = 14; - const static uint16 kListpos = 16; - const static uint16 kRyanpage = 18; - const static uint16 kWatchingtime = 19; - const static uint16 kReeltowatch = 21; - const static uint16 kEndwatchreel = 23; - const static uint16 kSpeedcount = 25; - const static uint16 kWatchspeed = 26; - const static uint16 kReeltohold = 27; - const static uint16 kEndofholdreel = 29; - const static uint16 kWatchmode = 31; - const static uint16 kDestafterhold = 32; - const static uint16 kNewsitem = 33; - const static uint16 kLiftflag = 34; - const static uint16 kLiftpath = 35; - const static uint16 kLockstatus = 36; - const static uint16 kDoorpath = 37; - const static uint16 kCounttoopen = 38; - const static uint16 kCounttoclose = 39; - const static uint16 kRockstardead = 40; - const static uint16 kGeneraldead = 41; - const static uint16 kSartaindead = 42; - const static uint16 kAidedead = 43; - const static uint16 kBeenmugged = 44; - const static uint16 kGunpassflag = 45; - const static uint16 kCanmovealtar = 46; - const static uint16 kTalkedtoattendant = 47; - const static uint16 kTalkedtosparky = 48; - const static uint16 kTalkedtoboss = 49; - const static uint16 kTalkedtorecep = 50; - const static uint16 kCardpassflag = 51; - const static uint16 kMadmanflag = 52; - const static uint16 kKeeperflag = 53; - const static uint16 kLasttrigger = 54; - const static uint16 kMandead = 55; - const static uint16 kSeed = 56; - const static uint16 kNeedtotravel = 59; - const static uint16 kThroughdoor = 60; - const static uint16 kNewobs = 61; - const static uint16 kRyanon = 62; - const static uint16 kCombatcount = 63; - const static uint16 kLastweapon = 64; - const static uint16 kDreamnumber = 65; - const static uint16 kRoomafterdream = 66; - const static uint16 kShakecounter = 67; - const static uint16 kSpeechcount = 68; - const static uint16 kCharshift = 69; - const static uint16 kKerning = 71; - const static uint16 kBrightness = 72; - const static uint16 kRoomloaded = 73; - const static uint16 kDidzoom = 74; - const static uint16 kLinespacing = 75; - const static uint16 kTextaddressx = 77; - const static uint16 kTextaddressy = 79; - const static uint16 kTextlen = 81; - const static uint16 kLastxpos = 82; - const static uint16 kIcontop = 84; - const static uint16 kIconleft = 86; - const static uint16 kItemframe = 88; - const static uint16 kItemtotran = 89; - const static uint16 kRoomad = 90; - const static uint16 kOldsubject = 92; - const static uint16 kWithobject = 94; - const static uint16 kWithtype = 95; - const static uint16 kLookcounter = 96; - const static uint16 kCommand = 98; - const static uint16 kCommandtype = 99; - const static uint16 kOldcommandtype = 100; - const static uint16 kObjecttype = 101; - const static uint16 kGetback = 102; - const static uint16 kInvopen = 103; - const static uint16 kMainmode = 104; - const static uint16 kPickup = 105; - const static uint16 kLastinvpos = 106; - const static uint16 kExamagain = 107; - const static uint16 kNewtextline = 108; - const static uint16 kOpenedob = 109; - const static uint16 kOpenedtype = 110; - const static uint16 kOldmapadx = 111; - const static uint16 kOldmapady = 113; - const static uint16 kMapadx = 115; - const static uint16 kMapady = 117; - const static uint16 kMapoffsetx = 119; - const static uint16 kMapoffsety = 121; - const static uint16 kMapxstart = 123; - const static uint16 kMapystart = 125; - const static uint16 kMapxsize = 127; - const static uint16 kMapysize = 128; - const static uint16 kHavedoneobs = 129; - const static uint16 kManisoffscreen = 130; - const static uint16 kRainspace = 131; - const static uint16 kFacing = 132; - const static uint16 kLeavedirection = 133; - const static uint16 kTurntoface = 134; - const static uint16 kTurndirection = 135; - const static uint16 kMaintimer = 136; - const static uint16 kIntrocount = 138; - const static uint16 kArrowad = 139; - const static uint16 kCurrentkey = 141; - const static uint16 kOldkey = 142; - const static uint16 kUseddirection = 143; - const static uint16 kCurrentkey2 = 144; - const static uint16 kTimercount = 145; - const static uint16 kOldtimercount = 146; - const static uint16 kMapx = 147; - const static uint16 kMapy = 148; - const static uint16 kNewscreen = 149; - const static uint16 kRyanx = 150; - const static uint16 kRyany = 151; - const static uint16 kLastflag = 152; - const static uint16 kLastflagex = 153; - const static uint16 kFlagx = 154; - const static uint16 kFlagy = 155; - const static uint16 kCurrentex = 156; - const static uint16 kCurrentfree = 157; - const static uint16 kCurrentframe = 158; - const static uint16 kFramesad = 160; - const static uint16 kDataad = 162; - const static uint16 kFrsegment = 164; - const static uint16 kObjectx = 166; - const static uint16 kObjecty = 168; - const static uint16 kOffsetx = 170; - const static uint16 kOffsety = 172; - const static uint16 kSavesize = 174; - const static uint16 kSavesource = 176; - const static uint16 kSavex = 178; - const static uint16 kSavey = 179; - const static uint16 kCurrentob = 180; - const static uint16 kPriority = 181; - const static uint16 kDestpos = 182; - const static uint16 kReallocation = 183; - const static uint16 kRoomnum = 184; - const static uint16 kNowinnewroom = 185; - const static uint16 kResetmanxy = 186; - const static uint16 kNewlocation = 187; - const static uint16 kAutolocation = 188; - const static uint16 kMustload = 189; - const static uint16 kAnswered = 190; - const static uint16 kSaidno = 191; - const static uint16 kDoorcheck1 = 192; - const static uint16 kDoorcheck2 = 193; - const static uint16 kDoorcheck3 = 194; - const static uint16 kDoorcheck4 = 195; - const static uint16 kMousex = 196; - const static uint16 kMousey = 198; - const static uint16 kMousebutton = 200; - const static uint16 kMousebutton1 = 202; - const static uint16 kMousebutton2 = 204; - const static uint16 kMousebutton3 = 206; - const static uint16 kMousebutton4 = 208; - const static uint16 kOldbutton = 210; - const static uint16 kOldx = 212; - const static uint16 kOldy = 214; - const static uint16 kLastbutton = 216; - const static uint16 kOldpointerx = 218; - const static uint16 kOldpointery = 220; - const static uint16 kDelherex = 222; - const static uint16 kDelherey = 224; - const static uint16 kPointerxs = 226; - const static uint16 kPointerys = 227; - const static uint16 kDelxs = 228; - const static uint16 kDelys = 229; - const static uint16 kPointerframe = 230; - const static uint16 kPointerpower = 231; - const static uint16 kAuxpointerframe = 232; - const static uint16 kPointermode = 233; - const static uint16 kPointerspeed = 234; - const static uint16 kPointercount = 235; - const static uint16 kInmaparea = 236; - const static uint16 kReelpointer = 237; - const static uint16 kSlotdata = 239; - const static uint16 kThisslot = 240; - const static uint16 kSlotflags = 241; - const static uint16 kTakeoff = 242; - const static uint16 kTalkmode = 244; - const static uint16 kTalkpos = 245; - const static uint16 kCharacter = 246; - const static uint16 kPersondata = 247; - const static uint16 kTalknum = 249; - const static uint16 kNumberinroom = 250; - const static uint16 kCurrentcel = 251; - const static uint16 kOldselection = 252; - const static uint16 kStopwalking = 253; - const static uint16 kMouseon = 254; - const static uint16 kPlayed = 255; - const static uint16 kTimer1 = 257; - const static uint16 kTimer2 = 258; - const static uint16 kTimer3 = 259; - const static uint16 kWholetimer = 260; - const static uint16 kTimer1to = 262; - const static uint16 kTimer2to = 263; - const static uint16 kTimer3to = 264; - const static uint16 kWatchdump = 265; - const static uint16 kCurrentset = 266; - const static uint16 kLogonum = 268; - const static uint16 kOldlogonum = 269; - const static uint16 kNewlogonum = 270; - const static uint16 kNetseg = 271; - const static uint16 kNetpoint = 273; - const static uint16 kKeynum = 275; - const static uint16 kCursorstate = 276; - const static uint16 kPressed = 277; - const static uint16 kPresspointer = 278; - const static uint16 kGraphicpress = 280; - const static uint16 kPresscount = 281; - const static uint16 kKeypadax = 282; - const static uint16 kKeypadcx = 284; - const static uint16 kLightcount = 286; - const static uint16 kFolderpage = 287; - const static uint16 kDiarypage = 288; - const static uint16 kMenucount = 289; - const static uint16 kSymboltopx = 290; - const static uint16 kSymboltopnum = 291; - const static uint16 kSymboltopdir = 292; - const static uint16 kSymbolbotx = 293; - const static uint16 kSymbolbotnum = 294; - const static uint16 kSymbolbotdir = 295; - const static uint16 kSymboltolight = 296; - const static uint16 kSymbol1 = 297; - const static uint16 kSymbol2 = 298; - const static uint16 kSymbol3 = 299; - const static uint16 kSymbolnum = 300; - const static uint16 kDumpx = 301; - const static uint16 kDumpy = 303; - const static uint16 kWalkandexam = 305; - const static uint16 kWalkexamtype = 306; - const static uint16 kWalkexamnum = 307; - const static uint16 kCursloc = 308; - const static uint16 kCurslocx = 310; - const static uint16 kCurslocy = 312; - const static uint16 kCurpos = 314; - const static uint16 kMonadx = 316; - const static uint16 kMonady = 318; - const static uint16 kGotfrom = 320; - const static uint16 kMonsource = 322; - const static uint16 kNumtodo = 324; - const static uint16 kTimecount = 326; - const static uint16 kCounttotimed = 328; - const static uint16 kTimedseg = 330; - const static uint16 kTimedoffset = 332; - const static uint16 kTimedy = 334; - const static uint16 kTimedx = 335; - const static uint16 kNeedtodumptimed = 336; - const static uint16 kHandle = 337; - const static uint16 kLoadingorsave = 339; - const static uint16 kCurrentslot = 340; - const static uint16 kCursorpos = 341; - const static uint16 kColourpos = 342; - const static uint16 kFadedirection = 343; - const static uint16 kNumtofade = 344; - const static uint16 kFadecount = 345; - const static uint16 kAddtogreen = 346; - const static uint16 kAddtored = 347; - const static uint16 kAddtoblue = 348; - const static uint16 kLastsoundreel = 349; - const static uint16 kSoundbuffer = 351; - const static uint16 kSoundbufferad = 353; - const static uint16 kSoundbufferpage = 355; - const static uint16 kSoundtimes = 356; - const static uint16 kNeedsoundbuff = 357; - const static uint16 kOldint9seg = 358; - const static uint16 kOldint9add = 360; - const static uint16 kOldint8seg = 362; - const static uint16 kOldint8add = 364; - const static uint16 kOldsoundintseg = 366; - const static uint16 kOldsoundintadd = 368; - const static uint16 kSoundbaseadd = 370; - const static uint16 kDsp_status = 372; - const static uint16 kDsp_write = 374; - const static uint16 kDmaaddress = 376; - const static uint16 kSoundint = 377; - const static uint16 kSounddmachannel = 378; - const static uint16 kSampleplaying = 379; - const static uint16 kTestresult = 380; - const static uint16 kCurrentirq = 381; - const static uint16 kSpeechloaded = 382; - const static uint16 kSpeechlength = 383; - const static uint16 kVolume = 385; - const static uint16 kVolumeto = 386; - const static uint16 kVolumedirection = 387; - const static uint16 kVolumecount = 388; - const static uint16 kPlayblock = 389; - const static uint16 kWongame = 390; - const static uint16 kLasthardkey = 391; - const static uint16 kBufferin = 392; - const static uint16 kBufferout = 394; - const static uint16 kExtras = 396; - const static uint16 kWorkspace = 398; - const static uint16 kMapstore = 400; - const static uint16 kCharset1 = 402; - const static uint16 kTempcharset = 404; - const static uint16 kIcons1 = 406; - const static uint16 kIcons2 = 408; - const static uint16 kBuffers = 410; - const static uint16 kMainsprites = 412; - const static uint16 kBackdrop = 414; - const static uint16 kMapdata = 416; - const static uint16 kSounddata = 418; - const static uint16 kSounddata2 = 420; - const static uint16 kRecordspace = 422; - const static uint16 kFreedat = 424; - const static uint16 kSetdat = 426; - const static uint16 kReel1 = 428; - const static uint16 kReel2 = 430; - const static uint16 kReel3 = 432; - const static uint16 kRoomdesc = 434; - const static uint16 kFreedesc = 436; - const static uint16 kSetdesc = 438; - const static uint16 kBlockdesc = 440; - const static uint16 kSetframes = 442; - const static uint16 kFreeframes = 444; - const static uint16 kPeople = 446; - const static uint16 kReels = 448; - const static uint16 kCommandtext = 450; - const static uint16 kPuzzletext = 452; - const static uint16 kTraveltext = 454; - const static uint16 kTempgraphics = 456; - const static uint16 kTempgraphics2 = 458; - const static uint16 kTempgraphics3 = 460; - const static uint16 kTempsprites = 462; - const static uint16 kTextfile1 = 464; - const static uint16 kTextfile2 = 466; - const static uint16 kTextfile3 = 468; - const static uint16 kBlinkframe = 470; - const static uint16 kBlinkcount = 471; - const static uint16 kReasseschanges = 472; - const static uint16 kPointerspath = 473; - const static uint16 kManspath = 474; - const static uint16 kPointerfirstpath = 475; - const static uint16 kFinaldest = 476; - const static uint16 kDestination = 477; - const static uint16 kLinestartx = 478; - const static uint16 kLinestarty = 480; - const static uint16 kLineendx = 482; - const static uint16 kLineendy = 484; - const static uint16 kIncrement1 = 486; - const static uint16 kIncrement2 = 488; - const static uint16 kLineroutine = 490; - const static uint16 kLinepointer = 491; - const static uint16 kLinedirection = 492; - const static uint16 kLinelength = 493; - const static uint16 kLiftsoundcount = 494; - const static uint16 kEmmhandle = 495; - const static uint16 kEmmpageframe = 497; - const static uint16 kEmmhardwarepage = 499; - const static uint16 kCh0emmpage = 500; - const static uint16 kCh0offset = 502; - const static uint16 kCh0blockstocopy = 504; - const static uint16 kCh0playing = 506; - const static uint16 kCh0repeat = 507; - const static uint16 kCh0oldemmpage = 508; - const static uint16 kCh0oldoffset = 510; - const static uint16 kCh0oldblockstocopy = 512; - const static uint16 kCh1playing = 514; - const static uint16 kCh1emmpage = 515; - const static uint16 kCh1offset = 517; - const static uint16 kCh1blockstocopy = 519; - const static uint16 kCh1blocksplayed = 521; - const static uint16 kSoundbufferwrite = 523; - const static uint16 kSoundemmpage = 525; - const static uint16 kSpeechemmpage = 527; - const static uint16 kCurrentsample = 529; - const static uint16 kRoomssample = 530; - const static uint16 kGameerror = 531; - const static uint16 kHowmuchalloc = 532; - const static uint16 kReelroutines = 534; - const static uint16 kReelcalls = 991; - const static uint16 kRoombyroom = 1214; - const static uint16 kR0 = 1326; - const static uint16 kR1 = 1327; - const static uint16 kR2 = 1331; - const static uint16 kR6 = 1350; - const static uint16 kR8 = 1357; - const static uint16 kR9 = 1373; - const static uint16 kR10 = 1380; - const static uint16 kR11 = 1384; - const static uint16 kR12 = 1388; - const static uint16 kR13 = 1392; - const static uint16 kR14 = 1405; - const static uint16 kR20 = 1439; - const static uint16 kR22 = 1461; - const static uint16 kR23 = 1492; - const static uint16 kR25 = 1505; - const static uint16 kR26 = 1527; - const static uint16 kR27 = 1549; - const static uint16 kR28 = 1574; - const static uint16 kR29 = 1593; - const static uint16 kR45 = 1609; - const static uint16 kR46 = 1616; - const static uint16 kR47 = 1653; - const static uint16 kR52 = 1666; - const static uint16 kR53 = 1670; - const static uint16 kR55 = 1677; - const static uint16 kSpritename1 = 1819; - const static uint16 kSpritename3 = 1832; - const static uint16 kIdname = 1845; - const static uint16 kCharacterset1 = 1857; - const static uint16 kCharacterset2 = 1870; - const static uint16 kCharacterset3 = 1883; - const static uint16 kSamplename = 1896; - const static uint16 kBasicsample = 1909; - const static uint16 kIcongraphics0 = 1922; - const static uint16 kIcongraphics1 = 1935; - const static uint16 kExtragraphics1 = 1948; - const static uint16 kIcongraphics8 = 1961; - const static uint16 kMongraphicname = 1974; - const static uint16 kMongraphics2 = 1987; - const static uint16 kCityname = 2000; - const static uint16 kTravelgraphic1 = 2013; - const static uint16 kTravelgraphic2 = 2026; - const static uint16 kDiarygraphic = 2039; - const static uint16 kMonitorfile1 = 2052; - const static uint16 kMonitorfile2 = 2065; - const static uint16 kMonitorfile10 = 2078; - const static uint16 kMonitorfile11 = 2091; - const static uint16 kMonitorfile12 = 2104; - const static uint16 kMonitorfile13 = 2117; - const static uint16 kMonitorfile20 = 2130; - const static uint16 kMonitorfile21 = 2143; - const static uint16 kMonitorfile22 = 2156; - const static uint16 kMonitorfile23 = 2169; - const static uint16 kMonitorfile24 = 2182; - const static uint16 kFoldertext = 2195; - const static uint16 kDiarytext = 2208; - const static uint16 kPuzzletextname = 2221; - const static uint16 kTraveltextname = 2234; - const static uint16 kIntrotextname = 2247; - const static uint16 kEndtextname = 2260; - const static uint16 kCommandtextname = 2273; - const static uint16 kVolumetabname = 2286; - const static uint16 kFoldergraphic1 = 2299; - const static uint16 kFoldergraphic2 = 2312; - const static uint16 kFoldergraphic3 = 2325; - const static uint16 kSymbolgraphic = 2338; - const static uint16 kGungraphic = 2351; - const static uint16 kMonkface = 2364; - const static uint16 kTitle0graphics = 2377; - const static uint16 kTitle1graphics = 2390; - const static uint16 kTitle2graphics = 2403; - const static uint16 kTitle3graphics = 2416; - const static uint16 kTitle4graphics = 2429; - const static uint16 kTitle5graphics = 2442; - const static uint16 kTitle6graphics = 2455; - const static uint16 kTitle7graphics = 2468; - const static uint16 kPalettescreen = 2481; - const static uint16 kCurrentfile = 2970; - const static uint16 kDmaaddresses = 5118; - const static uint16 kFileheader = 6091; - const static uint16 kFiledata = 6141; - const static uint16 kExtradata = 6181; - const static uint16 kRoomdata = 6187; - const static uint16 kMadeuproomdat = 7979; - const static uint16 kRoomscango = 8011; - const static uint16 kRoompics = 8027; - const static uint16 kOplist = 8042; - const static uint16 kInputline = 8045; - const static uint16 kLinedata = 8173; - const static uint16 kPresslist = 8573; - const static uint16 kSavenames = 8579; - const static uint16 kSavefiles = 8698; - const static uint16 kRecname = 8789; - const static uint16 kQuitrequested = 8802; - const static uint16 kSubtitles = 8803; - const static uint16 kForeignrelease = 8804; - const static uint16 kStak = 8805; - const static uint16 kBlocktextdat = (0); - const static uint16 kPersonframes = (0); - const static uint16 kDebuglevel1 = (0); - const static uint16 kDebuglevel2 = (0); - const static uint16 kPlayback = (0); - const static uint16 kMap = (0); - const static uint16 kSettextdat = (0); - const static uint16 kSpanish = (0); - const static uint16 kFramedata = (0); - const static uint16 kRecording = (0); - const static uint16 kFlags = (0); - const static uint16 kGerman = (0); - const static uint16 kTextunder = (0); - const static uint16 kPathdata = (0); - const static uint16 kDemo = (0); - const static uint16 kExframedata = (0); - const static uint16 kIntextdat = (0); - const static uint16 kFreetextdat = (0); - const static uint16 kFrframedata = (0); - const static uint16 kSettext = (0+(130*2)); - const static uint16 kOpeninvlist = (0+(228*13)); - const static uint16 kRyaninvlist = (0+(228*13)+32); - const static uint16 kPointerback = (0+(228*13)+32+60); - const static uint16 kMapflags = (0+(228*13)+32+60+(32*32)); - const static uint16 kStartpal = (0+(228*13)+32+60+(32*32)+(11*10*3)); - const static uint16 kEndpal = (0+(228*13)+32+60+(32*32)+(11*10*3)+768); - const static uint16 kMaingamepal = (0+(228*13)+32+60+(32*32)+(11*10*3)+768+768); - const static uint16 kSpritetable = (0+(228*13)+32+60+(32*32)+(11*10*3)+768+768+768); - const static uint16 kSetlist = (0+(228*13)+32+60+(32*32)+(11*10*3)+768+768+768+(32*32)); - const static uint16 kFreelist = (0+(228*13)+32+60+(32*32)+(11*10*3)+768+768+768+(32*32)+(128*5)); - const static uint16 kExlist = (0+(228*13)+32+60+(32*32)+(11*10*3)+768+768+768+(32*32)+(128*5)+(80*5)); - const static uint16 kPeoplelist = (0+(228*13)+32+60+(32*32)+(11*10*3)+768+768+768+(32*32)+(128*5)+(80*5)+(100*5)); - const static uint16 kZoomspace = (0+(228*13)+32+60+(32*32)+(11*10*3)+768+768+768+(32*32)+(128*5)+(80*5)+(100*5)+(12*5)); - const static uint16 kPrintedlist = (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)); - const static uint16 kListofchanges = (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)); - const static uint16 kUndertimedtext = (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)); - const static uint16 kRainlist = (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)); - const static uint16 kInitialreelrouts = (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)+(6*64)); - const static uint16 kInitialvars = (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)+(6*64)+991-534); - const static uint16 kLengthofbuffer = (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)+(6*64)+991-534+68-0); - const static uint16 kReellist = (0+(36*144)); - const static uint16 kIntext = (0+(38*2)); - const static uint16 kLengthofmap = (0+(66*60)); - const static uint16 kFreetext = (0+(82*2)); - const static uint16 kBlocktext = (0+(98*2)); - const static uint16 kBlocks = (0+192); - const static uint16 kFrframes = (0+2080); - const static uint16 kExframes = (0+2080); - const static uint16 kFrames = (0+2080); - const static uint16 kExdata = (0+2080+30000); - const static uint16 kExtextdat = (0+2080+30000+(16*114)); - const static uint16 kExtext = (0+2080+30000+(16*114)+((114+2)*2)); - const static uint16 kLengthofextra = (0+2080+30000+(16*114)+((114+2)*2)+18000); - const static uint16 kPersontxtdat = (0+24); - const static uint16 kPersontext = (0+24+(1026*2)); - const static uint16 kInputport = (0x63); - const static uint16 kForeign = (1); - const static uint16 kCd = (1); - const static uint16 kNumexobjects = (114); - const static uint16 kUndertextsizey = (13); - const static uint16 kZoomy = (132); - const static uint16 kFreedatlen = (16*80); - const static uint16 kExtextlen = (18000); - const static uint16 kLenofmapstore = (22*8*20*8); - const static uint16 kUndertextsizex = (228); - const static uint16 kNumchanges = (250); - const static uint16 kUndertimedysize = (30); - const static uint16 kExframeslen = (30000); - const static uint16 kTablesize = (32); - const static uint16 kScreenwidth = (320); - const static uint16 kKeypadx = (36+112); - const static uint16 kItempicsize = (44); - const static uint16 kDiaryy = (48+12); - const static uint16 kOpsy = (52); - const static uint16 kSymboly = (56); - const static uint16 kInventy = (58); - const static uint16 kMenuy = (60); - const static uint16 kOpsx = (60); - const static uint16 kMaplength = (60); - const static uint16 kHeaderlen = (6187-6091); - const static uint16 kSymbolx = (64); - const static uint16 kSetdatlen = (64*128); - const static uint16 kMapwidth = (66); - const static uint16 kTextstart = (66*2); - const static uint16 kMaplen = (66*60); - const static uint16 kDiaryx = (68+24); - const static uint16 kLengthofvars = (68-0); - const static uint16 kKeypady = (72); - const static uint16 kZoomx = (8); - const static uint16 kInventx = (80); - const static uint16 kMenux = (80+40); - const static uint16 kLenofreelrouts = (991-534); + static const uint16 addr_dreamweb = 0xc948; + static const uint16 addr_keyboardread = 0xcbb4; + static const uint16 addr_resetkeyboard = 0xcbb0; + static const uint16 addr_setkeyboardint = 0xcbac; + static const uint16 addr_readfromfile = 0xcba8; + static const uint16 addr_closefile = 0xcba4; + static const uint16 addr_openforsave = 0xcba0; + static const uint16 addr_openfilenocheck = 0xcb9c; + static const uint16 addr_openfilefromc = 0xcb94; + static const uint16 addr_openfile = 0xcb90; + static const uint16 addr_createfile = 0xcb8c; + static const uint16 addr_readsetdata = 0xcb88; + static const uint16 addr_getridoftempsp = 0xcb84; + static const uint16 addr_getridoftempcharset = 0xcb80; + static const uint16 addr_getridoftemp3 = 0xcb7c; + static const uint16 addr_getridoftemp2 = 0xcb78; + static const uint16 addr_getridoftemptext = 0xcb74; + static const uint16 addr_getridoftemp = 0xcb70; + static const uint16 addr_allocateload = 0xcb68; + static const uint16 addr_dontloadseg = 0xcb64; + static const uint16 addr_findroominloc = 0xcb58; + static const uint16 addr_disablepath = 0xcb50; + static const uint16 addr_sortoutmap = 0xcb48; + static const uint16 addr_restoreall = 0xcb44; + static const uint16 addr_restorereels = 0xcb40; + static const uint16 addr_getridofall = 0xcb3c; + static const uint16 addr_getridofreels = 0xcb38; + static const uint16 addr_loadroomssample = 0xcb34; + static const uint16 addr_loadroom = 0xcb30; + static const uint16 addr_loadtemptext = 0xcb2c; + static const uint16 addr_standardload = 0xcb28; + static const uint16 addr_loadtempcharset = 0xcb24; + static const uint16 addr_loadintotemp3 = 0xcb20; + static const uint16 addr_loadintotemp2 = 0xcb1c; + static const uint16 addr_loadintotemp = 0xcb18; + static const uint16 addr_loadtraveltext = 0xcb14; + static const uint16 addr_hangon = 0xcb10; + static const uint16 addr_randomnum2 = 0xcb08; + static const uint16 addr_randomnum1 = 0xcb04; + static const uint16 addr_readkey = 0xcafc; + static const uint16 addr_readmouse4 = 0xcaf8; + static const uint16 addr_readmouse3 = 0xcaf4; + static const uint16 addr_readmouse2 = 0xcaf0; + static const uint16 addr_readmouse1 = 0xcaec; + static const uint16 addr_mousecall = 0xcae8; + static const uint16 addr_readmouse = 0xcae4; + static const uint16 addr_setmouse = 0xcae0; + static const uint16 addr_animpointer = 0xcadc; + 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_putunderzoom = 0xcabc; + static const uint16 addr_dumpzoom = 0xcab8; + static const uint16 addr_getunderzoom = 0xcab4; + static const uint16 addr_hangoncurs = 0xcab0; + static const uint16 addr_hangonw = 0xcaac; + static const uint16 addr_hangonp = 0xcaa8; + static const uint16 addr_allpointer = 0xcaa4; + static const uint16 addr_blank = 0xcaa0; + static const uint16 addr_worktoscreenm = 0xca9c; + static const uint16 addr_dumpblink = 0xca98; + static const uint16 addr_showblink = 0xca94; + static const uint16 addr_zoomicon = 0xca90; + static const uint16 addr_gettime = 0xca8c; + static const uint16 addr_showwatch = 0xca88; + static const uint16 addr_panelicons1 = 0xca84; + static const uint16 addr_showexit = 0xca80; + static const uint16 addr_usetempcharset = 0xca7c; + static const uint16 addr_usecharset1 = 0xca78; + static const uint16 addr_roomname = 0xca74; + static const uint16 addr_showman = 0xca6c; + static const uint16 addr_middlepanel = 0xca68; + static const uint16 addr_showicon = 0xca64; + static const uint16 addr_workoutframes = 0xca54; + static const uint16 addr_bresenhams = 0xca50; + static const uint16 addr_setwalk = 0xca44; + static const uint16 addr_getflagunderp = 0xca40; + static const uint16 addr_printmessage2 = 0xca30; + static const uint16 addr_printmessage = 0xca2c; + static const uint16 addr_examineobtext = 0xca20; + static const uint16 addr_obname = 0xca18; + static const uint16 addr_afterintroroom = 0xca14; + static const uint16 addr_walkintoroom = 0xca10; + static const uint16 addr_atmospheres = 0xca0c; + static const uint16 addr_afternewroom = 0xca08; + static const uint16 addr_checkifpathison = 0xca04; + static const uint16 addr_turnanypathoff = 0xca00; + static const uint16 addr_turnanypathon = 0xc9fc; + static const uint16 addr_turnpathoff = 0xc9f8; + static const uint16 addr_turnpathon = 0xc9f4; + static const uint16 addr_findfirstpath = 0xc9f0; + static const uint16 addr_findpathofpoint = 0xc9ec; + static const uint16 addr_isitdescribed = 0xc9e8; + static const uint16 addr_checkifex = 0xc9e0; + static const uint16 addr_checkifset = 0xc9dc; + static const uint16 addr_identifyob = 0xc9d4; + static const uint16 addr_checkcoords = 0xc9d0; + static const uint16 addr_madmanrun = 0xc9cc; + static const uint16 addr_mainscreen = 0xc9c8; + static const uint16 addr_walkandexamine = 0xcbb8; + static const uint16 addr_convnum = 0xc9c4; + static const uint16 addr_showword = 0xc9c0; + static const uint16 addr_twodigitnum = 0xc9bc; + static const uint16 addr_onedigit = 0xc9b8; + static const uint16 addr_showbyte = 0xc9b4; + static const uint16 addr_dumpwatch = 0xc9b0; + static const uint16 addr_showtime = 0xc9ac; + static const uint16 addr_watchcount = 0xc9a8; + static const uint16 addr_checkforshake = 0xc9a4; + static const uint16 addr_watchreel = 0xc9a0; + static const uint16 addr_screenupdate = 0xc99c; + static const uint16 addr_startup1 = 0xc998; + static const uint16 addr_startup = 0xc994; + static const uint16 addr_allocatemem = 0xc988; + static const uint16 addr_deallocatemem = 0xc984; + static const uint16 addr_clearrest = 0xc980; + static const uint16 addr_clearreels = 0xc97c; + static const uint16 addr_clearbeforeload = 0xc978; + static const uint16 addr_clearchanges = 0xc974; + static const uint16 addr_clearbuffers = 0xc970; + static const uint16 addr_allocatebuffers = 0xc96c; + static const uint16 addr_checkbasemem = 0xc968; + static const uint16 addr_checkforemm = 0xc964; + static const uint16 addr_removeemm = 0xc960; + static const uint16 addr_setupemm = 0xc95c; + static const uint16 addr_pickupob = 0xc958; + static const uint16 addr_initialinv = 0xc954; + static const uint16 addr_entryanims = 0xc950; + static const uint16 addr_entrytexts = 0xc94c; + static const uint16 addr_pitinterupt = 0xc944; + static const uint16 addr_getridofpit = 0xc940; + static const uint16 addr_setuppit = 0xc93c; + static const uint16 addr_startdmablock = 0xc938; + static const uint16 addr_dmaend = 0xc934; + static const uint16 addr_restoreems = 0xc92c; + static const uint16 addr_saveems = 0xc928; + static const uint16 addr_bothchannels = 0xc924; + static const uint16 addr_channel1only = 0xc91c; + static const uint16 addr_channel0only = 0xc918; + static const uint16 addr_volumeadjust = 0xc908; + static const uint16 addr_playchannel1 = 0xc900; + static const uint16 addr_playchannel0 = 0xc8fc; + static const uint16 addr_out22c = 0xc8f8; + static const uint16 addr_soundend = 0xc8f4; + static const uint16 addr_interupttest = 0xc8f0; + static const uint16 addr_disablesoundint = 0xc8ec; + static const uint16 addr_enablesoundint = 0xc8e8; + static const uint16 addr_checksoundint = 0xc8e4; + static const uint16 addr_setsoundoff = 0xc8e0; + static const uint16 addr_trysoundalloc = 0xc8dc; + static const uint16 addr_soundstartup = 0xc8d8; + static const uint16 addr_loadsecondsample = 0xc8d4; + static const uint16 addr_loadsample = 0xc8d0; + static const uint16 addr_createname = 0xc8cc; + static const uint16 addr_loadspeech = 0xc8c8; + static const uint16 addr_loadold = 0xc8c4; + static const uint16 addr_doload = 0xcbbc; + static const uint16 addr_newgame = 0xc8c0; + static const uint16 addr_showdecisions = 0xc8bc; + static const uint16 addr_decide = 0xc8b8; + static const uint16 addr_scanfornames = 0xc8b4; + static const uint16 addr_saveseg = 0xc8ac; + static const uint16 addr_storeit = 0xc8a8; + static const uint16 addr_makeheader = 0xc8a4; + static const uint16 addr_loadseg = 0xc8a0; + static const uint16 addr_loadposition = 0xc89c; + static const uint16 addr_saveposition = 0xc898; + static const uint16 addr_savefileread = 0xc894; + static const uint16 addr_savefilewrite = 0xc890; + static const uint16 addr_oldtonames = 0xc88c; + static const uint16 addr_namestoold = 0xc888; + static const uint16 addr_error = 0xc884; + static const uint16 addr_generalerror = 0xcbc0; + static const uint16 addr_dosreturn = 0xc880; + static const uint16 addr_shownames = 0xc87c; + static const uint16 addr_showslots = 0xc878; + static const uint16 addr_selectslot = 0xc874; + static const uint16 addr_showsaveops = 0xc870; + static const uint16 addr_showloadops = 0xc86c; + static const uint16 addr_showopbox = 0xc868; + static const uint16 addr_getnamepos = 0xc864; + static const uint16 addr_checkinput = 0xc860; + static const uint16 addr_selectslot2 = 0xc85c; + static const uint16 addr_actualload = 0xc858; + static const uint16 addr_actualsave = 0xc854; + static const uint16 addr_savegame = 0xc850; + static const uint16 addr_discops = 0xc84c; + static const uint16 addr_getbacktoops = 0xc848; + static const uint16 addr_loadgame = 0xc844; + static const uint16 addr_loadsavebox = 0xc840; + static const uint16 addr_showdiscops = 0xc83c; + static const uint16 addr_showmainops = 0xc838; + static const uint16 addr_getbackfromops = 0xc834; + static const uint16 addr_dosaveload = 0xc830; + static const uint16 addr_saveload = 0xc82c; + static const uint16 addr_zoomonoff = 0xc828; + static const uint16 addr_findtext1 = 0xc824; + static const uint16 addr_showdiarypage = 0xc820; + static const uint16 addr_diarykeyn = 0xc81c; + static const uint16 addr_diarykeyp = 0xc818; + static const uint16 addr_dumpdiarykeys = 0xc814; + static const uint16 addr_showdiarykeys = 0xc810; + static const uint16 addr_showdiary = 0xc80c; + static const uint16 addr_usediary = 0xc808; + static const uint16 addr_dumpsymbox = 0xc804; + static const uint16 addr_updatesymbolbot = 0xc800; + static const uint16 addr_updatesymboltop = 0xc7fc; + static const uint16 addr_nextsymbol = 0xc7f8; + static const uint16 addr_showsymbol = 0xc7f4; + static const uint16 addr_dumpsymbol = 0xc7f0; + static const uint16 addr_setbotright = 0xc7ec; + static const uint16 addr_setbotleft = 0xc7e8; + static const uint16 addr_settopright = 0xc7e4; + static const uint16 addr_settopleft = 0xc7e0; + static const uint16 addr_quitsymbol = 0xc7dc; + static const uint16 addr_entersymbol = 0xc7d8; + static const uint16 addr_showrightpage = 0xc7d4; + static const uint16 addr_showleftpage = 0xc7d0; + static const uint16 addr_folderexit = 0xc7cc; + static const uint16 addr_showfolder = 0xc7c8; + static const uint16 addr_loadfolder = 0xc7c4; + static const uint16 addr_lastfolder = 0xc7c0; + static const uint16 addr_folderhints = 0xc7bc; + static const uint16 addr_nextfolder = 0xc7b8; + static const uint16 addr_viewfolder = 0xc7b4; + static const uint16 addr_loadmenu = 0xc7b0; + static const uint16 addr_showmenu = 0xc7ac; + static const uint16 addr_showoutermenu = 0xc7a8; + static const uint16 addr_putundermenu = 0xc7a4; + static const uint16 addr_getundermenu = 0xc7a0; + static const uint16 addr_dumpmenu = 0xc79c; + static const uint16 addr_usemenu = 0xc798; + static const uint16 addr_dumpkeypad = 0xc794; + static const uint16 addr_singlekey = 0xc790; + static const uint16 addr_showkeypad = 0xc78c; + static const uint16 addr_showouterpad = 0xc788; + static const uint16 addr_buttonpress = 0xc784; + static const uint16 addr_buttonenter = 0xc780; + static const uint16 addr_buttonnought = 0xc77c; + static const uint16 addr_buttonnine = 0xc778; + static const uint16 addr_buttoneight = 0xc774; + static const uint16 addr_buttonseven = 0xc770; + static const uint16 addr_buttonsix = 0xc76c; + static const uint16 addr_buttonfive = 0xc768; + static const uint16 addr_buttonfour = 0xc764; + static const uint16 addr_buttonthree = 0xc760; + static const uint16 addr_buttontwo = 0xc75c; + static const uint16 addr_buttonone = 0xc758; + static const uint16 addr_addtopresslist = 0xc754; + static const uint16 addr_quitkey = 0xc750; + static const uint16 addr_loadkeypad = 0xc74c; + static const uint16 addr_entercode = 0xc748; + static const uint16 addr_usewinch = 0xc744; + static const uint16 addr_useplate = 0xc740; + static const uint16 addr_usebuttona = 0xc73c; + static const uint16 addr_useshield = 0xc738; + static const uint16 addr_usegun = 0xc734; + static const uint16 addr_usechurchgate = 0xc730; + static const uint16 addr_usewall = 0xc72c; + static const uint16 addr_edenscdplayer = 0xc728; + static const uint16 addr_setuptimeduse = 0xc71c; + static const uint16 addr_autoappear = 0xc70c; + static const uint16 addr_switchryanoff = 0xc700; + static const uint16 addr_switchryanon = 0xc6fc; + static const uint16 addr_removefreeobject = 0xc6f4; + static const uint16 addr_placefreeobject = 0xc6f0; + static const uint16 addr_issetobonmap = 0xc6ec; + static const uint16 addr_findpuztext = 0xc6e0; + static const uint16 addr_showpuztext = 0xc6dc; + static const uint16 addr_putbackobstuff = 0xc6d8; + static const uint16 addr_usetext = 0xc6d4; + static const uint16 addr_checkinside = 0xc6d0; + static const uint16 addr_isryanholding = 0xc6cc; + static const uint16 addr_findexobject = 0xc6c8; + static const uint16 addr_findsetobject = 0xc6c4; + static const uint16 addr_compare = 0xc6c0; + static const uint16 addr_selectob = 0xc6bc; + static const uint16 addr_withwhat = 0xc6b8; + static const uint16 addr_useelvdoor = 0xc6b4; + static const uint16 addr_useaxe = 0xc6b0; + static const uint16 addr_usecooker = 0xc6ac; + static const uint16 addr_usestereo = 0xc6a8; + static const uint16 addr_usekey = 0xc6a4; + static const uint16 addr_useelevator5 = 0xc6a0; + static const uint16 addr_useelevator2 = 0xc69c; + static const uint16 addr_useelevator4 = 0xc698; + static const uint16 addr_useelevator3 = 0xc694; + static const uint16 addr_showfirstuse = 0xc690; + static const uint16 addr_useelevator1 = 0xc68c; + static const uint16 addr_usehandle = 0xc688; + static const uint16 addr_usewire = 0xc684; + static const uint16 addr_usehatch = 0xc680; + static const uint16 addr_usecontrol = 0xc67c; + static const uint16 addr_moneypoke = 0xc678; + static const uint16 addr_lookatcard = 0xc674; + static const uint16 addr_usecashcard = 0xc670; + static const uint16 addr_usecardreader3 = 0xc66c; + static const uint16 addr_usecardreader2 = 0xc668; + static const uint16 addr_usecardreader1 = 0xc664; + static const uint16 addr_showseconduse = 0xc660; + static const uint16 addr_uselighter = 0xc65c; + static const uint16 addr_usepoolreader = 0xc658; + static const uint16 addr_calledensdlift = 0xc654; + static const uint16 addr_calledenslift = 0xc650; + static const uint16 addr_callhotellift = 0xc64c; + static const uint16 addr_trapdoor = 0xc648; + static const uint16 addr_grafittidoor = 0xc644; + static const uint16 addr_openhoteldoor2 = 0xc640; + static const uint16 addr_openhoteldoor = 0xc63c; + static const uint16 addr_drawitall = 0xc638; + static const uint16 addr_isitright = 0xc634; + static const uint16 addr_opensarters = 0xc630; + static const uint16 addr_openeden = 0xc62c; + static const uint16 addr_openpoolboss = 0xc628; + static const uint16 addr_openryan = 0xc624; + static const uint16 addr_usebalcony = 0xc620; + static const uint16 addr_usewindow = 0xc61c; + static const uint16 addr_openyourneighbour = 0xc618; + static const uint16 addr_nextcolon = 0xc614; + static const uint16 addr_openlouis = 0xc610; + static const uint16 addr_usedryer = 0xc60c; + static const uint16 addr_opentvdoor = 0xc608; + static const uint16 addr_usealtar = 0xc604; + static const uint16 addr_usehole = 0xc600; + static const uint16 addr_usechurchhole = 0xc5fc; + static const uint16 addr_sitdowninbar = 0xc5f8; + static const uint16 addr_wearshades = 0xc5f4; + static const uint16 addr_wearwatch = 0xc5f0; + static const uint16 addr_useopenbox = 0xc5ec; + static const uint16 addr_userailing = 0xc5e8; + static const uint16 addr_usecoveredbox = 0xc5e4; + static const uint16 addr_useclearbox = 0xc5e0; + static const uint16 addr_usecart = 0xc5dc; + static const uint16 addr_useslab = 0xc5d8; + static const uint16 addr_slabdoorf = 0xc5d4; + static const uint16 addr_slabdoore = 0xc5d0; + static const uint16 addr_slabdoorc = 0xc5cc; + static const uint16 addr_slabdoord = 0xc5c8; + static const uint16 addr_slabdoorb = 0xc5c4; + static const uint16 addr_slabdoora = 0xc5c0; + static const uint16 addr_useladderb = 0xc5bc; + static const uint16 addr_useladder = 0xc5b8; + static const uint16 addr_chewy = 0xc5b4; + static const uint16 addr_useplinth = 0xc5b0; + static const uint16 addr_usefullcart = 0xc5ac; + static const uint16 addr_usepipe = 0xc5a8; + static const uint16 addr_nothelderror = 0xc5a4; + static const uint16 addr_usetrainer = 0xc5a0; + static const uint16 addr_opentomb = 0xc59c; + static const uint16 addr_hotelbell = 0xc598; + static const uint16 addr_hotelcontrol = 0xc594; + static const uint16 addr_playguitar = 0xc590; + static const uint16 addr_runtap = 0xc58c; + static const uint16 addr_wheelsound = 0xc588; + static const uint16 addr_useroutine = 0xc584; + static const uint16 addr_useobject = 0xc580; + static const uint16 addr_delcurs = 0xc57c; + static const uint16 addr_printcurs = 0xc578; + static const uint16 addr_triggermessage = 0xc574; + static const uint16 addr_processtrigger = 0xc570; + static const uint16 addr_monmessage = 0xc56c; + static const uint16 addr_showcurrentfile = 0xc568; + static const uint16 addr_printlogo = 0xc564; + static const uint16 addr_monitorlogo = 0xc560; + static const uint16 addr_scrollmonitor = 0xc558; + static const uint16 addr_parser = 0xc554; + static const uint16 addr_searchforstring = 0xc550; + static const uint16 addr_getkeyandlogo = 0xc54c; + static const uint16 addr_dirfile = 0xc548; + static const uint16 addr_read = 0xc544; + static const uint16 addr_showkeys = 0xc540; + static const uint16 addr_signon = 0xc53c; + static const uint16 addr_searchforfiles = 0xc538; + static const uint16 addr_dircom = 0xc534; + static const uint16 addr_neterror = 0xc530; + static const uint16 addr_execcommand = 0xc52c; + static const uint16 addr_delchar = 0xc528; + static const uint16 addr_makecaps = 0xc524; + static const uint16 addr_input = 0xc520; + static const uint16 addr_locklightoff = 0xc51c; + static const uint16 addr_locklighton = 0xc518; + static const uint16 addr_accesslightoff = 0xc514; + static const uint16 addr_accesslighton = 0xc510; + static const uint16 addr_powerlightoff = 0xc50c; + static const uint16 addr_powerlighton = 0xc508; + static const uint16 addr_randomaccess = 0xc504; + static const uint16 addr_turnonpower = 0xc500; + static const uint16 addr_lookininterface = 0xc4fc; + static const uint16 addr_loadcart = 0xc4f8; + static const uint16 addr_loadnews = 0xc4f4; + static const uint16 addr_loadpersonal = 0xc4f0; + static const uint16 addr_printoutermon = 0xc4ec; + static const uint16 addr_usemon = 0xc4e8; + static const uint16 addr_readcitypic = 0xc4e4; + static const uint16 addr_readdesticon = 0xc4e0; + static const uint16 addr_resetlocation = 0xc4dc; + static const uint16 addr_setlocation = 0xc4d8; + static const uint16 addr_getlocation = 0xc4d4; + static const uint16 addr_destselect = 0xc4d0; + static const uint16 addr_lastdest = 0xc4cc; + static const uint16 addr_nextdest = 0xc4c8; + static const uint16 addr_showarrows = 0xc4c4; + static const uint16 addr_getdestinfo = 0xc4c0; + static const uint16 addr_locationpic = 0xc4bc; + static const uint16 addr_putundercentre = 0xc4b8; + static const uint16 addr_getundercentre = 0xc4b4; + static const uint16 addr_lookatplace = 0xc4b0; + static const uint16 addr_showcity = 0xc4ac; + static const uint16 addr_selectlocation = 0xc4a8; + static const uint16 addr_newplace = 0xc4a4; + static const uint16 addr_redes = 0xc4a0; + static const uint16 addr_hangonpq = 0xc49c; + static const uint16 addr_dosometalk = 0xc498; + static const uint16 addr_moretalk = 0xc494; + static const uint16 addr_getpersontext = 0xc490; + static const uint16 addr_starttalk = 0xc48c; + static const uint16 addr_getpersframe = 0xc488; + static const uint16 addr_convicons = 0xc484; + static const uint16 addr_talk = 0xc480; + static const uint16 addr_getback1 = 0xc47c; + static const uint16 addr_redrawmainscrn = 0xc478; + static const uint16 addr_dolook = 0xc474; + static const uint16 addr_look = 0xc470; + static const uint16 addr_autolook = 0xc46c; + static const uint16 addr_showallex = 0xc450; + static const uint16 addr_drawflags = 0xc43c; + static const uint16 addr_drawfloor = 0xc428; + static const uint16 addr_blockget = 0xc424; + static const uint16 addr_deleteextext = 0xc420; + static const uint16 addr_deleteexframe = 0xc41c; + static const uint16 addr_deleteexobject = 0xc418; + static const uint16 addr_purgeanitem = 0xc414; + static const uint16 addr_emergencypurge = 0xc410; + static const uint16 addr_purgealocation = 0xc40c; + static const uint16 addr_getexpos = 0xc408; + static const uint16 addr_transfertext = 0xc404; + static const uint16 addr_transfercontoex = 0xc400; + static const uint16 addr_pickupconts = 0xc3fc; + static const uint16 addr_transfertoex = 0xc3f8; + static const uint16 addr_outofopen = 0xc3f4; + static const uint16 addr_checkobjectsize = 0xc3f0; + static const uint16 addr_errormessage3 = 0xc3ec; + static const uint16 addr_errormessage2 = 0xc3e8; + static const uint16 addr_errormessage1 = 0xc3e4; + static const uint16 addr_useopened = 0xc3e0; + static const uint16 addr_selectopenob = 0xc3dc; + static const uint16 addr_removeobfrominv = 0xc3d8; + static const uint16 addr_wornerror = 0xc3d4; + static const uint16 addr_cantdrop = 0xc3d0; + static const uint16 addr_droperror = 0xc3cc; + static const uint16 addr_dropobject = 0xc3c8; + static const uint16 addr_findopenpos = 0xc3c4; + static const uint16 addr_findinvpos = 0xc3c0; + static const uint16 addr_getsetad = 0xc3bc; + static const uint16 addr_getopenedsize = 0xc3b8; + static const uint16 addr_getanyaddir = 0xc3b4; + static const uint16 addr_getanyad = 0xc3b0; + static const uint16 addr_geteitherad = 0xc3ac; + static const uint16 addr_getexad = 0xc3a8; + static const uint16 addr_getfreead = 0xc3a4; + static const uint16 addr_outofinv = 0xc3a0; + static const uint16 addr_intoinv = 0xc398; + static const uint16 addr_swapwithopen = 0xc394; + static const uint16 addr_swapwithinv = 0xc390; + static const uint16 addr_reexfromopen = 0xc38c; + static const uint16 addr_reexfrominv = 0xc388; + static const uint16 addr_examinventory = 0xc384; + static const uint16 addr_setpickup = 0xc380; + static const uint16 addr_inventory = 0xc37c; + static const uint16 addr_findnextcolon = 0xc378; + static const uint16 addr_searchforsame = 0xc374; + static const uint16 addr_getobtextstart = 0xc370; + static const uint16 addr_obsthatdothings = 0xc36c; + static const uint16 addr_additionaltext = 0xc368; + static const uint16 addr_describeob = 0xc364; + static const uint16 addr_obpicture = 0xc360; + static const uint16 addr_examicon = 0xc35c; + static const uint16 addr_obicons = 0xc358; + static const uint16 addr_openob = 0xc354; + static const uint16 addr_showryanpage = 0xc350; + static const uint16 addr_openinv = 0xc34c; + static const uint16 addr_incryanpage = 0xc348; + static const uint16 addr_getbackfromob = 0xc344; + static const uint16 addr_makemainscreen = 0xc340; + static const uint16 addr_examineob = 0xc33c; + static const uint16 addr_makeworn = 0xc338; + static const uint16 addr_isitworn = 0xc334; + static const uint16 addr_obtoinv = 0xc330; + static const uint16 addr_findallopen = 0xc32c; + static const uint16 addr_findallryan = 0xc328; + static const uint16 addr_fillopen = 0xc324; + static const uint16 addr_fillryan = 0xc320; + static const uint16 addr_monprint = 0xc314; + static const uint16 addr_waitframes = 0xc308; + static const uint16 addr_realcredits = 0xc2f8; + static const uint16 addr_set16colpalette = 0xc2f4; + static const uint16 addr_mode640x480 = 0xc2f0; + static const uint16 addr_loadintroroom = 0xc2ec; + static const uint16 addr_runendseq = 0xc2e8; + static const uint16 addr_runintroseq = 0xc2e4; + static const uint16 addr_intro = 0xc2e0; + static const uint16 addr_hangone = 0xc2dc; + static const uint16 addr_biblequote = 0xc2d8; + static const uint16 addr_credits = 0xc2d4; + static const uint16 addr_gettingshot = 0xc2d0; + static const uint16 addr_showmonk = 0xc2cc; + static const uint16 addr_monkspeaking = 0xc2c8; + static const uint16 addr_endgame = 0xc2c4; + static const uint16 addr_titles = 0xc2c0; + static const uint16 addr_initialmoncols = 0xc2bc; + static const uint16 addr_fadeupyellows = 0xc2b8; + static const uint16 addr_fadeupmonfirst = 0xc2b4; + static const uint16 addr_fadeupmon = 0xc2b0; + static const uint16 addr_fadedownmon = 0xc2ac; + static const uint16 addr_dumpcurrent = 0xc2a8; + static const uint16 addr_allpalette = 0xc2a4; + static const uint16 addr_paltoendpal = 0xc2a0; + static const uint16 addr_startpaltoend = 0xc29c; + static const uint16 addr_endpaltostart = 0xc298; + static const uint16 addr_paltostartpal = 0xc294; + static const uint16 addr_showgroup = 0xc290; + static const uint16 addr_greyscalesum = 0xc28c; + static const uint16 addr_fadecalculation = 0xc288; + static const uint16 addr_rollem = 0xc284; + static const uint16 addr_rollendcredits2 = 0xc280; + static const uint16 addr_showgun = 0xc27c; + static const uint16 addr_clearstartpal = 0xc278; + static const uint16 addr_fadescreendowns = 0xc274; + static const uint16 addr_fadescreendown = 0xc270; + static const uint16 addr_fadescreenuphalf = 0xc26c; + static const uint16 addr_fadescreendownhalf = 0xc268; + static const uint16 addr_fadescreenups = 0xc264; + static const uint16 addr_fadefromwhite = 0xc260; + static const uint16 addr_fadetowhite = 0xc25c; + static const uint16 addr_fadescreenup = 0xc258; + static const uint16 addr_clearpalette = 0xc254; + static const uint16 addr_clearendpal = 0xc250; + static const uint16 addr_dofade = 0xc24c; + static const uint16 addr_fadedos = 0xc248; + static const uint16 addr_transfermap = 0xc244; + static const uint16 addr_transferinv = 0xc240; + static const uint16 addr_delthisone = 0xc214; + static const uint16 addr_doshake = 0xc20c; + static const uint16 addr_vsync = 0xc208; + static const uint16 addr_createpanel2 = 0xc200; + static const uint16 addr_createpanel = 0xc1fc; + static const uint16 addr_pixelcheckset = 0xc1f8; + static const uint16 addr_dumpmap = 0xc1f4; + static const uint16 addr_maptopanel = 0xc1f0; + static const uint16 addr_paneltomap = 0xc1ec; + static const uint16 addr_setmode = 0xc1dc; + static const uint16 addr_loadpalfromiff = 0xc1d8; + static const uint16 addr_showpcx = 0xc1cc; + static const uint16 addr_dumpeverything = 0xc1c4; + static const uint16 addr_deleverything = 0xc1c0; + static const uint16 addr_reconstruct = 0xc1ac; + static const uint16 addr_soundonreels = 0xc1a8; + static const uint16 addr_reelsonscreen = 0xc1a0; + 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_getblockofpixel = 0xc168; + static const uint16 addr_splitintolines = 0xc164; + static const uint16 addr_initrain = 0xc160; + static const uint16 addr_reminders = 0xc15c; + static const uint16 addr_adjustright = 0xc158; + static const uint16 addr_adjustleft = 0xc154; + static const uint16 addr_adjustup = 0xc150; + static const uint16 addr_adjustdown = 0xc14c; + static const uint16 addr_checkforexit = 0xc148; + static const uint16 addr_mainman = 0xc138; + static const uint16 addr_delsprite = 0xc11c; + static const uint16 addr_checkspeed = 0xc110; + static const uint16 addr_addtopeoplelist = 0xc108; + static const uint16 addr_train = 0xc104; + static const uint16 addr_sparky = 0xc100; + static const uint16 addr_copper = 0xc0fc; + static const uint16 addr_advisor = 0xc0f8; + static const uint16 addr_drunk = 0xc0f4; + static const uint16 addr_textformonk = 0xc0f0; + static const uint16 addr_textforend = 0xc0ec; + static const uint16 addr_priesttext = 0xc0e8; + static const uint16 addr_madman = 0xc0dc; + static const uint16 addr_madmanstelly = 0xc0d8; + static const uint16 addr_priest = 0xc0d4; + static const uint16 addr_rollendcredits = 0xc0d0; + static const uint16 addr_endgameseq = 0xc0cc; + static const uint16 addr_monkandryan = 0xc0c8; + static const uint16 addr_intro3text = 0xc0c4; + static const uint16 addr_intro2text = 0xc0c0; + static const uint16 addr_intro1text = 0xc0bc; + static const uint16 addr_monks2text = 0xc0b8; + static const uint16 addr_handclap = 0xc0b4; + static const uint16 addr_intromonks2 = 0xc0b0; + static const uint16 addr_intromonks1 = 0xc0ac; + static const uint16 addr_intromagic3 = 0xc0a8; + static const uint16 addr_intromagic2 = 0xc0a4; + static const uint16 addr_gates = 0xc0a0; + static const uint16 addr_candles2 = 0xc09c; + static const uint16 addr_candles = 0xc098; + static const uint16 addr_intromagic1 = 0xc094; + static const uint16 addr_smallcandle = 0xc090; + static const uint16 addr_candles1 = 0xc08c; + static const uint16 addr_keeper = 0xc088; + static const uint16 addr_carparkdrip = 0xc084; + static const uint16 addr_sparkydrip = 0xc080; + static const uint16 addr_gamer = 0xc07c; + static const uint16 addr_bossman = 0xc078; + static const uint16 addr_heavy = 0xc074; + static const uint16 addr_security = 0xc070; + static const uint16 addr_poolguard = 0xc06c; + static const uint16 addr_businessman = 0xc068; + static const uint16 addr_aide = 0xc064; + static const uint16 addr_mugger = 0xc060; + static const uint16 addr_helicopter = 0xc05c; + static const uint16 addr_rockstar = 0xc058; + static const uint16 addr_soldier1 = 0xc054; + static const uint16 addr_interviewer = 0xc050; + static const uint16 addr_barwoman = 0xc04c; + static const uint16 addr_othersmoker = 0xc048; + static const uint16 addr_bartender = 0xc044; + static const uint16 addr_drinker = 0xc040; + static const uint16 addr_tattooman = 0xc03c; + static const uint16 addr_mansatstill = 0xc038; + static const uint16 addr_manasleep2 = 0xc034; + static const uint16 addr_louischair = 0xc030; + static const uint16 addr_louis = 0xc02c; + static const uint16 addr_femalefan = 0xc028; + static const uint16 addr_malefan = 0xc024; + static const uint16 addr_edeninbath = 0xc020; + static const uint16 addr_eden = 0xc01c; + static const uint16 addr_manasleep = 0xc018; + static const uint16 addr_attendant = 0xc014; + static const uint16 addr_smokebloke = 0xc010; + static const uint16 addr_receptionist = 0xc00c; + static const uint16 addr_foghornsound = 0xc008; + static const uint16 addr_intromusic = 0xc004; + static const uint16 addr_alleybarksound = 0xc000; + static const uint16 offset_quitlist = 0x0a84; + static const uint16 offset_savelist = 0x0f44; + static const uint16 offset_mainlist = 0x1402; + static const uint16 offset_gameerror8 = 0x113f; + static const uint16 offset_blinktab = 0x1700; + static const uint16 offset_error2patch = 0x0ff6; + static const uint16 offset_openchangesize = 0x0a1c; + static const uint16 offset_keys = 0x0b14; + static const uint16 offset_mainlist2 = 0x1440; + static const uint16 offset_uselist = 0x0ba8; + static const uint16 offset_gameerror2 = 0x0fb2; + static const uint16 offset_loadlist = 0x0ef0; + static const uint16 offset_gameerror6 = 0x10be; + static const uint16 offset_flashmousetab = 0x1707; + static const uint16 offset_speechfile = 0x13f1; + static const uint16 offset_atmospherelist = 0x147e; + static const uint16 offset_gameerror4 = 0x1037; + static const uint16 offset_gameerror1 = 0x0f6e; + static const uint16 offset_examlist = 0x09be; + static const uint16 offset_gameinfo = 0x1170; + static const uint16 offset_decidelist = 0x13c1; + static const uint16 offset_invlist1 = 0x09fc; + static const uint16 offset_money2poke = 0x0d97; + static const uint16 offset_talklist = 0x0a64; + static const uint16 offset_menulist = 0x0e1e; + static const uint16 offset_comlist = 0x0ad8; + static const uint16 offset_withlist1 = 0x0a3a; + static const uint16 offset_money1poke = 0x0d92; + static const uint16 offset_gameerror7 = 0x1104; + static const uint16 offset_discopslist = 0x0f1a; + static const uint16 offset_commandline = 0x16d7; + static const uint16 offset_destlist = 0x0a9a; + static const uint16 offset_shaketable = 0x06af; + static const uint16 offset_error6patch = 0x10fe; + static const uint16 offset_keybuffer = 0x1718; + static const uint16 offset_speechfilename = 0x13eb; + static const uint16 offset_folderlist = 0x0e34; + static const uint16 offset_rootdir = 0x0b8c; + static const uint16 offset_gameerror3 = 0x1003; + static const uint16 offset_rainlocations = 0x0459; + static const uint16 offset_diarylist = 0x0e9c; + static const uint16 offset_opslist = 0x0ec6; + static const uint16 offset_symbollist = 0x0e5e; + static const uint16 offset_gameerror5 = 0x1074; + static const uint16 offset_facelist = 0x0451; + static const uint16 offset_operand1 = 0x0b7e; + static const uint16 offset_keypadlist = 0x0d9a; + static const uint16 kStartvars = 0; + static const uint16 kProgresspoints = 1; + static const uint16 kWatchon = 2; + static const uint16 kShadeson = 3; + static const uint16 kSecondcount = 4; + static const uint16 kMinutecount = 5; + static const uint16 kHourcount = 6; + static const uint16 kZoomon = 7; + static const uint16 kLocation = 8; + static const uint16 kExpos = 9; + static const uint16 kExframepos = 10; + static const uint16 kExtextpos = 12; + static const uint16 kCard1money = 14; + static const uint16 kListpos = 16; + static const uint16 kRyanpage = 18; + static const uint16 kWatchingtime = 19; + static const uint16 kReeltowatch = 21; + static const uint16 kEndwatchreel = 23; + static const uint16 kSpeedcount = 25; + static const uint16 kWatchspeed = 26; + static const uint16 kReeltohold = 27; + static const uint16 kEndofholdreel = 29; + static const uint16 kWatchmode = 31; + static const uint16 kDestafterhold = 32; + static const uint16 kNewsitem = 33; + static const uint16 kLiftflag = 34; + static const uint16 kLiftpath = 35; + static const uint16 kLockstatus = 36; + static const uint16 kDoorpath = 37; + static const uint16 kCounttoopen = 38; + static const uint16 kCounttoclose = 39; + static const uint16 kRockstardead = 40; + static const uint16 kGeneraldead = 41; + static const uint16 kSartaindead = 42; + static const uint16 kAidedead = 43; + static const uint16 kBeenmugged = 44; + static const uint16 kGunpassflag = 45; + static const uint16 kCanmovealtar = 46; + static const uint16 kTalkedtoattendant = 47; + static const uint16 kTalkedtosparky = 48; + static const uint16 kTalkedtoboss = 49; + static const uint16 kTalkedtorecep = 50; + static const uint16 kCardpassflag = 51; + static const uint16 kMadmanflag = 52; + static const uint16 kKeeperflag = 53; + static const uint16 kLasttrigger = 54; + static const uint16 kMandead = 55; + static const uint16 kSeed = 56; + static const uint16 kNeedtotravel = 59; + static const uint16 kThroughdoor = 60; + static const uint16 kNewobs = 61; + static const uint16 kRyanon = 62; + static const uint16 kCombatcount = 63; + static const uint16 kLastweapon = 64; + static const uint16 kDreamnumber = 65; + static const uint16 kRoomafterdream = 66; + static const uint16 kShakecounter = 67; + static const uint16 kSpeechcount = 68; + static const uint16 kCharshift = 69; + static const uint16 kKerning = 71; + static const uint16 kBrightness = 72; + static const uint16 kRoomloaded = 73; + static const uint16 kDidzoom = 74; + static const uint16 kLinespacing = 75; + static const uint16 kTextaddressx = 77; + static const uint16 kTextaddressy = 79; + static const uint16 kTextlen = 81; + static const uint16 kLastxpos = 82; + static const uint16 kIcontop = 84; + static const uint16 kIconleft = 86; + static const uint16 kItemframe = 88; + static const uint16 kItemtotran = 89; + static const uint16 kRoomad = 90; + static const uint16 kOldsubject = 92; + static const uint16 kWithobject = 94; + static const uint16 kWithtype = 95; + static const uint16 kLookcounter = 96; + static const uint16 kCommand = 98; + static const uint16 kCommandtype = 99; + static const uint16 kOldcommandtype = 100; + static const uint16 kObjecttype = 101; + static const uint16 kGetback = 102; + static const uint16 kInvopen = 103; + static const uint16 kMainmode = 104; + static const uint16 kPickup = 105; + static const uint16 kLastinvpos = 106; + static const uint16 kExamagain = 107; + static const uint16 kNewtextline = 108; + static const uint16 kOpenedob = 109; + static const uint16 kOpenedtype = 110; + static const uint16 kOldmapadx = 111; + static const uint16 kOldmapady = 113; + static const uint16 kMapadx = 115; + static const uint16 kMapady = 117; + static const uint16 kMapoffsetx = 119; + static const uint16 kMapoffsety = 121; + static const uint16 kMapxstart = 123; + static const uint16 kMapystart = 125; + static const uint16 kMapxsize = 127; + static const uint16 kMapysize = 128; + static const uint16 kHavedoneobs = 129; + static const uint16 kManisoffscreen = 130; + static const uint16 kRainspace = 131; + static const uint16 kFacing = 132; + static const uint16 kLeavedirection = 133; + static const uint16 kTurntoface = 134; + static const uint16 kTurndirection = 135; + static const uint16 kMaintimer = 136; + static const uint16 kIntrocount = 138; + static const uint16 kArrowad = 139; + static const uint16 kCurrentkey = 141; + static const uint16 kOldkey = 142; + static const uint16 kUseddirection = 143; + static const uint16 kCurrentkey2 = 144; + static const uint16 kTimercount = 145; + static const uint16 kOldtimercount = 146; + static const uint16 kMapx = 147; + static const uint16 kMapy = 148; + static const uint16 kNewscreen = 149; + static const uint16 kRyanx = 150; + static const uint16 kRyany = 151; + static const uint16 kLastflag = 152; + static const uint16 kLastflagex = 153; + static const uint16 kFlagx = 154; + static const uint16 kFlagy = 155; + static const uint16 kCurrentex = 156; + static const uint16 kCurrentfree = 157; + static const uint16 kCurrentframe = 158; + static const uint16 kFramesad = 160; + static const uint16 kDataad = 162; + static const uint16 kFrsegment = 164; + static const uint16 kObjectx = 166; + static const uint16 kObjecty = 168; + static const uint16 kOffsetx = 170; + static const uint16 kOffsety = 172; + static const uint16 kSavesize = 174; + static const uint16 kSavesource = 176; + static const uint16 kSavex = 178; + static const uint16 kSavey = 179; + static const uint16 kCurrentob = 180; + static const uint16 kPrioritydep = 181; + static const uint16 kDestpos = 182; + static const uint16 kReallocation = 183; + static const uint16 kRoomnum = 184; + static const uint16 kNowinnewroom = 185; + static const uint16 kResetmanxy = 186; + static const uint16 kNewlocation = 187; + static const uint16 kAutolocation = 188; + static const uint16 kMustload = 189; + static const uint16 kAnswered = 190; + static const uint16 kSaidno = 191; + static const uint16 kDoorcheck1 = 192; + static const uint16 kDoorcheck2 = 193; + static const uint16 kDoorcheck3 = 194; + static const uint16 kDoorcheck4 = 195; + static const uint16 kMousex = 196; + static const uint16 kMousey = 198; + static const uint16 kMousebutton = 200; + static const uint16 kMousebutton1 = 202; + static const uint16 kMousebutton2 = 204; + static const uint16 kMousebutton3 = 206; + static const uint16 kMousebutton4 = 208; + static const uint16 kOldbutton = 210; + static const uint16 kOldx = 212; + static const uint16 kOldy = 214; + static const uint16 kLastbutton = 216; + static const uint16 kOldpointerx = 218; + static const uint16 kOldpointery = 220; + static const uint16 kDelherex = 222; + static const uint16 kDelherey = 224; + static const uint16 kPointerxs = 226; + static const uint16 kPointerys = 227; + static const uint16 kDelxs = 228; + static const uint16 kDelys = 229; + static const uint16 kPointerframe = 230; + static const uint16 kPointerpower = 231; + static const uint16 kAuxpointerframe = 232; + static const uint16 kPointermode = 233; + static const uint16 kPointerspeed = 234; + static const uint16 kPointercount = 235; + static const uint16 kInmaparea = 236; + static const uint16 kReelpointer = 237; + static const uint16 kSlotdata = 239; + static const uint16 kThisslot = 240; + static const uint16 kSlotflags = 241; + static const uint16 kTakeoff = 242; + static const uint16 kTalkmode = 244; + static const uint16 kTalkpos = 245; + static const uint16 kCharacter = 246; + static const uint16 kPersondata = 247; + static const uint16 kTalknum = 249; + static const uint16 kNumberinroom = 250; + static const uint16 kCurrentcel = 251; + static const uint16 kOldselection = 252; + static const uint16 kStopwalking = 253; + static const uint16 kMouseon = 254; + static const uint16 kPlayed = 255; + static const uint16 kTimer1 = 257; + static const uint16 kTimer2 = 258; + static const uint16 kTimer3 = 259; + static const uint16 kWholetimer = 260; + static const uint16 kTimer1to = 262; + static const uint16 kTimer2to = 263; + static const uint16 kTimer3to = 264; + static const uint16 kWatchdump = 265; + static const uint16 kCurrentset = 266; + static const uint16 kLogonum = 268; + static const uint16 kOldlogonum = 269; + static const uint16 kNewlogonum = 270; + static const uint16 kNetseg = 271; + static const uint16 kNetpoint = 273; + static const uint16 kKeynum = 275; + static const uint16 kCursorstate = 276; + static const uint16 kPressed = 277; + static const uint16 kPresspointer = 278; + static const uint16 kGraphicpress = 280; + static const uint16 kPresscount = 281; + static const uint16 kKeypadax = 282; + static const uint16 kKeypadcx = 284; + static const uint16 kLightcount = 286; + static const uint16 kFolderpage = 287; + static const uint16 kDiarypage = 288; + static const uint16 kMenucount = 289; + static const uint16 kSymboltopx = 290; + static const uint16 kSymboltopnum = 291; + static const uint16 kSymboltopdir = 292; + static const uint16 kSymbolbotx = 293; + static const uint16 kSymbolbotnum = 294; + static const uint16 kSymbolbotdir = 295; + static const uint16 kSymboltolight = 296; + static const uint16 kSymbol1 = 297; + static const uint16 kSymbol2 = 298; + static const uint16 kSymbol3 = 299; + static const uint16 kSymbolnum = 300; + static const uint16 kDumpx = 301; + static const uint16 kDumpy = 303; + static const uint16 kWalkandexam = 305; + static const uint16 kWalkexamtype = 306; + static const uint16 kWalkexamnum = 307; + static const uint16 kCursloc = 308; + static const uint16 kCurslocx = 310; + static const uint16 kCurslocy = 312; + static const uint16 kCurpos = 314; + static const uint16 kMonadx = 316; + static const uint16 kMonady = 318; + static const uint16 kGotfrom = 320; + static const uint16 kMonsource = 322; + static const uint16 kNumtodo = 324; + static const uint16 kTimecount = 326; + static const uint16 kCounttotimed = 328; + static const uint16 kTimedseg = 330; + static const uint16 kTimedoffset = 332; + static const uint16 kTimedy = 334; + static const uint16 kTimedx = 335; + static const uint16 kNeedtodumptimed = 336; + static const uint16 kHandle = 337; + static const uint16 kLoadingorsave = 339; + static const uint16 kCurrentslot = 340; + static const uint16 kCursorpos = 341; + static const uint16 kColourpos = 342; + static const uint16 kFadedirection = 343; + static const uint16 kNumtofade = 344; + static const uint16 kFadecount = 345; + static const uint16 kAddtogreen = 346; + static const uint16 kAddtored = 347; + static const uint16 kAddtoblue = 348; + static const uint16 kLastsoundreel = 349; + static const uint16 kSoundbuffer = 351; + static const uint16 kSoundbufferad = 353; + static const uint16 kSoundbufferpage = 355; + static const uint16 kSoundtimes = 356; + static const uint16 kNeedsoundbuff = 357; + static const uint16 kOldint9seg = 358; + static const uint16 kOldint9add = 360; + static const uint16 kOldint8seg = 362; + static const uint16 kOldint8add = 364; + static const uint16 kOldsoundintseg = 366; + static const uint16 kOldsoundintadd = 368; + static const uint16 kSoundbaseadd = 370; + static const uint16 kDsp_status = 372; + static const uint16 kDsp_write = 374; + static const uint16 kDmaaddress = 376; + static const uint16 kSoundint = 377; + static const uint16 kSounddmachannel = 378; + static const uint16 kSampleplaying = 379; + static const uint16 kTestresult = 380; + static const uint16 kCurrentirq = 381; + static const uint16 kSpeechloaded = 382; + static const uint16 kSpeechlength = 383; + static const uint16 kVolume = 385; + static const uint16 kVolumeto = 386; + static const uint16 kVolumedirection = 387; + static const uint16 kVolumecount = 388; + static const uint16 kPlayblock = 389; + static const uint16 kWongame = 390; + static const uint16 kLasthardkey = 391; + static const uint16 kBufferin = 392; + static const uint16 kBufferout = 394; + static const uint16 kExtras = 396; + static const uint16 kWorkspace = 398; + static const uint16 kMapstore = 400; + static const uint16 kCharset1 = 402; + static const uint16 kTempcharset = 404; + static const uint16 kIcons1 = 406; + static const uint16 kIcons2 = 408; + static const uint16 kBuffers = 410; + static const uint16 kMainsprites = 412; + static const uint16 kBackdrop = 414; + static const uint16 kMapdata = 416; + static const uint16 kSounddata = 418; + static const uint16 kSounddata2 = 420; + static const uint16 kRecordspace = 422; + static const uint16 kFreedat = 424; + static const uint16 kSetdat = 426; + static const uint16 kReel1 = 428; + static const uint16 kReel2 = 430; + static const uint16 kReel3 = 432; + static const uint16 kRoomdesc = 434; + static const uint16 kFreedesc = 436; + static const uint16 kSetdesc = 438; + static const uint16 kBlockdesc = 440; + static const uint16 kSetframes = 442; + static const uint16 kFreeframes = 444; + static const uint16 kPeople = 446; + static const uint16 kReels = 448; + static const uint16 kCommandtext = 450; + static const uint16 kPuzzletext = 452; + static const uint16 kTraveltext = 454; + static const uint16 kTempgraphics = 456; + static const uint16 kTempgraphics2 = 458; + static const uint16 kTempgraphics3 = 460; + static const uint16 kTempsprites = 462; + static const uint16 kTextfile1 = 464; + static const uint16 kTextfile2 = 466; + static const uint16 kTextfile3 = 468; + static const uint16 kBlinkframe = 470; + static const uint16 kBlinkcount = 471; + static const uint16 kReasseschanges = 472; + static const uint16 kPointerspath = 473; + static const uint16 kManspath = 474; + static const uint16 kPointerfirstpath = 475; + static const uint16 kFinaldest = 476; + static const uint16 kDestination = 477; + static const uint16 kLinestartx = 478; + static const uint16 kLinestarty = 480; + static const uint16 kLineendx = 482; + static const uint16 kLineendy = 484; + static const uint16 kIncrement1 = 486; + static const uint16 kIncrement2 = 488; + static const uint16 kLineroutine = 490; + static const uint16 kLinepointer = 491; + static const uint16 kLinedirection = 492; + static const uint16 kLinelength = 493; + static const uint16 kLiftsoundcount = 494; + static const uint16 kEmmhandle = 495; + static const uint16 kEmmpageframe = 497; + static const uint16 kEmmhardwarepage = 499; + static const uint16 kCh0emmpage = 500; + static const uint16 kCh0offset = 502; + static const uint16 kCh0blockstocopy = 504; + static const uint16 kCh0playing = 506; + static const uint16 kCh0repeat = 507; + static const uint16 kCh0oldemmpage = 508; + static const uint16 kCh0oldoffset = 510; + static const uint16 kCh0oldblockstocopy = 512; + static const uint16 kCh1playing = 514; + static const uint16 kCh1emmpage = 515; + static const uint16 kCh1offset = 517; + static const uint16 kCh1blockstocopy = 519; + static const uint16 kCh1blocksplayed = 521; + static const uint16 kSoundbufferwrite = 523; + static const uint16 kSoundemmpage = 525; + static const uint16 kSpeechemmpage = 527; + static const uint16 kCurrentsample = 529; + static const uint16 kRoomssample = 530; + static const uint16 kGameerror = 531; + static const uint16 kHowmuchalloc = 532; + static const uint16 kReelroutines = 534; + static const uint16 kReelcalls = 991; + static const uint16 kRoombyroom = 1214; + static const uint16 kR0 = 1326; + static const uint16 kR1 = 1327; + static const uint16 kR2 = 1331; + static const uint16 kR6 = 1350; + static const uint16 kR8 = 1357; + static const uint16 kR9 = 1373; + static const uint16 kR10 = 1380; + static const uint16 kR11 = 1384; + static const uint16 kR12 = 1388; + static const uint16 kR13 = 1392; + static const uint16 kR14 = 1405; + static const uint16 kR20 = 1439; + static const uint16 kR22 = 1461; + static const uint16 kR23 = 1492; + static const uint16 kR25 = 1505; + static const uint16 kR26 = 1527; + static const uint16 kR27 = 1549; + static const uint16 kR28 = 1574; + static const uint16 kR29 = 1593; + static const uint16 kR45 = 1609; + static const uint16 kR46 = 1616; + static const uint16 kR47 = 1653; + static const uint16 kR52 = 1666; + static const uint16 kR53 = 1670; + static const uint16 kR55 = 1677; + static const uint16 kSpritename1 = 1819; + static const uint16 kSpritename3 = 1832; + static const uint16 kIdname = 1845; + static const uint16 kCharacterset1 = 1857; + static const uint16 kCharacterset2 = 1870; + static const uint16 kCharacterset3 = 1883; + static const uint16 kSamplename = 1896; + static const uint16 kBasicsample = 1909; + static const uint16 kIcongraphics0 = 1922; + static const uint16 kIcongraphics1 = 1935; + static const uint16 kExtragraphics1 = 1948; + static const uint16 kIcongraphics8 = 1961; + static const uint16 kMongraphicname = 1974; + static const uint16 kMongraphics2 = 1987; + static const uint16 kCityname = 2000; + static const uint16 kTravelgraphic1 = 2013; + static const uint16 kTravelgraphic2 = 2026; + static const uint16 kDiarygraphic = 2039; + static const uint16 kMonitorfile1 = 2052; + static const uint16 kMonitorfile2 = 2065; + static const uint16 kMonitorfile10 = 2078; + static const uint16 kMonitorfile11 = 2091; + static const uint16 kMonitorfile12 = 2104; + static const uint16 kMonitorfile13 = 2117; + static const uint16 kMonitorfile20 = 2130; + static const uint16 kMonitorfile21 = 2143; + static const uint16 kMonitorfile22 = 2156; + static const uint16 kMonitorfile23 = 2169; + static const uint16 kMonitorfile24 = 2182; + static const uint16 kFoldertext = 2195; + static const uint16 kDiarytext = 2208; + static const uint16 kPuzzletextname = 2221; + static const uint16 kTraveltextname = 2234; + static const uint16 kIntrotextname = 2247; + static const uint16 kEndtextname = 2260; + static const uint16 kCommandtextname = 2273; + static const uint16 kVolumetabname = 2286; + static const uint16 kFoldergraphic1 = 2299; + static const uint16 kFoldergraphic2 = 2312; + static const uint16 kFoldergraphic3 = 2325; + static const uint16 kSymbolgraphic = 2338; + static const uint16 kGungraphic = 2351; + static const uint16 kMonkface = 2364; + static const uint16 kTitle0graphics = 2377; + static const uint16 kTitle1graphics = 2390; + static const uint16 kTitle2graphics = 2403; + static const uint16 kTitle3graphics = 2416; + static const uint16 kTitle4graphics = 2429; + static const uint16 kTitle5graphics = 2442; + static const uint16 kTitle6graphics = 2455; + static const uint16 kTitle7graphics = 2468; + static const uint16 kPalettescreen = 2481; + static const uint16 kCurrentfile = 2970; + static const uint16 kDmaaddresses = 5118; + static const uint16 kFileheader = 6091; + static const uint16 kFiledata = 6141; + static const uint16 kExtradata = 6181; + static const uint16 kRoomdata = 6187; + static const uint16 kMadeuproomdat = 7979; + static const uint16 kRoomscango = 8011; + static const uint16 kRoompics = 8027; + static const uint16 kOplist = 8042; + static const uint16 kInputline = 8045; + static const uint16 kLinedata = 8173; + static const uint16 kPresslist = 8573; + static const uint16 kSavenames = 8579; + static const uint16 kSavefiles = 8698; + static const uint16 kRecname = 8789; + static const uint16 kQuitrequested = 8802; + static const uint16 kSubtitles = 8803; + static const uint16 kForeignrelease = 8804; + static const uint16 kStak = 8805; + static const uint16 kBlocktextdat = (0); + static const uint16 kPersonframes = (0); + static const uint16 kDebuglevel1 = (0); + static const uint16 kDebuglevel2 = (0); + static const uint16 kPlayback = (0); + static const uint16 kMap = (0); + static const uint16 kSettextdat = (0); + static const uint16 kSpanish = (0); + static const uint16 kFramedata = (0); + static const uint16 kRecording = (0); + static const uint16 kFlags = (0); + static const uint16 kGerman = (0); + static const uint16 kTextunder = (0); + static const uint16 kPathdata = (0); + static const uint16 kDemo = (0); + static const uint16 kExframedata = (0); + static const uint16 kIntextdat = (0); + static const uint16 kFreetextdat = (0); + static const uint16 kFrframedata = (0); + static const uint16 kSettext = (0+(130*2)); + static const uint16 kOpeninvlist = (0+(228*13)); + static const uint16 kRyaninvlist = (0+(228*13)+32); + static const uint16 kPointerback = (0+(228*13)+32+60); + static const uint16 kMapflags = (0+(228*13)+32+60+(32*32)); + static const uint16 kStartpal = (0+(228*13)+32+60+(32*32)+(11*10*3)); + static const uint16 kEndpal = (0+(228*13)+32+60+(32*32)+(11*10*3)+768); + static const uint16 kMaingamepal = (0+(228*13)+32+60+(32*32)+(11*10*3)+768+768); + static const uint16 kSpritetable = (0+(228*13)+32+60+(32*32)+(11*10*3)+768+768+768); + static const uint16 kSetlist = (0+(228*13)+32+60+(32*32)+(11*10*3)+768+768+768+(32*32)); + static const uint16 kFreelist = (0+(228*13)+32+60+(32*32)+(11*10*3)+768+768+768+(32*32)+(128*5)); + static const uint16 kExlist = (0+(228*13)+32+60+(32*32)+(11*10*3)+768+768+768+(32*32)+(128*5)+(80*5)); + static const uint16 kPeoplelist = (0+(228*13)+32+60+(32*32)+(11*10*3)+768+768+768+(32*32)+(128*5)+(80*5)+(100*5)); + static const uint16 kZoomspace = (0+(228*13)+32+60+(32*32)+(11*10*3)+768+768+768+(32*32)+(128*5)+(80*5)+(100*5)+(12*5)); + static const uint16 kPrintedlist = (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)); + static const uint16 kListofchanges = (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)); + static const uint16 kUndertimedtext = (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)); + static const uint16 kRainlist = (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)); + static const uint16 kInitialreelrouts = (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)+(6*64)); + static const uint16 kInitialvars = (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)+(6*64)+991-534); + static const uint16 kLengthofbuffer = (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)+(6*64)+991-534+68-0); + static const uint16 kReellist = (0+(36*144)); + static const uint16 kIntext = (0+(38*2)); + static const uint16 kLengthofmap = (0+(66*60)); + static const uint16 kFreetext = (0+(82*2)); + static const uint16 kBlocktext = (0+(98*2)); + static const uint16 kBlocks = (0+192); + static const uint16 kFrframes = (0+2080); + static const uint16 kExframes = (0+2080); + static const uint16 kFrames = (0+2080); + static const uint16 kExdata = (0+2080+30000); + static const uint16 kExtextdat = (0+2080+30000+(16*114)); + static const uint16 kExtext = (0+2080+30000+(16*114)+((114+2)*2)); + static const uint16 kLengthofextra = (0+2080+30000+(16*114)+((114+2)*2)+18000); + static const uint16 kPersontxtdat = (0+24); + static const uint16 kPersontext = (0+24+(1026*2)); + static const uint16 kInputport = (0x63); + static const uint16 kForeign = (1); + static const uint16 kCd = (1); + static const uint16 kNumexobjects = (114); + static const uint16 kUndertextsizey = (13); + static const uint16 kZoomy = (132); + static const uint16 kFreedatlen = (16*80); + static const uint16 kExtextlen = (18000); + static const uint16 kLenofmapstore = (22*8*20*8); + static const uint16 kUndertextsizex = (228); + static const uint16 kNumchanges = (250); + static const uint16 kUndertimedysize = (30); + static const uint16 kExframeslen = (30000); + static const uint16 kTablesize = (32); + static const uint16 kScreenwidth = (320); + static const uint16 kKeypadx = (36+112); + static const uint16 kItempicsize = (44); + static const uint16 kDiaryy = (48+12); + static const uint16 kOpsy = (52); + static const uint16 kSymboly = (56); + static const uint16 kInventy = (58); + static const uint16 kMenuy = (60); + static const uint16 kOpsx = (60); + static const uint16 kMaplength = (60); + static const uint16 kHeaderlen = (6187-6091); + static const uint16 kSymbolx = (64); + static const uint16 kSetdatlen = (64*128); + static const uint16 kMapwidth = (66); + static const uint16 kTextstart = (66*2); + static const uint16 kMaplen = (66*60); + static const uint16 kDiaryx = (68+24); + static const uint16 kLengthofvars = (68-0); + static const uint16 kKeypady = (72); + static const uint16 kZoomx = (8); + static const uint16 kInventx = (80); + static const uint16 kMenux = (80+40); + static const uint16 kLenofreelrouts = (991-534); void bothchannels(); void usewire(); void getnamepos(); - void drawitall(); + void loadtemptext(); void clearstartpal(); void femalefan(); - void greyscalesum(); - void showgamereel(); + //void showgamereel(); void identifyob(); void trysoundalloc(); void uselighter(); @@ -600,17 +1312,18 @@ public: void startdmablock(); void useopenbox(); void clearbuffers(); + //void getyad(); void neterror(); void storeit(); - void lockeddoorway(); + //void lockeddoorway(); void isitworn(); - void putundertimed(); + //void putundertimed(); void dumpmap(); - void multidump(); + //void multidump(); void channel0only(); void worktoscreenm(); void removeemm(); - void mansatstill(); + //void frameoutbh(); void getobtextstart(); void loadfolder(); void decide(); @@ -620,49 +1333,54 @@ 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 frameoutv(); + void opensarters(); void screenupdate(); - void addlength(); - void usetimedtext(); + //void addlength(); + void wornerror(); void putundercentre(); void checkobjectsize(); - void commandonly(); - void adjustlen(); + //void commandonly(); + void titles(); 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 worktoscreen(); void getexpos(); void fadedos(); - void multiget(); + //void fillspace(); + void selectlocation(); + //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 makename(); void buttonfour(); void animpointer(); - void lockmon(); - void dochange(); + //void lockmon(); + //void dochange(); void getanyaddir(); void showsaveops(); void intromonks1(); @@ -671,26 +1389,26 @@ public: void showdiscops(); void advisor(); void additionaltext(); - void kernchars(); + //void kernchars(); void othersmoker(); - void autosetwalk(); - void setuptimedtemp(); - void blocknametext(); + void dofade(); + //void setuptimedtemp(); + //void blocknametext(); void useelevator5(); void useelevator4(); void useelevator1(); - void attendant(); + //void findormake(); void useelevator3(); 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(); @@ -699,7 +1417,7 @@ public: void slabdoore(); void slabdoord(); void adjustup(); - void readsetdata(); + void slabdoorf(); void loadintotemp(); void loadintroroom(); void saveseg(); @@ -709,41 +1427,40 @@ public: void watchcount(); void fadedownmon(); void loadcart(); - void splitintolines(); + //void calcfrframe(); void bartender(); void eden(); void showdiary(); void purgealocation(); - void updatepeople(); - void slabdoorf(); + //void updatepeople(); void addtopeoplelist(); void hangoncurs(); void sparkydrip(); - void modifychar(); void compare(); void printcurs(); - void convertkey(); + //void convertkey(); void outofopen(); - void dealwithspecial(); + //void dealwithspecial(); + //void eraseoldobs(); void dircom(); - void liftsprite(); + //void liftsprite(); void dumpkeypad(); void dumpzoom(); void endgameseq(); - void cancelch0(); + //void cancelch0(); void setbotleft(); void findfirstpath(); - void showallfree(); + //void cancelch1(); void loadold(); void loadtempcharset(); + void showbyte(); void useslab(); - void aboutturn(); void usealtar(); void createpanel2(); void turnonpower(); void manasleep2(); void moretalk(); - void printslow(); + //void printslow(); void loadroom(); void starttalk(); void delchar(); @@ -751,7 +1468,7 @@ public: void endgame(); void monprint(); void usepipe(); - void startloading(); + //void startloading(); void getunderzoom(); void candles(); void backobject(); @@ -759,7 +1476,7 @@ public: void reminders(); void selectslot2(); void runtap(); - void domix(); + //void domix(); void priesttext(); void paneltomap(); void obname(); @@ -771,13 +1488,12 @@ public: void disablesoundint(); void checkifset(); void showallex(); - void showrain(); void openpoolboss(); void buttontwo(); - void fillopen(); + //void usetimedtext(); void delsprite(); - void getroomspaths(); - void dumptextline(); + //void getroomspaths(); + //void dumptextline(); void fadescreendownhalf(); void useplate(); void candles1(); @@ -786,11 +1502,12 @@ public: void isitdescribed(); void hotelbell(); void loadspeech(); - void cls(); - void printsprites(); - void dumptimedtext(); - void showallobs(); - void getnumber(); + void interupttest(); + //void cls(); + //void printsprites(); + //void checkifperson(); + //void showallobs(); + //void getnumber(); void adjustleft(); void calledenslift(); void useclearbox(); @@ -805,9 +1522,10 @@ public: void showpcx(); void showdecisions(); void checkspeed(); - void printchar(); + //void printchar(); void showkeypad(); void obtoinv(); + //void getroomdata(); void removeobfrominv(); void usecoveredbox(); void openyourneighbour(); @@ -819,58 +1537,56 @@ public: void usekey(); void locklighton(); void useladderb(); - void spriteupdate(); + //void spriteupdate(); void usetempcharset(); void discops(); - void printdirect(); + //void printdirect(); void delthisone(); - void makebackob(); + //void makebackob(); void middlepanel(); void dumpwatch(); void saveload(); void monitorlogo(); void loadposition(); - void wornerror(); void entersymbol(); void showword(); void dirfile(); void setmode(); - void walktotext(); + //void walktotext(); void pickupconts(); void locklightoff(); void wearwatch(); void runintroseq(); - void doblocks(); - void showbyte(); + //void doblocks(); + void restoreall(); void allpalette(); - void findormake(); + void attendant(); void nextsymbol(); void monks2text(); - void poolguard(); void clearpalette(); void cantdrop(); void maptopanel(); - void calcmapad(); + //void calcmapad(); void getridofall(); void copper(); void folderhints(); void openhoteldoor(); - void removesetobject(); - void checkifperson(); - void frameoutfx(); + //void removesetobject(); + //void dumptimedtext(); + //void frameoutfx(); void blank(); void drinker(); void nextcolon(); void placefreeobject(); void delpointer(); - void loopchannel0(); + //void loopchannel0(); void initrain(); void showleftpage(); void rockstar(); void adjustright(); void putunderzoom(); void vsync(); - void turnpathoff(); + //void finishedwalking(); void findinvpos(); void usetext(); void hangonpq(); @@ -893,34 +1609,32 @@ public: void chewy(); void accesslighton(); void dosreturn(); - void titles(); - void quickquit(); + //void adjustlen(); + //void quickquit(); void showpointer(); void usecooker(); void loadmenu(); - void checkforemm(); + //void aboutturn(); void checkifpathison(); - void smallcandle(); + //void finalframe(); void receptionist(); void selectslot(); - void edenscdplayer(); - void readoneblock(); + void openfilenocheck(); + //void readoneblock(); void fadeupmon(); void paltoendpal(); void fadetowhite(); - void textformonk(); void loadsavebox(); - void fadescreenup(); void soundend(); void redes(); void errormessage1(); void clearchanges(); void errormessage3(); - void deletetaken(); + //void deletetaken(); void putundermenu(); void checkifex(); void intromagic2(); - void findobname(); + void mainscreen(); void edeninbath(); void intromagic1(); void showdiarypage(); @@ -928,33 +1642,33 @@ public: void getbacktoops(); void rollendcredits(); void intro1text(); - void getmapad(); + void transfertoex(); void playchannel1(); void playchannel0(); void usemon(); 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(); + //void walking(); void diarykeyp(); - void readabyte(); - void showframe(); + //void readabyte(); + //void showframe(); void random(); void obicons(); - void frameoutbh(); + void mansatstill(); void channel1only(); void playguitar(); void lastfolder(); void transfermap(); - void showreelframe(); + //void showreelframe(); void showmonk(); void diarykeyn(); void set16colpalette(); @@ -965,7 +1679,7 @@ public: void madman(); void createpanel(); void turnpathon(); - void showmainops(); + void enablesoundint(); void madmanstelly(); void constant(); void loadroomssample(); @@ -975,9 +1689,9 @@ public: void getridofpit(); void convnum(); void nothelderror(); - void readheader(); + //void readheader(); void getsetad(); - void getyad(); + void textformonk(); void reconstruct(); void soldier1(); void getundercentre(); @@ -990,6 +1704,7 @@ public: void powerlighton(); void savefilewrite(); void printmessage2(); + //void showallfree(); void loadnews(); void rollem(); void makeworn(); @@ -1009,7 +1724,7 @@ public: void checkbasemem(); void transfertext(); void searchforsame(); - void enablesoundint(); + void showmainops(); void getback1(); void setlocation(); void fadefromwhite(); @@ -1020,9 +1735,9 @@ public: void pitinterupt(); void deleverything(); void fadescreendown(); - void findxyfrompath(); + //void findxyfrompath(); void namestoold(); - void getxad(); + //void getxad(); void openinv(); void lookatplace(); void useaxe(); @@ -1034,30 +1749,29 @@ public: void realcredits(); void handclap(); void smokebloke(); - void showexit(); - void printundermon(); + void afterintroroom(); + //void printundermon(); void buttonnine(); void findallopen(); void loadintotemp3(); void loadintotemp2(); void gamer(); - void personnametext(); - void quitsymbol(); + void poolguard(); void readfromfile(); void initialinv(); - void showslots(); - void dofade(); + void quitsymbol(); + //void modifychar(); void hangon(); void settopright(); void findsetobject(); void singlekey(); - void seecommandtail(); - void getundertimed(); + //void seecommandtail(); + //void getundertimed(); void hangone(); void carparkdrip(); void usediary(); void deleteexobject(); - void frameoutnm(); + //void frameoutnm(); void moneypoke(); void destselect(); void restoreems(); @@ -1067,23 +1781,24 @@ public: void openlouis(); void buttonthree(); void getundermenu(); - void randomnumber(); + //void randomnumber(); void lookatcard(); void helicopter(); void scrollmonitor(); void setsoundoff(); void setpickup(); + //void doorway(); void dropobject(); - void printmessage(); + void isitright(); void reexfromopen(); void fillryan(); - void loadtemptext(); + void drawitall(); void usestereo(); void showcurrentfile(); - void copyname(); + //void copyname(); void look(); void setmouse(); - void checkone(); + //void checkone(); void transferinv(); void candles2(); void pickupob(); @@ -1092,38 +1807,39 @@ public: void clearbeforeload(); void biblequote(); void doload(); - void afterintroroom(); + void showexit(); void blockget(); void usetrainer(); - void allocatework(); + //void allocatework(); void addtopresslist(); void walkandexamine(); void dmaend(); - void quickquit2(); + //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(); + //void personnametext(); void louischair(); void saveems(); void locationpic(); @@ -1131,25 +1847,24 @@ public: void dolook(); void opentvdoor(); void triggermessage(); - void finalframe(); - void plotreel(); + void smallcandle(); + //void plotreel(); void swapwithopen(); - void makesprite(); + //void makesprite(); void dreamweb(); void droperror(); - void openfilenocheck(); + void edenscdplayer(); void calledensdlift(); void checkinside(); void gates(); - void selectlocation(); + void newgame(); void showwatch(); void turnanypathon(); void restorereels(); void setwalk(); - void printboth(); void useroutine(); void zoomicon(); - void hotelcontrol(); + //void findlen(); void findpathofpoint(); void issetobonmap(); void getdestinfo(); @@ -1159,16 +1874,16 @@ public: void grafittidoor(); void input(); void nextdest(); - void getdimension(); + //void getdimension(); void makecaps(); void read(); void fadescreenups(); - void checkdest(); - void initman(); + //void checkdest(); + //void initman(); void loadpalfromiff(); - void facerightway(); + //void facerightway(); void startup1(); - void findlen(); + void hotelcontrol(); void showsymbol(); void mugger(); void atmospheres(); @@ -1177,12 +1892,12 @@ public: void gettingshot(); void settopleft(); void searchforstring(); - void clearsprites(); + //void clearsprites(); void obpicture(); void selectopenob(); - void widedoor(); + //void widedoor(); void security(); - void printasprite(); + //void printasprite(); void buttonfive(); void soundonreels(); void usegun(); @@ -1191,28 +1906,26 @@ public: void readmouse4(); void openryan(); void readmouse1(); - void showman(); + void readmouse3(); void readmouse2(); void newplace(); - void movemap(); + //void movemap(); void loadsample(); void usecardreader1(); void usecardreader2(); void usecardreader3(); void tattooman(); void usehandle(); - void quitkey(); void openfile(); void usecharset1(); - void makenextblock(); + //void makenextblock(); void showpuztext(); - void addalong(); - void width160(); + //void addalong(); + //void width160(); void incryanpage(); - void dodoor(); - void eraseoldobs(); + //void dodoor(); + void greyscalesum(); void buttoneight(); - void opensarters(); void findexobject(); void errormessage2(); void usechurchhole(); @@ -1221,7 +1934,7 @@ public: void fadecalculation(); void waitframes(); void clearrest(); - void getreelframeax(); + //void getreelframeax(); void barwoman(); void roomname(); void credits(); @@ -1235,13 +1948,13 @@ public: void closefile(); void delcurs(); void randomaccess(); - void calcfrframe(); + void splitintolines(); void intromagic3(); void initialmoncols(); void checkforshake(); void usebuttona(); - void cancelch1(); - void getnextword(); + void fadescreenup(); + //void getnextword(); void generalerror(); void actualload(); void allocateload(); @@ -1259,24 +1972,24 @@ public: void usecontrol(); void buttonseven(); void redrawmainscrn(); - void finishedwalking(); + void turnpathoff(); void findallryan(); - void channel0tran(); + //void channel0tran(); void buttonpress(); - void parseblaster(); + //void parseblaster(); void callhotellift(); void makemainscreen(); void intromonks2(); void usewinch(); void setbotright(); - void readmouse3(); + void showman(); void showfirstuse(); void setupemm(); void usefullcart(); - void transfertoex(); + //void getmapad(); void getlocation(); void geteitherad(); - void placesetobject(); + //void placesetobject(); void drawflags(); void zoomonoff(); void updatesymboltop(); @@ -1297,12 +2010,12 @@ public: void intro(); void hangonp(); void fadescreendowns(); - void showloadops(); + void openhoteldoor2(); void getridoftempsp(); void scanfornames(); - void setallchanges(); - void newgame(); - void examinventory(); + //void setallchanges(); + void readsetdata(); + //void printboth(); void standardload(); void undertextline(); void findroominloc(); @@ -1315,18 +2028,18 @@ public: void dosometalk(); void usecart(); void intromusic(); - void makename(); + void quitkey(); void processtrigger(); void monmessage(); void readdesticon(); void randomnum2(); void loadsecondsample(); void transfercontoex(); - void multiput(); - void isitright(); + //void multiput(); + void printmessage(); void businessman(); void switchryanoff(); - void commandwithob(); + //void commandwithob(); void panelicons1(); void adjustdown(); void withwhat(); @@ -1338,7 +2051,7 @@ public: void useobject(); void mainman(); void volumeadjust(); - void checkiffree(); + //void checkiffree(); }; } diff --git a/engines/dreamweb/dreamweb.cpp b/engines/dreamweb/dreamweb.cpp index eebadfddae..19d1d84a51 100644 --- a/engines/dreamweb/dreamweb.cpp +++ b/engines/dreamweb/dreamweb.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL: https://svn.scummvm.org:4444/svn/dreamweb/dreamweb.cpp $ - * $Id: dreamweb.cpp 79 2011-06-05 08:26:54Z eriktorbjorn $ - * */ #include "common/config-manager.h" @@ -113,14 +110,6 @@ void DreamWebEngine::processEvents() { return; } - if (_enableSavingOrLoading && _loadSavefile >= 0 && _loadSavefile <= 6) { - debug(1, "loading save state %d", _loadSavefile); - _context.data.byte(_context.kCurrentslot) = _loadSavefile; - _loadSavefile = -1; - _context.loadposition(); - _context.data.byte(_context.kGetback) = 1; - } - soundHandler(); Common::Event event; int softKey, hardKey; @@ -219,9 +208,9 @@ Common::Error DreamWebEngine::run() { syncSoundSettings(); _console = new DreamWebConsole(this); - _loadSavefile = Common::ConfigManager::instance().getInt("save_slot"); + ConfMan.registerDefault("dreamweb_originalsaveload", "true"); - getTimerManager()->installTimerProc(vSyncInterrupt, 1000000 / 70, this); + getTimerManager()->installTimerProc(vSyncInterrupt, 1000000 / 70, this, "dreamwebVSync"); _context.__start(); _context.data.byte(DreamGen::DreamGenContext::kQuitrequested) = 0; @@ -234,7 +223,7 @@ void DreamWebEngine::setSpeed(uint speed) { debug(0, "setting speed %u", speed); _speed = speed; getTimerManager()->removeTimerProc(vSyncInterrupt); - getTimerManager()->installTimerProc(vSyncInterrupt, 1000000 / 70 / speed, this); + getTimerManager()->installTimerProc(vSyncInterrupt, 1000000 / 70 / speed, this, "dreamwebVSync"); } void DreamWebEngine::openFile(const Common::String &name) { @@ -474,6 +463,16 @@ void DreamWebEngine::playSound(uint8 channel, uint8 id, uint8 loops) { _mixer->playStream(type, &_channelHandle[channel], stream); } +void DreamWebEngine::stopSound(uint8 channel) { + debug(1, "stopSound(%u)", channel); + assert(channel == 0 || channel == 1); + _mixer->stopHandle(_channelHandle[channel]); + if (channel == 0) + _channel0 = 0; + else + _channel1 = 0; +} + bool DreamWebEngine::loadSpeech(const Common::String &filename) { if (ConfMan.getBool("speech_mute")) return false; @@ -591,7 +590,7 @@ uint8 DreamWebEngine::modifyChar(uint8 c) const { return 'Z' + 4; case 154: return 'Z' + 6; - case 255: + case 225: return 'A' - 1; case 153: return 'Z' + 5; @@ -631,5 +630,3 @@ uint8 DreamWebEngine::modifyChar(uint8 c) const { } } // End of namespace DreamWeb - - diff --git a/engines/dreamweb/dreamweb.h b/engines/dreamweb/dreamweb.h index 7323cfe836..a7de64a350 100644 --- a/engines/dreamweb/dreamweb.h +++ b/engines/dreamweb/dreamweb.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL: https://svn.scummvm.org:4444/svn/dreamweb/dreamweb.h $ - * $Id: dreamweb.h 77 2011-05-18 14:26:43Z digitall $ - * */ #ifndef DREAMWEB_H @@ -114,6 +111,8 @@ public: Common::Language getLanguage() const { return _language; } uint8 modifyChar(uint8 c) const; + void stopSound(uint8 channel); + private: void keyPressed(uint16 ascii); void setSpeed(uint speed); @@ -130,7 +129,6 @@ private: uint _speed; bool _turbo; uint _oldMouseState; - int _loadSavefile; bool _enableSavingOrLoading; Common::Language _language; diff --git a/engines/dreamweb/module.mk b/engines/dreamweb/module.mk index 3b0c7f3325..bdacbe79f3 100644 --- a/engines/dreamweb/module.mk +++ b/engines/dreamweb/module.mk @@ -1,11 +1,17 @@ MODULE := engines/dreamweb MODULE_OBJS := \ + backdrop.o \ console.o \ detection.o \ dreamweb.o \ dreamgen.o \ - stubs.o + pathfind.o \ + print.o \ + saveload.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/pathfind.cpp b/engines/dreamweb/pathfind.cpp new file mode 100644 index 0000000000..2579105c6f --- /dev/null +++ b/engines/dreamweb/pathfind.cpp @@ -0,0 +1,106 @@ +/* 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" +#include "common/config-manager.h" + +namespace DreamGen { + +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::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::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; + } + 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; + } + data.byte(kDestination) = destination; +} + +void DreamGenContext::findxyfrompath() { + const uint8 *roomsPaths = getroomspathsCPP(); + data.byte(kRyanx) = roomsPaths[data.byte(kManspath) * 8 + 0] - 12; + data.byte(kRyany) = roomsPaths[data.byte(kManspath) * 8 + 1] - 12; +} + +} /*namespace dreamgen */ + 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 a97ea2cf3d..8aa71b285c 100644 --- a/engines/dreamweb/runtime.h +++ b/engines/dreamweb/runtime.h @@ -1,5 +1,27 @@ -#ifndef ENGINES_DREAMGEN_RUNTIME_H__ -#define ENGINES_DREAMGEN_RUNTIME_H__ +/* 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 DREAMGEN_RUNTIME_H__ +#define DREAMGEN_RUNTIME_H__ #include <assert.h> #include "common/scummsys.h" @@ -111,7 +133,7 @@ struct Segment { return WordRef(data, index); } - inline uint8* ptr(unsigned index, unsigned size) { + inline uint8 *ptr(unsigned index, unsigned size) { assert(index + size <= data.size()); return data.begin() + index; } @@ -164,7 +186,7 @@ public: _segment->assign(b, e); } - inline uint8* ptr(unsigned index, unsigned size) { + inline uint8 *ptr(unsigned index, unsigned size) { assert(_segment != 0); return _segment->ptr(index, size); } @@ -265,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); } @@ -465,7 +493,7 @@ public: inline void _movsb(uint size, bool clear_cx = false) { assert(size != 0xffff); //fixme: add overlap and segment boundary check and rewrite - while(size--) + while (size--) _movsb(); if (clear_cx) cx = 0; @@ -503,7 +531,7 @@ public: assert(size != 0xffff); uint8 *dst = es.ptr(di, size * 2); di += 2 * size; - while(size--) { + while (size--) { *dst++ = al; *dst++ = ah; } @@ -558,4 +586,3 @@ public: } #endif - diff --git a/engines/dreamweb/saveload.cpp b/engines/dreamweb/saveload.cpp new file mode 100644 index 0000000000..636182dc83 --- /dev/null +++ b/engines/dreamweb/saveload.cpp @@ -0,0 +1,343 @@ +/* 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/metaengine.h" +#include "gui/saveload.h" +#include "common/config-manager.h" +#include "common/translation.h" + +namespace DreamGen { + +void DreamGenContext::loadgame() { + STACK_CHECK; + if (data.byte(kCommandtype) != 246) { + data.byte(kCommandtype) = 246; + al = 41; + commandonly(); + } + if (data.word(kMousebutton) == data.word(kOldbutton)) + return; // "noload" + if (data.word(kMousebutton) == 1) { + ax = 0xFFFF; + doload(); + } +} + +// input: ax = savegameId +// if -1, open menu to ask for slot to load +// if >= 0, directly load from that slot +void DreamGenContext::doload() { + STACK_CHECK; + int savegameId = (int16)ax; + + data.byte(kLoadingorsave) = 1; + + if (ConfMan.getBool("dreamweb_originalsaveload") && savegameId == -1) { + showopbox(); + showloadops(); + data.byte(kCurrentslot) = 0; + showslots(); + shownames(); + data.byte(kPointerframe) = 0; + worktoscreenm(); + namestoold(); + data.byte(kGetback) = 0; + + while (true) { + if (data.byte(kQuitrequested)) + return; // "quitloaded" + delpointer(); + readmouse(); + showpointer(); + vsync(); + dumppointer(); + dumptextline(); + bx = offset_loadlist; + checkcoords(); + if (data.byte(kGetback) == 1) + break; + if (data.byte(kGetback) == 2) + return; // "quitloaded" + } + } else { + + if (savegameId == -1) { + // Open dialog to get savegameId + + const EnginePlugin *plugin = NULL; + Common::String gameId = ConfMan.get("gameid"); + EngineMan.findGame(gameId, &plugin); + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore")); + dialog->setSaveMode(false); + savegameId = dialog->runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName()); + delete dialog; + } + + if (savegameId < 0) { + data.byte(kGetback) = 0; + return; + } + + + // TODO: proper scheme for filename, in a separate function + //Common::String filename = ConfMan.getActiveDomainName() + Common::String::format(".d%02d", savegameId); + Common::String filename = Common::String::format("DREAMWEB.D%02d", savegameId); + debug(1, "Loading from filename: %s", filename.c_str()); + engine->openSaveFileForReading(filename); + + // TODO: The below is duplicated from Loadposition + data.word(kTimecount) = 0; + clearchanges(); + + ds = cs; + dx = kFileheader; + cx = kHeaderlen; + savefileread(); + es = cs; + di = kFiledata; + ax = savegameId; + if (savegameId < 7) { + cx = 17; + _mul(cx); + ds = data; + dx = kSavenames; + _add(dx, ax); + loadseg(); + } else { + // For potential support of more than 7 savegame slots, + // loading into the savenames buffer isn't always possible + // Emulate a loadseg call: + uint8 namebuf[17]; + engine->readFromFile(namebuf, 17); + _add(di, 2); + } + ds = data; + dx = kStartvars; + loadseg(); + ds = data.word(kExtras); + dx = kExframedata; + loadseg(); + ds = data.word(kBuffers); + dx = kListofchanges; + loadseg(); + ds = data; + dx = kMadeuproomdat; + loadseg(); + ds = cs; + dx = kReelroutines; + loadseg(); + closefile(); + data.byte(kGetback) = 1; + } + + // kTempgraphics might not have been allocated if we bypassed all menus + if (data.word(kTempgraphics) != 0xFFFF) + getridoftemp(); + + dx = data; + es = dx; + bx = kMadeuproomdat; + startloading(); + loadroomssample(); + data.byte(kRoomloaded) = 1; + data.byte(kNewlocation) = 255; + clearsprites(); + initman(); + initrain(); + data.word(kTextaddressx) = 13; + data.word(kTextaddressy) = 182; + data.byte(kTextlen) = 240; + startup(); + worktoscreen(); + data.byte(kGetback) = 4; +} + + +void DreamGenContext::savegame() { + STACK_CHECK; + if (data.byte(kMandead) == 2) { + blank(); + return; + } + + if (data.byte(kCommandtype) != 247) { + data.byte(kCommandtype) = 247; + al = 44; + commandonly(); + } + if (data.word(kMousebutton) != 1) + return; + + data.byte(kLoadingorsave) = 2; + + if (ConfMan.getBool("dreamweb_originalsaveload")) { + showopbox(); + showsaveops(); + data.byte(kCurrentslot) = 0; + showslots(); + shownames(); + worktoscreenm(); + namestoold(); + data.word(kBufferin) = 0; + data.word(kBufferout) = 0; + data.byte(kGetback) = 0; + + while (true) { + _cmp(data.byte(kQuitrequested), 0); + if (!flags.z()) + return /* (quitsavegame) */; + delpointer(); + checkinput(); + readmouse(); + showpointer(); + vsync(); + dumppointer(); + dumptextline(); + bx = offset_savelist; + checkcoords(); + _cmp(data.byte(kGetback), 0); + if (flags.z()) + continue; + break; + } + return; + } else { + const EnginePlugin *plugin = NULL; + Common::String gameId = ConfMan.get("gameid"); + EngineMan.findGame(gameId, &plugin); + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save")); + dialog->setSaveMode(true); + int savegameId = dialog->runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName()); + Common::String game_description = dialog->getResultString(); + if (game_description.empty()) + game_description = "Untitled"; + delete dialog; + + if (savegameId < 0) { + data.byte(kGetback) = 0; + return; + } + + // TODO: The below is copied from actualsave + al = data.byte(kLocation); + ah = 0; + cx = 32; + _mul(cx); + ds = cs; + si = kRoomdata; + _add(si, ax); + di = kMadeuproomdat; + bx = di; + es = cs; + cx = 16; + _movsw(cx, true); + al = data.byte(kRoomssample); + es.byte(bx+13) = al; + al = data.byte(kMapx); + es.byte(bx+15) = al; + al = data.byte(kMapy); + es.byte(bx+16) = al; + al = data.byte(kLiftflag); + es.byte(bx+20) = al; + al = data.byte(kManspath); + es.byte(bx+21) = al; + al = data.byte(kFacing); + es.byte(bx+22) = al; + al = 255; + es.byte(bx+27) = al; + + // TODO: The below is copied from saveposition + makeheader(); + + //Common::String filename = ConfMan.getActiveDomainName() + Common::String::format(".d%02d", savegameId); + Common::String filename = Common::String::format("DREAMWEB.D%02d", savegameId); + debug(1, "Saving to filename: %s (%s)", filename.c_str(), game_description.c_str()); + + engine->openSaveFileForWriting(filename.c_str()); + + dx = data; + ds = dx; + dx = kFileheader; + cx = kHeaderlen; + savefilewrite(); + dx = data; + es = dx; + di = kFiledata; + + // TODO: Check if this 2 is a constant + uint8 descbuf[17] = { 2, 0 }; + strncpy((char*)descbuf+1, game_description.c_str(), 16); + unsigned int desclen = game_description.size(); + if (desclen > 15) + desclen = 15; + // zero terminate, and pad with ones + descbuf[++desclen] = 0; + while (desclen < 17) + descbuf[++desclen] = 1; + if (savegameId < 7) { + ax = savegameId; + cx = 17; + _mul(cx); + ds = data; + dx = kSavenames; + _add(dx, ax); + memcpy(data.ptr(dx,17), descbuf, 17); + saveseg(); + } else { + // savenames only has room for descriptions for 7 slots + uint16 len = es.word(di); + _add(di, 2); + assert(len == 17); + engine->writeToSaveFile(descbuf, len); + } + + ds = data; + dx = kStartvars; + saveseg(); + ds = data.word(kExtras); + dx = kExframedata; + saveseg(); + ds = data.word(kBuffers); + dx = kListofchanges; + saveseg(); + ds = data; + dx = kMadeuproomdat; + saveseg(); + ds = data; + dx = kReelroutines; + saveseg(); + closefile(); + + getridoftemp(); + restoreall(); + data.word(kTextaddressx) = 13; + data.word(kTextaddressy) = 182; + data.byte(kTextlen) = 240; + redrawmainscrn(); + worktoscreenm(); + data.byte(kGetback) = 4; + } +} + + +} /*namespace dreamgen */ diff --git a/engines/dreamweb/sprite.cpp b/engines/dreamweb/sprite.cpp new file mode 100644 index 0000000000..e9a40d7f8c --- /dev/null +++ b/engines/dreamweb/sprite.cpp @@ -0,0 +1,893 @@ +/* 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; + showframe((const Frame *)segRef(sprite->frameData()).ptr(0, 0), x, y, sprite->b15, c); +} + +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); + showframe(source, x, y, frame, 8); +} + +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; + Frame *source = findsourceCPP(); + uint16 offset = data.word(kCurrentframe) - data.word(kTakeoff); + return source + 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; +} + +void DreamGenContext::checkone() { + uint8 flag, flagEx, type, flagX, flagY; + checkone(cl, ch, &flag, &flagEx, &type, &flagX, &flagY); + + cl = flag; + ch = flagEx; + dl = flagX; + dh = flagY; + al = type; +} + +void DreamGenContext::checkone(uint8 x, uint8 y, uint8 *flag, uint8 *flagEx, uint8 *type, uint8 *flagX, uint8 *flagY) { + *flagX = x / 16; + *flagY = y / 16; + const uint8 *tileData = segRef(data.word(kBuffers)).ptr(kMapflags + (*flagY * 11 + *flagX) * 3, 3); + *flag = tileData[0]; + *flagEx = tileData[1]; + *type = tileData[2]; +} + +} /*namespace dreamgen */ + diff --git a/engines/dreamweb/structs.h b/engines/dreamweb/structs.h new file mode 100644 index 0000000000..7e77bdf0e9 --- /dev/null +++ b/engines/dreamweb/structs.h @@ -0,0 +1,220 @@ +/* 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/endian.h" + +struct Sprite { + uint16 _updateCallback; + uint16 updateCallback() const { return READ_LE_UINT16(&_updateCallback); } + void setUpdateCallback(uint16 v) { WRITE_LE_UINT16(&_updateCallback, v); } + uint16 w2; + uint16 w4; + 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; + uint8 b16; + uint8 b17; + uint8 delay; + uint8 frame; + 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; + uint16 w26; + uint8 b28; + uint8 b29; + uint8 type; + uint8 hidden; +}; + +struct ObjData { + uint8 b0; + uint8 b1; + uint8 b2; + uint8 b3; + uint8 b4; + uint8 priority; + uint8 b6; + uint8 delay; + uint8 type; + uint8 b9; + uint8 b10; + uint8 b11; + uint8 name[4]; + uint8 b16; + uint8 b17; + uint8 b18[13]; // NB: Don't know the size yet + uint8 b31; + uint8 b32; + uint8 b33; + uint8 b34; + uint8 b35; + uint8 b36; + uint8 b37; + uint8 b38; + uint8 b39; + uint8 b40; + uint8 b41; + uint8 b42; + uint8 b43; + uint8 b44; + uint8 b45; + uint8 b46; + uint8 b47; + uint8 b48; + uint8 b49; + uint8 b50; + uint8 b51; + uint8 b52; + uint8 b53; + uint8 b54; + uint8 b55; + uint8 b56; + uint8 b57; + uint8 b58[5]; + uint8 b63; +}; + +struct FreeObject { + uint8 b0; + uint8 b1; + uint8 b2; + uint8 b3; + uint8 b4; + uint8 b5; + uint8 b6; + uint8 b7; + uint8 b8; + uint8 b9; + uint8 b10; + uint8 b11; + uint8 b12; + uint8 b13; + uint8 b14; + uint8 b15; +}; + +struct ObjPos { + uint8 xMin; + uint8 yMin; + uint8 xMax; + uint8 yMax; + uint8 index; +}; + +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; +}; + +struct Change { + uint8 index; + uint8 location; + uint8 value; + uint8 type; +}; + + diff --git a/engines/dreamweb/stubs.cpp b/engines/dreamweb/stubs.cpp index 5614aa391a..f0938ea30b 100644 --- a/engines/dreamweb/stubs.cpp +++ b/engines/dreamweb/stubs.cpp @@ -1,103 +1,204 @@ +/* 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" +#include "common/config-manager.h" namespace DreamGen { -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::dreamweb() { + STACK_CHECK; + seecommandtail(); + checkbasemem(); + soundstartup(); + setkeyboardint(); + setupemm(); + allocatebuffers(); + setmouse(); + fadedos(); + gettime(); + clearbuffers(); + clearpalette(); + set16colpalette(); + readsetdata(); + data.byte(kWongame) = 0; -void DreamGenContext::multiget() { - unsigned w = (uint8)cl, h = (uint8)ch; - unsigned x = (uint16)di, y = (uint16)bx; - 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; -} + dx = 1909; + loadsample(); + setsoundoff(); -void DreamGenContext::multiput() { - unsigned w = (uint8)cl, h = (uint8)ch; - unsigned x = (uint16)di, y = (uint16)bx; - 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; -} + bool firstLoop = true; -void DreamGenContext::multidump() { - ds = data.word(kWorkspace); - int w = (uint8)cl, h = (uint8)ch; - int x = (int16)di, y = (int16)bx; - 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, w * h), kScreenwidth, x, y, w, h); - si = di = offset + h * kScreenwidth; - cx = 0; -} + int savegameId = Common::ConfigManager::instance().getInt("save_slot"); -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; -} + while (true) { -void DreamGenContext::printundermon() { - engine->printUnderMonitor(); -} + scanfornames(); -void DreamGenContext::cls() { - engine->cls(); -} + bool startNewGame = true; + + if (firstLoop && savegameId >= 0) { + + // loading a savegame requested from launcher/command line + + cls(); + setmode(); + loadpalfromiff(); + clearpalette(); + + ax = savegameId; + doload(); + worktoscreen(); + fadescreenup(); + startNewGame = false; + + } else if (al == 0 && firstLoop) { + + // no savegames found, and we're not restarting. + + setmode(); + loadpalfromiff(); + + } else { + // "dodecisions" + + // Savegames found, so ask if we should load one. + // (If we're restarting after game over, we also always show these + // options.) + + cls(); + setmode(); + decide(); + if (data.byte(kQuitrequested)) + return; // exit game + + if (data.byte(kGetback) == 4) + startNewGame = false; // savegame has been loaded + + } + + firstLoop = false; + + if (startNewGame) { + // "playgame" + + titles(); + if (data.byte(kQuitrequested)) + return; // exit game + credits(); + + if (data.byte(kQuitrequested)) + return; // exit game + + clearchanges(); + setmode(); + loadpalfromiff(); + data.byte(kLocation) = 255; + data.byte(kRoomafterdream) = 1; + data.byte(kNewlocation) = 35; + data.byte(kVolume) = 7; + loadroom(); + clearsprites(); + initman(); + entrytexts(); + entryanims(); + data.byte(kDestpos) = 3; + initialinv(); + data.byte(kLastflag) = 32; + startup1(); + data.byte(kVolumeto) = 0; + data.byte(kVolumedirection) = -1; + data.byte(kCommandtype) = 255; + + } + + // main loop + while (true) { + + if (data.byte(kQuitrequested)) + return; // exit game + + screenupdate(); + + if (data.byte(kWongame) != 0) { + // "endofgame" + clearbeforeload(); + fadescreendowns(); + cx = 200; + hangon(); + endgame(); + quickquit2(); + return; + } + + if (data.byte(kMandead) == 1 || data.byte(kMandead) == 2) + break; + + if (data.word(kWatchingtime) > 0) { + if (data.byte(kFinaldest) == data.byte(kManspath)) + data.word(kWatchingtime)--; + } + + if (data.word(kWatchingtime) == 0) { + // "notwatching" + + if (data.byte(kMandead) == 4) + break; + + if (data.byte(kNewlocation) != 255) { + // "loadnew" + clearbeforeload(); + loadroom(); + clearsprites(); + initman(); + entrytexts(); + entryanims(); + data.byte(kNewlocation) = 255; + startup(); + data.byte(kCommandtype) = 255; + worktoscreenm(); + } + } + } + + // "gameover" + clearbeforeload(); + showgun(); + fadescreendown(); + cx = 100; + hangon(); -void DreamGenContext::frameoutnm() { - unsigned w = (uint8)cl, h = (uint8)ch; - unsigned pitch = (uint16)dx; - unsigned src = (uint16)si; - int x = (uint16)di, y = (uint16)bx; - unsigned dst = x + y * pitch; - //debug(1, "framenm %ux%u[pitch: %u]-> %d,%d, segment: %04x->%04x", w, h, pitch, x, y, (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 + pitch * l, w); - memcpy(dst_p, src_p, w); } - di += dst + pitch * h; - si += w * h; - cx = 0; +} + +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::seecommandtail() { @@ -191,6 +292,110 @@ void DreamGenContext::setmouse() { data.word(kOldpointerx) = 0xffff; } +void DreamGenContext::dumptextline() { + if (data.byte(kNewtextline) != 1) + return; + data.byte(kNewtextline) = 0; + uint16 x = data.word(kTextaddressx); + uint16 y = data.word(kTextaddressy); + if (data.byte(kForeignrelease) != 0) + y -= 3; + multidump(x, y, 228, 13); +} + +void DreamGenContext::getundertimed() { + uint16 y = data.byte(kTimedy); + if (data.byte(kForeignrelease)) + y -= 3; + ds = data.word(kBuffers); + si = kUndertimedtext; + multiget(ds.ptr(si, 0), data.byte(kTimedx), y, 240, kUndertimedysize); +} + +void DreamGenContext::putundertimed() { + uint16 y = data.byte(kTimedy); + if (data.byte(kForeignrelease)) + y -= 3; + ds = data.word(kBuffers); + si = kUndertimedtext; + multiput(ds.ptr(si, 0), data.byte(kTimedx), y, 240, kUndertimedysize); +} + +void DreamGenContext::usetimedtext() { + if (data.word(kTimecount) == 0) + return; + --data.word(kTimecount); + if (data.word(kTimecount) == 0) { + putundertimed(); + data.byte(kNeedtodumptimed) = 1; + return; + } + + if (data.word(kTimecount) == data.word(kCounttotimed)) + getundertimed(); + else if (data.word(kTimecount) > data.word(kCounttotimed)) + return; + + es = data.word(kTimedseg); + si = data.word(kTimedoffset); + const uint8 *string = es.ptr(si, 0); + uint16 y = data.byte(kTimedy); + printdirect(&string, data.byte(kTimedx), &y, 237, true); + data.byte(kNeedtodumptimed) = 1; +} + +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(); + } + dx = pop(); + cx = pop(); + bx = pop(); + ax = pop(); + if ((data.byte(kSpeechloaded) == 1) && (data.byte(kSubtitles) != 1)) + return; + } +#endif + + 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; + + multidump(data.byte(kTimedx), y, 240, kUndertimedysize); + data.byte(kNeedtodumptimed) = 0; +} + void DreamGenContext::gettime() { TimeDate t; g_system->getTimeAndDate(t); @@ -204,12 +409,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() { @@ -384,8 +594,6 @@ void DreamGenContext::dosreturn() { } void DreamGenContext::set16colpalette() { - //fixme: this is a bit hackish, set16colpalette called after initialization and nearly before main loop. - engine->enableSavingOrLoading(); } void DreamGenContext::mode640x480() { @@ -403,155 +611,564 @@ void DreamGenContext::fadedos() { engine->fadeDos(); } -void DreamGenContext::doshake() { - uint8 &counter = data.byte(kShakecounter); - _cmp(counter, 48); - if (flags.z()) +void DreamGenContext::eraseoldobs() { + if (data.byte(kNewobs) == 0) 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, + Sprite *sprites = spritetable(); + for (size_t i=0; i < 16; ++i) { + Sprite &sprite = sprites[i]; + if (sprite.objData() != 0xffff) { + memset(&sprite, 0xff, sizeof(Sprite)); + } + } +} + +void DreamGenContext::modifychar() { + al = engine->modifyChar(al); +} - 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, +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(); + } +} - 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, +void DreamGenContext::cancelch0() { + data.byte(kCh0repeat) = 0; + data.word(kCh0blockstocopy) = 0; + data.byte(kCh0playing) = 255; + engine->stopSound(0); +} - 0, -2, 3, -2, 0, 2, 4, -1, - 1, -3, 3, 0, - }; - int offset = shakeTable[counter]; - engine->setShakePos(offset >= 0? offset: -offset); +void DreamGenContext::cancelch1() { + data.word(kCh1blockstocopy) = 0; + data.byte(kCh1playing) = 255; + engine->stopSound(1); } -void DreamGenContext::vsync() { +void DreamGenContext::makebackob(ObjData *objData) { + if (data.byte(kNewobs) == 0) + return; + uint8 priority = objData->priority; + uint8 type = objData->type; + Sprite *sprite = makesprite(data.word(kObjectx), data.word(kObjecty), addr_backobject, data.word(kSetframes), 0); + + uint16 objDataOffset = (uint8 *)objData - segRef(data.word(kSetdat)).ptr(0, 0); + assert(objDataOffset % sizeof(ObjData) == 0); + assert(objDataOffset < 128 * sizeof(ObjData)); + sprite->setObjData(objDataOffset); + if (priority == 255) + priority = 0; + sprite->priority = priority; + sprite->type = type; + sprite->b16 = 0; + sprite->delay = 0; + sprite->frame = 0; +} + +void DreamGenContext::getroomdata() { + bx = kRoomdata + sizeof(Room) * al; +} + +void DreamGenContext::getroomdata(uint8 roomIndex) { + getroomdata(roomIndex); +} + +void DreamGenContext::startloading() { + const Room *room = (Room *)cs.ptr(bx, sizeof(Room)); + startloading(room); +} + +void DreamGenContext::readheader() { + ax = engine->readFromFile(cs.ptr(kFileheader, kHeaderlen), kHeaderlen); + es = cs; + di = kFiledata; +} + +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); - 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(); + 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(); + } + findxyfrompath(); } -void DreamGenContext::setmode() { - vsync(); - initGraphics(320, 200, false); +void DreamGenContext::fillspace() { + memset(ds.ptr(dx, cx), al, cx); } -void DreamGenContext::showpcx() { - Common::String name = getFilename(*this); - Common::File pcxFile; +void DreamGenContext::dealwithspecial(uint8 firstParam, uint8 secondParam) { + uint8 type = firstParam - 220; + if (type == 0) { + placesetobject(secondParam); + data.byte(kHavedoneobs) = 1; + } else if (type == 1) { + removesetobject(secondParam); + 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 { + movemap(secondParam); + } +} - if (!pcxFile.open(name)) { - warning("showpcx: Could not open '%s'", name.c_str()); - 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; } - uint8 *maingamepal; - int i, j; + for (size_t i = 0; i < 8; ++i) { + if (reel->frame() != 0xffff) + showreelframe(reel); + ++reel; + } + soundonreels(); +} - // Read the 16-color palette into the 'maingamepal' buffer. Note that - // the color components have to be adjusted from 8 to 6 bits. +void DreamGenContext::crosshair() { + uint8 frame; + if ((data.byte(kCommandtype) != 3) && (data.byte(kCommandtype) < 10)) { + frame = 9; + } else { + frame = 29; + } + const Frame *src = (const Frame *)segRef(data.word(kIcons1)).ptr(0, 0); + showframe(src, kZoomx + 24, kZoomy + 19, frame, 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); +} - pcxFile.seek(16, SEEK_SET); - es = data.word(kBuffers); - maingamepal = es.ptr(kMaingamepal, 768); - pcxFile.read(maingamepal, 48); +void DreamGenContext::commandonly() { + commandonly(al); +} + +void DreamGenContext::commandonly(uint8 command) { + deltextline(); + uint16 index = command * 2; + uint16 offset = kTextstart + segRef(data.word(kCommandtext)).word(index); + uint16 y = data.word(kTextaddressy); + const uint8 *string = segRef(data.word(kCommandtext)).ptr(offset, 0); + printdirect(&string, data.word(kTextaddressx), &y, data.byte(kTextlen), (bool)(data.byte(kTextlen) & 1)); + data.byte(kNewtextline) = 1; +} - memset(maingamepal + 48, 0xff, 720); - for (i = 0; i < 48; i++) { - maingamepal[i] >>= 2; +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; } + return false; +} - // Decode the image data. +void DreamGenContext::checkiffree() { + flags._z = not checkiffree(al, ah); +} - Graphics::Surface *s = g_system->lockScreen(); - Common::Rect rect(640, 480); +bool DreamGenContext::checkiffree(uint8 x, uint8 y) { + const ObjPos *freeList = (const ObjPos *)segRef(data.word(kBuffers)).ptr(kFreelist, 80 * sizeof(ObjPos)); + for (size_t i = 0; i < 80; ++i) { + const ObjPos *objPos = freeList + 79 - i; + if (objPos->index == 0xff) + continue; + if (x < objPos->xMin) + continue; + if (x >= objPos->xMax) + continue; + if (y < objPos->yMin) + continue; + if (y >= objPos->yMax) + continue; + al = objPos->index; + ah = 2; + obname(); + return true; + } + return false; +} - s->fillRect(rect, 0); - pcxFile.seek(128, SEEK_SET); +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 { + uint16 offset = segRef(data.word(kBlockdesc)).word(kBlocktextdat + index * 2) + kBlocktext; + return segRef(data.word(kBlockdesc)).ptr(offset, 0); + } +} - for (int y = 0; y < 480; y++) { - byte *dst = (byte *)s->getBasePtr(0, y); - int decoded = 0; +void DreamGenContext::copyname() { + copyname(ah, al, cs.ptr(di, 0)); +} - while (decoded < 320) { - byte col = pcxFile.readByte(); - byte len; +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; +} - if ((col & 0xc0) == 0xc0) { - len = col & 0x3f; - col = pcxFile.readByte(); - } else { - len = 1; - } +void DreamGenContext::commandwithob() { + commandwithob(al, bh, bl); +} - // The image uses 16 colors and is stored as four bit - // planes, one for each bit of the color, least - // significant bit plane first. +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; +} - for (i = 0; i < len; i++) { - int plane = decoded / 80; - int pos = decoded % 80; +void DreamGenContext::showpanel() { + Frame *frame = (Frame *)segRef(data.word(kIcons1)).ptr(0, sizeof(Frame)); + showframe(frame, 72, 0, 19, 0); + showframe(frame, 192, 0, 19, 0); +} - for (j = 0; j < 8; j++) { - byte bit = (col >> (7 - j)) & 1; - dst[8 * pos + j] |= (bit << plane); - } +void DreamGenContext::blocknametext() { + commandwithob(0, data.byte(kCommandtype), data.byte(kCommand)); +} - decoded++; - } +void DreamGenContext::personnametext() { + commandwithob(2, data.byte(kCommandtype), data.byte(kCommand) & 127); +} + +void DreamGenContext::walktotext() { + commandwithob(3, data.byte(kCommandtype), data.byte(kCommand)); +} + +void DreamGenContext::findormake() { + uint8 b0 = al; + uint8 b2 = cl; + uint8 b3 = ch; + findormake(b0, b2, b3); +} + +void DreamGenContext::findormake(uint8 index, uint8 value, uint8 type) { + Change *change = (Change *)segRef(data.word(kBuffers)).ptr(kListofchanges, sizeof(Change)); + while (true) { + if (change->index == 0xff) { + change->index = index; + change->location = data.byte(kReallocation); + change->value = value; + change->type = type; + return; } + if ((index == change->index) && (data.byte(kReallocation) == change->location) && (type == change->type)) { + change->value = value; + return; + } + ++change; } +} - g_system->unlockScreen(); - pcxFile.close(); +void DreamGenContext::setallchanges() { + Change *change = (Change *)segRef(data.word(kBuffers)).ptr(kListofchanges, sizeof(Change)); + while (change->index != 0xff) { + if (change->location == data.byte(kReallocation)) + dochange(change->index, change->value, change->type); + ++change; + } +} + +FreeObject *DreamGenContext::getfreead(uint8 index) { + return (FreeObject *)segRef(data.word(kFreedat)).ptr(0, 0) + index; } -void DreamGenContext::frameoutv() { - uint16 pitch = dx; - uint16 width = cx & 0xff; - uint16 height = cx >> 8; - uint16 stride = pitch - width; +ObjData *DreamGenContext::getsetad(uint8 index) { + return (ObjData *)segRef(data.word(kSetdat)).ptr(0, 0) + index; +} - const uint8* src = ds.ptr(si, width * height); - uint8* base = es.ptr(di, stride * height); - uint8* dst = base + pitch * bx; +void DreamGenContext::dochange() { + dochange(al, cl, ch); +} - // NB: Original code assumes non-zero width and height, "for" are unneeded, do-while would suffice but would be less readable - for (uint16 y = 0; y < height; ++y) { - for (uint16 x = 0; x < width; ++x) { - uint8 pixel = *src++; - if (pixel) - *dst = pixel; - ++dst; +void DreamGenContext::dochange(uint8 index, uint8 value, uint8 type) { + if (type == 0) { //object + getsetad(index)->b58[0] = value; + } else if (type == 1) { //freeobject + FreeObject *freeObject = getfreead(index); + if (freeObject->b2 == 0xff) + freeObject->b2 = value; + } else { //path + bx = kPathdata + (type - 100) * 144 + index * 8; + es = data.word(kReels); + es.byte(bx+6) = value; + } +} + +void DreamGenContext::deletetaken() { + ds = data.word(kExtras); + si = kExdata; + FreeObject *freeObjects = (FreeObject *)segRef(data.word(kFreedat)).ptr(0, 0); + for(size_t i = 0; i < kNumexobjects; ++i) { + uint8 location = ds.byte(si+11); + if (location == data.byte(kReallocation)) { + uint8 index = ds.byte(si+1); + freeObjects[index].b2 = 254; } - dst += stride; + si += 16; } } -void DreamGenContext::modifychar() { - al = engine->modifyChar(al); +void DreamGenContext::placesetobject() { + placesetobject(al); +} + +void DreamGenContext::placesetobject(uint8 index) { + findormake(index, 0, 0); + getsetad(index)->b58[0] = 0; +} + +void DreamGenContext::removesetobject() { + removesetobject(al); } +void DreamGenContext::removesetobject(uint8 index) { + findormake(index, 0xff, 0); + getsetad(index)->b58[0] = 0xff; +} + +void DreamGenContext::finishedwalking() { + flags._z = finishedwalkingCPP(); +} + +bool DreamGenContext::finishedwalkingCPP() { + return (data.byte(kLinepointer) == 254) && (data.byte(kFacing) == data.byte(kTurntoface)); +} + +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 new file mode 100644 index 0000000000..9d5550be5b --- /dev/null +++ b/engines/dreamweb/stubs.h @@ -0,0 +1,174 @@ +/* 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. + * + */ + 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); + void frameoutnm(uint8 *dst, const uint8 *src, uint16 pitch, uint16 width, uint16 height, uint16 x, uint16 y); + void frameoutbh(uint8 *dst, const uint8 *src, uint16 pitch, uint16 width, uint16 height, uint16 x, uint16 y); + void frameoutfx(uint8 *dst, const uint8 *src, uint16 pitch, uint16 width, uint16 height, uint16 x, uint16 y); + void worktoscreen(); + void multiget(); + void multiget(uint8 *dst, uint16 x, uint16 y, uint8 width, uint8 height); + void convertkey(); + void cls(); + void printsprites(); + void quickquit(); + void readoneblock(); + void printundermon(); + void seecommandtail(); + void randomnumber(); + void quickquit2(); + 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(const Frame* charSet, uint16 *x, uint16 y, uint8 c, uint8 nextChar, uint8 *width, uint8 *height); + void printdirect(); + 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(const uint8 *string, uint16 x, uint16 y, uint8 maxWidth, bool centered); + void printslow(); + void dumptextline(); + void getnumber(); + 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(const Frame *frameData, 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); + void printasprite(const Sprite *sprite); + void width160(); + 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 frameData, uint16 somethingInDi); + void spriteupdate(); + void initman(); + 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); + void steady(Sprite *sprite, ObjData *objData); + void random(Sprite *sprite, ObjData *objData); + void dodoor(); + void dodoor(Sprite *sprite, ObjData *objData); + void doorway(Sprite *sprite, ObjData *objData); + void widedoor(Sprite *sprite, ObjData *objData); + 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(ObjData *objData); + 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 commandonly(); + void commandonly(uint8 command); + void doblocks(); + void checkifperson(); + bool checkifperson(uint8 x, uint8 y); + void checkiffree(); + bool checkiffree(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 addalong(const uint8 *mapFlags); + bool addlength(const uint8 *mapFlags); + void getdimension(); + void getdimension(uint8 *mapXstart, uint8 *mapYstart, uint8 *mapXsize, uint8 *mapYsize); + void getmapad(); + void calcmapad(); + uint8 getmapad(const uint8 *setData); + uint8 getxad(const uint8 *setData, uint8 *result); + uint8 getyad(const uint8 *setData, uint8 *result); + void calcfrframe(); + void calcfrframe(uint8* width, uint8* height); + void finalframe(); + void finalframe(uint16 *x, uint16 *y); + void showallobs(); + void blocknametext(); + void walktotext(); + void personnametext(); + void findxyfrompath(); + void findormake(); + void findormake(uint8 index, uint8 value, uint8 type); + FreeObject *getfreead(uint8 index); + ObjData *getsetad(uint8 index); + void setallchanges(); + void dochange(); + void dochange(uint8 index, uint8 value, uint8 type); + void deletetaken(); + bool isCD(); + void placesetobject(); + void placesetobject(uint8 index); + void removesetobject(); + void removesetobject(uint8 index); + void showallfree(); + bool finishedwalkingCPP(); + void finishedwalking(); + void checkone(); + void checkone(uint8 x, uint8 y, uint8 *flag, uint8 *flagEx, uint8 *type, uint8 *flagX, uint8 *flagY); + diff --git a/engines/dreamweb/vgagrafx.cpp b/engines/dreamweb/vgagrafx.cpp new file mode 100644 index 0000000000..3c92640768 --- /dev/null +++ b/engines/dreamweb/vgagrafx.cpp @@ -0,0 +1,415 @@ +/* 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, height; + showframe(frameData, x, y, frameNumber, effectsFlag, &width, &height); +} + +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::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/engine.cpp b/engines/engine.cpp index b19daa2611..ee1d53fa9c 100644 --- a/engines/engine.cpp +++ b/engines/engine.cpp @@ -41,6 +41,7 @@ #include "common/list.h" #include "common/list_intern.h" #include "common/scummsys.h" +#include "common/taskbar.h" #include "common/textconsole.h" #include "common/translation.h" @@ -79,10 +80,21 @@ static void defaultErrorHandler(const char *msg) { if (isSmartphone()) debugger = 0; #endif + +#if defined(USE_TASKBAR) + g_system->getTaskbarManager()->notifyError(); +#endif + if (debugger && !debugger->isActive()) { debugger->attach(msg); debugger->onFrame(); } + + +#if defined(USE_TASKBAR) + g_system->getTaskbarManager()->clearError(); +#endif + } } diff --git a/engines/engines.mk b/engines/engines.mk index 07364a5bd3..eddd22039d 100644 --- a/engines/engines.mk +++ b/engines/engines.mk @@ -36,6 +36,11 @@ DEFINES += -DENABLE_CINE=$(ENABLE_CINE) MODULES += engines/cine endif +ifdef ENABLE_COMPOSER +DEFINES += -DENABLE_COMPOSER=$(ENABLE_COMPOSER) +MODULES += engines/composer +endif + ifdef ENABLE_CRUISE DEFINES += -DENABLE_CRUISE=$(ENABLE_CRUISE) MODULES += engines/cruise @@ -207,4 +212,3 @@ ifdef ENABLE_TUCKER DEFINES += -DENABLE_TUCKER=$(ENABLE_TUCKER) MODULES += engines/tucker endif - diff --git a/engines/gob/draw_v2.cpp b/engines/gob/draw_v2.cpp index cc8f6b5e3c..151ed42526 100644 --- a/engines/gob/draw_v2.cpp +++ b/engines/gob/draw_v2.cpp @@ -916,4 +916,3 @@ void Draw_v2::spriteOperation(int16 operation) { } } // End of namespace Gob - diff --git a/engines/gob/inter.h b/engines/gob/inter.h index 78d5e34271..b1689e8d9e 100644 --- a/engines/gob/inter.h +++ b/engines/gob/inter.h @@ -477,9 +477,14 @@ protected: virtual void setupOpcodesGob(); void o3_getTotTextItemPart(OpFuncParams ¶ms); + void o3_speakerOn(OpFuncParams ¶ms); + void o3_speakerOff(OpFuncParams ¶ms); void o3_copySprite(OpFuncParams ¶ms); void o3_wobble(OpGobParams ¶ms); + +private: + bool _ignoreSpeakerOff; }; class Inter_Inca2 : public Inter_v3 { diff --git a/engines/gob/inter_v3.cpp b/engines/gob/inter_v3.cpp index 47486b0899..edf56012d9 100644 --- a/engines/gob/inter_v3.cpp +++ b/engines/gob/inter_v3.cpp @@ -31,6 +31,7 @@ #include "gob/game.h" #include "gob/script.h" #include "gob/resources.h" +#include "gob/sound/sound.h" namespace Gob { @@ -39,7 +40,7 @@ namespace Gob { #define OPCODEFUNC(i, x) _opcodesFunc[i]._OPCODEFUNC(OPCODEVER, x) #define OPCODEGOB(i, x) _opcodesGob[i]._OPCODEGOB(OPCODEVER, x) -Inter_v3::Inter_v3(GobEngine *vm) : Inter_v2(vm) { +Inter_v3::Inter_v3(GobEngine *vm) : Inter_v2(vm), _ignoreSpeakerOff(false) { } void Inter_v3::setupOpcodesDraw() { @@ -50,6 +51,8 @@ void Inter_v3::setupOpcodesFunc() { Inter_v2::setupOpcodesFunc(); OPCODEFUNC(0x1A, o3_getTotTextItemPart); + OPCODEFUNC(0x22, o3_speakerOn); + OPCODEFUNC(0x23, o3_speakerOff); OPCODEFUNC(0x32, o3_copySprite); } @@ -245,6 +248,36 @@ void Inter_v3::o3_getTotTextItemPart(OpFuncParams ¶ms) { delete textItem; } +void Inter_v3::o3_speakerOn(OpFuncParams ¶ms) { + int16 frequency = _vm->_game->_script->readValExpr(); + int32 length = -1; + + _ignoreSpeakerOff = false; + + // WORKAROUND: This is the footsteps sound. The scripts just fire + // speaker on" and then a "speaker off" after a short while. Since + // we have delay in certain places avoid 100% CPU all the time and + // our PC speaker emulator sometimes "swallows" very short beeper + // bursts issued in this way, this is in general quite wonky and + // prone to fail, as can be seen in bug report #3376547. Therefore, + // we explicitely set a length in this case and ignore the next + // speaker off command. + if (frequency == 50) { + length = 5; + + _ignoreSpeakerOff = true; + } + + _vm->_sound->speakerOn(frequency, length); +} + +void Inter_v3::o3_speakerOff(OpFuncParams ¶ms) { + if (!_ignoreSpeakerOff) + _vm->_sound->speakerOff(); + + _ignoreSpeakerOff = false; +} + void Inter_v3::o3_copySprite(OpFuncParams ¶ms) { o1_copySprite(params); diff --git a/engines/gob/scenery.cpp b/engines/gob/scenery.cpp index bb50818ed8..33fdfcaa2a 100644 --- a/engines/gob/scenery.cpp +++ b/engines/gob/scenery.cpp @@ -622,7 +622,7 @@ void Scenery::updateAnim(int16 layer, int16 frame, int16 animation, int16 flags, if (frame >= (int32)_vm->_vidPlayer->getFrameCount(obj.videoSlot - 1)) frame = _vm->_vidPlayer->getFrameCount(obj.videoSlot - 1) - 1; - if (_vm->_vidPlayer->getCurrentFrame(obj.videoSlot - 1) >= 255) { + if ((int32)_vm->_vidPlayer->getCurrentFrame(obj.videoSlot - 1) >= 255) { // Allow for object videos with more than 255 frames, although the // object frame counter is just a byte. diff --git a/engines/groovie/groovie.cpp b/engines/groovie/groovie.cpp index 5f95de649a..f5f02b5cdd 100644 --- a/engines/groovie/groovie.cpp +++ b/engines/groovie/groovie.cpp @@ -20,6 +20,9 @@ * */ +#include "audio/mididrv.h" +#include "audio/mixer.h" + #include "groovie/groovie.h" #include "groovie/cursor.h" #include "groovie/detection.h" diff --git a/engines/groovie/music.cpp b/engines/groovie/music.cpp index c6e990dfcf..af929d439b 100644 --- a/engines/groovie/music.cpp +++ b/engines/groovie/music.cpp @@ -20,6 +20,9 @@ * */ +#include "audio/mididrv.h" +#include "audio/mixer.h" + #include "groovie/music.h" #include "groovie/groovie.h" #include "groovie/resource.h" @@ -766,7 +769,7 @@ Common::SeekableReadStream *MusicPlayerMac::decompressMidi(Common::SeekableReadS } MusicPlayerIOS::MusicPlayerIOS(GroovieEngine *vm) : MusicPlayer(vm) { - vm->getTimerManager()->installTimerProc(&onTimer, 50 * 1000, this); + vm->getTimerManager()->installTimerProc(&onTimer, 50 * 1000, this, "groovieMusic"); } MusicPlayerIOS::~MusicPlayerIOS() { diff --git a/engines/groovie/music.h b/engines/groovie/music.h index 7af482e45d..cc852aa8dc 100644 --- a/engines/groovie/music.h +++ b/engines/groovie/music.h @@ -25,8 +25,6 @@ #include "common/array.h" #include "common/mutex.h" -#include "audio/mididrv.h" -#include "audio/mixer.h" class MidiParser; diff --git a/engines/groovie/script.cpp b/engines/groovie/script.cpp index 5a24559e8b..9003a58ab8 100644 --- a/engines/groovie/script.cpp +++ b/engines/groovie/script.cpp @@ -20,6 +20,9 @@ * */ +#include "audio/mididrv.h" +#include "audio/mixer.h" + #include "groovie/script.h" #include "groovie/cell.h" #include "groovie/cursor.h" diff --git a/engines/hugo/detection.cpp b/engines/hugo/detection.cpp index f70a21aa8f..5d972f5658 100644 --- a/engines/hugo/detection.cpp +++ b/engines/hugo/detection.cpp @@ -241,12 +241,7 @@ SaveStateDescriptor HugoMetaEngine::querySaveMetaInfos(const char *target, int s SaveStateDescriptor desc(slot, saveName); - Graphics::Surface *thumbnail = new Graphics::Surface(); - assert(thumbnail); - if (!Graphics::loadThumbnail(*file, *thumbnail)) { - delete thumbnail; - thumbnail = 0; - } + Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*file); desc.setThumbnail(thumbnail); desc.setDeletableFlag(true); diff --git a/engines/hugo/display.cpp b/engines/hugo/display.cpp index 2d35bb0448..fa18d6b791 100644 --- a/engines/hugo/display.cpp +++ b/engines/hugo/display.cpp @@ -813,4 +813,3 @@ overlayState_t Screen_v1w::findOvl(seq_t *seq_p, image_pt dst_p, uint16 y) { } } // End of namespace Hugo - diff --git a/engines/hugo/file.cpp b/engines/hugo/file.cpp index cde6e108ea..2217cef92a 100644 --- a/engines/hugo/file.cpp +++ b/engines/hugo/file.cpp @@ -695,4 +695,3 @@ void FileManager::readUIFImages() { } } // End of namespace Hugo - diff --git a/engines/hugo/file_v1d.cpp b/engines/hugo/file_v1d.cpp index 0795923536..c3bb0e275f 100644 --- a/engines/hugo/file_v1d.cpp +++ b/engines/hugo/file_v1d.cpp @@ -128,4 +128,3 @@ void FileManager_v1d::instructions() const { } } // End of namespace Hugo - diff --git a/engines/hugo/file_v1w.cpp b/engines/hugo/file_v1w.cpp index 162019dd2e..8a06cef939 100644 --- a/engines/hugo/file_v1w.cpp +++ b/engines/hugo/file_v1w.cpp @@ -87,4 +87,3 @@ void FileManager_v1w::readOverlay(const int screenNum, image_pt image, ovl_t ove } } // End of namespace Hugo - diff --git a/engines/hugo/file_v2d.cpp b/engines/hugo/file_v2d.cpp index 7e44e756d5..520e1b77b6 100644 --- a/engines/hugo/file_v2d.cpp +++ b/engines/hugo/file_v2d.cpp @@ -187,4 +187,3 @@ const char *FileManager_v2d::fetchString(const int index) { return _fetchStringBuf; } } // End of namespace Hugo - diff --git a/engines/hugo/file_v2w.cpp b/engines/hugo/file_v2w.cpp index 1384f02df6..98a15526fa 100644 --- a/engines/hugo/file_v2w.cpp +++ b/engines/hugo/file_v2w.cpp @@ -49,4 +49,3 @@ void FileManager_v2w::instructions() const { } } // End of namespace Hugo - diff --git a/engines/hugo/file_v3d.cpp b/engines/hugo/file_v3d.cpp index 69371bb030..d86003a040 100644 --- a/engines/hugo/file_v3d.cpp +++ b/engines/hugo/file_v3d.cpp @@ -205,4 +205,3 @@ void FileManager_v3d::readOverlay(const int screenNum, image_pt image, ovl_t ove } } } // End of namespace Hugo - diff --git a/engines/hugo/sound.cpp b/engines/hugo/sound.cpp index 1fea1f4343..fe34e6ff2d 100644 --- a/engines/hugo/sound.cpp +++ b/engines/hugo/sound.cpp @@ -270,7 +270,7 @@ void SoundHandler::pcspkr_player() { static const uint16 pcspkrFlats[8] = {1435, 1279, 2342, 2150, 1916, 1755, 1611}; // The flats, Ab to Bb _vm->getTimerManager()->removeTimerProc(&loopPlayer); - _vm->getTimerManager()->installTimerProc(&loopPlayer, 1000000 / 9, this); + _vm->getTimerManager()->installTimerProc(&loopPlayer, 1000000 / 9, this, "hugoSoundLoop"); uint16 count; // Value to set timer chip to for note bool cmd_note; @@ -372,7 +372,7 @@ void SoundHandler::loadIntroSong(Common::ReadStream &in) { } void SoundHandler::initPcspkrPlayer() { - _vm->getTimerManager()->installTimerProc(&loopPlayer, 1000000 / 9, this); + _vm->getTimerManager()->installTimerProc(&loopPlayer, 1000000 / 9, this, "hugoSoundLoop"); } } // End of namespace Hugo diff --git a/engines/kyra/animator_hof.cpp b/engines/kyra/animator_hof.cpp index 4cdb622501..741e358143 100644 --- a/engines/kyra/animator_hof.cpp +++ b/engines/kyra/animator_hof.cpp @@ -314,4 +314,3 @@ void KyraEngine_HoF::resetCharacterAnimDim() { } } // End of namespace Kyra - diff --git a/engines/kyra/animator_lok.cpp b/engines/kyra/animator_lok.cpp index 3e9dd7aa66..4126681bbe 100644 --- a/engines/kyra/animator_lok.cpp +++ b/engines/kyra/animator_lok.cpp @@ -649,4 +649,3 @@ void Animator_LoK::setCharactersHeight() { } } // End of namespace Kyra - diff --git a/engines/kyra/animator_lok.h b/engines/kyra/animator_lok.h index 21d24866c8..74b8305468 100644 --- a/engines/kyra/animator_lok.h +++ b/engines/kyra/animator_lok.h @@ -125,4 +125,3 @@ protected: } // End of namespace Kyra #endif - diff --git a/engines/kyra/animator_mr.cpp b/engines/kyra/animator_mr.cpp index 84bda3f3fd..6414b99ffd 100644 --- a/engines/kyra/animator_mr.cpp +++ b/engines/kyra/animator_mr.cpp @@ -459,4 +459,3 @@ void KyraEngine_MR::showIdleAnim() { } } // End of namespace Kyra - diff --git a/engines/kyra/animator_v2.cpp b/engines/kyra/animator_v2.cpp index ad7057f11a..334356e261 100644 --- a/engines/kyra/animator_v2.cpp +++ b/engines/kyra/animator_v2.cpp @@ -185,4 +185,3 @@ void KyraEngine_v2::deleteItemAnimEntry(int item) { } } // End of namespace Kyra - diff --git a/engines/kyra/debugger.cpp b/engines/kyra/debugger.cpp index 4a48ac0674..dfc2a9f868 100644 --- a/engines/kyra/debugger.cpp +++ b/engines/kyra/debugger.cpp @@ -461,4 +461,3 @@ Debugger_LoL::Debugger_LoL(LoLEngine *vm) : Debugger(vm), _vm(vm) { #endif // ENABLE_LOL } // End of namespace Kyra - diff --git a/engines/kyra/debugger.h b/engines/kyra/debugger.h index 70c547381e..09ddd89a7a 100644 --- a/engines/kyra/debugger.h +++ b/engines/kyra/debugger.h @@ -106,4 +106,3 @@ protected: } // End of namespace Kyra #endif - diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp index a6af584fb8..0a49483f12 100644 --- a/engines/kyra/detection.cpp +++ b/engines/kyra/detection.cpp @@ -221,4 +221,3 @@ SaveStateDescriptor KyraMetaEngine::querySaveMetaInfos(const char *target, int s #else REGISTER_PLUGIN_STATIC(KYRA, PLUGIN_TYPE_ENGINE, KyraMetaEngine); #endif - diff --git a/engines/kyra/detection_tables.h b/engines/kyra/detection_tables.h index 47a3c4362a..c224c8f46d 100644 --- a/engines/kyra/detection_tables.h +++ b/engines/kyra/detection_tables.h @@ -21,38 +21,41 @@ namespace { -#define FLAGS(x, y, z, a, b, c, d, id) { Common::UNK_LANG, Common::UNK_LANG, Common::UNK_LANG, Common::kPlatformUnknown, x, y, z, a, b, c, d, id } -#define FLAGS_FAN(fanLang, repLang, x, y, z, a, b, c, d, id) { Common::UNK_LANG, fanLang, repLang, Common::kPlatformUnknown, x, y, z, a, b, c, d, id } - -#define KYRA1_FLOPPY_FLAGS FLAGS(false, false, false, false, false, false, false, Kyra::GI_KYRA1) -#define KYRA1_FLOPPY_CMP_FLAGS FLAGS(false, false, false, false, false, false, true, Kyra::GI_KYRA1) -#define KYRA1_AMIGA_FLAGS FLAGS(false, false, false, false, false, false, false, Kyra::GI_KYRA1) -#define KYRA1_TOWNS_FLAGS FLAGS(false, true, false, false, false, false, false, Kyra::GI_KYRA1) -#define KYRA1_TOWNS_SJIS_FLAGS FLAGS(false, true, false, true, false, false, false, Kyra::GI_KYRA1) -#define KYRA1_CD_FLAGS FLAGS(false, true, true, false, false, false, false, Kyra::GI_KYRA1) -#define KYRA1_DEMO_FLAGS FLAGS(true, false, false, false, false, false, false, Kyra::GI_KYRA1) -#define KYRA1_DEMO_CD_FLAGS FLAGS(true, true, true, false, false, false, false, Kyra::GI_KYRA1) - -#define KYRA2_FLOPPY_FLAGS FLAGS(false, false, false, false, false, false, false, Kyra::GI_KYRA2) -#define KYRA2_FLOPPY_CMP_FLAGS FLAGS(false, false, false, false, false, false, true, Kyra::GI_KYRA2) -#define KYRA2_CD_FLAGS FLAGS(false, false, true, false, false, false, false, Kyra::GI_KYRA2) -#define KYRA2_CD_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, true, false, false, false, false, Kyra::GI_KYRA2) -#define KYRA2_CD_DEMO_FLAGS FLAGS(true, false, true, false, false, false, false, Kyra::GI_KYRA2) -#define KYRA2_DEMO_FLAGS FLAGS(true, false, false, false, false, false, false, Kyra::GI_KYRA2) -#define KYRA2_TOWNS_FLAGS FLAGS(false, false, false, false, false, false, false, Kyra::GI_KYRA2) -#define KYRA2_TOWNS_SJIS_FLAGS FLAGS(false, false, false, true, false, false, false, Kyra::GI_KYRA2) - -#define KYRA3_CD_FLAGS FLAGS(false, false, true, false, false, true, true, Kyra::GI_KYRA3) -#define KYRA3_CD_INS_FLAGS FLAGS(false, false, true, false, false, true, false, Kyra::GI_KYRA3) -#define KYRA3_CD_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, true, false, false, true, false, Kyra::GI_KYRA3) - -#define LOL_CD_FLAGS FLAGS(false, false, true, false, false, false, false, Kyra::GI_LOL) -#define LOL_CD_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, true, false, false, false, false, Kyra::GI_LOL) -#define LOL_FLOPPY_FLAGS FLAGS(false, false, false, false, false, false, false, Kyra::GI_LOL) -#define LOL_FLOPPY_CMP_FLAGS FLAGS(false, false, false, false, false, false, true, Kyra::GI_LOL) -#define LOL_PC98_SJIS_FLAGS FLAGS(false, false, false, true, true, false, false, Kyra::GI_LOL) -#define LOL_DEMO_FLAGS FLAGS(true, true, false, false, false, false, false, Kyra::GI_LOL) -#define LOL_KYRA2_DEMO_FLAGS FLAGS(true, false, false, false, false, false, false, Kyra::GI_KYRA2) +#define FLAGS(x, y, z, a, b, c, d, e, id) { Common::UNK_LANG, Common::UNK_LANG, Common::UNK_LANG, Common::kPlatformUnknown, x, y, z, a, b, c, d, e, id } +#define FLAGS_FAN(fanLang, repLang, x, y, z, a, b, c, d, e, id) { Common::UNK_LANG, fanLang, repLang, Common::kPlatformUnknown, x, y, z, a, b, c, d, e, id } + +#define KYRA1_FLOPPY_FLAGS FLAGS(false, false, false, false, false, false, false, false, Kyra::GI_KYRA1) +#define KYRA1_FLOPPY_CMP_FLAGS FLAGS(false, false, false, false, false, false, false, true, Kyra::GI_KYRA1) +#define KYRA1_OLDFLOPPY_FLAGS FLAGS(false, false, false, true, false, false, false, false, Kyra::GI_KYRA1) +#define KYRA1_AMIGA_FLAGS FLAGS(false, false, false, false, false, false, false, false, Kyra::GI_KYRA1) +#define KYRA1_TOWNS_FLAGS FLAGS(false, true, false, false, false, false, false, false, Kyra::GI_KYRA1) +#define KYRA1_TOWNS_SJIS_FLAGS FLAGS(false, true, false, false, true, false, false, false, Kyra::GI_KYRA1) +#define KYRA1_CD_FLAGS FLAGS(false, true, true, false, false, false, false, false, Kyra::GI_KYRA1) +#define KYRA1_DEMO_FLAGS FLAGS(true, false, false, false, false, false, false, false, Kyra::GI_KYRA1) +#define KYRA1_DEMO_CD_FLAGS FLAGS(true, true, true, false, false, false, false, false, Kyra::GI_KYRA1) + +#define KYRA2_FLOPPY_FLAGS FLAGS(false, false, false, false, false, false, false, false, Kyra::GI_KYRA2) +#define KYRA2_FLOPPY_CMP_FLAGS FLAGS(false, false, false, false, false, false, false, true, Kyra::GI_KYRA2) +#define KYRA2_FLOPPY_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, false, false, false, false, false, false, Kyra::GI_KYRA2) +#define KYRA2_CD_FLAGS FLAGS(false, false, true, false, false, false, false, false, Kyra::GI_KYRA2) +#define KYRA2_CD_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, true, false, false, false, false, false, Kyra::GI_KYRA2) +#define KYRA2_CD_DEMO_FLAGS FLAGS(true, false, true, false, false, false, false, false, Kyra::GI_KYRA2) +#define KYRA2_DEMO_FLAGS FLAGS(true, false, false, false, false, false, false, false, Kyra::GI_KYRA2) +#define KYRA2_TOWNS_FLAGS FLAGS(false, false, false, false, false, false, false, false, Kyra::GI_KYRA2) +#define KYRA2_TOWNS_SJIS_FLAGS FLAGS(false, false, false, false, true, false, false, false, Kyra::GI_KYRA2) + +#define KYRA3_CD_FLAGS FLAGS(false, false, true, false, false, false, true, true, Kyra::GI_KYRA3) +#define KYRA3_CD_INS_FLAGS FLAGS(false, false, true, false, false, false, true, false, Kyra::GI_KYRA3) +#define KYRA3_CD_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, true, false, false, false, true, false, Kyra::GI_KYRA3) + +#define LOL_CD_FLAGS FLAGS(false, false, true, false, false, false, false, false, Kyra::GI_LOL) +#define LOL_CD_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, true, false, false, false, false, false, Kyra::GI_LOL) +#define LOL_FLOPPY_FLAGS FLAGS(false, false, false, false, false, false, false, false, Kyra::GI_LOL) +#define LOL_FLOPPY_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, false, false, false, false, false, false, Kyra::GI_LOL) +#define LOL_FLOPPY_CMP_FLAGS FLAGS(false, false, false, false, false, false, false, true, Kyra::GI_LOL) +#define LOL_PC98_SJIS_FLAGS FLAGS(false, false, false, false, true, true, false, false, Kyra::GI_LOL) +#define LOL_DEMO_FLAGS FLAGS(true, true, false, false, false, false, false, false, Kyra::GI_LOL) +#define LOL_KYRA2_DEMO_FLAGS FLAGS(true, false, false, false, false, false, false, false, Kyra::GI_KYRA2) const KYRAGameDescription adGameDescs[] = { /* disable these targets until they get supported @@ -95,6 +98,7 @@ const KYRAGameDescription adGameDescs[] = { }, KYRA1_FLOPPY_FLAGS }, + { { "kyra1", @@ -143,6 +147,18 @@ const KYRAGameDescription adGameDescs[] = { }, KYRA1_FLOPPY_FLAGS }, + { + { + "kyra1", + "Extracted", + AD_ENTRY1("GEMCUT.EMC", "689b62b7519215c1b2571d466c95624c"), + Common::RU_RUS, + Common::kPlatformPC, + ADGF_NO_FLAGS, + Common::GUIO_NOSPEECH | Common::GUIO_MIDIADLIB | Common::GUIO_MIDIMT32 | Common::GUIO_MIDIPCSPK + }, + KYRA1_OLDFLOPPY_FLAGS + }, { // from VooD { "kyra1", @@ -486,6 +502,32 @@ const KYRAGameDescription adGameDescs[] = { KYRA2_FLOPPY_FLAGS }, + { // Floppy version extracted + { + "kyra2", + "Extracted", + AD_ENTRY1("CH01-S00.DLG", "54b7a5a94f6e1ec91f0fb1311eec09ab"), + Common::RU_RUS, + Common::kPlatformPC, + ADGF_NO_FLAGS, + Common::GUIO_NOSPEECH | Common::GUIO_MIDIADLIB | Common::GUIO_MIDIMT32 | Common::GUIO_MIDIGM | Common::GUIO_MIDIPCSPK + }, + KYRA2_FLOPPY_FAN_FLAGS(Common::RU_RUS, Common::EN_ANY) + }, + + { // Floppy version extracted + { + "kyra2", + "Extracted", + AD_ENTRY1("CH01-S00.DLG", "7c36c0e63ab8c81cbb3ea58681331366"), + Common::RU_RUS, + Common::kPlatformPC, + ADGF_NO_FLAGS, + Common::GUIO_NOSPEECH | Common::GUIO_MIDIADLIB | Common::GUIO_MIDIMT32 | Common::GUIO_MIDIGM | Common::GUIO_MIDIPCSPK + }, + KYRA2_FLOPPY_FAN_FLAGS(Common::RU_RUS, Common::EN_ANY) + }, + { // CD version { "kyra2", @@ -1057,6 +1099,59 @@ const KYRAGameDescription adGameDescs[] = { LOL_CD_FLAGS }, + // Russian fan translation + { + { + "lol", + "CD", + { + { "GENERAL.PAK", 0, "19354b0f464295c38c801d30588df062", -1 }, + { "L01.PAK", 0, "174d37f21e0336c5d91020f8c58717ef", -1 }, + { 0, 0, 0, 0 } + }, + Common::EN_ANY, + Common::kPlatformPC, + ADGF_DROPLANGUAGE | ADGF_CD, + Common::GUIO_MIDIADLIB | Common::GUIO_MIDIMT32 | Common::GUIO_MIDIGM | Common::GUIO_MIDIPCSPK + }, + LOL_CD_FAN_FLAGS(Common::RU_RUS, Common::DE_DEU) + }, + + { + { + "lol", + "CD", + { + + { "GENERAL.PAK", 0, "19354b0f464295c38c801d30588df062", -1 }, + { "L01.PAK", 0, "174d37f21e0336c5d91020f8c58717ef", -1 }, + { 0, 0, 0, 0 } + }, + Common::FR_FRA, + Common::kPlatformPC, + ADGF_DROPLANGUAGE | ADGF_CD, + Common::GUIO_MIDIADLIB | Common::GUIO_MIDIMT32 | Common::GUIO_MIDIGM | Common::GUIO_MIDIPCSPK + }, + LOL_CD_FAN_FLAGS(Common::RU_RUS, Common::DE_DEU) + }, + + { + { + "lol", + "CD", + { + { "GENERAL.PAK", 0, "19354b0f464295c38c801d30588df062", -1 }, + { "L01.PAK", 0, "174d37f21e0336c5d91020f8c58717ef", -1 }, + { 0, 0, 0, 0 } + }, + Common::RU_RUS, + Common::kPlatformPC, + ADGF_DROPLANGUAGE | ADGF_CD, + Common::GUIO_MIDIADLIB | Common::GUIO_MIDIMT32 | Common::GUIO_MIDIGM | Common::GUIO_MIDIPCSPK + }, + LOL_CD_FAN_FLAGS(Common::RU_RUS, Common::DE_DEU) + }, + // Italian fan translation { { @@ -1276,6 +1371,24 @@ const KYRAGameDescription adGameDescs[] = { LOL_FLOPPY_FLAGS }, + // Russian fan translation + { + { + "lol", + "Extracted", + { + { "GENERAL.PAK", 0, "d8f4c1153aed2418f41f886c3fb27543", -1 }, + { "CHAPTER7.PAK", 0, "f0b8a2fdff951738834fadc12248ac1f", -1 }, + { 0, 0, 0, 0 } + }, + Common::RU_RUS, + Common::kPlatformPC, + ADGF_NO_FLAGS, + Common::GUIO_NOSPEECH | Common::GUIO_MIDIADLIB | Common::GUIO_MIDIMT32 | Common::GUIO_MIDIGM | Common::GUIO_MIDIPCSPK + }, + LOL_FLOPPY_FAN_FLAGS(Common::RU_RUS, Common::EN_ANY) + }, + { { "lol", @@ -1326,7 +1439,7 @@ const KYRAGameDescription adGameDescs[] = { LOL_KYRA2_DEMO_FLAGS }, #endif // ENABLE_LOL - { AD_TABLE_END_MARKER, FLAGS(0, 0, 0, 0, 0, 0, 0, 0) } + { AD_TABLE_END_MARKER, FLAGS(0, 0, 0, 0, 0, 0, 0, 0, 0) } }; const PlainGameDescriptor gameList[] = { diff --git a/engines/kyra/gui.cpp b/engines/kyra/gui.cpp index 29cbe20b23..7fd9880dce 100644 --- a/engines/kyra/gui.cpp +++ b/engines/kyra/gui.cpp @@ -415,7 +415,7 @@ void GUI::checkTextfieldInput() { bool running = true; int keys = 0; - while (_vm->_eventMan->pollEvent(event) && running) { + while (running && _vm->_eventMan->pollEvent(event)) { switch (event.type) { case Common::EVENT_KEYDOWN: if (event.kbd.keycode == Common::KEYCODE_q && event.kbd.hasFlags(Common::KBD_CTRL)) @@ -671,4 +671,3 @@ void MainMenu::printString(const char *format, int x, int y, int col1, int col2, } } // End of namespace Kyra - diff --git a/engines/kyra/gui.h b/engines/kyra/gui.h index 6afdc431ed..1efbdde394 100644 --- a/engines/kyra/gui.h +++ b/engines/kyra/gui.h @@ -263,4 +263,3 @@ private: } // end of namesapce Kyra #endif - diff --git a/engines/kyra/gui_hof.cpp b/engines/kyra/gui_hof.cpp index 1666cdd0e4..a1e0ce66bf 100644 --- a/engines/kyra/gui_hof.cpp +++ b/engines/kyra/gui_hof.cpp @@ -1195,4 +1195,3 @@ int GUI_HoF::loadMenu(Button *caller) { } } // End of namespace Kyra - diff --git a/engines/kyra/gui_hof.h b/engines/kyra/gui_hof.h index a02d14e9f1..c228c35551 100644 --- a/engines/kyra/gui_hof.h +++ b/engines/kyra/gui_hof.h @@ -82,4 +82,3 @@ private: } // End of namespace Kyra #endif - diff --git a/engines/kyra/gui_lok.cpp b/engines/kyra/gui_lok.cpp index eba2f8f279..4a2d51faa3 100644 --- a/engines/kyra/gui_lok.cpp +++ b/engines/kyra/gui_lok.cpp @@ -1137,4 +1137,3 @@ void KyraEngine_LoK::drawAmulet() { } } // End of namespace Kyra - diff --git a/engines/kyra/gui_lok.h b/engines/kyra/gui_lok.h index 4d7bfa1ada..5a8d6ab532 100644 --- a/engines/kyra/gui_lok.h +++ b/engines/kyra/gui_lok.h @@ -182,4 +182,3 @@ private: } // End of namespace Kyra #endif - diff --git a/engines/kyra/gui_lol.cpp b/engines/kyra/gui_lol.cpp index c64d3e7723..3ab52b9940 100644 --- a/engines/kyra/gui_lol.cpp +++ b/engines/kyra/gui_lol.cpp @@ -395,8 +395,8 @@ void LoLEngine::gui_drawCharPortraitWithStats(int charNum) { } else { gui_drawLiveMagicBar(33, 32, _characters[charNum].magicPointsCur, 0, _characters[charNum].magicPointsMax, 5, 32, 162, 1, 0); gui_drawLiveMagicBar(39, 32, _characters[charNum].hitPointsCur, 0, _characters[charNum].hitPointsMax, 5, 32, 154, 1, 1); - _screen->printText(getLangString(0x4253), 33, 1, 160, 0); - _screen->printText(getLangString(0x4254), 39, 1, 152, 0); + _screen->printText((_flags.platform == Common::kPlatformPC && !_flags.isTalkie) ? "M" : getLangString(0x4253), 33, 1, 160, 0); + _screen->printText((_flags.platform == Common::kPlatformPC && !_flags.isTalkie) ? "H" : getLangString(0x4254), 39, 1, 152, 0); } int spellLevels = 0; @@ -3007,4 +3007,3 @@ const char *GUI_LoL::getMenuItemLabel(const MenuItem &menuItem) { } // End of namespace Kyra #endif // ENABLE_LOL - diff --git a/engines/kyra/gui_lol.h b/engines/kyra/gui_lol.h index bc49b21299..0686926534 100644 --- a/engines/kyra/gui_lol.h +++ b/engines/kyra/gui_lol.h @@ -182,4 +182,3 @@ private: #endif #endif // ENABLE_LOL - diff --git a/engines/kyra/gui_mr.cpp b/engines/kyra/gui_mr.cpp index 32eb02e06d..82082961e9 100644 --- a/engines/kyra/gui_mr.cpp +++ b/engines/kyra/gui_mr.cpp @@ -1607,4 +1607,3 @@ void GUI_MR::drawSliderBar(int slider, const uint8 *shape) { } } // End of namespace Kyra - diff --git a/engines/kyra/gui_mr.h b/engines/kyra/gui_mr.h index 9c8d79b321..6303dff83f 100644 --- a/engines/kyra/gui_mr.h +++ b/engines/kyra/gui_mr.h @@ -85,4 +85,3 @@ private: } // End of namespace Kyra #endif - diff --git a/engines/kyra/gui_v2.cpp b/engines/kyra/gui_v2.cpp index dcc53b7c9e..c0477f29f1 100644 --- a/engines/kyra/gui_v2.cpp +++ b/engines/kyra/gui_v2.cpp @@ -887,4 +887,3 @@ int GUI_v2::choiceNo(Button *caller) { } } // End of namespace Kyra - diff --git a/engines/kyra/gui_v2.h b/engines/kyra/gui_v2.h index 0009bf8e54..ef95c0301a 100644 --- a/engines/kyra/gui_v2.h +++ b/engines/kyra/gui_v2.h @@ -231,4 +231,3 @@ protected: } // End of namespace Kyra #endif - diff --git a/engines/kyra/item.h b/engines/kyra/item.h index 86b6fc7d46..4b236372a2 100644 --- a/engines/kyra/item.h +++ b/engines/kyra/item.h @@ -39,4 +39,3 @@ enum { } // End of namespace Kyra #endif - diff --git a/engines/kyra/items_hof.cpp b/engines/kyra/items_hof.cpp index 73aed2e067..711e1b8f7c 100644 --- a/engines/kyra/items_hof.cpp +++ b/engines/kyra/items_hof.cpp @@ -427,4 +427,3 @@ void KyraEngine_HoF::setMouseCursor(Item item) { } } // End of namespace Kyra - diff --git a/engines/kyra/items_lok.cpp b/engines/kyra/items_lok.cpp index d66eb553f2..d598a17cf1 100644 --- a/engines/kyra/items_lok.cpp +++ b/engines/kyra/items_lok.cpp @@ -575,7 +575,14 @@ void KyraEngine_LoK::dropItem(int unk1, int item, int x, int y, int unk2) { if (processItemDrop(_currentCharacter->sceneId, item, x, y, unk1, unk2)) return; snd_playSoundEffect(54); + + // Old floppy versions don't print warning messages and don't have the necessary string resources. + // These versions will only play the warning sound effect. + if (_flags.isOldFloppy && !_noDropList) + return; + assert(_noDropList); + if (12 == countItemsInScene(_currentCharacter->sceneId)) drawSentenceCommand(_noDropList[0], 6); else @@ -969,4 +976,3 @@ int KyraEngine_LoK::getItemListIndex(Item item) { } } // End of namespace Kyra - diff --git a/engines/kyra/items_lol.cpp b/engines/kyra/items_lol.cpp index 2cf2cb2c70..7e9ae439fc 100644 --- a/engines/kyra/items_lol.cpp +++ b/engines/kyra/items_lol.cpp @@ -551,4 +551,3 @@ int LoLEngine::checkSceneForItems(uint16 *blockDrawObjects, int color) { } // End of namespace Kyra #endif // ENABLE_LOL - diff --git a/engines/kyra/items_mr.cpp b/engines/kyra/items_mr.cpp index 88c02f56c8..c731627026 100644 --- a/engines/kyra/items_mr.cpp +++ b/engines/kyra/items_mr.cpp @@ -544,4 +544,3 @@ int KyraEngine_MR::getItemCommandStringInv(uint16 item) { } } // End of namespace Kyra - diff --git a/engines/kyra/items_v2.cpp b/engines/kyra/items_v2.cpp index 29dddc6772..c191c2e62b 100644 --- a/engines/kyra/items_v2.cpp +++ b/engines/kyra/items_v2.cpp @@ -105,4 +105,3 @@ void KyraEngine_v2::removeHandItem() { } } // end of namesapce Kyra - diff --git a/engines/kyra/kyra_hof.cpp b/engines/kyra/kyra_hof.cpp index 5c58e6e3ed..b82099f058 100644 --- a/engines/kyra/kyra_hof.cpp +++ b/engines/kyra/kyra_hof.cpp @@ -1052,8 +1052,7 @@ void KyraEngine_HoF::runStartScript(int script, int unk1) { void KyraEngine_HoF::loadNPCScript() { _emc->unload(&_npcScriptData); - char filename[12]; - strcpy(filename, "_NPC.EMC"); + char filename[] = "_NPC.EMC"; if (_flags.platform != Common::kPlatformPC || _flags.isTalkie) { switch (_lang) { @@ -1084,7 +1083,7 @@ void KyraEngine_HoF::loadNPCScript() { #pragma mark - void KyraEngine_HoF::resetScaleTable() { - Common::set_to(_scaleTable, _scaleTable + ARRAYSIZE(_scaleTable), 0x100); + Common::set_to(_scaleTable, ARRAYEND(_scaleTable), 0x100); } void KyraEngine_HoF::setScaleTableItem(int item, int data) { @@ -1674,7 +1673,7 @@ void KyraEngine_HoF::setCauldronState(uint8 state, bool paletteFade) { } void KyraEngine_HoF::clearCauldronTable() { - Common::set_to(_cauldronTable, _cauldronTable+ARRAYSIZE(_cauldronTable), -1); + Common::set_to(_cauldronTable, ARRAYEND(_cauldronTable), -1); } void KyraEngine_HoF::addFrontCauldronTable(int item) { @@ -1998,4 +1997,3 @@ void KyraEngine_HoF::readSettings() { } } // End of namespace Kyra - diff --git a/engines/kyra/kyra_hof.h b/engines/kyra/kyra_hof.h index da7486bc29..2561171598 100644 --- a/engines/kyra/kyra_hof.h +++ b/engines/kyra/kyra_hof.h @@ -925,4 +925,3 @@ protected: } // End of namespace Kyra #endif - diff --git a/engines/kyra/kyra_lok.cpp b/engines/kyra/kyra_lok.cpp index 7f356f34c1..27d0849e5f 100644 --- a/engines/kyra/kyra_lok.cpp +++ b/engines/kyra/kyra_lok.cpp @@ -98,6 +98,8 @@ KyraEngine_LoK::KyraEngine_LoK(OSystem *system, const GameFlags &flags) _malcolmFrame = 0; _malcolmTimer1 = _malcolmTimer2 = 0; + + _soundFiles = 0; } KyraEngine_LoK::~KyraEngine_LoK() { @@ -121,6 +123,8 @@ KyraEngine_LoK::~KyraEngine_LoK() { delete _animator; delete _seq; + delete[] _soundFiles; + delete[] _characterList; delete[] _roomTable; diff --git a/engines/kyra/kyra_lok.h b/engines/kyra/kyra_lok.h index 066c27c69a..57e6bd39ab 100644 --- a/engines/kyra/kyra_lok.h +++ b/engines/kyra/kyra_lok.h @@ -826,4 +826,3 @@ protected: } // End of namespace Kyra #endif - diff --git a/engines/kyra/kyra_mr.cpp b/engines/kyra/kyra_mr.cpp index f5bcd04ea0..5798e99a1f 100644 --- a/engines/kyra/kyra_mr.cpp +++ b/engines/kyra/kyra_mr.cpp @@ -1426,4 +1426,3 @@ void KyraEngine_MR::readSettings() { } } // End of namespace Kyra - diff --git a/engines/kyra/kyra_mr.h b/engines/kyra/kyra_mr.h index b762648d29..ec76340638 100644 --- a/engines/kyra/kyra_mr.h +++ b/engines/kyra/kyra_mr.h @@ -668,4 +668,3 @@ private: } // End of namespace Kyra #endif - diff --git a/engines/kyra/kyra_v1.cpp b/engines/kyra/kyra_v1.cpp index 3b2c9b67eb..c950612a42 100644 --- a/engines/kyra/kyra_v1.cpp +++ b/engines/kyra/kyra_v1.cpp @@ -650,4 +650,3 @@ void KyraEngine_v1::syncSoundSettings() { } } // End of namespace Kyra - diff --git a/engines/kyra/kyra_v1.h b/engines/kyra/kyra_v1.h index 83455f3922..584176e08c 100644 --- a/engines/kyra/kyra_v1.h +++ b/engines/kyra/kyra_v1.h @@ -109,6 +109,7 @@ struct GameFlags { bool isDemo : 1; bool useAltShapeHeader : 1; // alternative shape header (uses 2 bytes more, those are unused though) bool isTalkie : 1; + bool isOldFloppy : 1; bool useHiResOverlay : 1; bool use16ColorMode : 1; bool useDigSound : 1; @@ -422,4 +423,3 @@ protected: } // End of namespace Kyra #endif - diff --git a/engines/kyra/kyra_v2.cpp b/engines/kyra/kyra_v2.cpp index d0f8d78bd1..e8cb9b4370 100644 --- a/engines/kyra/kyra_v2.cpp +++ b/engines/kyra/kyra_v2.cpp @@ -243,4 +243,3 @@ int KyraEngine_v2::updateCharPos(int *table, int force) { } } // End of namespace Kyra - diff --git a/engines/kyra/kyra_v2.h b/engines/kyra/kyra_v2.h index f21458ab5d..56391d151a 100644 --- a/engines/kyra/kyra_v2.h +++ b/engines/kyra/kyra_v2.h @@ -398,4 +398,3 @@ protected: } // End of namespace Kyra #endif - diff --git a/engines/kyra/lol.cpp b/engines/kyra/lol.cpp index 2cca4fd4e3..5aba264ceb 100644 --- a/engines/kyra/lol.cpp +++ b/engines/kyra/lol.cpp @@ -1038,11 +1038,14 @@ char *LoLEngine::getLangString(uint16 id) { char *string = (char *)getTableEntry(buffer, realId); char *srcBuffer = _stringBuffer[_lastUsedStringBuffer]; - if (_flags.lang != Common::JA_JPN) { - Util::decodeString1(string, srcBuffer); + if (_flags.lang == Common::JA_JPN) { + decodeSjis(string, srcBuffer); + } else if (_flags.lang == Common::RU_RUS && !_flags.isTalkie) { + decodeCyrillic(string, srcBuffer); Util::decodeString2(srcBuffer, srcBuffer); } else { - decodeSjis(string, srcBuffer); + Util::decodeString1(string, srcBuffer); + Util::decodeString2(srcBuffer, srcBuffer); } ++_lastUsedStringBuffer; @@ -1081,6 +1084,54 @@ void LoLEngine::decodeSjis(const char *src, char *dst) { *dst = 0; } +int LoLEngine::decodeCyrillic(const char *src, char *dst) { + static const uint8 decodeTable1[] = { + 0x20, 0xAE, 0xA5, 0xA0, 0xE2, 0xAD, 0xA8, 0xE0, 0xE1, 0xAB, 0xA2, + 0xA4, 0xAC, 0xAA, 0xE3, 0x2E + }; + + static const uint8 decodeTable2[] = { + 0xAD, 0xAF, 0xA2, 0xE1, 0xAC, 0xAA, 0x20, 0xA4, 0xAB, 0x20, + 0xE0, 0xE2, 0xA4, 0xA2, 0xA6, 0xAA, 0x20, 0xAD, 0xE2, 0xE0, + 0xAB, 0xAC, 0xE1, 0xA1, 0x20, 0xAC, 0xE1, 0xAA, 0xAB, 0xE0, + 0xE2, 0xAD, 0xAE, 0xEC, 0xA8, 0xA5, 0xA0, 0x20, 0xE0, 0xEB, + 0xAE, 0xA0, 0xA8, 0xA5, 0xEB, 0xEF, 0x20, 0xE3, 0xE2, 0x20, + 0xAD, 0xE7, 0xAB, 0xAC, 0xA5, 0xE0, 0xAE, 0xA0, 0xA5, 0xA8, + 0xE3, 0xEB, 0xEF, 0xAA, 0xE2, 0xEF, 0xA5, 0xEC, 0xAB, 0xAE, + 0xAA, 0xAF, 0xA8, 0xA0, 0xA5, 0xEF, 0xAE, 0xEE, 0xEC, 0xE3, + 0xA0, 0xAE, 0xA5, 0xA8, 0xEB, 0x20, 0xE0, 0xE3, 0xA0, 0xA5, + 0xAE, 0xA8, 0xE3, 0xE1, 0xAD, 0xAB, 0x20, 0xAE, 0xA5, 0xA0, + 0xA8, 0xAD, 0x2E, 0xE3, 0xAE, 0xA0, 0xA8, 0x20, 0xE0, 0xE3, + 0xAB, 0xE1, 0x20, 0xA4, 0xAD, 0xE2, 0xA1, 0xA6, 0xAC, 0xE1, + 0x0D, 0x20, 0x2E, 0x09, 0xA0, 0xA1, 0x9D, 0xA5 + }; + + int size = 0; + uint cChar = 0; + while ((cChar = *src++) != 0) { + if (cChar & 0x80) { + cChar &= 0x7F; + int index = (cChar & 0x78) >> 3; + *dst++ = decodeTable1[index]; + ++size; + assert(cChar < sizeof(decodeTable2)); + cChar = decodeTable2[cChar]; + } else if (cChar >= 0x70) { + cChar = *src++; + } else if (cChar >= 0x30) { + if (cChar < 0x60) + cChar -= 0x30; + cChar |= 0x80; + } + + *dst++ = cChar; + ++size; + } + + *dst++ = 0; + return size; +} + bool LoLEngine::addCharacter(int id) { const uint16 *cdf[] = { _charDefsMan, _charDefsMan, _charDefsMan, _charDefsWoman, _charDefsMan, _charDefsMan, _charDefsWoman, _charDefsKieran, _charDefsAkshel }; @@ -4547,4 +4598,3 @@ void LoLEngine::generateTempData() { } // End of namespace Kyra #endif // ENABLE_LOL - diff --git a/engines/kyra/lol.h b/engines/kyra/lol.h index 06a4f29f63..164f030a1d 100644 --- a/engines/kyra/lol.h +++ b/engines/kyra/lol.h @@ -363,12 +363,13 @@ private: void showIntro(); struct CharacterPrev { - const char *name; int x, y; int attrib[3]; }; static const CharacterPrev _charPreviews[]; + static const char *const _charPreviewNamesDefault[]; + static const char *const _charPreviewNamesRussianFloppy[]; // PC98 specific data static const uint16 _charPosXPC98[]; @@ -875,6 +876,7 @@ private: char *getLangString(uint16 id); uint8 *getTableEntry(uint8 *buffer, uint16 id); void decodeSjis(const char *src, char *dst); + int decodeCyrillic(const char *src, char *dst); static const char * const _languageExt[]; @@ -1525,4 +1527,3 @@ private: #endif #endif // ENABLE_LOL - diff --git a/engines/kyra/resource.cpp b/engines/kyra/resource.cpp index bc9c93f8ca..a35ec3d81b 100644 --- a/engines/kyra/resource.cpp +++ b/engines/kyra/resource.cpp @@ -366,6 +366,3 @@ void Resource::initializeLoaders() { } } // End of namespace Kyra - - - diff --git a/engines/kyra/resource.h b/engines/kyra/resource.h index 1c69362bfd..c2a697f18d 100644 --- a/engines/kyra/resource.h +++ b/engines/kyra/resource.h @@ -202,6 +202,7 @@ enum KyraResources { k1ConfigStrings, k1AudioTracks, + k1AudioTracks2, k1AudioTracksIntro, k1CreditsStrings, @@ -479,7 +480,3 @@ private: } // End of namespace Kyra #endif - - - - diff --git a/engines/kyra/saveload.cpp b/engines/kyra/saveload.cpp index 80182d949b..42c5d3e8a8 100644 --- a/engines/kyra/saveload.cpp +++ b/engines/kyra/saveload.cpp @@ -113,12 +113,7 @@ KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::Seekab if (header.version >= 14) { if (loadThumbnail) { - header.thumbnail = new Graphics::Surface(); - assert(header.thumbnail); - if (!Graphics::loadThumbnail(*in, *header.thumbnail)) { - delete header.thumbnail; - header.thumbnail = 0; - } + header.thumbnail = Graphics::loadThumbnail(*in); } else { Graphics::skipThumbnail(*in); } @@ -268,4 +263,3 @@ void KyraEngine_v1::loadGameStateCheck(int slot) { } } // End of namespace Kyra - diff --git a/engines/kyra/saveload_hof.cpp b/engines/kyra/saveload_hof.cpp index 645bd2903f..1d28b6bc13 100644 --- a/engines/kyra/saveload_hof.cpp +++ b/engines/kyra/saveload_hof.cpp @@ -329,4 +329,3 @@ Common::Error KyraEngine_HoF::loadGameState(int slot) { } } // End of namespace Kyra - diff --git a/engines/kyra/saveload_lok.cpp b/engines/kyra/saveload_lok.cpp index 34762d4c92..22d412e7f6 100644 --- a/engines/kyra/saveload_lok.cpp +++ b/engines/kyra/saveload_lok.cpp @@ -317,4 +317,3 @@ Common::Error KyraEngine_LoK::saveGameStateIntern(int slot, const char *saveName return Common::kNoError; } } // End of namespace Kyra - diff --git a/engines/kyra/saveload_lol.cpp b/engines/kyra/saveload_lol.cpp index 07842ea358..1bf26477e6 100644 --- a/engines/kyra/saveload_lol.cpp +++ b/engines/kyra/saveload_lol.cpp @@ -472,4 +472,3 @@ Graphics::Surface *LoLEngine::generateSaveThumbnail() const { } // End of namespace Kyra #endif // ENABLE_LOL - diff --git a/engines/kyra/saveload_mr.cpp b/engines/kyra/saveload_mr.cpp index 139375264f..c49a528d02 100644 --- a/engines/kyra/saveload_mr.cpp +++ b/engines/kyra/saveload_mr.cpp @@ -327,4 +327,3 @@ Common::Error KyraEngine_MR::loadGameState(int slot) { } } // End of namespace Kyra - diff --git a/engines/kyra/scene_hof.cpp b/engines/kyra/scene_hof.cpp index 197ef38bf1..f6cd77ca89 100644 --- a/engines/kyra/scene_hof.cpp +++ b/engines/kyra/scene_hof.cpp @@ -95,7 +95,7 @@ void KyraEngine_HoF::enterNewScene(uint16 newScene, int facing, int unk1, int un _emc->run(&_sceneScriptState); } - Common::for_each(_wsaSlots, _wsaSlots+ARRAYSIZE(_wsaSlots), Common::mem_fun(&WSAMovie_v2::close)); + Common::for_each(_wsaSlots, ARRAYEND(_wsaSlots), Common::mem_fun(&WSAMovie_v2::close)); _specialExitCount = 0; memset(_specialExitTable, -1, sizeof(_specialExitTable)); @@ -735,4 +735,3 @@ bool KyraEngine_HoF::lineIsPassable(int x, int y) { } } // End of namespace Kyra - diff --git a/engines/kyra/scene_lok.cpp b/engines/kyra/scene_lok.cpp index 6cb3e2a98a..a926f8493f 100644 --- a/engines/kyra/scene_lok.cpp +++ b/engines/kyra/scene_lok.cpp @@ -1299,4 +1299,3 @@ void KyraEngine_LoK::setupSceneResource(int sceneId) { } } // End of namespace Kyra - diff --git a/engines/kyra/scene_lol.cpp b/engines/kyra/scene_lol.cpp index 165919dff2..a5a2562448 100644 --- a/engines/kyra/scene_lol.cpp +++ b/engines/kyra/scene_lol.cpp @@ -2192,4 +2192,3 @@ void LoLEngine::drawSpecialGuiShape(int pageNum) { } // End of namespace Kyra #endif // ENABLE_LOL - diff --git a/engines/kyra/scene_mr.cpp b/engines/kyra/scene_mr.cpp index 6b234d9a73..74d2e89e6e 100644 --- a/engines/kyra/scene_mr.cpp +++ b/engines/kyra/scene_mr.cpp @@ -83,7 +83,7 @@ void KyraEngine_MR::enterNewScene(uint16 sceneId, int facing, int unk1, int unk2 } _specialExitCount = 0; - Common::set_to(_specialExitTable, _specialExitTable+ARRAYSIZE(_specialExitTable), 0xFFFF); + Common::set_to(_specialExitTable, ARRAYEND(_specialExitTable), 0xFFFF); _mainCharacter.sceneId = sceneId; _sceneList[sceneId].flags &= ~1; @@ -388,7 +388,7 @@ void KyraEngine_MR::initSceneScript(int unk1) { strcat(filename, ".CPS"); _screen->loadBitmap(filename, 3, 3, 0); - Common::set_to(_specialSceneScriptState, _specialSceneScriptState+ARRAYSIZE(_specialSceneScriptState), false); + Common::set_to(_specialSceneScriptState, ARRAYEND(_specialSceneScriptState), false); _sceneEnterX1 = 160; _sceneEnterY1 = 0; _sceneEnterX2 = 296; diff --git a/engines/kyra/scene_v2.cpp b/engines/kyra/scene_v2.cpp index fbddb6604e..061ce4c21a 100644 --- a/engines/kyra/scene_v2.cpp +++ b/engines/kyra/scene_v2.cpp @@ -225,4 +225,3 @@ void KyraEngine_v2::pathfinderFinializePath(int *moveTable, int tableLen, int x, } } // End of namespace Kyra - diff --git a/engines/kyra/screen.cpp b/engines/kyra/screen.cpp index 8f008a58b6..4eae89e0d4 100644 --- a/engines/kyra/screen.cpp +++ b/engines/kyra/screen.cpp @@ -3459,4 +3459,3 @@ uint8 *Palette::fetchRealPalette() const { } } // End of namespace Kyra - diff --git a/engines/kyra/screen.h b/engines/kyra/screen.h index e23f104760..51a9a7f744 100644 --- a/engines/kyra/screen.h +++ b/engines/kyra/screen.h @@ -616,4 +616,3 @@ protected: } // End of namespace Kyra #endif - diff --git a/engines/kyra/screen_hof.cpp b/engines/kyra/screen_hof.cpp index 1282447411..24e0751c0e 100644 --- a/engines/kyra/screen_hof.cpp +++ b/engines/kyra/screen_hof.cpp @@ -146,4 +146,3 @@ void Screen_HoF::copyRegionEx(int srcPage, int srcW, int srcH, int dstPage, int } } // End of namespace Kyra - diff --git a/engines/kyra/screen_hof.h b/engines/kyra/screen_hof.h index 08a9133809..edcb339da9 100644 --- a/engines/kyra/screen_hof.h +++ b/engines/kyra/screen_hof.h @@ -53,4 +53,3 @@ private: } // End of namespace Kyra #endif - diff --git a/engines/kyra/screen_lol.cpp b/engines/kyra/screen_lol.cpp index c6874ca0ed..6d0460e0a1 100644 --- a/engines/kyra/screen_lol.cpp +++ b/engines/kyra/screen_lol.cpp @@ -959,4 +959,3 @@ void Screen_LoL::postProcessCursor(uint8 *data, int w, int h, int pitch) { } // End of namespace Kyra #endif // ENABLE_LOL - diff --git a/engines/kyra/screen_lol.h b/engines/kyra/screen_lol.h index 926183225f..02b78606b9 100644 --- a/engines/kyra/screen_lol.h +++ b/engines/kyra/screen_lol.h @@ -119,4 +119,3 @@ private: #endif #endif // ENABLE_LOL - diff --git a/engines/kyra/screen_v2.cpp b/engines/kyra/screen_v2.cpp index 64fbe2b834..57581fa750 100644 --- a/engines/kyra/screen_v2.cpp +++ b/engines/kyra/screen_v2.cpp @@ -388,4 +388,3 @@ void Screen_v2::checkedPageUpdate(int srcPage, int dstPage) { } } // End of namespace Kyra - diff --git a/engines/kyra/screen_v2.h b/engines/kyra/screen_v2.h index eb8415be78..d85c762038 100644 --- a/engines/kyra/screen_v2.h +++ b/engines/kyra/screen_v2.h @@ -73,4 +73,3 @@ protected: } // End of namespace Kyra #endif - diff --git a/engines/kyra/script.cpp b/engines/kyra/script.cpp index b185b8ed6f..303cbb45aa 100644 --- a/engines/kyra/script.cpp +++ b/engines/kyra/script.cpp @@ -443,4 +443,3 @@ void EMCInterpreter::op_setRetAndJmp(EMCState *script) { } } } // End of namespace Kyra - diff --git a/engines/kyra/script.h b/engines/kyra/script.h index 4250732c7c..5bd75f7b80 100644 --- a/engines/kyra/script.h +++ b/engines/kyra/script.h @@ -140,4 +140,3 @@ private: } // End of namespace Kyra #endif - diff --git a/engines/kyra/script_hof.cpp b/engines/kyra/script_hof.cpp index 27cfc808cc..296cd4002b 100644 --- a/engines/kyra/script_hof.cpp +++ b/engines/kyra/script_hof.cpp @@ -1730,4 +1730,3 @@ void KyraEngine_HoF::setupOpcodeTable() { } } // End of namespace Kyra - diff --git a/engines/kyra/script_lok.cpp b/engines/kyra/script_lok.cpp index 2b90d001ca..4d40971124 100644 --- a/engines/kyra/script_lok.cpp +++ b/engines/kyra/script_lok.cpp @@ -558,7 +558,10 @@ int KyraEngine_LoK::o1_setCustomPaletteRange(EMCState *script) { _screen->copyPalette(0, 12); } } else { - _screen->getPalette(1).copy(_specialPalettes[stackPos(0)], 0, stackPos(2), stackPos(1)); + if (!_specialPalettes[stackPos(0)]) + warning("KyraEngine_LoK::o1_setCustomPaletteRange(): Trying to use missing special palette %d", stackPos(0)); + else + _screen->getPalette(1).copy(_specialPalettes[stackPos(0)], 0, stackPos(2), stackPos(1)); } return 0; } @@ -1956,4 +1959,3 @@ void KyraEngine_LoK::setupOpcodeTable() { #undef Opcode } // End of namespace Kyra - diff --git a/engines/kyra/script_lol.cpp b/engines/kyra/script_lol.cpp index 1afefcffa4..b4b8f00022 100644 --- a/engines/kyra/script_lol.cpp +++ b/engines/kyra/script_lol.cpp @@ -3071,4 +3071,3 @@ void LoLEngine::setupOpcodeTable() { } // End of namespace Kyra #endif // ENABLE_LOL - diff --git a/engines/kyra/script_tim.cpp b/engines/kyra/script_tim.cpp index 6f0f0ab083..83d03d1f63 100644 --- a/engines/kyra/script_tim.cpp +++ b/engines/kyra/script_tim.cpp @@ -1246,4 +1246,3 @@ int TIMInterpreter_LoL::cmd_dialogueBox(const uint16 *param) { #endif // ENABLE_LOL } // End of namespace Kyra - diff --git a/engines/kyra/script_tim.h b/engines/kyra/script_tim.h index 89040720c2..11b716c3a9 100644 --- a/engines/kyra/script_tim.h +++ b/engines/kyra/script_tim.h @@ -317,4 +317,3 @@ private: } // End of namespace Kyra #endif - diff --git a/engines/kyra/script_v1.cpp b/engines/kyra/script_v1.cpp index b12a08a417..4cfbdf8ab8 100644 --- a/engines/kyra/script_v1.cpp +++ b/engines/kyra/script_v1.cpp @@ -123,4 +123,3 @@ int KyraEngine_v1::o1_playSoundEffect(EMCState *script) { } } // End of namespace Kyra - diff --git a/engines/kyra/script_v2.cpp b/engines/kyra/script_v2.cpp index 2e3a3d2bc4..e42cdf9ff4 100644 --- a/engines/kyra/script_v2.cpp +++ b/engines/kyra/script_v2.cpp @@ -340,4 +340,3 @@ int KyraEngine_v2::o2a_setResetFrame(EMCState *script) { } } // End of namespace Kyra - diff --git a/engines/kyra/seqplayer.cpp b/engines/kyra/seqplayer.cpp index ce2eafcea5..531d864293 100644 --- a/engines/kyra/seqplayer.cpp +++ b/engines/kyra/seqplayer.cpp @@ -657,4 +657,3 @@ bool SeqPlayer::playSequence(const uint8 *seqData, bool skipSeq) { } // End of namespace Kyra - diff --git a/engines/kyra/seqplayer.h b/engines/kyra/seqplayer.h index 1f030cde19..12d94e3f6d 100644 --- a/engines/kyra/seqplayer.h +++ b/engines/kyra/seqplayer.h @@ -122,4 +122,3 @@ protected: } // End of namespace Kyra #endif - diff --git a/engines/kyra/sequences_hof.cpp b/engines/kyra/sequences_hof.cpp index e504278047..50b5db78fc 100644 --- a/engines/kyra/sequences_hof.cpp +++ b/engines/kyra/sequences_hof.cpp @@ -2920,5 +2920,3 @@ void KyraEngine_HoF::seq_makeBookAppear() { } } // End of namespace Kyra - - diff --git a/engines/kyra/sequences_lok.cpp b/engines/kyra/sequences_lok.cpp index 5f9bd86724..2de0565a74 100644 --- a/engines/kyra/sequences_lok.cpp +++ b/engines/kyra/sequences_lok.cpp @@ -250,7 +250,7 @@ bool KyraEngine_LoK::seq_introStory() { if (!textEnabled() && speechEnabled() && _flags.lang != Common::IT_ITA) return false; - if ((_flags.lang == Common::EN_ANY && !_flags.isTalkie && _flags.platform == Common::kPlatformPC) || _flags.platform == Common::kPlatformAmiga) + if (((_flags.lang == Common::EN_ANY || _flags.lang == Common::RU_RUS) && !_flags.isTalkie && _flags.platform == Common::kPlatformPC) || _flags.platform == Common::kPlatformAmiga) _screen->loadBitmap("TEXT.CPS", 3, 3, &_screen->getPalette(0)); else if (_flags.lang == Common::EN_ANY || _flags.lang == Common::JA_JPN) _screen->loadBitmap("TEXT_ENG.CPS", 3, 3, &_screen->getPalette(0)); @@ -2112,4 +2112,3 @@ void KyraEngine_LoK::drawJewelsFadeOutEnd(int jewel) { } } // End of namespace Kyra - diff --git a/engines/kyra/sequences_lol.cpp b/engines/kyra/sequences_lol.cpp index 27f3951faf..83d525d400 100644 --- a/engines/kyra/sequences_lol.cpp +++ b/engines/kyra/sequences_lol.cpp @@ -316,8 +316,9 @@ int LoLEngine::chooseCharacter() { _screen->printText(_tim->getCTableEntry(53), 72, 184, 0x81, 0x00); _screen->printText(_tim->getCTableEntry(55), 72, 192, 0x81, 0x00); } else { + const char *const *previewNames = (_flags.lang == Common::RU_RUS && !_flags.isTalkie) ? _charPreviewNamesRussianFloppy : _charPreviewNamesDefault; for (int i = 0; i < 4; ++i) { - _screen->fprintStringIntro("%s", _charPreviews[i].x + 16, _charPreviews[i].y + 36, 0xC0, 0x00, 0x9C, 0x120, _charPreviews[i].name); + _screen->fprintStringIntro("%s", _charPreviews[i].x + 16, _charPreviews[i].y + 36, 0xC0, 0x00, 0x9C, 0x120, previewNames[i]); _screen->fprintStringIntro("%d", _charPreviews[i].x + 21, _charPreviews[i].y + 48, 0x98, 0x00, 0x9C, 0x220, _charPreviews[i].attrib[0]); _screen->fprintStringIntro("%d", _charPreviews[i].x + 21, _charPreviews[i].y + 56, 0x98, 0x00, 0x9C, 0x220, _charPreviews[i].attrib[1]); _screen->fprintStringIntro("%d", _charPreviews[i].x + 21, _charPreviews[i].y + 64, 0x98, 0x00, 0x9C, 0x220, _charPreviews[i].attrib[2]); @@ -1518,4 +1519,3 @@ void LoLEngine::loadOutroShapes(int file, uint8 **storage) { } // End of namespace Kyra #endif // ENABLE_LOL - diff --git a/engines/kyra/sequences_mr.cpp b/engines/kyra/sequences_mr.cpp index b3adc687c2..d546d9c25b 100644 --- a/engines/kyra/sequences_mr.cpp +++ b/engines/kyra/sequences_mr.cpp @@ -235,4 +235,3 @@ void KyraEngine_MR::uninitAnimationShapes(int count, uint8 *filedata) { } } // End of namespace Kyra - diff --git a/engines/kyra/sequences_v2.cpp b/engines/kyra/sequences_v2.cpp index fb61d7cddf..e431e45f10 100644 --- a/engines/kyra/sequences_v2.cpp +++ b/engines/kyra/sequences_v2.cpp @@ -128,4 +128,3 @@ void KyraEngine_v2::processAnimationScript(int allowSkip, int resetChar) { } } // End of namespace Kyra - diff --git a/engines/kyra/sound.cpp b/engines/kyra/sound.cpp index 4da35cc28b..b4fcea784e 100644 --- a/engines/kyra/sound.cpp +++ b/engines/kyra/sound.cpp @@ -276,5 +276,3 @@ const Sound::SpeechCodecs Sound::_supportedCodecs[] = { }; } // End of namespace Kyra - - diff --git a/engines/kyra/sound_adlib.cpp b/engines/kyra/sound_adlib.cpp index 75041b8161..12c980486c 100644 --- a/engines/kyra/sound_adlib.cpp +++ b/engines/kyra/sound_adlib.cpp @@ -2445,4 +2445,3 @@ void SoundAdLibPC::unk2() { } } // End of namespace Kyra - diff --git a/engines/kyra/sound_adlib.h b/engines/kyra/sound_adlib.h index 58b97e3474..962df40de8 100644 --- a/engines/kyra/sound_adlib.h +++ b/engines/kyra/sound_adlib.h @@ -108,4 +108,3 @@ private: } // End of namespace Kyra #endif - diff --git a/engines/kyra/sound_amiga.cpp b/engines/kyra/sound_amiga.cpp index dc09670408..dfb0aa8bf3 100644 --- a/engines/kyra/sound_amiga.cpp +++ b/engines/kyra/sound_amiga.cpp @@ -214,4 +214,3 @@ void SoundAmiga::playSoundEffect(uint8 track) { } } // End of namespace Kyra - diff --git a/engines/kyra/sound_digital.cpp b/engines/kyra/sound_digital.cpp index 3f8eddbb0d..fe0f1fb9bc 100644 --- a/engines/kyra/sound_digital.cpp +++ b/engines/kyra/sound_digital.cpp @@ -544,4 +544,3 @@ const SoundDigital::AudioCodecs SoundDigital::_supportedCodecs[] = { } // End of namespace Kyra - diff --git a/engines/kyra/sound_lol.cpp b/engines/kyra/sound_lol.cpp index 7262635728..efa844968d 100644 --- a/engines/kyra/sound_lol.cpp +++ b/engines/kyra/sound_lol.cpp @@ -312,4 +312,3 @@ int LoLEngine::convertVolumeFromMixer(int value) { } // End of namespace Kyra #endif // ENABLE_LOL - diff --git a/engines/kyra/sound_midi.cpp b/engines/kyra/sound_midi.cpp index 26b6b31d0a..1a5c2f94ac 100644 --- a/engines/kyra/sound_midi.cpp +++ b/engines/kyra/sound_midi.cpp @@ -787,4 +787,3 @@ Common::String SoundMidiPC::getFileName(const Common::String &str) { } } // End of namespace Kyra - diff --git a/engines/kyra/sound_pcspk.cpp b/engines/kyra/sound_pcspk.cpp index 051f36dd1b..8664e2a22e 100644 --- a/engines/kyra/sound_pcspk.cpp +++ b/engines/kyra/sound_pcspk.cpp @@ -364,4 +364,3 @@ const uint8 MidiDriver_PCSpeaker::_noteTable2[] = { }; } // End of namespace Kyra - diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index 012f1f5d7d..c851842f22 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -673,4 +673,3 @@ void SoundTownsPC98_v2::updateVolumeSettings() { } // End of namespace Kyra #undef EUPHONY_FADEOUT_TICKS - diff --git a/engines/kyra/sprites.cpp b/engines/kyra/sprites.cpp index e0d1142905..f4cebf6470 100644 --- a/engines/kyra/sprites.cpp +++ b/engines/kyra/sprites.cpp @@ -573,4 +573,3 @@ int Sprites::getDrawLayer(int y) { return returnValue; } } // End of namespace Kyra - diff --git a/engines/kyra/sprites.h b/engines/kyra/sprites.h index 6a4241f13e..93cdcdbbcb 100644 --- a/engines/kyra/sprites.h +++ b/engines/kyra/sprites.h @@ -97,4 +97,3 @@ protected: } // End of namespace Kyra #endif - diff --git a/engines/kyra/sprites_lol.cpp b/engines/kyra/sprites_lol.cpp index a77fda043c..fbf4c7c5c2 100644 --- a/engines/kyra/sprites_lol.cpp +++ b/engines/kyra/sprites_lol.cpp @@ -1632,4 +1632,3 @@ void LoLEngine::killMonster(MonsterInPlay *monster) { } // End of namespace Kyra #endif // ENABLE_LOL - diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index d56abc5d47..f6d59922b1 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -38,7 +38,7 @@ namespace Kyra { -#define RESFILE_VERSION 74 +#define RESFILE_VERSION 78 namespace { bool checkKyraDat(Common::SeekableReadStream *file) { @@ -80,7 +80,7 @@ const IndexTable iGameTable[] = { }; byte getGameID(const GameFlags &flags) { - return Common::find(iGameTable, iGameTable + ARRAYSIZE(iGameTable) - 1, flags.gameID)->value; + return Common::find(iGameTable, ARRAYEND(iGameTable) - 1, flags.gameID)->value; } const IndexTable iLanguageTable[] = { @@ -90,11 +90,12 @@ const IndexTable iLanguageTable[] = { { Common::ES_ESP, 4 }, { Common::IT_ITA, 5 }, { Common::JA_JPN, 6 }, + { Common::RU_RUS, 7 }, { -1, -1 } }; byte getLanguageID(const GameFlags &flags) { - return Common::find(iLanguageTable, iLanguageTable + ARRAYSIZE(iLanguageTable) - 1, flags.lang)->value; + return Common::find(iLanguageTable, ARRAYEND(iLanguageTable) - 1, flags.lang)->value; } const IndexTable iPlatformTable[] = { @@ -107,11 +108,13 @@ const IndexTable iPlatformTable[] = { }; byte getPlatformID(const GameFlags &flags) { - return Common::find(iPlatformTable, iPlatformTable + ARRAYSIZE(iPlatformTable) - 1, flags.platform)->value; + return Common::find(iPlatformTable, ARRAYEND(iPlatformTable) - 1, flags.platform)->value; } byte getSpecialID(const GameFlags &flags) { - if (flags.isDemo && flags.isTalkie) + if (flags.isOldFloppy) + return 4; + else if (flags.isDemo && flags.isTalkie) return 3; else if (flags.isDemo) return 2; @@ -748,7 +751,17 @@ void KyraEngine_LoK::initStaticResource() { _storyStrings = _staticres->loadStrings(k1PC98StoryStrings, _storyStringsSize); - _soundFiles = _staticres->loadStrings(k1AudioTracks, _soundFilesSize); + int size1, size2; + const char *const *soundfiles1 = _staticres->loadStrings(k1AudioTracks, size1); + const char *const *soundfiles2 = _staticres->loadStrings(k1AudioTracks2, size2); + _soundFilesSize = size1 + size2; + if (_soundFilesSize) { + delete[] _soundFiles; + const char **soundfiles = new const char*[_soundFilesSize]; + for (int i = 0; i < _soundFilesSize; i++) + soundfiles[i] = (i < size1) ? soundfiles1[i] : soundfiles2[i - size1]; + _soundFiles = soundfiles; + } _soundFilesIntro = _staticres->loadStrings(k1AudioTracksIntro, _soundFilesIntroSize); _cdaTrackTable = (const int32 *)_staticres->loadRawData(k1TownsCDATable, _cdaTrackTableSize); @@ -926,7 +939,7 @@ void KyraEngine_LoK::loadButtonShapes() { void KyraEngine_LoK::loadMainScreen(int page) { _screen->clearPage(page); - if ((_flags.lang == Common::EN_ANY && !_flags.isTalkie && _flags.platform == Common::kPlatformPC) || _flags.platform == Common::kPlatformAmiga) + if (((_flags.lang == Common::EN_ANY || _flags.lang == Common::RU_RUS) && !_flags.isTalkie && _flags.platform == Common::kPlatformPC) || _flags.platform == Common::kPlatformAmiga) _screen->loadBitmap("MAIN15.CPS", page, page, &_screen->getPalette(0)); else if (_flags.lang == Common::EN_ANY || _flags.lang == Common::JA_JPN || (_flags.isTalkie && _flags.lang == Common::IT_ITA)) _screen->loadBitmap("MAIN_ENG.CPS", page, page, 0); @@ -2129,4 +2142,3 @@ const int8 KyraEngine_MR::_albumWSAY[] = { }; } // End of namespace Kyra - diff --git a/engines/kyra/staticres_lol.cpp b/engines/kyra/staticres_lol.cpp index cf75a317e1..ca35569afa 100644 --- a/engines/kyra/staticres_lol.cpp +++ b/engines/kyra/staticres_lol.cpp @@ -687,11 +687,25 @@ const char * const LoLEngine::_languageExt[] = { "GER" }; +const char *const LoLEngine::_charPreviewNamesDefault[] = { + "Ak\'shel", + "Michael", + "Kieran", + "Conrad" +}; + +const char *const LoLEngine::_charPreviewNamesRussianFloppy[] = { + "\x80\xAA\xE8\xA5\xAB\0", + "\x8C\xA0\xA9\xAA\xAB\0", + "\x8A\xA8\xE0\xA0\xAD\0", + "\x8A\xAE\xAD\xE0\xA0\xA4\0" +}; + const LoLEngine::CharacterPrev LoLEngine::_charPreviews[] = { - { "Ak\'shel", 0x060, 0x7F, { 0x0F, 0x08, 0x05 } }, - { "Michael", 0x09A, 0x7F, { 0x06, 0x0A, 0x0F } }, - { "Kieran", 0x0D4, 0x7F, { 0x08, 0x06, 0x08 } }, - { "Conrad", 0x10F, 0x7F, { 0x0A, 0x0C, 0x0A } } + { 0x060, 0x7F, { 0x0F, 0x08, 0x05 } }, + { 0x09A, 0x7F, { 0x06, 0x0A, 0x0F } }, + { 0x0D4, 0x7F, { 0x08, 0x06, 0x08 } }, + { 0x10F, 0x7F, { 0x0A, 0x0C, 0x0A } } }; const uint16 LoLEngine::_charPosXPC98[] = { @@ -877,4 +891,3 @@ const int LoLEngine::_outroMonsterScaleTableY[] = { } // End of namespace Kyra #endif - diff --git a/engines/kyra/text.h b/engines/kyra/text.h index a95c2c4abc..199029469e 100644 --- a/engines/kyra/text.h +++ b/engines/kyra/text.h @@ -79,4 +79,3 @@ protected: } // End of namespace Kyra #endif - diff --git a/engines/kyra/text_hof.h b/engines/kyra/text_hof.h index f371fb1898..414d02fe4b 100644 --- a/engines/kyra/text_hof.h +++ b/engines/kyra/text_hof.h @@ -50,4 +50,3 @@ private: } // End of namespace Kyra #endif - diff --git a/engines/kyra/text_lol.cpp b/engines/kyra/text_lol.cpp index 346d5100b8..1c2167b892 100644 --- a/engines/kyra/text_lol.cpp +++ b/engines/kyra/text_lol.cpp @@ -830,4 +830,3 @@ void TextDisplayer_LoL::clearCurDim() { } // End of namespace Kyra #endif // ENABLE_LOL - diff --git a/engines/kyra/text_lol.h b/engines/kyra/text_lol.h index 020d4b5e89..3e59bc90fe 100644 --- a/engines/kyra/text_lol.h +++ b/engines/kyra/text_lol.h @@ -97,4 +97,3 @@ private: #endif #endif // ENABLE_LOL - diff --git a/engines/kyra/text_mr.cpp b/engines/kyra/text_mr.cpp index d690b70266..fd4a00b73c 100644 --- a/engines/kyra/text_mr.cpp +++ b/engines/kyra/text_mr.cpp @@ -898,4 +898,3 @@ void KyraEngine_MR::doDialog(int dlgIndex, int funcNum) { } } // End of namespace Kyra - diff --git a/engines/kyra/timer.h b/engines/kyra/timer.h index e9cb8b2b0c..205be5957d 100644 --- a/engines/kyra/timer.h +++ b/engines/kyra/timer.h @@ -104,4 +104,3 @@ private: } // End of namespace Kyra #endif - diff --git a/engines/kyra/timer_lok.cpp b/engines/kyra/timer_lok.cpp index e1825d027d..555b3680e2 100644 --- a/engines/kyra/timer_lok.cpp +++ b/engines/kyra/timer_lok.cpp @@ -190,4 +190,3 @@ void KyraEngine_LoK::setWalkspeed(uint8 newSpeed) { } } // End of namespace Kyra - diff --git a/engines/kyra/timer_lol.cpp b/engines/kyra/timer_lol.cpp index 4f450f570f..3221556e6d 100644 --- a/engines/kyra/timer_lol.cpp +++ b/engines/kyra/timer_lol.cpp @@ -255,4 +255,3 @@ void LoLEngine::timerFadeMessageText(int timerNum) { } // End of namespace Kyra #endif // ENABLE_LOL - diff --git a/engines/kyra/util.cpp b/engines/kyra/util.cpp index 3776bdc705..f71978d03e 100644 --- a/engines/kyra/util.cpp +++ b/engines/kyra/util.cpp @@ -146,4 +146,3 @@ const uint8 Util::_charMapISOToDOS[128] = { }; } // End of namespace Kyra - diff --git a/engines/kyra/util.h b/engines/kyra/util.h index 042da74cd9..b91f84ad36 100644 --- a/engines/kyra/util.h +++ b/engines/kyra/util.h @@ -46,4 +46,3 @@ private: } // End of namespace Kyra #endif - diff --git a/engines/kyra/wsamovie.cpp b/engines/kyra/wsamovie.cpp index 37102744a8..21ff80f033 100644 --- a/engines/kyra/wsamovie.cpp +++ b/engines/kyra/wsamovie.cpp @@ -459,5 +459,3 @@ int WSAMovie_v2::open(const char *filename, int unk1, Palette *palBuf) { } } // End of namespace Kyra - - diff --git a/engines/kyra/wsamovie.h b/engines/kyra/wsamovie.h index 0d8bfdc869..7dadc9319b 100644 --- a/engines/kyra/wsamovie.h +++ b/engines/kyra/wsamovie.h @@ -132,5 +132,3 @@ protected: } // End of namespace Kyra #endif - - diff --git a/engines/lastexpress/data/snd.cpp b/engines/lastexpress/data/snd.cpp index 28d20df9bd..6845be8808 100644 --- a/engines/lastexpress/data/snd.cpp +++ b/engines/lastexpress/data/snd.cpp @@ -38,7 +38,7 @@ namespace LastExpress { #pragma region Sound filters tables -static const int filterData[1424] = { +static const int stepTable[1424] = { 0, 0, 0, 0, 128, 256, 384, 512, 0, 0, 0, 0, 128, 256, 384, 512, 0, 0, 0, 0, 192, 320, 448, 576, 0, 0, 0, 0, 192, 320, 448, 576, 64, 64, 64, 64, 256, 384, 512, 640, @@ -152,7 +152,7 @@ static const int filterData[1424] = { 4224, 4352, 4480, 4608, 4096, 4096, 4096, 4096, 4288, 4416, 4544, 4672, 4096, 4096, 4096, 4096, 4288, 4416, 4544, 4672, 4160, 4160, 4160, 4160, 4352, 4480, 4608, - 4.6, 4160, 4160, 4160, 4160, 4352, 4480, 4608, 4736, + 4736, 4160, 4160, 4160, 4160, 4352, 4480, 4608, 4736, 4224, 4224, 4224, 4224, 4416, 4544, 4672, 4800, 4224, 4224, 4224, 4224, 4416, 4544, 4672, 4800, 4288, 4288, 4288, 4288, 4480, 4608, 4736, 4864, 4288, 4288, 4288, @@ -195,7 +195,7 @@ static const int filterData[1424] = { 5632 }; -static const int filterData2[1424] = { +static const int imaTable[1424] = { 0, 2, 4, 6, 7, 9, 11, 13, 0, -2, -4, -6, -7, -9, -11, -13, 1, 3, 5, 7, 9, 11, 13, 15, -1, -3, -5, -7, -9, -11, -13, -15, 1, 3, 5, 7, 10, 12, 14, 16, -1, -3, -5, @@ -352,16 +352,20 @@ static const int p2s[17] = { 0, 1, 1, 3, 1, 5, 3, 7, 1, 9, 5, 11, 3, 13, 7, 15, // Last Express ADPCM is similar to MS IMA mono, but inverts its nibbles // and does not have the 4 byte per channel requirement -class LastExpress_ADPCMStream : public Audio::Ima_ADPCMStream { +class LastExpress_ADPCMStream : public Audio::ADPCMStream { public: LastExpress_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, uint32 blockSize, int32 filterId) : - Audio::Ima_ADPCMStream(stream, disposeAfterUse, size, 44100, 1, blockSize) { + Audio::ADPCMStream(stream, disposeAfterUse, size, 44100, 1, blockSize) { _currentFilterId = -1; _nextFilterId = filterId; } int readBuffer(int16 *buffer, const int numSamples) { int samples = 0; + // Temporary data + int step = 0; + int sample = 0; + byte idx = 0; assert(numSamples % 2 == 0); @@ -369,15 +373,37 @@ public: if (_blockPos[0] == _blockAlign) { // read block header _status.ima_ch[0].last = _stream->readSint16LE(); - _status.ima_ch[0].stepIndex = _stream->readSint16LE(); + _status.ima_ch[0].stepIndex = _stream->readSint16LE() << 6; _blockPos[0] = 4; + + // Get current filter + _currentFilterId = _nextFilterId; + _nextFilterId = -1; + + // No filter: skip decoding + if (_currentFilterId == -1) + break; + + // Compute step adjustment + _stepAdjust1 = p1s[_currentFilterId]; + _stepAdjust2 = p2s[_currentFilterId]; } for (; samples < numSamples && _blockPos[0] < _blockAlign && !_stream->eos() && _stream->pos() < _endpos; samples += 2) { byte data = _stream->readByte(); _blockPos[0]++; - buffer[samples] = decodeIMA((data >> 4) & 0x0f); - buffer[samples + 1] = decodeIMA(data & 0x0f); + + // First nibble + idx = data >> 4; + step = stepTable[idx + _status.ima_ch[0].stepIndex / 4]; + sample = CLIP(imaTable[idx + _status.ima_ch[0].stepIndex / 4] + _status.ima_ch[0].last, -32767, 32767); + buffer[samples] = (_stepAdjust2 * sample) >> _stepAdjust1; + + // Second nibble + idx = data & 0xF; + _status.ima_ch[0].stepIndex = stepTable[idx + step / 4]; + _status.ima_ch[0].last = CLIP(imaTable[idx + step / 4] + sample, -32767, 32767); + buffer[samples + 1] = (_stepAdjust2 * _status.ima_ch[0].last) >> _stepAdjust1; } } @@ -387,41 +413,10 @@ public: void setFilterId(int32 filterId) { _nextFilterId = filterId; } private: - int32 _currentFilterId; - int32 _nextFilterId; // the sound filter id, -1 for none - - /** - * Sound filter - * - * @param [in] data If non-null, the input data - * @param [in,out] buffer If non-null, the output buffer. - * @param p1 The first filter input. - * @param p2 The second filter input. - */ - static void soundFilter(byte *data, int16 *buffer, int p1, int p2) { - int data1, data2, data1p, data2p; - byte idx; - - data2 = data[0]; - data1 = data[1] << 6; - - data += 2; - - for (int count = 0; count < 735; count++) { - idx = data[count] >> 4; - - data1p = filterData[idx + data1]; - data2p = CLIP(filterData2[idx + data1] + data2, -32767, 32767); - - buffer[2 * count] = (p2 * data2p) >> p1; - - idx = data[count] & 0xF; - - data1 = filterData[idx + data1p]; - data2 = CLIP(filterData2[idx + data1p] + data2p, -32767, 32767); - buffer[2 * count + 1] = (p2 * data2) >> p1; - } - } + int32 _currentFilterId; + int32 _nextFilterId; // the sound filter id, -1 for none + int32 _stepAdjust1; + int32 _stepAdjust2; }; ////////////////////////////////////////////////////////////////////////// diff --git a/engines/lastexpress/game/savegame.cpp b/engines/lastexpress/game/savegame.cpp index ebada5dd4e..57c18b5697 100644 --- a/engines/lastexpress/game/savegame.cpp +++ b/engines/lastexpress/game/savegame.cpp @@ -45,12 +45,12 @@ namespace LastExpress { static const struct { const char *saveFile; } gameInfo[6] = { - {"blue.egg"}, - {"red.egg"}, - {"green.egg"}, - {"purple.egg"}, - {"teal.egg"}, - {"gold.egg"} + {"lastexpress-blue.egg"}, + {"lastexpress-red.egg"}, + {"lastexpress-green.egg"}, + {"lastexpress-purple.egg"}, + {"lastexpress-teal.egg"}, + {"lastexpress-gold.egg"} }; ////////////////////////////////////////////////////////////////////////// diff --git a/engines/lastexpress/lastexpress.cpp b/engines/lastexpress/lastexpress.cpp index 885ca8b212..250fa0f2d0 100644 --- a/engines/lastexpress/lastexpress.cpp +++ b/engines/lastexpress/lastexpress.cpp @@ -42,6 +42,7 @@ #include "common/debug-channels.h" #include "common/error.h" #include "common/fs.h" +#include "common/timer.h" #include "engines/util.h" @@ -146,7 +147,7 @@ Common::Error LastExpressEngine::run() { // Start sound manager and setup timer _soundMan = new SoundManager(this); - _timer->installTimerProc(&soundTimer, 17000, this); + _timer->installTimerProc(&soundTimer, 17000, this, "lastexpressSound"); // Menu _menu = new Menu(this); diff --git a/engines/lastexpress/lastexpress.h b/engines/lastexpress/lastexpress.h index f8f38788a0..1431b79b9f 100644 --- a/engines/lastexpress/lastexpress.h +++ b/engines/lastexpress/lastexpress.h @@ -27,7 +27,6 @@ #include "lastexpress/eventhandler.h" #include "common/random.h" -#include "common/timer.h" #include "engines/engine.h" diff --git a/engines/lastexpress/module.mk b/engines/lastexpress/module.mk index a11a7c4b67..8b3287d5d7 100644 --- a/engines/lastexpress/module.mk +++ b/engines/lastexpress/module.mk @@ -80,4 +80,4 @@ PLUGIN := 1 endif # Include common rules -include $(srcdir)/rules.mk
\ No newline at end of file +include $(srcdir)/rules.mk diff --git a/engines/lastexpress/shared.h b/engines/lastexpress/shared.h index 7b640c773a..d60a498447 100644 --- a/engines/lastexpress/shared.h +++ b/engines/lastexpress/shared.h @@ -84,29 +84,26 @@ enum SoundFlag { }; enum SoundState { - kSoundState0 = 0, - kSoundState1 = 1, - kSoundState2 = 2 + kSoundStateNone = 0, + kSoundState1 = 1, + kSoundState2 = 2 }; enum SoundStatus { + kSoundStatusClear0 = 0x10, + kSoundStatusFilter = 0x1F, kSoundStatus_20 = 0x20, kSoundStatus_40 = 0x40, + kSoundStatusCached = 0x80, kSoundStatus_180 = 0x180, kSoundStatusClosed = 0x200, kSoundStatus_400 = 0x400, - + kSoundStatusClear4 = 0x800, kSoundStatus_8000 = 0x8000, kSoundStatus_20000 = 0x20000, kSoundStatus_100000 = 0x100000, kSoundStatus_20000000 = 0x20000000, kSoundStatus_40000000 = 0x40000000, - - kSoundStatusClear0 = 0x10, - kSoundStatusFilter = 0x1F, - kSoundStatusCached = 0x80, - kSoundStatusClear3 = 0x200, - kSoundStatusClear4 = 0x800, kSoundStatusClearAll = 0xFFFFFFE0 }; diff --git a/engines/lastexpress/sound/entry.cpp b/engines/lastexpress/sound/entry.cpp index 87d8ccdb30..44cc68a57b 100644 --- a/engines/lastexpress/sound/entry.cpp +++ b/engines/lastexpress/sound/entry.cpp @@ -88,8 +88,8 @@ void SoundEntry::close() { _status.status |= kSoundStatusClosed; // Loop until ready - while (!(_status.status1 & 4) && !(getSoundQueue()->getFlag() & 8) && (getSoundQueue()->getFlag() & 1)) - ; // empty loop body + //while (!(_status.status1 & 4) && !(getSoundQueue()->getFlag() & 8) && (getSoundQueue()->getFlag() & 1)) + // ; // empty loop body // The original game remove the entry from the cache here, // but since we are called from within an iterator loop @@ -290,7 +290,7 @@ bool SoundEntry::updateSound() { } } } - //if (status.status2 & 0x40 && !((uint32)_status.status & 0x180) && v1->soundBuffer) + //if (status.status2 & 0x40 && !((uint32)_status.status & 0x180) && v1->soundBuffer) // Sound_FillSoundBuffer(v1); } result = true; diff --git a/engines/lastexpress/sound/queue.cpp b/engines/lastexpress/sound/queue.cpp index 0a6442ceed..33b4c06793 100644 --- a/engines/lastexpress/sound/queue.cpp +++ b/engines/lastexpress/sound/queue.cpp @@ -102,80 +102,41 @@ void SoundQueue::removeFromQueue(Common::String filename) { } void SoundQueue::updateQueue() { - //Common::StackLock locker(_mutex); - - //warning("[Sound::updateQueue] Not implemented"); - - int maxPriority = 0; - Common::List<SoundEntry *>::iterator lsnd; - SoundEntry *msnd; - - bool loopedPlaying; - - loopedPlaying = 0; - //++g_sound_flag; + Common::StackLock locker(_mutex); - for (lsnd = _soundList.begin(); lsnd != _soundList.end(); ++lsnd) { - if ((*lsnd)->getType() == kSoundType1) - break; - } + ++_flag; - if (getSoundState() & 1) { - if (!(*lsnd) || getFlags()->flag_3 || (*lsnd && (*lsnd)->getTime() > getSound()->getLoopingSoundDuration())) { + if (getSoundState() & kSoundState1) { + SoundEntry *entry = getEntry(kSoundType1); + if (!entry || getFlags()->flag_3 || (entry && entry->getTime() > getSound()->getLoopingSoundDuration())) { getSound()->playLoopingSound(0x45); } else { if (getSound()->getData1() && getSound()->getData2() >= getSound()->getData1()) { - (*lsnd)->update(getSound()->getData0()); + entry->update(getSound()->getData0()); getSound()->setData1(0); } } } - msnd = NULL; - - for (lsnd = _soundList.begin(); lsnd != _soundList.end(); ++lsnd) { - if ((*lsnd)->getStatus().status2 & 0x1) { // Sound is stopped - // original code - //if ((*lsnd)->soundBuffer) - // Sound_RemoveSoundDataFromCache(*lsnd); - //if ((*lsnd)->archive) { - // Archive_SetStatusNotLoaded((*lsnd)->archive); - // (*lsnd)->archive = 0; - // (*lsnd)->field_28 = 3; - //} - - if (_soundList.size() < 6) { - if ((*lsnd)->getStatus().status1 & 0x1F) { - int pri = (*lsnd)->getPriority() + ((*lsnd)->getStatus().status1 & 0x1F); - - if (pri > maxPriority) { - msnd = *lsnd; - maxPriority = pri; - } - } - } - } + for (Common::List<SoundEntry *>::iterator it = _soundList.begin(); it != _soundList.end(); ++it) { + SoundEntry *entry = *it; - if (!(*lsnd)->updateSound() && !((*lsnd)->getStatus().status3 & 0x8)) { - if (msnd == *lsnd) { - maxPriority = 0; - msnd = 0; - } - if (*lsnd) { - (*lsnd)->close(); - SAFE_DELETE(*lsnd); - lsnd = _soundList.reverse_erase(lsnd); - } + // Original removes the entry data from the cache and sets the archive as not loaded + // and if the sound data buffer is not full, loads a new entry to be played based on + // its priority and filter id + + if (!entry->updateSound() && !(entry->getStatus().status3 & 0x8)) { + entry->close(); + SAFE_DELETE(entry); + it = _soundList.reverse_erase(it); } } - - // We don't need this - //if (msnd) - // msnd->updateEntryInternal(); + // Original update the current entry, loading another set of samples to be decoded getFlags()->flag_3 = 0; - //--g_sound_flag; + + --_flag; } void SoundQueue::resetQueue() { @@ -209,17 +170,10 @@ void SoundQueue::resetQueue(SoundType type1, SoundType type2) { } void SoundQueue::clearQueue() { - _flag |= 4; - - // FIXME: Wait a while for a flag to be set - //for (int i = 0; i < 3000000; i++) - // if (_flag & 8) - // break; + Common::StackLock locker(_mutex); _flag |= 8; - Common::StackLock locker(_mutex); - for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) { SoundEntry *entry = (*i); @@ -240,7 +194,7 @@ void SoundQueue::clearStatus() { Common::StackLock locker(_mutex); for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) - (*i)->setStatus((*i)->getStatus().status | kSoundStatusClear3); + (*i)->setStatus((*i)->getStatus().status | kSoundStatusClosed); } ////////////////////////////////////////////////////////////////////////// diff --git a/engines/lastexpress/sound/sound.cpp b/engines/lastexpress/sound/sound.cpp index c04b6d361f..2f7bb4a601 100644 --- a/engines/lastexpress/sound/sound.cpp +++ b/engines/lastexpress/sound/sound.cpp @@ -1305,8 +1305,8 @@ void SoundManager::playLoopingSound(int param) { int partNumber = 1; int fnameLen = 6; - if (_queue->getSoundState() & 1 && param >= 0x45 && param <= 0x46) { - if (_queue->getSoundState() & 2) { + if (_queue->getSoundState() & kSoundState1 && param >= 0x45 && param <= 0x46) { + if (_queue->getSoundState() & kSoundState2) { strcpy(tmp, "STEAM.SND"); _loopingSoundDuration = 32767; diff --git a/engines/lure/module.mk b/engines/lure/module.mk index ba158756b4..57126a6491 100644 --- a/engines/lure/module.mk +++ b/engines/lure/module.mk @@ -31,4 +31,3 @@ endif # Include common rules include $(srcdir)/rules.mk - diff --git a/engines/lure/sound.h b/engines/lure/sound.h index 9fa9a91260..365a7ccdb6 100644 --- a/engines/lure/sound.h +++ b/engines/lure/sound.h @@ -30,10 +30,11 @@ #include "common/mutex.h" #include "common/singleton.h" #include "common/ptr.h" + #include "audio/mididrv.h" -#include "audio/mixer.h" class MidiParser; +class MidiChannel; namespace Lure { diff --git a/engines/m4/converse.cpp b/engines/m4/converse.cpp index 4630d2e2d6..bdce7928ac 100644 --- a/engines/m4/converse.cpp +++ b/engines/m4/converse.cpp @@ -609,7 +609,7 @@ void Converse::loadConversation(const char *convName) { // ---------------------------------------------------------------------------- // Entry action chunks case CHUNK_CASN: // Conditional assign - case CHUNK_ASGN: // Assign + case CHUNK_ASGN: { // Assign curAction = new EntryAction(); if (debugFlag) debugCN(kDebugConversations, "ASGN chunk\n"); curAction->actionType = kAssignValue; @@ -625,9 +625,11 @@ void Converse::loadConversation(const char *convName) { } curAction->targetOffset = convS->readUint32LE(); - assert(convS->readUint32LE() == kOpAssign); + int op = convS->readUint32LE(); + assert(op == kOpAssign); curAction->value = convS->readUint32LE(); break; + } case CHUNK_CCGO: // Conditional go to entry case CHUNK_CHDE: // Conditional hide entry case CHUNK_CUHD: // Conditional unhide entry diff --git a/engines/m4/globals.cpp b/engines/m4/globals.cpp index f4aab8ae8f..7a0b776eb8 100644 --- a/engines/m4/globals.cpp +++ b/engines/m4/globals.cpp @@ -380,6 +380,15 @@ void MadsGlobals::loadMadsObjects() { _vm->res()->toss("objects.dat"); } +int MadsGlobals::getObjectIndex(uint16 descId) { + for (uint i = 0; i < _madsObjects.size(); ++i) { + if (_madsObjects[i].get()->_descId == descId) + return i; + } + + return -1; +} + int MadsGlobals::messageIndexOf(uint32 messageId) { for (uint i = 0; i < _madsMessages.size(); ++i) { diff --git a/engines/m4/globals.h b/engines/m4/globals.h index ae2941c169..693dc9d6c9 100644 --- a/engines/m4/globals.h +++ b/engines/m4/globals.h @@ -297,6 +297,8 @@ public: void loadMadsObjects(); uint32 getObjectsSize() { return _madsObjects.size(); } MadsObject *getObject(uint32 index) { return _madsObjects[index].get(); } + int getObjectIndex(uint16 descId); + int getObjectFolder(uint32 folderId) { warning("TODO: getObjectFolder"); return -1; } void addVisitedScene(int sceneNumber); bool isSceneVisited(int sceneNumber); diff --git a/engines/m4/m4.h b/engines/m4/m4.h index 46107cb20a..b40ba0e878 100644 --- a/engines/m4/m4.h +++ b/engines/m4/m4.h @@ -26,7 +26,6 @@ #include "common/scummsys.h" #include "common/util.h" #include "common/random.h" -#include "audio/mididrv.h" #include "engines/engine.h" diff --git a/engines/m4/mads_logic.cpp b/engines/m4/mads_logic.cpp index cc28a26e68..335127393e 100644 --- a/engines/m4/mads_logic.cpp +++ b/engines/m4/mads_logic.cpp @@ -199,6 +199,10 @@ uint32 MadsSceneLogic::getDataValue(int dataId) { return getActiveAnimationBool(); case 11: return getAnimationCurrentFrame(); + case 12: + return _madsVm->scene()->_action._inProgress; + case 13: + return _madsVm->globals()->_difficultyLevel; default: // All other data variables get stored in the hash table return _madsVm->globals()->_dataMap[dataId]; @@ -239,6 +243,12 @@ void MadsSceneLogic::setDataValue(int dataId, uint16 dataValue) { case 11: error("Tried to set read only data field %d", dataId); break; + case 12: + _madsVm->scene()->_action._inProgress = dataValue != 0; + break; + case 13: + _madsVm->globals()->_difficultyLevel = dataValue; + break; default: // All other data variables get stored in the hash table _madsVm->globals()->_dataMap[dataId] = dataValue; @@ -986,6 +996,37 @@ void MadsSceneLogic::callSubroutine(int subIndex, Common::Stack<ScriptVar> &stac break; } + case 27: { + // object_get_id_from_desc + EXTRACT_PARAMS(1); + stack.push(_madsVm->globals()->getObjectIndex(p[0])); + break; + } + + case 28: { + // object_get_folder + EXTRACT_PARAMS(1); + stack.push(_madsVm->globals()->getObjectFolder(p[0])); + break; + } + + case 29: + // inventory_remove + EXTRACT_PARAMS(1); + _madsVm->scene()->getInterface()->addObjectToInventory(p[0]); + break; + + case 30: + // image_inter_list_call + EXTRACT_PARAMS(1); + warning("TODO: image_inter_list_call"); + break; + + case 31: + // dialog_flags_show + warning("todo: dialog_flags_show"); + break; + default: error("Unknown subroutine %d called", subIndex); break; diff --git a/engines/m4/midi.h b/engines/m4/midi.h index 6eef907ce3..817150fd81 100644 --- a/engines/m4/midi.h +++ b/engines/m4/midi.h @@ -57,4 +57,3 @@ protected: } // End of namespace M4 #endif - diff --git a/engines/m4/saveload.cpp b/engines/m4/saveload.cpp index aa35385bfe..a7615fa4b6 100644 --- a/engines/m4/saveload.cpp +++ b/engines/m4/saveload.cpp @@ -96,7 +96,8 @@ SaveGameList *SaveLoad::getSaves() { result->push_back(Common::String()); } else { // Skip over byte offset - assert(saveFile->readUint32LE() < 0x100); + uint32 offset = saveFile->readUint32LE(); + assert(offset < 0x100); // Read in savegame name saveFile->read(&saveName[0], MAX_SAVEGAME_NAME); diff --git a/engines/m4/scripttab.h b/engines/m4/scripttab.h index b6156f0b82..3264ae743c 100644 --- a/engines/m4/scripttab.h +++ b/engines/m4/scripttab.h @@ -133,4 +133,3 @@ VARIABLE(kInterfaceVisible) }; #undef VARIABLE - 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/console.cpp b/engines/mohawk/console.cpp index e7dc84606c..0234c86c7e 100644 --- a/engines/mohawk/console.cpp +++ b/engines/mohawk/console.cpp @@ -117,7 +117,7 @@ static const char *mystStackNames[12] = { static const uint16 default_start_card[12] = { 3137, 10000, - 2001, // TODO: Should be 2000? + 2000, 5038, 2, // TODO: Should be 1? 1, diff --git a/engines/mohawk/cstime.h b/engines/mohawk/cstime.h index 3a1de6a137..0bc236f930 100644 --- a/engines/mohawk/cstime.h +++ b/engines/mohawk/cstime.h @@ -30,8 +30,6 @@ #include "common/random.h" #include "common/list.h" -#include "audio/mixer.h" - namespace Mohawk { class CSTimeCase; 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 6cb455917e..4461a30ad4 100644 --- a/engines/mohawk/dialogs.cpp +++ b/engines/mohawk/dialogs.cpp @@ -81,14 +81,17 @@ enum { kTransCmd = 'TRAN', kWaterCmd = 'WATR', kDropCmd = 'DROP', - kMapCmd = 'SMAP' + kMapCmd = 'SMAP', + kMenuCmd = 'MENU' }; #ifdef ENABLE_MYST MystOptionsDialog::MystOptionsDialog(MohawkEngine_Myst* vm) : GUI::OptionsDialog("", 120, 120, 360, 200), _vm(vm) { + // I18N: Option for fast scene switching _zipModeCheckbox = new GUI::CheckboxWidget(this, 15, 10, 300, 15, _("~Z~ip Mode Activated"), 0, kZipCmd); _transitionsCheckbox = new GUI::CheckboxWidget(this, 15, 30, 300, 15, _("~T~ransitions Enabled"), 0, kTransCmd); + // I18N: Drop book page _dropPageButton = new GUI::ButtonWidget(this, 15, 60, 100, 25, _("~D~rop Page"), 0, kDropCmd); // Myst ME only has maps @@ -97,6 +100,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 +122,15 @@ 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); + _zipModeCheckbox->setState(_vm->_gameState->_globals.zipMode); _transitionsCheckbox->setState(_vm->_gameState->_globals.transitions); } @@ -133,6 +151,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/livingbooks.cpp b/engines/mohawk/livingbooks.cpp index f9d18ff7ff..65073bd970 100644 --- a/engines/mohawk/livingbooks.cpp +++ b/engines/mohawk/livingbooks.cpp @@ -204,9 +204,12 @@ Common::Error MohawkEngine_LivingBooks::run() { break; case Common::EVENT_LBUTTONDOWN: - for (uint16 i = 0; i < _items.size(); i++) - if (_items[i]->contains(event.mouse)) - found = _items[i]; + for (Common::List<LBItem *>::const_iterator i = _orderedItems.begin(); i != _orderedItems.end(); ++i) { + if ((*i)->contains(event.mouse)) { + found = *i; + break; + } + } if (found) found->handleMouseDown(event.mouse); @@ -341,6 +344,7 @@ void MohawkEngine_LivingBooks::destroyPage() { delete _page; assert(_items.empty()); + assert(_orderedItems.empty()); _page = NULL; _notifyEvents.clear(); @@ -567,6 +571,7 @@ void MohawkEngine_LivingBooks::updatePage() { case kLBDelayedEventDestroy: _items.remove_at(i); i--; + _orderedItems.remove(delayedEvent.item); delete delayedEvent.item; _page->itemDestroyed(delayedEvent.item); if (_focus == delayedEvent.item) @@ -613,6 +618,8 @@ void MohawkEngine_LivingBooks::removeArchive(Archive *archive) { void MohawkEngine_LivingBooks::addItem(LBItem *item) { _items.push_back(item); + _orderedItems.push_front(item); + item->_iterator = _orderedItems.begin(); } void MohawkEngine_LivingBooks::removeItems(const Common::Array<LBItem *> &items) { @@ -626,6 +633,7 @@ void MohawkEngine_LivingBooks::removeItems(const Common::Array<LBItem *> &items) break; } assert(found); + _orderedItems.erase(items[i]->_iterator); } } @@ -1319,8 +1327,13 @@ void MohawkEngine_LivingBooks::handleNotify(NotifyEvent &event) { if (getGameType() == GType_LIVINGBOOKSV1) { debug(2, "kLBNotifyChangeMode: %d", event.param); quitGame(); - } else { - debug(2, "kLBNotifyChangeMode: mode %d, page %d.%d", + break; + } + + debug(2, "kLBNotifyChangeMode: v2 type %d", event.param); + switch (event.param) { + case 1: + debug(2, "kLBNotifyChangeMode:, mode %d, page %d.%d", event.newMode, event.newPage, event.newSubpage); // TODO: what is entry.newUnknown? if (!event.newMode) @@ -1331,6 +1344,13 @@ void MohawkEngine_LivingBooks::handleNotify(NotifyEvent &event) { error("kLBNotifyChangeMode failed to move to mode %d, page %d.%d", event.newMode, event.newPage, event.newSubpage); } + break; + case 3: + debug(2, "kLBNotifyChangeMode: new cursor '%s'", event.newCursor.c_str()); + _cursor->setCursor(event.newCursor); + break; + default: + error("unknown v2 kLBNotifyChangeMode type %d", event.param); } break; @@ -2084,16 +2104,32 @@ LBScriptEntry *LBItem::parseScriptEntry(uint16 type, uint16 &size, Common::Memor } if (type == kLBNotifyScript && entry->opcode == kLBNotifyChangeMode && _vm->getGameType() != GType_LIVINGBOOKSV1) { - if (size < 8) { - error("%d unknown bytes in notify entry kLBNotifyChangeMode", size); + switch (entry->param) { + case 1: + if (size < 8) + error("%d unknown bytes in notify entry kLBNotifyChangeMode", size); + entry->newUnknown = stream->readUint16(); + entry->newMode = stream->readUint16(); + entry->newPage = stream->readUint16(); + entry->newSubpage = stream->readUint16(); + debug(4, "kLBNotifyChangeMode: unknown %04x, mode %d, page %d.%d", + entry->newUnknown, entry->newMode, entry->newPage, entry->newSubpage); + size -= 8; + break; + case 3: + { + Common::String newCursor = _vm->readString(stream); + entry->newCursor = newCursor; + if (size < newCursor.size() + 1) + error("failed to read newCursor in notify entry"); + size -= newCursor.size() + 1; + debug(4, "kLBNotifyChangeMode: new cursor '%s'", newCursor.c_str()); + } + break; + default: + // the original engine also does something when param==2 (but not a notify) + error("unknown v2 kLBNotifyChangeMode type %d", entry->param); } - entry->newUnknown = stream->readUint16(); - entry->newMode = stream->readUint16(); - entry->newPage = stream->readUint16(); - entry->newSubpage = stream->readUint16(); - debug(4, "kLBNotifyChangeMode: unknown %04x, mode %d, page %d.%d", - entry->newUnknown, entry->newMode, entry->newPage, entry->newSubpage); - size -= 8; } if (entry->opcode == kLBOpSendExpression) { if (size < 4) @@ -2577,6 +2613,7 @@ void LBItem::runScript(uint event, uint16 data, uint16 from) { notifyEvent.newMode = entry->newMode; notifyEvent.newPage = entry->newPage; notifyEvent.newSubpage = entry->newSubpage; + notifyEvent.newCursor = entry->newCursor; _vm->addNotifyEvent(notifyEvent); } else _vm->addNotifyEvent(NotifyEvent(entry->opcode, entry->param)); diff --git a/engines/mohawk/livingbooks.h b/engines/mohawk/livingbooks.h index ad2fe56a52..008a7dbf23 100644 --- a/engines/mohawk/livingbooks.h +++ b/engines/mohawk/livingbooks.h @@ -33,8 +33,6 @@ #include "common/queue.h" #include "common/random.h" -#include "audio/mixer.h" - #include "livingbooks_code.h" namespace Common { @@ -133,7 +131,9 @@ enum { kLBEventMouseUp = 5, kLBEventPhaseMain = 6, kLBEventNotified = 7, + kLBEventDragStart = 8, kLBEventDragMove = 9, + kLBEventDragEnd = 0xa, kLBEventRolloverBegin = 0xb, kLBEventRolloverMove = 0xc, kLBEventRolloverEnd = 0xd, @@ -271,6 +271,7 @@ struct LBScriptEntry { uint16 newMode; uint16 newPage; uint16 newSubpage; + Common::String newCursor; // kLBEventNotified uint16 matchFrom; @@ -405,6 +406,8 @@ public: uint16 getSoundPriority() { return _soundMode; } bool isAmbient() { return _isAmbient; } + Common::List<LBItem *>::iterator _iterator; + protected: MohawkEngine_LivingBooks *_vm; LBPage *_page; @@ -608,6 +611,7 @@ struct NotifyEvent { uint16 newMode; uint16 newPage; uint16 newSubpage; + Common::String newCursor; }; enum DelayedEventType { @@ -667,7 +671,7 @@ public: GUI::Debugger *getDebugger() { return _console; } void addArchive(Archive *archive); - void removeArchive(Archive *Archive); + void removeArchive(Archive *archive); void addItem(LBItem *item); void removeItems(const Common::Array<LBItem *> &items); @@ -714,6 +718,7 @@ private: uint16 _phase; LBPage *_page; Common::Array<LBItem *> _items; + Common::List<LBItem *> _orderedItems; Common::Queue<DelayedEvent> _eventQueue; LBItem *_focus; void destroyPage(); diff --git a/engines/mohawk/livingbooks_code.cpp b/engines/mohawk/livingbooks_code.cpp index e9ef2516e2..80b5fe9660 100644 --- a/engines/mohawk/livingbooks_code.cpp +++ b/engines/mohawk/livingbooks_code.cpp @@ -686,8 +686,8 @@ struct CodeCommandInfo { CodeCommandInfo generalCommandInfo[NUM_GENERAL_COMMANDS] = { { "eval", &LBCode::cmdEval }, { "random", &LBCode::cmdRandom }, - { "stringLen", 0 }, - { "substring", 0 }, + { "stringLen", &LBCode::cmdStringLen }, + { "substring", &LBCode::cmdSubstring }, { "max", 0 }, { "min", 0 }, { "abs", 0 }, @@ -861,6 +861,31 @@ void LBCode::cmdRandom(const Common::Array<LBValue> ¶ms) { _stack.push(_vm->_rnd->getRandomNumberRng(min, max)); } +void LBCode::cmdStringLen(const Common::Array<LBValue> ¶ms) { + if (params.size() != 1) + error("incorrect number of parameters (%d) to stringLen", params.size()); + + const Common::String &string = params[0].toString(); + _stack.push(string.size()); +} + +void LBCode::cmdSubstring(const Common::Array<LBValue> ¶ms) { + if (params.size() != 3) + error("incorrect number of parameters (%d) to substring", params.size()); + + const Common::String &string = params[0].toString(); + uint begin = params[1].toInt(); + uint end = params[2].toInt(); + if (begin == 0) + error("invalid substring call (%d to %d)", begin, end); + if (begin > end || end > string.size()) { + _stack.push(Common::String()); + return; + } + Common::String substring(string.c_str() + (begin - 1), end - begin + 1); + _stack.push(substring); +} + void LBCode::cmdGetRect(const Common::Array<LBValue> ¶ms) { if (params.size() < 2) { _stack.push(getRectFromParams(params)); @@ -1156,8 +1181,8 @@ bool LBCode::parseCodeSymbol(const Common::String &name, uint &pos, Common::Arra // first, check whether the name matches a known function for (uint i = 0; i < 2; i++) { byte cmdToken; - CodeCommandInfo *cmdInfo; - uint cmdCount; + CodeCommandInfo *cmdInfo = NULL; + uint cmdCount = 0; switch (i) { case 0: diff --git a/engines/mohawk/livingbooks_code.h b/engines/mohawk/livingbooks_code.h index 9c58ed7a46..79c9af94f7 100644 --- a/engines/mohawk/livingbooks_code.h +++ b/engines/mohawk/livingbooks_code.h @@ -222,6 +222,8 @@ public: void cmdUnimplemented(const Common::Array<LBValue> ¶ms); void cmdEval(const Common::Array<LBValue> ¶ms); void cmdRandom(const Common::Array<LBValue> ¶ms); + void cmdStringLen(const Common::Array<LBValue> ¶ms); + void cmdSubstring(const Common::Array<LBValue> ¶ms); void cmdGetRect(const Common::Array<LBValue> ¶ms); void cmdTopLeft(const Common::Array<LBValue> ¶ms); void cmdBottomRight(const Common::Array<LBValue> ¶ms); diff --git a/engines/mohawk/mohawk.cpp b/engines/mohawk/mohawk.cpp index faf52595b7..cb419064c0 100644 --- a/engines/mohawk/mohawk.cpp +++ b/engines/mohawk/mohawk.cpp @@ -31,8 +31,6 @@ #include "mohawk/sound.h" #include "mohawk/video.h" -#include "audio/mixer.h" - namespace Mohawk { MohawkEngine::MohawkEngine(OSystem *syst, const MohawkGameDescription *gamedesc) : Engine(syst), _gameDescription(gamedesc) { diff --git a/engines/mohawk/myst.cpp b/engines/mohawk/myst.cpp index 6bdf163a91..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; @@ -441,6 +447,7 @@ void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcS _scriptParser = new MystStacks::Credits(this); break; case kDemoStack: + _gameState->_globals.currentAge = 0; _scriptParser = new MystStacks::Demo(this); break; case kDniStack: @@ -469,6 +476,7 @@ void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcS _scriptParser = new MystStacks::Selenitic(this); break; case kDemoSlidesStack: + _gameState->_globals.currentAge = 1; _scriptParser = new MystStacks::Slides(this); break; case kStoneshipStack: @@ -645,7 +653,11 @@ void MohawkEngine_Myst::changeToCard(uint16 card, bool updateScreen) { for (uint16 i = 0; i < _resources.size(); i++) _resources[i]->handleCardChange(); - // TODO: Handle Script Resources + // The demo resets the cursor at each card change except when in the library + if (getFeatures() & GF_DEMO + && _gameState->_globals.currentAge != 2) { + _cursor->setDefaultCursor(); + } // Make sure the screen is updated if (updateScreen) { 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_scripts.cpp b/engines/mohawk/myst_scripts.cpp index 307be2dd05..ca8e985491 100644 --- a/engines/mohawk/myst_scripts.cpp +++ b/engines/mohawk/myst_scripts.cpp @@ -500,7 +500,7 @@ void MystScriptParser::o_disableAreas(uint16 op, uint16 var, uint16 argc, uint16 resource = _vm->_resources[argv[i + 1]]; if (resource) - resource->setEnabled(true); + resource->setEnabled(false); else warning("Unknown Resource in disableAreas script Opcode"); } 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 37b749f100..1b72c85d96 100644 --- a/engines/mohawk/myst_stacks/preview.cpp +++ b/engines/mohawk/myst_stacks/preview.cpp @@ -20,6 +20,7 @@ * */ +#include "mohawk/cursors.h" #include "mohawk/myst.h" #include "mohawk/graphics.h" #include "mohawk/myst_areas.h" @@ -35,6 +36,7 @@ namespace MystStacks { Preview::Preview(MohawkEngine_Myst *vm) : Myst(vm) { setupOpcodes(); + _vm->_cursor->hideCursor(); } Preview::~Preview() { @@ -52,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 72b299ee6d..943cb90071 100644 --- a/engines/mohawk/myst_stacks/slides.cpp +++ b/engines/mohawk/myst_stacks/slides.cpp @@ -20,6 +20,7 @@ * */ +#include "mohawk/cursors.h" #include "mohawk/myst.h" #include "mohawk/graphics.h" #include "mohawk/myst_areas.h" @@ -35,6 +36,7 @@ namespace MystStacks { Slides::Slides(MohawkEngine_Myst *vm) : MystScriptParser(vm) { setupOpcodes(); + _vm->_cursor->hideCursor(); } Slides::~Slides() { @@ -59,23 +61,28 @@ void Slides::disablePersistentScripts() { void Slides::runPersistentScripts() { if (_cardSwapEnabled) { // Used on Cards... - if (_vm->_system->getMillis() - _lastCardTime >= 2 * 1000) + 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) { - _vm->changeToStack(kDemoStack, 2001, 0, 0); + 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) { - // Used on Cards... - if (argc == 1) { - _nextCardID = argv[0]; - _lastCardTime = _vm->_system->getMillis(); - _cardSwapEnabled = true; - } else - unknown(op, var, argc, argv); + _nextCardID = argv[0]; + + debugC(kDebugScript, "Opcode %d: Set next card %d", op, _nextCardID); + + _nextCardTime = _vm->_system->getMillis() + 5000; + _cardSwapEnabled = true; } } // End of namespace MystStacks diff --git a/engines/mohawk/myst_stacks/slides.h b/engines/mohawk/myst_stacks/slides.h index 8bc61d0e24..9fb76728b6 100644 --- a/engines/mohawk/myst_stacks/slides.h +++ b/engines/mohawk/myst_stacks/slides.h @@ -52,7 +52,7 @@ private: bool _cardSwapEnabled; uint16 _nextCardID; - uint32 _lastCardTime; + uint32 _nextCardTime; }; } // End of namespace MystStacks diff --git a/engines/mohawk/myst_state.cpp b/engines/mohawk/myst_state.cpp index bab4b8dd51..3a8d233a26 100644 --- a/engines/mohawk/myst_state.cpp +++ b/engines/mohawk/myst_state.cpp @@ -320,6 +320,10 @@ void MystGameState::deleteSave(const Common::String &saveName) { void MystGameState::addZipDest(uint16 stack, uint16 view) { ZipDests *zipDests = 0; + // The demo has no zip dest storage + if (_vm->getFeatures() & GF_DEMO) + return; + // Select stack switch (stack) { case kChannelwoodStack: @@ -362,6 +366,10 @@ bool MystGameState::isReachableZipDest(uint16 stack, uint16 view) { if (!_globals.zipMode) return false; + // The demo has no zip dest storage + if (_vm->getFeatures() & GF_DEMO) + return false; + // Select stack ZipDests *zipDests; switch (stack) { 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 791b18db49..f92bebf10e 100644 --- a/engines/mohawk/sound.cpp +++ b/engines/mohawk/sound.cpp @@ -20,19 +20,20 @@ * */ -#include "mohawk/sound.h" - #include "common/debug.h" #include "common/system.h" #include "common/util.h" #include "common/textconsole.h" +#include "audio/midiparser.h" #include "audio/musicplugin.h" #include "audio/audiostream.h" #include "audio/decoders/mp3.h" #include "audio/decoders/raw.h" #include "audio/decoders/wave.h" +#include "mohawk/sound.h" + namespace Mohawk { Sound::Sound(MohawkEngine* vm) : _vm(vm) { @@ -84,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/mohawk/sound.h b/engines/mohawk/sound.h index 593f2fcd0b..12a59cdedf 100644 --- a/engines/mohawk/sound.h +++ b/engines/mohawk/sound.h @@ -27,14 +27,15 @@ #include "common/str.h" #include "audio/audiostream.h" -#include "audio/decoders/adpcm.h" -#include "audio/mididrv.h" -#include "audio/midiparser.h" #include "audio/mixer.h" +#include "audio/decoders/adpcm.h" #include "mohawk/mohawk.h" #include "mohawk/resource.h" +class MidiDriver; +class MidiParser; + namespace Mohawk { #define MAX_CHANNELS 2 // Can there be more than 2? diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h index 3eea1e871a..dacf7715ae 100644 --- a/engines/parallaction/graphics.h +++ b/engines/parallaction/graphics.h @@ -560,12 +560,3 @@ protected: #endif - - - - - - - - - diff --git a/engines/parallaction/gui_br.cpp b/engines/parallaction/gui_br.cpp index d1361a6e8c..56148d78d8 100644 --- a/engines/parallaction/gui_br.cpp +++ b/engines/parallaction/gui_br.cpp @@ -548,4 +548,3 @@ void Parallaction_br::startIngameMenu() { } // namespace Parallaction - diff --git a/engines/parallaction/sound.h b/engines/parallaction/sound.h index d0b5e5c175..e875e69334 100644 --- a/engines/parallaction/sound.h +++ b/engines/parallaction/sound.h @@ -26,10 +26,9 @@ #include "common/util.h" #include "common/mutex.h" +#include "audio/mixer.h" #include "audio/audiostream.h" #include "audio/decoders/iff_sound.h" -#include "audio/mixer.h" -#include "audio/mididrv.h" #define PATH_LEN 200 diff --git a/engines/queen/command.h b/engines/queen/command.h index aa72537a9f..6865aa80a2 100644 --- a/engines/queen/command.h +++ b/engines/queen/command.h @@ -234,4 +234,3 @@ private: } // End of namespace Queen #endif - diff --git a/engines/queen/credits.cpp b/engines/queen/credits.cpp index d503562601..43e3bc7c6a 100644 --- a/engines/queen/credits.cpp +++ b/engines/queen/credits.cpp @@ -141,4 +141,3 @@ void Credits::update() { } // End of namespace Queen - diff --git a/engines/saga/actor.h b/engines/saga/actor.h index a4f475660d..d9d4b70168 100644 --- a/engines/saga/actor.h +++ b/engines/saga/actor.h @@ -650,7 +650,7 @@ private: public: #ifdef ACTOR_DEBUG #ifndef SAGA_DEBUG - you must also define SAGA_DEBUG + #error You must also define SAGA_DEBUG #endif //path debug - use with care struct DebugPoint { diff --git a/engines/saga/detection.cpp b/engines/saga/detection.cpp index 7a98fe4164..091ec8d427 100644 --- a/engines/saga/detection.cpp +++ b/engines/saga/detection.cpp @@ -67,9 +67,6 @@ int SagaEngine::getGameId() const { return _gameDescription->gameId; } uint32 SagaEngine::getFeatures() const { uint32 result = _gameDescription->features; - if (_gf_wyrmkeep) - result |= GF_WYRMKEEP; - return result; } @@ -259,13 +256,7 @@ SaveStateDescriptor SagaMetaEngine::querySaveMetaInfos(const char *target, int s desc.setWriteProtectedFlag(false); if (version >= 6) { - Graphics::Surface *thumbnail = new Graphics::Surface(); - assert(thumbnail); - if (!Graphics::loadThumbnail(*in, *thumbnail)) { - delete thumbnail; - thumbnail = 0; - } - + Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*in); desc.setThumbnail(thumbnail); uint32 saveDate = in->readUint32BE(); diff --git a/engines/saga/detection_tables.h b/engines/saga/detection_tables.h index ab73fcba6e..3e83c30eef 100644 --- a/engines/saga/detection_tables.h +++ b/engines/saga/detection_tables.h @@ -221,7 +221,7 @@ static const SAGAGameDescription gameDescriptions[] = { GUIO_NOSPEECH }, GID_ITE, - GF_WYRMKEEP | GF_SCENE_SUBSTITUTES | GF_MONO_MUSIC | GF_LE_VOICES, + 0, ITE_DEFAULT_SCENE, &ITE_Resources, ARRAYSIZE(ITEWINDEMO_GameFonts), @@ -247,7 +247,7 @@ static const SAGAGameDescription gameDescriptions[] = { GUIO_NOSPEECH }, GID_ITE, - GF_WYRMKEEP | GF_LE_VOICES, + 0, ITE_DEFAULT_SCENE, &ITE_Resources, ARRAYSIZE(ITEWINDEMO_GameFonts), @@ -273,7 +273,7 @@ static const SAGAGameDescription gameDescriptions[] = { GUIO_NONE }, GID_ITE, - GF_WYRMKEEP | GF_SCENE_SUBSTITUTES, + 0, ITE_DEFAULT_SCENE, &ITE_Resources, ARRAYSIZE(ITEWINDEMO_GameFonts), @@ -299,7 +299,7 @@ static const SAGAGameDescription gameDescriptions[] = { GUIO_NONE }, GID_ITE, - GF_WYRMKEEP | GF_8BIT_UNSIGNED_PCM, + GF_8BIT_UNSIGNED_PCM, ITE_DEFAULT_SCENE, &ITE_Resources, ARRAYSIZE(ITEWINDEMO_GameFonts), @@ -328,7 +328,7 @@ static const SAGAGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformMacintosh, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_ITE, @@ -352,11 +352,11 @@ static const SAGAGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformMacintosh, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_ITE, - GF_WYRMKEEP, + 0, ITE_DEFAULT_SCENE, &ITE_Resources, ARRAYSIZE(ITEWINDEMO_GameFonts), @@ -384,11 +384,11 @@ static const SAGAGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformUnknown, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_ITE, - GF_WYRMKEEP, + 0, ITE_DEFAULT_SCENE, &ITE_Resources, ARRAYSIZE(ITE_GameFonts), @@ -414,11 +414,11 @@ static const SAGAGameDescription gameDescriptions[] = { }, Common::IT_ITA, Common::kPlatformUnknown, - ADGF_NO_FLAGS, + ADGF_CD, GUIO_NONE }, GID_ITE, - GF_WYRMKEEP, + 0, ITE_DEFAULT_SCENE, &ITE_Resources, ARRAYSIZE(ITE_GameFonts), @@ -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/saga/input.cpp b/engines/saga/input.cpp index 69a353da9f..8576a3e536 100644 --- a/engines/saga/input.cpp +++ b/engines/saga/input.cpp @@ -158,4 +158,3 @@ Point SagaEngine::mousePos() const { } } // End of namespace Saga - diff --git a/engines/saga/interface.cpp b/engines/saga/interface.cpp index 08c5ddc6f9..fe37ed8995 100644 --- a/engines/saga/interface.cpp +++ b/engines/saga/interface.cpp @@ -320,7 +320,7 @@ Interface::Interface(SagaEngine *vm) : _vm(vm) { _disableAbortSpeeches = false; // set save game reminder alarm - _vm->getTimerManager()->installTimerProc(&saveReminderCallback, TIMETOSAVE, this); + _vm->getTimerManager()->installTimerProc(&saveReminderCallback, TIMETOSAVE, this, "sagaSaveReminder"); } Interface::~Interface() { @@ -335,7 +335,7 @@ void Interface::updateSaveReminder() { _saveReminderState = _saveReminderState % _vm->getDisplayInfo().saveReminderNumSprites + 1; drawStatusBar(); _vm->getTimerManager()->removeTimerProc(&saveReminderCallback); - _vm->getTimerManager()->installTimerProc(&saveReminderCallback, ((_vm->getGameId() == GID_ITE) ? TIMETOBLINK_ITE : TIMETOBLINK_IHNM), this); + _vm->getTimerManager()->installTimerProc(&saveReminderCallback, ((_vm->getGameId() == GID_ITE) ? TIMETOBLINK_ITE : TIMETOBLINK_IHNM), this, "sagaSaveReminder"); } } @@ -1390,7 +1390,7 @@ void Interface::setSave(PanelButton *panelButton) { void Interface::resetSaveReminder() { _vm->getTimerManager()->removeTimerProc(&saveReminderCallback); - _vm->getTimerManager()->installTimerProc(&saveReminderCallback, TIMETOSAVE, this); + _vm->getTimerManager()->installTimerProc(&saveReminderCallback, TIMETOSAVE, this, "sagaSaveReminder"); setSaveReminderState(1); } diff --git a/engines/saga/introproc_ite.cpp b/engines/saga/introproc_ite.cpp index 87fd48e2d2..9248f2b530 100644 --- a/engines/saga/introproc_ite.cpp +++ b/engines/saga/introproc_ite.cpp @@ -179,21 +179,22 @@ enum { EventColumns *Scene::ITEQueueCredits(int delta_time, int duration, int n_credits, const IntroCredit credits[]) { int game; Common::Language lang; + bool hasWyrmkeepCredits = (Common::File::exists("credit3n.dlt") || // PC + Common::File::exists("credit3m.dlt")); // Mac // The assumption here is that all WyrmKeep versions have the same // credits, regardless of which operating system they're for. lang = _vm->getLanguage(); - if (_vm->getFeatures() & GF_WYRMKEEP) { + if (hasWyrmkeepCredits) game = kITEWyrmKeep; - } else if (_vm->getPlatform() == Common::kPlatformMacintosh) { + else if (_vm->getPlatform() == Common::kPlatformMacintosh) game = kITEMac; - } else if (_vm->getFeatures() & GF_EXTRA_ITE_CREDITS) { + else if (_vm->getFeatures() & GF_EXTRA_ITE_CREDITS) game = kITEPCCD; - } else { + else game = kITEPC; - } int line_spacing = 0; int paragraph_spacing; @@ -303,6 +304,11 @@ int Scene::SC_ITEIntroAnimProc(int param, void *refCon) { int Scene::ITEIntroAnimProc(int param) { Event event; EventColumns *eventColumns; + bool isMac = _vm->getPlatform() == Common::kPlatformMacintosh; + bool isMultiCD = _vm->getPlatform() == Common::kPlatformUnknown; + bool hasWyrmkeepCredits = (Common::File::exists("credit3n.dlt") || // PC + Common::File::exists("credit3m.dlt")); // Mac + bool isDemo = Common::File::exists("scriptsd.rsc"); switch (param) { case SCENE_BEGIN:{ @@ -324,19 +330,10 @@ int Scene::ITEIntroAnimProc(int param) { // playback int lastAnim; - if (_vm->getFeatures() & GF_WYRMKEEP) { - if (_vm->getPlatform() == Common::kPlatformMacintosh) { - lastAnim = 3; - } else { - lastAnim = 2; - } - } else { - if (_vm->getPlatform() == Common::kPlatformMacintosh) { - lastAnim = 4; - } else { - lastAnim = 5; - } - } + if (hasWyrmkeepCredits || isMultiCD || isDemo) + lastAnim = isMac ? 3 : 2; + else + lastAnim = isMac ? 4 : 5; for (int i = 0; i < lastAnim; i++) _vm->_anim->link(i, i+1); diff --git a/engines/saga/music.cpp b/engines/saga/music.cpp index 21f3cc489e..13850a0b6d 100644 --- a/engines/saga/music.cpp +++ b/engines/saga/music.cpp @@ -213,7 +213,7 @@ void Music::setVolume(int volume, int time) { return; } - _vm->getTimerManager()->installTimerProc(&musicVolumeGaugeCallback, time * 3000L, this); + _vm->getTimerManager()->installTimerProc(&musicVolumeGaugeCallback, time * 3000L, this, "sagaMusicVolume"); } bool Music::isPlaying() { @@ -287,7 +287,12 @@ void Music::play(uint32 resourceId, MusicFlags flags) { if (_vm->isBigEndian()) musicFlags &= ~Audio::FLAG_LITTLE_ENDIAN; - if (_vm->getFeatures() & GF_MONO_MUSIC) + // The newer ITE Mac demo version contains a music file, but it has mono music. + // This is the only music file that is about 7MB, whereas all the other ones + // are much larger. Thus, we use this simple heuristic to determine if we got + // mono music in the ITE demos or not. + if (!strcmp(_digitalMusicContext->fileName(), "musicd.rsc") && + _digitalMusicContext->fileSize() < 8000000) musicFlags &= ~Audio::FLAG_STEREO; audioStream = Audio::makeRawStream(musicStream, 11025, musicFlags, DisposeAfterUse::YES); @@ -368,10 +373,12 @@ void Music::play(uint32 resourceId, MusicFlags flags) { void Music::pause() { _player->pause(); + _player->setVolume(0); } void Music::resume() { _player->resume(); + _player->setVolume(_vm->_musicVolume); } void Music::stop() { @@ -379,4 +386,3 @@ void Music::stop() { } } // End of namespace Saga - diff --git a/engines/saga/palanim.h b/engines/saga/palanim.h index 9959d08e2f..920cbec65a 100644 --- a/engines/saga/palanim.h +++ b/engines/saga/palanim.h @@ -53,4 +53,3 @@ class PalAnim { } // End of namespace Saga #endif - diff --git a/engines/saga/puzzle.cpp b/engines/saga/puzzle.cpp index d5d83c706f..63d9a88fee 100644 --- a/engines/saga/puzzle.cpp +++ b/engines/saga/puzzle.cpp @@ -140,7 +140,7 @@ void Puzzle::initPieceInfo(int i, int16 curX, int16 curY, byte offX, byte offY, void Puzzle::execute() { _active = true; - _vm->getTimerManager()->installTimerProc(&hintTimerCallback, kPuzzleHintTime, this); + _vm->getTimerManager()->installTimerProc(&hintTimerCallback, kPuzzleHintTime, this, "sagaPuzzleHint"); initPieces(); @@ -408,12 +408,12 @@ void Puzzle::solicitHint() { switch (_hintRqState) { case kRQSpeaking: if (_vm->_actor->isSpeaking()) { - _vm->getTimerManager()->installTimerProc(&hintTimerCallback, 50 * 1000000, this); + _vm->getTimerManager()->installTimerProc(&hintTimerCallback, 50 * 1000000, this, "sagaPuzzleHint"); break; } _hintRqState = _hintNextRqState; - _vm->getTimerManager()->installTimerProc(&hintTimerCallback, 100*1000000/3, this); + _vm->getTimerManager()->installTimerProc(&hintTimerCallback, 100*1000000/3, this, "sagaPuzzleHint"); break; case kRQNoHint: @@ -436,11 +436,11 @@ void Puzzle::solicitHint() { // Roll to see if Sakka scolds if (_vm->_rnd.getRandomNumber(1)) { _hintRqState = kRQSakkaDenies; - _vm->getTimerManager()->installTimerProc(&hintTimerCallback, 200*1000000, this); + _vm->getTimerManager()->installTimerProc(&hintTimerCallback, 200*1000000, this, "sagaPuzzleHint"); } else { _hintRqState = kRQSpeaking; _hintNextRqState = kRQHintRequested; - _vm->getTimerManager()->installTimerProc(&hintTimerCallback, 50*1000000, this); + _vm->getTimerManager()->installTimerProc(&hintTimerCallback, 50*1000000, this, "sagaPuzzleHint"); } break; @@ -453,7 +453,7 @@ void Puzzle::solicitHint() { _hintRqState = kRQSpeaking; _hintNextRqState = kRQHintRequestedStage2; - _vm->getTimerManager()->installTimerProc(&hintTimerCallback, 50*1000000, this); + _vm->getTimerManager()->installTimerProc(&hintTimerCallback, 50*1000000, this, "sagaPuzzleHint"); _vm->_interface->converseClear(); _vm->_interface->converseAddText(optionsStr[_lang][kROAccept], 0, 1, 0, 0); @@ -480,7 +480,7 @@ void Puzzle::solicitHint() { _vm->_interface->converseAddText(optionsStr[_lang][kROLater], 0, 0, 0, 0); _vm->_interface->converseDisplayText(); - _vm->getTimerManager()->installTimerProc(&hintTimerCallback, kPuzzleHintTime, this); + _vm->getTimerManager()->installTimerProc(&hintTimerCallback, kPuzzleHintTime, this, "sagaPuzzleHint"); _hintRqState = kRQSkipEverything; break; @@ -504,7 +504,7 @@ void Puzzle::handleReply(int reply) { _vm->_actor->abortSpeech(); _hintRqState = kRQNoHint; _vm->getTimerManager()->removeTimerProc(&hintTimerCallback); - _vm->getTimerManager()->installTimerProc(&hintTimerCallback, kPuzzleHintTime * 2, this); + _vm->getTimerManager()->installTimerProc(&hintTimerCallback, kPuzzleHintTime * 2, this, "sagaPuzzleHint"); clearHint(); break; } @@ -566,7 +566,7 @@ void Puzzle::giveHint() { _vm->_interface->converseDisplayText(); _vm->getTimerManager()->removeTimerProc(&hintTimerCallback); - _vm->getTimerManager()->installTimerProc(&hintTimerCallback, kPuzzleHintTime, this); + _vm->getTimerManager()->installTimerProc(&hintTimerCallback, kPuzzleHintTime, this, "sagaPuzzleHint"); } void Puzzle::clearHint() { diff --git a/engines/saga/render.cpp b/engines/saga/render.cpp index 757374a3a3..a9ef23381e 100644 --- a/engines/saga/render.cpp +++ b/engines/saga/render.cpp @@ -50,7 +50,7 @@ Render::Render(SagaEngine *vm, OSystem *system) { #ifdef SAGA_DEBUG // Initialize FPS timer callback - _vm->getTimerManager()->installTimerProc(&fpsTimerCallback, 1000000, this); + _vm->getTimerManager()->installTimerProc(&fpsTimerCallback, 1000000, this, "sagaFPS"); #endif _backGroundSurface.create(_vm->getDisplayInfo().width, _vm->getDisplayInfo().height, Graphics::PixelFormat::createFormatCLUT8()); diff --git a/engines/saga/resource.cpp b/engines/saga/resource.cpp index 72b021309c..1b0dfa2f22 100644 --- a/engines/saga/resource.cpp +++ b/engines/saga/resource.cpp @@ -162,12 +162,6 @@ bool Resource::createContexts() { uint16 voiceFileAddType; }; - - // If the Wyrmkeep credits file is found, set the Wyrmkeep version flag to true - if (Common::File::exists("credit3n.dlt")) { - _vm->_gf_wyrmkeep = true; - } - for (const ADGameFileDescription *gameFileDescription = _vm->getFilesDescriptions(); gameFileDescription->fileName; gameFileDescription++) { addContext(gameFileDescription->fileName, gameFileDescription->fileType); diff --git a/engines/saga/saga.cpp b/engines/saga/saga.cpp index d168605e99..6e272d37c0 100644 --- a/engines/saga/saga.cpp +++ b/engines/saga/saga.cpp @@ -72,9 +72,8 @@ SagaEngine::SagaEngine(OSystem *syst, const SAGAGameDescription *gameDesc) _readingSpeed = 0; _copyProtection = false; - _gf_wyrmkeep = false; _musicWasPlaying = false; - + _hasITESceneSubstitutes = false; _sndRes = NULL; _sound = NULL; @@ -211,9 +210,9 @@ Common::Error SagaEngine::run() { _subtitlesEnabled = ConfMan.getBool("subtitles"); _readingSpeed = getTalkspeed(); _copyProtection = ConfMan.getBool("copy_protection"); - _gf_wyrmkeep = false; _musicWasPlaying = false; _isIHNMDemo = Common::File::exists("music.res"); + _hasITESceneSubstitutes = Common::File::exists("boarhall.bbm"); if (_readingSpeed > 3) _readingSpeed = 0; diff --git a/engines/saga/saga.h b/engines/saga/saga.h index 23258e1277..fb01b1ac5d 100644 --- a/engines/saga/saga.h +++ b/engines/saga/saga.h @@ -29,7 +29,6 @@ #include "common/random.h" #include "common/memstream.h" #include "common/textconsole.h" -#include "audio/mididrv.h" #include "saga/gfx.h" @@ -137,16 +136,12 @@ enum GameFileTypes { }; enum GameFeatures { - GF_WYRMKEEP = 1 << 0, - GF_ITE_FLOPPY = 1 << 1, - GF_SCENE_SUBSTITUTES = 1 << 2, + GF_ITE_FLOPPY = 1 << 0, #if 0 - GF_OLD_ITE_DOS = 1 << 3, // Currently unused + GF_OLD_ITE_DOS = 1 << 1, // Currently unused #endif - GF_MONO_MUSIC = 1 << 4, - GF_EXTRA_ITE_CREDITS = 1 << 5, - GF_LE_VOICES = 1 << 6, - GF_8BIT_UNSIGNED_PCM = 1 << 7 + GF_EXTRA_ITE_CREDITS = 1 << 2, + GF_8BIT_UNSIGNED_PCM = 1 << 3 }; enum VerbTypeIds { @@ -532,9 +527,9 @@ public: int _readingSpeed; bool _copyProtection; - bool _gf_wyrmkeep; bool _musicWasPlaying; bool _isIHNMDemo; + bool _hasITESceneSubstitutes; SndRes *_sndRes; Sound *_sound; diff --git a/engines/saga/saveload.cpp b/engines/saga/saveload.cpp index 8d7b718c09..9e0789fdaf 100644 --- a/engines/saga/saveload.cpp +++ b/engines/saga/saveload.cpp @@ -295,12 +295,7 @@ void SagaEngine::load(const char *fileName) { if (_saveHeader.version >= 6) { // We don't need the thumbnail here, so just read it and discard it - Graphics::Surface *thumbnail = new Graphics::Surface(); - assert(thumbnail); - Graphics::loadThumbnail(*in, *thumbnail); - thumbnail->free(); - delete thumbnail; - thumbnail = 0; + Graphics::skipThumbnail(*in); in->readUint32BE(); // save date in->readUint16BE(); // save time diff --git a/engines/saga/scene.cpp b/engines/saga/scene.cpp index 66ee8f4504..61e62d5626 100644 --- a/engines/saga/scene.cpp +++ b/engines/saga/scene.cpp @@ -451,7 +451,7 @@ void Scene::changeScene(int16 sceneNumber, int actorsEntrance, SceneTransitionTy // This is used for latter ITE demos where all places on world map except // Tent Faire are substituted with LBM picture and short description - if (_vm->getFeatures() & GF_SCENE_SUBSTITUTES) { + if (_vm->_hasITESceneSubstitutes) { for (int i = 0; i < ARRAYSIZE(sceneSubstitutes); i++) { if (sceneSubstitutes[i].sceneId == sceneNumber) { Surface bbmBuffer; diff --git a/engines/saga/shorten.cpp b/engines/saga/shorten.cpp index 39af7aa3db..5efc8d1f67 100644 --- a/engines/saga/shorten.cpp +++ b/engines/saga/shorten.cpp @@ -541,4 +541,3 @@ Audio::AudioStream *makeShortenStream(Common::SeekableReadStream &stream) { } // End of namespace Audio #endif // defined(SOUND_SHORTEN_H) - diff --git a/engines/saga/shorten.h b/engines/saga/shorten.h index f2114bedeb..77feafa54d 100644 --- a/engines/saga/shorten.h +++ b/engines/saga/shorten.h @@ -57,4 +57,3 @@ Audio::AudioStream *makeShortenStream(Common::ReadStream &stream); #endif #endif // engine and dynamic plugins guard - diff --git a/engines/saga/sndres.cpp b/engines/saga/sndres.cpp index 2433c93e93..add34e22a2 100644 --- a/engines/saga/sndres.cpp +++ b/engines/saga/sndres.cpp @@ -262,9 +262,12 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff buffer.flags |= Audio::FLAG_UNSIGNED; buffer.flags &= ~Audio::FLAG_16BITS; } else { - // Voice files in newer ITE demo versions are OKI ADPCM (VOX) encoded - if (!uncompressedSound && !scumm_stricmp(context->fileName(), "voicesd.rsc")) + // Voice files in newer ITE demo versions are OKI ADPCM (VOX) encoded. + // These are LE in all the Windows and Mac demos + if (!uncompressedSound && !scumm_stricmp(context->fileName(), "voicesd.rsc")) { resourceType = kSoundVOX; + buffer.flags |= Audio::FLAG_LITTLE_ENDIAN; + } } } buffer.buffer = NULL; @@ -272,8 +275,6 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff // Check for LE sounds if (!context->isBigEndian()) buffer.flags |= Audio::FLAG_LITTLE_ENDIAN; - if ((context->fileType() & GAME_VOICEFILE) && (_vm->getFeatures() & GF_LE_VOICES)) - buffer.flags |= Audio::FLAG_LITTLE_ENDIAN; // Older Mac versions of ITE were Macbinary packed int soundOffset = (context->fileType() & GAME_MACBINARY) ? 36 : 0; diff --git a/engines/saga/sthread.cpp b/engines/saga/sthread.cpp index ec81d8d733..afd528f4b5 100644 --- a/engines/saga/sthread.cpp +++ b/engines/saga/sthread.cpp @@ -236,4 +236,3 @@ bool Script::runThread(ScriptThread &thread) { } } // End of namespace Saga - diff --git a/engines/savestate.cpp b/engines/savestate.cpp index 0b187ce630..260c7cd3ff 100644 --- a/engines/savestate.cpp +++ b/engines/savestate.cpp @@ -58,4 +58,3 @@ void SaveStateDescriptor::setPlayTime(uint32 msecs) { uint minutes = msecs / 60000; setPlayTime(minutes / 60, minutes % 60); } - diff --git a/engines/sci/decompressor.h b/engines/sci/decompressor.h index 37a5b5d7cb..5753026709 100644 --- a/engines/sci/decompressor.h +++ b/engines/sci/decompressor.h @@ -197,4 +197,3 @@ protected: } // End of namespace Sci #endif // SCI_SCICORE_DECOMPRESSOR_H - diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp index 2285e512bd..33ca3a6c9c 100644 --- a/engines/sci/detection.cpp +++ b/engines/sci/detection.cpp @@ -285,7 +285,7 @@ static const OldNewIdTableEntry s_oldNewTable[] = { * @param[in] gameFlags The game's flags, which are adjusted accordingly for demos * @return The equivalent ScummVM game id */ -Common::String convertSierraGameId(Common::String sierraId, uint32 *gameFlags, ResourceManager *resMan) { +Common::String convertSierraGameId(Common::String sierraId, uint32 *gameFlags, ResourceManager &resMan) { // Convert the id to lower case, so that we match all upper/lower case variants. sierraId.toLowercase(); @@ -301,7 +301,7 @@ Common::String convertSierraGameId(Common::String sierraId, uint32 *gameFlags, R if (sierraId == "fp" || sierraId == "gk" || sierraId == "pq4") demoThreshold = 150; - Common::ScopedPtr<Common::List<ResourceId> > resources(resMan->listResources(kResourceTypeScript, -1)); + Common::ScopedPtr<Common::List<ResourceId> > resources(resMan.listResources(kResourceTypeScript, -1)); if (resources->size() < demoThreshold) { *gameFlags |= ADGF_DEMO; @@ -337,7 +337,7 @@ Common::String convertSierraGameId(Common::String sierraId, uint32 *gameFlags, R // This could either be qfg1 VGA, qfg3 or qfg4 demo (all SCI1.1), // or qfg4 full (SCI2) // qfg1 VGA doesn't have view 1 - if (!resMan->testResource(ResourceId(kResourceTypeView, 1))) + if (!resMan.testResource(ResourceId(kResourceTypeView, 1))) return "qfg1vga"; // qfg4 full is SCI2 @@ -480,10 +480,9 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles, return 0; } - Common::ScopedPtr<ResourceManager> resMan(new ResourceManager()); - assert(resMan); - resMan->addAppropriateSources(fslist); - resMan->init(true); + ResourceManager resMan; + resMan.addAppropriateSources(fslist); + resMan.init(true); // TODO: Add error handling. #ifndef ENABLE_SCI32 @@ -494,7 +493,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles, } #endif - ViewType gameViews = resMan->getViewType(); + ViewType gameViews = resMan.getViewType(); // Have we identified the game views? If not, stop here // Can't be SCI (or unsupported SCI views). Pinball Creep by sierra also uses resource.map/resource.000 files @@ -508,7 +507,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles, s_fallbackDesc.platform = Common::kPlatformAmiga; // Determine the game id - Common::String sierraGameId = resMan->findSierraGameId(); + Common::String sierraGameId = resMan.findSierraGameId(); // If we don't have a game id, the game is not SCI if (sierraGameId.empty()) { @@ -530,7 +529,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles, // As far as we know, these games store the messages of each language in separate // resources, and it's not possible to detect that easily // Also look for "%J" which is used in japanese games - Resource *text = resMan->findResource(ResourceId(kResourceTypeText, 0), 0); + Resource *text = resMan.findResource(ResourceId(kResourceTypeText, 0), 0); uint seeker = 0; if (text) { while (seeker < text->size) { @@ -588,7 +587,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles, s_fallbackDesc.extra = "CD"; } - return (const ADGameDescription *)&s_fallbackDesc; + return &s_fallbackDesc; } bool SciMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { @@ -677,13 +676,7 @@ SaveStateDescriptor SciMetaEngine::querySaveMetaInfos(const char *target, int sl SaveStateDescriptor desc(slot, meta.name); - Graphics::Surface *thumbnail = new Graphics::Surface(); - assert(thumbnail); - if (!Graphics::loadThumbnail(*in, *thumbnail)) { - delete thumbnail; - thumbnail = 0; - } - + Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*in); desc.setThumbnail(thumbnail); desc.setDeletableFlag(true); diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h index 6641f243e6..3b18a1f68d 100644 --- a/engines/sci/detection_tables.h +++ b/engines/sci/detection_tables.h @@ -3150,6 +3150,15 @@ static const struct ADGameDescription SciGameDescriptions[] = { AD_LISTEND}, Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH }, + + // Slater & Charlie Go Camping - English DOS/Windows (Sierra Originals) + {"slater", "", { + {"resource.000", 0, "d7b4cc8e2c0b3a4768f8dfb5de27f206", 2256126}, + {"resource.map", 0, "21f85414124dc23e54544a5536dc35cd", 4044}, + {"resource.msg", 0, "c44f51fb955eae266fecf360ebcd5ad2", 1132}, + AD_LISTEND}, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH }, + // Space Quest 1 VGA Remake - English Amiga (from www.back2roots.org) // SCI interpreter version 1.000.510 (just a guess) {"sq1sci", "SCI", { diff --git a/engines/sci/engine/kstring.cpp b/engines/sci/engine/kstring.cpp index 7b8db22e3f..b383f88840 100644 --- a/engines/sci/engine/kstring.cpp +++ b/engines/sci/engine/kstring.cpp @@ -336,8 +336,9 @@ reg_t kFormat(EngineState *s, int argc, reg_t *argv) { if (align >= 0) while (str_leng-- > 1) *target++ = ' '; /* Format into the text */ - - *target++ = arguments[paramindex++]; + char argchar = arguments[paramindex++]; + if (argchar) + *target++ = argchar; mode = 0; } break; diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp index ab67da32db..1510af8508 100644 --- a/engines/sci/engine/seg_manager.cpp +++ b/engines/sci/engine/seg_manager.cpp @@ -28,12 +28,6 @@ namespace Sci { -enum { - DEFAULT_SCRIPTS = 32, - DEFAULT_OBJECTS = 8, ///< default number of objects per script - DEFAULT_OBJECTS_INCREMENT = 4 ///< Number of additional objects to instantiate if we're running out of them -}; - SegManager::SegManager(ResourceManager *resMan) { _heap.push_back(0); diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp index e61da20f97..b2cde47f4a 100644 --- a/engines/sci/engine/workarounds.cpp +++ b/engines/sci/engine/workarounds.cpp @@ -283,6 +283,8 @@ const SciWorkaroundEntry kGraphSaveBox_workarounds[] = { // gameID, room,script,lvl, object-name, method-name, call,index, workaround const SciWorkaroundEntry kGraphRestoreBox_workarounds[] = { + { GID_LSL6, -1, 86, 0, "LL6Inv", "show", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // happens when restoring, is called with hunk segment, but hunk is not allocated at that time + // ^^ TODO: check, if this is really a script error or an issue with our restore code { GID_LSL6, -1, 86, 0, "LL6Inv", "hide", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // happens during the game, gets called with 1 extra parameter { GID_SQ5, 850, 850, 0, NULL, "changeState", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // happens while playing Battle Cruiser (invalid segment) - bug #3056811 SCI_WORKAROUNDENTRY_TERMINATOR diff --git a/engines/sci/graphics/palette.cpp b/engines/sci/graphics/palette.cpp index c5a3545701..38919593b4 100644 --- a/engines/sci/graphics/palette.cpp +++ b/engines/sci/graphics/palette.cpp @@ -683,7 +683,7 @@ bool GfxPalette::palVaryLoadTargetPalette(GuiResourceId resourceId) { void GfxPalette::palVaryInstallTimer() { int16 ticks = _palVaryTicks > 0 ? _palVaryTicks : 1; // Call signal increase every [ticks] - g_sci->getTimerManager()->installTimerProc(&palVaryCallback, 1000000 / 60 * ticks, this); + g_sci->getTimerManager()->installTimerProc(&palVaryCallback, 1000000 / 60 * ticks, this, "sciPalette"); } void GfxPalette::palVaryRemoveTimer() { diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp index dbe2135143..6469bc0cb3 100644 --- a/engines/sci/graphics/screen.cpp +++ b/engines/sci/graphics/screen.cpp @@ -20,9 +20,9 @@ * */ -#include "common/timer.h" #include "common/util.h" #include "common/system.h" +#include "common/timer.h" #include "graphics/surface.h" #include "engines/util.h" diff --git a/engines/sci/parser/said.cpp b/engines/sci/parser/said.cpp index 01c25ef401..d44109faec 100644 --- a/engines/sci/parser/said.cpp +++ b/engines/sci/parser/said.cpp @@ -1147,4 +1147,3 @@ True } // End of namespace Sci - diff --git a/engines/sci/sound/drivers/cms.cpp b/engines/sci/sound/drivers/cms.cpp index ace96ba499..dbcbf3d431 100644 --- a/engines/sci/sound/drivers/cms.cpp +++ b/engines/sci/sound/drivers/cms.cpp @@ -813,4 +813,3 @@ MidiPlayer *MidiPlayer_CMS_create(SciVersion version) { } } // End of namespace SCI - diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp index eaae64dc77..8558da397e 100644 --- a/engines/scumm/charset.cpp +++ b/engines/scumm/charset.cpp @@ -49,35 +49,28 @@ void ScummEngine::loadCJKFont() { _newLineCharacter = 0; if (_game.version <= 5 && _game.platform == Common::kPlatformFMTowns && _language == Common::JA_JPN) { // FM-TOWNS v3 / v5 Kanji -#ifdef DISABLE_TOWNS_DUAL_LAYER_MODE +#if defined(DISABLE_TOWNS_DUAL_LAYER_MODE) || !defined(USE_RGB_COLOR) GUIErrorMessage("FM-Towns Kanji font drawing requires dual graphics layer support which is disabled in this build"); error("FM-Towns Kanji font drawing requires dual graphics layer support which is disabled in this build"); #else // use FM-TOWNS font rom, since game files don't have kanji font resources - _cjkFont = Graphics::FontSJIS::createFont(Common::kPlatformFMTowns); + _cjkFont = Graphics::FontSJIS::createFont(_game.platform); if (!_cjkFont) error("SCUMM::Font: Could not open file 'FMT_FNT.ROM'"); _textSurfaceMultiplier = 2; _useCJKMode = true; #endif } else if (_game.id == GID_LOOM && _game.platform == Common::kPlatformPCEngine && _language == Common::JA_JPN) { - int numChar = 3418; - _2byteWidth = 12; - _2byteHeight = 12; +#ifdef USE_RGB_COLOR // use PC-Engine System Card, since game files don't have kanji font resources - if (!fp.open("pce.cdbios")) { - error("SCUMM::Font: Could not open System Card pce.cdbios"); - } else { - _useCJKMode = true; - debug(2, "Loading PC-Engine System Card"); - - // A 0x200 byte header can be present at the beginning of the syscard. Seek past it too. - fp.seek((fp.size() & 0x200) ? 0x30200 : 0x30000); + _cjkFont = Graphics::FontSJIS::createFont(_game.platform); + if (!_cjkFont) + error("SCUMM::Font: Could not open file 'pce.cdbios'"); - _2byteFontPtr = new byte[_2byteWidth * _2byteHeight * numChar / 8]; - fp.read(_2byteFontPtr, _2byteWidth * _2byteHeight * numChar / 8); - fp.close(); - } + _cjkFont->setDrawingMode(Graphics::FontSJIS::kShadowMode); + _2byteWidth = _2byteHeight = 12; + _useCJKMode = true; +#endif } else if (_game.id == GID_MONKEY && _game.platform == Common::kPlatformSegaCD && _language == Common::JA_JPN) { int numChar = 1413; _2byteWidth = 16; @@ -161,71 +154,16 @@ void ScummEngine::loadCJKFont() { } } -static int SJIStoPCEChunk(int f, int s) { //converts sjis code to pce font offset - // rangeTbl maps SJIS char-codes to the PCE System Card font rom. - // Each pair {<upperBound>,<lowerBound>} in the array represents a SJIS range. - const int rangeCnt = 45; - static const uint16 rangeTbl[rangeCnt][2] = { - // Symbols - {0x8140,0x817E},{0x8180,0x81AC}, - // 0-9 - {0x824F,0x8258}, - // Latin upper - {0x8260,0x8279}, - // Latin lower - {0x8281,0x829A}, - // Kana - {0x829F,0x82F1},{0x8340,0x837E},{0x8380,0x8396}, - // Greek upper - {0x839F,0x83B6}, - // Greek lower - {0x83BF,0x83D6}, - // Cyrillic upper - {0x8440,0x8460}, - // Cyrillic lower - {0x8470,0x847E},{0x8480,0x8491}, - // Kanji - {0x889F,0x88FC}, - {0x8940,0x897E},{0x8980,0x89FC}, - {0x8A40,0x8A7E},{0x8A80,0x8AFC}, - {0x8B40,0x8B7E},{0x8B80,0x8BFC}, - {0x8C40,0x8C7E},{0x8C80,0x8CFC}, - {0x8D40,0x8D7E},{0x8D80,0x8DFC}, - {0x8E40,0x8E7E},{0x8E80,0x8EFC}, - {0x8F40,0x8F7E},{0x8F80,0x8FFC}, - {0x9040,0x907E},{0x9080,0x90FC}, - {0x9140,0x917E},{0x9180,0x91FC}, - {0x9240,0x927E},{0x9280,0x92FC}, - {0x9340,0x937E},{0x9380,0x93FC}, - {0x9440,0x947E},{0x9480,0x94FC}, - {0x9540,0x957E},{0x9580,0x95FC}, - {0x9640,0x967E},{0x9680,0x96FC}, - {0x9740,0x977E},{0x9780,0x97FC}, - {0x9840,0x9872} - }; - - int ch = (f << 8) | (s & 0xFF); - int offset = 0; - for (int i = 0; i < rangeCnt; ++i) { - if (ch >= rangeTbl[i][0] && ch <= rangeTbl[i][1]) - return offset + ch - rangeTbl[i][0]; - offset += rangeTbl[i][1] - rangeTbl[i][0] + 1; - } - - debug(4, "Invalid Char: 0x%x", ch); - return 0; -} - byte *ScummEngine::get2byteCharPtr(int idx) { + if (_game.platform == Common::kPlatformFMTowns || _game.platform == Common::kPlatformPCEngine) + return 0; + switch (_language) { case Common::KO_KOR: idx = ((idx % 256) - 0xb0) * 94 + (idx / 256) - 0xa1; break; case Common::JA_JPN: - if (_game.id == GID_LOOM && _game.platform == Common::kPlatformPCEngine) { - idx = SJIStoPCEChunk((idx % 256), (idx / 256)); - return _2byteFontPtr + (_2byteWidth * _2byteHeight / 8) * idx; - } else if (_game.id == GID_MONKEY && _game.platform == Common::kPlatformSegaCD && _language == Common::JA_JPN) { + if (_game.id == GID_MONKEY && _game.platform == Common::kPlatformSegaCD && _language == Common::JA_JPN) { // init pointer to charset resource if (_2byteFontPtr[0] == 0xFF) { int charsetId = 5; @@ -314,7 +252,7 @@ CharsetRenderer::~CharsetRenderer() { CharsetRendererCommon::CharsetRendererCommon(ScummEngine *vm) : CharsetRenderer(vm), _bytesPerPixel(0), _fontHeight(0), _numChars(0) { - _shadowMode = kNoShadowMode; + _shadowMode = false; _shadowColor = 0; } @@ -362,17 +300,9 @@ void CharsetRendererV3::setCurID(int32 id) { } int CharsetRendererCommon::getFontHeight() { - if (_vm->_useCJKMode) { - if (_vm->_game.platform == Common::kPlatformFMTowns) { - static const uint8 sjisFontHeightM1[] = { 0, 8, 9, 8, 9, 8, 9, 0, 0, 0 }; - static const uint8 sjisFontHeightM2[] = { 0, 8, 9, 9, 9, 8, 9, 9, 9, 8 }; - static const uint8 sjisFontHeightI4[] = { 0, 8, 9, 9, 9, 8, 8, 8, 8, 8 }; - const uint8 *htbl = (_vm->_game.id == GID_MONKEY) ? sjisFontHeightM1 : ((_vm->_game.id == GID_INDY4) ? sjisFontHeightI4 : sjisFontHeightM2); - return (_vm->_game.version == 3) ? 8 : htbl[_curId]; - } else { - return MAX(_vm->_2byteHeight + 1, _fontHeight); - } - } else + if (_vm->_useCJKMode) + return MAX(_vm->_2byteHeight + 1, _fontHeight); + else return _fontHeight; } @@ -380,57 +310,16 @@ int CharsetRendererCommon::getFontHeight() { int CharsetRendererClassic::getCharWidth(uint16 chr) { int spacing = 0; - if (_vm->_useCJKMode) { - if (_vm->_game.platform == Common::kPlatformFMTowns) { - if ((chr & 0xff00) == 0xfd00) { - chr &= 0xff; - } else if (chr >= 256) { - spacing = 8; - } else if (useTownsFontRomCharacter(chr)) { - spacing = 4; - } + if (_vm->_useCJKMode && chr >= 0x80) + return _vm->_2byteWidth / 2; - if (spacing) { - if (_vm->_game.id == GID_MONKEY) { - spacing++; - if (_curId == 2) - spacing++; - } else if (_vm->_game.id != GID_INDY4 && _curId == 1) { - spacing++; - } - } - - } else if (chr >= 0x80) { - return _vm->_2byteWidth / 2; - } - } - - if (!spacing) { - int offs = READ_LE_UINT32(_fontPtr + chr * 4 + 4); - if (offs) { - spacing = _fontPtr[offs] + (signed char)_fontPtr[offs + 2]; - } - } + int offs = READ_LE_UINT32(_fontPtr + chr * 4 + 4); + if (offs) + spacing = _fontPtr[offs] + (signed char)_fontPtr[offs + 2]; return spacing; } -bool CharsetRendererClassic::useTownsFontRomCharacter(uint16 chr) { -#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE - if (_vm->_game.platform != Common::kPlatformFMTowns || !_vm->_useCJKMode) - return false; - - if (chr < 128) { - if (((_vm->_game.id == GID_MONKEY2 && _curId != 0) || (_vm->_game.id == GID_INDY4 && _curId != 3)) && (chr > 31 && chr != 94 && chr != 95 && chr != 126 && chr != 127)) - return true; - return false; - } - return true; -#else - return false; -#endif -} - int CharsetRenderer::getStringWidth(int arg, const byte *text) { int pos = 0; int width = 1; @@ -608,22 +497,51 @@ void CharsetRenderer::addLinebreaks(int a, byte *str, int pos, int maxwidth) { int CharsetRendererV3::getCharWidth(uint16 chr) { int spacing = 0; - if (_vm->_useCJKMode) { - if (_vm->_game.platform == Common::kPlatformFMTowns) { - if (chr >= 256) - spacing = 8; - else if (chr >= 128) - spacing = 4; - } else if (chr & 0x80) { - spacing = _vm->_2byteWidth / 2; + if (_vm->_useCJKMode && (chr & 0x80)) + spacing = _vm->_2byteWidth / 2; + + if (!spacing) + spacing = *(_widthTable + chr); + + return spacing; +} + +void CharsetRendererV3::enableShadow(bool enable) { + _shadowColor = 0; + _shadowMode = enable; +} + +void CharsetRendererV3::drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth) { + int y, x; + byte bits = 0; + uint8 col = _color; + int pitch = s.pitch - width * bitDepth; + byte *dst2 = dst + s.pitch; + + for (y = 0; y < height && y + drawTop < s.h; y++) { + for (x = 0; x < width; x++) { + if ((x % 8) == 0) + bits = *src++; + if ((bits & revBitMask(x % 8)) && y + drawTop >= 0) { + if (_shadowMode) + dst[1] = dst2[0] = dst2[1] = _shadowColor; + dst[0] = col; + } + dst += bitDepth; + dst2 += bitDepth; } - } - if (!spacing) { - spacing = *(_widthTable + chr); + dst += pitch; + dst2 += pitch; } +} - return spacing; +int CharsetRendererV3::getDrawWidthIntern(uint16 chr) { + return getCharWidth(chr); +} + +int CharsetRendererV3::getDrawHeightIntern(uint16) { + return 8; } void CharsetRendererV3::setColor(byte color) { @@ -662,43 +580,6 @@ void CharsetRendererPCE::setColor(byte color) { } #endif -void CharsetRendererCommon::enableShadow(bool enable) { - if (enable) { - if (_vm->_game.platform == Common::kPlatformFMTowns) { - _shadowColor = 8; -#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE - _shadowColor = _vm->_game.version == 5 ? _vm->_townsCharsetColorMap[0] : 0x88; - if (_vm->_cjkFont) { - if (_vm->_game.version == 5) { - if (((_vm->_game.id == GID_MONKEY) && (_curId == 2 || _curId == 4 || _curId == 6)) || - ((_vm->_game.id == GID_MONKEY2) && (_curId != 1 && _curId != 5 && _curId != 9)) || - ((_vm->_game.id == GID_INDY4) && (_curId == 2 || _curId == 3 || _curId == 4))) { - _vm->_cjkFont->setDrawingMode(Graphics::FontSJIS::kOutlineMode); - } else { - _vm->_cjkFont->setDrawingMode(Graphics::FontSJIS::kDefaultMode); - } - _vm->_cjkFont->toggleFlippedMode((_vm->_game.id == GID_MONKEY || _vm->_game.id == GID_MONKEY2) && _curId == 3); - } else { - _vm->_cjkFont->setDrawingMode(Graphics::FontSJIS::kShadowMode); - } - } -#endif - _shadowMode = kFMTOWNSShadowMode; - } else { - _shadowColor = 0; - _shadowMode = kNormalShadowMode; - } - } else { -#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE - if (_vm->_cjkFont) { - _vm->_cjkFont->setDrawingMode(Graphics::FontSJIS::kDefaultMode); - _vm->_cjkFont->toggleFlippedMode(false); - } -#endif - _shadowMode = kNoShadowMode; - } -} - void CharsetRendererV3::printChar(int chr, bool ignoreCharsetMask) { // WORKAROUND for bug #1509509: Indy3 Mac does not show black // characters (such as in the grail diary) if ignoreCharsetMask @@ -721,33 +602,19 @@ void CharsetRendererV3::printChar(int chr, bool ignoreCharsetMask) { if (chr == '@') return; -#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE - if (_vm->_useCJKMode && chr > 127) { - if (_vm->_game.platform == Common::kPlatformFMTowns) { - charPtr = 0; - width = _vm->_cjkFont->getCharWidth(chr); - height = _vm->_cjkFont->getFontHeight(); - } else { - width = _vm->_2byteWidth; - height = _vm->_2byteHeight; - charPtr = _vm->get2byteCharPtr(chr); - } - } else -#endif - { - charPtr = _fontPtr + chr * 8; - width = getCharWidth(chr); - height = 8; - } + charPtr = (_vm->_useCJKMode && chr > 127) ? _vm->get2byteCharPtr(chr) : _fontPtr + chr * 8; + width = getDrawWidthIntern(chr); + height = getDrawHeightIntern(chr); + setDrawCharIntern(chr); + + origWidth = width; + origHeight = height; // Clip at the right side (to avoid drawing "outside" the screen bounds). if (_left + origWidth > _right + 1) return; - origWidth = width; - origHeight = height; - - if (_shadowMode != kNoShadowMode) { + if (_shadowMode) { width++; height++; } @@ -769,30 +636,17 @@ void CharsetRendererV3::printChar(int chr, bool ignoreCharsetMask) { _textScreenID = vs->number; } - if ( -#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE - (_vm->_game.platform != Common::kPlatformFMTowns) && -#endif - (ignoreCharsetMask || !vs->hasTwoBuffers)) { + if ((ignoreCharsetMask || !vs->hasTwoBuffers)) { dst = vs->getPixels(_left, drawTop); - if (charPtr) - drawBits1(*vs, dst, charPtr, drawTop, origWidth, origHeight, vs->format.bytesPerPixel); -#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE - else if (_vm->_cjkFont) - _vm->_cjkFont->drawChar(*vs, chr, _left, drawTop, _color, _shadowColor); -#endif + drawBits1(*vs, dst, charPtr, drawTop, origWidth, origHeight, vs->format.bytesPerPixel); } else { dst = (byte *)_vm->_textSurface.getBasePtr(_left * _vm->_textSurfaceMultiplier, _top * _vm->_textSurfaceMultiplier); - if (charPtr) - drawBits1(_vm->_textSurface, dst, charPtr, drawTop, origWidth, origHeight, _vm->_textSurface.format.bytesPerPixel, (_vm->_textSurfaceMultiplier == 2 && !is2byte)); -#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE - else if (_vm->_cjkFont) - _vm->_cjkFont->drawChar(_vm->_textSurface, chr, _left * _vm->_textSurfaceMultiplier, _top * _vm->_textSurfaceMultiplier, _color, _shadowColor); -#endif - if (is2byte) { - origWidth /= _vm->_textSurfaceMultiplier; - height /= _vm->_textSurfaceMultiplier; - } + drawBits1(_vm->_textSurface, dst, charPtr, drawTop, origWidth, origHeight, _vm->_textSurface.format.bytesPerPixel); + } + + if (is2byte) { + origWidth /= _vm->_textSurfaceMultiplier; + height /= _vm->_textSurfaceMultiplier; } if (_str.left > _left) @@ -802,7 +656,7 @@ void CharsetRendererV3::printChar(int chr, bool ignoreCharsetMask) { if (_str.right < _left) { _str.right = _left; - if (_shadowMode != kNoShadowMode) + if (_shadowMode) _str.right++; } @@ -811,30 +665,12 @@ void CharsetRendererV3::printChar(int chr, bool ignoreCharsetMask) { } void CharsetRendererV3::drawChar(int chr, Graphics::Surface &s, int x, int y) { - const byte *charPtr; - byte *dst; - int width, height; - int is2byte = (chr >= 0x80 && _vm->_useCJKMode) ? 1 : 0; - if (is2byte) { -#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE - if (_vm->_game.platform == Common::kPlatformFMTowns) { - _vm->_cjkFont->drawChar(s, chr, x * _vm->_textSurfaceMultiplier, y * _vm->_textSurfaceMultiplier, _color, _shadowColor); - return; - } - else -#endif - { - charPtr = _vm->get2byteCharPtr(chr); - width = _vm->_2byteWidth; - height = _vm->_2byteHeight; - } - } else { - charPtr = _fontPtr + chr * 8; -// width = height = 8; - width = getCharWidth(chr); - height = 8; - } - dst = (byte *)s.pixels + y * s.pitch + x; + const byte *charPtr = (_vm->_useCJKMode && chr > 127) ? _vm->get2byteCharPtr(chr) : _fontPtr + chr * 8; + int width = getDrawWidthIntern(chr); + int height = getDrawHeightIntern(chr); + setDrawCharIntern(chr); + + byte *dst = (byte *)s.pixels + y * s.pitch + x; drawBits1(s, dst, charPtr, y, width, height, s.format.bytesPerPixel); } @@ -853,29 +689,6 @@ void CharsetRenderer::translateColor() { } } -#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE -void CharsetRenderer::processTownsCharsetColors(uint8 bytesPerPixel) { - if (_vm->_game.platform == Common::kPlatformFMTowns) { - for (int i = 0; i < (1 << bytesPerPixel); i++) { - uint8 c = _vm->_charsetColorMap[i]; - - if (c > 16) { - uint8 t = (_vm->_currentPalette[c * 3] < 32) ? 4 : 12; - t |= ((_vm->_currentPalette[c * 3 + 1] < 32) ? 2 : 10); - t |= ((_vm->_currentPalette[c * 3 + 1] < 32) ? 1 : 9); - c = t; - } - - if (c == 0) - c = _vm->_townsOverrideShadowColor; - - c = ((c & 0x0f) << 4) | (c & 0x0f); - _vm->_townsCharsetColorMap[i] = c; - } - } -} -#endif - void CharsetRenderer::saveLoadWithSerializer(Serializer *ser) { static const SaveLoadEntry charsetRendererEntries[] = { MKLINE_OLD(CharsetRenderer, _curId, sleByte, VER(73), VER(73)), @@ -893,10 +706,7 @@ void CharsetRenderer::saveLoadWithSerializer(Serializer *ser) { } void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) { - int width, height, origWidth, origHeight; - int offsX, offsY; VirtScreen *vs; - const byte *charPtr; bool is2byte = (chr >= 256 && _vm->_useCJKMode); assertRange(1, _curId, _vm->_numCharsets - 1, "charset"); @@ -911,64 +721,8 @@ void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) { _vm->_charsetColorMap[1] = _color; -#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE - processTownsCharsetColors(_bytesPerPixel); - bool noSjis = false; - - if (_vm->_game.platform == Common::kPlatformFMTowns && _vm->_useCJKMode) { - if ((chr & 0x00ff) == 0x00fd) { - chr >>= 8; - noSjis = true; - } - } - - if (useTownsFontRomCharacter(chr) && !noSjis) { - charPtr = 0; - _vm->_cjkChar = chr; - enableShadow(true); - - width = getCharWidth(chr); - // For whatever reason MI1 uses a different font width - // for alignment calculation and for drawing when - // charset 2 is active. This fixes some subtle glitches. - if (_vm->_game.id == GID_MONKEY && _curId == 2) - width--; - origWidth = width; - - origHeight = height = getFontHeight(); - offsX = offsY = 0; - } else if (_vm->_useCJKMode && (chr >= 128) && !noSjis) { - enableShadow(true); - origWidth = width = _vm->_2byteWidth; - origHeight = height = _vm->_2byteHeight; - charPtr = _vm->get2byteCharPtr(chr); - offsX = offsY = 0; - if (_shadowMode != kNoShadowMode) { - width++; - height++; - } - } else -#endif - { - uint32 charOffs = READ_LE_UINT32(_fontPtr + chr * 4 + 4); - assert(charOffs < 0x14000); - if (!charOffs) - return; - charPtr = _fontPtr + charOffs; - - width = origWidth = charPtr[0]; - height = origHeight = charPtr[1]; - - if (_disableOffsX) { - offsX = 0; - } else { - offsX = (signed char)charPtr[2]; - } - - offsY = (signed char)charPtr[3]; - - charPtr += 4; // Skip over char header - } + if (!prepareDraw(chr)) + return; if (_firstChar) { _str.left = 0; @@ -977,12 +731,12 @@ void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) { _str.bottom = 0; } - _top += offsY; - _left += offsX; + _top += _offsY; + _left += _offsX; - if (_left + origWidth > _right + 1 || _left < 0) { - _left += origWidth; - _top -= offsY; + if (_left + _origWidth > _right + 1 || _left < 0) { + _left += _origWidth; + _top -= _offsY; return; } @@ -1004,33 +758,29 @@ void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) { int drawTop = _top - vs->topline; - _vm->markRectAsDirty(vs->number, _left, _left + width, drawTop, drawTop + height); + _vm->markRectAsDirty(vs->number, _left, _left + _width, drawTop, drawTop + _height); // This check for kPlatformFMTowns and kMainVirtScreen is at least required for the chat with // the navigator's head in front of the ghost ship in Monkey Island 1 - if (!ignoreCharsetMask -#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE - || (_vm->_game.platform == Common::kPlatformFMTowns && vs->number == kMainVirtScreen) -#endif - ) { + if (!ignoreCharsetMask || (_vm->_game.platform == Common::kPlatformFMTowns && vs->number == kMainVirtScreen)) { _hasMask = true; _textScreenID = vs->number; } - printCharIntern(is2byte, charPtr, origWidth, origHeight, width, height, vs, ignoreCharsetMask); + printCharIntern(is2byte, _charPtr, _origWidth, _origHeight, _width, _height, vs, ignoreCharsetMask); - _left += origWidth; + _left += _origWidth; if (_str.right < _left) { _str.right = _left; - if (_vm->_game.platform != Common::kPlatformFMTowns && _shadowMode != kNoShadowMode) + if (_vm->_game.platform != Common::kPlatformFMTowns && _shadowMode) _str.right++; } - if (_str.bottom < _top + origHeight) - _str.bottom = _top + origHeight; + if (_str.bottom < _top + _origHeight) + _str.bottom = _top + _origHeight; - _top -= offsY; + _top -= _offsY; } void CharsetRendererClassic::printCharIntern(bool is2byte, const byte *charPtr, int origWidth, int origHeight, int width, int height, VirtScreen *vs, bool ignoreCharsetMask) { @@ -1068,11 +818,7 @@ void CharsetRendererClassic::printCharIntern(bool is2byte, const byte *charPtr, } else { Graphics::Surface dstSurface; Graphics::Surface backSurface; - if ((ignoreCharsetMask || !vs->hasTwoBuffers) -#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE - && (_vm->_game.platform != Common::kPlatformFMTowns) -#endif - ) { + if ((ignoreCharsetMask || !vs->hasTwoBuffers)) { dstSurface = *vs; dstPtr = vs->getPixels(_left, drawTop); } else { @@ -1091,16 +837,7 @@ void CharsetRendererClassic::printCharIntern(bool is2byte, const byte *charPtr, drawTop = _top - _vm->_screenTop; } -#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE - if (!charPtr && _vm->_cjkFont) { - _vm->_cjkFont->drawChar(dstSurface, _vm->_cjkChar, _left * _vm->_textSurfaceMultiplier, (_top - _vm->_screenTop) * _vm->_textSurfaceMultiplier, _vm->_townsCharsetColorMap[1], _shadowColor); - } else -#endif - if (is2byte) { - drawBits1(dstSurface, dstPtr, charPtr, drawTop, origWidth, origHeight, dstSurface.format.bytesPerPixel); - } else { - drawBitsN(dstSurface, dstPtr, charPtr, *_fontPtr, drawTop, origWidth, origHeight, _vm->_textSurfaceMultiplier == 2); - } + drawBitsN(dstSurface, dstPtr, charPtr, *_fontPtr, drawTop, origWidth, origHeight); if (_blitAlso && vs->hasTwoBuffers) { // FIXME: Revisiting this code, I think the _blitAlso mode is likely broken @@ -1139,54 +876,36 @@ void CharsetRendererClassic::printCharIntern(bool is2byte, const byte *charPtr, } } -void CharsetRendererClassic::drawChar(int chr, Graphics::Surface &s, int x, int y) { - const byte *charPtr; - byte *dst; - int width, height; - int is2byte = (chr >= 0x80 && _vm->_useCJKMode) ? 1 : 0; - - if (is2byte) { - enableShadow(true); -#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE - if (_vm->_game.platform == Common::kPlatformFMTowns) { - _vm->_cjkFont->drawChar(s, chr, x * _vm->_textSurfaceMultiplier, y * _vm->_textSurfaceMultiplier, _color, _shadowColor); - return; - } else -#endif - { - charPtr = _vm->get2byteCharPtr(chr); - width = _vm->_2byteWidth; - height = _vm->_2byteHeight; - } - } else { - uint32 charOffs = READ_LE_UINT32(_fontPtr + chr * 4 + 4); - assert(charOffs < 0x10000); - if (!charOffs) - return; - charPtr = _fontPtr + charOffs; +bool CharsetRendererClassic::prepareDraw(uint16 chr) { + uint32 charOffs = READ_LE_UINT32(_fontPtr + chr * 4 + 4); + assert(charOffs < 0x14000); + if (!charOffs) + return false; + _charPtr = _fontPtr + charOffs; - width = charPtr[0]; - height = charPtr[1]; + _width = _origWidth = _charPtr[0]; + _height = _origHeight = _charPtr[1]; - charPtr += 4; // Skip over char header + if (_disableOffsX) { + _offsX = 0; + } else { + _offsX = (signed char)_charPtr[2]; } - dst = (byte *)s.pixels + y * s.pitch + x; + _offsY = (signed char)_charPtr[3]; - if (is2byte) { - drawBits1(s, dst, charPtr, y, width, height, s.format.bytesPerPixel); - } else { - drawBitsN(s, dst, charPtr, *_fontPtr, y, width, height); - } + _charPtr += 4; // Skip over char header + return true; } -void CharsetRendererClassic::drawBitsN(const Graphics::Surface &s, byte *dst, const byte *src, byte bpp, int drawTop, int width, int height, -#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE - bool scale2x) { -#else - bool) { -#endif +void CharsetRendererClassic::drawChar(int chr, Graphics::Surface &s, int x, int y) { + if (!prepareDraw(chr)) + return; + byte *dst = (byte *)s.pixels + y * s.pitch + x; + drawBitsN(s, dst, _charPtr, *_fontPtr, y, _width, _height); +} +void CharsetRendererClassic::drawBitsN(const Graphics::Surface &s, byte *dst, const byte *src, byte bpp, int drawTop, int width, int height) { int y, x; int color; byte numbits, bits; @@ -1198,38 +917,13 @@ void CharsetRendererClassic::drawBitsN(const Graphics::Surface &s, byte *dst, co numbits = 8; byte *cmap = _vm->_charsetColorMap; -#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE - byte *dst2 = dst; - - if (_vm->_game.platform == Common::kPlatformFMTowns) - cmap = _vm->_townsCharsetColorMap; - if (scale2x) { - dst2 += s.pitch; - pitch <<= 1; - } -#endif - for (y = 0; y < height && y + drawTop < s.h; y++) { for (x = 0; x < width; x++) { color = (bits >> (8 - bpp)) & 0xFF; - if (color && y + drawTop >= 0) { + if (color && y + drawTop >= 0) *dst = cmap[color]; - -#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE - if (scale2x) - dst[1] = dst2[0] = dst2[1] = dst[0]; -#endif - } dst++; - -#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE - if (scale2x) { - dst++; - dst2 += 2; - } -#endif - bits <<= bpp; numbits -= bpp; if (numbits == 0) { @@ -1238,52 +932,93 @@ void CharsetRendererClassic::drawBitsN(const Graphics::Surface &s, byte *dst, co } } dst += pitch; + } +} + +CharsetRendererTownsV3::CharsetRendererTownsV3(ScummEngine *vm) : CharsetRendererV3(vm), _sjisCurChar(0) { +} + +int CharsetRendererTownsV3::getCharWidth(uint16 chr) { + int spacing = 0; + + if (_vm->_useCJKMode) { + if (chr >= 256) + spacing = 8; + else if (chr >= 128) + spacing = 4; + } + + if (!spacing) + spacing = *(_widthTable + chr); + + return spacing; +} + +int CharsetRendererTownsV3::getFontHeight() { + return _vm->_useCJKMode ? 8 : _fontHeight; +} + +void CharsetRendererTownsV3::enableShadow(bool enable) { + _shadowColor = 8; + _shadowMode = enable; + #ifndef DISABLE_TOWNS_DUAL_LAYER_MODE - dst2 += pitch; + _shadowColor = 0x88; +#ifdef USE_RGB_COLOR + if (_vm->_cjkFont) + _vm->_cjkFont->setDrawingMode(enable ? Graphics::FontSJIS::kFMTownsShadowMode : Graphics::FontSJIS::kDefaultMode); +#endif #endif - } } -void CharsetRendererCommon::drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth, +void CharsetRendererTownsV3::drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth) { #ifndef DISABLE_TOWNS_DUAL_LAYER_MODE - bool scale2x) { +#ifdef USE_RGB_COLOR + if (_sjisCurChar) { + assert(_vm->_cjkFont); + _vm->_cjkFont->drawChar(_vm->_textSurface, _sjisCurChar, _left * _vm->_textSurfaceMultiplier, _top * _vm->_textSurfaceMultiplier, _color, _shadowColor); + return; + } +#endif + + dst = (byte *)_vm->_textSurface.getBasePtr(_left * _vm->_textSurfaceMultiplier, _top * _vm->_textSurfaceMultiplier); + int sfPitch = _vm->_textSurface.pitch; + int sfHeight = _vm->_textSurface.h; + bool scale2x = (_vm->_textSurfaceMultiplier == 2 && !(_sjisCurChar >= 256 && _vm->_useCJKMode)); #else - bool) { + int sfPitch = s.pitch; + int sfHeight = s.h; #endif int y, x; byte bits = 0; uint8 col = _color; - int pitch = s.pitch - width * bitDepth; - byte *dst2 = dst + s.pitch; + int pitch = sfPitch - width * bitDepth; + byte *dst2 = dst + sfPitch; #ifndef DISABLE_TOWNS_DUAL_LAYER_MODE byte *dst3 = dst2; byte *dst4 = dst2; if (scale2x) { - dst3 = dst2 + s.pitch; - dst4 = dst3 + s.pitch; + dst3 = dst2 + sfPitch; + dst4 = dst3 + sfPitch; pitch <<= 1; } - if (_vm->_game.platform == Common::kPlatformFMTowns && _vm->_game.version == 5) - col = _vm->_townsCharsetColorMap[1]; #endif - for (y = 0; y < height && y + drawTop < s.h; y++) { + for (y = 0; y < height && y + drawTop < sfHeight; y++) { for (x = 0; x < width; x++) { if ((x % 8) == 0) bits = *src++; if ((bits & revBitMask(x % 8)) && y + drawTop >= 0) { if (bitDepth == 2) { - if (_shadowMode != kNoShadowMode) { + if (_shadowMode) { WRITE_UINT16(dst + 2, _vm->_16BitPalette[_shadowColor]); - WRITE_UINT16(dst + s.pitch, _vm->_16BitPalette[_shadowColor]); - if (_shadowMode != kFMTOWNSShadowMode) - WRITE_UINT16(dst + s.pitch + 2, _vm->_16BitPalette[_shadowColor]); + WRITE_UINT16(dst + sfPitch, _vm->_16BitPalette[_shadowColor]); } WRITE_UINT16(dst, _vm->_16BitPalette[_color]); } else { - if (_shadowMode != kNoShadowMode) { + if (_shadowMode) { #ifndef DISABLE_TOWNS_DUAL_LAYER_MODE if (scale2x) { dst[2] = dst[3] = dst2[2] = dst2[3] = _shadowColor; @@ -1292,8 +1027,6 @@ void CharsetRendererCommon::drawBits1(const Graphics::Surface &s, byte *dst, con #endif { dst[1] = dst2[0] = _shadowColor; - if (_shadowMode != kFMTOWNSShadowMode) - dst2[1] = _shadowColor; } } dst[0] = col; @@ -1324,31 +1057,64 @@ void CharsetRendererCommon::drawBits1(const Graphics::Surface &s, byte *dst, con #endif } } +#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE +int CharsetRendererTownsV3::getDrawWidthIntern(uint16 chr) { +#ifdef USE_RGB_COLOR + if (_vm->_useCJKMode && chr > 127) { + assert(_vm->_cjkFont); + return _vm->_cjkFont->getCharWidth(chr); + } +#endif + return CharsetRendererV3::getDrawWidthIntern(chr); +} + +int CharsetRendererTownsV3::getDrawHeightIntern(uint16 chr) { +#ifdef USE_RGB_COLOR + if (_vm->_useCJKMode && chr > 127) { + assert(_vm->_cjkFont); + return _vm->_cjkFont->getFontHeight(); + } +#endif + return CharsetRendererV3::getDrawHeightIntern(chr); +} + +void CharsetRendererTownsV3::setDrawCharIntern(uint16 chr) { + _sjisCurChar = (_vm->_useCJKMode && chr > 127) ? chr : 0; +} +#endif #ifdef USE_RGB_COLOR -void CharsetRendererPCE::drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth, bool scalex) { +void CharsetRendererPCE::drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth) { + if (_sjisCurChar) { + assert(_vm->_cjkFont); + uint16 col1 = _color; + uint16 col2 = _shadowColor; + + if (s.format.bytesPerPixel == 2) { + col1 = _vm->_16BitPalette[col1]; + col2 = _vm->_16BitPalette[col2]; + } + + _vm->_cjkFont->drawChar(dst, _sjisCurChar, s.pitch, s.format.bytesPerPixel, col1, col2, -1, -1); + return; + } + int y, x; - int bitCount = 0; byte bits = 0; - const bool resetLineBitCount = (_vm->_language != Common::JA_JPN || width != 12); - for (y = 0; y < height && y + drawTop < s.h; y++) { - if (resetLineBitCount) - bitCount = 0; + int bitCount = 0; for (x = 0; x < width; x++) { if ((bitCount % 8) == 0) bits = *src++; if ((bits & revBitMask(bitCount % 8)) && y + drawTop >= 0) { if (bitDepth == 2) { - if (_shadowMode != kNoShadowMode) { + if (_shadowMode) WRITE_UINT16(dst + s.pitch + 2, _vm->_16BitPalette[_shadowColor]); - } WRITE_UINT16(dst, _vm->_16BitPalette[_color]); } else { - if (_shadowMode != kNoShadowMode) { + if (_shadowMode) *(dst + s.pitch + 1) = _shadowColor; - } *dst = _color; } } @@ -1359,6 +1125,22 @@ void CharsetRendererPCE::drawBits1(const Graphics::Surface &s, byte *dst, const dst += s.pitch - width * bitDepth; } } + +int CharsetRendererPCE::getDrawWidthIntern(uint16 chr) { + if (_vm->_useCJKMode && chr > 127) + return _vm->_2byteWidth; + return CharsetRendererV3::getDrawWidthIntern(chr); +} + +int CharsetRendererPCE::getDrawHeightIntern(uint16 chr) { + if (_vm->_useCJKMode && chr > 127) + return _vm->_2byteHeight; + return CharsetRendererV3::getDrawHeightIntern(chr); +} + +void CharsetRendererPCE::setDrawCharIntern(uint16 chr) { + _sjisCurChar = (_vm->_useCJKMode && chr > 127) ? chr : 0; +} #endif #ifdef ENABLE_SCUMM_7_8 @@ -1533,7 +1315,7 @@ void CharsetRendererNES::printChar(int chr, bool ignoreCharsetMask) { if (_str.right < _left) { _str.right = _left; - if (_shadowMode != kNoShadowMode) + if (_shadowMode) _str.right++; } @@ -1556,7 +1338,204 @@ void CharsetRendererNES::drawChar(int chr, Graphics::Surface &s, int x, int y) { drawBits1(s, dst, charPtr, y, width, height, s.format.bytesPerPixel); } -void CharsetRendererNES::drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth, bool scalex) { +#ifdef USE_RGB_COLOR +#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE +CharsetRendererTownsClassic::CharsetRendererTownsClassic(ScummEngine *vm) : CharsetRendererClassic(vm), _sjisCurChar(0) { +} + +int CharsetRendererTownsClassic::getCharWidth(uint16 chr) { + int spacing = 0; + + if (_vm->_useCJKMode) { + if ((chr & 0xff00) == 0xfd00) { + chr &= 0xff; + } else if (chr >= 256) { + spacing = 8; + } else if (useFontRomCharacter(chr)) { + spacing = 4; + } + + if (spacing) { + if (_vm->_game.id == GID_MONKEY) { + spacing++; + if (_curId == 2) + spacing++; + } else if (_vm->_game.id != GID_INDY4 && _curId == 1) { + spacing++; + } + } + } + + if (!spacing) { + int offs = READ_LE_UINT32(_fontPtr + chr * 4 + 4); + if (offs) + spacing = _fontPtr[offs] + (signed char)_fontPtr[offs + 2]; + } + + return spacing; +} + +int CharsetRendererTownsClassic::getFontHeight() { + static const uint8 sjisFontHeightM1[] = { 0, 8, 9, 8, 9, 8, 9, 0, 0, 0 }; + static const uint8 sjisFontHeightM2[] = { 0, 8, 9, 9, 9, 8, 9, 9, 9, 8 }; + static const uint8 sjisFontHeightI4[] = { 0, 8, 9, 9, 9, 8, 8, 8, 8, 8 }; + const uint8 *htbl = (_vm->_game.id == GID_MONKEY) ? sjisFontHeightM1 : ((_vm->_game.id == GID_INDY4) ? sjisFontHeightI4 : sjisFontHeightM2); + return _vm->_useCJKMode ? htbl[_curId] : _fontHeight; +} + +void CharsetRendererTownsClassic::drawBitsN(const Graphics::Surface&, byte *dst, const byte *src, byte bpp, int drawTop, int width, int height) { + if (_sjisCurChar) { + assert(_vm->_cjkFont); + _vm->_cjkFont->drawChar(_vm->_textSurface, _sjisCurChar, _left * _vm->_textSurfaceMultiplier, (_top - _vm->_screenTop) * _vm->_textSurfaceMultiplier, _vm->_townsCharsetColorMap[1], _shadowColor); + return; + } + + bool scale2x = (_vm->_textSurfaceMultiplier == 2); + dst = (byte *)_vm->_textSurface.pixels + (_top - _vm->_screenTop) * _vm->_textSurface.pitch * _vm->_textSurfaceMultiplier + _left * _vm->_textSurfaceMultiplier; + + int y, x; + int color; + byte numbits, bits; + + int pitch = _vm->_textSurface.pitch - width; + + assert(bpp == 1 || bpp == 2 || bpp == 4 || bpp == 8); + bits = *src++; + numbits = 8; + byte *cmap = _vm->_charsetColorMap; + byte *dst2 = dst; + + if (_vm->_game.platform == Common::kPlatformFMTowns) + cmap = _vm->_townsCharsetColorMap; + if (scale2x) { + dst2 += _vm->_textSurface.pitch; + pitch <<= 1; + } + + for (y = 0; y < height && y + drawTop < _vm->_textSurface.h; y++) { + for (x = 0; x < width; x++) { + color = (bits >> (8 - bpp)) & 0xFF; + + if (color && y + drawTop >= 0) { + *dst = cmap[color]; + if (scale2x) + dst[1] = dst2[0] = dst2[1] = dst[0]; + } + dst++; + + if (scale2x) { + dst++; + dst2 += 2; + } + + bits <<= bpp; + numbits -= bpp; + if (numbits == 0) { + bits = *src++; + numbits = 8; + } + } + dst += pitch; + dst2 += pitch; + } +} + +bool CharsetRendererTownsClassic::prepareDraw(uint16 chr) { + processCharsetColors(); + bool noSjis = false; + + if (_vm->_game.platform == Common::kPlatformFMTowns && _vm->_useCJKMode) { + if ((chr & 0x00ff) == 0x00fd) { + chr >>= 8; + noSjis = true; + } + } + + if (useFontRomCharacter(chr) && !noSjis) { + setupShadowMode(); + _charPtr = 0; + _sjisCurChar = chr; + + _width = getCharWidth(chr); + // For whatever reason MI1 uses a different font width + // for alignment calculation and for drawing when + // charset 2 is active. This fixes some subtle glitches. + if (_vm->_game.id == GID_MONKEY && _curId == 2) + _width--; + _origWidth = _width; + + _origHeight = _height = getFontHeight(); + _offsX = _offsY = 0; + } else if (_vm->_useCJKMode && (chr >= 128) && !noSjis) { + setupShadowMode(); + _origWidth = _width = _vm->_2byteWidth; + _origHeight = _height = _vm->_2byteHeight; + _charPtr = _vm->get2byteCharPtr(chr); + _offsX = _offsY = 0; + if (_shadowMode) { + _width++; + _height++; + } + } else { + _sjisCurChar = 0; + return CharsetRendererClassic::prepareDraw(chr); + } + return true; +} + +void CharsetRendererTownsClassic::setupShadowMode() { + _shadowMode = true; + _shadowColor = _vm->_townsCharsetColorMap[0]; + assert(_vm->_cjkFont); + + if (((_vm->_game.id == GID_MONKEY) && (_curId == 2 || _curId == 4 || _curId == 6)) || + ((_vm->_game.id == GID_MONKEY2) && (_curId != 1 && _curId != 5 && _curId != 9)) || + ((_vm->_game.id == GID_INDY4) && (_curId == 2 || _curId == 3 || _curId == 4))) { + _vm->_cjkFont->setDrawingMode(Graphics::FontSJIS::kOutlineMode); + } else { + _vm->_cjkFont->setDrawingMode(Graphics::FontSJIS::kDefaultMode); + } + + _vm->_cjkFont->toggleFlippedMode((_vm->_game.id == GID_MONKEY || _vm->_game.id == GID_MONKEY2) && _curId == 3); +} + +bool CharsetRendererTownsClassic::useFontRomCharacter(uint16 chr) { + if (!_vm->_useCJKMode) + return false; + + // Some SCUMM 5 games contain hard coded logic to determine whether to use + // the SCUMM fonts or the FM-Towns font rom to draw a character. For the other + // games we will simply check for a character greater 127. + if (chr < 128) { + if (((_vm->_game.id == GID_MONKEY2 && _curId != 0) || (_vm->_game.id == GID_INDY4 && _curId != 3)) && (chr > 31 && chr != 94 && chr != 95 && chr != 126 && chr != 127)) + return true; + return false; + } + return true; +} + +void CharsetRendererTownsClassic::processCharsetColors() { + for (int i = 0; i < (1 << _bytesPerPixel); i++) { + uint8 c = _vm->_charsetColorMap[i]; + + if (c > 16) { + uint8 t = (_vm->_currentPalette[c * 3] < 32) ? 4 : 12; + t |= ((_vm->_currentPalette[c * 3 + 1] < 32) ? 2 : 10); + t |= ((_vm->_currentPalette[c * 3 + 1] < 32) ? 1 : 9); + c = t; + } + + if (c == 0) + c = _vm->_townsOverrideShadowColor; + + c = ((c & 0x0f) << 4) | (c & 0x0f); + _vm->_townsCharsetColorMap[i] = c; + } +} +#endif +#endif + +void CharsetRendererNES::drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth) { for (int i = 0; i < 8; i++) { byte c0 = src[i]; byte c1 = src[i + 8]; diff --git a/engines/scumm/charset.h b/engines/scumm/charset.h index 4c657b475e..b23ec996f5 100644 --- a/engines/scumm/charset.h +++ b/engines/scumm/charset.h @@ -25,6 +25,7 @@ #include "common/scummsys.h" #include "common/rect.h" #include "graphics/sjis.h" +#include "scumm/scumm.h" #include "scumm/gfx.h" #include "scumm/saveload.h" @@ -78,10 +79,6 @@ public: void addLinebreaks(int a, byte *str, int pos, int maxwidth); void translateColor(); -#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE - void processTownsCharsetColors(uint8 bytesPerPixel); -#endif - virtual void setCurID(int32 id) = 0; int getCurID() { return _curId; } @@ -101,31 +98,26 @@ protected: int _fontHeight; int _numChars; - enum ShadowMode { - kNoShadowMode, - kFMTOWNSShadowMode, - kNormalShadowMode - }; byte _shadowColor; - ShadowMode _shadowMode; - - void enableShadow(bool enable); - virtual void drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth, bool scale2x = false); - + bool _shadowMode; public: CharsetRendererCommon(ScummEngine *vm); void setCurID(int32 id); - int getFontHeight(); + virtual int getFontHeight(); }; class CharsetRendererClassic : public CharsetRendererCommon { protected: - void drawBitsN(const Graphics::Surface &s, byte *dst, const byte *src, byte bpp, int drawTop, int width, int height, bool scale2x = false); + virtual void drawBitsN(const Graphics::Surface &s, byte *dst, const byte *src, byte bpp, int drawTop, int width, int height); + void printCharIntern(bool is2byte, const byte *charPtr, int origWidth, int origHeight, int width, int height, VirtScreen *vs, bool ignoreCharsetMask); + virtual bool prepareDraw(uint16 chr); - void printCharIntern(bool is2byte, const byte *charPtr, int origWidth, int origHeight, int width, int height, VirtScreen *vs, bool ignoreCharsetMask); + int _width, _height, _origWidth, _origHeight; + int _offsX, _offsY; + const byte *_charPtr; public: CharsetRendererClassic(ScummEngine *vm) : CharsetRendererCommon(vm) {} @@ -134,18 +126,34 @@ public: void drawChar(int chr, Graphics::Surface &s, int x, int y); int getCharWidth(uint16 chr); +}; + +#ifdef USE_RGB_COLOR +#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE +class CharsetRendererTownsClassic : public CharsetRendererClassic { +public: + CharsetRendererTownsClassic(ScummEngine *vm); + + int getCharWidth(uint16 chr); + int getFontHeight(); - // Some SCUMM 5 games contain hard coded logic to determine whether to use - // the SCUMM fonts or the FM-Towns font rom to draw a character. For the other - // games we will simply check for a character greater 127. - bool useTownsFontRomCharacter(uint16 chr); +private: + void drawBitsN(const Graphics::Surface &s, byte *dst, const byte *src, byte bpp, int drawTop, int width, int height); + bool prepareDraw(uint16 chr); + void setupShadowMode(); + bool useFontRomCharacter(uint16 chr); + void processCharsetColors(); + + uint16 _sjisCurChar; }; +#endif +#endif class CharsetRendererNES : public CharsetRendererCommon { protected: byte *_trTable; - void drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth, bool scale2x = false); + void drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth); public: CharsetRendererNES(ScummEngine *vm) : CharsetRendererCommon(vm) {} @@ -160,6 +168,12 @@ public: class CharsetRendererV3 : public CharsetRendererCommon { protected: + virtual void enableShadow(bool enable); + virtual void drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth); + virtual int getDrawWidthIntern(uint16 chr); + virtual int getDrawHeightIntern(uint16 chr); + virtual void setDrawCharIntern(uint16 chr) {} + const byte *_widthTable; public: @@ -169,16 +183,40 @@ public: void drawChar(int chr, Graphics::Surface &s, int x, int y); void setCurID(int32 id); void setColor(byte color); + virtual int getCharWidth(uint16 chr); +}; + +class CharsetRendererTownsV3 : public CharsetRendererV3 { +public: + CharsetRendererTownsV3(ScummEngine *vm); + int getCharWidth(uint16 chr); + int getFontHeight(); + +private: + void enableShadow(bool enable); + void drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth); +#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE + int getDrawWidthIntern(uint16 chr); + int getDrawHeightIntern(uint16 chr); + void setDrawCharIntern(uint16 chr); +#endif + uint16 _sjisCurChar; }; #ifdef USE_RGB_COLOR class CharsetRendererPCE : public CharsetRendererV3 { -protected: - void drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth, bool scale2x = false); +private: + void drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height, uint8 bitDepth); + + int getDrawWidthIntern(uint16 chr); + int getDrawHeightIntern(uint16 chr); + void setDrawCharIntern(uint16 chr); + + uint16 _sjisCurChar; public: - CharsetRendererPCE(ScummEngine *vm) : CharsetRendererV3(vm) {} + CharsetRendererPCE(ScummEngine *vm) : CharsetRendererV3(vm), _sjisCurChar(0) {} void setColor(byte color); }; diff --git a/engines/scumm/cursor.cpp b/engines/scumm/cursor.cpp index a8adb4d5c5..6739282c9d 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,63 @@ void ScummEngine_v70he::setDefaultCursor() { } } + // 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; + } + } + } + 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); + CursorMan.replaceCursorPalette(palette, 0xfd, cursor->getPaletteCount()); } + delete cursor; + updateCursor(); } +#endif void ScummEngine_v6::setCursorFromImg(uint img, uint room, uint imgindex) { int w, h; diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp index 18f2f4ddec..037c12bdbf 100644 --- a/engines/scumm/detection.cpp +++ b/engines/scumm/detection.cpp @@ -33,6 +33,8 @@ #include "common/savefile.h" #include "common/system.h" +#include "audio/mididrv.h" + #include "scumm/detection.h" #include "scumm/detection_tables.h" #include "scumm/he/intern_he.h" @@ -142,6 +144,14 @@ Common::String ScummEngine_v70he::generateFilename(const int room) const { Common::String result; char id = 0; + Common::String bPattern = _filenamePattern.pattern; + + // Special cases for Blue's games, which share common (b) files + if (_game.id == GID_BIRTHDAYYELLOW || _game.id == GID_BIRTHDAYRED) + bPattern = "Blue'sBirthday"; + else if (_game.id == GID_TREASUREHUNT) + bPattern = "Blue'sTreasureHunt"; + switch (_filenamePattern.genMethod) { case kGenHEMac: case kGenHEMacNoParens: @@ -154,13 +164,7 @@ Common::String ScummEngine_v70he::generateFilename(const int room) const { switch (disk) { case 2: id = 'b'; - // Special cases for Blue's games, which share common (b) files - if (_game.id == GID_BIRTHDAY && !(_game.features & GF_DEMO)) - result = "Blue'sBirthday.(b)"; - else if (_game.id == GID_TREASUREHUNT) - result = "Blue'sTreasureHunt.(b)"; - else - result = Common::String::format("%s.(b)", _filenamePattern.pattern); + result = bPattern + ".(b)"; break; case 1: id = 'a'; @@ -185,10 +189,11 @@ Common::String ScummEngine_v70he::generateFilename(const int room) const { // For mac they're stored in game binary result = _filenamePattern.pattern; } else { + Common::String pattern = id == 'b' ? bPattern : _filenamePattern.pattern; if (_filenamePattern.genMethod == kGenHEMac) - result = Common::String::format("%s (%c)", _filenamePattern.pattern, id); + result = Common::String::format("%s (%c)", pattern.c_str(), id); else - result = Common::String::format("%s %c", _filenamePattern.pattern, id); + result = Common::String::format("%s %c", pattern.c_str(), id); } } diff --git a/engines/scumm/detection_tables.h b/engines/scumm/detection_tables.h index e510c46cf2..78645ea8d5 100644 --- a/engines/scumm/detection_tables.h +++ b/engines/scumm/detection_tables.h @@ -222,7 +222,7 @@ static const GameSettings gameVariantsTable[] = { {"indy3", "EGA", "ega", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB, 0, UNK, GUIO_NOSPEECH | GUIO_NOMIDI}, {"indy3", "No AdLib", "ega", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR, 0, UNK, GUIO_NOSPEECH | GUIO_NOMIDI}, - {"indy3", "VGA", "vga", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_ADLIB, GF_OLD256 | GF_FEW_LOCALS, Common::kPlatformPC, GUIO_NOSPEECH | GUIO_NOMIDI}, + {"indy3", "VGA", "vga", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB, GF_OLD256 | GF_FEW_LOCALS, Common::kPlatformPC, GUIO_NOSPEECH | GUIO_NOMIDI}, {"indy3", "FM-TOWNS", 0, GID_INDY3, 3, 0, MDT_TOWNS, GF_OLD256 | GF_FEW_LOCALS | GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO_NOSPEECH | GUIO_NOMIDI | GUIO_MIDITOWNS}, {"loom", "EGA", "ega", GID_LOOM, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO_NOSPEECH}, @@ -233,9 +233,9 @@ static const GameSettings gameVariantsTable[] = { {"loom", "FM-TOWNS", 0, GID_LOOM, 3, 0, MDT_TOWNS, GF_AUDIOTRACKS | GF_OLD256, Common::kPlatformFMTowns, GUIO_NOSPEECH | GUIO_NOMIDI | GUIO_MIDITOWNS}, {"loom", "VGA", "vga", GID_LOOM, 4, 0, MDT_NONE, GF_AUDIOTRACKS, Common::kPlatformPC, GUIO_NOSPEECH | GUIO_NOMIDI}, - {"pass", 0, 0, GID_PASS, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_ADLIB, GF_16COLOR, Common::kPlatformPC, GUIO_NOSPEECH | GUIO_NOMIDI}, + {"pass", 0, 0, GID_PASS, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB, GF_16COLOR, Common::kPlatformPC, GUIO_NOSPEECH | GUIO_NOMIDI}, - {"monkey", "VGA", "vga", GID_MONKEY_VGA, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO_NOSPEECH}, + {"monkey", "VGA", "vga", GID_MONKEY_VGA, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO_NOSPEECH}, {"monkey", "EGA", "ega", GID_MONKEY_EGA, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, GF_16COLOR, Common::kPlatformPC, GUIO_NOSPEECH}, {"monkey", "No AdLib", "ega", GID_MONKEY_EGA, 4, 0, MDT_PCSPK | MDT_PCJR, GF_16COLOR, Common::kPlatformAtariST, GUIO_NOSPEECH | GUIO_NOMIDI}, {"monkey", "Demo", "ega", GID_MONKEY_EGA, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_ADLIB, GF_16COLOR, Common::kPlatformPC, GUIO_NOSPEECH | GUIO_NOMIDI}, @@ -243,11 +243,11 @@ static const GameSettings gameVariantsTable[] = { {"monkey", "FM-TOWNS", 0, GID_MONKEY, 5, 0, MDT_TOWNS, GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO_NOSPEECH | GUIO_NOMIDI | GUIO_MIDITOWNS}, {"monkey", "SEGA", 0, GID_MONKEY, 5, 0, MDT_NONE, GF_AUDIOTRACKS, Common::kPlatformSegaCD, GUIO_NOSPEECH | GUIO_NOMIDI}, - {"monkey2", "", 0, GID_MONKEY2, 5, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO_NOSPEECH}, - {"monkey2", "FM-TOWNS", 0, GID_MONKEY2, 5, 0, MDT_TOWNS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, Common::kPlatformFMTowns, GUIO_NOSPEECH | GUIO_MIDITOWNS | GUIO_MIDIADLIB | GUIO_MIDIMT32}, + {"monkey2", "", 0, GID_MONKEY2, 5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO_NOSPEECH}, + {"monkey2", "FM-TOWNS", 0, GID_MONKEY2, 5, 0, MDT_PCSPK | MDT_TOWNS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, Common::kPlatformFMTowns, GUIO_NOSPEECH | GUIO_MIDITOWNS | GUIO_MIDIADLIB | GUIO_MIDIMT32}, - {"atlantis", "", 0, GID_INDY4, 5, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO_NONE}, - {"atlantis", "Floppy", 0, GID_INDY4, 5, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO_NOSPEECH}, + {"atlantis", "", 0, GID_INDY4, 5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO_NONE}, + {"atlantis", "Floppy", 0, GID_INDY4, 5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO_NOSPEECH}, {"atlantis", "FM-TOWNS", 0, GID_INDY4, 5, 0, MDT_TOWNS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, Common::kPlatformFMTowns, GUIO_MIDITOWNS | GUIO_MIDIADLIB | GUIO_MIDIMT32}, {"tentacle", "", 0, GID_TENTACLE, 6, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_GM, GF_USE_KEY, UNK, GUIO_NONE}, @@ -343,7 +343,9 @@ static const GameSettings gameVariantsTable[] = { {"puttrace", "HE 99", 0, GID_PUTTRACE, 6, 99, MDT_NONE, GF_USE_KEY, UNK, GUIO_NOLAUNCHLOAD | GUIO_NOMIDI}, {"bluesabctime", "", 0, GID_HEGAME, 6, 98, MDT_NONE, GF_USE_KEY, UNK, GUIO_NOLAUNCHLOAD | GUIO_NOMIDI}, - {"BluesBirthday", 0, 0, GID_BIRTHDAY, 6, 98, MDT_NONE, GF_USE_KEY, UNK, GUIO_NOLAUNCHLOAD | GUIO_NOMIDI}, + {"BluesBirthday", "", 0, GID_HEGAME, 6, 98, MDT_NONE, GF_USE_KEY, UNK, GUIO_NOLAUNCHLOAD | GUIO_NOMIDI}, + {"BluesBirthday", "Red", 0, GID_BIRTHDAYRED, 6, 98, MDT_NONE, GF_USE_KEY, UNK, GUIO_NOLAUNCHLOAD | GUIO_NOMIDI}, + {"BluesBirthday", "Yellow", 0, GID_BIRTHDAYYELLOW, 6, 98, MDT_NONE, GF_USE_KEY, UNK, GUIO_NOLAUNCHLOAD | GUIO_NOMIDI}, {"soccer", "", 0, GID_SOCCER, 6, 98, MDT_NONE, GF_USE_KEY, UNK, GUIO_NOLAUNCHLOAD | GUIO_NOMIDI}, // Global scripts increased to 2048 diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp index f7f0c7d7ec..74a92f2204 100644 --- a/engines/scumm/dialogs.cpp +++ b/engines/scumm/dialogs.cpp @@ -23,6 +23,7 @@ #include "common/savefile.h" #include "common/system.h" #include "common/events.h" +#include "common/localization.h" #include "common/translation.h" #include "graphics/scaler.h" @@ -171,29 +172,33 @@ static const ResString string_map_table_v6[] = { }; static const ResString string_map_table_v345[] = { - {1, "Insert Disk %c and Press Button to Continue."}, - {2, "Unable to Find %s, (%c%d) Press Button."}, - {3, "Error reading disk %c, (%c%d) Press Button."}, - {4, "Game Paused. Press SPACE to Continue."}, - {5, "Are you sure you want to restart? (Y/N)"}, - {6, "Are you sure you want to quit? (Y/N)"}, + {1, _s("Insert Disk %c and Press Button to Continue.")}, + {2, _s("Unable to Find %s, (%c%d) Press Button.")}, + {3, _s("Error reading disk %c, (%c%d) Press Button.")}, + {4, _s("Game Paused. Press SPACE to Continue.")}, + // I18N: You may specify 'Yes' symbol at the end of the line, like this: + // "Moechten Sie wirklich neu starten? (J/N)J" + // Will react to J as 'Yes' + {5, _s("Are you sure you want to restart? (Y/N)")}, + // I18N: you may specify 'Yes' symbol at the end of the line. See previous comment + {6, _s("Are you sure you want to quit? (Y/N)")}, // Added in SCUMM4 - {7, "Save"}, - {8, "Load"}, - {9, "Play"}, - {10, "Cancel"}, - {11, "Quit"}, - {12, "OK"}, - {13, "Insert save/load game disk"}, - {14, "You must enter a name"}, - {15, "The game was NOT saved (disk full?)"}, - {16, "The game was NOT loaded"}, - {17, "Saving '%s'"}, - {18, "Loading '%s'"}, - {19, "Name your SAVE game"}, - {20, "Select a game to LOAD"}, - {28, "Game title"} + {7, _s("Save")}, + {8, _s("Load")}, + {9, _s("Play")}, + {10, _s("Cancel")}, + {11, _s("Quit")}, + {12, _s("OK")}, + {13, _s("Insert save/load game disk")}, + {14, _s("You must enter a name")}, + {15, _s("The game was NOT saved (disk full?)")}, + {16, _s("The game was NOT loaded")}, + {17, _s("Saving '%s'")}, + {18, _s("Loading '%s'")}, + {19, _s("Name your SAVE game")}, + {20, _s("Select a game to LOAD")}, + {28, _s("Game title)")} }; #pragma mark - @@ -278,7 +283,9 @@ HelpDialog::HelpDialog(const GameSettings &game) _numPages = ScummHelp::numPages(_game.id); + // I18N: Previous page button _prevButton = new GUI::ButtonWidget(this, "ScummHelp.Prev", _("~P~revious"), 0, kPrevCmd); + // I18N: Next page button _nextButton = new GUI::ButtonWidget(this, "ScummHelp.Next", _("~N~ext"), 0, kNextCmd); new GUI::ButtonWidget(this, "ScummHelp.Close", _("~C~lose"), 0, GUI::kCloseCmd); _prevButton->clearFlags(WIDGET_ENABLED); @@ -429,7 +436,7 @@ const Common::String InfoDialog::queryResString(int stringno) { else if (_vm->_game.version >= 3) result = _vm->getStringAddress(string_map_table_v345[stringno - 1].num); else - return string_map_table_v345[stringno - 1].string; + return _(string_map_table_v345[stringno - 1].string); if (result && *result == '/') { _vm->translateText(result, buf); @@ -437,7 +444,7 @@ const Common::String InfoDialog::queryResString(int stringno) { } if (!result || *result == '\0') { // Gracelessly degrade to english :) - return string_map_table_v345[stringno - 1].string; + return _(string_map_table_v345[stringno - 1].string); } // Convert to a proper string (take care of FF codes) @@ -482,10 +489,14 @@ ConfirmDialog::ConfirmDialog(ScummEngine *scumm, int res) } void ConfirmDialog::handleKeyDown(Common::KeyState state) { - if (state.keycode == Common::KEYCODE_n || state.ascii == _noKey) { + Common::KeyCode keyYes, keyNo; + + Common::getLanguageYesNo(keyYes, keyNo); + + if (state.keycode == Common::KEYCODE_n || state.ascii == _noKey || state.ascii == keyNo) { setResult(0); close(); - } else if (state.keycode == Common::KEYCODE_y || state.ascii == _yesKey) { + } else if (state.keycode == Common::KEYCODE_y || state.ascii == _yesKey || state.ascii == keyYes) { setResult(1); close(); } else @@ -583,9 +594,9 @@ void SubtitleSettingsDialog::open() { void SubtitleSettingsDialog::cycleValue() { static const char* subtitleDesc[] = { - "Speech Only", - "Speech and Subtitles", - "Subtitles Only" + _s("Speech Only"), + _s("Speech and Subtitles"), + _s("Subtitles Only") }; _value += 1; @@ -593,9 +604,9 @@ void SubtitleSettingsDialog::cycleValue() { _value = 0; if (_value == 1 && g_system->getOverlayWidth() <= 320) - setInfoText("Speech & Subs"); + setInfoText(_sc("Speech & Subs", "lowres")); else - setInfoText(subtitleDesc[_value]); + setInfoText(_(subtitleDesc[_value])); _timer = g_system->getMillis() + 1500; } diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp index f22547f193..8a32b963cd 100644 --- a/engines/scumm/gfx.cpp +++ b/engines/scumm/gfx.cpp @@ -4111,4 +4111,3 @@ void ScummEngine::unkScreenEffect6() { } } // End of namespace Scumm - diff --git a/engines/scumm/he/animation_he.cpp b/engines/scumm/he/animation_he.cpp index 74183c24d3..40e99c26a8 100644 --- a/engines/scumm/he/animation_he.cpp +++ b/engines/scumm/he/animation_he.cpp @@ -26,27 +26,42 @@ #include "scumm/he/intern_he.h" #include "audio/audiostream.h" +#include "video/smk_decoder.h" + +#ifdef USE_BINK +#include "video/bink_decoder.h" +#endif namespace Scumm { -MoviePlayer::MoviePlayer(ScummEngine_v90he *vm, Audio::Mixer *mixer) - : SmackerDecoder(mixer), _vm(vm), _mixer(mixer) { +MoviePlayer::MoviePlayer(ScummEngine_v90he *vm, Audio::Mixer *mixer) : _vm(vm) { +#ifdef USE_BINK + if (_vm->_game.heversion >= 100 && (_vm->_game.features & GF_16BIT_COLOR)) + _video = new Video::BinkDecoder(); + else +#endif + _video = new Video::SmackerDecoder(mixer); _flags = 0; _wizResNum = 0; } +MoviePlayer::~MoviePlayer() { + delete _video; +} + int MoviePlayer::getImageNum() { - if (!isVideoLoaded()) + if (!_video->isVideoLoaded()) return 0; + return _wizResNum; } int MoviePlayer::load(const char *filename, int flags, int image) { - if (isVideoLoaded()) - close(); + if (_video->isVideoLoaded()) + _video->close(); - if (!loadFile(filename)) { + if (!_video->loadFile(filename)) { warning("Failed to load video file %s", filename); return -1; } @@ -54,7 +69,7 @@ int MoviePlayer::load(const char *filename, int flags, int image) { debug(1, "Playing video %s", filename); if (flags & 2) - _vm->_wiz->createWizEmptyImage(image, 0, 0, getWidth(), getHeight()); + _vm->_wiz->createWizEmptyImage(image, 0, 0, _video->getWidth(), _video->getHeight()); _flags = flags; _wizResNum = image; @@ -62,34 +77,59 @@ int MoviePlayer::load(const char *filename, int flags, int image) { } void MoviePlayer::copyFrameToBuffer(byte *dst, int dstType, uint x, uint y, uint pitch) { - uint h = getHeight(); - uint w = getWidth(); + uint h = _video->getHeight(); + uint w = _video->getWidth(); + + const Graphics::Surface *surface = _video->decodeNextFrame(); + + if (!surface) + return; - const Graphics::Surface *surface = decodeNextFrame(); byte *src = (byte *)surface->pixels; - if (hasDirtyPalette()) - _vm->setPaletteFromPtr(getPalette(), 256); + if (_video->hasDirtyPalette()) + _vm->setPaletteFromPtr(_video->getPalette(), 256); if (_vm->_game.features & GF_16BIT_COLOR) { - dst += y * pitch + x * 2; - do { - for (uint i = 0; i < w; i++) { - uint16 color = READ_LE_UINT16(_vm->_hePalettes + _vm->_hePaletteSlot + 768 + src[i] * 2); - switch (dstType) { - case kDstScreen: - WRITE_UINT16(dst + i * 2, color); - break; - case kDstResource: - WRITE_LE_UINT16(dst + i * 2, color); - break; - default: - error("copyFrameToBuffer: Unknown dstType %d", dstType); + if (surface->format.bytesPerPixel == 1) { + dst += y * pitch + x * 2; + do { + for (uint i = 0; i < w; i++) { + uint16 color = READ_LE_UINT16(_vm->_hePalettes + _vm->_hePaletteSlot + 768 + src[i] * 2); + switch (dstType) { + case kDstScreen: + WRITE_UINT16(dst + i * 2, color); + break; + case kDstResource: + WRITE_LE_UINT16(dst + i * 2, color); + break; + default: + error("copyFrameToBuffer: Unknown dstType %d", dstType); + } } - } - dst += pitch; - src += w; - } while (--h); + dst += pitch; + src += w; + } while (--h); + } else { + dst += y * pitch + x * 2; + do { + for (uint i = 0; i < w; i++) { + uint16 color = *((uint16 *)src + i); + switch (dstType) { + case kDstScreen: + WRITE_UINT16(dst + i * 2, color); + break; + case kDstResource: + WRITE_LE_UINT16(dst + i * 2, color); + break; + default: + error("copyFrameToBuffer: Unknown dstType %d", dstType); + } + } + dst += pitch; + src += surface->pitch; + } while (--h); + } } else { dst += y * pitch + x; do { @@ -101,7 +141,7 @@ void MoviePlayer::copyFrameToBuffer(byte *dst, int dstType, uint x, uint y, uint } void MoviePlayer::handleNextFrame() { - if (!isVideoLoaded()) + if (!_video->isVideoLoaded()) return; VirtScreen *pvs = &_vm->_virtscr[kMainVirtScreen]; @@ -115,17 +155,37 @@ void MoviePlayer::handleNextFrame() { } else if (_flags & 1) { copyFrameToBuffer(pvs->getBackPixels(0, 0), kDstScreen, 0, 0, pvs->pitch); - Common::Rect imageRect(getWidth(), getHeight()); + Common::Rect imageRect(_video->getWidth(), _video->getHeight()); _vm->restoreBackgroundHE(imageRect); } else { copyFrameToBuffer(pvs->getPixels(0, 0), kDstScreen, 0, 0, pvs->pitch); - Common::Rect imageRect(getWidth(), getHeight()); + Common::Rect imageRect(_video->getWidth(), _video->getHeight()); _vm->markRectAsDirty(kMainVirtScreen, imageRect); } - if (endOfVideo()) - close(); + if (_video->endOfVideo()) + _video->close(); +} + +void MoviePlayer::close() { + _video->close(); +} + +int MoviePlayer::getWidth() const { + return _video->getWidth(); +} + +int MoviePlayer::getHeight() const { + return _video->getHeight(); +} + +int MoviePlayer::getFrameCount() const { + return _video->getFrameCount(); +} + +int MoviePlayer::getCurFrame() const { + return _video->endOfVideo() ? -1 : _video->getCurFrame() + 1; } } // End of namespace Scumm diff --git a/engines/scumm/he/animation_he.h b/engines/scumm/he/animation_he.h index b3405fead0..7fa31a195d 100644 --- a/engines/scumm/he/animation_he.h +++ b/engines/scumm/he/animation_he.h @@ -23,34 +23,41 @@ #if !defined(SCUMM_HE_ANIMATION_H) && defined(ENABLE_HE) #define SCUMM_HE_ANIMATION_H -#include "video/smk_decoder.h" - #include "audio/mixer.h" +namespace Video { + class VideoDecoder; +} + namespace Scumm { class ScummEngine_v90he; -class MoviePlayer : public Video::SmackerDecoder { - ScummEngine_v90he *_vm; - - Audio::Mixer *_mixer; - - Audio::SoundHandle _bgSound; - Audio::AudioStream *_bgSoundStream; - - char baseName[40]; - uint32 _flags; - uint32 _wizResNum; - +class MoviePlayer { public: MoviePlayer(ScummEngine_v90he *vm, Audio::Mixer *mixer); + ~MoviePlayer(); int getImageNum(); int load(const char *filename, int flags, int image = 0); void copyFrameToBuffer(byte *dst, int dstType, uint x, uint y, uint pitch); void handleNextFrame(); + + void close(); + int getWidth() const; + int getHeight() const; + int getFrameCount() const; + int getCurFrame() const; + +private: + ScummEngine_v90he *_vm; + + Video::VideoDecoder *_video; + + char baseName[40]; + uint32 _flags; + uint32 _wizResNum; }; } // End of namespace Scumm 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/tsage/blueforce_logic.h b/engines/scumm/he/logic/baseball2001.cpp index 9237e50a13..342423fd79 100644 --- a/engines/tsage/blueforce_logic.h +++ b/engines/scumm/he/logic/baseball2001.cpp @@ -11,7 +11,7 @@ * 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 + * 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 @@ -20,23 +20,44 @@ * */ -#ifndef TSAGE_BLUEFORCE_LOGIC_H -#define TSAGE_BLUEFORCE_LOGIC_H +#include "scumm/he/intern_he.h" +#include "scumm/he/logic_he.h" -#include "common/scummsys.h" -#include "tsage/events.h" -#include "tsage/core.h" -#include "tsage/scenes.h" -#include "tsage/globals.h" +namespace Scumm { -namespace tSage { - -class BlueForceGame: public Game { +/** + * Logic code for: + * Backyard Baseball 2001 + */ +class LogicHEbaseball2001 : public LogicHE { public: - virtual void start(); - virtual Scene *createScene(int sceneNumber); + LogicHEbaseball2001(ScummEngine_v90he *vm) : LogicHE(vm) {} + + int versionID(); + int32 dispatch(int op, int numArgs, int32 *args); }; -} // End of namespace tSage +int LogicHEbaseball2001::versionID() { + return 1; +} + +int32 LogicHEbaseball2001::dispatch(int op, int numArgs, int32 *args) { + int res = 0; + + switch (op) { + case 3001: + // Check network status + break; + + default: + LogicHE::dispatch(op, numArgs, args); + } + + return res; +} + +LogicHE *makeLogicHEbaseball2001(ScummEngine_v90he *vm) { + return new LogicHEbaseball2001(vm); +} -#endif +} // End of namespace Scumm diff --git a/engines/scumm/he/logic/basketball.cpp b/engines/scumm/he/logic/basketball.cpp new file mode 100644 index 0000000000..8352aa4357 --- /dev/null +++ b/engines/scumm/he/logic/basketball.cpp @@ -0,0 +1,230 @@ +/* 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 "scumm/he/intern_he.h" +#include "scumm/he/logic_he.h" + +namespace Scumm { + +/** + * Logic code for: + * Backyard Basketball + */ +class LogicHEbasketball : public LogicHE { +public: + LogicHEbasketball(ScummEngine_v90he *vm) : LogicHE(vm) {} + + 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() { + return 1; +} + +int32 LogicHEbasketball::dispatch(int op, int numArgs, int32 *args) { + int res = 0; + + switch (op) { + case 1001: + break; + + case 1006: + break; + + case 1011: + break; + + case 1012: + res = op_1012(); + break; + + case 1035: + break; + + case 1050: + res = op_1050(args); + break; + + case 1051: + break; + + case 1052: + break; + + case 1053: + res = op_1053(); + break; + + case 1056: + break; + + case 1057: + break; + + case 1058: + break; + + case 1060: + break; + + case 1064: + break; + + case 1067: + break; + + case 1073: + break; + + case 1075: + break; + + case 1076: + break; + + case 1080: + break; + + case 1081: + break; + + case 1090: + break; + + case 1091: + break; + + case 1513: + break; + + default: + LogicHE::dispatch(op, numArgs, 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); +} + +} // End of namespace Scumm diff --git a/engines/scumm/he/logic/football.cpp b/engines/scumm/he/logic/football.cpp new file mode 100644 index 0000000000..f86f97eaf7 --- /dev/null +++ b/engines/scumm/he/logic/football.cpp @@ -0,0 +1,288 @@ +/* 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 "scumm/he/intern_he.h" +#include "scumm/he/logic_he.h" + +namespace Scumm { + +/** + * Logic code for: + * Backyard Football + * Backyard Football 2002 + */ +class LogicHEfootball : public LogicHE { +public: + LogicHEfootball(ScummEngine_v90he *vm) : LogicHE(vm) {} + + int versionID(); + int32 dispatch(int op, int numArgs, int32 *args); + +private: + int op_1004(int32 *args); + int op_1006(int32 *args); + int op_1007(int32 *args); + int op_1010(int32 *args); + int op_1022(int32 *args); + int op_1023(int32 *args); + int op_1024(int32 *args); +}; + +int LogicHEfootball::versionID() { + return 1; +} + +int32 LogicHEfootball::dispatch(int op, int numArgs, int32 *args) { + int res = 0; + + switch (op) { + case 1004: + res = op_1004(args); + break; + + case 1006: + res = op_1006(args); + break; + + case 1007: + res = op_1007(args); + break; + + case 1010: + res = op_1010(args); + break; + + case 1022: + res = op_1022(args); + break; + + case 1023: + res = op_1023(args); + break; + + case 1024: + res = op_1024(args); + break; + + case 8221968: + // Someone had a fun and used his birthday as opcode number + res = getFromArray(args[0], args[1], args[2]); + break; + + case 1492: case 1493: case 1494: case 1495: case 1496: + case 1497: case 1498: case 1499: case 1500: case 1501: + case 1502: case 1503: case 1504: case 1505: case 1506: + case 1507: case 1508: case 1509: case 1510: case 1511: + case 1512: case 1513: case 1514: case 1555: + // DirectPlay-related + // 1513: initialize + // 1555: set fake lag + break; + + case 2200: case 2201: case 2202: case 2203: case 2204: + case 2205: case 2206: case 2207: case 2208: case 2209: + case 2210: case 2211: case 2212: case 2213: case 2214: + case 2215: case 2216: case 2217: case 2218: case 2219: + case 2220: case 2221: case 2222: case 2223: case 2224: + case 2225: case 2226: case 2227: case 2228: + // Boneyards-related + break; + + case 3000: case 3001: case 3002: case 3003: case 3004: + // Internet-related + // 3000: check for updates + // 3001: check network status + // 3002: autoupdate + // 3003: close connection + break; + + default: + LogicHE::dispatch(op, numArgs, args); + warning("Tell sev how to reproduce it (%d)", op); + } + + return res; +} + +int LogicHEfootball::op_1004(int32 *args) { + // Identical to LogicHEsoccer::op_1004 + double res, a2, a4, a5; + + a5 = ((double)args[4] - (double)args[1]) / ((double)args[5] - (double)args[2]); + a4 = ((double)args[3] - (double)args[0]) / ((double)args[5] - (double)args[2]); + a2 = (double)args[2] - (double)args[0] * a4 - args[1] * a5; + + res = (double)args[6] * a4 + (double)args[7] * a5 + a2; + writeScummVar(108, (int32)res); + + writeScummVar(109, (int32)a2); + writeScummVar(110, (int32)a5); + writeScummVar(111, (int32)a4); + + return 1; +} + +int LogicHEfootball::op_1006(int32 *args) { + // This seems to be more or less the inverse of op_1010 + const double a1 = args[1]; + double res; + + // 2.9411764e-4 = 1/3400 + // 5.3050399e-2 = 1/18.85 = 20/377 + // 1.1764706e-2 = 1/85 = 40/3400 + // 1.2360656e-1 = 377/3050 + res = (1.0 - a1 * 2.9411764e-4 * 5.3050399e-2) * 1.2360656e-1 * args[0] + + a1 * 1.1764706e-2 + 46; + + // Shortened / optimized version of that formula: + // res = (377.0 - a1 / 170.0) / 3050.0 * args[0] + a1 / 85.0 + 46; + + writeScummVar(108, (int32)res); + + // 1.2360656e-1 = 377/3050 + // 1.1588235e-1 = 197/1700 = 394/3400 + res = 640.0 - args[2] * 1.2360656e-1 - a1 * 1.1588235e-1 - 26; + + writeScummVar(109, (int32)res); + + return 1; +} + +int LogicHEfootball::op_1007(int32 *args) { + double res, temp; + + temp = (double)args[1] * 0.32; + + if (temp > 304.0) + res = -args[2] * 0.142; + else + res = args[2] * 0.142; + + res += temp; + + writeScummVar(108, (int32)res); + + res = (1000.0 - args[2]) * 0.48; + + writeScummVar(109, (int32)res); + + return 1; +} + +int LogicHEfootball::op_1010(int32 *args) { + // This seems to be more or less the inverse of op_1006 + double a1 = (640.0 - (double)args[1] - 26.0) / 1.1588235e-1; + + // 2.9411764e-4 = 1/3400 + // 5.3050399e-2 = 1/18.85 = 20/377 + // 1.1764706e-2 = 1/85 = 40/3400 + // 1.2360656e-1 = 377/3050 + double a0 = ((double)args[0] - 46 - a1 * 1.1764706e-2) / + ((1.0 - a1 * 2.9411764e-4 * 5.3050399e-2) * 1.2360656e-1); + + writeScummVar(108, (int32)a0); + writeScummVar(109, (int32)a1); + + return 1; +} + +int LogicHEfootball::op_1022(int32 *args) { + double res; + double var10 = args[4] - args[1]; + double var8 = args[5] - args[2]; + double var6 = args[3] - args[0]; + + res = sqrt(var8 * var8 + var6 * var6 + var10 * var10); + + if (res >= (double)args[6]) { + var8 = (double)args[6] * var8 / res; + var10 = (double)args[6] * var10 / res; + res = (double)args[6] * var6 / res; + } + + writeScummVar(108, (int32)res); + writeScummVar(109, (int32)var10); + writeScummVar(110, (int32)var8); + + return 1; +} + +int LogicHEfootball::op_1023(int32 *args) { + double var10, var18, var20, var28, var30, var30_; + double argf[7]; + + for (int i = 0; i < 7; i++) + argf[i] = args[i]; + + var10 = (argf[3] - argf[1]) / (argf[2] - argf[0]); + var28 = var10 * var10 + 1; + var20 = argf[0] * var10; + var18 = (argf[5] + argf[1] + var20) * argf[4] * var10 * 2 + + argf[6] * argf[6] * var28 + argf[4] * argf[4] - + argf[0] * argf[0] * var10 * var10 - + argf[5] * argf[0] * var10 * 2 - + argf[5] * argf[1] * 2 - + argf[1] * argf[1] - argf[5] * argf[5]; + + if (var18 >= 0) { + var18 = sqrt(var18); + + var30_ = argf[4] + argf[5] * var10 + argf[1] * var10 + argf[0] * var10 * var10; + var30 = (var30_ - var18) / var28; + var18 = (var30_ + var18) / var28; + + if ((argf[0] - var30 < 0) && (argf[0] - var18 < 0)) { + var30_ = var30; + var30 = var18; + var18 = var30_; + } + var28 = var18 * var10 - var20 - argf[1]; + var20 = var30 * var10 - var20 - argf[1]; + } else { + var18 = 0; + var20 = 0; + var28 = 0; + var30 = 0; + } + + writeScummVar(108, (int32)var18); + writeScummVar(109, (int32)var28); + writeScummVar(110, (int32)var30); + writeScummVar(111, (int32)var20); + + return 1; +} + +int LogicHEfootball::op_1024(int32 *args) { + writeScummVar(108, 0); + writeScummVar(109, 0); + writeScummVar(110, 0); + writeScummVar(111, 0); + + return 1; +} + +LogicHE *makeLogicHEfootball(ScummEngine_v90he *vm) { + return new LogicHEfootball(vm); +} + +} // End of namespace Scumm diff --git a/engines/scumm/he/logic/funshop.cpp b/engines/scumm/he/logic/funshop.cpp new file mode 100644 index 0000000000..8993fedad2 --- /dev/null +++ b/engines/scumm/he/logic/funshop.cpp @@ -0,0 +1,216 @@ +/* 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 "scumm/he/intern_he.h" +#include "scumm/he/logic_he.h" + +namespace Scumm { + +/** + * Logic code for: + * Freddi Fish's One-Stop Fun Shop + * Pajama Sam's One-Stop Fun Shop + * Putt-Putt's One-Stop Fun Shop + */ +class LogicHEfunshop : public LogicHE { +public: + LogicHEfunshop(ScummEngine_v90he *vm) : LogicHE(vm) {} + + int versionID(); + int32 dispatch(int op, int numArgs, int32 *args); + +private: + void op_1004(int32 *args); + void op_1005(int32 *args); + int checkShape(int32 data0, int32 data1, int32 data4, int32 data5, int32 data2, int32 data3, int32 data6, int32 data7, int32 *x, int32 *y); +}; + +int LogicHEfunshop::versionID() { + return 1; +} + +int32 LogicHEfunshop::dispatch(int op, int numArgs, int32 *args) { + switch (op) { + case 1004: + op_1004(args); + break; + + case 1005: + op_1005(args); + break; + + default: + break; + } + + return 0; +} + +void LogicHEfunshop::op_1004(int32 *args) { + double data[8], at, sq; + int32 x, y; + int i=0; + + for (i = 0; i <= 6; i += 2) { + data[i] = getFromArray(args[0], 0, 519 + i); + data[i + 1] = getFromArray(args[0], 0, 519 + i + 1); + } + int s = checkShape((int32)data[0], (int32)data[1], (int32)data[4], (int32)data[5], + (int32)data[2], (int32)data[3], (int32)data[6], (int32)data[7], &x, &y); + + if (s != 1) { + error("LogicHEfunshop::op_1004: Your shape has defied the laws of physics"); + return; + } + + for (i = 0; i <= 6; i += 2) { + data[i] -= (double)x; + data[i + 1] -= (double)y; + } + + double a1 = (double)args[1] * DEG2RAD; + + for (i = 0; i <= 6; i += 2) { + at = atan2(data[i + 1], data[i]); + sq = sqrt(data[i + 1] * data[i + 1] + data[i] * data[i]); + + if (at <= 0) + at += 2 * M_PI; + + data[i] = cos(at + a1) * sq; + data[i + 1] = sin(at + a1) * sq; + } + + double minx = data[0]; + double miny = data[1]; + + for (i = 0; i <= 6; i += 2) { + if (data[i] < minx) + minx = data[i]; + if (data[i + 1] < miny) + miny = data[i + 1]; + } + + for (i = 0; i <= 6; i += 2) { + data[i] -= minx; + data[i + 1] -= miny; + + putInArray(args[0], 0, 519 + i, scummRound(data[i])); + putInArray(args[0], 0, 519 + i + 1, scummRound(data[i + 1])); + } +} + +void LogicHEfunshop::op_1005(int32 *args) { + double data[8]; + double args1, args2; + int i; + for (i = 520; i <= 526; i += 2) { + data[i - 520] = getFromArray(args[0], 0, i - 1); + data[i - 520 + 1] = getFromArray(args[0], 0, i); + } + + args1 = (double)args[1] * 0.01 + 1; + args2 = (double)args[2] * 0.01 + 1; + + for (i = 0; i < 4; i++) { + data[2 * i] *= args1; + data[2 * i + 1] *= args2; + } + + for (i = 520; i <= 526; i += 2) { + putInArray(args[0], 0, i - 1, scummRound(data[i - 520])); + putInArray(args[0], 0, i, scummRound(data[i - 520 + 1])); + } +} + +int LogicHEfunshop::checkShape(int32 data0, int32 data1, int32 data4, int32 data5, int32 data2, int32 data3, int32 data6, int32 data7, int32 *x, int32 *y) { + int32 diff5_1, diff0_4, diff7_3, diff2_6; + int32 diff1, diff2; + int32 delta, delta2; + int32 sum1, sum2; + + diff0_4 = data0 - data4; + diff5_1 = data5 - data1; + diff1 = data1 * data4 - data0 * data5; + sum1 = diff0_4 * data3 + diff1 + diff5_1 * data2; + sum2 = diff0_4 * data7 + diff1 + diff5_1 * data6; + + if (sum1 != 0 && sum2 != 0) { + sum2 ^= sum1; + + if (sum2 >= 0) + return 0; + } + + diff2_6 = data2 - data6; + diff7_3 = data7 - data3; + diff2 = data3 * data6 - data2 * data7; + sum1 = diff2_6 * data1 + diff2 + diff7_3 * data0; + sum2 = diff2_6 * data5 + diff2 + diff7_3 * data4; + + if (sum1 != 0 && sum2 != 0) { + sum2 ^= sum1; + + if (sum2 >= 0) + return 0; + } + + delta = diff2_6 * diff5_1 - diff0_4 * diff7_3; + + if (delta == 0) { + return 2; + } + + if (delta < 0) { + data7 = -((delta + 1) >> 1); + } else { + data7 = delta >> 1; + } + + delta2 = diff2 * diff0_4 - diff1 * diff2_6; + + if (delta2 < 0) { + delta2 -= data7; + } else { + delta2 += data7; + } + + *x = delta2 / delta; + + delta2 = diff1 * diff7_3 - diff2 * diff5_1; + + if (delta2 < 0) { + delta2 -= data7; + } else { + delta2 += data7; + } + + *y = delta2 / delta; + + return 1; +} + +LogicHE *makeLogicHEfunshop(ScummEngine_v90he *vm) { + return new LogicHEfunshop(vm); +} + +} // End of namespace Scumm diff --git a/engines/agi/preagi_common.h b/engines/scumm/he/logic/moonbase.cpp index a557f69977..fac2ea27ff 100644 --- a/engines/agi/preagi_common.h +++ b/engines/scumm/he/logic/moonbase.cpp @@ -20,32 +20,31 @@ * */ +#include "scumm/he/intern_he.h" +#include "scumm/he/logic_he.h" +namespace Scumm { -#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 +/** + * Logic code for: + * Moonbase Commander + */ +class LogicHEmoonbase : public LogicHE { +public: + LogicHEmoonbase(ScummEngine_v90he *vm) : LogicHE(vm) {} -enum SelectionTypes { - kSelYesNo, - kSelNumber, - kSelSpace, - kSelAnyKey, - kSelBackspace + int versionID(); }; -} // End of namespace Agi +int LogicHEmoonbase::versionID() { + if (_vm->_game.features & GF_DEMO) + return -100; + else + return 100; +} + +LogicHE *makeLogicHEmoonbase(ScummEngine_v90he *vm) { + return new LogicHEmoonbase(vm); +} -#endif +} // End of namespace Scumm diff --git a/engines/scumm/he/logic/puttrace.cpp b/engines/scumm/he/logic/puttrace.cpp new file mode 100644 index 0000000000..ea4397cd97 --- /dev/null +++ b/engines/scumm/he/logic/puttrace.cpp @@ -0,0 +1,376 @@ +/* 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 "scumm/he/intern_he.h" +#include "scumm/he/logic_he.h" + +namespace Scumm { + +/** + * Logic code for: + * Putt-Putt Enters the Race + */ +class LogicHErace : public LogicHE { +private: + float *_userData; + double *_userDataD; +public: + LogicHErace(ScummEngine_v90he *vm); + ~LogicHErace(); + + int versionID(); + int32 dispatch(int op, int numArgs, int32 *args); + +private: + int32 op_1003(int32 *args); + int32 op_1004(int32 *args); + int32 op_1100(int32 *args); + int32 op_1101(int32 *args); + int32 op_1102(int32 *args); + int32 op_1103(int32 *args); + int32 op_1110(); + int32 op_1120(int32 *args); + int32 op_1130(int32 *args); + int32 op_1140(int32 *args); + + void op_sub1(float arg); + void op_sub2(float arg); + void op_sub3(float arg); +}; + +LogicHErace::LogicHErace(ScummEngine_v90he *vm) : LogicHE(vm) { + // Originally it used 0x930 and stored both floats and doubles inside + _userData = (float *)calloc(550, sizeof(float)); + _userDataD = (double *)calloc(30, sizeof(double)); + + // FIXME: of the 550 entries in _userData, only 516 till 532 are used + // FIXME: similarly, in _userDataD only 9 till 17 are used for computations + // (some of the other entries are also set, but never read, hence useless). +} + +LogicHErace::~LogicHErace() { + free(_userData); + free(_userDataD); +} + +int LogicHErace::versionID() { + return 1; +} + +int32 LogicHErace::dispatch(int op, int numArgs, int32 *args) { + int32 res; + + switch (op) { + case 1003: + res = op_1003(args); + break; + + case 1004: + res = op_1004(args); + break; + + case 1100: + res = op_1100(args); + break; + + case 1101: + res = op_1101(args); + break; + + case 1102: + res = op_1102(args); + break; + + case 1103: + res = op_1103(args); + break; + + case 1110: + res = op_1110(); + break; + + case 1120: + res = op_1120(args); + break; + + case 1130: + res = op_1130(args); + break; + + case 1140: + res = op_1140(args); + break; + + default: + res = 0; + break; + + } + + return res; +} + +#define RAD2DEG (180 / M_PI) +#define DEG2RAD (M_PI / 180) + +int32 LogicHErace::op_1003(int32 *args) { + int value = args[2] ? args[2] : 1; + + writeScummVar(108, (int32)(atan2((double)args[0], (double)args[1]) * RAD2DEG * value)); + + return 1; +} + +int32 LogicHErace::op_1004(int32 *args) { + int value = args[1] ? args[1] : 1; + + writeScummVar(108, (int32)(sqrt((float)args[0]) * value)); + + return 1; +} + +int32 LogicHErace::op_1100(int32 *args) { + // _userData 516,517,518 describe a 3D translation? + _userData[516] = (float)args[0] / args[10]; + _userData[517] = (float)args[1] / args[10]; + _userData[518] = (float)args[2] / args[10]; + + // _userData 519,520,521 describe rotation angles around the x,y,z axes? + _userData[519] = (float)args[3] / args[10]; + _userData[520] = (float)args[4] / args[10]; + _userData[521] = (float)args[5] / args[10]; + + op_sub1(_userData[520]); + op_sub2(_userData[521]); + + // _userData[532] seems to be some kind of global scale factor + _userData[532] = (float)args[10]; + + _userData[524] = (float)args[8]; // not used + _userData[525] = (float)args[9]; // not used + _userData[522] = (float)args[6] / args[10]; // not used + _userData[523] = (float)args[7] / args[10]; // only used to compute 528 and 529 + + // The following two are some kind of scale factors + _userData[526] = (float)args[6] / args[8] / args[10]; + _userData[527] = (float)args[7] / args[9] / args[10]; + + // Set var 108 and 109 -- the value set here corresponds to the values + // set by op_1110! + writeScummVar(108, (int32)((float)args[6] / args[8] * args[10])); + writeScummVar(109, (int32)((float)args[7] / args[9] * args[10])); + + _userData[528] = (float)(_userData[519] - _userData[523] * 0.5); + _userData[529] = (float)(_userData[519] + _userData[523] * 0.5); + + writeScummVar(110, (int32)(_userData[528] * args[10])); + writeScummVar(111, (int32)(_userData[529] * args[10])); + + // 530 and 531 are only used to set vars 112 and 113, so no need + // to store them permanently + _userData[530] = (float)(_userData[517] / tan(_userData[529] * DEG2RAD)); + _userData[531] = (float)(_userData[517] / tan(_userData[528] * DEG2RAD)); + + writeScummVar(112, (int32)(_userData[530] * args[10])); + writeScummVar(113, (int32)(_userData[531] * args[10])); + + return 1; +} + +int32 LogicHErace::op_1101(int32 *args) { + // Update rotation params? + int32 retval; + float temp; + + temp = args[0] / _userData[532]; + if (_userData[519] != temp) { + _userData[519] = temp; + op_sub3(temp); + retval = 1; + } else { + retval = (int32)temp; + } + + temp = args[1] / _userData[532]; + if (_userData[520] != temp) { + _userData[520] = temp; + op_sub1(temp); + retval = 1; + } + + temp = args[2] / _userData[532]; + if (_userData[521] != temp) { + _userData[521] = temp; + op_sub2(temp); + retval = 1; + } + + return retval; +} + +int32 LogicHErace::op_1102(int32 *args) { + // Update translation params? + int32 retval; + float temp; + + temp = args[0] / _userData[532]; + if (_userData[516] != temp) { + _userData[516] = temp; + retval = 1; + } else { + retval = (int32)_userData[532]; + } + + temp = args[1] / _userData[532]; + if (_userData[517] != temp) { + _userData[517] = temp; + retval = 1; + } + + temp = args[2] / _userData[532]; + if (_userData[518] != temp) { + _userData[518] = temp; + retval = 1; + } + + return retval; +} + +int32 LogicHErace::op_1103(int32 *args) { + double angle = args[0] / args[1] * DEG2RAD; + + writeScummVar(108, (int32)(sin(angle) * args[2])); + writeScummVar(109, (int32)(cos(angle) * args[2])); + + return 1; +} + +int32 LogicHErace::op_1110() { + writeScummVar(108, (int32)(_userData[526] * _userData[532] * _userData[532])); + writeScummVar(109, (int32)(_userData[527] * _userData[532] * _userData[532])); + writeScummVar(110, (int32)(_userData[532])); + + return 1; +} + +int32 LogicHErace::op_1120(int32 *args) { + double a0, a1, a2; + double b0, b1, b2; + double res1, res2; + + a0 = args[0] / _userData[532] - _userData[516]; + a1 = args[1] / _userData[532] - _userData[517]; + a2 = args[2] / _userData[532] - _userData[518]; + + // Perform matrix multiplication (multiplying by a rotation matrix) + b2 = a2 * _userDataD[17] + a1 * _userDataD[14] + a0 * _userDataD[11]; + b1 = a2 * _userDataD[16] + a1 * _userDataD[13] + a0 * _userDataD[10]; + b0 = a2 * _userDataD[15] + a1 * _userDataD[12] + a0 * _userDataD[9]; + + res1 = (atan2(b0, b2) * RAD2DEG) / _userData[526]; + res2 = (atan2(b1, b2) * RAD2DEG - _userData[528]) / _userData[527]; + + writeScummVar(108, (int32)res1); + writeScummVar(109, (int32)res2); + + return 1; +} + +int32 LogicHErace::op_1130(int32 *args) { + double cs = cos(args[0] / _userData[532] * DEG2RAD); + double sn = sin(args[0] / _userData[532] * DEG2RAD); + + writeScummVar(108, (int32)(cs * args[1] + sn * args[2])); + writeScummVar(109, (int32)(cs * args[2] - sn * args[1])); + + return 1; +} + +int32 LogicHErace::op_1140(int32 *args) { + // This functions seems to perform some kind of projection: We project + // the vector (arg2,arg3) onto the vector (arg0,arg1), but also apply + // some kind of distortion factor ?!? + double x = args[2], y = args[3]; + + // We start by normalizing the vector described by arg2 and arg3. + // So compute its length and divide the x and y coordinates + const double sq = sqrt(x*x + y*y); + x /= sq; + y /= sq; + + // Compute the scalar product of the vectors (arg0,arg1) and (x,y) + const double scalarProduct = x * args[0] + y * args[1]; + + // Finally compute the projection of (arg2,arg3) onto (arg0,arg1) + double projX = args[0] - 2 * scalarProduct * x; + double projY = args[1] - 2 * scalarProduct * y; + + projX = projX * 20.0 / 23.0; // FIXME: Why is this here? + + writeScummVar(108, (int32)projX); + + if (args[3] >= 0) // FIXME: Why is this here? + projY = projY * 5.0 / 6.0; + + writeScummVar(109, (int32)projY); + + return 1; +} + +void LogicHErace::op_sub1(float arg) { + // Setup a rotation matrix + _userDataD[10] = _userDataD[12] = _userDataD[14] = _userDataD[16] = 0; + _userDataD[13] = 1; + + _userDataD[9] = cos(arg * DEG2RAD); + _userDataD[15] = sin(arg * DEG2RAD); + _userDataD[11] = -_userDataD[15]; + _userDataD[17] = _userDataD[9]; +} + +void LogicHErace::op_sub2(float arg) { + // Setup a rotation matrix -- but it is NEVER USED! + _userDataD[20] = _userDataD[21] = _userDataD[24] = _userDataD[25] = 0; + _userDataD[26] = 1; + + _userDataD[19] = sin(arg * DEG2RAD); + _userDataD[18] = cos(arg * DEG2RAD); + _userDataD[21] = -_userDataD[19]; + _userDataD[22] = _userDataD[18]; +} + +void LogicHErace::op_sub3(float arg) { + // Setup a rotation matrix -- but it is NEVER USED! + _userDataD[1] = _userDataD[2] = _userDataD[3] = _userDataD[6] = 0; + _userDataD[0] = 1; + + _userDataD[4] = cos(arg * DEG2RAD); + _userDataD[5] = sin(arg * DEG2RAD); + _userDataD[7] = -_userDataD[5]; + _userDataD[8] = _userDataD[4]; +} + +LogicHE *makeLogicHErace(ScummEngine_v90he *vm) { + return new LogicHErace(vm); +} + +} // End of namespace Scumm diff --git a/engines/scumm/he/logic/soccer.cpp b/engines/scumm/he/logic/soccer.cpp new file mode 100644 index 0000000000..05f377a736 --- /dev/null +++ b/engines/scumm/he/logic/soccer.cpp @@ -0,0 +1,1206 @@ +/* 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 "scumm/he/intern_he.h" +#include "scumm/he/logic_he.h" + +namespace Scumm { + +/** + * Logic code for: + * Backyard Soccer + * Backyard Soccer MLS Edition + * Backyard Soccer 2004 + */ +class LogicHEsoccer : public LogicHE { +private: + double *_userDataD; + +public: + LogicHEsoccer(ScummEngine_v90he *vm); + ~LogicHEsoccer(); + + int versionID(); + int32 dispatch(int op, int numArgs, int32 *args); + + void beforeBootScript(); + void initOnce(); + int startOfFrame(); + +private: + int op_1005(float x1, float y1, float z1, float x2, float y2, float z2, float *nextVelX, float *nextVelY, float *nextVelZ, float *a10); + int op_1006(int32 a1, int32 a2, int32 a3, int32 a4); + int op_1007(int32 *args); + int op_1008(int outArray, int srcX, int srcY, int srcZ, int vecX, int vecY, int vecZ, int airResX, int airResY, int airResZ, int vecNumerator, int vecDenom, int gravityMult, int requiredSegments, int a15, int a16, int a17, int a18, int fieldType); + int op_1011(int32 worldPosArray, int32 screenPosArray, int32 a3, int32 closestActorArray, int32 maxDistance, int32 fieldAreaArray); + int op_1012(int32 *args); + int op_1013(int32 a1, int32 a2, int32 a3); + int op_1014(int32 srcX, int32 srcY, int32 srcZ, int32 velX, int32 velY, int32 velZ, int32 outArray, int32 dataArrayId, int32 indexArrayId, int32 requestType, int32 vecNumerator, int32 vecDenom, int32 a13, int32 a14); + int op_1016(int32 *args); + int op_1017(int32 *args); + int op_1019(int32 *args); + int op_1021(int32 inX, int32 inY, int32 inZ, int32 velX, int32 velY, int32 velZ, int32 internalUse); + + // op_1007 allocates some arrays + // they're then filled by op_1019 + byte _collisionObjIds[4096], _collisionNodeEnabled[585]; + + // op_1011 has a subfunction + void calculateDistances(int32 worldPosArray, int32 a2, int32 closestActorArray, int32 maxDistance); + + // array containing collision detection tree + bool _collisionTreeAllocated; + uint32 *_collisionTree; + int addCollisionTreeChild(int depth, int index, int parent); + + // op_1014 has several subops + // ...and several sub-subops + int generateCollisionObjectList(float srcX, float srcY, float srcZ, float velX, float velY, float velZ); + int addFromCollisionTreeNode(int index, int parent, uint32 *indices, int objIndexBase); + void addCollisionObj(byte objId); + int findCollisionWith(int objId, float inX, float inY, float inZ, float inXVec, float inYVec, float inZVec, float &collideX, float &collideY, float &collideZ, int indexArrayId, int dataArrayId, float *nextVelX, float *nextVelY, float *nextVelZ, float *a15); + void getPointsForFace(int faceId, float &x1, float &y1, float &z1, float &x2, float &y2, float &z2, float &x3, float &y3, float &z3, float &x4, float &y4, float &z4, const int *objPoints); + void crossProduct(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4, float &outX, float &outY, float &outZ); + double dotProduct(float a1, float a2, float a3, float a4, float a5, float a6); + void sortCollisionList(float *data, int numEntries, int entrySize, int compareOn); + int setCollisionOutputData(float *collisionData, int entrySize, int dataArrayId, int indexArrayId, int startX, int startY, int startZ, float a8, int a9, int a10, int a11, int *out); + + // op_1014 sets an array optionally based upon + // setCollisionOutputData; it is then used by op_1008 + int _internalCollisionOutData[10]; + Common::List<byte> _collisionObjs; + + // op_1021 can (optionally) set two variables for use in op_1008 + uint32 _var1021[2]; +}; + +int LogicHEsoccer::versionID() { + return 1; +} + +LogicHEsoccer::LogicHEsoccer(ScummEngine_v90he *vm) : LogicHE(vm) { + _userDataD = (double *)calloc(1732, sizeof(double)); + _collisionTree = 0; + _collisionTreeAllocated = false; +} + +LogicHEsoccer::~LogicHEsoccer() { + free(_userDataD); + delete[] _collisionTree; +} + +int32 LogicHEsoccer::dispatch(int op, int numArgs, int32 *args) { + int res = 0; + + switch (op) { + case 1006: + res = op_1006(args[0], args[1], args[2], args[3]); + break; + + case 1007: + res = op_1007(args); + break; + + case 1008: + res = op_1008(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16], args[17], args[18]); + break; + + case 1011: + res = op_1011(args[0], args[1], args[2], args[3], args[4], args[5]); + break; + + case 1012: + res = op_1012(args); + break; + + case 1013: + res = op_1013(args[0], args[1], args[2]); + break; + + case 1014: + res = op_1014(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13]); + break; + + case 1016: + res = op_1016(args); + break; + + case 1017: + res = op_1017(args); + break; + + case 1019: + res = op_1019(args); + break; + + case 1021: + res = op_1021(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); + break; + + case 1001: case 1002: case 1003: case 1005: + case 1009: case 8221968: + // In the u32, but unused by any of the soccer scripts + // 1005 is called from another opcode, however + error("Unused soccer u32 opcode %d called", op); + + case 1004: case 1010: case 1015: case 1018: + case 1020: + // Used only by the unaccessible in-game editor (so, fall through) + + default: + LogicHE::dispatch(op, numArgs, args); + } + + return res; +} + +void LogicHEsoccer::beforeBootScript() { + _userDataD[530] = 0; +} + +void LogicHEsoccer::initOnce() { + // The original sets some paths here that we don't need to worry about + _collisionTreeAllocated = false; + _userDataD[530] = 0; +} + +int LogicHEsoccer::startOfFrame() { + // This variable is some sort of flag that activates this mode + int res = (int)_userDataD[530]; + + if (res) + res = op_1011((int)_userDataD[531], (int)_userDataD[532], (int)_userDataD[533], (int)_userDataD[534], (int)_userDataD[535], (int)_userDataD[536]); + + return res; +} + +int LogicHEsoccer::op_1005(float x1, float y1, float z1, float x2, float y2, float z2, float *nextVelX, float *nextVelY, float *nextVelZ, float *a10) { + // Called from op_1014 + + double dot = x1 * x2 + y1 * y2 + z1 * z2; + *nextVelX = x2 - 2 * dot * x1; + *nextVelY = y2 - 2 * dot * y1; + *nextVelZ = z2 - 2 * dot * z1; + *a10 = 1.0f; // It always does this. How curious! + + return 1; +} + +int LogicHEsoccer::op_1006(int32 a1, int32 a2, int32 a3, int32 a4) { + double v1 = a1 * 0.01; + double v2 = a2 * 0.01; + double v3 = a3 * 0.01; + double var108, var109; + + _userDataD[529] = a4; + + var108 = atan2(v1, v3) * _userDataD[523] - a4; + var109 = _userDataD[526] - _userDataD[528] - (_userDataD[521] - atan2(_userDataD[524] - v2, v3)) * _userDataD[522]; + + writeScummVar(108, (int32)var108); + writeScummVar(109, (int32)var109); + + return 1; +} + +int LogicHEsoccer::op_1007(int32 *args) { + // Used when the HE logo is shown + // This initializes the _userDataD fields that are used in op_1006/op_1011 + + float y1 = (double)args[0] / 100.0; + float x1 = (double)args[1] / 100.0; + float x2 = (double)args[2] / 100.0; + float y2 = (double)args[3] / 100.0; + float x3 = (double)args[4] / 100.0; + + _userDataD[518] = x2; + _userDataD[519] = 2 * atan2(y2, x2 - x3); + _userDataD[520] = atan2(y1, x2); + _userDataD[521] = atan2(y1, x1); + _userDataD[524] = y1; + _userDataD[525] = 2 * (_userDataD[521] - _userDataD[520]); + _userDataD[526] = args[6]; + _userDataD[527] = args[5]; + _userDataD[528] = args[7]; + _userDataD[522] = _userDataD[526] / _userDataD[525]; + _userDataD[523] = _userDataD[527] / _userDataD[519]; + + // Clear both byte arrays + memset(_collisionObjIds, 0, 4096); + memset(_collisionNodeEnabled, 0, 585); + + if (!_collisionTreeAllocated) + op_1013(4, args[8], args[9]); + + return 1; +} + +static inline double vectorLength(double x, double y, double z) { + return sqrt(x * x + y * y + z * z); +} + +int LogicHEsoccer::op_1008(int outArray, int srcX, int srcY, int srcZ, int vecX, int vecY, int vecZ, int airResX, int airResY, int airResZ, int vecNumerator, int vecDenom, int gravityMult, int requiredSegments, int a15, int a16, int a17, int a18, int fieldType) { + // Calculate requiredSegments consecutive movement segments, and place + // the associated data (positions, vectors, etc) into outArray. + + int loopsSoFar = 0; + int segmentsSoFar = 1; + int prevVecY = 500; + int inX = srcX; + int inZ = srcZ; + int checkForCollisions = 0; + + while (segmentsSoFar <= requiredSegments) { + if (fieldType == 1 && srcZ > 8819) + checkForCollisions = 1; + else if (fieldType == 2 && (srcX < -2350 || srcX > 2350)) + checkForCollisions = 1; + else if (fieldType == 3 && (srcX < -2350 || srcX > 2350 || srcZ < 6119 || srcZ > 8819)) + checkForCollisions = 1; + + if (srcY > 0) + vecY -= vecNumerator * gravityMult / vecDenom; + + int prevX = srcX; + int prevY = srcY; + int prevZ = srcZ; + srcX += vecNumerator * vecX / vecDenom; + srcY += vecNumerator * vecY / vecDenom; + srcZ += vecNumerator * vecZ / vecDenom; + + if (srcY > 0) { + if (checkForCollisions && op_1014(prevX, prevY, prevZ, vecX, vecY, vecZ, 0, a17, a18, 3, vecNumerator, vecDenom, a15, a16)) { + srcX = _internalCollisionOutData[6]; + srcY = _internalCollisionOutData[7]; + srcZ = _internalCollisionOutData[8]; + vecX = _internalCollisionOutData[3]; + vecY = _internalCollisionOutData[4]; + vecZ = _internalCollisionOutData[5]; + putInArray(outArray, segmentsSoFar, 0, loopsSoFar); + putInArray(outArray, segmentsSoFar, 1, (int)vectorLength((double)(_internalCollisionOutData[6] - inX), 0.0, (double)(_internalCollisionOutData[8] - inZ))); + putInArray(outArray, segmentsSoFar, 2, _internalCollisionOutData[6]); + putInArray(outArray, segmentsSoFar, 3, _internalCollisionOutData[7]); + putInArray(outArray, segmentsSoFar, 4, _internalCollisionOutData[8]); + putInArray(outArray, segmentsSoFar, 5, vecX); + putInArray(outArray, segmentsSoFar, 6, vecY); + putInArray(outArray, segmentsSoFar++, 7, vecZ); + } + } else { + srcY = 0; + int thisVecX = vecX; + int thisVecZ = vecZ; + vecX = vecX * airResX / 100; + + if (vecY) { + int v18 = ABS(vecY); + if (v18 > ABS(prevVecY)) + vecY = ABS(prevVecY); + vecY = ABS(airResY * vecY) / 100; + } + + vecZ = airResZ * vecZ / 100; + + if (prevVecY >= 0) { + if (op_1014(prevX, prevY, prevZ, thisVecX, prevVecY, thisVecZ, 0, a17, a18, 3, vecNumerator, vecDenom, a15, a16)) { + srcX = _internalCollisionOutData[6]; + srcY = _internalCollisionOutData[7]; + srcZ = _internalCollisionOutData[8]; + vecX = _internalCollisionOutData[3]; + vecY = _internalCollisionOutData[4]; + vecZ = _internalCollisionOutData[5]; + } + } else { + if (checkForCollisions) { + op_1021(srcX, 0, srcZ, thisVecX, prevVecY, thisVecZ, 1); + + if (op_1014(prevX, prevY, prevZ, thisVecX, prevVecY, thisVecZ, 0, a17, a18, 3, vecNumerator, vecDenom, a15, a16)) { + srcX = _internalCollisionOutData[6]; + srcY = _internalCollisionOutData[7]; + srcZ = _internalCollisionOutData[8]; + vecX = _internalCollisionOutData[3]; + vecY = _internalCollisionOutData[4]; + vecZ = _internalCollisionOutData[5]; + } else { + // try it with the output of op_1021 instead + int tmpVecZ = vecZ + prevZ - _var1021[1]; + int v20 = ABS(prevVecY); + + if (op_1014(_var1021[0], 0, _var1021[1], vecX + prevX - _var1021[0], v20 - prevY, tmpVecZ, 0, a17, a18, 3, vecNumerator, vecDenom, a15, a16)) { + srcX = _internalCollisionOutData[6]; + srcY = _internalCollisionOutData[7]; + srcZ = _internalCollisionOutData[8]; + vecX = _internalCollisionOutData[3]; + vecY = _internalCollisionOutData[4]; + vecZ = _internalCollisionOutData[5]; + } + } + } + } + + prevVecY = vecY; + putInArray(outArray, segmentsSoFar, 0, loopsSoFar); + putInArray(outArray, segmentsSoFar, 1, (int32)vectorLength(srcX - inX, 0.0, srcZ - inZ)); + putInArray(outArray, segmentsSoFar, 2, srcX); + putInArray(outArray, segmentsSoFar, 3, srcY); + putInArray(outArray, segmentsSoFar, 4, srcZ); + putInArray(outArray, segmentsSoFar, 5, vecX); + putInArray(outArray, segmentsSoFar, 6, vecY); + putInArray(outArray, segmentsSoFar++, 7, vecZ); + } + + loopsSoFar++; + } + + return 1; +} + +int LogicHEsoccer::op_1011(int32 worldPosArray, int32 screenPosArray, int32 a3, int32 closestActorArray, int32 maxDistance, int32 fieldAreaArray) { + // This is called on each frame by startOfFrame() if activated by op_1012. + + float objY = 0.0; + + // First, iterate over the field objects and project them onto the screen. + for (int i = 0; i < 18; i++) { + int rawX = getFromArray(worldPosArray, i, 0); + int rawY = getFromArray(worldPosArray, i, 1); + int rawZ = getFromArray(worldPosArray, i, 2); + + float objX = (double)rawX / 100.0; + objY = (double)rawY / 100.0; + float objZ = (double)rawZ / 100.0; + + if (i < 13) { + // For the players and the ball: work out the area of the field + // this object is in, storing it in an array if provided. + int areaX = (rawX + 2750) / 500; + areaX = CLIP(areaX, 0, 10); + + int areaZ = (9219 - rawZ) / 500; + areaZ = CLIP(areaZ, 0, 6); + + if (fieldAreaArray) + putInArray(fieldAreaArray, 0, i, areaX + 11 * areaZ); + } + + float v7 = atan2(_userDataD[524] - objY, (double)objZ); + int screenY = (int)(_userDataD[526] - (_userDataD[521] - v7) * _userDataD[522] - 300.0); + double v9 = _userDataD[523]; + + // x/y position of objects + putInArray(screenPosArray, i, 0, (int32)(atan2(objX, objZ) * v9 + 640.0)); + putInArray(screenPosArray, i, 1, screenY); + + double v10 = atan2(_userDataD[524], (double)objZ); + int shadowScreenY = (int)(_userDataD[526] - (_userDataD[521] - (float)v10) * _userDataD[522] - 300.0); + double v13 = _userDataD[523]; + + // x/y position of shadows + putInArray(screenPosArray, i + ((_vm->_game.id == GID_SOCCER) ? 20 : 22), 0, (int32)(atan2(objX, objZ) * v13 + 640.0)); + putInArray(screenPosArray, i + ((_vm->_game.id == GID_SOCCER) ? 20 : 22), 1, shadowScreenY); + } + + // soccer only uses one array here + // soccermls/soccer2004 use four + int start = (_vm->_game.id == GID_SOCCER) ? 19 : 18; + int end = (_vm->_game.id == GID_SOCCER) ? 19 : 21; + + // The following loop is doing cursor scaling + // The further up on the screen, the smaller the cursor is + for (int i = start; i <= end; i++) { + int x = getFromArray(screenPosArray, i, 0); + int y = getFromArray(screenPosArray, i, 1); + + // This retains objY from (i == 17)? + float v16 = _userDataD[524] - objY; + float scaledZ = v16 / tan((_userDataD[528] + y - _userDataD[526]) / _userDataD[522] + _userDataD[521]); + double scaledX = tan((double)(x - ((_vm->_game.id == GID_SOCCER) ? 0 : 640)) / _userDataD[523]) * scaledZ; + putInArray(worldPosArray, i, 0, (int)(scaledX * 100.0)); + putInArray(worldPosArray, i, 2, (int)(scaledZ * 100.0)); + } + + calculateDistances(worldPosArray, a3, closestActorArray, maxDistance); + + return 1; +} + +static inline int distance(int a1, int a2, int a3, int a4) { + return (int)sqrt((double)((a4 - a3) * (a4 - a3) + (a2 - a1) * (a2 - a1))); +} + +void LogicHEsoccer::calculateDistances(int32 worldPosArray, int32 a2, int32 closestActorArray, int32 maxDistance) { + // As you can guess, this is called from op_1011 + // This seems to be checking distances between the players and the ball + // and which distance is the shortest. + + int closestActor[13]; + int objectX[13]; + int objectZ[13]; + int closestDistance[195]; + + for (int i = 0; i < 13; i++) { + closestActor[i] = 0; + objectX[i] = getFromArray(worldPosArray, i, 0); + objectZ[i] = getFromArray(worldPosArray, i, 2); + } + + // 12 here, 13 up there + // Probably 12 for players, 13 for players+ball + for (int i = 0; i < 12; i++) { + int bestDistance = maxDistance; + for (int j = i + 1; j < 13; j++) { + closestDistance[i * 15 + j] = distance(objectX[i], objectX[j], objectZ[i], objectZ[j]); + putInArray(a2, i, j, closestDistance[i * 15 + j]); + putInArray(a2, j, i, closestDistance[i * 15 + j]); + if (closestDistance[i * 15 + j] < bestDistance) { + bestDistance = closestDistance[i * 15 + j]; + closestActor[i] = j + 1; + closestActor[j] = i + 1; + } + } + } + + int v13 = getFromArray(worldPosArray, 18, 0); + int v14 = getFromArray(worldPosArray, 18, 2); + int v15 = getFromArray(worldPosArray, 19, 0); + int v16 = getFromArray(worldPosArray, 19, 2); + int v19[15]; + int v20[15]; + + if (_vm->_game.id == GID_SOCCER) { + // soccer gets to be different + for (int i = 0; i < 13; i++) + v20[i] = distance(v15, objectX[i], v16, objectZ[i]); + + for (int i = 0; i < 13; i++) + v19[i] = distance(v13, objectX[i], v14, objectZ[i]); + } else { + // soccermls and soccer2004 use two other arrays here + int v9 = getFromArray(worldPosArray, 20, 0); + int v10 = getFromArray(worldPosArray, 20, 2); + int v11 = getFromArray(worldPosArray, 21, 0); + int v12 = getFromArray(worldPosArray, 21, 2); + + for (int i = 0; i < 6; i++) { + v20[i] = distance(v9, objectX[i], v10, objectZ[i]); + v19[i] = distance(v13, objectX[i], v14, objectZ[i]); + } + + for (int i = 6; i < 13; i++) { + v20[i] = distance(v11, objectX[i], v12, objectZ[i]); + v19[i] = distance(v15, objectX[i], v16, objectZ[i]); + } + } + + for (int i = 0; i < 13; i++) { + putInArray(a2, 14, i, v20[i]); + putInArray(a2, i, 14, v20[i]); + putInArray(a2, 13, i, v19[i]); + putInArray(a2, i, 13, v19[i]); + putInArray(closestActorArray, 0, i, closestActor[i]); + } +} + +int LogicHEsoccer::op_1012(int32 *args) { + // Used after op_1019 + // This function activates startOfFrame() to call op_1011 + // (Possibly field parameters?) + + _userDataD[530] = (args[0] != 0) ? 1 : 0; + _userDataD[531] = args[1]; + _userDataD[532] = args[2]; + _userDataD[533] = args[3]; + _userDataD[534] = args[4]; + _userDataD[535] = args[5]; + _userDataD[536] = args[6]; + + return 1; +} + +int LogicHEsoccer::addCollisionTreeChild(int depth, int index, int parent) { + uint32 *dataPtr = _collisionTree + 11 * index; + + /* + * This sets up a node of the tree stored in _collisionTree. There are + * two sets of parents (at depth 1 and 2), then child nodes at depth + * 3 which represent a single collision object. + * + * 0 = this index, 1 = parent index, + * 2-9 = child indices (or all -1 if leaf), + * 10 = _collisionObjIds index (if leaf) + */ + dataPtr[0] = index; + dataPtr[1] = parent; + + if (depth > 2) { + // store the offset into _collisionObjIds (which holds collision object ids), + // but subtract 585 first because there are already (8 + 8*8 + 8*8*8 = 584) + // indexes at higher levels of the tree, and we want to start at 0 + dataPtr[10] = 8 * index - 585; + for (int i = 0; i < 8; i++) + dataPtr[i + 2] = 0xffffffff; + } else { + for (int i = 0; i < 8; i++) + dataPtr[i + 2] = addCollisionTreeChild(depth + 1, i + 8 * index + 1, index); + } + + return index; +} + +int LogicHEsoccer::op_1013(int32 a1, int32 a2, int32 a3) { + // Initialises _collisionTree, a tree used for collision detection. + // It is used by op_1014 to work out which objects to check. + + _collisionTree = new uint32[585 * 11]; + _collisionTreeAllocated = true; + for (int i = 0; i < 585 * 11; i++) + _collisionTree[i] = 0; + + for (int i = 0; i < 8; i++) + _collisionTree[i + 2] = addCollisionTreeChild(1, i + 1, 0); + + return 1; +} + +int LogicHEsoccer::op_1014(int32 srcX, int32 srcY, int32 srcZ, int32 velX, int32 velY, int32 velZ, int32 outArray, int32 dataArrayId, int32 indexArrayId, int32 requestType, int32 vecNumerator, int32 vecDenom, int32 a13, int32 a14) { + // Used many times during a match + // And called from op_1008! + // This seems to be doing collision handling + + double startX = (double)srcX; + double startY = (double)srcY; + double startZ = (double)srcZ; + double adjustedVelZ = 0.0, adjustedVelY = 0.0, adjustedVelX = 0.0; + + writeScummVar(108, 0); + writeScummVar(109, 0); + + switch (requestType) { + case 1: + case 3: + adjustedVelX = (double)velX * (double)vecNumerator / (double)vecDenom / 100.0; + adjustedVelY = (double)velY * (double)vecNumerator / (double)vecDenom / 100.0; + adjustedVelZ = (double)velZ * (double)vecNumerator / (double)vecDenom / 100.0; + break; + case 2: + // length of movement vector + double v15 = vectorLength((double)velX * (double)vecNumerator / (double)vecDenom, (double)velY * (double)vecNumerator / (double)vecDenom, (double)velZ * (double)vecNumerator / (double)vecDenom); + + if (v15 != 0.0) { + // add the (scaled) movement vector to the input + double v26 = (double)ABS(velX) * (double)vecNumerator / (double)vecDenom * 50.0 / v15; + srcX = (int)((double)srcX + v26); + double v25 = (double)ABS(velY) * (double)vecNumerator / (double)vecDenom * 50.0 / v15; + srcY = (int)((double)srcY + v25); + double v24 = (double)ABS(velZ) * (double)vecNumerator / (double)vecDenom * 50.0 / v15; + srcZ = (int)((double)srcZ + v24); + } + + // srcX = (newX / newZ) * 3869 + startX = (double)srcX / (double)srcZ * 3869.0; + // srcY = (newY - (+524 * 100)) / (newZ * 3869 + (+524 * 100) + startY = ((double)srcY - _userDataD[524] * 100.0) / (double)srcZ * 3869.0 + _userDataD[524] * 100.0; + // srcZ = 3869 + startZ = 3869.0; + // vectorX = (newX - srcX) / 100 + adjustedVelX = ((double)srcX - startX) / 100.0; + // vectorY = (newY - srcY) / 100 + adjustedVelY = ((double)srcY - startY) / 100.0; + // vectorZ = (newZ - 3869 = srcZ) / 100 + adjustedVelZ = ((double)srcZ - 3869.0) / 100.0; + break; + } + + int foundCollision = 0; + + // work out which collision objects we might collide with (if any) + if (generateCollisionObjectList(startX, startY, startZ, adjustedVelX, adjustedVelY, adjustedVelZ)) { + int collisionId = 0; + float v46; // always 1.0 after a collision due to op_1005 + + float collisionInfo[42 * 8]; + memset(collisionInfo, 0, 42 * 8 * sizeof(float)); + + // check each potential collision object for an actual collision, + // add it to collisionInfo if there is one + for (Common::List<byte>::const_iterator it = _collisionObjs.begin(); it != _collisionObjs.end(); it++) { + float collideZ, collideY, collideX; + float nextVelX, nextVelY, nextVelZ; + + if (findCollisionWith(*it, startX, startY, startZ, adjustedVelX * 100.0, adjustedVelY * 100.0, adjustedVelZ * 100.0, collideX, collideY, collideZ, indexArrayId, dataArrayId, &nextVelX, &nextVelY, &nextVelZ, &v46)) { + collisionInfo[collisionId * 8] = *it; + collisionInfo[collisionId * 8 + 1] = vectorLength(collideX - startX, collideY - startY, collideZ - startZ); + collisionInfo[collisionId * 8 + 2] = collideX; + collisionInfo[collisionId * 8 + 3] = collideY; + collisionInfo[collisionId * 8 + 4] = collideZ; + collisionInfo[collisionId * 8 + 5] = vecDenom * nextVelX / vecNumerator; + collisionInfo[collisionId * 8 + 6] = vecDenom * nextVelY / vecNumerator; + collisionInfo[collisionId * 8 + 7] = vecDenom * nextVelZ / vecNumerator; + foundCollision = 1; + collisionId++; + } + } + + if (foundCollision) { + // if we have more than one collision, sort them by distance + // to find the closest one + if (collisionId != 1) + sortCollisionList(collisionInfo, 42, 8, 1); + + int v22, v39, v42; + float tmpData[8]; + int outData[10]; + + // output the collision we found + switch (requestType) { + case 1: + for (int i = 0; i < 8; i++) + tmpData[i] = collisionInfo[i]; + v22 = getFromArray(indexArrayId, 0, (int)((tmpData[0] - 1.0) * 4.0)); + v42 = getFromArray(indexArrayId, 0, (int)((tmpData[0] - 1.0) * 4.0 + 1.0)); + v39 = getFromArray(indexArrayId, 0, (int)((tmpData[0] - 1.0) * 4.0 + 2.0)); + setCollisionOutputData(tmpData, 8, dataArrayId, indexArrayId, (int)startX, (int)startY, (int)startZ, v46, v22, v42, v39, outData); + for (int i = 0; i < 10; i++) + putInArray(outArray, 0, i, outData[i]); + break; + case 2: + // write the object id if collision happened (note that other case can't happen) + if (collisionId) + writeScummVar(109, (int)collisionInfo[(collisionId - 1) * 8]); + else + writeScummVar(109, 0); + break; + case 3: + for (int i = 0; i < 8; i++) + tmpData[i] = collisionInfo[i]; + v22 = getFromArray(indexArrayId, 0, (int)((tmpData[0] - 1.0) * 4.0)); + v42 = getFromArray(indexArrayId, 0, (int)((tmpData[0] - 1.0) * 4.0 + 1.0)); + v39 = getFromArray(indexArrayId, 0, (int)((tmpData[0] - 1.0) * 4.0 + 2.0)); + setCollisionOutputData(tmpData, 8, dataArrayId, indexArrayId, (int)startX, (int)startY, (int)startZ, v46, v22, v42, v39, outData); + for (int i = 0; i < 10; i++) + _internalCollisionOutData[i] = outData[i]; + break; + } + } + } + + writeScummVar(108, foundCollision); + + _collisionObjs.clear(); + + return foundCollision; +} + +int LogicHEsoccer::generateCollisionObjectList(float srcX, float srcY, float srcZ, float velX, float velY, float velZ) { + float v36 = srcX / 100.0; + float v37 = v36 + 52.0; + float destX = v37 + velX; + + int v33, v29; + + if (((int)destX / 52) ^ ((int)v37 / 52)) { + v33 = 1; + v29 = 1; + } else if ((int)v37 / 52) { + v29 = 0; + v33 = 1; + } else { + v33 = 0; + v29 = 1; + } + + uint32 areaEnabled[8]; + for (int i = 0; i < 4; i++) { + areaEnabled[i] = v29; + areaEnabled[i + 4] = v33; + } + + float v38 = srcY / 100.0; + float destY = v38 + velY; + + if (((int)destY / 20) ^ ((int)v38 / 20)) { + v33 = 1; + v29 = 1; + } else if ((int)v38 / 20) { + v33 = 1; + v29 = 0; + } else { + v29 = 1; + v33 = 0; + } + + for (int i = 0; i < 2; i++) { + if (areaEnabled[i * 4 + 0]) + areaEnabled[i * 4 + 0] = v29; + if (areaEnabled[i * 4 + 1]) + areaEnabled[i * 4 + 1] = v29; + if (areaEnabled[i * 4 + 2]) + areaEnabled[i * 4 + 2] = v33; + if (areaEnabled[i * 4 + 3]) + areaEnabled[i * 4 + 3] = v33; + } + + float v39 = srcZ / 100.0; + float v40 = v39 - 38.69; + float destZ = v40 + velZ; + + if (((int)destZ / 36) ^ ((int)v40 / 36)) { + v33 = 1; + v29 = 1; + } else if ((int)v40 / 36) { + v29 = 0; + v33 = 1; + } else { + v33 = 0; + v29 = 1; + } + + for (int i = 0; i <= 6; i += 2) { + if (areaEnabled[i]) + areaEnabled[i] = v29; + if (areaEnabled[i + 1]) + areaEnabled[i + 1] = v33; + } + + int objCount = 0; + + for (int i = 0; i < 8; i++) { + if (areaEnabled[i]) { + uint32 *ptr = _collisionTree + _collisionTree[i + 2] * 11; + objCount += addFromCollisionTreeNode(ptr[0], ptr[1], &ptr[2], ptr[10]); + } + } + + writeScummVar(109, objCount); + return objCount; +} + +int LogicHEsoccer::addFromCollisionTreeNode(int index, int parent, uint32 *indices, int objIndexBase) { + int objCount = 0; + + if (indices[0] == 0xffffffff) { + for (int i = 0; i < 8; i++) { + if (_collisionObjIds[i + objIndexBase]) { + addCollisionObj(_collisionObjIds[i + objIndexBase]); + objCount = 1; + } + } + } else { + if (_collisionNodeEnabled[index]) { + for (int i = 0; i < 8; i++) { + uint32 *ptr = _collisionTree + indices[i] * 11; + objCount += addFromCollisionTreeNode(ptr[0], ptr[1], &ptr[2], ptr[10]); + } + } + } + + return objCount; +} + +void LogicHEsoccer::addCollisionObj(byte objId) { + // Add objId to the list if not found + for (Common::List<byte>::const_iterator it = _collisionObjs.begin(); it != _collisionObjs.end(); it++) + if (*it == objId) + return; + + _collisionObjs.push_back(objId); +} + +int LogicHEsoccer::findCollisionWith(int objId, float inX, float inY, float inZ, float inXVec, float inYVec, float inZVec, float &collideX, float &collideY, float &collideZ, int indexArrayId, int dataArrayId, float *nextVelX, float *nextVelY, float *nextVelZ, float *a15) { + int foundCollision = 0; + float inY_plus1 = inY + 1.0; + float destX = inX + inXVec; + float destY = inY_plus1 + inYVec; + float destZ = inZ + inZVec; + + // don't go below the ground! + if (inY_plus1 <= 1.0001 && destY < 0.0) { + destY = 0.0; + inYVec = ABS((int)inYVec); + } + + // get the 8 points which define the 6 faces of this object + int objIndex = getFromArray(indexArrayId, 0, 4 * objId - 1); + int objPoints[24]; + for (int i = 0; i < 24; i++) + objPoints[i] = getFromArray(dataArrayId, 0, objIndex + i); + + for (int faceId = 0; faceId < 6; faceId++) { + // This assigns variables from objPoints based on faceId + float x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4; + float faceCrossX, faceCrossY, faceCrossZ; + getPointsForFace(faceId, x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4, objPoints); + crossProduct(x1, y1, z1, x2, y2, z2, x1, y1, z1, x3, y3, z3, faceCrossX, faceCrossY, faceCrossZ); + + float faceArea = sqrt(faceCrossX * faceCrossX + faceCrossY * faceCrossY + faceCrossZ * faceCrossZ); + + // The original did not initialize these variables and would + // use them uninitialized if faceArea == 0.0 + float xMult = 0.0, yMult = 0.0, zMult = 0.0; + + if (faceArea != 0.0) { + // UnitCross = Cross/||Cross|| + xMult = faceCrossX / faceArea; + yMult = faceCrossY / faceArea; + zMult = faceCrossZ / faceArea; + } + double scalingMult = 5.0; + + float ZToFacePoint1 = z1 - inZ; + float YToFacePoint1 = y1 - inY_plus1; + float XToFacePoint1 = x1 - inX; + // scalar component of UnitCross in direction of (start -> P1) + double ToFacePoint1 = dotProduct(xMult, yMult, zMult, XToFacePoint1, YToFacePoint1, ZToFacePoint1); + + float ZToDest = destZ - inZ; + float YToDest = destY - inY_plus1; + float XToDest = destX - inX; + // scalar component of UnitCross in direction of (start -> dest) + double ToDest = dotProduct(xMult, yMult, zMult, XToDest, YToDest, ZToDest); + + if (fabs(ToDest) > 0.00000001) + scalingMult = ToFacePoint1 / ToDest; + + if (scalingMult >= 0.0 && fabs(scalingMult) <= 1.0 && ToDest != 0.0) { + // calculate where the collision would be, in the plane containing this face + double collisionX = inX + (destX - inX) * scalingMult; + double collisionY = inY_plus1 + (destY - inY_plus1) * scalingMult + 5.0; + double collisionZ = inZ + (destZ - inZ) * scalingMult; + + // now we need to work out whether this point is actually inside the face + double dot1 = dotProduct(x2 - x1, y2 - y1, z2 - z1, x3 - x1, y3 - y1, z3 - z1); + double sqrt1 = vectorLength(x2 - x1, y2 - y1, z2 - z1); + double num1 = dot1 / (vectorLength(x3 - x1, y3 - y1, z3 - z1) * sqrt1); + num1 = CLIP<double>(num1, -1.0, 1.0); + double faceAngle = acos(num1); + + double dot2 = dotProduct(x2 - x1, y2 - y1, z2 - z1, collisionX - x1, collisionY - y1, collisionZ - z1); + double sqrt2 = vectorLength(x2 - x1, y2 - y1, z2 - z1); + double num2 = dot2 / (vectorLength(collisionX - x1, collisionY - y1, collisionZ - z1) * sqrt2); + num2 = CLIP<double>(num2, -1.0, 1.0); + double angle1 = acos(num2); + + double dot3 = dotProduct(x3 - x1, y3 - y1, z3 - z1, collisionX - x1, collisionY - y1, collisionZ - z1); + double sqrt3 = vectorLength(x3 - x1, y3 - y1, z3 - z1); + double num3 = dot3 / (vectorLength(collisionX - x1, collisionY - y1, collisionZ - z1) * sqrt3); + num3 = CLIP<double>(num3, -1.0, 1.0); + double angle2 = acos(num3); + + if (angle1 + angle2 - 0.001 <= faceAngle) { + double dot4 = dotProduct(x2 - x4, y2 - y4, z2 - z4, x3 - x4, y3 - y4, z3 - z4); + double sqrt4 = vectorLength(x2 - x4, y2 - y4, z2 - z4); + double num4 = dot4 / (vectorLength(x3 - x4, y3 - y4, z3 - z4) * sqrt4); + num4 = CLIP<double>(num4, -1.0, 1.0); + faceAngle = acos(num4); + + double dot5 = dotProduct(x2 - x4, y2 - y4, z2 - z4, collisionX - x4, collisionY - y4, collisionZ - z4); + double sqrt5 = vectorLength(x2 - x4, y2 - y4, z2 - z4); + double num5 = dot5 / (vectorLength(collisionX - x4, collisionY - y4, collisionZ - z4) * sqrt5); + num5 = CLIP<double>(num5, -1.0, 1.0); + double angle3 = acos(num5); + + double dot6 = dotProduct(x3 - x4, y3 - y4, z3 - z4, collisionX - x4, collisionY - y4, collisionZ - z4); + double sqrt6 = vectorLength(x3 - x4, y3 - y4, z3 - z4); + double num6 = dot6 / (vectorLength(collisionX - x4, collisionY - y4, collisionZ - z4) * sqrt6); + num6 = CLIP<double>(num6, -1.0, 1.0); + double angle4 = acos(num6); + + if (angle3 + angle4 - 0.001 <= faceAngle) { + // found a collision with this face + if (foundCollision) { + // if we already found one, is the new one closer? + // (except this don't adjust for the modification of collideX/Y/Z..) + double ToCollide = vectorLength(inX - collisionX, inY_plus1 - collisionY, inZ - collisionZ); + if (vectorLength(inX - collideX, inY_plus1 - collideY, inZ - collideZ) > ToCollide) { + collideX = collisionX - xMult * 3.0; + collideY = collisionY - yMult * 3.0; + collideZ = collisionZ - zMult * 3.0; + op_1005(xMult, yMult, zMult, inXVec, inYVec, inZVec, nextVelX, nextVelY, nextVelZ, a15); + } + } else { + collideX = collisionX - xMult * 3.0; + collideY = collisionY - yMult * 3.0; + collideZ = collisionZ - zMult * 3.0; + op_1005(xMult, yMult, zMult, inXVec, inYVec, inZVec, nextVelX, nextVelY, nextVelZ, a15); + } + + foundCollision = 1; + } + } + } + } + + return foundCollision; +} + +void LogicHEsoccer::getPointsForFace(int faceId, float &x1, float &y1, float &z1, float &x2, float &y2, float &z2, float &x3, float &y3, float &z3, float &x4, float &y4, float &z4, const int *objPoints) { + // Note that this originally returned a value, but said value was never used + // TODO: This can probably be shortened using a few tables... + + switch (faceId) { + case 0: + x1 = objPoints[0]; + y1 = objPoints[1]; + z1 = objPoints[2]; + x2 = objPoints[3]; + y2 = objPoints[4]; + z2 = objPoints[5]; + x3 = objPoints[6]; + y3 = objPoints[7]; + z3 = objPoints[8]; + x4 = objPoints[9]; + y4 = objPoints[10]; + z4 = objPoints[11]; + break; + case 1: + x1 = objPoints[0]; + y1 = objPoints[1]; + z1 = objPoints[2]; + x2 = objPoints[6]; + y2 = objPoints[7]; + z2 = objPoints[8]; + x3 = objPoints[12]; + y3 = objPoints[13]; + z3 = objPoints[14]; + x4 = objPoints[18]; + y4 = objPoints[19]; + z4 = objPoints[20]; + break; + case 2: + x1 = objPoints[3]; + y1 = objPoints[4]; + z1 = objPoints[5]; + x2 = objPoints[15]; + y2 = objPoints[16]; + z2 = objPoints[17]; + x3 = objPoints[9]; + y3 = objPoints[10]; + z3 = objPoints[11]; + x4 = objPoints[21]; + y4 = objPoints[22]; + z4 = objPoints[23]; + break; + case 3: + x1 = objPoints[0]; + y1 = objPoints[1]; + z1 = objPoints[2]; + x2 = objPoints[12]; + y2 = objPoints[13]; + z2 = objPoints[14]; + x3 = objPoints[3]; + y3 = objPoints[4]; + z3 = objPoints[5]; + x4 = objPoints[15]; + y4 = objPoints[16]; + z4 = objPoints[17]; + break; + case 4: + x1 = objPoints[6]; + y1 = objPoints[7]; + z1 = objPoints[8]; + x2 = objPoints[9]; + y2 = objPoints[10]; + z2 = objPoints[11]; + x3 = objPoints[18]; + y3 = objPoints[19]; + z3 = objPoints[20]; + x4 = objPoints[21]; + y4 = objPoints[22]; + z4 = objPoints[23]; + break; + case 5: + x1 = objPoints[15]; + y1 = objPoints[16]; + z1 = objPoints[17]; + x2 = objPoints[12]; + y2 = objPoints[13]; + z2 = objPoints[14]; + x3 = objPoints[21]; + y3 = objPoints[22]; + z3 = objPoints[23]; + x4 = objPoints[18]; + y4 = objPoints[19]; + z4 = objPoints[20]; + break; + } +} + +void LogicHEsoccer::crossProduct(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4, float &outX, float &outY, float &outZ) { + outX = (y2 - y1) * (z4 - z3) - (y4 - y3) * (z2 - z1); + outY = ((x2 - x1) * (z4 - z3) - (x4 - x3) * (z2 - z1)) * -1.0; + outZ = (x2 - x1) * (y4 - y3) - (x4 - x3) * (y2 - y1); +} + +double LogicHEsoccer::dotProduct(float a1, float a2, float a3, float a4, float a5, float a6) { + return a1 * a4 + a2 * a5 + a3 * a6; +} + +void LogicHEsoccer::sortCollisionList(float *data, int numEntries, int entrySize, int compareOn) { + // This takes an input array of collisions, and tries to sort it based on the distance + // (index of compareOn, always 1), copying in groups of entrySize, which is always 8 + + bool found = true; + int entry = 0; + + while (found) { + found = false; + + // while we still have entries, and there is an obj id set for the next entry + while (entry <= numEntries - 2 && data[(entry + 1) * 8] != 0.0) { + // if the current entry has distance 0, or the next entry is closer (distance is less) + if (data[compareOn + entry * 8] == 0 || data[compareOn + entry * 8] > data[compareOn + (entry + 1) * 8]) { + found = true; + + // swap all data with the next entry + for (int i = 0; i < entrySize; i++) { + float tmp = data[i + entry * 8]; + data[i + entry * 8] = data[i + (entry + 1) * 8]; + data[i + (entry + 1) * 8] = tmp; + } + } + + entry++; + } + } +} + +int LogicHEsoccer::setCollisionOutputData(float *collisionData, int entrySize, int dataArrayId, int indexArrayId, int startX, int startY, int startZ, float a8, int a9, int a10, int a11, int *out) { + // area-provided data + out[0] = a9; + out[1] = a10; + out[2] = a11; + // new velocity, slowed by area-provided value + out[3] = (int)(collisionData[5] * (double)a10 / 100.0); + out[4] = (int)(collisionData[6] * (double)a10 / 100.0 * a8); // Note: a8 should always be 1 + out[5] = (int)(collisionData[7] * (double)a10 / 100.0); + // new position + out[6] = (int)collisionData[2]; + out[7] = (int)collisionData[3]; + out[8] = (int)collisionData[4]; + // collision object id + out[9] = (int)collisionData[0]; + return out[9]; +} + +int LogicHEsoccer::op_1016(int32 *args) { + // Called when a goal is scored + + int result = 0; + + double v9 = (double)args[1] / 100.0; + double v13 = (double)args[2] / 100.0; + double v12 = (double)args[3] / 100.0; + double v18 = v13 * v13; + double v10 = (double)args[0] / 100.0 * (double)args[0] / 100.0; + double v11 = v9 * v9; + double v19 = (v9 * v9 * v12 * v12 + 2.0 * v9 * v12 * v18 + v18 * v18) * v10 * v10 - (v10 + v11) * v12 * v12 * v10 * v10; + + if (v19 >= 0.0) { + double v6 = sqrt(v19); + double v17 = ((v9 * v12 + v18) * v10 + v6) / (v10 + v11 + v10 + v11); + double v16 = ((v9 * v12 + v18) * v10 - v6) / (v10 + v11 + v10 + v11); + double v7, v14; + + if (v17 <= 0.0 || (v7 = sqrt(v17), v14 = acos(v7 / v13), v14 > 0.7853981633974475)) { + double v8, v15; + if (v16 <= 0.0 || (v8 = sqrt(v16), v15 = acos(v8 / v13), v15 > 0.7853981633974475)) { + writeScummVar(108, -1); + } else { + writeScummVar(108, (int)(v15 / 0.01745329251994328 * 100.0)); + result = 1; + } + } else { + writeScummVar(108, (int)(v14 / 0.01745329251994328 * 100.0)); + result = 1; + } + } else { + writeScummVar(108, -1); + } + + return result; +} + +int LogicHEsoccer::op_1017(int32 *args) { + // Used sporadically during a match (out of bounds?) + if (!args[1]) + args[1] = 1; + + double v3 = asin((double)args[0] / (double)args[1]); + writeScummVar(108, (int32)(v3 / 0.01745329251994328 * (double)args[1])); + + return 1; +} + +int LogicHEsoccer::op_1019(int32 *args) { + // Used at the beginning of a match + // Initializes some arrays with field collision data + + // _collisionObjIds provides object ids for leaf nodes + // of the collision tree (_collisionTree). + for (int i = 0; i < 4096; i++) + _collisionObjIds[i] = getFromArray(args[1], 0, i); + + // _collisionNodeEnabled enables or disables non-leaf nodes + // of the collision tree (_collisionTree). + for (int i = 0; i < 585; i++) + _collisionNodeEnabled[i] = getFromArray(args[0], 0, i); + + // The remaining code of this function was used for the + // built-in editor. However, it is incomplete in the + // final product, so we do not need to have it. + + return 1; +} + +int LogicHEsoccer::op_1021(int32 inX, int32 inY, int32 inZ, int32 velX, int32 velY, int32 velZ, int32 internalUse) { + // Used during a match (ball movement?) + // Also called from op_1008 + + int outX; + if (velX && velY) + outX = (int)(((double)inY - (double)velY * (double)inX / (double)velX) * -1.0 * (double)velX / (double)velY); + else + outX = inX; + + int outZ; + if (velZ && velY) + outZ = (int)(((double)inY - (double)velY * (double)inZ / (double)velZ) * -1.0 * (double)velZ / (double)velY); + else + outZ = inZ; + + // The final argument chooses whether to store the results for op_1008 or + // store them in SCUMM variables. + if (internalUse) { + _var1021[0] = outX; + _var1021[1] = outZ; + } else { + writeScummVar(108, outX); + writeScummVar(109, outZ); + } + + return 1; +} + +LogicHE *makeLogicHEsoccer(ScummEngine_v90he *vm) { + return new LogicHEsoccer(vm); +} + +} // End of namespace Scumm diff --git a/engines/scumm/he/logic_he.cpp b/engines/scumm/he/logic_he.cpp index af56bca2ee..a76c393e13 100644 --- a/engines/scumm/he/logic_he.cpp +++ b/engines/scumm/he/logic_he.cpp @@ -33,29 +33,10 @@ LogicHE::LogicHE(ScummEngine_v90he *vm) : _vm(vm) { LogicHE::~LogicHE() { } -LogicHErace::LogicHErace(ScummEngine_v90he *vm) : LogicHE(vm) { - // Originally it used 0x930 and stored both floats and doubles inside - _userData = (float *)calloc(550, sizeof(float)); - _userDataD = (double *)calloc(30, sizeof(double)); - - // FIXME: of the 550 entries in _userData, only 516 till 532 are used - // FIXME: similarly, in _userDataD only 9 till 17 are used for computations - // (some of the other entries are also set, but never read, hence useless). -} - -LogicHErace::~LogicHErace() { - free(_userData); - free(_userDataD); -} - void LogicHE::writeScummVar(int var, int32 value) { _vm->writeVar(var, value); } -static int32 scumm_round(double arg) { - return (int32)(arg + 0.5); -} - int LogicHE::versionID() { return 1; } @@ -95,1370 +76,34 @@ int32 LogicHE::dispatch(int op, int numArgs, int32 *args) { return 1; } -/*********************** - * Putt-Putt Joins the Race - * - */ - -int LogicHErace::versionID() { - return 1; -} - -int32 LogicHErace::dispatch(int op, int numArgs, int32 *args) { - int32 res; - - switch (op) { - case 1003: - res = op_1003(args); - break; - - case 1004: - res = op_1004(args); - break; - - case 1100: - res = op_1100(args); - break; - - case 1101: - res = op_1101(args); - break; - - case 1102: - res = op_1102(args); - break; - - case 1103: - res = op_1103(args); - break; - - case 1110: - res = op_1110(); - break; - - case 1120: - res = op_1120(args); - break; - - case 1130: - res = op_1130(args); - break; - - case 1140: - res = op_1140(args); - break; - - default: - res = 0; - break; - - } - - return res; -} - -#define RAD2DEG (180 / M_PI) -#define DEG2RAD (M_PI / 180) - -int32 LogicHErace::op_1003(int32 *args) { - int value = args[2] ? args[2] : 1; - - writeScummVar(108, (int32)(atan2((double)args[0], (double)args[1]) * RAD2DEG * value)); - - return 1; -} - -int32 LogicHErace::op_1004(int32 *args) { - int value = args[1] ? args[1] : 1; - - writeScummVar(108, (int32)(sqrt((float)args[0]) * value)); - - return 1; -} - -int32 LogicHErace::op_1100(int32 *args) { - // _userData 516,517,518 describe a 3D translation? - _userData[516] = (float)args[0] / args[10]; - _userData[517] = (float)args[1] / args[10]; - _userData[518] = (float)args[2] / args[10]; - - // _userData 519,520,521 describe rotation angles around the x,y,z axes? - _userData[519] = (float)args[3] / args[10]; - _userData[520] = (float)args[4] / args[10]; - _userData[521] = (float)args[5] / args[10]; - - op_sub1(_userData[520]); - op_sub2(_userData[521]); - - // _userData[532] seems to be some kind of global scale factor - _userData[532] = (float)args[10]; - - _userData[524] = (float)args[8]; // not used - _userData[525] = (float)args[9]; // not used - _userData[522] = (float)args[6] / args[10]; // not used - _userData[523] = (float)args[7] / args[10]; // only used to compute 528 and 529 - - // The following two are some kind of scale factors - _userData[526] = (float)args[6] / args[8] / args[10]; - _userData[527] = (float)args[7] / args[9] / args[10]; - - // Set var 108 and 109 -- the value set here corresponds to the values - // set by op_1110! - writeScummVar(108, (int32)((float)args[6] / args[8] * args[10])); - writeScummVar(109, (int32)((float)args[7] / args[9] * args[10])); - - _userData[528] = (float)(_userData[519] - _userData[523] * 0.5); - _userData[529] = (float)(_userData[519] + _userData[523] * 0.5); - - writeScummVar(110, (int32)(_userData[528] * args[10])); - writeScummVar(111, (int32)(_userData[529] * args[10])); - - // 530 and 531 are only used to set vars 112 and 113, so no need - // to store them permanently - _userData[530] = (float)(_userData[517] / tan(_userData[529] * DEG2RAD)); - _userData[531] = (float)(_userData[517] / tan(_userData[528] * DEG2RAD)); - - writeScummVar(112, (int32)(_userData[530] * args[10])); - writeScummVar(113, (int32)(_userData[531] * args[10])); - - return 1; -} - -int32 LogicHErace::op_1101(int32 *args) { - // Update rotation params? - int32 retval; - float temp; - - temp = args[0] / _userData[532]; - if (_userData[519] != temp) { - _userData[519] = temp; - op_sub3(temp); - retval = 1; - } else { - retval = (int32)temp; - } - - temp = args[1] / _userData[532]; - if (_userData[520] != temp) { - _userData[520] = temp; - op_sub1(temp); - retval = 1; - } - - temp = args[2] / _userData[532]; - if (_userData[521] != temp) { - _userData[521] = temp; - op_sub2(temp); - retval = 1; - } - - return retval; -} - -int32 LogicHErace::op_1102(int32 *args) { - // Update translation params? - int32 retval; - float temp; - - temp = args[0] / _userData[532]; - if (_userData[516] != temp) { - _userData[516] = temp; - retval = 1; - } else { - retval = (int32)_userData[532]; - } - - temp = args[1] / _userData[532]; - if (_userData[517] != temp) { - _userData[517] = temp; - retval = 1; - } - - temp = args[2] / _userData[532]; - if (_userData[518] != temp) { - _userData[518] = temp; - retval = 1; - } - - return retval; -} - -int32 LogicHErace::op_1103(int32 *args) { - double angle = args[0] / args[1] * DEG2RAD; - - writeScummVar(108, (int32)(sin(angle) * args[2])); - writeScummVar(109, (int32)(cos(angle) * args[2])); - - return 1; -} - -int32 LogicHErace::op_1110() { - writeScummVar(108, (int32)(_userData[526] * _userData[532] * _userData[532])); - writeScummVar(109, (int32)(_userData[527] * _userData[532] * _userData[532])); - writeScummVar(110, (int32)(_userData[532])); - - return 1; -} - -int32 LogicHErace::op_1120(int32 *args) { - double a0, a1, a2; - double b0, b1, b2; - double res1, res2; - - a0 = args[0] / _userData[532] - _userData[516]; - a1 = args[1] / _userData[532] - _userData[517]; - a2 = args[2] / _userData[532] - _userData[518]; - - // Perform matrix multiplication (multiplying by a rotation matrix) - b2 = a2 * _userDataD[17] + a1 * _userDataD[14] + a0 * _userDataD[11]; - b1 = a2 * _userDataD[16] + a1 * _userDataD[13] + a0 * _userDataD[10]; - b0 = a2 * _userDataD[15] + a1 * _userDataD[12] + a0 * _userDataD[9]; - - res1 = (atan2(b0, b2) * RAD2DEG) / _userData[526]; - res2 = (atan2(b1, b2) * RAD2DEG - _userData[528]) / _userData[527]; - - writeScummVar(108, (int32)res1); - writeScummVar(109, (int32)res2); - - return 1; -} - -int32 LogicHErace::op_1130(int32 *args) { - double cs = cos(args[0] / _userData[532] * DEG2RAD); - double sn = sin(args[0] / _userData[532] * DEG2RAD); - - writeScummVar(108, (int32)(cs * args[1] + sn * args[2])); - writeScummVar(109, (int32)(cs * args[2] - sn * args[1])); - - return 1; -} - -int32 LogicHErace::op_1140(int32 *args) { - // This functions seems to perform some kind of projection: We project - // the vector (arg2,arg3) onto the vector (arg0,arg1), but also apply - // some kind of distortion factor ?!? - double x = args[2], y = args[3]; - - // We start by normalizing the vector described by arg2 and arg3. - // So compute its length and divide the x and y coordinates - const double sq = sqrt(x*x + y*y); - x /= sq; - y /= sq; - - // Compute the scalar product of the vectors (arg0,arg1) and (x,y) - const double scalarProduct = x * args[0] + y * args[1]; - - // Finally compute the projection of (arg2,arg3) onto (arg0,arg1) - double projX = args[0] - 2 * scalarProduct * x; - double projY = args[1] - 2 * scalarProduct * y; - - projX = projX * 20.0 / 23.0; // FIXME: Why is this here? - - writeScummVar(108, (int32)projX); - - if (args[3] >= 0) // FIXME: Why is this here? - projY = projY * 5.0 / 6.0; - - writeScummVar(109, (int32)projY); - - return 1; -} - -void LogicHErace::op_sub1(float arg) { - // Setup a rotation matrix - _userDataD[10] = _userDataD[12] = _userDataD[14] = _userDataD[16] = 0; - _userDataD[13] = 1; - - _userDataD[9] = cos(arg * DEG2RAD); - _userDataD[15] = sin(arg * DEG2RAD); - _userDataD[11] = -_userDataD[15]; - _userDataD[17] = _userDataD[9]; -} - -void LogicHErace::op_sub2(float arg) { - // Setup a rotation matrix -- but it is NEVER USED! - _userDataD[20] = _userDataD[21] = _userDataD[24] = _userDataD[25] = 0; - _userDataD[26] = 1; - - _userDataD[19] = sin(arg * DEG2RAD); - _userDataD[18] = cos(arg * DEG2RAD); - _userDataD[21] = -_userDataD[19]; - _userDataD[22] = _userDataD[18]; -} - -void LogicHErace::op_sub3(float arg) { - // Setup a rotation matrix -- but it is NEVER USED! - _userDataD[1] = _userDataD[2] = _userDataD[3] = _userDataD[6] = 0; - _userDataD[0] = 1; - - _userDataD[4] = cos(arg * DEG2RAD); - _userDataD[5] = sin(arg * DEG2RAD); - _userDataD[7] = -_userDataD[5]; - _userDataD[8] = _userDataD[4]; -} - -/*********************** - * Freddi Fish's One-Stop Fun Shop - * Pajama Sam's One-Stop Fun Shop - * Putt-Putt's One-Stop Fun Shop - * - */ - -int LogicHEfunshop::versionID() { - return 1; -} - -int32 LogicHEfunshop::dispatch(int op, int numArgs, int32 *args) { - switch (op) { - case 1004: - op_1004(args); - break; - - case 1005: - op_1005(args); - break; - - default: - break; - } - - return 0; -} - -void LogicHEfunshop::op_1004(int32 *args) { - double data[8], at, sq; - int32 x, y; - int i=0; - - for (i = 0; i <= 6; i += 2) { - data[i] = getFromArray(args[0], 0, 519 + i); - data[i + 1] = getFromArray(args[0], 0, 519 + i + 1); - } - int s = checkShape((int32)data[0], (int32)data[1], (int32)data[4], (int32)data[5], - (int32)data[2], (int32)data[3], (int32)data[6], (int32)data[7], &x, &y); - - if (s != 1) { - error("LogicHEfunshop::op_1004: Your shape has defied the laws of physics"); - return; - } - - for (i = 0; i <= 6; i += 2) { - data[i] -= (double)x; - data[i + 1] -= (double)y; - } - - double a1 = (double)args[1] * DEG2RAD; - - for (i = 0; i <= 6; i += 2) { - at = atan2(data[i + 1], data[i]); - sq = sqrt(data[i + 1] * data[i + 1] + data[i] * data[i]); - - if (at <= 0) - at += 2 * M_PI; - - data[i] = cos(at + a1) * sq; - data[i + 1] = sin(at + a1) * sq; - } - - double minx = data[0]; - double miny = data[1]; - - for (i = 0; i <= 6; i += 2) { - if (data[i] < minx) - minx = data[i]; - if (data[i + 1] < miny) - miny = data[i + 1]; - } - - for (i = 0; i <= 6; i += 2) { - data[i] -= minx; - data[i + 1] -= miny; - - putInArray(args[0], 0, 519 + i, scumm_round(data[i])); - putInArray(args[0], 0, 519 + i + 1, scumm_round(data[i + 1])); - } -} - -void LogicHEfunshop::op_1005(int32 *args) { - double data[8]; - double args1, args2; - int i; - for (i = 520; i <= 526; i += 2) { - data[i - 520] = getFromArray(args[0], 0, i - 1); - data[i - 520 + 1] = getFromArray(args[0], 0, i); - } - - args1 = (double)args[1] * 0.01 + 1; - args2 = (double)args[2] * 0.01 + 1; - - for (i = 0; i < 4; i++) { - data[2 * i] *= args1; - data[2 * i + 1] *= args2; - } - - for (i = 520; i <= 526; i += 2) { - putInArray(args[0], 0, i - 1, scumm_round(data[i - 520])); - putInArray(args[0], 0, i, scumm_round(data[i - 520 + 1])); - } -} - -int LogicHEfunshop::checkShape(int32 data0, int32 data1, int32 data4, int32 data5, int32 data2, int32 data3, int32 data6, int32 data7, int32 *x, int32 *y) { - int32 diff5_1, diff0_4, diff7_3, diff2_6; - int32 diff1, diff2; - int32 delta, delta2; - int32 sum1, sum2; - - diff0_4 = data0 - data4; - diff5_1 = data5 - data1; - diff1 = data1 * data4 - data0 * data5; - sum1 = diff0_4 * data3 + diff1 + diff5_1 * data2; - sum2 = diff0_4 * data7 + diff1 + diff5_1 * data6; - - if (sum1 != 0 && sum2 != 0) { - sum2 ^= sum1; - - if (sum2 >= 0) - return 0; - } - - diff2_6 = data2 - data6; - diff7_3 = data7 - data3; - diff2 = data3 * data6 - data2 * data7; - sum1 = diff2_6 * data1 + diff2 + diff7_3 * data0; - sum2 = diff2_6 * data5 + diff2 + diff7_3 * data4; - - if (sum1 != 0 && sum2 != 0) { - sum2 ^= sum1; - - if (sum2 >= 0) - return 0; - } - - delta = diff2_6 * diff5_1 - diff0_4 * diff7_3; - - if (delta == 0) { - return 2; - } - - if (delta < 0) { - data7 = -((delta + 1) >> 1); - } else { - data7 = delta >> 1; - } - - delta2 = diff2 * diff0_4 - diff1 * diff2_6; - - if (delta2 < 0) { - delta2 -= data7; - } else { - delta2 += data7; - } - - *x = delta2 / delta; - - delta2 = diff1 * diff7_3 - diff2 * diff5_1; - - if (delta2 < 0) { - delta2 -= data7; - } else { - delta2 += data7; - } - - *y = delta2 / delta; - - return 1; -} - -/*********************** - * Backyard Football - * Backyard Football 2002 - * Backyard Football Demo - * - */ - -int LogicHEfootball::versionID() { - return 1; -} - -int32 LogicHEfootball::dispatch(int op, int numArgs, int32 *args) { - int res = 0; - - switch (op) { - case 1004: - res = op_1004(args); - break; - - case 1006: - res = op_1006(args); - break; - - case 1007: - res = op_1007(args); - break; - - case 1010: - res = op_1010(args); - break; - - case 1022: - res = op_1022(args); - break; - - case 1023: - res = op_1023(args); - break; - - case 1024: - res = op_1024(args); - break; - - case 8221968: - // Someone had a fun and used his birthday as opcode number - res = getFromArray(args[0], args[1], args[2]); - break; - - case 1492: case 1493: case 1494: case 1495: case 1496: - case 1497: case 1498: case 1499: case 1500: case 1501: - case 1502: case 1503: case 1504: case 1505: case 1506: - case 1507: case 1508: case 1509: case 1510: case 1511: - case 1512: case 1513: case 1514: case 1555: - // DirectPlay-related - // 1513: initialize - // 1555: set fake lag - break; - - case 2200: case 2201: case 2202: case 2203: case 2204: - case 2205: case 2206: case 2207: case 2208: case 2209: - case 2210: case 2211: case 2212: case 2213: case 2214: - case 2215: case 2216: case 2217: case 2218: case 2219: - case 2220: case 2221: case 2222: case 2223: case 2224: - case 2225: case 2226: case 2227: case 2228: - // Boneyards-related - break; - - case 3000: case 3001: case 3002: case 3003: case 3004: - // Internet-related - // 3000: check for updates - // 3001: check network status - // 3002: autoupdate - // 3003: close connection - break; - - default: - LogicHE::dispatch(op, numArgs, args); - warning("Tell sev how to reproduce it (%d)", op); - } - - return res; -} - -int LogicHEfootball::op_1004(int32 *args) { - // Identical to LogicHEsoccer::op_1004 - double res, a2, a4, a5; - - a5 = ((double)args[4] - (double)args[1]) / ((double)args[5] - (double)args[2]); - a4 = ((double)args[3] - (double)args[0]) / ((double)args[5] - (double)args[2]); - a2 = (double)args[2] - (double)args[0] * a4 - args[1] * a5; - - res = (double)args[6] * a4 + (double)args[7] * a5 + a2; - writeScummVar(108, (int32)res); - - writeScummVar(109, (int32)a2); - writeScummVar(110, (int32)a5); - writeScummVar(111, (int32)a4); - - return 1; -} - -int LogicHEfootball::op_1006(int32 *args) { - // This seems to be more or less the inverse of op_1010 - const double a1 = args[1]; - double res; - - // 2.9411764e-4 = 1/3400 - // 5.3050399e-2 = 1/18.85 = 20/377 - // 1.1764706e-2 = 1/85 = 40/3400 - // 1.2360656e-1 = 377/3050 - res = (1.0 - a1 * 2.9411764e-4 * 5.3050399e-2) * 1.2360656e-1 * args[0] + - a1 * 1.1764706e-2 + 46; - - // Shortened / optimized version of that formula: - // res = (377.0 - a1 / 170.0) / 3050.0 * args[0] + a1 / 85.0 + 46; - - writeScummVar(108, (int32)res); - - // 1.2360656e-1 = 377/3050 - // 1.1588235e-1 = 197/1700 = 394/3400 - res = 640.0 - args[2] * 1.2360656e-1 - a1 * 1.1588235e-1 - 26; - - writeScummVar(109, (int32)res); - - return 1; -} - -int LogicHEfootball::op_1007(int32 *args) { - double res, temp; - - temp = (double)args[1] * 0.32; - - if (temp > 304.0) - res = -args[2] * 0.142; - else - res = args[2] * 0.142; - - res += temp; - - writeScummVar(108, (int32)res); - - res = (1000.0 - args[2]) * 0.48; - - writeScummVar(109, (int32)res); - - return 1; -} - -int LogicHEfootball::op_1010(int32 *args) { - // This seems to be more or less the inverse of op_1006 - double a1 = (640.0 - (double)args[1] - 26.0) / 1.1588235e-1; - - // 2.9411764e-4 = 1/3400 - // 5.3050399e-2 = 1/18.85 = 20/377 - // 1.1764706e-2 = 1/85 = 40/3400 - // 1.2360656e-1 = 377/3050 - double a0 = ((double)args[0] - 46 - a1 * 1.1764706e-2) / - ((1.0 - a1 * 2.9411764e-4 * 5.3050399e-2) * 1.2360656e-1); - - writeScummVar(108, (int32)a0); - writeScummVar(109, (int32)a1); - - return 1; -} - -int LogicHEfootball::op_1022(int32 *args) { - double res; - double var10 = args[4] - args[1]; - double var8 = args[5] - args[2]; - double var6 = args[3] - args[0]; - - res = sqrt(var8 * var8 + var6 * var6 + var10 * var10); - - if (res >= (double)args[6]) { - var8 = (double)args[6] * var8 / res; - var10 = (double)args[6] * var10 / res; - res = (double)args[6] * var6 / res; - } - - writeScummVar(108, (int32)res); - writeScummVar(109, (int32)var10); - writeScummVar(110, (int32)var8); - - return 1; -} - -int LogicHEfootball::op_1023(int32 *args) { - double var10, var18, var20, var28, var30, var30_; - double argf[7]; - - for (int i = 0; i < 7; i++) - argf[i] = args[i]; - - var10 = (argf[3] - argf[1]) / (argf[2] - argf[0]); - var28 = var10 * var10 + 1; - var20 = argf[0] * var10; - var18 = (argf[5] + argf[1] + var20) * argf[4] * var10 * 2 + - argf[6] * argf[6] * var28 + argf[4] * argf[4] - - argf[0] * argf[0] * var10 * var10 - - argf[5] * argf[0] * var10 * 2 - - argf[5] * argf[1] * 2 - - argf[1] * argf[1] - argf[5] * argf[5]; - - if (var18 >= 0) { - var18 = sqrt(var18); - - var30_ = argf[4] + argf[5] * var10 + argf[1] * var10 + argf[0] * var10 * var10; - var30 = (var30_ - var18) / var28; - var18 = (var30_ + var18) / var28; - - if ((argf[0] - var30 < 0) && (argf[0] - var18 < 0)) { - var30_ = var30; - var30 = var18; - var18 = var30_; - } - var28 = var18 * var10 - var20 - argf[1]; - var20 = var30 * var10 - var20 - argf[1]; - } else { - var18 = 0; - var20 = 0; - var28 = 0; - var30 = 0; - } - - writeScummVar(108, (int32)var18); - writeScummVar(109, (int32)var28); - writeScummVar(110, (int32)var30); - writeScummVar(111, (int32)var20); - - return 1; -} -int LogicHEfootball::op_1024(int32 *args) { - writeScummVar(108, 0); - writeScummVar(109, 0); - writeScummVar(110, 0); - writeScummVar(111, 0); - - return 1; -} - - -/*********************** - * Backyard Soccer - * - */ - -int LogicHEsoccer::versionID() { - return 1; -} - -LogicHEsoccer::LogicHEsoccer(ScummEngine_v90he *vm) : LogicHE(vm) { - _userDataD = (double *)calloc(1732, sizeof(double)); - _intArray1 = 0; - _intArray2 = 0; - _intArraysAllocated = false; - _array1013 = 0; - _array1013Allocated = false; -} - -LogicHEsoccer::~LogicHEsoccer() { - free(_userDataD); - op_1020(); // clear int arrays - delete[] _array1013; -} - -int32 LogicHEsoccer::dispatch(int op, int numArgs, int32 *args) { - int res = 0; - - switch (op) { - case 1001: - res = op_1001(args); - break; - - case 1002: - res = op_1002(args); - break; - - case 1004: - res = op_1004(args); - break; - - case 1006: - res = op_1006(args[0], args[1], args[2], args[3]); - break; - - case 1011: - // args[4] is ignored! - // soccer passes the argument, but then ends up not using it - // Makes sense that they removed it for soccermls - res = op_1011(args[0], args[1], args[2], args[3], args[5]); - break; - - case 1012: - res = op_1012(args); - break; - - case 1013: - res = op_1013(args[0], args[1], args[2]); - break; - - case 1019: - res = op_1019(args); - break; - - case 1020: - res = op_1020(); - break; - - case 1021: - res = op_1021(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); - break; - - case 8221968: - // Someone had a fun and used his birthday as opcode number - res = getFromArray(args[0], args[1], args[2]); - break; - - default: - // original range is 1001 - 1021 - LogicHE::dispatch(op, numArgs, args); - } - - return res; -} - -void LogicHEsoccer::beforeBootScript() { - if (_intArraysAllocated) - op_1020(); - - _userDataD[530] = 0; -} - -void LogicHEsoccer::initOnce() { - // The original sets some paths here that we don't need to worry about - _array1013Allocated = false; - _userDataD[530] = 0; -} - -int LogicHEsoccer::startOfFrame() { - // This variable is some sort of flag that activates this mode - int res = (int)_userDataD[530]; - - // _userDataD[535] is not used! - // soccer passes the argument, but then ends up not using it - // Makes sense that they removed it for soccermls - if (res) - res = op_1011((int)_userDataD[531], (int)_userDataD[532], (int)_userDataD[533], (int)_userDataD[534], (int)_userDataD[536]); - - return res; -} - -int LogicHEsoccer::op_1001(int32 *args) { - return (int)(args[0] * sin((float)args[1])); -} - -int LogicHEsoccer::op_1002(int32 *args) { - return _vm->VAR(2) * args[0]; -} - -int LogicHEsoccer::op_1003(int32 *args) { - double data[6], out[3]; - int i; - - for (i = 0; i < 6; i++) { - data[i] = getFromArray(args[0], 0, i); - } - - out[0] = data[1] * data[5] - data[4] * data[2]; - out[1] = data[5] * data[0] - data[3] * data[2]; - out[2] = data[4] * data[0] - data[3] * data[1]; - - for (i = 0; i < 3; i++) { - putInArray(args[0], 0, i, scumm_round(out[i])); - } - - return 1; -} - -int LogicHEsoccer::op_1004(int32 *args) { - // Identical to LogicHEfootball::op_1004 - double res, a2, a4, a5; - - a5 = ((double)args[4] - (double)args[1]) / ((double)args[5] - (double)args[2]); - a4 = ((double)args[3] - (double)args[0]) / ((double)args[5] - (double)args[2]); - a2 = (double)args[2] - (double)args[0] * a4 - args[1] * a5; - - res = (double)args[6] * a4 + (double)args[7] * a5 + a2; - writeScummVar(108, (int32)res); - - writeScummVar(109, (int32)a2); - writeScummVar(110, (int32)a5); - writeScummVar(111, (int32)a4); - - return 1; -} - -int LogicHEsoccer::op_1006(int32 a1, int32 a2, int32 a3, int32 a4) { - double v1 = a1 * 0.01; - double v2 = a2 * 0.01; - double v3 = a3 * 0.01; - double var108, var109; - - _userDataD[529] = a4; - - var108 = atan2(v1, v3) * _userDataD[523] - a4; - var109 = _userDataD[526] - _userDataD[528] + (_userDataD[521] - atan2(_userDataD[524] - v2, v3)) * _userDataD[522]; - - writeScummVar(108, (int32)var108); - writeScummVar(109, (int32)var109); - - return 1; -} - -int LogicHEsoccer::op_1007(int32 *args) { - // Used when the HE logo is shown - // This initializes the _userDataD fields that are used in op_1006/op_1011 - - _intArraysAllocated = false; - double v14 = (double)args[0] * 0.01; - double v13 = (double)args[2] * 0.01; - _userDataD[524] = v14; - double v12 = atan2(v13, v14); - _userDataD[520] = v12; - double v15 = atan2(v13 - (double)args[4] * 0.01, (double)args[3] * 0.01); - double v19 = v15 * 2.0; - double v17 = atan2(v13 - (double)args[4] * 0.01, v14); - _userDataD[519] = v19; - _userDataD[521] = v17; - _userDataD[525] = (v17 - v12) * 2.0; - _userDataD[527] = (double)args[5]; - _userDataD[526] = (double)args[6]; - _userDataD[528] = (double)args[7]; - _userDataD[522] = _userDataD[526] / _userDataD[525]; - _userDataD[523] = _userDataD[527] / _userDataD[519]; - _userDataD[518] = v13; - - // Clear both byte arrays - memset(_byteArray1, 0, 4096); - memset(_byteArray2, 0, 585); - - if (_array1013Allocated == 0 ) - op_1013(4, args[8], args[9]); - - return 1; -} - -// Returns the square root of the sum of the squares of the arguments -static inline double sqrtSquare(double a1, double a2, double a3) { - return sqrt(a1 * a1 + a2 * a2 + a3 * a3); -} - -int LogicHEsoccer::op_1008(int32 *args) { - // TODO: Used during a match (kicking?) - - return 1; -} - -int LogicHEsoccer::op_1011(int32 a1, int32 a2, int32 a3, int32 a4, int32 a5) { - // This is called on each frame by startOfFrame() if activated by op_1012. - // This seems to do player placement! - - float v28 = 0.0; - - for (int i = 0; i < 18; i++) { - // These seem to be some sort of percent? of angles? - int v32 = getFromArray(a1, i, 0); - int v6 = getFromArray(a1, i, 1); - int v30 = getFromArray(a1, i, 2); - - float v29 = (double)v32 / 100.0; - v28 = (double)v6 / 100.0; - float v31 = (double)v30 / 100.0; - - if (i < 13) { - int v25 = ((v32 + 2760) / 500 >= 0) ? ((v32 + 2750) / 500) : 0; - int v24 = 10; - - if (v25 <= 10) { - int v23 = 0; - if ((v32 + 2750) / 500 >= 0) - v23 = (v32 + 2750) / 500; - - v24 = v23; - } - - int v22 = 0; - if ((9219 - v30) / 500 >= 0) - v22 = (9219 - v30) / 500; - - int v21 = 6; - if (v22 <= 6) { - int v20 = 0; - if ((9219 - v30) / 500 >= 0) - v20 = (9219 - v30) / 500; - v21 = v20; - } - - if (a5) - putInArray(a5, 0, i, v24 + 11 * v21); - } - - float v7 = atan2(_userDataD[524] - v28, (double)v31); - int v8 = (int)(_userDataD[526] - (_userDataD[521] - v7) * _userDataD[522] + 300.0); - - double v9 = atan2(_userDataD[523], (double)v31); - // x/y position? - putInArray(a2, i, 0, (int32)(v29 * v9 + 640.0)); - putInArray(a2, i, 1, v8); - - double v10 = atan2(_userDataD[524], (double)v31); - int v12 = (int)(_userDataD[526] - (_userDataD[521] - (float)v10) * _userDataD[522] + 300.0); - double v13 = _userDataD[523]; - - v29 = atan2(v29, v31); - // x/y position? - putInArray(a2, i + 22, 0, (int32)(v29 * v13 + 640.0)); - putInArray(a2, i + 22, 1, v12); - } - - // soccer only uses one array here - // soccermls/soccer2004 use four - int start = (_vm->_game.id == GID_SOCCER) ? 19 : 18; - int end = (_vm->_game.id == GID_SOCCER) ? 19 : 21; - - for (int i = start; i <= end; i++) { - int v14 = getFromArray(a2, i, 0); - int v15 = getFromArray(a2, i, 1); - - // This retains v28 from (i == 17)? - float v16 = _userDataD[524] - v28; - float v17 = v16 / tan((_userDataD[528] + v15 - _userDataD[526]) / (_userDataD[522] + _userDataD[521])); - double v18 = tan((double)(v14 - 640) / _userDataD[523]) * v17; - putInArray(a1, i, 0, (int)(v18 * 100.0)); - putInArray(a1, i, 2, (int)(v17 * 100.0)); - } - - op_1011_sub(a1, a3, a4, a4); - - return 1; -} - -static inline int distance(int a1, int a2, int a3, int a4) { - return (int)sqrt((double)((a4 - a3) * (a4 - a3) + (a2 - a1) * (a2 - a1))); -} - -void LogicHEsoccer::op_1011_sub(int32 a1, int32 a2, int32 a3, int32 a4) { - // As you can guess, this is called from op_1011 - // This seems to be checking distances between the players and the ball - // and which distance is the shortest. - - int v6[13]; - int v7[13]; - int v8[13]; - int v18[195]; - - for (int i = 0; i < 13; i++) { - v6[i] = 0; - v7[i] = getFromArray(a1, i, 0); - v8[i] = getFromArray(a1, i, 2); - } - - // 12 here, 13 up there - // Probably 12 for players, 13 for players+ball - for (int i = 0; i < 12; i++) { - int v22 = a4; - for (int j = i + 1; j < 13; j++) { - v18[i * 15 + j] = distance(v7[i], v7[j], v8[i], v8[j]); - putInArray(a2, i, j, v18[i * 15 + j]); - putInArray(a2, j, i, v18[i * 15 + j]); - if (v18[i * 15 + j] < v22) { - v22 = v18[i * 15 + j]; - v6[i] = j + 1; - v6[j] = i + 1; - } - } - } - - int v13 = getFromArray(a1, 18, 0); - int v14 = getFromArray(a1, 18, 2); - int v15 = getFromArray(a1, 19, 0); - int v16 = getFromArray(a1, 19, 2); - int v19[15]; - int v20[15]; - - if (_vm->_game.id == GID_SOCCER) { - // soccer gets to be different - for (int i = 0; i < 13; i++) - v20[i] = distance(v13, v7[i], v14, v8[i]); - - for (int i = 0; i < 13; i++) - v19[i] = distance(v15, v7[i], v16, v8[i]); - } else { - // soccermls and soccer2004 use two other arrays here - int v9 = getFromArray(a1, 20, 0); - int v10 = getFromArray(a1, 20, 2); - int v11 = getFromArray(a1, 21, 0); - int v12 = getFromArray(a1, 21, 2); - - for (int i = 0; i < 6; i++) { - v20[i] = distance(v9, v7[i], v10, v8[i]); - v19[i] = distance(v13, v7[i], v14, v8[i]); - } - - for (int i = 6; i < 13; i++) { - v20[i] = distance(v11, v7[i], v12, v8[i]); - v19[i] = distance(v15, v7[i], v16, v8[i]); - } - } - - for (int i = 0; i < 13; i++) { - putInArray(a2, 14, i, v20[i]); - putInArray(a2, i, 14, v20[i]); - putInArray(a2, 13, i, v19[i]); - putInArray(a2, i, 13, v19[i]); - putInArray(a3, 0, i, v6[i]); - } -} - -int LogicHEsoccer::op_1012(int32 *args) { - // Used after op_1019 - // This function activates startOfFrame() to call op_1011 - // (Possibly field parameters?) - - _userDataD[530] = (args[0] != 0) ? 1 : 0; - _userDataD[531] = args[1]; - _userDataD[532] = args[2]; - _userDataD[533] = args[3]; - _userDataD[534] = args[4]; - _userDataD[535] = args[5]; // unused!!! - _userDataD[536] = args[6]; - - return 1; -} - -// Some strange power operation, ignores negative exponents -static inline double u32Pow(float a1, int a2) { - if (a2 < 0) - return 0.0; +LogicHE *LogicHE::makeLogicHE(ScummEngine_v90he *vm) { + switch (vm->_game.id) { + case GID_PUTTRACE: + return makeLogicHErace(vm); - float v4 = 1.0; + case GID_FUNSHOP: + return makeLogicHEfunshop(vm); - for (int i = 1; i <= a2; i++) - v4 *= a1; + case GID_FOOTBALL: + return makeLogicHEfootball(vm); - return v4; -} + case GID_SOCCER: + case GID_SOCCERMLS: + case GID_SOCCER2004: + return makeLogicHEsoccer(vm); -int LogicHEsoccer::op_sub5(int a1, int a2, int a3) { - byte *v9 = _array1013 + 44 * a2; + case GID_BASEBALL2001: + return makeLogicHEbaseball2001(vm); - *((uint32 *)v9 + 4) = a3; - *((uint32 *)v9) = a2; + case GID_BASKETBALL: + return makeLogicHEbasketball(vm); - if (a1 > 2) { - // Casual observation: 585 is also the size of _byteArray2 - *((uint32 *)v9 + 40) = 8 * a2 - 585; - for (int i = 0; i < 8; i++) - *((uint32 *)v9 + 4 * i + 8) = 0xffffffff; - } else { - for (int i = 0; i < 8; i++) - *((uint32 *)v9 + 4 * i + 8) = op_sub5(a1 + 1, i + 8 * a2 + 1, a2); - } - - return a2; -} - -int LogicHEsoccer::op_1013(int32 a1, int32 a2, int32 a3) { - // Creates _array1013 for *some* purpose - // _array1013Temp is used again op_1014 for some reason... - // Seems to be used in op_1015 - - int v4 = (int)((1.0 - u32Pow(8.0, 4)) / -7.0); - - _array1013 = new byte[v4 * 44]; - memset(_array1013, 0, v4 * 44); - _array1013Allocated = true; - memset(_array1013Temp, 0, 44); - - for (int i = 0; i < 8; i++) - _array1013Temp[i + 2] = op_sub5(1, i + 1, 0); - - // Yes, this is not endian-safe, but should not matter since we're - // not saving/loading the data anywhere - memcpy(_array1013, _array1013Temp, 44); - - return 1; -} - -int LogicHEsoccer::op_1014(int32 a1, int32 a2, int32 a3, int32 a4, int32 a5, int32 a6, int32 a7, int32 a8, int32 a9, int32 a10, int32 a11, int32 a12, int32 a13, int32 a14) { - // TODO: Used many times during a match - // And called from op_1008! - - return 1; -} - -int LogicHEsoccer::op_1019(int32 *args) { - // Used at the beginning of a match - // Initializes some arrays. Player positions? - - // These two arrays are used in op_1014 and op_1015 - for (int i = 0; i < 4096; i++) - _byteArray1[i] = getFromArray(args[1], 0, i); - - for (int i = 0; i < 585; i++) - _byteArray2[i] = getFromArray(args[0], 0, i); - - // Deallocate the two integer arrays - if (_intArraysAllocated) - op_1020(); - - // Reallocate them - _intArray1 = new uint32[1008]; - _intArray2 = new uint32[168]; - _intArraysAllocated = true; - - memset(_intArray1, 0, 4 * 4); - memset(_intArray2, 0, 24 * 4); - - // These two arrays are used in op_1015 - for (int i = 0; i < 42; i++) { - for (int j = 0; j < 24; j++) - _intArray1[j + 24 * i] = getFromArray(args[3], 0, j + 24 * i); - - for (int j = 0; j < 4; j++) - _intArray2[j + 4 * i] = getFromArray(args[2], 0, j + 4 * i); - } - - return 1; -} - -int LogicHEsoccer::op_1020() { - // Deallocate integer arrays - // The arrays can be allocated in op_1015 or op_1019 - - delete[] _intArray1; _intArray1 = 0; - delete[] _intArray2; _intArray2 = 0; - _intArraysAllocated = false; - - return 1; -} - -int LogicHEsoccer::op_1021(int32 a1, int32 a2, int32 a3, int32 a4, int32 a5, int32 a6, int32 a7) { - // Used during a match (ball movement?) - // Also called from op_1008 - - int v10; - if (a4 && a5) - v10 = (int)(((double)a2 - (double)a5 * (double)a1 / (double)a4) * -1.0 * (double)a4 / (double)a5); - else - v10 = a1; - - int v9; - if (a6 && a5) - v9 = (int)(((double)a2 - (double)a5 * (double)a3 / (double)a6) * -1.0 * (double)a6 / (double)a5); - else - v9 = a3; - - // The final argument chooses whether to store the results for op_1008 or - // store them in SCUMM variables. - if (a7) { - _var1021[0] = v10; - _var1021[1] = v9; - } else { - writeScummVar(108, v10); - writeScummVar(109, v9); - } - - return 1; -} - -/*********************** - * Backyard Baseball 2001 - * - */ - -int LogicHEbaseball2001::versionID() { - return 1; -} - -int32 LogicHEbaseball2001::dispatch(int op, int numArgs, int32 *args) { - int res = 0; - - switch (op) { - case 3001: - // Check network status - break; - - default: - LogicHE::dispatch(op, numArgs, args); - } - - return res; -} - -/*********************** - * Backyard Basketball - * - */ - -int LogicHEbasketball::versionID() { - return 1; -} - -int32 LogicHEbasketball::dispatch(int op, int numArgs, int32 *args) { - int res = 0; - - switch (op) { - case 1001: - break; - - case 1006: - break; - - case 1011: - break; - - case 1012: - break; - - case 1035: - break; - - case 1050: - break; - - case 1051: - break; - - case 1052: - break; - - case 1056: - break; - - case 1057: - break; - - case 1058: - break; - - case 1060: - break; - - case 1064: - break; - - case 1067: - break; - - case 1073: - break; - - case 1075: - break; - - case 1076: - break; - - case 1080: - break; - - case 1081: - break; - - case 1090: - break; - - case 1091: - break; - - case 1513: - break; + case GID_MOONBASE: + return makeLogicHEmoonbase(vm); default: - LogicHE::dispatch(op, numArgs, args); + return new LogicHE(vm); } - - return res; -} - -/*********************** - * Moonbase Commander - * - */ - -int LogicHEmoonbase::versionID() { - if (_vm->_game.features & GF_DEMO) - return -100; - else - return 100; } } // End of namespace Scumm diff --git a/engines/scumm/he/logic_he.h b/engines/scumm/he/logic_he.h index e05a05f310..893dc81b87 100644 --- a/engines/scumm/he/logic_he.h +++ b/engines/scumm/he/logic_he.h @@ -29,15 +29,10 @@ class ScummEngine_v90he; class LogicHE { public: - ScummEngine_v90he *_vm; + static LogicHE *makeLogicHE(ScummEngine_v90he *vm); - LogicHE(ScummEngine_v90he *vm); virtual ~LogicHE(); - void writeScummVar(int var, int32 value); - int getFromArray(int arg0, int idx2, int idx1); - void putInArray(int arg0, int idx2, int idx1, int val); - virtual void beforeBootScript() {} virtual void initOnce() {} virtual int startOfFrame() { return 1; } @@ -46,142 +41,30 @@ public: virtual int versionID(); virtual int32 dispatch(int op, int numArgs, int32 *args); -}; -class LogicHErace : public LogicHE { -private: - float *_userData; - double *_userDataD; -public: - LogicHErace(ScummEngine_v90he *vm); - ~LogicHErace(); - - int versionID(); - int32 dispatch(int op, int numArgs, int32 *args); - -private: - int32 op_1003(int32 *args); - int32 op_1004(int32 *args); - int32 op_1100(int32 *args); - int32 op_1101(int32 *args); - int32 op_1102(int32 *args); - int32 op_1103(int32 *args); - int32 op_1110(); - int32 op_1120(int32 *args); - int32 op_1130(int32 *args); - int32 op_1140(int32 *args); - - void op_sub1(float arg); - void op_sub2(float arg); - void op_sub3(float arg); -}; - -class LogicHEfunshop : public LogicHE { -public: - LogicHEfunshop(ScummEngine_v90he *vm) : LogicHE(vm) {} - - int versionID(); - int32 dispatch(int op, int numArgs, int32 *args); - -private: - void op_1004(int32 *args); - void op_1005(int32 *args); - int checkShape(int32 data0, int32 data1, int32 data4, int32 data5, int32 data2, int32 data3, int32 data6, int32 data7, int32 *x, int32 *y); -}; - -class LogicHEfootball : public LogicHE { -public: - LogicHEfootball(ScummEngine_v90he *vm) : LogicHE(vm) {} - - int versionID(); - int32 dispatch(int op, int numArgs, int32 *args); - -private: - int op_1004(int32 *args); - int op_1006(int32 *args); - int op_1007(int32 *args); - int op_1010(int32 *args); - int op_1022(int32 *args); - int op_1023(int32 *args); - int op_1024(int32 *args); -}; - -class LogicHEsoccer : public LogicHE { -private: - double *_userDataD; - -public: - LogicHEsoccer(ScummEngine_v90he *vm); - ~LogicHEsoccer(); - - int versionID(); - int32 dispatch(int op, int numArgs, int32 *args); - - void beforeBootScript(); - void initOnce(); - int startOfFrame(); - -private: - int op_1001(int32 *args); - int op_1002(int32 *args); - int op_1003(int32 *args); - int op_1004(int32 *args); - int op_1006(int32 a1, int32 a2, int32 a3, int32 a4); - int op_1007(int32 *args); - int op_1008(int32 *args); - int op_1011(int32 a1, int32 a2, int32 a3, int32 a4, int32 a5); - int op_1012(int32 *args); - int op_1013(int32 a1, int32 a2, int32 a3); - int op_1014(int32 a1, int32 a2, int32 a3, int32 a4, int32 a5, int32 a6, int32 a7, int32 a8, int32 a9, int32 a10, int32 a11, int32 a12, int32 a13, int32 a14); - int op_1019(int32 *args); - int op_1020(); - int op_1021(int32 a1, int32 a2, int32 a3, int32 a4, int32 a5, int32 a6, int32 a7); - - // Two integer arrays are used between some functions - // Originally, these pointers were in _userData, but we keep them separate - // Also, doing it that would break things on non 32-bit systems... - bool _intArraysAllocated; - uint32 *_intArray1, *_intArray2; - - // op_1007 allocates some arrays - // they're then filled by op_1019 - byte _byteArray1[4096], _byteArray2[585]; - - // op_1011 has a subfunction - void op_1011_sub(int32 a1, int32 a2, int32 a3, int32 a4); - - // op_1013 creates some array, purpose unknown - bool _array1013Allocated; - byte *_array1013; - uint32 _array1013Temp[11]; - int op_sub5(int a1, int a2, int a3); - - // op_1021 can (optionally) set two variables for use in op_1008 - uint32 _var1021[2]; -}; - -class LogicHEbaseball2001 : public LogicHE { -public: - LogicHEbaseball2001(ScummEngine_v90he *vm) : LogicHE(vm) {} +protected: + // Only to be used from makeLogicHE() + LogicHE(ScummEngine_v90he *vm); - int versionID(); - int32 dispatch(int op, int numArgs, int32 *args); -}; + ScummEngine_v90he *_vm; -class LogicHEbasketball : public LogicHE { -public: - LogicHEbasketball(ScummEngine_v90he *vm) : LogicHE(vm) {} + void writeScummVar(int var, int32 value); + int getFromArray(int arg0, int idx2, int idx1); + void putInArray(int arg0, int idx2, int idx1, int val); + int32 scummRound(double arg) { return (int32)(arg + 0.5); } - int versionID(); - int32 dispatch(int op, int numArgs, int32 *args); + #define RAD2DEG (180 / M_PI) + #define DEG2RAD (M_PI / 180) }; -class LogicHEmoonbase : public LogicHE { -public: - LogicHEmoonbase(ScummEngine_v90he *vm) : LogicHE(vm) {} - - int versionID(); -}; +// Logic declarations +LogicHE *makeLogicHErace(ScummEngine_v90he *vm); +LogicHE *makeLogicHEfunshop(ScummEngine_v90he *vm); +LogicHE *makeLogicHEfootball(ScummEngine_v90he *vm); +LogicHE *makeLogicHEsoccer(ScummEngine_v90he *vm); +LogicHE *makeLogicHEbaseball2001(ScummEngine_v90he *vm); +LogicHE *makeLogicHEbasketball(ScummEngine_v90he *vm); +LogicHE *makeLogicHEmoonbase(ScummEngine_v90he *vm); } // End of namespace Scumm diff --git a/engines/scumm/he/script_v100he.cpp b/engines/scumm/he/script_v100he.cpp index e057ab524a..56ea10f507 100644 --- a/engines/scumm/he/script_v100he.cpp +++ b/engines/scumm/he/script_v100he.cpp @@ -542,7 +542,7 @@ void ScummEngine_v100he::o100_arrayOps() { int dim1end, dim1start, dim2end, dim2start; int id, len, b, c, list[128]; int offs, tmp, tmp2; - uint tmp3; + uint tmp3, type; byte subOp = fetchScriptByte(); int array = fetchScriptWord(); @@ -625,11 +625,10 @@ void ScummEngine_v100he::o100_arrayOps() { } break; case 132: - debug(0, "o100_arrayOps: case 132"); - // TODO: Used by Moonbase Commander + // TODO: Used by room 2 script 2180 in Moonbase Commander fetchScriptWord(); fetchScriptWord(); - pop(); + type = pop(); pop(); pop(); pop(); @@ -646,6 +645,21 @@ void ScummEngine_v100he::o100_arrayOps() { if (id == 0) { defineArray(array, kDwordArray, dim2start, dim2end, dim1start, dim1end); } + switch (type) { + case 1: + break; + case 2: + break; + case 3: + break; + case 4: + break; + case 5: + break; + default: + error("o100_arrayOps: case 132 unknown type %d)", type); + } + debug(0, "o100_arrayOps: case 132 type %d", type); break; case 133: b = pop(); @@ -2933,7 +2947,7 @@ void ScummEngine_v100he::o100_getVideoData() { break; case 73: pop(); - push(_moviePlay->endOfVideo() ? -1 : (_moviePlay->getCurFrame() + 1)); + push(_moviePlay->getCurFrame()); break; case 84: pop(); diff --git a/engines/scumm/he/script_v60he.cpp b/engines/scumm/he/script_v60he.cpp index cf7d9fbd2f..dbeee567bf 100644 --- a/engines/scumm/he/script_v60he.cpp +++ b/engines/scumm/he/script_v60he.cpp @@ -94,6 +94,12 @@ int ScummEngine_v60he::convertFilePath(byte *dst, int dstSize) { debug(1, "convertFilePath: original filePath is %s", dst); int len = resStrLen(dst); + + // Switch all \ to / for portablity + for (int i = 0; i < len; i++) + if (dst[i] == '\\') + dst[i] = '/'; + if (_game.platform == Common::kPlatformMacintosh) { // Remove : prefix in HE71 games if (dst[0] == ':') { @@ -107,12 +113,6 @@ int ScummEngine_v60he::convertFilePath(byte *dst, int dstSize) { if (dst[i] == ':') dst[i] = '/'; } - } else { - // Switch all \ to / for portablity - for (int i = 0; i < len; i++) { - if (dst[i] == '\\') - dst[i] = '/'; - } } // Strip path diff --git a/engines/scumm/he/script_v72he.cpp b/engines/scumm/he/script_v72he.cpp index 5af4035930..b9f454de0f 100644 --- a/engines/scumm/he/script_v72he.cpp +++ b/engines/scumm/he/script_v72he.cpp @@ -1827,10 +1827,19 @@ void ScummEngine_v72he::o72_readINI() { switch (subOp) { case 43: // HE 100 case 6: // number - if (!strcmp((char *)option, "NoPrinting")) { + if (!strcmp((char *)option, "DisablePrinting") || !strcmp((char *)option, "NoPrinting")) { push(1); } else if (!strcmp((char *)option, "TextOn")) { push(ConfMan.getBool("subtitles")); + } else if (!strcmp((char *)option, "Disk") && (_game.id == GID_BIRTHDAYRED || _game.id == GID_BIRTHDAYYELLOW)) { + // WORKAROUND: Override the disk detection + // This removes the reliance on having the binary file around (which is + // very bad for the Mac version) just for the scripts to figure out if + // we're running Yellow or Red + if (_game.id == GID_BIRTHDAYRED) + push(4); + else + push(2); } else { push(ConfMan.getInt((char *)option)); } diff --git a/engines/scumm/he/script_v80he.cpp b/engines/scumm/he/script_v80he.cpp index 7970d7806f..9711f6415b 100644 --- a/engines/scumm/he/script_v80he.cpp +++ b/engines/scumm/he/script_v80he.cpp @@ -171,7 +171,10 @@ void ScummEngine_v80he::o80_readConfigFile() { case 6: // number ConfFile.getKey((const char *)option, (const char *)section, entry); - push(atoi(entry.c_str())); + if (!strcmp((char *)option, "Benchmark")) + push(2); + else + push(atoi(entry.c_str())); break; case 77: // HE 100 case 7: // string diff --git a/engines/scumm/he/script_v90he.cpp b/engines/scumm/he/script_v90he.cpp index 6b632d8ff2..66a0a34d16 100644 --- a/engines/scumm/he/script_v90he.cpp +++ b/engines/scumm/he/script_v90he.cpp @@ -1460,7 +1460,7 @@ void ScummEngine_v90he::o90_getVideoData() { break; case 52: // Get current frame pop(); - push(_moviePlay->endOfVideo() ? -1 : (_moviePlay->getCurFrame() + 1)); + push(_moviePlay->getCurFrame()); break; case 63: // Get image number pop(); diff --git a/engines/scumm/he/sprite_he.cpp b/engines/scumm/he/sprite_he.cpp index 0b37673e4a..081110c7cd 100644 --- a/engines/scumm/he/sprite_he.cpp +++ b/engines/scumm/he/sprite_he.cpp @@ -804,12 +804,18 @@ void Sprite::setSpriteImage(int spriteId, int imageNum) { if (_spriteTable[spriteId].image) { _spriteTable[spriteId].imageStateCount = _vm->_wiz->getWizImageStates(_spriteTable[spriteId].image); - _spriteTable[spriteId].flags |= kSFActive | kSFAutoAnim | kSFMarkDirty | kSFBlitDirectly; + + if (_vm->VAR(139)) + _spriteTable[spriteId].flags |= kSFActive; + else + _spriteTable[spriteId].flags |= kSFActive | kSFAutoAnim | kSFMarkDirty | kSFBlitDirectly; if (_spriteTable[spriteId].image != origResId || _spriteTable[spriteId].imageStateCount != origResWizStates) _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; } else { - if (_spriteTable[spriteId].flags & kSFImageless) + if (_vm->VAR(139)) + _spriteTable[spriteId].flags &= ~kSFActive; + else if (_spriteTable[spriteId].flags & kSFImageless) _spriteTable[spriteId].flags = 0; else _spriteTable[spriteId].flags = kSFChanged | kSFBlitDirectly; diff --git a/engines/scumm/he/sprite_he.h b/engines/scumm/he/sprite_he.h index d28c9f1944..be6717faa5 100644 --- a/engines/scumm/he/sprite_he.h +++ b/engines/scumm/he/sprite_he.h @@ -218,4 +218,3 @@ private: } // End of namespace Scumm #endif - diff --git a/engines/scumm/he/wiz_he.cpp b/engines/scumm/he/wiz_he.cpp index 4107034fe6..f67922c81c 100644 --- a/engines/scumm/he/wiz_he.cpp +++ b/engines/scumm/he/wiz_he.cpp @@ -1755,7 +1755,7 @@ void Wiz::captureWizPolygon(int resNum, int maskNum, int maskState, int id1, int uint8 *tmpPtr = imageBuffer; for (i = 0; i < dsth; i++) { for (j = 0; j < dstw; j++) - WRITE_UINT16(tmpPtr + j * 2, transColor); + WRITE_LE_UINT16(tmpPtr + j * 2, transColor); tmpPtr += dstpitch; } } else { diff --git a/engines/scumm/help.cpp b/engines/scumm/help.cpp index ae7a1ad3bc..cfb23a392a 100644 --- a/engines/scumm/help.cpp +++ b/engines/scumm/help.cpp @@ -175,6 +175,7 @@ void ScummHelp::updateStrings(byte gameId, byte version, Common::Platform platfo ADD_BIND("b", _("To Henry / To Indy")); break; case GID_LOOM: + // I18N: These are different musical notes ADD_BIND("q, c", _("play C minor on distaff")); ADD_BIND("w, d", _("play D on distaff")); ADD_BIND("e, e", _("play E on distaff")); @@ -238,6 +239,7 @@ void ScummHelp::updateStrings(byte gameId, byte version, Common::Platform platfo ADD_BIND("e", _("Examine")); ADD_BIND("t", _("Regular cursor")); ADD_BIND("i", _("Inventory")); + // I18N: Comm is a communication device ADD_BIND("c", _("Comm")); break; case GID_CMI: diff --git a/engines/scumm/help.h b/engines/scumm/help.h index 9763da8c00..5ba6bdc65c 100644 --- a/engines/scumm/help.h +++ b/engines/scumm/help.h @@ -42,4 +42,3 @@ public: } // End of namespace Scumm #endif - diff --git a/engines/scumm/imuse/imuse.cpp b/engines/scumm/imuse/imuse.cpp index 317ef36cb9..27a72c2afe 100644 --- a/engines/scumm/imuse/imuse.cpp +++ b/engines/scumm/imuse/imuse.cpp @@ -44,30 +44,31 @@ namespace Scumm { //////////////////////////////////////// IMuseInternal::IMuseInternal() : -_native_mt32(false), -_enable_gs(false), -_sc55(false), -_midi_adlib(NULL), -_midi_native(NULL), -_sysex(NULL), -_paused(false), -_initialized(false), -_tempoFactor(0), -_player_limit(ARRAYSIZE(_players)), -_recycle_players(false), -_queue_end(0), -_queue_pos(0), -_queue_sound(0), -_queue_adding(0), -_queue_marker(0), -_queue_cleared(0), -_master_volume(0), -_music_volume(0), -_trigger_count(0), -_snm_trigger_index(0) { - memset(_channel_volume,0,sizeof(_channel_volume)); - memset(_channel_volume_eff,0,sizeof(_channel_volume_eff)); - memset(_volchan_table,0,sizeof(_volchan_table)); + _native_mt32(false), + _enable_gs(false), + _sc55(false), + _midi_adlib(NULL), + _midi_native(NULL), + _sysex(NULL), + _paused(false), + _initialized(false), + _tempoFactor(0), + _player_limit(ARRAYSIZE(_players)), + _recycle_players(false), + _queue_end(0), + _queue_pos(0), + _queue_sound(0), + _queue_adding(0), + _queue_marker(0), + _queue_cleared(0), + _master_volume(0), + _music_volume(0), + _trigger_count(0), + _snm_trigger_index(0), + _pcSpeaker(false) { + memset(_channel_volume, 0, sizeof(_channel_volume)); + memset(_channel_volume_eff, 0, sizeof(_channel_volume_eff)); + memset(_volchan_table, 0, sizeof(_volchan_table)); } IMuseInternal::~IMuseInternal() { @@ -119,7 +120,7 @@ byte *IMuseInternal::findStartOfSound(int sound, int ct) { // Check for old-style headers first, like 'RO' int trFlag = (kMThd | kFORM); - if (ptr[0] == 'R' && ptr[1] == 'O'&& ptr[2] != 'L') + if (ptr[0] == 'R' && ptr[1] == 'O' && ptr[2] != 'L') return ct == trFlag ? ptr : 0; if (ptr[4] == 'S' && ptr[5] == 'O') return ct == trFlag ? ptr + 4 : 0; @@ -153,22 +154,22 @@ bool IMuseInternal::isMT32(int sound) { uint32 tag = READ_BE_UINT32(ptr); switch (tag) { - case MKTAG('A','D','L',' '): - case MKTAG('A','S','F','X'): // Special AD class for old AdLib sound effects - case MKTAG('S','P','K',' '): + case MKTAG('A', 'D', 'L', ' '): + case MKTAG('A', 'S', 'F', 'X'): // Special AD class for old AdLib sound effects + case MKTAG('S', 'P', 'K', ' '): return false; - case MKTAG('A','M','I',' '): - case MKTAG('R','O','L',' '): + case MKTAG('A', 'M', 'I', ' '): + case MKTAG('R', 'O', 'L', ' '): return true; - case MKTAG('M','A','C',' '): // Occurs in the Mac version of FOA and MI2 + case MKTAG('M', 'A', 'C', ' '): // Occurs in the Mac version of FOA and MI2 return true; - case MKTAG('G','M','D',' '): + case MKTAG('G', 'M', 'D', ' '): return false; - case MKTAG('M','I','D','I'): // Occurs in Sam & Max + case MKTAG('M', 'I', 'D', 'I'): // Occurs in Sam & Max // HE games use Roland music if (ptr[8] == 'H' && ptr[9] == 'S') return true; @@ -195,20 +196,20 @@ bool IMuseInternal::isMIDI(int sound) { uint32 tag = READ_BE_UINT32(ptr); switch (tag) { - case MKTAG('A','D','L',' '): - case MKTAG('A','S','F','X'): // Special AD class for old AdLib sound effects - case MKTAG('S','P','K',' '): + case MKTAG('A', 'D', 'L', ' '): + case MKTAG('A', 'S', 'F', 'X'): // Special AD class for old AdLib sound effects + case MKTAG('S', 'P', 'K', ' '): return false; - case MKTAG('A','M','I',' '): - case MKTAG('R','O','L',' '): + case MKTAG('A', 'M', 'I', ' '): + case MKTAG('R', 'O', 'L', ' '): return true; - case MKTAG('M','A','C',' '): // Occurs in the Mac version of FOA and MI2 + case MKTAG('M', 'A', 'C', ' '): // Occurs in the Mac version of FOA and MI2 return true; - case MKTAG('G','M','D',' '): - case MKTAG('M','I','D','I'): // Occurs in Sam & Max + case MKTAG('G', 'M', 'D', ' '): + case MKTAG('M', 'I', 'D', 'I'): // Occurs in Sam & Max return true; } @@ -381,7 +382,8 @@ int IMuseInternal::save_or_load(Serializer *ser, ScummEngine *scumm) { for (i = 0; i < ARRAYSIZE(_parts); ++i) _parts[i].saveLoadWithSerializer(ser); - { // Load/save the instrument definitions, which were revamped with V11. + { + // Load/save the instrument definitions, which were revamped with V11. Part *part = &_parts[0]; if (ser->getVersion() >= VER(11)) { for (i = ARRAYSIZE(_parts); i; --i, ++part) { @@ -467,6 +469,10 @@ uint32 IMuseInternal::property(int prop, uint32 value) { case IMuse::PROP_GAME_ID: _game_id = value; break; + + case IMuse::PROP_PC_SPEAKER: + _pcSpeaker = (value != 0); + break; } return 0; @@ -522,7 +528,7 @@ void IMuseInternal::stopAllSounds() { int IMuseInternal::getSoundStatus(int sound) const { Common::StackLock lock(_mutex, "IMuseInternal::getSoundStatus()"); - return getSoundStatus_internal (sound, true); + return getSoundStatus_internal(sound, true); } int IMuseInternal::getMusicTimer() { @@ -565,7 +571,7 @@ bool IMuseInternal::startSound_internal(int sound, int offset) { int i; ImTrigger *trigger = _snm_triggers; for (i = ARRAYSIZE(_snm_triggers); i; --i, ++trigger) { - if (trigger->sound && trigger->id && trigger->command[0] == 8 && trigger->command[1] == sound && getSoundStatus_internal (trigger->sound,true)) + if (trigger->sound && trigger->id && trigger->command[0] == 8 && trigger->command[1] == sound && getSoundStatus_internal(trigger->sound, true)) return false; } @@ -663,9 +669,7 @@ int IMuseInternal::getSoundStatus_internal(int sound, bool ignoreFadeouts) const return (sound == -1) ? 0 : get_queue_sound_status(sound); } -int32 IMuseInternal::doCommand_internal - (int a, int b, int c, int d, int e, int f, int g, int h) -{ +int32 IMuseInternal::doCommand_internal(int a, int b, int c, int d, int e, int f, int g, int h) { int args[8]; args[0] = a; args[1] = b; @@ -733,7 +737,7 @@ int32 IMuseInternal::doCommand_internal(int numargs, int a[]) { } return -1; case 13: - return getSoundStatus_internal (a[1], true); + return getSoundStatus_internal(a[1], true); case 14: // Sam and Max: Parameter fade player = findActivePlayer(a[1]); @@ -779,8 +783,7 @@ int32 IMuseInternal::doCommand_internal(int numargs, int a[]) { a[0] = 0; for (i = 0; i < ARRAYSIZE(_snm_triggers); ++i) { if (_snm_triggers[i].sound == a[1] && _snm_triggers[i].id && - (a[3] == -1 || _snm_triggers[i].id == a[3])) - { + (a[3] == -1 || _snm_triggers[i].id == a[3])) { ++a[0]; } } @@ -1002,9 +1005,9 @@ int IMuseInternal::get_queue_sound_status(int sound) const { i = (i + 1) % ARRAYSIZE(_cmd_queue); } - for (i = 0; i < ARRAYSIZE (_deferredCommands); ++i) { + for (i = 0; i < ARRAYSIZE(_deferredCommands); ++i) { if (_deferredCommands[i].time_left && _deferredCommands[i].a == 8 && - _deferredCommands[i].b == sound) { + _deferredCommands[i].b == sound) { return 2; } } @@ -1213,7 +1216,7 @@ int32 IMuseInternal::ImSetTrigger(int sound, int id, int a, int b, int c, int d, // NOTE: We ONLY do this if the sound that will trigger the command is actually // playing. Otherwise, there's a problem when exiting and re-entering the // Bumpusville mansion. Ref Bug #780918. - if (trig->command[0] == 8 && getSoundStatus_internal(trig->command[1],true) && getSoundStatus_internal(sound,true)) + if (trig->command[0] == 8 && getSoundStatus_internal(trig->command[1], true) && getSoundStatus_internal(sound, true)) stopSound_internal(trig->command[1]); return 0; } @@ -1246,8 +1249,7 @@ int32 IMuseInternal::ImFireAllTriggers(int sound) { return (count > 0) ? 0 : -1; } -int IMuseInternal::set_channel_volume(uint chan, uint vol) -{ +int IMuseInternal::set_channel_volume(uint chan, uint vol) { if (chan >= 8 || vol > 127) return -1; @@ -1427,7 +1429,7 @@ void IMuseInternal::initMT32(MidiDriver *midi) { // Display a welcome message on MT-32 displays. memcpy(&buffer[0], "\x41\x10\x16\x12\x20\x00\x00", 7); memcpy(&buffer[7], " ", 20); - memcpy(buffer + 7 +(20 - len) / 2, info, len); + memcpy(buffer + 7 + (20 - len) / 2, info, len); byte checksum = 0; for (int i = 4; i < 27; ++i) checksum -= buffer[i]; @@ -1473,9 +1475,9 @@ void IMuseInternal::initGM(MidiDriver *midi) { // Set Channels 1-16 to SC-55 Map, then CM-64/32L Variation for (i = 0; i < 16; ++i) { - midi->send(( 127 << 16) | (0 << 8) | (0xB0 | i)); - midi->send(( 1 << 16) | (32 << 8) | (0xB0 | i)); - midi->send(( 0 << 16) | (0 << 8) | (0xC0 | i)); + midi->send((127 << 16) | (0 << 8) | (0xB0 | i)); + midi->send((1 << 16) | (32 << 8) | (0xB0 | i)); + midi->send((0 << 16) | (0 << 8) | (0xC0 | i)); } debug(2, "GS Program Change: CM-64/32L Map Selected"); @@ -1496,7 +1498,7 @@ void IMuseInternal::initGM(MidiDriver *midi) { // Set Channels 1-16 Reverb to 64, which is the // equivalent of MT-32 default Reverb Level 5 for (i = 0; i < 16; ++i) - midi->send(( 64 << 16) | (91 << 8) | (0xB0 | i)); + midi->send((64 << 16) | (91 << 8) | (0xB0 | i)); debug(2, "GM Controller 91 Change: Channels 1-16 Reverb Level is 64"); // Set Channels 1-16 Pitch Bend Sensitivity to @@ -1637,8 +1639,8 @@ void IMuseInternal::reallocateMidiChannels(MidiDriver *midi) { hipart = NULL; for (i = 32, part = _parts; i; i--, part++) { if (part->_player && part->_player->getMidiDriver() == midi && - !part->_percussion && part->_on && - !part->_mc && part->_pri_eff >= hipri) { + !part->_percussion && part->_on && + !part->_mc && part->_pri_eff >= hipri) { hipri = part->_pri_eff; hipart = part; } @@ -1668,16 +1670,35 @@ void IMuseInternal::reallocateMidiChannels(MidiDriver *midi) { } } -void IMuseInternal::setGlobalAdLibInstrument(byte slot, byte *data) { +void IMuseInternal::setGlobalInstrument(byte slot, byte *data) { if (slot < 32) { - _global_adlib_instruments[slot].adlib(data); + if (_pcSpeaker) + _global_instruments[slot].pcspk(data); + else + _global_instruments[slot].adlib(data); } } -void IMuseInternal::copyGlobalAdLibInstrument(byte slot, Instrument *dest) { +void IMuseInternal::copyGlobalInstrument(byte slot, Instrument *dest) { if (slot >= 32) return; - _global_adlib_instruments[slot].copy_to(dest); + + // Both the AdLib code and the PC Speaker code use an all zero instrument + // as default in the original, thus we do the same. + // PC Speaker instrument size is 23, while AdLib instrument size is 30. + // Thus we just use a 30 byte instrument data array as default. + const byte defaultInstr[30] = { 0 }; + + if (_global_instruments[slot].isValid()) { + // In case we have an valid instrument set up, copy it to the part. + _global_instruments[slot].copy_to(dest); + } else if (_pcSpeaker) { + debug(0, "Trying to use non-existant global PC Speaker instrument %d", slot); + dest->pcspk(defaultInstr); + } else { + debug(0, "Trying to use non-existant global AdLib instrument %d", slot); + dest->adlib(defaultInstr); + } } diff --git a/engines/scumm/imuse/imuse.h b/engines/scumm/imuse/imuse.h index 8014b13409..23449e470b 100644 --- a/engines/scumm/imuse/imuse.h +++ b/engines/scumm/imuse/imuse.h @@ -37,7 +37,7 @@ class Player; class ScummEngine; class Serializer; -typedef void (*sysexfunc) (Player *, const byte *, uint16); +typedef void (*sysexfunc)(Player *, const byte *, uint16); /** * iMuse implementation interface. @@ -55,7 +55,8 @@ public: PROP_GS, PROP_LIMIT_PLAYERS, PROP_RECYCLE_PLAYERS, - PROP_GAME_ID + PROP_GAME_ID, + PROP_PC_SPEAKER }; public: @@ -66,7 +67,7 @@ public: virtual int32 doCommand(int numargs, int args[]) = 0; virtual int clear_queue() = 0; virtual uint32 property(int prop, uint32 value) = 0; - virtual void addSysexHandler (byte mfgID, sysexfunc handler) = 0; + virtual void addSysexHandler(byte mfgID, sysexfunc handler) = 0; public: virtual void startSoundWithNoteOffset(int sound, int offset) = 0; diff --git a/engines/scumm/imuse/imuse_internal.h b/engines/scumm/imuse/imuse_internal.h index 6a7b9fc7d9..3b0d36e119 100644 --- a/engines/scumm/imuse/imuse_internal.h +++ b/engines/scumm/imuse/imuse_internal.h @@ -135,7 +135,7 @@ struct ImTrigger { int sound; byte id; uint16 expire; - int command [8]; + int command[8]; ImTrigger() { memset(this, 0, sizeof(ImTrigger)); } }; @@ -153,12 +153,12 @@ struct CommandQueue { ////////////////////////////////////////////////// class Player : public MidiDriver_BASE { -/* - * External SysEx handler functions shall each be defined in - * a separate file. This header file shall be included at the - * top of the file immediately following this special #define: - * #define SYSEX_CALLBACK_FUNCTION nameOfHandlerFunction - */ + /* + * External SysEx handler functions shall each be defined in + * a separate file. This header file shall be included at the + * top of the file immediately following this special #define: + * #define SYSEX_CALLBACK_FUNCTION nameOfHandlerFunction + */ #ifdef SYSEX_CALLBACK_FUNCTION friend void SYSEX_CALLBACK_FUNCTION(Player *, const byte *, uint16); #endif @@ -244,7 +244,7 @@ public: void clear(); void clearLoop(); void fixAfterLoad(); - Part * getActivePart(uint8 part); + Part *getActivePart(uint8 part); uint getBeatIndex(); int8 getDetune() const { return _detune; } byte getEffectiveVolume() const { return _vol_eff; } @@ -252,7 +252,7 @@ public: MidiDriver *getMidiDriver() const { return _midi; } int getParam(int param, byte chan); int8 getPan() const { return _pan; } - Part * getPart(uint8 part); + Part *getPart(uint8 part); byte getPriority() const { return _priority; } uint getTicksPerBeat() const { return TICKS_PER_BEAT; } int8 getTranspose() const { return _transpose; } @@ -342,6 +342,7 @@ struct Part : public Serializable { void off(); void set_instrument(uint b); void set_instrument(byte *data); + void set_instrument_pcspk(byte *data); void load_global_instrument(byte b); void set_transpose(int8 transpose); @@ -375,12 +376,12 @@ class IMuseInternal : public IMuse { friend class Player; friend struct Part; -/* - * External SysEx handler functions shall each be defined in - * a separate file. This header file shall be included at the - * top of the file immediately following this special #define: - * #define SYSEX_CALLBACK_FUNCTION nameOfHandlerFunction - */ + /* + * External SysEx handler functions shall each be defined in + * a separate file. This header file shall be included at the + * top of the file immediately following this special #define: + * #define SYSEX_CALLBACK_FUNCTION nameOfHandlerFunction + */ #ifdef SYSEX_CALLBACK_FUNCTION friend void SYSEX_CALLBACK_FUNCTION(Player *, const byte *, uint16); #endif @@ -433,7 +434,8 @@ protected: Player _players[8]; Part _parts[32]; - Instrument _global_adlib_instruments[32]; + bool _pcSpeaker; + Instrument _global_instruments[32]; CommandQueue _cmd_queue[64]; DeferredCommand _deferredCommands[4]; @@ -449,8 +451,8 @@ protected: enum ChunkType { kMThd = 1, kFORM = 2, - kMDhd = 4, // Used in MI2 and INDY4. Contain certain start parameters (priority, volume, etc. ) for the player. - kMDpg = 8 // These chunks exist in DOTT and SAMNMAX. They don't get processed, however. + kMDhd = 4, // Used in MI2 and INDY4. Contain certain start parameters (priority, volume, etc. ) for the player. + kMDpg = 8 // These chunks exist in DOTT and SAMNMAX. They don't get processed, however. }; byte *findStartOfSound(int sound, int ct = (kMThd | kFORM)); @@ -498,8 +500,8 @@ protected: int setImuseMasterVolume(uint vol); void reallocateMidiChannels(MidiDriver *midi); - void setGlobalAdLibInstrument(byte slot, byte *data); - void copyGlobalAdLibInstrument(byte slot, Instrument *dest); + void setGlobalInstrument(byte slot, byte *data); + void copyGlobalInstrument(byte slot, Instrument *dest); bool isNativeMT32() { return _native_mt32; } protected: diff --git a/engines/scumm/imuse/imuse_part.cpp b/engines/scumm/imuse/imuse_part.cpp index 5df8407a96..73e7704469 100644 --- a/engines/scumm/imuse/imuse_part.cpp +++ b/engines/scumm/imuse/imuse_part.cpp @@ -193,14 +193,18 @@ void Part::set_onoff(bool on) { } } -void Part::set_instrument(byte * data) { - _instrument.adlib(data); +void Part::set_instrument(byte *data) { + if (_se->_pcSpeaker) + _instrument.pcspk(data); + else + _instrument.adlib(data); + if (clearToTransmit()) _instrument.send(_mc); } void Part::load_global_instrument(byte slot) { - _player->_se->copyGlobalAdLibInstrument(slot, &_instrument); + _player->_se->copyGlobalInstrument(slot, &_instrument); if (clearToTransmit()) _instrument.send(_mc); } @@ -234,7 +238,7 @@ void Part::noteOn(byte note, byte velocity) { // should be implemented as a class static var. As it is, using // a function level static var in most cases is arcane and evil. static byte prev_vol_eff = 128; - if (_vol_eff != prev_vol_eff){ + if (_vol_eff != prev_vol_eff) { mc->volume(_vol_eff); prev_vol_eff = _vol_eff; } diff --git a/engines/scumm/imuse/imuse_player.cpp b/engines/scumm/imuse/imuse_player.cpp index 61b9cad2cb..73be2174cd 100644 --- a/engines/scumm/imuse/imuse_player.cpp +++ b/engines/scumm/imuse/imuse_player.cpp @@ -79,7 +79,7 @@ Player::Player() : _isMT32(false), _isMIDI(false), _se(0), - _vol_chan(0){ + _vol_chan(0) { } Player::~Player() { @@ -133,7 +133,7 @@ bool Player::isFadingOut() const { int i; for (i = 0; i < ARRAYSIZE(_parameterFaders); ++i) { if (_parameterFaders[i].param == ParameterFader::pfVolume && - _parameterFaders[i].end == 0) { + _parameterFaders[i].end == 0) { return true; } } @@ -371,11 +371,13 @@ void Player::sysEx(const byte *p, uint16 len) { if (a != IMUSE_SYSEX_ID) { if (a == ROLAND_SYSEX_ID) { // Roland custom instrument definition. - part = getPart(p[0] & 0x0F); - if (part) { - part->_instrument.roland(p - 1); - if (part->clearToTransmit()) - part->_instrument.send(part->_mc); + if (_isMIDI || _isMT32) { + part = getPart(p[0] & 0x0F); + if (part) { + part->_instrument.roland(p - 1); + if (part->clearToTransmit()) + part->_instrument.send(part->_mc); + } } } else if (a == YM2612_SYSEX_ID) { // FM-TOWNS custom instrument definition @@ -399,13 +401,13 @@ void Player::sysEx(const byte *p, uint16 len) { if (!_scanning) { for (a = 0; a < len + 1 && a < 19; ++a) { - sprintf((char *)&buf[a*3], " %02X", p[a]); + sprintf((char *)&buf[a * 3], " %02X", p[a]); } // next for if (a < len + 1) { - buf[a*3] = buf[a*3+1] = buf[a*3+2] = '.'; + buf[a * 3] = buf[a * 3 + 1] = buf[a * 3 + 2] = '.'; ++a; } // end if - buf[a*3] = '\0'; + buf[a * 3] = '\0'; debugC(DEBUG_IMUSE, "[%02d] SysEx:%s", _id, buf); } @@ -814,7 +816,7 @@ int Player::query_part_param(int param, byte chan) { return part->_vol; case 16: // FIXME: Need to know where this occurs... -error("Trying to cast instrument (%d, %d) -- please tell Fingolfin", param, chan); + error("Trying to cast instrument (%d, %d) -- please tell Fingolfin", param, chan); // In old versions of the code, this used to return part->_program. // This was changed in revision 2.29 of imuse.cpp (where this code used // to reside). @@ -845,9 +847,8 @@ void Player::onTimer() { uint beat_index = target_tick / TICKS_PER_BEAT + 1; uint tick_index = target_tick % TICKS_PER_BEAT; - if (_loop_counter &&(beat_index > _loop_from_beat || - (beat_index == _loop_from_beat && tick_index >= _loop_from_tick))) - { + if (_loop_counter && (beat_index > _loop_from_beat || + (beat_index == _loop_from_beat && tick_index >= _loop_from_tick))) { _loop_counter--; jump(_track_index, _loop_to_beat, _loop_to_tick); } @@ -891,15 +892,15 @@ int Player::addParameterFader(int param, int target, int time) { // target = target * 128 / 100; break; - case 127: - { // FIXME? I *think* this clears all parameter faders. - ParameterFader *ptr = &_parameterFaders[0]; - int i; - for (i = ARRAYSIZE(_parameterFaders); i; --i, ++ptr) - ptr->param = 0; - return 0; - } - break; + case 127: { + // FIXME? I *think* this clears all parameter faders. + ParameterFader *ptr = &_parameterFaders[0]; + int i; + for (i = ARRAYSIZE(_parameterFaders); i; --i, ++ptr) + ptr->param = 0; + return 0; + } + break; default: debug(0, "Player::addParameterFader(%d, %d, %d): Unknown parameter", param, target, time); @@ -1085,7 +1086,7 @@ void Player::saveLoadWithSerializer(Serializer *ser) { } ser->saveLoadEntries(this, playerEntries); ser->saveLoadArrayOf(_parameterFaders, ARRAYSIZE(_parameterFaders), - sizeof(ParameterFader), parameterFaderEntries); + sizeof(ParameterFader), parameterFaderEntries); return; } diff --git a/engines/scumm/imuse/instrument.cpp b/engines/scumm/imuse/instrument.cpp index 955700fc2b..11bb4e7605 100644 --- a/engines/scumm/imuse/instrument.cpp +++ b/engines/scumm/imuse/instrument.cpp @@ -114,14 +114,15 @@ roland_to_gm_map[] = { // { "trickle4 ", ??? } }; +// This emulates the percussion bank setup LEC used with the MT-32, +// where notes 24 - 34 were assigned instruments without reverb. +// It also fixes problems on GS devices that map sounds to these +// notes by default. const byte Instrument::_gmRhythmMap[35] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 36, 37, 38, 39, 40, 41, 66, 47, - 65, 48, 56}; - // This emulates the percussion bank setup LEC used with the MT-32, - // where notes 24 - 34 were assigned instruments without reverb. - // It also fixes problems on GS devices that map sounds to these - // notes by default. + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 36, 37, 38, 39, 40, 41, 66, 47, + 65, 48, 56 +}; class Instrument_Program : public InstrumentInternal { private: @@ -136,15 +137,16 @@ public: void copy_to(Instrument *dest) { dest->program(_program, _mt32); } bool is_valid() { return (_program < 128) && - ((_native_mt32 == _mt32) || _native_mt32 - ? (MidiDriver::_gmToMt32[_program] < 128) - : (MidiDriver::_mt32ToGm[_program] < 128)); } + ((_native_mt32 == _mt32) || _native_mt32 + ? (MidiDriver::_gmToMt32[_program] < 128) + : (MidiDriver::_mt32ToGm[_program] < 128)); + } }; class Instrument_AdLib : public InstrumentInternal { private: -#include "common/pack-start.h" // START STRUCT PACKING +#include "common/pack-start.h" // START STRUCT PACKING struct AdLibInstrument { byte flags_1; @@ -159,13 +161,17 @@ private: byte waveform_2; byte feedback; byte flags_a; - struct { byte a,b,c,d,e,f,g,h; } extra_a; + struct { + byte a, b, c, d, e, f, g, h; + } extra_a; byte flags_b; - struct { byte a,b,c,d,e,f,g,h; } extra_b; + struct { + byte a, b, c, d, e, f, g, h; + } extra_b; byte duration; } PACKED_STRUCT; -#include "common/pack-end.h" // END STRUCT PACKING +#include "common/pack-end.h" // END STRUCT PACKING AdLibInstrument _instrument; @@ -181,7 +187,7 @@ public: class Instrument_Roland : public InstrumentInternal { private: -#include "common/pack-start.h" // START STRUCT PACKING +#include "common/pack-start.h" // START STRUCT PACKING struct RolandInstrument { byte roland_id; @@ -242,11 +248,11 @@ private: byte checksum; } PACKED_STRUCT; -#include "common/pack-end.h" // END STRUCT PACKING +#include "common/pack-end.h" // END STRUCT PACKING RolandInstrument _instrument; - char _instrument_name [11]; + char _instrument_name[11]; uint8 getEquivalentGM(); @@ -259,6 +265,19 @@ public: bool is_valid() { return (_native_mt32 ? true : (_instrument_name[0] != '\0')); } }; +class Instrument_PcSpk : public InstrumentInternal { +public: + Instrument_PcSpk(const byte *data); + Instrument_PcSpk(Serializer *s); + void saveOrLoad(Serializer *s); + void send(MidiChannel *mc); + void copy_to(Instrument *dest) { dest->pcspk((byte *)&_instrument); } + bool is_valid() { return true; } + +private: + byte _instrument[23]; +}; + //////////////////////////////////////// // // Instrument class members @@ -299,7 +318,15 @@ void Instrument::roland(const byte *instrument) { _instrument = new Instrument_Roland(instrument); } -void Instrument::saveOrLoad (Serializer *s) { +void Instrument::pcspk(const byte *instrument) { + clear(); + if (!instrument) + return; + _type = itPcSpk; + _instrument = new Instrument_PcSpk(instrument); +} + +void Instrument::saveOrLoad(Serializer *s) { if (s->isSaving()) { s->saveByte(_type); if (_instrument) @@ -319,6 +346,9 @@ void Instrument::saveOrLoad (Serializer *s) { case itRoland: _instrument = new Instrument_Roland(s); break; + case itPcSpk: + _instrument = new Instrument_PcSpk(s); + break; default: warning("No known instrument classification #%d", (int)_type); _type = itNone; @@ -333,8 +363,8 @@ void Instrument::saveOrLoad (Serializer *s) { //////////////////////////////////////// Instrument_Program::Instrument_Program(byte program, bool mt32) : -_program (program), -_mt32 (mt32) { + _program(program), + _mt32(mt32) { if (program > 127) _program = 255; } @@ -413,7 +443,7 @@ Instrument_Roland::Instrument_Roland(const byte *data) { Instrument_Roland::Instrument_Roland(Serializer *s) { _instrument_name[0] = '\0'; if (!s->isSaving()) - saveOrLoad (s); + saveOrLoad(s); else memset(&_instrument, 0, sizeof(_instrument)); } @@ -470,4 +500,32 @@ uint8 Instrument_Roland::getEquivalentGM() { return 255; } +//////////////////////////////////////// +// +// Instrument_PcSpk class members +// +//////////////////////////////////////// + +Instrument_PcSpk::Instrument_PcSpk(const byte *data) { + memcpy(_instrument, data, sizeof(_instrument)); +} + +Instrument_PcSpk::Instrument_PcSpk(Serializer *s) { + if (!s->isSaving()) + saveOrLoad(s); + else + memset(_instrument, 0, sizeof(_instrument)); +} + +void Instrument_PcSpk::saveOrLoad(Serializer *s) { + if (s->isSaving()) + s->saveBytes(_instrument, sizeof(_instrument)); + else + s->loadBytes(_instrument, sizeof(_instrument)); +} + +void Instrument_PcSpk::send(MidiChannel *mc) { + mc->sysEx_customInstrument('SPK ', (byte *)&_instrument); +} + } // End of namespace Scumm diff --git a/engines/scumm/imuse/instrument.h b/engines/scumm/imuse/instrument.h index 79cbd49032..a855c64155 100644 --- a/engines/scumm/imuse/instrument.h +++ b/engines/scumm/imuse/instrument.h @@ -51,10 +51,11 @@ public: itNone = 0, itProgram = 1, itAdLib = 2, - itRoland = 3 + itRoland = 3, + itPcSpk = 4 }; - Instrument() : _type (0), _instrument (0) { } + Instrument() : _type(0), _instrument(0) { } ~Instrument() { delete _instrument; } static void nativeMT32(bool native); static const byte _gmRhythmMap[35]; @@ -70,6 +71,7 @@ public: void program(byte program, bool mt32); void adlib(const byte *instrument); void roland(const byte *instrument); + void pcspk(const byte *instrument); byte getType() { return _type; } bool isValid() { return (_instrument ? _instrument->is_valid() : false); } diff --git a/engines/scumm/imuse/pcspk.cpp b/engines/scumm/imuse/pcspk.cpp new file mode 100644 index 0000000000..cbf3446f10 --- /dev/null +++ b/engines/scumm/imuse/pcspk.cpp @@ -0,0 +1,834 @@ +/* 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 "scumm/imuse/pcspk.h" + +#include "common/util.h" + +namespace Scumm { + +PcSpkDriver::PcSpkDriver(Audio::Mixer *mixer) + : MidiDriver_Emulated(mixer), _pcSpk(mixer->getOutputRate()) { +} + +PcSpkDriver::~PcSpkDriver() { + close(); +} + +int PcSpkDriver::open() { + if (_isOpen) + return MERR_ALREADY_OPEN; + + MidiDriver_Emulated::open(); + + for (uint i = 0; i < 6; ++i) + _channels[i].init(this, i); + _activeChannel = 0; + _effectTimer = 0; + _randBase = 1; + + // We need to take care we only send note frequencies, when the internal + // settings actually changed, thus we need some extra state to keep track + // of that. + _lastActiveChannel = 0; + _lastActiveOut = 0; + + // We set the output sound type to music here to allow sound volume + // adjustment. The drawback here is that we can not control the music and + // sfx separately here. But the AdLib output has the same issue so it + // should not be that bad. + _mixer->playStream(Audio::Mixer::kMusicSoundType, &_mixerSoundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); + return 0; +} + +void PcSpkDriver::close() { + if (!_isOpen) + return; + _isOpen = false; + + _mixer->stopHandle(_mixerSoundHandle); +} + +void PcSpkDriver::send(uint32 d) { + assert((d & 0x0F) < 6); + _channels[(d & 0x0F)].send(d); +} + +void PcSpkDriver::sysEx_customInstrument(byte channel, uint32 type, const byte *instr) { + assert(channel < 6); + if (type == 'SPK ') + _channels[channel].sysEx_customInstrument(type, instr); +} + +MidiChannel *PcSpkDriver::allocateChannel() { + for (uint i = 0; i < 6; ++i) { + if (_channels[i].allocate()) + return &_channels[i]; + } + + return 0; +} + +void PcSpkDriver::generateSamples(int16 *buf, int len) { + _pcSpk.readBuffer(buf, len); +} + +void PcSpkDriver::onTimer() { + if (!_activeChannel) + return; + + for (uint i = 0; i < 6; ++i) { + OutputChannel &out = _channels[i]._out; + + if (!out.active) + continue; + + if (out.length == 0 || --out.length != 0) { + if (out.unkB && out.unkC) { + out.unkA += out.unkB; + if (out.instrument) + out.unkE = ((int8)out.instrument[out.unkA] * out.unkC) >> 4; + } + + ++_effectTimer; + if (_effectTimer > 3) { + _effectTimer = 0; + + if (out.effectEnvelopeA.state) + updateEffectGenerator(_channels[i], out.effectEnvelopeA, out.effectDefA); + if (out.effectEnvelopeB.state) + updateEffectGenerator(_channels[i], out.effectEnvelopeB, out.effectDefB); + } + } else { + out.active = 0; + updateNote(); + return; + } + } + + if (_activeChannel->_tl) { + output((_activeChannel->_out.note << 7) + _activeChannel->_pitchBend + _activeChannel->_out.unk60 + _activeChannel->_out.unkE); + } else { + _pcSpk.stop(); + _lastActiveChannel = 0; + _lastActiveOut = 0; + } +} + +void PcSpkDriver::updateNote() { + uint8 priority = 0; + _activeChannel = 0; + for (uint i = 0; i < 6; ++i) { + if (_channels[i]._allocated && _channels[i]._out.active && _channels[i]._priority >= priority) { + priority = _channels[i]._priority; + _activeChannel = &_channels[i]; + } + } + + if (_activeChannel == 0 || _activeChannel->_tl == 0) { + _pcSpk.stop(); + _lastActiveChannel = 0; + _lastActiveOut = 0; + } else { + output(_activeChannel->_pitchBend + (_activeChannel->_out.note << 7)); + } +} + +void PcSpkDriver::output(uint16 out) { + byte v1 = (out >> 7) & 0xFF; + byte v2 = (out >> 2) & 0x1E; + + byte shift = _outputTable1[v1]; + uint16 indexBase = _outputTable2[v1] << 5; + uint16 frequency = _frequencyTable[(indexBase + v2) / 2] >> shift; + + // Only output in case the active channel changed or the frequency changed. + // This is not faithful to the original. Since our timings differ we would + // get distorted sound otherwise though. + if (_lastActiveChannel != _activeChannel || _lastActiveOut != out) { + _pcSpk.play(Audio::PCSpeaker::kWaveFormSquare, 1193180 / frequency, -1); + _lastActiveChannel = _activeChannel; + _lastActiveOut = out; + } +} + +void PcSpkDriver::MidiChannel_PcSpk::init(PcSpkDriver *owner, byte channel) { + _owner = owner; + _channel = channel; + _allocated = false; + memset(&_out, 0, sizeof(_out)); +} + +bool PcSpkDriver::MidiChannel_PcSpk::allocate() { + if (_allocated) + return false; + + memset(&_out, 0, sizeof(_out)); + memset(_instrument, 0, sizeof(_instrument)); + _out.effectDefA.envelope = &_out.effectEnvelopeA; + _out.effectDefB.envelope = &_out.effectEnvelopeB; + + _allocated = true; + return true; +} + +MidiDriver *PcSpkDriver::MidiChannel_PcSpk::device() { + return _owner; +} + +byte PcSpkDriver::MidiChannel_PcSpk::getNumber() { + return _channel; +} + +void PcSpkDriver::MidiChannel_PcSpk::release() { + _out.active = 0; + _allocated = false; + _owner->updateNote(); +} + +void PcSpkDriver::MidiChannel_PcSpk::send(uint32 b) { + uint8 type = b & 0xF0; + uint8 p1 = (b >> 8) & 0xFF; + uint8 p2 = (b >> 16) & 0xFF; + + switch (type) { + case 0x80: + noteOff(p1); + break; + + case 0x90: + if (p2) + noteOn(p1, p2); + else + noteOff(p1); + break; + + case 0xB0: + controlChange(p1, p2); + break; + + case 0xE0: + pitchBend((p1 | (p2 << 7)) - 0x2000); + break; + + default: + break; + } +} + +void PcSpkDriver::MidiChannel_PcSpk::noteOff(byte note) { + if (!_allocated) + return; + + if (_sustain) { + if (_out.note == note) + _out.sustainNoteOff = 1; + } else { + if (_out.note == note) { + _out.active = 0; + _owner->updateNote(); + } + } +} + +void PcSpkDriver::MidiChannel_PcSpk::noteOn(byte note, byte velocity) { + if (!_allocated) + return; + + _out.note = note; + _out.sustainNoteOff = 0; + _out.length = _instrument[0]; + + if (_instrument[4] * 256 < ARRAYSIZE(PcSpkDriver::_outInstrumentData)) + _out.instrument = _owner->_outInstrumentData + _instrument[4] * 256; + else + _out.instrument = 0; + + _out.unkA = 0; + _out.unkB = _instrument[1]; + _out.unkC = _instrument[2]; + _out.unkE = 0; + _out.unk60 = 0; + _out.active = 1; + + // In case we get a note on event on the last active channel, we reset the + // last active channel, thus we assure the frequency is correctly set, even + // when the same note was sent. + if (_owner->_lastActiveChannel == this) { + _owner->_lastActiveChannel = 0; + _owner->_lastActiveOut = 0; + } + _owner->updateNote(); + + _out.unkC += PcSpkDriver::getEffectModifier(_instrument[3] + ((velocity & 0xFE) << 4)); + if (_out.unkC > 63) + _out.unkC = 63; + + if ((_instrument[5] & 0x80) != 0) + _owner->setupEffects(*this, _out.effectEnvelopeA, _out.effectDefA, _instrument[5], _instrument + 6); + + if ((_instrument[14] & 0x80) != 0) + _owner->setupEffects(*this, _out.effectEnvelopeB, _out.effectDefB, _instrument[14], _instrument + 15); +} + +void PcSpkDriver::MidiChannel_PcSpk::programChange(byte program) { + // Nothing to implement here, the iMuse code takes care of passing us the + // instrument data. +} + +void PcSpkDriver::MidiChannel_PcSpk::pitchBend(int16 bend) { + _pitchBend = (bend * _pitchBendFactor) >> 6; +} + +void PcSpkDriver::MidiChannel_PcSpk::controlChange(byte control, byte value) { + switch (control) { + case 1: + if (_out.effectEnvelopeA.state && _out.effectDefA.useModWheel) + _out.effectEnvelopeA.modWheelState = (value >> 2); + if (_out.effectEnvelopeB.state && _out.effectDefB.useModWheel) + _out.effectEnvelopeB.modWheelState = (value >> 2); + break; + + case 7: + _tl = value; + if (_owner->_activeChannel == this) { + if (_tl == 0) { + _owner->_lastActiveChannel = 0; + _owner->_lastActiveOut = 0; + _owner->_pcSpk.stop(); + } else { + _owner->output((_out.note << 7) + _pitchBend + _out.unk60 + _out.unkE); + } + } + break; + + case 64: + _sustain = value; + if (!value && _out.sustainNoteOff) { + _out.active = 0; + _owner->updateNote(); + } + break; + + case 123: + _out.active = 0; + _owner->updateNote(); + break; + + default: + break; + } +} + +void PcSpkDriver::MidiChannel_PcSpk::pitchBendFactor(byte value) { + _pitchBendFactor = value; +} + +void PcSpkDriver::MidiChannel_PcSpk::priority(byte value) { + _priority = value; +} + +void PcSpkDriver::MidiChannel_PcSpk::sysEx_customInstrument(uint32 type, const byte *instr) { + memcpy(_instrument, instr, sizeof(_instrument)); +} + +uint8 PcSpkDriver::getEffectModifier(uint16 level) { + uint8 base = level / 32; + uint8 index = level % 32; + + if (index == 0) + return 0; + + return (base * (index + 1)) >> 5; +} + +int16 PcSpkDriver::getEffectModLevel(int16 level, int8 mod) { + if (!mod) { + return 0; + } else if (mod == 31) { + return level; + } else if (level < -63 || level > 63) { + return (mod * (level + 1)) >> 6; + } else if (mod < 0) { + if (level < 0) + return getEffectModifier(((-level) << 5) - mod); + else + return -getEffectModifier((level << 5) - mod); + } else { + if (level < 0) + return -getEffectModifier(((-level) << 5) + mod); + else + return getEffectModifier(((-level) << 5) + mod); + } +} + +int16 PcSpkDriver::getRandScale(int16 input) { + if (_randBase & 1) + _randBase = (_randBase >> 1) ^ 0xB8; + else + _randBase >>= 1; + + return (_randBase * input) >> 8; +} + +void PcSpkDriver::setupEffects(MidiChannel_PcSpk &chan, EffectEnvelope &env, EffectDefinition &def, byte flags, const byte *data) { + def.phase = 0; + def.useModWheel = flags & 0x40; + env.loop = flags & 0x20; + def.type = flags & 0x1F; + + env.modWheelSensitivity = 31; + if (def.useModWheel) + env.modWheelState = chan._modWheel >> 2; + else + env.modWheelState = 31; + + switch (def.type) { + case 0: + env.maxLevel = 767; + env.startLevel = 383; + break; + + case 1: + env.maxLevel = 31; + env.startLevel = 15; + break; + + case 2: + env.maxLevel = 63; + env.startLevel = chan._out.unkB; + break; + + case 3: + env.maxLevel = 63; + env.startLevel = chan._out.unkC; + break; + + case 4: + env.maxLevel = 3; + env.startLevel = chan._instrument[4]; + break; + + case 5: + env.maxLevel = 62; + env.startLevel = 31; + env.modWheelState = 0; + break; + + case 6: + env.maxLevel = 31; + env.startLevel = 0; + env.modWheelSensitivity = 0; + break; + + default: + break; + } + + startEffect(env, data); +} + +void PcSpkDriver::startEffect(EffectEnvelope &env, const byte *data) { + env.state = 1; + env.currentLevel = 0; + env.modWheelLast = 31; + env.duration = data[0] * 63; + + env.stateTargetLevels[0] = data[1]; + env.stateTargetLevels[1] = data[3]; + env.stateTargetLevels[2] = data[5]; + env.stateTargetLevels[3] = data[6]; + + env.stateModWheelLevels[0] = data[2]; + env.stateModWheelLevels[1] = data[4]; + env.stateModWheelLevels[2] = 0; + env.stateModWheelLevels[3] = data[7]; + + initNextEnvelopeState(env); +} + +void PcSpkDriver::initNextEnvelopeState(EffectEnvelope &env) { + uint8 lastState = env.state - 1; + + uint16 stepCount = _effectEnvStepTable[getEffectModifier(((env.stateTargetLevels[lastState] & 0x7F) << 5) + env.modWheelSensitivity)]; + if (env.stateTargetLevels[lastState] & 0x80) + stepCount = getRandScale(stepCount); + if (!stepCount) + stepCount = 1; + + env.stateNumSteps = env.stateStepCounter = stepCount; + + int16 totalChange = 0; + if (lastState != 2) { + totalChange = getEffectModLevel(env.maxLevel, (env.stateModWheelLevels[lastState] & 0x7F) - 31); + if (env.stateModWheelLevels[lastState] & 0x80) + totalChange = getRandScale(totalChange); + + if (totalChange + env.startLevel > env.maxLevel) + totalChange = env.maxLevel - env.startLevel; + else if (totalChange + env.startLevel < 0) + totalChange = -env.startLevel; + + totalChange -= env.currentLevel; + } + + env.changePerStep = totalChange / stepCount; + if (totalChange < 0) { + totalChange = -totalChange; + env.dir = -1; + } else { + env.dir = 1; + } + env.changePerStepRem = totalChange % stepCount; + env.changeCountRem = 0; +} + +void PcSpkDriver::updateEffectGenerator(MidiChannel_PcSpk &chan, EffectEnvelope &env, EffectDefinition &def) { + if (advanceEffectEnvelope(env, def) & 1) { + switch (def.type) { + case 0: case 1: + chan._out.unk60 = def.phase << 4; + break; + + case 2: + chan._out.unkB = (def.phase & 0xFF) + chan._instrument[1]; + break; + + case 3: + chan._out.unkC = (def.phase & 0xFF) + chan._instrument[2]; + break; + + case 4: + if ((chan._instrument[4] + (def.phase & 0xFF)) * 256 < ARRAYSIZE(_outInstrumentData)) + chan._out.instrument = _outInstrumentData + (chan._instrument[4] + (def.phase & 0xFF)) * 256; + else + chan._out.instrument = 0; + break; + + case 5: + env.modWheelState = (def.phase & 0xFF); + break; + + case 6: + env.modWheelSensitivity = (def.phase & 0xFF); + break; + + default: + break; + } + } +} + +uint8 PcSpkDriver::advanceEffectEnvelope(EffectEnvelope &env, EffectDefinition &def) { + if (env.duration != 0) { + env.duration -= 17; + if (env.duration <= 0) { + env.state = 0; + return 0; + } + } + + uint8 changedFlags = 0; + int16 newLevel = env.currentLevel + env.changePerStep; + env.changeCountRem += env.changePerStepRem; + if (env.changeCountRem >= env.stateNumSteps) { + env.changeCountRem -= env.stateNumSteps; + newLevel += env.dir; + } + + if (env.currentLevel != newLevel || env.modWheelLast != env.modWheelState) { + env.currentLevel = newLevel; + env.modWheelLast = env.modWheelState; + + int16 newPhase = getEffectModLevel(newLevel, env.modWheelState); + if (def.phase != newPhase) { + changedFlags |= 1; + def.phase = newPhase; + } + } + + --env.stateStepCounter; + if (!env.stateStepCounter) { + ++env.state; + if (env.state > 4) { + if (env.loop) { + env.state = 1; + changedFlags |= 2; + } else { + env.state = 0; + return changedFlags; + } + } + + initNextEnvelopeState(env); + } + + return changedFlags; +} + +const byte PcSpkDriver::_outInstrumentData[1024] = { + 0x00, 0x03, 0x06, 0x09, 0x0C, 0x0F, 0x12, 0x15, + 0x18, 0x1B, 0x1E, 0x21, 0x24, 0x27, 0x2A, 0x2D, + 0x30, 0x33, 0x36, 0x39, 0x3B, 0x3E, 0x41, 0x43, + 0x46, 0x49, 0x4B, 0x4E, 0x50, 0x52, 0x55, 0x57, + 0x59, 0x5B, 0x5E, 0x60, 0x62, 0x64, 0x66, 0x67, + 0x69, 0x6B, 0x6C, 0x6E, 0x70, 0x71, 0x72, 0x74, + 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7B, + 0x7C, 0x7D, 0x7D, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, + 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7D, 0x7D, + 0x7C, 0x7B, 0x7B, 0x7A, 0x79, 0x78, 0x77, 0x76, + 0x75, 0x74, 0x72, 0x71, 0x70, 0x6E, 0x6C, 0x6B, + 0x69, 0x67, 0x66, 0x64, 0x62, 0x60, 0x5E, 0x5B, + 0x59, 0x57, 0x55, 0x52, 0x50, 0x4E, 0x4B, 0x49, + 0x46, 0x43, 0x41, 0x3E, 0x3B, 0x39, 0x36, 0x33, + 0x30, 0x2D, 0x2A, 0x27, 0x24, 0x21, 0x1E, 0x1B, + 0x18, 0x15, 0x12, 0x0F, 0x0C, 0x09, 0x06, 0x03, + 0x00, 0xFD, 0xFA, 0xF7, 0xF4, 0xF1, 0xEE, 0xEB, + 0xE8, 0xE5, 0xE2, 0xDF, 0xDC, 0xD9, 0xD6, 0xD3, + 0xD0, 0xCD, 0xCA, 0xC7, 0xC5, 0xC2, 0xBF, 0xBD, + 0xBA, 0xB7, 0xB5, 0xB2, 0xB0, 0xAE, 0xAB, 0xA9, + 0xA7, 0xA5, 0xA2, 0xA0, 0x9E, 0x9C, 0x9A, 0x99, + 0x97, 0x95, 0x94, 0x92, 0x90, 0x8F, 0x8E, 0x8C, + 0x8B, 0x8A, 0x89, 0x88, 0x87, 0x86, 0x85, 0x85, + 0x84, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x83, 0x83, + 0x84, 0x85, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, + 0x8B, 0x8C, 0x8E, 0x8F, 0x90, 0x92, 0x94, 0x95, + 0x97, 0x99, 0x9A, 0x9C, 0x9E, 0xA0, 0xA2, 0xA5, + 0xA7, 0xA9, 0xAB, 0xAE, 0xB0, 0xB2, 0xB5, 0xB7, + 0xBA, 0xBD, 0xBF, 0xC2, 0xC5, 0xC7, 0xCA, 0xCD, + 0xD0, 0xD3, 0xD6, 0xD9, 0xDC, 0xDF, 0xE2, 0xE5, + 0xE8, 0xEB, 0xEE, 0xF1, 0xF4, 0xF7, 0xFA, 0xFD, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, + 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, + 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, + 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0x29, 0x23, 0xBE, 0x84, 0xE1, 0x6C, 0xD6, 0xAE, + 0x52, 0x90, 0x49, 0xF1, 0xF1, 0xBB, 0xE9, 0xEB, + 0xB3, 0xA6, 0xDB, 0x3C, 0x87, 0x0C, 0x3E, 0x99, + 0x24, 0x5E, 0x0D, 0x1C, 0x06, 0xB7, 0x47, 0xDE, + 0xB3, 0x12, 0x4D, 0xC8, 0x43, 0xBB, 0x8B, 0xA6, + 0x1F, 0x03, 0x5A, 0x7D, 0x09, 0x38, 0x25, 0x1F, + 0x5D, 0xD4, 0xCB, 0xFC, 0x96, 0xF5, 0x45, 0x3B, + 0x13, 0x0D, 0x89, 0x0A, 0x1C, 0xDB, 0xAE, 0x32, + 0x20, 0x9A, 0x50, 0xEE, 0x40, 0x78, 0x36, 0xFD, + 0x12, 0x49, 0x32, 0xF6, 0x9E, 0x7D, 0x49, 0xDC, + 0xAD, 0x4F, 0x14, 0xF2, 0x44, 0x40, 0x66, 0xD0, + 0x6B, 0xC4, 0x30, 0xB7, 0x32, 0x3B, 0xA1, 0x22, + 0xF6, 0x22, 0x91, 0x9D, 0xE1, 0x8B, 0x1F, 0xDA, + 0xB0, 0xCA, 0x99, 0x02, 0xB9, 0x72, 0x9D, 0x49, + 0x2C, 0x80, 0x7E, 0xC5, 0x99, 0xD5, 0xE9, 0x80, + 0xB2, 0xEA, 0xC9, 0xCC, 0x53, 0xBF, 0x67, 0xD6, + 0xBF, 0x14, 0xD6, 0x7E, 0x2D, 0xDC, 0x8E, 0x66, + 0x83, 0xEF, 0x57, 0x49, 0x61, 0xFF, 0x69, 0x8F, + 0x61, 0xCD, 0xD1, 0x1E, 0x9D, 0x9C, 0x16, 0x72, + 0x72, 0xE6, 0x1D, 0xF0, 0x84, 0x4F, 0x4A, 0x77, + 0x02, 0xD7, 0xE8, 0x39, 0x2C, 0x53, 0xCB, 0xC9, + 0x12, 0x1E, 0x33, 0x74, 0x9E, 0x0C, 0xF4, 0xD5, + 0xD4, 0x9F, 0xD4, 0xA4, 0x59, 0x7E, 0x35, 0xCF, + 0x32, 0x22, 0xF4, 0xCC, 0xCF, 0xD3, 0x90, 0x2D, + 0x48, 0xD3, 0x8F, 0x75, 0xE6, 0xD9, 0x1D, 0x2A, + 0xE5, 0xC0, 0xF7, 0x2B, 0x78, 0x81, 0x87, 0x44, + 0x0E, 0x5F, 0x50, 0x00, 0xD4, 0x61, 0x8D, 0xBE, + 0x7B, 0x05, 0x15, 0x07, 0x3B, 0x33, 0x82, 0x1F, + 0x18, 0x70, 0x92, 0xDA, 0x64, 0x54, 0xCE, 0xB1, + 0x85, 0x3E, 0x69, 0x15, 0xF8, 0x46, 0x6A, 0x04, + 0x96, 0x73, 0x0E, 0xD9, 0x16, 0x2F, 0x67, 0x68, + 0xD4, 0xF7, 0x4A, 0x4A, 0xD0, 0x57, 0x68, 0x76 +}; + +const byte PcSpkDriver::_outputTable1[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7 +}; + +const byte PcSpkDriver::_outputTable2[] = { + 0, 1, 2, 3, + 4, 5, 6, 7, + 8, 9, 10, 11, + 0, 1, 2, 3, + 4, 5, 6, 7, + 8, 9, 10, 11, + 0, 1, 2, 3, + 4, 5, 6, 7, + 8, 9, 10, 11, + 0, 1, 2, 3, + 4, 5, 6, 7, + 8, 9, 10, 11, + 0, 1, 2, 3, + 4, 5, 6, 7, + 8, 9, 10, 11, + 0, 1, 2, 3, + 4, 5, 6, 7, + 8, 9, 10, 11, + 0, 1, 2, 3, + 4, 5, 6, 7, + 8, 9, 10, 11, + 0, 1, 2, 3, + 4, 5, 6, 7, + 8, 9, 10, 11, + 0, 1, 2, 3, + 4, 5, 6, 7, + 8, 9, 10, 11, + 0, 1, 2, 3, + 4, 5, 6, 7, + 8, 9, 10, 11, + 0, 1, 2, 3, + 4, 5, 6, 7 +}; + +const uint16 PcSpkDriver::_effectEnvStepTable[] = { + 1, 2, 4, 5, + 6, 7, 8, 9, + 10, 12, 14, 16, + 18, 21, 24, 30, + 36, 50, 64, 82, + 100, 136, 160, 192, + 240, 276, 340, 460, + 600, 860, 1200, 1600 +}; + +const uint16 PcSpkDriver::_frequencyTable[] = { + 0x8E84, 0x8E00, 0x8D7D, 0x8CFA, + 0x8C78, 0x8BF7, 0x8B76, 0x8AF5, + 0x8A75, 0x89F5, 0x8976, 0x88F7, + 0x8879, 0x87FB, 0x877D, 0x8700, + 0x8684, 0x8608, 0x858C, 0x8511, + 0x8496, 0x841C, 0x83A2, 0x8328, + 0x82AF, 0x8237, 0x81BF, 0x8147, + 0x80D0, 0x8059, 0x7FE3, 0x7F6D, + 0x7EF7, 0x7E82, 0x7E0D, 0x7D99, + 0x7D25, 0x7CB2, 0x7C3F, 0x7BCC, + 0x7B5A, 0x7AE8, 0x7A77, 0x7A06, + 0x7995, 0x7925, 0x78B5, 0x7846, + 0x77D7, 0x7768, 0x76FA, 0x768C, + 0x761F, 0x75B2, 0x7545, 0x74D9, + 0x746D, 0x7402, 0x7397, 0x732C, + 0x72C2, 0x7258, 0x71EF, 0x7186, + 0x711D, 0x70B5, 0x704D, 0x6FE5, + 0x6F7E, 0x6F17, 0x6EB0, 0x6E4A, + 0x6DE5, 0x6D7F, 0x6D1A, 0x6CB5, + 0x6C51, 0x6BED, 0x6B8A, 0x6B26, + 0x6AC4, 0x6A61, 0x69FF, 0x699D, + 0x693C, 0x68DB, 0x687A, 0x681A, + 0x67BA, 0x675A, 0x66FA, 0x669B, + 0x663D, 0x65DF, 0x6581, 0x6523, + 0x64C6, 0x6469, 0x640C, 0x63B0, + 0x6354, 0x62F8, 0x629D, 0x6242, + 0x61E7, 0x618D, 0x6133, 0x60D9, + 0x6080, 0x6027, 0x5FCE, 0x5F76, + 0x5F1E, 0x5EC6, 0x5E6E, 0x5E17, + 0x5DC1, 0x5D6A, 0x5D14, 0x5CBE, + 0x5C68, 0x5C13, 0x5BBE, 0x5B6A, + 0x5B15, 0x5AC1, 0x5A6E, 0x5A1A, + 0x59C7, 0x5974, 0x5922, 0x58CF, + 0x587D, 0x582C, 0x57DA, 0x5789, + 0x5739, 0x56E8, 0x5698, 0x5648, + 0x55F9, 0x55A9, 0x555A, 0x550B, + 0x54BD, 0x546F, 0x5421, 0x53D3, + 0x5386, 0x5339, 0x52EC, 0x52A0, + 0x5253, 0x5207, 0x51BC, 0x5170, + 0x5125, 0x50DA, 0x5090, 0x5046, + 0x4FFB, 0x4FB2, 0x4F68, 0x4F1F, + 0x4ED6, 0x4E8D, 0x4E45, 0x4DFC, + 0x4DB5, 0x4D6D, 0x4D25, 0x4CDE, + 0x4C97, 0x4C51, 0x4C0A, 0x4BC4, + 0x4B7E, 0x4B39, 0x4AF3, 0x4AAE, + 0x4A69, 0x4A24, 0x49E0, 0x499C, + 0x4958, 0x4914, 0x48D1, 0x488E, + 0x484B, 0x4808, 0x47C6, 0x4783 +}; + +} // End of namespace Scumm diff --git a/engines/scumm/imuse/pcspk.h b/engines/scumm/imuse/pcspk.h new file mode 100644 index 0000000000..195bd34b07 --- /dev/null +++ b/engines/scumm/imuse/pcspk.h @@ -0,0 +1,160 @@ +/* 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 SCUMM_IMUSE_PCSPK_H +#define SCUMM_IMUSE_PCSPK_H + +#include "audio/softsynth/emumidi.h" +#include "audio/softsynth/pcspk.h" + +namespace Scumm { + +class PcSpkDriver : public MidiDriver_Emulated { +public: + PcSpkDriver(Audio::Mixer *mixer); + ~PcSpkDriver(); + + virtual int open(); + virtual void close(); + + virtual void send(uint32 d); + virtual void sysEx_customInstrument(byte channel, uint32 type, const byte *instr); + + virtual MidiChannel *allocateChannel(); + virtual MidiChannel *getPercussionChannel() { return 0; } + + bool isStereo() const { return _pcSpk.isStereo(); } + int getRate() const { return _pcSpk.getRate(); } +protected: + void generateSamples(int16 *buf, int len); + void onTimer(); + +private: + Audio::PCSpeaker _pcSpk; + int _effectTimer; + uint8 _randBase; + + void updateNote(); + void output(uint16 out); + + static uint8 getEffectModifier(uint16 level); + int16 getEffectModLevel(int16 level, int8 mod); + int16 getRandScale(int16 input); + + struct EffectEnvelope { + uint8 state; + int16 currentLevel; + int16 duration; + int16 maxLevel; + int16 startLevel; + uint8 loop; + uint8 stateTargetLevels[4]; + uint8 stateModWheelLevels[4]; + uint8 modWheelSensitivity; + uint8 modWheelState; + uint8 modWheelLast; + int16 stateNumSteps; + int16 stateStepCounter; + int16 changePerStep; + int8 dir; + int16 changePerStepRem; + int16 changeCountRem; + }; + + struct EffectDefinition { + int16 phase; + uint8 type; + uint8 useModWheel; + EffectEnvelope *envelope; + }; + + struct OutputChannel { + uint8 active; + uint8 note; + uint8 sustainNoteOff; + uint8 length; + const uint8 *instrument; + uint8 unkA; + uint8 unkB; + uint8 unkC; + int16 unkE; + EffectEnvelope effectEnvelopeA; + EffectDefinition effectDefA; + EffectEnvelope effectEnvelopeB; + EffectDefinition effectDefB; + int16 unk60; + }; + + struct MidiChannel_PcSpk : public MidiChannel { + virtual MidiDriver *device(); + virtual byte getNumber(); + virtual void release(); + + virtual void send(uint32 b); + virtual void noteOff(byte note); + virtual void noteOn(byte note, byte velocity); + virtual void programChange(byte program); + virtual void pitchBend(int16 bend); + virtual void controlChange(byte control, byte value); + virtual void pitchBendFactor(byte value); + virtual void priority(byte value); + virtual void sysEx_customInstrument(uint32 type, const byte *instr); + + void init(PcSpkDriver *owner, byte channel); + bool allocate(); + + PcSpkDriver *_owner; + bool _allocated; + byte _channel; + + OutputChannel _out; + uint8 _instrument[23]; + uint8 _programNr; + uint8 _priority; + uint8 _tl; + uint8 _modWheel; + uint8 _sustain; + uint8 _pitchBendFactor; + int16 _pitchBend; + }; + + void setupEffects(MidiChannel_PcSpk &chan, EffectEnvelope &env, EffectDefinition &def, byte flags, const byte *data); + void startEffect(EffectEnvelope &env, const byte *data); + void initNextEnvelopeState(EffectEnvelope &env); + void updateEffectGenerator(MidiChannel_PcSpk &chan, EffectEnvelope &env, EffectDefinition &def); + uint8 advanceEffectEnvelope(EffectEnvelope &env, EffectDefinition &def); + + MidiChannel_PcSpk _channels[6]; + MidiChannel_PcSpk *_activeChannel; + + MidiChannel_PcSpk *_lastActiveChannel; + uint16 _lastActiveOut; + + static const byte _outInstrumentData[1024]; + static const byte _outputTable1[]; + static const byte _outputTable2[]; + static const uint16 _effectEnvStepTable[]; + static const uint16 _frequencyTable[]; +}; + +} // End of namespace Scumm + +#endif diff --git a/engines/scumm/imuse/sysex.h b/engines/scumm/imuse/sysex.h index 7dd38e785e..06ac483afd 100644 --- a/engines/scumm/imuse/sysex.h +++ b/engines/scumm/imuse/sysex.h @@ -35,4 +35,3 @@ extern void sysexHandler_SamNMax(Player *, const byte *, uint16); } // End of namespace Scumm #endif - diff --git a/engines/scumm/imuse/sysex_samnmax.cpp b/engines/scumm/imuse/sysex_samnmax.cpp index 4c4219e7bb..a4f525da56 100644 --- a/engines/scumm/imuse/sysex_samnmax.cpp +++ b/engines/scumm/imuse/sysex_samnmax.cpp @@ -53,8 +53,7 @@ void sysexHandler_SamNMax(Player *player, const byte *msg, uint16 len) { // something magical is supposed to happen.... for (a = 0; a < ARRAYSIZE(se->_snm_triggers); ++a) { if (se->_snm_triggers[a].sound == player->_id && - se->_snm_triggers[a].id == *p) - { + se->_snm_triggers[a].id == *p) { se->_snm_triggers[a].sound = se->_snm_triggers[a].id = 0; se->doCommand(8, se->_snm_triggers[a].command); break; diff --git a/engines/scumm/imuse/sysex_scumm.cpp b/engines/scumm/imuse/sysex_scumm.cpp index c3bec93a60..85ffc86f47 100644 --- a/engines/scumm/imuse/sysex_scumm.cpp +++ b/engines/scumm/imuse/sysex_scumm.cpp @@ -49,50 +49,52 @@ void sysexHandler_Scumm(Player *player, const byte *msg, uint16 len) { switch (code = *p++) { case 0: // Allocate new part. - // There are 17 bytes of useful information here. + // There are 8 bytes (after decoding!) of useful information here. // Here is what we know about them so far: - // BYTE 00: Channel # - // BYTE 02: BIT 01(0x01): Part on?(1 = yes) + // BYTE 0: Channel # + // BYTE 1: BIT 01(0x01): Part on?(1 = yes) // BIT 02(0x02): Reverb? (1 = yes) [bug #1088045] - // BYTE 04: Priority adjustment [guessing] - // BYTE 05: Volume(upper 4 bits) [guessing] - // BYTE 06: Volume(lower 4 bits) [guessing] - // BYTE 07: Pan(upper 4 bits) [bug #1088045] - // BYTE 08: Pan(lower 4 bits) [bug #1088045] - // BYTE 09: BIT 04(0x08): Percussion?(1 = yes) - // BYTE 13: Pitchbend range(upper 4 bits) [bug #1088045] - // BYTE 14: Pitchbend range(lower 4 bits) [bug #1088045] - // BYTE 15: Program(upper 4 bits) - // BYTE 16: Program(lower 4 bits) - - // athrxx (05-21-2011): - // BYTE 9, 10: Transpose (if set to 0x80, this means that part->_transpose_eff will be 0 (also ignoring player->_transpose) - // BYTE 11, 12: Detune + // BYTE 2: Priority adjustment + // BYTE 3: Volume [guessing] + // BYTE 4: Pan [bug #1088045] + // BYTE 5: BIT 8(0x80): Percussion?(1 = yes) [guessed?] + // BYTE 5: Transpose, if set to 0x80(=-1) it means no transpose + // BYTE 6: Detune + // BYTE 7: Pitchbend factor [bug #1088045] + // BYTE 8: Program part = player->getPart(p[0] & 0x0F); + player->decode_sysex_bytes(p + 1, buf + 1, len - 1); if (part) { - part->set_onoff(p[2] & 0x01); - part->effectLevel((p[2] & 0x02) ? 127 : 0); - part->set_pri(p[4]); - part->volume((p[5] & 0x0F) << 4 |(p[6] & 0x0F)); - part->set_pan((p[7] & 0x0F) << 4 | (p[8] & 0x0F)); - part->_percussion = player->_isMIDI ? ((p[9] & 0x08) > 0) : false; - part->set_transpose((p[9] & 0x0F) << 4 | (p[10] & 0x0F)); - part->set_detune((p[11] & 0x0F) << 4 | (p[12] & 0x0F)); - part->pitchBendFactor((p[13] & 0x0F) << 4 | (p[14] & 0x0F)); + part->set_onoff(buf[1] & 0x01); + part->effectLevel((buf[1] & 0x02) ? 127 : 0); + part->set_pri(buf[2]); + part->volume(buf[3]); + part->set_pan(buf[4]); + part->_percussion = player->_isMIDI ? ((buf[5] & 0x80) > 0) : false; + part->set_transpose(buf[5]); + part->set_detune(buf[6]); + part->pitchBendFactor(buf[7]); if (part->_percussion) { if (part->_mc) { part->off(); se->reallocateMidiChannels(player->_midi); } } else { - // Even in cases where a program does not seem to be specified, - // i.e. bytes 15 and 16 are 0, we send a program change because - // 0 is a valid program number. MI2 tests show that in such - // cases, a regular program change message always seems to follow - // anyway. - if (player->_isMIDI) - part->_instrument.program((p[15] & 0x0F) << 4 |(p[16] & 0x0F), player->_isMT32); + if (player->_isMIDI) { + // Even in cases where a program does not seem to be specified, + // i.e. bytes 15 and 16 are 0, we send a program change because + // 0 is a valid program number. MI2 tests show that in such + // cases, a regular program change message always seems to follow + // anyway. + part->_instrument.program(buf[8], player->_isMT32); + } else { + // Like the original we set up the instrument data of the + // specified program here too. In case the global + // instrument data is not loaded already, this will take + // care of setting a default instrument too. + se->copyGlobalInstrument(buf[8], &part->_instrument); + } part->sendAll(); } } @@ -113,11 +115,10 @@ void sysexHandler_Scumm(Player *player, const byte *msg, uint16 len) { ++p; // Skip hardware type part = player->getPart(a); if (part) { - if (len == 62) { + if (len == 62 || len == 48) { player->decode_sysex_bytes(p, buf, len - 2); part->set_instrument((byte *)buf); } else { - // SPK tracks have len == 48 here, and are not supported part->programChange(254); // Must be invalid, but not 255 (which is reserved) } } @@ -127,7 +128,8 @@ void sysexHandler_Scumm(Player *player, const byte *msg, uint16 len) { p += 2; // Skip hardware type and... whatever came right before it a = *p++; player->decode_sysex_bytes(p, buf, len - 3); - se->setGlobalAdLibInstrument(a, buf); + if (len == 63 || len == 49) + se->setGlobalInstrument(a, buf); break; case 33: // Parameter adjust @@ -185,10 +187,9 @@ void sysexHandler_Scumm(Player *player, const byte *msg, uint16 len) { case 80: // Loop player->decode_sysex_bytes(p + 1, buf, len - 1); - player->setLoop - (READ_BE_UINT16(buf), READ_BE_UINT16(buf + 2), - READ_BE_UINT16(buf + 4), READ_BE_UINT16(buf + 6), - READ_BE_UINT16(buf + 8)); + player->setLoop(READ_BE_UINT16(buf), READ_BE_UINT16(buf + 2), + READ_BE_UINT16(buf + 4), READ_BE_UINT16(buf + 6), + READ_BE_UINT16(buf + 8)); break; case 81: // End loop diff --git a/engines/scumm/imuse_digi/dimuse.cpp b/engines/scumm/imuse_digi/dimuse.cpp index 23f57a01b9..eb3717494f 100644 --- a/engines/scumm/imuse_digi/dimuse.cpp +++ b/engines/scumm/imuse_digi/dimuse.cpp @@ -58,7 +58,7 @@ IMuseDigital::IMuseDigital(ScummEngine_v7 *scumm, Audio::Mixer *mixer, int fps) memset(_track[l], 0, sizeof(Track)); _track[l]->trackId = l; } - _vm->getTimerManager()->installTimerProc(timer_handler, 1000000 / _callbackFps, this); + _vm->getTimerManager()->installTimerProc(timer_handler, 1000000 / _callbackFps, this, "IMuseDigital"); _audioNames = NULL; _numAudioNames = 0; diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp index 5eea7acc6b..6d9e1f3f72 100644 --- a/engines/scumm/input.cpp +++ b/engines/scumm/input.cpp @@ -324,7 +324,17 @@ void ScummEngine::processInput() { VAR(VAR_LEFTBTN_HOLD) = (_leftBtnPressed & msDown) != 0; VAR(VAR_RIGHTBTN_HOLD) = (_rightBtnPressed & msDown) != 0; - if (_game.version >= 7) { + if (_game.heversion >= 72) { + // HE72 introduced a flag for whether or not this is a click + // or the player is continuing to hold the button down. + // 0x80 signifies that the button is continuing to be held down + // Backyard Soccer needs this in order to function + if (VAR(VAR_LEFTBTN_HOLD) && !(_leftBtnPressed & msClicked)) + VAR(VAR_LEFTBTN_HOLD) |= 0x80; + + if (VAR(VAR_RIGHTBTN_HOLD) && !(_rightBtnPressed & msClicked)) + VAR(VAR_RIGHTBTN_HOLD) |= 0x80; + } else if (_game.version >= 7) { VAR(VAR_LEFTBTN_DOWN) = (_leftBtnPressed & msClicked) != 0; VAR(VAR_RIGHTBTN_DOWN) = (_rightBtnPressed & msClicked) != 0; } diff --git a/engines/scumm/insane/insane_enemy.cpp b/engines/scumm/insane/insane_enemy.cpp index 68766ab72c..913f761f31 100644 --- a/engines/scumm/insane/insane_enemy.cpp +++ b/engines/scumm/insane/insane_enemy.cpp @@ -2779,4 +2779,3 @@ int32 Insane::actionEnemy() { } } - diff --git a/engines/scumm/insane/insane_iact.cpp b/engines/scumm/insane/insane_iact.cpp index 3592d67c18..48c96b537c 100644 --- a/engines/scumm/insane/insane_iact.cpp +++ b/engines/scumm/insane/insane_iact.cpp @@ -520,4 +520,3 @@ void Insane::iactScene21(byte *renderBitmap, int32 codecparam, int32 setupsan12, } } - diff --git a/engines/scumm/insane/insane_scenes.cpp b/engines/scumm/insane/insane_scenes.cpp index 841fedafe2..6db1cb5059 100644 --- a/engines/scumm/insane/insane_scenes.cpp +++ b/engines/scumm/insane/insane_scenes.cpp @@ -1506,4 +1506,3 @@ void Insane::postCaseMore(byte *renderBitmap, int32 codecparam, int32 setupsan12 } } - diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk index 1a60564a9e..781ca30459 100644 --- a/engines/scumm/module.mk +++ b/engines/scumm/module.mk @@ -27,6 +27,7 @@ MODULE_OBJS := \ imuse/imuse_part.o \ imuse/imuse_player.o \ imuse/instrument.o \ + imuse/pcspk.o \ imuse/sysex_samnmax.o \ imuse/sysex_scumm.o \ input.o \ @@ -123,7 +124,14 @@ MODULE_OBJS += \ he/script_v90he.o \ he/script_v100he.o \ he/sprite_he.o \ - he/wiz_he.o + he/wiz_he.o \ + he/logic/baseball2001.o \ + he/logic/basketball.o \ + he/logic/football.o \ + he/logic/funshop.o \ + he/logic/moonbase.o \ + he/logic/puttrace.o \ + he/logic/soccer.o endif # This module can be built as a plugin diff --git a/engines/scumm/palette.cpp b/engines/scumm/palette.cpp index 51ba2195d7..30096000ce 100644 --- a/engines/scumm/palette.cpp +++ b/engines/scumm/palette.cpp @@ -544,6 +544,12 @@ void ScummEngine::palManipulateInit(int resID, int start, int end, int time) { return; #endif + // This function is actually a nullsub in Indy4 Amiga. + // It might very well be a nullsub in other Amiga games, but for now I + // limit this to Indy4 Amiga, since that is the only game I can check. + if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) + return; + byte *string1 = getStringAddress(resID); byte *string2 = getStringAddress(resID + 1); byte *string3 = getStringAddress(resID + 2); @@ -670,6 +676,12 @@ static inline uint colorWeight(int red, int green, int blue) { } void ScummEngine::setShadowPalette(int redScale, int greenScale, int blueScale, int startColor, int endColor, int start, int end) { + // This function is actually a nullsub in Indy4 Amiga. + // It might very well be a nullsub in other Amiga games, but for now I + // limit this to Indy4 Amiga, since that is the only game I can check. + if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) + return; + const byte *basepal = getPalettePtr(_curPalIndex, _roomResource); const byte *compareptr; const byte *pal = basepal + start * 3; diff --git a/engines/scumm/player_v2.h b/engines/scumm/player_v2.h index 14a0b9c1e0..d932585b8e 100644 --- a/engines/scumm/player_v2.h +++ b/engines/scumm/player_v2.h @@ -46,10 +46,7 @@ public: virtual int getSoundStatus(int sound) const; // AudioStream API - int readBuffer(int16 *buffer, const int numSamples); - bool isStereo() const { return true; } - bool endOfData() const { return false; } - int getRate() const { return _sampleRate; } + virtual int readBuffer(int16 *buffer, const int numSamples); protected: unsigned int _update_step; diff --git a/engines/scumm/player_v2base.h b/engines/scumm/player_v2base.h index 2f048070ad..eb9ed941ca 100644 --- a/engines/scumm/player_v2base.h +++ b/engines/scumm/player_v2base.h @@ -86,9 +86,9 @@ public: return numSamples; } */ - bool isStereo() const { return true; } - bool endOfData() const { return false; } - int getRate() const { return _sampleRate; } + virtual bool isStereo() const { return true; } + virtual bool endOfData() const { return false; } + virtual int getRate() const { return _sampleRate; } protected: enum { diff --git a/engines/scumm/player_v2cms.cpp b/engines/scumm/player_v2cms.cpp index 21e7f193b5..d4b21774ed 100644 --- a/engines/scumm/player_v2cms.cpp +++ b/engines/scumm/player_v2cms.cpp @@ -28,162 +28,49 @@ namespace Scumm { -#define PROCESS_ATTACK 1 -#define PROCESS_RELEASE 2 -#define PROCESS_SUSTAIN 3 -#define PROCESS_DECAY 4 -#define PROCESS_VIBRATO 5 - -#define CMS_RATE 22050 - -static const byte freqTable[] = { - 3, 10, 17, 24, 31, 38, 45, 51, - 58, 65, 71, 77, 83, 90, 96, 102, - 107, 113, 119, 125, 130, 136, 141, 146, - 151, 157, 162, 167, 172, 177, 181, 186, - 191, 195, 200, 204, 209, 213, 217, 221, - 226, 230, 234, 238, 242, 246, 249, 253 -}; - -/*static const byte amplTable[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0 % - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 10 % - 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, // 20 % - 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x20, // 30% - 0x20, 0x20, 0x30, 0x30, 0x30, 0x30, 0x40, 0x40, - 0x00, 0x00, 0x00, 0x10, 0x10, 0x20, 0x20, 0x20, // 40 % - 0x30, 0x30, 0x40, 0x40, 0x40, 0x50, 0x50, 0x60, - 0x00, 0x00, 0x10, 0x10, 0x20, 0x20, 0x30, 0x30, // 50% - 0x40, 0x40, 0x50, 0x50, 0x60, 0x60, 0x70, 0x70, - 0x00, 0x00, 0x10, 0x10, 0x20, 0x30, 0x30, 0x40, // 60 % - 0x40, 0x50, 0x60, 0x60, 0x70, 0x70, 0x80, 0x90, - 0x00, 0x00, 0x10, 0x20, 0x20, 0x30, 0x40, 0x40, // 70 % - 0x50, 0x60, 0x70, 0x70, 0x80, 0x90, 0x90, 0xA0, - 0x00, 0x00, 0x10, 0x20, 0x30, 0x40, 0x40, 0x50, // 80 % - 0x60, 0x70, 0x80, 0x80, 0x90, 0xA0, 0xB0, 0xC0, - 0x00, 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, // 90 % - 0x70, 0x80, 0x90, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, - 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, // 100 % - 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0 -};*/ - -static const byte octaveTable[] = { - 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, - 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, - 0x00, 0x08, 0x00, 0x09, 0x00, 0x0A, 0x00, 0x0B, - 0x01, 0x00, 0x01, 0x01, 0x01, 0x02, 0x01, 0x03, - 0x01, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x07, - 0x01, 0x08, 0x01, 0x09, 0x01, 0x0A, 0x01, 0x0B, - 0x02, 0x00, 0x02, 0x01, 0x02, 0x02, 0x02, 0x03, - 0x02, 0x04, 0x02, 0x05, 0x02, 0x06, 0x02, 0x07, - 0x02, 0x08, 0x02, 0x09, 0x02, 0x0A, 0x02, 0x0B, - 0x03, 0x00, 0x03, 0x01, 0x03, 0x02, 0x03, 0x03, - 0x03, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x07, - 0x03, 0x08, 0x03, 0x09, 0x03, 0x0A, 0x03, 0x0B, - 0x04, 0x00, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, - 0x04, 0x04, 0x04, 0x05, 0x04, 0x06, 0x04, 0x07, - 0x04, 0x08, 0x04, 0x09, 0x04, 0x0A, 0x04, 0x0B, - 0x05, 0x00, 0x05, 0x01, 0x05, 0x02, 0x05, 0x03, - 0x05, 0x04, 0x05, 0x05, 0x05, 0x06, 0x05, 0x07, - 0x05, 0x08, 0x05, 0x09, 0x05, 0x0A, 0x05, 0x0B, - 0x06, 0x00, 0x06, 0x01, 0x06, 0x02, 0x06, 0x03, - 0x06, 0x04, 0x06, 0x05, 0x06, 0x06, 0x06, 0x07, - 0x06, 0x08, 0x06, 0x09, 0x06, 0x0A, 0x06, 0x0B, - 0x07, 0x00, 0x07, 0x01, 0x07, 0x02, 0x07, 0x03, - 0x07, 0x04, 0x07, 0x05, 0x07, 0x06, 0x07, 0x07, - 0x07, 0x08, 0x07, 0x09, 0x07, 0x0A, 0x07, 0x0B, - 0x08, 0x00, 0x08, 0x01, 0x08, 0x02, 0x08, 0x03, - 0x08, 0x04, 0x08, 0x05, 0x08, 0x06, 0x08, 0x07, - 0x08, 0x08, 0x08, 0x09, 0x08, 0x0A, 0x08, 0x0B, - 0x09, 0x00, 0x09, 0x01, 0x09, 0x02, 0x09, 0x03, - 0x09, 0x04, 0x09, 0x05, 0x09, 0x06, 0x09, 0x07, - 0x09, 0x08, 0x09, 0x09, 0x09, 0x0A, 0x09, 0x0B, - 0x0A, 0x00, 0x0A, 0x01, 0x0A, 0x02, 0x0A, 0x03, - 0x0A, 0x04, 0x0A, 0x05, 0x0A, 0x06, 0x0A, 0x07, - 0x0A, 0x08, 0x0A, 0x09, 0x0A, 0x0A, 0x0A, 0x0B -}; - -static const byte attackRate[] = { - 0, 2, 4, 7, 14, 26, 48, 82, - 128, 144, 160, 176, 192, 208, 224, 255 -}; - -static const byte decayRate[] = { - 0, 1, 2, 3, 4, 6, 12, 24, - 48, 96, 192, 215, 255, 255, 255, 255 -}; - -static const byte sustainRate[] = { - 255, 180, 128, 96, 80, 64, 56, 48, - 42, 36, 32, 28, 24, 20, 16, 0 -}; - -static const byte releaseRate[] = { - 0, 1, 2, 4, 6, 9, 14, 22, - 36, 56, 80, 100, 120, 140, 160, 255 -}; - -static const byte volumeTable[] = { - 0x00, 0x10, 0x10, 0x11, 0x11, 0x21, 0x22, 0x22, - 0x33, 0x44, 0x55, 0x66, 0x88, 0xAA, 0xCC, 0xFF -}; - Player_V2CMS::Player_V2CMS(ScummEngine *scumm, Audio::Mixer *mixer) - : Player_V2Base(scumm, mixer, true) { - int i; - + : Player_V2Base(scumm, mixer, true), _cmsVoicesBase(), _cmsVoices(), + _cmsChips(), _midiDelay(0), _octaveMask(0), _looping(0), _tempo(0), + _tempoSum(0), _midiData(0), _midiSongBegin(0), _musicTimer(0), + _musicTimerTicks(0), _voiceTimer(0), _loadedMidiSong(0), + _outputTableReady(0), _midiChannel(), _midiChannelUse() { setMusicVolume(255); - memset(_cmsVoicesBase, 0, sizeof(Voice)*16); - memset(_cmsVoices, 0, sizeof(Voice2)*8); - memset(_cmsChips, 0, sizeof(MusicChip)*2); - _midiDelay = _octaveMask = _looping = _tempo = 0; - _midiData = _midiSongBegin = 0; - _loadedMidiSong = 0; - memset(_midiChannel, 0, sizeof(Voice2*)*16); - memset(_midiChannelUse, 0, sizeof(byte)*16); - - _cmsVoices[0].amplitudeOutput = &(_cmsChips[0].ampl[0]); - _cmsVoices[0].freqOutput = &(_cmsChips[0].freq[0]); - _cmsVoices[0].octaveOutput = &(_cmsChips[0].octave[0]); - _cmsVoices[1].amplitudeOutput = &(_cmsChips[0].ampl[1]); - _cmsVoices[1].freqOutput = &(_cmsChips[0].freq[1]); - _cmsVoices[1].octaveOutput = &(_cmsChips[0].octave[0]); - _cmsVoices[2].amplitudeOutput = &(_cmsChips[0].ampl[2]); - _cmsVoices[2].freqOutput = &(_cmsChips[0].freq[2]); - _cmsVoices[2].octaveOutput = &(_cmsChips[0].octave[1]); - _cmsVoices[3].amplitudeOutput = &(_cmsChips[0].ampl[3]); - _cmsVoices[3].freqOutput = &(_cmsChips[0].freq[3]); - _cmsVoices[3].octaveOutput = &(_cmsChips[0].octave[1]); - _cmsVoices[4].amplitudeOutput = &(_cmsChips[1].ampl[0]); - _cmsVoices[4].freqOutput = &(_cmsChips[1].freq[0]); - _cmsVoices[4].octaveOutput = &(_cmsChips[1].octave[0]); - _cmsVoices[5].amplitudeOutput = &(_cmsChips[1].ampl[1]); - _cmsVoices[5].freqOutput = &(_cmsChips[1].freq[1]); - _cmsVoices[5].octaveOutput = &(_cmsChips[1].octave[0]); - _cmsVoices[6].amplitudeOutput = &(_cmsChips[1].ampl[2]); - _cmsVoices[6].freqOutput = &(_cmsChips[1].freq[2]); - _cmsVoices[6].octaveOutput = &(_cmsChips[1].octave[1]); - _cmsVoices[7].amplitudeOutput = &(_cmsChips[1].ampl[3]); - _cmsVoices[7].freqOutput = &(_cmsChips[1].freq[3]); - _cmsVoices[7].octaveOutput = &(_cmsChips[1].octave[1]); + 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]; + _cmsVoices[1].amplitudeOutput = &_cmsChips[0].ampl[1]; + _cmsVoices[1].freqOutput = &_cmsChips[0].freq[1]; + _cmsVoices[1].octaveOutput = &_cmsChips[0].octave[0]; + _cmsVoices[2].amplitudeOutput = &_cmsChips[0].ampl[2]; + _cmsVoices[2].freqOutput = &_cmsChips[0].freq[2]; + _cmsVoices[2].octaveOutput = &_cmsChips[0].octave[1]; + _cmsVoices[3].amplitudeOutput = &_cmsChips[0].ampl[3]; + _cmsVoices[3].freqOutput = &_cmsChips[0].freq[3]; + _cmsVoices[3].octaveOutput = &_cmsChips[0].octave[1]; + _cmsVoices[4].amplitudeOutput = &_cmsChips[1].ampl[0]; + _cmsVoices[4].freqOutput = &_cmsChips[1].freq[0]; + _cmsVoices[4].octaveOutput = &_cmsChips[1].octave[0]; + _cmsVoices[5].amplitudeOutput = &_cmsChips[1].ampl[1]; + _cmsVoices[5].freqOutput = &_cmsChips[1].freq[1]; + _cmsVoices[5].octaveOutput = &_cmsChips[1].octave[0]; + _cmsVoices[6].amplitudeOutput = &_cmsChips[1].ampl[2]; + _cmsVoices[6].freqOutput = &_cmsChips[1].freq[2]; + _cmsVoices[6].octaveOutput = &_cmsChips[1].octave[1]; + _cmsVoices[7].amplitudeOutput = &_cmsChips[1].ampl[3]; + _cmsVoices[7].freqOutput = &_cmsChips[1].freq[3]; + _cmsVoices[7].octaveOutput = &_cmsChips[1].octave[1]; // inits the CMS Emulator like in the original _cmsEmu = new CMSEmulator(_sampleRate); - static const byte cmsInitData[13*2] = { - 0x1C, 0x02, - 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, - 0x14, 0x3F, 0x15, 0x00, 0x16, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1C, 0x01 - }; - - i = 0; - for (int cmsPort = 0x220; i < 2; cmsPort += 2, ++i) { + for (int i = 0, cmsPort = 0x220; i < 2; cmsPort += 2, ++i) { for (int off = 0; off < 13; ++off) { - _cmsEmu->portWrite(cmsPort+1, cmsInitData[off*2]); - _cmsEmu->portWrite(cmsPort, cmsInitData[off*2+1]); + _cmsEmu->portWrite(cmsPort+1, _cmsInitData[off*2]); + _cmsEmu->portWrite(cmsPort, _cmsInitData[off*2+1]); } } @@ -200,6 +87,10 @@ Player_V2CMS::~Player_V2CMS() { void Player_V2CMS::setMusicVolume(int vol) { } +int Player_V2CMS::getMusicTimer() { + return _midiData ? _musicTimer : Player_V2Base::getMusicTimer(); +} + void Player_V2CMS::stopAllSounds() { Common::StackLock lock(_mutex); @@ -211,6 +102,7 @@ void Player_V2CMS::stopAllSounds() { _midiData = 0; _midiSongBegin = 0; _midiDelay = 0; + _musicTimer = _musicTimerTicks = 0; offAllChannels(); } @@ -244,6 +136,7 @@ void Player_V2CMS::startSound(int nr) { assert(data); if (data[6] == 0x80) { + _musicTimer = _musicTimerTicks = 0; loadMidiData(data, nr); } else { int cprio = _current_data ? *(_current_data + _header_len) : 0; @@ -282,7 +175,8 @@ void Player_V2CMS::startSound(int nr) { } void Player_V2CMS::loadMidiData(byte *data, int sound) { - memset(_midiChannelUse, 0, sizeof(byte)*16); + memset(_midiChannelUse, 0, sizeof(_midiChannelUse)); + memset(_midiChannel, 0, sizeof(_midiChannel)); _tempo = data[7]; _looping = data[8]; @@ -299,11 +193,11 @@ void Player_V2CMS::loadMidiData(byte *data, int sound) { Voice *voiceDef = &_cmsVoicesBase[channel]; byte attackDecay = voice2[10]; - voiceDef->attack = attackRate[attackDecay >> 4]; - voiceDef->decay = decayRate[attackDecay & 0x0F]; + voiceDef->attack = _attackRate[attackDecay >> 4]; + voiceDef->decay = _decayRate[attackDecay & 0x0F]; byte sustainRelease = voice2[11]; - voiceDef->sustain = sustainRate[sustainRelease >> 4]; - voiceDef->release = releaseRate[sustainRelease & 0x0F]; + voiceDef->sustain = _sustainRate[sustainRelease >> 4]; + voiceDef->release = _releaseRate[sustainRelease & 0x0F]; if (voice2[3] & 0x40) { voiceDef->vibrato = 0x0301; @@ -331,12 +225,10 @@ void Player_V2CMS::loadMidiData(byte *data, int sound) { } } - for (int i = 0, channel = 0; i < 8; ++i, channel += 2) { + for (int i = 0; i < 8; ++i) { _cmsVoices[i].chanNumber = 0xFF; _cmsVoices[i].curVolume = 0; _cmsVoices[i].nextVoice = 0; - - _midiChannel[channel] = 0; } _midiDelay = 0; @@ -351,11 +243,17 @@ int Player_V2CMS::getSoundStatus(int nr) const { return _current_nr == nr || _next_nr == nr || _loadedMidiSong == nr; } -void Player_V2CMS::processMidiData(uint ticks) { +void Player_V2CMS::processMidiData() { byte *currentData = _midiData; byte command = 0x00; int16 temp = 0; + ++_musicTimerTicks; + if (_musicTimerTicks > 60) { + _musicTimerTicks = 0; + ++_musicTimer; + } + if (!_midiDelay) { while (true) { if ((command = *currentData++) == 0xFF) { @@ -365,6 +263,8 @@ void Player_V2CMS::processMidiData(uint ticks) { continue; } _midiData = _midiSongBegin = 0; + _midiDelay = 0; + _loadedMidiSong = 0; offAllChannels(); return; } else { @@ -400,7 +300,7 @@ void Player_V2CMS::processMidiData(uint ticks) { _midiDelay = temp; } - _midiDelay -= ticks; + --_midiDelay; if (_midiDelay < 0) _midiDelay = 0; @@ -415,27 +315,21 @@ int Player_V2CMS::readBuffer(int16 *buffer, const int numSamples) { // maybe this needs a complete rewrite do { - if (_midiData) { - --_clkFrequenz; - if (!(_clkFrequenz & 0x01)) { - playVoice(); - } - - _tempoSum += _tempo; - // FIXME: _tempoSum is declared as char; on some systems char is unsigned. - // E.g. on OS X. Hence the following check is always false. - // Moral of the story: Use uint8, int8 or any of the other types provided by - // ScummVM if you want to ensure signedness and number of available bits. - if (_tempoSum < 0) { - // this have to be called in the same rate as in the original (I think) - processMidiData(1); + if (!(_next_tick >> FIXP_SHIFT)) { + if (_midiData) { + --_voiceTimer; + if (!(_voiceTimer & 0x01)) + playVoice(); + + int newTempoSum = _tempo + _tempoSum; + _tempoSum = newTempoSum & 0xFF; + if (newTempoSum > 0xFF) + processMidiData(); + } else { + nextTick(); + play(); } - } - - if (!(_next_tick >> FIXP_SHIFT) && !_midiData) { _next_tick += _tick_len; - nextTick(); - play(); } step = len; @@ -456,99 +350,95 @@ void Player_V2CMS::playVoice() { } _octaveMask = 0xF0; - Voice2 *voice =0; + Voice2 *voice = 0; for (int i = 0; i < 8; ++i) { voice = &_cmsVoices[i]; _octaveMask = ~_octaveMask; if (voice->chanNumber != 0xFF) { processChannel(voice); - continue; - } - - if (!voice->curVolume) { - *(voice->amplitudeOutput) = 0; - } + } else { + if (!voice->curVolume) { + *(voice->amplitudeOutput) = 0; + } - int volume = voice->curVolume - voice->releaseRate; - voice->curVolume = volume; + int volume = voice->curVolume - voice->releaseRate; + if (volume < 0) + volume = 0; - if (volume < 0) { - volume = voice->curVolume = 0; + voice->curVolume = volume; + *(voice->amplitudeOutput) = ((volume >> 4) | (volume & 0xF0)) & voice->channel; + ++_outputTableReady; } - - *(voice->amplitudeOutput) = ((volume >> 4) | (volume & 0xF0)) & voice->channel; - ++_outputTableReady; } } void Player_V2CMS::processChannel(Voice2 *channel) { ++_outputTableReady; switch (channel->nextProcessState) { - case PROCESS_RELEASE: - processRelease(channel); - break; - - case PROCESS_ATTACK: + case Voice2::kEnvelopeAttack: processAttack(channel); break; - case PROCESS_DECAY: + case Voice2::kEnvelopeDecay: processDecay(channel); break; - case PROCESS_SUSTAIN: + case Voice2::kEnvelopeSustain: processSustain(channel); break; - case PROCESS_VIBRATO: - processVibrato(channel); - break; - - default: + case Voice2::kEnvelopeRelease: + processRelease(channel); break; } } void Player_V2CMS::processRelease(Voice2 *channel) { - channel->curVolume -= channel->releaseRate; - if (channel->curVolume < 0) - channel->curVolume = 0; + int newVolume = channel->curVolume - channel->releaseRate; + if (newVolume < 0) + newVolume = 0; + + channel->curVolume = newVolume; processVibrato(channel); } void Player_V2CMS::processAttack(Voice2 *channel) { - channel->curVolume += channel->attackRate; - if (channel->curVolume >= 0) { - if (channel->curVolume <= channel->maxAmpl) - return processVibrato(channel); + int newVolume = channel->curVolume + channel->attackRate; + if (newVolume > channel->maxAmpl) { + channel->curVolume = channel->maxAmpl; + channel->nextProcessState = Voice2::kEnvelopeDecay; + } else { + channel->curVolume = newVolume; } - channel->curVolume = channel->maxAmpl; - channel->nextProcessState = PROCESS_DECAY; + processVibrato(channel); } void Player_V2CMS::processDecay(Voice2 *channel) { - channel->curVolume -= channel->decayRate; - if (channel->curVolume >= 0) { - if (channel->curVolume > channel->sustainRate) - return processVibrato(channel); + int newVolume = channel->curVolume - channel->decayRate; + if (newVolume <= channel->sustainRate) { + channel->curVolume = channel->sustainRate; + channel->nextProcessState = Voice2::kEnvelopeSustain; + } else { + channel->curVolume = newVolume; } - channel->curVolume = channel->sustainRate; - channel->nextProcessState = PROCESS_SUSTAIN; + processVibrato(channel); } void Player_V2CMS::processSustain(Voice2 *channel) { if (channel->unkVibratoRate) { - int volume = (int)channel->curVolume + (int)channel->unkRate; + int16 volume = channel->curVolume + channel->unkRate; if (volume & 0xFF00) { - volume = ((~volume) >> 8) & 0xFF; + volume = int8(volume >> 8); + volume = -volume; } + channel->curVolume = volume; - --(channel->unkCount); + --channel->unkCount; if (!channel->unkCount) { - channel->unkRate = ~(channel->unkRate); + channel->unkRate = -channel->unkRate; channel->unkCount = (channel->unkVibratoDepth & 0x0F) << 1; } } @@ -557,12 +447,13 @@ void Player_V2CMS::processSustain(Voice2 *channel) { void Player_V2CMS::processVibrato(Voice2 *channel) { if (channel->vibratoRate) { - uint16 temp = channel->curFreq + channel->curVibratoRate; + int16 temp = channel->curFreq + channel->curVibratoRate; channel->curOctave += (temp & 0xFF00) >> 8; channel->curFreq = temp & 0xFF; - --(channel->curVibratoUnk); + + --channel->curVibratoUnk; if (!channel->curVibratoUnk) { - channel->curVibratoRate = ~(channel->curVibratoRate); + channel->curVibratoRate = -channel->curVibratoRate; channel->curVibratoUnk = (channel->vibratoDepth & 0x0F) << 1; } } @@ -572,25 +463,16 @@ void Player_V2CMS::processVibrato(Voice2 *channel) { output = channel->freqOutput; *output = channel->curFreq; output = channel->octaveOutput; - *output = ((((channel->curOctave >> 4) | (channel->curOctave & 0x0F)) & _octaveMask) | ((~_octaveMask) & *output)); + *output = (((channel->curOctave << 4) | (channel->curOctave & 0x0F)) & _octaveMask) | ((~_octaveMask) & *output); } void Player_V2CMS::offAllChannels() { - warning("offAllChannels STUB"); -/* - // after using this sound can not be played anymore (since it would deinit the emulator) - static const byte cmsOffData[10*2] = { - 0x1C, 0x02, - 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, - 0x14, 0x3F, 0x15, 0x00, 0x16, 0x00 - }; - for (int cmsPort = 0x220, i = 0; i < 2; cmsPort += 2, ++i) { - for (int off = 0; off < 10; ++off) { - _cmsEmu->portWrite(cmsPort+1, cmsOffData[off*2]); - _cmsEmu->portWrite(cmsPort, cmsOffData[off*2+1]); + for (int off = 1; off <= 10; ++off) { + _cmsEmu->portWrite(cmsPort+1, _cmsInitData[off*2]); + _cmsEmu->portWrite(cmsPort, _cmsInitData[off*2+1]); } - }*/ + } } Player_V2CMS::Voice2 *Player_V2CMS::getFreeVoice() { @@ -637,8 +519,10 @@ void Player_V2CMS::playNote(byte *&data) { freeVoice->sustainRate = voice->sustain; freeVoice->releaseRate = voice->release; freeVoice->octaveAdd = voice->octadd; - freeVoice->vibratoRate = freeVoice->curVibratoRate = voice->vibrato; - freeVoice->unkVibratoRate = freeVoice->unkRate = voice->vibrato2; + freeVoice->vibratoRate = freeVoice->curVibratoRate = voice->vibrato & 0xFF; + freeVoice->vibratoDepth = freeVoice->curVibratoUnk = voice->vibrato >> 8; + freeVoice->unkVibratoRate = freeVoice->unkRate = voice->vibrato2 & 0xFF; + freeVoice->unkVibratoDepth = freeVoice->unkCount = voice->vibrato2 >> 8; freeVoice->maxAmpl = 0xFF; uint8 rate = freeVoice->attackRate; @@ -650,7 +534,14 @@ void Player_V2CMS::playNote(byte *&data) { rate -= freeVoice->attackRate; freeVoice->curVolume = rate; freeVoice->playingNote = *data; - int octave = octaveTable[(*data + 3) << 1] + freeVoice->octaveAdd - 3; + + int effectiveNote = freeVoice->playingNote + 3; + if (effectiveNote < 0 || effectiveNote >= ARRAYSIZE(_midiNotes)) { + warning("Player_V2CMS::playNote: Note %d out of bounds", effectiveNote); + effectiveNote = CLIP<int>(effectiveNote, 0, ARRAYSIZE(_midiNotes) - 1); + } + + int octave = _midiNotes[effectiveNote].baseOctave + freeVoice->octaveAdd - 3; if (octave < 0) octave = 0; if (octave > 7) @@ -658,10 +549,10 @@ void Player_V2CMS::playNote(byte *&data) { if (!octave) ++octave; freeVoice->curOctave = octave; - freeVoice->curFreq = freqTable[volume << 2]; + freeVoice->curFreq = _midiNotes[effectiveNote].frequency; freeVoice->curVolume = 0; - freeVoice->nextProcessState = PROCESS_ATTACK; - if (_lastMidiCommand & 1) + freeVoice->nextProcessState = Voice2::kEnvelopeAttack; + if (!(_lastMidiCommand & 1)) freeVoice->channel = 0xF0; else freeVoice->channel = 0x0F; @@ -672,35 +563,27 @@ void Player_V2CMS::playNote(byte *&data) { Player_V2CMS::Voice2 *Player_V2CMS::getPlayVoice(byte param) { byte channelNum = _lastMidiCommand & 0x0F; - Voice2 *channel = _midiChannel[channelNum]; + Voice2 *curVoice = _midiChannel[channelNum]; - if (channel) { - Voice2 *backUp = 0; + if (curVoice) { + Voice2 *prevVoice = 0; while (true) { - if (channel->playingNote == param) + if (curVoice->playingNote == param) break; - backUp = channel; - channel = channel->nextVoice; - if (!channel) + prevVoice = curVoice; + curVoice = curVoice->nextVoice; + if (!curVoice) return 0; } - Voice2 *backUp2 = channel->nextVoice; - { - Voice2 *temp = backUp; - backUp = channel; - channel = temp; - } - if (channel) { - channel->nextVoice = backUp2; - } else { - _midiChannel[channelNum] = backUp2; - } - channel = backUp; + if (prevVoice) + prevVoice->nextVoice = curVoice->nextVoice; + else + _midiChannel[channelNum] = curVoice->nextVoice; } - return channel; + return curVoice; } void Player_V2CMS::clearNote(byte *&data) { @@ -708,22 +591,17 @@ void Player_V2CMS::clearNote(byte *&data) { if (voice) { voice->chanNumber = 0xFF; voice->nextVoice = 0; - voice->nextProcessState = PROCESS_RELEASE; + voice->nextProcessState = Voice2::kEnvelopeRelease; } data += 2; } void Player_V2CMS::play() { _octaveMask = 0xF0; - channel_data *chan = &(_channels[0].d); + channel_data *chan = &_channels[0].d; - static byte volumeReg[4] = { 0x00, 0x00, 0x00, 0x00 }; - static byte octaveReg[4] = { 0x66, 0x66, 0x66, 0x66 }; - static byte freqReg[4] = { 0xFF, 0xFF, 0xFF, 0xFF }; + byte noiseGen = 3; - static byte freqEnable = 0x3E; - static byte noiseEnable = 0x01; - static byte noiseGen = 0x02; for (int i = 1; i <= 4; ++i) { if (chan->time_left) { uint16 freq = chan->freq; @@ -733,8 +611,8 @@ void Player_V2CMS::play() { noiseGen = freq & 0xFF; } else { noiseGen = 3; - freqReg[0] = freqReg[3]; - octaveReg[0] = (octaveReg[0] & 0xF0) | ((octaveReg[1] & 0xF0) >> 4); + _sfxFreq[0] = _sfxFreq[3]; + _sfxOctave[0] = (_sfxOctave[0] & 0xF0) | ((_sfxOctave[1] & 0xF0) >> 4); } } else { if (freq == 0) { @@ -760,17 +638,18 @@ void Player_V2CMS::play() { oct |= cmsOct; oct &= _octaveMask; - oct |= ((~_octaveMask) & octaveReg[((i & 3) >> 1)]); - octaveReg[((i & 3) >> 1)] = oct; + oct |= (~_octaveMask) & _sfxOctave[(i & 3) >> 1]; + _sfxOctave[(i & 3) >> 1] = oct; - freq >>= -(cmsOct-9); - freqReg[(i&3)] = (-(freq-511)) & 0xFF; + freq >>= -(cmsOct - 9); + _sfxFreq[i & 3] = (-(freq - 511)) & 0xFF; } - volumeReg[i & 3] = volumeTable[chan->volume >> 12]; + _sfxAmpl[i & 3] = _volumeTable[chan->volume >> 12]; } else { - volumeReg[i & 3] = 0; + _sfxAmpl[i & 3] = 0; } - chan = &(_channels[i].d); + + chan = &_channels[i].d; _octaveMask ^= 0xFF; } @@ -778,29 +657,29 @@ 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, volumeReg[0]); + _cmsEmu->portWrite(0x220, _sfxAmpl[0]); _cmsEmu->portWrite(0x221, 1); - _cmsEmu->portWrite(0x220, volumeReg[1]); + _cmsEmu->portWrite(0x220, _sfxAmpl[1]); _cmsEmu->portWrite(0x221, 2); - _cmsEmu->portWrite(0x220, volumeReg[2]); + _cmsEmu->portWrite(0x220, _sfxAmpl[2]); _cmsEmu->portWrite(0x221, 3); - _cmsEmu->portWrite(0x220, volumeReg[3]); + _cmsEmu->portWrite(0x220, _sfxAmpl[3]); _cmsEmu->portWrite(0x221, 8); - _cmsEmu->portWrite(0x220, freqReg[0]); + _cmsEmu->portWrite(0x220, _sfxFreq[0]); _cmsEmu->portWrite(0x221, 9); - _cmsEmu->portWrite(0x220, freqReg[1]); + _cmsEmu->portWrite(0x220, _sfxFreq[1]); _cmsEmu->portWrite(0x221, 10); - _cmsEmu->portWrite(0x220, freqReg[2]); + _cmsEmu->portWrite(0x220, _sfxFreq[2]); _cmsEmu->portWrite(0x221, 11); - _cmsEmu->portWrite(0x220, freqReg[3]); + _cmsEmu->portWrite(0x220, _sfxFreq[3]); _cmsEmu->portWrite(0x221, 0x10); - _cmsEmu->portWrite(0x220, octaveReg[0]); + _cmsEmu->portWrite(0x220, _sfxOctave[0]); _cmsEmu->portWrite(0x221, 0x11); - _cmsEmu->portWrite(0x220, octaveReg[1]); + _cmsEmu->portWrite(0x220, _sfxOctave[1]); _cmsEmu->portWrite(0x221, 0x14); - _cmsEmu->portWrite(0x220, freqEnable); + _cmsEmu->portWrite(0x220, 0x3E); _cmsEmu->portWrite(0x221, 0x15); - _cmsEmu->portWrite(0x220, noiseEnable); + _cmsEmu->portWrite(0x220, 0x01); _cmsEmu->portWrite(0x221, 0x16); _cmsEmu->portWrite(0x220, noiseGen); } @@ -838,4 +717,71 @@ void Player_V2CMS::playMusicChips(const MusicChip *table) { } while ((cmsPort & 2) == 0); } +const Player_V2CMS::MidiNote Player_V2CMS::_midiNotes[132] = { + { 3, 0 }, { 31, 0 }, { 58, 0 }, { 83, 0 }, + { 107, 0 }, { 130, 0 }, { 151, 0 }, { 172, 0 }, + { 191, 0 }, { 209, 0 }, { 226, 0 }, { 242, 0 }, + { 3, 1 }, { 31, 1 }, { 58, 1 }, { 83, 1 }, + { 107, 1 }, { 130, 1 }, { 151, 1 }, { 172, 1 }, + { 191, 1 }, { 209, 1 }, { 226, 1 }, { 242, 1 }, + { 3, 2 }, { 31, 2 }, { 58, 2 }, { 83, 2 }, + { 107, 2 }, { 130, 2 }, { 151, 2 }, { 172, 2 }, + { 191, 2 }, { 209, 2 }, { 226, 2 }, { 242, 2 }, + { 3, 3 }, { 31, 3 }, { 58, 3 }, { 83, 3 }, + { 107, 3 }, { 130, 3 }, { 151, 3 }, { 172, 3 }, + { 191, 3 }, { 209, 3 }, { 226, 3 }, { 242, 3 }, + { 3, 4 }, { 31, 4 }, { 58, 4 }, { 83, 4 }, + { 107, 4 }, { 130, 4 }, { 151, 4 }, { 172, 4 }, + { 191, 4 }, { 209, 4 }, { 226, 4 }, { 242, 4 }, + { 3, 5 }, { 31, 5 }, { 58, 5 }, { 83, 5 }, + { 107, 5 }, { 130, 5 }, { 151, 5 }, { 172, 5 }, + { 191, 5 }, { 209, 5 }, { 226, 5 }, { 242, 5 }, + { 3, 6 }, { 31, 6 }, { 58, 6 }, { 83, 6 }, + { 107, 6 }, { 130, 6 }, { 151, 6 }, { 172, 6 }, + { 191, 6 }, { 209, 6 }, { 226, 6 }, { 242, 6 }, + { 3, 7 }, { 31, 7 }, { 58, 7 }, { 83, 7 }, + { 107, 7 }, { 130, 7 }, { 151, 7 }, { 172, 7 }, + { 191, 7 }, { 209, 7 }, { 226, 7 }, { 242, 7 }, + { 3, 8 }, { 31, 8 }, { 58, 8 }, { 83, 8 }, + { 107, 8 }, { 130, 8 }, { 151, 8 }, { 172, 8 }, + { 191, 8 }, { 209, 8 }, { 226, 8 }, { 242, 8 }, + { 3, 9 }, { 31, 9 }, { 58, 9 }, { 83, 9 }, + { 107, 9 }, { 130, 9 }, { 151, 9 }, { 172, 9 }, + { 191, 9 }, { 209, 9 }, { 226, 9 }, { 242, 9 }, + { 3, 10 }, { 31, 10 }, { 58, 10 }, { 83, 10 }, + { 107, 10 }, { 130, 10 }, { 151, 10 }, { 172, 10 }, + { 191, 10 }, { 209, 10 }, { 226, 10 }, { 242, 10 } +}; + +const byte Player_V2CMS::_attackRate[16] = { + 0, 2, 4, 7, 14, 26, 48, 82, + 128, 144, 160, 176, 192, 208, 224, 255 +}; + +const byte Player_V2CMS::_decayRate[16] = { + 0, 1, 2, 3, 4, 6, 12, 24, + 48, 96, 192, 215, 255, 255, 255, 255 +}; + +const byte Player_V2CMS::_sustainRate[16] = { + 255, 180, 128, 96, 80, 64, 56, 48, + 42, 36, 32, 28, 24, 20, 16, 0 +}; + +const byte Player_V2CMS::_releaseRate[16] = { + 0, 1, 2, 4, 6, 9, 14, 22, + 36, 56, 80, 100, 120, 140, 160, 255 +}; + +const byte Player_V2CMS::_volumeTable[16] = { + 0x00, 0x10, 0x10, 0x11, 0x11, 0x21, 0x22, 0x22, + 0x33, 0x44, 0x55, 0x66, 0x88, 0xAA, 0xCC, 0xFF +}; + +const byte Player_V2CMS::_cmsInitData[26] = { + 0x1C, 0x02, + 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, + 0x14, 0x3F, 0x15, 0x00, 0x16, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1C, 0x01 +}; + } // End of namespace Scumm diff --git a/engines/scumm/player_v2cms.h b/engines/scumm/player_v2cms.h index f7dc0c16b1..905c7c141e 100644 --- a/engines/scumm/player_v2cms.h +++ b/engines/scumm/player_v2cms.h @@ -42,18 +42,14 @@ public: virtual void startSound(int sound); virtual void stopSound(int sound); virtual void stopAllSounds(); -// virtual int getMusicTimer(); + virtual int getMusicTimer(); virtual int getSoundStatus(int sound) const; // AudioStream API - int readBuffer(int16 *buffer, const int numSamples); - bool isStereo() const { return true; } - bool endOfData() const { return false; } - int getRate() const { return _sampleRate; } + virtual int readBuffer(int16 *buffer, const int numSamples); + virtual bool isStereo() const { return true; } -protected: - -#include "common/pack-start.h" // START STRUCT PACKING +private: struct Voice { byte attack; byte decay; @@ -63,7 +59,7 @@ protected: int16 vibrato; int16 vibrato2; int16 noise; - } PACKED_STRUCT; + }; struct Voice2 { byte *amplitudeOutput; @@ -72,12 +68,12 @@ protected: uint8 channel; int8 sustainLevel; - int8 attackRate; + uint8 attackRate; uint8 maxAmpl; - int8 decayRate; - int8 sustainRate; - int8 releaseRate; - int8 releaseTime; + uint8 decayRate; + uint8 sustainRate; + uint8 releaseRate; + uint8 releaseTime; int8 vibratoRate; int8 vibratoDepth; @@ -90,10 +86,17 @@ protected: int8 unkRate; int8 unkCount; - int nextProcessState; - int8 curVolume; - int8 curOctave; - int8 curFreq; + enum EnvelopeState { + kEnvelopeAttack, + kEnvelopeDecay, + kEnvelopeSustain, + kEnvelopeRelease + }; + + EnvelopeState nextProcessState; + uint8 curVolume; + uint8 curOctave; + uint8 curFreq; int8 octaveAdd; @@ -101,21 +104,20 @@ protected: 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]; MusicChip _cmsChips[2]; - int8 _tempo; - int8 _tempoSum; + uint8 _tempo; + uint8 _tempoSum; byte _looping; byte _octaveMask; int16 _midiDelay; @@ -126,11 +128,13 @@ protected: int _loadedMidiSong; + byte _sfxFreq[4], _sfxAmpl[4], _sfxOctave[2]; + byte _lastMidiCommand; uint _outputTableReady; - byte _clkFrequenz; - byte _restart; - byte _curSno; + byte _voiceTimer; + + int _musicTimer, _musicTimerTicks; void loadMidiData(byte *data, int sound); void play(); @@ -147,15 +151,25 @@ protected: void clearNote(byte *&data); void offAllChannels(); void playVoice(); - void processMidiData(uint ticks); + void processMidiData(); Voice2 *getFreeVoice(); Voice2 *getPlayVoice(byte param); - // from Player_V2 -protected: - CMSEmulator *_cmsEmu; + struct MidiNote { + byte frequency; + byte baseOctave; + }; + + static const MidiNote _midiNotes[132]; + static const byte _attackRate[16]; + static const byte _decayRate[16]; + static const byte _sustainRate[16]; + static const byte _releaseRate[16]; + static const byte _volumeTable[16]; + static const byte _cmsInitData[26]; + CMSEmulator *_cmsEmu; }; } // End of namespace Scumm diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp index 3cc710c207..870ec8cdf7 100644 --- a/engines/scumm/saveload.cpp +++ b/engines/scumm/saveload.cpp @@ -686,12 +686,7 @@ Graphics::Surface *ScummEngine::loadThumbnailFromSlot(const char *target, int sl Graphics::Surface *thumb = 0; if (Graphics::checkThumbnailHeader(*in)) { - thumb = new Graphics::Surface(); - assert(thumb); - if (!Graphics::loadThumbnail(*in, *thumb)) { - delete thumb; - thumb = 0; - } + thumb = Graphics::loadThumbnail(*in); } delete in; diff --git a/engines/scumm/script_v4.cpp b/engines/scumm/script_v4.cpp index 1302c8c28d..8340f62dbc 100644 --- a/engines/scumm/script_v4.cpp +++ b/engines/scumm/script_v4.cpp @@ -68,6 +68,18 @@ void ScummEngine_v4::o4_ifState() { int a = getVarOrDirectWord(PARAM_1); int b = getVarOrDirectByte(PARAM_2); + // WORKAROUND bug #3306145 (also occurs in original): Some old versions of + // Indy3 sometimes fail to allocate IQ points correctly. To quote: + // "About the points error leaving Castle Brunwald: It seems to "reversed"! + // When you get caught, free yourself and escape, you get 25 IQ points even + // though you're not supposed to. However if you escape WITHOUT getting + // caught, you get 0 IQ points (supposed to get 25 IQ points)." + // This workaround is meant to address that. + if (_game.id == GID_INDY3 && a == 367 && + vm.slot[_currentScript].number == 363 && _currentRoom == 25) { + b = 0; + } + jumpRelative(getState(a) == b); } diff --git a/engines/scumm/script_v5.cpp b/engines/scumm/script_v5.cpp index a6cf504586..02c8d977a5 100644 --- a/engines/scumm/script_v5.cpp +++ b/engines/scumm/script_v5.cpp @@ -2095,6 +2095,20 @@ void ScummEngine_v5::o5_startScript() { if (_game.id == GID_ZAK && _game.platform == Common::kPlatformFMTowns && script == 171) return; + // WORKAROUND bug #3306145 (also occurs in original): Some old versions of + // Indy3 sometimes fail to allocate IQ points correctly. To quote: + // "In the Amiga version you get the 15 points for puzzle 30 if you give the + // book or KO the guy. The PC version correctly gives 10 points for puzzle + // 29 for KO and 15 for puzzle 30 when giving the book." + // This workaround is meant to address that. + if (_game.id == GID_INDY3 && vm.slot[_currentScript].number == 106 && script == 125 && VAR(115) != 2) { + // If Var[115] != 2, then: + // Correct: startScript(125,[29,10]); + // Wrong : startScript(125,[30,15]); + data[0] = 29; + data[1] = 10; + } + // Method used by original games to skip copy protection scheme if (!_copyProtection) { // Copy protection was disabled in LucasArts Classic Adventures (PC Disk) diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h index 8f555818f4..319eddf871 100644 --- a/engines/scumm/scumm-md5.h +++ b/engines/scumm/scumm-md5.h @@ -1,5 +1,5 @@ /* - This file was generated by the md5table tool on Sun Apr 17 10:46:26 2011 + This file was generated by the md5table tool on Wed Aug 3 03:14:00 2011 DO NOT EDIT MANUALLY! */ @@ -99,7 +99,7 @@ static const MD5Table md5table[] = { { "1ed22f601f8b3695804a6583cc3083f1", "puttrace", "HE 98.5", "", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "1f2e62b5a9c50589fc342285a6bb3a27", "freddi", "HE 73", "", -1, Common::HE_ISR, Common::kPlatformWindows }, { "1fbebd7b2b692df5297870447a80cfed", "atlantis", "Floppy", "Floppy", 12030, Common::DE_DEU, Common::kPlatformPC }, - { "1ff5997c78fbd0a841a75ef15a05d9d5", "BluesBirthday", "", "Red", -1, Common::EN_ANY, Common::kPlatformWindows }, + { "1ff5997c78fbd0a841a75ef15a05d9d5", "BluesBirthday", "Red", "Red", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "2012f854d83d9cc6f73b2b544cd8bbf8", "water", "HE 80", "", -1, Common::RU_RUS, Common::kPlatformWindows }, { "20176076d708bf14407bcc9bdcd7a418", "pajama3", "", "", -1, Common::RU_RUS, Common::kPlatformWindows }, { "204453e33456c4faa26e276229fe5b76", "spyfox2", "", "Demo", 14689, Common::DE_DEU, Common::kPlatformWindows }, @@ -403,7 +403,7 @@ static const MD5Table md5table[] = { { "9781422e4288dbc090720e4563168ba7", "puttzoo", "", "", -1, Common::FR_FRA, Common::kPlatformWindows }, { "981e1e1891f2be7e25a01f50ae55a5af", "puttrace", "HE 98", "", -1, Common::EN_USA, Common::kPlatformUnknown }, { "98744fe66ff730e8c2b3b1f58803ab0b", "atlantis", "Floppy", "Demo", -1, Common::EN_ANY, Common::kPlatformPC }, - { "99128b6a5bdd9831d9682fb8b5cbf8d4", "BluesBirthday", "", "Yellow", -1, Common::EN_ANY, Common::kPlatformUnknown }, + { "99128b6a5bdd9831d9682fb8b5cbf8d4", "BluesBirthday", "Yellow", "Yellow", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "99a3699f80b8f776efae592b44b9b991", "maniac", "V2", "V2", -1, Common::FR_FRA, Common::kPlatformPC }, { "99b6f822b0b2612415407865438697d6", "atlantis", "", "Demo", -1, Common::EN_ANY, Common::kPlatformPC }, { "9b7452b5cd6d3ffb2b2f5118010af84f", "ft", "Demo", "Demo", 116463537, Common::EN_ANY, Common::kPlatformMacintosh }, diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp index 7b136dc36d..3b83019275 100644 --- a/engines/scumm/scumm.cpp +++ b/engines/scumm/scumm.cpp @@ -71,6 +71,7 @@ #include "scumm/he/cup_player_he.h" #include "scumm/util.h" #include "scumm/verbs.h" +#include "scumm/imuse/pcspk.h" #include "backends/audiocd/audiocd.h" @@ -283,8 +284,9 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr) _16BitPalette = NULL; #ifndef DISABLE_TOWNS_DUAL_LAYER_MODE _townsScreen = 0; +#ifdef USE_RGB_COLOR _cjkFont = 0; - _cjkChar = 0; +#endif #endif _shadowPalette = NULL; _shadowPaletteSize = 0; @@ -297,7 +299,6 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr) _haveActorSpeechMsg = false; _useTalkAnims = false; _defaultTalkDelay = 0; - _musicType = MDT_NONE; _saveSound = 0; memset(_extraBoxFlags, 0, sizeof(_extraBoxFlags)); memset(_scaleSlots, 0, sizeof(_scaleSlots)); @@ -633,8 +634,10 @@ ScummEngine::~ScummEngine() { #ifndef DISABLE_TOWNS_DUAL_LAYER_MODE delete _townsScreen; +#ifdef USE_RGB_COLOR delete _cjkFont; #endif +#endif delete _debugger; @@ -1350,13 +1353,23 @@ void ScummEngine::setupCharsetRenderer() { _charset = new CharsetRendererPCE(this); else #endif + if (_game.platform == Common::kPlatformFMTowns) + _charset = new CharsetRendererTownsV3(this); + else _charset = new CharsetRendererV3(this); #ifdef ENABLE_SCUMM_7_8 } else if (_game.version == 8) { _charset = new CharsetRendererNut(this); #endif } else { - _charset = new CharsetRendererClassic(this); +#ifdef USE_RGB_COLOR +#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE + if (_game.platform == Common::kPlatformFMTowns) + _charset = new CharsetRendererTownsClassic(this); + else +#endif +#endif + _charset = new CharsetRendererClassic(this); } } @@ -1655,43 +1668,8 @@ void ScummEngine_v90he::resetScumm() { _sprite->resetTables(0); memset(&_wizParams, 0, sizeof(_wizParams)); - if (_game.heversion >= 98) { - switch (_game.id) { - case GID_PUTTRACE: - _logicHE = new LogicHErace(this); - break; - - case GID_FUNSHOP: - _logicHE = new LogicHEfunshop(this); - break; - - case GID_FOOTBALL: - _logicHE = new LogicHEfootball(this); - break; - - case GID_SOCCER: - case GID_SOCCERMLS: - case GID_SOCCER2004: - _logicHE = new LogicHEsoccer(this); - break; - - case GID_BASEBALL2001: - _logicHE = new LogicHEbaseball2001(this); - break; - - case GID_BASKETBALL: - _logicHE = new LogicHEbasketball(this); - break; - - case GID_MOONBASE: - _logicHE = new LogicHEmoonbase(this); - break; - - default: - _logicHE = new LogicHE(this); - break; - } - } + if (_game.heversion >= 98) + _logicHE = LogicHE::makeLogicHE(this); } void ScummEngine_v99he::resetScumm() { @@ -1732,40 +1710,36 @@ void ScummEngine::setupMusic(int midi) { switch (MidiDriver::getMusicType(dev)) { case MT_NULL: - _musicType = MDT_NONE; + _sound->_musicType = MDT_NONE; break; case MT_PCSPK: - _musicType = MDT_PCSPK; + _sound->_musicType = MDT_PCSPK; break; case MT_PCJR: - _musicType = MDT_PCJR; + _sound->_musicType = MDT_PCJR; break; - //case MT_CMS: -#if 1 - _musicType = MDT_ADLIB; -#else - _musicType = MDT_CMS; // Still has number of bugs, disable by default -#endif + case MT_CMS: + _sound->_musicType = MDT_CMS; break; case MT_TOWNS: - _musicType = MDT_TOWNS; + _sound->_musicType = MDT_TOWNS; break; case MT_ADLIB: - _musicType = MDT_ADLIB; + _sound->_musicType = MDT_ADLIB; break; case MT_C64: - _musicType = MDT_C64; + _sound->_musicType = MDT_C64; break; case MT_APPLEIIGS: - _musicType = MDT_APPLEIIGS; + _sound->_musicType = MDT_APPLEIIGS; break; default: - _musicType = MDT_MIDI; + _sound->_musicType = MDT_MIDI; break; } if ((_game.id == GID_MONKEY_EGA || (_game.id == GID_LOOM && _game.version == 3)) - && (_game.platform == Common::kPlatformPC) && _musicType == MDT_MIDI) { + && (_game.platform == Common::kPlatformPC) && _sound->_musicType == MDT_MIDI) { Common::String fileName; bool missingFile = false; if (_game.id == GID_LOOM) { @@ -1795,7 +1769,7 @@ void ScummEngine::setupMusic(int midi) { "but %s is missing. Using AdLib instead."), fileName.c_str()), _("OK")); dialog.runModal(); - _musicType = MDT_ADLIB; + _sound->_musicType = MDT_ADLIB; } } @@ -1809,9 +1783,9 @@ void ScummEngine::setupMusic(int midi) { * automatically when samples need to be generated */ if (!_mixer->isReady()) { warning("Sound mixer initialization failed"); - if (_musicType == MDT_ADLIB || _musicType == MDT_PCSPK || _musicType == MDT_PCJR || _musicType == MDT_CMS) { + if (_sound->_musicType == MDT_ADLIB || _sound->_musicType == MDT_PCSPK || _sound->_musicType == MDT_PCJR || _sound->_musicType == MDT_CMS) { dev = 0; - _musicType = MDT_NONE; + _sound->_musicType = MDT_NONE; warning("MIDI driver depends on sound mixer, switching to null MIDI driver"); } } @@ -1843,9 +1817,9 @@ void ScummEngine::setupMusic(int midi) { _musicEngine = new Player_V1(this, _mixer, MidiDriver::getMusicType(dev) != MT_PCSPK); } else if (_game.version <= 2) { _musicEngine = new Player_V2(this, _mixer, MidiDriver::getMusicType(dev) != MT_PCSPK); - } else if ((_musicType == MDT_PCSPK || _musicType == MDT_PCJR) && (_game.version > 2 && _game.version <= 4)) { + } else if ((_sound->_musicType == MDT_PCSPK || _sound->_musicType == MDT_PCJR) && (_game.version > 2 && _game.version <= 4)) { _musicEngine = new Player_V2(this, _mixer, MidiDriver::getMusicType(dev) != MT_PCSPK); - } else if (_musicType == MDT_CMS) { + } else if (_sound->_musicType == MDT_CMS) { _musicEngine = new Player_V2CMS(this, _mixer); } else if (_game.platform == Common::kPlatform3DO && _game.heversion <= 62) { // 3DO versions use digital music and sound samples. @@ -1857,14 +1831,16 @@ void ScummEngine::setupMusic(int midi) { MidiDriver *nativeMidiDriver = 0; MidiDriver *adlibMidiDriver = 0; - if (_musicType != MDT_ADLIB && _musicType != MDT_TOWNS) + if (_sound->_musicType != MDT_ADLIB && _sound->_musicType != MDT_TOWNS && _sound->_musicType != MDT_PCSPK) nativeMidiDriver = MidiDriver::createMidi(dev); if (nativeMidiDriver != NULL && _native_mt32) nativeMidiDriver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE); - bool multi_midi = ConfMan.getBool("multi_midi") && _musicType != MDT_NONE && (midi & MDT_ADLIB); - if (_musicType == MDT_ADLIB || _musicType == MDT_TOWNS || multi_midi) { - adlibMidiDriver = MidiDriver::createMidi(MidiDriver::detectDevice(_musicType == MDT_TOWNS ? MDT_TOWNS : MDT_ADLIB)); + bool multi_midi = ConfMan.getBool("multi_midi") && _sound->_musicType != MDT_NONE && _sound->_musicType != MDT_PCSPK && (midi & MDT_ADLIB); + if (_sound->_musicType == MDT_ADLIB || _sound->_musicType == MDT_TOWNS || multi_midi) { + adlibMidiDriver = MidiDriver::createMidi(MidiDriver::detectDevice(_sound->_musicType == MDT_TOWNS ? MDT_TOWNS : MDT_ADLIB)); adlibMidiDriver->property(MidiDriver::PROP_OLD_ADLIB, (_game.features & GF_SMALL_HEADER) ? 1 : 0); + } else if (_sound->_musicType == MDT_PCSPK) { + adlibMidiDriver = new PcSpkDriver(_mixer); } _imuse = IMuse::create(_system, nativeMidiDriver, adlibMidiDriver); @@ -1893,6 +1869,8 @@ void ScummEngine::setupMusic(int midi) { _imuse->property(IMuse::PROP_LIMIT_PLAYERS, 1); _imuse->property(IMuse::PROP_RECYCLE_PLAYERS, 1); } + if (_sound->_musicType == MDT_PCSPK) + _imuse->property(IMuse::PROP_PC_SPEAKER, 1); } } } diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h index 01bde90e1c..04a175e732 100644 --- a/engines/scumm/scumm.h +++ b/engines/scumm/scumm.h @@ -40,15 +40,14 @@ #include "scumm/detection.h" #include "scumm/script.h" -#include "audio/mididrv.h" - #ifdef __DS__ /* This disables the dual layer mode which is used in FM-Towns versions * of SCUMM games and which emulates the behavior of the original code. * The only purpose is code size reduction for certain backends. - * SCUMM 3 (FM-Towns) games will run in normal (DOS VGA) mode, which should - * work just fine in most situations. Some glitches might occur. SCUMM 5 games - * will not work without dual layer (and 16 bit color) support. + * SCUMM 3 (FM-Towns) games will run in English in normal (DOS VGA) mode, + * which should work just fine in most situations. Some glitches might + * occur. Japanese mode and SCUMM 5 FM-Towns games will not work without + * dual layer (and 16 bit color) support. */ #define DISABLE_TOWNS_DUAL_LAYER_MODE #endif @@ -234,7 +233,8 @@ enum ScummGameId { GID_PUTTMOON, GID_FUNPACK, GID_FREDDI3, - GID_BIRTHDAY, + GID_BIRTHDAYRED, + GID_BIRTHDAYYELLOW, GID_TREASUREHUNT, GID_PUTTRACE, GID_FUNSHOP, // Used for all three funshops @@ -345,6 +345,7 @@ class ResourceManager; class ScummEngine : public Engine { friend class ScummDebugger; friend class CharsetRenderer; + friend class CharsetRendererTownsClassic; friend class ResourceManager; public: @@ -1082,7 +1083,6 @@ protected: int _saveSound; bool _native_mt32; bool _enable_gs; - MidiDriverFlags _musicType; bool _copyProtection; public: @@ -1326,14 +1326,17 @@ public: // Exists both in V7 and in V72HE: byte VAR_NUM_GLOBAL_OBJS; +#ifdef USE_RGB_COLOR + // FM-Towns / PC-Engine specific + Graphics::FontSJIS *_cjkFont; +#endif + // FM-Towns specific #ifndef DISABLE_TOWNS_DUAL_LAYER_MODE public: bool towns_isRectInStringBox(int x1, int y1, int x2, int y2); byte _townsPaletteFlags; - byte _townsCharsetColorMap[16]; - Graphics::FontSJIS *_cjkFont; - uint16 _cjkChar; + byte _townsCharsetColorMap[16]; protected: void towns_drawStripToScreen(VirtScreen *vs, int dstX, int dstY, int srcX, int srcY, int w, int h); diff --git a/engines/scumm/smush/channel.cpp b/engines/scumm/smush/channel.cpp index 7f71d0549b..fd822f56b6 100644 --- a/engines/scumm/smush/channel.cpp +++ b/engines/scumm/smush/channel.cpp @@ -60,6 +60,8 @@ void SmushChannel::processBuffer() { if (offset < _tbufferSize) { int new_size = _tbufferSize - offset; _tbuffer = (byte *)malloc(new_size); + // FIXME: _tbuffer might be 0 if new_size is 0. + // NB: Also check other "if (_tbuffer)" locations in smush if (!_tbuffer) error("smush channel failed to allocate memory"); memcpy(_tbuffer, _sbuffer + offset, new_size); @@ -97,6 +99,8 @@ void SmushChannel::processBuffer() { byte *old = _tbuffer; int32 new_size = _tbufferSize - offset; _tbuffer = (byte *)malloc(new_size); + // FIXME: _tbuffer might be 0 if new_size is 0. + // NB: Also check other "if (_tbuffer)" locations in smush if (!_tbuffer) error("smush channel failed to allocate memory"); memcpy(_tbuffer, old + offset, new_size); diff --git a/engines/scumm/smush/codec37.cpp b/engines/scumm/smush/codec37.cpp index dcc8ee3c19..344057e3ac 100644 --- a/engines/scumm/smush/codec37.cpp +++ b/engines/scumm/smush/codec37.cpp @@ -571,4 +571,3 @@ void Codec37Decoder::decode(byte *dst, const byte *src) { } } // End of namespace Scumm - diff --git a/engines/scumm/smush/smush_font.cpp b/engines/scumm/smush/smush_font.cpp index 7765bf1292..5cfa0ea519 100644 --- a/engines/scumm/smush/smush_font.cpp +++ b/engines/scumm/smush/smush_font.cpp @@ -258,4 +258,3 @@ void SmushFont::drawStringWrap(const char *str, byte *buffer, int dst_width, int } } // End of namespace Scumm - diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp index 27e43b3740..d8235206f8 100644 --- a/engines/scumm/sound.cpp +++ b/engines/scumm/sound.cpp @@ -84,6 +84,8 @@ Sound::Sound(ScummEngine *parent, Audio::Mixer *mixer) memset(_soundQue, 0, sizeof(_soundQue)); memset(_soundQue2, 0, sizeof(_soundQue2)); memset(_mouthSyncTimes, 0, sizeof(_mouthSyncTimes)); + + _musicType = MDT_NONE; } Sound::~Sound() { @@ -1016,7 +1018,7 @@ void Sound::startCDTimer() { // appears. _vm->getTimerManager()->removeTimerProc(&cd_timer_handler); - _vm->getTimerManager()->installTimerProc(&cd_timer_handler, 100700, _vm); + _vm->getTimerManager()->installTimerProc(&cd_timer_handler, 100700, _vm, "scummCDtimer"); } void Sound::stopCDTimer() { @@ -1094,7 +1096,7 @@ int ScummEngine::readSoundResource(ResId idx) { switch (basetag) { case MKTAG('M','I','D','I'): case MKTAG('i','M','U','S'): - if (_musicType != MDT_PCSPK && _musicType != MDT_PCJR) { + if (_sound->_musicType != MDT_PCSPK && _sound->_musicType != MDT_PCJR) { _fileHandle->seek(-8, SEEK_CUR); _fileHandle->read(_res->createResource(rtSound, idx, total_size + 8), total_size + 8); return 1; @@ -1118,7 +1120,7 @@ int ScummEngine::readSoundResource(ResId idx) { break; case MKTAG('A','D','L',' '): pri = 1; - if (_musicType == MDT_ADLIB || _musicType == MDT_TOWNS) + if (_sound->_musicType == MDT_ADLIB || _sound->_musicType == MDT_TOWNS) pri = 10; break; case MKTAG('A','M','I',' '): @@ -1137,16 +1139,33 @@ int ScummEngine::readSoundResource(ResId idx) { break; case MKTAG('S','P','K',' '): pri = -1; -// if (_musicType == MDT_PCSPK || _musicType == MDT_PCJR) -// pri = 11; + if (_sound->_musicType == MDT_PCSPK || _sound->_musicType == MDT_PCJR) + pri = 11; break; } - if ((_musicType == MDT_PCSPK || _musicType == MDT_PCJR || _musicType == MDT_CMS) && pri != 11) + // We only allow SPK resources for PC Speaker and PCJr here + // since other resource would sound horribly with their output + // drivers. + if ((_sound->_musicType == MDT_PCSPK || _sound->_musicType == MDT_PCJR) && pri != 11) pri = -1; - debugC(DEBUG_RESOURCE, " tag: %s, total_size=%d, pri=%d", tag2str(tag), size, pri); + // We only allow ADL resources when AdLib or FM-Towns is used as + // primary audio output. This fixes some odd sounds when Indy and + // Sophia leave Atlantis with the submarine in Indy4. (Easy to + // check with bootparam 4061 in the CD version). It seems the game + // 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. + // We make an exception for Macintosh, which uses priority 2 for + // its sound resources, and Amiga games, which feature only ROL + // resources, since we are a doing Midi -> AdLib conversion for + // these. + if ((_sound->_musicType == MDT_ADLIB || _sound->_musicType == MDT_TOWNS) && pri != 10 + && pri != 2 && _game.platform != Common::kPlatformAmiga) + pri = -1; + debugC(DEBUG_RESOURCE, " tag: %s, total_size=%d, pri=%d", tag2str(tag), size, pri); if (pri > best_pri) { best_pri = pri; @@ -1984,6 +2003,14 @@ static void convertADResource(ResourceManager *res, const GameSettings& game, Re break; case 0x80: + // FIXME: This is incorrect. The original uses 0x80 for + // looping a single channel. We currently interpret it as stop + // thus we won't get looping for sound effects. It should + // always jump to the start of the channel. + // + // Since we convert the data to MIDI and we cannot only loop a + // single channel via MIDI fixing this will require some more + // thought. track_time[ch] = -1; src_ptr ++; break; @@ -2074,7 +2101,7 @@ int ScummEngine::readSoundResourceSmallHeader(ResId idx) { } } - if ((_musicType == MDT_PCSPK || _musicType == MDT_PCJR) && wa_offs != 0) { + if ((_sound->_musicType == MDT_PCSPK || _sound->_musicType == MDT_PCJR) && wa_offs != 0) { if (_game.features & GF_OLD_BUNDLE) { _fileHandle->seek(wa_offs, SEEK_SET); _fileHandle->read(_res->createResource(rtSound, idx, wa_size), wa_size); @@ -2083,18 +2110,37 @@ int ScummEngine::readSoundResourceSmallHeader(ResId idx) { _fileHandle->read(_res->createResource(rtSound, idx, wa_size + 6), wa_size + 6); } return 1; - } else if (_musicType == MDT_CMS && ad_offs != 0) { + } else if (_sound->_musicType == MDT_CMS) { if (_game.features & GF_OLD_BUNDLE) { - _fileHandle->seek(wa_offs + wa_size + 6, SEEK_SET); - byte musType = _fileHandle->readByte(); + bool hasAdLibMusicTrack = false; + + if (ad_offs) { + _fileHandle->seek(ad_offs + 4 + 2, SEEK_SET); + hasAdLibMusicTrack = (_fileHandle->readByte() == 0x80); + } - if (musType == 0x80) { + if (hasAdLibMusicTrack) { _fileHandle->seek(ad_offs, SEEK_SET); _fileHandle->read(_res->createResource(rtSound, idx, ad_size), ad_size); } else { _fileHandle->seek(wa_offs, SEEK_SET); _fileHandle->read(_res->createResource(rtSound, idx, wa_size), wa_size); } + } else { + bool hasAdLibMusicTrack = false; + + if (ad_offs) { + _fileHandle->seek(ad_offs + 2, SEEK_SET); + hasAdLibMusicTrack = (_fileHandle->readByte() == 0x80); + } + + if (hasAdLibMusicTrack) { + _fileHandle->seek(ad_offs - 4, SEEK_SET); + _fileHandle->read(_res->createResource(rtSound, idx, ad_size + 4), ad_size + 4); + } else { + _fileHandle->seek(wa_offs - 6, SEEK_SET); + _fileHandle->read(_res->createResource(rtSound, idx, wa_size + 6), wa_size + 6); + } } } else if (ad_offs != 0) { // AD resources have a header, instrument definitions and one MIDI track. diff --git a/engines/scumm/sound.h b/engines/scumm/sound.h index 03659ceff1..e9a37ac9fa 100644 --- a/engines/scumm/sound.h +++ b/engines/scumm/sound.h @@ -24,6 +24,7 @@ #include "common/scummsys.h" #include "audio/audiostream.h" +#include "audio/mididrv.h" #include "audio/mixer.h" #include "scumm/saveload.h" @@ -90,6 +91,8 @@ public: byte _sfxMode; uint _lastSound; + MidiDriverFlags _musicType; + public: Sound(ScummEngine *parent, Audio::Mixer *mixer); virtual ~Sound(); diff --git a/engines/scumm/string.cpp b/engines/scumm/string.cpp index 2d2209c155..61bb89328d 100644 --- a/engines/scumm/string.cpp +++ b/engines/scumm/string.cpp @@ -1127,8 +1127,6 @@ int ScummEngine::convertMessageToString(const byte *msg, byte *dst, int dstSize) } num += (_game.version == 8) ? 4 : 2; } - } else if (_game.id == GID_DIG && (chr == 1 || chr == 2 || chr == 3 || chr == 8)) { - // Skip these characters } else { if ((chr != '@') || (_game.id == GID_CMI && _language == Common::ZH_TWN) || (_game.id == GID_LOOM && _game.platform == Common::kPlatformPCEngine && _language == Common::JA_JPN) || @@ -1142,6 +1140,14 @@ int ScummEngine::convertMessageToString(const byte *msg, byte *dst, int dstSize) if (dst >= end) error("convertMessageToString: buffer overflow"); } + + // WORKAROUND: Russian The Dig pads messages with 03. No idea why + // it does not work as is with our rendering code, thus fixing it + // with a workaround. + if (_game.id == GID_DIG) { + while (*(dst - 1) == 0x03) + dst--; + } *dst = 0; return dstSize - (end - dst); diff --git a/engines/scumm/vars.cpp b/engines/scumm/vars.cpp index 56f8de2ad1..26a6a2f3b1 100644 --- a/engines/scumm/vars.cpp +++ b/engines/scumm/vars.cpp @@ -25,9 +25,12 @@ #include "scumm/scumm.h" #include "scumm/scumm_v0.h" #include "scumm/scumm_v8.h" +#include "scumm/sound.h" #include "scumm/he/intern_he.h" #include "scumm/he/logic_he.h" +#include "audio/mididrv.h" + namespace Scumm { void ScummEngine::setupScummVars() { @@ -704,8 +707,12 @@ void ScummEngine_v99he::resetScummVars() { VAR(VAR_NUM_UNK) = _numUnk; if (_game.heversion >= 100 && (_game.features & GF_16BIT_COLOR)) { - // Disable Bink and Smacker video in 16bit color games + // Enable Bink video in 16bit color games +#ifdef USE_BINK + VAR(140) = 1; +#else VAR(140) = 0; +#endif } } #endif @@ -718,7 +725,7 @@ void ScummEngine::resetScummVars() { // 2 CMS // 3 AdLib // 4 Roland - switch (_musicType) { + switch (_sound->_musicType) { case MDT_NONE: case MDT_PCSPK: VAR(VAR_SOUNDCARD) = 0; diff --git a/engines/sky/autoroute.h b/engines/sky/autoroute.h index 2d01be01ec..8721ba6c54 100644 --- a/engines/sky/autoroute.h +++ b/engines/sky/autoroute.h @@ -56,4 +56,3 @@ private: } // End of namespace Sky #endif // AUTOROUTE_H - diff --git a/engines/sword1/control.h b/engines/sword1/control.h index 6c0cf8b1ef..c3550e6f02 100644 --- a/engines/sword1/control.h +++ b/engines/sword1/control.h @@ -162,4 +162,3 @@ private: } // End of namespace Sword1 #endif //BSCONTROL_H - diff --git a/engines/sword1/debug.h b/engines/sword1/debug.h index e4f004dc63..1505ae28dd 100644 --- a/engines/sword1/debug.h +++ b/engines/sword1/debug.h @@ -39,4 +39,3 @@ private: } // End of namespace Sword1 #endif // BSDEBUG_H - diff --git a/engines/sword1/detection.cpp b/engines/sword1/detection.cpp index 0c1e74082f..4da636bce9 100644 --- a/engines/sword1/detection.cpp +++ b/engines/sword1/detection.cpp @@ -274,13 +274,7 @@ SaveStateDescriptor SwordMetaEngine::querySaveMetaInfos(const char *target, int in->skip(1); if (Graphics::checkThumbnailHeader(*in)) { - Graphics::Surface *thumbnail = new Graphics::Surface(); - assert(thumbnail); - if (!Graphics::loadThumbnail(*in, *thumbnail)) { - delete thumbnail; - thumbnail = 0; - } - + Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*in); desc.setThumbnail(thumbnail); } diff --git a/engines/sword1/object.h b/engines/sword1/object.h index 5a6fd49c0b..4f5371fa72 100644 --- a/engines/sword1/object.h +++ b/engines/sword1/object.h @@ -123,4 +123,3 @@ struct Object { } // End of namespace Sword1 #endif //BSOBJECT_H - diff --git a/engines/sword1/screen.h b/engines/sword1/screen.h index ece37b0ecc..ff4df8c7c6 100644 --- a/engines/sword1/screen.h +++ b/engines/sword1/screen.h @@ -169,6 +169,3 @@ private: } // End of namespace Sword1 #endif //BSSCREEN_H - - - diff --git a/engines/sword25/detection.cpp b/engines/sword25/detection.cpp index b2f5795663..25a3df167b 100644 --- a/engines/sword25/detection.cpp +++ b/engines/sword25/detection.cpp @@ -99,4 +99,3 @@ SaveStateList Sword25MetaEngine::listSaves(const char *target) const { #else REGISTER_PLUGIN_STATIC(SWORD25, PLUGIN_TYPE_ENGINE, Sword25MetaEngine); #endif - diff --git a/engines/sword25/gfx/image/vectorimage.cpp b/engines/sword25/gfx/image/vectorimage.cpp index 45d43c465e..81f4fc2ad5 100644 --- a/engines/sword25/gfx/image/vectorimage.cpp +++ b/engines/sword25/gfx/image/vectorimage.cpp @@ -247,6 +247,9 @@ VectorImage::VectorImage(const byte *pFileData, uint fileSize, bool &success, co return; } + // readout SWF size + flashRectToBSRect(bs); + // Get frame rate and frame count /* uint32 frameRate = */ bs.getUInt16(); diff --git a/engines/sword25/kernel/inputpersistenceblock.cpp b/engines/sword25/kernel/inputpersistenceblock.cpp index 2d45dfb640..cdce539c31 100644 --- a/engines/sword25/kernel/inputpersistenceblock.cpp +++ b/engines/sword25/kernel/inputpersistenceblock.cpp @@ -55,8 +55,8 @@ void InputPersistenceBlock::read(int16 &value) { void InputPersistenceBlock::read(signed int &value) { if (checkMarker(SINT_MARKER)) { - rawRead(&value, sizeof(signed int)); - value = convertEndianessFromStorageToSystem(value); + value = (int32)READ_LE_UINT32(_iter); + _iter += 4; } else { value = 0; } @@ -64,8 +64,8 @@ void InputPersistenceBlock::read(signed int &value) { void InputPersistenceBlock::read(uint &value) { if (checkMarker(UINT_MARKER)) { - rawRead(&value, sizeof(uint)); - value = convertEndianessFromStorageToSystem(value); + value = READ_LE_UINT32(_iter); + _iter += 4; } else { value = 0; } @@ -73,8 +73,10 @@ void InputPersistenceBlock::read(uint &value) { void InputPersistenceBlock::read(float &value) { if (checkMarker(FLOAT_MARKER)) { - rawRead(&value, sizeof(float)); - value = convertEndianessFromStorageToSystem(value); + uint32 tmp[1]; + tmp[0] = READ_LE_UINT32(_iter); + value = ((float *)tmp)[0]; + _iter += 4; } else { value = 0.0f; } @@ -82,12 +84,11 @@ void InputPersistenceBlock::read(float &value) { void InputPersistenceBlock::read(bool &value) { if (checkMarker(BOOL_MARKER)) { - uint uintBool; - rawRead(&uintBool, sizeof(float)); - uintBool = convertEndianessFromStorageToSystem(uintBool); + uint uintBool = READ_LE_UINT32(_iter); + _iter += 4; value = uintBool == 0 ? false : true; } else { - value = 0.0f; + value = false; } } @@ -117,13 +118,6 @@ void InputPersistenceBlock::readByteArray(Common::Array<byte> &value) { } } -void InputPersistenceBlock::rawRead(void *destPtr, size_t size) { - if (checkBlockSize(size)) { - memcpy(destPtr, &*_iter, size); - _iter += size; - } -} - bool InputPersistenceBlock::checkBlockSize(int size) { if (_data.end() - _iter >= size) { return true; diff --git a/engines/sword25/kernel/inputpersistenceblock.h b/engines/sword25/kernel/inputpersistenceblock.h index 7e68137246..2518d7e32c 100644 --- a/engines/sword25/kernel/inputpersistenceblock.h +++ b/engines/sword25/kernel/inputpersistenceblock.h @@ -69,7 +69,6 @@ public: private: bool checkMarker(byte marker); bool checkBlockSize(int size); - void rawRead(void *destPtr, size_t size); Common::Array<byte> _data; Common::Array<byte>::const_iterator _iter; diff --git a/engines/sword25/kernel/outputpersistenceblock.cpp b/engines/sword25/kernel/outputpersistenceblock.cpp index cf28ea401f..e29d956e5f 100644 --- a/engines/sword25/kernel/outputpersistenceblock.cpp +++ b/engines/sword25/kernel/outputpersistenceblock.cpp @@ -43,19 +43,23 @@ OutputPersistenceBlock::OutputPersistenceBlock() { void OutputPersistenceBlock::write(signed int value) { writeMarker(SINT_MARKER); - value = convertEndianessFromSystemToStorage(value); + value = TO_LE_32(value); rawWrite(&value, sizeof(value)); } void OutputPersistenceBlock::write(uint value) { writeMarker(UINT_MARKER); - value = convertEndianessFromSystemToStorage(value); + value = TO_LE_32(value); rawWrite(&value, sizeof(value)); } void OutputPersistenceBlock::write(float value) { writeMarker(FLOAT_MARKER); - value = convertEndianessFromSystemToStorage(value); + uint32 tmp[1]; + + ((float *)tmp)[0] = value; + tmp[0] = TO_LE_32(tmp[0]); + rawWrite(&value, sizeof(value)); } @@ -63,7 +67,7 @@ void OutputPersistenceBlock::write(bool value) { writeMarker(BOOL_MARKER); uint uintBool = value ? 1 : 0; - uintBool = convertEndianessFromSystemToStorage(uintBool); + uintBool = TO_LE_32(uintBool); rawWrite(&uintBool, sizeof(uintBool)); } diff --git a/engines/sword25/kernel/persistenceblock.h b/engines/sword25/kernel/persistenceblock.h index d8440faa50..8ac3e84a41 100644 --- a/engines/sword25/kernel/persistenceblock.h +++ b/engines/sword25/kernel/persistenceblock.h @@ -64,48 +64,6 @@ protected: BLOCK_MARKER }; - // ----------------------------------------------------------------------------- - // Endianess Conversions - // ----------------------------------------------------------------------------- - // - // Everything is stored in Little Endian - // Big Endian Systems will need to be byte swapped during both saving and reading of saved values - // - - template<typename T> - static T convertEndianessFromSystemToStorage(T value) { - if (isBigEndian()) - reverseByteOrder(&value); - return value; - } - - template<typename T> - static T convertEndianessFromStorageToSystem(T value) { - if (isBigEndian()) - reverseByteOrder(&value); - return value; - } - -private: - static bool isBigEndian() { - uint dummy = 1; - byte *dummyPtr = reinterpret_cast<byte *>(&dummy); - return dummyPtr[0] == 0; - } - - template<typename T> - static void swap(T &one, T &two) { - T temp = one; - one = two; - two = temp; - } - - static void reverseByteOrder(void *ptr) { - // Reverses the byte order of the 32-bit word pointed to by Ptr - byte *charPtr = static_cast<byte *>(ptr); - swap(charPtr[0], charPtr[3]); - swap(charPtr[1], charPtr[2]); - } }; #define CTASSERT(ex) typedef char ctassert_type[(ex) ? 1 : -1] diff --git a/engines/sword25/sfx/soundengine.cpp b/engines/sword25/sfx/soundengine.cpp index 1b424dac65..78b2db19eb 100644 --- a/engines/sword25/sfx/soundengine.cpp +++ b/engines/sword25/sfx/soundengine.cpp @@ -209,7 +209,7 @@ uint SoundEngine::playSoundEx(const Common::String &fileName, SOUND_TYPES type, #ifdef USE_VORBIS Audio::SeekableAudioStream *stream = Audio::makeVorbisStream(in, DisposeAfterUse::YES); #endif - uint id; + uint id = handleId; SndHandle *handle; if (handleId == 0x1337) diff --git a/engines/sword25/util/lua/lapi.cpp b/engines/sword25/util/lua/lapi.cpp index ff25cfc653..b97e90012c 100644 --- a/engines/sword25/util/lua/lapi.cpp +++ b/engines/sword25/util/lua/lapi.cpp @@ -1074,4 +1074,3 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { lua_unlock(L); return name; } - diff --git a/engines/sword25/util/lua/lauxlib.cpp b/engines/sword25/util/lua/lauxlib.cpp index 1261777315..116d19dfce 100644 --- a/engines/sword25/util/lua/lauxlib.cpp +++ b/engines/sword25/util/lua/lauxlib.cpp @@ -655,4 +655,3 @@ LUALIB_API lua_State *luaL_newstate (void) { if (L) lua_atpanic(L, &panic); return L; } - diff --git a/engines/sword25/util/lua/lauxlib.h b/engines/sword25/util/lua/lauxlib.h index d58f290527..d3c1d5ca35 100644 --- a/engines/sword25/util/lua/lauxlib.h +++ b/engines/sword25/util/lua/lauxlib.h @@ -170,5 +170,3 @@ LUALIB_API void (luaL_pushresult) (luaL_Buffer *B); #define luaL_reg luaL_Reg #endif - - diff --git a/engines/sword25/util/lua/lbaselib.cpp b/engines/sword25/util/lua/lbaselib.cpp index 5032e6322a..3f0b645164 100644 --- a/engines/sword25/util/lua/lbaselib.cpp +++ b/engines/sword25/util/lua/lbaselib.cpp @@ -651,4 +651,3 @@ LUALIB_API int luaopen_base (lua_State *L) { luaL_register(L, LUA_COLIBNAME, co_funcs); return 2; } - diff --git a/engines/sword25/util/lua/lcode.cpp b/engines/sword25/util/lua/lcode.cpp index 6e7e10017f..ead780d359 100644 --- a/engines/sword25/util/lua/lcode.cpp +++ b/engines/sword25/util/lua/lcode.cpp @@ -836,4 +836,3 @@ void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { } fs->freereg = base + 1; /* free registers with list values */ } - diff --git a/engines/sword25/util/lua/ldblib.cpp b/engines/sword25/util/lua/ldblib.cpp index 618e9a843f..e5cb8231c0 100644 --- a/engines/sword25/util/lua/ldblib.cpp +++ b/engines/sword25/util/lua/ldblib.cpp @@ -398,4 +398,3 @@ LUALIB_API int luaopen_debug (lua_State *L) { luaL_register(L, LUA_DBLIBNAME, dblib); return 1; } - diff --git a/engines/sword25/util/lua/ldebug.cpp b/engines/sword25/util/lua/ldebug.cpp index 85c492cc77..e89ae9cad5 100644 --- a/engines/sword25/util/lua/ldebug.cpp +++ b/engines/sword25/util/lua/ldebug.cpp @@ -619,4 +619,3 @@ void luaG_runerror (lua_State *L, const char *fmt, ...) { va_end(argp); luaG_errormsg(L); } - diff --git a/engines/sword25/util/lua/ldo.cpp b/engines/sword25/util/lua/ldo.cpp index 49e0881a45..5d9667f4f0 100644 --- a/engines/sword25/util/lua/ldo.cpp +++ b/engines/sword25/util/lua/ldo.cpp @@ -534,5 +534,3 @@ int luaD_protectedparser (lua_State *L, ZIO *z, const char *name) { luaZ_freebuffer(L, &p.buff); return status; } - - diff --git a/engines/sword25/util/lua/ldo.h b/engines/sword25/util/lua/ldo.h index 4c97134805..e57b08dec0 100644 --- a/engines/sword25/util/lua/ldo.h +++ b/engines/sword25/util/lua/ldo.h @@ -54,4 +54,3 @@ LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop); #endif - diff --git a/engines/sword25/util/lua/lfunc.cpp b/engines/sword25/util/lua/lfunc.cpp index ce7acf4e77..f8fa19e25a 100644 --- a/engines/sword25/util/lua/lfunc.cpp +++ b/engines/sword25/util/lua/lfunc.cpp @@ -171,4 +171,3 @@ const char *luaF_getlocalname (const Proto *f, int local_number, int pc) { } return NULL; /* not found */ } - diff --git a/engines/sword25/util/lua/lgc.cpp b/engines/sword25/util/lua/lgc.cpp index 71e581ad30..54f7b548dd 100644 --- a/engines/sword25/util/lua/lgc.cpp +++ b/engines/sword25/util/lua/lgc.cpp @@ -708,4 +708,3 @@ void luaC_linkupval (lua_State *L, UpVal *uv) { } } } - diff --git a/engines/sword25/util/lua/linit.cpp b/engines/sword25/util/lua/linit.cpp index 93f41d0350..a01f28d1ff 100644 --- a/engines/sword25/util/lua/linit.cpp +++ b/engines/sword25/util/lua/linit.cpp @@ -35,4 +35,3 @@ LUALIB_API void luaL_openlibs (lua_State *L) { lua_call(L, 1, 0); } } - diff --git a/engines/sword25/util/lua/liolib.cpp b/engines/sword25/util/lua/liolib.cpp index 6c00de5094..0d27f9677f 100644 --- a/engines/sword25/util/lua/liolib.cpp +++ b/engines/sword25/util/lua/liolib.cpp @@ -590,4 +590,3 @@ LUALIB_API int luaopen_io (lua_State *L) { lua_pop(L, 1); /* pop 'popen' */ return 1; } - diff --git a/engines/sword25/util/lua/llex.cpp b/engines/sword25/util/lua/llex.cpp index b456ee2dfe..464ab3ec15 100644 --- a/engines/sword25/util/lua/llex.cpp +++ b/engines/sword25/util/lua/llex.cpp @@ -472,4 +472,3 @@ void luaX_lookahead (LexState *ls) { lua_assert(ls->lookahead.token == TK_EOS); ls->lookahead.token = llex(ls, &ls->lookahead.seminfo); } - diff --git a/engines/sword25/util/lua/lmathlib.cpp b/engines/sword25/util/lua/lmathlib.cpp index 6c36bbcf4e..c1a645b296 100644 --- a/engines/sword25/util/lua/lmathlib.cpp +++ b/engines/sword25/util/lua/lmathlib.cpp @@ -274,4 +274,3 @@ LUALIB_API int luaopen_math (lua_State *L) { #endif return 1; } - diff --git a/engines/sword25/util/lua/lmem.cpp b/engines/sword25/util/lua/lmem.cpp index ccd69357e0..004a467dc8 100644 --- a/engines/sword25/util/lua/lmem.cpp +++ b/engines/sword25/util/lua/lmem.cpp @@ -83,4 +83,3 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { g->totalbytes = (g->totalbytes - osize) + nsize; return block; } - diff --git a/engines/sword25/util/lua/lmem.h b/engines/sword25/util/lua/lmem.h index 97a888c7f8..6430912b41 100644 --- a/engines/sword25/util/lua/lmem.h +++ b/engines/sword25/util/lua/lmem.h @@ -46,4 +46,3 @@ LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int *size, const char *errormsg); #endif - diff --git a/engines/sword25/util/lua/loadlib.cpp b/engines/sword25/util/lua/loadlib.cpp index f4cdd70a78..49934ce059 100644 --- a/engines/sword25/util/lua/loadlib.cpp +++ b/engines/sword25/util/lua/loadlib.cpp @@ -329,4 +329,3 @@ LUALIB_API int luaopen_package (lua_State *L) { lua_pop(L, 1); return 1; /* return 'package' table */ } - diff --git a/engines/sword25/util/lua/lobject.h b/engines/sword25/util/lua/lobject.h index 5418a918b1..70b2c754ea 100644 --- a/engines/sword25/util/lua/lobject.h +++ b/engines/sword25/util/lua/lobject.h @@ -378,4 +378,3 @@ LUAI_FUNC void luaO_chunkid (char *out, const char *source, size_t len); #endif - diff --git a/engines/sword25/util/lua/lopcodes.cpp b/engines/sword25/util/lua/lopcodes.cpp index d9da16f689..255b2029e9 100644 --- a/engines/sword25/util/lua/lopcodes.cpp +++ b/engines/sword25/util/lua/lopcodes.cpp @@ -99,4 +99,3 @@ const lu_byte luaP_opmodes[NUM_OPCODES] = { ,opmode(0, 1, OpArgU, OpArgN, iABx) /* OP_CLOSURE */ ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_VARARG */ }; - diff --git a/engines/sword25/util/lua/loslib.cpp b/engines/sword25/util/lua/loslib.cpp index b61f8c65e1..25bfa2d1b5 100644 --- a/engines/sword25/util/lua/loslib.cpp +++ b/engines/sword25/util/lua/loslib.cpp @@ -243,4 +243,3 @@ LUALIB_API int luaopen_os (lua_State *L) { luaL_register(L, LUA_OSLIBNAME, syslib); return 1; } - diff --git a/engines/sword25/util/lua/lstate.cpp b/engines/sword25/util/lua/lstate.cpp index e542bcbacc..26bed7bec2 100644 --- a/engines/sword25/util/lua/lstate.cpp +++ b/engines/sword25/util/lua/lstate.cpp @@ -211,4 +211,3 @@ LUA_API void lua_close (lua_State *L) { luai_userstateclose(L); close_state(L); } - diff --git a/engines/sword25/util/lua/lstate.h b/engines/sword25/util/lua/lstate.h index 94a6249461..05ccb43d5e 100644 --- a/engines/sword25/util/lua/lstate.h +++ b/engines/sword25/util/lua/lstate.h @@ -166,4 +166,3 @@ LUAI_FUNC lua_State *luaE_newthread (lua_State *L); LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); #endif - diff --git a/engines/sword25/util/lua/lstring.cpp b/engines/sword25/util/lua/lstring.cpp index cd55cc63bf..046b87ee1c 100644 --- a/engines/sword25/util/lua/lstring.cpp +++ b/engines/sword25/util/lua/lstring.cpp @@ -108,4 +108,3 @@ Udata *luaS_newudata (lua_State *L, size_t s, Table *e) { G(L)->mainthread->next = obj2gco(u); return u; } - diff --git a/engines/sword25/util/lua/lstrlib.cpp b/engines/sword25/util/lua/lstrlib.cpp index 2a1b8690e2..bcc869cb98 100644 --- a/engines/sword25/util/lua/lstrlib.cpp +++ b/engines/sword25/util/lua/lstrlib.cpp @@ -865,4 +865,3 @@ LUALIB_API int luaopen_string (lua_State *L) { createmetatable(L); return 1; } - diff --git a/engines/sword25/util/lua/ltablib.cpp b/engines/sword25/util/lua/ltablib.cpp index 607c09ae71..93be9e6077 100644 --- a/engines/sword25/util/lua/ltablib.cpp +++ b/engines/sword25/util/lua/ltablib.cpp @@ -276,4 +276,3 @@ LUALIB_API int luaopen_table (lua_State *L) { luaL_register(L, LUA_TABLIBNAME, tab_funcs); return 1; } - diff --git a/engines/sword25/util/lua/ltm.cpp b/engines/sword25/util/lua/ltm.cpp index 02856a58fc..60ca76689a 100644 --- a/engines/sword25/util/lua/ltm.cpp +++ b/engines/sword25/util/lua/ltm.cpp @@ -72,4 +72,3 @@ const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) { } return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : luaO_nilobject); } - diff --git a/engines/sword25/util/lua/luaconf.h b/engines/sword25/util/lua/luaconf.h index f3509e969b..f5affe9fd7 100644 --- a/engines/sword25/util/lua/luaconf.h +++ b/engines/sword25/util/lua/luaconf.h @@ -723,4 +723,3 @@ union luai_Cast { double l_d; long l_l; }; #endif - diff --git a/engines/sword25/util/lua/lvm.cpp b/engines/sword25/util/lua/lvm.cpp index d0f2198651..d538d0b349 100644 --- a/engines/sword25/util/lua/lvm.cpp +++ b/engines/sword25/util/lua/lvm.cpp @@ -760,4 +760,3 @@ void luaV_execute (lua_State *L, int nexeccalls) { } } } - diff --git a/engines/sword25/util/lua/lzio.cpp b/engines/sword25/util/lua/lzio.cpp index e1e7b28a29..d05c613897 100644 --- a/engines/sword25/util/lua/lzio.cpp +++ b/engines/sword25/util/lua/lzio.cpp @@ -78,5 +78,3 @@ char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n) { } return buff->buffer; } - - diff --git a/engines/sword25/util/pluto/CHANGELOG b/engines/sword25/util/pluto/CHANGELOG index e31ed26044..1be321f898 100644 --- a/engines/sword25/util/pluto/CHANGELOG +++ b/engines/sword25/util/pluto/CHANGELOG @@ -35,4 +35,3 @@ Earlier versions are changelogged on the LuaForge site. * Fixed all outstanding 5.0->5.1 conversion issues * Made heavier use of size_t in preference to int * Fixed GC/Upval issue (thanks to Eric Jacobs) - diff --git a/engines/sword25/util/pluto/FILEFORMAT b/engines/sword25/util/pluto/FILEFORMAT index b3f10ee603..e7716675c7 100644 --- a/engines/sword25/util/pluto/FILEFORMAT +++ b/engines/sword25/util/pluto/FILEFORMAT @@ -165,4 +165,4 @@ struct LocVar { Object name; /* Name of the local variable */ int startpc; /* Point where variable is active */ int endpc; /* Point where variable is dead */ -};
\ No newline at end of file +}; diff --git a/engines/sword25/util/pluto/THANKS b/engines/sword25/util/pluto/THANKS index fea3595dbf..443713fa61 100644 --- a/engines/sword25/util/pluto/THANKS +++ b/engines/sword25/util/pluto/THANKS @@ -7,4 +7,3 @@ Goran Adrinek Eric Jacobs Anolan Milanes Malte Thiesen - diff --git a/engines/sword25/util/pluto/plzio.cpp b/engines/sword25/util/pluto/plzio.cpp index 0efc3dfcf2..21f69a9e8d 100644 --- a/engines/sword25/util/pluto/plzio.cpp +++ b/engines/sword25/util/pluto/plzio.cpp @@ -72,5 +72,3 @@ char *pdep_openspace (lua_State *L, Mbuffer *buff, size_t n) { } return buff->buffer; } - - diff --git a/engines/teenagent/animation.cpp b/engines/teenagent/animation.cpp index e945bda1e5..56107b67ca 100644 --- a/engines/teenagent/animation.cpp +++ b/engines/teenagent/animation.cpp @@ -106,11 +106,11 @@ void Animation::free() { index = 0; } -void Animation::load(Common::SeekableReadStream *s, Type type) { +void Animation::load(Common::SeekableReadStream &s, Type type) { //fixme: do not reload the same animation each time free(); - if (s == NULL || s->size() <= 1) { + if (s.size() <= 1) { debug(1, "empty animation"); return; } @@ -119,29 +119,29 @@ void Animation::load(Common::SeekableReadStream *s, Type type) { int off = 0; switch (type) { case kTypeLan: - data_size = s->readUint16LE(); - if (s->eos()) { + data_size = s.readUint16LE(); + if (s.eos()) { debug(1, "empty animation"); return; } data_size -= 2; data = new byte[data_size]; - data_size = s->read(data, data_size); + data_size = s.read(data, data_size); /* for (int i = 0; i < data_size; ++i) { debug(0, "%02x ", data[i]); } debug(0, ", %u frames", data_size / 3); */ - frames_count = s->readByte(); + frames_count = s.readByte(); debug(1, "%u physical frames", frames_count); if (frames_count == 0) return; frames = new Surface[frames_count]; - s->skip(frames_count * 2 - 2); //sizes - /*pos = */s->readUint16LE(); + s.skip(frames_count * 2 - 2); //sizes + /*pos = */s.readUint16LE(); //debug(0, "pos?: %04x", pos); for (uint16 i = 0; i < frames_count; ++i) { @@ -152,15 +152,15 @@ void Animation::load(Common::SeekableReadStream *s, Type type) { break; case kTypeInventory: { - data_size = 3 * s->readByte(); + data_size = 3 * s.readByte(); data = new byte[data_size]; frames_count = 0; for (byte i = 0; i < data_size / 3; ++i) { int idx = i * 3; /* byte unk = */ - s->readByte(); - data[idx] = s->readByte(); + s.readByte(); + data[idx] = s.readByte(); if (data[idx] == 0) data[idx] = 1; //fixme: investigate if (data[idx] > frames_count) @@ -179,17 +179,17 @@ void Animation::load(Common::SeekableReadStream *s, Type type) { break; case kTypeVaria: - frames_count = s->readByte(); + frames_count = s.readByte(); debug(1, "loading varia resource, %u physical frames", frames_count); uint16 offset[255]; for (byte i = 0; i < frames_count; ++i) { - offset[i] = s->readUint16LE(); + offset[i] = s.readUint16LE(); //debug(0, "%u: %04x", i, offset[i]); } frames = new Surface[frames_count]; for (uint16 i = 0; i < frames_count; ++i) { //debug(0, "%04x", offset[i]); - s->seek(offset[i] + off); + s.seek(offset[i] + off); frames[i].load(s, Surface::kTypeOns); } diff --git a/engines/teenagent/animation.h b/engines/teenagent/animation.h index e98bb42ea0..d9092d1707 100644 --- a/engines/teenagent/animation.h +++ b/engines/teenagent/animation.h @@ -35,7 +35,7 @@ public: enum Type {kTypeLan, kTypeVaria, kTypeInventory}; Animation(); - void load(Common::SeekableReadStream *s, Type type = kTypeLan); + void load(Common::SeekableReadStream&, Type type = kTypeLan); void free(); Surface *firstFrame(); diff --git a/engines/teenagent/detection.cpp b/engines/teenagent/detection.cpp index 72a338664b..fa5a578636 100644 --- a/engines/teenagent/detection.cpp +++ b/engines/teenagent/detection.cpp @@ -177,9 +177,8 @@ public: ssd.setDeletableFlag(true); //checking for the thumbnail - Common::ScopedPtr<Graphics::Surface> thumb(new Graphics::Surface); - if (Graphics::loadThumbnail(*in, *thumb)) - ssd.setThumbnail(thumb.release()); + if (Graphics::Surface *const thumb = Graphics::loadThumbnail(*in)) + ssd.setThumbnail(thumb); return ssd; } diff --git a/engines/teenagent/font.h b/engines/teenagent/font.h index 773edaf4e2..5146ace21f 100644 --- a/engines/teenagent/font.h +++ b/engines/teenagent/font.h @@ -47,4 +47,3 @@ private: } // End of namespace TeenAgent #endif - diff --git a/engines/teenagent/inventory.cpp b/engines/teenagent/inventory.cpp index 4951b2d940..2b858bbb4d 100644 --- a/engines/teenagent/inventory.cpp +++ b/engines/teenagent/inventory.cpp @@ -43,7 +43,7 @@ Inventory::Inventory(TeenAgentEngine *engine) { if (!s) error("no inventory background"); debug(0, "loading inventory background..."); - _background.load(s, Surface::kTypeOns); + _background.load(*s, Surface::kTypeOns); } uint32 items_size = varia.getSize(4); @@ -300,13 +300,13 @@ void Inventory::Item::load(Inventory *inventory, uint item_id) { if (_animation.empty()) { debug(0, "loading item %d from offset %x", obj->id, inventory->_offset[obj->id - 1]); Common::MemoryReadStream s(inventory->_items + inventory->_offset[obj->id - 1], inventory->_offset[obj->id] - inventory->_offset[obj->id - 1]); - _animation.load(&s, Animation::kTypeInventory); + _animation.load(s, Animation::kTypeInventory); } } else { if (_surface.empty()) { debug(0, "loading item %d from offset %x", obj->id, inventory->_offset[obj->id - 1]); Common::MemoryReadStream s(inventory->_items + inventory->_offset[obj->id - 1], inventory->_offset[obj->id] - inventory->_offset[obj->id - 1]); - _surface.load(&s, Surface::kTypeOns); + _surface.load(s, Surface::kTypeOns); } } } diff --git a/engines/teenagent/scene.cpp b/engines/teenagent/scene.cpp index 4be6c9c31a..39b77ea447 100644 --- a/engines/teenagent/scene.cpp +++ b/engines/teenagent/scene.cpp @@ -57,7 +57,7 @@ Scene::Scene(TeenAgentEngine *engine, OSystem *system) : intro(false), _id(0), o if (!s) error("invalid resource data"); - teenagent.load(s, Animation::kTypeVaria); + teenagent.load(*s, Animation::kTypeVaria); if (teenagent.empty()) error("invalid mark animation"); @@ -65,7 +65,7 @@ Scene::Scene(TeenAgentEngine *engine, OSystem *system) : intro(false), _id(0), o if (!s) error("invalid resource data"); - teenagent_idle.load(s, Animation::kTypeVaria); + teenagent_idle.load(*s, Animation::kTypeVaria); if (teenagent_idle.empty()) error("invalid mark animation"); @@ -340,7 +340,7 @@ void Scene::loadOns() { for (uint32 i = 0; i < ons_count; ++i) { Common::ScopedPtr<Common::SeekableReadStream> s(res->ons.getStream(on_id[i])); if (s) { - ons[i].load(s, Surface::kTypeOns); + ons[i].load(*s, Surface::kTypeOns); } } } @@ -363,7 +363,7 @@ void Scene::loadLans() { Common::ScopedPtr<Common::SeekableReadStream> s(res->loadLan000(res_id)); if (s) { - animation[i].load(s, Animation::kTypeLan); + animation[i].load(*s, Animation::kTypeLan); if (bxv != 0 && bxv != 0xff) animation[i].id = bxv; } @@ -412,7 +412,7 @@ void Scene::init(int id, const Common::Point &pos) { sub_hack = 2; } } - on.load(stream, SurfaceList::kTypeOn, sub_hack); + on.load(*stream, SurfaceList::kTypeOn, sub_hack); loadOns(); loadLans(); @@ -434,7 +434,7 @@ void Scene::playAnimation(byte idx, uint id, bool loop, bool paused, bool ignore if (!s) error("playing animation %u failed", id); - custom_animation[idx].load(s); + custom_animation[idx].load(*s); custom_animation[idx].loop = loop; custom_animation[idx].paused = paused; custom_animation[idx].ignore = ignore; @@ -446,7 +446,7 @@ void Scene::playActorAnimation(uint id, bool loop, bool ignore) { if (!s) error("playing animation %u failed", id); - actor_animation.load(s); + actor_animation.load(*s); actor_animation.loop = loop; actor_animation.ignore = ignore; actor_animation.id = id; diff --git a/engines/teenagent/surface.cpp b/engines/teenagent/surface.cpp index 2e23c7a8ed..e8b5a8ad59 100644 --- a/engines/teenagent/surface.cpp +++ b/engines/teenagent/surface.cpp @@ -33,26 +33,26 @@ Surface::~Surface() { free(); } -void Surface::load(Common::SeekableReadStream *stream, Type type) { +void Surface::load(Common::SeekableReadStream &stream, Type type) { //debug(0, "load()"); free(); x = y = 0; - uint16 w_ = stream->readUint16LE(); - uint16 h_ = stream->readUint16LE(); + uint16 w_ = stream.readUint16LE(); + uint16 h_ = stream.readUint16LE(); if (type != kTypeLan) { - uint16 pos = stream->readUint16LE(); + uint16 pos = stream.readUint16LE(); x = pos % 320; y = pos / 320; } //debug(0, "declared info: %ux%u (%04xx%04x) -> %u,%u", w_, h_, w_, h_, x, y); - if (stream->eos() || w_ == 0) + if (stream.eos() || w_ == 0) return; - if (w_ * h_ > stream->size()) { + if (w_ * h_ > stream.size()) { debug(0, "invalid surface %ux%u -> %u,%u", w_, h_, x, y); return; } @@ -60,7 +60,7 @@ void Surface::load(Common::SeekableReadStream *stream, Type type) { //debug(0, "creating surface %ux%u -> %u,%u", w_, h_, x, y); create(w_, h_, Graphics::PixelFormat::createFormatCLUT8()); - stream->read(pixels, w_ * h_); + stream.read(pixels, w_ * h_); } Common::Rect Surface::render(Graphics::Surface *surface, int dx, int dy, bool mirror, Common::Rect src_rect, uint zoom) const { diff --git a/engines/teenagent/surface.h b/engines/teenagent/surface.h index 5f74176c68..64e45a7330 100644 --- a/engines/teenagent/surface.h +++ b/engines/teenagent/surface.h @@ -40,7 +40,7 @@ public: Surface(); ~Surface(); - void load(Common::SeekableReadStream *stream, Type type); + void load(Common::SeekableReadStream&, Type type); Common::Rect render(Graphics::Surface *surface, int dx = 0, int dy = 0, bool mirror = false, Common::Rect src_rect = Common::Rect(), uint zoom = 256) const; bool empty() const { return pixels == NULL; } diff --git a/engines/teenagent/surface_list.cpp b/engines/teenagent/surface_list.cpp index e98153a935..7f7eb1dc38 100644 --- a/engines/teenagent/surface_list.cpp +++ b/engines/teenagent/surface_list.cpp @@ -31,11 +31,11 @@ SurfaceList::~SurfaceList() { free(); } -void SurfaceList::load(Common::SeekableReadStream *stream, Type type, int sub_hack) { +void SurfaceList::load(Common::SeekableReadStream &stream, Type type, int sub_hack) { free(); - byte fn = stream->readByte(); - if (stream->eos()) + byte fn = stream.readByte(); + if (stream.eos()) return; surfaces_n = fn - sub_hack; @@ -47,11 +47,11 @@ void SurfaceList::load(Common::SeekableReadStream *stream, Type type, int sub_ha surfaces = new Surface[surfaces_n]; for (byte i = 0; i < surfaces_n; ++i) { - uint offset = stream->readUint16LE(); - uint pos = stream->pos(); - stream->seek(offset); + uint offset = stream.readUint16LE(); + uint pos = stream.pos(); + stream.seek(offset); surfaces[i].load(stream, Surface::kTypeOns); - stream->seek(pos); + stream.seek(pos); } } diff --git a/engines/teenagent/surface_list.h b/engines/teenagent/surface_list.h index d949a722d6..fcb4fb25c5 100644 --- a/engines/teenagent/surface_list.h +++ b/engines/teenagent/surface_list.h @@ -33,7 +33,7 @@ public: SurfaceList(); ~SurfaceList(); - void load(Common::SeekableReadStream *stream, Type type, int sub_hack = 0); + void load(Common::SeekableReadStream&, Type type, int sub_hack = 0); void free(); void render(Graphics::Surface *surface, const Common::Rect & clip) const; @@ -45,4 +45,3 @@ protected: } #endif - diff --git a/engines/teenagent/teenagent.cpp b/engines/teenagent/teenagent.cpp index 0289b994e6..e6a248334c 100644 --- a/engines/teenagent/teenagent.cpp +++ b/engines/teenagent/teenagent.cpp @@ -386,7 +386,7 @@ bool TeenAgentEngine::showLogo() { } Surface s; - s.load(frame, Surface::kTypeOns); + s.load(*frame, Surface::kTypeOns); if (s.empty()) { free(bg); return true; diff --git a/engines/testbed/misc.cpp b/engines/testbed/misc.cpp index 034d3eb27e..aee3ccd294 100644 --- a/engines/testbed/misc.cpp +++ b/engines/testbed/misc.cpp @@ -110,7 +110,7 @@ TestExitStatus MiscTests::testDateTime() { TestExitStatus MiscTests::testTimers() { int valToModify = 0; - if (g_system->getTimerManager()->installTimerProc(timerCallback, 100000, &valToModify)) { + if (g_system->getTimerManager()->installTimerProc(timerCallback, 100000, &valToModify, "testbedTimer")) { g_system->delayMillis(150); g_system->getTimerManager()->removeTimerProc(timerCallback); @@ -133,7 +133,7 @@ TestExitStatus MiscTests::testMutexes() { SharedVars sv = {1, 1, true, g_system->createMutex()}; - if (g_system->getTimerManager()->installTimerProc(criticalSection, 100000, &sv)) { + if (g_system->getTimerManager()->installTimerProc(criticalSection, 100000, &sv, "testbedMutex")) { g_system->delayMillis(150); } diff --git a/engines/tinsel/adpcm.cpp b/engines/tinsel/adpcm.cpp index 4ea835586b..ca3150ca3d 100644 --- a/engines/tinsel/adpcm.cpp +++ b/engines/tinsel/adpcm.cpp @@ -61,7 +61,7 @@ void Tinsel_ADPCMStream::readBufferTinselHeader() { int16 Tinsel_ADPCMStream::decodeTinsel(int16 code, double eVal) { double sample; - sample = (double) code; + sample = (double)code; sample *= eVal * _status.predictor; sample += (_status.d0 * _status.K0) + (_status.d1 * _status.K1); diff --git a/engines/tinsel/coroutine.cpp b/engines/tinsel/coroutine.cpp index 998d98b52a..ef0097f043 100644 --- a/engines/tinsel/coroutine.cpp +++ b/engines/tinsel/coroutine.cpp @@ -80,4 +80,3 @@ CoroBaseContext::~CoroBaseContext() { } } // End of namespace Tinsel - diff --git a/engines/tinsel/detection.cpp b/engines/tinsel/detection.cpp index 9c52305a1c..1fce032633 100644 --- a/engines/tinsel/detection.cpp +++ b/engines/tinsel/detection.cpp @@ -322,9 +322,21 @@ int TinselMetaEngine::getMaximumSaveSlot() const { return 99; } void TinselMetaEngine::removeSaveState(const char *target, int slot) const { Tinsel::setNeedLoad(); - Tinsel::getList(g_system->getSavefileManager(), target); + // Same issue here as with loadGameState(): we need the physical savegame + // slot. Refer to bug #3387551. + int listSlot = -1; + const int numStates = Tinsel::getList(g_system->getSavefileManager(), target); + for (int i = 0; i < numStates; ++i) { + const char *fileName = Tinsel::ListEntry(i, Tinsel::LE_NAME); + const int saveSlot = atoi(fileName + strlen(fileName) - 3); + + if (saveSlot == slot) { + listSlot = i; + break; + } + } - g_system->getSavefileManager()->removeSavefile(Tinsel::ListEntry(slot, Tinsel::LE_NAME)); + g_system->getSavefileManager()->removeSavefile(Tinsel::ListEntry(listSlot, Tinsel::LE_NAME)); Tinsel::setNeedLoad(); Tinsel::getList(g_system->getSavefileManager(), target); } 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/tinsel/saveload.cpp b/engines/tinsel/saveload.cpp index 7a973ba4be..4ac172be43 100644 --- a/engines/tinsel/saveload.cpp +++ b/engines/tinsel/saveload.cpp @@ -154,8 +154,15 @@ static bool syncSaveGameHeader(Common::Serializer &s, SaveGameHeader &hdr) { syncTime(s, hdr.dateTime); int tmp = hdr.size - s.bytesSynced(); + + // NOTE: We can't use SAVEGAME_ID here when attempting to remove a saved game from the launcher, + // as there is no TinselEngine initialized then. This means that we can't check if this is a DW1 + // or DW2 savegame in this case, but it doesn't really matter, as the saved game is about to be + // deleted anyway. Refer to bug #3387551. + bool correctID = _vm ? (hdr.id == SAVEGAME_ID) : (hdr.id == DW1_SAVEGAME_ID || hdr.id == DW2_SAVEGAME_ID); + // Perform sanity check - if (tmp < 0 || hdr.id != SAVEGAME_ID || hdr.ver > CURRENT_VER || hdr.size > 1024) + if (tmp < 0 || !correctID || hdr.ver > CURRENT_VER || hdr.size > 1024) return false; // Skip over any extra bytes s.skip(tmp); diff --git a/engines/tinsel/strres.h b/engines/tinsel/strres.h index a63824a863..f6e86951b6 100644 --- a/engines/tinsel/strres.h +++ b/engines/tinsel/strres.h @@ -96,4 +96,3 @@ SCNHANDLE LanguageFlag(LANGUAGE thisOne); } // End of namespace Tinsel #endif - diff --git a/engines/tinsel/tinsel.h b/engines/tinsel/tinsel.h index 30b060766e..e18216cdf7 100644 --- a/engines/tinsel/tinsel.h +++ b/engines/tinsel/tinsel.h @@ -31,9 +31,6 @@ #include "common/random.h" #include "common/util.h" -#include "audio/mididrv.h" -#include "audio/mixer.h" - #include "engines/engine.h" #include "tinsel/debugger.h" #include "tinsel/graphics.h" @@ -53,6 +50,7 @@ namespace Tinsel { class BMVPlayer; class Config; +class MidiDriver; class MidiMusicPlayer; class PCMMusicPlayer; class Scheduler; diff --git a/engines/toon/audio.cpp b/engines/toon/audio.cpp index 0bf3316209..4a4a84e62c 100644 --- a/engines/toon/audio.cpp +++ b/engines/toon/audio.cpp @@ -613,4 +613,3 @@ void AudioManager::updateAmbientSFX() } } // End of namespace Toon - diff --git a/engines/toon/character.cpp b/engines/toon/character.cpp index 06c6e21d21..7d9a31c170 100644 --- a/engines/toon/character.cpp +++ b/engines/toon/character.cpp @@ -596,7 +596,8 @@ int32 Character::getId() { void Character::save(Common::WriteStream *stream) { debugC(1, kDebugCharacter, "save(stream)"); - stream->writeSint32LE(_flags); + // we have to save visibility too, put in flags to not invalidate old savegames. + stream->writeSint32LE(_flags | ((_visible == false) ? 0x100 : 0)); stream->writeSint32LE(_x); stream->writeSint32LE(_y); stream->writeSint32LE(_z); @@ -633,6 +634,12 @@ void Character::load(Common::ReadStream *stream) { if (_sceneAnimationId > -1) { setAnimationInstance(_vm->getSceneAnimation(_sceneAnimationId)->_animInstance); } + + // "not visible" flag. + if (_flags & 0x100) { + _flags &= ~0x100; + setVisible(false); + } } void Character::setAnimScript(int32 animScriptId) { @@ -1102,4 +1109,3 @@ void Character::updateIdle() { } } } // End of namespace Toon - diff --git a/engines/toon/detection.cpp b/engines/toon/detection.cpp index 810a37720a..ac4caae8b2 100644 --- a/engines/toon/detection.cpp +++ b/engines/toon/detection.cpp @@ -224,12 +224,7 @@ SaveStateDescriptor ToonMetaEngine::querySaveMetaInfos(const char *target, int s SaveStateDescriptor desc(slot, saveName); - Graphics::Surface *thumbnail = new Graphics::Surface(); - assert(thumbnail); - if (!Graphics::loadThumbnail(*file, *thumbnail)) { - delete thumbnail; - thumbnail = 0; - } + Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*file); desc.setThumbnail(thumbnail); desc.setDeletableFlag(true); diff --git a/engines/toon/drew.cpp b/engines/toon/drew.cpp index 89438fb35c..df5cfcfa03 100644 --- a/engines/toon/drew.cpp +++ b/engines/toon/drew.cpp @@ -129,4 +129,3 @@ void CharacterDrew::resetScale() setPosition(_x, _y); } } // End of namespace Toon - diff --git a/engines/toon/hotspot.cpp b/engines/toon/hotspot.cpp index 62458ad800..ee81b87417 100644 --- a/engines/toon/hotspot.cpp +++ b/engines/toon/hotspot.cpp @@ -149,4 +149,3 @@ HotspotData *Hotspots::Get(int32 id) { } } // End of namespace Toon - diff --git a/engines/toon/movie.cpp b/engines/toon/movie.cpp index 2318eaaac7..7637f4e62f 100644 --- a/engines/toon/movie.cpp +++ b/engines/toon/movie.cpp @@ -94,7 +94,7 @@ void Movie::play(Common::String video, int32 flags) { _vm->getAudioManager()->setMusicVolume(0); _decoder->loadFile(video.c_str()); playVideo(isFirstIntroVideo); - _vm->flushPalette(false); + _vm->flushPalette(true); if (flags & 1) _vm->getAudioManager()->setMusicVolume(_vm->getAudioManager()->isMusicMuted() ? 0 : 255); _decoder->close(); @@ -103,7 +103,6 @@ void Movie::play(Common::String video, int32 flags) { bool Movie::playVideo(bool isFirstIntroVideo) { debugC(1, kDebugMovie, "playVideo(isFirstIntroVideo: %d)", isFirstIntroVideo); - while (!_vm->shouldQuit() && !_decoder->endOfVideo()) { if (_decoder->needsUpdate()) { const Graphics::Surface *frame = _decoder->decodeNextFrame(); diff --git a/engines/toon/path.cpp b/engines/toon/path.cpp index 43a134e39b..60ca007930 100644 --- a/engines/toon/path.cpp +++ b/engines/toon/path.cpp @@ -28,54 +28,69 @@ namespace Toon { PathFindingHeap::PathFindingHeap() { _count = 0; - _alloc = 0; + _size = 0; _data = NULL; } PathFindingHeap::~PathFindingHeap() { - delete[] _data; + free(_data); } -int32 PathFindingHeap::init(int32 size) { +void PathFindingHeap::init(int32 size) { debugC(1, kDebugPath, "init(%d)", size); + _size = size; - delete[] _data; - _data = new HeapDataGrid[size * 2]; - memset(_data, 0, sizeof(HeapDataGrid) * size * 2); + free(_data); + _data = (HeapDataGrid *)malloc(sizeof(HeapDataGrid) * _size); + memset(_data, 0, sizeof(HeapDataGrid) * _size); _count = 0; - _alloc = size; - return size; } -int32 PathFindingHeap::unload() { - delete[] _data; +void PathFindingHeap::unload() { + _count = 0; + _size = 0; + free(_data); _data = NULL; - return 0; } -int32 PathFindingHeap::clear() { - //debugC(1, kDebugPath, "clear()"); +void PathFindingHeap::clear() { + debugC(1, kDebugPath, "clear()"); _count = 0; - memset(_data, 0, sizeof(HeapDataGrid) * _alloc * 2); - return 1; + memset(_data, 0, sizeof(HeapDataGrid) * _size); } -int32 PathFindingHeap::push(int32 x, int32 y, int32 weight) { - //debugC(6, kDebugPath, "push(%d, %d, %d)", x, y, weight); +void PathFindingHeap::push(int32 x, int32 y, int32 weight) { + debugC(2, kDebugPath, "push(%d, %d, %d)", x, y, weight); + + if (_count == _size) { + // 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; + } - _count++; _data[_count]._x = x; _data[_count]._y = y; _data[_count]._weight = weight; + _count++; - int32 lMax = _count; + int32 lMax = _count-1; int32 lT = 0; while (1) { - lT = lMax / 2; - if (lT < 1) + if (lMax <= 0) break; + lT = (lMax-1) / 2; if (_data[lT]._weight > _data[lMax]._weight) { HeapDataGrid temp; @@ -87,31 +102,31 @@ int32 PathFindingHeap::push(int32 x, int32 y, int32 weight) { break; } } - return 1; } -int32 PathFindingHeap::pop(int32 *x, int32 *y, int32 *weight) { - //debugC(6, kDebugPath, "pop(x, y, weight)"); +void PathFindingHeap::pop(int32 *x, int32 *y, int32 *weight) { + debugC(2, kDebugPath, "pop(x, y, weight)"); - if (!_count) - return 0; + if (!_count) { + warning("Attempt to pop empty PathFindingHeap!"); + return; + } - *x = _data[1]._x; - *y = _data[1]._y; - *weight = _data[1]._weight; + *x = _data[0]._x; + *y = _data[0]._y; + *weight = _data[0]._weight; - _data[1] = _data[_count]; - _count--; + _data[0] = _data[--_count]; if (!_count) - return 0; + return; - int32 lMin = 1; - int32 lT = 1; + int32 lMin = 0; + int32 lT = 0; while (1) { - lT = lMin << 1; - if (lT <= _count) { - if (lT < _count) { + lT = (lMin << 1) + 1; + if (lT < _count) { + if (lT < _count-1) { if (_data[lT + 1]._weight < _data[lT]._weight) lT++; } @@ -129,7 +144,6 @@ int32 PathFindingHeap::pop(int32 *x, int32 *y, int32 *weight) { break; } } - return 0; } PathFinding::PathFinding(ToonEngine *vm) : _vm(vm) { @@ -164,7 +178,7 @@ bool PathFinding::isLikelyWalkable(int32 x, int32 y) { } bool PathFinding::isWalkable(int32 x, int32 y) { - //debugC(6, kDebugPath, "isWalkable(%d, %d)", x, y); + debugC(2, kDebugPath, "isWalkable(%d, %d)", x, y); bool maskWalk = (_currentMask->getData(x, y) & 0x1f) > 0; @@ -299,7 +313,7 @@ int32 PathFinding::findPath(int32 x, int32 y, int32 destx, int32 desty) { _heap->push(curX, curY, abs(destx - x) + abs(desty - y)); int wei = 0; - while (_heap->_count) { + while (_heap->getCount()) { wei = 0; _heap->pop(&curX, &curY, &curWeight); int curNode = curX + curY * _width; @@ -424,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/toon/path.h b/engines/toon/path.h index 329127c9ce..2de58064f0 100644 --- a/engines/toon/path.h +++ b/engines/toon/path.h @@ -38,17 +38,18 @@ public: PathFindingHeap(); ~PathFindingHeap(); - int32 _alloc; - int32 _count; - - int32 push(int32 x, int32 y, int32 weight); - int32 pop(int32 *x, int32 *y, int32 *weight); - int32 init(int32 size); - int32 clear(); - int32 unload(); + void push(int32 x, int32 y, int32 weight); + void pop(int32 *x, int32 *y, int32 *weight); + void init(int32 size); + void clear(); + void unload(); + int32 getCount() { return _count; } private: HeapDataGrid *_data; + + int32 _size; + int32 _count; }; class PathFinding { diff --git a/engines/toon/picture.cpp b/engines/toon/picture.cpp index 0257964fb5..295e304765 100644 --- a/engines/toon/picture.cpp +++ b/engines/toon/picture.cpp @@ -29,16 +29,14 @@ namespace Toon { -bool Picture::loadPicture(Common::String file, bool totalPalette /*= false*/) { - debugC(1, kDebugPicture, "loadPicture(%s, %d)", file.c_str(), (totalPalette) ? 1 : 0); +bool Picture::loadPicture(Common::String file) { + debugC(1, kDebugPicture, "loadPicture(%s)", file.c_str()); uint32 size = 0; uint8 *fileData = _vm->resources()->getFileData(file, &size); if (!fileData) return false; - _useFullPalette = totalPalette; - uint32 compId = READ_BE_UINT32(fileData); switch (compId) { @@ -57,6 +55,8 @@ bool Picture::loadPicture(Common::String file, bool totalPalette /*= false*/) { // do we have a palette ? _paletteEntries = (dstsize & 0x7ff) / 3; + _useFullPalette = (_paletteEntries == 256); + // _useFullPalette = true; if (_paletteEntries) { _palette = new uint8[_paletteEntries * 3]; memcpy(_palette, _data + dstsize - (dstsize & 0x7ff), _paletteEntries * 3); @@ -70,7 +70,8 @@ bool Picture::loadPicture(Common::String file, bool totalPalette /*= false*/) { uint32 decSize = READ_LE_UINT32(fileData + 10); _data = new uint8[decSize + 100]; _paletteEntries = READ_LE_UINT16(fileData + 14) / 3; - + _useFullPalette = (_paletteEntries == 256); + if (_paletteEntries) { _palette = new uint8[_paletteEntries * 3]; memcpy(_palette, fileData + 16, _paletteEntries * 3); diff --git a/engines/toon/picture.h b/engines/toon/picture.h index 23edbc91da..ee0e006702 100644 --- a/engines/toon/picture.h +++ b/engines/toon/picture.h @@ -38,7 +38,7 @@ class Picture { public: Picture(ToonEngine *vm); ~Picture(); - bool loadPicture(Common::String file, bool totalPalette = false); + bool loadPicture(Common::String file); void setupPalette(); void draw(Graphics::Surface &surface, int32 x, int32 y, int32 dx, int32 dy); void drawWithRectList(Graphics::Surface& surface, int32 x, int32 y, int32 dx, int32 dy, Common::Array<Common::Rect>& rectArray); diff --git a/engines/toon/script.cpp b/engines/toon/script.cpp index eed781295a..69ae727bb5 100644 --- a/engines/toon/script.cpp +++ b/engines/toon/script.cpp @@ -502,4 +502,3 @@ void EMCInterpreter::loadState(EMCState *script, Common::ReadStream *stream) { } } // End of namespace Toon - diff --git a/engines/toon/script.h b/engines/toon/script.h index 9dd00dca80..8ef085f383 100644 --- a/engines/toon/script.h +++ b/engines/toon/script.h @@ -148,4 +148,3 @@ private: } // End of namespace Toon #endif - diff --git a/engines/toon/toon.cpp b/engines/toon/toon.cpp index 26639d71f7..cff6c24469 100644 --- a/engines/toon/toon.cpp +++ b/engines/toon/toon.cpp @@ -614,7 +614,7 @@ struct MainMenuEntry { bool ToonEngine::showMainmenu(bool &loadedGame) { Picture *mainmenuPicture = new Picture(this); - mainmenuPicture->loadPicture("TITLESCR.CPS", true); + mainmenuPicture->loadPicture("TITLESCR.CPS"); mainmenuPicture->setupPalette(); flushPalette(false); @@ -690,6 +690,11 @@ bool ToonEngine::showMainmenu(bool &loadedGame) { } } + if (_needPaletteFlush) { + flushPalette(false); + _needPaletteFlush = false; + } + parseInput(); copyToVirtualScreen(true); _system->delayMillis(17); @@ -1547,7 +1552,7 @@ void ToonEngine::clickEvent() { return; } } else { - if (!_drew->walkTo(_mouseX, _mouseY)) { + if (!_drew->walkTo(_mouseX + _gameState->_currentScrollValue, _mouseY)) { // walk was canceled ? return; } @@ -2600,7 +2605,7 @@ int32 ToonEngine::showInventory() { delete _inventoryPicture; _inventoryPicture = new Picture(this); fadeOut(5); - _inventoryPicture->loadPicture("SACK128.CPS", true); + _inventoryPicture->loadPicture("SACK128.CPS"); _inventoryPicture->setupPalette(); dirtyAllScreen(); @@ -2786,7 +2791,7 @@ void ToonEngine::showCutaway(Common::String cutawayPicture) { if (cutawayPicture == "") { cutawayPicture = Common::String(_gameState->_locations[_gameState->_currentScene]._cutaway) + ".CPS"; } - _currentCutaway->loadPicture(cutawayPicture, false); + _currentCutaway->loadPicture(cutawayPicture); _currentCutaway->setupPalette(); _oldScrollValue = _gameState->_currentScrollValue; _gameState->_currentScrollValue = 0; @@ -3418,7 +3423,7 @@ void ToonEngine::viewInventoryItem(Common::String str, int32 lineId, int32 itemD fadeOut(5); Picture *pic = new Picture(this); - pic->loadPicture(str, false); + pic->loadPicture(str); pic->setupPalette(); dirtyAllScreen(); flushPalette(); diff --git a/engines/tsage/blue_force/blueforce_logic.cpp b/engines/tsage/blue_force/blueforce_logic.cpp new file mode 100644 index 0000000000..46c9307632 --- /dev/null +++ b/engines/tsage/blue_force/blueforce_logic.cpp @@ -0,0 +1,355 @@ +/* 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(50); + + _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: + return new Scene50(); + 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; + } +} + +/*--------------------------------------------------------------------------*/ + +AObjectArray::AObjectArray(): EventHandler() { + _inUse = false; + clear(); +} + +void AObjectArray::clear() { + for (int i = 0; i < OBJ_ARRAY_SIZE; ++i) + _objList[i] = NULL; +} + +void AObjectArray::synchronize(Serializer &s) { + EventHandler::synchronize(s); + for (int i = 0; i < OBJ_ARRAY_SIZE; ++i) + SYNC_POINTER(_objList[i]); +} + +void AObjectArray::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 AObjectArray::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; +} + +int AObjectArray::getNewIndex() { + for (int i = 0; i < OBJ_ARRAY_SIZE; ++i) { + if (!_objList[i]) + return i; + } + error("AObjectArray too full."); +} + +void AObjectArray::add(EventHandler *obj) { + int idx = getNewIndex(); + _objList[idx] = obj; +} + +void AObjectArray::remove(EventHandler *obj) { + for (int i = 0; i < OBJ_ARRAY_SIZE; ++i) { + if (_objList[i] == obj) { + _objList[i] = NULL; + return; + } + } +} + +/*--------------------------------------------------------------------------*/ + +Timer::Timer() { + _endFrame = 0; + _endAction = NULL; + _tickAction = NULL; +} + +void Timer::remove() { + _endFrame = 0; + _endAction = NULL; + + ((Scene100 *)BF_GLOBALS._sceneManager._scene)->removeTimer(this); +} + +void Timer::signal() { + assert(_endAction); + Action *action = _endAction; + remove(); + action->signal(); +} + +void Timer::dispatch() { + if (_tickAction) + _tickAction->dispatch(); + + if (_endFrame) { + uint32 frameNumber = BF_GLOBALS._events.getFrameNumber(); + if (frameNumber > _endFrame) + // Timer has expired + signal(); + } +} + +void Timer::set(uint32 delay, Action *action) { + assert(delay != 0); + + _endFrame = BF_GLOBALS._sceneHandler->getFrameDifference() + delay; + _endAction = action; + + ((SceneExt *)BF_GLOBALS._sceneManager._scene)->addTimer(this); +} + +/*--------------------------------------------------------------------------*/ + +void SceneItemType1::process(Event &event) { + if (_action) + _action->process(event); +} + +void SceneItemType1::startMove(SceneObject *sceneObj, va_list va) { + warning("TODO: sub_1621C"); +} + +/*--------------------------------------------------------------------------*/ + +void SceneItemType2::startMove(SceneObject *sceneObj, va_list va) { +} + +/*--------------------------------------------------------------------------*/ + +SceneExt::SceneExt(): Scene() { + warning("TODO: dword_503AA/dword_503AE/dword_53030"); + + _field372 = 0; + _field37A = 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() { + _timerList.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; +} + +/*--------------------------------------------------------------------------*/ + +void SceneHandlerExt::postInit(SceneObjectList *OwnerList) { + SceneHandler::postInit(OwnerList); + + // Load the low end palette data + GLOBALS._scenePalette.loadPalette(2); + GLOBALS._scenePalette.refresh(); +} + +void SceneHandlerExt::process(Event &event) { + SceneHandler::process(event); + + // TODO: All the new stuff from Blue Force +} + +} // End of namespace BlueForce + +} // End of namespace TsAGE diff --git a/engines/tsage/blue_force/blueforce_logic.h b/engines/tsage/blue_force/blueforce_logic.h new file mode 100644 index 0000000000..9ab8a87a0c --- /dev/null +++ b/engines/tsage/blue_force/blueforce_logic.h @@ -0,0 +1,137 @@ +/* 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_LOGIC_H +#define TSAGE_BLUEFORCE_LOGIC_H + +#include "common/scummsys.h" +#include "tsage/events.h" +#include "tsage/core.h" +#include "tsage/scenes.h" +#include "tsage/globals.h" + +#define BF_INTERFACE_Y 168 + +namespace TsAGE { + +namespace BlueForce { + +using namespace TsAGE; + +class BlueForceGame: public Game { +public: + virtual void start(); + virtual Scene *createScene(int sceneNumber); +}; + +#define OBJ_ARRAY_SIZE 10 +class AObjectArray: public EventHandler { +public: + EventHandler *_objList[OBJ_ARRAY_SIZE]; + bool _inUse; + int getNewIndex(); +public: + AObjectArray(); + void clear(); + + virtual Common::String getClassName() { return "AObjectArray"; } + virtual void synchronize(Serializer &s); + virtual void process(Event &event); + virtual void dispatch(); + + void add(EventHandler *obj); + void remove(EventHandler *obj); +}; + +class Timer: public EventHandler { +public: + Action *_tickAction; + Action *_endAction; + uint32 _endFrame; +public: + Timer(); + void set(uint32 delay, Action *action); + + virtual void remove(); + virtual void signal(); + virtual void dispatch(); +}; + +class SceneItemType1: public SceneItem { +public: + virtual void process(Event &event); + virtual void startMove(SceneObject *sceneObj, va_list va); +}; + +class SceneItemType2: public SceneItemType1 { +public: + virtual void startMove(SceneObject *sceneObj, va_list va); +}; + +class SceneExt: public Scene { +public: + AObjectArray _timerList, _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"); } + + void addTimer(Timer *timer) { _timerList.add(timer); } + void removeTimer(Timer *timer) { _timerList.remove(timer); } +}; + +class GameScene: public SceneExt { +public: + int _field412; + int _field794; +public: + GameScene(); + + virtual void postInit(SceneObjectList *OwnerList = NULL); + virtual void remove(); +}; + +class SceneHandlerExt: public SceneHandler { +public: + virtual void postInit(SceneObjectList *OwnerList = NULL); + virtual void process(Event &event); +}; + +class BlueAnimatedSpeaker: public Speaker { +public: +}; + +} // End of namespace BlueForce + +} // End of namespace TsAGE + +#endif diff --git a/engines/tsage/blue_force/blueforce_scenes0.cpp b/engines/tsage/blue_force/blueforce_scenes0.cpp new file mode 100644 index 0000000000..f1b714ec6c --- /dev/null +++ b/engines/tsage/blue_force/blueforce_scenes0.cpp @@ -0,0 +1,501 @@ +/* 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_scenes0.h" +#include "tsage/scenes.h" +#include "tsage/tsage.h" +#include "tsage/staticres.h" + +namespace TsAGE { + +namespace BlueForce { + +/*-------------------------------------------------------------------------- + * Scene 20 - Tsunami Title Screen + * + *--------------------------------------------------------------------------*/ + +void Scene20::Action1::signal() { + Scene20 *scene = (Scene20 *)BF_GLOBALS._sceneManager._scene; + static byte black[3] = { 0, 0, 0 }; + + switch (_actionIndex++) { + case 0: + setDelay(2); + break; + case 1: + _sound.play(1); + BF_GLOBALS._scenePalette.addRotation(64, 127, -1, 1, this); + break; + case 2: + scene->_object1.setVisage(22); + scene->_object1._strip = 1; + scene->_object1._frame = 1; + scene->_object1.changeZoom(100); + + scene->_object2.setVisage(22); + scene->_object2._strip = 2; + scene->_object2._frame = 1; + scene->_object2.changeZoom(100); + + scene->_object3.setVisage(22); + scene->_object3._strip = 3; + scene->_object3._frame = 1; + scene->_object3.changeZoom(100); + + scene->_object4.setVisage(22); + scene->_object4._strip = 4; + scene->_object4._frame = 1; + scene->_object4.changeZoom(100); + + scene->_object5.setVisage(22); + scene->_object5._strip = 5; + scene->_object5._frame = 1; + scene->_object5.changeZoom(100); + + scene->_object6.setVisage(22); + scene->_object6._strip = 6; + scene->_object6._frame = 1; + scene->_object6.changeZoom(100); + + scene->_object7.setVisage(22); + scene->_object7._strip = 7; + scene->_object7._frame = 1; + scene->_object7.changeZoom(100); + + scene->_object8.setVisage(22); + scene->_object8._strip = 8; + scene->_object8._frame = 1; + scene->_object8.changeZoom(100); + + setDelay(1); + break; + case 3: + BF_GLOBALS._scenePalette.addFader(scene->_scenePalette._palette, 256, 8, this); + break; + case 4: + setDelay(60); + break; + case 5: + scene->_object2.animate(ANIM_MODE_5, NULL); + scene->_object3.animate(ANIM_MODE_5, NULL); + scene->_object4.animate(ANIM_MODE_5, NULL); + scene->_object5.animate(ANIM_MODE_5, NULL); + scene->_object6.animate(ANIM_MODE_5, NULL); + scene->_object7.animate(ANIM_MODE_5, this); + break; + case 6: + setDelay(120); + break; + case 7: + BF_GLOBALS._scenePalette.addFader(black, 1, 5, this); + break; + case 8: + BF_GLOBALS._sceneManager.changeScene(100); + remove(); + break; + } +} + +/*--------------------------------------------------------------------------*/ + +void Scene20::postInit(SceneObjectList *OwnerList) { + loadScene(20); + Scene::postInit(); + setZoomPercents(60, 85, 200, 100); + + _scenePalette.loadPalette(1); + _scenePalette.loadPalette(22); + + _object1.postInit(); + _object1.setVisage(21); + _object1._strip = 1; + _object1._frame = 1; + _object1.animate(ANIM_MODE_NONE, NULL); + _object1.setPosition(Common::Point(62, 85)); + _object1.changeZoom(100); + + _object2.postInit(); + _object2.setVisage(21); + _object2._strip = 2; + _object2._frame = 1; + _object2.animate(ANIM_MODE_NONE, NULL); + _object2.setPosition(Common::Point(27, 94)); + _object2.changeZoom(100); + + _object3.postInit(); + _object3.setVisage(21); + _object3._strip = 2; + _object3._frame = 2; + _object3.animate(ANIM_MODE_NONE, NULL); + _object3.setPosition(Common::Point(68, 94)); + _object3.changeZoom(100); + + _object4.postInit(); + _object4.setVisage(21); + _object4._strip = 2; + _object4._frame = 3; + _object4.animate(ANIM_MODE_NONE, NULL); + _object4.setPosition(Common::Point(110, 94)); + _object4.changeZoom(100); + + _object5.postInit(); + _object5.setVisage(21); + _object5._strip = 2; + _object5._frame = 4; + _object5.animate(ANIM_MODE_NONE, NULL); + _object5.setPosition(Common::Point(154, 94)); + _object5.changeZoom(100); + + _object6.postInit(); + _object6.setVisage(21); + _object6._strip = 2; + _object6._frame = 5; + _object6.animate(ANIM_MODE_NONE, NULL); + _object6.setPosition(Common::Point(199, 94)); + _object6.changeZoom(100); + + _object7.postInit(); + _object7.setVisage(21); + _object7._strip = 2; + _object7._frame = 6; + _object7.animate(ANIM_MODE_NONE, NULL); + _object7.setPosition(Common::Point(244, 94)); + _object7.changeZoom(100); + + _object8.postInit(); + _object8.setVisage(21); + _object8._strip = 2; + _object8._frame = 7; + _object8.animate(ANIM_MODE_NONE, NULL); + _object8.setPosition(Common::Point(286, 94)); + _object8.changeZoom(100); + + setAction(&_action1); +} + +/*-------------------------------------------------------------------------- + * Scene 50 - Map Screen + * + *--------------------------------------------------------------------------*/ + +Scene50::Tooltip::Tooltip(): SavedObject() { + _newSceneNumber = _locationId = 0; +} + +void Scene50::Tooltip::synchronize(Serializer &s) { + SavedObject::synchronize(s); + _bounds.synchronize(s); + s.syncString(_msg); +} + +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); + } +} + +void Scene50::Tooltip::set(const Rect &bounds, int v60, const Common::String &msg, int v62) { + _bounds = bounds; + _newSceneNumber = v60; + _msg = msg; + _locationId = v62; +} + +void Scene50::Tooltip::update() { + // Set up the text object for the scene with the appropriate settings + Scene50 *scene = (Scene50 *)BF_GLOBALS._sceneManager._scene; + scene->_text._fontNumber = 10; + scene->_text._color1 = BF_GLOBALS._scenePalette._colors.foreground; + scene->_text._color2 = BF_GLOBALS._scenePalette._colors.background; + scene->_text.setup(_msg); + + int yp = (scene->_text._textSurface.getBounds().height() == 0) ? _bounds.bottom : _bounds.top; + scene->_text.setPosition(Common::Point(_bounds.left, yp)); +} + +void Scene50::Tooltip::highlight(bool btnDown) { + Scene50 *scene = (Scene50 *)BF_GLOBALS._sceneManager._scene; + + scene->_field382 = _newSceneNumber; + if ((scene->_field380 != 0) || (scene->_field380 != _newSceneNumber)) + update(); + + if (btnDown) { + if ((BF_GLOBALS._bikiniHutState == 14) && BF_GLOBALS.getFlag(98)) + scene->_sceneNumber = 600; + else if (BF_GLOBALS._bikiniHutState == 5) + scene->_sceneNumber = 410; + else { + BF_GLOBALS._v4CEF4 = _newSceneNumber; + + switch (BF_GLOBALS._v4CEF2) { + case 330: + case 340: + case 342: + BF_GLOBALS._player.disableControl(); + if (_locationId != BF_GLOBALS._mapLocationId) { + scene->_sceneNumber = 330; + } else { + scene->_sceneNumber = (BF_GLOBALS._v4CEA2 != 1) || (BF_GLOBALS._bikiniHutState < 1) || + (BF_GLOBALS._bikiniHutState >= 2) ? 342 : 340; + } + break; + + case 410: + case 551: + if (BF_GLOBALS.getFlag((BF_GLOBALS._v4CEF2 == 410) ? 41 : 40)) { + BF_GLOBALS._mapLocationId = _locationId; + BF_GLOBALS._player.disableControl(); + scene->_sceneNumber = _newSceneNumber; + } else { + BF_GLOBALS._v4CEA8 = 4; + BF_GLOBALS._sceneManager.changeScene(666); + return; + } + break; + + case 300: + if (_locationId == 1) { + BF_GLOBALS._v4CEF4 = 300; + _newSceneNumber = 300; + } + // Deliberate fall through to default + default: + BF_GLOBALS._mapLocationId = _locationId; + BF_GLOBALS._player.disableControl(); + scene->_sceneNumber = _newSceneNumber; + break; + } + + // Signal the scene to change to the new scene + scene->_sceneMode = 1; + scene->signal(); + } + } +} + +/*--------------------------------------------------------------------------*/ + +Scene50::Scene50(): SceneExt() { + _field382 = 0; + _field380 = 0; +} + +void Scene50::postInit(SceneObjectList *OwnerList) { + SceneExt::postInit(); + + BF_GLOBALS._interfaceY = 200; + BF_GLOBALS._player.postInit(); + BF_GLOBALS._player.setVisage(830); + BF_GLOBALS._player.setStrip(3); + BF_GLOBALS._player.setPosition(Common::Point(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2)); + BF_GLOBALS._player.hide(); + BF_GLOBALS._player.enableControl(); + BF_GLOBALS._player._uiEnabled = false; + + BF_GLOBALS._scrollFollower = NULL; + _text._color1 = 19; + _text._color2 = 9; + _text._color3 = 9; + _text._width = 75; + _text._fontNumber = 4; + _text._textMode = ALIGN_LEFT; + _text.fixPriority(256); + + // Set all the hotspots + _location3.set(Rect(10, 92, 24, 105), 180, GRANDMA_FRANNIE, 4); + _location2.set(Rect(443, 149, 508, 178), 330, MARINA, 2); + _location1.set(Rect(573, 103, 604, 130), 190, POLICE_DEPARTMENT, 1); + _location4.set(Rect(313, 21, 325, 33), 114, TONYS_BAR, 8); + _location8.set(Rect(69, 79, 82, 88), 580, CHILD_PROTECTIVE_SERVICES, 256); + _location6.set(Rect(242, 131, 264, 144), 440, ALLEY_CAT, 64); + _location5.set(Rect(383, 57, 402, 70), 380, CITY_HALL_JAIL, 32); + _location7.set(Rect(128, 32, 143, 42), 800, JAMISON_RYAN, 128); + _location9.set(Rect(349, 125, 359, 132), + (BF_GLOBALS._bikiniHutState == 13) || (BF_GLOBALS._bikiniHutState == 14) ? 551 : 550, + BIKINI_HUT, 16); + + _item.setBounds(Rect(0, 0, SCREEN_WIDTH * 2, SCREEN_HEIGHT)); + BF_GLOBALS._sceneItems.push_back(&_item); + + // Find the location to start at + int selectedTooltip = BF_GLOBALS._mapLocationId; + Tooltip *tooltip = NULL; + int xp = 0; + + switch (selectedTooltip) { + case 1: + tooltip = &_location1; + xp = 588; + break; + case 2: + tooltip = &_location2; + xp = 475; + break; + case 4: + tooltip = &_location3; + xp = 17; + break; + case 8: + tooltip = &_location4; + xp = 319; + break; + case 32: + tooltip = &_location5; + xp = 392; + break; + case 64: + tooltip = &_location6; + xp = 253; + break; + case 128: + tooltip = &_location7; + xp = 135; + break; + case 16: + tooltip = &_location9; + xp = 354; + break; + case 256: + tooltip = &_location8; + xp = 75; + break; + } + + _timer.set(240, this); + _sceneBounds.center(xp, SCREEN_HEIGHT / 2); + loadScene(55); + _sceneMode = 2; + + loadBackground(xp - 160, 0); + tooltip->update(); +} + +void Scene50::remove() { + // Blank out the screen + BF_GLOBALS._screenSurface.fillRect(BF_GLOBALS._screenSurface.getBounds(), 0); + + SceneExt::remove(); + BF_GLOBALS._v4E238 = 1; +} + +void Scene50::signal() { + if (_sceneMode == 1) { + // Destination selected + if ((BF_GLOBALS._v4CEF2 == 551) && (_sceneNumber != BF_GLOBALS._v4CEF2)) { + BF_GLOBALS.setFlag(109); + BF_GLOBALS.setFlag(115); + BF_GLOBALS.setFlag(121); + BF_GLOBALS.setFlag(127); + BF_GLOBALS.setFlag(133); + } + + if ((BF_GLOBALS._v4CEF2 == 410) && (_sceneNumber != BF_GLOBALS._v4CEF2)) { + BF_GLOBALS.setFlag(125); + } + + if ((BF_GLOBALS._v4CEF2 == 340) && (_sceneNumber != BF_GLOBALS._v4CEF2)) { + BF_GLOBALS.setFlag(123); + } + + if ((BF_GLOBALS._v4CEF2 == 380) && (_sceneNumber != BF_GLOBALS._v4CEF2)) { + if (BF_GLOBALS._bikiniHutState >= 4) + BF_GLOBALS.setFlag(129); + if (BF_GLOBALS._bikiniHutState >= 6) + BF_GLOBALS.setFlag(131); + if (BF_GLOBALS._bikiniHutState == 3) { + BF_GLOBALS._v4CEA8 = 19; + _sceneNumber = 666; + } + } + + if ((_sceneNumber == 551) && BF_GLOBALS.getFlag(147)) + _sceneNumber = 550; + + BF_GLOBALS._sound1.fadeOut2(NULL); + BF_GLOBALS._sceneManager.changeScene(_sceneNumber); + + } else if (_sceneMode == 2) { + // Initial delay complete, time to switch to interactive mode + _text.remove(); + BF_GLOBALS._player.enableControl(); + _sceneMode = 0; + _field380 = 0; + } +} + +void Scene50::process(Event &event) { + SceneExt::process(event); + Common::Point pt(event.mousePos.x + _sceneBounds.left, event.mousePos.y + _sceneBounds.top); + bool mouseDown = false; + _field382 = 0; + + if ((event.mousePos.x > 270 && (_sceneBounds.right < (SCREEN_WIDTH * 2)))) + loadBackground(4, 0); + else if ((event.mousePos.x < 50) && (_sceneBounds.left > 0)) + loadBackground(-4, 0); + else + mouseDown = event.eventType == EVENT_BUTTON_DOWN; + + if (BF_GLOBALS._player._uiEnabled) { + Tooltip *tooltipList[9] = { &_location1, &_location2, &_location3, &_location4, + &_location5, &_location6, &_location7, &_location8, &_location9 }; + + for (int idx = 0; idx < 9; ++idx) { + if (tooltipList[idx]->_bounds.contains(pt)) { + // Found a tooltip to highlight + tooltipList[idx]->highlight(mouseDown); + return; + } + } + + // No hotspot selected, so remove any current tooltip display + _text.remove(); + } +} + +} // End of namespace BlueForce + +} // End of namespace TsAGE diff --git a/engines/tsage/blue_force/blueforce_scenes0.h b/engines/tsage/blue_force/blueforce_scenes0.h new file mode 100644 index 0000000000..5c98184ed8 --- /dev/null +++ b/engines/tsage/blue_force/blueforce_scenes0.h @@ -0,0 +1,103 @@ +/* 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_SCENES0_H +#define TSAGE_BLUEFORCE_SCENES0_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 Scene20 : public SceneExt { + /* Actions */ + class Action1 : public Action { + private: + ASoundExt _sound; + public: + virtual void signal(); + }; +public: + Action1 _action1; + ScenePalette _scenePalette; + SceneObject _object1, _object2, _object3, _object4; + SceneObject _object5, _object6, _object7, _object8; + + virtual void postInit(SceneObjectList *OwnerList = NULL); +}; + +class Scene50: public SceneExt { + class Tooltip: public SavedObject { + public: + Rect _bounds; + Common::String _msg; + int _newSceneNumber; + int _locationId; + public: + Tooltip(); + void set(const Rect &bounds, int v60, const Common::String &msg, int v62); + void update(); + void highlight(bool btnDown); + + 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: + int _field380, _field382; + int _sceneNumber; + SceneText _text; + SceneItemType2 _item; + Tooltip _location1, _location2, _location3, _location4, _location5; + Tooltip _location6, _location7, _location8, _location9; + Timer _timer; +public: + Scene50(); + virtual Common::String getClassName() { return "Scene50"; } + virtual void postInit(SceneObjectList *OwnerList = NULL); + virtual void remove(); + virtual void signal(); + virtual void process(Event &event); +}; + +} // 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 d266d5e1d9..0000000000 --- a/engines/tsage/blueforce_logic.cpp +++ /dev/null @@ -1,120 +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/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: - 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 b475310533..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 @@ -416,13 +447,13 @@ int ConversationChoiceDialog::execute(const Common::StringArray &choiceList) { // Event handling loop Event event; - while (!_vm->getEventManager()->shouldQuit()) { + while (!_vm->shouldQuit()) { while (!_globals->_events.getEvent(event, EVENT_KEYPRESS | EVENT_BUTTON_DOWN | EVENT_MOUSE_MOVE) && - !_vm->getEventManager()->shouldQuit()) { + !_vm->shouldQuit()) { g_system->delayMillis(10); g_system->updateScreen(); } - if (_vm->getEventManager()->shouldQuit()) + if (_vm->shouldQuit()) break; if ((event.eventType == EVENT_KEYPRESS) && (event.kbd.keycode >= Common::KEYCODE_1) && @@ -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 76714a6f10..42cb1d039f 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; } @@ -1552,7 +1566,7 @@ void SceneItem::display(int resNum, int lineNum, ...) { Event event; // Keep event on-screen until a mouse or keypress - while (!_vm->getEventManager()->shouldQuit() && !_globals->_events.getEvent(event, + while (!_vm->shouldQuit() && !_globals->_events.getEvent(event, EVENT_BUTTON_DOWN | EVENT_KEYPRESS)) { g_system->updateScreen(); g_system->delayMillis(10); @@ -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; @@ -1699,6 +1718,7 @@ SceneObject::SceneObject() : SceneHotspot() { _sceneRegionId = 0; _percent = 100; _flags |= OBJFLAG_PANES; + _priority = 0; _frameChange = 0; _visage = 0; @@ -2263,6 +2283,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 +2306,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; @@ -3426,6 +3474,7 @@ void GameHandler::synchronize(Serializer &s) { SceneHandler::SceneHandler() { _saveGameSlot = -1; _loadGameSlot = -1; + _prevFrameNumber = 0; } void SceneHandler::registerHandler() { @@ -3433,6 +3482,10 @@ void SceneHandler::registerHandler() { _globals->_game->addHandler(this); } +uint32 SceneHandler::getFrameDifference() { + return GLOBALS._events.getFrameNumber() - _prevFrameNumber; +} + void SceneHandler::postInit(SceneObjectList *OwnerList) { _delayTicks = 2; @@ -3547,10 +3600,19 @@ void SceneHandler::dispatch() { // Not actually used //_eventListeners.forEach(SceneHandler::handleListener); - // Handle pending eents + // Handle pending events Event event; - while (_globals->_events.getEvent(event)) + if (_globals->_events.getEvent(event)) { + // Process pending events + do { + process(event); + } while (_globals->_events.getEvent(event)); + } else if (_vm->getGameID() == GType_BlueForce) { + // For Blue Force, 'none' events need to be generated in the absence of any + event.eventType = EVENT_NONE; + event.mousePos = _globals->_events._mousePos; process(event); + } // Handle drawing the contents of the scene if (_globals->_sceneManager._scene) @@ -3573,4 +3635,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..19987ed399 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) { @@ -827,9 +846,11 @@ public: int _loadGameSlot; int _delayTicks; Common::String _saveName; + uint32 _prevFrameNumber; public: SceneHandler(); void registerHandler(); + uint32 getFrameDifference(); virtual Common::String getClassName() { return "SceneHandler"; } virtual void postInit(SceneObjectList *OwnerList = NULL); @@ -840,6 +861,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 9277fd429a..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)); @@ -38,6 +38,7 @@ Debugger::Debugger() : GUI::Debugger() { DCmd_Register("listobjects", WRAP_METHOD(Debugger, Cmd_ListObjects)); DCmd_Register("moveobject", WRAP_METHOD(Debugger, Cmd_MoveObject)); DCmd_Register("hotspots", WRAP_METHOD(Debugger, Cmd_Hotspots)); + DCmd_Register("sound", WRAP_METHOD(Debugger, Cmd_Sound)); } static int strToInt(const char *s) { @@ -434,5 +435,18 @@ bool Debugger::Cmd_Hotspots(int argc, const char **argv) { return false; } +/** + * Play the specified sound + */ +bool Debugger::Cmd_Sound(int argc, const char **argv) { + if (argc != 2) { + DebugPrintf("Usage: %s <sound number>\n", argv[0]); + return true; + } + + int soundNum = strToInt(argv[1]); + _globals->_soundHandler.play(soundNum); + return false; +} -} // End of namespace tSage +} // End of namespace TsAGE diff --git a/engines/tsage/debugger.h b/engines/tsage/debugger.h index 3c14cd7bed..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: @@ -42,10 +42,10 @@ protected: bool Cmd_ClearFlag(int argc, const char **argv); bool Cmd_ListObjects(int argc, const char **argv); bool Cmd_MoveObject(int argc, const char **argv); - bool Cmd_Hotspots(int argc, const char **argv); + 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 aaa9030a04..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,11 +55,11 @@ 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" }, - { "ring", "Ringworld: Revenge of the Patriarch" }, + { "ringworld", "Ringworld: Revenge of the Patriarch" }, { "blueforce", "Blue Force" }, { 0, 0 } }; @@ -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 8b80edf89d..4b69549673 100644 --- a/engines/tsage/detection_tables.h +++ b/engines/tsage/detection_tables.h @@ -20,19 +20,33 @@ * */ -namespace tSage { +namespace TsAGE { static const tSageGameDescription gameDescriptions[] = { - // Ringworld CD and First Wave versions + // Ringworld English CD and First Wave versions { { - "ring", + "ringworld", "CD", AD_ENTRY1s("ring.rlb", "466f0e6492d9d0f34d35c5cd088de90f", 37847618), Common::EN_ANY, Common::kPlatformPC, - ADGF_UNSTABLE, + ADGF_TESTING | ADGF_CD, + Common::GUIO_NOSPEECH | Common::GUIO_NOSFX + }, + GType_Ringworld, + GF_CD | GF_ALT_REGIONS + }, + // Ringworld Spanish CD + { + { + "ringworld", + "CD", + AD_ENTRY1s("ring.rlb", "cb8bba91b30cd172712371d7123bd763", 7427980), + Common::ES_ESP, + Common::kPlatformPC, + ADGF_TESTING | ADGF_CD, Common::GUIO_NOSPEECH | Common::GUIO_NOSFX }, GType_Ringworld, @@ -41,12 +55,12 @@ static const tSageGameDescription gameDescriptions[] = { // Ringworld English Floppy version { { - "ring", + "ringworld", "Floppy", AD_ENTRY1s("ring.rlb", "7b7f0c5b37b58fa5ec06ebb2ca0d0d9d", 8438770), Common::EN_ANY, Common::kPlatformPC, - ADGF_UNSTABLE, + ADGF_TESTING, Common::GUIO_NOSPEECH | Common::GUIO_NOSFX }, GType_Ringworld, @@ -55,7 +69,7 @@ static const tSageGameDescription gameDescriptions[] = { // Ringworld English Floppy Demo #1 version { { - "ring", + "ringworld", "Floppy Demo", AD_ENTRY1s("tsage.rlb", "3b3604a97c06c91f3735d3e9d341f63f", 833453), Common::EN_ANY, @@ -70,7 +84,7 @@ static const tSageGameDescription gameDescriptions[] = { // Ringworld English Floppy Demo #2 version { { - "ring", + "ringworld", "Floppy Demo", AD_ENTRY1s("demoring.rlb", "64050e1806203b15bb03876140eb4f56", 832206), Common::EN_ANY, @@ -106,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 { @@ -120,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 86fbbc8e43..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 { /*--------------------------------------------------------------------------*/ @@ -243,7 +243,7 @@ void RightClickDialog::execute() { // Dialog event handler loop _gfxManager.activate(); - while (!_vm->getEventManager()->shouldQuit() && (_selectedAction == -1)) { + while (!_vm->shouldQuit() && (_selectedAction == -1)) { Event evt; while (_globals->_events.getEvent(evt, EVENT_MOUSE_MOVE | EVENT_BUTTON_DOWN)) { evt.mousePos.x -= _bounds.left; @@ -465,14 +465,14 @@ void InventoryDialog::execute() { bool lookFlag = false; _gfxManager.activate(); - while (!_vm->getEventManager()->shouldQuit()) { + while (!_vm->shouldQuit()) { // Get events Event event; - while (!_globals->_events.getEvent(event) && !_vm->getEventManager()->shouldQuit()) { + while (!_globals->_events.getEvent(event) && !_vm->shouldQuit()) { g_system->delayMillis(10); g_system->updateScreen(); } - if (_vm->getEventManager()->shouldQuit()) + if (_vm->shouldQuit()) break; hiliteObj = NULL; @@ -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 a24f65421b..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; @@ -40,6 +40,7 @@ EventsClass::EventsClass() { _priorFrameTime = 0; _prevDelayFrame = 0; _saver->addListener(this); + _saver->addLoadNotifier(&EventsClass::loadNotifierProc); } bool EventsClass::pollEvent() { @@ -78,7 +79,7 @@ bool EventsClass::pollEvent() { void EventsClass::waitForPress(int eventMask) { Event evt; - while (!_vm->getEventManager()->shouldQuit() && !getEvent(evt, eventMask)) + while (!_vm->shouldQuit() && !getEvent(evt, eventMask)) g_system->delayMillis(10); } @@ -86,7 +87,7 @@ void EventsClass::waitForPress(int eventMask) { * Standard event retrieval, which only returns keyboard and mouse clicks */ bool EventsClass::getEvent(Event &evt, int eventMask) { - while (pollEvent() && !_vm->getEventManager()->shouldQuit()) { + while (pollEvent() && !_vm->shouldQuit()) { evt.handled = false; evt.eventType = EVENT_NONE; evt.mousePos = _event.mouse; @@ -154,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; } @@ -315,4 +316,13 @@ void EventsClass::listenerSynchronize(Serializer &s) { } } -} // end of namespace tSage +void EventsClass::loadNotifierProc(bool postFlag) { + if (postFlag) { + if (_globals->_events._lastCursor == CURSOR_NONE) + _globals->_events._lastCursor = _globals->_events._currentCursor; + else + _globals->_events._lastCursor = CURSOR_NONE; + } +} + +} // end of namespace TsAGE diff --git a/engines/tsage/events.h b/engines/tsage/events.h index e0fbd88745..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}; @@ -100,8 +100,9 @@ public: void delay(int numFrames); virtual void listenerSynchronize(Serializer &s); + 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..27067c7d1c 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,21 +111,25 @@ 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(); } + _sceneHandler = new SceneHandler(); break; case GType_BlueForce: - _game = new BlueForceGame(); + _game = new BlueForce::BlueForceGame(); + _sceneHandler = new BlueForce::SceneHandlerExt(); break; } } Globals::~Globals() { + _scenePalette.clearListeners(); delete _inventory; + delete _sceneHandler; delete _game; _globals = NULL; } @@ -142,9 +154,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 +178,39 @@ void Globals::dispatchSounds() { Common::for_each(_sounds.begin(), _sounds.end(), Globals::dispatchSound); } +/*--------------------------------------------------------------------------*/ + +namespace BlueForce { + +BlueForceGlobals::BlueForceGlobals(): Globals() { + _interfaceY = 0; + _v51C44 = 1; + _v4CEA2 = 0; + _v4CEA8 = 0; + _v4CEF2 = 0; + _v4CEF4 = 0; + _v4CF9E = 0; + _v4E238 = 0; + _v501FC = 0; + _v51C42 = 0; + _bikiniHutState = 0; + _mapLocationId = 1; + Common::set_to(&_globalFlags[0], &_globalFlags[12], 0); +} + +void BlueForceGlobals::synchronize(Serializer &s) { + Globals::synchronize(s); + error("Sync variables"); +} + +bool BlueForceGlobals::getFlag(int v) { + return _globalFlags[v / 16] & (1 << (v % 8)); +} + +void BlueForceGlobals::setFlag(int v) { + _globalFlags[v / 16] |= 1 << (v % 8); +} + +} // 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..2d409b6343 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: @@ -40,7 +40,7 @@ public: GfxSurface _screenSurface; GfxManager _gfxManagerInstance; Common::List<GfxManager *> _gfxManagers; - SceneHandler _sceneHandler; + SceneHandler *_sceneHandler; Game *_game; EventsClass _events; SceneManager _sceneManager; @@ -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,45 @@ 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: + ASoundExt _sound1, _sound2, _sound3; + int _v4CEA2; + int _v4CEA8; + int _v4CEF2; + int _v4CEF4; + int _v4CF9E; + int _v4E238; + int _v501FC; + int _v51C42; + int _v51C44; + int _interfaceY; + int _bikiniHutState; + int _mapLocationId; + uint8 _globalFlags[12]; + + BlueForceGlobals(); + virtual Common::String getClassName() { return "BFGlobals"; } + virtual void synchronize(Serializer &s); + + void setFlag(int v); + bool getFlag(int v); +}; + +} // End of namespace BlueForce + +} // End of namespace TsAGE #endif diff --git a/engines/tsage/graphics.cpp b/engines/tsage/graphics.cpp index fce9e1317d..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 @@ -408,7 +408,7 @@ bool GfxSurface::displayText(const Common::String &msg, const Common::Point &pt) // Write for a mouse or keypress Event event; - while (!_globals->_events.getEvent(event, EVENT_BUTTON_DOWN | EVENT_KEYPRESS) && !_vm->getEventManager()->shouldQuit()) + while (!_globals->_events.getEvent(event, EVENT_BUTTON_DOWN | EVENT_KEYPRESS) && !_vm->shouldQuit()) ; // Restore the display area @@ -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; } /** @@ -718,7 +718,7 @@ bool GfxElement::focusedEvent(Event &event) { int xOffset = mousePos.x - _globals->_events._mousePos.x; int yOffset = mousePos.y - _globals->_events._mousePos.y; - while (event.eventType != EVENT_BUTTON_UP && !_vm->getEventManager()->shouldQuit()) { + while (event.eventType != EVENT_BUTTON_UP && !_vm->shouldQuit()) { g_system->delayMillis(10); if (_bounds.contains(mousePos)) { @@ -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); @@ -1029,7 +1029,7 @@ GfxButton *GfxDialog::execute(GfxButton *defaultButton) { GfxButton *selectedButton = NULL; bool breakFlag = false; - while (!_vm->getEventManager()->shouldQuit() && !breakFlag) { + while (!_vm->shouldQuit() && !breakFlag) { Event event; while (_globals->_events.getEvent(event) && !breakFlag) { // Adjust mouse positions to be relative within the dialog @@ -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 aefc8b0992..5c7104936e 100644 --- a/engines/tsage/module.mk +++ b/engines/tsage/module.mk @@ -1,7 +1,9 @@ MODULE := engines/tsage MODULE_OBJS := \ - blueforce_logic.o \ + blue_force/blueforce_logic.o \ + blue_force/blueforce_scenes0.o \ + blue_force/blueforce_scenes1.o \ converse.o \ core.o \ debugger.o \ @@ -11,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 \ @@ -34,4 +36,3 @@ endif # Include common rules include $(srcdir)/rules.mk - 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 58501172af..2a34e49b39 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) { @@ -296,7 +298,7 @@ void SceneArea::draw(bool flag) { void SceneArea::wait() { // Wait until a mouse or keypress Event event; - while (!_vm->getEventManager()->shouldQuit() && !_globals->_events.getEvent(event)) { + while (!_vm->shouldQuit() && !_globals->_events.getEvent(event)) { g_system->updateScreen(); g_system->delayMillis(10); } @@ -1285,7 +1287,7 @@ void RingworldGame::saveGame() { MessageDialog::show(SAVING_NOT_ALLOWED_MSG, OK_BTN_STRING); else { // Show the save dialog - handleSaveLoad(true, _globals->_sceneHandler._saveGameSlot, _globals->_sceneHandler._saveName); + handleSaveLoad(true, _globals->_sceneHandler->_saveGameSlot, _globals->_sceneHandler->_saveName); } } @@ -1294,7 +1296,7 @@ void RingworldGame::restoreGame() { MessageDialog::show(RESTORING_NOT_ALLOWED_MSG, OK_BTN_STRING); else { // Show the load dialog - handleSaveLoad(false, _globals->_sceneHandler._loadGameSlot, _globals->_sceneHandler._saveName); + handleSaveLoad(false, _globals->_sceneHandler->_loadGameSlot, _globals->_sceneHandler->_saveName); } } @@ -1346,7 +1348,7 @@ void RingworldGame::start() { } if (slot >= 0) - _globals->_sceneHandler._loadGameSlot = slot; + _globals->_sceneHandler->_loadGameSlot = slot; else // Switch to the title screen _globals->_sceneManager.setNewScene(1000); @@ -1363,8 +1365,8 @@ void RingworldGame::restart() { _globals->setFlag(34); // Clear save/load slots - _globals->_sceneHandler._saveGameSlot = -1; - _globals->_sceneHandler._loadGameSlot = -1; + _globals->_sceneHandler->_saveGameSlot = -1; + _globals->_sceneHandler->_loadGameSlot = -1; _globals->_stripNum = 0; _globals->_events.setCursor(CURSOR_WALK); @@ -1429,8 +1431,8 @@ void RingworldGame::endGame(int resNum, int lineNum) { restart(); breakFlag = true; } else { - handleSaveLoad(false, _globals->_sceneHandler._loadGameSlot, _globals->_sceneHandler._saveName); - breakFlag = _globals->_sceneHandler._loadGameSlot >= 0; + handleSaveLoad(false, _globals->_sceneHandler->_loadGameSlot, _globals->_sceneHandler->_saveName); + breakFlag = _globals->_sceneHandler->_loadGameSlot >= 0; } } while (!breakFlag); } @@ -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 8299a05967..20af25561c 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) @@ -1330,6 +1332,24 @@ void Scene40::Action8::signal() { } } +void Scene40::Action8::dispatch() { + if (_action) + _action->dispatch(); + + if (_delayFrames) { + uint32 frameNumber = _globals->_events.getFrameNumber(); + if ((_startFrame + 60) < frameNumber) { + --_delayFrames; + _startFrame = frameNumber; + + if (_delayFrames <= 0) { + _delayFrames = 0; + signal(); + } + } + } +} + /*--------------------------------------------------------------------------*/ void Scene40::DyingKzin::doAction(int action) { @@ -1416,7 +1436,7 @@ void Scene40::Item2::doAction(int action) { SceneItem::display2(40, 37); break; default: - SceneItem::doAction(action); + SceneHotspot::doAction(action); break; } } @@ -1437,7 +1457,7 @@ void Scene40::Item6::doAction(int action) { SceneItem::display2(40, 36); break; default: - SceneItem::doAction(action); + SceneHotspot::doAction(action); break; } } @@ -1446,7 +1466,7 @@ void Scene40::Item6::doAction(int action) { Scene40::Scene40() : _item1(2, OBJECT_SCANNER, 40, 24, OBJECT_STUNNER, 40, 25, CURSOR_LOOK, 40, 7, CURSOR_USE, 40, 16, LIST_END), - _item3(5, OBJECT_SCANNER, 40, 26, OBJECT_STUNNER, 40, 27, CURSOR_LOOK, 40, 9, CURSOR_USE, 40, 17, LIST_END), + _item3(5, OBJECT_SCANNER, 40, 28, OBJECT_STUNNER, 40, 27, CURSOR_LOOK, 40, 2, CURSOR_USE, 40, 30, LIST_END), _item4(6, OBJECT_SCANNER, 40, 31, OBJECT_STUNNER, 40, 32, CURSOR_LOOK, 40, 5, CURSOR_USE, 40, 33, LIST_END), _item5(0, CURSOR_LOOK, 40, 11, LIST_END), _item7(4, OBJECT_SCANNER, 40, 26, OBJECT_STUNNER, 40, 27, CURSOR_LOOK, 40, 9, CURSOR_USE, 40, 17, LIST_END), @@ -2271,7 +2291,7 @@ void Scene60::Item::doAction(int action) { setAction(&scene->_sequenceManager, this, 62, NULL); break; default: - SceneItem::doAction(action); + SceneHotspot::doAction(action); break; } } @@ -3148,7 +3168,7 @@ Scene6100::Scene6100(): Scene() { _angle = 0; _msgActive = false; - _globals->_sceneHandler._delayTicks = 8; + _globals->_sceneHandler->_delayTicks = 8; _globals->_player.disableControl(); _globals->_events.setCursor(CURSOR_WALK); @@ -3324,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 283cf68e07..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 */ @@ -201,6 +205,7 @@ class Scene40 : public Scene { class Action8 : public Action { public: virtual void signal(); + virtual void dispatch(); }; /* Objects */ @@ -214,15 +219,15 @@ class Scene40 : public Scene { }; /* Items */ - class Item2 : public SceneItem { + class Item2 : public SceneHotspot { public: virtual void doAction(int action); }; - class Item6 : public SceneItem { + class Item6 : public SceneHotspot { public: virtual void doAction(int action); }; - class Item8 : public SceneItem { + class Item8 : public SceneHotspot { public: virtual void doAction(int action); }; @@ -532,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 ba4060548e..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; @@ -1746,7 +1748,8 @@ void Scene9900::strAction2::signal() { frameWidth = _txtArray2[_txtArray1Index].getFrame().getBounds().width(); _txtArray2[_txtArray1Index].setPosition(Common::Point((320 - frameWidth) / 2, 200 + frameHeight)); } else { - _globals->_player.enableControl(); + // WORKAROUND: Fix inventory becoming available at end of credits + _globals->_events.setCursor(CURSOR_WALK); _actionIndex = 3; signal(); } @@ -2085,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 824a96a18b..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 @@ -324,7 +326,7 @@ void Scene2000::Action14::signal() { scene->_stripManager.start(2001, this, scene); break; case 6: - _globals->_soundHandler.fadeOut(0/* was false */); + _globals->_soundHandler.fadeOut(NULL); scene->_object8.setStrip(1); scene->_object8.setFrame(scene->_object8.getFrameCount()); scene->_object8.animate(ANIM_MODE_6, this); @@ -526,7 +528,7 @@ void Scene2100::Action1::signal() { _state = 0; _globals->_events.setCursor(CURSOR_USE); - while (!_state && !_vm->getEventManager()->shouldQuit()) { + while (!_state && !_vm->shouldQuit()) { // Wait for an event Event event; if (!_globals->_events.getEvent(event)) { @@ -786,7 +788,7 @@ void Scene2100::Action9::signal() { scene->_stripManager.start(6051, this, scene); break; case 4: - scene->_soundHandler.fadeOut(0/* was false */); + scene->_soundHandler.fadeOut(NULL); scene->_object4.setStrip(1); scene->_object4.setFrame(scene->_object4.getFrameCount()); scene->_object4.animate(ANIM_MODE_6, this); @@ -1105,7 +1107,7 @@ void Scene2100::Action14::signal() { scene->_stripManager.start(6009, this, scene); break; case 6: - scene->_soundHandler.fadeOut(0/* was false */); + scene->_soundHandler.fadeOut(NULL); scene->_object4.setStrip(1); scene->_object4.setFrame(scene->_object4.getFrameCount()); scene->_object4.animate(ANIM_MODE_6, this); @@ -2257,7 +2259,7 @@ void Scene2150::Action1::signal() { _state = 0; _globals->_events.setCursor(CURSOR_USE); - while (!_state && !_vm->getEventManager()->shouldQuit()) { + while (!_state && !_vm->shouldQuit()) { // Wait for an event Event event; if (!_globals->_events.getEvent(event)) { @@ -5112,7 +5114,7 @@ void Scene2320::Action3::signal() { _state = 0; _globals->_events.setCursor(CURSOR_USE); - while (!_state && !_vm->getEventManager()->shouldQuit()) { + while (!_state && !_vm->shouldQuit()) { // Wait for an event Event event; if (!_globals->_events.getEvent(event)) { @@ -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 2b329b958a..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); @@ -2223,7 +2225,7 @@ void Scene7700::signal() { } break; case 7702: - _soundHandler.fadeOut(0); + _globals->_soundHandler.fadeOut(NULL); _globals->_sceneManager.changeScene(7600); break; case 7703: @@ -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 40444cd630..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; @@ -249,12 +249,9 @@ bool Saver::readSavegameHeader(Common::InSaveFile *in, tSageSavegameHeader &head while ((ch = (char)in->readByte()) != '\0') header.saveName += ch; // Get the thumbnail - header.thumbnail = new Graphics::Surface(); - if (!Graphics::loadThumbnail(*in, *header.thumbnail)) { - delete header.thumbnail; - header.thumbnail = NULL; + header.thumbnail = Graphics::loadThumbnail(*in); + if (!header.thumbnail) return false; - } // Read in save date/time header.saveYear = in->readSint16LE(); @@ -413,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 18b3da2698..5aeacda6fe 100644 --- a/engines/tsage/scenes.cpp +++ b/engines/tsage/scenes.cpp @@ -22,11 +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 { +namespace TsAGE { SceneManager::SceneManager() { _scene = NULL; @@ -38,6 +38,7 @@ SceneManager::SceneManager() { _scrollerRect = Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); _saver->addListener(this); _objectCount = 0; + _loadMode = 0; } SceneManager::~SceneManager() { @@ -45,7 +46,7 @@ SceneManager::~SceneManager() { } void SceneManager::setNewScene(int sceneNumber) { - warning("SetNewScene(%d)", sceneNumber); + debug(1, "SetNewScene(%d)", sceneNumber); _nextSceneNumber = sceneNumber; } @@ -113,7 +114,7 @@ void SceneManager::sceneChange() { assert(_objectCount == _saver->getObjectCount()); } _objectCount = _saver->getObjectCount(); - _globals->_sceneHandler._delayTicks = 2; + _globals->_sceneHandler->_delayTicks = 2; // Instantiate and set the new scene _scene = getNewScene(); @@ -146,7 +147,7 @@ void SceneManager::fadeInIfNecessary() { } void SceneManager::changeScene(int newSceneNumber) { - warning("changeScene(%d)", newSceneNumber); + debug(1, "changeScene(%d)", newSceneNumber); // Fade out the scene ScenePalette scenePalette; uint32 adjustData = 0; @@ -173,6 +174,11 @@ void SceneManager::changeScene(int newSceneNumber) { // Blank out the screen _globals->_screenSurface.fillRect(_globals->_screenSurface.getBounds(), 0); + // If there are any fading sounds, wait until fading is complete + while (_globals->_soundManager.isFading()) { + g_system->delayMillis(10); + } + // Set the new scene to be loaded setNewScene(newSceneNumber); } @@ -252,6 +258,7 @@ void SceneManager::listenerSynchronize(Serializer &s) { Scene::Scene() : _sceneBounds(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), _backgroundBounds(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT) { _sceneMode = 0; + _activeScreenNumber = 0; _oldSceneBounds = Rect(4000, 4000, 4100, 4100); Common::set_to(&_zoomPercents[0], &_zoomPercents[256], 0); } @@ -296,7 +303,7 @@ void Scene::dispatch() { } void Scene::loadScene(int sceneNum) { - warning("loadScene(%d)", sceneNum); + debug(1, "loadScene(%d)", sceneNum); _screenNumber = sceneNum; if (_globals->_scenePalette.loadPalette(sceneNum)) _globals->_sceneManager._hasPalette = true; @@ -419,6 +426,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); } @@ -511,7 +523,7 @@ void Game::execute() { activeFlag = true; } } - } while (activeFlag && !_vm->getEventManager()->shouldQuit()); + } 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 5845efaec9..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: @@ -134,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 e26b3d1544..0b77628801 100644 --- a/engines/tsage/sound.cpp +++ b/engines/tsage/sound.cpp @@ -20,6 +20,7 @@ * */ +#include "audio/decoders/raw.h" #include "common/config-manager.h" #include "tsage/core.h" #include "tsage/globals.h" @@ -27,7 +28,7 @@ #include "tsage/graphics.h" #include "tsage/tsage.h" -namespace tSage { +namespace TsAGE { static SoundManager *_soundManager = NULL; @@ -53,6 +54,7 @@ SoundManager::SoundManager() { SoundManager::~SoundManager() { if (__sndmgrReady) { Common::StackLock slock(_serverDisabledMutex); + _vm->_mixer->stopAll(); for (Common::List<Sound *>::iterator i = _soundList.begin(); i != _soundList.end(); ) { Sound *s = *i; @@ -66,7 +68,15 @@ SoundManager::~SoundManager() { } _sfTerminate(); - g_system->getTimerManager()->removeTimerProc(_sfUpdateCallback); +// g_system->getTimerManager()->removeTimerProc(_sfUpdateCallback); + } + + // Free any allocated voice type structures + for (int idx = 0; idx < SOUND_ARR_SIZE; ++idx) { + if (sfManager()._voiceTypeStructPtrs[idx]) { + delete sfManager()._voiceTypeStructPtrs[idx]; + sfManager()._voiceTypeStructPtrs[idx] = NULL; + } } _soundManager = NULL; @@ -78,9 +88,12 @@ void SoundManager::postInit() { _saver->addLoadNotifier(&SoundManager::loadNotifier); _saver->addListener(this); - // Install a timer for handling sound manager updates at 60Hz - g_system->getTimerManager()->installTimerProc(_sfUpdateCallback, 1000000 / GAME_FRAME_RATE, NULL); +// I originally separated the sound manager update method into a separate thread, since +// it handles updates for both music and Fx. However, since Adlib updates also get done in a +// thread, and doesn't get too far ahead, I've left it to the AdlibSoundDriver class to +// call the update method, rather than having it be called separately +// g_system->getTimerManager()->installTimerProc(_sfUpdateCallback, 1000000 / SOUND_FREQUENCY, NULL, "tsageSoundUpdate"); __sndmgrReady = true; } } @@ -155,9 +168,7 @@ Common::List<SoundDriverEntry> &SoundManager::buildDriverList(bool detectFlag) { void SoundManager::installConfigDrivers() { installDriver(ADLIB_DRIVER_NUM); -#ifdef DEBUG installDriver(SBLASTER_DRIVER_NUM); -#endif } Common::List<SoundDriverEntry> &SoundManager::getDriverList(bool detectFlag) { @@ -226,7 +237,7 @@ SoundDriver *SoundManager::instantiateDriver(int driverNum) { case ADLIB_DRIVER_NUM: return new AdlibSoundDriver(); case SBLASTER_DRIVER_NUM: - return new AdlibFxSoundDriver(); + return new SoundBlasterDriver(); default: error("Unknown sound driver - %d", driverNum); } @@ -357,9 +368,6 @@ void SoundManager::rethinkVoiceTypes() { } void SoundManager::_sfSoundServer() { - Common::StackLock slock1(sfManager()._serverDisabledMutex); - Common::StackLock slock2(sfManager()._serverSuspendedMutex); - if (sfManager()._needToRethink) { _sfRethinkVoiceTypes(); sfManager()._needToRethink = false; @@ -451,6 +459,22 @@ void SoundManager::_sfProcessFading() { } } +bool SoundManager::isFading() { + Common::StackLock slock(sfManager()._serverSuspendedMutex); + + // Loop through any active sounds to see if any are being actively faded + Common::List<Sound *>::iterator i = sfManager()._playList.begin(); + while (i != sfManager()._playList.end()) { + Sound *s = *i; + ++i; + + if (s->_fadeDest != -1) + return true; + } + + return false; +} + void SoundManager::_sfUpdateVoiceStructs() { for (int voiceIndex = 0; voiceIndex < SOUND_ARR_SIZE; ++voiceIndex) { VoiceTypeStruct *vs = sfManager()._voiceTypeStructPtrs[voiceIndex]; @@ -1341,7 +1365,7 @@ bool SoundManager::_sfInstallDriver(SoundDriver *driver) { sfManager()._installedDrivers.push_back(driver); driver->_groupOffset = driver->getGroupData(); - driver->_groupMask = READ_LE_UINT32(driver->_groupOffset); + driver->_groupMask = driver->_groupOffset->groupMask; _sfExtractGroupMask(); _sfRethinkSoundDrivers(); @@ -1967,9 +1991,9 @@ void Sound::_soServiceTrackType0(int trackIndex, const byte *channelData) { if (channelNum != -1) { if (voiceType != VOICETYPE_0) { if (chFlags & 0x10) - _soProc42(vtStruct, channelNum, chVoiceType, v); + _soPlaySound2(vtStruct, channelData, channelNum, chVoiceType, v); else - _soProc32(vtStruct, channelNum, chVoiceType, v, b); + _soPlaySound(vtStruct, channelData, channelNum, chVoiceType, v, b); } else if (voiceNum != -1) { assert(driver); driver->proc20(voiceNum, chVoiceType); @@ -2137,7 +2161,7 @@ void Sound::_soUpdateDamper(VoiceTypeStruct *voiceType, int channelNum, VoiceTyp } } -void Sound::_soProc32(VoiceTypeStruct *vtStruct, int channelNum, VoiceType voiceType, int v0, int v1) { +void Sound::_soPlaySound(VoiceTypeStruct *vtStruct, const byte *channelData, int channelNum, VoiceType voiceType, int v0, int v1) { int entryIndex = _soFindSound(vtStruct, channelNum); if (entryIndex != -1) { SoundDriver *driver = vtStruct->_entries[entryIndex]._driver; @@ -2147,11 +2171,11 @@ void Sound::_soProc32(VoiceTypeStruct *vtStruct, int channelNum, VoiceType voice vtStruct->_entries[entryIndex]._type1._field4 = v0; vtStruct->_entries[entryIndex]._type1._field5 = 0; - driver->proc32(this, vtStruct->_entries[entryIndex]._voiceNum, _chProgram[channelNum], v0, v1); + driver->playSound(channelData, 0, _chProgram[channelNum], vtStruct->_entries[entryIndex]._voiceNum, v0, v1); } } -void Sound::_soProc42(VoiceTypeStruct *vtStruct, int channelNum, VoiceType voiceType, int v0) { +void Sound::_soPlaySound2(VoiceTypeStruct *vtStruct, const byte *channelData, int channelNum, VoiceType voiceType, int v0) { for (int trackCtr = 0; trackCtr < _trackInfo._numTracks; ++trackCtr) { const byte *instrument = _channelData[trackCtr]; if ((*(instrument + 13) == v0) && (*instrument == 1)) { @@ -2160,13 +2184,14 @@ void Sound::_soProc42(VoiceTypeStruct *vtStruct, int channelNum, VoiceType voice if (entryIndex != -1) { SoundDriver *driver = vtStruct->_entries[entryIndex]._driver; assert(driver); + byte *trackData = _channelData[trackCtr]; vtStruct->_entries[entryIndex]._type1._field6 = 0; vtStruct->_entries[entryIndex]._type1._field4 = v0; vtStruct->_entries[entryIndex]._type1._field5 = 0; int v1, v2; - driver->proc32(this, vtStruct->_entries[entryIndex]._voiceNum, -1, v0, 0x7F); + driver->playSound(trackData, 14, -1, vtStruct->_entries[entryIndex]._voiceNum, v0, 0x7F); driver->proc42(vtStruct->_entries[entryIndex]._voiceNum, voiceType, 0, &v1, &v2); } break; @@ -2295,24 +2320,26 @@ void Sound::_soServiceTrackType1(int trackIndex, const byte *channelData) { vtStruct->_entries[entryIndex]._type1._field5 = 0; int v1, v2; - driver->proc32(this, vtStruct->_entries[entryIndex]._voiceNum, -1, *(channelData + 1), 0x7f); + driver->playSound(channelData, 14, -1, vtStruct->_entries[entryIndex]._voiceNum, *(channelData + 1), 0x7f); driver->proc42(vtStruct->_entries[entryIndex]._voiceNum, *(channelData + 1), _loop ? 1 : 0, &v1, &v2); + _trkState[trackIndex] = 2; } } else { for (uint entryIndex = 0; entryIndex < vtStruct->_entries.size(); ++entryIndex) { VoiceStructEntry &vte = vtStruct->_entries[entryIndex]; VoiceStructEntryType1 &vse = vte._type1; - if ((vse._sound == this) && (vse._channelNum == channel) && (vse._field4 == vtStruct->_total)) { + if ((vse._sound == this) && (vse._channelNum == channel) && (vse._field4 == *(channelData + 1))) { SoundDriver *driver = vte._driver; - int v1, v2; - driver->proc42(vte._voiceNum, vtStruct->_total, _loop ? 1 : 0, &v1, &v2); - if (v2) { + int isEnded, resetTimer; + driver->proc42(vte._voiceNum, vtStruct->_total, _loop ? 1 : 0, &isEnded, &resetTimer); + if (isEnded) { _trkState[trackIndex] = 0; - } else if (vtStruct->_total) { + } else if (resetTimer) { _timer = 0; } + return; } } @@ -2436,6 +2463,31 @@ void ASound::fade(int fadeDest, int fadeSteps, int fadeTicks, bool stopAfterFade _sound.fade(fadeDest, fadeSteps, fadeTicks, stopAfterFadeFlag); } +void ASound::fadeSound(int soundNum) { + play(soundNum, NULL, 0); + fade(127, 5, 1, false, NULL); +} + +/*--------------------------------------------------------------------------*/ + +ASoundExt::ASoundExt(): ASound() { + _soundNum = 0; +} + +void ASoundExt::synchronize(Serializer &s) { + ASound::synchronize(s); + s.syncAsSint16LE(_soundNum); +} + +void ASoundExt::signal() { + if (_soundNum != 0) { + fadeSound(_soundNum); + } +} + +void ASoundExt::fadeOut2(Action *action) { + fade(0, 10, 10, true, action); +} /*--------------------------------------------------------------------------*/ @@ -2488,7 +2540,12 @@ AdlibSoundDriver::AdlibSoundDriver(): SoundDriver() { _opl = OPL::Config::create(); assert(_opl); _opl->init(_sampleRate); - + + _samplesTillCallback = 0; + _samplesTillCallbackRemainder = 0; + _samplesPerCallback = getRate() / CALLBACKS_PER_SECOND; + _samplesPerCallbackRemainder = getRate() % CALLBACKS_PER_SECOND; + _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); Common::set_to(_channelVoiced, _channelVoiced + ADLIB_CHANNEL_COUNT, false); @@ -2558,7 +2615,7 @@ int AdlibSoundDriver::setMasterVolume(int volume) { return oldVolume; } -void AdlibSoundDriver::proc32(Sound *sound, int channel, int program, int v0, int v1) { +void AdlibSoundDriver::playSound(const byte *channelData, int dataOffset, int program, int channel, int v0, int v1) { if (program == -1) return; @@ -2750,34 +2807,38 @@ void AdlibSoundDriver::setFrequency(int channel) { } int AdlibSoundDriver::readBuffer(int16 *buffer, const int numSamples) { - update(buffer, numSamples); - return numSamples; -} - -void AdlibSoundDriver::update(int16 *buf, int len) { - static int samplesLeft = 0; - while (len != 0) { - int count = samplesLeft; - if (count > len) { - count = len; - } - samplesLeft -= count; - len -= count; - _opl->readBuffer(buf, count); - if (samplesLeft == 0) { + Common::StackLock slock1(SoundManager::sfManager()._serverDisabledMutex); + Common::StackLock slock2(SoundManager::sfManager()._serverSuspendedMutex); + + int32 samplesLeft = numSamples; + memset(buffer, 0, sizeof(int16) * numSamples); + while (samplesLeft) { + if (!_samplesTillCallback) { + SoundManager::_sfUpdateCallback(NULL); flush(); - samplesLeft = _sampleRate / 50; + + _samplesTillCallback = _samplesPerCallback; + _samplesTillCallbackRemainder += _samplesPerCallbackRemainder; + if (_samplesTillCallbackRemainder >= CALLBACKS_PER_SECOND) { + _samplesTillCallback++; + _samplesTillCallbackRemainder -= CALLBACKS_PER_SECOND; + } } - buf += count; + + int32 render = MIN<int>(samplesLeft, _samplesTillCallback); + samplesLeft -= render; + _samplesTillCallback -= render; + + _opl->readBuffer(buffer, render); + buffer += render; } + return numSamples; } /*--------------------------------------------------------------------------*/ -const byte adlibFx_group_data[] = { 3, 1, 1, 0, 0xff }; - -AdlibFxSoundDriver::AdlibFxSoundDriver(): SoundDriver() { +SoundBlasterDriver::SoundBlasterDriver(): SoundDriver() { _minVersion = 0x102; _maxVersion = 0x10A; _masterVolume = 0; @@ -2785,167 +2846,99 @@ AdlibFxSoundDriver::AdlibFxSoundDriver(): SoundDriver() { _groupData.groupMask = 1; _groupData.v1 = 0x3E; _groupData.v2 = 0; - _groupData.pData = &adlib_group_data[0]; + static byte const group_data[] = { 3, 1, 1, 0, 0xff }; + _groupData.pData = group_data; _mixer = _vm->_mixer; _sampleRate = _mixer->getOutputRate(); - _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); -/* - Common::set_to(_channelVoiced, _channelVoiced + ADLIB_CHANNEL_COUNT, false); - memset(_channelVolume, 0, ADLIB_CHANNEL_COUNT * sizeof(int)); - memset(_v4405E, 0, ADLIB_CHANNEL_COUNT * sizeof(int)); - memset(_v44067, 0, ADLIB_CHANNEL_COUNT * sizeof(int)); - memset(_v44070, 0, ADLIB_CHANNEL_COUNT * sizeof(int)); - memset(_v44079, 0, ADLIB_CHANNEL_COUNT * sizeof(int)); - memset(_v44082, 0, ADLIB_CHANNEL_COUNT * sizeof(int)); - _v44082[ADLIB_CHANNEL_COUNT] = 0x90; - Common::set_to(_pitchBlend, _pitchBlend + ADLIB_CHANNEL_COUNT, 0x2000); - memset(_v4409E, 0, ADLIB_CHANNEL_COUNT * sizeof(int)); - _patchData = NULL; -*/ + _audioStream = NULL; + _channelData = NULL; } -AdlibFxSoundDriver::~AdlibFxSoundDriver() { +SoundBlasterDriver::~SoundBlasterDriver() { _mixer->stopHandle(_soundHandle); } -bool AdlibFxSoundDriver::open() { - write209(); - write(64); - write(165); - - // for (int idx = 0; idx < 5000 * 16; ++idx) al = port[21h] - -// _v45071 = 1; -// _v4506F = 0; - +bool SoundBlasterDriver::open() { return true; } -void AdlibFxSoundDriver::close() { - write(208); - write211(); - +void SoundBlasterDriver::close() { } -bool AdlibFxSoundDriver::reset() { - +bool SoundBlasterDriver::reset() { return true; } -const GroupData *AdlibFxSoundDriver::getGroupData() { +const GroupData *SoundBlasterDriver::getGroupData() { return &_groupData; } -void AdlibFxSoundDriver::poll() { - if (!_masterVolume || !_channelVolume) { - if (_v45046) - write211(); - } else { - if (!_v45046) - write209(); - } -} - -int AdlibFxSoundDriver::setMasterVolume(int volume) { +int SoundBlasterDriver::setMasterVolume(int volume) { int oldVolume = _masterVolume; _masterVolume = volume; return oldVolume; } -void AdlibFxSoundDriver::proc32(Sound *sound, int channel, int program, int v0, int v1) { - if (program == -1) +void SoundBlasterDriver::playSound(const byte *channelData, int dataOffset, int program, int channel, int v0, int v1) { + if (program != -1) return; - if (_sound) + assert(channel == 0); + + // If sound data has been previously set, then release it + if (_channelData) updateVoice(channel); - // TODO: Stuff + // Set the new channel data + _channelData = channelData + dataOffset; + // Make a copy of the buffer + int dataSize = _vm->_memoryManager.getSize(channelData); + byte *soundData = (byte *)malloc(dataSize - dataOffset); + Common::copy(_channelData, _channelData + (dataSize - dataOffset), soundData); + _audioStream = Audio::makeQueuingAudioStream(11025, false); + _audioStream->queueBuffer(soundData, dataSize - dataOffset, DisposeAfterUse::YES, Audio::FLAG_UNSIGNED); + // Start the new sound + if (!_mixer->isSoundHandleActive(_soundHandle)) + _mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle, _audioStream); } -void AdlibFxSoundDriver::updateVoice(int channel) { - if (_sound) { - write(208); +void SoundBlasterDriver::updateVoice(int channel) { + // Stop the playing voice + if (_mixer->isSoundHandleActive(_soundHandle)) + _mixer->stopHandle(_soundHandle); - _sound = NULL; - _v45062 = 0; - _v45066 = 0; - _v45068 = 0; - } + _audioStream = NULL; + _channelData = NULL; } -void AdlibFxSoundDriver::proc38(int channel, int cmd, int value) { +void SoundBlasterDriver::proc38(int channel, int cmd, int value) { if (cmd == 7) { // Set channel volume _channelVolume = value; + _mixer->setChannelVolume(_soundHandle, (byte)MIN(255, value * 2)); } } -void AdlibFxSoundDriver::proc42(int channel, int cmd, int value, int *v1, int *v2) { - _v4506A = value; - *v1 = _v4506B; +void SoundBlasterDriver::proc42(int channel, int cmd, int value, int *v1, int *v2) { + // TODO: v2 is used for flagging a reset of the timer. I'm not sure if it's needed + *v1 = 0; *v2 = 0; - _v4506B = 0; - - if (!_sound) - *v2 = 1; -} - -void AdlibFxSoundDriver::write(int v) { - /* - port[adlib_port + 12] = v; - for (int i = 0; i < 100; ++i) { - if (!port[adlib_port + 12] & 0x80) - break; - } - */ -} - -void AdlibFxSoundDriver::flush() { - Common::StackLock slock(SoundManager::sfManager()._serverDisabledMutex); - - // No data output yet -} - - -int AdlibFxSoundDriver::readBuffer(int16 *buffer, const int numSamples) { - update(buffer, numSamples); - return numSamples; -} - -void AdlibFxSoundDriver::update(int16 *buf, int len) { -/* - static int samplesLeft = 0; - while (len != 0) { - int count = samplesLeft; - if (count > len) { - count = len; - } - samplesLeft -= count; - len -= count; - YM3812UpdateOne(_opl, buf, count); - if (samplesLeft == 0) { - flush(); - samplesLeft = _sampleRate / 50; - } - buf += count; + // Note: Checking whether a playing Fx sound had finished was originally done in another + // method in the sample playing code. But since we're using the ScummVM audio soundsystem, + // it's easier simply to do the check right here + if (_audioStream && (_audioStream->numQueuedStreams() == 0)) { + updateVoice(channel); } -*/ -} - -void AdlibFxSoundDriver::write209() { - write(209); - _v45046 = true; -} -void AdlibFxSoundDriver::write211() { - write(211); - _v45046 = false; + if (!_channelData) + // Flag that sound isn't playing + *v1 = 1; } -} // End of namespace tSage +} // End of namespace TsAGE diff --git a/engines/tsage/sound.h b/engines/tsage/sound.h index 6a47a1aaf5..afcc8f6377 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; @@ -41,6 +41,7 @@ class Sound; #define ROLAND_DRIVER_NUM 2 #define ADLIB_DRIVER_NUM 3 #define SBLASTER_DRIVER_NUM 4 +#define CALLBACKS_PER_SECOND 60 struct trackInfoStruct { int _numTracks; @@ -107,7 +108,7 @@ public: virtual void setProgram(int channel, int program) {} // Method #13 virtual void setVolume1(int channel, int v2, int v3, int volume) {} virtual void setPitchBlend(int channel, int pitchBlend) {} // Method #15 - virtual void proc32(Sound *sound, int channel, int program, int v0, int v1) {}// Method #16 + virtual void playSound(const byte *channelData, int dataOffset, int program, int channel, int v0, int v1) {}// Method #16 virtual void updateVoice(int channel) {} // Method #17 virtual void proc36() {} // Method #18 virtual void proc38(int channel, int cmd, int value) {} // Method #19 @@ -224,6 +225,7 @@ public: int getMasterVol() const; void loadSound(int soundNum, bool showErrors); void unloadSound(int soundNum); + bool isFading(); // _sf methods static SoundManager &sfManager(); @@ -348,8 +350,8 @@ public: void _soRemoteReceive(); void _soServiceTrackType0(int trackIndex, const byte *channelData); void _soUpdateDamper(VoiceTypeStruct *voiceType, int channelNum, VoiceType mode, int v0); - void _soProc32(VoiceTypeStruct *vtStruct, int channelNum, VoiceType voiceType, int v0, int v1); - void _soProc42(VoiceTypeStruct *vtStruct, int channelNum, VoiceType voiceType, int v0); + void _soPlaySound(VoiceTypeStruct *vtStruct, const byte *channelData, int channelNum, VoiceType voiceType, int v0, int v1); + void _soPlaySound2(VoiceTypeStruct *vtStruct, const byte *channelData, int channelNum, VoiceType voiceType, int v0); void _soProc38(VoiceTypeStruct *vtStruct, int channelNum, VoiceType voiceType, int cmd, int value); void _soProc40(VoiceTypeStruct *vtStruct, int channelNum, int pitchBlend); void _soDoTrackCommand(int channelNum, int command, int value); @@ -396,8 +398,22 @@ public: int getVol() const { return _sound.getVol(); } void holdAt(int v) { _sound.holdAt(v); } void release() { _sound.release(); } + void fadeSound(int soundNum); }; +class ASoundExt: public ASound { +public: + int _soundNum; + + ASoundExt(); + void fadeOut2(Action *action); + + virtual Common::String getClassName() { return "ASoundExt"; } + virtual void synchronize(Serializer &s); + virtual void signal(); +}; + + #define ADLIB_CHANNEL_COUNT 9 class AdlibSoundDriver: public SoundDriver, Audio::AudioStream { @@ -411,6 +427,10 @@ private: const byte *_patchData; int _masterVolume; Common::Queue<RegisterValue> _queue; + int _samplesTillCallback; + int _samplesTillCallbackRemainder; + int _samplesPerCallback; + int _samplesPerCallbackRemainder; bool _channelVoiced[ADLIB_CHANNEL_COUNT]; int _channelVolume[ADLIB_CHANNEL_COUNT]; @@ -440,7 +460,7 @@ public: virtual const GroupData *getGroupData(); virtual void installPatch(const byte *data, int size); virtual int setMasterVolume(int volume); - virtual void proc32(Sound *sound, int channel, int program, int v0, int v1); + virtual void playSound(const byte *channelData, int dataOffset, int program, int channel, int v0, int v1); virtual void updateVoice(int channel); virtual void proc38(int channel, int cmd, int value); virtual void setPitch(int channel, int pitchBlend); @@ -454,54 +474,33 @@ public: void update(int16 *buf, int len); }; -class AdlibFxSoundDriver: public SoundDriver, Audio::AudioStream { +class SoundBlasterDriver: public SoundDriver { private: - Common::Queue<RegisterValue> _queue; GroupData _groupData; Audio::Mixer *_mixer; Audio::SoundHandle _soundHandle; + Audio::QueuingAudioStream *_audioStream; int _sampleRate; - int _v45062; - int _v45066; - int _v45068; - int _v4506A; - int _v4506B; - bool _v45046; byte _masterVolume; byte _channelVolume; - Sound *_sound; - - void write(int v); - void flush(); - void sub_4556E(); - void write209(); - void write211(); + const byte *_channelData; public: - AdlibFxSoundDriver(); - virtual ~AdlibFxSoundDriver(); + SoundBlasterDriver(); + virtual ~SoundBlasterDriver(); virtual bool open(); virtual void close(); virtual bool reset(); virtual const GroupData *getGroupData(); - virtual void poll(); virtual int setMasterVolume(int volume); - virtual void proc32(Sound *sound, int channel, int program, int v0, int v1); + virtual void playSound(const byte *channelData, int dataOffset, int program, int channel, int v0, int v1); virtual void updateVoice(int channel); virtual void proc38(int channel, int cmd, int value); virtual void proc42(int channel, int cmd, int value, int *v1, int *v2); - - // AudioStream interface - virtual int readBuffer(int16 *buffer, const int numSamples); - virtual bool isStereo() const { return false; } - virtual bool endOfData() const { return false; } - virtual int getRate() const { return _sampleRate; } - - void update(int16 *buf, int len); }; -} // End of namespace tSage +} // End of namespace TsAGE #endif diff --git a/engines/tsage/staticres.cpp b/engines/tsage/staticres.cpp index 9f36268ce3..819cf56f31 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,37 @@ 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"; + +// Scene 50 hotspots +const char *GRANDMA_FRANNIE = "Grandma Frannie"; +const char *MARINA = "Marina"; +const char *POLICE_DEPARTMENT = "Police Department"; +const char *TONYS_BAR = "Tony's Bar"; +const char *CHILD_PROTECTIVE_SERVICES = "Child Protective Services"; +const char *ALLEY_CAT = "Alley Cat"; +const char *CITY_HALL_JAIL = "City Hall & Jail"; +const char *JAMISON_RYAN = "Jamison & Ryan"; +const char *BIKINI_HUT = "Bikini Hut"; + +} // End of namespace BlueForce + +} // End of namespace TsAGE diff --git a/engines/tsage/staticres.h b/engines/tsage/staticres.h index fa93511779..b08e92def2 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,39 @@ 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; + +// Scene 50 tooltips +extern const char *GRANDMA_FRANNIE; +extern const char *MARINA; +extern const char *POLICE_DEPARTMENT; +extern const char *TONYS_BAR; +extern const char *CHILD_PROTECTIVE_SERVICES; +extern const char *ALLEY_CAT; +extern const char *CITY_HALL_JAIL; +extern const char *JAMISON_RYAN; +extern const char *BIKINI_HUT; + +} // End of namespace BlueForce + +} // End of namespace TsAGE #endif diff --git a/engines/tsage/tsage.cpp b/engines/tsage/tsage.cpp index 41f3d58897..2fcabff16c 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 @@ -98,7 +102,7 @@ Common::Error TSageEngine::run() { // Basic initialisation initialize(); - _globals->_sceneHandler.registerHandler(); + _globals->_sceneHandler->registerHandler(); _globals->_game->execute(); deinitialize(); @@ -147,4 +151,8 @@ void TSageEngine::syncSoundSettings() { _globals->_soundManager.syncSounds(); } -} // End of namespace tSage +bool TSageEngine::shouldQuit() { + return getEventManager()->shouldQuit() || getEventManager()->shouldRTL(); +} + +} // End of namespace TsAGE diff --git a/engines/tsage/tsage.h b/engines/tsage/tsage.h index f004c7f625..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, @@ -78,6 +78,7 @@ public: uint32 getGameID() const; uint32 getFeatures() const; Common::String getPrimaryFilename() const; + bool shouldQuit(); virtual Common::Error init(); virtual Common::Error run(); @@ -98,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 |