Merge remote-tracking branch 'origin/master' into fof-things-suck

This commit is contained in:
James R 2020-04-24 20:36:30 -07:00
commit 4b2c13da0c
18 changed files with 249 additions and 168 deletions

View file

@ -18,6 +18,7 @@ set(SRB2_CORE_SOURCES
filesrch.c filesrch.c
g_game.c g_game.c
g_input.c g_input.c
g_splitscreen.c
hu_stuff.c hu_stuff.c
i_tcp.c i_tcp.c
info.c info.c
@ -156,7 +157,13 @@ set(SRB2_CORE_GAME_SOURCES
p_telept.c p_telept.c
p_tick.c p_tick.c
p_user.c p_user.c
k_battle.c
k_bheap.c
k_collide.c
k_kart.c k_kart.c
k_pathfind.c
k_pwrlv.c
k_waypoint.c
p_local.h p_local.h
p_maputl.h p_maputl.h
@ -168,7 +175,13 @@ set(SRB2_CORE_GAME_SOURCES
p_slopes.h p_slopes.h
p_spec.h p_spec.h
p_tick.h p_tick.h
k_battle.h
k_bheap.h
k_collide.h
k_kart.h k_kart.h
k_pathfind.h
k_pwrlv.h
k_waypoint.h
) )
if(NOT (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) if(NOT (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))

View file

@ -1543,7 +1543,7 @@ static void CV_SetCVar(consvar_t *var, const char *value, boolean stealth)
} }
// Only add to netcmd buffer if in a netgame, otherwise, just change it. // Only add to netcmd buffer if in a netgame, otherwise, just change it.
if (netgame || multiplayer) if (netgame)
{ {
WRITEUINT16(p, var->netid); WRITEUINT16(p, var->netid);
WRITESTRING(p, value); WRITESTRING(p, value);

View file

@ -1880,7 +1880,7 @@ void CL_UpdateServerList(boolean internetsearch, INT32 room)
{ {
char version[8] = ""; char version[8] = "";
#if VERSION > 0 || SUBVERSION > 0 #if VERSION > 0 || SUBVERSION > 0
snprintf(version, sizeof (version), "%d.%d.%d", VERSION/100, VERSION%100, SUBVERSION); snprintf(version, sizeof (version), "%d.%d", VERSION, SUBVERSION);
#else #else
strcpy(version, GetRevisionString()); strcpy(version, GetRevisionString());
#endif #endif
@ -2355,8 +2355,8 @@ static void CL_ConnectToServer(boolean viams)
gametypestr = Gametype_Names[num]; gametypestr = Gametype_Names[num];
if (gametypestr) if (gametypestr)
CONS_Printf(M_GetText("Gametype: %s\n"), gametypestr); CONS_Printf(M_GetText("Gametype: %s\n"), gametypestr);
CONS_Printf(M_GetText("Version: %d.%d.%u\n"), serverlist[i].info.version/100, CONS_Printf(M_GetText("Version: %d.%d\n"),
serverlist[i].info.version%100, serverlist[i].info.subversion); serverlist[i].info.version, serverlist[i].info.subversion);
} }
SL_ClearServerList(servernode); SL_ClearServerList(servernode);
#endif #endif
@ -3296,8 +3296,8 @@ static void Got_RemovePlayer(UINT8 **p, INT32 playernum);
// called one time at init // called one time at init
void D_ClientServerInit(void) void D_ClientServerInit(void)
{ {
DEBFILE(va("- - -== SRB2Kart v%d.%.2d.%d "VERSIONSTRING" debugfile ==- - -\n", DEBFILE(va("- - -== SRB2Kart v%d.%d "VERSIONSTRING" debugfile ==- - -\n",
VERSION/100, VERSION%100, SUBVERSION)); VERSION, SUBVERSION));
#ifndef NONET #ifndef NONET
COM_AddCommand("getplayernum", Command_GetPlayerNum); COM_AddCommand("getplayernum", Command_GetPlayerNum);
@ -3822,7 +3822,7 @@ static void HandleConnect(SINT8 node)
SV_SendRefuse(node, M_GetText("You have been banned\nfrom the server")); SV_SendRefuse(node, M_GetText("You have been banned\nfrom the server"));
else if (netbuffer->u.clientcfg.version != VERSION else if (netbuffer->u.clientcfg.version != VERSION
|| netbuffer->u.clientcfg.subversion != SUBVERSION) || netbuffer->u.clientcfg.subversion != SUBVERSION)
SV_SendRefuse(node, va(M_GetText("Different SRB2Kart versions cannot\nplay a netgame!\n(server version %d.%d.%d)"), VERSION/100, VERSION%100, SUBVERSION)); SV_SendRefuse(node, va(M_GetText("Different SRB2Kart versions cannot\nplay a netgame!\n(server version %d.%d)"), VERSION, SUBVERSION));
else if (!cv_allownewplayer.value && node) else if (!cv_allownewplayer.value && node)
SV_SendRefuse(node, M_GetText("The server is not accepting\njoins for the moment")); SV_SendRefuse(node, M_GetText("The server is not accepting\njoins for the moment"));
else if (D_NumPlayers() >= maxplayers) else if (D_NumPlayers() >= maxplayers)

View file

@ -1083,7 +1083,10 @@ void D_SRB2Main(void)
// use user specific config file // use user specific config file
#ifdef DEFAULTDIR #ifdef DEFAULTDIR
snprintf(srb2home, sizeof srb2home, "%s" PATHSEP DEFAULTDIR, userhome); snprintf(srb2home, sizeof srb2home, "%s" PATHSEP DEFAULTDIR, userhome);
snprintf(downloaddir, sizeof downloaddir, "%s" PATHSEP "DOWNLOAD", srb2home); #else
snprintf(srb2home, sizeof srb2home, "%s", userhome);
#endif
if (dedicated) if (dedicated)
snprintf(configfile, sizeof configfile, "%s" PATHSEP "d"CONFIGFILENAME, srb2home); snprintf(configfile, sizeof configfile, "%s" PATHSEP "d"CONFIGFILENAME, srb2home);
else else
@ -1091,18 +1094,6 @@ void D_SRB2Main(void)
// can't use sprintf since there is %u in savegamename // can't use sprintf since there is %u in savegamename
strcatbf(savegamename, srb2home, PATHSEP); strcatbf(savegamename, srb2home, PATHSEP);
#else
snprintf(srb2home, sizeof srb2home, "%s", userhome);
snprintf(downloaddir, sizeof downloaddir, "%s", userhome);
if (dedicated)
snprintf(configfile, sizeof configfile, "%s" PATHSEP "d"CONFIGFILENAME, userhome);
else
snprintf(configfile, sizeof configfile, "%s" PATHSEP CONFIGFILENAME, userhome);
// can't use sprintf since there is %u in savegamename
strcatbf(savegamename, userhome, PATHSEP);
#endif
} }
configfile[sizeof configfile - 1] = '\0'; configfile[sizeof configfile - 1] = '\0';
@ -1116,6 +1107,10 @@ void D_SRB2Main(void)
snprintf(addonsdir, sizeof addonsdir, "%s%s%s", srb2home, PATHSEP, "addons"); snprintf(addonsdir, sizeof addonsdir, "%s%s%s", srb2home, PATHSEP, "addons");
I_mkdir(addonsdir, 0755); I_mkdir(addonsdir, 0755);
/* and downloads in a subdirectory */
snprintf(downloaddir, sizeof downloaddir, "%s%s%s",
addonsdir, PATHSEP, "downloads");
// rand() needs seeded regardless of password // rand() needs seeded regardless of password
srand((unsigned int)time(NULL)); srand((unsigned int)time(NULL));

View file

@ -150,7 +150,7 @@ extern char logfilename[1024];
// most interface strings are ignored in development mode. // most interface strings are ignored in development mode.
// we use comprevision and compbranch instead. // we use comprevision and compbranch instead.
#else #else
#define VERSION 200 // Game version #define VERSION 2 // Game version
#define SUBVERSION 0 // more precise version number #define SUBVERSION 0 // more precise version number
#define VERSIONSTRING "v2.0" #define VERSIONSTRING "v2.0"
#define VERSIONSTRINGW L"v2.0" #define VERSIONSTRINGW L"v2.0"

View file

@ -796,6 +796,7 @@ static void K_KartGetItemResult(player_t *player, SINT8 getitem)
{ {
if (getitem == KITEM_SPB || getitem == KITEM_SHRINK) // Indirect items if (getitem == KITEM_SPB || getitem == KITEM_SHRINK) // Indirect items
indirectitemcooldown = 20*TICRATE; indirectitemcooldown = 20*TICRATE;
if (getitem == KITEM_HYUDORO) // Hyudoro cooldown if (getitem == KITEM_HYUDORO) // Hyudoro cooldown
hyubgone = 5*TICRATE; hyubgone = 5*TICRATE;
@ -1167,7 +1168,17 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd)
&& players[i].kartstuff[k_position] == 1) && players[i].kartstuff[k_position] == 1)
{ {
// This player is first! Yay! // This player is first! Yay!
pdis = player->distancetofinish - players[i].distancetofinish;
if (player->distancetofinish <= players[i].distancetofinish)
{
// Guess you're in first / tied for first?
pdis = 0;
}
else
{
// Subtract 1st's distance from your distance, to get your distance from 1st!
pdis = player->distancetofinish - players[i].distancetofinish;
}
break; break;
} }
} }
@ -1281,7 +1292,7 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd)
player->kartstuff[k_itemroulette] = 0; player->kartstuff[k_itemroulette] = 0;
player->kartstuff[k_roulettetype] = 0; player->kartstuff[k_roulettetype] = 0;
if (P_IsDisplayPlayer(player)) if (P_IsDisplayPlayer(player))
S_StartSound(NULL, (mashed ? sfx_itrolm : sfx_itrolf)); S_StartSound(NULL, sfx_itrolm);
return; return;
} }
} }
@ -1434,7 +1445,7 @@ static void K_DebtStingPlayer(player_t *player, INT32 length)
if (player->mo->state != &states[S_KART_SPIN]) if (player->mo->state != &states[S_KART_SPIN])
P_SetPlayerMobjState(player->mo, S_KART_SPIN); P_SetPlayerMobjState(player->mo, S_KART_SPIN);
K_DropHnextList(player); K_DropHnextList(player, false);
return; return;
} }
@ -2875,7 +2886,7 @@ void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, mobj_t *inflicto
if (cv_kartdebughuddrop.value && !modeattacking) if (cv_kartdebughuddrop.value && !modeattacking)
K_DropItems(player); K_DropItems(player);
else else
K_DropHnextList(player); K_DropHnextList(player, false);
return; return;
} }
@ -3020,7 +3031,7 @@ void K_SquishPlayer(player_t *player, mobj_t *source, mobj_t *inflictor)
if (cv_kartdebughuddrop.value && !modeattacking) if (cv_kartdebughuddrop.value && !modeattacking)
K_DropItems(player); K_DropItems(player);
else else
K_DropHnextList(player); K_DropHnextList(player, false);
return; return;
} }
@ -3226,7 +3237,7 @@ void K_StealBumper(player_t *player, player_t *victim, boolean force)
if (cv_kartdebughuddrop.value && !modeattacking) if (cv_kartdebughuddrop.value && !modeattacking)
K_DropItems(victim); K_DropItems(victim);
else else
K_DropHnextList(victim); K_DropHnextList(victim, false);
return; return;
} }
@ -4689,54 +4700,58 @@ void K_UpdateHnextList(player_t *player, boolean clean)
nextwork = work->hnext; nextwork = work->hnext;
while ((work = nextwork) && !P_MobjWasRemoved(work)) while ((work = nextwork) && !(work == NULL || P_MobjWasRemoved(work)))
{ {
nextwork = work->hnext; nextwork = work->hnext;
if (!clean && (!work->movedir || work->movedir <= (UINT16)player->kartstuff[k_itemamount])) if (!clean && (!work->movedir || work->movedir <= (UINT16)player->kartstuff[k_itemamount]))
{
continue; continue;
}
P_RemoveMobj(work); P_RemoveMobj(work);
} }
if (player->mo->hnext == NULL || P_MobjWasRemoved(player->mo->hnext))
{
// Like below, try to clean up the pointer if it's NULL.
// Maybe this was a cause of the shrink/eggbox fails?
P_SetTarget(&player->mo->hnext, NULL);
}
} }
// For getting hit! // For getting hit!
void K_DropHnextList(player_t *player) void K_DropHnextList(player_t *player, boolean keepshields)
{ {
mobj_t *work = player->mo, *nextwork, *dropwork; mobj_t *work = player->mo, *nextwork, *dropwork;
INT32 flip; INT32 flip;
mobjtype_t type; mobjtype_t type;
boolean orbit, ponground, dropall = true; boolean orbit, ponground, dropall = true;
INT32 shield = K_GetShieldFromItem(player->kartstuff[k_itemtype]);
if (!work || P_MobjWasRemoved(work)) if (work == NULL || P_MobjWasRemoved(work))
{
return; return;
}
flip = P_MobjFlip(player->mo); flip = P_MobjFlip(player->mo);
ponground = P_IsObjectOnGround(player->mo); ponground = P_IsObjectOnGround(player->mo);
if (player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD) if (shield != KSHIELD_NONE && !keepshields)
{ {
K_DoThunderShield(player); if (shield == KSHIELD_THUNDER)
player->kartstuff[k_itemtype] = KITEM_NONE; {
player->kartstuff[k_itemamount] = 0; K_DoThunderShield(player);
}
player->kartstuff[k_curshield] = KSHIELD_NONE; player->kartstuff[k_curshield] = KSHIELD_NONE;
}
else if (player->kartstuff[k_itemtype] == KITEM_BUBBLESHIELD)
{
player->kartstuff[k_itemtype] = KITEM_NONE; player->kartstuff[k_itemtype] = KITEM_NONE;
player->kartstuff[k_itemamount] = 0; player->kartstuff[k_itemamount] = player->kartstuff[k_itemheld] = 0;
player->kartstuff[k_curshield] = KSHIELD_NONE;
}
else if (player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD)
{
player->kartstuff[k_itemtype] = KITEM_NONE;
player->kartstuff[k_itemamount] = 0;
player->kartstuff[k_curshield] = KSHIELD_NONE;
} }
nextwork = work->hnext; nextwork = work->hnext;
while ((work = nextwork) && !P_MobjWasRemoved(work)) while ((work = nextwork) && !(work == NULL || P_MobjWasRemoved(work)))
{ {
nextwork = work->hnext; nextwork = work->hnext;
@ -4765,20 +4780,20 @@ void K_DropHnextList(player_t *player)
orbit = false; orbit = false;
type = MT_EGGMANITEM; type = MT_EGGMANITEM;
break; break;
// intentionally do nothing
case MT_SINK_SHIELD:
case MT_ROCKETSNEAKER:
return;
default: default:
continue; continue;
} }
dropwork = P_SpawnMobj(work->x, work->y, work->z, type); dropwork = P_SpawnMobj(work->x, work->y, work->z, type);
P_SetTarget(&dropwork->target, player->mo); P_SetTarget(&dropwork->target, player->mo);
P_AddKartItem(dropwork); // needs to be called here so shrink can bust items off players in front of the user. P_AddKartItem(dropwork); // needs to be called here so shrink can bust items off players in front of the user.
dropwork->angle = work->angle; dropwork->angle = work->angle;
dropwork->flags2 = work->flags2;
dropwork->flags |= MF_NOCLIPTHING; dropwork->flags |= MF_NOCLIPTHING;
dropwork->flags2 = work->flags2;
dropwork->floorz = work->floorz; dropwork->floorz = work->floorz;
dropwork->ceilingz = work->ceilingz; dropwork->ceilingz = work->ceilingz;
@ -4807,19 +4822,29 @@ void K_DropHnextList(player_t *player)
if (orbit) // splay out if (orbit) // splay out
{ {
dropwork->flags2 |= MF2_AMBUSH; dropwork->flags2 |= MF2_AMBUSH;
dropwork->z += flip; dropwork->z += flip;
dropwork->momx = player->mo->momx>>1; dropwork->momx = player->mo->momx>>1;
dropwork->momy = player->mo->momy>>1; dropwork->momy = player->mo->momy>>1;
dropwork->momz = 3*flip*mapobjectscale; dropwork->momz = 3*flip*mapobjectscale;
if (dropwork->eflags & MFE_UNDERWATER) if (dropwork->eflags & MFE_UNDERWATER)
dropwork->momz = (117 * dropwork->momz) / 200; dropwork->momz = (117 * dropwork->momz) / 200;
P_Thrust(dropwork, work->angle - ANGLE_90, 6*mapobjectscale); P_Thrust(dropwork, work->angle - ANGLE_90, 6*mapobjectscale);
dropwork->movecount = 2; dropwork->movecount = 2;
dropwork->movedir = work->angle - ANGLE_90; dropwork->movedir = work->angle - ANGLE_90;
P_SetMobjState(dropwork, dropwork->info->deathstate); P_SetMobjState(dropwork, dropwork->info->deathstate);
dropwork->tics = -1; dropwork->tics = -1;
if (type == MT_JAWZ_DUD) if (type == MT_JAWZ_DUD)
{
dropwork->z += 20*flip*dropwork->scale; dropwork->z += 20*flip*dropwork->scale;
}
else else
{ {
dropwork->color = work->color; dropwork->color = work->color;
@ -4835,39 +4860,33 @@ void K_DropHnextList(player_t *player)
P_RemoveMobj(work); P_RemoveMobj(work);
} }
// we need this here too because this is done in afterthink - pointers are cleaned up at the START of each tic...
P_SetTarget(&player->mo->hnext, NULL);
player->kartstuff[k_bananadrag] = 0;
if (player->kartstuff[k_eggmanheld])
{ {
// we need this here too because this is done in afterthink - pointers are cleaned up at the START of each tic... player->kartstuff[k_eggmanheld] = 0;
P_SetTarget(&player->mo->hnext, NULL); }
player->kartstuff[k_bananadrag] = 0; else if (player->kartstuff[k_itemheld]
if (player->kartstuff[k_eggmanheld]) && (dropall || (--player->kartstuff[k_itemamount] <= 0)))
player->kartstuff[k_eggmanheld] = 0; {
else if (player->kartstuff[k_itemheld] player->kartstuff[k_itemamount] = player->kartstuff[k_itemheld] = 0;
&& (dropall || (--player->kartstuff[k_itemamount] <= 0))) player->kartstuff[k_itemtype] = KITEM_NONE;
{
player->kartstuff[k_itemamount] = player->kartstuff[k_itemheld] = 0;
player->kartstuff[k_itemtype] = KITEM_NONE;
}
} }
} }
// For getting EXTRA hit! // For getting EXTRA hit!
void K_DropItems(player_t *player) void K_DropItems(player_t *player)
{ {
INT32 shieldhack = 0; K_DropHnextList(player, true);
if (player->kartstuff[k_curshield]) if (player->mo && !P_MobjWasRemoved(player->mo) && player->kartstuff[k_itemamount] > 0)
shieldhack = K_GetShieldFromItem(player->kartstuff[k_itemtype]);
if (shieldhack)
player->kartstuff[k_itemtype] = KITEM_NONE;
K_DropHnextList(player);
if (player->mo && !P_MobjWasRemoved(player->mo) && player->kartstuff[k_itemamount])
{ {
mobj_t *drop = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z + player->mo->height/2, MT_FLOATINGITEM); mobj_t *drop = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z + player->mo->height/2, MT_FLOATINGITEM);
P_SetScale(drop, drop->scale>>4); P_SetScale(drop, drop->scale>>4);
drop->destscale = (3*drop->destscale)/2;; drop->destscale = (3*drop->destscale)/2;
drop->angle = player->mo->angle + ANGLE_90; drop->angle = player->mo->angle + ANGLE_90;
P_Thrust(drop, P_Thrust(drop,
@ -4877,13 +4896,7 @@ void K_DropItems(player_t *player)
if (drop->eflags & MFE_UNDERWATER) if (drop->eflags & MFE_UNDERWATER)
drop->momz = (117 * drop->momz) / 200; drop->momz = (117 * drop->momz) / 200;
switch (shieldhack) drop->threshold = player->kartstuff[k_itemtype];
{
case KSHIELD_THUNDER: drop->threshold = KITEM_THUNDERSHIELD; break;
case KSHIELD_BUBBLE: drop->threshold = KITEM_BUBBLESHIELD; break;
case KSHIELD_FLAME: drop->threshold = KITEM_FLAMESHIELD; break;
default: drop->threshold = player->kartstuff[k_itemtype]; break;
}
drop->movecount = player->kartstuff[k_itemamount]; drop->movecount = player->kartstuff[k_itemamount];
drop->flags |= MF_NOCLIPTHING; drop->flags |= MF_NOCLIPTHING;
@ -6276,10 +6289,6 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
void K_KartPlayerAfterThink(player_t *player) void K_KartPlayerAfterThink(player_t *player)
{ {
// Moved to afterthink, as at this point the players have had their distances to the finish line updated
// and this will correctly account for all players
K_KartUpdatePosition(player);
if (player->kartstuff[k_curshield] if (player->kartstuff[k_curshield]
|| player->kartstuff[k_invincibilitytimer] || player->kartstuff[k_invincibilitytimer]
|| (player->kartstuff[k_growshrinktimer] != 0 && player->kartstuff[k_growshrinktimer] % 5 == 4)) // 4 instead of 0 because this is afterthink! || (player->kartstuff[k_growshrinktimer] != 0 && player->kartstuff[k_growshrinktimer] % 5 == 4)) // 4 instead of 0 because this is afterthink!
@ -6596,7 +6605,7 @@ static boolean K_PlayerCloserToNextWaypoints(waypoint_t *const waypoint, player_
} }
/*-------------------------------------------------- /*--------------------------------------------------
static void K_UpdateDistanceFromFinishLine(player_t *const player) void K_UpdateDistanceFromFinishLine(player_t *const player)
Updates the distance a player has to the finish line. Updates the distance a player has to the finish line.
@ -6606,7 +6615,7 @@ static boolean K_PlayerCloserToNextWaypoints(waypoint_t *const waypoint, player_
Return:- Return:-
None None
--------------------------------------------------*/ --------------------------------------------------*/
static void K_UpdateDistanceFromFinishLine(player_t *const player) void K_UpdateDistanceFromFinishLine(player_t *const player)
{ {
if ((player != NULL) && (player->mo != NULL)) if ((player != NULL) && (player->mo != NULL))
{ {
@ -7156,7 +7165,6 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
boolean HOLDING_ITEM = (player->kartstuff[k_itemheld] || player->kartstuff[k_eggmanheld]); boolean HOLDING_ITEM = (player->kartstuff[k_itemheld] || player->kartstuff[k_eggmanheld]);
boolean NO_HYUDORO = (player->kartstuff[k_stolentimer] == 0 && player->kartstuff[k_stealingtimer] == 0); boolean NO_HYUDORO = (player->kartstuff[k_stolentimer] == 0 && player->kartstuff[k_stealingtimer] == 0);
K_UpdateDistanceFromFinishLine(player);
player->pflags &= ~PF_HITFINISHLINE; player->pflags &= ~PF_HITFINISHLINE;
if (!player->exiting) if (!player->exiting)

View file

@ -56,9 +56,10 @@ void K_DoSneaker(player_t *player, INT32 type);
void K_DoPogoSpring(mobj_t *mo, fixed_t vertispeed, UINT8 sound); void K_DoPogoSpring(mobj_t *mo, fixed_t vertispeed, UINT8 sound);
void K_KillBananaChain(mobj_t *banana, mobj_t *inflictor, mobj_t *source); void K_KillBananaChain(mobj_t *banana, mobj_t *inflictor, mobj_t *source);
void K_UpdateHnextList(player_t *player, boolean clean); void K_UpdateHnextList(player_t *player, boolean clean);
void K_DropHnextList(player_t *player); void K_DropHnextList(player_t *player, boolean keepshields);
void K_RepairOrbitChain(mobj_t *orbit); void K_RepairOrbitChain(mobj_t *orbit);
player_t *K_FindJawzTarget(mobj_t *actor, player_t *source); player_t *K_FindJawzTarget(mobj_t *actor, player_t *source);
void K_UpdateDistanceFromFinishLine(player_t *const player);
boolean K_CheckPlayersRespawnColliding(INT32 playernum, fixed_t x, fixed_t y); boolean K_CheckPlayersRespawnColliding(INT32 playernum, fixed_t x, fixed_t y);
INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue); INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue);
INT32 K_GetKartDriftSparkValue(player_t *player); INT32 K_GetKartDriftSparkValue(player_t *player);

View file

@ -2101,14 +2101,14 @@ static void Nextmap_OnChange(void)
if (currentMenu == &SP_TimeAttackDef) if (currentMenu == &SP_TimeAttackDef)
{ {
// see also p_setup.c's P_LoadRecordGhosts // see also p_setup.c's P_LoadRecordGhosts
const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1; const size_t glen = strlen(srb2home)+1+strlen("media")+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1;
char *gpath = malloc(glen); char *gpath = malloc(glen);
INT32 i; INT32 i;
if (!gpath) if (!gpath)
return; return;
sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)); sprintf(gpath,"%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value));
CV_StealthSetValue(&cv_dummystaff, 0); CV_StealthSetValue(&cv_dummystaff, 0);
@ -5142,7 +5142,7 @@ void M_ReplayHut(INT32 choice)
if (!demo.inreplayhut) if (!demo.inreplayhut)
{ {
snprintf(menupath, 1024, "%s"PATHSEP"replay"PATHSEP"online"PATHSEP, srb2home); snprintf(menupath, 1024, "%s"PATHSEP"media"PATHSEP"replay"PATHSEP"online"PATHSEP, srb2home);
menupathindex[(menudepthleft = menudepth-1)] = strlen(menupath); menupathindex[(menudepthleft = menudepth-1)] = strlen(menupath);
} }
if (!preparefilemenu(false, true)) if (!preparefilemenu(false, true))
@ -7876,20 +7876,21 @@ static boolean M_QuitTimeAttackMenu(void)
static void M_ChooseTimeAttack(INT32 choice) static void M_ChooseTimeAttack(INT32 choice)
{ {
char *gpath; char *gpath;
const size_t glen = strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1; const size_t glen = strlen("media")+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1;
char nameofdemo[256]; char nameofdemo[256];
(void)choice; (void)choice;
emeralds = 0; emeralds = 0;
M_ClearMenus(true); M_ClearMenus(true);
modeattacking = (levellistmode == LLM_BREAKTHECAPSULES ? ATTACKING_CAPSULES : ATTACKING_RECORD); modeattacking = (levellistmode == LLM_BREAKTHECAPSULES ? ATTACKING_CAPSULES : ATTACKING_RECORD);
I_mkdir(va("%s"PATHSEP"replay", srb2home), 0755); gpath = va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s",
I_mkdir(va("%s"PATHSEP"replay"PATHSEP"%s", srb2home, timeattackfolder), 0755); srb2home, timeattackfolder);
M_MkdirEach(gpath, M_PathParts(gpath) - 3, 0755);
if ((gpath = malloc(glen)) == NULL) if ((gpath = malloc(glen)) == NULL)
I_Error("Out of memory for replay filepath\n"); I_Error("Out of memory for replay filepath\n");
sprintf(gpath,"replay"PATHSEP"%s"PATHSEP"%s", timeattackfolder, G_BuildMapName(cv_nextmap.value)); sprintf(gpath,"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", timeattackfolder, G_BuildMapName(cv_nextmap.value));
snprintf(nameofdemo, sizeof nameofdemo, "%s-%s-last", gpath, cv_chooseskin.string); snprintf(nameofdemo, sizeof nameofdemo, "%s-%s-last", gpath, cv_chooseskin.string);
if (!cv_autorecord.value) if (!cv_autorecord.value)

View file

@ -1121,8 +1121,8 @@ void M_StartMovie(void)
if (cv_movie_option.value != 3) if (cv_movie_option.value != 3)
{ {
strcat(pathname, PATHSEP"movies"PATHSEP); strcat(pathname, PATHSEP"media"PATHSEP"movies"PATHSEP);
I_mkdir(pathname, 0755); M_MkdirEach(pathname, M_PathParts(pathname) - 2, 0755);
} }
if (rendermode == render_none) if (rendermode == render_none)
@ -1483,8 +1483,8 @@ void M_DoScreenShot(void)
if (cv_screenshot_option.value != 3) if (cv_screenshot_option.value != 3)
{ {
strcat(pathname, PATHSEP"screenshots"PATHSEP); strcat(pathname, PATHSEP"media"PATHSEP"screenshots"PATHSEP);
I_mkdir(pathname, 0755); M_MkdirEach(pathname, M_PathParts(pathname) - 2, 0755);
} }
#ifdef USE_PNG #ifdef USE_PNG

View file

@ -751,7 +751,7 @@ static INT32 AddToMasterServer(boolean firstadd)
strcpy(info->name, cv_servername.string); strcpy(info->name, cv_servername.string);
M_Memcpy(&info->room, & room, sizeof (INT32)); M_Memcpy(&info->room, & room, sizeof (INT32));
#if VERSION > 0 || SUBVERSION > 0 #if VERSION > 0 || SUBVERSION > 0
sprintf(info->version, "%d.%d.%d", VERSION/100, VERSION%100, SUBVERSION); sprintf(info->version, "%d.%d", VERSION, SUBVERSION);
#else // Trunk build, send revision info #else // Trunk build, send revision info
strcpy(info->version, GetRevisionString()); strcpy(info->version, GetRevisionString());
#endif #endif
@ -789,7 +789,7 @@ static INT32 RemoveFromMasterSever(void)
strcpy(info->ip, ""); strcpy(info->ip, "");
strcpy(info->port, int2str(current_port)); strcpy(info->port, int2str(current_port));
strcpy(info->name, registered_server.name); strcpy(info->name, registered_server.name);
sprintf(info->version, "%d.%d.%d", VERSION/100, VERSION%100, SUBVERSION); sprintf(info->version, "%d.%d", VERSION, SUBVERSION);
msg.type = REMOVE_SERVER_MSG; msg.type = REMOVE_SERVER_MSG;
msg.length = (UINT32)sizeof (msg_server_t); msg.length = (UINT32)sizeof (msg_server_t);

View file

@ -542,7 +542,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
if (player->kartstuff[k_bubbleblowup] > 0) if (player->kartstuff[k_bubbleblowup] > 0)
{ {
K_DropHnextList(player); K_DropHnextList(player, false);
special->extravalue1 = 2; // WAIT... special->extravalue1 = 2; // WAIT...
special->extravalue2 = 52; // Slightly over the respawn timer length special->extravalue2 = 52; // Slightly over the respawn timer length
return; return;

View file

@ -6153,7 +6153,7 @@ boolean P_IsKartItem(INT32 type)
type == MT_JAWZ || type == MT_JAWZ_DUD || type == MT_JAWZ_SHIELD || type == MT_JAWZ || type == MT_JAWZ_DUD || type == MT_JAWZ_SHIELD ||
type == MT_SSMINE || type == MT_SSMINE_SHIELD || type == MT_SSMINE || type == MT_SSMINE_SHIELD ||
type == MT_SINK || type == MT_SINK_SHIELD || type == MT_SINK || type == MT_SINK_SHIELD ||
type == MT_SPB) type == MT_SPB || type == MT_BALLHOG || type == MT_BUBBLESHIELDTRAP)
return true; return true;
else else
return false; return false;
@ -7175,6 +7175,41 @@ void P_MobjThinker(mobj_t *mobj)
return; return;
} }
#endif #endif
// Destroy items sector special
if (mobj->type == MT_BANANA || mobj->type == MT_EGGMANITEM
|| mobj->type == MT_ORBINAUT || mobj->type == MT_BALLHOG
|| mobj->type == MT_JAWZ || mobj->type == MT_JAWZ_DUD
|| mobj->type == MT_SSMINE || mobj->type == MT_BUBBLESHIELDTRAP)
{
if (mobj->health > 0 && P_MobjTouchingSectorSpecial(mobj, 4, 7, true))
{
if (mobj->type == MT_SSMINE
|| mobj->type == MT_BUBBLESHIELDTRAP
|| mobj->type == MT_BALLHOG)
{
S_StartSound(mobj, mobj->info->deathsound);
P_KillMobj(mobj, NULL, NULL);
}
else
{
// This Item Damage
if (mobj->eflags & MFE_VERTICALFLIP)
mobj->z -= mobj->height;
else
mobj->z += mobj->height;
S_StartSound(mobj, mobj->info->deathsound);
P_KillMobj(mobj, NULL, NULL);
P_SetObjectMomZ(mobj, 8*FRACUNIT, false);
P_InstaThrust(mobj, R_PointToAngle2(0, 0, mobj->momx, mobj->momy) + ANGLE_90, 16*FRACUNIT);
}
return;
}
}
// if it's pushable, or if it would be pushable other than temporary disablement, use the // if it's pushable, or if it would be pushable other than temporary disablement, use the
// separate thinker // separate thinker
if (mobj->flags & MF_PUSHABLE || (mobj->info->flags & MF_PUSHABLE && mobj->fuse)) if (mobj->flags & MF_PUSHABLE || (mobj->info->flags & MF_PUSHABLE && mobj->fuse))
@ -7939,12 +7974,6 @@ void P_MobjThinker(mobj_t *mobj)
{ {
boolean grounded = P_IsObjectOnGround(mobj); boolean grounded = P_IsObjectOnGround(mobj);
if (P_MobjTouchingSectorSpecial(mobj, 4, 7, true))
{
P_RemoveMobj(mobj);
return;
}
if (mobj->flags2 & MF2_AMBUSH) if (mobj->flags2 & MF2_AMBUSH)
{ {
if (grounded && (mobj->flags & MF_NOCLIPTHING)) if (grounded && (mobj->flags & MF_NOCLIPTHING))
@ -8015,12 +8044,6 @@ void P_MobjThinker(mobj_t *mobj)
{ {
mobj_t *ghost = P_SpawnGhostMobj(mobj); mobj_t *ghost = P_SpawnGhostMobj(mobj);
if (P_MobjTouchingSectorSpecial(mobj, 4, 7, true))
{
P_RemoveMobj(mobj);
return;
}
if (mobj->target && !P_MobjWasRemoved(mobj->target) && mobj->target->player) if (mobj->target && !P_MobjWasRemoved(mobj->target) && mobj->target->player)
{ {
ghost->color = mobj->target->player->skincolor; ghost->color = mobj->target->player->skincolor;
@ -8045,12 +8068,6 @@ void P_MobjThinker(mobj_t *mobj)
{ {
boolean grounded = P_IsObjectOnGround(mobj); boolean grounded = P_IsObjectOnGround(mobj);
if (P_MobjTouchingSectorSpecial(mobj, 4, 7, true))
{
P_RemoveMobj(mobj);
return;
}
if (mobj->flags2 & MF2_AMBUSH) if (mobj->flags2 & MF2_AMBUSH)
{ {
if (grounded && (mobj->flags & MF_NOCLIPTHING)) if (grounded && (mobj->flags & MF_NOCLIPTHING))
@ -8124,12 +8141,6 @@ void P_MobjThinker(mobj_t *mobj)
case MT_BANANA: case MT_BANANA:
mobj->friction = ORIG_FRICTION/4; mobj->friction = ORIG_FRICTION/4;
if (P_MobjTouchingSectorSpecial(mobj, 4, 7, true))
{
P_RemoveMobj(mobj);
return;
}
if (mobj->momx || mobj->momy) if (mobj->momx || mobj->momy)
{ {
mobj_t *ghost = P_SpawnGhostMobj(mobj); mobj_t *ghost = P_SpawnGhostMobj(mobj);
@ -8159,12 +8170,6 @@ void P_MobjThinker(mobj_t *mobj)
mobj_t *ghost = P_SpawnGhostMobj(mobj); mobj_t *ghost = P_SpawnGhostMobj(mobj);
ghost->fuse = 3; ghost->fuse = 3;
if (P_MobjTouchingSectorSpecial(mobj, 4, 7, true))
{
P_RemoveMobj(mobj);
return;
}
if (mobj->target && !P_MobjWasRemoved(mobj->target) && mobj->target->player) if (mobj->target && !P_MobjWasRemoved(mobj->target) && mobj->target->player)
{ {
ghost->color = mobj->target->player->skincolor; ghost->color = mobj->target->player->skincolor;
@ -8197,12 +8202,6 @@ void P_MobjThinker(mobj_t *mobj)
mobj->threshold--; mobj->threshold--;
break; break;
case MT_SSMINE: case MT_SSMINE:
if (P_MobjTouchingSectorSpecial(mobj, 4, 7, true))
{
P_RemoveMobj(mobj);
return;
}
if (mobj->target && mobj->target->player) if (mobj->target && mobj->target->player)
mobj->color = mobj->target->player->skincolor; mobj->color = mobj->target->player->skincolor;
else else

View file

@ -2621,14 +2621,14 @@ static void P_ForceCharacter(const char *forcecharskin)
static void P_LoadRecordGhosts(void) static void P_LoadRecordGhosts(void)
{ {
// see also m_menu.c's Nextmap_OnChange // see also m_menu.c's Nextmap_OnChange
const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1; const size_t glen = strlen(srb2home)+1+strlen("media")+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1;
char *gpath = malloc(glen); char *gpath = malloc(glen);
INT32 i; INT32 i;
if (!gpath) if (!gpath)
return; return;
sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap)); sprintf(gpath,"%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap));
// Best Time ghost // Best Time ghost
if (cv_ghost_besttime.value) if (cv_ghost_besttime.value)
@ -3205,10 +3205,12 @@ boolean P_SetupLevel(boolean skipprecip)
//@TODO I'd like to fix dedis crashing when recording replays for the future too... //@TODO I'd like to fix dedis crashing when recording replays for the future too...
if (!demo.playback && multiplayer && !dedicated) { if (!demo.playback && multiplayer && !dedicated) {
static char buf[256]; static char buf[256];
sprintf(buf, "replay"PATHSEP"online"PATHSEP"%d-%s", (int) (time(NULL)), G_BuildMapName(gamemap)); char *path;
sprintf(buf, "media"PATHSEP"replay"PATHSEP"online"PATHSEP"%d-%s", (int) (time(NULL)), G_BuildMapName(gamemap));
path = va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"online", srb2home);
M_MkdirEach(path, M_PathParts(path) - 4, 0755);
I_mkdir(va("%s"PATHSEP"replay", srb2home), 0755);
I_mkdir(va("%s"PATHSEP"replay"PATHSEP"online", srb2home), 0755);
G_RecordDemo(buf); G_RecordDemo(buf);
} }

View file

@ -7289,9 +7289,15 @@ static void P_SpawnScrollers(void)
{ {
fixed_t dx = l->dx >> SCROLL_SHIFT; // direction and speed of scrolling fixed_t dx = l->dx >> SCROLL_SHIFT; // direction and speed of scrolling
fixed_t dy = l->dy >> SCROLL_SHIFT; fixed_t dy = l->dy >> SCROLL_SHIFT;
fixed_t bx = 0;/* backside variants */
fixed_t by = 0;
INT32 control = -1, accel = 0; // no control sector or acceleration INT32 control = -1, accel = 0; // no control sector or acceleration
INT32 special = l->special; INT32 special = l->special;
INT32 s;
// These types are same as the ones they get set to except that the // These types are same as the ones they get set to except that the
// first side's sector's heights cause scrolling when they change, and // first side's sector's heights cause scrolling when they change, and
// this linedef controls the direction and speed of the scrolling. The // this linedef controls the direction and speed of the scrolling. The
@ -7320,10 +7326,24 @@ static void P_SpawnScrollers(void)
control = (INT32)(sides[*l->sidenum].sector - sectors); control = (INT32)(sides[*l->sidenum].sector - sectors);
} }
if (special == 507) // front and back scrollers
{
s = l->sidenum[0];
dx = -(sides[s].textureoffset);
dy = sides[s].rowoffset;
s = l->sidenum[1];
if (s != 0xffff)
{
bx = -(sides[s].textureoffset);
by = sides[s].rowoffset;
}
}
switch (special) switch (special)
{ {
register INT32 s;
case 513: // scroll effect ceiling case 513: // scroll effect ceiling
case 533: // scroll and carry objects on ceiling case 533: // scroll and carry objects on ceiling
for (s = -1; (s = P_FindSectorFromLineTag(l, s)) >= 0 ;) for (s = -1; (s = P_FindSectorFromLineTag(l, s)) >= 0 ;)
@ -7376,6 +7396,18 @@ static void P_SpawnScrollers(void)
CONS_Debug(DBG_GAMELOGIC, "Line special 506 (line #%s) missing 2nd side!\n", sizeu1(i)); CONS_Debug(DBG_GAMELOGIC, "Line special 506 (line #%s) missing 2nd side!\n", sizeu1(i));
break; break;
case 507: // scroll front and backside of tagged lines
for (s = -1; (s = P_FindLineFromLineTag(l, s)) >= 0 ;)
{
if (s != (INT32)i)
{
Add_Scroller(sc_side, dx, dy, control, lines[s].sidenum[0], accel, 0);
if (lines[s].sidenum[1] != 0xffff)
Add_Scroller(sc_side, bx, by, control, lines[s].sidenum[1], accel, 0);
}
}
break;
case 500: // scroll first side case 500: // scroll first side
Add_Scroller(sc_side, FRACUNIT, 0, -1, lines[i].sidenum[0], accel, 0); Add_Scroller(sc_side, FRACUNIT, 0, -1, lines[i].sidenum[0], accel, 0);
break; break;

View file

@ -616,6 +616,17 @@ void P_Ticker(boolean run)
G_ReadDemoTiccmd(&players[i].cmd, i); G_ReadDemoTiccmd(&players[i].cmd, i);
} }
// First loop: Ensure all players' distance to the finish line are all accurate
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo))
K_UpdateDistanceFromFinishLine(&players[i]);
// Second loop: Ensure all player positions reflect everyone's distances
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo))
K_KartUpdatePosition(&players[i]);
// OK! Now that we got all of that sorted, players can think!
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo)) if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo))
P_PlayerThink(&players[i]); P_PlayerThink(&players[i]);
@ -778,6 +789,17 @@ void P_PreTicker(INT32 frames)
{ {
P_MapStart(); P_MapStart();
// First loop: Ensure all players' distance to the finish line are all accurate
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo))
K_UpdateDistanceFromFinishLine(&players[i]);
// Second loop: Ensure all player positions reflect everyone's distances
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo))
K_KartUpdatePosition(&players[i]);
// OK! Now that we got all of that sorted, players can think!
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo)) if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo))
{ {

View file

@ -7157,13 +7157,14 @@ void P_ResetCamera(player_t *player, camera_t *thiscam)
boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcalled) boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcalled)
{ {
static UINT8 lookbackdelay[4] = {0,0,0,0}; static boolean lookbackactive[MAXSPLITSCREENPLAYERS];
static UINT8 lookbackdelay[MAXSPLITSCREENPLAYERS];
UINT8 num; UINT8 num;
angle_t angle = 0, focusangle = 0, focusaiming = 0, pitch = 0; angle_t angle = 0, focusangle = 0, focusaiming = 0, pitch = 0;
fixed_t x, y, z, dist, distxy, distz, height, viewpointx, viewpointy, camspeed, camdist, camheight, pviewheight; fixed_t x, y, z, dist, distxy, distz, viewpointx, viewpointy, camspeed, camdist, camheight, pviewheight;
fixed_t pan, xpan, ypan; fixed_t pan, xpan, ypan;
INT32 camrotate; INT32 camrotate;
boolean camstill, lookback; boolean camstill, lookback, lookbackdown;
UINT8 timeover; UINT8 timeover;
mobj_t *mo; mobj_t *mo;
fixed_t f1, f2; fixed_t f1, f2;
@ -7343,15 +7344,19 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
camstill = true; camstill = true;
else if (lookback || lookbackdelay[num]) // SRB2kart - Camera flipper else if (lookback || lookbackdelay[num]) // SRB2kart - Camera flipper
{ {
#define MAXLOOKBACKDELAY 2
camspeed = FRACUNIT; camspeed = FRACUNIT;
if (lookback) if (lookback)
{ {
camrotate += 180; camrotate += 180;
lookbackdelay[num] = 2; lookbackdelay[num] = MAXLOOKBACKDELAY;
} }
else else
lookbackdelay[num]--; lookbackdelay[num]--;
} }
lookbackdown = (lookbackdelay[num] == MAXLOOKBACKDELAY) != lookbackactive[num];
lookbackactive[num] = (lookbackdelay[num] == MAXLOOKBACKDELAY);
#undef MAXLOOKBACKDELAY
if (mo->eflags & MFE_VERTICALFLIP) if (mo->eflags & MFE_VERTICALFLIP)
camheight += thiscam->height; camheight += thiscam->height;
@ -7394,8 +7399,6 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
thiscam->angle = angle; thiscam->angle = angle;
} }
height = camheight;
// sets ideal cam pos // sets ideal cam pos
dist = camdist; dist = camdist;
@ -7404,14 +7407,11 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
dist += abs(thiscam->momz)/4; dist += abs(thiscam->momz)/4;
if (player->karthud[khud_boostcam]) if (player->karthud[khud_boostcam])
{
dist -= FixedMul(11*dist/16, player->karthud[khud_boostcam]); dist -= FixedMul(11*dist/16, player->karthud[khud_boostcam]);
height -= FixedMul(height, player->karthud[khud_boostcam]);
}
if (mo->standingslope) if (mo->standingslope)
{ {
pitch = (angle_t)FixedMul(P_ReturnThrustX(mo, player->frameangle - mo->standingslope->xydirection, FRACUNIT), (fixed_t)mo->standingslope->zangle); pitch = (angle_t)FixedMul(P_ReturnThrustX(mo, thiscam->angle - mo->standingslope->xydirection, FRACUNIT), (fixed_t)mo->standingslope->zangle);
if (mo->eflags & MFE_VERTICALFLIP) if (mo->eflags & MFE_VERTICALFLIP)
{ {
if (pitch >= ANGLE_180) if (pitch >= ANGLE_180)
@ -7434,8 +7434,6 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
else else
distxy = dist; distxy = dist;
distz = -FixedMul(dist, FINESINE((pitch>>ANGLETOFINESHIFT) & FINEMASK)); distz = -FixedMul(dist, FINESINE((pitch>>ANGLETOFINESHIFT) & FINEMASK));
if (r_splitscreen == 1) // 2 player is weird, this helps keep players on screen
distz = 3*distz/5;
x = mo->x - FixedMul(FINECOSINE((angle>>ANGLETOFINESHIFT) & FINEMASK), distxy); x = mo->x - FixedMul(FINECOSINE((angle>>ANGLETOFINESHIFT) & FINEMASK), distxy);
y = mo->y - FixedMul(FINESINE((angle>>ANGLETOFINESHIFT) & FINEMASK), distxy); y = mo->y - FixedMul(FINESINE((angle>>ANGLETOFINESHIFT) & FINEMASK), distxy);
@ -7476,9 +7474,15 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
pviewheight = FixedMul(32<<FRACBITS, mo->scale); pviewheight = FixedMul(32<<FRACBITS, mo->scale);
if (mo->eflags & MFE_VERTICALFLIP) if (mo->eflags & MFE_VERTICALFLIP)
z = mo->z + mo->height - pviewheight - camheight + distz; {
distz = min(-camheight, distz);
z = mo->z + mo->height - pviewheight + distz;
}
else else
z = mo->z + pviewheight + camheight + distz; {
distz = max(camheight, distz);
z = mo->z + pviewheight + distz;
}
#ifndef NOCLIPCAM // Disable all z-clipping for noclip cam #ifndef NOCLIPCAM // Disable all z-clipping for noclip cam
// move camera down to move under lower ceilings // move camera down to move under lower ceilings
@ -7724,13 +7728,13 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
{ {
angle = R_PointToAngle2(0, thiscam->z + thiscam->height, dist, mo->z + mo->height - P_GetPlayerHeight(player)); angle = R_PointToAngle2(0, thiscam->z + thiscam->height, dist, mo->z + mo->height - P_GetPlayerHeight(player));
if (thiscam->pitch < ANGLE_180 && thiscam->pitch > angle) if (thiscam->pitch < ANGLE_180 && thiscam->pitch > angle)
angle = thiscam->pitch; angle += (thiscam->pitch - angle)/2;
} }
else else
{ {
angle = R_PointToAngle2(0, thiscam->z, dist, mo->z + P_GetPlayerHeight(player)); angle = R_PointToAngle2(0, thiscam->z, dist, mo->z + P_GetPlayerHeight(player));
if (thiscam->pitch >= ANGLE_180 && thiscam->pitch < angle) if (thiscam->pitch >= ANGLE_180 && thiscam->pitch < angle)
angle = thiscam->pitch; angle -= (angle - thiscam->pitch)/2;
} }
if (player->playerstate != PST_DEAD && !((player->pflags & PF_NIGHTSMODE) && player->exiting)) if (player->playerstate != PST_DEAD && !((player->pflags & PF_NIGHTSMODE) && player->exiting))
@ -7773,6 +7777,9 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
thiscam->aiming = ANGLE_22h; thiscam->aiming = ANGLE_22h;
} }
if (lookbackdown)
P_MoveChaseCamera(player, thiscam, false);
return (x == thiscam->x && y == thiscam->y && z == thiscam->z && angle == thiscam->aiming); return (x == thiscam->x && y == thiscam->y && z == thiscam->z && angle == thiscam->aiming);
} }

View file

@ -841,7 +841,7 @@ static void R_SetupFreelook(void)
// clip it in the case we are looking a hardware 90 degrees full aiming // clip it in the case we are looking a hardware 90 degrees full aiming
// (lmps, network and use F12...) // (lmps, network and use F12...)
G_SoftwareClipAimingPitch((INT32 *)&aimingangle); G_SoftwareClipAimingPitch((INT32 *)&aimingangle);
dy = AIMINGTODY(aimingangle) * viewheight/BASEVIDHEIGHT; dy = AIMINGTODY(aimingangle) * viewwidth/BASEVIDWIDTH;
yslope = &yslopetab[viewheight*8 - (viewheight/2 + dy)]; yslope = &yslopetab[viewheight*8 - (viewheight/2 + dy)];
} }
centery = (viewheight/2) + dy; centery = (viewheight/2) + dy;

View file

@ -787,7 +787,7 @@ void Y_Ticker(void)
// //
static void Y_UpdateRecordReplays(void) static void Y_UpdateRecordReplays(void)
{ {
const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1; const size_t glen = strlen(srb2home)+1+strlen("media")+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1;
char *gpath; char *gpath;
char lastdemo[256], bestdemo[256]; char lastdemo[256], bestdemo[256];
UINT8 earnedEmblems; UINT8 earnedEmblems;
@ -823,13 +823,14 @@ static void Y_UpdateRecordReplays(void)
G_SetDemoTime(players[consoleplayer].realtime, bestlap); G_SetDemoTime(players[consoleplayer].realtime, bestlap);
G_CheckDemoStatus(); G_CheckDemoStatus();
I_mkdir(va("%s"PATHSEP"replay", srb2home), 0755); gpath = va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s",
I_mkdir(va("%s"PATHSEP"replay"PATHSEP"%s", srb2home, timeattackfolder), 0755); srb2home, timeattackfolder);
M_MkdirEach(gpath, M_PathParts(gpath) - 3, 0755);
if ((gpath = malloc(glen)) == NULL) if ((gpath = malloc(glen)) == NULL)
I_Error("Out of memory for replay filepath\n"); I_Error("Out of memory for replay filepath\n");
sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap)); sprintf(gpath,"%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap));
snprintf(lastdemo, 255, "%s-%s-last.lmp", gpath, cv_chooseskin.string); snprintf(lastdemo, 255, "%s-%s-last.lmp", gpath, cv_chooseskin.string);
if (FIL_FileExists(lastdemo)) if (FIL_FileExists(lastdemo))