You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2479 lines
71 KiB
2479 lines
71 KiB
// |
|
// HPB bot - botman's High Ping Bastard bot |
|
// |
|
// (http://planethalflife.com/botman/) |
|
// |
|
// dll.cpp |
|
// |
|
|
|
#include "extdll.h" |
|
#include "enginecallback.h" |
|
#include "util.h" |
|
#include "cbase.h" |
|
#include "entity_state.h" |
|
#include "usercmd.h" |
|
|
|
#include "bot.h" |
|
#include "bot_func.h" |
|
#include "waypoint.h" |
|
|
|
|
|
#define VER_MAJOR 3 |
|
#define VER_MINOR 0 |
|
|
|
|
|
#define MENU_NONE 0 |
|
#define MENU_1 1 |
|
#define MENU_2 2 |
|
#define MENU_3 3 |
|
#define MENU_4 4 |
|
|
|
|
|
extern GETENTITYAPI other_GetEntityAPI; |
|
extern GETNEWDLLFUNCTIONS other_GetNewDLLFunctions; |
|
extern enginefuncs_t g_engfuncs; |
|
extern int debug_engine; |
|
extern globalvars_t *gpGlobals; |
|
extern char *g_argv; |
|
extern bool g_waypoint_on; |
|
extern bool g_auto_waypoint; |
|
extern bool g_path_waypoint; |
|
extern bool g_path_waypoint_enable; |
|
extern int num_waypoints; // number of waypoints currently in use |
|
extern WAYPOINT waypoints[MAX_WAYPOINTS]; |
|
extern float wp_display_time[MAX_WAYPOINTS]; |
|
extern bot_t bots[32]; |
|
extern bool b_observer_mode; |
|
extern bool b_botdontshoot; |
|
extern char welcome_msg[80]; |
|
|
|
static FILE *fp; |
|
|
|
DLL_FUNCTIONS other_gFunctionTable; |
|
DLL_GLOBAL const Vector g_vecZero = Vector(0,0,0); |
|
|
|
int mod_id = 0; |
|
int m_spriteTexture = 0; |
|
int default_bot_skill = 2; |
|
int bot_strafe_percent = 20; // percent of time to strafe |
|
int bot_chat_percent = 10; // percent of time to chat |
|
int bot_taunt_percent = 20; // percent of time to taunt after kill |
|
int bot_whine_percent = 10; // percent of time to whine after death |
|
int bot_grenade_time = 15; // seconds between grenade throws |
|
int bot_logo_percent = 40; // percent of time to spray logo after kill |
|
|
|
int bot_chat_tag_percent = 80; // percent of the time to drop clan tag |
|
int bot_chat_drop_percent = 10; // percent of the time to drop characters |
|
int bot_chat_swap_percent = 10; // percent of the time to swap characters |
|
int bot_chat_lower_percent = 50; // percent of the time to lowercase chat |
|
|
|
bool b_random_color = TRUE; |
|
int isFakeClientCommand = 0; |
|
int fake_arg_count; |
|
int IsDedicatedServer; |
|
float bot_check_time = 60.0; |
|
int bot_reaction_time = 2; |
|
int min_bots = -1; |
|
int max_bots = -1; |
|
int num_bots = 0; |
|
int prev_num_bots = 0; |
|
bool g_GameRules = FALSE; |
|
edict_t *clients[32]; |
|
edict_t *listenserver_edict = NULL; |
|
float welcome_time = 0.0; |
|
bool welcome_sent = FALSE; |
|
int g_menu_waypoint; |
|
int g_menu_state = 0; |
|
int bot_stop = 0; |
|
int jumppad_off = 0; |
|
|
|
bool is_team_play = FALSE; |
|
char team_names[MAX_TEAMS][MAX_TEAMNAME_LENGTH]; |
|
int num_teams = 0; |
|
bool checked_teamplay = FALSE; |
|
edict_t *pent_info_tfdetect = NULL; |
|
edict_t *pent_info_ctfdetect = NULL; |
|
edict_t *pent_info_frontline = NULL; |
|
edict_t *pent_item_tfgoal = NULL; |
|
edict_t *pent_info_tfgoal = NULL; |
|
int max_team_players[4]; |
|
int team_class_limits[4]; |
|
int team_allies[4]; // bit mapped allies BLUE, RED, YELLOW, and GREEN |
|
int max_teams = 0; |
|
int num_flags = 0; |
|
FLAG_S flags[MAX_FLAGS]; |
|
int num_backpacks = 0; |
|
BACKPACK_S backpacks[MAX_BACKPACKS]; |
|
|
|
FILE *bot_cfg_fp = NULL; |
|
bool need_to_open_cfg = TRUE; |
|
float bot_cfg_pause_time = 0.0; |
|
float respawn_time = 0.0; |
|
bool spawn_time_reset = FALSE; |
|
|
|
|
|
cvar_t sv_bot = {"HPB_bot",""}; |
|
|
|
char *show_menu_none = {" "}; |
|
char *show_menu_1 = |
|
{"Waypoint Tags\n\n1. Team Specific\n2. Wait for Lift\n3. Door\n4. Sniper Spot\n5. More..."}; |
|
char *show_menu_2 = |
|
{"Waypoint Tags\n\n1. Team 1\n2. Team 2\n3. Team 3\n4. Team 4\n5. CANCEL"}; |
|
char *show_menu_2_flf = |
|
{"Waypoint Tags\n\n1. Attackers\n2. Defenders\n\n5. CANCEL"}; |
|
char *show_menu_3 = |
|
{"Waypoint Tags\n\n1. Flag Location\n2. Flag Goal Location\n3. Sentry gun\n4. Dispenser\n5. More"}; |
|
char *show_menu_3_flf = |
|
{"Waypoint Tags\n\n1. Capture Point\n2. Defend Point\n3. Prone\n\n5. CANCEL"}; |
|
char *show_menu_3_hw = |
|
{"Waypoint Tags\n\n1. Halo Location\n\n\n\n5. More"}; |
|
char *show_menu_4 = |
|
{"Waypoint Tags\n\n1. Health\n2. Armor\n3. Ammo\n4. Jump\n5. CANCEL"}; |
|
|
|
|
|
void BotNameInit(void); |
|
void BotLogoInit(void); |
|
void UpdateClientData(const struct edict_s *ent, int sendweapons, struct clientdata_s *cd); |
|
void ProcessBotCfgFile(void); |
|
|
|
extern void welcome_init(void); |
|
|
|
|
|
void GameDLLInit( void ) |
|
{ |
|
int i; |
|
|
|
CVAR_REGISTER (&sv_bot); |
|
|
|
IsDedicatedServer = IS_DEDICATED_SERVER(); |
|
|
|
for (i=0; i<32; i++) |
|
clients[i] = NULL; |
|
|
|
welcome_init(); |
|
|
|
// initialize the bots array of structures... |
|
memset(bots, 0, sizeof(bots)); |
|
|
|
BotNameInit(); |
|
BotLogoInit(); |
|
|
|
LoadBotChat(); |
|
LoadBotModels(); |
|
|
|
(*other_gFunctionTable.pfnGameInit)(); |
|
} |
|
|
|
int DispatchSpawn( edict_t *pent ) |
|
{ |
|
int index; |
|
|
|
if (gpGlobals->deathmatch) |
|
{ |
|
char *pClassname = (char *)STRING(pent->v.classname); |
|
|
|
if (debug_engine) |
|
{ |
|
fp=fopen("HPB_bot.txt","a"); |
|
fprintf(fp, "DispatchSpawn: %x %s\n",pent,pClassname); |
|
if (pent->v.model != 0) |
|
fprintf(fp, " model=%s\n",STRING(pent->v.model)); |
|
fclose(fp); |
|
} |
|
|
|
if (strcmp(pClassname, "worldspawn") == 0) |
|
{ |
|
// do level initialization stuff here... |
|
|
|
WaypointInit(); |
|
WaypointLoad(NULL); |
|
|
|
pent_info_tfdetect = NULL; |
|
pent_info_ctfdetect = NULL; |
|
pent_info_frontline = NULL; |
|
pent_item_tfgoal = NULL; |
|
pent_info_tfgoal = NULL; |
|
|
|
for (index=0; index < 4; index++) |
|
{ |
|
max_team_players[index] = 0; // no player limit |
|
team_class_limits[index] = 0; // no class limits |
|
team_allies[index] = 0; |
|
} |
|
|
|
max_teams = 0; |
|
num_flags = 0; |
|
|
|
for (index=0; index < MAX_FLAGS; index++) |
|
{ |
|
flags[index].edict = NULL; |
|
flags[index].team_no = 0; // any team unless specified |
|
} |
|
|
|
num_backpacks = 0; |
|
|
|
for (index=0; index < MAX_BACKPACKS; index++) |
|
{ |
|
backpacks[index].edict = NULL; |
|
backpacks[index].armor = 0; |
|
backpacks[index].health = 0; |
|
backpacks[index].ammo = 0; |
|
backpacks[index].team = 0; // any team unless specified |
|
} |
|
|
|
PRECACHE_SOUND("weapons/xbow_hit1.wav"); // waypoint add |
|
PRECACHE_SOUND("weapons/mine_activate.wav"); // waypoint delete |
|
PRECACHE_SOUND("common/wpn_hudoff.wav"); // path add/delete start |
|
PRECACHE_SOUND("common/wpn_hudon.wav"); // path add/delete done |
|
PRECACHE_SOUND("common/wpn_moveselect.wav"); // path add/delete cancel |
|
PRECACHE_SOUND("common/wpn_denyselect.wav"); // path add/delete error |
|
PRECACHE_SOUND("player/sprayer.wav"); // logo spray sound |
|
|
|
m_spriteTexture = PRECACHE_MODEL( "sprites/lgtning.spr"); |
|
|
|
g_GameRules = TRUE; |
|
|
|
is_team_play = FALSE; |
|
memset(team_names, 0, sizeof(team_names)); |
|
num_teams = 0; |
|
checked_teamplay = FALSE; |
|
|
|
bot_cfg_pause_time = 0.0; |
|
respawn_time = 0.0; |
|
spawn_time_reset = FALSE; |
|
|
|
prev_num_bots = num_bots; |
|
num_bots = 0; |
|
|
|
bot_check_time = gpGlobals->time + 60.0; |
|
} |
|
|
|
if ((mod_id == HOLYWARS_DLL) && (jumppad_off) && |
|
(strcmp(pClassname, "trigger_jumppad") == 0)) |
|
{ |
|
return -1; // disable jumppads |
|
} |
|
} |
|
|
|
return (*other_gFunctionTable.pfnSpawn)(pent); |
|
} |
|
|
|
void DispatchThink( edict_t *pent ) |
|
{ |
|
(*other_gFunctionTable.pfnThink)(pent); |
|
} |
|
|
|
void DispatchUse( edict_t *pentUsed, edict_t *pentOther ) |
|
{ |
|
(*other_gFunctionTable.pfnUse)(pentUsed, pentOther); |
|
} |
|
|
|
void DispatchTouch( edict_t *pentTouched, edict_t *pentOther ) |
|
{ |
|
(*other_gFunctionTable.pfnTouch)(pentTouched, pentOther); |
|
} |
|
|
|
void DispatchBlocked( edict_t *pentBlocked, edict_t *pentOther ) |
|
{ |
|
(*other_gFunctionTable.pfnBlocked)(pentBlocked, pentOther); |
|
} |
|
|
|
void DispatchKeyValue( edict_t *pentKeyvalue, KeyValueData *pkvd ) |
|
{ |
|
static edict_t *temp_pent; |
|
static int flag_index; |
|
static int backpack_index; |
|
|
|
if (debug_engine) |
|
{ |
|
fp=fopen("HPB_bot.txt","a"); fprintf(fp, "DispatchKeyValue: %x %s=%s\n",pentKeyvalue,pkvd->szKeyName,pkvd->szValue); fclose(fp); |
|
} |
|
|
|
if (mod_id == TFC_DLL) |
|
{ |
|
if (pentKeyvalue == pent_info_tfdetect) |
|
{ |
|
if (strcmp(pkvd->szKeyName, "ammo_medikit") == 0) // max BLUE players |
|
max_team_players[0] = atoi(pkvd->szValue); |
|
else if (strcmp(pkvd->szKeyName, "ammo_detpack") == 0) // max RED players |
|
max_team_players[1] = atoi(pkvd->szValue); |
|
else if (strcmp(pkvd->szKeyName, "maxammo_medikit") == 0) // max YELLOW players |
|
max_team_players[2] = atoi(pkvd->szValue); |
|
else if (strcmp(pkvd->szKeyName, "maxammo_detpack") == 0) // max GREEN players |
|
max_team_players[3] = atoi(pkvd->szValue); |
|
|
|
else if (strcmp(pkvd->szKeyName, "maxammo_shells") == 0) // BLUE class limits |
|
team_class_limits[0] = atoi(pkvd->szValue); |
|
else if (strcmp(pkvd->szKeyName, "maxammo_nails") == 0) // RED class limits |
|
team_class_limits[1] = atoi(pkvd->szValue); |
|
else if (strcmp(pkvd->szKeyName, "maxammo_rockets") == 0) // YELLOW class limits |
|
team_class_limits[2] = atoi(pkvd->szValue); |
|
else if (strcmp(pkvd->szKeyName, "maxammo_cells") == 0) // GREEN class limits |
|
team_class_limits[3] = atoi(pkvd->szValue); |
|
|
|
else if (strcmp(pkvd->szKeyName, "team1_allies") == 0) // BLUE allies |
|
team_allies[0] = atoi(pkvd->szValue); |
|
else if (strcmp(pkvd->szKeyName, "team2_allies") == 0) // RED allies |
|
team_allies[1] = atoi(pkvd->szValue); |
|
else if (strcmp(pkvd->szKeyName, "team3_allies") == 0) // YELLOW allies |
|
team_allies[2] = atoi(pkvd->szValue); |
|
else if (strcmp(pkvd->szKeyName, "team4_allies") == 0) // GREEN allies |
|
team_allies[3] = atoi(pkvd->szValue); |
|
} |
|
else if (pent_info_tfdetect == NULL) |
|
{ |
|
if ((strcmp(pkvd->szKeyName, "classname") == 0) && |
|
(strcmp(pkvd->szValue, "info_tfdetect") == 0)) |
|
{ |
|
pent_info_tfdetect = pentKeyvalue; |
|
} |
|
} |
|
|
|
if (pentKeyvalue == pent_item_tfgoal) |
|
{ |
|
if (strcmp(pkvd->szKeyName, "team_no") == 0) |
|
flags[flag_index].team_no = atoi(pkvd->szValue); |
|
|
|
if ((strcmp(pkvd->szKeyName, "mdl") == 0) && |
|
((strcmp(pkvd->szValue, "models/flag.mdl") == 0) || |
|
(strcmp(pkvd->szValue, "models/keycard.mdl") == 0) || |
|
(strcmp(pkvd->szValue, "models/ball.mdl") == 0))) |
|
{ |
|
num_flags++; |
|
} |
|
} |
|
else if (pent_item_tfgoal == NULL) |
|
{ |
|
if ((strcmp(pkvd->szKeyName, "classname") == 0) && |
|
(strcmp(pkvd->szValue, "item_tfgoal") == 0)) |
|
{ |
|
if (num_flags < MAX_FLAGS) |
|
{ |
|
pent_item_tfgoal = pentKeyvalue; |
|
|
|
flags[num_flags].edict = pentKeyvalue; |
|
|
|
flag_index = num_flags; // in case the mdl comes before team_no |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
pent_item_tfgoal = NULL; // reset for non-flag item_tfgoal's |
|
} |
|
|
|
|
|
if (pentKeyvalue != pent_info_tfgoal) // different edict? |
|
{ |
|
pent_info_tfgoal = NULL; // reset |
|
} |
|
|
|
if (pentKeyvalue == pent_info_tfgoal) |
|
{ |
|
if (strcmp(pkvd->szKeyName, "team_no") == 0) |
|
backpacks[backpack_index].team = atoi(pkvd->szValue); |
|
|
|
if (strcmp(pkvd->szKeyName, "armorvalue") == 0) |
|
backpacks[backpack_index].armor = atoi(pkvd->szValue); |
|
|
|
if (strcmp(pkvd->szKeyName, "health") == 0) |
|
backpacks[backpack_index].health = atoi(pkvd->szValue); |
|
|
|
if ((strcmp(pkvd->szKeyName, "ammo_nails") == 0) || |
|
(strcmp(pkvd->szKeyName, "ammo_rockets") == 0) || |
|
(strcmp(pkvd->szKeyName, "ammo_cells") == 0) || |
|
(strcmp(pkvd->szKeyName, "ammo_shells") == 0)) |
|
backpacks[backpack_index].ammo = atoi(pkvd->szValue); |
|
|
|
if ((strcmp(pkvd->szKeyName, "mdl") == 0) && |
|
(strcmp(pkvd->szValue, "models/backpack.mdl") == 0)) |
|
{ |
|
num_backpacks++; |
|
} |
|
} |
|
else if (pent_info_tfgoal == NULL) |
|
{ |
|
if (((strcmp(pkvd->szKeyName, "classname") == 0) && |
|
(strcmp(pkvd->szValue, "info_tfgoal") == 0)) || |
|
((strcmp(pkvd->szKeyName, "classname") == 0) && |
|
(strcmp(pkvd->szValue, "i_t_g") == 0))) |
|
{ |
|
if (num_backpacks < MAX_BACKPACKS) |
|
{ |
|
pent_info_tfgoal = pentKeyvalue; |
|
|
|
backpacks[num_backpacks].edict = pentKeyvalue; |
|
|
|
// in case the mdl comes before the other fields |
|
backpack_index = num_backpacks; |
|
} |
|
} |
|
} |
|
|
|
if ((strcmp(pkvd->szKeyName, "classname") == 0) && |
|
((strcmp(pkvd->szValue, "info_player_teamspawn") == 0) || |
|
(strcmp(pkvd->szValue, "i_p_t") == 0))) |
|
{ |
|
temp_pent = pentKeyvalue; |
|
} |
|
else if (pentKeyvalue == temp_pent) |
|
{ |
|
if (strcmp(pkvd->szKeyName, "team_no") == 0) |
|
{ |
|
int value = atoi(pkvd->szValue); |
|
|
|
if (value > max_teams) |
|
max_teams = value; |
|
} |
|
} |
|
} |
|
else if (mod_id == GEARBOX_DLL) |
|
{ |
|
if (pent_info_ctfdetect == NULL) |
|
{ |
|
if ((strcmp(pkvd->szKeyName, "classname") == 0) && |
|
(strcmp(pkvd->szValue, "info_ctfdetect") == 0)) |
|
{ |
|
pent_info_ctfdetect = pentKeyvalue; |
|
} |
|
} |
|
} |
|
|
|
(*other_gFunctionTable.pfnKeyValue)(pentKeyvalue, pkvd); |
|
} |
|
|
|
void DispatchSave( edict_t *pent, SAVERESTOREDATA *pSaveData ) |
|
{ |
|
(*other_gFunctionTable.pfnSave)(pent, pSaveData); |
|
} |
|
|
|
int DispatchRestore( edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity ) |
|
{ |
|
return (*other_gFunctionTable.pfnRestore)(pent, pSaveData, globalEntity); |
|
} |
|
|
|
void DispatchObjectCollsionBox( edict_t *pent ) |
|
{ |
|
(*other_gFunctionTable.pfnSetAbsBox)(pent); |
|
} |
|
|
|
void SaveWriteFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ) |
|
{ |
|
(*other_gFunctionTable.pfnSaveWriteFields)(pSaveData, pname, pBaseData, pFields, fieldCount); |
|
} |
|
|
|
void SaveReadFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ) |
|
{ |
|
(*other_gFunctionTable.pfnSaveReadFields)(pSaveData, pname, pBaseData, pFields, fieldCount); |
|
} |
|
|
|
void SaveGlobalState( SAVERESTOREDATA *pSaveData ) |
|
{ |
|
(*other_gFunctionTable.pfnSaveGlobalState)(pSaveData); |
|
} |
|
|
|
void RestoreGlobalState( SAVERESTOREDATA *pSaveData ) |
|
{ |
|
(*other_gFunctionTable.pfnRestoreGlobalState)(pSaveData); |
|
} |
|
|
|
void ResetGlobalState( void ) |
|
{ |
|
(*other_gFunctionTable.pfnResetGlobalState)(); |
|
} |
|
|
|
BOOL ClientConnect( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) |
|
{ |
|
if (gpGlobals->deathmatch) |
|
{ |
|
int i; |
|
int count = 0; |
|
|
|
if (debug_engine) { fp=fopen("HPB_bot.txt","a"); fprintf(fp, "ClientConnect: pent=%x name=%s\n",pEntity,pszName); fclose(fp); } |
|
|
|
// check if this client is the listen server client |
|
if (strcmp(pszAddress, "loopback") == 0) |
|
{ |
|
// save the edict of the listen server client... |
|
listenserver_edict = pEntity; |
|
} |
|
|
|
// check if this is NOT a bot joining the server... |
|
if (strcmp(pszAddress, "127.0.0.1") != 0) |
|
{ |
|
// don't try to add bots for 60 seconds, give client time to get added |
|
bot_check_time = gpGlobals->time + 60.0; |
|
|
|
for (i=0; i < 32; i++) |
|
{ |
|
if (bots[i].is_used) // count the number of bots in use |
|
count++; |
|
} |
|
|
|
// if there are currently more than the minimum number of bots running |
|
// then kick one of the bots off the server... |
|
if ((count > min_bots) && (min_bots != -1)) |
|
{ |
|
for (i=0; i < 32; i++) |
|
{ |
|
if (bots[i].is_used) // is this slot used? |
|
{ |
|
char cmd[80]; |
|
|
|
sprintf(cmd, "kick \"%s\"\n", bots[i].name); |
|
|
|
SERVER_COMMAND(cmd); // kick the bot using (kick "name") |
|
|
|
break; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
return (*other_gFunctionTable.pfnClientConnect)(pEntity, pszName, pszAddress, szRejectReason); |
|
} |
|
|
|
void ClientDisconnect( edict_t *pEntity ) |
|
{ |
|
if (gpGlobals->deathmatch) |
|
{ |
|
int i; |
|
|
|
if (debug_engine) { fp=fopen("HPB_bot.txt","a"); fprintf(fp, "ClientDisconnect: %x\n",pEntity); fclose(fp); } |
|
|
|
i = 0; |
|
while ((i < 32) && (clients[i] != pEntity)) |
|
i++; |
|
|
|
if (i < 32) |
|
clients[i] = NULL; |
|
|
|
|
|
for (i=0; i < 32; i++) |
|
{ |
|
if (bots[i].pEdict == pEntity) |
|
{ |
|
// someone kicked this bot off of the server... |
|
|
|
bots[i].is_used = FALSE; // this slot is now free to use |
|
|
|
bots[i].f_kick_time = gpGlobals->time; // save the kicked time |
|
|
|
break; |
|
} |
|
} |
|
} |
|
|
|
(*other_gFunctionTable.pfnClientDisconnect)(pEntity); |
|
} |
|
|
|
void ClientKill( edict_t *pEntity ) |
|
{ |
|
if (debug_engine) { fp=fopen("HPB_bot.txt","a"); fprintf(fp, "ClientKill: %x\n",pEntity); fclose(fp); } |
|
(*other_gFunctionTable.pfnClientKill)(pEntity); |
|
} |
|
|
|
void ClientPutInServer( edict_t *pEntity ) |
|
{ |
|
if (debug_engine) { fp=fopen("HPB_bot.txt","a"); fprintf(fp, "ClientPutInServer: %x\n",pEntity); fclose(fp); } |
|
|
|
int i = 0; |
|
|
|
while ((i < 32) && (clients[i] != NULL)) |
|
i++; |
|
|
|
if (i < 32) |
|
clients[i] = pEntity; // store this clients edict in the clients array |
|
|
|
(*other_gFunctionTable.pfnClientPutInServer)(pEntity); |
|
} |
|
|
|
|
|
void ClientCommand( edict_t *pEntity ) |
|
{ |
|
const char *pcmd = Cmd_Argv(0); |
|
const char *arg1 = Cmd_Argv(1); |
|
const char *arg2 = Cmd_Argv(2); |
|
const char *arg3 = Cmd_Argv(3); |
|
const char *arg4 = Cmd_Argv(4); |
|
const char *arg5 = Cmd_Argv(5); |
|
|
|
if (debug_engine) |
|
{ |
|
fp=fopen("HPB_bot.txt","a"); fprintf(fp,"ClientCommand: %s",pcmd); |
|
if ((arg1 != NULL) && (*arg1 != 0)) |
|
fprintf(fp," %s", arg1); |
|
if ((arg2 != NULL) && (*arg2 != 0)) |
|
fprintf(fp," %s", arg2); |
|
if ((arg3 != NULL) && (*arg3 != 0)) |
|
fprintf(fp," %s", arg3); |
|
if ((arg4 != NULL) && (*arg4 != 0)) |
|
fprintf(fp," %s", arg4); |
|
if ((arg5 != NULL) && (*arg5 != 0)) |
|
fprintf(fp," %s", arg5); |
|
fprintf(fp, "\n"); |
|
fclose(fp); |
|
} |
|
|
|
// only allow custom commands if deathmatch mode and NOT dedicated server and |
|
// client sending command is the listen server client... |
|
|
|
if ((gpGlobals->deathmatch) && (!IsDedicatedServer) && |
|
(pEntity == listenserver_edict)) |
|
{ |
|
char msg[80]; |
|
|
|
if (FStrEq(pcmd, "addbot")) |
|
{ |
|
BotCreate( pEntity, arg1, arg2, arg3, arg4, arg5 ); |
|
|
|
bot_check_time = gpGlobals->time + 5.0; |
|
|
|
return; |
|
} |
|
else if (FStrEq(pcmd, "observer")) |
|
{ |
|
if ((arg1 != NULL) && (*arg1 != 0)) |
|
{ |
|
int temp = atoi(arg1); |
|
if (temp) |
|
b_observer_mode = TRUE; |
|
else |
|
b_observer_mode = FALSE; |
|
} |
|
|
|
if (b_observer_mode) |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "observer mode ENABLED\n"); |
|
else |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "observer mode DISABLED\n"); |
|
|
|
return; |
|
} |
|
else if (FStrEq(pcmd, "botskill")) |
|
{ |
|
if ((arg1 != NULL) && (*arg1 != 0)) |
|
{ |
|
int temp = atoi(arg1); |
|
|
|
if ((temp < 1) || (temp > 5)) |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "invalid botskill value!\n"); |
|
else |
|
default_bot_skill = temp; |
|
} |
|
|
|
sprintf(msg, "botskill is %d\n", default_bot_skill); |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, msg); |
|
|
|
return; |
|
} |
|
else if (FStrEq(pcmd, "bot_strafe_percent")) |
|
{ |
|
if ((arg1 != NULL) && (*arg1 != 0)) |
|
{ |
|
int temp = atoi(arg1); |
|
|
|
if ((temp < 0) || (temp > 100)) |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "invalid bot_strafe_percent value!\n"); |
|
else |
|
bot_strafe_percent = temp; |
|
} |
|
|
|
sprintf(msg, "bot_strafe_percent is %d\n", bot_strafe_percent); |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, msg); |
|
|
|
return; |
|
} |
|
else if (FStrEq(pcmd, "bot_chat_percent")) |
|
{ |
|
if ((arg1 != NULL) && (*arg1 != 0)) |
|
{ |
|
int temp = atoi(arg1); |
|
|
|
if ((temp < 0) || (temp > 100)) |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "invalid bot_chat_percent value!\n"); |
|
else |
|
bot_chat_percent = temp; |
|
} |
|
|
|
sprintf(msg, "bot_chat_percent is %d\n", bot_chat_percent); |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, msg); |
|
|
|
return; |
|
} |
|
else if (FStrEq(pcmd, "bot_taunt_percent")) |
|
{ |
|
if ((arg1 != NULL) && (*arg1 != 0)) |
|
{ |
|
int temp = atoi(arg1); |
|
|
|
if ((temp < 0) || (temp > 100)) |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "invalid bot_taunt_percent value!\n"); |
|
else |
|
bot_taunt_percent = temp; |
|
} |
|
|
|
sprintf(msg, "bot_taunt_percent is %d\n", bot_taunt_percent); |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, msg); |
|
|
|
return; |
|
} |
|
else if (FStrEq(pcmd, "bot_whine_percent")) |
|
{ |
|
if ((arg1 != NULL) && (*arg1 != 0)) |
|
{ |
|
int temp = atoi(arg1); |
|
|
|
if ((temp < 0) || (temp > 100)) |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "invalid bot_whine_percent value!\n"); |
|
else |
|
bot_whine_percent = temp; |
|
} |
|
|
|
sprintf(msg, "bot_whine_percent is %d\n", bot_whine_percent); |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, msg); |
|
|
|
return; |
|
} |
|
else if (FStrEq(pcmd, "bot_chat_tag_percent")) |
|
{ |
|
if ((arg1 != NULL) && (*arg1 != 0)) |
|
{ |
|
int temp = atoi(arg1); |
|
|
|
if ((temp < 0) || (temp > 100)) |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "invalid bot_chat_tag_percent value!\n"); |
|
else |
|
bot_chat_tag_percent = temp; |
|
} |
|
|
|
sprintf(msg, "bot_chat_tag_percent is %d\n", bot_chat_tag_percent); |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, msg); |
|
|
|
return; |
|
} |
|
else if (FStrEq(pcmd, "bot_chat_drop_percent")) |
|
{ |
|
if ((arg1 != NULL) && (*arg1 != 0)) |
|
{ |
|
int temp = atoi(arg1); |
|
|
|
if ((temp < 0) || (temp > 100)) |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "invalid bot_chat_drop_percent value!\n"); |
|
else |
|
bot_chat_drop_percent = temp; |
|
} |
|
|
|
sprintf(msg, "bot_chat_drop_percent is %d\n", bot_chat_drop_percent); |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, msg); |
|
|
|
return; |
|
} |
|
else if (FStrEq(pcmd, "bot_chat_swap_percent")) |
|
{ |
|
if ((arg1 != NULL) && (*arg1 != 0)) |
|
{ |
|
int temp = atoi(arg1); |
|
|
|
if ((temp < 0) || (temp > 100)) |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "invalid bot_chat_swap_percent value!\n"); |
|
else |
|
bot_chat_swap_percent = temp; |
|
} |
|
|
|
sprintf(msg, "bot_chat_swap_percent is %d\n", bot_chat_swap_percent); |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, msg); |
|
|
|
return; |
|
} |
|
else if (FStrEq(pcmd, "bot_chat_lower_percent")) |
|
{ |
|
if ((arg1 != NULL) && (*arg1 != 0)) |
|
{ |
|
int temp = atoi(arg1); |
|
|
|
if ((temp < 0) || (temp > 100)) |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "invalid bot_chat_lower_percent value!\n"); |
|
else |
|
bot_chat_lower_percent = temp; |
|
} |
|
|
|
sprintf(msg, "bot_chat_lower_percent is %d\n", bot_chat_lower_percent); |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, msg); |
|
|
|
return; |
|
} |
|
else if (FStrEq(pcmd, "bot_grenade_time")) |
|
{ |
|
if ((arg1 != NULL) && (*arg1 != 0)) |
|
{ |
|
int temp = atoi(arg1); |
|
|
|
if ((temp < 0) || (temp > 60)) |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "invalid bot_grenade_time value!\n"); |
|
else |
|
bot_grenade_time = temp; |
|
} |
|
|
|
sprintf(msg, "bot_grenade_time is %d\n", bot_grenade_time); |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, msg); |
|
|
|
return; |
|
} |
|
else if (FStrEq(pcmd, "bot_logo_percent")) |
|
{ |
|
if ((arg1 != NULL) && (*arg1 != 0)) |
|
{ |
|
int temp = atoi(arg1); |
|
|
|
if ((temp < 0) || (temp > 100)) |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "invalid bot_logo_percent value!\n"); |
|
else |
|
bot_logo_percent = temp; |
|
} |
|
|
|
sprintf(msg, "bot_logo_percent is %d\n", bot_logo_percent); |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, msg); |
|
|
|
return; |
|
} |
|
else if (FStrEq(pcmd, "bot_reaction_time")) |
|
{ |
|
if ((arg1 != NULL) && (*arg1 != 0)) |
|
{ |
|
int temp = atoi(arg1); |
|
|
|
if ((temp < 0) || (temp > 3)) |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "invalid bot_reaction_time value!\n"); |
|
else |
|
bot_reaction_time = temp; |
|
} |
|
|
|
if (bot_reaction_time) |
|
sprintf(msg, "bot_reaction_time is %d\n", bot_reaction_time); |
|
else |
|
sprintf(msg, "bot_reaction_time is DISABLED\n"); |
|
|
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, msg); |
|
|
|
return; |
|
} |
|
else if (FStrEq(pcmd, "random_color")) |
|
{ |
|
if ((arg1 != NULL) && (*arg1 != 0)) |
|
{ |
|
int temp = atoi(arg1); |
|
|
|
if (temp) |
|
b_random_color = TRUE; |
|
else |
|
b_random_color = FALSE; |
|
} |
|
|
|
if (b_random_color) |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "random_color ENABLED\n"); |
|
else |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "random_color DISABLED\n"); |
|
|
|
return; |
|
} |
|
else if (FStrEq(pcmd, "botdontshoot")) |
|
{ |
|
if ((arg1 != NULL) && (*arg1 != 0)) |
|
{ |
|
int temp = atoi(arg1); |
|
if (temp) |
|
b_botdontshoot = TRUE; |
|
else |
|
b_botdontshoot = FALSE; |
|
} |
|
|
|
if (b_botdontshoot) |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "botdontshoot ENABLED\n"); |
|
else |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "botdontshoot DISABLED\n"); |
|
|
|
return; |
|
} |
|
else if (FStrEq(pcmd, "debug_engine")) |
|
{ |
|
debug_engine = 1; |
|
|
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "debug_engine enabled!\n"); |
|
|
|
return; |
|
} |
|
else if (FStrEq(pcmd, "waypoint")) |
|
{ |
|
if (FStrEq(arg1, "on")) |
|
{ |
|
g_waypoint_on = TRUE; |
|
|
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "waypoints are ON\n"); |
|
} |
|
else if (FStrEq(arg1, "off")) |
|
{ |
|
g_waypoint_on = FALSE; |
|
|
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "waypoints are OFF\n"); |
|
} |
|
else if (FStrEq(arg1, "add")) |
|
{ |
|
if (!g_waypoint_on) |
|
g_waypoint_on = TRUE; // turn waypoints on if off |
|
|
|
WaypointAdd(pEntity); |
|
} |
|
else if (FStrEq(arg1, "delete")) |
|
{ |
|
if (!g_waypoint_on) |
|
g_waypoint_on = TRUE; // turn waypoints on if off |
|
|
|
WaypointDelete(pEntity); |
|
} |
|
else if (FStrEq(arg1, "save")) |
|
{ |
|
WaypointSave(); |
|
|
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "waypoints saved\n"); |
|
} |
|
else if (FStrEq(arg1, "load")) |
|
{ |
|
if (WaypointLoad(pEntity)) |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "waypoints loaded\n"); |
|
} |
|
else if (FStrEq(arg1, "menu")) |
|
{ |
|
int index; |
|
|
|
if (num_waypoints < 1) |
|
return; |
|
|
|
index = WaypointFindNearest(pEntity, 50.0, -1); |
|
|
|
if (index == -1) |
|
return; |
|
|
|
g_menu_waypoint = index; |
|
g_menu_state = MENU_1; |
|
|
|
UTIL_ShowMenu(pEntity, 0x1F, -1, FALSE, show_menu_1); |
|
} |
|
else if (FStrEq(arg1, "info")) |
|
{ |
|
WaypointPrintInfo(pEntity); |
|
} |
|
else if (FStrEq(arg1, "update")) |
|
{ |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "updating waypoint tags...\n"); |
|
|
|
WaypointUpdate(pEntity); |
|
|
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "...update done! (don't forget to save!)\n"); |
|
} |
|
else |
|
{ |
|
if (g_waypoint_on) |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "waypoints are ON\n"); |
|
else |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "waypoints are OFF\n"); |
|
} |
|
|
|
return; |
|
} |
|
else if (FStrEq(pcmd, "autowaypoint")) |
|
{ |
|
if (FStrEq(arg1, "on")) |
|
{ |
|
g_auto_waypoint = TRUE; |
|
g_waypoint_on = TRUE; // turn this on just in case |
|
} |
|
else if (FStrEq(arg1, "off")) |
|
{ |
|
g_auto_waypoint = FALSE; |
|
} |
|
|
|
if (g_auto_waypoint) |
|
sprintf(msg, "autowaypoint is ON\n"); |
|
else |
|
sprintf(msg, "autowaypoint is OFF\n"); |
|
|
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, msg); |
|
|
|
return; |
|
} |
|
else if (FStrEq(pcmd, "pathwaypoint")) |
|
{ |
|
if (FStrEq(arg1, "on")) |
|
{ |
|
g_path_waypoint = TRUE; |
|
g_waypoint_on = TRUE; // turn this on just in case |
|
|
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "pathwaypoint is ON\n"); |
|
} |
|
else if (FStrEq(arg1, "off")) |
|
{ |
|
g_path_waypoint = FALSE; |
|
|
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "pathwaypoint is OFF\n"); |
|
} |
|
else if (FStrEq(arg1, "enable")) |
|
{ |
|
g_path_waypoint_enable = TRUE; |
|
|
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "pathwaypoint is ENABLED\n"); |
|
} |
|
else if (FStrEq(arg1, "disable")) |
|
{ |
|
g_path_waypoint_enable = FALSE; |
|
|
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "pathwaypoint is DISABLED\n"); |
|
} |
|
else if (FStrEq(arg1, "create1")) |
|
{ |
|
WaypointCreatePath(pEntity, 1); |
|
} |
|
else if (FStrEq(arg1, "create2")) |
|
{ |
|
WaypointCreatePath(pEntity, 2); |
|
} |
|
else if (FStrEq(arg1, "remove1")) |
|
{ |
|
WaypointRemovePath(pEntity, 1); |
|
} |
|
else if (FStrEq(arg1, "remove2")) |
|
{ |
|
WaypointRemovePath(pEntity, 2); |
|
} |
|
|
|
return; |
|
} |
|
else if (FStrEq(pcmd, "menuselect") && (g_menu_state != MENU_NONE)) |
|
{ |
|
if (g_menu_state == MENU_1) // main menu... |
|
{ |
|
if (FStrEq(arg1, "1")) // team specific... |
|
{ |
|
g_menu_state = MENU_2; // display team specific menu... |
|
|
|
if (mod_id == FRONTLINE_DLL) |
|
UTIL_ShowMenu(pEntity, 0x13, -1, FALSE, show_menu_2_flf); |
|
else |
|
UTIL_ShowMenu(pEntity, 0x1F, -1, FALSE, show_menu_2); |
|
|
|
return; |
|
} |
|
else if (FStrEq(arg1, "2")) // wait for lift... |
|
{ |
|
if (waypoints[g_menu_waypoint].flags & W_FL_LIFT) |
|
waypoints[g_menu_waypoint].flags &= ~W_FL_LIFT; // off |
|
else |
|
waypoints[g_menu_waypoint].flags |= W_FL_LIFT; // on |
|
} |
|
else if (FStrEq(arg1, "3")) // door waypoint |
|
{ |
|
if (waypoints[g_menu_waypoint].flags & W_FL_DOOR) |
|
waypoints[g_menu_waypoint].flags &= ~W_FL_DOOR; // off |
|
else |
|
waypoints[g_menu_waypoint].flags |= W_FL_DOOR; // on |
|
} |
|
else if (FStrEq(arg1, "4")) // sniper spot |
|
{ |
|
if (waypoints[g_menu_waypoint].flags & W_FL_SNIPER) |
|
waypoints[g_menu_waypoint].flags &= ~W_FL_SNIPER; // off |
|
else |
|
{ |
|
waypoints[g_menu_waypoint].flags |= W_FL_SNIPER; // on |
|
|
|
// set the aiming waypoint... |
|
|
|
WaypointAddAiming(pEntity); |
|
} |
|
} |
|
else if (FStrEq(arg1, "5")) // more... |
|
{ |
|
g_menu_state = MENU_3; |
|
|
|
if (mod_id == FRONTLINE_DLL) |
|
UTIL_ShowMenu(pEntity, 0x17, -1, FALSE, show_menu_3_flf); |
|
else if (mod_id == HOLYWARS_DLL) |
|
UTIL_ShowMenu(pEntity, 0x11, -1, FALSE, show_menu_3_hw); |
|
else |
|
UTIL_ShowMenu(pEntity, 0x1F, -1, FALSE, show_menu_3); |
|
|
|
return; |
|
} |
|
} |
|
else if (g_menu_state == MENU_2) // team specific menu |
|
{ |
|
if (waypoints[g_menu_waypoint].flags & W_FL_TEAM_SPECIFIC) |
|
{ |
|
waypoints[g_menu_waypoint].flags &= ~W_FL_TEAM; |
|
waypoints[g_menu_waypoint].flags &= ~W_FL_TEAM_SPECIFIC; // off |
|
} |
|
else |
|
{ |
|
int team = atoi(arg1); |
|
|
|
team--; // make 0 to 3 |
|
|
|
// this is kind of a kludge (team bits MUST be LSB!!!) |
|
waypoints[g_menu_waypoint].flags |= team; |
|
waypoints[g_menu_waypoint].flags |= W_FL_TEAM_SPECIFIC; // on |
|
} |
|
} |
|
else if (g_menu_state == MENU_3) // third menu... |
|
{ |
|
if (mod_id == FRONTLINE_DLL) |
|
{ |
|
if (FStrEq(arg1, "1")) // capture point |
|
{ |
|
if (waypoints[g_menu_waypoint].flags & W_FL_FLF_CAP) |
|
waypoints[g_menu_waypoint].flags &= ~W_FL_FLF_CAP; // off |
|
else |
|
waypoints[g_menu_waypoint].flags |= W_FL_FLF_CAP; // on |
|
} |
|
else if (FStrEq(arg1, "2")) // defend point |
|
{ |
|
if (waypoints[g_menu_waypoint].flags & W_FL_FLF_DEFEND) |
|
waypoints[g_menu_waypoint].flags &= ~W_FL_FLF_DEFEND; // off |
|
else |
|
{ |
|
waypoints[g_menu_waypoint].flags |= W_FL_FLF_DEFEND; // on |
|
|
|
// set the aiming waypoint... |
|
|
|
WaypointAddAiming(pEntity); |
|
} |
|
} |
|
else if (FStrEq(arg1, "3")) // go prone |
|
{ |
|
if (waypoints[g_menu_waypoint].flags & W_FL_PRONE) |
|
waypoints[g_menu_waypoint].flags &= ~W_FL_PRONE; // off |
|
else |
|
waypoints[g_menu_waypoint].flags |= W_FL_PRONE; // on |
|
} |
|
} |
|
else if (mod_id == HOLYWARS_DLL) |
|
{ |
|
if (FStrEq(arg1, "1")) // flag location |
|
{ |
|
if (waypoints[g_menu_waypoint].flags & W_FL_FLAG) |
|
waypoints[g_menu_waypoint].flags &= ~W_FL_FLAG; // off |
|
else |
|
waypoints[g_menu_waypoint].flags |= W_FL_FLAG; // on |
|
} |
|
else if (FStrEq(arg1, "5")) |
|
{ |
|
g_menu_state = MENU_4; |
|
|
|
UTIL_ShowMenu(pEntity, 0x1F, -1, FALSE, show_menu_4); |
|
|
|
return; |
|
} |
|
} |
|
else |
|
{ |
|
if (FStrEq(arg1, "1")) // flag location |
|
{ |
|
if (waypoints[g_menu_waypoint].flags & W_FL_FLAG) |
|
waypoints[g_menu_waypoint].flags &= ~W_FL_FLAG; // off |
|
else |
|
waypoints[g_menu_waypoint].flags |= W_FL_FLAG; // on |
|
} |
|
else if (FStrEq(arg1, "2")) // flag goal |
|
{ |
|
if (waypoints[g_menu_waypoint].flags & W_FL_FLAG_GOAL) |
|
waypoints[g_menu_waypoint].flags &= ~W_FL_FLAG_GOAL; // off |
|
else |
|
waypoints[g_menu_waypoint].flags |= W_FL_FLAG_GOAL; // on |
|
} |
|
else if (FStrEq(arg1, "3")) // sentry gun |
|
{ |
|
if (waypoints[g_menu_waypoint].flags & W_FL_SENTRYGUN) |
|
waypoints[g_menu_waypoint].flags &= ~W_FL_SENTRYGUN; // off |
|
else |
|
{ |
|
waypoints[g_menu_waypoint].flags |= W_FL_SENTRYGUN; // on |
|
|
|
// set the aiming waypoint... |
|
|
|
WaypointAddAiming(pEntity); |
|
} |
|
} |
|
else if (FStrEq(arg1, "4")) // dispenser |
|
{ |
|
if (waypoints[g_menu_waypoint].flags & W_FL_DISPENSER) |
|
waypoints[g_menu_waypoint].flags &= ~W_FL_DISPENSER; // off |
|
else |
|
{ |
|
waypoints[g_menu_waypoint].flags |= W_FL_DISPENSER; // on |
|
|
|
// set the aiming waypoint... |
|
|
|
WaypointAddAiming(pEntity); |
|
} |
|
} |
|
else if (FStrEq(arg1, "5")) |
|
{ |
|
g_menu_state = MENU_4; |
|
|
|
UTIL_ShowMenu(pEntity, 0x1F, -1, FALSE, show_menu_4); |
|
|
|
return; |
|
} |
|
} |
|
} |
|
else if (g_menu_state == MENU_4) // fourth menu... |
|
{ |
|
if (FStrEq(arg1, "1")) // health |
|
{ |
|
if (waypoints[g_menu_waypoint].flags & W_FL_HEALTH) |
|
waypoints[g_menu_waypoint].flags &= ~W_FL_HEALTH; // off |
|
else |
|
waypoints[g_menu_waypoint].flags |= W_FL_HEALTH; // on |
|
} |
|
else if (FStrEq(arg1, "2")) // armor |
|
{ |
|
if (waypoints[g_menu_waypoint].flags & W_FL_ARMOR) |
|
waypoints[g_menu_waypoint].flags &= ~W_FL_ARMOR; // off |
|
else |
|
waypoints[g_menu_waypoint].flags |= W_FL_ARMOR; // on |
|
} |
|
else if (FStrEq(arg1, "3")) // ammo |
|
{ |
|
if (waypoints[g_menu_waypoint].flags & W_FL_AMMO) |
|
waypoints[g_menu_waypoint].flags &= ~W_FL_AMMO; // off |
|
else |
|
waypoints[g_menu_waypoint].flags |= W_FL_AMMO; // on |
|
} |
|
else if (FStrEq(arg1, "4")) // jump |
|
{ |
|
if (waypoints[g_menu_waypoint].flags & W_FL_JUMP) |
|
waypoints[g_menu_waypoint].flags &= ~W_FL_JUMP; // off |
|
else |
|
{ |
|
waypoints[g_menu_waypoint].flags |= W_FL_JUMP; // on |
|
|
|
// set the aiming waypoint... |
|
|
|
WaypointAddAiming(pEntity); |
|
} |
|
} |
|
} |
|
|
|
g_menu_state = MENU_NONE; |
|
|
|
// turn off the text menu if the mod doesn't do this automatically |
|
if ((mod_id == HOLYWARS_DLL) || (mod_id == DMC_DLL)) |
|
UTIL_ShowMenu(pEntity, 0x0, -1, FALSE, show_menu_none); |
|
|
|
return; |
|
} |
|
else if (FStrEq(pcmd, "search")) |
|
{ |
|
edict_t *pent = NULL; |
|
float radius = 100; |
|
char str[80]; |
|
|
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, "searching...\n"); |
|
|
|
while ((pent = UTIL_FindEntityInSphere( pent, pEntity->v.origin, radius )) != NULL) |
|
{ |
|
sprintf(str, "Found %s at %5.2f %5.2f %5.2f\n", |
|
STRING(pent->v.classname), |
|
pent->v.origin.x, pent->v.origin.y, |
|
pent->v.origin.z); |
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, str); |
|
|
|
FILE *fp=fopen("HPB_bot.txt", "a"); |
|
fprintf(fp, "ClientCommmand: search %s", str); |
|
fclose(fp); |
|
} |
|
|
|
return; |
|
} |
|
else if (FStrEq(pcmd, "jumppad")) |
|
{ |
|
char str[80]; |
|
|
|
if (FStrEq(arg1, "off")) |
|
jumppad_off = 1; |
|
if (FStrEq(arg1, "on")) |
|
jumppad_off = 0; |
|
|
|
if (jumppad_off) |
|
sprintf(str,"jumppad is OFF\n"); |
|
else |
|
sprintf(str,"jumppad is ON\n"); |
|
|
|
ClientPrint(pEntity, HUD_PRINTNOTIFY, str); |
|
|
|
return; |
|
} |
|
#if _DEBUG |
|
else if (FStrEq(pcmd, "botstop")) |
|
{ |
|
bot_stop = 1; |
|
|
|
return; |
|
} |
|
else if (FStrEq(pcmd, "botstart")) |
|
{ |
|
bot_stop = 0; |
|
|
|
return; |
|
} |
|
#endif |
|
} |
|
|
|
(*other_gFunctionTable.pfnClientCommand)(pEntity); |
|
} |
|
|
|
void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer ) |
|
{ |
|
if (debug_engine) { fp=fopen("HPB_bot.txt", "a"); fprintf(fp, "ClientUserInfoChanged: pEntity=%x infobuffer=%s\n", pEntity, infobuffer); fclose(fp); } |
|
|
|
(*other_gFunctionTable.pfnClientUserInfoChanged)(pEntity, infobuffer); |
|
} |
|
|
|
void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ) |
|
{ |
|
(*other_gFunctionTable.pfnServerActivate)(pEdictList, edictCount, clientMax); |
|
} |
|
|
|
void ServerDeactivate( void ) |
|
{ |
|
(*other_gFunctionTable.pfnServerDeactivate)(); |
|
} |
|
|
|
void PlayerPreThink( edict_t *pEntity ) |
|
{ |
|
(*other_gFunctionTable.pfnPlayerPreThink)(pEntity); |
|
} |
|
|
|
void PlayerPostThink( edict_t *pEntity ) |
|
{ |
|
(*other_gFunctionTable.pfnPlayerPostThink)(pEntity); |
|
} |
|
|
|
void StartFrame( void ) |
|
{ |
|
if (gpGlobals->deathmatch) |
|
{ |
|
edict_t *pPlayer; |
|
static float check_server_cmd = 0.0; |
|
static int i, index, player_index, bot_index; |
|
static float previous_time = -1.0; |
|
static float client_update_time = 0.0; |
|
clientdata_s cd; |
|
char msg[256]; |
|
int count; |
|
|
|
// if a new map has started then (MUST BE FIRST IN StartFrame)... |
|
if ((gpGlobals->time + 0.1) < previous_time) |
|
{ |
|
char filename[256]; |
|
char mapname[64]; |
|
|
|
check_server_cmd = 0.0; // reset at start of map |
|
|
|
// check if mapname_bot.cfg file exists... |
|
|
|
strcpy(mapname, STRING(gpGlobals->mapname)); |
|
strcat(mapname, "_HPB_bot.cfg"); |
|
|
|
UTIL_BuildFileName(filename, "maps", mapname); |
|
|
|
if ((bot_cfg_fp = fopen(filename, "r")) != NULL) |
|
{ |
|
sprintf(msg, "Executing %s\n", filename); |
|
ALERT( at_console, msg ); |
|
|
|
for (index = 0; index < 32; index++) |
|
{ |
|
bots[index].is_used = FALSE; |
|
bots[index].respawn_state = 0; |
|
bots[index].f_kick_time = 0.0; |
|
} |
|
|
|
if (IsDedicatedServer) |
|
bot_cfg_pause_time = gpGlobals->time + 5.0; |
|
else |
|
bot_cfg_pause_time = gpGlobals->time + 20.0; |
|
} |
|
else |
|
{ |
|
count = 0; |
|
|
|
// mark the bots as needing to be respawned... |
|
for (index = 0; index < 32; index++) |
|
{ |
|
if (count >= prev_num_bots) |
|
{ |
|
bots[index].is_used = FALSE; |
|
bots[index].respawn_state = 0; |
|
bots[index].f_kick_time = 0.0; |
|
} |
|
|
|
if (bots[index].is_used) // is this slot used? |
|
{ |
|
bots[index].respawn_state = RESPAWN_NEED_TO_RESPAWN; |
|
count++; |
|
} |
|
|
|
// check for any bots that were very recently kicked... |
|
if ((bots[index].f_kick_time + 5.0) > previous_time) |
|
{ |
|
bots[index].respawn_state = RESPAWN_NEED_TO_RESPAWN; |
|
count++; |
|
} |
|
else |
|
bots[index].f_kick_time = 0.0; // reset to prevent false spawns later |
|
} |
|
|
|
// set the respawn time |
|
if (IsDedicatedServer) |
|
respawn_time = gpGlobals->time + 5.0; |
|
else |
|
respawn_time = gpGlobals->time + 20.0; |
|
} |
|
|
|
client_update_time = gpGlobals->time + 10.0; // start updating client data again |
|
|
|
bot_check_time = gpGlobals->time + 60.0; |
|
} |
|
|
|
if (!IsDedicatedServer) |
|
{ |
|
if ((listenserver_edict != NULL) && (welcome_sent == FALSE) && |
|
(welcome_time < 1.0)) |
|
{ |
|
// are they out of observer mode yet? |
|
if (IsAlive(listenserver_edict)) |
|
welcome_time = gpGlobals->time + 5.0; // welcome in 5 seconds |
|
} |
|
|
|
if ((welcome_time > 0.0) && (welcome_time < gpGlobals->time) && |
|
(welcome_sent == FALSE)) |
|
{ |
|
char version[80]; |
|
|
|
sprintf(version,"%s Version %d.%d\n", welcome_msg, VER_MAJOR, VER_MINOR); |
|
|
|
// let's send a welcome message to this client... |
|
UTIL_SayText(version, listenserver_edict); |
|
|
|
welcome_sent = TRUE; // clear this so we only do it once |
|
} |
|
} |
|
|
|
if (mod_id != DMC_DLL) |
|
{ |
|
if ((client_update_time <= gpGlobals->time) && (mod_id != DMC_DLL)) |
|
{ |
|
client_update_time = gpGlobals->time + 1.0; |
|
|
|
for (i=0; i < 32; i++) |
|
{ |
|
if (bots[i].is_used) |
|
{ |
|
memset(&cd, 0, sizeof(cd)); |
|
|
|
UpdateClientData( bots[i].pEdict, 1, &cd ); |
|
|
|
// see if a weapon was dropped... |
|
if (bots[i].bot_weapons != cd.weapons) |
|
{ |
|
bots[i].bot_weapons = cd.weapons; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
count = 0; |
|
|
|
if (bot_stop == 0) |
|
{ |
|
for (bot_index = 0; bot_index < gpGlobals->maxClients; bot_index++) |
|
{ |
|
if ((bots[bot_index].is_used) && // is this slot used AND |
|
(bots[bot_index].respawn_state == RESPAWN_IDLE)) // not respawning |
|
{ |
|
BotThink(&bots[bot_index]); |
|
|
|
count++; |
|
} |
|
} |
|
} |
|
|
|
if (count > num_bots) |
|
num_bots = count; |
|
|
|
for (player_index = 1; player_index <= gpGlobals->maxClients; player_index++) |
|
{ |
|
pPlayer = INDEXENT(player_index); |
|
|
|
if (pPlayer && !pPlayer->free) |
|
{ |
|
if ((g_waypoint_on) && |
|
FBitSet(pPlayer->v.flags, FL_CLIENT) && |
|
!FBitSet(pPlayer->v.flags, FL_FAKECLIENT)) |
|
{ |
|
WaypointThink(pPlayer); |
|
} |
|
} |
|
} |
|
|
|
// are we currently respawning bots and is it time to spawn one yet? |
|
if ((respawn_time > 1.0) && (respawn_time <= gpGlobals->time)) |
|
{ |
|
int index = 0; |
|
|
|
// find bot needing to be respawned... |
|
while ((index < 32) && |
|
(bots[index].respawn_state != RESPAWN_NEED_TO_RESPAWN)) |
|
index++; |
|
|
|
if (index < 32) |
|
{ |
|
int strafe = bot_strafe_percent; // save global strafe percent |
|
int chat = bot_chat_percent; // save global chat percent |
|
int taunt = bot_taunt_percent; // save global taunt percent |
|
int whine = bot_whine_percent; // save global whine percent |
|
int grenade = bot_grenade_time; // save global grenade time |
|
int logo = bot_logo_percent; // save global logo percent |
|
int tag = bot_chat_tag_percent; // save global clan tag percent |
|
int drop = bot_chat_drop_percent; // save global chat drop percent |
|
int swap = bot_chat_swap_percent; // save global chat swap percent |
|
int lower = bot_chat_lower_percent; // save global chat lower percent |
|
int react = bot_reaction_time; |
|
|
|
bots[index].respawn_state = RESPAWN_IS_RESPAWNING; |
|
bots[index].is_used = FALSE; // free up this slot |
|
|
|
bot_strafe_percent = bots[index].strafe_percent; |
|
bot_chat_percent = bots[index].chat_percent; |
|
bot_taunt_percent = bots[index].taunt_percent; |
|
bot_whine_percent = bots[index].whine_percent; |
|
bot_grenade_time = bots[index].grenade_time; |
|
bot_logo_percent = bots[index].logo_percent; |
|
bot_chat_tag_percent = bots[index].chat_tag_percent; |
|
bot_chat_drop_percent = bots[index].chat_drop_percent; |
|
bot_chat_swap_percent = bots[index].chat_swap_percent; |
|
bot_chat_lower_percent = bots[index].chat_lower_percent; |
|
bot_reaction_time = bots[index].reaction_time; |
|
|
|
// respawn 1 bot then wait a while (otherwise engine crashes) |
|
if ((mod_id == VALVE_DLL) || |
|
((mod_id == GEARBOX_DLL) && (pent_info_ctfdetect == NULL)) || |
|
(mod_id == HOLYWARS_DLL) || (mod_id == DMC_DLL)) |
|
{ |
|
char c_skill[2]; |
|
char c_topcolor[4]; |
|
char c_bottomcolor[4]; |
|
|
|
sprintf(c_skill, "%d", bots[index].bot_skill); |
|
sprintf(c_topcolor, "%d", bots[index].top_color); |
|
sprintf(c_bottomcolor, "%d", bots[index].bottom_color); |
|
|
|
BotCreate(NULL, bots[index].skin, bots[index].name, c_skill, c_topcolor, c_bottomcolor); |
|
} |
|
else |
|
{ |
|
char c_skill[2]; |
|
char c_team[2]; |
|
char c_class[3]; |
|
|
|
sprintf(c_skill, "%d", bots[index].bot_skill); |
|
sprintf(c_team, "%d", bots[index].bot_team); |
|
sprintf(c_class, "%d", bots[index].bot_class); |
|
|
|
if ((mod_id == TFC_DLL) || (mod_id == GEARBOX_DLL)) |
|
BotCreate(NULL, NULL, NULL, bots[index].name, c_skill, NULL); |
|
else |
|
BotCreate(NULL, c_team, c_class, bots[index].name, c_skill, NULL); |
|
} |
|
|
|
bot_strafe_percent = strafe; // restore global strafe percent |
|
bot_chat_percent = chat; // restore global chat percent |
|
bot_taunt_percent = taunt; // restore global taunt percent |
|
bot_whine_percent = whine; // restore global whine percent |
|
bot_grenade_time = grenade; // restore global grenade time |
|
bot_logo_percent = logo; // restore global logo percent |
|
bot_chat_tag_percent = tag; // restore global chat percent |
|
bot_chat_drop_percent = drop; // restore global chat percent |
|
bot_chat_swap_percent = swap; // restore global chat percent |
|
bot_chat_lower_percent = lower; // restore global chat percent |
|
bot_reaction_time = react; |
|
|
|
respawn_time = gpGlobals->time + 2.0; // set next respawn time |
|
|
|
bot_check_time = gpGlobals->time + 5.0; |
|
} |
|
else |
|
{ |
|
respawn_time = 0.0; |
|
} |
|
} |
|
|
|
if (g_GameRules) |
|
{ |
|
if (need_to_open_cfg) // have we open HPB_bot.cfg file yet? |
|
{ |
|
char filename[256]; |
|
char mapname[64]; |
|
|
|
need_to_open_cfg = FALSE; // only do this once!!! |
|
|
|
// check if mapname_HPB_bot.cfg file exists... |
|
|
|
strcpy(mapname, STRING(gpGlobals->mapname)); |
|
strcat(mapname, "_HPB_bot.cfg"); |
|
|
|
UTIL_BuildFileName(filename, "maps", mapname); |
|
|
|
if ((bot_cfg_fp = fopen(filename, "r")) != NULL) |
|
{ |
|
sprintf(msg, "Executing %s\n", filename); |
|
ALERT( at_console, msg ); |
|
} |
|
else |
|
{ |
|
UTIL_BuildFileName(filename, "HPB_bot.cfg", NULL); |
|
|
|
sprintf(msg, "Executing %s\n", filename); |
|
ALERT( at_console, msg ); |
|
|
|
bot_cfg_fp = fopen(filename, "r"); |
|
|
|
if (bot_cfg_fp == NULL) |
|
ALERT( at_console, "HPB_bot.cfg file not found\n" ); |
|
} |
|
|
|
if (IsDedicatedServer) |
|
bot_cfg_pause_time = gpGlobals->time + 5.0; |
|
else |
|
bot_cfg_pause_time = gpGlobals->time + 20.0; |
|
} |
|
|
|
if (!IsDedicatedServer && !spawn_time_reset) |
|
{ |
|
if (listenserver_edict != NULL) |
|
{ |
|
if (IsAlive(listenserver_edict)) |
|
{ |
|
spawn_time_reset = TRUE; |
|
|
|
if (respawn_time >= 1.0) |
|
respawn_time = min(respawn_time, gpGlobals->time + (float)1.0); |
|
|
|
if (bot_cfg_pause_time >= 1.0) |
|
bot_cfg_pause_time = min(bot_cfg_pause_time, gpGlobals->time + (float)1.0); |
|
} |
|
} |
|
} |
|
|
|
if ((bot_cfg_fp) && |
|
(bot_cfg_pause_time >= 1.0) && (bot_cfg_pause_time <= gpGlobals->time)) |
|
{ |
|
// process HPB_bot.cfg file options... |
|
ProcessBotCfgFile(); |
|
} |
|
|
|
} |
|
|
|
// if time to check for server commands then do so... |
|
if ((check_server_cmd <= gpGlobals->time) && IsDedicatedServer) |
|
{ |
|
check_server_cmd = gpGlobals->time + 1.0; |
|
|
|
char *cvar_bot = (char *)CVAR_GET_STRING( "HPB_bot" ); |
|
|
|
if ( cvar_bot && cvar_bot[0] ) |
|
{ |
|
char cmd_line[80]; |
|
char *cmd, *arg1, *arg2, *arg3, *arg4, *arg5; |
|
|
|
strcpy(cmd_line, cvar_bot); |
|
|
|
index = 0; |
|
cmd = cmd_line; |
|
arg1 = arg2 = arg3 = arg4 = arg5 = NULL; |
|
|
|
// skip to blank or end of string... |
|
while ((cmd_line[index] != ' ') && (cmd_line[index] != 0)) |
|
index++; |
|
|
|
if (cmd_line[index] == ' ') |
|
{ |
|
cmd_line[index++] = 0; |
|
arg1 = &cmd_line[index]; |
|
|
|
// skip to blank or end of string... |
|
while ((cmd_line[index] != ' ') && (cmd_line[index] != 0)) |
|
index++; |
|
|
|
if (cmd_line[index] == ' ') |
|
{ |
|
cmd_line[index++] = 0; |
|
arg2 = &cmd_line[index]; |
|
|
|
// skip to blank or end of string... |
|
while ((cmd_line[index] != ' ') && (cmd_line[index] != 0)) |
|
index++; |
|
|
|
if (cmd_line[index] == ' ') |
|
{ |
|
cmd_line[index++] = 0; |
|
arg3 = &cmd_line[index]; |
|
|
|
// skip to blank or end of string... |
|
while ((cmd_line[index] != ' ') && (cmd_line[index] != 0)) |
|
index++; |
|
|
|
if (cmd_line[index] == ' ') |
|
{ |
|
cmd_line[index++] = 0; |
|
arg4 = &cmd_line[index]; |
|
|
|
// skip to blank or end of string... |
|
while ((cmd_line[index] != ' ') && (cmd_line[index] != 0)) |
|
index++; |
|
|
|
if (cmd_line[index] == ' ') |
|
{ |
|
cmd_line[index++] = 0; |
|
arg5 = &cmd_line[index]; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
if (strcmp(cmd, "addbot") == 0) |
|
{ |
|
BotCreate( NULL, arg1, arg2, arg3, arg4, arg5 ); |
|
|
|
bot_check_time = gpGlobals->time + 5.0; |
|
} |
|
else if (strcmp(cmd, "min_bots") == 0) |
|
{ |
|
min_bots = atoi( arg1 ); |
|
|
|
if ((min_bots < 0) || (min_bots > 31)) |
|
min_bots = 1; |
|
|
|
sprintf(msg, "min_bots set to %d\n", min_bots); |
|
printf(msg); |
|
} |
|
else if (strcmp(cmd, "max_bots") == 0) |
|
{ |
|
max_bots = atoi( arg1 ); |
|
|
|
if ((max_bots < 0) || (max_bots > 31)) |
|
max_bots = 1; |
|
|
|
sprintf(msg, "max_bots set to %d\n", max_bots); |
|
printf(msg); |
|
} |
|
|
|
CVAR_SET_STRING("HPB_bot", ""); |
|
} |
|
} |
|
|
|
// check if time to see if a bot needs to be created... |
|
if (bot_check_time < gpGlobals->time) |
|
{ |
|
int count = 0; |
|
|
|
bot_check_time = gpGlobals->time + 5.0; |
|
|
|
for (i = 0; i < 32; i++) |
|
{ |
|
if (clients[i] != NULL) |
|
count++; |
|
} |
|
|
|
// if there are currently less than the maximum number of "players" |
|
// then add another bot using the default skill level... |
|
if ((count < max_bots) && (max_bots != -1)) |
|
{ |
|
BotCreate( NULL, NULL, NULL, NULL, NULL, NULL ); |
|
} |
|
} |
|
|
|
previous_time = gpGlobals->time; |
|
} |
|
|
|
(*other_gFunctionTable.pfnStartFrame)(); |
|
} |
|
|
|
void ParmsNewLevel( void ) |
|
{ |
|
(*other_gFunctionTable.pfnParmsNewLevel)(); |
|
} |
|
|
|
void ParmsChangeLevel( void ) |
|
{ |
|
(*other_gFunctionTable.pfnParmsChangeLevel)(); |
|
} |
|
|
|
const char *GetGameDescription( void ) |
|
{ |
|
return (*other_gFunctionTable.pfnGetGameDescription)(); |
|
} |
|
|
|
void PlayerCustomization( edict_t *pEntity, customization_t *pCust ) |
|
{ |
|
if (debug_engine) { fp=fopen("HPB_bot.txt", "a"); fprintf(fp, "PlayerCustomization: %x\n",pEntity); fclose(fp); } |
|
|
|
(*other_gFunctionTable.pfnPlayerCustomization)(pEntity, pCust); |
|
} |
|
|
|
void SpectatorConnect( edict_t *pEntity ) |
|
{ |
|
(*other_gFunctionTable.pfnSpectatorConnect)(pEntity); |
|
} |
|
|
|
void SpectatorDisconnect( edict_t *pEntity ) |
|
{ |
|
(*other_gFunctionTable.pfnSpectatorDisconnect)(pEntity); |
|
} |
|
|
|
void SpectatorThink( edict_t *pEntity ) |
|
{ |
|
(*other_gFunctionTable.pfnSpectatorThink)(pEntity); |
|
} |
|
|
|
void Sys_Error( const char *error_string ) |
|
{ |
|
(*other_gFunctionTable.pfnSys_Error)(error_string); |
|
} |
|
|
|
void PM_Move ( struct playermove_s *ppmove, int server ) |
|
{ |
|
(*other_gFunctionTable.pfnPM_Move)(ppmove, server); |
|
} |
|
|
|
void PM_Init ( struct playermove_s *ppmove ) |
|
{ |
|
(*other_gFunctionTable.pfnPM_Init)(ppmove); |
|
} |
|
|
|
char PM_FindTextureType( char *name ) |
|
{ |
|
return (*other_gFunctionTable.pfnPM_FindTextureType)(name); |
|
} |
|
|
|
void SetupVisibility( edict_t *pViewEntity, edict_t *pClient, unsigned char **pvs, unsigned char **pas ) |
|
{ |
|
(*other_gFunctionTable.pfnSetupVisibility)(pViewEntity, pClient, pvs, pas); |
|
} |
|
|
|
void UpdateClientData ( const struct edict_s *ent, int sendweapons, struct clientdata_s *cd ) |
|
{ |
|
(*other_gFunctionTable.pfnUpdateClientData)(ent, sendweapons, cd); |
|
} |
|
|
|
int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, unsigned char *pSet ) |
|
{ |
|
return (*other_gFunctionTable.pfnAddToFullPack)(state, e, ent, host, hostflags, player, pSet); |
|
} |
|
|
|
void CreateBaseline( int player, int eindex, struct entity_state_s *baseline, struct edict_s *entity, int playermodelindex, vec3_t player_mins, vec3_t player_maxs ) |
|
{ |
|
(*other_gFunctionTable.pfnCreateBaseline)(player, eindex, baseline, entity, playermodelindex, player_mins, player_maxs); |
|
} |
|
|
|
void RegisterEncoders( void ) |
|
{ |
|
(*other_gFunctionTable.pfnRegisterEncoders)(); |
|
} |
|
|
|
int GetWeaponData( struct edict_s *player, struct weapon_data_s *info ) |
|
{ |
|
return (*other_gFunctionTable.pfnGetWeaponData)(player, info); |
|
} |
|
|
|
void CmdStart( const edict_t *player, const struct usercmd_s *cmd, unsigned int random_seed ) |
|
{ |
|
(*other_gFunctionTable.pfnCmdStart)(player, cmd, random_seed); |
|
} |
|
|
|
void CmdEnd ( const edict_t *player ) |
|
{ |
|
(*other_gFunctionTable.pfnCmdEnd)(player); |
|
} |
|
|
|
int ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ) |
|
{ |
|
return (*other_gFunctionTable.pfnConnectionlessPacket)(net_from, args, response_buffer, response_buffer_size); |
|
} |
|
|
|
int GetHullBounds( int hullnumber, float *mins, float *maxs ) |
|
{ |
|
return (*other_gFunctionTable.pfnGetHullBounds)(hullnumber, mins, maxs); |
|
} |
|
|
|
void CreateInstancedBaselines( void ) |
|
{ |
|
(*other_gFunctionTable.pfnCreateInstancedBaselines)(); |
|
} |
|
|
|
int InconsistentFile( const edict_t *player, const char *filename, char *disconnect_message ) |
|
{ |
|
if (debug_engine) { fp=fopen("HPB_bot.txt", "a"); fprintf(fp, "InconsistentFile: %x filename=%s\n",player,filename); fclose(fp); } |
|
|
|
return (*other_gFunctionTable.pfnInconsistentFile)(player, filename, disconnect_message); |
|
} |
|
|
|
int AllowLagCompensation( void ) |
|
{ |
|
return (*other_gFunctionTable.pfnAllowLagCompensation)(); |
|
} |
|
|
|
|
|
DLL_FUNCTIONS gFunctionTable = |
|
{ |
|
GameDLLInit, //pfnGameInit |
|
DispatchSpawn, //pfnSpawn |
|
DispatchThink, //pfnThink |
|
DispatchUse, //pfnUse |
|
DispatchTouch, //pfnTouch |
|
DispatchBlocked, //pfnBlocked |
|
DispatchKeyValue, //pfnKeyValue |
|
DispatchSave, //pfnSave |
|
DispatchRestore, //pfnRestore |
|
DispatchObjectCollsionBox, //pfnAbsBox |
|
|
|
SaveWriteFields, //pfnSaveWriteFields |
|
SaveReadFields, //pfnSaveReadFields |
|
|
|
SaveGlobalState, //pfnSaveGlobalState |
|
RestoreGlobalState, //pfnRestoreGlobalState |
|
ResetGlobalState, //pfnResetGlobalState |
|
|
|
ClientConnect, //pfnClientConnect |
|
ClientDisconnect, //pfnClientDisconnect |
|
ClientKill, //pfnClientKill |
|
ClientPutInServer, //pfnClientPutInServer |
|
ClientCommand, //pfnClientCommand |
|
ClientUserInfoChanged, //pfnClientUserInfoChanged |
|
ServerActivate, //pfnServerActivate |
|
ServerDeactivate, //pfnServerDeactivate |
|
|
|
PlayerPreThink, //pfnPlayerPreThink |
|
PlayerPostThink, //pfnPlayerPostThink |
|
|
|
StartFrame, //pfnStartFrame |
|
ParmsNewLevel, //pfnParmsNewLevel |
|
ParmsChangeLevel, //pfnParmsChangeLevel |
|
|
|
GetGameDescription, //pfnGetGameDescription Returns string describing current .dll game. |
|
PlayerCustomization, //pfnPlayerCustomization Notifies .dll of new customization for player. |
|
|
|
SpectatorConnect, //pfnSpectatorConnect Called when spectator joins server |
|
SpectatorDisconnect, //pfnSpectatorDisconnect Called when spectator leaves the server |
|
SpectatorThink, //pfnSpectatorThink Called when spectator sends a command packet (usercmd_t) |
|
|
|
Sys_Error, //pfnSys_Error Called when engine has encountered an error |
|
|
|
PM_Move, //pfnPM_Move |
|
PM_Init, //pfnPM_Init Server version of player movement initialization |
|
PM_FindTextureType, //pfnPM_FindTextureType |
|
|
|
SetupVisibility, //pfnSetupVisibility Set up PVS and PAS for networking for this client |
|
UpdateClientData, //pfnUpdateClientData Set up data sent only to specific client |
|
AddToFullPack, //pfnAddToFullPack |
|
CreateBaseline, //pfnCreateBaseline Tweak entity baseline for network encoding, allows setup of player baselines, too. |
|
RegisterEncoders, //pfnRegisterEncoders Callbacks for network encoding |
|
GetWeaponData, //pfnGetWeaponData |
|
CmdStart, //pfnCmdStart |
|
CmdEnd, //pfnCmdEnd |
|
ConnectionlessPacket, //pfnConnectionlessPacket |
|
GetHullBounds, //pfnGetHullBounds |
|
CreateInstancedBaselines, //pfnCreateInstancedBaselines |
|
InconsistentFile, //pfnInconsistentFile |
|
AllowLagCompensation, //pfnAllowLagCompensation |
|
}; |
|
|
|
#ifdef __BORLANDC__ |
|
int EXPORT GetEntityAPI( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion ) |
|
#else |
|
extern "C" EXPORT int GetEntityAPI( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion ) |
|
#endif |
|
{ |
|
// check if engine's pointer is valid and version is correct... |
|
|
|
if ( !pFunctionTable || interfaceVersion != INTERFACE_VERSION ) |
|
return FALSE; |
|
|
|
// pass engine callback function table to engine... |
|
memcpy( pFunctionTable, &gFunctionTable, sizeof( DLL_FUNCTIONS ) ); |
|
|
|
// pass other DLLs engine callbacks to function table... |
|
if (!(*other_GetEntityAPI)(&other_gFunctionTable, INTERFACE_VERSION)) |
|
{ |
|
return FALSE; // error initializing function table!!! |
|
} |
|
|
|
return TRUE; |
|
} |
|
|
|
|
|
#ifdef __BORLANDC__ |
|
int EXPORT GetNewDLLFunctions( NEW_DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ) |
|
#else |
|
extern "C" EXPORT int GetNewDLLFunctions( NEW_DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ) |
|
#endif |
|
{ |
|
if (other_GetNewDLLFunctions == NULL) |
|
return FALSE; |
|
|
|
// pass other DLLs engine callbacks to function table... |
|
if (!(*other_GetNewDLLFunctions)(pFunctionTable, interfaceVersion)) |
|
{ |
|
return FALSE; // error initializing function table!!! |
|
} |
|
|
|
return TRUE; |
|
} |
|
|
|
|
|
void FakeClientCommand(edict_t *pBot, char *arg1, char *arg2, char *arg3) |
|
{ |
|
int length; |
|
|
|
memset(g_argv, 0, 1024); |
|
|
|
isFakeClientCommand = 1; |
|
|
|
if ((arg1 == NULL) || (*arg1 == 0)) |
|
return; |
|
|
|
if ((arg2 == NULL) || (*arg2 == 0)) |
|
{ |
|
length = sprintf(&g_argv[0], "%s", arg1); |
|
fake_arg_count = 1; |
|
} |
|
else if ((arg3 == NULL) || (*arg3 == 0)) |
|
{ |
|
length = sprintf(&g_argv[0], "%s %s", arg1, arg2); |
|
fake_arg_count = 2; |
|
} |
|
else |
|
{ |
|
length = sprintf(&g_argv[0], "%s %s %s", arg1, arg2, arg3); |
|
fake_arg_count = 3; |
|
} |
|
|
|
g_argv[length] = 0; // null terminate just in case |
|
|
|
strcpy(&g_argv[64], arg1); |
|
|
|
if (arg2) |
|
strcpy(&g_argv[128], arg2); |
|
|
|
if (arg3) |
|
strcpy(&g_argv[192], arg3); |
|
|
|
if (debug_engine) { fp=fopen("HPB_bot.txt","a"); fprintf(fp,"FakeClientCommand=%s\n",g_argv); fclose(fp); } |
|
|
|
// allow the MOD DLL to execute the ClientCommand... |
|
ClientCommand(pBot); |
|
|
|
isFakeClientCommand = 0; |
|
} |
|
|
|
|
|
const char *Cmd_Args( void ) |
|
{ |
|
if (isFakeClientCommand) |
|
{ |
|
return &g_argv[0]; |
|
} |
|
else |
|
{ |
|
return (*g_engfuncs.pfnCmd_Args)(); |
|
} |
|
} |
|
|
|
|
|
const char *Cmd_Argv( int argc ) |
|
{ |
|
if (isFakeClientCommand) |
|
{ |
|
if (argc == 0) |
|
{ |
|
return &g_argv[64]; |
|
} |
|
else if (argc == 1) |
|
{ |
|
return &g_argv[128]; |
|
} |
|
else if (argc == 2) |
|
{ |
|
return &g_argv[192]; |
|
} |
|
else |
|
{ |
|
return NULL; |
|
} |
|
} |
|
else |
|
{ |
|
return (*g_engfuncs.pfnCmd_Argv)(argc); |
|
} |
|
} |
|
|
|
|
|
int Cmd_Argc( void ) |
|
{ |
|
if (isFakeClientCommand) |
|
{ |
|
return fake_arg_count; |
|
} |
|
else |
|
{ |
|
return (*g_engfuncs.pfnCmd_Argc)(); |
|
} |
|
} |
|
|
|
|
|
void ProcessBotCfgFile(void) |
|
{ |
|
int ch; |
|
char cmd_line[256]; |
|
int cmd_index; |
|
static char server_cmd[80]; |
|
char *cmd, *arg1, *arg2, *arg3, *arg4, *arg5; |
|
char msg[80]; |
|
|
|
if (bot_cfg_pause_time > gpGlobals->time) |
|
return; |
|
|
|
if (bot_cfg_fp == NULL) |
|
return; |
|
|
|
cmd_index = 0; |
|
cmd_line[cmd_index] = 0; |
|
|
|
ch = fgetc(bot_cfg_fp); |
|
|
|
// skip any leading blanks |
|
while (ch == ' ') |
|
ch = fgetc(bot_cfg_fp); |
|
|
|
while ((ch != EOF) && (ch != '\r') && (ch != '\n')) |
|
{ |
|
if (ch == '\t') // convert tabs to spaces |
|
ch = ' '; |
|
|
|
cmd_line[cmd_index] = ch; |
|
|
|
ch = fgetc(bot_cfg_fp); |
|
|
|
// skip multiple spaces in input file |
|
while ((cmd_line[cmd_index] == ' ') && |
|
(ch == ' ')) |
|
ch = fgetc(bot_cfg_fp); |
|
|
|
cmd_index++; |
|
} |
|
|
|
if (ch == '\r') // is it a carriage return? |
|
{ |
|
ch = fgetc(bot_cfg_fp); // skip the linefeed |
|
} |
|
|
|
// if reached end of file, then close it |
|
if (ch == EOF) |
|
{ |
|
fclose(bot_cfg_fp); |
|
|
|
bot_cfg_fp = NULL; |
|
|
|
bot_cfg_pause_time = 0.0; |
|
} |
|
|
|
cmd_line[cmd_index] = 0; // terminate the command line |
|
|
|
// copy the command line to a server command buffer... |
|
strcpy(server_cmd, cmd_line); |
|
strcat(server_cmd, "\n"); |
|
|
|
cmd_index = 0; |
|
cmd = cmd_line; |
|
arg1 = arg2 = arg3 = arg4 = arg5 = NULL; |
|
|
|
// skip to blank or end of string... |
|
while ((cmd_line[cmd_index] != ' ') && (cmd_line[cmd_index] != 0)) |
|
cmd_index++; |
|
|
|
if (cmd_line[cmd_index] == ' ') |
|
{ |
|
cmd_line[cmd_index++] = 0; |
|
arg1 = &cmd_line[cmd_index]; |
|
|
|
// skip to blank or end of string... |
|
while ((cmd_line[cmd_index] != ' ') && (cmd_line[cmd_index] != 0)) |
|
cmd_index++; |
|
|
|
if (cmd_line[cmd_index] == ' ') |
|
{ |
|
cmd_line[cmd_index++] = 0; |
|
arg2 = &cmd_line[cmd_index]; |
|
|
|
// skip to blank or end of string... |
|
while ((cmd_line[cmd_index] != ' ') && (cmd_line[cmd_index] != 0)) |
|
cmd_index++; |
|
|
|
if (cmd_line[cmd_index] == ' ') |
|
{ |
|
cmd_line[cmd_index++] = 0; |
|
arg3 = &cmd_line[cmd_index]; |
|
|
|
// skip to blank or end of string... |
|
while ((cmd_line[cmd_index] != ' ') && (cmd_line[cmd_index] != 0)) |
|
cmd_index++; |
|
|
|
if (cmd_line[cmd_index] == ' ') |
|
{ |
|
cmd_line[cmd_index++] = 0; |
|
arg4 = &cmd_line[cmd_index]; |
|
|
|
// skip to blank or end of string... |
|
while ((cmd_line[cmd_index] != ' ') && (cmd_line[cmd_index] != 0)) |
|
cmd_index++; |
|
|
|
if (cmd_line[cmd_index] == ' ') |
|
{ |
|
cmd_line[cmd_index++] = 0; |
|
arg5 = &cmd_line[cmd_index]; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
if ((cmd_line[0] == '#') || (cmd_line[0] == 0)) |
|
return; // return if comment or blank line |
|
|
|
if (strcmp(cmd, "addbot") == 0) |
|
{ |
|
BotCreate( NULL, arg1, arg2, arg3, arg4, arg5 ); |
|
|
|
// have to delay here or engine gives "Tried to write to |
|
// uninitialized sizebuf_t" error and crashes... |
|
|
|
bot_cfg_pause_time = gpGlobals->time + 2.0; |
|
bot_check_time = gpGlobals->time + 5.0; |
|
|
|
return; |
|
} |
|
|
|
if (strcmp(cmd, "botskill") == 0) |
|
{ |
|
int temp = atoi(arg1); |
|
|
|
if ((temp >= 1) && (temp <= 5)) |
|
default_bot_skill = atoi( arg1 ); // set default bot skill level |
|
|
|
return; |
|
} |
|
|
|
if (strcmp(cmd, "random_color") == 0) |
|
{ |
|
int temp = atoi(arg1); |
|
|
|
if (temp) |
|
b_random_color = TRUE; |
|
else |
|
b_random_color = FALSE; |
|
|
|
return; |
|
} |
|
|
|
if (strcmp(cmd, "bot_strafe_percent") == 0) |
|
{ |
|
int temp = atoi(arg1); |
|
|
|
if ((temp >= 0) && (temp <= 100)) |
|
bot_strafe_percent = atoi( arg1 ); // set bot strafe percent |
|
|
|
return; |
|
} |
|
|
|
if (strcmp(cmd, "bot_chat_percent") == 0) |
|
{ |
|
int temp = atoi(arg1); |
|
|
|
if ((temp >= 0) && (temp <= 100)) |
|
bot_chat_percent = atoi( arg1 ); // set bot chat percent |
|
|
|
return; |
|
} |
|
|
|
if (strcmp(cmd, "bot_taunt_percent") == 0) |
|
{ |
|
int temp = atoi(arg1); |
|
|
|
if ((temp >= 0) && (temp <= 100)) |
|
bot_taunt_percent = atoi( arg1 ); // set bot taunt percent |
|
|
|
return; |
|
} |
|
|
|
if (strcmp(cmd, "bot_whine_percent") == 0) |
|
{ |
|
int temp = atoi(arg1); |
|
|
|
if ((temp >= 0) && (temp <= 100)) |
|
bot_whine_percent = atoi( arg1 ); // set bot whine percent |
|
|
|
return; |
|
} |
|
|
|
if (strcmp(cmd, "bot_chat_tag_percent") == 0) |
|
{ |
|
int temp = atoi(arg1); |
|
|
|
if ((temp >= 0) && (temp <= 100)) |
|
bot_chat_tag_percent = atoi( arg1 ); // set bot chat percent |
|
|
|
return; |
|
} |
|
|
|
if (strcmp(cmd, "bot_chat_drop_percent") == 0) |
|
{ |
|
int temp = atoi(arg1); |
|
|
|
if ((temp >= 0) && (temp <= 100)) |
|
bot_chat_drop_percent = atoi( arg1 ); // set bot chat percent |
|
|
|
return; |
|
} |
|
|
|
if (strcmp(cmd, "bot_chat_swap_percent") == 0) |
|
{ |
|
int temp = atoi(arg1); |
|
|
|
if ((temp >= 0) && (temp <= 100)) |
|
bot_chat_swap_percent = atoi( arg1 ); // set bot chat percent |
|
|
|
return; |
|
} |
|
|
|
if (strcmp(cmd, "bot_chat_lower_percent") == 0) |
|
{ |
|
int temp = atoi(arg1); |
|
|
|
if ((temp >= 0) && (temp <= 100)) |
|
bot_chat_lower_percent = atoi( arg1 ); // set bot chat percent |
|
|
|
return; |
|
} |
|
|
|
if (strcmp(cmd, "bot_grenade_time") == 0) |
|
{ |
|
int temp = atoi(arg1); |
|
|
|
if ((temp >= 0) && (temp <= 60)) |
|
bot_grenade_time = atoi( arg1 ); // set bot grenade time |
|
|
|
return; |
|
} |
|
|
|
if (strcmp(cmd, "bot_logo_percent") == 0) |
|
{ |
|
int temp = atoi(arg1); |
|
|
|
if ((temp >= 0) && (temp <= 100)) |
|
bot_logo_percent = atoi( arg1 ); // set bot strafe percent |
|
|
|
return; |
|
} |
|
|
|
if (strcmp(cmd, "bot_reaction_time") == 0) |
|
{ |
|
int temp = atoi(arg1); |
|
|
|
if ((temp >= 0) && (temp <= 3)) |
|
bot_reaction_time = atoi( arg1 ); // set bot reaction time |
|
|
|
return; |
|
} |
|
|
|
if (strcmp(cmd, "observer") == 0) |
|
{ |
|
int temp = atoi(arg1); |
|
|
|
if (temp) |
|
b_observer_mode = TRUE; |
|
else |
|
b_observer_mode = FALSE; |
|
|
|
return; |
|
} |
|
|
|
if (strcmp(cmd, "botdontshoot") == 0) |
|
{ |
|
int temp = atoi(arg1); |
|
|
|
if (temp) |
|
b_botdontshoot = TRUE; |
|
else |
|
b_botdontshoot = FALSE; |
|
|
|
return; |
|
} |
|
|
|
if (strcmp(cmd, "min_bots") == 0) |
|
{ |
|
min_bots = atoi( arg1 ); |
|
|
|
if ((min_bots < 0) || (min_bots > 31)) |
|
min_bots = 1; |
|
|
|
if (IsDedicatedServer) |
|
{ |
|
sprintf(msg, "min_bots set to %d\n", min_bots); |
|
printf(msg); |
|
} |
|
|
|
return; |
|
} |
|
|
|
if (strcmp(cmd, "max_bots") == 0) |
|
{ |
|
max_bots = atoi( arg1 ); |
|
|
|
if ((max_bots < 0) || (max_bots > 31)) |
|
max_bots = 1; |
|
|
|
if (IsDedicatedServer) |
|
{ |
|
sprintf(msg, "max_bots set to %d\n", max_bots); |
|
printf(msg); |
|
} |
|
|
|
return; |
|
} |
|
|
|
if (strcmp(cmd, "pause") == 0) |
|
{ |
|
bot_cfg_pause_time = gpGlobals->time + atoi( arg1 ); |
|
|
|
return; |
|
} |
|
|
|
sprintf(msg, "executing server command: %s\n", server_cmd); |
|
ALERT( at_console, msg ); |
|
|
|
if (IsDedicatedServer) |
|
printf(msg); |
|
|
|
SERVER_COMMAND(server_cmd); |
|
}
|
|
|