From 9b224356fe7c494530ad55f7721208f25f0f2139 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Mon, 15 Jan 2024 17:49:10 -0700 Subject: [PATCH] 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());