From f5f9da940b6071df1e921faa42fa56a501e2ab62 Mon Sep 17 00:00:00 2001 From: Torbjörn Andersson Date: Tue, 3 May 2005 09:00:06 +0000 Subject: More cleanup/restructuring: Moved walk-related code from Logic to Router. (I may have to think up some better name for that class later.) svn-id: r17901 --- sword2/anims.cpp | 15 +- sword2/function.cpp | 557 +++++++++------------------------------------------- sword2/logic.h | 14 +- sword2/router.h | 22 +++ sword2/speech.cpp | 5 +- sword2/walker.cpp | 376 ++++++++++++++++++++++++++++++++++- 6 files changed, 503 insertions(+), 486 deletions(-) (limited to 'sword2') diff --git a/sword2/anims.cpp b/sword2/anims.cpp index 7f4a78b152..d4badbf640 100644 --- a/sword2/anims.cpp +++ b/sword2/anims.cpp @@ -33,7 +33,6 @@ #include "sword2/interpreter.h" #include "sword2/logic.h" #include "sword2/maketext.h" -#include "sword2/memory.h" #include "sword2/resman.h" #include "sword2/sound.h" #include "sword2/driver/animation.h" @@ -45,8 +44,8 @@ int32 Logic::animate(int32 *params, bool reverse) { // 1 pointer to object's graphic structure // 2 resource id of animation file - ObjectLogic *ob_logic = (ObjectLogic *) _vm->_memory->decodePtr(params[0]); - ObjectGraphic *ob_graphic = (ObjectGraphic *) _vm->_memory->decodePtr(params[1]); + ObjectLogic *ob_logic = (ObjectLogic *) decodePtr(params[0]); + ObjectGraphic *ob_graphic = (ObjectGraphic *) decodePtr(params[1]); byte *anim_file; AnimHeader *anim_head; int32 res = params[2]; @@ -166,11 +165,11 @@ int32 Logic::megaTableAnimate(int32 *params, bool reverse) { // If this is the start of the anim, read the anim table to get the // appropriate anim resource - ObjectLogic *ob_logic = (ObjectLogic *) _vm->_memory->decodePtr(params[0]); + ObjectLogic *ob_logic = (ObjectLogic *) decodePtr(params[0]); if (ob_logic->looping == 0) { - ObjectMega *ob_mega = (ObjectMega *) _vm->_memory->decodePtr(params[2]); - uint32 *anim_table = (uint32 *) _vm->_memory->decodePtr(params[3]); + ObjectMega *ob_mega = (ObjectMega *) decodePtr(params[2]); + uint32 *anim_table = (uint32 *) decodePtr(params[3]); // appropriate anim resource is in 'table[direction]' pars[2] = anim_table[ob_mega->current_dir]; @@ -180,14 +179,14 @@ int32 Logic::megaTableAnimate(int32 *params, bool reverse) { } void Logic::setSpriteStatus(uint32 sprite, uint32 type) { - ObjectGraphic *ob_graphic = (ObjectGraphic *) _vm->_memory->decodePtr(sprite); + ObjectGraphic *ob_graphic = (ObjectGraphic *) decodePtr(sprite); // Remove the previous status, but don't affect the shading upper-word ob_graphic->type = (ob_graphic->type & 0xffff0000) | type; } void Logic::setSpriteShading(uint32 sprite, uint32 type) { - ObjectGraphic *ob_graphic = (ObjectGraphic *) _vm->_memory->decodePtr(sprite); + ObjectGraphic *ob_graphic = (ObjectGraphic *) decodePtr(sprite); // Remove the previous shading, but don't affect the status lower-word. // Note that drivers may still shade mega frames automatically, even diff --git a/sword2/function.cpp b/sword2/function.cpp index 6508cee08a..da921ba4a4 100644 --- a/sword2/function.cpp +++ b/sword2/function.cpp @@ -29,7 +29,6 @@ #include "sword2/interpreter.h" #include "sword2/logic.h" #include "sword2/maketext.h" -#include "sword2/memory.h" #include "sword2/mouse.h" #include "sword2/resman.h" #include "sword2/router.h" @@ -53,7 +52,7 @@ int32 Logic::fnRegisterStartPoint(int32 *params) { // 1 pointer to ascii message int32 key = params[0]; - char *name = (char *) _vm->_memory->decodePtr(params[1]); + char *name = (char *) decodePtr(params[1]); _vm->registerStartPoint(key, name); return IR_CONT; @@ -107,7 +106,7 @@ int32 Logic::fnRegisterMouse(int32 *params) { // params: 0 pointer to ObjectMouse or 0 for no write to mouse // list - ObjectMouse *ob_mouse = (ObjectMouse *) _vm->_memory->decodePtr(params[0]); + ObjectMouse *ob_mouse = (ObjectMouse *) decodePtr(params[0]); _vm->_mouse->registerMouse(ob_mouse, NULL); return IR_CONT; @@ -197,162 +196,12 @@ int32 Logic::fnWalk(int32 *params) { // 5 target y-coord // 6 target direction (8 means end walk on ANY direction) - ObjectLogic *ob_logic = (ObjectLogic *) _vm->_memory->decodePtr(params[0]); - ObjectGraphic *ob_graph = (ObjectGraphic *) _vm->_memory->decodePtr(params[1]); - ObjectMega *ob_mega = (ObjectMega *) _vm->_memory->decodePtr(params[2]); - - int16 target_x = (int16) params[4]; - int16 target_y = (int16) params[5]; - uint8 target_dir = (uint8) params[6]; - - ObjectWalkdata *ob_walkdata; - - // If this is the start of the walk, calculate the route. - - if (!ob_logic->looping) { - // If we're already there, don't even bother allocating - // memory and calling the router, just quit back & continue - // the script! This avoids an embarassing mega stand frame - // appearing for one cycle when we're already in position for - // an anim eg. repeatedly clicking on same object to repeat - // an anim - no mega frame will appear in between runs of the - // anim. - - if (ob_mega->feet_x == target_x && ob_mega->feet_y == target_y && ob_mega->current_dir == target_dir) { - _scriptVars[RESULT] = 0; - return IR_CONT; - } - - assert(params[6] >= 0 && params[6] <= 8); - - ob_walkdata = (ObjectWalkdata *) _vm->_memory->decodePtr(params[3]); - - ob_mega->walk_pc = 0; - - // Set up mem for _walkData in route_slots[] & set mega's - // 'route_slot_id' accordingly - - _router->allocateRouteMem(); - - int32 route = _router->routeFinder(ob_mega, ob_walkdata, target_x, target_y, target_dir); - - // 0 = can't make route to target - // 1 = created route - // 2 = zero route but may need to turn - - if (route == 1 || route == 2) { - // so script fnWalk loop continues until end of - // walk-anim - - ob_logic->looping = 1; - - // need to animate the route now, so don't set result - // or return yet! - - // started walk - ob_mega->currently_walking = 1; - - // (see fnGetPlayerSaveData() in save_rest.cpp - } else { - _router->freeRouteMem(); - _scriptVars[RESULT] = 1; - return IR_CONT; - } - - // Walk is about to start, so set the mega's graphic resource - ob_graph->anim_resource = ob_mega->megaset_res; - } else if (_scriptVars[EXIT_FADING] && _vm->_screen->getFadeStatus() == RDFADE_BLACK) { - // Double clicked an exit so quit the walk when screen is black - // ok, thats it - back to script and change screen - - ob_logic->looping = 0; - _router->freeRouteMem(); - - // Must clear in-case on the new screen there's a walk - // instruction (which would get cut short) - _scriptVars[EXIT_CLICK_ID] = 0; - - // finished walk - ob_mega->currently_walking = 0; - - // see fnGetPlayerSaveData() in save_rest.cpp - - _scriptVars[RESULT] = 0; - - // continue the script so that RESULT can be checked! - return IR_CONT; - } - - // get pointer to walkanim & current frame position - - WalkData *walkAnim = _router->getRouteMem(); - int32 walk_pc = ob_mega->walk_pc; - - // If stopping the walk early, overwrite the next step with a - // slow-out, then finish - - if (checkEventWaiting()) { - if (walkAnim[walk_pc].step == 0 && walkAnim[walk_pc + 1].step == 1) { - // At the beginning of a step - ob_walkdata = (ObjectWalkdata *) _vm->_memory->decodePtr(params[3]); - _router->earlySlowOut(ob_mega, ob_walkdata); - } - } - - // Get new frame of walk - - ob_graph->anim_pc = walkAnim[walk_pc].frame; - ob_mega->current_dir = walkAnim[walk_pc].dir; - ob_mega->feet_x = walkAnim[walk_pc].x; - ob_mega->feet_y = walkAnim[walk_pc].y; - - // Check if NEXT frame is in fact the end-marker of the walk sequence - // so we can return to script just as the final (stand) frame of the - // walk is set - so that if followed by an anim, the anim's first - // frame replaces the final stand-frame of the walk (see below) - - // '512' is end-marker - if (walkAnim[walk_pc + 1].frame == 512) { - ob_logic->looping = 0; - _router->freeRouteMem(); - - // finished walk - ob_mega->currently_walking = 0; - - // (see fnGetPlayerSaveData() in save_rest.cpp - - // if George's walk has been interrupted to run a new action - // script for instance or Nico's walk has been interrupted by - // player clicking on her to talk - - // There used to be code here for checking if two megas were - // colliding, but that code had been commented out, and it - // was only run if a function that always returned zero - // returned non-zero. - - if (checkEventWaiting()) { - startEvent(); - _scriptVars[RESULT] = 1; - return IR_TERMINATE; - } else { - _scriptVars[RESULT] = 0; - - // CONTINUE the script so that RESULT can be checked! - // Also, if an anim command follows the fnWalk command, - // the 1st frame of the anim (which is always a stand - // frame itself) can replace the final stand frame of - // the walk, to hide the slight difference between the - // shrinking on the mega frames and the pre-shrunk anim - // start-frame. - - return IR_CONT; - } - } - - // Increment the walkanim frame number and come back next cycle - - ob_mega->walk_pc++; - return IR_REPEAT; + return _router->doWalk( + (ObjectLogic *) decodePtr(params[0]), + (ObjectGraphic *) decodePtr(params[1]), + (ObjectMega *) decodePtr(params[2]), + (ObjectWalkdata *) decodePtr(params[3]), + params[4], params[5], params[6]); } /** @@ -366,52 +215,16 @@ int32 Logic::fnWalkToAnim(int32 *params) { // 3 pointer to object's walkdata structure // 4 anim resource id - int32 pars[7]; - - // Walkdata is needed for earlySlowOut if player clicks elsewhere - // during the walk. - - pars[0] = params[0]; - pars[1] = params[1]; - pars[2] = params[2]; - pars[3] = params[3]; - - ObjectLogic *ob_logic = (ObjectLogic *) _vm->_memory->decodePtr(params[0]); - - // If this is the start of the walk, read anim file to get start coords - - if (!ob_logic->looping) { - byte *anim_file = _vm->_resman->openResource(params[4]); - AnimHeader *anim_head = _vm->fetchAnimHeader( anim_file ); - - pars[4] = anim_head->feetStartX; - pars[5] = anim_head->feetStartY; - pars[6] = anim_head->feetStartDir; - - _vm->_resman->closeResource(params[4]); - - // If start coords not yet set in anim header, use the standby - // coords (which should be set beforehand in the script). - - if (pars[4] == 0 && pars[5] == 0) { - byte buf[NAME_LEN]; - - pars[4] = _standbyX; - pars[5] = _standbyY; - pars[6] = _standbyDir; - - debug(3, "WARNING: fnWalkToAnim(%s) used standby coords", _vm->fetchObjectName(params[4], buf)); - } - - assert(pars[6] >= 0 && pars[6] <= 7); - } - - return fnWalk(pars); + return _router->walkToAnim( + (ObjectLogic *) decodePtr(params[0]), + (ObjectGraphic *) decodePtr(params[1]), + (ObjectMega *) decodePtr(params[2]), + (ObjectWalkdata *) decodePtr(params[3]), + params[4]); } /** - * Turn mega to the specified direction. Just needs to call fnWalk() with - * current feet coords, so router can produce anim of turn frames. + * Turn mega to the specified direction. */ int32 Logic::fnTurn(int32 *params) { @@ -421,29 +234,12 @@ int32 Logic::fnTurn(int32 *params) { // 3 pointer to object's walkdata structure // 4 target direction - int32 pars[7]; - - pars[0] = params[0]; - pars[1] = params[1]; - pars[2] = params[2]; - pars[3] = params[3]; - - ObjectLogic *ob_logic = (ObjectLogic *) _vm->_memory->decodePtr(params[0]); - - // If this is the start of the turn, get the mega's current feet - // coords + the required direction - - if (!ob_logic->looping) { - assert(params[4] >= 0 && params[4] <= 7); - - ObjectMega *ob_mega = (ObjectMega *) _vm->_memory->decodePtr(params[2]); - - pars[4] = ob_mega->feet_x; - pars[5] = ob_mega->feet_y; - pars[6] = params[4]; - } - - return fnWalk(pars); + return _router->doFace( + (ObjectLogic *) decodePtr(params[0]), + (ObjectGraphic *) decodePtr(params[1]), + (ObjectMega *) decodePtr(params[2]), + (ObjectWalkdata *) decodePtr(params[3]), + params[4]); } /** @@ -459,47 +255,28 @@ int32 Logic::fnStandAt(int32 *params) { // 3 target y-coord // 4 target direction - assert(params[4] >= 0 && params[4] <= 7); - - ObjectGraphic *ob_graph = (ObjectGraphic *) _vm->_memory->decodePtr(params[0]); - ObjectMega *ob_mega = (ObjectMega *) _vm->_memory->decodePtr(params[1]); - - // set up the stand frame & set the mega's new direction - - ob_mega->feet_x = params[2]; - ob_mega->feet_y = params[3]; - ob_mega->current_dir = params[4]; - - // mega-set animation file - ob_graph->anim_resource = ob_mega->megaset_res; - - // dir + first stand frame (always frame 96) - ob_graph->anim_pc = params[4] + 96; - + _router->standAt( + (ObjectGraphic *) decodePtr(params[0]), + (ObjectMega *) decodePtr(params[1]), + params[2], params[3], params[4]); return IR_CONT; } /** * Stand mega into the specified direction at current feet coords. - * Just needs to call fnStandAt() with current feet coords. + * Just needs to call standAt() with current feet coords. */ int32 Logic::fnStand(int32 *params) { // params: 0 pointer to object's graphic structure // 1 pointer to object's mega structure // 2 target direction + ObjectMega *ob_mega = (ObjectMega *) decodePtr(params[1]); - ObjectMega *ob_mega = (ObjectMega *) _vm->_memory->decodePtr(params[1]); - - int32 pars[5]; - - pars[0] = params[0]; - pars[1] = params[1]; - pars[2] = ob_mega->feet_x; - pars[3] = ob_mega->feet_y; - pars[4] = params[2]; - - return fnStandAt(pars); + _router->standAt( + (ObjectGraphic *) decodePtr(params[0]), + ob_mega, ob_mega->feet_x, ob_mega->feet_y, params[2]); + return IR_CONT; } /** @@ -511,35 +288,11 @@ int32 Logic::fnStandAfterAnim(int32 *params) { // 1 pointer to object's mega structure // 2 anim resource id - byte *anim_file = _vm->_resman->openResource(params[2]); - AnimHeader *anim_head = _vm->fetchAnimHeader(anim_file); - - int32 pars[5]; - - pars[0] = params[0]; - pars[1] = params[1]; - - pars[2] = anim_head->feetEndX; - pars[3] = anim_head->feetEndY; - pars[4] = anim_head->feetEndDir; - - // If start coords not available either use the standby coords (which - // should be set beforehand in the script) - - if (pars[2] == 0 && pars[3] == 0) { - byte buf[NAME_LEN]; - - pars[2] = _standbyX; - pars[3] = _standbyY; - pars[4] = _standbyDir; - - debug(3, "WARNING: fnStandAfterAnim(%s) used standby coords", _vm->fetchObjectName(params[2], buf)); - } - - assert(pars[4] >= 0 && pars[4] <= 7); - - _vm->_resman->closeResource(params[2]); - return fnStandAt(pars); + _router->standAfterAnim( + (ObjectGraphic *) decodePtr(params[0]), + (ObjectMega *) decodePtr(params[1]), + params[2]); + return IR_CONT; } int32 Logic::fnPause(int32 *params) { @@ -549,7 +302,7 @@ int32 Logic::fnPause(int32 *params) { // NB. Pause-value of 0 causes script to continue, 1 causes a 1-cycle // quit, 2 gives 2 cycles, etc. - ObjectLogic *ob_logic = (ObjectLogic *) _vm->_memory->decodePtr(params[0]); + ObjectLogic *ob_logic = (ObjectLogic *) decodePtr(params[0]); if (ob_logic->looping == 0) { ob_logic->looping = 1; @@ -577,9 +330,8 @@ int32 Logic::fnMegaTableAnim(int32 *params) { int32 Logic::fnAddMenuObject(int32 *params) { // params: 0 pointer to a MenuObject structure to copy down - MenuObject *menuObject = (MenuObject *) _vm->_memory->decodePtr(params[0]); - _vm->_mouse->addMenuObject(menuObject); + _vm->_mouse->addMenuObject((MenuObject *) decodePtr(params[0])); return IR_CONT; } @@ -628,7 +380,7 @@ int32 Logic::fnSetFrame(int32 *params) { AnimHeader *anim_head = _vm->fetchAnimHeader(anim_file); // set up anim resource in graphic object - ObjectGraphic *ob_graphic = (ObjectGraphic *) _vm->_memory->decodePtr(params[0]); + ObjectGraphic *ob_graphic = (ObjectGraphic *) decodePtr(params[0]); ob_graphic->anim_resource = res; ob_graphic->anim_pc = params[2] ? anim_head->noAnimFrames - 1 : 0; @@ -643,7 +395,7 @@ int32 Logic::fnRandomPause(int32 *params) { // 1 minimum number of game-cycles to pause // 2 maximum number of game-cycles to pause - ObjectLogic *ob_logic = (ObjectLogic *) _vm->_memory->decodePtr(params[0]); + ObjectLogic *ob_logic = (ObjectLogic *) decodePtr(params[0]); int32 pars[2]; if (ob_logic->looping == 0) { @@ -666,9 +418,9 @@ int32 Logic::fnRegisterFrame(int32 *params) { // 1 pointer to graphic structure // 2 pointer to mega structure or NULL if not a mega - ObjectMouse *ob_mouse = (ObjectMouse *) _vm->_memory->decodePtr(params[0]); - ObjectGraphic *ob_graph = (ObjectGraphic *) _vm->_memory->decodePtr(params[1]); - ObjectMega *ob_mega = (ObjectMega *) _vm->_memory->decodePtr(params[2]); + ObjectMouse *ob_mouse = (ObjectMouse *) decodePtr(params[0]); + ObjectGraphic *ob_graph = (ObjectGraphic *) decodePtr(params[1]); + ObjectMega *ob_mega = (ObjectMega *) decodePtr(params[2]); _vm->_screen->registerFrame(ob_mouse, ob_graph, ob_mega); return IR_CONT; @@ -705,7 +457,7 @@ int32 Logic::fnUpdatePlayerStats(int32 *params) { // params: 0 pointer to mega structure - ObjectMega *ob_mega = (ObjectMega *) _vm->_memory->decodePtr(params[0]); + ObjectMega *ob_mega = (ObjectMega *) decodePtr(params[0]); ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); screenInfo->player_feet_x = ob_mega->feet_x; @@ -738,7 +490,7 @@ int32 Logic::fnPassGraph(int32 *params) { int32 Logic::fnInitFloorMouse(int32 *params) { // params: 0 pointer to object's mouse structure - ObjectMouse *ob_mouse = (ObjectMouse *) _vm->_memory->decodePtr(params[0]); + ObjectMouse *ob_mouse = (ObjectMouse *) decodePtr(params[0]); ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); // floor is always lowest priority @@ -762,14 +514,12 @@ int32 Logic::fnPassMega(int32 *params) { // params: 0 pointer to a mega structure - memcpy(&_engineMega, _vm->_memory->decodePtr(params[0]), sizeof(ObjectMega)); + memcpy(&_engineMega, decodePtr(params[0]), sizeof(ObjectMega)); return IR_CONT; } /** * Turn mega to face point (x,y) on the floor - * Just needs to call fnWalk() with current feet coords & direction computed - * by whatTarget() */ int32 Logic::fnFaceXY(int32 *params) { @@ -780,27 +530,12 @@ int32 Logic::fnFaceXY(int32 *params) { // 4 target x-coord // 5 target y-coord - int32 pars[7]; - - pars[0] = params[0]; - pars[1] = params[1]; - pars[2] = params[2]; - pars[3] = params[3]; - - ObjectLogic *ob_logic = (ObjectLogic *) _vm->_memory->decodePtr(params[0]); - - // If this is the start of the turn, get the mega's current feet - // coords + the required direction - - if (!ob_logic->looping) { - ObjectMega *ob_mega = (ObjectMega *) _vm->_memory->decodePtr(params[2]); - - pars[4] = ob_mega->feet_x; - pars[5] = ob_mega->feet_y; - pars[6] = whatTarget(ob_mega->feet_x, ob_mega->feet_y, params[4], params[5]); - } - - return fnWalk(pars); + return _router->faceXY( + (ObjectLogic *) decodePtr(params[0]), + (ObjectGraphic *) decodePtr(params[1]), + (ObjectMega *) decodePtr(params[2]), + (ObjectWalkdata *) decodePtr(params[3]), + params[4], params[5]); } /** @@ -894,7 +629,7 @@ int32 Logic::fnTheyDoWeWait(int32 *params) { _vm->_resman->closeResource(target); - ObjectLogic *ob_logic = (ObjectLogic *) _vm->_memory->decodePtr(params[0]); + ObjectLogic *ob_logic = (ObjectLogic *) decodePtr(params[0]); if (_scriptVars[RESULT] == 1 && !_scriptVars[INS_COMMAND] && ob_logic->looping == 0) { // The target is waiting, i.e. not busy, and there is no other @@ -1001,65 +736,14 @@ int32 Logic::fnWalkToTalkToMega(int32 *params) { // 2 pointer to object's mega structure // 3 pointer to object's walkdata structure // 4 id of target mega to face - // 5 distance - - int32 pars[7]; - - pars[0] = params[0]; - pars[1] = params[1]; - pars[2] = params[2]; - pars[3] = params[3]; - - ObjectLogic *ob_logic = (ObjectLogic *) _vm->_memory->decodePtr(params[0]); - - // If this is the start of the walk, calculate the route. - - if (!ob_logic->looping) { - StandardHeader *head = (StandardHeader *) _vm->_resman->openResource(params[4]); - - assert(head->fileType == GAME_OBJECT); - - // Call the base script. This is the graphic/mouse service - // call, and will set _engineMega to the ObjectMega of mega we - // want to route to. + // 5 separation - char *raw_script_ad = (char *) head; - uint32 null_pc = 3; - - runScript(raw_script_ad, raw_script_ad, &null_pc); - - _vm->_resman->closeResource(params[4]); - - // Stand exactly beside the mega, ie. at same y-coord - pars[5] = _engineMega.feet_y; - - ObjectMega *ob_mega = (ObjectMega *) _vm->_memory->decodePtr(params[2]); - - // Apply scale factor to walk distance. Ay+B gives 256 * scale - // ie. 256 * 256 * true_scale for even better accuracy, ie. - // scale = (Ay + B) / 256 - - int scale = (ob_mega->scale_a * ob_mega->feet_y + ob_mega->scale_b) / 256; - int mega_separation = (params[5] * scale) / 256; - - debug(4, "Target is at (%d, %d), separation %d", _engineMega.feet_x, _engineMega.feet_y, mega_separation); - - if (_engineMega.feet_x < ob_mega->feet_x) { - // Target is left of us, so aim to stand to their - // right. Face down_left - - pars[4] = _engineMega.feet_x + mega_separation; - pars[6] = 5; - } else { - // Ok, must be right of us so aim to stand to their - // left. Face down_right. - - pars[4] = _engineMega.feet_x - mega_separation; - pars[6] = 3; - } - } - - return fnWalk(pars); + return _router->walkToTalkToMega( + (ObjectLogic *) decodePtr(params[0]), + (ObjectGraphic *) decodePtr(params[1]), + (ObjectMega *) decodePtr(params[2]), + (ObjectWalkdata *) decodePtr(params[3]), + params[4], params[5]); } int32 Logic::fnFadeDown(int32 *params) { @@ -1111,8 +795,8 @@ int32 Logic::fnISpeak(int32 *params) { // Set up the pointers which we know we'll always need - ObjectLogic *ob_logic = (ObjectLogic *) _vm->_memory->decodePtr(params[S_OB_LOGIC]); - ObjectGraphic *ob_graphic = (ObjectGraphic *) _vm->_memory->decodePtr(params[S_OB_GRAPHIC]); + ObjectLogic *ob_logic = (ObjectLogic *) decodePtr(params[S_OB_LOGIC]); + ObjectGraphic *ob_graphic = (ObjectGraphic *) decodePtr(params[S_OB_GRAPHIC]); // FIRST TIME ONLY: create the text, load the wav, set up the anim, // etc. @@ -1229,8 +913,8 @@ int32 Logic::fnISpeak(int32 *params) { // Use this direction table to derive the anim // NB. ASSUMES WE HAVE A MEGA OBJECT!! - ObjectMega *ob_mega = (ObjectMega *) _vm->_memory->decodePtr(params[S_OB_MEGA]); - int32 *anim_table = (int32 *) _vm->_memory->decodePtr(params[S_DIR_TABLE]); + ObjectMega *ob_mega = (ObjectMega *) decodePtr(params[S_OB_MEGA]); + int32 *anim_table = (int32 *) decodePtr(params[S_DIR_TABLE]); _animId = anim_table[ob_mega->current_dir]; } else { @@ -1504,7 +1188,7 @@ int32 Logic::fnSpeechProcess(int32 *params) { // 3 pointer to ob_mega // 4 pointer to ob_walkdata - ObjectSpeech *ob_speech = (ObjectSpeech *) _vm->_memory->decodePtr(params[1]); + ObjectSpeech *ob_speech = (ObjectSpeech *) decodePtr(params[1]); while (1) { int32 pars[9]; @@ -1733,7 +1417,7 @@ int32 Logic::fnSetScaling(int32 *params) { // Where s is system scale, which itself is (256 * actual_scale) ie. // s == 128 is half size - ObjectMega *ob_mega = (ObjectMega *) _vm->_memory->decodePtr(params[0]); + ObjectMega *ob_mega = (ObjectMega *) decodePtr(params[0]); ob_mega->scale_a = params[1]; ob_mega->scale_b = params[2]; @@ -1793,7 +1477,7 @@ int32 Logic::fnTimedWait(int32 *params) { StandardHeader *head = (StandardHeader *) _vm->_resman->openResource(params[1]); assert(head->fileType == GAME_OBJECT); - ObjectLogic *ob_logic = (ObjectLogic *) _vm->_memory->decodePtr(params[0]); + ObjectLogic *ob_logic = (ObjectLogic *) decodePtr(params[0]); if (!ob_logic->looping) { // This is the first time, so set up the time-out. @@ -1915,7 +1599,7 @@ int32 Logic::fnSetValue(int32 *params) { // params: 0 pointer to object's mega structure // 1 value to set it to - ObjectMega *ob_mega = (ObjectMega *) _vm->_memory->decodePtr(params[0]); + ObjectMega *ob_mega = (ObjectMega *) decodePtr(params[0]); ob_mega->megaset_res = params[1]; return IR_CONT; @@ -2041,12 +1725,7 @@ int32 Logic::fnSetStandbyCoords(int32 *params) { // 1 y-coord // 2 direction (0..7) - assert(params[2] >= 0 && params[2] <= 7); - - _standbyX = (int16) params[0]; - _standbyY = (int16) params[1]; - _standbyDir = (uint8) params[2]; - + _router->setStandbyCoords(params[0], params[1], params[2]); return IR_CONT; } @@ -2122,35 +1801,11 @@ int32 Logic::fnStandAtAnim(int32 *params) { // 1 pointer to object's mega structure // 2 anim resource id - byte *anim_file = _vm->_resman->openResource(params[2]); - AnimHeader *anim_head = _vm->fetchAnimHeader(anim_file); - - int32 pars[5]; - - pars[0] = params[0]; - pars[1] = params[1]; - - pars[2] = anim_head->feetStartX; - pars[3] = anim_head->feetStartY; - pars[4] = anim_head->feetStartDir; - - // If start coords not available use the standby coords (which should - // be set beforehand in the script) - - if (pars[2] == 0 && pars[3] == 0) { - byte buf[NAME_LEN]; - - pars[2] = _standbyX; - pars[3] = _standbyY; - pars[4] = _standbyDir; - - debug(3, "WARNING: fnStandAtAnim(%s) used standby coords", _vm->fetchObjectName(params[2], buf)); - } - - assert(pars[4] >= 0 && pars[4] <= 7); - - _vm->_resman->closeResource(params[2]); - return fnStandAt(pars); + _router->standAtAnim( + (ObjectGraphic *) decodePtr(params[0]), + (ObjectMega *) decodePtr(params[1]), + params[2]); + return IR_CONT; } #define SCROLL_MOUSE_WIDTH 20 @@ -2158,7 +1813,7 @@ int32 Logic::fnStandAtAnim(int32 *params) { int32 Logic::fnSetScrollLeftMouse(int32 *params) { // params: 0 pointer to object's mouse structure - ObjectMouse *ob_mouse = (ObjectMouse *) _vm->_memory->decodePtr(params[0]); + ObjectMouse *ob_mouse = (ObjectMouse *) decodePtr(params[0]); ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); // Highest priority @@ -2183,7 +1838,7 @@ int32 Logic::fnSetScrollLeftMouse(int32 *params) { int32 Logic::fnSetScrollRightMouse(int32 *params) { // params: 0 pointer to object's mouse structure - ObjectMouse *ob_mouse = (ObjectMouse *) _vm->_memory->decodePtr(params[0]); + ObjectMouse *ob_mouse = (ObjectMouse *) decodePtr(params[0]); ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); // Highest priority @@ -2302,9 +1957,9 @@ int32 Logic::fnGetPlayerSaveData(int32 *params) { // 1 pointer to object's graphic structure // 2 pointer to object's mega structure - byte *logic_ptr = _vm->_memory->decodePtr(params[0]); - byte *graphic_ptr = _vm->_memory->decodePtr(params[1]); - byte *mega_ptr = _vm->_memory->decodePtr(params[2]); + byte *logic_ptr = decodePtr(params[0]); + byte *graphic_ptr = decodePtr(params[1]); + byte *mega_ptr = decodePtr(params[2]); // Copy from savegame header to player object @@ -2352,9 +2007,9 @@ int32 Logic::fnPassPlayerSaveData(int32 *params) { // Copy from player object to savegame header - memcpy(&_vm->_saveGameHeader.logic, _vm->_memory->decodePtr(params[0]), sizeof(ObjectLogic)); - memcpy(&_vm->_saveGameHeader.graphic, _vm->_memory->decodePtr(params[1]), sizeof(ObjectGraphic)); - memcpy(&_vm->_saveGameHeader.mega, _vm->_memory->decodePtr(params[2]), sizeof(ObjectMega)); + memcpy(&_vm->_saveGameHeader.logic, decodePtr(params[0]), sizeof(ObjectLogic)); + memcpy(&_vm->_saveGameHeader.graphic, decodePtr(params[1]), sizeof(ObjectGraphic)); + memcpy(&_vm->_saveGameHeader.mega, decodePtr(params[2]), sizeof(ObjectMega)); return IR_CONT; } @@ -2426,7 +2081,7 @@ int32 Logic::fnPauseForEvent(int32 *params) { // params: 0 pointer to object's logic structure // 1 number of game-cycles to pause - ObjectLogic *ob_logic = (ObjectLogic *) _vm->_memory->decodePtr(params[0]); + ObjectLogic *ob_logic = (ObjectLogic *) decodePtr(params[0]); if (checkEventWaiting()) { ob_logic->looping = 0; @@ -2451,42 +2106,12 @@ int32 Logic::fnFaceMega(int32 *params) { // 3 pointer to object's walkdata structure // 4 id of target mega to face - int32 pars[7]; - - pars[0] = params[0]; - pars[1] = params[1]; - pars[2] = params[2]; - pars[3] = params[3]; - - ObjectLogic *ob_logic = (ObjectLogic *) _vm->_memory->decodePtr(params[0]); - - // If this is the start of the walk, decide where to walk to. - - if (!ob_logic->looping) { - StandardHeader *head = (StandardHeader *) _vm->_resman->openResource(params[4]); - - assert(head->fileType == GAME_OBJECT); - - // Call the base script. This is the graphic/mouse service - // call, and will set _engineMega to the ObjectMega of mega we - // want to turn to face. - - char *raw_script_ad = (char *) head; - uint32 null_pc = 3; - - runScript(raw_script_ad, raw_script_ad, &null_pc); - - _vm->_resman->closeResource(params[4]); - - ObjectMega *ob_mega = (ObjectMega *) _vm->_memory->decodePtr(params[2]); - - pars[3] = params[3]; - pars[4] = ob_mega->feet_x; - pars[5] = ob_mega->feet_y; - pars[6] = whatTarget(ob_mega->feet_x, ob_mega->feet_y, _engineMega.feet_x, _engineMega.feet_y); - } - - return fnWalk(pars); + return _router->faceMega( + (ObjectLogic *) decodePtr(params[0]), + (ObjectGraphic *) decodePtr(params[1]), + (ObjectMega *) decodePtr(params[2]), + (ObjectWalkdata *) decodePtr(params[3]), + params[4]); } int32 Logic::fnPlaySequence(int32 *params) { @@ -2501,11 +2126,11 @@ int32 Logic::fnPlaySequence(int32 *params) { // of computer games" - but at the very least we want to show the // cutscene subtitles, so I removed them. - debug(5, "fnPlaySequence(\"%s\");", (const char *) _vm->_memory->decodePtr(params[0])); + debug(5, "fnPlaySequence(\"%s\");", (const char *) decodePtr(params[0])); // add the appropriate file extension & play it - strcpy(filename, (const char *) _vm->_memory->decodePtr(params[0])); + strcpy(filename, (const char *) decodePtr(params[0])); // Write to walkthrough file (zebug0.txt) debug(5, "PLAYING SEQUENCE \"%s\"", filename); diff --git a/sword2/logic.h b/sword2/logic.h index 426c2a2745..e770e162df 100644 --- a/sword2/logic.h +++ b/sword2/logic.h @@ -23,6 +23,8 @@ #ifndef _LOGIC #define _LOGIC +#include "sword2/memory.h" + namespace Sword2 { struct MovieTextObject; @@ -51,6 +53,10 @@ class Logic { private: Sword2Engine *_vm; + inline byte *decodePtr(int32 n) { + return _vm->_memory->decodePtr(n); + } + uint32 _objectKillList[OBJECT_KILL_LIST_SIZE]; // keeps note of no. of objects in the kill list @@ -118,12 +124,6 @@ private: void formText(int32 *params); bool wantSpeechForLine(uint32 wavId); - int16 _standbyX; // see fnSetStandbyCoords() - int16 _standbyY; - int16 _standbyDir; - - int whatTarget(int startX, int startY, int destX, int destY); - // Set by fnPassMega() ObjectMega _engineMega; @@ -133,6 +133,8 @@ public: EventUnit *getEventList() { return _eventList; } + ObjectMega *getEngineMega() { return &_engineMega; } + // Point to the global variable data static uint32 *_scriptVars; diff --git a/sword2/router.h b/sword2/router.h index 20cd14bfa0..a016579fa6 100644 --- a/sword2/router.h +++ b/sword2/router.h @@ -104,6 +104,10 @@ class Router { private: Sword2Engine *_vm; + int16 _standbyX; // see fnSetStandbyCoords() + int16 _standbyY; + int16 _standbyDir; + // stores pointers to mem blocks containing routes created & used by // megas (NULL if slot not in use) WalkData *_routeSlots[TOTAL_ROUTE_SLOTS]; @@ -224,6 +228,24 @@ public: memset(_leadingLeg, 0, sizeof(_leadingLeg)); } + void setStandbyCoords(int16 x, int16 y, uint8 dir); + int whatTarget(int startX, int startY, int destX, int destY); + + // Walking + int doWalk(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata, int16 target_x, int16 target_y, uint8 target_dir); + int walkToAnim(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata, uint32 animRes); + int walkToTalkToMega(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata, uint32 megaId, uint32 separation); + + // Turning + int doFace(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata, uint8 target_dir); + int faceXY(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata, int16 target_x, int16 target_y); + int faceMega(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata, uint32 megaId); + + // Standing + void standAt(ObjectGraphic *ob_graph, ObjectMega *ob_mega, int32 x, int32 y, int32 dir); + void standAfterAnim(ObjectGraphic *ob_graph, ObjectMega *ob_mega, uint32 animRes); + void standAtAnim(ObjectGraphic *ob_graph, ObjectMega *ob_mega, uint32 animRes); + int32 routeFinder(ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata, int32 x, int32 y, int32 dir); void earlySlowOut(ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata); diff --git a/sword2/speech.cpp b/sword2/speech.cpp index 6702bb9325..80927da502 100644 --- a/sword2/speech.cpp +++ b/sword2/speech.cpp @@ -26,7 +26,6 @@ #include "sword2/defs.h" #include "sword2/logic.h" #include "sword2/maketext.h" -#include "sword2/memory.h" #include "sword2/resman.h" namespace Sword2 { @@ -88,7 +87,7 @@ void Logic::locateTalker(int32 *params) { if (cdt_entry->frameType & FRAME_OFFSET) { // The frame has offsets, i.e. it's a scalable mega frame - ObjectMega *ob_mega = (ObjectMega *) _vm->_memory->decodePtr(params[S_OB_MEGA]); + ObjectMega *ob_mega = (ObjectMega *) decodePtr(params[S_OB_MEGA]); // Calculate scale at which to print the sprite, based on feet // y-coord and scaling constants (NB. 'scale' is actually @@ -159,7 +158,7 @@ void Logic::formText(int32 *params) { return; } - ObjectSpeech *ob_speech = (ObjectSpeech *) _vm->_memory->decodePtr(params[S_OB_SPEECH]); + ObjectSpeech *ob_speech = (ObjectSpeech *) decodePtr(params[S_OB_SPEECH]); // Establish the max width allowed for this text sprite. uint32 textWidth = ob_speech->width ? ob_speech->width : 400; diff --git a/sword2/walker.cpp b/sword2/walker.cpp index 3492abab8f..102cc7950f 100644 --- a/sword2/walker.cpp +++ b/sword2/walker.cpp @@ -20,18 +20,26 @@ // WALKER.CPP by James (14nov96) -// Script functions for moving megas about the place & also for keeping tabs -// on them +// Functions for moving megas about the place & also for keeping tabs on them #include "common/stdafx.h" #include "sword2/sword2.h" #include "sword2/defs.h" +#include "sword2/interpreter.h" #include "sword2/logic.h" #include "sword2/resman.h" #include "sword2/router.h" namespace Sword2 { +void Router::setStandbyCoords(int16 x, int16 y, uint8 dir) { + assert(dir <= 7); + + _standbyX = x; + _standbyY = y; + _standbyDir = dir; +} + /** * Work out direction from start to dest. */ @@ -40,7 +48,7 @@ namespace Sword2 { #define diagonalx 36 #define diagonaly 8 -int Logic::whatTarget(int startX, int startY, int destX, int destY) { +int Router::whatTarget(int startX, int startY, int destX, int destY) { int deltaX = destX - startX; int deltaY = destY - startY; @@ -66,4 +74,366 @@ int Logic::whatTarget(int startX, int startY, int destX, int destY) { return (deltaY > 0) ? 5 : 7; } +/** + * Walk meta to (x,y,dir). Set RESULT to 0 if it succeeded. Otherwise, set + * RESULT to 1. Return true if the mega has finished walking. + */ + +int Router::doWalk(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata, int16 target_x, int16 target_y, uint8 target_dir) { + // If this is the start of the walk, calculate the route. + + if (!ob_logic->looping) { + // If we're already there, don't even bother allocating + // memory and calling the router, just quit back & continue + // the script! This avoids an embarassing mega stand frame + // appearing for one cycle when we're already in position for + // an anim eg. repeatedly clicking on same object to repeat + // an anim - no mega frame will appear in between runs of the + // anim. + + if (ob_mega->feet_x == target_x && ob_mega->feet_y == target_y && ob_mega->current_dir == target_dir) { + Logic::_scriptVars[RESULT] = 0; + return IR_CONT; + } + + assert(target_dir <= 8); + + ob_mega->walk_pc = 0; + + // Set up mem for _walkData in route_slots[] & set mega's + // 'route_slot_id' accordingly + allocateRouteMem(); + + int32 route = routeFinder(ob_mega, ob_walkdata, target_x, target_y, target_dir); + + // 0 = can't make route to target + // 1 = created route + // 2 = zero route but may need to turn + + if (route != 1 && route != 2) { + freeRouteMem(); + Logic::_scriptVars[RESULT] = 1; + return IR_CONT; + } + + // Walk is about to start + + ob_mega->currently_walking = 1; + ob_logic->looping = 1; + ob_graph->anim_resource = ob_mega->megaset_res; + } else if (Logic::_scriptVars[EXIT_FADING] && _vm->_screen->getFadeStatus() == RDFADE_BLACK) { + // Double clicked an exit, and the screen has faded down to + // black. Ok, that's it. Back to script and change screen. + + // We have to clear te EXIT_CLICK_ID variable in case there's a + // walk instruction on the new screen, or it'd be cut short. + + freeRouteMem(); + + ob_logic->looping = 0; + ob_mega->currently_walking = 0; + Logic::_scriptVars[EXIT_CLICK_ID] = 0; + Logic::_scriptVars[RESULT] = 0; + + return IR_CONT; + } + + // Get pointer to walkanim & current frame position + + WalkData *walkAnim = getRouteMem(); + int32 walk_pc = ob_mega->walk_pc; + + // If stopping the walk early, overwrite the next step with a + // slow-out, then finish + + if (_vm->_logic->checkEventWaiting() && walkAnim[walk_pc].step == 0 && walkAnim[walk_pc + 1].step == 1) { + // At the beginning of a step + earlySlowOut(ob_mega, ob_walkdata); + } + + // Get new frame of walk + + ob_graph->anim_pc = walkAnim[walk_pc].frame; + ob_mega->current_dir = walkAnim[walk_pc].dir; + ob_mega->feet_x = walkAnim[walk_pc].x; + ob_mega->feet_y = walkAnim[walk_pc].y; + + // Is the NEXT frame is the end-marker (512) of the walk sequence? + + if (walkAnim[walk_pc + 1].frame != 512) { + // No, it wasn't. Increment the walk-anim frame number and + // come back next cycle. + ob_mega->walk_pc++; + return IR_REPEAT; + } + + // We have reached the end-marker, which means we can return to the + // script just as the final (stand) frame of the walk is set. + + freeRouteMem(); + ob_logic->looping = 0; + ob_mega->currently_walking = 0; + + // If George's walk has been interrupted to run a new action script for + // instance or Nico's walk has been interrupted by player clicking on + // her to talk + + // There used to be code here for checking if two megas were colliding, + // but it had been commented out, and it was only run if a function + // that always returned zero returned non-zero. + + if (_vm->_logic->checkEventWaiting()) { + _vm->_logic->startEvent(); + Logic::_scriptVars[RESULT] = 1; + return IR_TERMINATE; + } + + Logic::_scriptVars[RESULT] = 0; + + // CONTINUE the script so that RESULT can be checked! Also, if an anim + // command follows the fnWalk command, the 1st frame of the anim (which + // is always a stand frame itself) can replace the final stand frame of + // the walk, to hide the slight difference between the shrinking on the + // mega frames and the pre-shrunk anim start-frame. + + return IR_CONT; +} + +/** + * Walk mega to start position of anim + */ + +int Router::walkToAnim(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata, uint32 animRes) { + int16 target_x = 0; + int16 target_y = 0; + uint8 target_dir = 0; + + // Walkdata is needed for earlySlowOut if player clicks elsewhere + // during the walk. + + // If this is the start of the walk, read anim file to get start coords + + if (!ob_logic->looping) { + byte *anim_file = _vm->_resman->openResource(animRes); + AnimHeader *anim_head = _vm->fetchAnimHeader(anim_file); + + target_x = anim_head->feetStartX; + target_y = anim_head->feetStartY; + target_dir = anim_head->feetStartDir; + + _vm->_resman->closeResource(animRes); + + // If start coords not yet set in anim header, use the standby + // coords (which should be set beforehand in the script). + + if (target_x == 0 && target_y == 0) { + target_x = _standbyX; + target_y = _standbyY; + target_dir = _standbyDir; + } + + assert(target_dir <= 7); + } + + return doWalk(ob_logic, ob_graph, ob_mega, ob_walkdata, target_x, target_y, target_dir); +} + +/** + * Route to the left or right hand side of target id, if possible. + */ + +int Router::walkToTalkToMega(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata, uint32 megaId, uint32 separation) { + int16 target_x = 0; + int16 target_y = 0; + uint8 target_dir = 0; + + // If this is the start of the walk, calculate the route. + + if (!ob_logic->looping) { + StandardHeader *head = (StandardHeader *) _vm->_resman->openResource(megaId); + + assert(head->fileType == GAME_OBJECT); + + // Call the base script. This is the graphic/mouse service + // call, and will set _engineMega to the ObjectMega of mega we + // want to route to. + + char *raw_script_ad = (char *) head; + uint32 null_pc = 3; + + _vm->_logic->runScript(raw_script_ad, raw_script_ad, &null_pc); + _vm->_resman->closeResource(megaId); + + ObjectMega *targetMega = _vm->_logic->getEngineMega(); + + // Stand exactly beside the mega, ie. at same y-coord + target_y = targetMega->feet_y; + + // Apply scale factor to walk distance. Ay+B gives 256 * scale + // ie. 256 * 256 * true_scale for even better accuracy, ie. + // scale = (Ay + B) / 256 + + int scale = (ob_mega->scale_a * ob_mega->feet_y + ob_mega->scale_b) / 256; + int mega_separation = (separation * scale) / 256; + + debug(4, "Target is at (%d, %d), separation %d", targetMega->feet_x, targetMega->feet_y, mega_separation); + + if (targetMega->feet_x < ob_mega->feet_x) { + // Target is left of us, so aim to stand to their + // right. Face down_left + + target_x = targetMega->feet_x + mega_separation; + target_dir = 5; + } else { + // Ok, must be right of us so aim to stand to their + // left. Face down_right. + + target_x = targetMega->feet_x - mega_separation; + target_dir = 3; + } + } + + return doWalk(ob_logic, ob_graph, ob_mega, ob_walkdata, target_x, target_y, target_dir); +} +/** + * Turn mega to the specified direction. Just needs to call doWalk() with + * current feet coords, so router can produce anim of turn frames. + */ + +int Router::doFace(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata, uint8 target_dir) { + int16 target_x = 0; + int16 target_y = 0; + + // If this is the start of the turn, get the mega's current feet + // coords + the required direction + + if (!ob_logic->looping) { + assert(target_dir <= 7); + + target_x = ob_mega->feet_x; + target_y = ob_mega->feet_y; + } + + return doWalk(ob_logic, ob_graph, ob_mega, ob_walkdata, target_x, target_y, target_dir); +} + +/** + * Turn mega to face point (x,y) on the floor + */ + +int Router::faceXY(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata, int16 target_x, int16 target_y) { + uint8 target_dir = 0; + + // If this is the start of the turn, get the mega's current feet + // coords + the required direction + + if (!ob_logic->looping) { + target_dir = whatTarget(ob_mega->feet_x, ob_mega->feet_y, target_x, target_y); + } + + return doFace(ob_logic, ob_graph, ob_mega, ob_walkdata, target_dir); +} + +/** + * Turn mega to face another mega. + */ + +int Router::faceMega(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata, uint32 megaId) { + uint8 target_dir = 0; + + // If this is the start of the walk, decide where to walk to. + + if (!ob_logic->looping) { + StandardHeader *head = (StandardHeader *) _vm->_resman->openResource(megaId); + + assert(head->fileType == GAME_OBJECT); + + // Call the base script. This is the graphic/mouse service + // call, and will set _engineMega to the ObjectMega of mega we + // want to turn to face. + + char *raw_script_ad = (char *) head; + uint32 null_pc = 3; + + _vm->_logic->runScript(raw_script_ad, raw_script_ad, &null_pc); + _vm->_resman->closeResource(megaId); + + ObjectMega *targetMega = _vm->_logic->getEngineMega(); + + target_dir = whatTarget(ob_mega->feet_x, ob_mega->feet_y, targetMega->feet_x, targetMega->feet_y); + } + + return doFace(ob_logic, ob_graph, ob_mega, ob_walkdata, target_dir); +} + +/** + * Stand mega at (x,y,dir) + * Sets up the graphic object, but also needs to set the new 'current_dir' in + * the mega object, so the router knows in future + */ + +void Router::standAt(ObjectGraphic *ob_graph, ObjectMega *ob_mega, int32 x, int32 y, int32 dir) { + assert(dir >= 0 && dir <= 7); + + // Set up the stand frame & set the mega's new direction + + ob_mega->feet_x = x; + ob_mega->feet_y = y; + ob_mega->current_dir = dir; + + // Mega-set animation file + ob_graph->anim_resource = ob_mega->megaset_res; + + // Dir + first stand frame (always frame 96) + ob_graph->anim_pc = dir + 96; +} + +/** + * stand mega at end position of anim + */ + +void Router::standAfterAnim(ObjectGraphic *ob_graph, ObjectMega *ob_mega, uint32 animRes) { + byte *anim_file = _vm->_resman->openResource(animRes); + AnimHeader *anim_head = _vm->fetchAnimHeader(anim_file); + + int32 x = anim_head->feetEndX; + int32 y = anim_head->feetEndY; + int32 dir = anim_head->feetEndDir; + + _vm->_resman->closeResource(animRes); + + // If start coords not available either use the standby coords (which + // should be set beforehand in the script) + + if (x == 0 && y == 0) { + x = _standbyX; + y = _standbyY; + dir = _standbyDir; + } + + standAt(ob_graph, ob_mega, x, y, dir); +} + +void Router::standAtAnim(ObjectGraphic *ob_graph, ObjectMega *ob_mega, uint32 animRes) { + byte *anim_file = _vm->_resman->openResource(animRes); + AnimHeader *anim_head = _vm->fetchAnimHeader(anim_file); + + int32 x = anim_head->feetStartX; + int32 y = anim_head->feetStartY; + int32 dir = anim_head->feetStartDir; + + _vm->_resman->closeResource(animRes); + + // If start coords not available use the standby coords (which should + // be set beforehand in the script) + + if (x == 0 && y == 0) { + x = _standbyX; + y = _standbyY; + dir = _standbyDir; + } + + standAt(ob_graph, ob_mega, x, y, dir); +} + } // End of namespace Sword2 -- cgit v1.2.3