499 lines
15 KiB
C++
499 lines
15 KiB
C++
//
|
|
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
|
|
// Copyright (c) YaPB Development Team.
|
|
//
|
|
// This software is licensed under the BSD-style license.
|
|
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
// http://yapb.jeefo.net/license
|
|
//
|
|
|
|
#include <core.h>
|
|
|
|
NetworkMsg::NetworkMsg (void)
|
|
{
|
|
m_message = NETMSG_UNDEFINED;
|
|
m_state = 0;
|
|
m_bot = NULL;
|
|
|
|
for (int i = 0; i < NETMSG_NUM; i++)
|
|
m_registerdMessages[i] = -1;
|
|
}
|
|
|
|
void NetworkMsg::HandleMessageIfRequired (int messageType, int requiredType)
|
|
{
|
|
if (messageType == m_registerdMessages[requiredType])
|
|
SetMessage (requiredType);
|
|
}
|
|
|
|
void NetworkMsg::Execute (void *p)
|
|
{
|
|
if (m_message == NETMSG_UNDEFINED)
|
|
return; // no message or not for bot, return
|
|
|
|
// some needed variables
|
|
static byte r, g, b;
|
|
static byte enabled;
|
|
|
|
static int damageArmor, damageTaken, damageBits;
|
|
static int killerIndex, victimIndex, playerIndex;
|
|
static int index, numPlayers;
|
|
static int state, id, clip;
|
|
|
|
static Vector damageOrigin;
|
|
static WeaponProperty weaponProp;
|
|
|
|
// now starts of netmessage execution
|
|
switch (m_message)
|
|
{
|
|
case NETMSG_VGUI:
|
|
// this message is sent when a VGUI menu is displayed.
|
|
|
|
if (m_state == 0)
|
|
{
|
|
switch (PTR_TO_INT (p))
|
|
{
|
|
case VMS_TEAM:
|
|
m_bot->m_startAction = GSM_TEAM_SELECT;
|
|
break;
|
|
|
|
case VMS_TF:
|
|
case VMS_CT:
|
|
m_bot->m_startAction = GSM_CLASS_SELECT;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case NETMSG_SHOWMENU:
|
|
// this message is sent when a text menu is displayed.
|
|
|
|
if (m_state < 3) // ignore first 3 fields of message
|
|
break;
|
|
|
|
if (strcmp (PTR_TO_STR (p), "#Team_Select") == 0) // team select menu?
|
|
m_bot->m_startAction = GSM_TEAM_SELECT;
|
|
else if (strcmp (PTR_TO_STR (p), "#Team_Select_Spect") == 0) // team select menu?
|
|
m_bot->m_startAction = GSM_TEAM_SELECT;
|
|
else if (strcmp (PTR_TO_STR (p), "#IG_Team_Select_Spect") == 0) // team select menu?
|
|
m_bot->m_startAction = GSM_TEAM_SELECT;
|
|
else if (strcmp (PTR_TO_STR (p), "#IG_Team_Select") == 0) // team select menu?
|
|
m_bot->m_startAction = GSM_TEAM_SELECT;
|
|
else if (strcmp (PTR_TO_STR (p), "#IG_VIP_Team_Select") == 0) // team select menu?
|
|
m_bot->m_startAction = GSM_TEAM_SELECT;
|
|
else if (strcmp (PTR_TO_STR (p), "#IG_VIP_Team_Select_Spect") == 0) // team select menu?
|
|
m_bot->m_startAction = GSM_TEAM_SELECT;
|
|
else if (strcmp (PTR_TO_STR (p), "#Terrorist_Select") == 0) // T model select?
|
|
m_bot->m_startAction = GSM_CLASS_SELECT;
|
|
else if (strcmp (PTR_TO_STR (p), "#CT_Select") == 0) // CT model select menu?
|
|
m_bot->m_startAction = GSM_CLASS_SELECT;
|
|
|
|
break;
|
|
|
|
case NETMSG_WEAPONLIST:
|
|
// 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.
|
|
|
|
switch (m_state)
|
|
{
|
|
case 0:
|
|
strncpy (weaponProp.className, PTR_TO_STR (p), SIZEOF_CHAR (weaponProp.className));
|
|
break;
|
|
|
|
case 1:
|
|
weaponProp.ammo1 = PTR_TO_INT (p); // ammo index 1
|
|
break;
|
|
|
|
case 2:
|
|
weaponProp.ammo1Max = PTR_TO_INT (p); // max ammo 1
|
|
break;
|
|
|
|
case 5:
|
|
weaponProp.slotID = PTR_TO_INT (p); // slot for this weapon
|
|
break;
|
|
|
|
case 6:
|
|
weaponProp.position = PTR_TO_INT (p); // position in slot
|
|
break;
|
|
|
|
case 7:
|
|
weaponProp.id = PTR_TO_INT (p); // weapon ID
|
|
break;
|
|
|
|
case 8:
|
|
weaponProp.flags = PTR_TO_INT (p); // flags for weapon (WTF???)
|
|
g_weaponDefs[weaponProp.id] = weaponProp; // store away this weapon with it's ammo information...
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case NETMSG_CURWEAPON:
|
|
// 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). In CS it's also called when Ammo is increased/decreased
|
|
|
|
switch (m_state)
|
|
{
|
|
case 0:
|
|
state = PTR_TO_INT (p); // state of the current weapon (WTF???)
|
|
break;
|
|
|
|
case 1:
|
|
id = PTR_TO_INT (p); // weapon ID of current weapon
|
|
break;
|
|
|
|
case 2:
|
|
clip = PTR_TO_INT (p); // ammo currently in the clip for this weapon
|
|
|
|
if (id <= 31)
|
|
{
|
|
if (state != 0)
|
|
m_bot->m_currentWeapon = id;
|
|
|
|
// ammo amount decreased ? must have fired a bullet...
|
|
if (id == m_bot->m_currentWeapon && m_bot->m_ammoInClip[id] > clip)
|
|
m_bot->m_timeLastFired = engine.Time (); // remember the last bullet time
|
|
|
|
m_bot->m_ammoInClip[id] = clip;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case NETMSG_AMMOX:
|
|
// this message is sent whenever ammo amounts are adjusted (up or down). NOTE: Logging reveals that CS uses it very unreliable!
|
|
|
|
switch (m_state)
|
|
{
|
|
case 0:
|
|
index = PTR_TO_INT (p); // ammo index (for type of ammo)
|
|
break;
|
|
|
|
case 1:
|
|
m_bot->m_ammo[index] = PTR_TO_INT (p); // store it away
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case NETMSG_AMMOPICKUP:
|
|
// this message is sent when the bot picks up some ammo (AmmoX messages are also sent so this message is probably
|
|
// not really necessary except it allows the HUD to draw pictures of ammo that have been picked up. The bots
|
|
// don't really need pictures since they don't have any eyes anyway.
|
|
|
|
switch (m_state)
|
|
{
|
|
case 0:
|
|
index = PTR_TO_INT (p);
|
|
break;
|
|
|
|
case 1:
|
|
m_bot->m_ammo[index] = PTR_TO_INT (p);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case NETMSG_DAMAGE:
|
|
// this message gets sent when the bots are getting damaged.
|
|
|
|
switch (m_state)
|
|
{
|
|
case 0:
|
|
damageArmor = PTR_TO_INT (p);
|
|
break;
|
|
|
|
case 1:
|
|
damageTaken = PTR_TO_INT (p);
|
|
break;
|
|
|
|
case 2:
|
|
damageBits = PTR_TO_INT (p);
|
|
|
|
if (m_bot != NULL && (damageArmor > 0 || damageTaken > 0))
|
|
m_bot->TakeDamage (m_bot->pev->dmg_inflictor, damageTaken, damageArmor, damageBits);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case NETMSG_MONEY:
|
|
// this message gets sent when the bots money amount changes
|
|
|
|
if (m_state == 0)
|
|
m_bot->m_moneyAmount = PTR_TO_INT (p); // amount of money
|
|
break;
|
|
|
|
case NETMSG_STATUSICON:
|
|
switch (m_state)
|
|
{
|
|
case 0:
|
|
enabled = PTR_TO_BYTE (p);
|
|
break;
|
|
|
|
case 1:
|
|
if (strcmp (PTR_TO_STR (p), "defuser") == 0)
|
|
m_bot->m_hasDefuser = (enabled != 0);
|
|
else if (strcmp (PTR_TO_STR (p), "buyzone") == 0)
|
|
{
|
|
m_bot->m_inBuyZone = (enabled != 0);
|
|
|
|
// try to equip in buyzone
|
|
m_bot->EquipInBuyzone (BUYSTATE_PRIMARY_WEAPON);
|
|
}
|
|
else if (strcmp (PTR_TO_STR (p), "vipsafety") == 0)
|
|
m_bot->m_inVIPZone = (enabled != 0);
|
|
else if (strcmp (PTR_TO_STR (p), "c4") == 0)
|
|
m_bot->m_inBombZone = (enabled == 2);
|
|
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case NETMSG_DEATH: // this message sends on death
|
|
switch (m_state)
|
|
{
|
|
case 0:
|
|
killerIndex = PTR_TO_INT (p);
|
|
break;
|
|
|
|
case 1:
|
|
victimIndex = PTR_TO_INT (p);
|
|
break;
|
|
|
|
case 2:
|
|
bots.SetDeathMsgState (true);
|
|
|
|
if (killerIndex != 0 && killerIndex != victimIndex)
|
|
{
|
|
edict_t *killer = engine.EntityOfIndex (killerIndex);
|
|
edict_t *victim = engine.EntityOfIndex (victimIndex);
|
|
|
|
if (engine.IsNullEntity (killer) || engine.IsNullEntity (victim))
|
|
break;
|
|
|
|
if (yb_communication_type.GetInt () == 2)
|
|
{
|
|
// need to send congrats on well placed shot
|
|
for (int i = 0; i < engine.MaxClients (); i++)
|
|
{
|
|
Bot *bot = bots.GetBot (i);
|
|
|
|
if (bot != NULL && bot->m_notKilled && killer != bot->GetEntity () && bot->EntityIsVisible (victim->v.origin) && engine.GetTeam (killer) == bot->m_team && engine.GetTeam (killer) != engine.GetTeam (victim))
|
|
{
|
|
if (killer == g_hostEntity)
|
|
bot->HandleChatterMessage ("#Bot_NiceShotCommander");
|
|
else
|
|
bot->HandleChatterMessage ("#Bot_NiceShotPall");
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// notice nearby to victim teammates, that attacker is near
|
|
for (int i = 0; i < engine.MaxClients (); i++)
|
|
{
|
|
Bot *bot = bots.GetBot (i);
|
|
|
|
if (bot != NULL && bot->m_seeEnemyTime + 2.0f < engine.Time () && bot->m_notKilled && bot->m_team == engine.GetTeam (victim) && IsVisible (killer->v.origin, bot->GetEntity ()) && engine.IsNullEntity (bot->m_enemy) && engine.GetTeam (killer) != engine.GetTeam (victim))
|
|
{
|
|
bot->m_actualReactionTime = 0.0f;
|
|
bot->m_seeEnemyTime = engine.Time ();
|
|
bot->m_enemy = killer;
|
|
bot->m_lastEnemy = killer;
|
|
bot->m_lastEnemyOrigin = killer->v.origin;
|
|
}
|
|
}
|
|
|
|
Bot *bot = bots.GetBot (killer);
|
|
|
|
// is this message about a bot who killed somebody?
|
|
if (bot != NULL)
|
|
bot->m_lastVictim = victim;
|
|
|
|
else // did a human kill a bot on his team?
|
|
{
|
|
Bot *target = bots.GetBot (victim);
|
|
|
|
if (target != NULL)
|
|
{
|
|
if (engine.GetTeam (killer) == engine.GetTeam (victim))
|
|
target->m_voteKickIndex = killerIndex;
|
|
|
|
target->m_notKilled = false;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case NETMSG_SCREENFADE: // this message gets sent when the Screen fades (Flashbang)
|
|
switch (m_state)
|
|
{
|
|
case 3:
|
|
r = PTR_TO_BYTE (p);
|
|
break;
|
|
|
|
case 4:
|
|
g = PTR_TO_BYTE (p);
|
|
break;
|
|
|
|
case 5:
|
|
b = PTR_TO_BYTE (p);
|
|
break;
|
|
|
|
case 6:
|
|
m_bot->TakeBlinded (Vector (r, g, b), PTR_TO_BYTE (p));
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case NETMSG_HLTV: // round restart in steam cs
|
|
switch (m_state)
|
|
{
|
|
case 0:
|
|
numPlayers = PTR_TO_INT (p);
|
|
break;
|
|
|
|
case 1:
|
|
if (numPlayers == 0 && PTR_TO_INT (p) == 0)
|
|
RoundInit ();
|
|
break;
|
|
}
|
|
break;
|
|
|
|
|
|
case NETMSG_RESETHUD:
|
|
#if 0
|
|
if (m_bot != NULL)
|
|
m_bot->NewRound ();
|
|
#endif
|
|
break;
|
|
|
|
case NETMSG_TEXTMSG:
|
|
if (m_state == 1)
|
|
{
|
|
if (FStrEq (PTR_TO_STR (p), "#CTs_Win") ||
|
|
FStrEq (PTR_TO_STR (p), "#Bomb_Defused") ||
|
|
FStrEq (PTR_TO_STR (p), "#Terrorists_Win") ||
|
|
FStrEq (PTR_TO_STR (p), "#Round_Draw") ||
|
|
FStrEq (PTR_TO_STR (p), "#All_Hostages_Rescued") ||
|
|
FStrEq (PTR_TO_STR (p), "#Target_Saved") ||
|
|
FStrEq (PTR_TO_STR (p), "#Hostages_Not_Rescued") ||
|
|
FStrEq (PTR_TO_STR (p), "#Terrorists_Not_Escaped") ||
|
|
FStrEq (PTR_TO_STR (p), "#VIP_Not_Escaped") ||
|
|
FStrEq (PTR_TO_STR (p), "#Escaping_Terrorists_Neutralized") ||
|
|
FStrEq (PTR_TO_STR (p), "#VIP_Assassinated") ||
|
|
FStrEq (PTR_TO_STR (p), "#VIP_Escaped") ||
|
|
FStrEq (PTR_TO_STR (p), "#Terrorists_Escaped") ||
|
|
FStrEq (PTR_TO_STR (p), "#CTs_PreventEscape") ||
|
|
FStrEq (PTR_TO_STR (p), "#Target_Bombed") ||
|
|
FStrEq (PTR_TO_STR (p), "#Game_Commencing") ||
|
|
FStrEq (PTR_TO_STR (p), "#Game_will_restart_in"))
|
|
{
|
|
g_roundEnded = true;
|
|
|
|
if (FStrEq (PTR_TO_STR (p), "#Game_Commencing"))
|
|
g_isCommencing = true;
|
|
|
|
if (FStrEq (PTR_TO_STR (p), "#CTs_Win"))
|
|
{
|
|
bots.SetLastWinner (CT); // update last winner for economics
|
|
|
|
if (yb_communication_type.GetInt () == 2)
|
|
{
|
|
Bot *bot = bots.FindOneValidAliveBot ();
|
|
|
|
if (bot != NULL && bot->m_notKilled)
|
|
bot->HandleChatterMessage (PTR_TO_STR (p));
|
|
}
|
|
}
|
|
|
|
if (FStrEq (PTR_TO_STR (p), "#Game_will_restart_in"))
|
|
{
|
|
bots.CheckTeamEconomics (CT, true);
|
|
bots.CheckTeamEconomics (TERRORIST, true);
|
|
}
|
|
|
|
if (FStrEq (PTR_TO_STR (p), "#Terrorists_Win"))
|
|
{
|
|
bots.SetLastWinner (TERRORIST); // update last winner for economics
|
|
|
|
if (yb_communication_type.GetInt () == 2)
|
|
{
|
|
Bot *bot = bots.FindOneValidAliveBot ();
|
|
|
|
if (bot != NULL && bot->m_notKilled)
|
|
bot->HandleChatterMessage (PTR_TO_STR (p));
|
|
}
|
|
}
|
|
waypoints.SetBombPosition (true);
|
|
}
|
|
else if (!g_bombPlanted && FStrEq (PTR_TO_STR (p), "#Bomb_Planted"))
|
|
{
|
|
waypoints.SetBombPosition ();
|
|
|
|
g_bombPlanted = g_bombSayString = true;
|
|
g_timeBombPlanted = engine.Time ();
|
|
|
|
for (int i = 0; i < engine.MaxClients (); i++)
|
|
{
|
|
Bot *bot = bots.GetBot (i);
|
|
|
|
if (bot != NULL && bot->m_notKilled)
|
|
{
|
|
bot->DeleteSearchNodes ();
|
|
bot->ResetTasks ();
|
|
|
|
if (yb_communication_type.GetInt () == 2 && Random.Long (0, 100) < 75 && bot->m_team == CT)
|
|
bot->ChatterMessage (Chatter_WhereIsTheBomb);
|
|
}
|
|
}
|
|
}
|
|
else if (m_bot != NULL && FStrEq (PTR_TO_STR (p), "#Switch_To_BurstFire"))
|
|
m_bot->m_weaponBurstMode = BM_ON;
|
|
else if (m_bot != NULL && FStrEq (PTR_TO_STR (p), "#Switch_To_SemiAuto"))
|
|
m_bot->m_weaponBurstMode = BM_OFF;
|
|
}
|
|
break;
|
|
|
|
case NETMSG_SCOREINFO:
|
|
switch (m_state)
|
|
{
|
|
case 0:
|
|
playerIndex = PTR_TO_INT (p);
|
|
break;
|
|
|
|
case 4:
|
|
if (playerIndex >= 0 && playerIndex <= engine.MaxClients ())
|
|
{
|
|
#ifndef XASH_CSDM
|
|
Client &cl = g_clients[playerIndex - 1];
|
|
|
|
if (PTR_TO_INT (p) == 1)
|
|
cl.realTeam = TERRORIST;
|
|
else if (PTR_TO_INT (p) == 2)
|
|
cl.realTeam = CT;
|
|
else
|
|
cl.realTeam = SPECTATOR;
|
|
|
|
if (yb_csdm_mode.GetInt () == 2)
|
|
cl.team = playerIndex;
|
|
else
|
|
cl.team = g_clients[playerIndex - 1].realTeam;
|
|
#endif
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case NETMSG_BARTIME:
|
|
if (m_state == 0)
|
|
{
|
|
if (PTR_TO_INT (p) > 0)
|
|
m_bot->m_hasProgressBar = true; // the progress bar on a hud
|
|
else if (PTR_TO_INT (p) == 0)
|
|
m_bot->m_hasProgressBar = false; // no progress bar or disappeared
|
|
}
|
|
break;
|
|
|
|
default:
|
|
AddLogEntry (true, LL_FATAL, "Network message handler error. Call to unrecognized message id (%d).\n", m_message);
|
|
}
|
|
m_state++; // and finally update network message state
|
|
}
|