Hereīs the full combat.cpp file (no secret is revealed, except the part to make bots shoot sentinels).
Use it freely (but give me some credit!!, haha).
Code:
//===========================================================
//
// Zion Warcry Bot Combat system.
// Based on botman's Half-Life bot example
//
// http://planethalflife.com/botman/
//
// bot_combat.cpp (c) Botman all modifications (c) MIFUNE
//
// 10-11-12-13-14 Enero 2017
//===========================================================
#include "extdll.h"
#include "util.h"
#include "client.h"
#include "cbase.h"
#include "player.h"
#include "items.h"
#include "effects.h"
#include "weapons.h"
#include "soundent.h"
#include "gamerules.h"
#include "animation.h"
#include "bot.h"
extern int f_Observer; // flag to indicate if player is in observer mode
ammo_check_t ammo_check[] = {
{"ammo_9mmAR", "9mm",_9MM_MAX_CARRY},
{"ammo_gaussclip", "uranium", URANIUM_MAX_CARRY},
{"", 0, 0}};
//========================================================================================================================
//========================================================================================================================
CBaseEntity * CBot::BotFindEnemy( void )
{
Vector vecEnd;
static BOOL flag=TRUE;
float nearestdistance = 10000;
CBaseEntity *pNewEnemy = NULL;
//=================================================================================
// Modulo para que los Bots Disparen a los Centinelas
// Module to make the Bots shot to the sentinels
//=================================================================================
CBaseEntity* pEnt = NULL;
if ( ( pEnt = UTIL_FindEntityByClassname( pEnt , "monster_sentinel" ) )||( pEnt = UTIL_FindEntityByClassname( pEnt , "monster_sentow" ) ))
{
pBotEnemy = pEnt ;
// face the enemy
Vector v_enemy = pBotEnemy->pev->origin; //- pev->origin; this part is commented trying to prevent headbanging
Vector bot_angles = UTIL_VecToAngles( v_enemy );
pev->ideal_yaw = bot_angles.y;
// check for wrap around of angle...
if (pev->ideal_yaw > 180)
pev->ideal_yaw -= 360;
if (pev->ideal_yaw < -180)
pev->ideal_yaw += 360;
return (pBotEnemy);
// see if Bot can see the Monster...NEW
if (FInViewCone( &vecEnd ) && FVisible( vecEnd ))
{
float distance = (pEnt ->pev->origin - pev->origin).Length();
if (distance < nearestdistance)
{
nearestdistance = distance;
pNewEnemy = pEnt ;
pBotUser = NULL;
}
}
}
//=================================================================================
// Fin del Modulo para que los Bots Disparen a los Centinelas
// End of module.
//=================================================================================
if (pNewEnemy)
{
// face the enemy
Vector v_enemy = pNewEnemy->pev->origin;// Lo mismo de arriba, comento esto " - pev->origin; "
Vector bot_angles = UTIL_VecToAngles( v_enemy );
pev->ideal_yaw = bot_angles.y;
// check for wrap around of angle...
if (pev->ideal_yaw > 180)
pev->ideal_yaw -= 360;
if (pev->ideal_yaw < -180)
pev->ideal_yaw += 360;
f_move_speed = -150.0;//freezes when see the enemy, then itīll shoot it
}
return (pNewEnemy);
//====================================================================================================================================
// Aņadido Final: parece que chuta 20-Junio-2007 Sin esto los Bots hacian que el juego se "colgase" si no "veian" a algun enemigo.
// Finall add: seems that it works 20-June-2007 Without this Bots make the game crash because they could not free-clear the pointer.
//====================================================================================================================================
//Si no hay enemigo o está muerto eliminar el puntero.
//If thereīs no enemy or if itīs dead clear the pointer
if (( !pNewEnemy) && (!pBotEnemy->IsAlive()))
{
pBotEnemy = NULL;
}
}
Vector CBot::BotBodyTarget( CBaseEntity *pBotEnemy )
{
Vector target;
float f_distance;
float f_scale;
int d_x, d_y, d_z;
f_distance = (pBotEnemy->pev->origin - pev->origin).Length();
if (f_distance > 5000)
f_scale = 1.0;
else if (f_distance > 500)
f_scale = f_distance / 1000.0;
else
f_scale = 0.1;
target = pBotEnemy->Center() + pBotEnemy->pev->view_ofs * RANDOM_FLOAT( 0.0, 0.0 );
d_x = 0; // no offset
d_y = 0;
d_z = 0;
target = target + Vector(d_x, d_y, d_z);
return target;
}
void CBot::BotWeaponInventory( void )
{
int i;
// initialize the elements of the weapons arrays...
for (i = 0; i < MAX_WEAPONS; i++)
{
weapon_ptr[i] = NULL;
primary_ammo[i] = 0;
secondary_ammo[i] = 0;
}
// find out which weapons the bot is carrying...
for (i = 0; i < MAX_ITEM_TYPES; i++)
{
CBasePlayerItem *pItem = NULL;
if (m_rgpPlayerItems[i])
{
pItem = m_rgpPlayerItems[i];
while (pItem)
{
weapon_ptr[pItem->m_iId] = pItem; // store pointer to item
pItem = pItem->m_pNext;
}
}
}
// find out how much ammo of each type the bot is carrying...
for (i = 0; i < MAX_AMMO_SLOTS; i++)
{
if (!CBasePlayerItem::AmmoInfoArray[i].pszName)
continue;
if (strcmp("9mm", CBasePlayerItem::AmmoInfoArray[i].pszName) == 0)
{
primary_ammo[WEAPON_TWOHAND] = m_rgAmmo[i];
primary_ammo[WEAPON_SHORYUKEN] = m_rgAmmo[i];
primary_ammo[WEAPON_SIEGE] = m_rgAmmo[i];
primary_ammo[WEAPON_MJOLNIR] = m_rgAmmo[i];
primary_ammo[WEAPON_SHREDDER] = m_rgAmmo[i];
}
else if (strcmp("uranium", CBasePlayerItem::AmmoInfoArray[i].pszName) == 0)
{
primary_ammo[WEAPON_FEMP] = m_rgAmmo[i];
}
}
}
// specifing a weapon_choice allows you to choose the weapon the bot will
// use (assuming enough ammo exists for that weapon)
// BotFireWeapon will return TRUE if weapon was fired, FALSE otherwise
// primary is used to indicate whether you want primary or secondary fire
// if you have specified a weapon using weapon_choice
BOOL CBot::BotFireWeapon( Vector v_enemy_origin, int weapon_choice, BOOL primary )
{
CBasePlayerItem *new_weapon;
// is it time to check weapons inventory yet?
if (f_weapon_inventory_time <= gpGlobals->time)
{
// check weapon and ammo inventory then update check time...
BotWeaponInventory();
f_weapon_inventory_time = gpGlobals->time + 1.0;
}
Vector v_enemy = v_enemy_origin - GetGunPosition( );
float distance = v_enemy.Length(); // how far away is the enemy?
//===========================================================================================================
// WEAPON URAKEN/CROWBAR
//===========================================================================================================
// if bot is carrying the crowbar...
if (pev->weapons & (1<<WEAPON_CROWBAR))
{
if (( (distance <= 78))) /*&&(weapon_choice == 0)|(weapon_choice == WEAPON_CROWBAR)))*/
{
new_weapon = weapon_ptr[WEAPON_CROWBAR];
// check if the bot isn't already using this item.
if (m_pActiveItem != new_weapon)
SelectItem("weapon_crowbar"); // select the crowbar
pev->button |= IN_ATTACK; // use primary attack (whack! whack!)
// set next time to "shoot"
f_shoot_time = gpGlobals->time + 0.3;// +
return TRUE;
}
}
//===========================================================================================================
// WEAPON APU GUNS// All derived from the MP5 Code.
//===========================================================================================================
//===========================================================================================================
// TWOHAND
//===========================================================================================================
if ((pev->weapons & (1<<WEAPON_TWOHAND)))
{
if (( (distance <= 8000)&&(weapon_choice == 0)||((weapon_choice == WEAPON_TWOHAND))))
{
new_weapon = weapon_ptr[WEAPON_TWOHAND];
// check if the bot has any ammo left for this weapon...
if (primary_ammo[WEAPON_TWOHAND] > 0)
{
// check if the bot isn't already using this item...
if (m_pActiveItem != new_weapon)
SelectItem("weapon_twohand"); // select the Twohand
pev->button |= IN_ATTACK; // use primary attack (bang! bang!)
pev->button |= IN_ATTACK2; // use primary attack (bang! bang!)
// set next time to shoot
f_shoot_time = gpGlobals->time + 0.1;//
return TRUE;
}
if (primary_ammo[WEAPON_TWOHAND] <= 100)// A ver si hay suerte y les da por usar la RECARGA
{
pev->button |= IN_RELOAD; // use primary attack, BAZINGA!!!
}
}
}
//============================================================================================================
// SHORYUKEN
//============================================================================================================
if ((pev->weapons & (1<<WEAPON_SHORYUKEN)) && (pev->waterlevel != 3))
{
if (( (distance <= 4000)&&(weapon_choice == 0)||((weapon_choice == WEAPON_SHORYUKEN))))
{
new_weapon = weapon_ptr[WEAPON_SHORYUKEN];
// check if the bot has any ammo left for this weapon...
if (primary_ammo[WEAPON_SHORYUKEN] > 0)
{
// check if the bot isn't already using this item...
if (m_pActiveItem != new_weapon)
SelectItem("weapon_shoryuken"); // select the Shoryuken
pev->button |= IN_ATTACK; // use primary attack (bang! bang!)
pev->button |= IN_ATTACK2; // use secondary attack (bang! bang!)
// set next time to shoot
f_shoot_time = gpGlobals->time + 0.1;
return TRUE;
}
if (primary_ammo[WEAPON_SHORYUKEN] <= 100)// A ver si hay suerte y les da por usar la RECARGA
// Cross fingers!, hope it reloads if ammo gets under 100
{
pev->button |= IN_RELOAD; // use primary attack, BAZINGA!!!
}
}
}
//=================================================================================================================
// SHREDDER
//=================================================================================================================
if ((pev->weapons & (1<<WEAPON_SHREDDER)))
{
if (( (distance <= 2000)&&(weapon_choice == 0)||((weapon_choice == WEAPON_SHREDDER))))
{
new_weapon = weapon_ptr[WEAPON_SHREDDER];
// check if the bot has any ammo left for this weapon...
if (primary_ammo[WEAPON_SHREDDER] > 0)
{
// check if the bot isn't already using this item...
if (m_pActiveItem != new_weapon)
SelectItem("weapon_shredder"); // select the Shredder
pev->button |= IN_ATTACK; // use primary attack, BAZINGA!!!
pev->button |= IN_ATTACK2; // use secondary attack (bang! bang!)
// set next time to shoot
f_shoot_time = gpGlobals->time + 0.1;
return TRUE;
}
if (primary_ammo[WEAPON_SHREDDER] <= 100)// A ver si hay suerte y les da por usar la RECARGA
{
pev->button |= IN_RELOAD; // use primary attack, BAZINGA!!!
}
}
}
//===============================================================================================================
// MJOLNIR
//===============================================================================================================
if ((pev->weapons & (1<<WEAPON_MJOLNIR)))
{
if (( (distance <= 5000)&&(weapon_choice == 0)||((weapon_choice == WEAPON_MJOLNIR))))
{
new_weapon = weapon_ptr[WEAPON_MJOLNIR];
// check if the bot has any ammo left for this weapon...
if (primary_ammo[WEAPON_MJOLNIR] > 0)
{
// check if the bot isn't already using this item...
if (m_pActiveItem != new_weapon)
SelectItem("weapon_mjolnir"); // select the mjolnir
pev->button |= IN_ATTACK; // use primary attack, BAZINGA!!!
pev->button |= IN_ATTACK2; // use secondary attack (bang! bang!)
// set next time to shoot
f_shoot_time = gpGlobals->time + 0.1;// +
return TRUE;
}
if (primary_ammo[WEAPON_MJOLNIR] <= 100)// A ver si hay suerte y les da por usar la RECARGA
{
pev->button |= IN_RELOAD; // use primary attack, BAZINGA!!!
}
}
}
//=================================================================================================================
// SIEGE
//=================================================================================================================
if ((pev->weapons & (1<<WEAPON_SIEGE)))
{
if (( (distance <= 9500)&&(weapon_choice == 0)||((weapon_choice == WEAPON_SIEGE))))
{
new_weapon = weapon_ptr[WEAPON_SIEGE];
// check if the bot has any ammo left for this weapon...
if (primary_ammo[WEAPON_SIEGE] > 0)
{
// check if the bot isn't already using this item...
if (m_pActiveItem != new_weapon)
SelectItem("weapon_siege"); // select the weapon_siege
pev->button |= IN_ATTACK; // use primary attack, BAZINGA!!!
pev->button |= IN_ATTACK2; // use secondary attack (bang! bang!)
// set next time to shoot
f_shoot_time = gpGlobals->time + 0.1;
return TRUE;
}
if (primary_ammo[WEAPON_SIEGE] <= 100)// A ver si hay suerte y les da por usar la RECARGA
{
pev->button |= IN_RELOAD; // use primary attack, BAZINGA!!!
}
}
}
//========================================================================================================================
// FEMP
//========================================================================================================================
if (pev->weapons & (1<<WEAPON_FEMP))
{
if (( (distance < 150)&&(weapon_choice == 0))||(weapon_choice == WEAPON_FEMP))
{
new_weapon = weapon_ptr[WEAPON_FEMP];
// check if the bot has any ammo left for this weapon...
if (primary_ammo[WEAPON_FEMP] > 0)
{
// check if the bot isn't already using this item...
if (m_pActiveItem != new_weapon)
SelectItem("weapon_femp");
pev->button |= IN_ATTACK; // use primary attack, BAZINGA!!!
// set next time to shoot
f_shoot_time = gpGlobals->time + 10;
}
}
if ( pev->health <= 30 )
{
// check if the bot isn't already using this item...
if (m_pActiveItem != new_weapon)
SelectItem("weapon_femp");
pev->button |= IN_ATTACK2; // use the secondary attack to restore the engine
// set next time to shoot
f_shoot_time = gpGlobals->time + 30;
}
return TRUE;
}
return FALSE;
}
//==========================================================================================================================
//
//==========================================================================================================================
void CBot::BotShootAtEnemy( void )
{
// aim for the head and/or body
Vector v_enemy = BotBodyTarget( pBotEnemy ) - GetGunPosition();
pev->v_angle = UTIL_VecToAngles( v_enemy );
pev->angles.x = pev->v_angle.x;//Esto es lo unico nuevo que he aņadido, de otro modo no apuntan arriba o abajo.
pev->angles.y = pev->v_angle.y;
pev->angles.z = 0;
pev->ideal_yaw = pev->v_angle.y;
// check for wrap around of angle...
if (pev->ideal_yaw > 180)
pev->ideal_yaw -= 360;
if (pev->ideal_yaw < -180)
pev->ideal_yaw += 360;
pev->v_angle.x = -pev->v_angle.x; //adjust pitch to point gun
//=================================================
//Limitador del angulo X (arriba-abajo)
//Limiter for the X angle (up-down)
//=================================================
if (pev->v_angle.x >45) (pev->v_angle.x = 45);
// if (pev->v_angle.x <45) (pev->v_angle.x += 90); <----Commented!!!
if (pev->v_angle.x < 0) (pev->v_angle.x = 0);
//==================================================
// is it time to shoot yet?
if (f_shoot_time <= gpGlobals->time)
{
// select the best weapon to use at this distance and fire...
BotFireWeapon( pBotEnemy->pev->origin );
f_move_speed = -150.0;//No se mueve al disparar
} //Freezes when shooting
v_enemy.z = 0; // ignore z component (up & down)
}
Hope you can help me, any WORKING help will appear on credits.
Hereīs a video of the Bot in action...
http://www.moddb.com/mods/zion-warcr...ource#imagebox