mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-15 14:18:37 +00:00
1513 lines
44 KiB
C++
1513 lines
44 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "engines/icb/common/px_common.h"
|
|
#include "engines/icb/debug.h"
|
|
#include "engines/icb/p4_generic.h"
|
|
#include "engines/icb/common/px_scriptengine.h"
|
|
#include "engines/icb/common/px_game_object.h"
|
|
#include "engines/icb/icb.h"
|
|
#include "engines/icb/common/ptr_util.h"
|
|
#include "engines/icb/floors.h"
|
|
#include "engines/icb/mission.h"
|
|
#include "engines/icb/global_objects.h"
|
|
#include "engines/icb/object_structs.h"
|
|
#include "engines/icb/sound.h"
|
|
#include "engines/icb/res_man.h"
|
|
|
|
namespace ICB {
|
|
|
|
mcodeFunctionReturnCodes fn_apply_bullet(int32 &result, int32 *params) { return (g_mission->session->fn_apply_bullet(result, params)); }
|
|
|
|
mcodeFunctionReturnCodes fn_set_to_last_frame_generic_anim(int32 &result, int32 *params) { return (MS->fn_set_to_last_frame_generic_anim(result, params)); }
|
|
|
|
mcodeFunctionReturnCodes fn_play_custom_anim(int32 &result, int32 *params) { return (MS->fn_play_custom_anim(result, params)); }
|
|
|
|
mcodeFunctionReturnCodes fn_easy_play_generic_anim(int32 &result, int32 *params) { return (MS->fn_easy_play_generic_anim(result, params)); }
|
|
|
|
mcodeFunctionReturnCodes fn_easy_play_custom_anim(int32 &result, int32 *params) { return (MS->fn_easy_play_custom_anim(result, params)); }
|
|
|
|
mcodeFunctionReturnCodes fn_snap_face_object(int32 &result, int32 *params) { return (MS->fn_snap_face_object(result, params)); }
|
|
|
|
mcodeFunctionReturnCodes fn_face_coord(int32 &result, int32 *params) { return (MS->fn_face_coord(result, params)); }
|
|
|
|
mcodeFunctionReturnCodes fn_face_object(int32 &result, int32 *params) { return (MS->fn_face_object(result, params)); }
|
|
|
|
mcodeFunctionReturnCodes fn_set_to_first_frame_custom_anim(int32 &result, int32 *params) { return (MS->fn_set_to_first_frame_custom_anim(result, params)); }
|
|
|
|
mcodeFunctionReturnCodes fn_set_to_last_frame_custom_anim(int32 &result, int32 *params) { return (MS->fn_set_to_last_frame_custom_anim(result, params)); }
|
|
|
|
mcodeFunctionReturnCodes fn_new_apply_bullet(int32 &result, int32 *params) { return (MS->fn_new_apply_bullet(result, params)); }
|
|
|
|
mcodeFunctionReturnCodes fn_play_generic_anim(int32 &result, int32 *params) { return (MS->fn_play_generic_anim(result, params)); }
|
|
|
|
mcodeFunctionReturnCodes fn_reverse_generic_anim(int32 &result, int32 *params) { return (MS->fn_reverse_generic_anim(result, params)); }
|
|
|
|
mcodeFunctionReturnCodes fn_apply_anim_y(int32 &result, int32 *params) { return (MS->fn_apply_anim_y(result, params)); }
|
|
|
|
mcodeFunctionReturnCodes fn_set_to_first_frame_generic_anim(int32 &result, int32 *params) { return (MS->fn_set_to_first_frame_generic_anim(result, params)); }
|
|
|
|
mcodeFunctionReturnCodes fn_easy_play_generic_anim_with_pan(int32 &result, int32 *params) { return (MS->fn_easy_play_generic_anim_with_pan(result, params)); }
|
|
|
|
mcodeFunctionReturnCodes fn_fast_face_object(int32 &result, int32 *params) { return (MS->fn_fast_face_object(result, params)); }
|
|
|
|
mcodeFunctionReturnCodes fn_face_nicos_pan(int32 &result, int32 *params) { return (MS->fn_face_nicos_pan(result, params)); }
|
|
|
|
mcodeFunctionReturnCodes fn_add_y(int32 &result, int32 *params) { return (MS->fn_add_y(result, params)); }
|
|
|
|
mcodeFunctionReturnCodes fn_reverse_custom_anim(int32 &result, int32 *params) { return (MS->fn_reverse_custom_anim(result, params)); }
|
|
|
|
mcodeFunctionReturnCodes fn_fast_face_coord(int32 &result, int32 *params) { return (MS->fn_fast_face_coord(result, params)); }
|
|
|
|
mcodeFunctionReturnCodes fn_easy_play_custom_anim_with_pan(int32 &result, int32 *params) { return (MS->fn_easy_play_custom_anim_with_pan(result, params)); }
|
|
|
|
mcodeFunctionReturnCodes fn_prime_custom_anim(int32 &result, int32 *params) { return (MS->fn_prime_custom_anim(result, params)); }
|
|
|
|
mcodeFunctionReturnCodes fn_sync_with_mega(int32 &result, int32 *params) { return (MS->fn_sync_with_mega(result, params)); }
|
|
|
|
mcodeFunctionReturnCodes fn_set_feet_to_pan(int32 &result, int32 *params) { return (MS->fn_set_feet_to_pan(result, params)); }
|
|
|
|
mcodeFunctionReturnCodes fn_hard_load_generic_anim(int32 &result, int32 *params) { return (MS->fn_hard_load_generic_anim(result, params)); }
|
|
|
|
mcodeFunctionReturnCodes fn_hard_load_custom_anim(int32 &result, int32 *params) { return (MS->fn_hard_load_custom_anim(result, params)); }
|
|
|
|
mcodeFunctionReturnCodes fn_face_camera(int32 &result, int32 *params) { return (MS->fn_face_camera(result, params)); }
|
|
|
|
mcodeFunctionReturnCodes _game_session::fn_face_camera(int32 &, int32 *params) {
|
|
// params 0 face away from camera
|
|
// 1 face toward camera
|
|
|
|
PXfloat new_pan, diff;
|
|
PXcamera currentCamera;
|
|
|
|
if (!L->looping) {
|
|
currentCamera = GetCamera();
|
|
new_pan = (PXfloat)currentCamera.pan;
|
|
|
|
// reverse 180deg?
|
|
if (params[1])
|
|
new_pan += HALF_TURN;
|
|
|
|
if (new_pan > HALF_TURN)
|
|
new_pan -= FULL_TURN;
|
|
|
|
else if (new_pan < -HALF_TURN)
|
|
new_pan += FULL_TURN;
|
|
|
|
// get difference between the two
|
|
diff = new_pan - L->pan;
|
|
|
|
if (PXfabs(diff) > (FULL_TURN / 10)) { // 0.1f
|
|
// work out which way to turn
|
|
if (diff > HALF_TURN)
|
|
diff -= FULL_TURN;
|
|
|
|
else if (diff < -HALF_TURN)
|
|
diff += FULL_TURN;
|
|
|
|
// diff is now the distance to turn by and its sign denotes direction
|
|
|
|
if (diff < FLOAT_ZERO) {
|
|
M->turn_dir = 0; // right
|
|
} else {
|
|
M->turn_dir = 1; // left
|
|
}
|
|
|
|
M->target_pan = (PXfloat)PXfabs(diff); // save positive pan distance
|
|
|
|
M->actual_target_pan = new_pan; // actual target which we may clip to
|
|
|
|
L->anim_pc = 0; // legal pc for first frame in turn anim - this needs thought
|
|
|
|
L->looping = TRUE8;
|
|
} else {
|
|
// shallow angle so snap and continue as normal
|
|
L->pan = new_pan;
|
|
return IR_CONT;
|
|
}
|
|
}
|
|
|
|
// still got some to go
|
|
if (M->target_pan) {
|
|
Animate_turn_to_pan(__TURN_ON_THE_SPOT_CLOCKWISE, 1);
|
|
return (IR_REPEAT);
|
|
}
|
|
|
|
// we're done
|
|
L->looping = FALSE8;
|
|
|
|
// set to stand
|
|
L->cur_anim_type = __STAND;
|
|
L->anim_pc = 0;
|
|
|
|
return (IR_CONT);
|
|
}
|
|
|
|
// fn_set_feet_to_pan()
|
|
// ensures actual pan is what we are looking at
|
|
mcodeFunctionReturnCodes _game_session::fn_set_feet_to_pan(int32 &, int32 *) {
|
|
// we face straight ahead
|
|
I->lookBone.boneTarget.vz = (int16)(0);
|
|
|
|
// and our pan is set to the looking_pan
|
|
L->pan = M->looking_pan;
|
|
|
|
return IR_CONT;
|
|
}
|
|
|
|
mcodeFunctionReturnCodes _game_session::fn_face_coord(int32 &, int32 *params) {
|
|
// params 0 target x
|
|
// 1 target z
|
|
|
|
// return IR_CONT or
|
|
// IR_REPEAT
|
|
|
|
if (!L->looping) {
|
|
// setup
|
|
|
|
if (Calc_target_pan((PXreal)params[0], (PXreal)params[1], L->mega->actor_xyz.x, L->mega->actor_xyz.z)) {
|
|
// turn required
|
|
|
|
L->looping = TRUE8;
|
|
} else
|
|
return (IR_CONT); // will have possibly made a tiny snap
|
|
}
|
|
|
|
// still got some to go
|
|
if (M->target_pan) {
|
|
Animate_turn_to_pan(__TURN_ON_THE_SPOT_CLOCKWISE, 1);
|
|
return (IR_REPEAT);
|
|
}
|
|
|
|
// we're done
|
|
L->looping = FALSE8;
|
|
|
|
// set to stand
|
|
L->cur_anim_type = __STAND;
|
|
L->anim_pc = 0;
|
|
|
|
return (IR_CONT);
|
|
}
|
|
|
|
mcodeFunctionReturnCodes _game_session::fn_face_nicos_pan(int32 &, int32 *params) {
|
|
// params 0 target nico
|
|
// 1 reserved for future use
|
|
|
|
// return IR_CONT or
|
|
// IR_REPEAT
|
|
|
|
_feature_info *start_pos;
|
|
PXfloat new_pan, diff;
|
|
|
|
const char *nico_name = (const char *)MemoryUtil::resolvePtr(params[0]);
|
|
|
|
if (!L->looping) {
|
|
// setup
|
|
start_pos = (_feature_info *)features->Try_fetch_item_by_name(nico_name);
|
|
if (!start_pos)
|
|
Fatal_error("no NICO marker (fn_face_nico) ob %s, nico %s", object->GetName(), nico_name);
|
|
|
|
new_pan = start_pos->direction;
|
|
|
|
// get difference between the two
|
|
diff = new_pan - L->pan;
|
|
|
|
if (PXfabs(diff) > (FULL_TURN / 10)) { // 0.1f
|
|
// work out which way to turn
|
|
if (diff > HALF_TURN)
|
|
diff -= FULL_TURN;
|
|
else if (diff < -HALF_TURN)
|
|
diff += FULL_TURN;
|
|
|
|
// diff is now the distance to turn by and its sign denotes direction
|
|
|
|
if (diff < FLOAT_ZERO) {
|
|
M->turn_dir = 0; // right
|
|
} else {
|
|
M->turn_dir = 1; // left
|
|
}
|
|
|
|
M->target_pan = (PXfloat)PXfabs(diff); // save positive pan distance
|
|
|
|
M->actual_target_pan = new_pan; // actual target which we may clip to
|
|
|
|
L->anim_pc = 0; // legal pc for first frame in turn anim - this needs thought
|
|
|
|
L->looping = TRUE8;
|
|
} else {
|
|
// shallow angle so snap and continue as normal
|
|
L->pan = new_pan;
|
|
return IR_CONT;
|
|
}
|
|
}
|
|
|
|
// still got some to go
|
|
if (M->target_pan) {
|
|
Animate_turn_to_pan(__TURN_ON_THE_SPOT_CLOCKWISE, 1);
|
|
return (IR_REPEAT);
|
|
}
|
|
|
|
// we're done
|
|
L->looping = FALSE8;
|
|
|
|
// set to stand
|
|
L->cur_anim_type = __STAND;
|
|
L->anim_pc = 0;
|
|
|
|
return (IR_CONT);
|
|
}
|
|
|
|
mcodeFunctionReturnCodes _game_session::fn_face_object(int32 &, int32 *params) {
|
|
// params target object
|
|
|
|
// return IR_CONT or
|
|
// IR_REPEAT
|
|
|
|
const char *object_name = (const char *)MemoryUtil::resolvePtr(params[0]);
|
|
|
|
if (!L->looping) {
|
|
// setup
|
|
_logic *log;
|
|
|
|
uint32 id = objects->Fetch_item_number_by_name(object_name);
|
|
|
|
log = Fetch_object_struct(id);
|
|
|
|
if (log->image_type == PROP) {
|
|
if (Calc_target_pan(log->prop_xyz.x, log->prop_xyz.z, M->actor_xyz.x, M->actor_xyz.z)) {
|
|
// turn required
|
|
L->looping = TRUE8;
|
|
} else
|
|
return (IR_CONT); // will have possibly made a tiny snap
|
|
|
|
} else {
|
|
if (Calc_target_pan(log->mega->actor_xyz.x, log->mega->actor_xyz.z, L->mega->actor_xyz.x, L->mega->actor_xyz.z)) {
|
|
// turn required
|
|
L->looping = TRUE8;
|
|
} else
|
|
return (IR_CONT); // will have possibly made a tiny snap
|
|
}
|
|
}
|
|
|
|
// still got some to go
|
|
if (M->target_pan) {
|
|
Animate_turn_to_pan(__TURN_ON_THE_SPOT_CLOCKWISE, 1);
|
|
return (IR_REPEAT);
|
|
}
|
|
|
|
// we're done
|
|
L->looping = FALSE8;
|
|
|
|
// set to stand
|
|
L->cur_anim_type = __STAND;
|
|
L->anim_pc = 0;
|
|
|
|
return (IR_CONT);
|
|
}
|
|
|
|
mcodeFunctionReturnCodes _game_session::fn_fast_face_object(int32 &, int32 *params) {
|
|
// params 0 target object
|
|
// 1 speed up
|
|
|
|
// return IR_CONT or
|
|
// IR_REPEAT
|
|
|
|
const char *object_name = (const char *)MemoryUtil::resolvePtr(params[0]);
|
|
|
|
if (!L->looping) {
|
|
// setup
|
|
_logic *log;
|
|
|
|
uint32 id = objects->Fetch_item_number_by_name(object_name);
|
|
|
|
log = Fetch_object_struct(id);
|
|
|
|
if (log->image_type == PROP) {
|
|
if (Calc_target_pan(log->prop_xyz.x, log->prop_xyz.z, M->actor_xyz.x, M->actor_xyz.z)) {
|
|
// turn required
|
|
L->looping = TRUE8;
|
|
} else
|
|
return (IR_CONT); // will have possibly made a tiny snap
|
|
} else {
|
|
if (Calc_target_pan(log->mega->actor_xyz.x, log->mega->actor_xyz.z, L->mega->actor_xyz.x, L->mega->actor_xyz.z)) {
|
|
// turn required
|
|
L->looping = TRUE8;
|
|
} else
|
|
return (IR_CONT); // will have possibly made a tiny snap
|
|
}
|
|
}
|
|
|
|
// still got some to go
|
|
if (M->target_pan) {
|
|
Animate_turn_to_pan(__TURN_ON_THE_SPOT_CLOCKWISE, params[1]);
|
|
return (IR_REPEAT);
|
|
}
|
|
|
|
// we're done
|
|
L->looping = FALSE8;
|
|
|
|
// set to stand
|
|
L->cur_anim_type = __STAND;
|
|
L->anim_pc = 0;
|
|
|
|
return (IR_CONT);
|
|
}
|
|
|
|
mcodeFunctionReturnCodes _game_session::fn_fast_face_coord(int32 &, int32 *params) {
|
|
// params 0 x
|
|
// 1 z
|
|
// 2 speed up
|
|
|
|
// return IR_CONT or
|
|
// IR_REPEAT
|
|
|
|
if (!L->looping) {
|
|
if (Calc_target_pan((PXreal)params[0], (PXreal)params[1], L->mega->actor_xyz.x, L->mega->actor_xyz.z)) {
|
|
// turn required
|
|
L->looping = TRUE8;
|
|
} else
|
|
return (IR_CONT); // will have possibly made a tiny snap
|
|
}
|
|
|
|
// still got some to go
|
|
if (M->target_pan) {
|
|
Animate_turn_to_pan(__TURN_ON_THE_SPOT_CLOCKWISE, params[2]);
|
|
return (IR_REPEAT);
|
|
}
|
|
|
|
// we're done
|
|
L->looping = FALSE8;
|
|
|
|
// set to stand
|
|
L->cur_anim_type = __STAND;
|
|
L->anim_pc = 0;
|
|
|
|
return (IR_CONT);
|
|
}
|
|
|
|
bool8 _game_session::Need_to_turn_to_face_object(uint32 id) {
|
|
// is a turn required to face an object
|
|
// used by chi
|
|
|
|
_logic *log;
|
|
|
|
log = Fetch_object_struct(id);
|
|
|
|
if (log->image_type == PROP)
|
|
Fatal_error("fast_face_object = target must be mega");
|
|
|
|
if (Calc_target_pan(log->mega->actor_xyz.x, log->mega->actor_xyz.z, L->mega->actor_xyz.x, L->mega->actor_xyz.z)) {
|
|
// turn required
|
|
return TRUE8;
|
|
}
|
|
|
|
return (FALSE8); // may even have made a tiny snap
|
|
}
|
|
|
|
bool8 _game_session::fast_face_object(uint32 id, uint32 speed) {
|
|
// called in engine
|
|
// for example from chi logic
|
|
|
|
if (!L->looping) {
|
|
// setup
|
|
_logic *log;
|
|
|
|
log = Fetch_object_struct(id);
|
|
|
|
if (log->image_type == PROP)
|
|
Fatal_error("fast_face_object = target must be mega");
|
|
|
|
if (Calc_target_pan(log->mega->actor_xyz.x, log->mega->actor_xyz.z, L->mega->actor_xyz.x, L->mega->actor_xyz.z)) {
|
|
// turn required
|
|
L->looping = TRUE8;
|
|
} else
|
|
return (TRUE8); // will have possibly made a tiny snap
|
|
}
|
|
|
|
// still got some to go
|
|
if (M->target_pan) {
|
|
Animate_turn_to_pan(__TURN_ON_THE_SPOT_CLOCKWISE, speed);
|
|
return (FALSE8);
|
|
}
|
|
|
|
// we're done
|
|
L->looping = FALSE8;
|
|
|
|
// set to stand
|
|
L->cur_anim_type = __STAND;
|
|
L->anim_pc = 0;
|
|
|
|
return (TRUE8);
|
|
}
|
|
|
|
bool8 _game_session::fast_face_rnd(uint32 speed) {
|
|
PXfloat new_pan, diff;
|
|
|
|
if (!L->looping) {
|
|
// pick a random pan
|
|
new_pan = (FULL_TURN * (g_icb->getRandomSource()->getRandomNumber(359 - 1))) / 360;
|
|
|
|
// get difference between the two
|
|
diff = new_pan - L->pan;
|
|
|
|
if (PXfabs(diff) > (FULL_TURN / 10)) { // 0.1f
|
|
// work out which way to turn
|
|
if (diff > HALF_TURN)
|
|
diff -= FULL_TURN;
|
|
|
|
else if (diff < -HALF_TURN)
|
|
diff += FULL_TURN;
|
|
|
|
// diff is now the distance to turn by and its sign denotes direction
|
|
if (diff < FLOAT_ZERO) {
|
|
M->turn_dir = 0; // right
|
|
} else {
|
|
M->turn_dir = 1; // left
|
|
}
|
|
|
|
M->target_pan = (PXfloat)PXfabs(diff); // save positive pan distance
|
|
|
|
M->actual_target_pan = new_pan; // actual target which we may clip to
|
|
|
|
L->anim_pc = 0; // legal pc for first frame in turn anim - this needs thought
|
|
|
|
L->looping = TRUE8;
|
|
|
|
} else
|
|
return TRUE8; // random was too tiny to bother
|
|
}
|
|
|
|
// still got some to go
|
|
if (M->target_pan) {
|
|
Animate_turn_to_pan(__TURN_ON_THE_SPOT_CLOCKWISE, speed);
|
|
return (FALSE8);
|
|
}
|
|
|
|
// we're done
|
|
L->looping = FALSE8;
|
|
|
|
// set to stand
|
|
L->cur_anim_type = __STAND;
|
|
L->anim_pc = 0;
|
|
|
|
return (TRUE8);
|
|
}
|
|
|
|
mcodeFunctionReturnCodes _game_session::fn_snap_face_object(int32 &, int32 *params) {
|
|
// force pan - no animation
|
|
|
|
// params 0 target object
|
|
// return IR_CONT
|
|
|
|
_logic *log;
|
|
|
|
const char *object_name = (const char *)MemoryUtil::resolvePtr(params[0]);
|
|
|
|
Zdebug("fn_snap_face_object [%s]", object_name);
|
|
|
|
uint32 id = objects->Fetch_item_number_by_name(object_name);
|
|
|
|
if (id == 0xffffffff)
|
|
Fatal_error("fn_snap_face_object cant find target object %s", object_name);
|
|
|
|
log = Fetch_object_struct(id);
|
|
|
|
if (log->image_type == PROP) {
|
|
if (Calc_target_pan(log->prop_xyz.x, log->prop_xyz.z, M->actor_xyz.x, M->actor_xyz.z)) {
|
|
L->pan = M->actual_target_pan;
|
|
M->actual_target_pan = REAL_ZERO;
|
|
}
|
|
} else {
|
|
if (Calc_target_pan(log->mega->actor_xyz.x, log->mega->actor_xyz.z, L->mega->actor_xyz.x, L->mega->actor_xyz.z)) {
|
|
L->pan = M->actual_target_pan;
|
|
M->actual_target_pan = REAL_ZERO;
|
|
}
|
|
}
|
|
|
|
return (IR_CONT);
|
|
}
|
|
|
|
bool8 _game_session::speech_face_object(uint32 tar_id) {
|
|
// custom system for speech
|
|
|
|
// return TRUE8 - more to do
|
|
// FALSE - done
|
|
bool8 res;
|
|
|
|
if (!L->looping) {
|
|
// setup
|
|
_logic *log;
|
|
|
|
log = Fetch_object_struct(tar_id);
|
|
|
|
if (log->image_type == VOXEL)
|
|
res = Calc_target_pan(log->mega->actor_xyz.x, log->mega->actor_xyz.z, L->mega->actor_xyz.x, L->mega->actor_xyz.z);
|
|
|
|
else
|
|
res = Calc_target_pan(log->prop_xyz.x, log->prop_xyz.z, L->mega->actor_xyz.x, L->mega->actor_xyz.z);
|
|
|
|
if (res) {
|
|
// turn required
|
|
L->looping = TRUE8;
|
|
} else { // will have possibly made a tiny snap
|
|
// set to stand
|
|
L->cur_anim_type = __STAND;
|
|
L->anim_pc = 0;
|
|
|
|
return (FALSE8); // done!
|
|
}
|
|
}
|
|
|
|
// still got some to go
|
|
if (M->target_pan) {
|
|
Animate_turn_to_pan(__TURN_ON_THE_SPOT_CLOCKWISE, 1);
|
|
return (TRUE8); // more to do
|
|
}
|
|
|
|
// we're done
|
|
L->looping = FALSE8;
|
|
|
|
// set to stand
|
|
L->cur_anim_type = __STAND;
|
|
L->anim_pc = 0;
|
|
|
|
Zdebug(" finished");
|
|
|
|
return (FALSE8); // done
|
|
}
|
|
|
|
mcodeFunctionReturnCodes _game_session::fn_reverse_generic_anim(int32 &, int32 *params) {
|
|
// params 0 ascii name of anim
|
|
|
|
// return IR_CONT or
|
|
// IR_REPEAT
|
|
|
|
bool8 ret;
|
|
|
|
const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
|
|
|
|
if (!L->looping) {
|
|
// setup
|
|
M->next_anim_type = Fetch_generic_anim_from_ascii(anim_name);
|
|
L->looping = 100;
|
|
ANIM_CHECK(M->next_anim_type);
|
|
L->list[0] = HashString(anim_name);
|
|
}
|
|
|
|
if (L->looping == 100) {
|
|
// setup
|
|
// psx async loading check - is file in memory
|
|
if (!rs_anims->Res_open(I->get_info_name(M->next_anim_type), I->info_name_hash[M->next_anim_type], I->base_path, I->base_path_hash))
|
|
return IR_REPEAT;
|
|
|
|
if ((Object_visible_to_camera(cur_id)) &&
|
|
(!rs_anims->Res_open(I->get_anim_name(M->next_anim_type), I->anim_name_hash[M->next_anim_type], I->base_path, I->base_path_hash)))
|
|
return IR_REPEAT;
|
|
|
|
L->cur_anim_type = M->next_anim_type; // anim now in memory
|
|
|
|
L->looping = TRUE8;
|
|
|
|
PXanim *anim = (PXanim *)rs_anims->Res_open(I->get_info_name(L->cur_anim_type), I->info_name_hash[L->cur_anim_type], I->base_path, I->base_path_hash); //
|
|
|
|
// set last frame
|
|
L->anim_pc = anim->frame_qty - 2;
|
|
|
|
return (IR_REPEAT);
|
|
}
|
|
|
|
// ok, we are simply animating through the frames
|
|
// last frame is currently displayed?
|
|
if (!L->anim_pc) {
|
|
L->looping = FALSE8;
|
|
return (IR_CONT);
|
|
}
|
|
|
|
// shift character and frame forward by the amount appropriate
|
|
ret = MS->Reverse_frame_and_motion(L->cur_anim_type, 0, M->anim_speed);
|
|
if (!ret) { // could not move forward?
|
|
L->looping = FALSE8;
|
|
return (IR_CONT);
|
|
}
|
|
|
|
return (IR_REPEAT);
|
|
}
|
|
|
|
mcodeFunctionReturnCodes _game_session::fn_play_generic_anim(int32 &, int32 *params) {
|
|
// params 0 ascii name of anim
|
|
|
|
// return IR_CONT or
|
|
// IR_REPEAT
|
|
|
|
bool8 ret;
|
|
|
|
const char *anim_name = nullptr;
|
|
if (params && params[0]) {
|
|
anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
|
|
}
|
|
|
|
if (!L->looping) {
|
|
// setup
|
|
M->next_anim_type = Fetch_generic_anim_from_ascii(anim_name);
|
|
L->looping = 100;
|
|
ANIM_CHECK(M->next_anim_type);
|
|
L->list[0] = HashString(anim_name);
|
|
}
|
|
|
|
if (L->looping == 100) {
|
|
// psx async loading check - is file in memory
|
|
if (!rs_anims->Res_open(I->get_info_name(M->next_anim_type), I->info_name_hash[M->next_anim_type], I->base_path, I->base_path_hash))
|
|
return IR_REPEAT;
|
|
|
|
if ((Object_visible_to_camera(cur_id)) &&
|
|
(!rs_anims->Res_open(I->get_anim_name(M->next_anim_type), I->anim_name_hash[M->next_anim_type], I->base_path, I->base_path_hash)))
|
|
return IR_REPEAT;
|
|
|
|
// anim found and started ok
|
|
L->looping = TRUE8;
|
|
|
|
L->cur_anim_type = M->next_anim_type; // anim now in memory
|
|
|
|
// get animation
|
|
ANIM_CHECK(L->cur_anim_type);
|
|
|
|
PXanim *anim = (PXanim *)rs_anims->Res_open(I->get_info_name(L->cur_anim_type), I->info_name_hash[L->cur_anim_type], I->base_path, I->base_path_hash); //
|
|
|
|
// advance the frame
|
|
L->anim_pc = anim->frame_qty - 2;
|
|
Advance_frame_and_motion(L->cur_anim_type, 0, 1);
|
|
L->anim_pc = 0;
|
|
|
|
return (IR_REPEAT);
|
|
}
|
|
|
|
// ok, we are simply animating through the frames
|
|
|
|
PXanim *anim = (PXanim *)rs_anims->Res_open(I->get_info_name(L->cur_anim_type), I->info_name_hash[L->cur_anim_type], I->base_path, I->base_path_hash); //
|
|
|
|
// last frame is currently displayed?
|
|
if ((int32)(L->anim_pc + M->anim_speed) >= (anim->frame_qty - 1)) {
|
|
L->looping = FALSE8;
|
|
return (IR_CONT);
|
|
}
|
|
|
|
// shift character and frame forward by the amount appropriate
|
|
ret = Advance_frame_and_motion(L->cur_anim_type, 0, M->anim_speed);
|
|
|
|
if (!ret) { // could not move forward?
|
|
L->looping = FALSE8;
|
|
return (IR_CONT);
|
|
}
|
|
|
|
// more to do - come back again next cycle
|
|
return (IR_REPEAT);
|
|
}
|
|
|
|
mcodeFunctionReturnCodes _game_session::fn_easy_play_generic_anim(int32 &, int32 *params) {
|
|
// barriers are ignored!
|
|
|
|
// params 0 ascii name of anim
|
|
|
|
// return IR_CONT or
|
|
// IR_REPEAT
|
|
|
|
const char *anim_name = nullptr;
|
|
if (params && params[0]) {
|
|
anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
|
|
}
|
|
|
|
if (!L->looping) {
|
|
// setup
|
|
M->next_anim_type = Fetch_generic_anim_from_ascii(anim_name);
|
|
L->looping = 100;
|
|
ANIM_CHECK(M->next_anim_type);
|
|
L->list[0] = HashString(anim_name);
|
|
}
|
|
|
|
if (L->looping == 100) {
|
|
// setup
|
|
// psx async loading check - is file in memory
|
|
if (!rs_anims->Res_open(I->get_info_name(M->next_anim_type), I->info_name_hash[M->next_anim_type], I->base_path, I->base_path_hash))
|
|
return IR_REPEAT;
|
|
|
|
if ((Object_visible_to_camera(cur_id)) &&
|
|
(!rs_anims->Res_open(I->get_anim_name(M->next_anim_type), I->anim_name_hash[M->next_anim_type], I->base_path, I->base_path_hash)))
|
|
return IR_REPEAT;
|
|
|
|
L->cur_anim_type = M->next_anim_type; // anim now in memory
|
|
L->looping = TRUE8;
|
|
|
|
// advance the frame
|
|
// get animation
|
|
ANIM_CHECK(L->cur_anim_type);
|
|
|
|
PXanim *anim = (PXanim *)rs_anims->Res_open(I->get_info_name(L->cur_anim_type), I->info_name_hash[L->cur_anim_type], I->base_path, I->base_path_hash); //
|
|
|
|
L->anim_pc = anim->frame_qty - 2;
|
|
Easy_frame_and_motion(L->cur_anim_type, 0, 1);
|
|
L->anim_pc = 0;
|
|
|
|
return (IR_REPEAT);
|
|
}
|
|
|
|
// ok, we are simply animating through the frames
|
|
|
|
// get animation
|
|
ANIM_CHECK(L->cur_anim_type);
|
|
|
|
PXanim *anim = (PXanim *)rs_anims->Res_open(I->get_info_name(L->cur_anim_type), I->info_name_hash[L->cur_anim_type], I->base_path, I->base_path_hash);
|
|
|
|
// last frame is currently displayed?
|
|
if ((int32)(L->anim_pc + M->anim_speed) >= (anim->frame_qty - 1)) {
|
|
L->looping = FALSE8;
|
|
return (IR_CONT);
|
|
}
|
|
|
|
// shift character and frame forward by the amount appropriate
|
|
MS->Easy_frame_and_motion(L->cur_anim_type, 0, M->anim_speed);
|
|
|
|
// more to do - come back again next cycle
|
|
return (IR_REPEAT);
|
|
}
|
|
|
|
mcodeFunctionReturnCodes _game_session::fn_easy_play_generic_anim_with_pan(int32 &, int32 *params) {
|
|
// barriers are ignored!
|
|
|
|
// params 0 ascii name of anim
|
|
|
|
// return IR_CONT or
|
|
// IR_REPEAT
|
|
|
|
const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
|
|
|
|
if (!L->looping) {
|
|
// setup
|
|
M->next_anim_type = Fetch_generic_anim_from_ascii(anim_name);
|
|
L->looping = 100;
|
|
ANIM_CHECK(M->next_anim_type);
|
|
L->list[0] = HashString(anim_name);
|
|
}
|
|
|
|
if (L->looping == 100) {
|
|
// setup
|
|
|
|
// psx async loading check - is file in memory
|
|
if (!rs_anims->Res_open(I->get_info_name(M->next_anim_type), I->info_name_hash[M->next_anim_type], I->base_path, I->base_path_hash))
|
|
return IR_REPEAT;
|
|
|
|
if ((Object_visible_to_camera(cur_id)) &&
|
|
(!rs_anims->Res_open(I->get_anim_name(M->next_anim_type), I->anim_name_hash[M->next_anim_type], I->base_path, I->base_path_hash)))
|
|
return IR_REPEAT;
|
|
|
|
L->cur_anim_type = M->next_anim_type; // anim now in memory
|
|
|
|
L->looping = TRUE8;
|
|
|
|
// advance the frame
|
|
// get animation
|
|
ANIM_CHECK(L->cur_anim_type);
|
|
|
|
PXanim *anim = (PXanim *)rs_anims->Res_open(I->get_info_name(L->cur_anim_type), I->info_name_hash[L->cur_anim_type], I->base_path, I->base_path_hash); //
|
|
|
|
L->anim_pc = anim->frame_qty - 2;
|
|
Easy_frame_motion_and_pan(L->cur_anim_type, 0);
|
|
L->anim_pc = 0;
|
|
|
|
return (IR_REPEAT);
|
|
}
|
|
|
|
// ok, we are simply animating through the frames
|
|
|
|
// get animation
|
|
ANIM_CHECK(L->cur_anim_type);
|
|
|
|
PXanim *anim = (PXanim *)rs_anims->Res_open(I->get_info_name(L->cur_anim_type), I->info_name_hash[L->cur_anim_type], I->base_path, I->base_path_hash); //
|
|
|
|
// last frame is currently displayed?
|
|
if ((int32)(L->anim_pc + 1) == (anim->frame_qty - 1)) {
|
|
L->looping = FALSE8;
|
|
return (IR_CONT);
|
|
}
|
|
|
|
// shift character and frame forward by the amount appropriate
|
|
MS->Easy_frame_motion_and_pan(L->cur_anim_type, 0);
|
|
|
|
// more to do - come back again next cycle
|
|
return (IR_REPEAT);
|
|
}
|
|
|
|
mcodeFunctionReturnCodes _game_session::fn_easy_play_custom_anim_with_pan(int32 &, int32 *params) {
|
|
// barriers are ignored!
|
|
// pan is updated
|
|
|
|
// params 0 ascii name of anim
|
|
|
|
// return IR_CONT or
|
|
// IR_REPEAT
|
|
|
|
const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
|
|
|
|
Zdebug("fn_easy_play_custom_anim_with_pan %s %s", object->GetName(), anim_name);
|
|
|
|
if (!L->looping) {
|
|
// set anim up
|
|
I->Init_custom_animation(anim_name);
|
|
Reset_cur_megas_custom_type();
|
|
L->looping = 100; // have to distinguish between first time in and first cycle with anim in memory
|
|
ANIM_CHECK(__NON_GENERIC);
|
|
L->list[0] = HashString(anim_name);
|
|
}
|
|
|
|
// anim is in memory so do first frame then pass on to normal logic path
|
|
if (L->looping == 100) {
|
|
// psx async loading check - is file in memory
|
|
if (!rs_anims->Res_open(I->get_info_name(__NON_GENERIC), I->info_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash))
|
|
return IR_REPEAT;
|
|
|
|
if ((Object_visible_to_camera(cur_id)) &&
|
|
(!rs_anims->Res_open(I->get_anim_name(__NON_GENERIC), I->anim_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash)))
|
|
return IR_REPEAT;
|
|
|
|
I->Promote_non_generic(); // swap out the _NON_GENERIC to safe place
|
|
L->cur_anim_type = __PROMOTED_NON_GENERIC;
|
|
|
|
L->anim_pc = 0;
|
|
L->looping = TRUE8;
|
|
|
|
return (IR_REPEAT);
|
|
}
|
|
|
|
// ok, we are simply animating through the frames
|
|
|
|
PXanim *anim = (PXanim *)rs_anims->Res_open(I->get_info_name(L->cur_anim_type), I->info_name_hash[L->cur_anim_type], I->base_path, I->base_path_hash); //
|
|
|
|
// last frame is currently displayed?
|
|
if ((int32)(L->anim_pc + 1) == (anim->frame_qty - 1)) {
|
|
L->looping = FALSE8;
|
|
|
|
return (IR_CONT);
|
|
}
|
|
|
|
// shift character and frame forward by the amount appropriate
|
|
MS->Easy_frame_motion_and_pan(L->cur_anim_type, 0);
|
|
|
|
// more to do - come back again next cycle
|
|
return (IR_REPEAT);
|
|
}
|
|
|
|
mcodeFunctionReturnCodes _game_session::fn_set_to_last_frame_generic_anim(int32 &, int32 *params) {
|
|
// params 0 ascii name of anim
|
|
|
|
// return IR_CONT or IR_STOP if error
|
|
|
|
const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
|
|
|
|
if (!L->looping) {
|
|
M->next_anim_type = Fetch_generic_anim_from_ascii(anim_name);
|
|
L->looping = 100;
|
|
ANIM_CHECK(M->next_anim_type);
|
|
L->list[0] = HashString(anim_name);
|
|
}
|
|
|
|
// psx async loading check - is file in memory
|
|
if (!rs_anims->Res_open(I->get_info_name(M->next_anim_type), I->info_name_hash[M->next_anim_type], I->base_path, I->base_path_hash))
|
|
return IR_REPEAT;
|
|
|
|
if ((Object_visible_to_camera(cur_id)) &&
|
|
(!rs_anims->Res_open(I->get_anim_name(M->next_anim_type), I->anim_name_hash[M->next_anim_type], I->base_path, I->base_path_hash)))
|
|
return IR_REPEAT;
|
|
|
|
L->cur_anim_type = M->next_anim_type; // anim now in memory
|
|
|
|
// ok, set to last frame
|
|
// get animation
|
|
ANIM_CHECK(L->cur_anim_type);
|
|
|
|
PXanim *anim = (PXanim *)rs_anims->Res_open(I->get_info_name(L->cur_anim_type), I->info_name_hash[L->cur_anim_type], I->base_path, I->base_path_hash); //
|
|
|
|
// set to last frame
|
|
L->anim_pc = anim->frame_qty - 2; // if 10 frames then 10+1 (looper) == 11 meaning 9 is last displayable frame number
|
|
L->looping = 0;
|
|
|
|
return IR_CONT;
|
|
}
|
|
|
|
mcodeFunctionReturnCodes _game_session::fn_set_to_first_frame_generic_anim(int32 &, int32 *params) {
|
|
// params 0 ascii name of anim
|
|
|
|
// return IR_CONT or IR_STOP if error
|
|
|
|
const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
|
|
|
|
if (!L->looping) {
|
|
M->next_anim_type = Fetch_generic_anim_from_ascii(anim_name);
|
|
L->looping = 100;
|
|
ANIM_CHECK(M->next_anim_type);
|
|
}
|
|
|
|
// psx async loading check - is file in memory
|
|
if (!rs_anims->Res_open(I->get_info_name(M->next_anim_type), I->info_name_hash[M->next_anim_type], I->base_path, I->base_path_hash))
|
|
return IR_REPEAT;
|
|
|
|
if ((Object_visible_to_camera(cur_id)) &&
|
|
(!rs_anims->Res_open(I->get_anim_name(M->next_anim_type), I->anim_name_hash[M->next_anim_type], I->base_path, I->base_path_hash)))
|
|
return IR_REPEAT;
|
|
|
|
L->cur_anim_type = M->next_anim_type; // anim now in memory
|
|
|
|
// set to last frame
|
|
L->anim_pc = 0; // first
|
|
L->looping = 0;
|
|
|
|
return (IR_CONT);
|
|
}
|
|
|
|
mcodeFunctionReturnCodes _game_session::fn_set_to_first_frame_custom_anim(int32 &, int32 *params) {
|
|
// set to first frame of a custom animation
|
|
// must use fn-set-custom before this
|
|
|
|
// params 0 name of anim
|
|
|
|
const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
|
|
|
|
if (!L->looping) { // once
|
|
I->Init_custom_animation(anim_name);
|
|
L->looping = 1;
|
|
ANIM_CHECK(__NON_GENERIC);
|
|
}
|
|
|
|
// psx async loading check - is file in memory
|
|
if (!rs_anims->Res_open(I->get_info_name(__NON_GENERIC), I->info_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash))
|
|
return IR_REPEAT;
|
|
|
|
if ((Object_visible_to_camera(cur_id)) && (!rs_anims->Res_open(I->get_anim_name(__NON_GENERIC), I->anim_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash)))
|
|
return IR_REPEAT;
|
|
|
|
I->Promote_non_generic(); // swap out the _NON_GENERIC to safe place
|
|
L->cur_anim_type = __PROMOTED_NON_GENERIC;
|
|
|
|
L->anim_pc = 0;
|
|
L->looping = 0;
|
|
|
|
return (IR_CONT);
|
|
}
|
|
|
|
mcodeFunctionReturnCodes _game_session::fn_set_to_last_frame_custom_anim(int32 &, int32 *params) {
|
|
// set to last frame of a custom animation
|
|
// must use fn-set-custom before this
|
|
|
|
// params 0 name of anim
|
|
|
|
const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
|
|
|
|
if (!L->looping) { // once
|
|
I->Init_custom_animation(anim_name);
|
|
L->looping = 1;
|
|
ANIM_CHECK(__NON_GENERIC);
|
|
}
|
|
|
|
// psx async loading check - is file in memory
|
|
if (!rs_anims->Res_open(I->get_info_name(__NON_GENERIC), I->info_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash))
|
|
return IR_REPEAT;
|
|
|
|
if ((Object_visible_to_camera(cur_id)) && (!rs_anims->Res_open(I->get_anim_name(__NON_GENERIC), I->anim_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash)))
|
|
return IR_REPEAT;
|
|
|
|
I->Promote_non_generic(); // swap out the _NON_GENERIC to safe place
|
|
L->cur_anim_type = __PROMOTED_NON_GENERIC;
|
|
|
|
PXanim *anim = (PXanim *)rs_anims->Res_open(I->get_info_name(L->cur_anim_type), I->info_name_hash[L->cur_anim_type], I->base_path, I->base_path_hash);
|
|
|
|
// set to last frame
|
|
L->anim_pc = anim->frame_qty - 2; // if 10 frames then 10+1 (looper) == 11 meaning 9 is last displayable frame number
|
|
|
|
L->looping = 0;
|
|
|
|
return IR_CONT;
|
|
}
|
|
|
|
mcodeFunctionReturnCodes _game_session::fn_hard_load_generic_anim(int32 &, int32 *params) {
|
|
// get generic anim into memory NOW
|
|
|
|
// params 0 name of anim
|
|
const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
|
|
|
|
__mega_set_names load;
|
|
|
|
load = Fetch_generic_anim_from_ascii(anim_name);
|
|
ANIM_CHECK(load);
|
|
rs_anims->Res_open(I->get_info_name(load), I->info_name_hash[load], I->base_path, I->base_path_hash);
|
|
|
|
if (Object_visible_to_camera(cur_id))
|
|
rs_anims->Res_open(I->get_anim_name(load), I->anim_name_hash[load], I->base_path, I->base_path_hash);
|
|
|
|
return IR_CONT;
|
|
}
|
|
|
|
mcodeFunctionReturnCodes _game_session::fn_hard_load_custom_anim(int32 &, int32 *params) {
|
|
// get custom anim into memory NOW
|
|
|
|
// params 0 name of anim
|
|
|
|
const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
|
|
|
|
I->Init_custom_animation(anim_name);
|
|
Reset_cur_megas_custom_type();
|
|
|
|
ANIM_CHECK(__NON_GENERIC);
|
|
rs_anims->Res_open(I->get_info_name(__NON_GENERIC), I->info_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash); //
|
|
|
|
if (Object_visible_to_camera(cur_id))
|
|
rs_anims->Res_open(I->get_anim_name(__NON_GENERIC), I->anim_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash);
|
|
|
|
return IR_CONT;
|
|
}
|
|
|
|
mcodeFunctionReturnCodes _game_session::fn_prime_custom_anim(int32 &, int32 *params) {
|
|
// get custom anim into memory
|
|
|
|
// params 0 name of anim
|
|
|
|
const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
|
|
|
|
if (!L->looping) {
|
|
I->Init_custom_animation(anim_name);
|
|
Reset_cur_megas_custom_type();
|
|
|
|
L->looping = 100;
|
|
|
|
ANIM_CHECK(__NON_GENERIC);
|
|
}
|
|
|
|
// anim is in memory so do first frame then pass on to normal logic path
|
|
if (L->looping == 100) {
|
|
// psx async loading check - is file in memory
|
|
if (!rs_anims->Res_open(I->get_info_name(__NON_GENERIC), I->info_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash))
|
|
return IR_REPEAT;
|
|
|
|
if ((Object_visible_to_camera(cur_id)) &&
|
|
(!rs_anims->Res_open(I->get_anim_name(__NON_GENERIC), I->anim_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash)))
|
|
return IR_REPEAT;
|
|
}
|
|
|
|
// anim is now in memory
|
|
L->looping = 0;
|
|
return IR_CONT;
|
|
}
|
|
|
|
mcodeFunctionReturnCodes _game_session::fn_play_custom_anim(int32 &result, int32 *params) {
|
|
// a mega character plays an anim
|
|
// the anim IS NOT part of the generic set
|
|
// barriers are checked
|
|
|
|
// params 0 name of anim
|
|
|
|
const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
|
|
|
|
if (!L->looping) {
|
|
I->Init_custom_animation(anim_name);
|
|
Reset_cur_megas_custom_type();
|
|
L->looping = 100;
|
|
ANIM_CHECK(__NON_GENERIC);
|
|
L->list[0] = HashString(anim_name);
|
|
}
|
|
|
|
// anim is in memory so do first frame then pass on to normal logic path
|
|
if (L->looping == 100) {
|
|
// psx async loading check - is file in memory
|
|
if (!rs_anims->Res_open(I->get_info_name(__NON_GENERIC), I->info_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash))
|
|
return IR_REPEAT;
|
|
|
|
if ((Object_visible_to_camera(cur_id)) &&
|
|
(!rs_anims->Res_open(I->get_anim_name(__NON_GENERIC), I->anim_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash)))
|
|
return IR_REPEAT;
|
|
|
|
I->Promote_non_generic(); // swap out the _NON_GENERIC to safe place
|
|
L->cur_anim_type = __PROMOTED_NON_GENERIC;
|
|
|
|
L->anim_pc = 0;
|
|
L->looping = TRUE8;
|
|
|
|
return IR_REPEAT;
|
|
}
|
|
|
|
return (fn_play_generic_anim(result, nullptr));
|
|
}
|
|
|
|
mcodeFunctionReturnCodes _game_session::fn_reverse_custom_anim(int32 &, int32 *params) {
|
|
// a mega character plays an anim backward
|
|
// the anim IS NOT part of the generic set
|
|
// barriers are checked
|
|
|
|
// params 0 name of anim
|
|
|
|
bool8 ret;
|
|
|
|
const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
|
|
|
|
if (!L->looping) {
|
|
I->Init_custom_animation(anim_name);
|
|
Reset_cur_megas_custom_type();
|
|
L->looping = 100;
|
|
ANIM_CHECK(__NON_GENERIC);
|
|
L->list[0] = HashString(anim_name);
|
|
}
|
|
|
|
// anim is in memory so do first frame then pass on to normal logic path
|
|
if (L->looping == 100) {
|
|
// psx async loading check - is file in memory
|
|
if (!rs_anims->Res_open(I->get_info_name(__NON_GENERIC), I->info_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash))
|
|
return IR_REPEAT;
|
|
|
|
if ((Object_visible_to_camera(cur_id)) &&
|
|
(!rs_anims->Res_open(I->get_anim_name(__NON_GENERIC), I->anim_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash)))
|
|
return IR_REPEAT;
|
|
|
|
I->Promote_non_generic(); // swap out the _NON_GENERIC to safe place
|
|
L->cur_anim_type = __PROMOTED_NON_GENERIC;
|
|
|
|
PXanim *anim = (PXanim *)rs_anims->Res_open(I->get_info_name(__NON_GENERIC), I->info_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash); //
|
|
L->anim_pc = anim->frame_qty - 2;
|
|
L->looping = TRUE8;
|
|
|
|
return IR_REPEAT;
|
|
}
|
|
|
|
// last frame is currently displayed?
|
|
if (!L->anim_pc) {
|
|
L->looping = FALSE8;
|
|
return IR_CONT;
|
|
}
|
|
|
|
// shift character and frame forward by the amount appropriate
|
|
ret = MS->Reverse_frame_and_motion(L->cur_anim_type, 0, M->anim_speed);
|
|
if (!ret) { // could not move forward?
|
|
L->looping = FALSE8;
|
|
return IR_CONT;
|
|
}
|
|
|
|
// more to do - come back again next cycle
|
|
return IR_REPEAT;
|
|
}
|
|
|
|
mcodeFunctionReturnCodes _game_session::fn_easy_play_custom_anim(int32 &result, int32 *params) {
|
|
// a mega character plays an anim
|
|
// the anim IS NOT part of the generic set
|
|
// barriers are ignored
|
|
|
|
const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
|
|
|
|
if (!L->looping) {
|
|
I->Init_custom_animation(anim_name);
|
|
Reset_cur_megas_custom_type();
|
|
L->looping = 100; // have to distinguish between first time in and first cycle with anim in memory
|
|
ANIM_CHECK(__NON_GENERIC);
|
|
L->list[0] = HashString(anim_name);
|
|
}
|
|
|
|
// anim is in memory so do first frame then pass on to normal logic path
|
|
if (L->looping == 100) {
|
|
// psx async loading check - is file in memory
|
|
if (!rs_anims->Res_open(I->get_info_name(__NON_GENERIC), I->info_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash))
|
|
return IR_REPEAT;
|
|
|
|
if ((Object_visible_to_camera(cur_id)) &&
|
|
(!rs_anims->Res_open(I->get_anim_name(__NON_GENERIC), I->anim_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash)))
|
|
return IR_REPEAT;
|
|
|
|
I->Promote_non_generic(); // swap out the _NON_GENERIC to safe place
|
|
L->cur_anim_type = __PROMOTED_NON_GENERIC;
|
|
|
|
L->anim_pc = 0;
|
|
L->looping = TRUE8;
|
|
return (IR_REPEAT);
|
|
}
|
|
|
|
return (fn_easy_play_generic_anim(result, nullptr));
|
|
}
|
|
|
|
mcodeFunctionReturnCodes _game_session::fn_apply_bullet(int32 &, int32 *) {
|
|
// a bullet is to hit an object
|
|
// we simply call its gun_shot socket
|
|
// this system circumvents the logic context switch
|
|
// this should be used when guards shoot the player... and when chi shoots guards
|
|
|
|
// params 0 name of target
|
|
|
|
M->SetDynamicLight(1, 255, 255, 255, 0, 150, 100, 200); // 2 metres
|
|
|
|
// Hey we are shooting someone (muzzle flash on / cartridge case on (we my want to split this!)
|
|
M->is_shooting = TRUE8;
|
|
|
|
return (IR_CONT);
|
|
}
|
|
|
|
mcodeFunctionReturnCodes _game_session::fn_sync_with_mega(int32 &, int32 *params) {
|
|
// params 0 name of target mega
|
|
// 1 nowt
|
|
|
|
const char *mega_name = (const char *)MemoryUtil::resolvePtr(params[0]);
|
|
|
|
if (!L->looping) {
|
|
L->list[0] = objects->Fetch_item_number_by_name(mega_name);
|
|
L->list[1] = 42; // we are here
|
|
L->looping = TRUE8; // dont do this again
|
|
}
|
|
|
|
if (logic_structs[L->list[0]]->list[1] == 42) {
|
|
// we are going first
|
|
L->list[1] = 43;
|
|
L->looping = 0;
|
|
return IR_CONT; // byeee
|
|
} else if (logic_structs[L->list[0]]->list[1] == 43) {
|
|
// its gone first
|
|
logic_structs[L->list[0]]->list[1] = 0; // clean it up
|
|
L->list[1] = 0; // clean us up
|
|
L->looping = 0;
|
|
return IR_CONT;
|
|
}
|
|
|
|
return IR_REPEAT;
|
|
}
|
|
|
|
mcodeFunctionReturnCodes _game_session::fn_new_apply_bullet(int32 &, int32 *params) {
|
|
// a bullet is to hit an object with a percentage chance of hitting
|
|
// on a hit simply call its gun_shot socket
|
|
// this system circumvents the logic context switch
|
|
// this should be used when guards shoot the player... and when chi shoots guards
|
|
|
|
// params 0 name of target
|
|
// 1 percentage chance
|
|
|
|
uint32 tid;
|
|
int32 retval;
|
|
int32 rnd;
|
|
PXreal sub1, sub2, len;
|
|
bool8 crouched = FALSE8;
|
|
|
|
const char *target_name = (const char *)MemoryUtil::resolvePtr(params[0]);
|
|
|
|
// gun sound
|
|
if (logic_structs[cur_id]->sfxVars[GUNSHOT_SFX_VAR] != 0)
|
|
RegisterSound(cur_id, nullptr, logic_structs[cur_id]->sfxVars[GUNSHOT_SFX_VAR], gunDesc, (int8)127); // have to use full version so we can give hash instead of string
|
|
else
|
|
RegisterSound(cur_id, defaultGunSfx, gunDesc); // use small version as we have string not hash
|
|
|
|
// shot types
|
|
// 0 - nothing on screen
|
|
// 1 - normal light/muzzleflash/cartridge case
|
|
// default is 1
|
|
int32 shotType = object->GetIntegerValueOrDefault("gun_effects", 1);
|
|
|
|
// if mega then do dynamic light (only if shotType isnt 0
|
|
if ((logic_structs[cur_id]->image_type == VOXEL) && (shotType == 1)) {
|
|
// dynamic light
|
|
M->SetDynamicLight(1, 255, 255, 255, 0, 150, 100, 200); // 2 metres
|
|
// Hey we are shooting someone (muzzle flash on / cartridge case on (we my want to split this!)
|
|
M->is_shooting = TRUE8;
|
|
}
|
|
|
|
// get id
|
|
tid = objects->Fetch_item_number_by_name(target_name);
|
|
|
|
// how near
|
|
if (L->image_type == PROP) { // we are prop
|
|
sub1 = (PXreal)L->prop_xyz.x - logic_structs[tid]->mega->actor_xyz.x;
|
|
sub2 = (PXreal)L->prop_xyz.z - logic_structs[tid]->mega->actor_xyz.z;
|
|
} else {
|
|
crouched = M->Is_crouched();
|
|
sub1 = (PXreal)M->actor_xyz.x - logic_structs[tid]->mega->actor_xyz.x;
|
|
sub2 = (PXreal)M->actor_xyz.z - logic_structs[tid]->mega->actor_xyz.z;
|
|
}
|
|
|
|
// dist
|
|
len = (PXreal)((sub1 * sub1) + (sub2 * sub2));
|
|
|
|
// hit chance
|
|
rnd = g_icb->getRandomSource()->getRandomNumber(100 - 1);
|
|
|
|
// we didn't miss
|
|
int32 missed = 0;
|
|
|
|
// user hit chance of 0 means always miss
|
|
if (params[1]) {
|
|
// age chance true, or within distance, or crouching
|
|
if ((rnd < params[1]) || (len < (PXreal)(ALWAYS_HIT_DIST * ALWAYS_HIT_DIST)) || (crouched)) { // hit
|
|
|
|
// if prop is firing then target must be on A floor
|
|
// ELSE
|
|
// if mega firing then both y coords must be the same
|
|
if (((L->image_type == PROP) && (floor_def->On_a_floor(logic_structs[tid]->mega))) ||
|
|
((L->image_type == VOXEL) && (M->actor_xyz.y == logic_structs[tid]->mega->actor_xyz.y))) {
|
|
|
|
// kick kinematic for the player if we are shooting the player
|
|
if (tid == player.Fetch_player_id()) {
|
|
MS->player.being_shot = 3; // cant shoot for 3 cycles (engine anim over three frames)
|
|
MS->player.shot_by_id = (int8)cur_id; // shot by us...!
|
|
|
|
c_game_object *ob = (c_game_object *)objects->Fetch_item_by_number(player.Fetch_player_id());
|
|
int32 ret = ob->GetVariable("hits");
|
|
uint32 hits = ob->GetIntegerVariable(ret);
|
|
|
|
PXreal subp1, subp2;
|
|
if (L->image_type == PROP) { // we are prop
|
|
subp1 = logic_structs[tid]->mega->actor_xyz.x - L->prop_xyz.x;
|
|
subp2 = logic_structs[tid]->mega->actor_xyz.z - L->prop_xyz.z;
|
|
} else {
|
|
subp1 = logic_structs[tid]->mega->actor_xyz.x - M->actor_xyz.x;
|
|
subp2 = logic_structs[tid]->mega->actor_xyz.z - M->actor_xyz.z;
|
|
}
|
|
PXreal dist = ((subp1 * subp1) + (subp2 * subp2));
|
|
|
|
if (dist < PXreal(200 * 200)) {
|
|
if (hits >= 4)
|
|
hits -= 4;
|
|
else
|
|
hits = 0;
|
|
} else if (dist < PXreal(500 * 500)) {
|
|
if (hits >= 2)
|
|
hits -= 2;
|
|
else
|
|
hits = 0;
|
|
} else if (hits)
|
|
hits--;
|
|
|
|
ob->SetIntegerVariable(ret, hits);
|
|
}
|
|
|
|
MS->Call_socket(tid, "gun_shot", &retval); // the hit takes
|
|
|
|
// cancel any speech
|
|
Exit_speech(tid);
|
|
}
|
|
} else {
|
|
// ricochet sound
|
|
missed = 1;
|
|
}
|
|
} else { // missed
|
|
missed = 1;
|
|
}
|
|
|
|
if (missed) {
|
|
// gun sound
|
|
if (logic_structs[cur_id]->sfxVars[RICOCHET_SFX_VAR] != 0)
|
|
RegisterSound(cur_id, nullptr, logic_structs[cur_id]->sfxVars[RICOCHET_SFX_VAR], ricochetDesc,
|
|
(int8)127); // have to use full version so we can give hash instead of string
|
|
else
|
|
RegisterSound(cur_id, defaultRicochetSfx, ricochetDesc); // use small version as we have string not hash
|
|
}
|
|
|
|
// if a guard, adjust the bullet/clip figures
|
|
if (logic_structs[cur_id]->image_type == VOXEL)
|
|
if (M->is_evil) {
|
|
// take chi and player out of the equation
|
|
|
|
int32 ret = object->GetVariable("cur_bullets");
|
|
if (ret != -1) {
|
|
int32 result = object->GetIntegerVariable(ret);
|
|
|
|
if (!result) { // no bullets
|
|
int32 clipret = object->GetVariable("number_of_clips");
|
|
int32 no_clips = object->GetIntegerVariable(clipret);
|
|
if (no_clips == -1)
|
|
Fatal_error("object has no 'number_of_clips' variable");
|
|
|
|
if (no_clips) { // has clips left
|
|
no_clips--; // 1 less
|
|
object->SetIntegerVariable(clipret, no_clips);
|
|
|
|
int32 bull_per_clip = MS->player.GetBulletsPerClip();
|
|
|
|
object->SetIntegerVariable(ret, bull_per_clip); // reload the gun
|
|
}
|
|
} else { // has bullets, fire one
|
|
result--;
|
|
object->SetIntegerVariable(ret, result); // reload
|
|
}
|
|
}
|
|
}
|
|
|
|
return (IR_CONT);
|
|
}
|
|
|
|
mcodeFunctionReturnCodes _game_session::fn_apply_anim_y(int32 &, int32 *params) {
|
|
// add the y offset from frame 0 to end frame
|
|
// used for climbing ladders and stairs and so on where the height gets moved
|
|
|
|
// params 0 generic anim name
|
|
|
|
uint32 k;
|
|
PXreal y_next;
|
|
|
|
const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
|
|
|
|
// 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(anim_name, master_anim_name_table[k].name)) {
|
|
// found!
|
|
ANIM_CHECK(k);
|
|
|
|
PXanim *pAnim = (PXanim *)rs_anims->Res_open(I->get_info_name(k), I->info_name_hash[k], I->base_path, I->base_path_hash); //
|
|
PXreal x, z;
|
|
PXreal yend;
|
|
PXreal ystart;
|
|
|
|
PXFrameEnOfAnim(pAnim->frame_qty - 1, pAnim)->markers[ORG_POS].GetXYZ(&x, ¥d, &z);
|
|
|
|
PXFrameEnOfAnim(0, pAnim)->markers[ORG_POS].GetXYZ(&x, &ystart, &z);
|
|
|
|
y_next = yend - ystart;
|
|
|
|
Tdebug("y_apply.txt", "%s offset - %3.1f", (const char *)I->get_info_name(k), y_next);
|
|
|
|
M->actor_xyz.y += y_next;
|
|
return IR_CONT;
|
|
}
|
|
}
|
|
|
|
Fatal_error("fn_apply_anim_y [%s] cant find generic anim [%s]", object->GetName(), anim_name);
|
|
|
|
return IR_CONT;
|
|
}
|
|
|
|
mcodeFunctionReturnCodes _game_session::fn_add_y(int32 &, int32 *params) {
|
|
// add y value to a mega
|
|
|
|
// params 0 value
|
|
|
|
if (L->image_type == PROP)
|
|
Fatal_error("fn_add_y cant be used on a prop - %s", object->GetName());
|
|
|
|
M->actor_xyz.y += params[0];
|
|
|
|
Tdebug("fn_add_y.txt", "%s +%d to %3.1f", object->GetName(), params[0], M->actor_xyz.y);
|
|
|
|
return IR_CONT;
|
|
}
|
|
|
|
} // End of namespace ICB
|