From e6e7056aae76bf1356a1e7f966314709b93171f9 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 14 Jun 2023 09:16:38 -0400 Subject: [PATCH] Add bot styles & bot spawn ACS function --- src/acs/call-funcs.cpp | 46 ++++++++++++++++++++ src/acs/call-funcs.hpp | 1 + src/acs/environment.cpp | 1 + src/acs/thread.cpp | 2 - src/acs/thread.hpp | 3 +- src/d_clisrv.c | 3 ++ src/d_player.h | 11 +++++ src/k_bot.c | 95 +++++++++++++++++++++++++++-------------- src/k_bot.h | 5 ++- src/k_grandprix.c | 2 +- 10 files changed, 132 insertions(+), 37 deletions(-) diff --git a/src/acs/call-funcs.cpp b/src/acs/call-funcs.cpp index cfb84c7b8..54fc987bd 100644 --- a/src/acs/call-funcs.cpp +++ b/src/acs/call-funcs.cpp @@ -41,6 +41,7 @@ #include "../r_skins.h" #include "../k_battle.h" #include "../k_podium.h" +#include "../k_bot.h" #include "../z_zone.h" #include "call-funcs.hpp" @@ -1710,6 +1711,51 @@ bool CallFunc_MapWarp(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Wor return false; } +/*-------------------------------------------------- + bool CallFunc_AddBot(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Inserts a bot, if there's room for them. +--------------------------------------------------*/ +bool CallFunc_AddBot(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + ACSVM::MapScope *map = NULL; + + ACSVM::String *skinStr = nullptr; + INT32 skin = -1; + + UINT8 difficulty = 0; + botStyle_e style = BOT_STYLE_NORMAL; + + UINT8 newplayernum = 0; + + (void)argC; + + map = thread->scopeMap; + + skinStr = map->getString(argV[0]); + if (skinStr->len != 0) + { + skin = R_SkinAvailable(skinStr->str); + } + + if (skin == -1) + { + skin = R_BotDefaultSkin(); + } + + difficulty = std::clamp(static_cast(argV[1]), 1, MAXBOTDIFFICULTY); + + style = static_cast(argV[2]); + if (style < BOT_STYLE_NORMAL || style >= BOT_STYLE__MAX) + { + style = BOT_STYLE_NORMAL; + } + + K_AddBot(skin, difficulty, style, &newplayernum); + thread->dataStk.push(newplayernum); + return false; +} + /*-------------------------------------------------- bool CallFunc_Get/SetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) diff --git a/src/acs/call-funcs.hpp b/src/acs/call-funcs.hpp index a59b4d916..9bc46d0ef 100644 --- a/src/acs/call-funcs.hpp +++ b/src/acs/call-funcs.hpp @@ -84,6 +84,7 @@ bool CallFunc_PodiumFinish(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM bool CallFunc_SetLineRenderStyle(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_MapWarp(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_AddBot(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_GetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_SetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); diff --git a/src/acs/environment.cpp b/src/acs/environment.cpp index ea0aaf5f2..0843773f8 100644 --- a/src/acs/environment.cpp +++ b/src/acs/environment.cpp @@ -166,6 +166,7 @@ Environment::Environment() addFuncDataACS0( 502, addCallFunc(CallFunc_PodiumFinish)); addFuncDataACS0( 503, addCallFunc(CallFunc_SetLineRenderStyle)); addFuncDataACS0( 504, addCallFunc(CallFunc_MapWarp)); + addFuncDataACS0( 505, addCallFunc(CallFunc_AddBot)); } ACSVM::Thread *Environment::allocThread() diff --git a/src/acs/thread.cpp b/src/acs/thread.cpp index 88494e5b3..35d088e22 100644 --- a/src/acs/thread.cpp +++ b/src/acs/thread.cpp @@ -15,7 +15,6 @@ #include "thread.hpp" -extern "C" { #include "../doomtype.h" #include "../doomdef.h" #include "../doomstat.h" @@ -26,7 +25,6 @@ extern "C" { #include "../r_defs.h" #include "../r_state.h" #include "../p_polyobj.h" -} using namespace srb2::acs; diff --git a/src/acs/thread.hpp b/src/acs/thread.hpp index 61c0d8fe2..3c146ddf6 100644 --- a/src/acs/thread.hpp +++ b/src/acs/thread.hpp @@ -16,6 +16,7 @@ #include "acsvm.hpp" +extern "C" { #include "../doomtype.h" #include "../doomdef.h" #include "../doomstat.h" @@ -23,7 +24,7 @@ #include "../r_defs.h" #include "../r_state.h" #include "../p_spec.h" - +} namespace srb2::acs { diff --git a/src/d_clisrv.c b/src/d_clisrv.c index c36bc9d8c..445545322 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -4010,6 +4010,7 @@ static void Got_AddBot(UINT8 **p, INT32 playernum) INT16 newplayernum; UINT8 skinnum = 0; UINT8 difficulty = DIFFICULTBOT; + botStyle_e style = BOT_STYLE_NORMAL; if (playernum != serverplayer && !IsPlayerAdmin(playernum)) { @@ -4025,6 +4026,7 @@ static void Got_AddBot(UINT8 **p, INT32 playernum) newplayernum = READUINT8(*p); skinnum = READUINT8(*p); difficulty = READUINT8(*p); + style = READUINT8(*p); CONS_Debug(DBG_NETPLAY, "addbot: %d\n", newplayernum); @@ -4045,6 +4047,7 @@ static void Got_AddBot(UINT8 **p, INT32 playernum) players[newplayernum].splitscreenindex = 0; players[newplayernum].bot = true; players[newplayernum].botvars.difficulty = difficulty; + players[newplayernum].botvars.style = style; players[newplayernum].lives = 9; players[newplayernum].skincolor = skins[skinnum].prefcolor; diff --git a/src/d_player.h b/src/d_player.h index 877f65c59..9a0a7e7b5 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -313,9 +313,20 @@ struct respawnvars_t boolean init; }; +typedef enum +{ + BOT_STYLE_NORMAL, + BOT_STYLE_STAY, + //BOT_STYLE_CHASE, + //BOT_STYLE_ESCAPE, + BOT_STYLE__MAX +} botStyle_e; + // player_t struct for all bot variables struct botvars_t { + botStyle_e style; // Training mode-style CPU mode + UINT8 difficulty; // Bot's difficulty setting UINT8 diffincrease; // In GP: bot difficulty will increase this much next round boolean rival; // If true, they're the GP rival diff --git a/src/k_bot.c b/src/k_bot.c index 8c588b37f..02f5a4af1 100644 --- a/src/k_bot.c +++ b/src/k_bot.c @@ -37,11 +37,11 @@ #endif /*-------------------------------------------------- - boolean K_AddBot(UINT8 skin, UINT8 difficulty, UINT8 *p) + boolean K_AddBot(UINT8 skin, UINT8 difficulty, botStyle_e style, UINT8 *p) See header file for description. --------------------------------------------------*/ -boolean K_AddBot(UINT8 skin, UINT8 difficulty, UINT8 *p) +boolean K_AddBot(UINT8 skin, UINT8 difficulty, botStyle_e style, UINT8 *p) { UINT8 buf[3]; UINT8 *buf_p = buf; @@ -96,6 +96,7 @@ boolean K_AddBot(UINT8 skin, UINT8 difficulty, UINT8 *p) } WRITEUINT8(buf_p, difficulty); + WRITEUINT8(buf_p, style); SendNetXCmd(XD_ADDBOT, buf, buf_p - buf); @@ -156,6 +157,9 @@ void K_UpdateMatchRaceBots(void) // While we're here, we should update bot difficulty to the proper value. players[i].botvars.difficulty = difficulty; + + // Enforce normal style for Match Race + players[i].botvars.style = BOT_STYLE_NORMAL; } else { @@ -169,7 +173,7 @@ void K_UpdateMatchRaceBots(void) } } - if (difficulty == 0 || !(gametyperules & GTR_BOTS)) + if (difficulty == 0 || (gametyperules & GTR_BOTS) == 0) { wantedbots = 0; } @@ -217,7 +221,7 @@ void K_UpdateMatchRaceBots(void) grabskins[index] = grabskins[--usableskins]; } - if (!K_AddBot(skinnum, difficulty, &newplayernum)) + if (!K_AddBot(skinnum, difficulty, BOT_STYLE_NORMAL, &newplayernum)) { // Not enough player slots to add the bot, break the loop. break; @@ -231,7 +235,6 @@ void K_UpdateMatchRaceBots(void) UINT8 buf[2]; i = MAXPLAYERS; - while (numbots > wantedbots && i > 0) { i--; @@ -1473,11 +1476,11 @@ static void K_BuildBotPodiumTiccmd(player_t *player, ticcmd_t *cmd) } /*-------------------------------------------------- - void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd) + static void K_BuildBotTiccmdNormal(player_t *player, ticcmd_t *cmd) - See header file for description. + Build ticcmd for bots with a style of BOT_STYLE_NORMAL --------------------------------------------------*/ -void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd) +static void K_BuildBotTiccmdNormal(player_t *player, ticcmd_t *cmd) { precise_t t = 0; botprediction_t *predict = NULL; @@ -1487,29 +1490,6 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd) INT32 turnamt = 0; const line_t *botController = player->botvars.controller != UINT16_MAX ? &lines[player->botvars.controller] : NULL; - // Remove any existing controls - memset(cmd, 0, sizeof(ticcmd_t)); - - if (player->mo == NULL - || player->spectator == true - || G_GamestateUsesLevel() == false) - { - // Not in the level. - return; - } - - // Complete override of all ticcmd functionality - if (LUA_HookTiccmd(player, cmd, HOOK(BotTiccmd)) == true) - { - return; - } - - if (K_PodiumSequence() == true) - { - K_BuildBotPodiumTiccmd(player, cmd); - return; - } - if (!(gametyperules & GTR_BOTS) // No bot behaviors || K_GetNumWaypoints() == 0 // No waypoints || leveltime <= introtime // During intro camera @@ -1762,6 +1742,59 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd) } } +/*-------------------------------------------------- + void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd) + + See header file for description. +--------------------------------------------------*/ +void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd) +{ + precise_t t = 0; + botprediction_t *predict = NULL; + boolean trySpindash = true; + angle_t destangle = 0; + UINT8 spindash = 0; + INT32 turnamt = 0; + const line_t *botController = player->botvars.controller != UINT16_MAX ? &lines[player->botvars.controller] : NULL; + + // Remove any existing controls + memset(cmd, 0, sizeof(ticcmd_t)); + + if (player->mo == NULL + || player->spectator == true + || G_GamestateUsesLevel() == false) + { + // Not in the level. + return; + } + + // Complete override of all ticcmd functionality + if (LUA_HookTiccmd(player, cmd, HOOK(BotTiccmd)) == true) + { + return; + } + + if (K_PodiumSequence() == true) + { + K_BuildBotPodiumTiccmd(player, cmd); + return; + } + + switch (player->botvars.style) + { + case BOT_STYLE_STAY: + { + // Hey, this one's pretty easy :P + break; + } + default: + { + K_BuildBotTiccmdNormal(player, cmd); + break; + } + } +} + /*-------------------------------------------------- void K_UpdateBotGameplayVars(player_t *player); diff --git a/src/k_bot.h b/src/k_bot.h index ab75034ee..8eca06316 100644 --- a/src/k_bot.h +++ b/src/k_bot.h @@ -142,13 +142,14 @@ fixed_t K_DistanceOfLineFromPoint(fixed_t v1x, fixed_t v1y, fixed_t v2x, fixed_t /*-------------------------------------------------- - boolean K_AddBot(UINT8 skin, UINT8 difficulty, UINT8 *newplayernum); + boolean K_AddBot(UINT8 skin, UINT8 difficulty, botStyle_e style, UINT8 *newplayernum); Returns the waypoint actually being used as the finish line. Input Arguments:- skin - Skin number that the bot will use. difficulty - Difficulty level this bot will use. + style - Bot style to spawn this bot with, see botStyle_e. newplayernum - Pointer to the last valid player slot number. Is a pointer so that this function can be called multiple times to add more than one bot. @@ -156,7 +157,7 @@ fixed_t K_DistanceOfLineFromPoint(fixed_t v1x, fixed_t v1y, fixed_t v2x, fixed_t true if a bot packet can be sent, otherwise false. --------------------------------------------------*/ -boolean K_AddBot(UINT8 skin, UINT8 difficulty, UINT8 *newplayernum); +boolean K_AddBot(UINT8 skin, UINT8 difficulty, botStyle_e style, UINT8 *p); /*-------------------------------------------------- diff --git a/src/k_grandprix.c b/src/k_grandprix.c index dff88ceab..073ad7362 100644 --- a/src/k_grandprix.c +++ b/src/k_grandprix.c @@ -256,7 +256,7 @@ void K_InitGrandPrixBots(void) for (i = 0; i < wantedbots; i++) { - if (!K_AddBot(botskinlist[i], difficultylevels[i], &newplayernum)) + if (!K_AddBot(botskinlist[i], difficultylevels[i], BOT_STYLE_NORMAL, &newplayernum)) { break; }