mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Merge branch 'sealed-acs-splitscreen' into 'master'
Sealed ACS Splitscreen (resolves #1209) Closes #1209 See merge request KartKrew/Kart!2190
This commit is contained in:
commit
8089cbd3a7
14 changed files with 200 additions and 29 deletions
|
|
@ -39,6 +39,7 @@
|
|||
#include "../r_textures.h"
|
||||
#include "../m_cond.h"
|
||||
#include "../r_skins.h"
|
||||
#include "../k_kart.h"
|
||||
#include "../k_battle.h"
|
||||
#include "../k_grandprix.h"
|
||||
#include "../k_podium.h"
|
||||
|
|
@ -1646,6 +1647,54 @@ bool CallFunc_PlayerBot(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::W
|
|||
return false;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
bool CallFunc_PlayerLosing(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
|
||||
|
||||
Returns the activating player's losing status.
|
||||
--------------------------------------------------*/
|
||||
bool CallFunc_PlayerLosing(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
|
||||
{
|
||||
auto info = &static_cast<Thread *>(thread)->info;
|
||||
|
||||
(void)argV;
|
||||
(void)argC;
|
||||
|
||||
if ((info != NULL)
|
||||
&& (info->mo != NULL && P_MobjWasRemoved(info->mo) == false)
|
||||
&& (info->mo->player != NULL))
|
||||
{
|
||||
thread->dataStk.push(K_IsPlayerLosing(info->mo->player));
|
||||
return false;
|
||||
}
|
||||
|
||||
thread->dataStk.push(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
bool CallFunc_PlayerExiting(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
|
||||
|
||||
Returns the activating player's exiting status.
|
||||
--------------------------------------------------*/
|
||||
bool CallFunc_PlayerExiting(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
|
||||
{
|
||||
auto info = &static_cast<Thread *>(thread)->info;
|
||||
|
||||
(void)argV;
|
||||
(void)argC;
|
||||
|
||||
if ((info != NULL)
|
||||
&& (info->mo != NULL && P_MobjWasRemoved(info->mo) == false)
|
||||
&& (info->mo->player != NULL))
|
||||
{
|
||||
thread->dataStk.push((info->mo->player->exiting != 0));
|
||||
return false;
|
||||
}
|
||||
|
||||
thread->dataStk.push(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
bool CallFunc_GetObjectDye(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
|
||||
|
||||
|
|
|
|||
|
|
@ -76,6 +76,8 @@ bool CallFunc_HaveUnlockableTrigger(ACSVM::Thread *thread, const ACSVM::Word *ar
|
|||
bool CallFunc_HaveUnlockable(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
bool CallFunc_PlayerSkin(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
bool CallFunc_PlayerBot(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
bool CallFunc_PlayerLosing(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
bool CallFunc_PlayerExiting(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
bool CallFunc_GetObjectDye(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
bool CallFunc_PlayerEmeralds(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
bool CallFunc_PlayerLap(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
|
|
|
|||
|
|
@ -172,6 +172,8 @@ Environment::Environment()
|
|||
addFuncDataACS0( 316, addCallFunc(CallFunc_PositionStart));
|
||||
addFuncDataACS0( 317, addCallFunc(CallFunc_FreePlay));
|
||||
addFuncDataACS0( 318, addCallFunc(CallFunc_CheckTutorialChallenge));
|
||||
addFuncDataACS0( 319, addCallFunc(CallFunc_PlayerLosing));
|
||||
addFuncDataACS0( 320, addCallFunc(CallFunc_PlayerExiting));
|
||||
|
||||
addFuncDataACS0( 500, addCallFunc(CallFunc_CameraWait));
|
||||
addFuncDataACS0( 501, addCallFunc(CallFunc_PodiumPosition));
|
||||
|
|
|
|||
|
|
@ -244,6 +244,29 @@ void ACS_RunPlayerEnterScript(player_t *player)
|
|||
map->scriptStartTypeForced(ACS_ST_ENTER, scriptInfo);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void ACS_RunPlayerFinishScript(player_t *player)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
void ACS_RunPlayerFinishScript(player_t *player)
|
||||
{
|
||||
Environment *env = &ACSEnv;
|
||||
|
||||
ACSVM::GlobalScope *const global = env->getGlobalScope(0);
|
||||
ACSVM::HubScope *const hub = global->getHubScope(0);
|
||||
ACSVM::MapScope *const map = hub->getMapScope(0);
|
||||
|
||||
ACSVM::MapScope::ScriptStartInfo scriptInfo;
|
||||
ThreadInfo info;
|
||||
|
||||
P_SetTarget(&info.mo, player->mo);
|
||||
|
||||
scriptInfo.info = &info;
|
||||
|
||||
map->scriptStartTypeForced(ACS_ST_FINISH, scriptInfo);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void ACS_RunLapScript(mobj_t *mo, line_t *line)
|
||||
|
||||
|
|
|
|||
|
|
@ -139,6 +139,22 @@ void ACS_RunPlayerDeathScript(player_t *player);
|
|||
void ACS_RunPlayerEnterScript(player_t *player);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
void ACS_RunPlayerFinishScript(player_t *player);
|
||||
|
||||
Runs the map's special script for a player
|
||||
finishing (P_DoPlayerExit).
|
||||
|
||||
Input Arguments:-
|
||||
player: The player to run the script for.
|
||||
|
||||
Return:-
|
||||
None
|
||||
--------------------------------------------------*/
|
||||
|
||||
void ACS_RunPlayerFinishScript(player_t *player);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
void ACS_RunLapScript(mobj_t *mo, line_t *line);
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ enum acs_scriptType_e
|
|||
ACS_ST_UFO = 8, // UFO: Runs when the UFO Catcher is destroyed in a Special Stage.
|
||||
ACS_ST_EMERALD = 9, // EMERALD: Runs when the Chaos Emerald is collected in a Special Stage.
|
||||
ACS_ST_GAMEOVER = 10, // GAMEOVER: Runs when the level ends due to a losing condition and no player has an extra life.
|
||||
ACS_ST_FINISH = 11, // FINISH: Runs when a player finishes
|
||||
};
|
||||
|
||||
//
|
||||
|
|
|
|||
13
src/g_game.c
13
src/g_game.c
|
|
@ -2520,9 +2520,9 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
}
|
||||
}
|
||||
|
||||
if (p->spectator == false)
|
||||
if (p->spectator == false && !betweenmaps)
|
||||
{
|
||||
if (betweenmaps || enteredGame == true)
|
||||
if (enteredGame == true)
|
||||
{
|
||||
ACS_RunPlayerEnterScript(p);
|
||||
}
|
||||
|
|
@ -2531,15 +2531,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
ACS_RunPlayerRespawnScript(p);
|
||||
}
|
||||
}
|
||||
|
||||
if (betweenmaps)
|
||||
return;
|
||||
|
||||
if (leveltime < starttime)
|
||||
return;
|
||||
|
||||
if (exiting)
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
|||
28
src/k_kart.c
28
src/k_kart.c
|
|
@ -2749,13 +2749,6 @@ void K_PlayOvertakeSound(mobj_t *source)
|
|||
|
||||
boolean tasteful = (!source->player || !source->player->karthud[khud_voices]);
|
||||
|
||||
if (!(gametyperules & GTR_CIRCUIT)) // Only in race
|
||||
return;
|
||||
|
||||
// 4 seconds from before race begins, 10 seconds afterwards
|
||||
if (leveltime < starttime+(10*TICRATE))
|
||||
return;
|
||||
|
||||
if (
|
||||
cv_kartvoices.value
|
||||
&& (tasteful || cv_kartvoices.value == 2)
|
||||
|
|
@ -11100,7 +11093,7 @@ void K_KartUpdatePosition(player_t *player)
|
|||
|
||||
if (position != oldposition) // Changed places?
|
||||
{
|
||||
if (player->positiondelay <= 0 && position < oldposition && P_IsDisplayPlayer(player) == true)
|
||||
if (!K_Cooperative() && player->positiondelay <= 0 && position < oldposition && P_IsDisplayPlayer(player) == true)
|
||||
{
|
||||
// Play sound when getting closer to 1st.
|
||||
UINT32 soundpos = (max(0, position - 1) * MAXPLAYERS)/realplayers; // always 1-15 despite there being 16 players at max...
|
||||
|
|
@ -11143,12 +11136,6 @@ void K_KartUpdatePosition(player_t *player)
|
|||
player->topinfirst = 0;
|
||||
}
|
||||
|
||||
// Special stages: fade out music near the finish line
|
||||
if (P_IsPartyPlayer(player))
|
||||
{
|
||||
K_FadeOutSpecialMusic(player->distancetofinish);
|
||||
}
|
||||
|
||||
player->position = position;
|
||||
}
|
||||
|
||||
|
|
@ -12106,14 +12093,23 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
boolean HOLDING_ITEM = (player->itemflags & (IF_ITEMOUT|IF_EGGMANOUT));
|
||||
boolean NO_HYUDORO = (player->stealingtimer == 0);
|
||||
|
||||
if (!player->exiting)
|
||||
// Play overtake sounds, but only if
|
||||
// - your place changed
|
||||
// - not exiting
|
||||
// - in relevant gametype
|
||||
// - more than 10 seconds after initial scramble
|
||||
if (player->oldposition != player->position
|
||||
&& !player->exiting
|
||||
&& (gametyperules & GTR_CIRCUIT)
|
||||
&& !K_Cooperative()
|
||||
&& leveltime >= starttime+(10*TICRATE))
|
||||
{
|
||||
if (player->oldposition < player->position) // But first, if you lost a place,
|
||||
{
|
||||
player->oldposition = player->position; // then the other player taunts.
|
||||
K_RegularVoiceTimers(player); // and you can't for a bit
|
||||
}
|
||||
else if (player->oldposition > player->position) // Otherwise,
|
||||
else // Otherwise,
|
||||
{
|
||||
K_PlayOvertakeSound(player->mo); // Say "YOU'RE TOO SLOW!"
|
||||
player->oldposition = player->position; // Restore the old position,
|
||||
|
|
|
|||
|
|
@ -120,6 +120,19 @@ void K_TickSpecialStage(void)
|
|||
return;
|
||||
}
|
||||
|
||||
// Special stages: fade out music near the finish line
|
||||
UINT8 i;
|
||||
UINT32 lowestdistance = UINT32_MAX;
|
||||
for (i = 0; i <= r_splitscreen; i++)
|
||||
{
|
||||
if (!playeringame[displayplayers[i]] || players[displayplayers[i]].spectator)
|
||||
continue;
|
||||
if (players[displayplayers[i]].distancetofinish >= lowestdistance)
|
||||
continue;
|
||||
lowestdistance = players[displayplayers[i]].distancetofinish;
|
||||
}
|
||||
K_FadeOutSpecialMusic(lowestdistance);
|
||||
|
||||
if (P_MobjWasRemoved(specialstageinfo.ufo))
|
||||
{
|
||||
P_SetTarget(&specialstageinfo.ufo, NULL);
|
||||
|
|
@ -148,6 +161,53 @@ mobj_t *K_GetPossibleSpecialTarget(void)
|
|||
return specialstageinfo.ufo;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_PlayerIsEmptyHandedInSpecial(void)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
boolean K_PlayerIsEmptyHandedInSpecial(player_t *player)
|
||||
{
|
||||
if (specialstageinfo.valid == false)
|
||||
return false; // Not Sealed Star
|
||||
|
||||
if (!(specialstageinfo.ufo == NULL || P_MobjWasRemoved(specialstageinfo.ufo)))
|
||||
return true; // UFO exists
|
||||
|
||||
thinker_t *think;
|
||||
mobj_t *thing;
|
||||
player_t *orbitplayer = NULL;
|
||||
for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
|
||||
{
|
||||
if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
||||
continue;
|
||||
|
||||
thing = (mobj_t *)think;
|
||||
if (thing->type != MT_EMERALD)
|
||||
continue;
|
||||
|
||||
// emerald_award(thing)
|
||||
if (!thing->tracer || P_MobjWasRemoved(thing->tracer))
|
||||
continue;
|
||||
if (thing->tracer->type != MT_PLAYER || !thing->tracer->player)
|
||||
continue;
|
||||
|
||||
orbitplayer = thing->tracer->player;
|
||||
|
||||
if (orbitplayer->exiting && !(orbitplayer->pflags & PF_NOCONTEST))
|
||||
{
|
||||
// Another player has successfully taken the emerald to the end
|
||||
return false;
|
||||
}
|
||||
|
||||
// The emerald is being carried, but not by you
|
||||
return (orbitplayer != player);
|
||||
}
|
||||
|
||||
// EMERALD DELETED!?
|
||||
return true;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_FadeOutSpecialMusic(UINT32 distance)
|
||||
|
||||
|
|
|
|||
|
|
@ -68,6 +68,21 @@ void K_TickSpecialStage(void);
|
|||
|
||||
mobj_t *K_GetPossibleSpecialTarget(void);
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_PlayerIsEmptyHandedInSpecial(player_t *player)
|
||||
|
||||
Gets whether the player has failed a Sealed
|
||||
Star via finishing without an Emerald
|
||||
|
||||
Input Arguments:-
|
||||
player - Player to check for
|
||||
|
||||
Return:-
|
||||
Should player fail or not
|
||||
--------------------------------------------------*/
|
||||
|
||||
boolean K_PlayerIsEmptyHandedInSpecial(player_t *player);
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_FadeOutSpecialMusic(UINT32 distance)
|
||||
|
||||
|
|
|
|||
|
|
@ -149,6 +149,9 @@ static void Obj_EmeraldOrbitPlayer(mobj_t *emerald)
|
|||
if (!(bestplayer->pflags & PF_NOCONTEST))
|
||||
{
|
||||
P_MoveOrigin(emerald, bestplayer->mo->x, bestplayer->mo->y, bestplayer->mo->z);
|
||||
P_SetTarget(&emerald->tracer, NULL); // Ensures that tracer is correctly reset, allowing ACS to detect empty-handdeness.
|
||||
// "Why not just check target, which has to be set for any part of the behavior to work at all?"
|
||||
// Because Hyudoro is an emerald. I will not explain further. Program for a different game.
|
||||
Obj_BeginEmeraldOrbit(emerald, bestplayer->mo, 100 * mapobjectscale, 64, 0);
|
||||
return;
|
||||
}
|
||||
|
|
@ -316,7 +319,7 @@ void Obj_BeginEmeraldOrbit(mobj_t *emerald, mobj_t *target, fixed_t radius, INT3
|
|||
P_SetTarget(&emerald_orbit(emerald), target);
|
||||
P_SetTarget(&emerald->punt_ref, target);
|
||||
|
||||
if (P_MobjWasRemoved(emerald_award(emerald)))
|
||||
if (!emerald_award(emerald) || P_MobjWasRemoved(emerald_award(emerald)))
|
||||
{
|
||||
P_SetTarget(&emerald_award(emerald), target);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8892,6 +8892,16 @@ void P_PostLoadLevel(void)
|
|||
ACS_RunLevelStartScripts();
|
||||
LUA_HookInt(gamemap, HOOK(MapLoad));
|
||||
|
||||
UINT8 i;
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i])
|
||||
continue;
|
||||
if (players[i].spectator)
|
||||
continue;
|
||||
ACS_RunPlayerEnterScript(&players[i]);
|
||||
}
|
||||
|
||||
P_MapEnd();
|
||||
|
||||
// We're now done loading the level.
|
||||
|
|
|
|||
|
|
@ -1997,7 +1997,7 @@ static void K_HandleLapIncrement(player_t *player)
|
|||
if (specialstageinfo.valid == true)
|
||||
{
|
||||
// Don't permit a win just by sneaking ahead of the UFO/emerald.
|
||||
if (!(specialstageinfo.ufo == NULL || P_MobjWasRemoved(specialstageinfo.ufo)))
|
||||
if (K_PlayerIsEmptyHandedInSpecial(player))
|
||||
{
|
||||
applyflags |= PF_NOCONTEST;
|
||||
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@
|
|||
#include "k_credits.h"
|
||||
#include "k_hud.h" // K_AddMessage
|
||||
#include "m_easing.h"
|
||||
#include "acs/interface.h"
|
||||
|
||||
#ifdef HWRENDER
|
||||
#include "hardware/hw_light.h"
|
||||
|
|
@ -1342,6 +1343,8 @@ void P_DoPlayerExit(player_t *player, pflags_t flags)
|
|||
demo.savebutton = leveltime;
|
||||
}
|
||||
}
|
||||
|
||||
ACS_RunPlayerFinishScript(player);
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue