fixed move angles not updated when not checking terrain
fixed reporting-in spam fixed bot-s won't fight in jason mode added yb_shoots_thru_walls 2 to use old method for checking shootable wall
This commit is contained in:
parent
4962302e6c
commit
eb13736a00
7 changed files with 328 additions and 294 deletions
|
|
@ -1139,8 +1139,9 @@ void Bot::CheckMessageQueue (void)
|
|||
else
|
||||
InstantChatterMessage (Chatter_HearSomething);
|
||||
}
|
||||
else
|
||||
else if (g_randGen.Long (0, 100) < 40)
|
||||
InstantChatterMessage (Chatter_ReportingIn);
|
||||
|
||||
break;
|
||||
|
||||
case TASK_MOVETOPOSITION:
|
||||
|
|
@ -1828,7 +1829,7 @@ void Bot::SetConditions (void)
|
|||
|
||||
if ((pev->origin - m_lastEnemyOrigin).GetLength () < 1600.0 && (tr.flFraction >= 0.2 || tr.pHit != g_worldEdict))
|
||||
{
|
||||
m_aimFlags |= AIM_PREDICT_ENEMY;
|
||||
m_aimFlags |= AIM_PREDICT_PATH;
|
||||
|
||||
if (EntityIsVisible (m_lastEnemyOrigin))
|
||||
m_aimFlags |= AIM_LAST_ENEMY;
|
||||
|
|
@ -2025,7 +2026,7 @@ void Bot::SetConditions (void)
|
|||
float desireLevel = 0.0;
|
||||
|
||||
// calculate desire to attack
|
||||
if ((m_states & STATE_SEEING_ENEMY) && ReactOnEnemy () && g_taskFilters[TASK_MOVETOPOSITION].desire < TASKPRI_HIDE)
|
||||
if ((m_states & STATE_SEEING_ENEMY) && ReactOnEnemy ())
|
||||
g_taskFilters[TASK_ATTACK].desire = TASKPRI_ATTACK;
|
||||
else
|
||||
g_taskFilters[TASK_ATTACK].desire = 0;
|
||||
|
|
@ -2324,7 +2325,7 @@ bool Bot::IsLastEnemyViewable (void)
|
|||
bool Bot::LastEnemyShootable (void)
|
||||
{
|
||||
// don't allow shooting through walls
|
||||
if (!(m_aimFlags & AIM_LAST_ENEMY) || IsEntityNull (m_lastEnemy) || GetTaskId () == TASK_PAUSE && m_lastEnemyOrigin != nullvec)
|
||||
if (!(m_aimFlags & AIM_LAST_ENEMY) || IsEntityNull (m_lastEnemy) || GetTaskId () == TASK_PAUSE || m_lastEnemyOrigin != nullvec)
|
||||
return false;
|
||||
|
||||
return GetShootingConeDeviation (GetEntity (), &m_lastEnemyOrigin) >= 0.90 && IsShootableThruObstacle (m_lastEnemy->v.origin);
|
||||
|
|
@ -2647,7 +2648,7 @@ void Bot::CheckRadioCommands (void)
|
|||
break;
|
||||
|
||||
case Radio_ReportTeam:
|
||||
if (g_randGen.Long (0, 100) < 85)
|
||||
if (g_randGen.Long (0, 100) < 30)
|
||||
RadioMessage ((GetNearbyEnemiesNearPosition (pev->origin, 400) == 0 && yb_communication_type.GetInt () != 2) ? Radio_SectorClear : Radio_ReportingIn);
|
||||
break;
|
||||
|
||||
|
|
@ -2891,19 +2892,19 @@ void Bot::ChooseAimDirection (void)
|
|||
|
||||
if ((pev->origin - m_lastEnemyOrigin).GetLength () >= 1600 && IsEntityNull (m_enemy) && !UsesSniper () || (tr.flFraction <= 0.2 && tr.pHit == g_hostEntity) && m_seeEnemyTime + 7.0 < GetWorldTime ())
|
||||
{
|
||||
if ((m_aimFlags & (AIM_LAST_ENEMY | AIM_PREDICT_ENEMY)) && m_wantsToFire)
|
||||
if ((m_aimFlags & (AIM_LAST_ENEMY | AIM_PREDICT_PATH)) && m_wantsToFire)
|
||||
m_wantsToFire = false;
|
||||
|
||||
m_lastEnemyOrigin = nullvec;
|
||||
m_aimFlags &= ~(AIM_LAST_ENEMY | AIM_PREDICT_ENEMY);
|
||||
m_aimFlags &= ~(AIM_LAST_ENEMY | AIM_PREDICT_PATH);
|
||||
|
||||
flags &= ~(AIM_LAST_ENEMY | AIM_PREDICT_ENEMY);
|
||||
flags &= ~(AIM_LAST_ENEMY | AIM_PREDICT_PATH);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_aimFlags &= ~(AIM_LAST_ENEMY | AIM_PREDICT_ENEMY);
|
||||
flags &= ~(AIM_LAST_ENEMY | AIM_PREDICT_ENEMY);
|
||||
m_aimFlags &= ~(AIM_LAST_ENEMY | AIM_PREDICT_PATH);
|
||||
flags &= ~(AIM_LAST_ENEMY | AIM_PREDICT_PATH);
|
||||
}
|
||||
|
||||
// don't allow bot to look at danger positions under certain circumstances
|
||||
|
|
@ -2911,7 +2912,7 @@ void Bot::ChooseAimDirection (void)
|
|||
{
|
||||
if (IsOnLadder () || IsInWater () || (m_waypointFlags & FLAG_LADDER) || (m_currentTravelFlags & PATHFLAG_JUMP))
|
||||
{
|
||||
flags &= ~(AIM_LAST_ENEMY | AIM_PREDICT_ENEMY);
|
||||
flags &= ~(AIM_LAST_ENEMY | AIM_PREDICT_PATH);
|
||||
canChooseAimDirection = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -2943,7 +2944,7 @@ void Bot::ChooseAimDirection (void)
|
|||
m_lastEnemyOrigin = nullvec;
|
||||
}
|
||||
}
|
||||
else if (flags & AIM_PREDICT_ENEMY)
|
||||
else if (flags & AIM_PREDICT_PATH)
|
||||
{
|
||||
if (((pev->origin - m_lastEnemyOrigin).GetLength () < 1600 || UsesSniper ()) && (tr.flFraction >= 0.2 || tr.pHit != g_worldEdict))
|
||||
{
|
||||
|
|
@ -2969,7 +2970,7 @@ void Bot::ChooseAimDirection (void)
|
|||
}
|
||||
else // forget an enemy far away
|
||||
{
|
||||
m_aimFlags &= ~AIM_PREDICT_ENEMY;
|
||||
m_aimFlags &= ~AIM_PREDICT_PATH;
|
||||
|
||||
if ((pev->origin - m_lastEnemyOrigin).GetLength () >= 1600.0)
|
||||
m_lastEnemyOrigin = nullvec;
|
||||
|
|
@ -2977,7 +2978,7 @@ void Bot::ChooseAimDirection (void)
|
|||
}
|
||||
else if (flags & AIM_CAMP)
|
||||
m_lookAt = m_camp;
|
||||
else if ((flags & AIM_NAVPOINT) && !(flags & (AIM_ENTITY | AIM_ENEMY)))
|
||||
else if (flags & AIM_NAVPOINT)
|
||||
{
|
||||
m_lookAt = m_destOrigin;
|
||||
|
||||
|
|
@ -3505,7 +3506,7 @@ void Bot::RunTask (void)
|
|||
}
|
||||
|
||||
// bots skill higher than 60?
|
||||
if (yb_walking_allowed.GetBool () && mp_footsteps.GetBool () && m_difficulty >= 1)
|
||||
if (yb_walking_allowed.GetBool () && mp_footsteps.GetBool () && m_difficulty >= 1 && !yb_jasonmode.GetBool ())
|
||||
{
|
||||
// then make him move slow if near enemy
|
||||
if (!(m_currentTravelFlags & PATHFLAG_JUMP))
|
||||
|
|
@ -3578,8 +3579,8 @@ void Bot::RunTask (void)
|
|||
if ((m_reloadState == RELOAD_NONE) && (GetAmmoInClip () < 8) && (GetAmmo () != 0))
|
||||
m_reloadState = RELOAD_PRIMARY;
|
||||
|
||||
m_moveSpeed = 0;
|
||||
m_strafeSpeed = 0;
|
||||
m_moveSpeed = 0.0f;
|
||||
m_strafeSpeed = 0.0f;
|
||||
|
||||
m_moveToGoal = false;
|
||||
m_checkTerrain = true;
|
||||
|
|
@ -4170,7 +4171,7 @@ void Bot::RunTask (void)
|
|||
}
|
||||
m_aimFlags |= AIM_NAVPOINT;
|
||||
|
||||
if (yb_walking_allowed.GetBool () && m_targetEntity->v.maxspeed < m_moveSpeed)
|
||||
if (yb_walking_allowed.GetBool () && m_targetEntity->v.maxspeed < m_moveSpeed && !yb_jasonmode.GetBool ())
|
||||
m_moveSpeed = GetWalkSpeed ();
|
||||
|
||||
if (IsShieldDrawn ())
|
||||
|
|
@ -4908,10 +4909,22 @@ void Bot::BotAI (void)
|
|||
// set the reaction time (surprise momentum) different each frame according to skill
|
||||
SetIdealReactionTimes ();
|
||||
|
||||
#if 0
|
||||
// calculate 2 direction vectors, 1 without the up/down component
|
||||
Vector directionOld = m_destOrigin - (pev->origin + pev->velocity * m_frameInterval);
|
||||
Vector directionNormal = directionOld.Normalize ();
|
||||
|
||||
Vector direction = directionNormal;
|
||||
directionNormal.z = 0.0;
|
||||
|
||||
m_moveAngles = directionOld.ToAngles ();
|
||||
|
||||
m_moveAngles.ClampAngles ();
|
||||
m_moveAngles.x *= -1.0; // invert for engine
|
||||
|
||||
#if 0 // get rid of ugly hack
|
||||
if (yb_hardcore_mode && GetTaskId () == TASK_NORMAL && ((m_aimFlags & AIM_ENEMY) || (m_states & STATE_SEEING_ENEMY)) && !IsOnLadder ())
|
||||
CombatFight ();
|
||||
#else
|
||||
|
||||
if (m_difficulty == 4 && ((m_aimFlags & AIM_ENEMY) || (m_states & (STATE_SEEING_ENEMY | STATE_SUSPECT_ENEMY)) || (GetTaskId () == TASK_SEEKCOVER && (m_isReloading || m_isVIP))) && !yb_jasonmode.GetBool () && GetTaskId () != TASK_CAMP && !IsOnLadder ())
|
||||
{
|
||||
m_moveToGoal = false; // don't move to goal
|
||||
|
|
@ -4921,6 +4934,7 @@ void Bot::BotAI (void)
|
|||
CombatFight ();
|
||||
}
|
||||
#endif
|
||||
|
||||
// check if we need to escape from bomb
|
||||
if ((g_mapType & MAP_DE) && g_bombPlanted && m_notKilled && GetTaskId () != TASK_ESCAPEFROMBOMB && GetTaskId () != TASK_CAMP && OutOfBombTimer ())
|
||||
{
|
||||
|
|
@ -4957,7 +4971,7 @@ void Bot::BotAI (void)
|
|||
}
|
||||
|
||||
if (m_checkTerrain) // are we allowed to check blocking terrain (and react to it)?
|
||||
CheckTerrain (movedDistance);
|
||||
CheckTerrain (movedDistance, direction, directionNormal);
|
||||
|
||||
// must avoid a grenade?
|
||||
if (m_needAvoidGrenade != 0)
|
||||
|
|
@ -5148,12 +5162,13 @@ void Bot::BotAI (void)
|
|||
selectTab++;
|
||||
weaponCount++;
|
||||
}
|
||||
memset (aimFlags, 0, sizeof (aimFlags));
|
||||
|
||||
// set the aim flags
|
||||
sprintf (aimFlags, "%s%s%s%s%s%s%s%s",
|
||||
m_aimFlags & AIM_NAVPOINT ? " NavPoint" : "",
|
||||
m_aimFlags & AIM_CAMP ? " CampPoint" : "",
|
||||
m_aimFlags & AIM_PREDICT_ENEMY ? " PredictEnemy" : "",
|
||||
m_aimFlags & AIM_PREDICT_PATH ? " predictPath" : "",
|
||||
m_aimFlags & AIM_LAST_ENEMY ? " LastEnemy" : "",
|
||||
m_aimFlags & AIM_ENTITY ? " Entity" : "",
|
||||
m_aimFlags & AIM_ENEMY ? " Enemy" : "",
|
||||
|
|
@ -5171,19 +5186,19 @@ void Bot::BotAI (void)
|
|||
switch (m_currentWeapon)
|
||||
{
|
||||
case WEAPON_EXPLOSIVE:
|
||||
sprintf (weaponName, "weapon_hegrenade");
|
||||
strcpy (weaponName, "weapon_hegrenade");
|
||||
break;
|
||||
|
||||
case WEAPON_FLASHBANG:
|
||||
sprintf (weaponName, "weapon_flashbang");
|
||||
strcpy (weaponName, "weapon_flashbang");
|
||||
break;
|
||||
|
||||
case WEAPON_SMOKE:
|
||||
sprintf (weaponName, "weapon_smokegrenade");
|
||||
strcpy (weaponName, "weapon_smokegrenade");
|
||||
break;
|
||||
|
||||
case WEAPON_C4:
|
||||
sprintf (weaponName, "weapon_c4");
|
||||
strcpy (weaponName, "weapon_c4");
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -5400,7 +5415,7 @@ void Bot::TakeBlinded (const Vector &fade, int alpha)
|
|||
m_blindSidemoveSpeed = -walkSpeed;
|
||||
|
||||
if (pev->health < 85)
|
||||
m_blindMoveSpeed = -GetWalkSpeed ();
|
||||
m_blindMoveSpeed = -walkSpeed;
|
||||
else if (m_personality == PERSONALITY_CAREFUL)
|
||||
{
|
||||
m_blindMoveSpeed = 0.0;
|
||||
|
|
@ -5819,7 +5834,7 @@ void Bot::RunPlayerMovement (void)
|
|||
// problems, such as bots getting stuck into each others. That's because the model's
|
||||
// bounding boxes, which are the boxes the engine uses to compute and detect all the
|
||||
// collisions of the model, only exist, and are only valid, while in the duration of the
|
||||
// movement. That's why if you get a pfnRunPlayerMove for one bot that lasts a little too
|
||||
// movement. That's why if you get a pfnRunPlayerMove for one boINFt that lasts a little too
|
||||
// short in comparison with the frame's duration, the remaining time until the frame
|
||||
// elapses, that bot will behave like a ghost : no movement, but bullets and players can
|
||||
// pass through it. Then, when the next frame will begin, the stucking problem will arise !
|
||||
|
|
@ -5882,7 +5897,7 @@ float Bot::GetBombTimeleft (void)
|
|||
|
||||
float Bot::GetEstimatedReachTime (void)
|
||||
{
|
||||
float estimatedTime = 3.0f; // time to reach next waypoint
|
||||
float estimatedTime = 2.0f; // time to reach next waypoint
|
||||
|
||||
// calculate 'real' time that we need to get from one waypoint to another
|
||||
if (m_currentWaypointIndex >= 0 && m_currentWaypointIndex < g_numWaypoints && m_prevWptIndex[0] >= 0 && m_prevWptIndex[0] < g_numWaypoints)
|
||||
|
|
@ -5897,15 +5912,15 @@ float Bot::GetEstimatedReachTime (void)
|
|||
|
||||
// check for special waypoints, that can slowdown our movement
|
||||
if ((m_currentPath->flags & FLAG_CROUCH) || (m_currentPath->flags & FLAG_LADDER) || (pev->button & IN_DUCK))
|
||||
estimatedTime *= 3.0;
|
||||
estimatedTime *= 2.0;
|
||||
|
||||
// check for too low values
|
||||
if (estimatedTime < 1.0f)
|
||||
estimatedTime = 1.0f;
|
||||
|
||||
// check for too high values
|
||||
if (estimatedTime > 8.0f)
|
||||
estimatedTime = 8.0f;
|
||||
if (estimatedTime > 5.0f)
|
||||
estimatedTime = 5.0f;
|
||||
}
|
||||
return estimatedTime;
|
||||
}
|
||||
|
|
@ -6060,31 +6075,6 @@ void Bot::ReactOnSound (void)
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// useless?
|
||||
#if 0
|
||||
extern ConVar yb_shoots_thru_walls;
|
||||
|
||||
// check if heard enemy can be seen
|
||||
if (CheckVisibility (VARS (player), &m_lastEnemyOrigin, &m_visibility))
|
||||
{
|
||||
m_enemy = player;
|
||||
m_lastEnemy = player;
|
||||
m_enemyOrigin = m_lastEnemyOrigin;
|
||||
|
||||
m_states |= STATE_SEEING_ENEMY;
|
||||
m_seeEnemyTime = GetWorldTime ();
|
||||
}
|
||||
else if (m_lastEnemy == player && m_seeEnemyTime + 1.0 > GetWorldTime () && yb_shoots_thru_walls.GetBool () && IsShootableThruObstacle (player->v.origin))
|
||||
{
|
||||
m_enemy = player;
|
||||
m_lastEnemy = player;
|
||||
m_lastEnemyOrigin = player->v.origin;
|
||||
|
||||
m_states |= STATE_SEEING_ENEMY;
|
||||
m_seeEnemyTime = GetWorldTime ();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -254,7 +254,7 @@ bool Bot::LookupEnemy (void)
|
|||
}
|
||||
|
||||
// check if bots should reload...
|
||||
if ((m_aimFlags <= AIM_PREDICT_ENEMY && m_seeEnemyTime + 3.0 < GetWorldTime () && !(m_states & (STATE_SEEING_ENEMY | STATE_HEARING_ENEMY)) && IsEntityNull (m_lastEnemy) && IsEntityNull (m_enemy) && GetTaskId () != TASK_SHOOTBREAKABLE && GetTaskId () != TASK_PLANTBOMB && GetTaskId () != TASK_DEFUSEBOMB) || g_roundEnded)
|
||||
if ((m_aimFlags <= AIM_PREDICT_PATH && m_seeEnemyTime + 3.0 < GetWorldTime () && !(m_states & (STATE_SEEING_ENEMY | STATE_HEARING_ENEMY)) && IsEntityNull (m_lastEnemy) && IsEntityNull (m_enemy) && GetTaskId () != TASK_SHOOTBREAKABLE && GetTaskId () != TASK_PLANTBOMB && GetTaskId () != TASK_DEFUSEBOMB) || g_roundEnded)
|
||||
{
|
||||
if (!m_reloadState)
|
||||
m_reloadState = RELOAD_PRIMARY;
|
||||
|
|
@ -430,11 +430,14 @@ bool Bot::IsFriendInLineOfFire (float distance)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Bot::IsShootableThruObstacle (Vector dest)
|
||||
bool Bot::IsShootableThruObstacle (const Vector &dest)
|
||||
{
|
||||
// this function returns true if enemy can be shoot through some obstacle, false otherwise.
|
||||
// credits goes to Immortal_BLG
|
||||
|
||||
if (yb_shoots_thru_walls.GetInt () == 2)
|
||||
return IsShootableThruObstacleEx (dest);
|
||||
|
||||
if (m_difficulty < 2)
|
||||
return false;
|
||||
|
||||
|
|
@ -478,6 +481,46 @@ bool Bot::IsShootableThruObstacle (Vector dest)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Bot::IsShootableThruObstacleEx (const Vector &dest)
|
||||
{
|
||||
// this function returns if enemy can be shoot through some obstacle
|
||||
|
||||
if (m_difficulty < 2 || GetWeaponPenetrationPower (m_currentWeapon) == 0)
|
||||
return false;
|
||||
|
||||
Vector source = EyePosition ();
|
||||
Vector direction = (dest - source).Normalize (); // 1 unit long
|
||||
Vector point = nullvec;
|
||||
|
||||
int thikness = 0;
|
||||
int numHits = 0;
|
||||
|
||||
TraceResult tr;
|
||||
TraceLine (source, dest, true, true, GetEntity (), &tr);
|
||||
|
||||
while (tr.flFraction != 1.0 && numHits < 3)
|
||||
{
|
||||
numHits++;
|
||||
thikness++;
|
||||
|
||||
point = tr.vecEndPos + direction;
|
||||
|
||||
while (POINT_CONTENTS (point) == CONTENTS_SOLID && thikness < 98)
|
||||
{
|
||||
point = point + direction;
|
||||
thikness++;
|
||||
}
|
||||
TraceLine (point, dest, true, true, GetEntity (), &tr);
|
||||
}
|
||||
|
||||
if (numHits < 3 && thikness < 98)
|
||||
{
|
||||
if ((dest - point).GetLengthSquared () < 13143)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Bot::DoFirePause (float distance, FireDelay *fireDelay)
|
||||
{
|
||||
// returns true if bot needs to pause between firing to compensate for punchangle & weapon spread
|
||||
|
|
@ -818,8 +861,8 @@ WeaponSelectEnd:
|
|||
pev->button &= ~IN_ATTACK;
|
||||
LookupEnemy();
|
||||
}
|
||||
|
||||
pev->button |= IN_ATTACK;
|
||||
|
||||
m_shootTime = GetWorldTime () + baseDelay + g_randGen.Float (minDelay, maxDelay);
|
||||
m_zoomCheckTime = GetWorldTime ();
|
||||
}
|
||||
|
|
@ -865,7 +908,7 @@ void Bot::FocusEnemy (void)
|
|||
|
||||
float distance = enemyOrigin.GetLength (); // how far away is the enemy scum?
|
||||
|
||||
if (distance < 128.0f)
|
||||
if (distance < 256.0f)
|
||||
{
|
||||
if (m_currentWeapon == WEAPON_KNIFE)
|
||||
{
|
||||
|
|
@ -919,11 +962,8 @@ void Bot::CombatFight (void)
|
|||
|
||||
float distance = enemyOrigin.GetLength (); // how far away is the enemy scum?
|
||||
|
||||
if (m_timeWaypointMove + m_frameInterval + 0.5f < GetWorldTime ())
|
||||
if (m_timeWaypointMove + m_frameInterval < GetWorldTime ())
|
||||
{
|
||||
if (m_currentWeapon == WEAPON_KNIFE)
|
||||
return;
|
||||
|
||||
int approach;
|
||||
|
||||
if ((m_states & STATE_SUSPECT_ENEMY) && !(m_states & STATE_SEEING_ENEMY)) // if suspecting enemy stand still
|
||||
|
|
@ -936,11 +976,12 @@ void Bot::CombatFight (void)
|
|||
{
|
||||
approach = static_cast <int> (pev->health * m_agressionLevel);
|
||||
|
||||
if (UsesSniper () && (approach > 49))
|
||||
if (UsesSniper () && approach > 49)
|
||||
approach = 49;
|
||||
}
|
||||
|
||||
if (UsesPistol() && !(m_enemy->v.weapons & (1 << WEAPON_ELITE) || m_enemy->v.weapons & (1 << WEAPON_FIVESEVEN) || m_enemy->v.weapons & (1 << WEAPON_GLOCK) || m_enemy->v.weapons & (1 << WEAPON_USP) || m_enemy->v.weapons & (1 << WEAPON_DEAGLE) || m_enemy->v.weapons & (1 << WEAPON_SG550)) && !g_bombPlanted)
|
||||
|
||||
if (UsesPistol() && !((m_enemy->v.weapons & WEAPON_SECONDARY) || (m_enemy->v.weapons & (1 << WEAPON_SG550))) && !g_bombPlanted)
|
||||
{
|
||||
m_fearLevel += 0.5;
|
||||
|
||||
|
|
@ -970,7 +1011,7 @@ void Bot::CombatFight (void)
|
|||
else
|
||||
m_moveSpeed = pev->maxspeed;
|
||||
|
||||
if (distance < 96 && m_currentWeapon != WEAPON_KNIFE)
|
||||
if (distance < 96)
|
||||
m_moveSpeed = -pev->maxspeed;
|
||||
|
||||
if (UsesSniper ())
|
||||
|
|
@ -1007,7 +1048,7 @@ void Bot::CombatFight (void)
|
|||
{
|
||||
if (m_lastFightStyleCheck + 3.0 < GetWorldTime ())
|
||||
{
|
||||
if (g_randGen.Long (0, 100) < 50)
|
||||
if ( g_randGen.Long (0, 100) < 50)
|
||||
m_fightStyle = 1;
|
||||
else
|
||||
m_fightStyle = 0;
|
||||
|
|
@ -1061,7 +1102,7 @@ void Bot::CombatFight (void)
|
|||
if (m_difficulty >= 3 && (m_jumpTime + 5.0 < GetWorldTime () && IsOnFloor () && g_randGen.Long (0, 1000) < (m_isReloading ? 8 : 2) && pev->velocity.GetLength2D () > 150.0))
|
||||
pev->button |= IN_JUMP;
|
||||
|
||||
if (m_moveSpeed > 0.0 && distance > 150.0)
|
||||
if (m_moveSpeed > 0.0 && distance > 150.0 && m_currentWeapon != WEAPON_KNIFE)
|
||||
m_moveSpeed = 0.0;
|
||||
}
|
||||
else if (m_fightStyle == 1)
|
||||
|
|
@ -1072,6 +1113,7 @@ void Bot::CombatFight (void)
|
|||
float enemyHalfHeight = ((m_enemy->v.flags & FL_DUCKING) == FL_DUCKING ? 36.0 : 72.0) / 2;
|
||||
|
||||
// check center/feet
|
||||
|
||||
if (!IsVisible (m_enemy->v.origin, GetEntity ()) && !IsVisible (m_enemy->v.origin + Vector (0, 0, -enemyHalfHeight), GetEntity ()))
|
||||
shouldDuck = false;
|
||||
|
||||
|
|
@ -1092,7 +1134,7 @@ void Bot::CombatFight (void)
|
|||
m_strafeSpeed = 0.0;
|
||||
}
|
||||
|
||||
if (m_moveSpeed > 0.0f)
|
||||
if (m_moveSpeed > 0.0f && m_currentWeapon != WEAPON_KNIFE)
|
||||
m_moveSpeed = GetWalkSpeed ();
|
||||
|
||||
if (m_isReloading)
|
||||
|
|
@ -1254,9 +1296,9 @@ void Bot::SelectBestWeapon (void)
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
if (m_isReloading)
|
||||
return;
|
||||
|
||||
WeaponSelect *selectTab = &g_weaponSelect[0];
|
||||
|
||||
int selectIndex = 0;
|
||||
|
|
|
|||
|
|
@ -309,7 +309,7 @@ bool Bot::GoalIsValid (void)
|
|||
return false;
|
||||
}
|
||||
|
||||
void Bot::CheckTerrain (float movedDistance)
|
||||
void Bot::CheckTerrain (float movedDistance, const Vector &dir, const Vector &dirNormal)
|
||||
{
|
||||
edict_t *ent = NULL;
|
||||
|
||||
|
|
@ -320,27 +320,17 @@ void Bot::CheckTerrain (float movedDistance)
|
|||
m_campButtons = pev->button & IN_DUCK;
|
||||
|
||||
StartTask (TASK_SHOOTBREAKABLE, TASKPRI_SHOOTBREAKABLE, -1, 0.0, false);
|
||||
m_breakableCheckTime = GetWorldTime () + 0.7f;
|
||||
m_breakableCheckTime = GetWorldTime () + 1.0f;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// calculate 2 direction vectors, 1 without the up/down component
|
||||
Vector directionOld = m_destOrigin - (pev->origin + pev->velocity * m_frameInterval);
|
||||
Vector directionNormal = directionOld.Normalize ();
|
||||
|
||||
Vector direction = directionNormal;
|
||||
directionNormal.z = 0.0;
|
||||
|
||||
m_moveAngles = directionOld.ToAngles ();
|
||||
|
||||
m_moveAngles.ClampAngles ();
|
||||
m_moveAngles.x *= -1.0; // invert for engine
|
||||
|
||||
m_isStuck = false;
|
||||
|
||||
Vector src = nullvec;
|
||||
Vector destination = nullvec;
|
||||
Vector dst = nullvec;
|
||||
|
||||
Vector direction = dir;
|
||||
Vector directionNormal = dirNormal;
|
||||
|
||||
TraceResult tr;
|
||||
|
||||
|
|
@ -415,237 +405,237 @@ void Bot::CheckTerrain (float movedDistance)
|
|||
if (m_collideMoves[m_collStateIndex] == COLLISION_DUCK && IsOnFloor () || IsInWater ())
|
||||
pev->button |= IN_DUCK;
|
||||
}
|
||||
return;
|
||||
}
|
||||
else // bot is stuck!
|
||||
// bot is stuck!
|
||||
|
||||
// not yet decided what to do?
|
||||
if (m_collisionState == COLLISION_NOTDECICED)
|
||||
{
|
||||
// not yet decided what to do?
|
||||
if (m_collisionState == COLLISION_NOTDECICED)
|
||||
char bits = 0;
|
||||
|
||||
if (IsOnLadder ())
|
||||
bits = PROBE_STRAFE;
|
||||
else if (IsInWater ())
|
||||
bits = (PROBE_JUMP | PROBE_STRAFE);
|
||||
else
|
||||
bits = ((g_randGen.Long (0, 10) > 7 ? PROBE_JUMP : 0) | PROBE_STRAFE | PROBE_DUCK);
|
||||
|
||||
// collision check allowed if not flying through the air
|
||||
if (IsOnFloor () || IsOnLadder () || IsInWater ())
|
||||
{
|
||||
char bits = 0;
|
||||
char state[8];
|
||||
int i = 0;
|
||||
|
||||
if (IsOnLadder ())
|
||||
bits = PROBE_STRAFE;
|
||||
else if (IsInWater ())
|
||||
bits = (PROBE_JUMP | PROBE_STRAFE);
|
||||
else
|
||||
bits = ((g_randGen.Long (0, 10) > 7 ? PROBE_JUMP : 0) | PROBE_STRAFE | PROBE_DUCK);
|
||||
// first 4 entries hold the possible collision states
|
||||
state[i++] = COLLISION_JUMP;
|
||||
state[i++] = COLLISION_DUCK;
|
||||
state[i++] = COLLISION_STRAFELEFT;
|
||||
state[i++] = COLLISION_STRAFERIGHT;
|
||||
|
||||
// collision check allowed if not flying through the air
|
||||
if (IsOnFloor () || IsOnLadder () || IsInWater ())
|
||||
// now weight all possible states
|
||||
if (bits & PROBE_JUMP)
|
||||
{
|
||||
char state[8];
|
||||
int i = 0;
|
||||
state[i] = 0;
|
||||
|
||||
// first 4 entries hold the possible collision states
|
||||
state[i++] = COLLISION_JUMP;
|
||||
state[i++] = COLLISION_DUCK;
|
||||
state[i++] = COLLISION_STRAFELEFT;
|
||||
state[i++] = COLLISION_STRAFERIGHT;
|
||||
if (CanJumpUp (directionNormal))
|
||||
state[i] += 10;
|
||||
|
||||
// now weight all possible states
|
||||
if (bits & PROBE_JUMP)
|
||||
if (m_destOrigin.z >= pev->origin.z + 18.0)
|
||||
state[i] += 5;
|
||||
|
||||
if (EntityIsVisible (m_destOrigin))
|
||||
{
|
||||
state[i] = 0;
|
||||
MakeVectors (m_moveAngles);
|
||||
|
||||
if (CanJumpUp (directionNormal))
|
||||
state[i] += 10;
|
||||
src = EyePosition ();
|
||||
src = src + (g_pGlobals->v_right * 15);
|
||||
|
||||
if (m_destOrigin.z >= pev->origin.z + 18.0)
|
||||
state[i] += 5;
|
||||
TraceLine (src, m_destOrigin, true, true, GetEntity (), &tr);
|
||||
|
||||
if (EntityIsVisible (m_destOrigin))
|
||||
if (tr.flFraction >= 1.0)
|
||||
{
|
||||
MakeVectors (m_moveAngles);
|
||||
|
||||
src = EyePosition ();
|
||||
src = src + (g_pGlobals->v_right * 15);
|
||||
src = src - (g_pGlobals->v_right * 15);
|
||||
|
||||
TraceLine (src, m_destOrigin, true, true, GetEntity (), &tr);
|
||||
|
||||
if (tr.flFraction >= 1.0)
|
||||
{
|
||||
src = EyePosition ();
|
||||
src = src - (g_pGlobals->v_right * 15);
|
||||
|
||||
TraceLine (src, m_destOrigin, true, true, GetEntity (), &tr);
|
||||
|
||||
if (tr.flFraction >= 1.0)
|
||||
state[i] += 5;
|
||||
}
|
||||
state[i] += 5;
|
||||
}
|
||||
if (pev->flags & FL_DUCKING)
|
||||
src = pev->origin;
|
||||
else
|
||||
src = pev->origin + Vector (0, 0, -17);
|
||||
|
||||
destination = src + directionNormal * 30;
|
||||
TraceLine (src, destination, true, true, GetEntity (), &tr);
|
||||
|
||||
if (tr.flFraction != 1.0)
|
||||
state[i] += 10;
|
||||
}
|
||||
if (pev->flags & FL_DUCKING)
|
||||
src = pev->origin;
|
||||
else
|
||||
state[i] = 0;
|
||||
src = pev->origin + Vector (0, 0, -17);
|
||||
|
||||
dst = src + directionNormal * 30;
|
||||
TraceLine (src, dst, true, true, GetEntity (), &tr);
|
||||
|
||||
if (tr.flFraction != 1.0)
|
||||
state[i] += 10;
|
||||
}
|
||||
else
|
||||
state[i] = 0;
|
||||
i++;
|
||||
|
||||
if (bits & PROBE_DUCK)
|
||||
{
|
||||
state[i] = 0;
|
||||
|
||||
if (CanDuckUnder (directionNormal))
|
||||
state[i] += 10;
|
||||
|
||||
if ((m_destOrigin.z + 36.0 <= pev->origin.z) && EntityIsVisible (m_destOrigin))
|
||||
state[i] += 5;
|
||||
}
|
||||
else
|
||||
state[i] = 0;
|
||||
i++;
|
||||
|
||||
if (bits & PROBE_STRAFE)
|
||||
{
|
||||
state[i] = 0;
|
||||
state[i + 1] = 0;
|
||||
|
||||
// to start strafing, we have to first figure out if the target is on the left side or right side
|
||||
MakeVectors (m_moveAngles);
|
||||
|
||||
Vector dirToPoint = (pev->origin - m_destOrigin).Normalize2D ();
|
||||
Vector rightSide = g_pGlobals->v_right.Normalize2D ();
|
||||
|
||||
bool dirRight = false;
|
||||
bool dirLeft = false;
|
||||
bool blockedLeft = false;
|
||||
bool blockedRight = false;
|
||||
|
||||
if ((dirToPoint | rightSide) > 0)
|
||||
dirRight = true;
|
||||
else
|
||||
dirLeft = true;
|
||||
|
||||
if (m_moveSpeed > 0)
|
||||
direction = g_pGlobals->v_forward;
|
||||
else
|
||||
direction = -g_pGlobals->v_forward;
|
||||
|
||||
// now check which side is blocked
|
||||
src = pev->origin + (g_pGlobals->v_right * 32);
|
||||
dst = src + (direction * 32);
|
||||
|
||||
TraceHull (src, dst, true, head_hull, GetEntity (), &tr);
|
||||
|
||||
if (tr.flFraction != 1.0)
|
||||
blockedRight = true;
|
||||
|
||||
src = pev->origin - (g_pGlobals->v_right * 32);
|
||||
dst = src + (direction * 32);
|
||||
|
||||
TraceHull (src, dst, true, head_hull, GetEntity (), &tr);
|
||||
|
||||
if (tr.flFraction != 1.0)
|
||||
blockedLeft = true;
|
||||
|
||||
if (dirLeft)
|
||||
state[i] += 5;
|
||||
else
|
||||
state[i] -= 5;
|
||||
|
||||
if (blockedLeft)
|
||||
state[i] -= 5;
|
||||
|
||||
i++;
|
||||
|
||||
if (bits & PROBE_DUCK)
|
||||
{
|
||||
state[i] = 0;
|
||||
|
||||
if (CanDuckUnder (directionNormal))
|
||||
state[i] += 10;
|
||||
|
||||
if ((m_destOrigin.z + 36.0 <= pev->origin.z) && EntityIsVisible (m_destOrigin))
|
||||
state[i] += 5;
|
||||
}
|
||||
if (dirRight)
|
||||
state[i] += 5;
|
||||
else
|
||||
state[i] = 0;
|
||||
state[i] -= 5;
|
||||
|
||||
if (blockedRight)
|
||||
state[i] -= 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
state[i] = 0;
|
||||
i++;
|
||||
|
||||
if (bits & PROBE_STRAFE)
|
||||
state[i] = 0;
|
||||
}
|
||||
|
||||
// weighted all possible moves, now sort them to start with most probable
|
||||
int temp = 0;
|
||||
bool isSorting = false;
|
||||
|
||||
do
|
||||
{
|
||||
isSorting = false;
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
state[i] = 0;
|
||||
state[i + 1] = 0;
|
||||
|
||||
// to start strafing, we have to first figure out if the target is on the left side or right side
|
||||
MakeVectors (m_moveAngles);
|
||||
|
||||
Vector dirToPoint = (pev->origin - m_destOrigin).Normalize2D ();
|
||||
Vector rightSide = g_pGlobals->v_right.Normalize2D ();
|
||||
|
||||
bool dirRight = false;
|
||||
bool dirLeft = false;
|
||||
bool blockedLeft = false;
|
||||
bool blockedRight = false;
|
||||
|
||||
if ((dirToPoint | rightSide) > 0)
|
||||
dirRight = true;
|
||||
else
|
||||
dirLeft = true;
|
||||
|
||||
if (m_moveSpeed > 0)
|
||||
direction = g_pGlobals->v_forward;
|
||||
else
|
||||
direction = -g_pGlobals->v_forward;
|
||||
|
||||
// now check which side is blocked
|
||||
src = pev->origin + (g_pGlobals->v_right * 32);
|
||||
destination = src + (direction * 32);
|
||||
|
||||
TraceHull (src, destination, true, head_hull, GetEntity (), &tr);
|
||||
|
||||
if (tr.flFraction != 1.0)
|
||||
blockedRight = true;
|
||||
|
||||
src = pev->origin - (g_pGlobals->v_right * 32);
|
||||
destination = src + (direction * 32);
|
||||
|
||||
TraceHull (src, destination, true, head_hull, GetEntity (), &tr);
|
||||
|
||||
if (tr.flFraction != 1.0)
|
||||
blockedLeft = true;
|
||||
|
||||
if (dirLeft)
|
||||
state[i] += 5;
|
||||
else
|
||||
state[i] -= 5;
|
||||
|
||||
if (blockedLeft)
|
||||
state[i] -= 5;
|
||||
|
||||
i++;
|
||||
|
||||
if (dirRight)
|
||||
state[i] += 5;
|
||||
else
|
||||
state[i] -= 5;
|
||||
|
||||
if (blockedRight)
|
||||
state[i] -= 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
state[i] = 0;
|
||||
i++;
|
||||
|
||||
state[i] = 0;
|
||||
}
|
||||
|
||||
// weighted all possible moves, now sort them to start with most probable
|
||||
int temp = 0;
|
||||
bool isSorting = false;
|
||||
|
||||
do
|
||||
{
|
||||
isSorting = false;
|
||||
for (i = 0; i < 3; i++)
|
||||
if (state[i + 4] < state[i + 5])
|
||||
{
|
||||
if (state[i + 4] < state[i + 5])
|
||||
{
|
||||
temp = state[i];
|
||||
temp = state[i];
|
||||
|
||||
state[i] = state[i + 1];
|
||||
state[i + 1] = temp;
|
||||
state[i] = state[i + 1];
|
||||
state[i + 1] = temp;
|
||||
|
||||
temp = state[i + 4];
|
||||
temp = state[i + 4];
|
||||
|
||||
state[i + 4] = state[i + 5];
|
||||
state[i + 5] = temp;
|
||||
state[i + 4] = state[i + 5];
|
||||
state[i + 5] = temp;
|
||||
|
||||
isSorting = true;
|
||||
}
|
||||
isSorting = true;
|
||||
}
|
||||
} while (isSorting);
|
||||
}
|
||||
} while (isSorting);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
m_collideMoves[i] = state[i];
|
||||
for (i = 0; i < 4; i++)
|
||||
m_collideMoves[i] = state[i];
|
||||
|
||||
m_collideTime = GetWorldTime ();
|
||||
m_probeTime = GetWorldTime () + 0.5;
|
||||
m_collisionProbeBits = bits;
|
||||
m_collisionState = COLLISION_PROBING;
|
||||
m_collStateIndex = 0;
|
||||
m_collideTime = GetWorldTime ();
|
||||
m_probeTime = GetWorldTime () + 0.5;
|
||||
m_collisionProbeBits = bits;
|
||||
m_collisionState = COLLISION_PROBING;
|
||||
m_collStateIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_collisionState == COLLISION_PROBING)
|
||||
{
|
||||
if (m_probeTime < GetWorldTime ())
|
||||
{
|
||||
m_collStateIndex++;
|
||||
m_probeTime = GetWorldTime () + 0.5;
|
||||
|
||||
if (m_collStateIndex > 4)
|
||||
{
|
||||
m_navTimeset = GetWorldTime () - 5.0;
|
||||
ResetCollideState ();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_collisionState == COLLISION_PROBING)
|
||||
if (m_collStateIndex <= 4)
|
||||
{
|
||||
if (m_probeTime < GetWorldTime ())
|
||||
switch (m_collideMoves[m_collStateIndex])
|
||||
{
|
||||
m_collStateIndex++;
|
||||
m_probeTime = GetWorldTime () + 0.5;
|
||||
case COLLISION_JUMP:
|
||||
if (IsOnFloor () || IsInWater ())
|
||||
pev->button |= IN_JUMP;
|
||||
break;
|
||||
|
||||
if (m_collStateIndex > 4)
|
||||
{
|
||||
m_navTimeset = GetWorldTime () - 5.0;
|
||||
ResetCollideState ();
|
||||
}
|
||||
}
|
||||
case COLLISION_DUCK:
|
||||
if (IsOnFloor () || IsInWater ())
|
||||
pev->button |= IN_DUCK;
|
||||
break;
|
||||
|
||||
if (m_collStateIndex <= 4)
|
||||
{
|
||||
switch (m_collideMoves[m_collStateIndex])
|
||||
{
|
||||
case COLLISION_JUMP:
|
||||
if (IsOnFloor () || IsInWater ())
|
||||
pev->button |= IN_JUMP;
|
||||
break;
|
||||
case COLLISION_STRAFELEFT:
|
||||
pev->button |= IN_MOVELEFT;
|
||||
SetStrafeSpeed (directionNormal, -pev->maxspeed);
|
||||
break;
|
||||
|
||||
case COLLISION_DUCK:
|
||||
if (IsOnFloor () || IsInWater ())
|
||||
pev->button |= IN_DUCK;
|
||||
break;
|
||||
|
||||
case COLLISION_STRAFELEFT:
|
||||
pev->button |= IN_MOVELEFT;
|
||||
SetStrafeSpeed (directionNormal, -pev->maxspeed);
|
||||
break;
|
||||
|
||||
case COLLISION_STRAFERIGHT:
|
||||
pev->button |= IN_MOVERIGHT;
|
||||
SetStrafeSpeed (directionNormal, pev->maxspeed);
|
||||
break;
|
||||
}
|
||||
case COLLISION_STRAFERIGHT:
|
||||
pev->button |= IN_MOVERIGHT;
|
||||
SetStrafeSpeed (directionNormal, pev->maxspeed);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -690,7 +680,7 @@ bool Bot::DoWaypointNav (void)
|
|||
// pressing the jump button gives the illusion of the bot actual jmping.
|
||||
if (IsOnFloor () || IsOnLadder ())
|
||||
{
|
||||
pev->velocity = m_desiredVelocity;
|
||||
pev->velocity = m_desiredVelocity + m_desiredVelocity * 0.15; // cheating i know, but something changed in recent cs updates...
|
||||
pev->button |= IN_JUMP;
|
||||
|
||||
m_jumpFinished = true;
|
||||
|
|
@ -1076,7 +1066,7 @@ bool Bot::DoWaypointNav (void)
|
|||
}
|
||||
|
||||
// make sure we are always facing the door when going through it
|
||||
m_aimFlags &= ~(AIM_LAST_ENEMY | AIM_PREDICT_ENEMY);
|
||||
m_aimFlags &= ~(AIM_LAST_ENEMY | AIM_PREDICT_PATH);
|
||||
|
||||
edict_t *button = FindNearestButton (STRING (tr.pHit->v.targetname));
|
||||
|
||||
|
|
@ -1818,6 +1808,9 @@ bool Bot::FindWaypoint (void)
|
|||
if (i == m_currentWaypointIndex || i == m_prevWptIndex[0] || i == m_prevWptIndex[1] || i == m_prevWptIndex[2] || i == m_prevWptIndex[3] || i == m_prevWptIndex[4])
|
||||
continue;
|
||||
|
||||
if ((g_mapType & MAP_CS) && HasHostage () && (g_waypoint->GetPath (i)->flags & FLAG_NOHOSTAGE))
|
||||
continue;
|
||||
|
||||
// ignore non-reacheable waypoints...
|
||||
if (!g_waypoint->Reachable (this, i))
|
||||
continue;
|
||||
|
|
@ -1854,21 +1847,25 @@ bool Bot::FindWaypoint (void)
|
|||
i = g_randGen.Long (0, 0);
|
||||
|
||||
else if (coveredWaypoint != -1)
|
||||
waypointIndeces[i = 0] = coveredWaypoint;
|
||||
|
||||
{
|
||||
i = 0;
|
||||
waypointIndeces[i] = coveredWaypoint;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = 0;
|
||||
|
||||
Array <int> found;
|
||||
g_waypoint->FindInRadius (found, 256.0, pev->origin);
|
||||
g_waypoint->FindInRadius (found, 1024.0f, pev->origin);
|
||||
|
||||
if (!found.IsEmpty ())
|
||||
waypointIndeces[i = 0] = found.GetRandomElement ();
|
||||
waypointIndeces[i] = found.GetRandomElement ();
|
||||
else
|
||||
waypointIndeces[i = 0] = g_randGen.Long (0, g_numWaypoints - 1);
|
||||
waypointIndeces[i] = g_randGen.Long (0, g_numWaypoints - 1);
|
||||
}
|
||||
|
||||
m_collideTime = GetWorldTime ();
|
||||
ChangeWptIndex (waypointIndeces[0]);
|
||||
ChangeWptIndex (waypointIndeces[i]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1249,7 +1249,7 @@ bool Waypoint::Reachable (Bot *bot, int index)
|
|||
return false;
|
||||
|
||||
Vector src = bot->pev->origin;
|
||||
Vector dest = GetPath (index)->origin;
|
||||
Vector dest = m_paths[index]->origin;
|
||||
|
||||
float distance = (dest - src).GetLength ();
|
||||
|
||||
|
|
@ -1262,7 +1262,7 @@ bool Waypoint::Reachable (Bot *bot, int index)
|
|||
float distance2D = (dest - src).GetLength2D ();
|
||||
|
||||
// is destination waypoint higher that source (45 is max jump height), or destination waypoint higher that source
|
||||
if ((dest.z > src.z + 40.0 || dest.z < src.z - 75.0) && (!(GetPath (index)->flags & FLAG_LADDER) || distance2D >= 16.0))
|
||||
if ((dest.z > src.z + 40.0 || dest.z < src.z - 75.0) && (!(m_paths[index]->flags & FLAG_LADDER) || distance2D >= 16.0))
|
||||
return false; // unable to reach this one
|
||||
}
|
||||
|
||||
|
|
@ -1451,7 +1451,7 @@ char *Waypoint::GetWaypointInfo (int id)
|
|||
{
|
||||
// this function returns path information for waypoint pointed by id.
|
||||
|
||||
Path *path = GetPath (id);
|
||||
Path *path = m_paths[id];
|
||||
|
||||
// if this path is null, return
|
||||
if (path == NULL)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue