Merge branch 'spraycans-2' into 'master'

Tutorial Spray Cans

Closes #669

See merge request KartKrew/Kart!1498
This commit is contained in:
toaster 2023-09-17 13:17:41 +00:00
commit 9ba5a93407
7 changed files with 160 additions and 12 deletions

View file

@ -40,6 +40,7 @@
#include "../m_cond.h"
#include "../r_skins.h"
#include "../k_battle.h"
#include "../k_grandprix.h"
#include "../k_podium.h"
#include "../k_bot.h"
#include "../z_zone.h"
@ -680,6 +681,12 @@ bool CallFunc_DialogueWaitDismiss(ACSVM::Thread *thread, const ACSVM::Word *argV
(void)argV;
(void)argC;
// TODO when we move away from g_dialogue
if (netgame)
{
return false;
}
g_dialogue.SetDismissable(true);
thread->state = {
@ -702,6 +709,12 @@ bool CallFunc_DialogueWaitText(ACSVM::Thread *thread, const ACSVM::Word *argV, A
(void)argV;
(void)argC;
// TODO when we move away from g_dialogue
if (netgame)
{
return false;
}
g_dialogue.SetDismissable(false);
thread->state = {
@ -1699,6 +1712,57 @@ bool CallFunc_TimeAttack(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::
return false;
}
/*--------------------------------------------------
bool CallFunc_GrandPrix(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
Returns if a Grand Prix is active.
--------------------------------------------------*/
bool CallFunc_GrandPrix(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
{
(void)argV;
(void)argC;
thread->dataStk.push(grandprixinfo.gp);
return false;
}
/*--------------------------------------------------
bool CallFunc_GetGrabbedSprayCan(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
Returns the level's associated Spray Can, if grabbed.
--------------------------------------------------*/
bool CallFunc_GetGrabbedSprayCan(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
{
Environment *env = &ACSEnv;
(void)argV;
(void)argC;
if (netgame == false // cans are per-player and completely unsyncable
&& gamemap-1 < basenummapheaders)
{
// See also P_SprayCanInit
UINT16 can_id = mapheaderinfo[gamemap-1]->cache_spraycan;
if (can_id < gamedata->numspraycans)
{
UINT16 col = gamedata->spraycans[can_id].col;
thread->dataStk.push(~env->getString( skincolors[col].name )->idx);
return false;
}
if (gamedata->gotspraycans >= gamedata->numspraycans)
{
thread->dataStk.push(~env->getString( "_Completed" )->idx);
return false;
}
}
thread->dataStk.push(0);
return false;
}
/*--------------------------------------------------
bool CallFunc_PodiumPosition(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
@ -1925,6 +1989,12 @@ bool CallFunc_DialogueSetSpeaker(ACSVM::Thread *thread, const ACSVM::Word *argV,
(void)argC;
// TODO when we move away from g_dialogue
if (netgame)
{
return false;
}
map = thread->scopeMap;
skinStr = map->getString(argV[0]);
@ -1963,6 +2033,12 @@ bool CallFunc_DialogueSetCustomSpeaker(ACSVM::Thread *thread, const ACSVM::Word
(void)argC;
// TODO when we move away from g_dialogue
if (netgame)
{
return false;
}
map = thread->scopeMap;
nametagStr = map->getString(argV[0]);
@ -2044,6 +2120,12 @@ bool CallFunc_DialogueNewText(ACSVM::Thread *thread, const ACSVM::Word *argV, AC
(void)argC;
// TODO when we move away from g_dialogue
if (netgame)
{
return false;
}
map = thread->scopeMap;
textStr = map->getString(argV[0]);

View file

@ -81,6 +81,8 @@ bool CallFunc_LowestLap(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::W
bool CallFunc_EncoreMode(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_BreakTheCapsules(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_TimeAttack(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_GrandPrix(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_GetGrabbedSprayCan(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_PodiumPosition(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_PodiumFinish(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);

View file

@ -165,6 +165,8 @@ Environment::Environment()
addFuncDataACS0( 310, addCallFunc(CallFunc_BreakTheCapsules));
addFuncDataACS0( 311, addCallFunc(CallFunc_TimeAttack));
addFuncDataACS0( 312, addCallFunc(CallFunc_ThingCount));
addFuncDataACS0( 313, addCallFunc(CallFunc_GrandPrix));
addFuncDataACS0( 314, addCallFunc(CallFunc_GetGrabbedSprayCan));
addFuncDataACS0( 500, addCallFunc(CallFunc_CameraWait));
addFuncDataACS0( 501, addCallFunc(CallFunc_PodiumPosition));
@ -299,6 +301,12 @@ bool Environment::checkTag(ACSVM::Word type, ACSVM::Word tag)
case ACS_TAGTYPE_DIALOGUE:
{
// TODO when we move away from g_dialogue
if (netgame)
{
return true;
}
if (tag == 0) // cheeky reuse
{
// wait for dismissal

View file

@ -157,9 +157,20 @@ void Dialogue::WriteText(void)
while (textTimer <= 0 && !textDest.empty())
{
char c = textDest.back();
char c = textDest.back(), nextc = '\n';
text.push_back(c);
textDest.pop_back();
if (c & 0x80)
{
// Color code support
continue;
}
if (!textDest.empty())
nextc = textDest.back();
if (voicePlayed == false
&& std::isprint(c)
&& c != ' ')
@ -174,7 +185,8 @@ void Dialogue::WriteText(void)
voicePlayed = true;
}
if (c == '.' || c == ',' || c == ';' || c == '!' || c == '?')
if (std::ispunct(c)
&& std::isspace(nextc))
{
// slow down for punctuation
textTimer += kTextPunctPause;
@ -183,8 +195,6 @@ void Dialogue::WriteText(void)
{
textTimer += FRACUNIT;
}
textDest.pop_back();
}
textDone = (textTimer <= 0 && textDest.empty());

View file

@ -692,6 +692,25 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
{
// Unassigned, get the next grabbable colour
can_id = gamedata->gotspraycans;
// Multiple cans in one map?
if (special->threshold != 0)
{
UINT16 ref_id = can_id + (special->threshold & UINT8_MAX);
if (ref_id >= gamedata->numspraycans)
return;
// Swap this specific can to the head of the list.
UINT16 swapcol = gamedata->spraycans[ref_id].col;
gamedata->spraycans[ref_id].col =
gamedata->spraycans[can_id].col;
skincolors[gamedata->spraycans[ref_id].col].cache_spraycan = ref_id;
gamedata->spraycans[can_id].col = swapcol;
skincolors[swapcol].cache_spraycan = can_id;
}
}
if (can_id >= gamedata->numspraycans)
@ -712,8 +731,30 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
gamedata->deferredsave = true;
}
// Don't delete the object, just fade it.
P_SprayCanInit(special);
{
mobj_t *canmo = NULL;
mobj_t *next = NULL;
for (canmo = trackercap; canmo; canmo = next)
{
next = canmo->itnext;
if (canmo->type != MT_SPRAYCAN)
continue;
// Don't delete the object(s), just fade it.
if (netgame || canmo == special)
{
P_SprayCanInit(canmo);
continue;
}
// Get ready to get rid of these
canmo->renderflags |= (tr_trans50 << RF_TRANSSHIFT);
canmo->destscale = 0;
}
}
return;
}

View file

@ -12463,8 +12463,14 @@ void P_SprayCanInit(mobj_t* mobj)
// Prevent footguns - these won't persist when custom levels are unloaded
else if (gamemap-1 < basenummapheaders)
{
// Unassigned, get the next grabbable colour
// Unassigned, get the next grabbable colour (offset by threshold)
can_id = gamedata->gotspraycans;
// It's ok if this goes over gamedata->numspraycans, as they're
// capped below in this func... but NEVER let this go backwards!!
if (mobj->threshold != 0)
can_id += (mobj->threshold & UINT8_MAX);
mobj->renderflags = 0;
}
@ -12940,17 +12946,15 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj)
}
case MT_SPRAYCAN:
{
if (nummapspraycans)
if (nummapspraycans == UINT8_MAX)
{
if (nummapspraycans != UINT8_MAX)
nummapspraycans++;
P_RemoveMobj(mobj);
return false;
}
P_SetScale(mobj, mobj->destscale = 2*mobj->scale);
mobj->threshold = nummapspraycans;
P_SprayCanInit(mobj);
nummapspraycans++;
break;

View file

@ -816,7 +816,8 @@ static void P_SpawnMapThings(boolean spawnemblems)
Z_Free(loopends);
if (spawnemblems)
if (spawnemblems
&& gametype != GT_TUTORIAL)
{
const UINT8 recommendedcans =
#ifdef DEVELOP