Merge branch 'bortsport' into blankart-dev

This commit is contained in:
NepDisk 2025-02-26 19:43:22 -05:00
commit 064be1b201
35 changed files with 2744 additions and 1443 deletions

View file

@ -52,6 +52,8 @@ add_custom_target(_SRB2_reconf ALL
)
add_dependencies(SRB2SDL2 _SRB2_reconf)
add_subdirectory(blua)
add_subdirectory(blan)
add_subdirectory(sdl)

View file

@ -115,12 +115,12 @@ k_collide.c
k_color.c
k_battle.c
k_pwrlv.c
k_waypoint.c
k_waypoint.cpp
k_pathfind.c
k_bheap.c
k_bot.c
k_botitem.c
k_botsearch.c
k_bot.cpp
k_botitem.cpp
k_botsearch.cpp
k_grandprix.c
k_boss.c
k_hud.c

View file

@ -3543,19 +3543,6 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum)
node = (UINT8)READUINT8(*p);
newplayernum = (UINT8)READUINT8(*p);
CONS_Debug(DBG_NETPLAY, "addplayer: %d %d\n", node, newplayernum);
{
// Clear player before joining, lest some things get set incorrectly
CL_ClearPlayer(newplayernum);
playeringame[newplayernum] = true;
G_AddPlayer(newplayernum);
if (newplayernum+1 > doomcom->numslots)
doomcom->numslots = (INT16)(newplayernum+1);
}
newplayer = &players[newplayernum];
newplayer->jointime = 0;
@ -3565,6 +3552,8 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum)
console = (UINT8)READUINT8(*p);
splitscreenplayer = (UINT8)READUINT8(*p);
G_AddPlayer(newplayernum, console);
// the server is creating my player
if (node == mynode)
{
@ -3685,34 +3674,7 @@ static void Got_AddBot(UINT8 **p, INT32 playernum)
difficulty = READUINT8(*p);
style = READUINT8(*p);
CONS_Debug(DBG_NETPLAY, "addbot: %d\n", newplayernum);
// Clear player before joining, lest some things get set incorrectly
CL_ClearPlayer(newplayernum);
playeringame[newplayernum] = true;
G_AddPlayer(newplayernum);
if (newplayernum+1 > doomcom->numslots)
doomcom->numslots = (INT16)(newplayernum+1);
playernode[newplayernum] = servernode;
players[newplayernum].splitscreenindex = 0;
players[newplayernum].bot = true;
players[newplayernum].botvars.difficulty = difficulty;
players[newplayernum].botvars.style = style;
players[newplayernum].lives = 9;
players[newplayernum].skincolor = skins[skinnum].prefcolor;
sprintf(player_names[newplayernum], "%s", skins[skinnum].realname);
SetPlayerSkinByNum(newplayernum, skinnum);
if (netgame)
{
HU_AddChatText(va("\x82*Bot %d has been added to the game", newplayernum+1), false);
}
LUA_HookInt(newplayernum, HOOK(PlayerJoin));
K_SetBot(newplayernum, skinnum, difficulty, style);
}
static boolean SV_AddWaitingPlayers(SINT8 node, const char *name, const char *name2, const char *name3, const char *name4)
@ -3811,6 +3773,85 @@ static boolean SV_AddWaitingPlayers(SINT8 node, const char *name, const char *na
return newplayer;
}
/*--------------------------------------------------
boolean K_AddBotFromServer(UINT8 skin, UINT8 difficulty, botStyle_e style, UINT8 *p)
See header file for description.
--------------------------------------------------*/
boolean K_AddBotFromServer(UINT8 skin, UINT8 difficulty, botStyle_e style, UINT8 *p)
{
UINT8 newplayernum = *p;
// search for a free playernum
// we can't use playeringame since it is not updated here
for (; newplayernum < MAXPLAYERS; newplayernum++)
{
UINT8 n;
for (n = 0; n < MAXNETNODES; n++)
{
if (nodetoplayer[n] == newplayernum
|| nodetoplayer2[n] == newplayernum
|| nodetoplayer3[n] == newplayernum
|| nodetoplayer4[n] == newplayernum)
break;
}
if (n == MAXNETNODES)
break;
}
for (; newplayernum < MAXPLAYERS; newplayernum++)
{
if (playeringame[newplayernum] == false)
{
// free player slot
break;
}
}
if (newplayernum >= MAXPLAYERS)
{
// nothing is free
*p = MAXPLAYERS;
return false;
}
if (server)
{
UINT8 buf[4];
UINT8 *buf_p = buf;
WRITEUINT8(buf_p, newplayernum);
if (skin > numskins)
{
skin = numskins;
}
WRITEUINT8(buf_p, skin);
if (difficulty < 1)
{
difficulty = 1;
}
else if (difficulty > MAXBOTDIFFICULTY)
{
difficulty = MAXBOTDIFFICULTY;
}
WRITEUINT8(buf_p, difficulty);
WRITEUINT8(buf_p, style);
SendNetXCmd(XD_ADDBOT, buf, buf_p - buf);
DEBFILE(va("Server added bot %d\n", newplayernum));
}
// use the next free slot (we can't put playeringame[newplayernum] = true here)
*p = newplayernum+1;
return true;
}
void CL_AddSplitscreenPlayer(void)
{
if (cl_mode == CL_CONNECTED)

View file

@ -262,6 +262,11 @@ static consvar_t cv_dummyconsvar = CVAR_INIT ("dummyconsvar", "Off", CV_CALL|CV_
consvar_t cv_restrictskinchange = CVAR_INIT ("restrictskinchange", "No", CV_NETVAR|CV_CHEAT, CV_YesNo, NULL);
consvar_t cv_allowteamchange = CVAR_INIT ("allowteamchange", "Yes", CV_NETVAR, CV_YesNo, NULL);
#ifdef DEVELOP
// change the default value in doomdef.h (so it affects release builds too)
consvar_t cv_debugtraversemax = CVAR_INIT ("debugtraversemax", TOSTR2(TRAVERSE_MAX), CV_NETVAR|CV_CHEAT, CV_Unsigned, NULL);
#endif
static CV_PossibleValue_t ingamecap_cons_t[] = {{0, "MIN"}, {MAXPLAYERS-1, "MAX"}, {0, NULL}};
consvar_t cv_ingamecap = CVAR_INIT ("ingamecap", "0", CV_NETVAR, ingamecap_cons_t, NULL);
@ -3652,6 +3657,40 @@ static void Command_ServerTeamChange_f(void)
SendNetXCmd(XD_TEAMCHANGE, &usvalue, sizeof(usvalue));
}
void P_SetPlayerSpectator(INT32 playernum)
{
//Make sure you're in the right gametype.
if (!G_GametypeHasTeams() && !G_GametypeHasSpectators())
return;
// Don't duplicate efforts.
if (players[playernum].spectator)
return;
players[playernum].spectator = true;
players[playernum].pflags &= ~PF_WANTSTOJOIN;
players[playernum].playerstate = PST_REBORN;
/*if (cv_spectatormusic.value && (players[displayplayers[0]].spectator == true) && !r_splitscreen)
{
if (P_UseContinuousLevelMusic())
{
if (!stricmp(Music_Song("level_nosync"), cv_spectatormusiclump.string))
{
// Do not reset music if it is the same
Music_BatchExempt("level_nosync");
}
Music_Remap("level_nosync", cv_spectatormusiclump.string);
}
else
{
Music_Remap("level", cv_spectatormusiclump.string);
}
}*/
}
//todo: This and the other teamchange functions are getting too long and messy. Needs cleaning.
static void Got_Teamchange(UINT8 **cp, INT32 playernum)
{
@ -3739,7 +3778,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum)
{
players[playernum].playerstate = PST_REBORN;
}
}
else
wasspectator = true;
@ -3832,7 +3871,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum)
if (players[playernum].spectator)
{
players[playernum].spectatorreentry = (cv_spectatorreentry.value * TICRATE);
if (gametyperules & GTR_BUMPERS) // SRB2kart
{
players[playernum].roundscore = 0;

View file

@ -65,6 +65,10 @@ extern consvar_t cv_pause;
extern consvar_t cv_restrictskinchange, cv_allowteamchange, cv_ingamecap, cv_respawntime;
extern consvar_t cv_spectatorreentry, cv_antigrief;
#ifdef DEVELOP
extern consvar_t cv_debugtraversemax;
#endif
// SRB2kart items
extern consvar_t cv_superring, cv_sneaker, cv_rocketsneaker, cv_invincibility, cv_banana;
extern consvar_t cv_eggmanmonitor, cv_orbinaut, cv_jawz, cv_mine, cv_landmine, cv_droptarget;
@ -255,6 +259,8 @@ void RemoveAdminPlayer(INT32 playernum);
void ItemFinder_OnChange(void);
void D_SetPassword(const char *pw);
void P_SetPlayerSpectator(INT32 playernum);
struct scheduleTask_t
{
UINT16 basetime;

View file

@ -274,6 +274,9 @@ enum {
LE_PARAMWIDTH = -100 // If an object that calls LinedefExecute has a nonzero parameter value, this times the parameter will be subtracted. (Mostly for the purpose of coexisting bosses...)
};
#define TOSTR(x) #x
#define TOSTR2(x) TOSTR(x) // expand x first
// Name of local directory for config files and savegames
#if (((defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON)) && !defined (__CYGWIN__)) && !defined (__APPLE__)
#define DEFAULTDIR ".srb2kart-v2"
@ -562,6 +565,9 @@ extern int compuncommitted;
/// Camera always has noclip.
#define NOCLIPCAM
// p_sight.c
#define TRAVERSE_MAX 8
#ifdef __cplusplus
} // extern "C"
#endif

View file

@ -1951,7 +1951,7 @@ void F_EndTextPrompt(boolean forceexec, boolean noexec)
// \todo net safety, maybe loop all player thinkers?
if ((promptwasactive || forceexec) && !noexec && promptpostexectag)
{
if (tm.thing) // edge case where starting an invalid prompt immediately on level load will make P_MapStart fail
if (g_tm.thing) // edge case where starting an invalid prompt immediately on level load will make P_MapStart fail
P_LinedefExecute(promptpostexectag, promptmo, NULL);
else
{

View file

@ -336,7 +336,7 @@ void G_ReadDemoExtraData(void)
{
CL_ClearPlayer(p);
playeringame[p] = true;
G_AddPlayer(p);
G_AddPlayer(p, p);
players[p].spectator = true;
//CONS_Printf("player %s is joining server on tic %d\n", player_names[p], leveltime);
}

View file

@ -2995,10 +2995,21 @@ void G_DoReborn(INT32 playernum)
ACS_RunPlayerEnterScript(player);
}
void G_AddPlayer(INT32 playernum)
void G_AddPlayer(INT32 playernum, INT32 console)
{
player_t *p = &players[playernum];
p->playerstate = PST_REBORN;
CL_ClearPlayer(playernum);
//G_DestroyParty(playernum);
playeringame[playernum] = true;
playerconsole[playernum] = console;
//G_BuildLocalSplitscreenParty(playernum);
player_t *newplayer = &players[playernum];
newplayer->playerstate = PST_REBORN;
newplayer->jointime = 0;
demo_extradata[playernum] |= DXD_PLAYSTATE|DXD_COLOR|DXD_NAME|DXD_SKIN|DXD_FOLLOWER; // Set everything
}
@ -5260,6 +5271,21 @@ void G_SetGamestate(gamestate_t newstate)
#endif
}
boolean G_GamestateUsesLevel(void)
{
switch (gamestate)
{
case GS_TITLESCREEN:
return titlemapinaction;
case GS_LEVEL:
return true;
default:
return false;
}
}
/* These functions handle the exitgame flag. Before, when the user
chose to end a game, it happened immediately, which could cause
crashes if the game was in the middle of something. Now, a flag

View file

@ -247,7 +247,7 @@ void G_AddPartyMember (INT32 party_member, INT32 new_party_member);
void G_RemovePartyMember (INT32 party_member);
void G_ResetSplitscreen (INT32 playernum);
void G_AddPlayer(INT32 playernum);
void G_AddPlayer(INT32 playernum, INT32 console);
void G_SetExitGameFlag(void);
void G_ClearExitGameFlag(void);
@ -268,6 +268,8 @@ void G_SetGameModified(boolean silent, boolean major);
void G_SetGamestate(gamestate_t newstate);
boolean G_GamestateUsesLevel(void);
// Gamedata record shit
void G_AllocMainRecordData(INT16 i);
void G_ClearRecords(void);

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 KART
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2018-2020 by Sally "TehRealSalt" Cochenour
// Copyright (C) 2018-2020 by Kart Krew
// Copyright (C) 2024 by Sally "TehRealSalt" Cochenour
// Copyright (C) 2024 by Kart Krew
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
@ -13,6 +13,7 @@
#ifndef __K_BOT__
#define __K_BOT__
#include "typedef.h"
#include "k_waypoint.h"
#include "d_player.h"
#include "r_defs.h"
@ -21,28 +22,41 @@
extern "C" {
#endif
#ifdef DEVELOP
extern consvar_t cv_botcontrol;
#endif
// Maximum value of botvars.difficulty
#define MAXBOTDIFFICULTY 13
#define MAXBOTDIFFICULTY (13)
// Level of a "difficult" bot. The max bot level was increased, but this keeps all of the same calculations.
#define DIFFICULTBOT 9
#define DIFFICULTBOT (9)
// How many tics in a row do you need to turn in this direction before we'll let you turn.
// Made it as small as possible without making it look like the bots are twitching constantly.
#define BOTTURNCONFIRM 4
// Point for bots to aim for
struct botprediction_t {
fixed_t x, y;
fixed_t radius;
};
// How many tics with only one spindash-viable condition before we'll let you spindash.
#define BOTSPINDASHCONFIRM (4*TICRATE)
// How many tics without being able to make progress before we'll let you respawn.
#define BOTRESPAWNCONFIRM (5*TICRATE)
// 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
{
fixed_t x, y;
fixed_t radius, baseRadius;
};
// AVAILABLE FOR LUA
/*--------------------------------------------------
boolean K_PlayerUsesBotMovement(player_t *player);
boolean K_PlayerUsesBotMovement(const player_t *player);
Tells if this player is being controlled via bot movement code (is a bot, or is exiting).
@ -53,7 +67,7 @@ struct botprediction_t {
true if using bot movement code, otherwise false.
--------------------------------------------------*/
boolean K_PlayerUsesBotMovement(player_t *player);
boolean K_PlayerUsesBotMovement(const player_t *player);
/*--------------------------------------------------
@ -73,7 +87,43 @@ boolean K_BotCanTakeCut(player_t *player);
/*--------------------------------------------------
fixed_t K_BotRubberband(player_t *player);
const botcontroller_t *K_GetBotController(mobj_t *mobj);
Retrieves the current bot controller values from
the player's current sector.
Input Arguments:-
mobj - The player's object to get the bot controller for.
Return:-
Pointer to the sector's bot controller struct.
--------------------------------------------------*/
const botcontroller_t *K_GetBotController(mobj_t *mobj);
/*--------------------------------------------------
fixed_t K_BotMapModifier(void);
Gives a multiplier, based on the track complexity.
Track complexity is a measure of how easy it is for
the bots to continuously rubberband. This is used
to make the rubberbanding and other difficulty
adjustments feel roughly the same between wildly
different layouts.
Input Arguments:-
N/A
Return:-
A multiplier in fixed point scale, between 0.0 and 2.0.
--------------------------------------------------*/
fixed_t K_BotMapModifier(void);
/*--------------------------------------------------
fixed_t K_BotRubberband(const player_t *player);
Gives a multiplier for a bot's rubberbanding.
Meant to be used for acceleration and handling.
@ -85,7 +135,7 @@ boolean K_BotCanTakeCut(player_t *player);
A multiplier in fixed point scale.
--------------------------------------------------*/
fixed_t K_BotRubberband(player_t *player);
fixed_t K_BotRubberband(const player_t *player);
/*--------------------------------------------------
@ -125,13 +175,10 @@ fixed_t K_UpdateRubberband(player_t *player);
fixed_t K_DistanceOfLineFromPoint(fixed_t v1x, fixed_t v1y, fixed_t v2x, fixed_t v2y, fixed_t cx, fixed_t cy);
// NOT AVAILABLE FOR LUA
/*--------------------------------------------------
boolean K_AddBot(UINT8 skin, UINT8 difficulty, botStyle_e style, UINT8 *newplayernum);
boolean K_AddBot(UINT8 skin, UINT8 difficulty, botStyle_e style, UINT8 *p);
Returns the waypoint actually being used as the finish line.
Adds a new bot, using code intended to run on all clients.
Input Arguments:-
skin - Skin number that the bot will use.
@ -141,12 +188,53 @@ fixed_t K_DistanceOfLineFromPoint(fixed_t v1x, fixed_t v1y, fixed_t v2x, fixed_t
Is a pointer so that this function can be called multiple times to add more than one bot.
Return:-
true if a bot packet can be sent, otherwise false.
true if a bot was added, otherwise false.
--------------------------------------------------*/
boolean K_AddBot(UINT8 skin, UINT8 difficulty, botStyle_e style, UINT8 *p);
// NOT AVAILABLE FOR LUA
/*--------------------------------------------------
void K_SetNameForBot(UINT8 newplayernum, const char *realname)
Sets a bot's name.
by K_AddBot, and indirectly by K_AddBotFromServer by sending
a packet.
Input Arguments:-
newplayernum - Player slot number to set name for.
realname - Proposed name for bot.
Return:-
None
--------------------------------------------------*/
void K_SetNameForBot(UINT8 newplayernum, const char *realname);
/*--------------------------------------------------
void K_SetBot(UINT8 newplayernum, UINT8 skinnum, UINT8 difficulty, botStyle_e style);
Sets a player ID to be a new bot directly. Invoked directly
by K_AddBot, and indirectly by K_AddBotFromServer by sending
a packet.
Input Arguments:-
newplayernum - Player slot number to set as a bot.
skin - Skin number that the bot will use.
difficulty - Difficulty level this bot will use.
style - Bot style to spawn this bot with, see botStyle_e.
Return:-
None
--------------------------------------------------*/
void K_SetBot(UINT8 newplayernum, UINT8 skinnum, UINT8 difficulty, botStyle_e style);
/*--------------------------------------------------
void K_UpdateMatchRaceBots(void);
@ -205,11 +293,11 @@ boolean K_BotHatesThisSector(player_t *player, sector_t *sec, fixed_t x, fixed_t
None
--------------------------------------------------*/
void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player);
void K_NudgePredictionTowardsObjects(botprediction_t *predict, const player_t *player);
/*--------------------------------------------------
INT32 K_PositionBully(player_t *player)
INT32 K_PositionBully(const player_t *player)
Calculates a turn value to reach a player that can be bullied.
@ -220,7 +308,7 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
INT32_MAX if couldn't find anything, otherwise a steering value.
--------------------------------------------------*/
INT32 K_PositionBully(player_t *player);
INT32 K_PositionBully(const player_t *player);
/*--------------------------------------------------
@ -240,6 +328,23 @@ INT32 K_PositionBully(player_t *player);
void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd);
/*--------------------------------------------------
void K_UpdateBotGameplayVarsItemUsage(player_t *player)
Updates gamestate affecting botvars, relating to
item usage. This must be called for both client
and server.
Input Arguments:-
player - Player to whom to update the botvars.
Return:-
N/A
--------------------------------------------------*/
void K_UpdateBotGameplayVarsItemUsage(player_t *player);
/*--------------------------------------------------
void K_UpdateBotGameplayVars(player_t *player);
@ -272,22 +377,6 @@ void K_UpdateBotGameplayVars(player_t *player);
void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt);
/*--------------------------------------------------
void K_UpdateBotGameplayVarsItemUsage(player_t *player)
Updates gamestate affecting botvars, relating to
item usage. This must be called for both client
and server.
Input Arguments:-
player - Player to whom to update the botvars.
Return:-
N/A
--------------------------------------------------*/
void K_UpdateBotGameplayVarsItemUsage(player_t *player);
#ifdef __cplusplus
} // extern "C"

