// // HPB bot - botman's High Ping Bastard bot // // (http://planethalflife.com/botman/) // // bot_client.cpp // #include "extdll.h" #include "util.h" #include "cbase.h" #include "bot.h" #include "bot_func.h" #include "bot_client.h" #include "bot_weapons.h" // types of damage to ignore... #define IGNORE_DAMAGE (DMG_CRUSH | DMG_BURN | DMG_FREEZE | DMG_FALL | \ DMG_SHOCK | DMG_DROWN | DMG_NERVEGAS | DMG_RADIATION | \ DMG_DROWNRECOVER | DMG_ACID | DMG_SLOWBURN | \ DMG_SLOWFREEZE | 0xFF000000) extern int mod_id; extern bot_t bots[32]; extern int num_logos; extern edict_t *holywars_saint; extern int halo_status; extern int holywars_gamemode; extern int bot_taunt_count; extern int recent_bot_taunt[]; extern bot_chat_t bot_taunt[MAX_BOT_CHAT]; bot_weapon_t weapon_defs[MAX_WEAPONS]; // array of weapon definitions // This message is sent when the TFC VGUI menu is displayed. void BotClient_TFC_VGUI(void *p, int bot_index) { static int state = 0; // current state machine state if (state == 0) { if ((*(int *)p) == 2) // is it a team select menu? bots[bot_index].start_action = MSG_TFC_TEAM_SELECT; else if ((*(int *)p) == 3) // is is a class selection menu? bots[bot_index].start_action = MSG_TFC_CLASS_SELECT; } state++; if (state == 1) state = 0; } // This message is sent when the Counter-Strike VGUI menu is displayed. void BotClient_CS_VGUI(void *p, int bot_index) { static int state = 0; // current state machine state if (state == 0) { if ((*(int *)p) == 2) // is it a team select menu? bots[bot_index].start_action = MSG_CS_TEAM_SELECT; else if ((*(int *)p) == 26) // is is a terrorist model select menu? bots[bot_index].start_action = MSG_CS_T_SELECT; else if ((*(int *)p) == 27) // is is a counter-terrorist model select menu? bots[bot_index].start_action = MSG_CS_CT_SELECT; } state++; if (state == 5) // ignore other fields in VGUI message state = 0; } // This message is sent when a menu is being displayed in Counter-Strike. void BotClient_CS_ShowMenu(void *p, int bot_index) { static int state = 0; // current state machine state if (state < 3) { state++; // ignore first 3 fields of message return; } if (strcmp((char *)p, "#Team_Select") == 0) // team select menu? { bots[bot_index].start_action = MSG_CS_TEAM_SELECT; } else if (strcmp((char *)p, "#Terrorist_Select") == 0) // T model select? { bots[bot_index].start_action = MSG_CS_T_SELECT; } else if (strcmp((char *)p, "#CT_Select") == 0) // CT model select menu? { bots[bot_index].start_action = MSG_CS_CT_SELECT; } state = 0; // reset state machine } // This message is sent when the OpFor VGUI menu is displayed. void BotClient_Gearbox_VGUI(void *p, int bot_index) { static int state = 0; // current state machine state if (state == 0) { if ((*(int *)p) == 2) // is it a team select menu? bots[bot_index].start_action = MSG_OPFOR_TEAM_SELECT; else if ((*(int *)p) == 3) // is is a class selection menu? bots[bot_index].start_action = MSG_OPFOR_CLASS_SELECT; } state++; if (state == 1) state = 0; } // This message is sent when the FrontLineForce VGUI menu is displayed. void BotClient_FLF_VGUI(void *p, int bot_index) { static int state = 0; // current state machine state if (p == NULL) // handle pfnMessageEnd case { state = 0; return; } if (state == 0) { if ((*(int *)p) == 2) // is it a team select menu? bots[bot_index].start_action = MSG_FLF_TEAM_SELECT; else if ((*(int *)p) == 3) // is it a class selection menu? bots[bot_index].start_action = MSG_FLF_CLASS_SELECT; else if ((*(int *)p) == 70) // is it a weapon selection menu? bots[bot_index].start_action = MSG_FLF_WEAPON_SELECT; else if ((*(int *)p) == 72) // is it a submachine gun selection menu? bots[bot_index].start_action = MSG_FLF_SUBMACHINE_SELECT; else if ((*(int *)p) == 73) // is it a shotgun selection menu? bots[bot_index].start_action = MSG_FLF_SHOTGUN_SELECT; else if ((*(int *)p) == 75) // is it a rifle selection menu? bots[bot_index].start_action = MSG_FLF_RIFLE_SELECT; else if ((*(int *)p) == 76) // is it a pistol selection menu? bots[bot_index].start_action = MSG_FLF_PISTOL_SELECT; else if ((*(int *)p) == 78) // is it a heavyweapons selection menu? bots[bot_index].start_action = MSG_FLF_HEAVYWEAPONS_SELECT; } state++; } // This message is sent when a client joins the game. All of the weapons // are sent with the weapon ID and information about what ammo is used. void BotClient_Valve_WeaponList(void *p, int bot_index) { static int state = 0; // current state machine state static bot_weapon_t bot_weapon; if (state == 0) { state++; strcpy(bot_weapon.szClassname, (char *)p); } else if (state == 1) { state++; bot_weapon.iAmmo1 = *(int *)p; // ammo index 1 } else if (state == 2) { state++; bot_weapon.iAmmo1Max = *(int *)p; // max ammo1 } else if (state == 3) { state++; bot_weapon.iAmmo2 = *(int *)p; // ammo index 2 } else if (state == 4) { state++; bot_weapon.iAmmo2Max = *(int *)p; // max ammo2 } else if (state == 5) { state++; bot_weapon.iSlot = *(int *)p; // slot for this weapon } else if (state == 6) { state++; bot_weapon.iPosition = *(int *)p; // position in slot } else if (state == 7) { state++; bot_weapon.iId = *(int *)p; // weapon ID } else if (state == 8) { state = 0; bot_weapon.iFlags = *(int *)p; // flags for weapon (WTF???) // store away this weapon with it's ammo information... weapon_defs[bot_weapon.iId] = bot_weapon; if (mod_id == DMC_DLL) { bots[bot_index].bot_weapons |= bot_weapon.iId; } } } void BotClient_TFC_WeaponList(void *p, int bot_index) { // this is just like the Valve Weapon List message BotClient_Valve_WeaponList(p, bot_index); } void BotClient_CS_WeaponList(void *p, int bot_index) { // this is just like the Valve Weapon List message BotClient_Valve_WeaponList(p, bot_index); } void BotClient_Gearbox_WeaponList(void *p, int bot_index) { // this is just like the Valve Weapon List message BotClient_Valve_WeaponList(p, bot_index); } void BotClient_FLF_WeaponList(void *p, int bot_index) { // this is just like the Valve Weapon List message BotClient_Valve_WeaponList(p, bot_index); } void BotClient_DMC_WeaponList(void *p, int bot_index) { // this is just like the Valve Weapon List message BotClient_Valve_WeaponList(p, bot_index); } // This message is sent when a weapon is selected (either by the bot chosing // a weapon or by the server auto assigning the bot a weapon). void BotClient_Valve_CurrentWeapon(void *p, int bot_index) { static int state = 0; // current state machine state static int iState; static int iId; static int iClip; if (state == 0) { state++; iState = *(int *)p; // state of the current weapon } else if (state == 1) { state++; iId = *(int *)p; // weapon ID of current weapon } else if (state == 2) { state = 0; iClip = *(int *)p; // ammo currently in the clip for this weapon if (mod_id == DMC_DLL) { if ((iState == 1) && (iId <= 128)) bots[bot_index].bot_weapons |= iId; } else { if (iId <= 31) { bots[bot_index].bot_weapons |= (1< 0) || (damage_taken > 0)) { // ignore certain types of damage... if (damage_bits & IGNORE_DAMAGE) return; // if the bot doesn't have an enemy and someone is shooting at it then // turn in the attacker's direction... if (bots[bot_index].pBotEnemy == NULL) { // face the attacker... Vector v_enemy = damage_origin - bots[bot_index].pEdict->v.origin; Vector bot_angles = UTIL_VecToAngles( v_enemy ); bots[bot_index].pEdict->v.ideal_yaw = bot_angles.y; BotFixIdealYaw(bots[bot_index].pEdict); // stop using health or HEV stations... bots[bot_index].b_use_health_station = FALSE; bots[bot_index].b_use_HEV_station = FALSE; bots[bot_index].b_use_capture = FALSE; } } } } void BotClient_TFC_Damage(void *p, int bot_index) { // this is just like the Valve Damage message BotClient_Valve_Damage(p, bot_index); } void BotClient_CS_Damage(void *p, int bot_index) { // this is just like the Valve Damage message BotClient_Valve_Damage(p, bot_index); } void BotClient_Gearbox_Damage(void *p, int bot_index) { // this is just like the Valve Damage message BotClient_Valve_Damage(p, bot_index); } void BotClient_FLF_Damage(void *p, int bot_index) { // this is just like the Valve Damage message BotClient_Valve_Damage(p, bot_index); } void BotClient_DMC_Damage(void *p, int bot_index) { // this is just like the Valve Damage message BotClient_Valve_Damage(p, bot_index); } // This message gets sent when the bots money ammount changes (for CS) void BotClient_CS_Money(void *p, int bot_index) { static int state = 0; // current state machine state if (state == 0) { state++; bots[bot_index].bot_money = *(int *)p; // amount of money } else { state = 0; // ingore this field } } // This message gets sent when the bots get killed void BotClient_Valve_DeathMsg(void *p, int bot_index) { static int state = 0; // current state machine state static int killer_index; static int victim_index; static edict_t *killer_edict; static edict_t *victim_edict; static int index; char chat_text[81]; char chat_name[64]; char temp_name[64]; const char *bot_name; if (state == 0) { state++; killer_index = *(int *)p; // ENTINDEX() of killer } else if (state == 1) { state++; victim_index = *(int *)p; // ENTINDEX() of victim } else if (state == 2) { state = 0; killer_edict = INDEXENT(killer_index); victim_edict = INDEXENT(victim_index); // get the bot index of the killer... index = UTIL_GetBotIndex(killer_edict); // is this message about a bot killing someone? if (index != -1) { if (killer_index != victim_index) // didn't kill self... { if ((RANDOM_LONG(1, 100) <= bots[index].logo_percent) && (num_logos)) { bots[index].b_spray_logo = TRUE; // this bot should spray logo now bots[index].f_spray_logo_time = gpGlobals->time; } } if (victim_edict != NULL) { // are there any taunt messages and should the bot taunt? if ((bot_taunt_count > 0) && (RANDOM_LONG(1,100) <= bots[index].taunt_percent)) { int taunt_index; bool used; int i, recent_count; // set chat flag and time to chat... bots[index].b_bot_say = TRUE; bots[index].f_bot_say = gpGlobals->time + 5.0 + RANDOM_FLOAT(0.0, 5.0); recent_count = 0; while (recent_count < 5) { taunt_index = RANDOM_LONG(0, bot_taunt_count-1); used = FALSE; for (i=0; i < 5; i++) { if (recent_bot_taunt[i] == taunt_index) used = TRUE; } if (used) recent_count++; else break; } for (i=4; i > 0; i--) recent_bot_taunt[i] = recent_bot_taunt[i-1]; recent_bot_taunt[0] = taunt_index; if (bot_taunt[taunt_index].can_modify) BotChatText(bot_taunt[taunt_index].text, chat_text); else strcpy(chat_text, bot_taunt[taunt_index].text); if (victim_edict->v.netname) { strncpy(temp_name, STRING(victim_edict->v.netname), 31); temp_name[31] = 0; BotChatName(temp_name, chat_name); } else strcpy(chat_name, "NULL"); bot_name = STRING(bots[index].pEdict->v.netname); BotChatFillInName(bots[index].bot_say_msg, chat_text, chat_name, bot_name); } } } // get the bot index of the victim... index = UTIL_GetBotIndex(victim_edict); // is this message about a bot being killed? if (index != -1) { if ((killer_index == 0) || (killer_index == victim_index)) { // bot killed by world (worldspawn) or bot killed self... bots[index].killer_edict = NULL; } else { // store edict of player that killed this bot... bots[index].killer_edict = INDEXENT(killer_index); } } } } void BotClient_TFC_DeathMsg(void *p, int bot_index) { // this is just like the Valve DeathMsg message BotClient_Valve_DeathMsg(p, bot_index); } void BotClient_CS_DeathMsg(void *p, int bot_index) { // this is just like the Valve DeathMsg message BotClient_Valve_DeathMsg(p, bot_index); } void BotClient_Gearbox_DeathMsg(void *p, int bot_index) { // this is just like the Valve DeathMsg message BotClient_Valve_DeathMsg(p, bot_index); } void BotClient_FLF_DeathMsg(void *p, int bot_index) { // this is just like the Valve DeathMsg message BotClient_Valve_DeathMsg(p, bot_index); } void BotClient_DMC_DeathMsg(void *p, int bot_index) { // this is just like the Valve DeathMsg message BotClient_Valve_DeathMsg(p, bot_index); } // This message gets sent when a text message is displayed void BotClient_TFC_TextMsg(void *p, int bot_index) { static int state = 0; // current state machine state static int msg_dest = 0; if (p == NULL) // handle pfnMessageEnd case { state = 0; return; } if (state == 0) { state++; msg_dest = *(int *)p; // HUD_PRINTCENTER, etc. } else if (state == 1) { if (strcmp((char *)p, "#Sentry_finish") == 0) // sentry gun built { bots[bot_index].sentrygun_level = 1; } else if (strcmp((char *)p, "#Sentry_upgrade") == 0) // sentry gun upgraded { bots[bot_index].sentrygun_level += 1; bots[bot_index].pBotEnemy = NULL; // don't attack it anymore bots[bot_index].enemy_attack_count = 0; } else if (strcmp((char *)p, "#Sentry_destroyed") == 0) // sentry gun destroyed { bots[bot_index].sentrygun_waypoint = -1; bots[bot_index].sentrygun_level = 0; } else if (strcmp((char *)p, "#Dispenser_finish") == 0) // dispenser built { bots[bot_index].dispenser_built = 1; } else if (strcmp((char *)p, "#Dispenser_destroyed") == 0) // dispenser destroyed { bots[bot_index].dispenser_waypoint = -1; bots[bot_index].dispenser_built = 0; } } } // This message gets sent when a text message is displayed void BotClient_FLF_TextMsg(void *p, int bot_index) { static int state = 0; // current state machine state static int msg_dest = 0; if (p == NULL) { state = 0; return; } if (state == 0) { state++; msg_dest = *(int *)p; // HUD_PRINTCENTER, etc. } else if (state == 1) { if (strcmp((char *)p, "You are Attacking\n") == 0) // attacker msg { bots[bot_index].defender = 0; // attacker } else if (strcmp((char *)p, "You are Defending\n") == 0) // defender msg { bots[bot_index].defender = 1; // defender } } } // This message gets sent when the WarmUpTime is enabled/disabled void BotClient_FLF_WarmUp(void *p, int bot_index) { bots[bot_index].warmup = *(int *)p; } // This message gets sent to ALL when the WarmUpTime is enabled/disabled void BotClient_FLF_WarmUpAll(void *p, int bot_index) { for (int i=0; i < 32; i++) { if (bots[i].is_used) // count the number of bots in use bots[i].warmup = *(int *)p; } } // This message gets sent when the round is over void BotClient_FLF_WinMessage(void *p, int bot_index) { for (int i=0; i < 32; i++) { if (bots[i].is_used) // count the number of bots in use bots[i].round_end = 1; } } // This message gets sent when a weapon is hidden or restored void BotClient_FLF_HideWeapon(void *p, int bot_index) { int hide; hide = *(int *)p; if ((hide == 0) && (bots[bot_index].b_use_capture)) { bots[bot_index].b_use_capture = FALSE; bots[bot_index].f_use_capture_time = 0.0; } if ((hide) && (bots[bot_index].b_use_capture)) bots[bot_index].f_use_capture_time = gpGlobals->time + 30; } void BotClient_Valve_ScreenFade(void *p, int bot_index) { static int state = 0; // current state machine state static int duration; static int hold_time; static int fade_flags; int length; if (state == 0) { state++; duration = *(int *)p; } else if (state == 1) { state++; hold_time = *(int *)p; } else if (state == 2) { state++; fade_flags = *(int *)p; } else if (state == 6) { state = 0; length = (duration + hold_time) / 4096; bots[bot_index].blinded_time = gpGlobals->time + length - 2.0; } else { state++; } } void BotClient_TFC_ScreenFade(void *p, int bot_index) { // this is just like the Valve ScreenFade message BotClient_Valve_ScreenFade(p, bot_index); } void BotClient_CS_ScreenFade(void *p, int bot_index) { // this is just like the Valve ScreenFade message BotClient_Valve_ScreenFade(p, bot_index); } void BotClient_Gearbox_ScreenFade(void *p, int bot_index) { // this is just like the Valve ScreenFade message BotClient_Valve_ScreenFade(p, bot_index); } void BotClient_FLF_ScreenFade(void *p, int bot_index) { // this is just like the Valve ScreenFade message BotClient_Valve_ScreenFade(p, bot_index); } void BotClient_HolyWars_Halo(void *p, int edict) { int type = *(int *)p; if (type == 0) // wait for halo to respawn { holywars_saint = NULL; halo_status = HW_WAIT_SPAWN; } else if (type == 1) // there's no saint { holywars_saint = NULL; } else if (type == 2) // there's a new saint { halo_status = HW_NEW_SAINT; } else if (type == 3) // you are the new saint { holywars_saint = (edict_t *)edict; halo_status = HW_NEW_SAINT; } } void BotClient_HolyWars_GameMode(void *p, int bot_index) { int mode = *(int *)p; holywars_gamemode = mode; } void BotClient_HolyWars_HudText(void *p, int bot_index) { if (strncmp((char *)p, "Voting for", 10) == 0) { bots[bot_index].vote_in_progress = TRUE; bots[bot_index].f_vote_time = gpGlobals->time + RANDOM_LONG(2.0, 5.0); } }