From 9b224356fe7c494530ad55f7721208f25f0f2139 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Mon, 15 Jan 2024 17:49:10 -0700 Subject: [PATCH 1/4] Add persistent objective messages via K_AddMessage, expose to ACS --- src/acs/call-funcs.cpp | 47 +++++++++++++++++++++++++++++++ src/acs/call-funcs.hpp | 5 ++++ src/k_collide.cpp | 4 +-- src/k_hud.cpp | 57 ++++++++++++++++++++++++++++++++++---- src/k_hud.h | 6 ++-- src/k_kart.c | 4 +-- src/k_powerup.cpp | 10 +++---- src/objects/battle-ufo.cpp | 3 +- 8 files changed, 118 insertions(+), 18 deletions(-) diff --git a/src/acs/call-funcs.cpp b/src/acs/call-funcs.cpp index 07d5c5940..ac7fcd314 100644 --- a/src/acs/call-funcs.cpp +++ b/src/acs/call-funcs.cpp @@ -47,6 +47,7 @@ #include "../music.h" #include "../r_draw.h" #include "../k_dialogue.hpp" +#include "../k_hud.h" #include "call-funcs.hpp" @@ -3997,3 +3998,49 @@ bool CallFunc_GetThingUserProperty(ACSVM::Thread *thread, const ACSVM::Word *arg thread->dataStk.push(ret); return false; } + +bool CallFunc_AddMessage(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + ACSVM::MapScope *map = thread->scopeMap; + + K_AddMessage(map->getString(argV[0])->str, argV[1], argV[2]); + + return true; +} + +bool CallFunc_AddMessageForPlayer(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + ACSVM::MapScope *map = thread->scopeMap; + + auto info = &static_cast(thread)->info; + + if ((info != NULL) + && (info->mo != NULL && P_MobjWasRemoved(info->mo) == false) + && (info->mo->player != NULL)) + { + K_AddMessageForPlayer(info->mo->player, map->getString(argV[0])->str, argV[1], argV[2]); + } + + return true; +} + +bool CallFunc_ClearPersistentMessages(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + K_ClearPersistentMessages(); + + return true; +} + +bool CallFunc_ClearPersistentMessageForPlayer(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + auto info = &static_cast(thread)->info; + + if ((info != NULL) + && (info->mo != NULL && P_MobjWasRemoved(info->mo) == false) + && (info->mo->player != NULL)) + { + K_ClearPersistentMessageForPlayer(info->mo->player); + } + + return true; +} \ No newline at end of file diff --git a/src/acs/call-funcs.hpp b/src/acs/call-funcs.hpp index e3379ee22..c346e5995 100644 --- a/src/acs/call-funcs.hpp +++ b/src/acs/call-funcs.hpp @@ -123,4 +123,9 @@ bool CallFunc_GetSideUserProperty(ACSVM::Thread *thread, const ACSVM::Word *argV bool CallFunc_GetSectorUserProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_GetThingUserProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_AddMessage(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_AddMessageForPlayer(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_ClearPersistentMessages(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_ClearPersistentMessageForPlayer(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); + #endif // __SRB2_ACS_CALL_FUNCS_HPP__ diff --git a/src/k_collide.cpp b/src/k_collide.cpp index 04e0025e7..2cf53cf1b 100644 --- a/src/k_collide.cpp +++ b/src/k_collide.cpp @@ -873,8 +873,8 @@ boolean K_InstaWhipCollide(mobj_t *shield, mobj_t *victim) attackerPlayer->instaWhipCharge = 0; attackerPlayer->flashing = 0; - K_AddMessageForPlayer(victimPlayer, va("Whip Reflected!"), false); - K_AddMessageForPlayer(attackerPlayer, va("COUNTERED!!"), false); + K_AddMessageForPlayer(victimPlayer, "Whip Reflected!", false, false); + K_AddMessageForPlayer(attackerPlayer, "COUNTERED!!", false, false); // Localized broly for a local event. if (mobj_t *broly = Obj_SpawnBrolyKi(victim, victimHitlag/2)) diff --git a/src/k_hud.cpp b/src/k_hud.cpp index 4283d8b96..20df24e89 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -5635,7 +5635,9 @@ typedef struct typedef struct { std::deque messages; + std::string objective = ""; tic_t timer = 0; + boolean persist = false; messagemode_t mode = MM_IN; const tic_t speedyswitch = 2*TICRATE; const tic_t lazyswitch = 4*TICRATE; @@ -5660,7 +5662,13 @@ typedef struct void tick() { if (messages.size() == 0) - return; + { + if (!objective.empty()) + restore(); + else + return; + } + if (timer == 0 && mode == MM_IN) S_StartSound(NULL, sfx_s3k47); @@ -5676,7 +5684,7 @@ typedef struct case MM_HOLD: if (messages.size() > 1 && timer > speedyswitch) // Waiting message, switch to it right away! next(); - else if (timer > lazyswitch) // If there's no pending message, we can chill for a bit. + else if (timer > lazyswitch && !persist) // If there's no pending message, we can chill for a bit. switch_mode(MM_OUT); break; case MM_OUT: @@ -5686,9 +5694,18 @@ typedef struct } } + void restore() + { + switch_mode(MM_IN); + persist = true; + messages.clear(); + messages.push_front(objective); + } + void next() { switch_mode(MM_IN); + persist = false; if (messages.size() > 0) messages.pop_front(); } @@ -5697,18 +5714,31 @@ typedef struct static std::vector messagestates{MAXSPLITSCREENPLAYERS}; -void K_AddMessage(char *msg, boolean interrupt) +void K_AddMessage(const char *msg, boolean interrupt, boolean persist) { for (auto &state : messagestates) { if (interrupt) state.clear(); - state.add(msg); + + if (persist) + state.objective = msg; + else + state.add(msg); + } +} + +void K_ClearPersistentMessages() +{ + for (auto &state : messagestates) + { + state.objective = ""; + state.clear(); } } // Return value can be used for "paired" splitscreen messages, true = was displayed -void K_AddMessageForPlayer(player_t *player, char *msg, boolean interrupt) +void K_AddMessageForPlayer(player_t *player, const char *msg, boolean interrupt, boolean persist) { if (!player) return; @@ -5721,7 +5751,22 @@ void K_AddMessageForPlayer(player_t *player, char *msg, boolean interrupt) if (interrupt) state->clear(); - state->add(msg); + if (persist) + state->objective = msg; + else + state->add(msg); +} + +void K_ClearPersistentMessageForPlayer(player_t *player) +{ + if (!player) + return; + + if (player && !P_IsDisplayPlayer(player)) + return; + + messagestate_t *state = &messagestates[G_PartyPosition(player - players)]; + state->objective = ""; } void K_TickMessages() diff --git a/src/k_hud.h b/src/k_hud.h index 185315d06..839827d3d 100644 --- a/src/k_hud.h +++ b/src/k_hud.h @@ -93,8 +93,10 @@ extern patch_t *kp_button_left[2]; extern patch_t *kp_eggnum[6]; extern patch_t *kp_facenum[MAXPLAYERS+1]; -void K_AddMessage(char *msg, boolean interrupt); -void K_AddMessageForPlayer(player_t *player, char *msg, boolean interrupt); +void K_AddMessage(const char *msg, boolean interrupt, boolean persist); +void K_AddMessageForPlayer(player_t *player, const char *msg, boolean interrupt, boolean persist); +void K_ClearPersistentMessages(void); +void K_ClearPersistentMessageForPlayer(player_t *player); void K_TickMessages(void); #ifdef __cplusplus diff --git a/src/k_kart.c b/src/k_kart.c index fb519e521..b3f47e411 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3841,8 +3841,8 @@ void K_DoGuardBreak(mobj_t *t1, mobj_t *t2) { S_StartSound(t1, sfx_gbrk); K_AddHitLag(t1, 24, true); - K_AddMessageForPlayer(t2->player, va("Smashed 'em!"), false); - K_AddMessageForPlayer(t1->player, va("BARRIER BREAK!!"), false); + K_AddMessageForPlayer(t2->player, "Smashed 'em!", false, false); + K_AddMessageForPlayer(t1->player, "BARRIER BREAK!!", false, false); angle_t thrangle = R_PointToAngle2(t1->x, t1->y, t2->x, t2->y); P_Thrust(t1, thrangle, 7*mapobjectscale); diff --git a/src/k_powerup.cpp b/src/k_powerup.cpp index 69bbddc36..4a3dfe4ea 100644 --- a/src/k_powerup.cpp +++ b/src/k_powerup.cpp @@ -53,29 +53,29 @@ void K_GivePowerUp(player_t* player, kartitems_t powerup, tic_t time) switch (powerup) { case POWERUP_SMONITOR: - K_AddMessageForPlayer(player, va("Got S MONITOR!"), true); + K_AddMessageForPlayer(player, "Got S MONITOR!", true, false); K_DoInvincibility(player, time); player->powerup.superTimer += time; break; case POWERUP_BARRIER: - K_AddMessageForPlayer(player, va("Got MEGA BARRIER!"), true); + K_AddMessageForPlayer(player, "Got MEGA BARRIER!", true, false); player->powerup.barrierTimer += time; Obj_SpawnMegaBarrier(player); break; case POWERUP_BUMPER: - K_AddMessageForPlayer(player, va("Got BUMPER RESTOCK!"), true); + K_AddMessageForPlayer(player, "Got BUMPER RESTOCK!", true, false); K_GiveBumpersToPlayer(player, nullptr, 5); break; case POWERUP_BADGE: - K_AddMessageForPlayer(player, va("Got RHYTHM BADGE!"), true); + K_AddMessageForPlayer(player, "Got RHYTHM BADGE!", true, false); player->powerup.rhythmBadgeTimer += time; break; case POWERUP_SUPERFLICKY: - K_AddMessageForPlayer(player, va("Got SUPER FLICKY!"), true); + K_AddMessageForPlayer(player, "Got SUPER FLICKY!", true, false); if (K_PowerUpRemaining(player, POWERUP_SUPERFLICKY)) { Obj_ExtendSuperFlickySwarm(player->powerup.flickyController, time); diff --git a/src/objects/battle-ufo.cpp b/src/objects/battle-ufo.cpp index 2057e5f8d..e1d2bb4d5 100644 --- a/src/objects/battle-ufo.cpp +++ b/src/objects/battle-ufo.cpp @@ -115,7 +115,8 @@ public: Spawner* spawner = next(g_battleufo.previousId); UFO* ufo = static_cast(P_SpawnMobjFromMobj(spawner, 0, 0, 250*FRACUNIT - ofs, MT_BATTLEUFO)); - K_AddMessage(va("Crack the Combat UFO!"), true); + + K_AddMessage("Crack the Combat UFO!", true, false); S_StartSound(NULL, sfx_mbs54); ufo->sprzoff(ofs * spawner->scale()); From 7b2c5276c686b410ec4cd8d7f23be4736d1f57bf Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Wed, 17 Jan 2024 00:46:22 -0700 Subject: [PATCH 2/4] Add opcodes for HUD message system --- src/acs/environment.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/acs/environment.cpp b/src/acs/environment.cpp index d1fd639a4..9929fbcc8 100644 --- a/src/acs/environment.cpp +++ b/src/acs/environment.cpp @@ -192,6 +192,11 @@ Environment::Environment() addFuncDataACS0( 603, addCallFunc(CallFunc_DialogueWaitDismiss)); addFuncDataACS0( 604, addCallFunc(CallFunc_DialogueWaitText)); addFuncDataACS0( 605, addCallFunc(CallFunc_DialogueAutoDismiss)); + + addFuncDataACS0( 700, addCallFunc(CallFunc_AddMessage)); + addFuncDataACS0( 701, addCallFunc(CallFunc_AddMessageForPlayer)); + addFuncDataACS0( 702, addCallFunc(CallFunc_ClearPersistentMessages)); + addFuncDataACS0( 703, addCallFunc(CallFunc_ClearPersistentMessageForPlayer)); } ACSVM::Thread *Environment::allocThread() From b903da899eec0c8dcd42e1b26a1628fde2b520f6 Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 17 Jan 2024 20:13:14 -0800 Subject: [PATCH 3/4] Objective text ACS: return false I think these are only supposed to return true if they suspend thread execution, but I'm not sure. --- src/acs/call-funcs.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/acs/call-funcs.cpp b/src/acs/call-funcs.cpp index ac7fcd314..09e393a65 100644 --- a/src/acs/call-funcs.cpp +++ b/src/acs/call-funcs.cpp @@ -4005,7 +4005,7 @@ bool CallFunc_AddMessage(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM:: K_AddMessage(map->getString(argV[0])->str, argV[1], argV[2]); - return true; + return false; } bool CallFunc_AddMessageForPlayer(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) @@ -4021,14 +4021,14 @@ bool CallFunc_AddMessageForPlayer(ACSVM::Thread *thread, const ACSVM::Word *argV K_AddMessageForPlayer(info->mo->player, map->getString(argV[0])->str, argV[1], argV[2]); } - return true; + return false; } bool CallFunc_ClearPersistentMessages(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) { K_ClearPersistentMessages(); - return true; + return false; } bool CallFunc_ClearPersistentMessageForPlayer(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) @@ -4042,5 +4042,5 @@ bool CallFunc_ClearPersistentMessageForPlayer(ACSVM::Thread *thread, const ACSVM K_ClearPersistentMessageForPlayer(info->mo->player); } - return true; -} \ No newline at end of file + return false; +} From c5bafc7b4cdb4eab99a4234d4c6bb88fdccb1f36 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Thu, 18 Jan 2024 14:55:10 -0700 Subject: [PATCH 4/4] Clear HUD messages on level transition --- src/p_setup.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 604f29b06..2e6eb31c0 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -114,6 +114,7 @@ #include "k_mapuser.h" #include "music.h" #include "k_dialogue.h" +#include "k_hud.h" // K_ClearPersistentMessages // Replay names have time #if !defined (UNDER_CE) @@ -8482,6 +8483,8 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) R_InitMobjInterpolators(); P_InitCachedActions(); + K_ClearPersistentMessages(); + // internal game map maplumpname = mapheaderinfo[gamemap-1]->lumpname; lastloadedmaplumpnum = mapheaderinfo[gamemap-1]->lumpnum;