scummvm/sword2/walker.cpp

709 lines
18 KiB
C++
Raw Normal View History

/* Copyright (C) 1994-2004 Revolution Software Ltd
2003-07-28 01:44:38 +00:00
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*/
// WALKER.CPP by James (14nov96)
2004-04-16 06:46:03 +00:00
// Script functions for moving megas about the place & also for keeping tabs
2003-09-20 12:43:52 +00:00
// on them
2003-07-28 01:44:38 +00:00
#include "common/stdafx.h"
2003-10-28 19:51:30 +00:00
#include "sword2/sword2.h"
#include "sword2/defs.h"
#include "sword2/interpreter.h"
#include "sword2/logic.h"
#include "sword2/resman.h"
#include "sword2/driver/d_draw.h"
2003-07-28 01:44:38 +00:00
2003-10-04 00:52:27 +00:00
namespace Sword2 {
2003-10-10 16:14:52 +00:00
/**
2004-04-16 06:46:03 +00:00
* Walk mega to (x,y,dir). Set RESULT to 0 if it succeeded. Otherwise, set
* RESULT to 1.
2003-10-10 16:14:52 +00:00
*/
2003-07-28 01:44:38 +00:00
int32 Logic::fnWalk(int32 *params) {
2003-07-28 01:44:38 +00:00
// params: 0 pointer to object's logic structure
2003-09-20 12:43:52 +00:00
// 1 pointer to object's graphic structure
// 2 pointer to object's mega structure
// 3 pointer to object's walkdata structure
// 4 target x-coord
// 5 target y-coord
2004-04-16 06:46:03 +00:00
// 6 target direction (8 means end walk on ANY direction)
2003-09-20 12:43:52 +00:00
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]);
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
int16 target_x = (int16) params[4];
int16 target_y = (int16) params[5];
uint8 target_dir = (uint8) params[6];
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
ObjectWalkdata *ob_walkdata;
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
// If this is the start of the walk, calculate the route.
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
if (!ob_logic->looping) {
2003-09-20 12:43:52 +00:00
// 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.
2003-07-28 01:44:38 +00:00
2003-09-20 12:43:52 +00:00
if (ob_mega->feet_x == target_x && ob_mega->feet_y == target_y && ob_mega->current_dir == target_dir) {
_scriptVars[RESULT] = 0;
2004-04-16 06:46:03 +00:00
return IR_CONT;
2003-07-28 01:44:38 +00:00
}
2004-04-16 06:46:03 +00:00
assert(params[6] >= 0 && params[6] <= 8);
2003-09-20 12:43:52 +00:00
ob_walkdata = (ObjectWalkdata *) _vm->_memory->decodePtr(params[3]);
2003-09-20 12:43:52 +00:00
2004-04-16 06:46:03 +00:00
ob_mega->walk_pc = 0;
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
// Set up mem for _walkData in route_slots[] & set mega's
2003-09-20 12:43:52 +00:00
// 'route_slot_id' accordingly
2003-07-28 01:44:38 +00:00
_router->allocateRouteMem();
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
int32 route = _router->routeFinder(ob_mega, ob_walkdata, target_x, target_y, target_dir);
2003-07-28 01:44:38 +00:00
2003-09-20 12:43:52 +00:00
// 0 = can't make route to target
// 1 = created route
// 2 = zero route but may need to turn
2003-07-28 01:44:38 +00:00
2003-09-20 12:43:52 +00:00
if (route == 1 || route == 2) {
// so script fnWalk loop continues until end of
2003-09-20 12:43:52 +00:00
// walk-anim
2003-07-28 01:44:38 +00:00
2003-09-20 12:43:52 +00:00
ob_logic->looping = 1;
// need to animate the route now, so don't set result
// or return yet!
// started walk
2003-09-20 12:43:52 +00:00
ob_mega->currently_walking = 1;
// (see fnGetPlayerSaveData() in save_rest.cpp
2003-09-20 12:43:52 +00:00
} else {
_router->freeRouteMem();
_scriptVars[RESULT] = 1;
2003-09-20 12:43:52 +00:00
return IR_CONT;
2003-07-28 01:44:38 +00:00
}
2004-04-16 06:46:03 +00:00
// Walk is about to start, so set the mega's graphic resource
2003-07-28 01:44:38 +00:00
ob_graph->anim_resource = ob_mega->megaset_res;
} else if (_scriptVars[EXIT_FADING] && _vm->_graphics->getFadeStatus() == RDFADE_BLACK) {
2004-04-16 06:46:03 +00:00
// Double clicked an exit so quit the walk when screen is black
2003-09-20 12:43:52 +00:00
// ok, thats it - back to script and change screen
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
ob_logic->looping = 0;
_router->freeRouteMem();
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
// Must clear in-case on the new screen there's a walk
2003-09-20 12:43:52 +00:00
// instruction (which would get cut short)
_scriptVars[EXIT_CLICK_ID] = 0;
2003-07-28 01:44:38 +00:00
// finished walk
2003-09-20 12:43:52 +00:00
ob_mega->currently_walking = 0;
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
// see fnGetPlayerSaveData() in save_rest.cpp
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
_scriptVars[RESULT] = 0;
2003-09-20 12:43:52 +00:00
// continue the script so that RESULT can be checked!
return IR_CONT;
2003-07-28 01:44:38 +00:00
}
2003-09-20 12:43:52 +00:00
2003-07-28 01:44:38 +00:00
// get pointer to walkanim & current frame position
WalkData *walkAnim = _router->getRouteMem();
2004-04-16 06:46:03 +00:00
int32 walk_pc = ob_mega->walk_pc;
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
// If stopping the walk early, overwrite the next step with a
2003-09-20 12:43:52 +00:00
// slow-out, then finish
2003-07-28 01:44:38 +00:00
if (checkEventWaiting()) {
2003-09-20 12:43:52 +00:00
if (walkAnim[walk_pc].step == 0 && walkAnim[walk_pc + 1].step == 1) {
2004-04-16 06:46:03 +00:00
// At the beginning of a step
ob_walkdata = (ObjectWalkdata *) _vm->_memory->decodePtr(params[3]);
_router->earlySlowOut(ob_mega, ob_walkdata);
2003-07-28 01:44:38 +00:00
}
}
2004-04-16 06:46:03 +00:00
// Get new frame of walk
2003-07-28 01:44:38 +00:00
2003-09-20 12:43:52 +00:00
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;
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
// Check if NEXT frame is in fact the end-marker of the walk sequence
2003-09-20 12:43:52 +00:00
// 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)
2003-07-28 01:44:38 +00:00
2003-09-20 12:43:52 +00:00
// '512' is end-marker
if (walkAnim[walk_pc + 1].frame == 512) {
2004-04-16 06:46:03 +00:00
ob_logic->looping = 0;
_router->freeRouteMem();
2003-09-20 12:43:52 +00:00
// finished walk
2003-09-20 12:43:52 +00:00
ob_mega->currently_walking = 0;
// (see fnGetPlayerSaveData() in save_rest.cpp
2003-09-20 12:43:52 +00:00
// 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
2003-07-28 01:44:38 +00:00
2003-09-20 12:43:52 +00:00
// 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;
2003-09-20 12:43:52 +00:00
return IR_TERMINATE;
} else {
_scriptVars[RESULT] = 0;
2003-09-20 12:43:52 +00:00
// 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.
2003-09-20 12:43:52 +00:00
return IR_CONT;
2003-07-28 01:44:38 +00:00
}
}
2003-09-20 12:43:52 +00:00
// Increment the walkanim frame number and come back next cycle
2003-07-28 01:44:38 +00:00
ob_mega->walk_pc++;
2003-09-20 12:43:52 +00:00
return IR_REPEAT;
2003-07-28 01:44:38 +00:00
}
2003-09-20 12:43:52 +00:00
2003-10-10 16:14:52 +00:00
/**
* Walk mega to start position of anim
*/
2003-07-28 01:44:38 +00:00
int32 Logic::fnWalkToAnim(int32 *params) {
2003-07-28 01:44:38 +00:00
// params: 0 pointer to object's logic structure
2003-09-20 12:43:52 +00:00
// 1 pointer to object's graphic structure
// 2 pointer to object's mega structure
// 3 pointer to object's walkdata structure
// 4 anim resource id
2003-07-28 01:44:38 +00:00
2003-09-20 12:43:52 +00:00
int32 pars[7];
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
// 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];
2003-07-28 01:44:38 +00:00
ObjectLogic *ob_logic = (ObjectLogic *) _vm->_memory->decodePtr(params[0]);
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
// If this is the start of the walk, read anim file to get start coords
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
if (!ob_logic->looping) {
byte *anim_file = _vm->_resman->openResource(params[4]);
2004-04-16 06:46:03 +00:00
AnimHeader *anim_head = _vm->fetchAnimHeader( anim_file );
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
pars[4] = anim_head->feetStartX;
pars[5] = anim_head->feetStartY;
pars[6] = anim_head->feetStartDir;
2003-07-28 01:44:38 +00:00
_vm->_resman->closeResource(params[4]);
2003-09-20 12:43:52 +00:00
2004-04-16 06:46:03 +00:00
// If start coords not yet set in anim header, use the standby
// coords (which should be set beforehand in the script).
2003-09-20 12:43:52 +00:00
if (pars[4] == 0 && pars[5] == 0) {
byte buf[NAME_LEN];
pars[4] = _standbyX;
pars[5] = _standbyY;
pars[6] = _standbyDir;
2003-07-28 01:44:38 +00:00
debug(3, "WARNING: fnWalkToAnim(%s) used standby coords", _vm->fetchObjectName(params[4], buf));
2003-07-28 01:44:38 +00:00
}
2004-04-16 06:46:03 +00:00
assert(pars[6] >= 0 && pars[6] <= 7);
2003-07-28 01:44:38 +00:00
}
2003-09-20 12:43:52 +00:00
return fnWalk(pars);
2003-07-28 01:44:38 +00:00
}
2003-10-10 16:14:52 +00:00
/**
2004-04-16 06:46:03 +00:00
* Turn mega to <direction>. Just needs to call fnWalk() with current feet
* coords, so router can produce anim of turn frames.
2003-10-10 16:14:52 +00:00
*/
2003-07-28 01:44:38 +00:00
int32 Logic::fnTurn(int32 *params) {
2003-07-28 01:44:38 +00:00
// params: 0 pointer to object's logic structure
2003-09-20 12:43:52 +00:00
// 1 pointer to object's graphic structure
// 2 pointer to object's mega structure
// 3 pointer to object's walkdata structure
// 4 target direction
2003-07-28 01:44:38 +00:00
2003-09-20 12:43:52 +00:00
int32 pars[7];
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
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]);
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
// If this is the start of the turn, get the mega's current feet
// coords + the required direction
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
if (!ob_logic->looping) {
assert(params[4] >= 0 && params[4] <= 7);
2003-07-28 01:44:38 +00:00
ObjectMega *ob_mega = (ObjectMega *) _vm->_memory->decodePtr(params[2]);
2003-11-08 19:47:20 +00:00
2003-07-28 01:44:38 +00:00
pars[4] = ob_mega->feet_x;
pars[5] = ob_mega->feet_y;
2004-04-16 06:46:03 +00:00
pars[6] = params[4];
2003-07-28 01:44:38 +00:00
}
return fnWalk(pars);
2003-07-28 01:44:38 +00:00
}
2003-09-20 12:43:52 +00:00
2003-10-10 16:14:52 +00:00
/**
2004-04-16 06:46:03 +00:00
* Stand mega at (x,y,dir)
* Sets up the graphic object, but also needs to set the new 'current_dir' in
2003-10-10 16:14:52 +00:00
* the mega object, so the router knows in future
*/
2003-07-28 01:44:38 +00:00
int32 Logic::fnStandAt(int32 *params) {
2003-07-28 01:44:38 +00:00
// params: 0 pointer to object's graphic structure
2003-09-20 12:43:52 +00:00
// 1 pointer to object's mega structure
// 2 target x-coord
// 3 target y-coord
// 4 target direction
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
assert(params[4] >= 0 && params[4] <= 7);
2003-07-28 01:44:38 +00:00
ObjectGraphic *ob_graph = (ObjectGraphic *) _vm->_memory->decodePtr(params[0]);
ObjectMega *ob_mega = (ObjectMega *) _vm->_memory->decodePtr(params[1]);
2003-07-28 01:44:38 +00:00
// set up the stand frame & set the mega's new direction
2003-09-20 12:43:52 +00:00
ob_mega->feet_x = params[2];
ob_mega->feet_y = params[3];
2004-04-16 06:46:03 +00:00
ob_mega->current_dir = params[4];
// mega-set animation file
ob_graph->anim_resource = ob_mega->megaset_res;
2003-09-20 12:43:52 +00:00
// dir + first stand frame (always frame 96)
ob_graph->anim_pc = params[4] + 96;
2003-07-28 01:44:38 +00:00
2003-09-20 12:43:52 +00:00
return IR_CONT;
2003-07-28 01:44:38 +00:00
}
2004-04-16 06:46:03 +00:00
/**
* Stand mega in <direction> at current feet coords
* Just needs to call fnStandAt() with current feet coords
*/
2003-07-28 01:44:38 +00:00
int32 Logic::fnStand(int32 *params) {
2003-07-28 01:44:38 +00:00
// params: 0 pointer to object's graphic structure
2003-09-20 12:43:52 +00:00
// 1 pointer to object's mega structure
// 2 target direction
2003-07-28 01:44:38 +00:00
ObjectMega *ob_mega = (ObjectMega *) _vm->_memory->decodePtr(params[1]);
2004-04-16 06:46:03 +00:00
2003-07-28 01:44:38 +00:00
int32 pars[5];
pars[0] = params[0];
pars[1] = params[1];
pars[2] = ob_mega->feet_x;
pars[3] = ob_mega->feet_y;
2004-04-16 06:46:03 +00:00
pars[4] = params[2];
2003-07-28 01:44:38 +00:00
return fnStandAt(pars);
2003-07-28 01:44:38 +00:00
}
2003-09-20 12:43:52 +00:00
2003-10-10 16:14:52 +00:00
/**
* stand mega at end position of anim
*/
2003-07-28 01:44:38 +00:00
int32 Logic::fnStandAfterAnim(int32 *params) {
2003-07-28 01:44:38 +00:00
// params: 0 pointer to object's graphic structure
2003-09-20 12:43:52 +00:00
// 1 pointer to object's mega structure
// 2 anim resource id
2003-07-28 01:44:38 +00:00
byte *anim_file = _vm->_resman->openResource(params[2]);
2004-04-16 06:46:03 +00:00
AnimHeader *anim_head = _vm->fetchAnimHeader(anim_file);
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
int32 pars[5];
2003-07-28 01:44:38 +00:00
pars[0] = params[0];
pars[1] = params[1];
2003-09-20 12:43:52 +00:00
pars[2] = anim_head->feetEndX;
pars[3] = anim_head->feetEndY;
pars[4] = anim_head->feetEndDir;
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
// If start coords not available either use the standby coords (which
2003-09-20 12:43:52 +00:00
// should be set beforehand in the script)
2003-07-28 01:44:38 +00:00
2003-09-20 12:43:52 +00:00
if (pars[2] == 0 && pars[3] == 0) {
byte buf[NAME_LEN];
pars[2] = _standbyX;
pars[3] = _standbyY;
pars[4] = _standbyDir;
2003-07-28 01:44:38 +00:00
debug(3, "WARNING: fnStandAfterAnim(%s) used standby coords", _vm->fetchObjectName(params[2], buf));
2003-07-28 01:44:38 +00:00
}
2004-04-16 06:46:03 +00:00
assert(pars[4] >= 0 && pars[4] <= 7);
2003-07-28 01:44:38 +00:00
_vm->_resman->closeResource(params[2]);
return fnStandAt(pars);
2003-07-28 01:44:38 +00:00
}
2004-04-16 06:46:03 +00:00
/**
* Stand mega at start position of anim
*/
2003-07-28 01:44:38 +00:00
int32 Logic::fnStandAtAnim(int32 *params) {
2003-07-28 01:44:38 +00:00
// params: 0 pointer to object's graphic structure
2003-09-20 12:43:52 +00:00
// 1 pointer to object's mega structure
// 2 anim resource id
2003-07-28 01:44:38 +00:00
byte *anim_file = _vm->_resman->openResource(params[2]);
2004-04-16 06:46:03 +00:00
AnimHeader *anim_head = _vm->fetchAnimHeader(anim_file);
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
int32 pars[5];
2003-07-28 01:44:38 +00:00
pars[0] = params[0];
pars[1] = params[1];
2003-09-20 12:43:52 +00:00
pars[2] = anim_head->feetStartX;
pars[3] = anim_head->feetStartY;
pars[4] = anim_head->feetStartDir;
2004-04-16 06:46:03 +00:00
// If start coords not available use the standby coords (which should
2003-09-20 12:43:52 +00:00
// be set beforehand in the script)
2003-07-28 01:44:38 +00:00
if (pars[2] == 0 && pars[3] == 0) {
byte buf[NAME_LEN];
pars[2] = _standbyX;
pars[3] = _standbyY;
pars[4] = _standbyDir;
2003-07-28 01:44:38 +00:00
debug(3, "WARNING: fnStandAtAnim(%s) used standby coords", _vm->fetchObjectName(params[2], buf));
2003-07-28 01:44:38 +00:00
}
2004-04-16 06:46:03 +00:00
assert(pars[4] >= 0 && pars[4] <= 7);
2003-07-28 01:44:38 +00:00
_vm->_resman->closeResource(params[2]);
return fnStandAt(pars);
2003-07-28 01:44:38 +00:00
}
2004-04-16 06:46:03 +00:00
/**
* Work out direction from start to dest.
*/
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
// Used in whatTarget(); not valid for all megas
2003-09-20 12:43:52 +00:00
#define diagonalx 36
2003-07-28 01:44:38 +00:00
#define diagonaly 8
int Logic::whatTarget(int startX, int startY, int destX, int destY) {
2003-09-20 12:43:52 +00:00
int deltaX = destX - startX;
int deltaY = destY - startY;
2003-07-28 01:44:38 +00:00
2003-09-20 12:43:52 +00:00
// 7 0 1
// 6 2
// 5 4 3
2003-07-28 01:44:38 +00:00
2003-09-20 12:43:52 +00:00
// Flat route
2003-07-28 01:44:38 +00:00
if (ABS(deltaY) * diagonalx < ABS(deltaX) * diagonaly / 2)
2003-09-20 12:43:52 +00:00
return (deltaX > 0) ? 2 : 6;
// Vertical route
if (ABS(deltaY) * diagonalx / 2 > ABS(deltaX) * diagonaly)
2003-09-20 12:43:52 +00:00
return (deltaY > 0) ? 4 : 0;
// Diagonal route
if (deltaX > 0)
return (deltaY > 0) ? 3 : 1;
return (deltaY > 0) ? 5 : 7;
2003-07-28 01:44:38 +00:00
}
2003-10-10 16:14:52 +00:00
/**
2004-04-16 06:46:03 +00:00
* Turn mega to face point (x,y) on the floor
* Just needs to call fnWalk() with current feet coords & direction computed
* by whatTarget()
2003-10-10 16:14:52 +00:00
*/
2003-07-28 01:44:38 +00:00
int32 Logic::fnFaceXY(int32 *params) {
2003-07-28 01:44:38 +00:00
// params: 0 pointer to object's logic structure
2003-09-20 12:43:52 +00:00
// 1 pointer to object's graphic structure
// 2 pointer to object's mega structure
// 3 pointer to object's walkdata structure
// 4 target x-coord
// 5 target y-coord
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
int32 pars[7];
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
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]);
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
// If this is the start of the turn, get the mega's current feet
// coords + the required direction
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
if (!ob_logic->looping) {
ObjectMega *ob_mega = (ObjectMega *) _vm->_memory->decodePtr(params[2]);
2003-07-28 01:44:38 +00:00
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]);
2003-07-28 01:44:38 +00:00
}
return fnWalk(pars);
2003-07-28 01:44:38 +00:00
}
int32 Logic::fnFaceMega(int32 *params) {
2003-09-20 12:43:52 +00:00
// params: 0 pointer to object's logic structure
// 1 pointer to object's graphic structure
// 2 pointer to object's mega structure
// 3 pointer to object's walkdata structure
// 4 id of target mega to face
int32 pars[7];
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
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]);
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
// If this is the start of the walk, decide where to walk to.
2003-09-20 12:43:52 +00:00
2004-04-16 06:46:03 +00:00
if (!ob_logic->looping) {
StandardHeader *head = (StandardHeader *) _vm->_resman->openResource(params[4]);
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
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;
2003-09-20 12:43:52 +00:00
runScript(raw_script_ad, raw_script_ad, &null_pc);
2003-07-28 01:44:38 +00:00
_vm->_resman->closeResource(params[4]);
2003-07-28 01:44:38 +00:00
ObjectMega *ob_mega = (ObjectMega *) _vm->_memory->decodePtr(params[2]);
2003-07-28 01:44:38 +00:00
pars[3] = params[3];
pars[4] = ob_mega->feet_x;
pars[5] = ob_mega->feet_y;
2004-04-16 06:46:03 +00:00
pars[6] = whatTarget(ob_mega->feet_x, ob_mega->feet_y, _engineMega.feet_x, _engineMega.feet_y);
2003-07-28 01:44:38 +00:00
}
return fnWalk(pars);
2003-07-28 01:44:38 +00:00
}
2004-04-16 06:46:03 +00:00
/**
* Route to the left or right hand side of target id, if possible.
*/
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
int32 Logic::fnWalkToTalkToMega(int32 *params) {
2003-09-20 12:43:52 +00:00
// params: 0 pointer to object's logic structure
// 1 pointer to object's graphic structure
// 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];
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
pars[0] = params[0];
2003-07-28 01:44:38 +00:00
pars[1] = params[1];
pars[2] = params[2];
2004-04-16 06:46:03 +00:00
pars[3] = params[3];
ObjectLogic *ob_logic = (ObjectLogic *) _vm->_memory->decodePtr(params[0]);
2004-04-16 06:46:03 +00:00
// If this is the start of the walk, calculate the route.
2003-07-28 01:44:38 +00:00
2003-09-20 12:43:52 +00:00
if (!ob_logic->looping) {
2004-04-16 06:46:03 +00:00
StandardHeader *head = (StandardHeader *) _vm->_resman->openResource(params[4]);
2003-09-20 12:43:52 +00:00
2004-04-16 06:46:03 +00:00
assert(head->fileType == GAME_OBJECT);
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
// 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;
2003-07-28 01:44:38 +00:00
runScript(raw_script_ad, raw_script_ad, &null_pc);
2003-07-28 01:44:38 +00:00
_vm->_resman->closeResource(params[4]);
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
// Stand exactly beside the mega, ie. at same y-coord
pars[5] = _engineMega.feet_y;
2003-07-28 01:44:38 +00:00
ObjectMega *ob_mega = (ObjectMega *) _vm->_memory->decodePtr(params[2]);
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
// 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
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
int scale = (ob_mega->scale_a * ob_mega->feet_y + ob_mega->scale_b) / 256;
int mega_separation = (params[5] * scale) / 256;
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
debug(4, "Target is at (%d, %d), separation %d", _engineMega.feet_x, _engineMega.feet_y, mega_separation);
2003-09-20 12:43:52 +00:00
2004-04-16 06:46:03 +00:00
if (_engineMega.feet_x < ob_mega->feet_x) {
2003-09-20 12:43:52 +00:00
// Target is left of us, so aim to stand to their
// right. Face down_left
2004-04-16 06:46:03 +00:00
pars[4] = _engineMega.feet_x + mega_separation;
2003-09-20 12:43:52 +00:00
pars[6] = 5;
} else {
// Ok, must be right of us so aim to stand to their
// left. Face down_right.
2004-04-16 06:46:03 +00:00
pars[4] = _engineMega.feet_x - mega_separation;
2003-09-20 12:43:52 +00:00
pars[6] = 3;
2003-07-28 01:44:38 +00:00
}
}
return fnWalk(pars);
2003-07-28 01:44:38 +00:00
}
2003-09-20 12:43:52 +00:00
int32 Logic::fnSetWalkGrid(int32 *params) {
// params: none
2004-04-16 06:46:03 +00:00
error("fnSetWalkGrid() is no longer a valid opcode");
2003-09-20 12:43:52 +00:00
return IR_CONT;
2003-07-28 01:44:38 +00:00
}
2004-04-16 06:46:03 +00:00
/**
* Add this walkgrid resource to the list of those used for routing in this
* location. Note that this is ignored if the resource is already in the list.
*/
2003-09-20 12:43:52 +00:00
int32 Logic::fnAddWalkGrid(int32 *params) {
2003-09-20 12:43:52 +00:00
// params: 0 id of walkgrid resource
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
// All objects that add walkgrids must be restarted whenever we
// re-enter a location.
2003-07-28 01:44:38 +00:00
2003-09-20 12:43:52 +00:00
// DON'T EVER KILL GEORGE!
if (_scriptVars[ID] != 8) {
2004-04-16 06:46:03 +00:00
// Need to call this in case it wasn't called in script!
fnAddToKillList(NULL);
2003-09-20 12:43:52 +00:00
}
2003-07-28 01:44:38 +00:00
_router->addWalkGrid(params[0]);
2004-04-16 06:46:03 +00:00
fnPreLoad(params);
2003-09-20 12:43:52 +00:00
return IR_CONT;
2003-07-28 01:44:38 +00:00
}
2004-04-16 06:46:03 +00:00
/**
* Remove this walkgrid resource from the list of those used for routing in
* this location. Note that this is ignored if the resource isn't actually
* in the list.
*/
2003-07-28 01:44:38 +00:00
int32 Logic::fnRemoveWalkGrid(int32 *params) {
2003-09-20 12:43:52 +00:00
// params: 0 id of walkgrid resource
2003-07-28 01:44:38 +00:00
_router->removeWalkGrid(params[0]);
2003-09-20 12:43:52 +00:00
return IR_CONT;
2003-07-28 01:44:38 +00:00
}
2003-09-20 12:43:52 +00:00
int32 Logic::fnRegisterWalkGrid(int32 *params) {
// params: none
2004-04-16 06:46:03 +00:00
error("fnRegisterWalkGrid() is no longer a valid opcode");
2003-09-20 12:43:52 +00:00
return IR_CONT;
2003-07-28 01:44:38 +00:00
}
int32 Logic::fnSetScaling(int32 *params) {
2003-09-20 12:43:52 +00:00
// params: 0 pointer to object's mega structure
// 1 scale constant A
// 2 scale constant B
2003-07-28 01:44:38 +00:00
2003-09-20 12:43:52 +00:00
// 256 * s = A * y + B
2004-04-16 06:46:03 +00:00
// Where s is system scale, which itself is (256 * actual_scale) ie.
2003-09-20 12:43:52 +00:00
// s == 128 is half size
2003-07-28 01:44:38 +00:00
ObjectMega *ob_mega = (ObjectMega *) _vm->_memory->decodePtr(params[0]);
2003-07-28 01:44:38 +00:00
ob_mega->scale_a = params[1];
ob_mega->scale_b = params[2];
2003-09-20 12:43:52 +00:00
return IR_CONT;
2003-07-28 01:44:38 +00:00
}
2004-04-16 06:46:03 +00:00
/**
* Set the standby walk coords to be used by fnWalkToAnim() and
* fnStandAfterAnim() when the anim header's start/end coords are zero.
* Useful during development; can stay in final game anyway.
*/
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
int32 Logic::fnSetStandbyCoords(int32 *params) {
2003-09-20 12:43:52 +00:00
// params: 0 x-coord
// 1 y-coord
// 2 direction (0..7)
2003-07-28 01:44:38 +00:00
2004-04-16 06:46:03 +00:00
assert(params[2] >= 0 && params[2] <= 7);
2003-07-28 01:44:38 +00:00
_standbyX = (int16) params[0];
_standbyY = (int16) params[1];
_standbyDir = (uint8) params[2];
2003-07-28 01:44:38 +00:00
2003-09-20 12:43:52 +00:00
return IR_CONT;
2003-07-28 01:44:38 +00:00
}
2003-10-04 00:52:27 +00:00
} // End of namespace Sword2