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

467 lines
16 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_rccommon.h"
#include "engines/icb/global_switches.h"
#include "engines/icb/session.h"
#include "engines/icb/animation_mega_set.h"
#include "engines/icb/object_structs.h"
#include "engines/icb/debug.h"
#include "engines/icb/p4_generic.h"
#include "engines/icb/mission.h"
#include "engines/icb/p4.h"
#include "engines/icb/player.h"
#include "engines/icb/global_objects.h"
#include "engines/icb/floors.h"
#include "engines/icb/common/px_scriptengine.h"
#include "engines/icb/common/px_floor_map.h"
#include "engines/icb/common/px_features.h"
#include "engines/icb/res_man.h"
#include "common/util.h"
namespace ICB {
// this is the master animation declaration table.
_an_anim_entry master_anim_name_table[__TOTAL_ANIMS] = {
{"walk", __WALK},
{"walk_to_stand", __WALK_TO_STAND},
{"walk_to_other_stand_(left_leg)", __WALK_TO_OTHER_STAND_LEFT_LEG},
{"walk_to_pull_out_weapon", __WALK_TO_PULL_OUT_WEAPON},
{"stand", __STAND},
{"stand_to_walk", __STAND_TO_WALK},
{"stand_to_walk_upstairs_right", __STAND_TO_WALK_UP_STAIRS_RIGHT},
{"stand_to_walk_downstairs_right", __STAND_TO_WALK_DOWN_STAIRS_RIGHT},
{"stand_to_run", __STAND_TO_RUN},
{"stand_to_step_backward", __STAND_TO_STEP_BACKWARD},
{"stand_crouch_to_stand", __STAND_CROUCHED_TO_STAND},
{"stand_crouch_to_walk_crouched", __STAND_CROUCHED_TO_WALK_CROUCHED},
{"run", __RUN},
{"run_to_stand", __RUN_TO_STAND},
{"run_to_pull_out_weapon", __RUN_TO_PULL_OUT_WEAPON},
{"use_card_on_slot", __USE_CARD_ON_SLOT},
{"pick_up_object_from_floor", __PICK_UP_OBJECT_FROM_FLOOR},
{"push_button", __PUSH_BUTTON},
{"being_shot", __BEING_SHOT},
{"being_shot_dead", __BEING_SHOT_DEAD},
{"sidestep_left", __SIDESTEP_LEFT},
{"step_backward", __STEP_BACKWARD},
{"step_forward", __STEP_FORWARD},
{"step_backward_to_stand", __STEP_BACKWARD_TO_STAND},
{"step_backward_to_other_stand_(left_leg)", __STEP_BACKWARD_TO_OTHER_STAND_LEFT},
{"stand_and_aim", __STAND_AND_AIM},
{"stand_and_shoot", __STAND_AND_SHOOT},
{"pull_out_weapon", __PULL_OUT_WEAPON},
{"cord_strike", __STRIKE},
{"low_strike", __LOW_STRIKE},
{"hit_from_behind", __HIT_FROM_BEHIND},
{"turn_on_the_spot_cw", __TURN_ON_THE_SPOT_CLOCKWISE},
{"walk_upstairs_left", __WALK_UPSTAIRS_LEFT},
{"walk_upstairs_right", __WALK_UPSTAIRS_RIGHT},
{"walk_downstairs_left", __WALK_DOWNSTAIRS_LEFT},
{"walk_downstairs_right", __WALK_DOWNSTAIRS_RIGHT},
{"walk_upstairs_left_to_stood_on_stairs_facing_up", __WALK_UPSTAIRS_LEFT_TO_STOOD_ON_STAIRS_FACING_UP},
{"walk_upstairs_right_to_stood_on_stairs_facing_up", __WALK_UPSTAIRS_RIGHT_TO_STOOD_ON_STAIRS_FACING_UP},
{"walk_downstairs_left_to_stood_on_stairs_facing_down", __WALK_DOWNSTAIRS_LEFT_TO_STOOD_ON_STAIRS_FACING_DOWN},
{"walk_downstairs_right_to_stood_on_stairs_facing_down", __WALK_DOWNSTAIRS_RIGHT_TO_STOOD_ON_STAIRS_FACING_DOWN},
{"walk_upstairs_left_to_walk_downstairs_right", __WALK_UPSTAIRS_LEFT_TO_WALK_DOWNSTAIRS_RIGHT},
{"walk_upstairs_right_to_walk_downstairs_left", __WALK_UPSTAIRS_RIGHT_TO_WALK_DOWNSTAIRS_LEFT},
{"walk_downstairs_left_to_walk_upstairs_right", __WALK_DOWNSTAIRS_LEFT_TO_WALK_UPSTAIRS_RIGHT},
{"walk_downstairs_right_to_walk_upstairs_left", __WALK_DOWNSTAIRS_RIGHT_TO_WALK_UPSTAIRS_LEFT},
{"run_up_stairs_left", __RUN_UPSTAIRS_LEFT},
{"run_up_stairs_right", __RUN_UPSTAIRS_RIGHT},
{"run_down_stairs_left", __RUN_DOWNSTAIRS_LEFT},
{"run_down_stairs_right", __RUN_DOWNSTAIRS_RIGHT},
{"climb_up_ladder_left", __CLIMB_UP_LADDER_LEFT},
{"climb_up_ladder_right", __CLIMB_UP_LADDER_RIGHT},
{"climb_down_ladder_left", __CLIMB_DOWN_LADDER_LEFT},
{"climb_down_ladder_right", __CLIMB_DOWN_LADDER_RIGHT},
{"climb_up_ladder_right_to_stand", __CLIMB_UP_LADDER_RIGHT_TO_STAND},
{"climb_down_ladder_right_to_stand", __CLIMB_DOWN_LADDER_RIGHT_TO_STAND},
{"cord_stand_to_climb_up_ladder", __CORD_STAND_TO_CLIMB_UP_LADDER},
{"stand_to_climb_up_ladder_right", __STAND_TO_CLIMB_UP_LADDER_RIGHT},
{"stand_to_climb_down_ladder_right", __STAND_TO_CLIMB_DOWN_LADDER_RIGHT},
{"climb_down_ladder_left_to_slide_down_ladder", __CLIMB_DOWN_LADDER_LEFT_TO_SLIDE_DOWN_LADDER},
{"slide_down_ladder", __SLIDE_DOWN_LADDER},
{"slide_down_ladder_to_stand", __SLIDE_DOWN_LADDER_TO_STAND},
{"load_gun", __LOAD_GUN},
{"load_gun_2", __LOAD_GUN_2},
{"load_gun2", __LOAD_GUN_CROUCH_2},
{"cowering", __COWER},
{"cowering_to_stand", __COWER_TO_STAND},
{"run_hand_through_hair", __HAND_HAIR},
{"shrug", __SHRUG},
{"look_at_watch", __LOOK_AT_WATCH},
{"stretch", __STRETCH},
{"scratching_backside", __SCRATCH},
};
// these names must be in same order as __weapon
char weapon_text[__TOTAL_WEAPONS][MAX_WEAPON_NAME_LENGTH] = {"unarmed", "gun", "crouched", "crouched_gun"};
bool8 armed_state_table[__TOTAL_WEAPONS] = {FALSE8, TRUE8, FALSE8, TRUE8};
_player_stat player_stat_table[__TOTAL_WEAPONS] = {STOOD, NEW_AIM, CROUCHING, CROUCH_AIM};
bool8 crouch_state_table[__TOTAL_WEAPONS] = {FALSE8, FALSE8, TRUE8, TRUE8};
void _vox_image::___init(const char *chr, const char *set, __weapon weapon) {
// store these things temporarily so we can recall this function when swapping voxel -> polygon and vice verse...
strcpy(temp_chr, chr);
strcpy(temp_set, set);
temp_weapon = weapon;
// constructor for mega-set-caps class
// resolve the path of the voxel image directory
// we are passed the character name AND the graphic set
// for example, cord, wetsuit
// this object is created by _game_session::fn_set_voxel_image_path
// where chr='cord'
// set='casual_wear'
int k, len;
// check for no weapon being set
if (weapon == __NOT_SET)
Fatal_error("WARNING %s does not have a weapon type", MS->Fetch_object_name(MS->Fetch_cur_id()));
palette_hash = NULL_HASH;
// get base path
// Make hash filename of the character
char chr_hash[8];
HashFile(chr, chr_hash);
// Make hash filename of the outfit
char set_hash[8];
HashFile(set, set_hash);
// Make the cluster name "\c\<#character>\<#outfit>\outfit.clu"
len = sprintf(base_path, CHR_PATH, chr_hash, set_hash);
if (len > BASE_PATH_STR_LEN)
Fatal_error("_vox_image::___init base_path string too long");
base_path_hash = NULL_HASH;
Zdebug("make base path == %s from %s %s\n", (const char *)base_path, chr, set);
// In the clustered version the image path is the path inside the cluster
len = sprintf(image_path, "%s\\", weapon_text[weapon]);
if (len > IMAGE_PATH_STR_LEN)
Fatal_error("_vox_image::___init image_path [%s] string too long", image_path);
len = sprintf(shadow_mesh_name, "%s", "mesh_shadow.rap");
if (len > IMAGE_PATH_STR_LEN)
Fatal_error("_vox_image::___init shadow_mesh_name [%s] string too long", shadow_mesh_name);
len = sprintf(pose_name, "%s\\pose.rap", weapon_text[weapon]);
if (len > IMAGE_PATH_STR_LEN)
Fatal_error("_vox_image::___init pose_name [%s] string too long", pose_name);
pose_hash = HashString(pose_name);
shadow_mesh_hash = HashString(shadow_mesh_name);
// Make the hash value for this cluster name
base_path_hash = HashString(base_path);
// Make the hash value for this cluster name
base_path_hash = HashString(base_path);
Zdebug("image path == %s\n", (const char *)image_path);
Zdebug("base path == %s\n", (const char *)base_path);
for (k = 0; k < __NON_GENERIC; k++) {
anim_table[k] = (int8)-1;
}
if (((g_mission) && (g_mission->session)) && (MS->Fetch_cur_id() != 999)) {
MS->logic_structs[MS->Fetch_cur_id()]->cur_anim_type = __STAND;
MS->logic_structs[MS->Fetch_cur_id()]->anim_pc = 0;
}
has_custom_path_built = FALSE8; // no custom animation exists
Zdebug("\n-------------------------------------------------------------------------------\n");
}
void _vox_image::MakeAnimEntry(int i) {
// make name
char name[ANIM_NAME_STR_LEN];
int len;
len = sprintf(name, "%s%s.rab", (const char *)image_path, (const char *)master_anim_name_table[i].name);
if (len > ANIM_NAME_STR_LEN)
Fatal_error("_vox_image::___init [%s] string too long", name);
strcpy(anim_name[i], name);
anim_name_hash[i] = HashString(name);
len = sprintf(name, "%s%s.raj", (const char *)image_path, (const char *)master_anim_name_table[i].name);
if (len > ANIM_NAME_STR_LEN)
Fatal_error("_vox_image::___init [%s] string too long", name);
strcpy(info_name[i], name);
info_name_hash[i] = HashString(name);
// do the test file
anim_table[i] = (int8)(rs_anims->Test_file(get_anim_name(i), anim_name_hash[i], base_path, base_path_hash));
}
bool8 _vox_image::Init_custom_animation(const char *anim) {
// init a non generic animation in its special __NON_GENERIC slot
// this does not ensure the anim exists
bool8 custom;
char custom_image_path_rav[128];
char custom_image_path_rai[128];
uint32 len;
len = strlen(anim);
uint32 j;
for (j = 0; j < len; j++)
if (Common::isUpper(*(anim + j)))
Fatal_error("Init_custom_animation finds [%s] has upper case letters - implementor must edit the script", anim);
// has anyone been and built the path before?
if (has_custom_path_built) {
has_custom_path_built = FALSE8; // remove it
return (TRUE8); // carry on
}
custom = MS->Fetch_custom();
// check for no weapon being set
if (custom == FALSE8 /*__NONE*/) {
// custom must be in the current weapon set - bah, shouldnt have done it like this - its daft
// rav (or equiverlant always come from pcp directory...
len = sprintf(custom_image_path_rav, "%s\\", weapon_text[MS->Fetch_cur_megas_pose()]);
// rai (or equiverlant always come from base path...
len = sprintf(custom_image_path_rai, "%s\\", weapon_text[MS->Fetch_cur_megas_pose()]);
// pose mesh name
len = sprintf(custom_pose_name, "%s\\pose.rap", weapon_text[MS->Fetch_cur_megas_pose()]);
custom_pose_hash = HashString(custom_pose_name);
} else {
// we have specified a custom type - i.e. the anim is not part of the current weapon set, but instead sits parallel to weapon directory
len = sprintf(custom_image_path_rav, "%s\\", MS->Fetch_cur_megas_custom_text());
len = sprintf(custom_image_path_rai, "%s\\", MS->Fetch_cur_megas_custom_text());
len = sprintf(custom_pose_name, "%s\\pose.rap", MS->Fetch_cur_megas_custom_text());
if (len > 128)
Fatal_error("Init_custom_animation string error");
custom_pose_hash = HashString(custom_pose_name);
}
len = sprintf(anim_name[__NON_GENERIC], "%s%s.rab", (const char *)custom_image_path_rav, (const char *)anim);
if (len > ANIM_NAME_STR_LEN)
Fatal_error("Init_custom_animation string error");
anim_name_hash[__NON_GENERIC] = HashString(anim_name[__NON_GENERIC]);
len = sprintf(info_name[__NON_GENERIC], "%s%s.raj", (const char *)custom_image_path_rai, (const char *)anim);
if (len > ANIM_NAME_STR_LEN)
Fatal_error("Init_custom_animation string error");
info_name_hash[__NON_GENERIC] = HashString(info_name[__NON_GENERIC]);
anim_table[__NON_GENERIC] = 1;
if (!rs_anims->Test_file(get_anim_name(__NON_GENERIC), anim_name_hash[__NON_GENERIC], base_path, base_path_hash)) {
Fatal_error("custom anim [%s,%08x] not found in cluster %s", (const char *)anim_name[__NON_GENERIC], anim_name_hash[__NON_GENERIC], base_path);
}
Zdebug(" created [%s]", (const char *)anim_name[__NON_GENERIC]);
return (TRUE8);
}
void _vox_image::Promote_non_generic() {
// copy non-generic path to safe __PROMOTED_NON_GENERIC slot
// this is all for psx asyncing
memcpy(&anim_name[__PROMOTED_NON_GENERIC], &anim_name[__NON_GENERIC], ANIM_NAME_STR_LEN);
memcpy(&info_name[__PROMOTED_NON_GENERIC], &info_name[__NON_GENERIC], ANIM_NAME_STR_LEN);
info_name_hash[__PROMOTED_NON_GENERIC] = info_name_hash[__NON_GENERIC];
anim_name_hash[__PROMOTED_NON_GENERIC] = anim_name_hash[__NON_GENERIC];
anim_table[__PROMOTED_NON_GENERIC] = 1; // hack this
}
bool8 _vox_image::Find_anim_type(__mega_set_names *anim, const char *name) {
uint32 k;
for (k = 0; k < __TOTAL_ANIMS; k++) {
// we must search the table
if (!strcmp(name, master_anim_name_table[k].name)) {
*(anim) = master_anim_name_table[k].ref;
return (TRUE8);
}
}
return (FALSE8);
}
bool8 _game_session::Start_generic_ascii_anim(const char *ascii_name) {
// search for named anim and setup if found
uint32 k;
// search for the named generic anim - cant use __ANIM_NAME from script unfortunately
for (k = 0; k < __TOTAL_ANIMS; k++) {
// we must search the table
if (!strcmp(const_cast<char *>(ascii_name), master_anim_name_table[k].name)) {
Zdebug(" Start_generic_ascii_anim found [%s]", ascii_name);
L->cur_anim_type = master_anim_name_table[k].ref;
L->anim_pc = 0;
// Check to see if this anim exists on the hard drive
// Note this will also make the name entry correctly if the name hasn't already
// been made
if (I->IsAnimTable(L->cur_anim_type) == (int8)-1)
return (FALSE8);
return (TRUE8);
}
}
Zdebug("nightmare!");
return (FALSE8);
}
__mega_set_names _game_session::Fetch_generic_anim_from_ascii(const char *ascii_name) {
// pass name of a generic anim and return the type
uint32 k;
// search for the named generic anim - cant use __ANIM_NAME from script unfortunately
for (k = 0; k < __TOTAL_ANIMS; k++) {
if (!strcmp(const_cast<char *>(ascii_name), master_anim_name_table[k].name)) {
// found!
if (I->IsAnimTable(L->cur_anim_type) == (int8)-1)
Fatal_error("Fetch_generic_anim_from_ascii cant find on drive %s", ascii_name);
return (master_anim_name_table[k].ref);
}
}
Fatal_error("Fetch_generic_anim_from_ascii cant find %s", ascii_name);
return __NON_GENERIC;
}
void PreRegisterTexture(const char *, uint32, const char *, uint32, const char *, uint32);
bool8 _vox_image::Set_texture(const char *tex_name) {
int len;
len = sprintf(texture_name, "%s.revtex", tex_name);
if (len > IMAGE_PATH_STR_LEN)
Fatal_error("_vox_image::Set_texture [%s] string too long", tex_name);
texture_hash = HashString(texture_name);
// set palette to be same as texture
strcpy(palette_name, texture_name);
palette_hash = texture_hash;
// okay preload the texture/palette combo
PreRegisterTexture(texture_name, texture_hash, palette_name, palette_hash, base_path, base_path_hash);
return TRUE8;
}
bool8 _vox_image::Set_mesh(const char *m_name) {
char name[32];
int len;
strcpy(name, m_name);
strcat(name, ".rap");
len = sprintf(mesh_name, "%s", name);
if (len > IMAGE_PATH_STR_LEN)
Fatal_error("_vox_image::___init mesh_name [%s] string too long", mesh_name);
mesh_hash = HashString(mesh_name);
return TRUE8;
}
bool8 _vox_image::Set_palette(const char *pal_name) {
// Ignore the default_palette : this is yucky and hacky but it is the end of the project so tough luck
if (strcmp(pal_name, "default") == 0) {
palette_hash = NULL_HASH;
return TRUE8;
}
int len;
len = sprintf(palette_name, "%s.revtex", pal_name);
if (len > IMAGE_PATH_STR_LEN)
Fatal_error("_vox_image::Set_palette [%s] string too long", pal_name);
palette_hash = HashString(palette_name);
// okay preload the texture/palette combo
PreRegisterTexture(texture_name, texture_hash, palette_name, palette_hash, base_path, base_path_hash);
return TRUE8;
}
} // End of namespace ICB