fixed some actor movement issues - fixed several scene changing issues - fixed memory bugs in LocalizeString and isVoicePlaying - fixed start_script called with LUA_T_NIL

This commit is contained in:
Erich Edgar Hoover 2005-08-01 03:49:02 +00:00
parent c1eda63527
commit f16975f426
11 changed files with 223 additions and 74 deletions

7
README
View File

@ -62,7 +62,7 @@ but many features are either missing or unstable. There is no abilitity
to save/load, lighting, etc. Crashes are likely.
Game currently playable to:
The Demon Beaver Dam (Petrified Forest)
Meche leaves Manny again (Rubacava, Year 2)
Caveats (in order of appearance):
1) Sound track destruction doesn't do quite a good enough job when
entering the spider web area (sp.set) in the Petrified Forest
@ -70,9 +70,8 @@ Caveats (in order of appearance):
the correct speed, this causes buffer overflows in the audio.
While hardcoding the speed to the correct value used by the other
movies works, it is not a good fix and so it is not implemented
3) When you return from getting the shocks at the tree pump in the
Petrified Forest the scene doesn't change correctly and the game
stops allowing input
3) Sometimes the Demon Beavers get stuck on obstacles - open the
menu for a moment and they will correct themselves
What are the default keys?
--------------------------

1
TODO
View File

@ -9,7 +9,6 @@ Assigned tasks:
(Ender: May just need the blending of the lighting values (p2->r, ->g, ->b)
to the result of pp[_a] in the non-24bpp PUT_PIXEL macro of
ztriangle.cpp/ZB_FillTriangleMappingPerspective. Maybe. :)
* Figure out problem changing scenes after getting shocks (compholio)
* Improve actor colormap supprt (compholio)
* Improve SMUSH looping support (compholio)
* Improve menu support (compholio)

View File