View file

@ -1,15 +1,19 @@
// SONIC ROBO BLAST 2 KART
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2018-2020 by Sally "TehRealSalt" Cochenour
// Copyright (C) 2018-2020 by Kart Krew
// Copyright (C) 2024 by Sally "TehRealSalt" Cochenour
// Copyright (C) 2024 by Kart Krew
//
// 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 k_botitem.c
/// \file k_botitem.cpp
/// \brief Bot item usage logic
#include <algorithm>
#include <tracy/tracy/Tracy.hpp>
#include "doomdef.h"
#include "d_player.h"
#include "g_game.h"
@ -29,7 +33,7 @@
#include "m_easing.h"
/*--------------------------------------------------
static inline boolean K_ItemButtonWasDown(player_t *player)
static inline boolean K_ItemButtonWasDown(const player_t *player)
Looks for players around the bot, and presses the item button
if there is one in range.
@ -40,13 +44,13 @@
Return:-
true if the item button was pressed last tic, otherwise false.
--------------------------------------------------*/
static inline boolean K_ItemButtonWasDown(player_t *player)
static inline boolean K_ItemButtonWasDown(const player_t *player)
{
return (player->oldcmd.buttons & BT_ATTACK);
}
/*--------------------------------------------------
static boolean K_BotUseItemNearPlayer(player_t *player, ticcmd_t *cmd, fixed_t radius)
static boolean K_BotUseItemNearPlayer(const player_t *player, ticcmd_t *cmd, fixed_t radius)
Looks for players around the bot, and presses the item button
if there is one in range.
@ -59,8 +63,10 @@ static inline boolean K_ItemButtonWasDown(player_t *player)
Return:-
true if a player was found & we can press the item button, otherwise false.
--------------------------------------------------*/
static boolean K_BotUseItemNearPlayer(player_t *player, ticcmd_t *cmd, fixed_t radius)
static boolean K_BotUseItemNearPlayer(const player_t *player, ticcmd_t *cmd, fixed_t radius)
{
ZoneScoped;
UINT8 i;
if (K_ItemButtonWasDown(player) == true)
@ -104,7 +110,7 @@ static boolean K_BotUseItemNearPlayer(player_t *player, ticcmd_t *cmd, fixed_t r
}
/*--------------------------------------------------
static player_t *K_PlayerNearSpot(player_t *player, fixed_t x, fixed_t y, fixed_t radius)
static player_t *K_PlayerNearSpot(const player_t *player, fixed_t x, fixed_t y, fixed_t radius)
Looks for players around a specified x/y coordinate.
@ -117,8 +123,10 @@ static boolean K_BotUseItemNearPlayer(player_t *player, ticcmd_t *cmd, fixed_t r
Return:-
The player we found, NULL if nothing was found.
--------------------------------------------------*/
static player_t *K_PlayerNearSpot(player_t *player, fixed_t x, fixed_t y, fixed_t radius)
static player_t *K_PlayerNearSpot(const player_t *player, fixed_t x, fixed_t y, fixed_t radius)
{
ZoneScoped;
UINT8 i;
for (i = 0; i < MAXPLAYERS; i++)
@ -155,7 +163,7 @@ static player_t *K_PlayerNearSpot(player_t *player, fixed_t x, fixed_t y, fixed_
}
/*--------------------------------------------------
static player_t *K_PlayerPredictThrow(player_t *player, UINT8 extra)
static player_t *K_PlayerPredictThrow(const player_t *player, UINT8 extra)
Looks for players around the predicted coordinates of their thrown item.
@ -166,36 +174,21 @@ static player_t *K_PlayerNearSpot(player_t *player, fixed_t x, fixed_t y, fixed_
Return:-
The player we're trying to throw at, NULL if none was found.
--------------------------------------------------*/
static player_t *K_PlayerPredictThrow(player_t *player, UINT8 extra)
static player_t *K_PlayerPredictThrow(const player_t *player, UINT8 extra)
{
ZoneScoped;
const fixed_t dist = (30 + (extra * 10)) * player->mo->scale;
const UINT32 airtime = FixedDiv(dist + player->mo->momz, gravity);
fixed_t throwspeed;
fixed_t estx;
fixed_t esty;
switch (gamespeed)
{
case 0:
throwspeed = 68*mapobjectscale; // Avg Speed is 34
break;
case 2:
throwspeed = 96*mapobjectscale; // Avg Speed is 48
break;
default:
throwspeed = 82*mapobjectscale; // Avg Speed is 41
break;
}
estx = player->mo->x + P_ReturnThrustX(NULL, player->mo->angle, (throwspeed + player->speed) * airtime);
esty = player->mo->y + P_ReturnThrustY(NULL, player->mo->angle, (throwspeed + player->speed) * airtime);
const fixed_t throwspeed = FixedMul(82 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed));
const fixed_t estx = player->mo->x + P_ReturnThrustX(NULL, player->mo->angle, (throwspeed + player->speed) * airtime);
const fixed_t esty = player->mo->y + P_ReturnThrustY(NULL, player->mo->angle, (throwspeed + player->speed) * airtime);
return K_PlayerNearSpot(player, estx, esty, player->mo->radius * 2);
}
/*--------------------------------------------------
static player_t *K_PlayerInCone(player_t *player, UINT16 cone, boolean flip)
static player_t *K_PlayerInCone(const player_t *player, UINT16 cone, boolean flip)
Looks for players in the .
@ -208,8 +201,10 @@ static player_t *K_PlayerPredictThrow(player_t *player, UINT8 extra)
Return:-
true if a player was found in the cone, otherwise false.
--------------------------------------------------*/
static player_t *K_PlayerInCone(player_t *player, fixed_t radius, UINT16 cone, boolean flip)
static player_t *K_PlayerInCone(const player_t *player, fixed_t radius, UINT16 cone, boolean flip)
{
ZoneScoped;
UINT8 i;
for (i = 0; i < MAXPLAYERS; i++)
@ -247,7 +242,7 @@ static player_t *K_PlayerInCone(player_t *player, fixed_t radius, UINT16 cone, b
{
ad = AngleFixed(a)>>FRACBITS;
}
else
else
{
ad = 360-(AngleFixed(a)>>FRACBITS);
}
@ -275,7 +270,7 @@ static player_t *K_PlayerInCone(player_t *player, fixed_t radius, UINT16 cone, b
}
/*--------------------------------------------------
static boolean K_RivalBotAggression(player_t *bot, player_t *target)
static boolean K_RivalBotAggression(const player_t *bot, const player_t *target)
Returns if a bot is a rival & wants to be aggressive to a player.
@ -286,7 +281,7 @@ static player_t *K_PlayerInCone(player_t *player, fixed_t radius, UINT16 cone, b
Return:-
false if not the rival. false if the target is another bot. Otherwise, true.
--------------------------------------------------*/
static boolean K_RivalBotAggression(player_t *bot, player_t *target)
static boolean K_RivalBotAggression(const player_t *bot, const player_t *target)
{
if (bot == NULL || target == NULL)
{
@ -317,19 +312,20 @@ static boolean K_RivalBotAggression(player_t *bot, player_t *target)
}
/*--------------------------------------------------
static void K_ItemConfirmForTarget(player_t *bot, player_t *target, UINT16 amount)
static void K_ItemConfirmForTarget(const player_t *bot, ticcmd_t *cmd, const player_t *target, UINT16 amount)
Handles updating item confirm values for offense items.
Input Arguments:-
bot - Bot to check.
cmd - Bot's ticcmd to edit.
target - Who the bot wants to attack.
amount - Amount to increase item confirm time by.
Return:-
None
--------------------------------------------------*/
static void K_ItemConfirmForTarget(player_t *bot, ticcmd_t *cmd, player_t *target, UINT16 amount)
static void K_ItemConfirmForTarget(const player_t *bot, ticcmd_t *cmd, const player_t *target, UINT16 amount)
{
if (bot == NULL || target == NULL)
{
@ -349,7 +345,7 @@ static void K_ItemConfirmForTarget(player_t *bot, ticcmd_t *cmd, player_t *targe
}
/*--------------------------------------------------
static boolean K_BotGenericPressItem(player_t *player, ticcmd_t *cmd, SINT8 dir)
static boolean K_BotGenericPressItem(const player_t *player, ticcmd_t *cmd, SINT8 dir)
Presses the item button & aim buttons for the bot.
@ -361,8 +357,10 @@ static void K_ItemConfirmForTarget(player_t *bot, ticcmd_t *cmd, player_t *targe
Return:-
true if we could press, false if not.
--------------------------------------------------*/
static boolean K_BotGenericPressItem(player_t *player, ticcmd_t *cmd, SINT8 dir)
static boolean K_BotGenericPressItem(const player_t *player, ticcmd_t *cmd, SINT8 dir)
{
ZoneScoped;
if (K_ItemButtonWasDown(player) == true)
{
return false;
@ -375,7 +373,7 @@ static boolean K_BotGenericPressItem(player_t *player, ticcmd_t *cmd, SINT8 dir)
}
/*--------------------------------------------------
static void K_BotItemGenericTap(player_t *player, ticcmd_t *cmd)
static void K_BotItemGenericTap(const player_t *player, ticcmd_t *cmd)
Item usage for generic items that you need to tap.
@ -386,8 +384,10 @@ static boolean K_BotGenericPressItem(player_t *player, ticcmd_t *cmd, SINT8 dir)
Return:-
None
--------------------------------------------------*/
static void K_BotItemGenericTap(player_t *player, ticcmd_t *cmd)
static void K_BotItemGenericTap(const player_t *player, ticcmd_t *cmd)
{
ZoneScoped;
if (K_ItemButtonWasDown(player) == false)
{
cmd->buttons |= BT_ATTACK;
@ -396,7 +396,7 @@ static void K_BotItemGenericTap(player_t *player, ticcmd_t *cmd)
}
/*--------------------------------------------------
static boolean K_BotRevealsGenericTrap(player_t *player, INT16 turnamt, boolean mine)
static boolean K_BotRevealsGenericTrap(const player_t *player, INT16 turnamt, boolean mine)
Decides if a bot is ready to reveal their trap item or not.
@ -408,8 +408,10 @@ static void K_BotItemGenericTap(player_t *player, ticcmd_t *cmd)
Return:-
true if we want the bot to reveal their banana, otherwise false.
--------------------------------------------------*/
static boolean K_BotRevealsGenericTrap(player_t *player, INT16 turnamt, boolean mine)
static boolean K_BotRevealsGenericTrap(const player_t *player, INT16 turnamt, boolean mine)
{
ZoneScoped;
const fixed_t coneDist = FixedMul(1280 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed));
if (abs(turnamt) >= KART_FULLTURN/2)
@ -443,7 +445,7 @@ static boolean K_BotRevealsGenericTrap(player_t *player, INT16 turnamt, boolean
}
/*--------------------------------------------------
static void K_BotItemGenericTrapShield(player_t *player, ticcmd_t *cmd, INT16 turnamt, boolean mine)
static void K_BotItemGenericTrapShield(const player_t *player, ticcmd_t *cmd, INT16 turnamt, boolean mine)
Item usage for Eggman shields.
@ -456,8 +458,10 @@ static boolean K_BotRevealsGenericTrap(player_t *player, INT16 turnamt, boolean
Return:-
None
--------------------------------------------------*/
static void K_BotItemGenericTrapShield(player_t *player, ticcmd_t *cmd, INT16 turnamt, boolean mine)
static void K_BotItemGenericTrapShield(const player_t *player, ticcmd_t *cmd, INT16 turnamt, boolean mine)
{
ZoneScoped;
if (player->itemflags & IF_ITEMOUT)
{
return;
@ -465,14 +469,14 @@ static void K_BotItemGenericTrapShield(player_t *player, ticcmd_t *cmd, INT16 tu
cmd->bot.itemconfirm++;
if (K_BotRevealsGenericTrap(player, turnamt, mine) || (player->botvars.itemconfirm++ > 5*TICRATE))
if (K_BotRevealsGenericTrap(player, turnamt, mine) || (player->botvars.itemconfirm > 5*TICRATE))
{
K_BotGenericPressItem(player, cmd, 0);
}
}
/*--------------------------------------------------
static void K_BotItemGenericOrbitShield(player_t *player, ticcmd_t *cmd)
static void K_BotItemGenericOrbitShield(const player_t *player, ticcmd_t *cmd)
Item usage for orbitting shields.
@ -483,8 +487,10 @@ static void K_BotItemGenericTrapShield(player_t *player, ticcmd_t *cmd, INT16 tu
Return:-
None
--------------------------------------------------*/
static void K_BotItemGenericOrbitShield(player_t *player, ticcmd_t *cmd)
static void K_BotItemGenericOrbitShield(const player_t *player, ticcmd_t *cmd)
{
ZoneScoped;
if (player->itemflags & IF_ITEMOUT)
{
return;
@ -494,7 +500,7 @@ static void K_BotItemGenericOrbitShield(player_t *player, ticcmd_t *cmd)
}
/*--------------------------------------------------
static void K_BotItemSneaker(player_t *player, ticcmd_t *cmd)
static void K_BotItemSneaker(const player_t *player, ticcmd_t *cmd)
Item usage for sneakers.
@ -507,6 +513,8 @@ static void K_BotItemGenericOrbitShield(player_t *player, ticcmd_t *cmd)
--------------------------------------------------*/
static void K_BotItemSneaker(player_t *player, ticcmd_t *cmd)
{
ZoneScoped;
if (P_IsObjectOnGround(player->mo) == false)
{
// Don't use while mid-air.
@ -543,8 +551,10 @@ static void K_BotItemSneaker(player_t *player, ticcmd_t *cmd)
Return:-
None
--------------------------------------------------*/
static void K_BotItemRocketSneaker(player_t *player, ticcmd_t *cmd)
static void K_BotItemRocketSneaker(const player_t *player, ticcmd_t *cmd)
{
ZoneScoped;
if (P_IsObjectOnGround(player->mo) == false)
{
// Don't use while mid-air.
@ -578,8 +588,10 @@ static void K_BotItemRocketSneaker(player_t *player, ticcmd_t *cmd)
Return:-
None
--------------------------------------------------*/
static void K_BotItemBanana(player_t *player, ticcmd_t *cmd, INT16 turnamt)
static void K_BotItemBanana(const player_t *player, ticcmd_t *cmd, INT16 turnamt)
{
ZoneScoped;
const fixed_t coneDist = FixedMul(1280 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed));
SINT8 throwdir = -1;
boolean tryLookback = false;
@ -635,8 +647,10 @@ static void K_BotItemBanana(player_t *player, ticcmd_t *cmd, INT16 turnamt)
Return:-
None
--------------------------------------------------*/
static void K_BotItemMine(player_t *player, ticcmd_t *cmd, INT16 turnamt)
static void K_BotItemMine(const player_t *player, ticcmd_t *cmd, INT16 turnamt)
{
ZoneScoped;
const fixed_t coneDist = FixedMul(1280 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed));
SINT8 throwdir = 0;
boolean tryLookback = false;
@ -698,8 +712,10 @@ static void K_BotItemMine(player_t *player, ticcmd_t *cmd, INT16 turnamt)
Return:-
None
--------------------------------------------------*/
static void K_BotItemLandmine(player_t *player, ticcmd_t *cmd, INT16 turnamt)
static void K_BotItemLandmine(const player_t *player, ticcmd_t *cmd, INT16 turnamt)
{
ZoneScoped;
const fixed_t coneDist = FixedMul(1280 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed));
player_t *target = NULL;
@ -714,7 +730,6 @@ static void K_BotItemLandmine(player_t *player, ticcmd_t *cmd, INT16 turnamt)
if (target != NULL)
{
K_ItemConfirmForTarget(player, cmd, target, player->botvars.difficulty);
cmd->buttons |= BT_LOOKBACK;
}
@ -736,8 +751,10 @@ static void K_BotItemLandmine(player_t *player, ticcmd_t *cmd, INT16 turnamt)
Return:-
None
--------------------------------------------------*/
static void K_BotItemEggman(player_t *player, ticcmd_t *cmd)
static void K_BotItemEggman(const player_t *player, ticcmd_t *cmd)
{
ZoneScoped;
const fixed_t coneDist = FixedMul(1280 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed));
const UINT8 stealth = K_EggboxStealth(player->mo->x, player->mo->y);
SINT8 throwdir = -1;
@ -761,9 +778,9 @@ static void K_BotItemEggman(player_t *player, ticcmd_t *cmd)
tryLookback = true;
}
if (stealth > 1 || player->itemroulette > 0)
if (stealth > 1 || player->itemroulette)
{
player->botvars.itemconfirm += player->botvars.difficulty * 4;
cmd->bot.itemconfirm += player->botvars.difficulty * 4;
throwdir = -1;
}
@ -779,7 +796,7 @@ static void K_BotItemEggman(player_t *player, ticcmd_t *cmd)
}
/*--------------------------------------------------
static boolean K_BotRevealsEggbox(player_t *player)
static boolean K_BotRevealsEggbox(const player_t *player)
Decides if a bot is ready to place their Eggman item or not.
@ -789,8 +806,10 @@ static void K_BotItemEggman(player_t *player, ticcmd_t *cmd)
Return:-
true if we want the bot to reveal their eggbox, otherwise false.
--------------------------------------------------*/
static boolean K_BotRevealsEggbox(player_t *player)
static boolean K_BotRevealsEggbox(const player_t *player)
{
ZoneScoped;
const fixed_t coneDist = FixedMul(1280 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed));
const UINT8 stealth = K_EggboxStealth(player->mo->x, player->mo->y);
player_t *target = NULL;
@ -819,7 +838,7 @@ static boolean K_BotRevealsEggbox(player_t *player)
}
/*--------------------------------------------------
static void K_BotItemEggmanShield(player_t *player, ticcmd_t *cmd)
static void K_BotItemEggmanShield(const player_t *player, ticcmd_t *cmd)
Item usage for Eggman shields.
@ -830,8 +849,10 @@ static boolean K_BotRevealsEggbox(player_t *player)
Return:-
None
--------------------------------------------------*/
static void K_BotItemEggmanShield(player_t *player, ticcmd_t *cmd)
static void K_BotItemEggmanShield(const player_t *player, ticcmd_t *cmd)
{
ZoneScoped;
if (player->itemflags & IF_EGGMANOUT)
{
return;
@ -839,14 +860,14 @@ static void K_BotItemEggmanShield(player_t *player, ticcmd_t *cmd)
cmd->bot.itemconfirm++;
if (K_BotRevealsEggbox(player) == true || (player->botvars.itemconfirm++ > 20*TICRATE))
if (K_BotRevealsEggbox(player) == true || (player->botvars.itemconfirm > 20*TICRATE))
{
K_BotGenericPressItem(player, cmd, 0);
}
}
/*--------------------------------------------------
static void K_BotItemEggmanExplosion(player_t *player, ticcmd_t *cmd)
static void K_BotItemEggmanExplosion(const player_t *player, ticcmd_t *cmd)
Item usage for Eggman explosions.
@ -857,8 +878,10 @@ static void K_BotItemEggmanShield(player_t *player, ticcmd_t *cmd)
Return:-
None
--------------------------------------------------*/
static void K_BotItemEggmanExplosion(player_t *player, ticcmd_t *cmd)
static void K_BotItemEggmanExplosion(const player_t *player, ticcmd_t *cmd)
{
ZoneScoped;
if (player->position == 1)
{
// Hey, we aren't gonna find anyone up here...
@ -870,7 +893,7 @@ static void K_BotItemEggmanExplosion(player_t *player, ticcmd_t *cmd)
}
/*--------------------------------------------------
static void K_BotItemOrbinaut(player_t *player, ticcmd_t *cmd)
static void K_BotItemOrbinaut(const player_t *player, ticcmd_t *cmd)
Item usage for Orbinaut throwing.
@ -883,6 +906,8 @@ static void K_BotItemEggmanExplosion(player_t *player, ticcmd_t *cmd)
--------------------------------------------------*/
static void K_BotItemOrbinaut(player_t *player, ticcmd_t *cmd)
{
ZoneScoped;
const fixed_t topspeed = K_GetKartSpeed(player, false, true);
fixed_t radius = FixedMul(2560 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed));
SINT8 throwdir = -1;
@ -928,9 +953,9 @@ static void K_BotItemOrbinaut(player_t *player, ticcmd_t *cmd)
}
/*--------------------------------------------------
static void K_BotItemDropTarget(player_t *player, ticcmd_t *cmd)
static void K_BotItemBallhog(const player_t *player, ticcmd_t *cmd)
Item usage for Drop Target throwing.
Item usage for Ballhog throwing.
Input Arguments:-
player - Bot to do this for.
@ -939,8 +964,87 @@ static void K_BotItemOrbinaut(player_t *player, ticcmd_t *cmd)
Return:-
None
--------------------------------------------------*/
static void K_BotItemDropTarget(player_t *player, INT16 turnamt, ticcmd_t *cmd)
static void K_BotItemBallhog(player_t *player, ticcmd_t *cmd)
{
ZoneScoped;
const fixed_t topspeed = K_GetKartSpeed(player, false, true);
fixed_t radius = FixedMul(2560 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed));
SINT8 throwdir = -1;
boolean tryLookback = false;
UINT8 snipeMul = 2;
player_t *target = NULL;
boolean hold = false;
if (player->speed > topspeed)
{
radius = FixedMul(radius, FixedDiv(player->speed, topspeed));
snipeMul = 3; // Confirm faster when you'll throw it with a bunch of extra speed!!
}
target = K_PlayerInCone(player, radius, 15, false);
if (target != NULL)
{
K_ItemConfirmForTarget(player, cmd, target, player->botvars.difficulty * snipeMul);
throwdir = 1;
}
else
{
target = K_PlayerInCone(player, radius, 15, true);
if (target != NULL)
{
K_ItemConfirmForTarget(player, cmd, target, player->botvars.difficulty);
throwdir = -1;
tryLookback = true;
}
}
if (tryLookback == true && throwdir == -1)
{
cmd->buttons |= BT_LOOKBACK;
}
if (target != NULL)
{
// Charge up!
hold = true;
}
else
{
// If we lose sight of the target, then we'll just
// let go and it'll do a partial-blast.
// If we've been waiting for too long though, then
// we'll go for the full charge :)
cmd->bot.itemconfirm++;
hold = (player->botvars.itemconfirm > 10*TICRATE);
}
if (hold == true)
{
cmd->throwdir = KART_FULLTURN * throwdir;
cmd->buttons |= BT_ATTACK;
}
}
/*--------------------------------------------------
static void K_BotItemDropTarget(const player_t *player, ticcmd_t *cmd, INT16 turnamt)
Item usage for Drop Target throwing.
Input Arguments:-
player - Bot to do this for.
cmd - Bot's ticcmd to edit.
turnamt - How hard they currently are turning.
Return:-
None
--------------------------------------------------*/
static void K_BotItemDropTarget(player_t *player, ticcmd_t *cmd, INT16 turnamt)
{
ZoneScoped;
const fixed_t topspeed = K_GetKartSpeed(player, false, true);
fixed_t radius = FixedMul(1280 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed));
SINT8 throwdir = -1;
@ -992,7 +1096,7 @@ static void K_BotItemDropTarget(player_t *player, INT16 turnamt, ticcmd_t *cmd)
}
/*--------------------------------------------------
static void K_BotItemJawz(player_t *player, ticcmd_t *cmd)
static void K_BotItemJawz(const player_t *player, ticcmd_t *cmd)
Item usage for Jawz throwing.
@ -1005,6 +1109,8 @@ static void K_BotItemDropTarget(player_t *player, INT16 turnamt, ticcmd_t *cmd)
--------------------------------------------------*/
static void K_BotItemJawz(player_t *player, ticcmd_t *cmd)
{
ZoneScoped;
const fixed_t topspeed = K_GetKartSpeed(player, false, true);
fixed_t radius = FixedMul(2560 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed));
SINT8 throwdir = 1;
@ -1072,9 +1178,9 @@ static void K_BotItemJawz(player_t *player, ticcmd_t *cmd)
}
/*--------------------------------------------------
static void K_BotItemLightning(player_t *player, ticcmd_t *cmd)
static void K_BotItemLightning(const player_t *player, ticcmd_t *cmd)
Item usage for Thunder Shield.
Item usage for Lightning Shield.
Input Arguments:-
player - Bot to do this for.
@ -1083,8 +1189,10 @@ static void K_BotItemJawz(player_t *player, ticcmd_t *cmd)
Return:-
None
--------------------------------------------------*/
static void K_BotItemLightning(player_t *player, ticcmd_t *cmd)
static void K_BotItemLightning(const player_t *player, ticcmd_t *cmd)
{
ZoneScoped;
fixed_t radius = 192 * player->mo->scale;
radius = Easing_Linear(FRACUNIT * player->botvars.difficulty / MAXBOTDIFFICULTY, 2*radius, radius);
@ -1102,7 +1210,7 @@ static void K_BotItemLightning(player_t *player, ticcmd_t *cmd)
}
/*--------------------------------------------------
static void K_BotItemBubble(player_t *player, ticcmd_t *cmd)
static void K_BotItemBubble(const player_t *player, ticcmd_t *cmd)
Item usage for Bubble Shield.
@ -1113,8 +1221,10 @@ static void K_BotItemLightning(player_t *player, ticcmd_t *cmd)
Return:-
None
--------------------------------------------------*/
static void K_BotItemBubble(player_t *player, ticcmd_t *cmd)
static void K_BotItemBubble(const player_t *player, ticcmd_t *cmd)
{
ZoneScoped;
boolean hold = false;
if (player->bubbleblowup <= 0)
@ -1180,7 +1290,7 @@ static void K_BotItemBubble(player_t *player, ticcmd_t *cmd)
}
/*--------------------------------------------------
static void K_BotItemFlame(player_t *player, ticcmd_t *cmd)
static void K_BotItemFlame(const player_t *player, ticcmd_t *cmd)
Item usage for Flame Shield.
@ -1191,15 +1301,17 @@ static void K_BotItemBubble(player_t *player, ticcmd_t *cmd)
Return:-
None
--------------------------------------------------*/
static void K_BotItemFlame(player_t *player, ticcmd_t *cmd)
static void K_BotItemFlame(const player_t *player, ticcmd_t *cmd)
{
ZoneScoped;
if (player->botvars.itemconfirm > 0)
{
cmd->bot.itemconfirm--;
}
else if (player->itemflags & IF_HOLDREADY)
{
INT32 flamemax = player->flamelength * flameseg;
INT32 flamemax = player->flamelength;
if (player->flamemeter < flamemax || flamemax == 0)
{
@ -1213,7 +1325,7 @@ static void K_BotItemFlame(player_t *player, ticcmd_t *cmd)
}
/*--------------------------------------------------
static void K_BotItemRings(player_t *player, ticcmd_t *cmd)
static void K_BotItemRings(const player_t *player, ticcmd_t *cmd)
Item usage for rings.
@ -1226,8 +1338,22 @@ static void K_BotItemFlame(player_t *player, ticcmd_t *cmd)
--------------------------------------------------*/
static void K_BotItemRings(player_t *player, ticcmd_t *cmd)
{
ZoneScoped;
INT32 saferingsval = 16 - K_GetKartRingPower(player, false);
if (leveltime < starttime)
{
// Don't use rings during POSITION!!
return;
}
if ((cmd->buttons & BT_ACCELERATE) == 0)
{
// Don't use rings if you're not trying to accelerate.
return;
}
if (P_IsObjectOnGround(player->mo) == false)
{
// Don't use while mid-air.
@ -1247,7 +1373,7 @@ static void K_BotItemRings(player_t *player, ticcmd_t *cmd)
}
/*--------------------------------------------------
static void K_BotItemRouletteMash(player_t *player, ticcmd_t *cmd)
static void K_BotItemRouletteMash(const player_t *player, ticcmd_t *cmd)
Item usage for item roulette mashing.
@ -1284,18 +1410,19 @@ static void K_BotItemRouletteMash(player_t *player, ticcmd_t *cmd)
}
/*--------------------------------------------------
void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt)
void K_BotItemUsage(const player_t *player, ticcmd_t *cmd, INT16 turnamt)
See header file for description.
--------------------------------------------------*/
void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt)
{
ZoneScoped;
if (player->itemflags & IF_USERINGS)
{
// Use rings!
if (leveltime > starttime)
if (player->rings > 0)
{
// Use rings!
K_BotItemRings(player, cmd);
}
}
@ -1343,7 +1470,6 @@ void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt)
case KITEM_SPB:
case KITEM_GROW:
case KITEM_SHRINK:
case KITEM_HYUDORO:
case KITEM_SUPERRING:
K_BotItemGenericTap(player, cmd);
break;
@ -1375,8 +1501,6 @@ void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt)
K_BotItemGenericOrbitShield(player, cmd);
}
else if (player->position != 1) // Hold onto orbiting items when in 1st :)
/* FALLTHRU */
case KITEM_BALLHOG:
{
K_BotItemOrbinaut(player, cmd);
}
@ -1402,8 +1526,12 @@ void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt)
}
break;
case KITEM_LANDMINE:
case KITEM_HYUDORO: // Function re-use, as they have about the same usage.
K_BotItemLandmine(player, cmd, turnamt);
break;
case KITEM_BALLHOG:
K_BotItemBallhog(player, cmd);
break;
case KITEM_DROPTARGET:
if (!(player->itemflags & IF_ITEMOUT))
{
@ -1411,7 +1539,7 @@ void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt)
}
else
{
K_BotItemDropTarget(player, turnamt, cmd);
K_BotItemDropTarget(player, cmd, turnamt);
}
break;
case KITEM_THUNDERSHIELD:
@ -1448,5 +1576,70 @@ void K_UpdateBotGameplayVarsItemUsage(player_t *player)
return;
}
player->botvars.itemconfirm += player->cmd.bot.itemconfirm;
if (player->cmd.bot.itemconfirm < 0 && abs(player->cmd.bot.itemconfirm) > player->botvars.itemconfirm)
{
player->botvars.itemconfirm = 0;
}
else
{
player->botvars.itemconfirm += player->cmd.bot.itemconfirm;
}
if (player->itemflags & IF_USERINGS)
{
;
}
else
{
if (player->itemroulette)
{
// Mashing behaviors
K_BotItemRouletteMash(player, &player->cmd);
return;
}
if (player->stealingtimer == 0)
{
if (player->eggmanexplode)
{
;
}
else if (player->itemflags & IF_EGGMANOUT)
{
;
}
else if (player->rocketsneakertimer > 0)
{
;
}
else
{
switch (player->itemtype)
{
default:
{
break;
}
case KITEM_FLAMESHIELD:
{
if (player->botvars.itemconfirm == 0
&& (player->itemflags & IF_HOLDREADY) == IF_HOLDREADY)
{
INT32 flamemax = player->flamelength;
if (player->flamemeter < flamemax || flamemax == 0)
{
;
}
else
{
player->botvars.itemconfirm = (3 * flamemax / 4) + (TICRATE / 2);
}
}
break;
}
}
}
}
}
}

View file

@ -1,15 +1,19 @@
// SONIC ROBO BLAST 2 KART
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2018-2020 by Sally "TehRealSalt" Cochenour
// Copyright (C) 2018-2020 by Kart Krew
// Copyright (C) 2024 by Sally "TehRealSalt" Cochenour
// Copyright (C) 2024 by Kart Krew
//
// 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 k_botsearch.c
/// \file k_botsearch.cpp
/// \brief Bot blockmap search functions
#include <algorithm>
#include <tracy/tracy/Tracy.hpp>
#include "doomdef.h"
#include "d_player.h"
#include "g_game.h"
@ -28,28 +32,7 @@
#include "r_things.h" // numskins
#include "p_slopes.h" // P_GetZAt
#include "m_perfstats.h"
struct globalsmuggle
{
mobj_t *botmo;
botprediction_t *predict;
fixed_t distancetocheck;
INT64 gotoAvgX[2], gotoAvgY[2];
UINT32 gotoObjs[2];
INT64 avoidAvgX[2], avoidAvgY[2];
UINT32 avoidObjs[2];
fixed_t annoyscore;
mobj_t *annoymo;
fixed_t closestlinedist;
fixed_t eggboxx, eggboxy;
UINT8 randomitems;
UINT8 eggboxes;
} globalsmuggle;
#include "k_objects.h"
/*--------------------------------------------------
static BlockItReturn_t K_FindEggboxes(mobj_t *thing)
@ -63,6 +46,14 @@ struct globalsmuggle
Return:-
BlockItReturn_t enum, see its definition for more information.
--------------------------------------------------*/
static struct eggboxSearch_s
{
fixed_t distancetocheck;
fixed_t eggboxx, eggboxy;
UINT8 randomitems;
UINT8 eggboxes;
} g_eggboxSearch;
static BlockItReturn_t K_FindEggboxes(mobj_t *thing)
{
fixed_t dist;
@ -77,20 +68,20 @@ static BlockItReturn_t K_FindEggboxes(mobj_t *thing)
return BMIT_CONTINUE;
}
dist = P_AproxDistance(thing->x - globalsmuggle.eggboxx, thing->y - globalsmuggle.eggboxy);
dist = P_AproxDistance(thing->x - g_eggboxSearch.eggboxx, thing->y - g_eggboxSearch.eggboxy);
if (dist > globalsmuggle.distancetocheck)
if (dist > g_eggboxSearch.distancetocheck)
{
return BMIT_CONTINUE;
}
if (thing->type == MT_RANDOMITEM)
{
globalsmuggle.randomitems++;
g_eggboxSearch.randomitems++;
}
else
{
globalsmuggle.eggboxes++;
g_eggboxSearch.eggboxes++;
}
return BMIT_CONTINUE;
@ -103,18 +94,20 @@ static BlockItReturn_t K_FindEggboxes(mobj_t *thing)
--------------------------------------------------*/
UINT8 K_EggboxStealth(fixed_t x, fixed_t y)
{
ZoneScoped;
INT32 xl, xh, yl, yh, bx, by;
globalsmuggle.eggboxx = x;
globalsmuggle.eggboxy = y;
globalsmuggle.distancetocheck = (mapobjectscale * 256);
globalsmuggle.randomitems = 0;
globalsmuggle.eggboxes = 0;
g_eggboxSearch.eggboxx = x;
g_eggboxSearch.eggboxy = y;
g_eggboxSearch.distancetocheck = (mapobjectscale * 256);
g_eggboxSearch.randomitems = 0;
g_eggboxSearch.eggboxes = 0;
xl = (unsigned)(globalsmuggle.eggboxx - globalsmuggle.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT;
xh = (unsigned)(globalsmuggle.eggboxx + globalsmuggle.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT;
yl = (unsigned)(globalsmuggle.eggboxy - globalsmuggle.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT;
yh = (unsigned)(globalsmuggle.eggboxy + globalsmuggle.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT;
xl = (unsigned)(g_eggboxSearch.eggboxx - g_eggboxSearch.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT;
xh = (unsigned)(g_eggboxSearch.eggboxx + g_eggboxSearch.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT;
yl = (unsigned)(g_eggboxSearch.eggboxy - g_eggboxSearch.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT;
yh = (unsigned)(g_eggboxSearch.eggboxy + g_eggboxSearch.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT;
BMBOUNDFIX(xl, xh, yl, yh);
@ -126,11 +119,11 @@ UINT8 K_EggboxStealth(fixed_t x, fixed_t y)
}
}
return (globalsmuggle.randomitems * (globalsmuggle.eggboxes + 1));
return (g_eggboxSearch.randomitems * (g_eggboxSearch.eggboxes + 1));
}
/*--------------------------------------------------
static boolean K_BotHatesThisSectorsSpecial(player_t *player, sector_t *sec)
static boolean K_BotHatesThisSectorsSpecial(const player_t *player, sector_t *sec)
Tells us if a bot will play more careful around
this sector's special type.
@ -175,7 +168,7 @@ static boolean K_BotHatesThisSectorsSpecial(player_t *player, sector_t *sec, con
}
/*--------------------------------------------------
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)
See header file for description.
--------------------------------------------------*/
@ -269,6 +262,19 @@ boolean K_BotHatesThisSector(player_t *player, sector_t *sec, fixed_t x, fixed_t
Return:-
None
--------------------------------------------------*/
static struct nudgeSearch_s
{
mobj_t *botmo;
angle_t angle;
fixed_t distancetocheck;
INT64 gotoAvgX[2], gotoAvgY[2];
UINT32 gotoObjs[2];
INT64 avoidAvgX[2], avoidAvgY[2];
UINT32 avoidObjs[2];
} g_nudgeSearch;
static void K_AddAttackObject(mobj_t *thing, UINT8 side, UINT8 weight)
{
fixed_t x, y;
@ -284,7 +290,7 @@ static void K_AddAttackObject(mobj_t *thing, UINT8 side, UINT8 weight)
x = thing->x;
y = thing->y;
a = R_PointToAngle2(globalsmuggle.botmo->x, globalsmuggle.botmo->y, x, y);
a = R_PointToAngle2(g_nudgeSearch.botmo->x, g_nudgeSearch.botmo->y, x, y);
dir = a + (side ? -ANGLE_90 : ANGLE_90);
x += FixedMul(thing->radius, FINECOSINE(dir >> ANGLETOFINESHIFT));
@ -295,9 +301,9 @@ static void K_AddAttackObject(mobj_t *thing, UINT8 side, UINT8 weight)
for (i = 0; i < weight; i++)
{
globalsmuggle.gotoAvgX[side] += x;
globalsmuggle.gotoAvgY[side] += y;
globalsmuggle.gotoObjs[side]++;
g_nudgeSearch.gotoAvgX[side] += x;
g_nudgeSearch.gotoAvgY[side] += y;
g_nudgeSearch.gotoObjs[side]++;
}
}
@ -329,7 +335,7 @@ static void K_AddDodgeObject(mobj_t *thing, UINT8 side, UINT8 weight)
x = thing->x;
y = thing->y;
a = R_PointToAngle2(globalsmuggle.botmo->x, globalsmuggle.botmo->y, x, y);
a = R_PointToAngle2(g_nudgeSearch.botmo->x, g_nudgeSearch.botmo->y, x, y);
dir = a + (side ? -ANGLE_90 : ANGLE_90);
x += FixedMul(thing->radius, FINECOSINE(dir >> ANGLETOFINESHIFT));
@ -340,9 +346,9 @@ static void K_AddDodgeObject(mobj_t *thing, UINT8 side, UINT8 weight)
for (i = 0; i < weight; i++)
{
globalsmuggle.avoidAvgX[side] += x;
globalsmuggle.avoidAvgY[side] += y;
globalsmuggle.avoidObjs[side]++;
g_nudgeSearch.avoidAvgX[side] += x;
g_nudgeSearch.avoidAvgY[side] += y;
g_nudgeSearch.avoidObjs[side]++;
}
}
@ -392,12 +398,13 @@ static boolean K_PlayerAttackSteer(mobj_t *thing, UINT8 side, UINT8 weight, bool
--------------------------------------------------*/
static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
{
ZoneScoped;
INT16 angledelta, anglediff;
fixed_t fulldist;
angle_t destangle, angle, predictangle;
angle_t destangle, angle;
UINT8 side = 0;
if (!globalsmuggle.botmo || P_MobjWasRemoved(globalsmuggle.botmo) || !globalsmuggle.botmo->player)
if (!g_nudgeSearch.botmo || P_MobjWasRemoved(g_nudgeSearch.botmo) || !g_nudgeSearch.botmo->player)
{
return BMIT_ABORT;
}
@ -407,32 +414,36 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
return BMIT_CONTINUE;
}
if (globalsmuggle.botmo == thing)
if (g_nudgeSearch.botmo == thing)
{
return BMIT_CONTINUE;
}
fulldist = R_PointToDist2(globalsmuggle.botmo->x, globalsmuggle.botmo->y, thing->x, thing->y) - thing->radius;
const fixed_t xDelta = abs(g_nudgeSearch.botmo->x - thing->x);
const fixed_t yDelta = abs(g_nudgeSearch.botmo->y - thing->y);
const fixed_t fullDist = (FixedMul(xDelta, xDelta) + FixedMul(yDelta, yDelta)) - FixedMul(thing->radius, thing->radius);
if (fulldist > globalsmuggle.distancetocheck)
if (fullDist > g_nudgeSearch.distancetocheck)
{
return BMIT_CONTINUE;
}
if (P_CheckSight(globalsmuggle.botmo, thing) == false)
#if 0
// this is very expensive to do, and probably not worth it.
if (P_CheckSight(g_nudgeSearch.botmo, thing) == false)
{
return BMIT_CONTINUE;
}
#endif
predictangle = R_PointToAngle2(globalsmuggle.botmo->x, globalsmuggle.botmo->y, globalsmuggle.predict->x, globalsmuggle.predict->y);
destangle = R_PointToAngle2(globalsmuggle.botmo->x, globalsmuggle.botmo->y, thing->x, thing->y);
angle = (predictangle - destangle);
destangle = R_PointToAngle2(g_nudgeSearch.botmo->x, g_nudgeSearch.botmo->y, thing->x, thing->y);
angle = (g_nudgeSearch.angle - destangle);
if (angle < ANGLE_180)
{
angledelta = AngleFixed(angle)>>FRACBITS;
}
else
else
{
angledelta = 360-(AngleFixed(angle)>>FRACBITS);
side = 1;
@ -448,7 +459,6 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
case MT_ORBINAUT:
case MT_ORBINAUT_SHIELD:
case MT_JAWZ:
case MT_JAWZ_DUD:
case MT_JAWZ_SHIELD:
case MT_SSMINE:
case MT_SSMINE_SHIELD:
@ -466,9 +476,9 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
break;
}
if (P_CanPickupItem(globalsmuggle.botmo->player, 1))
if (P_CanPickupItem(g_nudgeSearch.botmo->player, 1))
{
K_AddAttackObject(thing, side, 10);
K_AddAttackObject(thing, side, 20);
}
break;
case MT_EGGMANITEM:
@ -477,18 +487,18 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
break;
}
if (P_CanPickupItem(globalsmuggle.botmo->player, 1)) // Can pick up an actual item
if (P_CanPickupItem(g_nudgeSearch.botmo->player, 1)) // Can pick up an actual item
{
const UINT8 stealth = K_EggboxStealth(thing->x, thing->y);
const UINT8 requiredstealth = (globalsmuggle.botmo->player->botvars.difficulty * globalsmuggle.botmo->player->botvars.difficulty);
const UINT8 requiredstealth = (g_nudgeSearch.botmo->player->botvars.difficulty * g_nudgeSearch.botmo->player->botvars.difficulty);
if (stealth >= requiredstealth)
{
K_AddAttackObject(thing, side, 10);
K_AddAttackObject(thing, side, 20);
}
else
{
K_AddDodgeObject(thing, side, 10);
K_AddDodgeObject(thing, side, 20);
}
}
break;
@ -498,7 +508,7 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
break;
}
if (P_CanPickupItem(globalsmuggle.botmo->player, 3))
if (P_CanPickupItem(g_nudgeSearch.botmo->player, 3))
{
K_AddAttackObject(thing, side, 20);
}
@ -510,40 +520,39 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
break;
}
if ((RINGTOTAL(globalsmuggle.botmo->player) < 20 && !(globalsmuggle.botmo->player->pflags & PF_RINGLOCK)
&& P_CanPickupItem(globalsmuggle.botmo->player, 0))
if ((RINGTOTAL(g_nudgeSearch.botmo->player) < 20 && !(g_nudgeSearch.botmo->player->pflags & PF_RINGLOCK)
&& P_CanPickupItem(g_nudgeSearch.botmo->player, 0))
&& !thing->extravalue1
&& (globalsmuggle.botmo->player->itemtype != KITEM_THUNDERSHIELD))
&& (g_nudgeSearch.botmo->player->itemtype != KITEM_THUNDERSHIELD))
{
K_AddAttackObject(thing, side, (RINGTOTAL(globalsmuggle.botmo->player) < 3) ? 5 : 1);
K_AddAttackObject(thing, side, (RINGTOTAL(g_nudgeSearch.botmo->player) < 3) ? 5 : 1);
}
break;
case MT_PLAYER:
if (thing->player
&& !thing->player->spectator
&& !thing->player->hyudorotimer
&& !globalsmuggle.botmo->player->hyudorotimer)
&& !g_nudgeSearch.botmo->player->hyudorotimer)
{
// There REALLY ought to be a better way to handle this logic, right?!
// Squishing
if (K_PlayerAttackSteer(thing, side, 20,
globalsmuggle.botmo->scale > thing->scale + (mapobjectscale/8),
thing->scale > globalsmuggle.botmo->scale + (mapobjectscale/8)
))
g_nudgeSearch.botmo->scale > thing->scale,
thing->scale > g_nudgeSearch.botmo->scale))
{
break;
}
// Invincibility
else if (K_PlayerAttackSteer(thing, side, 20,
globalsmuggle.botmo->player->invincibilitytimer,
g_nudgeSearch.botmo->player->invincibilitytimer,
thing->player->invincibilitytimer
))
{
break;
}
// thunder Shield
// Thunder Shield
else if (K_PlayerAttackSteer(thing, side, 20,
globalsmuggle.botmo->player->itemtype == KITEM_THUNDERSHIELD,
g_nudgeSearch.botmo->player->itemtype == KITEM_THUNDERSHIELD,
thing->player->itemtype == KITEM_THUNDERSHIELD
))
{
@ -551,7 +560,7 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
}
// Bubble Shield
else if (K_PlayerAttackSteer(thing, side, 20,
globalsmuggle.botmo->player->itemtype == KITEM_BUBBLESHIELD,
g_nudgeSearch.botmo->player->itemtype == KITEM_BUBBLESHIELD,
thing->player->itemtype == KITEM_BUBBLESHIELD
))
{
@ -559,7 +568,7 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
}
// Flame Shield
else if (K_PlayerAttackSteer(thing, side, 20,
globalsmuggle.botmo->player->itemtype == KITEM_FLAMESHIELD,
g_nudgeSearch.botmo->player->itemtype == KITEM_FLAMESHIELD,
thing->player->itemtype == KITEM_FLAMESHIELD
))
{
@ -568,24 +577,24 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
// Has held item shield
else if (K_PlayerAttackSteer(thing, side, 20,
(thing->player->itemflags & (IF_ITEMOUT|IF_EGGMANOUT)),
(globalsmuggle.botmo->player->itemflags & (IF_ITEMOUT|IF_EGGMANOUT))
(g_nudgeSearch.botmo->player->itemflags & (IF_ITEMOUT|IF_EGGMANOUT))
))
{
break;
}
// Ring Sting
/*else if (K_PlayerAttackSteer(thing, side, 20,
else if (K_PlayerAttackSteer(thing, side, 20,
thing->player->rings <= 0,
globalsmuggle.botmo->player->rings <= 0
g_nudgeSearch.botmo->player->rings <= 0
))
{
break;
}*/
}
else
{
// After ALL of that, we can do standard bumping
fixed_t ourweight = K_GetMobjWeight(globalsmuggle.botmo, thing);
fixed_t theirweight = K_GetMobjWeight(thing, globalsmuggle.botmo);
fixed_t ourweight = K_GetMobjWeight(g_nudgeSearch.botmo, thing);
fixed_t theirweight = K_GetMobjWeight(thing, g_nudgeSearch.botmo);
fixed_t weightdiff = 0;
if (anglediff >= 90)
@ -644,17 +653,20 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
}
/*--------------------------------------------------
void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
void K_NudgePredictionTowardsObjects(botprediction_t *predict, const player_t *player)
See header file for description.
--------------------------------------------------*/
void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
void K_NudgePredictionTowardsObjects(botprediction_t *predict, const player_t *player)
{
ZoneScoped;
const precise_t time = I_GetPreciseTime();
INT32 xl, xh, yl, yh, bx, by;
fixed_t distToPredict = 0;
fixed_t radToPredict = 0;
angle_t angleToPredict = 0;
fixed_t avgX = 0, avgY = 0;
@ -677,31 +689,32 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
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);
globalsmuggle.distancetocheck = distToPredict >> 1;
radToPredict = distToPredict >> 1;
g_nudgeSearch.distancetocheck = FixedMul(radToPredict, radToPredict);
baseNudge = predict->radius * 2;
maxNudge = distToPredict;
baseNudge = predict->baseRadius >> 3;
maxNudge = predict->baseRadius - baseNudge;
globalsmuggle.botmo = player->mo;
globalsmuggle.predict = predict;
g_nudgeSearch.botmo = player->mo;
g_nudgeSearch.angle = angleToPredict;
// silly variable reuse
avgX = globalsmuggle.botmo->x + FixedMul(globalsmuggle.distancetocheck, FINECOSINE(angleToPredict >> ANGLETOFINESHIFT));
avgY = globalsmuggle.botmo->y + FixedMul(globalsmuggle.distancetocheck, FINESINE(angleToPredict >> ANGLETOFINESHIFT));
avgX = g_nudgeSearch.botmo->x + FixedMul(radToPredict, FINECOSINE(angleToPredict >> ANGLETOFINESHIFT));
avgY = g_nudgeSearch.botmo->y + FixedMul(radToPredict, FINESINE(angleToPredict >> ANGLETOFINESHIFT));
for (i = 0; i < 2; i++)
{
globalsmuggle.gotoAvgX[i] = globalsmuggle.gotoAvgY[i] = 0;
globalsmuggle.gotoObjs[i] = 0;
g_nudgeSearch.gotoAvgX[i] = g_nudgeSearch.gotoAvgY[i] = 0;
g_nudgeSearch.gotoObjs[i] = 0;
globalsmuggle.avoidAvgX[i] = globalsmuggle.avoidAvgY[i] = 0;
globalsmuggle.avoidObjs[i] = 0;
g_nudgeSearch.avoidAvgX[i] = g_nudgeSearch.avoidAvgY[i] = 0;
g_nudgeSearch.avoidObjs[i] = 0;
}
xl = (unsigned)(avgX - (globalsmuggle.distancetocheck + MAXRADIUS) - bmaporgx)>>MAPBLOCKSHIFT;
xh = (unsigned)(avgX + (globalsmuggle.distancetocheck + MAXRADIUS) - bmaporgx)>>MAPBLOCKSHIFT;
yl = (unsigned)(avgY - (globalsmuggle.distancetocheck + MAXRADIUS) - bmaporgy)>>MAPBLOCKSHIFT;
yh = (unsigned)(avgY + (globalsmuggle.distancetocheck + MAXRADIUS) - bmaporgy)>>MAPBLOCKSHIFT;
xl = (unsigned)(avgX - (radToPredict + MAXRADIUS) - bmaporgx)>>MAPBLOCKSHIFT;
xh = (unsigned)(avgX + (radToPredict + MAXRADIUS) - bmaporgx)>>MAPBLOCKSHIFT;
yl = (unsigned)(avgY - (radToPredict + MAXRADIUS) - bmaporgy)>>MAPBLOCKSHIFT;
yh = (unsigned)(avgY + (radToPredict + MAXRADIUS) - bmaporgy)>>MAPBLOCKSHIFT;
BMBOUNDFIX(xl, xh, yl, yh);
@ -714,9 +727,9 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
}
// Handle dodge characters
if (globalsmuggle.avoidObjs[1] > 0 || globalsmuggle.avoidObjs[0] > 0)
if (g_nudgeSearch.avoidObjs[1] > 0 || g_nudgeSearch.avoidObjs[0] > 0)
{
if (globalsmuggle.avoidObjs[1] > globalsmuggle.avoidObjs[0])
if (g_nudgeSearch.avoidObjs[1] > g_nudgeSearch.avoidObjs[0])
{
gotoSide = 1;
}
@ -725,8 +738,8 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
gotoSide = 0;
}
avgX = (globalsmuggle.avoidAvgX[gotoSide] / globalsmuggle.avoidObjs[gotoSide]) * mapobjectscale;
avgY = (globalsmuggle.avoidAvgY[gotoSide] / globalsmuggle.avoidObjs[gotoSide]) * mapobjectscale;
avgX = (g_nudgeSearch.avoidAvgX[gotoSide] / g_nudgeSearch.avoidObjs[gotoSide]) * mapobjectscale;
avgY = (g_nudgeSearch.avoidAvgY[gotoSide] / g_nudgeSearch.avoidObjs[gotoSide]) * mapobjectscale;
avgDist = R_PointToDist2(
avgX, avgY,
@ -734,9 +747,7 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
);
// High handling characters dodge better
nudgeDist = ((9 - globalsmuggle.botmo->player->kartweight) + 1) * baseNudge;
maxNudge = max(distToPredict - predict->radius, predict->radius);
nudgeDist = ((9 - g_nudgeSearch.botmo->player->kartweight) + 1) * baseNudge;
if (nudgeDist > maxNudge)
{
nudgeDist = maxNudge;
@ -750,6 +761,7 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
predict->x += FixedMul(nudgeDist, FINECOSINE(nudgeDir >> ANGLETOFINESHIFT));
predict->y += FixedMul(nudgeDist, FINESINE(nudgeDir >> ANGLETOFINESHIFT));
predict->radius = std::max(predict->radius - nudgeDist, baseNudge);
distToPredict = R_PointToDist2(player->mo->x, player->mo->y, predict->x, predict->y);
@ -770,7 +782,7 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
// We don't want to pick contradictory sides, so keep the old side otherwise,
// even if there's more to grab on the other side.
if (globalsmuggle.gotoObjs[1] > globalsmuggle.gotoObjs[0])
if (g_nudgeSearch.gotoObjs[1] > g_nudgeSearch.gotoObjs[0])
{
gotoSide = 1;
}
@ -781,7 +793,7 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
}
// Check if our side is invalid, if so, don't do the code below.
if (gotoSide != -1 && globalsmuggle.gotoObjs[gotoSide] == 0)
if (gotoSide != -1 && g_nudgeSearch.gotoObjs[gotoSide] == 0)
{
// Do not use a side
gotoSide = -1;
@ -789,8 +801,8 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
if (gotoSide != -1)
{
avgX = (globalsmuggle.gotoAvgX[gotoSide] / globalsmuggle.gotoObjs[gotoSide]) * mapobjectscale;
avgY = (globalsmuggle.gotoAvgY[gotoSide] / globalsmuggle.gotoObjs[gotoSide]) * mapobjectscale;
avgX = (g_nudgeSearch.gotoAvgX[gotoSide] / g_nudgeSearch.gotoObjs[gotoSide]) * mapobjectscale;
avgY = (g_nudgeSearch.gotoAvgY[gotoSide] / g_nudgeSearch.gotoObjs[gotoSide]) * mapobjectscale;
avgDist = R_PointToDist2(
predict->x, predict->y,
@ -798,9 +810,7 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
);
// Acceleration characters are more aggressive
nudgeDist = ((9 - globalsmuggle.botmo->player->kartspeed) + 1) * baseNudge;
maxNudge = max(distToPredict - predict->radius, predict->radius);
nudgeDist = ((9 - g_nudgeSearch.botmo->player->kartspeed) + 1) * baseNudge;
if (nudgeDist > maxNudge)
{
nudgeDist = maxNudge;
@ -810,6 +820,7 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
{
predict->x = avgX;
predict->y = avgY;
predict->radius = baseNudge;
}
else
{
@ -821,6 +832,7 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
predict->x += FixedMul(nudgeDist, FINECOSINE(nudgeDir >> ANGLETOFINESHIFT));
predict->y += FixedMul(nudgeDist, FINESINE(nudgeDir >> ANGLETOFINESHIFT));
predict->radius = std::max(predict->radius - nudgeDist, baseNudge);
//distToPredict = R_PointToDist2(player->mo->x, player->mo->y, predict->x, predict->y);
}
@ -841,6 +853,15 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
Return:-
BlockItReturn_t enum, see its definition for more information.
--------------------------------------------------*/
static struct bullySearch_s
{
mobj_t *botmo;
fixed_t distancetocheck;
fixed_t annoyscore;
mobj_t *annoymo;
} g_bullySearch;
static BlockItReturn_t K_FindPlayersToBully(mobj_t *thing)
{
INT16 anglediff;
@ -848,7 +869,7 @@ static BlockItReturn_t K_FindPlayersToBully(mobj_t *thing)
fixed_t ourweight, theirweight, weightdiff;
angle_t ourangle, destangle, angle;
if (!globalsmuggle.botmo || P_MobjWasRemoved(globalsmuggle.botmo) || !globalsmuggle.botmo->player)
if (!g_bullySearch.botmo || P_MobjWasRemoved(g_bullySearch.botmo) || !g_bullySearch.botmo->player)
{
return BMIT_ABORT;
}
@ -863,40 +884,40 @@ static BlockItReturn_t K_FindPlayersToBully(mobj_t *thing)
return BMIT_CONTINUE;
}
if (globalsmuggle.botmo == thing)
if (g_bullySearch.botmo == thing)
{
return BMIT_CONTINUE;
}
fulldist = R_PointToDist2(globalsmuggle.botmo->x, globalsmuggle.botmo->y, thing->x, thing->y) - thing->radius;
fulldist = R_PointToDist2(g_bullySearch.botmo->x, g_bullySearch.botmo->y, thing->x, thing->y) - thing->radius;
if (fulldist > globalsmuggle.distancetocheck)
if (fulldist > g_bullySearch.distancetocheck)
{
return BMIT_CONTINUE;
}
if (P_CheckSight(globalsmuggle.botmo, thing) == false)
if (P_CheckSight(g_bullySearch.botmo, thing) == false)
{
return BMIT_CONTINUE;
}
ourangle = globalsmuggle.botmo->angle;
destangle = R_PointToAngle2(globalsmuggle.botmo->x, globalsmuggle.botmo->y, thing->x, thing->y);
ourangle = g_bullySearch.botmo->angle;
destangle = R_PointToAngle2(g_bullySearch.botmo->x, g_bullySearch.botmo->y, thing->x, thing->y);
angle = (ourangle - destangle);
if (angle < ANGLE_180)
{
anglediff = AngleFixed(angle)>>FRACBITS;
}
else
else
{
anglediff = 360-(AngleFixed(angle)>>FRACBITS);
}
anglediff = abs(anglediff);
ourweight = K_GetMobjWeight(globalsmuggle.botmo, thing);
theirweight = K_GetMobjWeight(thing, globalsmuggle.botmo);
ourweight = K_GetMobjWeight(g_bullySearch.botmo, thing);
theirweight = K_GetMobjWeight(thing, g_bullySearch.botmo);
weightdiff = 0;
if (anglediff >= 90)
@ -908,37 +929,39 @@ static BlockItReturn_t K_FindPlayersToBully(mobj_t *thing)
weightdiff = ourweight - theirweight;
}
if (weightdiff > mapobjectscale && weightdiff > globalsmuggle.annoyscore)
if (weightdiff > mapobjectscale && weightdiff > g_bullySearch.annoyscore)
{
globalsmuggle.annoyscore = weightdiff;
globalsmuggle.annoymo = thing;
g_bullySearch.annoyscore = weightdiff;
g_bullySearch.annoymo = thing;
}
return BMIT_CONTINUE;
}
/*--------------------------------------------------
INT32 K_PositionBully(player_t *player)
INT32 K_PositionBully(const player_t *player)
See header file for description.
--------------------------------------------------*/
INT32 K_PositionBully(player_t *player)
INT32 K_PositionBully(const player_t *player)
{
ZoneScoped;
INT32 xl, xh, yl, yh, bx, by;
angle_t ourangle, destangle, angle;
INT16 anglediff;
globalsmuggle.botmo = player->mo;
globalsmuggle.distancetocheck = 1024*player->mo->scale;
g_bullySearch.botmo = player->mo;
g_bullySearch.distancetocheck = 1024*player->mo->scale;
globalsmuggle.annoymo = NULL;
globalsmuggle.annoyscore = 0;
g_bullySearch.annoymo = NULL;
g_bullySearch.annoyscore = 0;
xl = (unsigned)(globalsmuggle.botmo->x - globalsmuggle.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT;
xh = (unsigned)(globalsmuggle.botmo->x + globalsmuggle.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT;
yl = (unsigned)(globalsmuggle.botmo->y - globalsmuggle.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT;
yh = (unsigned)(globalsmuggle.botmo->y + globalsmuggle.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT;
xl = (unsigned)(g_bullySearch.botmo->x - g_bullySearch.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT;
xh = (unsigned)(g_bullySearch.botmo->x + g_bullySearch.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT;
yl = (unsigned)(g_bullySearch.botmo->y - g_bullySearch.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT;
yh = (unsigned)(g_bullySearch.botmo->y + g_bullySearch.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT;
BMBOUNDFIX(xl, xh, yl, yh);
@ -950,25 +973,25 @@ INT32 K_PositionBully(player_t *player)
}
}
if (globalsmuggle.annoymo == NULL)
if (g_bullySearch.annoymo == NULL)
{
return INT32_MAX;
}
ourangle = globalsmuggle.botmo->angle;
destangle = R_PointToAngle2(globalsmuggle.botmo->x, globalsmuggle.botmo->y, globalsmuggle.annoymo->x, globalsmuggle.annoymo->y);
ourangle = g_bullySearch.botmo->angle;
destangle = R_PointToAngle2(g_bullySearch.botmo->x, g_bullySearch.botmo->y, g_bullySearch.annoymo->x, g_bullySearch.annoymo->y);
angle = (ourangle - destangle);
if (angle < ANGLE_180)
{
anglediff = AngleFixed(angle)>>FRACBITS;
}
else
else
{
anglediff = 360-(AngleFixed(angle)>>FRACBITS);
}
if (anglediff < 30)
if (abs(anglediff) < 30)
return 0;
if (anglediff < 0)

View file

@ -721,12 +721,12 @@ boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2)
{
// Counter desyncs
/*mobj_t *oldthing = thing;
mobj_t *oldtm.thing = tm.thing;
mobj_t *oldg_tm.thing = g_tm.thing;
P_Thrust(tm.thing, R_PointToAngle2(thing->x, thing->y, tm.thing->x, tm.thing->y), 4*thing->scale);
P_Thrust(g_tm.thing, R_PointToAngle2(thing->x, thing->y, g_tm.thing->x, g_tm.thing->y), 4*thing->scale);
thing = oldthing;
P_SetTarget(&tm.thing, oldtm.thing);*/
P_SetTarget(&g_tm.thing, oldg_tm.thing);*/
if (P_PlayerInPain(t2->player)
|| t2->player->flashing || t2->player->hyudorotimer

View file

@ -102,7 +102,7 @@ INT16 K_CalculateGPRankPoints(UINT8 position, UINT8 numplayers)
--------------------------------------------------*/
UINT8 K_BotDefaultSkin(void)
{
const char *defaultbotskinname = "eggrobo";
const char *defaultbotskinname = "eggman";
INT32 defaultbotskin = R_SkinAvailable(defaultbotskinname);
if (defaultbotskin == -1)
@ -114,6 +114,21 @@ UINT8 K_BotDefaultSkin(void)
return (UINT8)defaultbotskin;
}
/*--------------------------------------------------
UINT8 K_GetGPPlayerCount(UINT8 humans)
See header file for description.
--------------------------------------------------*/
UINT8 K_GetGPPlayerCount(UINT8 humans)
{
// 1P -> 8 total
// 2P -> 8 total
// 3P -> 12 total
// 4P -> 16 total
return max(min(humans * 4, MAXPLAYERS), 8);
}
/*--------------------------------------------------
void K_InitGrandPrixBots(void)
@ -132,7 +147,7 @@ void K_InitGrandPrixBots(void)
UINT8 numplayers = 0;
UINT8 competitors[MAXSPLITSCREENPLAYERS];
UINT8 usableskins;
UINT8 usableskins, skincount = numskins;
UINT8 grabskins[MAXSKINS+1];
UINT8 botskinlist[MAXPLAYERS];
@ -145,7 +160,7 @@ void K_InitGrandPrixBots(void)
memset(botskinlist, defaultbotskin, sizeof (botskinlist));
// Init usable bot skins list
for (usableskins = 0; usableskins < numskins; usableskins++)
for (usableskins = 0; usableskins < skincount; usableskins++)
{
grabskins[usableskins] = usableskins;
}
@ -185,6 +200,13 @@ void K_InitGrandPrixBots(void)
{
if (playeringame[i])
{
if (players[i].bot == true)
{
// Remove existing bots.
CL_RemovePlayer(i, KR_LEAVE);
continue;
}
if (numplayers < MAXSPLITSCREENPLAYERS && !players[i].spectator)
{
competitors[numplayers] = i;
@ -193,27 +215,13 @@ void K_InitGrandPrixBots(void)
}
else
{
players[i].spectator = true; // force spectate for all other players, if they happen to exist?
P_SetPlayerSpectator(i); // force spectate for all other players, if they happen to exist?
}
}
}
if (numplayers > 2)
{
// Add 3 bots per player beyond 2P
playercount += (numplayers-2) * 3;
}
if (numbosswaypoints > 0 && !waypointcap)
{
CONS_Alert(CONS_ERROR, "Bots do not work on maps using the legacy checkpoint system.\nPlease consider using waypoints instead if bot support is desired!\n");
wantedbots = 0;
}
else
{
wantedbots = playercount - numplayers;
}
playercount = K_GetGPPlayerCount(numplayers);
wantedbots = playercount - numplayers;
// Create rival list
if (numplayers > 0)
@ -223,8 +231,10 @@ void K_InitGrandPrixBots(void)
for (j = 0; j < numplayers; j++)
{
player_t *p = &players[competitors[j]];
char *rivalname = skins[p->skin].rivals[i];
INT32 rivalnum = R_SkinAvailable(rivalname);
INT32 rivalnum;
const char *rivalname = skins[p->skin].rivals[i];
rivalnum = R_SkinAvailable(rivalname);
// Intentionally referenced before (currently dummied out) unlock check. Such a tease!
if (rivalnum != -1 && grabskins[(UINT8)rivalnum] != MAXSKINS)
@ -239,12 +249,16 @@ void K_InitGrandPrixBots(void)
// Rearrange usable bot skins list to prevent gaps for randomised selection
for (i = 0; i < usableskins; i++)
{
if (!(grabskins[i] == MAXSKINS /*|| K_SkinLocked(grabskins[i])*/))
if (!(grabskins[i] == MAXSKINS || !R_SkinUsable(-1, grabskins[i])))
{
continue;
while (usableskins > i && (grabskins[usableskins] == MAXSKINS /*|| K_SkinLocked(grabskins[i])*/))
}
while (usableskins > i && (grabskins[usableskins] == MAXSKINS || !R_SkinUsable(-1, grabskins[usableskins])))
{
usableskins--;
}
grabskins[i] = grabskins[usableskins];
grabskins[usableskins] = MAXSKINS;
}
@ -258,7 +272,7 @@ void K_InitGrandPrixBots(void)
if (usableskins > 0)
{
UINT8 index = M_RandomKey(usableskins);
UINT8 index = P_RandomKey(usableskins);
skinnum = grabskins[index];
grabskins[index] = grabskins[--usableskins];
}

View file

@ -80,6 +80,21 @@ INT16 K_CalculateGPRankPoints(UINT8 position, UINT8 numplayers);
UINT8 K_BotDefaultSkin(void);
/*--------------------------------------------------
UINT8 K_GetGPPlayerCount(UINT8 humans)
Counts the number of total players,
including humans and bots, to put into
a GP session.
Input Arguments:-
humans - Number of human players.
Return:-
Number of both human players and CPU.
--------------------------------------------------*/
UINT8 K_GetGPPlayerCount(UINT8 humans);
/*--------------------------------------------------
void K_InitGrandPrixBots(void);

View file

@ -3235,6 +3235,12 @@ static void K_GetKartBoostPower(player_t *player)
ADDBOOST(FRACUNIT/5, 4*FRACUNIT); // + 20% top speed, + 400% acceleration
}
// This should always remain the last boost stack before tethering
if (player->botvars.rubberband > FRACUNIT && K_PlayerUsesBotMovement(player) == true)
{
ADDBOOST(player->botvars.rubberband - FRACUNIT, 0);
}
player->boostpower = boostpower;
// value smoothing
@ -3327,7 +3333,8 @@ fixed_t K_GetKartSpeed(player_t *player, boolean doboostpower, boolean dorubberb
if (K_PlayerUsesBotMovement(player))
{
// Increase bot speed by 1-10% depending on difficulty
fixed_t add = (player->botvars.difficulty * (FRACUNIT/10)) / DIFFICULTBOT;
const fixed_t modifier = K_BotMapModifier();
fixed_t add = ((player->botvars.difficulty-1) * FixedMul(FRACUNIT / 10, modifier)) / (DIFFICULTBOT-1);
finalspeed = FixedMul(finalspeed, FRACUNIT + add);
if (player->bot && player->botvars.rival)
@ -7475,7 +7482,7 @@ boolean K_SafeRespawnPosition(mobj_t * mo)
po->validcount = validcount;
if (!P_BBoxInsidePolyobj(po, tm.bbox)
if (!P_BBoxInsidePolyobj(po, g_tm.bbox)
|| !(po->flags & POF_SOLID))
{
plink = (polymaplink_t *)(plink->link.next);
@ -8904,7 +8911,7 @@ static void K_AdjustPlayerFriction(player_t *player)
// Reduce friction after hitting a spring
if (player->tiregrease)
{
player->mo->friction += ((FRACUNIT - prevfriction) / greasetics) * player->tiregrease;
player->mo->friction += ((FRACUNIT - FRACUNIT) / greasetics) * player->tiregrease;
}
// Karma ice physics
@ -8942,6 +8949,14 @@ static void K_AdjustPlayerFriction(player_t *player)
// Remove this line once they can drift.
player->mo->friction -= extraFriction;
// Bots gain more traction as they rubberband.
const fixed_t traction_value = FixedMul(player->botvars.rubberband, max(FRACUNIT, K_BotMapModifier()));
if (traction_value > FRACUNIT)
{
const fixed_t traction_mul = traction_value - FRACUNIT;
player->mo->friction -= FixedMul(extraFriction, traction_mul);
}
if (player->mo->friction > FRACUNIT)
player->mo->friction = FRACUNIT;
if (player->mo->friction < 0)
@ -8949,7 +8964,6 @@ static void K_AdjustPlayerFriction(player_t *player)
player->mo->movefactor = FixedDiv(ORIG_FRICTION, player->mo->friction);
if (player->mo->movefactor < FRACUNIT)
player->mo->movefactor = 19*player->mo->movefactor - 18*FRACUNIT;
else

View file

@ -1,13 +1,13 @@
// SONIC ROBO BLAST 2 KART
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2018-2020 by Sean "Sryder" Ryder
// Copyright (C) 2018-2020 by Kart Krew
// Copyright (C) 2024 by Sean "Sryder" Ryder
// Copyright (C) 2024 by Kart Krew
//
// 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 k_waypoint.c
/// \file k_waypoint.cpp
/// \brief Waypoint handling from the relevant mobjs
/// Setup and interfacing with waypoints for the main game
@ -21,6 +21,13 @@
#include "g_game.h"
#include "p_slopes.h"
#include "cxxutil.hpp"
#include <algorithm>
#include <vector>
#include <fmt/format.h>
// The number of sparkles per waypoint connection in the waypoint visualisation
static const UINT32 SPARKLES_PER_CONNECTION = 16U;
@ -350,7 +357,6 @@ static void K_CompareOverlappingWaypoint
const boolean huntbackwards = false;
boolean pathfindsuccess = false;
path_t pathtofinish = {0};
Z_Free(pathtofinish.array);
if (K_GetWaypointIsShortcut(*bestwaypoint) == false
&& K_GetWaypointIsShortcut(checkwaypoint) == true)
@ -369,6 +375,8 @@ static void K_CompareOverlappingWaypoint
*bestwaypoint = checkwaypoint;
*bestfindist = pathtofinish.totaldist;
}
Z_Free(pathtofinish.array);
}
}
@ -391,7 +399,7 @@ waypoint_t *K_GetBestWaypointForMobj(mobj_t *const mobj, waypoint_t *const hint)
fixed_t checkdist = INT32_MAX;
fixed_t bestfindist = INT32_MAX;
void sort_waypoint (waypoint_t *const checkwaypoint)
auto sort_waypoint = [&](waypoint_t *const checkwaypoint)
{
if (!K_GetWaypointIsEnabled(checkwaypoint))
{
@ -1853,7 +1861,7 @@ static waypoint_t *K_SearchWaypointGraph(
I_Assert(conditionalfunc != NULL);
I_Assert(firstwaypoint != NULL);
visitedarray = Z_Calloc(numwaypoints * sizeof(boolean), PU_STATIC, NULL);
visitedarray = static_cast<boolean*>(Z_Calloc(numwaypoints * sizeof(boolean), PU_STATIC, NULL));
foundwaypoint = K_TraverseWaypoints(firstwaypoint, conditionalfunc, condition, visitedarray);
Z_Free(visitedarray);
@ -1975,6 +1983,8 @@ static UINT32 K_SetupCircuitLength(void)
if ((mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE) == LF_SECTIONRACE)
{
path_t bestsprintpath = {0};
auto sprint_finally = srb2::finally([&bestsprintpath]() { Z_Free(bestsprintpath.array); });
const boolean useshortcuts = false;
const boolean huntbackwards = true;
const UINT32 traveldist = UINT32_MAX - UINT16_MAX; // Go as far back as possible. Not exactly UINT32_MAX to avoid possible overflow.
@ -1991,8 +2001,6 @@ static UINT32 K_SetupCircuitLength(void)
{
startingwaypoint = (waypoint_t *)bestsprintpath.array[ bestsprintpath.numnodes - 1 ].nodedata;
}
Z_Free(bestsprintpath.array);
}
else
{
@ -2000,6 +2008,8 @@ static UINT32 K_SetupCircuitLength(void)
waypoint_t fakefinishline = *finishline;
path_t bestcircuitpath = {0};
auto circuit_finally = srb2::finally([&bestcircuitpath]() { Z_Free(bestcircuitpath.array); });
const boolean useshortcuts = false;
const boolean huntbackwards = false;
@ -2013,7 +2023,6 @@ static UINT32 K_SetupCircuitLength(void)
// this instead would be the most ideal
startingwaypoint = finishline->nextwaypoints[0];
}
Z_Free(bestcircuitpath.array);
}
return circuitlength;
@ -2039,16 +2048,18 @@ static void K_AddPrevToWaypoint(waypoint_t *const waypoint, waypoint_t *const pr
I_Assert(prevwaypoint != NULL);
waypoint->numprevwaypoints++;
waypoint->prevwaypoints =
Z_Realloc(waypoint->prevwaypoints, waypoint->numprevwaypoints * sizeof(waypoint_t *), PU_LEVEL, NULL);
waypoint->prevwaypoints = static_cast<waypoint_t**>(
Z_Realloc(waypoint->prevwaypoints, waypoint->numprevwaypoints * sizeof(waypoint_t *), PU_LEVEL, NULL)
);
if (!waypoint->prevwaypoints)
{
I_Error("K_AddPrevToWaypoint: Failed to reallocate memory for previous waypoints.");
}
waypoint->prevwaypointdistances =
Z_Realloc(waypoint->prevwaypointdistances, waypoint->numprevwaypoints * sizeof(fixed_t), PU_LEVEL, NULL);
waypoint->prevwaypointdistances = static_cast<UINT32*>(
Z_Realloc(waypoint->prevwaypointdistances, waypoint->numprevwaypoints * sizeof(fixed_t), PU_LEVEL, NULL)
);
if (!waypoint->prevwaypointdistances)
{
@ -2104,14 +2115,16 @@ static waypoint_t *K_MakeWaypoint(mobj_t *const mobj)
if (madewaypoint->numnextwaypoints != 0)
{
// Allocate memory to hold enough pointers to all of the next waypoints
madewaypoint->nextwaypoints =
Z_Calloc(madewaypoint->numnextwaypoints * sizeof(waypoint_t *), PU_LEVEL, NULL);
madewaypoint->nextwaypoints = static_cast<waypoint_t**>(
Z_Calloc(madewaypoint->numnextwaypoints * sizeof(waypoint_t *), PU_LEVEL, NULL)
);
if (madewaypoint->nextwaypoints == NULL)
{
I_Error("K_MakeWaypoint: Out of Memory allocating next waypoints.");
}
madewaypoint->nextwaypointdistances =
Z_Calloc(madewaypoint->numnextwaypoints * sizeof(fixed_t), PU_LEVEL, NULL);
madewaypoint->nextwaypointdistances = static_cast<UINT32*>(
Z_Calloc(madewaypoint->numnextwaypoints * sizeof(fixed_t), PU_LEVEL, NULL)
);
if (madewaypoint->nextwaypointdistances == NULL)
{
I_Error("K_MakeWaypoint: Out of Memory allocating next waypoint distances.");
@ -2262,7 +2275,7 @@ static boolean K_AllocateWaypointHeap(void)
{
// Allocate space in the heap for every mobj, it's possible some mobjs aren't linked up and not all of the
// heap allocated will be used, but it's a fairly reasonable assumption that this isn't going to be awful
waypointheap = Z_Calloc(numwaypointmobjs * sizeof(waypoint_t), PU_LEVEL, NULL);
waypointheap = static_cast<waypoint_t*>(Z_Calloc(numwaypointmobjs * sizeof(waypoint_t), PU_LEVEL, NULL));
if (waypointheap == NULL)
{
@ -2299,6 +2312,460 @@ static void K_FreeWaypoints(void)
K_ClearWaypoints();
}
namespace
{
/*--------------------------------------------------
BlockItReturn_t K_TrackWaypointNearOffroad(line_t *line)
Blockmap iteration function to check in an extra radius
around a waypoint to find any solid walls around it.
--------------------------------------------------*/
static fixed_t g_track_wp_x = INT32_MAX;
static fixed_t g_track_wp_y = INT32_MAX;
static fixed_t g_track_wp_radius = INT32_MAX;
static BlockItReturn_t K_TrackWaypointNearOffroad(line_t *line)
{
fixed_t dist = INT32_MAX;
vertex_t v = {0};
P_ClosestPointOnLine(
g_track_wp_x, g_track_wp_y,
line,
&v
);
dist = R_PointToDist2(
g_track_wp_x, g_track_wp_y,
v.x, v.y
);
const fixed_t buffer = FixedMul(mobjinfo[MT_PLAYER].radius * 2, mapobjectscale) * 3;
dist -= buffer;
if (dist <= 0) // line gets crossed
{
if (((line->flags & (ML_TWOSIDED|ML_IMPASSABLE|ML_MIDSOLID)) == ML_TWOSIDED) && !line->blockplayers)
{
// double-sided, and no blocking flags -- it's not a wall
const INT32 side = P_PointOnLineSide(g_track_wp_x, g_track_wp_y, line);
const sector_t *sec = side ? line->frontsector : line->backsector;
if (sec != nullptr && (sec->damagetype == SD_DEATHPIT || sec->damagetype == SD_INSTAKILL))
{
// force kill sectors to be more complex
return BMIT_STOP;
}
}
else
{
// actually is a wall
return BMIT_ABORT;
}
}
// not crossed, or not a wall
return BMIT_CONTINUE;
}
/*--------------------------------------------------
boolean K_SneakerPanelOverlap(struct sneakerpanel &panelA, struct sneakerpanel &panelB)
Returns whenever or not a sneaker panel sector / thing overlap
--------------------------------------------------*/
struct complexity_sneaker_s
{
fixed_t bbox[4];
//std::vector<sector_t *> sectors;
//std::vector<mapthing_t *> things;
complexity_sneaker_s(sector_t *sec)
{
M_ClearBox(bbox);
for (size_t i = 0; i < sec->linecount; i++)
{
line_t *const ld = sec->lines[i];
M_AddToBox(bbox, ld->bbox[BOXRIGHT], ld->bbox[BOXTOP]);
M_AddToBox(bbox, ld->bbox[BOXLEFT], ld->bbox[BOXBOTTOM]);
}
}
/*complexity_sneaker_s(mapthing_t *mt)
{
M_ClearBox(bbox);
fixed_t x = mt->x << FRACBITS;
fixed_t y = mt->y << FRACBITS;
fixed_t radius = FixedMul(FixedMul(mobjinfo[MT_SNEAKERPANEL].radius, mt->scale), mapobjectscale);
M_AddToBox(bbox, x - radius, y - radius);
M_AddToBox(bbox, x + radius, y + radius);
}*/
};
static boolean K_SneakerPanelOverlap(complexity_sneaker_s &panelA, complexity_sneaker_s &panelB)
{
const fixed_t overlap_extra = 528 * mapobjectscale; // merge ones this close together
const fixed_t a_width_half = (panelA.bbox[BOXRIGHT] - panelA.bbox[BOXLEFT]) / 2;
const fixed_t a_height_half = (panelA.bbox[BOXTOP] - panelA.bbox[BOXBOTTOM]) / 2;
const fixed_t a_x = panelA.bbox[BOXLEFT] + a_width_half;
const fixed_t a_y = panelA.bbox[BOXBOTTOM] + a_height_half;
const fixed_t b_width_half = (panelB.bbox[BOXRIGHT] - panelB.bbox[BOXLEFT]) / 2;
const fixed_t b_height_half = (panelB.bbox[BOXTOP] - panelB.bbox[BOXBOTTOM]) / 2;
const fixed_t b_x = panelB.bbox[BOXLEFT] + b_width_half;
const fixed_t b_y = panelB.bbox[BOXBOTTOM] + b_height_half;
const fixed_t dx = b_x - a_x;
const fixed_t px = (b_width_half - a_width_half) - abs(dx);
if (px <= -overlap_extra)
{
return false;
}
const fixed_t dy = b_y - a_y;
const fixed_t py = (b_height_half - a_height_half) - abs(dy);
if (py <= -overlap_extra)
{
return false;
}
return true;
}
/*--------------------------------------------------
INT32 K_CalculateTrackComplexity(void)
Sets the value of trackcomplexity. This value accumulates all of the
turn angle deltas to get an idea of how complicated the map is.
--------------------------------------------------*/
static INT32 K_CalculateTrackComplexity(void)
{
const boolean huntbackwards = false;
const boolean useshortcuts = false;
boolean pathfindsuccess = false;
path_t path = {0};
trackcomplexity = BASE_TRACK_COMPLEXITY;
if (startingwaypoint == NULL || finishline == NULL)
{
return trackcomplexity;
}
pathfindsuccess = K_PathfindToWaypoint(
startingwaypoint, finishline,
&path,
useshortcuts, huntbackwards
);
if (pathfindsuccess == true)
{
auto path_finally = srb2::finally([&path]() { Z_Free(path.array); });
for (size_t i = 1; i < path.numnodes-1; i++)
{
waypoint_t *const start = (waypoint_t *)path.array[ i - 1 ].nodedata;
waypoint_t *const mid = (waypoint_t *)path.array[ i ].nodedata;
waypoint_t *const end = (waypoint_t *)path.array[ i + 1 ].nodedata;
const INT32 turn_id = K_GetWaypointID(mid);
// would it be better to just check mid?
if (K_GetWaypointIsSpawnpoint(start) == false
|| K_GetWaypointIsSpawnpoint(mid) == false
|| K_GetWaypointIsSpawnpoint(end) == false)
{
CONS_Debug(DBG_SETUP, "%s", fmt::format("TURN [{}]: skipped\n", turn_id).c_str());
continue;
}
const fixed_t start_mid_dist = R_PointToDist2(
start->mobj->x, start->mobj->y,
mid->mobj->x, mid->mobj->y
);
const fixed_t mid_end_dist = R_PointToDist2(
mid->mobj->x, mid->mobj->y,
end->mobj->x, end->mobj->y
);
const angle_t start_mid_angle = R_PointToAngle2(
start->mobj->x, start->mobj->y,
mid->mobj->x, mid->mobj->y
);
const angle_t mid_end_angle = R_PointToAngle2(
mid->mobj->x, mid->mobj->y,
end->mobj->x, end->mobj->y
);
const angle_t start_mid_pitch = R_PointToAngle2(
0, start->mobj->z,
start_mid_dist, mid->mobj->z
);
const angle_t mid_end_pitch = R_PointToAngle2(
0, mid->mobj->z,
mid_end_dist, end->mobj->z
);
const fixed_t avg_radius = (start->mobj->radius + mid->mobj->radius + end->mobj->radius) / 3;
const fixed_t base_scale = DEFAULT_WAYPOINT_RADIUS * mapobjectscale;
// Reduce complexity with wider turns.
fixed_t radius_factor = FixedDiv(
base_scale,
std::max<fixed_t>(
1,
avg_radius
)
);
radius_factor = FRACUNIT + ((radius_factor - FRACUNIT) / 2); // reduce how much it's worth
// Reduce complexity with wider spaced waypoints.
fixed_t dist_factor = FixedDiv(
base_scale,
std::max<fixed_t>(
1,
start_mid_dist + mid_end_dist
)
);
fixed_t wall_factor = FRACUNIT;
constexpr fixed_t minimum_turn = 10 * FRACUNIT; // If the delta is lower than this, it's practically a straight-away.
fixed_t delta = AngleFixed(
AngleDelta(
start_mid_angle,
mid_end_angle
)
) - minimum_turn;
if (delta < 0)
{
dist_factor = FixedDiv(FRACUNIT, std::max<fixed_t>(1, dist_factor));
radius_factor = FixedDiv(FRACUNIT, std::max<fixed_t>(1, radius_factor));
}
else
{
// Weight turns hard enough
delta = FixedMul(delta, delta);
// Reduce turn complexity in walled maps.
wall_factor = FRACUNIT;
g_track_wp_x = mid->mobj->x;
g_track_wp_y = mid->mobj->y;
g_track_wp_radius = mid->mobj->radius;
const fixed_t searchRadius = /*g_track_wp_radius +*/ MAXRADIUS;
INT32 xl, xh, yl, yh;
INT32 bx, by;
const fixed_t c = FixedMul(g_track_wp_radius, FINECOSINE((start_mid_angle + ANGLE_90) >> ANGLETOFINESHIFT));
const fixed_t s = FixedMul(g_track_wp_radius, FINESINE((start_mid_angle + ANGLE_90) >> ANGLETOFINESHIFT));
validcount++; // used to make sure we only process a line once
xl = (unsigned)((g_track_wp_x + c - searchRadius) - bmaporgx)>>MAPBLOCKSHIFT;
xh = (unsigned)((g_track_wp_x + c + searchRadius) - bmaporgx)>>MAPBLOCKSHIFT;
yl = (unsigned)((g_track_wp_y + s - searchRadius) - bmaporgy)>>MAPBLOCKSHIFT;
yh = (unsigned)((g_track_wp_y + s + searchRadius) - bmaporgy)>>MAPBLOCKSHIFT;
BMBOUNDFIX(xl, xh, yl, yh);
for (bx = xl; bx <= xh; bx++)
{
for (by = yl; by <= yh; by++)
{
if (P_BlockLinesIterator(bx, by, K_TrackWaypointNearOffroad) == false)
{
wall_factor /= 4;
bx = xh + 1;
by = yh + 1;
}
}
}
validcount++; // used to make sure we only process a line once
xl = (unsigned)((g_track_wp_x - c - searchRadius) - bmaporgx)>>MAPBLOCKSHIFT;
xh = (unsigned)((g_track_wp_x - c + searchRadius) - bmaporgx)>>MAPBLOCKSHIFT;
yl = (unsigned)((g_track_wp_y - s - searchRadius) - bmaporgy)>>MAPBLOCKSHIFT;
yh = (unsigned)((g_track_wp_y - s + searchRadius) - bmaporgy)>>MAPBLOCKSHIFT;
BMBOUNDFIX(xl, xh, yl, yh);
for (bx = xl; bx <= xh; bx++)
{
for (by = yl; by <= yh; by++)
{
if (P_BlockLinesIterator(bx, by, K_TrackWaypointNearOffroad) == false)
{
wall_factor /= 4;
bx = xh + 1;
by = yh + 1;
}
}
}
}
fixed_t pitch_delta = AngleFixed(
AngleDelta(
start_mid_pitch,
mid_end_pitch
)
);
constexpr fixed_t minimum_drop = 30 * FRACUNIT; // If the delta is lower than this, it's probably just a slope.
if (pitch_delta > minimum_drop)
{
// bonus complexity for drop-off / ramp
constexpr fixed_t drop_factor = 10 * FRACUNIT;
const fixed_t drop_off_mul = FRACUNIT + FixedDiv(pitch_delta - minimum_drop, drop_factor);
delta += FixedMul(pitch_delta, drop_off_mul);
}
delta = FixedMul(delta, FixedMul(FixedMul(dist_factor, radius_factor), wall_factor));
std::string msg = fmt::format(
"TURN [{}]: r: {:.2f}, d: {:.2f}, w: {:.2f}, r*d*w: {:.2f}, DELTA: {}\n",
turn_id,
FixedToFloat(radius_factor),
FixedToFloat(dist_factor),
FixedToFloat(wall_factor),
FixedToFloat(FixedMul(FixedMul(dist_factor, radius_factor), wall_factor)),
(delta / FRACUNIT)
);
CONS_Debug(DBG_SETUP, "%s", msg.c_str());
trackcomplexity += (delta / FRACUNIT);
}
std::vector<complexity_sneaker_s> sneaker_panels;
for (size_t i = 0; i < numsectors; i++)
{
sector_t *const sec = &sectors[i];
if (sec->linecount == 0)
{
continue;
}
terrain_t *terrain_f = K_GetTerrainForFlatNum(sec->floorpic);
terrain_t *terrain_c = K_GetTerrainForFlatNum(sec->ceilingpic);
if ((terrain_f != nullptr && (terrain_f->flags & (TRF_SNEAKERPANEL|TRF_WATERRUNPANEL)) == (TRF_SNEAKERPANEL|TRF_WATERRUNPANEL))
|| (terrain_c != nullptr && (terrain_c->flags & (TRF_SNEAKERPANEL|TRF_WATERRUNPANEL)) == (TRF_SNEAKERPANEL|TRF_WATERRUNPANEL)))
{
complexity_sneaker_s new_panel(sec);
boolean create_new = true;
for (size_t j = 0; j < sec->linecount; j++)
{
line_t *const ld = sec->lines[j];
M_AddToBox(new_panel.bbox, ld->bbox[BOXRIGHT], ld->bbox[BOXTOP]);
M_AddToBox(new_panel.bbox, ld->bbox[BOXLEFT], ld->bbox[BOXBOTTOM]);
}
for (auto &panel : sneaker_panels)
{
if (K_SneakerPanelOverlap(new_panel, panel) == true)
{
// merge together
M_AddToBox(panel.bbox, new_panel.bbox[BOXRIGHT], new_panel.bbox[BOXTOP]);
M_AddToBox(panel.bbox, new_panel.bbox[BOXLEFT], new_panel.bbox[BOXBOTTOM]);
//panel.sectors.push_back(sec);
create_new = false;
break;
}
}
if (create_new == true)
{
//new_panel.sectors.push_back(sec);
sneaker_panels.push_back(new_panel);
}
}
if ((sec->specialflags & SSF_SNEAKERPANEL) || (sec->specialflags & SSF_WATERPANEL))
{
complexity_sneaker_s new_panel(sec);
boolean create_new = true;
for (size_t j = 0; j < sec->linecount; j++)
{
line_t *const ld = sec->lines[j];
M_AddToBox(new_panel.bbox, ld->bbox[BOXRIGHT], ld->bbox[BOXTOP]);
M_AddToBox(new_panel.bbox, ld->bbox[BOXLEFT], ld->bbox[BOXBOTTOM]);
}
for (auto &panel : sneaker_panels)
{
if (K_SneakerPanelOverlap(new_panel, panel) == true)
{
// merge together
M_AddToBox(panel.bbox, new_panel.bbox[BOXRIGHT], new_panel.bbox[BOXTOP]);
M_AddToBox(panel.bbox, new_panel.bbox[BOXLEFT], new_panel.bbox[BOXBOTTOM]);
//panel.sectors.push_back(sec);
create_new = false;
break;
}
}
if (create_new == true)
{
//new_panel.sectors.push_back(sec);
sneaker_panels.push_back(new_panel);
}
}
}
/*for (size_t i = 0; i < nummapthings; i++)
{
mapthing_t *const mt = &mapthings[i];
if (mt->type != mobjinfo[MT_SNEAKERPANEL].doomednum)
{
continue;
}
complexity_sneaker_s new_panel(mt);
boolean create_new = true;
for (auto &panel : sneaker_panels)
{
if (K_SneakerPanelOverlap(new_panel, panel) == true)
{
// merge together
M_AddToBox(panel.bbox, new_panel.bbox[BOXRIGHT], new_panel.bbox[BOXTOP]);
M_AddToBox(panel.bbox, new_panel.bbox[BOXLEFT], new_panel.bbox[BOXBOTTOM]);
create_new = false;
break;
}
}
if (create_new == true)
{
sneaker_panels.push_back(new_panel);
}
}*/
CONS_Debug(DBG_SETUP, "%s", fmt::format("Num sneaker panel sets: {}\n", sneaker_panels.size()).c_str());
trackcomplexity -= sneaker_panels.size() * 1250;
CONS_Debug(DBG_SETUP, " ** MAP COMPLEXITY: %d\n", trackcomplexity);
}
return trackcomplexity;
}
}; // namespace
/*--------------------------------------------------
boolean K_SetupWaypointList(void)
@ -2314,7 +2781,7 @@ boolean K_SetupWaypointList(void)
{
if (numbosswaypoints == 0)
{
CONS_Alert(CONS_ERROR, "No waypoints or checkpoints in map.\n");
CONS_Alert(CONS_ERROR, "No waypoints or legacy checkpoints in map.\n");
}
}
else
@ -2334,7 +2801,7 @@ boolean K_SetupWaypointList(void)
{
if (numbosswaypoints == 0)
{
CONS_Alert(CONS_ERROR, "No waypoints or checkpoints in map.\n");
CONS_Alert(CONS_ERROR, "No waypoints or legacy checkpoints in map.\n");
}
}
else
@ -2353,10 +2820,10 @@ boolean K_SetupWaypointList(void)
CONS_Alert(CONS_ERROR, "Circuit track waypoints do not form a circuit.\n");
}
/*if (startingwaypoint != NULL)
if (startingwaypoint != NULL)
{
K_CalculateTrackComplexity();
}*/
}
setupsuccessful = true;
}

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 KART
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2018-2020 by Sean "Sryder" Ryder
// Copyright (C) 2018-2020 by Kart Krew
// Copyright (C) 2024 by Sean "Sryder" Ryder
// Copyright (C) 2024 by Kart Krew
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
@ -156,8 +156,10 @@ INT32 K_GetWaypointNextID(waypoint_t *waypoint);
Return:-
The waypoint ID, -1 if there is no waypoint or mobj.
--------------------------------------------------*/
INT32 K_GetWaypointID(waypoint_t *waypoint);
/*--------------------------------------------------
waypoint_t *K_GetWaypointFromID(INT32 waypointID)
@ -172,6 +174,7 @@ INT32 K_GetWaypointID(waypoint_t *waypoint);
waypoint_t *K_GetWaypointFromID(INT32 waypointID);
/*--------------------------------------------------
UINT32 K_GetCircuitLength(void)
@ -182,6 +185,7 @@ waypoint_t *K_GetWaypointFromID(INT32 waypointID);
Return:-
The circuit length.
--------------------------------------------------*/
UINT32 K_GetCircuitLength(void);

View file

@ -1041,7 +1041,8 @@ static int lib_pRemoveFloorSpriteSlope(lua_State *L)
static int lib_pRailThinker(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
tm_t ptm = tm;
tm_t ptm = g_tm;
NOHUD
INLEVEL
if (!mobj)
@ -1054,7 +1055,8 @@ static int lib_pRailThinker(lua_State *L)
static int lib_pXYMovement(lua_State *L)
{
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
tm_t ptm = tm;
tm_t ptm = g_tm;
NOHUD
INLEVEL
if (!actor)
@ -1067,7 +1069,8 @@ static int lib_pXYMovement(lua_State *L)
static int lib_pRingXYMovement(lua_State *L)
{
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
tm_t ptm = tm;
tm_t ptm = g_tm;
NOHUD
INLEVEL
if (!actor)
@ -1080,7 +1083,8 @@ static int lib_pRingXYMovement(lua_State *L)
static int lib_pSceneryXYMovement(lua_State *L)
{
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
tm_t ptm = tm;
tm_t ptm = g_tm;
NOHUD
INLEVEL
if (!actor)
@ -1093,7 +1097,8 @@ static int lib_pSceneryXYMovement(lua_State *L)
static int lib_pZMovement(lua_State *L)
{
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
tm_t ptm = tm;
tm_t ptm = g_tm;
NOHUD
INLEVEL
if (!actor)
@ -1107,7 +1112,8 @@ static int lib_pZMovement(lua_State *L)
static int lib_pRingZMovement(lua_State *L)
{
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
tm_t ptm = tm;
tm_t ptm = g_tm;
NOHUD
INLEVEL
if (!actor)
@ -1121,7 +1127,8 @@ static int lib_pRingZMovement(lua_State *L)
static int lib_pSceneryZMovement(lua_State *L)
{
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
tm_t ptm = tm;
tm_t ptm = g_tm;
NOHUD
INLEVEL
if (!actor)
@ -1135,7 +1142,8 @@ static int lib_pSceneryZMovement(lua_State *L)
static int lib_pPlayerZMovement(lua_State *L)
{
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
tm_t ptm = tm;
tm_t ptm = g_tm;
NOHUD
INLEVEL
if (!actor)
@ -1354,7 +1362,8 @@ static int lib_pGivePlayerLives(lua_State *L)
static int lib_pMovePlayer(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
tm_t ptm = tm;
tm_t ptm = g_tm;
NOHUD
INLEVEL
if (!player)
@ -1432,7 +1441,8 @@ static int lib_pNukeEnemies(lua_State *L)
static int lib_pCheckPosition(lua_State *L)
{
tm_t ptm = tm;
tm_t ptm = g_tm;
mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
fixed_t x = luaL_checkfixed(L, 2);
fixed_t y = luaL_checkfixed(L, 3);
@ -1441,14 +1451,15 @@ static int lib_pCheckPosition(lua_State *L)
if (!thing)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_CheckPosition(thing, x, y, NULL));
LUA_PushUserdata(L, tm.thing, META_MOBJ);
LUA_PushUserdata(L, g_tm.thing, META_MOBJ);
P_RestoreTMStruct(ptm);
return 2;
}
static int lib_pTryMove(lua_State *L)
{
tm_t ptm = tm;
tm_t ptm = g_tm;
mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
fixed_t x = luaL_checkfixed(L, 2);
fixed_t y = luaL_checkfixed(L, 3);
@ -1458,14 +1469,15 @@ static int lib_pTryMove(lua_State *L)
if (!thing)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_TryMove(thing, x, y, allowdropoff, NULL));
LUA_PushUserdata(L, tm.thing, META_MOBJ);
LUA_PushUserdata(L, g_tm.thing, META_MOBJ);
P_RestoreTMStruct(ptm);
return 2;
}
static int lib_pMove(lua_State *L)
{
tm_t ptm = tm;
tm_t ptm = g_tm;
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
fixed_t speed = luaL_checkfixed(L, 2);
NOHUD
@ -1473,14 +1485,15 @@ static int lib_pMove(lua_State *L)
if (!actor)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_Move(actor, speed));
LUA_PushUserdata(L, tm.thing, META_MOBJ);
LUA_PushUserdata(L, g_tm.thing, META_MOBJ);
P_RestoreTMStruct(ptm);
return 2;
}
static int lib_pTeleportMove(lua_State *L)
{
tm_t ptm = tm;
tm_t ptm = g_tm;
mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
fixed_t x = luaL_checkfixed(L, 2);
fixed_t y = luaL_checkfixed(L, 3);
@ -1491,14 +1504,15 @@ static int lib_pTeleportMove(lua_State *L)
return LUA_ErrInvalid(L, "mobj_t");
LUA_Deprecated(L, "P_TeleportMove", "P_SetOrigin\" or \"P_MoveOrigin");
lua_pushboolean(L, P_MoveOrigin(thing, x, y, z));
LUA_PushUserdata(L, tm.thing, META_MOBJ);
LUA_PushUserdata(L, g_tm.thing, META_MOBJ);
P_RestoreTMStruct(ptm);
return 2;
}
static int lib_pSetOrigin(lua_State *L)
{
tm_t ptm = tm;
tm_t ptm = g_tm;
mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
fixed_t x = luaL_checkfixed(L, 2);
fixed_t y = luaL_checkfixed(L, 3);
@ -1508,14 +1522,15 @@ static int lib_pSetOrigin(lua_State *L)
if (!thing)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_SetOrigin(thing, x, y, z));
LUA_PushUserdata(L, tm.thing, META_MOBJ);
LUA_PushUserdata(L, g_tm.thing, META_MOBJ);
P_RestoreTMStruct(ptm);
return 2;
}
static int lib_pMoveOrigin(lua_State *L)
{
tm_t ptm = tm;
tm_t ptm = g_tm;
mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
fixed_t x = luaL_checkfixed(L, 2);
fixed_t y = luaL_checkfixed(L, 3);
@ -1525,7 +1540,7 @@ static int lib_pMoveOrigin(lua_State *L)
if (!thing)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_MoveOrigin(thing, x, y, z));
LUA_PushUserdata(L, tm.thing, META_MOBJ);
LUA_PushUserdata(L, g_tm.thing, META_MOBJ);
P_RestoreTMStruct(ptm);
return 2;
}

View file

@ -812,7 +812,8 @@ static int sector_set(lua_State *L)
return luaL_error(L, "sector_t has no field named " LUA_QS ".", lua_tostring(L, 2));
case sector_floorheight: { // floorheight
boolean flag;
tm_t ptm = tm;
tm_t ptm = g_tm;
fixed_t lastpos = sector->floorheight;
sector->floorheight = luaL_checkfixed(L, 3);
flag = P_CheckSector(sector, true);
@ -826,7 +827,8 @@ static int sector_set(lua_State *L)
}
case sector_ceilingheight: { // ceilingheight
boolean flag;
tm_t ptm = tm;
tm_t ptm = g_tm;
fixed_t lastpos = sector->ceilingheight;
sector->ceilingheight = luaL_checkfixed(L, 3);
flag = P_CheckSector(sector, true);
@ -2264,7 +2266,8 @@ static int ffloor_set(lua_State *L)
case ffloor_topheight: { // topheight
boolean flag;
fixed_t lastpos = *ffloor->topheight;
tm_t ptm = tm;
tm_t ptm = g_tm;
sector_t *sector = &sectors[ffloor->secnum];
sector->ceilingheight = luaL_checkfixed(L, 3);
flag = P_CheckSector(sector, true);
@ -2285,7 +2288,8 @@ static int ffloor_set(lua_State *L)
case ffloor_bottomheight: { // bottomheight
boolean flag;
fixed_t lastpos = *ffloor->bottomheight;
tm_t ptm = tm;
tm_t ptm = g_tm;
sector_t *sector = &sectors[ffloor->secnum];
sector->floorheight = luaL_checkfixed(L, 3);
flag = P_CheckSector(sector, true);

View file

@ -654,13 +654,14 @@ static int mobj_set(lua_State *L)
case mobj_z:
{
// z doesn't cross sector bounds so it's okay.
tm_t ptm = tm;
tm_t ptm = g_tm;
mo->z = luaL_checkfixed(L, 3);
P_CheckPosition(mo, mo->x, mo->y, NULL);
mo->floorz = tm.floorz;
mo->ceilingz = tm.ceilingz;
mo->floorrover = tm.floorrover;
mo->ceilingrover = tm.ceilingrover;
mo->floorz = g_tm.floorz;
mo->ceilingz = g_tm.ceilingz;
mo->floorrover = g_tm.floorrover;
mo->ceilingrover = g_tm.ceilingrover;
P_RestoreTMStruct(ptm);
break;
}
@ -734,29 +735,31 @@ static int mobj_set(lua_State *L)
return NOSET;
case mobj_radius:
{
tm_t ptm = tm;
tm_t ptm = g_tm;
mo->radius = luaL_checkfixed(L, 3);
if (mo->radius < 0)
mo->radius = 0;
P_CheckPosition(mo, mo->x, mo->y, NULL);
mo->floorz = tm.floorz;
mo->ceilingz = tm.ceilingz;
mo->floorrover = tm.floorrover;
mo->ceilingrover = tm.ceilingrover;
mo->floorz = g_tm.floorz;
mo->ceilingz = g_tm.ceilingz;
mo->floorrover = g_tm.floorrover;
mo->ceilingrover = g_tm.ceilingrover;
P_RestoreTMStruct(ptm);
break;
}
case mobj_height:
{
tm_t ptm = tm;
tm_t ptm = g_tm;
mo->height = luaL_checkfixed(L, 3);
if (mo->height < 0)
mo->height = 0;
P_CheckPosition(mo, mo->x, mo->y, NULL);
mo->floorz = tm.floorz;
mo->ceilingz = tm.ceilingz;
mo->floorrover = tm.floorrover;
mo->ceilingrover = tm.ceilingrover;
mo->floorz = g_tm.floorz;
mo->ceilingz = g_tm.ceilingz;
mo->floorrover = g_tm.floorrover;
mo->ceilingrover = g_tm.ceilingrover;
P_RestoreTMStruct(ptm);
break;
}

View file

@ -269,10 +269,10 @@ boolean P_Move(mobj_t *actor, fixed_t speed)
if (!P_TryMove(actor, tryx, tryy, false, NULL))
{
if (actor->flags & MF_FLOAT && tm.floatok)
if (actor->flags & MF_FLOAT && g_tm.floatok)
{
// must adjust height
if (actor->z < tm.floorz)
if (actor->z < g_tm.floorz)
actor->z += FixedMul(FLOATSPEED, actor->scale);
else
actor->z -= FixedMul(FLOATSPEED, actor->scale);
@ -10314,13 +10314,13 @@ void A_FlickyCenter(mobj_t *actor)
{
actor->extravalue2 = 1;
P_SetOrigin(actor, actor->target->x, actor->target->y, actor->target->z);
P_SetTarget(&tm.thing, NULL);
P_SetTarget(&g_tm.thing, NULL);
}
else if(actor->extravalue2)
{
actor->extravalue2 = 0;
P_SetOrigin(actor, originx, originy, originz);
P_SetTarget(&tm.thing, NULL);
P_SetTarget(&g_tm.thing, NULL);
}
}
}
@ -12999,7 +12999,7 @@ void A_ItemPop(mobj_t *actor)
remains->skin = NULL;
remains->spawnpoint = actor->spawnpoint;
P_SetTarget(&tm.thing, remains);
P_SetTarget(&g_tm.thing, remains);
//if (actor->info->deathsound)
//S_StartSound(remains, actor->info->deathsound);

View file

@ -404,12 +404,12 @@ struct tm_t
fixed_t precipbbox[4];
// If "floatok" true, move would be ok
// if within "tm.floorz - tm.ceilingz".
// if within "g_tm.floorz - g_tm.ceilingz".
boolean floatok;
fixed_t floorz, ceilingz;
fixed_t dropoffz, drpoffceilz; // drop-off floor/ceiling heights
mobj_t *floorthing; // the thing corresponding to tm.floorz or NULL if tm.floorz is from a sector
mobj_t *floorthing; // the thing corresponding to g_tm.floorz or NULL if g_tm.floorz is from a sector
mobj_t *hitthing; // the solid thing you bumped into (for collisions)
ffloor_t *floorrover, *ceilingrover;
pslope_t *floorslope, *ceilingslope;
@ -428,11 +428,11 @@ struct tm_t
// lines
boolean sweep;
// sweep: max step up at tm.x, tm.y
// sweep: max step up at g_tm.x, g_tm.y
fixed_t maxstep;
};
extern tm_t tm;
extern tm_t g_tm;
void P_RestoreTMStruct(tm_t tmrestore);

File diff suppressed because it is too large Load diff

View file

@ -315,8 +315,8 @@ void P_CameraLineOpening(line_t *linedef, opening_t *open)
}
else
{
frontfloor = P_CameraGetFloorZ (mapcampointer, front, tm.x, tm.y, linedef);
frontceiling = P_CameraGetCeilingZ(mapcampointer, front, tm.x, tm.y, linedef);
frontfloor = P_CameraGetFloorZ (mapcampointer, front, g_tm.x, g_tm.y, linedef);
frontceiling = P_CameraGetCeilingZ(mapcampointer, front, g_tm.x, g_tm.y, linedef);
}
if (back->camsec >= 0)
@ -333,8 +333,8 @@ void P_CameraLineOpening(line_t *linedef, opening_t *open)
}
else
{
backfloor = P_CameraGetFloorZ(mapcampointer, back, tm.x, tm.y, linedef);
backceiling = P_CameraGetCeilingZ(mapcampointer, back, tm.x, tm.y, linedef);
backfloor = P_CameraGetFloorZ(mapcampointer, back, g_tm.x, g_tm.y, linedef);
backceiling = P_CameraGetCeilingZ(mapcampointer, back, g_tm.x, g_tm.y, linedef);
}
thingtop = mapcampointer->z + mapcampointer->height;
@ -375,8 +375,8 @@ void P_CameraLineOpening(line_t *linedef, opening_t *open)
if (!(rover->fofflags & FOF_BLOCKOTHERS) || !(rover->fofflags & FOF_RENDERALL) || !(rover->fofflags & FOF_EXISTS) )
continue;
topheight = P_CameraGetFOFTopZ(mapcampointer, front, rover, tm.x, tm.y, linedef);
bottomheight = P_CameraGetFOFBottomZ(mapcampointer, front, rover, tm.x, tm.y, linedef);
topheight = P_CameraGetFOFTopZ(mapcampointer, front, rover, g_tm.x, g_tm.y, linedef);
bottomheight = P_CameraGetFOFBottomZ(mapcampointer, front, rover, g_tm.x, g_tm.y, linedef);
delta1 = abs(mapcampointer->z - (bottomheight + ((topheight - bottomheight)/2)));
delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2)));
@ -399,8 +399,8 @@ void P_CameraLineOpening(line_t *linedef, opening_t *open)
if (!(rover->fofflags & FOF_BLOCKOTHERS) || !(rover->fofflags & FOF_RENDERALL) || !(rover->fofflags & FOF_EXISTS) )
continue;
topheight = P_CameraGetFOFTopZ(mapcampointer, back, rover, tm.x, tm.y, linedef);
bottomheight = P_CameraGetFOFBottomZ(mapcampointer, back, rover, tm.x, tm.y, linedef);
topheight = P_CameraGetFOFTopZ(mapcampointer, back, rover, g_tm.x, g_tm.y, linedef);
bottomheight = P_CameraGetFOFBottomZ(mapcampointer, back, rover, g_tm.x, g_tm.y, linedef);
delta1 = abs(mapcampointer->z - (bottomheight + ((topheight - bottomheight)/2)));
delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2)));
@ -539,7 +539,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj, opening_t *open)
return;
}
P_ClosestPointOnLine(tm.x, tm.y, linedef, &cross);
P_ClosestPointOnLine(g_tm.x, g_tm.y, linedef, &cross);
// Treat polyobjects kind of like 3D Floors
if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT))
@ -567,8 +567,8 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj, opening_t *open)
fixed_t height[2];
const sector_t * sector[2] = { front, back };
height[FRONT] = P_GetCeilingZ(mobj, front, tm.x, tm.y, linedef);
height[BACK] = P_GetCeilingZ(mobj, back, tm.x, tm.y, linedef);
height[FRONT] = P_GetCeilingZ(mobj, front, g_tm.x, g_tm.y, linedef);
height[BACK] = P_GetCeilingZ(mobj, back, g_tm.x, g_tm.y, linedef);
hi = ( height[0] < height[1] );
lo = ! hi;
@ -587,8 +587,8 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj, opening_t *open)
open->ceilingdrop = ( topedge[hi] - topedge[lo] );
}
height[FRONT] = P_GetFloorZ(mobj, front, tm.x, tm.y, linedef);
height[BACK] = P_GetFloorZ(mobj, back, tm.x, tm.y, linedef);
height[FRONT] = P_GetFloorZ(mobj, front, g_tm.x, g_tm.y, linedef);
height[BACK] = P_GetFloorZ(mobj, back, g_tm.x, g_tm.y, linedef);
hi = ( height[0] < height[1] );
lo = ! hi;
@ -777,8 +777,8 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj, opening_t *open)
}
else
{
topheight = P_GetFOFTopZ(mobj, front, rover, tm.x, tm.y, linedef);
bottomheight = P_GetFOFBottomZ(mobj, front, rover, tm.x, tm.y, linedef);
topheight = P_GetFOFTopZ(mobj, front, rover, g_tm.x, g_tm.y, linedef);
bottomheight = P_GetFOFBottomZ(mobj, front, rover, g_tm.x, g_tm.y, linedef);
}
switch (open->fofType)
@ -869,8 +869,8 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj, opening_t *open)
}
else
{
topheight = P_GetFOFTopZ(mobj, back, rover, tm.x, tm.y, linedef);
bottomheight = P_GetFOFBottomZ(mobj, back, rover, tm.x, tm.y, linedef);
topheight = P_GetFOFTopZ(mobj, back, rover, g_tm.x, g_tm.y, linedef);
bottomheight = P_GetFOFBottomZ(mobj, back, rover, g_tm.x, g_tm.y, linedef);
}
switch (open->fofType)
@ -1834,16 +1834,16 @@ boolean P_RadiusLinesCheck(fixed_t radius, fixed_t x, fixed_t y,
INT32 xl, xh, yl, yh;
INT32 bx, by;
tm.bbox[BOXTOP] = y + radius;
tm.bbox[BOXBOTTOM] = y - radius;
tm.bbox[BOXRIGHT] = x + radius;
tm.bbox[BOXLEFT] = x - radius;
g_tm.bbox[BOXTOP] = y + radius;
g_tm.bbox[BOXBOTTOM] = y - radius;
g_tm.bbox[BOXRIGHT] = x + radius;
g_tm.bbox[BOXLEFT] = x - radius;
// check lines
xl = (unsigned)(tm.bbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT;
xh = (unsigned)(tm.bbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT;
yl = (unsigned)(tm.bbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT;
yh = (unsigned)(tm.bbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT;
xl = (unsigned)(g_tm.bbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT;
xh = (unsigned)(g_tm.bbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT;
yl = (unsigned)(g_tm.bbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT;
yh = (unsigned)(g_tm.bbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT;
for (bx = xl; bx <= xh; bx++)
for (by = yl; by <= yh; by++)

View file

@ -1508,12 +1508,12 @@ bustupdone:
//
static boolean P_CheckSkyHit(mobj_t *mo)
{
if (tm.ceilingline && tm.ceilingline->backsector
&& tm.ceilingline->backsector->ceilingpic == skyflatnum
&& tm.ceilingline->frontsector
&& tm.ceilingline->frontsector->ceilingpic == skyflatnum
&& (mo->z >= tm.ceilingline->frontsector->ceilingheight
|| mo->z >= tm.ceilingline->backsector->ceilingheight))
if (g_tm.ceilingline && g_tm.ceilingline->backsector
&& g_tm.ceilingline->backsector->ceilingpic == skyflatnum
&& g_tm.ceilingline->frontsector
&& g_tm.ceilingline->frontsector->ceilingpic == skyflatnum
&& (mo->z >= g_tm.ceilingline->frontsector->ceilingheight
|| mo->z >= g_tm.ceilingline->backsector->ceilingheight))
return true;
return false;
}
@ -1610,7 +1610,7 @@ void P_XYMovement(mobj_t *mo)
// blocked move
moved = false;
if (LUA_HookMobjMoveBlocked(mo, tm.hitthing, result.line))
if (LUA_HookMobjMoveBlocked(mo, g_tm.hitthing, result.line))
{
if (P_MobjWasRemoved(mo))
return;
@ -1651,7 +1651,7 @@ void P_XYMovement(mobj_t *mo)
// draw damage on wall
//SPLAT TEST ----------------------------------------------------------
#ifdef WALLSPLATS
if (tm.blockingline && mo->type != MT_REDRING && mo->type != MT_FIREBALL
if (g_tm.blockingline && mo->type != MT_REDRING && mo->type != MT_FIREBALL
&& !(mo->flags2 & (MF2_AUTOMATIC|MF2_RAILRING|MF2_BOUNCERING|MF2_EXPLOSION|MF2_SCATTER)))
// set by last P_TryMove() that failed
{
@ -1659,13 +1659,13 @@ void P_XYMovement(mobj_t *mo)
divline_t misl;
fixed_t frac;
P_MakeDivline(tm.blockingline, &divl);
P_MakeDivline(g_tm.blockingline, &divl);
misl.x = mo->x;
misl.y = mo->y;
misl.dx = mo->momx;
misl.dy = mo->momy;
frac = P_InterceptVector(&divl, &misl);
R_AddWallSplat(tm.blockingline, P_PointOnLineSide(mo->x,mo->y,tm.blockingline),
R_AddWallSplat(g_tm.blockingline, P_PointOnLineSide(mo->x,mo->y,g_tm.blockingline),
"A_DMG3", mo->z, frac, SPLATDRAWMODE_SHADE);
}
#endif
@ -2388,11 +2388,11 @@ boolean P_ZMovement(mobj_t *mo)
if (P_MobjWasRemoved(mo)) // mobjs can be removed by P_CheckPosition -- Monster Iestyn 31/07/21
return false;
K_UpdateMobjTerrain(mo, ((mo->eflags & MFE_VERTICALFLIP) ? tm.ceilingpic : tm.floorpic));
K_UpdateMobjTerrain(mo, ((mo->eflags & MFE_VERTICALFLIP) ? g_tm.ceilingpic : g_tm.floorpic));
if (((mo->eflags & MFE_VERTICALFLIP) ? tm.ceilingslope : tm.floorslope) && (mo->type != MT_STEAM))
if (((mo->eflags & MFE_VERTICALFLIP) ? g_tm.ceilingslope : g_tm.floorslope) && (mo->type != MT_STEAM))
{
mo->standingslope = (mo->eflags & MFE_VERTICALFLIP) ? tm.ceilingslope : tm.floorslope;
mo->standingslope = (mo->eflags & MFE_VERTICALFLIP) ? g_tm.ceilingslope : g_tm.floorslope;
P_SetPitchRollFromSlope(mo, mo->standingslope);
P_ReverseQuantizeMomentumToSlope(&mom, mo->standingslope);
}
@ -2525,11 +2525,11 @@ boolean P_ZMovement(mobj_t *mo)
}
}
else
mom.z = (tm.floorthing ? tm.floorthing->momz : 0);
mom.z = (g_tm.floorthing ? g_tm.floorthing->momz : 0);
}
else if (tm.floorthing)
mom.z = tm.floorthing->momz;
else if (g_tm.floorthing)
mom.z = g_tm.floorthing->momz;
if (mo->standingslope) { // MT_STEAM will never have a standingslope, see above.
P_QuantizeMomentumToSlope(&mom, mo->standingslope);
@ -2763,7 +2763,7 @@ void P_PlayerZMovement(mobj_t *mo)
mo->z = mo->floorz;
}
K_UpdateMobjTerrain(mo, (mo->eflags & MFE_VERTICALFLIP ? tm.ceilingpic : tm.floorpic));
K_UpdateMobjTerrain(mo, (mo->eflags & MFE_VERTICALFLIP ? g_tm.ceilingpic : g_tm.floorpic));
// Get up if you fell.
if (mo->player->panim == PA_HURT && mo->player->spinouttimer == 0 && mo->player->squishedtimer == 0)
@ -2771,10 +2771,10 @@ void P_PlayerZMovement(mobj_t *mo)
P_SetPlayerMobjState(mo, S_KART_STILL);
}
if (!mo->standingslope && (mo->eflags & MFE_VERTICALFLIP ? tm.ceilingslope : tm.floorslope))
if (!mo->standingslope && (mo->eflags & MFE_VERTICALFLIP ? g_tm.ceilingslope : g_tm.floorslope))
{
// Handle landing on slope during Z movement
P_HandleSlopeLanding(mo, (mo->eflags & MFE_VERTICALFLIP ? tm.ceilingslope : tm.floorslope));
P_HandleSlopeLanding(mo, (mo->eflags & MFE_VERTICALFLIP ? g_tm.ceilingslope : g_tm.floorslope));
}
if (P_MobjFlip(mo) * mo->momz < 0) // falling
@ -2789,12 +2789,12 @@ void P_PlayerZMovement(mobj_t *mo)
if (clipmomz)
{
mo->momz = (tm.floorthing ? tm.floorthing->momz : 0);
mo->momz = (g_tm.floorthing ? g_tm.floorthing->momz : 0);
}
}
else if (tm.floorthing)
else if (g_tm.floorthing)
{
mo->momz = tm.floorthing->momz;
mo->momz = g_tm.floorthing->momz;
}
}
else
@ -2963,9 +2963,9 @@ boolean P_SceneryZMovement(mobj_t *mo)
{
mo->eflags |= MFE_JUSTHITFLOOR; // Spin Attack
if (tm.floorthing)
mo->momz = tm.floorthing->momz;
else if (!tm.floorthing)
if (g_tm.floorthing)
mo->momz = g_tm.floorthing->momz;
else if (!g_tm.floorthing)
mo->momz = 0;
}
}
@ -3633,8 +3633,8 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled
}
thiscam->subsector = R_PointInSubsectorFast(thiscam->x, thiscam->y);
thiscam->floorz = tm.floorz;
thiscam->ceilingz = tm.ceilingz;
thiscam->floorz = g_tm.floorz;
thiscam->ceilingz = g_tm.ceilingz;
if (thiscam->momz || player->mo->pmomz)
{
@ -3781,8 +3781,8 @@ static void P_PlayerMobjThinker(mobj_t *mobj)
mobj->z += mobj->momz;
P_SetThingPosition(mobj);
P_CheckPosition(mobj, mobj->x, mobj->y, NULL);
mobj->floorz = tm.floorz;
mobj->ceilingz = tm.ceilingz;
mobj->floorz = g_tm.floorz;
mobj->ceilingz = g_tm.ceilingz;
mobj->terrain = NULL;
goto animonly;
}
@ -8603,8 +8603,8 @@ void P_MobjThinker(mobj_t *mobj)
mobj->eflags &= ~(MFE_PUSHED|MFE_SPRUNG|MFE_JUSTBOUNCEDWALL|MFE_SLOPELAUNCHED);
// sal: what the hell? is there any reason this isn't done, like, literally ANYWHERE else?
P_SetTarget(&tm.floorthing, NULL);
P_SetTarget(&tm.hitthing, NULL);
P_SetTarget(&g_tm.floorthing, NULL);
P_SetTarget(&g_tm.hitthing, NULL);
if (udmf)
{
@ -8988,10 +8988,10 @@ void P_SceneryThinker(mobj_t *mobj)
P_CheckPosition(mobj, mobj->x, mobj->y, NULL); // Need this to pick up objects!
if (P_MobjWasRemoved(mobj))
return;
mobj->floorz = tm.floorz;
mobj->ceilingz = tm.ceilingz;
mobj->floorrover = tm.floorrover;
mobj->ceilingrover = tm.ceilingrover;
mobj->floorz = g_tm.floorz;
mobj->ceilingz = g_tm.ceilingz;
mobj->floorrover = g_tm.floorrover;
mobj->ceilingrover = g_tm.ceilingrover;
}
else
{

View file

@ -200,7 +200,7 @@ boolean P_BBoxInsidePolyobj(polyobj_t *po, fixed_t *bbox)
{
if (P_BoxOnLineSide(bbox, po->lines[i]) == 0)
return false;
if (tm.sweep)
if (g_tm.sweep)
{
P_TestLine(po->lines[i]);
}
@ -801,7 +801,7 @@ static void Polyobj_removeFromBlockmap(polyobj_t *po)
// Movement functions
// A version of Lee's routine from p_maputl.c that accepts an mobj pointer
// argument instead of using tm.thing. Returns true if the line isn't contacted
// argument instead of using g_tm.thing. Returns true if the line isn't contacted
// and false otherwise.
static inline boolean Polyobj_untouched(line_t *ld, mobj_t *mo)
{
@ -845,10 +845,10 @@ static void Polyobj_pushThing(polyobj_t *po, line_t *line, mobj_t *mo)
if (po->damage && (mo->flags & MF_SHOOTABLE))
{
P_CheckPosition(mo, mo->x + momx, mo->y + momy, NULL);
mo->floorz = tm.floorz;
mo->ceilingz = tm.ceilingz;
mo->floorrover = tm.floorrover;
mo->ceilingrover = tm.ceilingrover;
mo->floorz = g_tm.floorz;
mo->ceilingz = g_tm.ceilingz;
mo->floorrover = g_tm.floorrover;
mo->ceilingrover = g_tm.ceilingrover;
}
}

View file

@ -995,6 +995,7 @@ static void P_NetUnArchiveColormaps(savebuffer_t *save)
//diff5 flags
#define SD_ACTIVATION 0x01
#define SD_BOTCONTROLLER 0x02
static boolean P_SectorArgsEqual(const sector_t *sc, const sector_t *spawnsc)
{
@ -1230,6 +1231,12 @@ static void ArchiveSectors(savebuffer_t *save)
diff4 |= SD_STRINGARGS;
if (ss->activation != spawnss->activation)
diff5 |= SD_ACTIVATION;
if (/*ss->botController.trick != spawnss->botController.trick
||*/ss->botController.flags != spawnss->botController.flags
|| ss->botController.forceAngle != spawnss->botController.forceAngle)
{
diff5 |= SD_BOTCONTROLLER;
}
if (ss->ffloors && CheckFFloorDiff(ss))
diff |= SD_FFLOORS;
@ -1343,6 +1350,13 @@ static void ArchiveSectors(savebuffer_t *save)
if (diff5 & SD_ACTIVATION)
WRITEUINT32(save->p, ss->activation);
if (diff5 & SD_BOTCONTROLLER)
{
//WRITEUINT8(save->p, ss->botController.trick);
WRITEUINT32(save->p, ss->botController.flags);
WRITEANGLE(save->p, ss->botController.forceAngle);
}
if (diff & SD_FFLOORS)
ArchiveFFloors(save, ss);
}
@ -1499,6 +1513,13 @@ static void UnArchiveSectors(savebuffer_t *save)
if (diff5 & SD_ACTIVATION)
sectors[i].activation = READUINT32(save->p);
if (diff5 & SD_BOTCONTROLLER)
{
//sectors[i].botController.trick = READUINT8(save->p);
sectors[i].botController.flags = READUINT32(save->p);
sectors[i].botController.forceAngle = READANGLE(save->p);
}
if (diff & SD_FFLOORS)
UnArchiveFFloors(save, &sectors[i]);
}

View file

@ -942,6 +942,8 @@ static void P_InitializeSector(sector_t *ss)
ss->spawn_lightlevel = ss->lightlevel;
ss->spawn_extra_colormap = NULL;
memset(&ss->botController, 0, sizeof(ss->botController));
}
static void P_LoadSectors(UINT8 *data)
@ -8634,7 +8636,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
P_ResetTubeWaypoints();
P_MapStart(); // tm.thing can be used starting from this point
P_MapStart(); // g_tm.thing can be used starting from this point
// init anything that P_SpawnSlopes/P_LoadThings needs to know
P_InitSpecials();
@ -8749,7 +8751,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
G_AddMapToBuffer(gamemap-1);
P_MapEnd(); // tm.thing is no longer needed from this point onwards
P_MapEnd(); // g_tm.thing is no longer needed from this point onwards
// Took me 3 hours to figure out why my progression kept on getting overwritten with the titlemap...
if (!titlemapinaction)
@ -8834,7 +8836,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
void P_PostLoadLevel(void)
{
TracyCZone(__zone, true);
P_MapStart(); // tm.thing can be used starting from this point
P_MapStart(); // g_tm.thing can be used starting from this point
if (G_GametypeHasSpectators())
{

View file

@ -1,8 +1,10 @@
// SONIC ROBO BLAST 2
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2020 by Sonic Team Junior.
// Copyright (C) 2024 by Sally "TehRealSalt" Cochenour.
// Copyright (C) 2024 by Kart Krew.
// Copyright (C) 2020 by Sonic Team Junior.
// Copyright (C) 2000 by DooM Legacy Team.
// Copyright (C) 1996 by id Software, Inc.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
@ -37,7 +39,6 @@ typedef struct
mobj_t *t1, *t2;
boolean alreadyHates; // For bot traversal, for if the bot is already in a sector it doesn't want to be
UINT8 traversed;
mobj_t *compareThing; // Original thing
} los_t;
typedef boolean (*los_init_t)(mobj_t *, mobj_t *, register los_t *);
@ -53,7 +54,11 @@ typedef struct
static INT32 sightcounts[2];
#define TRAVERSE_MAX (8)
#ifdef DEVELOP
extern consvar_t cv_debugtraversemax;
#undef TRAVERSE_MAX
#define TRAVERSE_MAX (cv_debugtraversemax.value)
#endif
//
// P_DivlineSide
@ -335,13 +340,13 @@ static boolean P_CanBotTraverse(seg_t *seg, divline_t *divl, register los_t *los
frac = P_InterceptVector(&los->strace, divl);
// calculate position at intercept
tm.x = los->strace.x + FixedMul(los->strace.dx, frac);
tm.y = los->strace.y + FixedMul(los->strace.dy, frac);
g_tm.x = los->strace.x + FixedMul(los->strace.dx, frac);
g_tm.y = los->strace.y + FixedMul(los->strace.dy, frac);
// set openrange, opentop, openbottom
open.fofType = (flip ? LO_FOF_CEILINGS : LO_FOF_FLOORS);
P_LineOpening(line, los->t1, &open);
maxstep = P_GetThingStepUp(los->t1, tm.x, tm.y);
maxstep = P_GetThingStepUp(los->t1, g_tm.x, g_tm.y);
if (open.range < los->t1->height)
{
@ -363,7 +368,7 @@ static boolean P_CanBotTraverse(seg_t *seg, divline_t *divl, register los_t *los
UINT8 side = P_DivlineSide(los->t2x, los->t2y, divl) & 1;
sector_t *sector = (side == 1) ? seg->backsector : seg->frontsector;
if (K_BotHatesThisSector(los->t1->player, sector, tm.x, tm.y))
if (K_BotHatesThisSector(los->t1->player, sector, g_tm.x, g_tm.y))
{
// This line does not block us, but we don't want to cross it regardless.
return false;
@ -403,13 +408,13 @@ static boolean P_CanWaypointTraverse(seg_t *seg, divline_t *divl, register los_t
frac = P_InterceptVector(&los->strace, divl);
// calculate position at intercept
tm.x = los->strace.x + FixedMul(los->strace.dx, frac);
tm.y = los->strace.y + FixedMul(los->strace.dy, frac);
g_tm.x = los->strace.x + FixedMul(los->strace.dx, frac);
g_tm.y = los->strace.y + FixedMul(los->strace.dy, frac);
// set openrange, opentop, openbottom
open.fofType = (flip ? LO_FOF_CEILINGS : LO_FOF_FLOORS);
P_LineOpening(line, los->t1, &open);
maxstep = P_GetThingStepUp(los->t1, tm.x, tm.y);
maxstep = P_GetThingStepUp(los->t1, g_tm.x, g_tm.y);
#if 0
if (los->t2->type == MT_WAYPOINT)
@ -470,10 +475,11 @@ static boolean P_CrossSubsector(size_t num, register los_t *los, register los_fu
seg_t *seg;
INT32 count;
#ifdef RANGECHECK
if (num >= numsubsectors)
I_Error("P_CrossSubsector: ss %s with numss = %s\n", sizeu1(num), sizeu2(numsubsectors));
#endif
{
CONS_Debug(DBG_RENDER, "P_CrossSubsector: ss %s with numss = %s\n", sizeu1(num), sizeu2(numsubsectors));
return true;
}
// haleyjd 02/23/06: this assignment should be after the above check
seg = segs + subsectors[num].firstline;
@ -556,11 +562,6 @@ static boolean P_CrossSubsector(size_t num, register los_t *los, register los_fu
static boolean P_CrossBSPNode(INT32 bspnum, register los_t *los, register los_funcs_t *funcs)
{
if (funcs->validate == NULL)
{
return false;
}
while (!(bspnum & NF_SUBSECTOR))
{
register node_t *bsp = nodes + bspnum;

View file

@ -2431,6 +2431,20 @@ mobj_t* P_FindObjectTypeFromTag(mobjtype_t type, mtag_t tag)
}
}
static void K_UpdateBotControllers(INT32 *args)
{
INT32 secnum;
TAG_ITER_SECTORS(args[0], secnum)
{
sector_t *const sec = sectors + secnum;
//sec->botController.trick = args[1];
sec->botController.flags = args[2];
sec->botController.forceAngle = FixedAngle(args[3] * FRACUNIT);
}
}
/** Processes the line special triggered by an object.
*
* \param line Line with the special command on it.
@ -4426,6 +4440,12 @@ boolean P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, cha
}
break;
case 2004: // Bot Controller.
{
K_UpdateBotControllers(args);
break;
}
default:
break;
}
@ -7692,6 +7712,10 @@ void P_SpawnSpecials(boolean fromnetsave)
}
break;
case 2004: // Bot Controller.
K_UpdateBotControllers(lines[i].args);
break;
default:
break;
}

View file

@ -360,6 +360,14 @@ typedef enum
MSF_DIRECTIONLIGHTING = 1<<14,
} sectorflags_t;
// Per-sector bot controller override
struct botcontroller_t
{
//UINT8 trick;
UINT32 flags;
angle_t forceAngle;
};
typedef enum
{
SSF_NOSTEPUP = 1,
@ -568,6 +576,9 @@ struct sector_t
// colormap structure
extracolormap_t *spawn_extra_colormap;
// Ring Racers bots
botcontroller_t botController;
// Action specials
INT16 action;
INT32 args[NUM_SCRIPT_ARGS];

View file

@ -158,6 +158,7 @@ TYPEDEF (weakspot_t);
// k_bot.h
TYPEDEF (botprediction_t);
TYPEDEF (botcontroller_t);
// k_brightmap.h
TYPEDEF (brightmapStorage_t);