添加看视频复活
This commit is contained in:
@@ -202,6 +202,7 @@ extern bool gameOverFlag;
|
||||
extern bool suspendFlag;
|
||||
extern bool targetFlag;
|
||||
extern bool bgmEnabled;
|
||||
extern bool reviveAvailable;
|
||||
extern int workRegion[20][10];
|
||||
extern Point point;
|
||||
extern Point target;
|
||||
@@ -241,6 +242,8 @@ void ComputeTarget();
|
||||
void Restart();
|
||||
void StartGameWithMode(int mode);
|
||||
void ReturnToMainMenu();
|
||||
void ReviveAfterVideo();
|
||||
void SetFeedbackMessage(const TCHAR* title, const TCHAR* detail, int ticks);
|
||||
void OpenRulesScreen();
|
||||
void OpenUpgradeMenu();
|
||||
void ConfirmUpgradeSelection();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "stdafx.h"
|
||||
#include "Tetris.h"
|
||||
#include <string>
|
||||
#include <shellapi.h>
|
||||
|
||||
#define MAX_LOADSTRING 100
|
||||
#define GAME_TIMER_ID 1
|
||||
@@ -16,11 +17,17 @@ bool bgmEnabled = true;
|
||||
static bool bgmPlaying = false;
|
||||
static bool bgmUsingMci = false;
|
||||
static constexpr const wchar_t* kBgmAlias = L"TereisBgm";
|
||||
static constexpr const wchar_t* kReviveVideoAlias = L"TereisReviveVideo";
|
||||
|
||||
ATOM MyRegisterClass(HINSTANCE hInstance);
|
||||
BOOL InitInstance(HINSTANCE, int);
|
||||
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
|
||||
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
|
||||
static std::wstring BuildAssetPath(const wchar_t* relativePath);
|
||||
static std::wstring BuildWorkingDirAssetPath(const wchar_t* relativePath);
|
||||
static bool FileExists(const std::wstring& path);
|
||||
static void StopBackgroundMusic();
|
||||
static void StartBackgroundMusic();
|
||||
|
||||
static void ResetGameTimer(HWND hWnd)
|
||||
{
|
||||
@@ -28,6 +35,90 @@ static void ResetGameTimer(HWND hWnd)
|
||||
SetTimer(hWnd, GAME_TIMER_ID, currentFallInterval > 0 ? currentFallInterval : GAME_TIMER_INTERVAL, nullptr);
|
||||
}
|
||||
|
||||
static bool PlayReviveVideo(HWND hWnd)
|
||||
{
|
||||
std::wstring videoPath = BuildAssetPath(L"assets\\video\\video.avi");
|
||||
if (!FileExists(videoPath))
|
||||
{
|
||||
videoPath = BuildWorkingDirAssetPath(L"assets\\video\\video.avi");
|
||||
}
|
||||
if (!FileExists(videoPath))
|
||||
{
|
||||
videoPath = BuildAssetPath(L"assets\\video\\video.mp4");
|
||||
}
|
||||
if (!FileExists(videoPath))
|
||||
{
|
||||
videoPath = BuildWorkingDirAssetPath(L"assets\\video\\video.mp4");
|
||||
}
|
||||
if (!FileExists(videoPath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool shouldResumeBgm = bgmEnabled;
|
||||
if (bgmPlaying)
|
||||
{
|
||||
StopBackgroundMusic();
|
||||
}
|
||||
|
||||
auto tryPlayWithMci = [&](bool forceMpegVideo) -> bool
|
||||
{
|
||||
mciSendStringW((std::wstring(L"close ") + kReviveVideoAlias).c_str(), nullptr, 0, nullptr);
|
||||
|
||||
std::wstring openCommand = L"open \"" + videoPath + L"\" ";
|
||||
if (forceMpegVideo)
|
||||
{
|
||||
openCommand += L"type mpegvideo ";
|
||||
}
|
||||
openCommand += L"alias ";
|
||||
openCommand += kReviveVideoAlias;
|
||||
|
||||
if (mciSendStringW(openCommand.c_str(), nullptr, 0, hWnd) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::wstring playCommand = std::wstring(L"play ") + kReviveVideoAlias + L" fullscreen wait";
|
||||
MCIERROR playResult = mciSendStringW(playCommand.c_str(), nullptr, 0, hWnd);
|
||||
mciSendStringW((std::wstring(L"close ") + kReviveVideoAlias).c_str(), nullptr, 0, nullptr);
|
||||
return playResult == 0;
|
||||
};
|
||||
|
||||
bool played = tryPlayWithMci(true);
|
||||
if (!played)
|
||||
{
|
||||
played = tryPlayWithMci(false);
|
||||
}
|
||||
|
||||
if (!played)
|
||||
{
|
||||
SHELLEXECUTEINFOW shellInfo = {};
|
||||
shellInfo.cbSize = sizeof(shellInfo);
|
||||
shellInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
|
||||
shellInfo.hwnd = hWnd;
|
||||
shellInfo.lpVerb = L"open";
|
||||
shellInfo.lpFile = videoPath.c_str();
|
||||
shellInfo.nShow = SW_SHOWNORMAL;
|
||||
|
||||
if (ShellExecuteExW(&shellInfo))
|
||||
{
|
||||
if (shellInfo.hProcess != nullptr)
|
||||
{
|
||||
WaitForSingleObject(shellInfo.hProcess, INFINITE);
|
||||
CloseHandle(shellInfo.hProcess);
|
||||
}
|
||||
played = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldResumeBgm)
|
||||
{
|
||||
StartBackgroundMusic();
|
||||
}
|
||||
|
||||
return played;
|
||||
}
|
||||
|
||||
static std::wstring BuildAssetPath(const wchar_t* relativePath)
|
||||
{
|
||||
wchar_t modulePath[MAX_PATH] = {};
|
||||
@@ -729,6 +820,21 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
break;
|
||||
}
|
||||
|
||||
if (gameOverFlag && reviveAvailable && wParam == 'V')
|
||||
{
|
||||
if (PlayReviveVideo(hWnd))
|
||||
{
|
||||
ReviveAfterVideo();
|
||||
ResetGameTimer(hWnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetFeedbackMessage(_T("视频播放失败"), _T("无法打开复活视频,复活机会未消耗。"), 14);
|
||||
}
|
||||
InvalidateRect(hWnd, nullptr, FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
if (gameOverFlag || suspendFlag)
|
||||
{
|
||||
break;
|
||||
|
||||
@@ -9,6 +9,7 @@ int tScore = 0;
|
||||
bool gameOverFlag = false;
|
||||
bool suspendFlag = false;
|
||||
bool targetFlag = false;
|
||||
bool reviveAvailable = false;
|
||||
int workRegion[20][10] = { 0 };
|
||||
Point point = { 0, 0 };
|
||||
Point target = { 0, 0 };
|
||||
@@ -1160,6 +1161,7 @@ void Restart()
|
||||
gameOverFlag = false;
|
||||
suspendFlag = false;
|
||||
targetFlag = true;
|
||||
reviveAvailable = true;
|
||||
currentFallInterval = 500;
|
||||
|
||||
ResetPlayerStats(classicStats, false);
|
||||
@@ -1194,6 +1196,45 @@ void Restart()
|
||||
ComputeTarget();
|
||||
}
|
||||
|
||||
void ReviveAfterVideo()
|
||||
{
|
||||
if (!gameOverFlag || !reviveAvailable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
reviveAvailable = false;
|
||||
gameOverFlag = false;
|
||||
suspendFlag = false;
|
||||
currentScreen = SCREEN_PLAYING;
|
||||
|
||||
int playableHeight = GetRoguePlayableHeight();
|
||||
int rowsToClear = playableHeight / 3;
|
||||
if (rowsToClear < 5)
|
||||
{
|
||||
rowsToClear = 5;
|
||||
}
|
||||
|
||||
for (int y = 0; y < rowsToClear && y < playableHeight; y++)
|
||||
{
|
||||
for (int x = 0; x < nGameWidth; x++)
|
||||
{
|
||||
workRegion[y][x] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
type = ConsumeNextType();
|
||||
nType = nextTypes[0];
|
||||
state = 0;
|
||||
holdUsedThisTurn = false;
|
||||
RollCurrentPieceSpecialFlags(true);
|
||||
point = GetSpawnPoint(type);
|
||||
target = point;
|
||||
ComputeTarget();
|
||||
|
||||
SetFeedbackMessage(_T("复活成功"), _T("已清理顶部空间,本局复活机会已用完。"), 14);
|
||||
}
|
||||
|
||||
void StartGameWithMode(int mode)
|
||||
{
|
||||
currentMode = mode;
|
||||
|
||||
@@ -1663,7 +1663,14 @@ void TDrawScreen(HDC hdc, HWND hWnd)
|
||||
{
|
||||
DrawText(hdc, _T("战局崩塌"), -1, &titleRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
|
||||
SelectObject(hdc, bodyFont);
|
||||
DrawText(hdc, _T("按 R 重新挑战\r\n或按 M 返回菜单"), -1, &tipRect, DT_CENTER | DT_VCENTER | DT_WORDBREAK);
|
||||
DrawText(
|
||||
hdc,
|
||||
reviveAvailable
|
||||
? _T("按 V 看视频复活(仅一次)\r\n按 R 重新挑战 或按 M 返回菜单")
|
||||
: _T("按 R 重新挑战\r\n或按 M 返回菜单"),
|
||||
-1,
|
||||
&tipRect,
|
||||
DT_CENTER | DT_VCENTER | DT_WORDBREAK);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user