diff --git a/src/d_player.h b/src/d_player.h index 1b9744efb..9eae9fdd8 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -367,7 +367,6 @@ struct botvars_t // All entries above persist between rounds and must be recorded in demos fixed_t rubberband; // Bot rubberband value - UINT16 controller; // Special bot controller linedef ID tic_t itemdelay; // Delay before using item at all tic_t itemconfirm; // When high enough, they will use their item diff --git a/src/g_game.c b/src/g_game.c index 72a580b47..6d4cc2b91 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2333,7 +2333,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) p->ringvolume = 255; p->botvars.rubberband = FRACUNIT; - p->botvars.controller = UINT16_MAX; p->spectatorReentry = spectatorReentry; p->griefValue = griefValue; diff --git a/src/k_bot.cpp b/src/k_bot.cpp index d6b070153..a63fd3056 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -379,74 +379,23 @@ static fixed_t K_BotSpeedScaled(player_t *player, fixed_t speed) } /*-------------------------------------------------- - static line_t *K_FindBotController(mobj_t *mo) + botcontroller_t *K_GetBotController(mobj_t *mobj) - Finds if any bot controller linedefs are tagged to the bot's sector. - - Input Arguments:- - mo - The bot player's mobj. - - Return:- - Linedef of the bot controller. nullptr if it doesn't exist. + See header file for description. --------------------------------------------------*/ -static line_t *K_FindBotController(mobj_t *mo) +botcontroller_t *K_GetBotController(mobj_t *mobj) { - msecnode_t *node; - ffloor_t *rover; - INT16 lineNum = -1; - mtag_t tag; - - I_Assert(mo != nullptr); - I_Assert(!P_MobjWasRemoved(mo)); - - for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next) - { - if (!node->m_sector) - { - continue; - } - - tag = Tag_FGet(&node->m_sector->tags); - lineNum = P_FindSpecialLineFromTag(2004, tag, -1); // todo: needs to not use P_FindSpecialLineFromTag - - if (lineNum != -1) - { - break; - } - - for (rover = node->m_sector->ffloors; rover; rover = rover->next) - { - sector_t *rs = nullptr; - - if (!(rover->fofflags & FOF_EXISTS)) - { - continue; - } - - if (mo->z > *rover->topheight || mo->z + mo->height < *rover->bottomheight) - { - continue; - } - - rs = §ors[rover->secnum]; - tag = Tag_FGet(&rs->tags); - lineNum = P_FindSpecialLineFromTag(2004, tag, -1); - - if (lineNum != -1) - { - break; - } - } - } - - if (lineNum != -1) - { - return &lines[lineNum]; - } - else + if (P_MobjWasRemoved(mobj) == true) { return nullptr; } + + if (mobj->subsector == nullptr || mobj->subsector->sector == nullptr) + { + return nullptr; + } + + return &mobj->subsector->sector->botController; } /*-------------------------------------------------- @@ -555,18 +504,10 @@ fixed_t K_BotRubberband(player_t *player) return FRACUNIT; } - if (player->botvars.controller != UINT16_MAX) + const botcontroller_t *botController = K_GetBotController(player->mo); + if (botController != nullptr && (botController->flags & TMBOT_NORUBBERBAND) == TMBOT_NORUBBERBAND) // Disable rubberbanding { - const line_t *botController = &lines[player->botvars.controller]; - - if (botController != nullptr) - { - // Disable rubberbanding - if (botController->args[1] & TMBOT_NORUBBERBAND) - { - return FRACUNIT; - } - } + return FRACUNIT; } for (i = 0; i < MAXPLAYERS; i++) @@ -1121,19 +1062,19 @@ static void K_DrawPredictionDebug(botprediction_t *predict, player_t *player) } /*-------------------------------------------------- - static void K_BotTrick(player_t *player, ticcmd_t *cmd, line_t *botController) + static void K_BotTrick(player_t *player, ticcmd_t *cmd, const botcontroller_t *botController) Determines inputs for trick panels. Input Arguments:- player - Player to generate the ticcmd for. cmd - The player's ticcmd to modify. - botController - Linedef for the bot controller. + botController - Bot controller struct. Return:- None --------------------------------------------------*/ -static void K_BotTrick(player_t *player, ticcmd_t *cmd, const line_t *botController) +static void K_BotTrick(player_t *player, ticcmd_t *cmd, const botcontroller_t *botController) { // Trick panel state -- do nothing until a controller line is found, in which case do a trick. if (botController == nullptr) @@ -1143,21 +1084,18 @@ static void K_BotTrick(player_t *player, ticcmd_t *cmd, const line_t *botControl if (player->trickpanel == 1) { - INT32 type = botController->args[0]; - - // Y Offset: Trick type - switch (type) + switch (botController->trick) { - case 1: + case TMBOTTR_LEFT: cmd->turning = KART_FULLTURN; break; - case 2: + case TMBOTTR_RIGHT: cmd->turning = -KART_FULLTURN; break; - case 3: + case TMBOTTR_UP: cmd->throwdir = KART_FULLTURN; break; - case 4: + case TMBOTTR_DOWN: cmd->throwdir = -KART_FULLTURN; break; } @@ -1531,7 +1469,6 @@ static void K_BuildBotTiccmdNormal(player_t *player, ticcmd_t *cmd) angle_t destangle = 0; UINT8 spindash = 0; INT32 turnamt = 0; - const line_t *botController = player->botvars.controller != UINT16_MAX ? &lines[player->botvars.controller] : nullptr; if (!(gametyperules & GTR_BOTS) // No bot behaviors || K_GetNumWaypoints() == 0 // No waypoints @@ -1554,15 +1491,9 @@ static void K_BuildBotTiccmdNormal(player_t *player, ticcmd_t *cmd) if (!cv_botcontrol.value) return; #endif + // Actual gameplay behaviors below this block! - - if (K_TryRingShooter(player) == true) - { - // We want to respawn. Simply hold Y and stop here! - cmd->buttons |= (BT_RESPAWN | BT_EBRAKEMASK); - return; - } - + const botcontroller_t *botController = K_GetBotController(player->mo); if (player->trickpanel != 0) { K_BotTrick(player, cmd, botController); @@ -1571,29 +1502,45 @@ static void K_BuildBotTiccmdNormal(player_t *player, ticcmd_t *cmd) return; } - if (botController != nullptr && (botController->args[1] & TMBOT_NOCONTROL)) + if (botController != nullptr && (botController->flags & TMBOT_NOCONTROL) == TMBOT_NOCONTROL) { // Disable bot controls entirely. return; } + if (K_TryRingShooter(player) == true) + { + // We want to respawn. Simply hold Y and stop here! + cmd->buttons |= (BT_RESPAWN | BT_EBRAKEMASK); + return; + } + destangle = player->mo->angle; - if (botController != nullptr && (botController->args[1] & TMBOT_FORCEDIR)) + if (botController != nullptr && (botController->flags & TMBOT_FORCEDIR) == TMBOT_FORCEDIR) { const fixed_t dist = DEFAULT_WAYPOINT_RADIUS * player->mo->scale; - // X Offset: Movement direction - destangle = FixedAngle(botController->args[2] * FRACUNIT); - // Overwritten prediction predict = static_cast(Z_Calloc(sizeof(botprediction_t), PU_STATIC, nullptr)); - predict->x = player->mo->x + FixedMul(dist, FINECOSINE(destangle >> ANGLETOFINESHIFT)); - predict->y = player->mo->y + FixedMul(dist, FINESINE(destangle >> ANGLETOFINESHIFT)); + predict->x = player->mo->x + FixedMul(dist, FINECOSINE(botController->forceAngle >> ANGLETOFINESHIFT)); + predict->y = player->mo->y + FixedMul(dist, FINESINE(botController->forceAngle >> ANGLETOFINESHIFT)); predict->radius = (DEFAULT_WAYPOINT_RADIUS / 4) * mapobjectscale; } + if (P_IsObjectOnGround(player->mo) == false) + { + if (botController != nullptr && (botController->flags & TMBOT_FASTFALL) == TMBOT_FASTFALL) + { + // Fast fall! + cmd->buttons |= BT_EBRAKEMASK; + return; + } + + return; + } + if (leveltime <= starttime && finishBeamLine != nullptr) { // Handle POSITION!! @@ -1838,9 +1785,6 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd) --------------------------------------------------*/ void K_UpdateBotGameplayVars(player_t *player) { - const line_t *botController; - - player->botvars.controller = UINT16_MAX; player->botvars.rubberband = FRACUNIT; if (gamestate != GS_LEVEL || !player->mo) @@ -1849,8 +1793,5 @@ void K_UpdateBotGameplayVars(player_t *player) return; } - botController = K_FindBotController(player->mo); - - player->botvars.controller = botController ? (botController - lines) : UINT16_MAX; player->botvars.rubberband = K_UpdateRubberband(player); } diff --git a/src/k_bot.h b/src/k_bot.h index 441bbffec..615450426 100644 --- a/src/k_bot.h +++ b/src/k_bot.h @@ -13,6 +13,7 @@ #ifndef __K_BOT__ #define __K_BOT__ +#include "typedef.h" #include "k_waypoint.h" #include "d_player.h" #include "r_defs.h" @@ -85,6 +86,22 @@ boolean K_PlayerUsesBotMovement(player_t *player); boolean K_BotCanTakeCut(player_t *player); +/*-------------------------------------------------- + botcontroller_t *K_GetBotController(mobj_t *mobj) + + Retrieves the current bot controller values from + the player's current sector. + + Input Arguments:- + mobj - The player's object to get the bot controller for. + + Return:- + Pointer to the sector's bot controller struct. +--------------------------------------------------*/ + +botcontroller_t *K_GetBotController(mobj_t *mobj); + + /*-------------------------------------------------- fixed_t K_BotMapModifier(void); diff --git a/src/p_saveg.c b/src/p_saveg.c index 4a8fd3027..2c9cd3173 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -611,7 +611,6 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEUINT8(save->p, players[i].botvars.diffincrease); WRITEUINT8(save->p, players[i].botvars.rival); WRITEFIXED(save->p, players[i].botvars.rubberband); - WRITEUINT16(save->p, players[i].botvars.controller); WRITEUINT32(save->p, players[i].botvars.itemdelay); WRITEUINT32(save->p, players[i].botvars.itemconfirm); WRITESINT8(save->p, players[i].botvars.turnconfirm); @@ -1126,7 +1125,6 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].botvars.diffincrease = READUINT8(save->p); players[i].botvars.rival = (boolean)READUINT8(save->p); players[i].botvars.rubberband = READFIXED(save->p); - players[i].botvars.controller = READUINT16(save->p); players[i].botvars.itemdelay = READUINT32(save->p); players[i].botvars.itemconfirm = READUINT32(save->p); players[i].botvars.turnconfirm = READSINT8(save->p); @@ -1729,6 +1727,7 @@ static void P_NetUnArchiveColormaps(savebuffer_t *save) //diff5 flags #define SD_ACTIVATION 0x01 +#define SD_BOTCONTROLLER 0x02 static boolean P_SectorArgsEqual(const sector_t *sc, const sector_t *spawnsc) { @@ -1964,6 +1963,12 @@ static void ArchiveSectors(savebuffer_t *save) diff4 |= SD_STRINGARGS; if (ss->activation != spawnss->activation) diff5 |= SD_ACTIVATION; + if (ss->botController.trick != spawnss->botController.trick + || ss->botController.flags != spawnss->botController.flags + || ss->botController.forceAngle != spawnss->botController.forceAngle) + { + diff5 |= SD_BOTCONTROLLER; + } if (ss->ffloors && CheckFFloorDiff(ss)) diff |= SD_FFLOORS; @@ -2076,6 +2081,12 @@ static void ArchiveSectors(savebuffer_t *save) } if (diff5 & SD_ACTIVATION) WRITEUINT32(save->p, ss->activation); + if (diff5 & SD_BOTCONTROLLER) + { + WRITEUINT8(save->p, ss->botController.trick); + WRITEUINT32(save->p, ss->botController.flags); + WRITEANGLE(save->p, ss->botController.forceAngle); + } if (diff & SD_FFLOORS) ArchiveFFloors(save, ss); @@ -2232,6 +2243,12 @@ static void UnArchiveSectors(savebuffer_t *save) } if (diff5 & SD_ACTIVATION) sectors[i].activation = READUINT32(save->p); + if (diff5 & SD_BOTCONTROLLER) + { + sectors[i].botController.trick = READUINT8(save->p); + sectors[i].botController.flags = READUINT32(save->p); + sectors[i].botController.forceAngle = READANGLE(save->p); + } if (diff & SD_FFLOORS) UnArchiveFFloors(save, §ors[i]); diff --git a/src/p_spec.c b/src/p_spec.c index 5071735a8..9b80efa4f 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1380,7 +1380,8 @@ boolean P_CanActivateSpecial(INT16 special) { case 2001: // Finish line case 2003: // Respawn line - case 2005: // Dismount Flying Object (always true here so that conditions are only kept on execution) + case 2004: // Bot controller + case 2005: // Dismount Flying Object { return true; } @@ -2474,6 +2475,20 @@ mobj_t* P_FindObjectTypeFromTag(mobjtype_t type, mtag_t tag) } } +static void K_UpdateBotControllers(INT32 *args) +{ + INT32 secnum; + + TAG_ITER_SECTORS(args[0], secnum) + { + sector_t *const sec = sectors + secnum; + + sec->botController.trick = args[1]; + sec->botController.flags = args[2]; + sec->botController.forceAngle = FixedAngle(args[3] * FRACUNIT); + } +} + /** Processes the line special triggered by an object. * * \param line Line with the special command on it. @@ -4418,8 +4433,8 @@ boolean P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, cha if ((gametyperules & GTR_CIRCUIT) && (mo->player->exiting == 0) && !(mo->player->pflags & PF_HITFINISHLINE)) { - if (((line->args[0] & TMCFF_FLIP) && (side == 0)) - || (!(line->args[0] & TMCFF_FLIP) && (side == 1))) // crossed from behind to infront + if (((args[0] & TMCFF_FLIP) && (side == 0)) + || (!(args[0] & TMCFF_FLIP) && (side == 1))) // crossed from behind to infront { K_HandleLapIncrement(mo->player); @@ -4446,7 +4461,7 @@ boolean P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, cha if ( mo->player->respawn.state == RESPAWNST_NONE && - (!(line->args[0] & TMCRF_FRONTONLY) || side == 0) + (!(args[0] & TMCRF_FRONTONLY) || side == 0) ) { P_DamageMobj(mo, NULL, NULL, 1, DMG_DEATHPIT); @@ -4454,6 +4469,12 @@ boolean P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, cha } break; + case 2004: // Bot Controller. + { + K_UpdateBotControllers(args); + break; + } + case 2005: // Dismount Flying object // the rideroid is a bit complex so it's the one controlling the player rather than the player controlling it. // so it is the object needing to be checked for rather than the player @@ -7641,6 +7662,10 @@ void P_SpawnSpecials(boolean fromnetsave) } break; + case 2004: // Bot Controller. + K_UpdateBotControllers(lines[i].args); + break; + default: break; } diff --git a/src/p_spec.h b/src/p_spec.h index f1f611213..31a03b330 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -525,8 +525,18 @@ typedef enum TMBOT_NORUBBERBAND = 1, TMBOT_NOCONTROL = 1<<1, TMBOT_FORCEDIR = 1<<2, + TMBOT_FASTFALL = 1<<3, } textmapbotcontroller_t; +typedef enum +{ + TMBOTTR_NONE = 0, + TMBOTTR_LEFT = 1, + TMBOTTR_RIGHT = 2, + TMBOTTR_UP = 3, + TMBOTTR_DOWN = 4, +} textmapbottrick_t; + typedef enum { TMLOOP_ALPHA = 0, diff --git a/src/r_defs.h b/src/r_defs.h index 8fae73aec..8d84fbd6e 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -32,6 +32,8 @@ #include "k_mapuser.h" +#include "k_bot.h" // botcontroller_t + #ifdef __cplusplus extern "C" { #endif @@ -331,6 +333,14 @@ struct pslope_t #endif }; +// Per-sector bot controller override +struct botcontroller_t +{ + UINT8 trick; + UINT32 flags; + angle_t forceAngle; +}; + typedef enum { // flipspecial - planes with effect @@ -552,6 +562,9 @@ struct sector_t // colormap structure extracolormap_t *spawn_extra_colormap; + // Ring Racers bots + botcontroller_t botController; + // Action specials INT16 action; INT32 args[NUM_SCRIPT_ARGS]; diff --git a/src/typedef.h b/src/typedef.h index f6979f09d..3885853ef 100644 --- a/src/typedef.h +++ b/src/typedef.h @@ -182,6 +182,7 @@ TYPEDEF (weakspot_t); // k_bot.h TYPEDEF (botprediction_t); +TYPEDEF (botcontroller_t); // k_brightmap.h TYPEDEF (brightmapStorage_t);