Commit eb028f4b authored by fallenstardust's avatar fallenstardust

sync ocgcore

添加注释game
parent 039c168a
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
#include <thread> #include <thread>
#include <string> #include <string>
#include <regex> #include <regex>
#ifdef _IRR_ANDROID_PLATFORM_
#include <android/CAndroidGUIEditBox.h> #include <android/CAndroidGUIEditBox.h>
#include <android/CAndroidGUIComboBox.h> #include <android/CAndroidGUIComboBox.h>
#include <android/CAndroidGUISkin.h> #include <android/CAndroidGUISkin.h>
...@@ -21,13 +21,22 @@ ...@@ -21,13 +21,22 @@
#include <COGLESExtensionHandler.h> #include <COGLESExtensionHandler.h>
#include <COGLES2Driver.h> #include <COGLES2Driver.h>
#include <COGLESDriver.h> #include <COGLESDriver.h>
#endif
namespace ygo { namespace ygo {
Game* mainGame; Game* mainGame;
/**
* @brief 清空决斗信息结构体中的所有数据
*
* 该函数将DuelInfo结构体中的所有成员变量重置为初始状态,
* 包括决斗状态标志、玩家生命值、回合信息、时间限制等。
*
* @param this 指向DuelInfo对象的指针
* @return 无返回值
*/
void DuelInfo::Clear() { void DuelInfo::Clear() {
// 重置决斗状态标志
isStarted = false; isStarted = false;
isInDuel = false; isInDuel = false;
isFinished = false; isFinished = false;
...@@ -40,18 +49,26 @@ void DuelInfo::Clear() { ...@@ -40,18 +49,26 @@ void DuelInfo::Clear() {
tag_player[0] = false; tag_player[0] = false;
tag_player[1] = false; tag_player[1] = false;
isReplaySwapped = false; isReplaySwapped = false;
// 重置生命值相关数据
lp[0] = 0; lp[0] = 0;
lp[1] = 0; lp[1] = 0;
start_lp = 0; start_lp = 0;
// 重置决斗规则和回合信息
duel_rule = 0; duel_rule = 0;
turn = 0; turn = 0;
curMsg = 0; curMsg = 0;
// 清空主机名和客户端名称
hostname[0] = 0; hostname[0] = 0;
clientname[0] = 0; clientname[0] = 0;
hostname_tag[0] = 0; hostname_tag[0] = 0;
clientname_tag[0] = 0; clientname_tag[0] = 0;
strLP[0][0] = 0; strLP[0][0] = 0;
strLP[1][0] = 0; strLP[1][0] = 0;
// 重置玩家类型和时间限制
player_type = 0; player_type = 0;
time_player = 0; time_player = 0;
time_limit = 0; time_limit = 0;
...@@ -59,10 +76,20 @@ void DuelInfo::Clear() { ...@@ -59,10 +76,20 @@ void DuelInfo::Clear() {
time_left[1] = 0; time_left[1] = 0;
} }
/**
* @brief 处理游戏事件
* @param event 输入事件引用,包含鼠标或键盘等输入信息
*
* 该函数主要用于处理鼠标输入事件,对鼠标的坐标进行优化处理。
* 当事件类型为鼠标输入时,会获取当前鼠标坐标并调用optX和optY函数
* 对坐标进行转换或优化,然后更新鼠标输入事件中的坐标值。
*/
void Game::process(irr::SEvent &event) { void Game::process(irr::SEvent &event) {
// 检查事件类型是否为鼠标输入事件
if (event.EventType == irr::EET_MOUSE_INPUT_EVENT) { if (event.EventType == irr::EET_MOUSE_INPUT_EVENT) {
irr::s32 x = event.MouseInput.X; irr::s32 x = event.MouseInput.X;
irr::s32 y = event.MouseInput.Y; irr::s32 y = event.MouseInput.Y;
// 对鼠标坐标进行优化处理并更新事件中的坐标值
event.MouseInput.X = optX(x); event.MouseInput.X = optX(x);
event.MouseInput.Y = optY(y); event.MouseInput.Y = optY(y);
} }
...@@ -135,59 +162,85 @@ bool IsExtension(const char* filename, const char* extension) { ...@@ -135,59 +162,85 @@ bool IsExtension(const char* filename, const char* extension) {
} }
bool Game::Initialize(ANDROID_APP app, irr::android::InitOptions *options) { bool Game::Initialize(ANDROID_APP app, irr::android::InitOptions *options) {
// 保存应用程序句柄
this->appMain = app; this->appMain = app;
// 初始化随机数种子
srand(time(0)); srand(time(0));
// 创建Irrlicht引擎参数结构体
irr::SIrrlichtCreationParameters params{}; irr::SIrrlichtCreationParameters params{};
// 获取OpenGL版本设置
glversion = options->getOpenglVersion(); glversion = options->getOpenglVersion();
// 根据OpenGL版本选择渲染驱动类型
if (glversion == 0) { if (glversion == 0) {
params.DriverType = irr::video::EDT_OGLES1; params.DriverType = irr::video::EDT_OGLES1;
} else{ } else{
params.DriverType = irr::video::EDT_OGLES2; params.DriverType = irr::video::EDT_OGLES2;
} }
// 设置应用程序私有数据
params.PrivateData = app; params.PrivateData = app;
// 设置颜色深度为24位
params.Bits = 24; params.Bits = 24;
// 设置Z缓冲区深度为16位
params.ZBufferBits = 16; params.ZBufferBits = 16;
params.AntiAlias = 0; // 关闭抗锯齿
params.AntiAlias = 1;
// 设置窗口大小为自适应
params.WindowSize = irr::core::dimension2d<irr::u32>(0, 0); params.WindowSize = irr::core::dimension2d<irr::u32>(0, 0);
// 创建Irrlicht设备实例
device = irr::createDeviceEx(params); device = irr::createDeviceEx(params);
// 检查设备创建是否成功
if(!device) { if(!device) {
ErrorLog("Failed to create Irrlicht Engine device!"); ErrorLog("Failed to create Irrlicht Engine device!");
return false; return false;
} }
// 执行Android平台特定的初始化技巧
if (!irr::android::perfromTrick(app)) { if (!irr::android::perfromTrick(app)) {
return false; return false;
} }
// 初始化Java桥接并获取应用位置信息
irr::core::vector2di appPosition = irr::android::initJavaBridge(app, device); irr::core::vector2di appPosition = irr::android::initJavaBridge(app, device);
// 设置位置修正参数
setPositionFix(appPosition); setPositionFix(appPosition);
// 设置进程接收器
device->setProcessReceiver(this); device->setProcessReceiver(this);
// 设置输入事件处理函数
app->onInputEvent = irr::android::handleInput; app->onInputEvent = irr::android::handleInput;
// 获取日志记录器
irr::ILogger* logger = device->getLogger(); irr::ILogger* logger = device->getLogger();
// logger->setLogLevel(ELL_WARNING); // logger->setLogLevel(ELL_WARNING);
// 检查是否启用钟摆刻度显示
isPSEnabled = options->isPendulumScaleEnabled(); isPSEnabled = options->isPendulumScaleEnabled();
// 获取文件系统并设置给数据管理器
dataManager.FileSystem = device->getFileSystem(); dataManager.FileSystem = device->getFileSystem();
// 设置应用命令回调函数
((irr::CIrrDeviceAndroid*)device)->onAppCmd = onHandleAndroidCommand; ((irr::CIrrDeviceAndroid*)device)->onAppCmd = onHandleAndroidCommand;
// 获取屏幕缩放比例
xScale = irr::android::getXScale(app); xScale = irr::android::getXScale(app);
yScale = irr::android::getYScale(app); yScale = irr::android::getYScale(app);
ALOGD("cc game: xScale = %f, yScale = %f", xScale, yScale); ALOGD("cc game: xScale = %f, yScale = %f", xScale, yScale);
SetCardS3DVertex();//reset cardfront cardback S3DVertex size // 重置卡片顶点数据大小
//io::path databaseDir = options->getDBDir(); SetCardS3DVertex();
// 获取工作目录路径
irr::io::path workingDir = options->getWorkDir(); irr::io::path workingDir = options->getWorkDir();
ALOGD("cc game: workingDir= %s", workingDir.c_str()); ALOGD("cc game: workingDir= %s", workingDir.c_str());
// 更改工作目录
dataManager.FileSystem->changeWorkingDirectoryTo(workingDir); dataManager.FileSystem->changeWorkingDirectoryTo(workingDir);
/* Your media must be somewhere inside the assets folder. The assets folder is the root for the file system. /* Your media must be somewhere inside the assets folder. The assets folder is the root for the file system.
This example copies the media in the Android.mk makefile. */ This example copies the media in the Android.mk makefile. */
// 定义媒体资源路径
irr::core::stringc mediaPath = "media/"; irr::core::stringc mediaPath = "media/";
// The Android assets file-system does not know which sub-directories it has (blame google). // The Android assets file-system does not know which sub-directories it has (blame google).
// So we have to add all sub-directories in assets manually. Otherwise we could still open the files, // So we have to add all sub-directories in assets manually. Otherwise we could still open the files,
// but existFile checks will fail (which are for example needed by getFont). // but existFile checks will fail (which are for example needed by getFont).
// 遍历文件档案,为Android资产文件系统添加目录列表
for ( irr::u32 i=0; i < dataManager.FileSystem->getFileArchiveCount(); ++i ) for ( irr::u32 i=0; i < dataManager.FileSystem->getFileArchiveCount(); ++i )
{ {
IFileArchive* archive = dataManager.FileSystem->getFileArchive(i); IFileArchive* archive = dataManager.FileSystem->getFileArchive(i);
...@@ -197,11 +250,12 @@ bool Game::Initialize(ANDROID_APP app, irr::android::InitOptions *options) { ...@@ -197,11 +250,12 @@ bool Game::Initialize(ANDROID_APP app, irr::android::InitOptions *options) {
break; break;
} }
} }
//pics.zip, scripts.zip, ...zip // 加载ZIP压缩包资源
irr::io::path* zips = options->getArchiveFiles(); irr::io::path* zips = options->getArchiveFiles();
int len = options->getArchiveCount(); int len = options->getArchiveCount();
for(int i=0;i<len;i++){ for(int i=0;i<len;i++){
irr::io::path zip_path = zips[i]; irr::io::path zip_path = zips[i];
// 添加文件档案
if(dataManager.FileSystem->addFileArchive(zip_path.c_str(), false, false, EFAT_ZIP)) { if(dataManager.FileSystem->addFileArchive(zip_path.c_str(), false, false, EFAT_ZIP)) {
ALOGD("cc game: add arrchive ok:%s", zip_path.c_str()); ALOGD("cc game: add arrchive ok:%s", zip_path.c_str());
}else{ }else{
...@@ -209,7 +263,9 @@ bool Game::Initialize(ANDROID_APP app, irr::android::InitOptions *options) { ...@@ -209,7 +263,9 @@ bool Game::Initialize(ANDROID_APP app, irr::android::InitOptions *options) {
} }
} }
// 加载配置文件
LoadConfig(); LoadConfig();
// 初始化各种游戏状态变量
linePatternD3D = 0; linePatternD3D = 0;
linePatternGL = 0x0f0f; linePatternGL = 0x0f0f;
waitFrame = 0; waitFrame = 0;
...@@ -223,15 +279,19 @@ bool Game::Initialize(ANDROID_APP app, irr::android::InitOptions *options) { ...@@ -223,15 +279,19 @@ bool Game::Initialize(ANDROID_APP app, irr::android::InitOptions *options) {
is_building = false; is_building = false;
menuHandler.prev_operation = 0; menuHandler.prev_operation = 0;
menuHandler.prev_sel = -1; menuHandler.prev_sel = -1;
// 获取视频驱动和场景管理器
driver = device->getVideoDriver(); driver = device->getVideoDriver();
#ifdef _IRR_ANDROID_PLATFORM_
// 获取卡片质量设置
int quality = options->getCardQualityOp(); int quality = options->getCardQualityOp();
// 检查是否支持非2次幂纹理
if (driver->getDriverType() == irr::video::EDT_OGLES2) { if (driver->getDriverType() == irr::video::EDT_OGLES2) {
isNPOTSupported = ((irr::video::COGLES2Driver *) driver)->queryOpenGLFeature(irr::video::COGLES2ExtensionHandler::IRR_OES_texture_npot); isNPOTSupported = ((irr::video::COGLES2Driver *) driver)->queryOpenGLFeature(irr::video::COGLES2ExtensionHandler::IRR_OES_texture_npot);
} else { } else {
isNPOTSupported = ((irr::video::COGLES1Driver *) driver)->queryOpenGLFeature(irr::video::COGLES1ExtensionHandler::IRR_OES_texture_npot); isNPOTSupported = ((irr::video::COGLES1Driver *) driver)->queryOpenGLFeature(irr::video::COGLES1ExtensionHandler::IRR_OES_texture_npot);
} }
ALOGD("cc game: isNPOTSupported = %d", isNPOTSupported); ALOGD("cc game: isNPOTSupported = %d", isNPOTSupported);
// 根据纹理支持情况设置纹理创建标志
if (isNPOTSupported) { if (isNPOTSupported) {
if (quality == 1) { if (quality == 1) {
driver->setTextureCreationFlag(irr::video::ETCF_CREATE_MIP_MAPS, false); driver->setTextureCreationFlag(irr::video::ETCF_CREATE_MIP_MAPS, false);
...@@ -242,30 +302,33 @@ bool Game::Initialize(ANDROID_APP app, irr::android::InitOptions *options) { ...@@ -242,30 +302,33 @@ bool Game::Initialize(ANDROID_APP app, irr::android::InitOptions *options) {
driver->setTextureCreationFlag(irr::video::ETCF_ALLOW_NON_POWER_2, true); driver->setTextureCreationFlag(irr::video::ETCF_ALLOW_NON_POWER_2, true);
driver->setTextureCreationFlag(irr::video::ETCF_CREATE_MIP_MAPS, false); driver->setTextureCreationFlag(irr::video::ETCF_CREATE_MIP_MAPS, false);
} }
#endif
// 设置纹理优化质量标志
driver->setTextureCreationFlag(irr::video::ETCF_OPTIMIZED_FOR_QUALITY, true); driver->setTextureCreationFlag(irr::video::ETCF_OPTIMIZED_FOR_QUALITY, true);
// 初始化图像管理器
imageManager.SetDevice(device); imageManager.SetDevice(device);
imageManager.ClearTexture(); imageManager.ClearTexture();
// 初始化图像资源
if(!imageManager.Initial(workingDir)) { if(!imageManager.Initial(workingDir)) {
ErrorLog("Failed to load textures!"); ErrorLog("Failed to load textures!");
return false; return false;
} }
// LoadExpansions only load zips, the other cdb databases are still loaded by getDBFiles // 加载数据库文件
irr::io::path* cdbs = options->getDBFiles(); irr::io::path* cdbs = options->getDBFiles();
len = options->getDbCount(); len = options->getDbCount();
//os::Printer::log("load cdbs count %d", len);
for(int i=0;i<len;i++){ for(int i=0;i<len;i++){
irr::io::path cdb_path = cdbs[i]; irr::io::path cdb_path = cdbs[i];
wchar_t wpath[1024]; wchar_t wpath[1024];
// 解码UTF8路径
BufferIO::DecodeUTF8(cdb_path.c_str(), wpath); BufferIO::DecodeUTF8(cdb_path.c_str(), wpath);
// 加载数据库
if(dataManager.LoadDB(wpath)) { if(dataManager.LoadDB(wpath)) {
ALOGD("cc game: add cdb ok:%s", cdb_path.c_str()); ALOGD("cc game: add cdb ok:%s", cdb_path.c_str());
}else{ }else{
ALOGW("cc game: add cdb fail:%s", cdb_path.c_str()); ALOGW("cc game: add cdb fail:%s", cdb_path.c_str());
} }
} }
//if(!dataManager.LoadDB(workingDir.append("/cards.cdb").c_str())) // 加载字符串配置文件
// return false;
if(dataManager.LoadStrings((workingDir + path("/expansions/strings.conf")).c_str())){ if(dataManager.LoadStrings((workingDir + path("/expansions/strings.conf")).c_str())){
ALOGD("cc game: loadStrings expansions/strings.conf"); ALOGD("cc game: loadStrings expansions/strings.conf");
} }
...@@ -273,27 +336,38 @@ bool Game::Initialize(ANDROID_APP app, irr::android::InitOptions *options) { ...@@ -273,27 +336,38 @@ bool Game::Initialize(ANDROID_APP app, irr::android::InitOptions *options) {
ErrorLog("Failed to load strings!"); ErrorLog("Failed to load strings!");
return false; return false;
} }
// 加载扩展卡包
LoadExpansions(); LoadExpansions();
// 加载禁限卡表
deckManager.LoadLFList(options); deckManager.LoadLFList(options);
// 获取GUI环境
env = device->getGUIEnvironment(); env = device->getGUIEnvironment();
// 检查是否启用字体抗锯齿
bool isAntialias = options->isFontAntiAliasEnabled(); bool isAntialias = options->isFontAntiAliasEnabled();
// 创建各种字体
numFont = irr::gui::CGUITTFont::createTTFont(env, gameConf.numfont, 18 * yScale, isAntialias, false); numFont = irr::gui::CGUITTFont::createTTFont(env, gameConf.numfont, 18 * yScale, isAntialias, false);
adFont = irr::gui::CGUITTFont::createTTFont(env, gameConf.numfont, 12 * yScale, isAntialias, false); adFont = irr::gui::CGUITTFont::createTTFont(env, gameConf.numfont, 12 * yScale, isAntialias, false);
lpcFont = irr::gui::CGUITTFont::createTTFont(env, gameConf.numfont, 48 * yScale, isAntialias, true); lpcFont = irr::gui::CGUITTFont::createTTFont(env, gameConf.numfont, 48 * yScale, isAntialias, true);
guiFont = irr::gui::CGUITTFont::createTTFont(env, gameConf.textfont, 18 * yScale, isAntialias, true); guiFont = irr::gui::CGUITTFont::createTTFont(env, gameConf.textfont, 18 * yScale, isAntialias, true);
titleFont = irr::gui::CGUITTFont::createTTFont(env, gameConf.textfont, 32 * yScale, isAntialias, true); titleFont = irr::gui::CGUITTFont::createTTFont(env, gameConf.textfont, 32 * yScale, isAntialias, true);
textFont = irr::gui::CGUITTFont::createTTFont(env, gameConf.textfont, (int)gameConf.textfontsize * yScale, isAntialias, true); textFont = irr::gui::CGUITTFont::createTTFont(env, gameConf.textfont, (int)gameConf.textfontsize * yScale, isAntialias, true);
// 检查字体创建是否成功
if(!numFont || !guiFont) { if(!numFont || !guiFont) {
ALOGW("cc game: add font fail "); ALOGW("cc game: add font fail ");
} }
// 获取场景管理器
smgr = device->getSceneManager(); smgr = device->getSceneManager();
// 设置窗口标题
device->setWindowCaption(L"[---]"); device->setWindowCaption(L"[---]");
// 禁止窗口大小调整
device->setResizable(false); device->setResizable(false);
// 创建并设置新的GUI皮肤
irr::gui::IGUISkin* newskin = irr::gui::CAndroidGUISkin::createAndroidSkin(irr::gui::EGST_BURNING_SKIN, driver, env, xScale, yScale); irr::gui::IGUISkin* newskin = irr::gui::CAndroidGUISkin::createAndroidSkin(irr::gui::EGST_BURNING_SKIN, driver, env, xScale, yScale);
newskin->setFont(guiFont); newskin->setFont(guiFont);
env->setSkin(newskin); env->setSkin(newskin);
// 释放皮肤资源
newskin->drop(); newskin->drop();
#ifdef _IRR_ANDROID_PLATFORM_
//main menu //main menu
wMainMenu = env->addWindow(Resize(450, 40, 900, 600), false, L""); wMainMenu = env->addWindow(Resize(450, 40, 900, 600), false, L"");
wMainMenu->getCloseButton()->setVisible(false); wMainMenu->getCloseButton()->setVisible(false);
...@@ -772,7 +846,7 @@ bool Game::Initialize(ANDROID_APP app, irr::android::InitOptions *options) { ...@@ -772,7 +846,7 @@ bool Game::Initialize(ANDROID_APP app, irr::android::InitOptions *options) {
scrOption->setLargeStep(1); scrOption->setLargeStep(1);
scrOption->setSmallStep(1); scrOption->setSmallStep(1);
scrOption->setMin(0); scrOption->setMin(0);
#endif
//pos select //pos select
wPosSelect = env->addWindow(irr::core::recti(660 * xScale - 223 * yScale, 160 * yScale, 660 * xScale + 223 * yScale, (160 + 228) * yScale), false, dataManager.GetSysString(561)); wPosSelect = env->addWindow(irr::core::recti(660 * xScale - 223 * yScale, 160 * yScale, 660 * xScale + 223 * yScale, (160 + 228) * yScale), false, dataManager.GetSysString(561));
wPosSelect->getCloseButton()->setVisible(false); wPosSelect->getCloseButton()->setVisible(false);
...@@ -790,7 +864,7 @@ bool Game::Initialize(ANDROID_APP app, irr::android::InitOptions *options) { ...@@ -790,7 +864,7 @@ bool Game::Initialize(ANDROID_APP app, irr::android::InitOptions *options) {
btnPSDD->setImageSize(irr::core::dimension2di(CARD_IMG_WIDTH * 0.6f * yScale, CARD_IMG_HEIGHT * 0.6f * yScale)); btnPSDD->setImageSize(irr::core::dimension2di(CARD_IMG_WIDTH * 0.6f * yScale, CARD_IMG_HEIGHT * 0.6f * yScale));
btnPSDD->setImageRotation(270); btnPSDD->setImageRotation(270);
btnPSDD->setImage(imageManager.tCover[0]);//show cover of player1 btnPSDD->setImage(imageManager.tCover[0]);//show cover of player1
#ifdef _IRR_ANDROID_PLATFORM_
//card select //card select
wCardSelect = env->addWindow(irr::core::recti(660 * xScale - 340 * yScale, 55 * yScale, 660 * xScale + 340 * yScale, 400 * yScale), false, L""); wCardSelect = env->addWindow(irr::core::recti(660 * xScale - 340 * yScale, 55 * yScale, 660 * xScale + 340 * yScale, 400 * yScale), false, L"");
wCardSelect->getCloseButton()->setVisible(false); wCardSelect->getCloseButton()->setVisible(false);
...@@ -825,7 +899,7 @@ bool Game::Initialize(ANDROID_APP app, irr::android::InitOptions *options) { ...@@ -825,7 +899,7 @@ bool Game::Initialize(ANDROID_APP app, irr::android::InitOptions *options) {
scrDisplayList = env->addScrollBar(true, Resize_Y(30, 245, 30 + 620, 285), wCardDisplay, SCROLL_CARD_DISPLAY); scrDisplayList = env->addScrollBar(true, Resize_Y(30, 245, 30 + 620, 285), wCardDisplay, SCROLL_CARD_DISPLAY);
btnDisplayOK = env->addButton(Resize_Y(340 - 55, 295, 340 + 55, 335), wCardDisplay, BUTTON_CARD_DISP_OK, dataManager.GetSysString(1211)); btnDisplayOK = env->addButton(Resize_Y(340 - 55, 295, 340 + 55, 335), wCardDisplay, BUTTON_CARD_DISP_OK, dataManager.GetSysString(1211));
ChangeToIGUIImageButton(btnDisplayOK, imageManager.tButton_S, imageManager.tButton_S_pressed); ChangeToIGUIImageButton(btnDisplayOK, imageManager.tButton_S, imageManager.tButton_S_pressed);
#endif
//announce number //announce number
wANNumber = env->addWindow(Resize(500, 50, 800, 470), false, L""); wANNumber = env->addWindow(Resize(500, 50, 800, 470), false, L"");
wANNumber->getCloseButton()->setVisible(false); wANNumber->getCloseButton()->setVisible(false);
...@@ -1012,7 +1086,7 @@ bool Game::Initialize(ANDROID_APP app, irr::android::InitOptions *options) { ...@@ -1012,7 +1086,7 @@ bool Game::Initialize(ANDROID_APP app, irr::android::InitOptions *options) {
for(int i = 1370; i <= 1373; i++) for(int i = 1370; i <= 1373; i++)
cbSortType->addItem(dataManager.GetSysString(i)); cbSortType->addItem(dataManager.GetSysString(i));
wSort->setVisible(false); wSort->setVisible(false);
#ifdef _IRR_ANDROID_PLATFORM_
//filters //filters
wFilter = env->addWindow(Resize(610, 1, 1020, 130), false, L""); wFilter = env->addWindow(Resize(610, 1, 1020, 130), false, L"");
wFilter->getCloseButton()->setVisible(false); wFilter->getCloseButton()->setVisible(false);
...@@ -1089,9 +1163,7 @@ bool Game::Initialize(ANDROID_APP app, irr::android::InitOptions *options) { ...@@ -1089,9 +1163,7 @@ bool Game::Initialize(ANDROID_APP app, irr::android::InitOptions *options) {
scrFilter->setLargeStep(10); scrFilter->setLargeStep(10);
scrFilter->setSmallStep(1); scrFilter->setSmallStep(1);
scrFilter->setVisible(false); scrFilter->setVisible(false);
#endif
#ifdef _IRR_ANDROID_PLATFORM_
//LINK MARKER SEARCH //LINK MARKER SEARCH
btnMarksFilter = env->addButton(Resize(60, 80 + 125 / 6, 190, 100 + 125 / 6), wFilter, BUTTON_MARKS_FILTER, dataManager.GetSysString(1374)); btnMarksFilter = env->addButton(Resize(60, 80 + 125 / 6, 190, 100 + 125 / 6), wFilter, BUTTON_MARKS_FILTER, dataManager.GetSysString(1374));
ChangeToIGUIImageButton(btnMarksFilter, imageManager.tButton_L, imageManager.tButton_L_pressed); ChangeToIGUIImageButton(btnMarksFilter, imageManager.tButton_L, imageManager.tButton_L_pressed);
...@@ -1283,7 +1355,7 @@ bool Game::Initialize(ANDROID_APP app, irr::android::InitOptions *options) { ...@@ -1283,7 +1355,7 @@ bool Game::Initialize(ANDROID_APP app, irr::android::InitOptions *options) {
chkMusicMode->setEnabled(false); chkMusicMode->setEnabled(false);
chkMusicMode->setVisible(false); chkMusicMode->setVisible(false);
} }
#endif
//big picture //big picture
wBigCard = env->addWindow(Resize(0, 0, 0, 0), false, L""); wBigCard = env->addWindow(Resize(0, 0, 0, 0), false, L"");
wBigCard->getCloseButton()->setVisible(false); wBigCard->getCloseButton()->setVisible(false);
...@@ -1325,112 +1397,167 @@ bool Game::Initialize(ANDROID_APP app, irr::android::InitOptions *options) { ...@@ -1325,112 +1397,167 @@ bool Game::Initialize(ANDROID_APP app, irr::android::InitOptions *options) {
col.setAlpha(200); col.setAlpha(200);
env->getSkin()->setColor((irr::gui::EGUI_DEFAULT_COLOR)i, col); env->getSkin()->setColor((irr::gui::EGUI_DEFAULT_COLOR)i, col);
} }
#ifdef _IRR_ANDROID_PLATFORM_
irr::gui::IGUIStaticText *text = env->addStaticText(L"", Resize(1,1,100,45), false, false, 0, GUI_INFO_FPS); irr::gui::IGUIStaticText *text = env->addStaticText(L"", Resize(1,1,100,45), false, false, 0, GUI_INFO_FPS);
#endif
hideChat = false; hideChat = false;
hideChatTimer = 0; hideChatTimer = 0;
return true; return true;
}//bool Game::Initialize }//bool Game::Initialize
/**
* @brief 游戏主循环函数,负责渲染游戏画面、处理输入事件以及更新逻辑状态。
*
* 此函数初始化摄像机、设置投影矩阵与视图矩阵,并根据平台加载对应的着色器材质。
* 在主循环中进行场景绘制、界面刷新、音频播放等操作,并控制帧率和时间显示。
* 同时支持多线程同步机制(如互斥锁)以确保数据安全访问。
*/
void Game::MainLoop() { void Game::MainLoop() {
wchar_t cap[256]; wchar_t cap[256]; // 字符缓冲区,用于临时存储宽字符文本
// 添加一个摄像机节点到场景管理器
camera = smgr->addCameraSceneNode(0); camera = smgr->addCameraSceneNode(0);
// 构建并设置自定义的投影矩阵
irr::core::matrix4 mProjection; irr::core::matrix4 mProjection;
BuildProjectionMatrix(mProjection, -0.90f, 0.45f, -0.42f, 0.42f, 1.0f, 100.0f); BuildProjectionMatrix(mProjection, -0.90f, 0.45f, -0.42f, 0.42f, 1.0f, 100.0f);
camera->setProjectionMatrix(mProjection); camera->setProjectionMatrix(mProjection);
mProjection.buildCameraLookAtMatrixLH(irr::core::vector3df(4.2f, 8.0f, 7.8f), irr::core::vector3df(4.2f, 0, 0), irr::core::vector3df(0, 0, 1)); // 设置摄像机视角变换矩阵(LookAt)
mProjection.buildCameraLookAtMatrixLH(
irr::core::vector3df(4.2f, 8.0f, 7.8f), // 摄像机位置
irr::core::vector3df(4.2f, 0, 0), // 观察目标点
irr::core::vector3df(0, 0, 1) // 上方向向量
);
camera->setViewMatrixAffector(mProjection); camera->setViewMatrixAffector(mProjection);
// 设置环境光颜色为白色
smgr->setAmbientLight(irr::video::SColorf(1.0f, 1.0f, 1.0f)); smgr->setAmbientLight(irr::video::SColorf(1.0f, 1.0f, 1.0f));
float atkframe = 0.1f;
float atkframe = 0.1f; // 动画帧计数器初始值
// 获取设备定时器并重置时间为0
irr::ITimer* timer = device->getTimer(); irr::ITimer* timer = device->getTimer();
timer->setTime(0); timer->setTime(0);
// get FPS
irr::gui::IGUIElement *stat = device->getGUIEnvironment()->getRootGUIElement()->getElementFromId ( GUI_INFO_FPS ); // 获取GUI中的FPS信息控件
int fps = 0; irr::gui::IGUIElement *stat = device->getGUIEnvironment()->getRootGUIElement()->getElementFromId(GUI_INFO_FPS);
int cur_time = 0; int fps = 0; // 当前秒内已渲染帧数
#if defined(_IRR_ANDROID_PLATFORM_) int cur_time = 0; // 定时器当前时间戳
// 初始化OpenGL ES 2.0材质类型变量
ogles2Solid = 0; ogles2Solid = 0;
ogles2TrasparentAlpha = 0; ogles2TrasparentAlpha = 0;
ogles2BlendTexture = 0; ogles2BlendTexture = 0;
// 根据GL版本选择是否使用内置或外部着色器文件
if (glversion == 0 || glversion == 2) { if (glversion == 0 || glversion == 2) {
ogles2Solid = irr::video::EMT_SOLID; ogles2Solid = irr::video::EMT_SOLID;
ogles2TrasparentAlpha = irr::video::EMT_TRANSPARENT_ALPHA_CHANNEL; ogles2TrasparentAlpha = irr::video::EMT_TRANSPARENT_ALPHA_CHANNEL;
ogles2BlendTexture = irr::video::EMT_ONETEXTURE_BLEND; ogles2BlendTexture = irr::video::EMT_ONETEXTURE_BLEND;
} else { } else {
// 着色器文件路径配置
irr::io::path solidvsFileName = "media/ogles2customsolid.frag"; irr::io::path solidvsFileName = "media/ogles2customsolid.frag";
irr::io::path TACvsFileName = "media/ogles2customTAC.frag"; irr::io::path TACvsFileName = "media/ogles2customTAC.frag";
irr::io::path blendvsFileName = "media/ogles2customblend.frag"; irr::io::path blendvsFileName = "media/ogles2customblend.frag";
irr::io::path psFileName = "media/ogles2custom.vert"; irr::io::path psFileName = "media/ogles2custom.vert";
// 检查硬件是否支持像素着色器
if (!driver->queryFeature(irr::video::EVDF_PIXEL_SHADER_1_1) && if (!driver->queryFeature(irr::video::EVDF_PIXEL_SHADER_1_1) &&
!driver->queryFeature(irr::video::EVDF_ARB_FRAGMENT_PROGRAM_1)) !driver->queryFeature(irr::video::EVDF_ARB_FRAGMENT_PROGRAM_1)) {
{ ALOGD("cc game: WARNING: Pixel shaders disabled because of missing driver/hardware support.");
ALOGD("cc game: WARNING: Pixel shaders disabled "
"because of missing driver/hardware support.");
psFileName = ""; psFileName = "";
} }
// 检查硬件是否支持顶点着色器
if (!driver->queryFeature(irr::video::EVDF_VERTEX_SHADER_1_1) && if (!driver->queryFeature(irr::video::EVDF_VERTEX_SHADER_1_1) &&
!driver->queryFeature(irr::video::EVDF_ARB_VERTEX_PROGRAM_1)) !driver->queryFeature(irr::video::EVDF_ARB_VERTEX_PROGRAM_1)) {
{ ALOGD("cc game: WARNING: Vertex shaders disabled because of missing driver/hardware support.");
ALOGD("cc game: WARNING: Vertex shaders disabled "
"because of missing driver/hardware support.");
solidvsFileName = ""; solidvsFileName = "";
TACvsFileName = ""; TACvsFileName = "";
blendvsFileName = ""; blendvsFileName = "";
} }
// 加载高级着色器程序
irr::video::IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices(); irr::video::IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices();
if (gpu) { if (gpu) {
const irr::video::E_GPU_SHADING_LANGUAGE shadingLanguage = irr::video::EGSL_DEFAULT; const irr::video::E_GPU_SHADING_LANGUAGE shadingLanguage = irr::video::EGSL_DEFAULT;
ogles2Solid = gpu->addHighLevelShaderMaterialFromFiles( ogles2Solid = gpu->addHighLevelShaderMaterialFromFiles(
psFileName, "vertexMain", irr::video::EVST_VS_1_1, psFileName, "vertexMain", irr::video::EVST_VS_1_1,
solidvsFileName, "pixelMain", irr::video::EPST_PS_1_1, solidvsFileName, "pixelMain", irr::video::EPST_PS_1_1,
&customShadersCallback, irr::video::EMT_SOLID, 0, shadingLanguage); &customShadersCallback, irr::video::EMT_SOLID, 0, shadingLanguage);
ogles2TrasparentAlpha = gpu->addHighLevelShaderMaterialFromFiles( ogles2TrasparentAlpha = gpu->addHighLevelShaderMaterialFromFiles(
psFileName, "vertexMain", irr::video::EVST_VS_1_1, psFileName, "vertexMain", irr::video::EVST_VS_1_1,
TACvsFileName, "pixelMain", irr::video::EPST_PS_1_1, TACvsFileName, "pixelMain", irr::video::EPST_PS_1_1,
&customShadersCallback, irr::video::EMT_TRANSPARENT_ALPHA_CHANNEL, 0 , shadingLanguage); &customShadersCallback, irr::video::EMT_TRANSPARENT_ALPHA_CHANNEL, 0, shadingLanguage);
ogles2BlendTexture = gpu->addHighLevelShaderMaterialFromFiles( ogles2BlendTexture = gpu->addHighLevelShaderMaterialFromFiles(
psFileName, "vertexMain", irr::video::EVST_VS_1_1, psFileName, "vertexMain", irr::video::EVST_VS_1_1,
blendvsFileName, "pixelMain", irr::video::EPST_PS_1_1, blendvsFileName, "pixelMain", irr::video::EPST_PS_1_1,
&customShadersCallback, irr::video::EMT_ONETEXTURE_BLEND, 0 , shadingLanguage); &customShadersCallback, irr::video::EMT_ONETEXTURE_BLEND, 0, shadingLanguage);
ALOGD("cc game:ogles2Sold = %d", ogles2Solid); ALOGD("cc game:ogles2Sold = %d", ogles2Solid);
ALOGD("cc game:ogles2BlendTexture = %d", ogles2BlendTexture); ALOGD("cc game:ogles2BlendTexture = %d", ogles2BlendTexture);
ALOGD("cc game:ogles2TrasparentAlpha = %d", ogles2TrasparentAlpha); ALOGD("cc game:ogles2TrasparentAlpha = %d", ogles2TrasparentAlpha);
} }
} }
// 将着色器材质应用至各个材质对象
// 设置卡片正面材质类型为混合纹理着色器
matManager.mCard.MaterialType = (irr::video::E_MATERIAL_TYPE)ogles2BlendTexture; matManager.mCard.MaterialType = (irr::video::E_MATERIAL_TYPE)ogles2BlendTexture;
// 设置纹理材质类型为透明alpha通道着色器
matManager.mTexture.MaterialType = (irr::video::E_MATERIAL_TYPE)ogles2TrasparentAlpha; matManager.mTexture.MaterialType = (irr::video::E_MATERIAL_TYPE)ogles2TrasparentAlpha;
// 设置背景线条材质类型为混合纹理着色器
matManager.mBackLine.MaterialType = (irr::video::E_MATERIAL_TYPE)ogles2BlendTexture; matManager.mBackLine.MaterialType = (irr::video::E_MATERIAL_TYPE)ogles2BlendTexture;
// 设置选择区域材质类型为混合纹理着色器
matManager.mSelField.MaterialType = (irr::video::E_MATERIAL_TYPE)ogles2BlendTexture; matManager.mSelField.MaterialType = (irr::video::E_MATERIAL_TYPE)ogles2BlendTexture;
// 设置轮廓线材质类型为纯色着色器
matManager.mOutLine.MaterialType = (irr::video::E_MATERIAL_TYPE)ogles2Solid; matManager.mOutLine.MaterialType = (irr::video::E_MATERIAL_TYPE)ogles2Solid;
// 设置透明纹理材质类型为透明alpha通道着色器
matManager.mTRTexture.MaterialType = (irr::video::E_MATERIAL_TYPE)ogles2TrasparentAlpha; matManager.mTRTexture.MaterialType = (irr::video::E_MATERIAL_TYPE)ogles2TrasparentAlpha;
// 设置攻击指示器材质类型为混合纹理着色器
matManager.mATK.MaterialType = (irr::video::E_MATERIAL_TYPE)ogles2BlendTexture; matManager.mATK.MaterialType = (irr::video::E_MATERIAL_TYPE)ogles2BlendTexture;
// 若不支持非幂次纹理尺寸,则设置纹理环绕模式为边缘夹紧
if (!isNPOTSupported) { if (!isNPOTSupported) {
// 当不支持非2次幂纹理时,设置各个材质的纹理环绕模式为边缘夹紧(CLAMP_TO_EDGE)
// 卡片正面材质的U轴和V轴纹理环绕模式设为边缘夹紧
matManager.mCard.TextureLayer[0].TextureWrapU = irr::video::ETC_CLAMP_TO_EDGE; matManager.mCard.TextureLayer[0].TextureWrapU = irr::video::ETC_CLAMP_TO_EDGE;
matManager.mCard.TextureLayer[0].TextureWrapV = irr::video::ETC_CLAMP_TO_EDGE; matManager.mCard.TextureLayer[0].TextureWrapV = irr::video::ETC_CLAMP_TO_EDGE;
// 纹理材质的U轴和V轴纹理环绕模式设为边缘夹紧
matManager.mTexture.TextureLayer[0].TextureWrapU = irr::video::ETC_CLAMP_TO_EDGE; matManager.mTexture.TextureLayer[0].TextureWrapU = irr::video::ETC_CLAMP_TO_EDGE;
matManager.mTexture.TextureLayer[0].TextureWrapV = irr::video::ETC_CLAMP_TO_EDGE; matManager.mTexture.TextureLayer[0].TextureWrapV = irr::video::ETC_CLAMP_TO_EDGE;
// 背景线条材质的U轴和V轴纹理环绕模式设为边缘夹紧
matManager.mBackLine.TextureLayer[0].TextureWrapU = irr::video::ETC_CLAMP_TO_EDGE; matManager.mBackLine.TextureLayer[0].TextureWrapU = irr::video::ETC_CLAMP_TO_EDGE;
matManager.mBackLine.TextureLayer[0].TextureWrapV = irr::video::ETC_CLAMP_TO_EDGE; matManager.mBackLine.TextureLayer[0].TextureWrapV = irr::video::ETC_CLAMP_TO_EDGE;
// 选择区域材质的U轴和V轴纹理环绕模式设为边缘夹紧
matManager.mSelField.TextureLayer[0].TextureWrapU = irr::video::ETC_CLAMP_TO_EDGE; matManager.mSelField.TextureLayer[0].TextureWrapU = irr::video::ETC_CLAMP_TO_EDGE;
matManager.mSelField.TextureLayer[0].TextureWrapV = irr::video::ETC_CLAMP_TO_EDGE; matManager.mSelField.TextureLayer[0].TextureWrapV = irr::video::ETC_CLAMP_TO_EDGE;
// 轮廓线材质的U轴和V轴纹理环绕模式设为边缘夹紧
matManager.mOutLine.TextureLayer[0].TextureWrapU = irr::video::ETC_CLAMP_TO_EDGE; matManager.mOutLine.TextureLayer[0].TextureWrapU = irr::video::ETC_CLAMP_TO_EDGE;
matManager.mOutLine.TextureLayer[0].TextureWrapV = irr::video::ETC_CLAMP_TO_EDGE; matManager.mOutLine.TextureLayer[0].TextureWrapV = irr::video::ETC_CLAMP_TO_EDGE;
// 透明纹理材质的U轴和V轴纹理环绕模式设为边缘夹紧
matManager.mTRTexture.TextureLayer[0].TextureWrapU = irr::video::ETC_CLAMP_TO_EDGE; matManager.mTRTexture.TextureLayer[0].TextureWrapU = irr::video::ETC_CLAMP_TO_EDGE;
matManager.mTRTexture.TextureLayer[0].TextureWrapV = irr::video::ETC_CLAMP_TO_EDGE; matManager.mTRTexture.TextureLayer[0].TextureWrapV = irr::video::ETC_CLAMP_TO_EDGE;
// 攻击指示器材质的U轴和V轴纹理环绕模式设为边缘夹紧
matManager.mATK.TextureLayer[0].TextureWrapU = irr::video::ETC_CLAMP_TO_EDGE; matManager.mATK.TextureLayer[0].TextureWrapU = irr::video::ETC_CLAMP_TO_EDGE;
matManager.mATK.TextureLayer[0].TextureWrapV = irr::video::ETC_CLAMP_TO_EDGE; matManager.mATK.TextureLayer[0].TextureWrapV = irr::video::ETC_CLAMP_TO_EDGE;
} }
#endif
// 主循环开始:持续运行直到窗口关闭
while(device->run()) { while(device->run()) {
//ALOGV("cc game draw frame"); linePatternD3D = (linePatternD3D + 1) % 30; // 更新线条图案索引(Direct3D风格)
linePatternD3D = (linePatternD3D + 1) % 30; linePatternGL = (linePatternGL << 1) | (linePatternGL >> 15); // 更新线条图案掩码(OpenGL风格)
linePatternGL = (linePatternGL << 1) | (linePatternGL >> 15);
atkframe += 0.1f; atkframe += 0.1f; // 增加动画帧计数
atkdy = (float)sin(atkframe); atkdy = (float)sin(atkframe); // 计算攻击动作偏移量
// 开始渲染场景
driver->beginScene(true, true, irr::video::SColor(0, 0, 0, 0)); driver->beginScene(true, true, irr::video::SColor(0, 0, 0, 0));
#ifdef _IRR_ANDROID_PLATFORM_
// 设置2D材质并启用2D渲染
driver->getMaterial2D().MaterialType = (irr::video::E_MATERIAL_TYPE)ogles2Solid; driver->getMaterial2D().MaterialType = (irr::video::E_MATERIAL_TYPE)ogles2Solid;
if (!isNPOTSupported) { if (!isNPOTSupported) {
driver->getMaterial2D().TextureLayer[0].TextureWrapU = irr::video::ETC_CLAMP_TO_EDGE; driver->getMaterial2D().TextureLayer[0].TextureWrapU = irr::video::ETC_CLAMP_TO_EDGE;
...@@ -1438,88 +1565,121 @@ void Game::MainLoop() { ...@@ -1438,88 +1565,121 @@ void Game::MainLoop() {
} }
driver->enableMaterial2D(true); driver->enableMaterial2D(true);
driver->getMaterial2D().ZBuffer = irr::video::ECFN_NEVER; driver->getMaterial2D().ZBuffer = irr::video::ECFN_NEVER;
// 绘制背景图像
if(imageManager.tBackGround) { if(imageManager.tBackGround) {
driver->draw2DImage(imageManager.tBackGround, Resize(0, 0, GAME_WIDTH, GAME_HEIGHT), irr::core::recti(0, 0, imageManager.tBackGround->getOriginalSize().Width, imageManager.tBackGround->getOriginalSize().Height)); driver->draw2DImage(imageManager.tBackGround, Resize(0, 0, GAME_WIDTH, GAME_HEIGHT),
irr::core::recti(0, 0, imageManager.tBackGround->getOriginalSize().Width,
imageManager.tBackGround->getOriginalSize().Height));
} }
if(imageManager.tBackGround_menu) { if(imageManager.tBackGround_menu) {
driver->draw2DImage(imageManager.tBackGround_menu, Resize(0, 0, GAME_WIDTH, GAME_HEIGHT), irr::core::recti(0, 0, imageManager.tBackGround->getOriginalSize().Width, imageManager.tBackGround->getOriginalSize().Height)); driver->draw2DImage(imageManager.tBackGround_menu, Resize(0, 0, GAME_WIDTH, GAME_HEIGHT),
irr::core::recti(0, 0, imageManager.tBackGround->getOriginalSize().Width,
imageManager.tBackGround->getOriginalSize().Height));
} }
if(imageManager.tBackGround_deck) { if(imageManager.tBackGround_deck) {
driver->draw2DImage(imageManager.tBackGround_deck, Resize(0, 0, GAME_WIDTH, GAME_HEIGHT), irr::core::recti(0, 0, imageManager.tBackGround->getOriginalSize().Width, imageManager.tBackGround->getOriginalSize().Height)); driver->draw2DImage(imageManager.tBackGround_deck, Resize(0, 0, GAME_WIDTH, GAME_HEIGHT),
irr::core::recti(0, 0, imageManager.tBackGround->getOriginalSize().Width,
imageManager.tBackGround->getOriginalSize().Height));
} }
driver->enableMaterial2D(false); driver->enableMaterial2D(false);
// 多线程保护:锁定互斥锁防止并发修改共享资源
gMutex.lock(); gMutex.lock();
// 根据不同状态绘制对应内容
if(dInfo.isStarted) { if(dInfo.isStarted) {
DrawBackImage(imageManager.tBackGround); DrawBackImage(imageManager.tBackGround); // 背景图片
DrawBackGround(); DrawBackGround(); // 场地背景
DrawCards(); DrawCards(); // 所有卡牌
DrawMisc(); DrawMisc(); // 其他元素
smgr->drawAll(); smgr->drawAll(); // 渲染所有3D场景节点
driver->setMaterial(irr::video::IdentityMaterial); driver->setMaterial(irr::video::IdentityMaterial);
driver->clearZBuffer(); driver->clearZBuffer(); // 清除深度缓存
} else if(is_building) { } else if(is_building) {
DrawBackImage(imageManager.tBackGround_deck); DrawBackImage(imageManager.tBackGround_deck); // 牌组编辑界面背景
driver->enableMaterial2D(true); driver->enableMaterial2D(true);
DrawDeckBd(); DrawDeckBd(); // 绘制牌组边框
driver->enableMaterial2D(false); driver->enableMaterial2D(false);
} else { } else {
DrawBackImage(imageManager.tBackGround_menu); DrawBackImage(imageManager.tBackGround_menu); // 菜单界面背景
} }
// 绘制用户界面及特殊效果
driver->enableMaterial2D(true); driver->enableMaterial2D(true);
DrawGUI(); DrawGUI(); // UI组件
DrawSpec(); DrawSpec(); // 特效相关
driver->enableMaterial2D(false); driver->enableMaterial2D(false);
gMutex.unlock();
playBGM(); gMutex.unlock(); // 解锁互斥锁
playBGM(); // 播放背景音乐
// 控制信号帧倒计时
if(signalFrame > 0) { if(signalFrame > 0) {
signalFrame--; signalFrame--;
if(!signalFrame) if(!signalFrame)
frameSignal.Set(); frameSignal.Set(); // 发送信号通知其他线程
} }
// 显示等待提示消息
if(waitFrame >= 0) { if(waitFrame >= 0) {
waitFrame++; waitFrame++;
if(waitFrame % 90 == 0) { if(waitFrame % 90 == 0) {
stHintMsg->setText(dataManager.GetSysString(1390)); stHintMsg->setText(dataManager.GetSysString(1390)); // 提示文字1
} else if(waitFrame % 90 == 30) { } else if(waitFrame % 90 == 30) {
stHintMsg->setText(dataManager.GetSysString(1391)); stHintMsg->setText(dataManager.GetSysString(1391)); // 提示文字2
} else if(waitFrame % 90 == 60) { } else if(waitFrame % 90 == 60) {
stHintMsg->setText(dataManager.GetSysString(1392)); stHintMsg->setText(dataManager.GetSysString(1392)); // 提示文字3
} }
} }
driver->endScene();
driver->endScene(); // 结束渲染过程
// 检查是否需要退出对战窗口
if(closeSignal.Wait(1)) if(closeSignal.Wait(1))
CloseDuelWindow(); CloseDuelWindow();
fps++;
cur_time = timer->getTime(); fps++; // 帧计数增加
cur_time = timer->getTime(); // 获取当前时间
// 控制帧率为约60FPS(每帧最大延迟20毫秒)
if(cur_time < fps * 17 - 20) if(cur_time < fps * 17 - 20)
std::this_thread::sleep_for(std::chrono::milliseconds(20)); std::this_thread::sleep_for(std::chrono::milliseconds(20));
// 每秒钟更新一次FPS显示和剩余时间
if(cur_time >= 1000) { if(cur_time >= 1000) {
if ( stat ) { if(stat) {
irr::core::stringw str = L"FPS: "; irr::core::stringw str = L"FPS: ";
str += (irr::s32)device->getVideoDriver()->getFPS(); str += (irr::s32)device->getVideoDriver()->getFPS();
stat->setText ( str.c_str() ); stat->setText(str.c_str());
} }
fps = 0; fps = 0;
cur_time -= 1000; cur_time -= 1000;
timer->setTime(0); timer->setTime(0);
// 更新玩家剩余时间
if(dInfo.time_player == 0 || dInfo.time_player == 1) if(dInfo.time_player == 0 || dInfo.time_player == 1)
if(dInfo.time_left[dInfo.time_player]) { if(dInfo.time_left[dInfo.time_player]) {
dInfo.time_left[dInfo.time_player]--; dInfo.time_left[dInfo.time_player]--;
RefreshTimeDisplay(); RefreshTimeDisplay();
} }
} }
device->yield(); // probably nicer to the battery
#endif device->yield(); // 礼让CPU,节省电池电量
} }
// 游戏结束后的清理工作
DuelClient::StopClient(true); DuelClient::StopClient(true);
if(dInfo.isSingleMode) if(dInfo.isSingleMode)
SingleMode::StopPlay(true); SingleMode::StopPlay(true);
usleep(500000); usleep(500000); // 等待半秒后保存配置
SaveConfig(); SaveConfig();
usleep(500000); usleep(500000); // 再等待半秒后释放设备资源
device->drop(); device->drop();
} }
void Game::RefreshTimeDisplay() { void Game::RefreshTimeDisplay() {
for(int i = 0; i < 2; ++i) { for(int i = 0; i < 2; ++i) {
if(dInfo.time_left[i] && dInfo.time_limit) { if(dInfo.time_left[i] && dInfo.time_limit) {
...@@ -1611,7 +1771,6 @@ std::wstring Game::SetStaticText(irr::gui::IGUIStaticText* pControl, irr::u32 cW ...@@ -1611,7 +1771,6 @@ std::wstring Game::SetStaticText(irr::gui::IGUIStaticText* pControl, irr::u32 cW
} }
void Game::LoadExpansions() { void Game::LoadExpansions() {
// TODO: get isUseExtraCards // TODO: get isUseExtraCards
#ifdef _IRR_ANDROID_PLATFORM_
DIR * dir; DIR * dir;
struct dirent * dirp; struct dirent * dirp;
if((dir = opendir("./expansions/")) == NULL) if((dir = opendir("./expansions/")) == NULL)
...@@ -1625,7 +1784,7 @@ void Game::LoadExpansions() { ...@@ -1625,7 +1784,7 @@ void Game::LoadExpansions() {
dataManager.FileSystem->addFileArchive(upath, true, false, EFAT_ZIP); dataManager.FileSystem->addFileArchive(upath, true, false, EFAT_ZIP);
} }
closedir(dir); closedir(dir);
#endif
for(irr::u32 i = 0; i < dataManager.FileSystem->getFileArchiveCount(); ++i) { for(irr::u32 i = 0; i < dataManager.FileSystem->getFileArchiveCount(); ++i) {
auto archive = dataManager.FileSystem->getFileArchive(i)->getFileList(); auto archive = dataManager.FileSystem->getFileArchive(i)->getFileList();
for(irr::u32 j = 0; j < archive->getFileCount(); ++j) { for(irr::u32 j = 0; j < archive->getFileCount(); ++j) {
......
...@@ -732,8 +732,7 @@ uint32_t field::process() { ...@@ -732,8 +732,7 @@ uint32_t field::process() {
core.units.pop_front(); // 移除当前处理单元 core.units.pop_front(); // 移除当前处理单元
} }
return pduel->buffer_size(); // 返回缓冲区大小 return pduel->buffer_size(); // 返回缓冲区大小
} }
case PROCESSOR_REMOVE_OVERLAY: { case PROCESSOR_REMOVE_OVERLAY: {
if(remove_overlay_card(it->step, it->arg3, (card*)(it->ptarget), it->arg1 >> 16, if(remove_overlay_card(it->step, it->arg3, (card*)(it->ptarget), it->arg1 >> 16,
(it->arg1 >> 8) & 0xff, it->arg1 & 0xff, it->arg2 & 0xffff, it->arg2 >> 16)) { (it->arg1 >> 8) & 0xff, it->arg1 & 0xff, it->arg2 & 0xffff, it->arg2 >> 16)) {
...@@ -4017,34 +4016,58 @@ int32_t field::process_turn(uint16_t step, uint8_t turn_player) { ...@@ -4017,34 +4016,58 @@ int32_t field::process_turn(uint16_t step, uint8_t turn_player) {
} }
return TRUE; return TRUE;
} }
/**
* @brief 处理连锁的添加过程
*
* 该函数负责将新发动的效果添加到连锁中,包括处理发动cost、移动卡片、设置连锁状态等操作。
* 连锁添加过程分为多个步骤,每个步骤处理不同的阶段,如cost处理、位置调整、取对象选择等。
*
* @param step 当前处理步骤
* @return int32_t 处理结果,TRUE表示处理完成,FALSE表示需要继续处理
*/
int32_t field::add_chain(uint16_t step) { int32_t field::add_chain(uint16_t step) {
switch (step) { switch (step) {
case 0: { case 0: {
// 如果没有新的连锁需要处理,则直接返回TRUE结束
if (!core.new_chains.size()) if (!core.new_chains.size())
return TRUE; return TRUE;
// 获取第一个待处理的连锁
auto& clit = core.new_chains.front(); auto& clit = core.new_chains.front();
effect* peffect = clit.triggering_effect; effect* peffect = clit.triggering_effect; // 获取发动的效果
card* phandler = peffect->get_handler(); card* phandler = peffect->get_handler(); // 获取效果持有者卡片
// 处理发动cost(EFFECT_ACTIVATE_COST)
effect_set eset; effect_set eset;
filter_player_effect(clit.triggering_player, EFFECT_ACTIVATE_COST, &eset); filter_player_effect(clit.triggering_player, EFFECT_ACTIVATE_COST, &eset);
for(effect_set::size_type i = 0; i < eset.size(); ++i) { for(effect_set::size_type i = 0; i < eset.size(); ++i) {
// 添加参数并检查条件
pduel->lua->add_param(eset[i], PARAM_TYPE_EFFECT); pduel->lua->add_param(eset[i], PARAM_TYPE_EFFECT);
pduel->lua->add_param(clit.triggering_effect, PARAM_TYPE_EFFECT); pduel->lua->add_param(clit.triggering_effect, PARAM_TYPE_EFFECT);
pduel->lua->add_param(clit.triggering_player, PARAM_TYPE_INT); pduel->lua->add_param(clit.triggering_player, PARAM_TYPE_INT);
if(!pduel->lua->check_condition(eset[i]->target, 3)) if(!pduel->lua->check_condition(eset[i]->target, 3))
continue; continue;
// 如果有条件且有操作,则执行操作
if(eset[i]->operation) { if(eset[i]->operation) {
core.sub_solving_event.push_back(clit.evt); core.sub_solving_event.push_back(clit.evt);
add_process(PROCESSOR_EXECUTE_OPERATION, 0, eset[i], 0, clit.triggering_player, 0); add_process(PROCESSOR_EXECUTE_OPERATION, 0, eset[i], 0, clit.triggering_player, 0);
} }
} }
// 如果是卡的发动类型的效果
if(peffect->type & EFFECT_TYPE_ACTIVATE) { if(peffect->type & EFFECT_TYPE_ACTIVATE) {
// 获取手牌或场地设置所需的效果
if(peffect->get_required_handorset_effects(&clit.required_handorset_effects, clit.triggering_player, clit.evt) != 2) { if(peffect->get_required_handorset_effects(&clit.required_handorset_effects, clit.triggering_player, clit.evt) != 2) {
clit.required_handorset_effects.clear(); clit.required_handorset_effects.clear();
} }
// 如果卡片在手牌中
if(phandler->current.location == LOCATION_HAND) { if(phandler->current.location == LOCATION_HAND) {
uint32_t zone = 0xff; uint32_t zone = 0xff; // 默认可放置区域
// 如果不是场地卡或钟摆卡,且有限制区域标志
if(!(phandler->data.type & (TYPE_FIELD | TYPE_PENDULUM)) && peffect->is_flag(EFFECT_FLAG_LIMIT_ZONE)) { if(!(phandler->data.type & (TYPE_FIELD | TYPE_PENDULUM)) && peffect->is_flag(EFFECT_FLAG_LIMIT_ZONE)) {
// 添加参数计算可用区域
pduel->lua->add_param(clit.triggering_player, PARAM_TYPE_INT); pduel->lua->add_param(clit.triggering_player, PARAM_TYPE_INT);
pduel->lua->add_param(clit.evt.event_cards , PARAM_TYPE_GROUP); pduel->lua->add_param(clit.evt.event_cards , PARAM_TYPE_GROUP);
pduel->lua->add_param(clit.evt.event_player, PARAM_TYPE_INT); pduel->lua->add_param(clit.evt.event_player, PARAM_TYPE_INT);
...@@ -4056,12 +4079,19 @@ int32_t field::add_chain(uint16_t step) { ...@@ -4056,12 +4079,19 @@ int32_t field::add_chain(uint16_t step) {
if(!zone) if(!zone)
zone = 0xff; zone = 0xff;
} }
// 禁用手牌效果,设置从手发动状态
phandler->enable_field_effect(false); phandler->enable_field_effect(false);
phandler->set_status(STATUS_ACT_FROM_HAND, TRUE); phandler->set_status(STATUS_ACT_FROM_HAND, TRUE);
// 场地卡只能放在特定区域
if(phandler->data.type & TYPE_FIELD) if(phandler->data.type & TYPE_FIELD)
zone = 0x1U << 5; zone = 0x1U << 5;
// 移动卡片到场上
move_to_field(phandler, phandler->current.controler, phandler->current.controler, LOCATION_SZONE, POS_FACEUP, FALSE, 0, (phandler->data.type & TYPE_PENDULUM) ? TRUE : FALSE, zone); move_to_field(phandler, phandler->current.controler, phandler->current.controler, LOCATION_SZONE, POS_FACEUP, FALSE, 0, (phandler->data.type & TYPE_PENDULUM) ? TRUE : FALSE, zone);
} else { } else {
// 如果不在手牌中,清除从手牌发动状态,并改为表侧表示
phandler->set_status(STATUS_ACT_FROM_HAND, FALSE); phandler->set_status(STATUS_ACT_FROM_HAND, FALSE);
change_position(phandler, 0, phandler->current.controler, POS_FACEUP, 0); change_position(phandler, 0, phandler->current.controler, POS_FACEUP, 0);
} }
...@@ -4069,32 +4099,47 @@ int32_t field::add_chain(uint16_t step) { ...@@ -4069,32 +4099,47 @@ int32_t field::add_chain(uint16_t step) {
return FALSE; return FALSE;
} }
case 1: { case 1: {
// 获取当前处理的连锁
auto& clit = core.new_chains.front(); auto& clit = core.new_chains.front();
effect* peffect = clit.triggering_effect; effect* peffect = clit.triggering_effect;
card* phandler = peffect->get_handler(); card* phandler = peffect->get_handler();
// 刷新卡片的禁用状态
phandler->refresh_disable_status(); phandler->refresh_disable_status();
// 如果是卡的发动类型效果,更新发动状态
if(peffect->type & EFFECT_TYPE_ACTIVATE) { if(peffect->type & EFFECT_TYPE_ACTIVATE) {
clit.set_triggering_state(phandler); clit.set_triggering_state(phandler);
} }
// 向客户端发送连锁消息
pduel->write_buffer8(MSG_CHAINING); pduel->write_buffer8(MSG_CHAINING);
pduel->write_buffer32(phandler->data.code); pduel->write_buffer32(phandler->data.code); // 卡片密码
pduel->write_buffer32(phandler->get_info_location()); pduel->write_buffer32(phandler->get_info_location()); // 卡片位置
pduel->write_buffer8(clit.triggering_controler); pduel->write_buffer8(clit.triggering_controler); // 诱发的玩家
pduel->write_buffer8((uint8_t)clit.triggering_location); pduel->write_buffer8((uint8_t)clit.triggering_location); // 诱发位置
pduel->write_buffer8(clit.triggering_sequence); pduel->write_buffer8(clit.triggering_sequence); // 诱发序号
pduel->write_buffer32(peffect->description); pduel->write_buffer32(peffect->description); // 效果描述
pduel->write_buffer8((uint8_t)core.current_chain.size() + 1); pduel->write_buffer8((uint8_t)core.current_chain.size() + 1); // 连锁序号
// 清除连锁限制
for(auto& ch_lim : core.chain_limit) for(auto& ch_lim : core.chain_limit)
luaL_unref(pduel->lua->lua_state, LUA_REGISTRYINDEX, ch_lim.function); luaL_unref(pduel->lua->lua_state, LUA_REGISTRYINDEX, ch_lim.function);
core.chain_limit.clear(); core.chain_limit.clear();
// 设置效果类型
peffect->card_type = phandler->get_type(); peffect->card_type = phandler->get_type();
if((peffect->card_type & (TYPE_TRAP | TYPE_MONSTER)) == (TYPE_TRAP | TYPE_MONSTER)) if((peffect->card_type & (TYPE_TRAP | TYPE_MONSTER)) == (TYPE_TRAP | TYPE_MONSTER))
peffect->card_type -= TYPE_TRAP; peffect->card_type -= TYPE_TRAP;
peffect->set_active_type(); peffect->set_active_type();
// 处理叠置素材效果
if (peffect->type & EFFECT_TYPE_XMATERIAL) { if (peffect->type & EFFECT_TYPE_XMATERIAL) {
peffect->active_handler = peffect->handler->overlay_target; peffect->active_handler = peffect->handler->overlay_target;
peffect->last_handler = peffect->handler->overlay_target; peffect->last_handler = peffect->handler->overlay_target;
} }
// 设置连锁属性
clit.chain_count = (uint8_t)core.current_chain.size() + 1; clit.chain_count = (uint8_t)core.current_chain.size() + 1;
clit.target_cards = 0; clit.target_cards = 0;
clit.target_player = PLAYER_NONE; clit.target_player = PLAYER_NONE;
...@@ -4102,18 +4147,28 @@ int32_t field::add_chain(uint16_t step) { ...@@ -4102,18 +4147,28 @@ int32_t field::add_chain(uint16_t step) {
clit.disable_reason = 0; clit.disable_reason = 0;
clit.disable_player = PLAYER_NONE; clit.disable_player = PLAYER_NONE;
clit.replace_op = 0; clit.replace_op = 0;
// 如果从手牌发动,设置相应标志
if(phandler->current.location == LOCATION_HAND) if(phandler->current.location == LOCATION_HAND)
clit.flag |= CHAIN_HAND_EFFECT; clit.flag |= CHAIN_HAND_EFFECT;
// 将连锁添加到当前连锁列表
core.current_chain.push_back(clit); core.current_chain.push_back(clit);
core.is_target_ready = false; core.is_target_ready = false;
// 检查连锁计数
check_chain_counter(peffect, clit.triggering_player, clit.chain_count); check_chain_counter(peffect, clit.triggering_player, clit.chain_count);
// triggered events which are not caused by event create relation with the handler
// 为非事件诱发的效果创建关系
if(!peffect->is_flag(EFFECT_FLAG_FIELD_ONLY) if(!peffect->is_flag(EFFECT_FLAG_FIELD_ONLY)
&& (!(peffect->type & (EFFECT_TYPE_TRIGGER_F | EFFECT_TYPE_TRIGGER_O)) || peffect->get_code_type() == CODE_PHASE)) { && (!(peffect->type & (EFFECT_TYPE_TRIGGER_F | EFFECT_TYPE_TRIGGER_O)) || peffect->get_code_type() == CODE_PHASE)) {
phandler->create_relation(clit); phandler->create_relation(clit);
} }
// 设置效果拥有者
peffect->effect_owner = clit.triggering_player; peffect->effect_owner = clit.triggering_player;
// DISABLE_CHAIN should be check before cost
// 检查禁用效果
effect* deffect; effect* deffect;
if(!peffect->is_flag(EFFECT_FLAG_FIELD_ONLY) && phandler->is_has_relation(clit) && (deffect = phandler->is_affected_by_effect(EFFECT_DISABLE_EFFECT))) { if(!peffect->is_flag(EFFECT_FLAG_FIELD_ONLY) && phandler->is_has_relation(clit) && (deffect = phandler->is_affected_by_effect(EFFECT_DISABLE_EFFECT))) {
effect* negeff = pduel->new_effect(); effect* negeff = pduel->new_effect();
...@@ -4124,32 +4179,42 @@ int32_t field::add_chain(uint16_t step) { ...@@ -4124,32 +4179,42 @@ int32_t field::add_chain(uint16_t step) {
negeff->reset_flag = RESET_CHAIN | RESET_EVENT | deffect->get_value(); negeff->reset_flag = RESET_CHAIN | RESET_EVENT | deffect->get_value();
phandler->add_effect(negeff); phandler->add_effect(negeff);
} }
// 从新连锁列表中移除已处理的连锁
core.new_chains.pop_front(); core.new_chains.pop_front();
return FALSE; return FALSE;
} }
case 2: { case 2: {
// 获取当前连锁
auto& clit = core.current_chain.back(); auto& clit = core.current_chain.back();
int32_t playerid = clit.triggering_player; int32_t playerid = clit.triggering_player;
effect* peffect = clit.triggering_effect; effect* peffect = clit.triggering_effect;
// 检查是否存在CEFFECT(手牌或场地区域设置效果)
if(get_cteffect(peffect, playerid, TRUE)) { if(get_cteffect(peffect, playerid, TRUE)) {
// 检查是否在伤害步骤且效果不允许在伤害步骤使用
const bool damage_step = infos.phase == PHASE_DAMAGE && !peffect->is_flag(EFFECT_FLAG_DAMAGE_STEP); const bool damage_step = infos.phase == PHASE_DAMAGE && !peffect->is_flag(EFFECT_FLAG_DAMAGE_STEP);
const bool damage_cal = infos.phase == PHASE_DAMAGE_CAL && !peffect->is_flag(EFFECT_FLAG_DAMAGE_CAL); const bool damage_cal = infos.phase == PHASE_DAMAGE_CAL && !peffect->is_flag(EFFECT_FLAG_DAMAGE_CAL);
if(damage_step || damage_cal) { if(damage_step || damage_cal) {
returns.ivalue[0] = TRUE; returns.ivalue[0] = TRUE;
return FALSE; return FALSE;
} }
// 询问玩家是否使用CEFFECT
add_process(PROCESSOR_SELECT_EFFECTYN, 0, 0, (group*)peffect->get_handler(), playerid, 94); add_process(PROCESSOR_SELECT_EFFECTYN, 0, 0, (group*)peffect->get_handler(), playerid, 94);
} else } else
returns.ivalue[0] = FALSE; returns.ivalue[0] = FALSE;
return FALSE; return FALSE;
} }
case 3: { case 3: {
// 如果玩家选择不使用CEFFECT
if(!returns.ivalue[0]) { if(!returns.ivalue[0]) {
core.select_chains.clear(); core.select_chains.clear();
core.select_options.clear(); core.select_options.clear();
core.units.begin()->step = 4; core.units.begin()->step = 4;
return FALSE; return FALSE;
} }
// 如果有多个CEFFECT选项,让玩家选择
if(core.select_chains.size() > 1) { if(core.select_chains.size() > 1) {
auto& clit = core.current_chain.back(); auto& clit = core.current_chain.back();
add_process(PROCESSOR_SELECT_OPTION, 0, 0, 0, clit.triggering_player, 0); add_process(PROCESSOR_SELECT_OPTION, 0, 0, 0, clit.triggering_player, 0);
...@@ -4158,25 +4223,37 @@ int32_t field::add_chain(uint16_t step) { ...@@ -4158,25 +4223,37 @@ int32_t field::add_chain(uint16_t step) {
return FALSE; return FALSE;
} }
case 4: { case 4: {
// 处理CEFFECT选择结果
auto& clit = core.current_chain.back(); auto& clit = core.current_chain.back();
chain& ch = core.select_chains[returns.ivalue[0]]; chain& ch = core.select_chains[returns.ivalue[0]];
int32_t playerid = clit.triggering_player; int32_t playerid = clit.triggering_player;
effect* peffect = ch.triggering_effect; effect* peffect = ch.triggering_effect;
card* phandler = peffect->get_handler(); card* phandler = peffect->get_handler();
// 发送选择提示消息
pduel->write_buffer8(MSG_HINT); pduel->write_buffer8(MSG_HINT);
pduel->write_buffer8(HINT_OPSELECTED); pduel->write_buffer8(HINT_OPSELECTED);
pduel->write_buffer8(playerid); pduel->write_buffer8(playerid);
pduel->write_buffer32(core.select_options.size() > 1 ? core.select_options[returns.ivalue[0]] : 65); pduel->write_buffer32(core.select_options.size() > 1 ? core.select_options[returns.ivalue[0]] : 65);
// 更新连锁效果和事件
clit.triggering_effect = peffect; clit.triggering_effect = peffect;
clit.evt = ch.evt; clit.evt = ch.evt;
phandler->create_relation(clit); phandler->create_relation(clit);
peffect->set_active_type();
peffect->dec_count(playerid); peffect->dec_count(playerid);
// 如果不是卡的发动类型效果,添加发动标志
if(!(peffect->type & EFFECT_TYPE_ACTIVATE)) { if(!(peffect->type & EFFECT_TYPE_ACTIVATE)) {
peffect->type |= EFFECT_TYPE_ACTIVATE; peffect->type |= EFFECT_TYPE_ACTIVATE;
clit.flag |= CHAIN_ACTIVATING; clit.flag |= CHAIN_ACTIVATING;
} }
// 清理选择项
core.select_chains.clear(); core.select_chains.clear();
core.select_options.clear(); core.select_options.clear();
// 添加客户端提示效果
effect* deffect = pduel->new_effect(); effect* deffect = pduel->new_effect();
deffect->owner = phandler; deffect->owner = phandler;
deffect->code = 0; deffect->code = 0;
...@@ -4188,16 +4265,19 @@ int32_t field::add_chain(uint16_t step) { ...@@ -4188,16 +4265,19 @@ int32_t field::add_chain(uint16_t step) {
return FALSE; return FALSE;
} }
case 5: { case 5: {
// 处理必需的手牌或场地设置效果
auto& clit = core.current_chain.back(); auto& clit = core.current_chain.back();
if (!clit.required_handorset_effects.size()) { if (!clit.required_handorset_effects.size()) {
core.units.begin()->step = 6; core.units.begin()->step = 6;
return FALSE; return FALSE;
} }
// 如果只有一个必需效果,直接使用
if(clit.required_handorset_effects.size() == 1) { if(clit.required_handorset_effects.size() == 1) {
returns.ivalue[0] = 0; returns.ivalue[0] = 0;
return FALSE; return FALSE;
} else { } else {
// check if there's only one type of ceffects // 检查是否所有效果都是同一种类型
auto peffect = clit.triggering_effect; auto peffect = clit.triggering_effect;
auto playerid = clit.triggering_player; auto playerid = clit.triggering_player;
int32_t ceffect_unique_id = 0; int32_t ceffect_unique_id = 0;
...@@ -4214,11 +4294,13 @@ int32_t field::add_chain(uint16_t step) { ...@@ -4214,11 +4294,13 @@ int32_t field::add_chain(uint16_t step) {
} }
} }
if (ceffect_unique_id) { if (ceffect_unique_id) {
// all ceffects are the same type, so skip asking // 所有效果相同,无需选择
returns.ivalue[0] = 0; returns.ivalue[0] = 0;
return FALSE; return FALSE;
} }
} }
// 让玩家选择必需效果
core.select_options.clear(); core.select_options.clear();
for(effect_set::size_type i = 0; i < clit.required_handorset_effects.size(); ++i) { for(effect_set::size_type i = 0; i < clit.required_handorset_effects.size(); ++i) {
core.select_options.push_back(clit.required_handorset_effects[i]->description); core.select_options.push_back(clit.required_handorset_effects[i]->description);
...@@ -4227,15 +4309,20 @@ int32_t field::add_chain(uint16_t step) { ...@@ -4227,15 +4309,20 @@ int32_t field::add_chain(uint16_t step) {
return FALSE; return FALSE;
} }
case 6: { case 6: {
// 执行选择的必需效果
auto& clit = core.current_chain.back(); auto& clit = core.current_chain.back();
auto ceffect = clit.required_handorset_effects[returns.ivalue[0]]; auto ceffect = clit.required_handorset_effects[returns.ivalue[0]];
ceffect->dec_count(clit.triggering_player); ceffect->dec_count(clit.triggering_player);
// 发送选择提示
if(ceffect->description) { if(ceffect->description) {
pduel->write_buffer8(MSG_HINT); pduel->write_buffer8(MSG_HINT);
pduel->write_buffer8(HINT_OPSELECTED); pduel->write_buffer8(HINT_OPSELECTED);
pduel->write_buffer8(clit.triggering_player); pduel->write_buffer8(clit.triggering_player);
pduel->write_buffer32(ceffect->description); pduel->write_buffer32(ceffect->description);
} }
// 执行支付cost步骤
if(ceffect->cost) { if(ceffect->cost) {
pduel->lua->add_param(clit.triggering_effect, PARAM_TYPE_EFFECT); pduel->lua->add_param(clit.triggering_effect, PARAM_TYPE_EFFECT);
core.sub_solving_event.push_back(clit.evt); core.sub_solving_event.push_back(clit.evt);
...@@ -4244,6 +4331,7 @@ int32_t field::add_chain(uint16_t step) { ...@@ -4244,6 +4331,7 @@ int32_t field::add_chain(uint16_t step) {
return FALSE; return FALSE;
} }
case 7: { case 7: {
// 支付主要效果的cost
auto& clit = core.current_chain.back(); auto& clit = core.current_chain.back();
effect* peffect = clit.triggering_effect; effect* peffect = clit.triggering_effect;
peffect->cost_checked = TRUE; peffect->cost_checked = TRUE;
...@@ -4254,6 +4342,7 @@ int32_t field::add_chain(uint16_t step) { ...@@ -4254,6 +4342,7 @@ int32_t field::add_chain(uint16_t step) {
return FALSE; return FALSE;
} }
case 8: { case 8: {
// 执行选择主要效果的发动对象
auto& clit = core.current_chain.back(); auto& clit = core.current_chain.back();
effect* peffect = clit.triggering_effect; effect* peffect = clit.triggering_effect;
if(peffect->target) { if(peffect->target) {
...@@ -4263,12 +4352,15 @@ int32_t field::add_chain(uint16_t step) { ...@@ -4263,12 +4352,15 @@ int32_t field::add_chain(uint16_t step) {
return FALSE; return FALSE;
} }
case 9: { case 9: {
// 连锁添加完成后的处理
break_effect(); break_effect();
core.is_target_ready = true; core.is_target_ready = true;
auto& clit = core.current_chain.back(); auto& clit = core.current_chain.back();
effect* peffect = clit.triggering_effect; effect* peffect = clit.triggering_effect;
peffect->cost_checked = FALSE; peffect->cost_checked = FALSE;
card* phandler = peffect->get_handler(); card* phandler = peffect->get_handler();
// 处理作为对象的卡片成为目标事件
if(clit.target_cards && clit.target_cards->container.size()) { if(clit.target_cards && clit.target_cards->container.size()) {
if(peffect->is_flag(EFFECT_FLAG_CARD_TARGET)) { if(peffect->is_flag(EFFECT_FLAG_CARD_TARGET)) {
for(auto& pcard : clit.target_cards->container) for(auto& pcard : clit.target_cards->container)
...@@ -4278,29 +4370,42 @@ int32_t field::add_chain(uint16_t step) { ...@@ -4278,29 +4370,42 @@ int32_t field::add_chain(uint16_t step) {
raise_event(clit.target_cards->container, EVENT_BECOME_TARGET, peffect, 0, clit.triggering_player, clit.triggering_player, clit.chain_count); raise_event(clit.target_cards->container, EVENT_BECOME_TARGET, peffect, 0, clit.triggering_player, clit.triggering_player, clit.chain_count);
} }
} }
// 处理发动的卡片的离场确认
if(peffect->type & EFFECT_TYPE_ACTIVATE) { if(peffect->type & EFFECT_TYPE_ACTIVATE) {
core.leave_confirmed.insert(phandler); core.leave_confirmed.insert(phandler);
if(!(phandler->data.type & (TYPE_CONTINUOUS | TYPE_FIELD | TYPE_EQUIP | TYPE_PENDULUM)) if(!(phandler->data.type & (TYPE_CONTINUOUS | TYPE_FIELD | TYPE_EQUIP | TYPE_PENDULUM))
&& !phandler->is_affected_by_effect(EFFECT_REMAIN_FIELD)) && !phandler->is_affected_by_effect(EFFECT_REMAIN_FIELD))
phandler->set_status(STATUS_LEAVE_CONFIRMED, TRUE); phandler->set_status(STATUS_LEAVE_CONFIRMED, TRUE);
} }
// 设置连续卡片标志
if((phandler->get_type() & (TYPE_SPELL | TYPE_TRAP)) if((phandler->get_type() & (TYPE_SPELL | TYPE_TRAP))
&& (phandler->get_type() & (TYPE_CONTINUOUS | TYPE_FIELD | TYPE_EQUIP | TYPE_PENDULUM)) && (phandler->get_type() & (TYPE_CONTINUOUS | TYPE_FIELD | TYPE_EQUIP | TYPE_PENDULUM))
&& phandler->is_has_relation(clit) && phandler->current.location == LOCATION_SZONE && phandler->is_has_relation(clit) && phandler->current.location == LOCATION_SZONE
&& !peffect->is_flag(EFFECT_FLAG_FIELD_ONLY)) && !peffect->is_flag(EFFECT_FLAG_FIELD_ONLY))
clit.flag |= CHAIN_CONTINUOUS_CARD; clit.flag |= CHAIN_CONTINUOUS_CARD;
// 发送连锁完成消息
pduel->write_buffer8(MSG_CHAINED); pduel->write_buffer8(MSG_CHAINED);
pduel->write_buffer8(clit.chain_count); pduel->write_buffer8(clit.chain_count);
// 诱发连锁事件
raise_event(phandler, EVENT_CHAINING, peffect, 0, clit.triggering_player, clit.triggering_player, clit.chain_count); raise_event(phandler, EVENT_CHAINING, peffect, 0, clit.triggering_player, clit.triggering_player, clit.chain_count);
process_instant_event(); process_instant_event();
// 如果还有新的连锁需要处理,继续添加
if(core.new_chains.size()) if(core.new_chains.size())
add_process(PROCESSOR_ADD_CHAIN, 0, 0, 0, 0, 0); add_process(PROCESSOR_ADD_CHAIN, 0, 0, 0, 0, 0);
// 调整所有状态
adjust_all(); adjust_all();
return TRUE; return TRUE;
} }
} }
return TRUE; return TRUE;
} }
void field::solve_continuous(uint8_t playerid, effect* peffect, const tevent& e) { void field::solve_continuous(uint8_t playerid, effect* peffect, const tevent& e) {
chain newchain; chain newchain;
newchain.chain_id = 0; newchain.chain_id = 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment