mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Merge remote-tracking branch 'origin/master' into no-trick-input-filter
This commit is contained in:
commit
3baf39a1fd
20 changed files with 248 additions and 90 deletions
|
|
@ -2,6 +2,10 @@ include:
|
|||
- '.gitlab/ci/templates/*.yml'
|
||||
- '.gitlab/ci/jobs/*.yml'
|
||||
|
||||
workflow:
|
||||
auto_cancel:
|
||||
on_new_commit: interruptible
|
||||
|
||||
variables:
|
||||
GIT_CLONE_PATH: $CI_BUILDS_DIR/$CI_CONCURRENT_ID/$CI_PROJECT_PATH
|
||||
GIT_DEPTH: 20
|
||||
|
|
@ -10,5 +14,6 @@ stages:
|
|||
- build
|
||||
|
||||
default:
|
||||
interruptible: true
|
||||
artifacts:
|
||||
expire_in: 1 day
|
||||
|
|
|
|||
|
|
@ -46,6 +46,9 @@ Environment::Environment()
|
|||
// Not that we're adding any modules to it, though. :p
|
||||
global->active = true;
|
||||
|
||||
// Set a branch limit (same as ZDoom's instruction limit)
|
||||
branchLimit = 2000000;
|
||||
|
||||
// Add the data & function pointers.
|
||||
|
||||
// Starting with raw ACS0 codes. I'm using this classic-style
|
||||
|
|
@ -405,3 +408,42 @@ ACSVM::Word Environment::callSpecImpl
|
|||
P_ProcessSpecial(activator, spec, args, stringargs);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Environment::printKill(ACSVM::Thread *thread, ACSVM::Word type, ACSVM::Word data)
|
||||
{
|
||||
std::string scriptName;
|
||||
|
||||
ACSVM::String *scriptNamePtr = (thread->script != nullptr) ? (thread->script->name.s) : nullptr;
|
||||
if (scriptNamePtr && scriptNamePtr->len)
|
||||
scriptName = std::string(scriptNamePtr->str);
|
||||
else
|
||||
scriptName = std::to_string((int)thread->script->name.i);
|
||||
|
||||
ACSVM::KillType killType = static_cast<ACSVM::KillType>(type);
|
||||
|
||||
if (killType == ACSVM::KillType::BranchLimit)
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, "Terminated runaway script %s\n", scriptName.c_str());
|
||||
return;
|
||||
}
|
||||
else if (killType == ACSVM::KillType::UnknownCode)
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, "ACSVM ERROR: Unknown opcode %d in script %s\n", data, scriptName.c_str());
|
||||
}
|
||||
else if (killType == ACSVM::KillType::UnknownFunc)
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, "ACSVM ERROR: Unknown function %d in script %s\n", data, scriptName.c_str());
|
||||
}
|
||||
else if (killType == ACSVM::KillType::OutOfBounds)
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, "ACSVM ERROR: Jumped to out of bounds location %lu in script %s\n",
|
||||
(thread->codePtr - thread->module->codeV.data() - 1), scriptName.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, "ACSVM ERROR: Kill %u:%d at %lu in script %s\n",
|
||||
type, data, (thread->codePtr - thread->module->codeV.data() - 1), scriptName.c_str());
|
||||
}
|
||||
|
||||
CONS_Printf("Script terminated.\n");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ public:
|
|||
|
||||
virtual ACSVM::Thread *allocThread();
|
||||
|
||||
virtual void printKill(ACSVM::Thread *thread, ACSVM::Word type, ACSVM::Word data);
|
||||
|
||||
protected:
|
||||
virtual void loadModule(ACSVM::Module *module);
|
||||
|
||||
|
|
|
|||
|
|
@ -860,7 +860,7 @@ consvar_t cv_ufo_health = OnlineCheat("ufo_health", "-1").min_max(-1, 100).descr
|
|||
consvar_t cv_botscanvote = ServerCheat("botscanvote", "No").yes_no();
|
||||
|
||||
void Gravity_OnChange(void);
|
||||
consvar_t cv_gravity = ServerCheat("gravity", "0.8").floating_point().onchange(Gravity_OnChange).description("Change the default gravity"); // change DEFAULT_GRAVITY if you change this
|
||||
consvar_t cv_gravity = ServerCheat("gravity", "0.8").floating_point().min_max(0, 200*FRACUNIT).onchange(Gravity_OnChange).description("Change the default gravity"); // change DEFAULT_GRAVITY if you change this
|
||||
|
||||
consvar_t cv_kartdebugcolorize = ServerCheat("debugcolorize", "Off").on_off().description("Show all colorized options on the HUD");
|
||||
consvar_t cv_kartdebugdirector = ServerCheat("debugdirector", "Off").on_off().description("Show director AI on the HUD");
|
||||
|
|
|
|||
|
|
@ -5762,8 +5762,26 @@ static void CL_SendClientCmd(void)
|
|||
spike_time = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
if (server) // Clients have to wait for the gamestate to make it back. Servers don't!
|
||||
lagDelay *= 2; // Simulate the HELLFUCK NIGHTMARE of a complete round trip.
|
||||
*/
|
||||
|
||||
// [deep breath in]
|
||||
// Plausible, elegant explanation that is WRONG AND SUPER HARMFUL.
|
||||
// Clients with stable connections were adding their mindelay to network delay,
|
||||
// even when their mindelay was as high or higher than network delay—which made
|
||||
// client delay APPEAR slower than host mindelay, by the exact value that made
|
||||
// "lmao just double it" make sense at the time.
|
||||
//
|
||||
// While this fix made client connections match server mindelay in our most common
|
||||
// test environment, it also masked an issue that seriously affected online handling
|
||||
// responsiveness, completely ruining our opportunity to further investigate it!
|
||||
//
|
||||
// See UpdatePingTable.
|
||||
// I am taking this shitty code to my grave as an example of "never trust your brain".
|
||||
// -Tyron 2024-05-15
|
||||
|
||||
}
|
||||
|
||||
packetsize = sizeof (clientcmd_pak);
|
||||
|
|
@ -6335,8 +6353,15 @@ static void UpdatePingTable(void)
|
|||
}
|
||||
else // We're a client, handle mindelay on the way out.
|
||||
{
|
||||
if ((neededtic - gametic) < (tic_t)cv_mindelay.value)
|
||||
lowest_lag = cv_mindelay.value - (neededtic - gametic);
|
||||
// Previously (neededtic - gametic) - WRONG VALUE!
|
||||
// Pretty sure that's measuring jitter, not RTT.
|
||||
// Stable connections would be punished by adding their mindelay to network delay!
|
||||
tic_t mydelay = playerpingtable[consoleplayer];
|
||||
|
||||
if (mydelay < (tic_t)cv_mindelay.value)
|
||||
lowest_lag = cv_mindelay.value - mydelay;
|
||||
else
|
||||
lowest_lag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ extern "C" consvar_t cv_lua_profile, cv_menuframeskip;
|
|||
#define ASSET_HASH_MAPS_PK3 "a8bd1f924531c483f500d96583b7b837"
|
||||
#define ASSET_HASH_UNLOCKS_PK3 "ebc06ff46c2cc80e93dadf5f7099d7b8"
|
||||
#define ASSET_HASH_STAFFGHOSTS_PK3 "9cb77f6c0e801c1bc61ca84870b65707"
|
||||
#define ASSET_HASH_SHADERS_PK3 "dbfb1d5eb9818cd2fb81680c0bab05c0"
|
||||
#define ASSET_HASH_SHADERS_PK3 "7aefd2aa55129b31210aa094cf782695"
|
||||
#ifdef USE_PATCH_FILE
|
||||
#define ASSET_HASH_PATCH_PK3 "00000000000000000000000000000000"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -6461,14 +6461,12 @@ void Command_Retry_f(void)
|
|||
*/
|
||||
static void Command_Isgamemodified_f(void)
|
||||
{
|
||||
if (majormods)
|
||||
CONS_Printf("The game has been modified with major addons, so you cannot play Record Attack.\n");
|
||||
else if (savemoddata)
|
||||
CONS_Printf("The game has been modified with an addon with its own save data, so you can play Record Attack and earn medals.\n");
|
||||
if (savemoddata)
|
||||
CONS_Printf("The game has been modified with an addon using its own save data.\n");
|
||||
else if (modifiedgame)
|
||||
CONS_Printf("The game has been modified with only minor addons. You can play Record Attack, earn medals and unlock extras.\n");
|
||||
CONS_Printf("The game has been modified, but is still using Ring Racers save data.\n");
|
||||
else
|
||||
CONS_Printf("The game has not been modified. You can play Record Attack, earn medals and unlock extras.\n");
|
||||
CONS_Printf("The game has not been modified.\n");
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
|
|
|||
|
|
@ -170,8 +170,9 @@ demoghost *ghosts = NULL;
|
|||
// - SPB cup TA replays were recorded at this time
|
||||
// - Slope physics changed with a scaling fix
|
||||
// - 0x000C (Ring Racers v2.2)
|
||||
// - 0x000D (Ring Racers v2.3)
|
||||
|
||||
#define DEMOVERSION 0x000C
|
||||
#define DEMOVERSION 0x000D
|
||||
|
||||
boolean G_CompatLevel(UINT16 level)
|
||||
{
|
||||
|
|
@ -2278,6 +2279,7 @@ void G_BeginRecording(void)
|
|||
WRITEUINT8(demobuf.p, grandprixinfo.gamespeed);
|
||||
WRITEUINT8(demobuf.p, grandprixinfo.masterbots == true);
|
||||
WRITEUINT8(demobuf.p, grandprixinfo.eventmode);
|
||||
WRITEUINT32(demobuf.p, grandprixinfo.specialDamage);
|
||||
}
|
||||
|
||||
// Save netUnlocked from actual unlocks
|
||||
|
|
@ -2525,8 +2527,9 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
|
|||
{
|
||||
case DEMOVERSION: // latest always supported
|
||||
case 0x0009: // older staff ghosts
|
||||
case 0x000A: // older staff ghosts
|
||||
case 0x000B: // older staff ghosts
|
||||
case 0x000A: // 2.0, 2.1
|
||||
case 0x000B: // 2.2 indev (staff ghosts)
|
||||
case 0x000C: // 2.2
|
||||
break;
|
||||
// too old, cannot support.
|
||||
default:
|
||||
|
|
@ -2676,8 +2679,9 @@ void G_LoadDemoInfo(menudemo_t *pdemo, boolean allownonmultiplayer)
|
|||
{
|
||||
case DEMOVERSION: // latest always supported
|
||||
case 0x0009: // older staff ghosts
|
||||
case 0x000A: // older staff ghosts
|
||||
case 0x000B: // older staff ghosts
|
||||
case 0x000A: // 2.0, 2.1
|
||||
case 0x000B: // 2.2 indev (staff ghosts)
|
||||
case 0x000C: // 2.2
|
||||
if (P_SaveBufferRemaining(&info) < 64)
|
||||
{
|
||||
goto corrupt;
|
||||
|
|
@ -3105,8 +3109,9 @@ void G_DoPlayDemoEx(const char *defdemoname, lumpnum_t deflumpnum)
|
|||
{
|
||||
case DEMOVERSION: // latest always supported
|
||||
case 0x0009: // older staff ghosts
|
||||
case 0x000A: // older staff ghosts
|
||||
case 0x000B: // older staff ghosts
|
||||
case 0x000A: // 2.0, 2.1
|
||||
case 0x000B: // 2.2 indev (staff ghosts)
|
||||
case 0x000C: // 2.2
|
||||
break;
|
||||
// too old, cannot support.
|
||||
default:
|
||||
|
|
@ -3275,6 +3280,10 @@ void G_DoPlayDemoEx(const char *defdemoname, lumpnum_t deflumpnum)
|
|||
grandprixinfo.gamespeed = READUINT8(demobuf.p);
|
||||
grandprixinfo.masterbots = READUINT8(demobuf.p) != 0;
|
||||
grandprixinfo.eventmode = static_cast<gpEvent_e>(READUINT8(demobuf.p));
|
||||
if (demo.version >= 0x000D)
|
||||
{
|
||||
grandprixinfo.specialDamage = READUINT32(demobuf.p);
|
||||
}
|
||||
}
|
||||
|
||||
// Load unlocks into netUnlocked
|
||||
|
|
@ -3565,8 +3574,9 @@ void G_AddGhost(savebuffer_t *buffer, const char *defdemoname)
|
|||
{
|
||||
case DEMOVERSION: // latest always supported
|
||||
case 0x0009: // older staff ghosts
|
||||
case 0x000A: // older staff ghosts
|
||||
case 0x000B: // older staff ghosts
|
||||
case 0x000A: // 2.0, 2.1
|
||||
case 0x000B: // 2.2 indev (staff ghosts)
|
||||
case 0x000C: // 2.2
|
||||
break;
|
||||
// too old, cannot support.
|
||||
default:
|
||||
|
|
@ -3653,7 +3663,11 @@ void G_AddGhost(savebuffer_t *buffer, const char *defdemoname)
|
|||
}
|
||||
|
||||
if ((flags & DF_GRANDPRIX))
|
||||
{
|
||||
p += 3;
|
||||
if (ghostversion >= 0x000D)
|
||||
p++;
|
||||
}
|
||||
|
||||
// Skip unlockables
|
||||
{
|
||||
|
|
@ -3823,8 +3837,9 @@ staffbrief_t *G_GetStaffGhostBrief(UINT8 *buffer)
|
|||
{
|
||||
case DEMOVERSION: // latest always supported
|
||||
case 0x0009: // older staff ghosts
|
||||
case 0x000A: // older staff ghosts
|
||||
case 0x000B: // older staff ghosts
|
||||
case 0x000A: // 2.0, 2.1
|
||||
case 0x000B: // 2.2 indev (staff ghosts)
|
||||
case 0x000C: // 2.2
|
||||
break;
|
||||
|
||||
// too old, cannot support.
|
||||
|
|
@ -3878,7 +3893,11 @@ staffbrief_t *G_GetStaffGhostBrief(UINT8 *buffer)
|
|||
}
|
||||
|
||||
if ((flags & DF_GRANDPRIX))
|
||||
{
|
||||
p += 3;
|
||||
if (ghostversion >= 0x000D)
|
||||
p++;
|
||||
}
|
||||
|
||||
// Skip unlockables
|
||||
{
|
||||
|
|
|
|||
|
|
@ -358,7 +358,7 @@ void G_ClearRecords(void)
|
|||
|
||||
// TODO: Technically, these should only remove time attack records here.
|
||||
// But I'm out of juice for dev (+ literally, just finished some OJ).
|
||||
// The stats need to be cleared in M_ClearStats, and I guess there's
|
||||
// The stats need to be cleared in M_ClearStats, and I guess there's
|
||||
// no perfect place to wipe mapvisited because it's not actually part of
|
||||
// basegame progression... so here's fine for launch. ~toast 100424
|
||||
unloaded_mapheader_t *unloadedmap, *nextunloadedmap = NULL;
|
||||
|
|
@ -652,7 +652,7 @@ static void G_UpdateRecordReplays(void)
|
|||
}
|
||||
}
|
||||
|
||||
// for consistency among messages: this modifies the game and removes savemoddata.
|
||||
// for consistency among messages: this marks the game as modified.
|
||||
void G_SetGameModified(boolean silent, boolean major)
|
||||
{
|
||||
if ((majormods && modifiedgame) || !mainwads || (refreshdirmenu & REFRESHDIR_GAMEDATA)) // new gamedata amnesty?
|
||||
|
|
@ -666,9 +666,6 @@ void G_SetGameModified(boolean silent, boolean major)
|
|||
//savemoddata = false; -- there is literally no reason to do this anymore.
|
||||
majormods = true;
|
||||
|
||||
if (!silent)
|
||||
CONS_Alert(CONS_NOTICE, M_GetText("Game must be restarted to play Record Attack.\n"));
|
||||
|
||||
// If in record attack recording, cancel it.
|
||||
if (modeattacking)
|
||||
M_EndModeAttackRun();
|
||||
|
|
|
|||
|
|
@ -287,15 +287,28 @@ void srb2::save_ng_gamedata()
|
|||
|
||||
std::string gamedataname_s {gamedatafilename};
|
||||
fs::path savepath {fmt::format("{}/{}", srb2home, gamedataname_s)};
|
||||
int random_number = rand();
|
||||
fs::path tmpsavepath {fmt::format("{}/{}_{}.tmp", srb2home, gamedataname_s, random_number)};
|
||||
fs::path baksavepath {fmt::format("{}/{}.bak", srb2home, gamedataname_s)};
|
||||
|
||||
json ngdata_json = ng;
|
||||
|
||||
|
||||
if (fs::exists(savepath))
|
||||
{
|
||||
try
|
||||
{
|
||||
fs::rename(savepath, baksavepath);
|
||||
}
|
||||
catch (const fs::filesystem_error& ex)
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, "Failed to record backup save. Not attempting to save. %s\n", ex.what());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
std::string tmpsavepathstring = tmpsavepath.string();
|
||||
srb2::io::FileStream file {tmpsavepathstring, srb2::io::FileStreamMode::kWrite};
|
||||
std::string savepathstring = savepath.string();
|
||||
srb2::io::FileStream file {savepathstring, srb2::io::FileStreamMode::kWrite};
|
||||
|
||||
// The header is necessary to validate during loading.
|
||||
srb2::io::write(static_cast<uint32_t>(GD_VERSION_MAJOR), file); // major
|
||||
|
|
@ -308,21 +321,11 @@ void srb2::save_ng_gamedata()
|
|||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, "NG Gamedata save failed: %s\n", ex.what());
|
||||
CONS_Alert(CONS_ERROR, "NG Gamedata save failed. Check directory for a ringdata.dat.bak. %s\n", ex.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, "NG Gamedata save failed\n");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Now that the save is written successfully, move it over the old save
|
||||
fs::rename(tmpsavepath, savepath);
|
||||
}
|
||||
catch (const fs::filesystem_error& ex)
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, "NG Gamedata save succeeded but did not replace old save successfully: %s\n", ex.what());
|
||||
CONS_Alert(CONS_ERROR, "NG Gamedata save failed. Check directory for a ringdata.dat.bak.\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include "m_random.h"
|
||||
#include "r_things.h" // numskins
|
||||
#include "k_roulette.h"
|
||||
#include "m_easing.h"
|
||||
|
||||
/*--------------------------------------------------
|
||||
static inline boolean K_ItemButtonWasDown(const player_t *player)
|
||||
|
|
@ -1193,7 +1194,10 @@ static void K_BotItemLightning(const player_t *player, ticcmd_t *cmd)
|
|||
{
|
||||
ZoneScoped;
|
||||
|
||||
if (K_BotUseItemNearPlayer(player, cmd, 192*player->mo->scale) == false)
|
||||
fixed_t radius = 192 * player->mo->scale;
|
||||
radius = Easing_Linear(FRACUNIT * player->botvars.difficulty / MAXBOTDIFFICULTY, 2*radius, radius);
|
||||
|
||||
if (K_BotUseItemNearPlayer(player, cmd, radius) == false)
|
||||
{
|
||||
if (player->botvars.itemconfirm > 10*TICRATE)
|
||||
{
|
||||
|
|
@ -1232,7 +1236,8 @@ static void K_BotItemBubble(const player_t *player, ticcmd_t *cmd)
|
|||
|
||||
if (player->bubblecool <= 0)
|
||||
{
|
||||
const fixed_t radius = 192 * player->mo->scale;
|
||||
fixed_t radius = 192 * player->mo->scale;
|
||||
radius = Easing_Linear(FRACUNIT * player->botvars.difficulty / MAXBOTDIFFICULTY, 2*radius, radius);
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2148,6 +2148,12 @@ void K_DrawKartPositionNumXY(
|
|||
boolean exit, boolean lastLap, boolean losing
|
||||
)
|
||||
{
|
||||
if (cv_reducevfx.value != 0)
|
||||
{
|
||||
// Reduce the flashing rate
|
||||
counter /= 4;
|
||||
}
|
||||
|
||||
counter /= 3; // Alternate colors every three frames
|
||||
|
||||
UINT8 *color = NULL;
|
||||
|
|
@ -5025,14 +5031,31 @@ static void K_drawKartStartBulbs(void)
|
|||
|
||||
bulbtic -= 14;
|
||||
|
||||
// Reduce VFX disables the bulb animation while still presenting this indicator
|
||||
|
||||
if (bulbtic > length)
|
||||
{
|
||||
bulbtic -= length;
|
||||
patchnum = chillloop_animation[bulbtic % 2];
|
||||
|
||||
if (cv_reducevfx.value != 0)
|
||||
{
|
||||
patchnum = chillloop_animation[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
patchnum = chillloop_animation[bulbtic % 2];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
patchnum = loop_animation[bulbtic % 4];
|
||||
if (cv_reducevfx.value != 0)
|
||||
{
|
||||
patchnum = loop_animation[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
patchnum = loop_animation[bulbtic % 4];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
53
src/k_kart.c
53
src/k_kart.c
|
|
@ -12617,7 +12617,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
// if a player picks up an item during the instawhip input safety window—the one that triggers
|
||||
// after you burn to 0 rings—they can continue to hold the input, then charge a usable whip
|
||||
// without stopping the roulette and acquiring an item, which cancels it.
|
||||
//
|
||||
//
|
||||
// No ghosts use this technique, but your least favorite tournament player might.
|
||||
if (player->itemRoulette.active)
|
||||
{
|
||||
|
|
@ -12857,9 +12857,9 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
}
|
||||
else if (ATTACK_IS_DOWN && (player->itemflags & IF_ITEMOUT)) // Banana x3 thrown
|
||||
{
|
||||
player->itemamount--;
|
||||
K_ThrowKartItem(player, false, MT_BANANA, -1, 0, 0);
|
||||
K_PlayAttackTaunt(player->mo);
|
||||
player->itemamount--;
|
||||
K_UpdateHnextList(player, false);
|
||||
player->botvars.itemconfirm = 0;
|
||||
}
|
||||
|
|
@ -12923,9 +12923,9 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
}
|
||||
else if (ATTACK_IS_DOWN && (player->itemflags & IF_ITEMOUT)) // Orbinaut x3 thrown
|
||||
{
|
||||
player->itemamount--;
|
||||
K_ThrowKartItem(player, true, MT_ORBINAUT, 1, 0, 0);
|
||||
K_PlayAttackTaunt(player->mo);
|
||||
player->itemamount--;
|
||||
K_UpdateHnextList(player, false);
|
||||
player->botvars.itemconfirm = 0;
|
||||
}
|
||||
|
|
@ -12966,9 +12966,9 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
}
|
||||
else if (ATTACK_IS_DOWN && HOLDING_ITEM && (player->itemflags & IF_ITEMOUT)) // Jawz thrown
|
||||
{
|
||||
player->itemamount--;
|
||||
K_ThrowKartItem(player, true, MT_JAWZ, 1, 0, 0);
|
||||
K_PlayAttackTaunt(player->mo);
|
||||
player->itemamount--;
|
||||
K_UpdateHnextList(player, false);
|
||||
player->botvars.itemconfirm = 0;
|
||||
}
|
||||
|
|
@ -12994,9 +12994,9 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
}
|
||||
else if (ATTACK_IS_DOWN && (player->itemflags & IF_ITEMOUT))
|
||||
{
|
||||
player->itemamount--;
|
||||
K_ThrowKartItem(player, false, MT_SSMINE, 1, 1, 0);
|
||||
K_PlayAttackTaunt(player->mo);
|
||||
player->itemamount--;
|
||||
player->itemflags &= ~IF_ITEMOUT;
|
||||
K_UpdateHnextList(player, true);
|
||||
player->botvars.itemconfirm = 0;
|
||||
|
|
@ -13032,9 +13032,9 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
}
|
||||
else if (ATTACK_IS_DOWN && (player->itemflags & IF_ITEMOUT))
|
||||
{
|
||||
player->itemamount--;
|
||||
K_ThrowKartItem(player, (player->throwdir > 0), MT_DROPTARGET, -1, 0, 0);
|
||||
K_PlayAttackTaunt(player->mo);
|
||||
player->itemamount--;
|
||||
player->itemflags &= ~IF_ITEMOUT;
|
||||
K_UpdateHnextList(player, true);
|
||||
player->botvars.itemconfirm = 0;
|
||||
|
|
@ -13276,9 +13276,10 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
|
||||
if (player->bubbleblowup > bubbletime*2)
|
||||
{
|
||||
player->itemamount--;
|
||||
K_ThrowKartItem(player, (player->throwdir > 0), MT_BUBBLESHIELDTRAP, -1, 0, 0);
|
||||
if (player->throwdir == -1)
|
||||
{
|
||||
{
|
||||
P_InstaThrust(player->mo, player->mo->angle, player->speed + (80 * mapobjectscale));
|
||||
player->wavedashboost += TICRATE;
|
||||
player->wavedashpower = FRACUNIT;
|
||||
|
|
@ -13288,7 +13289,6 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
player->bubbleblowup = 0;
|
||||
player->bubblecool = 0;
|
||||
player->itemflags &= ~IF_HOLDREADY;
|
||||
player->itemamount--;
|
||||
player->botvars.itemconfirm = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -13362,7 +13362,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
player->mo, player->mo->angle,
|
||||
FixedMul((50*player->mo->scale), K_GetKartGameSpeedScalar(gamespeed))
|
||||
);
|
||||
|
||||
|
||||
player->wavedashboost += TICRATE;
|
||||
player->wavedashpower = FRACUNIT;
|
||||
player->fakeBoost = TICRATE/3;
|
||||
|
|
@ -13454,9 +13454,9 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
}
|
||||
else if (ATTACK_IS_DOWN && HOLDING_ITEM && (player->itemflags & IF_ITEMOUT)) // Sink thrown
|
||||
{
|
||||
player->itemamount--;
|
||||
K_ThrowKartItem(player, false, MT_SINK, 1, 2, 0);
|
||||
K_PlayAttackTaunt(player->mo);
|
||||
player->itemamount--;
|
||||
player->itemflags &= ~IF_ITEMOUT;
|
||||
K_UpdateHnextList(player, true);
|
||||
player->botvars.itemconfirm = 0;
|
||||
|
|
@ -13465,11 +13465,11 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
case KITEM_GACHABOM:
|
||||
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
|
||||
{
|
||||
player->itemamount--;
|
||||
K_SetItemOut(player); // need this to set itemscale
|
||||
K_ThrowKartItem(player, true, MT_GACHABOM, 0, 0, 0);
|
||||
K_UnsetItemOut(player);
|
||||
K_PlayAttackTaunt(player->mo);
|
||||
player->itemamount--;
|
||||
player->roundconditions.gachabom_miser = (
|
||||
(player->roundconditions.gachabom_miser == 0)
|
||||
? 1 : 0xFF
|
||||
|
|
@ -13596,7 +13596,13 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
|
||||
// We'll never need to go above that.
|
||||
if (player->tricktime <= TRICKDELAY)
|
||||
{
|
||||
// 2.3 - Prevent accidental fastfalls during trickdelay
|
||||
if (!G_CompatLevel(0x000C))
|
||||
player->pflags |= PF_NOFASTFALL;
|
||||
|
||||
player->tricktime++;
|
||||
}
|
||||
|
||||
// debug shit
|
||||
//CONS_Printf("%d\n", player->mo->momz / mapobjectscale);
|
||||
|
|
@ -13628,14 +13634,20 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
// INT16 aimingcompare = abs(cmd->throwdir) - abs(cmd->turning);
|
||||
|
||||
boolean cantrick = true;
|
||||
UINT16 buttons = player->cmd.buttons;
|
||||
|
||||
// 2.2 - Pre-steering trickpanels
|
||||
if (!G_CompatLevel(0x000A) && !K_PlayerUsesBotMovement(player))
|
||||
{
|
||||
if (!(player->cmd.buttons & BT_ACCELERATE))
|
||||
if (!(buttons & BT_ACCELERATE))
|
||||
{
|
||||
cantrick = false;
|
||||
}
|
||||
// 2.3 - also allow tricking with the Spindash button
|
||||
else if (!G_CompatLevel(0x000C) && ((buttons & BT_SPINDASHMASK) == BT_SPINDASHMASK))
|
||||
{
|
||||
player->pflags |= PF_NOFASTFALL;
|
||||
}
|
||||
}
|
||||
|
||||
// Uses cmd->turning over steering intentionally.
|
||||
|
|
@ -13880,9 +13892,22 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
}
|
||||
else
|
||||
{
|
||||
if ((player->pflags & PF_TRICKDELAY) && !(player->cmd.buttons & BT_ACCELERATE) && (player->tricktime >= TRICKDELAY))
|
||||
if (G_CompatLevel(0x000C))
|
||||
{
|
||||
player->pflags &= ~PF_TRICKDELAY;
|
||||
if ((player->pflags & PF_TRICKDELAY) && !(player->cmd.buttons & BT_ACCELERATE) && (player->tricktime >= TRICKDELAY))
|
||||
{
|
||||
player->pflags &= ~PF_TRICKDELAY;
|
||||
}
|
||||
}
|
||||
else
|
||||
// 2.3 - Spindash to trick
|
||||
{
|
||||
// Ignore pre-existing Accel inputs if not pressing Spindash. Always ignore pre-existing Spindash inputs to prevent accidental tricking.
|
||||
if ((player->pflags & PF_TRICKDELAY) && (!(player->cmd.buttons & BT_ACCELERATE) || (((player->cmd.buttons & BT_SPINDASHMASK) == BT_SPINDASHMASK) && (player->oldcmd.buttons & BT_SPINDASHMASK) != BT_SPINDASHMASK)) && (player->tricktime >= TRICKDELAY))
|
||||
{
|
||||
player->pflags &= ~PF_TRICKDELAY;
|
||||
player->pflags |= PF_NOFASTFALL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -88,6 +88,9 @@ static void M_AddFloatVar(consvar_t *cv, fixed_t step)
|
|||
|
||||
const CV_PossibleValue_t *values = cv->PossibleValue;
|
||||
|
||||
if (values == NULL) //cvar is unbounded and will not work! return is here only as a failsafe to prevent crashes
|
||||
return;
|
||||
|
||||
for (i = 0; values[i].strvalue; ++i)
|
||||
{
|
||||
if (cv->value == values[i].value)
|
||||
|
|
@ -220,7 +223,7 @@ static void M_ChangeCvar(INT32 choice)
|
|||
"Turning on Auto Roulette",
|
||||
"\"Ring Racers\" is not designed with random items in mind. With Auto Roulette, you cannot select the item results you want or select an item early."
|
||||
"\n"
|
||||
"You will be at a distinct \x85" "disadvantage. \x80\n"
|
||||
"You will be at a distinct \x85" "disadvantage. \x80\n"
|
||||
"\n"
|
||||
"ARE YOU SURE?",
|
||||
M_ChangeCvarResponse,
|
||||
|
|
|
|||
|
|
@ -319,12 +319,24 @@ void PR_SaveProfiles(void)
|
|||
std::vector<uint8_t> ubjson = json::to_ubjson(ng);
|
||||
|
||||
std::string realpath = fmt::format("{}/{}", srb2home, PROFILESFILE);
|
||||
int random_number = rand();
|
||||
std::string tmppath = fmt::format("{}_{}.tmp", realpath, random_number);
|
||||
std::string bakpath = fmt::format("{}.bak", realpath);
|
||||
|
||||
if (fs::exists(realpath))
|
||||
{
|
||||
try
|
||||
{
|
||||
fs::rename(realpath, bakpath);
|
||||
}
|
||||
catch (const fs::filesystem_error& ex)
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, "Failed to record profiles backup. Not attempting to save profiles. %s\n", ex.what());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
io::FileStream file {tmppath, io::FileStreamMode::kWrite};
|
||||
io::FileStream file {realpath, io::FileStreamMode::kWrite};
|
||||
|
||||
io::write(static_cast<uint32_t>(0x52494E47), file, io::Endian::kBE); // "RING"
|
||||
io::write(static_cast<uint32_t>(0x5052464C), file, io::Endian::kBE); // "PRFL"
|
||||
|
|
@ -334,16 +346,14 @@ void PR_SaveProfiles(void)
|
|||
io::write(static_cast<uint8_t>(0), file); // reserved4
|
||||
io::write_exact(file, tcb::as_bytes(tcb::make_span(ubjson)));
|
||||
file.close();
|
||||
|
||||
fs::rename(tmppath, realpath);
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
I_Error("Couldn't save profiles. Are you out of Disk space / playing in a protected folder?\n\nException: %s", ex.what());
|
||||
I_Error("Couldn't save profiles. Are you out of Disk space / playing in a protected folder? Check directory for a ringprofiles.prf.bak if the profiles file is corrupt.\n\nException: %s", ex.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
I_Error("Couldn't save profiles. Are you out of Disk space / playing in a protected folder?");
|
||||
I_Error("Couldn't save profiles. Are you out of Disk space / playing in a protected folder? Check directory for a ringprofiles.prf.bak if the profiles file is corrupt.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ INT16 K_PowerLevelPlacementScore(player_t *player)
|
|||
|
||||
INT16 K_CalculatePowerLevelAvg(void)
|
||||
{
|
||||
fixed_t avg = 0;
|
||||
INT32 avg = 0;
|
||||
UINT8 div = 0;
|
||||
SINT8 t = PWRLV_DISABLED;
|
||||
UINT8 i;
|
||||
|
|
@ -166,7 +166,7 @@ INT16 K_CalculatePowerLevelAvg(void)
|
|||
|| clientpowerlevels[i][t] == 0) // splitscreen player
|
||||
continue;
|
||||
|
||||
avg += (clientpowerlevels[i][t] << FRACBITS);
|
||||
avg += clientpowerlevels[i][t];
|
||||
div++;
|
||||
}
|
||||
|
||||
|
|
@ -178,7 +178,7 @@ INT16 K_CalculatePowerLevelAvg(void)
|
|||
|
||||
avg /= div;
|
||||
|
||||
return (INT16)(avg >> FRACBITS);
|
||||
return (INT16)avg;
|
||||
}
|
||||
|
||||
void K_UpdatePowerLevels(player_t *player, UINT8 lap, boolean forfeit)
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ void M_AddonsRefresh(void)
|
|||
else if (majormods && !prevmajormods)
|
||||
{
|
||||
S_StartSound(NULL, sfx_s221);
|
||||
message = va("%c%s\x80\nYou've loaded a gameplay-modifying addon.\n\nRecord Attack has been disabled, but you\ncan still play alone in local Multiplayer.\n\nIf you wish to play Record Attack mode, restart the game to disable loaded addons.\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname);
|
||||
message = va("%c%s\x80\nYou've loaded a gameplay-modifying addon.\nCheck the console log for more info.\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname);
|
||||
prevmajormods = majormods;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -59,11 +59,12 @@ void Obj_InstaWhipThink (mobj_t *whip)
|
|||
|
||||
void Obj_SpawnInstaWhipRecharge(player_t *player, angle_t angleOffset)
|
||||
{
|
||||
mobj_t *x = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_INSTAWHIP_RECHARGE);
|
||||
mobj_t *x = P_SpawnMobjFromMobj(player->mo, 0, 0, player->mo->height / 2, MT_INSTAWHIP_RECHARGE);
|
||||
|
||||
// This was previously used to delay the visual, back when this was VFX for a cooldown
|
||||
// instead of VFX for a charge. We want to instantly bail out of that state now.
|
||||
x->tics = 1;
|
||||
x->eflags &= ~MFE_VERTICALFLIP; // Fix the visual being misaligned.
|
||||
x->renderflags |= RF_SLOPESPLAT | RF_NOSPLATBILLBOARD;
|
||||
|
||||
P_SetTarget(&recharge_target(x), player->mo);
|
||||
|
|
@ -81,7 +82,8 @@ void Obj_InstaWhipRechargeThink(mobj_t *x)
|
|||
}
|
||||
|
||||
P_MoveOrigin(x, target->x, target->y, target->z + (target->height / 2));
|
||||
P_InstaScale(x, 2 * target->scale);
|
||||
if (x->scale != target->scale * 2)
|
||||
P_InstaScale(x, target->scale * 2);
|
||||
x->angle = target->angle + recharge_offset(x);
|
||||
|
||||
// Flickers every other frame
|
||||
|
|
@ -91,6 +93,10 @@ void Obj_InstaWhipRechargeThink(mobj_t *x)
|
|||
void Obj_SpawnInstaWhipReject(player_t *player)
|
||||
{
|
||||
mobj_t *x = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_INSTAWHIP_REJECT);
|
||||
x->eflags &= ~MFE_VERTICALFLIP;
|
||||
// Fixes an issue with gravflip misplacing the object for the first tic.
|
||||
if (player->mo->eflags & MFE_VERTICALFLIP)
|
||||
P_SetOrigin(x, player->mo->x, player->mo->y, player->mo->z);
|
||||
|
||||
P_SetTarget(&recharge_target(x), player->mo);
|
||||
}
|
||||
|
|
|
|||
10
src/p_user.c
10
src/p_user.c
|
|
@ -2220,7 +2220,7 @@ static INT16 P_FindClosestTurningForAngle(player_t *player, INT32 targetAngle, I
|
|||
|
||||
// Slightly frumpy binary search for the ideal turning input.
|
||||
// We do this instead of reversing K_GetKartTurnValue so that future handling changes are automatically accounted for.
|
||||
|
||||
|
||||
while (attempts++ < 20) // Practical calls of this function search maximum 10 times, this is solely for safety.
|
||||
{
|
||||
// These need to be treated as signed, or situations where boundaries straddle 0 are a mess.
|
||||
|
|
@ -2341,7 +2341,7 @@ static void P_UpdatePlayerAngle(player_t *player)
|
|||
// Corrections via fake turn go through easing.
|
||||
// That means undoing them takes the same amount of time as doing them.
|
||||
// This can lead to oscillating death spiral states on a multi-tic correction, as we swing past the target angle.
|
||||
// So before we go into death-spirals, if our predicton is _almost_ right...
|
||||
// So before we go into death-spirals, if our predicton is _almost_ right...
|
||||
angle_t leniency_base;
|
||||
if (G_CompatLevel(0x000A))
|
||||
{
|
||||
|
|
@ -2450,7 +2450,7 @@ void P_MovePlayer(player_t *player)
|
|||
//////////////////////
|
||||
|
||||
P_UpdatePlayerAngle(player);
|
||||
|
||||
|
||||
ticruned++;
|
||||
if (!(cmd->flags & TICCMD_RECEIVED))
|
||||
ticmiss++;
|
||||
|
|
@ -4255,7 +4255,7 @@ void P_PlayerThink(player_t *player)
|
|||
}
|
||||
else if (cmd->buttons & BT_ACCELERATE)
|
||||
{
|
||||
if (!player->exiting && !(player->oldcmd.buttons & BT_ACCELERATE))
|
||||
if (!player->exiting && !(player->oldcmd.buttons & BT_ACCELERATE) && ((cmd->buttons & BT_SPINDASHMASK) != BT_SPINDASHMASK) && player->trickpanel != TRICKSTATE_READY)
|
||||
{
|
||||
player->kickstartaccel = 0;
|
||||
}
|
||||
|
|
@ -4550,7 +4550,7 @@ void P_PlayerThink(player_t *player)
|
|||
{
|
||||
player->stairjank--;
|
||||
}
|
||||
|
||||
|
||||
// Random skin / "ironman"
|
||||
{
|
||||
UINT32 skinflags = (demo.playback)
|
||||
|
|
|
|||
|
|
@ -428,7 +428,7 @@ static void I_ReportSignal(int num, int coredumped)
|
|||
}
|
||||
|
||||
#ifndef NEWSIGNALHANDLER
|
||||
FUNCNORETURN static ATTRNORETURN void signal_handler(INT32 num)
|
||||
static ATTRNORETURN void signal_handler(INT32 num)
|
||||
{
|
||||
g_in_exiting_signal_handler = true;
|
||||
|
||||
|
|
@ -447,10 +447,8 @@ FUNCNORETURN static ATTRNORETURN void signal_handler(INT32 num)
|
|||
write_backtrace(num);
|
||||
#endif
|
||||
I_ReportSignal(num, 0);
|
||||
I_ShutdownSystem();
|
||||
signal(num, SIG_DFL); //default signal action
|
||||
raise(num);
|
||||
I_Quit();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -1738,11 +1736,7 @@ void I_Error(const char *error, ...)
|
|||
if (errorcount == 7)
|
||||
SDL_Quit();
|
||||
if (errorcount == 8)
|
||||
{
|
||||
M_SaveConfig(NULL);
|
||||
G_DirtyGameData(); // done first in case an error is in G_SaveGameData
|
||||
G_SaveGameData();
|
||||
}
|
||||
G_DirtyGameData();
|
||||
if (errorcount > 20)
|
||||
{
|
||||
va_start(argptr, error);
|
||||
|
|
@ -1776,9 +1770,10 @@ void I_Error(const char *error, ...)
|
|||
I_OutputMsg("\nI_Error(): %s\n", buffer);
|
||||
// ---
|
||||
|
||||
M_SaveConfig(NULL); // save game config, cvars..
|
||||
G_DirtyGameData(); // done first in case an error is in G_SaveGameData
|
||||
G_SaveGameData(); // Tails 12-08-2002
|
||||
// FUCK OFF, stop allocating memory to write entire gamedata & configs
|
||||
// when the program needs to shut down ASAP and we already save
|
||||
// these all the time! Just set the dirty bit and GET OUT!
|
||||
G_DirtyGameData();
|
||||
|
||||
// Shutdown. Here might be other errors.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue