mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-14 13:50:13 +00:00
466 lines
16 KiB
C++
466 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/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'
|
|
|
|
int32 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(int32 i) {
|
|
// make name
|
|
|
|
char name[ANIM_NAME_STR_LEN];
|
|
int32 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) {
|
|
int32 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];
|
|
int32 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;
|
|
}
|
|
|
|
int32 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
|