scummvm/engines/icb/animation.cpp
2020-10-06 09:51:20 +02:00

445 lines
14 KiB
C++

/* ResidualVM - A 3D game interpreter
*
* ResidualVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the AUTHORS
* file distributed with this source distribution.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 "engines/icb/common/px_common.h"
#include "engines/icb/debug.h"
#include "engines/icb/res_man.h"
#include "engines/icb/common/px_scriptengine.h"
#include "engines/icb/common/px_linkeddatafile.h"
#include "engines/icb/common/px_prop_anims.h"
#include "engines/icb/common/ptr_util.h"
#include "engines/icb/object_structs.h"
#include "engines/icb/session.h"
#include "engines/icb/mission.h"
#include "engines/icb/global_switches.h"
#include "engines/icb/global_objects.h"
namespace ICB {
mcodeFunctionReturnCodes fn_prop_animate(int32 &result, int32 *params) { return (MS->fn_prop_animate(result, params)); }
mcodeFunctionReturnCodes fn_prop_set_to_last_frame(int32 &result, int32 *params) { return (MS->fn_prop_set_to_last_frame(result, params)); }
mcodeFunctionReturnCodes fn_prop_set_to_first_frame(int32 &result, int32 *params) { return (MS->fn_prop_set_to_first_frame(result, params)); }
mcodeFunctionReturnCodes fn_test_prop_anim(int32 &result, int32 *params) { return (MS->fn_test_prop_anim(result, params)); }
mcodeFunctionReturnCodes fn_inherit_prop_anim_height(int32 &result, int32 *params) { return (MS->fn_inherit_prop_anim_height(result, params)); }
mcodeFunctionReturnCodes fn_inherit_prop_anim_height_id(int32 &result, int32 *params) { return (MS->fn_inherit_prop_anim_height_id(result, params)); }
mcodeFunctionReturnCodes _game_session::fn_prop_animate(int32 &, int32 *params) {
// runs forward through a prop animation until it finishes
// bungs a frame in first time called - lets last frame have a whole cycle then quits next go
// note - this is for props only not actors
// in
// param 0 anim name
// out
// IR_CONT anim finished
// IR_REPEAT anim not finished yet - more frames remain to be played
_animating_prop *index;
_animation_entry *anim;
uint32 j;
// find entry for this object via its name
index = (_animating_prop *)prop_anims->Try_fetch_item_by_name(object->GetName());
const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// loop through all looking for our named anim
for (j = 0; j < index->num_anims; j++) {
// get each anim for this prop in turn until we match name
anim = (_animation_entry *)(((char *)index) + index->anims[j]);
if (!strcmp(((char *)((char *)index) + anim->name), anim_name)) {
// found the anim
// is this the first time in?
if (!L->looping) {
// first time so set up the anim
// set first frame
prop_state_table[cur_id] = anim->frames[0];
// current pc
L->anim_pc = 0;
// now looping
L->looping = 1;
// come back again next cycle
return (IR_REPEAT);
} else {
// just running through the animation
// is it the end? - i.e. was the frame set up last cycle the last in the sequence - if so then continue with
// the script
if ((uint8)L->anim_pc == (anim->num_frames - 1)) {
// not looping
logic_structs[cur_id]->looping = 0;
// last frame has been displayed so now continue with script
return (IR_CONT);
}
// advance current pc
++L->anim_pc;
// set next frame
prop_state_table[cur_id] = anim->frames[L->anim_pc];
// come back again next cycle
return (IR_REPEAT);
}
}
}
// didnt find the named anim so thats it
Tdebug("objects_that_died.txt", "_game_session::fn_prop_animate object %s cant find anim %s", object->GetName(), anim_name);
Shut_down_object("by fn_prop_animate");
return (IR_STOP);
}
mcodeFunctionReturnCodes _game_session::fn_prop_set_to_last_frame(int32 &, int32 *params) {
_animating_prop *index;
_animation_entry *anim;
uint32 j;
// find entry for this object via its name
index = (_animating_prop *)prop_anims->Try_fetch_item_by_name(object->GetName());
const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// loop through all looking for our named anim
for (j = 0; j < index->num_anims; j++) {
// get each anim for this prop in turn until we match name
anim = (_animation_entry *)(((char *)index) + index->anims[j]);
if (!strcmp(((char *)((char *)index) + anim->name), anim_name)) {
// found the anim
// set to last frame in sequence
prop_state_table[cur_id] = anim->frames[anim->num_frames - 1];
return (IR_CONT);
}
}
// didnt find the named anim so thats it
Tdebug("objects_that_died.txt", "fn_prop_set_to_last_frame object %s cant find anim %s", object->GetName(), anim_name);
Shut_down_object("by fn_prop_set_to_last_frame");
return (IR_REPEAT);
}
mcodeFunctionReturnCodes _game_session::fn_prop_set_to_first_frame(int32 &, int32 *params) {
_animating_prop *index;
_animation_entry *anim;
uint32 j;
// find entry for this object via its name
index = (_animating_prop *)prop_anims->Try_fetch_item_by_name(object->GetName());
const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// loop through all looking for our named anim
for (j = 0; j < index->num_anims; j++) {
// get each anim for this prop in turn until we match name
anim = (_animation_entry *)(((char *)index) + index->anims[j]);
if (!strcmp(((char *)((char *)index) + anim->name), anim_name)) {
// found the anim
// set to last frame in sequence
prop_state_table[cur_id] = anim->frames[0];
return (IR_CONT);
}
}
// didnt find the named anim so thats it
Tdebug("objects_that_died.txt", "fn_prop_set_to_first_frame object %s cant find anim %s", object->GetName(), anim_name);
Message_box("fn_prop_set_to_first_frame object %s cant find anim %s", object->GetName(), anim_name);
Shut_down_object("by fn_prop_set_to_first_frame");
return (IR_REPEAT);
}
mcodeFunctionReturnCodes _game_session::fn_test_prop_anim(int32 &result, int32 *params) {
// confirm that a prop anim actually exists
// this is useful for objects that may be using custom engine logic
_animating_prop *index;
_animation_entry *anim;
uint32 j;
// find entry for this object via its name
index = (_animating_prop *)prop_anims->Try_fetch_item_by_name(object->GetName());
const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// loop through all looking for our named anim
for (j = 0; j < index->num_anims; j++) {
// get each anim for this prop in turn until we match name
anim = (_animation_entry *)(((char *)index) + index->anims[j]);
if (!strcmp(((char *)((char *)index) + anim->name), anim_name)) {
// final check to see if there are actual frames in there
if (anim->num_frames) {
result = 1;
return (IR_CONT);
}
Message_box("fn_test_prop_anim object [%s] has anim [%s] but it has no frames", object->GetName(), anim_name);
result = 0;
return IR_CONT;
}
}
Message_box("fn_test_prop_anim didnt find anim [%s] for object [%s]", anim_name, object->GetName());
result = 0;
return IR_CONT;
}
uint32 _game_session::Validate_prop_anim(const char *anim_name) {
// confirm that a prop anim actually exists
// this is useful for objects that may be using custom engine logic
// return the anim number
_animating_prop *index;
_animation_entry *anim;
uint32 j;
// find entry for this object via its name
index = (_animating_prop *)prop_anims->Try_fetch_item_by_name(object->GetName());
// loop through all looking for our named anim
for (j = 0; j < index->num_anims; j++) {
// get each anim for this prop in turn until we match name
anim = (_animation_entry *)(((char *)index) + index->anims[j]);
if (!strcmp(((char *)((char *)index) + anim->name), anim_name)) {
// final check to see if there are actual frames in there
if (anim->num_frames)
return (j);
Fatal_error("Validate_prop_anim object [%s] has anim [%s] but it has no frames", object->GetName(), anim_name);
}
}
Fatal_error("Validate_prop_anim didnt find anim [%s] for object [%s]", anim_name, object->GetName());
return (FALSE8);
}
mcodeFunctionReturnCodes _game_session::fn_inherit_prop_anim_height_id(int32 &, int32 *params) {
// runs forward through a props animation until it finishes passing the height to the mega
// so instead of playing the anim we're just gettings the y height each frame instead
// the prop should therefore be playing the anim at the same time
// param 0 prop id
// 1 anim name
// out
// IR_CONT anim finished
// IR_REPEAT anim not finished yet - more frames remain to be played
_animating_prop *index;
_animation_entry *anim;
uint32 j;
const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[1]);
Zdebug("fn_inherit_prop_anim_height_id");
// find entry for this object via its name, which we find via its number :(
index = (_animating_prop *)prop_anims->Fetch_item_by_name((const char *)objects->Fetch_items_name_by_number(params[0]));
// loop through all looking for our named anim
for (j = 0; j < index->num_anims; j++) {
// get each anim for this prop in turn until we match name
anim = (_animation_entry *)(((char *)index) + index->anims[j]);
if (!strcmp(((char *)((char *)index) + anim->name), anim_name)) {
// found the anim
Zdebug(" found anim");
// is this the first time in?
if (!L->looping) {
// first time so set up the anim
if (!anim->offset_heights)
return IR_CONT;
// current pc
L->list[0] = 0; // our prop pc!
// now looping
L->looping = 1;
// protect the mega
L->do_not_disturb = 1;
// get first height
int16 *heights = (int16 *)(((char *)index) + anim->offset_heights);
PXreal one_height = (PXreal)(heights[0]);
M->actor_xyz.y = one_height;
// come back again next cycle
return (IR_REPEAT);
} else {
// just running through the animation
// is it the end? - i.e. was the frame set up last cycle the last in the sequence - if so then continue with
// the script
if (L->list[0] > (uint8)(anim->num_frames - 1))
Fatal_error("%s corrupted in fn_inherit_prop_anim_height_id", object->GetName());
if ((uint8)L->list[0] == (anim->num_frames - 1)) {
// not looping
logic_structs[cur_id]->looping = 0;
// unprotect the mega
L->do_not_disturb = 0;
// last frame has been displayed so now continue with script
return (IR_CONT);
}
// advance current pc
L->list[0]++;
Zdebug("pc = %d", L->list[0]);
// get height
int16 *heights = (int16 *)(((char *)index) + anim->offset_heights);
PXreal one_height = (PXreal)(heights[L->list[0]]);
M->actor_xyz.y = one_height;
Zdebug("new height %3.1f", M->actor_xyz.y);
// come back again next cycle
return (IR_REPEAT);
}
}
}
// didnt find the named anim so thats it
Fatal_error("fn_inherit_prop_anim_height_id object [%s] prop [%s] cant find anim [%s]", object->GetName(), objects->Fetch_items_name_by_number(params[0]), anim_name);
return (IR_STOP);
}
mcodeFunctionReturnCodes _game_session::fn_inherit_prop_anim_height(int32 &, int32 *params) {
// runs forward through a props animation until it finishes passing the height to the mega
// so instead of playing the anim we're just gettings the y height each frame instead
// the prop should therefore be playing the anim at the same time
// param 0 prop name
// 1 anim name
// out
// IR_CONT anim finished
// IR_REPEAT anim not finished yet - more frames remain to be played
_animating_prop *index;
_animation_entry *anim;
uint32 j;
const char *prop_name = (const char *)MemoryUtil::resolvePtr(params[0]);
const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[1]);
Zdebug("fn_inherit_prop_anim_height");
Zdebug("ob %s", object->GetName());
Zdebug("prop %s anim %s", prop_name, anim_name);
// find entry for this object via its name, which we find via its number :(
index = (_animating_prop *)prop_anims->Fetch_item_by_name(prop_name);
// loop through all looking for our named anim
for (j = 0; j < index->num_anims; j++) {
// get each anim for this prop in turn until we match name
anim = (_animation_entry *)(((char *)index) + index->anims[j]);
if (!strcmp(((char *)((char *)index) + anim->name), anim_name)) {
// found the anim
Zdebug(" found anim");
// is this the first time in?
if (!L->looping) {
// first time so set up the anim
// current pc
L->list[0] = 0; // our prop pc!
// now looping
L->looping = 1;
// protect the mega
L->do_not_disturb = 1;
// get first height
int16 *heights = (int16 *)(((char *)index) + anim->offset_heights);
PXreal one_height = (PXreal)(heights[0]);
M->actor_xyz.y = one_height;
// come back again next cycle
return (IR_REPEAT);
} else {
// just running through the animation
// is it the end? - i.e. was the frame set up last cycle the last in the sequence - if so then continue with
// the script
if ((uint8)L->list[0] == (anim->num_frames - 1)) {
// not looping
logic_structs[cur_id]->looping = 0;
// unprotect the mega
L->do_not_disturb = 0;
// last frame has been displayed so now continue with script
return (IR_CONT);
}
// advance current pc
L->list[0]++;
// get height
int16 *heights = (int16 *)(((char *)index) + anim->offset_heights);
PXreal one_height = (PXreal)(heights[L->list[0]]);
M->actor_xyz.y = one_height;
// come back again next cycle
return (IR_REPEAT);
}
}
}
// didnt find the named anim so thats it
Fatal_error("fn_inherit_prop_anim_height object [%s] prop [%s] cant find anim [%s]", object->GetName(), prop_name, anim_name);
return (IR_STOP); //
}
} // End of namespace ICB