2006-03-20 17:12:09 +00:00
/*
2014-06-01 17:55:23 +00:00
* Portions of this file are copyright Rebirth contributors and licensed as
* described in COPYING . txt .
* Portions of this file are copyright Parallax Software and licensed
* according to the Parallax license below .
* See COPYING . txt for license details .
2006-03-20 17:12:09 +00:00
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
SOFTWARE CORPORATION ( " PARALLAX " ) . PARALLAX , IN DISTRIBUTING THE CODE TO
END - USERS , AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN , GRANTS A
ROYALTY - FREE , PERPETUAL LICENSE TO SUCH END - USERS FOR USE BY SUCH END - USERS
IN USING , DISPLAYING , AND CREATING DERIVATIVE WORKS THEREOF , SO LONG AS
SUCH USE , DISPLAY OR CREATION IS FOR NON - COMMERCIAL , ROYALTY OR REVENUE
FREE PURPOSES . IN NO EVENT SHALL THE END - USER USE THE COMPUTER CODE
CONTAINED HEREIN FOR REVENUE - BEARING PURPOSES . THE END - USER UNDERSTANDS
AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE .
COPYRIGHT 1993 - 1999 PARALLAX SOFTWARE CORPORATION . ALL RIGHTS RESERVED .
*/
/*
*
* Code for flying through the mines
*
*/
# include <stdio.h>
# include <stdlib.h>
# include "joy.h"
2012-07-07 18:35:06 +00:00
# include "dxxerror.h"
2006-03-20 17:12:09 +00:00
# include "inferno.h"
# include "segment.h"
# include "object.h"
# include "physics.h"
# include "key.h"
# include "game.h"
# include "collide.h"
# include "fvi.h"
# include "newdemo.h"
2013-12-26 04:18:28 +00:00
# include "gameseg.h"
2006-03-20 17:12:09 +00:00
# include "timer.h"
# include "ai.h"
# include "wall.h"
# include "laser.h"
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
# include "bm.h"
# include "player.h"
2013-03-03 01:03:33 +00:00
# define MAX_OBJECT_VEL i2f(100)
# endif
2006-03-20 17:12:09 +00:00
2013-12-22 16:04:18 +00:00
# include "dxxsconf.h"
# include "compiler-range_for.h"
2006-03-20 17:12:09 +00:00
//Global variables for physics system
2013-02-21 00:20:26 +00:00
# define ROLL_RATE 0x2000
2006-03-21 14:01:57 +00:00
# define DAMP_ANG 0x400 //min angle to bank
2006-03-20 17:12:09 +00:00
# define TURNROLL_SCALE (0x4ec4 / 2)
//check point against each side of segment. return bitmask, where bit
//set means behind that side
int floor_levelling = 0 ;
//make sure matrix is orthogonal
void check_and_fix_matrix ( vms_matrix * m )
{
vms_matrix tempm ;
vm_vector_2_matrix ( & tempm , & m - > fvec , & m - > uvec , NULL ) ;
* m = tempm ;
}
2013-10-27 22:00:14 +00:00
static void do_physics_align_object ( object * obj )
2006-03-20 17:12:09 +00:00
{
vms_vector desired_upvec ;
fixang delta_ang , roll_ang ;
//vms_vector forvec = {0,0,f1_0};
vms_matrix temp_matrix ;
fix d , largest_d = - f1_0 ;
int i , best_side ;
best_side = 0 ;
// bank player according to segment orientation
//find side of segment that player is most alligned with
for ( i = 0 ; i < 6 ; i + + ) {
d = vm_vec_dot ( & Segments [ obj - > segnum ] . sides [ i ] . normals [ 0 ] , & obj - > orient . uvec ) ;
if ( d > largest_d ) { largest_d = d ; best_side = i ; }
}
if ( floor_levelling ) {
// old way: used floor's normal as upvec
desired_upvec = Segments [ obj - > segnum ] . sides [ 3 ] . normals [ 0 ] ;
}
else // new player leveling code: use normal of side closest to our up vec
if ( get_num_faces ( & Segments [ obj - > segnum ] . sides [ best_side ] ) = = 2 ) {
side * s = & Segments [ obj - > segnum ] . sides [ best_side ] ;
desired_upvec . x = ( s - > normals [ 0 ] . x + s - > normals [ 1 ] . x ) / 2 ;
desired_upvec . y = ( s - > normals [ 0 ] . y + s - > normals [ 1 ] . y ) / 2 ;
desired_upvec . z = ( s - > normals [ 0 ] . z + s - > normals [ 1 ] . z ) / 2 ;
vm_vec_normalize ( & desired_upvec ) ;
}
else
desired_upvec = Segments [ obj - > segnum ] . sides [ best_side ] . normals [ 0 ] ;
if ( labs ( vm_vec_dot ( & desired_upvec , & obj - > orient . fvec ) ) < f1_0 / 2 ) {
vms_angvec tangles ;
vm_vector_2_matrix ( & temp_matrix , & obj - > orient . fvec , & desired_upvec , NULL ) ;
2011-05-18 23:25:38 +00:00
delta_ang = vm_vec_delta_ang ( & obj - > orient . uvec , & temp_matrix . uvec , & obj - > orient . fvec ) ;
2006-03-20 17:12:09 +00:00
delta_ang + = obj - > mtype . phys_info . turnroll ;
if ( abs ( delta_ang ) > DAMP_ANG ) {
2014-07-13 04:40:28 +00:00
vms_matrix rotmat ;
2006-03-20 17:12:09 +00:00
roll_ang = fixmul ( FrameTime , ROLL_RATE ) ;
if ( abs ( delta_ang ) < roll_ang ) roll_ang = delta_ang ;
else if ( delta_ang < 0 ) roll_ang = - roll_ang ;
tangles . p = tangles . h = 0 ; tangles . b = roll_ang ;
vm_angles_2_matrix ( & rotmat , & tangles ) ;
2014-07-13 04:40:28 +00:00
obj - > orient = vm_matrix_x_matrix ( obj - > orient , rotmat ) ;
2006-03-20 17:12:09 +00:00
}
else floor_levelling = 0 ;
}
}
2013-10-27 22:00:14 +00:00
static void set_object_turnroll ( object * obj )
2006-03-20 17:12:09 +00:00
{
fixang desired_bank ;
desired_bank = - fixmul ( obj - > mtype . phys_info . rotvel . y , TURNROLL_SCALE ) ;
if ( obj - > mtype . phys_info . turnroll ! = desired_bank ) {
fixang delta_ang , max_roll ;
max_roll = fixmul ( ROLL_RATE , FrameTime ) ;
delta_ang = desired_bank - obj - > mtype . phys_info . turnroll ;
if ( labs ( delta_ang ) < max_roll )
max_roll = delta_ang ;
else
if ( delta_ang < 0 )
max_roll = - max_roll ;
obj - > mtype . phys_info . turnroll + = max_roll ;
}
}
//list of segments went through
int phys_seglist [ MAX_FVI_SEGS ] , n_phys_segs ;
# define MAX_IGNORE_OBJS 100
# ifndef NDEBUG
# define EXTRA_DEBUG 1 //no extra debug when NDEBUG is on
# endif
# ifdef EXTRA_DEBUG
object * debug_obj = NULL ;
# endif
# ifndef NDEBUG
int Total_retries = 0 , Total_sims = 0 ;
int Dont_move_ai_objects = 0 ;
# endif
# define FT (f1_0 / 64)
// -----------------------------------------------------------------------------------------------------------
// add rotational velocity & acceleration
2013-10-27 22:00:14 +00:00
static void do_physics_sim_rot ( object * obj )
2006-03-20 17:12:09 +00:00
{
vms_angvec tangles ;
vms_matrix rotmat , new_orient ;
2013-02-21 00:20:26 +00:00
//fix rotdrag_scale;
2006-03-20 17:12:09 +00:00
physics_info * pi ;
Assert ( FrameTime > 0 ) ; //Get MATT if hit this!
pi = & obj - > mtype . phys_info ;
if ( ! ( pi - > rotvel . x | | pi - > rotvel . y | | pi - > rotvel . z | | pi - > rotthrust . x | | pi - > rotthrust . y | | pi - > rotthrust . z ) )
return ;
if ( obj - > mtype . phys_info . drag ) {
int count ;
vms_vector accel ;
fix drag , r , k ;
count = FrameTime / FT ;
r = FrameTime % FT ;
k = fixdiv ( r , FT ) ;
drag = ( obj - > mtype . phys_info . drag * 5 ) / 2 ;
if ( obj - > mtype . phys_info . flags & PF_USES_THRUST ) {
vm_vec_copy_scale ( & accel , & obj - > mtype . phys_info . rotthrust , fixdiv ( f1_0 , obj - > mtype . phys_info . mass ) ) ;
while ( count - - ) {
vm_vec_add2 ( & obj - > mtype . phys_info . rotvel , & accel ) ;
vm_vec_scale ( & obj - > mtype . phys_info . rotvel , f1_0 - drag ) ;
}
//do linear scale on remaining bit of time
vm_vec_scale_add2 ( & obj - > mtype . phys_info . rotvel , & accel , k ) ;
vm_vec_scale ( & obj - > mtype . phys_info . rotvel , f1_0 - fixmul ( k , drag ) ) ;
}
2013-03-03 01:03:33 +00:00
else
# if defined(DXX_BUILD_DESCENT_II)
if ( ! ( obj - > mtype . phys_info . flags & PF_FREE_SPINNING ) )
# endif
2013-03-30 20:29:29 +00:00
{
2006-03-20 17:12:09 +00:00
fix total_drag = f1_0 ;
while ( count - - )
total_drag = fixmul ( total_drag , f1_0 - drag ) ;
//do linear scale on remaining bit of time
total_drag = fixmul ( total_drag , f1_0 - fixmul ( k , drag ) ) ;
vm_vec_scale ( & obj - > mtype . phys_info . rotvel , total_drag ) ;
}
}
//now rotate object
//unrotate object for bank caused by turn
if ( obj - > mtype . phys_info . turnroll ) {
tangles . p = tangles . h = 0 ;
tangles . b = - obj - > mtype . phys_info . turnroll ;
vm_angles_2_matrix ( & rotmat , & tangles ) ;
2014-07-13 04:40:28 +00:00
obj - > orient = vm_matrix_x_matrix ( obj - > orient , rotmat ) ;
2006-03-20 17:12:09 +00:00
}
tangles . p = fixmul ( obj - > mtype . phys_info . rotvel . x , FrameTime ) ;
tangles . h = fixmul ( obj - > mtype . phys_info . rotvel . y , FrameTime ) ;
2013-02-21 00:20:26 +00:00
tangles . b = fixmul ( obj - > mtype . phys_info . rotvel . z , FrameTime ) ;
2006-03-20 17:12:09 +00:00
vm_angles_2_matrix ( & rotmat , & tangles ) ;
vm_matrix_x_matrix ( & new_orient , & obj - > orient , & rotmat ) ;
obj - > orient = new_orient ;
if ( obj - > mtype . phys_info . flags & PF_TURNROLL )
set_object_turnroll ( obj ) ;
//re-rotate object for bank caused by turn
if ( obj - > mtype . phys_info . turnroll ) {
tangles . p = tangles . h = 0 ;
tangles . b = obj - > mtype . phys_info . turnroll ;
vm_angles_2_matrix ( & rotmat , & tangles ) ;
2014-07-13 04:40:28 +00:00
obj - > orient = vm_matrix_x_matrix ( obj - > orient , rotmat ) ;
2006-03-20 17:12:09 +00:00
}
check_and_fix_matrix ( & obj - > orient ) ;
}
2011-05-18 23:25:38 +00:00
// On joining edges fvi tends to get inaccurate as hell. Approach is to check if the object interects with the wall and if so, move away from it.
2013-10-27 22:00:14 +00:00
static void fix_illegal_wall_intersection ( object * obj , vms_vector * origin )
2011-05-04 00:15:10 +00:00
{
2013-12-29 04:28:07 +00:00
int hside = - 1 , hface = - 1 ;
2011-05-04 00:15:10 +00:00
2011-05-18 23:35:44 +00:00
if ( ! ( obj - > type = = OBJ_PLAYER | | obj - > type = = OBJ_ROBOT ) )
2011-05-04 00:15:10 +00:00
return ;
2013-12-29 04:28:07 +00:00
segnum_t hseg = segment_none ;
2011-05-18 23:25:38 +00:00
if ( object_intersects_wall_d ( obj , & hseg , & hside , & hface ) )
2011-05-04 11:06:30 +00:00
{
2011-06-16 22:33:46 +00:00
vm_vec_scale_add2 ( & obj - > pos , & Segments [ hseg ] . sides [ hside ] . normals [ 0 ] , FrameTime * 10 ) ;
2011-05-18 23:25:38 +00:00
update_object_seg ( obj ) ;
2011-05-04 11:06:30 +00:00
}
2011-05-04 00:15:10 +00:00
}
2006-03-20 17:12:09 +00:00
// -----------------------------------------------------------------------------------------------------------
//Simulate a physics object for this frame
2014-08-16 23:18:17 +00:00
void do_physics_sim ( vobjptridx_t obj )
2006-03-20 17:12:09 +00:00
{
2013-12-29 04:28:07 +00:00
objnum_t ignore_obj_list [ MAX_IGNORE_OBJS ] ;
int n_ignore_objs ;
2006-03-20 17:12:09 +00:00
int try_again ;
2007-12-29 14:18:49 +00:00
int fate = 0 ;
2006-03-20 17:12:09 +00:00
vms_vector frame_vec ; //movement in this frame
vms_vector new_pos , ipos ; //position after this frame
2011-03-14 10:07:39 +00:00
int count = 0 ;
2013-12-29 04:28:07 +00:00
segnum_t WallHitSeg ;
int WallHitSide ;
2006-03-20 17:12:09 +00:00
fvi_info hit_info ;
fvi_query fq ;
vms_vector save_pos ;
fix drag ;
2013-03-30 20:29:29 +00:00
fix sim_time ;
2006-03-20 17:12:09 +00:00
vms_vector start_pos ;
int obj_stopped = 0 ;
fix moved_time ; //how long objected moved before hit something
physics_info * pi ;
2013-12-29 04:28:07 +00:00
segnum_t orig_segnum = obj - > segnum ;
2006-03-20 17:12:09 +00:00
int bounced = 0 ;
Assert ( obj - > movement_type = = MT_PHYSICS ) ;
# ifndef NDEBUG
2006-03-21 14:01:57 +00:00
if ( Dont_move_ai_objects )
if ( obj - > control_type = = CT_AI )
return ;
2006-03-20 17:12:09 +00:00
# endif
pi = & obj - > mtype . phys_info ;
do_physics_sim_rot ( obj ) ;
if ( ! ( pi - > velocity . x | | pi - > velocity . y | | pi - > velocity . z | | pi - > thrust . x | | pi - > thrust . y | | pi - > thrust . z ) )
return ;
n_phys_segs = 0 ;
2014-08-17 21:56:08 +00:00
sim_time = FrameTime ;
2006-03-20 17:12:09 +00:00
2006-03-21 14:01:57 +00:00
//debug_obj = obj;
2006-03-20 17:12:09 +00:00
2006-03-21 14:01:57 +00:00
# ifdef EXTRA_DEBUG
2006-03-20 17:12:09 +00:00
//check for correct object segment
if ( ! get_seg_masks ( & obj - > pos , obj - > segnum , 0 , __FILE__ , __LINE__ ) . centermask = = 0 )
{
if ( ! update_object_seg ( obj ) ) {
if ( ! ( Game_mode & GM_MULTI ) )
Int3 ( ) ;
compute_segment_center ( & obj - > pos , & Segments [ obj - > segnum ] ) ;
2014-01-11 22:37:36 +00:00
obj - > pos . x + = obj ;
2006-03-20 17:12:09 +00:00
}
}
2006-03-21 14:01:57 +00:00
# endif
2006-03-20 17:12:09 +00:00
start_pos = obj - > pos ;
n_ignore_objs = 0 ;
//if uses thrust, cannot have zero drag
Assert ( ! ( obj - > mtype . phys_info . flags & PF_USES_THRUST ) | | obj - > mtype . phys_info . drag ! = 0 ) ;
//do thrust & drag
if ( ( drag = obj - > mtype . phys_info . drag ) ! = 0 ) {
int count ;
vms_vector accel ;
2008-09-30 00:07:07 +00:00
fix r , k , have_accel ;
2006-03-20 17:12:09 +00:00
2008-09-30 00:07:07 +00:00
count = FrameTime / FT ;
r = FrameTime % FT ;
2006-03-20 17:12:09 +00:00
k = fixdiv ( r , FT ) ;
if ( obj - > mtype . phys_info . flags & PF_USES_THRUST ) {
vm_vec_copy_scale ( & accel , & obj - > mtype . phys_info . thrust , fixdiv ( f1_0 , obj - > mtype . phys_info . mass ) ) ;
2008-09-30 00:07:07 +00:00
have_accel = ( accel . x | | accel . y | | accel . z ) ;
2006-03-20 17:12:09 +00:00
while ( count - - ) {
2008-09-30 00:07:07 +00:00
if ( have_accel )
vm_vec_add2 ( & obj - > mtype . phys_info . velocity , & accel ) ;
2006-03-20 17:12:09 +00:00
vm_vec_scale ( & obj - > mtype . phys_info . velocity , f1_0 - drag ) ;
}
//do linear scale on remaining bit of time
vm_vec_scale_add2 ( & obj - > mtype . phys_info . velocity , & accel , k ) ;
2008-09-30 00:07:07 +00:00
if ( drag )
vm_vec_scale ( & obj - > mtype . phys_info . velocity , f1_0 - fixmul ( k , drag ) ) ;
2006-03-20 17:12:09 +00:00
}
2008-09-30 00:07:07 +00:00
else if ( drag )
{
2006-03-20 17:12:09 +00:00
fix total_drag = f1_0 ;
while ( count - - )
total_drag = fixmul ( total_drag , f1_0 - drag ) ;
//do linear scale on remaining bit of time
total_drag = fixmul ( total_drag , f1_0 - fixmul ( k , drag ) ) ;
vm_vec_scale ( & obj - > mtype . phys_info . velocity , total_drag ) ;
}
}
do {
try_again = 0 ;
//Move the object
vm_vec_copy_scale ( & frame_vec , & obj - > mtype . phys_info . velocity , sim_time ) ;
if ( ( frame_vec . x = = 0 ) & & ( frame_vec . y = = 0 ) & & ( frame_vec . z = = 0 ) )
break ;
count + + ;
// If retry count is getting large, then we are trying to do something stupid.
2011-01-23 10:59:48 +00:00
if ( count > 8 ) break ; // in original code this was 3 for all non-player objects. still leave us some limit in case fvi goes apeshit.
2006-03-20 17:12:09 +00:00
vm_vec_add ( & new_pos , & obj - > pos , & frame_vec ) ;
2013-12-26 22:21:16 +00:00
ignore_obj_list [ n_ignore_objs ] = object_none ;
2006-03-20 17:12:09 +00:00
fq . p0 = & obj - > pos ;
fq . startseg = obj - > segnum ;
fq . p1 = & new_pos ;
fq . rad = obj - > size ;
2014-01-11 22:37:36 +00:00
fq . thisobjnum = obj ;
2006-03-20 17:12:09 +00:00
fq . ignore_obj_list = ignore_obj_list ;
fq . flags = FQ_CHECK_OBJS ;
if ( obj - > type = = OBJ_WEAPON )
fq . flags | = FQ_TRANSPOINT ;
if ( obj - > type = = OBJ_PLAYER )
fq . flags | = FQ_GET_SEGLIST ;
fate = find_vector_intersection ( & fq , & hit_info ) ;
// Matt: Mike's hack.
if ( fate = = HIT_OBJECT ) {
object * objp = & Objects [ hit_info . hit_object ] ;
2013-10-07 23:52:33 +00:00
if ( ( ( objp - > type = = OBJ_WEAPON ) & & is_proximity_bomb_or_smart_mine ( get_weapon_id ( objp ) ) ) | | objp - > type = = OBJ_POWERUP ) // do not increase count for powerups since they *should* not change our movement
2006-03-20 17:12:09 +00:00
count - - ;
}
2006-03-21 14:01:57 +00:00
# ifndef NDEBUG
2006-03-20 17:12:09 +00:00
if ( fate = = HIT_BAD_P0 ) {
Int3 ( ) ;
}
2006-03-21 14:01:57 +00:00
# endif
2006-03-20 17:12:09 +00:00
if ( obj - > type = = OBJ_PLAYER ) {
if ( n_phys_segs & & phys_seglist [ n_phys_segs - 1 ] = = hit_info . seglist [ 0 ] )
n_phys_segs - - ;
2013-12-22 16:04:18 +00:00
range_for ( const auto & hs , hit_info . seglist )
{
if ( ! ( n_phys_segs < MAX_FVI_SEGS - 1 ) )
break ;
phys_seglist [ n_phys_segs + + ] = hs ;
}
2006-03-20 17:12:09 +00:00
}
ipos = hit_info . hit_pnt ;
2013-12-29 04:28:07 +00:00
segnum_t iseg = hit_info . hit_seg ;
2006-03-20 17:12:09 +00:00
WallHitSide = hit_info . hit_side ;
WallHitSeg = hit_info . hit_side_seg ;
2013-12-26 22:21:16 +00:00
if ( iseg = = segment_none ) { //some sort of horrible error
2006-03-20 17:12:09 +00:00
if ( obj - > type = = OBJ_WEAPON )
obj - > flags | = OF_SHOULD_BE_DEAD ;
break ;
}
2013-12-26 22:21:16 +00:00
Assert ( ! ( ( fate = = HIT_WALL ) & & ( ( WallHitSeg = = segment_none ) | | ( WallHitSeg > Highest_segment_index ) ) ) ) ;
2006-03-20 17:12:09 +00:00
save_pos = obj - > pos ; //save the object's position
2013-12-29 04:28:07 +00:00
segnum_t save_seg = obj - > segnum ;
2006-03-20 17:12:09 +00:00
// update object's position and segment number
obj - > pos = ipos ;
if ( iseg ! = obj - > segnum )
2014-01-11 22:37:36 +00:00
obj_relink ( obj , iseg ) ;
2006-03-20 17:12:09 +00:00
//if start point not in segment, move object to center of segment
if ( get_seg_masks ( & obj - > pos , obj - > segnum , 0 , __FILE__ , __LINE__ ) . centermask ! = 0 )
{
2013-12-29 04:28:07 +00:00
segnum_t n ;
2006-03-20 17:12:09 +00:00
2013-12-26 22:21:16 +00:00
if ( ( n = find_object_seg ( obj ) ) = = segment_none ) {
2006-03-20 17:12:09 +00:00
//Int3();
2013-12-26 22:21:16 +00:00
if ( obj - > type = = OBJ_PLAYER & & ( n = find_point_seg ( & obj - > last_pos , obj - > segnum ) ) ! = segment_none ) {
2006-03-20 17:12:09 +00:00
obj - > pos = obj - > last_pos ;
2014-01-11 22:37:36 +00:00
obj_relink ( obj , n ) ;
2006-03-20 17:12:09 +00:00
}
else {
compute_segment_center ( & obj - > pos , & Segments [ obj - > segnum ] ) ;
2014-01-11 22:37:36 +00:00
obj - > pos . x + = obj ;
2006-03-20 17:12:09 +00:00
}
if ( obj - > type = = OBJ_WEAPON )
obj - > flags | = OF_SHOULD_BE_DEAD ;
}
return ;
}
//calulate new sim time
{
//vms_vector moved_vec;
vms_vector moved_vec_n ;
fix attempted_dist , actual_dist ;
actual_dist = vm_vec_normalized_dir ( & moved_vec_n , & obj - > pos , & save_pos ) ;
if ( fate = = HIT_WALL & & vm_vec_dot ( & moved_vec_n , & frame_vec ) < 0 ) { //moved backwards
//don't change position or sim_time
obj - > pos = save_pos ;
//iseg = obj->segnum; //don't change segment
2014-01-11 22:37:36 +00:00
obj_relink ( obj , save_seg ) ;
2006-03-20 17:12:09 +00:00
moved_time = 0 ;
}
else {
2013-03-30 20:29:29 +00:00
fix old_sim_time ;
2006-03-20 17:12:09 +00:00
attempted_dist = vm_vec_mag ( & frame_vec ) ;
2013-03-30 20:29:29 +00:00
old_sim_time = sim_time ;
2006-03-20 17:12:09 +00:00
sim_time = fixmuldiv ( sim_time , attempted_dist - actual_dist , attempted_dist ) ;
moved_time = old_sim_time - sim_time ;
if ( sim_time < 0 | | sim_time > old_sim_time ) {
sim_time = old_sim_time ;
//WHY DOES THIS HAPPEN??
moved_time = 0 ;
}
}
}
switch ( fate ) {
case HIT_WALL : {
vms_vector moved_v ;
2008-09-30 00:07:07 +00:00
fix hit_speed = 0 , wall_part = 0 ;
2011-04-13 19:08:11 +00:00
2006-03-20 17:12:09 +00:00
// Find hit speed
vm_vec_sub ( & moved_v , & obj - > pos , & save_pos ) ;
wall_part = vm_vec_dot ( & moved_v , & hit_info . hit_wallnorm ) ;
2012-03-28 09:02:30 +00:00
if ( ( wall_part ! = 0 & & moved_time > 0 & & ( hit_speed = - fixdiv ( wall_part , moved_time ) ) > 0 ) | | obj - > type = = OBJ_WEAPON | | obj - > type = = OBJ_DEBRIS )
2006-03-20 17:12:09 +00:00
collide_object_with_wall ( obj , hit_speed , WallHitSeg , WallHitSide , & hit_info . hit_pnt ) ;
2012-03-28 09:02:30 +00:00
if ( obj - > type = = OBJ_PLAYER )
scrape_player_on_wall ( obj , WallHitSeg , WallHitSide , & hit_info . hit_pnt ) ;
2006-03-20 17:12:09 +00:00
2013-12-26 22:21:16 +00:00
Assert ( WallHitSeg ! = segment_none ) ;
2006-03-20 17:12:09 +00:00
Assert ( WallHitSide > - 1 ) ;
if ( ! ( obj - > flags & OF_SHOULD_BE_DEAD ) ) {
int forcefield_bounce ; //bounce off a forcefield
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
if ( ! cheats . bouncyfire )
# endif
Assert ( ! ( obj - > mtype . phys_info . flags & PF_STICK & & obj - > mtype . phys_info . flags & PF_BOUNCE ) ) ; //can't be bounce and stick
# if defined(DXX_BUILD_DESCENT_I)
/*
* Force fields are not supported in Descent 1. Use
* this as a placeholder to make the code match the
* force field handling in Descent 2.
*/
forcefield_bounce = 0 ;
# elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
forcefield_bounce = ( TmapInfo [ Segments [ WallHitSeg ] . sides [ WallHitSide ] . tmap_num ] . flags & TMI_FORCE_FIELD ) ;
2013-03-03 01:03:33 +00:00
int check_vel = 0 ;
# endif
2006-03-20 17:12:09 +00:00
if ( ! forcefield_bounce & & ( obj - > mtype . phys_info . flags & PF_STICK ) ) { //stop moving
add_stuck_object ( obj , WallHitSeg , WallHitSide ) ;
vm_vec_zero ( & obj - > mtype . phys_info . velocity ) ;
obj_stopped = 1 ;
try_again = 0 ;
}
else { // Slide object along wall
wall_part = vm_vec_dot ( & hit_info . hit_wallnorm , & obj - > mtype . phys_info . velocity ) ;
2011-04-07 20:49:42 +00:00
// if wall_part, make sure the value is sane enough to get usable velocity computed
if ( wall_part < 0 & & wall_part > - f1_0 ) wall_part = - f1_0 ;
if ( wall_part > 0 & & wall_part < f1_0 ) wall_part = f1_0 ;
2006-03-20 17:12:09 +00:00
if ( forcefield_bounce | | ( obj - > mtype . phys_info . flags & PF_BOUNCE ) ) { //bounce off wall
wall_part * = 2 ; //Subtract out wall part twice to achieve bounce
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
if ( forcefield_bounce ) {
check_vel = 1 ; //check for max velocity
if ( obj - > type = = OBJ_PLAYER )
wall_part * = 2 ; //player bounce twice as much
}
if ( obj - > mtype . phys_info . flags & PF_BOUNCES_TWICE ) {
Assert ( obj - > mtype . phys_info . flags & PF_BOUNCE ) ;
if ( obj - > mtype . phys_info . flags & PF_BOUNCED_ONCE )
obj - > mtype . phys_info . flags & = ~ ( PF_BOUNCE + PF_BOUNCED_ONCE + PF_BOUNCES_TWICE ) ;
else
obj - > mtype . phys_info . flags | = PF_BOUNCED_ONCE ;
}
bounced = 1 ; //this object bounced
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
}
vm_vec_scale_add2 ( & obj - > mtype . phys_info . velocity , & hit_info . hit_wallnorm , - wall_part ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
if ( check_vel ) {
fix vel = vm_vec_mag_quick ( & obj - > mtype . phys_info . velocity ) ;
if ( vel > MAX_OBJECT_VEL )
vm_vec_scale ( & obj - > mtype . phys_info . velocity , fixdiv ( MAX_OBJECT_VEL , vel ) ) ;
}
if ( bounced & & obj - > type = = OBJ_WEAPON )
vm_vector_2_matrix ( & obj - > orient , & obj - > mtype . phys_info . velocity , & obj - > orient . uvec , NULL ) ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
try_again = 1 ;
}
}
2011-03-14 10:07:39 +00:00
2006-03-20 17:12:09 +00:00
break ;
}
case HIT_OBJECT : {
vms_vector old_vel ;
// Mark the hit object so that on a retry the fvi code
// ignores this object.
2013-12-26 22:21:16 +00:00
Assert ( hit_info . hit_object ! = object_none ) ;
2006-03-20 17:12:09 +00:00
// Calculcate the hit point between the two objects.
{ vms_vector * ppos0 , * ppos1 , pos_hit ;
fix size0 , size1 ;
ppos0 = & Objects [ hit_info . hit_object ] . pos ;
ppos1 = & obj - > pos ;
size0 = Objects [ hit_info . hit_object ] . size ;
size1 = obj - > size ;
Assert ( size0 + size1 ! = 0 ) ; // Error, both sizes are 0, so how did they collide, anyway?!?
//vm_vec_scale(vm_vec_sub(&pos_hit, ppos1, ppos0), fixdiv(size0, size0 + size1));
//vm_vec_add2(&pos_hit, ppos0);
vm_vec_sub ( & pos_hit , ppos1 , ppos0 ) ;
vm_vec_scale_add ( & pos_hit , ppos0 , & pos_hit , fixdiv ( size0 , size0 + size1 ) ) ;
old_vel = obj - > mtype . phys_info . velocity ;
collide_two_objects ( obj , & Objects [ hit_info . hit_object ] , & pos_hit ) ;
}
// Let object continue its movement
if ( ! ( obj - > flags & OF_SHOULD_BE_DEAD ) ) {
//obj->pos = save_pos;
if ( obj - > mtype . phys_info . flags & PF_PERSISTENT | | ( old_vel . x = = obj - > mtype . phys_info . velocity . x & & old_vel . y = = obj - > mtype . phys_info . velocity . y & & old_vel . z = = obj - > mtype . phys_info . velocity . z ) ) {
//if (Objects[hit_info.hit_object].type == OBJ_POWERUP)
ignore_obj_list [ n_ignore_objs + + ] = hit_info . hit_object ;
try_again = 1 ;
}
}
break ;
}
case HIT_NONE :
break ;
2006-03-21 14:01:57 +00:00
# ifndef NDEBUG
2006-03-20 17:12:09 +00:00
case HIT_BAD_P0 :
Int3 ( ) ; // Unexpected collision type: start point not in specified segment.
break ;
default :
// Unknown collision type returned from find_vector_intersection!!
Int3 ( ) ;
break ;
2006-03-21 14:01:57 +00:00
# endif
2006-03-20 17:12:09 +00:00
}
} while ( try_again ) ;
// Pass retry count info to AI.
if ( obj - > control_type = = CT_AI ) {
if ( count > 0 ) {
2013-12-25 03:16:41 +00:00
obj - > ctype . ai_info . ail . retry_count = count - 1 ;
2006-03-21 14:01:57 +00:00
# ifndef NDEBUG
2006-03-20 17:12:09 +00:00
Total_retries + = count - 1 ;
Total_sims + + ;
2006-03-21 14:01:57 +00:00
# endif
2006-03-20 17:12:09 +00:00
}
}
2008-09-30 00:07:07 +00:00
// After collision with objects and walls, set velocity from actual movement
2010-02-05 18:49:24 +00:00
if ( ! obj_stopped & & ! bounced
& & ( ( obj - > type = = OBJ_PLAYER ) | | ( obj - > type = = OBJ_ROBOT ) | | ( obj - > type = = OBJ_DEBRIS ) )
& & ( ( fate = = HIT_WALL ) | | ( fate = = HIT_OBJECT ) | | ( fate = = HIT_BAD_P0 ) )
)
2009-01-13 01:19:19 +00:00
{
2006-03-20 17:12:09 +00:00
vms_vector moved_vec ;
vm_vec_sub ( & moved_vec , & obj - > pos , & start_pos ) ;
vm_vec_copy_scale ( & obj - > mtype . phys_info . velocity , & moved_vec , fixdiv ( f1_0 , FrameTime ) ) ;
}
2011-05-19 09:49:49 +00:00
fix_illegal_wall_intersection ( obj , & start_pos ) ;
2011-05-04 00:15:10 +00:00
2006-03-20 17:12:09 +00:00
//Assert(check_point_in_seg(&obj->pos,obj->segnum,0).centermask==0);
//if (obj->control_type == CT_FLYING)
if ( obj - > mtype . phys_info . flags & PF_LEVELLING )
do_physics_align_object ( obj ) ;
//hack to keep player from going through closed doors
2011-02-14 21:27:07 +00:00
if ( obj - > type = = OBJ_PLAYER & & obj - > segnum ! = orig_segnum & & ( ! cheats . ghostphysics ) ) {
2006-03-20 17:12:09 +00:00
int sidenum ;
sidenum = find_connect_side ( & Segments [ obj - > segnum ] , & Segments [ orig_segnum ] ) ;
if ( sidenum ! = - 1 ) {
if ( ! ( WALL_IS_DOORWAY ( & Segments [ orig_segnum ] , sidenum ) & WID_FLY_FLAG ) ) {
side * s ;
2014-07-17 02:48:51 +00:00
int num_faces ;
2006-03-20 17:12:09 +00:00
fix dist ;
2014-07-17 03:22:06 +00:00
vertex_array_list_t vertex_list ;
2006-03-20 17:12:09 +00:00
//bump object back
s = & Segments [ orig_segnum ] . sides [ sidenum ] ;
create_abs_vertex_lists ( & num_faces , vertex_list , orig_segnum , sidenum , __FILE__ , __LINE__ ) ;
//let's pretend this wall is not triangulated
2014-07-17 02:48:51 +00:00
auto b = begin ( vertex_list ) ;
auto vertnum = * std : : min_element ( b , std : : next ( b , 4 ) ) ;
2006-03-20 17:12:09 +00:00
dist = vm_dist_to_plane ( & start_pos , & s - > normals [ 0 ] , & Vertices [ vertnum ] ) ;
vm_vec_scale_add ( & obj - > pos , & start_pos , & s - > normals [ 0 ] , obj - > size - dist ) ;
update_object_seg ( obj ) ;
}
}
}
//--WE ALWYS WANT THIS IN, MATT AND MIKE DECISION ON 12/10/94, TWO MONTHS AFTER FINAL #ifndef NDEBUG
//if end point not in segment, move object to last pos, or segment center
if ( get_seg_masks ( & obj - > pos , obj - > segnum , 0 , __FILE__ , __LINE__ ) . centermask ! = 0 )
{
2013-12-26 22:21:16 +00:00
if ( find_object_seg ( obj ) = = segment_none ) {
2013-12-29 04:28:07 +00:00
segnum_t n ;
2006-03-20 17:12:09 +00:00
//Int3();
2013-12-26 22:21:16 +00:00
if ( obj - > type = = OBJ_PLAYER & & ( n = find_point_seg ( & obj - > last_pos , obj - > segnum ) ) ! = segment_none ) {
2006-03-20 17:12:09 +00:00
obj - > pos = obj - > last_pos ;
2014-01-11 22:37:36 +00:00
obj_relink ( obj , n ) ;
2006-03-20 17:12:09 +00:00
}
else {
compute_segment_center ( & obj - > pos , & Segments [ obj - > segnum ] ) ;
2014-01-11 22:37:36 +00:00
obj - > pos . x + = obj ;
2006-03-20 17:12:09 +00:00
}
if ( obj - > type = = OBJ_WEAPON )
obj - > flags | = OF_SHOULD_BE_DEAD ;
}
}
//--WE ALWYS WANT THIS IN, MATT AND MIKE DECISION ON 12/10/94, TWO MONTHS AFTER FINAL #endif
}
//Applies an instantaneous force on an object, resulting in an instantaneous
//change in velocity.
void phys_apply_force ( object * obj , vms_vector * force_vec )
{
2013-03-03 01:03:33 +00:00
if ( obj - > movement_type ! = MT_PHYSICS )
return ;
2006-03-20 17:12:09 +00:00
// Put in by MK on 2/13/96 for force getting applied to Omega blobs, which have 0 mass,
// in collision with crazy reactor robot thing on d2levf-s.
if ( obj - > mtype . phys_info . mass = = 0 )
return ;
//Add in acceleration due to force
vm_vec_scale_add2 ( & obj - > mtype . phys_info . velocity , force_vec , fixdiv ( f1_0 , obj - > mtype . phys_info . mass ) ) ;
}
// ----------------------------------------------------------------
// Do *dest = *delta unless:
// *delta is pretty small
// and they are of different signs.
2013-10-27 22:00:14 +00:00
static void physics_set_rotvel_and_saturate ( fix * dest , fix delta )
2006-03-20 17:12:09 +00:00
{
if ( ( delta ^ * dest ) < 0 ) {
if ( abs ( delta ) < F1_0 / 8 ) {
* dest = delta / 4 ;
} else
* dest = delta ;
} else {
* dest = delta ;
}
}
// ------------------------------------------------------------------------------------------------------
// Note: This is the old ai_turn_towards_vector code.
// phys_apply_rot used to call ai_turn_towards_vector until I fixed it, which broke phys_apply_rot.
void physics_turn_towards_vector ( vms_vector * goal_vector , object * obj , fix rate )
{
vms_angvec dest_angles , cur_angles ;
fix delta_p , delta_h ;
vms_vector * rotvel_ptr = & obj - > mtype . phys_info . rotvel ;
// Make this object turn towards the goal_vector. Changes orientation, doesn't change direction of movement.
// If no one moves, will be facing goal_vector in 1 second.
// Detect null vector.
if ( ( goal_vector - > x = = 0 ) & & ( goal_vector - > y = = 0 ) & & ( goal_vector - > z = = 0 ) )
return ;
// Make morph objects turn more slowly.
if ( obj - > control_type = = CT_MORPH )
rate * = 2 ;
vm_extract_angles_vector ( & dest_angles , goal_vector ) ;
vm_extract_angles_vector ( & cur_angles , & obj - > orient . fvec ) ;
delta_p = ( dest_angles . p - cur_angles . p ) ;
delta_h = ( dest_angles . h - cur_angles . h ) ;
if ( delta_p > F1_0 / 2 ) delta_p = dest_angles . p - cur_angles . p - F1_0 ;
if ( delta_p < - F1_0 / 2 ) delta_p = dest_angles . p - cur_angles . p + F1_0 ;
if ( delta_h > F1_0 / 2 ) delta_h = dest_angles . h - cur_angles . h - F1_0 ;
if ( delta_h < - F1_0 / 2 ) delta_h = dest_angles . h - cur_angles . h + F1_0 ;
delta_p = fixdiv ( delta_p , rate ) ;
delta_h = fixdiv ( delta_h , rate ) ;
if ( abs ( delta_p ) < F1_0 / 16 ) delta_p * = 4 ;
if ( abs ( delta_h ) < F1_0 / 16 ) delta_h * = 4 ;
2006-12-19 02:25:50 +00:00
# ifdef WORDS_NEED_ALIGNMENT
if ( ( delta_p ^ rotvel_ptr - > x ) < 0 ) {
if ( abs ( delta_p ) < F1_0 / 8 )
rotvel_ptr - > x = delta_p / 4 ;
else
rotvel_ptr - > x = delta_p ;
} else
rotvel_ptr - > x = delta_p ;
if ( ( delta_h ^ rotvel_ptr - > y ) < 0 ) {
if ( abs ( delta_h ) < F1_0 / 8 )
rotvel_ptr - > y = delta_h / 4 ;
else
rotvel_ptr - > y = delta_h ;
} else
rotvel_ptr - > y = delta_h ;
# else
physics_set_rotvel_and_saturate ( & rotvel_ptr - > x , delta_p ) ;
2006-03-20 17:12:09 +00:00
physics_set_rotvel_and_saturate ( & rotvel_ptr - > y , delta_h ) ;
2006-12-19 02:25:50 +00:00
# endif
2006-03-20 17:12:09 +00:00
rotvel_ptr - > z = 0 ;
}
// -----------------------------------------------------------------------------
// Applies an instantaneous whack on an object, resulting in an instantaneous
// change in orientation.
void phys_apply_rot ( object * obj , vms_vector * force_vec )
{
fix rate , vecmag ;
if ( obj - > movement_type ! = MT_PHYSICS )
return ;
vecmag = vm_vec_mag ( force_vec ) / 8 ;
if ( vecmag < F1_0 / 256 )
rate = 4 * F1_0 ;
else if ( vecmag < obj - > mtype . phys_info . mass > > 14 )
rate = 4 * F1_0 ;
else {
rate = fixdiv ( obj - > mtype . phys_info . mass , vecmag ) ;
if ( obj - > type = = OBJ_ROBOT ) {
if ( rate < F1_0 / 4 )
rate = F1_0 / 4 ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
obj - > ctype . ai_info . SKIP_AI_COUNT = 2 ;
# elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
// Changed by mk, 10/24/95, claw guys should not slow down when attacking!
2013-10-07 23:52:33 +00:00
if ( ! Robot_info [ get_robot_id ( obj ) ] . thief & & ! Robot_info [ get_robot_id ( obj ) ] . attack_type ) {
2006-03-20 17:12:09 +00:00
if ( obj - > ctype . ai_info . SKIP_AI_COUNT * FrameTime < 3 * F1_0 / 4 ) {
fix tval = fixdiv ( F1_0 , 8 * FrameTime ) ;
int addval ;
addval = f2i ( tval ) ;
if ( ( d_rand ( ) * 2 ) < ( tval & 0xffff ) )
addval + + ;
obj - > ctype . ai_info . SKIP_AI_COUNT + = addval ;
}
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
} else {
if ( rate < F1_0 / 2 )
rate = F1_0 / 2 ;
}
}
// Turn amount inversely proportional to mass. Third parameter is seconds to do 360 turn.
physics_turn_towards_vector ( force_vec , obj , rate ) ;
}
//this routine will set the thrust for an object to a value that will
//(hopefully) maintain the object's current velocity
void set_thrust_from_velocity ( object * obj )
{
fix k ;
Assert ( obj - > movement_type = = MT_PHYSICS ) ;
k = fixmuldiv ( obj - > mtype . phys_info . mass , obj - > mtype . phys_info . drag , ( f1_0 - obj - > mtype . phys_info . drag ) ) ;
vm_vec_copy_scale ( & obj - > mtype . phys_info . thrust , & obj - > mtype . phys_info . velocity , k ) ;
}