Merge pull request 'Bot Refactor' (#82) from botrefactor into blankart-dev
Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/82
This commit is contained in:
commit
2a1d6396ab
33 changed files with 1752 additions and 1335 deletions
|
|
@ -109,6 +109,7 @@ lua_maplib.c
|
|||
lua_taglib.c
|
||||
lua_polyobjlib.c
|
||||
lua_blockmaplib.c
|
||||
lua_botvarslib.c
|
||||
lua_hudlib.c
|
||||
lua_hudlib_drawlist.c
|
||||
lua_followerlib.c
|
||||
|
|
|
|||
|
|
@ -5638,8 +5638,6 @@ static void SV_Maketic(void)
|
|||
// Moved here so bots and packetloss indication doesn't break....
|
||||
G_MoveTiccmd(netcmds[maketic % BACKUPTICS], playercmds, MAXPLAYERS);
|
||||
|
||||
PS_ResetBotInfo();
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
packetloss[i][maketic%PACKETMEASUREWINDOW] = false;
|
||||
|
|
@ -5649,13 +5647,7 @@ static void SV_Maketic(void)
|
|||
|
||||
if (K_PlayerUsesBotMovement(&players[i]))
|
||||
{
|
||||
const precise_t t = I_GetPreciseTime();
|
||||
|
||||
K_BuildBotTiccmd(&players[i], &netcmds[maketic%BACKUPTICS][i]);
|
||||
|
||||
ps_bots[i].isBot = true;
|
||||
ps_bots[i].total = I_GetPreciseTime() - t;
|
||||
ps_botticcmd_time += ps_bots[i].total;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -679,10 +679,6 @@ consvar_t cv_schedule = CVAR_INIT ("schedule", "On", CV_NETVAR|CV_CALL, CV_OnOff
|
|||
|
||||
consvar_t cv_automate = CVAR_INIT ("automate", "On", CV_NETVAR, CV_OnOff, NULL);
|
||||
|
||||
consvar_t cv_test1 = CVAR_INIT ("test1", "200", CV_NETVAR|CV_FLOAT, CV_Signed, NULL);
|
||||
consvar_t cv_test2 = CVAR_INIT ("test2", "40", CV_NETVAR|CV_FLOAT, CV_Signed, NULL);
|
||||
consvar_t cv_test3 = CVAR_INIT ("test3", "18", CV_NETVAR|CV_FLOAT, CV_Signed, NULL);
|
||||
|
||||
char timedemo_name[256];
|
||||
boolean timedemo_csv;
|
||||
char timedemo_csv_id[256];
|
||||
|
|
@ -3521,7 +3517,7 @@ static void Got_Pause(UINT8 **cp, INT32 playernum)
|
|||
// Command for stuck characters in netgames, griefing, etc.
|
||||
static void HandleRespawnCommand(UINT8 localplayer)
|
||||
{
|
||||
UINT8 buf[4];
|
||||
UINT8 buf[1];
|
||||
UINT8 *cp = buf;
|
||||
|
||||
if (!(gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_VOTING))
|
||||
|
|
@ -3548,7 +3544,7 @@ static void HandleRespawnCommand(UINT8 localplayer)
|
|||
return;
|
||||
}
|
||||
|
||||
WRITEINT32(cp, g_localplayers[localplayer]);
|
||||
WRITEUINT8(cp, g_localplayers[localplayer]);
|
||||
SendNetXCmdForPlayer(localplayer, XD_RESPAWN, &buf, sizeof(buf));
|
||||
}
|
||||
|
||||
|
|
@ -3575,10 +3571,13 @@ static void Command_Respawn4(void)
|
|||
|
||||
static void Got_Respawn(UINT8 **cp, INT32 playernum)
|
||||
{
|
||||
INT32 respawnplayer = READINT32(*cp);
|
||||
INT32 respawnplayer = READUINT8(*cp);
|
||||
|
||||
// You can't respawn someone else. Nice try, there.
|
||||
if (respawnplayer != playernum || P_PlayerInPain(&players[respawnplayer]) || spbplace == players[respawnplayer].position) // srb2kart: "|| (!(gametyperules & GTR_CIRCUIT))"
|
||||
// Unless it's a bot. They can respawn whenever they feel like it, if the server says so.
|
||||
if (players[respawnplayer].bot
|
||||
? playernum != serverplayer
|
||||
: respawnplayer != playernum || P_PlayerInPain(&players[respawnplayer]) || spbplace == players[respawnplayer].position)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Illegal respawn command received from %s\n"), player_names[playernum]);
|
||||
if (server)
|
||||
|
|
@ -3593,7 +3592,7 @@ static void Got_Respawn(UINT8 **cp, INT32 playernum)
|
|||
return;
|
||||
|
||||
P_DamageMobj(players[respawnplayer].mo, NULL, NULL, 1, DMG_INSTAKILL);
|
||||
demo_extradata[playernum] |= DXD_RESPAWN;
|
||||
demo_extradata[respawnplayer] |= DXD_RESPAWN;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -237,8 +237,6 @@ extern consvar_t cv_director;
|
|||
|
||||
extern consvar_t cv_schedule;
|
||||
|
||||
extern consvar_t cv_test1, cv_test2, cv_test3;
|
||||
|
||||
extern char timedemo_name[256];
|
||||
extern boolean timedemo_csv;
|
||||
extern char timedemo_csv_id[256];
|
||||
|
|
|
|||
|
|
@ -419,17 +419,6 @@ typedef enum
|
|||
// for kickstartaccel
|
||||
#define ACCEL_KICKSTART (TICRATE)
|
||||
|
||||
// Minimum percentage for a (non-auto) drift to begin.
|
||||
#define BOTDRIFTPERCENT (10)
|
||||
|
||||
// Minimum turning percentage for an auto drift to begin.
|
||||
#define DRIFTSTARTPCT (45)
|
||||
|
||||
#define BOTDRIFTTICS (2*TICRATE/3)
|
||||
#define BOTDRIFTLOCKOUT (TICRATE/2)
|
||||
|
||||
#define MAXDRIFTSKILL (FRACUNIT/2)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BOT_STYLE_NORMAL,
|
||||
|
|
@ -439,15 +428,6 @@ typedef enum
|
|||
BOT_STYLE__MAX
|
||||
} botStyle_e;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DRIFTSTATE_AUTO,
|
||||
DRIFTSTATE_STARTING,
|
||||
DRIFTSTATE_ACTIVE,
|
||||
DRIFTSTATE_ENDING,
|
||||
NUMDRIFTSTATES
|
||||
} botdrift_t;
|
||||
|
||||
// player_t struct for all bot variables
|
||||
struct botvars_t
|
||||
{
|
||||
|
|
@ -459,20 +439,6 @@ struct botvars_t
|
|||
|
||||
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
|
||||
|
||||
SINT8 turnconfirm; // Confirm turn direction
|
||||
UINT32 respawnconfirm; // Confirm when respawn is needed.
|
||||
|
||||
// Drift-relevant data below:
|
||||
fixed_t driftskill; // The bot's "skill" at drifts.
|
||||
// Determines how soon a bot starts to drift.
|
||||
botdrift_t driftstate; // Drifting state
|
||||
SINT8 driftturn; // Drifting turn direction
|
||||
tic_t drifttime; // Time spent drifting
|
||||
tic_t driftlockout; // do not allow drifting for this many tics
|
||||
};
|
||||
|
||||
struct sonicloopcamvars_t
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@ typedef enum
|
|||
#define TICCMD_RECEIVED (0x01) /* Actual tic recieved from client */
|
||||
#define TICCMD_TYPING (0x02) /* chat window or console open */
|
||||
#define TICCMD_KEYSTROKE (0x04) /* chat character input */
|
||||
#define TICCMD_BOT (0x80) /* generated by bot, demos write bot variables */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma pack(1)
|
||||
|
|
@ -74,12 +73,6 @@ struct ticcmd_t
|
|||
UINT16 buttons;
|
||||
UINT8 latency; // Netgames: how many tics ago was this ticcmd generated from this player's end?
|
||||
UINT8 flags;
|
||||
struct
|
||||
{
|
||||
SINT8 turnconfirm;
|
||||
SINT8 itemconfirm;
|
||||
SINT8 respawnconfirm;
|
||||
} bot;
|
||||
} ATTRPACK;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
|
|
|||
|
|
@ -27,11 +27,11 @@
|
|||
#include "r_data.h" // patchalphastyle_t
|
||||
#include "k_boss.h" // spottype_t (for lua)
|
||||
#include "k_follower.h" // followermode_t (for lua)
|
||||
#include "k_bot.h" // bot constants (for lua)
|
||||
#include "g_input.h" // Game controls (for lua)
|
||||
#include "k_kart.h" // awardscaledrings_t
|
||||
#include "k_waypoint.h" // waypoint values (for lua)
|
||||
|
||||
|
||||
#include "deh_tables.h"
|
||||
#include "fastcmp.h"
|
||||
|
||||
|
|
@ -1553,6 +1553,60 @@ struct int_const_s const INT_CONST[] = {
|
|||
{"SNEAKERTYPE_ROCKETSNEAKER", SNEAKERTYPE_ROCKETSNEAKER},
|
||||
{"SNEAKERTYPE_WATERPANEL", SNEAKERTYPE_WATERPANEL},
|
||||
|
||||
// k_bot.h constants
|
||||
{"MAXBOTDIFFICULTY",MAXBOTDIFFICULTY},
|
||||
{"DIFFICULTBOT",DIFFICULTBOT},
|
||||
{"BOTTURNCONFIRM",BOTTURNCONFIRM},
|
||||
{"BOTSPINDASHCONFIRM",BOTSPINDASHCONFIRM},
|
||||
{"BOTRESPAWNCONFIRM",BOTRESPAWNCONFIRM},
|
||||
{"BOT_ITEM_DECISION_TIME",BOT_ITEM_DECISION_TIME},
|
||||
|
||||
{"BOTDRIFTPERCENT",BOTDRIFTPERCENT},
|
||||
{"DRIFTSTARTPCT",DRIFTSTARTPCT},
|
||||
{"BOTDRIFTTICS",BOTDRIFTTICS},
|
||||
{"BOTDRIFTLOCKOUT",BOTDRIFTLOCKOUT},
|
||||
{"MAXDRIFTSKILL",MAXDRIFTSKILL},
|
||||
|
||||
// botStyle_e
|
||||
{"BOT_STYLE_NORMAL",BOT_STYLE_NORMAL},
|
||||
{"BOT_STYLE_STAY",BOT_STYLE_STAY},
|
||||
{"BOT_STYLE__MAX",BOT_STYLE__MAX},
|
||||
|
||||
// botItemPriority_e
|
||||
/*
|
||||
{"BOT_ITEM_PR__FALLBACK",BOT_ITEM_PR__FALLBACK},
|
||||
{"BOT_ITEM_PR_NEUTRAL",BOT_ITEM_PR_NEUTRAL},
|
||||
{"BOT_ITEM_PR_FRONTRUNNER",BOT_ITEM_PR_FRONTRUNNER},
|
||||
{"BOT_ITEM_PR_SPEED",BOT_ITEM_PR_SPEED},
|
||||
{"BOT_ITEM_PR__OVERRIDES",BOT_ITEM_PR__OVERRIDES},
|
||||
{"BOT_ITEM_PR_RINGDEBT",BOT_ITEM_PR_RINGDEBT},
|
||||
{"BOT_ITEM_PR_POWER",BOT_ITEM_PR_POWER},
|
||||
{"BOT_ITEM_PR_SPB",BOT_ITEM_PR_SPB},
|
||||
{"BOT_ITEM_PR__MAX",BOT_ITEM_PR__MAX},
|
||||
*/
|
||||
|
||||
// textmapbotcontroller_t
|
||||
{"TMBOT_NORUBBERBAND",TMBOT_NORUBBERBAND},
|
||||
{"TMBOT_NOCONTROL",TMBOT_NOCONTROL},
|
||||
{"TMBOT_FORCEDIR",TMBOT_FORCEDIR},
|
||||
//{"TMBOT_FASTFALL",TMBOT_FASTFALL},
|
||||
|
||||
// textmapbottrick_t
|
||||
/*
|
||||
{"TMBOTTR_NONE",TMBOTTR_NONE},
|
||||
{"TMBOTTR_LEFT",TMBOTTR_LEFT},
|
||||
{"TMBOTTR_RIGHT",TMBOTTR_RIGHT},
|
||||
{"TMBOTTR_UP",TMBOTTR_UP},
|
||||
{"TMBOTTR_DOWN",TMBOTTR_DOWN},
|
||||
*/
|
||||
|
||||
// botdrift_e
|
||||
{"DRIFTSTATE_AUTO",DRIFTSTATE_AUTO},
|
||||
{"DRIFTSTATE_STARTING",DRIFTSTATE_STARTING},
|
||||
{"DRIFTSTATE_ACTIVE",DRIFTSTATE_ACTIVE},
|
||||
{"DRIFTSTATE_ENDING",DRIFTSTATE_ENDING},
|
||||
{"NUMDRIFTSTATES",NUMDRIFTSTATES},
|
||||
|
||||
// t_overlay_action_t
|
||||
{"TOV_UNDEFINED",TOV_UNDEFINED},
|
||||
{"TOV_STILL",TOV_STILL},
|
||||
|
|
|
|||
54
src/g_demo.c
54
src/g_demo.c
|
|
@ -146,13 +146,8 @@ demoghost *ghosts = NULL;
|
|||
#define ZT_AIMING 0x0040
|
||||
#define ZT_LATENCY 0x0080
|
||||
#define ZT_FLAGS 0x0100
|
||||
#define ZT_BOT 0x8000
|
||||
// Ziptics are UINT16 now, go nuts
|
||||
|
||||
#define ZT_BOT_TURN 0x0001
|
||||
#define ZT_BOT_ITEM 0x0002
|
||||
#define ZT_BOT_RESPAWN 0x0004
|
||||
|
||||
#define DEMOMARKER 0x80 // demobuf.end
|
||||
|
||||
UINT8 demo_extradata[MAXPLAYERS];
|
||||
|
|
@ -398,16 +393,12 @@ static UINT8 *G_ReadZipTic(ticcmd_t *cmd, UINT8 *dp, UINT16 version)
|
|||
if (ziptic & ZT_FLAGS)
|
||||
cmd->flags = READUINT8(dp);
|
||||
|
||||
if (ziptic & ZT_BOT)
|
||||
if (version < 0x000a && ziptic & 0x8000) // ZT_BOT
|
||||
{
|
||||
UINT16 botziptic = READUINT16(dp);
|
||||
|
||||
if (botziptic & ZT_BOT_TURN)
|
||||
cmd->bot.turnconfirm = READSINT8(dp);
|
||||
if (botziptic & ZT_BOT_ITEM)
|
||||
cmd->bot.itemconfirm = READSINT8(dp);
|
||||
if (botziptic & ZT_BOT_RESPAWN)
|
||||
cmd->bot.respawnconfirm = READSINT8(dp);
|
||||
if (botziptic & 1) READSINT8(dp);
|
||||
if (botziptic & 2) READSINT8(dp);
|
||||
if (botziptic & 4) READSINT8(dp);
|
||||
}
|
||||
return dp;
|
||||
}
|
||||
|
|
@ -1403,45 +1394,8 @@ void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum)
|
|||
ziptic |= ZT_FLAGS;
|
||||
}
|
||||
|
||||
if (cmd->flags & TICCMD_BOT)
|
||||
{
|
||||
ziptic |= ZT_BOT;
|
||||
}
|
||||
|
||||
WRITEUINT16(ziptic_p, ziptic);
|
||||
|
||||
if (ziptic & ZT_BOT)
|
||||
{
|
||||
UINT16 botziptic = 0;
|
||||
UINT8 *botziptic_p;
|
||||
|
||||
botziptic_p = demobuf.p; // the ziptic, written at the end of this function
|
||||
demobuf.p += 2;
|
||||
|
||||
if (cmd->bot.turnconfirm != oldcmd[playernum].bot.turnconfirm)
|
||||
{
|
||||
WRITESINT8(demobuf.p, cmd->bot.turnconfirm);
|
||||
oldcmd[playernum].bot.turnconfirm = cmd->bot.turnconfirm;
|
||||
botziptic |= ZT_BOT_TURN;
|
||||
}
|
||||
|
||||
if (cmd->bot.itemconfirm != oldcmd[playernum].bot.itemconfirm)
|
||||
{
|
||||
WRITESINT8(demobuf.p, cmd->bot.itemconfirm);
|
||||
oldcmd[playernum].bot.itemconfirm = cmd->bot.itemconfirm;
|
||||
botziptic |= ZT_BOT_ITEM;
|
||||
}
|
||||
|
||||
if (cmd->bot.respawnconfirm != oldcmd[playernum].bot.respawnconfirm)
|
||||
{
|
||||
WRITESINT8(demobuf.p, cmd->bot.respawnconfirm);
|
||||
oldcmd[playernum].bot.respawnconfirm = cmd->bot.respawnconfirm;
|
||||
botziptic |= ZT_BOT_RESPAWN;
|
||||
}
|
||||
|
||||
WRITEUINT16(botziptic_p, botziptic);
|
||||
}
|
||||
|
||||
// attention here for the ticcmd size!
|
||||
// latest demos with mouse aiming byte in ticcmd
|
||||
if (!(demoflags & DF_GHOST) && ziptic_p > demobuf.end - 9)
|
||||
|
|
|
|||
15
src/g_game.c
15
src/g_game.c
|
|
@ -1363,13 +1363,6 @@ ticcmd_t *G_MoveTiccmd(ticcmd_t* dest, const ticcmd_t* src, const size_t n)
|
|||
dest[i].buttons = (UINT16)SHORT(src[i].buttons);
|
||||
dest[i].latency = src[i].latency;
|
||||
dest[i].flags = src[i].flags;
|
||||
|
||||
if (dest[i].flags & TICCMD_BOT)
|
||||
{
|
||||
dest[i].bot.itemconfirm = src[i].bot.itemconfirm;
|
||||
dest[i].bot.turnconfirm = src[i].bot.turnconfirm;
|
||||
dest[i].bot.respawnconfirm = src[i].bot.respawnconfirm;
|
||||
}
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
|
@ -2417,6 +2410,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
boolean spectator;
|
||||
boolean bot;
|
||||
UINT8 botdifficulty;
|
||||
botStyle_e style;
|
||||
|
||||
INT16 rings;
|
||||
angle_t playerangleturn;
|
||||
|
|
@ -2476,6 +2470,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
followitem = players[player].followitem;
|
||||
|
||||
bot = players[player].bot;
|
||||
style = players[player].botvars.style;
|
||||
botdifficulty = players[player].botvars.difficulty;
|
||||
|
||||
botdiffincrease = players[player].botvars.diffincrease;
|
||||
|
|
@ -2638,6 +2633,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
p->totalring = totalring;
|
||||
|
||||
p->bot = bot;
|
||||
p->botvars.style = style;
|
||||
p->botvars.difficulty = botdifficulty;
|
||||
p->rings = rings;
|
||||
p->botvars.diffincrease = botdiffincrease;
|
||||
|
|
@ -2668,9 +2664,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
|
||||
p->botvars.rubberband = FRACUNIT;
|
||||
p->botvars.controller = UINT16_MAX;
|
||||
p->botvars.driftskill =
|
||||
FixedMul(MAXDRIFTSKILL, K_BotDetermineDriftSkill(p));
|
||||
p->botvars.driftstate = DRIFTSTATE_AUTO;
|
||||
|
||||
K_BotReborn(p);
|
||||
|
||||
if (follower)
|
||||
P_RemoveMobj(follower);
|
||||
|
|
|
|||
671
src/k_bot.cpp
671
src/k_bot.cpp
|
|
@ -42,10 +42,46 @@
|
|||
#endif
|
||||
#include "i_net.h" // doomcom
|
||||
#include "blan/b_soc.h"
|
||||
#include "v_video.h" // for debugging
|
||||
|
||||
consvar_t cv_forcebots = CVAR_INIT ("kartforcebots", "Off", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
|
||||
consvar_t cv_botcontrol = CVAR_INIT ("kartbotcontrol", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
|
||||
|
||||
botdata_t botdata[MAXPLAYERS];
|
||||
|
||||
void K_DrawBotDebugger(const player_t *player)
|
||||
{
|
||||
INT32 vflags = V_6WIDTHSPACE|V_ALLOWLOWERCASE|V_30TRANS;
|
||||
botdata_t *bd = &botdata[player - players];
|
||||
|
||||
static const char *driftstates[] = {
|
||||
"auto", // DRIFTSTATE_AUTO
|
||||
"starting", // DRIFTSTATE_STARTING
|
||||
"active", // DRIFTSTATE_ACTIVE
|
||||
"ending", // DRIFTSTATE_ENDING
|
||||
};
|
||||
|
||||
if (!cv_kartdebugbot.value || !player->bot)
|
||||
return;
|
||||
|
||||
INT32 x1 = 26, x2 = 99, y = 92;
|
||||
|
||||
V_DrawThinString(x1, y+0, vflags, va("predict.x: %d", bd->predict.x/FRACUNIT));
|
||||
V_DrawThinString(x2, y+0, vflags, va("predict.y: %d", bd->predict.y/FRACUNIT));
|
||||
V_DrawThinString(x1, y+8, vflags, va("predict.radius: %d", bd->predict.radius/FRACUNIT));
|
||||
V_DrawThinString(x2, y+8, vflags, va("predict.baseradius: %d", bd->predict.baseRadius/FRACUNIT));
|
||||
|
||||
V_DrawThinString(x1, y+16, vflags, va("itemconfirm: %d", bd->itemconfirm));
|
||||
V_DrawThinString(x2, y+16, vflags, va("itemdelay: %d", bd->itemdelay));
|
||||
V_DrawThinString(x1, y+24, vflags, va("turnconfirm: %d", bd->turnconfirm));
|
||||
V_DrawThinString(x2, y+24, vflags, va("respawnconfirm: %d", bd->respawnconfirm));
|
||||
|
||||
V_DrawThinString(x1, y+32, vflags, va("driftstate: %s", driftstates[bd->driftstate]));
|
||||
V_DrawThinString(x2, y+32, vflags|(bd->driftlockout ? V_ORANGEMAP : 0), va("driftlockout: %d", bd->driftlockout));
|
||||
V_DrawThinString(x1, y+40, vflags, va("driftturn: %d", bd->driftturn));
|
||||
V_DrawThinString(x2, y+40, vflags, va("drifttime: %d", bd->drifttime));
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_SetNameForBot(UINT8 playerNum, const char *realname)
|
||||
|
||||
|
|
@ -132,6 +168,8 @@ void K_SetBot(UINT8 newplayernum, UINT16 skinnum, UINT8 difficulty, botStyle_e s
|
|||
|
||||
SetPlayerSkinByNum(newplayernum, skinnum);
|
||||
|
||||
LUA_HookPlayer(&players[newplayernum], HOOK(BotJoin));
|
||||
|
||||
for (UINT8 i = 0; i < PWRLV_NUMTYPES; i++)
|
||||
{
|
||||
clientpowerlevels[newplayernum][i] = 0;
|
||||
|
|
@ -359,6 +397,17 @@ void K_UpdateMatchRaceBots(void)
|
|||
--------------------------------------------------*/
|
||||
boolean K_PlayerUsesBotMovement(const player_t *player)
|
||||
{
|
||||
// Lua can't override the podium sequence result, but it can
|
||||
// override the following results:
|
||||
{
|
||||
UINT8 shouldOverride = LUA_HookPlayerForceResults(const_cast<player_t*>(player),
|
||||
HOOK(PlayerUsesBotMovement));
|
||||
if (shouldOverride == 1)
|
||||
return true;
|
||||
if (shouldOverride == 2)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (player->bot)
|
||||
return true;
|
||||
|
||||
|
|
@ -370,7 +419,7 @@ boolean K_PlayerUsesBotMovement(const player_t *player)
|
|||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
boolean K_BotCanTakeCut(player_t *player)
|
||||
boolean K_BotCanTakeCut(const player_t *player)
|
||||
{
|
||||
if (
|
||||
(K_TripwirePassConditions(player) != TRIPWIRE_NONE || K_ApplyOffroad(player) == false)
|
||||
|
|
@ -453,11 +502,11 @@ static fixed_t K_BotSpeedScaled(const player_t *player, fixed_t speed)
|
|||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
const botcontroller_t *K_GetBotController(const mobj_t *mobj)
|
||||
botcontroller_t *K_GetBotController(const mobj_t *mobj)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
const botcontroller_t *K_GetBotController(mobj_t *mobj)
|
||||
botcontroller_t *K_GetBotController(const mobj_t *mobj)
|
||||
{
|
||||
botcontroller_t *ret = nullptr;
|
||||
|
||||
|
|
@ -838,18 +887,8 @@ static fixed_t K_ScaleWPDistWithSlope(fixed_t disttonext, angle_t angletonext, c
|
|||
return disttonext;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static botprediction_t *K_CreateBotPrediction(const player_t *player)
|
||||
|
||||
Calculates a point further along the track to attempt to drive towards.
|
||||
|
||||
Input Arguments:-
|
||||
player - Player to compare.
|
||||
|
||||
Return:-
|
||||
Bot prediction struct.
|
||||
--------------------------------------------------*/
|
||||
static botprediction_t *K_CreateBotPrediction(player_t *player)
|
||||
// Calculates a point further along the track to attempt to drive towards.
|
||||
static boolean K_CreateBotPrediction(botdata_t *bd, const player_t *player)
|
||||
{
|
||||
ZoneScoped;
|
||||
|
||||
|
|
@ -884,17 +923,14 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
|
|||
boolean pathfindsuccess = false;
|
||||
path_t pathtofinish = {0};
|
||||
|
||||
botprediction_t *predict = nullptr;
|
||||
size_t i;
|
||||
|
||||
if (wp == nullptr || P_MobjWasRemoved(wp->mobj) == true)
|
||||
{
|
||||
// Can't do any of this if we don't have a waypoint.
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
predict = static_cast<botprediction_t *>(Z_Calloc(sizeof(botprediction_t), PU_LEVEL, nullptr));
|
||||
|
||||
// Init defaults in case of pathfind failure
|
||||
angletonext = R_PointToAngle2(prevwpmobj->x, prevwpmobj->y, wp->mobj->x, wp->mobj->y);
|
||||
disttonext = P_AproxDistance(prevwpmobj->x - wp->mobj->x, prevwpmobj->y - wp->mobj->y);
|
||||
|
|
@ -950,22 +986,22 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
|
|||
|
||||
// Set our predicted point's coordinates,
|
||||
// and use the smallest radius of all of the waypoints in the chain!
|
||||
predict->x = wp->mobj->x;
|
||||
predict->y = wp->mobj->y;
|
||||
bd->predict.x = wp->mobj->x;
|
||||
bd->predict.y = wp->mobj->y;
|
||||
|
||||
predict->baseRadius = radius;
|
||||
predict->radius = FixedMul(radiusScaled, radReduce);
|
||||
bd->predict.baseRadius = radius;
|
||||
bd->predict.radius = FixedMul(radiusScaled, radReduce);
|
||||
|
||||
// Set the prediction coordinates between the 2 waypoints if there's still distance left.
|
||||
if (distanceleft > 0)
|
||||
{
|
||||
// Scaled with the leftover anglemul!
|
||||
predict->x += P_ReturnThrustX(nullptr, angletonext, std::min<fixed_t>(disttonext, distanceleft) * FRACUNIT);
|
||||
predict->y += P_ReturnThrustY(nullptr, angletonext, std::min<fixed_t>(disttonext, distanceleft) * FRACUNIT);
|
||||
bd->predict.x += P_ReturnThrustX(nullptr, angletonext, std::min<fixed_t>(disttonext, distanceleft) * FRACUNIT);
|
||||
bd->predict.y += P_ReturnThrustY(nullptr, angletonext, std::min<fixed_t>(disttonext, distanceleft) * FRACUNIT);
|
||||
}
|
||||
|
||||
ps_bots[player - players].prediction += I_GetPreciseTime() - time;
|
||||
return predict;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
|
|
@ -980,19 +1016,18 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
|
|||
Return:-
|
||||
None
|
||||
--------------------------------------------------*/
|
||||
static void K_DrawPredictionDebug(botprediction_t *predict, const player_t *player)
|
||||
static void K_DrawPredictionDebug(botdata_t *bd, const player_t *player)
|
||||
{
|
||||
mobj_t *debugMobj = nullptr;
|
||||
angle_t sideAngle = ANGLE_MAX;
|
||||
UINT8 i = UINT8_MAX;
|
||||
|
||||
I_Assert(predict != nullptr);
|
||||
I_Assert(player != nullptr);
|
||||
I_Assert(player->mo != nullptr && P_MobjWasRemoved(player->mo) == false);
|
||||
|
||||
sideAngle = player->mo->angle + ANGLE_90;
|
||||
|
||||
debugMobj = P_SpawnMobj(predict->x, predict->y, player->mo->z, MT_SPARK);
|
||||
debugMobj = P_SpawnMobj(bd->predict.x, bd->predict.y, player->mo->z, MT_SPARK);
|
||||
P_SetMobjState(debugMobj, S_THOK);
|
||||
|
||||
debugMobj->frame &= ~FF_TRANSMASK;
|
||||
|
|
@ -1001,22 +1036,22 @@ static void K_DrawPredictionDebug(botprediction_t *predict, const player_t *play
|
|||
debugMobj->color = SKINCOLOR_ORANGE;
|
||||
P_SetScale(debugMobj, debugMobj->destscale * 2);
|
||||
|
||||
debugMobj->tics = 2;
|
||||
debugMobj->tics = 1;
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
mobj_t *radiusMobj = nullptr;
|
||||
fixed_t radiusX = predict->x, radiusY = predict->y;
|
||||
fixed_t radiusX = bd->predict.x, radiusY = bd->predict.y;
|
||||
|
||||
if (i & 1)
|
||||
{
|
||||
radiusX -= FixedMul(predict->radius, FINECOSINE(sideAngle >> ANGLETOFINESHIFT));
|
||||
radiusY -= FixedMul(predict->radius, FINESINE(sideAngle >> ANGLETOFINESHIFT));
|
||||
radiusX -= FixedMul(bd->predict.radius, FINECOSINE(sideAngle >> ANGLETOFINESHIFT));
|
||||
radiusY -= FixedMul(bd->predict.radius, FINESINE(sideAngle >> ANGLETOFINESHIFT));
|
||||
}
|
||||
else
|
||||
{
|
||||
radiusX += FixedMul(predict->radius, FINECOSINE(sideAngle >> ANGLETOFINESHIFT));
|
||||
radiusY += FixedMul(predict->radius, FINESINE(sideAngle >> ANGLETOFINESHIFT));
|
||||
radiusX += FixedMul(bd->predict.radius, FINECOSINE(sideAngle >> ANGLETOFINESHIFT));
|
||||
radiusY += FixedMul(bd->predict.radius, FINESINE(sideAngle >> ANGLETOFINESHIFT));
|
||||
}
|
||||
|
||||
radiusMobj = P_SpawnMobj(radiusX, radiusY, player->mo->z, MT_SPARK);
|
||||
|
|
@ -1028,24 +1063,15 @@ static void K_DrawPredictionDebug(botprediction_t *predict, const player_t *play
|
|||
radiusMobj->color = SKINCOLOR_YELLOW;
|
||||
P_SetScale(debugMobj, debugMobj->destscale / 2);
|
||||
|
||||
radiusMobj->tics = 2;
|
||||
radiusMobj->tics = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
fixed_t K_BotDetermineDriftSkill(player_t *player)
|
||||
|
||||
Calculates drift skill for a player based on stats.
|
||||
|
||||
Input Arguments:-
|
||||
player - Player to get drift skill for.
|
||||
|
||||
Return:-
|
||||
Calculated drift skill.
|
||||
--------------------------------------------------*/
|
||||
fixed_t K_BotDetermineDriftSkill(player_t *player)
|
||||
// Calculates drift skill for a player based on ~~stats~~ difficulty.
|
||||
static fixed_t K_BotDetermineDriftSkill(const player_t *player)
|
||||
{
|
||||
return ((FRACUNIT * (player->kartspeed + player->kartweight)) / 18);
|
||||
return FRACUNIT/8 + (FRACUNIT * player->botvars.difficulty) / DIFFICULTBOT;
|
||||
//return ((FRACUNIT * (player->kartspeed + player->kartweight)) / 18);
|
||||
}
|
||||
|
||||
static void K_WaypointGetDirectionVector(waypoint_t *wp1, waypoint_t *wp2, vector3_t *a_o)
|
||||
|
|
@ -1064,37 +1090,27 @@ static void K_WaypointGetDirectionVector(waypoint_t *wp1, waypoint_t *wp2, vecto
|
|||
FV3_Normalize(a_o);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_BotSetDriftState(player_t *player, botdrift_t newstate, tic_t lockout)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
void K_BotSetDriftState(player_t *player, botdrift_t newstate, tic_t lockout)
|
||||
// Changes a bot's drift state.
|
||||
// Resets the drift timer if the old and new state are different.
|
||||
// If lockout is non-zero, apply drift lockout for this many tics.
|
||||
void K_BotSetDriftState(const player_t *player, botdrift_e newstate, tic_t lockout)
|
||||
{
|
||||
if (newstate != player->botvars.driftstate)
|
||||
botdata_t *bd = &botdata[player - players];
|
||||
|
||||
if (newstate != bd->driftstate)
|
||||
{
|
||||
player->botvars.driftstate = newstate;
|
||||
player->botvars.drifttime = 0;
|
||||
bd->driftstate = newstate;
|
||||
bd->drifttime = 0;
|
||||
}
|
||||
|
||||
if (lockout > player->botvars.driftlockout)
|
||||
player->botvars.driftlockout = lockout;
|
||||
if (lockout > bd->driftlockout)
|
||||
bd->driftlockout = lockout;
|
||||
}
|
||||
|
||||
#define MINBOTDRIFT (KART_FULLTURN * 2) / 3 // 0.66
|
||||
|
||||
/*--------------------------------------------------
|
||||
static INT32 K_BotStartDrift(player_t* player)
|
||||
|
||||
Begins and ends "forced" drifts on a per-waypoint basis.
|
||||
|
||||
Input Arguments:-
|
||||
player - Player to begin the drift for.
|
||||
|
||||
Return:-
|
||||
Override value for turn amount.
|
||||
--------------------------------------------------*/
|
||||
static void K_BotStartDrift(player_t* player)
|
||||
// Begins and ends "forced" drifts on a per-waypoint basis.
|
||||
static void K_BotStartDrift(botdata_t *bd, const player_t* player)
|
||||
{
|
||||
// Handle DRIFTING towards waypoints!
|
||||
boolean shouldDrift;
|
||||
|
|
@ -1116,17 +1132,16 @@ static void K_BotStartDrift(player_t* player)
|
|||
return;
|
||||
}
|
||||
|
||||
if (player->botvars.driftlockout)
|
||||
if (bd->driftlockout)
|
||||
{
|
||||
// things are not working out in our favor
|
||||
player->botvars.driftlockout--;
|
||||
bd->driftlockout--;
|
||||
return;
|
||||
}
|
||||
|
||||
// check for waypoints ahead of us with drift settings, based on our current speed
|
||||
path_t path = {0};
|
||||
INT32 maxdist = FixedInt(cv_test1.value) + gamespeed*50;
|
||||
maxdist = FixedMul(maxdist, speedfactor * (player->botvars.driftstate == DRIFTSTATE_ACTIVE ? 1 : 2));
|
||||
INT32 maxdist = FixedMul(bd->driftmaxdist, speedfactor * (bd->driftstate == DRIFTSTATE_ACTIVE ? 1 : 2));
|
||||
|
||||
if (maxdist >= 0 && K_PathfindThruCircuit(player->currentwaypoint, maxdist, &path, false, false))
|
||||
{
|
||||
|
|
@ -1156,17 +1171,17 @@ static void K_BotStartDrift(player_t* player)
|
|||
|
||||
if (driftsetting == DRIFT_END)
|
||||
{
|
||||
if (player->botvars.driftstate != DRIFTSTATE_AUTO)
|
||||
if (bd->driftstate != DRIFTSTATE_AUTO)
|
||||
K_BotSetDriftState(player, DRIFTSTATE_ENDING, 0);
|
||||
}
|
||||
else if (driftsetting > DRIFT_NONE && driftsetting < DRIFT_END
|
||||
&& player->botvars.driftstate == DRIFTSTATE_AUTO)
|
||||
&& bd->driftstate == DRIFTSTATE_AUTO)
|
||||
{
|
||||
// Randomly decide to drift based on our skill at drifting,
|
||||
// and how fast we're moving.
|
||||
fixed_t driftpotential = P_RandomKey(MAXDRIFTSKILL);
|
||||
fixed_t driftpotential = M_RandomKey(MAXDRIFTSKILL);
|
||||
|
||||
if ((driftpotential <= player->botvars.driftskill) &&
|
||||
if ((driftpotential <= bd->driftskill) &&
|
||||
(botDriftSpeed <= player->speed))
|
||||
{
|
||||
shouldDrift = true;
|
||||
|
|
@ -1195,26 +1210,14 @@ static void K_BotStartDrift(player_t* player)
|
|||
break;
|
||||
}
|
||||
|
||||
player->botvars.driftturn = driftturn;
|
||||
bd->driftturn = driftturn;
|
||||
K_BotSetDriftState(player, DRIFTSTATE_STARTING, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static INT32 K_HandleBotTrack(const player_t *player, ticcmd_t *cmd, botprediction_t *predict)
|
||||
|
||||
Determines inputs for standard track driving.
|
||||
|
||||
Input Arguments:-
|
||||
player - Player to generate the ticcmd for.
|
||||
cmd - The player's ticcmd to modify.
|
||||
predict - Pointer to the bot's prediction.
|
||||
|
||||
Return:-
|
||||
New value for turn amount.
|
||||
--------------------------------------------------*/
|
||||
static INT32 K_HandleBotTrack(player_t *player, ticcmd_t *cmd, botprediction_t *predict, angle_t destangle)
|
||||
// Determines inputs for standard track driving.
|
||||
static INT32 K_HandleBotTrack(botdata_t *bd, const player_t *player, angle_t destangle)
|
||||
{
|
||||
ZoneScoped;
|
||||
|
||||
|
|
@ -1225,15 +1228,13 @@ static INT32 K_HandleBotTrack(player_t *player, ticcmd_t *cmd, botprediction_t *
|
|||
INT32 anglediff, anglediff2;
|
||||
fixed_t speedfactor = FixedDiv(player->speed, K_GetKartSpeed(player, false, false));
|
||||
|
||||
I_Assert(predict != nullptr);
|
||||
|
||||
moveangle = player->mo->angle;
|
||||
anglediff = AngleDeltaSigned(moveangle, destangle);
|
||||
|
||||
// line up for an incoming drift
|
||||
if (player->botvars.driftstate == DRIFTSTATE_STARTING)
|
||||
if (bd->driftstate == DRIFTSTATE_STARTING)
|
||||
{
|
||||
anglediff += FixedMul(ANG10-ANG2, speedfactor) * player->botvars.driftturn;
|
||||
anglediff += FixedMul(ANG10-ANG2, speedfactor) * bd->driftturn;
|
||||
}
|
||||
|
||||
if (anglediff < 0)
|
||||
|
|
@ -1252,18 +1253,18 @@ static INT32 K_HandleBotTrack(player_t *player, ticcmd_t *cmd, botprediction_t *
|
|||
if (anglediff > ANGLE_67h)
|
||||
{
|
||||
// Wrong way!
|
||||
cmd->forwardmove = -MAXPLMOVE;
|
||||
cmd->buttons |= BT_BRAKE;
|
||||
bd->acceldown = false;
|
||||
bd->brakedown = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
const fixed_t playerwidth = (player->mo->radius * 2);
|
||||
fixed_t realrad = predict->radius*3/4; // Remove a "safe" distance away from the edges of the road
|
||||
fixed_t realrad = bd->predict.radius*3/4; // Remove a "safe" distance away from the edges of the road
|
||||
fixed_t rad = realrad;
|
||||
fixed_t dirdist = K_DistanceOfLineFromPoint(
|
||||
player->mo->x, player->mo->y,
|
||||
player->mo->x + FINECOSINE(moveangle >> ANGLETOFINESHIFT), player->mo->y + FINESINE(moveangle >> ANGLETOFINESHIFT),
|
||||
predict->x, predict->y
|
||||
bd->predict.x, bd->predict.y
|
||||
);
|
||||
|
||||
if (realrad < playerwidth)
|
||||
|
|
@ -1296,11 +1297,11 @@ static INT32 K_HandleBotTrack(player_t *player, ticcmd_t *cmd, botprediction_t *
|
|||
}
|
||||
|
||||
// Full speed ahead!
|
||||
cmd->buttons |= BT_ACCELERATE;
|
||||
cmd->forwardmove = MAXPLMOVE;
|
||||
bd->acceldown = true;
|
||||
bd->brakedown = false;
|
||||
|
||||
if (dirdist <= rad
|
||||
&& player->botvars.driftstate != DRIFTSTATE_STARTING) // steer towards waypoints when starting drift
|
||||
&& bd->driftstate != DRIFTSTATE_STARTING) // steer towards waypoints when starting drift
|
||||
{
|
||||
// Going the right way, don't turn at all.
|
||||
turnamt = 0;
|
||||
|
|
@ -1310,11 +1311,11 @@ static INT32 K_HandleBotTrack(player_t *player, ticcmd_t *cmd, botprediction_t *
|
|||
//INT32 mindriftamt = FixedMul(MINBOTDRIFT * (cv_kartspeed.value + 1), 2 * FRACUNIT);
|
||||
|
||||
// Start or continue a drift.
|
||||
if (player->botvars.driftstate == DRIFTSTATE_ACTIVE || player->botvars.driftstate == DRIFTSTATE_ENDING)
|
||||
if (bd->driftstate == DRIFTSTATE_ACTIVE || bd->driftstate == DRIFTSTATE_ENDING)
|
||||
{
|
||||
cmd->buttons |= BT_DRIFT;
|
||||
bd->driftdown = true;
|
||||
|
||||
fixed_t angofs = K_GetKartSpeedFromStat(5 - (player->kartspeed - 5), false) * -player->botvars.driftturn;
|
||||
fixed_t angofs = K_GetKartSpeedFromStat(5 - (player->kartspeed - 5), false) * -bd->driftturn;
|
||||
|
||||
// adjust for speed
|
||||
angofs = FixedMul(angofs, speedfactor - (2-gamespeed)*FRACUNIT/4);
|
||||
|
|
@ -1322,20 +1323,20 @@ static INT32 K_HandleBotTrack(player_t *player, ticcmd_t *cmd, botprediction_t *
|
|||
fixed_t driftpower = angofs - FixedDiv(anglediff2, ANG1);
|
||||
|
||||
// arbitrary divider on the final driftpower
|
||||
driftpower /= FixedInt(cv_test2.value);
|
||||
driftpower /= bd->driftpowerdiv;
|
||||
|
||||
// brakedrift if we're steering too hard
|
||||
if (abs(driftpower) >= FRACUNIT)
|
||||
cmd->buttons |= BT_BRAKE;
|
||||
bd->brakedown = true;
|
||||
|
||||
// get the raw turn value and "invert" it (higher weight needs harder steering!)
|
||||
INT16 turnvalue = abs(K_GetKartTurnValue(player, KART_FULLTURN * (player->botvars.driftturn < 0 ? 1 : -1)));
|
||||
INT16 turnvalue = abs(K_GetKartTurnValue(player, KART_FULLTURN * (bd->driftturn < 0 ? 1 : -1)));
|
||||
turnvalue = 541 - (turnvalue - 541); // weight 5 = 541
|
||||
|
||||
turnamt = std::clamp(FixedMul(driftpower, turnvalue), -KART_FULLTURN, KART_FULLTURN);
|
||||
}
|
||||
/*
|
||||
else if ((turnamt) && (player->botvars.driftstate == DRIFTSTATE_AUTO) &&
|
||||
else if ((turnamt) && (bd->driftstate == DRIFTSTATE_AUTO) &&
|
||||
(turnpower > FixedPercentage(DRIFTSTARTPCT)))
|
||||
{
|
||||
// TODO: Figure out a drift prediction system.
|
||||
|
|
@ -1348,6 +1349,38 @@ static INT32 K_HandleBotTrack(player_t *player, ticcmd_t *cmd, botprediction_t *
|
|||
|
||||
#undef MINBOTDRIFT
|
||||
|
||||
static void K_IncrementBotRespawn(const player_t *player, UINT8 *respawn, const UINT8 respawnmax)
|
||||
{
|
||||
const fixed_t requireDist = (12*player->mo->scale) / FRACUNIT;
|
||||
INT32 progress = player->distancetofinishprev - player->distancetofinish;
|
||||
boolean exceptions = (
|
||||
(leveltime < starttime)
|
||||
|| player->flashing != 0
|
||||
|| player->spinouttimer != 0
|
||||
|| player->airtime > 3*TICRATE/2
|
||||
|| (player->justbumped > 0 && player->justbumped < bumptime-1)
|
||||
);
|
||||
|
||||
if (!exceptions && (progress < requireDist))
|
||||
{
|
||||
if (*respawn < respawnmax)
|
||||
{
|
||||
// Making no progress, start counting against you.
|
||||
*respawn = *respawn + 1;
|
||||
if (progress < -requireDist && *respawn < respawnmax)
|
||||
{
|
||||
// Making NEGATIVE progress? Start counting even harder.
|
||||
*respawn = *respawn + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (*respawn > 0)
|
||||
{
|
||||
// Playing normally.
|
||||
*respawn = *respawn - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static INT32 K_HandleBotReverse(const player_t *player, ticcmd_t *cmd, botprediction_t *predict)
|
||||
|
||||
|
|
@ -1361,7 +1394,7 @@ static INT32 K_HandleBotTrack(player_t *player, ticcmd_t *cmd, botprediction_t *
|
|||
Return:-
|
||||
New value for turn amount.
|
||||
--------------------------------------------------*/
|
||||
/*static INT32 K_HandleBotReverse(player_t *player, ticcmd_t *cmd, botprediction_t *predict, angle_t destangle)
|
||||
/*static INT32 K_HandleBotReverse(const player_t *player, ticcmd_t *cmd, botprediction_t *predict, angle_t destangle)
|
||||
{
|
||||
ZoneScoped;
|
||||
|
||||
|
|
@ -1493,26 +1526,24 @@ static INT32 K_HandleBotTrack(player_t *player, ticcmd_t *cmd, botprediction_t *
|
|||
return turnamt;
|
||||
}*/
|
||||
|
||||
/*--------------------------------------------------
|
||||
static void K_BuildBotTiccmdNormal(const player_t *player, ticcmd_t *cmd)
|
||||
|
||||
Build ticcmd for bots with a style of BOT_STYLE_NORMAL
|
||||
--------------------------------------------------*/
|
||||
static void K_BuildBotTiccmdNormal(player_t *player, ticcmd_t *cmd)
|
||||
// updates server-sided bot logic
|
||||
void K_BotTicker(const player_t *player)
|
||||
{
|
||||
precise_t t = 0;
|
||||
|
||||
botprediction_t *predict = nullptr;
|
||||
auto predict_finally = srb2::finally([&predict]() { Z_Free(predict); });
|
||||
|
||||
angle_t destangle = 0;
|
||||
INT32 turnamt = 0;
|
||||
|
||||
botdata_t *bd = &botdata[player - players];
|
||||
bd->itemwasdown = bd->itemdown;
|
||||
bd->acceldown = bd->brakedown = bd->driftdown = bd->itemdown = false;
|
||||
bd->dolookback = false;
|
||||
bd->itemthrow = 0;
|
||||
|
||||
if (!(gametyperules & GTR_BOTS) // No bot behaviors
|
||||
|| K_GetNumWaypoints() == 0 // No waypoints
|
||||
|| leveltime <= introtime // During intro camera
|
||||
|| player->playerstate == PST_DEAD // Dead, respawning.
|
||||
|| player->mo->scale <= 1) // Post-finish "death" animation
|
||||
|| player->mo->scale <= 1 // Post-finish "death" animation
|
||||
|| player->spectator) // spectating
|
||||
{
|
||||
// No need to do anything else.
|
||||
return;
|
||||
|
|
@ -1539,53 +1570,58 @@ static void K_BuildBotTiccmdNormal(player_t *player, ticcmd_t *cmd)
|
|||
|
||||
if (player->exiting)
|
||||
{
|
||||
|
||||
//Bot finish
|
||||
// TODO: Make bots spin around like a player would based on random chance
|
||||
return;
|
||||
}
|
||||
|
||||
if (player->botvars.respawnconfirm >= BOTRESPAWNCONFIRM)
|
||||
// Is a bot not making any progress? Kill it and respawn at next waypoint.
|
||||
K_IncrementBotRespawn(player, &bd->respawnconfirm, BOTRESPAWNCONFIRM);
|
||||
|
||||
if (bd->respawnconfirm > BOTRESPAWNCONFIRM - TICRATE)
|
||||
{
|
||||
// We want to respawn. Simply hold brake and stop here!
|
||||
cmd->buttons &= ~BT_ACCELERATE|BT_DRIFT|BT_ATTACK;
|
||||
bd->acceldown = false;
|
||||
K_BotSetDriftState(player, DRIFTSTATE_AUTO, TICRATE);
|
||||
if (player->speed > 0)
|
||||
{
|
||||
cmd->buttons |= (BT_BRAKE);
|
||||
cmd->bot.respawnconfirm++;
|
||||
}
|
||||
bd->brakedown = true;
|
||||
|
||||
if ((player->speed < 10*FRACUNIT))
|
||||
if (bd->respawnconfirm >= BOTRESPAWNCONFIRM || player->speed < 10*FRACUNIT)
|
||||
{
|
||||
cmd->bot.respawnconfirm = TICRATE;
|
||||
// WHAT ARE YOU DOING??? RACE ALREADY!
|
||||
// ...
|
||||
// FINE, I'LL SEND A RESPAWN COMMAND ON YOUR BEHALF!
|
||||
char buf[1], *cp = buf;
|
||||
WRITEUINT8(cp, player - players);
|
||||
SendNetXCmdForPlayer(consoleplayer, XD_RESPAWN, buf, sizeof(buf));
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd->bot.respawnconfirm = 0;
|
||||
}
|
||||
|
||||
destangle = player->mo->angle;
|
||||
|
||||
// it's time to start predicting
|
||||
memset(&bd->predict, 0, sizeof(bd->predict));
|
||||
|
||||
boolean forcedDir = false;
|
||||
if (botController != nullptr && (botController->flags & TMBOT_FORCEDIR) == TMBOT_FORCEDIR)
|
||||
{
|
||||
const fixed_t dist = DEFAULT_WAYPOINT_RADIUS * player->mo->scale;
|
||||
|
||||
// Overwritten prediction
|
||||
predict = static_cast<botprediction_t *>(Z_Calloc(sizeof(botprediction_t), PU_STATIC, nullptr));
|
||||
|
||||
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;
|
||||
bd->predict = {
|
||||
.x = player->mo->x + FixedMul(dist, FINECOSINE(botController->forceAngle >> ANGLETOFINESHIFT)),
|
||||
.y = player->mo->y + FixedMul(dist, FINESINE(botController->forceAngle >> ANGLETOFINESHIFT)),
|
||||
.radius = (DEFAULT_WAYPOINT_RADIUS / 4) * mapobjectscale,
|
||||
};
|
||||
|
||||
forcedDir = true;
|
||||
}
|
||||
|
||||
if (forcedDir == true)
|
||||
{
|
||||
destangle = R_PointToAngle2(player->mo->x, player->mo->y, predict->x, predict->y);
|
||||
turnamt = K_HandleBotTrack(player, cmd, predict, destangle);
|
||||
destangle = R_PointToAngle2(player->mo->x, player->mo->y, bd->predict.x, bd->predict.y);
|
||||
turnamt = K_HandleBotTrack(bd, player, destangle);
|
||||
}
|
||||
else if (leveltime <= starttime)
|
||||
{
|
||||
|
|
@ -1594,210 +1630,69 @@ static void K_BuildBotTiccmdNormal(player_t *player, ticcmd_t *cmd)
|
|||
if (player->botvars.difficulty > 4)
|
||||
{
|
||||
if (leveltime >= starttime-TICRATE-TICRATE/7+finaltiming)
|
||||
{
|
||||
cmd->buttons |= BT_ACCELERATE;
|
||||
cmd->forwardmove = MAXPLMOVE;
|
||||
}
|
||||
bd->acceldown = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Handle steering towards waypoints!
|
||||
if (predict == nullptr)
|
||||
// Create a prediction.
|
||||
if (K_CreateBotPrediction(bd, player))
|
||||
{
|
||||
// Create a prediction.
|
||||
predict = K_CreateBotPrediction(player);
|
||||
}
|
||||
|
||||
if (predict != nullptr)
|
||||
{
|
||||
K_NudgePredictionTowardsObjects(predict, player);
|
||||
destangle = R_PointToAngle2(player->mo->x, player->mo->y, predict->x, predict->y);
|
||||
turnamt = K_HandleBotTrack(player, cmd, predict, destangle);
|
||||
K_NudgePredictionTowardsObjects(bd, player);
|
||||
destangle = R_PointToAngle2(player->mo->x, player->mo->y, bd->predict.x, bd->predict.y);
|
||||
turnamt = K_HandleBotTrack(bd, player, destangle);
|
||||
}
|
||||
}
|
||||
|
||||
if (turnamt > KART_FULLTURN)
|
||||
{
|
||||
turnamt = KART_FULLTURN;
|
||||
}
|
||||
else if (turnamt < -KART_FULLTURN)
|
||||
{
|
||||
turnamt = -KART_FULLTURN;
|
||||
}
|
||||
|
||||
bd->turnamt = turnamt;
|
||||
|
||||
if (player->exiting == 0)
|
||||
{
|
||||
// TODO: Allowing projectile items like orbinaut while e-braking would be nice, maybe just pass in the spindash variable?
|
||||
t = I_GetPreciseTime();
|
||||
K_BotItemUsage(player, cmd, turnamt);
|
||||
precise_t t = I_GetPreciseTime();
|
||||
K_BotItemUsage(bd, player);
|
||||
ps_bots[player - players].item = I_GetPreciseTime() - t;
|
||||
}
|
||||
|
||||
if (turnamt != 0)
|
||||
if (turnamt > 0)
|
||||
{
|
||||
if (turnamt > KART_FULLTURN)
|
||||
// Count up
|
||||
if (bd->turnconfirm < BOTTURNCONFIRM)
|
||||
{
|
||||
turnamt = KART_FULLTURN;
|
||||
bd->turnconfirm++;
|
||||
}
|
||||
else if (turnamt < -KART_FULLTURN)
|
||||
}
|
||||
else if (turnamt < 0)
|
||||
{
|
||||
// Count down
|
||||
if (bd->turnconfirm > -BOTTURNCONFIRM)
|
||||
{
|
||||
turnamt = -KART_FULLTURN;
|
||||
bd->turnconfirm--;
|
||||
}
|
||||
|
||||
if (turnamt > 0)
|
||||
}
|
||||
else
|
||||
{
|
||||
// Back to neutral
|
||||
if (bd->turnconfirm < 0)
|
||||
{
|
||||
// Count up
|
||||
if (player->botvars.turnconfirm < BOTTURNCONFIRM)
|
||||
{
|
||||
cmd->bot.turnconfirm++;
|
||||
}
|
||||
bd->turnconfirm++;
|
||||
}
|
||||
else if (turnamt < 0)
|
||||
else if (bd->turnconfirm > 0)
|
||||
{
|
||||
// Count down
|
||||
if (player->botvars.turnconfirm > -BOTTURNCONFIRM)
|
||||
{
|
||||
cmd->bot.turnconfirm--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Back to neutral
|
||||
if (player->botvars.turnconfirm < 0)
|
||||
{
|
||||
cmd->bot.turnconfirm++;
|
||||
}
|
||||
else if (player->botvars.turnconfirm > 0)
|
||||
{
|
||||
cmd->bot.turnconfirm--;
|
||||
}
|
||||
}
|
||||
|
||||
if (abs(player->botvars.turnconfirm) >= BOTTURNCONFIRM)
|
||||
{
|
||||
// You're commiting to your turn, you're allowed!
|
||||
cmd->turning = turnamt;
|
||||
if (P_CanPlayerTurn(player, cmd))
|
||||
cmd->angle += K_GetKartTurnValue(player, turnamt);
|
||||
bd->turnconfirm--;
|
||||
}
|
||||
}
|
||||
|
||||
// Free the prediction we made earlier
|
||||
if (predict != nullptr)
|
||||
{
|
||||
if (cv_kartdebugbot.value != 0 && player - players == displayplayers[0] && !(paused || P_AutoPause()))
|
||||
{
|
||||
K_DrawPredictionDebug(predict, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
void K_BuildBotTiccmd(
|
||||
player_t *player, // annoyingly NOT const because of LUA_HookTiccmd... grumble grumble
|
||||
ticcmd_t *cmd)
|
||||
{
|
||||
ZoneScoped;
|
||||
|
||||
// Remove any existing controls
|
||||
memset(cmd, 0, sizeof(ticcmd_t));
|
||||
|
||||
if (player->mo == nullptr
|
||||
|| player->spectator == true
|
||||
|| G_GamestateUsesLevel() == false)
|
||||
{
|
||||
// Not in the level.
|
||||
return;
|
||||
}
|
||||
|
||||
cmd->angle = player->mo->angle >> TICCMD_REDUCE;
|
||||
|
||||
// Complete override of all ticcmd functionality.
|
||||
// May add more hooks to individual pieces of bot ticcmd,
|
||||
// but this should always be here so anyone can roll
|
||||
// their own :)
|
||||
if (LUA_HookTiccmd(player, cmd, HOOK(BotTiccmd)) == true)
|
||||
{
|
||||
cmd->flags |= TICCMD_BOT;
|
||||
return;
|
||||
}
|
||||
|
||||
cmd->flags |= TICCMD_BOT;
|
||||
|
||||
switch (player->botvars.style)
|
||||
{
|
||||
case BOT_STYLE_STAY:
|
||||
{
|
||||
// Hey, this one's pretty easy :P
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
K_BuildBotTiccmdNormal(player, cmd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void K_IncrementBotRespawn(player_t *player, UINT32 *respawn, const UINT32 respawnmax)
|
||||
{
|
||||
const fixed_t requireDist = (12*player->mo->scale) / FRACUNIT;
|
||||
INT32 progress = player->distancetofinishprev - player->distancetofinish;
|
||||
boolean exceptions = (
|
||||
(leveltime < starttime)
|
||||
|| player->flashing != 0
|
||||
|| player->spinouttimer != 0
|
||||
|| player->airtime > 3*TICRATE/2
|
||||
|| (player->justbumped > 0 && player->justbumped < bumptime-1)
|
||||
);
|
||||
|
||||
if (!exceptions && (progress < requireDist))
|
||||
{
|
||||
if (*respawn < respawnmax)
|
||||
{
|
||||
// Making no progress, start counting against you.
|
||||
*respawn = *respawn + 1;
|
||||
if (progress < -requireDist && *respawn < respawnmax)
|
||||
{
|
||||
// Making NEGATIVE progress? Start counting even harder.
|
||||
*respawn = *respawn + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (*respawn > 0)
|
||||
{
|
||||
// Playing normally.
|
||||
*respawn = *respawn - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_UpdateBotGameplayVars(player_t *player);
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
void K_UpdateBotGameplayVars(player_t *player)
|
||||
{
|
||||
if (gamestate != GS_LEVEL || !player->mo)
|
||||
{
|
||||
// Not in the level.
|
||||
return;
|
||||
}
|
||||
|
||||
player->botvars.rubberband = K_UpdateRubberband(player);
|
||||
|
||||
player->botvars.turnconfirm += player->cmd.bot.turnconfirm;
|
||||
|
||||
// Is a bot not making any progress? Kill it and respawn at next waypoint.
|
||||
K_IncrementBotRespawn(player, &player->botvars.respawnconfirm, BOTRESPAWNCONFIRM);
|
||||
|
||||
if ((player->cmd.bot.respawnconfirm >= TICRATE) && (player->botvars.respawnconfirm >= BOTRESPAWNCONFIRM))
|
||||
{
|
||||
// Now a clean function! Neat, eh?
|
||||
K_SetRespawnAtNextWaypoint(player);
|
||||
|
||||
// WHAT ARE YOU DOING??? RACE ALREADY!
|
||||
P_DamageMobj(player->mo, NULL, NULL, 1, DMG_INSTAKILL);
|
||||
|
||||
player->botvars.respawnconfirm = 0;
|
||||
}
|
||||
else if (player->cmd.forwardmove < 0)
|
||||
if (!bd->acceldown && bd->brakedown)
|
||||
{
|
||||
// stop drifting if we're reversing
|
||||
K_BotSetDriftState(player, DRIFTSTATE_AUTO, BOTDRIFTLOCKOUT);
|
||||
|
|
@ -1807,15 +1702,15 @@ void K_UpdateBotGameplayVars(player_t *player)
|
|||
// Figure out if we need to drift.
|
||||
// Drift-ending waypoints will kill the drift timer,
|
||||
// so no need to worry about doing that ourselves.
|
||||
K_BotStartDrift(player);
|
||||
K_BotStartDrift(bd, player);
|
||||
|
||||
INT32 limit = FixedInt(cv_test3.value) - gamespeed*5;
|
||||
INT32 dtime = ++player->botvars.drifttime;
|
||||
INT32 limit = bd->driftstatedelay;
|
||||
INT32 dtime = ++bd->drifttime;
|
||||
|
||||
// the faster we are going, the sooner we need to drift
|
||||
fixed_t speedfactor = FixedDiv(player->speed, K_GetKartSpeed(player, false, false));
|
||||
|
||||
switch (player->botvars.driftstate)
|
||||
switch (bd->driftstate)
|
||||
{
|
||||
case DRIFTSTATE_STARTING:
|
||||
limit = std::max(0, limit - FixedMul(TICRATE/5, speedfactor));
|
||||
|
|
@ -1838,5 +1733,123 @@ void K_UpdateBotGameplayVars(player_t *player)
|
|||
}
|
||||
}
|
||||
|
||||
if (cv_kartdebugbot.value != 0 && player - players == displayplayers[0] && !(paused || P_AutoPause()))
|
||||
{
|
||||
K_DrawPredictionDebug(bd, player);
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
|
||||
{
|
||||
ZoneScoped;
|
||||
|
||||
botdata_t *bd = &botdata[player - players];
|
||||
|
||||
// Remove any existing controls
|
||||
memset(cmd, 0, sizeof(ticcmd_t));
|
||||
|
||||
if (player->mo == nullptr
|
||||
|| player->spectator == true
|
||||
|| G_GamestateUsesLevel() == false)
|
||||
{
|
||||
// Not in the level.
|
||||
return;
|
||||
}
|
||||
|
||||
cmd->angle = player->mo->angle >> TICCMD_REDUCE;
|
||||
|
||||
// Complete override of all ticcmd functionality.
|
||||
// May add more hooks to individual pieces of bot ticcmd,
|
||||
// but this should always be here so anyone can roll
|
||||
// their own :)
|
||||
if (LUA_HookTiccmd(player, cmd, HOOK(BotTiccmd)) == true)
|
||||
return;
|
||||
|
||||
if (player->botvars.style == BOT_STYLE_STAY)
|
||||
{
|
||||
// Hey, this one's pretty easy :P
|
||||
return;
|
||||
}
|
||||
|
||||
// BOT_STYLE_NORMAL is the only other style, so...
|
||||
cmd->forwardmove = !!bd->acceldown * MAXPLMOVE - !!bd->brakedown * MAXPLMOVE/2;
|
||||
if (bd->itemthrow != 0)
|
||||
{
|
||||
cmd->throwdir = bd->itemthrow * KART_FULLTURN;
|
||||
cmd->buttons |= bd->itemthrow > 0 ? BT_FORWARD : BT_BACKWARD;
|
||||
}
|
||||
|
||||
if (bd->acceldown)
|
||||
cmd->buttons |= BT_ACCELERATE;
|
||||
if (bd->brakedown)
|
||||
cmd->buttons |= BT_BRAKE;
|
||||
if (bd->driftdown)
|
||||
cmd->buttons |= BT_DRIFT;
|
||||
if (bd->itemdown)
|
||||
cmd->buttons |= BT_ATTACK;
|
||||
|
||||
if (bd->dolookback)
|
||||
cmd->buttons |= BT_LOOKBACK;
|
||||
|
||||
if (abs(bd->turnconfirm) >= BOTTURNCONFIRM)
|
||||
{
|
||||
// You're commiting to your turn, you're allowed!
|
||||
cmd->turning = bd->turnamt;
|
||||
if (P_CanPlayerTurn(player, cmd))
|
||||
cmd->angle += K_GetKartTurnValue(player, bd->turnamt);
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_UpdateBotGameplayVars(player_t *player);
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
void K_UpdateBotGameplayVars(player_t *player)
|
||||
{
|
||||
if (gamestate != GS_LEVEL || !player->mo)
|
||||
{
|
||||
// Not in the level.
|
||||
return;
|
||||
}
|
||||
|
||||
player->botvars.rubberband = K_UpdateRubberband(player);
|
||||
|
||||
K_UpdateBotGameplayVarsItemUsage(player);
|
||||
}
|
||||
|
||||
// resets some botdata stuff after respawning
|
||||
void K_BotReborn(const player_t *player)
|
||||
{
|
||||
botdata_t *bd = &botdata[player - players];
|
||||
memset(bd, 0, sizeof(*bd));
|
||||
|
||||
bd->driftstate = DRIFTSTATE_AUTO;
|
||||
bd->driftskill = FixedMul(MAXDRIFTSKILL, K_BotDetermineDriftSkill(player));
|
||||
|
||||
// drift parameters, just fixed values for now
|
||||
bd->driftmaxdist = 200 + gamespeed*50;
|
||||
bd->driftpowerdiv = 40;
|
||||
bd->driftstatedelay = TICRATE/2 - gamespeed*5;
|
||||
}
|
||||
|
||||
void K_BotResetItemConfirm(const player_t *player, boolean setdelay)
|
||||
{
|
||||
botdata_t *bd = &botdata[player - players];
|
||||
bd->itemconfirm = 0;
|
||||
if (setdelay)
|
||||
bd->itemdelay = TICRATE;
|
||||
}
|
||||
|
||||
botdata_t *K_GetBotData(UINT8 num)
|
||||
{
|
||||
if (num < 0 || num >= MAXPLAYERS)
|
||||
return NULL;
|
||||
|
||||
return &botdata[num];
|
||||
}
|
||||
|
|
|
|||
154
src/k_bot.h
154
src/k_bot.h
|
|
@ -44,15 +44,67 @@ extern consvar_t cv_botcontrol;
|
|||
// How long it takes for a Lv.1 bot to decide to pick an item.
|
||||
#define BOT_ITEM_DECISION_TIME (2*TICRATE)
|
||||
|
||||
// Point for bots to aim for
|
||||
struct botprediction_t
|
||||
// Minimum percentage for a (non-auto) drift to begin.
|
||||
#define BOTDRIFTPERCENT (10)
|
||||
|
||||
// Minimum turning percentage for an auto drift to begin.
|
||||
#define DRIFTSTARTPCT (45)
|
||||
|
||||
#define BOTDRIFTTICS (2*TICRATE/3)
|
||||
#define BOTDRIFTLOCKOUT (TICRATE/2)
|
||||
|
||||
#define MAXDRIFTSKILL (FRACUNIT/2)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
fixed_t x, y;
|
||||
fixed_t radius, baseRadius;
|
||||
DRIFTSTATE_AUTO,
|
||||
DRIFTSTATE_STARTING,
|
||||
DRIFTSTATE_ACTIVE,
|
||||
DRIFTSTATE_ENDING,
|
||||
NUMDRIFTSTATES
|
||||
} ATTRPACK botdrift_e;
|
||||
|
||||
// unsynced bot variables, exclusively for use by bot logic and ticcmd generation
|
||||
// nobody except the server cares about this stuff!
|
||||
struct botdata_t
|
||||
{
|
||||
// Point for bots to aim for
|
||||
struct
|
||||
{
|
||||
fixed_t x, y;
|
||||
fixed_t radius, baseRadius;
|
||||
} predict;
|
||||
|
||||
tic_t itemdelay; // Delay before using item at all
|
||||
tic_t itemconfirm; // When high enough, they will use their item
|
||||
|
||||
SINT8 turnconfirm; // Confirm turn direction
|
||||
UINT8 respawnconfirm; // Confirm when respawn is needed.
|
||||
|
||||
botdrift_e driftstate; // Drifting state
|
||||
SINT8 driftturn; // Drifting turn direction
|
||||
tic_t drifttime; // Time spent drifting
|
||||
tic_t driftlockout; // do not allow drifting for this many tics
|
||||
|
||||
UINT16 driftmaxdist; // how far to look for drift waypoints
|
||||
UINT16 driftpowerdiv; // arbitrary divider on drift turning
|
||||
UINT16 driftstatedelay; // max time to wait between drift state changes
|
||||
|
||||
fixed_t driftskill; // The bot's "skill" at drifts.
|
||||
// Determines how soon a bot starts to drift.
|
||||
|
||||
boolean acceldown, brakedown, driftdown, itemdown; // buttons
|
||||
boolean dolookback; // look out behind you
|
||||
boolean itemwasdown; // last tic's item button
|
||||
SINT8 itemthrow; // throwdir
|
||||
INT16 turnamt; // turning
|
||||
};
|
||||
|
||||
// AVAILABLE FOR LUA
|
||||
|
||||
void K_BotTicker(const player_t *player);
|
||||
|
||||
void K_DrawBotDebugger(const player_t *player);
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_PlayerUsesBotMovement(const player_t *player);
|
||||
|
|
@ -70,7 +122,7 @@ boolean K_PlayerUsesBotMovement(const player_t *player);
|
|||
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_BotCanTakeCut(player_t *player);
|
||||
boolean K_BotCanTakeCut(const player_t *player);
|
||||
|
||||
Tells if this bot is able to take shortcuts (currently unaffected by offroad,
|
||||
or has certain items ready).
|
||||
|
|
@ -82,11 +134,11 @@ boolean K_PlayerUsesBotMovement(const player_t *player);
|
|||
true if able to take shortcuts, otherwise false.
|
||||
--------------------------------------------------*/
|
||||
|
||||
boolean K_BotCanTakeCut(player_t *player);
|
||||
boolean K_BotCanTakeCut(const player_t *player);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
const botcontroller_t *K_GetBotController(mobj_t *mobj);
|
||||
botcontroller_t *K_GetBotController(const mobj_t *mobj);
|
||||
|
||||
Retrieves the current bot controller values from
|
||||
the player's current sector.
|
||||
|
|
@ -98,7 +150,7 @@ boolean K_BotCanTakeCut(player_t *player);
|
|||
Pointer to the sector's bot controller struct.
|
||||
--------------------------------------------------*/
|
||||
|
||||
const botcontroller_t *K_GetBotController(mobj_t *mobj);
|
||||
botcontroller_t *K_GetBotController(const mobj_t *mobj);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
|
|
@ -261,7 +313,7 @@ UINT8 K_EggboxStealth(fixed_t x, fixed_t y);
|
|||
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_BotHatesThisSector(player_t *player, sector_t *sec, fixed_t x, fixed_t y)
|
||||
boolean K_BotHatesThisSector(const player_t *player, sector_t *sec, fixed_t x, fixed_t y)
|
||||
|
||||
Tells us if a bot will play more careful around
|
||||
this sector. Checks FOFs in the sector, as well.
|
||||
|
|
@ -276,23 +328,10 @@ UINT8 K_EggboxStealth(fixed_t x, fixed_t y);
|
|||
true if avoiding this sector, false otherwise.
|
||||
--------------------------------------------------*/
|
||||
|
||||
boolean K_BotHatesThisSector(player_t *player, sector_t *sec, fixed_t x, fixed_t y);
|
||||
boolean K_BotHatesThisSector(const player_t *player, sector_t *sec, fixed_t x, fixed_t y);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player);
|
||||
|
||||
Moves the bot's prediction, based on objects around the bot.
|
||||
|
||||
Input Arguments:-
|
||||
predict - The bot's prediction to nudge.
|
||||
player - Player to compare.
|
||||
|
||||
Return:-
|
||||
None
|
||||
--------------------------------------------------*/
|
||||
|
||||
void K_NudgePredictionTowardsObjects(botprediction_t *predict, const player_t *player);
|
||||
// Moves the bot's prediction, based on objects around the bot.
|
||||
void K_NudgePredictionTowardsObjects(botdata_t *bd, const player_t *player);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
|
|
@ -310,6 +349,21 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, const player_t *p
|
|||
INT32 K_PositionBully(const player_t *player);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_GetBlockedBubbleItem(const player_t *player, , fixed_t radius)
|
||||
|
||||
Searches the blockmap for items to block with the Bubble Shield
|
||||
|
||||
Input Arguments:-
|
||||
player - Bot to run this for.
|
||||
radius - Radius around player to check for items.
|
||||
|
||||
Return:-
|
||||
false if couldn't find anything, otherwise true to attempt blocking item.
|
||||
--------------------------------------------------*/
|
||||
|
||||
boolean K_GetBlockedBubbleItem(const player_t *player, fixed_t radius);
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd);
|
||||
|
||||
|
|
@ -359,54 +413,16 @@ void K_UpdateBotGameplayVarsItemUsage(player_t *player);
|
|||
|
||||
void K_UpdateBotGameplayVars(player_t *player);
|
||||
|
||||
// Item usage part of ticcmd generation.
|
||||
void K_BotItemUsage(botdata_t *bd, const player_t *player);
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt);
|
||||
void K_BotReborn(const player_t *player);
|
||||
|
||||
Item usage part of ticcmd generation.
|
||||
void K_BotResetItemConfirm(const player_t *player, boolean setdelay);
|
||||
|
||||
Input Arguments:-
|
||||
player - Player to generate the ticcmd for.
|
||||
cmd - The player's ticcmd to modify.
|
||||
turnamt - How hard the bot is turning.
|
||||
|
||||
Return:-
|
||||
None
|
||||
--------------------------------------------------*/
|
||||
|
||||
void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt);
|
||||
|
||||
/*--------------------------------------------------
|
||||
fixed_t K_BotDetermineDriftSkill(player_t *player)
|
||||
|
||||
Calculates drift skill for a player based on stats.
|
||||
|
||||
Input Arguments:-
|
||||
player - Player to get drift skill for.
|
||||
|
||||
Return:-
|
||||
Calculated drift skill.
|
||||
--------------------------------------------------*/
|
||||
|
||||
fixed_t K_BotDetermineDriftSkill(player_t *player);
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_BotSetDriftState(player_t *player, botdrift_t newstate, tic_t lockout)
|
||||
|
||||
Changes a bot's drift state.
|
||||
Resets the drift timer if the old and new state are different.
|
||||
|
||||
Input Arguments:-
|
||||
player - Player to set drift state for.
|
||||
newstate - The new drift state.
|
||||
lockout - If non-zero, apply drift lockout for this many tics.
|
||||
|
||||
Return:-
|
||||
None
|
||||
--------------------------------------------------*/
|
||||
|
||||
void K_BotSetDriftState(player_t *player, botdrift_t newstate, tic_t lockout);
|
||||
void K_BotSetDriftState(const player_t *player, botdrift_e newstate, tic_t lockout);
|
||||
|
||||
botdata_t *K_GetBotData(UINT8 num);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -137,7 +137,7 @@ UINT8 K_EggboxStealth(fixed_t x, fixed_t y)
|
|||
Return:-
|
||||
true if avoiding this sector special, false otherwise.
|
||||
--------------------------------------------------*/
|
||||
static boolean K_BotHatesThisSectorsSpecial(player_t *player, sector_t *sec, const boolean flip)
|
||||
static boolean K_BotHatesThisSectorsSpecial(const player_t *player, sector_t *sec, const boolean flip)
|
||||
{
|
||||
terrain_t *terrain = K_GetTerrainForFlatNum(flip ? sec->ceilingpic : sec->floorpic);
|
||||
|
||||
|
|
@ -174,7 +174,7 @@ static boolean K_BotHatesThisSectorsSpecial(player_t *player, sector_t *sec, con
|
|||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
boolean K_BotHatesThisSector(player_t *player, sector_t *sec, fixed_t x, fixed_t y)
|
||||
boolean K_BotHatesThisSector(const player_t *player, sector_t *sec, fixed_t x, fixed_t y)
|
||||
{
|
||||
const boolean flip = (player->mo->eflags & MFE_VERTICALFLIP);
|
||||
fixed_t highestfloor = INT32_MAX;
|
||||
|
|
@ -644,12 +644,8 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
|
|||
return BMIT_CONTINUE;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_NudgePredictionTowardsObjects(botprediction_t *predict, const player_t *player)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
void K_NudgePredictionTowardsObjects(botprediction_t *predict, const player_t *player)
|
||||
// See header file for description.
|
||||
void K_NudgePredictionTowardsObjects(botdata_t *bd, const player_t *player)
|
||||
{
|
||||
ZoneScoped;
|
||||
|
||||
|
|
@ -672,20 +668,14 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, const player_t *p
|
|||
SINT8 gotoSide = -1;
|
||||
UINT8 i;
|
||||
|
||||
if (predict == NULL)
|
||||
{
|
||||
ps_bots[player - players].nudge += I_GetPreciseTime() - time;
|
||||
return;
|
||||
}
|
||||
|
||||
distToPredict = R_PointToDist2(player->mo->x, player->mo->y, predict->x, predict->y);
|
||||
angleToPredict = R_PointToAngle2(player->mo->x, player->mo->y, predict->x, predict->y);
|
||||
distToPredict = R_PointToDist2(player->mo->x, player->mo->y, bd->predict.x, bd->predict.y);
|
||||
angleToPredict = R_PointToAngle2(player->mo->x, player->mo->y, bd->predict.x, bd->predict.y);
|
||||
|
||||
radToPredict = distToPredict >> 1;
|
||||
g_nudgeSearch.distancetocheck = FixedMul(radToPredict, radToPredict);
|
||||
|
||||
baseNudge = predict->baseRadius >> 3;
|
||||
maxNudge = predict->baseRadius - baseNudge;
|
||||
baseNudge = bd->predict.baseRadius >> 3;
|
||||
maxNudge = bd->predict.baseRadius - baseNudge;
|
||||
|
||||
g_nudgeSearch.botmo = player->mo;
|
||||
g_nudgeSearch.angle = angleToPredict;
|
||||
|
|
@ -735,7 +725,7 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, const player_t *p
|
|||
|
||||
avgDist = R_PointToDist2(
|
||||
avgX, avgY,
|
||||
predict->x, predict->y
|
||||
bd->predict.x, bd->predict.y
|
||||
);
|
||||
|
||||
// High handling characters dodge better
|
||||
|
|
@ -748,14 +738,14 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, const player_t *p
|
|||
// Point away
|
||||
nudgeDir = R_PointToAngle2(
|
||||
avgX, avgY,
|
||||
predict->x, predict->y
|
||||
bd->predict.x, bd->predict.y
|
||||
);
|
||||
|
||||
predict->x += FixedMul(nudgeDist, FINECOSINE(nudgeDir >> ANGLETOFINESHIFT));
|
||||
predict->y += FixedMul(nudgeDist, FINESINE(nudgeDir >> ANGLETOFINESHIFT));
|
||||
predict->radius = std::max(predict->radius - nudgeDist, baseNudge);
|
||||
bd->predict.x += FixedMul(nudgeDist, FINECOSINE(nudgeDir >> ANGLETOFINESHIFT));
|
||||
bd->predict.y += FixedMul(nudgeDist, FINESINE(nudgeDir >> ANGLETOFINESHIFT));
|
||||
bd->predict.radius = std::max(bd->predict.radius - nudgeDist, baseNudge);
|
||||
|
||||
distToPredict = R_PointToDist2(player->mo->x, player->mo->y, predict->x, predict->y);
|
||||
distToPredict = R_PointToDist2(player->mo->x, player->mo->y, bd->predict.x, bd->predict.y);
|
||||
|
||||
// Flip side, since we want to check for objects to steer towards on the side we're NOT dodging.
|
||||
if (gotoSide == 0)
|
||||
|
|
@ -797,7 +787,7 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, const player_t *p
|
|||
avgY = (g_nudgeSearch.gotoAvgY[gotoSide] / g_nudgeSearch.gotoObjs[gotoSide]) * mapobjectscale;
|
||||
|
||||
avgDist = R_PointToDist2(
|
||||
predict->x, predict->y,
|
||||
bd->predict.x, bd->predict.y,
|
||||
avgX, avgY
|
||||
);
|
||||
|
||||
|
|
@ -810,23 +800,23 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, const player_t *p
|
|||
|
||||
if (avgDist <= nudgeDist)
|
||||
{
|
||||
predict->x = avgX;
|
||||
predict->y = avgY;
|
||||
predict->radius = baseNudge;
|
||||
bd->predict.x = avgX;
|
||||
bd->predict.y = avgY;
|
||||
bd->predict.radius = baseNudge;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Point towards
|
||||
nudgeDir = R_PointToAngle2(
|
||||
predict->x, predict->y,
|
||||
bd->predict.x, bd->predict.y,
|
||||
avgX, avgY
|
||||
);
|
||||
|
||||
predict->x += FixedMul(nudgeDist, FINECOSINE(nudgeDir >> ANGLETOFINESHIFT));
|
||||
predict->y += FixedMul(nudgeDist, FINESINE(nudgeDir >> ANGLETOFINESHIFT));
|
||||
predict->radius = std::max(predict->radius - nudgeDist, baseNudge);
|
||||
bd->predict.x += FixedMul(nudgeDist, FINECOSINE(nudgeDir >> ANGLETOFINESHIFT));
|
||||
bd->predict.y += FixedMul(nudgeDist, FINESINE(nudgeDir >> ANGLETOFINESHIFT));
|
||||
bd->predict.radius = std::max(bd->predict.radius - nudgeDist, baseNudge);
|
||||
|
||||
//distToPredict = R_PointToDist2(player->mo->x, player->mo->y, predict->x, predict->y);
|
||||
//distToPredict = R_PointToDist2(player->mo->x, player->mo->y, bd->predict.x, bd->predict.y);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -991,3 +981,90 @@ INT32 K_PositionBully(const player_t *player)
|
|||
|
||||
return KART_FULLTURN;
|
||||
}
|
||||
|
||||
static mobj_t *bubbleSource;
|
||||
static fixed_t bubbleDist;
|
||||
static boolean bubbleBlock;
|
||||
|
||||
static inline BlockItReturn_t PIT_BubbleShieldBlock(mobj_t *thing)
|
||||
{
|
||||
if (bubbleSource == NULL || P_MobjWasRemoved(bubbleSource))
|
||||
{
|
||||
// Invalid?
|
||||
return BMIT_ABORT;
|
||||
}
|
||||
|
||||
if (thing == NULL || P_MobjWasRemoved(thing))
|
||||
{
|
||||
// Invalid?
|
||||
return BMIT_ABORT;
|
||||
}
|
||||
|
||||
if (thing == bubbleSource)
|
||||
{
|
||||
// Don't block yourself!!
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
|
||||
if (thing->player)
|
||||
{
|
||||
// We don't block players.
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
|
||||
if (thing->health <= 0)
|
||||
{
|
||||
// Dead
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
|
||||
if (!P_IsKartItem(thing->type) && !(thing->flags & MF_SHOOTABLE))
|
||||
{
|
||||
// Not a Item.
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
|
||||
if (P_AproxDistance(P_AproxDistance(
|
||||
bubbleSource->x - thing->x,
|
||||
bubbleSource->y - thing->y),
|
||||
(bubbleSource->z - thing->z) / 4) > bubbleDist)
|
||||
{
|
||||
// Too far away
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (P_CheckSight(bubbleSource, thing) == false)
|
||||
{
|
||||
// Not in sight
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
bubbleBlock = true;
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
|
||||
// Searches the blockmap for items to block with the Bubble Shield
|
||||
boolean K_GetBlockedBubbleItem(const player_t *player, fixed_t radius)
|
||||
{
|
||||
INT32 bx, by, xl, xh, yl, yh;
|
||||
|
||||
bubbleSource = player->mo;
|
||||
bubbleDist = radius;
|
||||
bubbleBlock = false;
|
||||
|
||||
// Use blockmap to check for nearby harmful items.
|
||||
yh = (unsigned)(bubbleSource->y + bubbleDist - bmaporgy)>>MAPBLOCKSHIFT;
|
||||
yl = (unsigned)(bubbleSource->y - bubbleDist - bmaporgy)>>MAPBLOCKSHIFT;
|
||||
xh = (unsigned)(bubbleSource->x + bubbleDist - bmaporgx)>>MAPBLOCKSHIFT;
|
||||
xl = (unsigned)(bubbleSource->x - bubbleDist - bmaporgx)>>MAPBLOCKSHIFT;
|
||||
|
||||
BMBOUNDFIX (xl, xh, yl, yh);
|
||||
|
||||
for (by = yl; by <= yh; by++)
|
||||
for (bx = xl; bx <= xh; bx++)
|
||||
P_BlockThingsIterator(bx, by, PIT_BubbleShieldBlock);
|
||||
|
||||
return bubbleBlock;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -554,9 +554,9 @@ boolean K_BubbleShieldReflect(mobj_t *t1, mobj_t *t2)
|
|||
}
|
||||
else
|
||||
{
|
||||
t2->momx = -6*t2->momx;
|
||||
t2->momy = -6*t2->momy;
|
||||
t2->momz = -6*t2->momz;
|
||||
t2->momx = (-1*t2->momx)/2;
|
||||
t2->momy = (-1*t2->momy)/2;
|
||||
t2->momz = (-1*t2->momz)/2;
|
||||
t2->angle += ANGLE_180;
|
||||
}
|
||||
if (t2->type == MT_JAWZ)
|
||||
|
|
@ -598,7 +598,15 @@ boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2)
|
|||
|
||||
if (t2->flags & MF_SHOOTABLE)
|
||||
{
|
||||
P_DamageMobj(t2, t1, t1->target, 1, DMG_NORMAL);
|
||||
boolean shootable = P_DamageMobj(t2, t1, t1->target, 1, DMG_NORMAL);
|
||||
|
||||
if (shootable)
|
||||
{
|
||||
// Drain my stuff please.
|
||||
K_BubbleShieldCollideDrain(t1->target->player, t1);
|
||||
}
|
||||
|
||||
return shootable;
|
||||
}
|
||||
|
||||
// no interaction
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
#include "k_kart.h"
|
||||
#include "m_random.h"
|
||||
#include "r_things.h"
|
||||
#include "lua_hook.h" // LUA_HookGPRankPoints
|
||||
#include "lua_hook.h"
|
||||
|
||||
struct grandprixinfo grandprixinfo;
|
||||
|
||||
|
|
@ -641,6 +641,7 @@ void K_RetireBots(void)
|
|||
K_SetNameForBot(i, skins[skinnum].realname);
|
||||
|
||||
bot->score = 0;
|
||||
LUA_HookPlayer(bot, HOOK(BotJoin));
|
||||
bot->pflags &= ~PF_NOCONTEST;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
29
src/k_hud.c
29
src/k_hud.c
|
|
@ -40,7 +40,7 @@
|
|||
#include "m_random.h"
|
||||
#include "g_party.h"
|
||||
#include "h_timers.h"
|
||||
#include "v_video.h"
|
||||
#include "k_bot.h" // K_DrawBotDebugger
|
||||
|
||||
#define NUMPOSNUMS 10
|
||||
#define NUMPOSFRAMES 7 // White, three blues, three reds
|
||||
|
|
@ -5068,29 +5068,6 @@ static void K_DrawClusterDebugger(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void K_DrawBotDebugger(void)
|
||||
{
|
||||
if (!cv_kartdebugbot.value || !stplyr->bot)
|
||||
return;
|
||||
|
||||
if (stplyrnum != 0) // only for p1
|
||||
return;
|
||||
|
||||
INT32 vflags = V_6WIDTHSPACE|V_ALLOWLOWERCASE;
|
||||
|
||||
static const char *driftstates[] = {
|
||||
[DRIFTSTATE_AUTO] = "Auto",
|
||||
[DRIFTSTATE_STARTING] = "Starting",
|
||||
[DRIFTSTATE_ACTIVE] = "Active",
|
||||
[DRIFTSTATE_ENDING] = "Ending",
|
||||
};
|
||||
|
||||
V_DrawThinString(24, 100, vflags, va("Drift state: %s", driftstates[stplyr->botvars.driftstate]));
|
||||
V_DrawThinString(24, 108, vflags|(stplyr->botvars.driftlockout ? V_ORANGEMAP : 0), va("Drift lockout: %d", stplyr->botvars.driftlockout));
|
||||
V_DrawThinString(24, 116, vflags, va("Drift turn: %d", stplyr->botvars.driftturn));
|
||||
V_DrawThinString(24, 124, vflags, va("Drift timer: %d", stplyr->botvars.drifttime));
|
||||
}
|
||||
|
||||
void K_drawKartHUD(void)
|
||||
{
|
||||
boolean islonesome = false;
|
||||
|
|
@ -5332,9 +5309,11 @@ void K_drawKartHUD(void)
|
|||
}
|
||||
|
||||
K_DrawWaypointDebugger();
|
||||
K_DrawBotDebugger();
|
||||
K_DrawClusterDebugger();
|
||||
K_DrawDirectorDebugger();
|
||||
|
||||
if (stplyrnum == 0)
|
||||
K_DrawBotDebugger(stplyr);
|
||||
}
|
||||
|
||||
// Thank you Haya....
|
||||
|
|
|
|||
109
src/k_kart.c
109
src/k_kart.c
|
|
@ -385,10 +385,6 @@ void K_RegisterKartStuff(void)
|
|||
CV_RegisterVar(&cv_itemtimers);
|
||||
CV_RegisterVar(&cv_saltyhop);
|
||||
|
||||
CV_RegisterVar(&cv_test1);
|
||||
CV_RegisterVar(&cv_test2);
|
||||
CV_RegisterVar(&cv_test3);
|
||||
|
||||
CV_RegisterVar(&cv_naturalcamera);
|
||||
}
|
||||
|
||||
|
|
@ -647,8 +643,7 @@ static void K_KartGetItemResult(player_t *player, SINT8 getitem)
|
|||
if (getitem == KITEM_HYUDORO) // Hyudoro cooldown
|
||||
hyubgone = 20*TICRATE;
|
||||
|
||||
player->botvars.itemdelay = TICRATE;
|
||||
player->botvars.itemconfirm = 0;
|
||||
K_BotResetItemConfirm(player, true);
|
||||
|
||||
player->itemtype = K_ItemResultToType(getitem);
|
||||
UINT8 itemamount = K_ItemResultToAmount(getitem);
|
||||
|
|
@ -1226,7 +1221,7 @@ INT32 K_KartGetLegacyItemOdds(UINT8 pos, SINT8 item, fixed_t clusterDist, fixed_
|
|||
|
||||
//{ SRB2kart Roulette Code - Distance Based, yes waypoints
|
||||
|
||||
UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbumper, boolean spbrush)
|
||||
UINT8 K_FindUseodds(const player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbumper, boolean spbrush)
|
||||
{
|
||||
UINT8 i;
|
||||
UINT8 useodds = 0;
|
||||
|
|
@ -3440,7 +3435,7 @@ void K_MomentumToFacing(player_t *player)
|
|||
player->mo->momy = FixedMul(player->mo->momy - player->cmomy, player->mo->friction) + player->cmomy;
|
||||
}
|
||||
|
||||
boolean K_ApplyOffroad(player_t *player)
|
||||
boolean K_ApplyOffroad(const player_t *player)
|
||||
{
|
||||
boolean sneakertimer = CANTCHAINOFFROAD ? (player->sneakertimer && player->realsneakertimer) : player->sneakertimer > 0;
|
||||
|
||||
|
|
@ -3452,7 +3447,7 @@ boolean K_ApplyOffroad(player_t *player)
|
|||
return true;
|
||||
}
|
||||
|
||||
fixed_t K_PlayerTripwireSpeedThreshold(player_t *player)
|
||||
fixed_t K_PlayerTripwireSpeedThreshold(const player_t *player)
|
||||
{
|
||||
fixed_t required_speed = 2 * K_GetKartSpeed(player, false, false); // 200%
|
||||
|
||||
|
|
@ -3476,7 +3471,7 @@ fixed_t K_PlayerTripwireSpeedThreshold(player_t *player)
|
|||
return required_speed;
|
||||
}
|
||||
|
||||
tripwirepass_t K_TripwirePassConditions(player_t *player)
|
||||
tripwirepass_t K_TripwirePassConditions(const player_t *player)
|
||||
{
|
||||
if (
|
||||
player->invincibilitytimer ||
|
||||
|
|
@ -3499,7 +3494,7 @@ tripwirepass_t K_TripwirePassConditions(player_t *player)
|
|||
return TRIPWIRE_NONE;
|
||||
}
|
||||
|
||||
boolean K_TripwirePass(player_t *player)
|
||||
boolean K_TripwirePass(const player_t *player)
|
||||
{
|
||||
return (player->tripwirePass != TRIPWIRE_NONE);
|
||||
}
|
||||
|
|
@ -4164,7 +4159,7 @@ fixed_t K_GetKartSpeedFromStat(UINT8 kartspeed, boolean karmabomb)
|
|||
return finalspeed;
|
||||
}
|
||||
|
||||
fixed_t K_GetKartSpeed(player_t *player, boolean doboostpower, boolean dorubberband)
|
||||
fixed_t K_GetKartSpeed(const player_t *player, boolean doboostpower, boolean dorubberband)
|
||||
{
|
||||
boolean karmabomb = ((gametyperules & GTR_KARMA) && player->bumper <= 0);
|
||||
fixed_t finalspeed;
|
||||
|
|
@ -4204,7 +4199,7 @@ fixed_t K_GetKartSpeed(player_t *player, boolean doboostpower, boolean dorubberb
|
|||
return finalspeed;
|
||||
}
|
||||
|
||||
fixed_t K_GetKartAccel(player_t *player)
|
||||
fixed_t K_GetKartAccel(const player_t *player)
|
||||
{
|
||||
fixed_t k_accel = 32; // 36;
|
||||
UINT8 kartspeed = player->kartspeed;
|
||||
|
|
@ -4217,7 +4212,7 @@ fixed_t K_GetKartAccel(player_t *player)
|
|||
return FixedMul(k_accel, FRACUNIT+player->accelboost);
|
||||
}
|
||||
|
||||
UINT16 K_GetKartFlashing(player_t *player)
|
||||
UINT16 K_GetKartFlashing(const player_t *player)
|
||||
{
|
||||
UINT16 tics = flashingtics;
|
||||
|
||||
|
|
@ -4230,7 +4225,7 @@ UINT16 K_GetKartFlashing(player_t *player)
|
|||
return tics;
|
||||
}
|
||||
|
||||
boolean K_PlayerShrinkCheat(player_t *player)
|
||||
boolean K_PlayerShrinkCheat(const player_t *player)
|
||||
{
|
||||
if (cv_kartdebugshrink.value)
|
||||
return true;
|
||||
|
|
@ -4261,20 +4256,20 @@ void K_UpdateShrinkCheat(player_t *player)
|
|||
}
|
||||
}
|
||||
|
||||
boolean K_KartKickstart(player_t *player)
|
||||
boolean K_KartKickstart(const player_t *player)
|
||||
{
|
||||
return ((player->pflags & PF_KICKSTARTACCEL)
|
||||
&& (!K_PlayerUsesBotMovement(player))
|
||||
&& (player->kickstartaccel >= ACCEL_KICKSTART));
|
||||
}
|
||||
|
||||
UINT16 K_GetKartButtons(player_t *player)
|
||||
UINT16 K_GetKartButtons(const player_t *player)
|
||||
{
|
||||
return (player->cmd.buttons |
|
||||
(K_KartKickstart(player) ? BT_ACCELERATE : 0));
|
||||
}
|
||||
|
||||
SINT8 K_GetForwardMove(player_t *player)
|
||||
SINT8 K_GetForwardMove(const player_t *player)
|
||||
{
|
||||
SINT8 forwardmove = player->cmd.forwardmove;
|
||||
|
||||
|
|
@ -4305,7 +4300,7 @@ SINT8 K_GetForwardMove(player_t *player)
|
|||
return forwardmove;
|
||||
}
|
||||
|
||||
SINT8 K_GetSideMove(player_t *player)
|
||||
SINT8 K_GetSideMove(const player_t *player)
|
||||
{
|
||||
SINT8 sidemove = player->cmd.sidemove;
|
||||
|
||||
|
|
@ -4325,7 +4320,7 @@ SINT8 K_GetSideMove(player_t *player)
|
|||
return sidemove;
|
||||
}
|
||||
|
||||
fixed_t K_GetNewSpeed(player_t *player)
|
||||
fixed_t K_GetNewSpeed(const player_t *player)
|
||||
{
|
||||
const fixed_t accelmax = 4000;
|
||||
const fixed_t p_speed = K_GetKartSpeed(player, true, true);
|
||||
|
|
@ -4365,7 +4360,7 @@ fixed_t K_GetNewSpeed(player_t *player)
|
|||
return finalspeed;
|
||||
}
|
||||
|
||||
fixed_t K_3dKartMovement(player_t *player, boolean onground, SINT8 forwardmove)
|
||||
fixed_t K_3dKartMovement(const player_t *player, boolean onground, SINT8 forwardmove)
|
||||
{
|
||||
fixed_t finalspeed = K_GetNewSpeed(player);
|
||||
|
||||
|
|
@ -4662,7 +4657,7 @@ INT32 K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source) // A
|
|||
return ringburst;
|
||||
}
|
||||
|
||||
boolean K_IsPlayerDamaged(player_t *player)
|
||||
boolean K_IsPlayerDamaged(const player_t *player)
|
||||
{
|
||||
return ((player->spinouttimer > 0) || (player->flipovertimer > 0));
|
||||
}
|
||||
|
|
@ -9781,7 +9776,7 @@ static void K_UpdatePlayerWaypoints(player_t *const player)
|
|||
player->pflags &= ~PF_TRUSTWAYPOINTS; // clear special exception
|
||||
}
|
||||
|
||||
INT32 K_GetKartRingPower(player_t *player, boolean boosted)
|
||||
INT32 K_GetKartRingPower(const player_t *player, boolean boosted)
|
||||
{
|
||||
fixed_t ringPower = ((9 - player->kartspeed) + (9 - player->kartweight)) * (FRACUNIT/2);
|
||||
UINT16 finalPower = 0;
|
||||
|
|
@ -9845,7 +9840,7 @@ boolean K_CheckPlayersRespawnColliding(INT32 playernum, fixed_t x, fixed_t y)
|
|||
|
||||
// countersteer is how strong the controls are telling us we are turning
|
||||
// turndir is the direction the controls are telling us to turn, -1 if turning right and 1 if turning left
|
||||
static INT16 K_GetKartDriftValue(player_t *player, fixed_t countersteer)
|
||||
static INT16 K_GetKartDriftValue(const player_t *player, fixed_t countersteer)
|
||||
{
|
||||
INT16 basedrift, driftangle;
|
||||
fixed_t driftweight = player->kartweight*14; // 12
|
||||
|
|
@ -9872,7 +9867,7 @@ static INT16 K_GetKartDriftValue(player_t *player, fixed_t countersteer)
|
|||
return basedrift + FixedMul(driftangle, countersteer);
|
||||
}
|
||||
|
||||
INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue)
|
||||
INT16 K_GetKartTurnValue(const player_t *player, INT16 turnvalue)
|
||||
{
|
||||
fixed_t p_topspeed = K_GetKartSpeed(player, false, false);
|
||||
fixed_t p_curspeed = min(player->speed, p_topspeed * 2);
|
||||
|
|
@ -9918,7 +9913,7 @@ INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue)
|
|||
return turnvalue;
|
||||
}
|
||||
|
||||
INT32 K_GetKartDriftSparkValue(player_t *player)
|
||||
INT32 K_GetKartDriftSparkValue(const player_t *player)
|
||||
{
|
||||
UINT8 kartspeed = ((gametyperules & GTR_KARMA) && player->bumper <= 0)
|
||||
? 1
|
||||
|
|
@ -9926,7 +9921,7 @@ INT32 K_GetKartDriftSparkValue(player_t *player)
|
|||
return (26*4 + kartspeed*2 + (9 - player->kartweight))*8;
|
||||
}
|
||||
|
||||
INT32 K_GetKartDriftSparkValueForStage(player_t *player, UINT8 stage)
|
||||
INT32 K_GetKartDriftSparkValueForStage(const player_t *player, UINT8 stage)
|
||||
{
|
||||
fixed_t mul = FRACUNIT;
|
||||
|
||||
|
|
@ -10850,7 +10845,7 @@ void K_StripOther(player_t *player)
|
|||
}
|
||||
}
|
||||
|
||||
SINT8 K_Sliptiding(player_t *player)
|
||||
SINT8 K_Sliptiding(const player_t *player)
|
||||
{
|
||||
return player->drift ? 0 : player->aizdriftstrat;
|
||||
}
|
||||
|
|
@ -10897,7 +10892,7 @@ static void K_AirFailsafe(player_t *player)
|
|||
//
|
||||
// K_PlayerBaseFriction
|
||||
//
|
||||
fixed_t K_PlayerBaseFriction(player_t *player, fixed_t original)
|
||||
fixed_t K_PlayerBaseFriction(const player_t *player, fixed_t original)
|
||||
{
|
||||
const fixed_t factor = FixedMul(
|
||||
FixedDiv(FRACUNIT - original, FRACUNIT - ORIG_FRICTION),
|
||||
|
|
@ -11023,7 +11018,7 @@ void K_SetTireGrease(player_t *player, tic_t tics)
|
|||
player->tiregrease = tics;
|
||||
}
|
||||
|
||||
boolean K_SlopeResistance(player_t *player)
|
||||
boolean K_SlopeResistance(const player_t *player)
|
||||
{
|
||||
if (player->tiregrease)
|
||||
return true;
|
||||
|
|
@ -11165,7 +11160,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
if (ATTACK_IS_DOWN && player->eggmanexplode <= 3*TICRATE && player->eggmanexplode > 1)
|
||||
{
|
||||
player->eggmanexplode = 1;
|
||||
player->botvars.itemconfirm = 0;
|
||||
K_BotResetItemConfirm(player, false);
|
||||
}
|
||||
}
|
||||
// Eggman Monitor throwing
|
||||
|
|
@ -11177,7 +11172,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
K_PlayAttackTaunt(player->mo);
|
||||
player->itemflags &= ~IF_EGGMANOUT;
|
||||
K_UpdateHnextList(player, true);
|
||||
player->botvars.itemconfirm = 0;
|
||||
K_BotResetItemConfirm(player, false);
|
||||
}
|
||||
}
|
||||
// Rocket Sneaker usage
|
||||
|
|
@ -11191,7 +11186,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
player->rocketsneakertimer = 1;
|
||||
else
|
||||
player->rocketsneakertimer -= 2*TICRATE;
|
||||
player->botvars.itemconfirm = 0;
|
||||
K_BotResetItemConfirm(player, false);
|
||||
}
|
||||
}
|
||||
// Flame Shield Usage
|
||||
|
|
@ -11304,7 +11299,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
K_DoSneaker(player, SNEAKERTYPE_SNEAKER);
|
||||
K_PlayBoostTaunt(player->mo);
|
||||
player->itemamount--;
|
||||
player->botvars.itemconfirm = 0;
|
||||
K_BotResetItemConfirm(player, false);
|
||||
}
|
||||
break;
|
||||
case KITEM_ROCKETSNEAKER:
|
||||
|
|
@ -11338,7 +11333,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
P_SetTarget(&prev->hnext, mo);
|
||||
prev = mo;
|
||||
}
|
||||
player->botvars.itemconfirm = 0;
|
||||
K_BotResetItemConfirm(player, false);
|
||||
}
|
||||
break;
|
||||
case KITEM_INVINCIBILITY:
|
||||
|
|
@ -11347,7 +11342,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
K_DoInvincibility(player, K_GetInvincibilityTime(player));
|
||||
K_PlayPowerGloatSound(player->mo);
|
||||
player->itemamount--;
|
||||
player->botvars.itemconfirm = 0;
|
||||
K_BotResetItemConfirm(player, false);
|
||||
}
|
||||
break;
|
||||
case KITEM_BANANA:
|
||||
|
|
@ -11378,7 +11373,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
P_SetTarget(&prev->hnext, mo);
|
||||
prev = mo;
|
||||
}
|
||||
player->botvars.itemconfirm = 0;
|
||||
K_BotResetItemConfirm(player, false);
|
||||
|
||||
}
|
||||
else if (ATTACK_IS_DOWN && (player->itemflags & IF_ITEMOUT)) // Banana x3 thrown
|
||||
|
|
@ -11387,7 +11382,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
K_ThrowKartItem(player, false, MT_BANANA, -1, 0);
|
||||
K_PlayAttackTaunt(player->mo);
|
||||
K_UpdateHnextList(player, false);
|
||||
player->botvars.itemconfirm = 0;
|
||||
K_BotResetItemConfirm(player, false);
|
||||
}
|
||||
break;
|
||||
case KITEM_EGGMAN:
|
||||
|
|
@ -11408,7 +11403,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
P_SetTarget(&mo->target, player->mo);
|
||||
P_SetTarget(&player->mo->hnext, mo);
|
||||
}
|
||||
player->botvars.itemconfirm = 0;
|
||||
K_BotResetItemConfirm(player, false);
|
||||
}
|
||||
break;
|
||||
case KITEM_ORBINAUT:
|
||||
|
|
@ -11443,7 +11438,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
P_SetTarget(&prev->hnext, mo);
|
||||
prev = mo;
|
||||
}
|
||||
player->botvars.itemconfirm = 0;
|
||||
K_BotResetItemConfirm(player, false);
|
||||
}
|
||||
else if (ATTACK_IS_DOWN && (player->itemflags & IF_ITEMOUT)) // Orbinaut x3 thrown
|
||||
{
|
||||
|
|
@ -11451,7 +11446,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
K_ThrowKartItem(player, true, MT_ORBINAUT, 1, 0);
|
||||
K_PlayAttackTaunt(player->mo);
|
||||
K_UpdateHnextList(player, false);
|
||||
player->botvars.itemconfirm = 0;
|
||||
K_BotResetItemConfirm(player, false);
|
||||
}
|
||||
break;
|
||||
case KITEM_JAWZ:
|
||||
|
|
@ -11485,7 +11480,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
P_SetTarget(&prev->hnext, mo);
|
||||
prev = mo;
|
||||
}
|
||||
player->botvars.itemconfirm = 0;
|
||||
K_BotResetItemConfirm(player, false);
|
||||
}
|
||||
else if (ATTACK_IS_DOWN && HOLDING_ITEM && (player->itemflags & IF_ITEMOUT)) // Jawz thrown
|
||||
{
|
||||
|
|
@ -11496,7 +11491,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
K_ThrowKartItem(player, true, MT_JAWZ_DUD, -1, 0);
|
||||
K_PlayAttackTaunt(player->mo);
|
||||
K_UpdateHnextList(player, false);
|
||||
player->botvars.itemconfirm = 0;
|
||||
K_BotResetItemConfirm(player, false);
|
||||
}
|
||||
break;
|
||||
case KITEM_MINE:
|
||||
|
|
@ -11515,7 +11510,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
P_SetTarget(&mo->target, player->mo);
|
||||
P_SetTarget(&player->mo->hnext, mo);
|
||||
}
|
||||
player->botvars.itemconfirm = 0;
|
||||
K_BotResetItemConfirm(player, false);
|
||||
}
|
||||
else if (ATTACK_IS_DOWN && (player->itemflags & IF_ITEMOUT))
|
||||
{
|
||||
|
|
@ -11524,7 +11519,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
K_PlayAttackTaunt(player->mo);
|
||||
player->itemflags &= ~IF_ITEMOUT;
|
||||
K_UpdateHnextList(player, true);
|
||||
player->botvars.itemconfirm = 0;
|
||||
K_BotResetItemConfirm(player, false);
|
||||
}
|
||||
break;
|
||||
case KITEM_LANDMINE:
|
||||
|
|
@ -11533,7 +11528,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
player->itemamount--;
|
||||
K_ThrowLandMine(player);
|
||||
K_PlayAttackTaunt(player->mo);
|
||||
player->botvars.itemconfirm = 0;
|
||||
K_BotResetItemConfirm(player, false);
|
||||
}
|
||||
break;
|
||||
case KITEM_BALLHOG:
|
||||
|
|
@ -11542,7 +11537,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
player->itemamount--;
|
||||
K_ThrowKartItem(player, true, MT_BALLHOG, 1, 0);
|
||||
K_PlayAttackTaunt(player->mo);
|
||||
player->botvars.itemconfirm = 0;
|
||||
K_BotResetItemConfirm(player, false);
|
||||
}
|
||||
break;
|
||||
case KITEM_SPB:
|
||||
|
|
@ -11551,7 +11546,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
player->itemamount--;
|
||||
K_ThrowKartItem(player, true, MT_SPB, 1, 0);
|
||||
K_PlayAttackTaunt(player->mo);
|
||||
player->botvars.itemconfirm = 0;
|
||||
K_BotResetItemConfirm(player, false);
|
||||
}
|
||||
break;
|
||||
case KITEM_GROW:
|
||||
|
|
@ -11595,7 +11590,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
S_StartSound(player->mo, sfx_kc5a);
|
||||
}
|
||||
|
||||
player->botvars.itemconfirm = 0;
|
||||
K_BotResetItemConfirm(player, false);
|
||||
}
|
||||
break;
|
||||
case KITEM_SHRINK:
|
||||
|
|
@ -11604,7 +11599,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
K_DoShrink(player);
|
||||
player->itemamount--;
|
||||
K_PlayPowerGloatSound(player->mo);
|
||||
player->botvars.itemconfirm = 0;
|
||||
K_BotResetItemConfirm(player, false);
|
||||
}
|
||||
break;
|
||||
case KITEM_THUNDERSHIELD:
|
||||
|
|
@ -11629,7 +11624,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
// ...:dumbestass:
|
||||
player->itemamount--;
|
||||
K_PlayAttackTaunt(player->mo);
|
||||
player->botvars.itemconfirm = 0;
|
||||
K_BotResetItemConfirm(player, false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -11719,7 +11714,7 @@ bubbledeflate:
|
|||
player->itemamount--;
|
||||
K_DoHyudoroSteal(player); // yes. yes they do.
|
||||
K_PlayAttackTaunt(player->mo);
|
||||
player->botvars.itemconfirm = 0;
|
||||
K_BotResetItemConfirm(player, false);
|
||||
}
|
||||
break;
|
||||
case KITEM_POGOSPRING:
|
||||
|
|
@ -11729,7 +11724,7 @@ bubbledeflate:
|
|||
K_PlayBoostTaunt(player->mo);
|
||||
K_DoPogoSpring(player->mo, 32<<FRACBITS, 2);
|
||||
player->pogospring = 1;
|
||||
player->botvars.itemconfirm = 0;
|
||||
K_BotResetItemConfirm(player, false);
|
||||
}
|
||||
break;
|
||||
case KITEM_SUPERRING:
|
||||
|
|
@ -11737,7 +11732,7 @@ bubbledeflate:
|
|||
{
|
||||
player->itemamount--;
|
||||
K_AwardScaledPlayerRings(player, ASR_SUPERRING);
|
||||
player->botvars.itemconfirm = 0;
|
||||
K_BotResetItemConfirm(player, false);
|
||||
}
|
||||
break;
|
||||
case KITEM_KITCHENSINK:
|
||||
|
|
@ -11756,7 +11751,7 @@ bubbledeflate:
|
|||
P_SetTarget(&mo->target, player->mo);
|
||||
P_SetTarget(&player->mo->hnext, mo);
|
||||
}
|
||||
player->botvars.itemconfirm = 0;
|
||||
K_BotResetItemConfirm(player, false);
|
||||
}
|
||||
else if (ATTACK_IS_DOWN && HOLDING_ITEM && (player->itemflags & IF_ITEMOUT)) // Sink thrown
|
||||
{
|
||||
|
|
@ -11765,7 +11760,7 @@ bubbledeflate:
|
|||
K_PlayAttackTaunt(player->mo);
|
||||
player->itemflags &= ~IF_ITEMOUT;
|
||||
K_UpdateHnextList(player, true);
|
||||
player->botvars.itemconfirm = 0;
|
||||
K_BotResetItemConfirm(player, false);
|
||||
}
|
||||
break;
|
||||
case KITEM_SAD:
|
||||
|
|
@ -11774,7 +11769,7 @@ bubbledeflate:
|
|||
{
|
||||
player->sadtimer = stealtime;
|
||||
player->itemamount--;
|
||||
player->botvars.itemconfirm = 0;
|
||||
K_BotResetItemConfirm(player, false);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
|
|||
46
src/k_kart.h
46
src/k_kart.h
|
|
@ -191,7 +191,7 @@ fixed_t K_GetKartGameSpeedScalar(SINT8 value);
|
|||
|
||||
extern consvar_t *KartItemCVars[NUMKARTRESULTS-1];
|
||||
|
||||
UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbumper, boolean spbrush);
|
||||
UINT8 K_FindUseodds(const player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbumper, boolean spbrush);
|
||||
INT32 K_FindLegacyUseodds(player_t *player, fixed_t mashed, INT32 pingame, INT32 bestbumper, boolean spbrush, boolean dontforcespb);
|
||||
fixed_t K_ItemOddsScale(UINT8 numPlayers, boolean spbrush);
|
||||
UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers, boolean spbrush);
|
||||
|
|
@ -227,7 +227,7 @@ void K_BattleAwardHit(player_t *player, player_t *victim, mobj_t *inflictor, UIN
|
|||
void K_SpinPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 type);
|
||||
void K_FlipPlayer(player_t *player, mobj_t *inflictor, mobj_t *source);
|
||||
INT32 K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source);
|
||||
boolean K_IsPlayerDamaged(player_t *player);
|
||||
boolean K_IsPlayerDamaged(const player_t *player);
|
||||
void K_HandleBumperChanges(player_t *player, UINT8 prevBumpers);
|
||||
void K_DestroyBumpers(player_t *player, UINT8 amount);
|
||||
void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount);
|
||||
|
|
@ -263,13 +263,13 @@ void K_RemoveBubbleHealth(player_t *player, INT16 sub);
|
|||
void K_RepairOrbitChain(mobj_t *orbit);
|
||||
void K_CalculateBananaSlope(mobj_t *mobj, fixed_t x, fixed_t y, fixed_t z, fixed_t radius, fixed_t height, boolean flip, boolean player);
|
||||
player_t *K_FindJawzTarget(mobj_t *actor, player_t *source);
|
||||
INT32 K_GetKartRingPower(player_t *player, boolean boosted);
|
||||
INT32 K_GetKartRingPower(const player_t *player, boolean boosted);
|
||||
size_t K_NextRespawnWaypointIndex(waypoint_t *waypoint);
|
||||
boolean K_CheckPlayersRespawnColliding(INT32 playernum, fixed_t x, fixed_t y);
|
||||
void K_SetRespawnAtNextWaypoint(player_t * player);
|
||||
INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue);
|
||||
INT32 K_GetKartDriftSparkValue(player_t *player);
|
||||
INT32 K_GetKartDriftSparkValueForStage(player_t *player, UINT8 stage);
|
||||
INT16 K_GetKartTurnValue(const player_t *player, INT16 turnvalue);
|
||||
INT32 K_GetKartDriftSparkValue(const player_t *player);
|
||||
INT32 K_GetKartDriftSparkValueForStage(const player_t *player, UINT8 stage);
|
||||
void K_SpawnDriftBoostExplosion(player_t *player, int stage);
|
||||
void K_SpawnDriftElectricSparks(player_t *player);
|
||||
INT32 K_GetDriftAngleOffset(player_t *player);
|
||||
|
|
@ -284,31 +284,31 @@ void K_DropKitchenSink(player_t *player);
|
|||
void K_StripItems(player_t *player);
|
||||
void K_StripOther(player_t *player);
|
||||
void K_MomentumToFacing(player_t *player);
|
||||
boolean K_ApplyOffroad(player_t *player);
|
||||
fixed_t K_PlayerTripwireSpeedThreshold(player_t *player);
|
||||
tripwirepass_t K_TripwirePassConditions(player_t *player);
|
||||
boolean K_TripwirePass(player_t *player);
|
||||
boolean K_ApplyOffroad(const player_t *player);
|
||||
fixed_t K_PlayerTripwireSpeedThreshold(const player_t *player);
|
||||
tripwirepass_t K_TripwirePassConditions(const player_t *player);
|
||||
boolean K_TripwirePass(const player_t *player);
|
||||
boolean K_WaterRun(mobj_t *mobj);
|
||||
void K_SpawnWaterTrail(mobj_t *mobj);
|
||||
boolean K_ItemMobjAllowedtoWaterRun(mobj_t *item);
|
||||
void K_SetTireGrease(player_t *player, tic_t tics);
|
||||
boolean K_SlopeResistance(player_t *player);
|
||||
boolean K_SlopeResistance(const player_t *player);
|
||||
void K_SquishPlayer(player_t *player, mobj_t *inflictor, mobj_t *source);
|
||||
void K_ApplyTripWire(player_t *player, tripwirestate_t state);
|
||||
fixed_t K_GetKartSpeedFromStat(UINT8 kartspeed, boolean karmabomb);
|
||||
fixed_t K_GetKartSpeed(player_t *player, boolean doboostpower, boolean dorubberbanding);
|
||||
fixed_t K_GetKartAccel(player_t *player);
|
||||
UINT16 K_GetKartFlashing(player_t *player);
|
||||
boolean K_PlayerShrinkCheat(player_t *player);
|
||||
fixed_t K_GetKartSpeed(const player_t *player, boolean doboostpower, boolean dorubberbanding);
|
||||
fixed_t K_GetKartAccel(const player_t *player);
|
||||
UINT16 K_GetKartFlashing(const player_t *player);
|
||||
boolean K_PlayerShrinkCheat(const player_t *player);
|
||||
void K_UpdateShrinkCheat(player_t *player);
|
||||
boolean K_KartKickstart(player_t *player);
|
||||
UINT16 K_GetKartButtons(player_t *player);
|
||||
SINT8 K_GetForwardMove(player_t *player);
|
||||
SINT8 K_GetSideMove(player_t *player);
|
||||
fixed_t K_GetNewSpeed(player_t *player);
|
||||
fixed_t K_3dKartMovement(player_t *player, boolean onground, SINT8 fowardmove);
|
||||
SINT8 K_Sliptiding(player_t *player);
|
||||
fixed_t K_PlayerBaseFriction(player_t *player, fixed_t original);
|
||||
boolean K_KartKickstart(const player_t *player);
|
||||
UINT16 K_GetKartButtons(const player_t *player);
|
||||
SINT8 K_GetForwardMove(const player_t *player);
|
||||
SINT8 K_GetSideMove(const player_t *player);
|
||||
fixed_t K_GetNewSpeed(const player_t *player);
|
||||
fixed_t K_3dKartMovement(const player_t *player, boolean onground, SINT8 fowardmove);
|
||||
SINT8 K_Sliptiding(const player_t *player);
|
||||
fixed_t K_PlayerBaseFriction(const player_t *player, fixed_t original);
|
||||
void K_MoveKartPlayer(player_t *player, boolean onground);
|
||||
void K_CheckSpectateStatus(boolean considermapreset);
|
||||
UINT8 K_GetInvincibilityItemFrame(void);
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@
|
|||
#include "p_spec.h" // P_StartQuake
|
||||
#include "i_system.h" // I_GetPreciseTime, I_GetPrecisePrecision
|
||||
#include "v_video.h"
|
||||
#include "k_terrain.h"
|
||||
#include "k_bot.h"
|
||||
|
||||
#include "lua_script.h"
|
||||
#include "lua_libs.h"
|
||||
|
|
@ -45,8 +47,6 @@
|
|||
#include "taglist.h" // P_FindSpecialLineFromTag
|
||||
#include "lua_hook.h" // hook_cmd_running errors
|
||||
|
||||
#include "k_terrain.h"
|
||||
|
||||
#define NOHUD if (hud_running)\
|
||||
return luaL_error(L, "HUD rendering code should not call this function!");\
|
||||
else if (hook_cmd_running)\
|
||||
|
|
@ -230,15 +230,21 @@ static const struct {
|
|||
{META_LUABANKS, "luabanks[]"},
|
||||
|
||||
{META_ACTIVATOR, "activator_t"},
|
||||
|
||||
|
||||
{META_FOLLOWER, "follower_t"},
|
||||
|
||||
{META_SONICLOOPVARS, "sonicloopvars_t"},
|
||||
{META_SONICLOOPCAMVARS, "sonicloopcamvars_t"},
|
||||
|
||||
{META_BOTVARS, "botvars_t"},
|
||||
{META_BOTCONTROLLER, "botcontroller_t"},
|
||||
{META_BOTDATA, "botdata_t"},
|
||||
|
||||
{META_SPLASH, "t_splash_t"},
|
||||
{META_FOOTSTEP, "t_footstep_t"},
|
||||
{META_OVERLAY, "t_overlay_t"},
|
||||
{META_TERRAIN, "terrain_t"},
|
||||
|
||||
{META_SONICLOOPVARS, "sonicloopvars_t"},
|
||||
{META_SONICLOOPCAMVARS, "sonicloopcamvars_t"},
|
||||
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
@ -2484,7 +2490,6 @@ static int lib_rSetPlayerSkin(lua_State *L)
|
|||
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
||||
INT32 i = -1, j = -1;
|
||||
NOHUD
|
||||
INLEVEL
|
||||
if (!player)
|
||||
return LUA_ErrInvalid(L, "player_t");
|
||||
|
||||
|
|
@ -4344,6 +4349,148 @@ static int lib_kAwardScaledPlayerRings(lua_State *L)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lib_kPlayerUsesBotMovement(lua_State *L)
|
||||
{
|
||||
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
||||
INLEVEL
|
||||
if (!player)
|
||||
return LUA_ErrInvalid(L, "player_t");
|
||||
|
||||
lua_pushboolean(L, K_PlayerUsesBotMovement(player));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lib_kBotCanTakeCut(lua_State *L)
|
||||
{
|
||||
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
||||
INLEVEL
|
||||
if (!player)
|
||||
return LUA_ErrInvalid(L, "player_t");
|
||||
|
||||
lua_pushboolean(L, K_BotCanTakeCut(player));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lib_kGetBotController(lua_State *L)
|
||||
{
|
||||
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
|
||||
INLEVEL
|
||||
if (!mobj)
|
||||
return LUA_ErrInvalid(L, "mobj_t");
|
||||
|
||||
botcontroller_t *botController = K_GetBotController(mobj);
|
||||
if (botController != NULL)
|
||||
LUA_PushUserdata(L, botController, META_BOTCONTROLLER);
|
||||
else
|
||||
lua_pushnil(L);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lib_kBotMapModifier(lua_State *L)
|
||||
{
|
||||
INLEVEL
|
||||
lua_pushfixed(L, K_BotMapModifier());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lib_kBotRubberband(lua_State *L)
|
||||
{
|
||||
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
||||
INLEVEL
|
||||
if (!player)
|
||||
return LUA_ErrInvalid(L, "player_t");
|
||||
|
||||
lua_pushfixed(L, K_BotRubberband(player));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lib_kUpdateRubberband(lua_State *L)
|
||||
{
|
||||
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
||||
INLEVEL
|
||||
if (!player)
|
||||
return LUA_ErrInvalid(L, "player_t");
|
||||
|
||||
lua_pushfixed(L, K_UpdateRubberband(player));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lib_kDistanceOfLineFromPoint(lua_State *L)
|
||||
{
|
||||
fixed_t v1x = luaL_checkfixed(L, 1);
|
||||
fixed_t v1y = luaL_checkfixed(L, 2);
|
||||
fixed_t v2x = luaL_checkfixed(L, 3);
|
||||
fixed_t v2y = luaL_checkfixed(L, 4);
|
||||
fixed_t cx = luaL_checkfixed(L, 5);
|
||||
fixed_t cy = luaL_checkfixed(L, 6);
|
||||
lua_pushfixed(L, K_DistanceOfLineFromPoint(v1x, v1y, v2x, v2y, cx, cy));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lib_kAddBot(lua_State *L)
|
||||
{
|
||||
INT32 skinid = -1;
|
||||
UINT8 difficulty = luaL_checkinteger(L, 2);
|
||||
botStyle_e style = luaL_checkinteger(L, 3);
|
||||
UINT8 newplayernum = 0;
|
||||
|
||||
// Copypaste of libd_getSprite2Patch, but fails loudly on each fail state instead.
|
||||
// get skin first!
|
||||
if (lua_isnumber(L, 1)) // find skin by number
|
||||
{
|
||||
skinid = lua_tonumber(L, 1);
|
||||
if (skinid < 0 || skinid >= numskins)
|
||||
return luaL_error(L, "skin number %d out of range (0 - %d)", skinid, numskins-1);
|
||||
}
|
||||
else // find skin by name
|
||||
{
|
||||
const char *name = luaL_checkstring(L, 1);
|
||||
skinid = R_SkinAvailable(name);
|
||||
if (skinid == -1)
|
||||
return luaL_error(L, "could not find skin %s by name", name);
|
||||
}
|
||||
|
||||
INLEVEL
|
||||
|
||||
boolean success = K_AddBot(skinid, difficulty, style, &newplayernum);
|
||||
lua_pushboolean(L, success);
|
||||
if (success)
|
||||
LUA_PushUserdata(L, &players[newplayernum - 1], META_PLAYER);
|
||||
else
|
||||
lua_pushnil(L);
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int lib_kSetNameForBot(lua_State *L)
|
||||
{
|
||||
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
||||
const char *realname = luaL_checkstring(L, 2);
|
||||
if (!player)
|
||||
return LUA_ErrInvalid(L, "player_t");
|
||||
if (!player->bot)
|
||||
return luaL_error(L, "You may only change bot names.");
|
||||
|
||||
K_SetNameForBot(player-players, realname);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lib_kRemoveBot(lua_State *L)
|
||||
{
|
||||
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
||||
INLEVEL
|
||||
if (!player)
|
||||
return LUA_ErrInvalid(L, "player_t");
|
||||
if (!player->bot)
|
||||
return luaL_error(L, "You may only remove bots.");
|
||||
|
||||
CL_RemovePlayer(player-players, KR_LEAVE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lib_kNextRespawnWaypointIndex(lua_State *L)
|
||||
{
|
||||
waypoint_t *waypoint = *((waypoint_t **)luaL_checkudata(L, 1, META_WAYPOINT));
|
||||
|
|
@ -5141,6 +5288,19 @@ static luaL_Reg lib[] = {
|
|||
// I_System
|
||||
{"I_GetPreciseTime",lib_iGetPreciseTime},
|
||||
|
||||
// k_bot
|
||||
{"K_PlayerUsesBotMovement", lib_kPlayerUsesBotMovement},
|
||||
{"K_BotCanTakeCut", lib_kBotCanTakeCut},
|
||||
{"K_GetBotController", lib_kGetBotController},
|
||||
{"K_BotMapModifier", lib_kBotMapModifier},
|
||||
{"K_BotRubberband", lib_kBotRubberband},
|
||||
{"K_UpdateRubberband", lib_kUpdateRubberband},
|
||||
{"K_DistanceOfLineFromPoint", lib_kDistanceOfLineFromPoint},
|
||||
{"K_AddBot", lib_kAddBot},
|
||||
{"K_SetNameForBot", lib_kSetNameForBot},
|
||||
// Lua-only function to allow safely removing bots.
|
||||
{"K_RemoveBot", lib_kRemoveBot},
|
||||
|
||||
// k_terrain
|
||||
{"K_AffectingTerrainActive", lib_kAffectingTerrainActive},
|
||||
{"K_GetDefaultTerrain", lib_kGetDefaultTerrain},
|
||||
|
|
|
|||
398
src/lua_botvarslib.c
Normal file
398
src/lua_botvarslib.c
Normal file
|
|
@ -0,0 +1,398 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2024 by Kart Krew.
|
||||
// Copyright (C) 2020 by Sonic Team Junior.
|
||||
// Copyright (C) 2016 by John "JTE" Muniz.
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file lua_botvarslib.c
|
||||
/// \brief player botvars structure library for Lua scripting
|
||||
|
||||
#include "doomdef.h"
|
||||
#include "fastcmp.h"
|
||||
|
||||
#include "lua_script.h"
|
||||
#include "lua_libs.h"
|
||||
#include "k_bot.h"
|
||||
|
||||
enum botvars {
|
||||
botvars_valid = 0,
|
||||
botvars_style,
|
||||
botvars_difficulty,
|
||||
botvars_diffincrease,
|
||||
botvars_rival,
|
||||
botvars_rubberband,
|
||||
};
|
||||
|
||||
static const char *const botvars_opt[] = {
|
||||
"valid",
|
||||
"style",
|
||||
"difficulty",
|
||||
"diffincrease",
|
||||
"rival",
|
||||
"rubberband",
|
||||
NULL
|
||||
};
|
||||
|
||||
#define UNIMPLEMENTED luaL_error(L, LUA_QL("botvars_t") " field " LUA_QS " is not implemented for Lua and cannot be accessed.", follower_opt[field])
|
||||
|
||||
static int botvars_get(lua_State *L)
|
||||
{
|
||||
botvars_t *botvars = *((botvars_t **)luaL_checkudata(L, 1, META_BOTVARS));
|
||||
enum botvars field = luaL_checkoption(L, 2, NULL, botvars_opt);
|
||||
|
||||
// This is a property that always exists in a player.
|
||||
I_Assert(botvars != NULL);
|
||||
|
||||
switch (field)
|
||||
{
|
||||
case botvars_valid:
|
||||
lua_pushboolean(L, botvars != NULL);
|
||||
break;
|
||||
case botvars_style:
|
||||
lua_pushinteger(L, botvars->style);
|
||||
break;
|
||||
case botvars_difficulty:
|
||||
lua_pushinteger(L, botvars->difficulty);
|
||||
break;
|
||||
case botvars_diffincrease:
|
||||
lua_pushinteger(L, botvars->diffincrease);
|
||||
break;
|
||||
case botvars_rival:
|
||||
lua_pushboolean(L, botvars->rival);
|
||||
break;
|
||||
case botvars_rubberband:
|
||||
lua_pushfixed(L, botvars->rubberband);
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define NOSET luaL_error(L, LUA_QL("botvars_t") " field " LUA_QS " should not be set directly.", botvars_opt[field])
|
||||
|
||||
static int botvars_set(lua_State *L)
|
||||
{
|
||||
botvars_t *botvars = *((botvars_t **)luaL_checkudata(L, 1, META_BOTVARS));
|
||||
enum botvars field = luaL_checkoption(L, 2, botvars_opt[0], botvars_opt);
|
||||
|
||||
// This is a property that always exists in a player.
|
||||
I_Assert(botvars != NULL);
|
||||
|
||||
INLEVEL
|
||||
|
||||
switch(field)
|
||||
{
|
||||
case botvars_valid:
|
||||
return NOSET;
|
||||
case botvars_style:
|
||||
botvars->style = luaL_checkinteger(L, 3);
|
||||
break;
|
||||
case botvars_difficulty:
|
||||
botvars->difficulty = luaL_checkinteger(L, 3);
|
||||
break;
|
||||
case botvars_diffincrease:
|
||||
botvars->diffincrease = luaL_checkinteger(L, 3);
|
||||
break;
|
||||
case botvars_rival:
|
||||
botvars->rival = luaL_checkboolean(L, 3);
|
||||
break;
|
||||
case botvars_rubberband:
|
||||
botvars->rubberband = luaL_checkfixed(L, 3);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#undef NOSET
|
||||
|
||||
enum botdata {
|
||||
botdata_valid,
|
||||
botdata_itemdelay,
|
||||
botdata_itemconfirm,
|
||||
botdata_turnconfirm,
|
||||
botdata_respawnconfirm,
|
||||
botdata_driftstate,
|
||||
botdata_driftturn,
|
||||
botdata_drifttime,
|
||||
botdata_driftlockout,
|
||||
botdata_driftmaxdist,
|
||||
botdata_driftpowerdiv,
|
||||
botdata_driftstatedelay,
|
||||
botdata_driftskill,
|
||||
botdata_acceldown,
|
||||
botdata_brakedown,
|
||||
botdata_driftdown,
|
||||
botdata_itemdown,
|
||||
botdata_dolookback,
|
||||
botdata_itemwasdown,
|
||||
botdata_itemthrow,
|
||||
botdata_turnamt,
|
||||
};
|
||||
|
||||
static const char *const botdata_opt[] = {
|
||||
"valid",
|
||||
"itemdelay",
|
||||
"itemconfirm",
|
||||
"turnconfirm",
|
||||
"respawnconfirm",
|
||||
"driftstate",
|
||||
"driftturn",
|
||||
"drifttime",
|
||||
"driftlockout",
|
||||
"driftmaxdist",
|
||||
"driftpowerdiv",
|
||||
"driftstatedelay",
|
||||
"driftskill",
|
||||
"acceldown",
|
||||
"brakedown",
|
||||
"driftdown",
|
||||
"itemdown",
|
||||
"dolookback",
|
||||
"itemwasdown",
|
||||
"itemthrow",
|
||||
"turnamt",
|
||||
NULL
|
||||
};
|
||||
|
||||
static int botdata_get(lua_State *L)
|
||||
{
|
||||
botdata_t *botdata = *((botdata_t **)luaL_checkudata(L, 1, META_BOTDATA));
|
||||
enum botdata field = luaL_checkoption(L, 2, NULL, botdata_opt);
|
||||
|
||||
// it's a static array... i think...
|
||||
I_Assert(botdata != NULL);
|
||||
|
||||
switch (field)
|
||||
{
|
||||
case botdata_valid:
|
||||
lua_pushboolean(L, botdata != NULL);
|
||||
return 1;
|
||||
case botdata_itemdelay:
|
||||
lua_pushinteger(L, botdata->itemdelay);
|
||||
return 1;
|
||||
case botdata_itemconfirm:
|
||||
lua_pushinteger(L, botdata->itemconfirm);
|
||||
return 1;
|
||||
case botdata_turnconfirm:
|
||||
lua_pushinteger(L, botdata->turnconfirm);
|
||||
return 1;
|
||||
case botdata_respawnconfirm:
|
||||
lua_pushinteger(L, botdata->respawnconfirm);
|
||||
return 1;
|
||||
case botdata_driftstate:
|
||||
lua_pushinteger(L, botdata->driftstate);
|
||||
return 1;
|
||||
case botdata_driftturn:
|
||||
lua_pushinteger(L, botdata->driftturn);
|
||||
return 1;
|
||||
case botdata_drifttime:
|
||||
lua_pushinteger(L, botdata->drifttime);
|
||||
return 1;
|
||||
case botdata_driftlockout:
|
||||
lua_pushinteger(L, botdata->driftlockout);
|
||||
return 1;
|
||||
case botdata_driftmaxdist:
|
||||
lua_pushinteger(L, botdata->driftmaxdist);
|
||||
return 1;
|
||||
case botdata_driftpowerdiv:
|
||||
lua_pushinteger(L, botdata->driftpowerdiv);
|
||||
return 1;
|
||||
case botdata_driftstatedelay:
|
||||
lua_pushinteger(L, botdata->driftstatedelay);
|
||||
return 1;
|
||||
case botdata_driftskill:
|
||||
lua_pushfixed(L, botdata->driftskill);
|
||||
return 1;
|
||||
case botdata_acceldown:
|
||||
lua_pushboolean(L, botdata->acceldown);
|
||||
return 1;
|
||||
case botdata_brakedown:
|
||||
lua_pushboolean(L, botdata->brakedown);
|
||||
return 1;
|
||||
case botdata_driftdown:
|
||||
lua_pushboolean(L, botdata->driftdown);
|
||||
return 1;
|
||||
case botdata_itemdown:
|
||||
lua_pushboolean(L, botdata->itemdown);
|
||||
return 1;
|
||||
case botdata_dolookback:
|
||||
lua_pushboolean(L, botdata->dolookback);
|
||||
return 1;
|
||||
case botdata_itemwasdown:
|
||||
lua_pushboolean(L, botdata->itemwasdown);
|
||||
return 1;
|
||||
case botdata_itemthrow:
|
||||
lua_pushinteger(L, botdata->itemthrow);
|
||||
return 1;
|
||||
case botdata_turnamt:
|
||||
lua_pushinteger(L, botdata->turnamt);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
#define NOSET luaL_error(L, LUA_QL("botdata_t") " field " LUA_QS " should not be set directly.", botdata_opt[field])
|
||||
|
||||
static int botdata_set(lua_State *L)
|
||||
{
|
||||
botdata_t *botdata = *((botdata_t **)luaL_checkudata(L, 1, META_BOTDATA));
|
||||
enum botdata field = luaL_checkoption(L, 2, NULL, botdata_opt);
|
||||
|
||||
I_Assert(botdata != NULL);
|
||||
|
||||
switch (field)
|
||||
{
|
||||
case botdata_valid:
|
||||
return NOSET;
|
||||
case botdata_itemdelay:
|
||||
botdata->itemdelay = luaL_checkinteger(L, 3);
|
||||
return 0;
|
||||
case botdata_itemconfirm:
|
||||
botdata->itemconfirm = luaL_checkinteger(L, 3);
|
||||
return 0;
|
||||
case botdata_turnconfirm:
|
||||
botdata->turnconfirm = luaL_checkinteger(L, 3);
|
||||
return 0;
|
||||
case botdata_respawnconfirm:
|
||||
botdata->respawnconfirm = luaL_checkinteger(L, 3);
|
||||
return 0;
|
||||
case botdata_driftstate:
|
||||
botdata->driftstate = luaL_checkinteger(L, 3);
|
||||
return 0;
|
||||
case botdata_driftturn:
|
||||
botdata->driftturn = luaL_checkinteger(L, 3);
|
||||
return 0;
|
||||
case botdata_drifttime:
|
||||
botdata->drifttime = luaL_checkinteger(L, 3);
|
||||
return 0;
|
||||
case botdata_driftlockout:
|
||||
botdata->driftlockout = luaL_checkinteger(L, 3);
|
||||
return 0;
|
||||
case botdata_driftmaxdist:
|
||||
botdata->driftmaxdist = luaL_checkinteger(L, 3);
|
||||
return 0;
|
||||
case botdata_driftpowerdiv:
|
||||
botdata->driftpowerdiv = luaL_checkinteger(L, 3);
|
||||
return 0;
|
||||
case botdata_driftstatedelay:
|
||||
botdata->driftstatedelay = luaL_checkinteger(L, 3);
|
||||
return 0;
|
||||
case botdata_driftskill:
|
||||
botdata->driftskill = luaL_checkfixed(L, 3);
|
||||
return 0;
|
||||
case botdata_acceldown:
|
||||
botdata->acceldown = luaL_checkboolean(L, 3);
|
||||
return 0;
|
||||
case botdata_brakedown:
|
||||
botdata->brakedown = luaL_checkboolean(L, 3);
|
||||
return 0;
|
||||
case botdata_driftdown:
|
||||
botdata->driftdown = luaL_checkboolean(L, 3);
|
||||
return 0;
|
||||
case botdata_itemdown:
|
||||
botdata->itemdown = luaL_checkboolean(L, 3);
|
||||
return 0;
|
||||
case botdata_dolookback:
|
||||
botdata->dolookback = luaL_checkboolean(L, 3);
|
||||
return 0;
|
||||
case botdata_itemwasdown:
|
||||
botdata->itemwasdown = luaL_checkboolean(L, 3);
|
||||
return 0;
|
||||
case botdata_itemthrow:
|
||||
botdata->itemthrow = luaL_checkinteger(L, 3);
|
||||
return 0;
|
||||
case botdata_turnamt:
|
||||
botdata->turnamt = luaL_checkinteger(L, 3);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#undef NOSET
|
||||
|
||||
static int lib_iterateBotData(lua_State *L)
|
||||
{
|
||||
INT32 i;
|
||||
|
||||
if (lua_gettop(L) < 2)
|
||||
{
|
||||
lua_pushcfunction(L, lib_iterateBotData);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lua_settop(L, 2);
|
||||
lua_remove(L, 1); // state is unused.
|
||||
|
||||
if (!lua_isnil(L, 1))
|
||||
i = (INT32)(*((botdata_t **)luaL_checkudata(L, 1, META_BOTDATA)) - K_GetBotData(0)) + 1;
|
||||
else
|
||||
i = 0;
|
||||
|
||||
if (i < MAXPLAYERS)
|
||||
{
|
||||
LUA_PushUserdata(L, K_GetBotData(i), META_BOTDATA);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lib_getBotData(lua_State *L)
|
||||
{
|
||||
INT32 i;
|
||||
|
||||
if (lua_type(L, 2) == LUA_TNUMBER)
|
||||
{
|
||||
i = luaL_checkinteger(L, 2);
|
||||
if (i < 0 || i >= MAXPLAYERS)
|
||||
return luaL_error(L, "botdata[] index %d out of range (0 - %d)", i, MAXPLAYERS-1);
|
||||
LUA_PushUserdata(L, K_GetBotData(i), META_BOTDATA);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (fastcmp(luaL_checkstring(L, 2), "iterate"))
|
||||
{
|
||||
lua_pushcfunction(L, lib_iterateBotData);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lib_numBotData(lua_State *L)
|
||||
{
|
||||
lua_pushinteger(L, MAXPLAYERS);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LUA_BotVarsLib(lua_State *L)
|
||||
{
|
||||
luaL_newmetatable(L, META_BOTVARS);
|
||||
lua_pushcfunction(L, botvars_get);
|
||||
lua_setfield(L, -2, "__index");
|
||||
|
||||
lua_pushcfunction(L, botvars_set);
|
||||
lua_setfield(L, -2, "__newindex");
|
||||
lua_pop(L,1);
|
||||
|
||||
luaL_newmetatable(L, META_BOTDATA);
|
||||
lua_pushcfunction(L, botdata_get);
|
||||
lua_setfield(L, -2, "__index");
|
||||
|
||||
lua_pushcfunction(L, botdata_set);
|
||||
lua_setfield(L, -2, "__newindex");
|
||||
lua_pop(L,1);
|
||||
|
||||
lua_newuserdata(L, 0);
|
||||
lua_createtable(L, 0, 2);
|
||||
lua_pushcfunction(L, lib_getBotData);
|
||||
lua_setfield(L, -2, "__index");
|
||||
|
||||
lua_pushcfunction(L, lib_numBotData);
|
||||
lua_setfield(L, -2, "__len");
|
||||
lua_setmetatable(L, -2);
|
||||
lua_setglobal(L, "botdata");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -82,6 +82,8 @@ automatically.
|
|||
X (PlayerCmd),/* building the player's ticcmd struct */\
|
||||
X (MusicChange),\
|
||||
X (VoteThinker),/* Y_VoteTicker */\
|
||||
X (PlayerUsesBotMovement),/* K_PlayerUsesBotMovement */\
|
||||
X (BotJoin),\
|
||||
X (GPRankPoints),/* K_CalculateGPRankPoints */\
|
||||
X (AddonLoaded),\
|
||||
|
||||
|
|
@ -136,6 +138,7 @@ void LUA_HookInt(INT32 integer, int hook);
|
|||
void LUA_HookGamemap(int hook);
|
||||
void LUA_HookBool(boolean value, int hook);
|
||||
int LUA_HookPlayer(player_t *, int hook);
|
||||
int LUA_HookPlayerForceResults(player_t *, int hook);
|
||||
int LUA_HookTiccmd(player_t *, ticcmd_t *, int hook);
|
||||
int LUA_HookKey(event_t *event, int hook); // Hooks for key events
|
||||
|
||||
|
|
|
|||
|
|
@ -676,6 +676,17 @@ int LUA_HookPlayer(player_t *player, int hook_type)
|
|||
return hook.status;
|
||||
}
|
||||
|
||||
int LUA_HookPlayerForceResults(player_t *player, int hook_type)
|
||||
{
|
||||
Hook_State hook;
|
||||
if (prepare_hook(&hook, 0, hook_type))
|
||||
{
|
||||
LUA_PushUserdata(gL, player, META_PLAYER);
|
||||
call_hooks(&hook, 1, res_force);
|
||||
}
|
||||
return hook.status;
|
||||
}
|
||||
|
||||
int LUA_HookTiccmd(player_t *player, ticcmd_t *cmd, int hook_type)
|
||||
{
|
||||
Hook_State hook;
|
||||
|
|
|
|||
|
|
@ -107,14 +107,18 @@ extern lua_State *gL;
|
|||
#define META_FOLLOWER "FOLLOWER_T*"
|
||||
#define META_WAYPOINT "WAYPOINT_T*"
|
||||
|
||||
#define META_SONICLOOPVARS "SONICLOOPVARS_T*"
|
||||
#define META_SONICLOOPCAMVARS "SONICLOOPCAMVARS_T*"
|
||||
|
||||
#define META_BOTVARS "BOTVARS_T*"
|
||||
#define META_BOTCONTROLLER "BOTCONTROLLER_T*"
|
||||
#define META_BOTDATA "BOTDATA_T*"
|
||||
|
||||
#define META_SPLASH "T_SPLASH_T*"
|
||||
#define META_FOOTSTEP "T_FOOTSTEP_T*"
|
||||
#define META_OVERLAY "T_OVERLAY_T*"
|
||||
#define META_TERRAIN "TERRAIN_T*"
|
||||
|
||||
#define META_SONICLOOPVARS "SONICLOOPVARS_T*"
|
||||
#define META_SONICLOOPCAMVARS "SONICLOOPCAMVARS_T*"
|
||||
|
||||
boolean luaL_checkboolean(lua_State *L, int narg);
|
||||
|
||||
int LUA_EnumLib(lua_State *L);
|
||||
|
|
@ -134,6 +138,7 @@ int LUA_PolyObjLib(lua_State *L);
|
|||
int LUA_BlockmapLib(lua_State *L);
|
||||
int LUA_HudLib(lua_State *L);
|
||||
int LUA_FollowerLib(lua_State *L);
|
||||
int LUA_BotVarsLib(lua_State *L);
|
||||
int LUA_TerrainLib(lua_State *L);
|
||||
int LUA_WaypointLib(lua_State *L);
|
||||
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ enum sector_e {
|
|||
sector_triggerer,
|
||||
sector_friction,
|
||||
sector_gravity,
|
||||
sector_botcontroller,
|
||||
sector_action,
|
||||
sector_args,
|
||||
sector_stringargs,
|
||||
|
|
@ -91,6 +92,7 @@ static const char *const sector_opt[] = {
|
|||
"triggerer",
|
||||
"friction",
|
||||
"gravity",
|
||||
"botcontroller",
|
||||
"action",
|
||||
"args"
|
||||
"stringargs",
|
||||
|
|
@ -409,6 +411,20 @@ static const char *const activator_opt[] = {
|
|||
"sector",
|
||||
"po",
|
||||
NULL};
|
||||
|
||||
enum botcontroller_e {
|
||||
botcontroller_valid = 0,
|
||||
//botcontroller_trick,
|
||||
botcontroller_flags,
|
||||
botcontroller_forceangle,
|
||||
};
|
||||
|
||||
static const char *const botcontroller_opt[] = {
|
||||
"valid",
|
||||
//"trick",
|
||||
"flags",
|
||||
"forceangle",
|
||||
NULL};
|
||||
|
||||
static const char *const array_opt[] ={"iterate",NULL};
|
||||
static const char *const valid_opt[] ={"valid",NULL};
|
||||
|
|
@ -767,6 +783,9 @@ static int sector_get(lua_State *L)
|
|||
case sector_gravity: // gravity
|
||||
lua_pushfixed(L, sector->gravity);
|
||||
return 1;
|
||||
case sector_botcontroller: // botController
|
||||
LUA_PushUserdata(L, §or->botController, META_BOTCONTROLLER);
|
||||
return 1;
|
||||
case sector_action: // action
|
||||
lua_pushinteger(L, (INT16)sector->action);
|
||||
return 1;
|
||||
|
|
@ -2690,6 +2709,49 @@ static int activator_get(lua_State *L)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/////////////////////
|
||||
// botcontroller_t //
|
||||
/////////////////////
|
||||
|
||||
static int botcontroller_get(lua_State *L)
|
||||
{
|
||||
botcontroller_t *botcontroller = *((botcontroller_t **)luaL_checkudata(L, 1, META_BOTCONTROLLER));
|
||||
enum botcontroller_e field = luaL_checkoption(L, 2, botcontroller_opt[0], botcontroller_opt);
|
||||
|
||||
if (!botcontroller)
|
||||
{
|
||||
if (field == botcontroller_valid) {
|
||||
lua_pushboolean(L, false);
|
||||
return 1;
|
||||
}
|
||||
return luaL_error(L, "accessed botcontroller_t doesn't exist anymore.");
|
||||
}
|
||||
|
||||
switch (field)
|
||||
{
|
||||
case botcontroller_valid:
|
||||
lua_pushboolean(L, true);
|
||||
return 1;
|
||||
|
||||
//case botcontroller_trick:
|
||||
//lua_pushinteger(L, botcontroller->trick);
|
||||
//return 1;
|
||||
|
||||
case botcontroller_flags:
|
||||
lua_pushinteger(L, botcontroller->flags);
|
||||
return 1;
|
||||
|
||||
case botcontroller_forceangle:
|
||||
lua_pushangle(L, botcontroller->forceAngle);
|
||||
return 1;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LUA_MapLib(lua_State *L)
|
||||
{
|
||||
luaL_newmetatable(L, META_SECTORLINES);
|
||||
|
|
@ -2856,6 +2918,12 @@ int LUA_MapLib(lua_State *L)
|
|||
lua_pushcfunction(L, activator_get);
|
||||
lua_setfield(L, -2, "__index");
|
||||
lua_pop(L, 1);
|
||||
|
||||
luaL_newmetatable(L, META_BOTCONTROLLER);
|
||||
lua_pushcfunction(L, botcontroller_get);
|
||||
lua_setfield(L, -2, "__index");
|
||||
lua_pop(L, 1);
|
||||
|
||||
|
||||
LUA_PushTaggableObjectArray(L, "sectors",
|
||||
lib_iterateSectors,
|
||||
|
|
|
|||
|
|
@ -345,6 +345,7 @@ enum player_e
|
|||
player_spectator,
|
||||
player_spectatewait,
|
||||
player_bot,
|
||||
player_botvars,
|
||||
player_jointime,
|
||||
player_spectatorreentry,
|
||||
player_grieftime,
|
||||
|
|
@ -539,6 +540,7 @@ static const char *const player_opt[] = {
|
|||
"spectator",
|
||||
"spectatewait",
|
||||
"bot",
|
||||
"botvars",
|
||||
"jointime",
|
||||
"spectatorreentry",
|
||||
"grieftime",
|
||||
|
|
@ -1135,6 +1137,9 @@ static int player_get(lua_State *L)
|
|||
case player_bot:
|
||||
lua_pushboolean(L, plr->bot);
|
||||
break;
|
||||
case player_botvars:
|
||||
LUA_PushUserdata(L, &plr->botvars, META_BOTVARS);
|
||||
break;
|
||||
case player_jointime:
|
||||
lua_pushinteger(L, plr->jointime);
|
||||
break;
|
||||
|
|
@ -1786,6 +1791,8 @@ static int player_set(lua_State *L)
|
|||
break;
|
||||
case player_bot:
|
||||
return NOSET;
|
||||
case player_botvars:
|
||||
return NOSET;
|
||||
case player_jointime:
|
||||
plr->jointime = (tic_t)luaL_checkinteger(L, 3);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ static lua_CFunction liblist[] = {
|
|||
LUA_BlockmapLib, // blockmap stuff
|
||||
LUA_HudLib, // HUD stuff
|
||||
LUA_FollowerLib, // follower_t, followers[]
|
||||
LUA_BotVarsLib, // botvars_t
|
||||
LUA_TerrainLib, // t_splash_t, t_footstep_t, t_overlay_t, terrain_t
|
||||
LUA_WaypointLib, // waypoint_t
|
||||
NULL
|
||||
|
|
|
|||
|
|
@ -370,10 +370,14 @@ static void M_DrawTickStats(void)
|
|||
{0}
|
||||
};
|
||||
|
||||
perfstatrow_t bot_time_row[] = {
|
||||
{"botcmd ", "Bot logic: ", &ps_botticcmd_time},
|
||||
{0}
|
||||
};
|
||||
|
||||
perfstatrow_t extra_thinker_time_row[] = {
|
||||
{"lthinkf", "LUAh_ThinkFrame:", &ps_lua_thinkframe_time},
|
||||
{"acs ", "ACS_Tick: ", &ps_acs_time},
|
||||
{"botcmd ", "Bot logic: ", &ps_botticcmd_time},
|
||||
{"other ", "Other: ", &extratime},
|
||||
{0}
|
||||
};
|
||||
|
|
@ -417,6 +421,7 @@ static void M_DrawTickStats(void)
|
|||
perfstatcol_t tictime_col = {20, 20, V_YELLOWMAP, tictime_row};
|
||||
perfstatcol_t thinker_time_col = {24, 24, V_YELLOWMAP, thinker_time_row};
|
||||
perfstatcol_t detailed_thinker_time_col = {28, 28, V_YELLOWMAP, detailed_thinker_time_row};
|
||||
perfstatcol_t bot_time_col = {24, 24, V_YELLOWMAP, bot_time_row};
|
||||
perfstatcol_t extra_thinker_time_col = {24, 24, V_YELLOWMAP, extra_thinker_time_row};
|
||||
|
||||
perfstatcol_t thinkercount_col = {90, 115, V_BLUEMAP, thinkercount_row};
|
||||
|
|
@ -462,6 +467,8 @@ static void M_DrawTickStats(void)
|
|||
M_DrawPerfTiming(&tictime_col);
|
||||
M_DrawPerfTiming(&thinker_time_col);
|
||||
M_DrawPerfTiming(&detailed_thinker_time_col);
|
||||
if (server)
|
||||
M_DrawPerfTiming(&bot_time_col);
|
||||
M_DrawPerfTiming(&extra_thinker_time_col);
|
||||
|
||||
draw_row = 10;
|
||||
|
|
@ -504,7 +511,11 @@ void M_DrawPerfStats(void)
|
|||
}
|
||||
else if (cv_perfstats.value == PS_BOT) // bot ticcmd
|
||||
{
|
||||
if (vid.width < 640 || vid.height < 400) // low resolution
|
||||
if (!server)
|
||||
{
|
||||
V_DrawThinString(30, 30, V_MONOSPACE | V_ALLOWLOWERCASE | V_YELLOWMAP, "Not applicable to clients");
|
||||
}
|
||||
else if (vid.width < 640 || vid.height < 400) // low resolution
|
||||
{
|
||||
// it's not gonna fit very well..
|
||||
V_DrawThinString(30, 30, V_MONOSPACE | V_ALLOWLOWERCASE | V_YELLOWMAP, "Not available for resolutions below 640x400");
|
||||
|
|
|
|||
|
|
@ -174,13 +174,13 @@ void P_CalcChasePostImg(player_t *player, camera_t *thiscam);
|
|||
|
||||
boolean P_CanPlayerTurn(player_t *player, ticcmd_t *cmd);
|
||||
|
||||
boolean P_PlayerInPain(player_t *player);
|
||||
boolean P_PlayerInPain(const player_t *player);
|
||||
void P_ResetPlayer(player_t *player);
|
||||
boolean P_PlayerCanDamage(player_t *player, mobj_t *thing);
|
||||
|
||||
fixed_t P_GetPlayerHeight(player_t *player);
|
||||
fixed_t P_GetPlayerSpinHeight(player_t *player);
|
||||
boolean P_IsLocalPlayer(player_t *player);
|
||||
boolean P_IsLocalPlayer(const player_t *player);
|
||||
boolean P_IsMachineLocalPlayer(player_t *player);
|
||||
boolean P_IsDisplayPlayer(player_t *player);
|
||||
|
||||
|
|
@ -189,12 +189,12 @@ angle_t P_GetLocalAngle(player_t *player);
|
|||
void P_ForceLocalAngle(player_t *player, angle_t angle, boolean interp);
|
||||
boolean P_PlayerFullbright(player_t *player);
|
||||
|
||||
boolean P_IsObjectInGoop(mobj_t *mo);
|
||||
boolean P_IsObjectOnGround(mobj_t *mo);
|
||||
boolean P_IsObjectOnGroundIn(mobj_t *mo, sector_t *sec);
|
||||
boolean P_IsObjectOnRealGround(mobj_t *mo, sector_t *sec); // SRB2Kart
|
||||
boolean P_IsObjectInGoop(const mobj_t *mo);
|
||||
boolean P_IsObjectOnGround(const mobj_t *mo);
|
||||
boolean P_IsObjectOnGroundIn(const mobj_t *mo, const sector_t *sec);
|
||||
boolean P_IsObjectOnRealGround(const mobj_t *mo, const sector_t *sec); // SRB2Kart
|
||||
#define P_IsObjectFlipped(o) (((o)->eflags & MFE_VERTICALFLIP) == MFE_VERTICALFLIP)
|
||||
boolean P_InQuicksand(mobj_t *mo);
|
||||
boolean P_InQuicksand(const mobj_t *mo);
|
||||
boolean P_PlayerHitFloor(player_t *player, boolean fromAir);
|
||||
|
||||
void P_SetObjectMomZ(mobj_t *mo, fixed_t value, boolean relative);
|
||||
|
|
@ -328,13 +328,13 @@ void P_SceneryThinker(mobj_t *mobj);
|
|||
|
||||
// This does not need to be added to Lua.
|
||||
// To test it in Lua, check mobj.valid
|
||||
FUNCINLINE static ATTRINLINE boolean P_MobjWasRemoved(mobj_t *mobj)
|
||||
FUNCINLINE static ATTRINLINE boolean P_MobjWasRemoved(const mobj_t *mobj)
|
||||
{
|
||||
return mobj == NULL || mobj->thinker.function.acp1 != (actionf_p1)P_MobjThinker;
|
||||
}
|
||||
|
||||
fixed_t P_MobjFloorZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect);
|
||||
fixed_t P_MobjCeilingZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect);
|
||||
fixed_t P_MobjFloorZ(const mobj_t *mobj, const sector_t *sector, const sector_t *boundsec, fixed_t x, fixed_t y, const line_t *line, boolean lowest, boolean perfect);
|
||||
fixed_t P_MobjCeilingZ(const mobj_t *mobj, const sector_t *sector, const sector_t *boundsec, fixed_t x, fixed_t y, const line_t *line, boolean lowest, boolean perfect);
|
||||
#define P_GetFloorZ(mobj, sector, x, y, line) P_MobjFloorZ(mobj, sector, NULL, x, y, line, false, false)
|
||||
#define P_GetCeilingZ(mobj, sector, x, y, line) P_MobjCeilingZ(mobj, sector, NULL, x, y, line, true, false)
|
||||
#define P_GetFOFTopZ(mobj, sector, fof, x, y, line) P_MobjCeilingZ(mobj, sectors + fof->secnum, sector, x, y, line, false, false)
|
||||
|
|
|
|||
|
|
@ -635,7 +635,7 @@ boolean P_InsideANonSolidFFloor(mobj_t *mobj, ffloor_t *rover)
|
|||
// Supply boundsec ONLY when checking for specials! It should be the "in-level" sector, and sector the control sector (if separate).
|
||||
// If set, then this function will iterate through boundsec's linedefs to find the highest contact point on the slope. Non-special-checking
|
||||
// usage will handle that later.
|
||||
static fixed_t HighestOnLine(fixed_t radius, fixed_t x, fixed_t y, line_t *line, pslope_t *slope, boolean actuallylowest)
|
||||
static fixed_t HighestOnLine(fixed_t radius, fixed_t x, fixed_t y, const line_t *line, const pslope_t *slope, boolean actuallylowest)
|
||||
{
|
||||
// Alright, so we're sitting on a line that contains our slope sector, and need to figure out the highest point we're touching...
|
||||
// The solution is simple! Get the line's vertices, and pull each one in along its line until it touches the object's bounding box
|
||||
|
|
@ -733,7 +733,7 @@ static fixed_t HighestOnLine(fixed_t radius, fixed_t x, fixed_t y, line_t *line,
|
|||
);
|
||||
}
|
||||
|
||||
fixed_t P_MobjFloorZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect)
|
||||
fixed_t P_MobjFloorZ(const mobj_t *mobj, const sector_t *sector, const sector_t *boundsec, fixed_t x, fixed_t y, const line_t *line, boolean lowest, boolean perfect)
|
||||
{
|
||||
I_Assert(mobj != NULL);
|
||||
I_Assert(sector != NULL);
|
||||
|
|
@ -810,7 +810,7 @@ fixed_t P_MobjFloorZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t
|
|||
return sector->floorheight;
|
||||
}
|
||||
|
||||
fixed_t P_MobjCeilingZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect)
|
||||
fixed_t P_MobjCeilingZ(const mobj_t *mobj, const sector_t *sector, const sector_t *boundsec, fixed_t x, fixed_t y, const line_t *line, boolean lowest, boolean perfect)
|
||||
{
|
||||
I_Assert(mobj != NULL);
|
||||
I_Assert(sector != NULL);
|
||||
|
|
|
|||
|
|
@ -396,20 +396,12 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
|
||||
// botvars_t
|
||||
WRITEUINT8(save->p, players[i].bot);
|
||||
WRITEUINT8(save->p, players[i].botvars.style);
|
||||
WRITEUINT8(save->p, players[i].botvars.difficulty);
|
||||
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);
|
||||
WRITEUINT32(save->p, players[i].botvars.respawnconfirm);
|
||||
WRITEFIXED(save->p, players[i].botvars.driftskill);
|
||||
WRITEINT32(save->p, players[i].botvars.driftstate);
|
||||
WRITESINT8(save->p, players[i].botvars.driftturn);
|
||||
WRITEUINT32(save->p, players[i].botvars.drifttime);
|
||||
WRITEUINT32(save->p, players[i].botvars.driftlockout);
|
||||
|
||||
WRITEFIXED(save->p, players[i].outrun);
|
||||
WRITEUINT8(save->p, players[i].outruntime);
|
||||
|
|
@ -751,20 +743,12 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
|
|||
|
||||
// botvars_t
|
||||
players[i].bot = READUINT8(save->p);
|
||||
players[i].botvars.style = READUINT8(save->p);
|
||||
players[i].botvars.difficulty = READUINT8(save->p);
|
||||
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);
|
||||
players[i].botvars.respawnconfirm = READUINT32(save->p);
|
||||
players[i].botvars.driftskill = READFIXED(save->p);
|
||||
players[i].botvars.driftstate = READINT32(save->p);
|
||||
players[i].botvars.driftturn = READSINT8(save->p);
|
||||
players[i].botvars.drifttime = READUINT32(save->p);
|
||||
players[i].botvars.driftlockout = READUINT32(save->p);
|
||||
|
||||
players[i].outrun = READFIXED(save->p);
|
||||
players[i].outruntime = READUINT8(save->p);
|
||||
|
|
|
|||
21
src/p_tick.c
21
src/p_tick.c
|
|
@ -40,6 +40,7 @@
|
|||
#include "k_waypoint.h"
|
||||
#include "k_director.h"
|
||||
#include "acs/interface.h"
|
||||
#include "k_bot.h" // K_BotTicker
|
||||
|
||||
#ifdef PARANOIA
|
||||
#include "deh_tables.h" // MOBJTYPE_LIST
|
||||
|
|
@ -767,6 +768,26 @@ void P_Ticker(boolean run)
|
|||
if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo))
|
||||
P_PlayerAfterThink(&players[i]);
|
||||
|
||||
// run all the bot tickers
|
||||
if (server)
|
||||
{
|
||||
PS_ResetBotInfo();
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
player_t *player = &players[i];
|
||||
if (playeringame[i] && player->mo && !P_MobjWasRemoved(player->mo) && K_PlayerUsesBotMovement(player))
|
||||
{
|
||||
const precise_t t = I_GetPreciseTime();
|
||||
|
||||
K_BotTicker(player);
|
||||
|
||||
ps_bots[i].total = I_GetPreciseTime() - t;
|
||||
ps_bots[i].isBot = true;
|
||||
ps_botticcmd_time += ps_bots[i].total;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bosses have a punchy start, so no position.
|
||||
if (bossinfo.boss == true)
|
||||
{
|
||||
|
|
|
|||
20
src/p_user.c
20
src/p_user.c
|
|
@ -465,7 +465,7 @@ UINT8 P_FindHighestLap(void)
|
|||
// Is player in pain??
|
||||
// Checks for painstate and flashing, if both found return true
|
||||
//
|
||||
boolean P_PlayerInPain(player_t *player)
|
||||
boolean P_PlayerInPain(const player_t *player)
|
||||
{
|
||||
if (K_IsPlayerDamaged(player) || player->squishedtimer)
|
||||
return true;
|
||||
|
|
@ -890,7 +890,7 @@ void P_RestoreMusic(player_t *player)
|
|||
// Returns true if the object is inside goop water.
|
||||
// (Spectators and objects otherwise without gravity cannot have goop gravity!)
|
||||
//
|
||||
boolean P_IsObjectInGoop(mobj_t *mo)
|
||||
boolean P_IsObjectInGoop(const mobj_t *mo)
|
||||
{
|
||||
if (mo->player && mo->player->spectator)
|
||||
return false;
|
||||
|
|
@ -908,7 +908,7 @@ boolean P_IsObjectInGoop(mobj_t *mo)
|
|||
// on the ground. Takes reverse
|
||||
// gravity and FOFs into account.
|
||||
//
|
||||
boolean P_IsObjectOnGround(mobj_t *mo)
|
||||
boolean P_IsObjectOnGround(const mobj_t *mo)
|
||||
{
|
||||
if (P_IsObjectInGoop(mo))
|
||||
{
|
||||
|
|
@ -953,7 +953,7 @@ boolean P_IsObjectOnGround(mobj_t *mo)
|
|||
// on the ground in a specific sector. Takes reverse
|
||||
// gravity and FOFs into account.
|
||||
//
|
||||
boolean P_IsObjectOnGroundIn(mobj_t *mo, sector_t *sec)
|
||||
boolean P_IsObjectOnGroundIn(const mobj_t *mo, const sector_t *sec)
|
||||
{
|
||||
ffloor_t *rover;
|
||||
|
||||
|
|
@ -1040,7 +1040,7 @@ boolean P_IsObjectOnGroundIn(mobj_t *mo, sector_t *sec)
|
|||
// Really simple, but personally I think it's also incredibly helpful. I think this is fine in p_user.c
|
||||
// -- Sal
|
||||
|
||||
boolean P_IsObjectOnRealGround(mobj_t *mo, sector_t *sec)
|
||||
boolean P_IsObjectOnRealGround(const mobj_t *mo, const sector_t *sec)
|
||||
{
|
||||
// Is the object in reverse gravity?
|
||||
if (mo->eflags & MFE_VERTICALFLIP)
|
||||
|
|
@ -1132,7 +1132,7 @@ boolean P_IsMachineLocalPlayer(player_t *player)
|
|||
// on the local machine
|
||||
// (or simulated party)
|
||||
//
|
||||
boolean P_IsLocalPlayer(player_t *player)
|
||||
boolean P_IsLocalPlayer(const player_t *player)
|
||||
{
|
||||
if (player == NULL)
|
||||
{
|
||||
|
|
@ -1400,7 +1400,7 @@ boolean P_PlayerHitFloor(player_t *player, boolean fromAir)
|
|||
return clipmomz;
|
||||
}
|
||||
|
||||
boolean P_InQuicksand(mobj_t *mo) // Returns true if you are in quicksand
|
||||
boolean P_InQuicksand(const mobj_t *mo) // Returns true if you are in quicksand
|
||||
{
|
||||
sector_t *sector = mo->subsector->sector;
|
||||
fixed_t topheight, bottomheight;
|
||||
|
|
@ -2934,6 +2934,12 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
|
|||
}
|
||||
else if (P_IsMachineLocalPlayer(player))
|
||||
{
|
||||
// Players-turned-bots outside of end of race contexts (Lua)
|
||||
// don't update their local camera angle, so it should be updated
|
||||
// somewhere - I choose here because it makes the most sense.
|
||||
if (K_PlayerUsesBotMovement(player) && !player->bot)
|
||||
P_ForceLocalAngle(player, mo->angle, true);
|
||||
|
||||
focusangle = localangle[num];
|
||||
focusaiming = localaiming[num];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ TYPEDEF (bheap_t);
|
|||
TYPEDEF (weakspot_t);
|
||||
|
||||
// k_bot.h
|
||||
TYPEDEF (botprediction_t);
|
||||
TYPEDEF (botdata_t);
|
||||
TYPEDEF (botcontroller_t);
|
||||
|
||||
// k_brightmap.h
|
||||
|
|
|
|||
Loading…
Reference in a new issue