diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9b3bc7715..dab39589c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -149,6 +149,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32 k_mapuser.c k_powerup.cpp k_hitlag.c + k_dialogue.cpp music.cpp music_manager.cpp ) diff --git a/src/acs/call-funcs.cpp b/src/acs/call-funcs.cpp index f70fecc3e..c7ff38591 100644 --- a/src/acs/call-funcs.cpp +++ b/src/acs/call-funcs.cpp @@ -44,6 +44,8 @@ #include "../k_bot.h" #include "../z_zone.h" #include "../music.h" +#include "../r_draw.h" +#include "../k_dialogue.hpp" #include "call-funcs.hpp" @@ -664,6 +666,50 @@ bool CallFunc_CameraWait(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM:: return true; // Execution interrupted } +/*-------------------------------------------------- + bool CallFunc_DialogueWaitDismiss(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Pauses the thread until the current + dialogue box is dismissed. +--------------------------------------------------*/ +bool CallFunc_DialogueWaitDismiss(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + (void)argV; + (void)argC; + + g_dialogue.SetDismissable(true); + + thread->state = { + ACSVM::ThreadState::WaitTag, + 0, + ACS_TAGTYPE_DIALOGUE + }; + + return true; // Execution interrupted +} + +/*-------------------------------------------------- + bool CallFunc_DialogueWaitText(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Pauses the thread until the current + dialogue box finishes rendering its text. +--------------------------------------------------*/ +bool CallFunc_DialogueWaitText(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + (void)argV; + (void)argC; + + g_dialogue.SetDismissable(false); + + thread->state = { + ACSVM::ThreadState::WaitTag, + 1, + ACS_TAGTYPE_DIALOGUE + }; + + return true; // Execution interrupted +} + /*-------------------------------------------------- bool CallFunc_ChangeFloor(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) @@ -1858,6 +1904,84 @@ bool CallFunc_AddBot(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word return false; } +/*-------------------------------------------------- + bool CallFunc_DialogueSetSpeaker(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Set the dialogue speaker to a skin. +--------------------------------------------------*/ +bool CallFunc_DialogueSetSpeaker(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + ACSVM::MapScope *map = nullptr; + + ACSVM::String *skinStr = nullptr; + const char *skinName = nullptr; + + int spriteFrame = 0; + + (void)argC; + + map = thread->scopeMap; + + skinStr = map->getString(argV[0]); + skinName = skinStr->str; + + spriteFrame = argV[1]; + + g_dialogue.SetSpeaker(skinName, spriteFrame); + return false; +} + +/*-------------------------------------------------- + bool CallFunc_DialogueSetCustomSpeaker(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Set the dialogue speaker to specific graphics. +--------------------------------------------------*/ +bool CallFunc_DialogueSetCustomSpeaker(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + ACSVM::MapScope *map = nullptr; + + ACSVM::String *nametagStr = nullptr; + const char *nametag = nullptr; + + ACSVM::String *patchStr = nullptr; + const char *patchName = nullptr; + patch_t *patch = nullptr; + + ACSVM::String *colorStr = nullptr; + const char *colorName = nullptr; + skincolornum_t colorID = SKINCOLOR_NONE; + UINT8 *colormap = nullptr; + + ACSVM::String *voiceStr = nullptr; + const char *voiceName = nullptr; + sfxenum_t voiceID = sfx_ktalk; + + (void)argC; + + map = thread->scopeMap; + + nametagStr = map->getString(argV[0]); + nametag = nametagStr->str; + + patchStr = map->getString(argV[1]); + patchName = patchStr->str; + patch = static_cast( W_CachePatchName(patchName, PU_CACHE) ); + + colorStr = map->getString(argV[2]); + colorName = colorStr->str; + if (ACS_GetColorFromString(colorName, &colorID) == true) + { + colormap = R_GetTranslationColormap(TC_DEFAULT, colorID, GTC_CACHE); + } + + voiceStr = map->getString(argV[3]); + voiceName = voiceStr->str; + ACS_GetSFXFromString(voiceName, &voiceID); + + g_dialogue.SetSpeaker(nametag, patch, colormap, voiceID); + return false; +} + /*-------------------------------------------------- bool CallFunc_StopLevelExit(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) @@ -1898,7 +2022,29 @@ bool CallFunc_ExitLevel(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::W if (server) SendNetXCmd(XD_EXITLEVEL, NULL, 0); + return false; +} +/*-------------------------------------------------- + bool CallFunc_DialogueNewText(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Change the current dialogue text. +--------------------------------------------------*/ +bool CallFunc_DialogueNewText(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + ACSVM::MapScope *map = nullptr; + + ACSVM::String *textStr = nullptr; + const char *text = nullptr; + + (void)argC; + + map = thread->scopeMap; + + textStr = map->getString(argV[0]); + text = textStr->str; + + g_dialogue.NewText(text); return false; } diff --git a/src/acs/call-funcs.hpp b/src/acs/call-funcs.hpp index b67302f47..48ce72e84 100644 --- a/src/acs/call-funcs.hpp +++ b/src/acs/call-funcs.hpp @@ -42,6 +42,8 @@ bool CallFunc_ThingCount(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM:: bool CallFunc_TagWait(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_PolyWait(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_CameraWait(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_DialogueWaitDismiss(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_DialogueWaitText(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_ChangeFloor(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_ChangeCeiling(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_LineSide(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); @@ -93,6 +95,10 @@ bool CallFunc_MusicPlay(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::W bool CallFunc_MusicStopAll(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_MusicRemap(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_DialogueSetSpeaker(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_DialogueSetCustomSpeaker(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_DialogueNewText(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); + bool CallFunc_GetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_SetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_GetSideProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); diff --git a/src/acs/environment.cpp b/src/acs/environment.cpp index f2bf53743..ad0c3e106 100644 --- a/src/acs/environment.cpp +++ b/src/acs/environment.cpp @@ -27,6 +27,7 @@ #include "../w_wad.h" #include "../z_zone.h" #include "../p_local.h" +#include "../k_dialogue.hpp" #include "environment.hpp" #include "thread.hpp" @@ -176,6 +177,12 @@ Environment::Environment() addFuncDataACS0( 508, addCallFunc(CallFunc_MusicPlay)); addFuncDataACS0( 509, addCallFunc(CallFunc_MusicStopAll)); addFuncDataACS0( 510, addCallFunc(CallFunc_MusicRemap)); + + addFuncDataACS0( 600, addCallFunc(CallFunc_DialogueSetSpeaker)); + addFuncDataACS0( 601, addCallFunc(CallFunc_DialogueSetCustomSpeaker)); + addFuncDataACS0( 602, addCallFunc(CallFunc_DialogueNewText)); + addFuncDataACS0( 603, addCallFunc(CallFunc_DialogueWaitDismiss)); + addFuncDataACS0( 604, addCallFunc(CallFunc_DialogueWaitText)); } ACSVM::Thread *Environment::allocThread() @@ -289,6 +296,20 @@ bool Environment::checkTag(ACSVM::Word type, ACSVM::Word tag) return (camera->tracer == nullptr || P_MobjWasRemoved(camera->tracer) == true); } + + case ACS_TAGTYPE_DIALOGUE: + { + if (tag == 0) // cheeky reuse + { + // wait for dismissal + return (!g_dialogue.Active()); + } + else + { + // wait for text to finish + return (g_dialogue.TextDone()); + } + } } return true; diff --git a/src/acs/thread.hpp b/src/acs/thread.hpp index 561945cf0..0b20271af 100644 --- a/src/acs/thread.hpp +++ b/src/acs/thread.hpp @@ -53,6 +53,7 @@ enum acs_tagType_e ACS_TAGTYPE_POLYOBJ, ACS_TAGTYPE_SECTOR, ACS_TAGTYPE_CAMERA, + ACS_TAGTYPE_DIALOGUE, }; class ThreadInfo : public ACSVM::ThreadInfo diff --git a/src/d_main.c b/src/d_main.c index c17737060..0d80071dc 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -84,6 +84,7 @@ #include "k_vote.h" #include "k_serverstats.h" #include "music.h" +#include "k_dialogue.h" #ifdef HWRENDER #include "hardware/hw_main.h" // 3D View Rendering @@ -1012,6 +1013,8 @@ void D_ClearState(void) if (gamedata && gamedata->deferredsave) G_SaveGameData(); + K_UnsetDialogue(); + G_SetGamestate(GS_NULL); wipegamestate = GS_NULL; } diff --git a/src/deh_tables.c b/src/deh_tables.c index c90855a42..e51e2e878 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -6657,6 +6657,7 @@ struct int_const_s const INT_CONST[] = { {"SKSKSLOW",SKSKSLOW}, // Overtake taunt {"SKSKHITM",SKSKHITM}, // Hit confirm taunt {"SKSKPOWR",SKSKPOWR}, // Power item taunt + {"SKSKTALK",SKSKTALK}, // Dialogue // 3D Floor/Fake Floor/FOF/whatever flags {"FOF_EXISTS",FOF_EXISTS}, ///< Always set, to check for validity. diff --git a/src/info.c b/src/info.c index 509a84571..a1fca74c2 100644 --- a/src/info.c +++ b/src/info.c @@ -915,6 +915,7 @@ char spr2names[NUMPLAYERSPRITES][5] = "SIGN", // Finish signpost "XTRA", // Three Faces of Darkness + "TALK", // Dialogue }; playersprite_t free_spr2 = SPR2_FIRSTFREESLOT; @@ -956,6 +957,7 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = { 0, // SPR2_SIGN 0, // SPR2_XTRA + 0, // SPR2_TALK }; // Doesn't work with g++, needs actionf_p1 (don't modify this comment) diff --git a/src/info.h b/src/info.h index 09abce486..dec72563c 100644 --- a/src/info.h +++ b/src/info.h @@ -1468,6 +1468,7 @@ typedef enum playersprite SPR2_DEAD, SPR2_SIGN, SPR2_XTRA, + SPR2_TALK, SPR2_FIRSTFREESLOT, SPR2_LASTFREESLOT = 0x7f, diff --git a/src/k_dialogue.cpp b/src/k_dialogue.cpp new file mode 100644 index 000000000..e75e18a4d --- /dev/null +++ b/src/k_dialogue.cpp @@ -0,0 +1,350 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) by Sonic Team Junior +// Copyright (C) by Kart Krew +// Copyright (C) by Sally "TehRealSalt" Cochenour +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file k_dialogue.cpp +/// \brief Basic text prompts + +#include "k_dialogue.hpp" +#include "k_dialogue.h" + +#include +#include + +#include "info.h" +#include "sounds.h" +#include "g_game.h" +#include "v_video.h" +#include "r_draw.h" +#include "m_easing.h" +#include "r_skins.h" +#include "s_sound.h" +#include "z_zone.h" +#include "k_hud.h" + +#include "v_draw.hpp" + +#include "acs/interface.h" + +using srb2::Dialogue; + +void Dialogue::Init(void) +{ + active = true; + syllable = true; +} + +void Dialogue::SetSpeaker(void) +{ + // Unset speaker + speaker.clear(); + + portrait = nullptr; + portraitColormap = nullptr; + + voiceSfx = sfx_ktalk; +} + +void Dialogue::SetSpeaker(std::string skinName, int portraitID) +{ + Init(); + + // Set speaker based on a skin + int skinID = -1; + if (!skinName.empty()) + { + skinID = R_SkinAvailable(skinName.c_str()); + } + + if (skinID >= 0 && skinID < numskins) + { + const skin_t *skin = &skins[skinID]; + const spritedef_t *sprdef = &skin->sprites[SPR2_TALK]; + + if (sprdef->numframes > 0) + { + portraitID %= sprdef->numframes; + } + + const spriteframe_t *sprframe = &sprdef->spriteframes[portraitID]; + + speaker = skin->realname; + + portrait = static_cast( W_CachePatchNum(sprframe->lumppat[0], PU_CACHE) ); + portraitColormap = R_GetTranslationColormap(skinID, static_cast(skin->prefcolor), GTC_CACHE); + + voiceSfx = skin->soundsid[ S_sfx[sfx_ktalk].skinsound ]; + } + else + { + SetSpeaker(); + } +} + +void Dialogue::SetSpeaker(std::string name, patch_t *patch, UINT8 *colormap, sfxenum_t voice) +{ + Init(); + + // Set custom speaker + speaker = name; + + if (speaker.empty()) + { + portrait = nullptr; + portraitColormap = nullptr; + voiceSfx = sfx_ktalk; + return; + } + + portrait = patch; + portraitColormap = colormap; + + voiceSfx = voice; +} + +void Dialogue::NewText(std::string newText) +{ + Init(); + + newText = V_ScaledWordWrap( + 290 << FRACBITS, + FRACUNIT, FRACUNIT, FRACUNIT, + 0, HU_FONT, + newText.c_str() + ); + + text.clear(); + + textDest = newText; + std::reverse(textDest.begin(), textDest.end()); + + textTimer = kTextPunctPause; + textSpeed = kTextSpeedDefault; + textDone = false; +} + +bool Dialogue::Active(void) +{ + return active; +} + +bool Dialogue::TextDone(void) +{ + return textDone; +} + +bool Dialogue::Dismissable(void) +{ + return dismissable; +} + +void Dialogue::SetDismissable(bool value) +{ + dismissable = value; +} + +void Dialogue::WriteText(void) +{ + bool voicePlayed = false; + + textTimer -= textSpeed; + + while (textTimer <= 0 && !textDest.empty()) + { + char c = textDest.back(); + text.push_back(c); + + if (voicePlayed == false + && std::isprint(c) + && c != ' ') + { + if (syllable) + { + S_StopSoundByNum(voiceSfx); + S_StartSound(nullptr, voiceSfx); + } + + syllable = !syllable; + voicePlayed = true; + } + + if (c == '.' || c == ',' || c == ';' || c == '!' || c == '?') + { + // slow down for punctuation + textTimer += kTextPunctPause; + } + else + { + textTimer += FRACUNIT; + } + + textDest.pop_back(); + } + + textDone = (textTimer <= 0 && textDest.empty()); +} + +bool Dialogue::Held(void) +{ + return ((players[serverplayer].cmd.buttons & BT_VOTE) == BT_VOTE); +} + +bool Dialogue::Pressed(void) +{ + return ( + ((players[serverplayer].cmd.buttons & BT_VOTE) == BT_VOTE) && + ((players[serverplayer].oldcmd.buttons & BT_VOTE) == 0) + ); +} + +void Dialogue::CompleteText(void) +{ + while (!textDest.empty()) + { + text.push_back( textDest.back() ); + textDest.pop_back(); + } + + textTimer = 0; + textDone = true; +} + +void Dialogue::Tick(void) +{ + if (Active()) + { + if (slide < FRACUNIT) + { + slide += kSlideSpeed; + } + } + else + { + if (slide > 0) + { + slide -= kSlideSpeed; + + if (slide <= 0) + { + Unset(); + } + } + } + + slide = std::clamp(slide, 0, FRACUNIT); + + if (slide != FRACUNIT) + { + return; + } + + WriteText(); + + if (Dismissable() == true) + { + if (Pressed() == true) + { + if (TextDone()) + { + Dismiss(); + } + else + { + CompleteText(); + } + } + } +} + +void Dialogue::Draw(void) +{ + if (slide == 0) + { + return; + } + + srb2::Draw drawer = + srb2::Draw( + 0, FixedToFloat(Easing_OutCubic(slide, -78 * FRACUNIT, 0)) + ).flags(V_SNAPTOTOP); + + drawer.patch("TUTDIAG1"); + + if (portrait != nullptr) + { + drawer + .xy(10, 41) + .colormap(portraitColormap) + .patch(portrait); + } + + drawer + .xy(45, 39) + .font(srb2::Draw::Font::kConsole) + .text( speaker.c_str() ); + + drawer + .xy(10, 3) + .font(srb2::Draw::Font::kConsole) + .text( text.c_str() ); + + if (Dismissable()) + { + if (TextDone()) + { + drawer + .xy(304, 7) + .patch("TUTDIAG2"); + } + + K_drawButton( + FloatToFixed(drawer.x() + 303), + FloatToFixed(drawer.y() + 39), + V_SNAPTOTOP, + kp_button_z[0], Held() + ); + } +} + +void Dialogue::Dismiss(void) +{ + active = false; + text.clear(); + textDest.clear(); +} + +void Dialogue::Unset(void) +{ + Dismiss(); + SetSpeaker(); +} + +/* + Ideally, the Dialogue class would be on player_t instead of in global space + for full multiplayer compatibility, but right now it's only being used for + the tutorial, and I don't feel like writing network code. If you feel like + doing that, then you can remove g_dialogue entirely. +*/ + +Dialogue g_dialogue; + +void K_UnsetDialogue(void) +{ + g_dialogue.Unset(); +} + +void K_DrawDialogue(void) +{ + g_dialogue.Draw(); +} + +void K_TickDialogue(void) +{ + g_dialogue.Tick(); +} diff --git a/src/k_dialogue.h b/src/k_dialogue.h new file mode 100644 index 000000000..7b4f7437e --- /dev/null +++ b/src/k_dialogue.h @@ -0,0 +1,32 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) by Sonic Team Junior +// Copyright (C) by Kart Krew +// Copyright (C) by Sally "TehRealSalt" Cochenour +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file k_dialogue.h +/// \brief Basic text prompts + +#ifndef __K_DIALOGUE__ +#define __K_DIALOGUE__ + +#include "doomtype.h" +#include "doomdef.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void K_UnsetDialogue(void); +void K_DrawDialogue(void); +void K_TickDialogue(void); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif //__K_DIALOGUE__ diff --git a/src/k_dialogue.hpp b/src/k_dialogue.hpp new file mode 100644 index 000000000..c3fb8dd5a --- /dev/null +++ b/src/k_dialogue.hpp @@ -0,0 +1,88 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) by Sonic Team Junior +// Copyright (C) by Kart Krew +// Copyright (C) by Sally "TehRealSalt" Cochenour +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file k_dialogue.hpp +/// \brief Basic text prompts + +#ifndef __K_DIALOGUE_HPP__ +#define __K_DIALOGUE_HPP__ + +#include + +#include "doomdef.h" +#include "doomtype.h" +#include "typedef.h" +#include "sounds.h" +#include "v_video.h" + +namespace srb2 +{ + +class Dialogue +{ +private: + patch_t *bgPatch; + patch_t *confirmPatch; + + std::string speaker; + patch_t *portrait; + UINT8 *portraitColormap; + sfxenum_t voiceSfx; + + std::string text; + std::string textDest; + + bool active; + fixed_t slide; + + fixed_t textTimer; + fixed_t textSpeed; + bool textDone; + bool syllable; + + bool dismissable; + + void Init(void); + //void Unset(void); + + void WriteText(void); + void CompleteText(void); + + bool Pressed(void); + bool Held(void); + +public: + static constexpr fixed_t kTextSpeedDefault = FRACUNIT; + static constexpr fixed_t kTextPunctPause = (FRACUNIT * TICRATE * 2) / 5; + static constexpr fixed_t kSlideSpeed = FRACUNIT / (TICRATE / 5); + + void SetSpeaker(void); + void SetSpeaker(std::string skinName, int portraitID); + void SetSpeaker(std::string name, patch_t *patch, UINT8 *colormap, sfxenum_t voice); + + void NewText(std::string newText); + + bool Active(void); + bool TextDone(void); + bool Dismissable(void); + void SetDismissable(bool value); + + void Tick(void); + void Draw(void); + + void Dismiss(void); + void Unset(void); +}; + +}; // namespace srb2 + +extern srb2::Dialogue g_dialogue; + +#endif //__K_DIALOGUE_HPP__ diff --git a/src/k_kart.c b/src/k_kart.c index 193da3181..2a2f4c8f4 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8250,7 +8250,6 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) } } - if (player->stealingtimer == 0 && player->rocketsneakertimer && onground == true) diff --git a/src/p_setup.c b/src/p_setup.c index beee4d955..958bfa22e 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -105,6 +105,7 @@ #include "k_rank.h" #include "k_mapuser.h" #include "music.h" +#include "k_dialogue.h" // Replay names have time #if !defined (UNDER_CE) @@ -1260,7 +1261,6 @@ static void P_LoadSidedefs(UINT8 *data) case 425: // Calls P_SetMobjState on calling mobj case 442: // Calls P_SetMobjState on mobjs of a given type in the tagged sectors case 443: // Calls a named Lua function - case 459: // Control text prompt (named tag) case 461: // Spawns an object on the map based on texture offsets case 463: // Colorizes an object case 475: // ACS_Execute @@ -5800,7 +5800,7 @@ static void P_ConvertBinaryLinedefTypes(void) lines[i].args[1] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; break; case 437: //Disable player control - lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[0] = ((sides[lines[i].sidenum[0]].textureoffset >> FRACBITS) != 0); break; case 438: //Change object size lines[i].args[0] = P_AproxDistance(lines[i].dx, lines[i].dy) >> FRACBITS; @@ -5950,25 +5950,6 @@ static void P_ConvertBinaryLinedefTypes(void) lines[i].args[3] = (lines[i].sidenum[1] != 0xffff) ? sides[lines[i].sidenum[1]].textureoffset >> FRACBITS : 0; lines[i].args[4] = !!(lines[i].flags & ML_NOSKEW); break; - case 459: //Control text prompt - lines[i].args[1] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; - lines[i].args[2] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; - if (lines[i].flags & ML_BLOCKPLAYERS) - lines[i].args[3] |= TMP_CLOSE; - if (lines[i].flags & ML_SKEWTD) - lines[i].args[3] |= TMP_RUNPOSTEXEC; - if (lines[i].flags & ML_TFERLINE) - lines[i].args[3] |= TMP_CALLBYNAME; - if (lines[i].flags & ML_NOSKEW) - lines[i].args[3] |= TMP_KEEPCONTROLS; - if (lines[i].flags & ML_MIDPEG) - lines[i].args[3] |= TMP_KEEPREALTIME; - /*if (lines[i].flags & ML_NOCLIMB) - lines[i].args[3] |= TMP_ALLPLAYERS; - if (lines[i].flags & ML_MIDSOLID) - lines[i].args[3] |= TMP_FREEZETHINKERS;*/ - lines[i].args[4] = (lines[i].sidenum[1] != 0xFFFF) ? sides[lines[i].sidenum[1]].textureoffset >> FRACBITS : tag; - break; case 460: //Award rings lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; lines[i].args[1] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; @@ -8278,6 +8259,8 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) // Close text prompt before freeing the old level F_EndTextPrompt(false, true); + K_UnsetDialogue(); + LUA_InvalidateLevel(); for (ss = sectors; sectors+numsectors != ss; ss++) diff --git a/src/p_spec.c b/src/p_spec.c index b640a9c41..85003e43e 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3284,13 +3284,10 @@ boolean P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, cha } break; - case 437: // Disable Player Controls + case 437: // Toggle Player Controls if (mo && mo->player) { - UINT16 fractime = (UINT16)(args[0]); - if (fractime < 1) - fractime = 1; //instantly wears off upon leaving - mo->player->nocontrol = fractime; + mo->player->nocontrol = ((args[0] == 0) ? UINT16_MAX : 0); } break; @@ -4071,33 +4068,6 @@ boolean P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, cha } break; - case 459: // Control Text Prompt - // console player only - if (mo && mo->player && P_IsLocalPlayer(mo->player)) - { - INT32 promptnum = max(0, args[1] - 1); - INT32 pagenum = max(0, args[2] - 1); - INT32 postexectag = abs(args[4]); - - boolean closetextprompt = (args[3] & TMP_CLOSE); - //boolean allplayers = (args[3] & TMP_ALLPLAYERS); - boolean runpostexec = (args[3] & TMP_RUNPOSTEXEC); - boolean blockcontrols = !(args[3] & TMP_KEEPCONTROLS); - boolean freezerealtime = !(args[3] & TMP_KEEPREALTIME); - //boolean freezethinkers = (args[3] & TMP_FREEZETHINKERS); - boolean callbynamedtag = (args[3] & TMP_CALLBYNAME); - - if (closetextprompt) - F_EndTextPrompt(false, false); - else - { - if (callbynamedtag && stringargs[0] && stringargs[0][0]) - F_GetPromptPageByNamedTag(stringargs[0], &promptnum, &pagenum); - F_StartTextPrompt(promptnum, pagenum, mo, runpostexec ? postexectag : 0, blockcontrols, freezerealtime); - } - } - break; - case 460: // Award rings { if (gametyperules & GTR_SPHERES) diff --git a/src/p_tick.c b/src/p_tick.c index 8e408e92b..b478a6668 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -43,6 +43,7 @@ #include "acs/interface.h" #include "k_objects.h" #include "music.h" +#include "k_dialogue.h" #ifdef PARANOIA #include "deh_tables.h" // MOBJTYPE_LIST @@ -1033,6 +1034,11 @@ void P_Ticker(boolean run) P_RunChaseCameras(); } + if (run) + { + K_TickDialogue(); + } + LUA_HOOK(PostThinkFrame); if (run) diff --git a/src/p_user.c b/src/p_user.c index e60230a0c..b3f88115f 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4335,15 +4335,13 @@ void P_PlayerThink(player_t *player) if (!(--player->nocontrol)) { if (player->pflags & PF_FAULT) - { + { player->pflags &= ~PF_FAULT; player->mo->renderflags &= ~RF_DONTDRAW; player->mo->flags &= ~MF_NOCLIPTHING; } } } - else - player->nocontrol = 0; // Flash player after being hit. if (!(player->hyudorotimer // SRB2kart - fixes Hyudoro not flashing when it should. diff --git a/src/sounds.c b/src/sounds.c index 7e8560eb2..8b1ff2a84 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -1439,6 +1439,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"kslow", false, 64, 32, -1, NULL, 0, SKSKSLOW, -1, LUMPERROR, ""}, {"khitem", false, 128, 32, -1, NULL, 0, SKSKHITM, -1, LUMPERROR, ""}, {"kgloat", false, 64, 48, -1, NULL, 0, SKSKPOWR, -1, LUMPERROR, ""}, + {"ktalk", false, 64, 48, -1, NULL, 0, SKSKTALK, -1, LUMPERROR, ""}, // skin sounds free slots to add sounds at run time (Boris HACK!!!) // initialized to NULL diff --git a/src/sounds.h b/src/sounds.h index 324066ac9..176dfc541 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -56,6 +56,7 @@ typedef enum SKSKSLOW, // Overtake taunt SKSKHITM, // Hit confirm taunt SKSKPOWR, // Power item taunt + SKSKTALK, NUMSKINSOUNDS } skinsound_t; @@ -1506,6 +1507,7 @@ typedef enum sfx_kslow, sfx_khitem, sfx_kgloat, + sfx_ktalk, // free slots for S_AddSoundFx() at run-time -------------------- sfx_freeslot0, diff --git a/src/st_stuff.c b/src/st_stuff.c index 748d6da1d..c1ff32972 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -52,6 +52,7 @@ #include "k_zvote.h" #include "music.h" #include "i_sound.h" +#include "k_dialogue.h" UINT16 objectsdrawn = 0; @@ -1244,6 +1245,8 @@ static void ST_overlayDrawer(void) } K_DrawMidVote(); + + K_DrawDialogue(); } void ST_DrawDemoTitleEntry(void)