|
General Bot Coding See what a pain it is to get those little mechs shooting around
|
|
Member
Status: Offline
Posts: 171
Join Date: Nov 2007
Location: Russian Federation
|
Another IsShootableThruObstacle() function!!!!!!!! -
26-08-2009
I wrote the function, placed below, that's 99,99% more accuracy than functions from PoDBot, YaPB or another bot!!!!!!!! - It based on cheat's CanPenetrate() function.
Code:
const bool Bot::IsShootableThruObstacle (const Math::Vector3D &destination)
{
// This function returns true if enemy can be shoot through some obstacle, false otherwise.
if (m_profile->skill <= 70u)
return false;
unsigned char currentWeaponPenetrationPower = g_weaponProperties[m_currentWeapon->GetID ()].penetrationPower;
if (currentWeaponPenetrationPower == 0u)
return false;
// set conditions....
Math::Vector3D source (m_edict->GetEyePosition ());
const Math::Vector3D &direction ((destination - source).Normalize () * 8.0f); // 8 units long
do
{
// trace from the bot's eyes to destination...
HalfLifeEngine::Globals::g_halfLifeEngine->TraceLine (source, destination, HalfLifeEngine::SDK::Constants::TraceIgnore_Monsters, m_edict, m_traceResult);
if (m_traceResult.isStartSolid)
{
if (m_traceResult.isAllSolid)
return false;
// move 8 units closer to the destination....
source += direction;
}
else
{
// check if line hit anything
if (m_traceResult.fraction == 1.0f)
return true;
--currentWeaponPenetrationPower;
// move 8 units closer to the destination....
source = m_traceResult.endPosition + direction;
}
} while (currentWeaponPenetrationPower > 0u);
return false;
}
There 'm_traceResult' it's a HL engine TraceResult structure, placed in main bot class for memory economy .
'currentWeaponPenetrationPower' it's a number, that's can be calculated with below function (from cheat, too)
Code:
int CorrectGun(int weaponID)
{
if (weaponID == WEAPONLIST_SG550 || weaponID == WEAPONLIST_G3SG1 || weaponID == WEAPONLIST_SCOUT || weaponID == WEAPONLIST_AWP)
return 3;
if (weaponID == WEAPONLIST_AUG || weaponID == WEAPONLIST_M249 || weaponID == WEAPONLIST_M4A1 || weaponID == WEAPONLIST_DEAGLE || weaponID == WEAPONLIST_SG552 || weaponID == WEAPONLIST_AK47|| weaponID == WEAPONLIST_FAMAS || weaponID == WEAPONLIST_GALIL)
return 2;
return 0;
}
- but for me it's too slow, and I placed the numbers above into the WeaponProperties_t structure.
|
|
|
|
|
Member
Status: Offline
Posts: 171
Join Date: Nov 2007
Location: Russian Federation
|
Re: Another IsShootableThruObstacle() function!!!!!!!! -
20-12-2009
Another function to determine penetration damage.
Code:
enum WeaponBulletType_t
{
WeaponBulletType_0,
WeaponBulletType_1,
WeaponBulletType_2,
WeaponBulletType_3,
WeaponBulletType_4,
WeaponBulletType_5,
WeaponBulletType_6,
WeaponBulletType_7,
WeaponBulletType_8,
WeaponBulletType_9,
WeaponBulletType_10,
WeaponBulletType_11,
WeaponBulletType_12,
WeaponBulletType_13,
WeaponBulletType_14,
WeaponBulletType_15
};
enum WeaponObstaclePenetrationPower_t
{
WeaponObstaclePenetrationPower_0,
WeaponObstaclePenetrationPower_1,
WeaponObstaclePenetrationPower_2
};
enum Constants_t
{
HalfMapSize = 4096u,
MapSize = 8192u
};
enum TextureType_t
{
TextureType_None,
TextureType_Concrete = 'C',
TextureType_Metal = 'M',
TextureType_Dirt = 'D',
TextureType_Ventillation = 'V',
TextureType_Grate = 'G',
TextureType_Tile = 'T',
TextureType_SloshLiquid = 'S',
TextureType_Wood = 'W',
TextureType_Computer = 'P',
TextureType_Grass = 'X',
TextureType_Glass = 'Y',
TextureType_Flesh = 'F',
TextureType_Snow = 'N'
};
struct WeaponPenetrationInformation_t
{
WeaponBulletType_t bulletType; // weapon bullet type
unsigned char penetrationPower; // can shoot thru walls
unsigned short maximumShootDistance; // maximum shoot distance
// Information: damage/obstacle pierce for usp/m4a1 - unsilenced/silenced.
unsigned char damage1; // damage 1
unsigned char damage2; // damage 2
float obstaclePierce1; // obstacle pierce 1
float obstaclePierce2; // obstacle pierce 2
} g_weaponPenetrationInformation[] =
{
// Terminator, since weapon id's are starting from 1 in Half-Life engine. :-(
{WeaponBulletType_0, WeaponObstaclePenetrationPower_0, 0u, 0u, 0u, 0.0f, 0.0f}, // WeaponID_None
{WeaponBulletType_15, WeaponObstaclePenetrationPower_0, HalfMapSize, 32u, 0u, 0.8f, 0.0f}, // WeaponID_P228
{WeaponBulletType_0, WeaponObstaclePenetrationPower_0, 0u, 0u, 0u, 0.0f, 0.0f}, // WeaponID_Shield
{WeaponBulletType_11, WeaponObstaclePenetrationPower_2, MapSize, 75u, 0u, 0.98f, 0.0f}, // WeaponID_Scout
{WeaponBulletType_0, WeaponObstaclePenetrationPower_0, 0u, 97u, 0u, 0.0f, 0.0f}, // WeaponID_Esplosive
{WeaponBulletType_0, WeaponObstaclePenetrationPower_0, 0u, 115u, 0u, 0.0f, 0.0f}, // WeaponID_XM1014
{WeaponBulletType_0, WeaponObstaclePenetrationPower_0, 0u, 0u, 0u, 0.0f, 0.0f}, // WeaponID_C4
{WeaponBulletType_9, WeaponObstaclePenetrationPower_0, MapSize, 29u, 0u, 0.82f, 0.0f}, // WeaponID_MAC10
{WeaponBulletType_12, WeaponObstaclePenetrationPower_1, MapSize, 32u, 0u, 0.96f, 0.0f}, // WeaponID_Aug
{WeaponBulletType_0, WeaponObstaclePenetrationPower_0, 0u, 0u, 0u, 0.0f, 0.0f}, // WeaponID_Smoke
{WeaponBulletType_1, WeaponObstaclePenetrationPower_0, MapSize, 36u, 0u, 0.75f, 0.0f}, // WeaponID_Elite
{WeaponBulletType_15, WeaponObstaclePenetrationPower_0, HalfMapSize, 20u, 0u, 0.885f, 0.0f}, // WeaponID_FiveSeven
{WeaponBulletType_9, WeaponObstaclePenetrationPower_0, MapSize, 30u, 0u, 0.82f, 0.0f}, // WeaponID_UMP45
{WeaponBulletType_12, WeaponObstaclePenetrationPower_1, MapSize, 70u, 0u, 0.98f, 0.0f}, // WeaponID_SG550
{WeaponBulletType_12, WeaponObstaclePenetrationPower_1, MapSize, 30u, 0u, 0.96f, 0.0f}, // WeaponID_Galil
{WeaponBulletType_12, WeaponObstaclePenetrationPower_1, MapSize, 30u, 0u, 0.96f, 0.0f}, // WeaponID_Famas
{WeaponBulletType_9, WeaponObstaclePenetrationPower_0, HalfMapSize, 34u, 30u, 0.79f, 0.79f}, // WeaponID_USP
{WeaponBulletType_1, WeaponObstaclePenetrationPower_0, MapSize, 25u, 0u, 0.75f, 0.0f}, // WeaponID_Glock18
{WeaponBulletType_10, WeaponObstaclePenetrationPower_2, MapSize, 115u, 0u, 0.99f, 0.0f}, // WeaponID_AWP
{WeaponBulletType_1, WeaponObstaclePenetrationPower_0, MapSize, 26u, 0u, 0.84f, 0.0f}, // WeaponID_MP5
{WeaponBulletType_12, WeaponObstaclePenetrationPower_1, MapSize, 32u, 0u, 0.97f, 0.0f}, // WeaponID_M249
{WeaponBulletType_0, WeaponObstaclePenetrationPower_0, HalfMapSize, 172u, 0u, 0.0f, 0.0f}, // WeaponID_M3
{WeaponBulletType_12, WeaponObstaclePenetrationPower_1, MapSize, 32u, 33u, 0.97f, 0.95f}, // WeaponID_M4A1
{WeaponBulletType_1, WeaponObstaclePenetrationPower_0, MapSize, 20u, 0u, 0.85f, 0.0f}, // WeaponID_TMP
{WeaponBulletType_11, WeaponObstaclePenetrationPower_1, MapSize, 80u, 0u, 0.98f, 0.0f}, // WeaponID_G3SG1
{WeaponBulletType_0, WeaponObstaclePenetrationPower_0, 0u, 0u, 0u, 0.0f, 0.0f}, // WeaponID_Flashbang
{WeaponBulletType_13, WeaponObstaclePenetrationPower_1, MapSize, 54u, 0u, 0.81f, 0.0f}, // WeaponID_Deagle
{WeaponBulletType_12, WeaponObstaclePenetrationPower_1, MapSize, 33u, 0u, 0.955f, 0.0f}, // WeaponID_SG552
{WeaponBulletType_11, WeaponObstaclePenetrationPower_1, MapSize, 36u, 0u, 0.98f, 0.0f}, // WeaponID_AK47
{WeaponBulletType_0, WeaponObstaclePenetrationPower_0, 0u, 16u, 66u, 0.0f, 0.0f}, // WeaponID_Knife
{WeaponBulletType_14, WeaponObstaclePenetrationPower_0, HalfMapSize, 21u, 0u, 0.885f, 0.0f} // WeaponID_P90
};
template <typename elementType> inline void Swap (elementType &left, elementType &right)
{
// This template function exchanges values stored at 'left' and 'right'.
// different, worth swapping
assert (&left != &right);
elementType temp (left);
// swap....
left = right;
right = temp;
}
inline const bool GetLineFromFileBuffer (const char *const fileBuffer, unsigned int fileSize, unsigned int &filePosition, char *const buffer, const unsigned short bufferSize)
{
// Bullet-proofing
assert (filePosition < fileSize);
unsigned int index (filePosition);
// fgets always NULL terminates, so only read bufferSize - 1 characters
if (fileSize - filePosition > bufferSize - 1u)
fileSize = filePosition + bufferSize - 1u;
// Stop at the next newline (inclusive) or end of buffer
while (index < fileSize)
if (fileBuffer[index++] == '\n')
break;
// If we actually advanced the pointer, copy it over
if (index > filePosition)
{
// We read in size bytes
const unsigned short size (static_cast <unsigned short> (index - filePosition));
// copy it out
memcpy (buffer, fileBuffer + filePosition, size);
buffer[size] = 0;
// Update file pointer
filePosition = index;
return true;
}
// No data read, bail
return false;
}
class TexturesManager
{
private:
enum
{
MaximumTextureNameLength = 13u, // only load first n chars of name
MaximumTexturesNumber = 512u // max number of textures loaded
};
struct Texture_t
{
char type; // texture type (from 'TextureType_t' enumeration)
char name[MaximumTextureNameLength]; // texture name
};
Texture_t m_textures[MaximumTexturesNumber];
unsigned short m_texturesNumber;
public:
TexturesManager (void) : m_texturesNumber (0u)
{
int fileSize;
unsigned char *const file (LOAD_FILE_FOR_ME ("sound/materials.txt", &fileSize));
if (file == NULL)
return;
char *buffer;
unsigned int filePosition (0u);
unsigned short startIndex, endIndex;
// for each line in the file...
while (GetLineFromFileBuffer (static_cast <const char *const> (static_cast <const void *const> (file)), fileSize, filePosition, buffer, 511u))
{
startIndex = 0u;
// skip whitespaces
while (buffer[startIndex] != 0 && isspace (buffer[startIndex]))
++startIndex;
if (buffer[startIndex] == 0)
continue;
// skip comment lines
if (buffer[startIndex] == '/' || !isalpha (buffer[startIndex]))
continue;
// get texture type
m_textures[m_texturesNumber].type = static_cast <char> (toupper (buffer[startIndex++]));
// skip whitespace
while (buffer[startIndex] != 0 && isspace (buffer[startIndex]))
++startIndex;
if (buffer[startIndex] == 0)
continue;
// get sentence name
endIndex = startIndex;
while (buffer[endIndex] != 0 && !isspace (buffer[endIndex]))
++endIndex;
if (buffer[endIndex] == 0)
continue;
// null-terminate name and save in sentences array
buffer[min (endIndex, MaximumTextureNameLength - 1u + startIndex)] = 0;
strcpy (m_textures[m_texturesNumber].name, buffer + startIndex);
if (++m_texturesNumber == MaximumTexturesNumber)
break;
}
// Must use engine to free since we are in a .dll
FREE_FILE (file);
SortTextures ();
}
private:
inline void SwapTextures (const unsigned short i, const unsigned short j)
{
Swap (m_textures[i].type, m_textures[j].type);
Swap (m_textures[i].name, m_textures[j].name);
}
inline void SortTextures (void)
{
// Bubble sort, yuck, but this only occurs at startup and it's only 512 elements...
for (unsigned short i (0u), j; i < m_texturesNumber; ++i)
for (j = i + 1u; j < m_texturesNumber; ++j)
if (stricmp (m_textures[i].name, m_textures[j].name) > 0)
{
// Swap
SwapTextures (i, j);
}
}
inline const char FindTextureType (const char *const name) const
{
// given texture name, find texture type
// if not found, return type 'concrete'
unsigned short pivot, left (0u);
int right (m_texturesNumber), value;
do
{
// To start, find the subscript of the middle position.
if ((value = strnicmp (m_textures[pivot = static_cast <unsigned short> ((left + right) / 2u)].name, name)) == 0)
return m_textures[pivot].type;
if (value > 0) // If the number is > key, increase position by one.
left = pivot + 1u;
else // Else (value < 0), decrease position by one.
right = pivot - 1;
} while (left <= right);
return TextureType_Concrete;
}
public:
inline const char GetTextureType (Edict_t *const entity, const Math::Vector3D &source, const Math::Vector3D &destination) const
{
const unsigned short entityIndex (ENTINDEX (entity));
if (entityIndex == 0u)
{
// get texture from entity or world (world is ent(0))
const char *textureName (TRACE_TEXTURE (entity, source, destination));
if (textureName != NULL)
{
// strip leading '-0' or '+0~' or '{' or '!'
if (*textureName == '-' || *textureName == '+')
textureName += 2u;
if (*textureName == '{' || *textureName == '!' || *textureName == '~' || *textureName == ' ')
++textureName;
// '}}'
// get texture type
return FindTextureType (textureName);
}
}
else if (entityIndex >= 1u && entityIndex <= g_pGlobals->maxClients) // Player
return TextureType_Flesh; // hit body
return TextureType_None;
}
};
TexturesManager *g_texturesManager; // NOTE: Initialize this after getting the engine functions!
const unsigned char Bot::GetPenetrationDamage (const Math::Vector3D &source, const Math::Vector3D &destination)
{
if (m_profile->skill <= 70u)
return 0u;
unsigned char currentWeaponPenetrationPower (static_cast <unsigned char> (g_weaponProperties[m_currentWeapon->GetID ()].penetrationPower));
if (currentWeaponPenetrationPower == WeaponObstaclePenetrationPower_0)
return false;
Math::Vector3D start (source), end (destination), direction (end - start);
float distanceFraction, damageMult (0.5f), distanceMaximum (0.0f);
const float length (direction.GetLength ());
unsigned char bulletVelocity (0u);
float distance (g_weaponPenetrationInformation[m_currentWeapon->GetID ()].maximumShootDistance);
unsigned char currentWeaponPenetrationPower (g_weaponPenetrationInformation[m_currentWeapon->GetID ()].currentWeaponPenetrationPower + 1u);
// What damage/obstaclePierce (first(silenced) or second(unsilenced)) can easily identify with CS offsets (for windows=74, for linux=don't know :), flags=USP_SILENCED = (1u << 0u), M4A1_SILENCED = (1u << 2u)) - ONLY FOR USP OR M4A1!!!!!!!!!!!!
unsigned char damage (g_weaponPenetrationInformation[m_currentWeapon->GetID ()].damage1);
const float obstaclePierce (g_weaponPenetrationInformation[m_currentWeapon->GetID ()].obstaclePierce1);
direction /= length;
end = direction * distance + start;
++currentWeaponPenetrationPower;
// damage gets a randomlong added to it in first switch
switch (g_weaponPenetrationInformation[m_currentWeapon->GetID ()].bulletType)
{
case WeaponBulletType_1:
bulletVelocity = 21u;
distanceMaximum = 800.0f;
break;
case WeaponBulletType_9:
switch (yb_wall_sensitivity.GetInt ())
{
case 0u:
damage -= 2u;
break;
case 2u:
damage += 2u;
break;
}
bulletVelocity = 15u;
distanceMaximum = 500.0f;
break;
case WeaponBulletType_13:
bulletVelocity = 30u;
distanceMaximum = 1000.0f;
break;
case WeaponBulletType_11:
switch (yb_wall_sensitivity.GetInt ())
{
case 0u:
damage -= 2u;
break;
case 2u:
damage += 2u;
break;
}
bulletVelocity = 39u;
distanceMaximum = 5000.0f;
break;
case WeaponBulletType_12:
switch (yb_wall_sensitivity.GetInt ())
{
case 0u:
damage -= 3u;
break;
case 2u:
damage += 3u;
break;
}
bulletVelocity = 35u;
distanceMaximum = 4000.0f;
break;
case WeaponBulletType_10:
switch (yb_wall_sensitivity.GetInt ())
{
case 0u:
damage -= 4u;
break;
case 2u:
damage += 4u;
break;
}
bulletVelocity = 45u;
distanceMaximum = 8000.0f;
break;
case WeaponBulletType_14:
switch (yb_wall_sensitivity.GetInt ())
{
case 0u:
damage -= 4u;
break;
case 2u:
damage += 6u;
break;
default:
++damage;
break;
}
bulletVelocity = 30u;
distanceMaximum = 2000.0f;
break;
case WeaponBulletType_15:
switch (yb_wall_sensitivity.GetInt ())
{
case 0u:
damage -= 4u;
break;
case 2u:
damage += 6u;
break;
default:
++damage;
break;
}
bulletVelocity = 25u;
distanceMaximum = 800.0f;
break;
default:
break;
}
for (/*Empty*/; /*Empty*/; /*Empty*/)
{
TRACE_LINE (start, end, TraceIgnore_Monsters, m_edict, m_traceResult);
if (m_traceResult.fraction == 1.0f)
return 0u;
switch (g_texturesManager->GetTextureType (m_traceResult.hitEntity, start, end))
{
case TextureType_Concrete:
bulletVelocity *= 0.25f;
break;
case TextureType_Grate:
bulletVelocity *= 0.5f;
damageMult = 0.4f;
break;
case TextureType_Metal:
bulletVelocity *= 0.15f;
damageMult = 0.2f;
break;
case TextureType_Computer:
bulletVelocity *= 0.4f;
break;
case TextureType_Tile:
bulletVelocity *= 0.65f;
damageMult = 0.2f;
break;
case TextureType_Ventillation:
bulletVelocity *= 0.5f;
damageMult = 0.45f;
break;
case TextureType_Wood:
damageMult = 0.6f;
default:
break;
}
if ((m_traceResult.endPosition - source).GetLength () >= length)
{
m_traceResult.fraction = (destination - start).GetLength () / (end - start).GetLength ();
distanceFraction = distance * m_traceResult.fraction;
damage *= pow (obstaclePierce, distanceFraction * 0.002f);
return damage;
}
if (--currentWeaponPenetrationPower == 0u || (distanceFraction = distance * m_traceResult.fraction) > distanceMaximum)
return 0u;
damage *= pow (obstaclePierce, distanceFraction * 0.002f);
start = bulletVelocity * direction + m_traceResult.endPosition;
distance = (distance - distanceFraction) * 0.5f;
end = direction * distance + start;
distanceFraction = damage;
damage = static_cast <unsigned char> (distanceFraction * damageMult);
}
}
Sorry, that without explanations - in the first place: badly with English, secondly: I badly explain
In general, anyone interested - will understand
Last edited by Immortal_BLG; 20-12-2009 at 07:04..
|
|
|
|
|
Summoner
Status: Offline
Posts: 1,499
Join Date: Feb 2004
Location: Mist Village
|
Re: Another IsShootableThruObstacle() function!!!!!!!! -
20-12-2009
well this looks much more detailed than the original PB function don't know how you figured this out but good job anyway
|
|
|
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
|
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
Powered by vBulletin® Version 3.8.2 Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
vBulletin Skin developed by: vBStyles.com
|
|