2006-02-24 04:48:15 +00:00
/*******************************
* B_spawn . c *
* Description : *
* various procedures that the *
* bot need to work *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-04-07 07:06:07 +00:00
# include <stdlib.h>
2006-02-24 04:48:15 +00:00
# include "doomtype.h"
# include "doomdef.h"
# include "doomstat.h"
# include "p_local.h"
2016-02-15 01:14:34 +00:00
# include "p_maputl.h"
2006-02-24 04:48:15 +00:00
# include "b_bot.h"
# include "g_game.h"
# include "m_random.h"
# include "r_sky.h"
# include "st_stuff.h"
# include "stats.h"
# include "i_system.h"
# include "s_sound.h"
2008-09-14 23:54:38 +00:00
# include "d_event.h"
2016-02-15 01:14:34 +00:00
# include "d_player.h"
# include "p_spec.h"
2016-02-15 12:40:31 +00:00
# include "p_checkposition.h"
2006-02-24 04:48:15 +00:00
static FRandom pr_botdofire ( " BotDoFire " ) ;
2008-04-09 18:35:21 +00:00
2014-11-29 17:03:58 +00:00
//Checks TRUE reachability from bot to a looker.
bool DBot : : Reachable ( AActor * rtarget )
2006-02-24 04:48:15 +00:00
{
2014-11-29 17:03:58 +00:00
if ( player - > mo = = rtarget )
2008-04-09 18:35:21 +00:00
return false ;
2006-02-24 04:48:15 +00:00
2016-01-17 12:48:16 +00:00
if ( ( rtarget - > Sector - > ceilingplane . ZatPoint ( rtarget ) -
rtarget - > Sector - > floorplane . ZatPoint ( rtarget ) )
2014-11-29 17:03:58 +00:00
< player - > mo - > height ) //Where rtarget is, player->mo can't be.
2008-04-09 18:35:21 +00:00
return false ;
2006-02-24 04:48:15 +00:00
2014-11-29 17:03:58 +00:00
sector_t * last_s = player - > mo - > Sector ;
2016-01-17 12:48:16 +00:00
fixed_t last_z = last_s - > floorplane . ZatPoint ( player - > mo ) ;
2016-01-10 16:52:41 +00:00
fixed_t estimated_dist = player - > mo - > AproxDistance ( rtarget ) ;
2008-04-09 18:35:21 +00:00
bool reachable = true ;
2006-02-24 04:48:15 +00:00
2016-01-17 12:48:16 +00:00
FPathTraverse it ( player - > mo - > X ( ) + player - > mo - > velx , player - > mo - > Y ( ) + player - > mo - > vely , rtarget - > X ( ) , rtarget - > Y ( ) , PT_ADDLINES | PT_ADDTHINGS ) ;
2008-04-09 18:35:21 +00:00
intercept_t * in ;
while ( ( in = it . Next ( ) ) )
2006-02-24 04:48:15 +00:00
{
2008-04-09 18:35:21 +00:00
fixed_t hitx , hity ;
fixed_t frac ;
line_t * line ;
AActor * thing ;
fixed_t dist ;
sector_t * s ;
2006-02-24 04:48:15 +00:00
2008-04-09 18:35:21 +00:00
frac = in - > frac - FixedDiv ( 4 * FRACUNIT , MAX_TRAVERSE_DIST ) ;
dist = FixedMul ( frac , MAX_TRAVERSE_DIST ) ;
2014-11-29 17:03:58 +00:00
hitx = it . Trace ( ) . x + FixedMul ( player - > mo - > velx , frac ) ;
hity = it . Trace ( ) . y + FixedMul ( player - > mo - > vely , frac ) ;
2008-04-09 18:35:21 +00:00
if ( in - > isaline )
2006-02-24 04:48:15 +00:00
{
2008-04-09 18:35:21 +00:00
line = in - > d . line ;
if ( ! ( line - > flags & ML_TWOSIDED ) | | ( line - > flags & ( ML_BLOCKING | ML_BLOCKEVERYTHING | ML_BLOCK_PLAYERS ) ) )
2006-02-24 04:48:15 +00:00
{
2008-04-09 18:35:21 +00:00
return false ; //Cannot continue.
2006-02-24 04:48:15 +00:00
}
else
{
2008-04-09 18:35:21 +00:00
//Determine if going to use backsector/frontsector.
s = ( line - > backsector = = last_s ) ? line - > frontsector : line - > backsector ;
fixed_t ceilingheight = s - > ceilingplane . ZatPoint ( hitx , hity ) ;
fixed_t floorheight = s - > floorplane . ZatPoint ( hitx , hity ) ;
if ( ! bglobal . IsDangerous ( s ) & & //Any nukage/lava?
( floorheight < = ( last_z + MAXMOVEHEIGHT )
& & ( ( ceilingheight = = floorheight & & line - > special )
2014-11-29 17:03:58 +00:00
| | ( ceilingheight - floorheight ) > = player - > mo - > height ) ) ) //Does it fit?
2008-04-09 18:35:21 +00:00
{
last_z = floorheight ;
last_s = s ;
continue ;
}
else
{
return false ;
}
2006-02-24 04:48:15 +00:00
}
}
2008-04-09 18:35:21 +00:00
if ( dist > estimated_dist )
{
return true ;
}
2006-02-24 04:48:15 +00:00
2008-04-09 18:35:21 +00:00
thing = in - > d . thing ;
2014-11-29 17:03:58 +00:00
if ( thing = = player - > mo ) //Can't reach self in this case.
2008-04-09 18:35:21 +00:00
continue ;
2016-01-17 12:48:16 +00:00
if ( thing = = rtarget & & ( rtarget - > Sector - > floorplane . ZatPoint ( rtarget ) < = ( last_z + MAXMOVEHEIGHT ) ) )
2008-04-09 18:35:21 +00:00
{
return true ;
}
2006-02-24 04:48:15 +00:00
2008-04-09 18:35:21 +00:00
reachable = false ;
}
2006-02-24 04:48:15 +00:00
return reachable ;
}
//doesnt check LOS, checks visibility with a set view angle.
//B_Checksight checks LOS (straight line)
//----------------------------------------------------------------------
//Check if mo1 has free line to mo2
//and if mo2 is within mo1 viewangle (vangle) given with normal degrees.
//if these conditions are true, the function returns true.
//GOOD TO KNOW is that the player's view angle
//in doom is 90 degrees infront.
2014-11-29 17:03:58 +00:00
bool DBot : : Check_LOS ( AActor * to , angle_t vangle )
2006-02-24 04:48:15 +00:00
{
2014-11-29 17:03:58 +00:00
if ( ! P_CheckSight ( player - > mo , to , SF_SEEPASTBLOCKEVERYTHING ) )
2006-02-24 04:48:15 +00:00
return false ; // out of sight
if ( vangle = = ANGLE_MAX )
return true ;
if ( vangle = = 0 )
return false ; //Looker seems to be blind.
2016-01-10 19:46:26 +00:00
return absangle ( player - > mo - > AngleTo ( to ) - player - > mo - > angle ) < = vangle / 2 ;
2006-02-24 04:48:15 +00:00
}
//-------------------------------------
//Bot_Dofire()
//-------------------------------------
//The bot will check if it's time to fire
//and do so if that is the case.
2014-11-29 17:03:58 +00:00
void DBot : : Dofire ( ticcmd_t * cmd )
2006-02-24 04:48:15 +00:00
{
bool no_fire ; //used to prevent bot from pumping rockets into nearby walls.
int aiming_penalty = 0 ; //For shooting at shading target, if screen is red, MAKEME: When screen red.
int aiming_value ; //The final aiming value.
fixed_t dist ;
angle_t an ;
int m ;
if ( ! enemy | | ! ( enemy - > flags & MF_SHOOTABLE ) | | enemy - > health < = 0 )
return ;
2014-11-29 17:03:58 +00:00
if ( player - > ReadyWeapon = = NULL )
2006-02-24 04:48:15 +00:00
return ;
2014-11-29 17:03:58 +00:00
if ( player - > damagecount > skill . isp )
2006-02-24 04:48:15 +00:00
{
2014-11-29 17:03:58 +00:00
first_shot = true ;
2006-02-24 04:48:15 +00:00
return ;
}
//Reaction skill thing.
2014-11-29 17:03:58 +00:00
if ( first_shot & &
! ( player - > ReadyWeapon - > WeaponFlags & WIF_BOT_REACTION_SKILL_THING ) )
2006-02-24 04:48:15 +00:00
{
2014-11-29 17:03:58 +00:00
t_react = ( 100 - skill . reaction + 1 ) / ( ( pr_botdofire ( ) % 3 ) + 3 ) ;
2006-02-24 04:48:15 +00:00
}
2014-11-29 17:03:58 +00:00
first_shot = false ;
if ( t_react )
2006-02-24 04:48:15 +00:00
return ;
//MAKEME: Decrease the rocket suicides even more.
no_fire = true ;
//Distance to enemy.
2016-01-10 16:52:41 +00:00
dist = player - > mo - > AproxDistance ( enemy , player - > mo - > velx - enemy - > velx , player - > mo - > vely - enemy - > vely ) ;
2006-02-24 04:48:15 +00:00
//FIRE EACH TYPE OF WEAPON DIFFERENT: Here should all the different weapons go.
2014-11-29 17:03:58 +00:00
if ( player - > ReadyWeapon - > WeaponFlags & WIF_MELEEWEAPON )
2006-02-24 04:48:15 +00:00
{
2014-11-29 17:03:58 +00:00
if ( ( player - > ReadyWeapon - > ProjectileType ! = NULL ) )
2006-02-24 04:48:15 +00:00
{
2014-11-29 17:03:58 +00:00
if ( player - > ReadyWeapon - > CheckAmmo ( AWeapon : : PrimaryFire , false , true ) )
2006-02-24 04:48:15 +00:00
{
// This weapon can fire a projectile and has enough ammo to do so
goto shootmissile ;
}
2014-11-29 17:03:58 +00:00
else if ( ! ( player - > ReadyWeapon - > WeaponFlags & WIF_AMMO_OPTIONAL ) )
2006-02-24 04:48:15 +00:00
{
// Ammo is required, so don't shoot. This is for weapons that shoot
// missiles that die at close range, such as the powered-up Phoneix Rod.
return ;
}
}
else
{
//*4 is for atmosphere, the chainsaws sounding and all..
no_fire = ( dist > ( MELEERANGE * 4 ) ) ;
}
}
2014-11-29 17:03:58 +00:00
else if ( player - > ReadyWeapon - > WeaponFlags & WIF_BOT_BFG )
2006-02-24 04:48:15 +00:00
{
//MAKEME: This should be smarter.
2014-11-29 17:03:58 +00:00
if ( ( pr_botdofire ( ) % 200 ) < = skill . reaction )
if ( Check_LOS ( enemy , SHOOTFOV ) )
2006-02-24 04:48:15 +00:00
no_fire = false ;
}
2014-11-29 17:03:58 +00:00
else if ( player - > ReadyWeapon - > ProjectileType ! = NULL )
2006-02-24 04:48:15 +00:00
{
2014-11-29 17:03:58 +00:00
if ( player - > ReadyWeapon - > WeaponFlags & WIF_BOT_EXPLOSIVE )
2006-02-24 04:48:15 +00:00
{
//Special rules for RL
2014-11-29 17:03:58 +00:00
an = FireRox ( enemy , cmd ) ;
2006-02-24 04:48:15 +00:00
if ( an )
{
2014-11-29 17:03:58 +00:00
angle = an ;
2006-02-24 04:48:15 +00:00
//have to be somewhat precise. to avoid suicide.
2015-03-08 22:21:15 +00:00
if ( absangle ( angle - player - > mo - > angle ) < 12 * ANGLE_1 )
2006-02-24 04:48:15 +00:00
{
2014-11-29 17:03:58 +00:00
t_rocket = 9 ;
2006-02-24 04:48:15 +00:00
no_fire = false ;
}
}
}
// prediction aiming
shootmissile :
2016-01-10 16:52:41 +00:00
dist = player - > mo - > AproxDistance ( enemy ) ;
2014-11-29 17:03:58 +00:00
m = dist / GetDefaultByType ( player - > ReadyWeapon - > ProjectileType ) - > Speed ;
2016-01-17 12:48:16 +00:00
bglobal . SetBodyAt ( enemy - > X ( ) + enemy - > velx * m * 2 , enemy - > Y ( ) + enemy - > vely * m * 2 , enemy - > Z ( ) , 1 ) ;
2016-01-10 19:46:26 +00:00
angle = player - > mo - > AngleTo ( bglobal . body1 ) ;
2014-11-29 17:03:58 +00:00
if ( Check_LOS ( enemy , SHOOTFOV ) )
2006-02-24 04:48:15 +00:00
no_fire = false ;
}
else
{
//Other weapons, mostly instant hit stuff.
2016-01-10 19:46:26 +00:00
angle = player - > mo - > AngleTo ( enemy ) ;
2006-02-24 04:48:15 +00:00
aiming_penalty = 0 ;
if ( enemy - > flags & MF_SHADOW )
aiming_penalty + = ( pr_botdofire ( ) % 25 ) + 10 ;
2014-11-29 17:03:58 +00:00
if ( enemy - > Sector - > lightlevel < WHATS_DARK /* && !(player->powers & PW_INFRARED)*/ )
2006-02-24 04:48:15 +00:00
aiming_penalty + = pr_botdofire ( ) % 40 ; //Dark
2014-11-29 17:03:58 +00:00
if ( player - > damagecount )
aiming_penalty + = player - > damagecount ; //Blood in face makes it hard to aim
aiming_value = skill . aiming - aiming_penalty ;
2006-02-24 04:48:15 +00:00
if ( aiming_value < = 0 )
aiming_value = 1 ;
m = ( ( SHOOTFOV / 2 ) - ( aiming_value * SHOOTFOV / 200 ) ) ; //Higher skill is more accurate
if ( m < = 0 )
m = 1 ; //Prevents lock.
if ( m )
{
2014-11-29 17:03:58 +00:00
if ( increase )
angle + = m ;
2006-02-24 04:48:15 +00:00
else
2014-11-29 17:03:58 +00:00
angle - = m ;
2006-02-24 04:48:15 +00:00
}
2015-03-08 22:21:15 +00:00
if ( absangle ( angle - player - > mo - > angle ) < 4 * ANGLE_1 )
2006-02-24 04:48:15 +00:00
{
2014-11-29 17:03:58 +00:00
increase = ! increase ;
2006-02-24 04:48:15 +00:00
}
2014-11-29 17:03:58 +00:00
if ( Check_LOS ( enemy , ( SHOOTFOV / 2 ) ) )
2006-02-24 04:48:15 +00:00
no_fire = false ;
}
if ( ! no_fire ) //If going to fire weapon
{
cmd - > ucmd . buttons | = BT_ATTACK ;
}
//Prevents bot from jerking, when firing automatic things with low skill.
}
2014-10-21 18:31:11 +00:00
bool FCajunMaster : : IsLeader ( player_t * player )
{
2014-11-15 08:58:29 +00:00
for ( int count = 0 ; count < MAXPLAYERS ; count + + )
2014-10-21 18:31:11 +00:00
{
2014-11-15 08:58:29 +00:00
if ( players [ count ] . Bot ! = NULL
& & players [ count ] . Bot - > mate = = player - > mo )
2014-10-21 18:31:11 +00:00
{
return true ;
}
}
return false ;
}
2006-02-24 04:48:15 +00:00
//This function is called every
//tick (for each bot) to set
//the mate (teammate coop mate).
2014-11-29 17:03:58 +00:00
AActor * DBot : : Choose_Mate ( )
2006-02-24 04:48:15 +00:00
{
int count ;
fixed_t closest_dist , test ;
AActor * target ;
AActor * observer ;
//is mate alive?
2014-11-29 17:03:58 +00:00
if ( mate )
2006-02-24 04:48:15 +00:00
{
2014-11-29 17:03:58 +00:00
if ( mate - > health < = 0 )
mate = NULL ;
2006-02-24 04:48:15 +00:00
else
2014-11-29 17:03:58 +00:00
last_mate = mate ;
2006-02-24 04:48:15 +00:00
}
2014-11-29 17:03:58 +00:00
if ( mate ) //Still is..
return mate ;
2006-02-24 04:48:15 +00:00
//Check old_mates status.
2014-11-29 17:03:58 +00:00
if ( last_mate )
if ( last_mate - > health < = 0 )
last_mate = NULL ;
2006-02-24 04:48:15 +00:00
target = NULL ;
closest_dist = FIXED_MAX ;
if ( bot_observer )
observer = players [ consoleplayer ] . mo ;
else
observer = NULL ;
//Check for player friends
for ( count = 0 ; count < MAXPLAYERS ; count + + )
{
player_t * client = & players [ count ] ;
if ( playeringame [ count ]
& & client - > mo
2014-11-29 17:03:58 +00:00
& & player - > mo ! = client - > mo
& & ( player - > mo - > IsTeammate ( client - > mo ) | | ! deathmatch )
2006-02-24 04:48:15 +00:00
& & client - > mo - > health > 0
& & client - > mo ! = observer
2014-11-29 17:03:58 +00:00
& & ( ( player - > mo - > health / 2 ) < = client - > mo - > health | | ! deathmatch )
& & ! bglobal . IsLeader ( client ) ) //taken?
2006-02-24 04:48:15 +00:00
{
2014-11-29 17:03:58 +00:00
if ( P_CheckSight ( player - > mo , client - > mo , SF_IGNOREVISIBILITY ) )
2006-02-24 04:48:15 +00:00
{
2016-01-10 16:52:41 +00:00
test = client - > mo - > AproxDistance ( player - > mo ) ;
2006-02-24 04:48:15 +00:00
if ( test < closest_dist )
{
closest_dist = test ;
target = client - > mo ;
}
}
}
}
/*
//Make a introducing to mate.
2014-11-29 17:03:58 +00:00
if ( target & & target ! = last_mate )
2006-02-24 04:48:15 +00:00
{
2008-03-28 00:38:17 +00:00
if ( ( P_Random ( ) % ( 200 * bglobal . botnum ) ) < 3 )
2006-02-24 04:48:15 +00:00
{
2014-11-29 17:03:58 +00:00
chat = c_teamup ;
2006-02-24 04:48:15 +00:00
if ( target - > bot )
2014-11-29 17:03:58 +00:00
strcpy ( c_target , botsingame [ target - > bot_id ] ) ;
2006-02-24 04:48:15 +00:00
else if ( target - > player )
2014-11-29 17:03:58 +00:00
strcpy ( c_target , player_names [ target - > play_id ] ) ;
2006-02-24 04:48:15 +00:00
}
}
*/
return target ;
}
//MAKEME: Make this a smart decision
2014-11-29 17:03:58 +00:00
AActor * DBot : : Find_enemy ( )
2006-02-24 04:48:15 +00:00
{
int count ;
fixed_t closest_dist , temp ; //To target.
AActor * target ;
angle_t vangle ;
AActor * observer ;
if ( ! deathmatch )
{ // [RH] Take advantage of the Heretic/Hexen code to be a little smarter
2014-11-29 17:03:58 +00:00
return P_RoughMonsterSearch ( player - > mo , 20 ) ;
2006-02-24 04:48:15 +00:00
}
//Note: It's hard to ambush a bot who is not alone
2014-11-29 17:03:58 +00:00
if ( allround | | mate )
2006-02-24 04:48:15 +00:00
vangle = ANGLE_MAX ;
else
vangle = ENEMY_SCAN_FOV ;
2014-11-29 17:03:58 +00:00
allround = false ;
2006-02-24 04:48:15 +00:00
target = NULL ;
closest_dist = FIXED_MAX ;
if ( bot_observer )
observer = players [ consoleplayer ] . mo ;
else
observer = NULL ;
for ( count = 0 ; count < MAXPLAYERS ; count + + )
{
player_t * client = & players [ count ] ;
if ( playeringame [ count ]
2014-11-29 17:03:58 +00:00
& & ! player - > mo - > IsTeammate ( client - > mo )
2006-02-24 04:48:15 +00:00
& & client - > mo ! = observer
& & client - > mo - > health > 0
2014-11-29 17:03:58 +00:00
& & player - > mo ! = client - > mo )
2006-02-24 04:48:15 +00:00
{
2014-11-29 17:03:58 +00:00
if ( Check_LOS ( client - > mo , vangle ) ) //Here's a strange one, when bot is standing still, the P_CheckSight within Check_LOS almost always returns false. tought it should be the same checksight as below but.. (below works) something must be fuckin wierd screded up.
//if(P_CheckSight(player->mo, players[count].mo))
2006-02-24 04:48:15 +00:00
{
2016-01-10 16:52:41 +00:00
temp = client - > mo - > AproxDistance ( player - > mo ) ;
2006-02-24 04:48:15 +00:00
//Too dark?
if ( temp > DARK_DIST & &
2007-05-01 15:09:44 +00:00
client - > mo - > Sector - > lightlevel < WHATS_DARK /*&&
2014-11-29 17:03:58 +00:00
player - > Powers & PW_INFRARED */ )
2006-02-24 04:48:15 +00:00
continue ;
if ( temp < closest_dist )
{
closest_dist = temp ;
target = client - > mo ;
}
}
}
}
return target ;
}
//Creates a temporary mobj (invisible) at the given location.
2008-03-28 00:38:17 +00:00
void FCajunMaster : : SetBodyAt ( fixed_t x , fixed_t y , fixed_t z , int hostnum )
2006-02-24 04:48:15 +00:00
{
if ( hostnum = = 1 )
{
if ( body1 )
2008-03-12 02:56:11 +00:00
{
2016-01-17 17:36:14 +00:00
body1 - > SetOrigin ( x , y , z , false ) ;
2008-03-12 02:56:11 +00:00
}
2006-02-24 04:48:15 +00:00
else
2008-03-12 02:56:11 +00:00
{
2006-12-23 12:12:06 +00:00
body1 = Spawn ( " CajunBodyNode " , x , y , z , NO_REPLACE ) ;
2008-03-12 02:56:11 +00:00
}
2006-02-24 04:48:15 +00:00
}
else if ( hostnum = = 2 )
{
if ( body2 )
2008-03-12 02:56:11 +00:00
{
2016-01-17 17:36:14 +00:00
body2 - > SetOrigin ( x , y , z , false ) ;
2008-03-12 02:56:11 +00:00
}
2006-02-24 04:48:15 +00:00
else
2008-03-12 02:56:11 +00:00
{
2006-12-23 12:12:06 +00:00
body2 = Spawn ( " CajunBodyNode " , x , y , z , NO_REPLACE ) ;
2008-03-12 02:56:11 +00:00
}
2006-02-24 04:48:15 +00:00
}
}
//------------------------------------------
// FireRox()
//
//Returns NULL if shouldn't fire
//else an angle (in degrees) are given
//This function assumes actor->player->angle
//has been set an is the main aiming angle.
//Emulates missile travel. Returns distance travelled.
2008-03-28 00:38:17 +00:00
fixed_t FCajunMaster : : FakeFire ( AActor * source , AActor * dest , ticcmd_t * cmd )
2006-02-24 04:48:15 +00:00
{
2016-01-18 20:01:52 +00:00
AActor * th = Spawn ( " CajunTrace " , source - > PosPlusZ ( 4 * 8 * FRACUNIT ) , NO_REPLACE ) ;
2006-02-24 04:48:15 +00:00
th - > target = source ; // where it came from
float speed = ( float ) th - > Speed ;
2016-01-23 19:44:33 +00:00
fixedvec3 fixvel = source - > Vec3To ( dest ) ;
TVector3 < double > velocity ( fixvel . x , fixvel . y , fixvel . z ) ;
2007-01-19 02:00:39 +00:00
velocity . MakeUnit ( ) ;
2009-06-30 20:57:51 +00:00
th - > velx = FLOAT2FIXED ( velocity [ 0 ] * speed ) ;
th - > vely = FLOAT2FIXED ( velocity [ 1 ] * speed ) ;
th - > velz = FLOAT2FIXED ( velocity [ 2 ] * speed ) ;
2006-02-24 04:48:15 +00:00
fixed_t dist = 0 ;
while ( dist < SAFE_SELF_MISDIST )
{
dist + = th - > Speed ;
2016-01-17 17:36:14 +00:00
th - > Move ( th - > velx , th - > vely , th - > velz ) ;
if ( ! CleanAhead ( th , th - > X ( ) , th - > Y ( ) , cmd ) )
2006-02-24 04:48:15 +00:00
break ;
}
th - > Destroy ( ) ;
return dist ;
}
2014-11-29 17:03:58 +00:00
angle_t DBot : : FireRox ( AActor * enemy , ticcmd_t * cmd )
2006-02-24 04:48:15 +00:00
{
fixed_t dist ;
angle_t ang ;
AActor * actor ;
int m ;
2016-01-17 12:48:16 +00:00
bglobal . SetBodyAt ( player - > mo - > X ( ) + FixedMul ( player - > mo - > velx , 5 * FRACUNIT ) ,
player - > mo - > Y ( ) + FixedMul ( player - > mo - > vely , 5 * FRACUNIT ) ,
player - > mo - > Z ( ) + ( player - > mo - > height / 2 ) , 2 ) ;
2006-02-24 04:48:15 +00:00
2008-03-28 00:38:17 +00:00
actor = bglobal . body2 ;
2006-02-24 04:48:15 +00:00
2016-01-10 16:52:41 +00:00
dist = actor - > AproxDistance ( enemy ) ;
2006-02-24 04:48:15 +00:00
if ( dist < SAFE_SELF_MISDIST )
return 0 ;
//Predict.
2007-04-28 09:06:32 +00:00
m = ( ( ( dist + 1 ) / FRACUNIT ) / GetDefaultByName ( " Rocket " ) - > Speed ) ;
2006-02-24 04:48:15 +00:00
2016-01-17 12:48:16 +00:00
bglobal . SetBodyAt ( enemy - > X ( ) + FixedMul ( enemy - > velx , ( m + 2 * FRACUNIT ) ) ,
enemy - > Y ( ) + FixedMul ( enemy - > vely , ( m + 2 * FRACUNIT ) ) , ONFLOORZ , 1 ) ;
2015-02-07 15:35:23 +00:00
2006-02-24 04:48:15 +00:00
//try the predicted location
2010-03-27 07:42:31 +00:00
if ( P_CheckSight ( actor , bglobal . body1 , SF_IGNOREVISIBILITY ) ) //See the predicted location, so give a test missile
2006-02-24 04:48:15 +00:00
{
2008-04-08 20:52:49 +00:00
FCheckPosition tm ;
2016-01-17 12:48:16 +00:00
if ( bglobal . SafeCheckPosition ( player - > mo , actor - > X ( ) , actor - > Y ( ) , tm ) )
2006-02-24 04:48:15 +00:00
{
2014-11-29 17:03:58 +00:00
if ( bglobal . FakeFire ( actor , bglobal . body1 , cmd ) > = SAFE_SELF_MISDIST )
2006-02-24 04:48:15 +00:00
{
2016-01-10 19:46:26 +00:00
ang = actor - > AngleTo ( bglobal . body1 ) ;
2006-02-24 04:48:15 +00:00
return ang ;
}
}
}
//Try fire straight.
if ( P_CheckSight ( actor , enemy , 0 ) )
{
2014-11-29 17:03:58 +00:00
if ( bglobal . FakeFire ( player - > mo , enemy , cmd ) > = SAFE_SELF_MISDIST )
2006-02-24 04:48:15 +00:00
{
2016-01-10 19:46:26 +00:00
ang = player - > mo - > AngleTo ( enemy ) ;
2006-02-24 04:48:15 +00:00
return ang ;
}
}
return 0 ;
}
// [RH] We absolutely do not want to pick things up here. The bot code is
// executed apart from all the other simulation code, so we don't want it
// creating side-effects during gameplay.
2008-04-08 20:52:49 +00:00
bool FCajunMaster : : SafeCheckPosition ( AActor * actor , fixed_t x , fixed_t y , FCheckPosition & tm )
2006-02-24 04:48:15 +00:00
{
2015-04-04 16:40:43 +00:00
ActorFlags savedFlags = actor - > flags ;
2006-02-24 04:48:15 +00:00
actor - > flags & = ~ MF_PICKUP ;
2008-04-08 20:52:49 +00:00
bool res = P_CheckPosition ( actor , x , y , tm ) ;
2006-02-24 04:48:15 +00:00
actor - > flags = savedFlags ;
return res ;
}
2014-11-14 16:54:56 +00:00
void FCajunMaster : : StartTravel ( )
{
2014-11-15 08:58:29 +00:00
for ( int i = 0 ; i < MAXPLAYERS ; + + i )
2014-11-14 16:54:56 +00:00
{
2014-11-15 08:58:29 +00:00
if ( players [ i ] . Bot ! = NULL )
{
players [ i ] . Bot - > ChangeStatNum ( STAT_TRAVELLING ) ;
}
2014-11-14 16:54:56 +00:00
}
}
void FCajunMaster : : FinishTravel ( )
{
2014-11-15 08:58:29 +00:00
for ( int i = 0 ; i < MAXPLAYERS ; + + i )
2014-11-14 16:54:56 +00:00
{
2014-11-15 08:58:29 +00:00
if ( players [ i ] . Bot ! = NULL )
{
players [ i ] . Bot - > ChangeStatNum ( STAT_BOT ) ;
}
2014-11-14 16:54:56 +00:00
}
}