@ -33,8 +33,11 @@
Actor::Actor(const char *name) :
_name(name), _talkColor(255, 255, 255), _pos(0, 0, 0),
_pitch(0), _yaw(0), _roll(0), _walkRate(0), _turnRate(0),
_reflectionAngle(80), _setName(""), _setNameTmp(""),
// Some actors don't set walk and turn rates, so we default the
// _turnRate so Doug at the cat races can turn and we set the
// _walkRate so Glottis at the demon beaver entrance can walk
_pitch(0), _yaw(0), _roll(0), _walkRate(1.0f), _turnRate(100.0f),
_reflectionAngle(80), _setName(""),
_visible(true), _lipSynch(NULL), _turning(false), _walking(false),
_restCostume(NULL), _restChore(-1),
_walkCostume(NULL), _walkChore(-1), _walkedLast(false), _walkedCur(false),
@ -369,9 +372,14 @@ bool Actor::talking() {
}
void Actor::shutUp() {
// Don't stop the sound, the call to stop the sound
// is made by the game
_talkSoundName = "";
// While the call to stop the sound is usually made by the game,
// we also need to handle when the user terminates the dialog.
// Some warning messages will occur when the user terminates the
// actor dialog but the game will continue alright.
if (_talkSoundName != "") {
g_imuse->stopSound(_talkSoundName.c_str());
_talkSoundName = "";
}
if (_lipSynch != NULL) {
if ((_talkAnim != -1) && (_talkChore[_talkAnim] >= 0))
_talkCostume[_talkAnim]->stopChore(_talkChore[_talkAnim]);
@ -467,7 +475,11 @@ void Actor::update() {
dyaw -= 360;
while (dyaw < -180)
dyaw += 360;
if (turnAmt >= std::abs(dyaw)) {
// If the actor won't turn because the rate is set to zero then
// have the actor turn all the way to the destination yaw.
// Without this some actors will lock the interface on changing
// scenes, this affects the Bone Wagon in particular.
if (turnAmt == 0 || turnAmt >= std::abs(dyaw)) {
setYaw(_destYaw);
_turning = false;
}
@ -490,7 +502,9 @@ void Actor::update() {
if (walkAmt >= dist) {
_pos = _destPos;
_walking = false;
_turning = false;
// It seems that we need to allow an already active turning motion to
// continue or else turning actors away from barriers won't work right
// _turning = false;
} else
_pos += dir * walkAmt;

22
actor.h
View File

@ -41,8 +41,17 @@ public:
void setTalkColor(const Color& c) { _talkColor = c; }
Color talkColor() const { return _talkColor; }
void setPos(Vector3d pos) { _pos = pos; }
Vector3d pos() const { return _pos; }
// When the actor is walking report where the actor is going to and
// not the actual current position, this fixes some scene change
// change issues with the Bone Wagon (along with other fixes)
Vector3d pos() const {
if (_walking)
return _destPos;
else
return _pos;
}
void walkTo(Vector3d p);
void stopWalking() { _walking = false; }
bool isWalking() const;
void setRot(float pitch, float yaw, float roll);
void turnTo(float pitch, float yaw, float roll);
@ -52,13 +61,9 @@ public:
float roll() const { return _roll; }
void setVisibility(bool val) { _visible = val; }
bool visible() const { return _visible; }
// Don't actually change the set immediately, see engine.cpp for details
void putInSet(const char *name) { _setNameTmp = name; }
void putInSet() {
if (_setName != _setNameTmp) {
_setName = _setNameTmp;
}
}
// The set should change immediately, otherwise a very rapid set change
// for an actor will be recognized incorrectly and the actor will be lost.
void putInSet(const char *name) { _setName = name; }
void setTurnRate(float rate) { _turnRate = rate; }
float turnRate() const { return _turnRate; }
void setWalkRate(float rate) { _walkRate = rate; }
@ -133,7 +138,6 @@ public:
private:
std::string _name;
std::string _setName; // The actual current set
std::string _setNameTmp; // The temporary name for the set
Color _talkColor;
Vector3d _pos;
float _pitch, _yaw, _roll;

View File

@ -249,11 +249,6 @@ void Engine::mainLoop() {
for (ActorListType::iterator i = _actors.begin(); i != _actors.end(); i++) {
Actor *a = *i;
// Activate the new set
// While this doesn't seem to affect anything this should be done here
// instead of inside the lua_runtasks loop, otherwise certain functions
// may request a set that was just deactivated
a->putInSet();
// Update the actor's costumes & chores
g_currentUpdatedActor = *i;
// Note that the actor need not be visible to update chores, for example:

View File

@ -102,14 +102,10 @@ public:
unsigned frameStart() const { return _frameStart; }
unsigned frameTime() const { return _frameTime; }
float perSecond(float rate) const {
// The actor "Doug" at the Kitty races has no _turnRate set by default
// so we need to return some sort of time that's non-zero for a rate
// value of zero
if (rate == 0.0)
rate = 100.0;
return rate * _frameTime / 1000;
}
// perSecond should allow rates of zero, some actors will accelerate
// up to their normal speed (such as the bone wagon) so handling
// a walking rate of zero should happen in the default actor creation
float perSecond(float rate) const { return rate * _frameTime / 1000; }
int getTextSpeed() { return _textSpeed; }
void setTextSpeed(int speed);

View File

@ -100,7 +100,10 @@ bool Imuse::isVoicePlaying() {
StackLock lock(_mutex);
for (int l = 0; l < MAX_IMUSE_TRACKS; l++) {
Track *track = _track[l];
if (track->volGroupId == IMUSE_VOLGRP_VOICE) {
// Make sure the track is in use before checking the group ID,
// otherwise volGroupId can be uninitialized or reference an
// old track.
if (track->used && track->volGroupId == IMUSE_VOLGRP_VOICE) {
if (track->handle.isActive()) {
return true;
}

160
lua.cpp
View File

@ -369,6 +369,19 @@ static void SetSelectedActor() {
g_engine->setSelectedActor(act);
}
/* Get the currently selected actor, this is used in
* "Camera-Relative" mode to handle the appropriate
* actor for movement
*/
static void GetCameraActor() {
Actor *act;
DEBUG_FUNCTION();
stubWarning("VERIFY: GetCameraActor");
act = g_engine->selectedActor();
lua_pushusertag(act, MKID('ACTR'));
}
static void SetSayLineDefaults() {
char *key_text = NULL;
lua_Object table_obj;
@ -530,6 +543,8 @@ static void GetActorPos() {
DEBUG_FUNCTION();
act = check_actor(1);
pos = act->pos();
// It is important to process this request for all actors,
// even for actors not within the active scene
lua_pushnumber(pos.x());
lua_pushnumber(pos.y());
lua_pushnumber(pos.z());
@ -548,10 +563,6 @@ static void SetActorRot() {
act->turnTo(pitch, yaw, roll);
else
act->setRot(pitch, yaw, roll);
// Naranja will cause the game to crash without this
lua_pushnumber(pitch);
lua_pushnumber(yaw);
lua_pushnumber(roll);
}
static void GetActorRot() {
@ -605,19 +616,25 @@ static void GetActorYawToPoint() {
lua_pushnumber(act->yawTo(yawVector));
}
/* Changes the set that an actor is associated with,
* by changing the set to "nil" an actor is disabled
* but should still not be destroyed.
*/
static void PutActorInSet() {
const char *set = "";
Actor *act;
DEBUG_FUNCTION();
act = check_actor(1);
if (!lua_isnil(lua_getparam(2))) {
const char *set;
// If the set is "nil" then set to an empty string, we should not render
// objects in the empty set or bad things will happen like the Bone
// Wagon not changing scenes correctly.
lua_Object param2 = lua_getparam(2);
if (!lua_isnil(param2))
set = luaL_check_string(2);
// Make sure the actor isn't already in the set
if (!act->inSet(set))
act->putInSet(set);
}
// Make sure the actor isn't already in the set
if (!act->inSet(set))
act->putInSet(set);
}
static void SetActorWalkRate() {
@ -776,7 +793,6 @@ static void GetActorNodeLocation() {
Actor *act;
int node;
// Should this actually do anything?
DEBUG_FUNCTION();
act = check_actor(1);
node = check_int(2);
@ -802,11 +818,14 @@ static void GetActorNodeLocation() {
lua_pushnumber(allNodes[node]._pos.z());
}
/* This function is called to stop walking actions that
* are in progress, it is unknown whether it should start
* walking actions that are not in progress.
*/
static void SetActorWalkDominate() {
lua_Object param2;
Actor *act;
// Should this actually do anything?
DEBUG_FUNCTION();
act = check_actor(1);
if (act == NULL) {
@ -814,13 +833,26 @@ static void SetActorWalkDominate() {
return;
}
param2 = lua_getparam(2);
if (lua_isnil(param2))
if (lua_isnil(param2)) {
lua_pushnil();
else if (lua_isnumber(param2))
lua_pushnumber(lua_getnumber(param2));
else
} else if (lua_isnumber(param2)) {
int walkcode = check_int(2);
if (walkcode != 1) {
warning("Unknown SetActorWalkDominate 'walking code' value: %d", walkcode);
lua_pushnil();
return;
}
// When Manny is pursued out of the dam area by a demon
// beaver he needs to stop his walk chore
act->stopWalking();
lua_pushnumber(walkcode);
} else {
warning("Unknown SetActorWalkDominate parameter!");
lua_pushnil();
}
}
static void SetActorColormap() {
char *mapname;
CMap *_cmap;
@ -876,7 +908,7 @@ static void GetActorCostume() {
if (c == NULL) {
lua_pushnil();
if (debugLevel == DEBUG_NORMAL || debugLevel == DEBUG_ALL)
printf("GetActorCostume() on '%s' when actor has no costume!", act->name());
printf("GetActorCostume() on '%s' when actor has no costume!\n", act->name());
return;
}
lua_pushstring(const_cast<char *>(c->filename()));
@ -1129,16 +1161,10 @@ static void TurnActorTo() {
// Find the vector pointing from the actor to the desired location
Vector3d turnToVector(x, y, z);
Vector3d lookVector = turnToVector - act->pos();
lookVector.z() = 0;
// must convert to use a unit vector
lookVector /= lookVector.magnitude();
// find the angle on the upper half of the unit circle
yaw = std::acos(lookVector.x()) * (180 / M_PI);
// adjust for the lower half of the unit circle
if (lookVector.y() < 0)
yaw = 360.0 - yaw;
// find the angle the requested position is around the unit circle
yaw = lookVector.unitCircleAngle();
// yaw is offset from forward by 90 degrees
yaw -= 90.0;
yaw -= 90.0f;
act->turnTo(0, yaw, 0);
// Game will lock in elevator if this doesn't return false
@ -1152,6 +1178,50 @@ static void PointActorAt() {
TurnActorTo();
}
/* WalkActorVector handles the movement of the selected actor
* when the game is in "Camera-Relative Movement Mode"
*
* NOTE: The usage for paramaters 1 and 5 are as-yet unknown.
*/
static void WalkActorVector() {
float moveHoriz, moveVert, yaw;
Actor *act;
DEBUG_FUNCTION();
stubWarning("VERIFY: WalkActorVector");
// Second option is the actor returned by GetCameraActor
act = check_actor(2);
// Third option is the "left/right" movement
moveHoriz = luaL_check_number(3);
// Fourth Option is the "up/down" movement
moveVert = luaL_check_number(4);
// Get the direction the camera is pointing
Vector3d cameraVector = g_engine->currScene()->_currSetup->_interest - g_engine->currScene()->_currSetup->_pos;
// find the angle the camera direction is around the unit circle
float cameraYaw = cameraVector.unitCircleAngle();
// Handle the turning
Vector3d adjustVector(moveHoriz, moveVert, 0);
// find the angle the adjust vector is around the unit circle
float adjustYaw = adjustVector.unitCircleAngle();
yaw = cameraYaw + adjustYaw;
// yaw is offset from forward by 180 degrees
yaw -= 180.0f;
// set the yaw so it can be compared against the current
// value for the actor yaw
if (yaw < 0.0f)
yaw += 360.0f;
if (yaw >= 360.0f)
yaw -= 360.0f;
// set the new direction or walk forward
if (act->yaw() != yaw)
act->turnTo(0, yaw, 0);
else
act->walkForward();
}
/* RotateVector takes a vector and rotates it around
* the point (0,0,0) by the requested number of degrees.
* This function is used to calculate the locations for
@ -1306,7 +1376,8 @@ static void GetVisibleThings() {
for (Engine::ActorListType::const_iterator i = g_engine->actorsBegin(); i != g_engine->actorsEnd(); i++) {
if (!(*i)->inSet(g_engine->sceneName()))
continue;
if (sel->angleTo(*(*i)) < 90) {
// Consider the active actor visible
if (sel == (*i) || sel->angleTo(*(*i)) < 90) {
lua_pushobject(result);
lua_pushusertag(*i, MKID('ACTR'));
lua_pushnumber(1);
@ -1406,12 +1477,21 @@ static void TextFileGetLineCount() {
static void LocalizeString() {
char msgId[32], buf[640], *str;
char *result;
DEBUG_FUNCTION();
str = luaL_check_string(1);
std::string msg = parseMsgText(str, msgId);
sprintf(buf, "/%s/%s", msgId, msg.c_str());
lua_pushstring(const_cast<char *>(buf));
// If the string that we're passed isn't localized yet then
// construct the localized string, otherwise spit back what
// we've been given
if (str[0] == '/' && str[strlen(str)-1] == '/') {
std::string msg = parseMsgText(str, msgId);
sprintf(buf, "/%s/%s", msgId, msg.c_str());
result = buf;
} else {
result = str;
}
lua_pushstring(const_cast<char *>(result));
}
static void SayLine() {
@ -1664,18 +1744,26 @@ static void MakeCurrentSetup() {
lua_endblock();
}
/* Find the requested scene and return the current setup
* id number. This function cannot just use the current
* scene or else when Manny opens his inventory information
* gets lost, such as the position for the demon beavors
* in the Petrified Forest.
*/
static void GetCurrentSetup() {
const char *name;
Scene *scene;
DEBUG_FUNCTION();
name = luaL_check_string(1);
if (std::strcmp(name, g_engine->sceneName()) == 0) {
lua_pushnumber(g_engine->currScene()->setup());
} else {
scene = g_engine->findScene(name);
if (scene == NULL) {
if (debugLevel == DEBUG_WARN || debugLevel == DEBUG_ALL)
warning("GetCurrentSetup() Requested scene (%s) is not the active scene (%s)", name, g_engine->sceneName());
warning("GetCurrentSetup() Requested scene (%s) is not loaded!", name);
lua_pushnil();
return;
}
lua_pushnumber(scene->setup());
}
// FIXME: Function only spits back what it's given
@ -3197,9 +3285,7 @@ STUB_FUNC(WorldToScreen)
STUB_FUNC(SetActorRoll)
STUB_FUNC(IsPointInSector)
STUB_FUNC(SetActorFrustrumCull)
STUB_FUNC(GetCameraActor)
STUB_FUNC(DriveActorTo)
STUB_FUNC(WalkActorVector)
STUB_FUNC(GetActorRect)
STUB_FUNC(SetActorTimeScale)
STUB_FUNC(SetActorScale)

View File

@ -32,6 +32,11 @@ void start_script (void) {
f = L->stack.stack + L->Cstack.lua2C;
if (ttype(f) == LUA_T_CLOSURE)
f = &clvalue(f)->consts[0];
// Start nothing? start_script gets called in this fashion
// by the scene in the scrimshaw parlor, if we just return
// immediately the game proceeds ok.
if (ttype(f) == LUA_T_NIL)
return;
if (ttype(f) != LUA_T_PROTO)
lua_error("can only start_script with a Lua function");

View File

@ -82,6 +82,23 @@ public:
return std::sqrt(x() * x() + y() * y() + z() * z());
}
// Get the angle a vector is around the unit circle
// (ignores z-component)
float unitCircleAngle() const {
float a = x() / magnitude();
float b = y() / magnitude();
float yaw;
// find the angle on the upper half of the unit circle
yaw = std::acos(a) * (180.0f / M_PI);
if (b < 0.0f)
// adjust for the lower half of the unit circle
return 360.0f - yaw;
else
// no adjustment, angle is on the upper half
return yaw;
}
float dotProduct( float sx, float sy, float sz ) {
return x() * sx + y() * sy + z()*sz;
}

View File

@ -96,8 +96,39 @@ bool Sector::isPointInSector(Vector3d point) const {
// vertices are always given in counterclockwise order, and the
// polygons are always convex.)
//
// (I don't know whether the box height actually has to be considered;
// if not then this will be fine as is.)
// Checking the box height on the first point fixes problems with Manny
// changing sectors outside Velasco's storeroom. We make an exceptions
// for heights of 0 and 9999 since these appear to have special meaning.
// In order to have the entrance to the Blue Casket work we need to
// handle the vertices having different z-coordinates.
// TODO: Improve height checking for when vertices have different
// z-coordinates so the railing in Cafe Calavera works properly.
if (_height != 0.0f && _height != 9999.0f) {
bool heightOK = false;
// Handle height above Z
if ((point.z() >= _vertices[0].z()) && (point.z() <= _vertices[0].z() + _height))
heightOK = true;
// Handle height below Z
if ((point.z() <= _vertices[0].z()) && (point.z() >= _vertices[0].z() - _height))
heightOK = true;
for (int i = 0; i < _numVertices; i++) {
if (_vertices[i + 1].z() != _vertices[i].z())
heightOK = true;
}
if (!heightOK) {
/* Use this for debugging problems at height interfaces
if (debugLevel == DEBUG_NORMAL || debugLevel == DEBUG_ALL) {
printf("Rejected trigger due to height: %s (%f)\n", _name.c_str(), _height);
printf("Actor Z: %f\n", point.z());
for (int i = 0; i < _numVertices; i++)
printf("(%d) Z: %f\n", i, _vertices[i].z());
}
*/
return false;
}
}
for (int i = 0; i < _numVertices; i++) {
Vector3d edge = _vertices[i + 1] - _vertices[i];